Example #1
0
class ModelerParametersDialog(QDialog):

    ENTER_NAME = '[Enter name if this is a final result]'
    NOT_SELECTED = '[Not selected]'
    USE_MIN_COVERING_EXTENT = '[Use min covering extent]'

    def __init__(self, alg, model, algName=None):
        QDialog.__init__(self)
        self.setModal(True)
        # The algorithm to define in this dialog. It is an instance of GeoAlgorithm
        self._alg = alg
        # The resulting algorithm after the user clicks on OK. it is an instance of the container Algorithm class
        self.alg = None
        # The model this algorithm is going to be added to
        self.model = model
        # The name of the algorithm in the model, in case we are editing it and not defining it for the first time
        self._algName = algName
        self.setupUi()
        self.params = None

    def setupUi(self):
        self.labels = {}
        self.widgets = {}
        self.checkBoxes = {}
        self.showAdvanced = False
        self.valueItems = {}
        self.dependentItems = {}
        self.resize(650, 450)
        self.buttonBox = QDialogButtonBox()
        self.buttonBox.setOrientation(Qt.Horizontal)
        self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel
                                          | QDialogButtonBox.Ok)
        tooltips = self._alg.getParameterDescriptions()
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.verticalLayout = QVBoxLayout()
        self.verticalLayout.setSpacing(5)
        self.verticalLayout.setMargin(20)

        self.bar = QgsMessageBar()
        self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        self.verticalLayout.addWidget(self.bar)

        hLayout = QHBoxLayout()
        hLayout.setSpacing(5)
        hLayout.setMargin(0)
        descriptionLabel = QLabel(self.tr("Description"))
        self.descriptionBox = QLineEdit()
        self.descriptionBox.setText(self._alg.name)
        hLayout.addWidget(descriptionLabel)
        hLayout.addWidget(self.descriptionBox)
        self.verticalLayout.addLayout(hLayout)
        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)
        self.verticalLayout.addWidget(line)

        for param in self._alg.parameters:
            if param.isAdvanced:
                self.advancedButton = QPushButton()
                self.advancedButton.setText(
                    self.tr('Show advanced parameters'))
                self.advancedButton.clicked.connect(
                    self.showAdvancedParametersClicked)
                advancedButtonHLayout = QHBoxLayout()
                advancedButtonHLayout.addWidget(self.advancedButton)
                advancedButtonHLayout.addStretch()
                self.verticalLayout.addLayout(advancedButtonHLayout)
                break
        for param in self._alg.parameters:
            if param.hidden:
                continue
            desc = param.description
            if isinstance(param, ParameterExtent):
                desc += self.tr('(xmin, xmax, ymin, ymax)')
            if isinstance(param, ParameterPoint):
                desc += self.tr('(x, y)')
            label = QLabel(desc)
            self.labels[param.name] = label
            widget = self.getWidgetFromParameter(param)
            self.valueItems[param.name] = widget
            if param.name in tooltips.keys():
                tooltip = tooltips[param.name]
            else:
                tooltip = param.description
            label.setToolTip(tooltip)
            widget.setToolTip(tooltip)
            if param.isAdvanced:
                label.setVisible(self.showAdvanced)
                widget.setVisible(self.showAdvanced)
                self.widgets[param.name] = widget
            self.verticalLayout.addWidget(label)
            self.verticalLayout.addWidget(widget)

        for output in self._alg.outputs:
            if output.hidden:
                continue
            if isinstance(output, (OutputRaster, OutputVector, OutputTable,
                                   OutputHTML, OutputFile, OutputDirectory)):
                label = QLabel(output.description + '<' +
                               output.__class__.__name__ + '>')
                item = QLineEdit()
                if hasattr(item, 'setPlaceholderText'):
                    item.setPlaceholderText(ModelerParametersDialog.ENTER_NAME)
                self.verticalLayout.addWidget(label)
                self.verticalLayout.addWidget(item)
                self.valueItems[output.name] = item

        label = QLabel(' ')
        self.verticalLayout.addWidget(label)
        label = QLabel(self.tr('Parent algorithms'))
        self.dependenciesPanel = self.getDependenciesPanel()
        self.verticalLayout.addWidget(label)
        self.verticalLayout.addWidget(self.dependenciesPanel)

        self.verticalLayout.addStretch(1000)
        self.setLayout(self.verticalLayout)

        self.setPreviousValues()
        self.setWindowTitle(self._alg.name)
        self.verticalLayout2 = QVBoxLayout()
        self.verticalLayout2.setSpacing(2)
        self.verticalLayout2.setMargin(0)
        self.tabWidget = QTabWidget()
        self.tabWidget.setMinimumWidth(300)
        self.paramPanel = QWidget()
        self.paramPanel.setLayout(self.verticalLayout)
        self.scrollArea = QScrollArea()
        self.scrollArea.setWidget(self.paramPanel)
        self.scrollArea.setWidgetResizable(True)
        self.tabWidget.addTab(self.scrollArea, self.tr('Parameters'))

        self.txtHelp = QTextBrowser()

        html = None
        isText, algHelp = self._alg.help()
        if algHelp is not None:
            algHelp = algHelp if isText else QUrl(algHelp)
            try:
                if isText:
                    self.txtHelp.setHtml(algHelp)
                else:
                    html = self.tr(
                        '<p>Downloading algorithm help... Please wait.</p>')
                    self.txtHelp.setHtml(html)
                    self.reply = QgsNetworkAccessManager.instance().get(
                        QNetworkRequest(algHelp))
                    self.reply.finished.connect(self.requestFinished)
            except:
                self.txtHelp.setHtml(
                    self.tr('<h2>No help available for this algorithm</h2>'))

        self.tabWidget.addTab(self.txtHelp, 'Help')

        self.verticalLayout2.addWidget(self.tabWidget)
        self.verticalLayout2.addWidget(self.buttonBox)
        self.setLayout(self.verticalLayout2)
        self.buttonBox.accepted.connect(self.okPressed)
        self.buttonBox.rejected.connect(self.cancelPressed)
        QMetaObject.connectSlotsByName(self)

    def requestFinished(self):
        """Change the webview HTML content"""
        reply = self.sender()
        if reply.error() != QNetworkReply.NoError:
            html = self.tr(
                '<h2>No help available for this algorithm</h2><p>{}</p>'.
                format(reply.errorString()))
        else:
            html = unicode(reply.readAll())
        reply.deleteLater()
        self.txtHelp.setHtml(html)

    def getAvailableDependencies(self):
        if self._algName is None:
            dependent = []
        else:
            dependent = self.model.getDependentAlgorithms(self._algName)
        opts = []
        for alg in self.model.algs.values():
            if alg.name not in dependent:
                opts.append(alg)
        return opts

    def getDependenciesPanel(self):
        return MultipleInputPanel(
            [alg.algorithm.name for alg in self.getAvailableDependencies()])

    def showAdvancedParametersClicked(self):
        self.showAdvanced = not self.showAdvanced
        if self.showAdvanced:
            self.advancedButton.setText(self.tr('Hide advanced parameters'))
        else:
            self.advancedButton.setText(self.tr('Show advanced parameters'))
        for param in self._alg.parameters:
            if param.isAdvanced:
                self.labels[param.name].setVisible(self.showAdvanced)
                self.widgets[param.name].setVisible(self.showAdvanced)

    def getAvailableValuesOfType(self, paramType, outType=None):
        values = []
        inputs = self.model.inputs
        for i in inputs.values():
            param = i.param
            if isinstance(param, paramType):
                values.append(ValueFromInput(param.name))
        if outType is None:
            return values
        if self._algName is None:
            dependent = []
        else:
            dependent = self.model.getDependentAlgorithms(self._algName)
        for alg in self.model.algs.values():
            if alg.name not in dependent:
                for out in alg.algorithm.outputs:
                    if isinstance(out, outType):
                        values.append(ValueFromOutput(alg.name, out.name))

        return values

    def resolveValueDescription(self, value):
        if isinstance(value, ValueFromInput):
            return self.model.inputs[value.name].param.description
        else:
            alg = self.model.algs[value.alg]
            return self.tr("'%s' from algorithm '%s'") % (
                alg.algorithm.getOutputFromName(
                    value.output).description, alg.description)

    def getWidgetFromParameter(self, param):
        if isinstance(param, ParameterRaster):
            item = QComboBox()
            layers = self.getAvailableValuesOfType(ParameterRaster,
                                                   OutputRaster)
            if param.optional:
                item.addItem(self.NOT_SELECTED, None)
            for layer in layers:
                item.addItem(self.resolveValueDescription(layer), layer)
        elif isinstance(param, ParameterVector):
            item = QComboBox()
            layers = self.getAvailableValuesOfType(ParameterVector,
                                                   OutputVector)
            if param.optional:
                item.addItem(self.NOT_SELECTED, None)
            for layer in layers:
                item.addItem(self.resolveValueDescription(layer), layer)
        elif isinstance(param, ParameterTable):
            item = QComboBox()
            tables = self.getAvailableValuesOfType(ParameterTable, OutputTable)
            layers = self.getAvailableValuesOfType(ParameterVector,
                                                   OutputVector)
            if param.optional:
                item.addItem(self.NOT_SELECTED, None)
            for table in tables:
                item.addItem(self.resolveValueDescription(table), table)
            for layer in layers:
                item.addItem(self.resolveValueDescription(layer), layer)
        elif isinstance(param, ParameterBoolean):
            item = QComboBox()
            item.addItem('Yes')
            item.addItem('No')
            bools = self.getAvailableValuesOfType(ParameterBoolean, None)
            for b in bools:
                item.addItem(self.resolveValueDescription(b), b)
            if param.default:
                item.setCurrentIndex(0)
            else:
                item.setCurrentIndex(1)
        elif isinstance(param, ParameterSelection):
            item = QComboBox()
            item.addItems(param.options)
            item.setCurrentIndex(param.default or 0)
        elif isinstance(param, ParameterFixedTable):
            item = FixedTablePanel(param)
        elif isinstance(param, ParameterRange):
            item = RangePanel(param)
        elif isinstance(param, ParameterMultipleInput):
            if param.datatype == ParameterMultipleInput.TYPE_VECTOR_ANY:
                options = self.getAvailableValuesOfType(
                    ParameterVector, OutputVector)
            else:
                options = self.getAvailableValuesOfType(
                    ParameterRaster, OutputRaster)
            opts = []
            for opt in options:
                opts.append(self.resolveValueDescription(opt))
            item = MultipleInputPanel(opts)
        elif isinstance(param, ParameterString):
            strings = self.getAvailableValuesOfType(ParameterString,
                                                    OutputString)
            options = [(self.resolveValueDescription(s), s) for s in strings]
            if param.multiline:
                item = MultilineTextPanel(options)
                item.setText(unicode(param.default or ""))
            else:
                item = QComboBox()
                item.setEditable(True)
                for desc, val in options:
                    item.addItem(desc, val)
                item.setEditText(unicode(param.default or ""))
        elif isinstance(param, ParameterTableField):
            item = QComboBox()
            item.setEditable(True)
            fields = self.getAvailableValuesOfType(ParameterTableField, None)
            for f in fields:
                item.addItem(self.resolveValueDescription(f), f)
        elif isinstance(param, ParameterTableMultipleField):
            item = QComboBox()
            item.setEditable(True)
            fields = self.getAvailableValuesOfType(ParameterTableMultipleField,
                                                   None)
            for f in fields:
                item.addItem(self.resolveValueDescription(f), f)
        elif isinstance(param, ParameterNumber):
            item = QComboBox()
            item.setEditable(True)
            numbers = self.getAvailableValuesOfType(ParameterNumber,
                                                    OutputNumber)
            for n in numbers:
                item.addItem(self.resolveValueDescription(n), n)
            item.setEditText(unicode(param.default))
        elif isinstance(param, ParameterCrs):
            item = CrsSelectionPanel(param.default)
        elif isinstance(param, ParameterExtent):
            item = QComboBox()
            item.setEditable(True)
            extents = self.getAvailableValuesOfType(ParameterExtent,
                                                    OutputExtent)
            if self.canUseAutoExtent():
                item.addItem(self.USE_MIN_COVERING_EXTENT, None)
            for ex in extents:
                item.addItem(self.resolveValueDescription(ex), ex)
            if not self.canUseAutoExtent():
                item.setEditText(unicode(param.default))
        elif isinstance(param, ParameterPoint):
            item = QComboBox()
            item.setEditable(True)
            points = self.getAvailableValuesOfType(ParameterPoint)
            for p in points:
                item.addItem(self.resolveValueDescription(p), p)
            item.setEditText(unicode(param.default))
        elif isinstance(param, ParameterFile):
            item = QComboBox()
            item.setEditable(True)
            files = self.getAvailableValuesOfType(ParameterFile, OutputFile)
            for f in files:
                item.addItem(self.resolveValueDescription(f), f)
        elif isinstance(param, ParameterGeometryPredicate):
            item = GeometryPredicateSelectionPanel(param.enabledPredicates)
        else:
            item = QLineEdit()
            try:
                item.setText(unicode(param.default))
            except:
                pass
        return item

    def canUseAutoExtent(self):
        for param in self._alg.parameters:
            if isinstance(
                    param,
                (ParameterRaster, ParameterVector, ParameterMultipleInput)):
                return True
        return False

    def setTableContent(self):
        params = self._alg.parameters
        outputs = self._alg.outputs
        visibleParams = [p for p in params if not p.hidden]
        visibleOutputs = [p for o in outputs if not o.hidden]
        self.tableWidget.setRowCount(len(visibleParams) + len(visibleOutputs))

        for i, param in visibleParams:
            item = QTableWidgetItem(param.description)
            item.setFlags(Qt.ItemIsEnabled)
            self.tableWidget.setItem(i, 0, item)
            item = self.getWidgetFromParameter(param)
            self.valueItems[param.name] = item
            self.tableWidget.setCellWidget(i, 1, item)
            self.tableWidget.setRowHeight(i, 22)

        for i, output in visibleOutputs:
            item = QTableWidgetItem(output.description + '<' +
                                    output.__module__.split('.')[-1] + '>')
            item.setFlags(Qt.ItemIsEnabled)
            self.tableWidget.setItem(i, 0, item)
            item = QLineEdit()
            if hasattr(item, 'setPlaceholderText'):
                item.setPlaceholderText(ModelerParametersDialog.ENTER_NAME)
            self.valueItems[output.name] = item
            self.tableWidget.setCellWidget(i, 1, item)
            self.tableWidget.setRowHeight(i, 22)

    def setComboBoxValue(self, combo, value, param):
        if isinstance(value, list):
            value = value[0]
        items = [combo.itemData(i) for i in range(combo.count())]
        try:
            idx = items.index(value)
            combo.setCurrentIndex(idx)
            return
        except ValueError:
            pass
        if combo.isEditable():
            if value is not None:
                combo.setEditText(unicode(value))
        elif isinstance(param, ParameterSelection):
            combo.setCurrentIndex(int(value))
        elif isinstance(param, ParameterBoolean):
            if value:
                combo.setCurrentIndex(0)
            else:
                combo.setCurrentIndex(1)

    def setPreviousValues(self):
        if self._algName is not None:
            alg = self.model.algs[self._algName]
            self.descriptionBox.setText(alg.description)
            for param in alg.algorithm.parameters:
                if param.hidden:
                    continue
                widget = self.valueItems[param.name]
                if param.name in alg.params:
                    value = alg.params[param.name]
                else:
                    value = param.default
                if isinstance(
                        param,
                    (ParameterRaster, ParameterVector, ParameterTable,
                     ParameterTableField, ParameterSelection, ParameterNumber,
                     ParameterBoolean, ParameterExtent, ParameterFile,
                     ParameterPoint)):
                    self.setComboBoxValue(widget, value, param)
                elif isinstance(param, ParameterString):
                    if param.multiline:
                        widget.setValue(value)
                    else:
                        self.setComboBoxValue(widget, value, param)
                elif isinstance(param, ParameterCrs):
                    widget.setAuthId(value)
                elif isinstance(param, ParameterFixedTable):
                    pass  # TODO!
                elif isinstance(param, ParameterMultipleInput):
                    if param.datatype == ParameterMultipleInput.TYPE_VECTOR_ANY:
                        options = self.getAvailableValuesOfType(
                            ParameterVector, OutputVector)
                    else:
                        options = self.getAvailableValuesOfType(
                            ParameterRaster, OutputRaster)
                    selected = []
                    for i, opt in enumerate(options):
                        if opt in value:
                            selected.append(i)
                    widget.setSelectedItems(selected)
                elif isinstance(param, ParameterGeometryPredicate):
                    widget.setValue(value)

            for name, out in alg.outputs.iteritems():
                widget = self.valueItems[name].setText(out.description)

            selected = []
            dependencies = self.getAvailableDependencies()
            for idx, dependency in enumerate(dependencies):
                if dependency.name in alg.dependencies:
                    selected.append(idx)

            self.dependenciesPanel.setSelectedItems(selected)

    def createAlgorithm(self):
        alg = Algorithm(self._alg.commandLineName())
        alg.setName(self.model)
        alg.description = self.descriptionBox.text()
        params = self._alg.parameters
        outputs = self._alg.outputs
        for param in params:
            if param.hidden:
                continue
            if not self.setParamValue(alg, param, self.valueItems[param.name]):
                self.bar.pushMessage(
                    "Error",
                    "Wrong or missing value for parameter '%s'" %
                    param.description,
                    level=QgsMessageBar.WARNING)
                return None
        for output in outputs:
            if not output.hidden:
                name = unicode(self.valueItems[output.name].text())
                if name.strip(
                ) != '' and name != ModelerParametersDialog.ENTER_NAME:
                    alg.outputs[output.name] = ModelerOutput(name)

        selectedOptions = self.dependenciesPanel.selectedoptions
        availableDependencies = self.getAvailableDependencies()
        for selected in selectedOptions:
            alg.dependencies.append(availableDependencies[selected].name)

        return alg

    def setParamValueLayerOrTable(self, alg, param, widget):
        idx = widget.currentIndex()
        if idx < 0:
            return False
        else:
            value = widget.itemData(widget.currentIndex())
            alg.params[param.name] = value
            return True

    def setParamTableFieldValue(self, alg, param, widget):
        idx = widget.findText(widget.currentText())
        if idx < 0:
            s = unicode(widget.currentText()).strip()
            if s == '':
                if param.optional:
                    alg.params[param.name] = None
                    return True
                else:
                    return False
            else:
                alg.params[param.name] = s
                return True
        else:
            alg.params[param.name] = widget.itemData(widget.currentIndex())
        return True

    def setParamStringValue(self, alg, param, widget):
        if param.multiline:
            value = widget.getValue()
            option = widget.getOption()
            if option == MultilineTextPanel.USE_TEXT:
                if value == '':
                    if param.optional:
                        alg.params[param.name] = None
                        return True
                    else:
                        return False
                else:
                    alg.params[param.name] = value
            else:
                alg.params[param.name] = value
        else:
            idx = widget.findText(widget.currentText())
            if idx < 0:
                value = widget.currentText().strip()
                if value == '':
                    if param.optional:
                        alg.params[param.name] = None
                        return True
                    else:
                        return False
                else:
                    alg.params[param.name] = value
            else:
                alg.params[param.name] = widget.itemData(widget.currentIndex())
        return True

    def setParamFileValue(self, alg, param, widget):
        idx = widget.findText(widget.currentText())
        if idx < 0:
            value = widget.currentText()
        else:
            value = widget.itemData(widget.currentIndex())
        alg.params[param.name] = value
        return True

    def setParamNumberValue(self, alg, param, widget):
        idx = widget.findText(widget.currentText())
        if idx < 0:
            s = widget.currentText().strip()
            if s:
                try:
                    value = float(s)
                except:
                    return False
            elif param.optional:
                value = None
            else:
                return False
        else:
            value = widget.itemData(widget.currentIndex())
        alg.params[param.name] = value
        return True

    def setParamExtentValue(self, alg, param, widget):
        idx = widget.findText(widget.currentText())
        if idx < 0:
            s = unicode(widget.currentText()).strip()
            if s:
                try:
                    tokens = s.split(',')
                    if len(tokens) != 4:
                        return False
                    for token in tokens:
                        float(token)
                except:
                    return False
            elif param.optional:
                s = None
            else:
                return False
            alg.params[param.name] = [s]
        else:
            value = widget.itemData(widget.currentIndex())
            alg.params[param.name] = value
        return True

    def setParamPointValue(self, alg, param, widget):
        idx = widget.findText(widget.currentText())
        if idx < 0:
            s = unicode(widget.currentText()).strip()
            if s:
                try:
                    tokens = s.split(',')
                    if len(tokens) != 2:
                        return False
                    for token in tokens:
                        float(token)
                except:
                    return False
            elif param.optional:
                s = None
            else:
                return False
            alg.params[param.name] = [s]
        else:
            value = widget.itemData(widget.currentIndex())
            alg.params[param.name] = value
        return True

    def setParamValue(self, alg, param, widget):
        if isinstance(param,
                      (ParameterRaster, ParameterVector, ParameterTable)):
            return self.setParamValueLayerOrTable(alg, param, widget)
        elif isinstance(param, ParameterBoolean):
            if widget.currentIndex() < 2:
                value = widget.currentIndex() == 0
            else:
                value = widget.itemData(widget.currentIndex())
            alg.params[param.name] = value
            return True
        elif isinstance(param, ParameterString):
            return self.setParamStringValue(alg, param, widget)
        elif isinstance(param, ParameterNumber):
            return self.setParamNumberValue(alg, param, widget)
        elif isinstance(param, ParameterExtent):
            return self.setParamExtentValue(alg, param, widget)
        elif isinstance(param, ParameterPoint):
            return self.setParamPointValue(alg, param, widget)
        elif isinstance(param, ParameterFile):
            return self.setParamFileValue(alg, param, widget)
        elif isinstance(param, ParameterSelection):
            alg.params[param.name] = widget.currentIndex()
            return True
        elif isinstance(param, ParameterRange):
            alg.params[param.name] = widget.getValue()
            return True
        elif isinstance(param, ParameterCrs):
            authid = widget.getValue()
            if authid is None and not param.optional:
                return False
            alg.params[param.name] = authid
            return True
        elif isinstance(param, ParameterFixedTable):
            table = widget.table
            if not bool(table) and not param.optional:
                return False
            alg.params[param.name] = ParameterFixedTable.tableToString(table)
            return True
        elif isinstance(param,
                        (ParameterTableField, ParameterTableMultipleField)):
            return self.setParamTableFieldValue(alg, param, widget)
        elif isinstance(param, ParameterMultipleInput):
            if param.datatype == ParameterMultipleInput.TYPE_VECTOR_ANY:
                options = self.getAvailableValuesOfType(
                    ParameterVector, OutputVector)
            else:
                options = self.getAvailableValuesOfType(
                    ParameterRaster, OutputRaster)
            values = [options[i] for i in widget.selectedoptions]
            if len(values) == 0 and not param.optional:
                return False
            alg.params[param.name] = values
            return True
        elif isinstance(param, ParameterGeometryPredicate):
            alg.params[param.name] = widget.value()
            return True
        else:
            alg.params[param.name] = unicode(widget.text())
            return True

    def okPressed(self):
        self.alg = self.createAlgorithm()
        if self.alg is not None:
            self.close()

    def cancelPressed(self):
        self.alg = None
        self.close()
