diff --git a/src/app/ogr/qgsogrsublayersdialog.cpp b/src/app/ogr/qgsogrsublayersdialog.cpp index 4ba27dde68ff..0cdef2fcaf4d 100644 --- a/src/app/ogr/qgsogrsublayersdialog.cpp +++ b/src/app/ogr/qgsogrsublayersdialog.cpp @@ -46,6 +46,16 @@ QStringList QgsOGRSublayersDialog::getSelection() return list; } +QList QgsOGRSublayersDialog::getSelectionIndexes() +{ + QList 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 ) diff --git a/src/app/ogr/qgsogrsublayersdialog.h b/src/app/ogr/qgsogrsublayersdialog.h index 5389e5f51633..eccb07533f77 100644 --- a/src/app/ogr/qgsogrsublayersdialog.h +++ b/src/app/ogr/qgsogrsublayersdialog.h @@ -28,6 +28,7 @@ class QgsOGRSublayersDialog : public QDialog, private Ui::QgsOGRSublayersDialogB ~QgsOGRSublayersDialog(); void populateLayerTable( QStringList theList, QString delim = ":" ); QStringList getSelection(); + QList getSelectionIndexes(); public slots: void on_buttonBox_helpRequested() { QgsContextHelp::run( metaObject()->className() ); } diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index 004b2d02a6f9..1dce5912926d 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -175,6 +175,7 @@ #include "qgsvectorlayer.h" #include "qgsvectorlayerproperties.h" #include "qgsmessagelogviewer.h" +#include "qgsdataitem.h" #include "ogr/qgsogrsublayersdialog.h" #include "ogr/qgsopenvectorlayerdialog.h" @@ -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" ) { @@ -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 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( 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( 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 ) { @@ -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 ); @@ -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() ); @@ -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 ); @@ -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 diff --git a/src/app/qgisapp.h b/src/app/qgisapp.h index d08cb6e4266e..68e4d3cc57db 100644 --- a/src/app/qgisapp.h +++ b/src/app/qgisapp.h @@ -77,6 +77,8 @@ class QgsMessageLogViewer; class QgsScaleComboBox; +class QgsDataItem; + #include #include #include @@ -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. */ diff --git a/src/providers/gdal/qgsgdaldataitems.cpp b/src/providers/gdal/qgsgdaldataitems.cpp index 245742d7f8f6..636743b03a67 100644 --- a/src/providers/gdal/qgsgdaldataitems.cpp +++ b/src/providers/gdal/qgsgdaldataitems.cpp @@ -93,11 +93,23 @@ QVector 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 );