Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
added recent algs list
tested and improved saga resampling
added non-spatial calculator
added mechanism to connect external plugins
Added example of provider plugin(still unfinished)

git-svn-id: http://sextante.googlecode.com/svn/trunk/soft/bindings/qgis-plugin@56 881b9c09-3ef8-f3c2-ec3d-21d735c97f4d
  • Loading branch information
volayaf committed Mar 29, 2012
1 parent 4dbb90e commit 0bd4ab3
Show file tree
Hide file tree
Showing 44 changed files with 735 additions and 174 deletions.
3 changes: 1 addition & 2 deletions .settings/org.eclipse.core.resources.prefs
@@ -1,6 +1,5 @@
#Fri Mar 16 10:56:39 CET 2012
#Tue Mar 27 17:10:35 CEST 2012
eclipse.preferences.version=1
encoding//src/sextante/ftools/ftools_utils.py=utf-8
encoding//src/sextante/gui/ui_ParametersDialog.py=utf-8
encoding//src/sextante/gui/ui_SextanteToolbox.py=utf-8
encoding//src/sextante/resources.py=utf-8
3 changes: 3 additions & 0 deletions build.xml
Expand Up @@ -8,5 +8,8 @@
<copy todir="C:/Users/volaya/.qgis/python/plugins/sextante">
<fileset dir="src/sextante" includes="**"/>
</copy>
<copy todir="C:/Users/volaya/.qgis/python/plugins/sextanteexampleprovider">
<fileset dir="src/sextanteexampleprovider" includes="**"/>
</copy>
</target>
</project>
1 change: 1 addition & 0 deletions src/sextante/SextantePlugin.py
Expand Up @@ -29,6 +29,7 @@ def __init__(self, iface):
def initGui(self):
self.toolbox = SextanteToolbox(self.iface)
self.toolbox.setVisible(False)
Sextante.addAlgListListener(self.toolbox)

self.menu = QMenu()
self.menu.setTitle("SEXTANTE")
Expand Down
24 changes: 21 additions & 3 deletions src/sextante/core/AlgorithmProvider.py
@@ -1,13 +1,30 @@
from sextante.core.SextanteConfig import Setting, SextanteConfig
import os
from PyQt4 import QtGui

class AlgorithmProvider():
'''this is the base class for algorithms providers.
An algorithm provider is a set of related algorithms, typically from the same
external application or related to a common area of analysis.
'''

def __init__(self):
name = "ACTIVATE_" + self.getName().upper().replace(" ", "_")
SextanteConfig.addSetting(Setting(self.getName(), name, "Activate", True))
self.actions = []
self.contextMenuActions = []

def initializeSettings(self):
'''this is the place where you should add config parameters to sextante using the SextanteConfig class.
this method is called when a provider is added to Sextante.
By default it just adds a setting to activate or deactivate algorithms from the provider'''
name = "ACTIVATE_" + self.getName().upper().replace(" ", "_")
SextanteConfig.addSetting(Setting(self.getName(), name, "Activate", True))

def unload(self):
'''Do here anything that you want to be done when the provider is removed from the list of available ones.
This method is called when you remove the provider from Sextante.
Removal of config setting should be done here'''
name = "ACTIVATE_" + self.getName().upper().replace(" ", "_")
SextanteConfig.removeSetting(name)
def getName(self):
return "Generic algorithm provider"

Expand All @@ -22,7 +39,8 @@ def loadAlgorithms(self):
#methods to be overridden.
#==============================

#Algorithm loading should take place here, filling sefl.algs
#Algorithm loading should take place here, filling self.algs, which is a list of
#elements of class GeoAlgorithm. Use that class to create your own algorithms
#Since algorithms should have a reference to the provider they come
#from, this is also the place to set the 'provider' variable of each algorithm
def _loadAlgorithms(self):
Expand Down
46 changes: 31 additions & 15 deletions src/sextante/core/GeoAlgorithm.py
Expand Up @@ -6,6 +6,7 @@
from PyQt4 import QtGui
import os.path
from sextante.core.SextanteUtils import SextanteUtils
from sextante.parameters.ParameterMultipleInput import ParameterMultipleInput


class GeoAlgorithm:
Expand All @@ -17,9 +18,13 @@ def __init__(self):
self.outputs = list()
self.name = ""
self.group = ""
self.defineCharacteristics()
#the crs taken from input layers (if possible), and used when loading output layers
self.crs = None
#change any of the following if your algorithm should not appear in the toolbox or modeler
self.showInToolbox = True
self.showInModeler = True

self.defineCharacteristics()

#methods to overwrite when creating a custom geoalgorithm
#=========================================================
Expand All @@ -34,9 +39,18 @@ def processAlgorithm(self):
pass

def defineCharacteristics(self):
'''here is where the parameters and outputs should be filled'''
'''here is where the parameters and outputs should be defined'''
pass

def getCustomParametersDialog(self):
'''if the algorithm has a custom parameters dialog, it should be returned here, ready to be executed'''
return None