Example #2
0
class OptionsDialog(QDialog, FORM_CLASS):

    """Options dialog for the InaSAFE plugin."""

    def __init__(self, iface, parent=None, qsetting=''):
        """Constructor for the dialog.

        :param iface: A Quantum GIS QgisAppInterface instance.
        :type iface: QgisAppInterface

        :param parent: Parent widget of this dialog
        :type parent: QWidget

        :param qsetting: String to specify the QSettings. By default,
            use empty string.
        :type qsetting: str
        """
        QDialog.__init__(self, parent)
        self.setupUi(self)
        icon = resources_path('img', 'icons', 'configure-inasafe.svg')
        self.setWindowIcon(QIcon(icon))
        self.setWindowTitle(self.tr('InaSAFE %s Options' % get_version()))
        # Save reference to the QGIS interface and parent
        self.iface = iface
        self.parent = parent
        if qsetting:
            self.settings = QSettings(qsetting)
        else:
            self.settings = QSettings()

        # InaSAFE default values
        self.default_value_parameters = []
        self.default_value_parameter_containers = []

        # Flag for restore default values
        self.is_restore_default = False

        # List of setting key and control
        self.boolean_settings = {
            'visibleLayersOnlyFlag': self.cbxVisibleLayersOnly,
            'set_layer_from_title_flag': self.cbxSetLayerNameFromTitle,
            'setZoomToImpactFlag': self.cbxZoomToImpact,
            'set_show_only_impact_on_report': self.cbx_show_only_impact,
            'print_atlas_report': self.cbx_print_atlas_report,
            'setHideExposureFlag': self.cbxHideExposure,
            'useSelectedFeaturesOnly': self.cbxUseSelectedFeaturesOnly,
            'useSentry': self.cbxUseSentry,
            'template_warning_verbose': self.template_warning_checkbox,
            'showOrganisationLogoInDockFlag':
                self.organisation_on_dock_checkbox,
            'developer_mode': self.cbxDevMode,
            'generate_report': self.checkbox_generate_reports,
            'memory_profile': self.check_box_memory,
            'always_show_welcome_message': self.welcome_message_check_box
        }
        self.text_settings = {
            'keywordCachePath': self.leKeywordCachePath,
            'ISO19115_ORGANIZATION': self.organisation_line_edit,
            'ISO19115_URL': self.website_line_edit,
            'ISO19115_EMAIL': self.email_line_edit,
            'ISO19115_LICENSE': self.license_line_edit,
        }

        # Export and Import button
        # Export button
        self.export_button = QPushButton(tr('Export'))
        # noinspection PyUnresolvedReferences
        self.export_button.clicked.connect(self.export_setting)
        self.button_box.addButton(
            self.export_button, QDialogButtonBox.ActionRole)
        # Import button
        self.import_button = QPushButton(tr('Import'))
        # noinspection PyUnresolvedReferences
        self.import_button.clicked.connect(self.import_setting)
        self.button_box.addButton(
            self.import_button, QDialogButtonBox.ActionRole)

        # Set up things for context help
        self.help_button = self.button_box.button(QDialogButtonBox.Help)
        # Allow toggling the help button
        self.help_button.setCheckable(True)
        self.help_button.toggled.connect(self.help_toggled)
        self.main_stacked_widget.setCurrentIndex(1)

        # Always set first tab to be open, 0-th index
        self.tabWidget.setCurrentIndex(0)

        # Hide not implemented group
        self.grpNotImplemented.hide()
        self.adjustSize()

        # Population parameter Tab
        # Label
        self.preference_label = QLabel()
        self.preference_label.setText(tr(
            'Please set parameters for each hazard class below. Affected '
            'status and displacement rates selected on this tab are only '
            'applied to exposed populations. '
        ))
        self.preference_layout.addWidget(self.preference_label)

        # Profile preference widget
        self.profile_widget = ProfileWidget()
        self.preference_layout.addWidget(self.profile_widget)

        # Demographic tab
        self.demographic_label = QLabel()
        self.demographic_label.setText(tr(
            'Please set the global default demographic ratio below.'))
        self.default_values_layout.addWidget(self.demographic_label)
        self.scroll_area = QScrollArea()
        self.scroll_area.setWidgetResizable(True)
        self.widget_container = QWidget()
        self.scroll_area.setWidget(self.widget_container)
        self.container_layout = QVBoxLayout()
        self.widget_container.setLayout(self.container_layout)
        self.default_values_layout.addWidget(self.scroll_area)

        # Restore state from setting
        self.restore_state()

        # Hide checkbox if not developers
        if not self.cbxDevMode.isChecked():
            self.checkbox_generate_reports.hide()

        # Connections
        # Check boxes
        self.custom_north_arrow_checkbox.toggled.connect(self.set_north_arrow)
        self.custom_UseUserDirectory_checkbox.toggled.connect(
            self.set_user_dir)
        self.custom_templates_dir_checkbox.toggled.connect(
            self.set_templates_dir)
        self.custom_org_disclaimer_checkbox.toggled.connect(
            self.set_org_disclaimer)
        self.custom_organisation_logo_check_box.toggled.connect(
            self.toggle_logo_path)
        # Buttons
        self.toolKeywordCachePath.clicked.connect(self.open_keyword_cache_path)
        self.toolUserDirectoryPath.clicked.connect(
            self.open_user_directory_path)
        self.toolNorthArrowPath.clicked.connect(self.open_north_arrow_path)
        self.open_organisation_logo_path_button.clicked.connect(
            self.open_organisation_logo_path)
        self.toolReportTemplatePath.clicked.connect(
            self.open_report_template_path)
        # Others
        self.organisation_logo_path_line_edit.textChanged.connect(
            self.update_logo_preview)
        self.earthquake_function.currentIndexChanged.connect(
            self.update_earthquake_info)

        # Set up listener for restore defaults button
        self.demographic_restore_defaults = self.button_box_restore_defaults.\
            button(QDialogButtonBox.RestoreDefaults)
        self.demographic_restore_defaults.setText(
            self.demographic_restore_defaults.text().capitalize())
        self.demographic_restore_defaults.setCheckable(True)
        self.demographic_restore_defaults.clicked.connect(
            self.restore_defaults_ratio)

        # Restore button in population parameter tab
        self.parameter_population_restore_button = \
            self.button_box_restore_preference.button(
                QDialogButtonBox.RestoreDefaults)
        self.parameter_population_restore_button.setText(
            self.parameter_population_restore_button.text().capitalize())

        self.parameter_population_restore_button.clicked.connect(
            partial(self.restore_population_parameters, global_default=True))

        # TODO: Hide this until behaviour is defined
        # hide template warning toggle
        self.template_warning_checkbox.hide()

        # hide custom template dir toggle
        self.custom_templates_dir_checkbox.hide()
        self.splitter_custom_report.hide()

        # Welcome message
        self.set_welcome_message()

    def save_boolean_setting(self, key, check_box):
        """Save boolean setting according to check_box state.

        :param key: Key to retrieve setting value.
        :type key: str

        :param check_box: Check box to show and set the setting.
        :type check_box: PyQt5.QtWidgets.QCheckBox.QCheckBox
        """
        set_setting(key, check_box.isChecked(), qsettings=self.settings)

    def restore_boolean_setting(self, key, check_box):
        """Set check_box according to setting of key.

        :param key: Key to retrieve setting value.
        :type key: str

        :param check_box: Check box to show and set the setting.
        :type check_box: PyQt5.QtWidgets.QCheckBox.QCheckBox
        """
        flag = setting(key, expected_type=bool, qsettings=self.settings)
        check_box.setChecked(flag)

    def save_text_setting(self, key, line_edit):
        """Save text setting according to line_edit value.

        :param key: Key to retrieve setting value.
        :type key: str

        :param line_edit: Line edit for user to edit the setting
        :type line_edit: PyQt5.QtWidgets.QLineEdit.QLineEdit
        """
        set_setting(key, line_edit.text(), self.settings)

    def restore_text_setting(self, key, line_edit):
        """Set line_edit text according to setting of key.

        :param key: Key to retrieve setting value.
        :type key: str

        :param line_edit: Line edit for user to edit the setting
        :type line_edit: PyQt5.QtWidgets.QLineEdit.QLineEdit
        """
        value = setting(key, expected_type=str, qsettings=self.settings)
        line_edit.setText(value)

    def restore_state(self):
        """Reinstate the options based on the user's stored session info."""
        # Restore boolean setting as check box.
        for key, check_box in list(self.boolean_settings.items()):
            self.restore_boolean_setting(key, check_box)

        # Restore text setting as line edit.
        for key, line_edit in list(self.text_settings.items()):
            self.restore_text_setting(key, line_edit)

        # User Directory
        user_directory_path = setting(
            key='defaultUserDirectory',
            default=temp_dir('impacts'),
            expected_type=str,
            qsettings=self.settings)
        custom_user_directory_flag = (
            user_directory_path != temp_dir('impacts'))
        self.custom_UseUserDirectory_checkbox.setChecked(
            custom_user_directory_flag)
        self.splitter_user_directory.setEnabled(custom_user_directory_flag)
        self.leUserDirectoryPath.setText(user_directory_path)

        # Currency
        # Populate the currency list
        for currency in currencies:
            self.currency_combo_box.addItem(currency['name'], currency['key'])

        # Then make selected the default one.
        default_currency = setting('currency', expected_type=str)
        keys = [currency['key'] for currency in currencies]
        if default_currency not in keys:
            default_currency = currencies[0]['key']
        index = self.currency_combo_box.findData(default_currency)
        self.currency_combo_box.setCurrentIndex(index)

        # Earthquake function.
        # Populate the combobox first.
        for model in EARTHQUAKE_FUNCTIONS:
            self.earthquake_function.addItem(model['name'], model['key'])

        # Then make selected the default one.
        default_earthquake_function = setting(
            'earthquake_function', expected_type=str)
        keys = [model['key'] for model in EARTHQUAKE_FUNCTIONS]
        if default_earthquake_function not in keys:
            default_earthquake_function = EARTHQUAKE_FUNCTIONS[0]['key']
        index = self.earthquake_function.findData(default_earthquake_function)
        self.earthquake_function.setCurrentIndex(index)
        self.update_earthquake_info()

        # Restore North Arrow Image Path
        north_arrow_path = setting(
            key='north_arrow_path',
            default=default_north_arrow_path(),
            expected_type=str,
            qsettings=self.settings)
        custom_north_arrow_flag = (
            north_arrow_path != default_north_arrow_path())
        self.custom_north_arrow_checkbox.setChecked(custom_north_arrow_flag)
        self.splitter_north_arrow.setEnabled(custom_north_arrow_flag)
        self.leNorthArrowPath.setText(north_arrow_path)

        # Restore Report Template Directory Path
        report_template_directory = setting(
            key='reportTemplatePath',
            default='',
            expected_type=str,
            qsettings=self.settings)
        custom_templates_dir_flag = (report_template_directory != '')
        self.custom_templates_dir_checkbox.setChecked(
            custom_templates_dir_flag)
        self.leReportTemplatePath.setText(report_template_directory)

        # Restore Disclaimer
        org_disclaimer = setting(
            key='reportDisclaimer',
            default=disclaimer(),
            expected_type=str,
            qsettings=self.settings)
        custom_org_disclaimer_flag = (org_disclaimer != disclaimer())
        self.custom_org_disclaimer_checkbox.setChecked(
            custom_org_disclaimer_flag)
        self.txtDisclaimer.setPlainText(org_disclaimer)

        # Restore Organisation Logo Path
        org_logo_path = setting(
            key='organisation_logo_path',
            default=supporters_logo_path(),
            expected_type=str,
            qsettings=self.settings)
        # Check if the path is default one or not
        custom_org_logo_flag = org_logo_path != supporters_logo_path()
        self.organisation_logo_path_line_edit.setText(org_logo_path)
        self.custom_organisation_logo_check_box.setChecked(
            custom_org_logo_flag)
        self.organisation_logo_path_line_edit.setEnabled(
            custom_org_logo_flag)
        self.open_organisation_logo_path_button.setEnabled(
            custom_org_logo_flag)
        # Manually call here
        self.update_logo_preview()

        # Restore InaSAFE default values
        self.restore_default_values_page()

        # Restore Population Parameter
        self.restore_population_parameters(global_default=False)

    def save_state(self):
        """Store the options into the user's stored session info."""
        # Save boolean settings
        for key, check_box in list(self.boolean_settings.items()):
            self.save_boolean_setting(key, check_box)
        # Save text settings
        for key, line_edit in list(self.text_settings.items()):
            self.save_text_setting(key, line_edit)

        set_setting(
            'north_arrow_path', self.leNorthArrowPath.text(), self.settings)
        set_setting(
            'organisation_logo_path',
            self.organisation_logo_path_line_edit.text(),
            self.settings)
        set_setting(
            'reportTemplatePath',
            self.leReportTemplatePath.text(),
            self.settings)
        set_setting(
            'reportDisclaimer',
            self.txtDisclaimer.toPlainText(),
            self.settings)
        set_setting(
            'defaultUserDirectory',
            self.leUserDirectoryPath.text(),
            self.settings)
        index = self.earthquake_function.currentIndex()
        value = self.earthquake_function.itemData(index)
        set_setting('earthquake_function', value, qsettings=self.settings)

        currency_index = self.currency_combo_box.currentIndex()
        currency_key = self.currency_combo_box.itemData(currency_index)
        set_setting('currency', currency_key, qsettings=self.settings)

        # Save InaSAFE default values
        self.save_default_values()

        # Save population parameters
        self.save_population_parameters()

    def accept(self):
        """Method invoked when OK button is clicked."""
        self.save_state()
        super(OptionsDialog, self).accept()

    def update_earthquake_info(self):
        """Update information about earthquake info."""
        self.label_earthquake_model()
        current_index = self.earthquake_function.currentIndex()
        model = EARTHQUAKE_FUNCTIONS[current_index]
        notes = ''
        for note in model['notes']:
            notes += note + '\n\n'

        citations = ''
        for citation in model['citations']:
            citations += citation['text'] + '\n\n'

        text = tr(
            'Description:\n\n%s\n\n'
            'Notes:\n\n%s\n\n'
            'Citations:\n\n%s') % (
            model['description'],
            notes,
            citations)

        self.earthquake_fatality_model_notes.setText(text)

    def label_earthquake_model(self):
        model = self.earthquake_function.currentText()
        help_text = tr(
            'Please select your preferred earthquake fatality model. The '
            'default fatality model is the {model}.').format(model=model)
        self.label_default_earthquake.setText(help_text)

    def open_keyword_cache_path(self):
        """Open File dialog to choose the keyword cache path."""
        # noinspection PyCallByClass,PyTypeChecker
        file_name, __ = QFileDialog.getSaveFileName(
            self,
            self.tr('Set keyword cache file'),
            self.leKeywordCachePath.text(),
            self.tr('Sqlite DB File (*.db)'))
        if file_name:
            self.leKeywordCachePath.setText(file_name)

    def open_user_directory_path(self):
        """Open File dialog to choose the user directory path."""
        # noinspection PyCallByClass,PyTypeChecker
        directory_name = QFileDialog.getExistingDirectory(
            self,
            self.tr('Results directory'),
            self.leUserDirectoryPath.text(),
            QFileDialog.ShowDirsOnly)
        if directory_name:
            self.leUserDirectoryPath.setText(directory_name)

    def open_north_arrow_path(self):
        """Open File dialog to choose the north arrow path."""
        # noinspection PyCallByClass,PyTypeChecker
        file_name, __ = QFileDialog.getOpenFileName(
            self,
            self.tr('Set north arrow image file'),
            self.leNorthArrowPath.text(),
            self.tr(
                'Portable Network Graphics files (*.png *.PNG);;'
                'JPEG Images (*.jpg *.jpeg);;'
                'GIF Images (*.gif *.GIF);;'
                'SVG Images (*.svg *.SVG);;'))
        if file_name:
            self.leNorthArrowPath.setText(file_name)

    def open_organisation_logo_path(self):
        """Open File dialog to choose the organisation logo path."""
        # noinspection PyCallByClass,PyTypeChecker
        file_name, __ = QFileDialog.getOpenFileName(
            self,
            self.tr('Set organisation logo file'),
            self.organisation_logo_path_line_edit.text(),
            self.tr(
                'Portable Network Graphics files (*.png *.PNG);;'
                'JPEG Images (*.jpg *.jpeg);;'
                'GIF Images (*.gif *.GIF);;'
                'SVG Images (*.svg *.SVG);;'))
        if file_name:
            self.organisation_logo_path_line_edit.setText(file_name)

    def open_report_template_path(self):
        """Open File dialog to choose the report template path."""
        # noinspection PyCallByClass,PyTypeChecker
        directory_name = QFileDialog.getExistingDirectory(
            self,
            self.tr('Templates directory'),
            self.leReportTemplatePath.text(),
            QFileDialog.ShowDirsOnly)
        if directory_name:
            self.leReportTemplatePath.setText(directory_name)

    def toggle_logo_path(self):
        """Set state of logo path line edit and button."""
        is_checked = self.custom_organisation_logo_check_box.isChecked()
        if is_checked:
            # Use previous org logo path
            path = setting(
                key='organisation_logo_path',
                default=supporters_logo_path(),
                expected_type=str,
                qsettings=self.settings)
        else:
            # Set organisation path line edit to default one
            path = supporters_logo_path()

        self.organisation_logo_path_line_edit.setText(path)
        self.organisation_logo_path_line_edit.setEnabled(is_checked)
        self.open_organisation_logo_path_button.setEnabled(is_checked)

    def update_logo_preview(self):
        """Update logo based on the current logo path."""
        logo_path = self.organisation_logo_path_line_edit.text()
        if os.path.exists(logo_path):
            icon = QPixmap(logo_path)
            label_size = self.organisation_logo_label.size()
            label_size.setHeight(label_size.height() - 2)
            label_size.setWidth(label_size.width() - 2)
            scaled_icon = icon.scaled(
                label_size, Qt.KeepAspectRatio)
            self.organisation_logo_label.setPixmap(scaled_icon)
        else:
            self.organisation_logo_label.setText(tr("Logo not found"))

    def set_north_arrow(self):
        """Auto-connect slot activated when north arrow checkbox is toggled."""
        is_checked = self.custom_north_arrow_checkbox.isChecked()
        if is_checked:
            # Show previous north arrow path
            path = setting(
                key='north_arrow_path',
                default=default_north_arrow_path(),
                expected_type=str,
                qsettings=self.settings)
        else:
            # Set the north arrow line edit to default one
            path = default_north_arrow_path()

        self.leNorthArrowPath.setText(path)
        self.splitter_north_arrow.setEnabled(is_checked)

    def set_user_dir(self):
        """Auto-connect slot activated when user dir checkbox is toggled.
        """
        is_checked = self.custom_UseUserDirectory_checkbox.isChecked()
        if is_checked:
            # Show previous templates dir
            path = setting(
                key='defaultUserDirectory',
                default='',
                expected_type=str,
                qsettings=self.settings)
        else:
            # Set the template report dir to ''
            path = temp_dir('impacts')

        self.leUserDirectoryPath.setText(path)
        self.splitter_user_directory.setEnabled(is_checked)

    def set_templates_dir(self):
        """Auto-connect slot activated when templates dir checkbox is toggled.
        """
        is_checked = self.custom_templates_dir_checkbox.isChecked()
        if is_checked:
            # Show previous templates dir
            path = setting(
                key='reportTemplatePath',
                default='',
                expected_type=str,
                qsettings=self.settings)
        else:
            # Set the template report dir to ''
            path = ''

        self.leReportTemplatePath.setText(path)
        self.splitter_custom_report.setEnabled(is_checked)

    def set_org_disclaimer(self):
        """Auto-connect slot activated when org disclaimer checkbox is toggled.
        """
        is_checked = self.custom_org_disclaimer_checkbox.isChecked()
        if is_checked:
            # Show previous organisation disclaimer
            org_disclaimer = setting(
                'reportDisclaimer',
                default=disclaimer(),
                expected_type=str,
                qsettings=self.settings)
        else:
            # Set the organisation disclaimer to the default one
            org_disclaimer = disclaimer()

        self.txtDisclaimer.setPlainText(org_disclaimer)
        self.txtDisclaimer.setEnabled(is_checked)

    @pyqtSlot(bool)  # prevents actions being handled twice
    def help_toggled(self, flag):
        """Show or hide the help tab in the stacked widget.

        .. versionadded: 3.2.1

        :param flag: Flag indicating whether help should be shown or hidden.
        :type flag: bool
        """
        if flag:
            self.help_button.setText(self.tr('Hide Help'))
            self.show_help()
        else:
            self.help_button.setText(self.tr('Show Help'))
            self.hide_help()

    def hide_help(self):
        """Hide the usage info from the user.

        .. versionadded: 3.2.1
        """
        self.main_stacked_widget.setCurrentIndex(1)

    def show_help(self):
        """Show usage info to the user."""
        # Read the header and footer html snippets
        self.main_stacked_widget.setCurrentIndex(0)
        header = html_header()
        footer = html_footer()

        string = header

        message = options_help()

        string += message.to_html()
        string += footer

        self.help_web_view.setHtml(string)

    def restore_default_values_page(self):
        """Setup UI for default values setting."""
        # Clear parameters so it doesn't add parameters when
        # restore from changes.
        if self.default_value_parameters:
            self.default_value_parameters = []
        if self.default_value_parameter_containers:
            self.default_value_parameter_containers = []

        for i in reversed(list(range(self.container_layout.count()))):
            widget = self.container_layout.itemAt(i).widget()
            if widget is not None:
                widget.setParent(None)

        default_fields = all_default_fields()

        for field_group in all_field_groups:
            settable_fields = []
            for field in field_group['fields']:
                if field not in default_fields:
                    continue
                else:
                    settable_fields.append(field)
                    default_fields.remove(field)

            if not settable_fields:
                continue
            # Create group box for each field group
            group_box = QGroupBox(self)
            group_box.setTitle(field_group['name'])
            self.container_layout.addWidget(group_box)
            parameters = []
            for settable_field in settable_fields:
                parameter = self.default_field_to_parameter(settable_field)
                if parameter:
                    parameters.append(parameter)
            parameter_container = ParameterContainer(
                parameters,
                description_text=field_group['description'],
                extra_parameters=extra_parameter
            )
            parameter_container.setup_ui(must_scroll=False)
            group_box_inner_layout = QVBoxLayout()
            group_box_inner_layout.addWidget(parameter_container)
            group_box.setLayout(group_box_inner_layout)

            # Add to attribute
            self.default_value_parameter_containers.append(parameter_container)

        # Only show non-groups default fields if there is one
        if len(default_fields) > 0:
            for default_field in default_fields:
                parameter = self.default_field_to_parameter(default_field)
                if parameter:
                    self.default_value_parameters.append(parameter)

            description_text = tr(
                'In this options you can change the global default values for '
                'these variables.')
            parameter_container = ParameterContainer(
                self.default_value_parameters,
                description_text=description_text,
                extra_parameters=extra_parameter
            )
            parameter_container.setup_ui(must_scroll=False)
            self.other_group_box = QGroupBox(tr('Non-group fields'))
            other_group_inner_layout = QVBoxLayout()
            other_group_inner_layout.addWidget(parameter_container)
            self.other_group_box.setLayout(other_group_inner_layout)
            self.container_layout.addWidget(self.other_group_box)

            # Add to attribute
            self.default_value_parameter_containers.append(parameter_container)

    def restore_population_parameters(self, global_default=True):
        """Setup UI for population parameter page from setting.

        :param global_default: If True, set to original default (from
            the value in definitions).
        :type global_default: bool
        """
        if global_default:
            data = generate_default_profile()
        else:
            data = setting('population_preference', generate_default_profile())
        if not isinstance(data, dict):
            LOGGER.debug(
                'population parameter is not a dictionary. InaSAFE will use '
                'the default one.')
            data = generate_default_profile()
        try:
            self.profile_widget.data = data
        except KeyError as e:
            LOGGER.debug(
                'Population parameter is not in correct format. InaSAFE will '
                'use the default one.')
            LOGGER.debug(e)
            data = generate_default_profile()
            self.profile_widget.data = data

    @staticmethod
    def age_ratios():
        """Helper to get list of age ratio from the options dialog.

        :returns: List of age ratio.
        :rtype: list
        """
        # FIXME(IS) set a correct parameter container
        parameter_container = None

        youth_ratio = parameter_container.get_parameter_by_guid(
            youth_ratio_field['key']).value
        adult_ratio = parameter_container.get_parameter_by_guid(
            adult_ratio_field['key']).value
        elderly_ratio = parameter_container.get_parameter_by_guid(
            elderly_ratio_field['key']).value
        ratios = [youth_ratio, adult_ratio, elderly_ratio]

        return ratios

    def is_good_age_ratios(self):
        """Method to check the sum of age ratio is 1.

        :returns: True if the sum is 1 or the sum less than 1 but there is
            None.
        :rtype: bool
        """
        ratios = self.age_ratios()

        if None in ratios:
            # If there is None, just check to not exceeding 1
            clean_ratios = [x for x in ratios if x is not None]
            ratios.remove(None)
            if sum(clean_ratios) > 1:
                return False
        else:
            if sum(ratios) != 1:
                return False

        return True

    def save_default_values(self):
        """Save InaSAFE default values."""
        for parameter_container in self.default_value_parameter_containers:
            parameters = parameter_container.get_parameters()
            for parameter in parameters:
                set_inasafe_default_value_qsetting(
                    self.settings,
                    GLOBAL,
                    parameter.guid,
                    parameter.value
                )

    def restore_defaults_ratio(self):
        """Restore InaSAFE default ratio."""
        # Set the flag to true because user ask to.
        self.is_restore_default = True
        # remove current default ratio
        for i in reversed(list(range(self.container_layout.count()))):
            widget = self.container_layout.itemAt(i).widget()
            if widget is not None:
                widget.setParent(None)

        # reload default ratio
        self.restore_default_values_page()

    def default_field_to_parameter(self, default_field):
        """Obtain parameter from default field.

        :param default_field: A default field definition.
        :type default_field: dict

        :returns: A parameter object.
        :rtype: FloatParameter, IntegerParameter
        """
        if default_field.get('type') == QVariant.Double:
            parameter = FloatParameter()
        elif default_field.get('type') in qvariant_whole_numbers:
            parameter = IntegerParameter()
        else:
            return
        default_value = default_field.get('default_value')
        if not default_value:
            message = (
                'InaSAFE default field %s does not have default value'
                % default_field.get('name'))
            LOGGER.exception(message)
            return

        parameter.guid = default_field.get('key')
        parameter.name = default_value.get('name')
        parameter.is_required = True
        parameter.precision = default_field.get('precision')
        parameter.minimum_allowed_value = default_value.get(
            'min_value', 0)
        parameter.maximum_allowed_value = default_value.get(
            'max_value', 100000000)
        parameter.help_text = default_value.get('help_text')
        parameter.description = default_value.get('description')

        # Check if user ask to restore to the most default value.
        if self.is_restore_default:
            parameter._value = default_value.get('default_value')
        else:
            # Current value
            qsetting_default_value = get_inasafe_default_value_qsetting(
                self.settings, GLOBAL, default_field['key'])

            # To avoid python error
            if qsetting_default_value > parameter.maximum_allowed_value:
                qsetting_default_value = parameter.maximum_allowed_value
            if qsetting_default_value < parameter.minimum_allowed_value:
                qsetting_default_value = parameter.minimum_allowed_value

            parameter.value = qsetting_default_value
        return parameter

    def save_population_parameters(self):
        """Helper to save population parameter to QSettings."""
        population_parameter = self.profile_widget.data
        set_setting('population_preference', population_parameter)

    def set_welcome_message(self):
        """Create and insert welcome message."""
        string = html_header()
        string += welcome_message().to_html()
        string += html_footer()
        self.welcome_message.setHtml(string)

    def show_option_dialog(self):
        """Helper to show usual option dialog (without welcome message tab)."""
        self.tabWidget.removeTab(0)

    def show_welcome_dialog(self):
        """Setup for showing welcome message dialog.

        This method will setup several things:
        - Only show welcome, organisation profile, and population parameter
            tab. Currently, they are the first 3 tabs.
        - Set the title
        - Move the check box for always showing welcome message.
        """
        self.welcome_layout.addWidget(self.welcome_message_check_box)
        while self.tabWidget.count() > 3:
            self.tabWidget.removeTab(self.tabWidget.count() - 1)
        self.setWindowTitle(self.tr('Welcome to InaSAFE %s' % get_version()))
        # Hide the export import button
        self.export_button.hide()
        self.import_button.hide()

    def export_setting(self):
        """Export setting from an existing file."""
        LOGGER.debug('Export button clicked')
        home_directory = os.path.expanduser('~')
        file_name = self.organisation_line_edit.text().replace(' ', '_')
        file_path, __ = QFileDialog.getSaveFileName(
            self,
            self.tr('Export InaSAFE settings'),
            os.path.join(home_directory, file_name + '.json'),
            self.tr('JSON File (*.json)'))
        if file_path:
            LOGGER.debug('Exporting to %s' % file_path)
            export_setting(file_path)

    def import_setting(self):
        """Import setting to a file."""
        LOGGER.debug('Import button clicked')
        home_directory = os.path.expanduser('~')
        file_path, __ = QFileDialog.getOpenFileName(
            self,
            self.tr('Import InaSAFE settings'),
            home_directory,
            self.tr('JSON File (*.json)'))
        if file_path:
            title = tr('Import InaSAFE Settings.')
            question = tr(
                'This action will replace your current InaSAFE settings with '
                'the setting from the file. This action is not reversible. '
                'Are you sure to import InaSAFE Setting?')
            answer = QMessageBox.question(
                self, title, question, QMessageBox.Yes | QMessageBox.No)
            if answer == QMessageBox.Yes:
                LOGGER.debug('Import from %s' % file_path)
                import_setting(file_path)
