Example #1
0
    def testSubsetStringExtent_bug17863(self):
        """Check that the extent is correct when applied in the ctor and when
        modified after a subset string is set """

        def _lessdigits(s):
            return re.sub(r'(\d+\.\d{3})\d+', r'\1', s)

        testPath = TEST_DATA_DIR + '/' + 'points.shp'
        subSetString = '"Class" = \'Biplane\''
        subSet = '|layerid=0|subset=%s' % subSetString

        # unfiltered
        vl = QgsVectorLayer(testPath, 'test', 'ogr')
        self.assertTrue(vl.isValid())
        unfiltered_extent = _lessdigits(vl.extent().toString())
        del(vl)

        # filter after construction ...
        subSet_vl2 = QgsVectorLayer(testPath, 'test', 'ogr')
        self.assertEqual(_lessdigits(subSet_vl2.extent().toString()), unfiltered_extent)
        # ... apply filter now!
        subSet_vl2.setSubsetString(subSetString)
        self.assertEqual(subSet_vl2.subsetString(), subSetString)
        self.assertNotEqual(_lessdigits(subSet_vl2.extent().toString()), unfiltered_extent)
        filtered_extent = _lessdigits(subSet_vl2.extent().toString())
        del(subSet_vl2)

        # filtered in constructor
        subSet_vl = QgsVectorLayer(testPath + subSet, 'subset_test', 'ogr')
        self.assertEqual(subSet_vl.subsetString(), subSetString)
        self.assertTrue(subSet_vl.isValid())

        # This was failing in bug 17863
        self.assertEqual(_lessdigits(subSet_vl.extent().toString()), filtered_extent)
        self.assertNotEqual(_lessdigits(subSet_vl.extent().toString()), unfiltered_extent)
Example #2
0
    def testSelectSubsetString(self):

        tmpfile = os.path.join(self.basetestpath, 'testSelectSubsetString.gpkg')
        ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
        lyr = ds.CreateLayer('test', geom_type=ogr.wkbMultiPolygon)
        lyr.CreateField(ogr.FieldDefn('foo', ogr.OFTString))
        f = ogr.Feature(lyr.GetLayerDefn())
        f['foo'] = 'bar'
        lyr.CreateFeature(f)
        f = None
        f = ogr.Feature(lyr.GetLayerDefn())
        f['foo'] = 'baz'
        lyr.CreateFeature(f)
        f = None
        ds = None

        vl = QgsVectorLayer('{}|layerid=0'.format(tmpfile), 'test', 'ogr')
        vl.setSubsetString("SELECT fid, foo FROM test WHERE foo = 'baz'")
        got = [feat for feat in vl.getFeatures()]
        self.assertEqual(len(got), 1)
        del vl

        testdata_path = unitTestDataPath('provider')
        shutil.copy(os.path.join(testdata_path, 'bug_19826.gpkg'), tmpfile)
        vl = QgsVectorLayer('{}|layerid=0'.format(tmpfile, 'test', 'ogr'))
        vl.setSubsetString("name = 'two'")
        got = [feat for feat in vl.getFeatures()]
        self.assertEqual(len(got), 1)

        attributes = got[0].attributes()
        self.assertEqual(got[0].id(), 2)
        self.assertEqual(attributes[0], 2)
        self.assertEqual(attributes[1], 'two')
        self.assertNotEqual(attributes[2], None)

        # Request by FeatureId on a subset layer
        got = [feat for feat in vl.getFeatures(QgsFeatureRequest(2))]
        self.assertEqual(len(got), 1)
        attributes = got[0].attributes()
        self.assertEqual(got[0].id(), 2)
        self.assertEqual(attributes[0], 2)
        self.assertEqual(attributes[1], 'two')
        self.assertNotEqual(attributes[2], None)

        request = QgsFeatureRequest(2).setSubsetOfAttributes([0])
        got = [feat for feat in vl.getFeatures(request)]
        self.assertEqual(len(got), 1)
        attributes = got[0].attributes()
        self.assertEqual(got[0].id(), 2)
        self.assertEqual(attributes[0], 2)
        self.assertEqual(attributes[1], None)
        self.assertEqual(attributes[2], None)

        # Request by FeatureId on a subset layer. The name = 'two' filter
        # only returns FID 2, so requesting on FID 1 should return nothing
        # but this is broken now.
        got = [feat for feat in vl.getFeatures(QgsFeatureRequest(1))]
        self.assertEqual(len(got), 1) # this is the current behavior, broken
    def testSubsetStringRegexp(self):
        """Check that the provider supports the REGEXP syntax"""

        testPath = "dbname=%s table='test_filter' (geometry) key='id'" % self.dbname
        vl = QgsVectorLayer(testPath, 'test', 'spatialite')
        self.assertTrue(vl.isValid())
        vl.setSubsetString('"name" REGEXP \'[txe]\'')
        self.assertEqual(vl.featureCount(), 4)
        del(vl)
Example #4
0
    def test_sql2(self):
        l2 = QgsVectorLayer(os.path.join(self.testDataDir, "france_parts.shp"), "france_parts", "ogr", False)
        self.assertEqual(l2.isValid(), True)
        QgsProject.instance().addMapLayer(l2)

        query = toPercent("SELECT * FROM france_parts")
        l4 = QgsVectorLayer("?query=%s&uid=ObjectId" % query, "tt", "virtual")
        self.assertEqual(l4.isValid(), True)

        self.assertEqual(l4.dataProvider().wkbType(), 3)
        self.assertEqual(l4.dataProvider().crs().postgisSrid(), 4326)

        n = 0
        r = QgsFeatureRequest(QgsRectangle(-1.677, 49.624, -0.816, 49.086))
        for f in l4.getFeatures(r):
            self.assertEqual(f.geometry() is not None, True)
            self.assertEqual(f.attributes()[0], 2661)
            n += 1
        self.assertEqual(n, 1)

        # use uid
        query = toPercent("SELECT * FROM france_parts")
        l5 = QgsVectorLayer("?query=%s&geometry=geometry:polygon:4326&uid=ObjectId" % query, "tt", "virtual")
        self.assertEqual(l5.isValid(), True)

        idSum = sum(f.id() for f in l5.getFeatures())
        self.assertEqual(idSum, 10659)

        r = QgsFeatureRequest(2661)
        idSum2 = sum(f.id() for f in l5.getFeatures(r))
        self.assertEqual(idSum2, 2661)

        r = QgsFeatureRequest()
        r.setFilterFids([2661, 2664])
        self.assertEqual(sum(f.id() for f in l5.getFeatures(r)), 2661 + 2664)

        # test attribute subset
        r = QgsFeatureRequest()
        r.setFlags(QgsFeatureRequest.SubsetOfAttributes)
        r.setSubsetOfAttributes([1])
        s = [(f.id(), f.attributes()[1]) for f in l5.getFeatures(r)]
        self.assertEqual(sum([x[0] for x in s]), 10659)
        self.assertEqual(sum([x[1] for x in s]), 3064.0)

        # test NoGeometry
        # by request flag
        r = QgsFeatureRequest()
        r.setFlags(QgsFeatureRequest.NoGeometry)
        self.assertEqual(all([not f.hasGeometry() for f in l5.getFeatures(r)]), True)

        # test subset
        self.assertEqual(l5.dataProvider().featureCount(), 4)
        l5.setSubsetString("ObjectId = 2661")
        idSum2 = sum(f.id() for f in l5.getFeatures(r))
        self.assertEqual(idSum2, 2661)
        self.assertEqual(l5.dataProvider().featureCount(), 1)
Example #5
0
 def filter_selection(self):
     '''
     filter the active layer by selected objects
     '''
     if not self.login:
         return
     # either name of layer or group have to match a category
     active_layer = iface.activeLayer()
     categories = self.categories.keys()
     layer_error = (u'Sie müssen im Layerfenster einen '
                    u'Layer auswählen, wahlweise aus den Gruppen '
                    u'Einrichtungen oder Filter.')
     if not active_layer:
         QtGui.QMessageBox.information(self, 'Fehler', layer_error)
         return
     else:
         layer_name = active_layer.name()
         if layer_name in categories:
             category = layer_name
         else:
             project_tree = QgsProject.instance().layerTreeRoot()
             layer_item = project_tree.findLayer(active_layer.id())
             group = layer_item.parent()
             group_name = group.name()
             if group_name in categories:
                 category = group_name
             else:
                 QtGui.QMessageBox.information(self, 'Fehler', layer_error)
                 return
         selected_feats = active_layer.selectedFeatures()
         if not selected_feats:
             msg = (u'Im ausgewählten Layer {} sind keine '
                    u'Einrichtungen selektiert.'.format(layer_name))
             QtGui.QMessageBox.information(self, 'Fehler', msg)
             return
 
         parent_group = get_group('Filter')
         subgroup = get_group(category, parent_group)
         ids = [str(f.attribute('sel_id')) for f in selected_feats]
         name, ok = QtGui.QInputDialog.getText(
             self, 'Filter', 'Name des zu erstellenden Layers',
             text=get_unique_layer_name(category, subgroup))
         if not ok:
             return
         
         subset = 'sel_id in ({})'.format(','.join(ids))
         layer = QgsVectorLayer(active_layer.source(), name, "postgres")
         remove_layer(name, subgroup)
         
         QgsMapLayerRegistry.instance().addMapLayer(layer, False)
         subgroup.addLayer(layer)
         layer.setSubsetString(subset)
         symbology = SimpleSymbology(self.colors[category], shape='triangle')
         symbology.apply(layer)
         self.copy_editor_attrs(active_layer, layer)
Example #6
0
 def toSqlLayer(self, sql, geomCol, uniqueCol, layerName="QueryLayer", layerType=None, avoidSelectById=False, _filter=""):
     q = QUrl.toPercentEncoding(sql)
     s = "?query=%s" % q
     if uniqueCol is not None:
         s += "&uid=" + uniqueCol
     if geomCol is not None:
         s += "&geometry=" + geomCol
     vl = QgsVectorLayer(s, layerName, "virtual")
     if _filter:
         vl.setSubsetString(_filter)
     return vl
Example #7
0
File: plugin.py Project: CS-SI/QGIS
 def toSqlLayer(self, sql, geomCol, uniqueCol, layerName="QueryLayer", layerType=None, avoidSelectById=False, _filter=""):
     df = QgsVirtualLayerDefinition()
     df.setQuery(sql)
     if uniqueCol is not None:
         uniqueCol = uniqueCol.strip('"').replace('""', '"')
         df.setUid(uniqueCol)
     if geomCol is not None:
         df.setGeometryField(geomCol)
     vl = QgsVectorLayer(df.toString(), layerName, "virtual")
     if _filter:
         vl.setSubsetString(_filter)
     return vl
Example #8
0
	def _createTSlayer(self, uri, providerType, subset=None):
		# utility function used to create the vector layer containing time
		# series data
		layer = QgsVectorLayer( uri, "time_series_layer", providerType )
		if not layer.isValid():
			QMessageBox.warning( self.iface.mainWindow(),
					"PS Time Series Viewer",
					"The layer '%s' wasn't found." % self.ts_tablename )
			self.ts_tablename = None
			return

		if subset is not None:
			layer.setSubsetString( subset )

		return layer
    def _loadSpaitaliteTable(self, databaseName, tableName, displayName=None, subsetString=None):
        try:
            if not displayName:
                displayName = tableName

            uri = QgsDataSourceURI()
            uri.setDatabase(databaseName)
            uri.setDataSource('', tableName, 'geometry')
            layer = QgsVectorLayer(uri.uri(), displayName, 'spatialite')
            if subsetString:
                layer.setSubsetString(subsetString)

            return layer
        except Exception, e:
            QMessageBox.warning(None, "Error Loading Spatialtie Table", u"{0}".format(e))
            return None
    def testSubsetStringExtent_bug17863(self):
        """Check that the extent is correct when applied in the ctor and when
        modified after a subset string is set """

        def _lessdigits(s):
            return re.sub(r'(\d+\.\d{3})\d+', r'\1', s)

        testPath = "dbname=%s table='test_filter' (geometry) key='id'" % self.dbname

        subSetString = '"name" = \'int\''
        subSet = ' sql=%s' % subSetString

        # unfiltered
        vl = QgsVectorLayer(testPath, 'test', 'spatialite')
        self.assertTrue(vl.isValid())
        self.assertEqual(vl.featureCount(), 8)
        unfiltered_extent = _lessdigits(vl.extent().toString())
        self.assertNotEqual('Empty', unfiltered_extent)
        del(vl)

        # filter after construction ...
        subSet_vl2 = QgsVectorLayer(testPath, 'test', 'spatialite')
        self.assertEqual(_lessdigits(subSet_vl2.extent().toString()), unfiltered_extent)
        self.assertEqual(subSet_vl2.featureCount(), 8)
        # ... apply filter now!
        subSet_vl2.setSubsetString(subSetString)
        self.assertEqual(subSet_vl2.featureCount(), 4)
        self.assertEqual(subSet_vl2.subsetString(), subSetString)
        self.assertNotEqual(_lessdigits(subSet_vl2.extent().toString()), unfiltered_extent)
        filtered_extent = _lessdigits(subSet_vl2.extent().toString())
        del(subSet_vl2)

        # filtered in constructor
        subSet_vl = QgsVectorLayer(testPath + subSet, 'subset_test', 'spatialite')
        self.assertEqual(subSet_vl.subsetString(), subSetString)
        self.assertTrue(subSet_vl.isValid())

        # This was failing in bug 17863
        self.assertEqual(subSet_vl.featureCount(), 4)
        self.assertEqual(_lessdigits(subSet_vl.extent().toString()), filtered_extent)
        self.assertNotEqual(_lessdigits(subSet_vl.extent().toString()), unfiltered_extent)

        self.assertTrue(subSet_vl.setSubsetString(''))
        self.assertEqual(subSet_vl.featureCount(), 8)
        self.assertEqual(_lessdigits(subSet_vl.extent().toString()), unfiltered_extent)
Example #11
0
    def testSelectSubsetString(self):

        tmpfile = os.path.join(self.basetestpath, 'testSelectSubsetString.gpkg')
        ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
        lyr = ds.CreateLayer('test', geom_type=ogr.wkbMultiPolygon)
        lyr.CreateField(ogr.FieldDefn('foo', ogr.OFTString))
        f = ogr.Feature(lyr.GetLayerDefn())
        f['foo'] = 'bar'
        lyr.CreateFeature(f)
        f = None
        f = ogr.Feature(lyr.GetLayerDefn())
        f['foo'] = 'baz'
        lyr.CreateFeature(f)
        f = None
        ds = None

        vl = QgsVectorLayer('{}|layerid=0'.format(tmpfile), 'test', 'ogr')
        vl.setSubsetString("SELECT fid, foo FROM test WHERE foo = 'baz'")
        got = [feat for feat in vl.getFeatures()]
        self.assertEqual(len(got), 1)
