1# -*- coding: utf-8 -*-
2"""
3***************************************************************************
4    OtbChoiceWidget.py
5    ------------------
6    Date                 : June 2017
7    Copyright            : (C) 2017 by CS Systemes d'Information (CS SI)
8    Email                : rashad dot kanavath at c-s fr
9
10***************************************************************************
11*                                                                         *
12*   This program is free software; you can redistribute it and/or modify  *
13*   it under the terms of the GNU General Public License as published by  *
14*   the Free Software Foundation; either version 2 of the License, or     *
15*   (at your option) any later version.                                   *
16*                                                                         *
17***************************************************************************
18"""
19
20__author__ = 'Rashad Kanavath'
21__date__ = 'June 2017'
22__copyright__ = "(C) 2017,2018 by CS Systemes d'information (CS SI)"
23
24from qgis.PyQt.QtWidgets import QComboBox
25from qgis.core import (QgsProcessingParameterString,
26                       QgsProcessingOutputString,
27                       QgsProcessingParameterDefinition)
28from qgis.gui import QgsProcessingModelerParameterWidget
29from processing.gui.wrappers import (WidgetWrapper,
30                                     DIALOG_STANDARD,
31                                     DIALOG_BATCH,
32                                     DIALOG_MODELER)
33
34
35# TODO: QGIS 3.8 move this class to processing/gui/
36# OtbChoiceWidget is a crucial parameter type in otb provider
37# It is the one that can handles required parameters are run-time depending on user input!.
38# This idea is indeed different from static list of required/optional parameters from a descriptor file.
39# So this class (if treated as first class citizen in processing/gui) have potential
40# to be reused in existing or future processing providers.
41
42
43class OtbChoiceWidgetWrapper(WidgetWrapper):
44
45    def __init__(self, param, dialog, row=0, col=0, **kwargs):
46        self.flagsModified = {}
47        super().__init__(param, dialog, row=0, col=0, **kwargs)
48        self.updateAllParameters(None)
49
50    def createWidget(self):
51        widget = QComboBox()
52        widget.addItems(self.param.options)
53        if self.dialogType in (DIALOG_MODELER, DIALOG_STANDARD):
54            widget.currentIndexChanged.connect(self.updateAllParameters)
55        return widget
56
57    def get_algorithm(self):
58        if self.dialogType == DIALOG_MODELER:
59            return self.dialog._alg
60        else:
61            return self.dialog.algorithm()
62
63    def __updateWrapper(self, name, visible):
64        if self.dialogType == DIALOG_BATCH:
65            return
66        elif self.dialogType == DIALOG_STANDARD:
67            if self.dialog.mainWidget() is None:
68                return
69            if name in self.dialog.mainWidget().wrappers:
70                self.__setWrapperVisibility(self.dialog.mainWidget().wrappers[name], visible)
71
72        # For QGIS modeler
73        else:
74            try:
75                if name in self.dialog.widget.widget.wrappers:
76                    self.__setWrapperVisibility(self.dialog.widget.widget.wrappers[name], visible)
77                if name in self.dialog.widget.widget.widget_labels:
78                    self.dialog.widget.widget.widget_labels[name].setVisible(visible)
79            except AttributeError:
80                pass
81
82    def __setWrapperVisibility(self, wrapper, v):
83        # For compatibility with 3.x API, we need to check whether the wrapper is
84        # the deprecated WidgetWrapper class. If not, it's the newer
85        # QgsAbstractProcessingParameterWidgetWrapper class
86        # TODO QGIS 4.0 - remove is_python_wrapper logic
87        if issubclass(wrapper.__class__, WidgetWrapper):
88            wrapper.widget.setVisible(v)
89            if wrapper.label:
90                wrapper.label.setVisible(v)
91        elif issubclass(wrapper.__class__, QgsProcessingModelerParameterWidget):
92            wrapper.setVisible(v)
93        else:
94            wrapper.wrappedWidget().setVisible(v)
95            if wrapper.wrappedLabel():
96                wrapper.wrappedLabel().setVisible(v)
97
98    def updateAllParameters(self, current_value):
99        for parameter in self.get_algorithm().parameterDefinitions():
100            if 'group_key' not in parameter.metadata() or parameter.metadata()['group_key'] != self.param.name():
101                continue
102            name = parameter.name()
103            choice_key = parameter.metadata()['group_key']
104            if choice_key and choice_key + "." in name:
105                choice_param = self.get_algorithm().parameterDefinition(choice_key)
106                if current_value is None:
107                    current_value = choice_param.defaultValue()
108                pattern = "{}.{}.".format(choice_key, choice_param.getValueAsText(current_value))
109                if pattern not in name:
110                    flags = self.get_algorithm().parameterDefinition(name).flags()
111                    if not flags & QgsProcessingParameterDefinition.FlagOptional:
112                        self.flagsModified[name] = True
113                    self.get_algorithm().parameterDefinition(name).setFlags(QgsProcessingParameterDefinition.FlagOptional)
114                    self.__updateWrapper(name, False)
115                else:
116                    if name in self.flagsModified.keys():
117                        self.get_algorithm().parameterDefinition(name).setFlags(QgsProcessingParameterDefinition.FlagAdvanced)
118                    self.__updateWrapper(name, True)
119
120    def setValue(self, value):
121        if value in self.param.options:
122            index = self.param.options.index(value)
123        else:
124            index = int(value)
125        self.widget.setCurrentIndex(index)
126
127    def value(self):
128        return self.widget.currentText()
129
130    def postInitialize(self, wrappers):
131        # if self.dialogType == DIALOG_BATCH:
132        #     return
133        self.updateAllParameters(current_value=None)
134        for parameter in self.get_algorithm().parameterDefinitions():
135            if 'group_key' not in parameter.metadata() or parameter.metadata()['group_key'] != self.param.name():
136                continue
137            for wrapper in wrappers:
138                if wrapper.param.name() == parameter.name():
139                    v = self.value() == parameter.metadata()['group_value']
140                    self.__setWrapperVisibility(wrapper, v)
141
142
143from qgis.core import QgsProcessingParameterDefinition
144
145
146class OtbParameterChoice(QgsProcessingParameterDefinition):
147
148    def __init__(self, name='', description='', options=[], default=None, isSource=False,
149                 multiple=False, optional=False):
150
151        QgsProcessingParameterDefinition.__init__(self, name, description, default, optional)
152
153        self.setMetadata({
154            'widget_wrapper': {
155                'class': 'otbprovider.OtbChoiceWidget.OtbChoiceWidgetWrapper'}})
156        self.options = options
157
158        if default is not None:
159            try:
160                self.default = int(default)
161            except Exception:
162                self.default = 0
163            self.value = self.default
164
165    def getValueAsText(self, value):
166        if value not in self.options:
167            value = self.options[int(value)]
168        return value
169
170    def setValue(self, value):
171        if value is None:
172            self.value = 0
173        else:
174            self.value = int(value)
175            return True
176
177    def type(self):
178        # This value is written by otbQgisDescriptor.
179        return 'OTBParameterChoice'
180