Example #3
0
    def __init__(self, iface, parent=None, qsetting=''):
        """Constructor for the dialog.

        :param iface: A Quantum GIS QgisAppInterface instance.
        :type iface: QgisAppInterface

        :param parent: Parent widget of this dialog
        :type parent: QWidget

        :param qsetting: String to specify the QSettings. By default,
            use empty string.
        :type qsetting: str
        """
        QDialog.__init__(self, parent)
        self.setupUi(self)
        icon = resources_path('img', 'icons', 'configure-inasafe.svg')
        self.setWindowIcon(QIcon(icon))
        self.setWindowTitle(self.tr('InaSAFE %s Options' % get_version()))
        # Save reference to the QGIS interface and parent
        self.iface = iface
        self.parent = parent
        if qsetting:
            self.settings = QSettings(qsetting)
        else:
            self.settings = QSettings()

        # InaSAFE default values
        self.default_value_parameters = []
        self.default_value_parameter_containers = []

        # Flag for restore default values
        self.is_restore_default = False

        # List of setting key and control
        self.boolean_settings = {
            'visibleLayersOnlyFlag': self.cbxVisibleLayersOnly,
            'set_layer_from_title_flag': self.cbxSetLayerNameFromTitle,
            'setZoomToImpactFlag': self.cbxZoomToImpact,
            'set_show_only_impact_on_report': self.cbx_show_only_impact,
            'print_atlas_report': self.cbx_print_atlas_report,
            'setHideExposureFlag': self.cbxHideExposure,
            'useSelectedFeaturesOnly': self.cbxUseSelectedFeaturesOnly,
            'useSentry': self.cbxUseSentry,
            'template_warning_verbose': self.template_warning_checkbox,
            'showOrganisationLogoInDockFlag':
                self.organisation_on_dock_checkbox,
            'developer_mode': self.cbxDevMode,
            'generate_report': self.checkbox_generate_reports,
            'memory_profile': self.check_box_memory,
            'always_show_welcome_message': self.welcome_message_check_box
        }
        self.text_settings = {
            'keywordCachePath': self.leKeywordCachePath,
            'ISO19115_ORGANIZATION': self.organisation_line_edit,
            'ISO19115_URL': self.website_line_edit,
            'ISO19115_EMAIL': self.email_line_edit,
            'ISO19115_LICENSE': self.license_line_edit,
        }

        # Export and Import button
        # Export button
        self.export_button = QPushButton(tr('Export'))
        # noinspection PyUnresolvedReferences
        self.export_button.clicked.connect(self.export_setting)
        self.button_box.addButton(
            self.export_button, QDialogButtonBox.ActionRole)
        # Import button
        self.import_button = QPushButton(tr('Import'))
        # noinspection PyUnresolvedReferences
        self.import_button.clicked.connect(self.import_setting)
        self.button_box.addButton(
            self.import_button, QDialogButtonBox.ActionRole)

        # Set up things for context help
        self.help_button = self.button_box.button(QDialogButtonBox.Help)
        # Allow toggling the help button
        self.help_button.setCheckable(True)
        self.help_button.toggled.connect(self.help_toggled)
        self.main_stacked_widget.setCurrentIndex(1)

        # Always set first tab to be open, 0-th index
        self.tabWidget.setCurrentIndex(0)

        # Hide not implemented group
        self.grpNotImplemented.hide()
        self.adjustSize()

        # Population parameter Tab
        # Label
        self.preference_label = QLabel()
        self.preference_label.setText(tr(
            'Please set parameters for each hazard class below. Affected '
            'status and displacement rates selected on this tab are only '
            'applied to exposed populations. '
        ))
        self.preference_layout.addWidget(self.preference_label)

        # Profile preference widget
        self.profile_widget = ProfileWidget()
        self.preference_layout.addWidget(self.profile_widget)

        # Demographic tab
        self.demographic_label = QLabel()
        self.demographic_label.setText(tr(
            'Please set the global default demographic ratio below.'))
        self.default_values_layout.addWidget(self.demographic_label)
        self.scroll_area = QScrollArea()
        self.scroll_area.setWidgetResizable(True)
        self.widget_container = QWidget()
        self.scroll_area.setWidget(self.widget_container)
        self.container_layout = QVBoxLayout()
        self.widget_container.setLayout(self.container_layout)
        self.default_values_layout.addWidget(self.scroll_area)

        # Restore state from setting
        self.restore_state()

        # Hide checkbox if not developers
        if not self.cbxDevMode.isChecked():
            self.checkbox_generate_reports.hide()

        # Connections
        # Check boxes
        self.custom_north_arrow_checkbox.toggled.connect(self.set_north_arrow)
        self.custom_UseUserDirectory_checkbox.toggled.connect(
            self.set_user_dir)
        self.custom_templates_dir_checkbox.toggled.connect(
            self.set_templates_dir)
        self.custom_org_disclaimer_checkbox.toggled.connect(
            self.set_org_disclaimer)
        self.custom_organisation_logo_check_box.toggled.connect(
            self.toggle_logo_path)
        # Buttons
        self.toolKeywordCachePath.clicked.connect(self.open_keyword_cache_path)
        self.toolUserDirectoryPath.clicked.connect(
            self.open_user_directory_path)
        self.toolNorthArrowPath.clicked.connect(self.open_north_arrow_path)
        self.open_organisation_logo_path_button.clicked.connect(
            self.open_organisation_logo_path)
        self.toolReportTemplatePath.clicked.connect(
            self.open_report_template_path)
        # Others
        self.organisation_logo_path_line_edit.textChanged.connect(
            self.update_logo_preview)
        self.earthquake_function.currentIndexChanged.connect(
            self.update_earthquake_info)

        # Set up listener for restore defaults button
        self.demographic_restore_defaults = self.button_box_restore_defaults.\
            button(QDialogButtonBox.RestoreDefaults)
        self.demographic_restore_defaults.setText(
            self.demographic_restore_defaults.text().capitalize())
        self.demographic_restore_defaults.setCheckable(True)
        self.demographic_restore_defaults.clicked.connect(
            self.restore_defaults_ratio)

        # Restore button in population parameter tab
        self.parameter_population_restore_button = \
            self.button_box_restore_preference.button(
                QDialogButtonBox.RestoreDefaults)
        self.parameter_population_restore_button.setText(
            self.parameter_population_restore_button.text().capitalize())

        self.parameter_population_restore_button.clicked.connect(
            partial(self.restore_population_parameters, global_default=True))

        # TODO: Hide this until behaviour is defined
        # hide template warning toggle
        self.template_warning_checkbox.hide()

        # hide custom template dir toggle
        self.custom_templates_dir_checkbox.hide()
        self.splitter_custom_report.hide()

        # Welcome message
        self.set_welcome_message()
Example #4
0
    def __init__(self, iface, parent=None, qsetting=''):
        """Constructor for the dialog.

        :param iface: A Quantum GIS QgisAppInterface instance.
        :type iface: QgisAppInterface

        :param parent: Parent widget of this dialog
        :type parent: QWidget

        :param qsetting: String to specify the QSettings. By default,
            use empty string.
        :type qsetting: str
        """
        QDialog.__init__(self, parent)
        self.setupUi(self)
        icon = resources_path('img', 'icons', 'configure-inasafe.svg')
        self.setWindowIcon(QIcon(icon))
        self.setWindowTitle(self.tr('InaSAFE %s Options' % get_version()))
        # Save reference to the QGIS interface and parent
        self.iface = iface
        self.parent = parent
        if qsetting:
            self.settings = QSettings(qsetting)
        else:
            self.settings = QSettings()

        # InaSAFE default values
        self.default_value_parameters = []
        self.default_value_parameter_containers = []

        # Flag for restore default values
        self.is_restore_default = False

        # List of setting key and control
        self.boolean_settings = {
            'visibleLayersOnlyFlag': self.cbxVisibleLayersOnly,
            'set_layer_from_title_flag': self.cbxSetLayerNameFromTitle,
            'setZoomToImpactFlag': self.cbxZoomToImpact,
            'set_show_only_impact_on_report': self.cbx_show_only_impact,
            'print_atlas_report': self.cbx_print_atlas_report,
            'setHideExposureFlag': self.cbxHideExposure,
            'useSelectedFeaturesOnly': self.cbxUseSelectedFeaturesOnly,
            'useSentry': self.cbxUseSentry,
            'template_warning_verbose': self.template_warning_checkbox,
            'showOrganisationLogoInDockFlag':
            self.organisation_on_dock_checkbox,
            'developer_mode': self.cbxDevMode,
            'generate_report': self.checkbox_generate_reports,
            'memory_profile': self.check_box_memory,
            'always_show_welcome_message': self.welcome_message_check_box
        }
        self.text_settings = {
            'keywordCachePath': self.leKeywordCachePath,
            'ISO19115_ORGANIZATION': self.organisation_line_edit,
            'ISO19115_URL': self.website_line_edit,
            'ISO19115_EMAIL': self.email_line_edit,
            'ISO19115_LICENSE': self.license_line_edit,
        }

        # Export and Import button
        # Export button
        self.export_button = QPushButton(tr('Export'))
        # noinspection PyUnresolvedReferences
        self.export_button.clicked.connect(self.export_setting)
        self.button_box.addButton(self.export_button,
                                  QDialogButtonBox.ActionRole)
        # Import button
        self.import_button = QPushButton(tr('Import'))
        # noinspection PyUnresolvedReferences
        self.import_button.clicked.connect(self.import_setting)
        self.button_box.addButton(self.import_button,
                                  QDialogButtonBox.ActionRole)

        # Set up things for context help
        self.help_button = self.button_box.button(QDialogButtonBox.Help)
        # Allow toggling the help button
        self.help_button.setCheckable(True)
        self.help_button.toggled.connect(self.help_toggled)
        self.main_stacked_widget.setCurrentIndex(1)

        # Always set first tab to be open, 0-th index
        self.tabWidget.setCurrentIndex(0)

        # Hide not implemented group
        self.grpNotImplemented.hide()
        self.adjustSize()

        # Population parameter Tab
        # Label
        self.preference_label = QLabel()
        self.preference_label.setText(
            tr('Please set parameters for each hazard class below. Affected '
               'status and displacement rates selected on this tab are only '
               'applied to exposed populations. '))
        self.preference_layout.addWidget(self.preference_label)

        # Profile preference widget
        self.profile_widget = ProfileWidget()
        self.preference_layout.addWidget(self.profile_widget)

        # Demographic tab
        self.demographic_label = QLabel()
        self.demographic_label.setText(
            tr('Please set the global default demographic ratio below.'))
        self.default_values_layout.addWidget(self.demographic_label)
        self.scroll_area = QScrollArea()
        self.scroll_area.setWidgetResizable(True)
        self.widget_container = QWidget()
        self.scroll_area.setWidget(self.widget_container)
        self.container_layout = QVBoxLayout()
        self.widget_container.setLayout(self.container_layout)
        self.default_values_layout.addWidget(self.scroll_area)

        # Restore state from setting
        self.restore_state()

        # Hide checkbox if not developers
        if not self.cbxDevMode.isChecked():
            self.checkbox_generate_reports.hide()

        # Connections
        # Check boxes
        self.custom_north_arrow_checkbox.toggled.connect(self.set_north_arrow)
        self.custom_UseUserDirectory_checkbox.toggled.connect(
            self.set_user_dir)
        self.custom_templates_dir_checkbox.toggled.connect(
            self.set_templates_dir)
        self.custom_org_disclaimer_checkbox.toggled.connect(
            self.set_org_disclaimer)
        self.custom_organisation_logo_check_box.toggled.connect(
            self.toggle_logo_path)
        # Buttons
        self.toolKeywordCachePath.clicked.connect(self.open_keyword_cache_path)
        self.toolUserDirectoryPath.clicked.connect(
            self.open_user_directory_path)
        self.toolNorthArrowPath.clicked.connect(self.open_north_arrow_path)
        self.open_organisation_logo_path_button.clicked.connect(
            self.open_organisation_logo_path)
        self.toolReportTemplatePath.clicked.connect(
            self.open_report_template_path)
        # Others
        self.organisation_logo_path_line_edit.textChanged.connect(
            self.update_logo_preview)
        self.earthquake_function.currentIndexChanged.connect(
            self.update_earthquake_info)

        # Set up listener for restore defaults button
        self.demographic_restore_defaults = self.button_box_restore_defaults.\
            button(QDialogButtonBox.RestoreDefaults)
        self.demographic_restore_defaults.setText(
            self.demographic_restore_defaults.text().capitalize())
        self.demographic_restore_defaults.setCheckable(True)
        self.demographic_restore_defaults.clicked.connect(
            self.restore_defaults_ratio)

        # Restore button in population parameter tab
        self.parameter_population_restore_button = \
            self.button_box_restore_preference.button(
                QDialogButtonBox.RestoreDefaults)
        self.parameter_population_restore_button.setText(
            self.parameter_population_restore_button.text().capitalize())

        self.parameter_population_restore_button.clicked.connect(
            partial(self.restore_population_parameters, global_default=True))

        # TODO: Hide this until behaviour is defined
        # hide template warning toggle
        self.template_warning_checkbox.hide()

        # hide custom template dir toggle
        self.custom_templates_dir_checkbox.hide()
        self.splitter_custom_report.hide()

        # Welcome message
        self.set_welcome_message()
Example #5
0
    def _load_source_documents(self, source_docs):
        """
        Load source documents into document listing widget.
        """
        # Configure progress dialog
        progress_msg = QApplication.translate(
            "ViewSTR", "Loading supporting documents...")

        progress_dialog = QProgressDialog(self)
        if len(source_docs) > 0:
            progress_dialog.setWindowTitle(progress_msg)
            progress_dialog.setRange(0, len(source_docs))
            progress_dialog.setWindowModality(Qt.WindowModal)
            progress_dialog.setFixedWidth(380)
            progress_dialog.show()
            progress_dialog.setValue(0)
        self._notif_search_config.clear()

        self.tbSupportingDocs.clear()
        self._source_doc_manager.reset()

        if len(source_docs) < 1:
            empty_msg = QApplication.translate(
                'ViewSTR', 'No supporting document is uploaded '
                'for this social tenure relationship.')
            self._notif_search_config.clear()
            self._notif_search_config.insertWarningNotification(empty_msg)

        for i, (doc_type_id, doc_obj) in enumerate(source_docs.items()):

            # add tabs, and container and widget for each tab
            tab_title = self._source_doc_manager.doc_type_mapping[doc_type_id]

            tab_widget = QWidget()
            tab_widget.setObjectName(tab_title)

            cont_layout = QVBoxLayout(tab_widget)
            cont_layout.setObjectName('widget_layout_' + tab_title)

            scrollArea = QScrollArea(tab_widget)
            scrollArea.setFrameShape(QFrame.NoFrame)

            scrollArea_contents = QWidget()
            scrollArea_contents.setObjectName('tab_scroll_area_' + tab_title)

            tab_layout = QVBoxLayout(scrollArea_contents)
            tab_layout.setObjectName('layout_' + tab_title)

            scrollArea.setWidgetResizable(True)

            scrollArea.setWidget(scrollArea_contents)
            cont_layout.addWidget(scrollArea)

            self._source_doc_manager.registerContainer(tab_layout, doc_type_id)

            for doc in doc_obj:

                try:
                    # add doc widgets
                    self._source_doc_manager.insertDocFromModel(
                        doc, doc_type_id)
                except DummyException as ex:
                    LOGGER.debug(str(ex))

            self.tbSupportingDocs.addTab(tab_widget, tab_title)
            progress_dialog.setValue(i + 1)
Example #6
0
class ModelerParametersDialog(QDialog):

    ENTER_NAME = '[Enter name if this is a final result]'
    NOT_SELECTED = '[Not selected]'
    USE_MIN_COVERING_EXTENT = '[Use min covering extent]'

    def __init__(self, alg, model, algName=None):
        QDialog.__init__(self)
        self.setModal(True)
        # The algorithm to define in this dialog. It is an instance of GeoAlgorithm
        self._alg = alg
        # The resulting algorithm after the user clicks on OK. it is an instance of the container Algorithm class
        self.alg = None
        # The model this algorithm is going to be added to
        self.model = model
        # The name of the algorithm in the model, in case we are editing it and not defining it for the first time
        self._algName = algName
        self.setupUi()
        self.params = None

    def setupUi(self):
        self.labels = {}
        self.widgets = {}
        self.checkBoxes = {}
        self.showAdvanced = False
        self.wrappers = {}
        self.valueItems = {}
        self.dependentItems = {}
        self.resize(650, 450)
        self.buttonBox = QDialogButtonBox()
        self.buttonBox.setOrientation(Qt.Horizontal)
        self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel
                                          | QDialogButtonBox.Ok)
        tooltips = self._alg.getParameterDescriptions()
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.verticalLayout = QVBoxLayout()
        self.verticalLayout.setSpacing(5)
        self.verticalLayout.setMargin(20)

        self.bar = QgsMessageBar()
        self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        self.verticalLayout.addWidget(self.bar)

        hLayout = QHBoxLayout()
        hLayout.setSpacing(5)
        hLayout.setMargin(0)
        descriptionLabel = QLabel(self.tr("Description"))
        self.descriptionBox = QLineEdit()
        self.descriptionBox.setText(self._alg.name)
        hLayout.addWidget(descriptionLabel)
        hLayout.addWidget(self.descriptionBox)
        self.verticalLayout.addLayout(hLayout)
        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)
        self.verticalLayout.addWidget(line)

        for param in self._alg.parameters:
            if param.isAdvanced:
                self.advancedButton = QPushButton()
                self.advancedButton.setText(
                    self.tr('Show advanced parameters'))
                self.advancedButton.clicked.connect(
                    self.showAdvancedParametersClicked)
                advancedButtonHLayout = QHBoxLayout()
                advancedButtonHLayout.addWidget(self.advancedButton)
                advancedButtonHLayout.addStretch()
                self.verticalLayout.addLayout(advancedButtonHLayout)
                break
        for param in self._alg.parameters:
            if param.hidden:
                continue
            desc = param.description
            if isinstance(param, ParameterExtent):
                desc += self.tr('(xmin, xmax, ymin, ymax)')
            if isinstance(param, ParameterPoint):
                desc += self.tr('(x, y)')
            if param.optional:
                desc += self.tr(' [optional]')
            label = QLabel(desc)
            self.labels[param.name] = label

            wrapper = param.wrapper(self)
            self.wrappers[param.name] = wrapper

            widget = wrapper.widget
            self.valueItems[param.name] = widget
            if param.name in list(tooltips.keys()):
                tooltip = tooltips[param.name]
            else:
                tooltip = param.description
            label.setToolTip(tooltip)
            widget.setToolTip(tooltip)
            if param.isAdvanced:
                label.setVisible(self.showAdvanced)
                widget.setVisible(self.showAdvanced)
                self.widgets[param.name] = widget

            self.verticalLayout.addWidget(label)
            self.verticalLayout.addWidget(widget)

        for output in self._alg.outputs:
            if output.hidden:
                continue
            if isinstance(output, (OutputRaster, OutputVector, OutputTable,
                                   OutputHTML, OutputFile, OutputDirectory)):
                label = QLabel(output.description + '<' +
                               output.__class__.__name__ + '>')
                item = QLineEdit()
                if hasattr(item, 'setPlaceholderText'):
                    item.setPlaceholderText(ModelerParametersDialog.ENTER_NAME)
                self.verticalLayout.addWidget(label)
                self.verticalLayout.addWidget(item)
                self.valueItems[output.name] = item

        label = QLabel(' ')
        self.verticalLayout.addWidget(label)
        label = QLabel(self.tr('Parent algorithms'))
        self.dependenciesPanel = self.getDependenciesPanel()
        self.verticalLayout.addWidget(label)
        self.verticalLayout.addWidget(self.dependenciesPanel)
        self.verticalLayout.addStretch(1000)

        self.setPreviousValues()
        self.setWindowTitle(self._alg.name)
        self.verticalLayout2 = QVBoxLayout()
        self.verticalLayout2.setSpacing(2)
        self.verticalLayout2.setMargin(0)
        self.tabWidget = QTabWidget()
        self.tabWidget.setMinimumWidth(300)
        self.paramPanel = QWidget()
        self.paramPanel.setLayout(self.verticalLayout)
        self.scrollArea = QScrollArea()
        self.scrollArea.setWidget(self.paramPanel)
        self.scrollArea.setWidgetResizable(True)
        self.tabWidget.addTab(self.scrollArea, self.tr('Parameters'))

        self.txtHelp = QTextBrowser()

        html = None
        isText, algHelp = self._alg.help()
        if algHelp is not None:
            algHelp = algHelp if isText else QUrl(algHelp)
            try:
                if isText:
                    self.txtHelp.setHtml(algHelp)
                else:
                    html = self.tr(
                        '<p>Downloading algorithm help... Please wait.</p>')
                    self.txtHelp.setHtml(html)
                    self.tabWidget.addTab(self.txtHelp, 'Help')
                    self.reply = QgsNetworkAccessManager.instance().get(
                        QNetworkRequest(algHelp))
                    self.reply.finished.connect(self.requestFinished)
            except:
                pass

        self.verticalLayout2.addWidget(self.tabWidget)
        self.verticalLayout2.addWidget(self.buttonBox)
        self.setLayout(self.verticalLayout2)
        self.buttonBox.accepted.connect(self.okPressed)
        self.buttonBox.rejected.connect(self.cancelPressed)
        QMetaObject.connectSlotsByName(self)

        for wrapper in list(self.wrappers.values()):
            wrapper.postInitialize(list(self.wrappers.values()))

    def requestFinished(self):
        """Change the webview HTML content"""
        reply = self.sender()
        if reply.error() != QNetworkReply.NoError:
            html = self.tr(
                '<h2>No help available for this algorithm</h2><p>{}</p>'.
                format(reply.errorString()))
        else:
            html = str(reply.readAll())
        reply.deleteLater()
        self.txtHelp.setHtml(html)

    def getAvailableDependencies(self):
        if self._algName is None:
            dependent = []
        else:
            dependent = self.model.getDependentAlgorithms(self._algName)
        opts = []
        for alg in list(self.model.algs.values()):
            if alg.name not in dependent:
                opts.append(alg)
        return opts

    def getDependenciesPanel(self):
        return MultipleInputPanel(
            [alg.description for alg in self.getAvailableDependencies()])

    def showAdvancedParametersClicked(self):
        self.showAdvanced = not self.showAdvanced
        if self.showAdvanced:
            self.advancedButton.setText(self.tr('Hide advanced parameters'))
        else:
            self.advancedButton.setText(self.tr('Show advanced parameters'))
        for param in self._alg.parameters:
            if param.isAdvanced:
                self.labels[param.name].setVisible(self.showAdvanced)
                self.widgets[param.name].setVisible(self.showAdvanced)

    def getAvailableValuesOfType(self, paramType, outType=None, dataType=None):
        # upgrade paramType to list
        if type(paramType) is not list:
            paramType = [paramType]

        values = []
        inputs = self.model.inputs
        for i in list(inputs.values()):
            param = i.param
            for t in paramType:
                if isinstance(param, t):
                    if dataType is not None:
                        if param.datatype in dataType:
                            values.append(ValueFromInput(param.name))
                    else:
                        values.append(ValueFromInput(param.name))
                    break
        if outType is None:
            return values
        if self._algName is None:
            dependent = []
        else:
            dependent = self.model.getDependentAlgorithms(self._algName)
        for alg in list(self.model.algs.values()):
            if alg.name not in dependent:
                for out in alg.algorithm.outputs:
                    if isinstance(out, outType):
                        if dataType is not None and out.datatype in dataType:
                            values.append(ValueFromOutput(alg.name, out.name))
                        else:
                            values.append(ValueFromOutput(alg.name, out.name))

        return values

    def resolveValueDescription(self, value):
        if isinstance(value, ValueFromInput):
            return self.model.inputs[value.name].param.description
        else:
            alg = self.model.algs[value.alg]
            return self.tr("'%s' from algorithm '%s'") % (
                alg.algorithm.getOutputFromName(
                    value.output).description, alg.description)

    def setTableContent(self):
        params = self._alg.parameters
        outputs = self._alg.outputs
        visibleParams = [p for p in params if not p.hidden]
        visibleOutputs = [p for o in outputs if not o.hidden]
        self.tableWidget.setRowCount(len(visibleParams) + len(visibleOutputs))

        for i, param in visibleParams:
            item = QTableWidgetItem(param.description)
            item.setFlags(Qt.ItemIsEnabled)
            self.tableWidget.setItem(i, 0, item)
            item = self.getWidgetFromParameter(param)
            self.valueItems[param.name] = item
            self.tableWidget.setCellWidget(i, 1, item)
            self.tableWidget.setRowHeight(i, 22)

        for i, output in visibleOutputs:
            item = QTableWidgetItem(output.description + '<' +
                                    output.__module__.split('.')[-1] + '>')
            item.setFlags(Qt.ItemIsEnabled)
            self.tableWidget.setItem(i, 0, item)
            item = QLineEdit()
            if hasattr(item, 'setPlaceholderText'):
                item.setPlaceholderText(ModelerParametersDialog.ENTER_NAME)
            self.valueItems[output.name] = item
            self.tableWidget.setCellWidget(i, 1, item)
            self.tableWidget.setRowHeight(i, 22)

    def setPreviousValues(self):
        if self._algName is not None:
            alg = self.model.algs[self._algName]
            self.descriptionBox.setText(alg.description)
            for param in alg.algorithm.parameters:
                if param.hidden:
                    continue
                if param.name in alg.params:
                    value = alg.params[param.name]
                else:
                    value = param.default
                self.wrappers[param.name].setValue(value)
            for name, out in list(alg.outputs.items()):
                self.valueItems[name].setText(out.description)

            selected = []
            dependencies = self.getAvailableDependencies()
            for idx, dependency in enumerate(dependencies):
                if dependency.name in alg.dependencies:
                    selected.append(idx)

            self.dependenciesPanel.setSelectedItems(selected)

    def createAlgorithm(self):
        alg = Algorithm(self._alg.commandLineName())
        alg.setName(self.model)
        alg.description = self.descriptionBox.text()
        params = self._alg.parameters
        outputs = self._alg.outputs
        for param in params:
            if param.hidden:
                continue
            if not self.setParamValue(alg, param, self.wrappers[param.name]):
                self.bar.pushMessage(
                    "Error",
                    "Wrong or missing value for parameter '%s'" %
                    param.description,
                    level=QgsMessageBar.WARNING)
                return None
        for output in outputs:
            if not output.hidden:
                name = str(self.valueItems[output.name].text())
                if name.strip(
                ) != '' and name != ModelerParametersDialog.ENTER_NAME:
                    alg.outputs[output.name] = ModelerOutput(name)

        selectedOptions = self.dependenciesPanel.selectedoptions
        availableDependencies = self.getAvailableDependencies()
        for selected in selectedOptions:
            alg.dependencies.append(availableDependencies[selected].name)

        return alg

    def setParamValue(self, alg, param, wrapper):
        try:
            value = wrapper.value()
            alg.params[param.name] = value
            return True
        except InvalidParameterValue:
            return False

    def okPressed(self):
        self.alg = self.createAlgorithm()
        if self.alg is not None:
            self.close()

    def cancelPressed(self):
        self.alg = None
        self.close()
