From cd4eff364a841b36c6fa1653ef8f0284ab1beef0 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 12 Jul 2016 12:54:11 +0200 Subject: [PATCH] Add printing to tab API This fixes printing for QtWebKit, and hopefully will make printing to PDF work with QtWebEngine with Qt >= 5.7 --- qutebrowser/browser/browsertab.py | 24 ++++++++ qutebrowser/browser/commands.py | 56 ++++++++++--------- qutebrowser/browser/webengine/webenginetab.py | 24 ++++++++ qutebrowser/browser/webkit/webkittab.py | 28 ++++++++++ tests/unit/browser/test_tab.py | 1 + 5 files changed, 107 insertions(+), 26 deletions(-) diff --git a/qutebrowser/browser/browsertab.py b/qutebrowser/browser/browsertab.py index 609c98204..f6579c87e 100644 --- a/qutebrowser/browser/browsertab.py +++ b/qutebrowser/browser/browsertab.py @@ -24,6 +24,7 @@ import itertools from PyQt5.QtCore import pyqtSignal, pyqtSlot, QUrl, QObject, QPoint from PyQt5.QtGui import QIcon from PyQt5.QtWidgets import QWidget, QLayout +from PyQt5.QtPrintSupport import QPrinter from qutebrowser.keyinput import modeman from qutebrowser.config import config @@ -105,6 +106,27 @@ class TabData: self.inspector = None +class AbstractPrinting: + + """Attribute of AbstractTab for printing the page.""" + + def __init__(self): + self._widget = None + + def check_pdf_support(self): + raise NotImplementedError + + def check_printer_support(self): + raise NotImplementedError + + def to_pdf(self, filename): + raise NotImplementedError + + @pyqtSlot(QPrinter) + def to_printer(self, printer): + raise NotImplementedError + + class AbstractSearch(QObject): """Attribute of AbstractTab for doing searches. @@ -468,6 +490,7 @@ class AbstractTab(QWidget): # parent=self) # self.zoom = AbstractZoom(win_id=win_id) # self.search = AbstractSearch(parent=self) + # self.printing = AbstractPrinting() self.data = TabData() self._layout = None self._widget = None @@ -485,6 +508,7 @@ class AbstractTab(QWidget): self.caret._widget = widget self.zoom._widget = widget self.search._widget = widget + self.printing._widget = widget widget.mouse_wheel_zoom.connect(self.zoom._on_mouse_wheel_zoom) widget.setParent(self) self.setFocusProxy(widget) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 74d857de7..761c58280 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -28,7 +28,7 @@ import functools from PyQt5.QtWidgets import QApplication, QTabBar from PyQt5.QtCore import Qt, QUrl, QEvent from PyQt5.QtGui import QKeyEvent -from PyQt5.QtPrintSupport import QPrintDialog, QPrinter, QPrintPreviewDialog +from PyQt5.QtPrintSupport import QPrintDialog, QPrintPreviewDialog from PyQt5.QtWebKitWidgets import QWebPage try: from PyQt5.QtWebEngineWidgets import QWebEnginePage @@ -308,33 +308,37 @@ class CommandDispatcher: count: The tab index to print, or None. pdf: The file path to write the PDF to. """ - if not qtutils.check_print_compat(): - # WORKAROUND (remove this when we bump the requirements to 5.3.0) - raise cmdexc.CommandError( - "Printing on Qt < 5.3.0 on Windows is broken, please upgrade!") tab = self._cntwidget(count) - if tab is not None: - if preview: - diag = QPrintPreviewDialog() - diag.setAttribute(Qt.WA_DeleteOnClose) - diag.setWindowFlags(diag.windowFlags() | - Qt.WindowMaximizeButtonHint | - Qt.WindowMinimizeButtonHint) - diag.paintRequested.connect(tab.print) - diag.exec_() - elif pdf: - pdf = os.path.expanduser(pdf) - directory = os.path.dirname(pdf) - if directory and not os.path.exists(directory): - os.mkdir(directory) - printer = QPrinter() - printer.setOutputFileName(pdf) - tab.print(printer) - log.misc.debug("Print to file: {}".format(pdf)) + if tab is None: + return + + try: + if pdf: + tab.printing.check_pdf_support() else: - diag = QPrintDialog() - diag.setAttribute(Qt.WA_DeleteOnClose) - diag.open(lambda: tab.print(diag.printer())) + tab.printing.check_printer_support() + except browsertab.WebTabError as e: + raise cmdexc.CommandError(e) + + if preview: + diag = QPrintPreviewDialog() + diag.setAttribute(Qt.WA_DeleteOnClose) + diag.setWindowFlags(diag.windowFlags() | + Qt.WindowMaximizeButtonHint | + Qt.WindowMinimizeButtonHint) + diag.paintRequested.connect(tab.printing.to_printer) + diag.exec_() + elif pdf: + pdf = os.path.expanduser(pdf) + directory = os.path.dirname(pdf) + if directory and not os.path.exists(directory): + os.mkdir(directory) + tab.printing.to_pdf(pdf) + log.misc.debug("Print to file: {}".format(pdf)) + else: + diag = QPrintDialog() + diag.setAttribute(Qt.WA_DeleteOnClose) + diag.open(lambda: tab.printing.to_printer(diag.printer())) @cmdutils.register(instance='command-dispatcher', scope='window') def tab_clone(self, bg=False, window=False): diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index 5e4ab7417..04c60c02d 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -25,6 +25,7 @@ from PyQt5.QtCore import pyqtSlot, Qt, QEvent, QPoint from PyQt5.QtGui import QKeyEvent, QIcon from PyQt5.QtWidgets import QApplication +from PyQt5.QtPrintSupport import QPrinter # pylint: disable=no-name-in-module,import-error,useless-suppression from PyQt5.QtWebEngineWidgets import QWebEnginePage # pylint: enable=no-name-in-module,import-error,useless-suppression @@ -34,6 +35,28 @@ from qutebrowser.browser.webengine import webview from qutebrowser.utils import usertypes, qtutils, log +class WebEnginePrinting(browsertab.AbstractPrinting): + + """QtWebEngine implementations related to printing.""" + + def check_pdf_support(self): + if not hasattr(self._widget.page(), 'printToPdf'): + raise browsertab.WebTabError( + "Printing to PDF is unsupported with QtWebEngine on Qt > 5.7") + + def check_printer_support(self): + raise browsertab.WebTabError( + "Printing is unsupported with QtWebEngine") + + def to_pdf(self, filename): + self._widget.page().printToPdf(filename) + + @pyqtSlot(QPrinter) + def to_printer(self, printer): + # Should never be called + assert False + + class WebEngineSearch(browsertab.AbstractSearch): """QtWebEngine implementations related to searching on the page.""" @@ -256,6 +279,7 @@ class WebEngineTab(browsertab.AbstractTab): tab=self, parent=self) self.zoom = WebEngineZoom(win_id=win_id, parent=self) self.search = WebEngineSearch(parent=self) + self.printing = WebEnginePrinting() self._set_widget(widget) self._connect_signals() self.backend = usertypes.Backend.QtWebEngine diff --git a/qutebrowser/browser/webkit/webkittab.py b/qutebrowser/browser/webkit/webkittab.py index 7ccd465a5..48016d627 100644 --- a/qutebrowser/browser/webkit/webkittab.py +++ b/qutebrowser/browser/webkit/webkittab.py @@ -27,12 +27,39 @@ from PyQt5.QtCore import pyqtSlot, Qt, QEvent, QUrl, QPoint, QTimer from PyQt5.QtGui import QKeyEvent from PyQt5.QtWebKitWidgets import QWebPage from PyQt5.QtWebKit import QWebSettings +from PyQt5.QtPrintSupport import QPrinter from qutebrowser.browser import browsertab from qutebrowser.browser.webkit import webview, tabhistory from qutebrowser.utils import qtutils, objreg, usertypes, utils +class WebKitPrinting(browsertab.AbstractPrinting): + + """QtWebKit implementations related to printing.""" + + def _do_check(self): + if not qtutils.check_print_compat(): + # WORKAROUND (remove this when we bump the requirements to 5.3.0) + raise browsertab.WebTabError( + "Printing on Qt < 5.3.0 on Windows is broken, please upgrade!") + + def check_pdf_support(self): + self._do_check() + + def check_printer_support(self): + self._do_check() + + def to_pdf(self, filename): + printer = QPrinter() + printer.setOutputFileName(filename) + self.to_printer(printer) + + @pyqtSlot(QPrinter) + def to_printer(self, printer): + self._widget.print(printer) + + class WebKitSearch(browsertab.AbstractSearch): """QtWebKit implementations related to searching on the page.""" @@ -461,6 +488,7 @@ class WebKitTab(browsertab.AbstractTab): tab=self, parent=self) self.zoom = WebKitZoom(win_id=win_id, parent=self) self.search = WebKitSearch(parent=self) + self.printing = WebKitPrinting() self._set_widget(widget) self._connect_signals() self.zoom.set_default() diff --git a/tests/unit/browser/test_tab.py b/tests/unit/browser/test_tab.py index 722fa04d0..7f1ae3073 100644 --- a/tests/unit/browser/test_tab.py +++ b/tests/unit/browser/test_tab.py @@ -77,6 +77,7 @@ def test_tab(qtbot, view, config_stub, tab_registry): tab=tab_w, parent=tab_w) tab_w.zoom = browsertab.AbstractZoom(win_id=tab_w.win_id) tab_w.search = browsertab.AbstractSearch(parent=tab_w) + tab_w.printing = browsertab.AbstractPrinting() tab_w._set_widget(w) assert tab_w._widget is w