コード例 #1
0
class ButtonLineEdit(QLineEdit):
    buttonClicked = pyqtSignal()

    def __init__(self, parent=None):
        super(ButtonLineEdit, self).__init__(parent)

        self.setPlaceholderText("Search")

        self.btnSearch = QToolButton(self)
        self.btnSearch.setIcon(QIcon(os.path.join(pluginPath, "icons", "search.svg")))
        self.btnSearch.setStyleSheet("QToolButton { padding: 0px; }")
        self.btnSearch.setCursor(Qt.ArrowCursor)
        self.btnSearch.clicked.connect(self.buttonClicked.emit)

        frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth)
        buttonSize = self.btnSearch.sizeHint()

        self.setStyleSheet("QLineEdit {{padding-right: {}px; }}".format(buttonSize.width() + frameWidth + 1))
        self.setMinimumSize(max(self.minimumSizeHint().width(), buttonSize.width() + frameWidth * 2 + 2),
                            max(self.minimumSizeHint().height(), buttonSize.height() + frameWidth * 2 + 2))

    def resizeEvent(self, event):
        buttonSize = self.btnSearch.sizeHint()
        frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth)
        self.btnSearch.move(self.rect().right() - frameWidth - buttonSize.width(),
                            (self.rect().bottom() - buttonSize.height() + 1) / 2)

        super(ButtonLineEdit, self).resizeEvent(event)
コード例 #2
0
    def append_menu_buttons(self):
        """
        Append menus and buttons to appropriate toolbar
        :return:
        """
        # add to QGIS menu
        if PluginSettings.move_to_layers_menu():
            self.iface.addLayerMenu().addMenu(self.menu)
        else:
            # need workaround for WebMenu
            _temp_act = QAction('temp', self.iface.mainWindow())
            self.iface.addPluginToWebMenu("_tmp", _temp_act)
            self.iface.webMenu().addMenu(self.menu)
            self.iface.removePluginWebMenu("_tmp", _temp_act)

        # add to QGIS toolbar
        toolbutton = QToolButton()
        toolbutton.setPopupMode(QToolButton.InstantPopup)
        toolbutton.setMenu(self.menu)
        toolbutton.setIcon(self.menu.icon())
        toolbutton.setText(self.menu.title())
        toolbutton.setToolTip(self.menu.title())
        # self.tb_action = toolbutton.defaultAction()
        # print "self.tb_action: ", self.tb_action
        if PluginSettings.move_to_layers_menu():
            self.tb_action = self.iface.layerToolBar().addWidget(toolbutton)
            self.iface.layerToolBar().addAction(self.qms_search_action)
        else:
            self.tb_action = self.iface.webToolBar().addWidget(toolbutton)
            self.iface.webToolBar().addAction(self.qms_search_action)
コード例 #3
0
ファイル: ProcessingToolbox.py プロジェクト: tomkralidis/QGIS
    def addProviderActions(self, provider):
        if provider.id() in ProviderActions.actions:
            toolbarButton = QToolButton()
            toolbarButton.setObjectName('provideraction_' + provider.id())
            toolbarButton.setIcon(provider.icon())
            toolbarButton.setToolTip(provider.name())
            toolbarButton.setPopupMode(QToolButton.InstantPopup)

            actions = ProviderActions.actions[provider.id()]
            menu = QMenu(provider.name(), self)
            for action in actions:
                action.setData(self)
                act = QAction(action.name, menu)
                act.triggered.connect(action.execute)
                menu.addAction(act)
            toolbarButton.setMenu(menu)
            self.processingToolbar.addWidget(toolbarButton)
コード例 #4
0
    def addProviderActions(self, provider):
        if provider.id() in ProviderActions.actions:
            toolbarButton = QToolButton()
            toolbarButton.setObjectName('provideraction_' + provider.id())
            toolbarButton.setIcon(provider.icon())
            toolbarButton.setToolTip(provider.name())
            toolbarButton.setPopupMode(QToolButton.InstantPopup)

            actions = ProviderActions.actions[provider.id()]
            menu = QMenu(provider.name(), self)
            for action in actions:
                action.setData(self)
                act = QAction(action.name, menu)
                act.triggered.connect(action.execute)
                menu.addAction(act)
            toolbarButton.setMenu(menu)
            self.processingToolbar.addWidget(toolbarButton)
コード例 #5
0
ファイル: wrappers.py プロジェクト: zgustaf/QGIS
    def createWidget(self):
        if self.dialogType == DIALOG_MODELER:
            self.combo = QComboBox()
            widget = QWidget()
            layout = QHBoxLayout()
            layout.setMargin(0)
            layout.setContentsMargins(0, 0, 0, 0)
            layout.setSpacing(1)
            layout.addWidget(self.combo)
            btn = QToolButton()
            btn.setIcon(QgsApplication.getThemeIcon("mActionSetProjection.svg"))
            btn.setToolTip(self.tr("Select CRS"))
            btn.clicked.connect(self.selectProjection)
            layout.addWidget(btn)

            widget.setLayout(layout)
            self.combo.setEditable(True)
            crss = self.dialog.getAvailableValuesOfType(ParameterCrs)
            for crs in crss:
                self.combo.addItem(self.dialog.resolveValueDescription(crs), crs)
            raster = self.dialog.getAvailableValuesOfType(ParameterRaster, OutputRaster)
            vector = self.dialog.getAvailableValuesOfType(ParameterVector, OutputVector)
            for r in raster:
                self.combo.addItem("Crs of layer " + self.dialog.resolveValueDescription(r), r)
            for v in vector:
                self.combo.addItem("Crs of layer " + self.dialog.resolveValueDescription(v), v)
            if not self.param.default:
                self.combo.setEditText(self.param.default)
            return widget
        else:
            widget = QgsProjectionSelectionWidget()
            if self.param.optional:
                widget.setOptionVisible(QgsProjectionSelectionWidget.CrsNotSet, True)

            if self.param.default:
                if self.param.default == 'ProjectCrs':
                    crs = QgsProject.instance().crs()
                else:
                    crs = QgsCoordinateReferenceSystem(self.param.default)
                widget.setCrs(crs)
            else:
                widget.setOptionVisible(QgsProjectionSelectionWidget.CrsNotSet, True)

            return widget
コード例 #6
0
class PasswordLineEdit(QLineEdit):
    def __init__(self, parent=None):
        QLineEdit.__init__(self, parent)

        self.setPlaceholderText(self.tr("Password"))
        self.setEchoMode(QLineEdit.Password)

        self.btnIcon = QToolButton(self)
        self.btnIcon.setIcon(QIcon(os.path.join(iconsPath, "lock.svg")))
        self.btnIcon.setEnabled(False)
        self.btnIcon.setStyleSheet(
            "QToolButton { border: none; padding: 0px; }")

        self.btnToggle = QToolButton(self)
        self.btnToggle.setIcon(QIcon(os.path.join(iconsPath, "eye-slash.svg")))
        self.btnToggle.setCheckable(True)
        self.btnToggle.setToolTip(self.tr("Toggle password visibility"))
        self.btnToggle.setCursor(Qt.ArrowCursor)
        self.btnToggle.setStyleSheet(
            "QToolButton { border: none; padding: 0px; }")

        self.btnToggle.toggled.connect(self.togglePassword)

        frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth)
        self.setStyleSheet(
            "QLineEdit {{ padding-right: {}px; padding-left: {}px }} ".format(
                self.btnToggle.sizeHint().width() + frameWidth + 1,
                self.btnIcon.sizeHint().width() + frameWidth + 1))
        msz = self.minimumSizeHint()
        self.setMinimumSize(
            max(msz.width(),
                self.btnToggle.sizeHint().height() + frameWidth * 2 + 2),
            max(msz.height(),
                self.btnToggle.sizeHint().height() + frameWidth * 2 + 2))

    def resizeEvent(self, event):
        frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth)

        sz = self.btnIcon.sizeHint()
        self.btnIcon.move(frameWidth + 1,
                          (self.rect().bottom() + 1 - sz.height()) / 2)

        sz = self.btnToggle.sizeHint()
        self.btnToggle.move(self.rect().right() - frameWidth - sz.width(),
                            (self.rect().bottom() + 1 - sz.height()) / 2)

    def togglePassword(self, toggled):
        if toggled:
            self.setEchoMode(QLineEdit.Normal)
            self.btnToggle.setIcon(QIcon(os.path.join(iconsPath, "eye.svg")))
        else:
            self.setEchoMode(QLineEdit.Password)
            self.btnToggle.setIcon(
                QIcon(os.path.join(iconsPath, "eye-slash.svg")))
コード例 #7
0
ファイル: wrappers.py プロジェクト: GrokImageCompression/QGIS
    def createWidget(self):
        if self.dialogType == DIALOG_MODELER:
            self.combo = QComboBox()
            widget = QWidget()
            layout = QHBoxLayout()
            layout.setMargin(0)
            layout.setContentsMargins(0, 0, 0, 0)
            layout.setSpacing(1)
            layout.addWidget(self.combo)
            btn = QToolButton()
            btn.setIcon(QgsApplication.getThemeIcon("mActionSetProjection.svg"))
            btn.setToolTip(self.tr("Select CRS"))
            btn.clicked.connect(self.selectProjection)
            layout.addWidget(btn)

            widget.setLayout(layout)
            self.combo.setEditable(True)
            crss = self.dialog.getAvailableValuesOfType(ParameterCrs)
            for crs in crss:
                self.combo.addItem(self.dialog.resolveValueDescription(crs), crs)
            raster = self.dialog.getAvailableValuesOfType(ParameterRaster, OutputRaster)
            vector = self.dialog.getAvailableValuesOfType(ParameterVector, OutputVector)
            for r in raster:
                self.combo.addItem("Crs of layer " + self.dialog.resolveValueDescription(r), r)
            for v in vector:
                self.combo.addItem("Crs of layer " + self.dialog.resolveValueDescription(v), v)
            if not self.param.default:
                self.combo.setEditText(self.param.default)
            return widget
        else:

            widget = QgsProjectionSelectionWidget()
            if self.param.optional:
                widget.setOptionVisible(QgsProjectionSelectionWidget.CrsNotSet, True)

            if self.param.default:
                crs = QgsCoordinateReferenceSystem(self.param.default)
                widget.setCrs(crs)

            return widget