Example #12
0
    def testSelectSubsetString(self):

        tmpfile = os.path.join(self.basetestpath, "testSelectSubsetString.gpkg")
        ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
        lyr = ds.CreateLayer("test", geom_type=ogr.wkbMultiPolygon)
        lyr.CreateField(ogr.FieldDefn("foo", ogr.OFTString))
        f = ogr.Feature(lyr.GetLayerDefn())
        f["foo"] = "bar"
        lyr.CreateFeature(f)
        f = None
        f = ogr.Feature(lyr.GetLayerDefn())
        f["foo"] = "baz"
        lyr.CreateFeature(f)
        f = None
        ds = None

        vl = QgsVectorLayer("{}|layerid=0".format(tmpfile), "test", "ogr")
        vl.setSubsetString("SELECT fid, foo FROM test WHERE foo = 'baz'")
        got = [feat for feat in vl.getFeatures()]
        self.assertEqual(len(got), 1)
 def __add_layers(self, thema):
     try:
         layers = []
         for quelle in thema.quellen:
             pfad = quelle.pfad.replace('{gem_name}', self.gem_name)
             qml = None
             if not quelle.qml is None:
                 qml = quelle.qml.replace('{gem_name}', self.gem_name)
             if VRP_DEBUG is True: QgsMessageLog.logMessage('adding lyr:\n{0}\n{1}'.format(pfad, qml), DLG_CAPTION)
             if pfad.lower().endswith('.shp') is True:
                 lyr = QgsVectorLayer(pfad, quelle.name, 'ogr')
                 if not quelle.filter is None:
                     if VRP_DEBUG is True: QgsMessageLog.logMessage('{0}'.format(quelle.filter), DLG_CAPTION)
                     #exp = QgsExpression(quelle.filter)
                     #if exp.hasParserError():
                     #    QgsMessageLog.logMessage( u'Filter ungültig!\nQuelle:[{0}]\nFilter:{1}'.format(quelle.name, quelle.filter), DLG_CAPTION)
                     #else:
                     #    exp.prepare(lyr.pendingFields())
                     lyr.setSubsetString(quelle.filter)
             else:
                 fileinfo = QFileInfo(pfad)
                 basename = fileinfo.baseName()
                 lyr = QgsRasterLayer(pfad, basename)
                 if not lyr.isValid():
                     QgsMessageLog.logMessage( u'Raster [{0}] konnte nicht geladen werden:\n{1}'.format(thema.name, pfad), DLG_CAPTION)
                     continue
             if not qml is None:
                 lyr.loadNamedStyle(qml)
             QgsMapLayerRegistry.instance().addMapLayer(lyr)
             #turn off layer, if no qml present
             #for layer that should not be displayed but should be
             #used for statistics
             if qml is None:
                 self.legiface.setLayerVisible(lyr, False)
             layers.append(lyr)
         return layers
     except:
         msg = 'export pdf (__add_layers): {0}'.format(sys.exc_info()[0])
         QgsMessageLog.logMessage(msg, DLG_CAPTION)
         return None
Example #14
0
    def testSubSetStringEditable_bug17795_but_with_modified_behavior(self):
        """Test that a layer is editable after setting a subset"""

        tmpfile = os.path.join(self.basetestpath, 'testSubSetStringEditable_bug17795.gpkg')
        shutil.copy(TEST_DATA_DIR + '/' + 'provider/bug_17795.gpkg', tmpfile)

        isEditable = QgsVectorDataProvider.ChangeAttributeValues
        testPath = tmpfile + '|layername=bug_17795'

        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
        self.assertTrue(vl.isValid())
        self.assertTrue(vl.dataProvider().capabilities() & isEditable)

        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
        vl.setSubsetString('')
        self.assertTrue(vl.isValid())
        self.assertTrue(vl.dataProvider().capabilities() & isEditable)

        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
        vl.setSubsetString('"category" = \'one\'')
        self.assertTrue(vl.isValid())
        self.assertTrue(vl.dataProvider().capabilities() & isEditable)

        vl.setSubsetString('')
        self.assertTrue(vl.dataProvider().capabilities() & isEditable)
Example #15
0
    def testSubsetStringExtent_bug17863(self):
        """Check that the extent is correct when applied in the ctor and when
        modified after a subset string is set """

        def _lessdigits(s):
            return re.sub(r'(\d+\.\d{3})\d+', r'\1', s)

        tmpfile = os.path.join(self.basetestpath, 'testSubsetStringExtent_bug17863.gpkg')
        shutil.copy(TEST_DATA_DIR + '/' + 'provider/bug_17795.gpkg', tmpfile)

        testPath = tmpfile + '|layername=bug_17795'
        subSetString = '"name" = \'int\''
        subSet = '|layername=bug_17795|subset=%s' % subSetString

        # unfiltered
        vl = QgsVectorLayer(testPath, 'test', 'ogr')
        self.assertTrue(vl.isValid())
        unfiltered_extent = _lessdigits(vl.extent().toString())
        del(vl)

        # filter after construction ...
        subSet_vl2 = QgsVectorLayer(testPath, 'test', 'ogr')
        self.assertEqual(_lessdigits(subSet_vl2.extent().toString()), unfiltered_extent)
        # ... apply filter now!
        subSet_vl2.setSubsetString(subSetString)
        self.assertEqual(subSet_vl2.subsetString(), subSetString)
        self.assertNotEqual(_lessdigits(subSet_vl2.extent().toString()), unfiltered_extent)
        filtered_extent = _lessdigits(subSet_vl2.extent().toString())
        del(subSet_vl2)

        # filtered in constructor
        subSet_vl = QgsVectorLayer(testPath + subSet, 'subset_test', 'ogr')
        self.assertEqual(subSet_vl.subsetString(), subSetString)
        self.assertTrue(subSet_vl.isValid())

        # This was failing in bug 17863
        self.assertEqual(_lessdigits(subSet_vl.extent().toString()), filtered_extent)
        self.assertNotEqual(_lessdigits(subSet_vl.extent().toString()), unfiltered_extent)
Example #16
0
    def apply_filters(self):
        '''
        filter a layer with settings made by user in filter-tree
        '''
        if not self.login:
            return
        category = self.get_selected_tab()
        scenario_group = get_group(self.active_scenario.name)
        err_group = get_group('Einrichtungen', scenario_group)
        filter_group = get_group('Filter', scenario_group)
        subgroup = get_group(category, filter_group, hide_in_composer=False)
        name, ok = QtGui.QInputDialog.getText(
            self, 'Filter', 'Name des zu erstellenden Layers',
            text=get_unique_layer_name(category, subgroup))
        if not ok or not name:
            return
        orig_layer = None
        for child in err_group.children():
            if child.name() == category:
                layer_id = child.layerId()
                orig_layer = QgsMapLayerRegistry.instance().mapLayers()[layer_id]
                break
        
        filter_tree = self.categories[category]
        subset = filter_tree.to_sql_query(self.active_scenario.id,
                                          year=filter_tree.year_slider.value())
        matches = QgsMapLayerRegistry.instance().mapLayersByName(category)
    
        remove_layer(name, subgroup)

        layer = QgsVectorLayer(orig_layer.source(), name, "postgres")
        QgsMapLayerRegistry.instance().addMapLayer(layer, False)
        subgroup.addLayer(layer)
        layer.setSubsetString(subset)
        symbology = SimpleSymbology(self.colors[category], shape='triangle')
        symbology.apply(layer)
        self.copy_editor_attrs(orig_layer, layer)
Example #17
0
    def testLayerChangeDirtiesProject(self):
        """
        Test that making changes to certain layer properties results in dirty projects
        """
        p = QgsProject()
        l = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "points.shp"), "points", "ogr")
        self.assertTrue(l.isValid())
        self.assertTrue(p.addMapLayers([l]))
        p.setDirty(False)

        l.setCrs(QgsCoordinateReferenceSystem('EPSG:3111'))
        self.assertTrue(p.isDirty())
        p.setDirty(False)

        l.setName('test')
        self.assertTrue(p.isDirty())
        p.setDirty(False)

        self.assertTrue(l.setSubsetString('class=\'a\''))
        self.assertTrue(p.isDirty())
Example #18
0
    def testLayerChangeDirtiesProject(self):
        """
        Test that making changes to certain layer properties results in dirty projects
        """
        p = QgsProject()
        l = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "points.shp"), "points",
                           "ogr")
        self.assertTrue(l.isValid())
        self.assertTrue(p.addMapLayers([l]))
        p.setDirty(False)

        l.setCrs(QgsCoordinateReferenceSystem('EPSG:3111'))
        self.assertTrue(p.isDirty())
        p.setDirty(False)

        l.setName('test')
        self.assertTrue(p.isDirty())
        p.setDirty(False)

        self.assertTrue(l.setSubsetString('class=\'a\''))
        self.assertTrue(p.isDirty())
Example #19
0
    def testSubSetStringEditable_bug17795_but_with_modified_behavior(self):
        """Test that a layer is still editable after setting a subset"""

        testPath = TEST_DATA_DIR + '/' + 'lines.shp'
        isEditable = QgsVectorDataProvider.ChangeAttributeValues

        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
        self.assertTrue(vl.isValid())
        self.assertTrue(vl.dataProvider().capabilities() & isEditable)

        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
        vl.setSubsetString('')
        self.assertTrue(vl.isValid())
        self.assertTrue(vl.dataProvider().capabilities() & isEditable)

        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
        vl.setSubsetString('"Name" = \'Arterial\'')
        self.assertTrue(vl.isValid())
        self.assertTrue(vl.dataProvider().capabilities() & isEditable)

        vl.setSubsetString('')
        self.assertTrue(vl.dataProvider().capabilities() & isEditable)
Example #20
0
    def testSubSetStringEditable_bug17795(self):
        """Test that a layer is not editable after setting a subset and it's reverted to editable after the filter is removed"""

        testPath = TEST_DATA_DIR + '/' + 'lines.shp'
        isEditable = QgsVectorDataProvider.ChangeAttributeValues

        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
        self.assertTrue(vl.isValid())
        self.assertTrue(vl.dataProvider().capabilities() & isEditable)

        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
        vl.setSubsetString('')
        self.assertTrue(vl.isValid())
        self.assertTrue(vl.dataProvider().capabilities() & isEditable)

        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
        vl.setSubsetString('"Name" = \'Arterial\'')
        self.assertTrue(vl.isValid())
        self.assertFalse(vl.dataProvider().capabilities() & isEditable)

        vl.setSubsetString('')
        self.assertTrue(vl.dataProvider().capabilities() & isEditable)
Example #21
0
    def testSubSetStringEditable_bug17795(self):
        """Test that a layer is not editable after setting a subset and it's reverted to editable after the filter is removed"""

        isEditable = QgsVectorDataProvider.ChangeAttributeValues
        testPath = TEST_DATA_DIR + '/' + 'provider/bug_17795.gpkg|layername=bug_17795'

        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
        self.assertTrue(vl.isValid())
        self.assertTrue(vl.dataProvider().capabilities() & isEditable)

        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
        vl.setSubsetString('')
        self.assertTrue(vl.isValid())
        self.assertTrue(vl.dataProvider().capabilities() & isEditable)

        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
        vl.setSubsetString('"category" = \'one\'')
        self.assertTrue(vl.isValid())
        self.assertFalse(vl.dataProvider().capabilities() & isEditable)

        vl.setSubsetString('')
        self.assertTrue(vl.dataProvider().capabilities() & isEditable)
Example #22
0
    def testSubSetStringEditable_bug17795(self):
        """Test that a layer is not editable after setting a subset and it's reverted to editable after the filter is removed"""

        isEditable = QgsVectorDataProvider.ChangeAttributeValues
        testPath = TEST_DATA_DIR + '/' + 'provider/bug_17795.gpkg|layername=bug_17795'

        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
        self.assertTrue(vl.isValid())
        self.assertTrue(vl.dataProvider().capabilities() & isEditable)

        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
        vl.setSubsetString('')
        self.assertTrue(vl.isValid())
        self.assertTrue(vl.dataProvider().capabilities() & isEditable)

        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
        vl.setSubsetString('"category" = \'one\'')
        self.assertTrue(vl.isValid())
        self.assertFalse(vl.dataProvider().capabilities() & isEditable)

        vl.setSubsetString('')
        self.assertTrue(vl.dataProvider().capabilities() & isEditable)
Example #23
0
    def testSubSetStringEditable_bug17795_but_with_modified_behavior(self):
        """Test that a layer is still editable after setting a subset"""

        testPath = TEST_DATA_DIR + '/' + 'lines.shp'
        isEditable = QgsVectorDataProvider.ChangeAttributeValues

        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
        self.assertTrue(vl.isValid())
        self.assertTrue(vl.dataProvider().capabilities() & isEditable)

        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
        vl.setSubsetString('')
        self.assertTrue(vl.isValid())
        self.assertTrue(vl.dataProvider().capabilities() & isEditable)

        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
        vl.setSubsetString('"Name" = \'Arterial\'')
        self.assertTrue(vl.isValid())
        self.assertTrue(vl.dataProvider().capabilities() & isEditable)

        vl.setSubsetString('')
        self.assertTrue(vl.dataProvider().capabilities() & isEditable)
Example #24
0
    def testSubSetStringEditable_bug17795(self):
        """Test that a layer is not editable after setting a subset and it's reverted to editable after the filter is removed"""

        testPath = TEST_DATA_DIR + '/' + 'lines.shp'
        isEditable = QgsVectorDataProvider.ChangeAttributeValues

        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
        self.assertTrue(vl.isValid())
        self.assertTrue(vl.dataProvider().capabilities() & isEditable)

        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
        vl.setSubsetString('')
        self.assertTrue(vl.isValid())
        self.assertTrue(vl.dataProvider().capabilities() & isEditable)

        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
        vl.setSubsetString('"Name" = \'Arterial\'')
        self.assertTrue(vl.isValid())
        self.assertFalse(vl.dataProvider().capabilities() & isEditable)

        vl.setSubsetString('')
        self.assertTrue(vl.dataProvider().capabilities() & isEditable)
