QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
qgsdataitem.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsdataitem.cpp - Data items
3  -------------------
4  begin : 2011-04-01
5  copyright : (C) 2011 Radim Blazek
6  email : radim dot blazek at gmail dot 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 <QApplication>
19 #include <QtConcurrentMap>
20 #include <QtConcurrentRun>
21 #include <QDateTime>
22 #include <QElapsedTimer>
23 #include <QDir>
24 #include <QFileInfo>
25 #include <QMenu>
26 #include <QMouseEvent>
27 #include <QTreeWidget>
28 #include <QTreeWidgetItem>
29 #include <QVector>
30 #include <QStyle>
31 #include <QTimer>
32 #include <mutex>
33 #include <QRegularExpression>
34 
35 #include "qgis.h"
36 #include "qgsdataitem.h"
37 #include "qgsapplication.h"
38 #include "qgsdataitemprovider.h"
40 #include "qgsdataprovider.h"
41 #include "qgslogger.h"
42 #include "qgsproviderregistry.h"
43 #include "qgsconfig.h"
44 #include "qgssettings.h"
45 #include "qgsanimatedicon.h"
46 #include "qgsproject.h"
47 #include "qgsvectorlayer.h"
48 #include "qgsprovidermetadata.h"
49 
50 // use GDAL VSI mechanism
51 #define CPL_SUPRESS_CPLUSPLUS //#spellok
52 #include "cpl_vsi.h"
53 #include "cpl_string.h"
54 
55 // shared icons
56 
58 {
60  switch ( geomType )
61  {
63  return iconTable();
65  return iconPoint();
67  return iconLine();
69  return iconPolygon();
70  default:
71  break;
72  }
73  return iconDefault();
74 }
75 
77 {
78  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconPointLayer.svg" ) );
79 }
80 
82 {
83  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconLineLayer.svg" ) );
84 }
85 
87 {
88  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconPolygonLayer.svg" ) );
89 }
90 
92 {
93  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconTableLayer.svg" ) );
94 }
95 
97 {
98  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconRaster.svg" ) );
99 }
100 
102 {
103  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconMeshLayer.svg" ) );
104 }
105 
107 {
108  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconVectorTileLayer.svg" ) );
109 }
110 
112 {
113  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconPointCloudLayer.svg" ) );
114 }
115 
117 {
118  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconLayer.png" ) );
119 }
120 
122 {
123  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconDbSchema.svg" ) );
124 }
125 
127 {
128  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconFolderOpen.svg" ) );
129 }
130 
132 {
133  return QgsApplication::getThemeIcon( QStringLiteral( "mIconFolderHome.svg" ) );
134 }
135 
137 {
138  const QString dataProviderKey { QgsApplication::dataItemProviderRegistry()->dataProviderKey( providerKey() ) };
140 
141  if ( ! md )
142  {
143  return nullptr;
144  }
145 
146  const QString connectionName { name() };
147 
148  try
149  {
150  // First try to retrieve the connection by name if this is a stored connection
151  if ( md->findConnection( connectionName ) )
152  {
153  return static_cast<QgsAbstractDatabaseProviderConnection *>( md->createConnection( connectionName ) );
154  }
155 
156  // If that fails, try to create a connection from the path, in case this is a
157  // filesystem-based DB (gpkg or spatialite)
158  // The name is useless, we need to get the file path from the data item path
159  const QString databaseFilePath { path().remove( QRegularExpression( R"re([\aZ]{2,}://)re" ) ) };
160 
161  if ( QFile::exists( databaseFilePath ) )
162  {
163  return static_cast<QgsAbstractDatabaseProviderConnection *>( md->createConnection( databaseFilePath, {} ) );
164  }
165  }
166  catch ( QgsProviderConnectionException &ex )
167  {
168  // This is expected and it is not an error in case the provider does not implement
169  // the connections API
170  }
171  return nullptr;
172 }
173 
175 {
176  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconFolder.svg" ) );
177 }
178 
179 
181  const QString &path,
182  const QString &connectionUri,
183  const QString &providerKey,
184  const QString &schema,
185  const QString &tableName )
186  : QgsDataItem( QgsDataItem::Fields, parent, tr( "Fields" ), path, providerKey )
187  , mSchema( schema )
188  , mTableName( tableName )
189  , mConnectionUri( connectionUri )
190 {
191  mCapabilities |= ( Fertile | Collapse );
193  if ( md )
194  {
195  try
196  {
197  std::unique_ptr<QgsAbstractDatabaseProviderConnection> conn { static_cast<QgsAbstractDatabaseProviderConnection *>( md->createConnection( mConnectionUri, {} ) ) };
198  mTableProperty = qgis::make_unique<QgsAbstractDatabaseProviderConnection::TableProperty>( conn->table( schema, tableName ) );
199  }
200  catch ( QgsProviderConnectionException &ex )
201  {
202  QgsDebugMsg( QStringLiteral( "Error creating fields item: %1" ).arg( ex.what() ) );
203  }
204  }
205 }
206 
208 {
209 
210 }
211 
212 QVector<QgsDataItem *> QgsFieldsItem::createChildren()
213 {
214  QVector<QgsDataItem *> children;
215  try
216  {
218  if ( md )
219  {
220  std::unique_ptr<QgsAbstractDatabaseProviderConnection> conn { static_cast<QgsAbstractDatabaseProviderConnection *>( md->createConnection( mConnectionUri, {} ) ) };
221  if ( conn )
222  {
223  int i = 0;
224  const QgsFields constFields { conn->fields( mSchema, mTableName ) };
225  for ( const auto &f : constFields )
226  {
227  QgsFieldItem *fieldItem { new QgsFieldItem( this, f ) };
228  fieldItem->setSortKey( i++ );
229  children.push_back( fieldItem );
230  }
231  }
232  }
233  }
234  catch ( const QgsProviderConnectionException &ex )
235  {
236  children.push_back( new QgsErrorItem( this, ex.what(), path() + QStringLiteral( "/error" ) ) );
237  }
238  return children;
239 }
240 
242 {
243  return QgsApplication::getThemeIcon( QStringLiteral( "mSourceFields.svg" ) );
244 }
245 
247 {
248  return mConnectionUri;
249 }
250 
252 {
253  std::unique_ptr<QgsVectorLayer> vl;
255  if ( md )
256  {
257  try
258  {
259  std::unique_ptr<QgsAbstractDatabaseProviderConnection> conn { static_cast<QgsAbstractDatabaseProviderConnection *>( md->createConnection( mConnectionUri, {} ) ) };
260  if ( conn )
261  {
262  vl.reset( new QgsVectorLayer( conn->tableUri( mSchema, mTableName ), QStringLiteral( "temp_layer" ), providerKey() ) );
263  if ( vl->isValid() )
264  {
265  return vl.release();
266  }
267  }
268  }
269  catch ( const QgsProviderConnectionException & )
270  {
271  // This should never happen!
272  QgsDebugMsg( QStringLiteral( "Error getting connection from %1" ).arg( mConnectionUri ) );
273  }
274  }
275  else
276  {
277  // This should never happen!
278  QgsDebugMsg( QStringLiteral( "Error getting metadata for provider %1" ).arg( providerKey() ) );
279  }
280  return nullptr;
281 }
282 
284 {
285  return mTableProperty.get();
286 }
287 
289 {
290  return mTableName;
291 }
292 
293 QString QgsFieldsItem::schema() const
294 {
295  return mSchema;
296 }
297 
299  : QgsDataItem( QgsDataItem::Type::Field, parent, field.name(), parent->path() + '/' + field.name(), parent->providerKey() )
300  , mField( field )
301 {
302  // Precondition
303  Q_ASSERT( static_cast<QgsFieldsItem *>( parent ) );
304  setState( QgsDataItem::State::Populated );
305 }
306 
308 {
309 }
310 
312 {
313  // Check if this is a geometry column and show the right icon
314  QgsFieldsItem *parentFields { static_cast<QgsFieldsItem *>( parent() ) };
315  if ( parentFields && parentFields->tableProperty() &&
316  parentFields->tableProperty()->geometryColumn() == mName &&
317  parentFields->tableProperty()->geometryColumnTypes().count() )
318  {
319  if ( mField.typeName() == QLatin1String( "raster" ) )
320  {
321  return QgsLayerItem::iconRaster();
322  }
323  const QgsWkbTypes::GeometryType geomType { QgsWkbTypes::geometryType( parentFields->tableProperty()->geometryColumnTypes().first().wkbType ) };
324  switch ( geomType )
325  {
326  case QgsWkbTypes::GeometryType::LineGeometry:
327  return QgsLayerItem::iconLine();
328  case QgsWkbTypes::GeometryType::PointGeometry:
329  return QgsLayerItem::iconPoint();
330  case QgsWkbTypes::GeometryType::PolygonGeometry:
331  return QgsLayerItem::iconPolygon();
332  case QgsWkbTypes::GeometryType::UnknownGeometry:
333  case QgsWkbTypes::GeometryType::NullGeometry:
334  return QgsLayerItem::iconDefault();
335  }
336  }
337  const QIcon icon { QgsFields::iconForFieldType( mField.type() ) };
338  // Try subtype if icon is null
339  if ( icon.isNull() )
340  {
341  return QgsFields::iconForFieldType( mField.subType() );
342  }
343  return icon;
344 }
345 
347 {
348  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconFavorites.svg" ) );
349 }
350 
352 {
353  return QStringLiteral( " 0" );
354 }
355 
357 {
358  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconZip.svg" ) );
359 }
360 
361 QgsAnimatedIcon *QgsDataItem::sPopulatingIcon = nullptr;
362 
363 QgsDataItem::QgsDataItem( QgsDataItem::Type type, QgsDataItem *parent, const QString &name, const QString &path, const QString &providerKey )
364 // Do not pass parent to QObject, Qt would delete this when parent is deleted
365  : mType( type )
366  , mCapabilities( NoCapabilities )
367  , mParent( parent )
368  , mState( NotPopulated )
369  , mName( name )
370  , mProviderKey( providerKey )
371  , mPath( path )
372  , mDeferredDelete( false )
373  , mFutureWatcher( nullptr )
374 {
375 }
376 
378 {
379  QgsDebugMsgLevel( QStringLiteral( "mName = %1 mPath = %2 mChildren.size() = %3" ).arg( mName, mPath ).arg( mChildren.size() ), 2 );
380  const auto constMChildren = mChildren;
381  for ( QgsDataItem *child : constMChildren )
382  {
383  if ( !child ) // should not happen
384  continue;
385  child->deleteLater();
386  }
387  mChildren.clear();
388 
389  if ( mFutureWatcher && !mFutureWatcher->isFinished() )
390  {
391  // this should not usually happen (until the item was deleted directly when createChildren was running)
392  QgsDebugMsg( QStringLiteral( "mFutureWatcher not finished (should not happen) -> waitForFinished()" ) );
393  mDeferredDelete = true;
394  mFutureWatcher->waitForFinished();
395  }
396 
397  delete mFutureWatcher;
398 }
399 
400 QString QgsDataItem::pathComponent( const QString &string )
401 {
402  return QString( string ).replace( QRegExp( "[\\\\/]" ), QStringLiteral( "|" ) );
403 }
404 
405 QVariant QgsDataItem::sortKey() const
406 {
407  return mSortKey.isValid() ? mSortKey : name();
408 }
409 
410 void QgsDataItem::setSortKey( const QVariant &key )
411 {
412  mSortKey = key;
413 }
414 
416 {
417  QgsDebugMsgLevel( "path = " + path(), 3 );
418  setParent( nullptr ); // also disconnects parent
419  const auto constMChildren = mChildren;
420  for ( QgsDataItem *child : constMChildren )
421  {
422  if ( !child ) // should not happen
423  continue;
424  child->deleteLater();
425  }
426  mChildren.clear();
427 
428  if ( mFutureWatcher && !mFutureWatcher->isFinished() )
429  {
430  QgsDebugMsg( QStringLiteral( "mFutureWatcher not finished -> schedule to delete later" ) );
431  mDeferredDelete = true;
432  }
433  else
434  {
435  QObject::deleteLater();
436  }
437 }
438 
439 void QgsDataItem::deleteLater( QVector<QgsDataItem *> &items )
440 {
441  const auto constItems = items;
442  for ( QgsDataItem *item : constItems )
443  {
444  if ( !item ) // should not happen
445  continue;
446  item->deleteLater();
447  }
448  items.clear();
449 }
450 
451 void QgsDataItem::moveToThread( QThread *targetThread )
452 {
453  // QObject::moveToThread() cannot move objects with parent, but QgsDataItem is not using paren/children from QObject
454  const auto constMChildren = mChildren;
455  for ( QgsDataItem *child : constMChildren )
456  {
457  if ( !child ) // should not happen
458  continue;
459  QgsDebugMsgLevel( "moveToThread child " + child->path(), 3 );
460  child->QObject::setParent( nullptr ); // to be sure
461  child->moveToThread( targetThread );
462  }
463  QObject::moveToThread( targetThread );
464 }
465 
467 {
468  return nullptr;
469 }
470 
472 {
473  if ( state() == Populating && sPopulatingIcon )
474  return sPopulatingIcon->icon();
475 
476  if ( !mIcon.isNull() )
477  return mIcon;
478 
479  if ( !mIconMap.contains( mIconName ) )
480  {
481  mIconMap.insert( mIconName, mIconName.startsWith( ':' ) ? QIcon( mIconName ) : QgsApplication::getThemeIcon( mIconName ) );
482  }
483 
484  return mIconMap.value( mIconName );
485 }
486 
487 void QgsDataItem::setName( const QString &name )
488 {
489  mName = name;
490  emit dataChanged( this );
491 }
492 
493 QVector<QgsDataItem *> QgsDataItem::createChildren()
494 {
495  return QVector<QgsDataItem *>();
496 }
497 
498 void QgsDataItem::populate( bool foreground )
499 {
500  if ( state() == Populated || state() == Populating )
501  return;
502 
503  QgsDebugMsgLevel( "mPath = " + mPath, 2 );
504 
505  if ( capabilities2() & QgsDataItem::Fast || foreground )
506  {
508  }
509  else
510  {
511  setState( Populating );
512  // The watcher must not be created with item (in constructor) because the item may be created in thread and the watcher created in thread does not work correctly.
513  if ( !mFutureWatcher )
514  {
515  mFutureWatcher = new QFutureWatcher< QVector <QgsDataItem *> >( this );
516  }
517 
518  connect( mFutureWatcher, &QFutureWatcherBase::finished, this, &QgsDataItem::childrenCreated );
519  mFutureWatcher->setFuture( QtConcurrent::run( runCreateChildren, this ) );
520  }
521 }
522 
523 // This is expected to be run in a separate thread
524 QVector<QgsDataItem *> QgsDataItem::runCreateChildren( QgsDataItem *item )
525 {
526  QgsDebugMsgLevel( "path = " + item->path(), 2 );
527  QElapsedTimer time;
528  time.start();
529  QVector <QgsDataItem *> children = item->createChildren();
530  QgsDebugMsgLevel( QStringLiteral( "%1 children created in %2 ms" ).arg( children.size() ).arg( time.elapsed() ), 3 );
531  // Children objects must be pushed to main thread.
532  const auto constChildren = children;
533  for ( QgsDataItem *child : constChildren )
534  {
535  if ( !child ) // should not happen
536  continue;
537  QgsDebugMsgLevel( "moveToThread child " + child->path(), 2 );
538  if ( qApp )
539  child->moveToThread( qApp->thread() ); // moves also children
540  }
541  QgsDebugMsgLevel( QStringLiteral( "finished path %1: %2 children" ).arg( item->path() ).arg( children.size() ), 3 );
542  return children;
543 }
544 
546 {
547  QgsDebugMsgLevel( QStringLiteral( "path = %1 children.size() = %2" ).arg( path() ).arg( mFutureWatcher->result().size() ), 3 );
548 
549  if ( deferredDelete() )
550  {
551  QgsDebugMsg( QStringLiteral( "Item was scheduled to be deleted later" ) );
552  QObject::deleteLater();
553  return;
554  }
555 
556  if ( mChildren.isEmpty() ) // usually populating but may also be refresh if originally there were no children
557  {
558  populate( mFutureWatcher->result() );
559  }
560  else // refreshing
561  {
562  refresh( mFutureWatcher->result() );
563  }
564  disconnect( mFutureWatcher, &QFutureWatcherBase::finished, this, &QgsDataItem::childrenCreated );
565  emit dataChanged( this ); // to replace loading icon by normal icon
566 }
567 
569 {
570  emit dataChanged( this );
571 }
572 
573 void QgsDataItem::populate( const QVector<QgsDataItem *> &children )
574 {
575  QgsDebugMsgLevel( "mPath = " + mPath, 3 );
576 
577  const auto constChildren = children;
578  for ( QgsDataItem *child : constChildren )
579  {
580  if ( !child ) // should not happen
581  continue;
582  // update after thread finished -> refresh
583  addChildItem( child, true );
584  }
585  setState( Populated );
586 }
587 
589 {
590  QgsDebugMsgLevel( "mPath = " + mPath, 3 );
591 
592  const auto constMChildren = mChildren;
593  for ( QgsDataItem *child : constMChildren )
594  {
595  QgsDebugMsgLevel( "remove " + child->path(), 3 );
596  child->depopulate(); // recursive
597  deleteChildItem( child );
598  }
600 }
601 
603 {
604  if ( state() == Populating )
605  return;
606 
607  QgsDebugMsgLevel( "mPath = " + mPath, 3 );
608 
610  {
611  refresh( createChildren() );
612  }
613  else
614  {
615  setState( Populating );
616  if ( !mFutureWatcher )
617  {
618  mFutureWatcher = new QFutureWatcher< QVector <QgsDataItem *> >( this );
619  }
620  connect( mFutureWatcher, &QFutureWatcherBase::finished, this, &QgsDataItem::childrenCreated );
621  mFutureWatcher->setFuture( QtConcurrent::run( runCreateChildren, this ) );
622  }
623 }
624 
625 void QgsDataItem::refreshConnections( const QString &key )
626 {
627  // Walk up until the root node is reached
628  if ( mParent )
629  {
630  mParent->refreshConnections( key );
631  }
632  else
633  {
634  // if a specific key was specified then we use that -- otherwise we assume the connections
635  // changed belong to the same provider as this item
636  emit connectionsChanged( key.isEmpty() ? providerKey() : key );
637  }
638 }
639 
640 void QgsDataItem::refresh( const QVector<QgsDataItem *> &children )
641 {
642  QgsDebugMsgLevel( "mPath = " + mPath, 2 );
643 
644  // Remove no more present children
645  QVector<QgsDataItem *> remove;
646  const auto constMChildren = mChildren;
647  for ( QgsDataItem *child : constMChildren )
648  {
649  if ( !child ) // should not happen
650  continue;
651  if ( findItem( children, child ) >= 0 )
652  continue;
653  remove.append( child );
654  }
655  const auto constRemove = remove;
656  for ( QgsDataItem *child : constRemove )
657  {
658  QgsDebugMsgLevel( "remove " + child->path(), 3 );
659  deleteChildItem( child );
660  }
661 
662  // Add new children
663  const auto constChildren = children;
664  for ( QgsDataItem *child : constChildren )
665  {
666  if ( !child ) // should not happen
667  continue;
668 
669  int index = findItem( mChildren, child );
670  if ( index >= 0 )
671  {
672  // Refresh recursively (some providers may create more generations of descendants)
673  if ( !( child->capabilities2() & QgsDataItem::Fertile ) )
674  {
675  // The child cannot createChildren() itself
676  mChildren.value( index )->refresh( child->children() );
677  }
678 
679  child->deleteLater();
680  continue;
681  }
682  addChildItem( child, true );
683  }
684  setState( Populated );
685 }
686 
688 {
689  return mProviderKey;
690 }
691 
692 void QgsDataItem::setProviderKey( const QString &value )
693 {
694  mProviderKey = value;
695 }
696 
698 {
699  return mChildren.size();
700 }
702 {
703  return ( state() == Populated ? !mChildren.isEmpty() : true );
704 }
705 
707 {
708  return false;
709 }
710 
712 {
713  if ( mParent )
714  {
715  disconnect( this, nullptr, mParent, nullptr );
716  }
717  if ( parent )
718  {
725  }
726  mParent = parent;
727 }
728 
729 void QgsDataItem::addChildItem( QgsDataItem *child, bool refresh )
730 {
731  Q_ASSERT( child );
732  QgsDebugMsgLevel( QStringLiteral( "path = %1 add child #%2 - %3 - %4" ).arg( mPath ).arg( mChildren.size() ).arg( child->mName ).arg( child->mType ), 3 );
733 
734  //calculate position to insert child
735  int i;
736  if ( type() == Directory )
737  {
738  for ( i = 0; i < mChildren.size(); i++ )
739  {
740  // sort items by type, so directories are before data items
741  if ( mChildren.at( i )->mType == child->mType &&
742  mChildren.at( i )->mName.localeAwareCompare( child->mName ) > 0 )
743  break;
744  }
745  }
746  else
747  {
748  for ( i = 0; i < mChildren.size(); i++ )
749  {
750  if ( mChildren.at( i )->mName.localeAwareCompare( child->mName ) >= 0 )
751  break;
752  }
753  }
754 
755  if ( refresh )
756  emit beginInsertItems( this, i, i );
757 
758  mChildren.insert( i, child );
759  child->setParent( this );
760 
761  if ( refresh )
762  emit endInsertItems();
763 }
764 
766 {
767  QgsDebugMsgLevel( "mName = " + child->mName, 2 );
768  int i = mChildren.indexOf( child );
769  Q_ASSERT( i >= 0 );
770  emit beginRemoveItems( this, i, i );
771  mChildren.remove( i );
772  child->deleteLater();
773  emit endRemoveItems();
774 }
775 
777 {
778  QgsDebugMsgLevel( "mName = " + child->mName, 2 );
779  int i = mChildren.indexOf( child );
780  Q_ASSERT( i >= 0 );
781  if ( i < 0 )
782  {
783  child->setParent( nullptr );
784  return nullptr;
785  }
786 
787  emit beginRemoveItems( this, i, i );
788  mChildren.remove( i );
789  emit endRemoveItems();
790  return child;
791 }
792 
793 int QgsDataItem::findItem( QVector<QgsDataItem *> items, QgsDataItem *item )
794 {
795  for ( int i = 0; i < items.size(); i++ )
796  {
797  Q_ASSERT_X( items[i], "findItem", QStringLiteral( "item %1 is nullptr" ).arg( i ).toLatin1() );
798  QgsDebugMsgLevel( QString::number( i ) + " : " + items[i]->mPath + " x " + item->mPath, 2 );
799  if ( items[i]->equal( item ) )
800  return i;
801  }
802  return -1;
803 }
804 
805 bool QgsDataItem::equal( const QgsDataItem *other )
806 {
807  return ( metaObject()->className() == other->metaObject()->className() &&
808  mPath == other->path() );
809 }
810 
811 QList<QAction *> QgsDataItem::actions( QWidget *parent )
812 {
813  Q_UNUSED( parent )
814  return QList<QAction *>();
815 }
816 
818 {
819  return false;
820 }
821 
823 {
824  return mimeUris().isEmpty() ? QgsMimeDataUtils::Uri() : mimeUris().first();
825 }
826 
827 bool QgsDataItem::rename( const QString & )
828 {
829  return false;
830 }
831 
833 {
834  return mState;
835 }
836 
838 {
839  QgsDebugMsgLevel( QStringLiteral( "item %1 set state %2 -> %3" ).arg( path() ).arg( this->state() ).arg( state ), 3 );
840  if ( state == mState )
841  return;
842 
843  State oldState = mState;
844 
845  if ( state == Populating ) // start loading
846  {
847  if ( !sPopulatingIcon )
848  {
849  // TODO: ensure that QgsAnimatedIcon is created on UI thread only
850  sPopulatingIcon = new QgsAnimatedIcon( QgsApplication::iconPath( QStringLiteral( "/mIconLoading.gif" ) ), QgsApplication::instance() );
851  }
852 
853  sPopulatingIcon->connectFrameChanged( this, &QgsDataItem::updateIcon );
854  }
855  else if ( mState == Populating && sPopulatingIcon ) // stop loading
856  {
857  sPopulatingIcon->disconnectFrameChanged( this, &QgsDataItem::updateIcon );
858  }
859 
860 
861  mState = state;
862 
863  emit stateChanged( this, oldState );
864  if ( state == Populated )
865  updateIcon();
866 }
867 
868 QList<QMenu *> QgsDataItem::menus( QWidget *parent )
869 {
870  Q_UNUSED( parent )
871  return QList<QMenu *>();
872 }
873 
874 // ---------------------------------------------------------------------
875 
876 QgsLayerItem::QgsLayerItem( QgsDataItem *parent, const QString &name, const QString &path,
877  const QString &uri, LayerType layerType, const QString &providerKey )
878  : QgsDataItem( Layer, parent, name, path, providerKey )
879  , mUri( uri )
880  , mLayerType( layerType )
881 {
882  mIconName = iconName( layerType );
883 }
884 
886 {
887  switch ( mLayerType )
888  {
891 
892  case QgsLayerItem::Mesh:
894 
897 
900 
903 
906  case QgsLayerItem::Point:
908  case QgsLayerItem::Line:
910  case QgsLayerItem::Table:
913  }
914 
915  return QgsMapLayerType::VectorLayer; // no warnings
916 }
917 
919 {
920  switch ( layer->type() )
921  {
923  {
924  switch ( qobject_cast< QgsVectorLayer * >( layer )->geometryType() )
925  {
927  return Point;
928 
930  return Line;
931 
933  return Polygon;
934 
936  return TableLayer;
937 
939  return Vector;
940  }
941 
942  return Vector; // no warnings
943  }
944 
946  return Raster;
948  return Plugin;
950  return Mesh;
952  return PointCloud;
954  return VectorTile;
956  return Vector; // will never happen!
957  }
958  return Vector; // no warnings
959 }
960 
962 {
963  static int enumIdx = staticMetaObject.indexOfEnumerator( "LayerType" );
964  return staticMetaObject.enumerator( enumIdx ).valueToKey( layerType );
965 }
966 
968 {
969  switch ( layerType )
970  {
971  case Point:
972  return QStringLiteral( "/mIconPointLayer.svg" );
973  case Line:
974  return QStringLiteral( "/mIconLineLayer.svg" );
975  case Polygon:
976  return QStringLiteral( "/mIconPolygonLayer.svg" );
977  // TODO add a new icon for generic Vector layers
978  case Vector :
979  return QStringLiteral( "/mIconVector.svg" );
980  case TableLayer:
981  case Table:
982  return QStringLiteral( "/mIconTableLayer.svg" );
983  case Raster:
984  return QStringLiteral( "/mIconRaster.svg" );
985  case Mesh:
986  return QStringLiteral( "/mIconMeshLayer.svg" );
987  case PointCloud:
988  return QStringLiteral( "/mIconPointCloudLayer.svg" );
989  default:
990  return QStringLiteral( "/mIconLayer.png" );
991  }
992 }
993 
995 {
996  return false;
997 }
998 
999 bool QgsLayerItem::equal( const QgsDataItem *other )
1000 {
1001  //QgsDebugMsg ( mPath + " x " + other->mPath );
1002  if ( type() != other->type() )
1003  {
1004  return false;
1005  }
1006  //const QgsLayerItem *o = qobject_cast<const QgsLayerItem *> ( other );
1007  const QgsLayerItem *o = qobject_cast<const QgsLayerItem *>( other );
1008  if ( !o )
1009  return false;
1010 
1011  return ( mPath == o->mPath && mName == o->mName && mUri == o->mUri && mProviderKey == o->mProviderKey );
1012 }
1013 
1015 {
1017 
1018  switch ( mapLayerType() )
1019  {
1021  u.layerType = QStringLiteral( "vector" );
1022  switch ( mLayerType )
1023  {
1024  case Point:
1026  break;
1027  case Line:
1029  break;
1030  case Polygon:
1032  break;
1033  case TableLayer:
1035  break;
1036 
1037  case Database:
1038  case Table:
1039  case NoType:
1040  case Vector:
1041  case Raster:
1042  case Plugin:
1043  case Mesh:
1044  case PointCloud:
1045  case VectorTile:
1046  break;
1047  }
1048  break;
1050  u.layerType = QStringLiteral( "raster" );
1051  break;
1053  u.layerType = QStringLiteral( "mesh" );
1054  break;
1056  u.layerType = QStringLiteral( "vector-tile" );
1057  break;
1059  u.layerType = QStringLiteral( "pointcloud" );
1060  break;
1062  u.layerType = QStringLiteral( "plugin" );
1063  break;
1065  u.layerType = QStringLiteral( "annotation" );
1066  break;
1067  }
1068 
1069  u.providerKey = providerKey();
1070  u.name = layerName();
1071  u.uri = uri();
1072  u.supportedCrs = supportedCrs();
1074  return { u };
1075 }
1076 
1077 // ---------------------------------------------------------------------
1079  const QString &name,
1080  const QString &path,
1081  const QString &providerKey )
1082  : QgsDataItem( Collection, parent, name, path, providerKey )
1083 {
1085  mIconName = QStringLiteral( "/mIconDbSchema.svg" );
1086 }
1087 
1089 {
1090  QgsDebugMsgLevel( "mName = " + mName + " mPath = " + mPath, 2 );
1091 
1092 // Do not delete children, children are deleted by QObject parent
1093 #if 0
1094  const auto constMChildren = mChildren;
1095  for ( QgsDataItem *i : constMChildren )
1096  {
1097  QgsDebugMsgLevel( QStringLiteral( "delete child = 0x%0" ).arg( static_cast<qlonglong>( i ), 8, 16, QLatin1Char( '0' ) ), 2 );
1098  delete i;
1099  }
1100 #endif
1101 }
1102 
1103 //-----------------------------------------------------------------------
1104 
1105 QgsDirectoryItem::QgsDirectoryItem( QgsDataItem *parent, const QString &name, const QString &path )
1106  : QgsDataCollectionItem( parent, QDir::toNativeSeparators( name ), path )
1107  , mDirPath( path )
1108  , mRefreshLater( false )
1109 {
1110  mType = Directory;
1111  init();
1112 }
1113 
1114 QgsDirectoryItem::QgsDirectoryItem( QgsDataItem *parent, const QString &name,
1115  const QString &dirPath, const QString &path,
1116  const QString &providerKey )
1117  : QgsDataCollectionItem( parent, QDir::toNativeSeparators( name ), path, providerKey )
1118  , mDirPath( dirPath )
1119  , mRefreshLater( false )
1120 {
1121  mType = Directory;
1122  init();
1123 }
1124 
1126 {
1127  setToolTip( QDir::toNativeSeparators( mDirPath ) );
1128 }
1129 
1131 {
1132  if ( mDirPath == QDir::homePath() )
1133  return homeDirIcon();
1134 
1135  // still loading? show the spinner
1136  if ( state() == Populating )
1137  return QgsDataItem::icon();
1138 
1139  // symbolic link? use link icon
1140  QFileInfo fi( mDirPath );
1141  if ( fi.isDir() && fi.isSymLink() )
1142  {
1143  return QgsApplication::getThemeIcon( QStringLiteral( "mIconFolderLink.svg" ) );
1144  }
1145 
1146  // loaded? show the open dir icon
1147  if ( state() == Populated )
1148  return openDirIcon();
1149 
1150  // show the closed dir icon
1151  return iconDir();
1152 }
1153 
1154 
1155 QVector<QgsDataItem *> QgsDirectoryItem::createChildren()
1156 {
1157  QVector<QgsDataItem *> children;
1158  QDir dir( mDirPath );
1159 
1160  const QList<QgsDataItemProvider *> providers = QgsApplication::dataItemProviderRegistry()->providers();
1161 
1162  QStringList entries = dir.entryList( QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name | QDir::IgnoreCase );
1163  const auto constEntries = entries;
1164  for ( const QString &subdir : constEntries )
1165  {
1166  if ( mRefreshLater )
1167  {
1168  deleteLater( children );
1169  return children;
1170  }
1171 
1172  QString subdirPath = dir.absoluteFilePath( subdir );
1173 
1174  QgsDebugMsgLevel( QStringLiteral( "creating subdir: %1" ).arg( subdirPath ), 2 );
1175 
1176  QString path = mPath + '/' + subdir; // may differ from subdirPath
1178  continue;
1179 
1180  bool handledByProvider = false;
1181  for ( QgsDataItemProvider *provider : providers )
1182  {
1183  if ( provider->handlesDirectoryPath( path ) )
1184  {
1185  handledByProvider = true;
1186  break;
1187  }
1188  }
1189  if ( handledByProvider )
1190  continue;
1191 
1192  QgsDirectoryItem *item = new QgsDirectoryItem( this, subdir, subdirPath, path );
1193 
1194  // we want directories shown before files
1195  item->setSortKey( QStringLiteral( " %1" ).arg( subdir ) );
1196 
1197  // propagate signals up to top
1198 
1199  children.append( item );
1200  }
1201 
1202  QStringList fileEntries = dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot | QDir::Files, QDir::Name );
1203  const auto constFileEntries = fileEntries;
1204  for ( const QString &name : constFileEntries )
1205  {
1206  if ( mRefreshLater )
1207  {
1208  deleteLater( children );
1209  return children;
1210  }
1211 
1212  QString path = dir.absoluteFilePath( name );
1213  QFileInfo fileInfo( path );
1214 
1215  if ( fileInfo.suffix().compare( QLatin1String( "zip" ), Qt::CaseInsensitive ) == 0 ||
1216  fileInfo.suffix().compare( QLatin1String( "tar" ), Qt::CaseInsensitive ) == 0 )
1217  {
1218  QgsDataItem *item = QgsZipItem::itemFromPath( this, path, name, mPath + '/' + name );
1219  if ( item )
1220  {
1221  children.append( item );
1222  continue;
1223  }
1224  }
1225 
1226  bool createdItem = false;
1227  for ( QgsDataItemProvider *provider : providers )
1228  {
1229  int capabilities = provider->capabilities();
1230 
1231  if ( !( ( fileInfo.isFile() && ( capabilities & QgsDataProvider::File ) ) ||
1232  ( fileInfo.isDir() && ( capabilities & QgsDataProvider::Dir ) ) ) )
1233  {
1234  continue;
1235  }
1236 
1237  QgsDataItem *item = provider->createDataItem( path, this );
1238  if ( item )
1239  {
1240  children.append( item );
1241  createdItem = true;
1242  }
1243  }
1244 
1245  if ( !createdItem )
1246  {
1247  // if item is a QGIS project, and no specific item provider has overridden handling of
1248  // project items, then use the default project item behavior
1249  if ( fileInfo.suffix().compare( QLatin1String( "qgs" ), Qt::CaseInsensitive ) == 0 ||
1250  fileInfo.suffix().compare( QLatin1String( "qgz" ), Qt::CaseInsensitive ) == 0 )
1251  {
1252  QgsDataItem *item = new QgsProjectItem( this, fileInfo.completeBaseName(), path );
1253  children.append( item );
1254  continue;
1255  }
1256  }
1257 
1258  }
1259  return children;
1260 }
1261 
1263 {
1265 
1266  if ( state == Populated )
1267  {
1268  if ( !mFileSystemWatcher )
1269  {
1270  mFileSystemWatcher = new QFileSystemWatcher( this );
1271  mFileSystemWatcher->addPath( mDirPath );
1272  connect( mFileSystemWatcher, &QFileSystemWatcher::directoryChanged, this, &QgsDirectoryItem::directoryChanged );
1273  }
1274  mLastScan = QDateTime::currentDateTime();
1275  }
1276  else if ( state == NotPopulated )
1277  {
1278  if ( mFileSystemWatcher )
1279  {
1280  delete mFileSystemWatcher;
1281  mFileSystemWatcher = nullptr;
1282  }
1283  }
1284 }
1285 
1287 {
1288  // If the last scan was less than 10 seconds ago, skip this
1289  if ( mLastScan.msecsTo( QDateTime::currentDateTime() ) < QgsSettings().value( QStringLiteral( "browser/minscaninterval" ), 10000 ).toInt() )
1290  {
1291  return;
1292  }
1293  if ( state() == Populating )
1294  {
1295  // schedule to refresh later, because refresh() simply returns if Populating
1296  mRefreshLater = true;
1297  }
1298  else
1299  {
1300  // We definintely don't want the temporary files created by sqlite
1301  // to re-trigger a refresh in an infinite loop.
1302  disconnect( mFileSystemWatcher, &QFileSystemWatcher::directoryChanged, this, &QgsDirectoryItem::directoryChanged );
1303  // QFileSystemWhatcher::directoryChanged is emitted when a
1304  // file is created and not when it is closed/flushed.
1305  //
1306  // Delay to give to OS the time to complete writing the file
1307  // this happens when a new file appears in the directory and
1308  // the item's children thread will try to open the file with
1309  // GDAL or OGR even if it is still being written.
1310  QTimer::singleShot( 100, this, [ = ] { refresh(); } );
1311  }
1312 }
1313 
1314 bool QgsDirectoryItem::hiddenPath( const QString &path )
1315 {
1316  QgsSettings settings;
1317  QStringList hiddenItems = settings.value( QStringLiteral( "browser/hiddenPaths" ),
1318  QStringList() ).toStringList();
1319  int idx = hiddenItems.indexOf( path );
1320  return ( idx > -1 );
1321 }
1322 
1324 {
1325  QgsDebugMsgLevel( QStringLiteral( "mRefreshLater = %1" ).arg( mRefreshLater ), 3 );
1326 
1327  if ( mRefreshLater )
1328  {
1329  QgsDebugMsgLevel( QStringLiteral( "directory changed during createChidren() -> refresh() again" ), 3 );
1330  mRefreshLater = false;
1331  setState( Populated );
1332  refresh();
1333  }
1334  else
1335  {
1337  }
1338  // Re-connect the file watcher after all children have been created
1339  connect( mFileSystemWatcher, &QFileSystemWatcher::directoryChanged, this, &QgsDirectoryItem::directoryChanged );
1340 }
1341 
1343 {
1344  //QgsDebugMsg ( mPath + " x " + other->mPath );
1345  if ( type() != other->type() )
1346  {
1347  return false;
1348  }
1349  return ( path() == other->path() );
1350 }
1351 
1353 {
1354  return new QgsDirectoryParamWidget( mPath );
1355 }
1356 
1358 {
1360  u.layerType = QStringLiteral( "directory" );
1361  u.name = mName;
1362  u.uri = mDirPath;
1363  return { u };
1364 }
1365 
1366 QgsDirectoryParamWidget::QgsDirectoryParamWidget( const QString &path, QWidget *parent )
1367  : QTreeWidget( parent )
1368 {
1369  setRootIsDecorated( false );
1370 
1371  // name, size, date, permissions, owner, group, type
1372  setColumnCount( 7 );
1373  QStringList labels;
1374  labels << tr( "Name" ) << tr( "Size" ) << tr( "Date" ) << tr( "Permissions" ) << tr( "Owner" ) << tr( "Group" ) << tr( "Type" );
1375  setHeaderLabels( labels );
1376 
1377  QIcon iconDirectory = QgsApplication::getThemeIcon( QStringLiteral( "mIconFolder.svg" ) );
1378  QIcon iconFile = QgsApplication::getThemeIcon( QStringLiteral( "mIconFile.svg" ) );
1379  QIcon iconDirLink = QgsApplication::getThemeIcon( QStringLiteral( "mIconFolderLink.svg" ) );
1380  QIcon iconFileLink = QgsApplication::getThemeIcon( QStringLiteral( "mIconFileLink.svg" ) );
1381 
1382  QList<QTreeWidgetItem *> items;
1383 
1384  QDir dir( path );
1385  QStringList entries = dir.entryList( QDir::AllEntries | QDir::NoDotAndDotDot, QDir::Name | QDir::IgnoreCase );
1386  const auto constEntries = entries;
1387  for ( const QString &name : constEntries )
1388  {
1389  QFileInfo fi( dir.absoluteFilePath( name ) );
1390  QStringList texts;
1391  texts << name;
1392  QString size;
1393  if ( fi.size() > 1024 )
1394  {
1395  size = QStringLiteral( "%1 KiB" ).arg( QString::number( fi.size() / 1024.0, 'f', 1 ) );
1396  }
1397  else if ( fi.size() > 1.048576e6 )
1398  {
1399  size = QStringLiteral( "%1 MiB" ).arg( QString::number( fi.size() / 1.048576e6, 'f', 1 ) );
1400  }
1401  else
1402  {
1403  size = QStringLiteral( "%1 B" ).arg( fi.size() );
1404  }
1405  texts << size;
1406  texts << QLocale().toString( fi.lastModified(), QLocale::ShortFormat );
1407  QString perm;
1408  perm += fi.permission( QFile::ReadOwner ) ? 'r' : '-';
1409  perm += fi.permission( QFile::WriteOwner ) ? 'w' : '-';
1410  perm += fi.permission( QFile::ExeOwner ) ? 'x' : '-';
1411  // QFile::ReadUser, QFile::WriteUser, QFile::ExeUser
1412  perm += fi.permission( QFile::ReadGroup ) ? 'r' : '-';
1413  perm += fi.permission( QFile::WriteGroup ) ? 'w' : '-';
1414  perm += fi.permission( QFile::ExeGroup ) ? 'x' : '-';
1415  perm += fi.permission( QFile::ReadOther ) ? 'r' : '-';
1416  perm += fi.permission( QFile::WriteOther ) ? 'w' : '-';
1417  perm += fi.permission( QFile::ExeOther ) ? 'x' : '-';
1418  texts << perm;
1419 
1420  texts << fi.owner();
1421  texts << fi.group();
1422 
1423  QString type;
1424  QIcon icon;
1425  if ( fi.isDir() && fi.isSymLink() )
1426  {
1427  type = tr( "folder" );
1428  icon = iconDirLink;
1429  }
1430  else if ( fi.isDir() )
1431  {
1432  type = tr( "folder" );
1433  icon = iconDirectory;
1434  }
1435  else if ( fi.isFile() && fi.isSymLink() )
1436  {
1437  type = tr( "file" );
1438  icon = iconFileLink;
1439  }
1440  else if ( fi.isFile() )
1441  {
1442  type = tr( "file" );
1443  icon = iconFile;
1444  }
1445 
1446  texts << type;
1447 
1448  QTreeWidgetItem *item = new QTreeWidgetItem( texts );
1449  item->setIcon( 0, icon );
1450  items << item;
1451  }
1452 
1453  addTopLevelItems( items );
1454 
1455  // hide columns that are not requested
1456  QgsSettings settings;
1457  QList<QVariant> lst = settings.value( QStringLiteral( "dataitem/directoryHiddenColumns" ) ).toList();
1458  const auto constLst = lst;
1459  for ( const QVariant &colVariant : constLst )
1460  {
1461  setColumnHidden( colVariant.toInt(), true );
1462  }
1463 }
1464 
1466 {
1467  if ( event->button() == Qt::RightButton )
1468  {
1469  // show the popup menu
1470  QMenu popupMenu;
1471 
1472  QStringList labels;
1473  labels << tr( "Name" ) << tr( "Size" ) << tr( "Date" ) << tr( "Permissions" ) << tr( "Owner" ) << tr( "Group" ) << tr( "Type" );
1474  for ( int i = 0; i < labels.count(); i++ )
1475  {
1476  QAction *action = popupMenu.addAction( labels[i], this, &QgsDirectoryParamWidget::showHideColumn );
1477  action->setObjectName( QString::number( i ) );
1478  action->setCheckable( true );
1479  action->setChecked( !isColumnHidden( i ) );
1480  }
1481 
1482  popupMenu.exec( event->globalPos() );
1483  }
1484 }
1485 
1487 {
1488  QAction *action = qobject_cast<QAction *>( sender() );
1489  if ( !action )
1490  return; // something is wrong
1491 
1492  int columnIndex = action->objectName().toInt();
1493  setColumnHidden( columnIndex, !isColumnHidden( columnIndex ) );
1494 
1495  // save in settings
1496  QgsSettings settings;
1497  QList<QVariant> lst;
1498  for ( int i = 0; i < columnCount(); i++ )
1499  {
1500  if ( isColumnHidden( i ) )
1501  lst.append( QVariant( i ) );
1502  }
1503  settings.setValue( QStringLiteral( "dataitem/directoryHiddenColumns" ), lst );
1504 }
1505 
1506 QgsProjectItem::QgsProjectItem( QgsDataItem *parent, const QString &name,
1507  const QString &path, const QString &providerKey )
1508  : QgsDataItem( QgsDataItem::Project, parent, name, path, providerKey )
1509 {
1510  mIconName = QStringLiteral( ":/images/icons/qgis_icon.svg" );
1511  setToolTip( QDir::toNativeSeparators( path ) );
1512  setState( Populated ); // no more children
1513 }
1514 
1516 {
1518  u.layerType = QStringLiteral( "project" );
1519  u.name = mName;
1520  u.uri = mPath;
1521  return { u };
1522 }
1523 
1524 QgsErrorItem::QgsErrorItem( QgsDataItem *parent, const QString &error, const QString &path )
1525  : QgsDataItem( QgsDataItem::Error, parent, error, path )
1526 {
1527  mIconName = QStringLiteral( "/mIconDelete.svg" );
1528 
1529  setState( Populated ); // no more children
1530 }
1531 
1532 QgsFavoritesItem::QgsFavoritesItem( QgsDataItem *parent, const QString &name, const QString &path )
1533  : QgsDataCollectionItem( parent, name, QStringLiteral( "favorites:" ), QStringLiteral( "special:Favorites" ) )
1534 {
1535  Q_UNUSED( path )
1536  mCapabilities |= Fast;
1537  mType = Favorites;
1538  mIconName = QStringLiteral( "/mIconFavorites.svg" );
1539  populate();
1540 }
1541 
1542 QVector<QgsDataItem *> QgsFavoritesItem::createChildren()
1543 {
1544  QVector<QgsDataItem *> children;
1545 
1546  QgsSettings settings;
1547 
1548  const QStringList favDirs = settings.value( QStringLiteral( "browser/favourites" ), QVariant() ).toStringList();
1549 
1550  for ( const QString &favDir : favDirs )
1551  {
1552  QStringList parts = favDir.split( QStringLiteral( "|||" ) );
1553  if ( parts.empty() )
1554  continue;
1555 
1556  QString dir = parts.at( 0 );
1557  QString name = dir;
1558  if ( parts.count() > 1 )
1559  name = parts.at( 1 );
1560 
1561  children << createChildren( dir, name );
1562  }
1563 
1564  return children;
1565 }
1566 
1567 void QgsFavoritesItem::addDirectory( const QString &favDir, const QString &n )
1568 {
1569  QString name = n.isEmpty() ? favDir : n;
1570 
1571  QgsSettings settings;
1572  QStringList favDirs = settings.value( QStringLiteral( "browser/favourites" ) ).toStringList();
1573  favDirs.append( QStringLiteral( "%1|||%2" ).arg( favDir, name ) );
1574  settings.setValue( QStringLiteral( "browser/favourites" ), favDirs );
1575 
1576  if ( state() == Populated )
1577  {
1578  QVector<QgsDataItem *> items = createChildren( favDir, name );
1579  const auto constItems = items;
1580  for ( QgsDataItem *item : constItems )
1581  {
1582  addChildItem( item, true );
1583  }
1584  }
1585 }
1586 
1588 {
1589  if ( !item )
1590  return;
1591 
1592  QgsSettings settings;
1593  QStringList favDirs = settings.value( QStringLiteral( "browser/favourites" ) ).toStringList();
1594  for ( int i = favDirs.count() - 1; i >= 0; --i )
1595  {
1596  QStringList parts = favDirs.at( i ).split( QStringLiteral( "|||" ) );
1597  if ( parts.empty() )
1598  continue;
1599 
1600  QString dir = parts.at( 0 );
1601  if ( dir == item->dirPath() )
1602  favDirs.removeAt( i );
1603  }
1604  settings.setValue( QStringLiteral( "browser/favourites" ), favDirs );
1605 
1606  int idx = findItem( mChildren, item );
1607  if ( idx < 0 )
1608  {
1609  QgsDebugMsg( QStringLiteral( "favorites item %1 not found" ).arg( item->path() ) );
1610  return;
1611  }
1612 
1613  if ( state() == Populated )
1614  deleteChildItem( mChildren.at( idx ) );
1615 }
1616 
1617 void QgsFavoritesItem::renameFavorite( const QString &path, const QString &name )
1618 {
1619  // update stored name
1620  QgsSettings settings;
1621  QStringList favDirs = settings.value( QStringLiteral( "browser/favourites" ) ).toStringList();
1622  for ( int i = 0; i < favDirs.count(); ++i )
1623  {
1624  QStringList parts = favDirs.at( i ).split( QStringLiteral( "|||" ) );
1625  if ( parts.empty() )
1626  continue;
1627 
1628  QString dir = parts.at( 0 );
1629  if ( dir == path )
1630  {
1631  favDirs[i] = QStringLiteral( "%1|||%2" ).arg( path, name );
1632  break;
1633  }
1634  }
1635  settings.setValue( QStringLiteral( "browser/favourites" ), favDirs );
1636 
1637  // also update existing data item
1638  const QVector<QgsDataItem *> ch = children();
1639  for ( QgsDataItem *child : ch )
1640  {
1641  if ( QgsFavoriteItem *favorite = qobject_cast< QgsFavoriteItem * >( child ) )
1642  {
1643  if ( favorite->dirPath() == path )
1644  {
1645  favorite->setName( name );
1646  break;
1647  }
1648  }
1649  }
1650 }
1651 
1652 QVector<QgsDataItem *> QgsFavoritesItem::createChildren( const QString &favDir, const QString &name )
1653 {
1654  QVector<QgsDataItem *> children;
1655  QString pathName = pathComponent( favDir );
1656  const auto constProviders = QgsApplication::dataItemProviderRegistry()->providers();
1657  for ( QgsDataItemProvider *provider : constProviders )
1658  {
1659  int capabilities = provider->capabilities();
1660 
1661  if ( capabilities & QgsDataProvider::Dir )
1662  {
1663  QgsDataItem *item = provider->createDataItem( favDir, this );
1664  if ( item )
1665  {
1666  item->setName( name );
1667  children.append( item );
1668  }
1669  }
1670  }
1671  if ( children.isEmpty() )
1672  {
1673  QgsFavoriteItem *item = new QgsFavoriteItem( this, name, favDir, mPath + '/' + pathName );
1674  if ( item )
1675  {
1676  children.append( item );
1677  }
1678  }
1679  return children;
1680 }
1681 
1682 //-----------------------------------------------------------------------
1683 QStringList QgsZipItem::sProviderNames = QStringList();
1684 
1685 
1686 QgsZipItem::QgsZipItem( QgsDataItem *parent, const QString &name, const QString &path )
1687  : QgsDataCollectionItem( parent, name, path )
1688 {
1689  mFilePath = path;
1690  init();
1691 }
1692 
1693 QgsZipItem::QgsZipItem( QgsDataItem *parent, const QString &name,
1694  const QString &filePath, const QString &path,
1695  const QString &providerKey )
1696  : QgsDataCollectionItem( parent, name, path, providerKey )
1697  , mFilePath( filePath )
1698 {
1699  init();
1700 }
1701 
1702 void QgsZipItem::init()
1703 {
1704  mType = Collection; //Zip??
1705  mIconName = QStringLiteral( "/mIconZip.svg" );
1707 
1708  static std::once_flag initialized;
1709  std::call_once( initialized, [ = ]
1710  {
1711  sProviderNames << QStringLiteral( "OGR" ) << QStringLiteral( "GDAL" );
1712  } );
1713 }
1714 
1715 QVector<QgsDataItem *> QgsZipItem::createChildren()
1716 {
1717  QVector<QgsDataItem *> children;
1718  QString tmpPath;
1719  QgsSettings settings;
1720  QString scanZipSetting = settings.value( QStringLiteral( "qgis/scanZipInBrowser2" ), "basic" ).toString();
1721 
1722  mZipFileList.clear();
1723 
1724  QgsDebugMsgLevel( QStringLiteral( "mFilePath = %1 path = %2 name= %3 scanZipSetting= %4 vsiPrefix= %5" ).arg( mFilePath, path(), name(), scanZipSetting, mVsiPrefix ), 3 );
1725 
1726  // if scanZipBrowser == no: skip to the next file
1727  if ( scanZipSetting == QLatin1String( "no" ) )
1728  {
1729  return children;
1730  }
1731 
1732  // first get list of files
1733  getZipFileList();
1734 
1735  const QList<QgsDataItemProvider *> providers = QgsApplication::dataItemProviderRegistry()->providers();
1736 
1737  // loop over files inside zip
1738  const auto constMZipFileList = mZipFileList;
1739  for ( const QString &fileName : constMZipFileList )
1740  {
1741  QFileInfo info( fileName );
1742  tmpPath = mVsiPrefix + mFilePath + '/' + fileName;
1743  QgsDebugMsgLevel( "tmpPath = " + tmpPath, 3 );
1744 
1745  for ( QgsDataItemProvider *provider : providers )
1746  {
1747  if ( !sProviderNames.contains( provider->name() ) )
1748  continue;
1749 
1750  // ugly hack to remove .dbf file if there is a .shp file
1751  if ( provider->name() == QLatin1String( "OGR" ) )
1752  {
1753  if ( info.suffix().compare( QLatin1String( "dbf" ), Qt::CaseInsensitive ) == 0 )
1754  {
1755  if ( mZipFileList.indexOf( fileName.left( fileName.count() - 4 ) + ".shp" ) != -1 )
1756  continue;
1757  }
1758  if ( info.completeSuffix().compare( QLatin1String( "shp.xml" ), Qt::CaseInsensitive ) == 0 )
1759  {
1760  continue;
1761  }
1762  }
1763 
1764  QgsDebugMsgLevel( QStringLiteral( "trying to load item %1 with %2" ).arg( tmpPath, provider->name() ), 3 );
1765  QgsDataItem *item = provider->createDataItem( tmpPath, this );
1766  if ( item )
1767  {
1768  // the item comes with zipped file name, set the name to relative path within zip file
1769  item->setName( fileName );
1770  children.append( item );
1771  }
1772  else
1773  {
1774  QgsDebugMsgLevel( QStringLiteral( "not loaded item" ), 3 );
1775  }
1776  }
1777  }
1778 
1779  return children;
1780 }
1781 
1782 QgsDataItem *QgsZipItem::itemFromPath( QgsDataItem *parent, const QString &path, const QString &name )
1783 {
1784  return itemFromPath( parent, path, name, path );
1785 }
1786 
1787 QgsDataItem *QgsZipItem::itemFromPath( QgsDataItem *parent, const QString &filePath, const QString &name, const QString &path )
1788 {
1789  QgsSettings settings;
1790  QString scanZipSetting = settings.value( QStringLiteral( "qgis/scanZipInBrowser2" ), "basic" ).toString();
1791  QStringList zipFileList;
1792  QString vsiPrefix = QgsZipItem::vsiPrefix( filePath );
1793  QgsZipItem *zipItem = nullptr;
1794  bool populated = false;
1795 
1796  QgsDebugMsgLevel( QStringLiteral( "path = %1 name= %2 scanZipSetting= %3 vsiPrefix= %4" ).arg( path, name, scanZipSetting, vsiPrefix ), 3 );
1797 
1798  // don't scan if scanZipBrowser == no
1799  if ( scanZipSetting == QLatin1String( "no" ) )
1800  return nullptr;
1801 
1802  // don't scan if this file is not a /vsizip/ or /vsitar/ item
1803  if ( ( vsiPrefix != QLatin1String( "/vsizip/" ) && vsiPrefix != QLatin1String( "/vsitar/" ) ) )
1804  return nullptr;
1805 
1806  zipItem = new QgsZipItem( parent, name, filePath, path );
1807 
1808  if ( zipItem )
1809  {
1810  // force populate zipItem if it has less than 10 items and is not a .tgz or .tar.gz file (slow loading)
1811  // for other items populating will be delayed until item is opened
1812  // this might be polluting the tree with empty items but is necessary for performance reasons
1813  // could also accept all files smaller than a certain size and add options for file count and/or size
1814 
1815  // first get list of files inside .zip or .tar files
1816  if ( path.endsWith( QLatin1String( ".zip" ), Qt::CaseInsensitive ) ||
1817  path.endsWith( QLatin1String( ".tar" ), Qt::CaseInsensitive ) )
1818  {
1819  zipFileList = zipItem->getZipFileList();
1820  }
1821  // force populate if less than 10 items
1822  if ( !zipFileList.isEmpty() && zipFileList.count() <= 10 )
1823  {
1824  zipItem->populate( zipItem->createChildren() );
1825  populated = true; // there is no QgsDataItem::isPopulated() function
1826  QgsDebugMsgLevel( QStringLiteral( "Got zipItem with %1 children, path=%2, name=%3" ).arg( zipItem->rowCount() ).arg( zipItem->path(), zipItem->name() ), 3 );
1827  }
1828  else
1829  {
1830  QgsDebugMsgLevel( QStringLiteral( "Delaying populating zipItem with path=%1, name=%2" ).arg( zipItem->path(), zipItem->name() ), 3 );
1831  }
1832  }
1833 
1834  // only display if has children or if is not populated
1835  if ( zipItem && ( !populated || zipItem->rowCount() > 0 ) )
1836  {
1837  QgsDebugMsgLevel( QStringLiteral( "returning zipItem" ), 3 );
1838  return zipItem;
1839  }
1840 
1841  return nullptr;
1842 }
1843 
1845 {
1846  if ( ! mZipFileList.isEmpty() )
1847  return mZipFileList;
1848 
1849  QString tmpPath;
1850  QgsSettings settings;
1851  QString scanZipSetting = settings.value( QStringLiteral( "qgis/scanZipInBrowser2" ), "basic" ).toString();
1852 
1853  QgsDebugMsgLevel( QStringLiteral( "mFilePath = %1 name= %2 scanZipSetting= %3 vsiPrefix= %4" ).arg( mFilePath, name(), scanZipSetting, mVsiPrefix ), 3 );
1854 
1855  // if scanZipBrowser == no: skip to the next file
1856  if ( scanZipSetting == QLatin1String( "no" ) )
1857  {
1858  return mZipFileList;
1859  }
1860 
1861  // get list of files inside zip file
1862  QgsDebugMsgLevel( QStringLiteral( "Open file %1 with gdal vsi" ).arg( mVsiPrefix + mFilePath ), 3 );
1863  char **papszSiblingFiles = VSIReadDirRecursive( QString( mVsiPrefix + mFilePath ).toLocal8Bit().constData() );
1864  if ( papszSiblingFiles )
1865  {
1866  for ( int i = 0; papszSiblingFiles[i]; i++ )
1867  {
1868  tmpPath = papszSiblingFiles[i];
1869  QgsDebugMsgLevel( QStringLiteral( "Read file %1" ).arg( tmpPath ), 3 );
1870  // skip directories (files ending with /)
1871  if ( tmpPath.right( 1 ) != QLatin1String( "/" ) )
1872  mZipFileList << tmpPath;
1873  }
1874  CSLDestroy( papszSiblingFiles );
1875  }
1876  else
1877  {
1878  QgsDebugMsg( QStringLiteral( "Error reading %1" ).arg( mFilePath ) );
1879  }
1880 
1881  return mZipFileList;
1882 }
1883 
1884 
1885 QgsDatabaseSchemaItem::QgsDatabaseSchemaItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &providerKey )
1886  : QgsDataCollectionItem( parent, name, path, providerKey )
1887 {
1888 
1889 }
1890 
1892 {
1893 
1894 }
1895 
1897 {
1898  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconDbSchema.svg" ) );
1899 }
1900 
1902 {
1903  const QString dataProviderKey { QgsApplication::dataItemProviderRegistry()->dataProviderKey( providerKey() ) };
1905  if ( ! md )
1906  {
1907  return nullptr;
1908  }
1909  const QString connectionName { parent()->name() };
1910  try
1911  {
1912  return static_cast<QgsAbstractDatabaseProviderConnection *>( md->createConnection( connectionName ) );
1913  }
1914  catch ( QgsProviderConnectionException &ex )
1915  {
1916  // This is expected and it is not an error in case the provider does not implement
1917  // the connections API
1918  }
1919  return nullptr;
1920 }
1921 
1922 
1923 QgsConnectionsRootItem::QgsConnectionsRootItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &providerKey )
1924  : QgsDataCollectionItem( parent, name, path, providerKey )
1925 {
1926 }
1927 
1928 
1930 
1931 QgsProjectHomeItem::QgsProjectHomeItem( QgsDataItem *parent, const QString &name, const QString &dirPath, const QString &path )
1932  : QgsDirectoryItem( parent, name, dirPath, path, QStringLiteral( "special:ProjectHome" ) )
1933 {
1934 }
1935 
1936 QIcon QgsProjectHomeItem::icon()
1937 {
1938  if ( state() == Populating )
1939  return QgsDirectoryItem::icon();
1940  return QgsApplication::getThemeIcon( QStringLiteral( "mIconFolderProject.svg" ) );
1941 }
1942 
1943 QVariant QgsProjectHomeItem::sortKey() const
1944 {
1945  return QStringLiteral( " 1" );
1946 }
1947 
1948 
1949 QgsFavoriteItem::QgsFavoriteItem( QgsFavoritesItem *parent, const QString &name, const QString &dirPath, const QString &path )
1950  : QgsDirectoryItem( parent, name, dirPath, path, QStringLiteral( "special:Favorites" ) )
1951  , mFavorites( parent )
1952 {
1953  mCapabilities |= Rename;
1954 }
1955 
1956 bool QgsFavoriteItem::rename( const QString &name )
1957 {
1958  mFavorites->renameFavorite( dirPath(), name );
1959  return true;
1960 }
1961 
1962 
The QgsAbstractDatabaseProviderConnection class provides common functionality for DB based connection...
Animated icon is keeping an animation running if there are listeners connected to frameChanged.
bool disconnectFrameChanged(const typename QtPrivate::FunctionPointer< Func1 >::Object *receiver, Func1 slot)
Convenience function to disconnect the same style that the frame change connection was established.
bool connectFrameChanged(const typename QtPrivate::FunctionPointer< Func1 >::Object *receiver, Func1 slot)
Connect a slot that will be notified repeatedly whenever a frame changes and which should request the...
QIcon icon() const
Gets the icons representation in the current frame.
static QgsDataItemProviderRegistry * dataItemProviderRegistry()
Returns the application's data item provider registry, which keeps a list of data item providers that...
static QgsApplication * instance()
Returns the singleton instance of the QgsApplication.
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
QgsConnectionsRootItem(QgsDataItem *parent, const QString &name, const QString &path=QString(), const QString &providerKey=QString())
Constructor for QgsConnectionsRootItem, with the specified parent item.
A Collection: logical collection of layers or subcollections, e.g.
Definition: qgsdataitem.h:683
static QIcon openDirIcon()
Shared open directory icon.
QgsDataCollectionItem(QgsDataItem *parent, const QString &name, const QString &path=QString(), const QString &providerKey=QString())
Constructor for QgsDataCollectionItem, with the specified parent item.
static QIcon homeDirIcon()
Shared home directory icon.
static QIcon iconDir()
Returns the standard browser directory icon.
~QgsDataCollectionItem() override
QgsAbstractDatabaseProviderConnection * databaseConnection() const override
For data items that represent a DB connection or one of its children, this method returns a connectio...
static QIcon iconDataCollection()
Returns the standard browser data collection icon.
QList< QgsDataItemProvider * > providers() const
Returns the list of available providers.
QString dataProviderKey(const QString &dataItemProviderName)
Returns the (possibly blank) data provider key for a given data item provider name.
This is the interface for those who want to add custom data items to the browser tree.
Base class for all items in the model.
Definition: qgsdataitem.h:52
void setSortKey(const QVariant &key)
Sets a custom sorting key for the item.
static int findItem(QVector< QgsDataItem * > items, QgsDataItem *item)
virtual Capabilities capabilities2() const
Returns the capabilities for the data item.
Definition: qgsdataitem.h:323
QString mName
Definition: qgsdataitem.h:464
bool hasChildren()
virtual QList< QMenu * > menus(QWidget *parent)
Returns the list of menus available for this item.
virtual void deleteChildItem(QgsDataItem *child)
Removes and deletes a child item, emitting relevant signals to the model.
QVector< QgsDataItem * > mChildren
Definition: qgsdataitem.h:462
@ Populated
Children created.
Definition: qgsdataitem.h:153
@ Populating
Creating children in separate thread (populating or refreshing)
Definition: qgsdataitem.h:152
@ NotPopulated
Children not yet created.
Definition: qgsdataitem.h:151
Capabilities mCapabilities
Definition: qgsdataitem.h:460
virtual QVariant sortKey() const
Returns the sorting key for the item.
void setToolTip(const QString &msg)
Definition: qgsdataitem.h:421
virtual bool handleDoubleClick()
Called when a user double clicks on the item.
void dataChanged(QgsDataItem *item)
bool deferredDelete()
The item is scheduled to be deleted.
Definition: qgsdataitem.h:457
void setParent(QgsDataItem *parent)
Set item parent and connect / disconnect parent to / from item signals.
static void deleteLater(QVector< QgsDataItem * > &items)
Type type() const
Definition: qgsdataitem.h:339
void endRemoveItems()
virtual bool layerCollection() const
Returns true if the data item is a collection of layers The default implementation returns false,...
QString mPath
Definition: qgsdataitem.h:470
QVector< QgsDataItem * > children() const
Definition: qgsdataitem.h:352
@ Fertile
Can create children. Even items without this capability may have children, but cannot create them,...
Definition: qgsdataitem.h:282
@ Collapse
The collapse/expand status for this items children should be ignored in order to avoid undesired netw...
Definition: qgsdataitem.h:284
@ Rename
Item can be renamed.
Definition: qgsdataitem.h:285
@ Fast
CreateChildren() is fast enough to be run in main thread when refreshing items, most root items (wms,...
Definition: qgsdataitem.h:283
void beginRemoveItems(QgsDataItem *parent, int first, int last)
QgsDataItem * parent() const
Gets item parent.
Definition: qgsdataitem.h:345
virtual void deleteLater()
Safely delete the item:
virtual QgsAbstractDatabaseProviderConnection * databaseConnection() const
For data items that represent a DB connection or one of its children, this method returns a connectio...
QString mIconName
Definition: qgsdataitem.h:472
virtual QVector< QgsDataItem * > createChildren()
Create children.
QMap< QString, QIcon > mIconMap
Definition: qgsdataitem.h:474
virtual void childrenCreated()
virtual void setState(State state)
Set item state.
virtual QgsDataItem * removeChildItem(QgsDataItem *child)
Removes a child item and returns it without deleting it.
static QString pathComponent(const QString &component)
Create path component replacing path separators.
State state() const
virtual QList< QAction * > actions(QWidget *parent)
Returns the list of actions available for this item.
@ Favorites
Represents a favorite item.
Definition: qgsdataitem.h:84
QVariant mSortKey
Custom sort key. If invalid, name() will be used for sorting instead.
Definition: qgsdataitem.h:477
void updateIcon()
Will request a repaint of this icon.
virtual Q_DECL_DEPRECATED bool rename(const QString &name)
Sets a new name for the item, and returns true if the item was successfully renamed.
void connectionsChanged(const QString &providerKey=QString())
Emitted when the connections of the provider with the specified providerKey have changed.
virtual Q_DECL_DEPRECATED QgsMimeDataUtils::Uri mimeUri() const
Returns mime URI for the data item.
QgsDataItem * mParent
Definition: qgsdataitem.h:461
QString name() const
Returns the name of the item (the displayed text for the item).
Definition: qgsdataitem.h:360
QString path() const
Definition: qgsdataitem.h:369
virtual QIcon icon()
void beginInsertItems(QgsDataItem *parent, int first, int last)
virtual void refreshConnections(const QString &providerKey=QString())
Causes a data item provider to refresh all registered connections.
virtual void addChildItem(QgsDataItem *child, bool refresh=false)
Inserts a new child item.
QgsDataItem(QgsDataItem::Type type, QgsDataItem *parent, const QString &name, const QString &path, const QString &providerKey=QString())
Constructor for QgsDataItem, with the specified parent item.
void setName(const QString &name)
Sets the name of the item (the displayed text for the item).
virtual void refresh()
void stateChanged(QgsDataItem *item, QgsDataItem::State oldState)
void moveToThread(QThread *targetThread)
Move object and all its descendants to thread.
QString providerKey() const
Returns the provider key that created this item (e.g.
void endInsertItems()
State mState
Definition: qgsdataitem.h:463
~QgsDataItem() override
void setProviderKey(const QString &value)
Sets the provider key that created this item (e.g.
QString mProviderKey
Definition: qgsdataitem.h:465
virtual void populate(const QVector< QgsDataItem * > &children)
virtual bool equal(const QgsDataItem *other)
Returns true if this item is equal to another item (by testing item type and path).
virtual QgsMimeDataUtils::UriList mimeUris() const
Returns mime URIs for the data item, most data providers will only return a single URI but some data ...
Definition: qgsdataitem.h:276
virtual void depopulate()
Remove children recursively and set as not populated. This is used when refreshing collapsed items.
~QgsDatabaseSchemaItem() override
QgsDatabaseSchemaItem(QgsDataItem *parent, const QString &name, const QString &path=QString(), const QString &providerKey=QString())
Constructor for QgsDatabaseSchemaItem, with the specified parent item.
QgsAbstractDatabaseProviderConnection * databaseConnection() const override
For data items that represent a DB connection or one of its children, this method returns a connectio...
static QIcon iconDataCollection()
Returns the standard browser data collection icon.
A directory: contains subdirectories and layers.
Definition: qgsdataitem.h:804
void setState(State state) override
Set item state.
QVector< QgsDataItem * > createChildren() override
Create children.
Q_DECL_DEPRECATED QWidget * paramWidget() override
Returns source widget from data item for QgsBrowserPropertiesWidget.
QgsMimeDataUtils::UriList mimeUris() const override
Returns mime URIs for the data item, most data providers will only return a single URI but some data ...
bool equal(const QgsDataItem *other) override
Returns true if this item is equal to another item (by testing item type and path).
QString dirPath() const
Returns the full path to the directory the item represents.
Definition: qgsdataitem.h:849
void childrenCreated() override
QgsDirectoryItem(QgsDataItem *parent, const QString &name, const QString &path)
Constructor for QgsDirectoryItem, with the specified parent item.
static bool hiddenPath(const QString &path)
Check if the given path is hidden from the browser model.
QIcon icon() override
Browser parameter widget implementation for directory items.
Definition: qgsdataitem.h:922
void mousePressEvent(QMouseEvent *event) override
QgsDirectoryParamWidget(const QString &path, QWidget *parent=nullptr)
Data item that can be used to report problems (e.g.
Definition: qgsdataitem.h:903
QgsErrorItem(QgsDataItem *parent, const QString &error, const QString &path)
QString what() const
Definition: qgsexception.h:48
Contains various Favorites directories.
Definition: qgsdataitem.h:941
void addDirectory(const QString &directory, const QString &name=QString())
Adds a new directory to the favorites group.
QVariant sortKey() const override
Returns the sorting key for the item.
void removeDirectory(QgsDirectoryItem *item)
Removes an existing directory from the favorites group.
static QIcon iconFavorites()
Icon for favorites group.
QVector< QgsDataItem * > createChildren() override
Create children.
QgsFavoritesItem(QgsDataItem *parent, const QString &name, const QString &path=QString())
Constructor for QgsFavoritesItem.
void renameFavorite(const QString &path, const QString &name)
Renames the stored favorite with corresponding path a new name.
A layer field item, information about the connection URI, the schema and the table as well as the lay...
Definition: qgsdataitem.h:1110
~QgsFieldItem() override
QgsFieldItem(QgsDataItem *parent, const QgsField &field)
Constructor for QgsFieldItem, with the specified parent item and field.
QIcon icon() override
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:51
QString typeName() const
Gets the field type.
Definition: qgsfield.cpp:138
QVariant::Type type
Definition: qgsfield.h:58
QVariant::Type subType() const
If the field is a collection, gets its element's type.
Definition: qgsfield.cpp:133
A collection of field items with some internal logic to retrieve the fields and a the vector layer in...
Definition: qgsdataitem.h:1038
QString tableName() const
Returns the table name.
QgsFieldsItem(QgsDataItem *parent, const QString &path, const QString &connectionUri, const QString &providerKey, const QString &schema, const QString &tableName)
Constructor for QgsFieldsItem, with the specified parent item.
QgsAbstractDatabaseProviderConnection::TableProperty * tableProperty() const
Returns the (possibly NULL) properties of the table this fields belong to.
QString connectionUri() const
Returns the connection URI.
QVector< QgsDataItem * > createChildren() override
Create children.
QgsVectorLayer * layer()
Creates and returns a (possibly NULL) layer from the connection URI and schema/table information.
~QgsFieldsItem() override
QString schema() const
Returns the schema name.
QIcon icon() override
Container of fields for a vector layer.
Definition: qgsfields.h:45
static QIcon iconForFieldType(const QVariant::Type &type)
Returns an icon corresponding to a field type.
Definition: qgsfields.cpp:295
Item that represents a layer that can be opened with one of the providers.
Definition: qgsdataitem.h:554
QStringList supportedFormats() const
Returns the supported formats.
Definition: qgsdataitem.h:614
static QIcon iconPoint()
Definition: qgsdataitem.cpp:76
QString uri() const
Returns layer uri or empty string if layer cannot be created.
Definition: qgsdataitem.h:599
virtual Q_DECL_DEPRECATED bool deleteLayer()
Delete this layer item Use QgsDataItemGuiProvider::deleteLayer instead.
static QIcon iconLine()
Definition: qgsdataitem.cpp:81
QString mUri
The URI.
Definition: qgsdataitem.h:644
QStringList supportedCrs() const
Returns the supported CRS.
Definition: qgsdataitem.h:608
static QIcon iconTable()
Definition: qgsdataitem.cpp:91
static LayerType typeFromMapLayer(QgsMapLayer *layer)
Returns the layer item type corresponding to a QgsMapLayer layer.
static QIcon iconDefault()
static QString iconName(LayerType layerType)
Returns the icon name of the given layerType.
static QString layerTypeAsString(LayerType layerType)
Returns the string representation of the given layerType.
QgsMapLayerType mapLayerType() const
Returns QgsMapLayerType.
QString providerKey() const
Returns provider key.
Definition: qgsdataitem.h:602
static QIcon iconRaster()
Definition: qgsdataitem.cpp:96
static QIcon iconMesh()
Returns icon for mesh layer type.
LayerType mLayerType
The layer type.
Definition: qgsdataitem.h:646
static QIcon iconForWkbType(QgsWkbTypes::Type type)
Returns the icon for a vector layer whose geometry type is provided.
Definition: qgsdataitem.cpp:57
static QIcon iconPolygon()
Definition: qgsdataitem.cpp:86
QgsMimeDataUtils::UriList mimeUris() const override
Returns mime URIs for the data item, most data providers will only return a single URI but some data ...
static QIcon iconPointCloud()
Returns icon for point cloud layer.
static QIcon iconVectorTile()
Returns icon for vector tile layer.
@ PointCloud
Added in 3.18.
Definition: qgsdataitem.h:572
@ Mesh
Added in 3.2.
Definition: qgsdataitem.h:570
@ Plugin
Added in 2.10.
Definition: qgsdataitem.h:569
@ VectorTile
Added in 3.14.
Definition: qgsdataitem.h:571
virtual QString layerName() const
Definition: qgsdataitem.h:673
QgsLayerItem(QgsDataItem *parent, const QString &name, const QString &path, const QString &uri, LayerType layerType, const QString &providerKey)
bool equal(const QgsDataItem *other) override
Returns true if this item is equal to another item (by testing item type and path).
Base class for all map layer types.
Definition: qgsmaplayer.h:85
QgsMapLayerType type
Definition: qgsmaplayer.h:92
QList< QgsMimeDataUtils::Uri > UriList
Data item that can be used to represent QGIS projects.
Definition: qgsdataitem.h:879
QgsMimeDataUtils::UriList mimeUris() const override
Returns mime URIs for the data item, most data providers will only return a single URI but some data ...
QgsProjectItem(QgsDataItem *parent, const QString &name, const QString &path, const QString &providerKey=QString())
A data item holding a reference to a QGIS project file.
Custom exception class for provider connection related exceptions.
Definition: qgsexception.h:101
Holds data provider key, description, and associated shared library file or function pointer informat...
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QgsProviderMetadata * providerMetadata(const QString &providerKey) const
Returns metadata of the provider or nullptr if not found.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Represents a vector layer which manages a vector based data sets.
static GeometryType geometryType(Type type) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:938
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:141
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
A zip file: contains layers, using GDAL/OGR VSIFILE mechanism.
Definition: qgsdataitem.h:988
static QIcon iconZip()
QgsZipItem(QgsDataItem *parent, const QString &name, const QString &path)
Constructor.
QStringList mZipFileList
Definition: qgsdataitem.h:994
QStringList getZipFileList()
QString mFilePath
Definition: qgsdataitem.h:992
static QgsDataItem * itemFromPath(QgsDataItem *parent, const QString &path, const QString &name)
Creates a new data item from the specified path.
QString mVsiPrefix
Definition: qgsdataitem.h:993
static QString vsiPrefix(const QString &uri)
Definition: qgsdataitem.h:1010
QVector< QgsDataItem * > createChildren() override
Create children.
static QStringList sProviderNames
Definition: qgsdataitem.h:1008
QgsMapLayerType
Types of layers that can be added to a map.
Definition: qgsmaplayer.h:69
@ PointCloudLayer
Added in 3.18.
@ MeshLayer
Added in 3.2.
@ VectorTileLayer
Added in 3.14.
@ AnnotationLayer
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
const QgsField & field
Definition: qgsfield.h:472
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
The TableProperty class represents a database table or view.
QString uri
Identifier of the data source recognized by its providerKey.
QString name
Human readable name to be used e.g. in layer tree.
QString providerKey
For "vector" / "raster" type: provider id.
QgsWkbTypes::Type wkbType
WKB type, if associated with a vector layer, or QgsWkbTypes::Unknown if not yet known.
QString layerType
Type of URI.