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.
This commit is contained in:
Nyall Dawson 2019-04-30 15:10:04 +10:00
parent 070de69e30
commit 72febb35e9
3 changed files with 287 additions and 4 deletions

View File

@ -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;
}

View File

@ -110,6 +110,21 @@ class TestQgsLayerDefinition(unittest.TestCase):
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
tests/testdata/invalid_source.qlr vendored Normal file
View File

@ -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>