mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Try restarting the render process on crash
Also only load the link reports web view on demand
This commit is contained in:
parent
c9b2578b33
commit
c6d6716965
@ -146,6 +146,7 @@ class Boss(QObject):
|
|||||||
self.gui.preview.split_start_requested.connect(self.split_start_requested)
|
self.gui.preview.split_start_requested.connect(self.split_start_requested)
|
||||||
self.gui.preview.split_requested.connect(self.split_requested)
|
self.gui.preview.split_requested.connect(self.split_requested)
|
||||||
self.gui.preview.link_clicked.connect(self.link_clicked)
|
self.gui.preview.link_clicked.connect(self.link_clicked)
|
||||||
|
self.gui.preview.render_process_restarted.connect(self.report_render_process_restart)
|
||||||
self.gui.check_book.item_activated.connect(self.check_item_activated)
|
self.gui.check_book.item_activated.connect(self.check_item_activated)
|
||||||
self.gui.check_book.check_requested.connect(self.check_requested)
|
self.gui.check_book.check_requested.connect(self.check_requested)
|
||||||
self.gui.check_book.fix_requested.connect(self.fix_requested)
|
self.gui.check_book.fix_requested.connect(self.fix_requested)
|
||||||
@ -170,6 +171,9 @@ class Boss(QObject):
|
|||||||
self.gui.reports.refresh_starting.connect(self.commit_all_editors_to_container)
|
self.gui.reports.refresh_starting.connect(self.commit_all_editors_to_container)
|
||||||
self.gui.reports.delete_requested.connect(self.delete_requested)
|
self.gui.reports.delete_requested.connect(self.delete_requested)
|
||||||
|
|
||||||
|
def report_render_process_restart(self):
|
||||||
|
self.gui.show_status_message(_('The Qt WebEngine Render process crashed and has been restarted'))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def currently_editing(self):
|
def currently_editing(self):
|
||||||
' Return the name of the file being edited currently or None if no file is being edited '
|
' Return the name of the file being edited currently or None if no file is being edited '
|
||||||
|
@ -14,8 +14,8 @@ from functools import partial
|
|||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
||||||
from PyQt5.Qt import (
|
from PyQt5.Qt import (
|
||||||
QApplication, QBuffer, QByteArray, QIcon, QMenu, QSize, QTimer,
|
QApplication, QBuffer, QByteArray, QIcon, QMenu, QSize, QTimer, QToolBar, QUrl,
|
||||||
QToolBar, QUrl, QVBoxLayout, QWidget, pyqtSignal
|
QVBoxLayout, QWidget, pyqtSignal
|
||||||
)
|
)
|
||||||
from PyQt5.QtWebEngineCore import QWebEngineUrlSchemeHandler
|
from PyQt5.QtWebEngineCore import QWebEngineUrlSchemeHandler
|
||||||
from PyQt5.QtWebEngineWidgets import (
|
from PyQt5.QtWebEngineWidgets import (
|
||||||
@ -30,7 +30,10 @@ from calibre.ebooks.oeb.base import OEB_DOCS, XHTML_MIME, serialize
|
|||||||
from calibre.ebooks.oeb.polish.parsing import parse
|
from calibre.ebooks.oeb.polish.parsing import parse
|
||||||
from calibre.gui2 import NO_URL_FORMATTING, error_dialog, open_url
|
from calibre.gui2 import NO_URL_FORMATTING, error_dialog, open_url
|
||||||
from calibre.gui2.tweak_book import TOP, actions, current_container, editors, tprefs
|
from calibre.gui2.tweak_book import TOP, actions, current_container, editors, tprefs
|
||||||
from calibre.gui2.webengine import create_script, insert_scripts, secure_webengine, Bridge, from_js, to_js
|
from calibre.gui2.webengine import (
|
||||||
|
Bridge, RestartingWebEngineView, create_script, from_js, insert_scripts,
|
||||||
|
secure_webengine, to_js
|
||||||
|
)
|
||||||
from calibre.gui2.widgets2 import HistoryLineEdit2
|
from calibre.gui2.widgets2 import HistoryLineEdit2
|
||||||
from calibre.utils.ipc.simple_worker import offload_worker
|
from calibre.utils.ipc.simple_worker import offload_worker
|
||||||
from polyglot.builtins import unicode_type
|
from polyglot.builtins import unicode_type
|
||||||
@ -325,10 +328,10 @@ class WebPage(QWebEnginePage):
|
|||||||
self.bridge.set_split_mode.emit(1 if enabled else 0)
|
self.bridge.set_split_mode.emit(1 if enabled else 0)
|
||||||
|
|
||||||
|
|
||||||
class WebView(QWebEngineView):
|
class WebView(RestartingWebEngineView):
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QWebEngineView.__init__(self, parent)
|
RestartingWebEngineView.__init__(self, parent)
|
||||||
self.inspector = QWebEngineView(self)
|
self.inspector = QWebEngineView(self)
|
||||||
w = QApplication.instance().desktop().availableGeometry(self).width()
|
w = QApplication.instance().desktop().availableGeometry(self).width()
|
||||||
self._size_hint = QSize(int(w/3), int(w/2))
|
self._size_hint = QSize(int(w/3), int(w/2))
|
||||||
@ -337,12 +340,13 @@ class WebView(QWebEngineView):
|
|||||||
self.setPage(self._page)
|
self.setPage(self._page)
|
||||||
self.clear()
|
self.clear()
|
||||||
self.setAcceptDrops(False)
|
self.setAcceptDrops(False)
|
||||||
self.renderProcessTerminated.connect(self.render_process_terminated)
|
self.render_process_failed.connect(self.render_process_died)
|
||||||
|
|
||||||
def render_process_terminated(self):
|
def render_process_died(self):
|
||||||
error_dialog(self, _('Render process crashed'), _(
|
error_dialog(self, _('Render process crashed'), _(
|
||||||
'The Qt WebEngine Render process has crashed so Preview/Live css'
|
'The Qt WebEngine Render process has crashed so Preview/Live css will not work.'
|
||||||
' will not work. You should try restarting the editor.'), show=True)
|
' You should try restarting the editor.')
|
||||||
|
, show=True)
|
||||||
|
|
||||||
def sizeHint(self):
|
def sizeHint(self):
|
||||||
return self._size_hint
|
return self._size_hint
|
||||||
@ -393,6 +397,7 @@ class Preview(QWidget):
|
|||||||
link_clicked = pyqtSignal(object, object)
|
link_clicked = pyqtSignal(object, object)
|
||||||
refresh_starting = pyqtSignal()
|
refresh_starting = pyqtSignal()
|
||||||
refreshed = pyqtSignal()
|
refreshed = pyqtSignal()
|
||||||
|
render_process_restarted = pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QWidget.__init__(self, parent)
|
QWidget.__init__(self, parent)
|
||||||
@ -403,6 +408,7 @@ class Preview(QWidget):
|
|||||||
self.view._page.bridge.request_sync.connect(self.request_sync)
|
self.view._page.bridge.request_sync.connect(self.request_sync)
|
||||||
self.view._page.bridge.request_split.connect(self.request_split)
|
self.view._page.bridge.request_split.connect(self.request_split)
|
||||||
self.view._page.loadFinished.connect(self.load_finished)
|
self.view._page.loadFinished.connect(self.load_finished)
|
||||||
|
self.view.render_process_restarted.connect(self.render_process_restarted)
|
||||||
self.pending_go_to_anchor = None
|
self.pending_go_to_anchor = None
|
||||||
self.inspector = self.view.inspector
|
self.inspector = self.view.inspector
|
||||||
l.addWidget(self.view)
|
l.addWidget(self.view)
|
||||||
|
@ -21,7 +21,6 @@ from PyQt5.Qt import (
|
|||||||
QStyledItemDelegate, QModelIndex, QRect, QStyle, QPalette, QTimer, QMenu,
|
QStyledItemDelegate, QModelIndex, QRect, QStyle, QPalette, QTimer, QMenu,
|
||||||
QAbstractItemModel, QTreeView, QFont, QRadioButton, QHBoxLayout,
|
QAbstractItemModel, QTreeView, QFont, QRadioButton, QHBoxLayout,
|
||||||
QFontDatabase, QComboBox, QUrl)
|
QFontDatabase, QComboBox, QUrl)
|
||||||
from PyQt5.QtWebEngineWidgets import QWebEngineView
|
|
||||||
|
|
||||||
from calibre import human_readable, fit_image
|
from calibre import human_readable, fit_image
|
||||||
from calibre.constants import DEBUG
|
from calibre.constants import DEBUG
|
||||||
@ -29,7 +28,7 @@ from calibre.ebooks.oeb.polish.report import (
|
|||||||
gather_data, CSSEntry, CSSFileMatch, MatchLocation, ClassEntry,
|
gather_data, CSSEntry, CSSFileMatch, MatchLocation, ClassEntry,
|
||||||
ClassFileMatch, ClassElement, CSSRule, LinkLocation)
|
ClassFileMatch, ClassElement, CSSRule, LinkLocation)
|
||||||
from calibre.gui2 import error_dialog, question_dialog, choose_save_file, open_url
|
from calibre.gui2 import error_dialog, question_dialog, choose_save_file, open_url
|
||||||
from calibre.gui2.webengine import secure_webengine
|
from calibre.gui2.webengine import secure_webengine, RestartingWebEngineView
|
||||||
from calibre.gui2.tweak_book import current_container, tprefs, dictionaries
|
from calibre.gui2.tweak_book import current_container, tprefs, dictionaries
|
||||||
from calibre.gui2.tweak_book.widgets import Dialog
|
from calibre.gui2.tweak_book.widgets import Dialog
|
||||||
from calibre.gui2.progress_indicator import ProgressIndicator
|
from calibre.gui2.progress_indicator import ProgressIndicator
|
||||||
@ -578,7 +577,7 @@ class LinksModel(FileCollection):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class WebView(QWebEngineView):
|
class WebView(RestartingWebEngineView):
|
||||||
|
|
||||||
def sizeHint(self):
|
def sizeHint(self):
|
||||||
return QSize(600, 200)
|
return QSize(600, 200)
|
||||||
@ -604,11 +603,8 @@ class LinksWidget(QWidget):
|
|||||||
e.textChanged.connect(f.proxy.filter_text)
|
e.textChanged.connect(f.proxy.filter_text)
|
||||||
s.addWidget(f)
|
s.addWidget(f)
|
||||||
self.links.restore_table('links-table', sort_column=1)
|
self.links.restore_table('links-table', sort_column=1)
|
||||||
self.view = WebView(self)
|
self.view = None
|
||||||
secure_webengine(self.view)
|
|
||||||
self.setContextMenuPolicy(Qt.NoContextMenu)
|
self.setContextMenuPolicy(Qt.NoContextMenu)
|
||||||
self.view.setContextMenuPolicy(Qt.NoContextMenu)
|
|
||||||
s.addWidget(self.view)
|
|
||||||
self.ignore_current_change = False
|
self.ignore_current_change = False
|
||||||
self.current_url = None
|
self.current_url = None
|
||||||
f.current_changed.connect(self.current_changed)
|
f.current_changed.connect(self.current_changed)
|
||||||
@ -616,10 +612,16 @@ class LinksWidget(QWidget):
|
|||||||
s.restoreState(read_state('links-view-splitter'))
|
s.restoreState(read_state('links-view-splitter'))
|
||||||
except TypeError:
|
except TypeError:
|
||||||
pass
|
pass
|
||||||
s.setCollapsible(0, False), s.setCollapsible(1, True)
|
s.setCollapsible(0, False)
|
||||||
s.setStretchFactor(0, 10)
|
s.setStretchFactor(0, 10)
|
||||||
|
|
||||||
def __call__(self, data):
|
def __call__(self, data):
|
||||||
|
if self.view is None:
|
||||||
|
self.view = WebView(self)
|
||||||
|
secure_webengine(self.view)
|
||||||
|
self.view.setContextMenuPolicy(Qt.NoContextMenu)
|
||||||
|
self.splitter.addWidget(self.view)
|
||||||
|
self.splitter.setCollapsible(1, True)
|
||||||
self.ignore_current_change = True
|
self.ignore_current_change = True
|
||||||
self.model(data)
|
self.model(data)
|
||||||
self.filter_edit.clear()
|
self.filter_edit.clear()
|
||||||
@ -644,10 +646,12 @@ class LinksWidget(QWidget):
|
|||||||
if link.anchor.id:
|
if link.anchor.id:
|
||||||
url.setFragment(link.anchor.id)
|
url.setFragment(link.anchor.id)
|
||||||
if url is None:
|
if url is None:
|
||||||
|
if self.view:
|
||||||
self.view.setHtml('<p>' + _('No destination found for this link'))
|
self.view.setHtml('<p>' + _('No destination found for this link'))
|
||||||
self.current_url = url
|
self.current_url = url
|
||||||
elif url != self.current_url:
|
elif url != self.current_url:
|
||||||
self.current_url = url
|
self.current_url = url
|
||||||
|
if self.view:
|
||||||
self.view.setUrl(url)
|
self.view.setUrl(url)
|
||||||
|
|
||||||
def double_clicked(self, index):
|
def double_clicked(self, index):
|
||||||
|
@ -6,10 +6,11 @@ from __future__ import absolute_import, division, print_function, unicode_litera
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from PyQt5.Qt import QObject, pyqtSignal
|
from PyQt5.Qt import QObject, Qt, pyqtSignal
|
||||||
from PyQt5.QtWebEngineWidgets import QWebEngineScript, QWebEngineView
|
from PyQt5.QtWebEngineWidgets import QWebEngineScript, QWebEngineView
|
||||||
|
|
||||||
from calibre import prints
|
from calibre import prints
|
||||||
|
from calibre.utils.monotonic import monotonic
|
||||||
from calibre.utils.rapydscript import special_title
|
from calibre.utils.rapydscript import special_title
|
||||||
|
|
||||||
|
|
||||||
@ -125,6 +126,27 @@ class Bridge(QObject):
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
|
class RestartingWebEngineView(QWebEngineView):
|
||||||
|
|
||||||
|
render_process_restarted = pyqtSignal()
|
||||||
|
render_process_failed = pyqtSignal()
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
QWebEngineView.__init__(self, parent)
|
||||||
|
self._last_reload_at = None
|
||||||
|
self.renderProcessTerminated.connect(self.render_process_terminated)
|
||||||
|
self.render_process_restarted.connect(self.reload, type=Qt.QueuedConnection)
|
||||||
|
|
||||||
|
def render_process_terminated(self):
|
||||||
|
if self._last_reload_at is not None and monotonic() - self._last_reload_at < 2:
|
||||||
|
self.render_process_failed.emit()
|
||||||
|
print('The Qt WebEngine Render process crashed too often')
|
||||||
|
else:
|
||||||
|
self._last_reload_at = monotonic()
|
||||||
|
self.render_process_restarted.emit()
|
||||||
|
prints('The Qt WebEngine Render process crashed, restarting it')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
from calibre.gui2 import Application
|
from calibre.gui2 import Application
|
||||||
from calibre.gui2.tweak_book.preview import WebPage
|
from calibre.gui2.tweak_book.preview import WebPage
|
||||||
|
Loading…
x
Reference in New Issue
Block a user