Skip to content
Permalink
Browse files

Merge pull request #5024 from nyalldawson/build-vrt

Restore gdal build vrt alg, plus improvements
  • Loading branch information
nyalldawson committed Aug 17, 2017
2 parents fdee6ea + 8139786 commit 6d388942adf512b8bd0f1e4d935299ab194979f3
@@ -35,6 +35,7 @@

from .AssignProjection import AssignProjection
from .aspect import aspect
from .buildvrt import buildvrt
from .ColorRelief import ColorRelief
from .tri import tri
from .warp import warp
@@ -44,7 +45,6 @@
# from .translate import translate
# from .pct2rgb import pct2rgb
# from .merge import merge
# from .buildvrt import buildvrt
# from .polygonize import polygonize
# from .gdaladdo import gdaladdo
# from .ClipByExtent import ClipByExtent
@@ -144,14 +144,14 @@ def loadAlgorithms(self):
# information(),
AssignProjection(),
aspect(),
buildvrt(),
ColorRelief(),
tri(),
warp(),
# translate(),
# rgb2pct(),
# pct2rgb(),
# merge(),
# buildvrt(),
# polygonize(),
# gdaladdo(),
# ClipByExtent(),
@@ -29,14 +29,16 @@

from qgis.PyQt.QtGui import QIcon

from qgis.core import QgsProcessingUtils
from qgis.core import (QgsProcessing,
QgsProperty,
QgsProcessingParameterMultipleLayers,
QgsProcessingParameterEnum,
QgsProcessingParameterBoolean,
QgsProcessingParameterRasterDestination,
QgsProcessingOutputLayerDefinition,
QgsProcessingUtils)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.core.outputs import OutputRaster
from processing.core.parameters import ParameterBoolean
from processing.core.parameters import ParameterMultipleInput
from processing.core.parameters import ParameterSelection
from processing.algs.gdal.GdalUtils import GdalUtils
from processing.tools import dataobjects

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

@@ -55,15 +57,27 @@ def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(ParameterMultipleInput(self.INPUT,
self.tr('Input layers'), dataobjects.TYPE_RASTER))
self.addParameter(ParameterSelection(self.RESOLUTION,
self.tr('Resolution'), self.RESOLUTION_OPTIONS, 0))
self.addParameter(ParameterBoolean(self.SEPARATE,
self.tr('Layer stack'), True))
self.addParameter(ParameterBoolean(self.PROJ_DIFFERENCE,
self.tr('Allow projection difference'), False))
self.addOutput(OutputRaster(buildvrt.OUTPUT, self.tr('Virtual')))

class ParameterVrtDestination(QgsProcessingParameterRasterDestination):

def __init__(self, name, description):
super().__init__(name, description)

def type(self):
return 'vrt_destination'

def defaultFileExtension(self):
return 'vrt'

self.addParameter(QgsProcessingParameterMultipleLayers(self.INPUT,
self.tr('Input layers'), QgsProcessing.TypeRaster))
self.addParameter(QgsProcessingParameterEnum(self.RESOLUTION,
self.tr('Resolution'), options=self.RESOLUTION_OPTIONS, defaultValue=0))
self.addParameter(QgsProcessingParameterBoolean(self.SEPARATE,
self.tr('Layer stack'), defaultValue=True))
self.addParameter(QgsProcessingParameterBoolean(self.PROJ_DIFFERENCE,
self.tr('Allow projection difference'), defaultValue=False))
self.addParameter(ParameterVrtDestination(self.OUTPUT, self.tr('Virtual')))

