Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
processing: add option to select directory to recurse for files (fixe…
…s regression with a number of tools that used to have this - eg. buildvrt for instance)
  • Loading branch information
jef-n committed May 31, 2019
1 parent d7fdbbe commit 5a54eb7
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 32 deletions.
19 changes: 11 additions & 8 deletions python/plugins/processing/algs/gdal/GdalUtils.py
Expand Up @@ -405,15 +405,18 @@ def parseCreationOptions(value):
@staticmethod
def writeLayerParameterToTextFile(filename, alg, parameters, parameter_name, context, quote=True, executing=False):
listFile = QgsProcessingUtils.generateTempFilename(filename)
with open(listFile, 'w') as f:
if executing:
layers = []
for l in alg.parameterAsLayerList(parameters, parameter_name, context):
if quote:
layers.append('"' + l.source() + '"')
else:
layers.append(l.source())

layers = []
for l in alg.parameterAsLayerList(parameters, parameter_name, context):
if quote:
layers.append('"' + l.source() + '"')
else:
layers.append(l.source())

if executing:
with open(listFile, 'w') as f:
f.write('\n'.join(layers))

return listFile

@staticmethod
Expand Down
3 changes: 3 additions & 0 deletions python/plugins/processing/algs/gdal/buildvrt.py
Expand Up @@ -76,6 +76,9 @@ def type(self):
def defaultFileExtension(self):
return 'vrt'

def parameterAsOutputLayer(self, definition, value, context):
return super(QgsProcessingParameterRasterDestination, self).parameterAsOutputLayer(definition, value, context)

