From 48a59e133371baca76a2f6eb91b2a9d44d59a1a1 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 5 May 2021 15:10:32 +0530 Subject: [PATCH] Add an abort button to the confirmation for moving large numbers of books to the recycle bin --- src/calibre/gui2/__init__.py | 11 +++++++++- src/calibre/gui2/actions/delete.py | 27 ++++++++++++++++--------- src/calibre/gui2/dialogs/message_box.py | 11 +++++++++- 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index e9f3779200..a0615d4e88 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -400,6 +400,10 @@ def error_dialog(parent, title, msg, det_msg='', show=False, return d +class Aborted(Exception): + pass + + def question_dialog(parent, title, msg, det_msg='', show_copy_button=False, default_yes=True, # Skippable dialogs @@ -412,6 +416,9 @@ def question_dialog(parent, title, msg, det_msg='', show_copy_button=False, # Change the text/icons of the yes and no buttons. # The icons must be QIcon objects or strings for I() yes_text=None, no_text=None, yes_icon=None, no_icon=None, + # Add an Abort button which if clicked will cause this function to raise + # the Aborted exception + add_abort_button=False, ): from calibre.gui2.dialogs.message_box import MessageBox prefs = gui_prefs() @@ -428,7 +435,7 @@ def question_dialog(parent, title, msg, det_msg='', show_copy_button=False, d = MessageBox(MessageBox.QUESTION, title, msg, det_msg, parent=parent, show_copy_button=show_copy_button, default_yes=default_yes, q_icon=override_icon, yes_text=yes_text, no_text=no_text, - yes_icon=yes_icon, no_icon=no_icon) + yes_icon=yes_icon, no_icon=no_icon, add_abort_button=add_abort_button) if skip_dialog_name is not None and skip_dialog_msg: tc = d.toggle_checkbox @@ -438,6 +445,8 @@ def question_dialog(parent, title, msg, det_msg='', show_copy_button=False, d.resize_needed.emit() ret = d.exec_() == QDialog.DialogCode.Accepted + if add_abort_button and d.aborted: + raise Aborted() if skip_dialog_name is not None and not d.toggle_checkbox.isChecked(): auto_skip.add(skip_dialog_name) diff --git a/src/calibre/gui2/actions/delete.py b/src/calibre/gui2/actions/delete.py index fc96e12bdc..edcbc485ef 100644 --- a/src/calibre/gui2/actions/delete.py +++ b/src/calibre/gui2/actions/delete.py @@ -6,18 +6,20 @@ __license__ = 'GPL v3' __copyright__ = '2010, Kovid Goyal ' __docformat__ = 'restructuredtext en' -import errno, os -from functools import partial +import errno +import os from collections import Counter - -from qt.core import QObject, QTimer, QModelIndex, QDialog +from functools import partial +from qt.core import QDialog, QModelIndex, QObject, QTimer from calibre.constants import ismacos -from calibre.gui2 import error_dialog, question_dialog -from calibre.gui2.dialogs.delete_matching_from_device import DeleteMatchingFromDeviceDialog +from calibre.gui2 import Aborted, error_dialog, question_dialog +from calibre.gui2.actions import InterfaceAction from calibre.gui2.dialogs.confirm_delete import confirm from calibre.gui2.dialogs.confirm_delete_location import confirm_location -from calibre.gui2.actions import InterfaceAction +from calibre.gui2.dialogs.delete_matching_from_device import ( + DeleteMatchingFromDeviceDialog +) from calibre.utils.recycle_bin import can_recycle single_shot = partial(QTimer.singleShot, 10) @@ -37,7 +39,9 @@ class MultiDeleter(QObject): # {{{ 'Sending so many files to the Recycle' ' Bin can be slow. Should calibre skip the' ' Recycle Bin? If you click Yes the files' - ' will be permanently deleted.')%len(ids)): + ' will be permanently deleted.')%len(ids), + add_abort_button=True + ): self.permanent = True self.gui = gui self.failures = [] @@ -388,8 +392,11 @@ class DeleteAction(InterfaceAction): raise self.library_ids_deleted2(to_delete_ids, next_id=next_id) else: - self.__md = MultiDeleter(self.gui, to_delete_ids, - partial(self.library_ids_deleted2, next_id=next_id)) + try: + self.__md = MultiDeleter(self.gui, to_delete_ids, + partial(self.library_ids_deleted2, next_id=next_id)) + except Aborted: + pass def delete_books(self, *args): ''' diff --git a/src/calibre/gui2/dialogs/message_box.py b/src/calibre/gui2/dialogs/message_box.py index c1c3817082..c5ce4ecdbc 100644 --- a/src/calibre/gui2/dialogs/message_box.py +++ b/src/calibre/gui2/dialogs/message_box.py @@ -82,8 +82,11 @@ class MessageBox(QDialog): # {{{ q_icon=None, show_copy_button=True, parent=None, default_yes=True, - yes_text=None, no_text=None, yes_icon=None, no_icon=None): + yes_text=None, no_text=None, yes_icon=None, no_icon=None, + add_abort_button=False + ): QDialog.__init__(self, parent) + self.aborted = False if q_icon is None: icon = { self.ERROR : 'error', @@ -139,12 +142,18 @@ class MessageBox(QDialog): # {{{ else: self.bb.button(QDialogButtonBox.StandardButton.Ok).setDefault(True) + if add_abort_button: + self.bb.addButton(QDialogButtonBox.StandardButton.Abort).clicked.connect(self.on_abort) + if not det_msg: self.det_msg_toggle.setVisible(False) self.resize_needed.connect(self.do_resize, type=Qt.ConnectionType.QueuedConnection) self.do_resize() + def on_abort(self): + self.aborted = True + def sizeHint(self): ans = QDialog.sizeHint(self) ans.setWidth(max(min(ans.width(), 500), self.bb.sizeHint().width() + 100))