First cut at DB preferences

This commit is contained in:
Charles Haley 2010-07-19 09:50:29 +01:00
parent a3d8ce4850
commit 77ddc1fedf
8 changed files with 70 additions and 40 deletions

View File

@ -25,8 +25,8 @@ class SavedSearchEditor(QDialog, Ui_SavedSearchEditor):
self.current_search_name = None self.current_search_name = None
self.searches = {} self.searches = {}
self.searches_to_delete = [] self.searches_to_delete = []
for name in saved_searches.names(): for name in saved_searches().names():
self.searches[name] = saved_searches.lookup(name) self.searches[name] = saved_searches().lookup(name)
self.populate_search_list() self.populate_search_list()
if initial_search is not None and initial_search in self.searches: if initial_search is not None and initial_search in self.searches:
@ -78,7 +78,7 @@ class SavedSearchEditor(QDialog, Ui_SavedSearchEditor):
if self.current_search_name: if self.current_search_name:
self.searches[self.current_search_name] = unicode(self.search_text.toPlainText()) self.searches[self.current_search_name] = unicode(self.search_text.toPlainText())
for name in self.searches_to_delete: for name in self.searches_to_delete:
saved_searches.delete(name) saved_searches().delete(name)
for name in self.searches: for name in self.searches:
saved_searches.add(name, self.searches[name]) saved_searches().add(name, self.searches[name])
QDialog.accept(self) QDialog.accept(self)

View File

@ -7,7 +7,6 @@ from PyQt4.QtCore import SIGNAL, Qt
from PyQt4.QtGui import QDialog, QIcon, QListWidgetItem from PyQt4.QtGui import QDialog, QIcon, QListWidgetItem
from calibre.gui2.dialogs.tag_categories_ui import Ui_TagCategories from calibre.gui2.dialogs.tag_categories_ui import Ui_TagCategories
from calibre.utils.config import prefs
from calibre.gui2.dialogs.confirm_delete import confirm from calibre.gui2.dialogs.confirm_delete import confirm
from calibre.constants import islinux from calibre.constants import islinux
@ -63,7 +62,7 @@ class TagCategories(QDialog, Ui_TagCategories):
self.all_items.append(t) self.all_items.append(t)
self.all_items_dict[label+':'+n] = t self.all_items_dict[label+':'+n] = t
self.categories = dict.copy(prefs['user_categories']) self.categories = dict.copy(db.prefs['user_categories'])
if self.categories is None: if self.categories is None:
self.categories = {} self.categories = {}
for cat in self.categories: for cat in self.categories:
@ -182,7 +181,7 @@ class TagCategories(QDialog, Ui_TagCategories):
def accept(self): def accept(self):
self.save_category() self.save_category()
prefs['user_categories'] = self.categories self.db.prefs['user_categories'] = self.categories
QDialog.accept(self) QDialog.accept(self)
def save_category(self): def save_category(self):

View File

