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
This commit is contained in:
Martin Dobias 2014-05-25 23:37:10 +07:00
parent 35de393d8d
commit f57d4063a8
5 changed files with 94 additions and 61 deletions

View File

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

View File

@ -37,6 +37,9 @@ class QgsAppLayerTreeViewMenuProvider : public QObject, public QgsLayerTreeViewM
protected:
void addCustomLayerActions( QMenu* menu, QgsMapLayer* layer );
QgsLayerTreeView* mView;
QgsMapCanvas* mCanvas;

View File

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

View File

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

View File

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