diff --git a/python/plugins/sextante/SextantePlugin.py b/python/plugins/sextante/SextantePlugin.py index b2b40a8f8806..aa83efa02f98 100644 --- a/python/plugins/sextante/SextantePlugin.py +++ b/python/plugins/sextante/SextantePlugin.py @@ -16,6 +16,9 @@ * * *************************************************************************** """ +from PyQt4 import QtGui +from sextante.commander.parser import parse +from sextante.commander.CommanderWindow import CommanderWindow __author__ = 'Victor Olaya' __date__ = 'August 2012' @@ -50,6 +53,7 @@ def __init__(self, iface): QGisLayers.setInterface(iface) Sextante.initialize() Sextante.setInterface(iface) + Sextante.setPlugin(self) def initGui(self): self.toolbox = SextanteToolbox(self.iface) @@ -92,6 +96,13 @@ def initGui(self): menuBar = self.iface.mainWindow().menuBar() menuBar.insertMenu(self.iface.firstRightStandardMenu().menuAction(), self.menu) + self.commanderAction = QAction(QIcon(":/sextante/images/toolbox.png"), + QCoreApplication.translate("SEXTANTE", "&SEXTANTE commander"), + self.iface.mainWindow()) + self.commanderAction.triggered.connect(self.openCommander) + self.menu.addAction(self.commanderAction) + self.iface.registerMainWindowAction(self.commanderAction, "Ctrl+Alt+M") + def unload(self): self.toolbox.setVisible(False) self.menu.deleteLater() @@ -99,7 +110,15 @@ def unload(self): folder = SextanteUtils.tempFolder() if QDir(folder).exists(): shutil.rmtree(folder, True) - + + self.iface.unregisterMainWindowAction(self.commanderAction) + + def openCommander(self): + dlg = CommanderWindow(self.iface.mainWindow(), self.iface.mapCanvas()) + dlg.show() + dlg.exec_() + + def openToolbox(self): if self.toolbox.isVisible(): self.toolbox.hide() diff --git a/python/plugins/sextante/commander/CommanderWindow.py b/python/plugins/sextante/commander/CommanderWindow.py new file mode 100644 index 000000000000..cb70730acf7e --- /dev/null +++ b/python/plugins/sextante/commander/CommanderWindow.py @@ -0,0 +1,225 @@ +# -*- coding: utf-8 -*- + +""" +*************************************************************************** + CommanderWindow.py + --------------------- + Date : April 2013 + 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. * +* * +*************************************************************************** +""" +__author__ = 'Victor Olaya' +__date__ = 'April 2013' +__copyright__ = '(C) 2013, Victor Olaya' +# This will get replaced with a git SHA1 when you do a git archive +__revision__ = '$Format:%H$' + +from PyQt4 import QtCore, QtGui +from PyQt4.QtCore import * +from PyQt4.QtGui import * +from sextante.core.Sextante import Sextante +from sextante.gui.MissingDependencyDialog import MissingDependencyDialog +from sextante.gui.ParametersDialog import ParametersDialog +from sextante.core.QGisLayers import QGisLayers +from sextante.core.SextanteUtils import SextanteUtils, mkdir +import types +import os +import imp + +ITEMHEIGHT = 30 +OFFSET = 20 +HEIGHT = 60 + +class CommanderWindow(QtGui.QDialog): + def __init__(self, parent, canvas): + self.canvas = canvas + QtGui.QDialog.__init__(self, parent, Qt.FramelessWindowHint) + self.setModal(True) + self.commands = imp.load_source("commands", self.commandsFile()) + self.initGui() + + def commandsFolder(self): + folder = unicode(os.path.join(SextanteUtils.userFolder(), "commander")) + mkdir(folder) + return os.path.abspath(folder) + + def commandsFile(self): + f = os.path.join(self.commandsFolder(), "commands.py") + if not os.path.exists(f): + out = open(f, "w") + out.write("from qgis.core import *\n") + out.write("import sextante\n\n") + out.write("def removeall():\n") + out.write("\tmapreg = QgsMapLayerRegistry.instance()\n") + out.write("\tmapreg.removeAllMapLayers()\n\n") + out.write("def load(*args):\n") + out.write("\tsextante.load(args[0])\n") + out.close() + return f + + + def initGui(self): + self.combo= ExtendedComboBox() + #add algorithm + for providerName in Sextante.algs.keys(): + provider = Sextante.algs[providerName] + algs = provider.values() + for alg in algs: + self.combo.addItem("SEXTANTE algorithm: " + alg.name) + #add functions + for command in dir(self.commands): + if isinstance(self.commands.__dict__.get(command), types.FunctionType): + self.combo.addItem("Command: " + command); + #add menu entries + menuActions = [] + actions = Sextante.getInterface().mainWindow().menuBar().actions() + for action in actions: + menuActions.extend(self.getActions(action)) + for action in menuActions: + self.combo.addItem("Menu action: " + unicode(action.text())) + + self.combo.setEditable(True) + self.combo.setEditText("") + self.label = QtGui.QLabel("Enter command:") + self.errorLabel = QtGui.QLabel("Enter command:") + self.vlayout = QtGui.QVBoxLayout() + self.vlayout.setSpacing(2) + self.vlayout.setMargin(0) + self.vlayout.addSpacerItem(QtGui.QSpacerItem(0, OFFSET, QSizePolicy.Maximum, QSizePolicy.Expanding)); + self.hlayout = QtGui.QHBoxLayout() + self.hlayout.addWidget(self.label) + #self.hlayout.addWidget(self.errorLabel) + self.vlayout.addLayout(self.hlayout) + self.hlayout2 = QtGui.QHBoxLayout() + self.hlayout2.addWidget(self.combo) + self.vlayout.addLayout(self.hlayout2) + self.vlayout.addSpacerItem(QtGui.QSpacerItem(0, OFFSET, QSizePolicy.Maximum, QSizePolicy.Expanding)); + self.setLayout(self.vlayout) + self.combo.lineEdit().returnPressed.connect(self.run) + self.combo.setMaximumSize(QtCore.QSize(self.canvas.rect().width() - 2 * OFFSET, ITEMHEIGHT)) + self.combo.view().setStyleSheet("min-height: 150px") + self.combo.setFocus(Qt.OtherFocusReason) + self.label.setMaximumSize(self.combo.maximumSize()) + self.label.setVisible(False) + self.adjustSize() + pt = self.canvas.rect().topLeft() + absolutePt = self.canvas.mapToGlobal(pt) + self.move(absolutePt) + self.resize(self.canvas.rect().width(), HEIGHT) + self.setStyleSheet("CommanderWindow { background-color: #e7f5fe; border: 1px solid #b9cfe4; }") + + + def getActions(self, action): + menuActions = [] + menu = action.menu() + if menu is None: + menuActions.append(action) + return menuActions + else: + actions = menu.actions() + for subaction in actions: + if subaction.menu() is not None: + menuActions.extend(self.getActions(subaction)) + elif not subaction.isSeparator(): + menuActions.append(subaction) + + return menuActions + + def run(self): + s = unicode(self.combo.currentText()) + if s.startswith("SEXTANTE algorithm: "): + algName = s[len("SEXTANTE algorithm: "):] + alg = Sextante.getAlgorithmFromFullName(algName) + if alg is not None: + self.close() + self.runAlgorithm(alg) + elif s.startswith("Command: "): + command = s[len("Command: "):] + try: + self.runCommand(command) + self.close() + except Exception, e: + self.label.setVisible(True) + self.label.setText("Error:" + unicode(e) ) + + elif s.startswith("Menu action: "): + actionName = s[len("Menu action: "):] + menuActions = [] + actions = Sextante.getInterface().mainWindow().menuBar().actions() + for action in actions: + menuActions.extend(self.getActions(action)) + for action in menuActions: + if action.text() == actionName: + self.close() + action.trigger() + return + else: + try: + self.runCommand(s) + self.close() + except Exception, e: + self.label.setVisible(True) + self.label.setText("Error:" + unicode(e) ) + + def runCommand(self, command): + tokens = command.split(" ") + if len(tokens) == 1: + method = self.commands.__dict__.get(command) + if method is not None: + method() + else: + raise Exception("Wrong command") + else: + method = self.commands.__dict__.get(tokens[0]) + if method is not None: + method(*tokens[1:]) + else: + raise Exception("Wrong command") + + + + def runAlgorithm(self, alg): + alg = alg.getCopy() + message = alg.checkBeforeOpeningParametersDialog() + if message: + dlg = MissingDependencyDialog(message) + dlg.exec_() + return + dlg = alg.getCustomParametersDialog() + if not dlg: + dlg = ParametersDialog(alg) + canvas = QGisLayers.iface.mapCanvas() + prevMapTool = canvas.mapTool() + dlg.show() + dlg.exec_() + if canvas.mapTool()!=prevMapTool: + try: + canvas.mapTool().reset() + except: + pass + canvas.setMapTool(prevMapTool) + + +class ExtendedComboBox(QComboBox): + def __init__(self, parent=None): + super(ExtendedComboBox, self).__init__(parent) + + self.setFocusPolicy(Qt.StrongFocus) + self.setEditable(True) + self.pFilterModel = QSortFilterProxyModel(self) + self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive) + self.pFilterModel.setSourceModel(self.model()) + self.completer = QCompleter(self.pFilterModel, self) + self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) + self.completer.popup().setStyleSheet("min-height: 150px") + self.completer.popup().setAlternatingRowColors(True) + self.setCompleter(self.completer) + self.lineEdit().textEdited[unicode].connect(self.pFilterModel.setFilterFixedString) diff --git a/python/plugins/sextante/commander/__init__.py b/python/plugins/sextante/commander/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/plugins/sextante/core/Sextante.py b/python/plugins/sextante/core/Sextante.py index 289a49bcfd45..7a4dde4bf776 100644 --- a/python/plugins/sextante/core/Sextante.py +++ b/python/plugins/sextante/core/Sextante.py @@ -41,7 +41,6 @@ from sextante.modeler.ModelerAlgorithmProvider import ModelerAlgorithmProvider from sextante.modeler.ModelerOnlyAlgorithmProvider import ModelerOnlyAlgorithmProvider from sextante.algs.QGISAlgorithmProvider import QGISAlgorithmProvider -from sextante.parameters.ParameterSelection import ParameterSelection from sextante.grass.GrassAlgorithmProvider import GrassAlgorithmProvider from sextante.lidar.LidarToolsAlgorithmProvider import LidarToolsAlgorithmProvider from sextante.gdal.GdalOgrAlgorithmProvider import GdalOgrAlgorithmProvider @@ -108,6 +107,14 @@ def getInterface(): @staticmethod def setInterface(iface): Sextante.iface = iface + + @staticmethod + def setPlugin(iface): + Sextante.plugin = iface + + @staticmethod + def getPlugin(): + return Sextante.plugin @staticmethod def initialize(): @@ -232,6 +239,14 @@ def getAlgorithm(name): if name in provider: return provider[name] return None + + @staticmethod + def getAlgorithmFromFullName(name): + for provider in Sextante.algs.values(): + for alg in provider.values(): + if alg.name == name: + return alg + return None @staticmethod def getObject(uri):