add support for reading datasets inside zip file in browser using quazip

This commit is contained in:
Etienne Tourigny 2012-03-24 18:08:25 -03:00
parent 9c0cfe941f
commit 90108d81d0
10 changed files with 500 additions and 93 deletions

View File

@ -193,6 +193,7 @@
<file>themes/default/mIconWms.png</file>
<file>themes/default/mIconWmsLayer.png</file>
<file>themes/default/mIconWarn.png</file>
<file>themes/default/mIconZip.png</file>
<file>themes/default/mMapserverExport.png</file>
<file>themes/default/plugin.png</file>
<file>themes/default/propertyicons/action.png</file>

Binary file not shown.

After

Width:  |  Height:  |  Size: 966 B

View File

@ -196,6 +196,14 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WFlags fl ) :
cmbPromptRasterSublayers->addItem( tr( "Load all" ) );
cmbPromptRasterSublayers->setCurrentIndex( settings.value( "/qgis/promptForRasterSublayers", 0 ).toInt() );
// Scan for contents of compressed files (.zip) in browser dock
cmbScanZipInBrowser->clear();
cmbScanZipInBrowser->addItem( tr( "No" ) ); // 0
cmbScanZipInBrowser->addItem( tr( "Basic scan" ) ); // 1
cmbScanZipInBrowser->addItem( tr( "Passthru" ) ); // 2
cmbScanZipInBrowser->addItem( tr( "Full scan" ) ); // 3
cmbScanZipInBrowser->setCurrentIndex( settings.value( "/qgis/scanZipInBrowser", 1 ).toInt() );
// set the display update threshold
spinBoxUpdateThreshold->setValue( settings.value( "/Map/updateThreshold" ).toInt() );
//set the default projection behaviour radio buttongs
@ -628,6 +636,7 @@ void QgsOptions::saveOptions()
settings.setValue( "/qgis/attributeTableBehaviour", cmbAttrTableBehaviour->currentIndex() );
settings.setValue( "/qgis/attributeTableRowCache", spinBoxAttrTableRowCache->value() );
settings.setValue( "/qgis/promptForRasterSublayers", cmbPromptRasterSublayers->currentIndex() );
settings.setValue( "/qgis/scanZipInBrowser", cmbScanZipInBrowser->currentIndex() );
settings.setValue( "/qgis/dockIdentifyResults", cbxIdentifyResultsDocked->isChecked() );
settings.setValue( "/qgis/dockSnapping", cbxSnappingOptionsDocked->isChecked() );
settings.setValue( "/qgis/addPostgisDC", cbxAddPostgisDC->isChecked() );

View File

