diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 83ed03d7b6..ab08fef8bd 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -392,6 +392,8 @@ def create_defs(): defs['edit_metadata_bulk_cc_label_length'] = 25 defs['edit_metadata_single_cc_label_length'] = 12 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): # If the tweak has been changed then leave the tweak in the file so diff --git a/src/calibre/gui2/preferences/look_feel.py b/src/calibre/gui2/preferences/look_feel.py index cf8d7a6c1f..f8ed2ebcba 100644 --- a/src/calibre/gui2/preferences/look_feel.py +++ b/src/calibre/gui2/preferences/look_feel.py @@ -394,7 +394,6 @@ class TBDisplayedFields(DisplayedFields): # {{{ 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_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: # 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.gui.tags_view.model().reset_tag_browser_categories() # }}} @@ -469,7 +467,6 @@ class TBHierarchicalFields(DisplayedFields): # {{{ def commit(self): if self.changed: 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, 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.changed.connect(self.changed_signal) self.tabWidget.addTab(self.edit_rules, @@ -780,6 +782,66 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): self.tabWidget.currentWidget().setFocus(Qt.FocusReason.OtherFocusReason) 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): if self.ui_style_available: enabled = self.opt_ui_style.currentData() == 'calibre' @@ -965,6 +1027,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): self.display_model.restore_defaults() self.em_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.icon_rules.clear() self.grid_rules.clear() @@ -1039,6 +1102,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): self.tb_display_model.commit() self.tb_categories_to_part_model.commit() self.tb_hierarchical_cats_model.commit() + self.tb_search_order_commit() self.edit_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) @@ -1063,6 +1127,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): self.update_font_display() gui.tags_view.set_look_and_feel() 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_grid() gui.library_view.refresh_composite_edit() diff --git a/src/calibre/gui2/preferences/look_feel.ui b/src/calibre/gui2/preferences/look_feel.ui index 3cd15b8e4a..d5aed65773 100644 --- a/src/calibre/gui2/preferences/look_feel.ui +++ b/src/calibre/gui2/preferences/look_feel.ui @@ -958,7 +958,7 @@ A value of zero means calculate automatically. - <p>Click this button to reset the list to its default order.</p> + Click this button to reset the list to its default order. Reset list @@ -1151,7 +1151,7 @@ using the Tab key. The F2 (Edit) key will still open the template editor.</p& - Select the categories to display and their &order + Select the categories to display in the Tag browser, and their &order tb_display_order @@ -1214,7 +1214,7 @@ using the Tab key. The F2 (Edit) key will still open the template editor.</p& - <p>Click this button to reset the list to its default order.</p> + Click this button to reset the list to its default order. Reset list @@ -1263,90 +1263,6 @@ structure and you want to use the same column order for each one.</p> - - - - Select categories with &hierarchical items: - - - tb_hierarchical_cats - - - <p>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.</p> -<p>The categories 'authors', 'publisher', 'news', 'formats', and 'rating' -cannot be hierarchical.</p> - - - - - - - - 0 - 200 - - - - true - - - - - - - - - <p>Click this button to reset the list to its default order.</p> - - - Reset list - - - - - - - <p>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.</p> - - - Import list - - - - - - - <p>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.</p> - - - Export list - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - @@ -1519,11 +1435,7 @@ if you never want subcategories</p> - - - - - + Combine letters &when fewer items than: @@ -1533,7 +1445,7 @@ if you never want subcategories</p> - + <p>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.</p> - + Co&llapse when more items than: @@ -1555,7 +1467,7 @@ not set to first letter, this value is ignored. Set to zero to disable.</p> - + <p>If a Tag browser category has more than this number of items, it is divided @@ -1604,7 +1516,7 @@ a few top-level elements.</p> - <p>Click this button to reset the list to its default order.</p> + Click this button to reset the list to its default order. Reset list @@ -1654,6 +1566,201 @@ structure and you want to use the same for each one.</p> + + + &Hierarchy and searching + + + + + + Select categories with &hierarchical items: + + + tb_hierarchical_cats + + + <p>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.</p> +<p>The categories 'authors', 'publisher', 'news', 'formats', and 'rating' +cannot be hierarchical.</p> + + + + + + + + 0 + 1 + + + + + 0 + 200 + + + + true + + + + + + + + + Click this button to reset the list to its default order. + + + Reset list + + + + + + + <p>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.</p> + + + Import list + + + + + + + <p>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.</p> + + + Export list + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 0 + 20 + + + + + + + + Set the &order of searches when clicking on items + + + <p>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.</p> + + + tb_search_order + + + + + + + QAbstractScrollArea::AdjustToContents + + + + + + + Move up. + + + + :/images/arrow-up.png:/images/arrow-up.png + + + + + + + Qt::Vertical + + + + 1 + 1 + + + + + + + + Move down. + + + + :/images/arrow-down.png:/images/arrow-down.png + + + + + + + + + Click this button to reset the list to its default order. + + + Reset list + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + diff --git a/src/calibre/gui2/tag_browser/model.py b/src/calibre/gui2/tag_browser/model.py index 0ef50cde0a..1114436095 100644 --- a/src/calibre/gui2/tag_browser/model.py +++ b/src/calibre/gui2/tag_browser/model.py @@ -264,7 +264,9 @@ class TagTreeItem: # {{{ ''' if set_to is None: 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 \ self.tag.state == TAG_SEARCH_STATES['mark_minus']: if self.tag.is_searchable: @@ -402,7 +404,7 @@ class TagsModel(QAbstractItemModel): # {{{ self._run_rebuild() self.endResetModel() - def reset_tag_browser_categories(self): + def reset_tag_browser(self): self.beginResetModel() hidden_cats = self.db.new_api.pref('tag_browser_hidden_categories', {}) self.hidden_categories = set()