Skip to content

Commit

Permalink
Fix #10343 (legend crash with invalid layer)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
wonder-sk committed May 25, 2014
1 parent 35de393 commit f57d406
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 61 deletions.
130 changes: 69 additions & 61 deletions src/app/qgsapplayertreeviewmenuprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,67 +142,7 @@ QMenu* QgsAppLayerTreeViewMenuProvider::createContextMenu()
duplicateLayersAction->setEnabled( false );
}

// add custom layer actions - should this go at end?
QList< LegendLayerAction > lyrActions = legendLayerActions( layer->type() );

if ( ! lyrActions.isEmpty() )
{
menu->addSeparator();
QList<QMenu*> theMenus;
for ( int i = 0; i < lyrActions.count(); i++ )
{
if ( lyrActions[i].allLayers || lyrActions[i].layers.contains( layer ) )
{
if ( lyrActions[i].menu.isEmpty() )
{
menu->addAction( lyrActions[i].action );
}
else
{
// find or create menu for given menu name
// adapted from QgisApp::getPluginMenu( QString menuName )
QString menuName = lyrActions[i].menu;
#ifdef Q_WS_MAC
// Mac doesn't have '&' keyboard shortcuts.
menuName.remove( QChar( '&' ) );
#endif
QAction* before = 0;
QMenu* newMenu = 0;
QString dst = menuName;
dst.remove( QChar( '&' ) );
foreach ( QMenu* menu, theMenus )
{
QString src = menu->title();
src.remove( QChar( '&' ) );
int comp = dst.localeAwareCompare( src );
if ( comp < 0 )
{
// Add item before this one
before = menu->menuAction();
break;
}
else if ( comp == 0 )
{
// Plugin menu item already exists
newMenu = menu;
break;
}
}
if ( ! newMenu )
{
// It doesn't exist, so create
newMenu = new QMenu( menuName );
theMenus.append( newMenu );
// Where to put it? - we worked that out above...
menu->insertMenu( before, newMenu );
}
// QMenu* menu = getMenu( lyrActions[i].menu, &theBeforeSep, &theAfterSep, &theMenu );
newMenu->addAction( lyrActions[i].action );
}
}
}
menu->addSeparator();
}
addCustomLayerActions( menu, layer );

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

return mLegendLayerActionMap.contains( type ) ? mLegendLayerActionMap.value( type ) : QList< LegendLayerAction >() ;
}

void QgsAppLayerTreeViewMenuProvider::addCustomLayerActions( QMenu* menu, QgsMapLayer* layer )
{
if ( !layer )
return;

// add custom layer actions - should this go at end?
QList< LegendLayerAction > lyrActions = legendLayerActions( layer->type() );

if ( ! lyrActions.isEmpty() )
{
menu->addSeparator();
QList<QMenu*> theMenus;
for ( int i = 0; i < lyrActions.count(); i++ )
{
if ( lyrActions[i].allLayers || lyrActions[i].layers.contains( layer ) )
{
if ( lyrActions[i].menu.isEmpty() )
{
menu->addAction( lyrActions[i].action );
}
else
{
// find or create menu for given menu name
// adapted from QgisApp::getPluginMenu( QString menuName )
QString menuName = lyrActions[i].menu;
#ifdef Q_WS_MAC
// Mac doesn't have '&' keyboard shortcuts.
menuName.remove( QChar( '&' ) );
#endif
QAction* before = 0;
QMenu* newMenu = 0;
QString dst = menuName;
dst.remove( QChar( '&' ) );
foreach ( QMenu* menu, theMenus )
{
QString src = menu->title();
src.remove( QChar( '&' ) );
int comp = dst.localeAwareCompare( src );
if ( comp < 0 )
{
// Add item before this one
before = menu->menuAction();
break;
}
else if ( comp == 0 )
{
// Plugin menu item already exists
newMenu = menu;
break;
}
}
if ( ! newMenu )
{
// It doesn't exist, so create
newMenu = new QMenu( menuName );
theMenus.append( newMenu );
// Where to put it? - we worked that out above...
menu->insertMenu( before, newMenu );
}
// QMenu* menu = getMenu( lyrActions[i].menu, &theBeforeSep, &theAfterSep, &theMenu );
newMenu->addAction( lyrActions[i].action );
}
}
}
menu->addSeparator();
}
}
3 changes: 3 additions & 0 deletions src/app/qgsapplayertreeviewmenuprovider.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ class QgsAppLayerTreeViewMenuProvider : public QObject, public QgsLayerTreeViewM


protected:

void addCustomLayerActions( QMenu* menu, QgsMapLayer* layer );

QgsLayerTreeView* mView;
QgsMapCanvas* mCanvas;

Expand Down
18 changes: 18 additions & 0 deletions src/core/layertree/qgslayertreeutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,3 +205,21 @@ bool QgsLayerTreeUtils::layersModified( const QList<QgsLayerTreeLayer*>& layerNo
}
return false;
}

void QgsLayerTreeUtils::removeInvalidLayers( QgsLayerTreeGroup* group )
{
QList<QgsLayerTreeNode*> nodesToRemove;
foreach ( QgsLayerTreeNode* node, group->children() )
{
if ( QgsLayerTree::isGroup( node ) )
removeInvalidLayers( QgsLayerTree::toGroup( node ) );
else if ( QgsLayerTree::isLayer( node ) )
{
if ( !QgsLayerTree::toLayer( node )->layer() )
nodesToRemove << node;
}
}

foreach ( QgsLayerTreeNode* node, nodesToRemove )
group->removeChildNode( node );
}
1 change: 1 addition & 0 deletions src/core/layertree/qgslayertreeutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class CORE_EXPORT QgsLayerTreeUtils
static bool layersEditable( const QList<QgsLayerTreeLayer*>& layerNodes );
static bool layersModified( const QList<QgsLayerTreeLayer*>& layerNodes );

static void removeInvalidLayers(QgsLayerTreeGroup* group );

protected:
static void addLegendGroupToTreeWidget( const QDomElement& groupElem, QgsLayerTreeGroup* parent );
Expand Down
3 changes: 3 additions & 0 deletions src/core/qgsproject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,9 @@ bool QgsProject::read()
// load embedded groups and layers
loadEmbeddedNodes( mRootGroup );

// make sure the are just valid layers
QgsLayerTreeUtils::removeInvalidLayers( mRootGroup );

// read the project: used by map canvas and legend
emit readProject( *doc );

Expand Down

0 comments on commit f57d406

Please sign in to comment.