2014-11-12 11:42:29 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
"""
|
|
|
|
***************************************************************************
|
|
|
|
AlgorithmDialog.py
|
|
|
|
---------------------
|
|
|
|
Date : August 2012
|
|
|
|
Copyright : (C) 2012 by Victor Olaya
|
|
|
|
Email : volayaf at gmail dot com
|
|
|
|
***************************************************************************
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
***************************************************************************
|
|
|
|
"""
|
2016-09-21 18:24:26 +02:00
|
|
|
from builtins import range
|
2014-11-12 11:42:29 +02:00
|
|
|
|
|
|
|
__author__ = 'Victor Olaya'
|
|
|
|
__date__ = 'August 2012'
|
|
|
|
__copyright__ = '(C) 2012, Victor Olaya'
|
|
|
|
|
|
|
|
# This will get replaced with a git SHA1 when you do a git archive
|
|
|
|
|
|
|
|
__revision__ = '$Format:%H$'
|
|
|
|
|
2016-04-22 10:38:48 +02:00
|
|
|
from qgis.PyQt.QtCore import Qt
|
2016-09-27 19:51:06 +02:00
|
|
|
from qgis.PyQt.QtWidgets import QMessageBox, QApplication, QPushButton, QWidget, QVBoxLayout, QSizePolicy
|
|
|
|
from qgis.PyQt.QtGui import QCursor, QColor, QPalette
|
2014-11-12 11:42:29 +02:00
|
|
|
|
2017-04-05 14:37:06 +10:00
|
|
|
from qgis.core import (QgsProject,
|
|
|
|
QgsProcessingUtils)
|
2016-09-16 14:32:30 +02:00
|
|
|
from qgis.gui import QgsMessageBar
|
2016-10-18 20:57:34 +03:00
|
|
|
from qgis.utils import iface
|
2016-01-18 14:16:31 +01:00
|
|
|
|
2014-11-12 11:42:29 +02:00
|
|
|
from processing.core.ProcessingLog import ProcessingLog
|
|
|
|
from processing.core.ProcessingConfig import ProcessingConfig
|
|
|
|
|
2015-09-24 12:07:46 +02:00
|
|
|
from processing.gui.BatchAlgorithmDialog import BatchAlgorithmDialog
|
2014-11-12 11:42:29 +02:00
|
|
|
from processing.gui.AlgorithmDialogBase import AlgorithmDialogBase
|
2017-03-22 17:17:14 +02:00
|
|
|
from processing.gui.AlgorithmExecutor import execute, executeIterating
|
2014-11-12 11:42:29 +02:00
|
|
|
from processing.gui.Postprocessing import handleAlgorithmResults
|
|
|
|
|
2016-10-18 20:57:34 +03:00
|
|
|
from processing.core.parameters import ParameterRaster
|
|
|
|
from processing.core.parameters import ParameterVector
|
|
|
|
from processing.core.parameters import ParameterExtent
|
|
|
|
from processing.core.parameters import ParameterMultipleInput
|
|
|
|
|
2014-11-12 11:42:29 +02:00
|
|
|
from processing.core.outputs import OutputRaster
|
|
|
|
from processing.core.outputs import OutputVector
|
|
|
|
from processing.core.outputs import OutputTable
|
|
|
|
|
2017-04-25 20:03:39 +10:00
|
|
|
from processing.tools import dataobjects
|
2016-10-13 13:40:47 +02:00
|
|
|
|
|
|
|
|
2014-11-12 11:42:29 +02:00
|
|
|
class AlgorithmDialog(AlgorithmDialogBase):
|
|
|
|
|
|
|
|
def __init__(self, alg):
|
|
|
|
AlgorithmDialogBase.__init__(self, alg)
|
|
|
|
|
|
|
|
self.alg = alg
|
|
|
|
|
2016-11-17 12:06:24 +01:00
|
|
|
self.setMainWidget(alg.getParametersPanel(self))
|
2014-11-12 11:42:29 +02:00
|
|
|
|
2016-09-16 14:32:30 +02:00
|
|
|
self.bar = QgsMessageBar()
|
|
|
|
self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
|
|
|
|
self.layout().insertWidget(0, self.bar)
|
|
|
|
|
2016-04-06 10:50:54 +02:00
|
|
|
self.cornerWidget = QWidget()
|
2015-09-26 19:53:10 +02:00
|
|
|
layout = QVBoxLayout()
|
|
|
|
layout.setContentsMargins(0, 0, 0, 5)
|
|
|
|
self.tabWidget.setStyleSheet("QTabBar::tab { height: 30px; }")
|
2016-04-06 10:50:54 +02:00
|
|
|
self.runAsBatchButton = QPushButton(self.tr("Run as batch process..."))
|
|
|
|
self.runAsBatchButton.clicked.connect(self.runAsBatch)
|
|
|
|
layout.addWidget(self.runAsBatchButton)
|
|
|
|
self.cornerWidget.setLayout(layout)
|
|
|
|
self.tabWidget.setCornerWidget(self.cornerWidget)
|
2015-09-24 12:07:46 +02:00
|
|
|
|
|
|
|
def runAsBatch(self):
|
2016-08-23 14:41:07 +02:00
|
|
|
self.close()
|
2015-09-24 12:07:46 +02:00
|
|
|
dlg = BatchAlgorithmDialog(self.alg)
|
2016-08-23 14:41:07 +02:00
|
|
|
dlg.show()
|
2015-09-24 12:07:46 +02:00
|
|
|
dlg.exec_()
|
|
|
|
|
2014-11-12 11:42:29 +02:00
|
|
|
def setParamValues(self):
|
|
|
|
params = self.alg.parameters
|
|
|
|
outputs = self.alg.outputs
|
|
|
|
|
|
|
|
for param in params:
|
|
|
|
if param.hidden:
|
|
|
|
continue
|
2016-09-07 14:30:20 +02:00
|
|
|
wrapper = self.mainWidget.wrappers[param.name]
|
2016-08-23 10:49:32 +02:00
|
|
|
if not self.setParamValue(param, wrapper):
|
2016-09-07 14:30:20 +02:00
|
|
|
raise AlgorithmDialogBase.InvalidParameterValue(param, wrapper.widget)
|
2014-11-12 11:42:29 +02:00
|
|
|
|
|
|
|
for output in outputs:
|
|
|
|
if output.hidden:
|
|
|
|
continue
|
2016-11-17 12:06:24 +01:00
|
|
|
output.value = self.mainWidget.outputWidgets[output.name].getValue()
|
2014-11-12 11:42:29 +02:00
|
|
|
if isinstance(output, (OutputRaster, OutputVector, OutputTable)):
|
|
|
|
output.open = self.mainWidget.checkBoxes[output.name].isChecked()
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
2016-11-17 12:06:24 +01:00
|
|
|
def setParamValue(self, param, wrapper):
|
|
|
|
if wrapper.widget:
|
|
|
|
return param.setValue(wrapper.value())
|
|
|
|
else:
|
|
|
|
return True
|
2014-11-12 11:42:29 +02:00
|
|
|
|
2016-10-13 13:40:47 +02:00
|
|
|
def checkExtentCRS(self):
|
|
|
|
unmatchingCRS = False
|
|
|
|
hasExtent = False
|
2017-05-01 17:40:47 +10:00
|
|
|
context = dataobjects.createContext()
|
2016-10-13 13:40:47 +02:00
|
|
|
projectCRS = iface.mapCanvas().mapSettings().destinationCrs()
|
2017-04-05 14:37:06 +10:00
|
|
|
layers = QgsProcessingUtils.compatibleLayers(QgsProject.instance())
|
2016-10-13 13:40:47 +02:00
|
|
|
for param in self.alg.parameters:
|
|
|
|
if isinstance(param, (ParameterRaster, ParameterVector, ParameterMultipleInput)):
|
|
|
|
if param.value:
|
|
|
|
if isinstance(param, ParameterMultipleInput):
|
|
|
|
inputlayers = param.value.split(';')
|
|
|
|
else:
|
|
|
|
inputlayers = [param.value]
|
|
|
|
for inputlayer in inputlayers:
|
|
|
|
for layer in layers:
|
|
|
|
if layer.source() == inputlayer:
|
|
|
|
if layer.crs() != projectCRS:
|
|
|
|
unmatchingCRS = True
|
|
|
|
|
2017-05-02 13:40:49 +10:00
|
|
|
p = QgsProcessingUtils.mapLayerFromString(inputlayer, context)
|
2016-10-13 13:40:47 +02:00
|
|
|
if p is not None:
|
|
|
|
if p.crs() != projectCRS:
|
|
|
|
unmatchingCRS = True
|
|
|
|
if isinstance(param, ParameterExtent):
|
2017-02-10 13:39:46 +10:00
|
|
|
if param.skip_crs_check:
|
|
|
|
continue
|
|
|
|
|
2016-11-17 12:06:24 +01:00
|
|
|
value = self.mainWidget.wrappers[param.name].widget.leText.text().strip()
|
2016-10-13 13:40:47 +02:00
|
|
|
if value:
|
|
|
|
hasExtent = True
|
|
|
|
|
|
|
|
return hasExtent and unmatchingCRS
|
|
|
|
|
2014-11-12 11:42:29 +02:00
|
|
|
def accept(self):
|
2015-09-11 09:33:51 +02:00
|
|
|
self.settings.setValue("/Processing/dialogBase", self.saveGeometry())
|
|
|
|
|
2017-04-29 12:14:53 +02:00
|
|
|
context = dataobjects.createContext()
|
|
|
|
|
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
|
|
|
checkCRS = ProcessingConfig.getSetting(ProcessingConfig.WARN_UNMATCHING_CRS)
|
2014-11-12 11:42:29 +02:00
|
|
|
try:
|
|
|
|
self.setParamValues()
|
|
|
|
if checkCRS and not self.alg.checkInputCRS():
|
|
|
|
reply = QMessageBox.question(self, self.tr("Unmatching CRS's"),
|
2015-08-22 14:29:41 +02:00
|
|
|
self.tr('Layers do not all use the same CRS. This can '
|
|
|
|
'cause unexpected results.\nDo you want to '
|
|
|
|
'continue?'),
|
|
|
|
QMessageBox.Yes | QMessageBox.No,
|
|
|
|
QMessageBox.No)
|
2014-11-12 11:42:29 +02:00
|
|
|
if reply == QMessageBox.No:
|
|
|
|
return
|
2016-10-13 13:40:47 +02:00
|
|
|
checkExtentCRS = ProcessingConfig.getSetting(ProcessingConfig.WARN_UNMATCHING_EXTENT_CRS)
|
|
|
|
if checkExtentCRS and self.checkExtentCRS():
|
|
|
|
reply = QMessageBox.question(self, self.tr("Extent CRS"),
|
|
|
|
self.tr('Extent parameters must use the same CRS as the input layers.\n'
|
|
|
|
'Your input layers do not have the same extent as the project, '
|
|
|
|
'so the extent might be in a wrong CRS if you have selected it from the canvas.\n'
|
|
|
|
'Do you want to continue?'),
|
|
|
|
QMessageBox.Yes | QMessageBox.No,
|
|
|
|
QMessageBox.No)
|
|
|
|
if reply == QMessageBox.No:
|
|
|
|
return
|
2017-04-29 12:14:53 +02:00
|
|
|
msg = self.alg._checkParameterValuesBeforeExecuting(context)
|
2014-11-12 11:42:29 +02:00
|
|
|
if msg:
|
|
|
|
QMessageBox.warning(
|
|
|
|
self, self.tr('Unable to execute algorithm'), msg)
|
|
|
|
return
|
|
|
|
self.btnRun.setEnabled(False)
|
|
|
|
self.btnClose.setEnabled(False)
|
|
|
|
buttons = self.mainWidget.iterateButtons
|
|
|
|
self.iterateParam = None
|
|
|
|
|
2016-09-21 18:24:26 +02:00
|
|
|
for i in range(len(list(buttons.values()))):
|
|
|
|
button = list(buttons.values())[i]
|
2014-11-12 11:42:29 +02:00
|
|
|
if button.isChecked():
|
2016-09-21 18:24:26 +02:00
|
|
|
self.iterateParam = list(buttons.keys())[i]
|
2014-11-12 11:42:29 +02:00
|
|
|
break
|
|
|
|
|
|
|
|
self.progressBar.setMaximum(0)
|
|
|
|
self.lblProgress.setText(self.tr('Processing algorithm...'))
|
2014-11-12 19:36:12 +02:00
|
|
|
# Make sure the Log tab is visible before executing the algorithm
|
2014-11-12 11:42:29 +02:00
|
|
|
try:
|
|
|
|
self.tabWidget.setCurrentIndex(1)
|
|
|
|
self.repaint()
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
|
|
|
|
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
|
|
|
|
|
|
|
|
self.setInfo(
|
2017-03-29 12:51:59 +10:00
|
|
|
self.tr('<b>Algorithm {0} starting...</b>').format(self.alg.displayName()))
|
2014-11-12 11:42:29 +02:00
|
|
|
|
|
|
|
if self.iterateParam:
|
2017-04-25 15:57:24 +10:00
|
|
|
if executeIterating(self.alg, self.iterateParam, context, self.feedback):
|
2017-04-26 14:33:53 +10:00
|
|
|
self.finish(context)
|
2014-11-12 11:42:29 +02:00
|
|
|
else:
|
|
|
|
QApplication.restoreOverrideCursor()
|
|
|
|
self.resetGUI()
|
|
|
|
else:
|
|
|
|
command = self.alg.getAsCommand()
|
|
|
|
if command:
|
2017-04-24 14:35:50 +10:00
|
|
|
ProcessingLog.addToLog(command)
|
2017-04-26 14:33:53 +10:00
|
|
|
if execute(self.alg, context, self.feedback):
|
|
|
|
self.finish(context)
|
2014-11-12 11:42:29 +02:00
|
|
|
else:
|
|
|
|
QApplication.restoreOverrideCursor()
|
|
|
|
self.resetGUI()
|
2015-08-22 14:29:41 +02:00
|
|
|
except AlgorithmDialogBase.InvalidParameterValue as e:
|
2014-11-12 11:42:29 +02:00
|
|
|
try:
|
2016-11-15 09:07:58 +07:00
|
|
|
self.buttonBox.accepted.connect(lambda e=e:
|
2015-08-22 14:29:41 +02:00
|
|
|
e.widget.setPalette(QPalette()))
|
2014-11-12 11:42:29 +02:00
|
|
|
palette = e.widget.palette()
|
|
|
|
palette.setColor(QPalette.Base, QColor(255, 255, 0))
|
|
|
|
e.widget.setPalette(palette)
|
|
|
|
except:
|
2016-09-16 14:32:30 +02:00
|
|
|
pass
|
|
|
|
self.bar.clearWidgets()
|
2017-03-04 16:23:36 +01:00
|
|
|
self.bar.pushMessage("", self.tr("Wrong or missing parameter value: {0}").format(e.parameter.description),
|
2016-09-16 14:32:30 +02:00
|
|
|
level=QgsMessageBar.WARNING, duration=5)
|
2014-11-12 11:42:29 +02:00
|
|
|
|
2017-04-26 14:33:53 +10:00
|
|
|
def finish(self, context):
|
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
|
|
|
keepOpen = ProcessingConfig.getSetting(ProcessingConfig.KEEP_DIALOG_OPEN)
|
2014-11-12 11:42:29 +02:00
|
|
|
|
|
|
|
if self.iterateParam is None:
|
2017-04-26 14:33:53 +10:00
|
|
|
if not handleAlgorithmResults(self.alg, context, self.feedback, not keepOpen):
|
2015-05-20 20:21:34 +02:00
|
|
|
self.resetGUI()
|
|
|
|
return
|
2014-11-12 11:42:29 +02:00
|
|
|
|
|
|
|
self.executed = True
|
2017-03-29 12:51:59 +10:00
|
|
|
self.setInfo(self.tr('Algorithm {0} finished').format(self.alg.displayName()))
|
2014-11-12 11:42:29 +02:00
|
|
|
QApplication.restoreOverrideCursor()
|
|
|
|
|
|
|
|
if not keepOpen:
|
|
|
|
self.close()
|
|
|
|
else:
|
|
|
|
self.resetGUI()
|
|
|
|
if self.alg.getHTMLOutputsCount() > 0:
|
|
|
|
self.setInfo(
|
|
|
|
self.tr('HTML output has been generated by this algorithm.'
|
|
|
|
'\nOpen the results dialog to check it.'))
|
2016-01-18 14:16:31 +01:00
|
|
|
|
|
|
|
def closeEvent(self, evt):
|
2016-12-10 15:18:12 +08:00
|
|
|
QgsProject.instance().layerWasAdded.disconnect(self.mainWidget.layerRegistryChanged)
|
|
|
|
QgsProject.instance().layersWillBeRemoved.disconnect(self.mainWidget.layerRegistryChanged)
|
2016-01-18 14:16:31 +01:00
|
|
|
super(AlgorithmDialog, self).closeEvent(evt)
|