Exemple #1
0
    def testTakeLayer(self):
        # test taking ownership of a layer from the project
        l1 = createLayer('l1')
        l2 = createLayer('l2')
        p = QgsProject()

        # add one layer to project
        p.addMapLayer(l1)
        self.assertEqual(p.mapLayers(), {l1.id(): l1})
        self.assertEqual(l1.parent().parent(), p)

        # try taking some layers which don't exist in project
        self.assertFalse(p.takeMapLayer(None))
        self.assertFalse(p.takeMapLayer(l2))
        # but l2 should still exist..
        self.assertTrue(l2.isValid())

        # take layer from project
        self.assertEqual(p.takeMapLayer(l1), l1)
        self.assertFalse(p.mapLayers())  # no layers left
        # but l1 should still exist
        self.assertTrue(l1.isValid())
        # layer should have no parent now
        self.assertFalse(l1.parent())

        # destroy project
        p = None
        self.assertTrue(l1.isValid())
    def testProject(self):
        layer = QgsVectorLayer('{}|layername=countries'.format(ABSOLUTE_PATH),
                               'Test', 'ogr')

        # write
        p = QgsProject()
        fh = NamedTemporaryFile(delete=False)
        p.setFileName(fh.name)
        p.addMapLayer(layer)
        self.assertTrue(p.write())
        found = False
        with open(fh.name) as fh:
            for line in fh:
                if '<datasource>localized:data/world_map.gpkg|layername=countries</datasource>' in line:
                    found = True
                    break
        self.assertTrue(found)

        # read
        p2 = QgsProject()
        p2.setFileName(fh.name)
        p2.read()
        self.assertTrue(len(p2.mapLayers()))
        self.assertEqual(
            p2.mapLayers()[layer.id()].source(),
            '{}/{}|layername=countries'.format(BASE_PATH, MAP_PATH))

        os.remove(fh.name)
Exemple #3
0
    def testTakeLayer(self):
        # test taking ownership of a layer from the project
        l1 = createLayer('l1')
        l2 = createLayer('l2')
        p = QgsProject()

        # add one layer to project
        p.addMapLayer(l1)
        self.assertEqual(p.mapLayers(), {l1.id(): l1})
        self.assertEqual(l1.parent().parent(), p)

        # try taking some layers which don't exist in project
        self.assertFalse(p.takeMapLayer(None))
        self.assertFalse(p.takeMapLayer(l2))
        # but l2 should still exist..
        self.assertTrue(l2.isValid())

        # take layer from project
        self.assertEqual(p.takeMapLayer(l1), l1)
        self.assertFalse(p.mapLayers()) # no layers left
        # but l1 should still exist
        self.assertTrue(l1.isValid())
        # layer should have no parent now
        self.assertFalse(l1.parent())

        # destroy project
        p = None
        self.assertTrue(l1.isValid())
    def testSaveLoadProject(self):

        schema_uri = encode_uri(self.ds_uri, 'qgis_test')
        project_uri = encode_uri(self.ds_uri, 'qgis_test', 'abc')

        self.dropProjectsTable()  # make sure we have a clean start

        prj = QgsProject()
        uri = self.vl.source()
        vl1 = QgsVectorLayer(uri, 'test', 'postgres')
        self.assertEqual(vl1.isValid(), True)
        prj.addMapLayer(vl1)

        prj_storage = QgsApplication.projectStorageRegistry().projectStorageFromType("postgresql")
        self.assertTrue(prj_storage)

        lst0 = prj_storage.listProjects(schema_uri)
        self.assertEqual(lst0, [])

        # try to save project in the database

        prj.setFileName(project_uri)
        res = prj.write()
        self.assertTrue(res)

        lst1 = prj_storage.listProjects(schema_uri)
        self.assertEqual(lst1, ["abc"])

        # now try to load the project back

        prj2 = QgsProject()
        prj2.setFileName(project_uri)
        res = prj2.read()
        self.assertTrue(res)

        self.assertEqual(len(prj2.mapLayers()), 1)

        self.assertEqual(prj2.baseName(), "abc")
        self.assertEqual(prj2.absoluteFilePath(), "")  # path not supported for project storages
        self.assertTrue(abs(prj2.lastModified().secsTo(QDateTime.currentDateTime())) < 10)

        # try to see project's metadata

        res, metadata = prj_storage.readProjectStorageMetadata(project_uri)
        self.assertTrue(res)
        self.assertEqual(metadata.name, "abc")
        time_project = metadata.lastModified
        time_now = QDateTime.currentDateTime()
        time_diff = time_now.secsTo(time_project)
        self.assertTrue(abs(time_diff) < 10)

        # try to remove the project

        res = prj_storage.removeProject(project_uri)
        self.assertTrue(res)

        lst2 = prj_storage.listProjects(schema_uri)
        self.assertEqual(lst2, [])

        self.dropProjectsTable()  # make sure we have a clean finish... "leave no trace"
Exemple #5
0
    def test_zip_unzip(self):
        tmpDir = QTemporaryDir()
        tmpFile = "{}/project.qgz".format(tmpDir.path())

        project = QgsProject()

        l0 = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "points.shp"), "points", "ogr")
        l1 = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "lines.shp"), "lines", "ogr")
        project.addMapLayers([l0, l1])

        self.assertTrue(project.write(tmpFile))

        project2 = QgsProject()
        self.assertFalse(project2.isZipped())
        self.assertTrue(project2.fileName() == "")
        self.assertTrue(project2.read(tmpFile))
        self.assertTrue(project2.isZipped())
        self.assertTrue(project2.fileName() == tmpFile)
        layers = project2.mapLayers()

        self.assertEqual(len(layers.keys()), 2)
        self.assertTrue(layers[l0.id()].isValid(), True)
        self.assertTrue(layers[l1.id()].isValid(), True)

        project2.clear()
        self.assertFalse(project2.isZipped())