def name(self):
return 'buildvirtualraster'
@@ -80,25 +94,34 @@ def group(self):
def getConsoleCommands(self, parameters, context, feedback):
arguments = []
arguments.append('-resolution')
arguments.append(self.RESOLUTION_OPTIONS[self.getParameterValue(self.RESOLUTION)])
if self.getParameterValue(buildvrt.SEPARATE):
arguments.append(self.RESOLUTION_OPTIONS[self.parameterAsEnum(parameters, self.RESOLUTION, context)])
if self.parameterAsBool(parameters, buildvrt.SEPARATE, context):
arguments.append('-separate')
if self.getParameterValue(buildvrt.PROJ_DIFFERENCE):
if self.parameterAsBool(parameters, buildvrt.PROJ_DIFFERENCE, context):
arguments.append('-allow_projection_difference')
# Always write input files to a text file in case there are many of them and the
# length of the command will be longer then allowed in command prompt
listFile = os.path.join(QgsProcessingUtils.tempFolder(), 'buildvrtInputFiles.txt')
with open(listFile, 'w') as f:
f.write(self.getParameterValue(buildvrt.INPUT).replace(';', '\n'))
layers = []
for l in self.parameterAsLayerList(parameters, self.INPUT, context):
layers.append(l.source())
f.write('\n'.join(layers))
arguments.append('-input_file_list')
arguments.append(listFile)
out = self.getOutputValue(buildvrt.OUTPUT)

out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
# Ideally the file extensions should be limited to just .vrt but I'm not sure how
# to do it simply so instead a check is performed.
_, ext = os.path.splitext(out)
if not ext.lower() == '.vrt':
out = out.replace(ext, '.vrt')
self.setOutputValue(self.OUTPUT, out)
out = out[:-len(ext)] + '.vrt'
if isinstance(parameters[self.OUTPUT], QgsProcessingOutputLayerDefinition):
output_def = QgsProcessingOutputLayerDefinition(parameters[self.OUTPUT])
output_def.sink = QgsProperty.fromValue(out)
self.setOutputValue(self.OUTPUT, output_def)
else:
self.setOutputValue(self.OUTPUT, out)
arguments.append(out)

return ['gdalbuildvrt', GdalUtils.escapeAndJoin(arguments)]
@@ -29,12 +29,17 @@

import os