def getCustomModelerParametersDialog(self, modelAlg):
'''if the algorithm has a custom parameters dialog when called from the modeler,
it should be returned here, ready to be executed'''
return None

#=========================================================

def execute(self, progress):
Expand All @@ -45,23 +59,21 @@ def execute(self, progress):
self.processAlgorithm(progress)

def resolveTemporaryOutputs(self):
'''sets temporary outputs (output.value = None) with a temporary file instead)'''
'''sets temporary outputs (output.value = None) with a temporary file instead'''
for out in self.outputs:
if out.value == None:
if (not out.hidden) and out.value == None:
SextanteUtils.setTempOutput(out, self)

def setOutputCRSFromInputLayers(self):
layers = QGisLayers.getAllLayers()
for param in self.parameters:
if isinstance(param, ParameterRaster):
layers = QGisLayers.getRasterLayers()
elif isinstance(param, ParameterVector):
layers = QGisLayers.getVectorLayers()
else:
continue
for layer in layers:
if layer.source() == param.value:
self.crs = layer.crs()
return
if isinstance(param, (ParameterRaster, ParameterVector ,ParameterMultipleInput)):
inputlayers = param.value.split(";")
for inputlayer in inputlayers:
for layer in layers:
if layer.source() == inputlayer:
self.crs = layer.crs()
return


def addOutput(self, output):
Expand Down Expand Up @@ -111,8 +123,12 @@ def __str__(self):


def commandLineName(self):
return self.provider.getName().lower() + ":" + self.name.lower().replace(" ", "").replace(",","")
return self.provider.getName().lower().replace(" ", "") + ":" + self.name.lower().replace(" ", "").replace(",","")

def removeOutputFromName(self, name):
for out in self.outputs:
if out.name == name:
self.outputs.remove(out)

def getOutputFromName(self, name):
for out in self.outputs:
Expand Down
30 changes: 21 additions & 9 deletions src/sextante/core/QGisLayers.py
Expand Up @@ -20,7 +20,7 @@ def getRasterLayers():

for layer in layers:
if layer.type() == layer.RasterLayer:
if os.path.exists(layer.source()):
if os.path.exists(layer.source()):#only file-based layers
raster.append(layer)
return raster

Expand All @@ -35,6 +35,15 @@ def getVectorLayers(shapetype=-1):
vector.append(layer)
return vector

@staticmethod
def getAllLayers():
layers = QGisLayers.iface.legendInterface().layers()
layerslist = list()
for layer in layers:
if os.path.exists(layer.source()):
layerslist.append(layer)
return layerslist

@staticmethod
def getTables():
layers = QGisLayers.iface.legendInterface().layers()
Expand Down Expand Up @@ -107,7 +116,7 @@ def loadFromDict(layersdict, crs):


@staticmethod
def getObjectFromUri(uri):
def getObjectFromUri(uri, forceLoad = True):
layers = QGisLayers.getRasterLayers()
for layer in layers:
if layer.source() == uri:
Expand All @@ -116,13 +125,16 @@ def getObjectFromUri(uri):
for layer in layers:
if layer.source() == uri:
return layer
#if is not opened, we open it
layer = QgsVectorLayer(uri, uri , 'ogr')
if layer.isValid():
return layer
layer = QgsRasterLayer(uri, uri)
if layer.isValid():
return layer
if forceLoad:
#if is not opened, we open it
layer = QgsVectorLayer(uri, uri , 'ogr')
if layer.isValid():
return layer
layer = QgsRasterLayer(uri, uri)
if layer.isValid():
return layer
else:
return None



Expand Down
93 changes: 77 additions & 16 deletions src/sextante/core/Sextante.py
Expand Up @@ -12,29 +12,54 @@
from sextante.mmqgis.MMQGISAlgorithmProvider import MMQGISAlgorithmProvider
from sextante.ftools.FToolsAlgorithmProvider import FToolsAlgorithmProvider
from sextante.gui.SextantePostprocessing import SextantePostprocessing
from sextante.modeler.ProviderIcons import ProviderIcons
from sextante.modeler.Providers import Providers
from sextante.r.RAlgorithmProvider import RAlgorithmProvider
from sextante.parameters.ParameterSelection import ParameterSelection
from sextante.grass.GrassAlgorithmProvider import GrassAlgorithmProvider
from sextante.gui.RenderingStyles import RenderingStyles
from sextante.modeler.ModelerOnlyAlgorithmProvider import ModelerOnlyAlgorithmProvider

class Sextante:

iface = None
providers = [SagaAlgorithmProvider(), ScriptAlgorithmProvider(),
MMQGISAlgorithmProvider(), FToolsAlgorithmProvider(),
RAlgorithmProvider()]#, GrassAlgorithmProvider()]
listeners = []
providers = []
#a dictionary of algorithms. Keys are names of providers
#and values are list with all algorithms from that provider
algs = {}
#Same structure as algs
actions = {}
#All the registered context menu actions for the toolbox
contextMenuActions = []

