Fix true/false searches dont work on device views (807262). Fix renaming of collections in device views (807256). Improved disaply of grouped search terms in Tag Browser

This commit is contained in:
Kovid Goyal 2011-07-08 10:26:44 -06:00
commit d7175e67bd
6 changed files with 44 additions and 21 deletions

View File

@ -446,9 +446,8 @@ class EditMetadataAction(InterfaceAction):
if d.result() == d.Accepted: if d.result() == d.Accepted:
to_rename = d.to_rename # dict of new text to old ids to_rename = d.to_rename # dict of new text to old ids
to_delete = d.to_delete # list of ids to_delete = d.to_delete # list of ids
for text in to_rename: for old_id, new_name in to_rename.iteritems():
for old_id in to_rename[text]: model.rename_collection(old_id, new_name=unicode(new_name))
model.rename_collection(old_id, new_name=unicode(text))
for item in to_delete: for item in to_delete:
model.delete_collection_using_id(item) model.delete_collection_using_id(item)
self.gui.upload_collections(model.db, view=view, oncard=oncard) self.gui.upload_collections(model.db, view=view, oncard=oncard)

View File

@ -950,11 +950,11 @@ class OnDeviceSearch(SearchQueryParser): # {{{
for locvalue in locations: for locvalue in locations:
accessor = q[locvalue] accessor = q[locvalue]
if query == 'true': if query == 'true':
if accessor(row) is not None: if accessor(row):
matches.add(index) matches.add(index)
continue continue
if query == 'false': if query == 'false':
if accessor(row) is None: if not accessor(row):
matches.add(index) matches.add(index)
continue continue
if locvalue == 'inlibrary': if locvalue == 'inlibrary':

View File

@ -12,7 +12,7 @@ import traceback, cPickle, copy
from itertools import repeat from itertools import repeat
from PyQt4.Qt import (QAbstractItemModel, QIcon, QVariant, QFont, Qt, 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.gui2 import NONE, gprefs, config, error_dialog
from calibre.library.database2 import Tag from calibre.library.database2 import Tag
@ -227,6 +227,10 @@ class TagsModel(QAbstractItemModel): # {{{
self._build_in_progress = False self._build_in_progress = False
self.reread_collapse_model({}, rebuild=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): def reread_collapse_model(self, state_map, rebuild=True):
if gprefs['tags_browser_collapse_at'] == 0: if gprefs['tags_browser_collapse_at'] == 0:
self.collapse_model = 'disable' self.collapse_model = 'disable'
@ -315,9 +319,11 @@ class TagsModel(QAbstractItemModel): # {{{
for i,p in enumerate(path_parts): for i,p in enumerate(path_parts):
path += p path += p
if path not in category_node_map: 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, node = self.create_node(parent=last_category_node,
data=p[1:] if i == 0 else p, 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, tooltip=tt if path == key else path,
category_key=path, category_key=path,
icon_map=self.icon_state_map) icon_map=self.icon_state_map)
@ -375,6 +381,7 @@ class TagsModel(QAbstractItemModel): # {{{
collapse_letter = None collapse_letter = None
category_node = category category_node = category
key = category_node.category_key key = category_node.category_key
is_gst = category_node.is_gst
if key not in data: if key not in data:
return return
cat_len = len(data[key]) cat_len = len(data[key])
@ -455,6 +462,7 @@ class TagsModel(QAbstractItemModel): # {{{
tooltip = None, temporary=True, tooltip = None, temporary=True,
category_key=category_node.category_key, category_key=category_node.category_key,
icon_map=self.icon_state_map) icon_map=self.icon_state_map)
sub_cat.is_gst = is_gst
node_parent = sub_cat node_parent = sub_cat
else: else:
node_parent = category node_parent = category
@ -722,12 +730,12 @@ class TagsModel(QAbstractItemModel): # {{{
if (key == 'authors' and len(ids) >= 5): if (key == 'authors' and len(ids) >= 5):
if not confirm('<p>'+_('Changing the authors for several books can ' if not confirm('<p>'+_('Changing the authors for several books can '
'take a while. Are you sure?') 'take a while. Are you sure?')
+'</p>', 'tag_browser_drop_authors', self.parent()): +'</p>', 'tag_browser_drop_authors', self.gui_parent):
return return
elif len(ids) > 15: elif len(ids) > 15:
if not confirm('<p>'+_('Changing the metadata for that many books ' if not confirm('<p>'+_('Changing the metadata for that many books '
'can take a while. Are you sure?') 'can take a while. Are you sure?')
+'</p>', 'tag_browser_many_changes', self.parent()): +'</p>', 'tag_browser_many_changes', self.gui_parent):
return return
fm = self.db.metadata_for_field(key) fm = self.db.metadata_for_field(key)
@ -871,13 +879,13 @@ class TagsModel(QAbstractItemModel): # {{{
# we position at the parent label # we position at the parent label
val = unicode(value.toString()).strip() val = unicode(value.toString()).strip()
if not val: 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_() _('An item cannot be set to nothing. Delete it instead.')).exec_()
return False return False
item = self.get_node(index) item = self.get_node(index)
if item.type == TagTreeItem.CATEGORY and item.category_key.startswith('@'): if item.type == TagTreeItem.CATEGORY and item.category_key.startswith('@'):
if val.find('.') >= 0: 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 ' _('You cannot use periods in the name when '
'renaming user categories'), show=True) 'renaming user categories'), show=True)
return False return False
@ -897,7 +905,7 @@ class TagsModel(QAbstractItemModel): # {{{
if len(c) == len(ckey): if len(c) == len(ckey):
if strcmp(ckey, nkey) != 0 and \ if strcmp(ckey, nkey) != 0 and \
nkey_lower in user_cat_keys_lower: 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) _('The name %s is already used')%nkey, show=True)
return False return False
user_cats[nkey] = user_cats[ckey] user_cats[nkey] = user_cats[ckey]
@ -906,7 +914,7 @@ class TagsModel(QAbstractItemModel): # {{{
rest = c[len(ckey):] rest = c[len(ckey):]
if strcmp(ckey, nkey) != 0 and \ if strcmp(ckey, nkey) != 0 and \
icu_lower(nkey + rest) in user_cat_keys_lower: 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) _('The name %s is already used')%(nkey+rest), show=True)
return False return False
user_cats[nkey + rest] = user_cats[ckey + rest] user_cats[nkey + rest] = user_cats[ckey + rest]
@ -921,12 +929,12 @@ class TagsModel(QAbstractItemModel): # {{{
return False return False
if key == 'authors': if key == 'authors':
if val.find('&') >= 0: 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_() _('Author names cannot contain & characters.')).exec_()
return False return False
if key == 'search': if key == 'search':
if val in saved_searches().names(): 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_() _('The saved search name %s is already used.')%val).exec_()
return False return False
saved_searches().rename(unicode(item.data(role).toString()), val) saved_searches().rename(unicode(item.data(role).toString()), val)
@ -1161,7 +1169,10 @@ class TagsModel(QAbstractItemModel): # {{{
prefix = ' not ' prefix = ' not '
else: else:
prefix = '' 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 add_colon = False
if self.db.field_metadata[tag.category]['is_csp']: if self.db.field_metadata[tag.category]['is_csp']:
add_colon = True add_colon = True

