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