mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Edit book: Add an "Open with" action to the context menu of the files browser to easily open files with external programs. Fixes #1860462 [[Enhancement] External Editor Needed](https://bugs.launchpad.net/calibre/+bug/1860462)
This commit is contained in:
parent
ffef6f303a
commit
d671ccaa49
@ -64,12 +64,14 @@ from calibre.gui2.tweak_book.widgets import (
|
||||
AddCover, BusyCursor, FilterCSS, ImportForeign, InsertLink, InsertSemantics,
|
||||
InsertTag, MultiSplit, QuickOpen, RationalizeFolders
|
||||
)
|
||||
from calibre.ptempfile import TemporaryDirectory
|
||||
from calibre.ptempfile import PersistentTemporaryDirectory, TemporaryDirectory
|
||||
from calibre.utils.config import JSONConfig
|
||||
from calibre.utils.icu import numeric_sort_key
|
||||
from calibre.utils.imghdr import identify
|
||||
from calibre.utils.tdir_in_cache import tdir_in_cache
|
||||
from polyglot.builtins import iteritems, itervalues, string_or_bytes, map, unicode_type
|
||||
from polyglot.builtins import (
|
||||
iteritems, itervalues, map, string_or_bytes, unicode_type
|
||||
)
|
||||
from polyglot.urllib import urlparse
|
||||
|
||||
_diff_dialogs = []
|
||||
@ -138,6 +140,7 @@ class Boss(QObject):
|
||||
fl.link_stylesheets_requested.connect(self.link_stylesheets_requested)
|
||||
fl.initiate_file_copy.connect(self.copy_files_to_clipboard)
|
||||
fl.initiate_file_paste.connect(self.paste_files_from_clipboard)
|
||||
fl.open_file_with.connect(self.open_file_with)
|
||||
self.gui.central.current_editor_changed.connect(self.apply_current_editor_state)
|
||||
self.gui.central.close_requested.connect(self.editor_close_requested)
|
||||
self.gui.central.search_panel.search_triggered.connect(self.search)
|
||||
@ -1361,6 +1364,29 @@ class Boss(QObject):
|
||||
raise
|
||||
self.export_file(name, dest)
|
||||
|
||||
def open_file_with(self, file_name, fmt, entry):
|
||||
if file_name in editors and not editors[file_name].is_synced_to_container:
|
||||
self.commit_editor_to_container(file_name)
|
||||
with current_container().open(file_name) as src:
|
||||
tdir = PersistentTemporaryDirectory(suffix='-ee-ow')
|
||||
with open(os.path.join(tdir, os.path.basename(file_name)), 'wb') as dest:
|
||||
shutil.copyfileobj(src, dest)
|
||||
from calibre.gui2.open_with import run_program
|
||||
run_program(entry, dest.name, self)
|
||||
if question_dialog(self.gui, _('File opened'), _(
|
||||
'When you are done editing {0} click "Update" to update'
|
||||
' the file in the book or "Discard" to lose any changes.').format(file_name),
|
||||
yes_text=_('Import'), no_text=_('Discard')
|
||||
):
|
||||
self.add_savepoint(_('Before: Replace %s') % file_name)
|
||||
with open(dest.name, 'rb') as src, current_container().open(file_name, 'wb') as cdest:
|
||||
shutil.copyfileobj(src, cdest)
|
||||
self.apply_container_update_to_gui()
|
||||
try:
|
||||
shutil.rmtree(tdir)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@in_thread_job
|
||||
def copy_files_to_clipboard(self, names):
|
||||
names = tuple(names)
|
||||
|
@ -202,6 +202,7 @@ class FileList(QTreeWidget):
|
||||
link_stylesheets_requested = pyqtSignal(object, object, object)
|
||||
initiate_file_copy = pyqtSignal(object)
|
||||
initiate_file_paste = pyqtSignal()
|
||||
open_file_with = pyqtSignal(object, object, object)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QTreeWidget.__init__(self, parent)
|
||||
@ -540,6 +541,8 @@ class FileList(QTreeWidget):
|
||||
m.addAction(_('Replace %s with file...') % n, partial(self.replace, cn))
|
||||
if num > 1:
|
||||
m.addAction(QIcon(I('save.png')), _('Export all %d selected files') % num, self.export_selected)
|
||||
if cn not in container.names_that_must_not_be_changed:
|
||||
self.add_open_with_actions(m, cn)
|
||||
|
||||
m.addSeparator()
|
||||
|
||||
@ -583,6 +586,35 @@ class FileList(QTreeWidget):
|
||||
if len(list(m.actions())) > 0:
|
||||
m.popup(self.mapToGlobal(point))
|
||||
|
||||
def add_open_with_actions(self, menu, file_name):
|
||||
from calibre.gui2.open_with import populate_menu, edit_programs
|
||||
fmt = file_name.rpartition('.')[-1].lower()
|
||||
if not fmt:
|
||||
return
|
||||
m = QMenu(_('Open %s with...') % file_name)
|
||||
|
||||
def connect_action(ac, entry):
|
||||
connect_lambda(ac.triggered, self, lambda self: self.open_with(file_name, fmt, entry))
|
||||
|
||||
populate_menu(m, connect_action, fmt)
|
||||
if len(m.actions()) == 0:
|
||||
menu.addAction(_('Open %s with...') % file_name, partial(self.choose_open_with, file_name, fmt))
|
||||
else:
|
||||
m.addSeparator()
|
||||
m.addAction(_('Add other application for %s files...') % fmt.upper(), partial(self.choose_open_with, file_name, fmt))
|
||||
m.addAction(_('Edit Open With applications...'), partial(edit_programs, fmt, file_name))
|
||||
menu.addMenu(m)
|
||||
menu.ow = m
|
||||
|
||||
def choose_open_with(self, file_name, fmt):
|
||||
from calibre.gui2.open_with import choose_program
|
||||
entry = choose_program(fmt, self)
|
||||
if entry is not None:
|
||||
self.open_with(file_name, fmt, entry)
|
||||
|
||||
def open_with(self, file_name, fmt, entry):
|
||||
self.open_file_with.emit(file_name, fmt, entry)
|
||||
|
||||
def index_of_name(self, name):
|
||||
for category, parent in iteritems(self.categories):
|
||||
for i in range(parent.childCount()):
|
||||
|
Loading…
x
Reference in New Issue
Block a user