Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 6bd5d07

Browse files
committedApr 18, 2019
Store vector layer wkb type in xml
We can use this when restoring the layer, if the uri turns out to be invalid at that stage (e.g. a file has moved). By storing and falling back to the last known wkb type, we avoid unnecessarily discarding the existing layer renderer, and can still show the expected layer type in the layer tree.
1 parent 5456f1d commit 6bd5d07

File tree

5 files changed

+53
-3
lines changed

5 files changed

+53
-3
lines changed
 
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
# The following has been generated automatically from src/core/geometry/qgswkbtypes.h
2+
QgsWkbTypes.Type.baseClass = QgsWkbTypes
23
QgsWkbTypes.GeometryType.baseClass = QgsWkbTypes

‎src/core/geometry/qgswkbtypes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ class CORE_EXPORT QgsWkbTypes
128128
MultiLineString25D,
129129
MultiPolygon25D
130130
};
131+
Q_ENUM( Type )
131132

132133
/**
133134
* The geometry types are used to group QgsWkbTypes::Type in a

‎src/core/qgsproject.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1803,8 +1803,9 @@ bool QgsProject::writeProjectFile( const QString &filename )
18031803
if ( emIt == mEmbeddedLayers.constEnd() )
18041804
{
18051805
QDomElement maplayerElem;
1806-
// If layer is not valid, let's try to restore saved properties from invalidLayerProperties
1807-
if ( ml->isValid() )
1806+
// If layer is not valid, prefer to restore saved properties from invalidLayerProperties. But if that's
1807+
// not available, just write what we DO have
1808+
if ( ml->isValid() || ml->originalXmlProperties().isEmpty() )
18081809
{
18091810
// general layer metadata
18101811
maplayerElem = doc->createElement( QStringLiteral( "maplayer" ) );

‎src/core/qgsvectorlayer.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1405,6 +1405,11 @@ bool QgsVectorLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &c
14051405
if ( !setDataProvider( mProviderKey, options ) )
14061406
{
14071407
QgsDebugMsg( QStringLiteral( "Could not set data provider for layer %1" ).arg( publicSource() ) );
1408+
const QDomElement elem = layer_node.toElement();
1409+
1410+
// for invalid layer sources, we fallback to stored wkbType if available
1411+
if ( elem.hasAttribute( QStringLiteral( "wkbType" ) ) )
1412+
mWkbType = qgsEnumKeyToValue( elem.attribute( QStringLiteral( "wkbType" ) ), mWkbType );
14081413
}
14091414

14101415
QDomElement pkeyElem = pkeyNode.toElement();
@@ -1691,6 +1696,7 @@ bool QgsVectorLayer::writeXml( QDomNode &layer_node,
16911696

16921697
// set the geometry type
16931698
mapLayerNode.setAttribute( QStringLiteral( "geometry" ), QgsWkbTypes::geometryDisplayString( geometryType() ) );
1699+
mapLayerNode.setAttribute( QStringLiteral( "wkbType" ), qgsEnumValueToKey( wkbType() ) );
16941700

16951701
// add provider node
16961702
if ( mDataProvider )

‎tests/src/python/test_qgsvectorlayer.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
import qgis # NOQA
1616

1717
import os
18+
import tempfile
19+
import shutil
1820

1921
from qgis.PyQt.QtCore import QVariant, Qt
20-
from qgis.PyQt.QtGui import QPainter
22+
from qgis.PyQt.QtGui import QPainter, QColor
2123
from qgis.PyQt.QtXml import QDomDocument
2224

2325
from qgis.core import (QgsWkbTypes,
@@ -392,6 +394,45 @@ def testSetDataSourceInvalidToValid(self):
392394
# should STILL have kept renderer!
393395
self.assertEqual(layer.renderer(), r)
394396

397+
def testStoreWkbTypeInvalidLayers(self):
398+
"""
399+
Test that layer wkb types are restored for projects with invalid layer paths
400+
"""
401+
layer = createLayerWithOnePoint()
402+
layer.setName('my test layer')
403+
r = QgsSingleSymbolRenderer(QgsSymbol.defaultSymbol(QgsWkbTypes.PointGeometry))
404+
r.symbol().setColor(QColor('#123456'))
405+
layer.setRenderer(r)
406+
self.assertEqual(layer.renderer().symbol().color().name(), '#123456')
407+
408+
p = QgsProject()
409+
p.addMapLayer(layer)
410+
411+
# reset layer to a bad path
412+
options = QgsDataProvider.ProviderOptions()
413+
layer.setDataSource('nothing', 'new name', 'ogr', options)
414+
# should have kept the same renderer and wkb type!
415+
self.assertEqual(layer.wkbType(), QgsWkbTypes.Point)
416+
self.assertEqual(layer.renderer().symbol().color().name(), '#123456')
417+
418+
# save project to a temporary file
419+
temp_path = tempfile.mkdtemp()
420+
temp_project_path = os.path.join(temp_path, 'temp.qgs')
421+
self.assertTrue(p.write(temp_project_path))
422+
423+
# restore project
424+
p2 = QgsProject()
425+
self.assertTrue(p2.read(temp_project_path))
426+
427+
l2 = p2.mapLayersByName('new name')[0]
428+
self.assertFalse(l2.isValid())
429+
430+
# should have kept the same renderer and wkb type!
431+
self.assertEqual(l2.wkbType(), QgsWkbTypes.Point)
432+
self.assertEqual(l2.renderer().symbol().color().name(), '#123456')
433+
434+
shutil.rmtree(temp_path, True)
435+
395436
def test_layer_crs(self):
396437
"""
397438
Test that spatial layers have CRS, and non-spatial don't

0 commit comments

Comments
 (0)
Please sign in to comment.