From 55c0f6f289be93c3861d47f331277e88399e8c61 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Thu, 3 Jun 2010 10:58:21 +0100 Subject: [PATCH] 1) Add 'managers' for series and publisher. 2) Option for manager now appears only if the right-click is on/in that category 3) Avoid the cleanup/repaints if no work was done --- src/calibre/gui2/dialogs/tag_list_editor.py | 86 +++++++++++++-------- src/calibre/gui2/dialogs/tag_list_editor.ui | 8 +- src/calibre/gui2/tag_view.py | 30 +++++-- src/calibre/gui2/ui.py | 9 ++- src/calibre/library/database2.py | 55 ++++++++++--- 5 files changed, 132 insertions(+), 56 deletions(-) diff --git a/src/calibre/gui2/dialogs/tag_list_editor.py b/src/calibre/gui2/dialogs/tag_list_editor.py index bccd0deee9..7ee616fe1b 100644 --- a/src/calibre/gui2/dialogs/tag_list_editor.py +++ b/src/calibre/gui2/dialogs/tag_list_editor.py @@ -6,12 +6,11 @@ from PyQt4.QtGui import QDialog, QListWidgetItem from calibre.gui2.dialogs.tag_list_editor_ui import Ui_TagListEditor from calibre.gui2 import question_dialog, error_dialog +from calibre.ebooks.metadata import title_sort + class TagListEditor(QDialog, Ui_TagListEditor): - def tag_cmp(self, x, y): - return cmp(x.lower(), y.lower()) - - def __init__(self, window, db, tag_to_match): + def __init__(self, window, db, tag_to_match, category): QDialog.__init__(self, window) Ui_TagListEditor.__init__(self) self.setupUi(self) @@ -20,9 +19,20 @@ class TagListEditor(QDialog, Ui_TagListEditor): self.to_delete = [] self.db = db self.all_tags = {} - for k,v in db.get_tags_with_ids(): + self.category = category + if category == 'tags': + result = db.get_tags_with_ids() + compare = (lambda x,y:cmp(x.lower(), y.lower())) + elif category == 'series': + result = db.get_series_with_ids() + compare = (lambda x,y:cmp(title_sort(x).lower(), title_sort(y).lower())) + elif category == 'publishers': + result = db.get_publishers_with_ids() + compare = (lambda x,y:cmp(x.lower(), y.lower())) + + for k,v in result: self.all_tags[v] = k - for tag in sorted(self.all_tags.keys(), cmp=self.tag_cmp): + for tag in sorted(self.all_tags.keys(), cmp=compare): item = QListWidgetItem(tag) item.setData(Qt.UserRole, self.all_tags[tag]) self.available_tags.addItem(item) @@ -38,17 +48,17 @@ class TagListEditor(QDialog, Ui_TagListEditor): def finish_editing(self, item): if not item.text(): - error_dialog(self, 'Tag is blank', - 'A tag cannot be set to nothing. Delete it instead.'%(item.text())).exec_() + error_dialog(self, 'Item is blank', + 'An item cannot be set to nothing. Delete it instead.'%(item.text())).exec_() item.setText(self.item_before_editing.text()) return if item.text() != self.item_before_editing.text(): if item.text() in self.all_tags.keys() or item.text() in self.to_rename.keys(): - error_dialog(self, 'Tag already used', - 'The tag %s is already used.'%(item.text())).exec_() + error_dialog(self, 'Item already used', + 'The item %s is already used.'%(item.text())).exec_() item.setText(self.item_before_editing.text()) return - (id,_) = self.item_before_editing.data(Qt.UserRole).toInt() + (id,ign) = self.item_before_editing.data(Qt.UserRole).toInt() self.to_rename[item.text()] = id def rename_tag(self): @@ -57,39 +67,49 @@ class TagListEditor(QDialog, Ui_TagListEditor): def _rename_tag(self, item): if item is None: - error_dialog(self, 'No tag selected', 'You must select one tag from the list of Available tags.').exec_() + error_dialog(self, 'No item selected', 'You must select one item from the list of Available items.').exec_() return self.item_before_editing = item.clone() item.setFlags (item.flags() | Qt.ItemIsEditable); self.available_tags.editItem(item) def delete_tags(self, item=None): - confirms, deletes = [], [] - items = self.available_tags.selectedItems() if item is None else [item] - if not items: - error_dialog(self, 'No tags selected', 'You must select at least one tag from the list of Available tags.').exec_() + deletes = self.available_tags.selectedItems() if item is None else [item] + if not deletes: + error_dialog(self, 'No items selected', 'You must select at least one items from the list.').exec_() + return + ct = ', '.join([unicode(item.text()) for item in deletes]) + if not question_dialog(self, _('Are your sure?'), + '

'+_('Are you certain you want to delete the following items?')+'
'+ct): return - for item in items: - if self.db.is_tag_used(unicode(item.text())): - confirms.append(item) - else: - deletes.append(item) - if confirms: - ct = ', '.join([unicode(item.text()) for item in confirms]) - if question_dialog(self, _('Are your sure?'), - '

'+_('The following tags are used by one or more books. ' - 'Are you certain you want to delete them?')+'
'+ct): - deletes += confirms for item in deletes: - (id,_) = item.data(Qt.UserRole).toInt() + (id,ign) = item.data(Qt.UserRole).toInt() self.to_delete.append(id) self.available_tags.takeItem(self.available_tags.row(item)) def accept(self): - for text in self.to_rename: - self.db.rename_tag(id=self.to_rename[text], new_name=unicode(text)) - for item in self.to_delete: - self.db.delete_tag_using_id(item) - QDialog.accept(self) + rename_func = None + if self.category == 'tags': + rename_func = self.db.rename_tag + delete_func = self.db.delete_tag_using_id + elif self.category == 'series': + rename_func = self.db.rename_series + delete_func = self.db.delete_series_using_id + elif self.category == 'publishers': + rename_func = self.db.rename_publisher + delete_func = self.db.delete_publisher_using_id + + work_done = False + if rename_func: + for text in self.to_rename: + work_done = True + rename_func(id=self.to_rename[text], new_name=unicode(text)) + for item in self.to_delete: + work_done = True + delete_func(item) + if not work_done: + QDialog.reject(self) + else: + QDialog.accept(self) diff --git a/src/calibre/gui2/dialogs/tag_list_editor.ui b/src/calibre/gui2/dialogs/tag_list_editor.ui index 383dc875ac..4f57af745b 100644 --- a/src/calibre/gui2/dialogs/tag_list_editor.ui +++ b/src/calibre/gui2/dialogs/tag_list_editor.ui @@ -11,7 +11,7 @@ - Tag Editor + Category Editor @@ -25,7 +25,7 @@ - Tags in use + Items in use available_tags @@ -54,7 +54,7 @@ - Delete tag from database. This will unapply the tag from all books and then remove it from the database. + Delete item from database. This will unapply the item from all books and then remove it from the database. ... @@ -74,7 +74,7 @@ - Rename the tag everywhere it is used. + Rename the item in every book where it is used. ... diff --git a/src/calibre/gui2/tag_view.py b/src/calibre/gui2/tag_view.py index 11db157ed4..fd232bb750 100644 --- a/src/calibre/gui2/tag_view.py +++ b/src/calibre/gui2/tag_view.py @@ -24,7 +24,7 @@ class TagsView(QTreeView): # {{{ restriction_set = pyqtSignal(object) tags_marked = pyqtSignal(object, object) user_category_edit = pyqtSignal(object) - tag_list_edit = pyqtSignal(object) + tag_list_edit = pyqtSignal(object, object) saved_search_edit = pyqtSignal(object) def __init__(self, *args): @@ -91,7 +91,13 @@ class TagsView(QTreeView): # {{{ return try: if action == 'manage_tags': - self.tag_list_edit.emit(category) + self.tag_list_edit.emit(category, 'tags') + return + if action == 'manage_series': + self.tag_list_edit.emit(category, 'series') + return + if action == 'manage_publishers': + self.tag_list_edit.emit(category, 'publishers') return if action == 'manage_categories': self.user_category_edit.emit(category) @@ -136,10 +142,24 @@ class TagsView(QTreeView): # {{{ partial(self.context_menu_handler, action='defaults')) self.context_menu.addSeparator() - self.context_menu.addAction(_('Manage Tags'), + if category == _('Tags'): + self.context_menu.addAction(_('Manage Tags'), partial(self.context_menu_handler, action='manage_tags', category=tag_name)) + elif category == _('Searches'): + self.context_menu.addAction(_('Manage Saved Searches'), + partial(self.context_menu_handler, action='manage_searches', + category=tag_name)) + elif category == _('Publishers'): + self.context_menu.addAction(_('Manage Publishers'), + partial(self.context_menu_handler, action='manage_publishers', + category=tag_name)) + elif category == _('Series'): + self.context_menu.addAction(_('Manage Series'), + partial(self.context_menu_handler, action='manage_series', + category=tag_name)) + self.context_menu.addSeparator() if category in prefs['user_categories'].keys(): self.context_menu.addAction(_('Manage User Categories'), partial(self.context_menu_handler, action='manage_categories', @@ -149,10 +169,6 @@ class TagsView(QTreeView): # {{{ partial(self.context_menu_handler, action='manage_categories', category=None)) - self.context_menu.addAction(_('Manage Saved Searches'), - partial(self.context_menu_handler, action='manage_searches', - category=tag_name)) - self.context_menu.popup(self.mapToGlobal(point)) return True diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index 773f44acd2..63172fc7a5 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -660,13 +660,16 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): self.tags_view.set_new_model() self.tags_view.recount() - def do_tags_list_edit(self, tag): - d = TagListEditor(self, self.library_view.model().db, tag) + def do_tags_list_edit(self, tag, category): + d = TagListEditor(self, self.library_view.model().db, tag, category) d.exec_() if d.result() == d.Accepted: + # Clean up everything, as information could have changed for many books. + self.library_view.model().refresh() self.tags_view.set_new_model() self.tags_view.recount() - self.library_view.model().refresh() + self.saved_search.clear_to_help() + self.search.clear_to_help() def do_saved_search_edit(self, search): d = SavedSearchEditor(self, search) diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index f76ae9c77a..c01d6fd4d6 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -731,8 +731,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): icon=icon, tooltip = tooltip) for r in data if item_not_zero_func(r)] if category == 'series': - categories[category].sort(cmp=lambda x,y:cmp(title_sort(x.name), - title_sort(y.name))) + categories[category].sort(cmp=lambda x,y:cmp(title_sort(x.name).lower(), + title_sort(y.name).lower())) # We delayed computing the standard formats category because it does not # use a view, but is computed dynamically @@ -985,7 +985,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): if notify: self.notify('metadata', [id]) - # Convenience method for tags_list_editor + # Convenience methods for tags_list_editor def get_tags_with_ids(self): result = self.conn.get('SELECT id,name FROM tags') if not result: @@ -996,6 +996,49 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): self.conn.execute('UPDATE tags SET name=? WHERE id=?', (new_name, id)) self.conn.commit() + def delete_tag_using_id(self, id): + if id: + self.conn.execute('DELETE FROM books_tags_link WHERE tag=?', (id,)) + self.conn.execute('DELETE FROM tags WHERE id=?', (id,)) + self.conn.commit() + + def get_series_with_ids(self): + result = self.conn.get('SELECT id,name FROM series') + if not result: + return [] + return result + + def rename_series(self, id, new_name): + self.conn.execute('UPDATE series SET name=? WHERE id=?', (new_name, id)) + self.conn.commit() + + def delete_series_using_id(self, id): + if id: + books = self.conn.get('SELECT book from books_series_link WHERE series=?', (id,)) + for (book_id,) in books: + self.conn.execute('UPDATE books SET series_index=1.0 WHERE id=?', (book_id,)) + self.conn.execute('DELETE FROM books_series_link WHERE series=?', (id,)) + self.conn.execute('DELETE FROM series WHERE id=?', (id,)) + self.conn.commit() + + def get_publishers_with_ids(self): + result = self.conn.get('SELECT id,name FROM publishers') + if not result: + return [] + return result + + def rename_publisher(self, id, new_name): + self.conn.execute('UPDATE publishers SET name=? WHERE id=?', (new_name, id)) + self.conn.commit() + + def delete_publisher_using_id(self, id): + if id: + self.conn.execute('DELETE FROM books_publishers_link WHERE publisher=?', (id,)) + self.conn.execute('DELETE FROM publishers WHERE id=?', (id,)) + self.conn.commit() + + # end convenience methods + def get_tags(self, id): result = self.conn.get( 'SELECT name FROM tags WHERE id IN (SELECT tag FROM books_tags_link WHERE book=?)', @@ -1080,12 +1123,6 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): self.conn.execute('DELETE FROM tags WHERE id=?', (id,)) self.conn.commit() - def delete_tag_using_id(self, id): - if id: - self.conn.execute('DELETE FROM books_tags_link WHERE tag=?', (id,)) - self.conn.execute('DELETE FROM tags WHERE id=?', (id,)) - self.conn.commit() - def set_series(self, id, series, notify=True): self.conn.execute('DELETE FROM books_series_link WHERE book=?',(id,)) self.conn.execute('DELETE FROM series WHERE (SELECT COUNT(id) FROM books_series_link WHERE series=series.id) < 1')