Exemple #6
0
    def test_zip_unzip(self):
        tmpDir = QTemporaryDir()
        tmpFile = "{}/project.qgz".format(tmpDir.path())

        project = QgsProject()

        l0 = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "points.shp"), "points", "ogr")
        l1 = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "lines.shp"), "lines", "ogr")
        project.addMapLayers([l0, l1])

        self.assertTrue(project.write(tmpFile))

        project2 = QgsProject()
        self.assertFalse(project2.isZipped())
        self.assertTrue(project2.fileName() == "")
        self.assertTrue(project2.read(tmpFile))
        self.assertTrue(project2.isZipped())
        self.assertTrue(project2.fileName() == tmpFile)
        layers = project2.mapLayers()

        self.assertEqual(len(layers.keys()), 2)
        self.assertTrue(layers[l0.id()].isValid(), True)
        self.assertTrue(layers[l1.id()].isValid(), True)

        project2.clear()
        self.assertFalse(project2.isZipped())
Exemple #7
0
    def testSaveLoadProject(self):

        schema_uri = encode_uri(self.ds_uri, 'qgis_test')
        project_uri = encode_uri(self.ds_uri, 'qgis_test', 'abc')

        self.dropProjectsTable()  # make sure we have a clean start

        prj = QgsProject()
        uri = self.vl.source()
        vl1 = QgsVectorLayer(uri, 'test', 'postgres')
        self.assertEqual(vl1.isValid(), True)
        prj.addMapLayer(vl1)

        prj_storage = QgsApplication.projectStorageRegistry().projectStorageFromType("postgresql")
        self.assertTrue(prj_storage)

        lst0 = prj_storage.listProjects(schema_uri)
        self.assertEqual(lst0, [])

        # try to save project in the database

        prj.setFileName(project_uri)
        res = prj.write()
        self.assertTrue(res)

        lst1 = prj_storage.listProjects(schema_uri)
        self.assertEqual(lst1, ["abc"])

        # now try to load the project back

        prj2 = QgsProject()
        prj2.setFileName(project_uri)
        res = prj2.read()
        self.assertTrue(res)

        self.assertEqual(len(prj2.mapLayers()), 1)

        self.assertEqual(prj2.baseName(), "abc")
        self.assertEqual(prj2.absoluteFilePath(), "")  # path not supported for project storages
        self.assertTrue(abs(prj2.lastModified().secsTo(QDateTime.currentDateTime())) < 10)

        # try to see project's metadata

        res, metadata = prj_storage.readProjectStorageMetadata(project_uri)
        self.assertTrue(res)
        self.assertEqual(metadata.name, "abc")
        time_project = metadata.lastModified
        time_now = QDateTime.currentDateTime()
        time_diff = time_now.secsTo(time_project)
        self.assertTrue(abs(time_diff) < 10)

        # try to remove the project

        res = prj_storage.removeProject(project_uri)
        self.assertTrue(res)

        lst2 = prj_storage.listProjects(schema_uri)
        self.assertEqual(lst2, [])

        self.dropProjectsTable()  # make sure we have a clean finish... "leave no trace"
def test_can_load_project(data):
    """ Check if project can be loaded
    """
    source = str(data / "france_parts.qgs")
    project = QgsProject()
    project.read(source)

    assert len(project.mapLayers()) >= 1
Exemple #9
0
def findVectorLayer(layername: str, project: QgsProject) -> QgsVectorLayer:
    """ Find vector layer with name, short name or layer id """
    for layer in project.mapLayers().values():
        # only vector layer
        if layer.type() != QgsMapLayer.VectorLayer:
            continue
        # check name
        if layer.name() == layername:
            return layer
        # check short name
        if layer.shortName() == layername:
            return layer
        # check layer id
        if layer.id() == layername:
            return layer
    return None
Exemple #10
0
def get_project_summary(key: str, project: QgsProject):
    """ Return json summary for cached project
    """
    def layer_summary(layer_id: str, layer: QgsMapLayer):
        return dict(
            id=layer_id,
            name=layer.name(),
            source=layer.publicSource(),
            crs=layer.crs().userFriendlyIdentifier(),
            valid=layer.isValid(),
            spatial=layer.isSpatial(),
        )

    layers = [
        layer_summary(idstr, l) for (idstr, l) in project.mapLayers().items()
    ]

    return dict(cache_key=key,
                filename=project.fileName(),
                bad_layers_count=sum(1 for ls in layers if not ls['valid']),
                layers=layers,
                crs=project.crs().userFriendlyIdentifier(),
                last_modified=project.lastModified().toString(Qt.ISODate))
