From 593e0f45c7661d48b0f239670d19f6544a207399 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Wed, 20 Nov 2024 14:20:29 +0000 Subject: [PATCH] Add internal link handling to the HTML shown in the template tester and the documentation viewer. --- src/calibre/gui2/dialogs/template_dialog.py | 53 +++++++++++++++++++-- src/calibre/gui2/dialogs/template_dialog.ui | 3 -- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/src/calibre/gui2/dialogs/template_dialog.py b/src/calibre/gui2/dialogs/template_dialog.py index 2367b77cfd..6549fea680 100644 --- a/src/calibre/gui2/dialogs/template_dialog.py +++ b/src/calibre/gui2/dialogs/template_dialog.py @@ -45,7 +45,8 @@ from calibre import sanitize_file_name from calibre.constants import config_dir, iswindows from calibre.ebooks.metadata.book.base import Metadata from calibre.ebooks.metadata.book.formatter import SafeFormat -from calibre.gui2 import choose_files, choose_save_file, error_dialog, gprefs, pixmap_to_data, question_dialog, safe_open_url +from calibre.gui2 import (choose_files, choose_save_file, error_dialog, gprefs, info_dialog, + pixmap_to_data, question_dialog, safe_open_url) from calibre.gui2.dialogs.template_dialog_ui import Ui_TemplateDialog from calibre.gui2.dialogs.template_general_info import GeneralInformationDialog from calibre.gui2.widgets2 import Dialog, HTMLDisplay @@ -68,6 +69,8 @@ class DocViewer(Dialog): self.builtins = builtins self.function_type_string = function_type_string_method self.last_operation = None + self.last_function = None + self.back_stack = [] super().__init__(title=_('Template function documentation'), name='template_editor_doc_viewer_dialog', default_buttons=QDialogButtonBox.StandardButton.Close, parent=parent) @@ -82,7 +85,7 @@ class DocViewer(Dialog): e = self.doc_viewer_widget = HTMLDisplay(self) if iswindows: e.setDefaultStyleSheet('pre { font-family: "Segoe UI Mono", "Consolas", monospace; }') - e.anchor_clicked.connect(safe_open_url) + e.anchor_clicked.connect(self.url_clicked) l.addWidget(e) bl = QHBoxLayout() l.addLayout(bl) @@ -91,10 +94,34 @@ class DocViewer(Dialog): cb.stateChanged.connect(self.english_cb_state_changed) bl.addWidget(cb) bl.addWidget(self.bb) + + b = self.back_button = self.bb.addButton(_('&Back'), QDialogButtonBox.ButtonRole.ActionRole) + b.clicked.connect(self.back) + b.setToolTip((_('Displays the previously viewed function'))) + b.setEnabled(False) + b = self.bb.addButton(_('Show &all functions'), QDialogButtonBox.ButtonRole.ActionRole) b.clicked.connect(self.show_all_functions) b.setToolTip((_('Shows a list of all built-in functions in alphabetic order'))) + def back(self): + if not self.back_stack: + info_dialog(self, _('Go back'), _('No function to go back to'), show=True) + else: + name = self.back_stack.pop() + if not self.back_stack: + self.back_button.setEnabled(False) + self.show_function(name) + + def url_clicked(self, qurl): + if qurl.scheme().startswith('http'): + safe_open_url(qurl) + else: + if self.last_function is not None: + self.back_stack.append(self.last_function) + self.back_button.setEnabled(True) + self.show_function(qurl.path()) + def english_cb_state_changed(self): if self.last_operation is not None: self.last_operation() @@ -113,10 +140,14 @@ class DocViewer(Dialog): if fname not in self.builtins or not bif.doc: self.set_html(self.header_line(fname) + ('No documentation provided')) else: + self.last_function = fname self.set_html(self.header_line(fname) + self.ffml.document_to_html(self.get_doc(bif), fname)) def show_all_functions(self): + self.back_button.setEnabled(False) + self.back_stack = [] + self.last_function = None self.last_operation = self.show_all_functions result = [] a = result.append @@ -127,7 +158,10 @@ class DocViewer(Dialog): if not doc: a(_('No documentation provided')) else: - a(self.ffml.document_to_html(doc.strip(), name)) + html = self.ffml.document_to_html(doc.strip(), name) + paren = html.find('(') + html = f'{name}{html[paren:]}' + a(html) except Exception: print('Exception in', name) raise @@ -541,6 +575,8 @@ class TemplateDialog(QDialog, Ui_TemplateDialog): self.doc_viewer = None self.current_function_name = None self.documentation.setReadOnly(True) + self.documentation.setOpenLinks(False) + self.documentation.anchorClicked.connect(self.url_clicked) self.source_code.setReadOnly(True) self.doc_button.clicked.connect(self.open_documentation_viewer) self.general_info_button.clicked.connect(self.open_general_info_dialog) @@ -569,7 +605,7 @@ class TemplateDialog(QDialog, Ui_TemplateDialog): except: self.builtin_source_dict = {} - func_names = sorted(self.all_functions) + self.function_names = func_names = sorted(self.all_functions) self.function.clear() self.function.addItem('') for f in func_names: @@ -603,6 +639,15 @@ class TemplateDialog(QDialog, Ui_TemplateDialog): # Now geometry self.restore_geometry(gprefs, self.geometry_string('template_editor_dialog_geometry')) + def url_clicked(self, qurl): + if qurl.scheme().startswith('http'): + safe_open_url(qurl) + elif qurl.scheme() == 'ffdoc': + name = qurl.path() + if name in self.function_names: + dex = self.function_names.index(name) + self.function.setCurrentIndex(dex+1) + def open_documentation_viewer(self): if self.doc_viewer is None: dv = self.doc_viewer = DocViewer(self.ffml, self.all_functions, diff --git a/src/calibre/gui2/dialogs/template_dialog.ui b/src/calibre/gui2/dialogs/template_dialog.ui index 15227e1fb9..7c42f73629 100644 --- a/src/calibre/gui2/dialogs/template_dialog.ui +++ b/src/calibre/gui2/dialogs/template_dialog.ui @@ -768,9 +768,6 @@ Selecting a function will show only that function's documentation - - true - 16777215