From 2c45544a16040e0aa665f5bbd1c64375f9d94e93 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 12 May 2020 16:10:09 +0530 Subject: [PATCH] Add and edit highlight buttons work --- src/calibre/gui2/viewer/highlights.py | 47 ++++++++++++++++++++++++--- src/calibre/gui2/viewer/ui.py | 5 +++ src/calibre/gui2/viewer/web_view.py | 4 +++ src/pyj/read_book/iframe.pyj | 8 +++++ src/pyj/read_book/view.pyj | 12 +++++++ src/pyj/viewer-main.pyj | 6 ++++ 6 files changed, 78 insertions(+), 4 deletions(-) diff --git a/src/calibre/gui2/viewer/highlights.py b/src/calibre/gui2/viewer/highlights.py index 20eeffa61a..018b249b15 100644 --- a/src/calibre/gui2/viewer/highlights.py +++ b/src/calibre/gui2/viewer/highlights.py @@ -7,8 +7,8 @@ from __future__ import absolute_import, division, print_function, unicode_litera from itertools import chain from PyQt5.Qt import ( - QItemSelectionModel, QLabel, QListWidget, QListWidgetItem, Qt, QVBoxLayout, - QWidget, pyqtSignal + QHBoxLayout, QIcon, QItemSelectionModel, QLabel, QListWidget, QListWidgetItem, + QPushButton, Qt, QVBoxLayout, QWidget, pyqtSignal ) from calibre.constants import plugins @@ -40,7 +40,6 @@ class Highlights(QListWidget): def __init__(self, parent=None): QListWidget.__init__(self, parent) - self.setFocusPolicy(Qt.NoFocus) self.setSpacing(2) pi = plugins['progress_indicator'][0] pi.set_no_activate_on_click(self) @@ -77,20 +76,29 @@ class Highlights(QListWidget): def item_activated(self, item): self.jump_to_highlight.emit(item.data(Qt.UserRole)) + @property + def current_highlight(self): + i = self.currentItem() + if i is not None: + return i.data(Qt.UserRole) + class HighlightsPanel(QWidget): jump_to_cfi = pyqtSignal(object) + add_highlight = pyqtSignal() + request_highlight_action = pyqtSignal(object, object, object) def __init__(self, parent=None): QWidget.__init__(self, parent) + self.setFocusPolicy(Qt.NoFocus) 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) - la = QLabel(_('Double click on an entry to jump to it')) + la = QLabel(_('Double click to jump to an entry')) la.setWordWrap(True) l.addWidget(la) @@ -99,6 +107,21 @@ class HighlightsPanel(QWidget): h.jump_to_highlight.connect(self.jump_to_highlight) self.load = h.load + self.h = h = QHBoxLayout() + l.addLayout(h) + + def button(icon, text, tt, target): + b = QPushButton(QIcon(I(icon)), text, self) + b.setToolTip(tt) + b.setFocusPolicy(Qt.NoFocus) + b.clicked.connect(target) + return b + + self.add_button = button('plus.png', _('Add'), _('Create a new highlight'), self.add_highlight) + self.edit_button = button('edit_input.png', _('Edit'), _('Edit the selected highlight'), self.edit_highlight) + self.remove_button = button('trash.png', _('Remove'), _('Remove the selected highlight'), self.remove_highlight) + h.addWidget(self.add_button), h.addWidget(self.edit_button), h.addWidget(self.remove_button) + def search_requested(self, query): if not self.highlights.find_query(query): error_dialog(self, _('No matches'), _( @@ -112,3 +135,19 @@ class HighlightsPanel(QWidget): idx = spine_index_for_highlight(highlight) cfi = 'epubcfi(/{}{})'.format(2*(idx + 1), cfi) self.jump_to_cfi.emit(cfi) + + def no_selected_highlight(self): + error_dialog(self, _('No selected highlight'), _( + 'No highlight is currently selected'), show=True) + + def edit_highlight(self): + h = self.highlights.current_highlight + if h is None: + return self.no_selected_highlight() + self.request_highlight_action.emit(h['uuid'], spine_index_for_highlight(h), 'edit') + + def remove_highlight(self): + h = self.highlights.current_highlight + if h is None: + return self.no_selected_highlight() + self.request_highlight_action.emit(h['uuid'], spine_index_for_highlight(h), 'delete') diff --git a/src/calibre/gui2/viewer/ui.py b/src/calibre/gui2/viewer/ui.py index 780bb09436..02dbcb506c 100644 --- a/src/calibre/gui2/viewer/ui.py +++ b/src/calibre/gui2/viewer/ui.py @@ -155,6 +155,7 @@ class EbookViewer(MainWindow): self.bookmarks_dock.setWidget(w) self.highlights_widget = w = HighlightsPanel(self) + w.add_highlight.connect(self.add_highlight) self.highlights_dock.setWidget(w) self.web_view = WebView(self) @@ -193,6 +194,7 @@ class EbookViewer(MainWindow): self.actions_toolbar.update_visibility() self.dock_visibility_changed() self.highlights_widget.jump_to_cfi.connect(self.web_view.goto_cfi) + self.highlights_widget.request_highlight_action.connect(self.web_view.highlight_action) if continue_reading: self.continue_reading() @@ -338,6 +340,9 @@ class EbookViewer(MainWindow): def bookmark_activated(self, cfi): self.web_view.goto_cfi(cfi) + def add_highlight(self): + self.web_view.trigger_shortcut('create_annotation') + def view_image(self, name): path = get_path_for_name(name) if path: diff --git a/src/calibre/gui2/viewer/web_view.py b/src/calibre/gui2/viewer/web_view.py index 6251bba3ea..df873d2220 100644 --- a/src/calibre/gui2/viewer/web_view.py +++ b/src/calibre/gui2/viewer/web_view.py @@ -291,6 +291,7 @@ class ViewerBridge(Bridge): goto_frac = to_js() trigger_shortcut = to_js() set_system_palette = to_js() + highlight_action = to_js() show_search_result = to_js() prepare_for_close = to_js() viewer_font_size_changed = to_js() @@ -694,6 +695,9 @@ class WebView(RestartingWebEngineView): def prepare_for_close(self): self.execute_when_ready('prepare_for_close') + def highlight_action(self, uuid, spine_index, which): + self.execute_when_ready('highlight_action', uuid, spine_index, which) + def contextMenuEvent(self, ev): ev.accept() self.trigger_shortcut('show_chrome') diff --git a/src/pyj/read_book/iframe.pyj b/src/pyj/read_book/iframe.pyj index a5bef026bc..29c08a26a4 100644 --- a/src/pyj/read_book/iframe.pyj +++ b/src/pyj/read_book/iframe.pyj @@ -128,6 +128,7 @@ class IframeBoss: 'scroll_to_frac': self.on_scroll_to_frac, 'scroll_to_ref': self.on_scroll_to_ref, 'set_reference_mode': self.set_reference_mode, + 'create_annotation': self.create_annotation, 'toggle_autoscroll': self.toggle_autoscroll, 'wheel_from_margin': self.wheel_from_margin, 'window_size': self.received_window_size, @@ -410,6 +411,10 @@ class IframeBoss: self.show_search_result(ipos, True) elif ipos.type is 'search': self.find(ipos.search_data, True) + elif ipos.type is 'edit_annotation': + window.setTimeout(def(): + self.annotations_msg_received({'type': 'edit-highlight', 'uuid': ipos.uuid}) + , 5) spine = self.book.manifest.spine files = self.book.manifest.files spine_index = csi.index @@ -655,6 +660,9 @@ class IframeBoss: else: end_reference_mode() + def create_annotation(self, data): + self.initiate_creation_of_annotation() + def initiate_creation_of_annotation(self, existing): self.auto_scroll_action('stop') in_flow_mode = current_layout_mode() is 'flow' diff --git a/src/pyj/read_book/view.pyj b/src/pyj/read_book/view.pyj index dc69a3b62c..5a0463bea6 100644 --- a/src/pyj/read_book/view.pyj +++ b/src/pyj/read_book/view.pyj @@ -432,6 +432,8 @@ class View: ui_operations.toggle_bookmarks() elif data.name is 'toggle_highlights': ui_operations.toggle_highlights() + elif data.name is 'create_annotation': + self.iframe_wrapper.send_message('create_annotation') elif data.name is 'new_bookmark': ui_operations.new_bookmark() elif data.name is 'toggle_inspector': @@ -1187,3 +1189,13 @@ class View: self.iframe_wrapper.send_message('show_search_result', search_result=sr) else: self.show_name(sr.file_name, initial_position={'type':'search_result', 'search_result':sr, 'replace_history':True}) + + def highlight_action(self, uuid, spine_index, which): + if which is 'edit': + if self.currently_showing.spine_index is spine_index: + self.create_annotation.edit_highlight(uuid) + else: + name = self.book.manifest.spine[spine_index] + self.show_name(name, initial_position={'type':'edit_annotation', 'uuid': uuid, 'replace_history':True}) + elif which is 'delete': + pass diff --git a/src/pyj/viewer-main.pyj b/src/pyj/viewer-main.pyj index 8dfeb7f9a6..617283e07b 100644 --- a/src/pyj/viewer-main.pyj +++ b/src/pyj/viewer-main.pyj @@ -240,6 +240,12 @@ def set_system_palette(system_colors): view.update_color_scheme() +@from_python +def highlight_action(uuid, spine_index, which): + if view: + view.highlight_action(uuid, spine_index, which) + + @from_python def show_home_page(): view.overlay.open_book(False)