Skip to content
Permalink
Browse files

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 070de69 commit 72febb35e9be54ce66670c1370b7e14fc705b2df
Showing with 287 additions and 4 deletions.
  1. +4 −4 src/core/qgslayerdefinition.cpp
  2. +15 −0 tests/src/python/test_qgslayerdefinition.py
  3. +268 −0 tests/testdata/invalid_source.qlr
@@ -280,10 +280,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;
}
@@ -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()
@@ -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 72febb3

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