Skip to content

Commit

Permalink
add zip item layer dialog to open .zip and .tar files with many files…
Browse files Browse the repository at this point in the history
… ; fix gdal sublayer names
  • Loading branch information
etiennesky authored and jef-n committed Jun 16, 2012
1 parent a4a85cb commit 74110ae
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 16 deletions.
10 changes: 10 additions & 0 deletions src/app/ogr/qgsogrsublayersdialog.cpp
Expand Up @@ -46,6 +46,16 @@ QStringList QgsOGRSublayersDialog::getSelection()
return list;
}

QList<int> QgsOGRSublayersDialog::getSelectionIndexes()
{
QList<int> list;
for ( int i = 0; i < layersTable->selectedItems().size(); i++ )
{
list << layersTable->selectedItems().at( i )->text( 0 ).toInt();
}
return list;
}

void QgsOGRSublayersDialog::populateLayerTable( QStringList theList, QString delim )
{
foreach( QString item, theList )
Expand Down
1 change: 1 addition & 0 deletions src/app/ogr/qgsogrsublayersdialog.h
Expand Up @@ -28,6 +28,7 @@ class QgsOGRSublayersDialog : public QDialog, private Ui::QgsOGRSublayersDialogB
~QgsOGRSublayersDialog();
void populateLayerTable( QStringList theList, QString delim = ":" );
QStringList getSelection();
QList<int> getSelectionIndexes();

public slots:
void on_buttonBox_helpRequested() { QgsContextHelp::run( metaObject()->className() ); }
Expand Down
164 changes: 156 additions & 8 deletions src/app/qgisapp.cpp
Expand Up @@ -175,6 +175,7 @@
#include "qgsvectorlayer.h"
#include "qgsvectorlayerproperties.h"
#include "qgsmessagelogviewer.h"
#include "qgsdataitem.h"

#include "ogr/qgsogrsublayersdialog.h"
#include "ogr/qgsopenvectorlayerdialog.h"
Expand Down Expand Up @@ -2225,6 +2226,15 @@ bool QgisApp::addVectorLayers( QStringList const & theLayerQStringList, const QS
{
QFileInfo fi( src );
base = fi.completeBaseName();

// if needed prompt for zipitem layers
QString vsiPrefix = QgsZipItem::vsiPrefix( src );
if ( ! src.startsWith( "/vsi", Qt::CaseInsensitive ) &&
( vsiPrefix == "/vsizip/" || vsiPrefix == "/vsitar/" ) )
{
if ( askUserForZipItemLayers( src ) )
continue;
}
}
else if ( dataSourceType == "database" )
{
Expand Down Expand Up @@ -2322,6 +2332,102 @@ bool QgisApp::addVectorLayers( QStringList const & theLayerQStringList, const QS
return true;
} // QgisApp::addVectorLayer()

// present a dialog to choose zipitem layers
bool QgisApp::askUserForZipItemLayers( QString path )
{
bool ok = false;
QVector<QgsDataItem*> childItems;
QgsZipItem *zipItem = 0;
QSettings settings;
int promptLayers = settings.value( "/qgis/promptForRasterSublayers", 1 ).toInt();

QgsDebugMsg( "askUserForZipItemLayers( " + path + ")" );

// if scanZipBrowser == no: skip to the next file
if ( settings.value( "/qgis/scanZipInBrowser", "basic" ).toString() == "no" )
{
return false;
}

zipItem = new QgsZipItem( 0, path, path );
if ( ! zipItem )
return false;

zipItem->populate();
QgsDebugMsg( QString( "Got zipitem with %1 children" ).arg( zipItem->rowCount() ) );

// if 1 or 0 child found, exit so a normal item is created by gdal or ogr provider
if ( zipItem->rowCount() <= 1 )
{
delete zipItem;
return false;
}

// if promptLayers=Load all, load all layers without prompting
if ( promptLayers == 3 )
{
childItems = zipItem->children();
}
// exit if promptLayers=Never
else if ( promptLayers == 2 )
{
delete zipItem;
return false;
}
else
{
// We initialize a selection dialog and display it.
QgsOGRSublayersDialog chooseSublayersDialog( this );
chooseSublayersDialog.setWindowTitle( tr( "Select zip layers to add..." ) );

QStringList layers;
for ( int i = 0; i < zipItem->children().size(); i++ )
{
QgsDataItem *item = zipItem->children()[i];
QgsLayerItem *layerItem = dynamic_cast<QgsLayerItem *>( item );
QgsDebugMsg( QString( "item path=%1 provider=" ).arg( item->path() ).arg( layerItem->providerKey() ) );
if ( layerItem && layerItem->providerKey() == "gdal" )
{
layers << QString( "%1|%2| |%3" ).arg( i ).arg( item->name() ).arg( "Raster" );
}
else if ( layerItem && layerItem->providerKey() == "ogr" )
{
layers << QString( "%1|%2| |%3" ).arg( i ).arg( item->name() ).arg( tr( "Vector" ) );
}
}

chooseSublayersDialog.populateLayerTable( layers, "|" );

if ( chooseSublayersDialog.exec() )
{
foreach( int i, chooseSublayersDialog.getSelectionIndexes() )
{
childItems << zipItem->children()[i];
}
}
}

// add childItems
foreach( QgsDataItem* item, childItems )
{
QgsLayerItem *layerItem = dynamic_cast<QgsLayerItem *>( item );
QgsDebugMsg( QString( "item path=%1 provider=" ).arg( item->path() ).arg( layerItem->providerKey() ) );
if ( layerItem && layerItem->providerKey() == "gdal" )
{
if ( addRasterLayer( item->path(), QFileInfo( item->name() ).completeBaseName() ) )
ok = true;
}
else if ( layerItem && layerItem->providerKey() == "ogr" )
{
if ( addVectorLayers( QStringList( item->path() ), "System", "file" ) )
ok = true;
}
}

delete zipItem;
return ok;
}

// present a dialog to choose GDAL raster sublayers
void QgisApp::askUserForGDALSublayers( QgsRasterLayer *layer )
{
Expand All @@ -2347,20 +2453,41 @@ void QgisApp::askUserForGDALSublayers( QgsRasterLayer *layer )
chooseSublayersDialog.setWindowTitle( tr( "Select raster layers to add..." ) );

QStringList layers;
QStringList names;
for ( int i = 0; i < sublayers.size(); i++ )
{
layers << QString( "%1|%2|1|%3" ).arg( i ).arg( sublayers[i] ).arg( tr( "Raster" ) );
// simplify raster sublayer name - should add a function in gdal provider for this?
// code is copied from QgsGdalLayerItem::createChildren
QString name = sublayers[i];
QString path = layer->source();
// if netcdf/hdf use all text after filename
// for hdf4 it would be best to get description, because the subdataset_index is not very practical
if ( name.startsWith( "netcdf", Qt::CaseInsensitive ) ||
name.startsWith( "hdf", Qt::CaseInsensitive ) )
name = name.mid( name.indexOf( path ) + path.length() + 1 );
else
{
// remove driver name and file name
name.replace( name.split( ":" )[0], "" );
name.replace( path, "" );
}
// remove any : or " left over
if ( name.startsWith( ":" ) ) name.remove( 0, 1 );
if ( name.startsWith( "\"" ) ) name.remove( 0, 1 );
if ( name.endsWith( ":" ) ) name.chop( 1 );
if ( name.endsWith( "\"" ) ) name.chop( 1 );

names << name;
layers << QString( "%1|%2|1|%3" ).arg( i ).arg( name ).arg( tr( "Raster" ) );
}

chooseSublayersDialog.populateLayerTable( layers, "|" );

if ( chooseSublayersDialog.exec() )
{
foreach( QString path, chooseSublayersDialog.getSelection() )
foreach( int i, chooseSublayersDialog.getSelectionIndexes() )
{
QString name = path;
name.replace( layer->source(), QFileInfo( layer->source() ).completeBaseName() );
QgsRasterLayer *rlayer = new QgsRasterLayer( path, name );
QgsRasterLayer *rlayer = new QgsRasterLayer( sublayers[i], names[i] );
if ( rlayer && rlayer->isValid() )
{
addRasterLayer( rlayer );
Expand Down Expand Up @@ -3176,10 +3303,22 @@ void QgisApp::openProject( const QString & fileName )
bool QgisApp::openLayer( const QString & fileName, bool allowInteractive )
{
QFileInfo fileInfo( fileName );

// try to load it as raster
bool ok( false );

CPLPushErrorHandler( CPLQuietErrorHandler );

// if needed prompt for zipitem layers
QString vsiPrefix = QgsZipItem::vsiPrefix( fileName );
if ( vsiPrefix == "/vsizip/" || vsiPrefix == "/vsitar/" )
{
if ( askUserForZipItemLayers( fileName ) )
{
CPLPopErrorHandler();
return true;
}
}

// try to load it as raster
if ( QgsRasterLayer::isValidRasterFileName( fileName ) )
{
ok = addRasterLayer( fileName, fileInfo.completeBaseName() );
Expand Down Expand Up @@ -6917,6 +7056,15 @@ bool QgisApp::addRasterLayers( QStringList const &theFileNameQStringList, bool g
{
QString errMsg;

// if needed prompt for zipitem layers
QString vsiPrefix = QgsZipItem::vsiPrefix( *myIterator );
if ( ! myIterator->startsWith( "/vsi", Qt::CaseInsensitive ) &&
( vsiPrefix == "/vsizip/" || vsiPrefix == "/vsitar/" ) )
{
if ( askUserForZipItemLayers( *myIterator ) )
continue;
}

if ( QgsRasterLayer::isValidRasterFileName( *myIterator, errMsg ) )
{
QFileInfo myFileInfo( *myIterator );
Expand Down Expand Up @@ -6952,7 +7100,7 @@ bool QgisApp::addRasterLayers( QStringList const &theFileNameQStringList, bool g
break;
}
}
}
} // valid raster filename
else
{
// Issue message box warning unless we are loading from cmd line since
Expand Down
19 changes: 16 additions & 3 deletions src/app/qgisapp.h
Expand Up @@ -77,6 +77,8 @@ class QgsMessageLogViewer;

class QgsScaleComboBox;

class QgsDataItem;

#include <QMainWindow>
#include <QToolBar>
#include <QAbstractSocket>
Expand Down Expand Up @@ -909,11 +911,22 @@ class QgisApp : public QMainWindow, private Ui::MainWindow
void customSrsValidation( QgsCoordinateReferenceSystem *crs );

private:
/** This method will open a dialog so the user can select the sublayers to load
*/
/** This method will open a dialog so the user can select GDAL sublayers to load
* @returns true if any items were loaded
* @note added in version 1.9
*/
bool askUserForZipItemLayers( QString path );
/** This method will open a dialog so the user can select GDAL sublayers to load
* @note added in version 1.8
*/
void askUserForGDALSublayers( QgsRasterLayer *layer );
/** This method will verify if a GDAL layer contains sublayers
* @note added in version 1.8
*/
bool shouldAskUserForGDALSublayers( QgsRasterLayer *layer );
/** This method will open a dialog so the user can select OGR sublayers to load
*/
void askUserForOGRSublayers( QgsVectorLayer *layer );
void askUserForGDALSublayers( QgsRasterLayer *layer );
/** Add a raster layer to the map (passed in as a ptr).
* It won't force a refresh.
*/
Expand Down
22 changes: 17 additions & 5 deletions src/providers/gdal/qgsgdaldataitems.cpp
Expand Up @@ -93,11 +93,23 @@ QVector<QgsDataItem*> QgsGdalLayerItem::createChildren( )
for ( int i = 0; i < sublayers.count(); i++ )
{
QString name = sublayers[i];
// replace full path with basename+extension
name.replace( mPath, mName );
// use subdataset name only - perhaps only if name is long
if ( name.length() > 50 )
name = name.split( mName )[1].mid( 2 );
// if netcdf/hdf use all text after filename
// for hdf4 it would be best to get description, because the subdataset_index is not very practical
if ( name.startsWith( "netcdf", Qt::CaseInsensitive ) ||
name.startsWith( "hdf", Qt::CaseInsensitive ) )
name = name.mid( name.indexOf( mPath ) + mPath.length() + 1 );
else
{
// remove driver name and file name
name.replace( name.split( ":" )[0], "" );
name.replace( mPath, "" );
}
// remove any : or " left over
if ( name.startsWith( ":" ) ) name.remove( 0, 1 );
if ( name.startsWith( "\"" ) ) name.remove( 0, 1 );
if ( name.endsWith( ":" ) ) name.chop( 1 );
if ( name.endsWith( "\"" ) ) name.chop( 1 );

childItem = new QgsGdalLayerItem( this, name, sublayers[i], sublayers[i] );
if ( childItem )
this->addChildItem( childItem );
Expand Down

0 comments on commit 74110ae

Please sign in to comment.