from qgis.core import QgsSettings
from qgis.core import (QgsSettings,
QgsProcessing,
QgsVectorFileWriter,
QgsProviderRegistry,
QgsProcessingModelChildParameterSource)
from qgis.PyQt import uic
from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtCore import QByteArray
from qgis.PyQt.QtWidgets import QDialog, QAbstractItemView, QPushButton, QDialogButtonBox
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]
WIDGET, BASE = uic.loadUiType(
@@ -43,9 +48,11 @@

class MultipleInputDialog(BASE, WIDGET):

def __init__(self, options, selectedoptions=None):
def __init__(self, options, selectedoptions=None, datatype=None):
super(MultipleInputDialog, self).__init__(None)
self.setupUi(self)
self.datatype = datatype
self.model = None

self.lstLayers.setSelectionMode(QAbstractItemView.NoSelection)

@@ -68,6 +75,11 @@ def __init__(self, options, selectedoptions=None):
self.btnToggleSelection = QPushButton(self.tr('Toggle selection'))
self.buttonBox.addButton(self.btnToggleSelection,
QDialogButtonBox.ActionRole)
if self.datatype is not None:
btnAddFile = QPushButton(self.tr('Add file(s)…'))
btnAddFile.clicked.connect(self.addFiles)
self.buttonBox.addButton(btnAddFile,
QDialogButtonBox.ActionRole)

self.btnSelectAll.clicked.connect(lambda: self.selectAll(True))
self.btnClearSelection.clicked.connect(lambda: self.selectAll(False))
@@ -76,22 +88,34 @@ def __init__(self, options, selectedoptions=None):
self.settings = QgsSettings()
self.restoreGeometry(self.settings.value("/Processing/multipleInputDialogGeometry", QByteArray()))

self.lstLayers.setSelectionMode(QAbstractItemView.ExtendedSelection)
self.populateList()
self.finished.connect(self.saveWindowGeometry)

def saveWindowGeometry(self):
self.settings.setValue("/Processing/multipleInputDialogGeometry", self.saveGeometry())

def populateList(self):
model = QStandardItemModel()
self.model = QStandardItemModel()
for value, text in self.options:
item = QStandardItem(text)
item.setData(value, Qt.UserRole)
item.setCheckState(Qt.Checked if value in self.selectedoptions else Qt.Unchecked)
item.setCheckable(True)
model.appendRow(item)
self.model.appendRow(item)

self.lstLayers.setModel(model)
# add extra options (e.g. manually added layers)
for t in [o for o in self.selectedoptions if not isinstance(o, int)]:
if isinstance(t, QgsProcessingModelChildParameterSource):
item = QStandardItem(t.staticValue())
else:
item = QStandardItem(t)
item.setData(item.text(), Qt.UserRole)
item.setCheckState(Qt.Checked)
item.setCheckable(True)
self.model.appendRow(item)

self.lstLayers.setModel(self.model)

def accept(self):
self.selectedoptions = []
@@ -106,15 +130,56 @@ def reject(self):
self.selectedoptions = None
QDialog.reject(self)

def getItemsToModify(self):
items = []
if len(self.lstLayers.selectedIndexes()) > 1:
for i in self.lstLayers.selectedIndexes():
items.append(self.model.itemFromIndex(i))
else:
for i in range(self.model.rowCount()):
items.append(self.model.item(i))
return items

def selectAll(self, value):
model = self.lstLayers.model()
for i in range(model.rowCount()):
item = model.item(i)
for item in self.getItemsToModify():
item.setCheckState(Qt.Checked if value else Qt.Unchecked)

def toggleSelection(self):
model = self.lstLayers.model()
for i in range(model.rowCount()):
item = model.item(i)
for item in self.getItemsToModify():
checked = item.checkState() == Qt.Checked
item.setCheckState(Qt.Unchecked if checked else Qt.Checked)

def getFileFilter(self, datatype):
"""
Returns a suitable file filter pattern for the specified parameter definition
:param param:
:return:
"""
if datatype == QgsProcessing.TypeRaster:
return QgsProviderRegistry.instance().fileRasterFilters()
elif datatype == QgsProcessing.TypeFile:
return self.tr('All files (*.*)')
else:
exts = QgsVectorFileWriter.supportedFormatExtensions()
for i in range(len(exts)):
exts[i] = self.tr('{0} files (*.{1})').format(exts[i].upper(), exts[i].lower())
return self.tr('All files (*.*)') + ';;' + ';;'.join(exts)

def addFiles(self):
filter = self.getFileFilter(self.datatype)

settings = QgsSettings()
path = str(settings.value('/Processing/LastInputPath'))

ret, selected_filter = QFileDialog.getOpenFileNames(self, self.tr('Select file(s)'),
path, filter)
if ret:
files = list(ret)
settings.setValue('/Processing/LastInputPath',
os.path.dirname(str(files[0])))
for filename in files:
item = QStandardItem(filename)
item.setData(filename, Qt.UserRole)
item.setCheckState(Qt.Checked)
item.setCheckable(True)
self.model.appendRow(item)
@@ -28,9 +28,10 @@

import os

from qgis.core import QgsProcessing
from qgis.PyQt import uic
from qgis.PyQt.QtCore import pyqtSignal

''
from processing.gui.MultipleInputDialog import MultipleInputDialog
from processing.gui.MultipleFileInputDialog import MultipleFileInputDialog

@@ -63,10 +64,10 @@ def setSelectedItems(self, selected):
self.tr('{0} elements selected').format(len(self.selectedoptions)))

def showSelectionDialog(self):
if self.datatype is None:
dlg = MultipleInputDialog(self.options, self.selectedoptions)
else:
if self.datatype == QgsProcessing.TypeFile:
dlg = MultipleFileInputDialog(self.selectedoptions)
else:
dlg = MultipleInputDialog(self.options, self.selectedoptions, datatype=self.datatype)
dlg.exec_()
if dlg.selectedoptions is not None:
self.selectedoptions = dlg.selectedoptions
@@ -76,12 +77,15 @@ def showSelectionDialog(self):

def updateForOptions(self, options):
selectedoptions = []
selected = [self.options[i] for i in self.selectedoptions]
selected = [self.options[i] if isinstance(i, int) else i for i in self.selectedoptions]
for sel in selected:
try:
idx = options.index(sel)
selectedoptions.append(idx)
except ValueError:
pass
if isinstance(sel, int):
try:
idx = options.index(sel)
selectedoptions.append(idx)
except ValueError:
pass
else:
selectedoptions.append(sel)
self.options = options
self.setSelectedItems(selectedoptions)

0 comments on commit 6d38894

Please sign in to comment.
You can’t perform that action at this time.