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