QGIS API Documentation  2.99.0-Master (0a63d1f)
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  if ( metaObject()->className() == other->metaObject()->className() &&
552  mPath == other->path() )
553  {
554  return true;
555  }
556  return false;
557 }
558 
560 {
561  return mState;
562 }
563 
565 {
566  QgsDebugMsgLevel( QString( "item %1 set state %2 -> %3" ).arg( path() ).arg( this->state() ).arg( state ), 3 );
567  if ( state == mState )
568  return;
569 
570  State oldState = mState;
571 
572  if ( state == Populating ) // start loading
573  {
574  if ( !sPopulatingIcon )
575  {
576  // TODO: ensure that QgsAnimatedIcon is created on UI thread only
577  sPopulatingIcon = new QgsAnimatedIcon( QgsApplication::iconPath( QStringLiteral( "/mIconLoading.gif" ) ) );
578  }
579  sPopulatingIcon->connectFrameChanged( this, SLOT( emitDataChanged() ) );
580  }
581  else if ( mState == Populating && sPopulatingIcon ) // stop loading
582  {
583  sPopulatingIcon->disconnectFrameChanged( this, SLOT( emitDataChanged() ) );
584  }
585 
586  mState = state;
587 
588  emit stateChanged( this, oldState );
589  if ( state == Populated )
590  emitDataChanged();
591 }
592 
593 // ---------------------------------------------------------------------
594 
595 QgsLayerItem::QgsLayerItem( QgsDataItem* parent, const QString& name, const QString& path, const QString& uri, LayerType layerType, const QString& providerKey )
596  : QgsDataItem( Layer, parent, name, path )
597  , mProviderKey( providerKey )
598  , mUri( uri )
599  , mLayerType( layerType )
600 {
601  switch ( layerType )
602  {
603  case Point:
604  mIconName = QStringLiteral( "/mIconPointLayer.svg" );
605  break;
606  case Line:
607  mIconName = QStringLiteral( "/mIconLineLayer.svg" );
608  break;
609  case Polygon:
610  mIconName = QStringLiteral( "/mIconPolygonLayer.svg" );
611  break;
612  // TODO add a new icon for generic Vector layers
613  case Vector :
614  mIconName = QStringLiteral( "/mIconPolygonLayer.svg" );
615  break;
616  case TableLayer:
617  mIconName = QStringLiteral( "/mIconTableLayer.svg" );
618  break;
619  case Raster:
620  mIconName = QStringLiteral( "/mIconRaster.svg" );
621  break;
622  default:
623  mIconName = QStringLiteral( "/mIconLayer.png" );
624  break;
625  }
626 }
627 
629 {
635 }
636 
637 bool QgsLayerItem::equal( const QgsDataItem *other )
638 {
639  //QgsDebugMsg ( mPath + " x " + other->mPath );
640  if ( type() != other->type() )
641  {
642  return false;
643  }
644  //const QgsLayerItem *o = qobject_cast<const QgsLayerItem *> ( other );
645  const QgsLayerItem *o = dynamic_cast<const QgsLayerItem *>( other );
646  if ( !o )
647  return false;
648 
649  return ( mPath == o->mPath && mName == o->mName && mUri == o->mUri && mProviderKey == o->mProviderKey );
650 }
651 
653 {
655 
656  switch ( mapLayerType() )
657  {
659  u.layerType = QStringLiteral( "vector" );
660  break;
662  u.layerType = QStringLiteral( "raster" );
663  break;
665  u.layerType = QStringLiteral( "plugin" );
666  break;
667  default:
668  return u; // invalid URI
669  }
670 
671  u.providerKey = providerKey();
672  u.name = layerName();
673  u.uri = uri();
676  return u;
677 }
678 
679 // ---------------------------------------------------------------------
681  : QgsDataItem( Collection, parent, name, path )
682 {
684  mIconName = QStringLiteral( "/mIconDbSchema.png" );
685 }
686 
688 {
689  QgsDebugMsgLevel( "mName = " + mName + " mPath = " + mPath, 2 );
690 
691 // Do not delete children, children are deleted by QObject parent
692 #if 0
693  Q_FOREACH ( QgsDataItem* i, mChildren )
694  {
695  QgsDebugMsgLevel( QString( "delete child = 0x%0" ).arg(( qlonglong )i, 8, 16, QLatin1Char( '0' ) ), 2 );
696  delete i;
697  }
698 #endif
699 }
700 
701 //-----------------------------------------------------------------------
702 
703 QgsDirectoryItem::QgsDirectoryItem( QgsDataItem* parent, const QString& name, const QString& path )
704  : QgsDataCollectionItem( parent, name, path )
705  , mDirPath( path )
706  , mFileSystemWatcher( nullptr )
707  , mRefreshLater( false )
708 {
709  mType = Directory;
710  init();
711 }
712 
713 QgsDirectoryItem::QgsDirectoryItem( QgsDataItem* parent, const QString& name, const QString& dirPath, const QString& path )
714  : QgsDataCollectionItem( parent, name, path )
715  , mDirPath( dirPath )
716  , mFileSystemWatcher( nullptr )
717  , mRefreshLater( false )
718 {
719  mType = Directory;
720  init();
721 }
722 
724 {
725 }
726 
728 {
729  if ( state() == Populating )
730  return QgsDataItem::icon();
731  return iconDir();
732 }
733 
734 
735 QVector<QgsDataItem*> QgsDirectoryItem::createChildren()
736 {
737  QVector<QgsDataItem*> children;
738  QDir dir( mDirPath );
739 
740  QStringList entries = dir.entryList( QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name | QDir::IgnoreCase );
741  Q_FOREACH ( const QString& subdir, entries )
742  {
743  if ( mRefreshLater )
744  {
745  deleteLater( children );
746  return children;
747  }
748 
749  QString subdirPath = dir.absoluteFilePath( subdir );
750 
751  QgsDebugMsgLevel( QString( "creating subdir: %1" ).arg( subdirPath ), 2 );
752 
753  QString path = mPath + '/' + subdir; // may differ from subdirPath
754  if ( QgsDirectoryItem::hiddenPath( path ) )
755  continue;
756  QgsDirectoryItem *item = new QgsDirectoryItem( this, subdir, subdirPath, path );
757  // propagate signals up to top
758 
759  children.append( item );
760  }
761 
762  QStringList fileEntries = dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot | QDir::Files, QDir::Name );
763  Q_FOREACH ( const QString& name, fileEntries )
764  {
765  if ( mRefreshLater )
766  {
767  deleteLater( children );
768  return children;
769  }
770 
771  QString path = dir.absoluteFilePath( name );
772  QFileInfo fileInfo( path );
773 
774  if ( fileInfo.suffix() == QLatin1String( "qgs" ) )
775  {
776  QgsDataItem * item = new QgsProjectItem( this, name, path );
777  children.append( item );
778  continue;
779  }
780 
781  // vsizip support was added to GDAL/OGR 1.6 but GDAL_VERSION_NUM not available here
782  // so we assume it's available anyway
783  {
784  QgsDataItem * item = QgsZipItem::itemFromPath( this, path, name, mPath + '/' + name );
785  if ( item )
786  {
787  children.append( item );
788  continue;
789  }
790  }
791 
792  Q_FOREACH ( QgsDataItemProvider* provider, QgsApplication::dataItemProviderRegistry()->providers() )
793  {
794  int capabilities = provider->capabilities();
795 
796  if ( !(( fileInfo.isFile() && ( capabilities & QgsDataProvider::File ) ) ||
797  ( fileInfo.isDir() && ( capabilities & QgsDataProvider::Dir ) ) ) )
798  {
799  continue;
800  }
801 
802  QgsDataItem * item = provider->createDataItem( path, this );
803  if ( item )
804  {
805  children.append( item );
806  }
807  }
808 
809  }
810 
811  return children;
812 }
813 
815 {
817 
818  if ( state == Populated )
819  {
820  if ( !mFileSystemWatcher )
821  {
822  mFileSystemWatcher = new QFileSystemWatcher( this );
823  mFileSystemWatcher->addPath( mDirPath );
824  connect( mFileSystemWatcher, SIGNAL( directoryChanged( const QString & ) ), SLOT( directoryChanged() ) );
825  }
826  }
827  else if ( state == NotPopulated )
828  {
829  if ( mFileSystemWatcher )
830  {
831  delete mFileSystemWatcher;
832  mFileSystemWatcher = nullptr;
833  }
834  }
835 }
836 
838 {
839  if ( state() == Populating )
840  {
841  // schedule to refresh later, because refres() simply returns if Populating
842  mRefreshLater = true;
843  }
844  else
845  {
846  refresh();
847  }
848 }
849 
850 bool QgsDirectoryItem::hiddenPath( const QString& path )
851 {
852  QSettings settings;
853  QStringList hiddenItems = settings.value( QStringLiteral( "/browser/hiddenPaths" ),
854  QStringList() ).toStringList();
855  int idx = hiddenItems.indexOf( path );
856  return ( idx > -1 );
857 }
858 
860 {
861  QgsDebugMsgLevel( QString( "mRefreshLater = %1" ).arg( mRefreshLater ), 3 );
862 
863  if ( mRefreshLater )
864  {
865  QgsDebugMsgLevel( "directory changed during createChidren() -> refresh() again", 3 );
866  mRefreshLater = false;
867  setState( Populated );
868  refresh();
869  }
870  else
871  {
873  }
874 }
875 
877 {
878  //QgsDebugMsg ( mPath + " x " + other->mPath );
879  if ( type() != other->type() )
880  {
881  return false;
882  }
883  return ( path() == other->path() );
884 }
885 
887 {
888  return new QgsDirectoryParamWidget( mPath );
889 }
890 
892  : QTreeWidget( parent )
893 {
894  setRootIsDecorated( false );
895 
896  // name, size, date, permissions, owner, group, type
897  setColumnCount( 7 );
898  QStringList labels;
899  labels << tr( "Name" ) << tr( "Size" ) << tr( "Date" ) << tr( "Permissions" ) << tr( "Owner" ) << tr( "Group" ) << tr( "Type" );
900  setHeaderLabels( labels );
901 
902  QStyle* style = QApplication::style();
903  QIcon iconDirectory = QIcon( style->standardPixmap( QStyle::SP_DirClosedIcon ) );
904  QIcon iconFile = QIcon( style->standardPixmap( QStyle::SP_FileIcon ) );
905  QIcon iconDirLink = QIcon( style->standardPixmap( QStyle::SP_DirLinkIcon ) );
906  QIcon iconFileLink = QIcon( style->standardPixmap( QStyle::SP_FileLinkIcon ) );
907 
908  QList<QTreeWidgetItem *> items;
909 
910  QDir dir( path );
911  QStringList entries = dir.entryList( QDir::AllEntries | QDir::NoDotAndDotDot, QDir::Name | QDir::IgnoreCase );
912  Q_FOREACH ( const QString& name, entries )
913  {
914  QFileInfo fi( dir.absoluteFilePath( name ) );
915  QStringList texts;
916  texts << name;
917  QString size;
918  if ( fi.size() > 1024 )
919  {
920  size = size.sprintf( "%.1f KiB", fi.size() / 1024.0 );
921  }
922  else if ( fi.size() > 1.048576e6 )
923  {
924  size = size.sprintf( "%.1f MiB", fi.size() / 1.048576e6 );
925  }
926  else
927  {
928  size = QStringLiteral( "%1 B" ).arg( fi.size() );
929  }
930  texts << size;
931  texts << fi.lastModified().toString( Qt::SystemLocaleShortDate );
932  QString perm;
933  perm += fi.permission( QFile::ReadOwner ) ? 'r' : '-';
934  perm += fi.permission( QFile::WriteOwner ) ? 'w' : '-';
935  perm += fi.permission( QFile::ExeOwner ) ? 'x' : '-';
936  // QFile::ReadUser, QFile::WriteUser, QFile::ExeUser
937  perm += fi.permission( QFile::ReadGroup ) ? 'r' : '-';
938  perm += fi.permission( QFile::WriteGroup ) ? 'w' : '-';
939  perm += fi.permission( QFile::ExeGroup ) ? 'x' : '-';
940  perm += fi.permission( QFile::ReadOther ) ? 'r' : '-';
941  perm += fi.permission( QFile::WriteOther ) ? 'w' : '-';
942  perm += fi.permission( QFile::ExeOther ) ? 'x' : '-';
943  texts << perm;
944 
945  texts << fi.owner();
946  texts << fi.group();
947 
948  QString type;
949  QIcon icon;
950  if ( fi.isDir() && fi.isSymLink() )
951  {
952  type = tr( "folder" );
953  icon = iconDirLink;
954  }
955  else if ( fi.isDir() )
956  {
957  type = tr( "folder" );
958  icon = iconDirectory;
959  }
960  else if ( fi.isFile() && fi.isSymLink() )
961  {
962  type = tr( "file" );
963  icon = iconFileLink;
964  }
965  else if ( fi.isFile() )
966  {
967  type = tr( "file" );
968  icon = iconFile;
969  }
970 
971  texts << type;
972 
973  QTreeWidgetItem *item = new QTreeWidgetItem( texts );
974  item->setIcon( 0, icon );
975  items << item;
976  }
977 
978  addTopLevelItems( items );
979 
980  // hide columns that are not requested
981  QSettings settings;
982  QList<QVariant> lst = settings.value( QStringLiteral( "/dataitem/directoryHiddenColumns" ) ).toList();
983  Q_FOREACH ( const QVariant& colVariant, lst )
984  {
985  setColumnHidden( colVariant.toInt(), true );
986  }
987 }
988 
990 {
991  if ( event->button() == Qt::RightButton )
992  {
993  // show the popup menu
994  QMenu popupMenu;
995 
996  QStringList labels;
997  labels << tr( "Name" ) << tr( "Size" ) << tr( "Date" ) << tr( "Permissions" ) << tr( "Owner" ) << tr( "Group" ) << tr( "Type" );
998  for ( int i = 0; i < labels.count(); i++ )
999  {
1000  QAction* action = popupMenu.addAction( labels[i], this, SLOT( showHideColumn() ) );
1001  action->setObjectName( QString::number( i ) );
1002  action->setCheckable( true );
1003  action->setChecked( !isColumnHidden( i ) );
1004  }
1005 
1006  popupMenu.exec( event->globalPos() );
1007  }
1008 }
1009 
1011 {
1012  QAction* action = qobject_cast<QAction*>( sender() );
1013  if ( !action )
1014  return; // something is wrong
1015 
1016  int columnIndex = action->objectName().toInt();
1017  setColumnHidden( columnIndex, !isColumnHidden( columnIndex ) );
1018 
1019  // save in settings
1020  QSettings settings;
1021  QList<QVariant> lst;
1022  for ( int i = 0; i < columnCount(); i++ )
1023  {
1024  if ( isColumnHidden( i ) )
1025  lst.append( QVariant( i ) );
1026  }
1027  settings.setValue( QStringLiteral( "/dataitem/directoryHiddenColumns" ), lst );
1028 }
1029 
1030 QgsProjectItem::QgsProjectItem( QgsDataItem* parent, const QString &name, const QString& path )
1031  : QgsDataItem( QgsDataItem::Project, parent, name, path )
1032 {
1033  mIconName = QStringLiteral( ":/images/icons/qgis-icon-16x16.png" );
1034 
1035  setState( Populated ); // no more children
1036 }
1037 
1038 QgsErrorItem::QgsErrorItem( QgsDataItem* parent, const QString& error, const QString& path )
1039  : QgsDataItem( QgsDataItem::Error, parent, error, path )
1040 {
1041  mIconName = QStringLiteral( "/mIconDelete.png" );
1042 
1043  setState( Populated ); // no more children
1044 }
1045 
1047  : QgsDataCollectionItem( parent, name, QStringLiteral( "favorites:" ) )
1048 {
1049  Q_UNUSED( path );
1050  mCapabilities |= Fast;
1051  mType = Favorites;
1052  mIconName = QStringLiteral( "/mIconFavourites.png" );
1053  populate();
1054 }
1055 
1056 QVector<QgsDataItem*> QgsFavoritesItem::createChildren()
1057 {
1058  QVector<QgsDataItem*> children;
1059 
1060  QSettings settings;
1061  QStringList favDirs = settings.value( QStringLiteral( "/browser/favourites" ), QVariant() ).toStringList();
1062 
1063  Q_FOREACH ( const QString& favDir, favDirs )
1064  {
1065  children << createChildren( favDir );
1066  }
1067 
1068  return children;
1069 }
1070 
1071 void QgsFavoritesItem::addDirectory( const QString& favDir )
1072 {
1073  QSettings settings;
1074  QStringList favDirs = settings.value( QStringLiteral( "/browser/favourites" ) ).toStringList();
1075  favDirs.append( favDir );
1076  settings.setValue( QStringLiteral( "/browser/favourites" ), favDirs );
1077 
1078  if ( state() == Populated )
1079  {
1080  QVector<QgsDataItem*> items = createChildren( favDir );
1081  Q_FOREACH ( QgsDataItem* item, items )
1082  {
1083  addChildItem( item, true );
1084  }
1085  }
1086 }
1087 
1089 {
1090  if ( !item )
1091  return;
1092 
1093  QSettings settings;
1094  QStringList favDirs = settings.value( QStringLiteral( "/browser/favourites" ) ).toStringList();
1095  favDirs.removeAll( item->dirPath() );
1096  settings.setValue( QStringLiteral( "/browser/favourites" ), favDirs );
1097 
1098  int idx = findItem( mChildren, item );
1099  if ( idx < 0 )
1100  {
1101  QgsDebugMsg( QString( "favorites item %1 not found" ).arg( item->path() ) );
1102  return;
1103  }
1104 
1105  if ( state() == Populated )
1106  deleteChildItem( mChildren.at( idx ) );
1107 }
1108 
1109 QVector<QgsDataItem*> QgsFavoritesItem::createChildren( const QString& favDir )
1110 {
1111  QVector<QgsDataItem*> children;
1112  QString pathName = pathComponent( favDir );
1113  Q_FOREACH ( QgsDataItemProvider* provider, QgsApplication::dataItemProviderRegistry()->providers() )
1114  {
1115  int capabilities = provider->capabilities();
1116 
1117  if ( capabilities & QgsDataProvider::Dir )
1118  {
1119  QgsDataItem * item = provider->createDataItem( favDir, this );
1120  if ( item )
1121  {
1122  item->setName( favDir );
1123  children.append( item );
1124  }
1125  }
1126  }
1127  if ( children.isEmpty() )
1128  {
1129  QgsDataItem *item = new QgsDirectoryItem( this, favDir, favDir, mPath + '/' + pathName );
1130  if ( item )
1131  {
1132  children.append( item );
1133  }
1134  }
1135  return children;
1136 }
1137 
1138 //-----------------------------------------------------------------------
1139 QStringList QgsZipItem::sProviderNames = QStringList();
1140 QVector<dataItem_t *> QgsZipItem::sDataItemPtr = QVector<dataItem_t*>();
1141 
1142 
1143 QgsZipItem::QgsZipItem( QgsDataItem* parent, const QString& name, const QString& path )
1144  : QgsDataCollectionItem( parent, name, path )
1145 {
1146  mFilePath = path;
1147  init();
1148 }
1149 
1150 QgsZipItem::QgsZipItem( QgsDataItem* parent, const QString& name, const QString& filePath, const QString& path )
1151  : QgsDataCollectionItem( parent, name, path )
1152  , mFilePath( filePath )
1153 {
1154  init();
1155 }
1156 
1157 void QgsZipItem::init()
1158 {
1159  mType = Collection; //Zip??
1160  mIconName = QStringLiteral( "/mIconZip.png" );
1162 
1163  if ( sProviderNames.isEmpty() )
1164  {
1165  // QStringList keys = QgsProviderRegistry::instance()->providerList();
1166  // only use GDAL and OGR providers as we use the VSIFILE mechanism
1167  QStringList keys;
1168  // keys << "ogr" << "gdal";
1169  keys << QStringLiteral( "gdal" ) << QStringLiteral( "ogr" );
1170 
1171  QStringList::const_iterator i;
1172  for ( i = keys.begin(); i != keys.end(); ++i )
1173  {
1174  QString k( *i );
1175  QgsDebugMsgLevel( "provider " + k, 3 );
1176  // some providers hangs with empty uri (Postgis) etc...
1177  // -> using libraries directly
1178  QLibrary *library = QgsProviderRegistry::instance()->providerLibrary( k );
1179  if ( library )
1180  {
1181  dataCapabilities_t * dataCapabilities = reinterpret_cast< dataCapabilities_t * >( cast_to_fptr( library->resolve( "dataCapabilities" ) ) );
1182  if ( !dataCapabilities )
1183  {
1184  QgsDebugMsg( library->fileName() + " does not have dataCapabilities" );
1185  continue;
1186  }
1187  if ( dataCapabilities() == QgsDataProvider::NoDataCapabilities )
1188  {
1189  QgsDebugMsg( library->fileName() + " has NoDataCapabilities" );
1190  continue;
1191  }
1192  QgsDebugMsg( QString( "%1 dataCapabilities : %2" ).arg( library->fileName() ).arg( dataCapabilities() ) );
1193 
1194  dataItem_t * dataItem = reinterpret_cast< dataItem_t * >( cast_to_fptr( library->resolve( "dataItem" ) ) );
1195  if ( ! dataItem )
1196  {
1197  QgsDebugMsg( library->fileName() + " does not have dataItem" );
1198  continue;
1199  }
1200 
1201  // mLibraries.append( library );
1202  sDataItemPtr.append( dataItem );
1203  sProviderNames.append( k );
1204  }
1205  else
1206  {
1207  //QgsDebugMsg ( "Cannot get provider " + k );
1208  }
1209  }
1210  }
1211 
1212 }
1213 
1214 // internal function to scan a vsidir (zip or tar file) recursively
1215 // GDAL trunk has this since r24423 (05/16/12) - VSIReadDirRecursive()
1216 // use a copy of the function internally for now,
1217 // but use char ** and CSLAddString, because CPLStringList was added in gdal-1.9
1218 char **VSIReadDirRecursive1( const char *pszPath )
1219 {
1220  // CPLStringList oFiles = nullptr;
1221  char **papszOFiles = nullptr;
1222  char **papszFiles1 = nullptr;
1223  char **papszFiles2 = nullptr;
1224  VSIStatBufL psStatBuf;
1225  CPLString osTemp1, osTemp2;
1226  int i, j;
1227  int nCount1, nCount2;
1228 
1229  // get listing
1230  papszFiles1 = VSIReadDir( pszPath );
1231  if ( ! papszFiles1 )
1232  return nullptr;
1233 
1234  // get files and directories inside listing
1235  nCount1 = CSLCount( papszFiles1 );
1236  for ( i = 0; i < nCount1; i++ )
1237  {
1238  // build complete file name for stat
1239  osTemp1.clear();
1240  osTemp1.append( pszPath );
1241  osTemp1.append( "/" );
1242  osTemp1.append( papszFiles1[i] );
1243 
1244  // if is file, add it
1245  if ( VSIStatL( osTemp1.c_str(), &psStatBuf ) == 0 &&
1246  VSI_ISREG( psStatBuf.st_mode ) )
1247  {
1248  // oFiles.AddString( papszFiles1[i] );
1249  papszOFiles = CSLAddString( papszOFiles, papszFiles1[i] );
1250  }
1251  else if ( VSIStatL( osTemp1.c_str(), &psStatBuf ) == 0 &&
1252  VSI_ISDIR( psStatBuf.st_mode ) )
1253  {
1254  // add directory entry
1255  osTemp2.clear();
1256  osTemp2.append( papszFiles1[i] );
1257  osTemp2.append( "/" );
1258  // oFiles.AddString( osTemp2.c_str() );
1259  papszOFiles = CSLAddString( papszOFiles, osTemp2.c_str() );
1260 
1261  // recursively add files inside directory
1262  papszFiles2 = VSIReadDirRecursive1( osTemp1.c_str() );
1263  if ( papszFiles2 )
1264  {
1265  nCount2 = CSLCount( papszFiles2 );
1266  for ( j = 0; j < nCount2; j++ )
1267  {
1268  osTemp2.clear();
1269  osTemp2.append( papszFiles1[i] );
1270  osTemp2.append( "/" );
1271  osTemp2.append( papszFiles2[j] );
1272  // oFiles.AddString( osTemp2.c_str() );
1273  papszOFiles = CSLAddString( papszOFiles, osTemp2.c_str() );
1274  }
1275  CSLDestroy( papszFiles2 );
1276  }
1277  }
1278  }
1279  CSLDestroy( papszFiles1 );
1280 
1281  // return oFiles.StealList();
1282  return papszOFiles;
1283 }
1284 
1285 QVector<QgsDataItem*> QgsZipItem::createChildren()
1286 {
1287  QVector<QgsDataItem*> children;
1288  QString tmpPath;
1289  QSettings settings;
1290  QString scanZipSetting = settings.value( QStringLiteral( "/qgis/scanZipInBrowser2" ), "basic" ).toString();
1291 
1292  mZipFileList.clear();
1293 
1294  QgsDebugMsgLevel( QString( "mFilePath = %1 path = %2 name= %3 scanZipSetting= %4 vsiPrefix= %5" ).arg( mFilePath, path(), name(), scanZipSetting, mVsiPrefix ), 2 );
1295 
1296  // if scanZipBrowser == no: skip to the next file
1297  if ( scanZipSetting == QLatin1String( "no" ) )
1298  {
1299  return children;
1300  }
1301 
1302  // first get list of files
1303  getZipFileList();
1304 
1305  // loop over files inside zip
1306  Q_FOREACH ( const QString& fileName, mZipFileList )
1307  {
1308  QFileInfo info( fileName );
1309  tmpPath = mVsiPrefix + mFilePath + '/' + fileName;
1310  QgsDebugMsgLevel( "tmpPath = " + tmpPath, 3 );
1311 
1312  // Q_FOREACH( dataItem_t *dataItem, mDataItemPtr )
1313  for ( int i = 0; i < sProviderNames.size(); i++ )
1314  {
1315  // ugly hack to remove .dbf file if there is a .shp file
1316  if ( sProviderNames[i] == QLatin1String( "ogr" ) )
1317  {
1318  if ( info.suffix().toLower() == QLatin1String( "dbf" ) )
1319  {
1320  if ( mZipFileList.indexOf( fileName.left( fileName.count() - 4 ) + ".shp" ) != -1 )
1321  continue;
1322  }
1323  if ( info.completeSuffix().toLower() == QLatin1String( "shp.xml" ) )
1324  {
1325  continue;
1326  }
1327  }
1328 
1329  // try to get data item from provider
1330  dataItem_t *dataItem = sDataItemPtr.at( i );
1331  if ( dataItem )
1332  {
1333  QgsDebugMsgLevel( QString( "trying to load item %1 with %2" ).arg( tmpPath, sProviderNames.at( i ) ), 3 );
1334  QgsDataItem * item = dataItem( tmpPath, this );
1335  if ( item )
1336  {
1337  QgsDebugMsgLevel( "loaded item", 3 );
1338  // the item comes with zipped file name, set the name to relative path within zip file
1339  item->setName( fileName );
1340  children.append( item );
1341  break;
1342  }
1343  else
1344  {
1345  QgsDebugMsgLevel( "not loaded item", 3 );
1346  }
1347  }
1348  }
1349 
1350  }
1351 
1352  return children;
1353 }
1354 
1355 QgsDataItem* QgsZipItem::itemFromPath( QgsDataItem* parent, const QString& path, const QString& name )
1356 {
1357  return itemFromPath( parent, path, name, path );
1358 }
1359 
1360 QgsDataItem* QgsZipItem::itemFromPath( QgsDataItem* parent, const QString& filePath, const QString& name, const QString& path )
1361 {
1362  QSettings settings;
1363  QString scanZipSetting = settings.value( QStringLiteral( "/qgis/scanZipInBrowser2" ), "basic" ).toString();
1364  int zipFileCount = 0;
1365  QStringList zipFileList;
1366  QString vsiPrefix = QgsZipItem::vsiPrefix( filePath );
1367  QgsZipItem * zipItem = nullptr;
1368  bool populated = false;
1369 
1370  QgsDebugMsgLevel( QString( "path = %1 name= %2 scanZipSetting= %3 vsiPrefix= %4" ).arg( path, name, scanZipSetting, vsiPrefix ), 3 );
1371 
1372  // don't scan if scanZipBrowser == no
1373  if ( scanZipSetting == QLatin1String( "no" ) )
1374  return nullptr;
1375 
1376  // don't scan if this file is not a /vsizip/ or /vsitar/ item
1377  if (( vsiPrefix != QLatin1String( "/vsizip/" ) && vsiPrefix != QLatin1String( "/vsitar/" ) ) )
1378  return nullptr;
1379 
1380  zipItem = new QgsZipItem( parent, name, filePath, path );
1381 
1382  if ( zipItem )
1383  {
1384  // force populate zipItem if it has less than 10 items and is not a .tgz or .tar.gz file (slow loading)
1385  // for other items populating will be delayed until item is opened
1386  // this might be polluting the tree with empty items but is necessary for performance reasons
1387  // could also accept all files smaller than a certain size and add options for file count and/or size
1388 
1389  // first get list of files inside .zip or .tar files
1390  if ( path.endsWith( QLatin1String( ".zip" ), Qt::CaseInsensitive ) ||
1391  path.endsWith( QLatin1String( ".tar" ), Qt::CaseInsensitive ) )
1392  {
1393  zipFileList = zipItem->getZipFileList();
1394  }
1395  // force populate if less than 10 items
1396  if ( !zipFileList.isEmpty() && zipFileList.count() <= 10 )
1397  {
1398  zipItem->populate( zipItem->createChildren() );
1399  populated = true; // there is no QgsDataItem::isPopulated() function
1400  QgsDebugMsgLevel( QString( "Got zipItem with %1 children, path=%2, name=%3" ).arg( zipItem->rowCount() ).arg( zipItem->path(), zipItem->name() ), 3 );
1401  }
1402  else
1403  {
1404  QgsDebugMsgLevel( QString( "Delaying populating zipItem with path=%1, name=%2" ).arg( zipItem->path(), zipItem->name() ), 3 );
1405  }
1406  }
1407 
1408  // only display if has children or if is not populated
1409  if ( zipItem && ( !populated || zipItem->rowCount() > 1 ) )
1410  {
1411  QgsDebugMsgLevel( "returning zipItem", 3 );
1412  return zipItem;
1413  }
1414  // if 1 or 0 child found, create a single data item using the normal path or the full path given by QgsZipItem
1415  else
1416  {
1417  QString vsiPath = vsiPrefix + filePath;
1418  if ( zipItem )
1419  {
1420  QVector<QgsDataItem*> children = zipItem->children();
1421  if ( children.size() == 1 )
1422  {
1423  // take the name of the only child so we can get a normal data item from it
1424  QgsLayerItem *layerItem = qobject_cast<QgsLayerItem*>( children.first() );
1425  if ( layerItem )
1426  vsiPath = layerItem->uri();
1427  }
1428  zipFileCount = zipFileList.count();
1429  delete zipItem;
1430  }
1431 
1432  QgsDebugMsgLevel( QString( "will try to create a normal dataItem from filePath= %2 or vsiPath = %3" ).arg( filePath, vsiPath ), 3 );
1433 
1434  // try to open using registered providers (gdal and ogr)
1435  for ( int i = 0; i < sProviderNames.size(); i++ )
1436  {
1437  dataItem_t *dataItem = sDataItemPtr.at( i );
1438  if ( dataItem )
1439  {
1440  QgsDataItem *item = nullptr;
1441  // try first with normal path (Passthru)
1442  // this is to simplify .qml handling, and without this some tests will fail
1443  // (e.g. testZipItemVectorTransparency(), second test)
1444  if (( sProviderNames.at( i ) == QLatin1String( "ogr" ) ) ||
1445  ( sProviderNames.at( i ) == QLatin1String( "gdal" ) && zipFileCount == 1 ) )
1446  item = dataItem( filePath, parent );
1447  // try with /vsizip/
1448  if ( ! item )
1449  item = dataItem( vsiPath, parent );
1450  if ( item )
1451  return item;
1452  }
1453  }
1454  }
1455 
1456  return nullptr;
1457 }
1458 
1460 {
1461  if ( ! mZipFileList.isEmpty() )
1462  return mZipFileList;
1463 
1464  QString tmpPath;
1465  QSettings settings;
1466  QString scanZipSetting = settings.value( QStringLiteral( "/qgis/scanZipInBrowser2" ), "basic" ).toString();
1467 
1468  QgsDebugMsgLevel( QString( "mFilePath = %1 name= %2 scanZipSetting= %3 vsiPrefix= %4" ).arg( mFilePath, name(), scanZipSetting, mVsiPrefix ), 3 );
1469 
1470  // if scanZipBrowser == no: skip to the next file
1471  if ( scanZipSetting == QLatin1String( "no" ) )
1472  {
1473  return mZipFileList;
1474  }
1475 
1476  // get list of files inside zip file
1477  QgsDebugMsgLevel( QString( "Open file %1 with gdal vsi" ).arg( mVsiPrefix + mFilePath ), 3 );
1478  char **papszSiblingFiles = VSIReadDirRecursive1( QString( mVsiPrefix + mFilePath ).toLocal8Bit().constData() );
1479  if ( papszSiblingFiles )
1480  {
1481  for ( int i = 0; i < CSLCount( papszSiblingFiles ); i++ )
1482  {
1483  tmpPath = papszSiblingFiles[i];
1484  QgsDebugMsgLevel( QString( "Read file %1" ).arg( tmpPath ), 3 );
1485  // skip directories (files ending with /)
1486  if ( tmpPath.right( 1 ) != QLatin1String( "/" ) )
1487  mZipFileList << tmpPath;
1488  }
1489  CSLDestroy( papszSiblingFiles );
1490  }
1491  else
1492  {
1493  QgsDebugMsg( QString( "Error reading %1" ).arg( mFilePath ) );
1494  }
1495 
1496  return mZipFileList;
1497 }
QString iconPath() const
Definition: qgsdataitem.cpp:62
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)
QString path() const
Definition: qgsdataitem.h:224
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 QString layerName() const
Definition: qgsdataitem.h:398
virtual void childrenCreated() override
virtual void refresh()
QString providerKey() const
Returns provider key.
Definition: qgsdataitem.h:359
QgsErrorItem(QgsDataItem *parent, const QString &error, const QString &path)
QString name() const
Definition: qgsdataitem.h:222
void dataChanged(QgsDataItem *item)
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.
void addDirectory(const QString &directory)
Adds a new directory to the favorites group.
QgsMapLayer::LayerType mapLayerType() const
Returns QgsMapLayer::LayerType.
QVector< QgsDataItem * > children() const
Definition: qgsdataitem.h:220
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
QString mProviderKey
The provider key.
Definition: qgsdataitem.h:379
static QIcon getThemeIcon(const QString &theName)
Helper to get a theme icon.
QLibrary * providerLibrary(const QString &providerKey) const
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:272
State mState
Definition: qgsdataitem.h:264
static QIcon iconLine()
Type type() const
Definition: qgsdataitem.h:211
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()
State state() const
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).
static void deleteLater(QVector< QgsDataItem *> &items)
QString mFilePath
Definition: qgsdataitem.h:566
QgsDataItem * parent() const
Get item parent.
Definition: qgsdataitem.h:215
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
#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:59
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
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.
#define cast_to_fptr(f)
Definition: qgis.h:123
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
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()
void moveToThread(QThread *targetThread)
Move object and all its descendants to thread.
QgsAnimatedIcon(const QString &iconPath=QString::null)
Constructor.
Definition: qgsdataitem.cpp:47
static QVector< dataItem_t * > sDataItemPtr
Definition: qgsdataitem.h:578
QVector< QgsDataItem * > createChildren() override
Create children.
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.
QStringList supportedFormats() const
Returns the supported formats.
Definition: qgsdataitem.h:369
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
QString uri() const
Returns layer uri or empty string if layer cannot be created.
Definition: qgsdataitem.h:356
QgsDataItem * mParent
Definition: qgsdataitem.h:262
bool deferredDelete()
The item is scheduled to be deleted.
Definition: qgsdataitem.h:258
QString dirPath() const
Definition: qgsdataitem.h:449
QIcon icon() const
Definition: qgsdataitem.h:55
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.
static int findItem(QVector< QgsDataItem *> items, QgsDataItem *item)
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
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: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).
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.
QStringList supportedCrs() const
Returns the supported CRS.
Definition: qgsdataitem.h:364
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
virtual Capabilities capabilities2() const
Definition: qgsdataitem.h:197
void frameChanged()
Emitted when icon changed.