diff --git a/src/calibre/gui2/dialogs/edit_authors_dialog.py b/src/calibre/gui2/dialogs/edit_authors_dialog.py index 752257bc5a..7622961886 100644 --- a/src/calibre/gui2/dialogs/edit_authors_dialog.py +++ b/src/calibre/gui2/dialogs/edit_authors_dialog.py @@ -13,7 +13,8 @@ from calibre.ebooks.metadata import author_to_author_sort, string_to_authors from calibre.gui2 import error_dialog, gprefs from calibre.gui2.dialogs.edit_authors_dialog_ui import Ui_EditAuthorsDialog from calibre.utils.config import prefs -from calibre.utils.icu import sort_key, primary_contains, contains +from calibre.utils.config_base import tweaks +from calibre.utils.icu import sort_key, primary_contains, contains, primary_startswith from polyglot.builtins import unicode_type QT_HIDDEN_CLEAR_ACTION = '_q_qlineeditclearaction' @@ -50,7 +51,8 @@ class EditColumnDelegate(QItemDelegate): class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog): - def __init__(self, parent, db, id_to_select, select_sort, select_link, find_aut_func): + def __init__(self, parent, db, id_to_select, select_sort, select_link, + find_aut_func, is_first_letter=False): QDialog.__init__(self, parent) Ui_EditAuthorsDialog.__init__(self) self.setupUi(self) @@ -153,19 +155,19 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog): self.author_order = 1 self.author_sort_order = 0 self.link_order = 1 - self.show_table(id_to_select, select_sort, select_link) + self.show_table(id_to_select, select_sort, select_link, is_first_letter) def use_vl_changed(self, x): - self.show_table(None, None, None) + self.show_table(None, None, None, False) def clear_filter(self): self.filter_box.setText('') - self.show_table(None, None, None) + self.show_table(None, None, None, False) def do_filter(self): - self.show_table(None, None, None) + self.show_table(None, None, None, False) - def show_table(self, id_to_select, select_sort, select_link): + def show_table(self, id_to_select, select_sort, select_link, is_first_letter): filter_text = icu_lower(unicode_type(self.filter_box.text())) auts_to_show = [] for t in self.find_aut_func(use_virtual_library=self.apply_vl_checkbox.isChecked()): @@ -176,7 +178,6 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog): self.table.setColumnCount(3) self.table.setRowCount(len(auts_to_show)) - select_item = None row = 0 for id_, v in self.authors.items(): if id_ not in auts_to_show: @@ -198,14 +199,6 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog): self.table.setItem(row, 0, name_item) self.table.setItem(row, 1, sort_item) self.table.setItem(row, 2, link_item) - - if id_to_select and id_to_select in (id_, name): - if select_sort: - select_item = sort_item - elif select_link: - select_item = link_item - else: - select_item = name_item row += 1 self.table.setItemDelegate(EditColumnDelegate(self.completion_data)) @@ -222,10 +215,28 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog): self.do_sort_by_link() # Position on the desired item - if select_item is not None: - self.table.setCurrentItem(select_item) - self.table.editItem(select_item) - self.start_find_pos = select_item.row() * 2 + select_item.column() + if id_to_select: + select_item = None + use_as = tweaks['categories_use_field_for_author_name'] + for row in range(0, len(auts_to_show)): + name_item = self.table.item(row, 1) if use_as else self.table.item(row, 0) + if is_first_letter: + if primary_startswith(name_item.text(), id_to_select): + select_item = self.table.item(row, 1) + break + elif id_to_select == self.table.item(row, 0).data(Qt.UserRole): + if select_sort: + select_item = self.table.item(row, 1) + elif select_link: + select_item = self.table.item(row, 2) + else: + select_item = name_item + break + if select_item: + self.table.setCurrentItem(select_item) + if select_sort or select_link: + self.table.editItem(select_item) + self.start_find_pos = select_item.row() * 2 + select_item.column() else: self.table.setCurrentCell(0, 0) self.start_find_pos = -1 diff --git a/src/calibre/gui2/dialogs/tag_list_editor.py b/src/calibre/gui2/dialogs/tag_list_editor.py index e034bd2b88..de5192781a 100644 --- a/src/calibre/gui2/dialogs/tag_list_editor.py +++ b/src/calibre/gui2/dialogs/tag_list_editor.py @@ -13,7 +13,7 @@ from calibre.gui2.dialogs.confirm_delete import confirm from calibre.gui2.widgets import EnLineEdit from calibre.gui2 import question_dialog, error_dialog, gprefs from calibre.utils.config import prefs -from calibre.utils.icu import sort_key, contains, primary_contains +from calibre.utils.icu import sort_key, contains, primary_contains, primary_startswith from polyglot.builtins import unicode_type QT_HIDDEN_CLEAR_ACTION = '_q_qlineeditclearaction' @@ -132,7 +132,8 @@ class EditColumnDelegate(QItemDelegate): class TagListEditor(QDialog, Ui_TagListEditor): - def __init__(self, window, cat_name, tag_to_match, get_book_ids, sorter): + def __init__(self, window, cat_name, tag_to_match, get_book_ids, sorter, + ttm_is_first_letter=False): QDialog.__init__(self, window) Ui_TagListEditor.__init__(self) self.setupUi(self) @@ -188,6 +189,7 @@ class TagListEditor(QDialog, Ui_TagListEditor): self.string_contains = contains self.delete_button.clicked.connect(self.delete_tags) + self.table.delete_pressed.connect(self.delete_pressed) self.rename_button.clicked.connect(self.rename_tag) self.undo_button.clicked.connect(self.undo_edit) self.table.itemDoubleClicked.connect(self._rename_tag) @@ -242,11 +244,11 @@ class TagListEditor(QDialog, Ui_TagListEditor): pass # Add the data self.search_item_row = -1 - self.fill_in_table(None, tag_to_match) + self.fill_in_table(None, tag_to_match, ttm_is_first_letter) def vl_box_changed(self): self.search_item_row = -1 - self.fill_in_table(None, None) + self.fill_in_table(None, None, False) def do_search(self): self.not_found_label.setVisible(False) @@ -271,7 +273,7 @@ class TagListEditor(QDialog, Ui_TagListEditor): self.search_item_row = -1 self.search_box.setText('') - def fill_in_table(self, tags, tag_to_match): + def fill_in_table(self, tags, tag_to_match, ttm_is_first_letter): data = self.get_book_ids(self.apply_vl_checkbox.isChecked()) self.all_tags = {} filter_text = icu_lower(unicode_type(self.filter_box.text())) @@ -310,8 +312,12 @@ class TagListEditor(QDialog, Ui_TagListEditor): item.setText(tag) item.setFlags(item.flags() | Qt.ItemIsSelectable | Qt.ItemIsEditable) self.table.setItem(row, 0, item) - if tag == tag_to_match: - select_item = item + if select_item is None: + if ttm_is_first_letter: + if primary_startswith(tag, tag_to_match): + select_item = item + elif tag == tag_to_match: + select_item = item item = CountTableWidgetItem(self.all_tags[tag]['count']) # only the name column can be selected item.setFlags(item.flags() & ~(Qt.ItemIsSelectable|Qt.ItemIsEditable)) @@ -343,10 +349,10 @@ class TagListEditor(QDialog, Ui_TagListEditor): def clear_filter(self): self.filter_box.setText('') - self.fill_in_table(None, None) + self.fill_in_table(None, None, False) def do_filter(self): - self.fill_in_table(None, None) + self.fill_in_table(None, None, False) def table_column_resized(self, col, old, new): self.table_column_widths = [] @@ -452,6 +458,10 @@ class TagListEditor(QDialog, Ui_TagListEditor): else: self.table.editItem(item) + def delete_pressed(self): + if self.table.currentColumn() == 0: + self.delete_tags() + def delete_tags(self): deletes = self.table.selectedItems() if not deletes: @@ -460,41 +470,26 @@ class TagListEditor(QDialog, Ui_TagListEditor): return to_del = [] - to_undel = [] for item in deletes: - if item.is_deleted: - to_undel.append(item) - else: + if not item.is_deleted: to_del.append(item) + if to_del: ct = ', '.join([unicode_type(item.text()) for item in to_del]) if not confirm( '

