mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
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:
commit
d7175e67bd
@ -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)
|
||||||
|
@ -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':
|
||||||
|
@ -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,6 +1169,9 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
prefix = ' not '
|
prefix = ' not '
|
||||||
else:
|
else:
|
||||||
prefix = ''
|
prefix = ''
|
||||||
|
if node.is_gst:
|
||||||
|
category = key
|
||||||
|
else:
|
||||||
category = tag.category if key != 'news' else 'tag'
|
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']:
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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,9 +1794,21 @@ 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]:
|
||||||
|
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])
|
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
|
||||||
|
@ -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',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user