Example #7
0
class EntityEditorDialog(MapperMixin):
    """
    Dialog for editing entity attributes.
    """
    addedModel = pyqtSignal(object)

    def __init__(self,
                 entity,
                 model=None,
                 parent=None,
                 manage_documents=True,
                 collect_model=False,
                 parent_entity=None,
                 exclude_columns=None,
                 plugin=None,
                 allow_str_creation=True):
        """
        Class constructor.
        :param entity: Entity object corresponding to a table object.
        :type entity: Entity
        :param model: Data object for loading data into the form widgets.
        If the model is set, then the editor dialog is assumed to be in edit
        mode.
        :type model: object
        :param parent: Parent widget that the form belongs to.
        :type parent: QWidget
        :param manage_documents: True if the dialog should provide controls
        for managing supporting documents. Only applicable if the entity
        allows for supporting documents to be attached.
        :type manage_documents: bool
        :param collect_model: If set to True only returns
        the filled form model without saving it to the database.
        :type collect_model: Boolean
        :param parent_entity: The parent entity of the editor
        :type parent_entity: Object
        :param exclude_columns: List of columns to be excluded if in a list.
        :type exclude_columns: List
        :return: If collect_model, returns SQLAlchemy Model
        """
        super().__init__(parent=parent, model=model, entity=entity)

        QgsGui.enableAutoGeometryRestore(self)

        self.collection_suffix = self.tr('Collection')

        # Set minimum width
        self.setMinimumWidth(450)

        self.plugin = plugin

        # Flag for mandatory columns
        self.has_mandatory = False
        self.reload_form = False
        self._entity = entity
        self.edit_model = model
        self.column_widgets = OrderedDict()
        self.columns = {}
        self._parent = parent
        self.exclude_columns = exclude_columns or []
        self.entity_tab_widget = None
        self._disable_collections = False
        self.filter_val = None
        self.parent_entity = parent_entity
        self.child_models = OrderedDict()
        self.entity_scroll_area = None
        self.entity_editor_widgets = OrderedDict()
        self.details_tree_view = None
        # Set notification layout bar
        self.vlNotification = QVBoxLayout()
        self.vlNotification.setObjectName('vlNotification')
        self._notifBar = NotificationBar(self.vlNotification)
        self.do_not_check_dirty = False
        # Set manage documents only if the entity supports documents
        if self._entity.supports_documents:
            self._manage_documents = manage_documents
        else:
            self._manage_documents = False

        # Setup entity model
        self._ent_document_model = None
        if self._entity.supports_documents:
            self.ent_model, self._ent_document_model = entity_model(
                self._entity, with_supporting_document=True)
        else:
            self.ent_model = entity_model(self._entity)
        if model is not None:
            self.ent_model = model

        MapperMixin.__init__(self, self.ent_model, entity)

        self.collect_model = collect_model

        self.register_column_widgets()

        try:
            if isinstance(parent._parent, EntityEditorDialog):
                # hide collections form child editor
                self._disable_collections = True
        except AttributeError:
            self._parent._parent = None

        # Set title
        editor_trans = self.tr('Editor')
        if self._entity.label is not None:
            if self._entity.label != '':
                title_str = self._entity.label
            else:
                title_str = format_name(self._entity.short_name)
        else:
            title_str = format_name(self._entity.short_name)

        self.title = '{0} {1}'.format(title_str, editor_trans)

        self.setWindowTitle(self.title)

        # determine whether the entity is part of the STR relationship
        curr_profile = current_profile()
        self.participates_in_str, self.is_party_unit = curr_profile.social_tenure.entity_participates_in_str(
            self.entity)

        self._init_gui(show_str_tab=allow_str_creation
                       and self.participates_in_str,
                       is_party_unit=self.is_party_unit)
        self.adjustSize()

        self._get_entity_editor_widgets()

        if isinstance(parent._parent, EntityEditorDialog):
            self.parent_entity = parent.parent_entity
            self.set_parent_values()
            # make the size smaller to differentiate from parent and as it
            # only has few tabs.
            self.adjustSize()

        self.attribute_mappers = self._attr_mapper_collection

        # Exception title for editor extension exceptions
        self._ext_exc_msg = self.tr(
            'An error has occured while executing Python code in the editor '
            'extension:')

        # Register custom editor extension if specified
        self._editor_ext = entity_dlg_extension(self)
        if self._editor_ext is not None:
            self._editor_ext.post_init()

            # Initialize CascadingFieldContext objects
            self._editor_ext.connect_cf_contexts()

    def _init_gui(self, show_str_tab: bool, is_party_unit: bool):
        # Setup base elements
        self.gridLayout = QGridLayout(self)
        self.gridLayout.setObjectName('glMain')
        self.gridLayout.addLayout(self.vlNotification, 0, 0, 1, 1)

        # set widgets values
        column_widget_area = self._setup_columns_content_area()

        self.gridLayout.addWidget(column_widget_area, 1, 0, 1, 1)

        if show_str_tab:
            self._setup_str_tab(is_party_unit=is_party_unit)

        # Add notification for mandatory columns if applicable
        next_row = 2
        if self.has_mandatory:
            self.required_fields_lbl = QLabel(self)
            msg = self.tr('Please fill out all required (*) fields.')
            msg = self._highlight_asterisk(msg)
            self.required_fields_lbl.setText(msg)
            self.gridLayout.addWidget(self.required_fields_lbl, next_row, 0, 1,
                                      2)
            # Bump up row reference
            next_row += 1

        self.buttonBox = QDialogButtonBox(self)
        self.buttonBox.setObjectName('buttonBox')
        self.gridLayout.addWidget(self.buttonBox, next_row, 0, 1, 1)

        self.buttonBox.setOrientation(Qt.Horizontal)
        self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel
                                          | QDialogButtonBox.Save)

        if self.edit_model is None:
            if not self.collect_model:
                self.save_new_button = QPushButton(
                    QApplication.translate('EntityEditorDialog',
                                           'Save and New'))
                self.buttonBox.addButton(self.save_new_button,
                                         QDialogButtonBox.ActionRole)

        # edit model, collect model
        # adding new record for child

        # Saving in parent editor
        if not isinstance(self._parent._parent, EntityEditorDialog):
            # adding a new record
            if self.edit_model is None:
                # saving when digitizing.
                if self.collect_model:
                    self.buttonBox.accepted.connect(self.on_model_added)
                # saving parent editor
                else:
                    self.buttonBox.accepted.connect(self.save_parent_editor)
                    self.save_new_button.clicked.connect(self.save_and_new)
            # updating existing record
            else:
                if not self.collect_model:
                    # updating existing record of the parent editor
                    self.buttonBox.accepted.connect(self.save_parent_editor)
                else:
                    self.buttonBox.accepted.connect(self.on_model_added)
        # Saving in child editor
        else:
            # save and new record
            if self.edit_model is None:
                self.buttonBox.accepted.connect(self.on_child_saved)
                self.save_new_button.clicked.connect(
                    lambda: self.on_child_saved(True))

            else:
                # When updating an existing child editor save to the db
                self.buttonBox.accepted.connect(self.on_child_saved)
                # self.buttonBox.accepted.connect(self.submit)

        self.buttonBox.rejected.connect(self.cancel)

    @property
    def notification_bar(self):
        """
        :return: Returns the dialog's notification bar.
        :rtype: NotificationBar
        """
        return self._notifBar

    def save_parent_editor(self):
        """
        Saves the parent editor and its children.
        """
        self.submit()
        self.save_children()

    def set_parent_values(self):
        """
        Sets the parent display column for the child.
        """
        if self.parent_entity is None:
            return
        for col in self._entity.columns.values():
            if col.TYPE_INFO == 'FOREIGN_KEY':
                parent_entity = col.parent
                if parent_entity == self.parent_entity:
                    self.parent_widgets_value_setter(self._parent._parent, col)

    def parent_widgets_value_setter(self, parent, col):
        """
        Finds and sets the value from parent widget and set it to the column
        widget of a child using the child column.
        :param parent: The parent widget
        :type parent: QWidget
        :param col: The child column object
        :type col: Object
        """
        for parent_col_name, parent_widget in parent.column_widgets.items():
            parent_col = parent.columns[parent_col_name]
            if parent_col.name == col.name:
                self.single_parent_value_setter(col, parent_widget)
                break
            if parent_col.name in col.entity_relation.display_cols:
                self.single_parent_value_setter(col, parent_widget)
                break

    def single_parent_value_setter(self, col, parent_widget):
        """
        Gets value from parent widget and set it to the column widget of a
        child using the child column.
        :param parent: The parent widget
        :type parent: QWidget
        :param col: The child column object
        :type col: Object
        """
        local_widget = self.column_widgets[col.name]
        local_widget.show_clear_button()
        self.filter_val = parent_widget.text()
        local_widget.setText(self.filter_val)

    def save_and_new(self):
        """
        A slot raised when Save and New button is click. It saves the form
        without showing a success message. Then it sets reload_form property
        to True so that entity_browser can re-load the form.
        """
        from stdm.ui.entity_browser import (EntityBrowserWithEditor)
        self.submit(False, True)
        self.save_children()

        if self.is_valid:
            self.addedModel.emit(self.model())
            self.setModel(self.ent_model())
            self.clear()
            self.child_models.clear()
            for index in range(0, self.entity_tab_widget.count() - 1):
                if isinstance(self.entity_tab_widget.widget(index),
                              EntityBrowserWithEditor):
                    child_browser = self.entity_tab_widget.widget(index)
                    child_browser.remove_rows()

    def on_model_added(self):
        """
        A slot raised when a form is submitted with collect model set to True.
        There will be no success message and the form does not close.
        """
        self.submit(True)
        self.addedModel.emit(self.model())

    def closeEvent(self, event):
        """
        Raised when a request to close the window is received.
        Check the dirty state of input controls and prompt user to
        save if dirty.
        """

        if self.do_not_check_dirty:
            event.accept()
            return
        isDirty, userResponse = self.checkDirty()

        if isDirty:
            if userResponse == QMessageBox.Yes:
                # We need to ignore the event so that validation and
                # saving operations can be executed
                event.ignore()
                self.submit()
            elif userResponse == QMessageBox.No:
                event.accept()
            elif userResponse == QMessageBox.Cancel:
                event.ignore()
        else:
            event.accept()

    def on_child_saved(self, save_and_new=False):
        """
        A slot raised when the save or save and new button is clicked. It sets
        the child_models dictionary of the parent when saved.
        :param save_and_new: A boolean indicating the save and new button is
        clicked to trigger the slot.
        :type save_and_new: Boolean
        """
        if self.parent_entity is None:
            return

        self.submit(True)

        insert_pos = self._parent.tbEntity.model().rowCount() + 1
        # Save to parent editor so that it is persistent.
        self._parent._parent.child_models[insert_pos, self._entity.name] = \
            (self._entity, self.model())
        self.addedModel.emit(self.model())
        if not save_and_new:
            self.accept()

        else:
            if self.is_valid:
                # self.addedModel.emit(self.model())
                self.setModel(self.ent_model())

                self.clear()
                self.set_parent_values()

    def save_children(self):
        """
        Saves children models into the database by assigning the the id of the
        parent for foreign key column.
        """
        if len(self.child_models) < 1:
            return
        children_obj = []
        for row_entity, row_value in self.child_models.items():
            entity, model = row_value

            ent_model = entity_model(entity)
            entity_obj = ent_model()
            for col in entity.columns.values():
                if col.TYPE_INFO == 'FOREIGN_KEY':
                    if col.parent.name == self._entity.name:
                        setattr(model, col.name, self.model().id)
                        children_obj.append(model)
            entity_obj.saveMany(children_obj)

    def register_column_widgets(self):
        """
        Registers the column widgets.
        """
        # Append column labels and widgets
        table_name = self._entity.name
        columns = table_column_names(table_name)
        self.scroll_widget_contents = QWidget()
        self.scroll_widget_contents.setObjectName('scrollAreaWidgetContents')
        for c in self._entity.columns.values():
            if c.name in self.exclude_columns:
                continue
            if c.name not in columns and not isinstance(c, VirtualColumn):
                continue
            # Get widget factory
            column_widget = ColumnWidgetRegistry.create(
                c, self.scroll_widget_contents, host=self)
            self.columns[c.name] = c
            self.column_widgets[c.name] = column_widget

    def _setup_columns_content_area(self):
        # Only use this if entity supports documents
        # self.entity_tab_widget = None
        self.doc_widget = None

        self.entity_scroll_area = QScrollArea(self)
        self.entity_scroll_area.setFrameShape(QFrame.NoFrame)
        self.entity_scroll_area.setWidgetResizable(True)
        self.entity_scroll_area.setObjectName('scrollArea')

        # Grid layout for controls
        self.gl = QGridLayout(self.scroll_widget_contents)
        self.gl.setObjectName('gl_widget_contents')

        # Append column labels and widgets
        table_name = self._entity.name
        columns = table_column_names(table_name)
        # Iterate entity column and assert if they exist
        row_id = 0
        for column_name, column_widget in self.column_widgets.items():
            c = self.columns[column_name]
            if c.name in self.exclude_columns:
                continue
            if c.name not in columns and not isinstance(c, VirtualColumn):
                continue

            if column_widget is not None:
                header = c.ui_display()
                self.c_label = QLabel(self.scroll_widget_contents)

                # Format label text if it is a mandatory field
                if c.mandatory:
                    header = '{0} *'.format(c.ui_display())
                    # Highlight asterisk
                    header = self._highlight_asterisk(header)

                self.c_label.setText(header)
                self.gl.addWidget(self.c_label, row_id, 0, 1, 1)

                self.column_widget = column_widget
                self.gl.addWidget(self.column_widget, row_id, 1, 1, 1)

                # Add user tip if specified for the column configuration
                if c.user_tip:
                    self.tip_lbl = UserTipLabel(user_tip=c.user_tip)
                    self.gl.addWidget(self.tip_lbl, row_id, 2, 1, 1)

                if c.mandatory and not self.has_mandatory:
                    self.has_mandatory = True

                col_name = c.name
                # Replace name accordingly based on column type
                if isinstance(c, MultipleSelectColumn):
                    col_name = c.model_attribute_name

                # Add widget to MapperMixin collection
                self.addMapping(col_name,
                                self.column_widget,
                                c.mandatory,
                                pseudoname=c.ui_display())

                # Bump up row_id
                row_id += 1

        self.entity_scroll_area.setWidget(self.scroll_widget_contents)

        if self.entity_tab_widget is None:
            self.entity_tab_widget = QTabWidget(self)
        # Check if there are children and add foreign key browsers

        # Add primary tab if necessary
        self._add_primary_attr_widget()

        if not self._disable_collections:
            ch_entities = self.children_entities()

            for col, ch in ch_entities:
                if hasattr(col.entity_relation, 'show_in_parent'):
                    if col.entity_relation.show_in_parent != '0':
                        self._add_fk_browser(ch, col)
                else:
                    self._add_fk_browser(ch, col)

        # Add tab widget if entity supports documents
        if self._entity.supports_documents:
            self.doc_widget = SupportingDocumentsWidget(
                self._entity.supporting_doc, self._ent_document_model, self)

            # Map the source document manager object
            self.addMapping('documents',
                            self.doc_widget.source_document_manager)

            #
            # # Add attribute tab
            # self._add_primary_attr_widget()

            # Add supporting documents tab
            self.entity_tab_widget.addTab(self.doc_widget,
                                          self.tr('Supporting Documents'))

        # Return the correct widget
        if self.entity_tab_widget is not None:
            return self.entity_tab_widget

        return self.entity_scroll_area

    def _add_primary_attr_widget(self):
        # Check if the primary entity
        # exists and add if it does not
        pr_txt = self.tr('Primary')
        if self.entity_tab_widget is not None:
            tab_txt = self.entity_tab_widget.tabText(0)
            if not tab_txt == pr_txt:
                self.entity_tab_widget.addTab(self.entity_scroll_area, pr_txt)

    def _setup_str_tab(self, is_party_unit: bool):
        """
        Creates the STR relationship tab
        """
        from stdm.ui.feature_details import DetailsTreeView

        layout = QVBoxLayout()
        hl = QHBoxLayout()

        add_btn = QToolButton(self)
        add_btn.setText(self.tr('Create STR'))
        add_btn.setIcon(GuiUtils.get_icon('add.png'))
        hl.addWidget(add_btn)
        add_btn.clicked.connect(self._create_str)

        edit_btn = QToolButton(self)
        edit_btn.setText(self.tr('Edit'))
        edit_btn.setIcon(GuiUtils.get_icon('edit.png'))
        edit_btn.setDisabled(True)
        hl.addWidget(edit_btn)

        view_document_btn = QToolButton(self)
        view_document_btn.setText(self.tr('View Supporting Documents'))
        view_document_btn.setIcon(GuiUtils.get_icon('document.png'))
        view_document_btn.setDisabled(True)
        hl.addWidget(view_document_btn)

        hl.addStretch()
        layout.addLayout(hl)

        self.details_tree_view = DetailsTreeView(
            parent=self,
            plugin=self.plugin,
            edit_button=edit_btn,
            view_document_button=view_document_btn)
        self.details_tree_view.activate_feature_details(
            True, follow_layer_selection=False)
        self.details_tree_view.model.clear()

        if is_party_unit:
            self.details_tree_view.search_party(self.entity,
                                                [self.ent_model.id])
        else:
            self.details_tree_view.search_spatial_unit(self.entity,
                                                       [self.ent_model.id])

        layout.addWidget(self.details_tree_view)
        w = QWidget()
        w.setLayout(layout)

        self.entity_tab_widget.addTab(w, self.tr('STR'))

    def _create_str(self):
        """
        Opens the dialog to create a new STR
        """
        from stdm.ui.social_tenure.str_editor import STREditor
        add_str_window = STREditor()

        #if is_party_unit:
        #    add_str.set_party_data(self.entity_model_obj)

        if add_str_window.exec_():
            # STR created - refresh STR view
            if self.is_party_unit:
                self.details_tree_view.search_party(self.entity,
                                                    [self.ent_model.id])
            else:
                self.details_tree_view.search_spatial_unit(
                    self.entity, [self.ent_model.id])

    def _add_fk_browser(self, child_entity, column):
        # Create and add foreign key
        # browser to the collection
        from stdm.ui.entity_browser import (ContentGroupEntityBrowser)

        attr = '{0}_collection'.format(child_entity.name)

        # Return if the attribute does not exist
        if not hasattr(self._model, attr):
            return

        table_content = TableContentGroup(User.CURRENT_USER.UserName,
                                          child_entity.short_name)

        if self.edit_model is not None:
            parent_id = self.edit_model.id
        else:
            parent_id = 0

        entity_browser = ContentGroupEntityBrowser(child_entity,
                                                   table_content,
                                                   rec_id=parent_id,
                                                   parent=self,
                                                   plugin=self.plugin,
                                                   load_recs=False)

        # entity_browser = EntityBrowserWithEditor(
        # child_entity,
        # self,
        # MANAGE,
        # False,
        # plugin=self.plugin
        # )

        entity_browser.buttonBox.setVisible(False)
        entity_browser.record_filter = []

        if len(child_entity.label) > 2:
            column_label = child_entity.label
        else:
            # Split and join  to filter out entity name prefix
            # e.g. 'lo_parcel' to 'parcel'
            column_label = format_name(" ".join(
                child_entity.name.split("_", 1)[1:]))

        self.set_filter(child_entity, entity_browser)

        self.entity_tab_widget.addTab(entity_browser,
                                      '{0}'.format(column_label))

    def set_filter(self, entity, browser):
        col = self.filter_col(entity)
        child_model = entity_model(entity)
        child_model_obj = child_model()
        col_obj = getattr(child_model, col.name)

        browser.filtered_records = []

        if self.model() is not None:
            if self.model().id is not None:
                browser.filtered_records = child_model_obj.queryObject(
                ).filter(col_obj == self.model().id).all()

        if self.edit_model is not None:
            browser.filtered_records = child_model_obj.queryObject().filter(
                col_obj == self.edit_model.id).all()

    def filter_col(self, child_entity):
        for col in child_entity.columns.values():
            if col.TYPE_INFO == 'FOREIGN_KEY':
                parent_entity = col.parent
                if parent_entity == self._entity:
                    return col

    def children_entities(self):
        """
        :return: Returns a list of children entities (by name)
        that refer to the main entity as the parent.
        :rtype: OrderedDict
        """
        child_columns = []
        for ch in self._entity.children():
            if ch.TYPE_INFO == Entity.TYPE_INFO:
                for col in ch.columns.values():
                    if hasattr(col, 'entity_relation'):

                        if col.parent.name == self._entity.name:
                            child_columns.append((col, ch))
        return child_columns

    def document_widget(self):
        """
        :return: Returns the widget for managing
        the supporting documents for an entity if enabled.
        :rtype: SupportingDocumentsWidget
        """
        return self.doc_widget

    def source_document_manager(self):
        """
        :return: Returns an instance of the
        SourceDocumentManager only if supporting
        documents are enabled for the given entity. Otherwise,
        None if supporting documents are not enabled.
        :rtype: SourceDocumentManager
        """
        if self.doc_widget is None:
            return None

        return self.doc_widget.source_document_manager

    def _highlight_asterisk(self, text):
        # Highlight asterisk in red
        c = '*'

        # Do not format if there is no asterisk
        if text.find(c) == -1:
            return text

        asterisk_highlight = '<span style=\" color:#ff0000;\">*</span>'
        text = text.replace(c, asterisk_highlight)

        return '<html><head/><body><p>{0}</p></body></html>'.format(text)

    def _custom_validate(self):
        """
        Override of the MapperMixin which enables custom editor extensions to
        inject additional validation before saving form data.
        :return: Return True if the validation was successful,
        otherwise False.
        :rtype: bool
        """
        if self._editor_ext is not None:
            return self._editor_ext.validate()

        # Return True if there is no custom editor extension specified
        return True

    def _post_save(self, model):
        """
        Include additional post-save logic by custom extensions.
        :param model: SQLAlchemy model
        :type model: object
        """
        if self._editor_ext is not None:
            self._editor_ext.post_save(model)

    def _get_entity_editor_widgets(self):
        """
        Gets entity editor widgets and appends them to a dictionary
        """
        if self.entity_tab_widget:
            tab_count = self.entity_tab_widget.count()
            for i in range(tab_count):
                tab_object = self.entity_tab_widget.widget(i)
                tab_text = self.entity_tab_widget.tabText(i)
                self.entity_editor_widgets[tab_text] = tab_object
        else:
            self.entity_editor_widgets['no_tab'] = self.entity_scroll_area
