mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Fix sorting by notes column in manage category dialogs
Also remove the notesitemwidget as its performance is unacceptable
This commit is contained in:
parent
b9e24ffb07
commit
823ec12f02
@ -15,7 +15,6 @@ from qt.core import (
|
||||
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.gui2.dialogs.tag_list_editor import NotesItemWidget
|
||||
from calibre.utils.config import prefs
|
||||
from calibre.utils.config_base import tweaks
|
||||
from calibre.utils.icu import (
|
||||
@ -28,9 +27,9 @@ QT_HIDDEN_CLEAR_ACTION = '_q_qlineeditclearaction'
|
||||
|
||||
class tableItem(QTableWidgetItem):
|
||||
|
||||
def __init__(self, txt):
|
||||
def __init__(self, txt, skey=None):
|
||||
QTableWidgetItem.__init__(self, txt)
|
||||
self.sort_key = sort_key(str(txt))
|
||||
self.sort_key = sort_key(str(txt)) if skey is None else skey
|
||||
|
||||
def setText(self, txt):
|
||||
self.sort_key = sort_key(str(txt))
|
||||
@ -177,6 +176,7 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
|
||||
self.author_order = 1
|
||||
self.author_sort_order = 0
|
||||
self.link_order = 1
|
||||
self.notes_order = 1
|
||||
self.show_table(id_to_select, select_sort, select_link, is_first_letter)
|
||||
|
||||
@contextmanager
|
||||
@ -214,6 +214,8 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
|
||||
row = 0
|
||||
from calibre.gui2.ui import get_gui
|
||||
all_items_that_have_notes = get_gui().current_db.new_api.get_all_items_that_have_notes('authors')
|
||||
yes, yes_skey = '✓', sort_key('✓')
|
||||
no, no_skey = '', sort_key('')
|
||||
for id_, v in self.authors.items():
|
||||
if id_ not in auts_to_show:
|
||||
continue
|
||||
@ -228,9 +230,10 @@ 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)
|
||||
|
||||
nw = NotesItemWidget('authors', id_, id_ in all_items_that_have_notes)
|
||||
self.table.setCellWidget(row, 3, nw)
|
||||
if id_ in all_items_that_have_notes:
|
||||
self.table.setItem(row, 3, tableItem(yes, yes_skey))
|
||||
else:
|
||||
self.table.setItem(row, 3, tableItem(no, no_skey))
|
||||
|
||||
self.set_icon(name_item, id_)
|
||||
self.set_icon(sort_item, id_)
|
||||
@ -246,9 +249,12 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
|
||||
elif self.last_sorted_by == 'author':
|
||||
self.author_order = 1 - self.author_order
|
||||
self.do_sort_by_author()
|
||||
else:
|
||||
elif self.last_sorted_by == 'link':
|
||||
self.link_order = 1 - self.link_order
|
||||
self.do_sort_by_link()
|
||||
else:
|
||||
self.notes_order = 1 - self.notes_order
|
||||
self.do_sort_by_notes()
|
||||
|
||||
# Position on the desired item
|
||||
select_item = None
|
||||
@ -443,7 +449,7 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
|
||||
self.not_found_label_timer.start(1500)
|
||||
|
||||
def do_sort(self, section):
|
||||
(self.do_sort_by_author, self.do_sort_by_author_sort, self.do_sort_by_link)[section]()
|
||||
(self.do_sort_by_author, self.do_sort_by_author_sort, self.do_sort_by_link, self.do_sort_by_notes)[section]()
|
||||
|
||||
def do_sort_by_author(self):
|
||||
self.last_sorted_by = 'author'
|
||||
@ -460,6 +466,11 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
|
||||
self.link_order = 1 - self.link_order
|
||||
self.table.sortByColumn(2, Qt.SortOrder(self.link_order))
|
||||
|
||||
def do_sort_by_notes(self):
|
||||
self.last_sorted_by = 'notes'
|
||||
self.notes_order = 1 - self.notes_order
|
||||
self.table.sortByColumn(3, Qt.SortOrder(self.notes_order))
|
||||
|
||||
def accepted(self):
|
||||
self.save_state()
|
||||
self.result = []
|
||||
|
@ -5,16 +5,14 @@
|
||||
from functools import partial
|
||||
from qt.core import (
|
||||
QAbstractItemView, QAction, QApplication, QCheckBox, QColor, QDialog,
|
||||
QDialogButtonBox, QEvent, QFrame, QHBoxLayout, QIcon, QItemDelegate, QLabel, QMenu,
|
||||
QSize, Qt, QTableWidgetItem, QTimer, QToolButton, QWidget, pyqtSignal, sip,
|
||||
QDialogButtonBox, QEvent, QFrame, QIcon, QItemDelegate, QLabel, QMenu,
|
||||
QSize, Qt, QTableWidgetItem, QTimer, QToolButton, pyqtSignal, sip,
|
||||
)
|
||||
|
||||
from calibre import sanitize_file_name
|
||||
from calibre.gui2 import error_dialog, gprefs, question_dialog, choose_files, choose_save_file
|
||||
from calibre.gui2 import error_dialog, gprefs, question_dialog
|
||||
from calibre.gui2.actions.show_quickview import get_quickview_action_plugin
|
||||
from calibre.gui2.complete2 import EditWithComplete
|
||||
from calibre.gui2.dialogs.confirm_delete import confirm
|
||||
from calibre.gui2.dialogs.edit_category_notes import EditNoteDialog
|
||||
from calibre.gui2.dialogs.tag_list_editor_ui import Ui_TagListEditor
|
||||
from calibre.gui2.dialogs.tag_list_editor_table_widget import TleTableWidget
|
||||
from calibre.gui2.widgets import EnLineEdit
|
||||
@ -172,158 +170,6 @@ class MyCheckBox(QCheckBox):
|
||||
self.event = partial(event, me=self, super_class=super(), context_menu_handler=context_menu_handler)
|
||||
|
||||
|
||||
class NotesItemWidget(QWidget):
|
||||
'''
|
||||
This is a self-contained widget for manipulating notes. It can be used in a
|
||||
table (as a cellWidget) or in a layout. It currently contains a check box
|
||||
indicating that the item has a note, and buttons to edit/create or delete a
|
||||
note, or undo a deletion.
|
||||
'''
|
||||
|
||||
edit_icon = QIcon.ic('edit_input.png')
|
||||
delete_icon = QIcon.ic('trash.png')
|
||||
undo_delete_icon = QIcon.ic('edit-undo.png')
|
||||
export_icon = QIcon.ic('forward.png')
|
||||
import_icon = QIcon.ic('back.png')
|
||||
|
||||
@property
|
||||
def db(self):
|
||||
from calibre.gui2.ui import get_gui
|
||||
return get_gui().current_db.new_api
|
||||
|
||||
@property
|
||||
def item_val(self):
|
||||
if self._item_val is None:
|
||||
self._item_val = self.db.get_item_name(self.field, self._item_id)
|
||||
return self._item_val
|
||||
|
||||
@property
|
||||
def item_id(self):
|
||||
if self._item_id is None:
|
||||
self._item_id = self.db.get_item_id(self.field, self._item_val)
|
||||
if self._item_id is None:
|
||||
raise KeyError(f'The value: {self._item_val} is not found in the field: {self.field}')
|
||||
return self._item_id
|
||||
|
||||
def __init__(self, field, item_id_or_val, has_notes):
|
||||
'''
|
||||
:param db: A database instance, either old or new api
|
||||
:param field: the lookup name of a field
|
||||
:param item_id_or_val: Either the numeric item_id of an item in the field or
|
||||
the item's string value
|
||||
'''
|
||||
super().__init__()
|
||||
self.field = field
|
||||
self._item_val = self._item_id = None
|
||||
self.has_notes = has_notes
|
||||
if isinstance(item_id_or_val, str):
|
||||
self._item_val = item_id_or_val
|
||||
else:
|
||||
self._item_id = item_id_or_val
|
||||
self.can_undo = False
|
||||
|
||||
self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
|
||||
|
||||
l = QHBoxLayout()
|
||||
l.setContentsMargins(2, 0, 0, 0)
|
||||
self.setLayout(l)
|
||||
cb = self.cb = MyCheckBox(self.show_context_menu)
|
||||
cb.setEnabled(False)
|
||||
l.addWidget(cb)
|
||||
|
||||
self.buttons = {}
|
||||
for button_data in (('edit', 'Edit or create the note. Changes cannot be undone or cancelled'),
|
||||
('delete', 'Delete the note'),
|
||||
('undo_delete', 'Undo the deletion')):
|
||||
button_name = button_data[0]
|
||||
tool_tip = button_data[1]
|
||||
b = self.buttons[button_name] = MyToolButton(self.show_context_menu)
|
||||
b.setIcon(getattr(self, button_name + '_icon'))
|
||||
b.setToolTip(tool_tip)
|
||||
b.clicked.connect(getattr(self, 'do_' + button_name))
|
||||
b.setContentsMargins(0, 0, 0, 0)
|
||||
l.addWidget(b)
|
||||
l.addStretch(3)
|
||||
|
||||
self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
|
||||
self.set_checked(refresh=False)
|
||||
self.customContextMenuRequested.connect(self.show_context_menu)
|
||||
|
||||
@classmethod
|
||||
def get_item_id(cls, db, field: str, value: str):
|
||||
return db.new_api.get_item_id(field, value)
|
||||
|
||||
def show_context_menu(self, point):
|
||||
m = QMenu()
|
||||
ac = m.addAction(self.edit_icon, _('Edit note') if self.cb.isChecked() else _('Create note'))
|
||||
ac.triggered.connect(self.do_edit)
|
||||
|
||||
ac = m.addAction(self.delete_icon, _('Delete note'))
|
||||
ac.setEnabled(self.cb.isChecked())
|
||||
ac.triggered.connect(self.do_delete)
|
||||
|
||||
ac = m.addAction(self.undo_delete_icon, _('Undo delete'))
|
||||
ac.setEnabled(self.can_undo)
|
||||
ac.triggered.connect(self.do_undo_delete)
|
||||
|
||||
ac = m.addAction(self.export_icon, _('Export note to a file'))
|
||||
ac.setEnabled(self.cb.isChecked())
|
||||
ac.triggered.connect(self.do_export)
|
||||
|
||||
ac = m.addAction(self.import_icon, _('Import note from a file'))
|
||||
ac.setEnabled(not self.cb.isChecked())
|
||||
ac.triggered.connect(self.do_import)
|
||||
|
||||
m.exec(self.mapToGlobal(point))
|
||||
|
||||
def do_edit(self):
|
||||
accepted = EditNoteDialog(self.field, self.item_id, self.db).exec()
|
||||
# Continue to allow an undo if it was allowed before and the dialog was cancelled.
|
||||
self.can_undo = not accepted and self.can_undo
|
||||
self.set_checked()
|
||||
|
||||
def do_delete(self):
|
||||
self.db.set_notes_for(self.field, self.item_id, '')
|
||||
self.can_undo = True
|
||||
self.set_checked()
|
||||
|
||||
def do_undo_delete(self):
|
||||
if self.can_undo:
|
||||
self.db.unretire_note_for(self.field, self.item_id)
|
||||
self.can_undo = False
|
||||
self.set_checked()
|
||||
|
||||
def do_export(self):
|
||||
dest = choose_save_file(self, 'save-exported-note', _('Export note to a file'),
|
||||
filters=[(_('HTML files'), ['html'])],
|
||||
initial_filename=f'{sanitize_file_name(self.item_val)}.html',
|
||||
all_files=False)
|
||||
if dest:
|
||||
html = self.db.export_note(self.field, self.item_id)
|
||||
with open(dest, 'wb') as f:
|
||||
f.write(html.encode('utf-8'))
|
||||
|
||||
def do_import(self):
|
||||
src = choose_files(self, 'load-imported-note', _('Import note from a file'),
|
||||
filters=[(_('HTML files'), ['html'])],
|
||||
all_files=False, select_only_single_file=True)
|
||||
if src:
|
||||
self.db.import_note(self.field, self.item_id, src[0])
|
||||
self.can_undo = False
|
||||
self.set_checked()
|
||||
|
||||
def set_checked(self, refresh=True):
|
||||
if refresh:
|
||||
self.has_notes = bool(self.db.notes_for(self.field, self.item_id))
|
||||
self.cb.setChecked(self.has_notes)
|
||||
self.buttons['delete'].setEnabled(self.has_notes)
|
||||
self.buttons['undo_delete'].setEnabled(self.can_undo)
|
||||
|
||||
def is_checked(self):
|
||||
# returns True if the checkbox is checked, meaning the note contains text
|
||||
return self.cb.isChecked()
|
||||
|
||||
|
||||
class TagListEditor(QDialog, Ui_TagListEditor):
|
||||
|
||||
VALUE_COLUMN = 0
|
||||
@ -361,9 +207,9 @@ class TagListEditor(QDialog, Ui_TagListEditor):
|
||||
self.get_book_ids = get_book_ids
|
||||
self.text_before_editing = ''
|
||||
|
||||
self.sort_names = ('name', 'count', 'was', 'link')
|
||||
self.sort_names = ('name', 'count', 'was', 'link', 'notes')
|
||||
self.last_sorted_by = 'name'
|
||||
self.name_order = self.count_order = self.was_order = self.link_order = 0
|
||||
self.name_order = self.count_order = self.was_order = self.link_order = self.notes_order = 0
|
||||
|
||||
if prefs['case_sensitive']:
|
||||
self.string_contains = contains
|
||||
@ -644,6 +490,7 @@ class TagListEditor(QDialog, Ui_TagListEditor):
|
||||
self.table.setHorizontalHeaderItem(4, self.link_col)
|
||||
|
||||
self.table.setRowCount(len(tags))
|
||||
if self.category is not None:
|
||||
from calibre.gui2.ui import get_gui
|
||||
all_items_that_have_notes = get_gui().current_db.new_api.get_all_items_that_have_notes(self.category)
|
||||
for row,tag in enumerate(tags):
|
||||
@ -697,8 +544,7 @@ class TagListEditor(QDialog, Ui_TagListEditor):
|
||||
self.table.setItem(row, self.LINK_COLUMN, item)
|
||||
|
||||
if self.category is not None:
|
||||
nw = NotesItemWidget(self.category, _id, _id in all_items_that_have_notes)
|
||||
self.table.setCellWidget(row, 4, nw)
|
||||
self.table.setItem(row, self.NOTES_COLUMN, QTableWidgetItem('✓' if _id in all_items_that_have_notes else ''))
|
||||
|
||||
# re-sort the table
|
||||
column = self.sort_names.index(self.last_sorted_by)
|
||||
|
Loading…
x
Reference in New Issue
Block a user