diff --git a/src/calibre/gui2/actions/edit_metadata.py b/src/calibre/gui2/actions/edit_metadata.py index 945c272718..86c6778191 100644 --- a/src/calibre/gui2/actions/edit_metadata.py +++ b/src/calibre/gui2/actions/edit_metadata.py @@ -446,9 +446,8 @@ class EditMetadataAction(InterfaceAction): if d.result() == d.Accepted: to_rename = d.to_rename # dict of new text to old ids to_delete = d.to_delete # list of ids - for text in to_rename: - for old_id in to_rename[text]: - model.rename_collection(old_id, new_name=unicode(text)) + for old_id, new_name in to_rename.iteritems(): + model.rename_collection(old_id, new_name=unicode(new_name)) for item in to_delete: model.delete_collection_using_id(item) self.gui.upload_collections(model.db, view=view, oncard=oncard) diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index 8cbc2e1979..0937f0bb12 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -950,11 +950,11 @@ class OnDeviceSearch(SearchQueryParser): # {{{ for locvalue in locations: accessor = q[locvalue] if query == 'true': - if accessor(row) is not None: + if accessor(row): matches.add(index) continue if query == 'false': - if accessor(row) is None: + if not accessor(row): matches.add(index) continue if locvalue == 'inlibrary': diff --git a/src/calibre/gui2/tag_browser/model.py b/src/calibre/gui2/tag_browser/model.py index e759783d7b..7ed6b473ab 100644 --- a/src/calibre/gui2/tag_browser/model.py +++ b/src/calibre/gui2/tag_browser/model.py @@ -12,7 +12,7 @@ import traceback, cPickle, copy from itertools import repeat from PyQt4.Qt import (QAbstractItemModel, QIcon, QVariant, QFont, Qt, - QMimeData, QModelIndex, pyqtSignal) + QMimeData, QModelIndex, pyqtSignal, QObject) from calibre.gui2 import NONE, gprefs, config, error_dialog from calibre.library.database2 import Tag @@ -227,6 +227,10 @@ class TagsModel(QAbstractItemModel): # {{{ self._build_in_progress = False self.reread_collapse_model({}, rebuild=False) + @property + def gui_parent(self): + return QObject.parent(self) + def reread_collapse_model(self, state_map, rebuild=True): if gprefs['tags_browser_collapse_at'] == 0: self.collapse_model = 'disable' @@ -315,9 +319,11 @@ class TagsModel(QAbstractItemModel): # {{{ for i,p in enumerate(path_parts): path += p if path not in category_node_map: + icon = self.category_icon_map['gst'] if is_gst else \ + self.category_icon_map[key] node = self.create_node(parent=last_category_node, data=p[1:] if i == 0 else p, - category_icon=self.category_icon_map[key], + category_icon=icon, tooltip=tt if path == key else path, category_key=path, icon_map=self.icon_state_map) @@ -375,6 +381,7 @@ class TagsModel(QAbstractItemModel): # {{{ collapse_letter = None category_node = category key = category_node.category_key + is_gst = category_node.is_gst if key not in data: return cat_len = len(data[key]) @@ -455,6 +462,7 @@ class TagsModel(QAbstractItemModel): # {{{ tooltip = None, temporary=True, category_key=category_node.category_key, icon_map=self.icon_state_map) + sub_cat.is_gst = is_gst node_parent = sub_cat else: node_parent = category @@ -722,12 +730,12 @@ class TagsModel(QAbstractItemModel): # {{{ if (key == 'authors' and len(ids) >= 5): if not confirm('

'+_('Changing the authors for several books can ' 'take a while. Are you sure?') - +'

', 'tag_browser_drop_authors', self.parent()): + +'

', 'tag_browser_drop_authors', self.gui_parent): return elif len(ids) > 15: if not confirm('

'+_('Changing the metadata for that many books ' 'can take a while. Are you sure?') - +'

', 'tag_browser_many_changes', self.parent()): + +'

