Enhancement #2002257: multiple template tester dialogs.

Also changed the quickview dialog to be parentless.
This commit is contained in:
Charles Haley 2023-01-09 16:29:13 +00:00
parent 779e69a38c
commit 56c1899868
3 changed files with 73 additions and 22 deletions

View File

@ -5,8 +5,6 @@ __license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>' __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
from qt.core import QDialog
from calibre.gui2.actions import InterfaceAction from calibre.gui2.actions import InterfaceAction
from calibre.gui2.dialogs.template_dialog import TemplateDialog from calibre.gui2.dialogs.template_dialog import TemplateDialog
from calibre.gui2 import error_dialog from calibre.gui2 import error_dialog
@ -23,6 +21,17 @@ class ShowTemplateTesterAction(InterfaceAction):
self.previous_text = _('Enter a template to test using data from the selected book') self.previous_text = _('Enter a template to test using data from the selected book')
self.first_time = True self.first_time = True
self.qaction.triggered.connect(self.show_template_editor) self.qaction.triggered.connect(self.show_template_editor)
self.window_title = self.action_spec[0]
# self.hidden_menu = QMenu()
# self.non_modal_window_title = _('Template tester -- separate dialog')
# self.shortcut_action = self.create_menu_action(
# menu=self.hidden_menu,
# unique_name='Template tester',
# text=self.non_modal_window_title,
# icon='debug.png',
# triggered=partial(self.show_template_editor, modal=False))
self.non_modal_dialogs = list()
def last_template_text(self): def last_template_text(self):
return self.previous_text return self.previous_text
@ -44,9 +53,27 @@ class ShowTemplateTesterAction(InterfaceAction):
if row.isValid(): if row.isValid():
mi.append(db.new_api.get_proxy_metadata(db.data.index_to_id(row.row()))) mi.append(db.new_api.get_proxy_metadata(db.data.index_to_id(row.row())))
if mi: if mi:
for dn in range(-1, len(self.non_modal_dialogs)):
if dn < 0:
continue
if self.non_modal_dialogs[dn] is None:
break
else:
dn = len(self.non_modal_dialogs)
if dn == len(self.non_modal_dialogs):
self.non_modal_dialogs.append(True)
else:
self.non_modal_dialogs[dn] = True
t = TemplateDialog(self.gui, self.previous_text, t = TemplateDialog(self.gui, self.previous_text,
mi, text_is_placeholder=self.first_time) mi, text_is_placeholder=self.first_time,
t.setWindowTitle(_('Template tester')) dialog_number=dn)
if t.exec() == QDialog.DialogCode.Accepted: self.non_modal_dialogs[dn] = t
self.previous_text = t.rule[1] t.setWindowTitle(self.window_title, dialog_number=dn+1)
t.tester_closed.connect(self.save_template_text)
t.show()
def save_template_text(self, txt, dialog_number):
if txt is not None:
self.previous_text = txt
self.first_time = False self.first_time = False
self.non_modal_dialogs[dialog_number] = None

View File

@ -154,11 +154,10 @@ class Quickview(QDialog, Ui_Quickview):
def __init__(self, gui, row, toggle_shortcut): def __init__(self, gui, row, toggle_shortcut):
self.is_pane = gprefs.get('quickview_is_pane', False) self.is_pane = gprefs.get('quickview_is_pane', False)
if not self.is_pane: if not self.is_pane:
QDialog.__init__(self, gui, flags=Qt.WindowType.Widget) QDialog.__init__(self, None, flags=Qt.WindowType.Window)
else: else:
QDialog.__init__(self, gui) QDialog.__init__(self, None, flags=Qt.WindowType.Dialog)
Ui_Quickview.__init__(self) Ui_Quickview.__init__(self)
self.setupUi(self) self.setupUi(self)
self.isClosed = False self.isClosed = False

View File