コード例 #8
0
class Ui_PostNAS_SearchDialogBase(object):
    def setupUi(self, PostNAS_SearchDialogBase):
        PostNAS_SearchDialogBase.setObjectName(_fromUtf8("PostNAS_SearchDialogBase"))
        PostNAS_SearchDialogBase.resize(501, 337)
        self.gridLayout = QGridLayout(PostNAS_SearchDialogBase)
        self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
        self.treeWidget = QTreeWidget(PostNAS_SearchDialogBase)
        self.treeWidget.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.treeWidget.setHeaderHidden(True)
        self.treeWidget.setObjectName(_fromUtf8("treeWidget"))
        self.treeWidget.headerItem().setText(0, _fromUtf8("1"))
        self.gridLayout.addWidget(self.treeWidget, 1, 0, 1, 3)
        self.lineEdit = QLineEdit(PostNAS_SearchDialogBase)
        self.lineEdit.setObjectName(_fromUtf8("lineEdit"))
        self.gridLayout.addWidget(self.lineEdit, 0, 0, 1, 3)
        self.showButton = QToolButton(PostNAS_SearchDialogBase)
        self.showButton.setEnabled(False)
        icon = QtGui.QIcon()
        icon.addPixmap(QPixmap(_fromUtf8(":/plugins/PostNAS_Search/search_16x16.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.showButton.setIcon(icon)
        self.showButton.setObjectName(_fromUtf8("showButton"))
        self.gridLayout.addWidget(self.showButton, 2, 2, 1, 1)
        self.resetButton = QToolButton(PostNAS_SearchDialogBase)
        self.resetButton.setEnabled(False)
        icon1 = QIcon()
        icon1.addPixmap(QtGui.QPixmap(_fromUtf8(":/plugins/PostNAS_Search/marker-delete.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.resetButton.setIcon(icon1)
        self.resetButton.setObjectName(_fromUtf8("resetButton"))
        self.gridLayout.addWidget(self.resetButton, 2, 1, 1, 1)

        self.retranslateUi(PostNAS_SearchDialogBase)
        QtCore.QMetaObject.connectSlotsByName(PostNAS_SearchDialogBase)

    def retranslateUi(self, PostNAS_SearchDialogBase):
        PostNAS_SearchDialogBase.setWindowTitle(_translate("PostNAS_SearchDialogBase", "KU_Search", None))
        self.showButton.setToolTip(_translate("PostNAS_SearchDialogBase", "Auswahl anzeigen", None))
        self.showButton.setText(_translate("PostNAS_SearchDialogBase", "Anzeigen", None))
        self.resetButton.setToolTip(_translate("PostNAS_SearchDialogBase", "Ergebnis löschen", None))
        self.resetButton.setText(_translate("PostNAS_SearchDialogBase", "Reset", None))
コード例 #9
0
ファイル: editor_dialog.py プロジェクト: gltn/stdm
    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'))
コード例 #10
0
class GwManageLayers:
    def __init__(self, iface, settings, controller, plugin_dir):
        """ Class to manage layers. Refactor code from giswater.py """

        self.iface = iface
        self.settings = settings
        self.controller = controller
        self.plugin_dir = plugin_dir
        self.available_layers = None
        self.add_layer = GwLayerTools(self.iface, self.settings,
                                      self.controller, self.plugin_dir)
        self.project_type = controller.get_project_type()
        self.schema_name = controller.schema_name
        self.project_vars = global_vars.qgis_tools.get_qgis_project_variables()
        self.qgis_project_infotype = self.project_vars['infotype']
        self.qgis_project_add_schema = self.project_vars['add_schema']

    def config_layers(self):

        status = self.manage_layers()
        if not status:
            return False

        # Set config layer fields when user add new layer into the TOC
        # QgsProject.instance().legendLayersAdded.connect(self.get_new_layers_name)

        # Put add layers button into toc
        # self.add_layers_button()

        # Set project layers with gw_fct_getinfofromid: This process takes time for user
        # Set background task 'ConfigLayerFields'
        description = f"ConfigLayerFields"
        task_get_layers = GwConfigLayerTask(description, self.controller)
        task_get_layers.set_params(self.project_type, self.schema_name,
                                   self.qgis_project_infotype)
        QgsApplication.taskManager().addTask(task_get_layers)
        QgsApplication.taskManager().triggerTask(task_get_layers)

        return True

    def manage_layers(self):
        """ Get references to project main layers """

        # Check if we have any layer loaded
        layers = self.controller.get_layers()
        if len(layers) == 0:
            return False

        if self.project_type in ('ws', 'ud'):
            QApplication.setOverrideCursor(Qt.ArrowCursor)
            self.check_project_result = GwProjectCheck(self.iface,
                                                       self.settings,
                                                       self.controller,
                                                       self.plugin_dir)
            self.check_project_result.set_controller(self.controller)

            # check project
            status, result = self.check_project_result.populate_audit_check_project(
                layers, "true")
            try:
                if 'actions' in result['body']:
                    if 'useGuideMap' in result['body']['actions']:
                        guided_map = result['body']['actions']['useGuideMap']
                        if guided_map:
                            self.controller.log_info("manage_guided_map")
                            self.manage_guided_map()
            except Exception as e:
                self.controller.log_info(str(e))
            finally:
                QApplication.restoreOverrideCursor()
                return status

        return True

    def get_new_layers_name(self, layers_list):

        layers_name = []
        for layer in layers_list:
            layer_source = self.controller.get_layer_source(layer)
            # Collect only the layers of the work scheme
            if 'schema' in layer_source:
                schema = layer_source['schema']
                if schema and schema.replace('"', '') == self.schema_name:
                    layers_name.append(layer.name())

        self.set_layer_config(layers_name)

    def set_layer_config(self, layers):
        """ Set layer fields configured according to client configuration.
            At the moment manage:
                Column names as alias, combos as ValueMap, typeahead as textedit"""

        self.controller.log_info("Start set_layer_config")

        msg_failed = ""
        msg_key = ""
        for layer_name in layers:
            layer = self.controller.get_layer_by_tablename(layer_name)
            if not layer:
                continue

            feature = '"tableName":"' + str(
                layer_name) + '", "id":"", "isLayer":true'
            extras = f'"infoType":"{self.qgis_project_infotype}"'
            body = self.create_body(feature=feature, extras=extras)
            complet_result = self.controller.get_json('gw_fct_getinfofromid',
                                                      body)
            if not complet_result:
                continue

            for field in complet_result['body']['data']['fields']:
                valuemap_values = {}

                # Get column index
                fieldIndex = layer.fields().indexFromName(field['columnname'])

                # Hide selected fields according table config_api_form_fields.hidden
                if 'hidden' in field:
                    self.set_column_visibility(layer, field['columnname'],
                                               field['hidden'])

                # Set alias column
                if field['label']:
                    layer.setFieldAlias(fieldIndex, field['label'])

                if 'widgetcontrols' in field:
                    # Set multiline fields according table config_api_form_fields.widgetcontrols['setQgisMultiline']
                    if field[
                            'widgetcontrols'] is not None and 'setQgisMultiline' in field[
                                'widgetcontrols']:
                        self.set_column_multiline(layer, field, fieldIndex)

                    # Set field constraints
                    if field[
                            'widgetcontrols'] and 'setQgisConstraints' in field[
                                'widgetcontrols']:
                        if field['widgetcontrols'][
                                'setQgisConstraints'] is True:
                            layer.setFieldConstraint(
                                fieldIndex,
                                QgsFieldConstraints.ConstraintNotNull,
                                QgsFieldConstraints.ConstraintStrengthSoft)
                            layer.setFieldConstraint(
                                fieldIndex,
                                QgsFieldConstraints.ConstraintUnique,
                                QgsFieldConstraints.ConstraintStrengthHard)

                if 'ismandatory' in field and not field['ismandatory']:
                    layer.setFieldConstraint(
                        fieldIndex, QgsFieldConstraints.ConstraintNotNull,
                        QgsFieldConstraints.ConstraintStrengthSoft)

                # Manage editability
                self.set_read_only(layer, field, fieldIndex)

                # delete old values on ValueMap
                editor_widget_setup = QgsEditorWidgetSetup(
                    'ValueMap', {'map': valuemap_values})
                layer.setEditorWidgetSetup(fieldIndex, editor_widget_setup)

                # Manage new values in ValueMap
                if field['widgettype'] == 'combo':
                    if 'comboIds' in field:
                        # Set values
                        for i in range(0, len(field['comboIds'])):
                            valuemap_values[field['comboNames']
                                            [i]] = field['comboIds'][i]
                    # Set values into valueMap
                    editor_widget_setup = QgsEditorWidgetSetup(
                        'ValueMap', {'map': valuemap_values})
                    layer.setEditorWidgetSetup(fieldIndex, editor_widget_setup)
                elif field['widgettype'] == 'check':
                    config = {
                        'CheckedState': 'true',
                        'UncheckedState': 'false'
                    }
                    editor_widget_setup = QgsEditorWidgetSetup(
                        'CheckBox', config)
                    layer.setEditorWidgetSetup(fieldIndex, editor_widget_setup)
                elif field['widgettype'] == 'datetime':
                    config = {
                        'allow_null': True,
                        'calendar_popup': True,
                        'display_format': 'yyyy-MM-dd',
                        'field_format': 'yyyy-MM-dd',
                        'field_iso_format': False
                    }
                    editor_widget_setup = QgsEditorWidgetSetup(
                        'DateTime', config)
                    layer.setEditorWidgetSetup(fieldIndex, editor_widget_setup)
                else:
                    editor_widget_setup = QgsEditorWidgetSetup(
                        'TextEdit', {'IsMultiline': 'True'})
                    layer.setEditorWidgetSetup(fieldIndex, editor_widget_setup)

        if msg_failed != "":
            self.controller.show_exceptions_msg("Execute failed.", msg_failed)

        if msg_key != "":
            self.controller.show_exceptions_msg(
                "Key on returned json from ddbb is missed.", msg_key)

        self.controller.log_info("Finish set_layer_config")

    def set_form_suppress(self, layers_list):
        """ Set form suppress on "Hide form on add feature (global settings) """

        for layer_name in layers_list:
            layer = self.controller.get_layer_by_tablename(layer_name)
            if layer is None: continue
            config = layer.editFormConfig()
            config.setSuppress(0)
            layer.setEditFormConfig(config)

    def set_read_only(self, layer, field, field_index):
        """ Set field readOnly according to client configuration into config_api_form_fields (field 'iseditable') """

        # Get layer config
        config = layer.editFormConfig()
        try:
            # Set field editability
            config.setReadOnly(field_index, not field['iseditable'])
        except KeyError:
            pass
        finally:
            # Set layer config
            layer.setEditFormConfig(config)

    def set_column_visibility(self, layer, col_name, hidden):
        """ Hide selected fields according table config_api_form_fields.hidden """

        config = layer.attributeTableConfig()
        columns = config.columns()
        for column in columns:
            if column.name == str(col_name):
                column.hidden = hidden
                break
        config.setColumns(columns)
        layer.setAttributeTableConfig(config)

    def set_column_multiline(self, layer, field, fieldIndex):
        """ Set multiline selected fields according table config_api_form_fields.widgetcontrols['setQgisMultiline'] """

        if field['widgettype'] == 'text':
            if field['widgetcontrols'] and 'setQgisMultiline' in field[
                    'widgetcontrols']:
                editor_widget_setup = QgsEditorWidgetSetup(
                    'TextEdit', {
                        'IsMultiline':
                        field['widgetcontrols']['setQgisMultiline']
                    })
                layer.setEditorWidgetSetup(fieldIndex, editor_widget_setup)

    def create_body(self, form='', feature='', filter_fields='', extras=None):
        """ Create and return parameters as body to functions"""

        client = f'$${{"client":{{"device":4, "infoType":1, "lang":"ES"}}, '
        form = '"form":{' + form + '}, '
        feature = '"feature":{' + feature + '}, '
        filter_fields = '"filterFields":{' + filter_fields + '}'
        page_info = '"pageInfo":{}'
        data = '"data":{' + filter_fields + ', ' + page_info
        if extras is not None:
            data += ', ' + extras
        data += f'}}}}$$'
        body = "" + client + form + feature + data

        return body

    def manage_guided_map(self):
        """ Guide map works using ext_municipality """

        self.layer_muni = self.controller.get_layer_by_tablename(
            'ext_municipality')
        if self.layer_muni is None:
            return

        self.iface.setActiveLayer(self.layer_muni)
        self.controller.set_layer_visible(self.layer_muni)
        self.layer_muni.selectAll()
        self.iface.actionZoomToSelected().trigger()
        self.layer_muni.removeSelection()
        self.iface.actionSelect().trigger()
        self.iface.mapCanvas().selectionChanged.connect(self.selection_changed)
        cursor = self.get_cursor_multiple_selection()
        if cursor:
            self.iface.mapCanvas().setCursor(cursor)

    def selection_changed(self):
        """ Get selected muni_id and execute function setselectors """

        muni_id = None
        features = self.layer_muni.getSelectedFeatures()
        for feature in features:
            muni_id = feature["muni_id"]
            self.controller.log_info(f"Selected muni_id: {muni_id}")
            break

        self.iface.mapCanvas().selectionChanged.disconnect()
        self.iface.actionZoomToSelected().trigger()
        self.layer_muni.removeSelection()

        if muni_id is None:
            return

        extras = f'"selectorType":"explfrommuni", "id":{muni_id}, "value":true, "isAlone":true, '
        extras += f'"addSchema":"{self.qgis_project_add_schema}"'
        body = self.create_body(extras=extras)
        sql = f"SELECT gw_fct_setselectors({body})::text"
        row = self.controller.get_row(sql, commit=True)
        if row:
            self.iface.mapCanvas().refreshAllLayers()
            self.layer_muni.triggerRepaint()
            self.iface.actionPan().trigger()
            self.iface.actionZoomIn().trigger()

    def get_cursor_multiple_selection(self):
        """ Set cursor for multiple selection """

        icon_path = self.plugin_dir + '/icons/211.png'
        if os.path.exists(icon_path):
            cursor = QCursor(QPixmap(icon_path))
        else:
            cursor = None

        return cursor

    def add_layers_button(self):

        icon_path = self.plugin_dir + '/icons/306.png'
        dockwidget = self.iface.mainWindow().findChild(QDockWidget, 'Layers')
        toolbar = dockwidget.findChildren(QToolBar)[0]
        btn_exist = toolbar.findChild(QToolButton, 'gw_add_layers')
        if btn_exist is None:
            self.btn_add_layers = QToolButton()
            self.btn_add_layers.setIcon(QIcon(icon_path))
            self.btn_add_layers.setObjectName('gw_add_layers')
            self.btn_add_layers.setToolTip('Load giswater layer')
            toolbar.addWidget(self.btn_add_layers)
            self.btn_add_layers.clicked.connect(
                partial(self.create_add_layer_menu))

    def create_add_layer_menu(self):

        # Create main menu and get cursor click position
        main_menu = QMenu()
        cursor = QCursor()
        x = cursor.pos().x()
        y = cursor.pos().y()
        click_point = QPoint(x + 5, y + 5)
        schema_name = self.schema_name.replace('"', '')
        # Get parent layers
        sql = (
            "SELECT distinct ( CASE parent_layer WHEN 'v_edit_node' THEN 'Node' "
            "WHEN 'v_edit_arc' THEN 'Arc' WHEN 'v_edit_connec' THEN 'Connec' "
            "WHEN 'v_edit_gully' THEN 'Gully' END ), parent_layer FROM cat_feature "
            "ORDER BY parent_layer")
        parent_layers = self.controller.get_rows(sql)

        for parent_layer in parent_layers:

            # Get child layers
            sql = (
                f"SELECT DISTINCT(child_layer), lower(feature_type), cat_feature.id as alias, style as style_id, "
                f" group_layer "
                f" FROM cat_feature "
                f" LEFT JOIN config_table ON config_table.id = child_layer "
                f"WHERE parent_layer = '{parent_layer[1]}' "
                f"AND child_layer IN ("
                f"   SELECT table_name FROM information_schema.tables"
                f"   WHERE table_schema = '{schema_name}')"
                f" ORDER BY child_layer")

            child_layers = self.controller.get_rows(sql)
            if not child_layers: continue

            # Create sub menu
            sub_menu = main_menu.addMenu(str(parent_layer[0]))
            child_layers.insert(
                0,
                ['Load all', 'Load all', 'Load all', 'Load all', 'Load all'])
            for child_layer in child_layers:
                # Create actions
                action = QAction(str(child_layer[2]), sub_menu, checkable=True)

                # Get load layers and create child layers menu (actions)
                layers_list = []
                layers = self.iface.mapCanvas().layers()
                for layer in layers:
                    layers_list.append(str(layer.name()))

                if str(child_layer[0]) in layers_list:
                    action.setChecked(True)

                sub_menu.addAction(action)
                if child_layer[0] == 'Load all':
                    action.triggered.connect(
                        partial(self.add_layer.from_postgres_to_toc,
                                child_layers=child_layers))

                else:
                    layer_name = child_layer[0]
                    the_geom = "the_geom"
                    geom_field = child_layer[1] + "_id"
                    style_id = child_layer[3]
                    group = child_layer[4] if child_layer[
                        4] is not None else 'GW Layers'
                    action.triggered.connect(
                        partial(self.add_layer.from_postgres_to_toc,
                                layer_name, the_geom, geom_field, None, group,
                                style_id))

        main_menu.exec_(click_point)
コード例 #11
0
ファイル: ParametersPanel.py プロジェクト: AM7000000/QGIS
    def initWidgets(self):
        # If there are advanced parameters — show corresponding groupbox
        for param in self.alg.parameters:
            if param.isAdvanced:
                self.grpAdvanced.show()
                break
        # Create widgets and put them in layouts
        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)')
            try:
                if param.optional:
                    desc += self.tr(' [optional]')
            except:
                pass

            widget = self.getWidgetFromParameter(param)
            self.valueItems[param.name] = widget

            if isinstance(param, ParameterVector) and \
                    not self.alg.allowOnlyOpenedLayers:
                layout = QHBoxLayout()
                layout.setSpacing(2)
                layout.setMargin(0)
                layout.addWidget(widget)
                button = QToolButton()
                icon = QIcon(os.path.join(pluginPath, 'images', 'iterate.png'))
                button.setIcon(icon)
                button.setToolTip(self.tr('Iterate over this layer'))
                button.setCheckable(True)
                layout.addWidget(button)
                self.iterateButtons[param.name] = button
                button.toggled.connect(self.buttonToggled)
                widget = QWidget()
                widget.setLayout(layout)

            tooltips = self.alg.getParameterDescriptions()
            widget.setToolTip(tooltips.get(param.name, param.description))

            if isinstance(param, ParameterBoolean):
                widget.setText(desc)
                if param.isAdvanced:
                    self.layoutAdvanced.addWidget(widget)
                else:
                    self.layoutMain.insertWidget(
                        self.layoutMain.count() - 2, widget)
            else:
                label = QLabel(desc)
                #label.setToolTip(tooltip)
                self.labels[param.name] = label
                if param.isAdvanced:
                    self.layoutAdvanced.addWidget(label)
                    self.layoutAdvanced.addWidget(widget)
                else:
                    self.layoutMain.insertWidget(
                        self.layoutMain.count() - 2, label)
                    self.layoutMain.insertWidget(
                        self.layoutMain.count() - 2, widget)

            self.widgets[param.name] = widget

        for output in self.alg.outputs:
            if output.hidden:
                continue

            label = QLabel(output.description)
            widget = OutputSelectionPanel(output, self.alg)
            self.layoutMain.insertWidget(self.layoutMain.count() - 1, label)
            self.layoutMain.insertWidget(self.layoutMain.count() - 1, widget)
            if isinstance(output, (OutputRaster, OutputVector, OutputTable)):
                check = QCheckBox()
                check.setText(self.tr('Open output file after running algorithm'))
                check.setChecked(True)
                self.layoutMain.insertWidget(self.layoutMain.count() - 1, check)
                self.checkBoxes[output.name] = check
            self.valueItems[output.name] = widget

            if isinstance(output, OutputVector):
                if output.base_input in self.dependentItems:
                    items = self.dependentItems[output.base_input]
                else:
                    items = []
                    self.dependentItems[output.base_input] = items
                items.append(output)

                base_input = self.alg.getParameterFromName(output.base_input)
                if isinstance(base_input, ParameterVector):
                    layers = dataobjects.getVectorLayers(base_input.shapetype)
                else:
                    layers = dataobjects.getTables()
                if len(layers) > 0:
                    output.base_layer = layers[0]
コード例 #12
0
ファイル: ParametersPanel.py プロジェクト: zhuyunlong/QGIS
    def initWidgets(self):
        # If there are advanced parameters — show corresponding groupbox
        for param in self.alg.parameterDefinitions():
            if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced:
                self.grpAdvanced.show()
                break
        # Create widgets and put them in layouts
        for param in self.alg.parameterDefinitions():
            if param.flags() & QgsProcessingParameterDefinition.FlagHidden:
                continue

            if param.isDestination():
                continue
            else:
                wrapper = WidgetWrapperFactory.create_wrapper(
                    param, self.parent)
                self.wrappers[param.name()] = wrapper
                widget = wrapper.widget

                if widget is not None:
                    if isinstance(param, QgsProcessingParameterFeatureSource):
                        layout = QHBoxLayout()
                        layout.setSpacing(6)
                        layout.setMargin(0)
                        layout.addWidget(widget)
                        button = QToolButton()
                        icon = QIcon(
                            os.path.join(pluginPath, 'images', 'iterate.png'))
                        button.setIcon(icon)
                        button.setSizePolicy(QSizePolicy.Fixed,
                                             QSizePolicy.Expanding)
                        button.setToolTip(
                            self.
                            tr('Iterate over this layer, creating a separate output for every feature in the layer'
                               ))
                        button.setCheckable(True)
                        layout.addWidget(button)
                        layout.setAlignment(button, Qt.AlignTop)
                        self.iterateButtons[param.name()] = button
                        button.toggled.connect(self.buttonToggled)
                        widget = QWidget()
                        widget.setLayout(layout)

                    widget.setToolTip(param.toolTip())

                    if wrapper.label is not None:
                        if param.flags(
                        ) & QgsProcessingParameterDefinition.FlagAdvanced:
                            self.layoutAdvanced.addWidget(wrapper.label)
                        else:
                            self.layoutMain.insertWidget(
                                self.layoutMain.count() - 2, wrapper.label)
                    else:
                        desc = param.description()
                        if isinstance(param, QgsProcessingParameterExtent):
                            desc += self.tr(' (xmin, xmax, ymin, ymax)')
                        if isinstance(param, QgsProcessingParameterPoint):
                            desc += self.tr(' (x, y)')
                        if param.flags(
                        ) & QgsProcessingParameterDefinition.FlagOptional:
                            desc += self.tr(' [optional]')
                        widget.setText(desc)
                    if param.flags(
                    ) & QgsProcessingParameterDefinition.FlagAdvanced:
                        self.layoutAdvanced.addWidget(widget)
                    else:
                        self.layoutMain.insertWidget(
                            self.layoutMain.count() - 2, widget)

        for output in self.alg.destinationParameterDefinitions():
            if output.flags() & QgsProcessingParameterDefinition.FlagHidden:
                continue

            label = QLabel(output.description())
            widget = DestinationSelectionPanel(output, self.alg)
            self.layoutMain.insertWidget(self.layoutMain.count() - 1, label)
            self.layoutMain.insertWidget(self.layoutMain.count() - 1, widget)
            if isinstance(output, (QgsProcessingParameterRasterDestination,
                                   QgsProcessingParameterFeatureSink,
                                   QgsProcessingParameterVectorDestination)):
                check = QCheckBox()
                check.setText(
                    QCoreApplication.translate(
                        'ParametersPanel',
                        'Open output file after running algorithm'))

                def skipOutputChanged(checkbox, skipped):
                    checkbox.setEnabled(not skipped)
                    if skipped:
                        checkbox.setChecked(False)

                check.setChecked(not widget.outputIsSkipped())
                check.setEnabled(not widget.outputIsSkipped())
                widget.skipOutputChanged.connect(
                    partial(skipOutputChanged, check))
                self.layoutMain.insertWidget(self.layoutMain.count() - 1,
                                             check)
                self.checkBoxes[output.name()] = check

            widget.setToolTip(param.toolTip())
            self.outputWidgets[output.name()] = widget

        for wrapper in list(self.wrappers.values()):
            wrapper.postInitialize(list(self.wrappers.values()))
コード例 #13
0
ファイル: ModelerDialog.py プロジェクト: dwsilk/QGIS
class ModelerDialog(BASE, WIDGET):
    ALG_ITEM = 'ALG_ITEM'
    PROVIDER_ITEM = 'PROVIDER_ITEM'
    GROUP_ITEM = 'GROUP_ITEM'

    NAME_ROLE = Qt.UserRole
    TAG_ROLE = Qt.UserRole + 1
    TYPE_ROLE = Qt.UserRole + 2

    CANVAS_SIZE = 4000

    update_model = pyqtSignal()

    def __init__(self, model=None):
        super().__init__(None)
        self.setAttribute(Qt.WA_DeleteOnClose)

        self.setupUi(self)

        self._variables_scope = None

        # LOTS of bug reports when we include the dock creation in the UI file
        # see e.g. #16428, #19068
        # So just roll it all by hand......!
        self.propertiesDock = QgsDockWidget(self)
        self.propertiesDock.setFeatures(
            QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable)
        self.propertiesDock.setObjectName("propertiesDock")
        propertiesDockContents = QWidget()
        self.verticalDockLayout_1 = QVBoxLayout(propertiesDockContents)
        self.verticalDockLayout_1.setContentsMargins(0, 0, 0, 0)
        self.verticalDockLayout_1.setSpacing(0)
        self.scrollArea_1 = QgsScrollArea(propertiesDockContents)
        sizePolicy = QSizePolicy(QSizePolicy.MinimumExpanding,
                                 QSizePolicy.MinimumExpanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.scrollArea_1.sizePolicy().hasHeightForWidth())
        self.scrollArea_1.setSizePolicy(sizePolicy)
        self.scrollArea_1.setFocusPolicy(Qt.WheelFocus)
        self.scrollArea_1.setFrameShape(QFrame.NoFrame)
        self.scrollArea_1.setFrameShadow(QFrame.Plain)
        self.scrollArea_1.setWidgetResizable(True)
        self.scrollAreaWidgetContents_1 = QWidget()
        self.gridLayout = QGridLayout(self.scrollAreaWidgetContents_1)
        self.gridLayout.setContentsMargins(6, 6, 6, 6)
        self.gridLayout.setSpacing(4)
        self.label_1 = QLabel(self.scrollAreaWidgetContents_1)
        self.gridLayout.addWidget(self.label_1, 0, 0, 1, 1)
        self.textName = QLineEdit(self.scrollAreaWidgetContents_1)
        self.gridLayout.addWidget(self.textName, 0, 1, 1, 1)
        self.label_2 = QLabel(self.scrollAreaWidgetContents_1)
        self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1)
        self.textGroup = QLineEdit(self.scrollAreaWidgetContents_1)
        self.gridLayout.addWidget(self.textGroup, 1, 1, 1, 1)
        self.label_1.setText(self.tr("Name"))
        self.textName.setToolTip(self.tr("Enter model name here"))
        self.label_2.setText(self.tr("Group"))
        self.textGroup.setToolTip(self.tr("Enter group name here"))
        self.scrollArea_1.setWidget(self.scrollAreaWidgetContents_1)
        self.verticalDockLayout_1.addWidget(self.scrollArea_1)
        self.propertiesDock.setWidget(propertiesDockContents)
        self.propertiesDock.setWindowTitle(self.tr("Model Properties"))

        self.inputsDock = QgsDockWidget(self)
        self.inputsDock.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable)
        self.inputsDock.setObjectName("inputsDock")
        self.inputsDockContents = QWidget()
        self.verticalLayout_3 = QVBoxLayout(self.inputsDockContents)
        self.verticalLayout_3.setContentsMargins(0, 0, 0, 0)
        self.scrollArea_2 = QgsScrollArea(self.inputsDockContents)
        sizePolicy.setHeightForWidth(self.scrollArea_2.sizePolicy().hasHeightForWidth())
        self.scrollArea_2.setSizePolicy(sizePolicy)
        self.scrollArea_2.setFocusPolicy(Qt.WheelFocus)
        self.scrollArea_2.setFrameShape(QFrame.NoFrame)
        self.scrollArea_2.setFrameShadow(QFrame.Plain)
        self.scrollArea_2.setWidgetResizable(True)
        self.scrollAreaWidgetContents_2 = QWidget()
        self.verticalLayout = QVBoxLayout(self.scrollAreaWidgetContents_2)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout.setSpacing(0)
        self.inputsTree = QTreeWidget(self.scrollAreaWidgetContents_2)
        self.inputsTree.setAlternatingRowColors(True)
        self.inputsTree.header().setVisible(False)
        self.verticalLayout.addWidget(self.inputsTree)
        self.scrollArea_2.setWidget(self.scrollAreaWidgetContents_2)
        self.verticalLayout_3.addWidget(self.scrollArea_2)
        self.inputsDock.setWidget(self.inputsDockContents)
        self.addDockWidget(Qt.DockWidgetArea(1), self.inputsDock)
        self.inputsDock.setWindowTitle(self.tr("Inputs"))

        self.algorithmsDock = QgsDockWidget(self)
        self.algorithmsDock.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable)
        self.algorithmsDock.setObjectName("algorithmsDock")
        self.algorithmsDockContents = QWidget()
        self.verticalLayout_4 = QVBoxLayout(self.algorithmsDockContents)
        self.verticalLayout_4.setContentsMargins(0, 0, 0, 0)
        self.scrollArea_3 = QgsScrollArea(self.algorithmsDockContents)
        sizePolicy.setHeightForWidth(self.scrollArea_3.sizePolicy().hasHeightForWidth())
        self.scrollArea_3.setSizePolicy(sizePolicy)
        self.scrollArea_3.setFocusPolicy(Qt.WheelFocus)
        self.scrollArea_3.setFrameShape(QFrame.NoFrame)
        self.scrollArea_3.setFrameShadow(QFrame.Plain)
        self.scrollArea_3.setWidgetResizable(True)
        self.scrollAreaWidgetContents_3 = QWidget()
        self.verticalLayout_2 = QVBoxLayout(self.scrollAreaWidgetContents_3)
        self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout_2.setSpacing(4)
        self.searchBox = QgsFilterLineEdit(self.scrollAreaWidgetContents_3)
        self.verticalLayout_2.addWidget(self.searchBox)
        self.algorithmTree = QgsProcessingToolboxTreeView(None,
                                                          QgsApplication.processingRegistry())
        self.algorithmTree.setAlternatingRowColors(True)
        self.algorithmTree.header().setVisible(False)
        self.verticalLayout_2.addWidget(self.algorithmTree)
        self.scrollArea_3.setWidget(self.scrollAreaWidgetContents_3)
        self.verticalLayout_4.addWidget(self.scrollArea_3)
        self.algorithmsDock.setWidget(self.algorithmsDockContents)
        self.addDockWidget(Qt.DockWidgetArea(1), self.algorithmsDock)
        self.algorithmsDock.setWindowTitle(self.tr("Algorithms"))
        self.searchBox.setToolTip(self.tr("Enter algorithm name to filter list"))
        self.searchBox.setShowSearchIcon(True)

        self.variables_dock = QgsDockWidget(self)
        self.variables_dock.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable)
        self.variables_dock.setObjectName("variablesDock")
        self.variables_dock_contents = QWidget()
        vl_v = QVBoxLayout()
        vl_v.setContentsMargins(0, 0, 0, 0)
        self.variables_editor = QgsVariableEditorWidget()
        vl_v.addWidget(self.variables_editor)
        self.variables_dock_contents.setLayout(vl_v)
        self.variables_dock.setWidget(self.variables_dock_contents)
        self.addDockWidget(Qt.DockWidgetArea(1), self.variables_dock)
        self.variables_dock.setWindowTitle(self.tr("Variables"))
        self.addDockWidget(Qt.DockWidgetArea(1), self.propertiesDock)
        self.tabifyDockWidget(self.propertiesDock, self.variables_dock)
        self.variables_editor.scopeChanged.connect(self.variables_changed)

        self.bar = QgsMessageBar()
        self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        self.centralWidget().layout().insertWidget(0, self.bar)

        try:
            self.setDockOptions(self.dockOptions() | QMainWindow.GroupedDragging)
        except:
            pass

        if iface is not None:
            self.mToolbar.setIconSize(iface.iconSize())
            self.setStyleSheet(iface.mainWindow().styleSheet())

        self.toolbutton_export_to_script = QToolButton()
        self.toolbutton_export_to_script.setPopupMode(QToolButton.InstantPopup)
        self.export_to_script_algorithm_action = QAction(QCoreApplication.translate('ModelerDialog', 'Export as Script Algorithm…'))
        self.toolbutton_export_to_script.addActions([self.export_to_script_algorithm_action])
        self.mToolbar.insertWidget(self.mActionExportImage, self.toolbutton_export_to_script)
        self.export_to_script_algorithm_action.triggered.connect(self.export_as_script_algorithm)

        self.mActionOpen.setIcon(
            QgsApplication.getThemeIcon('/mActionFileOpen.svg'))
        self.mActionSave.setIcon(
            QgsApplication.getThemeIcon('/mActionFileSave.svg'))
        self.mActionSaveAs.setIcon(
            QgsApplication.getThemeIcon('/mActionFileSaveAs.svg'))
        self.mActionSaveInProject.setIcon(
            QgsApplication.getThemeIcon('/mAddToProject.svg'))
        self.mActionZoomActual.setIcon(
            QgsApplication.getThemeIcon('/mActionZoomActual.svg'))
        self.mActionZoomIn.setIcon(
            QgsApplication.getThemeIcon('/mActionZoomIn.svg'))
        self.mActionZoomOut.setIcon(
            QgsApplication.getThemeIcon('/mActionZoomOut.svg'))
        self.mActionExportImage.setIcon(
            QgsApplication.getThemeIcon('/mActionSaveMapAsImage.svg'))
        self.mActionZoomToItems.setIcon(
            QgsApplication.getThemeIcon('/mActionZoomFullExtent.svg'))
        self.mActionExportPdf.setIcon(
            QgsApplication.getThemeIcon('/mActionSaveAsPDF.svg'))
        self.mActionExportSvg.setIcon(
            QgsApplication.getThemeIcon('/mActionSaveAsSVG.svg'))
        self.toolbutton_export_to_script.setIcon(
            QgsApplication.getThemeIcon('/mActionSaveAsPython.svg'))
        self.mActionEditHelp.setIcon(
            QgsApplication.getThemeIcon('/mActionEditHelpContent.svg'))
        self.mActionRun.setIcon(
            QgsApplication.getThemeIcon('/mActionStart.svg'))

        self.addDockWidget(Qt.LeftDockWidgetArea, self.propertiesDock)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.inputsDock)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.algorithmsDock)
        self.tabifyDockWidget(self.inputsDock, self.algorithmsDock)
        self.inputsDock.raise_()

        self.setWindowFlags(Qt.WindowMinimizeButtonHint |
                            Qt.WindowMaximizeButtonHint |
                            Qt.WindowCloseButtonHint)

        settings = QgsSettings()
        self.restoreState(settings.value("/Processing/stateModeler", QByteArray()))
        self.restoreGeometry(settings.value("/Processing/geometryModeler", QByteArray()))

        self.scene = ModelerScene(self, dialog=self)
        self.scene.setSceneRect(QRectF(0, 0, self.CANVAS_SIZE, self.CANVAS_SIZE))

        self.view.setScene(self.scene)
        self.view.setAcceptDrops(True)
        self.view.ensureVisible(0, 0, 10, 10)
        self.view.scale(QgsApplication.desktop().logicalDpiX() / 96, QgsApplication.desktop().logicalDpiX() / 96)

        def _dragEnterEvent(event):
            if event.mimeData().hasText() or event.mimeData().hasFormat('application/x-vnd.qgis.qgis.algorithmid'):
                event.acceptProposedAction()
            else:
                event.ignore()

        def _dropEvent(event):
            def alg_dropped(algorithm_id, pos):
                alg = QgsApplication.processingRegistry().createAlgorithmById(algorithm_id)
                if alg is not None:
                    self._addAlgorithm(alg, pos)
                else:
                    assert False, algorithm_id

            def input_dropped(id, pos):
                if id in [param.id() for param in QgsApplication.instance().processingRegistry().parameterTypes()]:
                    self.addInputOfType(itemId, pos)

            if event.mimeData().hasFormat('application/x-vnd.qgis.qgis.algorithmid'):
                data = event.mimeData().data('application/x-vnd.qgis.qgis.algorithmid')
                stream = QDataStream(data, QIODevice.ReadOnly)
                algorithm_id = stream.readQString()
                QTimer.singleShot(0, lambda id=algorithm_id, pos=self.view.mapToScene(event.pos()): alg_dropped(id, pos))
                event.accept()
            elif event.mimeData().hasText():
                itemId = event.mimeData().text()
                QTimer.singleShot(0, lambda id=itemId, pos=self.view.mapToScene(event.pos()): input_dropped(id, pos))
                event.accept()
            else:
                event.ignore()

        def _dragMoveEvent(event):
            if event.mimeData().hasText() or event.mimeData().hasFormat('application/x-vnd.qgis.qgis.algorithmid'):
                event.accept()
            else:
                event.ignore()

        def _wheelEvent(event):
            self.view.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)

            settings = QgsSettings()
            factor = settings.value('/qgis/zoom_favor', 2.0)

            # "Normal" mouse has an angle delta of 120, precision mouses provide data
            # faster, in smaller steps
            factor = 1.0 + (factor - 1.0) / 120.0 * abs(event.angleDelta().y())

            if (event.modifiers() == Qt.ControlModifier):
                factor = 1.0 + (factor - 1.0) / 20.0

            if event.angleDelta().y() < 0:
                factor = 1 / factor

            self.view.scale(factor, factor)

        def _enterEvent(e):
            QGraphicsView.enterEvent(self.view, e)
            self.view.viewport().setCursor(Qt.ArrowCursor)

        def _mouseReleaseEvent(e):
            QGraphicsView.mouseReleaseEvent(self.view, e)
            self.view.viewport().setCursor(Qt.ArrowCursor)

        def _mousePressEvent(e):
            if e.button() == Qt.MidButton:
                self.previousMousePos = e.pos()
            else:
                QGraphicsView.mousePressEvent(self.view, e)

        def _mouseMoveEvent(e):
            if e.buttons() == Qt.MidButton:
                offset = self.previousMousePos - e.pos()
                self.previousMousePos = e.pos()

                self.view.verticalScrollBar().setValue(self.view.verticalScrollBar().value() + offset.y())
                self.view.horizontalScrollBar().setValue(self.view.horizontalScrollBar().value() + offset.x())
            else:
                QGraphicsView.mouseMoveEvent(self.view, e)

        self.view.setDragMode(QGraphicsView.ScrollHandDrag)
        self.view.dragEnterEvent = _dragEnterEvent
        self.view.dropEvent = _dropEvent
        self.view.dragMoveEvent = _dragMoveEvent
        self.view.wheelEvent = _wheelEvent
        self.view.enterEvent = _enterEvent
        self.view.mousePressEvent = _mousePressEvent
        self.view.mouseMoveEvent = _mouseMoveEvent

        def _mimeDataInput(items):
            mimeData = QMimeData()
            text = items[0].data(0, Qt.UserRole)
            mimeData.setText(text)
            return mimeData

        self.inputsTree.mimeData = _mimeDataInput

        self.inputsTree.setDragDropMode(QTreeWidget.DragOnly)
        self.inputsTree.setDropIndicatorShown(True)

        self.algorithms_model = ModelerToolboxModel(self, QgsApplication.processingRegistry())
        self.algorithmTree.setToolboxProxyModel(self.algorithms_model)
        self.algorithmTree.setDragDropMode(QTreeWidget.DragOnly)
        self.algorithmTree.setDropIndicatorShown(True)

        filters = QgsProcessingToolboxProxyModel.Filters(QgsProcessingToolboxProxyModel.FilterModeler)
        if ProcessingConfig.getSetting(ProcessingConfig.SHOW_ALGORITHMS_KNOWN_ISSUES):
            filters |= QgsProcessingToolboxProxyModel.FilterShowKnownIssues
        self.algorithmTree.setFilters(filters)

        if hasattr(self.searchBox, 'setPlaceholderText'):
            self.searchBox.setPlaceholderText(QCoreApplication.translate('ModelerDialog', 'Search…'))
        if hasattr(self.textName, 'setPlaceholderText'):
            self.textName.setPlaceholderText(self.tr('Enter model name here'))
        if hasattr(self.textGroup, 'setPlaceholderText'):
            self.textGroup.setPlaceholderText(self.tr('Enter group name here'))

        # Connect signals and slots
        self.inputsTree.doubleClicked.connect(self.addInput)
        self.searchBox.textChanged.connect(self.algorithmTree.setFilterString)
        self.algorithmTree.doubleClicked.connect(self.addAlgorithm)

        # Ctrl+= should also trigger a zoom in action
        ctrlEquals = QShortcut(QKeySequence("Ctrl+="), self)
        ctrlEquals.activated.connect(self.zoomIn)

        self.mActionOpen.triggered.connect(self.openModel)
        self.mActionSave.triggered.connect(self.save)
        self.mActionSaveAs.triggered.connect(self.saveAs)
        self.mActionSaveInProject.triggered.connect(self.saveInProject)
        self.mActionZoomIn.triggered.connect(self.zoomIn)
        self.mActionZoomOut.triggered.connect(self.zoomOut)
        self.mActionZoomActual.triggered.connect(self.zoomActual)
        self.mActionZoomToItems.triggered.connect(self.zoomToItems)
        self.mActionExportImage.triggered.connect(self.exportAsImage)
        self.mActionExportPdf.triggered.connect(self.exportAsPdf)
        self.mActionExportSvg.triggered.connect(self.exportAsSvg)
        #self.mActionExportPython.triggered.connect(self.exportAsPython)
        self.mActionEditHelp.triggered.connect(self.editHelp)
        self.mActionRun.triggered.connect(self.runModel)

        if model is not None:
            self.model = model.create()
            self.model.setSourceFilePath(model.sourceFilePath())
            self.textGroup.setText(self.model.group())
            self.textName.setText(self.model.displayName())
            self.repaintModel()

        else:
            self.model = QgsProcessingModelAlgorithm()
            self.model.setProvider(QgsApplication.processingRegistry().providerById('model'))
        self.update_variables_gui()

        self.fillInputsTree()

        self.view.centerOn(0, 0)
        self.help = None

        self.hasChanged = False

    def closeEvent(self, evt):
        settings = QgsSettings()
        settings.setValue("/Processing/stateModeler", self.saveState())
        settings.setValue("/Processing/geometryModeler", self.saveGeometry())

        if self.hasChanged:
            ret = QMessageBox.question(
                self, self.tr('Save Model?'),
                self.tr('There are unsaved changes in this model. Do you want to keep those?'),
                QMessageBox.Save | QMessageBox.Cancel | QMessageBox.Discard, QMessageBox.Cancel)

            if ret == QMessageBox.Save:
                self.saveModel(False)
                evt.accept()
            elif ret == QMessageBox.Discard:
                evt.accept()
            else:
                evt.ignore()
        else:
            evt.accept()

    def editHelp(self):
        alg = self.model
        dlg = HelpEditionDialog(alg)
        dlg.exec_()
        if dlg.descriptions:
            self.model.setHelpContent(dlg.descriptions)
            self.hasChanged = True

    def update_variables_gui(self):
        variables_scope = QgsExpressionContextScope(self.tr('Model Variables'))
        for k, v in self.model.variables().items():
            variables_scope.setVariable(k, v)
        variables_context = QgsExpressionContext()
        variables_context.appendScope(variables_scope)
        self.variables_editor.setContext(variables_context)
        self.variables_editor.setEditableScopeIndex(0)

    def variables_changed(self):
        self.model.setVariables(self.variables_editor.variablesInActiveScope())

    def runModel(self):
        if len(self.model.childAlgorithms()) == 0:
            self.bar.pushMessage("", self.tr("Model doesn't contain any algorithm and/or parameter and can't be executed"), level=Qgis.Warning, duration=5)
            return

        dlg = AlgorithmDialog(self.model.create(), parent=iface.mainWindow())
        dlg.exec_()

    def save(self):
        self.saveModel(False)

    def saveAs(self):
        self.saveModel(True)

    def saveInProject(self):
        if not self.can_save():
            return

        self.model.setName(str(self.textName.text()))
        self.model.setGroup(str(self.textGroup.text()))
        self.model.setSourceFilePath(None)

        project_provider = QgsApplication.processingRegistry().providerById(PROJECT_PROVIDER_ID)
        project_provider.add_model(self.model)

        self.update_model.emit()
        self.bar.pushMessage("", self.tr("Model was saved inside current project"), level=Qgis.Success, duration=5)

        self.hasChanged = False
        QgsProject.instance().setDirty(True)

    def zoomIn(self):
        self.view.setTransformationAnchor(QGraphicsView.NoAnchor)
        point = self.view.mapToScene(QPoint(self.view.viewport().width() / 2, self.view.viewport().height() / 2))

        settings = QgsSettings()
        factor = settings.value('/qgis/zoom_favor', 2.0)

        self.view.scale(factor, factor)
        self.view.centerOn(point)
        self.repaintModel()

    def zoomOut(self):
        self.view.setTransformationAnchor(QGraphicsView.NoAnchor)
        point = self.view.mapToScene(QPoint(self.view.viewport().width() / 2, self.view.viewport().height() / 2))

        settings = QgsSettings()
        factor = settings.value('/qgis/zoom_favor', 2.0)
        factor = 1 / factor

        self.view.scale(factor, factor)
        self.view.centerOn(point)
        self.repaintModel()

    def zoomActual(self):
        point = self.view.mapToScene(QPoint(self.view.viewport().width() / 2, self.view.viewport().height() / 2))
        self.view.resetTransform()
        self.view.scale(QgsApplication.desktop().logicalDpiX() / 96, QgsApplication.desktop().logicalDpiX() / 96)
        self.view.centerOn(point)

    def zoomToItems(self):
        totalRect = self.scene.itemsBoundingRect()
        totalRect.adjust(-10, -10, 10, 10)
        self.view.fitInView(totalRect, Qt.KeepAspectRatio)

    def exportAsImage(self):
        self.repaintModel(controls=False)
        filename, fileFilter = QFileDialog.getSaveFileName(self,
                                                           self.tr('Save Model As Image'), '',
                                                           self.tr('PNG files (*.png *.PNG)'))
        if not filename:
            return

        if not filename.lower().endswith('.png'):
            filename += '.png'

        totalRect = self.scene.itemsBoundingRect()
        totalRect.adjust(-10, -10, 10, 10)
        imgRect = QRectF(0, 0, totalRect.width(), totalRect.height())

        img = QImage(totalRect.width(), totalRect.height(),
                     QImage.Format_ARGB32_Premultiplied)
        img.fill(Qt.white)
        painter = QPainter()
        painter.setRenderHint(QPainter.Antialiasing)
        painter.begin(img)
        self.scene.render(painter, imgRect, totalRect)
        painter.end()

        img.save(filename)

        self.bar.pushMessage("", self.tr("Successfully exported model as image to <a href=\"{}\">{}</a>").format(QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5)
        self.repaintModel(controls=True)

    def exportAsPdf(self):
        self.repaintModel(controls=False)
        filename, fileFilter = QFileDialog.getSaveFileName(self,
                                                           self.tr('Save Model As PDF'), '',
                                                           self.tr('PDF files (*.pdf *.PDF)'))
        if not filename:
            return

        if not filename.lower().endswith('.pdf'):
            filename += '.pdf'

        totalRect = self.scene.itemsBoundingRect()
        totalRect.adjust(-10, -10, 10, 10)
        printerRect = QRectF(0, 0, totalRect.width(), totalRect.height())

        printer = QPrinter()
        printer.setOutputFormat(QPrinter.PdfFormat)
        printer.setOutputFileName(filename)
        printer.setPaperSize(QSizeF(printerRect.width(), printerRect.height()), QPrinter.DevicePixel)
        printer.setFullPage(True)

        painter = QPainter(printer)
        self.scene.render(painter, printerRect, totalRect)
        painter.end()

        self.bar.pushMessage("", self.tr("Successfully exported model as PDF to <a href=\"{}\">{}</a>").format(QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5)
        self.repaintModel(controls=True)

    def exportAsSvg(self):
        self.repaintModel(controls=False)
        filename, fileFilter = QFileDialog.getSaveFileName(self,
                                                           self.tr('Save Model As SVG'), '',
                                                           self.tr('SVG files (*.svg *.SVG)'))
        if not filename:
            return

        if not filename.lower().endswith('.svg'):
            filename += '.svg'

        totalRect = self.scene.itemsBoundingRect()
        totalRect.adjust(-10, -10, 10, 10)
        svgRect = QRectF(0, 0, totalRect.width(), totalRect.height())

        svg = QSvgGenerator()
        svg.setFileName(filename)
        svg.setSize(QSize(totalRect.width(), totalRect.height()))
        svg.setViewBox(svgRect)
        svg.setTitle(self.model.displayName())

        painter = QPainter(svg)
        self.scene.render(painter, svgRect, totalRect)
        painter.end()

        self.bar.pushMessage("", self.tr("Successfully exported model as SVG to <a href=\"{}\">{}</a>").format(QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5)
        self.repaintModel(controls=True)

    def exportAsPython(self):
        filename, filter = QFileDialog.getSaveFileName(self,
                                                       self.tr('Save Model As Python Script'), '',
                                                       self.tr('Processing scripts (*.py *.PY)'))
        if not filename:
            return

        if not filename.lower().endswith('.py'):
            filename += '.py'

        text = self.model.asPythonCode()
        with codecs.open(filename, 'w', encoding='utf-8') as fout:
            fout.write(text)

        self.bar.pushMessage("", self.tr("Successfully exported model as python script to <a href=\"{}\">{}</a>").format(QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5)

    def can_save(self):
        """
        Tests whether a model can be saved, or if it is not yet valid
        :return: bool
        """
        if str(self.textName.text()).strip() == '':
            self.bar.pushWarning(
                "", self.tr('Please a enter model name before saving')
            )
            return False

        return True

    def saveModel(self, saveAs):
        if not self.can_save():
            return
        self.model.setName(str(self.textName.text()))
        self.model.setGroup(str(self.textGroup.text()))
        if self.model.sourceFilePath() and not saveAs:
            filename = self.model.sourceFilePath()
        else:
            filename, filter = QFileDialog.getSaveFileName(self,
                                                           self.tr('Save Model'),
                                                           ModelerUtils.modelsFolders()[0],
                                                           self.tr('Processing models (*.model3 *.MODEL3)'))
            if filename:
                if not filename.endswith('.model3'):
                    filename += '.model3'
                self.model.setSourceFilePath(filename)
        if filename:
            if not self.model.toFile(filename):
                if saveAs:
                    QMessageBox.warning(self, self.tr('I/O error'),
                                        self.tr('Unable to save edits. Reason:\n {0}').format(str(sys.exc_info()[1])))
                else:
                    QMessageBox.warning(self, self.tr("Can't save model"), QCoreApplication.translate('QgsPluginInstallerInstallingDialog', (
                        "This model can't be saved in its original location (probably you do not "
                        "have permission to do it). Please, use the 'Save as…' option."))
                    )
                return
            self.update_model.emit()
            if saveAs:
                self.bar.pushMessage("", self.tr("Model was correctly saved to <a href=\"{}\">{}</a>").format(QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5)
            else:
                self.bar.pushMessage("", self.tr("Model was correctly saved"), level=Qgis.Success, duration=5)

            self.hasChanged = False

    def openModel(self):
        filename, selected_filter = QFileDialog.getOpenFileName(self,
                                                                self.tr('Open Model'),
                                                                ModelerUtils.modelsFolders()[0],
                                                                self.tr('Processing models (*.model3 *.MODEL3)'))
        if filename:
            self.loadModel(filename)

    def loadModel(self, filename):
        alg = QgsProcessingModelAlgorithm()
        if alg.fromFile(filename):
            self.model = alg
            self.model.setProvider(QgsApplication.processingRegistry().providerById('model'))
            self.textGroup.setText(alg.group())
            self.textName.setText(alg.name())
            self.repaintModel()

            self.update_variables_gui()

            self.view.centerOn(0, 0)
            self.hasChanged = False
        else:
            QgsMessageLog.logMessage(self.tr('Could not load model {0}').format(filename),
                                     self.tr('Processing'),
                                     Qgis.Critical)
            QMessageBox.critical(self, self.tr('Open Model'),
                                 self.tr('The selected model could not be loaded.\n'
                                         'See the log for more information.'))

    def repaintModel(self, controls=True):
        self.scene = ModelerScene(self, dialog=self)
        self.scene.setSceneRect(QRectF(0, 0, self.CANVAS_SIZE,
                                       self.CANVAS_SIZE))
        self.scene.paintModel(self.model, controls)
        self.view.setScene(self.scene)

    def addInput(self):
        item = self.inputsTree.currentItem()
        param = item.data(0, Qt.UserRole)
        self.addInputOfType(param)

    def addInputOfType(self, paramType, pos=None):
        dlg = ModelerParameterDefinitionDialog(self.model, paramType)
        dlg.exec_()
        if dlg.param is not None:
            if pos is None:
                pos = self.getPositionForParameterItem()
            if isinstance(pos, QPoint):
                pos = QPointF(pos)
            component = QgsProcessingModelParameter(dlg.param.name())
            component.setDescription(dlg.param.name())
            component.setPosition(pos)
            self.model.addModelParameter(dlg.param, component)
            self.repaintModel()
            # self.view.ensureVisible(self.scene.getLastParameterItem())
            self.hasChanged = True

    def getPositionForParameterItem(self):
        MARGIN = 20
        BOX_WIDTH = 200
        BOX_HEIGHT = 80
        if len(self.model.parameterComponents()) > 0:
            maxX = max([i.position().x() for i in list(self.model.parameterComponents().values())])
            newX = min(MARGIN + BOX_WIDTH + maxX, self.CANVAS_SIZE - BOX_WIDTH)
        else:
            newX = MARGIN + BOX_WIDTH / 2
        return QPointF(newX, MARGIN + BOX_HEIGHT / 2)

    def fillInputsTree(self):
        icon = QIcon(os.path.join(pluginPath, 'images', 'input.svg'))
        parametersItem = QTreeWidgetItem()
        parametersItem.setText(0, self.tr('Parameters'))
        sortedParams = sorted(QgsApplication.instance().processingRegistry().parameterTypes(), key=lambda pt: pt.name())
        for param in sortedParams:
            if param.flags() & QgsProcessingParameterType.ExposeToModeler:
                paramItem = QTreeWidgetItem()
                paramItem.setText(0, param.name())
                paramItem.setData(0, Qt.UserRole, param.id())
                paramItem.setIcon(0, icon)
                paramItem.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled)
                paramItem.setToolTip(0, param.description())
                parametersItem.addChild(paramItem)
        self.inputsTree.addTopLevelItem(parametersItem)
        parametersItem.setExpanded(True)

    def addAlgorithm(self):
        algorithm = self.algorithmTree.selectedAlgorithm()
        if algorithm is not None:
            alg = QgsApplication.processingRegistry().createAlgorithmById(algorithm.id())
            self._addAlgorithm(alg)

    def _addAlgorithm(self, alg, pos=None):
        dlg = ModelerParametersDialog(alg, self.model)
        if dlg.exec_():
            alg = dlg.createAlgorithm()
            if pos is None:
                alg.setPosition(self.getPositionForAlgorithmItem())
            else:
                alg.setPosition(pos)
            from processing.modeler.ModelerGraphicItem import ModelerGraphicItem
            for i, out in enumerate(alg.modelOutputs()):
                alg.modelOutput(out).setPosition(alg.position() + QPointF(ModelerGraphicItem.BOX_WIDTH, (i + 1.5) *
                                                                          ModelerGraphicItem.BOX_HEIGHT))
            self.model.addChildAlgorithm(alg)
            self.repaintModel()
            self.hasChanged = True

    def getPositionForAlgorithmItem(self):
        MARGIN = 20
        BOX_WIDTH = 200
        BOX_HEIGHT = 80
        if self.model.childAlgorithms():
            maxX = max([alg.position().x() for alg in list(self.model.childAlgorithms().values())])
            maxY = max([alg.position().y() for alg in list(self.model.childAlgorithms().values())])
            newX = min(MARGIN + BOX_WIDTH + maxX, self.CANVAS_SIZE - BOX_WIDTH)
            newY = min(MARGIN + BOX_HEIGHT + maxY, self.CANVAS_SIZE -
                       BOX_HEIGHT)
        else:
            newX = MARGIN + BOX_WIDTH / 2
            newY = MARGIN * 2 + BOX_HEIGHT + BOX_HEIGHT / 2
        return QPointF(newX, newY)

    def export_as_script_algorithm(self):
        dlg = ScriptEditorDialog(None)

        dlg.editor.setText('\n'.join(self.model.asPythonCode(QgsProcessing.PythonQgsProcessingAlgorithmSubclass, 4)))
        dlg.show()
コード例 #14
0
    def initWidgets(self):
        # If there are advanced parameters — show corresponding groupbox
        for param in self.alg.parameterDefinitions():
            if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced:
                self.grpAdvanced.show()
                break

        widget_context = QgsProcessingParameterWidgetContext()
        widget_context.setProject(QgsProject.instance())
        if iface is not None:
            widget_context.setMapCanvas(iface.mapCanvas())
        if isinstance(self.alg, QgsProcessingModelAlgorithm):
            widget_context.setModel(self.alg)

        # Create widgets and put them in layouts
        for param in self.alg.parameterDefinitions():
            if param.flags() & QgsProcessingParameterDefinition.FlagHidden:
                continue

            if param.isDestination():
                continue
            else:
                wrapper = WidgetWrapperFactory.create_wrapper(
                    param, self.parent)
                wrapper.setWidgetContext(widget_context)
                wrapper.registerProcessingContextGenerator(
                    self.context_generator)
                self.wrappers[param.name()] = wrapper

                # For compatibility with 3.x API, we need to check whether the wrapper is
                # the deprecated WidgetWrapper class. If not, it's the newer
                # QgsAbstractProcessingParameterWidgetWrapper class
                # TODO QGIS 4.0 - remove
                is_python_wrapper = issubclass(wrapper.__class__,
                                               WidgetWrapper)
                if not is_python_wrapper:
                    widget = wrapper.createWrappedWidget(
                        self.processing_context)
                else:
                    widget = wrapper.widget

                if self.in_place and param.name() in ('INPUT', 'OUTPUT'):
                    # don't show the input/output parameter widgets in in-place mode
                    # we still need to CREATE them, because other wrappers may need to interact
                    # with them (e.g. those parameters which need the input layer for field
                    # selections/crs properties/etc)
                    continue

                if widget is not None:
                    if is_python_wrapper:
                        widget.setToolTip(param.toolTip())

                    if isinstance(param, QgsProcessingParameterFeatureSource):
                        layout = QHBoxLayout()
                        layout.setSpacing(6)
                        layout.setMargin(0)
                        layout.addWidget(widget)
                        button = QToolButton()
                        icon = QIcon(
                            os.path.join(pluginPath, 'images', 'iterate.png'))
                        button.setIcon(icon)
                        button.setSizePolicy(QSizePolicy.Fixed,
                                             QSizePolicy.Expanding)
                        button.setToolTip(
                            self.
                            tr('Iterate over this layer, creating a separate output for every feature in the layer'
                               ))
                        button.setCheckable(True)
                        layout.addWidget(button)
                        layout.setAlignment(button, Qt.AlignTop)
                        self.iterateButtons[param.name()] = button
                        button.toggled.connect(self.buttonToggled)
                        widget = QWidget()
                        widget.setLayout(layout)

                    label = None
                    if not is_python_wrapper:
                        label = wrapper.createWrappedLabel()
                    else:
                        label = wrapper.label

                    if label is not None:
                        if param.flags(
                        ) & QgsProcessingParameterDefinition.FlagAdvanced:
                            self.layoutAdvanced.addWidget(label)
                        else:
                            self.layoutMain.insertWidget(
                                self.layoutMain.count() - 2, label)
                    elif is_python_wrapper:
                        desc = param.description()
                        if isinstance(param, QgsProcessingParameterExtent):
                            desc += self.tr(' (xmin, xmax, ymin, ymax)')
                        if isinstance(param, QgsProcessingParameterPoint):
                            desc += self.tr(' (x, y)')
                        if param.flags(
                        ) & QgsProcessingParameterDefinition.FlagOptional:
                            desc += self.tr(' [optional]')
                        widget.setText(desc)
                    if param.flags(
                    ) & QgsProcessingParameterDefinition.FlagAdvanced:
                        self.layoutAdvanced.addWidget(widget)
                    else:
                        self.layoutMain.insertWidget(
                            self.layoutMain.count() - 2, widget)

        for output in self.alg.destinationParameterDefinitions():
            if output.flags() & QgsProcessingParameterDefinition.FlagHidden:
                continue

            if self.in_place and param.name() in ('INPUT', 'OUTPUT'):
                continue

            label = QLabel(output.description())
            widget = DestinationSelectionPanel(output, self.alg)
            self.layoutMain.insertWidget(self.layoutMain.count() - 1, label)
            self.layoutMain.insertWidget(self.layoutMain.count() - 1, widget)
            if isinstance(output, (QgsProcessingParameterRasterDestination,
                                   QgsProcessingParameterFeatureSink,
                                   QgsProcessingParameterVectorDestination)):
                check = QCheckBox()
                check.setText(
                    QCoreApplication.translate(
                        'ParametersPanel',
                        'Open output file after running algorithm'))

                def skipOutputChanged(checkbox, skipped):
                    checkbox.setEnabled(not skipped)
                    if skipped:
                        checkbox.setChecked(False)

                check.setChecked(not widget.outputIsSkipped())
                check.setEnabled(not widget.outputIsSkipped())
                widget.skipOutputChanged.connect(
                    partial(skipOutputChanged, check))
                self.layoutMain.insertWidget(self.layoutMain.count() - 1,
                                             check)
                self.checkBoxes[output.name()] = check

            widget.setToolTip(param.toolTip())
            self.outputWidgets[output.name()] = widget

        for wrapper in list(self.wrappers.values()):
            wrapper.postInitialize(list(self.wrappers.values()))
コード例 #15
0
ファイル: console.py プロジェクト: edwardaskew/QGIS
class PythonConsoleWidget(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.setWindowTitle(
            QCoreApplication.translate("PythonConsole", "Python Console"))

        self.settings = QgsSettings()

        self.shell = ShellScintilla(self)
        self.setFocusProxy(self.shell)
        self.shellOut = ShellOutputScintilla(self)
        self.tabEditorWidget = EditorTabWidget(self)

        # ------------ UI -------------------------------

        self.splitterEditor = QSplitter(self)
        self.splitterEditor.setOrientation(Qt.Horizontal)
        self.splitterEditor.setHandleWidth(6)
        self.splitterEditor.setChildrenCollapsible(True)

        self.shellOutWidget = QWidget(self)
        self.shellOutWidget.setLayout(QVBoxLayout())
        self.shellOutWidget.layout().setContentsMargins(0, 0, 0, 0)
        self.shellOutWidget.layout().addWidget(self.shellOut)

        self.splitter = QSplitter(self.splitterEditor)
        self.splitter.setOrientation(Qt.Vertical)
        self.splitter.setHandleWidth(3)
        self.splitter.setChildrenCollapsible(False)
        self.splitter.addWidget(self.shellOutWidget)
        self.splitter.addWidget(self.shell)

        # self.splitterEditor.addWidget(self.tabEditorWidget)

        self.splitterObj = QSplitter(self.splitterEditor)
        self.splitterObj.setHandleWidth(3)
        self.splitterObj.setOrientation(Qt.Horizontal)
        # self.splitterObj.setSizes([0, 0])
        # self.splitterObj.setStretchFactor(0, 1)

        self.widgetEditor = QWidget(self.splitterObj)
        self.widgetFind = QWidget(self)

        self.listClassMethod = QTreeWidget(self.splitterObj)
        self.listClassMethod.setColumnCount(2)
        objInspLabel = QCoreApplication.translate("PythonConsole",
                                                  "Object Inspector")
        self.listClassMethod.setHeaderLabels([objInspLabel, ''])
        self.listClassMethod.setColumnHidden(1, True)
        self.listClassMethod.setAlternatingRowColors(True)

        # self.splitterEditor.addWidget(self.widgetEditor)
        # self.splitterObj.addWidget(self.listClassMethod)
        # self.splitterObj.addWidget(self.widgetEditor)

        # Hide side editor on start up
        self.splitterObj.hide()
        self.listClassMethod.hide()
        # Hide search widget on start up
        self.widgetFind.hide()

        icon_size = iface.iconSize(
            dockedToolbar=True) if iface else QSize(16, 16)

        sizes = self.splitter.sizes()
        self.splitter.setSizes(sizes)

        # ----------------Restore Settings------------------------------------

        self.restoreSettingsConsole()

        # ------------------Toolbar Editor-------------------------------------

        # Action for Open File
        openFileBt = QCoreApplication.translate("PythonConsole",
                                                "Open Script...")
        self.openFileButton = QAction(self)
        self.openFileButton.setCheckable(False)
        self.openFileButton.setEnabled(True)
        self.openFileButton.setIcon(
            QgsApplication.getThemeIcon("console/iconOpenConsole.png"))
        self.openFileButton.setMenuRole(QAction.PreferencesRole)
        self.openFileButton.setIconVisibleInMenu(True)
        self.openFileButton.setToolTip(openFileBt)
        self.openFileButton.setText(openFileBt)

        openExtEditorBt = QCoreApplication.translate(
            "PythonConsole", "Open in External Editor")
        self.openInEditorButton = QAction(self)
        self.openInEditorButton.setCheckable(False)
        self.openInEditorButton.setEnabled(True)
        self.openInEditorButton.setIcon(
            QgsApplication.getThemeIcon("console/iconShowEditorConsole.png"))
        self.openInEditorButton.setMenuRole(QAction.PreferencesRole)
        self.openInEditorButton.setIconVisibleInMenu(True)
        self.openInEditorButton.setToolTip(openExtEditorBt)
        self.openInEditorButton.setText(openExtEditorBt)
        # Action for Save File
        saveFileBt = QCoreApplication.translate("PythonConsole", "Save")
        self.saveFileButton = QAction(self)
        self.saveFileButton.setCheckable(False)
        self.saveFileButton.setEnabled(False)
        self.saveFileButton.setIcon(
            QgsApplication.getThemeIcon("console/iconSaveConsole.png"))
        self.saveFileButton.setMenuRole(QAction.PreferencesRole)
        self.saveFileButton.setIconVisibleInMenu(True)
        self.saveFileButton.setToolTip(saveFileBt)
        self.saveFileButton.setText(saveFileBt)
        # Action for Save File As
        saveAsFileBt = QCoreApplication.translate("PythonConsole",
                                                  "Save As...")
        self.saveAsFileButton = QAction(self)
        self.saveAsFileButton.setCheckable(False)
        self.saveAsFileButton.setEnabled(True)
        self.saveAsFileButton.setIcon(
            QgsApplication.getThemeIcon("console/iconSaveAsConsole.png"))
        self.saveAsFileButton.setMenuRole(QAction.PreferencesRole)
        self.saveAsFileButton.setIconVisibleInMenu(True)
        self.saveAsFileButton.setToolTip(saveAsFileBt)
        self.saveAsFileButton.setText(saveAsFileBt)
        # Action Cut
        cutEditorBt = QCoreApplication.translate("PythonConsole", "Cut")
        self.cutEditorButton = QAction(self)
        self.cutEditorButton.setCheckable(False)
        self.cutEditorButton.setEnabled(True)
        self.cutEditorButton.setIcon(
            QgsApplication.getThemeIcon("mActionEditCut.svg"))
        self.cutEditorButton.setMenuRole(QAction.PreferencesRole)
        self.cutEditorButton.setIconVisibleInMenu(True)
        self.cutEditorButton.setToolTip(cutEditorBt)
        self.cutEditorButton.setText(cutEditorBt)
        # Action Copy
        copyEditorBt = QCoreApplication.translate("PythonConsole", "Copy")
        self.copyEditorButton = QAction(self)
        self.copyEditorButton.setCheckable(False)
        self.copyEditorButton.setEnabled(True)
        self.copyEditorButton.setIcon(
            QgsApplication.getThemeIcon("mActionEditCopy.svg"))
        self.copyEditorButton.setMenuRole(QAction.PreferencesRole)
        self.copyEditorButton.setIconVisibleInMenu(True)
        self.copyEditorButton.setToolTip(copyEditorBt)
        self.copyEditorButton.setText(copyEditorBt)
        # Action Paste
        pasteEditorBt = QCoreApplication.translate("PythonConsole", "Paste")
        self.pasteEditorButton = QAction(self)
        self.pasteEditorButton.setCheckable(False)
        self.pasteEditorButton.setEnabled(True)
        self.pasteEditorButton.setIcon(
            QgsApplication.getThemeIcon("mActionEditPaste.svg"))
        self.pasteEditorButton.setMenuRole(QAction.PreferencesRole)
        self.pasteEditorButton.setIconVisibleInMenu(True)
        self.pasteEditorButton.setToolTip(pasteEditorBt)
        self.pasteEditorButton.setText(pasteEditorBt)
        # Action Run Script (subprocess)
        runScriptEditorBt = QCoreApplication.translate("PythonConsole",
                                                       "Run script")
        self.runScriptEditorButton = QAction(self)
        self.runScriptEditorButton.setCheckable(False)
        self.runScriptEditorButton.setEnabled(True)
        self.runScriptEditorButton.setIcon(
            QgsApplication.getThemeIcon("console/iconRunScriptConsole.png"))
        self.runScriptEditorButton.setMenuRole(QAction.PreferencesRole)
        self.runScriptEditorButton.setIconVisibleInMenu(True)
        self.runScriptEditorButton.setToolTip(runScriptEditorBt)
        self.runScriptEditorButton.setText(runScriptEditorBt)
        # Action Run Script (subprocess)
        commentEditorBt = QCoreApplication.translate("PythonConsole",
                                                     "Comment")
        self.commentEditorButton = QAction(self)
        self.commentEditorButton.setCheckable(False)
        self.commentEditorButton.setEnabled(True)
        self.commentEditorButton.setIcon(
            QgsApplication.getThemeIcon(
                "console/iconCommentEditorConsole.png"))
        self.commentEditorButton.setMenuRole(QAction.PreferencesRole)
        self.commentEditorButton.setIconVisibleInMenu(True)
        self.commentEditorButton.setToolTip(commentEditorBt)
        self.commentEditorButton.setText(commentEditorBt)
        # Action Run Script (subprocess)
        uncommentEditorBt = QCoreApplication.translate("PythonConsole",
                                                       "Uncomment")
        self.uncommentEditorButton = QAction(self)
        self.uncommentEditorButton.setCheckable(False)
        self.uncommentEditorButton.setEnabled(True)
        self.uncommentEditorButton.setIcon(
            QgsApplication.getThemeIcon(
                "console/iconUncommentEditorConsole.png"))
        self.uncommentEditorButton.setMenuRole(QAction.PreferencesRole)
        self.uncommentEditorButton.setIconVisibleInMenu(True)
        self.uncommentEditorButton.setToolTip(uncommentEditorBt)
        self.uncommentEditorButton.setText(uncommentEditorBt)
        # Action for Object browser
        objList = QCoreApplication.translate("PythonConsole",
                                             "Object Inspector...")
        self.objectListButton = QAction(self)
        self.objectListButton.setCheckable(True)
        self.objectListButton.setEnabled(
            self.settings.value("pythonConsole/enableObjectInsp",
                                False,
                                type=bool))
        self.objectListButton.setIcon(
            QgsApplication.getThemeIcon("console/iconClassBrowserConsole.png"))
        self.objectListButton.setMenuRole(QAction.PreferencesRole)
        self.objectListButton.setIconVisibleInMenu(True)
        self.objectListButton.setToolTip(objList)
        self.objectListButton.setText(objList)
        # Action for Find text
        findText = QCoreApplication.translate("PythonConsole", "Find Text")
        self.findTextButton = QAction(self)
        self.findTextButton.setCheckable(True)
        self.findTextButton.setEnabled(True)
        self.findTextButton.setIcon(
            QgsApplication.getThemeIcon("console/iconSearchEditorConsole.png"))
        self.findTextButton.setMenuRole(QAction.PreferencesRole)
        self.findTextButton.setIconVisibleInMenu(True)
        self.findTextButton.setToolTip(findText)
        self.findTextButton.setText(findText)

        # ----------------Toolbar Console-------------------------------------

        # Action Show Editor
        showEditor = QCoreApplication.translate("PythonConsole", "Show Editor")
        self.showEditorButton = QAction(self)
        self.showEditorButton.setEnabled(True)
        self.showEditorButton.setCheckable(True)
        self.showEditorButton.setIcon(
            QgsApplication.getThemeIcon("console/iconShowEditorConsole.png"))
        self.showEditorButton.setMenuRole(QAction.PreferencesRole)
        self.showEditorButton.setIconVisibleInMenu(True)
        self.showEditorButton.setToolTip(showEditor)
        self.showEditorButton.setText(showEditor)
        # Action for Clear button
        clearBt = QCoreApplication.translate("PythonConsole", "Clear Console")
        self.clearButton = QAction(self)
        self.clearButton.setCheckable(False)
        self.clearButton.setEnabled(True)
        self.clearButton.setIcon(
            QgsApplication.getThemeIcon("console/iconClearConsole.png"))
        self.clearButton.setMenuRole(QAction.PreferencesRole)
        self.clearButton.setIconVisibleInMenu(True)
        self.clearButton.setToolTip(clearBt)
        self.clearButton.setText(clearBt)
        # Action for settings
        optionsBt = QCoreApplication.translate("PythonConsole", "Options...")
        self.optionsButton = QAction(self)
        self.optionsButton.setCheckable(False)
        self.optionsButton.setEnabled(True)
        self.optionsButton.setIcon(
            QgsApplication.getThemeIcon("console/iconSettingsConsole.png"))
        self.optionsButton.setMenuRole(QAction.PreferencesRole)
        self.optionsButton.setIconVisibleInMenu(True)
        self.optionsButton.setToolTip(optionsBt)
        self.optionsButton.setText(optionsBt)
        # Action for Run script
        runBt = QCoreApplication.translate("PythonConsole", "Run Command")
        self.runButton = QAction(self)
        self.runButton.setCheckable(False)
        self.runButton.setEnabled(True)
        self.runButton.setIcon(
            QgsApplication.getThemeIcon("console/iconRunConsole.png"))
        self.runButton.setMenuRole(QAction.PreferencesRole)
        self.runButton.setIconVisibleInMenu(True)
        self.runButton.setToolTip(runBt)
        self.runButton.setText(runBt)
        # Help action
        helpBt = QCoreApplication.translate("PythonConsole", "Help...")
        self.helpButton = QAction(self)
        self.helpButton.setCheckable(False)
        self.helpButton.setEnabled(True)
        self.helpButton.setIcon(
            QgsApplication.getThemeIcon("console/iconHelpConsole.png"))
        self.helpButton.setMenuRole(QAction.PreferencesRole)
        self.helpButton.setIconVisibleInMenu(True)
        self.helpButton.setToolTip(helpBt)
        self.helpButton.setText(helpBt)

        self.toolBar = QToolBar()
        self.toolBar.setEnabled(True)
        self.toolBar.setFocusPolicy(Qt.NoFocus)
        self.toolBar.setContextMenuPolicy(Qt.DefaultContextMenu)
        self.toolBar.setLayoutDirection(Qt.LeftToRight)
        self.toolBar.setIconSize(icon_size)
        self.toolBar.setMovable(False)
        self.toolBar.setFloatable(False)
        self.toolBar.addAction(self.clearButton)
        self.toolBar.addAction(self.runButton)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.showEditorButton)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.optionsButton)
        self.toolBar.addAction(self.helpButton)

        self.toolBarEditor = QToolBar()
        self.toolBarEditor.setEnabled(False)
        self.toolBarEditor.setFocusPolicy(Qt.NoFocus)
        self.toolBarEditor.setContextMenuPolicy(Qt.DefaultContextMenu)
        self.toolBarEditor.setLayoutDirection(Qt.LeftToRight)
        self.toolBarEditor.setIconSize(icon_size)
        self.toolBarEditor.setMovable(False)
        self.toolBarEditor.setFloatable(False)
        self.toolBarEditor.addAction(self.openFileButton)
        self.toolBarEditor.addAction(self.openInEditorButton)
        self.toolBarEditor.addSeparator()
        self.toolBarEditor.addAction(self.saveFileButton)
        self.toolBarEditor.addAction(self.saveAsFileButton)
        self.toolBarEditor.addSeparator()
        self.toolBarEditor.addAction(self.runScriptEditorButton)
        self.toolBarEditor.addSeparator()
        self.toolBarEditor.addAction(self.findTextButton)
        self.toolBarEditor.addSeparator()
        self.toolBarEditor.addAction(self.cutEditorButton)
        self.toolBarEditor.addAction(self.copyEditorButton)
        self.toolBarEditor.addAction(self.pasteEditorButton)
        self.toolBarEditor.addSeparator()
        self.toolBarEditor.addAction(self.commentEditorButton)
        self.toolBarEditor.addAction(self.uncommentEditorButton)
        self.toolBarEditor.addSeparator()
        self.toolBarEditor.addAction(self.objectListButton)

        self.widgetButton = QWidget()
        sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.widgetButton.sizePolicy().hasHeightForWidth())
        self.widgetButton.setSizePolicy(sizePolicy)

        self.widgetButtonEditor = QWidget(self.widgetEditor)
        sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.widgetButtonEditor.sizePolicy().hasHeightForWidth())
        self.widgetButtonEditor.setSizePolicy(sizePolicy)

        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.shellOut.sizePolicy().hasHeightForWidth())
        self.shellOut.setSizePolicy(sizePolicy)

        self.shellOut.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.shell.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)

        # ------------ Layout -------------------------------

        self.mainLayout = QGridLayout(self)
        self.mainLayout.setMargin(0)
        self.mainLayout.setSpacing(0)
        self.mainLayout.addWidget(self.widgetButton, 0, 0, 1, 1)
        self.mainLayout.addWidget(self.splitterEditor, 0, 1, 1, 1)

        self.shellOutWidget.layout().insertWidget(0, self.toolBar)

        self.layoutEditor = QGridLayout(self.widgetEditor)
        self.layoutEditor.setMargin(0)
        self.layoutEditor.setSpacing(0)
        self.layoutEditor.addWidget(self.toolBarEditor, 0, 1, 1, 1)
        self.layoutEditor.addWidget(self.widgetButtonEditor, 1, 0, 2, 1)
        self.layoutEditor.addWidget(self.tabEditorWidget, 1, 1, 1, 1)
        self.layoutEditor.addWidget(self.widgetFind, 2, 1, 1, 1)

        #  Layout for the find widget
        self.layoutFind = QGridLayout(self.widgetFind)
        self.layoutFind.setContentsMargins(0, 0, 0, 0)
        self.lineEditFind = QgsFilterLineEdit()
        placeHolderTxt = QCoreApplication.translate("PythonConsole",
                                                    "Enter text to find...")

        self.lineEditFind.setPlaceholderText(placeHolderTxt)
        self.findNextButton = QToolButton()
        self.findNextButton.setEnabled(False)
        toolTipfindNext = QCoreApplication.translate("PythonConsole",
                                                     "Find Next")
        self.findNextButton.setToolTip(toolTipfindNext)
        self.findNextButton.setIcon(
            QgsApplication.getThemeIcon(
                "console/iconSearchNextEditorConsole.png"))
        self.findNextButton.setIconSize(QSize(24, 24))
        self.findNextButton.setAutoRaise(True)
        self.findPrevButton = QToolButton()
        self.findPrevButton.setEnabled(False)
        toolTipfindPrev = QCoreApplication.translate("PythonConsole",
                                                     "Find Previous")
        self.findPrevButton.setToolTip(toolTipfindPrev)
        self.findPrevButton.setIcon(
            QgsApplication.getThemeIcon(
                "console/iconSearchPrevEditorConsole.png"))
        self.findPrevButton.setIconSize(QSize(24, 24))
        self.findPrevButton.setAutoRaise(True)
        self.caseSensitive = QCheckBox()
        caseSensTr = QCoreApplication.translate("PythonConsole",
                                                "Case Sensitive")
        self.caseSensitive.setText(caseSensTr)
        self.wholeWord = QCheckBox()
        wholeWordTr = QCoreApplication.translate("PythonConsole", "Whole Word")
        self.wholeWord.setText(wholeWordTr)
        self.wrapAround = QCheckBox()
        self.wrapAround.setChecked(True)
        wrapAroundTr = QCoreApplication.translate("PythonConsole",
                                                  "Wrap Around")
        self.wrapAround.setText(wrapAroundTr)
        self.layoutFind.addWidget(self.lineEditFind, 0, 1, 1, 1)
        self.layoutFind.addWidget(self.findPrevButton, 0, 2, 1, 1)
        self.layoutFind.addWidget(self.findNextButton, 0, 3, 1, 1)
        self.layoutFind.addWidget(self.caseSensitive, 0, 4, 1, 1)
        self.layoutFind.addWidget(self.wholeWord, 0, 5, 1, 1)
        self.layoutFind.addWidget(self.wrapAround, 0, 6, 1, 1)

        # ------------ Add first Tab in Editor -------------------------------

        # self.tabEditorWidget.newTabEditor(tabName='first', filename=None)

        # ------------ Signal -------------------------------

        self.findTextButton.triggered.connect(self._toggleFind)
        self.objectListButton.toggled.connect(self.toggleObjectListWidget)
        self.commentEditorButton.triggered.connect(self.commentCode)
        self.uncommentEditorButton.triggered.connect(self.uncommentCode)
        self.runScriptEditorButton.triggered.connect(self.runScriptEditor)
        self.cutEditorButton.triggered.connect(self.cutEditor)
        self.copyEditorButton.triggered.connect(self.copyEditor)
        self.pasteEditorButton.triggered.connect(self.pasteEditor)
        self.showEditorButton.toggled.connect(self.toggleEditor)
        self.clearButton.triggered.connect(self.shellOut.clearConsole)
        self.optionsButton.triggered.connect(self.openSettings)
        self.runButton.triggered.connect(self.shell.entered)
        self.openFileButton.triggered.connect(self.openScriptFile)
        self.openInEditorButton.triggered.connect(self.openScriptFileExtEditor)
        self.saveFileButton.triggered.connect(self.saveScriptFile)
        self.saveAsFileButton.triggered.connect(self.saveAsScriptFile)
        self.helpButton.triggered.connect(self.openHelp)
        self.listClassMethod.itemClicked.connect(self.onClickGoToLine)
        self.lineEditFind.returnPressed.connect(self._findNext)
        self.findNextButton.clicked.connect(self._findNext)
        self.findPrevButton.clicked.connect(self._findPrev)
        self.lineEditFind.textChanged.connect(self._textFindChanged)

        self.findScut = QShortcut(QKeySequence.Find, self.widgetEditor)
        self.findScut.setContext(Qt.WidgetWithChildrenShortcut)
        self.findScut.activated.connect(self._openFind)

        self.findNextScut = QShortcut(QKeySequence.FindNext, self.widgetEditor)
        self.findNextScut.setContext(Qt.WidgetWithChildrenShortcut)
        self.findNextScut.activated.connect(self._findNext)

        self.findPreviousScut = QShortcut(QKeySequence.FindPrevious,
                                          self.widgetEditor)
        self.findPreviousScut.setContext(Qt.WidgetWithChildrenShortcut)
        self.findPreviousScut.activated.connect(self._findPrev)

        # Escape on editor hides the find bar
        self.findScut = QShortcut(Qt.Key_Escape, self.widgetEditor)
        self.findScut.setContext(Qt.WidgetWithChildrenShortcut)
        self.findScut.activated.connect(self._closeFind)

    def _toggleFind(self):
        self.tabEditorWidget.currentWidget().newEditor.toggleFindWidget()

    def _openFind(self):
        self.tabEditorWidget.currentWidget().newEditor.openFindWidget()

    def _closeFind(self):
        self.tabEditorWidget.currentWidget().newEditor.closeFindWidget()

    def _findNext(self):
        self.tabEditorWidget.currentWidget().newEditor.findText(True)

    def _findPrev(self):
        self.tabEditorWidget.currentWidget().newEditor.findText(False)

    def _textFindChanged(self):
        if self.lineEditFind.text():
            self.findNextButton.setEnabled(True)
            self.findPrevButton.setEnabled(True)
            self.tabEditorWidget.currentWidget().newEditor.findText(
                True, showMessage=False, findFirst=True)
        else:
            self.lineEditFind.setStyleSheet('')
            self.findNextButton.setEnabled(False)
            self.findPrevButton.setEnabled(False)

    def onClickGoToLine(self, item, column):
        tabEditor = self.tabEditorWidget.currentWidget().newEditor
        if item.text(1) == 'syntaxError':
            check = tabEditor.syntaxCheck(fromContextMenu=False)
            if check and not tabEditor.isReadOnly():
                self.tabEditorWidget.currentWidget().save()
            return
        linenr = int(item.text(1))
        itemName = str(item.text(0))
        charPos = itemName.find(' ')
        if charPos != -1:
            objName = itemName[0:charPos]
        else:
            objName = itemName
        tabEditor.goToLine(objName, linenr)

    def toggleEditor(self, checked):
        self.splitterObj.show() if checked else self.splitterObj.hide()
        if not self.tabEditorWidget:
            self.tabEditorWidget.enableToolBarEditor(checked)
            self.tabEditorWidget.restoreTabsOrAddNew()

    def toggleObjectListWidget(self, checked):
        self.listClassMethod.show() if checked else self.listClassMethod.hide()

    def pasteEditor(self):
        self.tabEditorWidget.currentWidget().newEditor.paste()

    def cutEditor(self):
        self.tabEditorWidget.currentWidget().newEditor.cut()

    def copyEditor(self):
        self.tabEditorWidget.currentWidget().newEditor.copy()

    def runScriptEditor(self):
        self.tabEditorWidget.currentWidget().newEditor.runScriptCode()

    def commentCode(self):
        self.tabEditorWidget.currentWidget().newEditor.commentEditorCode(True)

    def uncommentCode(self):
        self.tabEditorWidget.currentWidget().newEditor.commentEditorCode(False)

    def openScriptFileExtEditor(self):
        tabWidget = self.tabEditorWidget.currentWidget()
        path = tabWidget.path
        import subprocess
        try:
            subprocess.Popen([os.environ['EDITOR'], path])
        except KeyError:
            QDesktopServices.openUrl(QUrl.fromLocalFile(path))

    def openScriptFile(self):
        lastDirPath = self.settings.value("pythonConsole/lastDirPath",
                                          QDir.homePath())
        openFileTr = QCoreApplication.translate("PythonConsole", "Open File")
        fileList, selected_filter = QFileDialog.getOpenFileNames(
            self, openFileTr, lastDirPath, "Script file (*.py)")
        if fileList:
            for pyFile in fileList:
                for i in range(self.tabEditorWidget.count()):
                    tabWidget = self.tabEditorWidget.widget(i)
                    if tabWidget.path == pyFile:
                        self.tabEditorWidget.setCurrentWidget(tabWidget)
                        break
                else:
                    tabName = QFileInfo(pyFile).fileName()
                    self.tabEditorWidget.newTabEditor(tabName, pyFile)

                    lastDirPath = QFileInfo(pyFile).path()
                    self.settings.setValue("pythonConsole/lastDirPath", pyFile)
                    self.updateTabListScript(pyFile, action='append')

    def saveScriptFile(self):
        tabWidget = self.tabEditorWidget.currentWidget()
        try:
            tabWidget.save()
        except (IOError, OSError) as error:
            msgText = QCoreApplication.translate(
                'PythonConsole',
                'The file <b>{0}</b> could not be saved. Error: {1}').format(
                    tabWidget.path, error.strerror)
            self.callWidgetMessageBarEditor(msgText, 2, False)

    def saveAsScriptFile(self, index=None):
        tabWidget = self.tabEditorWidget.currentWidget()
        if not index:
            index = self.tabEditorWidget.currentIndex()
        if not tabWidget.path:
            fileName = self.tabEditorWidget.tabText(index) + '.py'
            folder = self.settings.value("pythonConsole/lastDirPath",
                                         QDir.home())
            pathFileName = os.path.join(folder, fileName)
            fileNone = True
        else:
            pathFileName = tabWidget.path
            fileNone = False
        saveAsFileTr = QCoreApplication.translate("PythonConsole",
                                                  "Save File As")
        filename, filter = QFileDialog.getSaveFileName(self, saveAsFileTr,
                                                       pathFileName,
                                                       "Script file (*.py)")
        if filename:
            try:
                tabWidget.save(filename)
            except (IOError, OSError) as error:
                msgText = QCoreApplication.translate(
                    'PythonConsole',
                    'The file <b>{0}</b> could not be saved. Error: {1}'
                ).format(tabWidget.path, error.strerror)
                self.callWidgetMessageBarEditor(msgText, 2, False)
                if fileNone:
                    tabWidget.path = None
                else:
                    tabWidget.path = pathFileName
                return

            if not fileNone:
                self.updateTabListScript(pathFileName, action='remove')

    def openHelp(self):
        QgsHelp.openHelp("plugins/python_console.html")

    def openSettings(self):
        if optionsDialog(self).exec_():
            self.shell.refreshSettingsShell()
            self.shellOut.refreshSettingsOutput()
            self.tabEditorWidget.refreshSettingsEditor()

    def callWidgetMessageBar(self, text):
        self.shellOut.widgetMessageBar(iface, text)

    def callWidgetMessageBarEditor(self, text, level, timed):
        self.tabEditorWidget.widgetMessageBar(iface, text, level, timed)

    def updateTabListScript(self, script, action=None):
        if action == 'remove':
            self.tabListScript.remove(script)
        elif action == 'append':
            if not self.tabListScript:
                self.tabListScript = []
            if script not in self.tabListScript:
                self.tabListScript.append(script)
        else:
            self.tabListScript = []
        self.settings.setValue("pythonConsole/tabScripts", self.tabListScript)

    def saveSettingsConsole(self):
        self.settings.setValue("pythonConsole/splitterConsole",
                               self.splitter.saveState())
        self.settings.setValue("pythonConsole/splitterObj",
                               self.splitterObj.saveState())
        self.settings.setValue("pythonConsole/splitterEditor",
                               self.splitterEditor.saveState())

        self.shell.writeHistoryFile(True)

    def restoreSettingsConsole(self):
        storedTabScripts = self.settings.value("pythonConsole/tabScripts", [])
        self.tabListScript = storedTabScripts
        self.splitter.restoreState(
            self.settings.value("pythonConsole/splitterConsole", QByteArray()))
        self.splitterEditor.restoreState(
            self.settings.value("pythonConsole/splitterEditor", QByteArray()))
        self.splitterObj.restoreState(
            self.settings.value("pythonConsole/splitterObj", QByteArray()))
