QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
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::
40 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 )
41 != QMessageBox::Yes )
42 return;
43 }
44 else
45 {
46 if ( QMessageBox::
47 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 )
48 != QMessageBox::Yes )
49 return;
50 }
51
52 for ( const QString &connectionName : std::as_const( connectionNames ) )
53 {
54 deleteConnection( connectionName );
55 }
56
57 if ( firstParent )
58 firstParent->refreshConnections();
59}
60
61const QString QgsDataItemGuiProviderUtils::uniqueName( const QString &name, const QStringList &connectionNames )
62{
63 int i = 0;
64 QString newConnectionName( name );
65 while ( connectionNames.contains( newConnectionName ) )
66 {
67 ++i;
68 newConnectionName = QObject::tr( "%1 (copy %2)" ).arg( name ).arg( i );
69 }
70
71 return newConnectionName;
72}
73
75 std::unique_ptr<QgsAbstractDatabaseProviderConnection> connection,
76 const QgsMimeDataUtils::Uri &sourceUri,
77 const QString &destinationSchema,
79 const QString &shortTitle,
80 const QString &longTitle,
81 const QVariantMap &destinationProviderOptions,
82 const std::function<void()> &onSuccessfulCompletion,
83 const std::function<void( Qgis::VectorExportResult, const QString & )> &onError,
84 QObject *connectionContext
85)
86{
87 if ( !connection )
88 return false;
89
90 const QString connectionUri = connection->uri();
91 const QString connectionProvider = connection->providerKey();
92
93 QgsDbImportVectorLayerDialog dialog( connection.release(), context.messageBar() ? context.messageBar()->parentWidget() : nullptr );
94 dialog.setMapCanvas( context.mapCanvas() );
95 dialog.setSourceUri( sourceUri );
96 dialog.setDestinationSchema( destinationSchema );
97 if ( !dialog.exec() )
98 return false;
99
100 std::unique_ptr< QgsVectorLayerExporterTask > exportTask = dialog.createExporterTask( destinationProviderOptions );
101 if ( !exportTask )
102 return false;
103
104 const QString destSchema = dialog.schema();
105 const QString destTableName = dialog.tableName();
106 const QString tableComment = dialog.tableComment();
107
108 auto pushError = [shortTitle, longTitle, context]( const QString &error ) {
109 QgsMessageBarItem *item = new QgsMessageBarItem( shortTitle, QObject::tr( "Import failed." ), Qgis::MessageLevel::Warning, 0, nullptr );
110 QPushButton *detailsButton = new QPushButton( QObject::tr( "Details…" ) );
111 QObject::connect( detailsButton, &QPushButton::clicked, detailsButton, [longTitle, error] {
113 output->setTitle( longTitle );
115 output->showMessage();
116 } );
117 item->layout()->addWidget( detailsButton );
119 };
120
121 // when export is successful:
122 QObject::
123 connect( exportTask.get(), &QgsVectorLayerExporterTask::exportComplete, connectionContext, [onSuccessfulCompletion, connectionUri, longTitle, pushError, connectionProvider, destSchema, destTableName, tableComment, shortTitle, context]() {
124 if ( !tableComment.isEmpty() )
125 {
126 std::unique_ptr<QgsAbstractDatabaseProviderConnection> connection;
127 try
128 {
129 QgsProviderMetadata *md = QgsProviderRegistry::instance()->providerMetadata( connectionProvider );
130 connection.reset( static_cast<QgsAbstractDatabaseProviderConnection *>( md->createConnection( connectionUri, {} ) ) );
131 }
132 catch ( QgsProviderConnectionException &e )
133 {
134 pushError( QObject::tr( "Could not retrieve connection details:\n\n%1" ).arg( e.what() ) );
135 return;
136 }
137
138 try
139 {
140 connection->setTableComment( destSchema, destTableName, tableComment );
141 }
142 catch ( QgsProviderConnectionException &e )
143 {
144 pushError( QObject::tr( "Failed to set new table comment!\n\n" ) + e.what() );
145 return;
146 }
147 }
148
149 context.messageBar()->pushSuccess( shortTitle, QObject::tr( "Import was successful." ) );
150 onSuccessfulCompletion();
151 } );
152
153 // when an error occurs:
154 QObject::connect( exportTask.get(), &QgsVectorLayerExporterTask::errorOccurred, connectionContext, [onError, shortTitle, pushError, longTitle]( Qgis::VectorExportResult error, const QString &errorMessage ) {
155 if ( error != Qgis::VectorExportResult::UserCanceled )
156 {
157 pushError( QObject::tr( "Failed to import layer!\n\n" ) + errorMessage );
158 }
159
160 onError( error, errorMessage );
161 } );
162
163 QgsApplication::taskManager()->addTask( exportTask.release() );
164 return true;
165}
166
168 std::unique_ptr<QgsAbstractDatabaseProviderConnection> connection,
169 const QString &destinationSchema,
170 QgsDataItemGuiContext context,
171 const QString &shortTitle,
172 const QString &longTitle,
173 const QVariantMap &destinationProviderOptions,
174 const std::function<void()> &onSuccessfulCompletion,
175 const std::function<void( Qgis::VectorExportResult, const QString & )> &onError,
176 QObject *connectionContext
177)
178{
179 if ( !connection )
180 return;
181
182 const QString connectionUri = connection->uri();
183 const QString connectionProvider = connection->providerKey();
184
185 QgsDbImportVectorLayerDialog dialog( connection.release(), context.messageBar() ? context.messageBar()->parentWidget() : nullptr );
186 dialog.setMapCanvas( context.mapCanvas() );
187 dialog.setDestinationSchema( destinationSchema );
188 if ( !dialog.exec() )
189 return;
190
191 std::unique_ptr< QgsVectorLayerExporterTask > exportTask = dialog.createExporterTask( destinationProviderOptions );
192 if ( !exportTask )
193 return;
194
195 const QString destSchema = dialog.schema();
196 const QString destTableName = dialog.tableName();
197 const QString tableComment = dialog.tableComment();
198
199 auto pushError = [shortTitle, longTitle, context]( const QString &error ) {
200 QgsMessageBarItem *item = new QgsMessageBarItem( shortTitle, QObject::tr( "Import failed." ), Qgis::MessageLevel::Warning, 0, nullptr );
201 QPushButton *detailsButton = new QPushButton( QObject::tr( "Details…" ) );
202 QObject::connect( detailsButton, &QPushButton::clicked, detailsButton, [longTitle, error] {
204 output->setTitle( longTitle );
206 output->showMessage();
207 } );
208 item->layout()->addWidget( detailsButton );
210 };
211
212 // when export is successful:
213 QObject::
214 connect( exportTask.get(), &QgsVectorLayerExporterTask::exportComplete, connectionContext, [onSuccessfulCompletion, connectionUri, longTitle, pushError, connectionProvider, destSchema, destTableName, tableComment, shortTitle, context]() {
215 if ( !tableComment.isEmpty() )
216 {
217 std::unique_ptr<QgsAbstractDatabaseProviderConnection> connection;
218 try
219 {
220 QgsProviderMetadata *md = QgsProviderRegistry::instance()->providerMetadata( connectionProvider );
221 connection.reset( static_cast<QgsAbstractDatabaseProviderConnection *>( md->createConnection( connectionUri, {} ) ) );
222 }
223 catch ( QgsProviderConnectionException &e )
224 {
225 pushError( QObject::tr( "Could not retrieve connection details:\n\n%1" ).arg( e.what() ) );
226 return;
227 }
228
229 try
230 {
231 connection->setTableComment( destSchema, destTableName, tableComment );
232 }
233 catch ( QgsProviderConnectionException &e )
234 {
235 pushError( QObject::tr( "Failed to set new table comment!\n\n" ) + e.what() );
236 return;
237 }
238 }
239
240 context.messageBar()->pushSuccess( shortTitle, QObject::tr( "Import was successful." ) );
241 onSuccessfulCompletion();
242 } );
243
244 // when an error occurs:
245 QObject::connect( exportTask.get(), &QgsVectorLayerExporterTask::errorOccurred, connectionContext, [onError, shortTitle, pushError, longTitle]( Qgis::VectorExportResult error, const QString &errorMessage ) {
246 if ( error != Qgis::VectorExportResult::UserCanceled )
247 {
248 pushError( QObject::tr( "Failed to import layer!\n\n" ) + errorMessage );
249 }
250
251 onError( error, errorMessage );
252 } );
253
254 QgsApplication::taskManager()->addTask( exportTask.release() );
255}
256
257void QgsDataItemGuiProviderUtils::addToSubMenu( QMenu *mainMenu, QAction *actionToAdd, const QString &subMenuName )
258{
259 // this action should sit in the Manage menu. If one does not exist, create it now
260 bool foundExistingManageMenu = false;
261 const QList<QAction *> actions = mainMenu->actions();
262 for ( QAction *action : actions )
263 {
264 if ( action->text() == subMenuName )
265 {
266 action->menu()->addAction( actionToAdd );
267 foundExistingManageMenu = true;
268 break;
269 }
270 }
271 if ( !foundExistingManageMenu )
272 {
273 QMenu *addSubMenu = new QMenu( subMenuName, mainMenu );
274 addSubMenu->addAction( actionToAdd );
275 mainMenu->addMenu( addSubMenu );
276 }
277}
278
280{
281 const QVector<QgsDataItem *> constChildren { item->children() };
282 for ( QgsDataItem *c : constChildren )
283 {
284 if ( c->name() == name )
285 {
286 if ( c->state() != Qgis::BrowserItemState::NotPopulated )
287 {
288 c->refresh();
289 }
290 break;
291 }
292 }
293}
@ NotPopulated
Children not yet created.
Definition qgis.h:965
VectorExportResult
Vector layer export result codes.
Definition qgis.h:1078
@ Warning
Warning message.
Definition qgis.h:162
@ PlainText
Text message.
Definition qgis.h:176
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:50
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, Qgis::StringFormat format)=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