Exemple #11
0
    def populateLayerTable(self, layerType):
        """
        Fill the table for a given layer type
        """
        # Get parameters for the widget
        lt = self.layersTable[layerType]
        table = lt['tableWidget']

        # Reset layerBoardChangedData
        self.layerBoardChangedData[layerType] = {}

        # disconnect itemChanged signal
        try:
            table.itemChanged.disconnect()
        except Exception:
            pass

        attributes = self.layersTable['generic']['attributes'] + lt['attributes']
        self.layersAttributes[layerType] = attributes

        self.layerBoardData[layerType] = []
        headerData = [a['key'] for a in attributes]
        self.layerBoardData[layerType].append(headerData)

        # empty previous content
        for row in range(table.rowCount()):
            table.removeRow(row)
        table.setRowCount(0)
        table.setColumnCount(0)

        # create columns and header row
        columns = [a['key'] for a in attributes]
        columnsLabels = [a['label'] for a in attributes]
        colCount = len(columns)
        table.setColumnCount(colCount)
        table.setHorizontalHeaderLabels(tuple(columnsLabels))

        # load content from project layers
        lr = QgsProject().instance()
        for lid in lr.mapLayers():
            layer = lr.mapLayer(lid)

            if layerType == 'vector' and layer.type() != QgsMapLayer.VectorLayer:
                continue
            if layerType == 'raster' and layer.type() != QgsMapLayer.RasterLayer:
                continue

            # Add layer in the layerBoardChangedData
            self.layerBoardChangedData[layerType][lid] = {}
            lineData = []

            # Set row and column count
            twRowCount = table.rowCount()
            # add a new line
            table.setRowCount(twRowCount + 1)
            table.setColumnCount(colCount)
            i = 0

            # get information
            for attr in attributes:
                newItem = QTableWidgetItem()
                newItem.setToolTip(layer.name())

                if layerType == 'vector' and not layer.isSpatial() and attr.get('spatial_only'):
                    newItem.setFlags(Qt.NoItemFlags)
                # Is editable or not
                elif attr.get('editable'):
                    newItem.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEditable | Qt.ItemIsEnabled)
                else:
                    newItem.setFlags(Qt.ItemIsSelectable)

                # Item value
                if layerType == 'vector' and not layer.isSpatial() and attr.get('spatial_only'):
                    value = None
                else:
                    value = self.getLayerProperty(layer, attr['key'])
                newItem.setData(Qt.EditRole, value)

                # Add cell data to lineData
                # encode it in the file system encoding, only if needed
                # TODO DISABLED due to migration to Python 3, related to CSV export
                # if hasattr(value, 'encode'):
                #     value = value.encode(sys.getfilesystemencoding())
                lineData.append(value)

                if attr['key'] == 'name':
                    icon = QgsMapLayerModel.iconForLayer(layer)
                    newItem.setIcon(icon)

                # Add item
                table.setItem(twRowCount, i, newItem)
                i += 1

            # Add data to layerBoardData
            self.layerBoardData[layerType].append(lineData)

        # Launch slot on item changed slot
        slot = partial(self.onItemChanged, layerType)
        table.itemChanged.connect(slot)
Exemple #12
0
    def testProjectStorage(self):
        # New project without fileName
        p0 = QgsProject()
        self.assertTrue(p0.auxiliaryStorage().isValid())

        # Create new layers with key otherwise auxiliary layers are not
        # automacially created when added in project
        vl0 = createLayer()
        vl0Shp = writeShape(vl0, 'vl0.shp')

        vl1 = createLayer()
        vl1Shp = writeShape(vl1, 'vl1.shp')

        vl0 = QgsVectorLayer(vl0Shp, 'points', 'ogr')
        self.assertTrue(vl0.isValid())

        vl1 = QgsVectorLayer(vl1Shp, 'points', 'ogr')
        self.assertTrue(vl1.isValid())

        # Add layers to project and check underlying auxiliary layers
        p0.addMapLayers([vl0, vl1])

        self.assertTrue(vl0.loadAuxiliaryLayer(p0.auxiliaryStorage(), 'pk'))
        self.assertTrue(vl1.loadAuxiliaryLayer(p0.auxiliaryStorage(), 'num_char'))

        al0 = vl0.auxiliaryLayer()
        al1 = vl1.auxiliaryLayer()

        self.assertEqual(al0.joinInfo().targetFieldName(), 'pk')
        self.assertEqual(al1.joinInfo().targetFieldName(), 'num_char')

        # Add a field in auxiliary layers
        pdef0 = QgsPropertyDefinition('propname', QgsPropertyDefinition.DataTypeNumeric, '', '', 'ut')
        self.assertTrue(al0.addAuxiliaryField(pdef0))

        pdef1 = QgsPropertyDefinition('propname1', QgsPropertyDefinition.DataTypeString, '', '', 'ut')
        self.assertTrue(al1.addAuxiliaryField(pdef1))

        # Check auxiliary fields names
        af0Name = QgsAuxiliaryLayer.nameFromProperty(pdef0, False)
        self.assertEqual(af0Name, 'ut_propname')
        af1Name = QgsAuxiliaryLayer.nameFromProperty(pdef1, False)
        self.assertEqual(af1Name, 'ut_propname1')

        # Set value for auxiliary fields
        req = QgsFeatureRequest().setFilterExpression("name = 'Honey'")
        f = QgsFeature()
        vl0.getFeatures(req).nextFeature(f)
        self.assertTrue(f.isValid())
        af0Name = QgsAuxiliaryLayer.nameFromProperty(pdef0, True)
        index0 = vl0.fields().indexOf(af0Name)
        vl0.changeAttributeValue(f.id(), index0, 333)

        req = QgsFeatureRequest().setFilterExpression("name = 'Apple'")
        f = QgsFeature()
        vl1.getFeatures(req).nextFeature(f)
        self.assertTrue(f.isValid())
        af1Name = QgsAuxiliaryLayer.nameFromProperty(pdef1, True)
        index1 = vl1.fields().indexOf(af1Name)
        vl1.changeAttributeValue(f.id(), index0, 'myvalue')

        req = QgsFeatureRequest().setFilterExpression("name = 'Orange'")
        f = QgsFeature()
        vl1.getFeatures(req).nextFeature(f)
        self.assertTrue(f.isValid())
        vl1.changeAttributeValue(f.id(), index0, 'myvalue1')

        # Save the project in a zip file
        f = tmpPath() + '.qgz'
        p0.write(f)

        # Open the zip file with embedded auxiliary storage
        p1 = QgsProject()
        p1.read(f)

        # Check that auxiliary fields are well loaded in layers
        self.assertEqual(len(p1.mapLayers().values()), 2)

        for vl in p1.mapLayers().values():
            al = vl.auxiliaryLayer()
            self.assertEqual(len(al.auxiliaryFields()), 1)

            af = al.auxiliaryFields()[0]
            afPropDef = QgsAuxiliaryLayer.propertyDefinitionFromField(af)
            self.assertEqual(afPropDef.origin(), 'ut')

            if vl.auxiliaryLayer().joinInfo().targetFieldName() == 'pk':
                self.assertEqual(afPropDef.name(), 'propname')
                self.assertEqual(al.featureCount(), 1)

                req = QgsFeatureRequest().setFilterExpression("name = 'Honey'")
                f = QgsFeature()
                vl.getFeatures(req).nextFeature(f)
                self.assertTrue(f.isValid())
                self.assertEqual(f.attributes()[index0], 333.0)
            else: # num_char
                self.assertEqual(al.featureCount(), 2)
                self.assertEqual(afPropDef.name(), 'propname1')

                req = QgsFeatureRequest().setFilterExpression("name = 'Apple'")
                f = QgsFeature()
                vl.getFeatures(req).nextFeature(f)
                self.assertTrue(f.isValid())
                self.assertEqual(f.attributes()[index1], 'myvalue')

                req = QgsFeatureRequest().setFilterExpression("name = 'Orange'")
                f = QgsFeature()
                vl.getFeatures(req).nextFeature(f)
                self.assertTrue(f.isValid())
                self.assertEqual(f.attributes()[index1], 'myvalue1')
