QGIS API Documentation 3.29.0-Master (8c80f25a4f)
qgsbrowsermodel.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsbrowsermodel.cpp
3 ---------------------
4 begin : July 2011
5 copyright : (C) 2011 by Martin Dobias
6 email : wonder dot sk at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15#include <QDir>
16#include <QApplication>
17#include <QStyle>
18#include <QtConcurrentMap>
19#include <QUrl>
20#include <QStorageInfo>
21#include <QFuture>
22#include <QFutureWatcher>
23
24#include "qgis.h"
25#include "qgsapplication.h"
26#include "qgsdataitemprovider.h"
28#include "qgsdataprovider.h"
29#include "qgsmimedatautils.h"
30#include "qgslogger.h"
31#include "qgsproviderregistry.h"
32#include "qgsbrowsermodel.h"
33#include "qgsproject.h"
34#include "qgssettings.h"
35#include "qgsdirectoryitem.h"
36#include "qgsprojectitem.h"
37#include "qgslayeritem.h"
38#include "qgsfavoritesitem.h"
39#include "qgslayermetadata.h"
40
41#define PROJECT_HOME_PREFIX "project:"
42#define HOME_PREFIX "home:"
43
45class QgsBrowserWatcher : public QFutureWatcher<QVector <QgsDataItem *> >
46{
47 Q_OBJECT
48
49 public:
50 QgsBrowserWatcher( QgsDataItem *item )
51 : QFutureWatcher( nullptr )
52 , mItem( item )
53 {
54 }
55
56 QgsDataItem *item() const { return mItem; }
57
58 signals:
59 void finished( QgsDataItem *item, const QVector <QgsDataItem *> &items );
60
61 private:
62 QgsDataItem *mItem = nullptr;
63};
65
66// sort function for QList<QgsDataItem*>, e.g. sorted/grouped provider listings
67static bool cmpByDataItemName_( QgsDataItem *a, QgsDataItem *b )
68{
69 return QString::localeAwareCompare( a->name(), b->name() ) < 0;
70}
71
73 : QAbstractItemModel( parent )
74
75{
77 this, &QgsBrowserModel::dataItemProviderAdded );
79 this, &QgsBrowserModel::dataItemProviderWillBeRemoved );
80}
81
83{
85}
86
88{
89 QString home = QgsProject::instance()->homePath();
90 if ( mProjectHome && mProjectHome->path().mid( QStringLiteral( PROJECT_HOME_PREFIX ).length() ) == home )
91 return;
92
93 int idx = mRootItems.indexOf( mProjectHome );
94
95 // using layoutAboutToBeChanged() was messing expanded items
96 if ( idx >= 0 )
97 {
98 beginRemoveRows( QModelIndex(), idx, idx );
99 mRootItems.remove( idx );
100 endRemoveRows();
101 }
102 delete mProjectHome;
103 mProjectHome = home.isNull() ? nullptr : new QgsProjectHomeItem( nullptr, tr( "Project Home" ), home, QStringLiteral( PROJECT_HOME_PREFIX ) + home );
104 if ( mProjectHome )
105 {
106 setupItemConnections( mProjectHome );
107
108 beginInsertRows( QModelIndex(), 0, 0 );
109 mRootItems.insert( 0, mProjectHome );
110 endInsertRows();
111 }
112}
113
115{
117
118 // give the home directory a prominent third place
119 QgsDirectoryItem *item = new QgsDirectoryItem( nullptr, tr( "Home" ), QDir::homePath(),
120 QStringLiteral( HOME_PREFIX ) + QDir::homePath(),
121 QStringLiteral( "special:Home" ) );
122 item->setSortKey( QStringLiteral( " 2" ) );
123 setupItemConnections( item );
124 mRootItems << item;
125
126 // add favorite directories
127 mFavorites = new QgsFavoritesItem( nullptr, tr( "Favorites" ) );
128 if ( mFavorites )
129 {
130 setupItemConnections( mFavorites );
132 }
133
134 // add drives
135 const auto drives { QDir::drives() };
136 for ( const QFileInfo &drive : drives )
137 {
138 const QString path = drive.absolutePath();
139
140 if ( QgsDirectoryItem::hiddenPath( path ) )
141 continue;
142
143 const QString driveName = QStorageInfo( path ).displayName();
144 const QString name = driveName.isEmpty() || driveName == path ? path : QStringLiteral( "%1 (%2)" ).arg( path, driveName );
145
146 QgsDirectoryItem *item = new QgsDirectoryItem( nullptr, name, path, path, QStringLiteral( "special:Drives" ) );
147 item->setSortKey( QStringLiteral( " 3 %1" ).arg( path ) );
148 mDriveItems.insert( path, item );
149
150 setupItemConnections( item );
151 mRootItems << item;
152 }
153
154#ifdef Q_OS_MAC
155 QString path = QString( "/Volumes" );
156 QgsDirectoryItem *vols = new QgsDirectoryItem( nullptr, path, path, path, QStringLiteral( "special:Volumes" ) );
157 setupItemConnections( vols );
158 mRootItems << vols;
159#endif
160
161 // container for displaying providers as sorted groups (by QgsDataProvider::DataCapability enum)
162 QMultiMap<int, QgsDataItem *> providerMap;
163
164 const auto constProviders = QgsApplication::dataItemProviderRegistry()->providers();
165 for ( QgsDataItemProvider *pr : constProviders )
166 {
167 if ( QgsDataItem *item = addProviderRootItem( pr ) )
168 {
169 providerMap.insert( pr->capabilities(), item );
170 }
171 }
172
173 // add as sorted groups by QgsDataProvider::DataCapability enum
174 const auto constUniqueKeys = providerMap.uniqueKeys();
175 for ( int key : constUniqueKeys )
176 {
177 QList<QgsDataItem *> providerGroup = providerMap.values( key );
178 if ( providerGroup.size() > 1 )
179 {
180 std::sort( providerGroup.begin(), providerGroup.end(), cmpByDataItemName_ );
181 }
182
183 const auto constProviderGroup = providerGroup;
184 for ( QgsDataItem *ditem : constProviderGroup )
185 {
186 mRootItems << ditem;
187 }
188 }
189}
190
192{
193 const auto constMRootItems = mRootItems;
194 for ( QgsDataItem *item : constMRootItems )
195 {
196 delete item;
197 }
198
199 mRootItems.clear();
200 mDriveItems.clear();
201}
202
203void QgsBrowserModel::dataItemProviderAdded( QgsDataItemProvider *provider )
204{
205 if ( !mInitialized )
206 return;
207
208 if ( QgsDataItem *item = addProviderRootItem( provider ) )
209 {
210 beginInsertRows( QModelIndex(), rowCount(), rowCount() );
211 mRootItems << item;
212 endInsertRows();
213 }
214}
215
216void QgsBrowserModel::dataItemProviderWillBeRemoved( QgsDataItemProvider *provider )
217{
218 const auto constMRootItems = mRootItems;
219 for ( QgsDataItem *item : constMRootItems )
220 {
221 if ( item->providerKey() == provider->name() )
222 {
223 removeRootItem( item );
224 break; // assuming there is max. 1 root item per provider
225 }
226 }
227}
228
229void QgsBrowserModel::onConnectionsChanged( const QString &providerKey )
230{
231 // refresh the matching provider
232 for ( QgsDataItem *item : std::as_const( mRootItems ) )
233 {
234 if ( item->providerKey() == providerKey )
235 {
236 item->refresh();
237 break; // assuming there is max. 1 root item per provider
238 }
239 }
240
241 emit connectionsChanged( providerKey );
242}
243
244QMap<QString, QgsDirectoryItem *> QgsBrowserModel::driveItems() const
245{
246 return mDriveItems;
247}
248
249
251{
252 if ( ! mInitialized )
253 {
255 addRootItems();
256 mInitialized = true;
257 }
258}
259
260Qt::ItemFlags QgsBrowserModel::flags( const QModelIndex &index ) const
261{
262 if ( !index.isValid() )
263 return Qt::ItemFlags();
264
265 Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
266
267 QgsDataItem *ptr = dataItem( index );
268
269 if ( !ptr )
270 {
271 QgsDebugMsgLevel( QStringLiteral( "FLAGS PROBLEM!" ), 4 );
272 return Qt::ItemFlags();
273 }
274
275 if ( ptr->hasDragEnabled() )
276 flags |= Qt::ItemIsDragEnabled;
277
279 if ( ptr->acceptDrop() )
280 flags |= Qt::ItemIsDropEnabled;
282
285 flags |= Qt::ItemIsEditable;
286
287 return flags;
288}
289
290QVariant QgsBrowserModel::data( const QModelIndex &index, int role ) const
291{
292 if ( !index.isValid() )
293 return QVariant();
294
295 QgsDataItem *item = dataItem( index );
296 if ( !item )
297 {
298 return QVariant();
299 }
300 else if ( role == Qt::DisplayRole || role == Qt::EditRole )
301 {
302 return item->name();
303 }
304 else if ( role == QgsBrowserModel::SortRole )
305 {
306 return item->sortKey();
307 }
308 else if ( role == Qt::ToolTipRole )
309 {
310 return item->toolTip();
311 }
312 else if ( role == Qt::DecorationRole && index.column() == 0 )
313 {
314 return item->icon();
315 }
316 else if ( role == QgsBrowserModel::PathRole )
317 {
318 return item->path();
319 }
320 else if ( role == QgsBrowserModel::CommentRole )
321 {
322 if ( item->type() == Qgis::BrowserItemType::Layer )
323 {
324 QgsLayerItem *lyrItem = qobject_cast<QgsLayerItem *>( item );
325 return lyrItem->comments();
326 }
327 return QVariant();
328 }
329 else if ( role == QgsBrowserModel::LayerMetadataRole )
330 {
331 if ( item->type() == Qgis::BrowserItemType::Layer )
332 {
333 QgsLayerItem *lyrItem = qobject_cast<QgsLayerItem *>( item );
334 return QVariant::fromValue( lyrItem->layerMetadata() );
335 }
336 return QVariant();
337 }
338 else if ( role == QgsBrowserModel::ProviderKeyRole )
339 {
340 return item->providerKey();
341 }
342 else
343 {
344 // unsupported role
345 return QVariant();
346 }
347}
348
349bool QgsBrowserModel::setData( const QModelIndex &index, const QVariant &value, int role )
350{
351 if ( !index.isValid() )
352 return false;
353
354
355 QgsDataItem *item = dataItem( index );
356 if ( !item )
357 {
358 return false;
359 }
360
363 return false;
364
365 switch ( role )
366 {
367 case Qt::EditRole:
368 {
370 return item->rename( value.toString() );
372 }
373 }
374 return false;
375}
376
377QVariant QgsBrowserModel::headerData( int section, Qt::Orientation orientation, int role ) const
378{
379 Q_UNUSED( section )
380 if ( orientation == Qt::Horizontal && role == Qt::DisplayRole )
381 {
382 return QVariant( "header" );
383 }
384
385 return QVariant();
386}
387
388int QgsBrowserModel::rowCount( const QModelIndex &parent ) const
389{
390 //QgsDebugMsg(QString("isValid = %1 row = %2 column = %3").arg(parent.isValid()).arg(parent.row()).arg(parent.column()));
391
392 if ( !parent.isValid() )
393 {
394 // root item: its children are top level items
395 return mRootItems.count(); // mRoot
396 }
397 else
398 {
399 // ordinary item: number of its children
400 QgsDataItem *item = dataItem( parent );
401 //if ( item ) QgsDebugMsg(QString("path = %1 rowCount = %2").arg(item->path()).arg(item->rowCount()) );
402 return item ? item->rowCount() : 0;
403 }
404}
405
406bool QgsBrowserModel::hasChildren( const QModelIndex &parent ) const
407{
408 if ( !parent.isValid() )
409 return !mRootItems.isEmpty(); // root item: its children are top level items
410
411 QgsDataItem *item = dataItem( parent );
412 return item && item->hasChildren();
413}
414
415int QgsBrowserModel::columnCount( const QModelIndex &parent ) const
416{
417 Q_UNUSED( parent )
418 return 1;
419}
420
421QModelIndex QgsBrowserModel::findPath( const QString &path, Qt::MatchFlag matchFlag )
422{
423 return findPath( this, path, matchFlag );
424}
425
426QModelIndex QgsBrowserModel::findPath( QAbstractItemModel *model, const QString &path, Qt::MatchFlag matchFlag )
427{
428 if ( !model )
429 return QModelIndex();
430
431 QModelIndex index; // starting from root
432 bool foundChild = true;
433
434 while ( foundChild )
435 {
436 foundChild = false; // assume that the next child item will not be found
437
438 for ( int i = 0; i < model->rowCount( index ); i++ )
439 {
440 QModelIndex idx = model->index( i, 0, index );
441
442 QString itemPath = model->data( idx, PathRole ).toString();
443 if ( itemPath == path )
444 {
445 QgsDebugMsgLevel( "Arrived " + itemPath, 4 );
446 return idx; // we have found the item we have been looking for
447 }
448
449 // paths are slash separated identifier
450 if ( path.startsWith( itemPath + '/' ) )
451 {
452 foundChild = true;
453 index = idx;
454 break;
455 }
456 }
457 }
458
459 if ( matchFlag == Qt::MatchStartsWith )
460 return index;
461
462 QgsDebugMsgLevel( QStringLiteral( "path not found" ), 4 );
463 return QModelIndex(); // not found
464}
465
466QModelIndex QgsBrowserModel::findUri( const QString &uri, QModelIndex index )
467{
468 for ( int i = 0; i < this->rowCount( index ); i++ )
469 {
470 QModelIndex idx = this->index( i, 0, index );
471
472 if ( qobject_cast<QgsLayerItem *>( dataItem( idx ) ) )
473 {
474 QString itemUri = qobject_cast<QgsLayerItem *>( dataItem( idx ) )->uri();
475
476 if ( itemUri == uri )
477 {
478 QgsDebugMsgLevel( "Arrived " + itemUri, 4 );
479 return idx; // we have found the item we have been looking for
480 }
481 }
482
483 QModelIndex childIdx = findUri( uri, idx );
484 if ( childIdx.isValid() )
485 return childIdx;
486 }
487 return QModelIndex();
488}
489
491{
492 // deprecated, no use
493}
494
496{
497 // TODO: put items creating currently children in threads to deleteLater (does not seem urget because reload() is not used in QGIS)
498 beginResetModel();
500 addRootItems();
501 endResetModel();
502}
503
505{
506 const QList< QFileInfo > drives = QDir::drives();
507 // remove any removed drives
508 const QStringList existingDrives = mDriveItems.keys();
509 for ( const QString &drivePath : existingDrives )
510 {
511 bool stillExists = false;
512 for ( const QFileInfo &drive : drives )
513 {
514 if ( drivePath == drive.absolutePath() )
515 {
516 stillExists = true;
517 break;
518 }
519 }
520
521 if ( stillExists )
522 continue;
523
524 // drive has been removed, remove corresponding item
525 if ( QgsDirectoryItem *driveItem = mDriveItems.value( drivePath ) )
526 removeRootItem( driveItem );
527 }
528
529 for ( const QFileInfo &drive : drives )
530 {
531 const QString path = drive.absolutePath();
532
533 if ( QgsDirectoryItem::hiddenPath( path ) )
534 continue;
535
536 // does an item for this drive already exist?
537 if ( !mDriveItems.contains( path ) )
538 {
539 const QString driveName = QStorageInfo( path ).displayName();
540 const QString name = driveName.isEmpty() || driveName == path ? path : QStringLiteral( "%1 (%2)" ).arg( path, driveName );
541
542 QgsDirectoryItem *item = new QgsDirectoryItem( nullptr, name, path, path, QStringLiteral( "special:Drives" ) );
543 item->setSortKey( QStringLiteral( " 3 %1" ).arg( path ) );
544
545 mDriveItems.insert( path, item );
546 setupItemConnections( item );
547
548 beginInsertRows( QModelIndex(), mRootItems.count(), mRootItems.count() );
549 mRootItems << item;
550 endInsertRows();
551 }
552 }
553}
554
555QModelIndex QgsBrowserModel::index( int row, int column, const QModelIndex &parent ) const
556{
557 if ( column < 0 || column >= columnCount() || row < 0 )
558 return QModelIndex();
559
561 const QVector<QgsDataItem *> &items = p ? p->children() : mRootItems;
562 QgsDataItem *item = items.value( row, nullptr );
563 return item ? createIndex( row, column, item ) : QModelIndex();
564}
565
566QModelIndex QgsBrowserModel::parent( const QModelIndex &index ) const
567{
568 QgsDataItem *item = dataItem( index );
569 if ( !item )
570 return QModelIndex();
571
572 return findItem( item->parent() );
573}
574
575QModelIndex QgsBrowserModel::findItem( QgsDataItem *item, QgsDataItem *parent ) const
576{
577 const QVector<QgsDataItem *> &items = parent ? parent->children() : mRootItems;
578
579 for ( int i = 0; i < items.size(); i++ )
580 {
581 if ( items[i] == item )
582 return createIndex( i, 0, item );
583
584 QModelIndex childIndex = findItem( item, items[i] );
585 if ( childIndex.isValid() )
586 return childIndex;
587 }
588 return QModelIndex();
589}
590
591void QgsBrowserModel::beginInsertItems( QgsDataItem *parent, int first, int last )
592{
593 QgsDebugMsgLevel( "parent mPath = " + parent->path(), 3 );
594 QModelIndex idx = findItem( parent );
595 if ( !idx.isValid() )
596 return;
597 QgsDebugMsgLevel( QStringLiteral( "valid" ), 3 );
598 beginInsertRows( idx, first, last );
599 QgsDebugMsgLevel( QStringLiteral( "end" ), 3 );
600}
602{
603 QgsDebugMsgLevel( QStringLiteral( "Entered" ), 3 );
604 endInsertRows();
605}
606void QgsBrowserModel::beginRemoveItems( QgsDataItem *parent, int first, int last )
607{
608 QgsDebugMsgLevel( "parent mPath = " + parent->path(), 3 );
609 QModelIndex idx = findItem( parent );
610 if ( !idx.isValid() )
611 return;
612 beginRemoveRows( idx, first, last );
613}
615{
616 QgsDebugMsgLevel( QStringLiteral( "Entered" ), 3 );
617 endRemoveRows();
618}
620{
621 QgsDebugMsgLevel( QStringLiteral( "Entered" ), 3 );
622 QModelIndex idx = findItem( item );
623 if ( !idx.isValid() )
624 return;
625 emit dataChanged( idx, idx );
626}
628{
629 if ( !item )
630 return;
631 QModelIndex idx = findItem( item );
632 if ( !idx.isValid() )
633 return;
634 QgsDebugMsgLevel( QStringLiteral( "item %1 state changed %2 -> %3" ).arg( item->path() ).arg( qgsEnumValueToKey< Qgis::BrowserItemState >( oldState ) ).arg( qgsEnumValueToKey< Qgis::BrowserItemState >( item->state() ) ), 4 );
635 emit stateChanged( idx, oldState );
636}
637
638void QgsBrowserModel::setupItemConnections( QgsDataItem *item )
639{
640 connect( item, &QgsDataItem::beginInsertItems,
642 connect( item, &QgsDataItem::endInsertItems,
644 connect( item, &QgsDataItem::beginRemoveItems,
646 connect( item, &QgsDataItem::endRemoveItems,
648 connect( item, &QgsDataItem::dataChanged,
650 connect( item, &QgsDataItem::stateChanged,
652
653 // if it's a collection item, also forwards connectionsChanged
654 QgsDataCollectionItem *collectionItem = qobject_cast<QgsDataCollectionItem *>( item );
655 if ( collectionItem )
656 connect( collectionItem, &QgsDataCollectionItem::connectionsChanged, this, &QgsBrowserModel::onConnectionsChanged );
657}
658
659QStringList QgsBrowserModel::mimeTypes() const
660{
661 QStringList types;
662 // In theory the mime type convention is: application/x-vnd.<vendor>.<application>.<type>
663 // but it seems a bit over formalized. Would be an application/x-qgis-uri better?
664 types << QStringLiteral( "application/x-vnd.qgis.qgis.uri" );
665 return types;
666}
667
668QMimeData *QgsBrowserModel::mimeData( const QModelIndexList &indexes ) const
669{
671 const auto constIndexes = indexes;
672 for ( const QModelIndex &index : constIndexes )
673 {
674 if ( index.isValid() )
675 {
676 QgsDataItem *ptr = reinterpret_cast< QgsDataItem * >( index.internalPointer() );
677 const QgsMimeDataUtils::UriList uris = ptr->mimeUris();
678 for ( QgsMimeDataUtils::Uri uri : std::as_const( uris ) )
679 {
681 {
682 uri.filePath = ptr->path();
683 }
684 lst.append( uri );
685 }
686 }
687 }
689}
690
691bool QgsBrowserModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int, int, const QModelIndex &parent )
692{
693 QgsDataItem *destItem = dataItem( parent );
694 if ( !destItem )
695 {
696 QgsDebugMsgLevel( QStringLiteral( "DROP PROBLEM!" ), 4 );
697 return false;
698 }
699
701 return destItem->handleDrop( data, action );
703}
704
705QgsDataItem *QgsBrowserModel::dataItem( const QModelIndex &idx ) const
706{
707 void *v = idx.internalPointer();
708 QgsDataItem *d = reinterpret_cast<QgsDataItem *>( v );
709 Q_ASSERT( !v || d );
710 return d;
711}
712
713bool QgsBrowserModel::canFetchMore( const QModelIndex &parent ) const
714{
715 QgsDataItem *item = dataItem( parent );
716 // if ( item )
717 // QgsDebugMsg( QStringLiteral( "path = %1 canFetchMore = %2" ).arg( item->path() ).arg( item && ! item->isPopulated() ) );
718 return ( item && item->state() == Qgis::BrowserItemState::NotPopulated );
719}
720
721void QgsBrowserModel::fetchMore( const QModelIndex &parent )
722{
723 QgsDataItem *item = dataItem( parent );
724
726 return;
727
728 QgsDebugMsgLevel( "path = " + item->path(), 4 );
729
730 item->populate();
731}
732
733/* Refresh dir path */
734void QgsBrowserModel::refresh( const QString &path )
735{
736 QModelIndex index = findPath( path );
737 refresh( index );
738}
739
740/* Refresh item */
741void QgsBrowserModel::refresh( const QModelIndex &index )
742{
743 QgsDataItem *item = dataItem( index );
744 if ( !item || item->state() == Qgis::BrowserItemState::Populating )
745 return;
746
747 QgsDebugMsgLevel( "Refresh " + item->path(), 4 );
748
749 item->refresh();
750}
751
752void QgsBrowserModel::addFavoriteDirectory( const QString &directory, const QString &name )
753{
754 Q_ASSERT( mFavorites );
755 mFavorites->addDirectory( directory, name );
756}
757
758void QgsBrowserModel::removeFavorite( const QModelIndex &index )
759{
760 QgsDirectoryItem *item = qobject_cast<QgsDirectoryItem *>( dataItem( index ) );
761 if ( !item )
762 return;
763
765}
766
768{
769 if ( !favorite )
770 return;
771
772 mFavorites->removeDirectory( favorite );
773}
774
776{
777 QgsSettings settings;
778 QStringList hiddenItems = settings.value( QStringLiteral( "browser/hiddenPaths" ),
779 QStringList() ).toStringList();
780 int idx = hiddenItems.indexOf( item->path() );
781 if ( idx != -1 )
782 {
783 hiddenItems.removeAt( idx );
784 }
785 else
786 {
787 hiddenItems << item->path();
788 }
789 settings.setValue( QStringLiteral( "browser/hiddenPaths" ), hiddenItems );
790 if ( item->parent() )
791 {
792 item->parent()->deleteChildItem( item );
793 }
794 else
795 {
796 removeRootItem( item );
797 }
798}
799
800
801void QgsBrowserModel::removeRootItem( QgsDataItem *item )
802{
803 int i = mRootItems.indexOf( item );
804 beginRemoveRows( QModelIndex(), i, i );
805 mRootItems.remove( i );
806 QgsDirectoryItem *dirItem = qobject_cast< QgsDirectoryItem * >( item );
807 if ( !mDriveItems.key( dirItem ).isEmpty() )
808 {
809 mDriveItems.remove( mDriveItems.key( dirItem ) );
810 }
811 item->deleteLater();
812 endRemoveRows();
813}
814
815QgsDataItem *QgsBrowserModel::addProviderRootItem( QgsDataItemProvider *pr )
816{
817 int capabilities = pr->capabilities();
818 if ( capabilities == QgsDataProvider::NoDataCapabilities )
819 {
820 QgsDebugMsgLevel( pr->name() + " does not have any dataCapabilities", 4 );
821 return nullptr;
822 }
823
824 QgsDataItem *item = pr->createDataItem( QString(), nullptr ); // empty path -> top level
825 if ( item )
826 {
827 // make sure the top level key is always set
828 item->setProviderKey( pr->name() );
829 // Forward the signal from the root items to the model (and then to the app)
830 connect( item, &QgsDataItem::connectionsChanged, this, &QgsBrowserModel::onConnectionsChanged );
831 QgsDebugMsgLevel( "Add new top level item : " + item->name(), 4 );
832 setupItemConnections( item );
833 }
834 return item;
835}
836
837// For QgsBrowserWatcher
838#include "qgsbrowsermodel.moc"
BrowserItemState
Browser item states.
Definition: qgis.h:368
@ NotPopulated
Children not yet created.
@ Populating
Creating children in separate thread (populating or refreshing)
@ Populated
Children created.
@ Rename
Item can be renamed.
@ ItemRepresentsFile
Item's path() directly represents a file on disk (since QGIS 3.22)
@ Layer
Represents a map layer.
static QgsDataItemProviderRegistry * dataItemProviderRegistry()
Returns the application's data item provider registry, which keeps a list of data item providers that...
Q_DECL_DEPRECATED void connectItem(QgsDataItem *item)
void connectionsChanged(const QString &providerKey)
Emitted when connections for the specified providerKey have changed in the browser.
bool hasChildren(const QModelIndex &parent=QModelIndex()) const override
QgsFavoritesItem * mFavorites
QgsDataItem * dataItem(const QModelIndex &idx) const
Returns the data item at the specified index, or nullptr if no item exists at the index.
bool canFetchMore(const QModelIndex &parent) const override
void hidePath(QgsDataItem *item)
Hide the given path in the browser model.
void refreshDrives()
Refreshes the list of drive items, removing any corresponding to removed drives and adding newly adde...
void reload()
Reload the whole model.
Qt::ItemFlags flags(const QModelIndex &index) const override
void itemStateChanged(QgsDataItem *item, Qgis::BrowserItemState oldState)
Emitted when an item's state is changed.
void beginInsertItems(QgsDataItem *parent, int first, int last)
QModelIndex findPath(const QString &path, Qt::MatchFlag matchFlag=Qt::MatchExactly)
Returns index of item with given path.
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
void refresh(const QString &path)
Refresh item specified by path.
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
int columnCount(const QModelIndex &parent=QModelIndex()) const override
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
QVector< QgsDataItem * > mRootItems
QMap< QString, QgsDirectoryItem * > driveItems() const
Returns a map of the root drive items shown in the browser.
~QgsBrowserModel() override
int rowCount(const QModelIndex &parent=QModelIndex()) const override
void beginRemoveItems(QgsDataItem *parent, int first, int last)
QStringList mimeTypes() const override
QModelIndex parent(const QModelIndex &index) const override
QModelIndex findItem(QgsDataItem *item, QgsDataItem *parent=nullptr) const
Returns the model index corresponding to the specified data item.
void initialize()
Delayed initialization, needed because the provider registry must be already populated.
QMimeData * mimeData(const QModelIndexList &indexes) const override
void addFavoriteDirectory(const QString &directory, const QString &name=QString())
Adds a directory to the favorites group.
QgsBrowserModel(QObject *parent=nullptr)
Constructor for QgsBrowserModel, with the specified parent object.
QgsDirectoryItem * mProjectHome
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
void stateChanged(const QModelIndex &index, Qgis::BrowserItemState oldState)
Emitted when item children fetch was finished.
void itemDataChanged(QgsDataItem *item)
void addRootItems()
Populates the model.
QModelIndex findUri(const QString &uri, QModelIndex index=QModelIndex())
Returns index of layer item with given uri.
@ CommentRole
Item comment.
@ ProviderKeyRole
Data item provider key that created the item, see QgsDataItem::providerKey()
@ PathRole
Item path used to access path in the tree, see QgsDataItem::mPath.
@ SortRole
Custom sort role, see QgsDataItem::sortKey()
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override
void removeFavorite(const QModelIndex &index)
Removes a favorite directory from its corresponding model index.
void fetchMore(const QModelIndex &parent) override
A Collection: logical collection of layers or subcollections, e.g.
QList< QgsDataItemProvider * > providers() const
Returns the list of available providers.
void providerWillBeRemoved(QgsDataItemProvider *provider)
Emitted when a data item provider is about to be removed.
void providerAdded(QgsDataItemProvider *provider)
Emitted when a new data item provider has been added.
This is the interface for those who want to add custom data items to the browser tree.
virtual int capabilities() const =0
Returns combination of flags from QgsDataProvider::DataCapabilities.
virtual QString name()=0
Human-readable name of the provider name.
virtual QgsDataItem * createDataItem(const QString &path, QgsDataItem *parentItem)=0
Create a new instance of QgsDataItem (or nullptr) for given path and parent item.
Base class for all items in the model.
Definition: qgsdataitem.h:46
void stateChanged(QgsDataItem *item, Qgis::BrowserItemState oldState)
Emitted when an item's state is changed.
void setSortKey(const QVariant &key)
Sets a custom sorting key for the item.
bool hasChildren()
virtual void deleteChildItem(QgsDataItem *child)
Removes and deletes a child item, emitting relevant signals to the model.
virtual QVariant sortKey() const
Returns the sorting key for the item.
Definition: qgsdataitem.cpp:96
virtual Q_DECL_DEPRECATED bool handleDrop(const QMimeData *, Qt::DropAction)
Attempts to process the mime data dropped on this item.
Definition: qgsdataitem.h:233
virtual void refresh(const QVector< QgsDataItem * > &children)
Refresh the items from a specified list of child items.
void dataChanged(QgsDataItem *item)
static void deleteLater(QVector< QgsDataItem * > &items)
void endRemoveItems()
QVector< QgsDataItem * > children() const
Definition: qgsdataitem.h:337
void beginRemoveItems(QgsDataItem *parent, int first, int last)
virtual Q_DECL_DEPRECATED bool acceptDrop()
Returns whether the item accepts drag and dropped layers - e.g.
Definition: qgsdataitem.h:218
Qgis::BrowserItemType type() const
Definition: qgsdataitem.h:324
Qgis::BrowserItemState state() const
virtual bool hasDragEnabled() const
Returns true if the item may be dragged.
Definition: qgsdataitem.h:253
virtual Q_DECL_DEPRECATED bool rename(const QString &name)
Sets a new name for the item, and returns true if the item was successfully renamed.
void connectionsChanged(const QString &providerKey=QString())
Emitted when the connections of the provider with the specified providerKey have changed.
QString name() const
Returns the name of the item (the displayed text for the item).
Definition: qgsdataitem.h:345
QString path() const
Definition: qgsdataitem.h:354
virtual QIcon icon()
void beginInsertItems(QgsDataItem *parent, int first, int last)
QString toolTip() const
Definition: qgsdataitem.h:407
QgsDataItem * parent() const
Gets item parent.
Definition: qgsdataitem.h:330
virtual QgsMimeDataUtils::UriList mimeUris() const
Returns mime URIs for the data item, most data providers will only return a single URI but some data ...
QString providerKey() const
Returns the provider key that created this item (e.g.
void endInsertItems()
virtual Qgis::BrowserItemCapabilities capabilities2() const
Returns the capabilities for the data item.
Definition: qgsdataitem.h:303
void setProviderKey(const QString &value)
Sets the provider key that created this item (e.g.
virtual void populate(const QVector< QgsDataItem * > &children)
A directory: contains subdirectories and layers.
static bool hiddenPath(const QString &path)
Check if the given path is hidden from the browser model.
A directory item showing the a single favorite directory.
Contains various Favorites directories.
void addDirectory(const QString &directory, const QString &name=QString())
Adds a new directory to the favorites group.
void removeDirectory(QgsDirectoryItem *item)
Removes an existing directory from the favorites group.
Item that represents a layer that can be opened with one of the providers.
Definition: qgslayeritem.h:31
virtual QString comments() const
Returns comments of the layer.
Definition: qgslayeritem.h:90
const QgsLayerMetadata & layerMetadata() const
Returns layer's metadata, it may be a default constructed metadata if metadata is not explicitly set.
QList< QgsMimeDataUtils::Uri > UriList
static QMimeData * encodeUriList(const UriList &layers)
Encodes a URI list to a new QMimeData object.
A directory item showing the current project directory.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:476
void homePathChanged()
Emitted when the home path of the project changes.
QString homePath
Definition: qgsproject.h:109
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:3499
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:3498
#define PROJECT_HOME_PREFIX
#define HOME_PREFIX
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39