mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 10:44:09 -04:00
Dragging from book list: Only start drag if user clicks on an already selected item. Move the grouped search terms option from tweaks to the search preferences dialog
This commit is contained in:
commit
0917f81537
@ -245,19 +245,6 @@ sony_collection_name_template='{value}{category:| (|)}'
|
||||
sony_collection_sorting_rules = []
|
||||
|
||||
|
||||
#: 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 = {}
|
||||
|
||||
|
||||
#: Control how tags are applied when copying books to another library
|
||||
# Set this to True to ensure that tags in 'Tags to add when adding
|
||||
# a book' are added when copying books to another library
|
||||
|
@ -551,8 +551,10 @@ class BooksView(QTableView): # {{{
|
||||
return mods & Qt.ControlModifier or mods & Qt.ShiftModifier
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
if event.button() == Qt.LeftButton and not self.event_has_mods():
|
||||
self.drag_start_pos = event.pos()
|
||||
ep = event.pos()
|
||||
if self.indexAt(ep) in self.selectionModel().selectedIndexes() and \
|
||||
event.button() == Qt.LeftButton and not self.event_has_mods():
|
||||
self.drag_start_pos = ep
|
||||
return QTableView.mousePressEvent(self, event)
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
|
@ -10,13 +10,15 @@ from PyQt4.Qt import QApplication
|
||||
from calibre.gui2.preferences import ConfigWidgetBase, test_widget, \
|
||||
CommaSeparatedList
|
||||
from calibre.gui2.preferences.search_ui import Ui_Form
|
||||
from calibre.gui2 import config
|
||||
from calibre.gui2 import config, error_dialog
|
||||
from calibre.utils.config import prefs
|
||||
|
||||
class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
|
||||
def genesis(self, gui):
|
||||
self.gui = gui
|
||||
db = gui.library_view.model().db
|
||||
self.db = db
|
||||
|
||||
r = self.register
|
||||
|
||||
@ -24,11 +26,149 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
r('highlight_search_matches', config)
|
||||
r('limit_search_columns', prefs)
|
||||
r('limit_search_columns_to', prefs, setting=CommaSeparatedList)
|
||||
fl = gui.library_view.model().db.field_metadata.get_search_terms()
|
||||
fl = db.field_metadata.get_search_terms()
|
||||
self.opt_limit_search_columns_to.update_items_cache(fl)
|
||||
self.clear_history_button.clicked.connect(self.clear_histories)
|
||||
|
||||
self.gst_explanation.setText('<p>' + _(
|
||||
"<b>Grouped search terms</b> are search names that permit a query to automatically "
|
||||
"search across more than one column. For example, if you create a grouped "
|
||||
"search term <code>allseries</code> with the value "
|
||||
"<code>series, #myseries, #myseries2</code>, then "
|
||||
"the query <code>allseries:adhoc</code> will find 'adhoc' in any of the "
|
||||
"columns 'series', '#myseries', and '#myseries2'.<p> Enter the name of the "
|
||||
"grouped search term in the drop-down box, enter the list of columns "
|
||||
"to search in the value box, then push the Save button. "
|
||||
"<p>Note: Search terms are forced to lower case; 'MySearch' "
|
||||
"and 'mysearch' are the same term."
|
||||
"<p>You can have your grouped search term show up as a user category in "
|
||||
" the Tag Browser. Just add the grouped search term name to the user "
|
||||
"category box. You can add multiple terms separated by commas. "
|
||||
"The user category will be "
|
||||
"populated with all the items in the categories included in the grouped "
|
||||
"search term. <p>This permits you to see easily all the category items that "
|
||||
"are in the fields contained in the grouped search term. Using the above "
|
||||
"'myseries' example, the automatically-generated user category would contain "
|
||||
"all the series mentioned in 'series', '#myseries1', and '#myseries2'. This "
|
||||
"can be useful to check for duplicates or to find which column contains "
|
||||
"a particular item."))
|
||||
self.gst = db.prefs.get('grouped_search_terms', {})
|
||||
self.orig_gst_keys = self.gst.keys()
|
||||
|
||||
fl = []
|
||||
for f in db.all_field_keys():
|
||||
fm = db.metadata_for_field(f)
|
||||
if not fm['search_terms']:
|
||||
continue
|
||||
if not fm['is_category']:
|
||||
continue
|
||||
fl.append(f)
|
||||
self.gst_value.update_items_cache(fl)
|
||||
self.fill_gst_box(select=None)
|
||||
|
||||
self.gst_delete_button.setEnabled(False)
|
||||
self.gst_save_button.setEnabled(False)
|
||||
self.gst_names.currentIndexChanged[int].connect(self.gst_index_changed)
|
||||
self.gst_names.editTextChanged.connect(self.gst_text_changed)
|
||||
self.gst_value.textChanged.connect(self.gst_text_changed)
|
||||
self.gst_save_button.clicked.connect(self.gst_save_clicked)
|
||||
self.gst_delete_button.clicked.connect(self.gst_delete_clicked)
|
||||
self.gst_changed = False
|
||||
|
||||
if db.prefs.get('grouped_search_make_user_categories', None) is None:
|
||||
db.prefs.set('grouped_search_make_user_categories', [])
|
||||
r('grouped_search_make_user_categories', db.prefs, setting=CommaSeparatedList)
|
||||
self.muc_changed = False
|
||||
self.opt_grouped_search_make_user_categories.editingFinished.connect(
|
||||
self.muc_box_changed)
|
||||
|
||||
def muc_box_changed(self):
|
||||
self.muc_changed = True
|
||||
|
||||
def gst_save_clicked(self):
|
||||
idx = self.gst_names.currentIndex()
|
||||
name = icu_lower(unicode(self.gst_names.currentText()))
|
||||
if not name:
|
||||
return error_dialog(self.gui, _('Grouped Search Terms'),
|
||||
_('The search term cannot be blank'),
|
||||
show=True)
|
||||
if idx != 0:
|
||||
orig_name = unicode(self.gst_names.itemData(idx).toString())
|
||||
else:
|
||||
orig_name = ''
|
||||
if name != orig_name:
|
||||
if name in self.db.field_metadata.get_search_terms() and \
|
||||
name not in self.orig_gst_keys:
|
||||
return error_dialog(self.gui, _('Grouped Search Terms'),
|
||||
_('That name is already used for a column or grouped search term'),
|
||||
show=True)
|
||||
if name in [icu_lower(p) for p in self.db.prefs.get('user_categories', {})]:
|
||||
return error_dialog(self.gui, _('Grouped Search Terms'),
|
||||
_('That name is already used for user category'),
|
||||
show=True)
|
||||
|
||||
val = [v.strip() for v in unicode(self.gst_value.text()).split(',') if v.strip()]
|
||||
if not val:
|
||||
return error_dialog(self.gui, _('Grouped Search Terms'),
|
||||
_('The value box cannot be empty'), show=True)
|
||||
|
||||
if orig_name and name != orig_name:
|
||||
del self.gst[orig_name]
|
||||
self.gst_changed = True
|
||||
self.gst[name] = val
|
||||
self.fill_gst_box(select=name)
|
||||
self.changed_signal.emit()
|
||||
|
||||
def gst_delete_clicked(self):
|
||||
if self.gst_names.currentIndex() == 0:
|
||||
return error_dialog(self.gui, _('Grouped Search Terms'),
|
||||
_('The empty grouped search term cannot be deleted'), show=True)
|
||||
name = unicode(self.gst_names.currentText())
|
||||
if name in self.gst:
|
||||
del self.gst[name]
|
||||
self.fill_gst_box(select='')
|
||||
self.changed_signal.emit()
|
||||
self.gst_changed = True
|
||||
|
||||
def fill_gst_box(self, select=None):
|
||||
terms = sorted(self.gst.keys())
|
||||
self.opt_grouped_search_make_user_categories.update_items_cache(terms)
|
||||
self.gst_names.blockSignals(True)
|
||||
self.gst_names.clear()
|
||||
self.gst_names.addItem('', '')
|
||||
for t in terms:
|
||||
self.gst_names.addItem(t, t)
|
||||
self.gst_names.blockSignals(False)
|
||||
if select is not None:
|
||||
if select == '':
|
||||
self.gst_index_changed(0)
|
||||
elif select in terms:
|
||||
self.gst_names.setCurrentIndex(self.gst_names.findText(select))
|
||||
|
||||
def gst_text_changed(self):
|
||||
self.gst_delete_button.setEnabled(False)
|
||||
self.gst_save_button.setEnabled(True)
|
||||
|
||||
def gst_index_changed(self, idx):
|
||||
self.gst_delete_button.setEnabled(idx != 0)
|
||||
self.gst_save_button.setEnabled(False)
|
||||
self.gst_value.blockSignals(True)
|
||||
if idx == 0:
|
||||
self.gst_value.setText('')
|
||||
else:
|
||||
name = unicode(self.gst_names.itemData(idx).toString())
|
||||
self.gst_value.setText(','.join(self.gst[name]))
|
||||
self.gst_value.blockSignals(False)
|
||||
|
||||
def commit(self):
|
||||
if self.gst_changed:
|
||||
self.db.prefs.set('grouped_search_terms', self.gst)
|
||||
self.db.field_metadata.add_grouped_search_terms(self.gst)
|
||||
return ConfigWidgetBase.commit(self)
|
||||
|
||||
def refresh_gui(self, gui):
|
||||
if self.muc_changed:
|
||||
gui.tags_view.set_new_model()
|
||||
gui.search.search_as_you_type(config['search_as_you_type'])
|
||||
gui.library_view.model().set_highlight_only(config['highlight_search_matches'])
|
||||
gui.search.do_search()
|
||||
|
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>670</width>
|
||||
<height>392</height>
|
||||
<height>556</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -77,19 +77,6 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QPushButton" name="clear_history_button">
|
||||
<property name="toolTip">
|
||||
@ -100,6 +87,108 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Grouped Search Terms</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0">
|
||||
<layout class="QHBoxLayout" name="l12">
|
||||
<item>
|
||||
<widget class="QLabel" name="la10">
|
||||
<property name="text">
|
||||
<string>&Grouped search terms:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>gst_names</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="gst_names">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimumContentsLength">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="gst_delete_button">
|
||||
<property name="toolTip">
|
||||
<string>Delete the current search term</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../resources/images.qrc">
|
||||
<normaloff>:/images/trash.png</normaloff>:/images/trash.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="MultiCompleteLineEdit" name="gst_value"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="gst_save_button">
|
||||
<property name="toolTip">
|
||||
<string>Save the current search term. You can rename a search term by
|
||||
changing the name then pressing Save. You can change the value
|
||||
of a search term by changing the value box then pressing Save.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Save</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="1" rowspan="3">
|
||||
<widget class="QTextBrowser" name="gst_explanation">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>100</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<layout class="QHBoxLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="l11">
|
||||
<property name="text">
|
||||
<string>Make &user categories:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>opt_grouped_search_make_user_categories</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="MultiCompleteLineEdit" name="opt_grouped_search_make_user_categories"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
@ -109,6 +198,8 @@
|
||||
<header>calibre/gui2/complete.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<resources>
|
||||
<include location="../../../../resources/images.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
@ -466,10 +466,7 @@ class TagTreeItem(object): # {{{
|
||||
icon_map[0] = data.icon
|
||||
self.tag, self.icon_state_map = data, list(map(QVariant, icon_map))
|
||||
if tooltip:
|
||||
if tooltip.endswith(':'):
|
||||
self.tooltip = tooltip + ' '
|
||||
else:
|
||||
self.tooltip = tooltip + ': '
|
||||
self.tooltip = tooltip + ' '
|
||||
else:
|
||||
self.tooltip = ''
|
||||
|
||||
@ -589,11 +586,17 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
|
||||
# get_node_tree cannot return None here, because row_map is empty
|
||||
data = self.get_node_tree(config['sort_tags_by'])
|
||||
gst = db.prefs.get('grouped_search_terms', {})
|
||||
self.root_item = TagTreeItem()
|
||||
for i, r in enumerate(self.row_map):
|
||||
if self.hidden_categories and self.categories[i] in self.hidden_categories:
|
||||
continue
|
||||
tt = _(u'The lookup/search name is "{0}"').format(r)
|
||||
if r.startswith('@') and r[1:] in gst:
|
||||
tt = _(u'The grouped search term name is "{0}"').format(r[1:])
|
||||
elif r == 'news':
|
||||
tt = ''
|
||||
else:
|
||||
tt = _(u'The lookup/search name is "{0}"').format(r)
|
||||
TagTreeItem(parent=self.root_item,
|
||||
data=self.categories[i],
|
||||
category_icon=self.category_icon_map[r],
|
||||
@ -735,6 +738,14 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
self.row_map = []
|
||||
self.categories = []
|
||||
|
||||
# Get the categories
|
||||
if self.search_restriction:
|
||||
data = self.db.get_categories(sort=sort,
|
||||
icon_map=self.category_icon_map,
|
||||
ids=self.db.search('', return_matches=True))
|
||||
else:
|
||||
data = self.db.get_categories(sort=sort, icon_map=self.category_icon_map)
|
||||
|
||||
# Reconstruct the user categories, putting them into metadata
|
||||
self.db.field_metadata.remove_dynamic_categories()
|
||||
tb_cats = self.db.field_metadata
|
||||
@ -746,17 +757,16 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
except ValueError:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
for cat in sorted(self.db.prefs.get('grouped_search_terms', {}),
|
||||
key=sort_key):
|
||||
if (u'@' + cat) in data:
|
||||
tb_cats.add_user_category(label=u'@' + cat, name=cat)
|
||||
self.db.data.change_search_locations(self.db.field_metadata.get_search_terms())
|
||||
|
||||
if len(saved_searches().names()):
|
||||
tb_cats.add_search_category(label='search', name=_('Searches'))
|
||||
|
||||
# Now get the categories
|
||||
if self.search_restriction:
|
||||
data = self.db.get_categories(sort=sort,
|
||||
icon_map=self.category_icon_map,
|
||||
ids=self.db.search('', return_matches=True))
|
||||
else:
|
||||
data = self.db.get_categories(sort=sort, icon_map=self.category_icon_map)
|
||||
|
||||
if self.filter_categories_by:
|
||||
for category in data.keys():
|
||||
data[category] = [t for t in data[category]
|
||||
@ -767,6 +777,7 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
if category in data: # The search category can come and go
|
||||
self.row_map.append(category)
|
||||
self.categories.append(tb_categories[category]['name'])
|
||||
|
||||
if len(old_row_map) != 0 and len(old_row_map) != len(self.row_map):
|
||||
# A category has been added or removed. We must force a rebuild of
|
||||
# the model
|
||||
@ -822,6 +833,7 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
not self.db.field_metadata[r]['is_custom'] and \
|
||||
not self.db.field_metadata[r]['kind'] == 'user' \
|
||||
else False
|
||||
tt = r if self.db.field_metadata[r]['kind'] == 'user' else None
|
||||
for idx,tag in enumerate(data[r]):
|
||||
if clear_rating:
|
||||
tag.avg_rating = None
|
||||
@ -861,10 +873,10 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
category_icon = category_node.icon,
|
||||
tooltip = None,
|
||||
category_key=category_node.category_key)
|
||||
t = TagTreeItem(parent=sub_cat, data=tag, tooltip=r,
|
||||
t = TagTreeItem(parent=sub_cat, data=tag, tooltip=tt,
|
||||
icon_map=self.icon_state_map)
|
||||
else:
|
||||
t = TagTreeItem(parent=category, data=tag, tooltip=r,
|
||||
t = TagTreeItem(parent=category, data=tag, tooltip=tt,
|
||||
icon_map=self.icon_state_map)
|
||||
self.endInsertRows()
|
||||
return True
|
||||
|
@ -433,6 +433,10 @@ class ResultCache(SearchQueryParser): # {{{
|
||||
if len(candidates) == 0:
|
||||
return matches
|
||||
|
||||
if len(location) > 2 and location.startswith('@') and \
|
||||
location[1:] in self.db_prefs['grouped_search_terms']:
|
||||
location = location[1:]
|
||||
|
||||
if query and query.strip():
|
||||
# get metadata key associated with the search term. Eliminates
|
||||
# dealing with plurals and other aliases
|
||||
@ -440,9 +444,16 @@ class ResultCache(SearchQueryParser): # {{{
|
||||
# grouped search terms
|
||||
if isinstance(location, list):
|
||||
if allow_recursion:
|
||||
if query.lower() == 'false':
|
||||
invert = True
|
||||
query = 'true'
|
||||
else:
|
||||
invert = False
|
||||
for loc in location:
|
||||
matches |= self.get_matches(loc, query,
|
||||
candidates=candidates, allow_recursion=False)
|
||||
if invert:
|
||||
matches = self.universal_set() - matches
|
||||
return matches
|
||||
raise ParseException(query, len(query), 'Recursive query group detected', self)
|
||||
|
||||
|
@ -188,6 +188,17 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
migrate_preference('saved_searches', {})
|
||||
set_saved_searches(self, 'saved_searches')
|
||||
|
||||
# migrate grouped_search_terms
|
||||
if self.prefs.get('grouped_search_terms', None) is None:
|
||||
try:
|
||||
ogst = tweaks.get('grouped_search_terms', {})
|
||||
ngst = {}
|
||||
for t in ogst:
|
||||
ngst[icu_lower(t)] = ogst[t]
|
||||
self.prefs.set('grouped_search_terms', ngst)
|
||||
except:
|
||||
pass
|
||||
|
||||
# Rename any user categories with names that differ only in case
|
||||
user_cats = self.prefs.get('user_categories', [])
|
||||
catmap = {}
|
||||
@ -349,12 +360,8 @@ 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.field_metadata.add_grouped_search_terms(
|
||||
self.prefs.get('grouped_search_terms', {}))
|
||||
|
||||
self.book_on_device_func = None
|
||||
self.data = ResultCache(self.FIELD_MAP, self.field_metadata, db_prefs=self.prefs)
|
||||
@ -1293,7 +1300,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
# icon_map is not None if get_categories is to store an icon and
|
||||
# possibly a tooltip in the tag structure.
|
||||
icon = None
|
||||
tooltip = ''
|
||||
tooltip = '(' + category + ')'
|
||||
label = tb_cats.key_to_label(category)
|
||||
if icon_map:
|
||||
if not tb_cats.is_custom_field(category):
|
||||
@ -1379,7 +1386,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
categories['formats'].sort(key = lambda x:x.name)
|
||||
|
||||
#### Now do the user-defined categories. ####
|
||||
user_categories = self.prefs['user_categories']
|
||||
user_categories = dict.copy(self.prefs['user_categories'])
|
||||
|
||||
# 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
|
||||
@ -1390,6 +1397,17 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
for c in categories.keys():
|
||||
taglist[c] = dict(map(lambda t:(t.name, t), categories[c]))
|
||||
|
||||
muc = self.prefs.get('grouped_search_make_user_categories', [])
|
||||
gst = self.prefs.get('grouped_search_terms', {})
|
||||
for c in gst:
|
||||
if c not in muc:
|
||||
continue
|
||||
user_categories[c] = []
|
||||
for sc in gst[c]:
|
||||
if sc in categories.keys():
|
||||
for t in categories[sc]:
|
||||
user_categories[c].append([t.name, sc, 0])
|
||||
|
||||
for user_cat in sorted(user_categories.keys(), key=sort_key):
|
||||
items = []
|
||||
for (name,label,ign) in user_categories[user_cat]:
|
||||
|
@ -3,7 +3,7 @@ Created on 25 May 2010
|
||||
|
||||
@author: charles
|
||||
'''
|
||||
import copy
|
||||
import copy, traceback
|
||||
|
||||
from calibre.utils.ordered_dict import OrderedDict
|
||||
from calibre.utils.config import tweaks
|
||||
@ -488,6 +488,20 @@ class FieldMetadata(dict):
|
||||
del self._search_term_map[k]
|
||||
del self._tb_cats[key]
|
||||
|
||||
def _remove_grouped_search_terms(self):
|
||||
to_remove = [v for v in self._search_term_map
|
||||
if isinstance(self._search_term_map[v], list)]
|
||||
for v in to_remove:
|
||||
del self._search_term_map[v]
|
||||
|
||||
def add_grouped_search_terms(self, gst):
|
||||
self._remove_grouped_search_terms()
|
||||
for t in gst:
|
||||
try:
|
||||
self._add_search_terms_to_map(gst[t], [t])
|
||||
except ValueError:
|
||||
traceback.print_exc()
|
||||
|
||||
def cc_series_index_column_for(self, key):
|
||||
return self._tb_cats[key]['rec_index'] + 1
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user