Work on highlights panel

This commit is contained in:
Kovid Goyal 2020-04-29 14:53:35 +05:30
parent 9e88dfd3b4
commit e4a19c8808
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
7 changed files with 87 additions and 14 deletions

View File

@ -0,0 +1,44 @@
#!/usr/bin/env python2
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from __future__ import absolute_import, division, print_function, unicode_literals
from PyQt5.Qt import QListWidget, QListWidgetItem, Qt, QVBoxLayout, QWidget
from calibre.gui2.viewer.search import SearchInput
class Highlights(QListWidget):
def __init__(self, parent=None):
QListWidget.__init__(self, parent)
self.setFocusPolicy(Qt.NoFocus)
self.setSpacing(2)
def load(self, highlights):
self.clear()
for h in highlights:
i = QListWidgetItem(h['highlighted_text'], self)
i.setData(Qt.UserRole, h)
class HighlightsPanel(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.l = l = QVBoxLayout(self)
l.setContentsMargins(0, 0, 0, 0)
self.search_input = si = SearchInput(self, 'highlights-search')
si.do_search.connect(self.search_requested)
l.addWidget(si)
self.highlights = h = Highlights(self)
l.addWidget(h)
self.load = h.load
def search_requested(self, query):
pass
def focus(self):
self.highlights_list.setFocus(Qt.OtherFocusReason)

View File

@ -225,7 +225,7 @@ class SearchInput(QWidget): # {{{
do_search = pyqtSignal(object) do_search = pyqtSignal(object)
def __init__(self, parent=None): def __init__(self, parent=None, panel_name='search'):
QWidget.__init__(self, parent) QWidget.__init__(self, parent)
self.ignore_search_type_changes = False self.ignore_search_type_changes = False
self.l = l = QVBoxLayout(self) self.l = l = QVBoxLayout(self)
@ -235,7 +235,8 @@ class SearchInput(QWidget): # {{{
l.addLayout(h) l.addLayout(h)
self.search_box = sb = SearchBox(self) self.search_box = sb = SearchBox(self)
sb.initialize('viewer-search-panel-expression') self.panel_name = panel_name
sb.initialize('viewer-{}-panel-expression'.format(panel_name))
sb.item_selected.connect(self.saved_search_selected) sb.item_selected.connect(self.saved_search_selected)
sb.history_saved.connect(self.history_saved) sb.history_saved.connect(self.history_saved)
sb.lineEdit().setPlaceholderText(_('Search')) sb.lineEdit().setPlaceholderText(_('Search'))
@ -271,35 +272,35 @@ class SearchInput(QWidget): # {{{
'<li><b>Whole words</b> will search for whole words that equal the entered text.' '<li><b>Whole words</b> will search for whole words that equal the entered text.'
'<li><b>Regex</b> will interpret the text as a regular expression.' '<li><b>Regex</b> will interpret the text as a regular expression.'
))) )))
qt.setCurrentIndex(qt.findData(vprefs.get('viewer-search-mode', 'normal') or 'normal')) qt.setCurrentIndex(qt.findData(vprefs.get('viewer-{}-mode'.format(self.panel_name), 'normal') or 'normal'))
qt.currentIndexChanged.connect(self.save_search_type) qt.currentIndexChanged.connect(self.save_search_type)
h.addWidget(qt) h.addWidget(qt)
self.case_sensitive = cs = QCheckBox(_('&Case sensitive'), self) self.case_sensitive = cs = QCheckBox(_('&Case sensitive'), self)
cs.setFocusPolicy(Qt.NoFocus) cs.setFocusPolicy(Qt.NoFocus)
cs.setChecked(bool(vprefs.get('viewer-search-case-sensitive', False))) cs.setChecked(bool(vprefs.get('viewer-{}-case-sensitive'.format(self.panel_name), False)))
cs.stateChanged.connect(self.save_search_type) cs.stateChanged.connect(self.save_search_type)
h.addWidget(cs) h.addWidget(cs)
def history_saved(self, new_text, history): def history_saved(self, new_text, history):
if new_text: if new_text:
sss = vprefs.get('saved-search-settings') or {} sss = vprefs.get('saved-{}-settings'.format(self.panel_name)) or {}
sss[new_text] = {'case_sensitive': self.case_sensitive.isChecked(), 'mode': self.query_type.currentData()} sss[new_text] = {'case_sensitive': self.case_sensitive.isChecked(), 'mode': self.query_type.currentData()}
history = frozenset(history) history = frozenset(history)
sss = {k: v for k, v in iteritems(sss) if k in history} sss = {k: v for k, v in iteritems(sss) if k in history}
vprefs['saved-search-settings'] = sss vprefs['saved-{}-settings'.format(self.panel_name)] = sss
def save_search_type(self): def save_search_type(self):
text = self.search_box.currentText() text = self.search_box.currentText()
if text and not self.ignore_search_type_changes: if text and not self.ignore_search_type_changes:
sss = vprefs.get('saved-search-settings') or {} sss = vprefs.get('saved-{}-settings'.format(self.panel_name)) or {}
sss[text] = {'case_sensitive': self.case_sensitive.isChecked(), 'mode': self.query_type.currentData()} sss[text] = {'case_sensitive': self.case_sensitive.isChecked(), 'mode': self.query_type.currentData()}
vprefs['saved-search-settings'] = sss vprefs['saved-{}-settings'.format(self.panel_name)] = sss
def saved_search_selected(self): def saved_search_selected(self):
text = self.search_box.currentText() text = self.search_box.currentText()
if text: if text:
s = (vprefs.get('saved-search-settings') or {}).get(text) s = (vprefs.get('saved-{}-settings'.format(self.panel_name)) or {}).get(text)
if s: if s:
self.ignore_search_type_changes = True self.ignore_search_type_changes = True
if 'case_sensitive' in s: if 'case_sensitive' in s:
@ -320,8 +321,8 @@ class SearchInput(QWidget): # {{{
) )
def emit_search(self, backwards=False): def emit_search(self, backwards=False):
vprefs['viewer-search-case-sensitive'] = self.case_sensitive.isChecked() vprefs['viewer-{}-case-sensitive'.format(self.panel_name)] = self.case_sensitive.isChecked()
vprefs['viewer-search-mode'] = self.query_type.currentData() vprefs['viewer-{}-mode'.format(self.panel_name)] = self.query_type.currentData()
sq = self.search_query(backwards) sq = self.search_query(backwards)
if sq is not None: if sq is not None:
self.do_search.emit(sq) self.do_search.emit(sq)