View File

@ -218,7 +218,7 @@ class TagBrowserMixin(object): # {{{
d = TagListEditor(self, tag_to_match=tag, data=result, key=key) d = TagListEditor(self, tag_to_match=tag, data=result, key=key)
d.exec_() d.exec_()
if d.result() == d.Accepted: 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 to_delete = d.to_delete # list of ids
orig_name = d.original_names # dict of id: name orig_name = d.original_names # dict of id: name

View File

@ -7,7 +7,7 @@ __docformat__ = 'restructuredtext en'
The database used to store ebook metadata The database used to store ebook metadata
''' '''
import os, sys, shutil, cStringIO, glob, time, functools, traceback, re, \ import os, sys, shutil, cStringIO, glob, time, functools, traceback, re, \
json, uuid, tempfile, hashlib json, uuid, tempfile, hashlib, copy
from collections import defaultdict from collections import defaultdict
import threading, random import threading, random
from itertools import repeat from itertools import repeat
@ -1794,10 +1794,22 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
for user_cat in sorted(user_categories.keys(), key=sort_key): for user_cat in sorted(user_categories.keys(), key=sort_key):
items = [] items = []
names_seen = {}
for (name,label,ign) in user_categories[user_cat]: for (name,label,ign) in user_categories[user_cat]:
n = icu_lower(name) n = icu_lower(name)
if label in taglist and n in taglist[label]: 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 # else: do nothing, to not include nodes w zero counts
cat_name = '@' + user_cat # add the '@' to avoid name collision cat_name = '@' + user_cat # add the '@' to avoid name collision
# Not a problem if we accumulate entries in the icon map # Not a problem if we accumulate entries in the icon map

View File

@ -17,7 +17,7 @@ class TagsIcons(dict):
category_icons = ['authors', 'series', 'formats', 'publisher', 'rating', category_icons = ['authors', 'series', 'formats', 'publisher', 'rating',
'news', 'tags', 'custom:', 'user:', 'search', 'news', 'tags', 'custom:', 'user:', 'search',
'identifiers'] 'identifiers', 'gst']
def __init__(self, icon_dict): def __init__(self, icon_dict):
for a in self.category_icons: for a in self.category_icons:
if a not in icon_dict: if a not in icon_dict:
@ -35,7 +35,8 @@ category_icon_map = {
'custom:' : 'column.png', 'custom:' : 'column.png',
'user:' : 'tb_folder.png', 'user:' : 'tb_folder.png',
'search' : 'search.png', 'search' : 'search.png',
'identifiers': 'identifiers.png' 'identifiers': 'identifiers.png',
'gst' : 'catalog.png',
} }