From 2ff634034eb8fb10c96e046291a626d1b50955f5 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Sat, 16 May 2020 11:49:29 +0100 Subject: [PATCH 1/5] Tag browser 'Find' improvements: - Add exact match searching by using '=' as prefix, as in "=Science Fiction" - Add option to show only categories containing items, as if a '*' prefix had been used - Override the collapse option using a prefix of ':', as in :foo - Make Quickview use exact match searching when items are double-clicked --- src/calibre/gui2/__init__.py | 1 + src/calibre/gui2/dialogs/quickview.py | 2 +- src/calibre/gui2/preferences/look_feel.py | 1 + src/calibre/gui2/preferences/look_feel.ui | 12 +++++ src/calibre/gui2/tag_browser/model.py | 14 +++++- src/calibre/gui2/tag_browser/ui.py | 61 ++++++++++++++++------- 6 files changed, 69 insertions(+), 22 deletions(-) diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index a081926eba..7e5e02b1de 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -150,6 +150,7 @@ def create_defs(): defs['ui_style'] = 'calibre' if iswindows or isosx else 'system' defs['tag_browser_old_look'] = False defs['tag_browser_hide_empty_categories'] = False + defs['tag_browser_always_autocollapse'] = False defs['book_list_tooltips'] = True defs['show_layout_buttons'] = False defs['bd_show_cover'] = True diff --git a/src/calibre/gui2/dialogs/quickview.py b/src/calibre/gui2/dialogs/quickview.py index 48457384ff..5c7b2a8b33 100644 --- a/src/calibre/gui2/dialogs/quickview.py +++ b/src/calibre/gui2/dialogs/quickview.py @@ -281,7 +281,7 @@ class Quickview(QDialog, Ui_Quickview): def item_doubleclicked(self, item): tb = self.gui.stack.tb_widget tb.set_focus_to_find_box() - tb.item_search.lineEdit().setText(self.current_key + ':' + item.text()) + tb.item_search.lineEdit().setText(self.current_key + ':=' + item.text()) tb.do_find() def show_context_menu(self, point): diff --git a/src/calibre/gui2/preferences/look_feel.py b/src/calibre/gui2/preferences/look_feel.py index 2e2b8e76df..334b76cd65 100644 --- a/src/calibre/gui2/preferences/look_feel.py +++ b/src/calibre/gui2/preferences/look_feel.py @@ -412,6 +412,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): r('row_numbers_in_book_list', gprefs) r('tag_browser_old_look', gprefs) r('tag_browser_hide_empty_categories', gprefs) + r('tag_browser_always_autocollapse', gprefs) r('tag_browser_show_tooltips', gprefs) r('bd_show_cover', gprefs) r('bd_overlay_cover_size', gprefs) diff --git a/src/calibre/gui2/preferences/look_feel.ui b/src/calibre/gui2/preferences/look_feel.ui index 7ce4cd2449..c758319824 100644 --- a/src/calibre/gui2/preferences/look_feel.ui +++ b/src/calibre/gui2/preferences/look_feel.ui @@ -995,6 +995,18 @@ then the tags will be displayed each on their own line. + + + + When checked, Find in the Tag browser will show all items + that match the search instead of the first one. If Hide empty categories is + also checked then only categories containing a matched item will be shown. + + + Find &shows all items that match in the Tag browser + + + diff --git a/src/calibre/gui2/tag_browser/model.py b/src/calibre/gui2/tag_browser/model.py index 6bb903c3c9..779511ff68 100644 --- a/src/calibre/gui2/tag_browser/model.py +++ b/src/calibre/gui2/tag_browser/model.py @@ -994,9 +994,19 @@ class TagsModel(QAbstractItemModel): # {{{ self.restriction_error.emit() if self.filter_categories_by: + if self.filter_categories_by.startswith('='): + use_exact_match = True + filter_by = self.filter_categories_by[1:] + else: + use_exact_match = False + filter_by = self.filter_categories_by for category in data.keys(): - data[category] = [t for t in data[category] - if lower(t.name).find(self.filter_categories_by) >= 0] + if use_exact_match: + data[category] = [t for t in data[category] + if lower(t.name) == filter_by] + else: + data[category] = [t for t in data[category] + if lower(t.name).find(filter_by) >= 0] # Build a dict of the keys that have data tb_categories = self.db.field_metadata diff --git a/src/calibre/gui2/tag_browser/ui.py b/src/calibre/gui2/tag_browser/ui.py index 9359f79fd5..b67f643ac6 100644 --- a/src/calibre/gui2/tag_browser/ui.py +++ b/src/calibre/gui2/tag_browser/ui.py @@ -429,13 +429,16 @@ class TagBrowserBar(QWidget): # {{{ self.item_search.setSizeAdjustPolicy(self.item_search.AdjustToMinimumContentsLengthWithIcon) self.item_search.initialize('tag_browser_search') self.item_search.completer().setCaseSensitivity(Qt.CaseSensitive) - self.item_search.setToolTip(_( - 'Search for items. This is a "contains" search; items containing the\n' - 'text anywhere in the name will be found. You can limit the search\n' - 'to particular categories using syntax similar to search. For example,\n' - 'tags:foo will find foo in any tag, but not in authors etc. Entering\n' - '*foo will filter all categories at once, showing only those items\n' - 'containing the text "foo"')) + self.item_search.setToolTip( + '

