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