From 795f326ead0d21880f7bfd6a9726b2626407acc0 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Sat, 31 Oct 2020 12:49:58 +0000 Subject: [PATCH 1/6] Bug #1901249: Edit Metadata: Minor alignment issues with ellide tweak. Leave enough room on the right for a scroll bar. --- src/calibre/gui2/custom_column_widgets.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/calibre/gui2/custom_column_widgets.py b/src/calibre/gui2/custom_column_widgets.py index 9fde49eb87..bcf7c798f9 100644 --- a/src/calibre/gui2/custom_column_widgets.py +++ b/src/calibre/gui2/custom_column_widgets.py @@ -12,7 +12,7 @@ from functools import partial from PyQt5.Qt import (Qt, QComboBox, QLabel, QSpinBox, QDoubleSpinBox, QDateTime, QGroupBox, QVBoxLayout, QSizePolicy, QGridLayout, QUrl, QSpacerItem, QIcon, QCheckBox, QWidget, QHBoxLayout, QLineEdit, - QMessageBox, QToolButton, QPlainTextEdit) + QMessageBox, QToolButton, QPlainTextEdit, QApplication, QStyle) from calibre.utils.date import qt_to_dt, now, as_local_time, as_utc, internal_iso_format_string from calibre.gui2.complete2 import EditWithComplete @@ -756,6 +756,9 @@ def populate_metadata_page(layout, db, book_id, bulk=False, two_column=False, pa do_elision = tweaks['metadata_edit_elide_labels'] elide_pos = tweaks['metadata_edit_elision_point'] elide_pos = elide_pos if elide_pos in {'left', 'middle', 'right'} else 'right' + # make room on the right side for the scrollbar + sb_width = QApplication.instance().style().pixelMetric(QStyle.PM_ScrollBarExtent) + layout.setContentsMargins(0, 0, sb_width, 0) for key in cols: if not fm[key]['is_editable']: continue # The job spy plugin can change is_editable @@ -820,7 +823,6 @@ def populate_metadata_page(layout, db, book_id, bulk=False, two_column=False, pa l.addWidget(w.widgets[c+1], c, 1) else: l.addWidget(w.widgets[0], 0, 0, 1, 2) - l.addItem(QSpacerItem(0, 0, vPolicy=QSizePolicy.Expanding), c, 0, 1, 1) max_row = max(max_row, row) if row >= turnover_point: column = 1 From a380227d242f34bbe42a8189bd8b46dfa02f923f Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Sat, 31 Oct 2020 12:52:44 +0000 Subject: [PATCH 2/6] Bug 1901435]: Capitalized tags in the Category editor is not saved. Fixed by not offering the case change operations unless the item is being edited. This prevents unwelcome interactions between the widget's editor management (undo etc) and changing the case. --- src/calibre/gui2/dialogs/tag_list_editor.py | 27 +++++++++++---------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/calibre/gui2/dialogs/tag_list_editor.py b/src/calibre/gui2/dialogs/tag_list_editor.py index 0e56510a42..c6b8ab7641 100644 --- a/src/calibre/gui2/dialogs/tag_list_editor.py +++ b/src/calibre/gui2/dialogs/tag_list_editor.py @@ -296,19 +296,20 @@ class TagListEditor(QDialog, Ui_TagListEditor): ca.triggered.connect(partial(self.search_for_books, item)) if disable_copy_paste_search: ca.setEnabled(False) - m.addSeparator() - case_menu = QMenu(_('Change case')) - action_upper_case = case_menu.addAction(_('Upper case')) - action_lower_case = case_menu.addAction(_('Lower case')) - action_swap_case = case_menu.addAction(_('Swap case')) - action_title_case = case_menu.addAction(_('Title case')) - action_capitalize = case_menu.addAction(_('Capitalize')) - action_upper_case.triggered.connect(partial(self.do_case, icu_upper)) - action_lower_case.triggered.connect(partial(self.do_case, icu_lower)) - action_swap_case.triggered.connect(partial(self.do_case, self.swap_case)) - action_title_case.triggered.connect(partial(self.do_case, titlecase)) - action_capitalize.triggered.connect(partial(self.do_case, capitalize)) - m.addMenu(case_menu) + if self.table.state() == self.table.EditingState: + m.addSeparator() + case_menu = QMenu(_('Change case')) + action_upper_case = case_menu.addAction(_('Upper case')) + action_lower_case = case_menu.addAction(_('Lower case')) + action_swap_case = case_menu.addAction(_('Swap case')) + action_title_case = case_menu.addAction(_('Title case')) + action_capitalize = case_menu.addAction(_('Capitalize')) + action_upper_case.triggered.connect(partial(self.do_case, icu_upper)) + action_lower_case.triggered.connect(partial(self.do_case, icu_lower)) + action_swap_case.triggered.connect(partial(self.do_case, self.swap_case)) + action_title_case.triggered.connect(partial(self.do_case, titlecase)) + action_capitalize.triggered.connect(partial(self.do_case, capitalize)) + m.addMenu(case_menu) m.exec_(self.table.mapToGlobal(point)) def search_for_books(self, item): From 62c0d4dba354b431f99c8c7f23cb960e097c8cc3 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Sat, 31 Oct 2020 12:55:40 +0000 Subject: [PATCH 3/6] [Bug 1901456]: Slight text error in Column Icon rules --- src/calibre/gui2/preferences/coloring.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/calibre/gui2/preferences/coloring.py b/src/calibre/gui2/preferences/coloring.py index fed09e0b63..ad91f916b8 100644 --- a/src/calibre/gui2/preferences/coloring.py +++ b/src/calibre/gui2/preferences/coloring.py @@ -873,8 +873,9 @@ class RulesModel(QAbstractListModel): # {{{ _('
  • The condition using column %(col)s is invalid') % dict(col=c)) return ( - _('
  • If the %(col)s column %(action)s value: %(val)s') % dict( - col=c, action=action_name, val=prepare_string_for_xml(v))) + _('
  • If the %(col)s column %(action)s %(val_label)s%(val)s') % dict( + col=c, action=action_name, val=prepare_string_for_xml(v), + val_label=_('value: ') if v else '')) # }}} From c363a73083450e1d0421736f6728a29f1139d3d9 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Sat, 31 Oct 2020 12:56:56 +0000 Subject: [PATCH 4/6] Add text to look & feel / tag browser to ensure that people know they can set a keyboard shortcut to give the focus to the tag browser. --- src/calibre/gui2/preferences/look_feel.ui | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/calibre/gui2/preferences/look_feel.ui b/src/calibre/gui2/preferences/look_feel.ui index e11a68cb81..8b52d5bda3 100644 --- a/src/calibre/gui2/preferences/look_feel.ui +++ b/src/calibre/gui2/preferences/look_feel.ui @@ -1122,6 +1122,17 @@ using the mouse.</p> + + + + margin-left: 1.5em + + + <p>If you check this box then you probably want to define the +keyboard shortcut 'Tag browser / Give the tag browser keyboard focus'</p> + + + From 19c76941089d27bb91f0c3bcb5ff52efe8c4f1a2 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Sat, 31 Oct 2020 13:09:09 +0000 Subject: [PATCH 5/6] Various changes coming from MR discussions: 1) make the give-focus-to-TB a toggle, giving focus to the current view if the TB already has the focus. 2) Ensure that the TB loses the focus when it is hidden. 3) use coloring to mark the focused item in the TB, taking into consideration dark mode. The colors come from gui2.library.models. I don't really care what color is used. 4) Disable using the platform edit keys to edit TB items. Those keys don't permit asking the question about whether virtual libraries should be respected. This leaves using the context menu to start editing, which is how it has been forever. 5) Keep the focus on the TB when one uses RETURN to toggle the item. While there, ensure that RETURN is valid only if the TB is allowed to have focus. --- src/calibre/gui2/tag_browser/ui.py | 19 +++++++++++------ src/calibre/gui2/tag_browser/view.py | 32 ++++++++++++++++++++-------- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/src/calibre/gui2/tag_browser/ui.py b/src/calibre/gui2/tag_browser/ui.py index a8c4127f4d..b07af28a02 100644 --- a/src/calibre/gui2/tag_browser/ui.py +++ b/src/calibre/gui2/tag_browser/ui.py @@ -688,22 +688,27 @@ class TagBrowserWidget(QFrame): # {{{ def give_tb_focus(self, *args): if gprefs['tag_browser_allow_keyboard_focus']: tb = self.tags_view - idx = tb.currentIndex() - if not idx.isValid: - idx = tb.model().createIndex(0, 0) - tb.setCurrentIndex(idx) - tb.setFocus(Qt.OtherFocusReason) + if tb.hasFocus(): + self._parent.shift_esc() + elif self._parent.current_view() == self._parent.library_view: + tb.setFocus() + idx = tb.currentIndex() + if not idx.isValid(): + idx = tb.model().createIndex(0, 0) + tb.setCurrentIndex(idx) def set_pane_is_visible(self, to_what): self.tags_view.set_pane_is_visible(to_what) + if not to_what: + self._parent.shift_esc() - def find_text_changed(self, str): + def find_text_changed(self, str_): self.current_find_position = None def set_focus_to_find_box(self): self.tb_bar.set_focus_to_find_box() - def do_find(self, str=None): + def do_find(self, str_=None): self.current_find_position = None self.find() diff --git a/src/calibre/gui2/tag_browser/view.py b/src/calibre/gui2/tag_browser/view.py index 2639b8c01e..3896a2aab5 100644 --- a/src/calibre/gui2/tag_browser/view.py +++ b/src/calibre/gui2/tag_browser/view.py @@ -12,7 +12,7 @@ from functools import partial from PyQt5.Qt import ( QStyledItemDelegate, Qt, QTreeView, pyqtSignal, QSize, QIcon, QApplication, QMenu, QPoint, QToolTip, QCursor, QDrag, QRect, QModelIndex, - QLinearGradient, QPalette, QColor, QPen, QBrush, QFont + QLinearGradient, QPalette, QColor, QPen, QBrush, QFont, QTimer ) from calibre import sanitize_file_name @@ -22,7 +22,8 @@ from calibre.gui2.complete2 import EditWithComplete from calibre.gui2.tag_browser.model import (TagTreeItem, TAG_SEARCH_STATES, TagsModel, DRAG_IMAGE_ROLE, COUNT_ROLE) from calibre.gui2.widgets import EnLineEdit -from calibre.gui2 import config, gprefs, choose_files, pixmap_to_data, rating_font, empty_index +from calibre.gui2 import (config, gprefs, choose_files, pixmap_to_data, + rating_font, empty_index, is_dark_theme) from calibre.utils.icu import sort_key from calibre.utils.serialize import json_loads from polyglot.builtins import unicode_type, range, zip @@ -198,6 +199,10 @@ class TagsView(QTreeView): # {{{ self.set_look_and_feel() if not gprefs['tag_browser_allow_keyboard_focus']: self.setFocusPolicy(Qt.NoFocus) + else: + # This is necessary because the context menu sets things up. F2 + # and company don't. + self.setEditTriggers(QTreeView.NoEditTriggers) QApplication.instance().palette_changed.connect(self.set_style_sheet, type=Qt.QueuedConnection) def set_style_sheet(self): @@ -208,7 +213,7 @@ class TagsView(QTreeView): # {{{ border: none; } ''' - self.setStyleSheet(''' + self.setStyleSheet((''' QTreeView::item { border: 1px solid transparent; padding-top:PADex; @@ -220,8 +225,13 @@ class TagsView(QTreeView): # {{{ border: 1px solid #bfcde4; border-radius: 6px; } - '''.replace('PAD', unicode_type(gprefs['tag_browser_item_padding'])) + ( - '' if gprefs['tag_browser_old_look'] else stylish_tb)) + QTreeView::item:focus + { + background-color:FOCUS_COLOR; + } + '''.replace('PAD', unicode_type(gprefs['tag_browser_item_padding'])) + .replace('FOCUS_COLOR', '#027524' if is_dark_theme() else '#b4ecb4') + + ('' if gprefs['tag_browser_old_look'] else stylish_tb))) def set_look_and_feel(self): self.set_style_sheet() @@ -294,10 +304,14 @@ class TagsView(QTreeView): # {{{ self.collapsed.connect(self.collapse_node_and_children) def keyPressEvent(self, event): - if event.key() == Qt.Key_Return and self.state() != self.EditingState: - # I don't see how it can ever not be valid, but ... - if self.currentIndex().isValid(): - self.toggle_current_index() + if (gprefs['tag_browser_allow_keyboard_focus'] and event.key() == Qt.Key_Return + and self.state() != self.EditingState + # I don't see how current_index can ever be not valid, but ... + and self.currentIndex().isValid()): + self.toggle_current_index() + # Reset the focus to the TB. Use the singleshot in case + # some of of searching is done using queued signals. + QTimer.singleShot(0, lambda: self.setFocus()) return QTreeView.keyPressEvent(self, event) From 5aaabbf1067a0c69d592fdef16d47e6338bec595 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Sun, 1 Nov 2020 13:37:05 +0000 Subject: [PATCH 6/6] Remove the tag browser focus colors. --- src/calibre/gui2/tag_browser/view.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/calibre/gui2/tag_browser/view.py b/src/calibre/gui2/tag_browser/view.py index 3896a2aab5..30e74ef600 100644 --- a/src/calibre/gui2/tag_browser/view.py +++ b/src/calibre/gui2/tag_browser/view.py @@ -23,7 +23,7 @@ from calibre.gui2.tag_browser.model import (TagTreeItem, TAG_SEARCH_STATES, TagsModel, DRAG_IMAGE_ROLE, COUNT_ROLE) from calibre.gui2.widgets import EnLineEdit from calibre.gui2 import (config, gprefs, choose_files, pixmap_to_data, - rating_font, empty_index, is_dark_theme) + rating_font, empty_index) from calibre.utils.icu import sort_key from calibre.utils.serialize import json_loads from polyglot.builtins import unicode_type, range, zip @@ -213,7 +213,7 @@ class TagsView(QTreeView): # {{{ border: none; } ''' - self.setStyleSheet((''' + self.setStyleSheet(''' QTreeView::item { border: 1px solid transparent; padding-top:PADex; @@ -225,13 +225,8 @@ class TagsView(QTreeView): # {{{ border: 1px solid #bfcde4; border-radius: 6px; } - QTreeView::item:focus - { - background-color:FOCUS_COLOR; - } - '''.replace('PAD', unicode_type(gprefs['tag_browser_item_padding'])) - .replace('FOCUS_COLOR', '#027524' if is_dark_theme() else '#b4ecb4') - + ('' if gprefs['tag_browser_old_look'] else stylish_tb))) + '''.replace('PAD', unicode_type(gprefs['tag_browser_item_padding'])) + ( + '' if gprefs['tag_browser_old_look'] else stylish_tb)) def set_look_and_feel(self): self.set_style_sheet()