Example #25
0
    def showResult(self):
        """
        Perform calculations and send them to display.
        """
        # Tuple[Tuple[str, str, int]]
        selected_rows = tuple(self.windowRow.tab)
        selected_columns = tuple(self.windowColumn.tab)
        selected_ValCalc = tuple(self.windowValue.tab)

        # Reading a field that has been selected for calculation.
        # Only one is allowed.
        # List[Tuple[str, str, int]]
        value = [x for x in selected_ValCalc if x[0] != 'calculation'][0]

        # Set the calculation function depending on the type of the selected
        # value.
        if value[0] == 'geometry':
            if value[2] == 1:
                fun = lambda feat: feat.geometry().length()
            elif value[2] == 2:
                fun = lambda feat: feat.geometry().area()
        elif value[0] == 'text':
            fun = lambda feat: None if not feat.attribute(value[1]) else \
                feat.attribute(value[1])
        elif value[0] == 'number':
            fun = lambda feat: None if not feat.attribute(value[1]) else \
                float(feat.attribute(value[1]))

        # Get selected layer
        index = self.ui.layer.currentIndex()
        layer_id = self.ui.layer.itemData(index)
        layer = QgsProject.instance().mapLayer(layer_id)

        selected_features_id = layer.selectedFeatureIds()
        only_selected = self.ui.onlySelected.isChecked()

        tmp_layer = QgsVectorLayer(layer.source(), layer.name(),
                                   layer.providerType())
        tmp_layer.setCrs(layer.crs())
        filter_str = self.ui.filter.toPlainText()
        layer_filter = layer.subsetString()
        if not layer_filter and filter_str:
            tmp_layer.setSubsetString(filter_str)
        elif layer_filter and filter_str:
            tmp_layer.setSubsetString('{} and {}'.format(
                layer_filter, filter_str))

        provider = tmp_layer.dataProvider()
        features = provider.getFeatures()

        # Dictionary on results {((row) (column)): [[values], [indexes]} ??
        results = {}

        # Compute percent_factor for progress monitoring
        n_features = provider.featureCount()
        if n_features:
            percent_factor = 100 / n_features
        else:
            percent_factor = 100

        progress = 0
        count_null = 0

        for f in features:
            if not only_selected or \
                    (only_selected and f.id() in selected_features_id):
                key_col = []
                key_row = []
                key = ()

                for k in selected_columns:
                    if k[0] == 'geometry':
                        if k[2] == 1:
                            key_col.append(f.geometr().length())
                        elif k[2] == 2:
                            key_col.append(f.geometry().area())
                    elif k[0] in ['text', 'number']:
                        if f.attribute(k[1]) is None:
                            new_key_kol = ''
                        else:
                            new_key_kol = f.attribute(k[1])
                        key_col.append(new_key_kol)

                for k in selected_rows:
                    if k[0] == 'geometry':
                        if k[2] == 1:
                            key_row.append(f.geometry().length())
                        elif k[2] == 2:
                            key_row.append(f.geometry().area())
                    elif k[0] in ['text', 'number']:
                        if f.attribute(k[1]) is None:
                            new_key_row = ''
                        else:
                            new_key_row = f.attribute(k[1])
                        key_row.append(new_key_row)

                key = (tuple(key_row), tuple(key_col))

                value_to_calculate = fun(f)
                if value_to_calculate is not None or \
                        self.ui.useNULL.isChecked():
                    if value_to_calculate is None:
                        count_null += 1
                        if value[0] == 'number':
                            value_to_calculate = 0

                    # If the key exists then a new value is added to the list.
                    if key in results:
                        results[key][0].append(value_to_calculate)
                    # If the key does not exist then a new list is created.
                    else:
                        results[key] = [[value_to_calculate], []]

                    results[key][1].append(f.id())

                else:
                    count_null += 1

                # Display progress
                progress += percent_factor
                self.statusBar().showMessage(
                    QCoreApplication.translate('GroupStats', 'Calculate...') +
                    '{:.2f}'.format(progress))
        self.statusBar().showMessage(
            self.statusBar().currentMessage() + ' |  ' +
            QCoreApplication.translate('GroupStats', 'generate view...'))

        # Find unique row and column keys (separately)
        keys = list(results.keys())
        row_set = set([])
        col_set = set([])
        for key in keys:
            # Add keys to the collection to reject repetition
            row_set.add(key[0])
            col_set.add(key[1])
        rows = list(row_set)
        cols = list(col_set)

        # Create dictionary for rows and columns for faster searching.
        row_dict = {}
        col_dict = {}
        for n, row in enumerate(rows):
            row_dict[row] = n
        for n, col in enumerate(cols):
            col_dict[col] = n

        calculations = [
            [x[2] for x in selected_ValCalc if x[0] == 'calculation'],
            [x[2] for x in selected_rows if x[0] == 'calculation'],
            [x[2] for x in selected_columns if x[0] == 'calculation'],
        ]

        # Take only a non-empty part of the list to calculate.
        if calculations[0]:
            calculation = calculations[0]
        elif calculations[1]:
            calculation = calculations[1]
        else:
            calculation = calculations[2]

        # Create empty array for data (rows x columns)
        data = []
        for x in range(max(len(rows), len(rows) * len(calculations[1]))):
            data.append(
                max(len(cols),
                    len(cols) * len(calculations[2])) * [('', ())])

        # Calculate of values ​​for all keys
        for x in keys:
            # row and column number in the data table for the selected key
            krow = row_dict[x[0]]
            kcol = col_dict[x[1]]
            # Perform all calculations for all keys.
            for n, y in enumerate(calculation):
                # At the right side of the equation is a list of 2:
                # 1. Resulting computation
                # 2. A list of feature ID's used in the computation
                if calculations[1]:
                    data[krow * len(calculations[1]) + n][kcol] = [
                        self.calculation.list[y][1](results[x][0]),
                        results[x][1]
                    ]
                elif calculations[2]:
                    data[krow][kcol * len(calculations[2]) + n] = [
                        self.calculation.list[y][1](results[x][0]),
                        results[x][1]
                    ]
                else:
                    data[krow][kcol] = [
                        self.calculation.list[y][1](results[x][0]),
                        results[x][1]
                    ]

        attributes = {}
        for i in range(provider.fields().count()):
            attributes[i] = provider.fields().at(i)

        row_names = []
        for x in selected_rows:
            if x[0] == 'geometry':
                row_names.append(x[1])
            elif x[0] != 'calculation':
                row_names.append(attributes[x[2]].name())
        col_names = []
        for x in selected_columns:
            if x[0] == 'geometry':
                col_names.append(x[1])
            elif x[0] != 'calculation':
                col_names.append(attributes[x[2]].name())

        # Insert names of rows and columns with calculations.
        calc_col_name = ()
        calc_row_name = ()
        if calculations[1]:
            calc = [self.calculation.list[x][0] for x in calculations[1]]
            _rows = [w + (o, ) for w in rows for o in calc]
            _cols = cols
            calc_row_name = (QCoreApplication.translate(
                'GroupStats', 'Function'), )
        elif calculations[2]:
            calc = [self.calculation.list[x][0] for x in calculations[2]]
            _cols = [w + (o, ) for w in cols for o in calc]
            _rows = rows
            calc_col_name = (QCoreApplication.translate(
                'GroupStats', 'Function'), )
        else:
            _cols = cols
            _rows = rows

        if _rows and _rows[0]:
            _rows.insert(0, tuple(row_names) + calc_row_name)
        if _cols and _cols[0]:
            _cols.insert(0, tuple(col_names) + calc_col_name)

        if _rows and _cols:
            self.ui.results.setUpdatesEnabled(False)
            self.windowResult = ResultsModel(data, _rows, _cols, layer)
            self.ui.results.setModel(self.windowResult)

            for i in range(len(_cols[0]), 0, -1):
                self.ui.results.verticalHeader() \
                    .setSortIndicator(i - 1, Qt.AscendingOrder)
            for i in range(len(_rows[0]), 0, -1):
                self.ui.results.horizontalHeader() \
                    .setSortIndicator(i - 1, Qt.AscendingOrder)

            message = self.statusBar().currentMessage()
            percent_factor = 100 / self.windowResult.columnCount()
            progress = 0

            for i in range(self.windowResult.columnCount()):
                self.ui.results.resizeColumnToContents(i)
                progress += percent_factor
                self.statusBar() \
                    .showMessage(message + '{:.2f}'.format(progress))
            self.ui.results.setUpdatesEnabled(True)

            record = 'records'
            if count_null == 1:
                record = 'record'

            if self.ui.useNULL.isChecked() and count_null:
                null_text = QCoreApplication.translate(
                    'GroupStats',
                    ' (used {} {} with null value in {} field)'.format(
                        count_null, record, value[1]))
            elif not self.ui.useNULL.isChecked() and count_null:
                null_text = QCoreApplication.translate(
                    'GroupStats',
                    ' (not used {} {} with null value in {} field)'.format(
                        count_null, record, value[1]))
            else:
                null_text = ''
            self.statusBar().showMessage(
                message + ' | ' +
                QCoreApplication.translate('GroupStats', 'done. ') + null_text,
                20000)
        else:
            try:
                del self.windowResult
            except AttributeError:
                pass

            self.statusBar().showMessage(
                QCoreApplication.translate('GroupStats', 'No data found.'),
                10000)
Example #26
0
    def test_sql2(self):
        l2 = QgsVectorLayer(os.path.join(self.testDataDir, "france_parts.shp"),
                            "france_parts", "ogr",
                            QgsVectorLayer.LayerOptions(False))
        self.assertEqual(l2.isValid(), True)
        QgsProject.instance().addMapLayer(l2)

        query = toPercent("SELECT * FROM france_parts")
        l4 = QgsVectorLayer("?query=%s&uid=ObjectId" % query, "tt", "virtual")
        self.assertEqual(l4.isValid(), True)

        self.assertEqual(l4.dataProvider().wkbType(), 6)
        self.assertEqual(l4.dataProvider().crs().postgisSrid(), 4326)

        n = 0
        r = QgsFeatureRequest(QgsRectangle(-1.677, 49.624, -0.816, 49.086))
        for f in l4.getFeatures(r):
            self.assertEqual(f.geometry() is not None, True)
            self.assertEqual(f.attributes()[0], 2661)
            n += 1
        self.assertEqual(n, 1)

        # use uid
        query = toPercent("SELECT * FROM france_parts")
        l5 = QgsVectorLayer(
            "?query=%s&geometry=geometry:polygon:4326&uid=ObjectId" % query,
            "tt", "virtual")
        self.assertEqual(l5.isValid(), True)

        idSum = sum(f.id() for f in l5.getFeatures())
        self.assertEqual(idSum, 10659)

        r = QgsFeatureRequest(2661)
        idSum2 = sum(f.id() for f in l5.getFeatures(r))
        self.assertEqual(idSum2, 2661)

        r = QgsFeatureRequest()
        r.setFilterFids([2661, 2664])
        self.assertEqual(sum(f.id() for f in l5.getFeatures(r)), 2661 + 2664)

        # test attribute subset
        r = QgsFeatureRequest()
        r.setFlags(QgsFeatureRequest.SubsetOfAttributes)
        r.setSubsetOfAttributes([1])
        s = [(f.id(), f.attributes()[1]) for f in l5.getFeatures(r)]
        self.assertEqual(sum([x[0] for x in s]), 10659)
        self.assertEqual(sum([x[1] for x in s]), 3064.0)

        # test NoGeometry
        # by request flag
        r = QgsFeatureRequest()
        r.setFlags(QgsFeatureRequest.NoGeometry)
        self.assertEqual(all([not f.hasGeometry() for f in l5.getFeatures(r)]),
                         True)

        # test subset
        self.assertEqual(l5.dataProvider().featureCount(), 4)
        l5.setSubsetString("ObjectId = 2661")
        idSum2 = sum(f.id() for f in l5.getFeatures(r))
        self.assertEqual(idSum2, 2661)
        self.assertEqual(l5.dataProvider().featureCount(), 1)
