2014-11-12 19:36:12 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
"""
|
|
|
|
***************************************************************************
|
|
|
|
BatchPanel.py
|
|
|
|
---------------------
|
|
|
|
Date : November 2014
|
|
|
|
Copyright : (C) 2014 by Alexander Bruy
|
|
|
|
Email : alexander dot bruy 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. *
|
|
|
|
* *
|
|
|
|
***************************************************************************
|
|
|
|
"""
|
|
|
|
|
|
|
|
__author__ = 'Alexander Bruy'
|
|
|
|
__date__ = 'November 2014'
|
|
|
|
__copyright__ = '(C) 2014, Alexander Bruy'
|
|
|
|
|
|
|
|
# This will get replaced with a git SHA1 when you do a git archive
|
|
|
|
|
|
|
|
__revision__ = '$Format:%H$'
|
|
|
|
|
2015-05-18 19:51:26 +03:00
|
|
|
import os
|
2016-01-14 16:29:21 +01:00
|
|
|
import json
|
2015-05-18 19:51:26 +03:00
|
|
|
|
2016-04-29 11:39:26 +02:00
|
|
|
from qgis.PyQt import uic
|
2017-03-04 16:23:36 +01:00
|
|
|
from qgis.PyQt.QtWidgets import QTableWidgetItem, QComboBox, QHeaderView, QFileDialog, QMessageBox
|
2017-11-10 13:17:01 +10:00
|
|
|
from qgis.PyQt.QtCore import QDir, QFileInfo
|
2017-05-16 15:21:41 +10:00
|
|
|
from qgis.core import (QgsApplication,
|
2017-11-10 13:17:01 +10:00
|
|
|
QgsSettings,
|
2017-05-16 15:21:41 +10:00
|
|
|
QgsProcessingParameterDefinition)
|
2016-09-16 14:32:30 +02:00
|
|
|
from qgis.gui import QgsMessageBar
|
2014-11-12 19:36:12 +02:00
|
|
|
|
2017-11-27 16:03:14 +02:00
|
|
|
from processing.gui.wrappers import WidgetWrapperFactory
|
2014-11-12 19:36:12 +02:00
|
|
|
from processing.gui.BatchOutputSelectionPanel import BatchOutputSelectionPanel
|
|
|
|
|
2017-05-16 15:21:41 +10:00
|
|
|
from processing.tools import dataobjects
|
2014-11-12 19:36:12 +02:00
|
|
|
|
2015-05-18 19:51:26 +03:00
|
|
|
pluginPath = os.path.split(os.path.dirname(__file__))[0]
|
2015-05-18 21:04:20 +03:00
|
|
|
WIDGET, BASE = uic.loadUiType(
|
|
|
|
os.path.join(pluginPath, 'ui', 'widgetBatchPanel.ui'))
|
2015-05-18 19:51:26 +03:00
|
|
|
|
2015-08-22 14:29:41 +02:00
|
|
|
|
2015-05-18 21:04:20 +03:00
|
|
|
class BatchPanel(BASE, WIDGET):
|
2014-11-12 19:36:12 +02:00
|
|
|
|
2016-01-14 16:29:21 +01:00
|
|
|
PARAMETERS = "PARAMETERS"
|
|
|
|
OUTPUTS = "OUTPUTS"
|
|
|
|
|
2014-11-12 19:36:12 +02:00
|
|
|
def __init__(self, parent, alg):
|
2015-05-18 21:04:20 +03:00
|
|
|
super(BatchPanel, self).__init__(None)
|
2014-11-12 19:36:12 +02:00
|
|
|
self.setupUi(self)
|
|
|
|
|
2016-09-07 14:30:20 +02:00
|
|
|
self.wrappers = []
|
2016-08-23 14:40:06 +02:00
|
|
|
|
2014-11-12 19:36:12 +02:00
|
|
|
self.btnAdvanced.hide()
|
|
|
|
|
|
|
|
# Set icons
|
2015-06-22 16:20:27 +02:00
|
|
|
self.btnAdd.setIcon(QgsApplication.getThemeIcon('/symbologyAdd.svg'))
|
|
|
|
self.btnRemove.setIcon(QgsApplication.getThemeIcon('/symbologyRemove.svg'))
|
2016-01-14 16:29:21 +01:00
|
|
|
self.btnOpen.setIcon(QgsApplication.getThemeIcon('/mActionFileOpen.svg'))
|
|
|
|
self.btnSave.setIcon(QgsApplication.getThemeIcon('/mActionFileSave.svg'))
|
2017-01-09 12:34:46 +10:00
|
|
|
self.btnAdvanced.setIcon(QgsApplication.getThemeIcon("/processingAlgorithm.svg"))
|
2014-11-12 19:36:12 +02:00
|
|
|
|
|
|
|
self.alg = alg
|
|
|
|
self.parent = parent
|
|
|
|
|
|
|
|
self.btnAdd.clicked.connect(self.addRow)
|
|
|
|
self.btnRemove.clicked.connect(self.removeRows)
|
2016-01-14 16:29:21 +01:00
|
|
|
self.btnOpen.clicked.connect(self.load)
|
|
|
|
self.btnSave.clicked.connect(self.save)
|
2014-11-12 19:36:12 +02:00
|
|
|
self.btnAdvanced.toggled.connect(self.toggleAdvancedMode)
|
|
|
|
self.tblParameters.horizontalHeader().sectionDoubleClicked.connect(
|
|
|
|
self.fillParameterValues)
|
|
|
|
|
2017-11-10 11:25:11 +10:00
|
|
|
self.tblParameters.horizontalHeader().resizeSections(QHeaderView.ResizeToContents)
|
|
|
|
self.tblParameters.horizontalHeader().setDefaultSectionSize(250)
|
|
|
|
self.tblParameters.horizontalHeader().setMinimumSectionSize(150)
|
|
|
|
|
2014-11-12 19:36:12 +02:00
|
|
|
self.initWidgets()
|
2016-09-16 14:32:30 +02:00
|
|
|
|
2016-09-14 09:51:17 +02:00
|
|
|
def layerRegistryChanged(self):
|
|
|
|
pass
|
2014-11-12 19:36:12 +02:00
|
|
|
|
|
|
|
def initWidgets(self):
|
|
|
|
# If there are advanced parameters — show corresponding button
|
2017-06-13 12:32:30 +10:00
|
|
|
for param in self.alg.parameterDefinitions():
|
2017-05-16 16:36:00 +10:00
|
|
|
if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced:
|
2014-11-12 19:36:12 +02:00
|
|
|
self.btnAdvanced.show()
|
|
|
|
break
|
|
|
|
|
|
|
|
# Determine column count
|
2017-05-15 12:29:44 +10:00
|
|
|
nOutputs = len(self.alg.destinationParameterDefinitions()) + 1
|
2014-11-12 19:36:12 +02:00
|
|
|
if nOutputs == 1:
|
|
|
|
nOutputs = 0
|
|
|
|
|
|
|
|
self.tblParameters.setColumnCount(
|
2017-05-15 12:29:44 +10:00
|
|
|
self.alg.countVisibleParameters())
|
2014-11-12 19:36:12 +02:00
|
|
|
|
|
|
|
# Table headers
|
|
|
|
column = 0
|
2017-05-15 12:29:44 +10:00
|
|
|
for param in self.alg.parameterDefinitions():
|
|
|
|
if param.isDestination():
|
|
|
|
continue
|
2014-11-12 19:36:12 +02:00
|
|
|
self.tblParameters.setHorizontalHeaderItem(
|
2017-05-16 16:36:00 +10:00
|
|
|
column, QTableWidgetItem(param.description()))
|
|
|
|
if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced:
|
2014-11-12 19:36:12 +02:00
|
|
|
self.tblParameters.setColumnHidden(column, True)
|
|
|
|
column += 1
|
|
|
|
|
2017-05-15 12:29:44 +10:00
|
|
|
for out in self.alg.destinationParameterDefinitions():
|
2017-05-16 16:36:00 +10:00
|
|
|
if not out.flags() & QgsProcessingParameterDefinition.FlagHidden:
|
2014-11-12 19:36:12 +02:00
|
|
|
self.tblParameters.setHorizontalHeaderItem(
|
2017-05-16 16:36:00 +10:00
|
|
|
column, QTableWidgetItem(out.description()))
|
2014-11-12 19:36:12 +02:00
|
|
|
column += 1
|
|
|
|
|
|
|
|
# Last column for indicating if output will be added to canvas
|
2017-05-15 12:29:44 +10:00
|
|
|
if len(self.alg.destinationParameterDefinitions()) > 0:
|
2014-11-12 19:36:12 +02:00
|
|
|
self.tblParameters.setHorizontalHeaderItem(
|
|
|
|
column, QTableWidgetItem(self.tr('Load in QGIS')))
|
|
|
|
|
2017-11-10 13:48:54 +10:00
|
|
|
# Add an empty row to begin
|
|
|
|
self.addRow()
|
2014-11-12 19:36:12 +02:00
|
|
|
|
2017-11-10 11:25:11 +10:00
|
|
|
self.tblParameters.horizontalHeader().resizeSections(QHeaderView.ResizeToContents)
|
2016-11-03 16:32:28 +10:00
|
|
|
self.tblParameters.verticalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
|
2015-06-22 12:56:51 +02:00
|
|
|
self.tblParameters.horizontalHeader().setStretchLastSection(True)
|
|
|
|
|
2016-01-14 16:29:21 +01:00
|
|
|
def load(self):
|
2017-11-10 13:17:01 +10:00
|
|
|
settings = QgsSettings()
|
|
|
|
last_path = settings.value("/Processing/LastBatchPath", QDir.homePath())
|
2016-08-23 14:40:06 +02:00
|
|
|
filename, selected_filter = QFileDialog.getOpenFileName(self,
|
2017-11-10 13:17:01 +10:00
|
|
|
self.tr('Open Batch'), last_path,
|
2016-08-23 14:40:06 +02:00
|
|
|
self.tr('JSON files (*.json)'))
|
2016-01-14 16:29:21 +01:00
|
|
|
if filename:
|
2017-11-10 13:17:01 +10:00
|
|
|
last_path = QFileInfo(filename).path()
|
|
|
|
settings.setValue('/Processing/LastBatchPath', last_path)
|
2016-01-14 16:29:21 +01:00
|
|
|
with open(filename) as f:
|
|
|
|
values = json.load(f)
|
2016-02-17 11:53:36 +01:00
|
|
|
else:
|
|
|
|
# If the user clicked on the cancel button.
|
|
|
|
return
|
2016-01-14 16:29:21 +01:00
|
|
|
|
|
|
|
self.tblParameters.setRowCount(0)
|
2016-02-17 11:53:36 +01:00
|
|
|
try:
|
|
|
|
for row, alg in enumerate(values):
|
|
|
|
self.addRow()
|
|
|
|
params = alg[self.PARAMETERS]
|
|
|
|
outputs = alg[self.OUTPUTS]
|
|
|
|
column = 0
|
2017-05-16 16:36:00 +10:00
|
|
|
for param in self.alg.parameterDefinitions():
|
|
|
|
if param.flags() & QgsProcessingParameterDefinition.FlagHidden:
|
2016-02-17 11:53:36 +01:00
|
|
|
continue
|
2017-11-10 13:22:49 +10:00
|
|
|
if param.isDestination():
|
|
|
|
continue
|
2017-05-16 16:36:00 +10:00
|
|
|
if param.name() in params:
|
2017-11-10 13:22:49 +10:00
|
|
|
value = params[param.name()].strip("'")
|
2016-09-07 14:30:20 +02:00
|
|
|
wrapper = self.wrappers[row][column]
|
|
|
|
wrapper.setValue(value)
|
2016-02-17 11:53:36 +01:00
|
|
|
column += 1
|
|
|
|
|
2017-11-10 13:22:49 +10:00
|
|
|
for out in self.alg.destinationParameterDefinitions():
|
2017-05-16 16:36:00 +10:00
|
|
|
if out.flags() & QgsProcessingParameterDefinition.FlagHidden:
|
2016-02-17 11:53:36 +01:00
|
|
|
continue
|
2017-05-16 16:36:00 +10:00
|
|
|
if out.name() in outputs:
|
2017-11-10 13:22:49 +10:00
|
|
|
value = outputs[out.name()].strip("'")
|
2016-08-23 14:40:06 +02:00
|
|
|
widget = self.tblParameters.cellWidget(row, column)
|
2016-09-07 14:30:20 +02:00
|
|
|
widget.setValue(value)
|
2016-02-17 11:53:36 +01:00
|
|
|
column += 1
|
|
|
|
except TypeError:
|
|
|
|
QMessageBox.critical(
|
|
|
|
self,
|
|
|
|
self.tr('Error'),
|
2016-05-31 02:55:01 +02:00
|
|
|
self.tr('An error occurred while reading your file.'))
|
2016-01-14 16:29:21 +01:00
|
|
|
|
|
|
|
def save(self):
|
|
|
|
toSave = []
|
2017-05-16 15:21:41 +10:00
|
|
|
context = dataobjects.createContext()
|
2016-01-14 16:29:21 +01:00
|
|
|
for row in range(self.tblParameters.rowCount()):
|
|
|
|
algParams = {}
|
|
|
|
algOutputs = {}
|
|
|
|
col = 0
|
2017-05-19 10:24:59 +10:00
|
|
|
alg = self.alg
|
2017-05-16 15:21:41 +10:00
|
|
|
for param in alg.parameterDefinitions():
|
|
|
|
if param.flags() & QgsProcessingParameterDefinition.FlagHidden:
|
2016-01-14 16:29:21 +01:00
|
|
|
continue
|
2017-11-10 13:22:49 +10:00
|
|
|
if param.isDestination():
|
|
|
|
continue
|
2016-09-07 14:30:20 +02:00
|
|
|
wrapper = self.wrappers[row][col]
|
2017-11-10 13:22:49 +10:00
|
|
|
if not param.checkValueIsAcceptable(wrapper.value(), context):
|
2017-03-04 16:23:36 +01:00
|
|
|
self.parent.bar.pushMessage("", self.tr('Wrong or missing parameter value: {0} (row {1})').format(
|
2017-11-10 13:22:49 +10:00
|
|
|
param.description(), row + 1),
|
|
|
|
level=QgsMessageBar.WARNING, duration=5)
|
2016-01-14 16:29:21 +01:00
|
|
|
return
|
2017-11-10 13:22:49 +10:00
|
|
|
algParams[param.name()] = param.valueAsPythonString(wrapper.value(), context)
|
2016-01-14 16:29:21 +01:00
|
|
|
col += 1
|
2017-11-10 13:22:49 +10:00
|
|
|
for out in alg.destinationParameterDefinitions():
|
2017-05-16 16:36:00 +10:00
|
|
|
if out.flags() & QgsProcessingParameterDefinition.FlagHidden:
|
2016-01-14 16:29:21 +01:00
|
|
|
continue
|
|
|
|
widget = self.tblParameters.cellWidget(row, col)
|
|
|
|
text = widget.getValue()
|
|
|
|
if text.strip() != '':
|
2017-11-10 13:22:49 +10:00
|
|
|
algOutputs[out.name()] = text.strip()
|
2016-01-14 16:29:21 +01:00
|
|
|
col += 1
|
|
|
|
else:
|
2017-03-04 16:23:36 +01:00
|
|
|
self.parent.bar.pushMessage("", self.tr('Wrong or missing output value: {0} (row {1})').format(
|
2017-11-10 13:22:49 +10:00
|
|
|
out.description(), row + 1),
|
|
|
|
level=QgsMessageBar.WARNING, duration=5)
|
2016-01-14 16:29:21 +01:00
|
|
|
return
|
|
|
|
toSave.append({self.PARAMETERS: algParams, self.OUTPUTS: algOutputs})
|
|
|
|
|
2017-11-10 13:17:01 +10:00
|
|
|
settings = QgsSettings()
|
|
|
|
last_path = settings.value("/Processing/LastBatchPath", QDir.homePath())
|
2017-02-09 11:05:09 +01:00
|
|
|
filename, __ = QFileDialog.getSaveFileName(self,
|
2017-10-25 05:57:56 +02:00
|
|
|
self.tr('Save Batch'),
|
2017-11-10 13:17:01 +10:00
|
|
|
last_path,
|
2017-02-09 11:05:09 +01:00
|
|
|
self.tr('JSON files (*.json)'))
|
2016-01-14 16:29:21 +01:00
|
|
|
if filename:
|
|
|
|
if not filename.endswith('.json'):
|
|
|
|
filename += '.json'
|
2017-11-10 13:17:01 +10:00
|
|
|
last_path = QFileInfo(filename).path()
|
|
|
|
settings.setValue('/Processing/LastBatchPath', last_path)
|
2016-01-14 16:29:21 +01:00
|
|
|
with open(filename, 'w') as f:
|
|
|
|
json.dump(toSave, f)
|
|
|
|
|
2016-08-23 14:40:06 +02:00
|
|
|
def setCellWrapper(self, row, column, wrapper):
|
2016-09-07 14:30:20 +02:00
|
|
|
self.wrappers[row][column] = wrapper
|
2016-08-23 14:40:06 +02:00
|
|
|
self.tblParameters.setCellWidget(row, column, wrapper.widget)
|
|
|
|
|
2014-11-12 19:36:12 +02:00
|
|
|
def addRow(self):
|
2016-09-08 09:57:18 +02:00
|
|
|
self.wrappers.append([None] * self.tblParameters.columnCount())
|
2014-11-12 19:36:12 +02:00
|
|
|
self.tblParameters.setRowCount(self.tblParameters.rowCount() + 1)
|
|
|
|
|
2016-09-18 16:11:34 +02:00
|
|
|
wrappers = {}
|
2014-11-12 19:36:12 +02:00
|
|
|
row = self.tblParameters.rowCount() - 1
|
|
|
|
column = 0
|
2017-05-15 12:29:44 +10:00
|
|
|
for param in self.alg.parameterDefinitions():
|
2017-05-16 16:36:00 +10:00
|
|
|
if param.flags() & QgsProcessingParameterDefinition.FlagHidden or param.isDestination():
|
2014-11-12 19:36:12 +02:00
|
|
|
continue
|
|
|
|
|
2017-05-16 16:36:00 +10:00
|
|
|
wrapper = WidgetWrapperFactory.create_wrapper(param, self.parent, row, column)
|
|
|
|
wrappers[param.name()] = wrapper
|
2016-08-23 14:40:06 +02:00
|
|
|
self.setCellWrapper(row, column, wrapper)
|
2014-11-12 19:36:12 +02:00
|
|
|
column += 1
|
|
|
|
|
2017-05-15 12:29:44 +10:00
|
|
|
for out in self.alg.destinationParameterDefinitions():
|
2017-05-16 16:36:00 +10:00
|
|
|
if out.flags() & QgsProcessingParameterDefinition.FlagHidden:
|
2014-11-12 19:36:12 +02:00
|
|
|
continue
|
|
|
|
|
|
|
|
self.tblParameters.setCellWidget(
|
|
|
|
row, column, BatchOutputSelectionPanel(
|
|
|
|
out, self.alg, row, column, self))
|
|
|
|
column += 1
|
|
|
|
|
2017-05-15 12:29:44 +10:00
|
|
|
if len(self.alg.destinationParameterDefinitions()) > 0:
|
2014-11-12 19:36:12 +02:00
|
|
|
item = QComboBox()
|
|
|
|
item.addItem(self.tr('Yes'))
|
|
|
|
item.addItem(self.tr('No'))
|
|
|
|
item.setCurrentIndex(0)
|
|
|
|
self.tblParameters.setCellWidget(row, column, item)
|
|
|
|
|
2016-09-27 19:51:06 +02:00
|
|
|
for wrapper in list(wrappers.values()):
|
|
|
|
wrapper.postInitialize(list(wrappers.values()))
|
2016-09-18 16:11:34 +02:00
|
|
|
|
2014-11-12 19:36:12 +02:00
|
|
|
def removeRows(self):
|
2017-11-10 13:48:54 +10:00
|
|
|
if self.tblParameters.rowCount() > 1:
|
2016-09-08 09:57:18 +02:00
|
|
|
self.wrappers.pop()
|
2014-11-12 19:36:12 +02:00
|
|
|
self.tblParameters.setRowCount(self.tblParameters.rowCount() - 1)
|
|
|
|
|
|
|
|
def fillParameterValues(self, column):
|
2016-09-08 09:57:18 +02:00
|
|
|
wrapper = self.wrappers[0][column]
|
2017-11-10 13:40:50 +10:00
|
|
|
if wrapper is None:
|
|
|
|
# e.g. double clicking on a destination header
|
|
|
|
return
|
|
|
|
|
2016-09-08 09:57:18 +02:00
|
|
|
for row in range(1, self.tblParameters.rowCount()):
|
|
|
|
self.wrappers[row][column].setValue(wrapper.value())
|
2016-09-16 14:32:30 +02:00
|
|
|
|
2014-11-12 19:36:12 +02:00
|
|
|
def toggleAdvancedMode(self, checked):
|
2018-01-29 08:12:17 +01:00
|
|
|
for column, param in enumerate(self.alg.parameterDefinitions()):
|
2017-05-16 16:36:00 +10:00
|
|
|
if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced:
|
2014-11-12 19:36:12 +02:00
|
|
|
self.tblParameters.setColumnHidden(column, not checked)
|