%PDF- %PDF-
Direktori : /lib/calibre/calibre/gui2/preferences/ |
Current File : //lib/calibre/calibre/gui2/preferences/search.py |
#!/usr/bin/env python3 __license__ = 'GPL v3' __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>' __docformat__ = 'restructuredtext en' from qt.core import QApplication, QTimer from calibre.db.categories import find_categories from calibre.gui2.preferences import ConfigWidgetBase, test_widget, \ CommaSeparatedList, AbortCommit from calibre.gui2.preferences.search_ui import Ui_Form from calibre.gui2 import config, error_dialog, gprefs from calibre.utils.config import prefs from calibre.utils.icu import sort_key from calibre.library.caches import set_use_primary_find_in_search from polyglot.builtins import iteritems class ConfigWidget(ConfigWidgetBase, Ui_Form): def genesis(self, gui): self.gui = gui db = gui.library_view.model().db self.db = db r = self.register r('search_as_you_type', config) r('highlight_search_matches', config) r('show_highlight_toggle_button', gprefs) r('limit_search_columns', prefs) r('use_primary_find_in_search', prefs) r('case_sensitive', prefs) fl = db.field_metadata.get_search_terms() r('limit_search_columns_to', prefs, setting=CommaSeparatedList, choices=fl) self.clear_history_button.clicked.connect(self.clear_histories) self.gst_explanation.setText('<p>' + _( "<b>Grouped search terms</b> are search names that permit a query to automatically " "search across more than one column. For example, if you create a grouped " "search term <code>allseries</code> with the value " "<code>series, #myseries, #myseries2</code>, then " "the query <code>allseries:adhoc</code> will find 'adhoc' in any of the " "columns <code>series</code>, <code>#myseries</code>, and " "<code>#myseries2</code>.<p> Enter the name of the " "grouped search term in the drop-down box, enter the list of columns " "to search in the value box, then push the Save button. " "<p>Note: Search terms are forced to lower case; <code>MySearch</code> " "and <code>mysearch</code> are the same term." "<p>You can have your grouped search term show up as User categories in " " the Tag browser. Just add the grouped search term names to the Make User " "categories from box. You can add multiple terms separated by commas. " "The new User category will be automatically " "populated with all the items in the categories included in the grouped " "search term. <p>Automatic User categories permit you to see easily " "all the category items that " "are in the columns contained in the grouped search term. Using the above " "<code>allseries</code> example, the automatically-generated User category " "will contain all the series mentioned in <code>series</code>, " "<code>#myseries</code>, and <code>#myseries2</code>. This " "can be useful to check for duplicates, to find which column contains " "a particular item, or to have hierarchical categories (categories " "that contain categories).")) self.gst = db.prefs.get('grouped_search_terms', {}).copy() self.orig_gst_keys = list(self.gst.keys()) fm = db.new_api.field_metadata categories = [x[0] for x in find_categories(fm) if fm[x[0]]['search_terms']] self.gst_value.update_items_cache(categories) QTimer.singleShot(0, self.fill_gst_box) self.user_category_layout.setContentsMargins(0, 30, 0, 0) self.gst_names.lineEdit().setPlaceholderText( _('Enter new or select existing name')) self.gst_value.lineEdit().setPlaceholderText( _('Enter list of column lookup names to search')) self.category_fields = fl ml = [(_('Match any'), 'match_any'), (_('Match all'), 'match_all')] r('similar_authors_match_kind', db.prefs, choices=ml) r('similar_tags_match_kind', db.prefs, choices=ml) r('similar_series_match_kind', db.prefs, choices=ml) r('similar_publisher_match_kind', db.prefs, choices=ml) self.set_similar_fields(initial=True) self.similar_authors_search_key.currentIndexChanged[int].connect(self.something_changed) self.similar_tags_search_key.currentIndexChanged[int].connect(self.something_changed) self.similar_series_search_key.currentIndexChanged[int].connect(self.something_changed) self.similar_publisher_search_key.currentIndexChanged[int].connect(self.something_changed) self.gst_delete_button.setEnabled(False) self.gst_save_button.setEnabled(False) self.gst_names.currentIndexChanged[int].connect(self.gst_index_changed) self.gst_names.editTextChanged.connect(self.gst_text_changed) self.gst_value.textChanged.connect(self.gst_text_changed) self.gst_save_button.clicked.connect(self.gst_save_clicked) self.gst_delete_button.clicked.connect(self.gst_delete_clicked) self.gst_changed = False if db.prefs.get('grouped_search_make_user_categories', None) is None: db.new_api.set_pref('grouped_search_make_user_categories', []) r('grouped_search_make_user_categories', db.prefs, setting=CommaSeparatedList) self.muc_changed = False self.opt_grouped_search_make_user_categories.lineEdit().editingFinished.connect( self.muc_box_changed) def set_similar_fields(self, initial=False): self.set_similar('similar_authors_search_key', initial=initial) self.set_similar('similar_tags_search_key', initial=initial) self.set_similar('similar_series_search_key', initial=initial) self.set_similar('similar_publisher_search_key', initial=initial) def set_similar(self, name, initial=False): field = getattr(self, name) if not initial: val = field.currentText() else: val = self.db.prefs[name] field.blockSignals(True) field.clear() choices = [] choices.extend(self.category_fields) choices.extend(sorted(self.gst.keys(), key=sort_key)) field.addItems(choices) dex = field.findText(val) if dex >= 0: field.setCurrentIndex(dex) else: field.setCurrentIndex(0) field.blockSignals(False) def something_changed(self, dex): self.changed_signal.emit() def muc_box_changed(self): self.muc_changed = True def gst_save_clicked(self): idx = self.gst_names.currentIndex() name = icu_lower(str(self.gst_names.currentText())) if not name: return error_dialog(self.gui, _('Grouped search terms'), _('The search term cannot be blank'), show=True) if idx != 0: orig_name = str(self.gst_names.itemData(idx) or '') else: orig_name = '' if name != orig_name: if name in self.db.field_metadata.get_search_terms() and \ name not in self.orig_gst_keys: return error_dialog(self.gui, _('Grouped search terms'), _('That name is already used for a column or grouped search term'), show=True) if name in [icu_lower(p) for p in self.db.prefs.get('user_categories', {})]: return error_dialog(self.gui, _('Grouped search terms'), _('That name is already used for User category'), show=True) val = [v.strip() for v in str(self.gst_value.text()).split(',') if v.strip()] if not val: return error_dialog(self.gui, _('Grouped search terms'), _('The value box cannot be empty'), show=True) if orig_name and name != orig_name: del self.gst[orig_name] self.gst_changed = True self.gst[name] = val self.fill_gst_box(select=name) self.set_similar_fields(initial=False) self.changed_signal.emit() def gst_delete_clicked(self): if self.gst_names.currentIndex() == 0: return error_dialog(self.gui, _('Grouped search terms'), _('The empty grouped search term cannot be deleted'), show=True) name = str(self.gst_names.currentText()) if name in self.gst: del self.gst[name] self.fill_gst_box(select='') self.changed_signal.emit() self.gst_changed = True self.set_similar_fields(initial=False) def fill_gst_box(self, select=None): terms = sorted(self.gst.keys(), key=sort_key) self.opt_grouped_search_make_user_categories.update_items_cache(terms) self.gst_names.blockSignals(True) self.gst_names.clear() self.gst_names.addItem('', '') for t in terms: self.gst_names.addItem(t, t) self.gst_names.blockSignals(False) if select is not None: if select == '': self.gst_index_changed(0) elif select in terms: self.gst_names.setCurrentIndex(self.gst_names.findText(select)) def gst_text_changed(self): t = self.gst_names.currentText() self.gst_delete_button.setEnabled(len(t) > 0 and t in self.gst) self.gst_save_button.setEnabled(True) def gst_index_changed(self, idx): self.gst_delete_button.setEnabled(idx != 0) self.gst_save_button.setEnabled(False) self.gst_value.blockSignals(True) if idx == 0: self.gst_value.setText('') else: name = str(self.gst_names.itemData(idx) or '') self.gst_value.setText(','.join(self.gst[name])) self.gst_value.blockSignals(False) def commit(self): if self.opt_case_sensitive.isChecked() and self.opt_use_primary_find_in_search.isChecked(): error_dialog(self, _('Incompatible options'), _( 'The option to have un-accented characters match accented characters has no effect' ' if you also turn on case-sensitive searching. So only turn on one of those options'), show=True) raise AbortCommit() if self.gst_changed: self.db.new_api.set_pref('grouped_search_terms', self.gst) self.db.field_metadata.add_grouped_search_terms(self.gst) self.db.new_api.set_pref('similar_authors_search_key', str(self.similar_authors_search_key.currentText())) self.db.new_api.set_pref('similar_tags_search_key', str(self.similar_tags_search_key.currentText())) self.db.new_api.set_pref('similar_series_search_key', str(self.similar_series_search_key.currentText())) self.db.new_api.set_pref('similar_publisher_search_key', str(self.similar_publisher_search_key.currentText())) return ConfigWidgetBase.commit(self) def refresh_gui(self, gui): gui.current_db.new_api.clear_caches() set_use_primary_find_in_search(prefs['use_primary_find_in_search']) gui.set_highlight_only_button_icon() if self.muc_changed: gui.tags_view.recount() gui.search.search_as_you_type(config['search_as_you_type']) gui.search.do_search() def clear_histories(self, *args): for key, val in iteritems(config.defaults): if key.endswith('_search_history') and isinstance(val, list): config[key] = [] self.gui.search.clear_history() from calibre.gui2.widgets import history for key in ( 'bulk_edit_search_for', 'bulk_edit_replace_with', 'viewer-highlights-search-panel-expression', 'viewer-search-panel-expression', ): history.set('lineedit_history_' + key, []) from calibre.gui2.viewer.config import vprefs for k in ('search', 'highlights'): vprefs.set(f'saved-{k}-settings', {}) if __name__ == '__main__': app = QApplication([]) test_widget('Interface', 'Search')