diff --git a/src/calibre/gui2/dialogs/saved_search_editor.py b/src/calibre/gui2/dialogs/saved_search_editor.py
index e07fb0ff28..b69e2f7afe 100644
--- a/src/calibre/gui2/dialogs/saved_search_editor.py
+++ b/src/calibre/gui2/dialogs/saved_search_editor.py
@@ -4,8 +4,7 @@
from PyQt5.Qt import (
- QFormLayout, QIcon, QInputDialog, QLabel, QLineEdit, QListWidget, Qt,
- QVBoxLayout
+ QFormLayout, QIcon, QLabel, QLineEdit, QListWidget, Qt, QVBoxLayout
)
from calibre import prepare_string_for_xml
@@ -23,8 +22,10 @@ def commit_searches(searches):
class AddSavedSearch(Dialog):
- def __init__(self, parent=None, search=None, commit_changes=True):
+ def __init__(self, parent=None, search=None, commit_changes=True, label=None, validate=None):
self.initial_search = search
+ self.validate = validate
+ self.label = label
self.commit_changes = commit_changes
Dialog.__init__(
self, _('Add a new Saved search'), 'add-saved-search', parent)
@@ -39,7 +40,7 @@ class AddSavedSearch(Dialog):
self.l = l = QFormLayout(self)
l.setFieldGrowthPolicy(l.AllNonFixedFieldsGrow)
- self.la = la = QLabel(_(
+ self.la = la = QLabel(self.label or _(
'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.'))
@@ -60,7 +61,6 @@ class AddSavedSearch(Dialog):
l.addRow(self.bb)
def accept(self):
- Dialog.accept(self)
name = self.sname.text().strip()
if not name:
return error_dialog(
@@ -76,6 +76,11 @@ class AddSavedSearch(Dialog):
_('You must specify a search expression for the Saved search'),
show=True)
self.accepted_data = name, expression
+ if self.validate is not None:
+ err = self.validate(name, expression)
+ if err:
+ return error_dialog(self, _('Invalid saved search'), err, show=True)
+ Dialog.accept(self)
if self.commit_changes:
if icu_lower(name) in self.search_names:
self.searches.pop(self.search_names[icu_lower(name)], None)
@@ -102,11 +107,12 @@ class SavedSearchEditor(Dialog):
b.setIcon(QIcon(I('minus.png')))
b.clicked.connect(self.del_search)
- b = self.bb.addButton(_('Re&name search'), self.bb.ActionRole)
+ b = self.bb.addButton(_('&Edit search'), self.bb.ActionRole)
b.setIcon(QIcon(I('modified.png')))
- b.clicked.connect(self.rename_search)
+ b.clicked.connect(self.edit_search)
self.slist = QListWidget(self)
+ self.slist.setAlternatingRowColors(True)
self.searches = {name: db.saved_search_lookup(name) for name in db.saved_search_names()}
self.populate_search_list()
if self.initial_search is not None and self.initial_search in self.searches:
@@ -166,13 +172,26 @@ class SavedSearchEditor(Dialog):
self.slist.takeItem(self.slist.currentRow())
del self.searches[n]
- def rename_search(self):
+ def edit_search(self):
n = self.current_search_name
- if n:
- text, ok = QInputDialog.getText(self, _('Rename saved search'), _('&New name:'))
- if ok and text:
- self.slist.currentItem().setText(text)
- self.searches[text] = self.searches.pop(n)
+ if not n:
+ return
+ d = AddSavedSearch(parent=self, commit_changes=False, label=_('Edit the name and/or expression below.'), validate=self.validate_edit)
+ d.setWindowTitle(_('Edit saved search'))
+ d.sname.setText(n)
+ d.search.setText(self.searches[n])
+ if d.exec_() != d.Accepted:
+ return
+ name, expression = d.accepted_data
+ self.slist.currentItem().setText(name)
+ del self.searches[n]
+ self.searches[name] = expression
+ self.current_index_changed(self.slist.currentItem())
+
+ def validate_edit(self, name, expression):
+ q = self.current_search_name
+ if icu_lower(name) in {icu_lower(n) for n in self.searches if n != q}:
+ return _('A saved search with the name {} already exists. Choose another name').format(name)
def select_search(self, name):
items = self.slist.findItems(name, Qt.MatchFixedString | Qt.MatchCaseSensitive)