Exemple #13
0
    def _convert(self, project: QgsProject) -> None:
        project.baseName()
        xml_elements_to_preserve = {}
        on_original_project_read = self._on_original_project_read_wrapper(
            xml_elements_to_preserve)
        project.readProject.connect(on_original_project_read)

        if self.export_type == ExportType.Cable:
            # the `backup_filename` is copied right after packaging is requested. It has all the unsaved
            # project settings, which means they will be available in the packaged project too.
            project.read(self.backup_filename)
        elif self.export_type == ExportType.Cloud:
            # if you save the project without QGIS GUI, the project no longer has `theMapCanvas` canvas
            # so we should use the original project file that already has `theMapCanvas`. There is no
            # gain using the `backup_filename`, since there is no user to modify the project.
            project.read(project.fileName())
        else:
            raise NotImplementedError(
                f"Unknown package type: {self.export_type}")

        project.readProject.disconnect(on_original_project_read)

        self.export_folder.mkdir(parents=True, exist_ok=True)
        self.total_progress_updated.emit(0, 100,
                                         self.trUtf8("Converting project…"))
        self.__layers = list(project.mapLayers().values())

        # We store the pks of the original vector layers
        for layer in self.__layers:
            pk_names = None
            if layer.type() == QgsMapLayer.VectorLayer:
                pk_names = []
                for idx in layer.primaryKeyAttributes():
                    pk_name = layer.fields()[idx].name()
                    # and we check that the primary key fields names don't have a comma in the name
                    if "," in pk_name:
                        raise ValueError("Comma in field names not allowed")
                    pk_names.append(pk_name)
                    layer.setCustomProperty("QFieldSync/sourceDataPrimaryKeys",
                                            ",".join(pk_names))

            layer_data: LayerData = {
                "id": layer.id(),
                "name": layer.name(),
                "type": layer.type(),
                "source": layer.source(),
                "fields": layer.fields() if hasattr(layer, "fields") else None,
                "pk_names": pk_names,
            }

            self.__layer_data_by_id[layer.id()] = layer_data
            self.__layer_data_by_name[layer.name()] = layer_data

        if self.create_basemap and self.project_configuration.create_base_map:
            self._export_basemap()

        # Loop through all layers and copy/remove/offline them
        copied_files = list()
        non_ascii_filename_layers: Dict[str, str] = {}
        non_utf8_encoding_layers: Dict[str, str] = {}
        for layer_idx, layer in enumerate(self.__layers):
            self.total_progress_updated.emit(
                layer_idx - len(self.__offline_layers),
                len(self.__layers),
                self.trUtf8("Copying layers…"),
            )

            layer_source = LayerSource(layer)
            layer_action = (layer_source.action if self.export_type
                            == ExportType.Cable else layer_source.cloud_action)

            if not layer.isValid():
                project.removeMapLayer(layer)
                continue

            if not layer_source.is_supported:
                project.removeMapLayer(layer)
                continue

            if layer_source.is_file and not isascii(layer_source.filename):
                non_ascii_filename_layers[layer.name()] = layer_source.filename

            if layer_source.is_localized_path:
                continue

            if (layer.type() == QgsMapLayer.VectorLayer
                    and layer.dataProvider()
                    and layer.dataProvider().encoding() != "UTF-8"
                    # some providers return empty string as encoding, just ignore them
                    and layer.dataProvider().encoding() != ""):
                non_utf8_encoding_layers[
                    layer.name()] = layer.dataProvider().encoding()

            if layer_action == SyncAction.OFFLINE:
                if self.project_configuration.offline_copy_only_aoi:
                    extent = QgsCoordinateTransform(
                        QgsCoordinateReferenceSystem(
                            self.area_of_interest_crs),
                        layer.crs(),
                        QgsProject.instance(),
                    ).transformBoundingBox(self.area_of_interest.boundingBox())
                    layer.selectByRect(extent)

                if not layer.selectedFeatureCount():
                    layer.selectByIds([FID_NULL])

                self.__offline_layers.append(layer)
                self.__offline_layer_names.append(layer.name())
            elif (layer_action == SyncAction.COPY
                  or layer_action == SyncAction.NO_ACTION):
                copied_files = layer_source.copy(self.export_folder,
                                                 copied_files)
            elif layer_action == SyncAction.KEEP_EXISTENT:
                layer_source.copy(self.export_folder, copied_files, True)
            elif layer_action == SyncAction.REMOVE:
                project.removeMapLayer(layer)

        if non_ascii_filename_layers:
            layers = ", ".join([
                f'"{name}" at "{path}"'
                for name, path in non_ascii_filename_layers.items()
            ])
            message = self.tr(
                "Some layers are stored at file paths that are not ASCII encoded: {}. Working with paths that are not in ASCII might cause problems. It is highly recommended to rename them to ASCII encoded paths."
            ).format(layers)
            self.warning.emit(self.tr("QFieldSync"), message)

        if non_utf8_encoding_layers:
            layers = ", ".join([
                f"{name} ({encoding})"
                for name, encoding in non_utf8_encoding_layers.items()
            ])
            message = self.tr(
                "Some layers do not use UTF-8 encoding: {}. Working with layers that do not use UTF-8 encoding might cause problems. It is highly recommended to convert them to UTF-8 encoded layers."
            ).format(layers)
            self.warning.emit(self.tr("QFieldSync"), message)

        export_project_filename = self.export_folder.joinpath(
            f"{self.original_filename.stem}_qfield.qgs")

        # save the original project path
        self.project_configuration.original_project_path = str(
            self.original_filename)

        # save the offline project twice so that the offline plugin can "know" that it's a relative path
        QgsProject.instance().write(str(export_project_filename))

        # export the DCIM folder
        copy_images(
            str(self.original_filename.parent.joinpath("DCIM")),
            str(export_project_filename.parent.joinpath("DCIM")),
        )
        try:
            # Run the offline plugin for gpkg
            gpkg_filename = "data.gpkg"
            if self.__offline_layers:
                offline_layer_ids = [o_l.id() for o_l in self.__offline_layers]

                if not self.offline_editing.convertToOfflineProject(
                        str(self.export_folder),
                        gpkg_filename,
                        offline_layer_ids,
                        self.project_configuration.offline_copy_only_aoi,
                        self.offline_editing.GPKG,
                        None,
                ):
                    raise Exception(
                        self.
                        tr("QGIS Offline editing error: failed to convert layers to offline layers"
                           ))
        except AttributeError:
            # Run the offline plugin for spatialite
            spatialite_filename = "data.sqlite"
            if self.__offline_layers:
                offline_layer_ids = [o_l.id() for o_l in self.__offline_layers]

                if not self.offline_editing.convertToOfflineProject(
                        str(self.export_folder),
                        spatialite_filename,
                        offline_layer_ids,
                        self.project_configuration.offline_copy_only_aoi,
                        self.offline_editing.SpatiaLite,
                        None,
                ):
                    raise Exception(
                        self.
                        tr("QGIS Offline editing error: failed to convert layers to offline layers"
                           ))

        # Disable project options that could create problems on a portable
        # project with offline layers
        self.post_process_layers()

        # Now we have a project state which can be saved as offline project
        on_original_project_write = self._on_original_project_write_wrapper(
            xml_elements_to_preserve)
        project.writeProject.connect(on_original_project_write)
        QgsProject.instance().write(str(export_project_filename))
        project.writeProject.disconnect(on_original_project_write)
