diff --git a/src/calibre/gui2/dialogs/saved_search_editor.py b/src/calibre/gui2/dialogs/saved_search_editor.py index 169f847578..e07fb0ff28 100644 --- a/src/calibre/gui2/dialogs/saved_search_editor.py +++ b/src/calibre/gui2/dialogs/saved_search_editor.py @@ -1,14 +1,18 @@ -__license__ = 'GPL v3' +#!/usr/bin/env python2 +# vim:fileencoding=utf-8 +# License: GPLv3 Copyright: 2008, Kovid Goyal -__copyright__ = '2008, Kovid Goyal ' -from PyQt5.Qt import QDialog, QFormLayout, Qt, QLineEdit, QLabel +from PyQt5.Qt import ( + QFormLayout, QIcon, QInputDialog, QLabel, QLineEdit, QListWidget, Qt, + QVBoxLayout +) -from calibre.gui2.dialogs.saved_search_editor_ui import Ui_SavedSearchEditor -from calibre.utils.icu import sort_key +from calibre import prepare_string_for_xml from calibre.gui2 import error_dialog from calibre.gui2.dialogs.confirm_delete import confirm from calibre.gui2.widgets2 import Dialog +from calibre.utils.icu import sort_key def commit_searches(searches): @@ -19,8 +23,9 @@ def commit_searches(searches): class AddSavedSearch(Dialog): - def __init__(self, parent=None, search=None): + def __init__(self, parent=None, search=None, commit_changes=True): self.initial_search = search + self.commit_changes = commit_changes Dialog.__init__( self, _('Add a new Saved search'), 'add-saved-search', parent) from calibre.gui2.ui import get_gui @@ -28,7 +33,7 @@ class AddSavedSearch(Dialog): 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()} + self.search_names = {icu_lower(n):n for n in db.saved_search_names()} def setup_ui(self): self.l = l = QFormLayout(self) @@ -70,127 +75,118 @@ class AddSavedSearch(Dialog): _('No search expression'), _('You must specify a search expression for the Saved search'), show=True) - if icu_lower(name) in self.searches: - self.searches.pop(icu_lower(name), None) - self.searches[name] = expression - commit_searches(self.searches) + self.accepted_data = name, expression + if self.commit_changes: + if icu_lower(name) in self.search_names: + self.searches.pop(self.search_names[icu_lower(name)], None) + self.searches[name] = expression + commit_searches(self.searches) -class SavedSearchEditor(QDialog, Ui_SavedSearchEditor): +class SavedSearchEditor(Dialog): def __init__(self, parent, initial_search=None): + self.initial_search = initial_search + Dialog.__init__( + self, _('Manage saved searches'), 'manage-saved-searches', parent) + + def setup_ui(self): from calibre.gui2.ui import get_gui db = get_gui().current_db - QDialog.__init__(self, parent) - Ui_SavedSearchEditor.__init__(self) - self.setupUi(self) + self.l = l = QVBoxLayout(self) + b = self.bb.addButton(_('&Add search'), self.bb.ActionRole) + b.setIcon(QIcon(I('plus.png'))) + b.clicked.connect(self.add_search) - self.add_search_button.clicked.connect(self.add_search) - 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) + b = self.bb.addButton(_('&Remove search'), self.bb.ActionRole) + b.setIcon(QIcon(I('minus.png'))) + b.clicked.connect(self.del_search) - self.current_search_name = None - self.searches = {} - for name in db.saved_search_names(): - self.searches[name] = db.saved_search_lookup(name) - self.search_names = set([icu_lower(n) for n in db.saved_search_names()]) + b = self.bb.addButton(_('Re&name search'), self.bb.ActionRole) + b.setIcon(QIcon(I('modified.png'))) + b.clicked.connect(self.rename_search) + self.slist = QListWidget(self) + self.searches = {name: db.saved_search_lookup(name) for name in db.saved_search_names()} self.populate_search_list() - if initial_search is not None and initial_search in self.searches: - self.select_search(initial_search) + if self.initial_search is not None and self.initial_search in self.searches: + self.select_search(self.initial_search) + elif self.searches: + self.slist.setCurrentRow(0) + self.slist.currentItemChanged.connect(self.current_index_changed) + l.addWidget(self.slist) + + self.desc = la = QLabel('\xa0') + la.setWordWrap(True) + l.addWidget(la) + + l.addWidget(self.bb) + self.current_index_changed(self.slist.currentItem()) + self.setMinimumHeight(500) + self.setMinimumWidth(600) + + @property + def current_search_name(self): + i = self.slist.currentItem() + if i is not None: + ans = i.text() + if ans in self.searches: + return ans def populate_search_list(self): - self.search_name_box.blockSignals(True) - self.search_name_box.clear() - self.search_name_box.addItem('') + self.slist.clear() for name in sorted(self.searches.keys(), key=sort_key): - self.search_name_box.addItem(name) - self.search_names = set([icu_lower(n) for n in self.searches.keys()]) - self.search_name_box.blockSignals(False) - - def sanitize_name(self): - n = unicode(self.input_box.text()).strip().replace('\\', '') - self.input_box.setText(n) - return n + self.slist.addItem(name) def add_search(self): - self.save_current_search() - search_name = self.sanitize_name() - 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_() - return False - if search_name not in self.searches: - self.searches[search_name] = '' - self.populate_search_list() - self.select_search(search_name) - else: - self.select_search(search_name) - return True + d = AddSavedSearch(parent=self, commit_changes=False) + if d.exec_() != d.Accepted: + return + name, expression = d.accepted_data + nmap = {icu_lower(n):n for n in self.searches} + if icu_lower(name) in nmap: + q = nmap[icu_lower(name)] + del self.searches[q] + self.select_search(q) + self.slist.takeItem(self.slist.currentRow()) + self.searches[name] = expression + self.slist.insertItem(0, name) + self.slist.setCurrentRow(0) + self.current_index_changed(self.slist.currentItem()) def del_search(self): - if self.current_search_name is not None: + n = self.current_search_name + if n is not None: 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 - self.search_name_box.removeItem(self.search_name_box.currentIndex()) + self.slist.takeItem(self.slist.currentRow()) + del self.searches[n] def rename_search(self): - self.save_current_search() - new_search_name = self.sanitize_name() - 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_() - return False - if self.current_search_name in self.searches: - self.searches[new_search_name] = self.searches[self.current_search_name] - del self.searches[self.current_search_name] - self.current_search_name = None - self.populate_search_list() - self.select_search(new_search_name) - return True + 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) def select_search(self, name): - self.search_name_box.setCurrentIndex(self.search_name_box.findText(name)) + items = self.slist.findItems(name, Qt.MatchFixedString | Qt.MatchCaseSensitive) + if items: + self.slist.setCurrentItem(items[0]) - def current_index_changed(self, idx): - if self.current_search_name: - 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]) + def current_index_changed(self, item): + n = self.current_search_name + if n: + t = self.searches[n] else: - 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()) + t = '' + self.desc.setText('

{}: '.format(_('Search expression')) + prepare_string_for_xml(t)) def accept(self): - self.save_current_search() - ss = {name: self.searches[name] for name in self.searches} - commit_searches(ss) - QDialog.accept(self) + commit_searches(self.searches) + Dialog.accept(self)