diff --git a/python/core/qgsmaplayer.sip b/python/core/qgsmaplayer.sip index dd4e6f0b8b60..90f976c15891 100644 --- a/python/core/qgsmaplayer.sip +++ b/python/core/qgsmaplayer.sip @@ -181,7 +181,7 @@ public: void removeCustomProperty( const QString& key ); /** Read the symbology for the current layer from the Dom node supplied. - * @param QDomNode node that will contain the symbology definition for this layer. + * @param node node that will contain the symbology definition for this layer. * @param errorMessage reference to string that will be updated with any error messages * @return true in case of success. */ @@ -244,10 +244,19 @@ public: /** A convenience function to capitalise the layer name */ static QString capitaliseLayerName(const QString name); - /** Retrieve the default style for this layer if one + /** Retrieve the style URI for this layer + * (either as a .qml file on disk or as a + * record in the users style table in their personal qgis.db) + * @return a QString withe the style file name + * @see also loadNamedStyle () and saveNamedStyle (); + * @note This method was added in QGIS 1.8 + */ + virtual QString styleURI( ); + + /** Retrieve the default style for this layer if one * exists (either as a .qml file on disk or as a * record in the users style table in their personal qgis.db) - * @param a reference to a flag that will be set to false if + * @param theResultFlag a reference to a flag that will be set to false if * we did not manage to load the default style. * @return a QString with any status messages * @see also loadNamedStyle (); @@ -257,12 +266,12 @@ public: /** Retrieve a named style for this layer if one * exists (either as a .qml file on disk or as a * record in the users style table in their personal qgis.db) - * @param QString theURI - the file name or other URI for the + * @param theURI - the file name or other URI for the * style file. First an attempt will be made to see if this * is a file and load that, if that fails the qgis.db styles * table will be consulted to see if there is a style who's * key matches the URI. - * @param a reference to a flag that will be set to false if + * @param theResultFlag a reference to a flag that will be set to false if * we did not manage to load the default style. * @return a QString with any status messages * @see also loadDefaultStyle (); @@ -274,7 +283,7 @@ public: /** Save the properties of this layer as the default style * (either as a .qml file on disk or as a * record in the users style table in their personal qgis.db) - * @param a reference to a flag that will be set to false if + * @param theResultFlag a reference to a flag that will be set to false if * we did not manage to save the default style. * @return a QString with any status messages * @see also loadNamedStyle () and saveNamedStyle() @@ -284,12 +293,12 @@ public: /** Save the properties of this layer as a named style * (either as a .qml file on disk or as a * record in the users style table in their personal qgis.db) - * @param QString theURI - the file name or other URI for the + * @param theURI - the file name or other URI for the * style file. First an attempt will be made to see if this * is a file and save to that, if that fails the qgis.db styles * table will be used to create a style entry who's * key matches the URI. - * @param a reference to a flag that will be set to false if + * @param theResultFlag a reference to a flag that will be set to false if * we did not manage to save the default style. * @return a QString with any status messages * @see also saveDefaultStyle (); diff --git a/src/core/qgsdataitem.cpp b/src/core/qgsdataitem.cpp index 1aa787f45337..05b709ae871b 100644 --- a/src/core/qgsdataitem.cpp +++ b/src/core/qgsdataitem.cpp @@ -469,8 +469,7 @@ QVector QgsDirectoryItem::createChildren( ) QString path = dir.absoluteFilePath( name ); QFileInfo fileInfo( path ); - // vsizip support was added to GDAL/OGR 1.6 but this symbol not available here -// #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1600 + // vsizip support was added to GDAL/OGR 1.6 but GDAL_VERSION_NUM not available here if ( fileInfo.suffix() == "zip" && scanZip ) { QgsDataItem * item = QgsZipItem::itemFromPath( this, path, name ); @@ -480,7 +479,6 @@ QVector QgsDirectoryItem::createChildren( ) continue; } } -// #endif foreach( QLibrary *library, mLibraries ) { @@ -780,13 +778,14 @@ QgsZipItem::~QgsZipItem() QVector QgsZipItem::createChildren( ) { QVector children; - QStringList zipFileList; QString tmpPath; QString childPath; QSettings settings; int scanZipSetting = settings.value( "/qgis/scanZipInBrowser", 1 ).toInt(); + mZipFileList.clear(); + QgsDebugMsg( QString( "path = %1 name= %2 scanZipSetting= %3" ).arg( path() ).arg( name() ).arg( scanZipSetting ) ); // if scanZipBrowser == 0 (No): skip to the next file @@ -804,7 +803,7 @@ QVector QgsZipItem::createChildren( ) } #endif - // if scanZipBrowser == 1 (Passthru): do not scan zip and allow to open directly with /vsigzip/ + // if scanZipBrowser == 1 (Passthru): do not scan zip and allow to open directly with /vsizip/ if ( scanZipSetting == 1 ) { mPath = "/vsizip/" + path(); // should check for extension @@ -827,18 +826,20 @@ QVector QgsZipItem::createChildren( ) tmpPath = zip.getCurrentFileName(); // skip directories (files ending with /) if ( tmpPath.right( 1 ) != "/" ) - zipFileList << tmpPath; + mZipFileList << tmpPath; } + zip.close(); } - zip.close(); if ( zip.getZipError() != UNZ_OK ) { QgsDebugMsg( QString( "Zip error: %1" ).arg( zip.getZipError() ) ); } +#else + QgsDebugMsg( QString( "Cannot open file %1 with quazip - zlib not configured" ).arg( path() ) ); #endif // loop over files inside zip - foreach( QString fileName, zipFileList ) + foreach( QString fileName, mZipFileList ) { QFileInfo info( fileName ); tmpPath = "/vsizip/" + path() + "/" + fileName; @@ -852,7 +853,7 @@ QVector QgsZipItem::createChildren( ) { if ( info.suffix() == "dbf" ) { - if ( zipFileList.indexOf( fileName.left( fileName.count() - 4 ) + ".shp" ) != -1 ) + if ( mZipFileList.indexOf( fileName.left( fileName.count() - 4 ) + ".shp" ) != -1 ) continue; } if ( info.completeSuffix().toLower() == "shp.xml" ) @@ -899,8 +900,9 @@ QgsDataItem* QgsZipItem::itemFromPath( QgsDataItem* parent, QString path, QStrin QSettings settings; int scanZipSetting = settings.value( "/qgis/scanZipInBrowser", 1 ).toInt(); + QString vsizipPath = path; + int zipFileCount = 0; QFileInfo fileInfo( path ); - QString tmpPath = path; QgsZipItem * zipItem = 0; QgsDebugMsg( QString( "path = %1 name= %2 scanZipSetting= %3" ).arg( path ).arg( name ).arg( scanZipSetting ) ); @@ -910,10 +912,10 @@ QgsDataItem* QgsZipItem::itemFromPath( QgsDataItem* parent, QString path, QStrin { return 0; } - // if scanZipBrowser == 1 (Passthru): do not scan zip and allow to open directly with /vsigzip/ + // if scanZipBrowser == 1 (Passthru): do not scan zip and allow to open directly with /vsizip/ else if ( scanZipSetting == 1 ) { - tmpPath = "/vsizip/" + path; + vsizipPath = "/vsizip/" + path; zipItem = 0; } else @@ -935,16 +937,17 @@ QgsDataItem* QgsZipItem::itemFromPath( QgsDataItem* parent, QString path, QStrin QgsDebugMsg( "returning zipItem" ); return zipItem; } -// if 1 or 0 child found, create a data item using the full path given by QgsZipItem +// if 1 or 0 child found, create a single data item using the normal path or the full path given by QgsZipItem else { if ( zipItem ) { - tmpPath = zipItem->path(); + vsizipPath = zipItem->path(); + zipFileCount = zipItem->getZipFileList().count(); delete zipItem; } - QgsDebugMsg( QString( "will try to create a normal dataItem from path= %2" ).arg( tmpPath ) ); + QgsDebugMsg( QString( "will try to create a normal dataItem from path= %2 or %3" ).arg( path ).arg( vsizipPath ) ); // try to open using registered providers (gdal and ogr) for ( int i = 0; i < mProviderNames.size(); i++ ) @@ -952,7 +955,17 @@ QgsDataItem* QgsZipItem::itemFromPath( QgsDataItem* parent, QString path, QStrin dataItem_t *dataItem = mDataItemPtr[i]; if ( dataItem ) { - QgsDataItem *item = dataItem( tmpPath, parent ); + QgsDataItem *item = 0; + // try first with normal path (Passthru) + // this is to simplify .qml handling, and without this some tests will fail + // (e.g. testZipItemVectorTransparency(), second test) + if (( scanZipSetting == 1 ) || + ( mProviderNames[i] == "ogr" ) || + ( mProviderNames[i] == "gdal" && zipFileCount == 1 ) ) + item = dataItem( path, parent ); + // try with /vsizip/ + if ( ! item ) + item = dataItem( vsizipPath, parent ); if ( item ) return item; } diff --git a/src/core/qgsdataitem.h b/src/core/qgsdataitem.h index c69058480c31..d441e1a0e9d7 100644 --- a/src/core/qgsdataitem.h +++ b/src/core/qgsdataitem.h @@ -289,6 +289,10 @@ class CORE_EXPORT QgsFavouritesItem : public QgsDataCollectionItem class CORE_EXPORT QgsZipItem : public QgsDataCollectionItem { Q_OBJECT + + protected: + QStringList mZipFileList; + public: QgsZipItem( QgsDataItem* parent, QString name, QString path ); ~QgsZipItem(); @@ -302,6 +306,9 @@ class CORE_EXPORT QgsZipItem : public QgsDataCollectionItem static QgsDataItem* itemFromPath( QgsDataItem* parent, QString path, QString name ); static const QIcon &iconZip(); + + const QStringList & getZipFileList() const { return mZipFileList; } + }; #endif // QGSDATAITEM_H diff --git a/src/core/qgsmaplayer.cpp b/src/core/qgsmaplayer.cpp index 3db1cea8d6a6..befe879c7089 100644 --- a/src/core/qgsmaplayer.cpp +++ b/src/core/qgsmaplayer.cpp @@ -549,25 +549,57 @@ QString QgsMapLayer::capitaliseLayerName( const QString name ) return layerName; } -QString QgsMapLayer::loadDefaultStyle( bool & theResultFlag ) +QString QgsMapLayer::styleURI( ) { QString myURI = publicSource(); + + // if file is using the /vsizip/ or /vsigzip/ mechanism, cleanup the name + if ( myURI.left( 9 ) == "/vsigzip/" ) + { + myURI.remove( 1, 9 ); + } + else if ( myURI.left( 8 ) == "/vsizip/" && myURI.right( 4 ) == ".zip" ) + { + // ideally we should look for .qml file inside zip file + myURI.remove( 1, 8 ); + } + QFileInfo myFileInfo( myURI ); QString key; + if ( myFileInfo.exists() ) { + // if file is using the /vsizip/ or /vsigzip/ mechanism, cleanup the name + if ( myURI.right( 3 ) == ".gz" ) + { + myURI.chop( 3 ); + myFileInfo.setFile( myURI ); + } + else if ( myURI.right( 4 ) == ".zip" ) + { + myURI.chop( 4 ); + myFileInfo.setFile( myURI ); + } // get the file name for our .qml style file key = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".qml"; } else { - key = myURI; + key = publicSource(); } - return loadNamedStyle( key, theResultFlag ); + + return key; +} + +QString QgsMapLayer::loadDefaultStyle( bool & theResultFlag ) +{ + return loadNamedStyle( styleURI(), theResultFlag ); } bool QgsMapLayer::loadNamedStyleFromDb( const QString db, const QString theURI, QString &qml ) { + QgsDebugMsg( QString( "db = %1 uri = %2" ).arg( db ).arg( theURI ) ); + bool theResultFlag = false; // read from database @@ -610,6 +642,8 @@ bool QgsMapLayer::loadNamedStyleFromDb( const QString db, const QString theURI, QString QgsMapLayer::loadNamedStyle( const QString theURI, bool &theResultFlag ) { + QgsDebugMsg( QString( "uri = %1 myURI = %2" ).arg( theURI ).arg( publicSource() ) ); + theResultFlag = false; QDomDocument myDocument( "qgis" ); @@ -692,7 +726,7 @@ QString QgsMapLayer::loadNamedStyle( const QString theURI, bool &theResultFlag ) QString QgsMapLayer::saveDefaultStyle( bool & theResultFlag ) { - return saveNamedStyle( publicSource(), theResultFlag ); + return saveNamedStyle( styleURI(), theResultFlag ); } QString QgsMapLayer::saveNamedStyle( const QString theURI, bool & theResultFlag ) diff --git a/src/core/qgsmaplayer.h b/src/core/qgsmaplayer.h index eb164559ae35..ffa4191856e8 100644 --- a/src/core/qgsmaplayer.h +++ b/src/core/qgsmaplayer.h @@ -237,6 +237,15 @@ class CORE_EXPORT QgsMapLayer : public QObject /** A convenience function to capitalise the layer name */ static QString capitaliseLayerName( const QString name ); + /** Retrieve the style URI for this layer + * (either as a .qml file on disk or as a + * record in the users style table in their personal qgis.db) + * @return a QString withe the style file name + * @see also loadNamedStyle () and saveNamedStyle (); + * @note This method was added in QGIS 1.8 + */ + virtual QString styleURI( ); + /** Retrieve the default style for this layer if one * exists (either as a .qml file on disk or as a * record in the users style table in their personal qgis.db) diff --git a/src/core/qgsvectorlayer.cpp b/src/core/qgsvectorlayer.cpp index 24c5b85d7e54..974dc0fae28c 100644 --- a/src/core/qgsvectorlayer.cpp +++ b/src/core/qgsvectorlayer.cpp @@ -2844,6 +2844,13 @@ bool QgsVectorLayer::setDataProvider( QString const & provider ) // make sure that the "observer" has been removed from URI to avoid crashes mDataSource = mDataProvider->dataSourceUri(); } + else if ( provider == "ogr" ) + { + // make sure that the /vsigzip or /vsizip is added to uri, if applicable + mDataSource = mDataProvider->dataSourceUri(); + if ( mDataSource.right( 10 ) == "|layerid=0" ) + mDataSource.chop( 10 ); + } // label mLabel = new QgsLabel( mDataProvider->fields() ); diff --git a/src/core/raster/qgsrasterlayer.cpp b/src/core/raster/qgsrasterlayer.cpp index 1e422a0ae360..669b9fc79558 100644 --- a/src/core/raster/qgsrasterlayer.cpp +++ b/src/core/raster/qgsrasterlayer.cpp @@ -155,6 +155,14 @@ QgsRasterLayer::QgsRasterLayer( int dummy, bool loadDefaultStyleFlag = false ; // ??? setDataProvider( providerKey, layers, styles, format, crs, loadDefaultStyleFlag ); + // load default style if provider is gdal and if no style was given + // this should be an argument like in the other constructor + if ( mValid && providerKey == "gdal" && layers.isEmpty() && styles.isEmpty() ) + { + bool defaultLoadedFlag = false; + loadDefaultStyle( defaultLoadedFlag ); + } + // Default for the popup menu // TODO: popMenu = 0; @@ -2270,6 +2278,12 @@ void QgsRasterLayer::setDataProvider( QString const & provider, return; } + if ( provider == "gdal" ) + { + // make sure that the /vsigzip or /vsizip is added to uri, if applicable + mDataSource = mDataProvider->dataSourceUri(); + } + mDataProvider->addLayers( layers, styles ); mDataProvider->setImageEncoding( format ); mDataProvider->setImageCrs( theCrs ); diff --git a/src/providers/gdal/qgsgdaldataitems.cpp b/src/providers/gdal/qgsgdaldataitems.cpp index aa627481da64..3d3843b9d7f1 100644 --- a/src/providers/gdal/qgsgdaldataitems.cpp +++ b/src/providers/gdal/qgsgdaldataitems.cpp @@ -105,20 +105,29 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem ) if ( thePath.isEmpty() ) return 0; - QgsDebugMsg( "thePath= " + thePath ); - - QString uri = thePath; - QFileInfo info( thePath ); + // zip settings + info QSettings settings; - //extract basename with extension - QString name = info.fileName(); int scanItemsSetting = settings.value( "/qgis/scanItemsInBrowser", 0 ).toInt(); int scanZipSetting = settings.value( "/qgis/scanZipInBrowser", 1 ).toInt(); + bool is_vsizip = ( thePath.startsWith( "/vsizip/" ) || + thePath.endsWith( ".zip", Qt::CaseInsensitive ) ); + bool is_vsigzip = ( thePath.startsWith( "/vsigzip/" ) || + thePath.endsWith( ".gz", Qt::CaseInsensitive ) ); + + // get suffix, removing .gz if present + QString tmpPath = thePath; //path used for testing, not for layer creation + if ( is_vsigzip ) + tmpPath.chop( 3 ); + QFileInfo info( tmpPath ); + QString suffix = info.suffix().toLower(); + // extract basename with extension + info.setFile( thePath ); + QString name = info.fileName(); + + QgsDebugMsg( "thePath= " + thePath + " tmpPath= " + tmpPath ); - // allow normal files or VSIFILE items to pass - if ( !info.isFile() && - !thePath.startsWith( "/vsizip/" ) && - !thePath.startsWith( "/vsigzip/" ) ) + // allow only normal files or VSIFILE items to continue + if ( !info.isFile() && !is_vsizip && !is_vsigzip ) return 0; // get supported extensions @@ -132,7 +141,7 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem ) // skip *.aux.xml files (GDAL auxilary metadata files) // unless that extension is in the list (*.xml might be though) if ( thePath.endsWith( ".aux.xml", Qt::CaseInsensitive ) && - ! extensions.contains( "aux.xml" ) ) + !extensions.contains( "aux.xml" ) ) return 0; // skip .tar.gz files @@ -156,48 +165,43 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem ) return 0; } - // vsifile : depending on options we should just add the item without testing - if ( thePath.startsWith( "/vsizip/" ) ) + // add /vsizip/ or /vsigzip/ to path if file extension is .zip or .gz + if ( is_vsigzip ) { - // if this is a /vsigzip/path.zip/file_inside_zip change the name + if ( !thePath.startsWith( "/vsigzip/" ) ) + thePath = "/vsigzip/" + thePath; + } + else if ( is_vsizip ) + { + if ( !thePath.startsWith( "/vsizip/" ) ) + thePath = "/vsizip/" + thePath; + // if this is a /vsigzip/path_to_zip.zip/file_inside_zip remove the full path from the name if ( thePath != "/vsizip/" + parentItem->path() ) { name = thePath; name = name.replace( "/vsizip/" + parentItem->path() + "/", "" ); } - - // if setting = 2 (Basic scan), return an item without testing - if ( scanZipSetting == 2 ) - { - QStringList sublayers; - QgsDebugMsg( QString( "adding item name=%1 thePath=%2 uri=%3" ).arg( name ).arg( thePath ).arg( uri ) ); - QgsLayerItem * item = new QgsGdalLayerItem( parentItem, name, thePath, thePath, &sublayers ); - if ( item ) - return item; - } } - // if scan items == "Check extension", add item here without trying to open - if ( scanItemsSetting == 1 ) + // if setting = 2 (Basic scan), return a /vsizip/ item without testing + if ( is_vsizip && scanZipSetting == 2 ) { QStringList sublayers; - QgsDebugMsg( QString( "adding item name=%1 thePath=%2 uri=%3" ).arg( name ).arg( thePath ).arg( uri ) ); + QgsDebugMsg( QString( "adding item name=%1 thePath=%2" ).arg( name ).arg( thePath ) ); QgsLayerItem * item = new QgsGdalLayerItem( parentItem, name, thePath, thePath, &sublayers ); if ( item ) return item; } - - // try to open using VSIFileHandler - if ( thePath.endsWith( ".zip", Qt::CaseInsensitive ) ) - { - if ( !thePath.startsWith( "/vsizip/" ) ) - thePath = "/vsizip/" + thePath; - } - else if ( thePath.endsWith( ".gz", Qt::CaseInsensitive ) ) + // if scan items == "Check extension", add item here without trying to open + // unless item is /vsizip + if ( scanItemsSetting == 1 && !is_vsizip ) { - if ( !thePath.startsWith( "/vsigzip/" ) ) - thePath = "/vsigzip/" + thePath; + QStringList sublayers; + QgsDebugMsg( QString( "adding item name=%1 thePath=%2" ).arg( name ).arg( thePath ) ); + QgsLayerItem * item = new QgsGdalLayerItem( parentItem, name, thePath, thePath, &sublayers ); + if ( item ) + return item; } // test that file is valid with GDAL diff --git a/src/providers/gdal/qgsgdalprovider.cpp b/src/providers/gdal/qgsgdalprovider.cpp index a6f80ebd8f4f..4c370baf4e1e 100644 --- a/src/providers/gdal/qgsgdalprovider.cpp +++ b/src/providers/gdal/qgsgdalprovider.cpp @@ -1872,13 +1872,17 @@ QGISEXTERN bool isValidRasterFileName( QString const & theFileNameQString, QStri if ( fileName.endsWith( ".zip", Qt::CaseInsensitive ) ) { if ( !fileName.startsWith( "/vsizip/" ) ) + { fileName = "/vsizip/" + fileName; + } QgsDebugMsg( QString( "Trying /vsizip syntax, fileName= %1" ).arg( fileName ) ); } if ( fileName.endsWith( ".gz", Qt::CaseInsensitive ) ) { if ( !fileName.startsWith( "/vsigzip/" ) ) + { fileName = "/vsigzip/" + fileName; + } QgsDebugMsg( QString( "Trying /vsigzip syntax, fileName= %1" ).arg( fileName ) ); } diff --git a/src/providers/ogr/qgsogrdataitems.cpp b/src/providers/ogr/qgsogrdataitems.cpp index c7c3b9760d93..de040b5d3f12 100644 --- a/src/providers/ogr/qgsogrdataitems.cpp +++ b/src/providers/ogr/qgsogrdataitems.cpp @@ -228,31 +228,42 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem ) QgsDebugMsg( "thePath: " + thePath ); - QFileInfo info( thePath ); - QString name = info.fileName(); + // zip settings + info QSettings settings; int scanItemsSetting = settings.value( "/qgis/scanItemsInBrowser", 0 ).toInt(); int scanZipSetting = settings.value( "/qgis/scanZipInBrowser", 1 ).toInt(); + bool is_vsizip = ( thePath.startsWith( "/vsizip/" ) || + thePath.endsWith( ".zip", Qt::CaseInsensitive ) ); + bool is_vsigzip = ( thePath.startsWith( "/vsigzip/" ) || + thePath.endsWith( ".gz", Qt::CaseInsensitive ) ); + + // get suffix, removing .gz if present + QString tmpPath = thePath; //path used for testing, not for layer creation + if ( is_vsigzip ) + tmpPath.chop( 3 ); + QFileInfo info( tmpPath ); + QString suffix = info.suffix().toLower(); + // extract basename with extension + info.setFile( thePath ); + QString name = info.fileName(); - // allow normal files or VSIFILE items to pass - if ( !info.isFile() && - !thePath.startsWith( "/vsizip/" ) && - !thePath.startsWith( "/vsigzip/" ) ) + // allow only normal files or VSIFILE items to continue + if ( !info.isFile() && !is_vsizip && !is_vsigzip ) return 0; QStringList myExtensions = fileExtensions(); // skip *.aux.xml files (GDAL auxilary metadata files) and .shp.xml files (ESRI metadata) // unless that extension is in the list (*.xml might be though) - if ( thePath.right( 8 ).toLower() == ".aux.xml" && - myExtensions.indexOf( "aux.xml" ) < 0 ) + if ( thePath.endsWith( ".aux.xml", Qt::CaseInsensitive ) && + !myExtensions.contains( "aux.xml" ) ) return 0; - if ( thePath.right( 8 ).toLower() == ".shp.xml" && - myExtensions.indexOf( "shp.xml" ) < 0 ) + if ( thePath.endsWith( ".shp.xml", Qt::CaseInsensitive ) && + !myExtensions.contains( "shp.xml" ) ) return 0; // skip .tar.gz files - if ( thePath.right( 7 ) == ".tar.gz" ) + if ( thePath.endsWith( ".tar.gz", Qt::CaseInsensitive ) ) return 0; // We have to filter by extensions, otherwise e.g. all Shapefile files are displayed @@ -281,43 +292,41 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem ) return 0; } - // vsifile : depending on options we should just add the item without testing - if ( thePath.startsWith( "/vsizip/" ) ) + // add /vsizip/ or /vsigzip/ to path if file extension is .zip or .gz + if ( is_vsigzip ) + { + if ( !thePath.startsWith( "/vsigzip/" ) ) + thePath = "/vsigzip/" + thePath; + } + else if ( is_vsizip ) { - // if this is a /vsigzip/path.zip/file_inside_zip change the name + if ( !thePath.startsWith( "/vsizip/" ) ) + thePath = "/vsizip/" + thePath; + // if this is a /vsigzip/path_to_zip.zip/file_inside_zip remove the full path from the name if ( thePath != "/vsizip/" + parentItem->path() ) { name = thePath; name = name.replace( "/vsizip/" + parentItem->path() + "/", "" ); } - - // if setting== 2 (Basic scan), return an item without testing - if ( scanZipSetting == 2 ) - { - QgsLayerItem * item = new QgsOgrLayerItem( parentItem, name, thePath, thePath, QgsLayerItem::Vector ); - if ( item ) - return item; - } } - // if scan items == "Check extension", add item here without trying to open - if ( scanItemsSetting == 1 ) + // if setting = 2 (Basic scan), return a /vsizip/ item without testing + if ( is_vsizip && scanZipSetting == 2 ) { + QStringList sublayers; + QgsDebugMsg( QString( "adding item name=%1 thePath=%2" ).arg( name ).arg( thePath ) ); QgsLayerItem * item = new QgsOgrLayerItem( parentItem, name, thePath, thePath, QgsLayerItem::Vector ); if ( item ) return item; } - // try to open using VSIFileHandler - if ( thePath.endsWith( ".zip", Qt::CaseInsensitive ) ) - { - if ( !thePath.startsWith( "/vsizip/" ) ) - thePath = "/vsizip/" + thePath; - } - else if ( thePath.endsWith( ".gz", Qt::CaseInsensitive ) ) + // if scan items == "Check extension", add item here without trying to open + // unless item is /vsizip + if ( scanItemsSetting == 1 && !is_vsizip && !is_vsigzip ) { - if ( !thePath.startsWith( "/vsigzip/" ) ) - thePath = "/vsigzip/" + thePath; + QgsLayerItem * item = new QgsOgrLayerItem( parentItem, name, thePath, thePath, QgsLayerItem::Vector ); + if ( item ) + return item; } // test that file is valid with OGR diff --git a/src/providers/ogr/qgsogrprovider.cpp b/src/providers/ogr/qgsogrprovider.cpp index 3c0f99dfe499..072a3acbf4e3 100644 --- a/src/providers/ogr/qgsogrprovider.cpp +++ b/src/providers/ogr/qgsogrprovider.cpp @@ -270,13 +270,19 @@ QgsOgrProvider::QgsOgrProvider( QString const & uri ) // cannot be interleaved, so for now just use read-only. openReadOnly = true; if ( !mFilePath.startsWith( "/vsizip/" ) ) + { mFilePath = "/vsizip/" + mFilePath; + setDataSourceUri( mFilePath ); + } QgsDebugMsg( QString( "Trying /vsizip syntax, mFilePath= %1" ).arg( mFilePath ) ); } else if ( mFilePath.endsWith( ".gz", Qt::CaseInsensitive ) ) { if ( !mFilePath.startsWith( "/vsigzip/" ) ) + { mFilePath = "/vsigzip/" + mFilePath; + setDataSourceUri( mFilePath ); + } QgsDebugMsg( QString( "Trying /vsigzip syntax, mFilePath= %1" ).arg( mFilePath ) ); } diff --git a/tests/src/core/testziplayer.cpp b/tests/src/core/testziplayer.cpp index 094a89487808..21fbf7a3491b 100644 --- a/tests/src/core/testziplayer.cpp +++ b/tests/src/core/testziplayer.cpp @@ -2,8 +2,8 @@ testziplayer.cpp -------------------------------------- Date : Sun Sep 16 12:22:23 AKDT 2007 - Copyright : (C) 2012 Tim Sutton - Email : tim@linfiniti.com + Copyright : (C) 2012 Etienne Tourigny and Tim Sutton + Email : etourigny.dev@gmail.com *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * @@ -20,9 +20,14 @@ #include //qgis includes... -#include #include #include +#include +#include +#include +#include "qgsconfig.h" +#include +#include #include @@ -33,33 +38,315 @@ class TestZipLayer: public QObject { Q_OBJECT; + private: + + QString mDataDir; + QSettings mSettings; + int mMaxScanZipSetting; + int mScanZipSetting; + + // get map layer using Passthru + QgsMapLayer * getLayer( QString myPath, QString myName, QString myProviderKey ); + bool testZipItemPassthru( QString myFileName, QString myProviderKey ); + // get map layer using QgsZipItem (only 1 child) + QgsMapLayer * getZipLayer( QString myPath, QString myName ); + // test item(s) in zip item (supply name or test all) + bool testZipItem( QString myFileName, QString myChildName ); + // get layer transparency to test for .qml loading + int getLayerTransparency( QString myFileName, QString myProviderKey, int myScanZipSetting = 1 ); + private slots: - void testZipLayer() + // init / cleanup + void initTestCase();// will be called before the first testfunction is executed. + void cleanupTestCase();// will be called after the last testfunction was executed. + void init() {};// will be called before each testfunction is executed. + void cleanup() {};// will be called after every testfunction. + + // tests + // test for .zip and .gz files using all options + void testPassthruVectorZip(); + void testPassthruVectorGzip(); + void testPassthruRasterZip(); + void testPassthruRasterGzip(); + // test both "Basic Scan" and "Full scan" for .zip files + void testZipItemRaster(); + void testZipItemVector(); + void testZipItemAll(); + // test that styles are loaded from .qml files outside zip files + void testZipItemVectorTransparency(); + void testGipItemVectorTransparency(); + void testZipItemRasterTransparency(); + void testGZipItemRasterTransparency(); +}; + + +QgsMapLayer *TestZipLayer::getLayer( QString myPath, QString myName, QString myProviderKey ) +{ + if ( myName == "" ) + { + QFileInfo myFileInfo( myPath ); + myName = myFileInfo.completeBaseName(); + } + QgsMapLayer *myLayer = NULL; + + if ( myProviderKey == "ogr" ) + { + myLayer = new QgsVectorLayer( myPath, myName, "ogr" ); + } + else if ( myProviderKey == "gdal" ) + { + myLayer = new QgsRasterLayer( myPath, myName, "gdal" ); + } + // item should not have other provider key, but if it does will return NULL + + return myLayer; +} + +QgsMapLayer *TestZipLayer::getZipLayer( QString myPath, QString myName ) +{ + QgsMapLayer *myLayer = NULL; + QgsDirectoryItem *dirItem = new QgsDirectoryItem( NULL, "/", "" ); + QgsDataItem* myItem = QgsZipItem::itemFromPath( dirItem, myPath, myName ); + if ( myItem ) + { + QgsLayerItem *layerItem = dynamic_cast( myItem ); + if ( layerItem ) + myLayer = getLayer( layerItem->path(), layerItem->name(), layerItem->providerKey() ); + } + delete dirItem; + return myLayer; +} + +bool TestZipLayer::testZipItemPassthru( QString myFileName, QString myProviderKey ) +{ + QgsMapLayer * myLayer = getLayer( myFileName, "", myProviderKey ); + bool ok = myLayer && myLayer->isValid(); + if ( myLayer ) + delete myLayer; + return ok; +} + +bool TestZipLayer::testZipItem( QString myFileName, QString myChildName = "" ) +{ + QgsDebugMsg( QString( "\n=======================================\nfile = %1 name = %2" ).arg( myFileName ).arg( myChildName ) ); + QFileInfo myFileInfo( myFileName ); + QgsZipItem *myZipItem = new QgsZipItem( NULL, myFileInfo.fileName(), myFileName ); + myZipItem->populate(); + bool ok = false; + QVector myChildren = myZipItem->children(); + + if ( myChildren.size() > 0 ) + { + QgsDebugMsg( QString( "has %1 items" ).arg( myChildren.size() ) ); + foreach( QgsDataItem* item, myChildren ) { - QgsApplication::init(); - QgsProviderRegistry::instance( QgsApplication::pluginPath() ); - // - //create a point layer that will be used in all tests... - // - QString myPointsFileName( QString( TEST_DATA_DIR ) + QDir::separator() + "points.zip" ); - qDebug() << "GDAL: " << GDAL_RELEASE_NAME; + QgsDebugMsg( QString( "child name=%1" ).arg( item->name() ) ); + QgsLayerItem *layerItem = dynamic_cast( item ); + if ( layerItem ) + { + QgsDebugMsg( QString( "child name=%1 provider=%2 path=%3" ).arg( layerItem->name() ).arg( layerItem->providerKey() ).arg( layerItem->path() ) ); + if ( myChildName == "" || myChildName == item->name() ) + { + QgsMapLayer* layer = getLayer( layerItem->path(), layerItem->name(), layerItem->providerKey() ); + if ( layer != NULL ) + { + // we got a layer, check if it is valid and exit + // if no child name given in argument, then pass to next one (unless current child is invalid) + QgsDebugMsg( QString( "valid: %1" ).arg( layer->isValid() ) ); + ok = layer->isValid(); + delete layer; + if ( ! ok ) + { + QWARN( QString( "Invalid layer %1" ).arg( layerItem->path() ).toLocal8Bit().data() ); + } + if ( myChildName == "" ) + { + if ( ! ok ) + break; + } + else + { + break; + } + } + else + { + QWARN( QString( "Invalid layer %1" ).arg( layerItem->path() ).toLocal8Bit().data() ); + break; + } + } + } + else + { + QWARN( QString( "Invalid layer %1" ).arg( layerItem->path() ).toLocal8Bit().data() ); + break; + } + } + } + delete myZipItem; + return ok; +} + +int TestZipLayer::getLayerTransparency( QString myFileName, QString myProviderKey, int myScanZipSetting ) +{ + int myTransparency = -1; + mSettings.setValue( "/qgis/scanZipInBrowser", myScanZipSetting ); + QgsMapLayer * myLayer = NULL; + if ( myScanZipSetting == 1 ) + myLayer = getLayer( myFileName, "", myProviderKey ); + else + myLayer = getZipLayer( myFileName, "" ); + if ( myLayer && myLayer->isValid() ) + myTransparency = myLayer->getTransparency(); + if ( myLayer ) + delete myLayer; + return myTransparency; +} + + +// slots +void TestZipLayer::initTestCase() +{ + QgsApplication::init(); + QgsProviderRegistry::instance( QgsApplication::pluginPath() ); + // save data dir + mDataDir = QString( TEST_DATA_DIR ) + QDir::separator(); + // set zipSetting to 1 (Passthru) and save current value + mScanZipSetting = mSettings.value( "/qgis/scanZipInBrowser", 1 ).toInt(); + mSettings.setValue( "/qgis/scanZipInBrowser", 1 ); + // max zipSetting value, depending on zlib presence + mMaxScanZipSetting = 1; +#ifdef HAVE_ZLIB + mMaxScanZipSetting = 3; +#endif + +} + +void TestZipLayer::cleanupTestCase() +{ + // restore zipSetting + mSettings.setValue( "/qgis/scanZipInBrowser", mScanZipSetting ); +} + + +void TestZipLayer::testPassthruVectorZip() +{ + QString myFileName = mDataDir + "points2.zip"; + QgsDebugMsg( "GDAL: " + QString( GDAL_RELEASE_NAME ) ); #if GDAL_VERSION_NUM < 1800 - myPointsFileName = "/vsizip/" + myPointsFileName + "/points.shp"; + myFileName = "/vsizip/" + myFileName + "/points.shp"; #endif - qDebug() << "FILE: " << myPointsFileName; - QFileInfo myPointFileInfo( myPointsFileName ); - QgsVectorLayer * mypPointsLayer = new QgsVectorLayer( myPointFileInfo.filePath(), - myPointFileInfo.completeBaseName(), "ogr" ); - QVERIFY( mypPointsLayer->isValid() ); - delete mypPointsLayer; - } + QgsDebugMsg( "FILE: " + QString( myFileName ) ); + for ( int i = 1 ; i <= mMaxScanZipSetting ; i++ ) + { + mSettings.setValue( "/qgis/scanZipInBrowser", i ); + QVERIFY( testZipItemPassthru( myFileName, "ogr" ) ); + } +} -}; +void TestZipLayer::testPassthruVectorGzip() +{ + for ( int i = 1 ; i <= mMaxScanZipSetting ; i++ ) + { + mSettings.setValue( "/qgis/scanZipInBrowser", i ); + QVERIFY( testZipItemPassthru( mDataDir + "points3.geojson.gz", "ogr" ) ); + } +} -QTEST_MAIN( TestZipLayer ) -#include "moc_testziplayer.cxx" +void TestZipLayer::testPassthruRasterZip() +{ + for ( int i = 1 ; i <= mMaxScanZipSetting ; i++ ) + { + mSettings.setValue( "/qgis/scanZipInBrowser", i ); + QVERIFY( testZipItemPassthru( mDataDir + "landsat_b1.zip", "gdal" ) ); + } +} +void TestZipLayer::testPassthruRasterGzip() +{ + for ( int i = 1 ; i <= mMaxScanZipSetting ; i++ ) + { + mSettings.setValue( "/qgis/scanZipInBrowser", i ); + QVERIFY( testZipItemPassthru( mDataDir + "landsat_b1.tif.gz", "gdal" ) ); + } +} +void TestZipLayer::testZipItemRaster() +{ +#ifndef HAVE_ZLIB + QSKIP( "This test requires ZLIB", SkipSingle ); +#endif + for ( int i = 2 ; i <= mMaxScanZipSetting ; i++ ) + { + mSettings.setValue( "/qgis/scanZipInBrowser", i ); + QVERIFY( testZipItem( mDataDir + "testzip.zip", "landsat_b1.tif" ) ); + } +} +void TestZipLayer::testZipItemVector() +{ +#ifndef HAVE_ZLIB + QSKIP( "This test requires ZLIB", SkipSingle ); +#endif + for ( int i = 2 ; i <= mMaxScanZipSetting ; i++ ) + { + mSettings.setValue( "/qgis/scanZipInBrowser", i ); + QVERIFY( testZipItem( mDataDir + "testzip.zip", "points.shp" ) ); + } +} + +void TestZipLayer::testZipItemAll() +{ +#ifndef HAVE_ZLIB + QSKIP( "This test requires ZLIB", SkipSingle ); +#endif + // test file contains invalid items (tmp1.tif, tmp1.txt and tmp1.xml) + // test for all items inside zip, using zipSetting 3 (Full Scan) which will ignore invalid items + // using zipSetting 2 (Basic Scan) would raise errors, because QgsZipItem would not test for valid items + // and return child names of the invalid items + mSettings.setValue( "/qgis/scanZipInBrowser", 3 ); + QVERIFY( testZipItem( mDataDir + "testzip.zip", "" ) ); +} + + +void TestZipLayer::testZipItemVectorTransparency() +{ + int myTarget = 250; + int myTransparency = getLayerTransparency( mDataDir + "points2.zip", "ogr", 1 ); + QVERIFY2(( myTransparency == myTarget ), QString( "Transparency is %1, should be %2" ).arg( myTransparency ).arg( myTarget ).toLocal8Bit().data() ); + myTransparency = getLayerTransparency( mDataDir + "points2.zip", "ogr", 2 ); + QVERIFY2(( myTransparency == myTarget ), QString( "Transparency is %1, should be %2" ).arg( myTransparency ).arg( myTarget ).toLocal8Bit().data() ); +} + +void TestZipLayer::testGipItemVectorTransparency() +{ + int myTarget = 250; + int myTransparency = getLayerTransparency( mDataDir + "points3.geojson.gz", "ogr", 1 ); + QVERIFY2(( myTransparency == myTarget ), QString( "Transparency is %1, should be %2" ).arg( myTransparency ).arg( myTarget ).toLocal8Bit().data() ); + myTransparency = getLayerTransparency( mDataDir + "points3.geojson.gz", "ogr", 2 ); + QVERIFY2(( myTransparency == myTarget ), QString( "Transparency is %1, should be %2" ).arg( myTransparency ).arg( myTarget ).toLocal8Bit().data() ); +} + +void TestZipLayer::testZipItemRasterTransparency() +{ + int myTarget = 250; + int myTransparency = getLayerTransparency( mDataDir + "landsat_b1.zip", "gdal", 1 ); + QVERIFY2(( myTransparency == myTarget ), QString( "Transparency is %1, should be %2" ).arg( myTransparency ).arg( myTarget ).toLocal8Bit().data() ); + myTransparency = getLayerTransparency( mDataDir + "landsat_b1.zip", "gdal", 2 ); + QVERIFY2(( myTransparency == myTarget ), QString( "Transparency is %1, should be %2" ).arg( myTransparency ).arg( myTarget ).toLocal8Bit().data() ); +} + +void TestZipLayer::testGZipItemRasterTransparency() +{ + int myTarget = 250; + int myTransparency = getLayerTransparency( mDataDir + "landsat_b1.tif.gz", "gdal", 1 ); + QVERIFY2(( myTransparency == myTarget ), QString( "Transparency is %1, should be %2" ).arg( myTransparency ).arg( myTarget ).toLocal8Bit().data() ); + myTransparency = getLayerTransparency( mDataDir + "landsat_b1.tif.gz", "gdal", 2 ); + QVERIFY2(( myTransparency == myTarget ), QString( "Transparency is %1, should be %2" ).arg( myTransparency ).arg( myTarget ).toLocal8Bit().data() ); +} + + +QTEST_MAIN( TestZipLayer ) +#include "moc_testziplayer.cxx" diff --git a/tests/testdata/landsat_b1.qml b/tests/testdata/landsat_b1.qml new file mode 100644 index 000000000000..ca6d53485a0f --- /dev/null +++ b/tests/testdata/landsat_b1.qml @@ -0,0 +1,32 @@ + + + 250 + + SingleBandGray + UndefinedShader + + Not Set + Not Set + Not Set + Band 1 + 0 + + + + + StretchAndClipToMinimumMaximum + + + 122 + 130 + + + -32768.000000 + + + + + + + + diff --git a/tests/testdata/landsat_b1.tif.gz b/tests/testdata/landsat_b1.tif.gz new file mode 100644 index 000000000000..abbf94102845 Binary files /dev/null and b/tests/testdata/landsat_b1.tif.gz differ diff --git a/tests/testdata/landsat_b1.tif.qml b/tests/testdata/landsat_b1.tif.qml new file mode 100644 index 000000000000..4f99453a1122 --- /dev/null +++ b/tests/testdata/landsat_b1.tif.qml @@ -0,0 +1,32 @@ + + + 248 + + SingleBandGray + UndefinedShader + + + + + Band 1 + 0 + + + + + StretchAndClipToMinimumMaximum + + + 122 + 130 + + + -32768.000000 + + + + + + + + diff --git a/tests/testdata/landsat_b1.zip b/tests/testdata/landsat_b1.zip new file mode 100644 index 000000000000..b341559556a5 Binary files /dev/null and b/tests/testdata/landsat_b1.zip differ diff --git a/tests/testdata/points.zip b/tests/testdata/points.zip deleted file mode 100644 index 006239784a43..000000000000 Binary files a/tests/testdata/points.zip and /dev/null differ diff --git a/tests/testdata/points2.qml b/tests/testdata/points2.qml new file mode 100644 index 000000000000..2771aee26a4a --- /dev/null +++ b/tests/testdata/points2.qml @@ -0,0 +1,93 @@ + + + 250 + Importance + Heading + Class + + Class + + B52 + + + svg:/gpsicons/plane.svg + 11 + pixels + Importance + Importance + + + SolidLine + 1 + + SolidPattern + + + + Biplane + + + svg:/gpsicons/plane_orange.svg + 18 + pixels + Heading + Importance + + + SolidLine + 1 + + SolidPattern + + + + Jet + + + svg:/gpsicons/plane.svg + 11 + pixels + Heading + Importance + + + SolidLine + 1 + + SolidPattern + + + + + Class + + + + + + + + + + + + + diff --git a/tests/testdata/points2.zip b/tests/testdata/points2.zip new file mode 100644 index 000000000000..73505ddbd5e4 Binary files /dev/null and b/tests/testdata/points2.zip differ diff --git a/tests/testdata/points3.geojson.gz b/tests/testdata/points3.geojson.gz new file mode 100644 index 000000000000..b8109bfb7d0c Binary files /dev/null and b/tests/testdata/points3.geojson.gz differ diff --git a/tests/testdata/points3.qml b/tests/testdata/points3.qml new file mode 100644 index 000000000000..2771aee26a4a --- /dev/null +++ b/tests/testdata/points3.qml @@ -0,0 +1,93 @@ + + + 250 + Importance + Heading + Class + + Class + + B52 + + + svg:/gpsicons/plane.svg + 11 + pixels + Importance + Importance + + + SolidLine + 1 + + SolidPattern + + + + Biplane + + + svg:/gpsicons/plane_orange.svg + 18 + pixels + Heading + Importance + + + SolidLine + 1 + + SolidPattern + + + + Jet + + + svg:/gpsicons/plane.svg + 11 + pixels + Heading + Importance + + + SolidLine + 1 + + SolidPattern + + + + + Class + + + + + + + + + + + + + diff --git a/tests/testdata/testzip.zip b/tests/testdata/testzip.zip new file mode 100644 index 000000000000..6f8572b120f7 Binary files /dev/null and b/tests/testdata/testzip.zip differ