Esempio n. 1
0
    def set_metadata_layer(self, request, **kwargs):

        self.layer = self.get_layer_by_params(kwargs)

        # set layer_name
        self.layer_name = self.layer.origname

        geomodel, self.database_to_use, geometrytype = create_geomodel_from_qdjango_layer(
            self.layer)

        if geometrytype is None:
            geometrytype = QGIS_LAYER_TYPE_NO_GEOM

        # set bbox_filter_field with geomentry model field
        if geometrytype != QGIS_LAYER_TYPE_NO_GEOM:
            serializer = QGISGeoLayerSerializer
            self.bbox_filter_field = get_geometry_column(geomodel).name
        else:
            serializer = QGISLayerSerializer

        # create model and add to editing_layers
        self.metadata_layer = MetadataVectorLayer(geomodel,
                                                  serializer,
                                                  geometrytype,
                                                  self.layer.origname,
                                                  layer_id=self.layer.pk)
Esempio n. 2
0
    def set_metadata_relations(self, request, **kwargs):

        # init relations
        self.set_relations()

        # Determine if we are using an old and bugged version of QGIS
        IS_QGIS_3_10 = Qgis.QGIS_VERSION.startswith('3.10')

        for idr, relation in list(self.relations.items()):

            # check if in relation there is referencedLayer == self layer
            if relation['referencedLayer'] == self.layer.qgs_layer_id:
                # get relation layer object
                relation_layer = self._layer_model.objects.get(
                    qgs_layer_id=relation['referencingLayer'],
                    project=self.layer.project)

                # qgis_layer is the referenced layer
                qgis_layer = self.layer.qgis_layer
                referenced_field_is_pk = [
                    qgis_layer.fields().indexFromName(
                        relation['fieldRef']['referencedField'])
                ] == qgis_layer.primaryKeyAttributes()

                # It's an old and buggy QGIS version so we cannot trust primaryKeyAttributes() and we go guessing
                if IS_QGIS_3_10:
                    field_index = qgis_layer.fields().indexFromName(
                        relation['fieldRef']['referencedField'])
                    # Safety check
                    if field_index >= 0:
                        field = qgis_layer.fields()[field_index]
                        default_clause = qgis_layer.dataProvider(
                        ).defaultValueClause(field_index)
                        constraints = qgis_layer.fieldConstraints(field_index)
                        not_null = bool(constraints & QgsFieldConstraints.ConstraintNotNull) and \
                            field.constraints().constraintStrength(
                            QgsFieldConstraints.ConstraintNotNull) == QgsFieldConstraints.ConstraintStrengthHard
                        unique = bool(constraints & QgsFieldConstraints.ConstraintUnique) and \
                            field.constraints().constraintStrength(
                            QgsFieldConstraints.ConstraintUnique) == QgsFieldConstraints.ConstraintStrengthHard
                        referenced_field_is_pk = unique and default_clause and not_null

                self.metadata_relations[
                    relation['referencingLayer']] = MetadataVectorLayer(
                        get_qgis_layer(relation_layer),
                        relation_layer.origname,
                        idr,
                        layer=relation_layer,
                        referencing_field=relation['fieldRef']
                        ['referencingField'],
                        layer_id=relation_layer.pk,
                        referenced_field_is_pk=referenced_field_is_pk)
Esempio n. 3
0
    def set_metadata_layer(self, request, **kwargs):
        """Set the metadata layer to a QgsVectorLayer instance

        returns a dictionary with layer information and the QGIS layer instance
        """

        self.layer = self.get_layer_by_params(kwargs)

        # set layer_name
        self.layer_name = self.layer.origname

        qgis_layer = get_qgis_layer(self.layer)

        # create model and add to editing_layers
        self.metadata_layer = MetadataVectorLayer(qgis_layer,
                                                  self.layer.origname,
                                                  layer_id=self.layer.pk)
Esempio n. 4
0
    def set_metadata_relations(self, request, **kwargs):

        # init relations
        self.set_relations()

        for idr, relation in self.relations.items():

            # check if in relation there is referencedLayer == self layer
            if relation['referencedLayer'] == self.layer.qgs_layer_id:
                # get relation layer object
                relation_layer = Layer.objects.get(
                    qgs_layer_id=relation['referencingLayer'],
                    project=self.layer.project)

                geomodel, database_to_use, geometrytype = create_geomodel_from_qdjango_layer(
                    relation_layer)

                if geometrytype and geometrytype != QGIS_LAYER_TYPE_NO_GEOM:
                    serializer = QGISGeoLayerSerializer
                else:
                    serializer = QGISLayerSerializer

                self.metadata_relations[
                    relation['referencingLayer']] = MetadataVectorLayer(
                        geomodel,
                        serializer,
                        geometrytype,
                        relation_layer.origname,
                        idr,
                        using=database_to_use,
                        layer=relation_layer,
                        referencing_field=relation['fieldRef']
                        ['referencingField'],
                        referenced_field_is_pk=self.metadata_layer.model._meta.
                        pk.name == relation['fieldRef']['referencedField'],
                        layer_id=relation_layer.pk)