@ -15,7 +15,7 @@ from qt.core import (
QAbstractItemView, QApplication, QColor, QComboBox, QCursor, QDialog, QAbstractItemView, QApplication, QColor, QComboBox, QCursor, QDialog,
QDialogButtonBox, QFont, QFontDatabase, QFontInfo, QFontMetrics, QIcon, QLineEdit, QDialogButtonBox, QFont, QFontDatabase, QFontInfo, QFontMetrics, QIcon, QLineEdit,
QPalette, QSize, QSyntaxHighlighter, Qt, QTableWidget, QTableWidgetItem, QPalette, QSize, QSyntaxHighlighter, Qt, QTableWidget, QTableWidgetItem,
QTextCharFormat, QTextOption, QVBoxLayout, QTextCharFormat, QTextOption, QVBoxLayout, pyqtSignal
) )
from calibre import sanitize_file_name from calibre import sanitize_file_name
@ -316,15 +316,35 @@ translate_table = str.maketrans({
class TemplateDialog(QDialog, Ui_TemplateDialog): class TemplateDialog(QDialog, Ui_TemplateDialog):
tester_closed = pyqtSignal(object, object)
def setWindowTitle(self, title, dialog_number=None):
if dialog_number is None:
title = _('{title} (only one template dialog allowed)').format(title=title)
else:
title = _('{title} dialog number {number} (multiple template dialogs allowed)').format(
title=title, number=dialog_number)
super().setWindowTitle(title)
def __init__(self, parent, text, mi=None, fm=None, color_field=None, def __init__(self, parent, text, mi=None, fm=None, color_field=None,
icon_field_key=None, icon_rule_kind=None, doing_emblem=False, icon_field_key=None, icon_rule_kind=None, doing_emblem=False,
text_is_placeholder=False, dialog_is_st_editor=False, text_is_placeholder=False, dialog_is_st_editor=False,
global_vars=None, all_functions=None, builtin_functions=None, global_vars=None, all_functions=None, builtin_functions=None,
python_context_object=None): python_context_object=None, dialog_number=None):
QDialog.__init__(self, parent) # If dialog_number isn't None then we want separate non-modal windows
# that don't stay on top of the main dialog. This lets Alt-Tab work to
# switch between them. dialog_number must be set only by the template
# tester, not the rules dialogs etc that depend on modality.
if dialog_number is None:
QDialog.__init__(self, parent, flags=Qt.WindowType.Dialog)
else:
QDialog.__init__(self, None, flags=Qt.WindowType.Window)
self.raise_() # Not needed on windows but here just in case
Ui_TemplateDialog.__init__(self) Ui_TemplateDialog.__init__(self)
self.setupUi(self) self.setupUi(self)
self.setWindowIcon(self.windowIcon())
self.dialog_number = dialog_number
self.coloring = color_field is not None self.coloring = color_field is not None
self.iconing = icon_field_key is not None self.iconing = icon_field_key is not None
self.embleming = doing_emblem self.embleming = doing_emblem
@ -387,10 +407,6 @@ class TemplateDialog(QDialog, Ui_TemplateDialog):
self.icon_field.setCurrentIndex(self.icon_field.findData(icon_field_key)) self.icon_field.setCurrentIndex(self.icon_field.findData(icon_field_key))
self.setup_saved_template_editor(not dialog_is_st_editor, dialog_is_st_editor) self.setup_saved_template_editor(not dialog_is_st_editor, dialog_is_st_editor)
# Remove help icon on title bar
icon = self.windowIcon()
self.setWindowFlags(self.windowFlags()&(~Qt.WindowType.WindowContextHelpButtonHint))
self.setWindowIcon(icon)
self.all_functions = all_functions if all_functions else formatter_functions().get_functions() self.all_functions = all_functions if all_functions else formatter_functions().get_functions()
self.builtins = (builtin_functions if builtin_functions else self.builtins = (builtin_functions if builtin_functions else
@ -411,8 +427,7 @@ class TemplateDialog(QDialog, Ui_TemplateDialog):
# Set up the display table # Set up the display table
self.table_column_widths = None self.table_column_widths = None
try: try:
self.table_column_widths = \ self.table_column_widths = gprefs.get(self.geometry_string('template_editor_table_widths'), None)
gprefs.get('template_editor_table_widths', None)
except: except:
pass pass
self.set_mi(mi, fm) self.set_mi(mi, fm)
@ -483,7 +498,12 @@ class TemplateDialog(QDialog, Ui_TemplateDialog):
self.textbox.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) self.textbox.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
self.textbox.customContextMenuRequested.connect(self.show_context_menu) self.textbox.customContextMenuRequested.connect(self.show_context_menu)
# Now geometry # Now geometry
self.restore_geometry(gprefs, 'template_editor_dialog_geometry') self.restore_geometry(gprefs, self.geometry_string('template_editor_dialog_geometry'))
def geometry_string(self, txt):
if self.dialog_number is None or self.dialog_number == 0:
return txt
return txt + '_' + str(self.dialog_number)
def setup_saved_template_editor(self, show_buttonbox, show_doc_and_name): def setup_saved_template_editor(self, show_buttonbox, show_doc_and_name):
self.buttonBox.setVisible(show_buttonbox) self.buttonBox.setVisible(show_buttonbox)
@ -890,8 +910,8 @@ def evaluate(book, context):
self.table_column_widths.append(self.template_value.columnWidth(c)) self.table_column_widths.append(self.template_value.columnWidth(c))
def save_geometry(self): def save_geometry(self):
gprefs['template_editor_table_widths'] = self.table_column_widths gprefs[self.geometry_string('template_editor_table_widths')] = self.table_column_widths
super().save_geometry(gprefs, 'template_editor_dialog_geometry') super().save_geometry(gprefs, self.geometry_string('template_editor_dialog_geometry'))
def keyPressEvent(self, ev): def keyPressEvent(self, ev):
if ev.key() == Qt.Key.Key_Escape: if ev.key() == Qt.Key.Key_Escape:
@ -932,8 +952,11 @@ def evaluate(book, context):
self.rule = ('', txt) self.rule = ('', txt)
self.save_geometry() self.save_geometry()
QDialog.accept(self) QDialog.accept(self)
if self.dialog_number is not None:
self.tester_closed.emit(txt, self.dialog_number)
def reject(self): def reject(self):
self.save_geometry()
QDialog.reject(self) QDialog.reject(self)
if self.dialog_is_st_editor: if self.dialog_is_st_editor:
parent = self.parent() parent = self.parent()
@ -944,6 +967,8 @@ def evaluate(book, context):
parent = parent.parent() parent = parent.parent()
if parent is None: if parent is None:
break break
if self.dialog_number is not None:
self.tester_closed.emit(None, self.dialog_number)
class BreakReporterItem(QTableWidgetItem): class BreakReporterItem(QTableWidgetItem):