%PDF- %PDF-
Direktori : /lib/calibre/calibre/gui2/dialogs/ |
Current File : //lib/calibre/calibre/gui2/dialogs/saved_search_editor.py |
#!/usr/bin/env python3 # License: GPLv3 Copyright: 2008, Kovid Goyal <kovid at kovidgoyal.net> from qt.core import ( QFormLayout, QIcon, QLabel, QLineEdit, QListWidget, Qt, QVBoxLayout, QDialog, QDialogButtonBox, QPlainTextEdit ) 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): 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, 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) 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):n for n in db.saved_search_names()} def setup_ui(self): self.l = l = QFormLayout(self) l.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow) self.la = la = QLabel(self.label or _( 'You can create a <i>Saved search</i>, for frequently used searches here.' ' The search will be visible under <i>Saved searches</i> 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 = QPlainTextEdit(self) s.setMinimumWidth(400) l.addRow(_('&Search:'), s) s.setPlaceholderText(_('The search expression')) if self.initial_search: s.setPlainText(self.initial_search) n.setFocus(Qt.FocusReason.OtherFocusReason) l.addRow(self.bb) def accept(self): name = self.sname.text().strip() if not name: return error_dialog( self, _('No search name'), _('You must specify a name for the Saved search'), show=True) expression = self.search.toPlainText().strip() if not expression: return error_dialog( self, _('No search expression'), _('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) self.searches[name] = expression commit_searches(self.searches) 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 self.l = l = QVBoxLayout(self) b = self.bb.addButton(_('&Add search'), QDialogButtonBox.ButtonRole.ActionRole) b.setIcon(QIcon(I('plus.png'))) b.clicked.connect(self.add_search) b = self.bb.addButton(_('&Remove search'), QDialogButtonBox.ButtonRole.ActionRole) b.setIcon(QIcon(I('minus.png'))) b.clicked.connect(self.del_search) b = self.bb.addButton(_('&Edit search'), QDialogButtonBox.ButtonRole.ActionRole) b.setIcon(QIcon(I('modified.png'))) b.clicked.connect(self.edit_search) self.slist = QListWidget(self) self.slist.setStyleSheet('QListView::item { padding: 3px }') self.slist.activated.connect(self.edit_search) 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: 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 keyPressEvent(self, ev): if ev.key() == Qt.Key.Key_Delete: self.del_search() return return Dialog.keyPressEvent(self, ev) def populate_search_list(self): self.slist.clear() for name in sorted(self.searches.keys(), key=sort_key): self.slist.addItem(name) def add_search(self): d = AddSavedSearch(parent=self, commit_changes=False, validate=self.validate_add) if d.exec() != QDialog.DialogCode.Accepted: return name, expression = d.accepted_data self.searches[name] = expression self.populate_search_list() self.select_search(name) def del_search(self): n = self.current_search_name if n is not None: if not confirm( '<p>' + _( 'The current saved search will be ' '<b>permanently deleted</b>. Are you sure?') + '</p>', 'saved_search_editor_delete', self): return self.slist.takeItem(self.slist.currentRow()) del self.searches[n] def edit_search(self): n = self.current_search_name 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.setPlainText(self.searches[n]) if d.exec() != QDialog.DialogCode.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 duplicate_msg(self, name): return _('A saved search with the name {} already exists. Choose another name').format(name) 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 self.duplicate_msg(name) def validate_add(self, name, expression): if icu_lower(name) in {icu_lower(n) for n in self.searches}: return self.duplicate_msg(name) def select_search(self, name): items = self.slist.findItems(name, Qt.MatchFlag.MatchFixedString | Qt.MatchFlag.MatchCaseSensitive) if items: self.slist.setCurrentItem(items[0]) def current_index_changed(self, item): n = self.current_search_name if n: t = self.searches[n] else: t = '' self.desc.setText('<p><b>{}</b>: '.format(_('Search expression')) + prepare_string_for_xml(t)) def accept(self): commit_searches(self.searches) Dialog.accept(self)