class NLSGeoPackageLoader:
    """QGIS Plugin Implementation."""
    def __init__(self, iface):
        """Constructor.

        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgsInterface
        """
        # Save reference to the QGIS interface
        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',
                                   'NLSGeoPackageLoader_{}.qm'.format(locale))

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

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

        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&NLS GeoPackage Downloader')

        # Check if plugin was started the first time in current QGIS session
        # Must be set in initGui() to survive plugin reloads
        self.first_start = None

        self.path = os.path.dirname(__file__)
        self.data_download_dir = self.path

        self.nls_user_key_dialog = uic.loadUi(
            os.path.join(self.path, NLS_USER_KEY_DIALOG_FILE))
        self.first_run = QSettings().value("/NLSgpkgloader/first_run",
                                           True,
                                           type=bool)
        if self.first_run:
            QSettings().setValue("/NLSgpkgloader/first_run", False)

    # 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('NLSGeoPackageLoader', 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)
        action.setEnabled(enabled_flag)

        if status_tip is not None:
            action.setStatusTip(status_tip)

        if whats_this is not None:
            action.setWhatsThis(whats_this)

        if add_to_toolbar:
            # Adds plugin icon to Plugins toolbar
            self.iface.addToolBarIcon(action)

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

        self.actions.append(action)

        return action

    def initGui(self):
        """Create the menu entries and toolbar icons inside the QGIS GUI."""

        icon_path = ':/plugins/nls_geopackage_loader/icon.png'
        self.add_action(icon_path,
                        text=self.tr(u'NLS GeoPackage Downloader'),
                        callback=self.run,
                        parent=self.iface.mainWindow())

        # will be set False in run()
        self.first_start = True

    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        for action in self.actions:
            self.iface.removePluginMenu(self.tr(u'&NLS GeoPackage Downloader'),
                                        action)
            self.iface.removeToolBarIcon(action)

    def run(self):
        """Run method that performs all the real work"""
        self.nls_user_key = QSettings().value("/NLSgpkgloader/userKey",
                                              "",
                                              type=str)
        self.data_download_dir = QSettings().value(
            "/NLSgpkgloader/dataDownloadDir", "", type=str)
        self.fileName = QSettings().value("/NLSgpkgloader/defaultFileName",
                                          "mtk.gpkg",
                                          type=str)
        self.addDownloadedDataAsLayer = QSettings().value(
            "/NLSgpkgloader/addDownloadedDataAsLayer", True, type=bool)
        self.showMunicipalitiesAsLayer = QSettings().value(
            "/NLSgpkgloader/showMunicipalitiesAsLayer", True, type=bool)
        self.showUTMGridsAsLayer = QSettings().value(
            "/NLSgpkgloader/showUTMGridsAsLayer", False, type=bool)
        self.showSeatilesAsLayer = QSettings().value(
            "/NLSgpkgloader/showSeatilesAsLayer", False, type=bool)

        if self.nls_user_key == "":
            res = self.showSettingsDialog()
            if not res: return
        if not self.loadLayers():
            QMessageBox.critical(
                self.iface.mainWindow(), self.tr(u'Failed to load data'),
                self.tr(u'Check that necessary files exist in data folder'))
            return

        self.product_types = self.downloadNLSProductTypes()

        self.municipalities_dialog = uic.loadUi(
            os.path.join(self.path, MUNICIPALITIES_DIALOG_FILE))
        self.municipalities_dialog.settingsPushButton.clicked.connect(
            self.showSettingsDialog)
        self.municipalities_dialog.fileNameEdit.setValue(self.fileName)
        self.municipalities_dialog.loadLayers.setChecked(
            self.addDownloadedDataAsLayer)
        self.municipalities_dialog.loadMunLayer.setChecked(
            self.showMunicipalitiesAsLayer)
        self.municipalities_dialog.loadUtmGrids.setChecked(
            self.showUTMGridsAsLayer)
        self.municipalities_dialog.loadSeaGrids.setChecked(
            self.showSeatilesAsLayer)
        self.municipalities_dialog.loadLayers.stateChanged.connect(
            self.toggleLayers)
        self.municipalities_dialog.loadMunLayer.stateChanged.connect(
            self.toggleLayers)
        self.municipalities_dialog.loadUtmGrids.stateChanged.connect(
            self.toggleLayers)
        self.municipalities_dialog.loadSeaGrids.stateChanged.connect(
            self.toggleLayers)
        self.toggleLayers()

        for feature in self.municipality_layer.getFeatures():
            item = QListWidgetItem(feature['NAMEFIN'])
            self.municipalities_dialog.municipalityListWidget.addItem(item)

        for key, value in self.product_types.items():
            item = QListWidgetItem(value)
            self.municipalities_dialog.productListWidget.addItem(item)
            if value in MTK_PRESELECTED_PRODUCTS:
                self.municipalities_dialog.productListWidget.setCurrentItem(
                    item)

        self.municipalities_dialog.show()

        result = self.municipalities_dialog.exec_()
        if result:
            self.fileName = self.municipalities_dialog.fileNameEdit.text(
            ).strip()
            if self.fileName == "":
                QMessageBox.critical(self.iface.mainWindow(),
                                     self.tr(u'Invalid filename'),
                                     self.tr(u'Please enter a filename'))
                return
            if self.fileName.split('.')[-1].lower() != 'gpkg':
                self.fileName += '.gpkg'
            QSettings().setValue("/NLSgpkgloader/defaultFileName",
                                 self.fileName)
            self.gpkg_path = os.path.join(self.data_download_dir,
                                          self.fileName)
            if os.path.isfile(self.gpkg_path):
                reply = QMessageBox.question(
                    self.iface.mainWindow(), 'Overwrite?',
                    'Overwrite file ' + self.gpkg_path + '?', QMessageBox.Yes,
                    QMessageBox.No)
                if reply == QMessageBox.Yes:
                    os.remove(self.gpkg_path)
                else:
                    return

            self.progress_dialog = uic.loadUi(
                os.path.join(self.path, NLS_PROGRESS_DIALOG_FILE))
            self.progress_dialog.progressBar.hide()
            self.progress_dialog.label.setText('Initializing...')
            self.progress_dialog.show()

            self.utm25lr_features = []
            self.selected_geoms = []
            for feature in self.utm25lr_layer.selectedFeatures():
                self.utm25lr_features.append(feature)
                self.selected_geoms.append(feature.geometry())
            grids = [
                self.utm5_layer, self.utm10_layer, self.utm25_layer,
                self.utm50_layer, self.utm100_layer, self.utm200_layer
            ]
            for grid in grids:
                for feature in grid.selectedFeatures():
                    self.selected_geoms.append(feature.geometry())

            selected_mun_names = []
            for item in self.municipalities_dialog.municipalityListWidget.selectedItems(
            ):
                selected_mun_names.append(item.text())
            for feature in self.municipality_layer.getFeatures():
                if feature["NAMEFIN"] in selected_mun_names:
                    self.selected_geoms.append(feature.geometry())

            for feature in self.municipality_layer.selectedFeatures():
                self.selected_geoms.append(feature.geometry())
            for feature in self.seatile_layer.selectedFeatures():
                self.selected_geoms.append(feature.geometry())

            product_types = {
            }  # TODO ask from the user via dialog that lists types based on NLS Atom service
            self.selected_mtk_product_types = []
            for selected_prod_title in self.municipalities_dialog.productListWidget.selectedItems(
            ):  # TODO: clean up the loop
                for key, value in list(self.product_types.items()):
                    if selected_prod_title.text() == value:
                        if key.startswith(
                                MTK_LAYERS_KEY_PREFIX):  # Individual MTK layer
                            self.selected_mtk_product_types.append(
                                selected_prod_title.text())
                            product_types[
                                MTK_ALL_PRODUCTS_URL] = MTK_ALL_PRODUCTS_TITLE
                        else:
                            product_types[key] = value

            if len(product_types) > 0 and len(self.selected_geoms) > 0:
                QCoreApplication.processEvents()

                self.getIntersectingFeatures(
                    self.municipality_layer.selectedFeatures(),
                    self.utm25lr_layer, selected_mun_names)
                self.getIntersectingFeatures(
                    self.seatile_layer.selectedFeatures(), self.utm25lr_layer)
                for grid in grids:
                    self.getIntersectingFeatures(grid.selectedFeatures(),
                                                 self.utm25lr_layer)

                self.downloadData(product_types)

            else:
                self.progress_dialog.hide()
                QMessageBox.critical(self.iface.mainWindow(),
                                     self.tr(u'Invalid selection'),
                                     self.tr(u'Found nothing to download!'))
                return

    def toggleLayers(self):
        '''Load municipality and map tile layers'''
        self.addDownloadedDataAsLayer = self.municipalities_dialog.loadLayers.isChecked(
        )
        self.showMunicipalitiesAsLayer = self.municipalities_dialog.loadMunLayer.isChecked(
        )
        self.showUTMGridsAsLayer = self.municipalities_dialog.loadUtmGrids.isChecked(
        )
        self.showSeatilesAsLayer = self.municipalities_dialog.loadSeaGrids.isChecked(
        )
        QSettings().setValue("/NLSgpkgloader/addDownloadedDataAsLayer",
                             self.addDownloadedDataAsLayer)
        QSettings().setValue("/NLSgpkgloader/showMunicipalitiesAsLayer",
                             self.showMunicipalitiesAsLayer)
        QSettings().setValue("/NLSgpkgloader/showUTMGridsAsLayer",
                             self.showUTMGridsAsLayer)
        QSettings().setValue("/NLSgpkgloader/showSeatilesAsLayer",
                             self.showSeatilesAsLayer)

        found_utm5_layer = found_utm10_layer = found_utm25lr_layer = \
            found_utm25_layer = found_utm50_layer = found_utm100_layer = \
                found_utm200_layer = found_seatiles_layer = found_municipality_layer = False

        current_layers = self.getLayers(self.instance.layerTreeRoot())

        for current_layer in current_layers:
            if current_layer.layer() == self.utm5_layer:
                found_utm5_layer = True
                current_layer.setItemVisibilityChecked(
                    self.showUTMGridsAsLayer)
            if current_layer.layer() == self.utm10_layer:
                found_utm10_layer = True
                current_layer.setItemVisibilityChecked(
                    self.showUTMGridsAsLayer)
            if current_layer.layer() == self.utm25lr_layer:
                found_utm25lr_layer = True
                current_layer.setItemVisibilityChecked(
                    self.showUTMGridsAsLayer)
            if current_layer.layer() == self.utm25_layer:
                found_utm25_layer = True
                current_layer.setItemVisibilityChecked(
                    self.showUTMGridsAsLayer)
            if current_layer.layer() == self.utm50_layer:
                found_utm50_layer = True
                current_layer.setItemVisibilityChecked(
                    self.showUTMGridsAsLayer)
            if current_layer.layer() == self.utm100_layer:
                found_utm100_layer = True
                current_layer.setItemVisibilityChecked(
                    self.showUTMGridsAsLayer)
            if current_layer.layer() == self.utm200_layer:
                found_utm200_layer = True
                current_layer.setItemVisibilityChecked(
                    self.showUTMGridsAsLayer)
            if current_layer.layer() == self.seatile_layer:
                found_seatiles_layer = True
                current_layer.setItemVisibilityChecked(
                    self.showSeatilesAsLayer)
            if current_layer.layer() == self.municipality_layer:
                found_municipality_layer = True
                current_layer.setItemVisibilityChecked(
                    self.showMunicipalitiesAsLayer)

        if self.showUTMGridsAsLayer:
            try:
                if not found_utm200_layer and self.utm200_layer:
                    self.instance.addMapLayer(self.utm200_layer)
                if not found_utm100_layer and self.utm100_layer:
                    self.instance.addMapLayer(self.utm100_layer)
                if not found_utm50_layer and self.utm50_layer:
                    self.instance.addMapLayer(self.utm50_layer)
                if not found_utm25_layer and self.utm25_layer:
                    self.instance.addMapLayer(self.utm25_layer)
                if not found_utm25lr_layer:
                    self.instance.addMapLayer(self.utm25lr_layer)
                if not found_utm10_layer and self.utm10_layer:
                    self.instance.addMapLayer(self.utm10_layer)
                if not found_utm5_layer and self.utm5_layer:
                    self.instance.addMapLayer(self.utm5_layer)
            except:
                self.loadLayers()
                if not found_utm200_layer and self.utm200_layer:
                    self.instance.addMapLayer(self.utm200_layer)
                if not found_utm100_layer and self.utm100_layer:
                    self.instance.addMapLayer(self.utm100_layer)
                if not found_utm50_layer and self.utm50_layer:
                    self.instance.addMapLayer(self.utm50_layer)
                if not found_utm25_layer and self.utm25_layer:
                    self.instance.addMapLayer(self.utm25_layer)
                if not found_utm25lr_layer:
                    self.instance.addMapLayer(self.utm25lr_layer)
                if not found_utm10_layer and self.utm10_layer:
                    self.instance.addMapLayer(self.utm10_layer)
                if not found_utm5_layer and self.utm5_layer:
                    self.instance.addMapLayer(self.utm5_layer)

        if self.showSeatilesAsLayer and not found_seatiles_layer:
            try:
                self.instance.addMapLayer(self.seatile_layer)
            except:
                self.loadLayers()
                self.instance.addMapLayer(self.seatile_layer)

        if self.showMunicipalitiesAsLayer and not found_municipality_layer:
            try:
                self.instance.addMapLayer(self.municipality_layer)
            except:
                self.loadLayers()
                self.instance.addMapLayer(self.municipality_layer)

    def loadLayers(self):
        self.municipality_layer = QgsVectorLayer(
            os.path.join(self.path, "data/SuomenKuntajako_2018_10k.shp"),
            "municipalities", "ogr")
        if not self.municipality_layer.isValid():
            QgsMessageLog.logMessage('Failed to load the municipality layer',
                                     'NLSgpkgloader', 2)
            self.iface.messageBar().pushMessage(
                "Error",
                "Failed to load the municipality layer",
                level=2,
                duration=5)
            return False
        self.municipality_layer.setProviderEncoding('ISO-8859-1')
        self.utm5_layer = QgsVectorLayer(
            os.path.join(self.path, "data/utm5.shp"), "utm5", "ogr")
        if not self.utm5_layer.isValid():
            QgsMessageLog.logMessage('Failed to load the UTM 5 grid layer',
                                     'NLSgpkgloader', 1)
            self.iface.messageBar().pushMessage(
                "Error",
                "Failed to load the UTM 5 grid layer",
                level=1,
                duration=5)
            self.utm5_layer = False
        self.utm10_layer = QgsVectorLayer(
            os.path.join(self.path, "data/utm10.shp"), "utm10", "ogr")
        if not self.utm10_layer.isValid():
            QgsMessageLog.logMessage('Failed to load the UTM 10 grid layer',
                                     'NLSgpkgloader', 1)
            self.iface.messageBar().pushMessage(
                "Error",
                "Failed to load the UTM 10 grid layer",
                level=1,
                duration=5)
            self.utm10_layer = False
        self.utm25lr_layer = QgsVectorLayer(
            os.path.join(self.path, "data/utm25LR.shp"), "utm25lr", "ogr")
        if not self.utm25lr_layer.isValid():
            QgsMessageLog.logMessage('Failed to load the UTM 25LR grid layer',
                                     'NLSgpkgloader', 2)
            self.iface.messageBar().pushMessage(
                "Error",
                "Failed to load the UTM 25LR grid layer",
                level=2,
                duration=5)
            return False
        self.utm25_layer = QgsVectorLayer(
            os.path.join(self.path, "data/utm25.shp"), "utm25", "ogr")
        if not self.utm25_layer.isValid():
            QgsMessageLog.logMessage('Failed to load the UTM 25 grid layer',
                                     'NLSgpkgloader', 1)
            self.iface.messageBar().pushMessage(
                "Error",
                "Failed to load the UTM 25 grid layer",
                level=1,
                duration=5)
            self.utm25_layer = False
        self.utm50_layer = QgsVectorLayer(
            os.path.join(self.path, "data/utm50.shp"), "utm50", "ogr")
        if not self.utm50_layer.isValid():
            QgsMessageLog.logMessage('Failed to load the UTM 50 grid layer',
                                     'NLSgpkgloader', 1)
            self.iface.messageBar().pushMessage(
                "Error",
                "Failed to load the UTM 50 grid layer",
                level=1,
                duration=5)
            self.utm50_layer = False
        self.utm100_layer = QgsVectorLayer(
            os.path.join(self.path, "data/utm100.shp"), "utm100", "ogr")
        if not self.utm100_layer.isValid():
            QgsMessageLog.logMessage('Failed to load the UTM 100 grid layer',
                                     'NLSgpkgloader', 1)
            self.iface.messageBar().pushMessage(
                "Error",
                "Failed to load the UTM 100 grid layer",
                level=1,
                duration=5)
            self.utm100_layer = False
        self.utm200_layer = QgsVectorLayer(
            os.path.join(self.path, "data/utm200.shp"), "utm200", "ogr")
        if not self.utm200_layer.isValid():
            QgsMessageLog.logMessage('Failed to load the UTM 200 grid layer',
                                     'NLSgpkgloader', 1)
            self.iface.messageBar().pushMessage(
                "Error",
                "Failed to load the UTM 200 grid layer",
                level=1,
                duration=5)
            self.utm200_layer = False

        expression = '"product_group_id" = 5'
        self.seatile_layer = QgsVectorLayer(
            os.path.join(self.path, "data/seatiles_3067.gpkg"), "seatiles",
            "ogr")
        self.seatile_layer.setSubsetString(expression)
        if not self.seatile_layer.isValid():
            QgsMessageLog.logMessage('Failed to load the ocean grid layer',
                                     'NLSgpkgloader', 2)
            self.iface.messageBar().pushMessage(
                "Error",
                "Failed to load the sea grid layer",
                level=2,
                duration=5)
            self.seatile_layer = False

        self.instance = QgsProject.instance()
        current_layers = self.getLayers(self.instance.layerTreeRoot())

        for lnode in current_layers:
            if lnode.layer().dataProvider().dataSourceUri(
            ) == self.municipality_layer.dataProvider().dataSourceUri():
                self.municipality_layer = lnode.layer()
            if lnode.layer().dataProvider().dataSourceUri(
            ) == self.seatile_layer.dataProvider().dataSourceUri():
                self.seatile_layer = lnode.layer()
            if lnode.layer().dataProvider().dataSourceUri(
            ) == self.utm5_layer.dataProvider().dataSourceUri():
                self.utm5_layer = lnode.layer()
            if lnode.layer().dataProvider().dataSourceUri(
            ) == self.utm10_layer.dataProvider().dataSourceUri():
                self.utm10_layer = lnode.layer()
            if lnode.layer().dataProvider().dataSourceUri(
            ) == self.utm25_layer.dataProvider().dataSourceUri():
                self.utm25_layer = lnode.layer()
            if lnode.layer().dataProvider().dataSourceUri(
            ) == self.utm25lr_layer.dataProvider().dataSourceUri():
                self.utm25lr_layer = lnode.layer()
            if lnode.layer().dataProvider().dataSourceUri(
            ) == self.utm50_layer.dataProvider().dataSourceUri():
                self.utm50_layer = lnode.layer()
            if lnode.layer().dataProvider().dataSourceUri(
            ) == self.utm100_layer.dataProvider().dataSourceUri():
                self.utm100_layer = lnode.layer()
            if lnode.layer().dataProvider().dataSourceUri(
            ) == self.utm200_layer.dataProvider().dataSourceUri():
                self.utm200_layer = lnode.layer()

        return True

    def getLayers(self, root):
        layers = []
        for node in root.children():
            if isinstance(node, QgsLayerTreeGroup):
                layers.extend(self.getLayers(node))
            else:
                layers.append(node)
        return layers

    def getIntersectingFeatures(self,
                                features,
                                layer,
                                selected_mun_names=None):
        if selected_mun_names:
            expression = ''
            for mun in selected_mun_names:
                expression += u'"NAMEFIN" = \'' + mun + u'\' OR '
            expression = expression[:-4]

            iter = self.municipality_layer.getFeatures(expression)
            for feature in iter:
                mun_geom = feature.geometry()
                for layer_feature in layer.getFeatures():
                    layer_geom = layer_feature.geometry()
                    if mun_geom.intersects(layer_geom):
                        if feature not in self.utm25lr_features:
                            self.utm25lr_features.append(layer_feature)

        for feature in features:
            feat_geom = feature.geometry()
            for layer_feature in layer.getFeatures():
                layer_geom = layer_feature.geometry()
                if feat_geom.intersects(layer_geom):
                    if feature not in self.utm25lr_features:
                        self.utm25lr_features.append(layer_feature)

    def downloadData(self, product_types):

        self.all_urls = []
        self.total_download_count = 0
        self.download_count = 0
        self.layers_added_count = 0

        for product_key, product_title in product_types.items():
            urls = self.createDownloadURLS(product_key, product_title)
            self.all_urls.extend(urls)
            self.total_download_count += len(urls)

        try:
            percentage = self.download_count / float(
                self.total_download_count) * 100.0
            percentage_text = "%.2f" % round(percentage, 2)
        except ZeroDivisionError:
            QMessageBox.critical(self.iface.mainWindow(),
                                 self.tr(u'Invalid selection'),
                                 self.tr(u'Found nothing to download!'))
            self.progress_dialog.hide()
            return

        self.progress_dialog.progressBar.reset()
        self.progress_dialog.progressBar.show()
        self.progress_dialog.label.setText('Downloading data...')
        QTimer.singleShot(1000, self.downloadOneFile)

    def downloadNLSProductTypes(self):
        products = {}

        url = "https://tiedostopalvelu.maanmittauslaitos.fi/tp/feed/mtp?api_key=" + self.nls_user_key
        # TODO: use qgis.gui.QgsFileDownloader?
        self.verify = True
        try:
            r = requests.get(url, verify=self.verify)
        except requests.exceptions.SSLError:
            # TODO: warn user of certification fail
            self.verify = False
            r = requests.get(url, verify=self.verify)

        e = xml.etree.ElementTree.fromstring(r.text)

        for entry in e.findall('{http://www.w3.org/2005/Atom}entry'):
            title = entry.find('{http://www.w3.org/2005/Atom}title')
            QgsMessageLog.logMessage(title.text, 'NLSgpkgloader', 0)
            id = entry.find('{http://www.w3.org/2005/Atom}id')
            QgsMessageLog.logMessage(id.text, 'NLSgpkgloader', 0)

            if title.text == 'Maastotietokanta, kaikki kohteet':
                # TODO let user choose in the options dialog if the individual layers can be selected
                for mtk_product_name in MTK_PRODUCT_NAMES:
                    products[MTK_LAYERS_KEY_PREFIX +
                             mtk_product_name] = mtk_product_name
            else:
                # products[id.text] = title.text
                pass

        return products

    def downloadOneFile(self):
        if self.download_count == self.total_download_count or self.download_count >= len(
                self.all_urls):
            QgsMessageLog.logMessage(
                "download_count == total_download_count or download_count >= len(all_urls)",
                'NLSgpkgloader', 2)
            return

        url = self.all_urls[self.download_count][0]
        # QgsMessageLog.logMessage(url, 'NLSgpkgloader', 0)
        r = requests.get(url, stream=True, verify=self.verify)
        # TODO check r.status_code & r.ok

        url_parts = url.split('/')
        file_name = url_parts[-1].split('?')[0]

        data_dir_name = self.all_urls[self.download_count][1]
        data_dir_name = data_dir_name.replace(":", "_suhde_")
        dir_path = os.path.join(self.data_download_dir, data_dir_name)

        #QgsMessageLog.logMessage(dir_path, 'NLSgpkgloader', 0)
        if not os.path.exists(dir_path):
            try:
                os.makedirs(dir_path)
            except OSError as exc:
                QgsMessageLog.logMessage(str(exc.errno), 'NLSgpkgloader', 2)
        if not os.path.exists(dir_path):
            QgsMessageLog.logMessage("dir not created", 'NLSgpkgloader', 2)

        # TODO: don't keep zipfiles
        #z = zipfile.ZipFile(StringIO.StringIO(r.content))
        #z.extractall(os.path.join(self.data_download_dir, value))
        with open(os.path.join(dir_path, file_name), 'wb') as f:
            f.write(r.content)

        if "zip" in file_name:
            dir_path = os.path.join(dir_path, file_name.split('.')[0])
            try:
                z = zipfile.ZipFile(io.BytesIO(r.content))
                z.extractall(dir_path)
            except BadZipFile:
                QgsMessageLog.logMessage("Bad zip file: " + file_name,
                                         'NLSgpkgloader', 1)

        self.download_count += 1
        percentage = self.download_count / float(
            self.total_download_count) * 100.0
        self.progress_dialog.progressBar.setValue(percentage)

        if self.download_count == self.total_download_count:
            QgsMessageLog.logMessage("done downloading data", 'NLSgpkgloader',
                                     0)
            self.createGeoPackage()
        else:
            QTimer.singleShot(10, self.downloadOneFile)

    def createGeoPackage(self):
        '''Creates a GeoPackage from the downloaded MTK data'''
        self.progress_dialog.progressBar.reset()
        self.progress_dialog.label.setText('Writing layers to GeoPackage...')

        writeTask = CreateGeoPackageTask('Write GML to GPKG', self.all_urls, self.total_download_count, \
            self.selected_mtk_product_types, self.data_download_dir, self.gpkg_path)
        dissolveTask = DissolveFeaturesTask("Dissolve features",
                                            self.gpkg_path)
        clipTask = ClipLayersTask("Clip layers", self.selected_geoms,
                                  self.gpkg_path)
        cleanupTask = CleanUpTask("Delete temporary tables", self.path,
                                  self.gpkg_path)

        writeTask.taskCompleted.connect(lambda: self.runTask(dissolveTask))
        dissolveTask.taskCompleted.connect(lambda: self.runTask(clipTask))
        clipTask.taskCompleted.connect(lambda: self.runTask(cleanupTask))
        cleanupTask.taskCompleted.connect(lambda: self.finishProcessing())

        self.runTask(writeTask)

    def runTask(self, task):
        self.progress_dialog.label.setText(task.description())
        task.progressChanged.connect(
            lambda: self.progress_dialog.progressBar.setValue(task.progress()))
        QgsApplication.taskManager().addTask(task)

    def finishProcessing(self):
        if self.addDownloadedDataAsLayer:
            self.progress_dialog.label.setText("Adding layers to QGIS")
            self.progress_dialog.progressBar.hide()
            conn = ogr.Open(self.gpkg_path)
            for i in conn:
                if i.GetName() in MTK_STYLED_LAYERS.values() or i.GetName(
                )[3:] in MTK_PRODUCT_NAMES:
                    self.instance.addMapLayer(
                        QgsVectorLayer(
                            self.gpkg_path + "|layername=" + i.GetName(),
                            i.GetName(), "ogr"))
        self.iface.messageBar().pushMessage(self.tr(u'GeoPackage creation finished'), \
            self.tr(u'NLS data download finished. Data located under ') + \
            self.gpkg_path, level=3)
        self.progress_dialog.hide()
        return True

    def showSettingsDialog(self):
        self.nls_user_key_dialog.dataLocationQgsFileWidget.setStorageMode(
            QgsFileWidget.GetDirectory)
        self.nls_user_key_dialog.userKeyLineEdit.setText(self.nls_user_key)
        self.nls_user_key_dialog.dataLocationQgsFileWidget.setFilePath(
            QSettings().value("/NLSgpkgloader/dataDownloadDir",
                              os.path.join(self.path, "data"),
                              type=str))

        self.nls_user_key_dialog.show()
        result = self.nls_user_key_dialog.exec_()
        if result:
            self.nls_user_key = self.nls_user_key_dialog.userKeyLineEdit.text(
            ).strip()
            if self.nls_user_key == "":
                # cannot work without the key, so user needs to be notified
                QMessageBox.critical(
                    self.iface.mainWindow(), self.tr(u'User-key is needed'),
                    self.tr(u'Data cannot be downloaded without the NLS key'))
                return False
            self.data_download_dir = self.nls_user_key_dialog.dataLocationQgsFileWidget.filePath(
            )

            QSettings().setValue("/NLSgpkgloader/userKey", self.nls_user_key)
            QSettings().setValue("/NLSgpkgloader/dataDownloadDir",
                                 self.data_download_dir)
            return True

        else:
            # cannot work without the key, so user needs to be notified
            QMessageBox.critical(
                self.iface.mainWindow(), self.tr(u'User-key is needed'),
                self.tr(u'Data cannot be downloaded without the NLS key'))
            return False

    def createDownloadURLS(self, product_key, product_title):
        urls = []
        if product_key == "https://tiedostopalvelu.maanmittauslaitos.fi/tp/feed/mtp/maastotietokanta/kaikki":
            for utm_feature in self.utm25lr_features:
                sheet_name = utm_feature["LEHTITUNNU"]
                sn1 = sheet_name[:2]
                sn2 = sheet_name[:3]
                modified_key = product_key.replace("/feed/mtp",
                                                   "/tilauslataus/tuotteet")
                url = modified_key + "/etrs89/gml/" + sn1 + "/" + sn2 + "/" + sheet_name + "_mtk.zip?api_key=" + self.nls_user_key
                urls.append((url, product_title, product_key, "gml"))
        else:
            QgsMessageLog.logMessage(
                'Unknown product ' + product_title +
                ', please send error report to the author', 'NLSgpkgloader', 2)
            self.iface.messageBar().pushMessage(
                'Unknown product ' + product_title +
                ', please send error report to the author',
                level=2,
                duration=10)

        return urls
Example #28
0
    def testEditSubsetString(self):

        tmpfile = os.path.join(self.basetestpath, 'testEditSubsetString.gpkg')
        ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
        lyr = ds.CreateLayer('test', geom_type=ogr.wkbMultiPolygon)
        lyr.CreateField(ogr.FieldDefn('foo', ogr.OFTString))
        f = ogr.Feature(lyr.GetLayerDefn())
        f['foo'] = 'bar'
        lyr.CreateFeature(f)
        f = None
        f = ogr.Feature(lyr.GetLayerDefn())
        f['foo'] = 'baz'
        lyr.CreateFeature(f)
        f = None
        ds = None

        vl = QgsVectorLayer('{}|layerid=0'.format(tmpfile), 'test', 'ogr')
        self.assertEqual(vl.dataProvider().featureCount(), 2)

        # Test adding features
        vl.setSubsetString("foo = 'baz'")
        self.assertTrue(vl.startEditing())
        feature = QgsFeature(vl.fields())
        feature['foo'] = 'abc'
        vl.addFeature(feature)
        vl.commitChanges()
        vl.setSubsetString(None)
        self.assertEqual(vl.dataProvider().featureCount(), 3)

        # Test deleting a feature
        vl.setSubsetString("foo = 'baz'")
        self.assertTrue(vl.startEditing())
        vl.deleteFeature(1)
        vl.commitChanges()
        vl.setSubsetString(None)
        self.assertEqual(vl.dataProvider().featureCount(), 2)

        # Test editing a feature
        vl.setSubsetString("foo = 'baz'")
        self.assertTrue(vl.startEditing())
        vl.changeAttributeValue(2, 1, 'xx')
        vl.commitChanges()
        vl.setSubsetString(None)
        self.assertEqual(set((feat['foo'] for feat in vl.getFeatures())), set(['xx', 'abc']))
Example #29
0
    def test_data_defined_layout_properties(self):  # pylint: disable=too-many-statements
        """
        Test data defined stroke color
        """
        layer_path = os.path.join(os.path.dirname(__file__), 'test_layer.shp')

        vl1 = QgsVectorLayer(layer_path, 'test_layer', 'ogr')
        vl1.setSubsetString('id < 10')
        self.assertTrue(vl1.isValid())
        QgsProject.instance().addMapLayer(vl1)

        settings = PlotSettings('scatter')
        settings.source_layer_id = vl1.id()
        settings.properties['x_name'] = 'so4'
        settings.properties['y_name'] = 'mg'
        settings.layout['title'] = 'title'
        settings.layout['legend_title'] = 'legend_title'
        settings.layout['x_title'] = 'x_title'
        settings.layout['y_title'] = 'y_title'
        settings.layout['z_title'] = 'z_title'
        settings.layout['x_min'] = 0
        settings.layout['x_max'] = 1
        settings.layout['y_min'] = 0
        settings.layout['y_max'] = 1

        factory = PlotFactory(settings)
        # should be empty, not using data defined size
        self.assertEqual(factory.settings.x,
                         [98, 88, 267, 329, 319, 137, 350, 151, 203])
        self.assertEqual(
            factory.settings.y,
            [72.31, 86.03, 85.26, 81.11, 131.59, 95.36, 112.88, 80.55, 78.34])
        self.assertEqual(factory.settings.data_defined_title, '')
        self.assertEqual(factory.settings.data_defined_legend_title, '')
        self.assertEqual(factory.settings.data_defined_x_title, '')
        self.assertEqual(factory.settings.data_defined_y_title, '')
        self.assertEqual(factory.settings.data_defined_z_title, '')
        self.assertEqual(factory.settings.data_defined_x_min, None)
        self.assertEqual(factory.settings.data_defined_x_max, None)
        self.assertEqual(factory.settings.data_defined_y_min, None)
        self.assertEqual(factory.settings.data_defined_y_max, None)

        class TestGenerator(QgsExpressionContextGenerator):  # pylint: disable=missing-docstring, too-few-public-methods
            def createExpressionContext(self) -> QgsExpressionContext:  # pylint: disable=missing-docstring, no-self-use
                context = QgsExpressionContext()
                scope = QgsExpressionContextScope()
                scope.setVariable('some_var', 10)
                context.appendScope(scope)
                context.appendScope(vl1.createExpressionContextScope())
                return context

        generator = TestGenerator()
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_TITLE,
            QgsProperty.fromExpression("concat('my', '_title_', @some_var)"))
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_LEGEND_TITLE,
            QgsProperty.fromExpression("concat('my', '_legend_', @some_var)"))
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_X_TITLE,
            QgsProperty.fromExpression("concat('my', '_x_axis_', @some_var)"))
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_Y_TITLE,
            QgsProperty.fromExpression("concat('my', '_y_axis_', @some_var)"))
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_Z_TITLE,
            QgsProperty.fromExpression("concat('my', '_z_axis_', @some_var)"))
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_X_MIN,
            QgsProperty.fromExpression("-1*@some_var"))
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_X_MAX,
            QgsProperty.fromExpression("+1*@some_var"))
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_Y_MIN,
            QgsProperty.fromExpression("-1*@some_var"))
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_Y_MAX,
            QgsProperty.fromExpression("+1*@some_var"))
        factory = PlotFactory(settings, context_generator=generator)
        self.assertEqual(factory.settings.x,
                         [98, 88, 267, 329, 319, 137, 350, 151, 203])
        self.assertEqual(
            factory.settings.y,
            [72.31, 86.03, 85.26, 81.11, 131.59, 95.36, 112.88, 80.55, 78.34])
        self.assertEqual(factory.settings.data_defined_title, 'my_title_10')
        self.assertEqual(factory.settings.data_defined_legend_title,
                         'my_legend_10')
        self.assertEqual(factory.settings.data_defined_x_title, 'my_x_axis_10')
        self.assertEqual(factory.settings.data_defined_y_title, 'my_y_axis_10')
        self.assertEqual(factory.settings.data_defined_z_title, 'my_z_axis_10')
        self.assertEqual(factory.settings.data_defined_x_min, -10)
        self.assertEqual(factory.settings.data_defined_x_max, 10)
        self.assertEqual(factory.settings.data_defined_y_min, -10)
        self.assertEqual(factory.settings.data_defined_y_max, 10)
Example #30
0
    def testMalformedSubsetStrings(self):
        """Test that invalid where clauses always return false"""

        testPath = TEST_DATA_DIR + '/' + 'lines.shp'

        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
        self.assertTrue(vl.isValid())
        self.assertTrue(vl.setSubsetString(''))
        self.assertTrue(vl.setSubsetString('"Name" = \'Arterial\''))
        self.assertTrue(
            vl.setSubsetString(
                'select * from lines where "Name" = \'Arterial\''))
        self.assertFalse(vl.setSubsetString('this is invalid sql'))
        self.assertFalse(
            vl.setSubsetString(
                'select * from lines where "NonExistentField" = \'someValue\'')
        )
        self.assertFalse(
            vl.setSubsetString('select * from lines where "Name" = \'Arte...'))
        self.assertFalse(
            vl.setSubsetString(
                'select * from lines where "Name" in (\'Arterial\', \'Highway\' '
            ))
        self.assertFalse(vl.setSubsetString('select * from NonExistentTable'))
        self.assertFalse(
            vl.setSubsetString('select NonExistentField from lines'))
        self.assertFalse(
            vl.setSubsetString('"NonExistentField" = \'someValue\''))
        self.assertFalse(vl.setSubsetString('"Name" = \'Arte...'))
        self.assertFalse(
            vl.setSubsetString('"Name" in (\'Arterial\', \'Highway\' '))
        self.assertTrue(vl.setSubsetString(''))
Example #31
0
    def toSqlLayer(self, sql, geomCol, uniqueCol, layerName="QueryLayer", layerType=None, avoidSelectById=False, filter=""):
        from qgis.core import QgsVectorLayer

        vl = QgsVectorLayer(self.uri().database(), layerName, 'ogr')
        vl.setSubsetString(sql)
        return vl
    def loadTable(self):
        sites = u", ".join(u"'{0}'".format(siteNumber) for siteNumber in self.polygonDict)

        # Fundstellen des Fundortes Editieren
        uri = QgsDataSourceURI()
        uri.setDatabase(self.dbm.db.databaseName())
        uri.setDataSource('', 'fundstelle', 'geometry')
        findSpotLayer = QgsVectorLayer(uri.uri(), u'Fundstelle', 'spatialite')
        findSpotLayer.setSubsetString(u'"fundortnummer" IN ({0})'.format(sites))

        if findSpotLayer.featureCount() > 0:
            fSIter = findSpotLayer.getFeatures()
            for fSFeature in fSIter:
                fSGeom = fSFeature.geometry()
                sN = fSFeature.attribute("fundortnummer")
                fSN = fSFeature.attribute("fundstellenummer")

                fSNumber = u"{0}.{1}".format(sN,fSN)
                #QMessageBox.information(None, 'Error', u"{0}, {1}, {2}".format(self.polygonDict[sN][0], self.polygonDict[sN][1], self.polygonDict[sN][2]))
                #dj0 = self.polygonDict[sN][0].disjoint(fSGeom)
                #tc0 = self.polygonDict[sN][0].touches(fSGeom)
                #eq0 = self.polygonDict[sN][0].equals(fSGeom)
                #co0 = self.polygonDict[sN][0].contains(fSGeom)
                #co2 = self.polygonDict[sN][2].contains(fSGeom)
                #eq1 = fSGeom.equals(self.polygonDict[sN][1])
                #wi0 = self.polygonDict[sN][0].within(fSGeom)
                #ol0 = self.polygonDict[sN][0].overlaps(fSGeom)
                if self.polygonDict[sN][0].disjoint(fSGeom):
                    relationship = "disjoint"
                    action = [self.ACTION_1]
                elif self.polygonDict[sN][0].touches(fSGeom):
                    relationship = "touches"
                    action = [self.ACTION_1]
                elif self.polygonDict[sN][0].equals(fSGeom):
                    relationship = "equal"
                    action = [self.ACTION_0]
                elif self.polygonDict[sN][0].contains(fSGeom) or self.polygonDict[sN][2].contains(fSGeom):
                    relationship = "contains"
                    if fSGeom.equals(self.polygonDict[sN][1]):
                        action = [self.ACTION_1, self.ACTION_0]
                    else:
                        action = [self.ACTION_0, self.ACTION_1]
                elif self.polygonDict[sN][0].within(fSGeom):
                    relationship = "within"
                    action = [self.ACTION_1]
                elif self.polygonDict[sN][0].overlaps(fSGeom):
                    relationship = "overlaps"
                    if fSGeom.equals(self.polygonDict[sN][1]):
                        action = [self.ACTION_1, self.ACTION_2]
                    else:
                        action = [self.ACTION_2, self.ACTION_1]
                else:
                    relationship = "error"
                    action = []

                rowPos = self.uiFindSpotAssessmentTable.rowCount()
                self.uiFindSpotAssessmentTable.insertRow(rowPos)

                self.uiFindSpotAssessmentTable.setItem(rowPos, 0, QTableWidgetItem(fSNumber))
                self.uiFindSpotAssessmentTable.setItem(rowPos, 1, QTableWidgetItem(relationship))

                if len(action) > 1:
                    comboBox = QComboBox()
                    comboBox.addItems(action)
                    self.uiFindSpotAssessmentTable.setCellWidget(rowPos, 2, comboBox)
                else:
                    self.uiFindSpotAssessmentTable.setItem(rowPos, 2, QTableWidgetItem(", ".join(action)))
Example #33
0
    def layer_to_QgsVectorLayer(
            source_layer,  # pylint: disable=too-many-locals,too-many-branches,too-many-statements
            input_file,
            context: Context,
            fallback_crs=QgsCoordinateReferenceSystem(),
            defer_layer_uri_set: bool = False):
        """
        Converts a vector layer
        """
        if source_layer.__class__.__name__ == 'CadFeatureLayer':
            layer = source_layer.layer
        else:
            layer = source_layer

        crs = CrsConverter.convert_crs(
            layer.layer_extent.crs,
            context) if layer.layer_extent else QgsCoordinateReferenceSystem()
        if not crs.isValid():
            crs = fallback_crs

        subset_string = ''
        if layer.selection_set:
            subset_string = 'fid in ({})'.format(','.join(
                [str(s) for s in layer.selection_set]))
        elif layer.definition_query:
            subset_string = ExpressionConverter.convert_esri_sql(
                layer.definition_query)

        base, _ = os.path.split(input_file)

        uri, wkb_type, provider, encoding, file_name = VectorLayerConverter.get_uri(
            source_layer=source_layer,
            obj=layer,
            base=base,
            crs=crs,
            subset=subset_string,
            context=context)

        if wkb_type is None or wkb_type == QgsWkbTypes.Unknown:
            wkb_type = VectorLayerConverter.layer_to_wkb_type(layer)
        context.layer_type_hint = wkb_type

        if Qgis.QGIS_VERSION_INT >= 31600:
            # try to get the layer name so that we can remove it from field references.
            # e.g. if layer name is polys then qgis won't support to arcgis style "polys.field" format
            parts = QgsProviderRegistry.instance().decodeUri(provider, uri)
            context.main_layer_name = parts.get('layerName')
            if not context.main_layer_name and provider == 'ogr':
                context.main_layer_name = Path(parts['path']).stem

            if context.main_layer_name:
                subset_string = subset_string.replace(
                    context.main_layer_name + '.', '')
        else:
            context.main_layer_name = None

        if provider == 'ogr' and (not file_name
                                  or not os.path.exists(file_name)
                                  ) and context.invalid_layer_resolver:
            res = context.invalid_layer_resolver(layer.name, uri, wkb_type)
            uri = res.uri
            provider = res.providerKey

        if Qgis.QGIS_VERSION_INT >= 31000:
            opts = QgsVectorLayer.LayerOptions()
            if wkb_type is not None:
                opts.fallbackWkbType = wkb_type

            if provider == 'ogr' and subset_string:
                uri += '|subset={}'.format(subset_string)

            original_uri = uri
            if defer_layer_uri_set:
                uri = 'xxxxxxxxx' + uri

            vl = QgsVectorLayer(uri, layer.name, provider, opts)
            if defer_layer_uri_set:
                vl.setCustomProperty('original_uri', original_uri)
        else:
            vl = QgsMemoryProviderUtils.createMemoryLayer(
                layer.name, QgsFields(), wkb_type, crs)

        # context.style_folder, _ = os.path.split(output_file)
        if layer.renderer:
            renderer = VectorRendererConverter.convert_renderer(
                layer.renderer, context)
            try:
                if not renderer.usingSymbolLevels():
                    renderer.setUsingSymbolLevels(
                        layer.use_advanced_symbol_levels)
            except AttributeError:
                pass

            if layer.use_page_definition_query:
                filter_expression = '"{}" {} @atlas_pagename'.format(
                    layer.page_name_field, layer.page_name_match_operator)
                root_rule = QgsRuleBasedRenderer.Rule(None)

                # special case -- convert a simple renderer
                if isinstance(renderer, QgsSingleSymbolRenderer):
                    filter_rule = QgsRuleBasedRenderer.Rule(
                        renderer.symbol().clone())
                    filter_rule.setFilterExpression(filter_expression)
                    filter_rule.setLabel(layer.name)
                    filter_rule.setDescription(layer.name)
                    root_rule.appendChild(filter_rule)
                else:
                    source_rule_renderer = QgsRuleBasedRenderer.convertFromRenderer(
                        renderer)
                    filter_rule = QgsRuleBasedRenderer.Rule(None)
                    filter_rule.setFilterExpression(filter_expression)
                    filter_rule.setLabel('Current Atlas Page')
                    filter_rule.setDescription('Current Atlas Page')
                    root_rule.appendChild(filter_rule)
                    for child in source_rule_renderer.rootRule().children():
                        filter_rule.appendChild(child.clone())

                renderer = QgsRuleBasedRenderer(root_rule)

            if renderer:
                vl.setRenderer(renderer)
                vl.triggerRepaint()
        else:
            vl.setRenderer(QgsNullSymbolRenderer())
            vl.triggerRepaint()

        metadata = vl.metadata()
        metadata.setAbstract(layer.description)
        vl.setMetadata(metadata)  #

        # layer.zoom_max = "don't show when zoomed out beyond"
        zoom_max = layer.zoom_max
        # layer.zoom_min = "don't show when zoomed in beyond"
        zoom_min = layer.zoom_min

        enabled_scale_range = bool(zoom_max or zoom_min)
        if zoom_max and zoom_min and zoom_min > zoom_max:
            # inconsistent scale range -- zoom_max should be bigger number than zoom_min
            zoom_min, zoom_max = zoom_max, zoom_min

        # qgis minimum scale = don't show when zoomed out beyond, i.e. ArcGIS zoom_max
        vl.setMinimumScale(
            zoom_max if enabled_scale_range else layer.stored_zoom_max)
        # qgis maximum scale = don't show when zoomed in beyond, i.e. ArcGIS zoom_min
        vl.setMaximumScale(
            zoom_min if enabled_scale_range else layer.stored_zoom_min)
        vl.setScaleBasedVisibility(enabled_scale_range)

        vl.setOpacity(1.0 - (layer.transparency or 0) / 100)

        if layer.display_expression_properties and layer.display_expression_properties.expression and layer.display_expression_properties.expression_parser is not None:
            vl.setDisplayExpression(
                ExpressionConverter.convert(
                    layer.display_expression_properties.expression,
                    layer.display_expression_properties.expression_parser,
                    layer.display_expression_properties.advanced, context))

        if Qgis.QGIS_VERSION_INT < 31000:
            vl.setDataSource(uri, layer.name, provider)

        if encoding:
            vl.dataProvider().setEncoding(encoding)

        if subset_string:
            vl.setSubsetString(subset_string)

        vl.setCrs(crs)

        for e in layer.extensions:
            if e.__class__.__name__ == 'ServerLayerExtension':
                if 'CopyrightText' in e.properties.properties:
                    layer_credits = e.properties.properties['CopyrightText']
                    metadata = vl.metadata()
                    rights = metadata.rights()
                    rights.append(layer_credits)
                    metadata.setRights(rights)
                    vl.setMetadata(metadata)

        LabelConverter.convert_annotation_collection(
            layer.annotation_collection, dest_layer=vl, context=context)
        vl.setLabelsEnabled(layer.labels_enabled)

        DiagramConverter.convert_diagrams(layer.renderer,
                                          dest_layer=vl,
                                          context=context)

        # setup joins
        join_layer = VectorLayerConverter.add_joined_layer(
            source_layer=layer,
            input_file=input_file,
            base_layer=vl,
            context=context)

        context.dataset_name = ''

        vl.setLegend(QgsMapLayerLegend.defaultVectorLegend(vl))

        if layer.hyperlinks:
            VectorLayerConverter.convert_hyperlinks(layer.hyperlinks, vl)

        vl.setDisplayExpression(
            QgsExpression.quotedColumnRef(layer.display_field))

        res = [vl]
        if join_layer:
            res.append(join_layer)

        context.main_layer_name = None
        return res
Example #34
0
    def standalone_table_to_QgsVectorLayer(
            layer: StandaloneTable,  # pylint: disable=too-many-locals,too-many-branches
            input_file,
            context: Context):
        """
        Converts a standalone table to a vector layer
        """
        subset_string = ''
        if layer.definition_query:
            subset_string = ExpressionConverter.convert_esri_sql(
                layer.definition_query)

        base, _ = os.path.split(input_file)

        uri, wkb_type, provider, encoding, file_name = VectorLayerConverter.get_uri(
            source_layer=layer,
            obj=layer,
            base=base,
            crs=QgsCoordinateReferenceSystem(),
            subset=subset_string,
            context=context)

        if wkb_type is None:
            wkb_type = QgsWkbTypes.NoGeometry
        context.layer_type_hint = wkb_type

        if provider == 'ogr' and (not file_name
                                  or not os.path.exists(file_name)
                                  ) and context.invalid_layer_resolver:
            res = context.invalid_layer_resolver(layer.name, uri, wkb_type)
            uri = res.uri
            provider = res.providerKey

        if Qgis.QGIS_VERSION_INT >= 31000:
            opts = QgsVectorLayer.LayerOptions()
            if wkb_type is not None:
                opts.fallbackWkbType = wkb_type

            if provider == 'ogr' and subset_string:
                uri += '|subset={}'.format(subset_string)

            vl = QgsVectorLayer(uri, layer.name, provider, opts)
        else:
            vl = QgsMemoryProviderUtils.createMemoryLayer(
                layer.name, QgsFields(), wkb_type,
                QgsCoordinateReferenceSystem())

        metadata = vl.metadata()
        metadata.setAbstract(layer.description)
        vl.setMetadata(metadata)  #

        if Qgis.QGIS_VERSION_INT < 31000:
            vl.setDataSource(uri, layer.name, provider)

        if encoding:
            vl.dataProvider().setEncoding(encoding)

        if subset_string:
            vl.setSubsetString(subset_string)

        for e in layer.extensions:
            if e.__class__.__name__ == 'ServerLayerExtension':
                if 'CopyrightText' in e.properties.properties:
                    layer_credits = e.properties.properties['CopyrightText']
                    metadata = vl.metadata()
                    rights = metadata.rights()
                    rights.append(layer_credits)
                    metadata.setRights(rights)
                    vl.setMetadata(metadata)

        # setup joins
        join_layer = VectorLayerConverter.add_joined_layer(
            source_layer=layer,
            input_file=input_file,
            base_layer=vl,
            context=context)

        context.dataset_name = ''

        vl.setLegend(QgsMapLayerLegend.defaultVectorLegend(vl))

        res = [vl]
        if join_layer:
            res.append(join_layer)

        return res
Example #35
0
    def testEditSubsetString(self):

        tmpfile = os.path.join(self.basetestpath, 'testEditSubsetString.gpkg')
        ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
        lyr = ds.CreateLayer('test', geom_type=ogr.wkbMultiPolygon)
        lyr.CreateField(ogr.FieldDefn('foo', ogr.OFTString))
        f = ogr.Feature(lyr.GetLayerDefn())
        f['foo'] = 'bar'
        lyr.CreateFeature(f)
        f = None
        f = ogr.Feature(lyr.GetLayerDefn())
        f['foo'] = 'baz'
        lyr.CreateFeature(f)
        f = None
        ds = None

        vl = QgsVectorLayer('{}|layerid=0'.format(tmpfile), 'test', 'ogr')
        self.assertEqual(vl.dataProvider().featureCount(), 2)

        # Test adding features
        vl.setSubsetString("foo = 'baz'")
        self.assertTrue(vl.startEditing())
        feature = QgsFeature(vl.fields())
        feature['foo'] = 'abc'
        vl.addFeature(feature)
        vl.commitChanges()
        vl.setSubsetString(None)
        self.assertEqual(vl.dataProvider().featureCount(), 3)

        # Test deleting a feature
        vl.setSubsetString("foo = 'baz'")
        self.assertTrue(vl.startEditing())
        vl.deleteFeature(1)
        vl.commitChanges()
        vl.setSubsetString(None)
        self.assertEqual(vl.dataProvider().featureCount(), 2)

        # Test editing a feature
        vl.setSubsetString("foo = 'baz'")
        self.assertTrue(vl.startEditing())
        vl.changeAttributeValue(2, 1, 'xx')
        vl.commitChanges()
        vl.setSubsetString(None)
        self.assertEqual(set((feat['foo'] for feat in vl.getFeatures())), set(['xx', 'abc']))
    def loadTable(self):
        sites = u", ".join(u"'{0}'".format(siteNumber)
                           for siteNumber in self.polygonDict)

        # Fundstellen des Fundortes Editieren
        uri = QgsDataSourceUri()
        uri.setDatabase(self.dbm.db.databaseName())
        uri.setDataSource('', 'fundstelle', 'geometry')
        findSpotLayer = QgsVectorLayer(uri.uri(), u'Fundstelle', 'spatialite')
        findSpotLayer.setSubsetString(
            u'"fundortnummer" IN ({0})'.format(sites))

        if findSpotLayer.featureCount() > 0:
            fSIter = findSpotLayer.getFeatures()
            for fSFeature in fSIter:
                fSGeom = fSFeature.geometry()
                sN = fSFeature.attribute("fundortnummer")
                fSN = fSFeature.attribute("fundstellenummer")

                fSNumber = u"{0}.{1}".format(sN, fSN)
                #QMessageBox.information(None, 'Error', u"{0}, {1}, {2}".format(self.polygonDict[sN][0], self.polygonDict[sN][1], self.polygonDict[sN][2]))
                #dj0 = self.polygonDict[sN][0].disjoint(fSGeom)
                #tc0 = self.polygonDict[sN][0].touches(fSGeom)
                #eq0 = self.polygonDict[sN][0].equals(fSGeom)
                #co0 = self.polygonDict[sN][0].contains(fSGeom)
                #co2 = self.polygonDict[sN][2].contains(fSGeom)
                #eq1 = fSGeom.equals(self.polygonDict[sN][1])
                #wi0 = self.polygonDict[sN][0].within(fSGeom)
                #ol0 = self.polygonDict[sN][0].overlaps(fSGeom)
                if self.polygonDict[sN][0].disjoint(fSGeom):
                    relationship = "disjoint"
                    action = [self.ACTION_1]
                elif self.polygonDict[sN][0].touches(fSGeom):
                    relationship = "touches"
                    action = [self.ACTION_1]
                elif self.polygonDict[sN][0].equals(fSGeom):
                    relationship = "equal"
                    action = [self.ACTION_0]
                elif self.polygonDict[sN][0].contains(
                        fSGeom) or self.polygonDict[sN][2].contains(fSGeom):
                    relationship = "contains"
                    if fSGeom.equals(self.polygonDict[sN][1]):
                        action = [self.ACTION_1, self.ACTION_0]
                    else:
                        action = [self.ACTION_0, self.ACTION_1]
                elif self.polygonDict[sN][0].within(fSGeom):
                    relationship = "within"
                    action = [self.ACTION_1]
                elif self.polygonDict[sN][0].overlaps(fSGeom):
                    relationship = "overlaps"
                    if fSGeom.equals(self.polygonDict[sN][1]):
                        action = [self.ACTION_1, self.ACTION_2]
                    else:
                        action = [self.ACTION_2, self.ACTION_1]
                else:
                    relationship = "error"
                    action = []

                rowPos = self.uiFindspotAssessmentTable.rowCount()
                self.uiFindspotAssessmentTable.insertRow(rowPos)

                self.uiFindspotAssessmentTable.setItem(
                    rowPos, 0, QTableWidgetItem(fSNumber))
                self.uiFindspotAssessmentTable.setItem(
                    rowPos, 1, QTableWidgetItem(relationship))

                if len(action) > 1:
                    comboBox = QComboBox()
                    comboBox.addItems(action)
                    self.uiFindspotAssessmentTable.setCellWidget(
                        rowPos, 2, comboBox)
                else:
                    self.uiFindspotAssessmentTable.setItem(
                        rowPos, 2, QTableWidgetItem(", ".join(action)))
Example #37
0
    def test_values(self):  # pylint: disable=too-many-statements
        """
        Test value collection
        """

        layer_path = os.path.join(os.path.dirname(__file__), 'test_layer.shp')

        vl1 = QgsVectorLayer(layer_path, 'test_layer', 'ogr')
        vl1.setSubsetString('id < 10')
        self.assertTrue(vl1.isValid())
        QgsProject.instance().addMapLayer(vl1)

        # default plot settings
        settings = PlotSettings('scatter')

        # no source layer, fixed values must be used
        settings.source_layer_id = ''
        settings.x = [1, 2, 3]
        settings.y = [4, 5, 6]
        settings.z = [7, 8, 9]

        factory = PlotFactory(settings)
        self.assertEqual(factory.settings.x, [1, 2, 3])
        self.assertEqual(factory.settings.y, [4, 5, 6])
        self.assertEqual(factory.settings.z, [7, 8, 9])
        self.assertEqual(factory.settings.additional_hover_text, [])

        # use source layer
        settings.source_layer_id = vl1.id()

        # no source set => no values
        factory = PlotFactory(settings)
        self.assertEqual(factory.settings.x, [])
        self.assertEqual(factory.settings.y, [])
        self.assertEqual(factory.settings.z, [])
        self.assertEqual(factory.settings.additional_hover_text, [])

        settings.properties['x_name'] = 'so4'
        settings.properties['y_name'] = 'ca'
        factory = PlotFactory(settings)
        self.assertEqual(factory.settings.x,
                         [98, 88, 267, 329, 319, 137, 350, 151, 203])
        self.assertEqual(factory.settings.y, [
            81.87, 22.26, 74.16, 35.05, 46.64, 126.73, 116.44, 108.25, 110.45
        ])
        self.assertEqual(factory.settings.z, [])
        self.assertEqual(factory.settings.additional_hover_text, [])

        # with z
        settings.properties['z_name'] = 'mg'
        factory = PlotFactory(settings)
        self.assertEqual(factory.settings.x,
                         [98, 88, 267, 329, 319, 137, 350, 151, 203])
        self.assertEqual(factory.settings.y, [
            81.87, 22.26, 74.16, 35.05, 46.64, 126.73, 116.44, 108.25, 110.45
        ])
        self.assertEqual(
            factory.settings.z,
            [72.31, 86.03, 85.26, 81.11, 131.59, 95.36, 112.88, 80.55, 78.34])
        self.assertEqual(factory.settings.additional_hover_text, [])

        # with expressions
        settings.properties['x_name'] = '"so4"/10'
        settings.properties[
            'y_name'] = 'case when "profm" >-16 then "ca" else "mg" end'
        settings.properties['z_name'] = 'case when $x < 10.5 then 1 else 0 end'
        factory = PlotFactory(settings)
        self.assertEqual(factory.settings.x,
                         [9.8, 8.8, 26.7, 32.9, 31.9, 13.7, 35.0, 15.1, 20.3])
        self.assertEqual(
            factory.settings.y,
            [81.87, 86.03, 85.26, 35.05, 131.59, 95.36, 112.88, 108.25, 78.34])
        self.assertEqual(factory.settings.z, [0, 1, 0, 0, 0, 0, 0, 1, 1])
        self.assertEqual(factory.settings.additional_hover_text, [])

        # with some nulls
        settings.properties['x_name'] = '"so4"/10'
        settings.properties[
            'y_name'] = 'case when "profm" >-16 then "ca" else "mg" end'
        settings.properties[
            'z_name'] = 'case when $x < 10.5 then NULL else 1 end'
        factory = PlotFactory(settings)
        self.assertEqual(factory.settings.x,
                         [9.8, 26.7, 32.9, 31.9, 13.7, 35.0])
        self.assertEqual(factory.settings.y,
                         [81.87, 85.26, 35.05, 131.59, 95.36, 112.88])
        self.assertEqual(factory.settings.z, [1, 1, 1, 1, 1, 1])
        self.assertEqual(factory.settings.additional_hover_text, [])

        # with additional values
        settings.layout['additional_info_expression'] = 'id'
        factory = PlotFactory(settings)
        self.assertEqual(factory.settings.x,
                         [9.8, 26.7, 32.9, 31.9, 13.7, 35.0])
        self.assertEqual(factory.settings.y,
                         [81.87, 85.26, 35.05, 131.59, 95.36, 112.88])
        self.assertEqual(factory.settings.z, [1, 1, 1, 1, 1, 1])
        self.assertEqual(factory.settings.additional_hover_text,
                         [9, 7, 6, 5, 4, 3])
Example #38
0
    def toSqlLayer(self, sql, geomCol, uniqueCol, layerName="QueryLayer", layerType=None, avoidSelectById=False, filter=""):
        from qgis.core import QgsVectorLayer

        vl = QgsVectorLayer(self.uri().database(), layerName, 'ogr')
        vl.setSubsetString(sql)
        return vl
Example #39
0
def add_design_to_map(qris_project, item, node):
    """adds designs to the map"""
    # Establish paths to layers
    design_id = item.data(item_code['feature_id'])
    subset_string = ("design_id = " + str(design_id))
    design_name = item.text()
    geopackage_path = qris_project.project_designs.geopackage_path(
        qris_project.project_path)
    designs_layer = QgsVectorLayer(geopackage_path + "|layername=designs",
                                   "Designs", "ogr")
    structure_types_layer = QgsVectorLayer(
        geopackage_path + "|layername=structure_types", "Structure Types",
        "ogr")
    phases_layer = QgsVectorLayer(geopackage_path + "|layername=phases",
                                  "Implementation Phases", "ogr")
    zoi_layer = QgsVectorLayer(geopackage_path + "|layername=zoi", "ZOI",
                               "ogr")
    zoi_types_layer = QgsVectorLayer(geopackage_path + "|layername=zoi_types",
                                     "ZOI", "ogr")
    complexes_layer = QgsVectorLayer(geopackage_path + "|layername=complexes",
                                     "Complexes", "ogr")
    structure_points_layer = QgsVectorLayer(
        geopackage_path + "|layername=structure_points", "Structures", "ogr")
    structure_lines_layer = QgsVectorLayer(
        geopackage_path + "|layername=structure_lines", "Structures", "ogr")

    # Get the structure geometry type
    # Could also do this with SQL
    design_iterator = designs_layer.getFeatures(
        QgsFeatureRequest().setFilterFid(design_id))
    design_feature = next(design_iterator)
    structure_geometry = design_feature['structure_geometry']

    def add_design_table(display_name, table_name, qml_name, read_only,
                         group_node):
        """A handy way to add design layers and tables to the map"""
        if not any([c.name() == display_name for c in group_node.children()]):
            layer = QgsProject.instance().addMapLayer(
                QgsVectorLayer(geopackage_path + "|layername=" + table_name,
                               display_name, "ogr"), False)
            if qml_name:
                layer_qml = os.path.join(symbology_path, 'symbology', qml_name)
                layer.loadNamedStyle(layer_qml)
            if read_only:
                layer.setReadOnly()
            group_node.addLayer(layer)

    # Summary tables (views)
    if any([c.name() == "Low-Tech Tables" for c in node.children()]):
        # if is there set it to the design node
        table_node = next(n for n in node.children()
                          if n.name() == "Low-Tech Tables")
    else:
        # if not add the node as a group
        table_node = node.addGroup("Low-Tech Tables")
        table_node.setExpanded(False)

    # Summary tables (views)
    if any([c.name() == "Summary Tables" for c in table_node.children()]):
        # if is there set it to the design node
        summary_node = next(n for n in table_node.children()
                            if n.name() == "Summary Tables")
    else:
        # if not add the node as a group
        summary_node = table_node.addGroup("Summary Tables")
        summary_node.setExpanded(False)

    add_design_table('Structure Totals - Points',
                     'qry_total_structures_points', None, True, summary_node)
    add_design_table('Structure Totals - Lines', 'qry_total_structures_lines',
                     None, True, summary_node)
    add_design_table('Structure Summary - Points',
                     'qry_structure_summary_points', None, True, summary_node)
    add_design_table('Structure Summary - Lines',
                     'qry_structure_summary_lines', None, True, summary_node)
    add_design_table('Complexes Summary - Points',
                     'qry_complexes_by_type_points', None, True, summary_node)
    add_design_table('Complexes Summary - Lines',
                     'qry_complexes_by_type_lines', None, True, summary_node)
    add_design_table('ZOI Summary', 'qry_zoi_summary', None, True,
                     summary_node)

    # Lookup Tables
    if any([c.name() == "Lookup Tables" for c in table_node.children()]):
        # if is there set it to the design node
        lookup_node = next(n for n in table_node.children()
                           if n.name() == "Lookup Tables")
    else:
        # if not add the node as a group
        lookup_node = table_node.addGroup("Lookup Tables")
        lookup_node.setExpanded(False)

    add_design_table('Design Status', 'lkp_design_status',
                     'lkp_design_status.qml', True, lookup_node)
    add_design_table('Phase Action', 'lkp_phase_action',
                     'lkp_phase_action.qml', True, lookup_node)
    add_design_table('ZOI Influence', 'lkp_zoi_influence',
                     'lkp_zoi_influence.qml', True, lookup_node)
    add_design_table('ZOI Stage', 'lkp_zoi_stage', 'lkp_zoi_stage.qml', True,
                     lookup_node)
    add_design_table('Structure Mimics', 'lkp_structure_mimics',
                     'lkp_structure_mimics.qml', True, lookup_node)

    # Add Design Tables
    if any([c.name() == "Design Tables" for c in table_node.children()]):
        # if is there set it to the design node
        design_tables_node = next(n for n in table_node.children()
                                  if n.name() == "Design Tables")
    else:
        # if not add the node as a group
        design_tables_node = table_node.addGroup("Design Tables")
        design_tables_node.setExpanded(False)

    # Check if the designs table has been added and if not add it.
    add_design_table('Designs', 'designs', 'designs.qml', False,
                     design_tables_node)
    add_design_table('Structure Types', 'structure_types',
                     'structure_types.qml', False, design_tables_node)
    add_design_table('ZOI Types', 'zoi_types', 'zoi_types.qml', False,
                     design_tables_node)
    add_design_table('Phases', 'phases', 'phases.qml', False,
                     design_tables_node)

    # Check if the design node is already added
    design_group_name = str(design_id) + "-" + item.text()
    if any([c.name() == design_group_name for c in node.children()]):
        # if is there set it to the design node
        design_node = next(n for n in node.children()
                           if n.name() == design_group_name)
    else:
        # if not add the node as a group
        design_node = node.addGroup(design_group_name)

    # Add structures
    structure_layer_name = str(design_id) + "-Structures"
    if structure_geometry == 'Point':
        # Start setting custom symbology
        # TODO Refactor into a functio
        unique_values = []
        for feature in structure_types_layer.getFeatures():
            values = (feature["fid"], feature["name"])
            unique_values.append(values)
        categories = []
        for value in unique_values:
            layer_style = {}
            layer_style["color"] = '%d, %d, %d' % (randrange(
                0, 256), randrange(0, 256), randrange(0, 256))
            layer_style['size'] = '3'
            layer_style['outline_color'] = 'black'
            symbol_layer = QgsMarkerSymbol.createSimple(layer_style)
            category = QgsRendererCategory(str(value[0]), symbol_layer,
                                           value[1])
            categories.append(category)
        renderer = QgsCategorizedSymbolRenderer('structure_type_id',
                                                categories)

        if not any(
            [c.name() == structure_layer_name
             for c in design_node.children()]):
            # Adding the type suffix as I could see adding qml that symbolizes on other attributes
            structure_points_qml = os.path.join(symbology_path, 'symbology',
                                                'structure_points.qml')
            structure_points_layer.loadNamedStyle(structure_points_qml)
            QgsExpressionContextUtils.setLayerVariable(structure_points_layer,
                                                       'parent_id', design_id)
            structure_points_layer.setSubsetString(subset_string)
            QgsProject.instance().addMapLayer(structure_points_layer, False)
            structure_points_layer.setName(structure_layer_name)
            design_node.addLayer(structure_points_layer)
            layer_node = design_node.findLayer(structure_points_layer.id())
            layer_node.setExpanded(False)
        else:
            structure_points_layer = QgsProject.instance().mapLayersByName(
                structure_layer_name)[0]
        if renderer is not None:
            structure_points_layer.setRenderer(renderer)
            structure_points_layer.triggerRepaint()

    else:
        # Add line structures
        # Start setting custom symbology
        # TODO Refactor into a function
        unique_values = []
        for feature in structure_types_layer.getFeatures():
            values = (feature["fid"], feature["name"])
            unique_values.append(values)

        categories = []
        for value in unique_values:
            layer_style = {}
            layer_style["color"] = '%d, %d, %d' % (randrange(
                0, 256), randrange(0, 256), randrange(0, 256))
            layer_style['width'] = '1'
            layer_style['capstyle'] = 'round'
            symbol_layer = QgsLineSymbol.createSimple(layer_style)
            category = QgsRendererCategory(str(value[0]), symbol_layer,
                                           value[1])
            categories.append(category)
        renderer = QgsCategorizedSymbolRenderer('structure_type_id',
                                                categories)
        # end custom symbology

        if not any(
            [c.name() == structure_layer_name
             for c in design_node.children()]):
            structures_lines_qml = os.path.join(symbology_path, 'symbology',
                                                'structure_lines.qml')
            structure_lines_layer.loadNamedStyle(structures_lines_qml)
            QgsExpressionContextUtils.setLayerVariable(structure_lines_layer,
                                                       'parent_id', design_id)
            structure_lines_layer.setSubsetString(subset_string)
            QgsProject.instance().addMapLayer(structure_lines_layer, False)
            structure_lines_layer.setName(structure_layer_name)
            design_node.addLayer(structure_lines_layer)
            layer_node = design_node.findLayer(structure_lines_layer.id())
            layer_node.setExpanded(False)
        else:
            structure_lines_layer = QgsProject.instance().mapLayersByName(
                structure_layer_name)[0]
        if renderer is not None:
            structure_lines_layer.setRenderer(renderer)
            structure_lines_layer.triggerRepaint()

    # Add zoi
    zoi_layer_name = str(design_id) + "-ZOI"
    # TODO Refactor into a function
    # TODO Refactor into sql query
    unique_values = []
    for feature in zoi_types_layer.getFeatures():
        values = (feature["fid"], feature["name"])
        unique_values.append(values)
    categories = []
    for value in unique_values:
        layer_style = {}
        alpha = 60
        layer_style["color"] = "{}, {}, {}, {}".format(randrange(0, 256),
                                                       randrange(0, 256),
                                                       randrange(0, 256),
                                                       alpha)
        layer_style["outline_width"] = '0.50'
        layer_style["outline_style"] = 'dash'
        symbol_layer = QgsFillSymbol.createSimple(layer_style)
        category = QgsRendererCategory(str(value[0]), symbol_layer, value[1])
        categories.append(category)
    renderer = QgsCategorizedSymbolRenderer('influence_type_id', categories)
    # End custom symbology

    # check for the zoi layer, and if it is not there symbolize and add it
    if not any([c.name() == zoi_layer_name for c in design_node.children()]):
        zoi_qml = os.path.join(symbology_path, 'symbology', 'zoi.qml')
        zoi_layer.loadNamedStyle(zoi_qml)
        QgsExpressionContextUtils.setLayerVariable(zoi_layer, 'parent_id',
                                                   design_id)
        zoi_layer.setSubsetString(subset_string)
        QgsProject.instance().addMapLayer(zoi_layer, False)
        zoi_layer.setName(zoi_layer_name)
        design_node.addLayer(zoi_layer)
        layer_node = design_node.findLayer(zoi_layer.id())
        layer_node.setExpanded(False)
    else:
        zoi_layer = QgsProject.instance().mapLayersByName(zoi_layer_name)[0]
    if renderer is not None:
        zoi_layer.setRenderer(renderer)
    zoi_layer.triggerRepaint()

    # Add complexes
    complex_layer_name = str(design_id) + "-Complexes"
    if not any(
        [c.name() == complex_layer_name for c in design_node.children()]):
        complex_qml = os.path.join(symbology_path, 'symbology',
                                   'complexes.qml')
        complexes_layer.loadNamedStyle(complex_qml)
        QgsExpressionContextUtils.setLayerVariable(complexes_layer,
                                                   'parent_id', design_id)
        complexes_layer.setSubsetString(subset_string)
        QgsProject.instance().addMapLayer(complexes_layer, False)
        complexes_layer.setName(complex_layer_name)
        design_node.addLayer(complexes_layer)
Example #40
0
class Layer:
    '''
    wrapper of a vector layer in the QGIS layer tree with some
    convenient functions. Can be grouped and addressed by its name.
    '''
    def __init__(self,
                 layername: str,
                 data_path: str,
                 groupname: str = '',
                 prepend: bool = True):
        '''
        Parameters
        ----------
        layername : str
            name of the layer in the data source
        data_path : str
            path to the data source of the layer
        groupname : str, optional
            name of the parent group, will be created if not existing, can be
            nested by joining groups with '/' e.g. 'Projekt/Hintergrundkarten',
            defaults to add layer to the root of the layer tree
        prepend : bool
            prepend the group of the layer if True (prepends each group if
            nested), append if False, defaults to prepending the group
        '''
        self.layername = layername
        self.data_path = data_path
        self.layer = None
        self._l = None
        self.groupname = groupname
        self.prepend = prepend

    @property
    def parent(self) -> QgsLayerTreeGroup:
        '''
        the parent group of the layer
        '''
        parent = QgsProject.instance().layerTreeRoot()
        if self.groupname:
            parent = Layer.add_group(self.groupname, prepend=self.prepend)
        return parent

    @property
    def _tree_layer(self) -> QgsLayerTreeLayer:
        '''
        tree representation of the layer
        '''
        if not self.layer:
            return None
        return self.parent.findLayer(self.layer)

    @property
    def layer(self) -> QgsVectorLayer:
        '''
        the wrapped vector layer
        '''
        try:
            layer = self._layer
            if layer is not None:
                # call function on layer to check if it still exists
                layer.id()
        except RuntimeError:
            return None
        return layer

    @layer.setter
    def layer(self, layer: QgsVectorLayer):
        self._layer = layer

    @classmethod
    def add_group(cls,
                  groupname: str,
                  prepend: bool = True) -> QgsLayerTreeGroup:
        '''
        add a group to the layer tree

        Parameters
        ----------
        groupname : str
            name of the parent group, will be created if not existing, can be
            nested by joining groups with '/' e.g. 'Projekt/Hintergrundkarten'
        prepend : bool, optional
            prepend the group if True (prepends each group if nested),
            append if False, defaults to prepending the group

        Returns
        ----------
        QgsLayerTreeGroup
            the created group (the deepest one in hierarchy if nested)
        '''
        groupnames = groupname.split('/')
        parent = QgsProject.instance().layerTreeRoot()
        group = cls._nest_groups(parent, groupnames, prepend=prepend)
        return group

    @classmethod
    def _nest_groups(cls,
                     parent: QgsLayerTreeGroup,
                     groupnames: List[str],
                     prepend: bool = True) -> QgsLayerTreeGroup:
        '''recursively nests groups in order of groupnames'''
        if len(groupnames) == 0:
            return parent
        next_parent = parent.findGroup(groupnames[0])
        if not next_parent:
            next_parent = (parent.insertGroup(0, groupnames[0])
                           if prepend else parent.addGroup(groupnames[0]))
        return cls._nest_groups(next_parent, groupnames[1:], prepend=prepend)

    @classmethod
    def find(cls, label: str, groupname: str = '') -> List[QgsLayerTreeLayer]:
        '''
        deep find tree layer by name in a group recursively

        Parameters
        ----------
        label : str
            label of the tree layer
        groupname : str, optional
            name of the group to search in, can be nested by joining groups with
            '/' e.g. 'Projekt/Hintergrundkarten', defaults to searching in layer
            tree root

        Returns
        ----------
        list
            list of tree layers matching the name, empty list if none found
        '''
        parent = QgsProject.instance().layerTreeRoot()
        if groupname:
            groupnames = groupname.split('/')
            while groupnames:
                g = groupnames.pop(0)
                parent = parent.findGroup(g)
                if not parent:
                    return []

        def deep_find(node, label):
            found = []
            if node:
                for child in node.children():
                    if child.name() == label:
                        found.append(child)
                    found.extend(deep_find(child, label))
            return found

        found = deep_find(parent, label)
        return found

    def draw(self,
             style_path: str = None,
             label: str = '',
             redraw: str = True,
             checked: bool = True,
             filter: str = None,
             expanded: bool = True,
             prepend: bool = False) -> QgsVectorLayer:
        '''
        load the data into a vector layer, draw it and add it to the layer tree

        Parameters
        ----------
        label : str, optional
            label of the layer, defaults to layer name this is initialized with
        style_path : str, optional
            a QGIS style (.qml) can be applied to the layer, defaults to no
            style
        redraw : bool, optional
            replace old layer with same name in same group if True,
            only create if not existing if set to False, else it is refreshed,
            defaults to redrawing the layer
        checked: bool, optional
            set check state of layer in layer tree, defaults to being checked
        filter: str, optional
            QGIS filter expression to filter the layer, defaults to no filtering
        expanded: str, optional
            sets the legend to expanded or not, defaults to an expanded legend
        prepend: bool, optional
            prepend the layer to the other layers in its group if True,
            append it if False, defaults to appending the layer

        Returns
        ----------
        QgsVectorLayer
            the created, replaced or refreshed vector layer

        '''
        if not self.layer:
            layers = Layer.find(label, groupname=self.groupname)
            if layers:
                self.layer = layers[0].layer()
        if redraw:
            self.remove()
        else:
            iface.mapCanvas().refreshAllLayers()

        if not self.layer:
            self.layer = QgsVectorLayer(self.data_path, self.layername, "ogr")
            if label:
                self.layer.setName(label)
            QgsProject.instance().addMapLayer(self.layer, False)
            self.layer.loadNamedStyle(style_path)
        tree_layer = self._tree_layer
        if not tree_layer:
            tree_layer = self.parent.insertLayer(0, self.layer) if prepend else\
                self.parent.addLayer(self.layer)
        tree_layer.setItemVisibilityChecked(checked)
        tree_layer.setExpanded(expanded)
        if filter is not None:
            self.layer.setSubsetString(filter)
        return self.layer

    def set_visibility(self, state: bool):
        '''
        change check state of layer, layer is not visible if unchecked

        Parameters
        ----------
        state: bool
            set check state of layer in layer tree
        '''

        tree_layer = self._tree_layer
        if tree_layer:
            tree_layer.setItemVisibilityChecked(state)

    def zoom_to(self):
        '''
        zooms map canvas to the extent of this layer
        '''
        if not self.layer:
            return
        canvas = iface.mapCanvas()
        self.layer.updateExtents()
        transform = QgsCoordinateTransform(
            self.layer.crs(),
            canvas.mapSettings().destinationCrs(), QgsProject.instance())
        canvas.setExtent(transform.transform(self.layer.extent()))

    def remove(self):
        '''
        remove the layer from map and layer tree
        '''
        if not self.layer:
            return
        QgsProject.instance().removeMapLayer(self.layer.id())
        self.layer = None
Example #41
0
    def testDateTimeFiltering(self):

        endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testDateTimeFiltering'
        create_landing_page_api_collection(endpoint)

        items = {
            "type":
            "FeatureCollection",
            "features": [{
                "type": "Feature",
                "id": "feat.1",
                "properties": {
                    "my_dt_field": "2019-10-15T00:34:00Z",
                    "foo": "bar"
                },
                "geometry": {
                    "type": "Point",
                    "coordinates": [-70.332, 66.33]
                }
            }]
        }

        no_items = {"type": "FeatureCollection", "features": []}

        filename = sanitize(
            endpoint,
            '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS)
        with open(filename, 'wb') as f:
            f.write(json.dumps(items).encode('UTF-8'))

        vl = QgsVectorLayer(
            "url='http://" + endpoint +
            "' typename='mycollection' filter='\"my_dt_field\" >= \\'2019-05-15T00:00:00Z\\''",
            'test', 'OAPIF')
        self.assertTrue(vl.isValid())
        os.unlink(filename)

        filename = sanitize(
            endpoint,
            '/collections/mycollection/items?limit=1000&datetime=2019-05-15T00:00:00Z/9999-12-31T00:00:00Z&'
            + ACCEPT_ITEMS)
        with open(filename, 'wb') as f:
            f.write(json.dumps(items).encode('UTF-8'))
        values = [f['id'] for f in vl.getFeatures()]
        os.unlink(filename)
        self.assertEqual(values, ['feat.1'])

        assert vl.setSubsetString(""""my_dt_field" < '2019-01-01T00:34:00Z'""")

        filename = sanitize(
            endpoint,
            '/collections/mycollection/items?limit=1000&datetime=0000-01-01T00:00:00Z/2019-01-01T00:34:00Z&'
            + ACCEPT_ITEMS)
        with open(filename, 'wb') as f:
            f.write(json.dumps(no_items).encode('UTF-8'))
        values = [f['id'] for f in vl.getFeatures()]
        os.unlink(filename)
        self.assertEqual(values, [])

        assert vl.setSubsetString(""""my_dt_field" = '2019-10-15T00:34:00Z'""")

        filename = sanitize(
            endpoint,
            '/collections/mycollection/items?limit=1000&datetime=2019-10-15T00:34:00Z&'
            + ACCEPT_ITEMS)
        with open(filename, 'wb') as f:
            f.write(json.dumps(items).encode('UTF-8'))
        values = [f['id'] for f in vl.getFeatures()]
        os.unlink(filename)
        self.assertEqual(values, ['feat.1'])

        assert vl.setSubsetString(
            """("my_dt_field" >= '2019-01-01T00:34:00Z') AND ("my_dt_field" <= '2019-12-31T00:00:00Z')"""
        )

        filename = sanitize(
            endpoint,
            '/collections/mycollection/items?limit=1000&datetime=2019-01-01T00:34:00Z/2019-12-31T00:00:00Z&'
            + ACCEPT_ITEMS)
        with open(filename, 'wb') as f:
            f.write(json.dumps(items).encode('UTF-8'))
        values = [f['id'] for f in vl.getFeatures()]
        os.unlink(filename)
        self.assertEqual(values, ['feat.1'])

        # Partial on client side
        assert vl.setSubsetString(
            """("my_dt_field" >= '2019-01-01T00:34:00Z') AND ("foo" = 'bar')"""
        )

        filename = sanitize(
            endpoint,
            '/collections/mycollection/items?limit=1000&datetime=2019-01-01T00:34:00Z/9999-12-31T00:00:00Z&'
            + ACCEPT_ITEMS)
        with open(filename, 'wb') as f:
            f.write(json.dumps(items).encode('UTF-8'))
        values = [f['id'] for f in vl.getFeatures()]
        os.unlink(filename)
        self.assertEqual(values, ['feat.1'])

        # Same but with non-matching client-side part
        assert vl.setSubsetString(
            """("my_dt_field" >= '2019-01-01T00:34:00Z') AND ("foo" != 'bar')"""
        )

        filename = sanitize(
            endpoint,
            '/collections/mycollection/items?limit=1000&datetime=2019-01-01T00:34:00Z/9999-12-31T00:00:00Z&'
            + ACCEPT_ITEMS)
        with open(filename, 'wb') as f:
            f.write(json.dumps(items).encode('UTF-8'))
        values = [f['id'] for f in vl.getFeatures()]
        os.unlink(filename)
        self.assertEqual(values, [])

        # Switch order
        assert vl.setSubsetString(
            """("foo" = 'bar') AND ("my_dt_field" >= '2019-01-01T00:34:00Z')"""
        )

        filename = sanitize(
            endpoint,
            '/collections/mycollection/items?limit=1000&datetime=2019-01-01T00:34:00Z/9999-12-31T00:00:00Z&'
            + ACCEPT_ITEMS)
        with open(filename, 'wb') as f:
            f.write(json.dumps(items).encode('UTF-8'))
        values = [f['id'] for f in vl.getFeatures()]
        os.unlink(filename)
        self.assertEqual(values, ['feat.1'])