@ -35,6 +35,10 @@
#include "qgslogger.h"
#include "qgsproviderregistry.h"
// use internal quazip for /vsizip support
#define QUAZIP_STATIC
#include <quazip/quazip.h>
// shared icons
const QIcon &QgsLayerItem::iconPoint()
{
@ -125,14 +129,25 @@ const QIcon &QgsDataCollectionItem::iconDir()
const QIcon &QgsFavouritesItem::iconFavourites()
{
static QIcon icon;
if ( icon.isNull() )
icon = QIcon( getThemePixmap( "/mIconFavourites.png" ) );
// this icon added by ET, modfied mIconNew and set colour to that of folder icon
return icon;
}
const QIcon &QgsZipItem::iconZip()
{
static QIcon icon;
if ( icon.isNull() )
icon = QIcon( getThemePixmap( "/mIconZip.png" ) );
// icon from http://www.softicons.com/free-icons/application-icons/mega-pack-icons-1-by-nikolay-verin/winzip-folder-icon
return icon;
}
QgsDataItem::QgsDataItem( QgsDataItem::Type type, QgsDataItem* parent, QString name, QString path )
: QObject( parent ), mType( type ), mParent( parent ), mPopulated( false ), mName( name ), mPath( path )
{
@ -144,8 +159,10 @@ QPixmap QgsDataItem::getThemePixmap( const QString theName )
{
QString myPreferredPath = QgsApplication::activeThemePath() + QDir::separator() + theName;
QString myDefaultPath = QgsApplication::defaultThemePath() + QDir::separator() + theName;
//QgsDebugMsg( "myPreferredPath = " + myPreferredPath );
//QgsDebugMsg( "myDefaultPath = " + myDefaultPath );
// QgsDebugMsg( "theName = " + theName );
// QgsDebugMsg( "myPreferredPath = " + myPreferredPath );
// QgsDebugMsg( "myDefaultPath = " + myDefaultPath );
if ( QFile::exists( myPreferredPath ) )
{
return QPixmap( myPreferredPath );
@ -214,7 +231,7 @@ bool QgsDataItem::hasChildren()
void QgsDataItem::addChildItem( QgsDataItem * child, bool refresh )
{
QgsDebugMsg( QString( "add child #%1 - %2" ).arg( mChildren.size() ).arg( child->mName ) );
QgsDebugMsg( QString( "add child #%1 - %2 - %3" ).arg( mChildren.size() ).arg( child->mName ).arg( child->mType ) );
int i;
if ( type() == Directory )
@ -334,6 +351,8 @@ QgsLayerItem::QgsLayerItem( QgsDataItem* parent, QString name, QString path, QSt
case Point: mIcon = iconPoint(); break;
case Line: mIcon = iconLine(); break;
case Polygon: mIcon = iconPolygon(); break;
// TODO add a new icon for generic Vector layers
case Vector : mIcon = iconPolygon(); break;
case TableLayer: mIcon = iconTable(); break;
case Raster: mIcon = iconRaster(); break;
default: mIcon = iconDefault(); break;
@ -373,7 +392,7 @@ QgsDataCollectionItem::~QgsDataCollectionItem()
}
//-----------------------------------------------------------------------
QVector<QgsDataProvider*> QgsDirectoryItem::mProviders = QVector<QgsDataProvider*>();
// QVector<QgsDataProvider*> QgsDirectoryItem::mProviders = QVector<QgsDataProvider*>();
QVector<QLibrary*> QgsDirectoryItem::mLibraries = QVector<QLibrary*>();
@ -406,6 +425,7 @@ QgsDirectoryItem::QgsDirectoryItem( QgsDataItem* parent, QString name, QString p
QgsDebugMsg( library->fileName() + " has NoDataCapabilities" );
continue;
}
QgsDebugMsg( QString( "%1 dataCapabilities : %2" ).arg( library->fileName() ).arg( dataCapabilities() ) );
mLibraries.append( library );
}
@ -425,11 +445,14 @@ QVector<QgsDataItem*> QgsDirectoryItem::createChildren( )
{
QVector<QgsDataItem*> children;
QDir dir( mPath );
QSettings settings;
bool scanZip = ( settings.value( "/qgis/scanZipInBrowser", 1 ).toInt() != 0 );
QStringList entries = dir.entryList( QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name | QDir::IgnoreCase );
foreach( QString subdir, entries )
{
QString subdirPath = dir.absoluteFilePath( subdir );
qDebug( "creating subdir: %s", subdirPath.toAscii().data() );
QgsDebugMsg( QString( "creating subdir: %1" ).arg( subdirPath ) );
QgsDirectoryItem *item = new QgsDirectoryItem( this, subdir, subdirPath );
// propagate signals up to top
@ -442,6 +465,20 @@ QVector<QgsDataItem*> 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
if ( fileInfo.suffix() == "zip" && scanZip )
{
QgsDataItem * item = QgsZipItem::itemFromPath( this, path, name );
if ( item )
{
children.append( item );
continue;
}
}
// #endif
foreach( QLibrary *library, mLibraries )
{
// we could/should create separate list of providers for each purpose
@ -475,6 +512,7 @@ QVector<QgsDataItem*> QgsDirectoryItem::createChildren( )
}
}
}
return children;
}
@ -669,3 +707,238 @@ QVector<QgsDataItem*> QgsFavouritesItem::createChildren( )
return children;
}
//-----------------------------------------------------------------------
QStringList QgsZipItem::mProviderNames = QStringList();
QVector<dataItem_t *> QgsZipItem::mDataItemPtr = QVector<dataItem_t*>();
QgsZipItem::QgsZipItem( QgsDataItem* parent, QString name, QString path )
: QgsDataCollectionItem( parent, name, path )
{
mType = Collection; //Zip??
mIcon = iconZip();
if ( mProviderNames.size() == 0 )
{
// QStringList keys = QgsProviderRegistry::instance()->providerList();
// only use GDAL and OGR providers as we use the VSIFILE mechanism
QStringList keys;
// keys << "ogr" << "gdal";
keys << "gdal" << "ogr";
QStringList::const_iterator i;
for ( i = keys.begin(); i != keys.end(); ++i )
{
QString k( *i );
QgsDebugMsg( "provider " + k );
// some providers hangs with empty uri (Postgis) etc...
// -> using libraries directly
QLibrary *library = QgsProviderRegistry::instance()->providerLibrary( k );
if ( library )
{
dataCapabilities_t * dataCapabilities = ( dataCapabilities_t * ) cast_to_fptr( library->resolve( "dataCapabilities" ) );
if ( !dataCapabilities )
{
QgsDebugMsg( library->fileName() + " does not have dataCapabilities" );
continue;
}
if ( dataCapabilities() == QgsDataProvider::NoDataCapabilities )
{
QgsDebugMsg( library->fileName() + " has NoDataCapabilities" );
continue;
}
QgsDebugMsg( QString( "%1 dataCapabilities : %2" ).arg( library->fileName() ).arg( dataCapabilities() ) );
dataItem_t * dataItem = ( dataItem_t * ) cast_to_fptr( library->resolve( "dataItem" ) );
if ( ! dataItem )
{
QgsDebugMsg( library->fileName() + " does not have dataItem" );
continue;
}
// mLibraries.append( library );
mDataItemPtr.append( dataItem );
mProviderNames.append( k );
}
else
{
//QgsDebugMsg ( "Cannot get provider " + k );
}
}
}
}
QgsZipItem::~QgsZipItem()
{
}
QVector<QgsDataItem*> QgsZipItem::createChildren( )
{
QVector<QgsDataItem*> children;
QStringList fileList;
QString tmpPath;
QString childPath;
QSettings settings;
int scanZipSetting = settings.value( "/qgis/scanZipInBrowser", 1 ).toInt();
if ( scanZipSetting == 0 )
{
return children;
}
// if scanZipBrowser == "Passthru": do not scan zip and allow to open directly with /vsigzip/
if ( scanZipSetting == 2 )
{
mPath = "/vsizip/" + path(); // should check for extension
QgsDebugMsg( "set path to " + path() );
return children;
}
// get list of files inside zip file
QuaZip zip( path() );
if ( ! zip.open( QuaZip::mdUnzip ) || ! zip.isOpen() )
{
QgsDebugMsg( QString( "Zip error: %1" ).arg( zip.getZipError() ) );
}
else
{
for ( bool more = zip.goToFirstFile(); more; more = zip.goToNextFile() )
{
// tmpPath = "/vsizip/" + path() + "/" + zip.getCurrentFileName();
// QgsDebugMsg( QString( "file %1 - %2" ).arg( zip.getCurrentFileName() ).arg( tmpPath ) );
tmpPath = zip.getCurrentFileName();
// skip directories (files ending with /)
if ( tmpPath.right( 1 ) != "/" )
fileList << tmpPath;
}
}
zip.close();
if ( zip.getZipError() != UNZ_OK )
{
QgsDebugMsg( QString( "Zip error: %1" ).arg( zip.getZipError() ) );
}
// loop over files inside zip
foreach( QString fileName, fileList )
{
QFileInfo info( fileName );
tmpPath = "/vsizip/" + path() + "/" + fileName;
QgsDebugMsg( "tmpPath = " + tmpPath );
// foreach( dataItem_t *dataItem, mDataItemPtr )
for ( int i = 0; i < mProviderNames.size(); i++ )
{
// ugly hack to remove .dbf file if there is a .shp file
if ( mProviderNames[i] == "ogr" )
{
if ( info.suffix() == "dbf" )
{
if ( fileList.indexOf( fileName.left( fileName.count() - 4 ) + ".shp" ) != -1 )
continue;
}
if ( info.completeSuffix().toLower() == "shp.xml" )
{
continue;
}
}
// try to get data item from provider
dataItem_t *dataItem = mDataItemPtr[i];
if ( dataItem )
{
QgsDebugMsg( QString( "trying to load item %1 with %2" ).arg( tmpPath ).arg( mProviderNames[i] ) );
QgsDataItem * item = dataItem( tmpPath, this );
if ( item )
{
QgsDebugMsg( "loaded item" );
childPath = tmpPath;
children.append( item );
break;
}
else
{
QgsDebugMsg( "not loaded item" );
}
}
}
}
if ( children.size() == 1 )
{
// save the name of the only child so we can get a normal data item from it
mPath = childPath;
}
return children;
}
QgsDataItem* QgsZipItem::itemFromPath( QgsDataItem* parent, QString path, QString name )
{
QSettings settings;
int scanZipSetting = settings.value( "/qgis/scanZipInBrowser", 1 ).toInt();
QFileInfo fileInfo( path );
QString tmpPath = path;
QgsZipItem * zipItem = 0;
QgsDebugMsg( "path = " + path + " name= " + name );
// if scanZipBrowser == 0 (No): skip to the next file
if ( scanZipSetting == 0 )
{
return 0;
}
// if scanZipBrowser == 2 (Passthru): do not scan zip and allow to open directly with /vsigzip/
else if ( scanZipSetting == 2 )
{
tmpPath = "/vsizip/" + path;
zipItem = 0;
}
else
{
zipItem = new QgsZipItem( parent, name, path );
}
if ( zipItem )
{
QgsDebugMsg( QString( "Got zipItem with %1 children, path=%2, name=%3" ).arg( zipItem->rowCount() ).arg( zipItem->path() ).arg( zipItem->name() ) );
}
// only display if has children
// other option would be to delay until item is opened, but we would be polluting the tree with empty items
if ( zipItem && zipItem->rowCount() > 1 )
{
QgsDebugMsg( "returning zipItem" );
return zipItem;
}
// if 1 or 0 child found, create a data item using the full path given by QgsZipItem
else
{
if ( zipItem )
{
tmpPath = zipItem->path();
delete zipItem;
}
QgsDebugMsg( QString( "will try to create a normal dataItem from path= %2" ).arg( tmpPath ) );
// try to open using registered providers (gdal and ogr)
for ( int i = 0; i < mProviderNames.size(); i++ )
{
dataItem_t *dataItem = mDataItemPtr[i];
if ( dataItem )
{
QgsDataItem *item = dataItem( tmpPath, parent );
if ( item )
return item;
}
}
}
return 0;
}

View File

@ -36,7 +36,6 @@ typedef int dataCapabilities_t();
typedef QgsDataItem * dataItem_t( QString, QgsDataItem* );
/** base class for all items in the model */
class CORE_EXPORT QgsDataItem : public QObject
{
@ -236,7 +235,7 @@ class CORE_EXPORT QgsDirectoryItem : public QgsDataCollectionItem
virtual QWidget * paramWidget();
static QVector<QgsDataProvider*> mProviders;
/* static QVector<QgsDataProvider*> mProviders; */
static QVector<QLibrary*> mLibraries;
};
@ -281,8 +280,28 @@ class CORE_EXPORT QgsFavouritesItem : public QgsDataCollectionItem
~QgsFavouritesItem();
QVector<QgsDataItem*> createChildren();
static const QIcon &iconFavourites();
};
/** A zip file: contains layers, using GDAL/OGR VSIFILE mechanism */
class CORE_EXPORT QgsZipItem : public QgsDataCollectionItem
{
Q_OBJECT
public:
QgsZipItem( QgsDataItem* parent, QString name, QString path );
~QgsZipItem();
QVector<QgsDataItem*> createChildren();
QStringList getFiles();
static QVector<dataItem_t *> mDataItemPtr;
static QStringList mProviderNames;
static QgsDataItem* itemFromPath( QgsDataItem* parent, QString path, QString name );
static const QIcon &iconZip();
};
#endif // QGSDATAITEM_H

View File

@ -3,6 +3,7 @@
#include "qgslogger.h"
#include <QFileInfo>
#include <QSettings>
// defined in qgsgdalprovider.cpp
void buildSupportedRasterFileFilterAndExtensions( QString & theFileFiltersString, QStringList & theExtensions, QStringList & theWildcards );
@ -90,6 +91,7 @@ QVector<QgsDataItem*> QgsGdalLayerItem::createChildren( )
// ---------------------------------------------------------------------------
static QString filterString;
static QStringList extensions = QStringList();
static QStringList wildcards = QStringList();
@ -103,79 +105,111 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem )
if ( thePath.isEmpty() )
return 0;
QgsDebugMsg( "thePath= " + thePath );
QString uri = thePath;
QFileInfo info( thePath );
if ( info.isFile() )
QSettings settings;
//extract basename with extension
QString name = info.fileName();
int scanZipSetting = settings.value( "/qgis/scanZipInBrowser", 1 ).toInt();
// allow normal files or VSIFILE items to pass
if ( ! info.isFile() &&
thePath.left( 8 ) != "/vsizip/" &&
thePath.left( 9 ) != "/vsigzip/" )
return 0;
// get supported extensions
if ( extensions.isEmpty() )
{
// get supported extensions
if ( extensions.isEmpty() )
{
QString filterString;
buildSupportedRasterFileFilterAndExtensions( filterString, extensions, wildcards );
QgsDebugMsg( "extensions: " + extensions.join( " " ) );
QgsDebugMsg( "wildcards: " + wildcards.join( " " ) );
}
// skip *.aux.xml files (GDAL auxilary metadata files)
// unless that extension is in the list (*.xml might be though)
if ( thePath.right( 8 ) == ".aux.xml" &&
extensions.indexOf( "aux.xml" ) < 0 )
return 0;
// skip .tar.gz files
if ( thePath.right( 7 ) == ".tar.gz" )
return 0;
// Filter files by extension
if ( extensions.indexOf( info.suffix().toLower() ) < 0 )
{
bool matches = false;
foreach( QString wildcard, wildcards )
{
QRegExp rx( wildcard, Qt::CaseInsensitive, QRegExp::Wildcard );
if ( rx.exactMatch( info.fileName() ) )
{
matches = true;
break;
}
}
if ( !matches )
return 0;
}
// try to open using VSIFileHandler
// TODO use the file name of the file inside the zip for layer name
if ( thePath.right( 4 ) == ".zip" )
{
if ( thePath.left( 8 ) != "/vsizip/" )
thePath = "/vsizip/" + thePath;
}
else if ( thePath.right( 3 ) == ".gz" )
{
if ( thePath.left( 9 ) != "/vsigzip/" )
thePath = "/vsigzip/" + thePath;
}
GDALAllRegister();
GDALDatasetH hDS = GDALOpen( TO8F( thePath ), GA_ReadOnly );
if ( !hDS )
return 0;
// get layers list now so we can pass it to item
QStringList sublayers = QgsGdalProvider::subLayers( hDS );
GDALClose( hDS );
QgsDebugMsg( "GdalDataset opened " + thePath );
//extract basename with extension
QString name = info.completeBaseName() + "." + info.suffix();
QString uri = thePath;
QgsLayerItem * item = new QgsGdalLayerItem( parentItem, name, thePath, uri,
&sublayers );
return item;
buildSupportedRasterFileFilterAndExtensions( filterString, extensions, wildcards );
QgsDebugMsg( "extensions: " + extensions.join( " " ) );
QgsDebugMsg( "wildcards: " + wildcards.join( " " ) );
}
return 0;
// skip *.aux.xml files (GDAL auxilary metadata files)
// unless that extension is in the list (*.xml might be though)
if ( thePath.right( 8 ).toLower() == ".aux.xml" &&
extensions.indexOf( "aux.xml" ) < 0 )
return 0;
// skip .tar.gz files
if ( thePath.right( 7 ) == ".tar.gz" )
return 0;
// Filter files by extension
if ( extensions.indexOf( info.suffix().toLower() ) < 0 )
{
bool matches = false;
foreach( QString wildcard, wildcards )
{
QRegExp rx( wildcard, Qt::CaseInsensitive, QRegExp::Wildcard );
if ( rx.exactMatch( info.fileName() ) )
{
matches = true;
break;
}
}
if ( !matches )
return 0;
}
// vsifile : depending on options we should just add the item without testing
if ( thePath.left( 8 ) == "/vsizip/" )
{
// if this is a /vsigzip/path.zip/file_inside_zip change the name
if ( thePath != "/vsizip/" + parentItem->path() )
{
name = thePath;
name = name.replace( "/vsizip/" + parentItem->path() + "/", "" );
}
// unless setting== 2 (passthru) or 3 (Full scan), return an item without testing
if ( scanZipSetting != 2 && scanZipSetting != 3 )
{
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;
}
}
// try to open using VSIFileHandler
if ( thePath.right( 4 ) == ".zip" )
{
if ( thePath.left( 8 ) != "/vsizip/" )
thePath = "/vsizip/" + thePath;
}
else if ( thePath.right( 3 ) == ".gz" )
{
if ( thePath.left( 9 ) != "/vsigzip/" )
thePath = "/vsigzip/" + thePath;
}
// test that file is valid with GDAL
GDALAllRegister();
// do not print errors, but write to debug
CPLErrorHandler oErrorHandler = CPLSetErrorHandler( CPLQuietErrorHandler );
CPLErrorReset();
GDALDatasetH hDS = GDALOpen( TO8F( thePath ), GA_ReadOnly );
CPLSetErrorHandler( oErrorHandler );
if ( ! hDS )
{
QgsDebugMsg( QString( "GDALOpen error # %1 : %2 " ).arg( CPLGetLastErrorNo() ).arg( CPLGetLastErrorMsg() ) );
return 0;
}
QStringList sublayers = QgsGdalProvider::subLayers( hDS );
GDALClose( hDS );
QgsDebugMsg( "GdalDataset opened " + thePath );
QgsLayerItem * item = new QgsGdalLayerItem( parentItem, name, thePath, thePath,
&sublayers );
return item;
}

