Implement loading of resources direct from editrs->preview pane

This commit is contained in:
Kovid Goyal 2013-11-06 15:01:22 +05:30
parent 82a0183360
commit a40c6fe846
3 changed files with 87 additions and 17 deletions

View File

@ -24,3 +24,4 @@ def set_current_container(container):
_current_container = container
actions = {}
editors = {}

View File

@ -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.gui2 import error_dialog, choose_files, question_dialog, info_dialog
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.save import SaveManager
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.report_error.connect(self.report_save_error)
self.doing_terminal_save = False
self.editors = {}
def __call__(self, gui):
self.gui = gui
@ -57,7 +56,7 @@ class Boss(QObject):
return tempfile.mkdtemp(prefix='%s%05d-' % (prefix, self.container_count), dir=self.tdir)
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:
return True
return question_dialog(self.gui, _('Unsaved changes'), _(
@ -124,7 +123,7 @@ class Boss(QObject):
self.gui.action_save.setEnabled(True)
self.gui.file_list.delete_done(spine_items, other_items)
for name in list(spine_items) + list(other_items):
if name in self.editors:
if name in editors:
self.close_editor(name)
# TODO: Update other GUI elements
@ -210,7 +209,7 @@ class Boss(QObject):
def save_book(self):
c = current_container()
for name, ed in self.editors.iteritems():
for name, ed in editors.iteritems():
if ed.is_modified:
with c.open(name, 'wb') as f:
f.write(ed.data)
@ -229,9 +228,9 @@ class Boss(QObject):
' for more information.'), det_msg=tb, show=True)
def edit_file(self, name, syntax):
editor = self.editors.get(name, None)
editor = editors.get(name, 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)
self.gui.central.add_editor(name, editor)
c = current_container()
@ -241,8 +240,8 @@ class Boss(QObject):
self.gui.central.show_editor(editor)
def edit_file_requested(self, name, syntax, mime):
if name in self.editors:
self.gui.show_editor(self.editors[name])
if name in editors:
self.gui.show_editor(editors[name])
return
syntax = syntax or syntax_from_mime(mime)
if not syntax:
@ -281,7 +280,7 @@ class Boss(QObject):
def editor_close_requested(self, editor):
name = None
for n, ed in self.editors.iteritems():
for n, ed in editors.iteritems():
if ed is editor:
name = n
if not name:
@ -294,7 +293,7 @@ class Boss(QObject):
self.close_editor(name)
def close_editor(self, name):
editor = self.editors.pop(name)
editor = editors.pop(name)
self.gui.central.close_editor(editor)
editor.break_cycles()
@ -303,7 +302,7 @@ class Boss(QObject):
if ed is None:
return
name = None
for n, x in self.editors.iteritems():
for n, x in editors.iteritems():
if x is ed:
name = n
break
@ -317,7 +316,7 @@ class Boss(QObject):
container = clone_container(c, tdir)
self.save_manager.schedule(tdir, container)
is_modified = False
for ed in self.editors.itervalues():
for ed in editors.itervalues():
if ed.is_modified:
is_modified = True
break

View File

@ -9,9 +9,13 @@ __copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
from threading import Thread
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 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.config import config
from calibre.utils.ipc.simple_worker import offload_worker
@ -56,6 +60,47 @@ class ParseWorker(Thread):
def shutdown(self):
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):
OPERATION_NAMES = {getattr(QNetworkAccessManager, '%sOperation'%x) :
@ -65,7 +110,19 @@ class NetworkAccessManager(QNetworkAccessManager):
def createRequest(self, operation, request, data):
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,
data)
@ -78,9 +135,17 @@ class WebView(QWebView):
settings = self.page().settings()
apply_settings(settings, config().parse())
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.nam = NetworkAccessManager(self)
self.page().setNetworkAccessManager(self.nam)
self.page().setNetworkAccessManager(NetworkAccessManager(self))
def sizeHint(self):
return self._size_hint
@ -96,3 +161,8 @@ class Preview(QWidget):
self.view = WebView(self)
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)))