View File

@ -32,6 +32,7 @@ from calibre.gui2.viewer.bookmarks import BookmarkManager
from calibre.gui2.viewer.convert_book import ( from calibre.gui2.viewer.convert_book import (
clean_running_workers, prepare_book, update_book clean_running_workers, prepare_book, update_book
) )
from calibre.gui2.viewer.highlights import HighlightsPanel
from calibre.gui2.viewer.lookup import Lookup from calibre.gui2.viewer.lookup import Lookup
from calibre.gui2.viewer.overlay import LoadingOverlay from calibre.gui2.viewer.overlay import LoadingOverlay
from calibre.gui2.viewer.search import SearchPanel from calibre.gui2.viewer.search import SearchPanel
@ -73,6 +74,7 @@ def dock_defs():
d(_('Bookmarks'), 'bookmarks', Qt.RightDockWidgetArea) d(_('Bookmarks'), 'bookmarks', Qt.RightDockWidgetArea)
d(_('Search'), 'search', Qt.LeftDockWidgetArea) d(_('Search'), 'search', Qt.LeftDockWidgetArea)
d(_('Inspector'), 'inspector', Qt.RightDockWidgetArea, Qt.AllDockWidgetAreas) d(_('Inspector'), 'inspector', Qt.RightDockWidgetArea, Qt.AllDockWidgetAreas)
d(_('Highlights'), 'highlights', Qt.RightDockWidgetArea)
return ans return ans
@ -152,6 +154,9 @@ class EbookViewer(MainWindow):
w.toggle_requested.connect(self.toggle_bookmarks) w.toggle_requested.connect(self.toggle_bookmarks)
self.bookmarks_dock.setWidget(w) self.bookmarks_dock.setWidget(w)
self.highlights_widget = w = HighlightsPanel(self)
self.highlights_dock.setWidget(w)
self.web_view = WebView(self) self.web_view = WebView(self)
self.web_view.cfi_changed.connect(self.cfi_changed) self.web_view.cfi_changed.connect(self.cfi_changed)
self.web_view.reload_book.connect(self.reload_book) self.web_view.reload_book.connect(self.reload_book)
@ -161,6 +166,7 @@ class EbookViewer(MainWindow):
self.search_widget.show_search_result.connect(self.web_view.show_search_result) self.search_widget.show_search_result.connect(self.web_view.show_search_result)
self.web_view.search_result_not_found.connect(self.search_widget.search_result_not_found) self.web_view.search_result_not_found.connect(self.search_widget.search_result_not_found)
self.web_view.toggle_bookmarks.connect(self.toggle_bookmarks) self.web_view.toggle_bookmarks.connect(self.toggle_bookmarks)
self.web_view.toggle_highlights.connect(self.toggle_highlights)
self.web_view.new_bookmark.connect(self.bookmarks_widget.create_requested) self.web_view.new_bookmark.connect(self.bookmarks_widget.create_requested)
self.web_view.toggle_inspector.connect(self.toggle_inspector) self.web_view.toggle_inspector.connect(self.toggle_inspector)
self.web_view.toggle_lookup.connect(self.toggle_lookup) self.web_view.toggle_lookup.connect(self.toggle_lookup)
@ -301,6 +307,14 @@ class EbookViewer(MainWindow):
else: else:
self.bookmarks_widget.bookmarks_list.setFocus(Qt.OtherFocusReason) self.bookmarks_widget.bookmarks_list.setFocus(Qt.OtherFocusReason)
def toggle_highlights(self):
is_visible = self.highlights_dock.isVisible()
self.highlights_dock.setVisible(not is_visible)
if is_visible:
self.web_view.setFocus(Qt.OtherFocusReason)
else:
self.highlights_widget.focus()
def toggle_lookup(self): def toggle_lookup(self):
self.lookup_dock.setVisible(not self.lookup_dock.isVisible()) self.lookup_dock.setVisible(not self.lookup_dock.isVisible())
@ -490,9 +504,11 @@ class EbookViewer(MainWindow):
initial_position = {'type': 'ref', 'data': open_at[len('ref:'):]} initial_position = {'type': 'ref', 'data': open_at[len('ref:'):]}
elif is_float(open_at): elif is_float(open_at):
initial_position = {'type': 'bookpos', 'data': float(open_at)} initial_position = {'type': 'bookpos', 'data': float(open_at)}
highlights = self.current_book_data['annotations_map']['highlight']
self.highlights_widget.load(highlights)
self.web_view.start_book_load( self.web_view.start_book_load(
initial_position=initial_position, initial_position=initial_position,
highlights=list(map(serialize_annotation, self.current_book_data['annotations_map']['highlight'])) highlights=list(map(serialize_annotation, highlights))
) )
def load_book_data(self): def load_book_data(self):