View File

@ -40,6 +40,7 @@
#include <QFile>
#include <QHash>
#include <QTime>
#include <QSettings>
#include "gdalwarper.h"
#include "ogr_spatialref.h"
@ -1077,7 +1078,7 @@ bool QgsGdalProvider::identify( const QgsPoint& thePoint, QMap<QString, QString>
int col = ( int ) floor(( x - mExtent.xMinimum() ) / xres );
int row = ( int ) floor(( mExtent.yMaximum() - y ) / yres );
QgsDebugMsg( "row = " + QString::number( row ) + " col = " + QString::number( col ) );
// QgsDebugMsg( "row = " + QString::number( row ) + " col = " + QString::number( col ) );
for ( int i = 1; i <= GDALGetRasterCount( mGdalDataset ); i++ )
{
@ -1093,7 +1094,7 @@ bool QgsGdalProvider::identify( const QgsPoint& thePoint, QMap<QString, QString>
}
//double value = readValue( data, type, 0 );
QgsDebugMsg( QString( "value=%1" ).arg( value ) );
// QgsDebugMsg( QString( "value=%1" ).arg( value ) );
QString v;
if ( mValidNoDataValue && ( fabs( value - mNoDataValue[i-1] ) <= TINY_VALUE || value != value ) )
@ -1842,6 +1843,8 @@ void buildSupportedRasterFileFilterAndExtensions( QString & theFileFiltersString
// VSIFileHandler (see qgsogrprovider.cpp)
#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1600
// QSettings settings;
// if ( settings.value( "/qgis/scanZipInBrowser", 1 ).toInt() != 0 )
if ( 1 )
{
QString glob = "*.zip";
@ -1995,3 +1998,4 @@ QGISEXTERN void buildSupportedRasterFileFilter( QString & theFileFiltersString )
QStringList wildcards;
buildSupportedRasterFileFilterAndExtensions( theFileFiltersString, exts, wildcards );
}

View File

@ -20,6 +20,7 @@
#include <QFileInfo>
#include <QTextStream>
#include <QSettings>
#include <ogr_srs_api.h>
#include <cpl_error.h>
@ -225,8 +226,17 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem )
if ( thePath.isEmpty() )
return 0;
QgsDebugMsg( "thePath: " + thePath );
QFileInfo info( thePath );
if ( !info.isFile() )
QString name = info.fileName();
QSettings settings;
int scanZipSetting = settings.value( "/qgis/scanZipInBrowser", 1 ).toInt();
// allow normal files or VSIFILE items to pass
if ( ! info.isFile() &&
thePath.left( 8 ) != "/vsizip/" &&
thePath.left( 9 ) != "/vsigzip/" )
return 0;
QStringList myExtensions = fileExtensions();
@ -261,7 +271,27 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem )
return 0;
}
// try to open using the /vsizip mechanism
// vsifile : depending on options we should just add the item without testing
if ( thePath.left( 8 ) == "/vsizip/" )
{
// if this is a /vsigzip/path.zip/file_inside_zip change the name
if ( thePath.left( 8 ) == "/vsizip/" &&
thePath != "/vsizip/" + parentItem->path() )
{
name = thePath;
name = name.replace( "/vsizip/" + parentItem->path() + "/", "" );
}
// unless setting== 2 (Passthru) or 3 (Full scan), return an item without testing
if ( scanZipSetting != 2 && scanZipSetting != 3 )
{
QgsLayerItem * item = new QgsOgrLayerItem( parentItem, name, thePath, thePath, QgsLayerItem::Vector );
if ( item )
return item;
}
}
// try to open using VSIFileHandler
if ( thePath.right( 4 ) == ".zip" )
{
if ( thePath.left( 8 ) != "/vsizip/" )
@ -273,12 +303,20 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem )
thePath = "/vsigzip/" + thePath;
}
// test that file is valid with OGR
OGRRegisterAll();
OGRSFDriverH hDriver;
// do not print errors, but write to debug
CPLErrorHandler oErrorHandler = CPLSetErrorHandler( CPLQuietErrorHandler );
CPLErrorReset();
OGRDataSourceH hDataSource = OGROpen( TO8F( thePath ), false, &hDriver );
CPLSetErrorHandler( oErrorHandler );
if ( !hDataSource )
if ( ! hDataSource )
{
QgsDebugMsg( QString( "OGROpen error # %1 : %2 " ).arg( CPLGetLastErrorNo() ).arg( CPLGetLastErrorMsg() ) );
return 0;
}
QString driverName = OGR_Dr_GetName( hDriver );
QgsDebugMsg( "OGR Driver : " + driverName );
@ -289,13 +327,13 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem )
if ( numLayers == 1 )
{
//extract basename with extension
QString name = info.completeBaseName() + "." + QFileInfo( thePath ).suffix();
QgsDebugMsg( QString( "using name = %1" ).arg( name ) );
item = dataItemForLayer( parentItem, name, thePath, hDataSource, 0 );
}
else if ( numLayers > 1 )
{
item = new QgsOgrDataCollectionItem( parentItem, info.fileName(), thePath );
QgsDebugMsg( QString( "using name = %1" ).arg( name ) );
item = new QgsOgrDataCollectionItem( parentItem, name, thePath );
}
OGR_DS_Destroy( hDataSource );

