Add preference to automatically set a tag when adding books (Preferences->General). Add a tweak to create compound search terms. Show error message in tooltip when user inputs an invalid search query.

This commit is contained in:
Kovid Goyal 2010-09-02 08:30:13 -06:00
commit cb4cc4219a
11 changed files with 103 additions and 17 deletions

View File

@ -90,4 +90,18 @@ save_template_title_series_sorting = 'library_order'
# Examples:
# auto_connect_to_folder = 'C:\\Users\\someone\\Desktop\\testlib'
# auto_connect_to_folder = '/home/dropbox/My Dropbox/someone/library'
auto_connect_to_folder = ''
auto_connect_to_folder = ''
# Create search terms to apply a query across several built-in search terms.
# Syntax: {'new term':['existing term 1', 'term 2', ...], 'new':['old'...] ...}
# Example: create the term 'myseries' that when used as myseries:foo would
# search all of the search categories 'series', '#myseries', and '#myseries2':
# grouped_search_terms={'myseries':['series','#myseries', '#myseries2']}
# Example: two search terms 'a' and 'b' both that search 'tags' and '#mytags':
# grouped_search_terms={'a':['tags','#mytags'], 'b':['tags','#mytags']}
# Note: You cannot create a search term that is a duplicate of an existing term.
# Such duplicates will be silently ignored. Also note that search terms ignore
# case. 'MySearch' and 'mysearch' are the same term.
grouped_search_terms = {}

View File

@ -66,7 +66,8 @@ class Worker(Thread):
for identical_book in identical_book_list:
self.add_formats(identical_book, paths, newdb, replace=False)
if not added:
newdb.import_book(mi, paths, notify=False, import_hooks=False)
newdb.import_book(mi, paths, notify=False, import_hooks=False,
apply_import_tags=False)
co = self.db.conversion_options(x, 'PIPE')
if co is not None:
newdb.set_conversion_options(x, 'PIPE', co)

View File