', 'tag_browser_many_changes', self.gui_parent): return fm = self.db.metadata_for_field(key) @@ -871,13 +879,13 @@ class TagsModel(QAbstractItemModel): # {{{ # we position at the parent label val = unicode(value.toString()).strip() if not val: - error_dialog(self.parent(), _('Item is blank'), + error_dialog(self.gui_parent, _('Item is blank'), _('An item cannot be set to nothing. Delete it instead.')).exec_() return False item = self.get_node(index) if item.type == TagTreeItem.CATEGORY and item.category_key.startswith('@'): if val.find('.') >= 0: - error_dialog(self.parent(), _('Rename user category'), + error_dialog(self.gui_parent, _('Rename user category'), _('You cannot use periods in the name when ' 'renaming user categories'), show=True) return False @@ -897,7 +905,7 @@ class TagsModel(QAbstractItemModel): # {{{ if len(c) == len(ckey): if strcmp(ckey, nkey) != 0 and \ nkey_lower in user_cat_keys_lower: - error_dialog(self.parent(), _('Rename user category'), + error_dialog(self.gui_parent, _('Rename user category'), _('The name %s is already used')%nkey, show=True) return False user_cats[nkey] = user_cats[ckey] @@ -906,7 +914,7 @@ class TagsModel(QAbstractItemModel): # {{{ rest = c[len(ckey):] if strcmp(ckey, nkey) != 0 and \ icu_lower(nkey + rest) in user_cat_keys_lower: - error_dialog(self.parent(), _('Rename user category'), + error_dialog(self.gui_parent, _('Rename user category'), _('The name %s is already used')%(nkey+rest), show=True) return False user_cats[nkey + rest] = user_cats[ckey + rest] @@ -921,12 +929,12 @@ class TagsModel(QAbstractItemModel): # {{{ return False if key == 'authors': if val.find('&') >= 0: - error_dialog(self.parent(), _('Invalid author name'), + error_dialog(self.gui_parent, _('Invalid author name'), _('Author names cannot contain & characters.')).exec_() return False if key == 'search': if val in saved_searches().names(): - error_dialog(self.parent(), _('Duplicate search name'), + error_dialog(self.gui_parent, _('Duplicate search name'), _('The saved search name %s is already used.')%val).exec_() return False saved_searches().rename(unicode(item.data(role).toString()), val) @@ -1161,7 +1169,10 @@ class TagsModel(QAbstractItemModel): # {{{ prefix = ' not ' else: prefix = '' - category = tag.category if key != 'news' else 'tag' + if node.is_gst: + category = key + else: + category = tag.category if key != 'news' else 'tag' add_colon = False if self.db.field_metadata[tag.category]['is_csp']: add_colon = True diff --git a/src/calibre/gui2/tag_browser/ui.py b/src/calibre/gui2/tag_browser/ui.py index d7e504b3e9..390273e5b2 100644 --- a/src/calibre/gui2/tag_browser/ui.py +++ b/src/calibre/gui2/tag_browser/ui.py @@ -218,7 +218,7 @@ class TagBrowserMixin(object): # {{{ d = TagListEditor(self, tag_to_match=tag, data=result, key=key) d.exec_() if d.result() == d.Accepted: - to_rename = d.to_rename # dict of new text to old id + to_rename = d.to_rename # dict of old id to new name to_delete = d.to_delete # list of ids orig_name = d.original_names # dict of id: name diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index 9d8a27d1fb..9fe9d3dabb 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -7,7 +7,7 @@ __docformat__ = 'restructuredtext en' The database used to store ebook metadata ''' import os, sys, shutil, cStringIO, glob, time, functools, traceback, re, \ - json, uuid, tempfile, hashlib + json, uuid, tempfile, hashlib, copy from collections import defaultdict import threading, random from itertools import repeat @@ -1794,10 +1794,22 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): for user_cat in sorted(user_categories.keys(), key=sort_key): items = [] + names_seen = {} for (name,label,ign) in user_categories[user_cat]: n = icu_lower(name) if label in taglist and n in taglist[label]: - items.append(taglist[label][n]) + if user_cat in gst: + # for gst items, make copy and consolidate the tags by name. + if n in names_seen: + names_seen[n].id_set |= taglist[label][n].id_set + names_seen[n].count += taglist[label][n].count + else: + t = copy.copy(taglist[label][n]) + t.icon = icon_map['gst'] + names_seen[t.name] = t + items.append(t) + else: + items.append(taglist[label][n]) # else: do nothing, to not include nodes w zero counts cat_name = '@' + user_cat # add the '@' to avoid name collision # Not a problem if we accumulate entries in the icon map diff --git a/src/calibre/library/field_metadata.py b/src/calibre/library/field_metadata.py index 231af23038..51511e26d9 100644 --- a/src/calibre/library/field_metadata.py +++ b/src/calibre/library/field_metadata.py @@ -17,7 +17,7 @@ class TagsIcons(dict): category_icons = ['authors', 'series', 'formats', 'publisher', 'rating', 'news', 'tags', 'custom:', 'user:', 'search', - 'identifiers'] + 'identifiers', 'gst'] def __init__(self, icon_dict): for a in self.category_icons: if a not in icon_dict: @@ -35,7 +35,8 @@ category_icon_map = { 'custom:' : 'column.png', 'user:' : 'tb_folder.png', 'search' : 'search.png', - 'identifiers': 'identifiers.png' + 'identifiers': 'identifiers.png', + 'gst' : 'catalog.png', }