Populate preview panel when opening/changing editors

This commit is contained in:
Kovid Goyal 2013-11-07 11:10:01 +05:30
parent 087bcee620
commit 53b164d7fb
3 changed files with 73 additions and 12 deletions

View File

@ -593,10 +593,11 @@ def parse_html5(raw, decoder=None, log=None, discard_namespaces=False, line_numb
raise ValueError('Failed to parse correctly, root has tag: %s and prefix: %s' % (root.tag, root.prefix)) raise ValueError('Failed to parse correctly, root has tag: %s and prefix: %s' % (root.tag, root.prefix))
return root return root
def parse(raw, decoder=None, log=None, line_numbers=True, linenumber_attribute=None): def parse(raw, decoder=None, log=None, line_numbers=True, linenumber_attribute=None, replace_entities=True):
if isinstance(raw, bytes): if isinstance(raw, bytes):
raw = xml_to_unicode(raw)[0] if decoder is None else decoder(raw) raw = xml_to_unicode(raw)[0] if decoder is None else decoder(raw)
raw = xml_replace_entities(raw).replace('\0', '') # Handle � if replace_entities:
raw = xml_replace_entities(raw).replace('\0', '') # Handle �
raw = raw.replace('\r\n', '\n').replace('\r', '\n') raw = raw.replace('\r\n', '\n').replace('\r', '\n')
# Remove any preamble before the opening html tag as it can cause problems, # Remove any preamble before the opening html tag as it can cause problems,

View File

@ -232,16 +232,16 @@ class Boss(QObject):
if editor is None: if editor is None:
editor = 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)
c = current_container() c = current_container()
with c.open(name) as f: with c.open(name) as f:
editor.data = c.decode(f.read()) editor.data = c.decode(f.read())
editor.modification_state_changed.connect(self.editor_modification_state_changed) editor.modification_state_changed.connect(self.editor_modification_state_changed)
self.gui.central.add_editor(name, editor)
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 editors: if name in editors:
self.gui.show_editor(editors[name]) self.gui.central.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:
@ -275,6 +275,13 @@ class Boss(QObject):
actions['editor-redo'].setEnabled(ed.redo_available) actions['editor-redo'].setEnabled(ed.redo_available)
actions['editor-save'].setEnabled(ed.is_modified) actions['editor-save'].setEnabled(ed.is_modified)
self.gui.keyboard.set_mode(ed.syntax) self.gui.keyboard.set_mode(ed.syntax)
name = None
for n, x in editors.iteritems():
if ed is x:
name = n
break
if name is not None:
self.gui.preview.show(name)
else: else:
self.gui.keyboard.set_mode('other') self.gui.keyboard.set_mode('other')

View File

@ -6,6 +6,7 @@ from __future__ import (unicode_literals, division, absolute_import,
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>' __copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
import time
from threading import Thread from threading import Thread
from Queue import Queue, Empty from Queue import Queue, Empty
@ -14,7 +15,11 @@ from PyQt4.Qt import (
QNetworkReply, QTimer, QNetworkRequest, QUrl) QNetworkReply, QTimer, QNetworkRequest, QUrl)
from PyQt4.QtWebKit import QWebView from PyQt4.QtWebKit import QWebView
from calibre import prints
from calibre.constants import iswindows from calibre.constants import iswindows
from calibre.ebooks.oeb.polish.parsing import parse
from calibre.ebooks.oeb.base import serialize
from calibre.gui2 import Dispatcher
from calibre.gui2.tweak_book import current_container, editors 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
@ -22,27 +27,36 @@ from calibre.utils.ipc.simple_worker import offload_worker
shutdown = object() shutdown = object()
def parse_html(raw):
root = parse(raw, decoder=lambda x:x.decode('utf-8'), replace_entities=False, line_numbers=True, linenumber_attribute='lnum')
return serialize(root, 'text/html').decode('utf-8')
class ParseWorker(Thread): class ParseWorker(Thread):
daemon = True daemon = True
SLEEP_TIME = 1
def __init__(self): def __init__(self, callback=lambda x, y: None):
Thread.__init__(self) Thread.__init__(self)
self.worker = offload_worker(priority='low') self.worker = offload_worker(priority='low')
self.requests = Queue() self.requests = Queue()
self.request_count = 0 self.request_count = 0
self.start() self.start()
self.cache = {}
self.callback = callback
def run(self): def run(self):
mod, func = 'calibre.gui2.tweak_book.preview', 'parse_html'
try: try:
# Connect to the worker and send a dummy job to initialize it # Connect to the worker and send a dummy job to initialize it
self.worker(None, None, (), {}) self.worker(mod, func, b'<p></p>')
except: except:
import traceback import traceback
traceback.print_exc() traceback.print_exc()
return return
while True: while True:
time.sleep(self.SLEEP_TIME)
x = self.requests.get() x = self.requests.get()
requests = [x] requests = [x]
while True: while True:
@ -55,7 +69,37 @@ class ParseWorker(Thread):
break break
request = sorted(requests, reverse=True)[0] request = sorted(requests, reverse=True)[0]
del requests del requests
request name, data = request[1:]
old_len, old_fp, old_parsed = self.cache.get(name, (None, None, None))
length, fp = len(data), hash(data)
if length == old_len and fp == old_fp:
self.done(name, old_parsed)
continue
try:
res = self.worker(mod, func, data)
except:
import traceback
traceback.print_exc()
else:
parsed_data = res['result']
if res['tb']:
prints("Parser error:")
prints(res['tb'])
else:
self.cache[name] = (length, fp, parsed_data)
self.done(name, parsed_data)
def done(self, name, data):
try:
self.callback(name, data)
except Exception:
import traceback
traceback.print_exc()
def add_request(self, name):
data = get_data(name)
self.requests.put((self.request_count, name, data))
self.request_count += 1
def shutdown(self): def shutdown(self):
self.requests.put(shutdown) self.requests.put(shutdown)
@ -158,12 +202,21 @@ class Preview(QWidget):
self.l = l = QVBoxLayout() self.l = l = QVBoxLayout()
self.setLayout(l) self.setLayout(l)
l.setContentsMargins(0, 0, 0, 0) l.setContentsMargins(0, 0, 0, 0)
self.parse_worker = ParseWorker() self.parse_worker = ParseWorker(callback=Dispatcher(self.parsing_done))
self.view = WebView(self) self.view = WebView(self)
l.addWidget(self.view) l.addWidget(self.view)
def show(self, name): self.current_name = None
data = get_data(name) self.parse_pending = False
c = current_container() self.last_sync_request = None
self.view.setHtml(data, QUrl.fromLocalFile(c.name_to_abspath(name)))
def show(self, name):
self.current_name, self.parse_pending = name, True
self.parse_worker.add_request(name)
def parsing_done(self, name, data):
if name == self.current_name:
c = current_container()
self.view.setHtml(data, QUrl.fromLocalFile(c.name_to_abspath(name)))
self.parse_pending = False