Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Allow loading QLR files with invalid sources
E.g. if the layer path has moved, we still should allow these
files to be read, so that the layer path can be fixed by the user
manually.
  • Loading branch information
nyalldawson committed Apr 30, 2019
1 parent e4dc3ba commit 4a72ed4
Show file tree
Hide file tree
Showing 3 changed files with 287 additions and 4 deletions.
8 changes: 4 additions & 4 deletions src/core/qgslayerdefinition.cpp
Expand Up @@ -274,10 +274,10 @@ QList<QgsMapLayer *> QgsLayerDefinition::loadLayerDefinitionLayers( QDomDocument
if ( !layer )
continue;

if ( layer->readLayerXml( layerElem, context ) )
{
layers << layer;
}
// always add the layer, even if the source is invalid -- this allows users to fix the source
// at a later stage and still retain all the layer properties intact
layer->readLayerXml( layerElem, context );
layers << layer;
}
return layers;
}
Expand Down
15 changes: 15 additions & 0 deletions tests/src/python/test_qgslayerdefinition.py
Expand Up @@ -110,6 +110,21 @@ def testVectorAndRaster(self):
self.assertEqual(len(layers), 2)
QgsProject.instance().removeAllMapLayers()

def testInvalidSource(self):
# Load a QLR containing a vector layer with a broken path
QgsProject.instance().removeAllMapLayers()
layers = QgsProject.instance().mapLayers()
self.assertEqual(len(layers), 0)

(result, errMsg) = QgsLayerDefinition.loadLayerDefinition(TEST_DATA_DIR + '/invalid_source.qlr', QgsProject.instance(), QgsProject.instance().layerTreeRoot())
self.assertTrue(result)
self.assertFalse(errMsg)

layers = QgsProject.instance().mapLayers()
self.assertEqual(len(layers), 1)
self.assertFalse(list(layers.values())[0].isValid())
QgsProject.instance().removeAllMapLayers()


