Skip to content
Permalink
Browse files
Fix leak of QActions in browser right click menu
Since these actions are created anew whenever we show the menu,
they should be parented to the menu so that they get correctly
cleaned up as soon as the menu is destroyed.
  • Loading branch information
nyalldawson committed Jul 15, 2021
1 parent 14c645e commit d9b6edab76603a00f8b6eb5c1ef5c5fcdd266b97
@@ -75,7 +75,7 @@ void QgsAppDirectoryItemGuiProvider::populateContextMenu( QgsDataItem *item, QMe

QgsSettings settings;

QAction *actionRefresh = new QAction( tr( "Refresh" ), this );
QAction *actionRefresh = new QAction( tr( "Refresh" ), menu );
connect( actionRefresh, &QAction::triggered, this, [ = ] { directoryItem->refresh(); } );
menu->addAction( actionRefresh );

@@ -50,7 +50,7 @@ void QgsGeoPackageItemGuiProvider::populateContextMenu( QgsDataItem *item, QMenu
// Check capabilities
if ( layerItem->capabilities2() & Qgis::BrowserItemCapability::Rename )
{
QAction *actionRenameLayer = new QAction( tr( "Rename Layer '%1'…" ).arg( layerItem->name() ), this );
QAction *actionRenameLayer = new QAction( tr( "Rename Layer '%1'…" ).arg( layerItem->name() ), menu );
QVariantMap data;
const QString uri = layerItem->uri();
const QString providerKey = layerItem->providerKey();
@@ -66,11 +66,11 @@ void QgsGeoPackageItemGuiProvider::populateContextMenu( QgsDataItem *item, QMenu

if ( QgsGeoPackageRootItem *rootItem = qobject_cast< QgsGeoPackageRootItem * >( item ) )
{
QAction *actionNew = new QAction( tr( "New Connection…" ), rootItem->parent() );
QAction *actionNew = new QAction( tr( "New Connection…" ), menu );
connect( actionNew, &QAction::triggered, rootItem, &QgsGeoPackageRootItem::newConnection );
menu->addAction( actionNew );

QAction *actionCreateDatabase = new QAction( tr( "Create Database…" ), rootItem->parent() );
QAction *actionCreateDatabase = new QAction( tr( "Create Database…" ), menu );
QPointer< QgsGeoPackageRootItem > rootItemPointer( rootItem );
connect( actionCreateDatabase, &QAction::triggered, this, [this, rootItemPointer ]
{
@@ -83,24 +83,22 @@ void QgsGeoPackageItemGuiProvider::populateContextMenu( QgsDataItem *item, QMenu
{
if ( QgsOgrDbConnection::connectionList( QStringLiteral( "GPKG" ) ).contains( collectionItem->name() ) )
{
QAction *actionDeleteConnection = new QAction( tr( "Remove Connection" ), collectionItem->parent() );
QAction *actionDeleteConnection = new QAction( tr( "Remove Connection" ), menu );
connect( actionDeleteConnection, &QAction::triggered, collectionItem, &QgsGeoPackageConnectionItem::deleteConnection );
menu->addAction( actionDeleteConnection );
}
else
{
// Add to stored connections
QAction *actionAddConnection = new QAction( tr( "Add Connection" ), collectionItem->parent() );
QAction *actionAddConnection = new QAction( tr( "Add Connection" ), menu );
connect( actionAddConnection, &QAction::triggered, collectionItem, &QgsGeoPackageCollectionItem::addConnection );
menu->addAction( actionAddConnection );
}

QAction *sep = new QAction( collectionItem->parent() );
sep->setSeparator( true );
menu->addAction( sep );
menu->addSeparator();

QString message = QObject::tr( "Delete %1…" ).arg( collectionItem->name() );
QAction *actionDelete = new QAction( message, collectionItem->parent() );
QAction *actionDelete = new QAction( message, menu );
QString collectionPath = collectionItem->path();
QString collectionName = collectionItem->name();
QPointer< QgsDataItem > parent( collectionItem->parent() );
@@ -111,7 +109,7 @@ void QgsGeoPackageItemGuiProvider::populateContextMenu( QgsDataItem *item, QMenu
menu->addAction( actionDelete );

// Run VACUUM
QAction *actionVacuumDb = new QAction( tr( "Compact Database (VACUUM)" ), collectionItem->parent() );
QAction *actionVacuumDb = new QAction( tr( "Compact Database (VACUUM)" ), menu );
QVariantMap dataVacuum;
const QString name = collectionItem->name();
const QString path = collectionItem->path();
@@ -38,7 +38,7 @@ void QgsOgrItemGuiProvider::populateContextMenu(
{
// Messages are different for files and tables
QString message = layerItem->isSubLayer() ? QObject::tr( "Delete Layer “%1”…" ).arg( layerItem->name() ) : QObject::tr( "Delete File “%1”…" ).arg( layerItem->name() );
QAction *actionDeleteLayer = new QAction( message, layerItem->parent() );
QAction *actionDeleteLayer = new QAction( message, menu );
QVariantMap data;
data.insert( QStringLiteral( "isSubLayer" ), layerItem->isSubLayer() );
data.insert( QStringLiteral( "uri" ), layerItem->uri() );
@@ -54,7 +54,7 @@ void QgsOgrItemGuiProvider::populateContextMenu(
const bool isFolder = QFileInfo( collectionItem->path() ).isDir();
// Messages are different for files and tables
QString message = QObject::tr( "Delete %1 “%2”…" ).arg( isFolder ? tr( "Folder" ) : tr( "File" ), collectionItem->name() );
QAction *actionDeleteCollection = new QAction( message, collectionItem->parent() );
QAction *actionDeleteCollection = new QAction( message, menu );

QVariantMap data;
data.insert( QStringLiteral( "path" ), collectionItem->path() );
@@ -30,32 +30,32 @@ void QgsVectorTileDataItemGuiProvider::populateContextMenu( QgsDataItem *item, Q
{
if ( QgsVectorTileLayerItem *layerItem = qobject_cast< QgsVectorTileLayerItem * >( item ) )
{
QAction *actionEdit = new QAction( tr( "Edit…" ), this );
QAction *actionEdit = new QAction( tr( "Edit…" ), menu );
connect( actionEdit, &QAction::triggered, this, [layerItem] { editConnection( layerItem ); } );
menu->addAction( actionEdit );

QAction *actionDelete = new QAction( tr( "Delete" ), this );
QAction *actionDelete = new QAction( tr( "Delete" ), menu );
connect( actionDelete, &QAction::triggered, this, [layerItem] { deleteConnection( layerItem ); } );
menu->addAction( actionDelete );
}

if ( QgsVectorTileRootItem *rootItem = qobject_cast< QgsVectorTileRootItem * >( item ) )
{
QAction *actionNew = new QAction( tr( "New Generic Connection…" ), this );
QAction *actionNew = new QAction( tr( "New Generic Connection…" ), menu );
connect( actionNew, &QAction::triggered, this, [rootItem] { newConnection( rootItem ); } );
menu->addAction( actionNew );

QAction *actionNewArcGISConnection = new QAction( tr( "New ArcGIS Vector Tile Service Connection…" ), this );
QAction *actionNewArcGISConnection = new QAction( tr( "New ArcGIS Vector Tile Service Connection…" ), menu );
connect( actionNewArcGISConnection, &QAction::triggered, this, [rootItem] { newArcGISConnection( rootItem ); } );
menu->addAction( actionNewArcGISConnection );

menu->addSeparator();

QAction *actionSaveXyzTilesServers = new QAction( tr( "Save Connections…" ), this );
QAction *actionSaveXyzTilesServers = new QAction( tr( "Save Connections…" ), menu );
connect( actionSaveXyzTilesServers, &QAction::triggered, this, [] { saveXyzTilesServers(); } );
menu->addAction( actionSaveXyzTilesServers );

QAction *actionLoadXyzTilesServers = new QAction( tr( "Load Connections…" ), this );
QAction *actionLoadXyzTilesServers = new QAction( tr( "Load Connections…" ), menu );
connect( actionLoadXyzTilesServers, &QAction::triggered, this, [rootItem] { loadXyzTilesServers( rootItem ); } );
menu->addAction( actionLoadXyzTilesServers );
}
@@ -32,11 +32,11 @@ void QgsArcGisRestDataItemGuiProvider::populateContextMenu( QgsDataItem *item, Q
connect( actionNew, &QAction::triggered, this, [rootItem] { newConnection( rootItem ); } );
menu->addAction( actionNew );

QAction *actionSaveServers = new QAction( tr( "Save Connections…" ), this );
QAction *actionSaveServers = new QAction( tr( "Save Connections…" ), menu );
connect( actionSaveServers, &QAction::triggered, this, [] { saveConnections(); } );
menu->addAction( actionSaveServers );

QAction *actionLoadServers = new QAction( tr( "Load Connections…" ), this );
QAction *actionLoadServers = new QAction( tr( "Load Connections…" ), menu );
connect( actionLoadServers, &QAction::triggered, this, [rootItem] { loadConnections( rootItem ); } );
menu->addAction( actionLoadServers );
}
@@ -30,11 +30,11 @@ void QgsDb2DataItemGuiProvider::populateContextMenu( QgsDataItem *item, QMenu *m
connect( actionNew, &QAction::triggered, this, [rootItem] { newConnection( rootItem ); } );
menu->addAction( actionNew );

QAction *actionSaveServers = new QAction( tr( "Save Connections…" ), this );
QAction *actionSaveServers = new QAction( tr( "Save Connections…" ), menu );
connect( actionSaveServers, &QAction::triggered, this, [] { saveConnections(); } );
menu->addAction( actionSaveServers );

QAction *actionLoadServers = new QAction( tr( "Load Connections…" ), this );
QAction *actionLoadServers = new QAction( tr( "Load Connections…" ), menu );
connect( actionLoadServers, &QAction::triggered, this, [rootItem] { loadConnections( rootItem ); } );
menu->addAction( actionLoadServers );
}
@@ -29,11 +29,11 @@ void QgsGeoNodeDataItemGuiProvider::populateContextMenu( QgsDataItem *item, QMen
connect( actionNew, &QAction::triggered, this, [rootItem] { newConnection( rootItem ); } );
menu->addAction( actionNew );

QAction *actionSaveServers = new QAction( tr( "Save Connections…" ), this );
QAction *actionSaveServers = new QAction( tr( "Save Connections…" ), menu );
connect( actionSaveServers, &QAction::triggered, this, [] { saveConnections(); } );
menu->addAction( actionSaveServers );

QAction *actionLoadServers = new QAction( tr( "Load Connections…" ), this );
QAction *actionLoadServers = new QAction( tr( "Load Connections…" ), menu );
connect( actionLoadServers, &QAction::triggered, this, [rootItem] { loadConnections( rootItem ); } );
menu->addAction( actionLoadServers );
}
@@ -33,11 +33,11 @@ void QgsMssqlDataItemGuiProvider::populateContextMenu( QgsDataItem *item, QMenu
connect( actionNew, &QAction::triggered, this, [rootItem] { newConnection( rootItem ); } );
menu->addAction( actionNew );

QAction *actionSaveServers = new QAction( tr( "Save Connections…" ), this );
QAction *actionSaveServers = new QAction( tr( "Save Connections…" ), menu );
connect( actionSaveServers, &QAction::triggered, this, [] { saveConnections(); } );
menu->addAction( actionSaveServers );

QAction *actionLoadServers = new QAction( tr( "Load Connections…" ), this );
QAction *actionLoadServers = new QAction( tr( "Load Connections…" ), menu );
connect( actionLoadServers, &QAction::triggered, this, [rootItem] { loadConnections( rootItem ); } );
menu->addAction( actionLoadServers );
}
@@ -31,58 +31,58 @@ void QgsPostgresDataItemGuiProvider::populateContextMenu( QgsDataItem *item, QMe
{
if ( QgsPGRootItem *rootItem = qobject_cast< QgsPGRootItem * >( item ) )
{
QAction *actionNew = new QAction( tr( "New Connection…" ), this );
QAction *actionNew = new QAction( tr( "New Connection…" ), menu );
connect( actionNew, &QAction::triggered, this, [rootItem] { newConnection( rootItem ); } );
menu->addAction( actionNew );

QAction *actionSaveServers = new QAction( tr( "Save Connections…" ), this );
QAction *actionSaveServers = new QAction( tr( "Save Connections…" ), menu );
connect( actionSaveServers, &QAction::triggered, this, [] { saveConnections(); } );
menu->addAction( actionSaveServers );

QAction *actionLoadServers = new QAction( tr( "Load Connections…" ), this );
QAction *actionLoadServers = new QAction( tr( "Load Connections…" ), menu );
connect( actionLoadServers, &QAction::triggered, this, [rootItem] { loadConnections( rootItem ); } );
menu->addAction( actionLoadServers );
}

if ( QgsPGConnectionItem *connItem = qobject_cast< QgsPGConnectionItem * >( item ) )
{
QAction *actionRefresh = new QAction( tr( "Refresh" ), this );
QAction *actionRefresh = new QAction( tr( "Refresh" ), menu );
connect( actionRefresh, &QAction::triggered, this, [connItem] { refreshConnection( connItem ); } );
menu->addAction( actionRefresh );

menu->addSeparator();

QAction *actionEdit = new QAction( tr( "Edit Connection…" ), this );
QAction *actionEdit = new QAction( tr( "Edit Connection…" ), menu );
connect( actionEdit, &QAction::triggered, this, [connItem] { editConnection( connItem ); } );
menu->addAction( actionEdit );

QAction *actionDelete = new QAction( tr( "Delete Connection" ), this );
QAction *actionDelete = new QAction( tr( "Delete Connection" ), menu );
connect( actionDelete, &QAction::triggered, this, [connItem] { deleteConnection( connItem ); } );
menu->addAction( actionDelete );

menu->addSeparator();

QAction *actionCreateSchema = new QAction( tr( "New Schema…" ), this );
QAction *actionCreateSchema = new QAction( tr( "New Schema…" ), menu );
connect( actionCreateSchema, &QAction::triggered, this, [connItem, context] { createSchema( connItem, context ); } );
menu->addAction( actionCreateSchema );

}

if ( QgsPGSchemaItem *schemaItem = qobject_cast< QgsPGSchemaItem * >( item ) )
{
QAction *actionRefresh = new QAction( tr( "Refresh" ), this );
QAction *actionRefresh = new QAction( tr( "Refresh" ), menu );
connect( actionRefresh, &QAction::triggered, this, [schemaItem] { schemaItem->refresh(); } );
menu->addAction( actionRefresh );

menu->addSeparator();

QMenu *maintainMenu = new QMenu( tr( "Schema Operations" ), menu );

QAction *actionRename = new QAction( tr( "Rename Schema…" ), this );
QAction *actionRename = new QAction( tr( "Rename Schema…" ), menu );
connect( actionRename, &QAction::triggered, this, [schemaItem, context] { renameSchema( schemaItem, context ); } );
maintainMenu->addAction( actionRename );

QAction *actionDelete = new QAction( tr( "Delete Schema…" ), this );
QAction *actionDelete = new QAction( tr( "Delete Schema…" ), menu );
connect( actionDelete, &QAction::triggered, this, [schemaItem, context] { deleteSchema( schemaItem, context ); } );
maintainMenu->addAction( actionDelete );

@@ -96,20 +96,20 @@ void QgsPostgresDataItemGuiProvider::populateContextMenu( QgsDataItem *item, QMe

QMenu *maintainMenu = new QMenu( tr( "%1 Operations" ).arg( typeName ), menu );

QAction *actionRenameLayer = new QAction( tr( "Rename %1…" ).arg( typeName ), this );
QAction *actionRenameLayer = new QAction( tr( "Rename %1…" ).arg( typeName ), menu );
connect( actionRenameLayer, &QAction::triggered, this, [layerItem, context] { renameLayer( layerItem, context ); } );
maintainMenu->addAction( actionRenameLayer );

if ( !layerInfo.isView )
{
QAction *actionTruncateLayer = new QAction( tr( "Truncate %1…" ).arg( typeName ), this );
QAction *actionTruncateLayer = new QAction( tr( "Truncate %1…" ).arg( typeName ), menu );
connect( actionTruncateLayer, &QAction::triggered, this, [layerItem, context] { truncateTable( layerItem, context ); } );
maintainMenu->addAction( actionTruncateLayer );
}

if ( layerInfo.isMaterializedView )
{
QAction *actionRefreshMaterializedView = new QAction( tr( "Refresh Materialized View…" ), this );
QAction *actionRefreshMaterializedView = new QAction( tr( "Refresh Materialized View…" ), menu );
connect( actionRefreshMaterializedView, &QAction::triggered, this, [layerItem, context] { refreshMaterializedView( layerItem, context ); } );
maintainMenu->addAction( actionRefreshMaterializedView );
}
@@ -36,18 +36,18 @@ void QgsSpatiaLiteDataItemGuiProvider::populateContextMenu( QgsDataItem *item, Q
{
if ( QgsSLRootItem *rootItem = qobject_cast< QgsSLRootItem * >( item ) )
{
QAction *actionNew = new QAction( tr( "New Connection…" ), this );
QAction *actionNew = new QAction( tr( "New Connection…" ), menu );
connect( actionNew, &QAction::triggered, this, [rootItem] { newConnection( rootItem ); } );
menu->addAction( actionNew );

QAction *actionCreateDatabase = new QAction( tr( "Create Database…" ), this );
QAction *actionCreateDatabase = new QAction( tr( "Create Database…" ), menu );
connect( actionCreateDatabase, &QAction::triggered, this, [rootItem] { createDatabase( rootItem ); } );
menu->addAction( actionCreateDatabase );
}

if ( QgsSLConnectionItem *connItem = qobject_cast< QgsSLConnectionItem * >( item ) )
{
QAction *actionDelete = new QAction( tr( "Delete" ), this );
QAction *actionDelete = new QAction( tr( "Delete" ), menu );
connect( actionDelete, &QAction::triggered, this, [connItem] { deleteConnection( connItem ); } );
menu->addAction( actionDelete );
}
@@ -28,32 +28,32 @@ void QgsWcsDataItemGuiProvider::populateContextMenu( QgsDataItem *item, QMenu *m
{
if ( QgsWCSRootItem *rootItem = qobject_cast< QgsWCSRootItem * >( item ) )
{
QAction *actionNew = new QAction( tr( "New Connection…" ), this );
QAction *actionNew = new QAction( tr( "New Connection…" ), menu );
connect( actionNew, &QAction::triggered, this, [rootItem] { newConnection( rootItem ); } );
menu->addAction( actionNew );

QAction *actionSaveServers = new QAction( tr( "Save Connections…" ), this );
QAction *actionSaveServers = new QAction( tr( "Save Connections…" ), menu );
connect( actionSaveServers, &QAction::triggered, this, [] { saveConnections(); } );
menu->addAction( actionSaveServers );

QAction *actionLoadServers = new QAction( tr( "Load Connections…" ), this );
QAction *actionLoadServers = new QAction( tr( "Load Connections…" ), menu );
connect( actionLoadServers, &QAction::triggered, this, [rootItem] { loadConnections( rootItem ); } );
menu->addAction( actionLoadServers );
}

if ( QgsWCSConnectionItem *connItem = qobject_cast< QgsWCSConnectionItem * >( item ) )
{
QAction *actionRefresh = new QAction( tr( "Refresh" ), this );
QAction *actionRefresh = new QAction( tr( "Refresh" ), menu );
connect( actionRefresh, &QAction::triggered, this, [connItem] { refreshConnection( connItem ); } );
menu->addAction( actionRefresh );

menu->addSeparator();

QAction *actionEdit = new QAction( tr( "Edit…" ), this );
QAction *actionEdit = new QAction( tr( "Edit…" ), menu );
connect( actionEdit, &QAction::triggered, this, [connItem] { editConnection( connItem ); } );
menu->addAction( actionEdit );

QAction *actionDelete = new QAction( tr( "Delete" ), this );
QAction *actionDelete = new QAction( tr( "Delete" ), menu );
connect( actionDelete, &QAction::triggered, this, [connItem] { deleteConnection( connItem ); } );
menu->addAction( actionDelete );
}

0 comments on commit d9b6eda

Please sign in to comment.