diff --git a/resources/default_tweaks.py b/resources/default_tweaks.py index c22d24a6a7..47036a7b6d 100644 --- a/resources/default_tweaks.py +++ b/resources/default_tweaks.py @@ -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 diff --git a/src/calibre/gui2/library/views.py b/src/calibre/gui2/library/views.py index 61161cd5e6..c62936a46f 100644 --- a/src/calibre/gui2/library/views.py +++ b/src/calibre/gui2/library/views.py @@ -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): diff --git a/src/calibre/gui2/preferences/search.py b/src/calibre/gui2/preferences/search.py index 749a7c8de0..4f108d7cbc 100644 --- a/src/calibre/gui2/preferences/search.py +++ b/src/calibre/gui2/preferences/search.py @@ -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('
' + _(
+ "Grouped search terms are search names that permit a query to automatically "
+ "search across more than one column. For example, if you create a grouped "
+ "search term allseries
with the value "
+ "series, #myseries, #myseries2
, then "
+ "the query allseries:adhoc
will find 'adhoc' in any of the "
+ "columns 'series', '#myseries', and '#myseries2'.
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. " + "
Note: Search terms are forced to lower case; 'MySearch' " + "and 'mysearch' are the same term." + "
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.
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()
diff --git a/src/calibre/gui2/preferences/search.ui b/src/calibre/gui2/preferences/search.ui
index 7d40f723ea..3466b53a24 100644
--- a/src/calibre/gui2/preferences/search.ui
+++ b/src/calibre/gui2/preferences/search.ui
@@ -7,7 +7,7 @@