コード例 #16
0
ファイル: console.py プロジェクト: cayetanobv/QGIS
class PythonConsoleWidget(QWidget):

    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.setWindowTitle(QCoreApplication.translate("PythonConsole", "Python Console"))

        self.settings = QgsSettings()

        self.shell = ShellScintilla(self)
        self.setFocusProxy(self.shell)
        self.shellOut = ShellOutputScintilla(self)
        self.tabEditorWidget = EditorTabWidget(self)

        # ------------ UI -------------------------------

        self.splitterEditor = QSplitter(self)
        self.splitterEditor.setOrientation(Qt.Horizontal)
        self.splitterEditor.setHandleWidth(6)
        self.splitterEditor.setChildrenCollapsible(True)

        self.shellOutWidget = QWidget(self)
        self.shellOutWidget.setLayout(QVBoxLayout())
        self.shellOutWidget.layout().setContentsMargins(0, 0, 0, 0)
        self.shellOutWidget.layout().addWidget(self.shellOut)

        self.splitter = QSplitter(self.splitterEditor)
        self.splitter.setOrientation(Qt.Vertical)
        self.splitter.setHandleWidth(3)
        self.splitter.setChildrenCollapsible(False)
        self.splitter.addWidget(self.shellOutWidget)
        self.splitter.addWidget(self.shell)

        # self.splitterEditor.addWidget(self.tabEditorWidget)

        self.splitterObj = QSplitter(self.splitterEditor)
        self.splitterObj.setHandleWidth(3)
        self.splitterObj.setOrientation(Qt.Horizontal)
        # self.splitterObj.setSizes([0, 0])
        # self.splitterObj.setStretchFactor(0, 1)

        self.widgetEditor = QWidget(self.splitterObj)
        self.widgetFind = QWidget(self)

        self.listClassMethod = QTreeWidget(self.splitterObj)
        self.listClassMethod.setColumnCount(2)
        objInspLabel = QCoreApplication.translate("PythonConsole", "Object Inspector")
        self.listClassMethod.setHeaderLabels([objInspLabel, ''])
        self.listClassMethod.setColumnHidden(1, True)
        self.listClassMethod.setAlternatingRowColors(True)

        # self.splitterEditor.addWidget(self.widgetEditor)
        # self.splitterObj.addWidget(self.listClassMethod)
        # self.splitterObj.addWidget(self.widgetEditor)

        # Hide side editor on start up
        self.splitterObj.hide()
        self.listClassMethod.hide()
        # Hide search widget on start up
        self.widgetFind.hide()

        sizes = self.splitter.sizes()
        self.splitter.setSizes(sizes)

        # ----------------Restore Settings------------------------------------

        self.restoreSettingsConsole()

        # ------------------Toolbar Editor-------------------------------------

        # Action for Open File
        openFileBt = QCoreApplication.translate("PythonConsole", "Open Script...")
        self.openFileButton = QAction(self)
        self.openFileButton.setCheckable(False)
        self.openFileButton.setEnabled(True)
        self.openFileButton.setIcon(QgsApplication.getThemeIcon("console/iconOpenConsole.png"))
        self.openFileButton.setMenuRole(QAction.PreferencesRole)
        self.openFileButton.setIconVisibleInMenu(True)
        self.openFileButton.setToolTip(openFileBt)
        self.openFileButton.setText(openFileBt)

        openExtEditorBt = QCoreApplication.translate("PythonConsole", "Open in External Editor")
        self.openInEditorButton = QAction(self)
        self.openInEditorButton.setCheckable(False)
        self.openInEditorButton.setEnabled(True)
        self.openInEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconShowEditorConsole.png"))
        self.openInEditorButton.setMenuRole(QAction.PreferencesRole)
        self.openInEditorButton.setIconVisibleInMenu(True)
        self.openInEditorButton.setToolTip(openExtEditorBt)
        self.openInEditorButton.setText(openExtEditorBt)
        # Action for Save File
        saveFileBt = QCoreApplication.translate("PythonConsole", "Save")
        self.saveFileButton = QAction(self)
        self.saveFileButton.setCheckable(False)
        self.saveFileButton.setEnabled(False)
        self.saveFileButton.setIcon(QgsApplication.getThemeIcon("console/iconSaveConsole.png"))
        self.saveFileButton.setMenuRole(QAction.PreferencesRole)
        self.saveFileButton.setIconVisibleInMenu(True)
        self.saveFileButton.setToolTip(saveFileBt)
        self.saveFileButton.setText(saveFileBt)
        # Action for Save File As
        saveAsFileBt = QCoreApplication.translate("PythonConsole", "Save As...")
        self.saveAsFileButton = QAction(self)
        self.saveAsFileButton.setCheckable(False)
        self.saveAsFileButton.setEnabled(True)
        self.saveAsFileButton.setIcon(QgsApplication.getThemeIcon("console/iconSaveAsConsole.png"))
        self.saveAsFileButton.setMenuRole(QAction.PreferencesRole)
        self.saveAsFileButton.setIconVisibleInMenu(True)
        self.saveAsFileButton.setToolTip(saveAsFileBt)
        self.saveAsFileButton.setText(saveAsFileBt)
        # Action Cut
        cutEditorBt = QCoreApplication.translate("PythonConsole", "Cut")
        self.cutEditorButton = QAction(self)
        self.cutEditorButton.setCheckable(False)
        self.cutEditorButton.setEnabled(True)
        self.cutEditorButton.setIcon(QgsApplication.getThemeIcon("mActionEditCut.svg"))
        self.cutEditorButton.setMenuRole(QAction.PreferencesRole)
        self.cutEditorButton.setIconVisibleInMenu(True)
        self.cutEditorButton.setToolTip(cutEditorBt)
        self.cutEditorButton.setText(cutEditorBt)
        # Action Copy
        copyEditorBt = QCoreApplication.translate("PythonConsole", "Copy")
        self.copyEditorButton = QAction(self)
        self.copyEditorButton.setCheckable(False)
        self.copyEditorButton.setEnabled(True)
        self.copyEditorButton.setIcon(QgsApplication.getThemeIcon("mActionEditCopy.svg"))
        self.copyEditorButton.setMenuRole(QAction.PreferencesRole)
        self.copyEditorButton.setIconVisibleInMenu(True)
        self.copyEditorButton.setToolTip(copyEditorBt)
        self.copyEditorButton.setText(copyEditorBt)
        # Action Paste
        pasteEditorBt = QCoreApplication.translate("PythonConsole", "Paste")
        self.pasteEditorButton = QAction(self)
        self.pasteEditorButton.setCheckable(False)
        self.pasteEditorButton.setEnabled(True)
        self.pasteEditorButton.setIcon(QgsApplication.getThemeIcon("mActionEditPaste.svg"))
        self.pasteEditorButton.setMenuRole(QAction.PreferencesRole)
        self.pasteEditorButton.setIconVisibleInMenu(True)
        self.pasteEditorButton.setToolTip(pasteEditorBt)
        self.pasteEditorButton.setText(pasteEditorBt)
        # Action Run Script (subprocess)
        runScriptEditorBt = QCoreApplication.translate("PythonConsole", "Run script")
        self.runScriptEditorButton = QAction(self)
        self.runScriptEditorButton.setCheckable(False)
        self.runScriptEditorButton.setEnabled(True)
        self.runScriptEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconRunScriptConsole.png"))
        self.runScriptEditorButton.setMenuRole(QAction.PreferencesRole)
        self.runScriptEditorButton.setIconVisibleInMenu(True)
        self.runScriptEditorButton.setToolTip(runScriptEditorBt)
        self.runScriptEditorButton.setText(runScriptEditorBt)
        # Action Run Script (subprocess)
        commentEditorBt = QCoreApplication.translate("PythonConsole", "Comment")
        self.commentEditorButton = QAction(self)
        self.commentEditorButton.setCheckable(False)
        self.commentEditorButton.setEnabled(True)
        self.commentEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconCommentEditorConsole.png"))
        self.commentEditorButton.setMenuRole(QAction.PreferencesRole)
        self.commentEditorButton.setIconVisibleInMenu(True)
        self.commentEditorButton.setToolTip(commentEditorBt)
        self.commentEditorButton.setText(commentEditorBt)
        # Action Run Script (subprocess)
        uncommentEditorBt = QCoreApplication.translate("PythonConsole", "Uncomment")
        self.uncommentEditorButton = QAction(self)
        self.uncommentEditorButton.setCheckable(False)
        self.uncommentEditorButton.setEnabled(True)
        self.uncommentEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconUncommentEditorConsole.png"))
        self.uncommentEditorButton.setMenuRole(QAction.PreferencesRole)
        self.uncommentEditorButton.setIconVisibleInMenu(True)
        self.uncommentEditorButton.setToolTip(uncommentEditorBt)
        self.uncommentEditorButton.setText(uncommentEditorBt)
        # Action for Object browser
        objList = QCoreApplication.translate("PythonConsole", "Object Inspector...")
        self.objectListButton = QAction(self)
        self.objectListButton.setCheckable(True)
        self.objectListButton.setEnabled(self.settings.value("pythonConsole/enableObjectInsp",
                                                             False, type=bool))
        self.objectListButton.setIcon(QgsApplication.getThemeIcon("console/iconClassBrowserConsole.png"))
        self.objectListButton.setMenuRole(QAction.PreferencesRole)
        self.objectListButton.setIconVisibleInMenu(True)
        self.objectListButton.setToolTip(objList)
        self.objectListButton.setText(objList)
        # Action for Find text
        findText = QCoreApplication.translate("PythonConsole", "Find Text")
        self.findTextButton = QAction(self)
        self.findTextButton.setCheckable(True)
        self.findTextButton.setEnabled(True)
        self.findTextButton.setIcon(QgsApplication.getThemeIcon("console/iconSearchEditorConsole.png"))
        self.findTextButton.setMenuRole(QAction.PreferencesRole)
        self.findTextButton.setIconVisibleInMenu(True)
        self.findTextButton.setToolTip(findText)
        self.findTextButton.setText(findText)

        # ----------------Toolbar Console-------------------------------------

        # Action Show Editor
        showEditor = QCoreApplication.translate("PythonConsole", "Show Editor")
        self.showEditorButton = QAction(self)
        self.showEditorButton.setEnabled(True)
        self.showEditorButton.setCheckable(True)
        self.showEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconShowEditorConsole.png"))
        self.showEditorButton.setMenuRole(QAction.PreferencesRole)
        self.showEditorButton.setIconVisibleInMenu(True)
        self.showEditorButton.setToolTip(showEditor)
        self.showEditorButton.setText(showEditor)
        # Action for Clear button
        clearBt = QCoreApplication.translate("PythonConsole", "Clear Console")
        self.clearButton = QAction(self)
        self.clearButton.setCheckable(False)
        self.clearButton.setEnabled(True)
        self.clearButton.setIcon(QgsApplication.getThemeIcon("console/iconClearConsole.png"))
        self.clearButton.setMenuRole(QAction.PreferencesRole)
        self.clearButton.setIconVisibleInMenu(True)
        self.clearButton.setToolTip(clearBt)
        self.clearButton.setText(clearBt)
        # Action for settings
        optionsBt = QCoreApplication.translate("PythonConsole", "Options...")
        self.optionsButton = QAction(self)
        self.optionsButton.setCheckable(False)
        self.optionsButton.setEnabled(True)
        self.optionsButton.setIcon(QgsApplication.getThemeIcon("console/iconSettingsConsole.png"))
        self.optionsButton.setMenuRole(QAction.PreferencesRole)
        self.optionsButton.setIconVisibleInMenu(True)
        self.optionsButton.setToolTip(optionsBt)
        self.optionsButton.setText(optionsBt)
        # Action menu for class
        actionClassBt = QCoreApplication.translate("PythonConsole", "Import Class")
        self.actionClass = QAction(self)
        self.actionClass.setCheckable(False)
        self.actionClass.setEnabled(True)
        self.actionClass.setIcon(QgsApplication.getThemeIcon("console/iconClassConsole.png"))
        self.actionClass.setMenuRole(QAction.PreferencesRole)
        self.actionClass.setIconVisibleInMenu(True)
        self.actionClass.setToolTip(actionClassBt)
        self.actionClass.setText(actionClassBt)
        # Action for Run script
        runBt = QCoreApplication.translate("PythonConsole", "Run Command")
        self.runButton = QAction(self)
        self.runButton.setCheckable(False)
        self.runButton.setEnabled(True)
        self.runButton.setIcon(QgsApplication.getThemeIcon("console/iconRunConsole.png"))
        self.runButton.setMenuRole(QAction.PreferencesRole)
        self.runButton.setIconVisibleInMenu(True)
        self.runButton.setToolTip(runBt)
        self.runButton.setText(runBt)
        # Help action
        helpBt = QCoreApplication.translate("PythonConsole", "Help...")
        self.helpButton = QAction(self)
        self.helpButton.setCheckable(False)
        self.helpButton.setEnabled(True)
        self.helpButton.setIcon(QgsApplication.getThemeIcon("console/iconHelpConsole.png"))
        self.helpButton.setMenuRole(QAction.PreferencesRole)
        self.helpButton.setIconVisibleInMenu(True)
        self.helpButton.setToolTip(helpBt)
        self.helpButton.setText(helpBt)

        self.toolBar = QToolBar()
        self.toolBar.setEnabled(True)
        self.toolBar.setFocusPolicy(Qt.NoFocus)
        self.toolBar.setContextMenuPolicy(Qt.DefaultContextMenu)
        self.toolBar.setLayoutDirection(Qt.LeftToRight)
        self.toolBar.setIconSize(QSize(16, 16))
        self.toolBar.setMovable(False)
        self.toolBar.setFloatable(False)
        self.toolBar.addAction(self.clearButton)
        self.toolBar.addAction(self.actionClass)
        self.toolBar.addAction(self.runButton)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.showEditorButton)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.optionsButton)
        self.toolBar.addAction(self.helpButton)

        self.toolBarEditor = QToolBar()
        self.toolBarEditor.setEnabled(False)
        self.toolBarEditor.setFocusPolicy(Qt.NoFocus)
        self.toolBarEditor.setContextMenuPolicy(Qt.DefaultContextMenu)
        self.toolBarEditor.setLayoutDirection(Qt.LeftToRight)
        self.toolBarEditor.setIconSize(QSize(16, 16))
        self.toolBarEditor.setMovable(False)
        self.toolBarEditor.setFloatable(False)
        self.toolBarEditor.addAction(self.openFileButton)
        self.toolBarEditor.addAction(self.openInEditorButton)
        self.toolBarEditor.addSeparator()
        self.toolBarEditor.addAction(self.saveFileButton)
        self.toolBarEditor.addAction(self.saveAsFileButton)
        self.toolBarEditor.addSeparator()
        self.toolBarEditor.addAction(self.runScriptEditorButton)
        self.toolBarEditor.addSeparator()
        self.toolBarEditor.addAction(self.findTextButton)
        self.toolBarEditor.addSeparator()
        self.toolBarEditor.addAction(self.cutEditorButton)
        self.toolBarEditor.addAction(self.copyEditorButton)
        self.toolBarEditor.addAction(self.pasteEditorButton)
        self.toolBarEditor.addSeparator()
        self.toolBarEditor.addAction(self.commentEditorButton)
        self.toolBarEditor.addAction(self.uncommentEditorButton)
        self.toolBarEditor.addSeparator()
        self.toolBarEditor.addAction(self.objectListButton)

        # Menu Import Class
        default_command = {
            (QCoreApplication.translate("PythonConsole", "Import Processing Class"),
             QgsApplication.getThemeIcon("console/iconProcessingConsole.png")):
            ["import processing"],
            (QCoreApplication.translate("PythonConsole", "Import PyQt.QtCore Class"),
             QgsApplication.getThemeIcon("console/iconQtCoreConsole.png")):
            ["from qgis.PyQt.QtCore import *"],
            (QCoreApplication.translate("PythonConsole", "Import PyQt.QtGui Class"),
             QgsApplication.getThemeIcon("console/iconQtGuiConsole.png")):
            ["from qgis.PyQt.QtGui import *", "from qgis.PyQt.QtWidgets import *"]
        }

        self.classMenu = QMenu()
        for (title, icon), commands in list(default_command.items()):
            action = self.classMenu.addAction(icon, title)
            action.triggered.connect(partial(self.shell.commandConsole, commands))

        cM = self.toolBar.widgetForAction(self.actionClass)
        cM.setMenu(self.classMenu)
        cM.setPopupMode(QToolButton.InstantPopup)

        self.widgetButton = QWidget()
        sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.widgetButton.sizePolicy().hasHeightForWidth())
        self.widgetButton.setSizePolicy(sizePolicy)

        self.widgetButtonEditor = QWidget(self.widgetEditor)
        sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.widgetButtonEditor.sizePolicy().hasHeightForWidth())
        self.widgetButtonEditor.setSizePolicy(sizePolicy)

        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.shellOut.sizePolicy().hasHeightForWidth())
        self.shellOut.setSizePolicy(sizePolicy)

        self.shellOut.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.shell.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)

        # ------------ Layout -------------------------------

        self.mainLayout = QGridLayout(self)
        self.mainLayout.setMargin(0)
        self.mainLayout.setSpacing(0)
        self.mainLayout.addWidget(self.widgetButton, 0, 0, 1, 1)
        self.mainLayout.addWidget(self.splitterEditor, 0, 1, 1, 1)

        self.shellOutWidget.layout().insertWidget(0, self.toolBar)

        self.layoutEditor = QGridLayout(self.widgetEditor)
        self.layoutEditor.setMargin(0)
        self.layoutEditor.setSpacing(0)
        self.layoutEditor.addWidget(self.toolBarEditor, 0, 1, 1, 1)
        self.layoutEditor.addWidget(self.widgetButtonEditor, 1, 0, 2, 1)
        self.layoutEditor.addWidget(self.tabEditorWidget, 1, 1, 1, 1)
        self.layoutEditor.addWidget(self.widgetFind, 2, 1, 1, 1)

        #  Layout for the find widget
        self.layoutFind = QGridLayout(self.widgetFind)
        self.layoutFind.setContentsMargins(0, 0, 0, 0)
        self.lineEditFind = QgsFilterLineEdit()
        placeHolderTxt = QCoreApplication.translate("PythonConsole", "Enter text to find...")

        self.lineEditFind.setPlaceholderText(placeHolderTxt)
        self.findNextButton = QToolButton()
        self.findNextButton.setEnabled(False)
        toolTipfindNext = QCoreApplication.translate("PythonConsole", "Find Next")
        self.findNextButton.setToolTip(toolTipfindNext)
        self.findNextButton.setIcon(QgsApplication.getThemeIcon("console/iconSearchNextEditorConsole.png"))
        self.findNextButton.setIconSize(QSize(24, 24))
        self.findNextButton.setAutoRaise(True)
        self.findPrevButton = QToolButton()
        self.findPrevButton.setEnabled(False)
        toolTipfindPrev = QCoreApplication.translate("PythonConsole", "Find Previous")
        self.findPrevButton.setToolTip(toolTipfindPrev)
        self.findPrevButton.setIcon(QgsApplication.getThemeIcon("console/iconSearchPrevEditorConsole.png"))
        self.findPrevButton.setIconSize(QSize(24, 24))
        self.findPrevButton.setAutoRaise(True)
        self.caseSensitive = QCheckBox()
        caseSensTr = QCoreApplication.translate("PythonConsole", "Case Sensitive")
        self.caseSensitive.setText(caseSensTr)
        self.wholeWord = QCheckBox()
        wholeWordTr = QCoreApplication.translate("PythonConsole", "Whole Word")
        self.wholeWord.setText(wholeWordTr)
        self.wrapAround = QCheckBox()
        self.wrapAround.setChecked(True)
        wrapAroundTr = QCoreApplication.translate("PythonConsole", "Wrap Around")
        self.wrapAround.setText(wrapAroundTr)
        self.layoutFind.addWidget(self.lineEditFind, 0, 1, 1, 1)
        self.layoutFind.addWidget(self.findPrevButton, 0, 2, 1, 1)
        self.layoutFind.addWidget(self.findNextButton, 0, 3, 1, 1)
        self.layoutFind.addWidget(self.caseSensitive, 0, 4, 1, 1)
        self.layoutFind.addWidget(self.wholeWord, 0, 5, 1, 1)
        self.layoutFind.addWidget(self.wrapAround, 0, 6, 1, 1)

        # ------------ Add first Tab in Editor -------------------------------

        # self.tabEditorWidget.newTabEditor(tabName='first', filename=None)

        # ------------ Signal -------------------------------

        self.findTextButton.triggered.connect(self._toggleFind)
        self.objectListButton.toggled.connect(self.toggleObjectListWidget)
        self.commentEditorButton.triggered.connect(self.commentCode)
        self.uncommentEditorButton.triggered.connect(self.uncommentCode)
        self.runScriptEditorButton.triggered.connect(self.runScriptEditor)
        self.cutEditorButton.triggered.connect(self.cutEditor)
        self.copyEditorButton.triggered.connect(self.copyEditor)
        self.pasteEditorButton.triggered.connect(self.pasteEditor)
        self.showEditorButton.toggled.connect(self.toggleEditor)
        self.clearButton.triggered.connect(self.shellOut.clearConsole)
        self.optionsButton.triggered.connect(self.openSettings)
        self.runButton.triggered.connect(self.shell.entered)
        self.openFileButton.triggered.connect(self.openScriptFile)
        self.openInEditorButton.triggered.connect(self.openScriptFileExtEditor)
        self.saveFileButton.triggered.connect(self.saveScriptFile)
        self.saveAsFileButton.triggered.connect(self.saveAsScriptFile)
        self.helpButton.triggered.connect(self.openHelp)
        self.listClassMethod.itemClicked.connect(self.onClickGoToLine)
        self.lineEditFind.returnPressed.connect(self._findNext)
        self.findNextButton.clicked.connect(self._findNext)
        self.findPrevButton.clicked.connect(self._findPrev)
        self.lineEditFind.textChanged.connect(self._textFindChanged)

        self.findScut = QShortcut(QKeySequence.Find, self.widgetEditor)
        self.findScut.setContext(Qt.WidgetWithChildrenShortcut)
        self.findScut.activated.connect(self._openFind)

        self.findNextScut = QShortcut(QKeySequence.FindNext, self.widgetEditor)
        self.findNextScut.setContext(Qt.WidgetWithChildrenShortcut)
        self.findNextScut.activated.connect(self._findNext)

        self.findPreviousScut = QShortcut(QKeySequence.FindPrevious, self.widgetEditor)
        self.findPreviousScut.setContext(Qt.WidgetWithChildrenShortcut)
        self.findPreviousScut.activated.connect(self._findPrev)

        # Escape on editor hides the find bar
        self.findScut = QShortcut(Qt.Key_Escape, self.widgetEditor)
        self.findScut.setContext(Qt.WidgetWithChildrenShortcut)
        self.findScut.activated.connect(self._closeFind)

    def _toggleFind(self):
        self.tabEditorWidget.currentWidget().newEditor.toggleFindWidget()

    def _openFind(self):
        self.tabEditorWidget.currentWidget().newEditor.openFindWidget()

    def _closeFind(self):
        self.tabEditorWidget.currentWidget().newEditor.closeFindWidget()

    def _findNext(self):
        self.tabEditorWidget.currentWidget().newEditor.findText(True)

    def _findPrev(self):
        self.tabEditorWidget.currentWidget().newEditor.findText(False)

    def _textFindChanged(self):
        if self.lineEditFind.text():
            self.findNextButton.setEnabled(True)
            self.findPrevButton.setEnabled(True)
            self.tabEditorWidget.currentWidget().newEditor.findText(True, showMessage=False, findFirst=True)
        else:
            self.lineEditFind.setStyleSheet('')
            self.findNextButton.setEnabled(False)
            self.findPrevButton.setEnabled(False)

    def onClickGoToLine(self, item, column):
        tabEditor = self.tabEditorWidget.currentWidget().newEditor
        if item.text(1) == 'syntaxError':
            check = tabEditor.syntaxCheck(fromContextMenu=False)
            if check and not tabEditor.isReadOnly():
                self.tabEditorWidget.currentWidget().save()
            return
        linenr = int(item.text(1))
        itemName = str(item.text(0))
        charPos = itemName.find(' ')
        if charPos != -1:
            objName = itemName[0:charPos]
        else:
            objName = itemName
        tabEditor.goToLine(objName, linenr)

    def toggleEditor(self, checked):
        self.splitterObj.show() if checked else self.splitterObj.hide()
        if not self.tabEditorWidget:
            self.tabEditorWidget.enableToolBarEditor(checked)
            self.tabEditorWidget.restoreTabsOrAddNew()

    def toggleObjectListWidget(self, checked):
        self.listClassMethod.show() if checked else self.listClassMethod.hide()

    def pasteEditor(self):
        self.tabEditorWidget.currentWidget().newEditor.paste()

    def cutEditor(self):
        self.tabEditorWidget.currentWidget().newEditor.cut()

    def copyEditor(self):
        self.tabEditorWidget.currentWidget().newEditor.copy()

    def runScriptEditor(self):
        self.tabEditorWidget.currentWidget().newEditor.runScriptCode()

    def commentCode(self):
        self.tabEditorWidget.currentWidget().newEditor.commentEditorCode(True)

    def uncommentCode(self):
        self.tabEditorWidget.currentWidget().newEditor.commentEditorCode(False)

    def openScriptFileExtEditor(self):
        tabWidget = self.tabEditorWidget.currentWidget()
        path = tabWidget.path
        import subprocess
        try:
            subprocess.Popen([os.environ['EDITOR'], path])
        except KeyError:
            QDesktopServices.openUrl(QUrl.fromLocalFile(path))

    def openScriptFile(self):
        lastDirPath = self.settings.value("pythonConsole/lastDirPath", QDir.homePath())
        openFileTr = QCoreApplication.translate("PythonConsole", "Open File")
        fileList, selected_filter = QFileDialog.getOpenFileNames(
            self, openFileTr, lastDirPath, "Script file (*.py)")
        if fileList:
            for pyFile in fileList:
                for i in range(self.tabEditorWidget.count()):
                    tabWidget = self.tabEditorWidget.widget(i)
                    if tabWidget.path == pyFile:
                        self.tabEditorWidget.setCurrentWidget(tabWidget)
                        break
                else:
                    tabName = QFileInfo(pyFile).fileName()
                    self.tabEditorWidget.newTabEditor(tabName, pyFile)

                    lastDirPath = QFileInfo(pyFile).path()
                    self.settings.setValue("pythonConsole/lastDirPath", pyFile)
                    self.updateTabListScript(pyFile, action='append')

    def saveScriptFile(self):
        tabWidget = self.tabEditorWidget.currentWidget()
        try:
            tabWidget.save()
        except (IOError, OSError) as error:
            msgText = QCoreApplication.translate('PythonConsole',
                                                 'The file <b>{0}</b> could not be saved. Error: {1}').format(tabWidget.path,
                                                                                                              error.strerror)
            self.callWidgetMessageBarEditor(msgText, 2, False)

    def saveAsScriptFile(self, index=None):
        tabWidget = self.tabEditorWidget.currentWidget()
        if not index:
            index = self.tabEditorWidget.currentIndex()
        if not tabWidget.path:
            fileName = self.tabEditorWidget.tabText(index) + '.py'
            folder = self.settings.value("pythonConsole/lastDirPath", QDir.home())
            pathFileName = os.path.join(folder, fileName)
            fileNone = True
        else:
            pathFileName = tabWidget.path
            fileNone = False
        saveAsFileTr = QCoreApplication.translate("PythonConsole", "Save File As")
        filename, filter = QFileDialog.getSaveFileName(self,
                                                       saveAsFileTr,
                                                       pathFileName, "Script file (*.py)")
        if filename:
            try:
                tabWidget.save(filename)
            except (IOError, OSError) as error:
                msgText = QCoreApplication.translate('PythonConsole',
                                                     'The file <b>{0}</b> could not be saved. Error: {1}').format(tabWidget.path,
                                                                                                                  error.strerror)
                self.callWidgetMessageBarEditor(msgText, 2, False)
                if fileNone:
                    tabWidget.path = None
                else:
                    tabWidget.path = pathFileName
                return

            if not fileNone:
                self.updateTabListScript(pathFileName, action='remove')

    def openHelp(self):
        QgsContextHelp.run("PythonConsole")

    def openSettings(self):
        if optionsDialog(self).exec_():
            self.shell.refreshSettingsShell()
            self.shellOut.refreshSettingsOutput()
            self.tabEditorWidget.refreshSettingsEditor()

    def callWidgetMessageBar(self, text):
        self.shellOut.widgetMessageBar(iface, text)

    def callWidgetMessageBarEditor(self, text, level, timed):
        self.tabEditorWidget.widgetMessageBar(iface, text, level, timed)

    def updateTabListScript(self, script, action=None):
        if action == 'remove':
            self.tabListScript.remove(script)
        elif action == 'append':
            if not self.tabListScript:
                self.tabListScript = []
            if script not in self.tabListScript:
                self.tabListScript.append(script)
        else:
            self.tabListScript = []
        self.settings.setValue("pythonConsole/tabScripts",
                               self.tabListScript)

    def saveSettingsConsole(self):
        self.settings.setValue("pythonConsole/splitterConsole", self.splitter.saveState())
        self.settings.setValue("pythonConsole/splitterObj", self.splitterObj.saveState())
        self.settings.setValue("pythonConsole/splitterEditor", self.splitterEditor.saveState())

        self.shell.writeHistoryFile(True)

    def restoreSettingsConsole(self):
        storedTabScripts = self.settings.value("pythonConsole/tabScripts", [])
        self.tabListScript = storedTabScripts
        self.splitter.restoreState(self.settings.value("pythonConsole/splitterConsole", QByteArray()))
        self.splitterEditor.restoreState(self.settings.value("pythonConsole/splitterEditor", QByteArray()))
        self.splitterObj.restoreState(self.settings.value("pythonConsole/splitterObj", QByteArray()))
