Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework layer "Execute SQL" action to use non-modal dialog #60820

Merged
merged 1 commit into from
Mar 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 62 additions & 34 deletions src/app/qgsapplayertreeviewmenuprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -314,51 +314,79 @@ QMenu *QgsAppLayerTreeViewMenuProvider::createContextMenu()

// SQL dialog
if ( conn->capabilities().testFlag( QgsAbstractDatabaseProviderConnection::Capability::ExecuteSql ) )
menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/dbmanager.svg" ) ), tr( "Execute SQL…" ), menu, [layer, this] {
std::unique_ptr<QgsAbstractDatabaseProviderConnection> conn2 { QgsMapLayerUtils::databaseConnection( layer ) };
if ( conn2 )
{
QAction *executeSqlAction = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/dbmanager.svg" ) ), tr( "Execute SQL…" ), menu );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO one day, copy/rename that icon to be slightly more generic than referring to DB Manager as we move forward to phasing that out.

menu->addAction( executeSqlAction );

const QString providerType = layer->providerType();
const QString layerSource = layer->source();
const QString layerName = layer->name();

connect( executeSqlAction, &QAction::triggered, executeSqlAction, [providerType, layerSource, layerName] {
try
{
QgsAbstractDatabaseProviderConnection::SqlVectorLayerOptions options { conn2->sqlOptions( layer->source() ) };
QgsProviderMetadata *providerMetadata = QgsProviderRegistry::instance()->providerMetadata( providerType );
if ( !providerMetadata )
{
return;
}

QgsQueryResultDialog dialog( conn2.release() );
dialog.setObjectName( QStringLiteral( "SqlExecuteDialog" ) );
dialog.setStyleSheet( QgisApp::instance()->styleSheet() );
dialog.setWindowTitle( tr( "Execute SQL" ) );
QgsGui::enableAutoGeometryRestore( &dialog );
dialog.resultWidget()->setSqlVectorLayerOptions( options );
dialog.resultWidget()->executeQuery();
std::unique_ptr< QgsAbstractDatabaseProviderConnection > conn2 { static_cast<QgsAbstractDatabaseProviderConnection *>( providerMetadata->createConnection( layerSource, {} ) ) };
if ( conn2 )
{
QgsAbstractDatabaseProviderConnection::SqlVectorLayerOptions options { conn2->sqlOptions( layerSource ) };

connect( dialog.resultWidget(), &QgsQueryResultWidget::requestDialogTitleUpdate, &dialog, [&dialog]( const QString &fileName ) {
if ( fileName.isEmpty() )
{
dialog.setWindowTitle( tr( "Execute SQL" ) );
}
else
{
dialog.setWindowTitle( tr( "%1 — Execute SQL" ).arg( fileName ) );
}
} );
QgsQueryResultMainWindow *dialog = new QgsQueryResultMainWindow( conn2.release(), layerName );
dialog->setAttribute( Qt::WA_DeleteOnClose );
dialog->setStyleSheet( QgisApp::instance()->styleSheet() );
dialog->resultWidget()->setSqlVectorLayerOptions( options );

connect( dialog.resultWidget(), &QgsQueryResultWidget::createSqlVectorLayer, &dialog, [&dialog, layer, this]( const QString &, const QString &, const QgsAbstractDatabaseProviderConnection::SqlVectorLayerOptions &options ) {
( void ) this;
std::unique_ptr<QgsAbstractDatabaseProviderConnection> conn3 { QgsMapLayerUtils::databaseConnection( layer ) };
if ( conn3 )
{
try
connect( dialog->resultWidget(), &QgsQueryResultWidget::requestDialogTitleUpdate, dialog, [dialog]( const QString &fileName ) {
if ( fileName.isEmpty() )
{
QgsMapLayer *sqlLayer { conn3->createSqlVectorLayer( options ) };
QgsProject::instance()->addMapLayers( { sqlLayer } );
dialog->setWindowTitle( tr( "Execute SQL" ) );
}
catch ( QgsProviderConnectionException &ex )
else
{
dialog.resultWidget()->notify( QObject::tr( "New SQL Layer Creation Error" ), QObject::tr( "Error creating the SQL layer: %1" ).arg( ex.what() ), Qgis::MessageLevel::Critical );
dialog->setWindowTitle( tr( "%1 — Execute SQL" ).arg( fileName ) );
}
}
} );
} );

dialog.exec();
connect( dialog->resultWidget(), &QgsQueryResultWidget::createSqlVectorLayer, dialog, [dialog, layerSource, providerType]( const QString &, const QString &, const QgsAbstractDatabaseProviderConnection::SqlVectorLayerOptions &options ) {
QgsProviderMetadata *providerMetadata = QgsProviderRegistry::instance()->providerMetadata( providerType );
if ( !providerMetadata )
{
return;
}

std::unique_ptr< QgsAbstractDatabaseProviderConnection > conn3 { static_cast<QgsAbstractDatabaseProviderConnection *>( providerMetadata->createConnection( layerSource, {} ) ) };
if ( conn3 )
{
try
{
QgsMapLayer *sqlLayer { conn3->createSqlVectorLayer( options ) };
QgsProject::instance()->addMapLayers( { sqlLayer } );
}
catch ( QgsProviderConnectionException &ex )
{
dialog->resultWidget()->notify( QObject::tr( "New SQL Layer Creation Error" ), QObject::tr( "Error creating the SQL layer: %1" ).arg( ex.what() ), Qgis::MessageLevel::Critical );
}
}
} );

dialog->show();
}
}
catch ( const QgsProviderConnectionException &ex )
{
if ( !ex.what().contains( QLatin1String( "createConnection" ) ) )
{
QgsDebugError( QStringLiteral( "Error retrieving database connection for layer %1: %2" ).arg( layerName, ex.what() ) );
}
return;
}
} );
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/core/qgsmaplayerutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,14 @@ QgsRectangle QgsMapLayerUtils::combinedExtent( const QList<QgsMapLayer *> &layer

QgsAbstractDatabaseProviderConnection *QgsMapLayerUtils::databaseConnection( const QgsMapLayer *layer )
{
if ( ! layer || ! layer->dataProvider() )
if ( !layer )
{
return nullptr;
}

try
{
QgsProviderMetadata *providerMetadata = QgsProviderRegistry::instance()->providerMetadata( layer->dataProvider()->name() );
QgsProviderMetadata *providerMetadata = QgsProviderRegistry::instance()->providerMetadata( layer->providerType() );
if ( ! providerMetadata )
{
return nullptr;
Expand Down
Loading