'+_('Are you sure you want to delete the following items?')+'
'+ct, 'tag_list_editor_delete'): return - if to_undel: - ct = ', '.join([unicode_type(item.text()) for item in to_undel]) - if not confirm( - '

'+_('Are you sure you want to undelete the following items?')+'
'+ct, - 'tag_list_editor_undelete'): - return + row = self.table.row(deletes[0]) + self.table.blockSignals(True) for item in deletes: - if item.is_deleted: - item.set_is_deleted(False) - self.to_delete.discard(int(item.data(Qt.UserRole))) - orig = self.table.item(item.row(), 2) - self.table.blockSignals(True) - orig.setData(Qt.DisplayRole, '') - self.table.blockSignals(False) - else: - id = int(item.data(Qt.UserRole)) - self.to_delete.add(id) - item.set_is_deleted(True) - orig = self.table.item(item.row(), 2) - self.table.blockSignals(True) - orig.setData(Qt.DisplayRole, item.initial_text()) - self.table.blockSignals(False) + id_ = int(item.data(Qt.UserRole)) + self.to_delete.add(id_) + item.set_is_deleted(True) + orig = self.table.item(item.row(), 2) + orig.setData(Qt.DisplayRole, item.initial_text()) + self.table.blockSignals(False) if row >= self.table.rowCount(): row = self.table.rowCount() - 1 if row >= 0: diff --git a/src/calibre/gui2/dialogs/tag_list_editor.ui b/src/calibre/gui2/dialogs/tag_list_editor.ui index 031e0e2d39..a0373d32c6 100644 --- a/src/calibre/gui2/dialogs/tag_list_editor.ui +++ b/src/calibre/gui2/dialogs/tag_list_editor.ui @@ -197,7 +197,7 @@ - + true @@ -224,6 +224,12 @@ QLineEdit

