QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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 "qgsmimedatautils.h"
29#include "qgslogger.h"
30#include "qgsbrowsermodel.h"
31#include "qgsproject.h"
32#include "qgssettings.h"
33#include "qgsdirectoryitem.h"
34#include "qgslayeritem.h"
35#include "qgsfavoritesitem.h"
36#include "qgslayermetadata.h"
37
38#define PROJECT_HOME_PREFIX "project:"
39#define HOME_PREFIX "home:"
40
42class QgsBrowserWatcher : public QFutureWatcher<QVector <QgsDataItem *> >
43{
44 Q_OBJECT
45
46 public:
47 QgsBrowserWatcher( QgsDataItem *item )
48 : QFutureWatcher( nullptr )
49 , mItem( item )
50 {
51 }
52
53 QgsDataItem *item() const { return mItem; }
54
55 signals:
56 void finished( QgsDataItem *item, const QVector <QgsDataItem *> &items );
57
58 private:
59 QgsDataItem *mItem = nullptr;
60};
62
63// sort function for QList<QgsDataItem*>, e.g. sorted/grouped provider listings
64static bool cmpByDataItemName_( QgsDataItem *a, QgsDataItem *b )
65{
66 return QString::localeAwareCompare( a->name(), b->name() ) < 0;
67}
68
70 : QAbstractItemModel( parent )
71
72{
74 this, &QgsBrowserModel::dataItemProviderAdded );
76 this, &QgsBrowserModel::dataItemProviderWillBeRemoved );
77}
78
80{
82}
83
85{
86 QString home = QgsProject::instance()->homePath();
87 if ( mProjectHome && mProjectHome->path().mid( QStringLiteral( PROJECT_HOME_PREFIX ).length() ) == home )
88 return;
89
90 int idx = mRootItems.indexOf( mProjectHome );
91
92 // using layoutAboutToBeChanged() was messing expanded items
93 if ( idx >= 0 )
94 {
95 beginRemoveRows( QModelIndex(), idx, idx );
96 mRootItems.remove( idx );
97 endRemoveRows();
98 }
99 delete mProjectHome;
100 mProjectHome = home.isNull() ? nullptr : new QgsProjectHomeItem( nullptr, tr( "Project Home" ), home, QStringLiteral( PROJECT_HOME_PREFIX ) + home );
101 if ( mProjectHome )
102 {
103 setupItemConnections( mProjectHome );
104
105 beginInsertRows( QModelIndex(), 0, 0 );
106 mRootItems.insert( 0, mProjectHome );
107 endInsertRows();
108 }
109}
110
112{
114
115 // give the home directory a prominent third place
116 QgsDirectoryItem *item = new QgsDirectoryItem( nullptr, tr( "Home" ), QDir::homePath(),
117 QStringLiteral( HOME_PREFIX ) + QDir::homePath(),
118 QStringLiteral( "special:Home" ) );
119 item->setSortKey( QStringLiteral( " 2" ) );
120 setupItemConnections( item );
121 mRootItems << item;
122
123 // add favorite directories
124 mFavorites = new QgsFavoritesItem( nullptr, tr( "Favorites" ) );
125 if ( mFavorites )
126 {
127 setupItemConnections( mFavorites );
129 }
130
131 // add drives
132 const auto drives { QDir::drives() };
133 for ( const QFileInfo &drive : drives )
134 {
135 const QString path = drive.absolutePath();
136
137 if ( QgsDirectoryItem::hiddenPath( path ) )
138 continue;
139
140 const QString driveName = QStorageInfo( path ).displayName();
141 const QString name = driveName.isEmpty() || driveName == path ? path : QStringLiteral( "%1 (%2)" ).arg( path, driveName );
142
143 QgsDirectoryItem *item = new QgsDirectoryItem( nullptr, name, path, path, QStringLiteral( "special:Drives" ) );
144 item->setSortKey( QStringLiteral( " 3 %1" ).arg( path ) );
145 mDriveItems.insert( path, item );
146
147 setupItemConnections( item );
148 mRootItems << item;
149 }
150
151#ifdef Q_OS_MAC
152 QString path = QString( "/Volumes" );
153 QgsDirectoryItem *vols = new QgsDirectoryItem( nullptr, path, path, path, QStringLiteral( "special:Volumes" ) );
154 setupItemConnections( vols );
155 mRootItems << vols;
156#endif
157
158 // container for displaying providers as sorted groups (by QgsDataProvider::DataCapability enum)
159 QMultiMap<int, QgsDataItem *> providerMap;
160
161 const auto constProviders = QgsApplication::dataItemProviderRegistry()->providers();
162 for ( QgsDataItemProvider *pr : constProviders )
163 {
164 if ( QgsDataItem *item = addProviderRootItem( pr ) )
165 {
166 providerMap.insert( pr->capabilities(), item );
167 }
168 }
169
170 // add as sorted groups by QgsDataProvider::DataCapability enum
171 const auto constUniqueKeys = providerMap.uniqueKeys();
172 for ( int key : constUniqueKeys )
173 {
174 QList<QgsDataItem *> providerGroup = providerMap.values( key );
175 if ( providerGroup.size() > 1 )
176 {
177 std::sort( providerGroup.begin(), providerGroup.end(), cmpByDataItemName_ );
178 }
179
180 const auto constProviderGroup = providerGroup;
181 for ( QgsDataItem *ditem : constProviderGroup )
182 {
183 mRootItems << ditem;
184 }
185 }
186}
187
189{
190 const auto constMRootItems = mRootItems;
191 for ( QgsDataItem *item : constMRootItems )
192 {
193 delete item;
194 }
195
196 mRootItems.clear();
197 mDriveItems.clear();
198}
199
200void QgsBrowserModel::dataItemProviderAdded( QgsDataItemProvider *provider )
201{
202 if ( !mInitialized )
203 return;
204
205 if ( QgsDataItem *item = addProviderRootItem( provider ) )
206 {
207 beginInsertRows( QModelIndex(), rowCount(), rowCount() );
208 mRootItems << item;
209 endInsertRows();
210 }
211}
212
213void QgsBrowserModel::dataItemProviderWillBeRemoved( QgsDataItemProvider *provider )
214{
215 const auto constMRootItems = mRootItems;
216 for ( QgsDataItem *item : constMRootItems )
217 {
218 if ( item->providerKey() == provider->name() )
219 {
220 removeRootItem( item );
221 break; // assuming there is max. 1 root item per provider
222 }
223 }
224}
225
226void QgsBrowserModel::onConnectionsChanged( const QString &providerKey )
227{
228 // refresh the matching provider
229 for ( QgsDataItem *item : std::as_const( mRootItems ) )
230 {
231 if ( item->providerKey() == providerKey )
232 {
233 item->refresh();
234 break; // assuming there is max. 1 root item per provider
235 }
236 }
237
238 emit connectionsChanged( providerKey );
239}
240
241QMap<QString, QgsDirectoryItem *> QgsBrowserModel::driveItems() const
242{
243 return mDriveItems;
244}
245
246
248{
249 if ( ! mInitialized )
250 {
252 addRootItems();
253 mInitialized = true;
254 }
255}
256
257Qt::ItemFlags QgsBrowserModel::flags( const QModelIndex &index ) const
258{
259 if ( !index.isValid() )
260 return Qt::ItemFlags();
261
262 Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
263
264 QgsDataItem *ptr = dataItem( index );
265
266 if ( !ptr )
267 {
268 QgsDebugMsgLevel( QStringLiteral( "FLAGS PROBLEM!" ), 4 );
269 return Qt::ItemFlags();
270 }
271
272 if ( ptr->hasDragEnabled() )
273 flags |= Qt::ItemIsDragEnabled;
274
276 if ( ptr->acceptDrop() )
277 flags |= Qt::ItemIsDropEnabled;
279
282 flags |= Qt::ItemIsEditable;
283
284 return flags;
285}
286
287QVariant QgsBrowserModel::data( const QModelIndex &index, int role ) const
288{
289 if ( !index.isValid() )
290 return QVariant();
291
292 QgsDataItem *item = dataItem( index );
293 if ( !item )
294 {
295 return QVariant();
296 }
297 else if ( role == Qt::DisplayRole || role == Qt::EditRole )
298 {
299 return item->name();
300 }
301 else if ( role == static_cast< int >( QgsBrowserModel::CustomRole::Sort ) )
302 {
303 return item->sortKey();
304 }
305 else if ( role == Qt::ToolTipRole )
306 {
307 return item->toolTip();
308 }
309 else if ( role == Qt::DecorationRole && index.column() == 0 )
310 {
311 return item->icon();
312 }
313 else if ( role == static_cast< int >( QgsBrowserModel::CustomRole::Path ) )
314 {
315 return item->path();
316 }
317 else if ( role == static_cast< int >( QgsBrowserModel::CustomRole::Comment ) )
318 {
319 if ( item->type() == Qgis::BrowserItemType::Layer )
320 {
321 QgsLayerItem *lyrItem = qobject_cast<QgsLayerItem *>( item );
322 return lyrItem->comments();
323 }
324 return QVariant();
325 }
326 else if ( role == static_cast< int >( QgsBrowserModel::CustomRole::LayerMetadata ) )
327 {
328 if ( item->type() == Qgis::BrowserItemType::Layer )
329 {
330 QgsLayerItem *lyrItem = qobject_cast<QgsLayerItem *>( item );
331 return QVariant::fromValue( lyrItem->layerMetadata() );
332 }
333 return QVariant();
334 }
335 else if ( role == static_cast< int >( QgsBrowserModel::CustomRole::ProviderKey ) )
336 {
337 return item->providerKey();
338 }
339 else
340 {
341 // unsupported role
342 return QVariant();
343 }
344}
345
346bool QgsBrowserModel::setData( const QModelIndex &index, const QVariant &value, int role )
347{
348 if ( !index.isValid() )
349 return false;
350
351
352 QgsDataItem *item = dataItem( index );
353 if ( !item )
354 {
355 return false;
356 }
357
360 return false;
361
362 switch ( role )
363 {
364 case Qt::EditRole:
365 {
367 return item->rename( value.toString() );
369 }
370 }
371 return false;
372}
373
374QVariant QgsBrowserModel::headerData( int section, Qt::Orientation orientation, int role ) const
375{
376 Q_UNUSED( section )
377 if ( orientation == Qt::Horizontal && role == Qt::DisplayRole )
378 {
379 return QVariant( "header" );
380 }
381
382 return QVariant();
383}
384
385int QgsBrowserModel::rowCount( const QModelIndex &parent ) const
386{
387 //QgsDebugMsgLevel(QString("isValid = %1 row = %2 column = %3").arg(parent.isValid()).arg(parent.row()).arg(parent.column()), 2);
388
389 if ( !parent.isValid() )
390 {
391 // root item: its children are top level items
392 return mRootItems.count(); // mRoot
393 }
394 else
395 {
396 // ordinary item: number of its children
397 QgsDataItem *item = dataItem( parent );
398 //if ( item ) QgsDebugMsgLevel(QString("path = %1 rowCount = %2").arg(item->path()).arg(item->rowCount()), 2);
399 return item ? item->rowCount() : 0;
400 }
401}
402
403bool QgsBrowserModel::hasChildren( const QModelIndex &parent ) const
404{
405 if ( !parent.isValid() )
406 return !mRootItems.isEmpty(); // root item: its children are top level items
407
408 QgsDataItem *item = dataItem( parent );
409 return item && item->hasChildren();
410}
411
412int QgsBrowserModel::columnCount( const QModelIndex &parent ) const
413{
414 Q_UNUSED( parent )
415 return 1;
416}
417
418QModelIndex QgsBrowserModel::findPath( const QString &path, Qt::MatchFlag matchFlag )
419{
420 return findPath( this, path, matchFlag );
421}
422
423QModelIndex QgsBrowserModel::findPath( QAbstractItemModel *model, const QString &path, Qt::MatchFlag matchFlag )
424{
425 if ( !model )
426 return QModelIndex();
427
428 QModelIndex index; // starting from root
429 bool foundChild = true;
430
431 while ( foundChild )
432 {
433 foundChild = false; // assume that the next child item will not be found
434
435 for ( int i = 0; i < model->rowCount( index ); i++ )
436 {
437 QModelIndex idx = model->index( i, 0, index );
438
439 QString itemPath = model->data( idx, static_cast< int >( QgsBrowserModel::CustomRole::Path ) ).toString();
440 if ( itemPath == path )
441 {
442 QgsDebugMsgLevel( "Arrived " + itemPath, 4 );
443 return idx; // we have found the item we have been looking for
444 }
445
446 // paths are slash separated identifier
447 if ( path.startsWith( itemPath + '/' ) )
448 {
449 foundChild = true;
450 index = idx;
451 break;
452 }
453 }
454 }
455
456 if ( matchFlag == Qt::MatchStartsWith )
457 return index;
458
459 QgsDebugMsgLevel( QStringLiteral( "path not found" ), 4 );
460 return QModelIndex(); // not found
461}
462
463QModelIndex QgsBrowserModel::findUri( const QString &uri, QModelIndex index )
464{
465 for ( int i = 0; i < this->rowCount( index ); i++ )
466 {
467 QModelIndex idx = this->index( i, 0, index );
468
469 if ( qobject_cast<QgsLayerItem *>( dataItem( idx ) ) )
470 {
471 QString itemUri = qobject_cast<QgsLayerItem *>( dataItem( idx ) )->uri();
472
473 if ( itemUri == uri )
474 {
475 QgsDebugMsgLevel( "Arrived " + itemUri, 4 );
476 return idx; // we have found the item we have been looking for
477 }
478 }
479
480 QModelIndex childIdx = findUri( uri, idx );
481 if ( childIdx.isValid() )
482 return childIdx;
483 }
484 return QModelIndex();
485}
486
488{
489 // deprecated, no use
490}
491
493{
494 // TODO: put items creating currently children in threads to deleteLater (does not seem urget because reload() is not used in QGIS)
495 beginResetModel();
497 addRootItems();
498 endResetModel();
499}
500
502{
503 const QList< QFileInfo > drives = QDir::drives();
504 // remove any removed drives
505 const QStringList existingDrives = mDriveItems.keys();
506 for ( const QString &drivePath : existingDrives )
507 {
508 bool stillExists = false;
509 for ( const QFileInfo &drive : drives )
510 {
511 if ( drivePath == drive.absolutePath() )
512 {
513 stillExists = true;
514 break;
515 }
516 }
517
518 if ( stillExists )
519 continue;
520
521 // drive has been removed, remove corresponding item
522 if ( QgsDirectoryItem *driveItem = mDriveItems.value( drivePath ) )
523 removeRootItem( driveItem );
524 }
525
526 for ( const QFileInfo &drive : drives )
527 {
528 const QString path = drive.absolutePath();
529
530 if ( QgsDirectoryItem::hiddenPath( path ) )
531 continue;
532
533 // does an item for this drive already exist?
534 if ( !mDriveItems.contains( path ) )
535 {
536 const QString driveName = QStorageInfo( path ).displayName();
537 const QString name = driveName.isEmpty() || driveName == path ? path : QStringLiteral( "%1 (%2)" ).arg( path, driveName );
538
539 QgsDirectoryItem *item = new QgsDirectoryItem( nullptr, name, path, path, QStringLiteral( "special:Drives" ) );
540 item->setSortKey( QStringLiteral( " 3 %1" ).arg( path ) );
541
542 mDriveItems.insert( path, item );
543 setupItemConnections( item );
544
545 beginInsertRows( QModelIndex(), mRootItems.count(), mRootItems.count() );
546 mRootItems << item;
547 endInsertRows();
548 }
549 }
550}
551
552QModelIndex QgsBrowserModel::index( int row, int column, const QModelIndex &parent ) const
553{
554 if ( column < 0 || column >= columnCount() || row < 0 )
555 return QModelIndex();
556
558 const QVector<QgsDataItem *> &items = p ? p->children() : mRootItems;
559 QgsDataItem *item = items.value( row, nullptr );
560 return item ? createIndex( row, column, item ) : QModelIndex();
561}
562
563QModelIndex QgsBrowserModel::parent( const QModelIndex &index ) const
564{
565 QgsDataItem *item = dataItem( index );
566 if ( !item )
567 return QModelIndex();
568
569 return findItem( item->parent(), item->parent() ? item->parent()->parent() : nullptr );
570}
571
572QModelIndex QgsBrowserModel::findItem( QgsDataItem *item, QgsDataItem *parent ) const
573{
574 const QVector<QgsDataItem *> &items = parent ? parent->children() : mRootItems;
575
576 for ( int i = 0; i < items.size(); i++ )
577 {
578 if ( items[i] == item )
579 return createIndex( i, 0, item );
580
581 QModelIndex childIndex = findItem( item, items[i] );
582 if ( childIndex.isValid() )
583 return childIndex;
584 }
585 return QModelIndex();
586}
587
588void QgsBrowserModel::beginInsertItems( QgsDataItem *parent, int first, int last )
589{
590 QgsDebugMsgLevel( "parent mPath = " + parent->path(), 3 );
591 QModelIndex idx = findItem( parent );
592 if ( !idx.isValid() )
593 return;
594 QgsDebugMsgLevel( QStringLiteral( "valid" ), 3 );
595 beginInsertRows( idx, first, last );
596 QgsDebugMsgLevel( QStringLiteral( "end" ), 3 );
597}
599{
600 QgsDebugMsgLevel( QStringLiteral( "Entered" ), 3 );
601 endInsertRows();
602}
603void QgsBrowserModel::beginRemoveItems( QgsDataItem *parent, int first, int last )
604{
605 QgsDebugMsgLevel( "parent mPath = " + parent->path(), 3 );
606 QModelIndex idx = findItem( parent );
607 if ( !idx.isValid() )
608 return;
609 beginRemoveRows( idx, first, last );
610}
612{
613 QgsDebugMsgLevel( QStringLiteral( "Entered" ), 3 );
614 endRemoveRows();
615}
617{
618 QgsDebugMsgLevel( QStringLiteral( "Entered" ), 3 );
619 QModelIndex idx = findItem( item );
620 if ( !idx.isValid() )
621 return;
622 emit dataChanged( idx, idx );
623}
625{
626 if ( !item )
627 return;
628 QModelIndex idx = findItem( item );
629 if ( !idx.isValid() )
630 return;
631 QgsDebugMsgLevel( QStringLiteral( "item %1 state changed %2 -> %3" ).arg( item->path() ).arg( qgsEnumValueToKey< Qgis::BrowserItemState >( oldState ) ).arg( qgsEnumValueToKey< Qgis::BrowserItemState >( item->state() ) ), 4 );
632 emit stateChanged( idx, oldState );
633}
634
635void QgsBrowserModel::setupItemConnections( QgsDataItem *item )
636{
637 connect( item, &QgsDataItem::beginInsertItems,
639 connect( item, &QgsDataItem::endInsertItems,
641 connect( item, &QgsDataItem::beginRemoveItems,
643 connect( item, &QgsDataItem::endRemoveItems,
645 connect( item, &QgsDataItem::dataChanged,
647 connect( item, &QgsDataItem::stateChanged,
649
650 // if it's a collection item, also forwards connectionsChanged
651 QgsDataCollectionItem *collectionItem = qobject_cast<QgsDataCollectionItem *>( item );
652 if ( collectionItem )
653 connect( collectionItem, &QgsDataCollectionItem::connectionsChanged, this, &QgsBrowserModel::onConnectionsChanged );
654}
655
656QStringList QgsBrowserModel::mimeTypes() const
657{
658 QStringList types;
659 // In theory the mime type convention is: application/x-vnd.<vendor>.<application>.<type>
660 // but it seems a bit over formalized. Would be an application/x-qgis-uri better?
661 types << QStringLiteral( "application/x-vnd.qgis.qgis.uri" );
662 return types;
663}
664
665QMimeData *QgsBrowserModel::mimeData( const QModelIndexList &indexes ) const
666{
668 const auto constIndexes = indexes;
669 for ( const QModelIndex &index : constIndexes )
670 {
671 if ( index.isValid() )
672 {
673 QgsDataItem *ptr = reinterpret_cast< QgsDataItem * >( index.internalPointer() );
675 if ( uris.isEmpty() )
676 {
678 QgsMimeDataUtils::Uri uri = ptr->mimeUri();
680 if ( uri.isValid() )
681 {
682 uris << uri;
683 }
684 }
685 for ( QgsMimeDataUtils::Uri uri : std::as_const( uris ) )
686 {
688 {
689 uri.filePath = ptr->path();
690 }
691 lst.append( uri );
692 }
693 }
694 }
696}
697
698bool QgsBrowserModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int, int, const QModelIndex &parent )
699{
700 QgsDataItem *destItem = dataItem( parent );
701 if ( !destItem )
702 {
703 QgsDebugMsgLevel( QStringLiteral( "DROP PROBLEM!" ), 4 );
704 return false;
705 }
706
708 return destItem->handleDrop( data, action );
710}
711
712QgsDataItem *QgsBrowserModel::dataItem( const QModelIndex &idx ) const
713{
714 void *v = idx.internalPointer();
715 QgsDataItem *d = reinterpret_cast<QgsDataItem *>( v );
716 Q_ASSERT( !v || d );
717 return d;
718}
719
720bool QgsBrowserModel::canFetchMore( const QModelIndex &parent ) const
721{
722 QgsDataItem *item = dataItem( parent );
723 // if ( item )
724 // QgsDebugMsgLevel( QStringLiteral( "path = %1 canFetchMore = %2" ).arg( item->path() ).arg( item && ! item->isPopulated() ), 2 );
725 return ( item && item->state() == Qgis::BrowserItemState::NotPopulated );
726}
727
728void QgsBrowserModel::fetchMore( const QModelIndex &parent )
729{
730 QgsDataItem *item = dataItem( parent );
731
733 return;
734
735 QgsDebugMsgLevel( "path = " + item->path(), 4 );
736
737 item->populate();
738}
739
740/* Refresh dir path */
741void QgsBrowserModel::refresh( const QString &path )
742{
743 QModelIndex index = findPath( path );
744 refresh( index );
745}
746
747/* Refresh item */
748void QgsBrowserModel::refresh( const QModelIndex &index )
749{
750 QgsDataItem *item = dataItem( index );
751 if ( !item || item->state() == Qgis::BrowserItemState::Populating )
752 return;
753
754 QgsDebugMsgLevel( "Refresh " + item->path(), 4 );
755
756 item->refresh();
757}
758
759void QgsBrowserModel::addFavoriteDirectory( const QString &directory, const QString &name )
760{
761 Q_ASSERT( mFavorites );
762 mFavorites->addDirectory( directory, name );
763}
764
765void QgsBrowserModel::removeFavorite( const QModelIndex &index )
766{
767 QgsDirectoryItem *item = qobject_cast<QgsDirectoryItem *>( dataItem( index ) );
768 if ( !item )
769 return;
770
772}
773
775{
776 if ( !favorite )
777 return;
778
779 mFavorites->removeDirectory( favorite );
780}
781
783{
784 QgsSettings settings;
785 QStringList hiddenItems = settings.value( QStringLiteral( "browser/hiddenPaths" ),
786 QStringList() ).toStringList();
787 int idx = hiddenItems.indexOf( item->path() );
788 if ( idx != -1 )
789 {
790 hiddenItems.removeAt( idx );
791 }
792 else
793 {
794 hiddenItems << item->path();
795 }
796 settings.setValue( QStringLiteral( "browser/hiddenPaths" ), hiddenItems );
797 if ( item->parent() )
798 {
799 item->parent()->deleteChildItem( item );
800 }
801 else
802 {
803 removeRootItem( item );
804 }
805}
806
807
808void QgsBrowserModel::removeRootItem( QgsDataItem *item )
809{
810 int i = mRootItems.indexOf( item );
811 beginRemoveRows( QModelIndex(), i, i );
812 mRootItems.remove( i );
813 QgsDirectoryItem *dirItem = qobject_cast< QgsDirectoryItem * >( item );
814 if ( !mDriveItems.key( dirItem ).isEmpty() )
815 {
816 mDriveItems.remove( mDriveItems.key( dirItem ) );
817 }
818 item->deleteLater();
819 endRemoveRows();
820}
821
822QgsDataItem *QgsBrowserModel::addProviderRootItem( QgsDataItemProvider *pr )
823{
824 const Qgis::DataItemProviderCapabilities capabilities = pr->capabilities();
826 {
827 QgsDebugMsgLevel( pr->name() + " does not have any dataCapabilities", 4 );
828 return nullptr;
829 }
830
831 QgsDataItem *item = pr->createDataItem( QString(), nullptr ); // empty path -> top level
832 if ( item )
833 {
834 // make sure the top level key is always set
835 item->setProviderKey( pr->name() );
836 // Forward the signal from the root items to the model (and then to the app)
837 connect( item, &QgsDataItem::connectionsChanged, this, &QgsBrowserModel::onConnectionsChanged );
838 QgsDebugMsgLevel( "Add new top level item : " + item->name(), 4 );
839 setupItemConnections( item );
840 }
841 return item;
842}
843
844// For QgsBrowserWatcher
845#include "qgsbrowsermodel.moc"
@ NoCapabilities
No capabilities.
BrowserItemState
Browser item states.
Definition: qgis.h:674
@ 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)
QFlags< DataItemProviderCapability > DataItemProviderCapabilities
Capabilities for data item providers.
Definition: qgis.h:727
@ 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.
@ Sort
Custom sort role, see QgsDataItem::sortKey()
@ Path
Item path used to access path in the tree, see QgsDataItem::mPath.
@ ProviderKey
Data item provider key that created the item, see QgsDataItem::providerKey()
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 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.
virtual Qgis::DataItemProviderCapabilities capabilities() const =0
Returns combination of flags from QgsDataProvider::DataCapabilities.
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:230
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:331
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:215
Qgis::BrowserItemType type() const
Definition: qgsdataitem.h:318
Qgis::BrowserItemState state() const
virtual bool hasDragEnabled() const
Returns true if the item may be dragged.
Definition: qgsdataitem.h:248
virtual Q_DECL_DEPRECATED bool rename(const QString &name)
Sets a new name for the item, and returns true if the item was successfully renamed.
void connectionsChanged(const QString &providerKey=QString())
Emitted when the connections of the provider with the specified providerKey have changed.
virtual Q_DECL_DEPRECATED QgsMimeDataUtils::Uri mimeUri() const
Returns mime URI for the data item.
QString name() const
Returns the name of the item (the displayed text for the item).
Definition: qgsdataitem.h:339
QString path() const
Definition: qgsdataitem.h:348
virtual QIcon icon()
void beginInsertItems(QgsDataItem *parent, int first, int last)
QString toolTip() const
Definition: qgsdataitem.h:399
QgsDataItem * parent() const
Gets item parent.
Definition: qgsdataitem.h:324
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:297
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:89
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:481
void homePathChanged()
Emitted when the home path of the project changes.
QString homePath
Definition: qgsproject.h:111
This class is a composition of two QSettings instances:
Definition: qgssettings.h:64
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:5776
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:5775
#define PROJECT_HOME_PREFIX
#define HOME_PREFIX
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39