mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-28 00:17:30 -05:00
Merge pull request #9901 from nyalldawson/invalid_qlr
Allow loading QLR files with invalid sources
This commit is contained in:
commit
f70acf260b
@ -140,18 +140,24 @@ QMenu *QgsAppLayerTreeViewMenuProvider::createContextMenu()
|
||||
|
||||
if ( layer && layer->isSpatial() )
|
||||
{
|
||||
menu->addAction( actions->actionZoomToLayer( mCanvas, menu ) );
|
||||
QAction *zoomToLayer = actions->actionZoomToLayer( mCanvas, menu );
|
||||
zoomToLayer->setEnabled( layer->isValid() );
|
||||
menu->addAction( zoomToLayer );
|
||||
if ( vlayer )
|
||||
{
|
||||
QAction *actionZoomSelected = actions->actionZoomToSelection( mCanvas, menu );
|
||||
actionZoomSelected->setEnabled( !vlayer->selectedFeatureIds().isEmpty() );
|
||||
actionZoomSelected->setEnabled( vlayer->isValid() && !vlayer->selectedFeatureIds().isEmpty() );
|
||||
menu->addAction( actionZoomSelected );
|
||||
}
|
||||
menu->addAction( actions->actionShowInOverview( menu ) );
|
||||
}
|
||||
|
||||
if ( vlayer )
|
||||
menu->addAction( actions->actionShowFeatureCount( menu ) );
|
||||
{
|
||||
QAction *showFeatureCount = actions->actionShowFeatureCount( menu );
|
||||
menu->addAction( showFeatureCount );
|
||||
showFeatureCount->setEnabled( vlayer->isValid() );
|
||||
}
|
||||
|
||||
QAction *actionCopyLayer = new QAction( tr( "Copy Layer" ), menu );
|
||||
connect( actionCopyLayer, &QAction::triggered, QgisApp::instance(), &QgisApp::copyLayer );
|
||||
@ -161,10 +167,14 @@ QMenu *QgsAppLayerTreeViewMenuProvider::createContextMenu()
|
||||
|
||||
if ( rlayer )
|
||||
{
|
||||
menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionZoomActual.svg" ) ), tr( "&Zoom to Native Resolution (100%)" ), QgisApp::instance(), &QgisApp::legendLayerZoomNative );
|
||||
QAction *zoomToNative = menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionZoomActual.svg" ) ), tr( "&Zoom to Native Resolution (100%)" ), QgisApp::instance(), &QgisApp::legendLayerZoomNative );
|
||||
zoomToNative->setEnabled( rlayer->isValid() );
|
||||
|
||||
if ( rlayer->rasterType() != QgsRasterLayer::Palette )
|
||||
menu->addAction( tr( "&Stretch Using Current Extent" ), QgisApp::instance(), &QgisApp::legendLayerStretchUsingCurrentExtent );
|
||||
{
|
||||
QAction *stretch = menu->addAction( tr( "&Stretch Using Current Extent" ), QgisApp::instance(), &QgisApp::legendLayerStretchUsingCurrentExtent );
|
||||
stretch->setEnabled( rlayer->isValid() );
|
||||
}
|
||||
}
|
||||
|
||||
addCustomLayerActions( menu, layer );
|
||||
@ -208,8 +218,9 @@ QMenu *QgsAppLayerTreeViewMenuProvider::createContextMenu()
|
||||
// attribute table
|
||||
QgsSettings settings;
|
||||
QgsAttributeTableFilterModel::FilterMode initialMode = settings.enumValue( QStringLiteral( "qgis/attributeTableBehavior" ), QgsAttributeTableFilterModel::ShowAll );
|
||||
menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionOpenTable.svg" ) ), tr( "&Open Attribute Table" ),
|
||||
QgisApp::instance(), [ = ] { QgisApp::instance()->attributeTable( initialMode ); } );
|
||||
QAction *attributeTable = menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionOpenTable.svg" ) ), tr( "&Open Attribute Table" ),
|
||||
QgisApp::instance(), [ = ] { QgisApp::instance()->attributeTable( initialMode ); } );
|
||||
attributeTable->setEnabled( vlayer->isValid() );
|
||||
|
||||
// allow editing
|
||||
unsigned int cap = vlayer->dataProvider()->capabilities();
|
||||
@ -219,7 +230,7 @@ QMenu *QgsAppLayerTreeViewMenuProvider::createContextMenu()
|
||||
{
|
||||
menu->addAction( toggleEditingAction );
|
||||
toggleEditingAction->setChecked( vlayer->isEditable() );
|
||||
toggleEditingAction->setEnabled( true );
|
||||
toggleEditingAction->setEnabled( vlayer->isValid() );
|
||||
}
|
||||
if ( saveLayerEditsAction && vlayer->isModified() )
|
||||
{
|
||||
@ -298,10 +309,11 @@ QMenu *QgsAppLayerTreeViewMenuProvider::createContextMenu()
|
||||
QMenu *menuExportVector = new QMenu( tr( "Export" ), menu );
|
||||
QAction *actionSaveAs = new QAction( tr( "Save Features As…" ), menuExportVector );
|
||||
connect( actionSaveAs, &QAction::triggered, QgisApp::instance(), [ = ] { QgisApp::instance()->saveAsFile(); } );
|
||||
actionSaveAs->setEnabled( vlayer->isValid() );
|
||||
menuExportVector->addAction( actionSaveAs );
|
||||
QAction *actionSaveSelectedFeaturesAs = new QAction( tr( "Save Selected Features As…" ), menuExportVector );
|
||||
connect( actionSaveSelectedFeaturesAs, &QAction::triggered, QgisApp::instance(), [ = ] { QgisApp::instance()->saveAsFile( nullptr, true ); } );
|
||||
actionSaveSelectedFeaturesAs->setEnabled( vlayer->selectedFeatureCount() > 0 );
|
||||
actionSaveSelectedFeaturesAs->setEnabled( vlayer->isValid() && vlayer->selectedFeatureCount() > 0 );
|
||||
menuExportVector->addAction( actionSaveSelectedFeaturesAs );
|
||||
QAction *actionSaveAsDefinitionLayer = new QAction( tr( "Save as Layer Definition File…" ), menuExportVector );
|
||||
connect( actionSaveAsDefinitionLayer, &QAction::triggered, QgisApp::instance(), &QgisApp::saveAsLayerDefinition );
|
||||
@ -322,6 +334,7 @@ QMenu *QgsAppLayerTreeViewMenuProvider::createContextMenu()
|
||||
QAction *actionSaveStyle = new QAction( tr( "Save as QGIS Layer Style File…" ), menuExportRaster );
|
||||
connect( actionSaveAs, &QAction::triggered, QgisApp::instance(), [ = ] { QgisApp::instance()->saveAsFile(); } );
|
||||
menuExportRaster->addAction( actionSaveAs );
|
||||
actionSaveAs->setEnabled( rlayer->isValid() );
|
||||
connect( actionSaveAsDefinitionLayer, &QAction::triggered, QgisApp::instance(), &QgisApp::saveAsLayerDefinition );
|
||||
menuExportRaster->addAction( actionSaveAsDefinitionLayer );
|
||||
connect( actionSaveStyle, &QAction::triggered, QgisApp::instance(), [ = ] { QgisApp::instance()->saveStyleFile(); } );
|
||||
|
@ -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 @@ 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
268
tests/testdata/invalid_source.qlr
vendored
Normal 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>
|
Loading…
x
Reference in New Issue
Block a user