Viewer: Allow editing the current book by pressing ctrl+alt+e or adding a button for it to the viewer toolbar. Fixes #1917967 [Enhancement Request: ebook-viewer: Button to open book in editor](https://bugs.launchpad.net/calibre/+bug/1917967)

This commit is contained in:
Kovid Goyal 2021-03-09 14:06:59 +05:30
parent e57e255d3a
commit 09627ab8dd
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
7 changed files with 72 additions and 23 deletions

View File

@ -68,6 +68,7 @@ def all_actions():
'toggle_read_aloud': Action('bullhorn.png', _('Read aloud'), 'toggle_read_aloud'),
'toggle_highlights': Action('highlight_only_on.png', _('Browse highlights in book'), 'toggle_highlights'),
'select_all': Action('edit-select-all.png', _('Select all text in the current file')),
'edit_book': Action('edit_book.png', _('Edit this book'), 'edit_book'),
}
all_actions.ans = Actions(amap)
return all_actions.ans
@ -193,6 +194,7 @@ class ActionsToolBar(ToolBar):
self.print_action = shortcut_action('print')
self.preferences_action = shortcut_action('preferences')
self.metadata_action = shortcut_action('metadata')
self.edit_book_action = shortcut_action('edit_book')
self.update_mode_action()
self.color_scheme_action = a = QAction(aa.color_scheme.icon, aa.color_scheme.text, self)
self.color_scheme_menu = m = QMenu(self)

View File

