mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
[FEATURE] Export processing models as PDF/SVG
This commit is contained in:
parent
4603eb0f3d
commit
f54476cdda
@ -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):
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
|
@ -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">
|
||||
|
Loading…
x
Reference in New Issue
Block a user