[FEATURE] Export processing models as PDF/SVG

This commit is contained in:
nirvn 2017-01-02 10:27:41 +07:00
parent 4603eb0f3d
commit f54476cdda
4 changed files with 112 additions and 19 deletions

View File

@ -31,9 +31,11 @@ import sys
import os
from qgis.PyQt import uic
from qgis.PyQt.QtCore import Qt, QRectF, QMimeData, QPoint, QPointF, QSettings, QByteArray, QSize, pyqtSignal
from qgis.PyQt.QtCore import Qt, QRectF, QMimeData, QPoint, QPointF, QSettings, QByteArray, QSize, QSizeF, pyqtSignal
from qgis.PyQt.QtWidgets import QGraphicsView, QTreeWidget, QMessageBox, QFileDialog, QTreeWidgetItem, QSizePolicy, QMainWindow
from qgis.PyQt.QtGui import QIcon, QImage, QPainter
from qgis.PyQt.QtSvg import QSvgGenerator
from qgis.PyQt.QtPrintSupport import QPrinter
from qgis.core import QgsApplication
from qgis.gui import QgsMessageBar
from processing.core.ProcessingConfig import ProcessingConfig
@ -213,6 +215,8 @@ class ModelerDialog(BASE, WIDGET):
self.mActionSave.triggered.connect(self.save)
self.mActionSaveAs.triggered.connect(self.saveAs)
self.mActionExportImage.triggered.connect(self.exportAsImage)
self.mActionExportPdf.triggered.connect(self.exportAsPdf)
self.mActionExportSvg.triggered.connect(self.exportAsSvg)
self.mActionExportPython.triggered.connect(self.exportAsPython)
self.mActionEditHelp.triggered.connect(self.editHelp)
self.mActionRun.triggered.connect(self.runModel)
@ -287,6 +291,7 @@ class ModelerDialog(BASE, WIDGET):
self.saveModel(True)
def exportAsImage(self):
self.repaintModel(controls=False)
filename, fileFilter = QFileDialog.getSaveFileName(self,
self.tr('Save Model As Image'), '',
self.tr('PNG files (*.png *.PNG)'))
@ -296,10 +301,9 @@ class ModelerDialog(BASE, WIDGET):
if not filename.lower().endswith('.png'):
filename += '.png'
totalRect = QRectF(0, 0, 1, 1)
for item in list(self.scene.items()):
totalRect = totalRect.united(item.sceneBoundingRect())
totalRect = self.scene.itemsBoundingRect()
totalRect.adjust(-10, -10, 10, 10)
imgRect = QRectF(0, 0, totalRect.width(), totalRect.height())
img = QImage(totalRect.width(), totalRect.height(),
QImage.Format_ARGB32_Premultiplied)
@ -307,12 +311,69 @@ class ModelerDialog(BASE, WIDGET):
painter = QPainter()
painter.setRenderHint(QPainter.Antialiasing)
painter.begin(img)
self.scene.render(painter, totalRect, totalRect)
self.scene.render(painter, imgRect, totalRect)
painter.end()
img.save(filename)
self.bar.pushMessage("", "Model was correctly exported as image", level=QgsMessageBar.SUCCESS, duration=5)
self.repaintModel(controls=True)
def exportAsPdf(self):
self.repaintModel(controls=False)
filename, fileFilter = QFileDialog.getSaveFileName(self,
self.tr('Save Model As PDF'), '',
self.tr('SVG files (*.pdf *.PDF)'))
if not filename:
return
if not filename.lower().endswith('.pdf'):
filename += '.pdf'
totalRect = self.scene.itemsBoundingRect()
totalRect.adjust(-10, -10, 10, 10)
printerRect = QRectF(0, 0, totalRect.width(), totalRect.height())
printer = QPrinter()
printer.setOutputFormat(QPrinter.PdfFormat)
printer.setOutputFileName(filename)
printer.setPaperSize(QSizeF(printerRect.width(), printerRect.height()), QPrinter.DevicePixel)
printer.setFullPage(True)
painter = QPainter(printer)
self.scene.render(painter, printerRect, totalRect)
painter.end()
self.bar.pushMessage("", "Model was correctly exported as PDF", level=QgsMessageBar.SUCCESS, duration=5)
self.repaintModel(controls=True)
def exportAsSvg(self):
self.repaintModel(controls=False)
filename, fileFilter = QFileDialog.getSaveFileName(self,
self.tr('Save Model As SVG'), '',
self.tr('SVG files (*.svg *.SVG)'))
if not filename:
return
if not filename.lower().endswith('.svg'):
filename += '.svg'
totalRect = self.scene.itemsBoundingRect()
totalRect.adjust(-10, -10, 10, 10)
svgRect = QRectF(0, 0, totalRect.width(), totalRect.height())
svg = QSvgGenerator()
svg.setFileName(filename)
svg.setSize(QSize(totalRect.width(), totalRect.height()))
svg.setViewBox(svgRect)
svg.setTitle(self.alg.name)
painter = QPainter(svg)
self.scene.render(painter, svgRect, totalRect)
painter.end()
self.bar.pushMessage("", "Model was correctly exported as SVG", level=QgsMessageBar.SUCCESS, duration=5)
self.repaintModel(controls=True)
def exportAsPython(self):
filename, filter = QFileDialog.getSaveFileName(self,
@ -399,11 +460,11 @@ class ModelerDialog(BASE, WIDGET):
self.tr('The selected model could not be loaded.\n'
'See the log for more information.'))
def repaintModel(self):
def repaintModel(self, controls=True):
self.scene = ModelerScene()
self.scene.setSceneRect(QRectF(0, 0, ModelerAlgorithm.CANVAS_SIZE,
ModelerAlgorithm.CANVAS_SIZE))
self.scene.paintModel(self.alg)
self.scene.paintModel(self.alg, controls)
self.view.setScene(self.scene)
def addInput(self):

