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