QGIS/python/plugins/processing/ProcessingPlugin.py

363 lines
14 KiB
Python
Raw Normal View History

2012-10-05 23:28:47 +02:00
# -*- coding: utf-8 -*-
"""
***************************************************************************
2013-08-12 20:44:27 +02:00
ProcessingPlugin.py
2012-10-05 23:28:47 +02:00
---------------------
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'
import shutil
import os
import sys
2018-09-05 16:34:22 +02:00
from functools import partial
from qgis.core import (QgsApplication,
QgsProcessingUtils,
QgsProcessingModelAlgorithm,
QgsDataItemProvider,
QgsDataProvider,
QgsDataItem,
2019-03-27 07:20:43 +10:00
QgsMapLayerType,
QgsMimeDataUtils)
from qgis.gui import (QgsOptionsWidgetFactory,
QgsCustomDropHandler)
from qgis.PyQt.QtCore import Qt, QCoreApplication, QDir, QFileInfo
2016-04-22 10:38:48 +02:00
from qgis.PyQt.QtWidgets import QMenu, QAction
from qgis.PyQt.QtGui import QIcon, QKeySequence
from qgis.utils import iface
2013-08-12 20:44:27 +02:00
from processing.core.Processing import Processing
from processing.gui.AlgorithmDialog import AlgorithmDialog
2013-08-12 20:44:27 +02:00
from processing.gui.ProcessingToolbox import ProcessingToolbox
from processing.gui.HistoryDialog import HistoryDialog
2017-03-13 10:00:51 +01:00
from processing.gui.ConfigDialog import ConfigOptionsPage
from processing.gui.ResultsDock import ResultsDock
2018-07-23 13:58:11 +10:00
from processing.gui.AlgorithmLocatorFilter import (AlgorithmLocatorFilter,
InPlaceAlgorithmLocatorFilter)
from processing.modeler.ModelerDialog import ModelerDialog
from processing.tools.system import tempHelpFolder
from processing.gui.menus import removeMenus, initializeMenus, createMenus
from processing.core.ProcessingResults import resultsList
2012-09-18 20:02:43 +03:00
pluginPath = os.path.dirname(__file__)
2012-09-15 18:25:25 +03:00
class ProcessingOptionsFactory(QgsOptionsWidgetFactory):
def __init__(self):
super(QgsOptionsWidgetFactory, self).__init__()
def icon(self):
return QgsApplication.getThemeIcon('/processingAlgorithm.svg')
def createWidget(self, parent):
return ConfigOptionsPage(parent)
class ProcessingDropHandler(QgsCustomDropHandler):
def handleFileDrop(self, file):
if not file.lower().endswith('.model3'):
return False
return self.runAlg(file)
@staticmethod
def runAlg(file):
alg = QgsProcessingModelAlgorithm()
if not alg.fromFile(file):
return False
alg.setProvider(QgsApplication.processingRegistry().providerById('model'))
dlg = AlgorithmDialog(alg, parent=iface.mainWindow())
dlg.show()
return True
def customUriProviderKey(self):
return 'processing'
def handleCustomUriDrop(self, uri):
path = uri.uri
self.runAlg(path)
class ProcessingModelItem(QgsDataItem):
def __init__(self, parent, name, path):
2017-09-20 18:41:42 +10:00
super(ProcessingModelItem, self).__init__(QgsDataItem.Custom, parent, name, path)
self.setState(QgsDataItem.Populated) # no children
self.setIconName(":/images/themes/default/processingModel.svg")
2017-09-20 18:41:42 +10:00
self.setToolTip(QDir.toNativeSeparators(path))
def hasDragEnabled(self):
return True
def handleDoubleClick(self):
self.runModel()
return True
def mimeUri(self):
u = QgsMimeDataUtils.Uri()
u.layerType = "custom"
u.providerKey = "processing"
u.name = self.name()
u.uri = self.path()
return u
def runModel(self):
ProcessingDropHandler.runAlg(self.path())
def editModel(self):
dlg = ModelerDialog()
dlg.loadModel(self.path())
dlg.show()
2017-12-13 16:54:12 +10:00
def actions(self, parent):
run_model_action = QAction(QCoreApplication.translate('ProcessingPlugin', '&Run Model…'), parent)
run_model_action.triggered.connect(self.runModel)
2017-12-13 16:54:12 +10:00
edit_model_action = QAction(QCoreApplication.translate('ProcessingPlugin', '&Edit Model…'), parent)
edit_model_action.triggered.connect(self.editModel)
return [run_model_action, edit_model_action]
class ProcessingDataItemProvider(QgsDataItemProvider):
def __init__(self):
super(ProcessingDataItemProvider, self).__init__()
def name(self):
return 'processing'
def capabilities(self):
return QgsDataProvider.File
def createDataItem(self, path, parentItem):
file_info = QFileInfo(path)
if file_info.suffix().lower() == 'model3':
alg = QgsProcessingModelAlgorithm()
if alg.fromFile(path):
return ProcessingModelItem(parentItem, alg.name(), path)
return None
2017-09-20 18:41:42 +10:00
class ProcessingPlugin:
2012-09-15 18:25:25 +03:00
def __init__(self, iface):
self.iface = iface
self.options_factory = None
self.drop_handler = None
self.item_provider = None
self.locator_filter = None
self.edit_features_locator_filter = None
self.initialized = False
self.initProcessing()
def initProcessing(self):
if not self.initialized:
self.initialized = True
Processing.initialize()
def initGui(self):
self.options_factory = ProcessingOptionsFactory()
self.options_factory.setTitle(self.tr('Processing'))
iface.registerOptionsWidgetFactory(self.options_factory)
self.drop_handler = ProcessingDropHandler()
iface.registerCustomDropHandler(self.drop_handler)
self.item_provider = ProcessingDataItemProvider()
QgsApplication.dataItemProviderRegistry().addProvider(self.item_provider)
self.locator_filter = AlgorithmLocatorFilter()
iface.registerLocatorFilter(self.locator_filter)
# Invalidate the locator filter for in-place when active layer changes
iface.currentLayerChanged.connect(lambda _: self.iface.invalidateLocatorResults())
2018-07-23 13:58:11 +10:00
self.edit_features_locator_filter = InPlaceAlgorithmLocatorFilter()
iface.registerLocatorFilter(self.edit_features_locator_filter)
self.toolbox = ProcessingToolbox()
self.iface.addDockWidget(Qt.RightDockWidgetArea, self.toolbox)
self.toolbox.hide()
self.toolbox.visibilityChanged.connect(self.toolboxVisibilityChanged)
2013-05-01 23:45:20 +02:00
self.resultsDock = ResultsDock()
self.iface.addDockWidget(Qt.RightDockWidgetArea, self.resultsDock)
self.resultsDock.hide()
self.menu = QMenu(self.iface.mainWindow().menuBar())
self.menu.setObjectName('processing')
self.menu.setTitle(self.tr('Pro&cessing'))
2012-09-15 18:25:25 +03:00
self.toolboxAction = QAction(self.tr('&Toolbox'), self.iface.mainWindow())
self.toolboxAction.setCheckable(True)
self.toolboxAction.setObjectName('toolboxAction')
self.toolboxAction.setIcon(
QgsApplication.getThemeIcon("/processingAlgorithm.svg"))
self.iface.registerMainWindowAction(self.toolboxAction,
QKeySequence('Ctrl+Alt+T').toString(QKeySequence.NativeText))
self.toolboxAction.toggled.connect(self.openToolbox)
self.iface.attributesToolBar().insertAction(self.iface.actionOpenStatisticalSummary(), self.toolboxAction)
2012-09-15 18:25:25 +03:00
self.menu.addAction(self.toolboxAction)
self.modelerAction = QAction(
QgsApplication.getThemeIcon("/processingModel.svg"),
QCoreApplication.translate('ProcessingPlugin', '&Graphical Modeler…'), self.iface.mainWindow())
self.modelerAction.setObjectName('modelerAction')
self.modelerAction.triggered.connect(self.openModeler)
self.iface.registerMainWindowAction(self.modelerAction,
QKeySequence('Ctrl+Alt+G').toString(QKeySequence.NativeText))
2012-09-15 18:25:25 +03:00
self.menu.addAction(self.modelerAction)
self.historyAction = QAction(
2018-07-07 14:22:04 +10:00
QgsApplication.getThemeIcon("/mIconHistory.svg"),
2018-02-15 22:30:52 +01:00
QCoreApplication.translate('ProcessingPlugin', '&History…'), self.iface.mainWindow())
self.historyAction.setObjectName('historyAction')
self.historyAction.triggered.connect(self.openHistory)
self.iface.registerMainWindowAction(self.historyAction,
QKeySequence('Ctrl+Alt+H').toString(QKeySequence.NativeText))
2012-09-15 18:25:25 +03:00
self.menu.addAction(self.historyAction)
2018-01-23 22:30:29 +01:00
self.toolbox.processingToolbar.addAction(self.historyAction)
2012-09-15 18:25:25 +03:00
self.resultsAction = QAction(
QgsApplication.getThemeIcon("/processingResult.svg"),
self.tr('&Results Viewer'), self.iface.mainWindow())
self.resultsAction.setObjectName('resultsViewer')
self.resultsAction.setCheckable(True)
self.iface.registerMainWindowAction(self.resultsAction,
QKeySequence('Ctrl+Alt+R').toString(QKeySequence.NativeText))
2012-09-15 18:25:25 +03:00
self.menu.addAction(self.resultsAction)
2018-01-23 22:30:29 +01:00
self.toolbox.processingToolbar.addAction(self.resultsAction)
self.resultsDock.visibilityChanged.connect(self.resultsAction.setChecked)
self.resultsAction.toggled.connect(self.resultsDock.setUserVisible)
2018-01-23 22:30:29 +01:00
self.toolbox.processingToolbar.addSeparator()
2012-09-15 18:25:25 +03:00
self.editInPlaceAction = QAction(
QgsApplication.getThemeIcon("/mActionProcessSelected.svg"),
self.tr('Edit Features In-Place'), self.iface.mainWindow())
self.editInPlaceAction.setObjectName('editInPlaceFeatures')
self.editInPlaceAction.setCheckable(True)
self.editInPlaceAction.toggled.connect(self.editSelected)
self.menu.addAction(self.editInPlaceAction)
self.toolbox.processingToolbar.addAction(self.editInPlaceAction)
2018-07-23 13:58:11 +10:00
self.toolbox.processingToolbar.addSeparator()
self.optionsAction = QAction(
QgsApplication.getThemeIcon("/mActionOptions.svg"),
self.tr('Options'), self.iface.mainWindow())
self.optionsAction.setObjectName('optionsAction')
self.optionsAction.triggered.connect(self.openProcessingOptions)
self.toolbox.processingToolbar.addAction(self.optionsAction)
menuBar = self.iface.mainWindow().menuBar()
menuBar.insertMenu(
self.iface.firstRightStandardMenu().menuAction(), self.menu)
2012-09-15 18:25:25 +03:00
self.menu.addSeparator()
initializeMenus()
createMenus()
2018-09-05 16:34:22 +02:00
# In-place editing button state sync
self.iface.currentLayerChanged.connect(self.sync_in_place_button_state)
self.iface.mapCanvas().selectionChanged.connect(self.sync_in_place_button_state)
self.iface.actionToggleEditing().triggered.connect(partial(self.sync_in_place_button_state, None))
self.sync_in_place_button_state()
2018-07-23 13:58:11 +10:00
2018-09-05 16:34:22 +02:00
def sync_in_place_button_state(self, layer=None):
"""Synchronise the button state with layer state"""
2018-09-05 17:10:55 +02:00
2018-09-05 16:34:22 +02:00
if layer is None:
layer = self.iface.activeLayer()
2018-09-05 17:10:55 +02:00
old_enabled_state = self.editInPlaceAction.isEnabled()
2018-09-05 17:10:55 +02:00
new_enabled_state = layer is not None and layer.type() == QgsMapLayerType.VectorLayer
self.editInPlaceAction.setEnabled(new_enabled_state)
2018-09-05 17:10:55 +02:00
if new_enabled_state != old_enabled_state:
self.toolbox.set_in_place_edit_mode(new_enabled_state and self.editInPlaceAction.isChecked())
2018-07-23 13:58:11 +10:00
2018-01-23 22:30:29 +01:00
def openProcessingOptions(self):
self.iface.showOptionsDialog(self.iface.mainWindow(), currentPage='processingOptions')
2012-09-15 18:25:25 +03:00
def unload(self):
self.toolbox.setVisible(False)
self.iface.removeDockWidget(self.toolbox)
self.iface.attributesToolBar().removeAction(self.toolboxAction)
self.resultsDock.setVisible(False)
self.iface.removeDockWidget(self.resultsDock)
self.toolbox.deleteLater()
2012-09-15 18:25:25 +03:00
self.menu.deleteLater()
# delete temporary output files
folder = QgsProcessingUtils.tempFolder()
if QDir(folder).exists():
shutil.rmtree(folder, True)
2013-05-01 23:45:20 +02:00
# also delete temporary help files
folder = tempHelpFolder()
if QDir(folder).exists():
shutil.rmtree(folder, True)
self.iface.unregisterMainWindowAction(self.toolboxAction)
self.iface.unregisterMainWindowAction(self.modelerAction)
self.iface.unregisterMainWindowAction(self.historyAction)
self.iface.unregisterMainWindowAction(self.resultsAction)
2013-05-01 23:45:20 +02:00
self.iface.unregisterOptionsWidgetFactory(self.options_factory)
self.iface.deregisterLocatorFilter(self.locator_filter)
2018-07-23 13:58:11 +10:00
self.iface.deregisterLocatorFilter(self.edit_features_locator_filter)
self.iface.unregisterCustomDropHandler(self.drop_handler)
QgsApplication.dataItemProviderRegistry().removeProvider(self.item_provider)
removeMenus()
Processing.deinitialize()
def openToolbox(self, show):
self.toolbox.setUserVisible(show)
def toolboxVisibilityChanged(self, visible):
self.toolboxAction.setChecked(visible)
2012-09-15 18:25:25 +03:00
def openModeler(self):
dlg = ModelerDialog()
dlg.update_model.connect(self.updateModel)
dlg.show()
def updateModel(self):
model_provider = QgsApplication.processingRegistry().providerById('model')
model_provider.refreshAlgorithms()
2012-09-15 18:25:25 +03:00
def openResults(self):
if self.resultsDock.isVisible():
self.resultsDock.hide()
else:
self.resultsDock.show()
2012-09-15 18:25:25 +03:00
def openHistory(self):
dlg = HistoryDialog()
dlg.exec_()
def tr(self, message):
return QCoreApplication.translate('ProcessingPlugin', message)
2018-07-23 13:58:11 +10:00
def editSelected(self, enabled):
self.toolbox.set_in_place_edit_mode(enabled)