Implement searching and clicking in the ToC

This commit is contained in:
Kovid Goyal 2019-08-07 09:29:14 +05:30
parent 02d8563efc
commit 08081eaebb
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
5 changed files with 36 additions and 2 deletions

View File

@ -40,6 +40,7 @@ class TOCView(QTreeView):
def __init__(self, *args): def __init__(self, *args):
QTreeView.__init__(self, *args) QTreeView.__init__(self, *args)
self.setFocusPolicy(Qt.NoFocus)
self.delegate = Delegate(self) self.delegate = Delegate(self)
self.setItemDelegate(self.delegate) self.setItemDelegate(self.delegate)
self.setMinimumWidth(80) self.setMinimumWidth(80)
@ -123,6 +124,7 @@ class TOCSearch(QWidget):
return return
index = self.toc_view.model().search(text) index = self.toc_view.model().search(text)
if index.isValid(): if index.isValid():
self.toc_view.scrollTo(index)
self.toc_view.searched.emit(index) self.toc_view.searched.emit(index)
else: else:
error_dialog(self.toc_view, _('No matches found'), _( error_dialog(self.toc_view, _('No matches found'), _(

View File

@ -11,7 +11,7 @@ from collections import defaultdict
from hashlib import sha256 from hashlib import sha256
from threading import Thread 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 import prints
from calibre.constants import config_dir from calibre.constants import config_dir
@ -61,6 +61,8 @@ class EbookViewer(MainWindow):
self.toc_container = w = QWidget(self) self.toc_container = w = QWidget(self)
w.l = QVBoxLayout(w) w.l = QVBoxLayout(w)
self.toc = TOCView(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) 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) w.l.addWidget(self.toc), w.l.addWidget(self.toc_search), w.l.setContentsMargins(0, 0, 0, 0)
self.toc_dock.setWidget(w) self.toc_dock.setWidget(w)
@ -96,6 +98,14 @@ class EbookViewer(MainWindow):
else: else:
self.toc_dock.setVisible(True) 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): def load_ebook(self, pathtoebook, open_at=None, reload_book=False):
# TODO: Implement open_at # TODO: Implement open_at
self.web_view.show_preparing_message() self.web_view.show_preparing_message()

View File

@ -8,7 +8,7 @@ import os
import sys import sys
from PyQt5.Qt import ( from PyQt5.Qt import (
QApplication, QBuffer, QByteArray, QHBoxLayout, QSize, QTimer, QUrl, QWidget, QApplication, QBuffer, QByteArray, QHBoxLayout, QSize, Qt, QTimer, QUrl, QWidget,
pyqtSignal pyqtSignal
) )
from PyQt5.QtWebEngineCore import QWebEngineUrlSchemeHandler from PyQt5.QtWebEngineCore import QWebEngineUrlSchemeHandler
@ -174,6 +174,7 @@ class ViewerBridge(Bridge):
create_view = to_js() create_view = to_js()
show_preparing_message = to_js() show_preparing_message = to_js()
start_book_load = to_js() start_book_load = to_js()
goto_toc_node = to_js()
class WebPage(QWebEnginePage): class WebPage(QWebEnginePage):
@ -301,6 +302,7 @@ class WebView(RestartingWebEngineView):
child = event.child() child = event.child()
if 'HostView' in child.metaObject().className(): if 'HostView' in child.metaObject().className():
self._host_widget = child self._host_widget = child
self._host_widget.setFocus(Qt.OtherFocusReason)
return QWebEngineView.event(self, event) return QWebEngineView.event(self, event)
def sizeHint(self): def sizeHint(self):
@ -335,6 +337,9 @@ class WebView(RestartingWebEngineView):
msg = _('Preparing book for first read, please wait…') msg = _('Preparing book for first read, please wait…')
self.execute_when_ready('show_preparing_message', msg) 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): def set_session_data(self, key, val):
if key == '*' and val is None: if key == '*' and val is None:
vprefs['session_data'] = {} vprefs['session_data'] = {}

View File

@ -472,6 +472,18 @@ class View:
return return
self.show_name(name, initial_position={'type':'anchor', 'anchor':frag, 'replace_history':False}) 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): def on_next_spine_item(self, data):
spine = self.book.manifest.spine spine = self.book.manifest.spine
idx = spine.indexOf(self.currently_showing.name) idx = spine.indexOf(self.currently_showing.name)

View File

@ -193,6 +193,11 @@ def start_book_load(key, initial_cfi):
xhr.send() 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): def onerror(msg, script_url, line_number, column_number, error_object):
if not error_object: if not error_object:
# cross domain error # cross domain error