Example #8
0
class ModelerParametersDialog(QDialog):

    ENTER_NAME = '[Enter name if this is a final result]'
    NOT_SELECTED = '[Not selected]'
    USE_MIN_COVERING_EXTENT = '[Use min covering extent]'

    def __init__(self, alg, model, algName=None):
        QDialog.__init__(self)
        self.setModal(True)
        #The algorithm to define in this dialog. It is an instance of GeoAlgorithm
        self._alg = alg
        #The resulting algorithm after the user clicks on OK. it is an instance of the container Algorithm class
        self.alg = None
        #The model this algorithm is going to be added to
        self.model = model
        #The name of the algorithm in the model, in case we are editing it and not defining it for the first time
        self._algName = algName
        self.setupUi()
        self.params = None

    def setupUi(self):
        self.labels = {}
        self.widgets = {}
        self.checkBoxes = {}
        self.showAdvanced = False
        self.valueItems = {}
        self.dependentItems = {}
        self.resize(650, 450)
        self.buttonBox = QDialogButtonBox()
        self.buttonBox.setOrientation(Qt.Horizontal)
        self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel
                                          | QDialogButtonBox.Ok)
        tooltips = self._alg.getParameterDescriptions()
        self.setSizePolicy(QSizePolicy.Expanding,
                           QSizePolicy.Expanding)
        self.verticalLayout = QVBoxLayout()
        self.verticalLayout.setSpacing(5)
        self.verticalLayout.setMargin(20)

        hLayout = QHBoxLayout()
        hLayout.setSpacing(5)
        hLayout.setMargin(0)
        descriptionLabel = QLabel(self.tr("Description"))
        self.descriptionBox = QLineEdit()
        self.descriptionBox.setText(self._alg.name)
        hLayout.addWidget(descriptionLabel)
        hLayout.addWidget(self.descriptionBox)
        self.verticalLayout.addLayout(hLayout)
        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)
        self.verticalLayout.addWidget(line)

        for param in self._alg.parameters:
            if param.isAdvanced:
                self.advancedButton = QPushButton()
                self.advancedButton.setText(self.tr('Show advanced parameters'))
                self.advancedButton.clicked.connect(
                    self.showAdvancedParametersClicked)
                advancedButtonHLayout = QHBoxLayout()
                advancedButtonHLayout.addWidget(self.advancedButton)
                advancedButtonHLayout.addStretch()
                self.verticalLayout.addLayout(advancedButtonHLayout)
                break
        for param in self._alg.parameters:
            if param.hidden:
                continue
            desc = param.description
            if isinstance(param, ParameterExtent):
                desc += self.tr('(xmin, xmax, ymin, ymax)')
            if isinstance(param, ParameterPoint):
                desc += self.tr('(x, y)')
            label = QLabel(desc)
            self.labels[param.name] = label
            widget = self.getWidgetFromParameter(param)
            self.valueItems[param.name] = widget
            if param.name in tooltips.keys():
                tooltip = tooltips[param.name]
            else:
                tooltip = param.description
            label.setToolTip(tooltip)
            widget.setToolTip(tooltip)
            if param.isAdvanced:
                label.setVisible(self.showAdvanced)
                widget.setVisible(self.showAdvanced)
                self.widgets[param.name] = widget
            self.verticalLayout.addWidget(label)
            self.verticalLayout.addWidget(widget)

        for output in self._alg.outputs:
            if output.hidden:
                continue
            if isinstance(output, (OutputRaster, OutputVector, OutputTable,
                                   OutputHTML, OutputFile, OutputDirectory)):
                label = QLabel(output.description + '<'
                               + output.__class__.__name__ + '>')
                item = QLineEdit()
                if hasattr(item, 'setPlaceholderText'):
                    item.setPlaceholderText(ModelerParametersDialog.ENTER_NAME)
                self.verticalLayout.addWidget(label)
                self.verticalLayout.addWidget(item)
                self.valueItems[output.name] = item

        label = QLabel(' ')
        self.verticalLayout.addWidget(label)
        label = QLabel(self.tr('Parent algorithms'))
        self.dependenciesPanel = self.getDependenciesPanel()
        self.verticalLayout.addWidget(label)
        self.verticalLayout.addWidget(self.dependenciesPanel)

        self.verticalLayout.addStretch(1000)
        self.setLayout(self.verticalLayout)

        self.setPreviousValues()
        self.setWindowTitle(self._alg.name)
        self.verticalLayout2 = QVBoxLayout()
        self.verticalLayout2.setSpacing(2)
        self.verticalLayout2.setMargin(0)
        self.tabWidget = QTabWidget()
        self.tabWidget.setMinimumWidth(300)
        self.paramPanel = QWidget()
        self.paramPanel.setLayout(self.verticalLayout)
        self.scrollArea = QScrollArea()
        self.scrollArea.setWidget(self.paramPanel)
        self.scrollArea.setWidgetResizable(True)
        self.tabWidget.addTab(self.scrollArea, self.tr('Parameters'))
        self.webView = QWebView()

        html = None
        url = None
        isText, help = self._alg.help()
        if help is not None:
            if isText:
                html = help
            else:
                url = QUrl(help)
        else:
            html = self.tr('<h2>Sorry, no help is available for this '
                           'algorithm.</h2>')
        try:
            if html:
                self.webView.setHtml(html)
            elif url:
                self.webView.load(url)
        except:
            self.webView.setHtml(self.tr('<h2>Could not open help file :-( </h2>'))
        self.tabWidget.addTab(self.webView, 'Help')
        self.verticalLayout2.addWidget(self.tabWidget)
        self.verticalLayout2.addWidget(self.buttonBox)
        self.setLayout(self.verticalLayout2)
        self.buttonBox.accepted.connect(self.okPressed)
        self.buttonBox.rejected.connect(self.cancelPressed)
        QMetaObject.connectSlotsByName(self)

    def getAvailableDependencies(self):
        if self._algName is None:
            dependent = []
        else:
            dependent = self.model.getDependentAlgorithms(self._algName)
        opts = []
        for alg in self.model.algs.values():
            if alg.name not in dependent:
                opts.append(alg)
        return opts

    def getDependenciesPanel(self):
        return MultipleInputPanel([alg.algorithm.name for alg in self.getAvailableDependencies()])

    def showAdvancedParametersClicked(self):
        self.showAdvanced = not self.showAdvanced
        if self.showAdvanced:
            self.advancedButton.setText(self.tr('Hide advanced parameters'))
        else:
            self.advancedButton.setText(self.tr('Show advanced parameters'))
        for param in self._alg.parameters:
            if param.isAdvanced:
                self.labels[param.name].setVisible(self.showAdvanced)
                self.widgets[param.name].setVisible(self.showAdvanced)

    def getAvailableValuesOfType(self, paramType, outType=None):
        values = []
        inputs = self.model.inputs
        for i in inputs.values():
            param = i.param
            if isinstance(param, paramType):
                values.append(ValueFromInput(param.name))
        if outType is None:
            return values
        if self._algName is None:
            dependent = []
        else:
            dependent = self.model.getDependentAlgorithms(self._algName)
        for alg in self.model.algs.values():
            if alg.name not in dependent:
                for out in alg.algorithm.outputs:
                    if isinstance(out, outType):
                        values.append(ValueFromOutput(alg.name, out.name))

        return values

    def resolveValueDescription(self, value):
        if isinstance(value, ValueFromInput):
            return self.model.inputs[value.name].param.description
        else:
            alg = self.model.algs[value.alg]
            return self.tr("'%s' from algorithm '%s'") % (alg.algorithm.getOutputFromName(value.output).description, alg.description)

    def getWidgetFromParameter(self, param):
        if isinstance(param, ParameterRaster):
            item = QComboBox()
            layers = self.getAvailableValuesOfType(ParameterRaster, OutputRaster)
            if param.optional:
                item.addItem(self.NOT_SELECTED, None)
            for layer in layers:
                item.addItem(self.resolveValueDescription(layer), layer)
        elif isinstance(param, ParameterVector):
            item = QComboBox()
            layers = self.getAvailableValuesOfType(ParameterVector, OutputVector)
            if param.optional:
                item.addItem(self.NOT_SELECTED, None)
            for layer in layers:
                item.addItem(self.resolveValueDescription(layer), layer)
        elif isinstance(param, ParameterTable):
            item = QComboBox()
            tables = self.getAvailableValuesOfType(ParameterTable, OutputTable)
            layers = self.getAvailableValuesOfType(ParameterVector, OutputVector)
            if param.optional:
                item.addItem(self.NOT_SELECTED, None)
            for table in tables:
                item.addItem(self.resolveValueDescription(table), table)
            for layer in layers:
                item.addItem(self.resolveValueDescription(layer), layer)
        elif isinstance(param, ParameterBoolean):
            item = QComboBox()
            item.addItem('Yes')
            item.addItem('No')
            bools = self.getAvailableValuesOfType(ParameterBoolean, None)
            for b in bools:
                item.addItem(self.resolveValueDescription(b), b)
            if param.default:
                item.setCurrentIndex(0)
            else:
                item.setCurrentIndex(1)
        elif isinstance(param, ParameterSelection):
            item = QComboBox()
            item.addItems(param.options)
            item.setCurrentIndex(param.default or 1)
        elif isinstance(param, ParameterFixedTable):
            item = FixedTablePanel(param)
        elif isinstance(param, ParameterRange):
            item = RangePanel(param)
        elif isinstance(param, ParameterMultipleInput):
            if param.datatype == ParameterMultipleInput.TYPE_VECTOR_ANY:
                options = self.getAvailableValuesOfType(ParameterVector, OutputVector)
            else:
                options = self.getAvailableValuesOfType(ParameterRaster, OutputRaster)
            opts = []
            for opt in options:
                opts.append(self.resolveValueDescription(opt))
            item = MultipleInputPanel(opts)
        elif isinstance(param, ParameterString):
            strings = self.getAvailableValuesOfType(ParameterString, OutputString)
            options = [(self.resolveValueDescription(s), s) for s in strings]
            if param.multiline:
                item = MultilineTextPanel(options)
                item.setText(unicode(param.default or ""))
            else:
                item = QComboBox()
                item.setEditable(True)
                for desc, val in options:
                    item.addItem(desc, val)
                item.setEditText(unicode(param.default or ""))
        elif isinstance(param, ParameterTableField):
            item = QComboBox()
            item.setEditable(True)
            fields = self.getAvailableValuesOfType(ParameterTableField, None)
            for f in fields:
                item.addItem(self.resolveValueDescription(f), f)
        elif isinstance(param, ParameterNumber):
            item = QComboBox()
            item.setEditable(True)
            numbers = self.getAvailableValuesOfType(ParameterNumber, OutputNumber)
            for n in numbers:
                item.addItem(self.resolveValueDescription(n), n)
            item.setEditText(unicode(param.default))
        elif isinstance(param, ParameterCrs):
            item = CrsSelectionPanel(param.default)
        elif isinstance(param, ParameterExtent):
            item = QComboBox()
            item.setEditable(True)
            extents = self.getAvailableValuesOfType(ParameterExtent, OutputExtent)
            if self.canUseAutoExtent():
                item.addItem(self.USE_MIN_COVERING_EXTENT, None)
            for ex in extents:
                item.addItem(self.resolveValueDescription(ex), ex)
            if not self.canUseAutoExtent():
                item.setEditText(unicode(param.default))
        elif isinstance(param, ParameterPoint):
            item = QComboBox()
            item.setEditable(True)
            points = self.getAvailableValuesOfType(ParameterPoint)
            for p in points:
                item.addItem(self.resolveValueDescription(p), p)
            item.setEditText(unicode(param.default))
        elif isinstance(param, ParameterFile):
            item = QComboBox()
            item.setEditable(True)
            files = self.getAvailableValuesOfType(ParameterFile, OutputFile)
            for f in files:
                item.addItem(self.resolveValueDescription(f), f)
        elif isinstance(param, ParameterGeometryPredicate):
            item = GeometryPredicateSelectionPanel(param.enabledPredicates)
        else:
            item = QLineEdit()
            try:
                item.setText(unicode(param.default))
            except:
                pass
        return item

    def canUseAutoExtent(self):
        for param in self._alg.parameters:
            if isinstance(param, (ParameterRaster, ParameterVector, ParameterMultipleInput)):
                return True
        return False

    def setTableContent(self):
        params = self._alg.parameters
        outputs = self._alg.outputs
        visibleParams = [p for p in params if not p.hidden]
        visibleOutputs = [p for o in outputs if not o.hidden]
        self.tableWidget.setRowCount(len(visibleParams) + len(visibleOutputs))

        for i, param in visibleParams:
            item = QTableWidgetItem(param.description)
            item.setFlags(Qt.ItemIsEnabled)
            self.tableWidget.setItem(i, 0, item)
            item = self.getWidgetFromParameter(param)
            self.valueItems[param.name] = item
            self.tableWidget.setCellWidget(i, 1, item)
            self.tableWidget.setRowHeight(i, 22)

        for i, output in visibleOutputs:
            item = QTableWidgetItem(output.description + '<'
                                    + output.__module__.split('.')[-1] + '>')
            item.setFlags(Qt.ItemIsEnabled)
            self.tableWidget.setItem(i, 0, item)
            item = QLineEdit()
            if hasattr(item, 'setPlaceholderText'):
                item.setPlaceholderText(ModelerParametersDialog.ENTER_NAME)
            self.valueItems[output.name] = item
            self.tableWidget.setCellWidget(i, 1, item)
            self.tableWidget.setRowHeight(i, 22)

    def setComboBoxValue(self, combo, value, param):
        if isinstance(value, list):
            value = value[0]
        items = [combo.itemData(i) for i in range(combo.count())]
        try:
            idx = items.index(value)
            combo.setCurrentIndex(idx)
            return
        except ValueError:
            pass
        if combo.isEditable():
            if value is not None:
                combo.setEditText(unicode(value))
        elif isinstance(param, ParameterSelection):
            combo.setCurrentIndex(int(value))
        elif isinstance(param, ParameterBoolean):
            if value:
                combo.setCurrentIndex(0)
            else:
                combo.setCurrentIndex(1)

    def setPreviousValues(self):
        if self._algName is not None:
            alg = self.model.algs[self._algName]
            self.descriptionBox.setText(alg.description)
            for param in alg.algorithm.parameters:
                if param.hidden:
                    continue
                widget = self.valueItems[param.name]
                if param.name in alg.params:
                    value = alg.params[param.name]
                else:
                    value = param.default
                if isinstance(param, (
                        ParameterRaster,
                        ParameterVector,
                        ParameterTable,
                        ParameterTableField,
                        ParameterSelection,
                        ParameterNumber,
                        ParameterBoolean,
                        ParameterExtent,
                        ParameterFile,
                        ParameterPoint
                )):
                    self.setComboBoxValue(widget, value, param)
                elif isinstance(param, ParameterString):
                    if param.multiline:
                        widget.setValue(value)
                    else:
                        self.setComboBoxValue(widget, value, param)
                elif isinstance(param, ParameterCrs):
                    widget.setAuthId(value)
                elif isinstance(param, ParameterFixedTable):
                    pass  # TODO!
                elif isinstance(param, ParameterMultipleInput):
                    if param.datatype == ParameterMultipleInput.TYPE_VECTOR_ANY:
                        options = self.getAvailableValuesOfType(ParameterVector, OutputVector)
                    else:
                        options = self.getAvailableValuesOfType(ParameterRaster, OutputRaster)
                    selected = []
                    for i, opt in enumerate(options):
                        if opt in value:
                            selected.append(i)
                    widget.setSelectedItems(selected)
                elif isinstance(param, ParameterGeometryPredicate):
                    widget.setValue(value)

            for name, out in alg.outputs.iteritems():
                widget = self.valueItems[name].setText(out.description)

            selected = []
            dependencies = self.getAvailableDependencies()
            for idx, dependency in enumerate(dependencies):
                if dependency.name in alg.dependencies:
                    selected.append(idx)

            self.dependenciesPanel.setSelectedItems(selected)

    def createAlgorithm(self):
        alg = Algorithm(self._alg.commandLineName())
        alg.setName(self.model)
        alg.description = self.descriptionBox.text()
        params = self._alg.parameters
        outputs = self._alg.outputs
        for param in params:
            if param.hidden:
                continue
            if not self.setParamValue(alg, param, self.valueItems[param.name]):
                return None
        for output in outputs:
            if not output.hidden:
                name = unicode(self.valueItems[output.name].text())
                if name.strip() != '' and name != ModelerParametersDialog.ENTER_NAME:
                    alg.outputs[output.name] = ModelerOutput(name)

        selectedOptions = self.dependenciesPanel.selectedoptions
        availableDependencies = self.getAvailableDependencies()
        for selected in selectedOptions:
            alg.dependencies.append(availableDependencies[selected].name)

        return alg

    def setParamValueLayerOrTable(self, alg, param, widget):
        idx = widget.currentIndex()
        if idx < 0:
            return False
        else:
            value = widget.itemData(widget.currentIndex())
            alg.params[param.name] = value
            return True

    def setParamTableFieldValue(self, alg, param, widget):
        idx = widget.findText(widget.currentText())
        if idx < 0:
            s = unicode(widget.currentText()).strip()
            if s == '':
                if param.optional:
                    alg.params[param.name] = None
                    return True
                else:
                    return False
            else:
                alg.params[param.name] = s
                return True
        else:
            alg.params[param.name] = widget.itemData(widget.currentIndex())
        return True

    def setParamStringValue(self, alg, param, widget):
        if param.multiline:
            value = widget.getValue()
            option = widget.getOption()
            if option == MultilineTextPanel.USE_TEXT:
                if value == '':
                    if param.optional:
                        alg.params[param.name] = None
                        return True
                    else:
                        return False
                else:
                    alg.params[param.name] = value
            else:
                alg.params[param.name] = value
        else:
            idx = widget.findText(widget.currentText())
            if idx < 0:
                value = widget.currentText().strip()
                if value == '':
                    if param.optional:
                        alg.params[param.name] = None
                        return True
                    else:
                        return False
                else:
                    alg.params[param.name] = value
            else:
                alg.params[param.name] = widget.itemData(widget.currentIndex())
        return True

    def setParamFileValue(self, alg, param, widget):
        idx = widget.findText(widget.currentText())
        if idx < 0:
            value = widget.currentText()
        else:
            value = widget.itemData(widget.currentIndex())
        alg.params[param.name] = value
        return True

    def setParamNumberValue(self, alg, param, widget):
        idx = widget.findText(widget.currentText())
        if idx < 0:
            s = widget.currentText().strip()
            if s:
                try:
                    value = float(s)
                except:
                    return False
            elif param.optional:
                value = None
            else:
                return False
        else:
            value = widget.itemData(widget.currentIndex())
        alg.params[param.name] = value
        return True

    def setParamExtentValue(self, alg, param, widget):
        idx = widget.findText(widget.currentText())
        if idx < 0:
            s = unicode(widget.currentText()).strip()
            if s:
                try:
                    tokens = s.split(',')
                    if len(tokens) != 4:
                        return False
                    for token in tokens:
                        float(token)
                except:
                    return False
            elif param.optional:
                s = None
            else:
                return False
            alg.params[param.name] = [s]
        else:
            value = widget.itemData(widget.currentIndex())
            alg.params[param.name] = value
        return True

    def setParamPointValue(self, alg, param, widget):
        idx = widget.findText(widget.currentText())
        if idx < 0:
            s = unicode(widget.currentText()).strip()
            if s:
                try:
                    tokens = s.split(',')
                    if len(tokens) != 2:
                        return False
                    for token in tokens:
                        float(token)
                except:
                    return False
            elif param.optional:
                s = None
            else:
                return False
            alg.params[param.name] = [s]
        else:
            value = widget.itemData(widget.currentIndex())
            alg.params[param.name] = value
        return True

    def setParamValue(self, alg, param, widget):
        if isinstance(param, (ParameterRaster, ParameterVector,
                              ParameterTable)):
            return self.setParamValueLayerOrTable(alg, param, widget)
        elif isinstance(param, ParameterBoolean):
            if widget.currentIndex() < 2:
                value = widget.currentIndex() == 0
            else:
                value = widget.itemData(widget.currentIndex())
            alg.params[param.name] = value
            return True
        elif isinstance(param, ParameterString):
            return self.setParamStringValue(alg, param, widget)
        elif isinstance(param, ParameterNumber):
            return self.setParamNumberValue(alg, param, widget)
        elif isinstance(param, ParameterExtent):
            return self.setParamExtentValue(alg, param, widget)
        elif isinstance(param, ParameterPoint):
            return self.setParamPointValue(alg, param, widget)
        elif isinstance(param, ParameterFile):
            return self.setParamFileValue(alg, param, widget)
        elif isinstance(param, ParameterSelection):
            alg.params[param.name] = widget.currentIndex()
            return True
        elif isinstance(param, ParameterRange):
            alg.params[param.name] = widget.getValue()
            return True
        elif isinstance(param, ParameterCrs):
            authid = widget.getValue()
            if authid is None and not param.optional:
                return False
            alg.params[param.name] = authid
            return True
        elif isinstance(param, ParameterFixedTable):
            table = widget.table
            if not bool(table) and not param.optional:
                return False
            alg.params[param.name] = ParameterFixedTable.tableToString(table)
            return True
        elif isinstance(param, ParameterTableField):
            return self.setParamTableFieldValue(alg, param, widget)
        elif isinstance(param, ParameterMultipleInput):
            if param.datatype == ParameterMultipleInput.TYPE_VECTOR_ANY:
                options = self.getAvailableValuesOfType(ParameterVector, OutputVector)
            else:
                options = self.getAvailableValuesOfType(ParameterRaster, OutputRaster)
            values = [options[i] for i in widget.selectedoptions]
            if len(values) == 0 and not param.optional:
                return False
            alg.params[param.name] = values
            return True
        elif isinstance(param, ParameterGeometryPredicate):
            alg.params[param.name] = widget.value()
            return True
        else:
            alg.params[param.name] = unicode(widget.text())
            return True

    def okPressed(self):
        self.alg = self.createAlgorithm()
        if self.alg is not None:
            self.close()
        else:
            QMessageBox.warning(self, self.tr('Unable to add algorithm'),
                                self.tr('Wrong or missing parameter values'))

    def cancelPressed(self):
        self.alg = None
        self.close()
Example #9
0
    def setupUi(self):
        self.labels = {}
        self.widgets = {}
        self.checkBoxes = {}
        self.showAdvanced = False
        self.valueItems = {}
        self.dependentItems = {}
        self.resize(650, 450)
        self.buttonBox = QDialogButtonBox()
        self.buttonBox.setOrientation(Qt.Horizontal)
        self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel
                                          | QDialogButtonBox.Ok)
        tooltips = self._alg.getParameterDescriptions()
        self.setSizePolicy(QSizePolicy.Expanding,
                           QSizePolicy.Expanding)
        self.verticalLayout = QVBoxLayout()
        self.verticalLayout.setSpacing(5)
        self.verticalLayout.setMargin(20)

        hLayout = QHBoxLayout()
        hLayout.setSpacing(5)
        hLayout.setMargin(0)
        descriptionLabel = QLabel(self.tr("Description"))
        self.descriptionBox = QLineEdit()
        self.descriptionBox.setText(self._alg.name)
        hLayout.addWidget(descriptionLabel)
        hLayout.addWidget(self.descriptionBox)
        self.verticalLayout.addLayout(hLayout)
        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)
        self.verticalLayout.addWidget(line)

        for param in self._alg.parameters:
            if param.isAdvanced:
                self.advancedButton = QPushButton()
                self.advancedButton.setText(self.tr('Show advanced parameters'))
                self.advancedButton.clicked.connect(
                    self.showAdvancedParametersClicked)
                advancedButtonHLayout = QHBoxLayout()
                advancedButtonHLayout.addWidget(self.advancedButton)
                advancedButtonHLayout.addStretch()
                self.verticalLayout.addLayout(advancedButtonHLayout)
                break
        for param in self._alg.parameters:
            if param.hidden:
                continue
            desc = param.description
            if isinstance(param, ParameterExtent):
                desc += self.tr('(xmin, xmax, ymin, ymax)')
            if isinstance(param, ParameterPoint):
                desc += self.tr('(x, y)')
            label = QLabel(desc)
            self.labels[param.name] = label
            widget = self.getWidgetFromParameter(param)
            self.valueItems[param.name] = widget
            if param.name in tooltips.keys():
                tooltip = tooltips[param.name]
            else:
                tooltip = param.description
            label.setToolTip(tooltip)
            widget.setToolTip(tooltip)
            if param.isAdvanced:
                label.setVisible(self.showAdvanced)
                widget.setVisible(self.showAdvanced)
                self.widgets[param.name] = widget
            self.verticalLayout.addWidget(label)
            self.verticalLayout.addWidget(widget)

        for output in self._alg.outputs:
            if output.hidden:
                continue
            if isinstance(output, (OutputRaster, OutputVector, OutputTable,
                                   OutputHTML, OutputFile, OutputDirectory)):
                label = QLabel(output.description + '<'
                               + output.__class__.__name__ + '>')
                item = QLineEdit()
                if hasattr(item, 'setPlaceholderText'):
                    item.setPlaceholderText(ModelerParametersDialog.ENTER_NAME)
                self.verticalLayout.addWidget(label)
                self.verticalLayout.addWidget(item)
                self.valueItems[output.name] = item

        label = QLabel(' ')
        self.verticalLayout.addWidget(label)
        label = QLabel(self.tr('Parent algorithms'))
        self.dependenciesPanel = self.getDependenciesPanel()
        self.verticalLayout.addWidget(label)
        self.verticalLayout.addWidget(self.dependenciesPanel)

        self.verticalLayout.addStretch(1000)
        self.setLayout(self.verticalLayout)

        self.setPreviousValues()
        self.setWindowTitle(self._alg.name)
        self.verticalLayout2 = QVBoxLayout()
        self.verticalLayout2.setSpacing(2)
        self.verticalLayout2.setMargin(0)
        self.tabWidget = QTabWidget()
        self.tabWidget.setMinimumWidth(300)
        self.paramPanel = QWidget()
        self.paramPanel.setLayout(self.verticalLayout)
        self.scrollArea = QScrollArea()
        self.scrollArea.setWidget(self.paramPanel)
        self.scrollArea.setWidgetResizable(True)
        self.tabWidget.addTab(self.scrollArea, self.tr('Parameters'))
        self.webView = QWebView()

        html = None
        url = None
        isText, help = self._alg.help()
        if help is not None:
            if isText:
                html = help
            else:
                url = QUrl(help)
        else:
            html = self.tr('<h2>Sorry, no help is available for this '
                           'algorithm.</h2>')
        try:
            if html:
                self.webView.setHtml(html)
            elif url:
                self.webView.load(url)
        except:
            self.webView.setHtml(self.tr('<h2>Could not open help file :-( </h2>'))
        self.tabWidget.addTab(self.webView, 'Help')
        self.verticalLayout2.addWidget(self.tabWidget)
        self.verticalLayout2.addWidget(self.buttonBox)
        self.setLayout(self.verticalLayout2)
        self.buttonBox.accepted.connect(self.okPressed)
        self.buttonBox.rejected.connect(self.cancelPressed)
        QMetaObject.connectSlotsByName(self)
Example #10
0
class AdvancedSearch(EntityEditorDialog):
    search_triggered = pyqtSignal(dict)

    def __init__(self, entity, parent, initial_values: dict = None):
        super().__init__(entity, parent=parent)
        self.parent = parent

        self.initial_values = initial_values or {}

        for k, v in self.initial_values.items():
            for mapper in self._attrMappers:
                if mapper.attributeName() == k:
                    mapper.valueHandler().setValue(v)

    def _init_gui(self, show_str_tab: bool, is_party_unit: bool=False):
        # Setup base elements
        self.gridLayout = QGridLayout(self)
        self.gridLayout.setObjectName('glMain')
        self.gridLayout.addLayout(
            self.vlNotification, 0, 0, 1, 1
        )
        column_widget_area = self._setup_columns_content_area()
        self.gridLayout.addWidget(
            column_widget_area, 1, 0, 1, 1
        )
        # Add notification for mandatory columns if applicable
        next_row = 2
        # Set title
        search_trans = self.tr('Advanced Search')
        if self._entity.label is not None:
            if self._entity.label != '':
                title_str = self._entity.label
            else:
                title_str = format_name(self._entity.short_name)
        else:
            title_str = format_name(self._entity.short_name)

        title = '{0} {1}'.format(title_str, search_trans)
        self.do_not_check_dirty = True
        self.setWindowTitle(title)

        self.buttonBox = QDialogButtonBox(self)
        self.buttonBox.setObjectName('buttonBox')
        self.gridLayout.addWidget(
            self.buttonBox, next_row, 0, 1, 1
        )

        self.buttonBox.setOrientation(Qt.Horizontal)

        self.search = QPushButton(
            QApplication.translate(
                'EntityEditorDialog', 'Search'
            )
        )
        self.buttonBox.addButton(
            self.search, QDialogButtonBox.ActionRole
        )
        self.buttonBox.setStandardButtons(
            QDialogButtonBox.Close | QDialogButtonBox.Reset
        )
        self.search.clicked.connect(self.on_search)
        self.buttonBox.button(QDialogButtonBox.Close).clicked.connect(self.reject)
        self.buttonBox.button(QDialogButtonBox.Reset).clicked.connect(self.reset)

    def reset(self):
        """
        Resets the dialog back to an empty/no filter status
        """
        for column in self._entity.columns.values():
            if column.name in entity_display_columns(self._entity):
                if column.name == 'id':
                    continue
                handler = self.attribute_mappers[
                    column.name].valueHandler()
                handler.setValue(handler.default())

    def on_search(self):
        """
        Builds a dictionary of the desired search values and emits the search_triggered signal
        """
        self.search_triggered.emit(self.current_search_data())

    def current_search_data(self) -> dict:
        """
        Returns a dictionary representing the current search data
        """
        search_data = {}
        for column in self._entity.columns.values():
            if column.name in entity_display_columns(self._entity):
                if column.name == 'id':
                    continue
                handler = self.attribute_mappers[
                    column.name].valueHandler()
                value = handler.value()
                if value != handler.default() and bool(value):
                    search_data[column.name] = value
        return search_data

    def _setup_columns_content_area(self):
        # Only use this if entity supports documents
        # self.entity_tab_widget = None
        self.doc_widget = None

        self.entity_scroll_area = QScrollArea(self)
        self.entity_scroll_area.setFrameShape(QFrame.NoFrame)
        self.entity_scroll_area.setWidgetResizable(True)
        self.entity_scroll_area.setObjectName('scrollArea')

        # Grid layout for controls
        self.gl = QGridLayout(self.scroll_widget_contents)
        self.gl.setObjectName('gl_widget_contents')

        # Append column labels and widgets
        table_name = self._entity.name
        columns = table_column_names(table_name)
        # Iterate entity column and assert if they exist
        row_id = 0
        for column_name, column_widget in self.column_widgets.items():
            c = self.columns[column_name]

            if c.name in self.exclude_columns:
                continue
            if isinstance(c, MultipleSelectColumn):
                continue
            if c.name not in columns and not isinstance(c, VirtualColumn):
                continue

            if column_widget is not None:
                header = c.ui_display()
                self.c_label = QLabel(self.scroll_widget_contents)

                self.c_label.setText(header)
                self.gl.addWidget(self.c_label, row_id, 0, 1, 1)

                if c.TYPE_INFO == 'AUTO_GENERATED':
                    column_widget.setReadOnly(False)
                    column_widget.btn_load.hide()
                self.gl.addWidget(column_widget, row_id, 1, 1, 1)

                col_name = c.name

                # Add widget to MapperMixin collection
                self.addMapping(
                    col_name,
                    column_widget,
                    c.mandatory,
                    pseudoname=c.ui_display()
                )

                # Bump up row_id
                row_id += 1

        self.entity_scroll_area.setWidget(self.scroll_widget_contents)
        if self.entity_tab_widget is None:
            self.entity_tab_widget = QTabWidget(self)
        # Check if there are children and add foreign key browsers

        # Add primary tab if necessary
        self._add_primary_attr_widget()
        # self.entity_tab_widget.setTabEnabled(0, False)  # enable/disable the tab
        # set the style sheet
        self.setStyleSheet(
            "QTabBar::tab::selected {width: 0; height: 0; margin: 0; "
            "padding: 0; border: none;} ")
        # Return the correct widget
        if self.entity_tab_widget is not None:
            return self.entity_tab_widget

        return self.entity_scroll_area
Example #11
0
    def show(self, *args, title: str = 'Parameter einstellen',
             scrollable: bool = False):
        '''
        render parameters and elements in parent

        Parameters
        ----------
        args : optional
            arguments for appending parameter layout to parent
            (like x, y if parent is grid layout)
        title : str, optional
            title of the parameter dialog, defaults to 'Parameter einstellen'
        scrollable : bool, optional
            a scrollbar will be added to both preview and dialog if True,
            recommended if there are a lot of parameters, defaults to not
            scrollable
        '''
        if self.parent is None:
            raise Exception("can't render Params object with no parent set")

        # Debug: function to automatically write a help file with all params
        # with empty texts, should be removed in production
        if (settings.DEBUG and getattr(self, 'help_file', None) and
            not os.path.exists(self.help_file)):
            if not os.path.exists(self.HELP_PATH):
                os.mkdir(self.HELP_PATH)
            with open(self.help_file, 'w') as json_file:
                json.dump(self.help_dict, json_file, indent=4)

        self.dialog = ParamsDialog(parent=None,
                                   help_text=self.help_dict['beschreibung'],
                                   title=title)

        self.parent.addLayout(self.layout, *args)

        if scrollable:
            frame = QFrame()
            scroll_area = QScrollArea()
            layout = QVBoxLayout()
            layout.setSpacing(5)
            frame.setLayout(layout)
            scroll_area.setWidget(frame)
            scroll_area.setWidgetResizable(True)
            scroll_area.setFixedHeight(400)
            self.layout.addWidget(scroll_area)
        else:
            layout = self.layout

        for element in self._elements:
            if isinstance(element, QLayoutItem):
                layout.addItem(element)
            # overview
            elif not getattr(element, 'hide_in_overview', None):
                element.draw(layout)
            self.dialog.draw(element)

        if not self.editable:
            return

        row = QHBoxLayout()
        button = QPushButton(self.button_label)
        icon = QIcon(os.path.join(settings.IMAGE_PATH, 'iconset_mob',
                                  '20190619_iconset_mob_edit_1.png'))
        button.setIcon(icon)
        tool_tip = self.help_dict.get('tooltip', None)
        button.setToolTip(tool_tip)
        row.addItem(
            QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Minimum))
        row.addWidget(button)
        self.layout.addItem(
            QSpacerItem(10, 10, QSizePolicy.Fixed, QSizePolicy.Minimum))
        self.layout.addLayout(row)

        button.clicked.connect(self.show_dialog)
