Enhancement: add the ability to change the search order when clicking on items in the tag browser, using a third tab in L&F / Tag browser.

Also some small cleanup of strings and ALT-x characters.
This commit is contained in:
Charles Haley 2022-08-29 11:11:15 +01:00
parent 8f0226d8b1
commit 977ad34b50
4 changed files with 277 additions and 101 deletions

View File

@ -392,6 +392,8 @@ def create_defs():
defs['edit_metadata_bulk_cc_label_length'] = 25 defs['edit_metadata_bulk_cc_label_length'] = 25
defs['edit_metadata_single_cc_label_length'] = 12 defs['edit_metadata_single_cc_label_length'] = 12
defs['edit_metadata_templates_only_F2_on_booklist'] = False defs['edit_metadata_templates_only_F2_on_booklist'] = False
# JSON dumps converts integer keys to strings, so do it explicitly
defs['tb_search_order'] = {'0': 1, '1': 2, '2': 3, '3': 4, '4': 0}
def migrate_tweak(tweak_name, pref_name): def migrate_tweak(tweak_name, pref_name):
# If the tweak has been changed then leave the tweak in the file so # If the tweak has been changed then leave the tweak in the file so

View File

@ -394,7 +394,6 @@ class TBDisplayedFields(DisplayedFields): # {{{
if self.changed: if self.changed:
self.db.prefs.set('tag_browser_hidden_categories', [k for k,v in self.fields if not v]) self.db.prefs.set('tag_browser_hidden_categories', [k for k,v in self.fields if not v])
self.db.prefs.set('tag_browser_category_order', [k for k,v in self.fields]) self.db.prefs.set('tag_browser_category_order', [k for k,v in self.fields])
self.gui.tags_view.model().reset_tag_browser_categories()
# }}} # }}}
@ -431,7 +430,6 @@ class TBPartitionedFields(DisplayedFields): # {{{
if self.changed: if self.changed:
# Migrate to a per-library setting # Migrate to a per-library setting
self.db.prefs.set('tag_browser_dont_collapse', [k for k,v in self.fields if not v]) self.db.prefs.set('tag_browser_dont_collapse', [k for k,v in self.fields if not v])
self.gui.tags_view.model().reset_tag_browser_categories()
# }}} # }}}
@ -469,7 +467,6 @@ class TBHierarchicalFields(DisplayedFields): # {{{
def commit(self): def commit(self):
if self.changed: if self.changed:
self.db.prefs.set('categories_using_hierarchy', [k for k,v in self.fields if v]) self.db.prefs.set('categories_using_hierarchy', [k for k,v in self.fields if v])
self.gui.tags_view.model().reset_tag_browser_categories()
# }}} # }}}
@ -716,6 +713,11 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.tb_hierarchy_import_layout_button.clicked.connect(partial(self.import_layout, self.tb_hierarchy_import_layout_button.clicked.connect(partial(self.import_layout,
model=self.tb_hierarchical_cats_model)) model=self.tb_hierarchical_cats_model))
self.fill_tb_search_order_box()
self.tb_search_order_up_button.clicked.connect(self.move_tb_search_up)
self.tb_search_order_down_button.clicked.connect(self.move_tb_search_down)
self.tb_search_order_reset_button.clicked.connect(self.reset_tb_search_order)
self.edit_rules = EditRules(self.tabWidget) self.edit_rules = EditRules(self.tabWidget)
self.edit_rules.changed.connect(self.changed_signal) self.edit_rules.changed.connect(self.changed_signal)
self.tabWidget.addTab(self.edit_rules, self.tabWidget.addTab(self.edit_rules,
@ -780,6 +782,66 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.tabWidget.currentWidget().setFocus(Qt.FocusReason.OtherFocusReason) self.tabWidget.currentWidget().setFocus(Qt.FocusReason.OtherFocusReason)
self.opt_ui_style.currentIndexChanged.connect(self.update_color_palette_state) self.opt_ui_style.currentIndexChanged.connect(self.update_color_palette_state)
def fill_tb_search_order_box(self):
# The tb_search_order is a directed graph of nodes with an arc to the next
# node in the sequence. Node 0 (zero) is the start node with the last node
# arcing back to node 0. This code linearizes the graph
choices = [(1, _('Search for books containing the current item')),
(2, _('Search for books containing the current item or its children')),
(3, _('Search for books not containing the current item')),
(4, _('Search for books not containing the current item or its children'))]
icon_map = self.gui.tags_view.model().icon_state_map
order = gprefs.get('tb_search_order')
self.tb_search_order.clear()
node = 0
while True:
v = order[str(node)]
if v == 0:
break
item = QListWidgetItem(icon_map[v], choices[v-1][1])
item.setData(Qt.UserRole, choices[v-1][0])
self.tb_search_order.addItem(item)
node = v
def move_tb_search_up(self):
idx = self.tb_search_order.currentRow()
if idx <= 0:
return
item = self.tb_search_order.takeItem(idx)
self.tb_search_order.insertItem(idx-1, item)
self.tb_search_order.setCurrentRow(idx-1)
self.changed_signal.emit()
def move_tb_search_down(self):
idx = self.tb_search_order.currentRow()
if idx < 0 or idx == 3:
return
item = self.tb_search_order.takeItem(idx)
self.tb_search_order.insertItem(idx+1, item)
self.tb_search_order.setCurrentRow(idx+1)
self.changed_signal.emit()
def tb_search_order_commit(self):
t = {}
# Walk the items in the list box building the (node -> node) graph of
# the option order
node = 0
for i in range(0, 4):
v = self.tb_search_order.item(i).data(Qt.UserRole)
# JSON dumps converts integer keys to strings, so do it explicitly
t[str(node)] = v
node = v
# Add the arc from the last node back to node 0
t[str(node)] = 0
gprefs.set('tb_search_order', t)
def reset_tb_search_order(self):
gprefs.set('tb_search_order', gprefs.defaults['tb_search_order'])
self.fill_tb_search_order_box()
self.changed_signal.emit()
def update_color_palette_state(self): def update_color_palette_state(self):
if self.ui_style_available: if self.ui_style_available:
enabled = self.opt_ui_style.currentData() == 'calibre' enabled = self.opt_ui_style.currentData() == 'calibre'
@ -965,6 +1027,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.display_model.restore_defaults() self.display_model.restore_defaults()
self.em_display_model.restore_defaults() self.em_display_model.restore_defaults()
self.qv_display_model.restore_defaults() self.qv_display_model.restore_defaults()
gprefs.set('tb_search_order', gprefs.defaults['tb_search_order'])
self.edit_rules.clear() self.edit_rules.clear()
self.icon_rules.clear() self.icon_rules.clear()
self.grid_rules.clear() self.grid_rules.clear()
@ -1039,6 +1102,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.tb_display_model.commit() self.tb_display_model.commit()
self.tb_categories_to_part_model.commit() self.tb_categories_to_part_model.commit()
self.tb_hierarchical_cats_model.commit() self.tb_hierarchical_cats_model.commit()
self.tb_search_order_commit()
self.edit_rules.commit(self.gui.current_db.prefs) self.edit_rules.commit(self.gui.current_db.prefs)
self.icon_rules.commit(self.gui.current_db.prefs) self.icon_rules.commit(self.gui.current_db.prefs)
self.grid_rules.commit(self.gui.current_db.prefs) self.grid_rules.commit(self.gui.current_db.prefs)
@ -1063,6 +1127,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.update_font_display() self.update_font_display()
gui.tags_view.set_look_and_feel() gui.tags_view.set_look_and_feel()
gui.tags_view.reread_collapse_parameters() gui.tags_view.reread_collapse_parameters()
gui.tags_view.model().reset_tag_browser()
gui.library_view.refresh_book_details(force=True) gui.library_view.refresh_book_details(force=True)
gui.library_view.refresh_grid() gui.library_view.refresh_grid()
gui.library_view.refresh_composite_edit() gui.library_view.refresh_composite_edit()

View File

@ -958,7 +958,7 @@ A value of zero means calculate automatically.</string>
<item> <item>
<widget class="QPushButton" name="em_reset_layout_button"> <widget class="QPushButton" name="em_reset_layout_button">
<property name="toolTip"> <property name="toolTip">
<string>&lt;p&gt;Click this button to reset the list to its default order.&lt;/p&gt;</string> <string>Click this button to reset the list to its default order.</string>
</property> </property>
<property name="text"> <property name="text">
<string>Reset list</string> <string>Reset list</string>
@ -1151,7 +1151,7 @@ using the Tab key. The F2 (Edit) key will still open the template editor.&lt;/p&
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel"> <widget class="QLabel">
<property name="text"> <property name="text">
<string>Select the categories to display and their &amp;order</string> <string>Select the categories to display in the Tag browser, and their &amp;order</string>
</property> </property>
<property name="buddy"> <property name="buddy">
<cstring>tb_display_order</cstring> <cstring>tb_display_order</cstring>
@ -1214,7 +1214,7 @@ using the Tab key. The F2 (Edit) key will still open the template editor.&lt;/p&
<item> <item>
<widget class="QPushButton" name="tb_reset_layout_button"> <widget class="QPushButton" name="tb_reset_layout_button">
<property name="toolTip"> <property name="toolTip">
<string>&lt;p&gt;Click this button to reset the list to its default order.&lt;/p&gt;</string> <string>Click this button to reset the list to its default order.</string>
</property> </property>
<property name="text"> <property name="text">
<string>Reset list</string> <string>Reset list</string>
@ -1263,90 +1263,6 @@ structure and you want to use the same column order for each one.&lt;/p&gt;</str
</item> </item>
</layout> </layout>
</item> </item>
<item row="0" column="2">
<widget class="QLabel">
<property name="text">
<string>Select categories with &amp;hierarchical items:</string>
</property>
<property name="buddy">
<cstring>tb_hierarchical_cats</cstring>
</property>
<property name="toolTip">
<string>&lt;p&gt;Check the box for an item if it is to be displayed as a
hierarchical tree in the Tag browser. For example, if you check
'tags' then tags of the form 'Mystery.English'
and 'Mystery.Thriller' will be displayed with English and Thriller
both under 'Mystery'. If 'tags' is not checked
then the tags will be displayed each on their own line.&lt;/p&gt;
&lt;p&gt;The categories 'authors', 'publisher', 'news', 'formats', and 'rating'
cannot be hierarchical.&lt;/p&gt;</string>
</property>
</widget>
</item>
<item row="1" column="2" rowspan="3">
<widget class="QListView" name="tb_hierarchical_cats">
<property name="minimumSize">
<size>
<width>0</width>
<height>200</height>
</size>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="2">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QPushButton" name="tb_hierarchy_reset_layout_button">
<property name="toolTip">
<string>&lt;p&gt;Click this button to reset the list to its default order.&lt;/p&gt;</string>
</property>
<property name="text">
<string>Reset list</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="tb_hierarchy_import_layout_button">
<property name="toolTip">
<string>&lt;p&gt;Click this button to set the list to one
previously exported. This could be useful if you have several libraries with
similar structure and you want to use the same for each one.&lt;/p&gt;</string>
</property>
<property name="text">
<string>Import list</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="tb_hierarchy_export_layout_button">
<property name="toolTip">
<string>&lt;p&gt;Click this button to write the current display
settings to a file. This could be useful if you have several libraries with similar
structure and you want to use the same for each one.&lt;/p&gt;</string>
</property>
<property name="text">
<string>Export list</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="5" column="0"> <item row="5" column="0">
<widget class="QCheckBox" name="opt_show_avg_rating"> <widget class="QCheckBox" name="opt_show_avg_rating">
<property name="text"> <property name="text">
@ -1519,11 +1435,7 @@ if you never want subcategories&lt;/p&gt;</string>
</property> </property>
</widget> </widget>
</item> </item>
</layout> <item row="1" column="0">
</item>
<item row="0" column="1">
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_10"> <widget class="QLabel" name="label_10">
<property name="text"> <property name="text">
<string>Combine letters &amp;when fewer items than:</string> <string>Combine letters &amp;when fewer items than:</string>
@ -1533,7 +1445,7 @@ if you never want subcategories&lt;/p&gt;</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="1" column="1">
<widget class="QSpinBox" name="opt_tags_browser_collapse_fl_at"> <widget class="QSpinBox" name="opt_tags_browser_collapse_fl_at">
<property name="toolTip"> <property name="toolTip">
<string>&lt;p&gt;If collapsing by first letter, combine adjacent letters together if <string>&lt;p&gt;If collapsing by first letter, combine adjacent letters together if
@ -1545,7 +1457,7 @@ not set to first letter, this value is ignored. Set to zero to disable.&lt;/p&gt
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0"> <item row="2" column="0">
<widget class="QLabel" name="label_10"> <widget class="QLabel" name="label_10">
<property name="text"> <property name="text">
<string>Co&amp;llapse when more items than:</string> <string>Co&amp;llapse when more items than:</string>
@ -1555,7 +1467,7 @@ not set to first letter, this value is ignored. Set to zero to disable.&lt;/p&gt
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="2" column="1">
<widget class="QSpinBox" name="opt_tags_browser_collapse_at"> <widget class="QSpinBox" name="opt_tags_browser_collapse_at">
<property name="toolTip"> <property name="toolTip">
<string>&lt;p&gt;If a Tag browser category has more than this number of items, it is divided <string>&lt;p&gt;If a Tag browser category has more than this number of items, it is divided
@ -1604,7 +1516,7 @@ a few top-level elements.&lt;/p&gt;</string>
<item> <item>
<widget class="QPushButton" name="tb_partition_reset_button"> <widget class="QPushButton" name="tb_partition_reset_button">
<property name="toolTip"> <property name="toolTip">
<string>&lt;p&gt;Click this button to reset the list to its default order.&lt;/p&gt;</string> <string>Click this button to reset the list to its default order.</string>
</property> </property>
<property name="text"> <property name="text">
<string>Reset list</string> <string>Reset list</string>
@ -1654,6 +1566,201 @@ structure and you want to use the same for each one.&lt;/p&gt;</string>
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tb_tab3">
<attribute name="title">
<string>&amp;Hierarchy and searching</string>
</attribute>
<layout class="QGridLayout">
<item row="0" column="0">
<widget class="QLabel">
<property name="text">
<string>Select categories with &amp;hierarchical items:</string>
</property>
<property name="buddy">
<cstring>tb_hierarchical_cats</cstring>
</property>
<property name="toolTip">
<string>&lt;p&gt;Check the box for an item if it is to be displayed as a
hierarchical tree in the Tag browser. For example, if you check
'tags' then tags of the form 'Mystery.English'
and 'Mystery.Thriller' will be displayed with English and Thriller
both under 'Mystery'. If 'tags' is not checked
then the tags will be displayed each on their own line.&lt;/p&gt;
&lt;p&gt;The categories 'authors', 'publisher', 'news', 'formats', and 'rating'
cannot be hierarchical.&lt;/p&gt;</string>
</property>
</widget>
</item>
<item row="1" column="0" rowspan="3">
<widget class="QListView" name="tb_hierarchical_cats">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>200</height>
</size>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QPushButton" name="tb_hierarchy_reset_layout_button">
<property name="toolTip">
<string>Click this button to reset the list to its default order.</string>
</property>
<property name="text">
<string>Reset list</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="tb_hierarchy_import_layout_button">
<property name="toolTip">
<string>&lt;p&gt;Click this button to set the list to one
previously exported. This could be useful if you have several libraries with
similar structure and you want to use the same for each one.&lt;/p&gt;</string>
</property>
<property name="text">
<string>Import list</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="tb_hierarchy_export_layout_button">
<property name="toolTip">
<string>&lt;p&gt;Click this button to write the current display
settings to a file. This could be useful if you have several libraries with similar
structure and you want to use the same for each one.&lt;/p&gt;</string>
</property>
<property name="text">
<string>Export list</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="10" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="11" column="0">
<widget class="QLabel">
<property name="text">
<string>Set the &amp;order of searches when clicking on items</string>
</property>
<property name="toolTip">
<string>&lt;p&gt;Set the order of the searches when clicking on an item in
the Tag browser. The 'or its children' options are ignored when clicking on
top-level categories, items that aren't in a hierarchical category, and items
that don't have children.&lt;/p&gt;</string>
</property>
<property name="buddy">
<cstring>tb_search_order</cstring>
</property>
</widget>
</item>
<item row="12" column="0" rowspan="3">
<widget class="QListWidget" name="tb_search_order">
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QToolButton" name="tb_search_order_up_button">
<property name="toolTip">
<string>Move up.</string>
</property>
<property name="icon">
<iconset resource="../../../../resources/images.qrc">
<normaloff>:/images/arrow-up.png</normaloff>:/images/arrow-up.png</iconset>
</property>
</widget>
</item>
<item row="13" column="1">
<spacer name="verticalSpacer_51">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>1</width>
<height>1</height>
</size>
</property>
</spacer>
</item>
<item row="14" column="1">
<widget class="QToolButton" name="tb_search_order_down_button">
<property name="toolTip">
<string>Move down.</string>
</property>
<property name="icon">
<iconset resource="../../../../resources/images.qrc">
<normaloff>:/images/arrow-down.png</normaloff>:/images/arrow-down.png</iconset>
</property>
</widget>
</item>
<item row="15" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QPushButton" name="tb_search_order_reset_button">
<property name="toolTip">
<string>Click this button to reset the list to its default order.</string>
</property>
<property name="text">
<string>Reset list</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</widget> </widget>
<widget class="QWidget" name="cover_browser_tab"> <widget class="QWidget" name="cover_browser_tab">
<attribute name="icon"> <attribute name="icon">

View File

@ -264,7 +264,9 @@ class TagTreeItem: # {{{
''' '''
if set_to is None: if set_to is None:
while True: while True:
self.tag.state = (self.tag.state + 1)%5 tag_search_order_graph = gprefs.get('tb_search_order')
# JSON dumps converts integer keys to strings, so do it explicitly
self.tag.state = tag_search_order_graph[str(self.tag.state)]
if self.tag.state == TAG_SEARCH_STATES['mark_plus'] or \ if self.tag.state == TAG_SEARCH_STATES['mark_plus'] or \
self.tag.state == TAG_SEARCH_STATES['mark_minus']: self.tag.state == TAG_SEARCH_STATES['mark_minus']:
if self.tag.is_searchable: if self.tag.is_searchable:
@ -402,7 +404,7 @@ class TagsModel(QAbstractItemModel): # {{{
self._run_rebuild() self._run_rebuild()
self.endResetModel() self.endResetModel()
def reset_tag_browser_categories(self): def reset_tag_browser(self):
self.beginResetModel() self.beginResetModel()
hidden_cats = self.db.new_api.pref('tag_browser_hidden_categories', {}) hidden_cats = self.db.new_api.pref('tag_browser_hidden_categories', {})
self.hidden_categories = set() self.hidden_categories = set()