Exemple #14
0
def get_memory_layers(project: QgsProject) -> List[QgsMapLayer]:
    return [
        layer for layer in project.mapLayers().values()
        if layer.isValid() and layer.dataProvider().name() == "memory"
    ]
Exemple #15
0
    def testProjectStorage(self):
        # New project without fileName
        p0 = QgsProject()
        self.assertTrue(p0.auxiliaryStorage().isValid())

        # Create new layers with key otherwise auxiliary layers are not
        # automacially created when added in project
        vl0 = createLayer()
        vl0Shp = writeShape(vl0, 'vl0.shp')

        vl1 = createLayer()
        vl1Shp = writeShape(vl1, 'vl1.shp')

        vl0 = QgsVectorLayer(vl0Shp, 'points', 'ogr')
        self.assertTrue(vl0.isValid())

        vl1 = QgsVectorLayer(vl1Shp, 'points', 'ogr')
        self.assertTrue(vl1.isValid())

        # Add layers to project and check underlying auxiliary layers
        p0.addMapLayers([vl0, vl1])

        self.assertTrue(vl0.loadAuxiliaryLayer(p0.auxiliaryStorage(), 'pk'))
        self.assertTrue(
            vl1.loadAuxiliaryLayer(p0.auxiliaryStorage(), 'num_char'))

        al0 = vl0.auxiliaryLayer()
        al1 = vl1.auxiliaryLayer()

        self.assertEqual(al0.joinInfo().targetFieldName(), 'pk')
        self.assertEqual(al1.joinInfo().targetFieldName(), 'num_char')

        # Add a field in auxiliary layers
        pdef0 = QgsPropertyDefinition('propname',
                                      QgsPropertyDefinition.DataTypeNumeric,
                                      '', '', 'ut')
        self.assertTrue(al0.addAuxiliaryField(pdef0))

        pdef1 = QgsPropertyDefinition('propname1',
                                      QgsPropertyDefinition.DataTypeString, '',
                                      '', 'ut')
        self.assertTrue(al1.addAuxiliaryField(pdef1))

        # Check auxiliary fields names
        af0Name = QgsAuxiliaryLayer.nameFromProperty(pdef0, False)
        self.assertEqual(af0Name, 'ut_propname')
        af1Name = QgsAuxiliaryLayer.nameFromProperty(pdef1, False)
        self.assertEqual(af1Name, 'ut_propname1')

        # Set value for auxiliary fields
        req = QgsFeatureRequest().setFilterExpression("name = 'Honey'")
        f = QgsFeature()
        vl0.getFeatures(req).nextFeature(f)
        self.assertTrue(f.isValid())
        af0Name = QgsAuxiliaryLayer.nameFromProperty(pdef0, True)
        index0 = vl0.fields().indexOf(af0Name)
        vl0.changeAttributeValue(f.id(), index0, 333)

        req = QgsFeatureRequest().setFilterExpression("name = 'Apple'")
        f = QgsFeature()
        vl1.getFeatures(req).nextFeature(f)
        self.assertTrue(f.isValid())
        af1Name = QgsAuxiliaryLayer.nameFromProperty(pdef1, True)
        index1 = vl1.fields().indexOf(af1Name)
        vl1.changeAttributeValue(f.id(), index0, 'myvalue')

        req = QgsFeatureRequest().setFilterExpression("name = 'Orange'")
        f = QgsFeature()
        vl1.getFeatures(req).nextFeature(f)
        self.assertTrue(f.isValid())
        vl1.changeAttributeValue(f.id(), index0, 'myvalue1')

        # Save the project in a zip file
        f = tmpPath() + '.qgz'
        p0.write(f)

        # Open the zip file with embedded auxiliary storage
        p1 = QgsProject()
        p1.read(f)

        # Check that auxiliary fields are well loaded in layers
        self.assertEqual(len(p1.mapLayers().values()), 2)

        for vl in p1.mapLayers().values():
            al = vl.auxiliaryLayer()
            self.assertEqual(len(al.auxiliaryFields()), 1)

            af = al.auxiliaryFields()[0]
            afPropDef = QgsAuxiliaryLayer.propertyDefinitionFromField(af)
            self.assertEqual(afPropDef.origin(), 'ut')

            if vl.auxiliaryLayer().joinInfo().targetFieldName() == 'pk':
                self.assertEqual(afPropDef.name(), 'propname')
                self.assertEqual(al.featureCount(), 1)

                req = QgsFeatureRequest().setFilterExpression("name = 'Honey'")
                f = QgsFeature()
                vl.getFeatures(req).nextFeature(f)
                self.assertTrue(f.isValid())
                self.assertEqual(f.attributes()[index0], 333.0)
            else:  # num_char
                self.assertEqual(al.featureCount(), 2)
                self.assertEqual(afPropDef.name(), 'propname1')

                req = QgsFeatureRequest().setFilterExpression("name = 'Apple'")
                f = QgsFeature()
                vl.getFeatures(req).nextFeature(f)
                self.assertTrue(f.isValid())
                self.assertEqual(f.attributes()[index1], 'myvalue')

                req = QgsFeatureRequest().setFilterExpression(
                    "name = 'Orange'")
                f = QgsFeature()
                vl.getFeatures(req).nextFeature(f)
                self.assertTrue(f.isValid())
                self.assertEqual(f.attributes()[index1], 'myvalue1')
