mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
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:
parent
761b2f4aa8
commit
ec281bfa42
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user