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