if __name__ == '__main__':
unittest.main()
268 changes: 268 additions & 0 deletions tests/testdata/invalid_source.qlr
@@ -0,0 +1,268 @@
<!DOCTYPE qgis-layer-definition>
<qlr>
<layer-tree-group expanded="1" name="" checked="Qt::Checked">
<customproperties/>
<layer-tree-layer source="C:\temp/points.shp" expanded="1" id="points_1cff66ba_ca06_4c6d_8542_610e215f65ca" name="points" providerKey="ogr" checked="Qt::Checked">
<customproperties/>
</layer-tree-layer>
</layer-tree-group>
<maplayers>
<maplayer geometry="Point" labelsEnabled="0" autoRefreshEnabled="0" styleCategories="AllStyleCategories" refreshOnNotifyEnabled="0" maxScale="0" refreshOnNotifyMessage="" simplifyLocal="1" wkbType="Point" simplifyDrawingTol="1" autoRefreshTime="0" simplifyMaxScale="1" readOnly="0" minScale="0" simplifyDrawingHints="1" simplifyAlgorithm="0" type="vector" hasScaleBasedVisibilityFlag="0">
<id>points_1cff66ba_ca06_4c6d_8542_610e215f65ca</id>
<datasource>C:\temp/points.shp</datasource>
<keywordList>
<value></value>
</keywordList>
<layername>points</layername>
<srs>
<spatialrefsys>
<proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
<srsid>3452</srsid>
<srid>4326</srid>
<authid>EPSG:4326</authid>
<description>WGS 84</description>
<projectionacronym>longlat</projectionacronym>
<ellipsoidacronym>WGS84</ellipsoidacronym>
<geographicflag>true</geographicflag>
</spatialrefsys>
</srs>
<resourceMetadata>
<identifier></identifier>
<parentidentifier></parentidentifier>
<language></language>
<type></type>
<title></title>
<abstract></abstract>
<links/>
<fees></fees>
<encoding></encoding>
<crs>
<spatialrefsys>
<proj4></proj4>
<srsid>0</srsid>
<srid>0</srid>
<authid></authid>
<description></description>
<projectionacronym></projectionacronym>
<ellipsoidacronym></ellipsoidacronym>
<geographicflag>false</geographicflag>
</spatialrefsys>
</crs>
<extent/>
</resourceMetadata>
<provider encoding="UTF-8">ogr</provider>
<vectorjoins/>
<layerDependencies/>
<dataDependencies/>
<legend type="default-vector"/>
<expressionfields/>
<map-layer-style-manager current="default">
<map-layer-style name="default"/>
</map-layer-style-manager>
<auxiliaryLayer/>
<flags>
<Identifiable>1</Identifiable>
<Removable>1</Removable>
<Searchable>1</Searchable>
</flags>
<renderer-v2 symbollevels="0" graduatedMethod="GraduatedColor" attr="Importance" enableorderby="0" type="graduatedSymbol" forceraster="0">
<ranges>
<range render="true" upper="1.000000000000000" symbol="0" label="1.000" lower="1.000000000000000"/>
<range render="true" upper="3.000000000000000" symbol="1" label="1.001 - 3.000" lower="1.001000000000000"/>
<range render="true" upper="4.000000000000000" symbol="2" label="3.001 - 4.000" lower="3.001000000000000"/>
<range render="true" upper="10.000000000000000" symbol="3" label="4.001 - 10.000" lower="4.001000000000000"/>
<range render="true" upper="20.000000000000000" symbol="4" label="10.001 - 20.000" lower="10.000999999999999"/>
</ranges>
<symbols>
<symbol alpha="1" force_rhr="0" clip_to_extent="1" type="marker" name="0">
<layer enabled="1" pass="0" class="SimpleMarker" locked="0">
<prop k="angle" v="0"/>
<prop k="color" v="255,255,127,255"/>
<prop k="horizontal_anchor_point" v="1"/>
<prop k="joinstyle" v="bevel"/>
<prop k="name" v="circle"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="offset_unit" v="Point"/>
<prop k="outline_color" v="0,0,0,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.5"/>
<prop k="outline_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="outline_width_unit" v="Point"/>
<prop k="scale_method" v="diameter"/>
<prop k="size" v="4"/>
<prop k="size_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="size_unit" v="Point"/>
<prop k="vertical_anchor_point" v="1"/>
<data_defined_properties>
<Option type="Map">
<Option value="" type="QString" name="name"/>
<Option name="properties"/>
<Option value="collection" type="QString" name="type"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
<symbol alpha="1" force_rhr="0" clip_to_extent="1" type="marker" name="1">
<layer enabled="1" pass="0" class="SimpleMarker" locked="0">
<prop k="angle" v="0"/>
<prop k="color" v="250,209,85,255"/>
<prop k="horizontal_anchor_point" v="1"/>
<prop k="joinstyle" v="bevel"/>
<prop k="name" v="circle"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="offset_unit" v="Point"/>
<prop k="outline_color" v="0,0,0,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.5"/>
<prop k="outline_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="outline_width_unit" v="Point"/>
<prop k="scale_method" v="diameter"/>
<prop k="size" v="4"/>
<prop k="size_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="size_unit" v="Point"/>
<prop k="vertical_anchor_point" v="1"/>
<data_defined_properties>
<Option type="Map">
<Option value="" type="QString" name="name"/>
<Option name="properties"/>
<Option value="collection" type="QString" name="type"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
<symbol alpha="1" force_rhr="0" clip_to_extent="1" type="marker" name="2">
<layer enabled="1" pass="0" class="SimpleMarker" locked="0">
<prop k="angle" v="0"/>
<prop k="color" v="242,167,46,255"/>
<prop k="horizontal_anchor_point" v="1"/>
<prop k="joinstyle" v="bevel"/>
<prop k="name" v="circle"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="offset_unit" v="Point"/>
<prop k="outline_color" v="0,0,0,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.5"/>
<prop k="outline_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="outline_width_unit" v="Point"/>
<prop k="scale_method" v="diameter"/>
<prop k="size" v="4"/>
<prop k="size_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="size_unit" v="Point"/>
<prop k="vertical_anchor_point" v="1"/>
<data_defined_properties>
<Option type="Map">
<Option value="" type="QString" name="name"/>
<Option name="properties"/>
<Option value="collection" type="QString" name="type"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
<symbol alpha="1" force_rhr="0" clip_to_extent="1" type="marker" name="3">
<layer enabled="1" pass="0" class="SimpleMarker" locked="0">
<prop k="angle" v="0"/>
<prop k="color" v="173,83,19,255"/>
<prop k="horizontal_anchor_point" v="1"/>
<prop k="joinstyle" v="bevel"/>
<prop k="name" v="circle"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="offset_unit" v="Point"/>
<prop k="outline_color" v="0,0,0,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.5"/>
<prop k="outline_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="outline_width_unit" v="Point"/>
<prop k="scale_method" v="diameter"/>
<prop k="size" v="4"/>
<prop k="size_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="size_unit" v="Point"/>
<prop k="vertical_anchor_point" v="1"/>
<data_defined_properties>
<Option type="Map">
<Option value="" type="QString" name="name"/>
<Option name="properties"/>
<Option value="collection" type="QString" name="type"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
<symbol alpha="1" force_rhr="0" clip_to_extent="1" type="marker" name="4">
<layer enabled="1" pass="0" class="SimpleMarker" locked="0">
<prop k="angle" v="0"/>
<prop k="color" v="107,0,0,255"/>
<prop k="horizontal_anchor_point" v="1"/>
<prop k="joinstyle" v="bevel"/>
<prop k="name" v="circle"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="offset_unit" v="Point"/>
<prop k="outline_color" v="0,0,0,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.5"/>
<prop k="outline_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="outline_width_unit" v="Point"/>
<prop k="scale_method" v="diameter"/>
<prop k="size" v="4"/>
<prop k="size_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="size_unit" v="Point"/>
<prop k="vertical_anchor_point" v="1"/>
<data_defined_properties>
<Option type="Map">
<Option value="" type="QString" name="name"/>
<Option name="properties"/>
<Option value="collection" type="QString" name="type"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
</symbols>
<symmetricMode enabled="false" symmetryPoint="0" astride="false"/>
<rotation/>
<sizescale/>
<labelformat trimtrailingzeroes="false" decimalplaces="4" format="%1 - %2"/>
</renderer-v2>
<customproperties/>
<blendMode>0</blendMode>
<featureBlendMode>0</featureBlendMode>
<layerOpacity>1</layerOpacity>
<geometryOptions removeDuplicateNodes="0" geometryPrecision="0">
<activeChecks type="StringList">
<Option value="" type="QString"/>
</activeChecks>
<checkConfiguration/>
</geometryOptions>
<fieldConfiguration/>
<aliases/>
<excludeAttributesWMS/>
<excludeAttributesWFS/>
<defaults/>
<constraints/>
<constraintExpressions/>
<expressionfields/>
<attributeactions/>
<attributetableconfig sortExpression="" actionWidgetStyle="dropDown" sortOrder="0">
<columns/>
</attributetableconfig>
<conditionalstyles>
<rowstyles/>
<fieldstyles/>
</conditionalstyles>
<editform tolerant="1"></editform>
<editforminit/>
<editforminitcodesource>0</editforminitcodesource>
<editforminitfilepath></editforminitfilepath>
<editforminitcode><![CDATA[]]></editforminitcode>
<featformsuppress>0</featformsuppress>
<editorlayout>generatedlayout</editorlayout>
<editable/>
<labelOnTop/>
<widgets/>
<previewExpression></previewExpression>
<mapTip></mapTip>
</maplayer>
</maplayers>
</qlr>

0 comments on commit 4a72ed4

Please sign in to comment.