From 87e8c06819c2cde7497dad3c66a4ac01292adced Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 25 Feb 2025 17:35:32 +0530 Subject: [PATCH] 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 --- src/calibre/gui2/dnd.py | 11 ++++++++++- src/calibre/gui2/library/alternate_views.py | 8 ++++---- src/calibre/gui2/library/views.py | 4 ++-- src/calibre/gui2/tweak_book/boss.py | 3 ++- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/calibre/gui2/dnd.py b/src/calibre/gui2/dnd.py index 3b09b494fc..cfdaab2b58 100644 --- a/src/calibre/gui2/dnd.py +++ b/src/calibre/gui2/dnd.py @@ -11,7 +11,7 @@ import re from contextlib import suppress 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.constants import DEBUG, iswindows @@ -386,3 +386,12 @@ def get_firefox_rurl(md, exts): def has_firefox_ext(md, exts): 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 diff --git a/src/calibre/gui2/library/alternate_views.py b/src/calibre/gui2/library/alternate_views.py index bc69e5c92b..74510abfea 100644 --- a/src/calibre/gui2/library/alternate_views.py +++ b/src/calibre/gui2/library/alternate_views.py @@ -48,7 +48,6 @@ from qt.core import ( QTimer, QToolTip, QTreeView, - QUrl, pyqtProperty, pyqtSignal, pyqtSlot, @@ -208,7 +207,7 @@ def drag_data(self): md.setData('application/calibre+from_library', ids.encode('utf-8')) fmt = prefs['output_format'] - def url_for_id(i): + def path_for_id(i): try: ans = db.format_path(i, fmt, index_is_id=True) except: @@ -226,9 +225,10 @@ def drag_data(self): ans = None if ans is None: 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) col = self.selectionModel().currentIndex().column() try: diff --git a/src/calibre/gui2/library/views.py b/src/calibre/gui2/library/views.py index 0a7a7a46f9..8d2a745b79 100644 --- a/src/calibre/gui2/library/views.py +++ b/src/calibre/gui2/library/views.py @@ -36,7 +36,6 @@ from qt.core import ( Qt, QTableView, QTimer, - QUrl, pyqtSignal, ) @@ -1623,7 +1622,8 @@ class DeviceBooksView(BooksView): # {{{ paths = [force_unicode(p, enc=filesystem_encoding) for p in m.paths(rows) if p] md = QMimeData() 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.setMimeData(md) cover = self.drag_icon(m.cover(self.currentIndex().row()), len(paths) > 1) diff --git a/src/calibre/gui2/tweak_book/boss.py b/src/calibre/gui2/tweak_book/boss.py index da9662e70c..637bfa3795 100644 --- a/src/calibre/gui2/tweak_book/boss.py +++ b/src/calibre/gui2/tweak_book/boss.py @@ -1613,7 +1613,8 @@ class Boss(QObject): name:container.get_file_path_for_processing(name, allow_modification=False) 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 md.setData(FILE_COPY_MIME, as_bytes(json.dumps({ name: (url_map[name], container.mime_map.get(name)) for name in names