From 0e1e7d1dd7ede3f9ced9b21f44f5cdded7b5de50 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Sun, 29 Dec 2024 14:11:07 +0000 Subject: [PATCH 1/4] 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 From 9eaef3ceb001407646b13146090528ff0f056229 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Sun, 29 Dec 2024 15:10:31 +0000 Subject: [PATCH 2/4] This is a more elegant implementation of the changes to delegates.py. --- src/calibre/gui2/library/delegates.py | 161 ++++++++++++-------------- 1 file changed, 74 insertions(+), 87 deletions(-) diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py index e3c11e3ee8..259ec2eb3a 100644 --- a/src/calibre/gui2/library/delegates.py +++ b/src/calibre/gui2/library/delegates.py @@ -202,23 +202,40 @@ 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): # {{{ +class StyledItemDelegate(QStyledItemDelegate): + + ''' + 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 __init__(self, *args, **kwargs): - QStyledItemDelegate.__init__(self, *args) + super().__init__(*args, **kwargs) + self.table_widget = args[0] + + def createEditor(self, parent, option, index): + if self.table_widget.currentIndex().row() != index.row(): + print(f'createEditor row error: delegate: {self.__class__.__name__}. ' + f'row: {self.table_widget.currentIndex().row()}, ' + f'index row: {index.row()}, index column:{index.column()}') + return None + return self.create_editor(parent, option, index) + + def create_editor(self, parent, option, index): + # Must be overridden by the "real" createEditor + raise NotImplementedError + + +class RatingDelegate(StyledItemDelegate, UpdateEditorGeometry): # {{{ + + def __init__(self, *args, **kwargs): + StyledItemDelegate.__init__(self, *args) self.is_half_star = kwargs.get('is_half_star', False) self.table_widget = args[0] self.rf = QFont(rating_font()) @@ -234,9 +251,7 @@ class RatingDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ def displayText(self, value, locale): 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 + def create_editor(self, parent, option, index): return RatingEditor(parent, is_half_star=self.is_half_star) def setEditorData(self, editor, index): @@ -253,21 +268,21 @@ class RatingDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ def sizeHint(self, option, index): option.font = self.rf option.textElideMode = self.em - return QStyledItemDelegate.sizeHint(self, option, index) + return StyledItemDelegate.sizeHint(self, option, index) def paint(self, painter, option, index): option.font = self.rf option.textElideMode = self.em - return QStyledItemDelegate.paint(self, painter, option, index) + return StyledItemDelegate.paint(self, painter, option, index) # }}} -class DateDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ +class DateDelegate(StyledItemDelegate, UpdateEditorGeometry): # {{{ def __init__(self, parent, tweak_name='gui_timestamp_display_format', default_format='dd MMM yyyy'): - QStyledItemDelegate.__init__(self, parent) + StyledItemDelegate.__init__(self, parent) self.table_widget = parent self.tweak_name = tweak_name self.format = tweaks[self.tweak_name] @@ -280,9 +295,7 @@ class DateDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ return '' return format_date(d, self.format) - def createEditor(self, parent, option, index): - if not check_index_of_editor(self, index): - return None + def create_editor(self, parent, option, index): return DateTimeEdit(parent, self.format) def setEditorData(self, editor, index): @@ -301,10 +314,10 @@ class DateDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ # }}} -class PubDateDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ +class PubDateDelegate(StyledItemDelegate, UpdateEditorGeometry): # {{{ def __init__(self, *args, **kwargs): - QStyledItemDelegate.__init__(self, *args, **kwargs) + StyledItemDelegate.__init__(self, *args, **kwargs) self.format = tweaks['gui_pubdate_display_format'] self.table_widget = args[0] if self.format is None: @@ -316,9 +329,7 @@ class PubDateDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ return '' return format_date(d, self.format) - def createEditor(self, parent, option, index): - if not check_index_of_editor(self, index): - return None + def create_editor(self, parent, option, index): return DateTimeEdit(parent, self.format) def setEditorData(self, editor, index): @@ -336,7 +347,7 @@ class PubDateDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ # }}} -class TextDelegate(QStyledItemDelegate, UpdateEditorGeometry, EditableTextDelegate): # {{{ +class TextDelegate(StyledItemDelegate, UpdateEditorGeometry, EditableTextDelegate): # {{{ use_title_sort = False @@ -346,16 +357,14 @@ class TextDelegate(QStyledItemDelegate, UpdateEditorGeometry, EditableTextDelega of text items to auto-complete with. If the function is None no auto-complete will be used. ''' - QStyledItemDelegate.__init__(self, parent) + StyledItemDelegate.__init__(self, parent) self.table_widget = parent self.auto_complete_function = None def set_auto_complete_function(self, f): self.auto_complete_function = f - def createEditor(self, parent, option, index): - if not check_index_of_editor(self, index): - return None + def create_editor(self, parent, option, index): if self.auto_complete_function: if self.use_title_sort: editor = EditWithComplete(parent, sort_func=title_sort) @@ -374,7 +383,7 @@ class TextDelegate(QStyledItemDelegate, UpdateEditorGeometry, EditableTextDelega val = editor.lineEdit().text() model.setData(index, (val), Qt.ItemDataRole.EditRole) else: - QStyledItemDelegate.setModelData(self, editor, model, index) + StyledItemDelegate.setModelData(self, editor, model, index) # }}} @@ -389,10 +398,10 @@ class SeriesDelegate(TextDelegate): # {{{ # }}} -class CompleteDelegate(QStyledItemDelegate, UpdateEditorGeometry, EditableTextDelegate): # {{{ +class CompleteDelegate(StyledItemDelegate, UpdateEditorGeometry, EditableTextDelegate): # {{{ def __init__(self, parent, sep, items_func_name, space_before_sep=False): - QStyledItemDelegate.__init__(self, parent) + StyledItemDelegate.__init__(self, parent) self.sep = sep self.items_func_name = items_func_name self.space_before_sep = space_before_sep @@ -401,9 +410,7 @@ class CompleteDelegate(QStyledItemDelegate, UpdateEditorGeometry, EditableTextDe def set_database(self, db): self.db = db - def createEditor(self, parent, option, index): - if not check_index_of_editor(self, index): - return None + def create_editor(self, parent, option, index): if self.db and hasattr(self.db, self.items_func_name): m = index.model() col = m.column_map[index.column()] @@ -437,19 +444,17 @@ class CompleteDelegate(QStyledItemDelegate, UpdateEditorGeometry, EditableTextDe val = editor.lineEdit().text() model.setData(index, (val), Qt.ItemDataRole.EditRole) else: - QStyledItemDelegate.setModelData(self, editor, model, index) + StyledItemDelegate.setModelData(self, editor, model, index) # }}} -class LanguagesDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ +class LanguagesDelegate(StyledItemDelegate, UpdateEditorGeometry): # {{{ def __init__(self, parent): - QStyledItemDelegate.__init__(self, parent) + StyledItemDelegate.__init__(self, parent) self.table_widget = parent - def createEditor(self, parent, option, index): - if not check_index_of_editor(self, index): - return None + def create_editor(self, parent, option, index): editor = LanguagesEdit(parent=parent) editor.init_langs(index.model().db) return editor @@ -464,7 +469,7 @@ class LanguagesDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ # }}} -class CcDateDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ +class CcDateDelegate(StyledItemDelegate, UpdateEditorGeometry): # {{{ ''' Delegate for custom columns dates. Because this delegate stores the @@ -473,7 +478,7 @@ class CcDateDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ ''' def __init__(self, parent): - QStyledItemDelegate.__init__(self, parent) + StyledItemDelegate.__init__(self, parent) self.table_widget = parent def set_format(self, _format): @@ -490,9 +495,7 @@ class CcDateDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ return '' return format_date(d, self.format) - def createEditor(self, parent, option, index): - if not check_index_of_editor(self, index): - return None + def create_editor(self, parent, option, index): return DateTimeEdit(parent, self.format) def setEditorData(self, editor, index): @@ -517,7 +520,7 @@ class CcDateDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ # }}} -class CcTextDelegate(QStyledItemDelegate, UpdateEditorGeometry, EditableTextDelegate): # {{{ +class CcTextDelegate(StyledItemDelegate, UpdateEditorGeometry, EditableTextDelegate): # {{{ ''' Delegate for text data. @@ -525,12 +528,10 @@ class CcTextDelegate(QStyledItemDelegate, UpdateEditorGeometry, EditableTextDele use_title_sort = False def __init__(self, parent): - QStyledItemDelegate.__init__(self, parent) + StyledItemDelegate.__init__(self, parent) self.table_widget = parent - def createEditor(self, parent, option, index): - if not check_index_of_editor(self, index): - return None + def create_editor(self, parent, option, index): m = index.model() col = m.column_map[index.column()] key = m.db.field_metadata.key_to_label(col) @@ -568,20 +569,18 @@ class CcSeriesDelegate(CcTextDelegate): # {{{ # }}} -class CcLongTextDelegate(QStyledItemDelegate): # {{{ +class CcLongTextDelegate(StyledItemDelegate): # {{{ ''' Delegate for comments data. ''' def __init__(self, parent): - QStyledItemDelegate.__init__(self, parent) + StyledItemDelegate.__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 + def create_editor(self, parent, option, index): m = index.model() col = m.column_map[index.column()] if check_key_modifier(Qt.KeyboardModifier.ControlModifier): @@ -598,7 +597,7 @@ class CcLongTextDelegate(QStyledItemDelegate): # {{{ # }}} -class CcMarkdownDelegate(QStyledItemDelegate): # {{{ +class CcMarkdownDelegate(StyledItemDelegate): # {{{ ''' Delegate for markdown data. @@ -631,9 +630,7 @@ class CcMarkdownDelegate(QStyledItemDelegate): # {{{ self.document.documentLayout().draw(painter, ctx) painter.restore() - def createEditor(self, parent, option, index): - if not check_index_of_editor(self, index): - return None + def create_editor(self, parent, option, index): m = index.model() col = m.column_map[index.column()] if check_key_modifier(Qt.KeyboardModifier.ControlModifier): @@ -654,19 +651,17 @@ class CcMarkdownDelegate(QStyledItemDelegate): # {{{ # }}} -class CcNumberDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ +class CcNumberDelegate(StyledItemDelegate, UpdateEditorGeometry): # {{{ ''' Delegate for text/int/float data. ''' def __init__(self, parent): - QStyledItemDelegate.__init__(self, parent) + StyledItemDelegate.__init__(self, parent) self.table_widget = parent - def createEditor(self, parent, option, index): - if not check_index_of_editor(self, index): - return None + def create_editor(self, parent, option, index): m = index.model() col = m.column_map[index.column()] if m.custom_columns[col]['datatype'] == 'int': @@ -707,20 +702,18 @@ class CcNumberDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ # }}} -class CcEnumDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ +class CcEnumDelegate(StyledItemDelegate, UpdateEditorGeometry): # {{{ ''' Delegate for text/int/float data. ''' def __init__(self, parent): - QStyledItemDelegate.__init__(self, parent) + StyledItemDelegate.__init__(self, parent) self.table_widget = parent self.longest_text = '' - def createEditor(self, parent, option, index): - if not check_index_of_editor(self, index): - return None + def create_editor(self, parent, option, index): m = index.model() col = m.column_map[index.column()] editor = DelegateCB(parent) @@ -757,14 +750,14 @@ class CcEnumDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ # }}} -class CcCommentsDelegate(QStyledItemDelegate): # {{{ +class CcCommentsDelegate(StyledItemDelegate): # {{{ ''' Delegate for comments data. ''' def __init__(self, parent): - QStyledItemDelegate.__init__(self, parent) + StyledItemDelegate.__init__(self, parent) self.table_widget = parent self.document = QTextDocument() @@ -790,9 +783,7 @@ class CcCommentsDelegate(QStyledItemDelegate): # {{{ self.document.documentLayout().draw(painter, ctx) painter.restore() - def createEditor(self, parent, option, index): - if not check_index_of_editor(self, index): - return None + def create_editor(self, parent, option, index): m = index.model() col = m.column_map[index.column()] if check_key_modifier(Qt.KeyboardModifier.ControlModifier): @@ -822,19 +813,17 @@ class DelegateCB(QComboBox): # {{{ # }}} -class CcBoolDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ +class CcBoolDelegate(StyledItemDelegate, UpdateEditorGeometry): # {{{ def __init__(self, parent): ''' Delegate for custom_column bool data. ''' self.nuke_option_data = False - QStyledItemDelegate.__init__(self, parent) + StyledItemDelegate.__init__(self, parent) self.table_widget = parent - def createEditor(self, parent, option, index): - if not check_index_of_editor(self, index): - return None + def create_editor(self, parent, option, index): editor = DelegateCB(parent) items = [_('Yes'), _('No'), _('Undefined')] icons = ['ok.png', 'list_remove.png', 'blank.png'] @@ -888,19 +877,17 @@ class CcBoolDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ # }}} -class CcTemplateDelegate(QStyledItemDelegate): # {{{ +class CcTemplateDelegate(StyledItemDelegate): # {{{ def __init__(self, parent): ''' Delegate for composite custom_columns. ''' - QStyledItemDelegate.__init__(self, parent) + StyledItemDelegate.__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 + def create_editor(self, parent, option, index): if self.disallow_edit: editor = QLineEdit(parent) editor.setText(_('Template editing disabled')) From b3b08b0e17b1446ac8d30eb084308e558bf932c2 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Mon, 30 Dec 2024 14:20:41 +0000 Subject: [PATCH 3/4] Another try at preventing random edit dialogs while not losing "editing" when tabbing over read-only fields. The problem of random dialogs is handled in delegates.py. Losing "editing" when tabbing is handled by jumping over fields that are readonly or are implemented by a doalog. This is a behavior change. We will see whether it will result in screams of complaint. NB: after hours of trying, this was the only solution I found to both the random dialog and the loss of editing. --- src/calibre/gui2/library/delegates.py | 15 +++++++++++---- src/calibre/gui2/library/views.py | 17 ++++++++++++++++- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py index 259ec2eb3a..9b1a03ce4a 100644 --- a/src/calibre/gui2/library/delegates.py +++ b/src/calibre/gui2/library/delegates.py @@ -218,12 +218,15 @@ class StyledItemDelegate(QStyledItemDelegate): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.table_widget = args[0] + # Set this to True here. It is up the the subclasses to set it to False if needed. + self.is_editable_with_tab = True def createEditor(self, parent, option, index): - if self.table_widget.currentIndex().row() != index.row(): - print(f'createEditor row error: delegate: {self.__class__.__name__}. ' - f'row: {self.table_widget.currentIndex().row()}, ' - f'index row: {index.row()}, index column:{index.column()}') + if self.table_widget.currentIndex() != index: + idx = self.table_widget.currentIndex() + print(f'createEditor idx err: delegate={self.__class__.__name__}. ' + f'cur idx=({idx.row()}, {idx.column()}), ' + f'given idx=({index.row()}, {index.column()})') return None return self.create_editor(parent, option, index) @@ -579,6 +582,7 @@ class CcLongTextDelegate(StyledItemDelegate): # {{{ StyledItemDelegate.__init__(self, parent) self.table_widget = parent self.document = QTextDocument() + self.is_editable_with_tab = False def create_editor(self, parent, option, index): m = index.model() @@ -607,6 +611,7 @@ class CcMarkdownDelegate(StyledItemDelegate): # {{{ super().__init__(parent) self.table_widget = parent self.document = QTextDocument() + self.is_editable_with_tab = False def paint(self, painter, option, index): self.initStyleOption(option, index) @@ -760,6 +765,7 @@ class CcCommentsDelegate(StyledItemDelegate): # {{{ StyledItemDelegate.__init__(self, parent) self.table_widget = parent self.document = QTextDocument() + self.is_editable_with_tab = False def paint(self, painter, option, index): self.initStyleOption(option, index) @@ -886,6 +892,7 @@ class CcTemplateDelegate(StyledItemDelegate): # {{{ StyledItemDelegate.__init__(self, parent) self.table_widget = parent self.disallow_edit = gprefs['edit_metadata_templates_only_F2_on_booklist'] + self.is_editable_with_tab = False def create_editor(self, parent, option, index): if self.disallow_edit: diff --git a/src/calibre/gui2/library/views.py b/src/calibre/gui2/library/views.py index bdd7f6e2c7..de13f3b0b7 100644 --- a/src/calibre/gui2/library/views.py +++ b/src/calibre/gui2/library/views.py @@ -1652,7 +1652,22 @@ class BooksView(QTableView): # {{{ hint = QAbstractItemDelegate.EndEditHint.NoHint ans = super().closeEditor(editor, hint) if move_by is not None and self.currentIndex() == orig and self.state() is not QAbstractItemView.State.EditingState: - index = self.moveCursor(move_by, Qt.KeyboardModifier.NoModifier) + # Skip over columns that aren't editable or are implemented by a dialog + while True: + index = self.moveCursor(move_by, Qt.KeyboardModifier.NoModifier) + if not index.isValid(): + break + self.setCurrentIndex(index) + m = self._model + col = m.column_map[index.column()] + if m.is_custom_column(col): + # Don't try to open editors implemented by dialogs such as + # markdown, composites and comments + if self.itemDelegateForIndex(index).is_editable_with_tab: + break + elif m.flags(index) & Qt.ItemFlag.ItemIsEditable: + # Standard editable column + break if index.isValid(): def edit(): if index.isValid(): From 82f63ea6f2611f243445695cbecb1bd656d5c357 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Mon, 30 Dec 2024 14:22:55 +0000 Subject: [PATCH 4/4] Remove unused code --- src/calibre/gui2/library/delegates.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py index 9b1a03ce4a..2aac2d6853 100644 --- a/src/calibre/gui2/library/delegates.py +++ b/src/calibre/gui2/library/delegates.py @@ -202,10 +202,6 @@ def get_val_for_textlike_columns(index_): # }}} -def check_index_of_editor(delegate, index): - return ans - - class StyledItemDelegate(QStyledItemDelegate): '''