Skip to content
Permalink
Browse files

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.
  • Loading branch information
nyalldawson committed Apr 18, 2019
1 parent 786929b commit 0f1660990f1c2e0fd7f6e6fb1859565120f1aff2
@@ -1,2 +1,3 @@
# The following has been generated automatically from src/core/geometry/qgswkbtypes.h
QgsWkbTypes.Type.baseClass = QgsWkbTypes
QgsWkbTypes.GeometryType.baseClass = QgsWkbTypes
@@ -128,6 +128,7 @@ class CORE_EXPORT QgsWkbTypes
MultiLineString25D,
MultiPolygon25D
};
Q_ENUM( Type )

/**
* The geometry types are used to group QgsWkbTypes::Type in a
@@ -1839,8 +1839,9 @@ bool QgsProject::writeProjectFile( const QString &filename )
if ( emIt == mEmbeddedLayers.constEnd() )
{
QDomElement maplayerElem;
// If layer is not valid, let's try to restore saved properties from invalidLayerProperties
if ( ml->isValid() )
// If layer is not valid, prefer to restore saved properties from invalidLayerProperties. But if that's
// not available, just write what we DO have
if ( ml->isValid() || ml->originalXmlProperties().isEmpty() )
{
// general layer metadata
maplayerElem = doc->createElement( QStringLiteral( "maplayer" ) );
@@ -1418,6 +1418,11 @@ bool QgsVectorLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &c
if ( !setDataProvider( mProviderKey, options ) )
{
QgsDebugMsg( QStringLiteral( "Could not set data provider for layer %1" ).arg( publicSource() ) );
const QDomElement elem = layer_node.toElement();

// for invalid layer sources, we fallback to stored wkbType if available
if ( elem.hasAttribute( QStringLiteral( "wkbType" ) ) )
mWkbType = qgsEnumKeyToValue( elem.attribute( QStringLiteral( "wkbType" ) ), mWkbType );
}

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

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

// add provider node
if ( mDataProvider )
@@ -15,9 +15,11 @@
import qgis # NOQA

import os
import tempfile
import shutil

from qgis.PyQt.QtCore import QVariant, Qt
from qgis.PyQt.QtGui import QPainter
from qgis.PyQt.QtGui import QPainter, QColor
from qgis.PyQt.QtXml import QDomDocument

from qgis.core import (QgsWkbTypes,
@@ -393,6 +395,45 @@ def testSetDataSourceInvalidToValid(self):
# should STILL have kept renderer!
self.assertEqual(layer.renderer(), r)

def testStoreWkbTypeInvalidLayers(self):
"""
Test that layer wkb types are restored for projects with invalid layer paths
"""
layer = createLayerWithOnePoint()
layer.setName('my test layer')
r = QgsSingleSymbolRenderer(QgsSymbol.defaultSymbol(QgsWkbTypes.PointGeometry))
r.symbol().setColor(QColor('#123456'))
layer.setRenderer(r)
self.assertEqual(layer.renderer().symbol().color().name(), '#123456')

p = QgsProject()
p.addMapLayer(layer)

# reset layer to a bad path
options = QgsDataProvider.ProviderOptions()
layer.setDataSource('nothing', 'new name', 'ogr', options)
# should have kept the same renderer and wkb type!
self.assertEqual(layer.wkbType(), QgsWkbTypes.Point)
self.assertEqual(layer.renderer().symbol().color().name(), '#123456')

# save project to a temporary file
temp_path = tempfile.mkdtemp()
temp_project_path = os.path.join(temp_path, 'temp.qgs')
self.assertTrue(p.write(temp_project_path))

# restore project
p2 = QgsProject()
self.assertTrue(p2.read(temp_project_path))

l2 = p2.mapLayersByName('new name')[0]
self.assertFalse(l2.isValid())

# should have kept the same renderer and wkb type!
self.assertEqual(l2.wkbType(), QgsWkbTypes.Point)
self.assertEqual(l2.renderer().symbol().color().name(), '#123456')

shutil.rmtree(temp_path, True)

def test_layer_crs(self):
"""
Test that spatial layers have CRS, and non-spatial don't

0 comments on commit 0f16609

Please sign in to comment.
You can’t perform that action at this time.