self.RESAMPLING_OPTIONS = ((self.tr('Nearest Neighbour'), 'nearest'),
(self.tr('Bilinear'), 'bilinear'),
(self.tr('Cubic Convolution'), 'cubic'),
Expand Down
12 changes: 3 additions & 9 deletions python/plugins/processing/gui/BatchAlgorithmDialog.py
Expand Up @@ -24,21 +24,15 @@
from pprint import pformat
import time

from qgis.PyQt.QtWidgets import QMessageBox, QPushButton, QDialogButtonBox
from qgis.PyQt.QtWidgets import QPushButton, QDialogButtonBox
from qgis.PyQt.QtCore import Qt, QCoreApplication

from qgis.core import (QgsProcessingParameterDefinition,
QgsProcessingParameterRasterDestination,
QgsProcessingParameterVectorDestination,
QgsProcessingParameterFeatureSink,
QgsProcessingOutputLayerDefinition,
QgsProcessingOutputHtml,
from qgis.core import (QgsProcessingOutputHtml,
QgsProcessingOutputNumber,
QgsProcessingOutputString,
QgsProcessingOutputBoolean,
QgsProject,
QgsProcessingMultiStepFeedback,
Qgis,
QgsScopedProxyProgressTask)

from qgis.gui import QgsProcessingAlgorithmDialogBase
Expand Down Expand Up @@ -104,7 +98,7 @@ def runAlgorithm(self):
try:
self.showLog()
self.repaint()
except:
except Exception: # FIXME which one?
pass

start_time = time.time()
Expand Down
66 changes: 52 additions & 14 deletions python/plugins/processing/gui/BatchInputSelectionPanel.py
Expand Up @@ -22,19 +22,20 @@
__copyright__ = '(C) 2012, Victor Olaya'

import os
from pathlib import Path

from qgis.PyQt.QtCore import pyqtSignal, QCoreApplication
from qgis.PyQt.QtWidgets import QWidget, QHBoxLayout, QMenu, QPushButton, QLineEdit, QSizePolicy, QAction, QFileDialog
from qgis.PyQt.QtGui import QCursor

from qgis.core import (QgsMapLayer,
QgsRasterLayer,
QgsSettings,
QgsProject,
QgsProcessing,
QgsProcessingUtils,
QgsProcessingParameterMultipleLayers,
QgsProcessingParameterRasterLayer,
QgsProcessingParameterDefinition,
QgsProcessingParameterVectorLayer,
QgsProcessingParameterMeshLayer,
QgsProcessingParameterFeatureSource)
Expand Down Expand Up @@ -81,30 +82,35 @@ def _table(self):
def showPopupMenu(self):
popupmenu = QMenu()

if not (isinstance(self.param, QgsProcessingParameterMultipleLayers) and
self.param.layerType == dataobjects.TYPE_FILE):
if not (isinstance(self.param, QgsProcessingParameterMultipleLayers)
and self.param.layerType == dataobjects.TYPE_FILE):
selectLayerAction = QAction(
QCoreApplication.translate('BatchInputSelectionPanel', 'Select from Open Layers…'), self.pushButton)
selectLayerAction.triggered.connect(self.showLayerSelectionDialog)
popupmenu.addAction(selectLayerAction)

selectFileAction = QAction(
QCoreApplication.translate('BatchInputSelectionPanel', 'Select from File System…'), self.pushButton)
QCoreApplication.translate('BatchInputSelectionPanel', 'Select Files…'), self.pushButton)
selectFileAction.triggered.connect(self.showFileSelectionDialog)
popupmenu.addAction(selectFileAction)

selectDirectoryAction = QAction(
QCoreApplication.translate('BatchInputSelectionPanel', 'Select Directory…'), self.pushButton)
selectDirectoryAction.triggered.connect(self.showDirectorySelectionDialog)
popupmenu.addAction(selectDirectoryAction)

popupmenu.exec_(QCursor.pos())

def showLayerSelectionDialog(self):
layers = []
if (isinstance(self.param, QgsProcessingParameterRasterLayer) or
(isinstance(self.param, QgsProcessingParameterMultipleLayers) and
if (isinstance(self.param, QgsProcessingParameterRasterLayer)
or (isinstance(self.param, QgsProcessingParameterMultipleLayers) and
self.param.layerType() == QgsProcessing.TypeRaster)):
layers = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance())
elif isinstance(self.param, QgsProcessingParameterVectorLayer):
layers = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance())
elif (isinstance(self.param, QgsProcessingParameterMeshLayer) or
(isinstance(self.param, QgsProcessingParameterMultipleLayers) and
elif (isinstance(self.param, QgsProcessingParameterMeshLayer)
or (isinstance(self.param, QgsProcessingParameterMultipleLayers) and
self.param.layerType() == QgsProcessing.TypeMesh)):
layers = QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance())
else:
Expand Down Expand Up @@ -146,23 +152,55 @@ def generate_layer_id(layer):
self.col).setValue(generate_layer_id(layers[layeridx]))

def showFileSelectionDialog(self):
self.showFileDialog(seldir=False)

def showDirectorySelectionDialog(self):
self.showFileDialog(seldir=True)

def showFileDialog(self, seldir):
settings = QgsSettings()
text = str(self.text.text())
if os.path.isdir(text):
path = text
elif os.path.isdir(os.path.dirname(text)):
elif not seldir and os.path.isdir(os.path.dirname(text)):
path = os.path.dirname(text)
elif settings.contains('/Processing/LastInputPath'):
path = str(settings.value('/Processing/LastInputPath'))
else:
path = ''

ret, selected_filter = QFileDialog.getOpenFileNames(self, self.tr('Select Files'), path,
getFileFilter(self.param))
if not seldir:
ret, selected_filter = QFileDialog.getOpenFileNames(
self, self.tr('Select Files'), path, getFileFilter(self.param)
)
else:
ret = QFileDialog.getExistingDirectory(self, self.tr('Select Directory'), path)

if ret:
files = list(ret)
settings.setValue('/Processing/LastInputPath',
os.path.dirname(str(files[0])))
if seldir:
settings.setValue('/Processing/LastInputPath', ret)

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

p = pp.as_posix()

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

files.append(p)

if not files:
return

else:
files = list(ret)
settings.setValue('/Processing/LastInputPath', os.path.dirname(str(files[0])))

for i, filename in enumerate(files):
files[i] = dataobjects.getRasterSublayer(filename, self.param)
if len(files) == 1:
Expand Down
45 changes: 44 additions & 1 deletion python/plugins/processing/gui/MultipleInputDialog.py
Expand Up @@ -23,6 +23,7 @@

import os
import warnings
from pathlib import Path

from qgis.core import (QgsSettings,
QgsProcessing,
Expand All @@ -33,7 +34,6 @@
from qgis.PyQt.QtCore import Qt, QByteArray, QCoreApplication
from qgis.PyQt.QtWidgets import QDialog, QAbstractItemView, QPushButton, QDialogButtonBox, QFileDialog
from qgis.PyQt.QtGui import QStandardItemModel, QStandardItem
from processing.tools import dataobjects

pluginPath = os.path.split(os.path.dirname(__file__))[0]
with warnings.catch_warnings():
Expand Down Expand Up @@ -75,6 +75,11 @@ def __init__(self, options, selectedoptions=None, datatype=None):
self.buttonBox.addButton(btnAddFile,
QDialogButtonBox.ActionRole)

btnAddDir = QPushButton(QCoreApplication.translate("MultipleInputDialog", 'Add Directory…'))
btnAddDir.clicked.connect(self.addDirectory)
self.buttonBox.addButton(btnAddDir,
QDialogButtonBox.ActionRole)

self.btnSelectAll.clicked.connect(lambda: self.selectAll(True))
self.btnClearSelection.clicked.connect(lambda: self.selectAll(False))
self.btnToggleSelection.clicked.connect(self.toggleSelection)
Expand Down Expand Up @@ -182,3 +187,41 @@ def addFiles(self):
item.setCheckable(True)
item.setDropEnabled(False)
self.model.appendRow(item)

def addDirectory(self):
settings = QgsSettings()
path = str(settings.value('/Processing/LastInputPath'))

ret = QFileDialog.getExistingDirectory(self, self.tr('Select File(s)'), path)
if ret:
exts = []

if self.datatype == QgsProcessing.TypeVector:
exts = QgsVectorFileWriter.supportedFormatExtensions()
elif self.datatype == QgsProcessing.TypeRaster:
for t in QgsProviderRegistry.instance().fileRasterFilters().split(';;')[1:]:
for e in t[t.index('(') + 1:-1].split(' '):
if e != "*.*" and e.startswith("*."):
exts.append(e[2:])

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

if exts and pp.suffix[1:] not in exts:
continue

p = pp.as_posix()

files.append(p)

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

for filename in files:
item = QStandardItem(filename)
item.setData(filename, Qt.UserRole)
item.setCheckState(Qt.Checked)
item.setCheckable(True)
item.setDropEnabled(False)
self.model.appendRow(item)

0 comments on commit 5a54eb7

Please sign in to comment.