mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
Basic web view implementation for the new viewer
This commit is contained in:
parent
f6edb4de07
commit
559adc51a2
153
src/calibre/gui2/viewer2/web_view.py
Normal file
153
src/calibre/gui2/viewer2/web_view.py
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
#!/usr/bin/env python2
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||||
|
|
||||||
|
from PyQt5.Qt import QApplication, QBuffer, QByteArray
|
||||||
|
from PyQt5.QtWebEngineCore import QWebEngineUrlSchemeHandler
|
||||||
|
from PyQt5.QtWebEngineWidgets import (
|
||||||
|
QWebEnginePage, QWebEngineProfile, QWebEngineScript
|
||||||
|
)
|
||||||
|
|
||||||
|
from calibre import prints
|
||||||
|
from calibre.constants import (
|
||||||
|
FAKE_HOST, FAKE_PROTOCOL, __version__, is_running_from_develop
|
||||||
|
)
|
||||||
|
from calibre.gui2 import open_url
|
||||||
|
from calibre.gui2.webengine import (
|
||||||
|
Bridge, RestartingWebEngineView, create_script, from_js, insert_scripts,
|
||||||
|
secure_webengine, to_js
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
from PyQt5 import sip
|
||||||
|
except ImportError:
|
||||||
|
import sip
|
||||||
|
|
||||||
|
# Override network access to load data from the book {{{
|
||||||
|
|
||||||
|
|
||||||
|
def get_data(name):
|
||||||
|
raise NotImplementedError('TODO: implement this')
|
||||||
|
|
||||||
|
|
||||||
|
class UrlSchemeHandler(QWebEngineUrlSchemeHandler):
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
QWebEngineUrlSchemeHandler.__init__(self, parent)
|
||||||
|
|
||||||
|
def requestStarted(self, rq):
|
||||||
|
if bytes(rq.requestMethod()) != b'GET':
|
||||||
|
rq.fail(rq.RequestDenied)
|
||||||
|
return
|
||||||
|
url = rq.requestUrl()
|
||||||
|
if url.host() != FAKE_HOST or url.scheme() != FAKE_PROTOCOL:
|
||||||
|
rq.fail(rq.UrlNotFound)
|
||||||
|
return
|
||||||
|
name = url.path()[1:]
|
||||||
|
try:
|
||||||
|
data, mime_type = get_data(name)
|
||||||
|
if data is None:
|
||||||
|
rq.fail(rq.UrlNotFound)
|
||||||
|
return
|
||||||
|
if isinstance(data, type('')):
|
||||||
|
data = data.encode('utf-8')
|
||||||
|
mime_type = {
|
||||||
|
# Prevent warning in console about mimetype of fonts
|
||||||
|
'application/vnd.ms-opentype':'application/x-font-ttf',
|
||||||
|
'application/x-font-truetype':'application/x-font-ttf',
|
||||||
|
'application/font-sfnt': 'application/x-font-ttf',
|
||||||
|
}.get(mime_type, mime_type)
|
||||||
|
self.send_reply(rq, mime_type, data)
|
||||||
|
except Exception:
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
rq.fail(rq.RequestFailed)
|
||||||
|
|
||||||
|
def send_reply(self, rq, mime_type, data):
|
||||||
|
if sip.isdeleted(rq):
|
||||||
|
return
|
||||||
|
buf = QBuffer(parent=rq)
|
||||||
|
buf.open(QBuffer.WriteOnly)
|
||||||
|
# we have to copy data into buf as it will be garbage
|
||||||
|
# collected by python
|
||||||
|
buf.write(data)
|
||||||
|
buf.seek(0)
|
||||||
|
buf.close()
|
||||||
|
buf.aboutToClose.connect(buf.deleteLater)
|
||||||
|
rq.reply(mime_type.encode('ascii'), buf)
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
|
def create_profile():
|
||||||
|
ans = getattr(create_profile, 'ans', None)
|
||||||
|
if ans is None:
|
||||||
|
ans = QWebEngineProfile(QApplication.instance())
|
||||||
|
ua = 'calibre-viewer ' + __version__
|
||||||
|
ans.setHttpUserAgent(ua)
|
||||||
|
if is_running_from_develop:
|
||||||
|
from calibre.utils.rapydscript import compile_editor
|
||||||
|
compile_editor()
|
||||||
|
js = P('editor.js', data=True, allow_user_override=False)
|
||||||
|
cparser = P('csscolorparser.js', data=True, allow_user_override=False)
|
||||||
|
|
||||||
|
insert_scripts(ans,
|
||||||
|
create_script('csscolorparser.js', cparser),
|
||||||
|
create_script('editor.js', js),
|
||||||
|
)
|
||||||
|
url_handler = UrlSchemeHandler(ans)
|
||||||
|
ans.installUrlSchemeHandler(QByteArray(FAKE_PROTOCOL.encode('ascii')), url_handler)
|
||||||
|
s = ans.settings()
|
||||||
|
s.setDefaultTextEncoding('utf-8')
|
||||||
|
s.setAttribute(s.FullScreenSupportEnabled, False)
|
||||||
|
s.setAttribute(s.LinksIncludedInFocusChain, False)
|
||||||
|
create_profile.ans = ans
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
class ViewerBridge(Bridge):
|
||||||
|
|
||||||
|
request_sync = from_js(object, object, object)
|
||||||
|
request_split = from_js(object, object)
|
||||||
|
live_css_data = from_js(object)
|
||||||
|
|
||||||
|
go_to_sourceline_address = to_js()
|
||||||
|
go_to_anchor = to_js()
|
||||||
|
set_split_mode = to_js()
|
||||||
|
live_css = to_js()
|
||||||
|
|
||||||
|
|
||||||
|
class WebPage(QWebEnginePage):
|
||||||
|
|
||||||
|
def __init__(self, parent):
|
||||||
|
QWebEnginePage.__init__(self, create_profile(), parent)
|
||||||
|
secure_webengine(self, for_viewer=True)
|
||||||
|
self.bridge = ViewerBridge(self)
|
||||||
|
|
||||||
|
def javaScriptConsoleMessage(self, level, msg, linenumber, source_id):
|
||||||
|
prints('%s:%s: %s' % (source_id, linenumber, msg))
|
||||||
|
|
||||||
|
def acceptNavigationRequest(self, url, req_type, is_main_frame):
|
||||||
|
if req_type == self.NavigationTypeReload:
|
||||||
|
return True
|
||||||
|
if url.scheme() in (FAKE_PROTOCOL, 'data'):
|
||||||
|
return True
|
||||||
|
open_url(url)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def go_to_anchor(self, anchor):
|
||||||
|
self.bridge.go_to_anchor.emit(anchor or '')
|
||||||
|
|
||||||
|
def runjs(self, src, callback=None):
|
||||||
|
if callback is None:
|
||||||
|
self.runJavaScript(src, QWebEngineScript.ApplicationWorld)
|
||||||
|
else:
|
||||||
|
self.runJavaScript(src, QWebEngineScript.ApplicationWorld, callback)
|
||||||
|
|
||||||
|
|
||||||
|
class WebView(RestartingWebEngineView):
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
RestartingWebEngineView.__init__(self, parent)
|
Loading…
x
Reference in New Issue
Block a user