' +_( + 'Search for items. If the text begins with equals (=) the search is ' + 'exact match, otherwise it is "contains" finding items containing ' + 'the text anywhere in the item name. Both exact and contains ' + 'searches ignore case. You can limit the search to particular ' + 'categories using syntax similar to search. For example, ' + 'tags:foo will find foo in any tag, but not in authors etc. Entering ' + '*foo will collapse all categories then showing only those categories ' + 'with items containing the text "foo"') + '= 0: + key = self._parent.library_view.model().db.\ + field_metadata.search_term_to_field_key(txt[:colon]) + if key in self._parent.library_view.model().db.field_metadata: + txt = txt[colon+1:] + else: + key = '' + txt = txt[1:] if colon == 0 else txt + else: + key = None + + # key is None indicates that no colon was found. + # key == '' means either a leading : was found or the key is invalid + + # At this point the txt might have a leading =, in which case do an + # exact match search + + if (gprefs.get('tag_browser_always_autocollapse', False) and + key is None and not txt.startswith('*')): + txt = '*' + txt if txt.startswith('*'): self.tags_view.collapseAll() model.set_categories_filter(txt[1:]) @@ -659,18 +686,14 @@ class TagBrowserWidget(QFrame): # {{{ self.search_button.setFocus(True) self.item_search.lineEdit().blockSignals(False) - key = None - colon = txt.find(':') if len(txt) > 2 else 0 - if colon > 0: - key = self._parent.library_view.model().db.\ - field_metadata.search_term_to_field_key(txt[:colon]) - if key in self._parent.library_view.model().db.field_metadata: - txt = txt[colon+1:] - else: - key = None - + if txt.startswith('='): + equals_match = True + txt = txt[1:] + else: + equals_match = False self.current_find_position = \ - model.find_item_node(key, txt, self.current_find_position) + model.find_item_node(key, txt, self.current_find_position, + equals_match=equals_match) if self.current_find_position: self.tags_view.show_item_at_path(self.current_find_position, box=True) From b2e108042b9f01516328dce45332cae12644ac5e Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Sat, 16 May 2020 15:39:00 +0100 Subject: [PATCH 2/5] Enhancement #1878940: allow restricting manage authors to the current virtual library. Other improvements: - Get rid of sort buttons, instead sorting by clicking on the header - Support sorting by the author link column - Add an "edited" icon to any cell that has been changed --- .../gui2/dialogs/edit_authors_dialog.py | 221 ++++++++++++------ .../gui2/dialogs/edit_authors_dialog.ui | 26 +-- src/calibre/gui2/dialogs/tag_list_editor.ui | 6 +- src/calibre/gui2/tag_browser/ui.py | 26 ++- 4 files changed, 177 insertions(+), 102 deletions(-) diff --git a/src/calibre/gui2/dialogs/edit_authors_dialog.py b/src/calibre/gui2/dialogs/edit_authors_dialog.py index 43c7faad24..edddeee05b 100644 --- a/src/calibre/gui2/dialogs/edit_authors_dialog.py +++ b/src/calibre/gui2/dialogs/edit_authors_dialog.py @@ -47,10 +47,11 @@ class EditColumnDelegate(QItemDelegate): class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog): - def __init__(self, parent, db, id_to_select, select_sort, select_link): + def __init__(self, parent, db, id_to_select, select_sort, select_link, find_aut_func): QDialog.__init__(self, parent) Ui_EditAuthorsDialog.__init__(self) self.setupUi(self) + # Remove help icon on title bar icon = self.windowIcon() self.setWindowFlags(self.windowFlags()&(~Qt.WindowContextHelpButtonHint)) @@ -68,49 +69,15 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog): self.buttonBox.button(QDialogButtonBox.Ok).setText(_('&OK')) self.buttonBox.button(QDialogButtonBox.Cancel).setText(_('&Cancel')) self.buttonBox.accepted.connect(self.accepted) + self.apply_vl_checkbox.stateChanged.connect(self.use_vl_changed) - # Set up the column headings + # Set up the heading for sorting self.table.setSelectionMode(QAbstractItemView.SingleSelection) - self.table.setColumnCount(3) self.down_arrow_icon = QIcon(I('arrow-down.png')) self.up_arrow_icon = QIcon(I('arrow-up.png')) self.blank_icon = QIcon(I('blank.png')) - self.auth_col = QTableWidgetItem(_('Author')) - self.table.setHorizontalHeaderItem(0, self.auth_col) - self.auth_col.setIcon(self.blank_icon) - self.aus_col = QTableWidgetItem(_('Author sort')) - self.table.setHorizontalHeaderItem(1, self.aus_col) - self.aus_col.setIcon(self.up_arrow_icon) - self.aul_col = QTableWidgetItem(_('Link')) - self.table.setHorizontalHeaderItem(2, self.aul_col) - self.aus_col.setIcon(self.blank_icon) - - # Add the data - self.authors = {} - auts = db.get_authors_with_ids() - self.table.setRowCount(len(auts)) - select_item = None - completion_data = [] - for row, (_id, author, sort, link) in enumerate(auts): - author = author.replace('|', ',') - self.authors[_id] = (author, sort, link) - completion_data.append(author) - aut = tableItem(author) - aut.setData(Qt.UserRole, _id) - sort = tableItem(sort) - link = tableItem(link) - self.table.setItem(row, 0, aut) - self.table.setItem(row, 1, sort) - self.table.setItem(row, 2, link) - if id_to_select in (_id, author): - if select_sort: - select_item = sort - elif select_link: - select_item = link - else: - select_item = aut - self.table.setItemDelegate(EditColumnDelegate(completion_data)) + self.find_aut_func = find_aut_func self.table.resizeColumnsToContents() if self.table.columnWidth(2) < 200: self.table.setColumnWidth(2, 200) @@ -118,28 +85,14 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog): # set up the cellChanged signal only after the table is filled self.table.cellChanged.connect(self.cell_changed) - # set up sort buttons - self.sort_by_author.setCheckable(True) - self.sort_by_author.setChecked(False) - self.sort_by_author.clicked.connect(self.do_sort_by_author) - self.author_order = 1 - - self.sort_by_author_sort.clicked.connect(self.do_sort_by_author_sort) - self.sort_by_author_sort.setCheckable(True) - self.sort_by_author_sort.setChecked(True) - self.author_sort_order = 1 - self.recalc_author_sort.clicked.connect(self.do_recalc_author_sort) self.auth_sort_to_author.clicked.connect(self.do_auth_sort_to_author) - # Position on the desired item - if select_item is not None: - self.table.setCurrentItem(select_item) - self.table.editItem(select_item) - self.start_find_pos = select_item.row() * 2 + select_item.column() - else: - self.table.setCurrentCell(0, 0) - self.start_find_pos = -1 + # Capture clicks on the horizontal header to sort the table columns + hh = self.table.horizontalHeader() + hh.setSectionsClickable(True) + hh.sectionClicked.connect(self.header_clicked) + hh.sectionResized.connect(self.table_column_resized) # set up the search box self.find_box.initialize('manage_authors_search') @@ -165,7 +118,101 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog): self.table.setContextMenuPolicy(Qt.CustomContextMenu) self.table.customContextMenuRequested.connect(self.show_context_menu) - self.do_sort_by_author_sort() + + # Fetch the data + self.authors = {} + self.original_authors = {} + auts = db.new_api.author_data() + self.completion_data = [] + for id_, v in auts.items(): + name = v['name'] + name = name.replace('|', ',') + self.completion_data.append(name) + self.authors[id_] = {'name': name, 'sort': v['sort'], 'link': v['link']} + self.original_authors[id_] = {'name': name, 'sort': v['sort'], + 'link': v['link']} + + self.edited_icon = QIcon(I('edit_input.png')) + self.down_arrow_icon = QIcon(I('arrow-down.png')) + self.up_arrow_icon = QIcon(I('arrow-up.png')) + self.blank_icon = QIcon(I('blank.png')) + self.last_sorted_by = 'sort' + self.author_order = 1 + self.author_sort_order = 0 + self.link_order = 1 + self.show_table(id_to_select, select_sort, select_link) + + def use_vl_changed(self, x): + self.show_table(None, None, None) + + def show_table(self, id_to_select, select_sort, select_link): + auts_to_show = [t[0] for t in + self.find_aut_func(use_virtual_library = self.apply_vl_checkbox.isChecked())] + self.table.blockSignals(True) + self.table.clear() + self.table.setColumnCount(3) + self.auth_col = QTableWidgetItem(_('Author')) + self.table.setHorizontalHeaderItem(0, self.auth_col) + self.aus_col = QTableWidgetItem(_('Author sort')) + self.table.setHorizontalHeaderItem(1, self.aus_col) + self.aul_col = QTableWidgetItem(_('Link')) + self.table.setHorizontalHeaderItem(2, self.aul_col) + + self.table.setRowCount(len(auts_to_show)) + select_item = None + row = 0 + for id_, v in self.authors.items(): + if id_ not in auts_to_show: + continue + name, sort, link = (v['name'], v['sort'], v['link']) + orig = self.original_authors[id_] + name = name.replace('|', ',') + + name_item = tableItem(name) + name_item.setData(Qt.UserRole, id_) + if name != orig['name']: + name_item.setIcon(self.edited_icon) + sort_item = tableItem(sort) + if sort != orig['sort']: + sort_item.setIcon(self.edited_icon) + link_item = tableItem(link) + if link != orig['link']: + link_item.setIcon(self.edited_icon) + self.table.setItem(row, 0, name_item) + self.table.setItem(row, 1, sort_item) + self.table.setItem(row, 2, link_item) + + if id_to_select and id_to_select in (id_, name): + print('id', id_to_select) + if select_sort: + select_item = sort_item + elif select_link: + select_item = link_item + else: + select_item = name_item + row += 1 + + self.table.setItemDelegate(EditColumnDelegate(self.completion_data)) + + if self.last_sorted_by == 'sort': + self.author_sort_order = 1 if self.author_sort_order == 0 else 0 + self.do_sort_by_author_sort() + elif self.last_sorted_by == 'author': + self.author_order = 1 if self.author_order == 0 else 0 + self.do_sort_by_author() + else: + self.link_order = 1 if self.link_order == 0 else 0 + self.do_sort_by_link() + + # Position on the desired item + if select_item is not None: + self.table.setCurrentItem(select_item) + self.table.editItem(select_item) + self.start_find_pos = select_item.row() * 2 + select_item.column() + else: + self.table.setCurrentCell(0, 0) + self.start_find_pos = -1 + self.table.blockSignals(False) def save_state(self): self.table_column_widths = [] @@ -174,6 +221,11 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog): gprefs['manage_authors_table_widths'] = self.table_column_widths gprefs['manage_authors_dialog_geometry'] = bytearray(self.saveGeometry()) + def table_column_resized(self, col, old, new): + self.table_column_widths = [] + for c in range(0, self.table.columnCount()): + self.table_column_widths.append(self.table.columnWidth(c)) + def resizeEvent(self, *args): QDialog.resizeEvent(self, *args) if self.table_column_widths is not None: @@ -216,7 +268,7 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog): ca.triggered.connect(self.copy_au_to_aus) m.addSeparator() ca = m.addAction(_("Show books by author in book list")) - ca.triggered.connect(self.search) + ca.triggered.connect(self.search_in_book_list) else: ca = m.addAction(_('Copy to author')) ca.triggered.connect(self.copy_aus_to_au) @@ -224,7 +276,7 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog): m.addMenu(case_menu) m.exec_(self.table.mapToGlobal(point)) - def search(self): + def search_in_book_list(self): from calibre.gui2.ui import get_gui row = self.context_item.row() get_gui().search.set_search_string(self.table.item(row, 0).text()) @@ -294,35 +346,48 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog): self.not_found_label.setVisible(True) self.not_found_label_timer.start(1500) + def header_clicked(self, idx): + if idx == 0: + self.do_sort_by_author() + elif idx == 1: + self.do_sort_by_author_sort() + else: + self.do_sort_by_link() + def do_sort_by_author(self): + self.last_sorted_by = 'author' self.author_order = 1 if self.author_order == 0 else 0 self.table.sortByColumn(0, self.author_order) - self.sort_by_author.setChecked(True) - self.sort_by_author_sort.setChecked(False) self.auth_col.setIcon(self.down_arrow_icon if self.author_order else self.up_arrow_icon) self.aus_col.setIcon(self.blank_icon) + self.aul_col.setIcon(self.blank_icon) def do_sort_by_author_sort(self): + self.last_sorted_by = 'sort' self.author_sort_order = 1 if self.author_sort_order == 0 else 0 self.table.sortByColumn(1, self.author_sort_order) - self.sort_by_author.setChecked(False) - self.sort_by_author_sort.setChecked(True) self.aus_col.setIcon(self.down_arrow_icon if self.author_sort_order else self.up_arrow_icon) self.auth_col.setIcon(self.blank_icon) + self.aul_col.setIcon(self.blank_icon) + + def do_sort_by_link(self): + self.last_sorted_by = 'link' + self.link_order = 1 if self.link_order == 0 else 0 + self.table.sortByColumn(2, self.link_order) + self.aul_col.setIcon(self.down_arrow_icon if self.link_order + else self.up_arrow_icon) + self.auth_col.setIcon(self.blank_icon) + self.aus_col.setIcon(self.blank_icon) def accepted(self): self.save_state() self.result = [] - for row in range(0,self.table.rowCount()): - id = int(self.table.item(row, 0).data(Qt.UserRole)) - aut = unicode_type(self.table.item(row, 0).text()).strip() - sort = unicode_type(self.table.item(row, 1).text()).strip() - link = unicode_type(self.table.item(row, 2).text()).strip() - orig_aut,orig_sort,orig_link = self.authors[id] - if orig_aut != aut or orig_sort != sort or orig_link != link: - self.result.append((id, orig_aut, aut, sort, link)) + for id_, v in self.authors.items(): + orig = self.original_authors[id_] + if orig != v: + self.result.append((id_, orig['name'], v['name'], v['sort'], v['link'])) def do_recalc_author_sort(self): self.table.cellChanged.disconnect() @@ -347,8 +412,10 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog): self.table.cellChanged.connect(self.cell_changed) def cell_changed(self, row, col): + id_ = int(self.table.item(row, 0).data(Qt.UserRole)) if col == 0: item = self.table.item(row, 0) + item.setIcon(self.edited_icon) aut = unicode_type(item.text()).strip() aut_list = string_to_authors(aut) if len(aut_list) != 1: @@ -356,10 +423,18 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog): _('You cannot change an author to multiple authors.')).exec_() aut = ' % '.join(aut_list) self.table.item(row, 0).setText(aut) + self.authors[id_]['name'] = aut c = self.table.item(row, 1) - c.setText(author_to_author_sort(aut)) + txt = author_to_author_sort(aut) + c.setText(txt) + self.authors[id_]['sort'] = txt item = c else: item = self.table.item(row, col) + item.setIcon(self.edited_icon) + if col == 1: + self.authors[id_]['sort'] = item.text() + else: + self.authors[id_]['link'] = item.text() self.table.setCurrentItem(item) self.table.scrollToItem(item) diff --git a/src/calibre/gui2/dialogs/edit_authors_dialog.ui b/src/calibre/gui2/dialogs/edit_authors_dialog.ui index e0f08d1b6a..8268c551ec 100644 --- a/src/calibre/gui2/dialogs/edit_authors_dialog.ui +++ b/src/calibre/gui2/dialogs/edit_authors_dialog.ui @@ -62,6 +62,18 @@ + + + + <p>Show authors only if they appear in the + current Virtual library. Edits already done may be hidden but will + not be forgotten.</p> + + + &Show only available items in current Virtual library + + + @@ -79,20 +91,6 @@ - - - - Sort by &author - - - - - - - Sort by author &sort - - - diff --git a/src/calibre/gui2/dialogs/tag_list_editor.ui b/src/calibre/gui2/dialogs/tag_list_editor.ui index f9235dc69e..bd2e157ae8 100644 --- a/src/calibre/gui2/dialogs/tag_list_editor.ui +++ b/src/calibre/gui2/dialogs/tag_list_editor.ui @@ -65,9 +65,9 @@ - <p>Show items in the Available items box only if they appear in the - current Virtual library. Applied items not in the Virtual library will be marked - "not on any book".</p> + <p>Show items only if they appear in the + current Virtual library. Edits already done may be hidden but will + not be forgotten.</p> &Show only available items in current Virtual library diff --git a/src/calibre/gui2/tag_browser/ui.py b/src/calibre/gui2/tag_browser/ui.py index b67f643ac6..0bbd848679 100644 --- a/src/calibre/gui2/tag_browser/ui.py +++ b/src/calibre/gui2/tag_browser/ui.py @@ -231,6 +231,15 @@ class TagBrowserMixin(object): # {{{ self.tags_view.recount() self.user_categories_edited() + def get_book_ids(self, use_virtual_library, db, category): + book_ids = None if not use_virtual_library else self.tags_view.model().get_book_ids_to_use() + data = db.new_api.get_categories(book_ids=book_ids) + if category in data: + result = [(t.id, t.original_name, t.count) for t in data[category] if t.count > 0] + else: + result = None + return result + def do_tags_list_edit(self, tag, category): ''' Open the 'manage_X' dialog where X == category. If tag is not None, the @@ -238,23 +247,15 @@ class TagBrowserMixin(object): # {{{ ''' db = self.current_db - - def get_book_ids(use_virtual_library): - book_ids = None if not use_virtual_library else self.tags_view.model().get_book_ids_to_use() - data = db.new_api.get_categories(book_ids=book_ids) - if category in data: - result = [(t.id, t.original_name, t.count) for t in data[category] if t.count > 0] - else: - result = None - return result - if category == 'series': key = lambda x:sort_key(title_sort(x)) else: key = sort_key d = TagListEditor(self, cat_name=db.field_metadata[category]['name'], - tag_to_match=tag, get_book_ids=get_book_ids, sorter=key) + tag_to_match=tag, + get_book_ids=partial(self.get_book_ids, db=db, category=category), + sorter=key) d.exec_() if d.result() == d.Accepted: to_rename = d.to_rename # dict of old id to new name @@ -361,7 +362,8 @@ class TagBrowserMixin(object): # {{{ ''' db = self.library_view.model().db - editor = EditAuthorsDialog(parent, db, id_, select_sort, select_link) + editor = EditAuthorsDialog(parent, db, id_, select_sort, select_link, + partial(self.get_book_ids, db=db, category='authors')) if editor.exec_() == editor.Accepted: # Save and restore the current selections. Note that some changes # will cause sort orders to change, so don't bother with attempting From dbf596e42147e6652aa415af603d0f62de9bcb55 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Sat, 16 May 2020 16:43:13 +0100 Subject: [PATCH 3/5] Fix not being able to reset a collapsed tag browser with the X in the find box. --- src/calibre/gui2/tag_browser/ui.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/calibre/gui2/tag_browser/ui.py b/src/calibre/gui2/tag_browser/ui.py index 0bbd848679..1e88d44a44 100644 --- a/src/calibre/gui2/tag_browser/ui.py +++ b/src/calibre/gui2/tag_browser/ui.py @@ -11,7 +11,7 @@ from functools import partial from PyQt5.Qt import ( Qt, QIcon, QWidget, QHBoxLayout, QVBoxLayout, QToolButton, QLabel, QFrame, - QTimer, QMenu, QActionGroup, QAction, QSizePolicy) + QTimer, QMenu, QActionGroup, QAction, QSizePolicy, pyqtSignal) from calibre.gui2 import error_dialog, question_dialog, gprefs from calibre.gui2.widgets import HistoryLineEdit @@ -406,9 +406,12 @@ class FindBox(HistoryLineEdit): # {{{ class TagBrowserBar(QWidget): # {{{ - def __init__(self, parent): + clear_find = pyqtSignal() + + def __init__(self, parent, reset_find): QWidget.__init__(self, parent) self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Preferred) + self.clear_find.connect(reset_find) parent = parent.parent() self.l = l = QHBoxLayout(self) l.setContentsMargins(0, 0, 0, 0) @@ -477,6 +480,7 @@ class TagBrowserBar(QWidget): # {{{ self.item_search.setCurrentIndex(0) self.item_search.setCurrentText('') self.toggle_search_button.click() + self.clear_find.emit() def set_focus_to_find_box(self): self.toggle_search_button.setChecked(True) @@ -521,7 +525,7 @@ class TagBrowserWidget(QFrame): # {{{ self._layout.setContentsMargins(0,0,0,0) # Set up the find box & button - self.tb_bar = tbb = TagBrowserBar(self) + self.tb_bar = tbb = TagBrowserBar(self, self.reset_find) self.alter_tb, self.item_search, self.search_button = tbb.alter_tb, tbb.item_search, tbb.search_button self.toggle_search_button = tbb.toggle_search_button self._layout.addWidget(tbb) @@ -641,6 +645,13 @@ class TagBrowserWidget(QFrame): # {{{ def find_text(self): return unicode_type(self.item_search.currentText()).strip() + def reset_find(self): + model = self.tags_view.model() + if model.get_categories_filter(): + model.set_categories_filter(None) + self.tags_view.recount() + self.current_find_position = None + def find(self): model = self.tags_view.model() model.clear_boxed() From c9314ccc10bfe18e380010b092e3af7ef8554240 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Sat, 16 May 2020 18:12:52 +0100 Subject: [PATCH 4/5] Change to my last fix. This way preserves interface compatibility by not changing the constructor. --- src/calibre/gui2/tag_browser/ui.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/calibre/gui2/tag_browser/ui.py b/src/calibre/gui2/tag_browser/ui.py index 1e88d44a44..16d0385a44 100644 --- a/src/calibre/gui2/tag_browser/ui.py +++ b/src/calibre/gui2/tag_browser/ui.py @@ -408,10 +408,9 @@ class TagBrowserBar(QWidget): # {{{ clear_find = pyqtSignal() - def __init__(self, parent, reset_find): + def __init__(self, parent): QWidget.__init__(self, parent) self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Preferred) - self.clear_find.connect(reset_find) parent = parent.parent() self.l = l = QHBoxLayout(self) l.setContentsMargins(0, 0, 0, 0) @@ -525,7 +524,8 @@ class TagBrowserWidget(QFrame): # {{{ self._layout.setContentsMargins(0,0,0,0) # Set up the find box & button - self.tb_bar = tbb = TagBrowserBar(self, self.reset_find) + self.tb_bar = tbb = TagBrowserBar(self) + tbb.clear_find.connect(self.reset_find) self.alter_tb, self.item_search, self.search_button = tbb.alter_tb, tbb.item_search, tbb.search_button self.toggle_search_button = tbb.toggle_search_button self._layout.addWidget(tbb) From 682ce7f23385ad2c45d57a1eea6297bcf1b5d8de Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Sat, 16 May 2020 18:13:55 +0100 Subject: [PATCH 5/5] Small change so that the saved search box in create VL isn't empty. --- src/calibre/gui2/search_restriction_mixin.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/calibre/gui2/search_restriction_mixin.py b/src/calibre/gui2/search_restriction_mixin.py index a988d63a94..c06ba03073 100644 --- a/src/calibre/gui2/search_restriction_mixin.py +++ b/src/calibre/gui2/search_restriction_mixin.py @@ -125,6 +125,8 @@ class CreateVirtualLibrary(QDialog): # {{{ self.vl_text.textChanged.connect(self.search_text_changed) la2.setBuddy(self.vl_text) gl.addWidget(self.vl_text, 1, 1) + # Trigger the textChanged signal to initialize the saved searches box + self.vl_text.setText(' ') self.vl_text.setText(_build_full_search_string(self.gui)) self.sl = sl = QLabel('

'+_('Create a Virtual library based on: ')+ @@ -213,10 +215,7 @@ class CreateVirtualLibrary(QDialog): # {{{ txt = '' else: txt = '' - if len(searches) > 1: - self.saved_searches_label.setPlainText('\n'.join(searches)) - else: - self.saved_searches_label.setPlainText('') + self.saved_searches_label.setPlainText('\n'.join(searches)) def name_text_edited(self, new_name): self.new_name = unicode_type(new_name)