@ -259,8 +259,7 @@ class SavedSearchBox(QComboBox):
self.setMinimumContentsLength(10) self.setMinimumContentsLength(10)
self.tool_tip_text = self.toolTip() self.tool_tip_text = self.toolTip()
def initialize(self, _saved_searches, _search_box, colorize=False, help_text=_('Search')): def initialize(self, _search_box, colorize=False, help_text=_('Search')):
self.saved_searches = _saved_searches
self.search_box = _search_box self.search_box = _search_box
self.help_text = help_text self.help_text = help_text
self.colorize = colorize self.colorize = colorize
@ -302,11 +301,11 @@ class SavedSearchBox(QComboBox):
self.normalize_state() self.normalize_state()
self.search_box.set_search_string(u'search:"%s"' % qname) self.search_box.set_search_string(u'search:"%s"' % qname)
self.setEditText(qname) self.setEditText(qname)
self.setToolTip(self.saved_searches.lookup(qname)) self.setToolTip(saved_searches().lookup(qname))
def initialize_saved_search_names(self): def initialize_saved_search_names(self):
self.clear() self.clear()
qnames = self.saved_searches.names() qnames = saved_searches().names()
self.addItems(qnames) self.addItems(qnames)
self.setCurrentIndex(-1) self.setCurrentIndex(-1)
@ -319,10 +318,10 @@ class SavedSearchBox(QComboBox):
idx = self.currentIndex idx = self.currentIndex
if idx < 0: if idx < 0:
return return
ss = self.saved_searches.lookup(unicode(self.currentText())) ss = saved_searches().lookup(unicode(self.currentText()))
if ss is None: if ss is None:
return return
self.saved_searches.delete(unicode(self.currentText())) saved_searches().delete(unicode(self.currentText()))
self.clear_to_help() self.clear_to_help()
self.search_box.clear_to_help() self.search_box.clear_to_help()
self.emit(SIGNAL('changed()')) self.emit(SIGNAL('changed()'))
@ -332,8 +331,8 @@ class SavedSearchBox(QComboBox):
name = unicode(self.currentText()) name = unicode(self.currentText())
if self.help_state or not name.strip(): if self.help_state or not name.strip():
name = unicode(self.search_box.text()).replace('"', '') name = unicode(self.search_box.text()).replace('"', '')
self.saved_searches.delete(name) saved_searches().delete(name)
self.saved_searches.add(name, unicode(self.search_box.text())) saved_searches().add(name, unicode(self.search_box.text()))
# now go through an initialization cycle to ensure that the combobox has # now go through an initialization cycle to ensure that the combobox has
# the new search in it, that it is selected, and that the search box # the new search in it, that it is selected, and that the search box
# references the new search instead of the text in the search. # references the new search instead of the text in the search.
@ -348,7 +347,7 @@ class SavedSearchBox(QComboBox):
idx = self.currentIndex(); idx = self.currentIndex();
if idx < 0: if idx < 0:
return return
self.search_box.set_search_string(self.saved_searches.lookup(unicode(self.currentText()))) self.search_box.set_search_string(saved_searches().lookup(unicode(self.currentText())))
class SearchBoxMixin(object): class SearchBoxMixin(object):
@ -390,11 +389,12 @@ class SearchBoxMixin(object):
class SavedSearchBoxMixin(object): class SavedSearchBoxMixin(object):
def __init__(self): def __init__(self, db):
self.db = db
self.connect(self.saved_search, SIGNAL('changed()'), self.saved_searches_changed) self.connect(self.saved_search, SIGNAL('changed()'), self.saved_searches_changed)
self.saved_searches_changed() self.saved_searches_changed()
self.connect(self.clear_button, SIGNAL('clicked()'), self.saved_search.clear_to_help) self.connect(self.clear_button, SIGNAL('clicked()'), self.saved_search.clear_to_help)
self.saved_search.initialize(saved_searches, self.search, colorize=True, self.saved_search.initialize(self.search, colorize=True,
help_text=_('Saved Searches')) help_text=_('Saved Searches'))
self.connect(self.save_search_button, SIGNAL('clicked()'), self.connect(self.save_search_button, SIGNAL('clicked()'),
self.saved_search.save_search_button_clicked) self.saved_search.save_search_button_clicked)
@ -409,9 +409,12 @@ class SavedSearchBoxMixin(object):
b = getattr(self, x+'_search_button') b = getattr(self, x+'_search_button')
b.setStatusTip(b.toolTip()) b.setStatusTip(b.toolTip())
def set_database(self, db):
self.db = db
self.saved_searches_changed()
def saved_searches_changed(self): def saved_searches_changed(self):
p = prefs['saved_searches'].keys() p = saved_searches().names()
p.sort() p.sort()
t = unicode(self.search_restriction.currentText()) t = unicode(self.search_restriction.currentText())
self.search_restriction.clear() # rebuild the restrictions combobox using current saved searches self.search_restriction.clear() # rebuild the restrictions combobox using current saved searches

View File

@ -224,7 +224,7 @@ class TagsView(QTreeView): # {{{
# Always show the user categories editor # Always show the user categories editor
self.context_menu.addSeparator() self.context_menu.addSeparator()
if category in prefs['user_categories'].keys(): if category in self.db.prefs['user_categories'].keys():
self.context_menu.addAction(_('Manage User Categories'), self.context_menu.addAction(_('Manage User Categories'),
partial(self.context_menu_handler, action='manage_categories', partial(self.context_menu_handler, action='manage_categories',
category=category)) category=category))
@ -426,10 +426,10 @@ class TagsModel(QAbstractItemModel): # {{{
for k in tb_cats.keys(): for k in tb_cats.keys():
if tb_cats[k]['kind'] in ['user', 'search']: if tb_cats[k]['kind'] in ['user', 'search']:
del tb_cats[k] del tb_cats[k]
for user_cat in sorted(prefs['user_categories'].keys()): for user_cat in sorted(self.db.prefs['user_categories'].keys()):
cat_name = user_cat+':' # add the ':' to avoid name collision cat_name = user_cat+':' # add the ':' to avoid name collision
tb_cats.add_user_category(label=cat_name, name=user_cat) tb_cats.add_user_category(label=cat_name, name=user_cat)
if len(saved_searches.names()): if len(saved_searches().names()):
tb_cats.add_search_category(label='search', name=_('Searches')) tb_cats.add_search_category(label='search', name=_('Searches'))
# Now get the categories # Now get the categories
@ -507,11 +507,11 @@ class TagsModel(QAbstractItemModel): # {{{
if key not in self.db.field_metadata: if key not in self.db.field_metadata:
return return
if key == 'search': if key == 'search':
if val in saved_searches.names(): if val in saved_searches().names():
error_dialog(self.tags_view, _('Duplicate search name'), error_dialog(self.tags_view, _('Duplicate search name'),
_('The saved search name %s is already used.')%val).exec_() _('The saved search name %s is already used.')%val).exec_()
return False return False
saved_searches.rename(unicode(item.data(role).toString()), val) saved_searches().rename(unicode(item.data(role).toString()), val)
self.tags_view.search_item_renamed.emit() self.tags_view.search_item_renamed.emit()
else: else:
if key == 'series': if key == 'series':