コード例 #17
0
class CoordinateCaptureDockWidget(QDockWidget):

    closingPlugin = pyqtSignal()

    def __init__(self, parent=None):
        """Constructor."""
        super(CoordinateCaptureDockWidget, self).__init__(parent)

        self.setWindowTitle(self.tr("Coordinate Capture"))
        self.setGeometry(0, 0, 300, 228)
        self.dockWidgetContents = QWidget(self)
        self.setWidget(self.dockWidgetContents)
        self.gridLayout = QGridLayout()
        self.dockWidgetContents.setLayout(self.gridLayout)

        self.dockWidgetContents.layout().setColumnMinimumWidth(0, 36)

        self.userCrsToolButton = QToolButton(self.dockWidgetContents)
        self.userCrsToolButton.setIcon(
            QIcon(":/plugins/coordinate_capture/mIconProjectionEnabled.svg"))
        self.userCrsToolButton.setToolTip(
            self.tr("Click to select the CRS to use for coordinate display"))

        self.userCrsLabel = QLabel(self.dockWidgetContents)
        self.userCrsLabel.setPixmap(
            QPixmap(":/plugins/coordinate_capture/transformed.svg"))
        self.userCrsLabel.setGeometry(self.userCrsToolButton.geometry())

        self.userCrsEdit = QLineEdit(self.dockWidgetContents)
        self.userCrsEdit.setReadOnly(True)
        self.userCrsEdit.setToolTip(
            self.tr("Coordinate in your selected CRS (lat,lon or east,north)"))
        self.copyUserCrsCoordinatesAction = self.userCrsEdit.addAction(
            QIcon(":/plugins/coordinate_capture/mActionEditCopy.svg"),
            QLineEdit.TrailingPosition)
        self.copyUserCrsCoordinatesAction.triggered.connect(
            self.copyUserCrsCoordinates)

        self.canvasCrsEdit = QLineEdit(self.dockWidgetContents)
        self.canvasCrsEdit.setReadOnly(True)
        self.canvasCrsEdit.setToolTip(
            self.
            tr("Coordinate in map canvas coordinate reference system (lat,lon or east,north)"
               ))
        self.copyCanvasCrsCoordinatesAction = self.canvasCrsEdit.addAction(
            QIcon(":/plugins/coordinate_capture/mActionEditCopy.svg"),
            QLineEdit.TrailingPosition)
        self.copyCanvasCrsCoordinatesAction.triggered.connect(
            self.copyCanvasCrsCoordinates)

        self.trackMouseButton = QToolButton(self.dockWidgetContents)
        self.trackMouseButton.setIcon(
            QIcon(":/plugins/coordinate_capture/tracking.svg"))
        self.trackMouseButton.setCheckable(True)
        self.trackMouseButton.setToolTip(
            self.tr(
                "Click to enable mouse tracking. Click the canvas to stop"))
        self.trackMouseButton.setChecked(False)

        # Create the action for tool
        self.captureButton = QPushButton(self.dockWidgetContents)
        self.captureButton.setText(self.tr("Start Capture"))
        self.captureButton.setToolTip(
            self.tr("Click to enable coordinate capture"))
        self.captureButton.setIcon(
            QIcon(":/plugins/coordinate_capture/coordinate_capture.png"))
        self.captureButton.setWhatsThis(
            self.
            tr("Click on the map to view coordinates and capture to clipboard."
               ))

        # // Set the icons
        # setCurrentTheme(QString());

        self.dockWidgetContents.layout().addWidget(self.userCrsToolButton, 0,
                                                   0)
        self.dockWidgetContents.layout().addWidget(self.userCrsEdit, 0, 1)
        self.dockWidgetContents.layout().addWidget(self.userCrsLabel, 1, 0)
        self.dockWidgetContents.layout().addWidget(self.canvasCrsEdit, 1, 1)
        self.dockWidgetContents.layout().addWidget(self.trackMouseButton, 2, 0)
        self.dockWidgetContents.layout().addWidget(self.captureButton, 2, 1)

    def copyUserCrsCoordinates(self):
        self.userCrsEdit.selectAll()
        self.userCrsEdit.copy()

    def copyCanvasCrsCoordinates(self):
        self.canvasCrsEdit.selectAll()
        self.canvasCrsEdit.copy()

    def closeEvent(self, event):
        self.closingPlugin.emit()
        event.accept()
コード例 #18
0
ファイル: foreign_key_mapper.py プロジェクト: gltn/stdm
class ForeignKeyMapper(QWidget):
    """
    Widget for selecting database records through an entity browser or
    using an ExpressionBuilder for filtering records.
    """
    # Custom signals
    beforeEntityAdded = pyqtSignal("PyQt_PyObject")
    afterEntityAdded = pyqtSignal("PyQt_PyObject", int)
    entityRemoved = pyqtSignal("PyQt_PyObject")
    deletedRows = pyqtSignal(list)

    def __init__(self,
                 entity,
                 parent=None,
                 notification_bar=None,
                 enable_list=True,
                 can_filter=False,
                 plugin=None):

        QWidget.__init__(self, parent)
        self.current_profile = current_profile()

        self._tbFKEntity = QTableView(self)
        self._tbFKEntity.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self._tbFKEntity.setAlternatingRowColors(True)
        self._tbFKEntity.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.plugin = plugin
        self._add_entity_btn = QToolButton(self)
        self._add_entity_btn.setToolTip(
            QApplication.translate("ForeignKeyMapper", "Add"))
        self._add_entity_btn.setIcon(GuiUtils.get_icon("add.png"))
        self._add_entity_btn.clicked.connect(self.onAddEntity)

        self._edit_entity_btn = QToolButton(self)
        self._edit_entity_btn.setVisible(False)
        self._edit_entity_btn.setToolTip(
            QApplication.translate("ForeignKeyMapper", "Edit"))
        self._edit_entity_btn.setIcon(GuiUtils.get_icon("edit.png"))

        self._filter_entity_btn = QToolButton(self)
        self._filter_entity_btn.setVisible(False)
        self._filter_entity_btn.setToolTip(
            QApplication.translate("ForeignKeyMapper", "Select by expression"))
        self._filter_entity_btn.setIcon(GuiUtils.get_icon("filter.png"))
        self._filter_entity_btn.clicked.connect(self.onFilterEntity)

        self._delete_entity_btn = QToolButton(self)
        self._delete_entity_btn.setToolTip(
            QApplication.translate("ForeignKeyMapper", "Remove"))
        self._delete_entity_btn.setIcon(GuiUtils.get_icon("remove.png"))
        self._delete_entity_btn.clicked.connect(self.onRemoveEntity)

        layout = QVBoxLayout(self)
        layout.setSpacing(4)
        layout.setMargin(5)

        self.grid_layout = QGridLayout()
        self.grid_layout.setHorizontalSpacing(5)
        self.grid_layout.addWidget(self._add_entity_btn, 0, 0, 1, 1)
        self.grid_layout.addWidget(self._filter_entity_btn, 0, 1, 1, 1)
        self.grid_layout.addWidget(self._edit_entity_btn, 0, 2, 1, 1)
        self.grid_layout.addWidget(self._delete_entity_btn, 0, 3, 1, 1)
        self.grid_layout.setColumnStretch(4, 5)

        layout.addLayout(self.grid_layout)
        layout.addWidget(self._tbFKEntity)
        self.social_tenure = self.current_profile.social_tenure

        self._tableModel = None
        self._notifBar = notification_bar
        self._headers = []
        self._entity_attrs = []
        self._cell_formatters = {}
        self._searchable_columns = OrderedDict()
        self._supportsLists = enable_list
        self._deleteOnRemove = False
        self._uniqueValueColIndices = OrderedDict()
        self.global_id = None
        self._deferred_objects = {}
        self._use_expression_builder = can_filter

        if self._use_expression_builder:
            self._filter_entity_btn.setVisible(True)
            self._edit_entity_btn.setVisible(False)
        self.set_entity(entity)

    def set_entity(self, entity):
        """
        Sets new entity and updates the ForeignKeyMapper with a new
        :param entity: The entity of the ForeignKeyMapper
        :type entity:Object
        """
        from stdm.ui.entity_browser import EntityBrowser

        self._entity = entity

        self._dbmodel = entity_model(entity)
        self._init_fk_columns()
        self._entitySelector = EntityBrowser(self._entity,
                                             parent=self,
                                             state=SELECT,
                                             plugin=self.plugin)

        # Connect signals
        self._entitySelector.recordSelected.connect(
            self._onRecordSelectedEntityBrowser)

    def _init_fk_columns(self):
        """
        Asserts if the entity columns actually do exist in the database. The
        method also initializes the table headers, entity column and cell
        formatters.
        """
        self._headers[:] = []
        self._entity_attrs[:] = []
        if self._dbmodel is None:
            msg = QApplication.translate(
                'ForeignKeyMapper', 'The data model for '
                'the entity could '
                'not be loaded, '
                'please contact '
                'your database '
                'administrator.')
            QMessageBox.critical(
                self, QApplication.translate('EntityBrowser',
                                             'Entity Browser'), msg)

            return

        table_name = self._entity.name
        columns = table_column_names(table_name)
        missing_columns = []

        header_idx = 0

        # Iterate entity column and assert if they exist
        for c in self._entity.columns.values():
            # Do not include virtual columns in list of missing columns
            if not c.name in columns and not isinstance(c, VirtualColumn):
                missing_columns.append(c.name)

            else:
                header = c.header()
                self._headers.append(header)
                '''
                If it is a virtual column then use column name as the header
                but fully qualified column name (created by SQLAlchemy
                relationship) as the entity attribute name.
                '''
                col_name = c.name

                if isinstance(c, MultipleSelectColumn):
                    col_name = c.model_attribute_name

                self._entity_attrs.append(col_name)

                # Get widget factory so that we can use the value formatter
                w_factory = ColumnWidgetRegistry.factory(c.TYPE_INFO)
                if not w_factory is None:
                    try:
                        formatter = w_factory(c)
                        self._cell_formatters[col_name] = formatter
                    except WidgetException as we:
                        msg = QApplication.translate(
                            'ForeignKeyMapper', 'Error in creating column:')
                        msg = '{0} {1}:{2}\n{3}'.format(
                            msg, self._entity.name, c.name, str(we))
                        QMessageBox.critical(
                            self,
                            QApplication.translate('ForeignKeyMapper',
                                                   'Widget Creation Error'),
                            msg)

                # Set searchable columns
                if c.searchable:
                    self._searchable_columns[header] = {
                        'name': c.name,
                        'header_index': header_idx
                    }

                header_idx += 1

        if len(missing_columns) > 0:
            msg = QApplication.translate(
                'ForeignKeyMapper',
                'The following columns have been defined in the '
                'configuration but are missing in corresponding '
                'database table, please re-run the configuration wizard '
                'to create them.\n{0}'.format('\n'.join(missing_columns)))

            QMessageBox.warning(
                self,
                QApplication.translate('ForeignKeyMapper', 'Entity Browser'),
                msg)

        self._tableModel = BaseSTDMTableModel([], self._headers, self)
        self._tbFKEntity.setModel(self._tableModel)
        # First (id) column will always be hidden
        self._tbFKEntity.hideColumn(0)

        self._tbFKEntity.horizontalHeader().setSectionResizeMode(
            QHeaderView.Interactive)
        self._tbFKEntity.horizontalHeader().setStretchLastSection(True)

        self._tbFKEntity.verticalHeader().setVisible(True)

    def databaseModel(self):
        '''
        Returns the database model that represents the foreign key entity.
        '''
        return self._dbmodel

    def setDatabaseModel(self, model):
        '''
        Set the database model that represents the foreign key entity.
        Model has to be a callable.
        '''
        self._dbmodel = model

    def cellFormatters(self):
        """
        Returns a dictionary of cell formatters used by the foreign key mapper.
        """
        return self._cell_formatters

    def cell_formatter(self, column):
        """
        :param column: Column name:
        :type column: str
        :return: Returns the corresponding formatter object based on the
        column name. None will be returned if there is no corresponding
        object.
        :rtype: object
        """
        return self._cell_formatters.get(column, None)

    def entitySelector(self):
        '''
        Returns the dialog for selecting the entity objects.
        '''
        return self._entitySelector

    def supportList(self):
        '''
        Returns whether the mapper supports only one item or multiple entities.
        Default is 'True'.
        '''
        return self._supportsLists

    def setSupportsList(self, supportsList):
        '''
        Sets whether the mapper supports only one item or multiple entities i.e.
        one-to-one (False) and one-to-many mapping (True).
        '''
        self._supportsLists = supportsList

    def setNotificationBar(self, notificationBar):
        '''
        Set the notification bar for displaying user messages.
        '''
        self._notifBar = notificationBar

    def viewModel(self):
        '''
        Return the view model used by the table view.
        '''
        return self._tableModel

    def set_expression_builder(self, state):
        """
        Set the mapper to use QGIS expression builder as the entity selector.
        """
        self._use_expression_builder = state

    def expression_builder_enabled(self):
        """
        Returns whether the mapper has been configured to use the expression builder
        """
        return self._use_expression_builder

    def deleteOnRemove(self):
        '''
        Returns the state whether a record should be deleted from the database when it
        is removed from the list.
        '''
        return self._deleteOnRemove

    def setDeleteonRemove(self, delete):
        '''
        Set whether whether a record should be deleted from the database when it
        is removed from the list.
        '''
        self._deleteOnRemove = delete

    def addUniqueColumnName(self, colName, replace=True):
        '''
        Set the name of the column whose values are to be unique.
        If 'replace' is True then the existing row will be replaced
        with one with the new value; else, the new row will not be added to the list.
        '''
        headers = list(self._dbmodel.displayMapping().values())
        colIndex = getIndex(headers, colName)

        if colIndex != -1:
            self.addUniqueColumnIndex(colIndex, replace)

    def addUniqueColumnIndex(self, colIndex, replace=True):
        '''
        Set the index of the column whose values are to be unique. The column indices are
        zero-based.
        If 'replace' is True then the existing row will be replaced with the
        new value; else, the new row will not be added to the list.
        For multiple replace rules defined, then the first one added to the collection is the
        one that will be applied.
        '''
        self._uniqueValueColIndices[colIndex] = replace

    def onFilterEntity(self):
        """
        Slot raised to load the expression builder dialog.
        """
        vl, msg = self.vector_layer()

        if vl is None:
            msg = msg + "\n" + QApplication.translate(
                "ForeignKeyMapper",
                "The expression builder cannot be used at this moment.")
            QMessageBox.critical(
                self,
                QApplication.translate("ForeignKeyMapper",
                                       "Expression Builder"), msg)

            return

        context = self._entity.short_name

        filter_dlg = ForeignKeyMapperExpressionDialog(vl,
                                                      self,
                                                      context=context)
        filter_dlg.setWindowTitle(
            QApplication.translate("ForeignKeyMapper", "Filter By Expression"))
        filter_dlg.recordSelected[int].connect(
            self._onRecordSelectedEntityBrowser)

        res = filter_dlg.exec_()

    def _removeRow(self, rowNumber):
        '''
        Remove the row at the given index.
        '''
        self._tableModel.removeRows(rowNumber, 1)

    def onRemoveEntity(self):
        '''
        Slot raised on clicking to remove the selected entity.
        '''
        selectedRowIndices = self._tbFKEntity.selectionModel().selectedRows(0)

        deleted_rows = []
        if len(selectedRowIndices) == 0:
            msg = QApplication.translate(
                "ForeignKeyMapper", "Please select the record to be removed.")
            self._notifBar.clear()
            self._notifBar.insertWarningNotification(msg)
            return

        for selectedRowIndex in selectedRowIndices:
            # Delete record from database if flag has been set to True
            recId = selectedRowIndex.data()

            dbHandler = self._dbmodel()
            delRec = dbHandler.queryObject().filter(
                self._dbmodel.id == recId).first()

            if not delRec is None:
                self.entityRemoved.emit(delRec)

                if self._deleteOnRemove:
                    delRec.delete()

            self._removeRow(selectedRowIndex.row())

            deleted_rows.append(selectedRowIndex.row())

        self.deletedRows.emit(deleted_rows)

    def _recordIds(self):
        '''
        Returns the primary keys of the records in the table.
        '''
        recordIds = []

        if self._tableModel:
            rowCount = self._tableModel.rowCount()

            for r in range(rowCount):
                # Get ID value
                modelIndex = self._tableModel.index(r, 0)
                modelId = modelIndex.data()
                recordIds.append(modelId)

        return recordIds

    def entities(self):
        '''
        Returns the model instance(s) depending on the configuration specified by the user.
        '''
        recIds = self._recordIds()

        modelInstances = self._modelInstanceFromIds(recIds)

        if len(modelInstances) == 0:
            if self._supportsLists:
                return []

            else:
                return None

        else:
            if self._supportsLists:
                return modelInstances

            else:
                return modelInstances[0]

    def setEntities(self, entities):
        '''
        Insert entities into the table.
        '''
        if isinstance(entities, list):
            for entity in entities:
                self._insertModelToView(entity)

        else:
            self._insertModelToView(entities)

    def searchModel(self, columnIndex, columnValue):
        '''
        Searches for 'columnValue' in the column whose index is specified by 'columnIndex' in all
        rows contained in the model.
        '''
        if isinstance(columnValue, QVariant):
            columnValue = str(columnValue.toString())

        if not isinstance(columnValue, str):
            columnValue = str(columnValue)

        columnValue = columnValue.strip()

        proxy = QSortFilterProxyModel(self)
        proxy.setSourceModel(self._tableModel)
        proxy.setFilterKeyColumn(columnIndex)
        proxy.setFilterFixedString(columnValue)
        # Will return model index containing the primary key.
        matchingIndex = proxy.mapToSource(proxy.index(0, 0))

        return matchingIndex

    def _modelInstanceFromIds(self, ids):
        '''
        Returns the model instance based the value of its primary key.
        '''
        dbHandler = self._dbmodel()

        modelInstances = []

        for modelId in ids:
            modelObj = dbHandler.queryObject().filter(
                self._dbmodel.id == modelId).first()
            if not modelObj is None:
                modelInstances.append(modelObj)

        return modelInstances

    def _onRecordSelectedEntityBrowser(self, rec, row_number=-1):
        '''
        Slot raised when the user has clicked the select button
        in the 'EntityBrowser' dialog
        to add the selected record to the table's list.
        Add the record to the foreign key table using the mappings.
        '''
        # Check if the record exists using the primary key so as to ensure
        # only one instance is added to the table
        if isinstance(rec, int):
            recIndex = getIndex(self._recordIds(), rec)

            if recIndex != -1:
                return

            dbHandler = self._dbmodel()
            modelObj = dbHandler.queryObject().filter(
                self._dbmodel.id == rec).first()

        elif isinstance(rec, object):
            modelObj = rec

        else:
            return

        if modelObj is not None:
            # Raise before entity added signal
            self.beforeEntityAdded.emit(modelObj)

            # Validate for unique value configurations
            '''
            if not self._validate_unique_columns(modelObj, row_number):
                return
            '''

            if not self._supportsLists and self._tableModel.rowCount() > 0:
                self._removeRow(0)

            insert_position = self._insertModelToView(modelObj, row_number)

            if isinstance(rec, object):
                self._deferred_objects[insert_position] = modelObj

    def _validate_unique_columns(self, model, exclude_row=-1):
        """
        Loop through the attributes of the model to assert
        for existing row values that should be unique based on
        the configuration of unique columns.
        """
        for colIndex, replace in list(self._uniqueValueColIndices.items()):
            attrName = list(self._dbmodel.displayMapping().keys())[colIndex]
            attrValue = getattr(model, attrName)

            # Check to see if there are cell formatters so
            # that the correct value is searched for in the model
            if attrName in self._cell_formatters:
                attrValue = self._cell_formatters[attrName](attrValue)

            matchingIndex = self.searchModel(colIndex, attrValue)

            if matchingIndex.isValid() and matchingIndex.row() != exclude_row:
                if replace:
                    existingId = matchingIndex.data()

                    # Delete old record from db
                    entityModels = self._modelInstanceFromIds([existingId])

                    if len(entityModels) > 0:
                        entityModels[0].delete()

                    self._removeRow(matchingIndex.row())

                    return True

                else:
                    # Break. Do not add item to the list.
                    return False

        return True

    def _insertModelToView(self, model_obj, row_number=-1):
        """
        Insert the given database model instance into the view
        at the given row number position.
        """
        if row_number == -1:
            row_number = self._tableModel.rowCount()
            self._tableModel.insertRows(row_number, 1)

        # In some instances, we will need to get the model object with
        # backrefs included else exceptions will be raised on missing
        # attributes
        q_objs = self._modelInstanceFromIds([model_obj.id])
        if len(q_objs) == 0:
            return

        model_obj = q_objs[0]

        for i, attr in enumerate(self._entity_attrs):
            prop_idx = self._tableModel.index(row_number, i)
            attr_val = getattr(model_obj, attr)
            '''
            Check if there are display formatters and apply if one exists
            for the given attribute.
            '''
            if attr in self._cell_formatters:
                formatter = self._cell_formatters[attr]
                attr_val = formatter.format_column_value(attr_val)

            self._tableModel.setData(prop_idx, attr_val)

        # Raise signal once entity has been inserted
        self.afterEntityAdded.emit(model_obj, row_number)

        self._tbFKEntity.resizeColumnsToContents()

        return row_number

    def insert_model_to_table(self, model_obj, row_number=-1):
        """
         Insert the given database model instance into the view
         at the given row number position.
         """
        if row_number == -1:
            row_number = self._tableModel.rowCount()
            self._tableModel.insertRows(row_number, 1)
        # In some instances, we will need to get the model object with
        # backrefs included else exceptions will be raised on missing
        # attributes
        q_objs = self._modelInstanceFromIds([model_obj.id])

        if len(q_objs) == 0:
            return

        model_obj = q_objs[0]

        for i, attr in enumerate(self._entity_attrs):
            prop_idx = self._tableModel.index(row_number, i)
            attr_val = getattr(model_obj, attr)

            # Check if there are display formatters and apply if one exists
            # for the given attribute.

            if attr in self._cell_formatters:
                formatter = self._cell_formatters[attr]
                attr_val = formatter.format_column_value(attr_val)

            self._tableModel.setData(prop_idx, attr_val)

        #self._tbFKEntity.resizeColumnsToContents()
        self._tbFKEntity.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)

        return row_number

    def remove_rows(self):
        """
        Removes rows from the fk browser.
        """
        row_count = self._tbFKEntity.model().rowCount()

        self._tbFKEntity.model().removeRows(0, row_count)

    def vector_layer(self):
        """
        Returns a QgsVectorLayer based on the configuration information
        specified in the mapper including the system-wide data connection
        properties.
        """
        from stdm.data.pg_utils import vector_layer

        if self._dbmodel is None:
            msg = QApplication.translate(
                "ForeignKeyMapper",
                "Primary database model object not defined.")
            return None, msg

        filter_layer = vector_layer(self._entity.name)
        if filter_layer is None:
            msg = QApplication.translate(
                "ForeignKeyMapper",
                "Vector layer could not be constructed from the database table."
            )

            return None, msg

        if not filter_layer.isValid():
            trans_msg = QApplication.translate(
                "ForeignKeyMapper",
                "The vector layer for '{0}' table is invalid.")
            msg = trans_msg.format(self._entity.name)

            return None, msg

        return filter_layer, ""

    def onAddEntity(self):
        """
        Slot raised on selecting to add related entities that will be mapped to the primary
        database model instance.
        """
        self._entitySelector.buttonBox.button(
            QDialogButtonBox.Cancel).setVisible(False)

        # Clear any previous selections in the entity browser
        self._entitySelector.clear_selection()

        # Clear any previous notifications
        self._entitySelector.clear_notifications()

        self._entitySelector.exec_()
