Merge branch 'jdkaplan-issues/1630'

This commit is contained in:
Florian Bruhin 2016-07-12 13:31:36 +02:00
commit 6de8f85e04
10 changed files with 127 additions and 18 deletions

View File

@ -26,6 +26,8 @@ Added
`$QUTE_DOWNLOAD_DIR` available for userscripts.
- New option `ui` -> `status-position` to configure the position of the
status bar (top/bottom).
- New `--pdf <filename>` argument for `:print` which can be used to generate a
PDF without a dialog.
Changed
~~~~~~~

View File

@ -201,6 +201,7 @@ Contributors, sorted by the number of commits in descending order:
* Link
* Larry Hynes
* Johannes Altmanninger
* Jeremy Kaplan
* Ismail
* Edgar Hipp
* Daryl Finlay

View File

@ -495,12 +495,13 @@ If the pasted text contains newlines, each line gets opened in its own tab.
[[print]]
=== print
Syntax: +:print [*--preview*]+
Syntax: +:print [*--preview*] [*--pdf* 'file']+
Print the current/[count]th tab.
==== optional arguments
* +*-p*+, +*--preview*+: Show preview instead of printing.
* +*-f*+, +*--pdf*+: The file path to write the PDF to.
==== count
The tab index to print.

View File

@ -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)

View File

@ -299,31 +299,46 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', name='print',
scope='window')
@cmdutils.argument('count', count=True)
def printpage(self, preview=False, count=None):
@cmdutils.argument('pdf', flag='f', metavar='file')
def printpage(self, preview=False, count=None, *, pdf=None):
"""Print the current/[count]th tab.
Args:
preview: Show preview instead of printing.
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_()
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):

View File

@ -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

View File

@ -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()

View File

@ -339,6 +339,12 @@ Feature: Various utility commands.
And I run :debug-pyeval QApplication.instance().activeModalWidget().close()
Then no crash should happen
Scenario: print --pdf
When I open data/hello.txt
And I run :print --pdf (tmpdir)/hello.pdf
And I wait for "Print to file: *" in the log or skip the test
Then the PDF hello.pdf should exist in the tmpdir
# :pyeval
Scenario: Running :pyeval

View File

@ -73,3 +73,10 @@ def check_cookie(quteproc, name, value):
data = json.loads(content)
print(data)
assert data['cookies'][name] == value
@bdd.then(bdd.parsers.parse('the PDF {filename} should exist in the tmpdir'))
def pdf_exists(quteproc, tmpdir, filename):
path = tmpdir / filename
data = path.read_binary()
assert data.startswith(b'%PDF')

View File

@ -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