LCOV - code coverage report
Current view: top level - core - qgsdataitem.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 1 1113 0.1 %
Date: 2021-04-10 08:29:14 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       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"
      39                 :            : #include "qgsdataitemproviderregistry.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                 :            : 
      57                 :          0 : QIcon QgsLayerItem::iconForWkbType( QgsWkbTypes::Type type )
      58                 :            : {
      59                 :          0 :   QgsWkbTypes::GeometryType geomType = QgsWkbTypes::geometryType( QgsWkbTypes::Type( type ) );
      60                 :          0 :   switch ( geomType )
      61                 :            :   {
      62                 :            :     case QgsWkbTypes::NullGeometry:
      63                 :          0 :       return iconTable();
      64                 :            :     case QgsWkbTypes::PointGeometry:
      65                 :          0 :       return iconPoint();
      66                 :            :     case QgsWkbTypes::LineGeometry:
      67                 :          0 :       return iconLine();
      68                 :            :     case QgsWkbTypes::PolygonGeometry:
      69                 :          0 :       return iconPolygon();
      70                 :            :     default:
      71                 :          0 :       break;
      72                 :            :   }
      73                 :          0 :   return iconDefault();
      74                 :          0 : }
      75                 :            : 
      76                 :          0 : QIcon QgsLayerItem::iconPoint()
      77                 :            : {
      78                 :          0 :   return QgsApplication::getThemeIcon( QStringLiteral( "/mIconPointLayer.svg" ) );
      79                 :          0 : }
      80                 :            : 
      81                 :          0 : QIcon QgsLayerItem::iconLine()
      82                 :            : {
      83                 :          0 :   return QgsApplication::getThemeIcon( QStringLiteral( "/mIconLineLayer.svg" ) );
      84                 :          0 : }
      85                 :            : 
      86                 :          0 : QIcon QgsLayerItem::iconPolygon()
      87                 :            : {
      88                 :          0 :   return QgsApplication::getThemeIcon( QStringLiteral( "/mIconPolygonLayer.svg" ) );
      89                 :          0 : }
      90                 :            : 
      91                 :          0 : QIcon QgsLayerItem::iconTable()
      92                 :            : {
      93                 :          0 :   return QgsApplication::getThemeIcon( QStringLiteral( "/mIconTableLayer.svg" ) );
      94                 :          0 : }
      95                 :            : 
      96                 :          0 : QIcon QgsLayerItem::iconRaster()
      97                 :            : {
      98                 :          0 :   return QgsApplication::getThemeIcon( QStringLiteral( "/mIconRaster.svg" ) );
      99                 :          0 : }
     100                 :            : 
     101                 :          0 : QIcon QgsLayerItem::iconMesh()
     102                 :            : {
     103                 :          0 :   return QgsApplication::getThemeIcon( QStringLiteral( "/mIconMeshLayer.svg" ) );
     104                 :          0 : }
     105                 :            : 
     106                 :          0 : QIcon QgsLayerItem::iconVectorTile()
     107                 :            : {
     108                 :          0 :   return QgsApplication::getThemeIcon( QStringLiteral( "/mIconVectorTileLayer.svg" ) );
     109                 :          0 : }
     110                 :            : 
     111                 :          0 : QIcon QgsLayerItem::iconPointCloud()
     112                 :            : {
     113                 :          0 :   return QgsApplication::getThemeIcon( QStringLiteral( "/mIconPointCloudLayer.svg" ) );
     114                 :          0 : }
     115                 :            : 
     116                 :          0 : QIcon QgsLayerItem::iconDefault()
     117                 :            : {
     118                 :          0 :   return QgsApplication::getThemeIcon( QStringLiteral( "/mIconLayer.png" ) );
     119                 :          0 : }
     120                 :            : 
     121                 :          0 : QIcon QgsDataCollectionItem::iconDataCollection()
     122                 :            : {
     123                 :          0 :   return QgsApplication::getThemeIcon( QStringLiteral( "/mIconDbSchema.svg" ) );
     124                 :          0 : }
     125                 :            : 
     126                 :          0 : QIcon QgsDataCollectionItem::openDirIcon()
     127                 :            : {
     128                 :          0 :   return QgsApplication::getThemeIcon( QStringLiteral( "/mIconFolderOpen.svg" ) );
     129                 :          0 : }
     130                 :            : 
     131                 :          0 : QIcon QgsDataCollectionItem::homeDirIcon()
     132                 :            : {
     133                 :          0 :   return QgsApplication::getThemeIcon( QStringLiteral( "mIconFolderHome.svg" ) );
     134                 :          0 : }
     135                 :            : 
     136                 :          0 : QgsAbstractDatabaseProviderConnection *QgsDataCollectionItem::databaseConnection() const
     137                 :            : {
     138                 :          0 :   const QString dataProviderKey { QgsApplication::dataItemProviderRegistry()->dataProviderKey( providerKey() ) };
     139                 :          0 :   QgsProviderMetadata *md { QgsProviderRegistry::instance()->providerMetadata( dataProviderKey ) };
     140                 :            : 
     141                 :          0 :   if ( ! md )
     142                 :            :   {
     143                 :          0 :     return nullptr;
     144                 :            :   }
     145                 :            : 
     146                 :          0 :   const QString connectionName { name() };
     147                 :            : 
     148                 :            :   try
     149                 :            :   {
     150                 :            :     // First try to retrieve the connection by name if this is a stored connection
     151                 :          0 :     if ( md->findConnection( connectionName ) )
     152                 :            :     {
     153                 :          0 :       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                 :          0 :     const QString databaseFilePath { path().remove( QRegularExpression( R"re([\aZ]{2,}://)re" ) ) };
     160                 :            : 
     161                 :          0 :     if ( QFile::exists( databaseFilePath ) )
     162                 :            :     {
     163                 :          0 :       return static_cast<QgsAbstractDatabaseProviderConnection *>( md->createConnection( databaseFilePath, {} ) );
     164                 :            :     }
     165                 :          0 :   }
     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                 :          0 :   }
     171                 :          0 :   return nullptr;
     172                 :          0 : }
     173                 :            : 
     174                 :          0 : QIcon QgsDataCollectionItem::iconDir()
     175                 :            : {
     176                 :          0 :   return QgsApplication::getThemeIcon( QStringLiteral( "/mIconFolder.svg" ) );
     177                 :          0 : }
     178                 :            : 
     179                 :            : 
     180                 :          0 : QgsFieldsItem::QgsFieldsItem( QgsDataItem *parent,
     181                 :            :                               const QString &path,
     182                 :            :                               const QString &connectionUri,
     183                 :            :                               const QString &providerKey,
     184                 :            :                               const QString &schema,
     185                 :            :                               const QString &tableName )
     186                 :          0 :   : QgsDataItem( QgsDataItem::Fields, parent, tr( "Fields" ), path, providerKey )
     187                 :          0 :   , mSchema( schema )
     188                 :          0 :   , mTableName( tableName )
     189                 :          0 :   , mConnectionUri( connectionUri )
     190                 :          0 : {
     191                 :          0 :   mCapabilities |= ( Fertile | Collapse );
     192                 :          0 :   QgsProviderMetadata *md { QgsProviderRegistry::instance()->providerMetadata( providerKey ) };
     193                 :          0 :   if ( md )
     194                 :            :   {
     195                 :            :     try
     196                 :            :     {
     197                 :          0 :       std::unique_ptr<QgsAbstractDatabaseProviderConnection> conn { static_cast<QgsAbstractDatabaseProviderConnection *>( md->createConnection( mConnectionUri, {} ) ) };
     198                 :          0 :       mTableProperty = std::make_unique<QgsAbstractDatabaseProviderConnection::TableProperty>( conn->table( schema, tableName ) );
     199                 :          0 :     }
     200                 :            :     catch ( QgsProviderConnectionException &ex )
     201                 :            :     {
     202                 :          0 :       QgsDebugMsg( QStringLiteral( "Error creating fields item: %1" ).arg( ex.what() ) );
     203                 :          0 :     }
     204                 :          0 :   }
     205                 :          0 : }
     206                 :            : 
     207                 :          0 : QgsFieldsItem::~QgsFieldsItem()
     208                 :          0 : {
     209                 :            : 
     210                 :          0 : }
     211                 :            : 
     212                 :          0 : QVector<QgsDataItem *> QgsFieldsItem::createChildren()
     213                 :            : {
     214                 :          0 :   QVector<QgsDataItem *> children;
     215                 :            :   try
     216                 :            :   {
     217                 :          0 :     QgsProviderMetadata *md { QgsProviderRegistry::instance()->providerMetadata( providerKey() ) };
     218                 :          0 :     if ( md )
     219                 :            :     {
     220                 :          0 :       std::unique_ptr<QgsAbstractDatabaseProviderConnection> conn { static_cast<QgsAbstractDatabaseProviderConnection *>( md->createConnection( mConnectionUri, {} ) ) };
     221                 :          0 :       if ( conn )
     222                 :            :       {
     223                 :          0 :         int i = 0;
     224                 :          0 :         const QgsFields constFields { conn->fields( mSchema, mTableName ) };
     225                 :          0 :         for ( const auto &f : constFields )
     226                 :            :         {
     227                 :          0 :           QgsFieldItem *fieldItem { new QgsFieldItem( this, f ) };
     228                 :          0 :           fieldItem->setSortKey( i++ );
     229                 :          0 :           children.push_back( fieldItem );
     230                 :            :         }
     231                 :          0 :       }
     232                 :          0 :     }
     233                 :          0 :   }
     234                 :            :   catch ( const QgsProviderConnectionException &ex )
     235                 :            :   {
     236                 :          0 :     children.push_back( new QgsErrorItem( this, ex.what(), path() + QStringLiteral( "/error" ) ) );
     237                 :          0 :   }
     238                 :          0 :   return children;
     239                 :          0 : }
     240                 :            : 
     241                 :          0 : QIcon QgsFieldsItem::icon()
     242                 :            : {
     243                 :          0 :   return QgsApplication::getThemeIcon( QStringLiteral( "mSourceFields.svg" ) );
     244                 :          0 : }
     245                 :            : 
     246                 :          0 : QString QgsFieldsItem::connectionUri() const
     247                 :            : {
     248                 :          0 :   return mConnectionUri;
     249                 :            : }
     250                 :            : 
     251                 :          0 : QgsVectorLayer *QgsFieldsItem::layer()
     252                 :            : {
     253                 :          0 :   std::unique_ptr<QgsVectorLayer> vl;
     254                 :          0 :   QgsProviderMetadata *md { QgsProviderRegistry::instance()->providerMetadata( providerKey() ) };
     255                 :          0 :   if ( md )
     256                 :            :   {
     257                 :            :     try
     258                 :            :     {
     259                 :          0 :       std::unique_ptr<QgsAbstractDatabaseProviderConnection> conn { static_cast<QgsAbstractDatabaseProviderConnection *>( md->createConnection( mConnectionUri, {} ) ) };
     260                 :          0 :       if ( conn )
     261                 :            :       {
     262                 :          0 :         vl.reset( new QgsVectorLayer( conn->tableUri( mSchema, mTableName ), QStringLiteral( "temp_layer" ), providerKey() ) );
     263                 :          0 :         if ( vl->isValid() )
     264                 :            :         {
     265                 :          0 :           return vl.release();
     266                 :            :         }
     267                 :          0 :       }
     268                 :          0 :     }
     269                 :            :     catch ( const QgsProviderConnectionException & )
     270                 :            :     {
     271                 :            :       // This should never happen!
     272                 :          0 :       QgsDebugMsg( QStringLiteral( "Error getting connection from %1" ).arg( mConnectionUri ) );
     273                 :          0 :     }
     274                 :          0 :   }
     275                 :            :   else
     276                 :            :   {
     277                 :            :     // This should never happen!
     278                 :          0 :     QgsDebugMsg( QStringLiteral( "Error getting metadata for provider %1" ).arg( providerKey() ) );
     279                 :            :   }
     280                 :          0 :   return nullptr;
     281                 :          0 : }
     282                 :            : 
     283                 :          0 : QgsAbstractDatabaseProviderConnection::TableProperty *QgsFieldsItem::tableProperty() const
     284                 :            : {
     285                 :          0 :   return mTableProperty.get();
     286                 :            : }
     287                 :            : 
     288                 :          0 : QString QgsFieldsItem::tableName() const
     289                 :            : {
     290                 :          0 :   return mTableName;
     291                 :            : }
     292                 :            : 
     293                 :          0 : QString QgsFieldsItem::schema() const
     294                 :            : {
     295                 :          0 :   return mSchema;
     296                 :            : }
     297                 :            : 
     298                 :          0 : QgsFieldItem::QgsFieldItem( QgsDataItem *parent, const QgsField &field )
     299                 :          0 :   : QgsDataItem( QgsDataItem::Type::Field, parent, field.name(), parent->path() + '/' + field.name(), parent->providerKey() )
     300                 :          0 :   , mField( field )
     301                 :          0 : {
     302                 :            :   // Precondition
     303                 :            :   Q_ASSERT( static_cast<QgsFieldsItem *>( parent ) );
     304                 :          0 :   setState( QgsDataItem::State::Populated );
     305                 :          0 : }
     306                 :            : 
     307                 :          0 : QgsFieldItem::~QgsFieldItem()
     308                 :          0 : {
     309                 :          0 : }
     310                 :            : 
     311                 :          0 : QIcon QgsFieldItem::icon()
     312                 :            : {
     313                 :            :   // Check if this is a geometry column and show the right icon
     314                 :          0 :   QgsFieldsItem *parentFields { static_cast<QgsFieldsItem *>( parent() ) };
     315                 :          0 :   if ( parentFields && parentFields->tableProperty() &&
     316                 :          0 :        parentFields->tableProperty()->geometryColumn() == mName &&
     317                 :          0 :        parentFields->tableProperty()->geometryColumnTypes().count() )
     318                 :            :   {
     319                 :          0 :     if ( mField.typeName() == QLatin1String( "raster" ) )
     320                 :            :     {
     321                 :          0 :       return QgsLayerItem::iconRaster();
     322                 :            :     }
     323                 :          0 :     const QgsWkbTypes::GeometryType geomType { QgsWkbTypes::geometryType( parentFields->tableProperty()->geometryColumnTypes().first().wkbType ) };
     324                 :          0 :     switch ( geomType )
     325                 :            :     {
     326                 :            :       case QgsWkbTypes::GeometryType::LineGeometry:
     327                 :          0 :         return QgsLayerItem::iconLine();
     328                 :            :       case QgsWkbTypes::GeometryType::PointGeometry:
     329                 :          0 :         return QgsLayerItem::iconPoint();
     330                 :            :       case QgsWkbTypes::GeometryType::PolygonGeometry:
     331                 :          0 :         return QgsLayerItem::iconPolygon();
     332                 :            :       case QgsWkbTypes::GeometryType::UnknownGeometry:
     333                 :            :       case QgsWkbTypes::GeometryType::NullGeometry:
     334                 :          0 :         return QgsLayerItem::iconDefault();
     335                 :            :     }
     336                 :          0 :   }
     337                 :          0 :   const QIcon icon { QgsFields::iconForFieldType( mField.type() ) };
     338                 :            :   // Try subtype if icon is null
     339                 :          0 :   if ( icon.isNull() )
     340                 :            :   {
     341                 :          0 :     return QgsFields::iconForFieldType( mField.subType() );
     342                 :            :   }
     343                 :          0 :   return icon;
     344                 :          0 : }
     345                 :            : 
     346                 :          0 : QIcon QgsFavoritesItem::iconFavorites()
     347                 :            : {
     348                 :          0 :   return QgsApplication::getThemeIcon( QStringLiteral( "/mIconFavorites.svg" ) );
     349                 :          0 : }
     350                 :            : 
     351                 :          0 : QVariant QgsFavoritesItem::sortKey() const
     352                 :            : {
     353                 :          0 :   return QStringLiteral( " 0" );
     354                 :          0 : }
     355                 :            : 
     356                 :          0 : QIcon QgsZipItem::iconZip()
     357                 :            : {
     358                 :          0 :   return QgsApplication::getThemeIcon( QStringLiteral( "/mIconZip.svg" ) );
     359                 :          0 : }
     360                 :            : 
     361                 :            : QgsAnimatedIcon *QgsDataItem::sPopulatingIcon = nullptr;
     362                 :            : 
     363                 :          0 : 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                 :          0 :   : mType( type )
     366                 :          0 :   , mCapabilities( NoCapabilities )
     367                 :          0 :   , mParent( parent )
     368                 :          0 :   , mState( NotPopulated )
     369                 :          0 :   , mName( name )
     370                 :          0 :   , mProviderKey( providerKey )
     371                 :          0 :   , mPath( path )
     372                 :          0 :   , mDeferredDelete( false )
     373                 :          0 :   , mFutureWatcher( nullptr )
     374                 :          0 : {
     375                 :          0 : }
     376                 :            : 
     377                 :          0 : QgsDataItem::~QgsDataItem()
     378                 :          0 : {
     379                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "mName = %1 mPath = %2 mChildren.size() = %3" ).arg( mName, mPath ).arg( mChildren.size() ), 2 );
     380                 :          0 :   const auto constMChildren = mChildren;
     381                 :          0 :   for ( QgsDataItem *child : constMChildren )
     382                 :            :   {
     383                 :          0 :     if ( !child ) // should not happen
     384                 :          0 :       continue;
     385                 :          0 :     child->deleteLater();
     386                 :            :   }
     387                 :          0 :   mChildren.clear();
     388                 :            : 
     389                 :          0 :   if ( mFutureWatcher && !mFutureWatcher->isFinished() )
     390                 :            :   {
     391                 :            :     // this should not usually happen (until the item was deleted directly when createChildren was running)
     392                 :          0 :     QgsDebugMsg( QStringLiteral( "mFutureWatcher not finished (should not happen) -> waitForFinished()" ) );
     393                 :          0 :     mDeferredDelete = true;
     394                 :          0 :     mFutureWatcher->waitForFinished();
     395                 :          0 :   }
     396                 :            : 
     397                 :          0 :   delete mFutureWatcher;
     398                 :          0 : }
     399                 :            : 
     400                 :          0 : QString QgsDataItem::pathComponent( const QString &string )
     401                 :            : {
     402                 :          0 :   return QString( string ).replace( QRegExp( "[\\\\/]" ), QStringLiteral( "|" ) );
     403                 :          0 : }
     404                 :            : 
     405                 :          0 : QVariant QgsDataItem::sortKey() const
     406                 :            : {
     407                 :          0 :   return mSortKey.isValid() ? mSortKey : name();
     408                 :          0 : }
     409                 :            : 
     410                 :          0 : void QgsDataItem::setSortKey( const QVariant &key )
     411                 :            : {
     412                 :          0 :   mSortKey = key;
     413                 :          0 : }
     414                 :            : 
     415                 :          0 : void QgsDataItem::deleteLater()
     416                 :            : {
     417                 :          0 :   QgsDebugMsgLevel( "path = " + path(), 3 );
     418                 :          0 :   setParent( nullptr ); // also disconnects parent
     419                 :          0 :   const auto constMChildren = mChildren;
     420                 :          0 :   for ( QgsDataItem *child : constMChildren )
     421                 :            :   {
     422                 :          0 :     if ( !child ) // should not happen
     423                 :          0 :       continue;
     424                 :          0 :     child->deleteLater();
     425                 :            :   }
     426                 :          0 :   mChildren.clear();
     427                 :            : 
     428                 :          0 :   if ( mFutureWatcher && !mFutureWatcher->isFinished() )
     429                 :            :   {
     430                 :          0 :     QgsDebugMsg( QStringLiteral( "mFutureWatcher not finished -> schedule to delete later" ) );
     431                 :          0 :     mDeferredDelete = true;
     432                 :          0 :   }
     433                 :            :   else
     434                 :            :   {
     435                 :          0 :     QObject::deleteLater();
     436                 :            :   }
     437                 :          0 : }
     438                 :            : 
     439                 :          0 : void QgsDataItem::deleteLater( QVector<QgsDataItem *> &items )
     440                 :            : {
     441                 :          0 :   const auto constItems = items;
     442                 :          0 :   for ( QgsDataItem *item : constItems )
     443                 :            :   {
     444                 :          0 :     if ( !item ) // should not happen
     445                 :          0 :       continue;
     446                 :          0 :     item->deleteLater();
     447                 :            :   }
     448                 :          0 :   items.clear();
     449                 :          0 : }
     450                 :            : 
     451                 :          0 : void QgsDataItem::moveToThread( QThread *targetThread )
     452                 :            : {
     453                 :            :   // QObject::moveToThread() cannot move objects with parent, but QgsDataItem is not using paren/children from QObject
     454                 :          0 :   const auto constMChildren = mChildren;
     455                 :          0 :   for ( QgsDataItem *child : constMChildren )
     456                 :            :   {
     457                 :          0 :     if ( !child ) // should not happen
     458                 :          0 :       continue;
     459                 :          0 :     QgsDebugMsgLevel( "moveToThread child " + child->path(), 3 );
     460                 :          0 :     child->QObject::setParent( nullptr ); // to be sure
     461                 :          0 :     child->moveToThread( targetThread );
     462                 :            :   }
     463                 :          0 :   QObject::moveToThread( targetThread );
     464                 :          0 : }
     465                 :            : 
     466                 :          0 : QgsAbstractDatabaseProviderConnection *QgsDataItem::databaseConnection() const
     467                 :            : {
     468                 :          0 :   return nullptr;
     469                 :            : }
     470                 :            : 
     471                 :          0 : QIcon QgsDataItem::icon()
     472                 :            : {
     473                 :          0 :   if ( state() == Populating && sPopulatingIcon )
     474                 :          0 :     return sPopulatingIcon->icon();
     475                 :            : 
     476                 :          0 :   if ( !mIcon.isNull() )
     477                 :          0 :     return mIcon;
     478                 :            : 
     479                 :          0 :   if ( !mIconMap.contains( mIconName ) )
     480                 :            :   {
     481                 :          0 :     mIconMap.insert( mIconName, mIconName.startsWith( ':' ) ? QIcon( mIconName ) : QgsApplication::getThemeIcon( mIconName ) );
     482                 :          0 :   }
     483                 :            : 
     484                 :          0 :   return mIconMap.value( mIconName );
     485                 :          0 : }
     486                 :            : 
     487                 :          0 : void QgsDataItem::setName( const QString &name )
     488                 :            : {
     489                 :          0 :   mName = name;
     490                 :          0 :   emit dataChanged( this );
     491                 :          0 : }
     492                 :            : 
     493                 :          0 : QVector<QgsDataItem *> QgsDataItem::createChildren()
     494                 :            : {
     495                 :          0 :   return QVector<QgsDataItem *>();
     496                 :            : }
     497                 :            : 
     498                 :          0 : void QgsDataItem::populate( bool foreground )
     499                 :            : {
     500                 :          0 :   if ( state() == Populated || state() == Populating )
     501                 :          0 :     return;
     502                 :            : 
     503                 :          0 :   QgsDebugMsgLevel( "mPath = " + mPath, 2 );
     504                 :            : 
     505                 :          0 :   if ( capabilities2() & QgsDataItem::Fast || foreground )
     506                 :            :   {
     507                 :          0 :     populate( createChildren() );
     508                 :          0 :   }
     509                 :            :   else
     510                 :            :   {
     511                 :          0 :     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                 :          0 :     if ( !mFutureWatcher )
     514                 :            :     {
     515                 :          0 :       mFutureWatcher = new QFutureWatcher< QVector <QgsDataItem *> >( this );
     516                 :          0 :     }
     517                 :            : 
     518                 :          0 :     connect( mFutureWatcher, &QFutureWatcherBase::finished, this, &QgsDataItem::childrenCreated );
     519                 :          0 :     mFutureWatcher->setFuture( QtConcurrent::run( runCreateChildren, this ) );
     520                 :            :   }
     521                 :          0 : }
     522                 :            : 
     523                 :            : // This is expected to be run in a separate thread
     524                 :          0 : QVector<QgsDataItem *> QgsDataItem::runCreateChildren( QgsDataItem *item )
     525                 :            : {
     526                 :          0 :   QgsDebugMsgLevel( "path = " + item->path(), 2 );
     527                 :          0 :   QElapsedTimer time;
     528                 :          0 :   time.start();
     529                 :          0 :   QVector <QgsDataItem *> children = item->createChildren();
     530                 :          0 :   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                 :          0 :   const auto constChildren = children;
     533                 :          0 :   for ( QgsDataItem *child : constChildren )
     534                 :            :   {
     535                 :          0 :     if ( !child ) // should not happen
     536                 :          0 :       continue;
     537                 :          0 :     QgsDebugMsgLevel( "moveToThread child " + child->path(), 2 );
     538                 :          0 :     if ( qApp )
     539                 :          0 :       child->moveToThread( qApp->thread() ); // moves also children
     540                 :            :   }
     541                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "finished path %1: %2 children" ).arg( item->path() ).arg( children.size() ), 3 );
     542                 :          0 :   return children;
     543                 :          0 : }
     544                 :            : 
     545                 :          0 : void QgsDataItem::childrenCreated()
     546                 :            : {
     547                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "path = %1 children.size() = %2" ).arg( path() ).arg( mFutureWatcher->result().size() ), 3 );
     548                 :            : 
     549                 :          0 :   if ( deferredDelete() )
     550                 :            :   {
     551                 :          0 :     QgsDebugMsg( QStringLiteral( "Item was scheduled to be deleted later" ) );
     552                 :          0 :     QObject::deleteLater();
     553                 :          0 :     return;
     554                 :            :   }
     555                 :            : 
     556                 :          0 :   if ( mChildren.isEmpty() ) // usually populating but may also be refresh if originally there were no children
     557                 :            :   {
     558                 :          0 :     populate( mFutureWatcher->result() );
     559                 :          0 :   }
     560                 :            :   else // refreshing
     561                 :            :   {
     562                 :          0 :     refresh( mFutureWatcher->result() );
     563                 :            :   }
     564                 :          0 :   disconnect( mFutureWatcher, &QFutureWatcherBase::finished, this, &QgsDataItem::childrenCreated );
     565                 :          0 :   emit dataChanged( this ); // to replace loading icon by normal icon
     566                 :          0 : }
     567                 :            : 
     568                 :          0 : void QgsDataItem::updateIcon()
     569                 :            : {
     570                 :          0 :   emit dataChanged( this );
     571                 :          0 : }
     572                 :            : 
     573                 :          0 : void QgsDataItem::populate( const QVector<QgsDataItem *> &children )
     574                 :            : {
     575                 :          0 :   QgsDebugMsgLevel( "mPath = " + mPath, 3 );
     576                 :            : 
     577                 :          0 :   const auto constChildren = children;
     578                 :          0 :   for ( QgsDataItem *child : constChildren )
     579                 :            :   {
     580                 :          0 :     if ( !child ) // should not happen
     581                 :          0 :       continue;
     582                 :            :     // update after thread finished -> refresh
     583                 :          0 :     addChildItem( child, true );
     584                 :            :   }
     585                 :          0 :   setState( Populated );
     586                 :          0 : }
     587                 :            : 
     588                 :          0 : void QgsDataItem::depopulate()
     589                 :            : {
     590                 :          0 :   QgsDebugMsgLevel( "mPath = " + mPath, 3 );
     591                 :            : 
     592                 :          0 :   const auto constMChildren = mChildren;
     593                 :          0 :   for ( QgsDataItem *child : constMChildren )
     594                 :            :   {
     595                 :          0 :     QgsDebugMsgLevel( "remove " + child->path(), 3 );
     596                 :          0 :     child->depopulate(); // recursive
     597                 :          0 :     deleteChildItem( child );
     598                 :            :   }
     599                 :          0 :   setState( NotPopulated );
     600                 :          0 : }
     601                 :            : 
     602                 :          0 : void QgsDataItem::refresh()
     603                 :            : {
     604                 :          0 :   if ( state() == Populating )
     605                 :          0 :     return;
     606                 :            : 
     607                 :          0 :   QgsDebugMsgLevel( "mPath = " + mPath, 3 );
     608                 :            : 
     609                 :          0 :   if ( capabilities2() & QgsDataItem::Fast )
     610                 :            :   {
     611                 :          0 :     refresh( createChildren() );
     612                 :          0 :   }
     613                 :            :   else
     614                 :            :   {
     615                 :          0 :     setState( Populating );
     616                 :          0 :     if ( !mFutureWatcher )
     617                 :            :     {
     618                 :          0 :       mFutureWatcher = new QFutureWatcher< QVector <QgsDataItem *> >( this );
     619                 :          0 :     }
     620                 :          0 :     connect( mFutureWatcher, &QFutureWatcherBase::finished, this, &QgsDataItem::childrenCreated );
     621                 :          0 :     mFutureWatcher->setFuture( QtConcurrent::run( runCreateChildren, this ) );
     622                 :            :   }
     623                 :          0 : }
     624                 :            : 
     625                 :          0 : void QgsDataItem::refreshConnections( const QString &key )
     626                 :            : {
     627                 :            :   // Walk up until the root node is reached
     628                 :          0 :   if ( mParent )
     629                 :            :   {
     630                 :          0 :     mParent->refreshConnections( key );
     631                 :          0 :   }
     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                 :          0 :     emit connectionsChanged( key.isEmpty() ? providerKey() : key );
     637                 :            :   }
     638                 :          0 : }
     639                 :            : 
     640                 :          0 : void QgsDataItem::refresh( const QVector<QgsDataItem *> &children )
     641                 :            : {
     642                 :          0 :   QgsDebugMsgLevel( "mPath = " + mPath, 2 );
     643                 :            : 
     644                 :            :   // Remove no more present children
     645                 :          0 :   QVector<QgsDataItem *> remove;
     646                 :          0 :   const auto constMChildren = mChildren;
     647                 :          0 :   for ( QgsDataItem *child : constMChildren )
     648                 :            :   {
     649                 :          0 :     if ( !child ) // should not happen
     650                 :          0 :       continue;
     651                 :          0 :     if ( findItem( children, child ) >= 0 )
     652                 :          0 :       continue;
     653                 :          0 :     remove.append( child );
     654                 :            :   }
     655                 :          0 :   const auto constRemove = remove;
     656                 :          0 :   for ( QgsDataItem *child : constRemove )
     657                 :            :   {
     658                 :          0 :     QgsDebugMsgLevel( "remove " + child->path(), 3 );
     659                 :          0 :     deleteChildItem( child );
     660                 :            :   }
     661                 :            : 
     662                 :            :   // Add new children
     663                 :          0 :   const auto constChildren = children;
     664                 :          0 :   for ( QgsDataItem *child : constChildren )
     665                 :            :   {
     666                 :          0 :     if ( !child ) // should not happen
     667                 :          0 :       continue;
     668                 :            : 
     669                 :          0 :     int index = findItem( mChildren, child );
     670                 :          0 :     if ( index >= 0 )
     671                 :            :     {
     672                 :            :       // Refresh recursively (some providers may create more generations of descendants)
     673                 :          0 :       if ( !( child->capabilities2() & QgsDataItem::Fertile ) )
     674                 :            :       {
     675                 :            :         // The child cannot createChildren() itself
     676                 :          0 :         mChildren.value( index )->refresh( child->children() );
     677                 :          0 :       }
     678                 :            : 
     679                 :          0 :       child->deleteLater();
     680                 :          0 :       continue;
     681                 :            :     }
     682                 :          0 :     addChildItem( child, true );
     683                 :            :   }
     684                 :          0 :   setState( Populated );
     685                 :          0 : }
     686                 :            : 
     687                 :          0 : QString QgsDataItem::providerKey() const
     688                 :            : {
     689                 :          0 :   return mProviderKey;
     690                 :            : }
     691                 :            : 
     692                 :          0 : void QgsDataItem::setProviderKey( const QString &value )
     693                 :            : {
     694                 :          0 :   mProviderKey = value;
     695                 :          0 : }
     696                 :            : 
     697                 :          0 : int QgsDataItem::rowCount()
     698                 :            : {
     699                 :          0 :   return mChildren.size();
     700                 :            : }
     701                 :          0 : bool QgsDataItem::hasChildren()
     702                 :            : {
     703                 :          0 :   return ( state() == Populated ? !mChildren.isEmpty() : true );
     704                 :            : }
     705                 :            : 
     706                 :          0 : bool QgsDataItem::layerCollection() const
     707                 :            : {
     708                 :          0 :   return false;
     709                 :            : }
     710                 :            : 
     711                 :          0 : void QgsDataItem::setParent( QgsDataItem *parent )
     712                 :            : {
     713                 :          0 :   if ( mParent )
     714                 :            :   {
     715                 :          0 :     disconnect( this, nullptr, mParent, nullptr );
     716                 :          0 :   }
     717                 :          0 :   if ( parent )
     718                 :            :   {
     719                 :          0 :     connect( this, &QgsDataItem::beginInsertItems, parent, &QgsDataItem::beginInsertItems );
     720                 :          0 :     connect( this, &QgsDataItem::endInsertItems, parent, &QgsDataItem::endInsertItems );
     721                 :          0 :     connect( this, &QgsDataItem::beginRemoveItems, parent, &QgsDataItem::beginRemoveItems );
     722                 :          0 :     connect( this, &QgsDataItem::endRemoveItems, parent, &QgsDataItem::endRemoveItems );
     723                 :          0 :     connect( this, &QgsDataItem::dataChanged, parent, &QgsDataItem::dataChanged );
     724                 :          0 :     connect( this, &QgsDataItem::stateChanged, parent, &QgsDataItem::stateChanged );
     725                 :          0 :   }
     726                 :          0 :   mParent = parent;
     727                 :          0 : }
     728                 :            : 
     729                 :          0 : void QgsDataItem::addChildItem( QgsDataItem *child, bool refresh )
     730                 :            : {
     731                 :            :   Q_ASSERT( child );
     732                 :          0 :   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                 :          0 :   if ( type() == Directory )
     737                 :            :   {
     738                 :          0 :     for ( i = 0; i < mChildren.size(); i++ )
     739                 :            :     {
     740                 :            :       // sort items by type, so directories are before data items
     741                 :          0 :       if ( mChildren.at( i )->mType == child->mType &&
     742                 :          0 :            mChildren.at( i )->mName.localeAwareCompare( child->mName ) > 0 )
     743                 :          0 :         break;
     744                 :          0 :     }
     745                 :          0 :   }
     746                 :            :   else
     747                 :            :   {
     748                 :          0 :     for ( i = 0; i < mChildren.size(); i++ )
     749                 :            :     {
     750                 :          0 :       if ( mChildren.at( i )->mName.localeAwareCompare( child->mName ) >= 0 )
     751                 :          0 :         break;
     752                 :          0 :     }
     753                 :            :   }
     754                 :            : 
     755                 :          0 :   if ( refresh )
     756                 :          0 :     emit beginInsertItems( this, i, i );
     757                 :            : 
     758                 :          0 :   mChildren.insert( i, child );
     759                 :          0 :   child->setParent( this );
     760                 :            : 
     761                 :          0 :   if ( refresh )
     762                 :          0 :     emit endInsertItems();
     763                 :          0 : }
     764                 :            : 
     765                 :          0 : void QgsDataItem::deleteChildItem( QgsDataItem *child )
     766                 :            : {
     767                 :          0 :   QgsDebugMsgLevel( "mName = " + child->mName, 2 );
     768                 :          0 :   int i = mChildren.indexOf( child );
     769                 :            :   Q_ASSERT( i >= 0 );
     770                 :          0 :   emit beginRemoveItems( this, i, i );
     771                 :          0 :   mChildren.remove( i );
     772                 :          0 :   child->deleteLater();
     773                 :          0 :   emit endRemoveItems();
     774                 :          0 : }
     775                 :            : 
     776                 :          0 : QgsDataItem *QgsDataItem::removeChildItem( QgsDataItem *child )
     777                 :            : {
     778                 :          0 :   QgsDebugMsgLevel( "mName = " + child->mName, 2 );
     779                 :          0 :   int i = mChildren.indexOf( child );
     780                 :            :   Q_ASSERT( i >= 0 );
     781                 :          0 :   if ( i < 0 )
     782                 :            :   {
     783                 :          0 :     child->setParent( nullptr );
     784                 :          0 :     return nullptr;
     785                 :            :   }
     786                 :            : 
     787                 :          0 :   emit beginRemoveItems( this, i, i );
     788                 :          0 :   mChildren.remove( i );
     789                 :          0 :   emit endRemoveItems();
     790                 :          0 :   return child;
     791                 :          0 : }
     792                 :            : 
     793                 :          0 : int QgsDataItem::findItem( QVector<QgsDataItem *> items, QgsDataItem *item )
     794                 :            : {
     795                 :          0 :   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                 :          0 :     QgsDebugMsgLevel( QString::number( i ) + " : " + items[i]->mPath + " x " + item->mPath, 2 );
     799                 :          0 :     if ( items[i]->equal( item ) )
     800                 :          0 :       return i;
     801                 :          0 :   }
     802                 :          0 :   return -1;
     803                 :          0 : }
     804                 :            : 
     805                 :          0 : bool QgsDataItem::equal( const QgsDataItem *other )
     806                 :            : {
     807                 :          0 :   return ( metaObject()->className() == other->metaObject()->className() &&
     808                 :          0 :            mPath == other->path() );
     809                 :            : }
     810                 :            : 
     811                 :          0 : QList<QAction *> QgsDataItem::actions( QWidget *parent )
     812                 :            : {
     813                 :            :   Q_UNUSED( parent )
     814                 :          0 :   return QList<QAction *>();
     815                 :            : }
     816                 :            : 
     817                 :          0 : bool QgsDataItem::handleDoubleClick()
     818                 :            : {
     819                 :          0 :   return false;
     820                 :            : }
     821                 :            : 
     822                 :          0 : QgsMimeDataUtils::Uri QgsDataItem::mimeUri() const
     823                 :            : {
     824                 :          0 :   return mimeUris().isEmpty() ? QgsMimeDataUtils::Uri() : mimeUris().first();
     825                 :          0 : }
     826                 :            : 
     827                 :          0 : bool QgsDataItem::rename( const QString & )
     828                 :            : {
     829                 :          0 :   return false;
     830                 :            : }
     831                 :            : 
     832                 :          0 : QgsDataItem::State QgsDataItem::state() const
     833                 :            : {
     834                 :          0 :   return mState;
     835                 :            : }
     836                 :            : 
     837                 :          0 : void QgsDataItem::setState( State state )
     838                 :            : {
     839                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "item %1 set state %2 -> %3" ).arg( path() ).arg( this->state() ).arg( state ), 3 );
     840                 :          0 :   if ( state == mState )
     841                 :          0 :     return;
     842                 :            : 
     843                 :          0 :   State oldState = mState;
     844                 :            : 
     845                 :          0 :   if ( state == Populating ) // start loading
     846                 :            :   {
     847                 :          0 :     if ( !sPopulatingIcon )
     848                 :            :     {
     849                 :            :       // TODO: ensure that QgsAnimatedIcon is created on UI thread only
     850                 :          0 :       sPopulatingIcon = new QgsAnimatedIcon( QgsApplication::iconPath( QStringLiteral( "/mIconLoading.gif" ) ), QgsApplication::instance() );
     851                 :          0 :     }
     852                 :            : 
     853                 :          0 :     sPopulatingIcon->connectFrameChanged( this, &QgsDataItem::updateIcon );
     854                 :          0 :   }
     855                 :          0 :   else if ( mState == Populating && sPopulatingIcon ) // stop loading
     856                 :            :   {
     857                 :          0 :     sPopulatingIcon->disconnectFrameChanged( this, &QgsDataItem::updateIcon );
     858                 :          0 :   }
     859                 :            : 
     860                 :            : 
     861                 :          0 :   mState = state;
     862                 :            : 
     863                 :          0 :   emit stateChanged( this, oldState );
     864                 :          0 :   if ( state == Populated )
     865                 :          0 :     updateIcon();
     866                 :          0 : }
     867                 :            : 
     868                 :          0 : QList<QMenu *> QgsDataItem::menus( QWidget *parent )
     869                 :          0 : {
     870                 :            :   Q_UNUSED( parent )
     871                 :          0 :   return QList<QMenu *>();
     872                 :            : }
     873                 :            : 
     874                 :            : // ---------------------------------------------------------------------
     875                 :            : 
     876                 :          0 : QgsLayerItem::QgsLayerItem( QgsDataItem *parent, const QString &name, const QString &path,
     877                 :            :                             const QString &uri, LayerType layerType, const QString &providerKey )
     878                 :          0 :   : QgsDataItem( Layer, parent, name, path, providerKey )
     879                 :          0 :   , mUri( uri )
     880                 :          0 :   , mLayerType( layerType )
     881                 :          0 : {
     882                 :          0 :   mIconName = iconName( layerType );
     883                 :          0 : }
     884                 :            : 
     885                 :          0 : QgsMapLayerType QgsLayerItem::mapLayerType() const
     886                 :            : {
     887                 :          0 :   switch ( mLayerType )
     888                 :            :   {
     889                 :            :     case QgsLayerItem::Raster:
     890                 :          0 :       return QgsMapLayerType::RasterLayer;
     891                 :            : 
     892                 :            :     case QgsLayerItem::Mesh:
     893                 :          0 :       return QgsMapLayerType::MeshLayer;
     894                 :            : 
     895                 :            :     case QgsLayerItem::VectorTile:
     896                 :          0 :       return QgsMapLayerType::VectorTileLayer;
     897                 :            : 
     898                 :            :     case QgsLayerItem::Plugin:
     899                 :          0 :       return QgsMapLayerType::PluginLayer;
     900                 :            : 
     901                 :            :     case QgsLayerItem::PointCloud:
     902                 :          0 :       return QgsMapLayerType::PointCloudLayer;
     903                 :            : 
     904                 :            :     case QgsLayerItem::NoType:
     905                 :            :     case QgsLayerItem::Vector:
     906                 :            :     case QgsLayerItem::Point:
     907                 :            :     case QgsLayerItem::Polygon:
     908                 :            :     case QgsLayerItem::Line:
     909                 :            :     case QgsLayerItem::TableLayer:
     910                 :            :     case QgsLayerItem::Table:
     911                 :            :     case QgsLayerItem::Database:
     912                 :          0 :       return QgsMapLayerType::VectorLayer;
     913                 :            :   }
     914                 :            : 
     915                 :          0 :   return QgsMapLayerType::VectorLayer; // no warnings
     916                 :          0 : }
     917                 :            : 
     918                 :          0 : QgsLayerItem::LayerType QgsLayerItem::typeFromMapLayer( QgsMapLayer *layer )
     919                 :            : {
     920                 :          0 :   switch ( layer->type() )
     921                 :            :   {
     922                 :            :     case QgsMapLayerType::VectorLayer:
     923                 :            :     {
     924                 :          0 :       switch ( qobject_cast< QgsVectorLayer * >( layer )->geometryType() )
     925                 :            :       {
     926                 :            :         case QgsWkbTypes::PointGeometry:
     927                 :          0 :           return Point;
     928                 :            : 
     929                 :            :         case QgsWkbTypes::LineGeometry:
     930                 :          0 :           return Line;
     931                 :            : 
     932                 :            :         case QgsWkbTypes::PolygonGeometry:
     933                 :          0 :           return Polygon;
     934                 :            : 
     935                 :            :         case QgsWkbTypes::NullGeometry:
     936                 :          0 :           return TableLayer;
     937                 :            : 
     938                 :            :         case QgsWkbTypes::UnknownGeometry:
     939                 :          0 :           return Vector;
     940                 :            :       }
     941                 :            : 
     942                 :          0 :       return Vector; // no warnings
     943                 :            :     }
     944                 :            : 
     945                 :            :     case QgsMapLayerType::RasterLayer:
     946                 :          0 :       return Raster;
     947                 :            :     case QgsMapLayerType::PluginLayer:
     948                 :          0 :       return Plugin;
     949                 :            :     case QgsMapLayerType::MeshLayer:
     950                 :          0 :       return Mesh;
     951                 :            :     case QgsMapLayerType::PointCloudLayer:
     952                 :          0 :       return PointCloud;
     953                 :            :     case QgsMapLayerType::VectorTileLayer:
     954                 :          0 :       return VectorTile;
     955                 :            :     case QgsMapLayerType::AnnotationLayer:
     956                 :          0 :       return Vector; // will never happen!
     957                 :            :   }
     958                 :          0 :   return Vector; // no warnings
     959                 :          0 : }
     960                 :            : 
     961                 :          0 : QString QgsLayerItem::layerTypeAsString( QgsLayerItem::LayerType layerType )
     962                 :            : {
     963                 :          0 :   static int enumIdx = staticMetaObject.indexOfEnumerator( "LayerType" );
     964                 :          0 :   return staticMetaObject.enumerator( enumIdx ).valueToKey( layerType );
     965                 :          0 : }
     966                 :            : 
     967                 :          0 : QString QgsLayerItem::iconName( QgsLayerItem::LayerType layerType )
     968                 :            : {
     969                 :          0 :   switch ( layerType )
     970                 :            :   {
     971                 :            :     case Point:
     972                 :          0 :       return QStringLiteral( "/mIconPointLayer.svg" );
     973                 :            :     case Line:
     974                 :          0 :       return QStringLiteral( "/mIconLineLayer.svg" );
     975                 :            :     case Polygon:
     976                 :          0 :       return QStringLiteral( "/mIconPolygonLayer.svg" );
     977                 :            :     // TODO add a new icon for generic Vector layers
     978                 :            :     case Vector :
     979                 :          0 :       return QStringLiteral( "/mIconVector.svg" );
     980                 :            :     case TableLayer:
     981                 :            :     case Table:
     982                 :          0 :       return QStringLiteral( "/mIconTableLayer.svg" );
     983                 :            :     case Raster:
     984                 :          0 :       return QStringLiteral( "/mIconRaster.svg" );
     985                 :            :     case Mesh:
     986                 :          0 :       return QStringLiteral( "/mIconMeshLayer.svg" );
     987                 :            :     case PointCloud:
     988                 :          0 :       return QStringLiteral( "/mIconPointCloudLayer.svg" );
     989                 :            :     default:
     990                 :          0 :       return QStringLiteral( "/mIconLayer.png" );
     991                 :            :   }
     992                 :          0 : }
     993                 :            : 
     994                 :          0 : bool QgsLayerItem::deleteLayer()
     995                 :            : {
     996                 :          0 :   return false;
     997                 :            : }
     998                 :            : 
     999                 :          0 : bool QgsLayerItem::equal( const QgsDataItem *other )
    1000                 :            : {
    1001                 :            :   //QgsDebugMsg ( mPath + " x " + other->mPath );
    1002                 :          0 :   if ( type() != other->type() )
    1003                 :            :   {
    1004                 :          0 :     return false;
    1005                 :            :   }
    1006                 :            :   //const QgsLayerItem *o = qobject_cast<const QgsLayerItem *> ( other );
    1007                 :          0 :   const QgsLayerItem *o = qobject_cast<const QgsLayerItem *>( other );
    1008                 :          0 :   if ( !o )
    1009                 :          0 :     return false;
    1010                 :            : 
    1011                 :          0 :   return ( mPath == o->mPath && mName == o->mName && mUri == o->mUri && mProviderKey == o->mProviderKey );
    1012                 :          0 : }
    1013                 :            : 
    1014                 :          0 : QgsMimeDataUtils::UriList QgsLayerItem::mimeUris() const
    1015                 :            : {
    1016                 :          0 :   QgsMimeDataUtils::Uri u;
    1017                 :            : 
    1018                 :          0 :   switch ( mapLayerType() )
    1019                 :            :   {
    1020                 :            :     case QgsMapLayerType::VectorLayer:
    1021                 :          0 :       u.layerType = QStringLiteral( "vector" );
    1022                 :          0 :       switch ( mLayerType )
    1023                 :            :       {
    1024                 :            :         case Point:
    1025                 :          0 :           u.wkbType = QgsWkbTypes::Point;
    1026                 :          0 :           break;
    1027                 :            :         case Line:
    1028                 :          0 :           u.wkbType = QgsWkbTypes::LineString;
    1029                 :          0 :           break;
    1030                 :            :         case Polygon:
    1031                 :          0 :           u.wkbType = QgsWkbTypes::Polygon;
    1032                 :          0 :           break;
    1033                 :            :         case TableLayer:
    1034                 :          0 :           u.wkbType = QgsWkbTypes::NoGeometry;
    1035                 :          0 :           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                 :          0 :           break;
    1047                 :            :       }
    1048                 :          0 :       break;
    1049                 :            :     case QgsMapLayerType::RasterLayer:
    1050                 :          0 :       u.layerType = QStringLiteral( "raster" );
    1051                 :          0 :       break;
    1052                 :            :     case QgsMapLayerType::MeshLayer:
    1053                 :          0 :       u.layerType = QStringLiteral( "mesh" );
    1054                 :          0 :       break;
    1055                 :            :     case QgsMapLayerType::VectorTileLayer:
    1056                 :          0 :       u.layerType = QStringLiteral( "vector-tile" );
    1057                 :          0 :       break;
    1058                 :            :     case QgsMapLayerType::PointCloudLayer:
    1059                 :          0 :       u.layerType = QStringLiteral( "pointcloud" );
    1060                 :          0 :       break;
    1061                 :            :     case QgsMapLayerType::PluginLayer:
    1062                 :          0 :       u.layerType = QStringLiteral( "plugin" );
    1063                 :          0 :       break;
    1064                 :            :     case QgsMapLayerType::AnnotationLayer:
    1065                 :          0 :       u.layerType = QStringLiteral( "annotation" );
    1066                 :          0 :       break;
    1067                 :            :   }
    1068                 :            : 
    1069                 :          0 :   u.providerKey = providerKey();
    1070                 :          0 :   u.name = layerName();
    1071                 :          0 :   u.uri = uri();
    1072                 :          0 :   u.supportedCrs = supportedCrs();
    1073                 :          0 :   u.supportedFormats = supportedFormats();
    1074                 :          0 :   return { u };
    1075                 :          0 : }
    1076                 :            : 
    1077                 :            : // ---------------------------------------------------------------------
    1078                 :          0 : QgsDataCollectionItem::QgsDataCollectionItem( QgsDataItem *parent,
    1079                 :            :     const QString &name,
    1080                 :            :     const QString &path,
    1081                 :            :     const QString &providerKey )
    1082                 :          0 :   : QgsDataItem( Collection, parent, name, path, providerKey )
    1083                 :          0 : {
    1084                 :          0 :   mCapabilities = Fertile;
    1085                 :          0 :   mIconName = QStringLiteral( "/mIconDbSchema.svg" );
    1086                 :          0 : }
    1087                 :            : 
    1088                 :          0 : QgsDataCollectionItem::~QgsDataCollectionItem()
    1089                 :          0 : {
    1090                 :          0 :   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                 :          0 : }
    1102                 :            : 
    1103                 :            : //-----------------------------------------------------------------------
    1104                 :            : 
    1105                 :          0 : QgsDirectoryItem::QgsDirectoryItem( QgsDataItem *parent, const QString &name, const QString &path )
    1106                 :          0 :   : QgsDataCollectionItem( parent, QDir::toNativeSeparators( name ), path )
    1107                 :          0 :   , mDirPath( path )
    1108                 :          0 :   , mRefreshLater( false )
    1109                 :          0 : {
    1110                 :          0 :   mType = Directory;
    1111                 :          0 :   init();
    1112                 :          0 : }
    1113                 :            : 
    1114                 :          0 : QgsDirectoryItem::QgsDirectoryItem( QgsDataItem *parent, const QString &name,
    1115                 :            :                                     const QString &dirPath, const QString &path,
    1116                 :            :                                     const QString &providerKey )
    1117                 :          0 :   : QgsDataCollectionItem( parent, QDir::toNativeSeparators( name ), path, providerKey )
    1118                 :          0 :   , mDirPath( dirPath )
    1119                 :          0 :   , mRefreshLater( false )
    1120                 :          0 : {
    1121                 :          0 :   mType = Directory;
    1122                 :          0 :   init();
    1123                 :          0 : }
    1124                 :            : 
    1125                 :          0 : void QgsDirectoryItem::init()
    1126                 :            : {
    1127                 :          0 :   setToolTip( QDir::toNativeSeparators( mDirPath ) );
    1128                 :          0 : }
    1129                 :            : 
    1130                 :          0 : QIcon QgsDirectoryItem::icon()
    1131                 :            : {
    1132                 :          0 :   if ( mDirPath == QDir::homePath() )
    1133                 :          0 :     return homeDirIcon();
    1134                 :            : 
    1135                 :            :   // still loading? show the spinner
    1136                 :          0 :   if ( state() == Populating )
    1137                 :          0 :     return QgsDataItem::icon();
    1138                 :            : 
    1139                 :            :   // symbolic link? use link icon
    1140                 :          0 :   QFileInfo fi( mDirPath );
    1141                 :          0 :   if ( fi.isDir() && fi.isSymLink() )
    1142                 :            :   {
    1143                 :          0 :     return QgsApplication::getThemeIcon( QStringLiteral( "mIconFolderLink.svg" ) );
    1144                 :            :   }
    1145                 :            : 
    1146                 :            :   // loaded? show the open dir icon
    1147                 :          0 :   if ( state() == Populated )
    1148                 :          0 :     return openDirIcon();
    1149                 :            : 
    1150                 :            :   // show the closed dir icon
    1151                 :          0 :   return iconDir();
    1152                 :          0 : }
    1153                 :            : 
    1154                 :            : 
    1155                 :          0 : QVector<QgsDataItem *> QgsDirectoryItem::createChildren()
    1156                 :            : {
    1157                 :          0 :   QVector<QgsDataItem *> children;
    1158                 :          0 :   QDir dir( mDirPath );
    1159                 :            : 
    1160                 :          0 :   const QList<QgsDataItemProvider *> providers = QgsApplication::dataItemProviderRegistry()->providers();
    1161                 :            : 
    1162                 :          0 :   QStringList entries = dir.entryList( QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name | QDir::IgnoreCase );
    1163                 :          0 :   const auto constEntries = entries;
    1164                 :          0 :   for ( const QString &subdir : constEntries )
    1165                 :            :   {
    1166                 :          0 :     if ( mRefreshLater )
    1167                 :            :     {
    1168                 :          0 :       deleteLater( children );
    1169                 :          0 :       return children;
    1170                 :            :     }
    1171                 :            : 
    1172                 :          0 :     QString subdirPath = dir.absoluteFilePath( subdir );
    1173                 :            : 
    1174                 :          0 :     QgsDebugMsgLevel( QStringLiteral( "creating subdir: %1" ).arg( subdirPath ), 2 );
    1175                 :            : 
    1176                 :          0 :     QString path = mPath + '/' + subdir; // may differ from subdirPath
    1177                 :          0 :     if ( QgsDirectoryItem::hiddenPath( path ) )
    1178                 :          0 :       continue;
    1179                 :            : 
    1180                 :          0 :     bool handledByProvider = false;
    1181                 :          0 :     for ( QgsDataItemProvider *provider : providers )
    1182                 :            :     {
    1183                 :          0 :       if ( provider->handlesDirectoryPath( path ) )
    1184                 :            :       {
    1185                 :          0 :         handledByProvider = true;
    1186                 :          0 :         break;
    1187                 :            :       }
    1188                 :            :     }
    1189                 :          0 :     if ( handledByProvider )
    1190                 :          0 :       continue;
    1191                 :            : 
    1192                 :          0 :     QgsDirectoryItem *item = new QgsDirectoryItem( this, subdir, subdirPath, path );
    1193                 :            : 
    1194                 :            :     // we want directories shown before files
    1195                 :          0 :     item->setSortKey( QStringLiteral( "  %1" ).arg( subdir ) );
    1196                 :            : 
    1197                 :            :     // propagate signals up to top
    1198                 :            : 
    1199                 :          0 :     children.append( item );
    1200                 :          0 :   }
    1201                 :            : 
    1202                 :          0 :   QStringList fileEntries = dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot | QDir::Files, QDir::Name );
    1203                 :          0 :   const auto constFileEntries = fileEntries;
    1204                 :          0 :   for ( const QString &name : constFileEntries )
    1205                 :            :   {
    1206                 :          0 :     if ( mRefreshLater )
    1207                 :            :     {
    1208                 :          0 :       deleteLater( children );
    1209                 :          0 :       return children;
    1210                 :            :     }
    1211                 :            : 
    1212                 :          0 :     QString path = dir.absoluteFilePath( name );
    1213                 :          0 :     QFileInfo fileInfo( path );
    1214                 :            : 
    1215                 :          0 :     if ( fileInfo.suffix().compare( QLatin1String( "zip" ), Qt::CaseInsensitive ) == 0 ||
    1216                 :          0 :          fileInfo.suffix().compare( QLatin1String( "tar" ), Qt::CaseInsensitive ) == 0 )
    1217                 :            :     {
    1218                 :          0 :       QgsDataItem *item = QgsZipItem::itemFromPath( this, path, name, mPath + '/' + name );
    1219                 :          0 :       if ( item )
    1220                 :            :       {
    1221                 :          0 :         children.append( item );
    1222                 :          0 :         continue;
    1223                 :            :       }
    1224                 :          0 :     }
    1225                 :            : 
    1226                 :          0 :     bool createdItem = false;
    1227                 :          0 :     for ( QgsDataItemProvider *provider : providers )
    1228                 :            :     {
    1229                 :          0 :       int capabilities = provider->capabilities();
    1230                 :            : 
    1231                 :          0 :       if ( !( ( fileInfo.isFile() && ( capabilities & QgsDataProvider::File ) ) ||
    1232                 :          0 :               ( fileInfo.isDir() && ( capabilities & QgsDataProvider::Dir ) ) ) )
    1233                 :            :       {
    1234                 :          0 :         continue;
    1235                 :            :       }
    1236                 :            : 
    1237                 :          0 :       QgsDataItem *item = provider->createDataItem( path, this );
    1238                 :          0 :       if ( item )
    1239                 :            :       {
    1240                 :          0 :         children.append( item );
    1241                 :          0 :         createdItem = true;
    1242                 :          0 :       }
    1243                 :            :     }
    1244                 :            : 
    1245                 :          0 :     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                 :          0 :       if ( fileInfo.suffix().compare( QLatin1String( "qgs" ), Qt::CaseInsensitive ) == 0 ||
    1250                 :          0 :            fileInfo.suffix().compare( QLatin1String( "qgz" ), Qt::CaseInsensitive ) == 0 )
    1251                 :            :       {
    1252                 :          0 :         QgsDataItem *item = new QgsProjectItem( this, fileInfo.completeBaseName(), path );
    1253                 :          0 :         children.append( item );
    1254                 :          0 :         continue;
    1255                 :            :       }
    1256                 :          0 :     }
    1257                 :            : 
    1258                 :          0 :   }
    1259                 :          0 :   return children;
    1260                 :          0 : }
    1261                 :            : 
    1262                 :          0 : void QgsDirectoryItem::setState( State state )
    1263                 :            : {
    1264                 :          0 :   QgsDataCollectionItem::setState( state );
    1265                 :            : 
    1266                 :          0 :   if ( state == Populated )
    1267                 :            :   {
    1268                 :          0 :     if ( !mFileSystemWatcher )
    1269                 :            :     {
    1270                 :          0 :       mFileSystemWatcher = new QFileSystemWatcher( this );
    1271                 :          0 :       mFileSystemWatcher->addPath( mDirPath );
    1272                 :          0 :       connect( mFileSystemWatcher, &QFileSystemWatcher::directoryChanged, this, &QgsDirectoryItem::directoryChanged );
    1273                 :          0 :     }
    1274                 :          0 :     mLastScan = QDateTime::currentDateTime();
    1275                 :          0 :   }
    1276                 :          0 :   else if ( state == NotPopulated )
    1277                 :            :   {
    1278                 :          0 :     if ( mFileSystemWatcher )
    1279                 :            :     {
    1280                 :          0 :       delete mFileSystemWatcher;
    1281                 :          0 :       mFileSystemWatcher = nullptr;
    1282                 :          0 :     }
    1283                 :          0 :   }
    1284                 :          0 : }
    1285                 :            : 
    1286                 :          0 : void QgsDirectoryItem::directoryChanged()
    1287                 :            : {
    1288                 :            :   // If the last scan was less than 10 seconds ago, skip this
    1289                 :          0 :   if ( mLastScan.msecsTo( QDateTime::currentDateTime() ) < QgsSettings().value( QStringLiteral( "browser/minscaninterval" ), 10000 ).toInt() )
    1290                 :            :   {
    1291                 :          0 :     return;
    1292                 :            :   }
    1293                 :          0 :   if ( state() == Populating )
    1294                 :            :   {
    1295                 :            :     // schedule to refresh later, because refresh() simply returns if Populating
    1296                 :          0 :     mRefreshLater = true;
    1297                 :          0 :   }
    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                 :          0 :     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                 :          0 :     QTimer::singleShot( 100, this, [ = ] { refresh(); } );
    1311                 :            :   }
    1312                 :          0 : }
    1313                 :            : 
    1314                 :          0 : bool QgsDirectoryItem::hiddenPath( const QString &path )
    1315                 :            : {
    1316                 :          0 :   QgsSettings settings;
    1317                 :          0 :   QStringList hiddenItems = settings.value( QStringLiteral( "browser/hiddenPaths" ),
    1318                 :          0 :                             QStringList() ).toStringList();
    1319                 :          0 :   int idx = hiddenItems.indexOf( path );
    1320                 :          0 :   return ( idx > -1 );
    1321                 :          0 : }
    1322                 :            : 
    1323                 :          0 : void QgsDirectoryItem::childrenCreated()
    1324                 :            : {
    1325                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "mRefreshLater = %1" ).arg( mRefreshLater ), 3 );
    1326                 :            : 
    1327                 :          0 :   if ( mRefreshLater )
    1328                 :            :   {
    1329                 :          0 :     QgsDebugMsgLevel( QStringLiteral( "directory changed during createChidren() -> refresh() again" ), 3 );
    1330                 :          0 :     mRefreshLater = false;
    1331                 :          0 :     setState( Populated );
    1332                 :          0 :     refresh();
    1333                 :          0 :   }
    1334                 :            :   else
    1335                 :            :   {
    1336                 :          0 :     QgsDataCollectionItem::childrenCreated();
    1337                 :            :   }
    1338                 :            :   // Re-connect the file watcher after all children have been created
    1339                 :          0 :   connect( mFileSystemWatcher, &QFileSystemWatcher::directoryChanged, this, &QgsDirectoryItem::directoryChanged );
    1340                 :          0 : }
    1341                 :            : 
    1342                 :          0 : bool QgsDirectoryItem::equal( const QgsDataItem *other )
    1343                 :            : {
    1344                 :            :   //QgsDebugMsg ( mPath + " x " + other->mPath );
    1345                 :          0 :   if ( type() != other->type() )
    1346                 :            :   {
    1347                 :          0 :     return false;
    1348                 :            :   }
    1349                 :          0 :   return ( path() == other->path() );
    1350                 :          0 : }
    1351                 :            : 
    1352                 :          0 : QWidget *QgsDirectoryItem::paramWidget()
    1353                 :            : {
    1354                 :          0 :   return new QgsDirectoryParamWidget( mPath );
    1355                 :          0 : }
    1356                 :            : 
    1357                 :          0 : QgsMimeDataUtils::UriList QgsDirectoryItem::mimeUris() const
    1358                 :            : {
    1359                 :          0 :   QgsMimeDataUtils::Uri u;
    1360                 :          0 :   u.layerType = QStringLiteral( "directory" );
    1361                 :          0 :   u.name = mName;
    1362                 :          0 :   u.uri = mDirPath;
    1363                 :          0 :   return { u };
    1364                 :          0 : }
    1365                 :            : 
    1366                 :          0 : QgsDirectoryParamWidget::QgsDirectoryParamWidget( const QString &path, QWidget *parent )
    1367                 :          0 :   : QTreeWidget( parent )
    1368                 :          0 : {
    1369                 :          0 :   setRootIsDecorated( false );
    1370                 :            : 
    1371                 :            :   // name, size, date, permissions, owner, group, type
    1372                 :          0 :   setColumnCount( 7 );
    1373                 :          0 :   QStringList labels;
    1374                 :          0 :   labels << tr( "Name" ) << tr( "Size" ) << tr( "Date" ) << tr( "Permissions" ) << tr( "Owner" ) << tr( "Group" ) << tr( "Type" );
    1375                 :          0 :   setHeaderLabels( labels );
    1376                 :            : 
    1377                 :          0 :   QIcon iconDirectory = QgsApplication::getThemeIcon( QStringLiteral( "mIconFolder.svg" ) );
    1378                 :          0 :   QIcon iconFile = QgsApplication::getThemeIcon( QStringLiteral( "mIconFile.svg" ) );
    1379                 :          0 :   QIcon iconDirLink = QgsApplication::getThemeIcon( QStringLiteral( "mIconFolderLink.svg" ) );
    1380                 :          0 :   QIcon iconFileLink = QgsApplication::getThemeIcon( QStringLiteral( "mIconFileLink.svg" ) );
    1381                 :            : 
    1382                 :          0 :   QList<QTreeWidgetItem *> items;
    1383                 :            : 
    1384                 :          0 :   QDir dir( path );
    1385                 :          0 :   QStringList entries = dir.entryList( QDir::AllEntries | QDir::NoDotAndDotDot, QDir::Name | QDir::IgnoreCase );
    1386                 :          0 :   const auto constEntries = entries;
    1387                 :          0 :   for ( const QString &name : constEntries )
    1388                 :            :   {
    1389                 :          0 :     QFileInfo fi( dir.absoluteFilePath( name ) );
    1390                 :          0 :     QStringList texts;
    1391                 :          0 :     texts << name;
    1392                 :          0 :     QString size;
    1393                 :          0 :     if ( fi.size() > 1024 )
    1394                 :            :     {
    1395                 :          0 :       size = QStringLiteral( "%1 KiB" ).arg( QString::number( fi.size() / 1024.0, 'f', 1 ) );
    1396                 :          0 :     }
    1397                 :          0 :     else if ( fi.size() > 1.048576e6 )
    1398                 :            :     {
    1399                 :          0 :       size = QStringLiteral( "%1 MiB" ).arg( QString::number( fi.size() / 1.048576e6, 'f', 1 ) );
    1400                 :          0 :     }
    1401                 :            :     else
    1402                 :            :     {
    1403                 :          0 :       size = QStringLiteral( "%1 B" ).arg( fi.size() );
    1404                 :            :     }
    1405                 :          0 :     texts << size;
    1406                 :          0 :     texts << QLocale().toString( fi.lastModified(), QLocale::ShortFormat );
    1407                 :          0 :     QString perm;
    1408                 :          0 :     perm += fi.permission( QFile::ReadOwner ) ? 'r' : '-';
    1409                 :          0 :     perm += fi.permission( QFile::WriteOwner ) ? 'w' : '-';
    1410                 :          0 :     perm += fi.permission( QFile::ExeOwner ) ? 'x' : '-';
    1411                 :            :     // QFile::ReadUser, QFile::WriteUser, QFile::ExeUser
    1412                 :          0 :     perm += fi.permission( QFile::ReadGroup ) ? 'r' : '-';
    1413                 :          0 :     perm += fi.permission( QFile::WriteGroup ) ? 'w' : '-';
    1414                 :          0 :     perm += fi.permission( QFile::ExeGroup ) ? 'x' : '-';
    1415                 :          0 :     perm += fi.permission( QFile::ReadOther ) ? 'r' : '-';
    1416                 :          0 :     perm += fi.permission( QFile::WriteOther ) ? 'w' : '-';
    1417                 :          0 :     perm += fi.permission( QFile::ExeOther ) ? 'x' : '-';
    1418                 :          0 :     texts << perm;
    1419                 :            : 
    1420                 :          0 :     texts << fi.owner();
    1421                 :          0 :     texts << fi.group();
    1422                 :            : 
    1423                 :          0 :     QString type;
    1424                 :          0 :     QIcon icon;
    1425                 :          0 :     if ( fi.isDir() && fi.isSymLink() )
    1426                 :            :     {
    1427                 :          0 :       type = tr( "folder" );
    1428                 :          0 :       icon = iconDirLink;
    1429                 :          0 :     }
    1430                 :          0 :     else if ( fi.isDir() )
    1431                 :            :     {
    1432                 :          0 :       type = tr( "folder" );
    1433                 :          0 :       icon = iconDirectory;
    1434                 :          0 :     }
    1435                 :          0 :     else if ( fi.isFile() && fi.isSymLink() )
    1436                 :            :     {
    1437                 :          0 :       type = tr( "file" );
    1438                 :          0 :       icon = iconFileLink;
    1439                 :          0 :     }
    1440                 :          0 :     else if ( fi.isFile() )
    1441                 :            :     {
    1442                 :          0 :       type = tr( "file" );
    1443                 :          0 :       icon = iconFile;
    1444                 :          0 :     }
    1445                 :            : 
    1446                 :          0 :     texts << type;
    1447                 :            : 
    1448                 :          0 :     QTreeWidgetItem *item = new QTreeWidgetItem( texts );
    1449                 :          0 :     item->setIcon( 0, icon );
    1450                 :          0 :     items << item;
    1451                 :          0 :   }
    1452                 :            : 
    1453                 :          0 :   addTopLevelItems( items );
    1454                 :            : 
    1455                 :            :   // hide columns that are not requested
    1456                 :          0 :   QgsSettings settings;
    1457                 :          0 :   QList<QVariant> lst = settings.value( QStringLiteral( "dataitem/directoryHiddenColumns" ) ).toList();
    1458                 :          0 :   const auto constLst = lst;
    1459                 :          0 :   for ( const QVariant &colVariant : constLst )
    1460                 :            :   {
    1461                 :          0 :     setColumnHidden( colVariant.toInt(), true );
    1462                 :            :   }
    1463                 :          0 : }
    1464                 :            : 
    1465                 :          0 : void QgsDirectoryParamWidget::mousePressEvent( QMouseEvent *event )
    1466                 :            : {
    1467                 :          0 :   if ( event->button() == Qt::RightButton )
    1468                 :            :   {
    1469                 :            :     // show the popup menu
    1470                 :          0 :     QMenu popupMenu;
    1471                 :            : 
    1472                 :          0 :     QStringList labels;
    1473                 :          0 :     labels << tr( "Name" ) << tr( "Size" ) << tr( "Date" ) << tr( "Permissions" ) << tr( "Owner" ) << tr( "Group" ) << tr( "Type" );
    1474                 :          0 :     for ( int i = 0; i < labels.count(); i++ )
    1475                 :            :     {
    1476                 :          0 :       QAction *action = popupMenu.addAction( labels[i], this, &QgsDirectoryParamWidget::showHideColumn );
    1477                 :          0 :       action->setObjectName( QString::number( i ) );
    1478                 :          0 :       action->setCheckable( true );
    1479                 :          0 :       action->setChecked( !isColumnHidden( i ) );
    1480                 :          0 :     }
    1481                 :            : 
    1482                 :          0 :     popupMenu.exec( event->globalPos() );
    1483                 :          0 :   }
    1484                 :          0 : }
    1485                 :            : 
    1486                 :          0 : void QgsDirectoryParamWidget::showHideColumn()
    1487                 :            : {
    1488                 :          0 :   QAction *action = qobject_cast<QAction *>( sender() );
    1489                 :          0 :   if ( !action )
    1490                 :          0 :     return; // something is wrong
    1491                 :            : 
    1492                 :          0 :   int columnIndex = action->objectName().toInt();
    1493                 :          0 :   setColumnHidden( columnIndex, !isColumnHidden( columnIndex ) );
    1494                 :            : 
    1495                 :            :   // save in settings
    1496                 :          0 :   QgsSettings settings;
    1497                 :          0 :   QList<QVariant> lst;
    1498                 :          0 :   for ( int i = 0; i < columnCount(); i++ )
    1499                 :            :   {
    1500                 :          0 :     if ( isColumnHidden( i ) )
    1501                 :          0 :       lst.append( QVariant( i ) );
    1502                 :          0 :   }
    1503                 :          0 :   settings.setValue( QStringLiteral( "dataitem/directoryHiddenColumns" ), lst );
    1504                 :          0 : }
    1505                 :            : 
    1506                 :          0 : QgsProjectItem::QgsProjectItem( QgsDataItem *parent, const QString &name,
    1507                 :            :                                 const QString &path, const QString &providerKey )
    1508                 :          0 :   : QgsDataItem( QgsDataItem::Project, parent, name, path, providerKey )
    1509                 :          0 : {
    1510                 :          0 :   mIconName = QStringLiteral( ":/images/icons/qgis_icon.svg" );
    1511                 :          0 :   setToolTip( QDir::toNativeSeparators( path ) );
    1512                 :          0 :   setState( Populated ); // no more children
    1513                 :          0 : }
    1514                 :            : 
    1515                 :          0 : QgsMimeDataUtils::UriList QgsProjectItem::mimeUris() const
    1516                 :            : {
    1517                 :          0 :   QgsMimeDataUtils::Uri u;
    1518                 :          0 :   u.layerType = QStringLiteral( "project" );
    1519                 :          0 :   u.name = mName;
    1520                 :          0 :   u.uri = mPath;
    1521                 :          0 :   return { u };
    1522                 :          0 : }
    1523                 :            : 
    1524                 :          0 : QgsErrorItem::QgsErrorItem( QgsDataItem *parent, const QString &error, const QString &path )
    1525                 :          0 :   : QgsDataItem( QgsDataItem::Error, parent, error, path )
    1526                 :          0 : {
    1527                 :          0 :   mIconName = QStringLiteral( "/mIconDelete.svg" );
    1528                 :            : 
    1529                 :          0 :   setState( Populated ); // no more children
    1530                 :          0 : }
    1531                 :            : 
    1532                 :          0 : QgsFavoritesItem::QgsFavoritesItem( QgsDataItem *parent, const QString &name, const QString &path )
    1533                 :          0 :   : QgsDataCollectionItem( parent, name, QStringLiteral( "favorites:" ), QStringLiteral( "special:Favorites" ) )
    1534                 :          0 : {
    1535                 :          0 :   Q_UNUSED( path )
    1536                 :          0 :   mCapabilities |= Fast;
    1537                 :          0 :   mType = Favorites;
    1538                 :          0 :   mIconName = QStringLiteral( "/mIconFavorites.svg" );
    1539                 :          0 :   populate();
    1540                 :          0 : }
    1541                 :            : 
    1542                 :          0 : QVector<QgsDataItem *> QgsFavoritesItem::createChildren()
    1543                 :            : {
    1544                 :          0 :   QVector<QgsDataItem *> children;
    1545                 :            : 
    1546                 :          0 :   QgsSettings settings;
    1547                 :            : 
    1548                 :          0 :   const QStringList favDirs = settings.value( QStringLiteral( "browser/favourites" ), QVariant() ).toStringList();
    1549                 :            : 
    1550                 :          0 :   for ( const QString &favDir : favDirs )
    1551                 :            :   {
    1552                 :          0 :     QStringList parts = favDir.split( QStringLiteral( "|||" ) );
    1553                 :          0 :     if ( parts.empty() )
    1554                 :          0 :       continue;
    1555                 :            : 
    1556                 :          0 :     QString dir = parts.at( 0 );
    1557                 :          0 :     QString name = dir;
    1558                 :          0 :     if ( parts.count() > 1 )
    1559                 :          0 :       name = parts.at( 1 );
    1560                 :            : 
    1561                 :          0 :     children << createChildren( dir, name );
    1562                 :          0 :   }
    1563                 :            : 
    1564                 :          0 :   return children;
    1565                 :          0 : }
    1566                 :            : 
    1567                 :          0 : void QgsFavoritesItem::addDirectory( const QString &favDir, const QString &n )
    1568                 :            : {
    1569                 :          0 :   QString name = n.isEmpty() ? favDir : n;
    1570                 :            : 
    1571                 :          0 :   QgsSettings settings;
    1572                 :          0 :   QStringList favDirs = settings.value( QStringLiteral( "browser/favourites" ) ).toStringList();
    1573                 :          0 :   favDirs.append( QStringLiteral( "%1|||%2" ).arg( favDir, name ) );
    1574                 :          0 :   settings.setValue( QStringLiteral( "browser/favourites" ), favDirs );
    1575                 :            : 
    1576                 :          0 :   if ( state() == Populated )
    1577                 :            :   {
    1578                 :          0 :     QVector<QgsDataItem *> items = createChildren( favDir, name );
    1579                 :          0 :     const auto constItems = items;
    1580                 :          0 :     for ( QgsDataItem *item : constItems )
    1581                 :            :     {
    1582                 :          0 :       addChildItem( item, true );
    1583                 :            :     }
    1584                 :          0 :   }
    1585                 :          0 : }
    1586                 :            : 
    1587                 :          0 : void QgsFavoritesItem::removeDirectory( QgsDirectoryItem *item )
    1588                 :            : {
    1589                 :          0 :   if ( !item )
    1590                 :          0 :     return;
    1591                 :            : 
    1592                 :          0 :   QgsSettings settings;
    1593                 :          0 :   QStringList favDirs = settings.value( QStringLiteral( "browser/favourites" ) ).toStringList();
    1594                 :          0 :   for ( int i = favDirs.count() - 1; i >= 0; --i )
    1595                 :            :   {
    1596                 :          0 :     QStringList parts = favDirs.at( i ).split( QStringLiteral( "|||" ) );
    1597                 :          0 :     if ( parts.empty() )
    1598                 :          0 :       continue;
    1599                 :            : 
    1600                 :          0 :     QString dir = parts.at( 0 );
    1601                 :          0 :     if ( dir == item->dirPath() )
    1602                 :          0 :       favDirs.removeAt( i );
    1603                 :          0 :   }
    1604                 :          0 :   settings.setValue( QStringLiteral( "browser/favourites" ), favDirs );
    1605                 :            : 
    1606                 :          0 :   int idx = findItem( mChildren, item );
    1607                 :          0 :   if ( idx < 0 )
    1608                 :            :   {
    1609                 :          0 :     QgsDebugMsg( QStringLiteral( "favorites item %1 not found" ).arg( item->path() ) );
    1610                 :          0 :     return;
    1611                 :            :   }
    1612                 :            : 
    1613                 :          0 :   if ( state() == Populated )
    1614                 :          0 :     deleteChildItem( mChildren.at( idx ) );
    1615                 :          0 : }
    1616                 :            : 
    1617                 :          0 : void QgsFavoritesItem::renameFavorite( const QString &path, const QString &name )
    1618                 :            : {
    1619                 :            :   // update stored name
    1620                 :          0 :   QgsSettings settings;
    1621                 :          0 :   QStringList favDirs = settings.value( QStringLiteral( "browser/favourites" ) ).toStringList();
    1622                 :          0 :   for ( int i = 0; i < favDirs.count(); ++i )
    1623                 :            :   {
    1624                 :          0 :     QStringList parts = favDirs.at( i ).split( QStringLiteral( "|||" ) );
    1625                 :          0 :     if ( parts.empty() )
    1626                 :          0 :       continue;
    1627                 :            : 
    1628                 :          0 :     QString dir = parts.at( 0 );
    1629                 :          0 :     if ( dir == path )
    1630                 :            :     {
    1631                 :          0 :       favDirs[i] = QStringLiteral( "%1|||%2" ).arg( path, name );
    1632                 :          0 :       break;
    1633                 :            :     }
    1634                 :          0 :   }
    1635                 :          0 :   settings.setValue( QStringLiteral( "browser/favourites" ), favDirs );
    1636                 :            : 
    1637                 :            :   // also update existing data item
    1638                 :          0 :   const QVector<QgsDataItem *> ch = children();
    1639                 :          0 :   for ( QgsDataItem *child : ch )
    1640                 :            :   {
    1641                 :          0 :     if ( QgsFavoriteItem *favorite = qobject_cast< QgsFavoriteItem * >( child ) )
    1642                 :            :     {
    1643                 :          0 :       if ( favorite->dirPath() == path )
    1644                 :            :       {
    1645                 :          0 :         favorite->setName( name );
    1646                 :          0 :         break;
    1647                 :            :       }
    1648                 :          0 :     }
    1649                 :            :   }
    1650                 :          0 : }
    1651                 :            : 
    1652                 :          0 : QVector<QgsDataItem *> QgsFavoritesItem::createChildren( const QString &favDir, const QString &name )
    1653                 :            : {
    1654                 :          0 :   QVector<QgsDataItem *> children;
    1655                 :          0 :   QString pathName = pathComponent( favDir );
    1656                 :          0 :   const auto constProviders = QgsApplication::dataItemProviderRegistry()->providers();
    1657                 :          0 :   for ( QgsDataItemProvider *provider : constProviders )
    1658                 :            :   {
    1659                 :          0 :     int capabilities = provider->capabilities();
    1660                 :            : 
    1661                 :          0 :     if ( capabilities & QgsDataProvider::Dir )
    1662                 :            :     {
    1663                 :          0 :       QgsDataItem *item = provider->createDataItem( favDir, this );
    1664                 :          0 :       if ( item )
    1665                 :            :       {
    1666                 :          0 :         item->setName( name );
    1667                 :          0 :         children.append( item );
    1668                 :          0 :       }
    1669                 :          0 :     }
    1670                 :            :   }
    1671                 :          0 :   if ( children.isEmpty() )
    1672                 :            :   {
    1673                 :          0 :     QgsFavoriteItem *item = new QgsFavoriteItem( this, name, favDir, mPath + '/' + pathName );
    1674                 :          0 :     if ( item )
    1675                 :            :     {
    1676                 :          0 :       children.append( item );
    1677                 :          0 :     }
    1678                 :          0 :   }
    1679                 :          0 :   return children;
    1680                 :          0 : }
    1681                 :            : 
    1682                 :            : //-----------------------------------------------------------------------
    1683                 :          5 : QStringList QgsZipItem::sProviderNames = QStringList();
    1684                 :            : 
    1685                 :            : 
    1686                 :          0 : QgsZipItem::QgsZipItem( QgsDataItem *parent, const QString &name, const QString &path )
    1687                 :          0 :   : QgsDataCollectionItem( parent, name, path )
    1688                 :          0 : {
    1689                 :          0 :   mFilePath = path;
    1690                 :          0 :   init();
    1691                 :          0 : }
    1692                 :            : 
    1693                 :          0 : QgsZipItem::QgsZipItem( QgsDataItem *parent, const QString &name,
    1694                 :            :                         const QString &filePath, const QString &path,
    1695                 :            :                         const QString &providerKey )
    1696                 :          0 :   : QgsDataCollectionItem( parent, name, path, providerKey )
    1697                 :          0 :   , mFilePath( filePath )
    1698                 :          0 : {
    1699                 :          0 :   init();
    1700                 :          0 : }
    1701                 :            : 
    1702                 :          0 : void QgsZipItem::init()
    1703                 :            : {
    1704                 :          0 :   mType = Collection; //Zip??
    1705                 :          0 :   mIconName = QStringLiteral( "/mIconZip.svg" );
    1706                 :          0 :   mVsiPrefix = vsiPrefix( mFilePath );
    1707                 :            : 
    1708                 :            :   static std::once_flag initialized;
    1709                 :          0 :   std::call_once( initialized, [ = ]
    1710                 :            :   {
    1711                 :          0 :     sProviderNames << QStringLiteral( "OGR" ) << QStringLiteral( "GDAL" );
    1712                 :          0 :   } );
    1713                 :          0 : }
    1714                 :            : 
    1715                 :          0 : QVector<QgsDataItem *> QgsZipItem::createChildren()
    1716                 :            : {
    1717                 :          0 :   QVector<QgsDataItem *> children;
    1718                 :          0 :   QString tmpPath;
    1719                 :          0 :   QgsSettings settings;
    1720                 :          0 :   QString scanZipSetting = settings.value( QStringLiteral( "qgis/scanZipInBrowser2" ), "basic" ).toString();
    1721                 :            : 
    1722                 :          0 :   mZipFileList.clear();
    1723                 :            : 
    1724                 :          0 :   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                 :          0 :   if ( scanZipSetting == QLatin1String( "no" ) )
    1728                 :            :   {
    1729                 :          0 :     return children;
    1730                 :            :   }
    1731                 :            : 
    1732                 :            :   // first get list of files
    1733                 :          0 :   getZipFileList();
    1734                 :            : 
    1735                 :          0 :   const QList<QgsDataItemProvider *> providers = QgsApplication::dataItemProviderRegistry()->providers();
    1736                 :            : 
    1737                 :            :   // loop over files inside zip
    1738                 :          0 :   const auto constMZipFileList = mZipFileList;
    1739                 :          0 :   for ( const QString &fileName : constMZipFileList )
    1740                 :            :   {
    1741                 :          0 :     QFileInfo info( fileName );
    1742                 :          0 :     tmpPath = mVsiPrefix + mFilePath + '/' + fileName;
    1743                 :          0 :     QgsDebugMsgLevel( "tmpPath = " + tmpPath, 3 );
    1744                 :            : 
    1745                 :          0 :     for ( QgsDataItemProvider *provider : providers )
    1746                 :            :     {
    1747                 :          0 :       if ( !sProviderNames.contains( provider->name() ) )
    1748                 :          0 :         continue;
    1749                 :            : 
    1750                 :            :       // ugly hack to remove .dbf file if there is a .shp file
    1751                 :          0 :       if ( provider->name() == QLatin1String( "OGR" ) )
    1752                 :            :       {
    1753                 :          0 :         if ( info.suffix().compare( QLatin1String( "dbf" ), Qt::CaseInsensitive ) == 0 )
    1754                 :            :         {
    1755                 :          0 :           if ( mZipFileList.indexOf( fileName.left( fileName.count() - 4 ) + ".shp" ) != -1 )
    1756                 :          0 :             continue;
    1757                 :          0 :         }
    1758                 :          0 :         if ( info.completeSuffix().compare( QLatin1String( "shp.xml" ), Qt::CaseInsensitive ) == 0 )
    1759                 :            :         {
    1760                 :          0 :           continue;
    1761                 :            :         }
    1762                 :          0 :       }
    1763                 :            : 
    1764                 :          0 :       QgsDebugMsgLevel( QStringLiteral( "trying to load item %1 with %2" ).arg( tmpPath, provider->name() ), 3 );
    1765                 :          0 :       QgsDataItem *item = provider->createDataItem( tmpPath, this );
    1766                 :          0 :       if ( item )
    1767                 :            :       {
    1768                 :            :         // the item comes with zipped file name, set the name to relative path within zip file
    1769                 :          0 :         item->setName( fileName );
    1770                 :          0 :         children.append( item );
    1771                 :          0 :       }
    1772                 :            :       else
    1773                 :            :       {
    1774                 :          0 :         QgsDebugMsgLevel( QStringLiteral( "not loaded item" ), 3 );
    1775                 :            :       }
    1776                 :            :     }
    1777                 :          0 :   }
    1778                 :            : 
    1779                 :          0 :   return children;
    1780                 :          0 : }
    1781                 :            : 
    1782                 :          0 : QgsDataItem *QgsZipItem::itemFromPath( QgsDataItem *parent, const QString &path, const QString &name )
    1783                 :            : {
    1784                 :          0 :   return itemFromPath( parent, path, name, path );
    1785                 :            : }
    1786                 :            : 
    1787                 :          0 : QgsDataItem *QgsZipItem::itemFromPath( QgsDataItem *parent, const QString &filePath, const QString &name, const QString &path )
    1788                 :            : {
    1789                 :          0 :   QgsSettings settings;
    1790                 :          0 :   QString scanZipSetting = settings.value( QStringLiteral( "qgis/scanZipInBrowser2" ), "basic" ).toString();
    1791                 :          0 :   QStringList zipFileList;
    1792                 :          0 :   QString vsiPrefix = QgsZipItem::vsiPrefix( filePath );
    1793                 :          0 :   QgsZipItem *zipItem = nullptr;
    1794                 :          0 :   bool populated = false;
    1795                 :            : 
    1796                 :          0 :   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                 :          0 :   if ( scanZipSetting == QLatin1String( "no" ) )
    1800                 :          0 :     return nullptr;
    1801                 :            : 
    1802                 :            :   // don't scan if this file is not a /vsizip/ or /vsitar/ item
    1803                 :          0 :   if ( ( vsiPrefix != QLatin1String( "/vsizip/" ) && vsiPrefix != QLatin1String( "/vsitar/" ) ) )
    1804                 :          0 :     return nullptr;
    1805                 :            : 
    1806                 :          0 :   zipItem = new QgsZipItem( parent, name, filePath, path );
    1807                 :            : 
    1808                 :          0 :   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                 :          0 :     if ( path.endsWith( QLatin1String( ".zip" ), Qt::CaseInsensitive ) ||
    1817                 :          0 :          path.endsWith( QLatin1String( ".tar" ), Qt::CaseInsensitive ) )
    1818                 :            :     {
    1819                 :          0 :       zipFileList = zipItem->getZipFileList();
    1820                 :          0 :     }
    1821                 :            :     // force populate if less than 10 items
    1822                 :          0 :     if ( !zipFileList.isEmpty() && zipFileList.count() <= 10 )
    1823                 :            :     {
    1824                 :          0 :       zipItem->populate( zipItem->createChildren() );
    1825                 :          0 :       populated = true; // there is no QgsDataItem::isPopulated() function
    1826                 :          0 :       QgsDebugMsgLevel( QStringLiteral( "Got zipItem with %1 children, path=%2, name=%3" ).arg( zipItem->rowCount() ).arg( zipItem->path(), zipItem->name() ), 3 );
    1827                 :          0 :     }
    1828                 :            :     else
    1829                 :            :     {
    1830                 :          0 :       QgsDebugMsgLevel( QStringLiteral( "Delaying populating zipItem with path=%1, name=%2" ).arg( zipItem->path(), zipItem->name() ), 3 );
    1831                 :            :     }
    1832                 :          0 :   }
    1833                 :            : 
    1834                 :            :   // only display if has children or if is not populated
    1835                 :          0 :   if ( zipItem && ( !populated || zipItem->rowCount() > 0 ) )
    1836                 :            :   {
    1837                 :          0 :     QgsDebugMsgLevel( QStringLiteral( "returning zipItem" ), 3 );
    1838                 :          0 :     return zipItem;
    1839                 :            :   }
    1840                 :            : 
    1841                 :          0 :   return nullptr;
    1842                 :          0 : }
    1843                 :            : 
    1844                 :          0 : QStringList QgsZipItem::getZipFileList()
    1845                 :            : {
    1846                 :          0 :   if ( ! mZipFileList.isEmpty() )
    1847                 :          0 :     return mZipFileList;
    1848                 :            : 
    1849                 :          0 :   QString tmpPath;
    1850                 :          0 :   QgsSettings settings;
    1851                 :          0 :   QString scanZipSetting = settings.value( QStringLiteral( "qgis/scanZipInBrowser2" ), "basic" ).toString();
    1852                 :            : 
    1853                 :          0 :   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                 :          0 :   if ( scanZipSetting == QLatin1String( "no" ) )
    1857                 :            :   {
    1858                 :          0 :     return mZipFileList;
    1859                 :            :   }
    1860                 :            : 
    1861                 :            :   // get list of files inside zip file
    1862                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "Open file %1 with gdal vsi" ).arg( mVsiPrefix + mFilePath ), 3 );
    1863                 :          0 :   char **papszSiblingFiles = VSIReadDirRecursive( QString( mVsiPrefix + mFilePath ).toLocal8Bit().constData() );
    1864                 :          0 :   if ( papszSiblingFiles )
    1865                 :            :   {
    1866                 :          0 :     for ( int i = 0; papszSiblingFiles[i]; i++ )
    1867                 :            :     {
    1868                 :          0 :       tmpPath = papszSiblingFiles[i];
    1869                 :          0 :       QgsDebugMsgLevel( QStringLiteral( "Read file %1" ).arg( tmpPath ), 3 );
    1870                 :            :       // skip directories (files ending with /)
    1871                 :          0 :       if ( tmpPath.right( 1 ) != QLatin1String( "/" ) )
    1872                 :          0 :         mZipFileList << tmpPath;
    1873                 :          0 :     }
    1874                 :          0 :     CSLDestroy( papszSiblingFiles );
    1875                 :          0 :   }
    1876                 :            :   else
    1877                 :            :   {
    1878                 :          0 :     QgsDebugMsg( QStringLiteral( "Error reading %1" ).arg( mFilePath ) );
    1879                 :            :   }
    1880                 :            : 
    1881                 :          0 :   return mZipFileList;
    1882                 :          0 : }
    1883                 :            : 
    1884                 :            : 
    1885                 :          0 : QgsDatabaseSchemaItem::QgsDatabaseSchemaItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &providerKey )
    1886                 :          0 :   : QgsDataCollectionItem( parent, name, path, providerKey )
    1887                 :          0 : {
    1888                 :            : 
    1889                 :          0 : }
    1890                 :            : 
    1891                 :          0 : QgsDatabaseSchemaItem::~QgsDatabaseSchemaItem()
    1892                 :          0 : {
    1893                 :            : 
    1894                 :          0 : }
    1895                 :            : 
    1896                 :          0 : QIcon QgsDatabaseSchemaItem::iconDataCollection()
    1897                 :            : {
    1898                 :          0 :   return QgsApplication::getThemeIcon( QStringLiteral( "/mIconDbSchema.svg" ) );
    1899                 :          0 : }
    1900                 :            : 
    1901                 :          0 : QgsAbstractDatabaseProviderConnection *QgsDatabaseSchemaItem::databaseConnection() const
    1902                 :            : {
    1903                 :          0 :   const QString dataProviderKey { QgsApplication::dataItemProviderRegistry()->dataProviderKey( providerKey() ) };
    1904                 :          0 :   QgsProviderMetadata *md { QgsProviderRegistry::instance()->providerMetadata( dataProviderKey ) };
    1905                 :          0 :   if ( ! md )
    1906                 :            :   {
    1907                 :          0 :     return nullptr;
    1908                 :            :   }
    1909                 :          0 :   const QString connectionName { parent()->name() };
    1910                 :            :   try
    1911                 :            :   {
    1912                 :          0 :     return static_cast<QgsAbstractDatabaseProviderConnection *>( md->createConnection( connectionName ) );
    1913                 :          0 :   }
    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                 :          0 :   }
    1919                 :          0 :   return nullptr;
    1920                 :          0 : }
    1921                 :            : 
    1922                 :            : 
    1923                 :          0 : QgsConnectionsRootItem::QgsConnectionsRootItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &providerKey )
    1924                 :          0 :   : QgsDataCollectionItem( parent, name, path, providerKey )
    1925                 :          0 : {
    1926                 :          0 : }
    1927                 :            : 
    1928                 :            : 
    1929                 :            : ///@cond PRIVATE
    1930                 :            : 
    1931                 :          0 : QgsProjectHomeItem::QgsProjectHomeItem( QgsDataItem *parent, const QString &name, const QString &dirPath, const QString &path )
    1932                 :          0 :   : QgsDirectoryItem( parent, name, dirPath, path, QStringLiteral( "special:ProjectHome" ) )
    1933                 :          0 : {
    1934                 :          0 : }
    1935                 :            : 
    1936                 :          0 : QIcon QgsProjectHomeItem::icon()
    1937                 :            : {
    1938                 :          0 :   if ( state() == Populating )
    1939                 :          0 :     return QgsDirectoryItem::icon();
    1940                 :          0 :   return QgsApplication::getThemeIcon( QStringLiteral( "mIconFolderProject.svg" ) );
    1941                 :          0 : }
    1942                 :            : 
    1943                 :          0 : QVariant QgsProjectHomeItem::sortKey() const
    1944                 :            : {
    1945                 :          0 :   return QStringLiteral( " 1" );
    1946                 :          0 : }
    1947                 :            : 
    1948                 :            : 
    1949                 :          0 : QgsFavoriteItem::QgsFavoriteItem( QgsFavoritesItem *parent, const QString &name, const QString &dirPath, const QString &path )
    1950                 :          0 :   : QgsDirectoryItem( parent, name, dirPath, path, QStringLiteral( "special:Favorites" ) )
    1951                 :          0 :   , mFavorites( parent )
    1952                 :          0 : {
    1953                 :          0 :   mCapabilities |= Rename;
    1954                 :          0 : }
    1955                 :            : 
    1956                 :          0 : bool QgsFavoriteItem::rename( const QString &name )
    1957                 :            : {
    1958                 :          0 :   mFavorites->renameFavorite( dirPath(), name );
    1959                 :          0 :   return true;
    1960                 :          0 : }
    1961                 :            : 
    1962                 :            : 
    1963                 :            : ///@endcond

Generated by: LCOV version 1.14