ParametersPanel.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. """
  2. ***************************************************************************
  3. ParametersPanel.py
  4. ---------------------
  5. Date : August 2012
  6. Copyright : (C) 2012 by Victor Olaya
  7. (C) 2013 by CS Systemes d'information (CS SI)
  8. Email : volayaf at gmail dot com
  9. otb at c-s dot fr (CS SI)
  10. Contributors : Victor Olaya
  11. ***************************************************************************
  12. * *
  13. * This program is free software; you can redistribute it and/or modify *
  14. * it under the terms of the GNU General Public License as published by *
  15. * the Free Software Foundation; either version 2 of the License, or *
  16. * (at your option) any later version. *
  17. * *
  18. ***************************************************************************
  19. """
  20. __author__ = 'Victor Olaya'
  21. __date__ = 'August 2012'
  22. __copyright__ = '(C) 2012, Victor Olaya'
  23. from qgis.core import (QgsProcessingParameterDefinition,
  24. QgsProcessingParameterExtent,
  25. QgsProject,
  26. QgsProcessingModelAlgorithm,
  27. QgsProcessingOutputLayerDefinition)
  28. from qgis.gui import (QgsProcessingContextGenerator,
  29. QgsProcessingParameterWidgetContext,
  30. QgsProcessingParametersWidget,
  31. QgsGui,
  32. QgsProcessingGui,
  33. QgsProcessingParametersGenerator,
  34. QgsProcessingHiddenWidgetWrapper)
  35. from qgis.utils import iface
  36. from processing.gui.wrappers import WidgetWrapperFactory, WidgetWrapper
  37. from processing.gui.AlgorithmDialogBase import AlgorithmDialogBase
  38. from processing.tools.dataobjects import createContext
  39. class ParametersPanel(QgsProcessingParametersWidget):
  40. def __init__(self, parent, alg, in_place=False, active_layer=None):
  41. super().__init__(alg, parent)
  42. self.in_place = in_place
  43. self.active_layer = active_layer
  44. self.wrappers = {}
  45. self.extra_parameters = {}
  46. self.processing_context = createContext()
  47. class ContextGenerator(QgsProcessingContextGenerator):
  48. def __init__(self, context):
  49. super().__init__()
  50. self.processing_context = context
  51. def processingContext(self):
  52. return self.processing_context
  53. self.context_generator = ContextGenerator(self.processing_context)
  54. self.initWidgets()
  55. QgsProject.instance().layerWasAdded.connect(self.layerRegistryChanged)
  56. QgsProject.instance().layersWillBeRemoved.connect(self.layerRegistryChanged)
  57. def layerRegistryChanged(self, layers):
  58. for wrapper in list(self.wrappers.values()):
  59. try:
  60. wrapper.refresh()
  61. except AttributeError:
  62. pass
  63. def initWidgets(self):
  64. super().initWidgets()
  65. widget_context = QgsProcessingParameterWidgetContext()
  66. widget_context.setProject(QgsProject.instance())
  67. if iface is not None:
  68. widget_context.setMapCanvas(iface.mapCanvas())
  69. widget_context.setBrowserModel(iface.browserModel())
  70. widget_context.setActiveLayer(iface.activeLayer())
  71. widget_context.setMessageBar(self.parent().messageBar())
  72. if isinstance(self.algorithm(), QgsProcessingModelAlgorithm):
  73. widget_context.setModel(self.algorithm())
  74. in_place_input_parameter_name = 'INPUT'
  75. if hasattr(self.algorithm(), 'inputParameterName'):
  76. in_place_input_parameter_name = self.algorithm().inputParameterName()
  77. # Create widgets and put them in layouts
  78. for param in self.algorithm().parameterDefinitions():
  79. if param.flags() & QgsProcessingParameterDefinition.FlagHidden:
  80. continue
  81. if param.isDestination():
  82. continue
  83. else:
  84. if self.in_place and param.name() in (in_place_input_parameter_name, 'OUTPUT'):
  85. # don't show the input/output parameter widgets in in-place mode
  86. # we still need to CREATE them, because other wrappers may need to interact
  87. # with them (e.g. those parameters which need the input layer for field
  88. # selections/crs properties/etc)
  89. self.wrappers[param.name()] = QgsProcessingHiddenWidgetWrapper(param, QgsProcessingGui.Standard, self)
  90. self.wrappers[param.name()].setLinkedVectorLayer(self.active_layer)
  91. continue
  92. wrapper = WidgetWrapperFactory.create_wrapper(param, self.parent())
  93. wrapper.setWidgetContext(widget_context)
  94. wrapper.registerProcessingContextGenerator(self.context_generator)
  95. wrapper.registerProcessingParametersGenerator(self)
  96. self.wrappers[param.name()] = wrapper
  97. # For compatibility with 3.x API, we need to check whether the wrapper is
  98. # the deprecated WidgetWrapper class. If not, it's the newer
  99. # QgsAbstractProcessingParameterWidgetWrapper class
  100. # TODO QGIS 4.0 - remove
  101. is_python_wrapper = issubclass(wrapper.__class__, WidgetWrapper)
  102. stretch = 0
  103. if not is_python_wrapper:
  104. widget = wrapper.createWrappedWidget(self.processing_context)
  105. stretch = wrapper.stretch()
  106. else:
  107. widget = wrapper.widget
  108. if widget is not None:
  109. if is_python_wrapper:
  110. widget.setToolTip(param.toolTip())
  111. label = None
  112. if not is_python_wrapper:
  113. label = wrapper.createWrappedLabel()
  114. else:
  115. label = wrapper.label
  116. if label is not None:
  117. self.addParameterLabel(param, label)
  118. elif is_python_wrapper:
  119. desc = param.description()
  120. if isinstance(param, QgsProcessingParameterExtent):
  121. desc += self.tr(' (xmin, xmax, ymin, ymax)')
  122. if param.flags() & QgsProcessingParameterDefinition.FlagOptional:
  123. desc += self.tr(' [optional]')
  124. widget.setText(desc)
  125. self.addParameterWidget(param, widget, stretch)
  126. for output in self.algorithm().destinationParameterDefinitions():
  127. if output.flags() & QgsProcessingParameterDefinition.FlagHidden:
  128. continue
  129. if self.in_place and output.name() in (in_place_input_parameter_name, 'OUTPUT'):
  130. continue
  131. wrapper = QgsGui.processingGuiRegistry().createParameterWidgetWrapper(output, QgsProcessingGui.Standard)
  132. wrapper.setWidgetContext(widget_context)
  133. wrapper.registerProcessingContextGenerator(self.context_generator)
  134. wrapper.registerProcessingParametersGenerator(self)
  135. self.wrappers[output.name()] = wrapper
  136. label = wrapper.createWrappedLabel()
  137. if label is not None:
  138. self.addOutputLabel(label)
  139. widget = wrapper.createWrappedWidget(self.processing_context)
  140. self.addOutputWidget(widget, wrapper.stretch())
  141. # def skipOutputChanged(widget, checkbox, skipped):
  142. # TODO
  143. # enabled = not skipped
  144. #
  145. # # Do not try to open formats that are write-only.
  146. # value = widget.value()
  147. # if value and isinstance(value, QgsProcessingOutputLayerDefinition) and isinstance(output, (
  148. # QgsProcessingParameterFeatureSink, QgsProcessingParameterVectorDestination)):
  149. # filename = value.sink.staticValue()
  150. # if filename not in ('memory:', ''):
  151. # path, ext = os.path.splitext(filename)
  152. # format = QgsVectorFileWriter.driverForExtension(ext)
  153. # drv = gdal.GetDriverByName(format)
  154. # if drv:
  155. # if drv.GetMetadataItem(gdal.DCAP_OPEN) is None:
  156. # enabled = False
  157. #
  158. # checkbox.setEnabled(enabled)
  159. # checkbox.setChecked(enabled)
  160. for wrapper in list(self.wrappers.values()):
  161. wrapper.postInitialize(list(self.wrappers.values()))
  162. def createProcessingParameters(self, flags=QgsProcessingParametersGenerator.Flags()):
  163. include_default = not (flags & QgsProcessingParametersGenerator.Flag.SkipDefaultValueParameters)
  164. parameters = {}
  165. for p, v in self.extra_parameters.items():
  166. parameters[p] = v
  167. for param in self.algorithm().parameterDefinitions():
  168. if param.flags() & QgsProcessingParameterDefinition.FlagHidden:
  169. continue
  170. if not param.isDestination():
  171. try:
  172. wrapper = self.wrappers[param.name()]
  173. except KeyError:
  174. continue
  175. # For compatibility with 3.x API, we need to check whether the wrapper is
  176. # the deprecated WidgetWrapper class. If not, it's the newer
  177. # QgsAbstractProcessingParameterWidgetWrapper class
  178. # TODO QGIS 4.0 - remove
  179. if issubclass(wrapper.__class__, WidgetWrapper):
  180. widget = wrapper.widget
  181. else:
  182. widget = wrapper.wrappedWidget()
  183. if not isinstance(wrapper, QgsProcessingHiddenWidgetWrapper) and widget is None:
  184. continue
  185. value = wrapper.parameterValue()
  186. if param.defaultValue() != value or include_default:
  187. parameters[param.name()] = value
  188. if not param.checkValueIsAcceptable(value):
  189. raise AlgorithmDialogBase.InvalidParameterValue(param, widget)
  190. else:
  191. if self.in_place and param.name() == 'OUTPUT':
  192. parameters[param.name()] = 'memory:'
  193. continue
  194. try:
  195. wrapper = self.wrappers[param.name()]
  196. except KeyError:
  197. continue
  198. widget = wrapper.wrappedWidget()
  199. value = wrapper.parameterValue()
  200. dest_project = None
  201. if wrapper.customProperties().get('OPEN_AFTER_RUNNING'):
  202. dest_project = QgsProject.instance()
  203. if value and isinstance(value, QgsProcessingOutputLayerDefinition):
  204. value.destinationProject = dest_project
  205. if value and (param.defaultValue() != value or include_default):
  206. parameters[param.name()] = value
  207. context = createContext()
  208. ok, error = param.isSupportedOutputValue(value, context)
  209. if not ok:
  210. raise AlgorithmDialogBase.InvalidOutputExtension(widget, error)
  211. return self.algorithm().preprocessParameters(parameters)
  212. def setParameters(self, parameters):
  213. self.extra_parameters = {}
  214. for param in self.algorithm().parameterDefinitions():
  215. if param.flags() & QgsProcessingParameterDefinition.FlagHidden:
  216. if param.name() in parameters:
  217. self.extra_parameters[param.name()] = parameters[param.name()]
  218. continue
  219. if not param.name() in parameters:
  220. continue
  221. value = parameters[param.name()]
  222. wrapper = self.wrappers[param.name()]
  223. wrapper.setParameterValue(value, self.processing_context)