QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
qgsdataitemguiproviderutils.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsdataitemguiproviderutils.cpp
3 --------------------------------------
4 Date : June 2024
5 Copyright : (C) 2024 by Nyall Dawson
6 Email : nyall dot dawson at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17
19#include "qgsapplication.h"
20#include "qgsdataitem.h"
23#include "qgsmessagebar.h"
24#include "qgsmessagebaritem.h"
25#include "qgsmessageoutput.h"
26#include "qgsprovidermetadata.h"
27#include "qgsproviderregistry.h"
28#include "qgstaskmanager.h"
30
31#include <QMessageBox>
32#include <QPointer>
33#include <QPushButton>
34
35void QgsDataItemGuiProviderUtils::deleteConnectionsPrivate( const QStringList &connectionNames, const std::function<void( const QString & )> &deleteConnection, QPointer<QgsDataItem> firstParent )
36{
37 if ( connectionNames.size() > 1 )
38 {
39 if ( QMessageBox::question( nullptr, QObject::tr( "Remove Connections" ), QObject::tr( "Are you sure you want to remove all %1 selected connections?" ).arg( connectionNames.size() ), QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
40 return;
41 }
42 else
43 {
44 if ( QMessageBox::question( nullptr, QObject::tr( "Remove Connection" ), QObject::tr( "Are you sure you want to remove the connection to “%1”?" ).arg( connectionNames.at( 0 ) ), QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
45 return;
46 }
47
48 for ( const QString &connectionName : std::as_const( connectionNames ) )
49 {
50 deleteConnection( connectionName );
51 }
52
53 if ( firstParent )
54 firstParent->refreshConnections();
55}
56
57const QString QgsDataItemGuiProviderUtils::uniqueName( const QString &name, const QStringList &connectionNames )
58{
59 int i = 0;
60 QString newConnectionName( name );
61 while ( connectionNames.contains( newConnectionName ) )
62 {
63 ++i;
64 newConnectionName = QObject::tr( "%1 (copy %2)" ).arg( name ).arg( i );
65 }
66
67 return newConnectionName;
68}
69
70bool QgsDataItemGuiProviderUtils::handleDropUriForConnection( std::unique_ptr<QgsAbstractDatabaseProviderConnection> connection, const QgsMimeDataUtils::Uri &sourceUri, const QString &destinationSchema, QgsDataItemGuiContext context, const QString &shortTitle, const QString &longTitle, const QVariantMap &destinationProviderOptions, const std::function<void()> &onSuccessfulCompletion, const std::function<void( Qgis::VectorExportResult, const QString & )> &onError, QObject *connectionContext )
71{
72 if ( !connection )
73 return false;
74
75 const QString connectionUri = connection->uri();
76 const QString connectionProvider = connection->providerKey();
77
78 QgsDbImportVectorLayerDialog dialog( connection.release(), context.messageBar() ? context.messageBar()->parentWidget() : nullptr );
79 dialog.setMapCanvas( context.mapCanvas() );
80 dialog.setSourceUri( sourceUri );
81 dialog.setDestinationSchema( destinationSchema );
82 if ( !dialog.exec() )
83 return false;
84
85 std::unique_ptr< QgsVectorLayerExporterTask > exportTask = dialog.createExporterTask( destinationProviderOptions );
86 if ( !exportTask )
87 return false;
88
89 const QString destSchema = dialog.schema();
90 const QString destTableName = dialog.tableName();
91 const QString tableComment = dialog.tableComment();
92
93 auto pushError = [shortTitle, longTitle, context]( const QString &error ) {
94 QgsMessageBarItem *item = new QgsMessageBarItem( shortTitle, QObject::tr( "Import failed." ), Qgis::MessageLevel::Warning, 0, nullptr );
95 QPushButton *detailsButton = new QPushButton( QObject::tr( "Details…" ) );
96 QObject::connect( detailsButton, &QPushButton::clicked, detailsButton, [longTitle, error] {
98 output->setTitle( longTitle );
100 output->showMessage();
101 } );
102 item->layout()->addWidget( detailsButton );
104 };
105
106 // when export is successful:
107 QObject::connect( exportTask.get(), &QgsVectorLayerExporterTask::exportComplete, connectionContext, [onSuccessfulCompletion, connectionUri, longTitle, pushError, connectionProvider, destSchema, destTableName, tableComment, shortTitle, context]() {
108 if ( !tableComment.isEmpty() )
109 {
110 std::unique_ptr<QgsAbstractDatabaseProviderConnection> connection;
111 try
112 {
113 QgsProviderMetadata *md = QgsProviderRegistry::instance()->providerMetadata( connectionProvider );
114 connection.reset( static_cast<QgsAbstractDatabaseProviderConnection *>( md->createConnection( connectionUri, {} ) ) );
115 }
116 catch ( QgsProviderConnectionException &e )
117 {
118 pushError( QObject::tr( "Could not retrieve connection details:\n\n%1" ).arg( e.what() ) );
119 return;
120 }
121
122 try
123 {
124 connection->setTableComment( destSchema, destTableName, tableComment );
125 }
126 catch ( QgsProviderConnectionException &e )
127 {
128 pushError( QObject::tr( "Failed to set new table comment!\n\n" ) + e.what() );
129 return;
130 }
131 }
132
133 context.messageBar()->pushSuccess( shortTitle, QObject::tr( "Import was successful." ) );
134 onSuccessfulCompletion();
135 } );
136
137 // when an error occurs:
138 QObject::connect( exportTask.get(), &QgsVectorLayerExporterTask::errorOccurred, connectionContext, [onError, shortTitle, pushError, longTitle]( Qgis::VectorExportResult error, const QString &errorMessage ) {
139 if ( error != Qgis::VectorExportResult::UserCanceled )
140 {
141 pushError( QObject::tr( "Failed to import layer!\n\n" ) + errorMessage );
142 }
143
144 onError( error, errorMessage );
145 } );
146
147 QgsApplication::taskManager()->addTask( exportTask.release() );
148 return true;
149}
150
151void QgsDataItemGuiProviderUtils::handleImportVectorLayerForConnection( std::unique_ptr<QgsAbstractDatabaseProviderConnection> connection, const QString &destinationSchema, QgsDataItemGuiContext context, const QString &shortTitle, const QString &longTitle, const QVariantMap &destinationProviderOptions, const std::function<void()> &onSuccessfulCompletion, const std::function<void( Qgis::VectorExportResult, const QString & )> &onError, QObject *connectionContext )
152{
153 if ( !connection )
154 return;
155
156 const QString connectionUri = connection->uri();
157 const QString connectionProvider = connection->providerKey();
158
159 QgsDbImportVectorLayerDialog dialog( connection.release(), context.messageBar() ? context.messageBar()->parentWidget() : nullptr );
160 dialog.setMapCanvas( context.mapCanvas() );
161 dialog.setDestinationSchema( destinationSchema );
162 if ( !dialog.exec() )
163 return;
164
165 std::unique_ptr< QgsVectorLayerExporterTask > exportTask = dialog.createExporterTask( destinationProviderOptions );
166 if ( !exportTask )
167 return;
168
169 const QString destSchema = dialog.schema();
170 const QString destTableName = dialog.tableName();
171 const QString tableComment = dialog.tableComment();
172
173 auto pushError = [shortTitle, longTitle, context]( const QString &error ) {
174 QgsMessageBarItem *item = new QgsMessageBarItem( shortTitle, QObject::tr( "Import failed." ), Qgis::MessageLevel::Warning, 0, nullptr );
175 QPushButton *detailsButton = new QPushButton( QObject::tr( "Details…" ) );
176 QObject::connect( detailsButton, &QPushButton::clicked, detailsButton, [longTitle, error] {
178 output->setTitle( longTitle );
180 output->showMessage();
181 } );
182 item->layout()->addWidget( detailsButton );
184 };
185
186 // when export is successful:
187 QObject::connect( exportTask.get(), &QgsVectorLayerExporterTask::exportComplete, connectionContext, [onSuccessfulCompletion, connectionUri, longTitle, pushError, connectionProvider, destSchema, destTableName, tableComment, shortTitle, context]() {
188 if ( !tableComment.isEmpty() )
189 {
190 std::unique_ptr<QgsAbstractDatabaseProviderConnection> connection;
191 try
192 {
193 QgsProviderMetadata *md = QgsProviderRegistry::instance()->providerMetadata( connectionProvider );
194 connection.reset( static_cast<QgsAbstractDatabaseProviderConnection *>( md->createConnection( connectionUri, {} ) ) );
195 }
196 catch ( QgsProviderConnectionException &e )
197 {
198 pushError( QObject::tr( "Could not retrieve connection details:\n\n%1" ).arg( e.what() ) );
199 return;
200 }
201
202 try
203 {
204 connection->setTableComment( destSchema, destTableName, tableComment );
205 }
206 catch ( QgsProviderConnectionException &e )
207 {
208 pushError( QObject::tr( "Failed to set new table comment!\n\n" ) + e.what() );
209 return;
210 }
211 }
212
213 context.messageBar()->pushSuccess( shortTitle, QObject::tr( "Import was successful." ) );
214 onSuccessfulCompletion();
215 } );
216
217 // when an error occurs:
218 QObject::connect( exportTask.get(), &QgsVectorLayerExporterTask::errorOccurred, connectionContext, [onError, shortTitle, pushError, longTitle]( Qgis::VectorExportResult error, const QString &errorMessage ) {
219 if ( error != Qgis::VectorExportResult::UserCanceled )
220 {
221 pushError( QObject::tr( "Failed to import layer!\n\n" ) + errorMessage );
222 }
223
224 onError( error, errorMessage );
225 } );
226
227 QgsApplication::taskManager()->addTask( exportTask.release() );
228}
229
230void QgsDataItemGuiProviderUtils::addToSubMenu( QMenu *mainMenu, QAction *actionToAdd, const QString &subMenuName )
231{
232 // this action should sit in the Manage menu. If one does not exist, create it now
233 bool foundExistingManageMenu = false;
234 const QList<QAction *> actions = mainMenu->actions();
235 for ( QAction *action : actions )
236 {
237 if ( action->text() == subMenuName )
238 {
239 action->menu()->addAction( actionToAdd );
240 foundExistingManageMenu = true;
241 break;
242 }
243 }
244 if ( !foundExistingManageMenu )
245 {
246 QMenu *addSubMenu = new QMenu( subMenuName, mainMenu );
247 addSubMenu->addAction( actionToAdd );
248 mainMenu->addMenu( addSubMenu );
249 }
250}
251
253{
254 const QVector<QgsDataItem *> constChildren { item->children() };
255 for ( QgsDataItem *c : constChildren )
256 {
257 if ( c->name() == name )
258 {
259 if ( c->state() != Qgis::BrowserItemState::NotPopulated )
260 {
261 c->refresh();
262 }
263 break;
264 }
265 }
266}
@ NotPopulated
Children not yet created.
Definition qgis.h:939
VectorExportResult
Vector layer export result codes.
Definition qgis.h:1052
@ Warning
Warning message.
Definition qgis.h:158
static QgsTaskManager * taskManager()
Returns the application's task manager, used for managing application wide background task handling.
Encapsulates the context in which a QgsDataItem is shown within the application GUI.
QgsMessageBar * messageBar() const
Returns the associated message bar.
QgsMapCanvas * mapCanvas() const
Returns the map canvas associated with the item.
static void refreshChildWithName(QgsDataItem *item, const QString &name)
Refresh child of item that has give name.
static void handleImportVectorLayerForConnection(std::unique_ptr< QgsAbstractDatabaseProviderConnection > connection, const QString &destinationSchema, QgsDataItemGuiContext context, const QString &shortTitle, const QString &longTitle, const QVariantMap &destinationProviderOptions, const std::function< void()> &onSuccessfulCompletion, const std::function< void(Qgis::VectorExportResult error, const QString &errorMessage)> &onError, QObject *connectionContext)
Handles importing a vector layer for connection items.
static const QString uniqueName(const QString &name, const QStringList &connectionNames)
Check if connection with name exists in connectionNames list and then try to append a number to it to...
static bool handleDropUriForConnection(std::unique_ptr< QgsAbstractDatabaseProviderConnection > connection, const QgsMimeDataUtils::Uri &sourceUri, const QString &destinationSchema, QgsDataItemGuiContext context, const QString &shortTitle, const QString &longTitle, const QVariantMap &destinationProviderOptions, const std::function< void()> &onSuccessfulCompletion, const std::function< void(Qgis::VectorExportResult error, const QString &errorMessage)> &onError, QObject *connectionContext)
Handles dropping a vector layer for connection items.
static void addToSubMenu(QMenu *mainMenu, QAction *actionToAdd, const QString &subMenuName)
Add an actionToAdd to the sub menu with subMenuName in mainMenu.
Base class for all items in the model.
Definition qgsdataitem.h:47
QVector< QgsDataItem * > children() const
A generic dialog for customising vector layer import options for database connections.
void setDestinationSchema(const QString &schema)
Sets the destination schema for the new table.
std::unique_ptr< QgsVectorLayerExporterTask > createExporterTask(const QVariantMap &extraProviderOptions=QVariantMap())
Creates a new exporter task to match the settings defined in the dialog.
void setMapCanvas(QgsMapCanvas *canvas)
Sets a map canvas to associate with the dialog.
void setSourceUri(const QgsMimeDataUtils::Uri &uri)
Sets the source table uri.
QString schema() const
Returns the destination schema.
QString tableName() const
Returns the destination table name.
QString tableComment() const
Returns the optional comment to use for the new table.
Represents an item shown within a QgsMessageBar widget.
QgsMessageBarItem * pushWidget(QWidget *widget, Qgis::MessageLevel level=Qgis::MessageLevel::Info, int duration=0)
Display a widget as a message on the bar, after hiding the currently visible one and putting it in a ...
void pushSuccess(const QString &title, const QString &message)
Pushes a success message with default timeout to the message bar.
Interface for showing messages from QGIS in GUI independent way.
virtual void showMessage(bool blocking=true)=0
display the message to the user and deletes itself
static QgsMessageOutput * createMessageOutput()
function that returns new class derived from QgsMessageOutput (don't forget to delete it then if show...
virtual void setMessage(const QString &message, MessageType msgType)=0
Sets message, it won't be displayed until.
virtual void setTitle(const QString &title)=0
Sets title for the messages.
long addTask(QgsTask *task, int priority=0)
Adds a task to the manager.
void exportComplete()
Emitted when exporting the layer is successfully completed.
void errorOccurred(Qgis::VectorExportResult error, const QString &errorMessage)
Emitted when an error occurs which prevented the layer being exported (or if the task is canceled).
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c