modeler = ModelerAlgorithmProvider()

@staticmethod
def setInterface(iface):
Sextante.iface = iface
def addProvider(provider):
'''use this method to add algorithms from external providers'''
'''Adding a new provider automatically initializes it, so there is no need to do it in advance'''
#Note: this might slow down the initialization process if there are many new providers added.
#Should think of a different solution
provider.initializeSettings()
Sextante.providers.append(provider)
Sextante.updateAlgsList()

@staticmethod
def removeProvider(provider):
'''Use this method to remove a provider.
This method should be called when unloading a plugin that contributes a provider to SEXTANTE'''
try:
provider.unload()
Sextante.providers.remove(provider)
Sextante.updateAlgsList()
except:
pass #This try catch block is here to avoid problems if the plugin with a provider is unloaded
#after SEXTANTEe itself has been unloaded. It is a quick fix before I found out how to
#properly avoid that

@staticmethod
def getProviderFromName(name):
'''returns the provider with the given name'''
for provider in Sextante.providers:
if provider.getName() == name:
return provider
Expand All @@ -44,26 +69,59 @@ def getProviderFromName(name):
def getInterface():
return Sextante.iface

@staticmethod
def setInterface(iface):
Sextante.iface = iface

@staticmethod
def initialize():
#add the basic providers
Sextante.addProvider(MMQGISAlgorithmProvider())
Sextante.addProvider(FToolsAlgorithmProvider())
Sextante.addProvider(ModelerOnlyAlgorithmProvider())
Sextante.addProvider(ScriptAlgorithmProvider())
Sextante.addProvider(RAlgorithmProvider())
Sextante.addProvider(SagaAlgorithmProvider())
Sextante.modeler.initializeSettings();
#and initialize
SextanteLog.startLogging()
SextanteConfig.initialize()
SextanteConfig.loadSettings()
RenderingStyles.loadStyles()
Sextante.loadFromProviders()

@staticmethod
def updateAlgsList():
'''call this method when there has been any change that requires the list of algorithms
to be created again from algorithm providers'''
Sextante.loadFromProviders()
Sextante.fireAlgsListHasChanged()

@staticmethod
def loadFromProviders():
Sextante.loadAlgorithms()
Sextante.loadActions()
Sextante.loadContextMenuActions()
#SextanteConfig.loadSettings()


@staticmethod
def updateProviders():
for provider in Sextante.providers:
provider.loadAlgorithms()

@staticmethod
def addAlgListListener(listener):
'''listener should implement a algsListHasChanged() method. whenever the list of algorithms changed,
that method will be called for all registered listeners'''
Sextante.listeners.append(listener)

@staticmethod
def fireAlgsListHasChanged():
for listener in Sextante.listeners:
listener.algsListHasChanged()

@staticmethod
def loadAlgorithms():
Sextante.algs={}
Sextante.updateProviders()
for provider in Sextante.providers:
providerAlgs = provider.algs
Expand Down Expand Up @@ -92,13 +150,11 @@ def loadAlgorithms():
for alg in providerAlgs:
algs[alg.commandLineName()] = alg
Sextante.algs[provider.getName()] = algs
icons = {}
provs = {}
for provider in Sextante.providers:
icons[provider.getName()] = provider.getIcon()
icons[Sextante.modeler.getName()] = Sextante.modeler.getIcon()
ProviderIcons.providerIcons = icons


provs[provider.getName()] = provider
provs[Sextante.modeler.getName()] = Sextante.modeler
Providers.providers = provs

@staticmethod
def loadActions():
Expand All @@ -117,6 +173,7 @@ def loadActions():

@staticmethod
def loadContextMenuActions():
Sextante.contextMenuActions = []
for provider in Sextante.providers:
providerActions = provider.contextMenuActions
for action in providerActions:
Expand Down Expand Up @@ -181,7 +238,7 @@ def runalg(name, *args):
if alg == None:
print("Error: Algorithm not found\n")
return
if len(args) != len(alg.parameters) + len(alg.getVisibleOutputsCount()):
if len(args) != len(alg.parameters) + alg.getVisibleOutputsCount():
print ("Error: Wrong number of parameters")
Sextante.alghelp(name)
return
Expand Down Expand Up @@ -236,7 +293,7 @@ def runandload(name, *args):
#in theory, this could not happen. Maybe we should show a message box?
QMessageBox.critical(None,"Error", "Error: Algorithm not found\n")
return
if len(args) != len(alg.parameters) + len(alg.getVisibleOutputsCount()):
if len(args) != len(alg.parameters) + alg.getVisibleOutputsCount():
QMessageBox.critical(None,"Error", "Error: Wrong number of parameters")
Sextante.alghelp(name)
return
Expand Down Expand Up @@ -267,3 +324,7 @@ def runandload(name, *args):







0 comments on commit 0bd4ab3

Please sign in to comment.