From 0e1e7d1dd7ede3f9ced9b21f44f5cdded7b5de50 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Sun, 29 Dec 2024 14:11:07 +0000 Subject: [PATCH] The fix for https://bugs.launchpad.net/calibre/+bug/2092643 isn't enough. Sometimes Qt opens the "wrong" editor on a column with a dialog for an editor, which remains open because closeEditor doesn't close them properly. You can see this by pressing Tab twice rapidly, which can nullify the effects of the singleShot timer. This fix prevents these "wrong" dialogs from opening. It also fixes the original issue in the bug because the currentIndex() isn't incorrectly changed. --- src/calibre/gui2/library/delegates.py | 47 +++++++++++++++++++++++++++ src/calibre/gui2/library/views.py | 2 -- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py index 39718265b7..e3c11e3ee8 100644 --- a/src/calibre/gui2/library/delegates.py +++ b/src/calibre/gui2/library/delegates.py @@ -202,6 +202,19 @@ def get_val_for_textlike_columns(index_): # }}} +# When closing an editor and opening another, Qt sometimes picks what appears to +# be a random line and column for the second editor. This function checks that +# the row of a new editor is the same as the current row in the view. If it +# isn't then the caller shouldn't open the editor. +def check_index_of_editor(delegate, index): + ans = delegate.table_widget.currentIndex().row() == index.row() + if not ans: + print(f'check_index_of_editor False. delegate: {delegate.__class__.__name__}.' + f'current row: {delegate.table_widget.currentIndex().row()}, ' + f'specified row: {index.row()}, specified column:{index.column()}') + return ans + + class RatingDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ def __init__(self, *args, **kwargs): @@ -222,6 +235,8 @@ class RatingDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ return rating_to_stars(value, self.is_half_star) def createEditor(self, parent, option, index): + if not check_index_of_editor(self, index): + return None return RatingEditor(parent, is_half_star=self.is_half_star) def setEditorData(self, editor, index): @@ -266,6 +281,8 @@ class DateDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ return format_date(d, self.format) def createEditor(self, parent, option, index): + if not check_index_of_editor(self, index): + return None return DateTimeEdit(parent, self.format) def setEditorData(self, editor, index): @@ -300,6 +317,8 @@ class PubDateDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ return format_date(d, self.format) def createEditor(self, parent, option, index): + if not check_index_of_editor(self, index): + return None return DateTimeEdit(parent, self.format) def setEditorData(self, editor, index): @@ -335,6 +354,8 @@ class TextDelegate(QStyledItemDelegate, UpdateEditorGeometry, EditableTextDelega self.auto_complete_function = f def createEditor(self, parent, option, index): + if not check_index_of_editor(self, index): + return None if self.auto_complete_function: if self.use_title_sort: editor = EditWithComplete(parent, sort_func=title_sort) @@ -381,6 +402,8 @@ class CompleteDelegate(QStyledItemDelegate, UpdateEditorGeometry, EditableTextDe self.db = db def createEditor(self, parent, option, index): + if not check_index_of_editor(self, index): + return None if self.db and hasattr(self.db, self.items_func_name): m = index.model() col = m.column_map[index.column()] @@ -425,6 +448,8 @@ class LanguagesDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ self.table_widget = parent def createEditor(self, parent, option, index): + if not check_index_of_editor(self, index): + return None editor = LanguagesEdit(parent=parent) editor.init_langs(index.model().db) return editor @@ -466,6 +491,8 @@ class CcDateDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ return format_date(d, self.format) def createEditor(self, parent, option, index): + if not check_index_of_editor(self, index): + return None return DateTimeEdit(parent, self.format) def setEditorData(self, editor, index): @@ -502,6 +529,8 @@ class CcTextDelegate(QStyledItemDelegate, UpdateEditorGeometry, EditableTextDele self.table_widget = parent def createEditor(self, parent, option, index): + if not check_index_of_editor(self, index): + return None m = index.model() col = m.column_map[index.column()] key = m.db.field_metadata.key_to_label(col) @@ -547,9 +576,12 @@ class CcLongTextDelegate(QStyledItemDelegate): # {{{ def __init__(self, parent): QStyledItemDelegate.__init__(self, parent) + self.table_widget = parent self.document = QTextDocument() def createEditor(self, parent, option, index): + if not check_index_of_editor(self, index): + return None m = index.model() col = m.column_map[index.column()] if check_key_modifier(Qt.KeyboardModifier.ControlModifier): @@ -574,6 +606,7 @@ class CcMarkdownDelegate(QStyledItemDelegate): # {{{ def __init__(self, parent): super().__init__(parent) + self.table_widget = parent self.document = QTextDocument() def paint(self, painter, option, index): @@ -599,6 +632,8 @@ class CcMarkdownDelegate(QStyledItemDelegate): # {{{ painter.restore() def createEditor(self, parent, option, index): + if not check_index_of_editor(self, index): + return None m = index.model() col = m.column_map[index.column()] if check_key_modifier(Qt.KeyboardModifier.ControlModifier): @@ -630,6 +665,8 @@ class CcNumberDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ self.table_widget = parent def createEditor(self, parent, option, index): + if not check_index_of_editor(self, index): + return None m = index.model() col = m.column_map[index.column()] if m.custom_columns[col]['datatype'] == 'int': @@ -682,6 +719,8 @@ class CcEnumDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ self.longest_text = '' def createEditor(self, parent, option, index): + if not check_index_of_editor(self, index): + return None m = index.model() col = m.column_map[index.column()] editor = DelegateCB(parent) @@ -726,6 +765,7 @@ class CcCommentsDelegate(QStyledItemDelegate): # {{{ def __init__(self, parent): QStyledItemDelegate.__init__(self, parent) + self.table_widget = parent self.document = QTextDocument() def paint(self, painter, option, index): @@ -751,6 +791,8 @@ class CcCommentsDelegate(QStyledItemDelegate): # {{{ painter.restore() def createEditor(self, parent, option, index): + if not check_index_of_editor(self, index): + return None m = index.model() col = m.column_map[index.column()] if check_key_modifier(Qt.KeyboardModifier.ControlModifier): @@ -791,6 +833,8 @@ class CcBoolDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ self.table_widget = parent def createEditor(self, parent, option, index): + if not check_index_of_editor(self, index): + return None editor = DelegateCB(parent) items = [_('Yes'), _('No'), _('Undefined')] icons = ['ok.png', 'list_remove.png', 'blank.png'] @@ -851,9 +895,12 @@ class CcTemplateDelegate(QStyledItemDelegate): # {{{ Delegate for composite custom_columns. ''' QStyledItemDelegate.__init__(self, parent) + self.table_widget = parent self.disallow_edit = gprefs['edit_metadata_templates_only_F2_on_booklist'] def createEditor(self, parent, option, index): + if not check_index_of_editor(self, index): + return None if self.disallow_edit: editor = QLineEdit(parent) editor.setText(_('Template editing disabled')) diff --git a/src/calibre/gui2/library/views.py b/src/calibre/gui2/library/views.py index fe66b01cbd..bdd7f6e2c7 100644 --- a/src/calibre/gui2/library/views.py +++ b/src/calibre/gui2/library/views.py @@ -1658,8 +1658,6 @@ class BooksView(QTableView): # {{{ if index.isValid(): self.setCurrentIndex(index) self.edit(index) - # This is needed for https://bugs.launchpad.net/calibre/+bug/2092643 - self._model.current_changed(index, None) QTimer.singleShot(0, edit) return ans