Esempio n. 5
0
    def fetch_values_from_layer(self):
        """
        (Re)fetches plot values from the source layer.

        Modified by Walter lorenzetti for integration into G3W-SUITE
        :param djrequest: Django HttpRequest instance.
        """

        # Note: we keep things nice and efficient and only iterate a single time over the layer!

        if self.layer:
            self.metadata_layer = MetadataVectorLayer(
                self.source_layer,
                self.layer.origname,
                layer_id=self.layer.pk
            )

        if not self.context_generator:
            context = QgsExpressionContext()
            context.appendScopes(
                QgsExpressionContextUtils.globalProjectLayerScopes(self.source_layer))
        else:
            context = self.context_generator.createExpressionContext()
            # add a new scope corresponding to the source layer -- this will potentially overwrite any other
            # layer scopes which may be present in the context (e.g. from atlas layers), but we need to ensure
            # that source layer fields and attributes are present in the context
            context.appendScope(
                self.source_layer.createExpressionContextScope())

        self.settings.data_defined_properties.prepare(context)

        self.fetch_layout_properties(context)

        def add_source_field_or_expression(field_or_expression):
            field_index = self.source_layer.fields().lookupField(field_or_expression)
            if field_index == -1:
                expression = QgsExpression(field_or_expression)
                if not expression.hasParserError():
                    expression.prepare(context)
                return expression, expression.needsGeometry(), expression.referencedColumns()

            return None, False, {field_or_expression}

        x_expression, x_needs_geom, x_attrs = add_source_field_or_expression(self.settings.properties['x_name']) if \
            self.settings.properties[
                'x_name'] else (None, False, set())
        y_expression, y_needs_geom, y_attrs = add_source_field_or_expression(self.settings.properties['y_name']) if \
            self.settings.properties[
                'y_name'] else (None, False, set())
        z_expression, z_needs_geom, z_attrs = add_source_field_or_expression(self.settings.properties['z_name']) if \
            self.settings.properties[
                'z_name'] else (None, False, set())
        additional_info_expression, additional_needs_geom, additional_attrs = add_source_field_or_expression(
            self.settings.layout['additional_info_expression']) if self.settings.layout[
            'additional_info_expression'] else (None, False, set())

        attrs = set().union(self.settings.data_defined_properties.referencedFields(),
                            x_attrs,
                            y_attrs,
                            z_attrs,
                            additional_attrs)

        request = QgsFeatureRequest()

        if self.settings.data_defined_properties.property(PlotSettings.PROPERTY_FILTER).isActive():
            expression = self.settings.data_defined_properties.property(
                PlotSettings.PROPERTY_FILTER).asExpression()
            request.setFilterExpression(expression)
            request.setExpressionContext(context)

        original_subset_string = self.source_layer.subsetString()

        if hasattr(self, 'filter_backends') \
                and hasattr(self, 'djrequest') \
                and hasattr(self, 'layer') \
                and self.djrequest \
                and self.layer:
            for backend in self.filter_backends:
                backend().apply_filter(self.djrequest, self.metadata_layer, request, self)

        request.setSubsetOfAttributes(attrs, self.source_layer.fields())

        if not x_needs_geom and not y_needs_geom and not z_needs_geom and not additional_needs_geom and not self.settings.data_defined_properties.hasActiveProperties():
            request.setFlags(QgsFeatureRequest.NoGeometry)

        visible_geom_engine = None
        if self.visible_features_only and self.visible_region is not None:
            ct = QgsCoordinateTransform(self.visible_region.crs(), self.source_layer.crs(),
                                        QgsProject.instance().transformContext())
            try:
                rect = ct.transformBoundingBox(self.visible_region)
                request.setFilterRect(rect)
            except QgsCsException:
                pass
        elif self.visible_features_only and self.polygon_filter is not None:
            ct = QgsCoordinateTransform(self.polygon_filter.crs(), self.source_layer.crs(),
                                        QgsProject.instance().transformContext())
            try:
                rect = ct.transformBoundingBox(
                    self.polygon_filter.geometry.boundingBox())
                request.setFilterRect(rect)
                g = self.polygon_filter.geometry
                g.transform(ct)

                visible_geom_engine = QgsGeometry.createGeometryEngine(
                    g.constGet())
                visible_geom_engine.prepareGeometry()
            except QgsCsException:
                pass

        # self.selected_features_only is not used into qplotly module !
        # -------------------------------------------------------------
        # if self.selected_features_only:
        #    it = self.source_layer.getSelectedFeatures(request)
        # else:
        it = self.source_layer.getFeatures(request)

        self.qgsrequest = request

        # Some plot types don't draw individual glyphs for each feature, but aggregate them instead.
        # In that case it doesn't make sense to evaluate expressions for settings like marker size or color for each
        # feature. Instead, the evaluation should be executed only once for these settings.
        aggregating = self.settings.plot_type in ['box', 'histogram']
        executed = False

        xx = []
        yy = []
        zz = []
        additional_hover_text = []
        marker_sizes = []
        colors = []
        stroke_colors = []
        stroke_widths = []
        for f in it:
            if visible_geom_engine and not visible_geom_engine.intersects(f.geometry().constGet()):
                continue

            self.settings.feature_ids.append(f.id())
            context.setFeature(f)

            x = None
            if x_expression:
                x = x_expression.evaluate(context)
                if x == NULL or x is None:
                    continue
            elif self.settings.properties['x_name']:
                x = f[self.settings.properties['x_name']]
                if x == NULL or x is None:
                    continue

            y = None
            if y_expression:
                y = y_expression.evaluate(context)
                if y == NULL or y is None:
                    continue
            elif self.settings.properties['y_name']:
                y = f[self.settings.properties['y_name']]
                if y == NULL or y is None:
                    continue

            z = None
            if z_expression:
                z = z_expression.evaluate(context)
                if z == NULL or z is None:
                    continue
            elif self.settings.properties['z_name']:
                z = f[self.settings.properties['z_name']]
                if z == NULL or z is None:
                    continue

            if additional_info_expression:
                additional_hover_text.append(
                    additional_info_expression.evaluate(context))
            elif self.settings.layout['additional_info_expression']:
                additional_hover_text.append(
                    f[self.settings.layout['additional_info_expression']])

            if x is not None:
                xx.append(x)
            if y is not None:
                yy.append(y)
            if z is not None:
                zz.append(z)

            if self.settings.data_defined_properties.isActive(PlotSettings.PROPERTY_MARKER_SIZE):
                default_value = self.settings.properties['marker_size']
                context.setOriginalValueVariable(default_value)
                value, _ = self.settings.data_defined_properties.valueAsDouble(PlotSettings.PROPERTY_MARKER_SIZE,
                                                                               context, default_value)
                marker_sizes.append(value)
            if self.settings.data_defined_properties.isActive(PlotSettings.PROPERTY_STROKE_WIDTH):
                default_value = self.settings.properties['marker_width']
                context.setOriginalValueVariable(default_value)
                value, _ = self.settings.data_defined_properties.valueAsDouble(PlotSettings.PROPERTY_STROKE_WIDTH,
                                                                               context, default_value)
                stroke_widths.append(value)

            if self.settings.data_defined_properties.isActive(PlotSettings.PROPERTY_COLOR) and (not aggregating or not executed):
                default_value = QColor(self.settings.properties['in_color'])
                value, conversion_success = self.settings.data_defined_properties.valueAsColor(PlotSettings.PROPERTY_COLOR, context,
                                                                                               default_value)
                if conversion_success:
                    # We were given a valid color specification, use that color
                    colors.append(value.name())
                else:
                    try:
                        # Attempt to interpret the value as a list of color specifications
                        value_list = self.settings.data_defined_properties.value(
                            PlotSettings.PROPERTY_COLOR, context)
                        color_list = [QgsSymbolLayerUtils.decodeColor(
                            item).name() for item in value_list]
                        colors.extend(color_list)
                    except TypeError:
                        # Not a list of color specifications, use the default color instead
                        colors.append(default_value.name())

            if self.settings.data_defined_properties.isActive(PlotSettings.PROPERTY_STROKE_COLOR) and (not aggregating or not executed):
                default_value = QColor(self.settings.properties['out_color'])
                value, conversion_success = self.settings.data_defined_properties.valueAsColor(PlotSettings.PROPERTY_STROKE_COLOR, context,
                                                                                               default_value)
                if conversion_success:
                    # We were given a valid color specification, use that color
                    stroke_colors.append(value.name())
                else:
                    try:
                        # Attempt to interpret the value as a list of color specifications
                        value_list = self.settings.data_defined_properties.value(
                            PlotSettings.PROPERTY_STROKE_COLOR, context)
                        color_list = [QgsSymbolLayerUtils.decodeColor(
                            item).name() for item in value_list]
                        stroke_colors.extend(color_list)
                    except TypeError:
                        # Not a list of color specifications, use the default color instead
                        stroke_colors.append(default_value.name())

            executed = True

        self.settings.additional_hover_text = additional_hover_text
        self.settings.x = xx
        self.settings.y = yy
        self.settings.z = zz
        if marker_sizes:
            self.settings.data_defined_marker_sizes = marker_sizes
        if colors:
            self.settings.data_defined_colors = colors
        if stroke_colors:
            self.settings.data_defined_stroke_colors = stroke_colors
        if stroke_widths:
            self.settings.data_defined_stroke_widths = stroke_widths

        # Restore the original subset string
        self.source_layer.setSubsetString(original_subset_string)