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 import prepare_string_for_xml
|
||||||
from calibre.utils.icu import sort_key
|
|
||||||
from calibre.gui2 import error_dialog
|
from calibre.gui2 import error_dialog
|
||||||
from calibre.gui2.dialogs.confirm_delete import confirm
|
from calibre.gui2.dialogs.confirm_delete import confirm
|
||||||
from calibre.gui2.widgets2 import Dialog
|
from calibre.gui2.widgets2 import Dialog
|
||||||
|
from calibre.utils.icu import sort_key
|
||||||
|
|
||||||
|
|
||||||
def commit_searches(searches):
|
def commit_searches(searches):
|
||||||
@ -19,8 +23,9 @@ def commit_searches(searches):
|
|||||||
|
|
||||||
class AddSavedSearch(Dialog):
|
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.initial_search = search
|
||||||
|
self.commit_changes = commit_changes
|
||||||
Dialog.__init__(
|
Dialog.__init__(
|
||||||
self, _('Add a new Saved search'), 'add-saved-search', parent)
|
self, _('Add a new Saved search'), 'add-saved-search', parent)
|
||||||
from calibre.gui2.ui import get_gui
|
from calibre.gui2.ui import get_gui
|
||||||
@ -28,7 +33,7 @@ class AddSavedSearch(Dialog):
|
|||||||
self.searches = {}
|
self.searches = {}
|
||||||
for name in db.saved_search_names():
|
for name in db.saved_search_names():
|
||||||
self.searches[name] = db.saved_search_lookup(name)
|
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):
|
def setup_ui(self):
|
||||||
self.l = l = QFormLayout(self)
|
self.l = l = QFormLayout(self)
|
||||||
@ -70,127 +75,118 @@ class AddSavedSearch(Dialog):
|
|||||||
_('No search expression'),
|
_('No search expression'),
|
||||||
_('You must specify a search expression for the Saved search'),
|
_('You must specify a search expression for the Saved search'),
|
||||||
show=True)
|
show=True)
|
||||||
if icu_lower(name) in self.searches:
|
self.accepted_data = name, expression
|
||||||
self.searches.pop(icu_lower(name), None)
|
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
|
self.searches[name] = expression
|
||||||
commit_searches(self.searches)
|
commit_searches(self.searches)
|
||||||
|
|
||||||
|
|
||||||
class SavedSearchEditor(QDialog, Ui_SavedSearchEditor):
|
class SavedSearchEditor(Dialog):
|
||||||
|
|
||||||
def __init__(self, parent, initial_search=None):
|
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
|
from calibre.gui2.ui import get_gui
|
||||||
db = get_gui().current_db
|
db = get_gui().current_db
|
||||||
QDialog.__init__(self, parent)
|
self.l = l = QVBoxLayout(self)
|
||||||
Ui_SavedSearchEditor.__init__(self)
|
b = self.bb.addButton(_('&Add search'), self.bb.ActionRole)
|
||||||
self.setupUi(self)
|
b.setIcon(QIcon(I('plus.png')))
|
||||||
|
b.clicked.connect(self.add_search)
|
||||||
|
|
||||||
self.add_search_button.clicked.connect(self.add_search)
|
b = self.bb.addButton(_('&Remove search'), self.bb.ActionRole)
|
||||||
self.search_name_box.currentIndexChanged[(
|
b.setIcon(QIcon(I('minus.png')))
|
||||||
int)].connect(self.current_index_changed)
|
b.clicked.connect(self.del_search)
|
||||||
self.delete_search_button.clicked.connect(self.del_search)
|
|
||||||
self.rename_button.clicked.connect(self.rename_search)
|
|
||||||
|
|
||||||
self.current_search_name = None
|
b = self.bb.addButton(_('Re&name search'), self.bb.ActionRole)
|
||||||
self.searches = {}
|
b.setIcon(QIcon(I('modified.png')))
|
||||||
for name in db.saved_search_names():
|
b.clicked.connect(self.rename_search)
|
||||||
self.searches[name] = db.saved_search_lookup(name)
|
|
||||||
self.search_names = set([icu_lower(n) for n in db.saved_search_names()])
|
|
||||||
|
|
||||||
|
self.slist = QListWidget(self)
|
||||||
|
self.searches = {name: db.saved_search_lookup(name) for name in db.saved_search_names()}
|
||||||
self.populate_search_list()
|
self.populate_search_list()
|
||||||
if initial_search is not None and initial_search in self.searches:
|
if self.initial_search is not None and self.initial_search in self.searches:
|
||||||
self.select_search(initial_search)
|
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):
|
def populate_search_list(self):
|
||||||
self.search_name_box.blockSignals(True)
|
self.slist.clear()
|
||||||
self.search_name_box.clear()
|
|
||||||
self.search_name_box.addItem('')
|
|
||||||
for name in sorted(self.searches.keys(), key=sort_key):
|
for name in sorted(self.searches.keys(), key=sort_key):
|
||||||
self.search_name_box.addItem(name)
|
self.slist.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
|
|
||||||
|
|
||||||
def add_search(self):
|
def add_search(self):
|
||||||
self.save_current_search()
|
d = AddSavedSearch(parent=self, commit_changes=False)
|
||||||
search_name = self.sanitize_name()
|
if d.exec_() != d.Accepted:
|
||||||
if search_name == '':
|
return
|
||||||
return False
|
name, expression = d.accepted_data
|
||||||
if icu_lower(search_name) in self.search_names:
|
nmap = {icu_lower(n):n for n in self.searches}
|
||||||
error_dialog(
|
if icu_lower(name) in nmap:
|
||||||
self,
|
q = nmap[icu_lower(name)]
|
||||||
_('Saved search already exists'),
|
del self.searches[q]
|
||||||
_(
|
self.select_search(q)
|
||||||
'The saved search %s already exists, perhaps with '
|
self.slist.takeItem(self.slist.currentRow())
|
||||||
'different case') % search_name).exec_()
|
self.searches[name] = expression
|
||||||
return False
|
self.slist.insertItem(0, name)
|
||||||
if search_name not in self.searches:
|
self.slist.setCurrentRow(0)
|
||||||
self.searches[search_name] = ''
|
self.current_index_changed(self.slist.currentItem())
|
||||||
self.populate_search_list()
|
|
||||||
self.select_search(search_name)
|
|
||||||
else:
|
|
||||||
self.select_search(search_name)
|
|
||||||
return True
|
|
||||||
|
|
||||||
def del_search(self):
|
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(
|
if not confirm(
|
||||||
'<p>' + _(
|
'<p>' + _(
|
||||||
'The current saved search will be '
|
'The current saved search will be '
|
||||||
'<b>permanently deleted</b>. Are you sure?') + '</p>',
|
'<b>permanently deleted</b>. Are you sure?') + '</p>',
|
||||||
'saved_search_editor_delete', self):
|
'saved_search_editor_delete', self):
|
||||||
return
|
return
|
||||||
del self.searches[self.current_search_name]
|
self.slist.takeItem(self.slist.currentRow())
|
||||||
self.current_search_name = None
|
del self.searches[n]
|
||||||
self.search_name_box.removeItem(self.search_name_box.currentIndex())
|
|
||||||
|
|
||||||
def rename_search(self):
|
def rename_search(self):
|
||||||
self.save_current_search()
|
n = self.current_search_name
|
||||||
new_search_name = self.sanitize_name()
|
if n:
|
||||||
if new_search_name == '':
|
text, ok = QInputDialog.getText(self, _('Rename saved search'), _('&New name:'))
|
||||||
return False
|
if ok and text:
|
||||||
if icu_lower(new_search_name) in self.search_names:
|
self.slist.currentItem().setText(text)
|
||||||
error_dialog(
|
self.searches[text] = self.searches.pop(n)
|
||||||
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
|
|
||||||
|
|
||||||
def select_search(self, name):
|
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):
|
def current_index_changed(self, item):
|
||||||
if self.current_search_name:
|
n = self.current_search_name
|
||||||
self.searches[self.current_search_name] = unicode(
|
if n:
|
||||||
self.search_text.toPlainText())
|
t = self.searches[n]
|
||||||
name = unicode(self.search_name_box.itemText(idx))
|
|
||||||
if name:
|
|
||||||
self.current_search_name = name
|
|
||||||
self.search_text.setPlainText(self.searches[name])
|
|
||||||
else:
|
else:
|
||||||
self.current_search_name = None
|
t = ''
|
||||||
self.search_text.setPlainText('')
|
self.desc.setText('<p><b>{}</b>: '.format(_('Search expression')) + prepare_string_for_xml(t))
|
||||||
|
|
||||||
def save_current_search(self):
|
|
||||||
if self.current_search_name:
|
|
||||||
self.searches[self.current_search_name] = unicode(
|
|
||||||
self.search_text.toPlainText())
|
|
||||||
|
|
||||||
def accept(self):
|
def accept(self):
|
||||||
self.save_current_search()
|
commit_searches(self.searches)
|
||||||
ss = {name: self.searches[name] for name in self.searches}
|
Dialog.accept(self)
|
||||||
commit_searches(ss)
|
|
||||||
QDialog.accept(self)
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user