コード例 #19
0
def fill_tree_with_element(widget,
                           treeItem,
                           elt,
                           ns_imap={},
                           custom_viewers={},
                           ns_map={}):
    """
    :param widget: the QTreeWidget
    :param treeItem: a QTreeWidgetItem to fill
    :param elt: the XML node
    :param ns_imap: an "inverse" namespace map { uri : prefix }
    :param custom_viewers: a dict giving a custom viewer plugin (QWidget) for some elements {tag : constructor}
    :param ns_map: a namespace map { prefix : uri }
    """
    is_root = treeItem == widget.invisibleRootItem()
    # tag
    ns, tag = split_tag(elt.tag)
    if ns and ns_imap.get(ns):
        treeItem.setText(0, ns_imap[ns] + ":" + tag)
    else:
        treeItem.setText(0, tag)
    f = treeItem.font(0)
    f.setBold(True)
    treeItem.setFont(0, f)

    # custom viewer
    if elt.tag in custom_viewers:
        custom_viewer_widget, filter = custom_viewers[elt.tag]
        if filter is None or elt.find(filter, ns_map) is not None:
            btn = QToolButton(widget)
            btn.setIcon(custom_viewer_widget.icon())
            btn.setIconSize(QSize(32, 32))

            def show_viewer(btn):
                widget.w = custom_viewer_widget.init_from_xml(elt)
                widget.w.setWindowModality(Qt.WindowModal)
                widget.w.show()

            btn.clicked.connect(show_viewer)

            w = QWidget(widget)
            l = QHBoxLayout()
            l.addWidget(btn)
            l.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding))
            w.setLayout(l)
            if is_root:
                # insert an item
                child = QTreeWidgetItem()
                treeItem.addChild(child)
                widget.setItemWidget(child, 0, w)
            else:
                widget.setItemWidget(treeItem, 1, w)

    # attributes
    for k, v in elt.attrib.items():
        child = QTreeWidgetItem()
        treeItem.addChild(child)
        if "}" in k:
            i = k.index("}")
            ns = k[1:i]
            # get ns prefix from ns uri
            p = ns_imap.get(ns)
            if p is not None:
                n = p + ":" + k[i + 1:]
            else:
                n = k[i + 1:]
        else:
            n = no_prefix(k)
        child.setText(0, "@" + n)
        if n == "xlink:href" and v.startswith("http"):
            html = QLabel(widget)
            html.setOpenExternalLinks(True)
            html.setTextFormat(Qt.RichText)
            html.setText('<a href="{}">{}</a>'.format(v, v))
            child.setData(1, Qt.UserRole, v)
            widget.setItemWidget(child, 1, html)
        else:
            child.setText(1, v)
    # text
    if elt.text:
        treeItem.setText(1, elt.text)

    # children
    for xmlChild in elt:
        child = QTreeWidgetItem()
        treeItem.addChild(child)
        fill_tree_with_element(widget, child, xmlChild, ns_imap,
                               custom_viewers, ns_map)
コード例 #20
0
    def initWidgets(self):
        # If there are advanced parameters — show corresponding groupbox
        for param in self.alg.parameters:
            if param.isAdvanced:
                self.grpAdvanced.show()
                break
        # Create widgets and put them in layouts
        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)')
            try:
                if param.optional:
                    desc += self.tr(' [optional]')
            except:
                pass

            widget = self.getWidgetFromParameter(param)
            self.valueItems[param.name] = widget

            if isinstance(param, ParameterVector) and \
                    not self.alg.allowOnlyOpenedLayers:
                layout = QHBoxLayout()
                layout.setSpacing(2)
                layout.setMargin(0)
                layout.addWidget(widget)
                button = QToolButton()
                icon = QIcon(os.path.join(pluginPath, 'images', 'iterate.png'))
                button.setIcon(icon)
                button.setToolTip(self.tr('Iterate over this layer'))
                button.setCheckable(True)
                layout.addWidget(button)
                self.iterateButtons[param.name] = button
                button.toggled.connect(self.buttonToggled)
                widget = QWidget()
                widget.setLayout(layout)

            tooltips = self.alg.getParameterDescriptions()
            widget.setToolTip(tooltips.get(param.name, param.description))

            if isinstance(param, ParameterBoolean):
                widget.setText(desc)
                if param.isAdvanced:
                    self.layoutAdvanced.addWidget(widget)
                else:
                    self.layoutMain.insertWidget(
                        self.layoutMain.count() - 2, widget)
            else:
                label = QLabel(desc)
                #label.setToolTip(tooltip)
                self.labels[param.name] = label
                if param.isAdvanced:
                    self.layoutAdvanced.addWidget(label)
                    self.layoutAdvanced.addWidget(widget)
                else:
                    self.layoutMain.insertWidget(
                        self.layoutMain.count() - 2, label)
                    self.layoutMain.insertWidget(
                        self.layoutMain.count() - 2, widget)

            self.widgets[param.name] = widget

        for output in self.alg.outputs:
            if output.hidden:
                continue

            label = QLabel(output.description)
            widget = OutputSelectionPanel(output, self.alg)
            self.layoutMain.insertWidget(self.layoutMain.count() - 1, label)
            self.layoutMain.insertWidget(self.layoutMain.count() - 1, widget)
            if isinstance(output, (OutputRaster, OutputVector, OutputTable)):
                check = QCheckBox()
                check.setText(self.tr('Open output file after running algorithm'))
                check.setChecked(True)
                self.layoutMain.insertWidget(self.layoutMain.count() - 1, check)
                self.checkBoxes[output.name] = check
            self.valueItems[output.name] = widget

            if isinstance(output, OutputVector):
                if output.base_input in self.dependentItems:
                    items = self.dependentItems[output.base_input]
                else:
                    items = []
                    self.dependentItems[output.base_input] = items
                items.append(output)

                base_input = self.alg.getParameterFromName(output.base_input)
                if isinstance(base_input, ParameterVector):
                    layers = dataobjects.getVectorLayers(base_input.datatype)
                else:
                    layers = dataobjects.getTables()
                if len(layers) > 0:
                    output.base_layer = layers[0]
コード例 #21
0
class PlanetExplorer(object):
    def __init__(self, iface):

        self.iface = iface

        # Initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)

        # Initialize locale
        locale = QSettings().value("locale/userLocale")[0:2]
        locale_path = os.path.join(
            self.plugin_dir, "i18n", "{0}Plugin_{1}.qm".format(PE, locale)
        )

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)
            QCoreApplication.installTranslator(self.translator)

        # Declare instance attributes
        self.actions = []
        self.menu = self.tr("&{0}".format(P_E))
        self.toolbar = None

        # noinspection PyTypeChecker
        self.explorer_dock_widget = None
        self._terms_browser = None

        if is_segments_write_key_valid():
            analytics.write_key = segments_write_key()
        if is_sentry_dsn_valid():
            try:
                sentry_sdk.init(sentry_dsn(), release=plugin_version(True))
                sentry_sdk.set_context(
                    "qgis",
                    {
                        "type": "runtime",
                        "name": Qgis.QGIS_RELEASE_NAME,
                        "version": Qgis.QGIS_VERSION,
                    },
                )
                system = platform.system()
                if system == "Darwin":
                    sentry_sdk.set_context(
                        "mac",
                        {
                            "type": "os",
                            "name": "macOS",
                            "version": platform.mac_ver()[0],
                            "kernel_version": platform.uname().release,
                        },
                    )
                if system == "Linux":
                    sentry_sdk.set_context(
                        "linux",
                        {
                            "type": "os",
                            "name": "Linux",
                            "version": platform.release(),
                            "build": platform.version(),
                        },
                    )
                if system == "Windows":
                    sentry_sdk.set_context(
                        "windows",
                        {
                            "type": "os",
                            "name": "Windows",
                            "version": platform.version(),
                        },
                    )
            except Exception:
                QMessageBox.warning(
                    self.iface.mainWindow(),
                    "Error",
                    "Error initializing Planet Explorer.\n"
                    "Please restart QGIS to load updated libraries.",
                )

        self.qgis_hook = sys.excepthook

        def plugin_hook(t, value, tb):
            trace = "".join(traceback.format_exception(t, value, tb))
            if PLUGIN_NAMESPACE in trace.lower():
                s = ""
                if issubclass(t, exceptions.Timeout):
                    s = "Connection to Planet server timed out."
                elif issubclass(t, exceptions.ConnectionError):
                    s = (
                        "Connection error.\n Verify that your computer is correctly"
                        " connected to the Internet"
                    )
                elif issubclass(t, (exceptions.ProxyError, exceptions.InvalidProxyURL)):
                    s = (
                        "ProxyError.\n Verify that your proxy is correctly configured"
                        " in the QGIS settings"
                    )
                elif issubclass(t, planet.api.exceptions.ServerError):
                    s = "Server Error.\n Please, try again later"
                elif issubclass(t, urllib3.exceptions.ProxySchemeUnknown):
                    s = (
                        "Proxy Error\n Proxy URL must start with 'http://' or"
                        " 'https://'"
                    )

                if s:
                    QMessageBox.warning(self.iface.mainWindow(), "Error", s)
                else:
                    try:
                        sentry_sdk.capture_exception(value)
                    except Exception:
                        pass  # we swallow all exceptions here, to avoid entering an endless loop
                    self.qgis_hook(t, value, tb)
            else:
                self.qgis_hook(t, value, tb)

        sys.excepthook = plugin_hook

    def tr(self, message):
        """Get the translation for a string using Qt translation API.

        We implement this ourselves since we do not inherit QObject.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString
        """
        # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
        return QCoreApplication.translate(PE, message)

    def add_action(
        self,
        icon_path,
        text,
        callback,
        enabled_flag=True,
        add_to_menu=True,
        add_to_toolbar=True,
        status_tip=None,
        whats_this=None,
        parent=None,
    ):
        """Add a toolbar icon to the toolbar.

        :param icon_path: Path to the icon for this action. Can be a resource
            path (e.g. ':/plugins/foo/bar.png') or a normal file system path.
        :type icon_path: str

        :param text: Text that should be shown in menu items for this action.
        :type text: str

        :param callback: Function to be called when the action is triggered.
        :type callback: function

        :param enabled_flag: A flag indicating if the action should be enabled
            by default. Defaults to True.
        :type enabled_flag: bool

        :param add_to_menu: Flag indicating whether the action should also
            be added to the menu. Defaults to True.
        :type add_to_menu: bool

        :param add_to_toolbar: Flag indicating whether the action should also
            be added to the toolbar. Defaults to True.
        :type add_to_toolbar: bool

        :param status_tip: Optional text to show in a popup when mouse pointer
            hovers over the action.
        :type status_tip: str

        :param parent: Parent widget for the new action. Defaults None.
        :type parent: QWidget

        :param whats_this: Optional text to show in the status bar when the
            mouse pointer hovers over the action.

        :returns: The action that was created. Note that the action is also
            added to self.actions list.
        :rtype: QAction
        """

        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)

        if add_to_toolbar:
            self.toolbar.addAction(action)

        if add_to_menu:
            self.iface.addPluginToWebMenu(self.menu, action)

        self.actions.append(action)

        return action

    # noinspection PyPep8Naming
    def initGui(self):

        self.toolbar = self.iface.addToolBar(P_E)
        self.toolbar.setObjectName(P_E)

        self.showdailyimages_act = self.add_action(
            os.path.join(plugin_path, "resources", "search.svg"),
            text=self.tr(P_E),
            callback=toggle_images_search,
            add_to_menu=True,
            add_to_toolbar=True,
            parent=self.iface.mainWindow(),
        )

        self.showbasemaps_act = self.add_action(
            os.path.join(plugin_path, "resources", "basemap.svg"),
            text=self.tr("Show Basemaps Search"),
            callback=toggle_mosaics_search,
            add_to_menu=True,
            add_to_toolbar=True,
            parent=self.iface.mainWindow(),
        )

        self.showinspector_act = self.add_action(
            os.path.join(plugin_path, "resources", "inspector.svg"),
            text=self.tr("Show Planet Inspector..."),
            callback=toggle_inspector,
            add_to_menu=False,
            add_to_toolbar=True,
            parent=self.iface.mainWindow(),
        )

        self.showtasking_act = self.add_action(
            os.path.join(plugin_path, "resources", "tasking.svg"),
            text=self.tr("Show Tasking..."),
            callback=toggle_tasking_widget,
            add_to_menu=False,
            add_to_toolbar=True,
            parent=self.iface.mainWindow(),
        )

        self.add_central_toolbar_button()

        self.showorders_act = self.add_action(
            os.path.join(plugin_path, "resources", "orders.svg"),
            text=self.tr("Show Orders Monitor..."),
            callback=toggle_orders_monitor,
            add_to_menu=False,
            add_to_toolbar=True,
            parent=self.iface.mainWindow(),
        )

        self.add_user_button()
        self.add_info_button()

        self.settings_act = self.add_action(
            os.path.join(plugin_path, "resources", "cog.svg"),
            text=self.tr("Settings..."),
            callback=self.show_settings,
            add_to_menu=True,
            add_to_toolbar=False,
            parent=self.iface.mainWindow(),
        )

        self.provider = BasemapLayerWidgetProvider()
        QgsGui.layerTreeEmbeddedWidgetRegistry().addProvider(self.provider)

        QgsProject.instance().projectSaved.connect(self.project_saved)
        QgsProject.instance().layersAdded.connect(self.layers_added)
        QgsProject.instance().layerRemoved.connect(self.layer_removed)

        PlanetClient.getInstance().loginChanged.connect(self.login_changed)

        self.enable_buttons(False)

    def add_central_toolbar_button(self):
        widget = QWidget()
        widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
        layout = QHBoxLayout()
        layout.addStretch()
        self.btnLogin = QPushButton()
        palette = self.btnLogin.palette()
        palette.setColor(QPalette.Button, PLANET_COLOR)
        self.btnLogin.setPalette(palette)
        self.btnLogin.setText("Log in")
        # self.btnLogin.setAutoRaise(True)
        self.btnLogin.setAttribute(Qt.WA_TranslucentBackground)
        self.btnLogin.clicked.connect(self.btn_login_clicked)
        icon = QIcon(os.path.join(plugin_path, "resources", "planet-logo-p.svg"))
        labelIcon = QLabel()
        labelIcon.setPixmap(icon.pixmap(QSize(16, 16)))
        layout.addWidget(labelIcon)
        self.labelLoggedIn = QLabel()
        self.labelLoggedIn.setText("")
        layout.addWidget(self.labelLoggedIn)
        layout.addWidget(self.btnLogin)
        layout.addStretch()
        widget.setLayout(layout)
        self.toolbar.addWidget(widget)

    def btn_login_clicked(self):
        if PlanetClient.getInstance().has_api_key():
            self.logout()
        else:
            self.login()

    def layer_removed(self, layer):
        self.provider.layerWasRemoved(layer)

    def layers_added(self, layers):
        for layer in layers:
            add_widget_to_layer(layer)

    def login_changed(self, loggedin):
        self.provider.updateLayerWidgets()
        self.enable_buttons(loggedin)
        if not loggedin:
            hide_orders_monitor()
            hide_inspector()

    def add_info_button(self):
        info_menu = QMenu()

        add_menu_section_action("Planet", info_menu)

        p_com_act = QAction(QIcon(EXT_LINK), "planet.com", info_menu)
        p_com_act.triggered[bool].connect(lambda: open_link_with_browser(PLANET_COM))
        info_menu.addAction(p_com_act)

        p_explorer_act = QAction(QIcon(EXT_LINK), "Planet Explorer web app", info_menu)
        p_explorer_act.triggered[bool].connect(
            lambda: open_link_with_browser(PLANET_EXPLORER)
        )
        info_menu.addAction(p_explorer_act)

        p_sat_act = QAction(QIcon(EXT_LINK), "Satellite specs PDF", info_menu)
        p_sat_act.triggered[bool].connect(lambda: open_link_with_browser(SAT_SPECS_PDF))
        info_menu.addAction(p_sat_act)

        p_support_act = QAction(QIcon(EXT_LINK), "Support Community", info_menu)
        p_support_act.triggered[bool].connect(
            lambda: open_link_with_browser(PLANET_SUPPORT_COMMUNITY)
        )
        info_menu.addAction(p_support_act)

        p_whatsnew_act = QAction(QIcon(EXT_LINK), "What's new", info_menu)
        p_whatsnew_act.triggered[bool].connect(
            lambda: open_link_with_browser(PLANET_INTEGRATIONS)
        )
        info_menu.addAction(p_whatsnew_act)

        p_sales_act = QAction(QIcon(EXT_LINK), "Sales", info_menu)
        p_sales_act.triggered[bool].connect(
            lambda: open_link_with_browser(PLANET_SALES)
        )
        info_menu.addAction(p_sales_act)

        add_menu_section_action("Documentation", info_menu)

        terms_act = QAction("Terms", info_menu)
        terms_act.triggered[bool].connect(self.show_terms)
        info_menu.addAction(terms_act)

        btn = QToolButton()
        btn.setIcon(
            QIcon(
                os.path.join(plugin_path, "resources", "info.svg"),
            )
        )
        btn.setMenu(info_menu)

        btn.setPopupMode(QToolButton.MenuButtonPopup)
        # Also show menu on click, to keep disclosure triangle visible
        btn.clicked.connect(btn.showMenu)

        self.toolbar.addWidget(btn)

    def add_user_button(self):
        user_menu = QMenu()

        self.acct_act = QAction(QIcon(EXT_LINK), "Account", user_menu)
        self.acct_act.triggered[bool].connect(
            lambda: QDesktopServices.openUrl(QUrl(ACCOUNT_URL))
        )
        user_menu.addAction(self.acct_act)

        self.logout_act = QAction("Logout", user_menu)
        self.logout_act.triggered[bool].connect(self.logout)
        user_menu.addAction(self.logout_act)

        self.user_button = QToolButton()
        self.user_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.user_button.setIcon(
            QIcon(
                os.path.join(plugin_path, "resources", "account.svg"),
            )
        )
        self.user_button.setMenu(user_menu)

        self.user_button.setPopupMode(QToolButton.MenuButtonPopup)
        # Also show menu on click, to keep disclosure triangle visible
        self.user_button.clicked.connect(self.user_button.showMenu)

        self.toolbar.addWidget(self.user_button)

    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""

        PlanetClient.getInstance().log_out()
        self.provider.updateLayerWidgets()

        for action in self.actions:
            self.iface.removePluginWebMenu(self.tr("&{0}".format(P_E)), action)
            self.iface.removeToolBarIcon(action)

        # remove the toolbar
        if self.toolbar is not None:
            del self.toolbar

        remove_inspector()
        remove_explorer()
        remove_orders_monitor()
        remove_tasking_widget()

        QgsGui.layerTreeEmbeddedWidgetRegistry().removeProvider(self.provider.id())

        sys.excepthook = self.qgis_hook

        QgsProject.instance().projectSaved.disconnect(self.project_saved)
        QgsProject.instance().layersAdded.disconnect(self.layers_added)
        QgsProject.instance().layerRemoved.disconnect(self.layer_removed)

    # -----------------------------------------------------------

    def show_settings(self):
        dlg = SettingsDialog()
        dlg.exec()

    def show_terms(self, _):
        if self._terms_browser is None:
            self._terms_browser = QTextBrowser()
            self._terms_browser.setReadOnly(True)
            self._terms_browser.setOpenExternalLinks(True)
            self._terms_browser.setMinimumSize(600, 700)
            # TODO: Template terms.html first section, per subscription level
            #       Collect subscription info from self.p_client.user
            self._terms_browser.setSource(
                QUrl("qrc:/plugins/planet_explorer/terms.html")
            )
            self._terms_browser.setWindowModality(Qt.ApplicationModal)
        self._terms_browser.show()

    def login(self):
        if Qgis.QGIS_VERSION_INT >= 32000 and platform.system() == "Darwin":
            text = (
                "WARNING: Your configuration may encounter serious issues with the"
                " Planet QGIS Plugin using QGIS V3.20. We are actively troubleshooting"
                " the issue with the QGIS team, you can track <a"
                " href='https://github.com/qgis/QGIS/issues/44182'>Issue 44182"
                " here</a>. In the meantime, we recommend that you use a QGIS version"
                " between 3.10 and 3.20, such as the 3.16 long term stable release. For"
                " further information including instructions on how to downgrade QGIS,"
                " please refer to our <a"
                " href='https://support.planet.com/hc/en-us/articles/4404372169233'>support"
                " page here</a>."
            )
            QMessageBox.warning(self.iface.mainWindow(), "Planet Explorer", text)
        show_explorer()

    def logout(self):
        PlanetClient.getInstance().log_out()

    def enable_buttons(self, loggedin):
        self.btnLogin.setVisible(not loggedin)
        labelText = "<b>Welcome to Planet</b>" if not loggedin else "<b>Planet</b>"
        self.labelLoggedIn.setText(labelText)
        self.showdailyimages_act.setEnabled(loggedin)
        self.showbasemaps_act.setEnabled(loggedin)
        self.showinspector_act.setEnabled(loggedin)
        self.showorders_act.setEnabled(loggedin)
        self.showtasking_act.setEnabled(loggedin)
        self.user_button.setEnabled(loggedin)
        self.user_button.setText(
            PlanetClient.getInstance().user()["user_name"] if loggedin else ""
        )
        if loggedin:
            self.showdailyimages_act.setToolTip(
                "Show / Hide the Planet Imagery Search Panel"
            )
            self.showbasemaps_act.setToolTip(
                "Show / Hide the Planet Basemaps Search Panel"
            )
            self.showorders_act.setToolTip("Show / Hide the Order Status Panel")
            self.showinspector_act.setToolTip("Show / Hide the Planet Inspector Panel")
            self.showtasking_act.setToolTip("Show / Hide the Tasking Panel")
        else:
            self.showdailyimages_act.setToolTip("Login to access Imagery Search")
            self.showbasemaps_act.setToolTip("Login to access Basemaps Search")
            self.showorders_act.setToolTip("Login to access Order Status")
            self.showinspector_act.setToolTip("Login to access Planet Inspector")
            self.showtasking_act.setToolTip("Login to access Tasking Panel")

    def project_saved(self):
        if PlanetClient.getInstance().has_api_key():

            def resave():
                try:
                    path = QgsProject.instance().absoluteFilePath()
                    if path.lower().endswith(".qgs"):
                        with open(path, encoding="utf-8") as f:
                            s = f.read()
                        with open(path, "w", encoding="utf-8") as f:
                            f.write(s.replace(PlanetClient.getInstance().api_key(), ""))
                    else:
                        tmpfilename = path + ".temp"
                        qgsfilename = (
                            os.path.splitext(os.path.basename(path))[0] + ".qgs"
                        )
                        with zipfile.ZipFile(path, "r") as zin:
                            with zipfile.ZipFile(tmpfilename, "w") as zout:
                                zout.comment = zin.comment
                                for item in zin.infolist():
                                    if not item.filename.lower().endswith(".qgs"):
                                        zout.writestr(item, zin.read(item.filename))
                                    else:
                                        s = zin.read(item.filename).decode("utf-8")
                                        s = s.replace(
                                            PlanetClient.getInstance().api_key(), ""
                                        )
                                        qgsfilename = item.filename
                        os.remove(path)
                        os.rename(tmpfilename, path)
                        with zipfile.ZipFile(
                            path, mode="a", compression=zipfile.ZIP_DEFLATED
                        ) as zf:
                            zf.writestr(qgsfilename, s)
                except Exception:
                    QMessageBox.warning(
                        self.iface.mainWindow(),
                        "Error saving project",
                        "There was an error while removing API keys from QGIS project"
                        " file.\nThe project that you have just saved might contain"
                        " Planet API keys in plain text.",
                    )

            QTimer.singleShot(100, resave)
コード例 #22
0
ファイル: relation_line_edit.py プロジェクト: ollawone/stdm
class ExpressionLineEdit(QLineEdit):
    def __init__(self, column, host=None, parent=None):
        # Use a different pixmap

        self._current_profile = current_profile()

        QLineEdit.__init__(self, parent)

        self.column = column
        self._entity = self.column.entity

        self.layer = self.create_layer()
        self.host = host
        # Configure load button
        self.btn_load = QToolButton(parent)
        self.btn_load.setCursor(Qt.PointingHandCursor)
        self.btn_load.setFocusPolicy(Qt.NoFocus)
        px = GuiUtils.get_icon_pixmap('expression.png')

        self.btn_load.setIcon(QIcon(px))
        self.btn_load.setIconSize(px.size())
        self.btn_load.setStyleSheet('background: transparent; padding: 0px; '
                                    'border: none;')

        frame_width = self.set_button_minimum_size(self.btn_load)

        # Ensure that text does not overlay button
        padding = self.btn_load.sizeHint().width() + frame_width + 1

        self.setStyleSheet('padding-right: ' + str(padding * 2) + 'px;')

        # Set layout
        self.button_layout = QHBoxLayout(self)

        self.button_layout.addWidget(self.btn_load, 0, Qt.AlignRight)

        self.button_layout.setSpacing(0)
        self.button_layout.setMargin(5)

        # Readonly as text generated automatically
        self.setReadOnly(True)

        # Current model object
        self._current_item = None

    def create_layer(self):
        srid = None
        column = ''
        if self.entity.has_geometry_column():
            geom_cols = [col.name for col in self.entity.columns.values()
                         if col.TYPE_INFO == 'GEOMETRY']
            column = geom_cols[0]
            geom_col_obj = self.entity.columns[column]

            if geom_col_obj.srid >= 100000:
                srid = geom_col_obj.srid
        layer = vector_layer(self.entity.name, geom_column=column,
                             proj_wkt=srid)
        return layer

    def get_feature_value(self, model=None):
        self.layer.startEditing()
        feature = None

        request = QgsFeatureRequest()
        if model is None:
            model = self.host.model()
        request.setFilterFid(model.id)
        feature_itr = self.layer.getFeatures(request)
        for feat in feature_itr:
            feature = feat
            break

        exp = QgsExpression(self.column.expression)

        if exp.hasParserError():
            raise Exception(exp.parserErrorString())

        exp.prepare(self.layer.fields())
        if feature is not None:
            value = exp.evaluate(feature)

            return value
        else:
            return None

    def set_button_minimum_size(self, button):
        """
        Sets the minimum button size.
        :param button: The button to be set.
        :type button: QToolButton
        :return: Returns the frame width of the button
        :rtype: Integer
        """
        frame_width = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth)
        msz = self.minimumSizeHint()
        self.setMinimumSize(
            max(
                msz.width(),
                button.sizeHint().height() + frame_width * 2 + 2
            ), max(
                msz.height(),
                button.sizeHint().height() + frame_width * 2 + 2
            )
        )
        return frame_width

    @property
    def entity(self):
        """
        :return: Returns the entity object corresponding to this widget.
        :rtype: Entity
        """
        return self._entity

    def clear_line_edit(self):
        """
        Clears the text in the line edit.
        """
        self.clear()

    def on_expression_triggered(self, model=None):
        """
        Slot raised to load browser for selecting foreign key entities. To be
        implemented by subclasses.
        """
        self.format_display(self.get_feature_value(model))
        return self.get_feature_value()

    def format_display(self, value):
        """
        Extract object values to show in the line edit based on the specified
        display columns.
        """
        if value is not None:
            self.setText(str(value))