View File

@ -35,6 +35,7 @@ email : sherman at mrcc.com
#include <QMap>
#include <QString>
#include <QTextCodec>
#include <QSettings>
#include "qgsapplication.h"
#include "qgsdataitem.h"
@ -1778,11 +1779,12 @@ QString createFilters( QString type )
// see http://trac.osgeo.org/gdal/wiki/UserDocs/ReadInZip
// Requires GDAL>=1.6.0 with libz support, let's assume we have it.
// For .zip this works only if there is one file (or dataset) in the root of the zip.
// Only tested with shape (zip) and spatialite (zip and gz).
// Ideally we should add a new subclass of QgsCollectionItem (or QgsDirItem), say QgsZipItem
// and read the files inside the zip (requires unzip.h or cpl_minizip_unzip.h)
// and also add support for /vsitar/ (requires cpl_vsil_tar.cpp).
// Only tested with tiff, shape (zip) and spatialite (zip and gz).
// This does not work for some file types, see VSIFileHandler doc.
// Ideally we should also add support for /vsitar/ (requires cpl_vsil_tar.cpp).
#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1600
// QSettings settings;
// if ( settings.value( "/qgis/scanZipInBrowser", 1 ).toInt() != 0 )
if ( 1 )
{
myFileFilters += createFileFilter_( QObject::tr( "GDAL/OGR VSIFileHandler" ), "*.zip *.gz" );

View File

@ -602,6 +602,33 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_13">
<item>
<widget class="QLabel" name="label_24">
<property name="text">
<string>Scan for contents of compressed files (.zip) in browser dock</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_11">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QComboBox" name="cmbScanZipInBrowser"/>
</item>
</layout>
</item>
</layout>
</widget>
</item>