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