QGIS API Documentation  2.99.0-Master (7d4f81d)
qgsdataitem.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsdataitem.cpp - Data items
3  -------------------
4  begin : 2011-04-01
5  copyright : (C) 2011 Radim Blazek
6  email : radim dot blazek at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include <QApplication>
19 #include <QtConcurrentMap>
20 #include <QtConcurrentRun>
21 #include <QDateTime>
22 #include <QDir>
23 #include <QFileInfo>
24 #include <QMenu>
25 #include <QMouseEvent>
26 #include <QTreeWidget>
27 #include <QTreeWidgetItem>
28 #include <QVector>
29 #include <QStyle>
30 
31 #include "qgis.h"
32 #include "qgsdataitem.h"
33 #include "qgsapplication.h"
34 #include "qgsdataitemprovider.h"
36 #include "qgsdataprovider.h"
37 #include "qgslogger.h"
38 #include "qgsproviderregistry.h"
39 #include "qgsconfig.h"
40 #include "qgssettings.h"
41 #include "qgsanimatedicon.h"
42 
43 // use GDAL VSI mechanism
44 #include "cpl_vsi.h"
45 #include "cpl_string.h"
46 
47 // shared icons
49 {
50  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconPointLayer.svg" ) );
51 }
52 
54 {
55  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconLineLayer.svg" ) );
56 }
57 
59 {
60  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconPolygonLayer.svg" ) );
61 }
62 
64 {
65  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconTableLayer.svg" ) );
66 }
67 
69 {
70  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconRaster.svg" ) );
71 }
72 
74 {
75  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconLayer.png" ) );
76 }
77 
79 {
80  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconDbSchema.png" ) );
81 }
82 
84 {
85  static QIcon sIcon;
86 
87  if ( sIcon.isNull() )
88  {
89  // initialize shared icons
90  QStyle *style = QApplication::style();
91  sIcon = QIcon( style->standardPixmap( QStyle::SP_DirClosedIcon ) );
92  sIcon.addPixmap( style->standardPixmap( QStyle::SP_DirOpenIcon ),
93  QIcon::Normal, QIcon::On );
94  }
95 
96  return sIcon;
97 }
98 
100 {
101  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconFavourites.png" ) );
102 }
103 
105 {
106  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconZip.png" ) );
107 // icon from http://www.softicons.com/free-icons/application-icons/mega-pack-icons-1-by-nikolay-verin/winzip-folder-icon
108 }
109 
110 QgsAnimatedIcon *QgsDataItem::sPopulatingIcon = nullptr;
111 
113 // Do not pass parent to QObject, Qt would delete this when parent is deleted
114  : QObject()
115  , mType( type )
117  , mParent( parent )
118  , mState( NotPopulated )
119  , mName( name )
120  , mPath( path )
121  , mDeferredDelete( false )
122  , mFutureWatcher( nullptr )
123 {
124 }
125 
127 {
128  QgsDebugMsgLevel( QString( "mName = %1 mPath = %2 mChildren.size() = %3" ).arg( mName, mPath ).arg( mChildren.size() ), 2 );
129  Q_FOREACH ( QgsDataItem *child, mChildren )
130  {
131  if ( !child ) // should not happen
132  continue;
133  child->deleteLater();
134  }
135  mChildren.clear();
136 
137  if ( mFutureWatcher && !mFutureWatcher->isFinished() )
138  {
139  // this should not usually happen (until the item was deleted directly when createChildren was running)
140  QgsDebugMsg( "mFutureWatcher not finished (should not happen) -> waitForFinished()" );
141  mDeferredDelete = true;
142  mFutureWatcher->waitForFinished();
143  }
144 
145  delete mFutureWatcher;
146 }
147 
148 QString QgsDataItem::pathComponent( const QString &string )
149 {
150  return QString( string ).replace( QRegExp( "[\\\\/]" ), QStringLiteral( "|" ) );
151 }
152 
154 {
155  QgsDebugMsgLevel( "path = " + path(), 3 );
156  setParent( nullptr ); // also disconnects parent
157  Q_FOREACH ( QgsDataItem *child, mChildren )
158  {
159  if ( !child ) // should not happen
160  continue;
161  child->deleteLater();
162  }
163  mChildren.clear();
164 
165  if ( mFutureWatcher && !mFutureWatcher->isFinished() )
166  {
167  QgsDebugMsg( "mFutureWatcher not finished -> schedule to delete later" );
168  mDeferredDelete = true;
169  }
170  else
171  {
172  QObject::deleteLater();
173  }
174 }
175 
176 void QgsDataItem::deleteLater( QVector<QgsDataItem *> &items )
177 {
178  Q_FOREACH ( QgsDataItem *item, items )
179  {
180  if ( !item ) // should not happen
181  continue;
182  item->deleteLater();
183  }
184  items.clear();
185 }
186 
187 void QgsDataItem::moveToThread( QThread *targetThread )
188 {
189  // QObject::moveToThread() cannot move objects with parent, but QgsDataItem is not using paren/children from QObject
190  Q_FOREACH ( QgsDataItem *child, mChildren )
191  {
192  if ( !child ) // should not happen
193  continue;
194  QgsDebugMsgLevel( "moveToThread child " + child->path(), 3 );
195  child->QObject::setParent( nullptr ); // to be sure
196  child->moveToThread( targetThread );
197  }
198  QObject::moveToThread( targetThread );
199 }
200 
202 {
203  if ( state() == Populating && sPopulatingIcon )
204  return sPopulatingIcon->icon();
205 
206  if ( !mIcon.isNull() )
207  return mIcon;
208 
209  if ( !mIconMap.contains( mIconName ) )
210  {
211  mIconMap.insert( mIconName, mIconName.startsWith( ':' ) ? QIcon( mIconName ) : QgsApplication::getThemeIcon( mIconName ) );
212  }
213 
214  return mIconMap.value( mIconName );
215 }
216 
217 QVector<QgsDataItem *> QgsDataItem::createChildren()
218 {
219  return QVector<QgsDataItem *>();
220 }
221 
222 void QgsDataItem::populate( bool foreground )
223 {
224  if ( state() == Populated || state() == Populating )
225  return;
226 
227  QgsDebugMsgLevel( "mPath = " + mPath, 2 );
228 
229  if ( capabilities2() & QgsDataItem::Fast || foreground )
230  {
232  }
233  else
234  {
235  setState( Populating );
236  // The watcher must not be created with item (in constructor) because the item may be created in thread and the watcher created in thread does not work correctly.
237  if ( !mFutureWatcher )
238  {
239  mFutureWatcher = new QFutureWatcher< QVector <QgsDataItem *> >( this );
240  }
241 
242  connect( mFutureWatcher, &QFutureWatcherBase::finished, this, &QgsDataItem::childrenCreated );
243  mFutureWatcher->setFuture( QtConcurrent::run( runCreateChildren, this ) );
244  }
245 }
246 
247 // This is expected to be run in a separate thread
248 QVector<QgsDataItem *> QgsDataItem::runCreateChildren( QgsDataItem *item )
249 {
250  QgsDebugMsgLevel( "path = " + item->path(), 2 );
251  QTime time;
252  time.start();
253  QVector <QgsDataItem *> children = item->createChildren();
254  QgsDebugMsgLevel( QString( "%1 children created in %2 ms" ).arg( children.size() ).arg( time.elapsed() ), 3 );
255  // Children objects must be pushed to main thread.
256  Q_FOREACH ( QgsDataItem *child, children )
257  {
258  if ( !child ) // should not happen
259  continue;
260  QgsDebugMsgLevel( "moveToThread child " + child->path(), 2 );
261  if ( qApp )
262  child->moveToThread( qApp->thread() ); // moves also children
263  }
264  QgsDebugMsgLevel( QString( "finished path %1: %2 children" ).arg( item->path() ).arg( children.size() ), 3 );
265  return children;
266 }
267 
269 {
270  QgsDebugMsgLevel( QString( "path = %1 children.size() = %2" ).arg( path() ).arg( mFutureWatcher->result().size() ), 3 );
271 
272  if ( deferredDelete() )
273  {
274  QgsDebugMsg( "Item was scheduled to be deleted later" );
275  QObject::deleteLater();
276  return;
277  }
278 
279  if ( mChildren.isEmpty() ) // usually populating but may also be refresh if originally there were no children
280  {
281  populate( mFutureWatcher->result() );
282  }
283  else // refreshing
284  {
285  refresh( mFutureWatcher->result() );
286  }
287  disconnect( mFutureWatcher, &QFutureWatcherBase::finished, this, &QgsDataItem::childrenCreated );
288  emit dataChanged( this ); // to replace loading icon by normal icon
289 }
290 
292 {
293  emit dataChanged( this );
294 }
295 
296 void QgsDataItem::populate( const QVector<QgsDataItem *> &children )
297 {
298  QgsDebugMsgLevel( "mPath = " + mPath, 3 );
299 
300  Q_FOREACH ( QgsDataItem *child, children )
301  {
302  if ( !child ) // should not happen
303  continue;
304  // update after thread finished -> refresh
305  addChildItem( child, true );
306  }
307  setState( Populated );
308 }
309 
311 {
312  QgsDebugMsgLevel( "mPath = " + mPath, 3 );
313 
314  Q_FOREACH ( QgsDataItem *child, mChildren )
315  {
316  QgsDebugMsgLevel( "remove " + child->path(), 3 );
317  child->depopulate(); // recursive
318  deleteChildItem( child );
319  }
321 }
322 
324 {
325  if ( state() == Populating )
326  return;
327 
328  QgsDebugMsgLevel( "mPath = " + mPath, 3 );
329 
331  {
332  refresh( createChildren() );
333  }
334  else
335  {
336  setState( Populating );
337  if ( !mFutureWatcher )
338  {
339  mFutureWatcher = new QFutureWatcher< QVector <QgsDataItem *> >( this );
340  }
341  connect( mFutureWatcher, &QFutureWatcherBase::finished, this, &QgsDataItem::childrenCreated );
342  mFutureWatcher->setFuture( QtConcurrent::run( runCreateChildren, this ) );
343  }
344 }
345 
347 {
348  refresh();
349  emit connectionsChanged();
350 }
351 
352 void QgsDataItem::refresh( const QVector<QgsDataItem *> &children )
353 {
354  QgsDebugMsgLevel( "mPath = " + mPath, 2 );
355 
356  // Remove no more present children
357  QVector<QgsDataItem *> remove;
358  Q_FOREACH ( QgsDataItem *child, mChildren )
359  {
360  if ( !child ) // should not happen
361  continue;
362  if ( findItem( children, child ) >= 0 )
363  continue;
364  remove.append( child );
365  }
366  Q_FOREACH ( QgsDataItem *child, remove )
367  {
368  QgsDebugMsgLevel( "remove " + child->path(), 3 );
369  deleteChildItem( child );
370  }
371 
372  // Add new children
373  Q_FOREACH ( QgsDataItem *child, children )
374  {
375  if ( !child ) // should not happen
376  continue;
377 
378  int index = findItem( mChildren, child );
379  if ( index >= 0 )
380  {
381  // Refresh recursively (some providers may create more generations of descendants)
382  if ( !( child->capabilities2() & QgsDataItem::Fertile ) )
383  {
384  // The child cannot createChildren() itself
385  mChildren.value( index )->refresh( child->children() );
386  }
387 
388  child->deleteLater();
389  continue;
390  }
391  addChildItem( child, true );
392  }
393  setState( Populated );
394 }
395 
397 {
398  return mChildren.size();
399 }
401 {
402  return ( state() == Populated ? !mChildren.isEmpty() : true );
403 }
404 
406 {
407  if ( mParent )
408  {
409  disconnect( this, nullptr, mParent, nullptr );
410  }
411  if ( parent )
412  {
414  connect( this, &QgsDataItem::endInsertItems, parent, &QgsDataItem::endInsertItems );
416  connect( this, &QgsDataItem::endRemoveItems, parent, &QgsDataItem::endRemoveItems );
417  connect( this, &QgsDataItem::dataChanged, parent, &QgsDataItem::dataChanged );
418  connect( this, &QgsDataItem::stateChanged, parent, &QgsDataItem::stateChanged );
419  }
420  mParent = parent;
421 }
422 
424 {
425  Q_ASSERT( child );
426  QgsDebugMsgLevel( QString( "path = %1 add child #%2 - %3 - %4" ).arg( mPath ).arg( mChildren.size() ).arg( child->mName ).arg( child->mType ), 3 );
427 
428  //calculate position to insert child
429  int i;
430  if ( type() == Directory )
431  {
432  for ( i = 0; i < mChildren.size(); i++ )
433  {
434  // sort items by type, so directories are before data items
435  if ( mChildren.at( i )->mType == child->mType &&
436  mChildren.at( i )->mName.localeAwareCompare( child->mName ) > 0 )
437  break;
438  }
439  }
440  else
441  {
442  for ( i = 0; i < mChildren.size(); i++ )
443  {
444  if ( mChildren.at( i )->mName.localeAwareCompare( child->mName ) >= 0 )
445  break;
446  }
447  }
448 
449  if ( refresh )
450  emit beginInsertItems( this, i, i );
451 
452  mChildren.insert( i, child );
453  child->setParent( this );
454 
455  if ( refresh )
456  emit endInsertItems();
457 }
458 
460 {
461  QgsDebugMsgLevel( "mName = " + child->mName, 2 );
462  int i = mChildren.indexOf( child );
463  Q_ASSERT( i >= 0 );
464  emit beginRemoveItems( this, i, i );
465  mChildren.remove( i );
466  child->deleteLater();
467  emit endRemoveItems();
468 }
469 
471 {
472  QgsDebugMsgLevel( "mName = " + child->mName, 2 );
473  int i = mChildren.indexOf( child );
474  Q_ASSERT( i >= 0 );
475  if ( i < 0 )
476  {
477  child->setParent( nullptr );
478  return nullptr;
479  }
480 
481  emit beginRemoveItems( this, i, i );
482  mChildren.remove( i );
483  emit endRemoveItems();
484  return child;
485 }
486 
487 int QgsDataItem::findItem( QVector<QgsDataItem *> items, QgsDataItem *item )
488 {
489  for ( int i = 0; i < items.size(); i++ )
490  {
491  Q_ASSERT_X( items[i], "findItem", QString( "item %1 is nullptr" ).arg( i ).toLatin1() );
492  QgsDebugMsgLevel( QString::number( i ) + " : " + items[i]->mPath + " x " + item->mPath, 2 );
493  if ( items[i]->equal( item ) )
494  return i;
495  }
496  return -1;
497 }
498 
499 bool QgsDataItem::equal( const QgsDataItem *other )
500 {
501  return ( metaObject()->className() == other->metaObject()->className() &&
502  mPath == other->path() );
503 }
504 
506 {
507  return mState;
508 }
509 
511 {
512  QgsDebugMsgLevel( QString( "item %1 set state %2 -> %3" ).arg( path() ).arg( this->state() ).arg( state ), 3 );
513  if ( state == mState )
514  return;
515 
516  State oldState = mState;
517 
518  if ( state == Populating ) // start loading
519  {
520  if ( !sPopulatingIcon )
521  {
522  // TODO: ensure that QgsAnimatedIcon is created on UI thread only
523  sPopulatingIcon = new QgsAnimatedIcon( QgsApplication::iconPath( QStringLiteral( "/mIconLoading.gif" ) ), QgsApplication::instance() );
524  }
525 
526  sPopulatingIcon->connectFrameChanged( this, &QgsDataItem::updateIcon );
527  }
528  else if ( mState == Populating && sPopulatingIcon ) // stop loading
529  {
530  sPopulatingIcon->disconnectFrameChanged( this, &QgsDataItem::updateIcon );
531  }
532 
533 
534  mState = state;
535 
536  emit stateChanged( this, oldState );
537  if ( state == Populated )
538  updateIcon();
539 }
540 
541 // ---------------------------------------------------------------------
542 
543 QgsLayerItem::QgsLayerItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &uri, LayerType layerType, const QString &providerKey )
544  : QgsDataItem( Layer, parent, name, path )
545  , mProviderKey( providerKey )
546  , mUri( uri )
547  , mLayerType( layerType )
548 {
549  switch ( layerType )
550  {
551  case Point:
552  mIconName = QStringLiteral( "/mIconPointLayer.svg" );
553  break;
554  case Line:
555  mIconName = QStringLiteral( "/mIconLineLayer.svg" );
556  break;
557  case Polygon:
558  mIconName = QStringLiteral( "/mIconPolygonLayer.svg" );
559  break;
560  // TODO add a new icon for generic Vector layers
561  case Vector :
562  mIconName = QStringLiteral( "/mIconPolygonLayer.svg" );
563  break;
564  case TableLayer:
565  mIconName = QStringLiteral( "/mIconTableLayer.svg" );
566  break;
567  case Raster:
568  mIconName = QStringLiteral( "/mIconRaster.svg" );
569  break;
570  default:
571  mIconName = QStringLiteral( "/mIconLayer.png" );
572  break;
573  }
574 }
575 
577 {
583 }
584 
586 {
587  static int enumIdx = staticMetaObject.indexOfEnumerator( "LayerType" );
588  return staticMetaObject.enumerator( enumIdx ).valueToKey( layerType );
589 }
590 
591 bool QgsLayerItem::equal( const QgsDataItem *other )
592 {
593  //QgsDebugMsg ( mPath + " x " + other->mPath );
594  if ( type() != other->type() )
595  {
596  return false;
597  }
598  //const QgsLayerItem *o = qobject_cast<const QgsLayerItem *> ( other );
599  const QgsLayerItem *o = dynamic_cast<const QgsLayerItem *>( other );
600  if ( !o )
601  return false;
602 
603  return ( mPath == o->mPath && mName == o->mName && mUri == o->mUri && mProviderKey == o->mProviderKey );
604 }
605 
607 {
609 
610  switch ( mapLayerType() )
611  {
613  u.layerType = QStringLiteral( "vector" );
614  break;
616  u.layerType = QStringLiteral( "raster" );
617  break;
619  u.layerType = QStringLiteral( "plugin" );
620  break;
621  default:
622  return u; // invalid URI
623  }
624 
625  u.providerKey = providerKey();
626  u.name = layerName();
627  u.uri = uri();
630  return u;
631 }
632 
633 // ---------------------------------------------------------------------
635  : QgsDataItem( Collection, parent, name, path )
636 {
638  mIconName = QStringLiteral( "/mIconDbSchema.png" );
639 }
640 
642 {
643  QgsDebugMsgLevel( "mName = " + mName + " mPath = " + mPath, 2 );
644 
645 // Do not delete children, children are deleted by QObject parent
646 #if 0
647  Q_FOREACH ( QgsDataItem *i, mChildren )
648  {
649  QgsDebugMsgLevel( QString( "delete child = 0x%0" ).arg( ( qlonglong )i, 8, 16, QLatin1Char( '0' ) ), 2 );
650  delete i;
651  }
652 #endif
653 }
654 
655 //-----------------------------------------------------------------------
656 
657 QgsDirectoryItem::QgsDirectoryItem( QgsDataItem *parent, const QString &name, const QString &path )
658  : QgsDataCollectionItem( parent, name, path )
659  , mDirPath( path )
660  , mFileSystemWatcher( nullptr )
661  , mRefreshLater( false )
662 {
663  mType = Directory;
664  init();
665 }
666 
667 QgsDirectoryItem::QgsDirectoryItem( QgsDataItem *parent, const QString &name, const QString &dirPath, const QString &path )
668  : QgsDataCollectionItem( parent, name, path )
669  , mDirPath( dirPath )
670  , mFileSystemWatcher( nullptr )
671  , mRefreshLater( false )
672 {
673  mType = Directory;
674  init();
675 }
676 
678 {
679 }
680 
682 {
683  if ( state() == Populating )
684  return QgsDataItem::icon();
685  return iconDir();
686 }
687 
688 
689 QVector<QgsDataItem *> QgsDirectoryItem::createChildren()
690 {
691  QVector<QgsDataItem *> children;
692  QDir dir( mDirPath );
693 
694  QStringList entries = dir.entryList( QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name | QDir::IgnoreCase );
695  Q_FOREACH ( const QString &subdir, entries )
696  {
697  if ( mRefreshLater )
698  {
699  deleteLater( children );
700  return children;
701  }
702 
703  QString subdirPath = dir.absoluteFilePath( subdir );
704 
705  QgsDebugMsgLevel( QString( "creating subdir: %1" ).arg( subdirPath ), 2 );
706 
707  QString path = mPath + '/' + subdir; // may differ from subdirPath
708  if ( QgsDirectoryItem::hiddenPath( path ) )
709  continue;
710  QgsDirectoryItem *item = new QgsDirectoryItem( this, subdir, subdirPath, path );
711  // propagate signals up to top
712 
713  children.append( item );
714  }
715 
716  QStringList fileEntries = dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot | QDir::Files, QDir::Name );
717  Q_FOREACH ( const QString &name, fileEntries )
718  {
719  if ( mRefreshLater )
720  {
721  deleteLater( children );
722  return children;
723  }
724 
725  QString path = dir.absoluteFilePath( name );
726  QFileInfo fileInfo( path );
727 
728  if ( fileInfo.suffix() == QLatin1String( "qgs" ) )
729  {
730  QgsDataItem *item = new QgsProjectItem( this, name, path );
731  children.append( item );
732  continue;
733  }
734 
735  // vsizip support was added to GDAL/OGR 1.6 but GDAL_VERSION_NUM not available here
736  // so we assume it's available anyway
737  {
738  QgsDataItem *item = QgsZipItem::itemFromPath( this, path, name, mPath + '/' + name );
739  if ( item )
740  {
741  children.append( item );
742  continue;
743  }
744  }
745 
746  Q_FOREACH ( QgsDataItemProvider *provider, QgsApplication::dataItemProviderRegistry()->providers() )
747  {
748  int capabilities = provider->capabilities();
749 
750  if ( !( ( fileInfo.isFile() && ( capabilities & QgsDataProvider::File ) ) ||
751  ( fileInfo.isDir() && ( capabilities & QgsDataProvider::Dir ) ) ) )
752  {
753  continue;
754  }
755 
756  QgsDataItem *item = provider->createDataItem( path, this );
757  if ( item )
758  {
759  children.append( item );
760  }
761  }
762 
763  }
764 
765  return children;
766 }
767 
769 {
771 
772  if ( state == Populated )
773  {
774  if ( !mFileSystemWatcher )
775  {
776  mFileSystemWatcher = new QFileSystemWatcher( this );
777  mFileSystemWatcher->addPath( mDirPath );
778  connect( mFileSystemWatcher, &QFileSystemWatcher::directoryChanged, this, &QgsDirectoryItem::directoryChanged );
779  }
780  }
781  else if ( state == NotPopulated )
782  {
783  if ( mFileSystemWatcher )
784  {
785  delete mFileSystemWatcher;
786  mFileSystemWatcher = nullptr;
787  }
788  }
789 }
790 
792 {
793  if ( state() == Populating )
794  {
795  // schedule to refresh later, because refresh() simply returns if Populating
796  mRefreshLater = true;
797  }
798  else
799  {
800  // We definintely don't want the temporary files created by sqlite
801  // to re-trigger a refresh in an infinite loop.
802  disconnect( mFileSystemWatcher, &QFileSystemWatcher::directoryChanged, this, &QgsDirectoryItem::directoryChanged );
803  // QFileSystemWhatcher::directoryChanged is emitted when a
804  // file is created and not when it is closed/flushed.
805  //
806  // Delay to give to OS the time to complete writing the file
807  // this happens when a new file appears in the directory and
808  // the item's children thread will try to open the file with
809  // GDAL or OGR even if it is still being written.
810  QTimer::singleShot( 100, this, SLOT( refresh() ) );
811  }
812 }
813 
814 bool QgsDirectoryItem::hiddenPath( const QString &path )
815 {
816  QgsSettings settings;
817  QStringList hiddenItems = settings.value( QStringLiteral( "browser/hiddenPaths" ),
818  QStringList() ).toStringList();
819  int idx = hiddenItems.indexOf( path );
820  return ( idx > -1 );
821 }
822 
823 
825 {
826  QgsDebugMsgLevel( QString( "mRefreshLater = %1" ).arg( mRefreshLater ), 3 );
827 
828  if ( mRefreshLater )
829  {
830  QgsDebugMsgLevel( "directory changed during createChidren() -> refresh() again", 3 );
831  mRefreshLater = false;
832  setState( Populated );
833  refresh();
834  }
835  else
836  {
838  }
839  // Re-connect the file watcher after all children have been created
840  connect( mFileSystemWatcher, &QFileSystemWatcher::directoryChanged, this, &QgsDirectoryItem::directoryChanged );
841 }
842 
844 {
845  //QgsDebugMsg ( mPath + " x " + other->mPath );
846  if ( type() != other->type() )
847  {
848  return false;
849  }
850  return ( path() == other->path() );
851 }
852 
854 {
855  return new QgsDirectoryParamWidget( mPath );
856 }
857 
859  : QTreeWidget( parent )
860 {
861  setRootIsDecorated( false );
862 
863  // name, size, date, permissions, owner, group, type
864  setColumnCount( 7 );
865  QStringList labels;
866  labels << tr( "Name" ) << tr( "Size" ) << tr( "Date" ) << tr( "Permissions" ) << tr( "Owner" ) << tr( "Group" ) << tr( "Type" );
867  setHeaderLabels( labels );
868 
869  QStyle *style = QApplication::style();
870  QIcon iconDirectory = QIcon( style->standardPixmap( QStyle::SP_DirClosedIcon ) );
871  QIcon iconFile = QIcon( style->standardPixmap( QStyle::SP_FileIcon ) );
872  QIcon iconDirLink = QIcon( style->standardPixmap( QStyle::SP_DirLinkIcon ) );
873  QIcon iconFileLink = QIcon( style->standardPixmap( QStyle::SP_FileLinkIcon ) );
874 
875  QList<QTreeWidgetItem *> items;
876 
877  QDir dir( path );
878  QStringList entries = dir.entryList( QDir::AllEntries | QDir::NoDotAndDotDot, QDir::Name | QDir::IgnoreCase );
879  Q_FOREACH ( const QString &name, entries )
880  {
881  QFileInfo fi( dir.absoluteFilePath( name ) );
882  QStringList texts;
883  texts << name;
884  QString size;
885  if ( fi.size() > 1024 )
886  {
887  size = size.sprintf( "%.1f KiB", fi.size() / 1024.0 );
888  }
889  else if ( fi.size() > 1.048576e6 )
890  {
891  size = size.sprintf( "%.1f MiB", fi.size() / 1.048576e6 );
892  }
893  else
894  {
895  size = QStringLiteral( "%1 B" ).arg( fi.size() );
896  }
897  texts << size;
898  texts << fi.lastModified().toString( Qt::SystemLocaleShortDate );
899  QString perm;
900  perm += fi.permission( QFile::ReadOwner ) ? 'r' : '-';
901  perm += fi.permission( QFile::WriteOwner ) ? 'w' : '-';
902  perm += fi.permission( QFile::ExeOwner ) ? 'x' : '-';
903  // QFile::ReadUser, QFile::WriteUser, QFile::ExeUser
904  perm += fi.permission( QFile::ReadGroup ) ? 'r' : '-';
905  perm += fi.permission( QFile::WriteGroup ) ? 'w' : '-';
906  perm += fi.permission( QFile::ExeGroup ) ? 'x' : '-';
907  perm += fi.permission( QFile::ReadOther ) ? 'r' : '-';
908  perm += fi.permission( QFile::WriteOther ) ? 'w' : '-';
909  perm += fi.permission( QFile::ExeOther ) ? 'x' : '-';
910  texts << perm;
911 
912  texts << fi.owner();
913  texts << fi.group();
914 
915  QString type;
916  QIcon icon;
917  if ( fi.isDir() && fi.isSymLink() )
918  {
919  type = tr( "folder" );
920  icon = iconDirLink;
921  }
922  else if ( fi.isDir() )
923  {
924  type = tr( "folder" );
925  icon = iconDirectory;
926  }
927  else if ( fi.isFile() && fi.isSymLink() )
928  {
929  type = tr( "file" );
930  icon = iconFileLink;
931  }
932  else if ( fi.isFile() )
933  {
934  type = tr( "file" );
935  icon = iconFile;
936  }
937 
938  texts << type;
939 
940  QTreeWidgetItem *item = new QTreeWidgetItem( texts );
941  item->setIcon( 0, icon );
942  items << item;
943  }
944 
945  addTopLevelItems( items );
946 
947  // hide columns that are not requested
948  QgsSettings settings;
949  QList<QVariant> lst = settings.value( QStringLiteral( "dataitem/directoryHiddenColumns" ) ).toList();
950  Q_FOREACH ( const QVariant &colVariant, lst )
951  {
952  setColumnHidden( colVariant.toInt(), true );
953  }
954 }
955 
957 {
958  if ( event->button() == Qt::RightButton )
959  {
960  // show the popup menu
961  QMenu popupMenu;
962 
963  QStringList labels;
964  labels << tr( "Name" ) << tr( "Size" ) << tr( "Date" ) << tr( "Permissions" ) << tr( "Owner" ) << tr( "Group" ) << tr( "Type" );
965  for ( int i = 0; i < labels.count(); i++ )
966  {
967  QAction *action = popupMenu.addAction( labels[i], this, SLOT( showHideColumn() ) );
968  action->setObjectName( QString::number( i ) );
969  action->setCheckable( true );
970  action->setChecked( !isColumnHidden( i ) );
971  }
972 
973  popupMenu.exec( event->globalPos() );
974  }
975 }
976 
978 {
979  QAction *action = qobject_cast<QAction *>( sender() );
980  if ( !action )
981  return; // something is wrong
982 
983  int columnIndex = action->objectName().toInt();
984  setColumnHidden( columnIndex, !isColumnHidden( columnIndex ) );
985 
986  // save in settings
987  QgsSettings settings;
988  QList<QVariant> lst;
989  for ( int i = 0; i < columnCount(); i++ )
990  {
991  if ( isColumnHidden( i ) )
992  lst.append( QVariant( i ) );
993  }
994  settings.setValue( QStringLiteral( "dataitem/directoryHiddenColumns" ), lst );
995 }
996 
997 QgsProjectItem::QgsProjectItem( QgsDataItem *parent, const QString &name, const QString &path )
998  : QgsDataItem( QgsDataItem::Project, parent, name, path )
999 {
1000  mIconName = QStringLiteral( ":/images/icons/qgis-icon-16x16.png" );
1001 
1002  setState( Populated ); // no more children
1003 }
1004 
1005 QgsErrorItem::QgsErrorItem( QgsDataItem *parent, const QString &error, const QString &path )
1006  : QgsDataItem( QgsDataItem::Error, parent, error, path )
1007 {
1008  mIconName = QStringLiteral( "/mIconDelete.png" );
1009 
1010  setState( Populated ); // no more children
1011 }
1012 
1014  : QgsDataCollectionItem( parent, name, QStringLiteral( "favorites:" ) )
1015 {
1016  Q_UNUSED( path );
1017  mCapabilities |= Fast;
1018  mType = Favorites;
1019  mIconName = QStringLiteral( "/mIconFavourites.png" );
1020  populate();
1021 }
1022 
1023 QVector<QgsDataItem *> QgsFavoritesItem::createChildren()
1024 {
1025  QVector<QgsDataItem *> children;
1026 
1027  QgsSettings settings;
1028  QStringList favDirs = settings.value( QStringLiteral( "browser/favourites" ), QVariant() ).toStringList();
1029 
1030  Q_FOREACH ( const QString &favDir, favDirs )
1031  {
1032  children << createChildren( favDir );
1033  }
1034 
1035  return children;
1036 }
1037 
1038 void QgsFavoritesItem::addDirectory( const QString &favDir )
1039 {
1040  QgsSettings settings;
1041  QStringList favDirs = settings.value( QStringLiteral( "browser/favourites" ) ).toStringList();
1042  favDirs.append( favDir );
1043  settings.setValue( QStringLiteral( "browser/favourites" ), favDirs );
1044 
1045  if ( state() == Populated )
1046  {
1047  QVector<QgsDataItem *> items = createChildren( favDir );
1048  Q_FOREACH ( QgsDataItem *item, items )
1049  {
1050  addChildItem( item, true );
1051  }
1052  }
1053 }
1054 
1056 {
1057  if ( !item )
1058  return;
1059 
1060  QgsSettings settings;
1061  QStringList favDirs = settings.value( QStringLiteral( "browser/favourites" ) ).toStringList();
1062  favDirs.removeAll( item->dirPath() );
1063  settings.setValue( QStringLiteral( "browser/favourites" ), favDirs );
1064 
1065  int idx = findItem( mChildren, item );
1066  if ( idx < 0 )
1067  {
1068  QgsDebugMsg( QString( "favorites item %1 not found" ).arg( item->path() ) );
1069  return;
1070  }
1071 
1072  if ( state() == Populated )
1073  deleteChildItem( mChildren.at( idx ) );
1074 }
1075 
1076 QVector<QgsDataItem *> QgsFavoritesItem::createChildren( const QString &favDir )
1077 {
1078  QVector<QgsDataItem *> children;
1079  QString pathName = pathComponent( favDir );
1080  Q_FOREACH ( QgsDataItemProvider *provider, QgsApplication::dataItemProviderRegistry()->providers() )
1081  {
1082  int capabilities = provider->capabilities();
1083 
1084  if ( capabilities & QgsDataProvider::Dir )
1085  {
1086  QgsDataItem *item = provider->createDataItem( favDir, this );
1087  if ( item )
1088  {
1089  item->setName( favDir );
1090  children.append( item );
1091  }
1092  }
1093  }
1094  if ( children.isEmpty() )
1095  {
1096  QgsDataItem *item = new QgsDirectoryItem( this, favDir, favDir, mPath + '/' + pathName );
1097  if ( item )
1098  {
1099  children.append( item );
1100  }
1101  }
1102  return children;
1103 }
1104 
1105 //-----------------------------------------------------------------------
1106 QStringList QgsZipItem::sProviderNames = QStringList();
1107 QVector<dataItem_t *> QgsZipItem::sDataItemPtr = QVector<dataItem_t *>();
1108 
1109 
1110 QgsZipItem::QgsZipItem( QgsDataItem *parent, const QString &name, const QString &path )
1111  : QgsDataCollectionItem( parent, name, path )
1112 {
1113  mFilePath = path;
1114  init();
1115 }
1116 
1117 QgsZipItem::QgsZipItem( QgsDataItem *parent, const QString &name, const QString &filePath, const QString &path )
1118  : QgsDataCollectionItem( parent, name, path )
1119  , mFilePath( filePath )
1120 {
1121  init();
1122 }
1123 
1124 void QgsZipItem::init()
1125 {
1126  mType = Collection; //Zip??
1127  mIconName = QStringLiteral( "/mIconZip.png" );
1129 
1130  if ( sProviderNames.isEmpty() )
1131  {
1132  // QStringList keys = QgsProviderRegistry::instance()->providerList();
1133  // only use GDAL and OGR providers as we use the VSIFILE mechanism
1134  QStringList keys;
1135  // keys << "ogr" << "gdal";
1136  keys << QStringLiteral( "gdal" ) << QStringLiteral( "ogr" );
1137 
1138  QStringList::const_iterator i;
1139  for ( i = keys.begin(); i != keys.end(); ++i )
1140  {
1141  QString k( *i );
1142  QgsDebugMsgLevel( "provider " + k, 3 );
1143  // some providers hangs with empty uri (PostGIS) etc...
1144  // -> using libraries directly
1145  std::unique_ptr< QLibrary > library( QgsProviderRegistry::instance()->createProviderLibrary( k ) );
1146  if ( library )
1147  {
1148  dataCapabilities_t *dataCapabilities = reinterpret_cast< dataCapabilities_t * >( cast_to_fptr( library->resolve( "dataCapabilities" ) ) );
1149  if ( !dataCapabilities )
1150  {
1151  QgsDebugMsg( library->fileName() + " does not have dataCapabilities" );
1152  continue;
1153  }
1154  if ( dataCapabilities() == QgsDataProvider::NoDataCapabilities )
1155  {
1156  QgsDebugMsg( library->fileName() + " has NoDataCapabilities" );
1157  continue;
1158  }
1159  QgsDebugMsg( QString( "%1 dataCapabilities : %2" ).arg( library->fileName() ).arg( dataCapabilities() ) );
1160 
1161  dataItem_t *dataItem = reinterpret_cast< dataItem_t * >( cast_to_fptr( library->resolve( "dataItem" ) ) );
1162  if ( ! dataItem )
1163  {
1164  QgsDebugMsg( library->fileName() + " does not have dataItem" );
1165  continue;
1166  }
1167 
1168  // mLibraries.append( library );
1169  sDataItemPtr.append( dataItem );
1170  sProviderNames.append( k );
1171  }
1172  else
1173  {
1174  //QgsDebugMsg ( "Cannot get provider " + k );
1175  }
1176  }
1177  }
1178 
1179 }
1180 
1181 // internal function to scan a vsidir (zip or tar file) recursively
1182 // GDAL trunk has this since r24423 (05/16/12) - VSIReadDirRecursive()
1183 // use a copy of the function internally for now,
1184 // but use char ** and CSLAddString, because CPLStringList was added in gdal-1.9
1185 char **VSIReadDirRecursive1( const char *pszPath )
1186 {
1187  // CPLStringList oFiles = nullptr;
1188  char **papszOFiles = nullptr;
1189  char **papszFiles1 = nullptr;
1190  char **papszFiles2 = nullptr;
1191  VSIStatBufL psStatBuf;
1192  CPLString osTemp1, osTemp2;
1193  int i, j;
1194  int nCount1, nCount2;
1195 
1196  // get listing
1197  papszFiles1 = VSIReadDir( pszPath );
1198  if ( ! papszFiles1 )
1199  return nullptr;
1200 
1201  // get files and directories inside listing
1202  nCount1 = CSLCount( papszFiles1 );
1203  for ( i = 0; i < nCount1; i++ )
1204  {
1205  // build complete file name for stat
1206  osTemp1.clear();
1207  osTemp1.append( pszPath );
1208  osTemp1.append( "/" );
1209  osTemp1.append( papszFiles1[i] );
1210 
1211  // if is file, add it
1212  if ( VSIStatL( osTemp1.c_str(), &psStatBuf ) == 0 &&
1213  VSI_ISREG( psStatBuf.st_mode ) )
1214  {
1215  // oFiles.AddString( papszFiles1[i] );
1216  papszOFiles = CSLAddString( papszOFiles, papszFiles1[i] );
1217  }
1218  else if ( VSIStatL( osTemp1.c_str(), &psStatBuf ) == 0 &&
1219  VSI_ISDIR( psStatBuf.st_mode ) )
1220  {
1221  // add directory entry
1222  osTemp2.clear();
1223  osTemp2.append( papszFiles1[i] );
1224  osTemp2.append( "/" );
1225  // oFiles.AddString( osTemp2.c_str() );
1226  papszOFiles = CSLAddString( papszOFiles, osTemp2.c_str() );
1227 
1228  // recursively add files inside directory
1229  papszFiles2 = VSIReadDirRecursive1( osTemp1.c_str() );
1230  if ( papszFiles2 )
1231  {
1232  nCount2 = CSLCount( papszFiles2 );
1233  for ( j = 0; j < nCount2; j++ )
1234  {
1235  osTemp2.clear();
1236  osTemp2.append( papszFiles1[i] );
1237  osTemp2.append( "/" );
1238  osTemp2.append( papszFiles2[j] );
1239  // oFiles.AddString( osTemp2.c_str() );
1240  papszOFiles = CSLAddString( papszOFiles, osTemp2.c_str() );
1241  }
1242  CSLDestroy( papszFiles2 );
1243  }
1244  }
1245  }
1246  CSLDestroy( papszFiles1 );
1247 
1248  // return oFiles.StealList();
1249  return papszOFiles;
1250 }
1251 
1252 QVector<QgsDataItem *> QgsZipItem::createChildren()
1253 {
1254  QVector<QgsDataItem *> children;
1255  QString tmpPath;
1256  QgsSettings settings;
1257  QString scanZipSetting = settings.value( QStringLiteral( "qgis/scanZipInBrowser2" ), "basic" ).toString();
1258 
1259  mZipFileList.clear();
1260 
1261  QgsDebugMsgLevel( QString( "mFilePath = %1 path = %2 name= %3 scanZipSetting= %4 vsiPrefix= %5" ).arg( mFilePath, path(), name(), scanZipSetting, mVsiPrefix ), 2 );
1262 
1263  // if scanZipBrowser == no: skip to the next file
1264  if ( scanZipSetting == QLatin1String( "no" ) )
1265  {
1266  return children;
1267  }
1268 
1269  // first get list of files
1270  getZipFileList();
1271 
1272  // loop over files inside zip
1273  Q_FOREACH ( const QString &fileName, mZipFileList )
1274  {
1275  QFileInfo info( fileName );
1276  tmpPath = mVsiPrefix + mFilePath + '/' + fileName;
1277  QgsDebugMsgLevel( "tmpPath = " + tmpPath, 3 );
1278 
1279  // Q_FOREACH( dataItem_t *dataItem, mDataItemPtr )
1280  for ( int i = 0; i < sProviderNames.size(); i++ )
1281  {
1282  // ugly hack to remove .dbf file if there is a .shp file
1283  if ( sProviderNames[i] == QLatin1String( "ogr" ) )
1284  {
1285  if ( info.suffix().toLower() == QLatin1String( "dbf" ) )
1286  {
1287  if ( mZipFileList.indexOf( fileName.left( fileName.count() - 4 ) + ".shp" ) != -1 )
1288  continue;
1289  }
1290  if ( info.completeSuffix().toLower() == QLatin1String( "shp.xml" ) )
1291  {
1292  continue;
1293  }
1294  }
1295 
1296  // try to get data item from provider
1297  dataItem_t *dataItem = sDataItemPtr.at( i );
1298  if ( dataItem )
1299  {
1300  QgsDebugMsgLevel( QString( "trying to load item %1 with %2" ).arg( tmpPath, sProviderNames.at( i ) ), 3 );
1301  QgsDataItem *item = dataItem( tmpPath, this );
1302  if ( item )
1303  {
1304  QgsDebugMsgLevel( "loaded item", 3 );
1305  // the item comes with zipped file name, set the name to relative path within zip file
1306  item->setName( fileName );
1307  children.append( item );
1308  break;
1309  }
1310  else
1311  {
1312  QgsDebugMsgLevel( "not loaded item", 3 );
1313  }
1314  }
1315  }
1316 
1317  }
1318 
1319  return children;
1320 }
1321 
1322 QgsDataItem *QgsZipItem::itemFromPath( QgsDataItem *parent, const QString &path, const QString &name )
1323 {
1324  return itemFromPath( parent, path, name, path );
1325 }
1326 
1327 QgsDataItem *QgsZipItem::itemFromPath( QgsDataItem *parent, const QString &filePath, const QString &name, const QString &path )
1328 {
1329  QgsSettings settings;
1330  QString scanZipSetting = settings.value( QStringLiteral( "qgis/scanZipInBrowser2" ), "basic" ).toString();
1331  int zipFileCount = 0;
1332  QStringList zipFileList;
1333  QString vsiPrefix = QgsZipItem::vsiPrefix( filePath );
1334  QgsZipItem *zipItem = nullptr;
1335  bool populated = false;
1336 
1337  QgsDebugMsgLevel( QString( "path = %1 name= %2 scanZipSetting= %3 vsiPrefix= %4" ).arg( path, name, scanZipSetting, vsiPrefix ), 3 );
1338 
1339  // don't scan if scanZipBrowser == no
1340  if ( scanZipSetting == QLatin1String( "no" ) )
1341  return nullptr;
1342 
1343  // don't scan if this file is not a /vsizip/ or /vsitar/ item
1344  if ( ( vsiPrefix != QLatin1String( "/vsizip/" ) && vsiPrefix != QLatin1String( "/vsitar/" ) ) )
1345  return nullptr;
1346 
1347  zipItem = new QgsZipItem( parent, name, filePath, path );
1348 
1349  if ( zipItem )
1350  {
1351  // force populate zipItem if it has less than 10 items and is not a .tgz or .tar.gz file (slow loading)
1352  // for other items populating will be delayed until item is opened
1353  // this might be polluting the tree with empty items but is necessary for performance reasons
1354  // could also accept all files smaller than a certain size and add options for file count and/or size
1355 
1356  // first get list of files inside .zip or .tar files
1357  if ( path.endsWith( QLatin1String( ".zip" ), Qt::CaseInsensitive ) ||
1358  path.endsWith( QLatin1String( ".tar" ), Qt::CaseInsensitive ) )
1359  {
1360  zipFileList = zipItem->getZipFileList();
1361  }
1362  // force populate if less than 10 items
1363  if ( !zipFileList.isEmpty() && zipFileList.count() <= 10 )
1364  {
1365  zipItem->populate( zipItem->createChildren() );
1366  populated = true; // there is no QgsDataItem::isPopulated() function
1367  QgsDebugMsgLevel( QString( "Got zipItem with %1 children, path=%2, name=%3" ).arg( zipItem->rowCount() ).arg( zipItem->path(), zipItem->name() ), 3 );
1368  }
1369  else
1370  {
1371  QgsDebugMsgLevel( QString( "Delaying populating zipItem with path=%1, name=%2" ).arg( zipItem->path(), zipItem->name() ), 3 );
1372  }
1373  }
1374 
1375  // only display if has children or if is not populated
1376  if ( zipItem && ( !populated || zipItem->rowCount() > 1 ) )
1377  {
1378  QgsDebugMsgLevel( "returning zipItem", 3 );
1379  return zipItem;
1380  }
1381  // if 1 or 0 child found, create a single data item using the normal path or the full path given by QgsZipItem
1382  else
1383  {
1384  QString vsiPath = vsiPrefix + filePath;
1385  if ( zipItem )
1386  {
1387  QVector<QgsDataItem *> children = zipItem->children();
1388  if ( children.size() == 1 )
1389  {
1390  // take the name of the only child so we can get a normal data item from it
1391  QgsLayerItem *layerItem = qobject_cast<QgsLayerItem *>( children.first() );
1392  if ( layerItem )
1393  vsiPath = layerItem->uri();
1394  }
1395  zipFileCount = zipFileList.count();
1396  delete zipItem;
1397  }
1398 
1399  QgsDebugMsgLevel( QString( "will try to create a normal dataItem from filePath= %2 or vsiPath = %3" ).arg( filePath, vsiPath ), 3 );
1400 
1401  // try to open using registered providers (gdal and ogr)
1402  for ( int i = 0; i < sProviderNames.size(); i++ )
1403  {
1404  dataItem_t *dataItem = sDataItemPtr.at( i );
1405  if ( dataItem )
1406  {
1407  QgsDataItem *item = nullptr;
1408  // try first with normal path (Passthru)
1409  // this is to simplify .qml handling, and without this some tests will fail
1410  // (e.g. testZipItemVectorTransparency(), second test)
1411  if ( ( sProviderNames.at( i ) == QLatin1String( "ogr" ) ) ||
1412  ( sProviderNames.at( i ) == QLatin1String( "gdal" ) && zipFileCount == 1 ) )
1413  item = dataItem( filePath, parent );
1414  // try with /vsizip/
1415  if ( ! item )
1416  item = dataItem( vsiPath, parent );
1417  if ( item )
1418  return item;
1419  }
1420  }
1421  }
1422 
1423  return nullptr;
1424 }
1425 
1427 {
1428  if ( ! mZipFileList.isEmpty() )
1429  return mZipFileList;
1430 
1431  QString tmpPath;
1432  QgsSettings settings;
1433  QString scanZipSetting = settings.value( QStringLiteral( "qgis/scanZipInBrowser2" ), "basic" ).toString();
1434 
1435  QgsDebugMsgLevel( QString( "mFilePath = %1 name= %2 scanZipSetting= %3 vsiPrefix= %4" ).arg( mFilePath, name(), scanZipSetting, mVsiPrefix ), 3 );
1436 
1437  // if scanZipBrowser == no: skip to the next file
1438  if ( scanZipSetting == QLatin1String( "no" ) )
1439  {
1440  return mZipFileList;
1441  }
1442 
1443  // get list of files inside zip file
1444  QgsDebugMsgLevel( QString( "Open file %1 with gdal vsi" ).arg( mVsiPrefix + mFilePath ), 3 );
1445  char **papszSiblingFiles = VSIReadDirRecursive1( QString( mVsiPrefix + mFilePath ).toLocal8Bit().constData() );
1446  if ( papszSiblingFiles )
1447  {
1448  for ( int i = 0; i < CSLCount( papszSiblingFiles ); i++ )
1449  {
1450  tmpPath = papszSiblingFiles[i];
1451  QgsDebugMsgLevel( QString( "Read file %1" ).arg( tmpPath ), 3 );
1452  // skip directories (files ending with /)
1453  if ( tmpPath.right( 1 ) != QLatin1String( "/" ) )
1454  mZipFileList << tmpPath;
1455  }
1456  CSLDestroy( papszSiblingFiles );
1457  }
1458  else
1459  {
1460  QgsDebugMsg( QString( "Error reading %1" ).arg( mFilePath ) );
1461  }
1462 
1463  return mZipFileList;
1464 }
A Collection: logical collection of layers or subcollections, e.g.
Definition: qgsdataitem.h:419
QString layerType
Type of URI. Recognized types: "vector" / "raster" / "plugin" / "custom".
static QIcon iconRaster()
Definition: qgsdataitem.cpp:68
void beginInsertItems(QgsDataItem *parent, int first, int last)
QString path() const
Definition: qgsdataitem.h:214
bool disconnectFrameChanged(const typename QtPrivate::FunctionPointer< Func1 >::Object *receiver, Func1 slot)
Convenience function to disconnect the same style that the frame change connection was established...
QgsFavoritesItem(QgsDataItem *parent, const QString &name, const QString &path=QString())
Constructor for QgsFavoritesItem.
virtual void childrenCreated()
virtual QString layerName() const
Definition: qgsdataitem.h:412
virtual void childrenCreated() override
virtual void refresh()
QString providerKey() const
Returns provider key.
Definition: qgsdataitem.h:368
QgsErrorItem(QgsDataItem *parent, const QString &error, const QString &path)
QString name() const
Definition: qgsdataitem.h:212
void dataChanged(QgsDataItem *item)
static QgsApplication * instance()
Returns the singleton instance of the QgsApplication.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:54
virtual QgsDataItem * createDataItem(const QString &path, QgsDataItem *parentItem)=0
Create a new instance of QgsDataItem (or null) for given path and parent item.
void addDirectory(const QString &directory)
Adds a new directory to the favorites group.
QgsMapLayer::LayerType mapLayerType() const
Returns QgsMapLayer::LayerType.
void connectionsChanged()
Emitted when the provider&#39;s connections of the child items have changed This signal is normally forwa...
#define QgsDebugMsg(str)
Definition: qgslogger.h:37
QString mProviderKey
The provider key.
Definition: qgsdataitem.h:393
QgsDataCollectionItem(QgsDataItem *parent, const QString &name, const QString &path=QString())
QString name
Human readable name to be used e.g. in layer tree.
static QString pathComponent(const QString &component)
Create path component replacing path separators.
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
virtual QIcon icon()
virtual void setState(State state) override
Set item state.
QString mIconName
Definition: qgsdataitem.h:262
State mState
Definition: qgsdataitem.h:254
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
static QIcon iconLine()
Definition: qgsdataitem.cpp:53
Type type() const
Definition: qgsdataitem.h:201
QStringList supportedFormats
static QIcon iconPoint()
Definition: qgsdataitem.cpp:48
virtual void depopulate()
Remove children recursively and set as not populated. This is used when refreshing collapsed items...
static QIcon iconDefault()
Definition: qgsdataitem.cpp:73
QgsDirectoryItem(QgsDataItem *parent, const QString &name, const QString &path)
char ** VSIReadDirRecursive1(const char *pszPath)
void endRemoveItems()
State state() const
A zip file: contains layers, using GDAL/OGR VSIFILE mechanism.
Definition: qgsdataitem.h:576
virtual bool equal(const QgsDataItem *other)
Returns true if this item is equal to another item (by testing item type and path).
void setValue(const QString &key, const QVariant &value, const QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
static void deleteLater(QVector< QgsDataItem *> &items)
QString mFilePath
Definition: qgsdataitem.h:581
QgsDataItem * parent() const
Get item parent.
Definition: qgsdataitem.h:205
virtual ~QgsDataItem()
static QIcon iconPolygon()
Definition: qgsdataitem.cpp:58
void beginRemoveItems(QgsDataItem *parent, int first, int last)
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:38
QString mName
Definition: qgsdataitem.h:255
LayerType
Types of layers that can be added to a map.
Definition: qgsmaplayer.h:92
static QIcon iconDir()
Definition: qgsdataitem.cpp:83
QStringList mZipFileList
Definition: qgsdataitem.h:583
QgsDirectoryParamWidget(const QString &path, QWidget *parent=nullptr)
QgsZipItem(QgsDataItem *parent, const QString &name, const QString &path)
static QgsDataItem * itemFromPath(QgsDataItem *parent, const QString &path, const QString &name)
Creates a new data item from the specified path.
Children not yet created.
Definition: qgsdataitem.h:99
Creating children in separate thread (populating or refreshing)
Definition: qgsdataitem.h:100
void updateIcon()
Will request a repaint of this icon.
virtual void refreshConnections()
Refresh connections: update GUI and emit signal.
virtual int capabilities()=0
Return combination of flags from QgsDataProvider::DataCapabilities.
bool hasChildren()
static bool hiddenPath(const QString &path)
Check if the given path is hidden from the browser model.
#define cast_to_fptr(f)
Definition: qgis.h:136
virtual bool equal(const QgsDataItem *other) override
Returns true if this item is equal to another item (by testing item type and path).
QgsDataItem(QgsDataItem::Type type, QgsDataItem *parent, const QString &name, const QString &path)
Create new data item.
virtual QIcon icon() override
A directory: contains subdirectories and layers.
Definition: qgsdataitem.h:435
static QStringList sProviderNames
Definition: qgsdataitem.h:594
Base class for all items in the model.
Definition: qgsdataitem.h:47
void mousePressEvent(QMouseEvent *event) override
Capabilities mCapabilities
Definition: qgsdataitem.h:251
virtual void setState(State state)
Set item state.
virtual void addChildItem(QgsDataItem *child, bool refresh=false)
Inserts a new child item.
void setName(const QString &name)
Definition: qgsdataitem.h:213
Can create children. Even items without this capability may have children, but cannot create them...
Definition: qgsdataitem.h:174
QVector< QgsDataItem * > children() const
Definition: qgsdataitem.h:210
QString mPath
Definition: qgsdataitem.h:260
QVector< QgsDataItem * > createChildren() override
Create children.
QString mUri
The URI.
Definition: qgsdataitem.h:395
static QIcon iconZip()
void moveToThread(QThread *targetThread)
Move object and all its descendants to thread.
static QString layerTypeAsString(const LayerType &layerType)
Returns the string representatio of the given layerType.
static QVector< dataItem_t * > sDataItemPtr
Definition: qgsdataitem.h:593
QVector< QgsDataItem * > createChildren() override
Create children.
void removeDirectory(QgsDirectoryItem *item)
Removes an existing directory from the favorites group.
QString mVsiPrefix
Definition: qgsdataitem.h:582
virtual QgsMimeDataUtils::Uri mimeUri() const override
Return mime URI for the data item.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), const Section section=NoSection) const
Returns the value for setting key.
QStringList supportedFormats() const
Returns the supported formats.
Definition: qgsdataitem.h:378
void setParent(QgsDataItem *parent)
Set item parent and connect / disconnect parent to / from item signals.
Animated icon is keeping an animation running if there are listeners connected to frameChanged...
QString uri() const
Returns layer uri or empty string if layer cannot be created.
Definition: qgsdataitem.h:365
QgsDataItem * mParent
Definition: qgsdataitem.h:252
bool deferredDelete()
The item is scheduled to be deleted.
Definition: qgsdataitem.h:248
QString dirPath() const
Definition: qgsdataitem.h:463
QIcon icon() const
Get the icons representation in the current frame.
static QIcon iconFavorites()
Icon for favorites group.
Definition: qgsdataitem.cpp:99
QString providerKey
For "vector" / "raster" type: provider id.
void endInsertItems()
QString uri
Identifier of the data source recognized by its providerKey.
virtual QVector< QgsDataItem * > createChildren()
Create children.
static QIcon iconDataCollection()
Definition: qgsdataitem.cpp:78
QVector< QgsDataItem * > createChildren() override
Create children.
Item that represents a layer that can be opened with one of the providers.
Definition: qgsdataitem.h:328
static QIcon iconTable()
Definition: qgsdataitem.cpp:63
QgsProjectItem(QgsDataItem *parent, const QString &name, const QString &path)
A data item holding a reference to a QGIS project file.
static int findItem(QVector< QgsDataItem *> items, QgsDataItem *item)
QgsDataItem * dataItem_t(QString, QgsDataItem *)
Definition: qgsdataitem.h:41
virtual QgsDataItem * removeChildItem(QgsDataItem *child)
Removes a child item and returns it without deleting it.
virtual void deleteChildItem(QgsDataItem *child)
Removes and deletes a child item, emitting relevant signals to the model.
virtual void populate(const QVector< QgsDataItem *> &children)
QgsLayerItem(QgsDataItem *parent, const QString &name, const QString &path, const QString &uri, LayerType layerType, const QString &providerKey)
Data item that can be used to represent QGIS projects.
Definition: qgsdataitem.h:488
Children created.
Definition: qgsdataitem.h:101
LayerType mLayerType
The layer type.
Definition: qgsdataitem.h:397
virtual bool equal(const QgsDataItem *other) override
Returns true if this item is equal to another item (by testing item type and path).
int dataCapabilities_t()
QVector< QgsDataItem * > mChildren
Definition: qgsdataitem.h:253
QStringList getZipFileList()
virtual void deleteLater()
Safely delete the item:
static QgsDataItemProviderRegistry * dataItemProviderRegistry()
Returns the application&#39;s data item provider registry, which keeps a list of data item providers that...
virtual QWidget * paramWidget() override
CreateChildren() is fast enough to be run in main thread when refreshing items, most root items (wms...
Definition: qgsdataitem.h:175
bool connectFrameChanged(const typename QtPrivate::FunctionPointer< Func1 >::Object *receiver, Func1 slot)
Connect a slot that will be notified repeatedly whenever a frame changes and which should request the...
Represents a favorite item.
Definition: qgsdataitem.h:81
This is the interface for those who want to add custom data items to the browser tree.
QStringList supportedCrs() const
Returns the supported CRS.
Definition: qgsdataitem.h:373
void stateChanged(QgsDataItem *item, QgsDataItem::State oldState)
static QString vsiPrefix(const QString &uri)
Definition: qgsdataitem.h:596
QMap< QString, QIcon > mIconMap
Definition: qgsdataitem.h:264
Added in 2.10.
Definition: qgsdataitem.h:344
virtual Capabilities capabilities2() const
Definition: qgsdataitem.h:187