コード例 #23
0
ファイル: ParametersPanel.py プロジェクト: minorua/QGIS
    def initWidgets(self):
        # If there are advanced parameters — show corresponding groupbox
        for param in self.alg.parameterDefinitions():
            if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced:
                self.grpAdvanced.show()
                break
        # Create widgets and put them in layouts
        for param in self.alg.parameterDefinitions():
            if param.flags() & QgsProcessingParameterDefinition.FlagHidden:
                continue

            if param.isDestination():
                continue
            else:
                desc = param.description()
                if isinstance(param, QgsProcessingParameterExtent):
                    desc += self.tr(' (xmin, xmax, ymin, ymax)')
                if isinstance(param, QgsProcessingParameterPoint):
                    desc += self.tr(' (x, y)')
                if param.flags() & QgsProcessingParameterDefinition.FlagOptional:
                    desc += self.tr(' [optional]')

                wrapper = WidgetWrapperFactory.create_wrapper(param, self.parent)
                self.wrappers[param.name()] = wrapper
                widget = wrapper.widget

                if widget is not None:
                    if isinstance(param, QgsProcessingParameterFeatureSource):
                        layout = QHBoxLayout()
                        layout.setSpacing(2)
                        layout.setMargin(0)
                        layout.addWidget(widget)
                        button = QToolButton()
                        icon = QIcon(os.path.join(pluginPath, 'images', 'iterate.png'))
                        button.setIcon(icon)
                        button.setToolTip(self.tr('Iterate over this layer, creating a separate output for every feature in the layer'))
                        button.setCheckable(True)
                        layout.addWidget(button)
                        layout.setAlignment(button, Qt.AlignTop)
                        self.iterateButtons[param.name()] = button
                        button.toggled.connect(self.buttonToggled)
                        widget = QWidget()
                        widget.setLayout(layout)

                    widget.setToolTip(param.toolTip())

                    if type(widget) is QCheckBox:
                        # checkbox widget - so description is embedded in widget rather than a separate
                        # label
                        widget.setText(desc)
                    else:
                        label = QLabel(desc)
                        # label.setToolTip(tooltip)
                        self.labels[param.name()] = label

                        if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced:
                            self.layoutAdvanced.addWidget(label)
                        else:
                            self.layoutMain.insertWidget(
                                self.layoutMain.count() - 2, label)

                    if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced:
                        self.layoutAdvanced.addWidget(widget)
                    else:
                        self.layoutMain.insertWidget(
                            self.layoutMain.count() - 2, widget)

        for output in self.alg.destinationParameterDefinitions():
            if output.flags() & QgsProcessingParameterDefinition.FlagHidden:
                continue

            label = QLabel(output.description())
            widget = DestinationSelectionPanel(output, self.alg)
            self.layoutMain.insertWidget(self.layoutMain.count() - 1, label)
            self.layoutMain.insertWidget(self.layoutMain.count() - 1, widget)
            if isinstance(output, (QgsProcessingParameterRasterDestination, QgsProcessingParameterFeatureSink, QgsProcessingParameterVectorDestination)):
                check = QCheckBox()
                check.setText(self.tr('Open output file after running algorithm'))
                check.setChecked(True)
                self.layoutMain.insertWidget(self.layoutMain.count() - 1, check)
                self.checkBoxes[output.name()] = check

            widget.setToolTip(param.toolTip())
            self.outputWidgets[output.name()] = widget

        for wrapper in list(self.wrappers.values()):
            wrapper.postInitialize(list(self.wrappers.values()))
コード例 #24
0
    def initGui(self):
        # Add GUI elements
        self.splash_screen = ui.SplashScreen(self)
        self.config_dialog = ui.ConfigDialog()
        self.tilesManager = tiles.TilesManager()

        self.toolbar = self.iface.addToolBar("Travel Time Platform Toolbar")

        # Logo
        button = QPushButton(resources.logo, "")
        button.setIconSize(QSize(112, 30))
        button.setFlat(True)
        button.pressed.connect(self.show_splash)
        self.toolbar.addWidget(button)
        self.toolbar.addSeparator()

        # Show toolbox action
        self.action_show_toolbox = QAction(resources.icon_general,
                                           tr("Show the toolbox"),
                                           self.iface.mainWindow())
        self.action_show_toolbox.triggered.connect(self.show_toolbox)
        self.toolbar.addAction(self.action_show_toolbox)
        self.iface.addPluginToMenu(u"&Travel Time Platform",
                                   self.action_show_toolbox)

        # Add tiles
        tiles_menu = QMenu()
        for key, tile in self.tilesManager.tiles.items():
            action = QAction(tile["resource"], tile["label"], tiles_menu)
            action.triggered.connect(
                functools.partial(self.tilesManager.add_layer, key))
            action.setEnabled(self.tilesManager.has_tiles)
            tiles_menu.addAction(action)
        if not self.tilesManager.has_tiles:
            action = QAction(tr("Request access to backgrounds"), tiles_menu)
            action.triggered.connect(
                lambda: self.tilesManager.request_access())
            tiles_menu.addAction(action)

        tiles_button = QToolButton()
        tiles_button.setToolTip(tr("Add background"))
        tiles_button.setIcon(resources.icon_tiles)
        tiles_button.setMenu(tiles_menu)
        tiles_button.setPopupMode(QToolButton.InstantPopup)

        # self.action_show_toolbox.triggered.connect(self.show_toolbox)
        self.toolbar.addWidget(tiles_button)
        # self.iface.addPluginToMenu(u"&Travel Time Platform", self.action_show_toolbox)
        self.toolbar.addSeparator()

        # Show help actions
        self.action_show_help = QAction(resources.icon_help, tr("Help"),
                                        self.iface.mainWindow())
        self.action_show_help.triggered.connect(self.show_splash)
        self.toolbar.addAction(self.action_show_help)
        self.iface.addPluginToMenu(u"&Travel Time Platform",
                                   self.action_show_help)

        # Show config actions
        self.action_show_config = QAction(
            resources.icon_config,
            tr("Configure Travel Time Platform plugin"),
            self.iface.mainWindow(),
        )
        self.action_show_config.triggered.connect(self.show_config)
        self.toolbar.addAction(self.action_show_config)
        self.iface.addPluginToMenu(u"&Travel Time Platform",
                                   self.action_show_config)

        # Add the provider to the registry
        QgsApplication.processingRegistry().addProvider(self.provider)

        # Show splash screen
        if not QSettings().value(
                "travel_time_platform/spashscreen_dontshowagain", False,
                type=bool):
            self.show_splash()
コード例 #25
0
ファイル: manager.py プロジェクト: jeremyk6/annotationManager
    def __init__(self, iface):
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(os.path.dirname(__file__), 'i18n',
                                   'annotationManager_{}.qm'.format(locale))

        self.translator = None
        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)

        if qVersion() > '4.3.3':
            QCoreApplication.installTranslator(self.translator)

        self.iface = iface
        self.iface.projectRead.connect(self.projectOpen)

        self.dock = QDockWidget(self.tr('Annotations'))
        self.manager = QWidget()
        toolbar = QToolBar()

        self.annotationList = QListWidget()
        self.annotationList.setSelectionMode(
            QAbstractItemView.ExtendedSelection)
        self.annotationList.itemSelectionChanged.connect(self.selectAnnotation)
        self.annotationList.itemChanged.connect(self.checkItem)
        action_refresh = QAction(
            QIcon(':/plugins/annotationManager/resources/mActionDraw.png'),
            self.tr('Refresh the annotations list'), self.manager)
        action_refresh.triggered.connect(self.refreshAnnotations)
        action_remove = QAction(
            QIcon(
                ':/plugins/annotationManager/resources/mActionRemoveAnnotation.png'
            ), self.tr('Remove the selected annotation'), self.manager)
        action_remove.triggered.connect(self.removeAnnotation)

        viewMenu = QMenu()
        action_showAll = QAction(
            QIcon(':/plugins/annotationManager/resources/mActionShowAll.png'),
            self.tr('Show all annotations'), self.manager)
        action_showAll.triggered.connect(self.showAll)
        action_hideAll = QAction(
            QIcon(':/plugins/annotationManager/resources/mActionHideAll.png'),
            self.tr('Hide all annotations'), self.manager)
        action_hideAll.triggered.connect(self.hideAll)
        action_showAllSelected = QAction(
            QIcon(':/plugins/annotationManager/resources/mActionShowAll.png'),
            self.tr('Show all selected annotations'), self.manager)
        action_showAllSelected.triggered.connect(self.showAllSelected)
        action_hideAllSelected = QAction(
            QIcon(':/plugins/annotationManager/resources/mActionHideAll.png'),
            self.tr('Hide all selected annotations'), self.manager)
        action_hideAllSelected.triggered.connect(self.hideAllSelected)
        viewMenu.addAction(action_showAll)
        viewMenu.addAction(action_hideAll)
        viewMenu.addAction(action_showAllSelected)
        viewMenu.addAction(action_hideAllSelected)
        viewButton = QToolButton()
        viewButton.setIcon(
            QIcon(':/plugins/annotationManager/resources/mActionShowAll.png'))
        viewButton.setPopupMode(2)
        viewButton.setMenu(viewMenu)

        toolbar.addAction(action_refresh)
        toolbar.addAction(action_remove)
        toolbar.addWidget(viewButton)
        toolbar.setIconSize(QSize(16, 16))

        p1_vertical = QVBoxLayout()
        p1_vertical.setContentsMargins(0, 0, 0, 0)
        p1_vertical.addWidget(toolbar)
        p1_vertical.addWidget(self.annotationList)
        self.manager.setLayout(p1_vertical)

        self.dock.setWidget(self.manager)
        self.dock.setAllowedAreas(Qt.LeftDockWidgetArea
                                  | Qt.RightDockWidgetArea)
        self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dock)

        self.rb = QgsRubberBand(self.iface.mapCanvas(),
                                QgsWkbTypes.PolygonGeometry)

        self.project = QgsProject.instance()
        self.annotationManager = self.project.annotationManager()
        self.annotationManager.annotationAdded.connect(self.refreshAnnotations)
        self.annotationManager.annotationRemoved.connect(
            self.refreshAnnotations)
コード例 #26
0
ファイル: ParametersPanel.py プロジェクト: cayetanobv/QGIS
    def initWidgets(self):
        # If there are advanced parameters — show corresponding groupbox
        for param in self.alg.parameters:
            if param.isAdvanced:
                self.grpAdvanced.show()
                break
        # Create widgets and put them in layouts
        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]')

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

            if widget is not None:
                if isinstance(param, ParameterVector):
                    layout = QHBoxLayout()
                    layout.setSpacing(2)
                    layout.setMargin(0)
                    layout.addWidget(widget)
                    button = QToolButton()
                    icon = QIcon(os.path.join(pluginPath, 'images', 'iterate.png'))
                    button.setIcon(icon)
                    button.setToolTip(self.tr('Iterate over this layer'))
                    button.setCheckable(True)
                    layout.addWidget(button)
                    self.iterateButtons[param.name] = button
                    button.toggled.connect(self.buttonToggled)
                    widget = QWidget()
                    widget.setLayout(layout)

                tooltips = self.alg.getParameterDescriptions()
                widget.setToolTip(tooltips.get(param.name, param.description))

                if type(widget) is QCheckBox:
                    # checkbox widget - so description is embedded in widget rather than a separate
                    # label
                    widget.setText(desc)
                else:
                    label = QLabel(desc)
                    # label.setToolTip(tooltip)
                    self.labels[param.name] = label

                    if param.isAdvanced:
                        self.layoutAdvanced.addWidget(label)
                    else:
                        self.layoutMain.insertWidget(
                            self.layoutMain.count() - 2, label)

                if param.isAdvanced:
                    self.layoutAdvanced.addWidget(widget)
                else:
                    self.layoutMain.insertWidget(
                        self.layoutMain.count() - 2, widget)

        for output in self.alg.outputs:
            if output.hidden:
                continue

            label = QLabel(output.description)
            widget = OutputSelectionPanel(output, self.alg)
            self.layoutMain.insertWidget(self.layoutMain.count() - 1, label)
            self.layoutMain.insertWidget(self.layoutMain.count() - 1, widget)
            if isinstance(output, (OutputRaster, OutputVector, OutputTable)):
                check = QCheckBox()
                check.setText(self.tr('Open output file after running algorithm'))
                check.setChecked(True)
                self.layoutMain.insertWidget(self.layoutMain.count() - 1, check)
                self.checkBoxes[output.name] = check
            self.outputWidgets[output.name] = widget
        for wrapper in list(self.wrappers.values()):
            wrapper.postInitialize(list(self.wrappers.values()))
コード例 #27
0
class PlanetExplorer(object):

    def __init__(self, iface):

        self.iface = iface

        # Initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)

        # Initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(
            self.plugin_dir,
            'i18n',
            '{0}Plugin_{1}.qm'.format(PE, locale)
        )

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)
            QCoreApplication.installTranslator(self.translator)

        # Declare instance attributes
        self.actions = []
        self.menu = self.tr('&{0}'.format(P_E))
        self.toolbar = None

        # noinspection PyTypeChecker
        self.explorer_dock_widget = None
        self._terms_browser = None

        readSettings()

        if is_segments_write_key_valid():
            analytics.write_key = segments_write_key()
        if is_sentry_dsn_valid():
            sentry_sdk.init(sentry_dsn(), default_integrations=False)

        self.qgis_hook = sys.excepthook

        def plugin_hook(t, value, tb):
            trace = "".join(traceback.format_exception(t, value, tb))
            if PLUGIN_NAMESPACE in trace.lower():
                try:
                    sentry_sdk.capture_exception(value)
                except:
                    pass # we swallow all exceptions here, to avoid entering an endless loop
            self.qgis_hook(t, value, tb)

        sys.excepthook = plugin_hook

        metadataFile = os.path.join(os.path.dirname(__file__), "metadata.txt")
        cp = configparser.ConfigParser()
        with codecs.open(metadataFile, "r", "utf8") as f:
            cp.read_file(f)

        if is_sentry_dsn_valid():
            version = cp["general"]["version"]
            with sentry_sdk.configure_scope() as scope:
                scope.set_context("plugin_version", version)
                scope.set_context("qgis_version", Qgis.QGIS_VERSION)

    # noinspection PyMethodMayBeStatic
    def tr(self, message):
        """Get the translation for a string using Qt translation API.

        We implement this ourselves since we do not inherit QObject.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString
        """
        # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
        return QCoreApplication.translate(PE, message)

    def add_action(
            self,
            icon_path,
            text,
            callback,
            enabled_flag=True,
            add_to_menu=True,
            add_to_toolbar=True,
            status_tip=None,
            whats_this=None,
            parent=None):
        """Add a toolbar icon to the toolbar.

        :param icon_path: Path to the icon for this action. Can be a resource
            path (e.g. ':/plugins/foo/bar.png') or a normal file system path.
        :type icon_path: str

        :param text: Text that should be shown in menu items for this action.
        :type text: str

        :param callback: Function to be called when the action is triggered.
        :type callback: function

        :param enabled_flag: A flag indicating if the action should be enabled
            by default. Defaults to True.
        :type enabled_flag: bool

        :param add_to_menu: Flag indicating whether the action should also
            be added to the menu. Defaults to True.
        :type add_to_menu: bool

        :param add_to_toolbar: Flag indicating whether the action should also
            be added to the toolbar. Defaults to True.
        :type add_to_toolbar: bool

        :param status_tip: Optional text to show in a popup when mouse pointer
            hovers over the action.
        :type status_tip: str

        :param parent: Parent widget for the new action. Defaults None.
        :type parent: QWidget

        :param whats_this: Optional text to show in the status bar when the
            mouse pointer hovers over the action.

        :returns: The action that was created. Note that the action is also
            added to self.actions list.
        :rtype: QAction
        """

        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)

        if add_to_toolbar:
            self.toolbar.addAction(action)

        if add_to_menu:
            self.iface.addPluginToWebMenu(
                self.menu,
                action)

        self.actions.append(action)

        return action

    # noinspection PyPep8Naming
    def initGui(self):

        self.toolbar = self.iface.addToolBar(P_E)
        self.toolbar.setObjectName(P_E)

        self.showdailyimages_act = self.add_action(
            os.path.join(plugin_path, "resources", "search.svg"),
            text=self.tr(P_E),
            callback=toggle_images_search,
            add_to_menu=True,
            add_to_toolbar=True,
            parent=self.iface.mainWindow())

        self.showbasemaps_act = self.add_action(
            os.path.join(plugin_path, "resources", "basemap.svg"),
            text=self.tr("Show Basemaps Search"),
            callback=toggle_mosaics_search,
            add_to_menu=True,
            add_to_toolbar=True,
            parent=self.iface.mainWindow())

        self.showinspector_act = self.add_action(
            os.path.join(plugin_path, "resources", "inspector.svg"),
            text=self.tr("Show Planet Inspector..."),
            callback=toggle_inspector,
            add_to_menu=False,
            add_to_toolbar=True,
            parent=self.iface.mainWindow())

        self.showtasking_act = self.add_action(
            os.path.join(plugin_path, "resources", "tasking.svg"),
            text=self.tr("Show Tasking..."),
            callback=toggle_tasking_widget,
            add_to_menu=False,
            add_to_toolbar=True,
            parent=self.iface.mainWindow())

        self.add_central_toolbar_button()

        self.showorders_act = self.add_action(
            os.path.join(plugin_path, "resources", "orders.svg"),
            text=self.tr("Show Orders Monitor..."),
            callback=toggle_orders_monitor,
            add_to_menu=False,
            add_to_toolbar=True,
            parent=self.iface.mainWindow())

        self.add_user_button()
        self.add_info_button()

        addSettingsMenu(P_E, self.iface.addPluginToWebMenu)
        addAboutMenu(P_E, self.iface.addPluginToWebMenu)

        self.provider = BasemapLayerWidgetProvider()
        QgsGui.layerTreeEmbeddedWidgetRegistry().addProvider(self.provider)

        QgsProject.instance().projectSaved.connect(self.project_saved)
        QgsProject.instance().layersAdded.connect(self.layers_added)
        QgsProject.instance().layerRemoved.connect(self.layer_removed)

        PlanetClient.getInstance().loginChanged.connect(self.login_changed)

        self.enable_buttons(False)

    def add_central_toolbar_button(self):
        widget = QWidget()
        widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
        layout = QHBoxLayout()
        layout.addStretch()
        self.btnLogin = QPushButton()
        palette = self.btnLogin.palette()
        palette.setColor(QPalette.Button, PLANET_COLOR)
        self.btnLogin.setPalette(palette)
        self.btnLogin.setText("Log in")
        #self.btnLogin.setAutoRaise(True)
        self.btnLogin.setAttribute(Qt.WA_TranslucentBackground)
        self.btnLogin.clicked.connect(self.btn_login_clicked)
        icon = QIcon(os.path.join(plugin_path, "resources", "planet-logo-p.svg"))
        labelIcon = QLabel()
        labelIcon.setPixmap(icon.pixmap(QSize(16, 16)))
        layout.addWidget(labelIcon)
        self.labelLoggedIn = QLabel()
        self.labelLoggedIn.setText("")
        layout.addWidget(self.labelLoggedIn)
        layout.addWidget(self.btnLogin)
        layout.addStretch()
        widget.setLayout(layout)
        self.toolbar.addWidget(widget)

    def btn_login_clicked(self):
        if PlanetClient.getInstance().has_api_key():
            self.logout()
        else:
            self.login()

    def layer_removed(self, layer):
        self.provider.layerWasRemoved(layer)

    def layers_added(self, layers):
        for layer in layers:
            add_widget_to_layer(layer)

    def login_changed(self, loggedin):
        self.provider.updateLayerWidgets()
        self.enable_buttons(loggedin)
        if not loggedin:
            hide_orders_monitor()
            hide_inspector()

    def add_info_button(self):
        info_menu = QMenu()

        p_sec_act = add_menu_section_action('Planet', info_menu)

        p_com_act = QAction(QIcon(EXT_LINK),
                            'planet.com', info_menu)
        p_com_act.triggered[bool].connect(
            lambda: open_link_with_browser(PLANET_COM)
        )
        info_menu.addAction(p_com_act)

        p_explorer_act = QAction(QIcon(EXT_LINK),
                                 'Planet Explorer web app', info_menu)
        p_explorer_act.triggered[bool].connect(
            lambda: open_link_with_browser(PLANET_EXPLORER)
        )
        info_menu.addAction(p_explorer_act)

        p_sat_act = QAction(QIcon(EXT_LINK),
                            'Satellite specs PDF', info_menu)
        p_sat_act.triggered[bool].connect(
            lambda: open_link_with_browser(SAT_SPECS_PDF)
        )
        info_menu.addAction(p_sat_act)

        p_support_act = QAction(QIcon(EXT_LINK),
                                'Support Community', info_menu)
        p_support_act.triggered[bool].connect(
            lambda: open_link_with_browser(PLANET_SUPPORT_COMMUNITY)
        )
        info_menu.addAction(p_support_act)

        p_whatsnew_act = QAction(QIcon(EXT_LINK),
                                "What's new", info_menu)
        p_whatsnew_act.triggered[bool].connect(
            lambda: open_link_with_browser(PLANET_INTEGRATIONS)
        )
        info_menu.addAction(p_whatsnew_act)

        p_sales_act = QAction(QIcon(EXT_LINK),
                                "Sales", info_menu)
        p_sales_act.triggered[bool].connect(
            lambda: open_link_with_browser(PLANET_SALES)
        )
        info_menu.addAction(p_sales_act)

        add_menu_section_action('Documentation', info_menu)

        terms_act = QAction('Terms', info_menu)
        terms_act.triggered[bool].connect(self.show_terms)
        info_menu.addAction(terms_act)

        btn = QToolButton()
        btn.setIcon(QIcon(os.path.join(plugin_path, "resources", "info.svg"),))
        btn.setMenu(info_menu)

        btn.setPopupMode(QToolButton.MenuButtonPopup)
        # Also show menu on click, to keep disclosure triangle visible
        btn.clicked.connect(btn.showMenu)

        self.toolbar.addWidget(btn)

    def add_user_button(self):
        user_menu = QMenu()

        self.acct_act = QAction(QIcon(EXT_LINK),
                           'Account', user_menu)
        self.acct_act.triggered[bool].connect(
            lambda: QDesktopServices.openUrl(QUrl(ACCOUNT_URL))
        )
        user_menu.addAction(self.acct_act)

        self.logout_act = QAction('Logout', user_menu)
        self.logout_act.triggered[bool].connect(self.logout)
        user_menu.addAction(self.logout_act)

        self.user_button = QToolButton()
        self.user_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon);
        self.user_button.setIcon(QIcon(os.path.join(plugin_path, "resources", "account.svg"),))
        self.user_button.setMenu(user_menu)

        self.user_button.setPopupMode(QToolButton.MenuButtonPopup)
        # Also show menu on click, to keep disclosure triangle visible
        self.user_button.clicked.connect(self.user_button.showMenu)

        self.toolbar.addWidget(self.user_button)

    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""

        PlanetClient.getInstance().log_out()
        self.provider.updateLayerWidgets()

        removeSettingsMenu(P_E, self.iface.removePluginWebMenu)
        # removeHelpMenu(P_E, self.iface.removePluginWebMenu)
        removeAboutMenu(P_E, self.iface.removePluginWebMenu)

        for action in self.actions:
            self.iface.removePluginWebMenu(
                self.tr('&{0}'.format(P_E)), action)
            self.iface.removeToolBarIcon(action)

        # remove the toolbar
        if self.toolbar is not None:
            del self.toolbar

        remove_inspector()
        remove_explorer()
        remove_orders_monitor()
        remove_tasking_widget()

        sys.excepthook = self.qgis_hook

        QgsProject.instance().projectSaved.disconnect(self.project_saved)
        QgsProject.instance().layersAdded.disconnect(self.layers_added)
        QgsProject.instance().layerRemoved.disconnect(self.layer_removed)

    # -----------------------------------------------------------

    def show_terms(self, _):
        if self._terms_browser is None:
            self._terms_browser = QTextBrowser()
            self._terms_browser.setReadOnly(True)
            self._terms_browser.setOpenExternalLinks(True)
            self._terms_browser.setMinimumSize(600, 700)
            # TODO: Template terms.html first section, per subscription level
            #       Collect subscription info from self.p_client.user
            self._terms_browser.setSource(
                QUrl('qrc:/plugins/planet_explorer/terms.html'))
            self._terms_browser.setWindowModality(Qt.ApplicationModal)
        self._terms_browser.show()

    def login(self):
        show_explorer()

    def logout(self):
        PlanetClient.getInstance().log_out()

    def enable_buttons(self, loggedin):
        self.btnLogin.setVisible(not loggedin)
        labelText = (f"<b>Welcome to Planet</b>" if not loggedin else "<b>Planet</b>")
        self.labelLoggedIn.setText(labelText)
        self.showdailyimages_act.setEnabled(loggedin)
        self.showbasemaps_act.setEnabled(loggedin)
        self.showinspector_act.setEnabled(loggedin)
        self.showorders_act.setEnabled(loggedin)
        self.showtasking_act.setEnabled(loggedin)
        self.user_button.setEnabled(loggedin)
        self.user_button.setText(
            PlanetClient.getInstance().user()['user_name']
            if loggedin else "")
        if loggedin:
            self.showdailyimages_act.setToolTip("Show / Hide the Planet Imagery Search Panel")
            self.showbasemaps_act.setToolTip("Show / Hide the Planet Basemaps Search Panel")
            self.showorders_act.setToolTip("Show / Hide the Order Status Panel")
            self.showinspector_act.setToolTip("Show / Hide the Planet Inspector Panel")
            self.showtasking_act.setToolTip("Show / Hide the Tasking Panel")
        else:
            self.showdailyimages_act.setToolTip("Login to access Imagery Search")
            self.showbasemaps_act.setToolTip("Login to access Basemaps Search")
            self.showorders_act.setToolTip("Login to access Order Status")
            self.showinspector_act.setToolTip("Login to access Planet Inspector")
            self.showtasking_act.setToolTip("Login to access Tasking Panel")

    def project_saved(self):
        if PlanetClient.getInstance().has_api_key():
            def resave():
                path = QgsProject.instance().absoluteFilePath()
                if path.lower().endswith(".qgs"):
                    with open(path) as f:
                        s = f.read()
                    with open(path, "w") as f:
                        f.write(s.replace(PlanetClient.getInstance().api_key(), ""))
                else:
                    tmpfilename = path + ".temp"
                    qgsfilename = os.path.splitext(os.path.basename(path))[0] + ".qgs"
                    with zipfile.ZipFile(path, 'r') as zin:
                        with zipfile.ZipFile(tmpfilename, 'w') as zout:
                            zout.comment = zin.comment
                            for item in zin.infolist():
                                if not item.filename.lower().endswith(".qgs"):
                                    zout.writestr(item, zin.read(item.filename))
                                else:
                                    s = zin.read(item.filename).decode("utf-8")
                                    s = s.replace(PlanetClient.getInstance().api_key(), "")
                                    qgsfilename = item.filename
                    os.remove(path)
                    os.rename(tmpfilename, path)
                    with zipfile.ZipFile(path, mode='a', compression=zipfile.ZIP_DEFLATED) as zf:
                        zf.writestr(qgsfilename, s)
            QTimer.singleShot(100, resave)