@ -17,9 +17,10 @@ from qt.core import (
from threading import Thread
from calibre import prints
from calibre.constants import ismacos
from calibre.customize.ui import available_input_formats
from calibre.db.annotations import merge_annotations
from calibre.gui2 import choose_files, error_dialog
from calibre.gui2 import choose_files, error_dialog, sanitize_env_vars
from calibre.gui2.dialogs.drm_error import DRMErrorMessage
from calibre.gui2.image_popup import ImagePopup
from calibre.gui2.main_window import MainWindow
@ -189,6 +190,7 @@ class EbookViewer(MainWindow):
self.web_view.scrollbar_context_menu.connect(self.scrollbar_context_menu)
self.web_view.close_prep_finished.connect(self.close_prep_finished)
self.web_view.highlights_changed.connect(self.highlights_changed)
self.web_view.edit_book.connect(self.edit_book)
self.actions_toolbar.initialize(self.web_view, self.search_dock.toggleViewAction())
self.setCentralWidget(self.web_view)
self.loading_overlay = LoadingOverlay(self)
@ -639,6 +641,29 @@ class EbookViewer(MainWindow):
self.highlights_widget.refresh(highlights)
self.save_annotations()
def edit_book(self, file_name, progress_frac):
import subprocess
from calibre.ebooks.oeb.polish.main import SUPPORTED
from calibre.utils.ipc.launch import exe_path, macos_edit_book_bundle_path
try:
path = set_book_path.pathtoebook
except AttributeError:
return error_dialog(self, _('Cannot edit book'), _(
'No book is currently open'), show=True)
fmt = path.rpartition('.')[-1].upper().replace('ORIGINAL_', '')
if fmt not in SUPPORTED:
return error_dialog(self, _('Cannot edit book'), _(
'The book must be in the %s formats to edit.'
'\n\nFirst convert the book to one of these formats.'
) % (_(' or ').join(SUPPORTED)), show=True)
exe = 'ebook-edit'
if ismacos:
exe = os.path.join(macos_edit_book_bundle_path(), exe)
else:
exe = exe_path(exe)
with sanitize_env_vars():
subprocess.Popen([exe, path, file_name])
def save_state(self):
with vprefs:
vprefs['main_window_state'] = bytearray(self.saveState(self.MAIN_WINDOW_STATE_VERSION))

View File

@ -273,6 +273,7 @@ class ViewerBridge(Bridge):
open_url = from_js(object)
speak_simple_text = from_js(object)
tts = from_js(object, object)
edit_book = from_js(object, object)
create_view = to_js()
start_book_load = to_js()
@ -472,6 +473,7 @@ class WebView(RestartingWebEngineView):
scrollbar_context_menu = pyqtSignal(object, object, object)
close_prep_finished = pyqtSignal(object)
highlights_changed = pyqtSignal(object)
edit_book = pyqtSignal(object, object)
shortcuts_changed = pyqtSignal(object)
paged_mode_changed = pyqtSignal()
standalone_misc_settings_changed = pyqtSignal(object)
@ -532,6 +534,7 @@ class WebView(RestartingWebEngineView):
self.bridge.scrollbar_context_menu.connect(self.scrollbar_context_menu)
self.bridge.close_prep_finished.connect(self.close_prep_finished)
self.bridge.highlights_changed.connect(self.highlights_changed)
self.bridge.edit_book.connect(self.edit_book)
self.bridge.open_url.connect(safe_open_url)
self.bridge.speak_simple_text.connect(self.tts.speak_simple_text)
self.bridge.tts.connect(self.tts.action)

View File

@ -30,6 +30,33 @@ def renice(niceness):
pass
def macos_edit_book_bundle_path():
base = os.path.dirname(sys.executables_location)
return os.path.join(base, 'ebook-viewer.app/Contents/ebook-edit.app/Contents/MacOS/')
def exe_path(exe_name):
if hasattr(sys, 'running_from_setup'):
return [sys.executable, os.path.join(sys.setup_dir, 'run-calibre-worker.py')]
if getattr(sys, 'run_local', False):
return [sys.executable, sys.run_local, exe_name]
e = exe_name
if iswindows:
return os.path.join(os.path.dirname(sys.executable),
e+'.exe' if isfrozen else 'Scripts\\%s.exe'%e)
if ismacos:
return os.path.join(sys.executables_location, e)
if isfrozen:
return os.path.join(sys.executables_location, e)
if hasattr(sys, 'executables_location'):
c = os.path.join(sys.executables_location, e)
if os.access(c, os.X_OK):
return c
return e
class Worker:
'''
Platform independent object for launching child processes. All processes
@ -47,25 +74,7 @@ class Worker:
@property
def executable(self):
if hasattr(sys, 'running_from_setup'):
return [sys.executable, os.path.join(sys.setup_dir, 'run-calibre-worker.py')]
if getattr(sys, 'run_local', False):
return [sys.executable, sys.run_local, self.exe_name]
e = self.exe_name
if iswindows:
return os.path.join(os.path.dirname(sys.executable),
e+'.exe' if isfrozen else 'Scripts\\%s.exe'%e)
if ismacos:
return os.path.join(sys.executables_location, e)
if isfrozen:
return os.path.join(sys.executables_location, e)
if hasattr(sys, 'executables_location'):
c = os.path.join(sys.executables_location, e)
if os.access(c, os.X_OK):
return c
return e
return exe_path(self.exe_name)
@property
def gui_executable(self):
@ -74,8 +83,7 @@ class Worker:
base = os.path.dirname(sys.executables_location)
return os.path.join(base, 'ebook-viewer.app/Contents/MacOS/', self.exe_name)
if self.job_name == 'ebook-edit':
base = os.path.dirname(sys.executables_location)
return os.path.join(base, 'ebook-viewer.app/Contents/ebook-edit.app/Contents/MacOS/', self.exe_name)
return os.path.join(macos_edit_book_bundle_path(), self.exe_name)
return os.path.join(sys.executables_location, self.exe_name)

View File

@ -432,6 +432,13 @@ def add_standalone_viewer_shortcuts(sc):
_('Toggle the highlights panel')
)
sc['edit_book'] = desc(
"Ctrl+Alt+e",
'ui',
_('Edit this book')
)
def create_shortcut_map(custom_shortcuts):
ans = {}

View File

@ -17,7 +17,7 @@ from read_book.annotations import AnnotationsManager
from read_book.bookmarks import create_new_bookmark
from read_book.content_popup import ContentPopupOverlay
from read_book.globals import (
current_book, is_dark_theme, rtl_page_progression, runtime,
current_book, current_spine_item, is_dark_theme, rtl_page_progression, runtime,
set_current_spine_item, ui_operations
)
from read_book.goto import get_next_section
@ -555,6 +555,8 @@ class View:
self.show_chrome({'initial_panel': 'show_prefs'})
elif data.name is 'metadata':
self.overlay.show_metadata()
elif data.name is 'edit_book':
ui_operations.edit_book(current_spine_item(), self.current_file_progress_frac)
elif data.name is 'goto_location':
self.overlay.show_ask_for_location()
elif data.name is 'shrink_selection_by_word':

View File

@ -419,6 +419,8 @@ if window is window.top:
to_python.speak_simple_text(text)
ui_operations.tts = def(action, data):
to_python.tts(action, data or v'{}')
ui_operations.edit_book = def (spine_name, frac):
to_python.edit_book(spine_name, frac)
document.body.appendChild(E.div(id='view'))
window.onerror = onerror