Skip to content
Browse files
Added support for non-file-based output channels
Changed GUI elements accordingly
Only Ftools's Convex hull algorithm has been changed to support this. All other native algorithms have to be adapted

git-svn-id: 881b9c09-3ef8-f3c2-ec3d-21d735c97f4d
  • Loading branch information
volayaf committed Aug 10, 2012
1 parent 1433a12 commit 24406ab
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 19 deletions.
@@ -34,3 +34,6 @@ def getIcon(self):

def _loadAlgorithms(self):
self.algs = self.alglist

def supportsNonFileBasedOutput(self):
return True
@@ -1,6 +1,7 @@
from sextante.core.SextanteConfig import Setting, SextanteConfig
import os
from PyQt4 import QtGui
from qgis.core import *

class AlgorithmProvider():
'''this is the base class for algorithms providers.
@@ -67,7 +68,19 @@ def getSupportedOutputRasterLayerExtensions(self):
return ["tif"]

def getSupportedOutputVectorLayerExtensions(self):
return ["shp"]
formats = QgsVectorFileWriter.supportedFiltersAndFormats()
extensions = ["shp"]#shp is the default, should be the first
for extension in formats.keys():
extension = str(extension)
extension = extension[extension.find('*.') + 2:]
extension = extension[:extension.find(" ")]
if extension.lower() != "shp":
return extensions
#return ["shp"]

def getSupportedOutputTableExtensions(self):
return ["dbf"]
return ["dbf"]

def supportsNonFileBasedOutput(self):
return False
@@ -4,6 +4,8 @@
from sextante.parameters.ParameterRaster import ParameterRaster
from sextante.parameters.ParameterVector import ParameterVector
from PyQt4 import QtGui
from PyQt4.QtCore import *
from qgis.core import *
import os.path
from sextante.core.SextanteUtils import SextanteUtils
from sextante.parameters.ParameterMultipleInput import ParameterMultipleInput
@@ -117,20 +119,27 @@ def execute(self, progress):
except GeoAlgorithmExecutionException, gaee:
SextanteLog.addToLog(SextanteLog.LOG_ERROR, gaee.msg)
raise gaee
except Exception, e:
#if something goes wrong and is not caught in the algorithm,
#we catch it here and wrap it
lines = []
lines.append(traceback.format_exc().replace("\n", "|"))
lines = ["Uncaught error while executing algorithm"]
errstring = traceback.format_exc()
newline = errstring.find("\n")
if newline != -1:
lines.append(errstring.replace("\n", "|"))
SextanteLog.addToLog(SextanteLog.LOG_ERROR, lines)
raise GeoAlgorithmExecutionException(str(e))
raise GeoAlgorithmExecutionException(errstring)

def checkOutputFileExtensions(self):
'''Checks if the values of outputs are correct and have one of the supported output extensions.
If not, it adds the first one of the supported extensions, which is assumed to be the default one'''
for out in self.outputs:
if (not out.hidden) and out.value != None:
if not os.path.isabs(out.value):
if isinstance(out, OutputRaster):
exts = self.provider.getSupportedOutputRasterLayerExtensions()
elif isinstance(out, OutputVector):
@@ -263,3 +272,5 @@ def getAsCommand(self):
s+=out.getValueAsCommandLineParameter() + ","
s= s[:-1] + ")"
return s

@@ -27,9 +27,6 @@ def getIcon(self):
return QtGui.QIcon(os.path.dirname(__file__) + "/icons/convex_hull.png")

def processAlgorithm(self, progress):
settings = QSettings()
systemEncoding = settings.value( "/UI/encoding", "System" ).toString()
output = self.getOutputValue(ConvexHull.OUTPUT)
useSelection = self.getParameterValue(ConvexHull.USE_SELECTED)
useField = (self.getParameterValue(ConvexHull.METHOD) == 1)
field = self.getParameterValue(ConvexHull.FIELD)
@@ -39,8 +36,11 @@ def processAlgorithm(self, progress):
vproviderA = vlayerA.dataProvider()
allAttrsA = vproviderA.attributeIndexes()
fields = vproviderA.fields()
writer = QgsVectorFileWriter(output, systemEncoding, fields, QGis.WKBPolygon, )
#fields = vproviderA.fields()
fields = [ QgsField("ID", QVariant.Int),
QgsField("Area", QVariant.Double),
QgsField("Perim", QVariant.Double) ]
writer = self.getOutputFromName(ConvexHull.OUTPUT).getVectorWriter(fields, QGis.WKBPolygon,
inFeat = QgsFeature()
outFeat = QgsFeature()
inGeom = QgsGeometry()
@@ -78,3 +78,6 @@ def _loadAlgorithms(self):

def getSupportedOutputTableExtensions(self):
return ["csv"]

def supportsNonFileBasedOutput(self):
return True
@@ -1,4 +1,6 @@
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import os.path
from sextante.core.SextanteConfig import SextanteConfig

@@ -22,11 +24,32 @@ def __init__(self, output, alg):
self.pushButton = QtGui.QPushButton()

def showSelectionDialog(self):
def buttonPushed(self):
popupmenu = QMenu()
saveToTemporaryFileAction = QtGui.QAction("Save to a temporary file", self.pushButton)
popupmenu.addAction(saveToTemporaryFileAction )
if (self.alg.provider.supportsNonFileBasedOutput()):
saveToMemoryAction= QtGui.QAction("Save to a memory layer...", self.pushButton)
saveToFileAction = QtGui.QAction("Save to file...", self.pushButton)


def saveToTemporaryFile(self):

def saveToMemory(self):

def saveToFile(self):
filefilter = self.output.getFileFilter(self.alg)
settings = QtCore.QSettings()
if settings.contains("/SextanteQGIS/LastOutputPath"):
@@ -42,6 +65,8 @@ def getValue(self):
filename = str(self.text.text())
if filename.strip() == "" or filename == OutputSelectionPanel.SAVE_TO_TEMP_FILE:
return None
if filename.startswith("memory:"):
return filename
if not os.path.isabs(filename):
filename = SextanteConfig.getSetting(SextanteConfig.OUTPUT_FOLDER) + os.sep + filename
@@ -7,6 +7,7 @@
from sextante.gui.RenderingStyles import RenderingStyles
from sextante.outputs.OutputHTML import OutputHTML
from PyQt4.QtGui import *
from qgis.core import *
from sextante.core.SextanteConfig import SextanteConfig
import os
class SextantePostprocessing:
@@ -19,11 +20,17 @@ def handleAlgorithmResults(alg, showResults = True):
if isinstance(out, (OutputRaster, OutputVector, OutputTable)):
if SextanteConfig.getSetting(SextanteConfig.USE_FILENAME_AS_LAYER_NAME):
name = os.path.basename(out.value)
if out.value.startswith("memory:"):
layer = out.memoryLayer
name = out.description
QGisLayers.load(out.value, name,, RenderingStyles.getStyle(alg.commandLineName(),
if SextanteConfig.getSetting(SextanteConfig.USE_FILENAME_AS_LAYER_NAME):
name = os.path.basename(out.value)
name = out.description
QGisLayers.load(out.value, name,, RenderingStyles.getStyle(alg.commandLineName(),
except Exception, e:
QMessageBox.critical(None, "Error", str(e))
elif isinstance(out, OutputHTML):
@@ -1,12 +1,55 @@
from sextante.outputs.Output import Output
from qgis.core import *
from PyQt4.QtCore import *

class OutputVector(Output):


def getFileFilter(self,alg):
exts = alg.provider.getSupportedOutputVectorLayerExtensions()
for i in range(len(exts)):
exts[i] = exts[i].upper() + " files(*." + exts[i].lower() + ")"
return ";;".join(exts)

def getDefaultFileExtension(self, alg):
return alg.provider.getSupportedOutputVectorLayerExtensions()[0]
return alg.provider.getSupportedOutputVectorLayerExtensions()[0]

def getVectorWriter(self, fields, geomType, crs, options=None):
'''Returns a suitable writer to which features can be added as a result of the algorithm.
Use this to transparently handle output values instead of creating your own method.
-field: an array with the fields of the attributes table
-geomType: A suitable geometry type, as it would be passed to a QgsVectorFileWriter constructor
-crs: the crs of the layer to create.
Executing this method might modify the object, adding additional information to it, so the writer
can be later accessed and processed within QGIS.
It should be called just once, since a new call might result in previous data being replaced,
thus rendering a previously obtained writer useless'''

if self.value.startswith(self.MEMORY_LAYER_PREFIX):
types = { QGis.WKBPoint : "Point", QGis.WKBLineString : "Point", QGis.WKBPolygon : "Polygon",
QGis.WKBMultiPoint : "MultiPoint", QGis.WKBMultiLineString : "MultiLineString", QGis.WKBMultiPolygon : "MultiPolygon",}
v = QgsVectorLayer(types[geomType], self.description, "memory")
pr = v.dataProvider()
self.memoryLayer = v #keep a reference to the writer
return v
else: #outputChannel is a file path
#TODO: Add support for encodings
formats = QgsVectorFileWriter.supportedFiltersAndFormats()
OGRCodes = {}
for key,value in formats.items():
extension = str(key)
extension = extension[extension.find('*.') + 2:]
extension = extension[:extension.find(" ")]
OGRCodes[extension] = value
fieldsDict = {}
i = 0
for field in fields:
fieldsDict[i] = field
i += 1
settings = QSettings()
systemEncoding = settings.value( "/UI/encoding", "System" ).toString()
extension = self.value[self.value.find(".")+1:]
return QgsVectorFileWriter(self.value, systemEncoding, fieldsDict, geomType, crs, OGRCodes[extension] )

0 comments on commit 24406ab

Please sign in to comment.