View File

@ -248,6 +248,7 @@ class ViewerBridge(Bridge):
reload_book = from_js() reload_book = from_js()
toggle_toc = from_js() toggle_toc = from_js()
toggle_bookmarks = from_js() toggle_bookmarks = from_js()
toggle_highlights = from_js()
new_bookmark = from_js() new_bookmark = from_js()
toggle_inspector = from_js() toggle_inspector = from_js()
toggle_lookup = from_js() toggle_lookup = from_js()
@ -439,6 +440,7 @@ class WebView(RestartingWebEngineView):
search_result_not_found = pyqtSignal(object) search_result_not_found = pyqtSignal(object)
find_next = pyqtSignal(object) find_next = pyqtSignal(object)
toggle_bookmarks = pyqtSignal() toggle_bookmarks = pyqtSignal()
toggle_highlights = pyqtSignal()
new_bookmark = pyqtSignal() new_bookmark = pyqtSignal()
toggle_inspector = pyqtSignal() toggle_inspector = pyqtSignal()
toggle_lookup = pyqtSignal() toggle_lookup = pyqtSignal()
@ -491,6 +493,7 @@ class WebView(RestartingWebEngineView):
self.bridge.search_result_not_found.connect(self.search_result_not_found) self.bridge.search_result_not_found.connect(self.search_result_not_found)
self.bridge.find_next.connect(self.find_next) self.bridge.find_next.connect(self.find_next)
self.bridge.toggle_bookmarks.connect(self.toggle_bookmarks) self.bridge.toggle_bookmarks.connect(self.toggle_bookmarks)
self.bridge.toggle_highlights.connect(self.toggle_highlights)
self.bridge.new_bookmark.connect(self.new_bookmark) self.bridge.new_bookmark.connect(self.new_bookmark)
self.bridge.toggle_inspector.connect(self.toggle_inspector) self.bridge.toggle_inspector.connect(self.toggle_inspector)
self.bridge.toggle_lookup.connect(self.toggle_lookup) self.bridge.toggle_lookup.connect(self.toggle_lookup)

View File

@ -333,12 +333,11 @@ def shortcuts_definition():
} }
if runtime.in_develop_mode: if runtime.in_develop_mode:
ans.create_annotation = desc( ans.create_annotation = desc(
"a", "Ctrl+h",
'ui', 'ui',
_('Create a highlight'), _('Create a highlight'),
) )
return ans return ans
@ -398,6 +397,12 @@ def add_standalone_viewer_shortcuts():
'ui', 'ui',
_('Toggle the toolbar'), _('Toggle the toolbar'),
) )
if runtime.in_develop_mode:
sc['toggle_highlights'] = desc(
"Ctrl+Alt+h",
'ui',
_('Toggle the highlights panel')
)
def create_shortcut_map(custom_shortcuts): def create_shortcut_map(custom_shortcuts):

View File

@ -427,6 +427,8 @@ class View:
ui_operations.toggle_toc() ui_operations.toggle_toc()
elif data.name is 'toggle_bookmarks': elif data.name is 'toggle_bookmarks':
ui_operations.toggle_bookmarks() ui_operations.toggle_bookmarks()
elif data.name is 'toggle_highlights':
ui_operations.toggle_highlights()
elif data.name is 'new_bookmark': elif data.name is 'new_bookmark':
ui_operations.new_bookmark() ui_operations.new_bookmark()
elif data.name is 'toggle_inspector': elif data.name is 'toggle_inspector':

View File

@ -357,6 +357,8 @@ if window is window.top:
to_python.toggle_toc() to_python.toggle_toc()
ui_operations.toggle_bookmarks = def(): ui_operations.toggle_bookmarks = def():
to_python.toggle_bookmarks() to_python.toggle_bookmarks()
ui_operations.toggle_highlights = def():
to_python.toggle_highlights()
ui_operations.new_bookmark = def(): ui_operations.new_bookmark = def():
to_python.new_bookmark() to_python.new_bookmark()
ui_operations.toggle_inspector = def(): ui_operations.toggle_inspector = def():