Skip to content

Commit

Permalink
Added support for non-file-based output channels
Browse files Browse the repository at this point in the history
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: http://sextante.googlecode.com/svn/trunk/soft/bindings/qgis-plugin@343 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.
3 changes: 3 additions & 0 deletions src/sextante/algs/SextanteAlgorithmProvider.py
Expand Up @@ -34,3 +34,6 @@ def getIcon(self):

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

def supportsNonFileBasedOutput(self):
return True
17 changes: 15 additions & 2 deletions src/sextante/core/AlgorithmProvider.py
@@ -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.
Expand Down Expand Up @@ -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":
extensions.append(extension)
return extensions
#return ["shp"]

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

def supportsNonFileBasedOutput(self):
return False
21 changes: 16 additions & 5 deletions src/sextante/core/GeoAlgorithm.py
Expand Up @@ -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
Expand Down Expand Up @@ -117,20 +119,27 @@ def execute(self, progress):
except GeoAlgorithmExecutionException, gaee:
SextanteLog.addToLog(SextanteLog.LOG_ERROR, gaee.msg)
raise gaee
except Exception, e:
except:
#if something goes wrong and is not caught in the algorithm,
#we catch it here and wrap it
lines = []
lines.append(str(e))
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[:newline])
else:
lines.append(errstring)
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):
continue
if isinstance(out, OutputRaster):
exts = self.provider.getSupportedOutputRasterLayerExtensions()
elif isinstance(out, OutputVector):
Expand Down Expand Up @@ -263,3 +272,5 @@ def getAsCommand(self):
s+=out.getValueAsCommandLineParameter() + ","
s= s[:-1] + ")"
return s


10 changes: 5 additions & 5 deletions src/sextante/ftools/ConvexHull.py
Expand Up @@ -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)
Expand All @@ -39,8 +36,11 @@ def processAlgorithm(self, progress):
vproviderA = vlayerA.dataProvider()
allAttrsA = vproviderA.attributeIndexes()
vproviderA.select(allAttrsA)
fields = vproviderA.fields()
writer = QgsVectorFileWriter(output, systemEncoding, fields, QGis.WKBPolygon, vproviderA.crs() )
#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, vproviderA.crs())
inFeat = QgsFeature()
outFeat = QgsFeature()
inGeom = QgsGeometry()
Expand Down
3 changes: 3 additions & 0 deletions src/sextante/ftools/FToolsAlgorithmProvider.py
Expand Up @@ -78,3 +78,6 @@ def _loadAlgorithms(self):

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

def supportsNonFileBasedOutput(self):
return True
29 changes: 27 additions & 2 deletions src/sextante/gui/OutputSelectionPanel.py
@@ -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

Expand All @@ -22,11 +24,32 @@ def __init__(self, output, alg):
self.horizontalLayout.addWidget(self.text)
self.pushButton = QtGui.QPushButton()
self.pushButton.setText("...")
self.pushButton.clicked.connect(self.showSelectionDialog)
self.pushButton.clicked.connect(self.buttonPushed)
self.horizontalLayout.addWidget(self.pushButton)
self.setLayout(self.horizontalLayout)

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

popupmenu.exec_(QtGui.QCursor.pos())

def saveToTemporaryFile(self):
self.text.setText("")

def saveToMemory(self):
self.text.setText("memory:")

def saveToFile(self):
filefilter = self.output.getFileFilter(self.alg)
settings = QtCore.QSettings()
if settings.contains("/SextanteQGIS/LastOutputPath"):
Expand All @@ -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
else:
if not os.path.isabs(filename):
filename = SextanteConfig.getSetting(SextanteConfig.OUTPUT_FOLDER) + os.sep + filename
Expand Down
15 changes: 11 additions & 4 deletions src/sextante/gui/SextantePostprocessing.py
Expand Up @@ -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:
Expand All @@ -19,11 +20,17 @@ def handleAlgorithmResults(alg, showResults = True):
continue
if isinstance(out, (OutputRaster, OutputVector, OutputTable)):
try:
if SextanteConfig.getSetting(SextanteConfig.USE_FILENAME_AS_LAYER_NAME):
name = os.path.basename(out.value)
if out.value.startswith("memory:"):
layer = out.memoryLayer
layer.updateFieldMap()
layer.updateExtents()
QgsMapLayerRegistry.instance().addMapLayer(layer)
else:
name = out.description
QGisLayers.load(out.value, name, alg.crs, RenderingStyles.getStyle(alg.commandLineName(),out.name))
if SextanteConfig.getSetting(SextanteConfig.USE_FILENAME_AS_LAYER_NAME):
name = os.path.basename(out.value)
else:
name = out.description
QGisLayers.load(out.value, name, alg.crs, RenderingStyles.getStyle(alg.commandLineName(),out.name))
except Exception, e:
QMessageBox.critical(None, "Error", str(e))
elif isinstance(out, OutputHTML):
Expand Down
45 changes: 44 additions & 1 deletion src/sextante/outputs/OutputVector.py
@@ -1,12 +1,55 @@
from sextante.outputs.Output import Output
from qgis.core import *
from PyQt4.QtCore import *

class OutputVector(Output):

MEMORY_LAYER_PREFIX = "memory:"

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.
Parameters:
-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()
pr.addAttributes(fields)
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.