View File

@ -45,8 +45,9 @@ class ModelerGraphicItem(QGraphicsItem):
BOX_HEIGHT = 30
BOX_WIDTH = 200
def __init__(self, element, model):
def __init__(self, element, model, controls):
super(ModelerGraphicItem, self).__init__(None)
self.controls = controls
self.model = model
self.element = element
if isinstance(element, ModelerParameter):
@ -73,7 +74,7 @@ class ModelerGraphicItem(QGraphicsItem):
self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
self.setZValue(1000)
if not isinstance(element, ModelerOutput):
if not isinstance(element, ModelerOutput) and controls:
svg = QSvgRenderer(os.path.join(pluginPath, 'images', 'edit.svg'))
picture = QPicture()
painter = QPainter(picture)
@ -101,13 +102,15 @@ class ModelerGraphicItem(QGraphicsItem):
if alg.parameters:
pt = self.getLinkPointForParameter(-1)
pt = QPointF(0, pt.y())
self.inButton = FoldButtonGraphicItem(pt, self.foldInput, self.element.paramsFolded)
self.inButton.setParentItem(self)
if controls:
self.inButton = FoldButtonGraphicItem(pt, self.foldInput, self.element.paramsFolded)
self.inButton.setParentItem(self)
if alg.outputs:
pt = self.getLinkPointForOutput(-1)
pt = QPointF(0, pt.y())
self.outButton = FoldButtonGraphicItem(pt, self.foldOutput, self.element.outputsFolded)
self.outButton.setParentItem(self)
if controls:
self.outButton = FoldButtonGraphicItem(pt, self.foldOutput, self.element.outputsFolded)
self.outButton.setParentItem(self)
def foldInput(self, folded):
self.element.paramsFolded = folded
@ -237,12 +240,15 @@ class ModelerGraphicItem(QGraphicsItem):
ModelerGraphicItem.BOX_HEIGHT + 2)
color = QColor(172, 196, 114)
outline = QColor(90, 140, 90)
selected = QColor(90, 140, 90)
if isinstance(self.element, ModelerParameter):
color = QColor(238, 242, 131)
outline = QColor(234, 226, 118)
selected = QColor(151, 153, 83)
elif isinstance(self.element, Algorithm):
color = Qt.white
outline = Qt.gray
selected = Qt.gray
painter.setPen(QPen(outline, 1))
painter.setBrush(QBrush(color, Qt.SolidPattern))
painter.drawRect(rect)
@ -255,7 +261,7 @@ class ModelerGraphicItem(QGraphicsItem):
painter.setPen(QPen(Qt.gray))
text = text + "\n(deactivated)"
elif self.isSelected():
painter.setPen(QPen(outline))
painter.setPen(QPen(selected))
fm = QFontMetricsF(font)
text = self.getAdjustedText(self.text)
h = fm.ascent()
@ -379,7 +385,7 @@ class FlatButtonGraphicItem(QGraphicsItem):
rect = QRectF(pt.x(), pt.y(), self.WIDTH, self.HEIGHT)
if self.isIn:
painter.setPen(QPen(Qt.transparent, 1))
painter.setBrush(QBrush(Qt.lightGray,
painter.setBrush(QBrush(QColor(55, 55, 55, 33),
Qt.SolidPattern))
else:
painter.setPen(QPen(Qt.transparent, 1))

View File

@ -78,11 +78,11 @@ class ModelerScene(QGraphicsScene):
items.append((self.algItems[value.alg], i))
return items
def paintModel(self, model):
def paintModel(self, model, controls=True):
self.model = model
# Inputs
for inp in list(model.inputs.values()):
item = ModelerGraphicItem(inp, model)
item = ModelerGraphicItem(inp, model, controls)
item.setFlag(QGraphicsItem.ItemIsMovable, True)
item.setFlag(QGraphicsItem.ItemIsSelectable, True)
self.addItem(item)
@ -91,7 +91,7 @@ class ModelerScene(QGraphicsScene):
# We add the algs
for alg in list(model.algs.values()):
item = ModelerGraphicItem(alg, model)
item = ModelerGraphicItem(alg, model, controls)
item.setFlag(QGraphicsItem.ItemIsMovable, True)
item.setFlag(QGraphicsItem.ItemIsSelectable, True)
self.addItem(item)
@ -131,7 +131,7 @@ class ModelerScene(QGraphicsScene):
for key in outputs:
out = outputs[key]
if out is not None:
item = ModelerGraphicItem(out, model)
item = ModelerGraphicItem(out, model, controls)
item.setFlag(QGraphicsItem.ItemIsMovable, True)
item.setFlag(QGraphicsItem.ItemIsSelectable, True)
self.addItem(item)

View File

@ -310,6 +310,8 @@
<addaction name="mActionSaveAs"/>
<addaction name="separator"/>
<addaction name="mActionExportImage"/>
<addaction name="mActionExportPdf"/>
<addaction name="mActionExportSvg"/>
<addaction name="mActionExportPython"/>
<addaction name="separator"/>
<addaction name="mActionEditHelp"/>
@ -373,6 +375,30 @@
<string>Export as image</string>
</property>
</action>
<action name="mActionExportPdf">
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionSaveAsPDF.svg</normaloff>:/images/themes/default/mActionSaveAsPDF.svg</iconset>
</property>
<property name="text">
<string>Export as PDF...</string>
</property>
<property name="toolTip">
<string>Export as PDF</string>
</property>
</action>
<action name="mActionExportSvg">
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionSaveAsSVG.svg</normaloff>:/images/themes/default/mActionSaveAsSVG.svg</iconset>
</property>
<property name="text">
<string>Export as SVG...</string>
</property>
<property name="toolTip">
<string>Export as SVG</string>
</property>
</action>
<action name="mActionExportPython">
<property name="icon">
<iconset resource="../../images/images.qrc">