Skip to content

Commit f57d406

Browse files
committed
Fix #10343 (legend crash with invalid layer)
Fixed the crash itself in the context menu, but also changed the behavior to remove any invalid layers from project as currently there is no mechanism for postponing handling of invalid layers after project load
1 parent 35de393 commit f57d406

5 files changed

+94
-61
lines changed

src/app/qgsapplayertreeviewmenuprovider.cpp

+69-61
Original file line numberDiff line numberDiff line change
@@ -142,67 +142,7 @@ QMenu* QgsAppLayerTreeViewMenuProvider::createContextMenu()
142142
duplicateLayersAction->setEnabled( false );
143143
}
144144

145-
// add custom layer actions - should this go at end?
146-
QList< LegendLayerAction > lyrActions = legendLayerActions( layer->type() );
147-
148-
if ( ! lyrActions.isEmpty() )
149-
{
150-
menu->addSeparator();
151-
QList<QMenu*> theMenus;
152-
for ( int i = 0; i < lyrActions.count(); i++ )
153-
{
154-
if ( lyrActions[i].allLayers || lyrActions[i].layers.contains( layer ) )
155-
{
156-
if ( lyrActions[i].menu.isEmpty() )
157-
{
158-
menu->addAction( lyrActions[i].action );
159-
}
160-
else
161-
{
162-
// find or create menu for given menu name
163-
// adapted from QgisApp::getPluginMenu( QString menuName )
164-
QString menuName = lyrActions[i].menu;
165-
#ifdef Q_WS_MAC
166-
// Mac doesn't have '&' keyboard shortcuts.
167-
menuName.remove( QChar( '&' ) );
168-
#endif
169-
QAction* before = 0;
170-
QMenu* newMenu = 0;
171-
QString dst = menuName;
172-
dst.remove( QChar( '&' ) );
173-
foreach ( QMenu* menu, theMenus )
174-
{
175-
QString src = menu->title();
176-
src.remove( QChar( '&' ) );
177-
int comp = dst.localeAwareCompare( src );
178-
if ( comp < 0 )
179-
{
180-
// Add item before this one
181-
before = menu->menuAction();
182-
break;
183-
}
184-
else if ( comp == 0 )
185-
{
186-
// Plugin menu item already exists
187-
newMenu = menu;
188-
break;
189-
}
190-
}
191-
if ( ! newMenu )
192-
{
193-
// It doesn't exist, so create
194-
newMenu = new QMenu( menuName );
195-
theMenus.append( newMenu );
196-
// Where to put it? - we worked that out above...
197-
menu->insertMenu( before, newMenu );
198-
}
199-
// QMenu* menu = getMenu( lyrActions[i].menu, &theBeforeSep, &theAfterSep, &theMenu );
200-
newMenu->addAction( lyrActions[i].action );
201-
}
202-
}
203-
}
204-
menu->addSeparator();
205-
}
145+
addCustomLayerActions( menu, layer );
206146

