diff --git a/src/calibre/gui2/viewer/toolbars.py b/src/calibre/gui2/viewer/toolbars.py index 5455953c77..243108f4f5 100644 --- a/src/calibre/gui2/viewer/toolbars.py +++ b/src/calibre/gui2/viewer/toolbars.py @@ -306,10 +306,13 @@ class ActionsToolBar(ToolBar): continue if hasattr(set_book_path, 'pathtoebook') and path == os.path.abspath(set_book_path.pathtoebook): continue - m.addAction('{}\t {}'.format( - elided_text(entry['title'], pos='right', width=250), - elided_text(os.path.basename(path), width=250))).triggered.connect(partial( - self.open_book_at_path.emit, path)) + if os.path.exists(path): + m.addAction('{}\t {}'.format( + elided_text(entry['title'], pos='right', width=250), + elided_text(os.path.basename(path), width=250))).triggered.connect(partial( + self.open_book_at_path.emit, path)) + else: + self.web_view.remove_recently_opened(path) def on_view_created(self, data): self.default_color_schemes = data['default_color_schemes'] diff --git a/src/calibre/gui2/viewer/ui.py b/src/calibre/gui2/viewer/ui.py index 23b0cd94bf..6783bcb6c8 100644 --- a/src/calibre/gui2/viewer/ui.py +++ b/src/calibre/gui2/viewer/ui.py @@ -178,7 +178,7 @@ class EbookViewer(MainWindow): self.web_view.quit.connect(self.quit) self.web_view.update_current_toc_nodes.connect(self.toc.update_current_toc_nodes) self.web_view.toggle_full_screen.connect(self.toggle_full_screen) - self.web_view.ask_for_open.connect(self.ask_for_open, type=Qt.ConnectionType.QueuedConnection) + self.web_view.ask_for_open.connect(self.ask_for_open_from_js, type=Qt.ConnectionType.QueuedConnection) self.web_view.selection_changed.connect(self.lookup_widget.selected_text_changed, type=Qt.ConnectionType.QueuedConnection) self.web_view.selection_changed.connect(self.highlights_widget.selected_text_changed, type=Qt.ConnectionType.QueuedConnection) self.web_view.view_image.connect(self.view_image, type=Qt.ConnectionType.QueuedConnection) @@ -452,6 +452,14 @@ class EbookViewer(MainWindow): self.removeToolBar(toolbar) self.addToolBar(Qt.ToolBarArea.LeftToolBarArea, toolbar) + def ask_for_open_from_js(self, path): + if path and not os.path.exists(path): + self.web_view.remove_recently_opened(path) + error_dialog(self, _('Book does not exist'), _( + 'Cannot open {} as it no longer exists').format(path), show=True) + else: + self.ask_for_open(path) + def ask_for_open(self, path=None): if path is None: files = choose_files( diff --git a/src/calibre/gui2/viewer/web_view.py b/src/calibre/gui2/viewer/web_view.py index 4bff7f438e..6e83ba63cc 100644 --- a/src/calibre/gui2/viewer/web_view.py +++ b/src/calibre/gui2/viewer/web_view.py @@ -753,3 +753,6 @@ class WebView(RestartingWebEngineView): def repair_after_fullscreen_switch(self): self.execute_when_ready('repair_after_fullscreen_switch') + + def remove_recently_opened(self, path): + self.generic_action('remove-recently-opened', {'path': path}) diff --git a/src/pyj/read_book/open_book.pyj b/src/pyj/read_book/open_book.pyj index 33cff6e34b..26b5025a66 100644 --- a/src/pyj/read_book/open_book.pyj +++ b/src/pyj/read_book/open_book.pyj @@ -3,29 +3,42 @@ from __python__ import bound_methods, hash_literals from elementmaker import E -from gettext import gettext as _ from book_list.globals import get_session_data from book_list.item_list import create_item, create_item_list -from dom import unique_id +from dom import clear, unique_id +from gettext import gettext as _ from read_book.globals import ui_operations from widgets import create_button +current_container_id = None +current_opened_book_path = None + def create_open_book(container, book): - container.appendChild(E.div(style='margin: 1rem')) + nonlocal current_container_id, current_opened_book_path + container.appendChild(E.div(style='margin: 1rem', id=unique_id())) container = container.lastChild + current_container_id = container.id + current_opened_book_path = None + if book: + current_opened_book_path = book.manifest.pathtoebook + rebuild_open_list(container) + + +def rebuild_open_list(container): + clear(container) container.appendChild(create_button(_('Open a book from your computer'), action=ui_operations.ask_for_open.bind(None, None))) sd = get_session_data() rl = sd.get('standalone_recently_opened') - if rl.length: + if rl?.length: container.appendChild(E.div(id=unique_id())) c = container.lastChild items = [] c.appendChild(E.h2(style='margin-top: 1rem', _('Recently viewed books'))) c.appendChild(E.div()) for entry in rl: - if book and book.manifest.pathtoebook is entry.pathtoebook: + if current_opened_book_path and current_opened_book_path is entry.pathtoebook: continue if jstype(entry.pathtoebook) is not 'string': continue @@ -62,3 +75,17 @@ def add_book_to_recently_viewed(book): ans.push(entry) sd.set('standalone_recently_opened', ans.slice(0, 25)) return ans + + +def remove_recently_opened(path): + sd = get_session_data() + rl = sd.get('standalone_recently_opened') + newl = v'[]' + for entry in rl: + if entry.key is not path: + newl.push(entry) + sd.set('standalone_recently_opened', newl) + if current_container_id: + container = document.getElementById(current_container_id) + if container: + rebuild_open_list(container) diff --git a/src/pyj/viewer-main.pyj b/src/pyj/viewer-main.pyj index 30aecaeff4..b447d95d50 100644 --- a/src/pyj/viewer-main.pyj +++ b/src/pyj/viewer-main.pyj @@ -2,25 +2,28 @@ # License: GPL v3 Copyright: 2018, Kovid Goyal from __python__ import bound_methods, hash_literals -import traceback from elementmaker import E -from gettext import gettext as _, install -from date import format_date import initialize # noqa: unused-import +import traceback from ajax import ajax, workaround_qt_bug from book_list.globals import get_session_data, set_session_data from book_list.library_data import library_data -from book_list.theme import get_color, css_for_variables +from book_list.theme import css_for_variables, get_color +from date import format_date from dom import get_widget_css, set_css +from gettext import gettext as _, install from modals import create_modal_container from qt import from_python, to_python from read_book.db import new_book from read_book.footnotes import main as footnotes_main -from read_book.globals import runtime, set_system_colors, ui_operations, default_color_schemes +from read_book.globals import ( + default_color_schemes, runtime, set_system_colors, ui_operations +) from read_book.iframe import main as iframe_main -from read_book.view import View +from read_book.open_book import remove_recently_opened from read_book.prefs.head_foot import set_time_formatter +from read_book.view import View from session import local_storage, session_defaults from utils import debounce, encode_query_with_path, parse_url_params from viewer.constants import FAKE_HOST, FAKE_PROTOCOL, READER_BACKGROUND_URL @@ -209,6 +212,8 @@ def generic_action(which, data): view.set_notes_for_highlight(data.uuid, data.notes or '') if which is 'show-status-message': view.show_status_message(data.text) + if which is 'remove-recently-opened': + remove_recently_opened(data.path) @from_python