コード例 #28
0
class ModelerDialog(BASE, WIDGET):
    ALG_ITEM = 'ALG_ITEM'
    PROVIDER_ITEM = 'PROVIDER_ITEM'
    GROUP_ITEM = 'GROUP_ITEM'

    NAME_ROLE = Qt.UserRole
    TAG_ROLE = Qt.UserRole + 1
    TYPE_ROLE = Qt.UserRole + 2

    CANVAS_SIZE = 4000

    update_model = pyqtSignal()

    def __init__(self, model=None):
        super().__init__(None)
        self.setAttribute(Qt.WA_DeleteOnClose)

        self.setupUi(self)

        self._variables_scope = None

        # LOTS of bug reports when we include the dock creation in the UI file
        # see e.g. #16428, #19068
        # So just roll it all by hand......!
        self.propertiesDock = QgsDockWidget(self)
        self.propertiesDock.setFeatures(QDockWidget.DockWidgetFloatable
                                        | QDockWidget.DockWidgetMovable)
        self.propertiesDock.setObjectName("propertiesDock")
        propertiesDockContents = QWidget()
        self.verticalDockLayout_1 = QVBoxLayout(propertiesDockContents)
        self.verticalDockLayout_1.setContentsMargins(0, 0, 0, 0)
        self.verticalDockLayout_1.setSpacing(0)
        self.scrollArea_1 = QgsScrollArea(propertiesDockContents)
        sizePolicy = QSizePolicy(QSizePolicy.MinimumExpanding,
                                 QSizePolicy.MinimumExpanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.scrollArea_1.sizePolicy().hasHeightForWidth())
        self.scrollArea_1.setSizePolicy(sizePolicy)
        self.scrollArea_1.setFocusPolicy(Qt.WheelFocus)
        self.scrollArea_1.setFrameShape(QFrame.NoFrame)
        self.scrollArea_1.setFrameShadow(QFrame.Plain)
        self.scrollArea_1.setWidgetResizable(True)
        self.scrollAreaWidgetContents_1 = QWidget()
        self.gridLayout = QGridLayout(self.scrollAreaWidgetContents_1)
        self.gridLayout.setContentsMargins(6, 6, 6, 6)
        self.gridLayout.setSpacing(4)
        self.label_1 = QLabel(self.scrollAreaWidgetContents_1)
        self.gridLayout.addWidget(self.label_1, 0, 0, 1, 1)
        self.textName = QLineEdit(self.scrollAreaWidgetContents_1)
        self.gridLayout.addWidget(self.textName, 0, 1, 1, 1)
        self.label_2 = QLabel(self.scrollAreaWidgetContents_1)
        self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1)
        self.textGroup = QLineEdit(self.scrollAreaWidgetContents_1)
        self.gridLayout.addWidget(self.textGroup, 1, 1, 1, 1)
        self.label_1.setText(self.tr("Name"))
        self.textName.setToolTip(self.tr("Enter model name here"))
        self.label_2.setText(self.tr("Group"))
        self.textGroup.setToolTip(self.tr("Enter group name here"))
        self.scrollArea_1.setWidget(self.scrollAreaWidgetContents_1)
        self.verticalDockLayout_1.addWidget(self.scrollArea_1)
        self.propertiesDock.setWidget(propertiesDockContents)
        self.propertiesDock.setWindowTitle(self.tr("Model Properties"))

        self.inputsDock = QgsDockWidget(self)
        self.inputsDock.setFeatures(QDockWidget.DockWidgetFloatable
                                    | QDockWidget.DockWidgetMovable)
        self.inputsDock.setObjectName("inputsDock")
        self.inputsDockContents = QWidget()
        self.verticalLayout_3 = QVBoxLayout(self.inputsDockContents)
        self.verticalLayout_3.setContentsMargins(0, 0, 0, 0)
        self.scrollArea_2 = QgsScrollArea(self.inputsDockContents)
        sizePolicy.setHeightForWidth(
            self.scrollArea_2.sizePolicy().hasHeightForWidth())
        self.scrollArea_2.setSizePolicy(sizePolicy)
        self.scrollArea_2.setFocusPolicy(Qt.WheelFocus)
        self.scrollArea_2.setFrameShape(QFrame.NoFrame)
        self.scrollArea_2.setFrameShadow(QFrame.Plain)
        self.scrollArea_2.setWidgetResizable(True)
        self.scrollAreaWidgetContents_2 = QWidget()
        self.verticalLayout = QVBoxLayout(self.scrollAreaWidgetContents_2)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout.setSpacing(0)
        self.inputsTree = QTreeWidget(self.scrollAreaWidgetContents_2)
        self.inputsTree.setAlternatingRowColors(True)
        self.inputsTree.header().setVisible(False)
        self.verticalLayout.addWidget(self.inputsTree)
        self.scrollArea_2.setWidget(self.scrollAreaWidgetContents_2)
        self.verticalLayout_3.addWidget(self.scrollArea_2)
        self.inputsDock.setWidget(self.inputsDockContents)
        self.addDockWidget(Qt.DockWidgetArea(1), self.inputsDock)
        self.inputsDock.setWindowTitle(self.tr("Inputs"))

        self.algorithmsDock = QgsDockWidget(self)
        self.algorithmsDock.setFeatures(QDockWidget.DockWidgetFloatable
                                        | QDockWidget.DockWidgetMovable)
        self.algorithmsDock.setObjectName("algorithmsDock")
        self.algorithmsDockContents = QWidget()
        self.verticalLayout_4 = QVBoxLayout(self.algorithmsDockContents)
        self.verticalLayout_4.setContentsMargins(0, 0, 0, 0)
        self.scrollArea_3 = QgsScrollArea(self.algorithmsDockContents)
        sizePolicy.setHeightForWidth(
            self.scrollArea_3.sizePolicy().hasHeightForWidth())
        self.scrollArea_3.setSizePolicy(sizePolicy)
        self.scrollArea_3.setFocusPolicy(Qt.WheelFocus)
        self.scrollArea_3.setFrameShape(QFrame.NoFrame)
        self.scrollArea_3.setFrameShadow(QFrame.Plain)
        self.scrollArea_3.setWidgetResizable(True)
        self.scrollAreaWidgetContents_3 = QWidget()
        self.verticalLayout_2 = QVBoxLayout(self.scrollAreaWidgetContents_3)
        self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout_2.setSpacing(4)
        self.searchBox = QgsFilterLineEdit(self.scrollAreaWidgetContents_3)
        self.verticalLayout_2.addWidget(self.searchBox)
        self.algorithmTree = QgsProcessingToolboxTreeView(
            None, QgsApplication.processingRegistry())
        self.algorithmTree.setAlternatingRowColors(True)
        self.algorithmTree.header().setVisible(False)
        self.verticalLayout_2.addWidget(self.algorithmTree)
        self.scrollArea_3.setWidget(self.scrollAreaWidgetContents_3)
        self.verticalLayout_4.addWidget(self.scrollArea_3)
        self.algorithmsDock.setWidget(self.algorithmsDockContents)
        self.addDockWidget(Qt.DockWidgetArea(1), self.algorithmsDock)
        self.algorithmsDock.setWindowTitle(self.tr("Algorithms"))
        self.searchBox.setToolTip(
            self.tr("Enter algorithm name to filter list"))
        self.searchBox.setShowSearchIcon(True)

        self.variables_dock = QgsDockWidget(self)
        self.variables_dock.setFeatures(QDockWidget.DockWidgetFloatable
                                        | QDockWidget.DockWidgetMovable)
        self.variables_dock.setObjectName("variablesDock")
        self.variables_dock_contents = QWidget()
        vl_v = QVBoxLayout()
        vl_v.setContentsMargins(0, 0, 0, 0)
        self.variables_editor = QgsVariableEditorWidget()
        vl_v.addWidget(self.variables_editor)
        self.variables_dock_contents.setLayout(vl_v)
        self.variables_dock.setWidget(self.variables_dock_contents)
        self.addDockWidget(Qt.DockWidgetArea(1), self.variables_dock)
        self.variables_dock.setWindowTitle(self.tr("Variables"))
        self.addDockWidget(Qt.DockWidgetArea(1), self.propertiesDock)
        self.tabifyDockWidget(self.propertiesDock, self.variables_dock)
        self.variables_editor.scopeChanged.connect(self.variables_changed)

        self.bar = QgsMessageBar()
        self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        self.centralWidget().layout().insertWidget(0, self.bar)

        try:
            self.setDockOptions(self.dockOptions()
                                | QMainWindow.GroupedDragging)
        except:
            pass

        if iface is not None:
            self.mToolbar.setIconSize(iface.iconSize())
            self.setStyleSheet(iface.mainWindow().styleSheet())

        self.toolbutton_export_to_script = QToolButton()
        self.toolbutton_export_to_script.setPopupMode(QToolButton.InstantPopup)
        self.export_to_script_algorithm_action = QAction(
            QCoreApplication.translate('ModelerDialog',
                                       'Export as Script Algorithm…'))
        self.toolbutton_export_to_script.addActions(
            [self.export_to_script_algorithm_action])
        self.mToolbar.insertWidget(self.mActionExportImage,
                                   self.toolbutton_export_to_script)
        self.export_to_script_algorithm_action.triggered.connect(
            self.export_as_script_algorithm)

        self.mActionOpen.setIcon(
            QgsApplication.getThemeIcon('/mActionFileOpen.svg'))
        self.mActionSave.setIcon(
            QgsApplication.getThemeIcon('/mActionFileSave.svg'))
        self.mActionSaveAs.setIcon(
            QgsApplication.getThemeIcon('/mActionFileSaveAs.svg'))
        self.mActionSaveInProject.setIcon(
            QgsApplication.getThemeIcon('/mAddToProject.svg'))
        self.mActionZoomActual.setIcon(
            QgsApplication.getThemeIcon('/mActionZoomActual.svg'))
        self.mActionZoomIn.setIcon(
            QgsApplication.getThemeIcon('/mActionZoomIn.svg'))
        self.mActionZoomOut.setIcon(
            QgsApplication.getThemeIcon('/mActionZoomOut.svg'))
        self.mActionExportImage.setIcon(
            QgsApplication.getThemeIcon('/mActionSaveMapAsImage.svg'))
        self.mActionZoomToItems.setIcon(
            QgsApplication.getThemeIcon('/mActionZoomFullExtent.svg'))
        self.mActionExportPdf.setIcon(
            QgsApplication.getThemeIcon('/mActionSaveAsPDF.svg'))
        self.mActionExportSvg.setIcon(
            QgsApplication.getThemeIcon('/mActionSaveAsSVG.svg'))
        self.toolbutton_export_to_script.setIcon(
            QgsApplication.getThemeIcon('/mActionSaveAsPython.svg'))
        self.mActionEditHelp.setIcon(
            QgsApplication.getThemeIcon('/mActionEditHelpContent.svg'))
        self.mActionRun.setIcon(
            QgsApplication.getThemeIcon('/mActionStart.svg'))

        self.addDockWidget(Qt.LeftDockWidgetArea, self.propertiesDock)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.inputsDock)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.algorithmsDock)
        self.tabifyDockWidget(self.inputsDock, self.algorithmsDock)
        self.inputsDock.raise_()

        self.setWindowFlags(Qt.WindowMinimizeButtonHint
                            | Qt.WindowMaximizeButtonHint
                            | Qt.WindowCloseButtonHint)

        settings = QgsSettings()
        self.restoreState(
            settings.value("/Processing/stateModeler", QByteArray()))
        self.restoreGeometry(
            settings.value("/Processing/geometryModeler", QByteArray()))

        self.scene = ModelerScene(self, dialog=self)
        self.scene.setSceneRect(
            QRectF(0, 0, self.CANVAS_SIZE, self.CANVAS_SIZE))

        self.view.setScene(self.scene)
        self.view.setAcceptDrops(True)
        self.view.ensureVisible(0, 0, 10, 10)
        self.view.scale(QgsApplication.desktop().logicalDpiX() / 96,
                        QgsApplication.desktop().logicalDpiX() / 96)

        def _dragEnterEvent(event):
            if event.mimeData().hasText() or event.mimeData().hasFormat(
                    'application/x-vnd.qgis.qgis.algorithmid'):
                event.acceptProposedAction()
            else:
                event.ignore()

        def _dropEvent(event):
            def alg_dropped(algorithm_id, pos):
                alg = QgsApplication.processingRegistry().createAlgorithmById(
                    algorithm_id)
                if alg is not None:
                    self._addAlgorithm(alg, pos)
                else:
                    assert False, algorithm_id

            def input_dropped(id, pos):
                if id in [
                        param.id() for param in QgsApplication.instance().
                        processingRegistry().parameterTypes()
                ]:
                    self.addInputOfType(itemId, pos)

            if event.mimeData().hasFormat(
                    'application/x-vnd.qgis.qgis.algorithmid'):
                data = event.mimeData().data(
                    'application/x-vnd.qgis.qgis.algorithmid')
                stream = QDataStream(data, QIODevice.ReadOnly)
                algorithm_id = stream.readQString()
                QTimer.singleShot(
                    0,
                    lambda id=algorithm_id, pos=self.view.mapToScene(event.pos(
                    )): alg_dropped(id, pos))
                event.accept()
            elif event.mimeData().hasText():
                itemId = event.mimeData().text()
                QTimer.singleShot(0,
                                  lambda id=itemId, pos=self.view.mapToScene(
                                      event.pos()): input_dropped(id, pos))
                event.accept()
            else:
                event.ignore()

        def _dragMoveEvent(event):
            if event.mimeData().hasText() or event.mimeData().hasFormat(
                    'application/x-vnd.qgis.qgis.algorithmid'):
                event.accept()
            else:
                event.ignore()

        def _wheelEvent(event):
            self.view.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)

            settings = QgsSettings()
            factor = settings.value('/qgis/zoom_favor', 2.0)

            # "Normal" mouse has an angle delta of 120, precision mouses provide data
            # faster, in smaller steps
            factor = 1.0 + (factor - 1.0) / 120.0 * abs(event.angleDelta().y())

            if (event.modifiers() == Qt.ControlModifier):
                factor = 1.0 + (factor - 1.0) / 20.0

            if event.angleDelta().y() < 0:
                factor = 1 / factor

            self.view.scale(factor, factor)

        def _enterEvent(e):
            QGraphicsView.enterEvent(self.view, e)
            self.view.viewport().setCursor(Qt.ArrowCursor)

        def _mouseReleaseEvent(e):
            QGraphicsView.mouseReleaseEvent(self.view, e)
            self.view.viewport().setCursor(Qt.ArrowCursor)

        def _mousePressEvent(e):
            if e.button() == Qt.MidButton:
                self.previousMousePos = e.pos()
            else:
                QGraphicsView.mousePressEvent(self.view, e)

        def _mouseMoveEvent(e):
            if e.buttons() == Qt.MidButton:
                offset = self.previousMousePos - e.pos()
                self.previousMousePos = e.pos()

                self.view.verticalScrollBar().setValue(
                    self.view.verticalScrollBar().value() + offset.y())
                self.view.horizontalScrollBar().setValue(
                    self.view.horizontalScrollBar().value() + offset.x())
            else:
                QGraphicsView.mouseMoveEvent(self.view, e)

        self.view.setDragMode(QGraphicsView.ScrollHandDrag)
        self.view.dragEnterEvent = _dragEnterEvent
        self.view.dropEvent = _dropEvent
        self.view.dragMoveEvent = _dragMoveEvent
        self.view.wheelEvent = _wheelEvent
        self.view.enterEvent = _enterEvent
        self.view.mousePressEvent = _mousePressEvent
        self.view.mouseMoveEvent = _mouseMoveEvent

        def _mimeDataInput(items):
            mimeData = QMimeData()
            text = items[0].data(0, Qt.UserRole)
            mimeData.setText(text)
            return mimeData

        self.inputsTree.mimeData = _mimeDataInput

        self.inputsTree.setDragDropMode(QTreeWidget.DragOnly)
        self.inputsTree.setDropIndicatorShown(True)

        self.algorithms_model = ModelerToolboxModel(
            self, QgsApplication.processingRegistry())
        self.algorithmTree.setToolboxProxyModel(self.algorithms_model)
        self.algorithmTree.setDragDropMode(QTreeWidget.DragOnly)
        self.algorithmTree.setDropIndicatorShown(True)

        filters = QgsProcessingToolboxProxyModel.Filters(
            QgsProcessingToolboxProxyModel.FilterModeler)
        if ProcessingConfig.getSetting(
                ProcessingConfig.SHOW_ALGORITHMS_KNOWN_ISSUES):
            filters |= QgsProcessingToolboxProxyModel.FilterShowKnownIssues
        self.algorithmTree.setFilters(filters)

        if hasattr(self.searchBox, 'setPlaceholderText'):
            self.searchBox.setPlaceholderText(
                QCoreApplication.translate('ModelerDialog', 'Search…'))
        if hasattr(self.textName, 'setPlaceholderText'):
            self.textName.setPlaceholderText(self.tr('Enter model name here'))
        if hasattr(self.textGroup, 'setPlaceholderText'):
            self.textGroup.setPlaceholderText(self.tr('Enter group name here'))

        # Connect signals and slots
        self.inputsTree.doubleClicked.connect(self.addInput)
        self.searchBox.textChanged.connect(self.algorithmTree.setFilterString)
        self.algorithmTree.doubleClicked.connect(self.addAlgorithm)

        # Ctrl+= should also trigger a zoom in action
        ctrlEquals = QShortcut(QKeySequence("Ctrl+="), self)
        ctrlEquals.activated.connect(self.zoomIn)

        self.mActionOpen.triggered.connect(self.openModel)
        self.mActionSave.triggered.connect(self.save)
        self.mActionSaveAs.triggered.connect(self.saveAs)
        self.mActionSaveInProject.triggered.connect(self.saveInProject)
        self.mActionZoomIn.triggered.connect(self.zoomIn)
        self.mActionZoomOut.triggered.connect(self.zoomOut)
        self.mActionZoomActual.triggered.connect(self.zoomActual)
        self.mActionZoomToItems.triggered.connect(self.zoomToItems)
        self.mActionExportImage.triggered.connect(self.exportAsImage)
        self.mActionExportPdf.triggered.connect(self.exportAsPdf)
        self.mActionExportSvg.triggered.connect(self.exportAsSvg)
        #self.mActionExportPython.triggered.connect(self.exportAsPython)
        self.mActionEditHelp.triggered.connect(self.editHelp)
        self.mActionRun.triggered.connect(self.runModel)

        if model is not None:
            self.model = model.create()
            self.model.setSourceFilePath(model.sourceFilePath())
            self.textGroup.setText(self.model.group())
            self.textName.setText(self.model.displayName())
            self.repaintModel()

        else:
            self.model = QgsProcessingModelAlgorithm()
            self.model.setProvider(
                QgsApplication.processingRegistry().providerById('model'))
        self.update_variables_gui()

        self.fillInputsTree()

        self.view.centerOn(0, 0)
        self.help = None

        self.hasChanged = False

    def closeEvent(self, evt):
        settings = QgsSettings()
        settings.setValue("/Processing/stateModeler", self.saveState())
        settings.setValue("/Processing/geometryModeler", self.saveGeometry())

        if self.hasChanged:
            ret = QMessageBox.question(
                self, self.tr('Save Model?'),
                self.
                tr('There are unsaved changes in this model. Do you want to keep those?'
                   ),
                QMessageBox.Save | QMessageBox.Cancel | QMessageBox.Discard,
                QMessageBox.Cancel)

            if ret == QMessageBox.Save:
                self.saveModel(False)
                evt.accept()
            elif ret == QMessageBox.Discard:
                evt.accept()
            else:
                evt.ignore()
        else:
            evt.accept()

    def editHelp(self):
        alg = self.model
        dlg = HelpEditionDialog(alg)
        dlg.exec_()
        if dlg.descriptions:
            self.model.setHelpContent(dlg.descriptions)
            self.hasChanged = True

    def update_variables_gui(self):
        variables_scope = QgsExpressionContextScope(self.tr('Model Variables'))
        for k, v in self.model.variables().items():
            variables_scope.setVariable(k, v)
        variables_context = QgsExpressionContext()
        variables_context.appendScope(variables_scope)
        self.variables_editor.setContext(variables_context)
        self.variables_editor.setEditableScopeIndex(0)

    def variables_changed(self):
        self.model.setVariables(self.variables_editor.variablesInActiveScope())

    def runModel(self):
        if len(self.model.childAlgorithms()) == 0:
            self.bar.pushMessage(
                "",
                self.
                tr("Model doesn't contain any algorithm and/or parameter and can't be executed"
                   ),
                level=Qgis.Warning,
                duration=5)
            return

        dlg = AlgorithmDialog(self.model.create(), parent=iface.mainWindow())
        dlg.exec_()

    def save(self):
        self.saveModel(False)

    def saveAs(self):
        self.saveModel(True)

    def saveInProject(self):
        if not self.can_save():
            return

        self.model.setName(str(self.textName.text()))
        self.model.setGroup(str(self.textGroup.text()))
        self.model.setSourceFilePath(None)

        project_provider = QgsApplication.processingRegistry().providerById(
            PROJECT_PROVIDER_ID)
        project_provider.add_model(self.model)

        self.update_model.emit()
        self.bar.pushMessage("",
                             self.tr("Model was saved inside current project"),
                             level=Qgis.Success,
                             duration=5)

        self.hasChanged = False
        QgsProject.instance().setDirty(True)

    def zoomIn(self):
        self.view.setTransformationAnchor(QGraphicsView.NoAnchor)
        point = self.view.mapToScene(
            QPoint(self.view.viewport().width() / 2,
                   self.view.viewport().height() / 2))

        settings = QgsSettings()
        factor = settings.value('/qgis/zoom_favor', 2.0)

        self.view.scale(factor, factor)
        self.view.centerOn(point)
        self.repaintModel()

    def zoomOut(self):
        self.view.setTransformationAnchor(QGraphicsView.NoAnchor)
        point = self.view.mapToScene(
            QPoint(self.view.viewport().width() / 2,
                   self.view.viewport().height() / 2))

        settings = QgsSettings()
        factor = settings.value('/qgis/zoom_favor', 2.0)
        factor = 1 / factor

        self.view.scale(factor, factor)
        self.view.centerOn(point)
        self.repaintModel()

    def zoomActual(self):
        point = self.view.mapToScene(
            QPoint(self.view.viewport().width() / 2,
                   self.view.viewport().height() / 2))
        self.view.resetTransform()
        self.view.scale(QgsApplication.desktop().logicalDpiX() / 96,
                        QgsApplication.desktop().logicalDpiX() / 96)
        self.view.centerOn(point)

    def zoomToItems(self):
        totalRect = self.scene.itemsBoundingRect()
        totalRect.adjust(-10, -10, 10, 10)
        self.view.fitInView(totalRect, Qt.KeepAspectRatio)

    def exportAsImage(self):
        self.repaintModel(controls=False)
        filename, fileFilter = QFileDialog.getSaveFileName(
            self, self.tr('Save Model As Image'), '',
            self.tr('PNG files (*.png *.PNG)'))
        if not filename:
            return

        if not filename.lower().endswith('.png'):
            filename += '.png'

        totalRect = self.scene.itemsBoundingRect()
        totalRect.adjust(-10, -10, 10, 10)
        imgRect = QRectF(0, 0, totalRect.width(), totalRect.height())

        img = QImage(totalRect.width(), totalRect.height(),
                     QImage.Format_ARGB32_Premultiplied)
        img.fill(Qt.white)
        painter = QPainter()
        painter.setRenderHint(QPainter.Antialiasing)
        painter.begin(img)
        self.scene.render(painter, imgRect, totalRect)
        painter.end()

        img.save(filename)

        self.bar.pushMessage(
            "",
            self.tr(
                "Successfully exported model as image to <a href=\"{}\">{}</a>"
            ).format(
                QUrl.fromLocalFile(filename).toString(),
                QDir.toNativeSeparators(filename)),
            level=Qgis.Success,
            duration=5)
        self.repaintModel(controls=True)

    def exportAsPdf(self):
        self.repaintModel(controls=False)
        filename, fileFilter = QFileDialog.getSaveFileName(
            self, self.tr('Save Model As PDF'), '',
            self.tr('PDF files (*.pdf *.PDF)'))
        if not filename:
            return

        if not filename.lower().endswith('.pdf'):
            filename += '.pdf'

        totalRect = self.scene.itemsBoundingRect()
        totalRect.adjust(-10, -10, 10, 10)
        printerRect = QRectF(0, 0, totalRect.width(), totalRect.height())

        printer = QPrinter()
        printer.setOutputFormat(QPrinter.PdfFormat)
        printer.setOutputFileName(filename)
        printer.setPaperSize(QSizeF(printerRect.width(), printerRect.height()),
                             QPrinter.DevicePixel)
        printer.setFullPage(True)

        painter = QPainter(printer)
        self.scene.render(painter, printerRect, totalRect)
        painter.end()

        self.bar.pushMessage(
            "",
            self.tr(
                "Successfully exported model as PDF to <a href=\"{}\">{}</a>").
            format(
                QUrl.fromLocalFile(filename).toString(),
                QDir.toNativeSeparators(filename)),
            level=Qgis.Success,
            duration=5)
        self.repaintModel(controls=True)

    def exportAsSvg(self):
        self.repaintModel(controls=False)
        filename, fileFilter = QFileDialog.getSaveFileName(
            self, self.tr('Save Model As SVG'), '',
            self.tr('SVG files (*.svg *.SVG)'))
        if not filename:
            return

        if not filename.lower().endswith('.svg'):
            filename += '.svg'

        totalRect = self.scene.itemsBoundingRect()
        totalRect.adjust(-10, -10, 10, 10)
        svgRect = QRectF(0, 0, totalRect.width(), totalRect.height())

        svg = QSvgGenerator()
        svg.setFileName(filename)
        svg.setSize(QSize(totalRect.width(), totalRect.height()))
        svg.setViewBox(svgRect)
        svg.setTitle(self.model.displayName())

        painter = QPainter(svg)
        self.scene.render(painter, svgRect, totalRect)
        painter.end()

        self.bar.pushMessage(
            "",
            self.tr(
                "Successfully exported model as SVG to <a href=\"{}\">{}</a>").
            format(
                QUrl.fromLocalFile(filename).toString(),
                QDir.toNativeSeparators(filename)),
            level=Qgis.Success,
            duration=5)
        self.repaintModel(controls=True)

    def exportAsPython(self):
        filename, filter = QFileDialog.getSaveFileName(
            self, self.tr('Save Model As Python Script'), '',
            self.tr('Processing scripts (*.py *.PY)'))
        if not filename:
            return

        if not filename.lower().endswith('.py'):
            filename += '.py'

        text = self.model.asPythonCode()
        with codecs.open(filename, 'w', encoding='utf-8') as fout:
            fout.write(text)

        self.bar.pushMessage(
            "",
            self.
            tr("Successfully exported model as python script to <a href=\"{}\">{}</a>"
               ).format(
                   QUrl.fromLocalFile(filename).toString(),
                   QDir.toNativeSeparators(filename)),
            level=Qgis.Success,
            duration=5)

    def can_save(self):
        """
        Tests whether a model can be saved, or if it is not yet valid
        :return: bool
        """
        if str(self.textName.text()).strip() == '':
            self.bar.pushWarning(
                "", self.tr('Please a enter model name before saving'))
            return False

        return True

    def saveModel(self, saveAs):
        if not self.can_save():
            return
        self.model.setName(str(self.textName.text()))
        self.model.setGroup(str(self.textGroup.text()))
        if self.model.sourceFilePath() and not saveAs:
            filename = self.model.sourceFilePath()
        else:
            filename, filter = QFileDialog.getSaveFileName(
                self, self.tr('Save Model'),
                ModelerUtils.modelsFolders()[0],
                self.tr('Processing models (*.model3 *.MODEL3)'))
            if filename:
                if not filename.endswith('.model3'):
                    filename += '.model3'
                self.model.setSourceFilePath(filename)
        if filename:
            if not self.model.toFile(filename):
                if saveAs:
                    QMessageBox.warning(
                        self, self.tr('I/O error'),
                        self.tr('Unable to save edits. Reason:\n {0}').format(
                            str(sys.exc_info()[1])))
                else:
                    QMessageBox.warning(
                        self, self.tr("Can't save model"),
                        QCoreApplication.
                        translate('QgsPluginInstallerInstallingDialog', (
                            "This model can't be saved in its original location (probably you do not "
                            "have permission to do it). Please, use the 'Save as…' option."
                        )))
                return
            self.update_model.emit()
            if saveAs:
                self.bar.pushMessage(
                    "",
                    self.tr(
                        "Model was correctly saved to <a href=\"{}\">{}</a>").
                    format(
                        QUrl.fromLocalFile(filename).toString(),
                        QDir.toNativeSeparators(filename)),
                    level=Qgis.Success,
                    duration=5)
            else:
                self.bar.pushMessage("",
                                     self.tr("Model was correctly saved"),
                                     level=Qgis.Success,
                                     duration=5)

            self.hasChanged = False

    def openModel(self):
        filename, selected_filter = QFileDialog.getOpenFileName(
            self, self.tr('Open Model'),
            ModelerUtils.modelsFolders()[0],
            self.tr('Processing models (*.model3 *.MODEL3)'))
        if filename:
            self.loadModel(filename)

    def loadModel(self, filename):
        alg = QgsProcessingModelAlgorithm()
        if alg.fromFile(filename):
            self.model = alg
            self.model.setProvider(
                QgsApplication.processingRegistry().providerById('model'))
            self.textGroup.setText(alg.group())
            self.textName.setText(alg.name())
            self.repaintModel()

            self.update_variables_gui()

            self.view.centerOn(0, 0)
            self.hasChanged = False
        else:
            QgsMessageLog.logMessage(
                self.tr('Could not load model {0}').format(filename),
                self.tr('Processing'), Qgis.Critical)
            QMessageBox.critical(
                self, self.tr('Open Model'),
                self.tr('The selected model could not be loaded.\n'
                        'See the log for more information.'))

    def repaintModel(self, controls=True):
        self.scene = ModelerScene(self, dialog=self)
        self.scene.setSceneRect(
            QRectF(0, 0, self.CANVAS_SIZE, self.CANVAS_SIZE))
        self.scene.paintModel(self.model, controls)
        self.view.setScene(self.scene)

    def addInput(self):
        item = self.inputsTree.currentItem()
        param = item.data(0, Qt.UserRole)
        self.addInputOfType(param)

    def addInputOfType(self, paramType, pos=None):
        dlg = ModelerParameterDefinitionDialog(self.model, paramType)
        dlg.exec_()
        if dlg.param is not None:
            if pos is None:
                pos = self.getPositionForParameterItem()
            if isinstance(pos, QPoint):
                pos = QPointF(pos)
            component = QgsProcessingModelParameter(dlg.param.name())
            component.setDescription(dlg.param.name())
            component.setPosition(pos)
            self.model.addModelParameter(dlg.param, component)
            self.repaintModel()
            # self.view.ensureVisible(self.scene.getLastParameterItem())
            self.hasChanged = True

    def getPositionForParameterItem(self):
        MARGIN = 20
        BOX_WIDTH = 200
        BOX_HEIGHT = 80
        if len(self.model.parameterComponents()) > 0:
            maxX = max([
                i.position().x()
                for i in list(self.model.parameterComponents().values())
            ])
            newX = min(MARGIN + BOX_WIDTH + maxX, self.CANVAS_SIZE - BOX_WIDTH)
        else:
            newX = MARGIN + BOX_WIDTH / 2
        return QPointF(newX, MARGIN + BOX_HEIGHT / 2)

    def fillInputsTree(self):
        icon = QIcon(os.path.join(pluginPath, 'images', 'input.svg'))
        parametersItem = QTreeWidgetItem()
        parametersItem.setText(0, self.tr('Parameters'))
        sortedParams = sorted(
            QgsApplication.instance().processingRegistry().parameterTypes(),
            key=lambda pt: pt.name())
        for param in sortedParams:
            if param.flags() & QgsProcessingParameterType.ExposeToModeler:
                paramItem = QTreeWidgetItem()
                paramItem.setText(0, param.name())
                paramItem.setData(0, Qt.UserRole, param.id())
                paramItem.setIcon(0, icon)
                paramItem.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable
                                   | Qt.ItemIsDragEnabled)
                paramItem.setToolTip(0, param.description())
                parametersItem.addChild(paramItem)
        self.inputsTree.addTopLevelItem(parametersItem)
        parametersItem.setExpanded(True)

    def addAlgorithm(self):
        algorithm = self.algorithmTree.selectedAlgorithm()
        if algorithm is not None:
            alg = QgsApplication.processingRegistry().createAlgorithmById(
                algorithm.id())
            self._addAlgorithm(alg)

    def _addAlgorithm(self, alg, pos=None):
        dlg = ModelerParametersDialog(alg, self.model)
        if dlg.exec_():
            alg = dlg.createAlgorithm()
            if pos is None:
                alg.setPosition(self.getPositionForAlgorithmItem())
            else:
                alg.setPosition(pos)
            from processing.modeler.ModelerGraphicItem import ModelerGraphicItem
            for i, out in enumerate(alg.modelOutputs()):
                alg.modelOutput(out).setPosition(
                    alg.position() +
                    QPointF(ModelerGraphicItem.BOX_WIDTH, (i + 1.5) *
                            ModelerGraphicItem.BOX_HEIGHT))
            self.model.addChildAlgorithm(alg)
            self.repaintModel()
            self.hasChanged = True

    def getPositionForAlgorithmItem(self):
        MARGIN = 20
        BOX_WIDTH = 200
        BOX_HEIGHT = 80
        if self.model.childAlgorithms():
            maxX = max([
                alg.position().x()
                for alg in list(self.model.childAlgorithms().values())
            ])
            maxY = max([
                alg.position().y()
                for alg in list(self.model.childAlgorithms().values())
            ])
            newX = min(MARGIN + BOX_WIDTH + maxX, self.CANVAS_SIZE - BOX_WIDTH)
            newY = min(MARGIN + BOX_HEIGHT + maxY,
                       self.CANVAS_SIZE - BOX_HEIGHT)
        else:
            newX = MARGIN + BOX_WIDTH / 2
            newY = MARGIN * 2 + BOX_HEIGHT + BOX_HEIGHT / 2
        return QPointF(newX, newY)

    def export_as_script_algorithm(self):
        dlg = ScriptEditorDialog(None)

        dlg.editor.setText('\n'.join(
            self.model.asPythonCode(
                QgsProcessing.PythonQgsProcessingAlgorithmSubclass, 4)))
        dlg.show()
コード例 #29
0
    def add_info_button(self):
        info_menu = QMenu()

        p_sec_act = add_menu_section_action('Planet', info_menu)

        p_com_act = QAction(QIcon(EXT_LINK),
                            'planet.com', info_menu)
        p_com_act.triggered[bool].connect(
            lambda: open_link_with_browser(PLANET_COM)
        )
        info_menu.addAction(p_com_act)

        p_explorer_act = QAction(QIcon(EXT_LINK),
                                 'Planet Explorer web app', info_menu)
        p_explorer_act.triggered[bool].connect(
            lambda: open_link_with_browser(PLANET_EXPLORER)
        )
        info_menu.addAction(p_explorer_act)

        p_sat_act = QAction(QIcon(EXT_LINK),
                            'Satellite specs PDF', info_menu)
        p_sat_act.triggered[bool].connect(
            lambda: open_link_with_browser(SAT_SPECS_PDF)
        )
        info_menu.addAction(p_sat_act)

        p_support_act = QAction(QIcon(EXT_LINK),
                                'Support Community', info_menu)
        p_support_act.triggered[bool].connect(
            lambda: open_link_with_browser(PLANET_SUPPORT_COMMUNITY)
        )
        info_menu.addAction(p_support_act)

        p_whatsnew_act = QAction(QIcon(EXT_LINK),
                                "What's new", info_menu)
        p_whatsnew_act.triggered[bool].connect(
            lambda: open_link_with_browser(PLANET_INTEGRATIONS)
        )
        info_menu.addAction(p_whatsnew_act)

        p_sales_act = QAction(QIcon(EXT_LINK),
                                "Sales", info_menu)
        p_sales_act.triggered[bool].connect(
            lambda: open_link_with_browser(PLANET_SALES)
        )
        info_menu.addAction(p_sales_act)

        add_menu_section_action('Documentation', info_menu)

        terms_act = QAction('Terms', info_menu)
        terms_act.triggered[bool].connect(self.show_terms)
        info_menu.addAction(terms_act)

        btn = QToolButton()
        btn.setIcon(QIcon(os.path.join(plugin_path, "resources", "info.svg"),))
        btn.setMenu(info_menu)

        btn.setPopupMode(QToolButton.MenuButtonPopup)
        # Also show menu on click, to keep disclosure triangle visible
        btn.clicked.connect(btn.showMenu)

        self.toolbar.addWidget(btn)
コード例 #30
0
ファイル: ParametersPanel.py プロジェクト: samuvack/QGIS
    def initWidgets(self):
        # If there are advanced parameters — show corresponding groupbox
        for param in self.alg.parameters:
            if param.isAdvanced:
                self.grpAdvanced.show()
                break
        # Create widgets and put them in layouts
        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]')

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

            if widget is not None:
                if isinstance(param, ParameterVector):
                    layout = QHBoxLayout()
                    layout.setSpacing(2)
                    layout.setMargin(0)
                    layout.addWidget(widget)
                    button = QToolButton()
                    icon = QIcon(
                        os.path.join(pluginPath, 'images', 'iterate.png'))
                    button.setIcon(icon)
                    button.setToolTip(self.tr('Iterate over this layer'))
                    button.setCheckable(True)
                    layout.addWidget(button)
                    self.iterateButtons[param.name] = button
                    button.toggled.connect(self.buttonToggled)
                    widget = QWidget()
                    widget.setLayout(layout)

                tooltips = self.alg.getParameterDescriptions()
                widget.setToolTip(tooltips.get(param.name, param.description))

                if type(widget) is QCheckBox:
                    # checkbox widget - so description is embedded in widget rather than a separate
                    # label
                    widget.setText(desc)
                else:
                    label = QLabel(desc)
                    # label.setToolTip(tooltip)
                    self.labels[param.name] = label

                    if param.isAdvanced:
                        self.layoutAdvanced.addWidget(label)
                    else:
                        self.layoutMain.insertWidget(
                            self.layoutMain.count() - 2, label)

                if param.isAdvanced:
                    self.layoutAdvanced.addWidget(widget)
                else:
                    self.layoutMain.insertWidget(self.layoutMain.count() - 2,
                                                 widget)

        for output in self.alg.outputs:
            if output.hidden:
                continue

            label = QLabel(output.description)
            widget = OutputSelectionPanel(output, self.alg)
            self.layoutMain.insertWidget(self.layoutMain.count() - 1, label)
            self.layoutMain.insertWidget(self.layoutMain.count() - 1, widget)
            if isinstance(output, (OutputRaster, OutputVector, OutputTable)):
                check = QCheckBox()
                check.setText(
                    self.tr('Open output file after running algorithm'))
                check.setChecked(True)
                self.layoutMain.insertWidget(self.layoutMain.count() - 1,
                                             check)
                self.checkBoxes[output.name] = check
            self.outputWidgets[output.name] = widget
        for wrapper in list(self.wrappers.values()):
            wrapper.postInitialize(list(self.wrappers.values()))
コード例 #31
0
ファイル: relation_line_edit.py プロジェクト: ollawone/stdm
class ForeignKeyLineEdit(QLineEdit):
    """
    Line edit that enables the browsing of related entities defined through
    foreign key constraint.
    """

    def __init__(self, column, parent=None, pixmap=None, host=None):
        """
        Class constructor.
        :param column: Column object containing foreign key information.
        :type column: BaseColumn
        :param parent: Parent widget for the control.
        :type parent: QWidget
        :param pixmap: Pixmap to use for the line edit button.
        :type pixmap: QPixmap
        """

        QLineEdit.__init__(self, parent)

        self.column = column
        self._entity = self.column.entity
        self.entity_dialog = host

        # Configure load button
        self.btn_load = QToolButton(parent)
        self.btn_load.setCursor(Qt.PointingHandCursor)
        self.btn_load.setFocusPolicy(Qt.NoFocus)
        px = GuiUtils.get_icon_pixmap('select_record.png')
        if not pixmap is None:
            px = pixmap
        self.btn_load.setIcon(QIcon(px))
        self.btn_load.setIconSize(px.size())
        self.btn_load.setStyleSheet('background: transparent; padding: 0px; '
                                    'border: none;')
        self.btn_load.clicked.connect(self.on_load_foreign_key_browser)

        clear_px = GuiUtils.get_icon_pixmap('clear.png')

        self.btn_clear = QToolButton(parent)
        self.btn_clear.setCursor(Qt.PointingHandCursor)
        self.btn_clear.setFocusPolicy(Qt.NoFocus)
        self.btn_clear.setIcon(QIcon(clear_px))
        self.btn_clear.setIconSize(clear_px.size())
        self.btn_clear.setStyleSheet('background: transparent; padding: 0px; '
                                     'border: none;')

        self.btn_clear.clicked.connect(self.clear_line_edit)

        frame_width = self.set_button_minimum_size(self.btn_load)
        self.set_button_minimum_size(self.btn_clear)
        # Ensure that text does not overlay button
        padding = self.btn_load.sizeHint().width() + frame_width + 1

        self.setStyleSheet('padding-right: ' + str(padding * 2) + 'px;')

        # Set layout
        self.button_layout = QHBoxLayout(self)

        self.button_layout.addWidget(self.btn_clear, 0, Qt.AlignRight)
        self.button_layout.addWidget(self.btn_load, 0, Qt.AlignRight)

        self.button_layout.setSpacing(0)
        self.button_layout.setMargin(5)

        self.btn_clear.setVisible(False)
        # Readonly as text is loaded from the related entity
        self.setReadOnly(True)

        # Current model object
        self._current_item = None

    def set_button_minimum_size(self, button):
        """
        Sets the minimum button size.
        :param button: The button to be set.
        :type button: QToolButton
        :return: Returns the frame width of the button
        :rtype: Integer
        """
        frame_width = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth)
        msz = self.minimumSizeHint()
        self.setMinimumSize(
            max(
                msz.width(),
                button.sizeHint().height() + frame_width * 2 + 2
            ), max(
                msz.height(),
                button.sizeHint().height() + frame_width * 2 + 2
            )
        )
        return frame_width

    @property
    def current_item(self):
        return self._current_item

    @current_item.setter
    def current_item(self, value):
        # Update display every time the current item is changed.
        self._current_item = value
        self.format_display()

    @property
    def entity(self):
        """
        :return: Returns the entity object corresponding to this widget.
        :rtype: Entity
        """
        return self._entity

    def clear_line_edit(self):
        """
        Clears the text in the line edit.
        """
        self.clear()
        self.hide_clear_button()

    def hide_clear_button(self):
        """
        Hides the clear button.
        """
        self.btn_clear.setVisible(False)
        self.button_layout.setStretch(0, 0)

    def show_clear_button(self):
        """
        Shows the clear button if a text exists.
        """
        if len(self.text()) > 0:
            self.btn_clear.setVisible(True)
            self.button_layout.setStretch(0, 5)

    def on_load_foreign_key_browser(self):
        """
        Slot raised to load browser for selecting foreign key entities. To be
        implemented by subclasses.
        """
        raise NotImplementedError

    def format_display(self):
        """
        Extract object values to show in the line edit based on the specified
        display columns.
        """
        raise NotImplementedError

    def parent_entity_model(self):
        """
        :return: Returns the database model corresponding to the parent table
        of the relation defined by this column. Please note that the database
        model will not contain relationship configurations in its attributes.
        :rtype: object
        """
        entity = self.column.entity_relation.parent

        return entity_model(entity, entity_only=True)

    def load_current_item_from_id(self, id):
        """
        Loads the current item from the id corresponding to the primary
        key.
        :param id: Primary key of the referenced entity.
        :type id: int
        """
        QApplication.processEvents()
        model = self.parent_entity_model()

        if model is None:
            return

        model_obj = model()
        res = model_obj.queryObject().filter(model.id == id).first()

        if not res is None:
            self.current_item = res
