mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 02:34:06 -04:00
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:
parent
e57e255d3a
commit
09627ab8dd
@ -68,6 +68,7 @@ def all_actions():
|
|||||||
'toggle_read_aloud': Action('bullhorn.png', _('Read aloud'), 'toggle_read_aloud'),
|
'toggle_read_aloud': Action('bullhorn.png', _('Read aloud'), 'toggle_read_aloud'),
|
||||||
'toggle_highlights': Action('highlight_only_on.png', _('Browse highlights in book'), 'toggle_highlights'),
|
'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')),
|
'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)
|
all_actions.ans = Actions(amap)
|
||||||
return all_actions.ans
|
return all_actions.ans
|
||||||
@ -193,6 +194,7 @@ class ActionsToolBar(ToolBar):
|
|||||||
self.print_action = shortcut_action('print')
|
self.print_action = shortcut_action('print')
|
||||||
self.preferences_action = shortcut_action('preferences')
|
self.preferences_action = shortcut_action('preferences')
|
||||||
self.metadata_action = shortcut_action('metadata')
|
self.metadata_action = shortcut_action('metadata')
|
||||||
|
self.edit_book_action = shortcut_action('edit_book')
|
||||||
self.update_mode_action()
|
self.update_mode_action()
|
||||||
self.color_scheme_action = a = QAction(aa.color_scheme.icon, aa.color_scheme.text, self)
|
self.color_scheme_action = a = QAction(aa.color_scheme.icon, aa.color_scheme.text, self)
|
||||||
self.color_scheme_menu = m = QMenu(self)
|
self.color_scheme_menu = m = QMenu(self)
|
||||||
|
@ -17,9 +17,10 @@ from qt.core import (
|
|||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
||||||
from calibre import prints
|
from calibre import prints
|
||||||
|
from calibre.constants import ismacos
|
||||||
from calibre.customize.ui import available_input_formats
|
from calibre.customize.ui import available_input_formats
|
||||||
from calibre.db.annotations import merge_annotations
|
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.dialogs.drm_error import DRMErrorMessage
|
||||||
from calibre.gui2.image_popup import ImagePopup
|
from calibre.gui2.image_popup import ImagePopup
|
||||||
from calibre.gui2.main_window import MainWindow
|
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.scrollbar_context_menu.connect(self.scrollbar_context_menu)
|
||||||
self.web_view.close_prep_finished.connect(self.close_prep_finished)
|
self.web_view.close_prep_finished.connect(self.close_prep_finished)
|
||||||
self.web_view.highlights_changed.connect(self.highlights_changed)
|
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.actions_toolbar.initialize(self.web_view, self.search_dock.toggleViewAction())
|
||||||
self.setCentralWidget(self.web_view)
|
self.setCentralWidget(self.web_view)
|
||||||
self.loading_overlay = LoadingOverlay(self)
|
self.loading_overlay = LoadingOverlay(self)
|
||||||
@ -639,6 +641,29 @@ class EbookViewer(MainWindow):
|
|||||||
self.highlights_widget.refresh(highlights)
|
self.highlights_widget.refresh(highlights)
|
||||||
self.save_annotations()
|
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):
|
def save_state(self):
|
||||||
with vprefs:
|
with vprefs:
|
||||||
vprefs['main_window_state'] = bytearray(self.saveState(self.MAIN_WINDOW_STATE_VERSION))
|
vprefs['main_window_state'] = bytearray(self.saveState(self.MAIN_WINDOW_STATE_VERSION))
|
||||||
|
@ -273,6 +273,7 @@ class ViewerBridge(Bridge):
|
|||||||
open_url = from_js(object)
|
open_url = from_js(object)
|
||||||
speak_simple_text = from_js(object)
|
speak_simple_text = from_js(object)
|
||||||
tts = from_js(object, object)
|
tts = from_js(object, object)
|
||||||
|
edit_book = from_js(object, object)
|
||||||
|
|
||||||
create_view = to_js()
|
create_view = to_js()
|
||||||
start_book_load = to_js()
|
start_book_load = to_js()
|
||||||
@ -472,6 +473,7 @@ class WebView(RestartingWebEngineView):
|
|||||||
scrollbar_context_menu = pyqtSignal(object, object, object)
|
scrollbar_context_menu = pyqtSignal(object, object, object)
|
||||||
close_prep_finished = pyqtSignal(object)
|
close_prep_finished = pyqtSignal(object)
|
||||||
highlights_changed = pyqtSignal(object)
|
highlights_changed = pyqtSignal(object)
|
||||||
|
edit_book = pyqtSignal(object, object)
|
||||||
shortcuts_changed = pyqtSignal(object)
|
shortcuts_changed = pyqtSignal(object)
|
||||||
paged_mode_changed = pyqtSignal()
|
paged_mode_changed = pyqtSignal()
|
||||||
standalone_misc_settings_changed = pyqtSignal(object)
|
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.scrollbar_context_menu.connect(self.scrollbar_context_menu)
|
||||||
self.bridge.close_prep_finished.connect(self.close_prep_finished)
|
self.bridge.close_prep_finished.connect(self.close_prep_finished)
|
||||||
self.bridge.highlights_changed.connect(self.highlights_changed)
|
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.open_url.connect(safe_open_url)
|
||||||
self.bridge.speak_simple_text.connect(self.tts.speak_simple_text)
|
self.bridge.speak_simple_text.connect(self.tts.speak_simple_text)
|
||||||
self.bridge.tts.connect(self.tts.action)
|
self.bridge.tts.connect(self.tts.action)
|
||||||
|
@ -30,6 +30,33 @@ def renice(niceness):
|
|||||||
pass
|
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:
|
class Worker:
|
||||||
'''
|
'''
|
||||||
Platform independent object for launching child processes. All processes
|
Platform independent object for launching child processes. All processes
|
||||||
@ -47,25 +74,7 @@ class Worker:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def executable(self):
|
def executable(self):
|
||||||
if hasattr(sys, 'running_from_setup'):
|
return exe_path(self.exe_name)
|
||||||
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
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def gui_executable(self):
|
def gui_executable(self):
|
||||||
@ -74,8 +83,7 @@ class Worker:
|
|||||||
base = os.path.dirname(sys.executables_location)
|
base = os.path.dirname(sys.executables_location)
|
||||||
return os.path.join(base, 'ebook-viewer.app/Contents/MacOS/', self.exe_name)
|
return os.path.join(base, 'ebook-viewer.app/Contents/MacOS/', self.exe_name)
|
||||||
if self.job_name == 'ebook-edit':
|
if self.job_name == 'ebook-edit':
|
||||||
base = os.path.dirname(sys.executables_location)
|
return os.path.join(macos_edit_book_bundle_path(), self.exe_name)
|
||||||
return os.path.join(base, 'ebook-viewer.app/Contents/ebook-edit.app/Contents/MacOS/', self.exe_name)
|
|
||||||
|
|
||||||
return os.path.join(sys.executables_location, self.exe_name)
|
return os.path.join(sys.executables_location, self.exe_name)
|
||||||
|
|
||||||
|
@ -432,6 +432,13 @@ def add_standalone_viewer_shortcuts(sc):
|
|||||||
_('Toggle the highlights panel')
|
_('Toggle the highlights panel')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
sc['edit_book'] = desc(
|
||||||
|
"Ctrl+Alt+e",
|
||||||
|
'ui',
|
||||||
|
_('Edit this book')
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def create_shortcut_map(custom_shortcuts):
|
def create_shortcut_map(custom_shortcuts):
|
||||||
ans = {}
|
ans = {}
|
||||||
|
@ -17,7 +17,7 @@ from read_book.annotations import AnnotationsManager
|
|||||||
from read_book.bookmarks import create_new_bookmark
|
from read_book.bookmarks import create_new_bookmark
|
||||||
from read_book.content_popup import ContentPopupOverlay
|
from read_book.content_popup import ContentPopupOverlay
|
||||||
from read_book.globals import (
|
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
|
set_current_spine_item, ui_operations
|
||||||
)
|
)
|
||||||
from read_book.goto import get_next_section
|
from read_book.goto import get_next_section
|
||||||
@ -555,6 +555,8 @@ class View:
|
|||||||
self.show_chrome({'initial_panel': 'show_prefs'})
|
self.show_chrome({'initial_panel': 'show_prefs'})
|
||||||
elif data.name is 'metadata':
|
elif data.name is 'metadata':
|
||||||
self.overlay.show_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':
|
elif data.name is 'goto_location':
|
||||||
self.overlay.show_ask_for_location()
|
self.overlay.show_ask_for_location()
|
||||||
elif data.name is 'shrink_selection_by_word':
|
elif data.name is 'shrink_selection_by_word':
|
||||||
|
@ -419,6 +419,8 @@ if window is window.top:
|
|||||||
to_python.speak_simple_text(text)
|
to_python.speak_simple_text(text)
|
||||||
ui_operations.tts = def(action, data):
|
ui_operations.tts = def(action, data):
|
||||||
to_python.tts(action, data or v'{}')
|
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'))
|
document.body.appendChild(E.div(id='view'))
|
||||||
window.onerror = onerror
|
window.onerror = onerror
|
||||||
|
Loading…
x
Reference in New Issue
Block a user