Exemple #16
0
QgsApplication.initQgis()

# Open the project
p = QgsProject()
p.read(project_path)
canvas = QgsMapCanvas()
bridge = QgsLayerTreeMapCanvasBridge(
    p.layerTreeRoot(),
    canvas
)
bridge.setCanvasLayers()

# Get the layers in the project
layerList = p.mapLayersByName(parcelle_layer)
if not layerList:
    layers = p.mapLayers()
    for lname, layer in layers.items():
        print(lname + ' ' + layer.name() + ' ' + parcelle_layer)
    layerList = [layer for lname, layer in layers.items() if layer.name() == parcelle_layer]
layer = layerList[0]

# Get Feature
req = QgsFeatureRequest()
req.setFilterExpression(' "geo_parcelle" = \'%s\' ' % parcelle_id)
it = layer.getFeatures(req)
feat = None
for f in it:
    feat = f
    break

# Get connecion params
Exemple #17
0
    def setUpTestData(cls):

        super().setUpTestData()

        cls.temp_dir = QTemporaryDir()
        cls.temp_project_path = os.path.join(cls.temp_dir.path(),
                                             'pg_openrouteservice.qgs')

        # Create test layer
        conn_str = "dbname='{NAME}' host={HOST} port={PORT} user='******' password='******' sslmode=disable".format(
            **settings.DATABASES['default'])

        cls.conn_uri = conn_str

        md = QgsProviderRegistry.instance().providerMetadata('postgres')

        conn = md.createConnection(conn_str, {})

        conn.executeSql(
            "DROP SCHEMA IF EXISTS \"openrouteservice test\" CASCADE")
        conn.executeSql("CREATE SCHEMA \"openrouteservice test\"")
        conn.executeSql(
            "CREATE TABLE \"openrouteservice test\".openrouteservice_poly_not_compatible ( pk SERIAL NOT NULL, name TEXT, geom GEOMETRY(POLYGON, 4326), PRIMARY KEY ( pk ) )"
        )

        conn.executeSql(
            "CREATE TABLE \"openrouteservice test\".openrouteservice_point_not_compatible ( pk SERIAL NOT NULL, value NUMERIC, group_index INTEGER, area NUMERIC, reachfactor NUMERIC, total_pop INTEGER, geom GEOMETRY(POINT, 4326), PRIMARY KEY ( pk ) )"
        )

        conn.executeSql(
            "CREATE TABLE \"openrouteservice test\".openrouteservice_compatible ( pk SERIAL NOT NULL, value NUMERIC, group_index INTEGER, area NUMERIC, reachfactor NUMERIC, total_pop INTEGER, geom GEOMETRY(POLYGON, 4326), PRIMARY KEY ( pk ) )"
        )

        conn.executeSql(
            "CREATE TABLE \"openrouteservice test\".openrouteservice_compatible_3857 ( pk SERIAL NOT NULL, value NUMERIC, group_index INTEGER, area NUMERIC, reachfactor NUMERIC, total_pop INTEGER, geom GEOMETRY(POLYGON, 3857), PRIMARY KEY ( pk ) )"
        )

        # Input layers for async tests
        conn.executeSql(
            "CREATE TABLE \"openrouteservice test\".openrouteservice_point_3857 ( pk SERIAL NOT NULL, geom GEOMETRY(POINT, 3857), PRIMARY KEY ( pk ) )"
        )
        conn.executeSql(
            "CREATE TABLE \"openrouteservice test\".openrouteservice_multipoint_4326 ( pk SERIAL NOT NULL, geom GEOMETRY(MULTIPOINT, 4326), PRIMARY KEY ( pk ) )"
        )

        # Add sample points for async tests
        conn.executeSql(
            """INSERT INTO "openrouteservice test".openrouteservice_multipoint_4326 (geom) VALUES
            ( 'SRID=4326;MULTIPOINT ((-77.55542807059459 37.56350130888833), (-77.5513628235481 37.547924590224554), (-77.53848954123421 37.58068563329007), (-77.59608054105951 37.59518182260462))'::geometry),
	        ('SRID=4326;MULTIPOINT ((-77.4077240945721 37.538254644499624), (-77.41991983571157 37.54470141434406), (-77.4260177062813 37.55920460826607), (-77.39349572990939 37.562427156963516), (-77.40840163574651 37.58337032579007))'::geometry)"""
        )

        conn.executeSql(
            """INSERT INTO "openrouteservice test".openrouteservice_point_3857 (geom) VALUES
            ('SRID=3857;POINT (-8636824.820306677 4510025.909782101)'::geometry),
            ('SRID=3857;POINT (-8633657.031688528 4512364.0394764505)'::geometry),
            ('SRID=3857;POINT (-8637126.514460787 4512741.157169087)'::geometry),
            ('SRID=3857;POINT (-8634109.572919691 4503916.603161385)'::geometry)"""
        )

        cls.layer_specs = {}

        project = QgsProject()

        for table_name, table_spec in {
                'openrouteservice_poly_not_compatible': ('Polygon', 4326),
                'openrouteservice_point_not_compatible': ('Point', 4326),
                'openrouteservice_compatible': ('Polygon', 4326),
                'openrouteservice_compatible_3857': ('Polygon', 3857),
                'openrouteservice_point_3857': ('Point', 3857),
                'openrouteservice_multipoint_4326': ('MultiPoint', 4326),
        }.items():
            layer_uri = conn_str + " sslmode=disable key='pk' estimatedmetadata=false srid={srid} type={geometry_type} checkPrimaryKeyUnicity='0' table=\"openrouteservice test\".\"{table_name}\" (geom)".format(
                table_name=table_name,
                geometry_type=table_spec[0],
                srid=table_spec[1])
            layer = QgsVectorLayer(layer_uri, table_name, 'postgres')
            assert layer.isValid()
            cls.layer_specs[table_name] = layer_uri
            project.addMapLayers([layer])

        assert project.write(cls.temp_project_path)

        Project.objects.filter(title='Test openrouteservice project').delete()

        toc = buildLayerTreeNodeObject(project.layerTreeRoot())

        cls.qdjango_project = Project(qgis_file=File(
            open(cls.temp_project_path, 'r')),
                                      title='Test openrouteservice project',
                                      group=cls.project_group,
                                      layers_tree=toc)
        cls.qdjango_project.save()

        for layer_id, layer in project.mapLayers().items():
            _, created = Layer.objects.get_or_create(
                name=layer.name(),
                title=layer.name(),
                origname=layer.name(),
                qgs_layer_id=layer_id,
                srid=layer.crs().postgisSrid(),
                project=cls.qdjango_project,
                layer_type='postgres',
                datasource=cls.layer_specs[layer.name()])
            assert created

        OpenrouteserviceProject.objects.get_or_create(
            project=cls.qdjango_project,
            services={OpenrouteserviceService.ISOCHRONE.value})
