Example #1
0
    def add_layer_to_map(item: QStandardItem):
        """
        Add a layer to the map
        :param layer:
        :return:
        """

        # No multiselect so there is only ever one item
        pt_data: ProjectTreeData = item.data(Qt.UserRole)
        project = pt_data.project
        map_layer: QRaveMapLayer = pt_data.data

        settings = Settings()

        # Loop over all the parent group layers for this raster
        # ensuring they are in the tree in correct, nested order
        ancestry = []
        if map_layer.exists is True:
            parent = item.parent()
            while parent is not None and len(ancestry) < 50:
                ancestry.append((parent.text(), parent.row()))
                parent = parent.parent()
        else:
            # Layer does not exist. do not try to put it on the map
            return

        ancestry.reverse()
        parentGroup = None
        for agroup in ancestry:
            parentGroup = QRaveMapLayer._addgrouptomap(agroup[0], agroup[1],
                                                       parentGroup)

        assert parentGroup, "All rasters should be nested and so parentGroup should be instantiated by now"

        # Loop over all the parent group layers for this raster
        # ensuring they are in the tree in correct, nested order

        # Only add the layer if it's not already in the registry
        exists = False
        existing_layers = QgsProject.instance().mapLayersByName(
            map_layer.label)
        layers_ancestry = [
            QRaveMapLayer.get_layer_ancestry(lyr) for lyr in existing_layers
        ]

        # Now we compare the ancestry group labels to the business logic ancestry branch names
        # to see if this layer is already in the map
        for lyr in layers_ancestry:
            if len(lyr) == len(ancestry) \
                    and all(iter([ancestry[x][0] == lyr[x] for x in range(len(ancestry))])):
                exists = True
                break

        if not exists:
            layer_uri = map_layer.layer_uri
            rOutput = None
            # This might be a basemap
            if map_layer.layer_type == QRaveMapLayer.LayerTypes.WEBTILE:
                rOutput = QgsRasterLayer(layer_uri, map_layer.label, 'wms')

            elif map_layer.layer_type in [
                    QRaveMapLayer.LayerTypes.LINE,
                    QRaveMapLayer.LayerTypes.POLYGON,
                    QRaveMapLayer.LayerTypes.POINT
            ]:
                if map_layer.layer_name is not None:
                    layer_uri += "|layername={}".format(map_layer.layer_name)
                rOutput = QgsVectorLayer(layer_uri, map_layer.label, "ogr")

            elif map_layer.layer_type == QRaveMapLayer.LayerTypes.RASTER:
                # Raster
                rOutput = QgsRasterLayer(layer_uri, map_layer.label)

            if rOutput is not None:
                ##########################################
                # Symbology
                ##########################################

                symbology = map_layer.bl_attr[
                    'symbology'] if map_layer.bl_attr is not None and 'symbology' in map_layer.bl_attr else None
                # If the business logic has symbology defined
                if symbology is not None:
                    qml_fname = '{}.qml'.format(symbology)
                    os.path.abspath(
                        os.path.join(project.project_dir, qml_fname))

                    # Here are the search paths for QML files in order of precedence
                    hierarchy = [
                        os.path.abspath(
                            os.path.join(project.project_dir, qml_fname)),
                        # This is the default one
                        os.path.abspath(
                            os.path.join(SYMBOLOGY_DIR, project.project_type,
                                         qml_fname)),
                        os.path.abspath(
                            os.path.join(SYMBOLOGY_DIR, 'Shared', qml_fname))
                    ]
                    # Find the first match
                    try:
                        chosen_qml = next(
                            iter([
                                candidate for candidate in hierarchy
                                if os.path.isfile(candidate)
                            ]))
                        # Report to the terminal if we couldn't find a qml file to use
                        if chosen_qml is None:
                            settings.msg_bar(
                                "Missing Symbology",
                                "Could not find a valid .qml symbology file for layer {}. Search paths: [{}]"
                                .format(layer_uri, ', '.join(hierarchy)),
                                level=Qgis.Warning)
                        # Apply the QML file
                        else:
                            rOutput.loadNamedStyle(chosen_qml)

                    except StopIteration:
                        settings.log(
                            'Could not find valid symbology for layer at any of the following search paths: [ {} ]'
                            .format(', '.join(hierarchy)), Qgis.Warning)

                ############################################################
                # Transparency. A few notes:
                # - QML transparency will prevail for rasters before 3.18
                # - We set this here so that QML layer transparency will be
                #   overruled
                ############################################################
                transparency = 0

                try:
                    if 'transparency' in map_layer.bl_attr:
                        transparency = int(map_layer.bl_attr['transparency'])
                except Exception as e:
                    settings.log(
                        'Error deriving transparency from layer: {}'.format(e))

                try:
                    if transparency > 0:
                        if rOutput.__class__ is QgsVectorLayer:
                            rOutput.setLayerTransparency(transparency)
                            # rOutput.triggerRepaint()
                        elif rOutput.__class__ is QgsRasterLayer:
                            renderer = rOutput.renderer()
                            renderer.setOpacity((100 - transparency) / 100.0)
                            # rOutput.triggerRepaint()
                except Exception as e:
                    settings.log(
                        'Error deriving transparency from layer: {}'.format(e))

                QgsProject.instance().addMapLayer(rOutput, False)
                parentGroup.insertLayer(item.row(), rOutput)

        # if the layer already exists trigger a refresh
        else:
            QgsProject.instance().mapLayersByName(
                map_layer.label)[0].triggerRepaint()