From 815fb4bc30299d44dc26d4d80bc2900770844af3 Mon Sep 17 00:00:00 2001
From: un-pogaz <46523284+un-pogaz@users.noreply.github.com>
Date: Mon, 27 Apr 2026 16:17:56 +0200
Subject: [PATCH] allow auto close when all jobs finished
---
src/calibre/gui2/__init__.py | 6 +++++
src/calibre/gui2/dialogs/jobs.ui | 11 ++++++++
src/calibre/gui2/dialogs/message_box.py | 34 +++++++++++++++++++++++++
src/calibre/gui2/ui.py | 27 +++++++++++++++++++-
4 files changed, 77 insertions(+), 1 deletion(-)
diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py
index 6e8e9e1003..4aab84f769 100644
--- a/src/calibre/gui2/__init__.py
+++ b/src/calibre/gui2/__init__.py
@@ -843,6 +843,12 @@ def show_restart_warning(msg, parent=None):
return d.do_restart
+def show_auto_close_warning(parent, timeout=30):
+ from calibre.gui2.dialogs.message_box import AutoCloseNotification
+ d = AutoCloseNotification(parent=parent, timeout=timeout)
+ return d.exec() == QDialog.DialogCode.Accepted
+
+
class Dispatcher(QObject):
'''
Convenience class to use Qt signals with arbitrary python callables.
diff --git a/src/calibre/gui2/dialogs/jobs.ui b/src/calibre/gui2/dialogs/jobs.ui
index c91017b5ef..a582c877ea 100644
--- a/src/calibre/gui2/dialogs/jobs.ui
+++ b/src/calibre/gui2/dialogs/jobs.ui
@@ -106,6 +106,17 @@
+ -
+
+
+ &Automatically close calibre after all jobs are finished
+
+
+
+ :/images/dialog_warning.png:/images/dialog_warning.png
+
+
+
diff --git a/src/calibre/gui2/dialogs/message_box.py b/src/calibre/gui2/dialogs/message_box.py
index 7dd810e59b..28ce0235fc 100644
--- a/src/calibre/gui2/dialogs/message_box.py
+++ b/src/calibre/gui2/dialogs/message_box.py
@@ -25,6 +25,7 @@ from qt.core import (
Qt,
QTextBrowser,
QTextDocument,
+ QTimer,
QVBoxLayout,
QWidget,
pyqtSignal,
@@ -378,6 +379,39 @@ class ErrorNotification(MessageBox): # {{{
# }}}
+class AutoCloseNotification(MessageBox): # {{{
+
+ def __init__(self, timeout=30, parent=None):
+ super().__init__(
+ MessageBox.QUESTION,
+ _('calibre automatic closing'),
+ _('calibre is about to close automatically. Do you want to confim or abort the action?'),
+ parent=parent,
+ show_copy_button=False,
+ q_icon='dialog_warning.png',
+ default_yes=True,
+ yes_text=None,
+ no_text=_('Abort'),
+ )
+ self.timeout = timeout
+ self.timer = QTimer(self)
+ self.timer.setInterval(self.timeout * 1000)
+ self.timer.timeout.connect(self.accept)
+ self.timer.setSingleShot(True)
+ self.updater = QTimer(self)
+ self.updater.setInterval(1000)
+ self.updater.timeout.connect(self.update_texts)
+ self.updater.setSingleShot(False)
+ self.timer.start()
+ self.updater.start()
+ self.update_texts()
+
+ def update_texts(self):
+ time = self.timer.remainingTime() // 1000
+ self.bb.button(QDialogButtonBox.StandardButton.Yes).setText(_('Close now ({}s)').format(time))
+# }}}
+
+
class JobError(QDialog): # {{{
WIDTH = 600
diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py
index 3082231192..7171b35436 100644
--- a/src/calibre/gui2/ui.py
+++ b/src/calibre/gui2/ui.py
@@ -26,7 +26,19 @@ from calibre.constants import DEBUG, __appname__, config_dir, filesystem_encodin
from calibre.customize import PluginInstallationType
from calibre.customize.ui import available_store_plugins, interface_actions
from calibre.db.legacy import LibraryDatabase
-from calibre.gui2 import Dispatcher, GetMetadata, config, error_dialog, gprefs, info_dialog, max_available_height, open_url, question_dialog, warning_dialog
+from calibre.gui2 import (
+ Dispatcher,
+ GetMetadata,
+ config,
+ error_dialog,
+ gprefs,
+ info_dialog,
+ max_available_height,
+ open_url,
+ question_dialog,
+ show_auto_close_warning,
+ warning_dialog,
+)
from calibre.gui2.auto_add import AutoAdder
from calibre.gui2.changes import handle_changes
from calibre.gui2.cover_flow import CoverFlowMixin
@@ -238,6 +250,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
self.jobs_dialog = JobsDialog(self, self.job_manager)
self.jobs_button = JobsButton(parent=self)
self.jobs_button.initialize(self.jobs_dialog, self.job_manager)
+ self.job_manager.job_done.connect(self._jobs_auto_close)
# }}}
LayoutMixin.init_layout_mixin(self)
@@ -1219,6 +1232,18 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
self.system_tray_icon.setVisible(False)
QApplication.instance().exit()
+ def _jobs_auto_close(self, nnum):
+ if self.jobs_dialog.auto_close_calibre.isChecked() and nnum == 0:
+ self.auto_close_calibre()
+
+ def auto_close_calibre(self):
+ timed_print('Auto-closing asked...')
+ if show_auto_close_warning(self):
+ self.quit(confirm_quit=False)
+ else:
+ timed_print('Auto-closing rejected')
+ self.jobs_dialog.auto_close_calibre.setChecked(False)
+
def donate(self, *args):
from calibre.utils.localization import localize_website_link
open_url(QUrl(localize_website_link('https://calibre-ebook.com/donate')))