From 2dd042cd93adb9db739d099622f38ea9e0463499 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Thu, 17 Apr 2025 14:33:09 +1000 Subject: [PATCH] Show history panel in execute sql dialog --- .../history/qgshistorywidgetcontext.sip.in | 18 ++++++++++ .../history/qgshistorywidgetcontext.sip.in | 18 ++++++++++ src/gui/history/qgshistorywidget.cpp | 1 + src/gui/history/qgshistorywidgetcontext.cpp | 10 ++++++ src/gui/history/qgshistorywidgetcontext.h | 18 ++++++++++ src/gui/qgsdbqueryhistoryprovider.cpp | 27 ++++++++++++-- src/gui/qgsdbqueryhistoryprovider.h | 30 ++++++++++++++++ src/gui/qgsqueryresultwidget.cpp | 36 +++++++++++++++++++ src/gui/qgsqueryresultwidget.h | 3 ++ src/ui/qgsqueryresultwidgetbase.ui | 12 +++++++ 10 files changed, 171 insertions(+), 2 deletions(-) diff --git a/python/PyQt6/gui/auto_generated/history/qgshistorywidgetcontext.sip.in b/python/PyQt6/gui/auto_generated/history/qgshistorywidgetcontext.sip.in index 7773fd3d607..4e0ec5f19f3 100644 --- a/python/PyQt6/gui/auto_generated/history/qgshistorywidgetcontext.sip.in +++ b/python/PyQt6/gui/auto_generated/history/qgshistorywidgetcontext.sip.in @@ -37,6 +37,24 @@ widget to push feedback messages to the appropriate message bar. Returns the message bar associated with the widget. .. seealso:: :py:func:`setMessageBar` +%End + + void setHistoryWidget( QgsHistoryWidget *widget ); +%Docstring +Sets the parent history ``widget``. + +.. seealso:: :py:func:`historyWidget` + +.. versionadded:: 3.44 +%End + + QgsHistoryWidget *historyWidget() const; +%Docstring +Returns the parent histroy widget. + +.. seealso:: :py:func:`setHistoryWidget` + +.. versionadded:: 3.44 %End }; diff --git a/python/gui/auto_generated/history/qgshistorywidgetcontext.sip.in b/python/gui/auto_generated/history/qgshistorywidgetcontext.sip.in index 7773fd3d607..4e0ec5f19f3 100644 --- a/python/gui/auto_generated/history/qgshistorywidgetcontext.sip.in +++ b/python/gui/auto_generated/history/qgshistorywidgetcontext.sip.in @@ -37,6 +37,24 @@ widget to push feedback messages to the appropriate message bar. Returns the message bar associated with the widget. .. seealso:: :py:func:`setMessageBar` +%End + + void setHistoryWidget( QgsHistoryWidget *widget ); +%Docstring +Sets the parent history ``widget``. + +.. seealso:: :py:func:`historyWidget` + +.. versionadded:: 3.44 +%End + + QgsHistoryWidget *historyWidget() const; +%Docstring +Returns the parent histroy widget. + +.. seealso:: :py:func:`setHistoryWidget` + +.. versionadded:: 3.44 %End }; diff --git a/src/gui/history/qgshistorywidget.cpp b/src/gui/history/qgshistorywidget.cpp index 5bf8fa8c2c1..284a6f29934 100644 --- a/src/gui/history/qgshistorywidget.cpp +++ b/src/gui/history/qgshistorywidget.cpp @@ -32,6 +32,7 @@ QgsHistoryWidget::QgsHistoryWidget( const QString &providerId, Qgis::HistoryProv , mContext( context ) { setupUi( this ); + mContext.setHistoryWidget( this ); mModel = new QgsHistoryEntryModel( providerId, backends, registry, mContext, this ); mProxyModel = new QgsHistoryEntryProxyModel( this ); diff --git a/src/gui/history/qgshistorywidgetcontext.cpp b/src/gui/history/qgshistorywidgetcontext.cpp index 61d2d238d83..60ac1c86f45 100644 --- a/src/gui/history/qgshistorywidgetcontext.cpp +++ b/src/gui/history/qgshistorywidgetcontext.cpp @@ -24,3 +24,13 @@ QgsMessageBar *QgsHistoryWidgetContext::messageBar() const { return mMessageBar; } + +void QgsHistoryWidgetContext::setHistoryWidget( QgsHistoryWidget *widget ) +{ + mHistoryWidget = widget; +} + +QgsHistoryWidget *QgsHistoryWidgetContext::historyWidget() const +{ + return mHistoryWidget; +} diff --git a/src/gui/history/qgshistorywidgetcontext.h b/src/gui/history/qgshistorywidgetcontext.h index 66aadf4abd8..28d46c6ca85 100644 --- a/src/gui/history/qgshistorywidgetcontext.h +++ b/src/gui/history/qgshistorywidgetcontext.h @@ -20,6 +20,7 @@ #include "qgis_gui.h" class QgsMessageBar; +class QgsHistoryWidget; /** * \ingroup gui @@ -46,8 +47,25 @@ class GUI_EXPORT QgsHistoryWidgetContext */ QgsMessageBar *messageBar() const; + /** + * Sets the parent history \a widget. + * + * \see historyWidget() + * \since QGIS 3.44 + */ + void setHistoryWidget( QgsHistoryWidget *widget ); + + /** + * Returns the parent histroy widget. + * + * \see setHistoryWidget() + * \since QGIS 3.44 + */ + QgsHistoryWidget *historyWidget() const; + private: QgsMessageBar *mMessageBar = nullptr; + QgsHistoryWidget *mHistoryWidget = nullptr; }; #endif // QGSHISTORYWIDGETCONTEXT_H diff --git a/src/gui/qgsdbqueryhistoryprovider.cpp b/src/gui/qgsdbqueryhistoryprovider.cpp index dec379318b8..7e7da7db894 100644 --- a/src/gui/qgsdbqueryhistoryprovider.cpp +++ b/src/gui/qgsdbqueryhistoryprovider.cpp @@ -21,6 +21,7 @@ #include "qgsprovidermetadata.h" #include "qgsproviderregistry.h" #include "qgsapplication.h" +#include "qgshistorywidgetcontext.h" #include #include @@ -150,9 +151,16 @@ class DatabaseQueryRootNode : public DatabaseQueryHistoryNode return editor; } - bool doubleClicked( const QgsHistoryWidgetContext & ) override + bool doubleClicked( const QgsHistoryWidgetContext &context ) override { - mProvider->emitOpenSqlDialog( mEntry.entry.value( QStringLiteral( "connection" ) ).toString(), mEntry.entry.value( QStringLiteral( "provider" ) ).toString(), mEntry.entry.value( QStringLiteral( "query" ) ).toString() ); + if ( QgsDatabaseQueryHistoryWidget *queryHistoryWidget = qobject_cast< QgsDatabaseQueryHistoryWidget * >( context.historyWidget() ) ) + { + queryHistoryWidget->emitSqlTriggered( mEntry.entry.value( QStringLiteral( "connection" ) ).toString(), mEntry.entry.value( QStringLiteral( "provider" ) ).toString(), mEntry.entry.value( QStringLiteral( "query" ) ).toString() ); + } + else + { + mProvider->emitOpenSqlDialog( mEntry.entry.value( QStringLiteral( "connection" ) ).toString(), mEntry.entry.value( QStringLiteral( "provider" ) ).toString(), mEntry.entry.value( QStringLiteral( "query" ) ).toString() ); + } return true; } @@ -215,3 +223,18 @@ void QgsDatabaseQueryHistoryProvider::emitOpenSqlDialog( const QString &connecti { emit openSqlDialog( connectionUri, provider, sql ); } + + +// +// QgsDatabaseQueryHistoryWidget +// + +QgsDatabaseQueryHistoryWidget::QgsDatabaseQueryHistoryWidget( Qgis::HistoryProviderBackends backends, QgsHistoryProviderRegistry *registry, const QgsHistoryWidgetContext &context, QWidget *parent ) + : QgsHistoryWidget( QStringLiteral( "dbquery" ), backends, registry, context, parent ) +{ +} + +void QgsDatabaseQueryHistoryWidget::emitSqlTriggered( const QString &connectionUri, const QString &provider, const QString &sql ) +{ + emit sqlTriggered( connectionUri, provider, sql ); +} diff --git a/src/gui/qgsdbqueryhistoryprovider.h b/src/gui/qgsdbqueryhistoryprovider.h index 6b403400f59..625c458d738 100644 --- a/src/gui/qgsdbqueryhistoryprovider.h +++ b/src/gui/qgsdbqueryhistoryprovider.h @@ -21,9 +21,39 @@ #include "qgshistoryprovider.h" #include "qgshistoryentrynode.h" +#include "qgshistorywidget.h" #define SIP_NO_FILE +/** + * Custom QgsHistoryWidget for use with the database query provider. + * + * \ingroup gui + * + * \note Not available in Python bindings + * \since QGIS 3.44 + */ +class GUI_EXPORT QgsDatabaseQueryHistoryWidget : public QgsHistoryWidget +{ + Q_OBJECT + + public: + QgsDatabaseQueryHistoryWidget( Qgis::HistoryProviderBackends backends = Qgis::HistoryProviderBackend::LocalProfile, QgsHistoryProviderRegistry *registry = nullptr, const QgsHistoryWidgetContext &context = QgsHistoryWidgetContext(), QWidget *parent = nullptr ); + + /** + * Causes the widget to emit the sqlTriggered() signal. + */ + void emitSqlTriggered( const QString &connectionUri, const QString &provider, const QString &sql ); + + signals: + + /** + * Emitted when the user has triggered a previously executed SQL statement in the widget. + */ + void sqlTriggered( const QString &connectionUri, const QString &provider, const QString &sql ); +}; + + /** * History provider for operations database queries. * diff --git a/src/gui/qgsqueryresultwidget.cpp b/src/gui/qgsqueryresultwidget.cpp index 3e365dabe92..0a274b53b06 100644 --- a/src/gui/qgsqueryresultwidget.cpp +++ b/src/gui/qgsqueryresultwidget.cpp @@ -32,6 +32,8 @@ #include "qgsstoredquerymanager.h" #include "qgsproject.h" #include "qgsnewnamedialog.h" +#include "qgshistorywidget.h" +#include "qgsdbqueryhistoryprovider.h" #include #include @@ -691,6 +693,8 @@ QgsQueryResultWidget::QgsQueryResultWidget( QWidget *parent, QgsAbstractDatabase connect( mQueryWidget->codeEditorWidget(), &QgsCodeEditorWidget::searchBarToggled, mActionFindReplace, &QAction::setChecked ); connect( mQueryWidget->sqlEditor(), &QgsCodeEditor::modificationChanged, this, &QgsQueryResultWidget::setHasChanged ); + connect( mActionShowHistory, &QAction::toggled, this, &QgsQueryResultWidget::showHistoryPanel ); + connect( mActionClear, &QAction::triggered, this, [=] { mQueryWidget->sqlEditor()->setText( QString() ); mActionUndo->setEnabled( false ); @@ -711,6 +715,11 @@ QgsQueryResultWidget::QgsQueryResultWidget( QWidget *parent, QgsAbstractDatabase QgsQueryResultWidget::~QgsQueryResultWidget() { + if ( mHistoryWidget ) + { + mPanelStack->closePanel( mHistoryWidget ); + mHistoryWidget->deleteLater(); + } } void QgsQueryResultWidget::setSqlVectorLayerOptions( const QgsAbstractDatabaseProviderConnection::SqlVectorLayerOptions &options ) @@ -1020,6 +1029,33 @@ void QgsQueryResultWidget::storeCurrentQuery( Qgis::QueryStorageBackend backend } } + +void QgsQueryResultWidget::showHistoryPanel( bool show ) +{ + if ( show ) + { + mHistoryWidget = new QgsDatabaseQueryHistoryWidget(); + mHistoryWidget->setPanelTitle( tr( "SQL History" ) ); + mPanelStack->showPanel( mHistoryWidget ); + connect( mHistoryWidget, &QgsPanelWidget::panelAccepted, this, [this] { whileBlocking( mActionShowHistory )->setChecked( false ); } ); + connect( mHistoryWidget, &QgsDatabaseQueryHistoryWidget::sqlTriggered, this, [this]( const QString &connectionUri, const QString &provider, const QString &sql ) { + Q_UNUSED( connectionUri ); + Q_UNUSED( provider ); + + mQueryWidget->sqlEditor()->setText( sql ); + mActionUndo->setEnabled( false ); + mActionRedo->setEnabled( false ); + mHistoryWidget->acceptPanel(); + } ); + } + else if ( mHistoryWidget ) + { + mPanelStack->closePanel( mHistoryWidget ); + mHistoryWidget->deleteLater(); + } +} + + ///@cond private void QgsConnectionsApiFetcher::fetchTokens() diff --git a/src/gui/qgsqueryresultwidget.h b/src/gui/qgsqueryresultwidget.h index 2b657a5e5f4..184dce1cc9c 100644 --- a/src/gui/qgsqueryresultwidget.h +++ b/src/gui/qgsqueryresultwidget.h @@ -35,6 +35,7 @@ class QgsCodeEditorWidget; class QgsCodeEditorSQL; class QgsQueryResultPanelWidget; +class QgsDatabaseQueryHistoryWidget; ///@cond private @@ -228,9 +229,11 @@ class GUI_EXPORT QgsQueryResultWidget : public QWidget, private Ui::QgsQueryResu void saveQuery( bool saveAs ); void setHasChanged( bool hasChanged ); void populatePresetQueryMenu(); + void showHistoryPanel( bool show ); private: QgsQueryResultPanelWidget *mQueryWidget = nullptr; + QPointer< QgsDatabaseQueryHistoryWidget > mHistoryWidget; QMenu *mPresetQueryMenu = nullptr; diff --git a/src/ui/qgsqueryresultwidgetbase.ui b/src/ui/qgsqueryresultwidgetbase.ui index 78a2b8db308..7b6f9a682d8 100644 --- a/src/ui/qgsqueryresultwidgetbase.ui +++ b/src/ui/qgsqueryresultwidgetbase.ui @@ -53,6 +53,7 @@ + @@ -205,6 +206,17 @@ Ctrl+Shift+S + + + true + + + History + + + QAction::NoRole + +