diff --git a/resources/default_tweaks.py b/resources/default_tweaks.py index 902a4ad4f9..44bfe3c8c0 100644 --- a/resources/default_tweaks.py +++ b/resources/default_tweaks.py @@ -559,3 +559,9 @@ content_server_thumbnail_compression_quality = 75 # Examples: # cover_drop_exclude = {'tiff', 'webp'} cover_drop_exclude = () + +#: Show the Saved searches box in the search bar +# In newer version of calibre, only a button that allows you to add a new Saved +# search is shown in the search bar. If you would like to have the old +# Saved searches box with its two buttons back, set this tweak to True. +show_saved_search_box = False diff --git a/src/calibre/gui2/dialogs/saved_search_editor.py b/src/calibre/gui2/dialogs/saved_search_editor.py index 11864656c0..fc73e0472b 100644 --- a/src/calibre/gui2/dialogs/saved_search_editor.py +++ b/src/calibre/gui2/dialogs/saved_search_editor.py @@ -1,14 +1,79 @@ -__license__ = 'GPL v3' +__license__ = 'GPL v3' __copyright__ = '2008, Kovid Goyal ' - -from PyQt5.Qt import QDialog +from PyQt5.Qt import QDialog, QFormLayout, Qt, QLineEdit, QLabel from calibre.gui2.dialogs.saved_search_editor_ui import Ui_SavedSearchEditor from calibre.utils.icu import sort_key from calibre.gui2 import error_dialog from calibre.gui2.dialogs.confirm_delete import confirm +from calibre.gui2.widgets2 import Dialog + + +def commit_searches(searches): + from calibre.gui2.ui import get_gui + db = get_gui().current_db + db.saved_search_set_all(searches) + + +class AddSavedSearch(Dialog): + + def __init__(self, parent=None, search=None): + self.initial_search = search + Dialog.__init__( + self, _('Add a new Saved search'), 'add-saved-search', parent) + from calibre.gui2.ui import get_gui + db = get_gui().current_db + self.searches = {} + for name in db.saved_search_names(): + self.searches[name] = db.saved_search_lookup(name) + self.search_names = {icu_lower(n) for n in db.saved_search_names()} + + def setup_ui(self): + self.l = l = QFormLayout(self) + l.setFieldGrowthPolicy(l.AllNonFixedFieldsGrow) + + self.la = la = QLabel(_( + 'You can create a Saved search, for frequently used searches here.' + ' The search will be visible under Searches in the Tag browser,' + ' using the name that you specify here.')) + la.setWordWrap(True) + l.addRow(la) + + self.sname = n = QLineEdit(self) + l.addRow(_('&Name:'), n) + n.setPlaceholderText(_('The Saved search name')) + + self.search = s = QLineEdit(self) + s.setMinimumWidth(400) + l.addRow(_('&Search:'), s) + s.setPlaceholderText(_('The search expression')) + if self.initial_search: + s.setText(self.initial_search) + n.setFocus(Qt.OtherFocusReason) + l.addRow(self.bb) + + def accept(self): + Dialog.accept(self) + name = self.sname.text().strip() + if not name: + return error_dialog( + self, + _('No search name'), + _('You must specify a search name'), + show=True) + expression = self.search.text().strip() + if not expression: + return error_dialog( + self, + _('No search expression'), + _('You must specify a search expression'), + show=True) + if icu_lower(name) in self.searches: + self.searches.pop(icu_lower(name), None) + self.searches[name] = expression + commit_searches(self.searches) class SavedSearchEditor(QDialog, Ui_SavedSearchEditor): @@ -21,7 +86,8 @@ class SavedSearchEditor(QDialog, Ui_SavedSearchEditor): self.setupUi(self) self.add_search_button.clicked.connect(self.add_search) - self.search_name_box.currentIndexChanged[(int)].connect(self.current_index_changed) + self.search_name_box.currentIndexChanged[( + int)].connect(self.current_index_changed) self.delete_search_button.clicked.connect(self.del_search) self.rename_button.clicked.connect(self.rename_search) @@ -55,9 +121,12 @@ class SavedSearchEditor(QDialog, Ui_SavedSearchEditor): if search_name == '': return False if icu_lower(search_name) in self.search_names: - error_dialog(self, _('Saved search already exists'), - _('The saved search %s already exists, perhaps with ' - 'different case')%search_name).exec_() + error_dialog( + self, + _('Saved search already exists'), + _( + 'The saved search %s already exists, perhaps with ' + 'different case') % search_name).exec_() return False if search_name not in self.searches: self.searches[search_name] = '' @@ -69,9 +138,11 @@ class SavedSearchEditor(QDialog, Ui_SavedSearchEditor): def del_search(self): if self.current_search_name is not None: - if not confirm('