@ -457,6 +457,7 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
self.priority.setCurrentIndex(p)
self.priority.setVisible(iswindows)
self.priority_label.setVisible(iswindows)
self.new_book_tags.setText(', '.join(prefs['new_book_tags']))
self._plugin_model = PluginModel()
self.plugin_view.setModel(self._plugin_model)
self.plugin_view.setStyleSheet(
@ -906,6 +907,9 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
config['disable_tray_notification'] = not self.systray_notifications.isChecked()
p = {0:'normal', 1:'high', 2:'low'}[self.priority.currentIndex()]
prefs['worker_process_priority'] = p
nbt = [x.strip() for x in
unicode(self.new_book_tags.text()).strip().split(',')]
prefs['new_book_tags'] = [x for x in nbt if x]
prefs['output_format'] = unicode(self.output_format.currentText()).upper()
config['cover_flow_queue_length'] = self.cover_browse.value()
prefs['language'] = str(self.language.itemData(self.language.currentIndex()).toString())

View File

@ -136,7 +136,7 @@
</item>
<item>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0">
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Default network &amp;timeout:</string>
@ -146,7 +146,7 @@
</property>
</widget>
</item>
<item row="1" column="1">
<item row="2" column="1">
<widget class="QSpinBox" name="timeout">
<property name="toolTip">
<string>Set the default timeout for network fetches (i.e. anytime we go out to the internet to get information)</string>
@ -165,10 +165,10 @@
</property>
</widget>
</item>
<item row="2" column="1">
<item row="3" column="1">
<widget class="QComboBox" name="language"/>
</item>
<item row="2" column="0">
<item row="3" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Choose &amp;language (requires restart):</string>
@ -178,7 +178,7 @@
</property>
</widget>
</item>
<item row="3" column="1">
<item row="4" column="1">
<widget class="QComboBox" name="priority">
<item>
<property name="text">
@ -197,7 +197,7 @@
</item>
</widget>
</item>
<item row="3" column="0">
<item row="4" column="0">
<widget class="QLabel" name="priority_label">
<property name="text">
<string>Job &amp;priority:</string>
@ -207,7 +207,7 @@
</property>
</widget>
</item>
<item row="0" column="0">
<item row="1" column="0">
<widget class="QLabel" name="label_23">
<property name="text">
<string>Preferred &amp;output format:</string>
@ -217,9 +217,26 @@
</property>
</widget>
</item>
<item row="0" column="1">
<item row="1" column="1">
<widget class="QComboBox" name="output_format"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_230">
<property name="text">
<string>Tags to apply when adding a book:</string>
</property>
<property name="buddy">
<cstring>new_book_tags</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="new_book_tags">
<property name="toolTip">
<string>A comma-separated list of tags that will be applied to books added to the library</string>
</property>
</widget>
</item>
</layout>
</item>
<item>

View File

@ -236,8 +236,8 @@ class BooksModel(QAbstractTableModel): # {{{
def search(self, text, reset=True):
try:
self.db.search(text)
except ParseException:
self.searched.emit(False)
except ParseException as e:
self.searched.emit(e.msg)
return
self.last_search = text
if reset:

View File

@ -164,6 +164,20 @@
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="opt_new_book_tags">
<property name="toolTip">
<string>A comma-separated list of tags that will be applied to books added to the library</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_230">
<property name="text">
<string>Tags to apply when adding a book:</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="6" column="0" colspan="2">

View File

@ -90,6 +90,7 @@ class SearchBox2(QComboBox):
self.setSizeAdjustPolicy(self.AdjustToMinimumContentsLengthWithIcon)
self.setMinimumContentsLength(25)
self._in_a_search = False
self.tool_tip_text = self.toolTip()
def initialize(self, opt_name, colorize=False, help_text=_('Search')):
self.as_you_type = config['search_as_you_type']
@ -100,6 +101,7 @@ class SearchBox2(QComboBox):
self.clear_to_help()
def normalize_state(self):
self.setToolTip(self.tool_tip_text)
if self.help_state:
self.setEditText('')
self.line_edit.setStyleSheet(
@ -112,6 +114,7 @@ class SearchBox2(QComboBox):
self.normal_background)
def clear_to_help(self):
self.setToolTip(self.tool_tip_text)
if self.help_state:
return
self.help_state = True
@ -131,6 +134,9 @@ class SearchBox2(QComboBox):
self.clear_to_help()
def search_done(self, ok):
if isinstance(ok, basestring):
self.setToolTip(ok)
ok = False
if not unicode(self.currentText()).strip():
return self.clear_to_help()
self._in_a_search = ok

View File

@ -319,12 +319,18 @@ class ResultCache(SearchQueryParser):
matches.add(item[0])
return matches
def get_matches(self, location, query):
def get_matches(self, location, query, allow_recursion=True):
matches = set([])
if query and query.strip():
# get metadata key associated with the search term. Eliminates
# dealing with plurals and other aliases
location = self.field_metadata.search_term_to_key(location.lower().strip())
if isinstance(location, list):
if allow_recursion:
for loc in location:
matches |= self.get_matches(loc, query, allow_recursion=False)
return matches
raise ParseException(query, len(query), 'Recursive query group detected', self)
# take care of dates special case
if location in self.field_metadata and \

View File

@ -297,6 +297,13 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
if len(saved_searches().names()):
tb_cats.add_search_category(label='search', name=_('Searches'))
gst = tweaks['grouped_search_terms']
for t in gst:
try:
self.field_metadata._add_search_terms_to_map(gst[t], [t])
except ValueError:
traceback.print_exc()
self.book_on_device_func = None
self.data = ResultCache(self.FIELD_MAP, self.field_metadata)
self.search = self.data.search
@ -1718,7 +1725,18 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
path = path_or_stream
return run_plugins_on_import(path, format)
def _add_newbook_tag(self, mi):
tags = prefs['new_book_tags']
if tags:
for tag in [t.strip() for t in tags]:
if tag:
if mi.tags is None:
mi.tags = [tag]
else:
mi.tags.append(tag)
def create_book_entry(self, mi, cover=None, add_duplicates=True):
self._add_newbook_tag(mi)
if not add_duplicates and self.has_book(mi):
return None
series_index = 1.0 if mi.series_index is None else mi.series_index
@ -1757,6 +1775,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
ids = []
for path in paths:
mi = metadata.next()
self._add_newbook_tag(mi)
format = formats.next()
if not add_duplicates and self.has_book(mi):
duplicates.append((path, format, mi))
@ -1795,8 +1814,11 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
return (paths, formats, metadata), len(ids)
return None, len(ids)
def import_book(self, mi, formats, notify=True, import_hooks=True):
def import_book(self, mi, formats, notify=True, import_hooks=True,
apply_import_tags=True):
series_index = 1.0 if mi.series_index is None else mi.series_index
if apply_import_tags:
self._add_newbook_tag(mi)
if not mi.title:
mi.title = _('Unknown')
if not mi.authors:

View File

@ -475,9 +475,7 @@ class FieldMetadata(dict):
# ])
def get_search_terms(self):
s_keys = []
for v in self._tb_cats.itervalues():
map((lambda x:s_keys.append(x)), v['search_terms'])
s_keys = sorted(self._search_term_map.keys())
for v in self.search_items:
s_keys.append(v)
# if set(s_keys) != self.DEFAULT_LOCATIONS:
@ -488,6 +486,9 @@ class FieldMetadata(dict):
def _add_search_terms_to_map(self, key, terms):
if terms is not None:
for t in terms:
t = t.lower()
if t in self._search_term_map:
raise ValueError('Attempt to add duplicate search term "%s"'%t)
self._search_term_map[t] = key
def search_term_to_key(self, term):

View File

@ -717,6 +717,7 @@ def _prefs():
c.add_opt('add_formats_to_existing', default=False,
help=_('Add new formats to existing book records'))
c.add_opt('installation_uuid', default=None, help='Installation UUID')
c.add_opt('new_book_tags', default=[], help=_('Tags to apply to books added to the library'))
# these are here instead of the gui preferences because calibredb and
# calibre server can execute searches