diff --git a/src/calibre/gui2/actions/column_tooltips.py b/src/calibre/gui2/actions/column_tooltips.py index fb76442958..d612bb06b4 100644 --- a/src/calibre/gui2/actions/column_tooltips.py +++ b/src/calibre/gui2/actions/column_tooltips.py @@ -2,9 +2,12 @@ # License: GPLv3 Copyright: 2022, Charles Haley # +from qt.core import Qt, QDialogButtonBox, QVBoxLayout + from calibre.gui2 import error_dialog from calibre.gui2.actions import InterfaceAction from calibre.gui2.dialogs.template_dialog import TemplateDialog +from calibre.gui2.widgets2 import Dialog, HTMLDisplay def column_template_placeholder_text(): @@ -12,37 +15,84 @@ def column_template_placeholder_text(): 'Notes:\n' '• The template global variable "{0}" contains the column lookup name.\n' '• The global variable "{1}" contains the original tooltip text').format('column_lookup_name', - 'original_text') +class ToolTipDialog(Dialog): + + def __init__(self, title, prefs): + super().__init__(title, 'show_tooltip_dialog', + prefs = prefs, + default_buttons=QDialogButtonBox.StandardButton.Ok) + + def setup_ui(self): + l = QVBoxLayout(self) + d = self.display = HTMLDisplay() + l.addWidget(d) + l.addWidget(self.bb) + + def set_html(self, tt_text): + self.display.setHtml(tt_text) + + class ColumnTooltipsAction(InterfaceAction): name = 'Column tooltips' action_spec = (_('Column tooltips'), 'edit_input.png', _('Define a custom tooltip for values in a column'), ()) action_type = 'current' + action_add_menu = True + action_menu_clone_qaction = _('Edit/define column tooltip') dont_add_to = frozenset(('context-menu-device', 'menubar-device')) def genesis(self): self.qaction.triggered.connect(self.show_template_editor) + m = self.qaction.menu() + ac = self.create_menu_action(m, 'tooltip_in_dialog_box', _('Show item tooltip in a dialog'), + icon='dialog_information.png', triggered=self.show_tooltip_in_dialog, shortcut=None) + m.addAction(ac) - def show_template_editor(self): + def check_errors(self, only_one_row=False): view = self.gui.current_view() if view is not self.gui.library_view: - return error_dialog(self.gui, _('No template tester available'), - _('Template tester is not available for books ' - 'on the device.')).exec() - + error_dialog(self.gui, _('No library view available'), + _("You can't set custom tooltips for books on the device.")).exec() + return (None, None, None, None) idx = view.currentIndex() if not idx.isValid(): - return error_dialog(self.gui, _('No column selected'), + error_dialog(self.gui, _('No column selected'), _('A column (cell) must be selected'), show=True) + return (None, None, None, None) column = view.model().column_map[idx.column()] rows = view.selectionModel().selectedRows() if not rows: - return error_dialog(self.gui, _('No books selected'), + error_dialog(self.gui, _('No books selected'), _('At least one book must be selected'), show=True) + return (None, None, None, None) + if only_one_row and len(rows) != 1: + error_dialog(self.gui, _('Only one book'), + _('Only one book can be selected'), show=True) + return (None, None, None, None) + return view, idx, column, rows + + def show_tooltip_in_dialog(self): + view, idx, column, rows = self.check_errors(only_one_row=True) + if view is None: + return + from calibre.gui2.ui import get_gui + db = get_gui().current_db.new_api + fm = db.field_metadata.get(column) + col_name = fm['name'] + d = ToolTipDialog( + _('Tooltip for column {name}, row {row_num}').format(name=col_name, row_num=rows[0].row()+1), + prefs=db.backend.prefs) + d.set_html(idx.data(Qt.ItemDataRole.ToolTipRole)) + d.exec() + + def show_template_editor(self): + view, _, column, rows = self.check_errors() + if view is None: + return mi = [] db = view.model().db for row in rows: diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index ab4df75713..79fec7bb2f 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -15,7 +15,10 @@ import traceback from collections import defaultdict, namedtuple from itertools import groupby -from qt.core import QAbstractTableModel, QApplication, QColor, QFont, QFontMetrics, QIcon, QImage, QModelIndex, QPainter, QPixmap, Qt, pyqtSignal +from qt.core import ( + QAbstractTableModel, QApplication, QColor, QDateTime, + QFont, QFontMetrics, QIcon, QImage, QLocale, QModelIndex, QPainter, + QPixmap, Qt, pyqtSignal) from calibre import fit_image, human_readable, isbytestring, prepare_string_for_xml, strftime from calibre.constants import DEBUG, config_dir, dark_link_color, filesystem_encoding @@ -1008,14 +1011,29 @@ class BooksModel(QAbstractTableModel): # {{{ def f(idx): try: template = self.db.new_api.pref('column_tooltip_templates', {}).get(key, '') + # Simulate what Qt does to get the text for non-string data + # types so that idx.data(Qt.ItemDataRole.ToolTipRole) + # always returns a string. + orig_obj = orig_tt_func(idx) + match orig_obj: + case None: + v = '' + case str(): + v = orig_obj + case bool(): + v = str(orig_obj) + case int() | float() | QDateTime(): + v = QLocale().toString(orig_obj) + case _: + v = f'unsupported type {type(orig_obj)}' if template: - global_vars = {'column_lookup_name': key, 'original_text': orig_tt_func(idx)} + global_vars = {'column_lookup_name': key, 'original_text': v} mi = self.db.new_api.get_proxy_metadata(self.db.data.index_to_id(idx)) return self.formatter.safe_format( template, {}, _('tooltip template error'), mi, global_vars=global_vars) + return v except Exception as e: return str(e) - return orig_tt_func(idx) return f for f, allow_half in iteritems(rating_fields):