18 #include <QApplication>
19 #include <QtConcurrentMap>
20 #include <QtConcurrentRun>
22 #include <QElapsedTimer>
26 #include <QMouseEvent>
27 #include <QTreeWidget>
28 #include <QTreeWidgetItem>
41 #include "qgsconfig.h"
49 #define CPL_SUPRESS_CPLUSPLUS //#spellok
51 #include "cpl_string.h"
117 const QString &connectionUri,
118 const QString &providerKey,
119 const QString &schema,
120 const QString &tableName )
123 , mTableName( tableName )
124 , mConnectionUri( connectionUri )
133 mTableProperty = qgis::make_unique<QgsAbstractDatabaseProviderConnection::TableProperty>( conn->table(
schema,
tableName ) );
137 QgsDebugMsg( QStringLiteral(
"Error creating fields item: %1" ).arg( ex.
what() ) );
159 const QgsFields constFields { conn->fields( mSchema, mTableName ) };
160 for (
const auto &f : constFields )
183 return mConnectionUri;
188 std::unique_ptr<QgsVectorLayer> vl;
207 QgsDebugMsg( QStringLiteral(
"Error getting connection from %1" ).arg( mConnectionUri ) );
220 return mTableProperty.get();
239 setState( QgsDataItem::State::Populated );
250 if ( parentFields && parentFields->tableProperty() &&
251 parentFields->tableProperty()->geometryColumn() ==
mName &&
252 parentFields->tableProperty()->geometryColumnTypes().count() )
254 if ( mField.
typeName() == QLatin1String(
"raster" ) )
261 case QgsWkbTypes::GeometryType::LineGeometry:
263 case QgsWkbTypes::GeometryType::PointGeometry:
265 case QgsWkbTypes::GeometryType::PolygonGeometry:
267 case QgsWkbTypes::GeometryType::UnknownGeometry:
268 case QgsWkbTypes::GeometryType::NullGeometry:
288 return QStringLiteral(
" 0" );
301 , mCapabilities( NoCapabilities )
303 , mState( NotPopulated )
305 , mProviderKey( providerKey )
307 , mDeferredDelete( false )
308 , mFutureWatcher( nullptr )
320 child->deleteLater();
324 if ( mFutureWatcher && !mFutureWatcher->isFinished() )
327 QgsDebugMsg( QStringLiteral(
"mFutureWatcher not finished (should not happen) -> waitForFinished()" ) );
328 mDeferredDelete =
true;
329 mFutureWatcher->waitForFinished();
332 delete mFutureWatcher;
337 return QString(
string ).replace( QRegExp(
"[\\\\/]" ), QStringLiteral(
"|" ) );
359 child->deleteLater();
363 if ( mFutureWatcher && !mFutureWatcher->isFinished() )
365 QgsDebugMsg( QStringLiteral(
"mFutureWatcher not finished -> schedule to delete later" ) );
366 mDeferredDelete =
true;
370 QObject::deleteLater();
376 const auto constItems = items;
395 child->QObject::setParent(
nullptr );
396 child->moveToThread( targetThread );
398 QObject::moveToThread( targetThread );
404 return sPopulatingIcon->
icon();
406 if ( !
mIcon.isNull() )
425 return QVector<QgsDataItem *>();
443 if ( !mFutureWatcher )
445 mFutureWatcher =
new QFutureWatcher< QVector <QgsDataItem *> >( this );
449 mFutureWatcher->setFuture( QtConcurrent::run( runCreateChildren,
this ) );
454 QVector<QgsDataItem *> QgsDataItem::runCreateChildren(
QgsDataItem *item )
460 QgsDebugMsgLevel( QStringLiteral(
"%1 children created in %2 ms" ).arg(
children.size() ).arg( time.elapsed() ), 3 );
462 const auto constChildren =
children;
469 child->moveToThread( qApp->thread() );
477 QgsDebugMsgLevel( QStringLiteral(
"path = %1 children.size() = %2" ).arg(
path() ).arg( mFutureWatcher->result().size() ), 3 );
481 QgsDebugMsg( QStringLiteral(
"Item was scheduled to be deleted later" ) );
482 QObject::deleteLater();
488 populate( mFutureWatcher->result() );
492 refresh( mFutureWatcher->result() );
507 const auto constChildren =
children;
546 if ( !mFutureWatcher )
548 mFutureWatcher =
new QFutureWatcher< QVector <QgsDataItem *> >( this );
551 mFutureWatcher->setFuture( QtConcurrent::run( runCreateChildren,
this ) );
575 QVector<QgsDataItem *> remove;
583 remove.append( child );
585 const auto constRemove = remove;
593 const auto constChildren =
children;
606 mChildren.value( index )->refresh( child->children() );
609 child->deleteLater();
645 disconnect(
this,
nullptr,
mParent,
nullptr );
680 if (
mChildren.at( i )->mName.localeAwareCompare( child->
mName ) >= 0 )
725 for (
int i = 0; i < items.size(); i++ )
727 Q_ASSERT_X( items[i],
"findItem", QStringLiteral(
"item %1 is nullptr" ).arg( i ).toLatin1() );
729 if ( items[i]->
equal( item ) )
737 return ( metaObject()->className() == other->metaObject()->className() &&
744 return QList<QAction *>();
772 if ( !sPopulatingIcon )
796 return QList<QMenu *>();
802 const QString &uri,
LayerType layerType,
const QString &providerKey )
803 :
QgsDataItem( Layer, parent, name, path, providerKey )
805 , mLayerType( layerType )
842 switch ( layer->
type() )
846 switch ( qobject_cast< QgsVectorLayer * >( layer )->geometryType() )
883 static int enumIdx = staticMetaObject.indexOfEnumerator(
"LayerType" );
884 return staticMetaObject.enumerator( enumIdx ).valueToKey( layerType );
892 return QStringLiteral(
"/mIconPointLayer.svg" );
894 return QStringLiteral(
"/mIconLineLayer.svg" );
896 return QStringLiteral(
"/mIconPolygonLayer.svg" );
899 return QStringLiteral(
"/mIconVector.svg" );
902 return QStringLiteral(
"/mIconTableLayer.svg" );
904 return QStringLiteral(
"/mIconRaster.svg" );
906 return QStringLiteral(
"/mIconMeshLayer.svg" );
908 return QStringLiteral(
"/mIconLayer.png" );
925 const QgsLayerItem *o = qobject_cast<const QgsLayerItem *>( other );
939 u.
layerType = QStringLiteral(
"vector" );
967 u.
layerType = QStringLiteral(
"raster" );
973 u.
layerType = QStringLiteral(
"vector-tile" );
976 u.
layerType = QStringLiteral(
"plugin" );
979 u.
layerType = QStringLiteral(
"annotation" );
995 const QString &providerKey )
996 :
QgsDataItem( Collection, parent, name, path, providerKey )
999 mIconName = QStringLiteral(
"/mIconDbSchema.svg" );
1011 QgsDebugMsgLevel( QStringLiteral(
"delete child = 0x%0" ).arg(
static_cast<qlonglong
>( i ), 8, 16, QLatin1Char(
'0' ) ), 2 );
1022 , mRefreshLater( false )
1029 const QString &dirPath,
const QString &path,
1030 const QString &providerKey )
1032 , mDirPath( dirPath )
1033 , mRefreshLater( false )
1046 if (
mDirPath == QDir::homePath() )
1055 if ( fi.isDir() && fi.isSymLink() )
1076 QStringList entries = dir.entryList( QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name | QDir::IgnoreCase );
1077 const auto constEntries = entries;
1078 for (
const QString &subdir : constEntries )
1080 if ( mRefreshLater )
1086 QString subdirPath = dir.absoluteFilePath( subdir );
1088 QgsDebugMsgLevel( QStringLiteral(
"creating subdir: %1" ).arg( subdirPath ), 2 );
1094 bool handledByProvider =
false;
1097 if ( provider->handlesDirectoryPath(
path ) )
1099 handledByProvider =
true;
1103 if ( handledByProvider )
1109 item->
setSortKey( QStringLiteral(
" %1" ).arg( subdir ) );
1116 QStringList fileEntries = dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot | QDir::Files, QDir::Name );
1117 const auto constFileEntries = fileEntries;
1118 for (
const QString &
name : constFileEntries )
1120 if ( mRefreshLater )
1126 QString
path = dir.absoluteFilePath(
name );
1127 QFileInfo fileInfo(
path );
1129 if ( fileInfo.suffix().compare( QLatin1String(
"zip" ), Qt::CaseInsensitive ) == 0 ||
1130 fileInfo.suffix().compare( QLatin1String(
"tar" ), Qt::CaseInsensitive ) == 0 )
1140 bool createdItem =
false;
1143 int capabilities = provider->capabilities();
1163 if ( fileInfo.suffix().compare( QLatin1String(
"qgs" ), Qt::CaseInsensitive ) == 0 ||
1164 fileInfo.suffix().compare( QLatin1String(
"qgz" ), Qt::CaseInsensitive ) == 0 )
1182 if ( !mFileSystemWatcher )
1184 mFileSystemWatcher =
new QFileSystemWatcher(
this );
1185 mFileSystemWatcher->addPath(
mDirPath );
1188 mLastScan = QDateTime::currentDateTime();
1192 if ( mFileSystemWatcher )
1194 delete mFileSystemWatcher;
1195 mFileSystemWatcher =
nullptr;
1203 if ( mLastScan.msecsTo( QDateTime::currentDateTime() ) <
QgsSettings().value( QStringLiteral(
"browser/minscaninterval" ), 10000 ).toInt() )
1210 mRefreshLater =
true;
1224 QTimer::singleShot( 100,
this, [ = ] {
refresh(); } );
1231 QStringList hiddenItems = settings.
value( QStringLiteral(
"browser/hiddenPaths" ),
1232 QStringList() ).toStringList();
1233 int idx = hiddenItems.indexOf(
path );
1234 return ( idx > -1 );
1239 QgsDebugMsgLevel( QStringLiteral(
"mRefreshLater = %1" ).arg( mRefreshLater ), 3 );
1241 if ( mRefreshLater )
1243 QgsDebugMsgLevel( QStringLiteral(
"directory changed during createChidren() -> refresh() again" ), 3 );
1244 mRefreshLater =
false;
1263 return (
path() == other->
path() );
1274 u.
layerType = QStringLiteral(
"directory" );
1281 : QTreeWidget( parent )
1283 setRootIsDecorated(
false );
1286 setColumnCount( 7 );
1288 labels << tr(
"Name" ) << tr(
"Size" ) << tr(
"Date" ) << tr(
"Permissions" ) << tr(
"Owner" ) << tr(
"Group" ) << tr(
"Type" );
1289 setHeaderLabels( labels );
1296 QList<QTreeWidgetItem *> items;
1299 QStringList entries = dir.entryList( QDir::AllEntries | QDir::NoDotAndDotDot, QDir::Name | QDir::IgnoreCase );
1300 const auto constEntries = entries;
1301 for (
const QString &name : constEntries )
1303 QFileInfo fi( dir.absoluteFilePath( name ) );
1307 if ( fi.size() > 1024 )
1309 size = QStringLiteral(
"%1 KiB" ).arg( QString::number( fi.size() / 1024.0,
'f', 1 ) );
1311 else if ( fi.size() > 1.048576e6 )
1313 size = QStringLiteral(
"%1 MiB" ).arg( QString::number( fi.size() / 1.048576e6,
'f', 1 ) );
1317 size = QStringLiteral(
"%1 B" ).arg( fi.size() );
1320 texts << QLocale().toString( fi.lastModified(), QLocale::ShortFormat );
1322 perm += fi.permission( QFile::ReadOwner ) ?
'r' :
'-';
1323 perm += fi.permission( QFile::WriteOwner ) ?
'w' :
'-';
1324 perm += fi.permission( QFile::ExeOwner ) ?
'x' :
'-';
1326 perm += fi.permission( QFile::ReadGroup ) ?
'r' :
'-';
1327 perm += fi.permission( QFile::WriteGroup ) ?
'w' :
'-';
1328 perm += fi.permission( QFile::ExeGroup ) ?
'x' :
'-';
1329 perm += fi.permission( QFile::ReadOther ) ?
'r' :
'-';
1330 perm += fi.permission( QFile::WriteOther ) ?
'w' :
'-';
1331 perm += fi.permission( QFile::ExeOther ) ?
'x' :
'-';
1334 texts << fi.owner();
1335 texts << fi.group();
1339 if ( fi.isDir() && fi.isSymLink() )
1341 type = tr(
"folder" );
1344 else if ( fi.isDir() )
1346 type = tr(
"folder" );
1347 icon = iconDirectory;
1349 else if ( fi.isFile() && fi.isSymLink() )
1351 type = tr(
"file" );
1352 icon = iconFileLink;
1354 else if ( fi.isFile() )
1356 type = tr(
"file" );
1362 QTreeWidgetItem *item =
new QTreeWidgetItem( texts );
1363 item->setIcon( 0, icon );
1367 addTopLevelItems( items );
1371 QList<QVariant> lst = settings.
value( QStringLiteral(
"dataitem/directoryHiddenColumns" ) ).toList();
1372 const auto constLst = lst;
1373 for (
const QVariant &colVariant : constLst )
1375 setColumnHidden( colVariant.toInt(),
true );
1381 if ( event->button() == Qt::RightButton )
1387 labels << tr(
"Name" ) << tr(
"Size" ) << tr(
"Date" ) << tr(
"Permissions" ) << tr(
"Owner" ) << tr(
"Group" ) << tr(
"Type" );
1388 for (
int i = 0; i < labels.count(); i++ )
1391 action->setObjectName( QString::number( i ) );
1392 action->setCheckable(
true );
1393 action->setChecked( !isColumnHidden( i ) );
1396 popupMenu.exec( event->globalPos() );
1402 QAction *action = qobject_cast<QAction *>( sender() );
1406 int columnIndex = action->objectName().toInt();
1407 setColumnHidden( columnIndex, !isColumnHidden( columnIndex ) );
1411 QList<QVariant> lst;
1412 for (
int i = 0; i < columnCount(); i++ )
1414 if ( isColumnHidden( i ) )
1415 lst.append( QVariant( i ) );
1417 settings.
setValue( QStringLiteral(
"dataitem/directoryHiddenColumns" ), lst );
1421 const QString &path,
const QString &providerKey )
1424 mIconName = QStringLiteral(
":/images/icons/qgis_icon.svg" );
1432 u.
layerType = QStringLiteral(
"project" );
1441 mIconName = QStringLiteral(
"/mIconDelete.svg" );
1447 :
QgsDataCollectionItem( parent, name, QStringLiteral(
"favorites:" ), QStringLiteral(
"special:Favorites" ) )
1452 mIconName = QStringLiteral(
"/mIconFavorites.svg" );
1462 const QStringList favDirs = settings.
value( QStringLiteral(
"browser/favourites" ), QVariant() ).toStringList();
1464 for (
const QString &favDir : favDirs )
1466 QStringList parts = favDir.split( QStringLiteral(
"|||" ) );
1467 if ( parts.empty() )
1470 QString dir = parts.at( 0 );
1472 if ( parts.count() > 1 )
1473 name = parts.at( 1 );
1483 QString
name = n.isEmpty() ? favDir : n;
1486 QStringList favDirs = settings.
value( QStringLiteral(
"browser/favourites" ) ).toStringList();
1487 favDirs.append( QStringLiteral(
"%1|||%2" ).arg( favDir,
name ) );
1488 settings.
setValue( QStringLiteral(
"browser/favourites" ), favDirs );
1493 const auto constItems = items;
1507 QStringList favDirs = settings.
value( QStringLiteral(
"browser/favourites" ) ).toStringList();
1508 for (
int i = favDirs.count() - 1; i >= 0; --i )
1510 QStringList parts = favDirs.at( i ).split( QStringLiteral(
"|||" ) );
1511 if ( parts.empty() )
1514 QString dir = parts.at( 0 );
1516 favDirs.removeAt( i );
1518 settings.
setValue( QStringLiteral(
"browser/favourites" ), favDirs );
1523 QgsDebugMsg( QStringLiteral(
"favorites item %1 not found" ).arg( item->
path() ) );
1535 QStringList favDirs = settings.
value( QStringLiteral(
"browser/favourites" ) ).toStringList();
1536 for (
int i = 0; i < favDirs.count(); ++i )
1538 QStringList parts = favDirs.at( i ).split( QStringLiteral(
"|||" ) );
1539 if ( parts.empty() )
1542 QString dir = parts.at( 0 );
1545 favDirs[i] = QStringLiteral(
"%1|||%2" ).arg(
path,
name );
1549 settings.
setValue( QStringLiteral(
"browser/favourites" ), favDirs );
1552 const QVector<QgsDataItem *> ch =
children();
1555 if ( QgsFavoriteItem *favorite = qobject_cast< QgsFavoriteItem * >( child ) )
1557 if ( favorite->dirPath() ==
path )
1559 favorite->setName(
name );
1573 int capabilities = provider->capabilities();
1577 QgsDataItem *item = provider->createDataItem( favDir,
this );
1587 QgsFavoriteItem *item =
new QgsFavoriteItem(
this,
name, favDir,
mPath +
'/' + pathName );
1608 const QString &filePath,
const QString &path,
1609 const QString &providerKey )
1611 , mFilePath( filePath )
1616 void QgsZipItem::init()
1619 mIconName = QStringLiteral(
"/mIconZip.svg" );
1622 static std::once_flag initialized;
1623 std::call_once( initialized, [ = ]
1625 sProviderNames << QStringLiteral(
"OGR" ) << QStringLiteral(
"GDAL" );
1634 QString scanZipSetting = settings.
value( QStringLiteral(
"qgis/scanZipInBrowser2" ),
"basic" ).toString();
1641 if ( scanZipSetting == QLatin1String(
"no" ) )
1653 for (
const QString &fileName : constMZipFileList )
1655 QFileInfo info( fileName );
1665 if ( provider->name() == QLatin1String(
"OGR" ) )
1667 if ( info.suffix().compare( QLatin1String(
"dbf" ), Qt::CaseInsensitive ) == 0 )
1669 if (
mZipFileList.indexOf( fileName.left( fileName.count() - 4 ) +
".shp" ) != -1 )
1672 if ( info.completeSuffix().compare( QLatin1String(
"shp.xml" ), Qt::CaseInsensitive ) == 0 )
1678 QgsDebugMsgLevel( QStringLiteral(
"trying to load item %1 with %2" ).arg( tmpPath, provider->name() ), 3 );
1679 QgsDataItem *item = provider->createDataItem( tmpPath,
this );
1704 QString scanZipSetting = settings.
value( QStringLiteral(
"qgis/scanZipInBrowser2" ),
"basic" ).toString();
1705 QStringList zipFileList;
1708 bool populated =
false;
1713 if ( scanZipSetting == QLatin1String(
"no" ) )
1717 if ( (
vsiPrefix != QLatin1String(
"/vsizip/" ) &&
vsiPrefix != QLatin1String(
"/vsitar/" ) ) )
1730 if (
path.endsWith( QLatin1String(
".zip" ), Qt::CaseInsensitive ) ||
1731 path.endsWith( QLatin1String(
".tar" ), Qt::CaseInsensitive ) )
1736 if ( !zipFileList.isEmpty() && zipFileList.count() <= 10 )
1740 QgsDebugMsgLevel( QStringLiteral(
"Got zipItem with %1 children, path=%2, name=%3" ).arg( zipItem->
rowCount() ).arg( zipItem->
path(), zipItem->
name() ), 3 );
1744 QgsDebugMsgLevel( QStringLiteral(
"Delaying populating zipItem with path=%1, name=%2" ).arg( zipItem->
path(), zipItem->
name() ), 3 );
1749 if ( zipItem && ( !populated || zipItem->
rowCount() > 0 ) )
1765 QString scanZipSetting = settings.
value( QStringLiteral(
"qgis/scanZipInBrowser2" ),
"basic" ).toString();
1770 if ( scanZipSetting == QLatin1String(
"no" ) )
1777 char **papszSiblingFiles = VSIReadDirRecursive( QString(
mVsiPrefix +
mFilePath ).toLocal8Bit().constData() );
1778 if ( papszSiblingFiles )
1780 for (
int i = 0; papszSiblingFiles[i]; i++ )
1782 tmpPath = papszSiblingFiles[i];
1785 if ( tmpPath.right( 1 ) != QLatin1String(
"/" ) )
1788 CSLDestroy( papszSiblingFiles );
1824 QgsProjectHomeItem::QgsProjectHomeItem(
QgsDataItem *parent,
const QString &name,
const QString &dirPath,
const QString &path )
1825 :
QgsDirectoryItem( parent, name, dirPath, path, QStringLiteral(
"special:ProjectHome" ) )
1829 QIcon QgsProjectHomeItem::icon()
1831 if ( state() == Populating )
1836 QVariant QgsProjectHomeItem::sortKey()
const
1838 return QStringLiteral(
" 1" );
1842 QgsFavoriteItem::QgsFavoriteItem(
QgsFavoritesItem *parent,
const QString &name,
const QString &dirPath,
const QString &path )
1843 :
QgsDirectoryItem( parent, name, dirPath, path, QStringLiteral(
"special:Favorites" ) )
1844 , mFavorites( parent )
1849 bool QgsFavoriteItem::rename(
const QString &name )
1851 mFavorites->renameFavorite( dirPath(), name );