1 /***************************************************************************
2 qgsmssqldataitems.cpp - description
3 -------------------
4 begin : 2011-10-08
5 copyright : (C) 2011 by Tamas Szekeres
6 email : szekerest at gmail.com
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18 #include "qgsmssqldataitems.h"
19 #include "qgsmssqlconnection.h"
20 #include "qgsmssqldatabase.h"
21
22 #include "qgsmssqlgeomcolumntypethread.h"
23 #include "qgslogger.h"
24 #include "qgsmimedatautils.h"
25 #include "qgsvectorlayer.h"
26 #include "qgsvectorlayerexporter.h"
27 #include "qgsdatasourceuri.h"
28 #include "qgsmssqlprovider.h"
29 #include "qgssettings.h"
30 #include "qgsmessageoutput.h"
31 #include "qgsmssqlconnection.h"
32 #include "qgsapplication.h"
33 #include "qgsproject.h"
34 #include "qgsfieldsitem.h"
35
36 #ifdef HAVE_GUI
37 #include "qgsmssqlsourceselect.h"
38 #endif
39
40 #include <QMessageBox>
41 #include <QSqlDatabase>
42 #include <QSqlError>
43
44 // ---------------------------------------------------------------------------
QgsMssqlConnectionItem(QgsDataItem * parent,const QString & name,const QString & path)45 QgsMssqlConnectionItem::QgsMssqlConnectionItem( QgsDataItem *parent, const QString &name, const QString &path )
46 : QgsDataCollectionItem( parent, name, path, QStringLiteral( "MSSQL" ) )
47 , mUseGeometryColumns( false )
48 , mUseEstimatedMetadata( false )
49 , mAllowGeometrylessTables( true )
50 {
51 mCapabilities |= Qgis::BrowserItemCapability::Fast | Qgis::BrowserItemCapability::Collapse;
52 mIconName = QStringLiteral( "mIconConnect.svg" );
53 }
54
~QgsMssqlConnectionItem()55 QgsMssqlConnectionItem::~QgsMssqlConnectionItem()
56 {
57 stop();
58 }
59
readConnectionSettings()60 void QgsMssqlConnectionItem::readConnectionSettings()
61 {
62 QgsSettings settings;
63 QString key = "/MSSQL/connections/" + mName;
64 mService = settings.value( key + "/service" ).toString();
65 mHost = settings.value( key + "/host" ).toString();
66 mDatabase = settings.value( key + "/database" ).toString();
67 if ( settings.value( key + "/saveUsername" ).toString() == QLatin1String( "true" ) )
68 {
69 mUsername = settings.value( key + "/username" ).toString();
70 }
71
72 if ( settings.value( key + "/savePassword" ).toString() == QLatin1String( "true" ) )
73 {
74 mPassword = settings.value( key + "/password" ).toString();
75 }
76
77 mSchemaSettings.clear();
78 mSchemasFilteringEnabled = settings.value( key + "/schemasFiltering" ).toBool();
79
80 if ( mSchemasFilteringEnabled )
81 {
82 QVariant schemasSettingsVariant = settings.value( key + "/excludedSchemas" );
83 if ( schemasSettingsVariant.isValid() && schemasSettingsVariant.type() == QVariant::Map )
84 mSchemaSettings = schemasSettingsVariant.toMap();
85 }
86
87 mUseGeometryColumns = QgsMssqlConnection::geometryColumnsOnly( mName );
88 mUseEstimatedMetadata = QgsMssqlConnection::useEstimatedMetadata( mName );
89 mAllowGeometrylessTables = QgsMssqlConnection::allowGeometrylessTables( mName );
90
91 mConnInfo = "dbname='" + mDatabase + "' host='" + mHost + "' user='" + mUsername + "' password='" + mPassword + '\'';
92 if ( !mService.isEmpty() )
93 mConnInfo += " service='" + mService + '\'';
94 if ( mUseEstimatedMetadata )
95 mConnInfo += QLatin1String( " estimatedmetadata=true" );
96 }
97
stop()98 void QgsMssqlConnectionItem::stop()
99 {
100 if ( mColumnTypeThread )
101 {
102 mColumnTypeThread->stop();
103 mColumnTypeThread->wait();
104 delete mColumnTypeThread;
105 mColumnTypeThread = nullptr;
106 }
107 }
108
refresh()109 void QgsMssqlConnectionItem::refresh()
110 {
111 QgsDebugMsgLevel( "mPath = " + mPath, 3 );
112 stop();
113
114 // Clear all children
115 const QVector<QgsDataItem *> allChidren = children();
116 for ( QgsDataItem *item : allChidren )
117 {
118 removeChildItem( item );
119 delete item;
120 }
121
122 // read up the schemas and layers from database
123 const QVector<QgsDataItem *> items = createChildren();
124 for ( QgsDataItem *item : items )
125 addChildItem( item, true );
126 }
127
createChildren()128 QVector<QgsDataItem *> QgsMssqlConnectionItem::createChildren()
129 {
130 setState( Qgis::BrowserItemState::Populating );
131
132 stop();
133
134 QVector<QgsDataItem *> children;
135 if ( deferredDelete() )
136 return children;
137
138 readConnectionSettings();
139
140 std::shared_ptr<QgsMssqlDatabase> db = QgsMssqlDatabase::connectDb( mService, mHost, mDatabase, mUsername, mPassword );
141
142 if ( !db->isValid() )
143 {
144 children.append( new QgsErrorItem( this, db->errorText(), mPath + "/error" ) );
145 setAsPopulated();
146 return children;
147 }
148
149 // build sql statement
150 QString query = QgsMssqlConnection::buildQueryForTables( mName );
151
152 const bool disableInvalidGeometryHandling = QgsMssqlConnection::isInvalidGeometryHandlingDisabled( mName );
153
154 // issue the sql query
155 QSqlQuery q = QSqlQuery( db->db() );
156 q.setForwardOnly( true );
157 ( void )q.exec( query );
158
159 QSet< QString > addedSchemas;
160
161 if ( q.isActive() )
162 {
163 QVector<QgsDataItem *> newLayers;
164 while ( q.next() )
165 {
166 QgsMssqlLayerProperty layer;
167 layer.schemaName = q.value( 0 ).toString();
168 layer.tableName = q.value( 1 ).toString();
169 layer.geometryColName = q.value( 2 ).toString();
170 layer.srid = q.value( 3 ).toString();
171 layer.type = q.value( 4 ).toString();
172 layer.isView = q.value( 5 ).toBool();
173 layer.pkCols = QStringList(); //TODO
174 layer.isGeography = false;
175
176 // skip layers which are added already
177 bool skip = false;
178 const auto constMChildren = mChildren;
179 for ( QgsDataItem *child : constMChildren )
180 {
181 if ( child->name() == layer.schemaName )
182 {
183 const auto constChildren = child->children();
184 for ( QgsDataItem *child2 : constChildren )
185 {
186 QgsMssqlLayerItem *layerItem = qobject_cast< QgsMssqlLayerItem *>( child2 );
187 if ( child2->name() == layer.tableName && layerItem && layerItem->disableInvalidGeometryHandling() == disableInvalidGeometryHandling )
188 {
189 newLayers.append( child2 );
190 skip = true; // already added
191 break;
192 }
193 }
194 }
195 }
196
197 if ( skip )
198 continue;
199
200 QString type = layer.type;
201 QString srid = layer.srid;
202
203 QgsMssqlSchemaItem *schemaItem = nullptr;
204 const auto constChildren = children;
205 for ( QgsDataItem *child : constChildren )
206 {
207 if ( child->name() == layer.schemaName )
208 {
209 schemaItem = static_cast< QgsMssqlSchemaItem * >( child );
210 break;
211 }
212 }
213
214 if ( !schemaItem )
215 {
216 schemaItem = new QgsMssqlSchemaItem( this, layer.schemaName, mPath + '/' + layer.schemaName );
217 schemaItem->setState( Qgis::BrowserItemState::Populating );
218 addedSchemas.insert( layer.schemaName );
219 children.append( schemaItem );
220 }
221
222 if ( !layer.geometryColName.isNull() )
223 {
224 if ( type == QLatin1String( "GEOMETRY" ) || type.isNull() || srid.isEmpty() )
225 {
226 if ( !mColumnTypeThread )
227 {
228 mColumnTypeThread = new QgsMssqlGeomColumnTypeThread( mService, mHost, mDatabase, mUsername, mPassword, true /* use estimated metadata */ );
229
230 connect( mColumnTypeThread, &QgsMssqlGeomColumnTypeThread::setLayerType,
231 this, &QgsMssqlConnectionItem::setLayerType );
232 connect( this, &QgsMssqlConnectionItem::addGeometryColumn,
233 mColumnTypeThread, &QgsMssqlGeomColumnTypeThread::addGeometryColumn );
234 }
235
236 emit addGeometryColumn( layer );
237 continue;
238 }
239 }
240
241 QgsMssqlLayerItem *added = schemaItem->addLayer( layer, false );
242 if ( added )
243 newLayers.append( added );
244 }
245
246 // Remove no more present items
247 const auto constMChildren = mChildren;
248 for ( QgsDataItem *child : constMChildren )
249 {
250 const auto constChildren = child->children();
251 for ( QgsDataItem *child2 : constChildren )
252 {
253 if ( findItem( newLayers, child2 ) < 0 )
254 child->deleteChildItem( child2 );
255 }
256 }
257
258 // add missing schemas (i.e., empty schemas)
259 const QString uri = connInfo();
260 const QStringList allSchemas = QgsMssqlConnection::schemas( uri, nullptr );
261 QStringList excludedSchema = QgsMssqlConnection::excludedSchemasList( mName );
262 for ( const QString &schema : allSchemas )
263 {
264 if ( mSchemasFilteringEnabled && excludedSchema.contains( schema ) )
265 continue; // user does not want it to be shown
266
267 if ( addedSchemas.contains( schema ) )
268 continue;
269
270 if ( QgsMssqlConnection::isSystemSchema( schema ) )
271 continue;
272
273 QgsMssqlSchemaItem *schemaItem = new QgsMssqlSchemaItem( this, schema, mPath + '/' + schema );
274 schemaItem->setState( Qgis::BrowserItemState::Populated ); // no tables
275 addedSchemas.insert( schema );
276 children.append( schemaItem );
277 }
278
279 // spawn threads (new layers will be added later on)
280 if ( mColumnTypeThread )
281 {
282 connect( mColumnTypeThread, &QThread::finished, this, &QgsMssqlConnectionItem::setAsPopulated );
283 mColumnTypeThread->start();
284 }
285 else
286 {
287 //set all as populated -- we also need to do this for newly created items, because they won't yet be children of this item
288 for ( QgsDataItem *child : std::as_const( children ) )
289 {
290 child->setState( Qgis::BrowserItemState::Populated );
291 }
292 setAsPopulated();
293 }
294 }
295 else
296 {
297 setAsPopulated();
298 }
299
300 return children;
301 }
302
setAsPopulated()303 void QgsMssqlConnectionItem::setAsPopulated()
304 {
305 const auto constMChildren = mChildren;
306 for ( QgsDataItem *child : constMChildren )
307 {
308 child->setState( Qgis::BrowserItemState::Populated );
309 }
310 setState( Qgis::BrowserItemState::Populated );
311 }
312
setAllowGeometrylessTables(const bool allow)313 void QgsMssqlConnectionItem::setAllowGeometrylessTables( const bool allow )
314 {
315 mAllowGeometrylessTables = allow;
316 QgsMssqlConnection::setAllowGeometrylessTables( mName, allow );
317 refresh();
318 }
319
setLayerType(QgsMssqlLayerProperty layerProperty)320 void QgsMssqlConnectionItem::setLayerType( QgsMssqlLayerProperty layerProperty )
321 {
322 QgsMssqlSchemaItem *schemaItem = nullptr;
323
324 const auto constMChildren = mChildren;
325 for ( QgsDataItem *child : constMChildren )
326 {
327 if ( child->name() == layerProperty.schemaName )
328 {
329 schemaItem = static_cast< QgsMssqlSchemaItem * >( child );
330 break;
331 }
332 }
333
334 if ( !schemaItem )
335 {
336 QgsDebugMsg( QStringLiteral( "schema item for %1 not found." ).arg( layerProperty.schemaName ) );
337 return;
338 }
339
340 const auto constChildren = schemaItem->children();
341 for ( QgsDataItem *layerItem : constChildren )
342 {
343 if ( layerItem->name() == layerProperty.tableName )
344 return; // already added
345 }
346
347 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
348 QStringList typeList = layerProperty.type.split( ',', QString::SkipEmptyParts );
349 QStringList sridList = layerProperty.srid.split( ',', QString::SkipEmptyParts );
350 #else
351 QStringList typeList = layerProperty.type.split( ',', Qt::SkipEmptyParts );
352 QStringList sridList = layerProperty.srid.split( ',', Qt::SkipEmptyParts );
353 #endif
354 Q_ASSERT( typeList.size() == sridList.size() );
355
356 for ( int i = 0; i < typeList.size(); i++ )
357 {
358 QgsWkbTypes::Type wkbType = QgsMssqlTableModel::wkbTypeFromMssql( typeList[i] );
359 if ( wkbType == QgsWkbTypes::Unknown )
360 {
361 QgsDebugMsg( QStringLiteral( "unsupported geometry type:%1" ).arg( typeList[i] ) );
362 continue;
363 }
364
365 layerProperty.type = typeList[i];
366 layerProperty.srid = sridList[i];
367 schemaItem->addLayer( layerProperty, true );
368 }
369
370 if ( typeList.isEmpty() )
371 {
372 // this suggests that retrieval of geometry type and CRS failed if no results were returned
373 // for examle due to invalid geometries in the table (WHAAAT?)
374 // but we still want to add have such table in the list
375 schemaItem->addLayer( layerProperty, true );
376 }
377 }
378
equal(const QgsDataItem * other)379 bool QgsMssqlConnectionItem::equal( const QgsDataItem *other )
380 {
381 if ( type() != other->type() )
382 {
383 return false;
384 }
385
386 const QgsMssqlConnectionItem *o = qobject_cast<const QgsMssqlConnectionItem *>( other );
387 return ( mPath == o->mPath && mName == o->mName );
388 }
389
handleDrop(const QMimeData * data,const QString & toSchema)390 bool QgsMssqlConnectionItem::handleDrop( const QMimeData *data, const QString &toSchema )
391 {
392 if ( !QgsMimeDataUtils::isUriList( data ) )
393 return false;
394
395 // TODO: probably should show a GUI with settings etc
396 QStringList importResults;
397 bool hasError = false;
398
399 QgsMimeDataUtils::UriList lst = QgsMimeDataUtils::decodeUriList( data );
400 const auto constLst = lst;
401 for ( const QgsMimeDataUtils::Uri &u : constLst )
402 {
403 if ( u.layerType != QLatin1String( "vector" ) )
404 {
405 importResults.append( tr( "%1: Not a vector layer!" ).arg( u.name ) );
406 hasError = true; // only vectors can be imported
407 continue;
408 }
409
410 // open the source layer
411 const QgsVectorLayer::LayerOptions options { QgsProject::instance()->transformContext() };
412 QgsVectorLayer *srcLayer = new QgsVectorLayer( u.uri, u.name, u.providerKey, options );
413
414 if ( srcLayer->isValid() )
415 {
416 QString tableName;
417 if ( !toSchema.isEmpty() )
418 {
419 tableName = QStringLiteral( "\"%1\".\"%2\"" ).arg( toSchema, u.name );
420 }
421 else
422 {
423 tableName = u.name;
424 }
425
426 QString uri = connInfo() + " table=" + tableName;
427 if ( srcLayer->geometryType() != QgsWkbTypes::NullGeometry )
428 uri += QLatin1String( " (geom)" );
429
430 std::unique_ptr< QgsVectorLayerExporterTask > exportTask( QgsVectorLayerExporterTask::withLayerOwnership( srcLayer, uri, QStringLiteral( "mssql" ), srcLayer->crs() ) );
431
432 // when export is successful:
433 connect( exportTask.get(), &QgsVectorLayerExporterTask::exportComplete, this, [ = ]()
434 {
435 // this is gross - TODO - find a way to get access to messageBar from data items
436 QMessageBox::information( nullptr, tr( "Import to MSSQL database" ), tr( "Import was successful." ) );
437 if ( state() == Qgis::BrowserItemState::Populated )
438 refresh();
439 else
440 populate();
441 } );
442
443 // when an error occurs:
444 connect( exportTask.get(), &QgsVectorLayerExporterTask::errorOccurred, this, [ = ]( Qgis::VectorExportResult error, const QString & errorMessage )
445 {
446 if ( error != Qgis::VectorExportResult::UserCanceled )
447 {
448 QgsMessageOutput *output = QgsMessageOutput::createMessageOutput();
449 output->setTitle( tr( "Import to MSSQL database" ) );
450 output->setMessage( tr( "Failed to import some layers!\n\n" ) + errorMessage, QgsMessageOutput::MessageText );
451 output->showMessage();
452 }
453 if ( state() == Qgis::BrowserItemState::Populated )
454 refresh();
455 else
456 populate();
457 } );
458
459 QgsApplication::taskManager()->addTask( exportTask.release() );
460 }
461 else
462 {
463 importResults.append( tr( "%1: Not a valid layer!" ).arg( u.name ) );
464 hasError = true;
465 }
466 }
467
468 if ( hasError )
469 {
470 QgsMessageOutput *output = QgsMessageOutput::createMessageOutput();
471 output->setTitle( tr( "Import to MSSQL database" ) );
472 output->setMessage( tr( "Failed to import some layers!\n\n" ) + importResults.join( QLatin1Char( '\n' ) ), QgsMessageOutput::MessageText );
473 output->showMessage();
474 }
475
476 return true;
477 }
478
479
480 // ---------------------------------------------------------------------------
QgsMssqlLayerItem(QgsDataItem * parent,const QString & name,const QString & path,Qgis::BrowserLayerType layerType,const QgsMssqlLayerProperty & layerProperty)481 QgsMssqlLayerItem::QgsMssqlLayerItem( QgsDataItem *parent, const QString &name, const QString &path, Qgis::BrowserLayerType layerType, const QgsMssqlLayerProperty &layerProperty )
482 : QgsLayerItem( parent, name, path, QString(), layerType, QStringLiteral( "mssql" ) )
483 , mLayerProperty( layerProperty )
484 {
485 mCapabilities |= Qgis::BrowserItemCapability::Delete;
486 mUri = createUri();
487 setState( Qgis::BrowserItemState::NotPopulated );
488 }
489
490
createClone()491 QgsMssqlLayerItem *QgsMssqlLayerItem::createClone()
492 {
493 return new QgsMssqlLayerItem( mParent, mName, mPath, mLayerType, mLayerProperty );
494 }
495
disableInvalidGeometryHandling() const496 bool QgsMssqlLayerItem::disableInvalidGeometryHandling() const
497 {
498 return mDisableInvalidGeometryHandling;
499 }
500
createUri()501 QString QgsMssqlLayerItem::createUri()
502 {
503 QString pkColName = !mLayerProperty.pkCols.isEmpty() ? mLayerProperty.pkCols.at( 0 ) : QString();
504 QgsMssqlConnectionItem *connItem = qobject_cast<QgsMssqlConnectionItem *>( parent() ? parent()->parent() : nullptr );
505
506 if ( !connItem )
507 {
508 QgsDebugMsg( QStringLiteral( "connection item not found." ) );
509 return QString();
510 }
511
512 QgsDataSourceUri uri = QgsDataSourceUri( connItem->connInfo() );
513 uri.setDataSource( mLayerProperty.schemaName, mLayerProperty.tableName, mLayerProperty.geometryColName, mLayerProperty.sql, pkColName );
514 uri.setSrid( mLayerProperty.srid );
515 uri.setWkbType( QgsMssqlTableModel::wkbTypeFromMssql( mLayerProperty.type ) );
516 uri.setUseEstimatedMetadata( QgsMssqlConnection::useEstimatedMetadata( connItem->name() ) );
517 mDisableInvalidGeometryHandling = QgsMssqlConnection::isInvalidGeometryHandlingDisabled( connItem->name() );
518 uri.setParam( QStringLiteral( "disableInvalidGeometryHandling" ), mDisableInvalidGeometryHandling ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
519 if ( QgsMssqlConnection::geometryColumnsOnly( connItem->name() ) )
520 {
521 uri.setParam( QStringLiteral( "extentInGeometryColumns" ), QgsMssqlConnection::extentInGeometryColumns( connItem->name() ) ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
522 }
523 if ( mLayerProperty.isView )
524 uri.setParam( QStringLiteral( "primaryKeyInGeometryColumns" ), QgsMssqlConnection::primaryKeyInGeometryColumns( connItem->name() ) ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
525
526 QgsDebugMsgLevel( QStringLiteral( "layer uri: %1" ).arg( uri.uri() ), 3 );
527 return uri.uri();
528 }
529
530 // ---------------------------------------------------------------------------
QgsMssqlSchemaItem(QgsDataItem * parent,const QString & name,const QString & path)531 QgsMssqlSchemaItem::QgsMssqlSchemaItem( QgsDataItem *parent, const QString &name, const QString &path )
532 : QgsDatabaseSchemaItem( parent, name, path, QStringLiteral( "MSSQL" ) )
533 {
534 mIconName = QStringLiteral( "mIconDbSchema.svg" );
535 //not fertile, since children are created by QgsMssqlConnectionItem
536 mCapabilities &= ~Qgis::BrowserItemCapabilities( Qgis::BrowserItemCapability::Fertile );
537 }
538
createChildren()539 QVector<QgsDataItem *> QgsMssqlSchemaItem::createChildren()
540 {
541 return QVector<QgsDataItem *>();
542 }
543
544
addLayers(QgsDataItem * newLayers)545 void QgsMssqlSchemaItem::addLayers( QgsDataItem *newLayers )
546 {
547 // Add new items
548 const auto constChildren = newLayers->children();
549 for ( QgsDataItem *child : constChildren )
550 {
551 // Is it present in children?
552 if ( findItem( mChildren, child ) >= 0 )
553 {
554 continue;
555 }
556 QgsMssqlLayerItem *layer = static_cast< QgsMssqlLayerItem * >( child )->createClone();
557 addChildItem( layer, true );
558 }
559 }
560
addLayer(const QgsMssqlLayerProperty & layerProperty,bool refresh)561 QgsMssqlLayerItem *QgsMssqlSchemaItem::addLayer( const QgsMssqlLayerProperty &layerProperty, bool refresh )
562 {
563 QgsWkbTypes::Type wkbType = QgsMssqlTableModel::wkbTypeFromMssql( layerProperty.type );
564 QString tip = tr( "%1 as %2 in %3" ).arg( layerProperty.geometryColName, QgsWkbTypes::displayString( wkbType ), layerProperty.srid );
565
566 Qgis::BrowserLayerType layerType;
567 QgsWkbTypes::Type flatType = QgsWkbTypes::flatType( wkbType );
568 switch ( flatType )
569 {
570 case QgsWkbTypes::Point:
571 case QgsWkbTypes::MultiPoint:
572 layerType = Qgis::BrowserLayerType::Point;
573 break;
574 case QgsWkbTypes::LineString:
575 case QgsWkbTypes::MultiLineString:
576 layerType = Qgis::BrowserLayerType::Line;
577 break;
578 case QgsWkbTypes::Polygon:
579 case QgsWkbTypes::MultiPolygon:
580 layerType = Qgis::BrowserLayerType::Polygon;
581 break;
582 default:
583 if ( layerProperty.type == QLatin1String( "NONE" ) && layerProperty.geometryColName.isEmpty() )
584 {
585 layerType = Qgis::BrowserLayerType::TableLayer;
586 tip = tr( "as geometryless table" );
587 }
588 else if ( !layerProperty.geometryColName.isEmpty() && layerProperty.type.isEmpty() )
589 {
590 // geometry column is there but we failed to determine geometry type (e.g. due to invalid geometries)
591 layerType = Qgis::BrowserLayerType::Vector;
592 }
593 else
594 {
595 return nullptr;
596 }
597 }
598
599 QgsMssqlLayerItem *layerItem = new QgsMssqlLayerItem( this, layerProperty.tableName, mPath + '/' + layerProperty.tableName, layerType, layerProperty );
600 layerItem->setToolTip( tip );
601 if ( refresh )
602 addChildItem( layerItem, true );
603 else
604 {
605 addChild( layerItem );
606 layerItem->setParent( this );
607 }
608
609 return layerItem;
610 }
611
refresh()612 void QgsMssqlSchemaItem::refresh()
613 {
614 if ( auto *lParent = parent() )
615 lParent->refresh();
616 }
617
618
createChildren()619 QVector<QgsDataItem *> QgsMssqlLayerItem::createChildren()
620 {
621 QVector<QgsDataItem *> children;
622 children.push_back( new QgsFieldsItem( this, uri() + QStringLiteral( "/columns/ " ), createUri(), providerKey(), mLayerProperty.schemaName, mLayerProperty.tableName ) );
623 return children;
624 }
625
626 // ---------------------------------------------------------------------------
QgsMssqlRootItem(QgsDataItem * parent,const QString & name,const QString & path)627 QgsMssqlRootItem::QgsMssqlRootItem( QgsDataItem *parent, const QString &name, const QString &path )
628 : QgsConnectionsRootItem( parent, name, path, QStringLiteral( "MSSQL" ) )
629 {
630 mIconName = QStringLiteral( "mIconMssql.svg" );
631 populate();
632 }
633
createChildren()634 QVector<QgsDataItem *> QgsMssqlRootItem::createChildren()
635 {
636 QVector<QgsDataItem *> connections;
637 QgsSettings settings;
638 settings.beginGroup( QStringLiteral( "/MSSQL/connections" ) );
639 const auto constChildGroups = settings.childGroups();
640 for ( const QString &connName : constChildGroups )
641 {
642 connections << new QgsMssqlConnectionItem( this, connName, mPath + '/' + connName );
643 }
644 return connections;
645 }
646
647 #ifdef HAVE_GUI
paramWidget()648 QWidget *QgsMssqlRootItem::paramWidget()
649 {
650 QgsMssqlSourceSelect *select = new QgsMssqlSourceSelect( nullptr, Qt::WindowFlags(), QgsProviderRegistry::WidgetMode::Manager );
651 connect( select, &QgsMssqlSourceSelect::connectionsChanged, this, &QgsMssqlRootItem::onConnectionsChanged );
652 return select;
653 }
654
onConnectionsChanged()655 void QgsMssqlRootItem::onConnectionsChanged()
656 {
657 refresh();
658 }
659 #endif
660
name()661 QString QgsMssqlDataItemProvider::name()
662 {
663 return QStringLiteral( "MSSQL" );
664 }
665
dataProviderKey() const666 QString QgsMssqlDataItemProvider::dataProviderKey() const
667 {
668 return QStringLiteral( "mssql" );
669 }
670
capabilities() const671 int QgsMssqlDataItemProvider::capabilities() const
672 {
673 return QgsDataProvider::Database;
674 }
675
createDataItem(const QString & pathIn,QgsDataItem * parentItem)676 QgsDataItem *QgsMssqlDataItemProvider::createDataItem( const QString &pathIn, QgsDataItem *parentItem )
677 {
678 Q_UNUSED( pathIn )
679 return new QgsMssqlRootItem( parentItem, QStringLiteral( "MSSQL" ), QStringLiteral( "mssql:" ) );
680 }
681
682
layerCollection() const683 bool QgsMssqlSchemaItem::layerCollection() const
684 {
685 return true;
686 }
687