Example #12
0
    def _setup_columns_content_area(self):
        # Only use this if entity supports documents
        # self.entity_tab_widget = None
        self.doc_widget = None

        self.entity_scroll_area = QScrollArea(self)
        self.entity_scroll_area.setFrameShape(QFrame.NoFrame)
        self.entity_scroll_area.setWidgetResizable(True)
        self.entity_scroll_area.setObjectName('scrollArea')

        # Grid layout for controls
        self.gl = QGridLayout(self.scroll_widget_contents)
        self.gl.setObjectName('gl_widget_contents')

        # Append column labels and widgets
        table_name = self._entity.name
        columns = table_column_names(table_name)
        # Iterate entity column and assert if they exist
        row_id = 0
        for column_name, column_widget in self.column_widgets.items():
            c = self.columns[column_name]

            if c.name in self.exclude_columns:
                continue
            if isinstance(c, MultipleSelectColumn):
                continue
            if c.name not in columns and not isinstance(c, VirtualColumn):
                continue

            if column_widget is not None:
                header = c.ui_display()
                self.c_label = QLabel(self.scroll_widget_contents)

                self.c_label.setText(header)
                self.gl.addWidget(self.c_label, row_id, 0, 1, 1)

                if c.TYPE_INFO == 'AUTO_GENERATED':
                    column_widget.setReadOnly(False)
                    column_widget.btn_load.hide()
                self.gl.addWidget(column_widget, row_id, 1, 1, 1)

                col_name = c.name

                # Add widget to MapperMixin collection
                self.addMapping(
                    col_name,
                    column_widget,
                    c.mandatory,
                    pseudoname=c.ui_display()
                )

                # Bump up row_id
                row_id += 1

        self.entity_scroll_area.setWidget(self.scroll_widget_contents)
        if self.entity_tab_widget is None:
            self.entity_tab_widget = QTabWidget(self)
        # Check if there are children and add foreign key browsers

        # Add primary tab if necessary
        self._add_primary_attr_widget()
        # self.entity_tab_widget.setTabEnabled(0, False)  # enable/disable the tab
        # set the style sheet
        self.setStyleSheet(
            "QTabBar::tab::selected {width: 0; height: 0; margin: 0; "
            "padding: 0; border: none;} ")
        # Return the correct widget
        if self.entity_tab_widget is not None:
            return self.entity_tab_widget

        return self.entity_scroll_area
Example #13
0
    def setupUi(self, DistroMap):
        DistroMap.setObjectName("DistroMap")
        DistroMap.resize(439, 657)
        self.gridLayout_3 = QGridLayout(DistroMap)
        self.gridLayout_3.setObjectName("gridLayout_3")
        self.scrollArea = QScrollArea(DistroMap)
        self.scrollArea.setWidgetResizable(True)
        self.scrollArea.setObjectName("scrollArea")
        self.scrollAreaWidgetContents = QWidget()
        self.scrollAreaWidgetContents.setGeometry(QRect(0, 0, 419, 573))
        self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
        self.gridLayout_6 = QGridLayout(self.scrollAreaWidgetContents)
        self.gridLayout_6.setObjectName("gridLayout_6")
        self.verticalLayout = QVBoxLayout()
        self.verticalLayout.setObjectName("verticalLayout")
        self.label_5 = QLabel(self.scrollAreaWidgetContents)
        self.label_5.setObjectName("label_5")
        self.verticalLayout.addWidget(self.label_5)
        self.comboLocalities = QComboBox(self.scrollAreaWidgetContents)
        self.comboLocalities.setObjectName("comboLocalities")
        self.verticalLayout.addWidget(self.comboLocalities)
        self.gridLayout_6.addLayout(self.verticalLayout, 1, 0, 1, 1)
        self.horizontalLayout_6 = QHBoxLayout()
        self.horizontalLayout_6.setObjectName("horizontalLayout_6")
        self.verticalLayout_13 = QVBoxLayout()
        self.verticalLayout_13.setObjectName("verticalLayout_13")
        self.label_19 = QLabel(self.scrollAreaWidgetContents)
        self.label_19.setObjectName("label_19")
        self.verticalLayout_13.addWidget(self.label_19)
        self.horizontalLayout_3 = QHBoxLayout()
        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
        self.spnOutWidth = QSpinBox(self.scrollAreaWidgetContents)
        self.spnOutWidth.setMaximum(999999)
        self.spnOutWidth.setProperty("value", 325)
        self.spnOutWidth.setObjectName("spnOutWidth")
        self.horizontalLayout_3.addWidget(self.spnOutWidth)
        self.label_20 = QLabel(self.scrollAreaWidgetContents)
        self.label_20.setAlignment(Qt.AlignCenter)
        self.label_20.setObjectName("label_20")
        self.horizontalLayout_3.addWidget(self.label_20)
        self.spnOutHeight = QSpinBox(self.scrollAreaWidgetContents)
        self.spnOutHeight.setMaximum(999999)
        self.spnOutHeight.setProperty("value", 299)
        self.spnOutHeight.setObjectName("spnOutHeight")
        self.horizontalLayout_3.addWidget(self.spnOutHeight)
        self.verticalLayout_13.addLayout(self.horizontalLayout_3)
        self.horizontalLayout_6.addLayout(self.verticalLayout_13)
        self.horizontalLayout_5 = QHBoxLayout()
        self.horizontalLayout_5.setObjectName("horizontalLayout_5")
        self.verticalLayout_14 = QVBoxLayout()
        self.verticalLayout_14.setObjectName("verticalLayout_14")
        self.label_21 = QLabel(self.scrollAreaWidgetContents)
        sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.label_21.sizePolicy().hasHeightForWidth())
        self.label_21.setSizePolicy(sizePolicy)
        self.label_21.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
        self.label_21.setObjectName("label_21")
        self.verticalLayout_14.addWidget(self.label_21)
        self.horizontalLayout_4 = QHBoxLayout()
        self.horizontalLayout_4.setObjectName("horizontalLayout_4")
        spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.horizontalLayout_4.addItem(spacerItem)
        self.btnColour = QPushButton(self.scrollAreaWidgetContents)
        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.btnColour.sizePolicy().hasHeightForWidth())
        self.btnColour.setSizePolicy(sizePolicy)
        self.btnColour.setObjectName("btnColour")
        self.horizontalLayout_4.addWidget(self.btnColour)
        self.verticalLayout_14.addLayout(self.horizontalLayout_4)
        self.horizontalLayout_5.addLayout(self.verticalLayout_14)
        self.frmColour = QFrame(self.scrollAreaWidgetContents)
        sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.frmColour.sizePolicy().hasHeightForWidth())
        self.frmColour.setSizePolicy(sizePolicy)
        self.frmColour.setMinimumSize(QSize(45, 45))
        self.frmColour.setSizeIncrement(QSize(1, 1))
        self.frmColour.setBaseSize(QSize(0, 0))
        self.frmColour.setFrameShape(QFrame.StyledPanel)
        self.frmColour.setFrameShadow(QFrame.Raised)
        self.frmColour.setObjectName("frmColour")
        self.horizontalLayout_5.addWidget(self.frmColour)
        self.horizontalLayout_6.addLayout(self.horizontalLayout_5)
        self.gridLayout_6.addLayout(self.horizontalLayout_6, 4, 0, 1, 1)
        self.verticalLayout_2 = QVBoxLayout()
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.label_6 = QLabel(self.scrollAreaWidgetContents)
        self.label_6.setObjectName("label_6")
        self.verticalLayout_2.addWidget(self.label_6)
        self.comboTaxonField = QComboBox(self.scrollAreaWidgetContents)
        self.comboTaxonField.setObjectName("comboTaxonField")
        self.verticalLayout_2.addWidget(self.comboTaxonField)
        self.gridLayout_6.addLayout(self.verticalLayout_2, 2, 0, 1, 1)
        self.verticalLayout_5 = QVBoxLayout()
        self.verticalLayout_5.setObjectName("verticalLayout_5")
        self.label_9 = QLabel(self.scrollAreaWidgetContents)
        self.label_9.setObjectName("label_9")
        self.verticalLayout_5.addWidget(self.label_9)
        self.horizontalLayout = QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.leOutDir = QLineEdit(self.scrollAreaWidgetContents)
        self.leOutDir.setPlaceholderText("")
        self.leOutDir.setObjectName("leOutDir")
        self.horizontalLayout.addWidget(self.leOutDir)
        self.btnBrowse = QPushButton(self.scrollAreaWidgetContents)
        self.btnBrowse.setObjectName("btnBrowse")
        self.horizontalLayout.addWidget(self.btnBrowse)
        self.verticalLayout_5.addLayout(self.horizontalLayout)
        self.gridLayout_6.addLayout(self.verticalLayout_5, 5, 0, 1, 1)
        self.verticalLayout_6 = QVBoxLayout()
        self.verticalLayout_6.setObjectName("verticalLayout_6")
        self.label = QLabel(self.scrollAreaWidgetContents)
        self.label.setObjectName("label")
        self.verticalLayout_6.addWidget(self.label)
        self.gridLayout = QGridLayout()
        self.gridLayout.setObjectName("gridLayout")
        self.label_2 = QLabel(self.scrollAreaWidgetContents)
        self.label_2.setObjectName("label_2")
        self.gridLayout.addWidget(self.label_2, 0, 0, 1, 1)
        self.comboSecondary = QComboBox(self.scrollAreaWidgetContents)
        self.comboSecondary.setObjectName("comboSecondary")
        self.gridLayout.addWidget(self.comboSecondary, 1, 1, 1, 1)
        self.comboSurface = QComboBox(self.scrollAreaWidgetContents)
        self.comboSurface.setObjectName("comboSurface")
        self.gridLayout.addWidget(self.comboSurface, 2, 1, 1, 1)
        self.label_3 = QLabel(self.scrollAreaWidgetContents)
        self.label_3.setObjectName("label_3")
        self.gridLayout.addWidget(self.label_3, 1, 0, 1, 1)
        self.label_4 = QLabel(self.scrollAreaWidgetContents)
        self.label_4.setObjectName("label_4")
        self.gridLayout.addWidget(self.label_4, 2, 0, 1, 1)
        self.comboBase = QComboBox(self.scrollAreaWidgetContents)
        self.comboBase.setObjectName("comboBase")
        self.gridLayout.addWidget(self.comboBase, 0, 1, 1, 1)
        self.gridLayout.setColumnStretch(0, 1)
        self.gridLayout.setColumnStretch(1, 3)
        self.verticalLayout_6.addLayout(self.gridLayout)
        self.gridLayout_6.addLayout(self.verticalLayout_6, 0, 0, 1, 1)
        self.verticalLayout_3 = QVBoxLayout()
        self.verticalLayout_3.setObjectName("verticalLayout_3")
        self.label_7 = QLabel(self.scrollAreaWidgetContents)
        self.label_7.setObjectName("label_7")
        self.verticalLayout_3.addWidget(self.label_7)
        self.comboGrid = QComboBox(self.scrollAreaWidgetContents)
        self.comboGrid.setObjectName("comboGrid")
        self.verticalLayout_3.addWidget(self.comboGrid)
        self.verticalLayout_4 = QVBoxLayout()
        self.verticalLayout_4.setObjectName("verticalLayout_4")
        self.label_8 = QLabel(self.scrollAreaWidgetContents)
        self.label_8.setObjectName("label_8")
        self.verticalLayout_4.addWidget(self.label_8)
        self.gridLayout_2 = QGridLayout()
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.leMaxY = QLineEdit(self.scrollAreaWidgetContents)
        self.leMaxY.setObjectName("leMaxY")
        self.gridLayout_2.addWidget(self.leMaxY, 0, 1, 1, 1)
        self.leMinX = QLineEdit(self.scrollAreaWidgetContents)
        self.leMinX.setObjectName("leMinX")
        self.gridLayout_2.addWidget(self.leMinX, 1, 0, 1, 1)
        self.leMaxX = QLineEdit(self.scrollAreaWidgetContents)
        self.leMaxX.setObjectName("leMaxX")
        self.gridLayout_2.addWidget(self.leMaxX, 1, 2, 1, 1)
        self.leMinY = QLineEdit(self.scrollAreaWidgetContents)
        self.leMinY.setObjectName("leMinY")
        self.gridLayout_2.addWidget(self.leMinY, 2, 1, 1, 1)
        self.btnExtent = QPushButton(self.scrollAreaWidgetContents)
        self.btnExtent.setObjectName("btnExtent")
        self.gridLayout_2.addWidget(self.btnExtent, 1, 1, 1, 1)
        self.verticalLayout_4.addLayout(self.gridLayout_2)
        self.verticalLayout_3.addLayout(self.verticalLayout_4)
        self.gridLayout_6.addLayout(self.verticalLayout_3, 3, 0, 1, 1)
        self.scrollArea.setWidget(self.scrollAreaWidgetContents)
        self.gridLayout_3.addWidget(self.scrollArea, 0, 0, 1, 1)
        self.buttonBox = QDialogButtonBox(DistroMap)
        self.buttonBox.setOrientation(Qt.Horizontal)
        self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok)
        self.buttonBox.setObjectName("buttonBox")
        self.gridLayout_3.addWidget(self.buttonBox, 2, 0, 1, 1)
        self.progressBar = QProgressBar(DistroMap)
        self.progressBar.setProperty("value", 0)
        self.progressBar.setObjectName("progressBar")
        self.gridLayout_3.addWidget(self.progressBar, 1, 0, 1, 1)

        self.retranslateUi(DistroMap)
        self.buttonBox.rejected.connect(DistroMap.reject)
        QMetaObject.connectSlotsByName(DistroMap)
Example #14
0
    def _setup_columns_content_area(self):
        # Only use this if entity supports documents
        # self.entity_tab_widget = None
        self.doc_widget = None

        self.entity_scroll_area = QScrollArea(self)
        self.entity_scroll_area.setFrameShape(QFrame.NoFrame)
        self.entity_scroll_area.setWidgetResizable(True)
        self.entity_scroll_area.setObjectName('scrollArea')

        # Grid layout for controls
        self.gl = QGridLayout(self.scroll_widget_contents)
        self.gl.setObjectName('gl_widget_contents')

        # Append column labels and widgets
        table_name = self._entity.name
        columns = table_column_names(table_name)
        # Iterate entity column and assert if they exist
        row_id = 0
        for column_name, column_widget in self.column_widgets.items():
            c = self.columns[column_name]
            if c.name in self.exclude_columns:
                continue
            if c.name not in columns and not isinstance(c, VirtualColumn):
                continue

            if column_widget is not None:
                header = c.ui_display()
                self.c_label = QLabel(self.scroll_widget_contents)

                # Format label text if it is a mandatory field
                if c.mandatory:
                    header = '{0} *'.format(c.ui_display())
                    # Highlight asterisk
                    header = self._highlight_asterisk(header)

                self.c_label.setText(header)
                self.gl.addWidget(self.c_label, row_id, 0, 1, 1)

                self.column_widget = column_widget
                self.gl.addWidget(self.column_widget, row_id, 1, 1, 1)

                # Add user tip if specified for the column configuration
                if c.user_tip:
                    self.tip_lbl = UserTipLabel(user_tip=c.user_tip)
                    self.gl.addWidget(self.tip_lbl, row_id, 2, 1, 1)

                if c.mandatory and not self.has_mandatory:
                    self.has_mandatory = True

                col_name = c.name
                # Replace name accordingly based on column type
                if isinstance(c, MultipleSelectColumn):
                    col_name = c.model_attribute_name

                # Add widget to MapperMixin collection
                self.addMapping(col_name,
                                self.column_widget,
                                c.mandatory,
                                pseudoname=c.ui_display())

                # Bump up row_id
                row_id += 1

        self.entity_scroll_area.setWidget(self.scroll_widget_contents)

        if self.entity_tab_widget is None:
            self.entity_tab_widget = QTabWidget(self)
        # Check if there are children and add foreign key browsers

        # Add primary tab if necessary
        self._add_primary_attr_widget()

        if not self._disable_collections:
            ch_entities = self.children_entities()

            for col, ch in ch_entities:
                if hasattr(col.entity_relation, 'show_in_parent'):
                    if col.entity_relation.show_in_parent != '0':
                        self._add_fk_browser(ch, col)
                else:
                    self._add_fk_browser(ch, col)

        # Add tab widget if entity supports documents
        if self._entity.supports_documents:
            self.doc_widget = SupportingDocumentsWidget(
                self._entity.supporting_doc, self._ent_document_model, self)

            # Map the source document manager object
            self.addMapping('documents',
                            self.doc_widget.source_document_manager)

            #
            # # Add attribute tab
            # self._add_primary_attr_widget()

            # Add supporting documents tab
            self.entity_tab_widget.addTab(self.doc_widget,
                                          self.tr('Supporting Documents'))

        # Return the correct widget
        if self.entity_tab_widget is not None:
            return self.entity_tab_widget

        return self.entity_scroll_area
Example #15
0
class ModelerParametersDialog(QDialog):

    ENTER_NAME = '[Enter name if this is a final result]'
    NOT_SELECTED = '[Not selected]'
    USE_MIN_COVERING_EXTENT = '[Use min covering extent]'

    def __init__(self, alg, model, algName=None):
        QDialog.__init__(self)
        self.setModal(True)
        # The algorithm to define in this dialog. It is an instance of GeoAlgorithm
        self._alg = alg
        # The resulting algorithm after the user clicks on OK. it is an instance of the container Algorithm class
        self.alg = None
        # The model this algorithm is going to be added to
        self.model = model
        # The name of the algorithm in the model, in case we are editing it and not defining it for the first time
        self._algName = algName
        self.setupUi()
        self.params = None

    def setupUi(self):
        self.labels = {}
        self.widgets = {}
        self.checkBoxes = {}
        self.showAdvanced = False
        self.wrappers = {}
        self.valueItems = {}
        self.dependentItems = {}
        self.resize(650, 450)
        self.buttonBox = QDialogButtonBox()
        self.buttonBox.setOrientation(Qt.Horizontal)
        self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel
                                          | QDialogButtonBox.Ok)
        tooltips = self._alg.getParameterDescriptions()
        self.setSizePolicy(QSizePolicy.Expanding,
                           QSizePolicy.Expanding)
        self.verticalLayout = QVBoxLayout()
        self.verticalLayout.setSpacing(5)
        self.verticalLayout.setMargin(20)

        self.bar = QgsMessageBar()
        self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        self.verticalLayout.addWidget(self.bar)

        hLayout = QHBoxLayout()
        hLayout.setSpacing(5)
        hLayout.setMargin(0)
        descriptionLabel = QLabel(self.tr("Description"))
        self.descriptionBox = QLineEdit()
        self.descriptionBox.setText(self._alg.name)
        hLayout.addWidget(descriptionLabel)
        hLayout.addWidget(self.descriptionBox)
        self.verticalLayout.addLayout(hLayout)
        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)
        self.verticalLayout.addWidget(line)

        for param in self._alg.parameters:
            if param.isAdvanced:
                self.advancedButton = QPushButton()
                self.advancedButton.setText(self.tr('Show advanced parameters'))
                self.advancedButton.clicked.connect(
                    self.showAdvancedParametersClicked)
                advancedButtonHLayout = QHBoxLayout()
                advancedButtonHLayout.addWidget(self.advancedButton)
                advancedButtonHLayout.addStretch()
                self.verticalLayout.addLayout(advancedButtonHLayout)
                break
        for param in self._alg.parameters:
            if param.hidden:
                continue
            desc = param.description
            if isinstance(param, ParameterExtent):
                desc += self.tr('(xmin, xmax, ymin, ymax)')
            if isinstance(param, ParameterPoint):
                desc += self.tr('(x, y)')
            if param.optional:
                desc += self.tr(' [optional]')
            label = QLabel(desc)
            self.labels[param.name] = label

            wrapper = param.wrapper(self)
            self.wrappers[param.name] = wrapper

            widget = wrapper.widget
            if widget:
                self.valueItems[param.name] = widget
                if param.name in list(tooltips.keys()):
                    tooltip = tooltips[param.name]
                else:
                    tooltip = param.description
                label.setToolTip(tooltip)
                widget.setToolTip(tooltip)
                if param.isAdvanced:
                    label.setVisible(self.showAdvanced)
                    widget.setVisible(self.showAdvanced)
                    self.widgets[param.name] = widget

                self.verticalLayout.addWidget(label)
                self.verticalLayout.addWidget(widget)

        for output in self._alg.outputs:
            if output.hidden:
                continue
            if isinstance(output, (OutputRaster, OutputVector, OutputTable,
                                   OutputHTML, OutputFile, OutputDirectory)):
                label = QLabel(output.description + '<'
                               + output.__class__.__name__ + '>')
                item = QLineEdit()
                if hasattr(item, 'setPlaceholderText'):
                    item.setPlaceholderText(ModelerParametersDialog.ENTER_NAME)
                self.verticalLayout.addWidget(label)
                self.verticalLayout.addWidget(item)
                self.valueItems[output.name] = item

        label = QLabel(' ')
        self.verticalLayout.addWidget(label)
        label = QLabel(self.tr('Parent algorithms'))
        self.dependenciesPanel = self.getDependenciesPanel()
        self.verticalLayout.addWidget(label)
        self.verticalLayout.addWidget(self.dependenciesPanel)
        self.verticalLayout.addStretch(1000)

        self.setPreviousValues()
        self.setWindowTitle(self._alg.name)
        self.verticalLayout2 = QVBoxLayout()
        self.verticalLayout2.setSpacing(2)
        self.verticalLayout2.setMargin(0)
        self.tabWidget = QTabWidget()
        self.tabWidget.setMinimumWidth(300)
        self.paramPanel = QWidget()
        self.paramPanel.setLayout(self.verticalLayout)
        self.scrollArea = QScrollArea()
        self.scrollArea.setWidget(self.paramPanel)
        self.scrollArea.setWidgetResizable(True)
        self.tabWidget.addTab(self.scrollArea, self.tr('Parameters'))

        self.txtHelp = QTextBrowser()

        html = None
        isText, algHelp = self._alg.help()
        if algHelp is not None:
            algHelp = algHelp if isText else QUrl(algHelp)
            try:
                if isText:
                    self.txtHelp.setHtml(algHelp)
                else:
                    html = self.tr('<p>Downloading algorithm help... Please wait.</p>')
                    self.txtHelp.setHtml(html)
                    self.tabWidget.addTab(self.txtHelp, 'Help')
                    self.reply = QgsNetworkAccessManager.instance().get(QNetworkRequest(algHelp))
                    self.reply.finished.connect(self.requestFinished)
            except:
                pass

        self.verticalLayout2.addWidget(self.tabWidget)
        self.verticalLayout2.addWidget(self.buttonBox)
        self.setLayout(self.verticalLayout2)
        self.buttonBox.accepted.connect(self.okPressed)
        self.buttonBox.rejected.connect(self.cancelPressed)
        QMetaObject.connectSlotsByName(self)

        for wrapper in list(self.wrappers.values()):
            wrapper.postInitialize(list(self.wrappers.values()))

    def requestFinished(self):
        """Change the webview HTML content"""
        reply = self.sender()
        if reply.error() != QNetworkReply.NoError:
            html = self.tr('<h2>No help available for this algorithm</h2><p>{}</p>'.format(reply.errorString()))
        else:
            html = str(reply.readAll())
        reply.deleteLater()
        self.txtHelp.setHtml(html)

    def getAvailableDependencies(self):
        if self._algName is None:
            dependent = []
        else:
            dependent = self.model.getDependentAlgorithms(self._algName)
        opts = []
        for alg in list(self.model.algs.values()):
            if alg.name not in dependent:
                opts.append(alg)
        return opts

    def getDependenciesPanel(self):
        return MultipleInputPanel([alg.description for alg in self.getAvailableDependencies()])

    def showAdvancedParametersClicked(self):
        self.showAdvanced = not self.showAdvanced
        if self.showAdvanced:
            self.advancedButton.setText(self.tr('Hide advanced parameters'))
        else:
            self.advancedButton.setText(self.tr('Show advanced parameters'))
        for param in self._alg.parameters:
            if param.isAdvanced:
                self.labels[param.name].setVisible(self.showAdvanced)
                self.widgets[param.name].setVisible(self.showAdvanced)

    def getAvailableValuesOfType(self, paramType, outType=None, dataType=None):
        # upgrade paramType to list
        if type(paramType) is not list:
            paramType = [paramType]

        values = []
        inputs = self.model.inputs
        for i in list(inputs.values()):
            param = i.param
            for t in paramType:
                if isinstance(param, t):
                    if dataType is not None:
                        if param.datatype in dataType:
                            values.append(ValueFromInput(param.name))
                    else:
                        values.append(ValueFromInput(param.name))
                    break
        if outType is None:
            return values
        if self._algName is None:
            dependent = []
        else:
            dependent = self.model.getDependentAlgorithms(self._algName)
        for alg in list(self.model.algs.values()):
            if alg.name not in dependent:
                for out in alg.algorithm.outputs:
                    if isinstance(out, outType):
                        if dataType is not None and out.datatype in dataType:
                            values.append(ValueFromOutput(alg.name, out.name))
                        else:
                            values.append(ValueFromOutput(alg.name, out.name))

        return values

    def resolveValueDescription(self, value):
        if isinstance(value, ValueFromInput):
            return self.model.inputs[value.name].param.description
        else:
            alg = self.model.algs[value.alg]
            return self.tr("'%s' from algorithm '%s'") % (alg.algorithm.getOutputFromName(value.output).description, alg.description)

    def setPreviousValues(self):
        if self._algName is not None:
            alg = self.model.algs[self._algName]
            self.descriptionBox.setText(alg.description)
            for param in alg.algorithm.parameters:
                if param.hidden:
                    continue
                if param.name in alg.params:
                    value = alg.params[param.name]
                else:
                    value = param.default
                self.wrappers[param.name].setValue(value)
            for name, out in list(alg.outputs.items()):
                self.valueItems[name].setText(out.description)

            selected = []
            dependencies = self.getAvailableDependencies()
            for idx, dependency in enumerate(dependencies):
                if dependency.name in alg.dependencies:
                    selected.append(idx)

            self.dependenciesPanel.setSelectedItems(selected)

    def createAlgorithm(self):
        alg = Algorithm(self._alg.commandLineName())
        alg.setName(self.model)
        alg.description = self.descriptionBox.text()
        params = self._alg.parameters
        outputs = self._alg.outputs
        for param in params:
            if param.hidden:
                continue
            if not self.setParamValue(alg, param, self.wrappers[param.name]):
                self.bar.pushMessage("Error", "Wrong or missing value for parameter '%s'" % param.description,
                                     level=QgsMessageBar.WARNING)
                return None
        for output in outputs:
            if not output.hidden:
                name = str(self.valueItems[output.name].text())
                if name.strip() != '' and name != ModelerParametersDialog.ENTER_NAME:
                    alg.outputs[output.name] = ModelerOutput(name)

        selectedOptions = self.dependenciesPanel.selectedoptions
        availableDependencies = self.getAvailableDependencies()
        for selected in selectedOptions:
            alg.dependencies.append(availableDependencies[selected].name)

        self._alg.processBeforeAddingToModeler(alg, self.model)
        return alg

    def setParamValue(self, alg, param, wrapper):
        try:
            if wrapper.widget:
                value = wrapper.value()
                alg.params[param.name] = value
            return True
        except InvalidParameterValue:
            return False

    def okPressed(self):
        self.alg = self.createAlgorithm()
        if self.alg is not None:
            self.close()

    def cancelPressed(self):
        self.alg = None
        self.close()
