diff --git a/Orange/widgets/io.py b/Orange/widgets/io.py index 2567e40c338..20aeae0fd11 100644 --- a/Orange/widgets/io.py +++ b/Orange/widgets/io.py @@ -1,3 +1,6 @@ +import os +import tempfile + from AnyQt import QtGui, QtCore, QtSvg from AnyQt.QtCore import QMimeData from AnyQt.QtWidgets import ( @@ -59,8 +62,8 @@ def write_image(cls, filename, scene): scene.render(painter, target, rect) except TypeError: scene.render(painter) # QWidget.render() takes different params - cls._save_buffer(buffer, filename) painter.end() + cls._save_buffer(buffer, filename) @classmethod def write(cls, filename, scene): @@ -139,6 +142,9 @@ def _get_target(scene, painter, buffer, source): @staticmethod def _save_buffer(buffer, filename): + dev = buffer.outputDevice() + if dev is not None: + dev.flush() pass @staticmethod @@ -164,3 +170,38 @@ def write_image(cls, filename, scene): pass super().write_image(filename, scene) + + +if hasattr(QtGui, "QPdfWriter"): + class PdfFormat(ImgFormat): + EXTENSIONS = ('.pdf', ) + DESCRIPTION = 'Portable Document Format' + PRIORITY = 110 + + @classmethod + def write_image(cls, filename, scene): + # export via svg to temp file then print that + # NOTE: can't use NamedTemporaryFile with delete = True + # (see https://bugs.python.org/issue14243) + fd, tmpname = tempfile.mkstemp(suffix=".svg") + os.close(fd) + try: + SvgFormat.write_image(tmpname, scene) + with open(tmpname, "rb") as f: + svgcontents = f.read() + finally: + os.unlink(tmpname) + + svgrend = QtSvg.QSvgRenderer(QtCore.QByteArray(svgcontents)) + vbox = svgrend.viewBox() + if not vbox.isValid(): + size = svgrend.defaultSize() + else: + size = vbox.size() + writer = QtGui.QPdfWriter(filename) + writer.setPageSizeMM(QtCore.QSizeF(size) * 0.282) + painter = QtGui.QPainter(writer) + svgrend.render(painter) + painter.end() + del svgrend + del painter diff --git a/Orange/widgets/tests/test_io.py b/Orange/widgets/tests/test_io.py new file mode 100644 index 00000000000..d21498f5d17 --- /dev/null +++ b/Orange/widgets/tests/test_io.py @@ -0,0 +1,20 @@ +import os +import tempfile +import unittest + +from AnyQt.QtWidgets import QGraphicsScene, QGraphicsRectItem +from Orange.widgets.tests.base import GuiTest + +from Orange.widgets import io as imgio + +@unittest.skipUnless(hasattr(imgio, "PdfFormat"), "QPdfWriter not available") +class TestIO(GuiTest): + def test_pdf(self): + sc = QGraphicsScene() + sc.addItem(QGraphicsRectItem(0, 0, 20, 20)) + fd, fname = tempfile.mkstemp() + os.close(fd) + try: + imgio.PdfFormat.write_image(fname, sc) + finally: + os.unlink(fname) diff --git a/Orange/widgets/utils/saveplot.py b/Orange/widgets/utils/saveplot.py index 9060e4ac2f4..6812a72a11e 100644 --- a/Orange/widgets/utils/saveplot.py +++ b/Orange/widgets/utils/saveplot.py @@ -1,4 +1,5 @@ import os.path +import traceback from AnyQt.QtWidgets import QMessageBox from AnyQt.QtCore import QSettings @@ -24,8 +25,13 @@ def save_plot(data, file_formats, filename=""): try: writer.write(filename, data) except Exception as e: - QMessageBox.critical( - None, "Error", 'Error occurred while saving file "{}": {}'.format(filename, e)) + mb = QMessageBox( + None, + windowTitle="Error", + text='Error occurred while saving file "{}": {}'.format(filename, e), + detailedText=traceback.format_exc(), + icon=QMessageBox.Critical) + mb.exec_() else: settings.setValue(_LAST_DIR_KEY, os.path.split(filename)[0]) settings.setValue(_LAST_FILTER_KEY, filter)