View File

@ -199,7 +199,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{
UpdateMixin.__init__(self, opts) UpdateMixin.__init__(self, opts)
####################### Search boxes ######################## ####################### Search boxes ########################
SavedSearchBoxMixin.__init__(self) SavedSearchBoxMixin.__init__(self, db)
SearchBoxMixin.__init__(self) SearchBoxMixin.__init__(self)
####################### Library view ######################## ####################### Library view ########################
@ -392,6 +392,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{
self.library_view.model().set_book_on_device_func(self.book_on_device) self.library_view.model().set_book_on_device_func(self.book_on_device)
self.status_bar.clear_message() self.status_bar.clear_message()
self.search.clear_to_help() self.search.clear_to_help()
self.saved_search.clear_to_help()
self.book_details.reset_info() self.book_details.reset_info()
self.library_view.model().count_changed() self.library_view.model().count_changed()
self.scheduler.database_changed(db) self.scheduler.database_changed(db)

View File

@ -30,7 +30,7 @@ from calibre.customize.ui import run_plugins_on_import
from calibre.utils.filenames import ascii_filename from calibre.utils.filenames import ascii_filename
from calibre.utils.date import utcnow, now as nowf, utcfromtimestamp from calibre.utils.date import utcnow, now as nowf, utcfromtimestamp
from calibre.utils.config import prefs, tweaks from calibre.utils.config import prefs, tweaks
from calibre.utils.search_query_parser import saved_searches from calibre.utils.search_query_parser import saved_searches, set_saved_searches
from calibre.ebooks import BOOK_EXTENSIONS, check_ebook_format from calibre.ebooks import BOOK_EXTENSIONS, check_ebook_format
from calibre.utils.magick_draw import save_cover_data_to from calibre.utils.magick_draw import save_cover_data_to
@ -142,6 +142,24 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
def initialize_dynamic(self): def initialize_dynamic(self):
self.prefs = DBPrefs(self) self.prefs = DBPrefs(self)
# Migrate saved search and user categories to db preference scheme
def migrate_preference(name):
ans = self.prefs.get(name, None)
if ans is None:
ans = prefs[name]
try:
del prefs[name]
except:
pass
if ans is not None:
self.prefs[name] = ans
migrate_preference('user_categories')
migrate_preference('saved_searches')
set_saved_searches(self, 'saved_searches')
self.conn.executescript(''' self.conn.executescript('''
DROP TRIGGER IF EXISTS author_insert_trg; DROP TRIGGER IF EXISTS author_insert_trg;
CREATE TEMP TRIGGER author_insert_trg CREATE TEMP TRIGGER author_insert_trg
@ -270,10 +288,10 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
for k in tb_cats.keys(): for k in tb_cats.keys():
if tb_cats[k]['kind'] in ['user', 'search']: if tb_cats[k]['kind'] in ['user', 'search']:
del tb_cats[k] del tb_cats[k]
for user_cat in sorted(prefs['user_categories'].keys()): for user_cat in sorted(self.prefs['user_categories'].keys()):
cat_name = user_cat+':' # add the ':' to avoid name collision cat_name = user_cat+':' # add the ':' to avoid name collision
tb_cats.add_user_category(label=cat_name, name=user_cat) tb_cats.add_user_category(label=cat_name, name=user_cat)
if len(saved_searches.names()): if len(saved_searches().names()):
tb_cats.add_search_category(label='search', name=_('Searches')) tb_cats.add_search_category(label='search', name=_('Searches'))
self.book_on_device_func = None self.book_on_device_func = None
@ -845,7 +863,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
categories['formats'].sort(key = lambda x:x.name) categories['formats'].sort(key = lambda x:x.name)
#### Now do the user-defined categories. #### #### Now do the user-defined categories. ####
user_categories = prefs['user_categories'] user_categories = self.prefs['user_categories']
# We want to use same node in the user category as in the source # We want to use same node in the user category as in the source
# category. To do that, we need to find the original Tag node. There is # category. To do that, we need to find the original Tag node. There is
@ -882,8 +900,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
icon = None icon = None
if icon_map and 'search' in icon_map: if icon_map and 'search' in icon_map:
icon = icon_map['search'] icon = icon_map['search']
for srch in saved_searches.names(): for srch in saved_searches().names():
items.append(Tag(srch, tooltip=saved_searches.lookup(srch), icon=icon)) items.append(Tag(srch, tooltip=saved_searches().lookup(srch), icon=icon))
if len(items): if len(items):
if icon_map is not None: if icon_map is not None:
icon_map['search'] = icon_map['search'] icon_map['search'] = icon_map['search']

View File

@ -397,4 +397,3 @@ class SchemaUpgrade(object):
UNIQUE(key)); UNIQUE(key));
''' '''
self.conn.executescript(script) self.conn.executescript(script)

View File

@ -21,7 +21,6 @@ import sys, string, operator
from calibre.utils.pyparsing import Keyword, Group, Forward, CharsNotIn, Suppress, \ from calibre.utils.pyparsing import Keyword, Group, Forward, CharsNotIn, Suppress, \
OneOrMore, oneOf, CaselessLiteral, Optional, NoMatch, ParseException OneOrMore, oneOf, CaselessLiteral, Optional, NoMatch, ParseException
from calibre.constants import preferred_encoding from calibre.constants import preferred_encoding
from calibre.utils.config import prefs
''' '''
This class manages access to the preference holding the saved search queries. This class manages access to the preference holding the saved search queries.
@ -32,9 +31,13 @@ class SavedSearchQueries(object):
queries = {} queries = {}
opt_name = '' opt_name = ''
def __init__(self, _opt_name): def __init__(self, db, _opt_name):
self.opt_name = _opt_name; self.opt_name = _opt_name;
self.queries = prefs[self.opt_name] self.db = db
if db is not None:
self.queries = db.prefs[self.opt_name]
else:
self.queries = {}
def force_unicode(self, x): def force_unicode(self, x):
if not isinstance(x, unicode): if not isinstance(x, unicode):
@ -43,20 +46,20 @@ class SavedSearchQueries(object):
def add(self, name, value): def add(self, name, value):
self.queries[self.force_unicode(name)] = self.force_unicode(value).strip() self.queries[self.force_unicode(name)] = self.force_unicode(value).strip()
prefs[self.opt_name] = self.queries self.db.prefs[self.opt_name] = self.queries
def lookup(self, name): def lookup(self, name):
return self.queries.get(self.force_unicode(name), None) return self.queries.get(self.force_unicode(name), None)
def delete(self, name): def delete(self, name):
self.queries.pop(self.force_unicode(name), False) self.queries.pop(self.force_unicode(name), False)
prefs[self.opt_name] = self.queries self.db.prefs[self.opt_name] = self.queries
def rename(self, old_name, new_name): def rename(self, old_name, new_name):
self.queries[self.force_unicode(new_name)] = \ self.queries[self.force_unicode(new_name)] = \
self.queries.get(self.force_unicode(old_name), None) self.queries.get(self.force_unicode(old_name), None)
self.queries.pop(self.force_unicode(old_name), False) self.queries.pop(self.force_unicode(old_name), False)
prefs[self.opt_name] = self.queries self.db.prefs[self.opt_name] = self.queries
def names(self): def names(self):
return sorted(self.queries.keys(), return sorted(self.queries.keys(),
@ -66,8 +69,15 @@ class SavedSearchQueries(object):
Create a global instance of the saved searches. It is global so that the searches Create a global instance of the saved searches. It is global so that the searches
are common across all instances of the parser (devices, library, etc). are common across all instances of the parser (devices, library, etc).
''' '''
saved_searches = SavedSearchQueries('saved_searches') ss = SavedSearchQueries(None, None)
def set_saved_searches(db, opt_name):
global ss
ss = SavedSearchQueries(db, opt_name)
def saved_searches():
global ss
return ss
class SearchQueryParser(object): class SearchQueryParser(object):
''' '''
@ -209,7 +219,7 @@ class SearchQueryParser(object):
raise ParseException(query, len(query), 'undefined saved search', self) raise ParseException(query, len(query), 'undefined saved search', self)
if self.recurse_level > 5: if self.recurse_level > 5:
self.searches_seen.add(query) self.searches_seen.add(query)
return self._parse(saved_searches.lookup(query)) return self._parse(saved_searches().lookup(query))
except: # convert all exceptions (e.g., missing key) to a parse error except: # convert all exceptions (e.g., missing key) to a parse error
raise ParseException(query, len(query), 'undefined saved search', self) raise ParseException(query, len(query), 'undefined saved search', self)
return self.get_matches(location, query) return self.get_matches(location, query)