diff --git a/src/calibre/gui2/dialogs/saved_search_editor.py b/src/calibre/gui2/dialogs/saved_search_editor.py index 1143a6f06a..c9f843109a 100644 --- a/src/calibre/gui2/dialogs/saved_search_editor.py +++ b/src/calibre/gui2/dialogs/saved_search_editor.py @@ -9,12 +9,13 @@ from PyQt4.QtGui import QDialog from calibre.gui2.dialogs.saved_search_editor_ui import Ui_SavedSearchEditor from calibre.utils.search_query_parser import saved_searches from calibre.utils.icu import sort_key +from calibre.gui2 import error_dialog from calibre.gui2.dialogs.confirm_delete import confirm class SavedSearchEditor(QDialog, Ui_SavedSearchEditor): - def __init__(self, window, initial_search=None): - QDialog.__init__(self, window) + def __init__(self, parent, initial_search=None): + QDialog.__init__(self, parent) Ui_SavedSearchEditor.__init__(self) self.setupUi(self) @@ -22,12 +23,13 @@ class SavedSearchEditor(QDialog, Ui_SavedSearchEditor): self.connect(self.search_name_box, SIGNAL('currentIndexChanged(int)'), self.current_index_changed) self.connect(self.delete_search_button, SIGNAL('clicked()'), self.del_search) + self.rename_button.clicked.connect(self.rename_search) self.current_search_name = None self.searches = {} - self.searches_to_delete = [] for name in saved_searches().names(): self.searches[name] = saved_searches().lookup(name) + self.search_names = set([icu_lower(n) for n in saved_searches().names()]) self.populate_search_list() if initial_search is not None and initial_search in self.searches: @@ -42,6 +44,11 @@ class SavedSearchEditor(QDialog, Ui_SavedSearchEditor): search_name = unicode(self.input_box.text()).strip() if search_name == '': return False + if icu_lower(search_name) in self.search_names: + error_dialog(self, _('Saved search already exists'), + _('The saved search %s already exists, perhaps with ' + 'different case')%search_name).exec_() + return False if search_name not in self.searches: self.searches[search_name] = '' self.populate_search_list() @@ -57,10 +64,25 @@ class SavedSearchEditor(QDialog, Ui_SavedSearchEditor): +'

', 'saved_search_editor_delete', self): return del self.searches[self.current_search_name] - self.searches_to_delete.append(self.current_search_name) self.current_search_name = None self.search_name_box.removeItem(self.search_name_box.currentIndex()) + def rename_search(self): + new_search_name = unicode(self.input_box.text()).strip() + if new_search_name == '': + return False + if icu_lower(new_search_name) in self.search_names: + error_dialog(self, _('Saved search already exists'), + _('The saved search %s already exists, perhaps with ' + 'different case')%new_search_name).exec_() + return False + if self.current_search_name in self.searches: + self.searches[new_search_name] = self.searches[self.current_search_name] + del self.searches[self.current_search_name] + self.populate_search_list() + self.select_search(new_search_name) + return True + def select_search(self, name): self.search_name_box.setCurrentIndex(self.search_name_box.findText(name)) @@ -78,7 +100,7 @@ class SavedSearchEditor(QDialog, Ui_SavedSearchEditor): def accept(self): if self.current_search_name: self.searches[self.current_search_name] = unicode(self.search_text.toPlainText()) - for name in self.searches_to_delete: + for name in saved_searches().names(): saved_searches().delete(name) for name in self.searches: saved_searches().add(name, self.searches[name]) diff --git a/src/calibre/gui2/dialogs/saved_search_editor.ui b/src/calibre/gui2/dialogs/saved_search_editor.ui index 3ba37bdf10..99672b5b8e 100644 --- a/src/calibre/gui2/dialogs/saved_search_editor.ui +++ b/src/calibre/gui2/dialogs/saved_search_editor.ui @@ -134,6 +134,20 @@ + + + + Rename the current search to what is in the box + + + ... + + + + :/images/edit-undo.png:/images/edit-undo.png + + + diff --git a/src/calibre/gui2/preferences/look_feel.py b/src/calibre/gui2/preferences/look_feel.py index 15d5666978..206f2b97fb 100644 --- a/src/calibre/gui2/preferences/look_feel.py +++ b/src/calibre/gui2/preferences/look_feel.py @@ -67,6 +67,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): if db.field_metadata[k]['is_category'] and db.field_metadata[k]['datatype'] in ['text', 'series', 'enumeration']]) choices -= set(['authors', 'publisher', 'formats', 'news', 'identifiers']) + choices |= set(['search']) self.opt_categories_using_hierarchy.update_items_cache(choices) r('categories_using_hierarchy', db.prefs, setting=CommaSeparatedList, choices=sorted(list(choices), key=sort_key)) diff --git a/src/calibre/gui2/tag_view.py b/src/calibre/gui2/tag_view.py index c4871880a4..12a29a469c 100644 --- a/src/calibre/gui2/tag_view.py +++ b/src/calibre/gui2/tag_view.py @@ -533,7 +533,9 @@ class TagsView(QTreeView): # {{{ self.setModel(self._model) except: # The DB must be gone. Set the model to None and hope that someone - # will call set_database later. I don't know if this in fact works + # will call set_database later. I don't know if this in fact works. + # But perhaps a Bad Thing Happened, so print the exception + traceback.print_exc() self._model = None self.setModel(None) # }}} @@ -678,7 +680,8 @@ class TagTreeItem(object): # {{{ break elif self.tag.state == TAG_SEARCH_STATES['mark_plusplus'] or\ self.tag.state == TAG_SEARCH_STATES['mark_minusminus']: - if self.tag.is_hierarchical and len(self.children): + if self.tag.is_searchable and self.tag.is_hierarchical \ + and len(self.children): break else: break @@ -1258,19 +1261,22 @@ class TagsModel(QAbstractItemModel): # {{{ if t.type != TagTreeItem.CATEGORY]) if (comp,tag.category) in child_map: node_parent = child_map[(comp,tag.category)] - node_parent.tag.is_hierarchical = True + node_parent.tag.is_hierarchical = key != 'search' else: if i < len(components)-1: t = copy.copy(tag) t.original_name = '.'.join(components[:i+1]) - # This 'manufactured' intermediate node can - # be searched, but cannot be edited. - t.is_editable = False + if key != 'search': + # This 'manufactured' intermediate node can + # be searched, but cannot be edited. + t.is_editable = False + else: + t.is_searchable = t.is_editable = False else: t = tag if not in_uc: t.original_name = t.name - t.is_hierarchical = True + t.is_hierarchical = key != 'search' t.name = comp self.beginInsertRows(category_index, 999999, 1) node_parent = TagTreeItem(parent=node_parent, data=t, diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index ea30c08aff..e70a746b15 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -56,7 +56,7 @@ class Tag(object): self.is_hierarchical = False self.is_editable = is_editable self.is_searchable = is_searchable - self.id_set = id_set + self.id_set = id_set if id_set is not None else set([]) self.avg_rating = avg/2.0 if avg is not None else 0 self.sort = sort if self.avg_rating > 0: