Skip to content

Commit 0f16609

Browse files
committed
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 786929b commit 0f16609

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
@@ -1839,8 +1839,9 @@ bool QgsProject::writeProjectFile( const QString &filename )
18391839
if ( emIt == mEmbeddedLayers.constEnd() )
18401840
{
18411841
QDomElement maplayerElem;
1842-
// If layer is not valid, let's try to restore saved properties from invalidLayerProperties
1843-
if ( ml->isValid() )
1842+
// If layer is not valid, prefer to restore saved properties from invalidLayerProperties. But if that's
1843+
// not available, just write what we DO have
1844+
if ( ml->isValid() || ml->originalXmlProperties().isEmpty() )
18441845
{
18451846
// general layer metadata
18461847
maplayerElem = doc->createElement( QStringLiteral( "maplayer" ) );

src/core/qgsvectorlayer.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1418,6 +1418,11 @@ bool QgsVectorLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &c
14181418
if ( !setDataProvider( mProviderKey, options ) )
14191419
{
14201420
QgsDebugMsg( QStringLiteral( "Could not set data provider for layer %1" ).arg( publicSource() ) );
1421+
const QDomElement elem = layer_node.toElement();
1422+
1423+
// for invalid layer sources, we fallback to stored wkbType if available
1424+
if ( elem.hasAttribute( QStringLiteral( "wkbType" ) ) )
1425+
mWkbType = qgsEnumKeyToValue( elem.attribute( QStringLiteral( "wkbType" ) ), mWkbType );
14211426
}
14221427

14231428
QDomElement pkeyElem = pkeyNode.toElement();
@@ -1705,6 +1710,7 @@ bool QgsVectorLayer::writeXml( QDomNode &layer_node,
17051710

17061711
// set the geometry type
17071712
mapLayerNode.setAttribute( QStringLiteral( "geometry" ), QgsWkbTypes::geometryDisplayString( geometryType() ) );
1713+
mapLayerNode.setAttribute( QStringLiteral( "wkbType" ), qgsEnumValueToKey( wkbType() ) );
17081714

17091715
// add provider node
17101716
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,
@@ -393,6 +395,45 @@ def testSetDataSourceInvalidToValid(self):
393395
# should STILL have kept renderer!
394396
self.assertEqual(layer.renderer(), r)
395397

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

0 commit comments

Comments
 (0)