calibre/gui2/widgets.h
+ + TleTableWidget + QTableWidget +
calibre/gui2/dialogs/tag_list_editor_table_widget.h
+ 1 +
diff --git a/src/calibre/gui2/dialogs/tag_list_editor_table_widget.py b/src/calibre/gui2/dialogs/tag_list_editor_table_widget.py new file mode 100644 index 0000000000..c357c950e7 --- /dev/null +++ b/src/calibre/gui2/dialogs/tag_list_editor_table_widget.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python2 +# vim:fileencoding=utf-8 +# License: GPLv3 Copyright: 2008, Kovid Goyal +from __future__ import absolute_import, division, print_function, unicode_literals + +from PyQt5.Qt import (Qt, QTableWidget, pyqtSignal) + + +class TleTableWidget(QTableWidget): + + delete_pressed = pyqtSignal() + + def __init__(self, parent=None): + QTableWidget.__init__(self, parent=parent) + + def keyPressEvent(self, event): + if event.key() == Qt.Key_Delete: + self.delete_pressed.emit() + event.accept() + return + return QTableWidget.keyPressEvent(self, event) diff --git a/src/calibre/gui2/tag_browser/ui.py b/src/calibre/gui2/tag_browser/ui.py index 16d0385a44..991482dc35 100644 --- a/src/calibre/gui2/tag_browser/ui.py +++ b/src/calibre/gui2/tag_browser/ui.py @@ -240,7 +240,7 @@ class TagBrowserMixin(object): # {{{ result = None return result - def do_tags_list_edit(self, tag, category): + def do_tags_list_edit(self, tag, category, is_first_letter=False): ''' Open the 'manage_X' dialog where X == category. If tag is not None, the dialog will position the editor on that item. @@ -255,7 +255,7 @@ class TagBrowserMixin(object): # {{{ d = TagListEditor(self, cat_name=db.field_metadata[category]['name'], tag_to_match=tag, get_book_ids=partial(self.get_book_ids, db=db, category=category), - sorter=key) + sorter=key, ttm_is_first_letter=is_first_letter) d.exec_() if d.result() == d.Accepted: to_rename = d.to_rename # dict of old id to new name @@ -356,14 +356,16 @@ class TagBrowserMixin(object): # {{{ self.library_view.select_rows(ids) # refreshing the tags view happens at the emit()/call() site - def do_author_sort_edit(self, parent, id_, select_sort=True, select_link=False): + def do_author_sort_edit(self, parent, id_, select_sort=True, + select_link=False, is_first_letter=False): ''' Open the manage authors dialog ''' db = self.library_view.model().db editor = EditAuthorsDialog(parent, db, id_, select_sort, select_link, - partial(self.get_book_ids, db=db, category='authors')) + partial(self.get_book_ids, db=db, category='authors'), + is_first_letter) if editor.exec_() == editor.Accepted: # Save and restore the current selections. Note that some changes # will cause sort orders to change, so don't bother with attempting diff --git a/src/calibre/gui2/tag_browser/view.py b/src/calibre/gui2/tag_browser/view.py index 66eccb2db1..11bbd3d1a6 100644 --- a/src/calibre/gui2/tag_browser/view.py +++ b/src/calibre/gui2/tag_browser/view.py @@ -145,10 +145,10 @@ class TagsView(QTreeView): # {{{ del_item_from_user_cat = pyqtSignal(object, object, object) add_item_to_user_cat = pyqtSignal(object, object, object) add_subcategory = pyqtSignal(object) - tags_list_edit = pyqtSignal(object, object) + tags_list_edit = pyqtSignal(object, object, object) saved_search_edit = pyqtSignal(object) rebuild_saved_searches = pyqtSignal() - author_sort_edit = pyqtSignal(object, object, object, object) + author_sort_edit = pyqtSignal(object, object, object, object, object) tag_item_renamed = pyqtSignal() search_item_renamed = pyqtSignal() drag_drop_finished = pyqtSignal(object) @@ -390,7 +390,7 @@ class TagsView(QTreeView): # {{{ def context_menu_handler(self, action=None, category=None, key=None, index=None, search_state=None, - use_vl=None): + use_vl=None, is_first_letter=False): if not action: return try: @@ -447,7 +447,7 @@ class TagsView(QTreeView): # {{{ self.tag_item_delete.emit(key, index.id, index.original_name, None) return if action == 'open_editor': - self.tags_list_edit.emit(category, key) + self.tags_list_edit.emit(category, key, is_first_letter) return if action == 'manage_categories': self.edit_user_category.emit(category) @@ -492,11 +492,14 @@ class TagsView(QTreeView): # {{{ if action == 'manage_searches': self.saved_search_edit.emit(category) return + if action == 'edit_authors': + self.author_sort_edit.emit(self, index, False, False, is_first_letter) + return if action == 'edit_author_sort': - self.author_sort_edit.emit(self, index, True, False) + self.author_sort_edit.emit(self, index, True, False, is_first_letter) return if action == 'edit_author_link': - self.author_sort_edit.emit(self, index, False, True) + self.author_sort_edit.emit(self, index, False, True, False) return reset_filter_categories = True @@ -557,9 +560,9 @@ class TagsView(QTreeView): # {{{ if index.isValid(): item = index.data(Qt.UserRole) tag = None + tag_item = item if item.type == TagTreeItem.TAG: - tag_item = item tag = item.tag while item.type != TagTreeItem.CATEGORY: item = item.parent @@ -726,13 +729,29 @@ class TagsView(QTreeView): # {{{ self.context_menu.addSeparator() if key in ['tags', 'publisher', 'series'] or ( self.db.field_metadata[key]['is_custom'] and self.db.field_metadata[key]['datatype'] != 'composite'): - self.context_menu.addAction(_('Manage %s')%category, + if tag_item.type == TagTreeItem.CATEGORY and tag_item.temporary: + self.context_menu.addAction(_('Manage %s')%category, + partial(self.context_menu_handler, action='open_editor', + category=tag_item.name, + key=key, is_first_letter=True)) + else: + self.context_menu.addAction(_('Manage %s')%category, partial(self.context_menu_handler, action='open_editor', category=tag.original_name if tag else None, key=key)) elif key == 'authors': - self.context_menu.addAction(_('Manage %s')%category, - partial(self.context_menu_handler, action='edit_author_sort')) + if tag_item.type == TagTreeItem.CATEGORY: + if tag_item.temporary: + self.context_menu.addAction(_('Manage %s')%category, + partial(self.context_menu_handler, action='edit_authors', + index=tag_item.name, is_first_letter=True)) + else: + self.context_menu.addAction(_('Manage %s')%category, + partial(self.context_menu_handler, action='edit_authors')) + else: + self.context_menu.addAction(_('Manage %s')%category, + partial(self.context_menu_handler, action='edit_authors', + index=tag.id)) elif key == 'search': self.context_menu.addAction(_('Manage Saved searches'), partial(self.context_menu_handler, action='manage_searches',