コード例 #32
0
class FeatureSelectorWidget(QWidget):
    feature_identified = pyqtSignal(QgsFeature)

    def __init__(self, parent):
        QWidget.__init__(self, parent)

        edit_layout = QHBoxLayout()
        edit_layout.setContentsMargins(0, 0, 0, 0)
        edit_layout.setSpacing(2)
        self.setLayout(edit_layout)

        self.line_edit = QLineEdit(self)
        self.line_edit.setReadOnly(True)
        edit_layout.addWidget(self.line_edit)

        self.highlight_feature_button = QToolButton(self)
        self.highlight_feature_button.setPopupMode(QToolButton.MenuButtonPopup)
        self.highlight_feature_action = QAction(
            QgsApplication.getThemeIcon("/mActionHighlightFeature.svg"),
            "Highlight feature", self)
        self.scale_highlight_feature_action = QAction(
            QgsApplication.getThemeIcon("/mActionScaleHighlightFeature.svg"),
            "Scale and highlight feature", self)
        self.pan_highlight_feature_action = QAction(
            QgsApplication.getThemeIcon("/mActionPanHighlightFeature.svg"),
            "Pan and highlight feature", self)
        self.highlight_feature_button.addAction(self.highlight_feature_action)
        self.highlight_feature_button.addAction(
            self.scale_highlight_feature_action)
        self.highlight_feature_button.addAction(
            self.pan_highlight_feature_action)
        self.highlight_feature_button.setDefaultAction(
            self.highlight_feature_action)
        edit_layout.addWidget(self.highlight_feature_button)

        self.map_identification_button = QToolButton(self)
        self.map_identification_button.setIcon(
            QgsApplication.getThemeIcon("/mActionMapIdentification.svg"))
        self.map_identification_button.setText("Select on map")
        self.map_identification_button.setCheckable(True)
        edit_layout.addWidget(self.map_identification_button)

        self.map_identification_button.clicked.connect(self.map_identification)
        self.highlight_feature_button.triggered.connect(
            self.highlight_action_triggered)

        self.layer = None
        self.map_tool = None
        self.canvas = None
        self.window_widget = None
        self.highlight = None
        self.feature = QgsFeature()

    def set_canvas(self, map_canvas):
        self.map_tool = QgsMapToolIdentifyFeature(map_canvas)
        self.map_tool.setButton(self.map_identification_button)
        self.canvas = map_canvas

    def set_layer(self, layer):
        self.layer = layer

    def set_feature(self, feature, canvas_extent=CanvasExtent.Fixed):
        self.line_edit.clear()
        self.feature = feature

        if self.feature is None or not self.feature.isValid(
        ) or self.layer is None:
            return

        expression = QgsExpression(self.layer.displayExpression())
        context = QgsExpressionContext()
        scope = QgsExpressionContextScope()
        context.appendScope(scope)
        scope.setFeature(feature)
        feature_title = expression.evaluate(context)
        if feature_title == "":
            feature_title = feature.id()
        self.line_edit.setText(str(feature_title))
        self.highlight_feature(canvas_extent)

    def clear(self):
        self.feature = QgsFeature()
        self.line_edit.clear()

    @pyqtSlot()
    def map_identification(self):
        if self.layer is None or self.map_tool is None or self.canvas is None:
            return

        self.map_tool.setLayer(self.layer)
        self.canvas.setMapTool(self.map_tool)

        self.window_widget = QWidget.window(self)
        self.canvas.window().raise_()
        self.canvas.activateWindow()
        self.canvas.setFocus()

        self.map_tool.featureIdentified.connect(
            self.map_tool_feature_identified)
        self.map_tool.deactivated.connect(self.map_tool_deactivated)

    def map_tool_feature_identified(self, feature):
        feature = QgsFeature(feature)
        self.feature_identified.emit(feature)
        self.unset_map_tool()
        self.set_feature(feature)

    def map_tool_deactivated(self):
        if self.window_widget is not None:
            self.window_widget.raise_()
            self.window_widget.activateWindow()

    def highlight_feature(self, canvas_extent=CanvasExtent.Fixed):
        if self.canvas is None or not self.feature.isValid():
            return

        geom = self.feature.geometry()

        if geom is None:
            return

        if canvas_extent == CanvasExtent.Scale:
            feature_bounding_box = geom.boundingBox()
            feature_bounding_box = self.canvas.mapSettings(
            ).layerToMapCoordinates(self.layer, feature_bounding_box)
            extent = self.canvas.extent()
            if not extent.contains(feature_bounding_box):
                extent.combineExtentWith(feature_bounding_box)
                extent.scale(1.1)
                self.canvas.setExtent(extent)
                self.canvas.refresh()

        elif canvas_extent == CanvasExtent.Pan:
            centroid = geom.centroid()
            center = centroid.asPoint()

            center = self.canvas.mapSettings().layerToMapCoordinates(
                self.layer, center)
            self.canvas.zoomByFactor(1.0,
                                     center)  # refresh is done in this method

        # highlight
        self.delete_highlight()
        self.highlight = QgsHighlight(self.canvas, geom, self.layer)

        settings = QSettings()
        color = QColor(
            settings.value("/Map/highlight/color",
                           Qgis.DEFAULT_HIGHLIGHT_COLOR.name()))
        alpha = int(
            settings.value("/Map/highlight/colorAlpha",
                           Qgis.DEFAULT_HIGHLIGHT_COLOR.alpha()))
        buffer = 2 * float(
            settings.value("/Map/highlight/buffer",
                           Qgis.DEFAULT_HIGHLIGHT_BUFFER_MM))
        min_width = 2 * float(
            settings.value("/Map/highlight/min_width",
                           Qgis.DEFAULT_HIGHLIGHT_MIN_WIDTH_MM))

        self.highlight.setColor(color)  # sets also fill with default alpha
        color.setAlpha(alpha)
        self.highlight.setFillColor(color)  # sets fill with alpha
        self.highlight.setBuffer(buffer)
        self.highlight.setMinWidth(min_width)
        self.highlight.setWidth(4.0)
        self.highlight.show()

        self.timer = QTimer(self)
        self.timer.setSingleShot(True)
        self.timer.timeout.connect(self.delete_highlight)
        self.timer.start(3000)

    def delete_highlight(self):
        if self.highlight is not None:
            self.highlight.hide()
            del self.highlight
            self.highlight = None

    def unset_map_tool(self):
        if self.canvas is not None and self.map_tool is not None:
            # this will call mapTool.deactivated
            self.canvas.unsetMapTool(self.map_tool)

    def highlight_action_triggered(self, action):
        self.highlight_feature_button.setDefaultAction(action)

        if action == self.highlight_feature_action:
            self.highlight_feature()

        elif action == self.scale_highlight_feature_action:
            self.highlight_feature(CanvasExtent.Scale)

        elif action == self.pan_highlight_feature_action:
            self.highlight_feature(CanvasExtent.Pan)
コード例 #33
0
    def initWidgets(self): # Heavy overload
        # If there are advanced parameters — show corresponding groupbox
        for param in self.alg.parameterDefinitions():
            if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced:
                self.grpAdvanced.show()
                break

        #widget_context = QgsProcessingParameterWidgetContext()
        #if iface is not None:
        #    widget_context.setMapCanvas(iface.mapCanvas())

        # Create widgets and put them in layouts
        for param in self.alg.parameterDefinitions():
            if param.flags() & QgsProcessingParameterDefinition.FlagHidden:
                continue

            print('initWidgets - param.name(): {}'.format(param.name()))
            if param.isDestination(): # and param.name() != 'OUTPUT_ASC':
                continue
            else:
                wrapper = WidgetWrapperFactory.create_wrapper(param, self.parent)
                self.wrappers[param.name()] = wrapper

                #widget = wrapper.widget    

                # For compatibility with 3.x API, we need to check whether the wrapper is
                # the deprecated WidgetWrapper class. If not, it's the newer
                # QgsAbstractProcessingParameterWidgetWrapper class
                # TODO QGIS 4.0 - remove
                is_python_wrapper = issubclass(wrapper.__class__, WidgetWrapper)
                if not is_python_wrapper:
                    from qgis.gui import (QgsProcessingContextGenerator, QgsProcessingParameterWidgetContext)
                    widget_context = QgsProcessingParameterWidgetContext()
                    if iface is not None:
                        widget_context.setMapCanvas(iface.mapCanvas())
                    wrapper.setWidgetContext(widget_context)
                    widget = wrapper.createWrappedWidget(self.processing_context)
                    wrapper.registerProcessingContextGenerator(self.context_generator)
                else:
                    widget = wrapper.widget

                #if self.in_place and param.name() in ('INPUT', 'OUTPUT'):
                    # don't show the input/output parameter widgets in in-place mode
                    # we still need to CREATE them, because other wrappers may need to interact
                    # with them (e.g. those parameters which need the input layer for field
                    # selections/crs properties/etc)
                #    continue

                if widget is not None:
                    if is_python_wrapper:
                        widget.setToolTip(param.toolTip())

                    if isinstance(param, QgsProcessingParameterFeatureSource):
                        layout = QHBoxLayout()
                        layout.setSpacing(6)
                        layout.setMargin(0)
                        layout.addWidget(widget)
                        button = QToolButton()
                        icon = QIcon(os.path.join(pluginPath, 'images', 'iterate.png'))
                        button.setIcon(icon)
                        button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)
                        button.setToolTip(self.tr('Iterate over this layer, creating a separate output for every feature in the layer'))
                        button.setCheckable(True)
                        layout.addWidget(button)
                        layout.setAlignment(button, Qt.AlignTop)
                        self.iterateButtons[param.name()] = button
                        button.toggled.connect(self.buttonToggled)
                        widget = QWidget()
                        widget.setLayout(layout)

                    label = None
                    if not is_python_wrapper:
                        label = wrapper.createWrappedLabel()
                    else:
                        label = wrapper.label

                    if label is not None:
                        if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced:
                            self.layoutAdvanced.addWidget(label)
                        else:
                            self.layoutMain.insertWidget(
                                self.layoutMain.count() - 2, label)
                    elif is_python_wrapper:
                        desc = param.description()
                        if isinstance(param, QgsProcessingParameterExtent):
                            desc += self.tr(' (xmin, xmax, ymin, ymax)')
                        if isinstance(param, QgsProcessingParameterPoint):
                            desc += self.tr(' (x, y)')
                        if param.flags() & QgsProcessingParameterDefinition.FlagOptional:
                            desc += self.tr(' [optional]')
                        widget.setText(desc)
                    if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced:
                        self.layoutAdvanced.addWidget(widget)
                    else:
                        self.layoutMain.insertWidget(
                            self.layoutMain.count() - 2, widget)

        for output in self.alg.destinationParameterDefinitions():
            if output.flags() & QgsProcessingParameterDefinition.FlagHidden:
                continue

            #if self.in_place and param.name() in ('INPUT', 'OUTPUT'):
            #    continue

            label = QLabel(output.description())
            #print('initWidgets 2 - param.name(): {}'.format(param.name()))
            widget = DestinationSelectionPanel(output, self.alg) # TODO, overload
            self.layoutMain.insertWidget(self.layoutMain.count() - 1, label)
            self.layoutMain.insertWidget(self.layoutMain.count() - 1, widget)
            if isinstance(output, (QgsProcessingParameterRasterDestination, 
                                   QgsProcessingParameterFeatureSink, 
                                   QgsProcessingParameterVectorDestination
                                   # alk: checkboxes for Chloe handling  
                                   ,ChloeCSVParameterFileDestination,
                                   ChloeASCParameterFileDestination,
                                   ChloeParameterFolderDestination)
                                   ):
                check = QCheckBox()
                check.setText(QCoreApplication.translate('ParametersPanel', 'Open output file(s) after running algorithm'))

                def skipOutputChanged(checkbox, skipped):
                    checkbox.setEnabled(not skipped)
                    if skipped:
                        checkbox.setChecked(False)
                check.setChecked(not widget.outputIsSkipped())
                check.setEnabled(not widget.outputIsSkipped())
                widget.skipOutputChanged.connect(partial(skipOutputChanged, check))
                self.layoutMain.insertWidget(self.layoutMain.count() - 1, check)
                self.checkBoxes[output.name()] = check
                # initial state
                if hasattr(output,'addToMapDefaultState'):
                    check.setChecked(output.addToMapDefaultState)


            widget.setToolTip(param.toolTip())
            self.outputWidgets[output.name()] = widget

        for wrapper in list(self.wrappers.values()):
            wrapper.postInitialize(list(self.wrappers.values()))
        
        
        # # alk: checkboxes for Chloe handling  
        # for output in self.alg.destinationParameterDefinitions():
        #     if output.flags() & QgsProcessingParameterDefinition.FlagHidden:
        #         continue

        #     if isinstance(output, (ChloeCSVParameterFileDestination)) or isinstance(output, (ChloeASCParameterFileDestination)):
        #         check = QCheckBox()
        #         check.setText(QCoreApplication.translate('ParametersPanel', 'Open output file(s) after running algorithm'))

        #         def skipOutputChanged(checkbox, skipped):
        #             checkbox.setEnabled(not skipped)
        #             if skipped:
        #                 checkbox.setChecked(False)
        #         check.setChecked(not widget.outputIsSkipped())
        #         check.setEnabled(not widget.outputIsSkipped())
        #         widget.skipOutputChanged.connect(partial(skipOutputChanged, check))
        #         print(str(self.layoutMain)+1)
        #         self.layoutMain.insertWidget(self.layoutMain.count() - 1, check)
        #         self.checkBoxes[output.name()] = check
                
                # # connecting alg outputLoading info with checkbox state
                # self.alg.outputLoading[output.name()] = check.isChecked()
                # def updateOutputLoadingState(alg, outputName, checkbox, state):
                #     self.alg.outputLoading[outputName] = checkbox.isChecked()
                #     print( outputName + " " + str(checkbox.isChecked()) + " " + str(self.alg.outputLoading) + " " + str(self.alg))
                #     #print(str(self.alg.parameters))
                # check.stateChanged.connect(partial(updateOutputLoadingState, self, output.name(), check))
        
        # alk: addition of wrapper special config handling
        # for dependancy between wrapper, i.e. changing the value 
        # of a FileSelectionPanel entails the update of another widget
        for k in self.wrappers:
            w = self.wrappers[k]
            if hasattr(w,'getParentWidgetConfig'):
                print(str(w) + " "  + "getParentWidgetConfig")
                config = w.getParentWidgetConfig()
                if config != None:
                    p = self.wrappers[config['paramName']]
                    m = getattr(w, config['refreshMethod'])
                    if m!=None:
                        print(str(p) + " " + str(p.widget))
                        # todo generalize valueChanged handling 
                        # to any type of widget componant
                        if isinstance(p.widget, FileSelectionPanel):
                            p.widget.leText.textChanged.connect(m)
                        elif isinstance(p, RasterWidgetWrapper):
                            try:
                                p.combo.valueChanged.connect(m) # QGIS 3.8 version
                            except:
                                p.combo.currentIndexChanged.connect(m) # QGIS LTR 3.4
コード例 #34
0
ファイル: ParametersPanel.py プロジェクト: enricofer/QGIS
    def initWidgets(self):
        # If there are advanced parameters — show corresponding groupbox
        for param in self.alg.parameterDefinitions():
            if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced:
                self.grpAdvanced.show()
                break

        widget_context = QgsProcessingParameterWidgetContext()
        if iface is not None:
            widget_context.setMapCanvas(iface.mapCanvas())

        # Create widgets and put them in layouts
        for param in self.alg.parameterDefinitions():
            if param.flags() & QgsProcessingParameterDefinition.FlagHidden:
                continue

            if param.isDestination():
                continue
            else:
                wrapper = WidgetWrapperFactory.create_wrapper(param, self.parent)
                self.wrappers[param.name()] = wrapper

                # For compatibility with 3.x API, we need to check whether the wrapper is
                # the deprecated WidgetWrapper class. If not, it's the newer
                # QgsAbstractProcessingParameterWidgetWrapper class
                # TODO QGIS 4.0 - remove
                is_python_wrapper = issubclass(wrapper.__class__, WidgetWrapper)
                if not is_python_wrapper:
                    wrapper.setWidgetContext(widget_context)
                    widget = wrapper.createWrappedWidget(self.processing_context)
                    wrapper.registerProcessingContextGenerator(self.context_generator)
                else:
                    widget = wrapper.widget

                if self.in_place and param.name() in ('INPUT', 'OUTPUT'):
                    # don't show the input/output parameter widgets in in-place mode
                    # we still need to CREATE them, because other wrappers may need to interact
                    # with them (e.g. those parameters which need the input layer for field
                    # selections/crs properties/etc)
                    continue

                if widget is not None:
                    if is_python_wrapper:
                        widget.setToolTip(param.toolTip())

                    if isinstance(param, QgsProcessingParameterFeatureSource):
                        layout = QHBoxLayout()
                        layout.setSpacing(6)
                        layout.setMargin(0)
                        layout.addWidget(widget)
                        button = QToolButton()
                        icon = QIcon(os.path.join(pluginPath, 'images', 'iterate.png'))
                        button.setIcon(icon)
                        button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)
                        button.setToolTip(self.tr('Iterate over this layer, creating a separate output for every feature in the layer'))
                        button.setCheckable(True)
                        layout.addWidget(button)
                        layout.setAlignment(button, Qt.AlignTop)
                        self.iterateButtons[param.name()] = button
                        button.toggled.connect(self.buttonToggled)
                        widget = QWidget()
                        widget.setLayout(layout)

                    label = None
                    if not is_python_wrapper:
                        label = wrapper.createWrappedLabel()
                    else:
                        label = wrapper.label

                    if label is not None:
                        if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced:
                            self.layoutAdvanced.addWidget(label)
                        else:
                            self.layoutMain.insertWidget(
                                self.layoutMain.count() - 2, label)
                    elif is_python_wrapper:
                        desc = param.description()
                        if isinstance(param, QgsProcessingParameterExtent):
                            desc += self.tr(' (xmin, xmax, ymin, ymax)')
                        if isinstance(param, QgsProcessingParameterPoint):
                            desc += self.tr(' (x, y)')
                        if param.flags() & QgsProcessingParameterDefinition.FlagOptional:
                            desc += self.tr(' [optional]')
                        widget.setText(desc)
                    if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced:
                        self.layoutAdvanced.addWidget(widget)
                    else:
                        self.layoutMain.insertWidget(
                            self.layoutMain.count() - 2, widget)

        for output in self.alg.destinationParameterDefinitions():
            if output.flags() & QgsProcessingParameterDefinition.FlagHidden:
                continue

            if self.in_place and param.name() in ('INPUT', 'OUTPUT'):
                continue

            label = QLabel(output.description())
            widget = DestinationSelectionPanel(output, self.alg)
            self.layoutMain.insertWidget(self.layoutMain.count() - 1, label)
            self.layoutMain.insertWidget(self.layoutMain.count() - 1, widget)
            if isinstance(output, (QgsProcessingParameterRasterDestination, QgsProcessingParameterFeatureSink, QgsProcessingParameterVectorDestination)):
                check = QCheckBox()
                check.setText(QCoreApplication.translate('ParametersPanel', 'Open output file after running algorithm'))

                def skipOutputChanged(checkbox, skipped):
                    checkbox.setEnabled(not skipped)
                    if skipped:
                        checkbox.setChecked(False)
                check.setChecked(not widget.outputIsSkipped())
                check.setEnabled(not widget.outputIsSkipped())
                widget.skipOutputChanged.connect(partial(skipOutputChanged, check))
                self.layoutMain.insertWidget(self.layoutMain.count() - 1, check)
                self.checkBoxes[output.name()] = check

            widget.setToolTip(param.toolTip())
            self.outputWidgets[output.name()] = widget

        for wrapper in list(self.wrappers.values()):
            wrapper.postInitialize(list(self.wrappers.values()))
コード例 #35
0
    def update_layers(self):
        if self.tabWidget.currentIndex() != 2:
            return

        if self.layerSelection.currentIndex() == 3:  # by selection string
            self.selectionStringLineEdit.setEnabled(True)
        else:
            self.selectionStringLineEdit.setEnabled(False)

        if self.layerSelection.currentIndex() == 0:  # visible layers
            layers = self.activeRasterLayers(0)
        elif self.layerSelection.currentIndex() == 3:  # by selection string
            layers = self.activeRasterLayers(3)
        else:
            layers = self.activeRasterLayers(1)  # All layers

        self.selectionTable.blockSignals(True)
        self.selectionTable.clearContents()
        self.selectionTable.setRowCount(len(layers))
        self.selectionTable.horizontalHeader().resizeSection(0, 20)
        self.selectionTable.horizontalHeader().resizeSection(2, 20)

        j = 0
        for layer in layers:
            item = QTableWidgetItem()
            item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
            if self.layerSelection.currentIndex() != 2:
                item.setFlags(item.flags() & ~Qt.ItemIsEnabled)
                item.setCheckState(Qt.Checked)
            else:
                # manual selection
                if layer.id() in self.layersSelected:
                    item.setCheckState(Qt.Checked)
                else:
                    item.setCheckState(Qt.Unchecked)
            self.selectionTable.setItem(j, 0, item)
            item = QTableWidgetItem(layer.name())
            item.setData(Qt.UserRole, layer.id())
            self.selectionTable.setItem(j, 1, item)
            activeBands = self.activeBandsForRaster(layer)
            button = QToolButton()
            button.setIcon(QIcon(':/plugins/mutant/img/bands.jpg'))
            # button.setIconSize(QtCore.QSize(400, 400))
            button.setPopupMode(QToolButton.InstantPopup)
            group = QActionGroup(button)
            group.setExclusive(False)
            group.triggered.connect(self.bandSelected)
            if self.bandSelection.currentIndex(
            ) == 2 and layer.bandCount() > 1:
                menu = QMenu()
                menu.installEventFilter(self)

                for iband in range(1, layer.bandCount() + 1):
                    action = QAction(str(layer.bandName(iband)), group)
                    action.setData([layer.id(), iband, j, False])
                    action.setCheckable(True)
                    action.setChecked(iband in activeBands)
                    menu.addAction(action)
                if layer.bandCount() > 1:
                    action = QAction(str(self.tr("All")), group)
                    action.setData([layer.id(), -1, j, True])
                    action.setCheckable(False)
                    menu.addAction(action)
                    action = QAction(str(self.tr("None")), group)
                    action.setData([layer.id(), -1, j, False])
                    action.setCheckable(False)
                    menu.addAction(action)

                button.setMenu(menu)
            else:
                button.setEnabled(False)
            self.selectionTable.setCellWidget(j, 2, button)
            item = QTableWidgetItem(str(activeBands))
            item.setToolTip(str(activeBands))
            self.selectionTable.setItem(j, 3, item)
            j += 1

        self.selectionTable.blockSignals(False)
コード例 #36
0
class MirrorMap(QWidget):
    def __init__(self, parent=None, iface=None):
        QWidget.__init__(self, parent)
        # self.setAttribute(Qt.WA_DeleteOnClose)

        self.iface = iface
        self.layerId2canvasLayer = {}
        self.canvasLayers = []

        self.setupUi()

    def closeEvent(self, event):
        self.scaleFactor.valueChanged.disconnect(self.onExtentsChanged)

        if not self.iface is None:
            self.iface.mapCanvas().extentsChanged.discconnect(
                self.onExtentsChanged)
            self.iface.mapCanvas().mapRenderer(
            ).destinationCrsChanged.disconnect(self.onCrsChanged)
            self.iface.mapCanvas().mapRenderer().mapUnitsChanged.disconnect(
                self.onCrsChanged)
            self.iface.mapCanvas().mapRenderer(
            ).hasCrsTransformEnabled.disconnect(self.onCrsTransformEnabled)
            QgsProject.instance().layerWillBeRemoved.disconnect(self.delLayer)
            self.iface.currentLayerChanged.disconnect(self.refreshLayerButtons)

        self.closed.emit()

        return QWidget.closeEvent(self, event)

    def setupUi(self):
        self.setObjectName("mirrormap")

        gridLayout = QGridLayout(self)
        gridLayout.setContentsMargins(0, 0, gridLayout.verticalSpacing(),
                                      gridLayout.verticalSpacing())

        self.canvas = QgsMapCanvas(self)
        self.canvas.setCanvasColor(QColor(255, 255, 255))
        settings = QSettings()
        gridLayout.addWidget(self.canvas, 0, 0, 1, 5)

        self.addLayerBtn = QToolButton(self)
        # self.addLayerBtn.setToolButtonStyle( Qt.ToolButtonTextBesideIcon )
        # self.addLayerBtn.setText("Add current layer")
        self.addLayerBtn.setIcon(GuiUtils.get_icon("add.png"))

        self.addLayerBtn.clicked.connect(self.tool_add_layer)
        gridLayout.addWidget(self.addLayerBtn, 1, 0, 1, 1)

        self.delLayerBtn = QToolButton(self)
        # self.delLayerBtn.setToolButtonStyle( Qt.ToolButtonTextBesideIcon )
        # self.delLayerBtn.setText("Remove current layer")
        self.delLayerBtn.setIcon(GuiUtils.get_icon("remove.png"))
        self.delLayerBtn.clicked.connect(self.tool_remove_layer)
        gridLayout.addWidget(self.delLayerBtn, 1, 1, 1, 1)

        self.renderCheck = QCheckBox("Render", self)
        self.renderCheck.toggled.connect(self.toggleRender)
        self.renderCheck.setChecked(True)
        gridLayout.addWidget(self.renderCheck, 1, 2, 1, 1)

        self.scaleFactorLabel = QLabel(self)
        self.scaleFactorLabel.setText("Scale factor:")
        self.scaleFactorLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        gridLayout.addWidget(self.scaleFactorLabel, 1, 3, 1, 1)
        self.scaleFactor = QDoubleSpinBox(self)
        self.scaleFactor.setMinimum(0.0)
        self.scaleFactor.setMaximum(1000.0)
        self.scaleFactor.setDecimals(3)
        self.scaleFactor.setValue(1)
        self.scaleFactor.setObjectName("scaleFactor")
        self.scaleFactor.setSingleStep(.05)
        gridLayout.addWidget(self.scaleFactor, 1, 4, 1, 1)
        self.scaleFactor.valueChanged.connect(self.onExtentsChanged)

        # Add a default pan tool
        self.toolPan = QgsMapToolPan(self.canvas)
        self.canvas.setMapTool(self.toolPan)

        self.scaleFactor.valueChanged.connect(self.onExtentsChanged)
        self.set_iface(self.iface)

    def toggleRender(self, enabled):
        self.canvas.setRenderFlag(enabled)

    def extent(self):
        """
        :return: Current extents of the map canvas view.
        """
        return self.canvas.extent()

    def canvas_layers(self):
        """
        :return: Layers currently in the canvas.
        :rtype: list
        """
        return self.canvasLayers

    def on_canvas_refreshed(self):
        """
        """
        self.refresh_layers()

    def tool_add_layer(self):
        self.addLayer()

    def tool_remove_layer(self):
        self.delLayer()

    def set_iface(self, iface):
        if iface is None:
            return

        self.iface = iface
        self.iface.mapCanvas().extentsChanged.connect(self.onExtentsChanged)
        # self.iface.mapCanvas().mapCanvasRefreshed.connect(self.on_canvas_refreshed)
        self.iface.mapCanvas().destinationCrsChanged.connect(self.onCrsChanged)
        QgsProject.instance().layerWillBeRemoved.connect(self.delLayer)
        self.iface.currentLayerChanged.connect(self.refreshLayerButtons)

        self.refreshLayerButtons()

        self.onExtentsChanged()
        self.onCrsChanged()

    def refresh_layers(self):
        """
        Checks if the layers in the canvas list have already been added.
        If not, then add to the property viewer canvas.
        """
        for ly in self.iface.mapCanvas().layers():
            layer_id = self._layerId(ly)
            if layer_id not in self.layerId2canvasLayer:
                self.addLayer(layer_id)
        # QCoreApplication.processEvents(QEventLoop.ExcludeSocketNotifiers|QEventLoop.ExcludeUserInputEvents)

    def onExtentsChanged(self):
        prevFlag = self.canvas.renderFlag()
        self.canvas.setRenderFlag(False)

        self.canvas.setExtent(self.iface.mapCanvas().extent())
        self.canvas.zoomByFactor(self.scaleFactor.value())
        # self.canvas.refresh()

        self.canvas.setRenderFlag(prevFlag)

    def onCrsChanged(self):
        self.canvas.setDestinationCrs(
            self.iface.mapCanvas().mapSettings().destinationCrs())

    def refreshLayerButtons(self):
        layer = self.iface.activeLayer()

        isLayerSelected = layer != None
        hasLayer = False
        for l in self.canvas.layers():
            if l == layer:
                hasLayer = True
                break

        self.addLayerBtn.setEnabled(isLayerSelected and not hasLayer)
        self.delLayerBtn.setEnabled(isLayerSelected and hasLayer)

    def getLayerSet(self):
        return [self._layerId(x.layer()) for x in self.canvasLayers]

    def setLayerSet(self, layerIds=None):
        prevFlag = self.canvas.renderFlag()
        self.canvas.setRenderFlag(False)

        if layerIds == None:
            self.layerId2canvasLayer = {}
            self.canvasLayers = []
            self.canvas.setLayers([])

        else:
            for lid in layerIds:
                self.addLayer(lid)

        self.refreshLayerButtons()
        self.onExtentsChanged()
        self.canvas.setRenderFlag(prevFlag)

    def addLayer(self, layerId=None):
        if layerId == None:
            layer = self.iface.activeLayer()
        else:
            layer = QgsProject.instance().mapLayer(layerId)

        if layer == None:
            return

        prevFlag = self.canvas.renderFlag()
        self.canvas.setRenderFlag(False)

        # add the layer to the map canvas layer set
        self.canvasLayers = []
        id2cl_dict = {}
        for l in self.iface.mapCanvas().layers():
            lid = self._layerId(l)
            if lid in self.layerId2canvasLayer:  # previously added
                cl = self.layerId2canvasLayer[lid]
            elif l == layer:  # Selected layer
                cl = layer
            else:
                continue

            id2cl_dict[lid] = cl
            self.canvasLayers.append(cl)

        self.layerId2canvasLayer = id2cl_dict
        self.canvas.setLayers(self.canvasLayers)

        self.refreshLayerButtons()
        self.onExtentsChanged()
        self.canvas.setRenderFlag(prevFlag)

    def delLayer(self, layerId=None):
        if layerId == None:
            layer = self.iface.activeLayer()
            if layer == None:
                return
            layerId = self._layerId(layer)

        # remove the layer from the map canvas layer set
        if layerId not in self.layerId2canvasLayer:
            return

        prevFlag = self.canvas.renderFlag()
        self.canvas.setRenderFlag(False)

        cl = self.layerId2canvasLayer[layerId]
        del self.layerId2canvasLayer[layerId]
        self.canvasLayers.remove(cl)
        self.canvas.setLayers(self.canvasLayers)

        self.refreshLayerButtons()
        self.onExtentsChanged()
        self.canvas.setRenderFlag(prevFlag)

    def _layerId(self, layer):
        if hasattr(layer, 'id'):
            return layer.id()

        return layer.getLayerID()
コード例 #37
0
ファイル: search_bar.py プロジェクト: tlh22/TOMs
class searchBar():

    def __init__(self, iface, TOMsSearchBar, proposalsManager):

        TOMsMessageLog.logMessage("In searchBar", level=Qgis.Info)
        # Save reference to the QGIS interface
        self.iface = iface
        self.canvas = self.iface.mapCanvas()
        self.TOMsSearchBar = TOMsSearchBar
        self.proposalsManager = proposalsManager

        self.tool = TOMsInstantPrintTool(self.iface, self.proposalsManager)

        self.initSearchBar()


        # https: // gis.stackexchange.com / questions / 244584 / adding - textbox - to - qgis - plugin - toolbar

    def initSearchBar(self):
        TOMsMessageLog.logMessage("In initSearchBox:", level=Qgis.Info)

        self.initialPass = True
        self.gazetteerStringList = []

        # Create & add a textbox
        self.searchTextbox = QLineEdit(self.iface.mainWindow())
        # Set width
        self.searchTextbox.setFixedWidth(250)
        # Add textbox to toolbar
        self.txtEntry = self.TOMsSearchBar.addWidget(self.searchTextbox)
        #self.txtEntry.setToolTip(self.tr(u'Enter Street Name'))

        self.searchTextbox.textChanged.connect(self.doLookupItem)

        self.actionGoToItem = QAction(QIcon(":/plugins/TOMs/resources/magnifyingGlass.png"),
                                            QCoreApplication.translate("MyPlugin", "Start TOMs"), self.iface.mainWindow())
        self.TOMsSearchBar.addAction(self.actionGoToItem)
        self.actionGoToItem.triggered.connect(self.doGoToItem)
        self.actionGoToItem.setCheckable(True)

        # Add in details of the Instant Print plugin
        self.toolButton = QToolButton(self.iface.mainWindow())
        self.toolButton.setIcon(QIcon(":/plugins/TOMs/InstantPrint/icons/icon.png"))
        #self.toolButton.setToolTip(self.tr("Instant Print"))
        self.toolButton.setCheckable(True)
        self.printButtonAction = self.TOMsSearchBar.addWidget(self.toolButton)

        """self.actionInstantPrint = QAction(QIcon(":/plugins/TOMs/InstantPrint/icons/icon.png"),
                                          QCoreApplication.translate("Print", "Print"), self.iface.mainWindow())"""

        self.toolButton.toggled.connect(self.__enablePrintTool)
        self.iface.mapCanvas().mapToolSet.connect(self.__onPrintToolSet)

    def enableSearchBar(self):
        TOMsMessageLog.logMessage("In enableSearchBar", level=Qgis.Info)

        self.actionGoToItem.setEnabled(True)
        self.toolButton.setEnabled(True)
        self.searchTextbox.textChanged.connect(self.doLookupItem)

    def disableSearchBar(self):
        TOMsMessageLog.logMessage("In disableSearchBar", level=Qgis.Info)

        self.initialPass = True
        self.actionGoToItem.setEnabled(False)
        self.toolButton.setEnabled(False)
        self.searchTextbox.textChanged.disconnect(self.doLookupItem)

    def doLookupItem(self):

        TOMsMessageLog.logMessage("In doLookupItem:", level=Qgis.Info)

        # TODO: Check whether or not a project has been opened

        #https: // gis.stackexchange.com / questions / 246339 / drop - down - list - qgis - plugin - based - on - keyword - search / 246347

        if self.initialPass:
            self.setupCompleter()
            self.initialPass = False

        searchText = self.searchTextbox.text()
        TOMsMessageLog.logMessage("In doLookupItem: searchText " + str(searchText), level=Qgis.Info)

        #search_in = txt
        #query = "SELECT myfield1, myfield2 FROM my_table WHERE '%s' LIKE '%' || search_field || '%';" % (search_in)
        # access your db and run the query
        # run the query with while query.next() and store values in a list
        # feed list to resiver (combox.addItems(myList)

    def setupCompleter(self):
        # set up string list for completer

        TOMsMessageLog.logMessage("In setupCompleter:", level=Qgis.Info)
        lookupStringSet = set()
        # https://gis.stackexchange.com/questions/155805/qstringlist-error-in-plugin-of-qgis-2-10

        self.GazetteerLayer = QgsProject.instance().mapLayersByName("StreetGazetteerRecords")[0]

        for row in self.GazetteerLayer.getFeatures():
            streetName = row.attribute("Descriptor_")
            locality = row.attribute("Locality")
            nameString = streetName
            if locality:
                nameString = nameString + ", " + locality

            if nameString:
                TOMsMessageLog.logMessage("In setupCompleter: nameString: " + nameString, level=Qgis.Info)
                lookupStringSet.add(nameString)
                # self.gazetteerStringList.append((nameString))

        completer = QCompleter()
        completer.setCaseSensitivity(Qt.CaseInsensitive)
        completer.setFilterMode(Qt.MatchContains)
        self.searchTextbox.setCompleter(completer)
        model = QStringListModel()
        completer.setModel(model)
        model.setStringList(self.gazetteerStringList)
        model.setStringList(sorted(lookupStringSet))

    def doGoToItem(self):

        TOMsMessageLog.logMessage("In doGoToItem:", level=Qgis.Info)

        searchText = self.searchTextbox.text()
        TOMsMessageLog.logMessage("In doGoToItem: searchText " + str(searchText), level=Qgis.Info)

        # Split out the components of the text

        streetName, localityName = searchText.split(',')
        #amendedStreetName = streetName.replace("'", "\'\'")
        #amendedLocalityName = localityName.replace("'", "\'\'")
        TOMsMessageLog.logMessage("In doGoToItem: streetName: " + str(streetName.replace("'", "\'\'")) + " locality: + " + str(localityName.replace("'", "\'\'")), level=Qgis.Info)

        # Now search for the street

        queryString = "\"Descriptor_\" = \'" + streetName.replace("'", "\'\'") + "\'"
        if localityName:
            queryString = queryString + " AND \"Locality\" = \'" + localityName.replace("'", "\'\'").lstrip() + "\'"

        TOMsMessageLog.logMessage("In doGoToItem: queryString: " + str(queryString), level=Qgis.Info)

        it = self.GazetteerLayer.selectByExpression(queryString, QgsVectorLayer.SetSelection)

        self.canvas.zoomToSelected(self.GazetteerLayer)

        """box = layer.boundingBoxOfSelected()
        iface.mapCanvas().setExtent(box)
        iface.mapCanvas().refresh()"""

    def unload(self):
        self.tool.setEnabled(False)
        self.tool = None
        self.iface.TOMsSearchBar().removeAction(self.printButtonAction)
        self.iface.TOMsSearchBar().removeAction(self.actionGoToItem)

    def __enablePrintTool(self, active):
        self.tool.setEnabled(active)

    def __onPrintToolSet(self, tool):
        if tool != self.tool:
            self.toolButton.setChecked(False)