360 lines
13 KiB
Python
Raw Normal View History

2012-10-05 23:28:47 +02:00
# -*- coding: utf-8 -*-
"""
***************************************************************************
Sextante.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. *
* *
***************************************************************************
"""
2012-10-05 23:28:47 +02:00
__author__ = 'Victor Olaya'
__date__ = 'August 2012'
__copyright__ = '(C) 2012, Victor Olaya'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
2013-04-12 12:29:29 +02:00
import sextante
2012-09-15 18:25:25 +03:00
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import *
2012-09-15 18:25:25 +03:00
from sextante.core.QGisLayers import QGisLayers
from sextante.core.SextanteConfig import SextanteConfig
from sextante.core.GeoAlgorithm import GeoAlgorithm
from sextante.core.SextanteLog import SextanteLog
from sextante.gui.AlgorithmClassification import AlgorithmDecorator
2012-10-20 17:15:42 +03:00
from sextante.gui.AlgorithmExecutor import AlgorithmExecutor
from sextante.gui.RenderingStyles import RenderingStyles
2012-09-15 18:25:25 +03:00
from sextante.gui.SextantePostprocessing import SextantePostprocessing
from sextante.gui.UnthreadedAlgorithmExecutor import UnthreadedAlgorithmExecutor
from sextante.core.SilentProgress import SilentProgress
2012-09-15 18:25:25 +03:00
from sextante.modeler.Providers import Providers
2012-10-20 17:15:42 +03:00
from sextante.modeler.ModelerAlgorithmProvider import ModelerAlgorithmProvider
2012-09-15 18:25:25 +03:00
from sextante.modeler.ModelerOnlyAlgorithmProvider import ModelerOnlyAlgorithmProvider
from sextante.algs.QGISAlgorithmProvider import QGISAlgorithmProvider
2012-10-20 17:15:42 +03:00
from sextante.grass.GrassAlgorithmProvider import GrassAlgorithmProvider
from sextante.lidar.LidarToolsAlgorithmProvider import LidarToolsAlgorithmProvider
from sextante.gdal.GdalOgrAlgorithmProvider import GdalOgrAlgorithmProvider
2012-09-15 18:25:25 +03:00
from sextante.otb.OTBAlgorithmProvider import OTBAlgorithmProvider
2012-10-20 17:15:42 +03:00
from sextante.r.RAlgorithmProvider import RAlgorithmProvider
from sextante.saga.SagaAlgorithmProvider import SagaAlgorithmProvider
from sextante.script.ScriptAlgorithmProvider import ScriptAlgorithmProvider
from sextante.taudem.TauDEMAlgorithmProvider import TauDEMAlgorithmProvider
from sextante.admintools.AdminToolsAlgorithmProvider import AdminToolsAlgorithmProvider
2012-11-06 00:05:08 +01:00
2012-09-15 18:25:25 +03:00
class Sextante:
iface = None
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
2013-01-26 23:55:14 +01:00
def addProvider(provider, updateList = False):
2012-09-15 18:25:25 +03:00
'''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)
SextanteConfig.loadSettings()
2013-01-26 23:55:14 +01:00
if updateList:
Sextante.updateAlgsList()
2012-09-15 18:25:25 +03:00
@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)
SextanteConfig.loadSettings()
Sextante.updateAlgsList()
except:
pass #This try catch block is here to avoid problems if the plugin with a provider is unloaded
#after SEXTANTE 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
return Sextante.modeler
@staticmethod
def getInterface():
return Sextante.iface
@staticmethod
def setInterface(iface):
Sextante.iface = iface
2013-05-01 23:45:20 +02:00
2013-04-13 15:05:19 +02:00
@staticmethod
def setPlugin(iface):
2013-05-01 23:45:20 +02:00
Sextante.plugin = iface
2013-04-13 15:05:19 +02:00
@staticmethod
def getPlugin():
2013-05-01 23:45:20 +02:00
return Sextante.plugin
2012-09-15 18:25:25 +03:00
@staticmethod
def initialize():
#add the basic providers
Sextante.addProvider(QGISAlgorithmProvider())
2012-09-15 18:25:25 +03:00
Sextante.addProvider(ModelerOnlyAlgorithmProvider())
2012-12-10 00:12:07 +01:00
Sextante.addProvider(GdalOgrAlgorithmProvider())
2012-09-15 18:25:25 +03:00
Sextante.addProvider(LidarToolsAlgorithmProvider())
Sextante.addProvider(OTBAlgorithmProvider())
Sextante.addProvider(RAlgorithmProvider())
Sextante.addProvider(SagaAlgorithmProvider())
Sextante.addProvider(GrassAlgorithmProvider())
Sextante.addProvider(ScriptAlgorithmProvider())
2012-10-20 17:15:42 +03:00
Sextante.addProvider(TauDEMAlgorithmProvider())
Sextante.addProvider(AdminToolsAlgorithmProvider())
2012-09-15 18:25:25 +03:00
Sextante.modeler.initializeSettings();
#and initialize
AlgorithmDecorator.loadClassification()
2012-09-15 18:25:25 +03:00
SextanteLog.startLogging()
2012-12-10 00:12:07 +01:00
SextanteConfig.initialize()
2012-09-15 18:25:25 +03:00
SextanteConfig.loadSettings()
2013-02-28 22:08:32 +01:00
RenderingStyles.loadStyles()
2012-09-15 18:25:25 +03:00
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
2013-02-07 01:09:39 +01:00
def loadFromProviders():
2012-09-15 18:25:25 +03:00
Sextante.loadAlgorithms()
Sextante.loadActions()
Sextante.loadContextMenuActions()
@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 changes,
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
algs = {}
for alg in providerAlgs:
algs[alg.commandLineName()] = alg
Sextante.algs[provider.getName()] = algs
2013-02-07 01:09:39 +01:00
2012-09-15 18:25:25 +03:00
#this is a special provider, since it depends on others
#TODO Fix circular imports, so this provider can be incorporated
#as a normal one
provider = Sextante.modeler
provider.setAlgsList(Sextante.algs)
provider.loadAlgorithms()
providerAlgs = provider.algs
algs = {}
for alg in providerAlgs:
algs[alg.commandLineName()] = alg
Sextante.algs[provider.getName()] = algs
#And we do it again, in case there are models containing models
#TODO: Improve this
provider.setAlgsList(Sextante.algs)
provider.loadAlgorithms()
providerAlgs = provider.algs
algs = {}
for alg in providerAlgs:
algs[alg.commandLineName()] = alg
Sextante.algs[provider.getName()] = algs
provs = {}
for provider in Sextante.providers:
provs[provider.getName()] = provider
provs[Sextante.modeler.getName()] = Sextante.modeler
Providers.providers = provs
@staticmethod
def loadActions():
for provider in Sextante.providers:
providerActions = provider.actions
actions = list()
for action in providerActions:
actions.append(action)
Sextante.actions[provider.getName()] = actions
provider = Sextante.modeler
actions = list()
for action in provider.actions:
actions.append(action)
Sextante.actions[provider.getName()] = actions
@staticmethod
def loadContextMenuActions():
Sextante.contextMenuActions = []
for provider in Sextante.providers:
providerActions = provider.contextMenuActions
for action in providerActions:
Sextante.contextMenuActions.append(action)
provider = Sextante.modeler
providerActions = provider.contextMenuActions
for action in providerActions:
Sextante.contextMenuActions.append(action)
@staticmethod
def getAlgorithm(name):
for provider in Sextante.algs.values():
if name in provider:
return provider[name]
return None
2013-05-01 23:45:20 +02:00
2013-04-13 15:05:19 +02:00
@staticmethod
def getAlgorithmFromFullName(name):
for provider in Sextante.algs.values():
for alg in provider.values():
if alg.name == name:
return alg
return None
2012-09-15 18:25:25 +03:00
@staticmethod
def getObject(uri):
'''Returns the QGIS object identified by the given URI'''
return QGisLayers.getObjectFromUri(uri)
2012-09-15 18:25:25 +03:00
@staticmethod
def runandload(name, *args):
Sextante.runAlgorithm(name, SextantePostprocessing.handleAlgorithmResults, *args)
2012-09-15 18:25:25 +03:00
@staticmethod
def runAlgorithm(algOrName, onFinish, *args):
if isinstance(algOrName, GeoAlgorithm):
alg = algOrName
else:
alg = Sextante.getAlgorithm(algOrName)
if alg == None:
print("Error: Algorithm not found\n")
return
if len(args) != alg.getVisibleParametersCount() + alg.getVisibleOutputsCount():
print ("Error: Wrong number of parameters")
2013-04-12 12:29:29 +02:00
sextante.alghelp(algOrName)
2012-09-15 18:25:25 +03:00
return
alg = alg.getCopy()
2012-09-15 18:25:25 +03:00
if isinstance(args, dict):
# set params by name
for name, value in args.items():
if alg.getParameterFromName(name).setValue(value):
continue;
if alg.getOutputFromName(name).setValue(value):
continue;
print ("Error: Wrong parameter value %s for parameter %s." % (value, name))
return
else:
i = 0
for param in alg.parameters:
if not param.hidden:
if not param.setValue(args[i]):
print ("Error: Wrong parameter value: " + unicode(args[i]))
2012-09-15 18:25:25 +03:00
return
i = i +1
for output in alg.outputs:
if not output.hidden:
if not output.setValue(args[i]):
print ("Error: Wrong output value: " + unicode(args[i]))
2012-09-15 18:25:25 +03:00
return
i = i +1
msg = alg.checkParameterValuesBeforeExecuting()
if msg:
print ("Unable to execute algorithm\n" + msg)
return
2012-09-15 18:25:25 +03:00
if not alg.checkInputCRS():
2013-02-07 01:09:39 +01:00
print ("Warning: Not all input layers use the same CRS.\n" +
"This can cause unexpected results.")
2013-02-07 01:09:39 +01:00
2012-09-15 18:25:25 +03:00
SextanteLog.addToLog(SextanteLog.LOG_ALGORITHM, alg.getAsCommand())
# don't set the wait cursor twice, because then when you restore it
# it will still be a wait cursor
cursor = QApplication.overrideCursor()
if cursor == None or cursor == 0:
2012-12-10 00:12:07 +01:00
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
elif cursor.shape() != Qt.WaitCursor:
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
2012-12-10 00:12:07 +01:00
useThreads = SextanteConfig.getSetting(SextanteConfig.USE_THREADS)
2013-02-07 01:09:39 +01:00
#this is doing strange things, so temporarily the thread execution is disabled from the console
2013-02-07 01:09:39 +01:00
useThreads = False
if useThreads:
2012-09-15 18:25:25 +03:00
algEx = AlgorithmExecutor(alg)
progress = QProgressDialog()
progress.setWindowTitle(alg.name)
progress.setLabelText("Executing %s..." % alg.name)
def finish():
QApplication.restoreOverrideCursor()
if onFinish is not None:
onFinish(alg, SilentProgress())
2012-09-15 18:25:25 +03:00
progress.close()
def error(msg):
QApplication.restoreOverrideCursor()
print msg
SextanteLog.addToLog(SextanteLog.LOG_ERROR, msg)
def cancel():
try:
algEx.finished.disconnect()
algEx.terminate()
QApplication.restoreOverrideCursor()
progress.close()
except:
pass
algEx.error.connect(error)
algEx.finished.connect(finish)
algEx.start()
algEx.wait()
else:
progress = SilentProgress()
ret = UnthreadedAlgorithmExecutor.runalg(alg, progress)
2012-09-15 18:25:25 +03:00
if onFinish is not None and ret:
onFinish(alg, progress)
2012-09-15 18:25:25 +03:00
QApplication.restoreOverrideCursor()
return alg