Tag Browser: Add API for locating categories

This commit is contained in:
Kovid Goyal 2011-01-23 10:12:00 -07:00
commit 269e58b0df
3 changed files with 42 additions and 27 deletions

View File

@ -515,8 +515,8 @@ class TagsModel(QAbstractItemModel): # {{{
QAbstractItemModel.__init__(self, parent) QAbstractItemModel.__init__(self, parent)
# must do this here because 'QPixmap: Must construct a QApplication # must do this here because 'QPixmap: Must construct a QApplication
# before a QPaintDevice'. The ':' in front avoids polluting either the # before a QPaintDevice'. The ':' at the end avoids polluting either the
# user-defined categories (':' at end) or columns namespaces (no ':'). # user-defined categories (':' at front) or columns namespaces (no ':').
iconmap = {} iconmap = {}
for key in category_icon_map: for key in category_icon_map:
iconmap[key] = QIcon(I(category_icon_map[key])) iconmap[key] = QIcon(I(category_icon_map[key]))
@ -690,7 +690,7 @@ class TagsModel(QAbstractItemModel): # {{{
tb_cats = self.db.field_metadata tb_cats = self.db.field_metadata
for user_cat in sorted(self.db.prefs.get('user_categories', {}).keys(), for user_cat in sorted(self.db.prefs.get('user_categories', {}).keys(),
key=sort_key): key=sort_key):
cat_name = user_cat+':' # add the ':' to avoid name collision cat_name = ':' + user_cat # add the ':' to avoid name collision
tb_cats.add_user_category(label=cat_name, name=user_cat) tb_cats.add_user_category(label=cat_name, name=user_cat)
if len(saved_searches().names()): if len(saved_searches().names()):
tb_cats.add_search_category(label='search', name=_('Searches')) tb_cats.add_search_category(label='search', name=_('Searches'))
@ -997,7 +997,7 @@ class TagsModel(QAbstractItemModel): # {{{
if self.hidden_categories and self.categories[i] in self.hidden_categories: if self.hidden_categories and self.categories[i] in self.hidden_categories:
continue continue
row_index += 1 row_index += 1
if key.endswith(':'): if key.startswith(':'):
# User category, so skip it. The tag will be marked in its real category # User category, so skip it. The tag will be marked in its real category
continue continue
category_item = self.root_item.children[row_index] category_item = self.root_item.children[row_index]
@ -1016,7 +1016,7 @@ class TagsModel(QAbstractItemModel): # {{{
ans.append('%s%s:"=%s"'%(prefix, category, tag.name)) ans.append('%s%s:"=%s"'%(prefix, category, tag.name))
return ans return ans
def find_node(self, key, txt, start_path): def find_item_node(self, key, txt, start_path):
''' '''
Search for an item (a node) in the tags browser list that matches both Search for an item (a node) in the tags browser list that matches both
the key (exact case-insensitive match) and txt (contains case- the key (exact case-insensitive match) and txt (contains case-
@ -1070,6 +1070,22 @@ class TagsModel(QAbstractItemModel): # {{{
break break
return self.path_found return self.path_found
def find_category_node(self, key):
'''
Search for an category node (a top-level node) in the tags browser list
that matches the key (exact case-insensitive match). Returns the path to
the node. Paths are as in find_item_node.
'''
if not key:
return None
for i in xrange(self.rowCount(QModelIndex())):
idx = self.index(i, 0, QModelIndex())
ckey = idx.internalPointer().category_key
if strcmp(ckey, key) == 0:
return self.path_for_index(idx)
return None
def show_item_at_path(self, path, box=False): def show_item_at_path(self, path, box=False):
''' '''
Scroll the browser and open categories to show the item referenced by Scroll the browser and open categories to show the item referenced by
@ -1355,15 +1371,15 @@ class TagBrowserWidget(QWidget): # {{{
self.search_button.setFocus(True) self.search_button.setFocus(True)
self.item_search.lineEdit().blockSignals(False) self.item_search.lineEdit().blockSignals(False)
colon = txt.find(':')
key = None key = None
colon = txt.rfind(':') if len(txt) > 2 else 0
if colon > 0: if colon > 0:
key = self.parent.library_view.model().db.\ key = self.parent.library_view.model().db.\
field_metadata.search_term_to_field_key(txt[:colon]) field_metadata.search_term_to_field_key(txt[:colon])
txt = txt[colon+1:] txt = txt[colon+1:]
self.current_find_position = model.find_node(key, txt, self.current_find_position = \
self.current_find_position) model.find_item_node(key, txt, self.current_find_position)
if self.current_find_position: if self.current_find_position:
model.show_item_at_path(self.current_find_position, box=True) model.show_item_at_path(self.current_find_position, box=True)
elif self.item_search.text(): elif self.item_search.text():

View File

@ -319,7 +319,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
self.field_metadata.remove_dynamic_categories() self.field_metadata.remove_dynamic_categories()
tb_cats = self.field_metadata tb_cats = self.field_metadata
for user_cat in sorted(self.prefs.get('user_categories', {}).keys(), key=sort_key): for user_cat in sorted(self.prefs.get('user_categories', {}).keys(), key=sort_key):
cat_name = user_cat+':' # add the ':' to avoid name collision cat_name = ':' + user_cat # add the ':' to avoid name collision
tb_cats.add_user_category(label=cat_name, name=user_cat) tb_cats.add_user_category(label=cat_name, name=user_cat)
if len(saved_searches().names()): if len(saved_searches().names()):
tb_cats.add_search_category(label='search', name=_('Searches')) tb_cats.add_search_category(label='search', name=_('Searches'))
@ -1243,7 +1243,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
if category in icon_map: if category in icon_map:
icon = icon_map[label] icon = icon_map[label]
else: else:
icon = icon_map[':custom'] icon = icon_map['custom:']
icon_map[category] = icon icon_map[category] = icon
datatype = cat['datatype'] datatype = cat['datatype']
@ -1339,11 +1339,10 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
if label in taglist and name in taglist[label]: if label in taglist and name in taglist[label]:
items.append(taglist[label][name]) items.append(taglist[label][name])
# else: do nothing, to not include nodes w zero counts # else: do nothing, to not include nodes w zero counts
if len(items): 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
if icon_map is not None: if icon_map is not None:
icon_map[cat_name] = icon_map[':user'] icon_map[cat_name] = icon_map['user:']
if sort == 'popularity': if sort == 'popularity':
categories[cat_name] = \ categories[cat_name] = \
sorted(items, key=lambda x: x.count, reverse=True) sorted(items, key=lambda x: x.count, reverse=True)

View File

@ -16,7 +16,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',]
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:
@ -31,8 +31,8 @@ category_icon_map = {
'rating' : 'rating.png', 'rating' : 'rating.png',
'news' : 'news.png', 'news' : 'news.png',
'tags' : 'tags.png', 'tags' : 'tags.png',
':custom' : 'column.png', 'custom:' : 'column.png',
':user' : 'drawer.png', 'user:' : 'drawer.png',
'search' : 'search.png' 'search' : 'search.png'
} }