Skip to content

Commit

Permalink
[processing] When running in a batch mode, move the layer adding
Browse files Browse the repository at this point in the history
actions to the "Autofill" menu

This adds more UI consistency, as currently there's a disconnect
from the autofill options available via the Autofill buttons
vs some options which need to be done from the first rows "..."
button
  • Loading branch information
nyalldawson committed Mar 28, 2020
1 parent c81ef4d commit 3d30471
Showing 1 changed file with 132 additions and 1 deletion.
133 changes: 132 additions & 1 deletion python/plugins/processing/gui/BatchPanel.py
Expand Up @@ -24,6 +24,7 @@
import os
import json
import warnings
from pathlib import Path

from qgis.PyQt import uic
from qgis.PyQt.QtWidgets import (
Expand Down Expand Up @@ -60,10 +61,14 @@
QgsProcessingParameterFeatureSource,
QgsProcessingParameterRasterDestination,
QgsProcessingParameterVectorDestination,
QgsProcessingParameterMultipleLayers,
QgsProcessingParameterFeatureSink,
QgsProcessingOutputLayerDefinition,
QgsExpressionContextUtils,
QgsExpression
QgsProcessing,
QgsExpression,
QgsRasterLayer,
QgsProcessingUtils
)
from qgis.gui import (
QgsProcessingParameterWidgetContext,
Expand All @@ -79,6 +84,7 @@

from processing.tools import dataobjects
from processing.tools.dataobjects import createContext
from processing.gui.MultipleInputDialog import MultipleInputDialog

pluginPath = os.path.split(os.path.dirname(__file__))[0]

Expand Down Expand Up @@ -146,6 +152,22 @@ def createMenu(self):
find_by_pattern_action.setToolTip(self.tr('Adds files by a file pattern match'))
self.menu.addAction(find_by_pattern_action)

select_file_action = QAction(
QCoreApplication.translate('BatchInputSelectionPanel', 'Select Files…'), self.menu)
select_file_action.triggered.connect(self.showFileSelectionDialog)
self.menu.addAction(select_file_action)

select_directory_action = QAction(
QCoreApplication.translate('BatchInputSelectionPanel', 'Add All Files from a Directory…'), self.menu)
select_directory_action.triggered.connect(self.showDirectorySelectionDialog)
self.menu.addAction(select_directory_action)

if not isinstance(self.parameterDefinition, QgsProcessingParameterFile):
select_layer_action = QAction(
QCoreApplication.translate('BatchInputSelectionPanel', 'Select from Open Layers…'), self.menu)
select_layer_action.triggered.connect(self.showLayerSelectionDialog)
self.menu.addAction(select_layer_action)

def fillDown(self):
"""
Copy the top value down
Expand Down Expand Up @@ -191,6 +213,115 @@ def addFilesByPattern(self):
for row, file in enumerate(files):
self.setRowValue(first_row + row, file, context)

def showFileSelectionDialog(self):
settings = QgsSettings()
if settings.contains('/Processing/LastInputPath'):
path = str(settings.value('/Processing/LastInputPath'))
else:
path = QDir.homePath()

files, selected_filter = QFileDialog.getOpenFileNames(
self, self.tr('Select Files'), path, self.parameterDefinition.createFileFilter()
)

if not files:
return

settings.setValue('/Processing/LastInputPath', os.path.dirname(str(files[0])))

context = dataobjects.createContext()

first_row = self.panel.batchRowCount() if self.panel.batchRowCount() > 1 else 0
for row, file in enumerate(files):
self.setRowValue(first_row + row, file, context)

def showDirectorySelectionDialog(self):
settings = QgsSettings()
if settings.contains('/Processing/LastInputPath'):
path = str(settings.value('/Processing/LastInputPath'))
else:
path = QDir.homePath()

folder = QFileDialog.getExistingDirectory(self, self.tr('Select Directory'), path)
if not folder:
return

settings.setValue('/Processing/LastInputPath', folder)

files = []
for pp in Path(folder).rglob("*"):
if not pp.is_file():
continue

p = pp.as_posix()

if ((isinstance(self.parameterDefinition, QgsProcessingParameterRasterLayer) or
(isinstance(self.parameterDefinition,
QgsProcessingParameterMultipleLayers) and self.param.layerType() == QgsProcessing.TypeRaster)) and
not QgsRasterLayer.isValidRasterFileName(p)):
continue

files.append(p)

if not files:
return

context = dataobjects.createContext()

first_row = self.panel.batchRowCount() if self.panel.batchRowCount() > 1 else 0
for row, file in enumerate(files):
self.setRowValue(first_row + row, file, context)

def showLayerSelectionDialog(self):
layers = []
if (isinstance(self.parameterDefinition, QgsProcessingParameterRasterLayer) or
(isinstance(self.parameterDefinition, QgsProcessingParameterMultipleLayers) and
self.param.layerType() == QgsProcessing.TypeRaster)):
layers = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance())
elif isinstance(self.parameterDefinition, QgsProcessingParameterVectorLayer):
layers = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance())
elif isinstance(self.parameterDefinition, QgsProcessingParameterMapLayer):
layers = QgsProcessingUtils.compatibleLayers(QgsProject.instance())
elif (isinstance(self.parameterDefinition, QgsProcessingParameterMeshLayer) or
(isinstance(self.parameterDefinition, QgsProcessingParameterMultipleLayers) and
self.parameterDefinition.layerType() == QgsProcessing.TypeMesh)):
layers = QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance())
else:
datatypes = [QgsProcessing.TypeVectorAnyGeometry]
if isinstance(self.parameterDefinition, QgsProcessingParameterFeatureSource):
datatypes = self.parameterDefinition.dataTypes()
elif isinstance(self.parameterDefinition, QgsProcessingParameterMultipleLayers):
datatypes = [self.parameterDefinition.layerType()]

if QgsProcessing.TypeVectorAnyGeometry not in datatypes:
layers = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), datatypes)
else:
layers = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance())

dlg = MultipleInputDialog([layer.name() for layer in layers])
dlg.exec_()

def generate_layer_id(layer):
# prefer layer name if unique
if len([l for l in layers if l.name().lower() == layer.name().lower()]) == 1:
return layer.name()
else:
# otherwise fall back to layer id
return layer.id()

if not dlg.selectedoptions:
return

selected = dlg.selectedoptions

context = dataobjects.createContext()

first_row = self.panel.batchRowCount() if self.panel.batchRowCount() > 1 else 0
for row, selected_idx in enumerate(selected):
layer = layers[selected_idx]
value = generate_layer_id(layer)
self.setRowValue(first_row + row, value, context)

def calculateByExpression(self):
"""
Calculates parameter values by evaluating expressions.
Expand Down

0 comments on commit 3d30471

Please sign in to comment.