207147
if ( layer && QgsProject::instance()->layerIsEmbedded( layer->id() ).isEmpty() )
208148
menu->addAction( tr( "&Properties" ), QgisApp::instance(), SLOT( layerProperties() ) );
@@ -308,3 +248,71 @@ QList< LegendLayerAction > QgsAppLayerTreeViewMenuProvider::legendLayerActions(
308248

309249
return mLegendLayerActionMap.contains( type ) ? mLegendLayerActionMap.value( type ) : QList< LegendLayerAction >() ;
310250
}
251+
252+
void QgsAppLayerTreeViewMenuProvider::addCustomLayerActions( QMenu* menu, QgsMapLayer* layer )
253+
{
254+
if ( !layer )
255+
return;
256+
257+
// add custom layer actions - should this go at end?
258+
QList< LegendLayerAction > lyrActions = legendLayerActions( layer->type() );
259+
260+
if ( ! lyrActions.isEmpty() )
261+
{
262+
menu->addSeparator();
263+
QList<QMenu*> theMenus;
264+
for ( int i = 0; i < lyrActions.count(); i++ )
265+
{
266+
if ( lyrActions[i].allLayers || lyrActions[i].layers.contains( layer ) )
267+
{
268+
if ( lyrActions[i].menu.isEmpty() )
269+
{
270+
menu->addAction( lyrActions[i].action );
271+
}
272+
else
273+
{
274+
// find or create menu for given menu name
275+
// adapted from QgisApp::getPluginMenu( QString menuName )
276+
QString menuName = lyrActions[i].menu;
277+
#ifdef Q_WS_MAC
278+
// Mac doesn't have '&' keyboard shortcuts.
279+
menuName.remove( QChar( '&' ) );
280+
#endif
281+
QAction* before = 0;
282+
QMenu* newMenu = 0;
283+
QString dst = menuName;
284+
dst.remove( QChar( '&' ) );
285+
foreach ( QMenu* menu, theMenus )
286+
{
287+
QString src = menu->title();
288+
src.remove( QChar( '&' ) );
289+
int comp = dst.localeAwareCompare( src );
290+
if ( comp < 0 )
291+
{
292+
// Add item before this one
293+
before = menu->menuAction();
294+
break;
295+
}
296+
else if ( comp == 0 )
297+
{
298+
// Plugin menu item already exists
299+
newMenu = menu;
300+
break;
301+
}
302+
}
303+
if ( ! newMenu )
304+
{
305+
// It doesn't exist, so create
306+
newMenu = new QMenu( menuName );
307+
theMenus.append( newMenu );
308+
// Where to put it? - we worked that out above...
309+
menu->insertMenu( before, newMenu );
310+
}
311+
// QMenu* menu = getMenu( lyrActions[i].menu, &theBeforeSep, &theAfterSep, &theMenu );
312+
newMenu->addAction( lyrActions[i].action );
313+
}
314+
}
315+
}
316+
menu->addSeparator();
317+
}
318+
}

src/app/qgsapplayertreeviewmenuprovider.h

+3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ class QgsAppLayerTreeViewMenuProvider : public QObject, public QgsLayerTreeViewM
3737

3838

3939
protected:
40+
41+
void addCustomLayerActions( QMenu* menu, QgsMapLayer* layer );
42+
4043
QgsLayerTreeView* mView;
4144
QgsMapCanvas* mCanvas;
4245

src/core/layertree/qgslayertreeutils.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -205,3 +205,21 @@ bool QgsLayerTreeUtils::layersModified( const QList<QgsLayerTreeLayer*>& layerNo
205205
}
206206
return false;
207207
}
208+
209+
void QgsLayerTreeUtils::removeInvalidLayers( QgsLayerTreeGroup* group )
210+
{
211+
QList<QgsLayerTreeNode*> nodesToRemove;
212+
foreach ( QgsLayerTreeNode* node, group->children() )
213+
{
214+
if ( QgsLayerTree::isGroup( node ) )
215+
removeInvalidLayers( QgsLayerTree::toGroup( node ) );
216+
else if ( QgsLayerTree::isLayer( node ) )
217+
{
218+
if ( !QgsLayerTree::toLayer( node )->layer() )
219+
nodesToRemove << node;
220+
}
221+
}
222+
223+
foreach ( QgsLayerTreeNode* node, nodesToRemove )
224+
group->removeChildNode( node );
225+
}

src/core/layertree/qgslayertreeutils.h

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class CORE_EXPORT QgsLayerTreeUtils
4545
static bool layersEditable( const QList<QgsLayerTreeLayer*>& layerNodes );
4646
static bool layersModified( const QList<QgsLayerTreeLayer*>& layerNodes );
4747

48+
static void removeInvalidLayers(QgsLayerTreeGroup* group );
4849

4950
protected:
5051
static void addLegendGroupToTreeWidget( const QDomElement& groupElem, QgsLayerTreeGroup* parent );

src/core/qgsproject.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,9 @@ bool QgsProject::read()
942942
// load embedded groups and layers
943943
loadEmbeddedNodes( mRootGroup );
944944

945+
// make sure the are just valid layers
946+
QgsLayerTreeUtils::removeInvalidLayers( mRootGroup );
947+
945948
// read the project: used by map canvas and legend
946949
emit readProject( *doc );
947950

0 commit comments

Comments
 (0)