mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
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:
commit
cb4cc4219a
@ -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 = {}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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())
|
||||
|
@ -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 &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 &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 &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 &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>
|
||||
|
@ -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:
|
||||
|
@ -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">
|
||||
|
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -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:
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user