""" *************************************************************************** BatchOutputSelectionPanel.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. * * * *************************************************************************** """ __author__ = "Victor Olaya" __date__ = "August 2012" __copyright__ = "(C) 2012, Victor Olaya" import os import re from qgis.core import ( QgsMapLayer, QgsSettings, QgsProcessingParameterFolderDestination, QgsProcessingParameterRasterLayer, QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer, QgsProcessingParameterMultipleLayers, QgsProcessingParameterMapLayer, QgsProcessingParameterBoolean, QgsProcessingParameterEnum, QgsProject, QgsProcessingParameterMatrix, QgsApplication, ) from qgis.PyQt.QtWidgets import ( QWidget, QPushButton, QLineEdit, QHBoxLayout, QSizePolicy, QFileDialog, QMenu, ) from qgis.PyQt.QtGui import QAction from processing.gui.AutofillDialog import AutofillDialog class BatchOutputSelectionPanel(QWidget): def __init__(self, output, alg, row, col, panel): super().__init__(None) self.alg = alg self.row = row self.col = col self.output = output self.panel = panel self.table = self.panel.tblParameters self.horizontalLayout = QHBoxLayout(self) self.horizontalLayout.setSpacing(2) self.horizontalLayout.setMargin(0) self.text = QLineEdit() self.text.setText("") self.text.setMinimumWidth(300) self.text.setSizePolicy( QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding ) self.horizontalLayout.addWidget(self.text) self.pushButton = QPushButton() self.pushButton.setText("…") self.actionTemporaryOutput = QAction( self.tr("Create Temporary Layer"), self, ) self.actionTemporaryOutput.setCheckable(True) self.actionTemporaryOutput.changed.connect(self.onTemporaryOutputChanged) if isinstance(self.output, QgsProcessingParameterFolderDestination): self.pushButton.clicked.connect(self.showSelectionDialog) else: self.menu = QMenu(self.pushButton) self.menu.addAction( self.tr("Select File/Folder…"), self.showSelectionDialog ) self.menu.addAction(self.actionTemporaryOutput) self.pushButton.setMenu(self.menu) self.horizontalLayout.addWidget(self.pushButton) self.setLayout(self.horizontalLayout) self.actionTemporaryOutputIcon = QAction( QgsApplication.getThemeIcon("/mActionCreateMemory.svg"), self.tr("Temporary Output"), self, ) def showSelectionDialog(self): if isinstance(self.output, QgsProcessingParameterFolderDestination): self.selectDirectory() return filefilter = self.output.createFileFilter() settings = QgsSettings() if settings.contains("/Processing/LastBatchOutputPath"): path = str(settings.value("/Processing/LastBatchOutputPath")) else: path = "" filename, selectedFileFilter = QFileDialog.getSaveFileName( self, self.tr("Save File"), path, filefilter ) if filename: self.actionTemporaryOutput.setChecked(False) if not filename.lower().endswith( tuple(re.findall("\\*(\\.[a-z]{1,10})", filefilter)) ): ext = re.search("\\*(\\.[a-z]{1,10})", selectedFileFilter) if ext: filename += ext.group(1) settings.setValue( "/Processing/LastBatchOutputPath", os.path.dirname(filename) ) dlg = AutofillDialog(self.alg) dlg.exec() if dlg.mode is not None: if dlg.mode == AutofillDialog.DO_NOT_AUTOFILL: self.table.cellWidget(self.row, self.col).setValue(filename) elif dlg.mode == AutofillDialog.FILL_WITH_NUMBERS: n = self.table.rowCount() - self.row for i in range(n): name = ( filename[: filename.rfind(".")] + str(i + 1) + filename[filename.rfind(".") :] ) self.table.cellWidget(i + self.row, self.col).setValue(name) self.table.cellWidget( i + self.row, self.col ).setTemporaryOutput(False) elif dlg.mode == AutofillDialog.FILL_WITH_PARAMETER: for row in range(self.row, self.table.rowCount()): v = self.panel.valueForParameter(row - 1, dlg.param_name) param = self.alg.parameterDefinition(dlg.param_name) if isinstance( param, ( QgsProcessingParameterRasterLayer, QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer, QgsProcessingParameterMultipleLayers, QgsProcessingParameterMapLayer, ), ): if isinstance(v, QgsMapLayer): s = v.name() else: if v in QgsProject.instance().mapLayers(): layer = QgsProject.instance().mapLayer(v) # value is a layer ID, but we'd prefer to show a layer name if it's unique in the project if ( len( [ l for _, l in QgsProject.instance() .mapLayers() .items() if l.name().lower() == layer.name().lower() ] ) == 1 ): s = layer.name() else: # otherwise fall back to layer id s = v else: # else try to use file base name # TODO: this is bad for database sources!! s = os.path.basename(v) s = os.path.splitext(s)[0] elif isinstance(param, QgsProcessingParameterBoolean): s = "true" if v else "false" elif isinstance(param, QgsProcessingParameterEnum): s = param.options()[v] else: s = str(v) name = ( filename[: filename.rfind(".")] + s + filename[filename.rfind(".") :] ) self.table.cellWidget(row, self.col).setValue(name) self.table.cellWidget(row, self.col).setTemporaryOutput(False) def selectDirectory(self): settings = QgsSettings() if settings.contains("/Processing/LastBatchOutputPath"): lastDir = str(settings.value("/Processing/LastBatchOutputPath")) else: lastDir = "" dirName = QFileDialog.getExistingDirectory( self, self.tr("Output Directory"), lastDir, QFileDialog.Option.ShowDirsOnly ) if dirName: self.table.cellWidget(self.row, self.col).setValue(dirName) settings.setValue("/Processing/LastBatchOutputPath", dirName) def setValue(self, text): return self.text.setText(text) def getValue(self): return str(self.text.text()) def outputName(self) -> str: return self.text.text() def isTemporaryOutput(self) -> bool: return self.actionTemporaryOutput.isChecked() def onTemporaryOutputChanged(self) -> None: if self.actionTemporaryOutput.isChecked(): self.text.addAction( self.actionTemporaryOutputIcon, QLineEdit.LeadingPosition ) else: self.text.removeAction(self.actionTemporaryOutputIcon) self.text.repaint() def setTemporaryOutput(self, temporary: bool) -> None: self.actionTemporaryOutput.setChecked(temporary)