Quantum GIS API Documentation
1.8
|
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 }