Add a right-click option to send (copy) an item to a user category. Clean up some names and documentation

This commit is contained in:
Charles Haley 2011-02-24 14:04:22 +00:00
parent 9f7034f893
commit c2a1bd7a4c

View File

@ -70,18 +70,19 @@ TAG_SEARCH_STATES = {'clear': 0, 'mark_plus': 1, 'mark_minus': 2}
class TagsView(QTreeView): # {{{ class TagsView(QTreeView): # {{{
refresh_required = pyqtSignal() refresh_required = pyqtSignal()
tags_marked = pyqtSignal(object) tags_marked = pyqtSignal(object)
user_category_edit = pyqtSignal(object) edit_user_category = pyqtSignal(object)
user_category_delete= pyqtSignal(object) delete_user_category = pyqtSignal(object)
del_user_cat_item = pyqtSignal(object, object, object) del_item_from_user_cat = pyqtSignal(object, object, object)
add_subcategory = pyqtSignal(object) add_item_to_user_cat = pyqtSignal(object, object, object)
tag_list_edit = pyqtSignal(object, object) add_subcategory = pyqtSignal(object)
saved_search_edit = pyqtSignal(object) tag_list_edit = pyqtSignal(object, object)
author_sort_edit = pyqtSignal(object, object) saved_search_edit = pyqtSignal(object)
tag_item_renamed = pyqtSignal() author_sort_edit = pyqtSignal(object, object)
search_item_renamed = pyqtSignal() tag_item_renamed = pyqtSignal()
drag_drop_finished = pyqtSignal(object, object) search_item_renamed = pyqtSignal()
drag_drop_finished = pyqtSignal(object, object)
def __init__(self, parent=None): def __init__(self, parent=None):
QTreeView.__init__(self, parent=None) QTreeView.__init__(self, parent=None)
@ -221,11 +222,16 @@ class TagsView(QTreeView): # {{{
self.tag_list_edit.emit(category, key) self.tag_list_edit.emit(category, key)
return return
if action == 'manage_categories': if action == 'manage_categories':
self.user_category_edit.emit(category) self.edit_user_category.emit(category)
return 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_to_category':
self.add_item_to_user_cat.emit(category,
getattr(index, 'original_name', index.name),
index.category)
return
if action == 'add_subcategory': if action == 'add_subcategory':
self.add_subcategory.emit(key) self.add_subcategory.emit(key)
return return
@ -233,10 +239,10 @@ class TagsView(QTreeView): # {{{
self.tags_marked.emit(key + ':' + search_state) self.tags_marked.emit(key + ':' + search_state)
return return
if action == 'delete_user_category': if action == 'delete_user_category':
self.user_category_delete.emit(key) self.delete_user_category.emit(key)
return return
if action == 'delete_item_from_user_category': if action == 'delete_item_from_user_category':
self.del_user_cat_item.emit(key, self.del_item_from_user_cat.emit(key,
getattr(index, 'original_name', index.name), index.category) getattr(index, 'original_name', index.name), index.category)
return return
if action == 'manage_searches': if action == 'manage_searches':
@ -300,6 +306,25 @@ class TagsView(QTreeView): # {{{
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))
m = self.context_menu.addMenu(self.user_category_icon,
_('Add %s to user category')%tag.name)
nt = self.model().category_node_tree
def add_node_tree(tree_dict, m, path):
p = path[:]
for k in sorted(tree_dict.keys(), key=sort_key):
p.append(k)
m.addAction(self.user_category_icon, k,
partial(self.context_menu_handler,
'add_to_category',
category='.'.join(p),
index=tag))
if len(tree_dict[k]):
tm = m.addMenu(self.user_category_icon,
_('Children of %s')%k)
add_node_tree(tree_dict[k], tm, p)
p.pop()
add_node_tree(nt, m, [])
if key.startswith('@') and not item.is_gst: if key.startswith('@') and not item.is_gst:
self.context_menu.addAction(self.user_category_icon, self.context_menu.addAction(self.user_category_icon,
_('Remove %s from category %s')%(tag.name, item.py_name), _('Remove %s from category %s')%(tag.name, item.py_name),
@ -652,6 +677,7 @@ class TagsModel(QAbstractItemModel): # {{{
last_category_node = None last_category_node = None
category_node_map = {} category_node_map = {}
self.category_node_tree = {}
for i, r in enumerate(self.row_map): for i, r in enumerate(self.row_map):
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
@ -668,6 +694,7 @@ class TagsModel(QAbstractItemModel): # {{{
path_parts = [p.strip() for p in r.split('.') if p.strip()] path_parts = [p.strip() for p in r.split('.') if p.strip()]
path = '' path = ''
last_category_node = self.root_item last_category_node = self.root_item
tree_root = self.category_node_tree
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:
@ -681,8 +708,12 @@ class TagsModel(QAbstractItemModel): # {{{
self.category_nodes.append(node) self.category_nodes.append(node)
node.can_edit = (not is_gst) and (i == (len(path_parts)-1)) node.can_edit = (not is_gst) and (i == (len(path_parts)-1))
node.is_gst = is_gst node.is_gst = is_gst
if not is_gst:
tree_root[p] = {}
tree_root = tree_root[p]
else: else:
last_category_node = category_node_map[path] last_category_node = category_node_map[path]
tree_root = tree_root[p]
path += '.' path += '.'
else: else:
node = TagTreeItem(parent=self.root_item, node = TagTreeItem(parent=self.root_item,
@ -756,6 +787,7 @@ class TagsModel(QAbstractItemModel): # {{{
src is a list of tuples representing items to copy. The tuple is src is a list of tuples representing items to copy. The tuple is
(type, containing category key, category key is global search term, (type, containing category key, category key is global search term,
full name, category key, id) full name, category key, id)
The 'id' member is ignored, and can be None.
The type must be TagTreeItem.TAG The type must be TagTreeItem.TAG
dest is the TagTreeItem node to receive the items dest is the TagTreeItem node to receive the items
action is Qt.CopyAction or Qt.MoveAction action is Qt.CopyAction or Qt.MoveAction
@ -1550,43 +1582,34 @@ class TagBrowserMixin(object): # {{{
self.tags_view.set_database(db, self.tag_match, self.sort_by) self.tags_view.set_database(db, self.tag_match, self.sort_by)
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.edit_user_category.connect(self.do_edit_user_categories)
self.tags_view.user_category_delete.connect(self.do_user_category_delete) self.tags_view.delete_user_category.connect(self.do_delete_user_category)
self.tags_view.del_user_cat_item.connect(self.do_del_user_cat_item) self.tags_view.del_item_from_user_cat.connect(self.do_del_item_from_user_cat)
self.tags_view.add_subcategory.connect(self.do_add_subcategory) self.tags_view.add_subcategory.connect(self.do_add_subcategory)
self.tags_view.add_item_to_user_cat.connect(self.do_add_item_to_user_cat)
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)
self.tags_view.tag_item_renamed.connect(self.do_tag_item_renamed) self.tags_view.tag_item_renamed.connect(self.do_tag_item_renamed)
self.tags_view.search_item_renamed.connect(self.saved_searches_changed) self.tags_view.search_item_renamed.connect(self.saved_searches_changed)
self.tags_view.drag_drop_finished.connect(self.drag_drop_finished) self.tags_view.drag_drop_finished.connect(self.drag_drop_finished)
self.edit_categories.clicked.connect(lambda x: self.edit_categories.clicked.connect(lambda x:
self.do_user_categories_edit()) self.do_edit_user_categories())
def do_del_user_cat_item(self, user_cat, item_name, item_category): def do_add_subcategory(self, on_category_key, new_category_name=None):
''' '''
Delete the item (item_name, item_category) from the user category with Add a subcategory to the category 'on_category'. If new_category_name is
key user_cat. Any leading '@' characters are removed None, then a default name is shown and the user is offered the
opportunity to edit the name.
''' '''
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
self.tags_view.model().delete_item_from_user_category(user_cat,
item_name, item_category)
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', {})
# Ensure that the temporary name we will use is not already there # Ensure that the temporary name we will use is not already there
i = 0 i = 0
new_name = _('New Category').replace('.', '') if new_category_name is not None:
new_name = new_category_name.replace('.', '')
else:
new_name = _('New Category').replace('.', '')
n = new_name n = new_name
while True: while True:
new_cat = on_category_key[1:] + '.' + n new_cat = on_category_key[1:] + '.' + n
@ -1602,9 +1625,13 @@ class TagBrowserMixin(object): # {{{
idx = m.index_for_path(m.find_category_node('@' + new_cat)) idx = m.index_for_path(m.find_category_node('@' + new_cat))
m.show_item_at_index(idx) m.show_item_at_index(idx)
# Open the editor on the new item to rename it # Open the editor on the new item to rename it
self.tags_view.edit(idx) if new_category_name is None:
self.tags_view.edit(idx)
def do_user_categories_edit(self, on_category=None): def do_edit_user_categories(self, on_category=None):
'''
Open the user categories editor.
'''
db = self.library_view.model().db db = self.library_view.model().db
d = TagCategories(self, db, on_category) d = TagCategories(self, db, on_category)
if d.exec_() == d.Accepted: if d.exec_() == d.Accepted:
@ -1615,7 +1642,7 @@ class TagBrowserMixin(object): # {{{
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()
def do_user_category_delete(self, category_name): def do_delete_user_category(self, category_name):
''' '''
Delete the user category named category_name. Any leading '@' is removed Delete the user category named category_name. Any leading '@' is removed
''' '''
@ -1648,7 +1675,55 @@ class TagBrowserMixin(object): # {{{
db.prefs.set('user_categories', user_cats) db.prefs.set('user_categories', user_cats)
self.tags_view.set_new_model() self.tags_view.set_new_model()
def do_del_item_from_user_cat(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
self.tags_view.model().delete_item_from_user_category(user_cat,
item_name, item_category)
self.tags_view.recount()
def do_add_item_to_user_cat(self, dest_category, src_name, src_category):
'''
Add the item src_name in src_category to the user category
dest_category. Any leading '@' is removed
'''
db = self.library_view.model().db
user_cats = db.prefs.get('user_categories', {})
if dest_category.startswith('@'):
dest_category = dest_category[1:]
if dest_category not in user_cats:
return error_dialog(self.tags_view, _('Add to user category'),
_('A user category %s does not exist')%dest_category, show=True)
# Now add the item to the destination user category
add_it = True
if src_category == 'news':
src_category = 'tags'
for tup in user_cats[dest_category]:
if src_name == tup[0] and src_category == tup[1]:
add_it = False
if add_it:
user_cats[dest_category].append([src_name, src_category, 0])
db.prefs.set('user_categories', user_cats)
self.tags_view.recount()
def do_tags_list_edit(self, tag, category): def do_tags_list_edit(self, tag, category):
'''
Open the 'manage_X' dialog where X == category. If tag is not None, the
dialog will position the editor on that item.
'''
db=self.library_view.model().db db=self.library_view.model().db
if category == 'tags': if category == 'tags':
result = db.get_tags_with_ids() result = db.get_tags_with_ids()
@ -1716,6 +1791,9 @@ class TagBrowserMixin(object): # {{{
# refreshing the tags view happens at the emit()/call() site # refreshing the tags view happens at the emit()/call() site
def do_author_sort_edit(self, parent, id): def do_author_sort_edit(self, parent, id):
'''
Open the manage authors dialog
'''
db = self.library_view.model().db db = self.library_view.model().db
editor = EditAuthorsDialog(parent, db, id) editor = EditAuthorsDialog(parent, db, id)
d = editor.exec_() d = editor.exec_()