'+_('The current saved search will be ' - 'permanently deleted. Are you sure?') + - '

', 'saved_search_editor_delete', self): + if not confirm( + '

' + _( + 'The current saved search will be ' + 'permanently deleted. Are you sure?') + '

', + 'saved_search_editor_delete', self): return del self.searches[self.current_search_name] self.current_search_name = None @@ -83,9 +154,12 @@ class SavedSearchEditor(QDialog, Ui_SavedSearchEditor): if new_search_name == '': return False if icu_lower(new_search_name) in self.search_names: - error_dialog(self, _('Saved search already exists'), - _('The saved search %s already exists, perhaps with ' - 'different case')%new_search_name).exec_() + error_dialog( + self, + _('Saved search already exists'), + _( + 'The saved search %s already exists, perhaps with ' + 'different case') % new_search_name).exec_() return False if self.current_search_name in self.searches: self.searches[new_search_name] = self.searches[self.current_search_name] @@ -100,23 +174,23 @@ class SavedSearchEditor(QDialog, Ui_SavedSearchEditor): def current_index_changed(self, idx): if self.current_search_name: - self.searches[self.current_search_name] = unicode(self.search_text.toPlainText()) + self.searches[self.current_search_name] = unicode( + self.search_text.toPlainText()) name = unicode(self.search_name_box.itemText(idx)) if name: self.current_search_name = name self.search_text.setPlainText(self.searches[name]) else: - self.current_search_name = None + self.current_search_name = None self.search_text.setPlainText('') def save_current_search(self): if self.current_search_name: - self.searches[self.current_search_name] = unicode(self.search_text.toPlainText()) + self.searches[self.current_search_name] = unicode( + self.search_text.toPlainText()) def accept(self): - from calibre.gui2.ui import get_gui - db = get_gui().current_db self.save_current_search() - ss = {name:self.searches[name] for name in self.searches} - db.saved_search_set_all(ss) + ss = {name: self.searches[name] for name in self.searches} + commit_searches(ss) QDialog.accept(self) diff --git a/src/calibre/gui2/layout.py b/src/calibre/gui2/layout.py index 3ec29c023c..2883b44b27 100644 --- a/src/calibre/gui2/layout.py +++ b/src/calibre/gui2/layout.py @@ -238,17 +238,25 @@ class SearchBar(QWidget): # {{{ x.setMinimumContentsLength(10) x.setObjectName("saved_search") l.addWidget(x) + x.setVisible(tweaks['show_saved_search_box']) x = parent.copy_search_button = QToolButton(self) x.setIcon(QIcon(I("search_copy_saved.png"))) x.setObjectName("copy_search_button") l.addWidget(x) x.setToolTip(_("Copy current search text (instead of search name)")) + x.setVisible(tweaks['show_saved_search_box']) x = parent.save_search_button = RightClickButton(self) x.setIcon(QIcon(I("search_add_saved.png"))) x.setObjectName("save_search_button") l.addWidget(x) + x.setVisible(tweaks['show_saved_search_box']) + + x = parent.add_saved_search_button = RightClickButton(self) + x.setIcon(QIcon(I("plus.png"))) + l.addWidget(x) + x.setVisible(not tweaks['show_saved_search_box']) # }}} diff --git a/src/calibre/gui2/search_box.py b/src/calibre/gui2/search_box.py index 9817c4bee6..59fa2478bb 100644 --- a/src/calibre/gui2/search_box.py +++ b/src/calibre/gui2/search_box.py @@ -553,6 +553,9 @@ class SavedSearchBoxMixin(object): # {{{ QIcon(I('trash.png')), _('Delete saved search'), self.saved_search.delete_current_search) self.save_search_button.menu().addAction( QIcon(I('search.png')), _('Manage saved searches'), partial(self.do_saved_search_edit, None)) + self.add_saved_search_button.clicked.connect(self.add_saved_search) + self.add_saved_search_button.setMenu(QMenu()) + self.add_saved_search_button.menu().addActions(self.save_search_button.menu().actions()) def saved_searches_changed(self, set_restriction=None, recount=True): self.build_search_restriction_list() @@ -571,4 +574,10 @@ class SavedSearchBoxMixin(object): # {{{ self.saved_searches_changed() self.saved_search.clear() + def add_saved_search(self): + from calibre.gui2.dialogs.saved_search_editor import AddSavedSearch + d = AddSavedSearch(parent=self, search=self.search.current_text) + if d.exec_() == d.Accepted: + self.do_rebuild_saved_searches() + # }}}