Make the Manage saved searches dialog a little easier for new users. Fixes #1733163 [Suggestions to the Saved search editor](https://bugs.launchpad.net/calibre/+bug/1733163)

This commit is contained in:
Kovid Goyal 2017-11-19 20:37:38 +05:30
parent 761b2f4aa8
commit ec281bfa42
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C

View File

@ -1,14 +1,18 @@
__license__ = 'GPL v3'
#!/usr/bin/env python2
# vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2008, Kovid Goyal <kovid at kovidgoyal.net>
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
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(
'<p>' + _(
'The current saved search will be '
'<b>permanently deleted</b>. Are you sure?') + '</p>',
'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('<p><b>{}</b>: '.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)