From 08081eaebb614214401d7a99a26c4b3a0ad8423e Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 7 Aug 2019 09:29:14 +0530 Subject: [PATCH] Implement searching and clicking in the ToC --- src/calibre/gui2/viewer/toc.py | 2 ++ src/calibre/gui2/viewer/ui.py | 12 +++++++++++- src/calibre/gui2/viewer/web_view.py | 7 ++++++- src/pyj/read_book/view.pyj | 12 ++++++++++++ src/pyj/viewer-main.pyj | 5 +++++ 5 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/calibre/gui2/viewer/toc.py b/src/calibre/gui2/viewer/toc.py index a0c8b570c4..031ff2745f 100644 --- a/src/calibre/gui2/viewer/toc.py +++ b/src/calibre/gui2/viewer/toc.py @@ -40,6 +40,7 @@ class TOCView(QTreeView): def __init__(self, *args): QTreeView.__init__(self, *args) + self.setFocusPolicy(Qt.NoFocus) self.delegate = Delegate(self) self.setItemDelegate(self.delegate) self.setMinimumWidth(80) @@ -123,6 +124,7 @@ class TOCSearch(QWidget): return index = self.toc_view.model().search(text) if index.isValid(): + self.toc_view.scrollTo(index) self.toc_view.searched.emit(index) else: error_dialog(self.toc_view, _('No matches found'), _( diff --git a/src/calibre/gui2/viewer/ui.py b/src/calibre/gui2/viewer/ui.py index 2970852aaf..d7a61cfa08 100644 --- a/src/calibre/gui2/viewer/ui.py +++ b/src/calibre/gui2/viewer/ui.py @@ -11,7 +11,7 @@ from collections import defaultdict from hashlib import sha256 from threading import Thread -from PyQt5.Qt import QDockWidget, Qt, QVBoxLayout, QWidget, pyqtSignal +from PyQt5.Qt import QDockWidget, QModelIndex, Qt, QVBoxLayout, QWidget, pyqtSignal from calibre import prints from calibre.constants import config_dir @@ -61,6 +61,8 @@ class EbookViewer(MainWindow): self.toc_container = w = QWidget(self) w.l = QVBoxLayout(w) self.toc = TOCView(w) + self.toc.pressed[QModelIndex].connect(self.toc_clicked) + self.toc.searched.connect(self.toc_searched) self.toc_search = TOCSearch(self.toc, parent=w) w.l.addWidget(self.toc), w.l.addWidget(self.toc_search), w.l.setContentsMargins(0, 0, 0, 0) self.toc_dock.setWidget(w) @@ -96,6 +98,14 @@ class EbookViewer(MainWindow): else: self.toc_dock.setVisible(True) + def toc_clicked(self, index): + item = self.toc_model.itemFromIndex(index) + self.web_view.goto_toc_node(item.node_id) + + def toc_searched(self, index): + item = self.toc_model.itemFromIndex(index) + self.web_view.goto_toc_node(item.node_id) + def load_ebook(self, pathtoebook, open_at=None, reload_book=False): # TODO: Implement open_at self.web_view.show_preparing_message() diff --git a/src/calibre/gui2/viewer/web_view.py b/src/calibre/gui2/viewer/web_view.py index fab95586a0..54d8135f8d 100644 --- a/src/calibre/gui2/viewer/web_view.py +++ b/src/calibre/gui2/viewer/web_view.py @@ -8,7 +8,7 @@ import os import sys from PyQt5.Qt import ( - QApplication, QBuffer, QByteArray, QHBoxLayout, QSize, QTimer, QUrl, QWidget, + QApplication, QBuffer, QByteArray, QHBoxLayout, QSize, Qt, QTimer, QUrl, QWidget, pyqtSignal ) from PyQt5.QtWebEngineCore import QWebEngineUrlSchemeHandler @@ -174,6 +174,7 @@ class ViewerBridge(Bridge): create_view = to_js() show_preparing_message = to_js() start_book_load = to_js() + goto_toc_node = to_js() class WebPage(QWebEnginePage): @@ -301,6 +302,7 @@ class WebView(RestartingWebEngineView): child = event.child() if 'HostView' in child.metaObject().className(): self._host_widget = child + self._host_widget.setFocus(Qt.OtherFocusReason) return QWebEngineView.event(self, event) def sizeHint(self): @@ -335,6 +337,9 @@ class WebView(RestartingWebEngineView): msg = _('Preparing book for first read, please wait…') self.execute_when_ready('show_preparing_message', msg) + def goto_toc_node(self, node_id): + self.execute_when_ready('goto_toc_node', node_id) + def set_session_data(self, key, val): if key == '*' and val is None: vprefs['session_data'] = {} diff --git a/src/pyj/read_book/view.pyj b/src/pyj/read_book/view.pyj index 49230c3013..a09140dcb4 100644 --- a/src/pyj/read_book/view.pyj +++ b/src/pyj/read_book/view.pyj @@ -472,6 +472,18 @@ class View: return self.show_name(name, initial_position={'type':'anchor', 'anchor':frag, 'replace_history':False}) + def goto_toc_node(self, node_id): + toc = self.book.manifest.toc + + def process_node(x): + if x.id is node_id: + self.goto_named_destination(x.dest or '', x.frag or '') + return + for c in x.children: + process_node(c) + if toc: + process_node(toc) + def on_next_spine_item(self, data): spine = self.book.manifest.spine idx = spine.indexOf(self.currently_showing.name) diff --git a/src/pyj/viewer-main.pyj b/src/pyj/viewer-main.pyj index 33b3cbe3ff..9f74142042 100644 --- a/src/pyj/viewer-main.pyj +++ b/src/pyj/viewer-main.pyj @@ -193,6 +193,11 @@ def start_book_load(key, initial_cfi): xhr.send() +@from_python +def goto_toc_node(node_id): + view.goto_toc_node(node_id) + + def onerror(msg, script_url, line_number, column_number, error_object): if not error_object: # cross domain error