Quantum GIS API Documentation  1.8
src/core/qgsdataitem.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                qgsdataitem.cpp  - Data items
00003                              -------------------
00004     begin                : 2011-04-01
00005     copyright            : (C) 2011 Radim Blazek
00006     email                : radim dot blazek at gmail dot com
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 #include <QApplication>
00019 #include <QDateTime>
00020 #include <QDir>
00021 #include <QFileInfo>
00022 #include <QMenu>
00023 #include <QMouseEvent>
00024 #include <QTreeWidget>
00025 #include <QTreeWidgetItem>
00026 #include <QVector>
00027 #include <QStyle>
00028 #include <QSettings>
00029 
00030 #include "qgis.h"
00031 #include "qgsapplication.h"
00032 #include "qgsdataitem.h"
00033 
00034 #include "qgsdataprovider.h"
00035 #include "qgslogger.h"
00036 #include "qgsproviderregistry.h"
00037 #include "qgsconfig.h"
00038 
00039 // use GDAL VSI mechanism
00040 #include "cpl_vsi.h"
00041 #include "cpl_string.h"
00042 
00043 // shared icons
00044 const QIcon &QgsLayerItem::iconPoint()
00045 {
00046   static QIcon icon;
00047 
00048   if ( icon.isNull() )
00049     icon = QIcon( getThemePixmap( "/mIconPointLayer.png" ) );
00050 
00051   return icon;
00052 }
00053 
00054 const QIcon &QgsLayerItem::iconLine()
00055 {
00056   static QIcon icon;
00057 
00058   if ( icon.isNull() )
00059     icon = QIcon( getThemePixmap( "/mIconLineLayer.png" ) );
00060 
00061   return icon;
00062 }
00063 
00064 const QIcon &QgsLayerItem::iconPolygon()
00065 {
00066   static QIcon icon;
00067 
00068   if ( icon.isNull() )
00069     icon = QIcon( getThemePixmap( "/mIconPolygonLayer.png" ) );
00070 
00071   return icon;
00072 }
00073 
00074 const QIcon &QgsLayerItem::iconTable()
00075 {
00076   static QIcon icon;
00077 
00078   if ( icon.isNull() )
00079     icon = QIcon( getThemePixmap( "/mIconTableLayer.png" ) );
00080 
00081   return icon;
00082 }
00083 
00084 const QIcon &QgsLayerItem::iconRaster()
00085 {
00086   static QIcon icon;
00087 
00088   if ( icon.isNull() )
00089     icon = QIcon( getThemePixmap( "/mIconRaster.png" ) );
00090 
00091   return icon;
00092 }
00093 
00094 const QIcon &QgsLayerItem::iconDefault()
00095 {
00096   static QIcon icon;
00097 
00098   if ( icon.isNull() )
00099     icon = QIcon( getThemePixmap( "/mIconLayer.png" ) );
00100 
00101   return icon;
00102 }
00103 
00104 const QIcon &QgsDataCollectionItem::iconDataCollection()
00105 {
00106   static QIcon icon;
00107 
00108   if ( icon.isNull() )
00109     icon = QIcon( getThemePixmap( "/mIconDbSchema.png" ) );
00110 
00111   return icon;
00112 }
00113 
00114 const QIcon &QgsDataCollectionItem::iconDir()
00115 {
00116   static QIcon icon;
00117 
00118   if ( icon.isNull() )
00119   {
00120     // initialize shared icons
00121     QStyle *style = QApplication::style();
00122     icon = QIcon( style->standardPixmap( QStyle::SP_DirClosedIcon ) );
00123     icon.addPixmap( style->standardPixmap( QStyle::SP_DirOpenIcon ),
00124                     QIcon::Normal, QIcon::On );
00125   }
00126 
00127   return icon;
00128 }
00129 
00130 const QIcon &QgsFavouritesItem::iconFavourites()
00131 {
00132   static QIcon icon;
00133 
00134   if ( icon.isNull() )
00135     icon = QIcon( getThemePixmap( "/mIconFavourites.png" ) );
00136 
00137   return icon;
00138 }
00139 
00140 const QIcon &QgsZipItem::iconZip()
00141 {
00142   static QIcon icon;
00143 
00144   if ( icon.isNull() )
00145     icon = QIcon( getThemePixmap( "/mIconZip.png" ) );
00146 // icon from http://www.softicons.com/free-icons/application-icons/mega-pack-icons-1-by-nikolay-verin/winzip-folder-icon
00147 
00148   return icon;
00149 }
00150 
00151 
00152 QgsDataItem::QgsDataItem( QgsDataItem::Type type, QgsDataItem* parent, QString name, QString path )
00153     : QObject( parent ), mType( type ), mParent( parent ), mPopulated( false ), mName( name ), mPath( path )
00154 {
00155 }
00156 
00157 // TODO: This is copy from QgisApp, bad
00158 // TODO: add some caching mechanism ?
00159 QPixmap QgsDataItem::getThemePixmap( const QString theName )
00160 {
00161   QString myPreferredPath = QgsApplication::activeThemePath()  + QDir::separator() + theName;
00162   QString myDefaultPath = QgsApplication::defaultThemePath()  + QDir::separator() + theName;
00163 
00164   // QgsDebugMsg( "theName = " + theName );
00165   // QgsDebugMsg( "myPreferredPath = " + myPreferredPath );
00166   // QgsDebugMsg( "myDefaultPath = " + myDefaultPath );
00167   if ( QFile::exists( myPreferredPath ) )
00168   {
00169     return QPixmap( myPreferredPath );
00170   }
00171   else
00172   {
00173     //could still return an empty icon if it
00174     //doesnt exist in the default theme either!
00175     return QPixmap( myDefaultPath );
00176   }
00177 }
00178 
00179 void QgsDataItem::emitBeginInsertItems( QgsDataItem* parent, int first, int last )
00180 {
00181   emit beginInsertItems( parent, first, last );
00182 }
00183 void QgsDataItem::emitEndInsertItems()
00184 {
00185   emit endInsertItems();
00186 }
00187 void QgsDataItem::emitBeginRemoveItems( QgsDataItem* parent, int first, int last )
00188 {
00189   emit beginRemoveItems( parent, first, last );
00190 }
00191 void QgsDataItem::emitEndRemoveItems()
00192 {
00193   emit endRemoveItems();
00194 }
00195 
00196 QVector<QgsDataItem*> QgsDataItem::createChildren( )
00197 {
00198   QVector<QgsDataItem*> children;
00199   return children;
00200 }
00201 
00202 void QgsDataItem::populate()
00203 {
00204   if ( mPopulated )
00205     return;
00206 
00207   QgsDebugMsg( "mPath = " + mPath );
00208 
00209   QApplication::setOverrideCursor( Qt::WaitCursor );
00210 
00211   QVector<QgsDataItem*> children = createChildren( );
00212   foreach( QgsDataItem *child, children )
00213   {
00214     // initialization, do not refresh! That would result in infinite loop (beginInsertItems->rowCount->populate)
00215     addChildItem( child );
00216   }
00217   mPopulated = true;
00218 
00219   QApplication::restoreOverrideCursor();
00220 }
00221 
00222 int QgsDataItem::rowCount()
00223 {
00224   if ( !mPopulated )
00225     populate();
00226   return mChildren.size();
00227 }
00228 bool QgsDataItem::hasChildren()
00229 {
00230   return ( mPopulated ? mChildren.count() > 0 : true );
00231 }
00232 
00233 void QgsDataItem::addChildItem( QgsDataItem * child, bool refresh )
00234 {
00235   QgsDebugMsg( QString( "add child #%1 - %2 - %3" ).arg( mChildren.size() ).arg( child->mName ).arg( child->mType ) );
00236 
00237   int i;
00238   if ( type() == Directory )
00239   {
00240     for ( i = 0; i < mChildren.size(); i++ )
00241     {
00242       // sort items by type, so directories are before data items
00243       if ( mChildren[i]->mType == child->mType &&
00244            mChildren[i]->mName.localeAwareCompare( child->mName ) >= 0 )
00245         break;
00246     }
00247   }
00248   else
00249   {
00250     for ( i = 0; i < mChildren.size(); i++ )
00251     {
00252       if ( mChildren[i]->mName.localeAwareCompare( child->mName ) >= 0 )
00253         break;
00254     }
00255   }
00256 
00257   if ( refresh )
00258     emit beginInsertItems( this, i, i );
00259 
00260   mChildren.insert( i, child );
00261 
00262   connect( child, SIGNAL( beginInsertItems( QgsDataItem*, int, int ) ),
00263            this, SLOT( emitBeginInsertItems( QgsDataItem*, int, int ) ) );
00264   connect( child, SIGNAL( endInsertItems() ),
00265            this, SLOT( emitEndInsertItems() ) );
00266   connect( child, SIGNAL( beginRemoveItems( QgsDataItem*, int, int ) ),
00267            this, SLOT( emitBeginRemoveItems( QgsDataItem*, int, int ) ) );
00268   connect( child, SIGNAL( endRemoveItems() ),
00269            this, SLOT( emitEndRemoveItems() ) );
00270 
00271   if ( refresh )
00272     emit endInsertItems();
00273 }
00274 void QgsDataItem::deleteChildItem( QgsDataItem * child )
00275 {
00276   QgsDebugMsg( "mName = " + child->mName );
00277   int i = mChildren.indexOf( child );
00278   Q_ASSERT( i >= 0 );
00279   emit beginRemoveItems( this, i, i );
00280   mChildren.remove( i );
00281   delete child;
00282   emit endRemoveItems();
00283 }
00284 
00285 int QgsDataItem::findItem( QVector<QgsDataItem*> items, QgsDataItem * item )
00286 {
00287   for ( int i = 0; i < items.size(); i++ )
00288   {
00289     QgsDebugMsg( QString::number( i ) + " : " + items[i]->mPath + " x " + item->mPath );
00290     if ( items[i]->equal( item ) )
00291       return i;
00292   }
00293   return -1;
00294 }
00295 
00296 void QgsDataItem::refresh()
00297 {
00298   QgsDebugMsg( "mPath = " + mPath );
00299 
00300   QApplication::setOverrideCursor( Qt::WaitCursor );
00301 
00302   QVector<QgsDataItem*> items = createChildren( );
00303 
00304   // Remove no more present items
00305   QVector<QgsDataItem*> remove;
00306   foreach( QgsDataItem *child, mChildren )
00307   {
00308     if ( findItem( items, child ) >= 0 )
00309       continue;
00310     remove.append( child );
00311   }
00312   foreach( QgsDataItem *child, remove )
00313   {
00314     deleteChildItem( child );
00315   }
00316 
00317   // Add new items
00318   foreach( QgsDataItem *item, items )
00319   {
00320     // Is it present in childs?
00321     if ( findItem( mChildren, item ) >= 0 )
00322     {
00323       delete item;
00324       continue;
00325     }
00326     addChildItem( item, true );
00327   }
00328 
00329   QApplication::restoreOverrideCursor();
00330 }
00331 
00332 bool QgsDataItem::equal( const QgsDataItem *other )
00333 {
00334   if ( metaObject()->className() == other->metaObject()->className() &&
00335        mPath == other->path() )
00336   {
00337     return true;
00338   }
00339   return false;
00340 }
00341 
00342 // ---------------------------------------------------------------------
00343 
00344 QgsLayerItem::QgsLayerItem( QgsDataItem* parent, QString name, QString path, QString uri, LayerType layerType, QString providerKey )
00345     : QgsDataItem( Layer, parent, name, path )
00346     , mProviderKey( providerKey )
00347     , mUri( uri )
00348     , mLayerType( layerType )
00349 {
00350   switch ( layerType )
00351   {
00352     case Point:      mIcon = iconPoint(); break;
00353     case Line:       mIcon = iconLine(); break;
00354     case Polygon:    mIcon = iconPolygon(); break;
00355       // TODO add a new icon for generic Vector layers
00356     case Vector :    mIcon = iconPolygon(); break;
00357     case TableLayer: mIcon = iconTable(); break;
00358     case Raster:     mIcon = iconRaster(); break;
00359     default:         mIcon = iconDefault(); break;
00360   }
00361 }
00362 
00363 QgsMapLayer::LayerType QgsLayerItem::mapLayerType()
00364 {
00365   if ( mLayerType == QgsLayerItem::Raster )
00366     return QgsMapLayer::RasterLayer;
00367   return QgsMapLayer::VectorLayer;
00368 }
00369 
00370 bool QgsLayerItem::equal( const QgsDataItem *other )
00371 {
00372   //QgsDebugMsg ( mPath + " x " + other->mPath );
00373   if ( type() != other->type() )
00374   {
00375     return false;
00376   }
00377   //const QgsLayerItem *o = qobject_cast<const QgsLayerItem *> ( other );
00378   const QgsLayerItem *o = dynamic_cast<const QgsLayerItem *>( other );
00379   return ( mPath == o->mPath && mName == o->mName && mUri == o->mUri && mProviderKey == o->mProviderKey );
00380 }
00381 
00382 // ---------------------------------------------------------------------
00383 QgsDataCollectionItem::QgsDataCollectionItem( QgsDataItem* parent, QString name, QString path )
00384     : QgsDataItem( Collection, parent, name, path )
00385 {
00386   mIcon = iconDataCollection();
00387 }
00388 
00389 QgsDataCollectionItem::~QgsDataCollectionItem()
00390 {
00391   foreach( QgsDataItem* i, mChildren )
00392   delete i;
00393 }
00394 
00395 //-----------------------------------------------------------------------
00396 // QVector<QgsDataProvider*> QgsDirectoryItem::mProviders = QVector<QgsDataProvider*>();
00397 QVector<QLibrary*> QgsDirectoryItem::mLibraries = QVector<QLibrary*>();
00398 
00399 
00400 QgsDirectoryItem::QgsDirectoryItem( QgsDataItem* parent, QString name, QString path )
00401     : QgsDataCollectionItem( parent, name, path )
00402 {
00403   mType = Directory;
00404   mIcon = iconDir();
00405 
00406   if ( mLibraries.size() == 0 )
00407   {
00408     QStringList keys = QgsProviderRegistry::instance()->providerList();
00409     QStringList::const_iterator i;
00410     for ( i = keys.begin(); i != keys.end(); ++i )
00411     {
00412       QString k( *i );
00413       // some providers hangs with empty uri (Postgis) etc...
00414       // -> using libraries directly
00415       QLibrary *library = QgsProviderRegistry::instance()->providerLibrary( k );
00416       if ( library )
00417       {
00418         dataCapabilities_t * dataCapabilities = ( dataCapabilities_t * ) cast_to_fptr( library->resolve( "dataCapabilities" ) );
00419         if ( !dataCapabilities )
00420         {
00421           QgsDebugMsg( library->fileName() + " does not have dataCapabilities" );
00422           continue;
00423         }
00424         if ( dataCapabilities() == QgsDataProvider::NoDataCapabilities )
00425         {
00426           QgsDebugMsg( library->fileName() + " has NoDataCapabilities" );
00427           continue;
00428         }
00429 
00430         QgsDebugMsg( QString( "%1 dataCapabilities : %2" ).arg( library->fileName() ).arg( dataCapabilities() ) );
00431         mLibraries.append( library );
00432       }
00433       else
00434       {
00435         //QgsDebugMsg ( "Cannot get provider " + k );
00436       }
00437     }
00438   }
00439 }
00440 
00441 QgsDirectoryItem::~QgsDirectoryItem()
00442 {
00443 }
00444 
00445 QVector<QgsDataItem*> QgsDirectoryItem::createChildren( )
00446 {
00447   QVector<QgsDataItem*> children;
00448   QDir dir( mPath );
00449   QSettings settings;
00450   bool scanZip = ( settings.value( "/qgis/scanZipInBrowser", 2 ).toInt() != 0 );
00451 
00452   QStringList entries = dir.entryList( QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name | QDir::IgnoreCase );
00453   foreach( QString subdir, entries )
00454   {
00455     QString subdirPath = dir.absoluteFilePath( subdir );
00456     QgsDebugMsg( QString( "creating subdir: %1" ).arg( subdirPath ) );
00457 
00458     QgsDirectoryItem *item = new QgsDirectoryItem( this, subdir, subdirPath );
00459     // propagate signals up to top
00460 
00461     children.append( item );
00462   }
00463 
00464   QStringList fileEntries = dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot | QDir::Files, QDir::Name );
00465   foreach( QString name, fileEntries )
00466   {
00467     QString path = dir.absoluteFilePath( name );
00468     QFileInfo fileInfo( path );
00469 
00470     // vsizip support was added to GDAL/OGR 1.6 but GDAL_VERSION_NUM not available here
00471     if ( fileInfo.suffix() == "zip" && scanZip )
00472     {
00473       QgsDataItem * item = QgsZipItem::itemFromPath( this, path, name );
00474       if ( item )
00475       {
00476         children.append( item );
00477         continue;
00478       }
00479     }
00480 
00481     foreach( QLibrary *library, mLibraries )
00482     {
00483       // we could/should create separate list of providers for each purpose
00484 
00485       // TODO: use existing fileVectorFilters(),directoryDrivers() ?
00486       dataCapabilities_t * dataCapabilities = ( dataCapabilities_t * ) cast_to_fptr( library->resolve( "dataCapabilities" ) );
00487       if ( !dataCapabilities )
00488       {
00489         continue;
00490       }
00491 
00492       int capabilities = dataCapabilities();
00493 
00494       if ( !(( fileInfo.isFile() && ( capabilities & QgsDataProvider::File ) ) ||
00495              ( fileInfo.isDir() && ( capabilities & QgsDataProvider::Dir ) ) ) )
00496       {
00497         continue;
00498       }
00499 
00500       dataItem_t * dataItem = ( dataItem_t * ) cast_to_fptr( library->resolve( "dataItem" ) );
00501       if ( ! dataItem )
00502       {
00503         QgsDebugMsg( library->fileName() + " does not have dataItem" );
00504         continue;
00505       }
00506 
00507       QgsDataItem * item = dataItem( path, this );
00508       if ( item )
00509       {
00510         children.append( item );
00511       }
00512     }
00513   }
00514 
00515   return children;
00516 }
00517 
00518 bool QgsDirectoryItem::equal( const QgsDataItem *other )
00519 {
00520   //QgsDebugMsg ( mPath + " x " + other->mPath );
00521   if ( type() != other->type() )
00522   {
00523     return false;
00524   }
00525   return ( path() == other->path() );
00526 }
00527 
00528 QWidget * QgsDirectoryItem::paramWidget()
00529 {
00530   return new QgsDirectoryParamWidget( mPath );
00531 }
00532 
00533 QgsDirectoryParamWidget::QgsDirectoryParamWidget( QString path, QWidget* parent )
00534     : QTreeWidget( parent )
00535 {
00536   setRootIsDecorated( false );
00537 
00538   // name, size, date, permissions, owner, group, type
00539   setColumnCount( 7 );
00540   QStringList labels;
00541   labels << tr( "Name" ) << tr( "Size" ) << tr( "Date" ) << tr( "Permissions" ) << tr( "Owner" ) << tr( "Group" ) << tr( "Type" );
00542   setHeaderLabels( labels );
00543 
00544   QStyle* style = QApplication::style();
00545   QIcon iconDirectory = QIcon( style->standardPixmap( QStyle::SP_DirClosedIcon ) );
00546   QIcon iconFile = QIcon( style->standardPixmap( QStyle::SP_FileIcon ) );
00547   QIcon iconLink = QIcon( style->standardPixmap( QStyle::SP_FileLinkIcon ) ); // TODO: symlink to directory?
00548 
00549   QList<QTreeWidgetItem *> items;
00550 
00551   QDir dir( path );
00552   QStringList entries = dir.entryList( QDir::AllEntries | QDir::NoDotAndDotDot, QDir::Name | QDir::IgnoreCase );
00553   foreach( QString name, entries )
00554   {
00555     QFileInfo fi( dir.absoluteFilePath( name ) );
00556     QStringList texts;
00557     texts << name;
00558     QString size;
00559     if ( fi.size() > 1024 )
00560     {
00561       size = size.sprintf( "%.1f KiB", fi.size() / 1024.0 );
00562     }
00563     else if ( fi.size() > 1.048576e6 )
00564     {
00565       size = size.sprintf( "%.1f MiB", fi.size() / 1.048576e6 );
00566     }
00567     else
00568     {
00569       size = QString( "%1 B" ).arg( fi.size() );
00570     }
00571     texts << size;
00572     texts << fi.lastModified().toString( Qt::SystemLocaleShortDate );
00573     QString perm;
00574     perm += fi.permission( QFile::ReadOwner ) ? 'r' : '-';
00575     perm += fi.permission( QFile::WriteOwner ) ? 'w' : '-';
00576     perm += fi.permission( QFile::ExeOwner ) ? 'x' : '-';
00577     // QFile::ReadUser, QFile::WriteUser, QFile::ExeUser
00578     perm += fi.permission( QFile::ReadGroup ) ? 'r' : '-';
00579     perm += fi.permission( QFile::WriteGroup ) ? 'w' : '-';
00580     perm += fi.permission( QFile::ExeGroup ) ? 'x' : '-';
00581     perm += fi.permission( QFile::ReadOther ) ? 'r' : '-';
00582     perm += fi.permission( QFile::WriteOther ) ? 'w' : '-';
00583     perm += fi.permission( QFile::ExeOther ) ? 'x' : '-';
00584     texts << perm;
00585 
00586     texts << fi.owner();
00587     texts << fi.group();
00588 
00589     QString type;
00590     QIcon icon;
00591     if ( fi.isDir() )
00592     {
00593       type = tr( "folder" );
00594       icon = iconDirectory;
00595     }
00596     else if ( fi.isFile() )
00597     {
00598       type = tr( "file" );
00599       icon = iconFile;
00600     }
00601     else if ( fi.isSymLink() )
00602     {
00603       type = tr( "link" );
00604       icon = iconLink;
00605     }
00606 
00607     texts << type;
00608 
00609     QTreeWidgetItem *item = new QTreeWidgetItem( texts );
00610     item->setIcon( 0, icon );
00611     items << item;
00612   }
00613 
00614   addTopLevelItems( items );
00615 
00616   // hide columns that are not requested
00617   QSettings settings;
00618   QList<QVariant> lst = settings.value( "/dataitem/directoryHiddenColumns" ).toList();
00619   foreach( QVariant colVariant, lst )
00620   {
00621     setColumnHidden( colVariant.toInt(), true );
00622   }
00623 }
00624 
00625 void QgsDirectoryParamWidget::mousePressEvent( QMouseEvent* event )
00626 {
00627   if ( event->button() == Qt::RightButton )
00628   {
00629     // show the popup menu
00630     QMenu popupMenu;
00631 
00632     QStringList labels;
00633     labels << tr( "Name" ) << tr( "Size" ) << tr( "Date" ) << tr( "Permissions" ) << tr( "Owner" ) << tr( "Group" ) << tr( "Type" );
00634     for ( int i = 0; i < labels.count(); i++ )
00635     {
00636       QAction* action = popupMenu.addAction( labels[i], this, SLOT( showHideColumn() ) );
00637       action->setObjectName( QString::number( i ) );
00638       action->setCheckable( true );
00639       action->setChecked( !isColumnHidden( i ) );
00640     }
00641 
00642     popupMenu.exec( event->globalPos() );
00643   }
00644 }
00645 
00646 void QgsDirectoryParamWidget::showHideColumn()
00647 {
00648   QAction* action = qobject_cast<QAction*>( sender() );
00649   if ( !action )
00650     return; // something is wrong
00651 
00652   int columnIndex = action->objectName().toInt();
00653   setColumnHidden( columnIndex, !isColumnHidden( columnIndex ) );
00654 
00655   // save in settings
00656   QSettings settings;
00657   QList<QVariant> lst;
00658   for ( int i = 0; i < columnCount(); i++ )
00659   {
00660     if ( isColumnHidden( i ) )
00661       lst.append( QVariant( i ) );
00662   }
00663   settings.setValue( "/dataitem/directoryHiddenColumns", lst );
00664 }
00665 
00666 
00667 QgsErrorItem::QgsErrorItem( QgsDataItem* parent, QString error, QString path )
00668     : QgsDataItem( QgsDataItem::Error, parent, error, path )
00669 {
00670   mIcon = QIcon( getThemePixmap( "/mIconDelete.png" ) );
00671 
00672   mPopulated = true; // no more children
00673 }
00674 
00675 QgsErrorItem::~QgsErrorItem()
00676 {
00677 }
00678 
00679 QgsFavouritesItem::QgsFavouritesItem( QgsDataItem* parent, QString name, QString path )
00680     : QgsDataCollectionItem( parent, name, path )
00681 {
00682   mType = Favourites;
00683   mIcon = iconFavourites();
00684 }
00685 
00686 QgsFavouritesItem::~QgsFavouritesItem()
00687 {
00688 }
00689 
00690 QVector<QgsDataItem*> QgsFavouritesItem::createChildren( )
00691 {
00692   QVector<QgsDataItem*> children;
00693   QgsDataItem* item;
00694 
00695   QSettings settings;
00696   QStringList favDirs = settings.value( "/browser/favourites", QVariant() ).toStringList();
00697 
00698   foreach( QString favDir, favDirs )
00699   {
00700     item = new QgsDirectoryItem( this, favDir, favDir );
00701     if ( item )
00702     {
00703       children.append( item );
00704     }
00705   }
00706 
00707   return children;
00708 }
00709 
00710 //-----------------------------------------------------------------------
00711 QStringList QgsZipItem::mProviderNames = QStringList();
00712 QVector<dataItem_t *> QgsZipItem::mDataItemPtr = QVector<dataItem_t*>();
00713 
00714 
00715 QgsZipItem::QgsZipItem( QgsDataItem* parent, QString name, QString path )
00716     : QgsDataCollectionItem( parent, name, path )
00717 {
00718   mType = Collection; //Zip??
00719   mIcon = iconZip();
00720 
00721   if ( mProviderNames.size() == 0 )
00722   {
00723     // QStringList keys = QgsProviderRegistry::instance()->providerList();
00724     // only use GDAL and OGR providers as we use the VSIFILE mechanism
00725     QStringList keys;
00726     // keys << "ogr" << "gdal";
00727     keys << "gdal" << "ogr";
00728 
00729     QStringList::const_iterator i;
00730     for ( i = keys.begin(); i != keys.end(); ++i )
00731     {
00732       QString k( *i );
00733       QgsDebugMsg( "provider " + k );
00734       // some providers hangs with empty uri (Postgis) etc...
00735       // -> using libraries directly
00736       QLibrary *library = QgsProviderRegistry::instance()->providerLibrary( k );
00737       if ( library )
00738       {
00739         dataCapabilities_t * dataCapabilities = ( dataCapabilities_t * ) cast_to_fptr( library->resolve( "dataCapabilities" ) );
00740         if ( !dataCapabilities )
00741         {
00742           QgsDebugMsg( library->fileName() + " does not have dataCapabilities" );
00743           continue;
00744         }
00745         if ( dataCapabilities() == QgsDataProvider::NoDataCapabilities )
00746         {
00747           QgsDebugMsg( library->fileName() + " has NoDataCapabilities" );
00748           continue;
00749         }
00750         QgsDebugMsg( QString( "%1 dataCapabilities : %2" ).arg( library->fileName() ).arg( dataCapabilities() ) );
00751 
00752         dataItem_t * dataItem = ( dataItem_t * ) cast_to_fptr( library->resolve( "dataItem" ) );
00753         if ( ! dataItem )
00754         {
00755           QgsDebugMsg( library->fileName() + " does not have dataItem" );
00756           continue;
00757         }
00758 
00759         // mLibraries.append( library );
00760         mDataItemPtr.append( dataItem );
00761         mProviderNames.append( k );
00762       }
00763       else
00764       {
00765         //QgsDebugMsg ( "Cannot get provider " + k );
00766       }
00767     }
00768   }
00769 
00770 }
00771 
00772 QgsZipItem::~QgsZipItem()
00773 {
00774 }
00775 
00776 // internal function to scan a vsidir (zip or tar file) recursively
00777 // GDAL trunk has this since r24423 (05/16/12) - VSIReadDirRecursive()
00778 // use a copy of the function internally for now,
00779 // but use char ** and CSLAddString, because CPLStringList was added in gdal-1.9
00780 char **VSIReadDirRecursive1( const char *pszPath )
00781 {
00782   // CPLStringList oFiles = NULL;
00783   char **papszOFiles = NULL;
00784   char **papszFiles1 = NULL;
00785   char **papszFiles2 = NULL;
00786   VSIStatBufL psStatBuf;
00787   CPLString osTemp1, osTemp2;
00788   int i, j;
00789   int nCount1, nCount2;
00790 
00791   // get listing
00792   papszFiles1 = VSIReadDir( pszPath );
00793   if ( ! papszFiles1 )
00794     return NULL;
00795 
00796   // get files and directories inside listing
00797   nCount1 = CSLCount( papszFiles1 );
00798   for ( i = 0; i < nCount1; i++ )
00799   {
00800     // build complete file name for stat
00801     osTemp1.clear();
00802     osTemp1.append( pszPath );
00803     osTemp1.append( "/" );
00804     osTemp1.append( papszFiles1[i] );
00805 
00806     // if is file, add it
00807     if ( VSIStatL( osTemp1.c_str(), &psStatBuf ) == 0 &&
00808          VSI_ISREG( psStatBuf.st_mode ) )
00809     {
00810       // oFiles.AddString( papszFiles1[i] );
00811       papszOFiles = CSLAddString( papszOFiles, papszFiles1[i] );
00812     }
00813     else if ( VSIStatL( osTemp1.c_str(), &psStatBuf ) == 0 &&
00814               VSI_ISDIR( psStatBuf.st_mode ) )
00815     {
00816       // add directory entry
00817       osTemp2.clear();
00818       osTemp2.append( papszFiles1[i] );
00819       osTemp2.append( "/" );
00820       // oFiles.AddString( osTemp2.c_str() );
00821       papszOFiles = CSLAddString( papszOFiles, osTemp2.c_str() );
00822 
00823       // recursively add files inside directory
00824       papszFiles2 = VSIReadDirRecursive1( osTemp1.c_str() );
00825       if ( papszFiles2 )
00826       {
00827         nCount2 = CSLCount( papszFiles2 );
00828         for ( j = 0; j < nCount2; j++ )
00829         {
00830           osTemp2.clear();
00831           osTemp2.append( papszFiles1[i] );
00832           osTemp2.append( "/" );
00833           osTemp2.append( papszFiles2[j] );
00834           // oFiles.AddString( osTemp2.c_str() );
00835           papszOFiles = CSLAddString( papszOFiles, osTemp2.c_str() );
00836         }
00837         CSLDestroy( papszFiles2 );
00838       }
00839     }
00840   }
00841   CSLDestroy( papszFiles1 );
00842 
00843   // return oFiles.StealList();
00844   return papszOFiles;
00845 }
00846 
00847 QVector<QgsDataItem*> QgsZipItem::createChildren( )
00848 {
00849   QVector<QgsDataItem*> children;
00850   QString tmpPath;
00851   QString childPath;
00852 
00853   QSettings settings;
00854   int scanZipSetting = settings.value( "/qgis/scanZipInBrowser", 2 ).toInt();
00855 
00856   mZipFileList.clear();
00857 
00858   QgsDebugMsg( QString( "path = %1 name= %2 scanZipSetting= %3" ).arg( path() ).arg( name() ).arg( scanZipSetting ) );
00859 
00860   // if scanZipBrowser == 0 (No): skip to the next file
00861   if ( scanZipSetting == 0 )
00862   {
00863     return children;
00864   }
00865 
00866   // if scanZipBrowser == 1 (Passthru): do not scan zip and allow to open directly with /vsizip/
00867   if ( scanZipSetting == 1 )
00868   {
00869     mPath = "/vsizip/" + path(); // should check for extension
00870     QgsDebugMsg( "set path to " + path() );
00871     return children;
00872   }
00873 
00874   // get list of files inside zip file
00875   QgsDebugMsg( QString( "Open file %1 with gdal vsi" ).arg( path() ) );
00876   char **papszSiblingFiles = VSIReadDirRecursive1( QString( "/vsizip/" + path() ).toLocal8Bit().constData() );
00877   if ( papszSiblingFiles )
00878   {
00879     for ( int i = 0; i < CSLCount( papszSiblingFiles ); i++ )
00880     {
00881       tmpPath = papszSiblingFiles[i];
00882       QgsDebugMsg( QString( "Read file %1" ).arg( tmpPath ) );
00883       // skip directories (files ending with /)
00884       if ( tmpPath.right( 1 ) != "/" )
00885         mZipFileList << tmpPath;
00886     }
00887     CSLDestroy( papszSiblingFiles );
00888   }
00889   else
00890   {
00891     QgsDebugMsg( QString( "Error reading %1" ).arg( path() ) );
00892   }
00893 
00894   // loop over files inside zip
00895   foreach( QString fileName, mZipFileList )
00896   {
00897     QFileInfo info( fileName );
00898     tmpPath = "/vsizip/" + path() + "/" + fileName;
00899     QgsDebugMsg( "tmpPath = " + tmpPath );
00900 
00901     // foreach( dataItem_t *dataItem, mDataItemPtr )
00902     for ( int i = 0; i < mProviderNames.size(); i++ )
00903     {
00904       // ugly hack to remove .dbf file if there is a .shp file
00905       if ( mProviderNames[i] == "ogr" )
00906       {
00907         if ( info.suffix() == "dbf" )
00908         {
00909           if ( mZipFileList.indexOf( fileName.left( fileName.count() - 4 ) + ".shp" ) != -1 )
00910             continue;
00911         }
00912         if ( info.completeSuffix().toLower() == "shp.xml" )
00913         {
00914           continue;
00915         }
00916       }
00917 
00918       // try to get data item from provider
00919       dataItem_t *dataItem = mDataItemPtr[i];
00920       if ( dataItem )
00921       {
00922         QgsDebugMsg( QString( "trying to load item %1 with %2" ).arg( tmpPath ).arg( mProviderNames[i] ) );
00923         QgsDataItem * item = dataItem( tmpPath, this );
00924         if ( item )
00925         {
00926           QgsDebugMsg( "loaded item" );
00927           childPath = tmpPath;
00928           children.append( item );
00929           break;
00930         }
00931         else
00932         {
00933           QgsDebugMsg( "not loaded item" );
00934         }
00935       }
00936     }
00937 
00938   }
00939 
00940   if ( children.size() == 1 )
00941   {
00942     // save the name of the only child so we can get a normal data item from it
00943     mPath = childPath;
00944   }
00945 
00946   return children;
00947 }
00948 
00949 
00950 
00951 QgsDataItem* QgsZipItem::itemFromPath( QgsDataItem* parent, QString path, QString name )
00952 {
00953   QSettings settings;
00954   int scanZipSetting = settings.value( "/qgis/scanZipInBrowser", 2 ).toInt();
00955   QString vsizipPath = path;
00956   int zipFileCount = 0;
00957   QFileInfo fileInfo( path );
00958   QgsZipItem * zipItem = 0;
00959 
00960   QgsDebugMsg( QString( "path = %1 name= %2 scanZipSetting= %3" ).arg( path ).arg( name ).arg( scanZipSetting ) );
00961 
00962   // if scanZipBrowser == 0 (No): skip to the next file
00963   if ( scanZipSetting == 0 )
00964   {
00965     return 0;
00966   }
00967   // if scanZipBrowser == 1 (Passthru): do not scan zip and allow to open directly with /vsizip/
00968   else if ( scanZipSetting == 1 )
00969   {
00970     vsizipPath = "/vsizip/" + path;
00971     zipItem = 0;
00972   }
00973   else
00974   {
00975     zipItem = new QgsZipItem( parent, name, path );
00976   }
00977 
00978   if ( zipItem )
00979   {
00980     // force populate zipItem
00981     zipItem->populate();
00982     QgsDebugMsg( QString( "Got zipItem with %1 children, path=%2, name=%3" ).arg( zipItem->rowCount() ).arg( zipItem->path() ).arg( zipItem->name() ) );
00983   }
00984 
00985 // only display if has children
00986 // other option would be to delay until item is opened, but we would be polluting the tree with empty items
00987   if ( zipItem && zipItem->rowCount() > 1 )
00988   {
00989     QgsDebugMsg( "returning zipItem" );
00990     return zipItem;
00991   }
00992 // if 1 or 0 child found, create a single data item using the normal path or the full path given by QgsZipItem
00993   else
00994   {
00995     if ( zipItem )
00996     {
00997       vsizipPath = zipItem->path();
00998       zipFileCount = zipItem->getZipFileList().count();
00999       delete zipItem;
01000     }
01001 
01002     QgsDebugMsg( QString( "will try to create a normal dataItem from path= %2 or %3" ).arg( path ).arg( vsizipPath ) );
01003 
01004     // try to open using registered providers (gdal and ogr)
01005     for ( int i = 0; i < mProviderNames.size(); i++ )
01006     {
01007       dataItem_t *dataItem = mDataItemPtr[i];
01008       if ( dataItem )
01009       {
01010         QgsDataItem *item = 0;
01011         // try first with normal path (Passthru)
01012         // this is to simplify .qml handling, and without this some tests will fail
01013         // (e.g. testZipItemVectorTransparency(), second test)
01014         if (( scanZipSetting == 1 ) ||
01015             ( mProviderNames[i] == "ogr" ) ||
01016             ( mProviderNames[i] == "gdal" && zipFileCount == 1 ) )
01017           item = dataItem( path, parent );
01018         // try with /vsizip/
01019         if ( ! item )
01020           item = dataItem( vsizipPath, parent );
01021         if ( item )
01022           return item;
01023       }
01024     }
01025   }
01026 
01027   return 0;
01028 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines