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