Example #16
0
    def setupUi(self):
        self.labels = {}
        self.widgets = {}
        self.checkBoxes = {}
        self.showAdvanced = False
        self.valueItems = {}
        self.dependentItems = {}
        self.resize(650, 450)
        self.buttonBox = QDialogButtonBox()
        self.buttonBox.setOrientation(Qt.Horizontal)
        self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel
                                          | QDialogButtonBox.Ok)
        tooltips = self._alg.getParameterDescriptions()
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.verticalLayout = QVBoxLayout()
        self.verticalLayout.setSpacing(5)
        self.verticalLayout.setMargin(20)

        hLayout = QHBoxLayout()
        hLayout.setSpacing(5)
        hLayout.setMargin(0)
        descriptionLabel = QLabel(self.tr("Description"))
        self.descriptionBox = QLineEdit()
        self.descriptionBox.setText(self._alg.name)
        hLayout.addWidget(descriptionLabel)
        hLayout.addWidget(self.descriptionBox)
        self.verticalLayout.addLayout(hLayout)
        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)
        self.verticalLayout.addWidget(line)

        for param in self._alg.parameters:
            if param.isAdvanced:
                self.advancedButton = QPushButton()
                self.advancedButton.setText(
                    self.tr('Show advanced parameters'))
                self.advancedButton.clicked.connect(
                    self.showAdvancedParametersClicked)
                advancedButtonHLayout = QHBoxLayout()
                advancedButtonHLayout.addWidget(self.advancedButton)
                advancedButtonHLayout.addStretch()
                self.verticalLayout.addLayout(advancedButtonHLayout)
                break
        for param in self._alg.parameters:
            if param.hidden:
                continue
            desc = param.description
            if isinstance(param, ParameterExtent):
                desc += self.tr('(xmin, xmax, ymin, ymax)')
            if isinstance(param, ParameterPoint):
                desc += self.tr('(x, y)')
            label = QLabel(desc)
            self.labels[param.name] = label
            widget = self.getWidgetFromParameter(param)
            self.valueItems[param.name] = widget
            if param.name in tooltips.keys():
                tooltip = tooltips[param.name]
            else:
                tooltip = param.description
            label.setToolTip(tooltip)
            widget.setToolTip(tooltip)
            if param.isAdvanced:
                label.setVisible(self.showAdvanced)
                widget.setVisible(self.showAdvanced)
                self.widgets[param.name] = widget
            self.verticalLayout.addWidget(label)
            self.verticalLayout.addWidget(widget)

        for output in self._alg.outputs:
            if output.hidden:
                continue
            if isinstance(output, (OutputRaster, OutputVector, OutputTable,
                                   OutputHTML, OutputFile, OutputDirectory)):
                label = QLabel(output.description + '<' +
                               output.__class__.__name__ + '>')
                item = QLineEdit()
                if hasattr(item, 'setPlaceholderText'):
                    item.setPlaceholderText(ModelerParametersDialog.ENTER_NAME)
                self.verticalLayout.addWidget(label)
                self.verticalLayout.addWidget(item)
                self.valueItems[output.name] = item

        label = QLabel(' ')
        self.verticalLayout.addWidget(label)
        label = QLabel(self.tr('Parent algorithms'))
        self.dependenciesPanel = self.getDependenciesPanel()
        self.verticalLayout.addWidget(label)
        self.verticalLayout.addWidget(self.dependenciesPanel)

        self.verticalLayout.addStretch(1000)
        self.setLayout(self.verticalLayout)

        self.setPreviousValues()
        self.setWindowTitle(self._alg.name)
        self.verticalLayout2 = QVBoxLayout()
        self.verticalLayout2.setSpacing(2)
        self.verticalLayout2.setMargin(0)
        self.tabWidget = QTabWidget()
        self.tabWidget.setMinimumWidth(300)
        self.paramPanel = QWidget()
        self.paramPanel.setLayout(self.verticalLayout)
        self.scrollArea = QScrollArea()
        self.scrollArea.setWidget(self.paramPanel)
        self.scrollArea.setWidgetResizable(True)
        self.tabWidget.addTab(self.scrollArea, self.tr('Parameters'))
        self.webView = QWebView()

        html = None
        url = None
        isText, help = self._alg.help()
        if help is not None:
            if isText:
                html = help
            else:
                url = QUrl(help)
        else:
            html = self.tr('<h2>Sorry, no help is available for this '
                           'algorithm.</h2>')
        try:
            if html:
                self.webView.setHtml(html)
            elif url:
                self.webView.load(url)
        except:
            self.webView.setHtml(
                self.tr('<h2>Could not open help file :-( </h2>'))
        self.tabWidget.addTab(self.webView, 'Help')
        self.verticalLayout2.addWidget(self.tabWidget)
        self.verticalLayout2.addWidget(self.buttonBox)
        self.setLayout(self.verticalLayout2)
        self.buttonBox.accepted.connect(self.okPressed)
        self.buttonBox.rejected.connect(self.cancelPressed)
        QMetaObject.connectSlotsByName(self)
Example #17
0
    def setupUi(self):
        self.labels = {}
        self.widgets = {}
        self.checkBoxes = {}
        self.showAdvanced = False
        self.wrappers = {}
        self.valueItems = {}
        self.dependentItems = {}
        self.resize(650, 450)
        self.buttonBox = QDialogButtonBox()
        self.buttonBox.setOrientation(Qt.Horizontal)
        self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel
                                          | QDialogButtonBox.Ok)
        tooltips = self._alg.getParameterDescriptions()
        self.setSizePolicy(QSizePolicy.Expanding,
                           QSizePolicy.Expanding)
        self.verticalLayout = QVBoxLayout()
        self.verticalLayout.setSpacing(5)
        self.verticalLayout.setMargin(20)

        self.bar = QgsMessageBar()
        self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        self.verticalLayout.addWidget(self.bar)

        hLayout = QHBoxLayout()
        hLayout.setSpacing(5)
        hLayout.setMargin(0)
        descriptionLabel = QLabel(self.tr("Description"))
        self.descriptionBox = QLineEdit()
        self.descriptionBox.setText(self._alg.name)
        hLayout.addWidget(descriptionLabel)
        hLayout.addWidget(self.descriptionBox)
        self.verticalLayout.addLayout(hLayout)
        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)
        self.verticalLayout.addWidget(line)

        for param in self._alg.parameters:
            if param.isAdvanced:
                self.advancedButton = QPushButton()
                self.advancedButton.setText(self.tr('Show advanced parameters'))
                self.advancedButton.clicked.connect(
                    self.showAdvancedParametersClicked)
                advancedButtonHLayout = QHBoxLayout()
                advancedButtonHLayout.addWidget(self.advancedButton)
                advancedButtonHLayout.addStretch()
                self.verticalLayout.addLayout(advancedButtonHLayout)
                break
        for param in self._alg.parameters:
            if param.hidden:
                continue
            desc = param.description
            if isinstance(param, ParameterExtent):
                desc += self.tr('(xmin, xmax, ymin, ymax)')
            if isinstance(param, ParameterPoint):
                desc += self.tr('(x, y)')
            if param.optional:
                desc += self.tr(' [optional]')
            label = QLabel(desc)
            self.labels[param.name] = label

            wrapper = param.wrapper(self)
            self.wrappers[param.name] = wrapper

            widget = wrapper.widget
            if widget:
                self.valueItems[param.name] = widget
                if param.name in list(tooltips.keys()):
                    tooltip = tooltips[param.name]
                else:
                    tooltip = param.description
                label.setToolTip(tooltip)
                widget.setToolTip(tooltip)
                if param.isAdvanced:
                    label.setVisible(self.showAdvanced)
                    widget.setVisible(self.showAdvanced)
                    self.widgets[param.name] = widget

                self.verticalLayout.addWidget(label)
                self.verticalLayout.addWidget(widget)

        for output in self._alg.outputs:
            if output.hidden:
                continue
            if isinstance(output, (OutputRaster, OutputVector, OutputTable,
                                   OutputHTML, OutputFile, OutputDirectory)):
                label = QLabel(output.description + '<'
                               + output.__class__.__name__ + '>')
                item = QLineEdit()
                if hasattr(item, 'setPlaceholderText'):
                    item.setPlaceholderText(ModelerParametersDialog.ENTER_NAME)
                self.verticalLayout.addWidget(label)
                self.verticalLayout.addWidget(item)
                self.valueItems[output.name] = item

        label = QLabel(' ')
        self.verticalLayout.addWidget(label)
        label = QLabel(self.tr('Parent algorithms'))
        self.dependenciesPanel = self.getDependenciesPanel()
        self.verticalLayout.addWidget(label)
        self.verticalLayout.addWidget(self.dependenciesPanel)
        self.verticalLayout.addStretch(1000)

        self.setPreviousValues()
        self.setWindowTitle(self._alg.name)
        self.verticalLayout2 = QVBoxLayout()
        self.verticalLayout2.setSpacing(2)
        self.verticalLayout2.setMargin(0)
        self.tabWidget = QTabWidget()
        self.tabWidget.setMinimumWidth(300)
        self.paramPanel = QWidget()
        self.paramPanel.setLayout(self.verticalLayout)
        self.scrollArea = QScrollArea()
        self.scrollArea.setWidget(self.paramPanel)
        self.scrollArea.setWidgetResizable(True)
        self.tabWidget.addTab(self.scrollArea, self.tr('Parameters'))

        self.txtHelp = QTextBrowser()

        html = None
        isText, algHelp = self._alg.help()
        if algHelp is not None:
            algHelp = algHelp if isText else QUrl(algHelp)
            try:
                if isText:
                    self.txtHelp.setHtml(algHelp)
                else:
                    html = self.tr('<p>Downloading algorithm help... Please wait.</p>')
                    self.txtHelp.setHtml(html)
                    self.tabWidget.addTab(self.txtHelp, 'Help')
                    self.reply = QgsNetworkAccessManager.instance().get(QNetworkRequest(algHelp))
                    self.reply.finished.connect(self.requestFinished)
            except:
                pass

        self.verticalLayout2.addWidget(self.tabWidget)
        self.verticalLayout2.addWidget(self.buttonBox)
        self.setLayout(self.verticalLayout2)
        self.buttonBox.accepted.connect(self.okPressed)
        self.buttonBox.rejected.connect(self.cancelPressed)
        QMetaObject.connectSlotsByName(self)

        for wrapper in list(self.wrappers.values()):
            wrapper.postInitialize(list(self.wrappers.values()))
Example #18
0
class OptionsDialog(QDialog, FORM_CLASS):
    """Options dialog for the InaSAFE plugin."""
    def __init__(self, iface, parent=None, qsetting=''):
        """Constructor for the dialog.

        :param iface: A Quantum GIS QgisAppInterface instance.
        :type iface: QgisAppInterface

        :param parent: Parent widget of this dialog
        :type parent: QWidget

        :param qsetting: String to specify the QSettings. By default,
            use empty string.
        :type qsetting: str
        """
        QDialog.__init__(self, parent)
        self.setupUi(self)
        icon = resources_path('img', 'icons', 'configure-inasafe.svg')
        self.setWindowIcon(QIcon(icon))
        self.setWindowTitle(self.tr('InaSAFE %s Options' % get_version()))
        # Save reference to the QGIS interface and parent
        self.iface = iface
        self.parent = parent
        if qsetting:
            self.settings = QSettings(qsetting)
        else:
            self.settings = QSettings()

        # InaSAFE default values
        self.default_value_parameters = []
        self.default_value_parameter_containers = []

        # Flag for restore default values
        self.is_restore_default = False

        # List of setting key and control
        self.boolean_settings = {
            'visibleLayersOnlyFlag': self.cbxVisibleLayersOnly,
            'set_layer_from_title_flag': self.cbxSetLayerNameFromTitle,
            'setZoomToImpactFlag': self.cbxZoomToImpact,
            'set_show_only_impact_on_report': self.cbx_show_only_impact,
            'print_atlas_report': self.cbx_print_atlas_report,
            'setHideExposureFlag': self.cbxHideExposure,
            'useSelectedFeaturesOnly': self.cbxUseSelectedFeaturesOnly,
            'useSentry': self.cbxUseSentry,
            'template_warning_verbose': self.template_warning_checkbox,
            'showOrganisationLogoInDockFlag':
            self.organisation_on_dock_checkbox,
            'developer_mode': self.cbxDevMode,
            'generate_report': self.checkbox_generate_reports,
            'memory_profile': self.check_box_memory,
            'always_show_welcome_message': self.welcome_message_check_box
        }
        self.text_settings = {
            'keywordCachePath': self.leKeywordCachePath,
            'ISO19115_ORGANIZATION': self.organisation_line_edit,
            'ISO19115_URL': self.website_line_edit,
            'ISO19115_EMAIL': self.email_line_edit,
            'ISO19115_LICENSE': self.license_line_edit,
        }

        # Export and Import button
        # Export button
        self.export_button = QPushButton(tr('Export'))
        # noinspection PyUnresolvedReferences
        self.export_button.clicked.connect(self.export_setting)
        self.button_box.addButton(self.export_button,
                                  QDialogButtonBox.ActionRole)
        # Import button
        self.import_button = QPushButton(tr('Import'))
        # noinspection PyUnresolvedReferences
        self.import_button.clicked.connect(self.import_setting)
        self.button_box.addButton(self.import_button,
                                  QDialogButtonBox.ActionRole)

        # Set up things for context help
        self.help_button = self.button_box.button(QDialogButtonBox.Help)
        # Allow toggling the help button
        self.help_button.setCheckable(True)
        self.help_button.toggled.connect(self.help_toggled)
        self.main_stacked_widget.setCurrentIndex(1)

        # Always set first tab to be open, 0-th index
        self.tabWidget.setCurrentIndex(0)

        # Hide not implemented group
        self.grpNotImplemented.hide()
        self.adjustSize()

        # Population parameter Tab
        # Label
        self.preference_label = QLabel()
        self.preference_label.setText(
            tr('Please set parameters for each hazard class below. Affected '
               'status and displacement rates selected on this tab are only '
               'applied to exposed populations. '))
        self.preference_layout.addWidget(self.preference_label)

        # Profile preference widget
        self.profile_widget = ProfileWidget()
        self.preference_layout.addWidget(self.profile_widget)

        # Demographic tab
        self.demographic_label = QLabel()
        self.demographic_label.setText(
            tr('Please set the global default demographic ratio below.'))
        self.default_values_layout.addWidget(self.demographic_label)
        self.scroll_area = QScrollArea()
        self.scroll_area.setWidgetResizable(True)
        self.widget_container = QWidget()
        self.scroll_area.setWidget(self.widget_container)
        self.container_layout = QVBoxLayout()
        self.widget_container.setLayout(self.container_layout)
        self.default_values_layout.addWidget(self.scroll_area)

        # Restore state from setting
        self.restore_state()

        # Hide checkbox if not developers
        if not self.cbxDevMode.isChecked():
            self.checkbox_generate_reports.hide()

        # Connections
        # Check boxes
        self.custom_north_arrow_checkbox.toggled.connect(self.set_north_arrow)
        self.custom_UseUserDirectory_checkbox.toggled.connect(
            self.set_user_dir)
        self.custom_templates_dir_checkbox.toggled.connect(
            self.set_templates_dir)
        self.custom_org_disclaimer_checkbox.toggled.connect(
            self.set_org_disclaimer)
        self.custom_organisation_logo_check_box.toggled.connect(
            self.toggle_logo_path)
        # Buttons
        self.toolKeywordCachePath.clicked.connect(self.open_keyword_cache_path)
        self.toolUserDirectoryPath.clicked.connect(
            self.open_user_directory_path)
        self.toolNorthArrowPath.clicked.connect(self.open_north_arrow_path)
        self.open_organisation_logo_path_button.clicked.connect(
            self.open_organisation_logo_path)
        self.toolReportTemplatePath.clicked.connect(
            self.open_report_template_path)
        # Others
        self.organisation_logo_path_line_edit.textChanged.connect(
            self.update_logo_preview)
        self.earthquake_function.currentIndexChanged.connect(
            self.update_earthquake_info)

        # Set up listener for restore defaults button
        self.demographic_restore_defaults = self.button_box_restore_defaults.\
            button(QDialogButtonBox.RestoreDefaults)
        self.demographic_restore_defaults.setText(
            self.demographic_restore_defaults.text().capitalize())
        self.demographic_restore_defaults.setCheckable(True)
        self.demographic_restore_defaults.clicked.connect(
            self.restore_defaults_ratio)

        # Restore button in population parameter tab
        self.parameter_population_restore_button = \
            self.button_box_restore_preference.button(
                QDialogButtonBox.RestoreDefaults)
        self.parameter_population_restore_button.setText(
            self.parameter_population_restore_button.text().capitalize())

        self.parameter_population_restore_button.clicked.connect(
            partial(self.restore_population_parameters, global_default=True))

        # TODO: Hide this until behaviour is defined
        # hide template warning toggle
        self.template_warning_checkbox.hide()

        # hide custom template dir toggle
        self.custom_templates_dir_checkbox.hide()
        self.splitter_custom_report.hide()

        # Welcome message
        self.set_welcome_message()

    def save_boolean_setting(self, key, check_box):
        """Save boolean setting according to check_box state.

        :param key: Key to retrieve setting value.
        :type key: str

        :param check_box: Check box to show and set the setting.
        :type check_box: PyQt5.QtWidgets.QCheckBox.QCheckBox
        """
        set_setting(key, check_box.isChecked(), qsettings=self.settings)

    def restore_boolean_setting(self, key, check_box):
        """Set check_box according to setting of key.

        :param key: Key to retrieve setting value.
        :type key: str

        :param check_box: Check box to show and set the setting.
        :type check_box: PyQt5.QtWidgets.QCheckBox.QCheckBox
        """
        flag = setting(key, expected_type=bool, qsettings=self.settings)
        check_box.setChecked(flag)

    def save_text_setting(self, key, line_edit):
        """Save text setting according to line_edit value.

        :param key: Key to retrieve setting value.
        :type key: str

        :param line_edit: Line edit for user to edit the setting
        :type line_edit: PyQt5.QtWidgets.QLineEdit.QLineEdit
        """
        set_setting(key, line_edit.text(), self.settings)

    def restore_text_setting(self, key, line_edit):
        """Set line_edit text according to setting of key.

        :param key: Key to retrieve setting value.
        :type key: str

        :param line_edit: Line edit for user to edit the setting
        :type line_edit: PyQt5.QtWidgets.QLineEdit.QLineEdit
        """
        value = setting(key, expected_type=str, qsettings=self.settings)
        line_edit.setText(value)

    def restore_state(self):
        """Reinstate the options based on the user's stored session info."""
        # Restore boolean setting as check box.
        for key, check_box in list(self.boolean_settings.items()):
            self.restore_boolean_setting(key, check_box)

        # Restore text setting as line edit.
        for key, line_edit in list(self.text_settings.items()):
            self.restore_text_setting(key, line_edit)

        # User Directory
        user_directory_path = setting(key='defaultUserDirectory',
                                      default=temp_dir('impacts'),
                                      expected_type=str,
                                      qsettings=self.settings)
        custom_user_directory_flag = (user_directory_path !=
                                      temp_dir('impacts'))
        self.custom_UseUserDirectory_checkbox.setChecked(
            custom_user_directory_flag)
        self.splitter_user_directory.setEnabled(custom_user_directory_flag)
        self.leUserDirectoryPath.setText(user_directory_path)

        # Currency
        # Populate the currency list
        for currency in currencies:
            self.currency_combo_box.addItem(currency['name'], currency['key'])

        # Then make selected the default one.
        default_currency = setting('currency', expected_type=str)
        keys = [currency['key'] for currency in currencies]
        if default_currency not in keys:
            default_currency = currencies[0]['key']
        index = self.currency_combo_box.findData(default_currency)
        self.currency_combo_box.setCurrentIndex(index)

        # Earthquake function.
        # Populate the combobox first.
        for model in EARTHQUAKE_FUNCTIONS:
            self.earthquake_function.addItem(model['name'], model['key'])

        # Then make selected the default one.
        default_earthquake_function = setting('earthquake_function',
                                              expected_type=str)
        keys = [model['key'] for model in EARTHQUAKE_FUNCTIONS]
        if default_earthquake_function not in keys:
            default_earthquake_function = EARTHQUAKE_FUNCTIONS[0]['key']
        index = self.earthquake_function.findData(default_earthquake_function)
        self.earthquake_function.setCurrentIndex(index)
        self.update_earthquake_info()

        # Restore North Arrow Image Path
        north_arrow_path = setting(key='north_arrow_path',
                                   default=default_north_arrow_path(),
                                   expected_type=str,
                                   qsettings=self.settings)
        custom_north_arrow_flag = (north_arrow_path !=
                                   default_north_arrow_path())
        self.custom_north_arrow_checkbox.setChecked(custom_north_arrow_flag)
        self.splitter_north_arrow.setEnabled(custom_north_arrow_flag)
        self.leNorthArrowPath.setText(north_arrow_path)

        # Restore Report Template Directory Path
        report_template_directory = setting(key='reportTemplatePath',
                                            default='',
                                            expected_type=str,
                                            qsettings=self.settings)
        custom_templates_dir_flag = (report_template_directory != '')
        self.custom_templates_dir_checkbox.setChecked(
            custom_templates_dir_flag)
        self.leReportTemplatePath.setText(report_template_directory)

        # Restore Disclaimer
        org_disclaimer = setting(key='reportDisclaimer',
                                 default=disclaimer(),
                                 expected_type=str,
                                 qsettings=self.settings)
        custom_org_disclaimer_flag = (org_disclaimer != disclaimer())
        self.custom_org_disclaimer_checkbox.setChecked(
            custom_org_disclaimer_flag)
        self.txtDisclaimer.setPlainText(org_disclaimer)

        # Restore Organisation Logo Path
        org_logo_path = setting(key='organisation_logo_path',
                                default=supporters_logo_path(),
                                expected_type=str,
                                qsettings=self.settings)
        # Check if the path is default one or not
        custom_org_logo_flag = org_logo_path != supporters_logo_path()
        self.organisation_logo_path_line_edit.setText(org_logo_path)
        self.custom_organisation_logo_check_box.setChecked(
            custom_org_logo_flag)
        self.organisation_logo_path_line_edit.setEnabled(custom_org_logo_flag)
        self.open_organisation_logo_path_button.setEnabled(
            custom_org_logo_flag)
        # Manually call here
        self.update_logo_preview()

        # Restore InaSAFE default values
        self.restore_default_values_page()

        # Restore Population Parameter
        self.restore_population_parameters(global_default=False)

    def save_state(self):
        """Store the options into the user's stored session info."""
        # Save boolean settings
        for key, check_box in list(self.boolean_settings.items()):
            self.save_boolean_setting(key, check_box)
        # Save text settings
        for key, line_edit in list(self.text_settings.items()):
            self.save_text_setting(key, line_edit)

        set_setting('north_arrow_path', self.leNorthArrowPath.text(),
                    self.settings)
        set_setting('organisation_logo_path',
                    self.organisation_logo_path_line_edit.text(),
                    self.settings)
        set_setting('reportTemplatePath', self.leReportTemplatePath.text(),
                    self.settings)
        set_setting('reportDisclaimer', self.txtDisclaimer.toPlainText(),
                    self.settings)
        set_setting('defaultUserDirectory', self.leUserDirectoryPath.text(),
                    self.settings)
        index = self.earthquake_function.currentIndex()
        value = self.earthquake_function.itemData(index)
        set_setting('earthquake_function', value, qsettings=self.settings)

        currency_index = self.currency_combo_box.currentIndex()
        currency_key = self.currency_combo_box.itemData(currency_index)
        set_setting('currency', currency_key, qsettings=self.settings)

        # Save InaSAFE default values
        self.save_default_values()

        # Save population parameters
        self.save_population_parameters()

    def accept(self):
        """Method invoked when OK button is clicked."""
        self.save_state()
        super(OptionsDialog, self).accept()

    def update_earthquake_info(self):
        """Update information about earthquake info."""
        self.label_earthquake_model()
        current_index = self.earthquake_function.currentIndex()
        model = EARTHQUAKE_FUNCTIONS[current_index]
        notes = ''
        for note in model['notes']:
            notes += note + '\n\n'

        citations = ''
        for citation in model['citations']:
            citations += citation['text'] + '\n\n'

        text = tr(
            'Description:\n\n%s\n\n'
            'Notes:\n\n%s\n\n'
            'Citations:\n\n%s') % (model['description'], notes, citations)

        self.earthquake_fatality_model_notes.setText(text)

    def label_earthquake_model(self):
        model = self.earthquake_function.currentText()
        help_text = tr(
            'Please select your preferred earthquake fatality model. The '
            'default fatality model is the {model}.').format(model=model)
        self.label_default_earthquake.setText(help_text)

    def open_keyword_cache_path(self):
        """Open File dialog to choose the keyword cache path."""
        # noinspection PyCallByClass,PyTypeChecker
        file_name, __ = QFileDialog.getSaveFileName(
            self, self.tr('Set keyword cache file'),
            self.leKeywordCachePath.text(), self.tr('Sqlite DB File (*.db)'))
        if file_name:
            self.leKeywordCachePath.setText(file_name)

    def open_user_directory_path(self):
        """Open File dialog to choose the user directory path."""
        # noinspection PyCallByClass,PyTypeChecker
        directory_name = QFileDialog.getExistingDirectory(
            self, self.tr('Results directory'),
            self.leUserDirectoryPath.text(), QFileDialog.ShowDirsOnly)
        if directory_name:
            self.leUserDirectoryPath.setText(directory_name)

    def open_north_arrow_path(self):
        """Open File dialog to choose the north arrow path."""
        # noinspection PyCallByClass,PyTypeChecker
        file_name, __ = QFileDialog.getOpenFileName(
            self, self.tr('Set north arrow image file'),
            self.leNorthArrowPath.text(),
            self.tr('Portable Network Graphics files (*.png *.PNG);;'
                    'JPEG Images (*.jpg *.jpeg);;'
                    'GIF Images (*.gif *.GIF);;'
                    'SVG Images (*.svg *.SVG);;'))
        if file_name:
            self.leNorthArrowPath.setText(file_name)

    def open_organisation_logo_path(self):
        """Open File dialog to choose the organisation logo path."""
        # noinspection PyCallByClass,PyTypeChecker
        file_name, __ = QFileDialog.getOpenFileName(
            self, self.tr('Set organisation logo file'),
            self.organisation_logo_path_line_edit.text(),
            self.tr('Portable Network Graphics files (*.png *.PNG);;'
                    'JPEG Images (*.jpg *.jpeg);;'
                    'GIF Images (*.gif *.GIF);;'
                    'SVG Images (*.svg *.SVG);;'))
        if file_name:
            self.organisation_logo_path_line_edit.setText(file_name)

    def open_report_template_path(self):
        """Open File dialog to choose the report template path."""
        # noinspection PyCallByClass,PyTypeChecker
        directory_name = QFileDialog.getExistingDirectory(
            self, self.tr('Templates directory'),
            self.leReportTemplatePath.text(), QFileDialog.ShowDirsOnly)
        if directory_name:
            self.leReportTemplatePath.setText(directory_name)

    def toggle_logo_path(self):
        """Set state of logo path line edit and button."""
        is_checked = self.custom_organisation_logo_check_box.isChecked()
        if is_checked:
            # Use previous org logo path
            path = setting(key='organisation_logo_path',
                           default=supporters_logo_path(),
                           expected_type=str,
                           qsettings=self.settings)
        else:
            # Set organisation path line edit to default one
            path = supporters_logo_path()

        self.organisation_logo_path_line_edit.setText(path)
        self.organisation_logo_path_line_edit.setEnabled(is_checked)
        self.open_organisation_logo_path_button.setEnabled(is_checked)

    def update_logo_preview(self):
        """Update logo based on the current logo path."""
        logo_path = self.organisation_logo_path_line_edit.text()
        if os.path.exists(logo_path):
            icon = QPixmap(logo_path)
            label_size = self.organisation_logo_label.size()
            label_size.setHeight(label_size.height() - 2)
            label_size.setWidth(label_size.width() - 2)
            scaled_icon = icon.scaled(label_size, Qt.KeepAspectRatio)
            self.organisation_logo_label.setPixmap(scaled_icon)
        else:
            self.organisation_logo_label.setText(tr("Logo not found"))

    def set_north_arrow(self):
        """Auto-connect slot activated when north arrow checkbox is toggled."""
        is_checked = self.custom_north_arrow_checkbox.isChecked()
        if is_checked:
            # Show previous north arrow path
            path = setting(key='north_arrow_path',
                           default=default_north_arrow_path(),
                           expected_type=str,
                           qsettings=self.settings)
        else:
            # Set the north arrow line edit to default one
            path = default_north_arrow_path()

        self.leNorthArrowPath.setText(path)
        self.splitter_north_arrow.setEnabled(is_checked)

    def set_user_dir(self):
        """Auto-connect slot activated when user dir checkbox is toggled.
        """
        is_checked = self.custom_UseUserDirectory_checkbox.isChecked()
        if is_checked:
            # Show previous templates dir
            path = setting(key='defaultUserDirectory',
                           default='',
                           expected_type=str,
                           qsettings=self.settings)
        else:
            # Set the template report dir to ''
            path = temp_dir('impacts')

        self.leUserDirectoryPath.setText(path)
        self.splitter_user_directory.setEnabled(is_checked)

    def set_templates_dir(self):
        """Auto-connect slot activated when templates dir checkbox is toggled.
        """
        is_checked = self.custom_templates_dir_checkbox.isChecked()
        if is_checked:
            # Show previous templates dir
            path = setting(key='reportTemplatePath',
                           default='',
                           expected_type=str,
                           qsettings=self.settings)
        else:
            # Set the template report dir to ''
            path = ''

        self.leReportTemplatePath.setText(path)
        self.splitter_custom_report.setEnabled(is_checked)

    def set_org_disclaimer(self):
        """Auto-connect slot activated when org disclaimer checkbox is toggled.
        """
        is_checked = self.custom_org_disclaimer_checkbox.isChecked()
        if is_checked:
            # Show previous organisation disclaimer
            org_disclaimer = setting('reportDisclaimer',
                                     default=disclaimer(),
                                     expected_type=str,
                                     qsettings=self.settings)
        else:
            # Set the organisation disclaimer to the default one
            org_disclaimer = disclaimer()

        self.txtDisclaimer.setPlainText(org_disclaimer)
        self.txtDisclaimer.setEnabled(is_checked)

    @pyqtSlot(bool)  # prevents actions being handled twice
    def help_toggled(self, flag):
        """Show or hide the help tab in the stacked widget.

        .. versionadded: 3.2.1

        :param flag: Flag indicating whether help should be shown or hidden.
        :type flag: bool
        """
        if flag:
            self.help_button.setText(self.tr('Hide Help'))
            self.show_help()
        else:
            self.help_button.setText(self.tr('Show Help'))
            self.hide_help()

    def hide_help(self):
        """Hide the usage info from the user.

        .. versionadded: 3.2.1
        """
        self.main_stacked_widget.setCurrentIndex(1)

    def show_help(self):
        """Show usage info to the user."""
        # Read the header and footer html snippets
        self.main_stacked_widget.setCurrentIndex(0)
        header = html_header()
        footer = html_footer()

        string = header

        message = options_help()

        string += message.to_html()
        string += footer

        self.help_web_view.setHtml(string)

    def restore_default_values_page(self):
        """Setup UI for default values setting."""
        # Clear parameters so it doesn't add parameters when
        # restore from changes.
        if self.default_value_parameters:
            self.default_value_parameters = []
        if self.default_value_parameter_containers:
            self.default_value_parameter_containers = []

        for i in reversed(list(range(self.container_layout.count()))):
            widget = self.container_layout.itemAt(i).widget()
            if widget is not None:
                widget.setParent(None)

        default_fields = all_default_fields()

        for field_group in all_field_groups:
            settable_fields = []
            for field in field_group['fields']:
                if field not in default_fields:
                    continue
                else:
                    settable_fields.append(field)
                    default_fields.remove(field)

            if not settable_fields:
                continue
            # Create group box for each field group
            group_box = QGroupBox(self)
            group_box.setTitle(field_group['name'])
            self.container_layout.addWidget(group_box)
            parameters = []
            for settable_field in settable_fields:
                parameter = self.default_field_to_parameter(settable_field)
                if parameter:
                    parameters.append(parameter)
            parameter_container = ParameterContainer(
                parameters,
                description_text=field_group['description'],
                extra_parameters=extra_parameter)
            parameter_container.setup_ui(must_scroll=False)
            group_box_inner_layout = QVBoxLayout()
            group_box_inner_layout.addWidget(parameter_container)
            group_box.setLayout(group_box_inner_layout)

            # Add to attribute
            self.default_value_parameter_containers.append(parameter_container)

        # Only show non-groups default fields if there is one
        if len(default_fields) > 0:
            for default_field in default_fields:
                parameter = self.default_field_to_parameter(default_field)
                if parameter:
                    self.default_value_parameters.append(parameter)

            description_text = tr(
                'In this options you can change the global default values for '
                'these variables.')
            parameter_container = ParameterContainer(
                self.default_value_parameters,
                description_text=description_text,
                extra_parameters=extra_parameter)
            parameter_container.setup_ui(must_scroll=False)
            self.other_group_box = QGroupBox(tr('Non-group fields'))
            other_group_inner_layout = QVBoxLayout()
            other_group_inner_layout.addWidget(parameter_container)
            self.other_group_box.setLayout(other_group_inner_layout)
            self.container_layout.addWidget(self.other_group_box)

            # Add to attribute
            self.default_value_parameter_containers.append(parameter_container)

    def restore_population_parameters(self, global_default=True):
        """Setup UI for population parameter page from setting.

        :param global_default: If True, set to original default (from
            the value in definitions).
        :type global_default: bool
        """
        if global_default:
            data = generate_default_profile()
        else:
            data = setting('population_preference', generate_default_profile())
        if not isinstance(data, dict):
            LOGGER.debug(
                'population parameter is not a dictionary. InaSAFE will use '
                'the default one.')
            data = generate_default_profile()
        try:
            self.profile_widget.data = data
        except KeyError as e:
            LOGGER.debug(
                'Population parameter is not in correct format. InaSAFE will '
                'use the default one.')
            LOGGER.debug(e)
            data = generate_default_profile()
            self.profile_widget.data = data

    @staticmethod
    def age_ratios():
        """Helper to get list of age ratio from the options dialog.

        :returns: List of age ratio.
        :rtype: list
        """
        # FIXME(IS) set a correct parameter container
        parameter_container = None

        youth_ratio = parameter_container.get_parameter_by_guid(
            youth_ratio_field['key']).value
        adult_ratio = parameter_container.get_parameter_by_guid(
            adult_ratio_field['key']).value
        elderly_ratio = parameter_container.get_parameter_by_guid(
            elderly_ratio_field['key']).value
        ratios = [youth_ratio, adult_ratio, elderly_ratio]

        return ratios

    def is_good_age_ratios(self):
        """Method to check the sum of age ratio is 1.

        :returns: True if the sum is 1 or the sum less than 1 but there is
            None.
        :rtype: bool
        """
        ratios = self.age_ratios()

        if None in ratios:
            # If there is None, just check to not exceeding 1
            clean_ratios = [x for x in ratios if x is not None]
            ratios.remove(None)
            if sum(clean_ratios) > 1:
                return False
        else:
            if sum(ratios) != 1:
                return False

        return True

    def save_default_values(self):
        """Save InaSAFE default values."""
        for parameter_container in self.default_value_parameter_containers:
            parameters = parameter_container.get_parameters()
            for parameter in parameters:
                set_inasafe_default_value_qsetting(self.settings, GLOBAL,
                                                   parameter.guid,
                                                   parameter.value)

    def restore_defaults_ratio(self):
        """Restore InaSAFE default ratio."""
        # Set the flag to true because user ask to.
        self.is_restore_default = True
        # remove current default ratio
        for i in reversed(list(range(self.container_layout.count()))):
            widget = self.container_layout.itemAt(i).widget()
            if widget is not None:
                widget.setParent(None)

        # reload default ratio
        self.restore_default_values_page()

    def default_field_to_parameter(self, default_field):
        """Obtain parameter from default field.

        :param default_field: A default field definition.
        :type default_field: dict

        :returns: A parameter object.
        :rtype: FloatParameter, IntegerParameter
        """
        if default_field.get('type') == QVariant.Double:
            parameter = FloatParameter()
        elif default_field.get('type') in qvariant_whole_numbers:
            parameter = IntegerParameter()
        else:
            return
        default_value = default_field.get('default_value')
        if not default_value:
            message = ('InaSAFE default field %s does not have default value' %
                       default_field.get('name'))
            LOGGER.exception(message)
            return

        parameter.guid = default_field.get('key')
        parameter.name = default_value.get('name')
        parameter.is_required = True
        parameter.precision = default_field.get('precision')
        parameter.minimum_allowed_value = default_value.get('min_value', 0)
        parameter.maximum_allowed_value = default_value.get(
            'max_value', 100000000)
        parameter.help_text = default_value.get('help_text')
        parameter.description = default_value.get('description')

        # Check if user ask to restore to the most default value.
        if self.is_restore_default:
            parameter._value = default_value.get('default_value')
        else:
            # Current value
            qsetting_default_value = get_inasafe_default_value_qsetting(
                self.settings, GLOBAL, default_field['key'])

            # To avoid python error
            if qsetting_default_value > parameter.maximum_allowed_value:
                qsetting_default_value = parameter.maximum_allowed_value
            if qsetting_default_value < parameter.minimum_allowed_value:
                qsetting_default_value = parameter.minimum_allowed_value

            parameter.value = qsetting_default_value
        return parameter

    def save_population_parameters(self):
        """Helper to save population parameter to QSettings."""
        population_parameter = self.profile_widget.data
        set_setting('population_preference', population_parameter)

    def set_welcome_message(self):
        """Create and insert welcome message."""
        string = html_header()
        string += welcome_message().to_html()
        string += html_footer()
        self.welcome_message.setHtml(string)

    def show_option_dialog(self):
        """Helper to show usual option dialog (without welcome message tab)."""
        self.tabWidget.removeTab(0)

    def show_welcome_dialog(self):
        """Setup for showing welcome message dialog.

        This method will setup several things:
        - Only show welcome, organisation profile, and population parameter
            tab. Currently, they are the first 3 tabs.
        - Set the title
        - Move the check box for always showing welcome message.
        """
        self.welcome_layout.addWidget(self.welcome_message_check_box)
        while self.tabWidget.count() > 3:
            self.tabWidget.removeTab(self.tabWidget.count() - 1)
        self.setWindowTitle(self.tr('Welcome to InaSAFE %s' % get_version()))
        # Hide the export import button
        self.export_button.hide()
        self.import_button.hide()

    def export_setting(self):
        """Export setting from an existing file."""
        LOGGER.debug('Export button clicked')
        home_directory = os.path.expanduser('~')
        file_name = self.organisation_line_edit.text().replace(' ', '_')
        file_path, __ = QFileDialog.getSaveFileName(
            self, self.tr('Export InaSAFE settings'),
            os.path.join(home_directory, file_name + '.json'),
            self.tr('JSON File (*.json)'))
        if file_path:
            LOGGER.debug('Exporting to %s' % file_path)
            export_setting(file_path)

    def import_setting(self):
        """Import setting to a file."""
        LOGGER.debug('Import button clicked')
        home_directory = os.path.expanduser('~')
        file_path, __ = QFileDialog.getOpenFileName(
            self, self.tr('Import InaSAFE settings'), home_directory,
            self.tr('JSON File (*.json)'))
        if file_path:
            title = tr('Import InaSAFE Settings.')
            question = tr(
                'This action will replace your current InaSAFE settings with '
                'the setting from the file. This action is not reversible. '
                'Are you sure to import InaSAFE Setting?')
            answer = QMessageBox.question(self, title, question,
                                          QMessageBox.Yes | QMessageBox.No)
            if answer == QMessageBox.Yes:
                LOGGER.debug('Import from %s' % file_path)
                import_setting(file_path)
Example #19
0
    def setupUi(self):
        self.labels = {}
        self.widgets = {}
        self.checkBoxes = {}
        self.showAdvanced = False
        self.wrappers = {}
        self.valueItems = {}
        self.dependentItems = {}
        self.resize(650, 450)
        self.buttonBox = QDialogButtonBox()
        self.buttonBox.setOrientation(Qt.Horizontal)
        self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel
                                          | QDialogButtonBox.Ok)
        tooltips = self._alg.getParameterDescriptions()
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.verticalLayout = QVBoxLayout()
        self.verticalLayout.setSpacing(5)
        self.verticalLayout.setMargin(20)

        self.bar = QgsMessageBar()
        self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        self.verticalLayout.addWidget(self.bar)

        hLayout = QHBoxLayout()
        hLayout.setSpacing(5)
        hLayout.setMargin(0)
        descriptionLabel = QLabel(self.tr("Description"))
        self.descriptionBox = QLineEdit()
        self.descriptionBox.setText(self._alg.name)
        hLayout.addWidget(descriptionLabel)
        hLayout.addWidget(self.descriptionBox)
        self.verticalLayout.addLayout(hLayout)
        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)
        self.verticalLayout.addWidget(line)

        for param in self._alg.parameters:
            if param.isAdvanced:
                self.advancedButton = QPushButton()
                self.advancedButton.setText(
                    self.tr('Show advanced parameters'))
                self.advancedButton.clicked.connect(
                    self.showAdvancedParametersClicked)
                advancedButtonHLayout = QHBoxLayout()
                advancedButtonHLayout.addWidget(self.advancedButton)
                advancedButtonHLayout.addStretch()
                self.verticalLayout.addLayout(advancedButtonHLayout)
                break
        for param in self._alg.parameters:
            if param.hidden:
                continue
            desc = param.description
            if isinstance(param, ParameterExtent):
                desc += self.tr('(xmin, xmax, ymin, ymax)')
            if isinstance(param, ParameterPoint):
                desc += self.tr('(x, y)')
            if param.optional:
                desc += self.tr(' [optional]')
            label = QLabel(desc)
            self.labels[param.name] = label

            wrapper = param.wrapper(self)
            self.wrappers[param.name] = wrapper

            widget = wrapper.widget
            self.valueItems[param.name] = widget
            if param.name in list(tooltips.keys()):
                tooltip = tooltips[param.name]
            else:
                tooltip = param.description
            label.setToolTip(tooltip)
            widget.setToolTip(tooltip)
            if param.isAdvanced:
                label.setVisible(self.showAdvanced)
                widget.setVisible(self.showAdvanced)
                self.widgets[param.name] = widget

            self.verticalLayout.addWidget(label)
            self.verticalLayout.addWidget(widget)

        for output in self._alg.outputs:
            if output.hidden:
                continue
            if isinstance(output, (OutputRaster, OutputVector, OutputTable,
                                   OutputHTML, OutputFile, OutputDirectory)):
                label = QLabel(output.description + '<' +
                               output.__class__.__name__ + '>')
                item = QLineEdit()
                if hasattr(item, 'setPlaceholderText'):
                    item.setPlaceholderText(ModelerParametersDialog.ENTER_NAME)
                self.verticalLayout.addWidget(label)
                self.verticalLayout.addWidget(item)
                self.valueItems[output.name] = item

        label = QLabel(' ')
        self.verticalLayout.addWidget(label)
        label = QLabel(self.tr('Parent algorithms'))
        self.dependenciesPanel = self.getDependenciesPanel()
        self.verticalLayout.addWidget(label)
        self.verticalLayout.addWidget(self.dependenciesPanel)
        self.verticalLayout.addStretch(1000)

        self.setPreviousValues()
        self.setWindowTitle(self._alg.name)
        self.verticalLayout2 = QVBoxLayout()
        self.verticalLayout2.setSpacing(2)
        self.verticalLayout2.setMargin(0)
        self.tabWidget = QTabWidget()
        self.tabWidget.setMinimumWidth(300)
        self.paramPanel = QWidget()
        self.paramPanel.setLayout(self.verticalLayout)
        self.scrollArea = QScrollArea()
        self.scrollArea.setWidget(self.paramPanel)
        self.scrollArea.setWidgetResizable(True)
        self.tabWidget.addTab(self.scrollArea, self.tr('Parameters'))

        self.txtHelp = QTextBrowser()

        html = None
        isText, algHelp = self._alg.help()
        if algHelp is not None:
            algHelp = algHelp if isText else QUrl(algHelp)
            try:
                if isText:
                    self.txtHelp.setHtml(algHelp)
                else:
                    html = self.tr(
                        '<p>Downloading algorithm help... Please wait.</p>')
                    self.txtHelp.setHtml(html)
                    self.tabWidget.addTab(self.txtHelp, 'Help')
                    self.reply = QgsNetworkAccessManager.instance().get(
                        QNetworkRequest(algHelp))
                    self.reply.finished.connect(self.requestFinished)
            except:
                pass

        self.verticalLayout2.addWidget(self.tabWidget)
        self.verticalLayout2.addWidget(self.buttonBox)
        self.setLayout(self.verticalLayout2)
        self.buttonBox.accepted.connect(self.okPressed)
        self.buttonBox.rejected.connect(self.cancelPressed)
        QMetaObject.connectSlotsByName(self)

        for wrapper in list(self.wrappers.values()):
            wrapper.postInitialize(list(self.wrappers.values()))
Example #20
0
class AdvancedSearch(EntityEditorDialog):
    def __init__(self, entity, parent):

        EntityEditorDialog.__init__(self, entity, parent=parent)
        self.parent = parent

    def _init_gui(self):
        # Setup base elements
        self.gridLayout = QGridLayout(self)
        self.gridLayout.setObjectName('glMain')
        self.gridLayout.addLayout(self.vlNotification, 0, 0, 1, 1)
        QApplication.processEvents()

        column_widget_area = self._setup_columns_content_area()
        self.gridLayout.addWidget(column_widget_area, 1, 0, 1, 1)
        QApplication.processEvents()
        # Add notification for mandatory columns if applicable
        next_row = 2
        # Set title
        search_trans = self.tr('Advanced Search')
        if self._entity.label is not None:
            if self._entity.label != '':
                title_str = self._entity.label
            else:
                title_str = format_name(self._entity.short_name)
        else:
            title_str = format_name(self._entity.short_name)

        title = '{0} {1}'.format(title_str, search_trans)
        self.do_not_check_dirty = True
        self.setWindowTitle(title)
        # if self.has_mandatory:
        #     self.required_fields_lbl = QLabel(self)
        #     msg = self.tr(
        #         'Please fill out all required (*) fields.'
        #     )
        #     msg = self._highlight_asterisk(msg)
        #     self.required_fields_lbl.setText(msg)
        #     self.gridLayout.addWidget(
        #         self.required_fields_lbl, next_row, 0, 1, 2
        #     )
        #     # Bump up row reference
        #     next_row += 1

        self.buttonBox = QDialogButtonBox(self)
        self.buttonBox.setObjectName('buttonBox')
        self.gridLayout.addWidget(self.buttonBox, next_row, 0, 1, 1)

        self.buttonBox.setOrientation(Qt.Horizontal)

        self.search = QPushButton(
            QApplication.translate('EntityEditorDialog', 'Search'))
        self.buttonBox.addButton(self.search, QDialogButtonBox.ActionRole)
        self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel)
        self.search.clicked.connect(self.on_search)
        #
        #
        # # edit model, collect model
        # # adding new record for child
        #
        # # Saving in parent editor
        # if not isinstance(self._parent._parent, EntityEditorDialog):
        #     # adding a new record
        #     if self.edit_model is None:
        #         # saving when digitizing.
        #         if self.collect_model:
        #             self.buttonBox.accepted.connect(self.on_model_added)
        #         # saving parent editor
        #         else:
        #             self.buttonBox.accepted.connect(self.save_parent_editor)
        #             self.save_new_button.clicked.connect(self.save_and_new)
        #     # updating existing record
        #     else:
        #         if not self.collect_model:
        #             # updating existing record of the parent editor
        #             self.buttonBox.accepted.connect(self.save_parent_editor)
        #         else:
        #             self.buttonBox.accepted.connect(self.on_model_added)
        # # Saving in child editor
        # else:
        #     # save and new record
        #     if self.edit_model is None:
        #         self.buttonBox.accepted.connect(self.on_child_saved)
        #         self.save_new_button.clicked.connect(
        #             lambda: self.on_child_saved(True)
        #         )
        #
        #     else:
        #         # When updating an existing child editor save to the db
        #         self.buttonBox.accepted.connect(
        #             self.on_child_saved
        #         )
        #         #self.buttonBox.accepted.connect(self.submit)
        #
        self.buttonBox.rejected.connect(self.cancel)

    def on_search(self):
        search_data = {}
        for column in self._entity.columns.values():
            if column.name in entity_display_columns(self._entity):
                if column.name == 'id':
                    continue
                handler = self.attribute_mappers[column.name].valueHandler()
                value = handler.value()
                if value != handler.default() and bool(value):
                    search_data[column.name] = value
        # self.search_db(search_data)
        result = self.search_db_raw(search_data)
        self.parent._tableModel.removeRows(0,
                                           self.parent._tableModel.rowCount())
        if result is not None:
            found = QApplication.translate('AdvancedSearch', 'records found')
            new_title = '{} - {} {}'.format(self.title, result.rowcount, found)
            if result.rowcount > 3000:
                title = QApplication.translate('AdvancedSearch',
                                               'Advanced Search')
                message = QApplication.translate(
                    'AdvancedSearch',
                    'The search result returned {0} records, which is above the '
                    'search result limit. <br>Would you like to see the first 3000 '
                    'records?'.format("{:,}".format(result.rowcount)))

                res, chk_result = simple_dialog(self, title, message)
                if res:
                    self.setWindowTitle(new_title)
                    self.parent._initializeData(result)
                else:
                    return

            else:
                self.setWindowTitle(new_title)
                self.parent._initializeData(result)

    def search_db(self, search_data):
        ent_model_obj = self.ent_model()
        # query = ent_model_obj.queryObject()
        for attr, value in search_data.items():
            ent_model_obj.queryObject().filter(
                getattr(self.ent_model(), attr) == value)

        # now we can run the query
        # print(ent_model_obj.queryObject(), vars(ent_model_obj.queryObject()))
        # print(str(ent_model_obj.queryObject()))
        results = ent_model_obj.queryObject().all()

    def search_db_raw(self, search_data):
        sql = "SELECT * FROM {} WHERE ".format(self._entity.name)
        # query = ent_model_obj.queryObject()
        param = []
        if len(search_data) == 0:
            return None
        for attr, value in search_data.items():
            if isinstance(value, (int, float)):
                param.append('{} = {}'.format(str(attr), str(value)))
            if isinstance(value, str):
                param.append("{} = '{}'".format(str(attr), str(value)))
        final_sql = '{} {}'.format(sql, ' AND '.join(param))
        # sql_text = text(final_sql)
        results = fetch_with_filter(final_sql)
        # now we can run the query

        return results

    def _setup_columns_content_area(self):
        # Only use this if entity supports documents
        # self.entity_tab_widget = None
        self.doc_widget = None

        self.entity_scroll_area = QScrollArea(self)
        self.entity_scroll_area.setFrameShape(QFrame.NoFrame)
        self.entity_scroll_area.setWidgetResizable(True)
        self.entity_scroll_area.setObjectName('scrollArea')

        # Grid layout for controls
        self.gl = QGridLayout(self.scroll_widget_contents)
        self.gl.setObjectName('gl_widget_contents')

        # Append column labels and widgets
        table_name = self._entity.name
        columns = table_column_names(table_name)
        # Iterate entity column and assert if they exist
        row_id = 0
        for column_name, column_widget in self.column_widgets.items():
            c = self.columns[column_name]

            if c.name in self.exclude_columns:
                continue
            if isinstance(c, MultipleSelectColumn):
                continue
            if not c.name in columns and not isinstance(c, VirtualColumn):
                continue

            if column_widget is not None:
                header = c.ui_display()
                self.c_label = QLabel(self.scroll_widget_contents)

                self.c_label.setText(header)
                self.gl.addWidget(self.c_label, row_id, 0, 1, 1)

                if c.TYPE_INFO == 'AUTO_GENERATED':
                    column_widget.setReadOnly(False)
                    column_widget.btn_load.hide()
                self.gl.addWidget(column_widget, row_id, 1, 1, 1)

                col_name = c.name

                # Add widget to MapperMixin collection
                self.addMapping(col_name,
                                column_widget,
                                c.mandatory,
                                pseudoname=c.ui_display())

                # Bump up row_id
                row_id += 1

        self.entity_scroll_area.setWidget(self.scroll_widget_contents)
        if self.entity_tab_widget is None:
            self.entity_tab_widget = QTabWidget(self)
        # Check if there are children and add foreign key browsers

        # Add primary tab if necessary
        self._add_primary_attr_widget()
        # self.entity_tab_widget.setTabEnabled(0, False)  # enable/disable the tab
        # set the style sheet
        self.setStyleSheet(
            "QTabBar::tab::selected {width: 0; height: 0; margin: 0; "
            "padding: 0; border: none;} ")
        # Return the correct widget
        if self.entity_tab_widget is not None:
            return self.entity_tab_widget

        return self.entity_scroll_area

    def closeEvent(self, event):
        '''
        Raised when a request to close the window is received.
        Check the dirty state of input controls and prompt user to
        save if dirty.
        '''
        event.accept()

    def cancel(self):
        '''
        Slot for closing the dialog.
        Checks the dirty state first before closing.
        '''
        self.reject()