mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Implement loading of resources direct from editrs->preview pane
This commit is contained in:
parent
82a0183360
commit
a40c6fe846
@ -24,3 +24,4 @@ def set_current_container(container):
|
|||||||
_current_container = container
|
_current_container = container
|
||||||
|
|
||||||
actions = {}
|
actions = {}
|
||||||
|
editors = {}
|
||||||
|
@ -21,7 +21,7 @@ from calibre.ebooks.oeb.polish.container import get_container as _gc, clone_cont
|
|||||||
from calibre.ebooks.oeb.polish.replace import rename_files
|
from calibre.ebooks.oeb.polish.replace import rename_files
|
||||||
from calibre.gui2 import error_dialog, choose_files, question_dialog, info_dialog
|
from calibre.gui2 import error_dialog, choose_files, question_dialog, info_dialog
|
||||||
from calibre.gui2.dialogs.confirm_delete import confirm
|
from calibre.gui2.dialogs.confirm_delete import confirm
|
||||||
from calibre.gui2.tweak_book import set_current_container, current_container, tprefs, actions
|
from calibre.gui2.tweak_book import set_current_container, current_container, tprefs, actions, editors
|
||||||
from calibre.gui2.tweak_book.undo import GlobalUndoHistory
|
from calibre.gui2.tweak_book.undo import GlobalUndoHistory
|
||||||
from calibre.gui2.tweak_book.save import SaveManager
|
from calibre.gui2.tweak_book.save import SaveManager
|
||||||
from calibre.gui2.tweak_book.editor import editor_from_syntax, syntax_from_mime
|
from calibre.gui2.tweak_book.editor import editor_from_syntax, syntax_from_mime
|
||||||
@ -40,7 +40,6 @@ class Boss(QObject):
|
|||||||
self.save_manager = SaveManager(parent)
|
self.save_manager = SaveManager(parent)
|
||||||
self.save_manager.report_error.connect(self.report_save_error)
|
self.save_manager.report_error.connect(self.report_save_error)
|
||||||
self.doing_terminal_save = False
|
self.doing_terminal_save = False
|
||||||
self.editors = {}
|
|
||||||
|
|
||||||
def __call__(self, gui):
|
def __call__(self, gui):
|
||||||
self.gui = gui
|
self.gui = gui
|
||||||
@ -57,7 +56,7 @@ class Boss(QObject):
|
|||||||
return tempfile.mkdtemp(prefix='%s%05d-' % (prefix, self.container_count), dir=self.tdir)
|
return tempfile.mkdtemp(prefix='%s%05d-' % (prefix, self.container_count), dir=self.tdir)
|
||||||
|
|
||||||
def check_dirtied(self):
|
def check_dirtied(self):
|
||||||
dirtied = {name for name, ed in self.editors.iteritems() if ed.is_modified}
|
dirtied = {name for name, ed in editors.iteritems() if ed.is_modified}
|
||||||
if not dirtied:
|
if not dirtied:
|
||||||
return True
|
return True
|
||||||
return question_dialog(self.gui, _('Unsaved changes'), _(
|
return question_dialog(self.gui, _('Unsaved changes'), _(
|
||||||
@ -124,7 +123,7 @@ class Boss(QObject):
|
|||||||
self.gui.action_save.setEnabled(True)
|
self.gui.action_save.setEnabled(True)
|
||||||
self.gui.file_list.delete_done(spine_items, other_items)
|
self.gui.file_list.delete_done(spine_items, other_items)
|
||||||
for name in list(spine_items) + list(other_items):
|
for name in list(spine_items) + list(other_items):
|
||||||
if name in self.editors:
|
if name in editors:
|
||||||
self.close_editor(name)
|
self.close_editor(name)
|
||||||
# TODO: Update other GUI elements
|
# TODO: Update other GUI elements
|
||||||
|
|
||||||
@ -210,7 +209,7 @@ class Boss(QObject):
|
|||||||
|
|
||||||
def save_book(self):
|
def save_book(self):
|
||||||
c = current_container()
|
c = current_container()
|
||||||
for name, ed in self.editors.iteritems():
|
for name, ed in editors.iteritems():
|
||||||
if ed.is_modified:
|
if ed.is_modified:
|
||||||
with c.open(name, 'wb') as f:
|
with c.open(name, 'wb') as f:
|
||||||
f.write(ed.data)
|
f.write(ed.data)
|
||||||
@ -229,9 +228,9 @@ class Boss(QObject):
|
|||||||
' for more information.'), det_msg=tb, show=True)
|
' for more information.'), det_msg=tb, show=True)
|
||||||
|
|
||||||
def edit_file(self, name, syntax):
|
def edit_file(self, name, syntax):
|
||||||
editor = self.editors.get(name, None)
|
editor = editors.get(name, None)
|
||||||
if editor is None:
|
if editor is None:
|
||||||
editor = self.editors[name] = editor_from_syntax(syntax, self.gui.editor_tabs)
|
editor = editors[name] = editor_from_syntax(syntax, self.gui.editor_tabs)
|
||||||
editor.undo_redo_state_changed.connect(self.editor_undo_redo_state_changed)
|
editor.undo_redo_state_changed.connect(self.editor_undo_redo_state_changed)
|
||||||
self.gui.central.add_editor(name, editor)
|
self.gui.central.add_editor(name, editor)
|
||||||
c = current_container()
|
c = current_container()
|
||||||
@ -241,8 +240,8 @@ class Boss(QObject):
|
|||||||
self.gui.central.show_editor(editor)
|
self.gui.central.show_editor(editor)
|
||||||
|
|
||||||
def edit_file_requested(self, name, syntax, mime):
|
def edit_file_requested(self, name, syntax, mime):
|
||||||
if name in self.editors:
|
if name in editors:
|
||||||
self.gui.show_editor(self.editors[name])
|
self.gui.show_editor(editors[name])
|
||||||
return
|
return
|
||||||
syntax = syntax or syntax_from_mime(mime)
|
syntax = syntax or syntax_from_mime(mime)
|
||||||
if not syntax:
|
if not syntax:
|
||||||
@ -281,7 +280,7 @@ class Boss(QObject):
|
|||||||
|
|
||||||
def editor_close_requested(self, editor):
|
def editor_close_requested(self, editor):
|
||||||
name = None
|
name = None
|
||||||
for n, ed in self.editors.iteritems():
|
for n, ed in editors.iteritems():
|
||||||
if ed is editor:
|
if ed is editor:
|
||||||
name = n
|
name = n
|
||||||
if not name:
|
if not name:
|
||||||
@ -294,7 +293,7 @@ class Boss(QObject):
|
|||||||
self.close_editor(name)
|
self.close_editor(name)
|
||||||
|
|
||||||
def close_editor(self, name):
|
def close_editor(self, name):
|
||||||
editor = self.editors.pop(name)
|
editor = editors.pop(name)
|
||||||
self.gui.central.close_editor(editor)
|
self.gui.central.close_editor(editor)
|
||||||
editor.break_cycles()
|
editor.break_cycles()
|
||||||
|
|
||||||
@ -303,7 +302,7 @@ class Boss(QObject):
|
|||||||
if ed is None:
|
if ed is None:
|
||||||
return
|
return
|
||||||
name = None
|
name = None
|
||||||
for n, x in self.editors.iteritems():
|
for n, x in editors.iteritems():
|
||||||
if x is ed:
|
if x is ed:
|
||||||
name = n
|
name = n
|
||||||
break
|
break
|
||||||
@ -317,7 +316,7 @@ class Boss(QObject):
|
|||||||
container = clone_container(c, tdir)
|
container = clone_container(c, tdir)
|
||||||
self.save_manager.schedule(tdir, container)
|
self.save_manager.schedule(tdir, container)
|
||||||
is_modified = False
|
is_modified = False
|
||||||
for ed in self.editors.itervalues():
|
for ed in editors.itervalues():
|
||||||
if ed.is_modified:
|
if ed.is_modified:
|
||||||
is_modified = True
|
is_modified = True
|
||||||
break
|
break
|
||||||
|
@ -9,9 +9,13 @@ __copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
|||||||
from threading import Thread
|
from threading import Thread
|
||||||
from Queue import Queue, Empty
|
from Queue import Queue, Empty
|
||||||
|
|
||||||
from PyQt4.Qt import (QWidget, QVBoxLayout, QApplication, QSize, QNetworkAccessManager)
|
from PyQt4.Qt import (
|
||||||
|
QWidget, QVBoxLayout, QApplication, QSize, QNetworkAccessManager,
|
||||||
|
QNetworkReply, QTimer, QNetworkRequest, QUrl)
|
||||||
from PyQt4.QtWebKit import QWebView
|
from PyQt4.QtWebKit import QWebView
|
||||||
|
|
||||||
|
from calibre.constants import iswindows
|
||||||
|
from calibre.gui2.tweak_book import current_container, editors
|
||||||
from calibre.gui2.viewer.documentview import apply_settings
|
from calibre.gui2.viewer.documentview import apply_settings
|
||||||
from calibre.gui2.viewer.config import config
|
from calibre.gui2.viewer.config import config
|
||||||
from calibre.utils.ipc.simple_worker import offload_worker
|
from calibre.utils.ipc.simple_worker import offload_worker
|
||||||
@ -56,6 +60,47 @@ class ParseWorker(Thread):
|
|||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
self.requests.put(shutdown)
|
self.requests.put(shutdown)
|
||||||
|
|
||||||
|
|
||||||
|
class LocalNetworkReply(QNetworkReply):
|
||||||
|
|
||||||
|
def __init__(self, parent, request, mime_type, data):
|
||||||
|
QNetworkReply.__init__(self, parent)
|
||||||
|
self.setOpenMode(QNetworkReply.ReadOnly | QNetworkReply.Unbuffered)
|
||||||
|
self.__data = data
|
||||||
|
self.setRequest(request)
|
||||||
|
self.setUrl(request.url())
|
||||||
|
self.setHeader(QNetworkRequest.ContentTypeHeader, mime_type)
|
||||||
|
self.setHeader(QNetworkRequest.ContentLengthHeader, len(self.__data))
|
||||||
|
QTimer.singleShot(0, self.finalize_reply)
|
||||||
|
|
||||||
|
def bytesAvailable(self):
|
||||||
|
return len(self.__data)
|
||||||
|
|
||||||
|
def isSequential(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def abort(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def readData(self, maxlen):
|
||||||
|
ans, self.__data = self.__data[:maxlen], self.__data[maxlen:]
|
||||||
|
return ans
|
||||||
|
read = readData
|
||||||
|
|
||||||
|
def finalize_reply(self):
|
||||||
|
self.setFinished(True)
|
||||||
|
self.setAttribute(QNetworkRequest.HttpStatusCodeAttribute, 200)
|
||||||
|
self.setAttribute(QNetworkRequest.HttpReasonPhraseAttribute, "Ok")
|
||||||
|
self.metaDataChanged.emit()
|
||||||
|
self.downloadProgress.emit(len(self.__data), len(self.__data))
|
||||||
|
self.readyRead.emit()
|
||||||
|
self.finished.emit()
|
||||||
|
|
||||||
|
def get_data(name):
|
||||||
|
if name in editors:
|
||||||
|
return editors[name].data
|
||||||
|
return current_container().open(name).read()
|
||||||
|
|
||||||
class NetworkAccessManager(QNetworkAccessManager):
|
class NetworkAccessManager(QNetworkAccessManager):
|
||||||
|
|
||||||
OPERATION_NAMES = {getattr(QNetworkAccessManager, '%sOperation'%x) :
|
OPERATION_NAMES = {getattr(QNetworkAccessManager, '%sOperation'%x) :
|
||||||
@ -65,7 +110,19 @@ class NetworkAccessManager(QNetworkAccessManager):
|
|||||||
|
|
||||||
def createRequest(self, operation, request, data):
|
def createRequest(self, operation, request, data):
|
||||||
url = unicode(request.url().toString())
|
url = unicode(request.url().toString())
|
||||||
print (url)
|
if url.startswith('file://'):
|
||||||
|
path = url[7:]
|
||||||
|
if iswindows and path.startswith('/'):
|
||||||
|
path = path[1:]
|
||||||
|
c = current_container()
|
||||||
|
name = c.abspath_to_name(path)
|
||||||
|
if c.has_name(name):
|
||||||
|
try:
|
||||||
|
return LocalNetworkReply(self, request, c.mime_map.get(name, 'application/octet-stream'),
|
||||||
|
get_data(name) if operation == self.GetOperation else b'')
|
||||||
|
except Exception:
|
||||||
|
import traceback
|
||||||
|
traceback.print_stack()
|
||||||
return QNetworkAccessManager.createRequest(self, operation, request,
|
return QNetworkAccessManager.createRequest(self, operation, request,
|
||||||
data)
|
data)
|
||||||
|
|
||||||
@ -78,9 +135,17 @@ class WebView(QWebView):
|
|||||||
settings = self.page().settings()
|
settings = self.page().settings()
|
||||||
apply_settings(settings, config().parse())
|
apply_settings(settings, config().parse())
|
||||||
settings.setMaximumPagesInCache(0)
|
settings.setMaximumPagesInCache(0)
|
||||||
|
settings.setAttribute(settings.JavaEnabled, False)
|
||||||
|
settings.setAttribute(settings.PluginsEnabled, False)
|
||||||
|
settings.setAttribute(settings.PrivateBrowsingEnabled, True)
|
||||||
|
settings.setAttribute(settings.JavascriptCanOpenWindows, False)
|
||||||
|
settings.setAttribute(settings.JavascriptCanAccessClipboard, False)
|
||||||
|
settings.setAttribute(settings.LinksIncludedInFocusChain, False)
|
||||||
|
settings.setAttribute(settings.DeveloperExtrasEnabled, True)
|
||||||
|
settings.setDefaultTextEncoding('utf-8')
|
||||||
|
|
||||||
self.setHtml('<p>')
|
self.setHtml('<p>')
|
||||||
self.nam = NetworkAccessManager(self)
|
self.page().setNetworkAccessManager(NetworkAccessManager(self))
|
||||||
self.page().setNetworkAccessManager(self.nam)
|
|
||||||
|
|
||||||
def sizeHint(self):
|
def sizeHint(self):
|
||||||
return self._size_hint
|
return self._size_hint
|
||||||
@ -96,3 +161,8 @@ class Preview(QWidget):
|
|||||||
self.view = WebView(self)
|
self.view = WebView(self)
|
||||||
l.addWidget(self.view)
|
l.addWidget(self.view)
|
||||||
|
|
||||||
|
def show(self, name):
|
||||||
|
data = get_data(name)
|
||||||
|
c = current_container()
|
||||||
|
self.view.setHtml(data, QUrl.fromLocalFile(c.name_to_abspath(name)))
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user