Index: src/app/qgisapp.h =================================================================== --- src/app/qgisapp.h (révision 10043) +++ src/app/qgisapp.h (copie de travail) @@ -63,6 +63,8 @@ #include "qgsconfig.h" #include "qgspoint.h" +#include "../providers/ogr/qgsogrprovider.h" + /*! \class QgisApp * \brief Main window for the Qgis application */ @@ -342,6 +344,8 @@ */ void editPaste( QgsMapLayer * destinationLayer = 0 ); + void loadOGRSublayers( QString uri, QStringList *list ); + protected: //! Handle state changes (WindowTitleChange) @@ -594,6 +598,10 @@ void bookmarkAdded(); private: + /** This method will open a dialog so the user can select the sublayers + * to load + */ + void askUserForSublayers(QgsVectorLayer *layer); /** Add a raster layer to the map (passed in as a ptr). * It won't force a refresh. */ Index: src/app/qgsogrsublayersdialog.cpp =================================================================== --- src/app/qgsogrsublayersdialog.cpp (révision 0) +++ src/app/qgsogrsublayersdialog.cpp (révision 0) @@ -0,0 +1,70 @@ +/*************************************************************************** + * Copyright (C) 2003 by Tim Sutton * + * tim@linfiniti.com * + * * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "qgsogrsublayersdialog.h" +#include "qgscontexthelp.h" + +//qt includes + +//standard includes + +QgsOGRSublayersDialog::QgsOGRSublayersDialog( QWidget* parent, Qt::WFlags fl ) + : QDialog( parent, fl ) +{ + setupUi( this ); + QStringList labels=QStringList() << "Layer ID" << "Layer name" << "Nb of features" << "Geometry type"; + layersTable->setHeaderLabels(labels); +} + +QgsOGRSublayersDialog::~QgsOGRSublayersDialog() +{ +} + +void QgsOGRSublayersDialog::setURI(QString uri) +{ + if ( uri.contains('&', Qt::CaseSensitive)) + { + // If we get here, there are some options added to the filename. + // A valid uri is of the form: filename&option1=value1&option2=value2,... + // We want only the filename here, so we get the first part of the split. + QStringList theURIParts = uri.split("&"); + uri = theURIParts.at( 0 ); + } + mURI=QString(uri); +} + +void QgsOGRSublayersDialog::on_buttonBox_accepted() +{ + //close the dialog + QStringList list=QStringList(); + for (int i = 0; i < layersTable-> selectedItems().size(); i++) + { + QString theItem =layersTable-> selectedItems().at(i)->text(1); + list.append(theItem); + } + emit updated( mURI , &list ); + accept(); +} + +void QgsOGRSublayersDialog::on_buttonBox_rejected() +{ + reject(); +} + +void QgsOGRSublayersDialog::populateLayerTable (QStringList *theList) +{ + for (int i =0; i< theList->size(); i++){ + QString ligne = theList -> at(i); + QStringList elements = ligne.split(":"); + QStringList item=QStringList(); + item << elements.at(0) << elements.at(1) << elements.at(2) << elements.at(3); + layersTable -> addTopLevelItem(new QTreeWidgetItem(item)); + } +} Index: src/app/CMakeLists.txt =================================================================== --- src/app/CMakeLists.txt (révision 10043) +++ src/app/CMakeLists.txt (copie de travail) @@ -39,6 +39,7 @@ qgsmeasuretool.cpp qgsnewhttpconnection.cpp qgsnumericsortlistviewitem.cpp + qgsogrsublayersdialog.cpp qgsoptions.cpp qgspastetransformations.cpp qgspluginitem.cpp @@ -113,6 +114,7 @@ qgsmeasuredialog.h qgsnewhttpconnection.h qgsoptions.h + qgsogrsublayersdialog.h qgspastetransformations.h qgspluginmanager.h qgspythondialog.h Index: src/app/qgisapp.cpp =================================================================== --- src/app/qgisapp.cpp (révision 10043) +++ src/app/qgisapp.cpp (copie de travail) @@ -98,6 +98,7 @@ #include "qgscursors.h" #include "qgscustomprojectiondialog.h" #include "qgsencodingfiledialog.h" +#include "qgsogrsublayersdialog.h" #include "qgsexception.h" #include "qgsfeature.h" #include "qgsgeomtypedialog.h" @@ -800,7 +801,7 @@ mActionLayerSelectionSaveAs->setStatusTip( tr( "Save the selection as a shapefile" ) ); connect( mActionLayerSelectionSaveAs, SIGNAL( triggered() ), this, SLOT( saveSelectionAsShapefile() ) ); mActionLayerSelectionSaveAs->setEnabled( false ); - + mActionRemoveLayer = new QAction( getThemeIcon( "mActionRemoveLayer.png" ), tr( "Remove Layer" ), this ); mActionRemoveLayer->setShortcut( tr( "Ctrl+D", "Remove a Layer" ) ); mActionRemoveLayer->setStatusTip( tr( "Remove a Layer" ) ); @@ -2168,11 +2169,30 @@ { layer->setProviderEncoding( enc ); - // Register this layer with the layers registry - QgsMapLayerRegistry::instance()->addMapLayer( layer ); - // notify the project we've made a change - QgsProject::instance()->dirty( true ); + // The next cast is possible because we know that the provider was ogr and it is + // necessary because the QgsMapLayer subLayers method returns an empty QStringList. + // We have to get down to the actual provider to get the approriate list. + QgsOgrProvider* theCurrentProvider = ( QgsOgrProvider * )( layer->dataProvider()); + QStringList liste = theCurrentProvider->subLayers(); + + // If the newly created layer has more than 1 layer of data available, we show the + // sublayers selection dialog so the user can select the sublayers to actually load. + if ( liste.count() > 1) + { + askUserForSublayers(layer); + + // The first layer loaded is not usefull in that case. The user can select it in + // the list if he wants to load it. + delete layer; + + }else // there is 1 layer of data available + { + // Register this layer with the layers registry + QgsMapLayerRegistry::instance()->addMapLayer( layer ); + // notify the project we've made a change + QgsProject::instance()->dirty( true ); + } } else { @@ -2203,8 +2223,52 @@ return true; } // QgisApp::addVectorLayer() +// This method is the method that does the real job. If the layer given in +// parameter is NULL, then the method tries to act on the activeLayer. +void QgisApp::askUserForSublayers(QgsVectorLayer *layer) +{ + if (NULL == layer) + { + if (mQgisInterface->activeLayer() && + mQgisInterface->activeLayer()->type() == QgsMapLayer::VectorLayer && + 0 == (( QgsVectorLayer *)mQgisInterface->activeLayer())->dataProvider()->name().compare("ogr")) + { + layer=(QgsVectorLayer*)(mQgisInterface->activeLayer()); + } + else return; + } + QgsOgrProvider* theCurrentProvider = ( QgsOgrProvider * )( layer->dataProvider()); + QStringList liste = theCurrentProvider->subLayers(); + QgsOGRSublayersDialog *chooseSublayersDialog; + // We initialize a selection dialog and display it. + chooseSublayersDialog = new QgsOGRSublayersDialog(this , QgisGui::ModalDialogFlags ); + chooseSublayersDialog->setURI(layer-> source()); + chooseSublayersDialog->setAttribute( Qt::WA_DeleteOnClose ); + chooseSublayersDialog->show(); + chooseSublayersDialog->populateLayerTable( & liste ); + // We want to get the signal from this dialog when the user has done his choice + connect( chooseSublayersDialog, SIGNAL( updated(QString, QStringList * ) ), this, SLOT( loadOGRSublayers(QString, QStringList * ) ) ); +} + +// This method will load with OGR the layers in parameter. +// This method has been conceived to use the new URI +// format of the ogrprovider so as to give precisions about which +// sublayer to load into QGIS. It is normally triggered by the +// sublayer selection dialog. +void QgisApp::loadOGRSublayers( QString uri, QStringList *list) +{ + // The uri must contain the actual uri of the vectorLayer from which we are + // going to load the sublayers. + QString fileName = QFileInfo(uri).baseName(); + for (int i = 0; i < list->size(); i++) + { + QString composedURI=uri+"&layername="+list->at(i); + QgsVectorLayer *layer=addVectorLayer(composedURI,fileName+":"+list->at(i),"ogr"); + } +} + /** This helper checks to see whether the file name appears to be a valid vector file name */ bool QgisApp::isValidVectorFileName( QString theFileNameQString ) { Index: src/app/qgsogrsublayersdialog.h =================================================================== --- src/app/qgsogrsublayersdialog.h (révision 0) +++ src/app/qgsogrsublayersdialog.h (révision 0) @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 2003 by Tim Sutton * + * tim@linfiniti.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef QGSOGRSUBLAYERSDIALOG_H +#define QGSOGRSUBLAYERSDIALOG_H + +#include +#include +#include + +#include + +/** +@author Tim Sutton +*/ +class QgsOGRSublayersDialog : public QDialog, private Ui::QgsOGRSublayersDialogBase +{ + Q_OBJECT + public: + QgsOGRSublayersDialog( QWidget* parent = 0, Qt::WFlags fl = 0 ); + ~QgsOGRSublayersDialog(); + void populateLayerTable (QStringList *theList); + QStringList * getSelection (); + void setURI(QString uri); + + private: + static const int context_id = 0; + QString mURI; + + private slots: + void on_buttonBox_accepted(); + void on_buttonBox_rejected(); + + signals: + void updated(QString uri, QStringList*list); + +}; + +#endif Index: src/providers/ogr/qgsogrprovider.h =================================================================== --- src/providers/ogr/qgsogrprovider.h (révision 10043) +++ src/providers/ogr/qgsogrprovider.h (copie de travail) @@ -47,6 +47,13 @@ virtual QgsCoordinateReferenceSystem crs(); + /** + * Sub-layers handled by this provider, in order from bottom to top + * + * Sub-layers are used when the provider's source can combine layers + * it knows about in some way before it hands them off to the provider. + */ + virtual QStringList subLayers(); /** * Returns the permanent storage type for this layer as a friendly name. @@ -181,14 +188,6 @@ * @param index the index of the attribute * @param values reference to the list of unique values */ virtual void uniqueValues( int index, QList &uniqueValues ); - - protected: - /** loads fields from input file to member attributeFields */ - void loadFields(); - - /**Get an attribute associated with a feature*/ - void getFeatureAttribute( OGRFeatureH ogrFet, QgsFeature & f, int attindex ); - /** return a provider name Essentially just returns the provider key. Should be used to build file @@ -219,7 +218,15 @@ */ QString description() const; + protected: + /** loads fields from input file to member attributeFields */ + void loadFields(); + /**Get an attribute associated with a feature*/ + void getFeatureAttribute( OGRFeatureH ogrFet, QgsFeature & f, int attindex ); + + + private: unsigned char *getGeometryPointer( OGRFeatureH fet ); @@ -247,7 +254,6 @@ //! Selection rectangle OGRGeometryH mSelectionRectangle; - /**Adds one feature*/ bool addFeature( QgsFeature& f ); /**Deletes one feature*/ Index: src/providers/ogr/qgsogrprovider.cpp =================================================================== --- src/providers/ogr/qgsogrprovider.cpp (révision 10043) +++ src/providers/ogr/qgsogrprovider.cpp (copie de travail) @@ -73,14 +73,61 @@ // try to open for update, but disable error messages to avoid a // message if the file is read only, because we cope with that // ourselves. + + // This part of the code parses the uri transmitted to the ogr provider to + // get the options the client wants us to apply + + QString mFilePath; + QString theLayerName; + int theLayerIndex=0; + + // If there is no & in the uri, then the uri is just the filename. The loaded + // layer will be layer 0. + if ( ! uri.contains('&', Qt::CaseSensitive)) + { + mFilePath = uri; + } + else + { + // If we get here, there are some options added to the filename. We must parse + // the different parts separated by &, and among each option, the name and the + // value around the =. + // A valid uri is of the form: filename&option1=value1&option2=value2,... + + QStringList theURIParts = uri.split("&"); + mFilePath = theURIParts.at( 0 ); + + for (int i = 1 ; i < theURIParts.size(); i++ ) + { + QStringList theInstruction = theURIParts.at( i ).split( "=" ); + if ( 0 == theInstruction.at( 0 ).compare( QString( "layerid" ))) + { + bool ok; + theLayerIndex = theInstruction.at( 1 ).toInt( &ok ); + if ( ! ok ) + { + theLayerIndex = 0; + } + } + if ( 0 == theInstruction.at( 0 ).compare( QString( "layername" ))) + { + theLayerName = theInstruction.at( 1 ); + } + } + } + + QgsLogger::debug("[OGR] mFilePath: " + mFilePath); + QgsLogger::debug("[OGR] theLayerIndex: "+theLayerIndex); + QgsLogger::debug("[OGR] theLayerName: "+theLayerName); + CPLPushErrorHandler( CPLQuietErrorHandler ); - ogrDataSource = OGROpen( QFile::encodeName( uri ).constData(), TRUE, &ogrDriver ); + ogrDataSource = OGROpen( QFile::encodeName( mFilePath ).constData(), TRUE, &ogrDriver ); CPLPopErrorHandler(); if ( ogrDataSource == NULL ) { // try to open read-only - ogrDataSource = OGROpen( QFile::encodeName( uri ).constData(), FALSE, &ogrDriver ); + ogrDataSource = OGROpen( QFile::encodeName( mFilePath ).constData(), FALSE, &ogrDriver ); //TODO Need to set a flag or something to indicate that the layer //TODO is in read-only mode, otherwise edit ops will fail @@ -95,9 +142,17 @@ valid = true; ogrDriverName = OGR_Dr_GetName( ogrDriver ); + + // We get the layer which was requested by the uri. The layername + // has precedence over the layerid if both are given. + if ( NULL == theLayerName ) + { + ogrLayer = OGR_DS_GetLayer( ogrDataSource, theLayerIndex ); + }else + { + ogrLayer = OGR_DS_GetLayerByName( ogrDataSource, (char*)(theLayerName.toLocal8Bit().data()) ); + } - ogrLayer = OGR_DS_GetLayer( ogrDataSource, 0 ); - // get the extent_ (envelope) of the layer QgsDebugMsg( "Starting get extent" ); @@ -145,6 +200,67 @@ } } +QStringList QgsOgrProvider::subLayers() +{ + QStringList theList = QStringList(); + if (! valid ) + { + return theList; + } + for ( int i = 0; i < layerCount() ; i++ ) + { + QString theLayerName = QString(OGR_FD_GetName(OGR_L_GetLayerDefn(OGR_DS_GetLayer( ogrDataSource, i )))); + QGis::WkbType layerGeomType = (QGis::WkbType)(OGR_FD_GetGeomType(OGR_L_GetLayerDefn(OGR_DS_GetLayer( ogrDataSource, i )))); + + int theLayerFeatureCount=OGR_L_GetFeatureCount(OGR_DS_GetLayer( ogrDataSource, i ),1) ; + + QString geom; + switch (layerGeomType) + { + case QGis::WKBPoint: + geom="WKBPoint"; + break; + case QGis::WKBLineString: + geom="WKBLineString"; + break; + case QGis::WKBPolygon: + geom="WKBPolygon"; + break; + case QGis::WKBMultiPoint: + geom="WKBMultiPoint"; + break; + case QGis::WKBMultiLineString: + geom="WKBMultiLineString"; + break; + case QGis::WKBUnknown: + geom="WKBUnknown"; + break; + case QGis::WKBPoint25D: + geom="WKBPoint25D"; + break; + case QGis::WKBLineString25D: + geom="WKBLineString25D"; + break; + case QGis::WKBPolygon25D: + geom="WKBPolygon25D"; + break; + case QGis::WKBMultiPoint25D: + geom="WKBMultiPoint25D"; + break; + case QGis::WKBMultiLineString25D: + geom="WKBMultiLineString25D"; + break; + case QGis::WKBMultiPolygon25D: + geom="WKBMultiPolygon25D"; + break; + default: + geom="Unknown OGR geometry ID->" + QString::number(layerGeomType); + } + theList.append(QString::number(i)+":"+ theLayerName+":"+QString::number(theLayerFeatureCount)+":"+geom); + } + return theList; +} + void QgsOgrProvider::setEncoding( const QString& e ) { QgsVectorDataProvider::setEncoding( e ); Index: src/ui/qgsogrsublayersdialogbase.ui =================================================================== --- src/ui/qgsogrsublayersdialogbase.ui (révision 0) +++ src/ui/qgsogrsublayersdialogbase.ui (révision 0) @@ -0,0 +1,111 @@ + + QgsOGRSublayersDialogBase + + + + 0 + 0 + 584 + 535 + + + + Select OGR layers to load + + + ../../../qgis_1.0.0/src/plugins/ogrsublayers + + + + 9 + + + 9 + + + 9 + + + 9 + + + 6 + + + 6 + + + + + + 0 + 0 + + + + + Sans Serif + 24 + 75 + false + true + false + false + + + + Sub layers list + + + Qt::AlignCenter + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok + + + + + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is the list of all layers available in the datasource of the active layer. You can select the layers to load. The layers will be loaded when you press "OK".</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The layer name is format dependant. Consult the OGR documentation or the documentation of your data format to determine the nature of the included information.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Be advised: </span>selecting an already opened layer will not generate an error message and the layer will end up loaded twice!</p></body></html> + + + + + + + Qt::NonModal + + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectRows + + + + 1 + + + + + + + + + +