mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 10:44:09 -04:00
Several things:
1) can remove an item from a user category 2) can remove a user category 3) renaming an item will also rename the item in all user categories 4) make find_item_node work in the face of hierarchies (user cats and items) 5) change set_new_model() to recount() where possible to avoid closing expanded trees
This commit is contained in:
parent
1f88b1f1b5
commit
f5f1c87cd5
@ -25,7 +25,7 @@ from calibre.utils.config import tweaks
|
|||||||
from calibre.utils.icu import sort_key, upper, lower, strcmp
|
from calibre.utils.icu import sort_key, upper, lower, strcmp
|
||||||
from calibre.utils.search_query_parser import saved_searches
|
from calibre.utils.search_query_parser import saved_searches
|
||||||
from calibre.utils.formatter import eval_formatter
|
from calibre.utils.formatter import eval_formatter
|
||||||
from calibre.gui2 import error_dialog
|
from calibre.gui2 import error_dialog, question_dialog
|
||||||
from calibre.gui2.dialogs.confirm_delete import confirm
|
from calibre.gui2.dialogs.confirm_delete import confirm
|
||||||
from calibre.gui2.dialogs.tag_categories import TagCategories
|
from calibre.gui2.dialogs.tag_categories import TagCategories
|
||||||
from calibre.gui2.dialogs.tag_list_editor import TagListEditor
|
from calibre.gui2.dialogs.tag_list_editor import TagListEditor
|
||||||
@ -73,6 +73,8 @@ class TagsView(QTreeView): # {{{
|
|||||||
refresh_required = pyqtSignal()
|
refresh_required = pyqtSignal()
|
||||||
tags_marked = pyqtSignal(object)
|
tags_marked = pyqtSignal(object)
|
||||||
user_category_edit = pyqtSignal(object)
|
user_category_edit = pyqtSignal(object)
|
||||||
|
user_category_delete= pyqtSignal(object)
|
||||||
|
del_user_cat_item = pyqtSignal(object, object, object)
|
||||||
add_subcategory = pyqtSignal(object)
|
add_subcategory = pyqtSignal(object)
|
||||||
tag_list_edit = pyqtSignal(object, object)
|
tag_list_edit = pyqtSignal(object, object)
|
||||||
saved_search_edit = pyqtSignal(object)
|
saved_search_edit = pyqtSignal(object)
|
||||||
@ -105,6 +107,7 @@ class TagsView(QTreeView): # {{{
|
|||||||
else:
|
else:
|
||||||
self.collapse_model = gprefs['tags_browser_partition_method']
|
self.collapse_model = gprefs['tags_browser_partition_method']
|
||||||
self.search_icon = QIcon(I('search.png'))
|
self.search_icon = QIcon(I('search.png'))
|
||||||
|
self.user_category_icon = QIcon(I('tb_folder.png'))
|
||||||
|
|
||||||
def set_pane_is_visible(self, to_what):
|
def set_pane_is_visible(self, to_what):
|
||||||
pv = self.pane_is_visible
|
pv = self.pane_is_visible
|
||||||
@ -220,15 +223,21 @@ class TagsView(QTreeView): # {{{
|
|||||||
if action == 'manage_categories':
|
if action == 'manage_categories':
|
||||||
self.user_category_edit.emit(category)
|
self.user_category_edit.emit(category)
|
||||||
return
|
return
|
||||||
if action == 'add_subcategory':
|
|
||||||
self.add_subcategory.emit(category)
|
|
||||||
return
|
|
||||||
if action == 'search':
|
if action == 'search':
|
||||||
self._toggle(index, set_to=search_state)
|
self._toggle(index, set_to=search_state)
|
||||||
return
|
return
|
||||||
|
if action == 'add_subcategory':
|
||||||
|
self.add_subcategory.emit(key)
|
||||||
|
return
|
||||||
if action == 'search_category':
|
if action == 'search_category':
|
||||||
self.tags_marked.emit(key + ':' + search_state)
|
self.tags_marked.emit(key + ':' + search_state)
|
||||||
return
|
return
|
||||||
|
if action == 'delete_user_category':
|
||||||
|
self.user_category_delete.emit(key)
|
||||||
|
return
|
||||||
|
if action == 'delete_item_from_user_category':
|
||||||
|
self.del_user_cat_item.emit(key, index.name, index.category)
|
||||||
|
return
|
||||||
if action == 'manage_searches':
|
if action == 'manage_searches':
|
||||||
self.saved_search_edit.emit(category)
|
self.saved_search_edit.emit(category)
|
||||||
return
|
return
|
||||||
@ -259,14 +268,11 @@ class TagsView(QTreeView): # {{{
|
|||||||
|
|
||||||
if index.isValid():
|
if index.isValid():
|
||||||
item = index.internalPointer()
|
item = index.internalPointer()
|
||||||
tag_name = ''
|
tag = None
|
||||||
|
|
||||||
if item.type == TagTreeItem.TAG:
|
if item.type == TagTreeItem.TAG:
|
||||||
tag_item = item
|
tag = item.tag
|
||||||
t = item.tag
|
can_edit = getattr(tag, 'can_edit', True)
|
||||||
tag_name = t.name
|
|
||||||
tag_id = t.id
|
|
||||||
can_edit = getattr(t, 'can_edit', True)
|
|
||||||
while item.type != TagTreeItem.CATEGORY:
|
while item.type != TagTreeItem.CATEGORY:
|
||||||
item = item.parent
|
item = item.parent
|
||||||
|
|
||||||
@ -281,42 +287,50 @@ class TagsView(QTreeView): # {{{
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
# Did the user click on a leaf node?
|
# Did the user click on a leaf node?
|
||||||
if tag_name:
|
if tag:
|
||||||
# If the user right-clicked on an editable item, then offer
|
# If the user right-clicked on an editable item, then offer
|
||||||
# the possibility of renaming that item.
|
# the possibility of renaming that item.
|
||||||
if can_edit and \
|
if can_edit:
|
||||||
key in ['authors', 'tags', 'series', 'publisher', 'search'] or \
|
|
||||||
(self.db.field_metadata[key]['is_custom'] and \
|
|
||||||
self.db.field_metadata[key]['datatype'] != 'rating'):
|
|
||||||
# Add the 'rename' items
|
# Add the 'rename' items
|
||||||
self.context_menu.addAction(_('Rename %s')%tag_name,
|
self.context_menu.addAction(_('Rename %s')%tag.name,
|
||||||
partial(self.context_menu_handler, action='edit_item',
|
partial(self.context_menu_handler, action='edit_item',
|
||||||
category=tag_item, index=index))
|
index=index))
|
||||||
if key == 'authors':
|
if key == 'authors':
|
||||||
self.context_menu.addAction(_('Edit sort for %s')%tag_name,
|
self.context_menu.addAction(_('Edit sort for %s')%tag.name,
|
||||||
partial(self.context_menu_handler,
|
partial(self.context_menu_handler,
|
||||||
action='edit_author_sort', index=tag_id))
|
action='edit_author_sort', index=tag.id))
|
||||||
|
if key.startswith('@'):
|
||||||
|
self.context_menu.addAction(self.user_category_icon,
|
||||||
|
_('Remove %s from category %s')%(tag.name, item.py_name),
|
||||||
|
partial(self.context_menu_handler,
|
||||||
|
action='delete_item_from_user_category',
|
||||||
|
key = key, index = tag))
|
||||||
# Add the search for value items
|
# Add the search for value items
|
||||||
self.context_menu.addAction(self.search_icon,
|
self.context_menu.addAction(self.search_icon,
|
||||||
_('Search for %s')%tag_name,
|
_('Search for %s')%tag.name,
|
||||||
partial(self.context_menu_handler, action='search',
|
partial(self.context_menu_handler, action='search',
|
||||||
search_state=TAG_SEARCH_STATES['mark_plus'],
|
search_state=TAG_SEARCH_STATES['mark_plus'],
|
||||||
index=index))
|
index=index))
|
||||||
self.context_menu.addAction(self.search_icon,
|
self.context_menu.addAction(self.search_icon,
|
||||||
_('Search for everything but %s')%tag_name,
|
_('Search for everything but %s')%tag.name,
|
||||||
partial(self.context_menu_handler, action='search',
|
partial(self.context_menu_handler, action='search',
|
||||||
search_state=TAG_SEARCH_STATES['mark_minus'],
|
search_state=TAG_SEARCH_STATES['mark_minus'],
|
||||||
index=index))
|
index=index))
|
||||||
self.context_menu.addSeparator()
|
self.context_menu.addSeparator()
|
||||||
elif key.startswith('@'):
|
elif key.startswith('@'):
|
||||||
if item.can_edit:
|
if item.can_edit:
|
||||||
self.context_menu.addAction(_('Rename %s')%key[1:],
|
self.context_menu.addAction(self.user_category_icon,
|
||||||
|
_('Rename %s')%item.py_name,
|
||||||
partial(self.context_menu_handler, action='edit_item',
|
partial(self.context_menu_handler, action='edit_item',
|
||||||
category=key, index=index))
|
index=index))
|
||||||
self.context_menu.addAction(self.search_icon,
|
self.context_menu.addAction(self.user_category_icon,
|
||||||
_('Add sub-category to %s')%key[1:],
|
_('Add sub-category to %s')%item.py_name,
|
||||||
partial(self.context_menu_handler,
|
partial(self.context_menu_handler,
|
||||||
action='add_subcategory', category=key))
|
action='add_subcategory', key=key))
|
||||||
|
self.context_menu.addAction(self.user_category_icon,
|
||||||
|
_('Delete user category %s')%item.py_name,
|
||||||
|
partial(self.context_menu_handler,
|
||||||
|
action='delete_user_category', key=key))
|
||||||
self.context_menu.addSeparator()
|
self.context_menu.addSeparator()
|
||||||
# Hide/Show/Restore categories
|
# Hide/Show/Restore categories
|
||||||
if not key.startswith('@') or key.find('.') < 0:
|
if not key.startswith('@') or key.find('.') < 0:
|
||||||
@ -345,14 +359,14 @@ class TagsView(QTreeView): # {{{
|
|||||||
self.db.field_metadata[key]['is_custom']:
|
self.db.field_metadata[key]['is_custom']:
|
||||||
self.context_menu.addAction(_('Manage %s')%category,
|
self.context_menu.addAction(_('Manage %s')%category,
|
||||||
partial(self.context_menu_handler, action='open_editor',
|
partial(self.context_menu_handler, action='open_editor',
|
||||||
category=tag_name, key=key))
|
category=tag.name if tag else None, key=key))
|
||||||
elif key == 'authors':
|
elif key == 'authors':
|
||||||
self.context_menu.addAction(_('Manage %s')%category,
|
self.context_menu.addAction(_('Manage %s')%category,
|
||||||
partial(self.context_menu_handler, action='edit_author_sort'))
|
partial(self.context_menu_handler, action='edit_author_sort'))
|
||||||
elif key == 'search':
|
elif key == 'search':
|
||||||
self.context_menu.addAction(_('Manage Saved Searches'),
|
self.context_menu.addAction(_('Manage Saved Searches'),
|
||||||
partial(self.context_menu_handler, action='manage_searches',
|
partial(self.context_menu_handler, action='manage_searches',
|
||||||
category=tag_name))
|
category=tag.name if tag else None))
|
||||||
|
|
||||||
# Always show the user categories editor
|
# Always show the user categories editor
|
||||||
self.context_menu.addSeparator()
|
self.context_menu.addSeparator()
|
||||||
@ -534,6 +548,8 @@ class TagTreeItem(object): # {{{
|
|||||||
def category_data(self, role):
|
def category_data(self, role):
|
||||||
if role == Qt.DisplayRole:
|
if role == Qt.DisplayRole:
|
||||||
return QVariant(self.py_name + ' [%d]'%len(self.child_tags()))
|
return QVariant(self.py_name + ' [%d]'%len(self.child_tags()))
|
||||||
|
if role == Qt.EditRole:
|
||||||
|
return QVariant(self.py_name)
|
||||||
if role == Qt.DecorationRole:
|
if role == Qt.DecorationRole:
|
||||||
return self.icon
|
return self.icon
|
||||||
if role == Qt.FontRole:
|
if role == Qt.FontRole:
|
||||||
@ -727,8 +743,19 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
for s in src:
|
for s in src:
|
||||||
if s[0] != TagTreeItem.TAG:
|
if s[0] != TagTreeItem.TAG:
|
||||||
return False
|
return False
|
||||||
|
return self.move_or_copy_item_to_user_category(src, dest, action)
|
||||||
|
|
||||||
|
def move_or_copy_item_to_user_category(self, src, dest, action):
|
||||||
|
'''
|
||||||
|
src is a list of tuples representing items to copy. The tuple is
|
||||||
|
(type, containing category key, full name, category key, id)
|
||||||
|
The type must be TagTreeItem.TAG
|
||||||
|
dest is the TagTreeItem node to receive the items
|
||||||
|
action is Qt.CopyAction or Qt.MoveAction
|
||||||
|
'''
|
||||||
user_cats = self.db.prefs.get('user_categories', {})
|
user_cats = self.db.prefs.get('user_categories', {})
|
||||||
parent_node = None
|
parent_node = None
|
||||||
|
copied_node = None
|
||||||
for s in src:
|
for s in src:
|
||||||
src_parent, src_name, src_cat = s[1:4]
|
src_parent, src_name, src_cat = s[1:4]
|
||||||
parent_node = src_parent
|
parent_node = src_parent
|
||||||
@ -748,6 +775,9 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
continue
|
continue
|
||||||
new_cat.append(list(tup))
|
new_cat.append(list(tup))
|
||||||
user_cats[src_parent] = new_cat
|
user_cats[src_parent] = new_cat
|
||||||
|
else:
|
||||||
|
copied_node = (src_parent, src_name)
|
||||||
|
|
||||||
# Now add the item to the destination user category
|
# Now add the item to the destination user category
|
||||||
add_it = True
|
add_it = True
|
||||||
if not is_uc and src_cat == 'news':
|
if not is_uc and src_cat == 'news':
|
||||||
@ -757,11 +787,16 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
add_it = False
|
add_it = False
|
||||||
if add_it:
|
if add_it:
|
||||||
user_cats[dest_key].append([src_name, src_cat, 0])
|
user_cats[dest_key].append([src_name, src_cat, 0])
|
||||||
|
|
||||||
self.db.prefs.set('user_categories', user_cats)
|
self.db.prefs.set('user_categories', user_cats)
|
||||||
self.tags_view.set_new_model()
|
self.tags_view.recount()
|
||||||
|
|
||||||
if parent_node is not None:
|
if parent_node is not None:
|
||||||
# Must work with the new model here
|
|
||||||
m = self.tags_view.model()
|
m = self.tags_view.model()
|
||||||
|
if copied_node is not None:
|
||||||
|
path = m.find_item_node(parent_node, copied_node[1], None,
|
||||||
|
equals_match=True)
|
||||||
|
else:
|
||||||
path = m.find_category_node(parent_node)
|
path = m.find_category_node(parent_node)
|
||||||
idx = m.index_for_path(path)
|
idx = m.index_for_path(path)
|
||||||
self.tags_view.setExpanded(idx, True)
|
self.tags_view.setExpanded(idx, True)
|
||||||
@ -1031,15 +1066,17 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
node_parent = category
|
node_parent = category
|
||||||
|
|
||||||
components = [t for t in tag.name.split('.')]
|
components = [t for t in tag.name.split('.')]
|
||||||
if key in ['authors', 'publisher', 'news', 'formats'] or \
|
if key in ['authors', 'publisher', 'news', 'formats', 'rating'] or \
|
||||||
key not in self.db.prefs.get('categories_using_hierarchy', []) or\
|
key not in self.db.prefs.get('categories_using_hierarchy', []) or\
|
||||||
len(components) == 1 or \
|
len(components) == 1 or \
|
||||||
fm['kind'] == 'user' or \
|
fm['kind'] == 'user':
|
||||||
fm['datatype'] not in ['text', 'series', 'enumeration']:
|
|
||||||
self.beginInsertRows(category_index, 999999, 1)
|
self.beginInsertRows(category_index, 999999, 1)
|
||||||
TagTreeItem(parent=node_parent, data=tag, tooltip=tt,
|
TagTreeItem(parent=node_parent, data=tag, tooltip=tt,
|
||||||
icon_map=self.icon_state_map)
|
icon_map=self.icon_state_map)
|
||||||
self.endInsertRows()
|
self.endInsertRows()
|
||||||
|
tag.can_edit = key != 'formats' and \
|
||||||
|
self.db.field_metadata[tag.category]['datatype'] in \
|
||||||
|
['text', 'series', 'enumeration']
|
||||||
else:
|
else:
|
||||||
for i,comp in enumerate(components):
|
for i,comp in enumerate(components):
|
||||||
child_map = dict([(t.tag.name, t) for t in node_parent.children
|
child_map = dict([(t.tag.name, t) for t in node_parent.children
|
||||||
@ -1137,10 +1174,9 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
p = self.tags_view.model().find_category_node('@' + nkey)
|
p = self.tags_view.model().find_category_node('@' + nkey)
|
||||||
self.tags_view.model().show_item_at_path(p)
|
self.tags_view.model().show_item_at_path(p)
|
||||||
return True
|
return True
|
||||||
itm = item.parent
|
|
||||||
while itm.type != TagTreeItem.CATEGORY:
|
key = item.tag.category
|
||||||
itm = itm.parent
|
name = item.tag.name
|
||||||
key = itm.category_key
|
|
||||||
# make certain we know about the item's category
|
# make certain we know about the item's category
|
||||||
if key not in self.db.field_metadata:
|
if key not in self.db.field_metadata:
|
||||||
return False
|
return False
|
||||||
@ -1171,6 +1207,17 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
label=self.db.field_metadata[key]['label'])
|
label=self.db.field_metadata[key]['label'])
|
||||||
self.tags_view.tag_item_renamed.emit()
|
self.tags_view.tag_item_renamed.emit()
|
||||||
item.tag.name = val
|
item.tag.name = val
|
||||||
|
# rename the item in any user categories
|
||||||
|
user_cats = self.db.prefs.get('user_categories', {})
|
||||||
|
for k in user_cats.keys():
|
||||||
|
new_contents = []
|
||||||
|
for tup in user_cats[k]:
|
||||||
|
if tup[0] == name and tup[1] == key:
|
||||||
|
new_contents.append([val, key, 0])
|
||||||
|
else:
|
||||||
|
new_contents.append(tup)
|
||||||
|
user_cats[k] = new_contents
|
||||||
|
self.db.prefs.set('user_categories', user_cats)
|
||||||
self.refresh() # Should work, because no categories can have disappeared
|
self.refresh() # Should work, because no categories can have disappeared
|
||||||
self.show_item_at_path(path)
|
self.show_item_at_path(path)
|
||||||
return True
|
return True
|
||||||
@ -1329,19 +1376,20 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
name.replace(r'"', r'\"')))
|
name.replace(r'"', r'\"')))
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
def find_item_node(self, key, txt, start_path):
|
def find_item_node(self, key, txt, start_path, equals_match=False):
|
||||||
'''
|
'''
|
||||||
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 (not equals_match =>
|
||||||
insensitive match). Returns the path to the node. Note that paths are to
|
case-insensitive contains match; equals_match => case_insensitive
|
||||||
a location (second item, fourth item, 25 item), not to a node. If
|
equal match). Returns the path to the node. Note that paths are to a
|
||||||
|
location (second item, fourth item, 25 item), not to a node. If
|
||||||
start_path is None, the search starts with the topmost node. If the tree
|
start_path is None, the search starts with the topmost node. If the tree
|
||||||
is changed subsequent to calling this method, the path can easily refer
|
is changed subsequent to calling this method, the path can easily refer
|
||||||
to a different node or no node at all.
|
to a different node or no node at all.
|
||||||
'''
|
'''
|
||||||
if not txt:
|
if not txt:
|
||||||
return None
|
return None
|
||||||
txt = lower(txt)
|
txt = lower(txt) if not equals_match else txt
|
||||||
self.path_found = None
|
self.path_found = None
|
||||||
if start_path is None:
|
if start_path is None:
|
||||||
start_path = []
|
start_path = []
|
||||||
@ -1353,7 +1401,9 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
tag = tag_item.tag
|
tag = tag_item.tag
|
||||||
if tag is None:
|
if tag is None:
|
||||||
return False
|
return False
|
||||||
if lower(tag.name).find(txt) >= 0:
|
name = getattr(tag, 'original_name', tag.name)
|
||||||
|
if (equals_match and strcmp(name, txt) == 0) or \
|
||||||
|
(not equals_match and lower(name).find(txt) >= 0):
|
||||||
self.path_found = path
|
self.path_found = path
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
@ -1365,15 +1415,14 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
return False
|
return False
|
||||||
if path[depth] > start_path[depth]:
|
if path[depth] > start_path[depth]:
|
||||||
start_path = path
|
start_path = path
|
||||||
if key and strcmp(category_index.internalPointer().category_key, key) != 0:
|
my_key = category_index.internalPointer().category_key
|
||||||
return False
|
|
||||||
for j in xrange(self.rowCount(category_index)):
|
for j in xrange(self.rowCount(category_index)):
|
||||||
tag_index = self.index(j, 0, category_index)
|
tag_index = self.index(j, 0, category_index)
|
||||||
tag_item = tag_index.internalPointer()
|
tag_item = tag_index.internalPointer()
|
||||||
if tag_item.type == TagTreeItem.CATEGORY:
|
if tag_item.type == TagTreeItem.CATEGORY:
|
||||||
if process_level(depth+1, tag_index, start_path):
|
if process_level(depth+1, tag_index, start_path):
|
||||||
return True
|
return True
|
||||||
else:
|
elif not key or strcmp(key, my_key) == 0:
|
||||||
if process_tag(depth+1, tag_index, tag_item, start_path):
|
if process_tag(depth+1, tag_index, tag_item, start_path):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
@ -1457,6 +1506,8 @@ class TagBrowserMixin(object): # {{{
|
|||||||
self.tags_view.tags_marked.connect(self.search.set_search_string)
|
self.tags_view.tags_marked.connect(self.search.set_search_string)
|
||||||
self.tags_view.tag_list_edit.connect(self.do_tags_list_edit)
|
self.tags_view.tag_list_edit.connect(self.do_tags_list_edit)
|
||||||
self.tags_view.user_category_edit.connect(self.do_user_categories_edit)
|
self.tags_view.user_category_edit.connect(self.do_user_categories_edit)
|
||||||
|
self.tags_view.user_category_delete.connect(self.do_user_category_delete)
|
||||||
|
self.tags_view.del_user_cat_item.connect(self.do_del_user_cat_item)
|
||||||
self.tags_view.add_subcategory.connect(self.do_add_subcategory)
|
self.tags_view.add_subcategory.connect(self.do_add_subcategory)
|
||||||
self.tags_view.saved_search_edit.connect(self.do_saved_search_edit)
|
self.tags_view.saved_search_edit.connect(self.do_saved_search_edit)
|
||||||
self.tags_view.author_sort_edit.connect(self.do_author_sort_edit)
|
self.tags_view.author_sort_edit.connect(self.do_author_sort_edit)
|
||||||
@ -1466,7 +1517,29 @@ class TagBrowserMixin(object): # {{{
|
|||||||
self.edit_categories.clicked.connect(lambda x:
|
self.edit_categories.clicked.connect(lambda x:
|
||||||
self.do_user_categories_edit())
|
self.do_user_categories_edit())
|
||||||
|
|
||||||
def do_add_subcategory(self, on_category=None):
|
def do_del_user_cat_item(self, user_cat, item_name, item_category):
|
||||||
|
'''
|
||||||
|
Delete the item (item_name, item_category) from the user category with
|
||||||
|
key user_cat. Any leading '@' characters are removed
|
||||||
|
'''
|
||||||
|
if user_cat.startswith('@'):
|
||||||
|
user_cat = user_cat[1:]
|
||||||
|
db = self.library_view.model().db
|
||||||
|
user_cats = db.prefs.get('user_categories', {})
|
||||||
|
if user_cat not in user_cats:
|
||||||
|
error_dialog(self.tags_view, _('Remove category'),
|
||||||
|
_('User category %s does not exist')%user_cat,
|
||||||
|
show=True)
|
||||||
|
return
|
||||||
|
new_contents = []
|
||||||
|
for tup in user_cats[user_cat]:
|
||||||
|
if tup[0] != item_name or tup[1] != item_category:
|
||||||
|
new_contents.append(tup)
|
||||||
|
user_cats[user_cat] = new_contents
|
||||||
|
db.prefs.set('user_categories', user_cats)
|
||||||
|
self.tags_view.recount()
|
||||||
|
|
||||||
|
def do_add_subcategory(self, on_category_key=None):
|
||||||
db = self.library_view.model().db
|
db = self.library_view.model().db
|
||||||
user_cats = db.prefs.get('user_categories', {})
|
user_cats = db.prefs.get('user_categories', {})
|
||||||
|
|
||||||
@ -1475,7 +1548,7 @@ class TagBrowserMixin(object): # {{{
|
|||||||
new_name = _('New Category').replace('.', '')
|
new_name = _('New Category').replace('.', '')
|
||||||
n = new_name
|
n = new_name
|
||||||
while True:
|
while True:
|
||||||
new_cat = on_category[1:] + '.' + n
|
new_cat = on_category_key[1:] + '.' + n
|
||||||
if new_cat not in user_cats:
|
if new_cat not in user_cats:
|
||||||
break
|
break
|
||||||
i += 1
|
i += 1
|
||||||
@ -1500,7 +1573,39 @@ class TagBrowserMixin(object): # {{{
|
|||||||
db.field_metadata.add_user_category('@' + k, k)
|
db.field_metadata.add_user_category('@' + k, k)
|
||||||
db.data.change_search_locations(db.field_metadata.get_search_terms())
|
db.data.change_search_locations(db.field_metadata.get_search_terms())
|
||||||
self.tags_view.set_new_model()
|
self.tags_view.set_new_model()
|
||||||
self.tags_view.recount()
|
|
||||||
|
def do_user_category_delete(self, category_name):
|
||||||
|
'''
|
||||||
|
Delete the user category named category_name. Any leading '@' is removed
|
||||||
|
'''
|
||||||
|
if category_name.startswith('@'):
|
||||||
|
category_name = category_name[1:]
|
||||||
|
db = self.library_view.model().db
|
||||||
|
user_cats = db.prefs.get('user_categories', {})
|
||||||
|
cat_keys = sorted(user_cats.keys(), key=sort_key)
|
||||||
|
has_children = False
|
||||||
|
found = False
|
||||||
|
for k in cat_keys:
|
||||||
|
if k == category_name:
|
||||||
|
found = True
|
||||||
|
has_children = len(user_cats[k])
|
||||||
|
elif k.startswith(category_name + '.'):
|
||||||
|
has_children = True
|
||||||
|
if not found:
|
||||||
|
return error_dialog(self.tags_view, _('Delete user category'),
|
||||||
|
_('%s is not a user category')%category_name, show=True)
|
||||||
|
if has_children:
|
||||||
|
if not question_dialog(self.tags_view, _('Delete user category'),
|
||||||
|
_('%s contains items. Do you really '
|
||||||
|
'want to delete it?')%category_name):
|
||||||
|
return
|
||||||
|
for k in cat_keys:
|
||||||
|
if k == category_name:
|
||||||
|
del user_cats[k]
|
||||||
|
elif k.startswith(category_name + '.'):
|
||||||
|
del user_cats[k]
|
||||||
|
db.prefs.set('user_categories', user_cats)
|
||||||
|
self.tags_view.set_new_model()
|
||||||
|
|
||||||
def do_tags_list_edit(self, tag, category):
|
def do_tags_list_edit(self, tag, category):
|
||||||
db=self.library_view.model().db
|
db=self.library_view.model().db
|
||||||
@ -1548,7 +1653,7 @@ class TagBrowserMixin(object): # {{{
|
|||||||
|
|
||||||
# Clean up the library view
|
# Clean up the library view
|
||||||
self.do_tag_item_renamed()
|
self.do_tag_item_renamed()
|
||||||
self.tags_view.set_new_model() # does a refresh for free
|
self.tags_view.set_new_model()
|
||||||
|
|
||||||
def do_tag_item_renamed(self):
|
def do_tag_item_renamed(self):
|
||||||
# Clean up library view and search
|
# Clean up library view and search
|
||||||
|
Loading…
x
Reference in New Issue
Block a user