Fix #2099939 [Book drag data includes invalid file URI](https://bugs.launchpad.net/calibre/+bug/2099939)

Workaround for https://bugreports.qt.io/browse/QTBUG-134073
This commit is contained in:
Kovid Goyal 2025-02-25 17:35:32 +05:30
parent 084a672f17
commit 87e8c06819
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 18 additions and 8 deletions

View File

@ -11,7 +11,7 @@ import re
from contextlib import suppress from contextlib import suppress
from threading import Thread from threading import Thread
from qt.core import QDialog, QDialogButtonBox, QImageReader, QLabel, QPixmap, QProgressBar, Qt, QTimer, QUrl, QVBoxLayout from qt.core import QDialog, QDialogButtonBox, QImageReader, QLabel, QMimeData, QPixmap, QProgressBar, Qt, QTimer, QUrl, QVBoxLayout
from calibre import as_unicode, browser, prints from calibre import as_unicode, browser, prints
from calibre.constants import DEBUG, iswindows from calibre.constants import DEBUG, iswindows
@ -386,3 +386,12 @@ def get_firefox_rurl(md, exts):
def has_firefox_ext(md, exts): def has_firefox_ext(md, exts):
return bool(get_firefox_rurl(md, exts)[0]) return bool(get_firefox_rurl(md, exts)[0])
def set_urls_from_local_file_paths(md: QMimeData, *paths: str) -> QMimeData:
# see https://bugreports.qt.io/browse/QTBUG-134073
md.setUrls(list(map(QUrl.fromLocalFile, paths)))
raw = bytes(md.data('text/uri-list'))
raw = raw.replace(b'[', b'%5B').replace(b']', b'%5D')
md.setData('text/uri-list', raw)
return md

View File

@ -48,7 +48,6 @@ from qt.core import (
QTimer, QTimer,
QToolTip, QToolTip,
QTreeView, QTreeView,
QUrl,
pyqtProperty, pyqtProperty,
pyqtSignal, pyqtSignal,
pyqtSlot, pyqtSlot,
@ -208,7 +207,7 @@ def drag_data(self):
md.setData('application/calibre+from_library', ids.encode('utf-8')) md.setData('application/calibre+from_library', ids.encode('utf-8'))
fmt = prefs['output_format'] fmt = prefs['output_format']
def url_for_id(i): def path_for_id(i):
try: try:
ans = db.format_path(i, fmt, index_is_id=True) ans = db.format_path(i, fmt, index_is_id=True)
except: except:
@ -226,9 +225,10 @@ def drag_data(self):
ans = None ans = None
if ans is None: if ans is None:
ans = db.abspath(i, index_is_id=True) ans = db.abspath(i, index_is_id=True)
return QUrl.fromLocalFile(ans) return ans
md.setUrls([url_for_id(i) for i in selected]) from calibre.gui2.dnd import set_urls_from_local_file_paths
set_urls_from_local_file_paths(md, *[path_for_id(i) for i in selected])
drag = QDrag(self) drag = QDrag(self)
col = self.selectionModel().currentIndex().column() col = self.selectionModel().currentIndex().column()
try: try:

View File

@ -36,7 +36,6 @@ from qt.core import (
Qt, Qt,
QTableView, QTableView,
QTimer, QTimer,
QUrl,
pyqtSignal, pyqtSignal,
) )
@ -1623,7 +1622,8 @@ class DeviceBooksView(BooksView): # {{{
paths = [force_unicode(p, enc=filesystem_encoding) for p in m.paths(rows) if p] paths = [force_unicode(p, enc=filesystem_encoding) for p in m.paths(rows) if p]
md = QMimeData() md = QMimeData()
md.setData('application/calibre+from_device', b'dummy') md.setData('application/calibre+from_device', b'dummy')
md.setUrls([QUrl.fromLocalFile(p) for p in paths]) from calibre.gui2.dnd import set_urls_from_local_file_paths
set_urls_from_local_file_paths(md, *paths)
drag = QDrag(self) drag = QDrag(self)
drag.setMimeData(md) drag.setMimeData(md)
cover = self.drag_icon(m.cover(self.currentIndex().row()), len(paths) > 1) cover = self.drag_icon(m.cover(self.currentIndex().row()), len(paths) > 1)

View File

@ -1613,7 +1613,8 @@ class Boss(QObject):
name:container.get_file_path_for_processing(name, allow_modification=False) name:container.get_file_path_for_processing(name, allow_modification=False)
for name in names for name in names
} }
md.setUrls(list(map(QUrl.fromLocalFile, list(url_map.values())))) from calibre.gui2.dnd import set_urls_from_local_file_paths
set_urls_from_local_file_paths(md, *url_map.values())
import json import json
md.setData(FILE_COPY_MIME, as_bytes(json.dumps({ md.setData(FILE_COPY_MIME, as_bytes(json.dumps({
name: (url_map[name], container.mime_map.get(name)) for name in names name: (url_map[name], container.mime_map.get(name)) for name in names