Exemple #18
0
def project_info(project_path):
    """Extracts project information and returns it as a dictionary"""

    info = {}
    p = QgsProject()
    canvas = QgsMapCanvas()

    def _readCanvasSettings(xmlDocument):
        canvas.readProject(xmlDocument)

    p.readProject.connect(_readCanvasSettings, Qt.DirectConnection)

    if p.read(project_path):

        # initial extent
        extent = canvas.extent()
        if p.crs().authid() != 4326:
            ct = QgsCoordinateTransform(
                p.crs(), QgsCoordinateReferenceSystem.fromEpsgId(4326),
                p.transformContext())
            extent = ct.transform(extent)

        info['initial_extent'] = [
            extent.xMinimum(),
            extent.yMinimum(),
            extent.xMaximum(),
            extent.yMaximum(),
        ]

        ####################################################
        # Main section

        info['title'] = p.metadata().title()
        if not info['title']:
            info['title'] = QgsServerProjectUtils.owsServiceTitle(p)
        if not info['title']:
            info['title'] = p.title()
        if not info['title']:
            info['title'] = p.baseName()

        info['description'] = p.metadata().abstract()
        if not info['description']:
            info['description'] = QgsServerProjectUtils.owsServiceAbstract(p)

        # Extent, CRS and published WMS layers typenames
        wmsOutputCrsList = QgsServerProjectUtils.wmsOutputCrsList(p)
        info[
            'crs'] = 'EPSG:4326' if 'EPSG:4326' in wmsOutputCrsList else wmsOutputCrsList[
                0]
        extent, info['wms_layers'] = project_wms(p, info['crs'])
        info['extent'] = [
            extent.xMinimum(),
            extent.yMinimum(),
            extent.xMaximum(),
            extent.yMaximum()
        ]
        geographic_extent = extent
        if info['crs'] != 'EPSG:4326':
            extent_crs = QgsCoordinateReferenceSystem.fromEpsgId(
                int(info['crs'].split(':')[1]))
            ct = QgsCoordinateTransform(
                extent_crs, QgsCoordinateReferenceSystem.fromEpsgId(4326),
                p.transformContext())
            geographic_extent = ct.transform(geographic_extent)
        info['geographic_extent'] = [
            geographic_extent.xMinimum(),
            geographic_extent.yMinimum(),
            geographic_extent.xMaximum(),
            geographic_extent.yMaximum()
        ]

        ####################################################
        # Metadata section

        m = p.metadata()
        metadata = {}
        for prop in (
                'title',
                'identifier',
                'parentIdentifier',
                'abstract',
                'author',
                'language',
                'categories',
                'history',
                'type',
        ):
            metadata[prop] = getattr(m, prop)()

        # links array
        metadata['links'] = _read_links(m)
        # contacts array
        metadata['contacts'] = _read_contacts(m)
        metadata['creationDateTime'] = m.creationDateTime().toString(
            Qt.ISODate)
        info['metadata'] = metadata

        ####################################################
        # WMS Service Capabilities section

        capabilities = {}
        for c in ('owsServiceAbstract', 'owsServiceAccessConstraints',
                  'owsServiceCapabilities', 'owsServiceContactMail',
                  'owsServiceContactOrganization', 'owsServiceContactPerson',
                  'owsServiceContactPhone', 'owsServiceContactPosition',
                  'owsServiceFees', 'owsServiceKeywords',
                  'owsServiceOnlineResource', 'owsServiceTitle', 'wcsLayerIds',
                  'wcsServiceUrl', 'wfsLayerIds', 'wfsServiceUrl',
                  'wfstDeleteLayerIds', 'wfstInsertLayerIds',
                  'wfstUpdateLayerIds', 'wmsDefaultMapUnitsPerMm', 'wmsExtent',
                  'wmsFeatureInfoAddWktGeometry',
                  'wmsFeatureInfoDocumentElement',
                  'wmsFeatureInfoDocumentElementNs',
                  'wmsFeatureInfoLayerAliasMap', 'wmsFeatureInfoPrecision',
                  'wmsFeatureInfoSchema',
                  'wmsFeatureInfoSegmentizeWktGeometry', 'wmsImageQuality',
                  'wmsInfoFormatSia2045', 'wmsInspireActivate',
                  'wmsInspireLanguage', 'wmsInspireMetadataDate',
                  'wmsInspireMetadataUrl', 'wmsInspireMetadataUrlType',
                  'wmsInspireTemporalReference', 'wmsMaxAtlasFeatures',
                  'wmsMaxHeight', 'wmsMaxWidth', 'wmsOutputCrsList',
                  'wmsRestrictedComposers', 'wmsRestrictedLayers',
                  'wmsRootName', 'wmsServiceUrl', 'wmsTileBuffer',
                  'wmsUseLayerIds', 'wmtsServiceUrl'):
            capabilities[c] = getattr(QgsServerProjectUtils, c)(p)

        info['capabilities'] = capabilities

        ####################################################
        # WMS Layers section

        info['wms_root_name'] = capabilities['wmsRootName'] if capabilities[
            'wmsRootName'] else p.title()
        restricted_wms = capabilities['wmsRestrictedLayers']
        wms_layers = {}
        use_ids = capabilities['wmsUseLayerIds']
        # Map layer title to layer name (or id if use_ids)
        wms_layers_map = {}
        # Maps a typename to a layer id
        wms_layers_typename_id_map = {}
        wms_layers_searchable = []
        wms_layers_queryable = []

        for l in p.mapLayers().values():
            if l.name() not in restricted_wms:
                wms_layers[l.id()] = layer_info(l)
                name = l.title() if l.title() else l.name()
                short_name = l.shortName() if l.shortName() else l.name()
                wms_layers_typename_id_map[short_name] = l.id()
                wms_layers_map[name] = l.id() if use_ids else short_name
                if bool(l.flags() & QgsMapLayer.Searchable):
                    wms_layers_searchable.append(l.id())
                if bool(l.flags() & QgsMapLayer.Identifiable):
                    wms_layers_queryable.append(l.id())

        info['wms_layers'] = wms_layers
        info['wms_layers_map'] = wms_layers_map
        info['wms_layers_searchable'] = wms_layers_searchable
        info['wms_layers_queryable'] = wms_layers_queryable
        info['wms_layers_typename_id_map'] = wms_layers_typename_id_map

        ####################################################
        # TOC tree (WMS published only)
        info['toc'] = get_toc(p, info)

    return info
Exemple #19
0
QgsApplication.initQgis()

# Open the project
p = QgsProject()
p.read(project_path)
canvas = QgsMapCanvas()
bridge = QgsLayerTreeMapCanvasBridge(
    p.layerTreeRoot(),
    canvas
)
bridge.setCanvasLayers()

# Get the layers in the project
layerList = p.mapLayersByName(parcelle_layer)
if not layerList:
    layers = p.mapLayers()
    for lname,layer in layers.items():
        print(lname+' '+layer.name()+' '+parcelle_layer)
    layerList = [ layer for lname,layer in layers.items() if layer.name() == parcelle_layer ]
layer = layerList[0]

# Get Feature
req = QgsFeatureRequest()
req.setFilterExpression(' "geo_parcelle" = \'%s\' ' % parcelle_id)
it = layer.getFeatures(req)
feat = None
for f in it:
    feat = f
    break

# Get connecion params