ProcessingToolbox.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. """
  2. ***************************************************************************
  3. ProcessingToolbox.py
  4. ---------------------
  5. Date : August 2012
  6. Copyright : (C) 2012 by Victor Olaya
  7. Email : volayaf at gmail dot com
  8. ***************************************************************************
  9. * *
  10. * This program is free software; you can redistribute it and/or modify *
  11. * it under the terms of the GNU General Public License as published by *
  12. * the Free Software Foundation; either version 2 of the License, or *
  13. * (at your option) any later version. *
  14. * *
  15. ***************************************************************************
  16. """
  17. __author__ = 'Victor Olaya'
  18. __date__ = 'August 2012'
  19. __copyright__ = '(C) 2012, Victor Olaya'
  20. import operator
  21. import os
  22. import warnings
  23. from qgis.PyQt import uic
  24. from qgis.PyQt.QtCore import Qt, QCoreApplication, pyqtSignal
  25. from qgis.PyQt.QtWidgets import QWidget, QToolButton, QMenu, QAction
  26. from qgis.utils import iface
  27. from qgis.core import (QgsWkbTypes,
  28. QgsMapLayerType,
  29. QgsApplication,
  30. QgsProcessingAlgorithm)
  31. from qgis.gui import (QgsGui,
  32. QgsDockWidget,
  33. QgsProcessingToolboxProxyModel)
  34. from processing.gui.Postprocessing import handleAlgorithmResults
  35. from processing.core.ProcessingConfig import ProcessingConfig
  36. from processing.gui.MessageDialog import MessageDialog
  37. from processing.gui.EditRenderingStylesDialog import EditRenderingStylesDialog
  38. from processing.gui.MessageBarProgress import MessageBarProgress
  39. from processing.gui.ProviderActions import (ProviderActions,
  40. ProviderContextMenuActions)
  41. from processing.tools import dataobjects
  42. pluginPath = os.path.split(os.path.dirname(__file__))[0]
  43. with warnings.catch_warnings():
  44. warnings.filterwarnings("ignore", category=DeprecationWarning)
  45. WIDGET, BASE = uic.loadUiType(
  46. os.path.join(pluginPath, 'ui', 'ProcessingToolbox.ui'))
  47. class ProcessingToolbox(QgsDockWidget, WIDGET):
  48. ALG_ITEM = 'ALG_ITEM'
  49. PROVIDER_ITEM = 'PROVIDER_ITEM'
  50. GROUP_ITEM = 'GROUP_ITEM'
  51. NAME_ROLE = Qt.UserRole
  52. TAG_ROLE = Qt.UserRole + 1
  53. TYPE_ROLE = Qt.UserRole + 2
  54. # Trigger algorithm execution
  55. executeWithGui = pyqtSignal(str, QWidget, bool, bool)
  56. def __init__(self):
  57. super().__init__(None)
  58. self.tipWasClosed = False
  59. self.in_place_mode = False
  60. self.setupUi(self)
  61. self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
  62. self.processingToolbar.setIconSize(iface.iconSize(True))
  63. self.algorithmTree.setRegistry(QgsApplication.processingRegistry(),
  64. QgsGui.instance().processingRecentAlgorithmLog())
  65. filters = QgsProcessingToolboxProxyModel.Filters(QgsProcessingToolboxProxyModel.FilterToolbox)
  66. if ProcessingConfig.getSetting(ProcessingConfig.SHOW_ALGORITHMS_KNOWN_ISSUES):
  67. filters |= QgsProcessingToolboxProxyModel.FilterShowKnownIssues
  68. self.algorithmTree.setFilters(filters)
  69. self.searchBox.setShowSearchIcon(True)
  70. self.searchBox.textChanged.connect(self.set_filter_string)
  71. self.searchBox.returnPressed.connect(self.activateCurrent)
  72. self.algorithmTree.customContextMenuRequested.connect(
  73. self.showPopupMenu)
  74. self.algorithmTree.doubleClicked.connect(self.executeAlgorithm)
  75. self.txtTip.setVisible(self.disabledProviders())
  76. def openSettings(url):
  77. if url == "close":
  78. self.txtTip.setVisible(False)
  79. self.tipWasClosed = True
  80. else:
  81. iface.showOptionsDialog(iface.mainWindow(), 'processingOptions')
  82. self.txtTip.setVisible(self.disabledProviders())
  83. self.txtTip.linkActivated.connect(openSettings)
  84. if hasattr(self.searchBox, 'setPlaceholderText'):
  85. self.searchBox.setPlaceholderText(QCoreApplication.translate('ProcessingToolbox', 'Search…'))
  86. # connect to existing providers
  87. for p in QgsApplication.processingRegistry().providers():
  88. if p.isActive():
  89. self.addProviderActions(p)
  90. QgsApplication.processingRegistry().providerRemoved.connect(self.addProvider)
  91. QgsApplication.processingRegistry().providerRemoved.connect(self.removeProvider)
  92. iface.currentLayerChanged.connect(self.layer_changed)
  93. def set_filter_string(self, string):
  94. filters = self.algorithmTree.filters()
  95. if ProcessingConfig.getSetting(ProcessingConfig.SHOW_ALGORITHMS_KNOWN_ISSUES):
  96. filters |= QgsProcessingToolboxProxyModel.FilterShowKnownIssues
  97. else:
  98. filters &= ~QgsProcessingToolboxProxyModel.FilterShowKnownIssues
  99. self.algorithmTree.setFilters(filters)
  100. self.algorithmTree.setFilterString(string)
  101. def set_in_place_edit_mode(self, enabled):
  102. filters = QgsProcessingToolboxProxyModel.Filters(QgsProcessingToolboxProxyModel.FilterToolbox)
  103. if ProcessingConfig.getSetting(ProcessingConfig.SHOW_ALGORITHMS_KNOWN_ISSUES):
  104. filters |= QgsProcessingToolboxProxyModel.FilterShowKnownIssues
  105. if enabled:
  106. self.algorithmTree.setFilters(filters | QgsProcessingToolboxProxyModel.FilterInPlace)
  107. else:
  108. self.algorithmTree.setFilters(filters)
  109. self.in_place_mode = enabled
  110. def layer_changed(self, layer):
  111. if layer is None or layer.type() != QgsMapLayerType.VectorLayer:
  112. return
  113. self.algorithmTree.setInPlaceLayer(layer)
  114. def disabledProviders(self):
  115. showTip = ProcessingConfig.getSetting(ProcessingConfig.SHOW_PROVIDERS_TOOLTIP)
  116. if not showTip or self.tipWasClosed:
  117. return False
  118. for provider in QgsApplication.processingRegistry().providers():
  119. if not provider.isActive() and provider.canBeActivated():
  120. return True
  121. return False
  122. def addProviderActions(self, provider):
  123. if provider.id() in ProviderActions.actions:
  124. toolbarButton = QToolButton()
  125. toolbarButton.setObjectName('provideraction_' + provider.id())
  126. toolbarButton.setIcon(provider.icon())
  127. toolbarButton.setToolTip(provider.name())
  128. toolbarButton.setPopupMode(QToolButton.InstantPopup)
  129. actions = ProviderActions.actions[provider.id()]
  130. menu = QMenu(provider.name(), self)
  131. for action in actions:
  132. action.setData(self)
  133. act = QAction(action.name, menu)
  134. act.triggered.connect(action.execute)
  135. menu.addAction(act)
  136. toolbarButton.setMenu(menu)
  137. self.processingToolbar.addWidget(toolbarButton)
  138. def addProvider(self, provider_id):
  139. provider = QgsApplication.processingRegistry().providerById(provider_id)
  140. if provider is not None:
  141. self.addProviderActions(provider)
  142. def removeProvider(self, provider_id):
  143. button = self.findChild(QToolButton, 'provideraction-' + provider_id)
  144. if button:
  145. self.processingToolbar.removeChild(button)
  146. def showPopupMenu(self, point):
  147. index = self.algorithmTree.indexAt(point)
  148. popupmenu = QMenu()
  149. alg = self.algorithmTree.algorithmForIndex(index)
  150. if alg is not None:
  151. executeAction = QAction(QCoreApplication.translate('ProcessingToolbox', 'Execute…'), popupmenu)
  152. executeAction.triggered.connect(self.executeAlgorithm)
  153. popupmenu.addAction(executeAction)
  154. if alg.flags() & QgsProcessingAlgorithm.FlagSupportsBatch:
  155. executeBatchAction = QAction(
  156. QCoreApplication.translate('ProcessingToolbox', 'Execute as Batch Process…'),
  157. popupmenu)
  158. executeBatchAction.triggered.connect(
  159. self.executeAlgorithmAsBatchProcess)
  160. popupmenu.addAction(executeBatchAction)
  161. popupmenu.addSeparator()
  162. editRenderingStylesAction = QAction(
  163. QCoreApplication.translate('ProcessingToolbox', 'Edit Rendering Styles for Outputs…'),
  164. popupmenu)
  165. editRenderingStylesAction.triggered.connect(
  166. self.editRenderingStyles)
  167. popupmenu.addAction(editRenderingStylesAction)
  168. actions = ProviderContextMenuActions.actions
  169. if len(actions) > 0:
  170. popupmenu.addSeparator()
  171. for action in actions:
  172. action.setData(alg, self)
  173. if action.is_separator:
  174. popupmenu.addSeparator()
  175. elif action.isEnabled():
  176. contextMenuAction = QAction(action.name,
  177. popupmenu)
  178. contextMenuAction.setIcon(action.icon())
  179. contextMenuAction.triggered.connect(action.execute)
  180. popupmenu.addAction(contextMenuAction)
  181. popupmenu.exec_(self.algorithmTree.mapToGlobal(point))
  182. def editRenderingStyles(self):
  183. alg = self.algorithmTree.selectedAlgorithm().create() if self.algorithmTree.selectedAlgorithm() is not None else None
  184. if alg is not None:
  185. dlg = EditRenderingStylesDialog(alg)
  186. dlg.exec_()
  187. def activateCurrent(self):
  188. self.executeAlgorithm()
  189. def executeAlgorithmAsBatchProcess(self):
  190. alg = self.algorithmTree.selectedAlgorithm()
  191. if alg is not None:
  192. self.executeWithGui.emit(alg.id(), self, self.in_place_mode, True)
  193. def executeAlgorithm(self):
  194. alg = self.algorithmTree.selectedAlgorithm()
  195. if alg is not None:
  196. self.executeWithGui.emit(alg.id(), self, self.in_place_mode, False)