Skip to content

Commit

Permalink
Applied patch from ticket #767 by Florian El Ahdab.
Browse files Browse the repository at this point in the history
Thanks for the contribution!

I've slightly modified the patch to simplify some pieces of code.


git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@10065 c8812cc2-4d05-0410-92ff-de0c093fc19c
  • Loading branch information
wonder committed Jan 31, 2009
1 parent 6f94dbb commit 70bbe63
Show file tree
Hide file tree
Showing 9 changed files with 430 additions and 18 deletions.
1 change: 1 addition & 0 deletions CONTRIBUTORS
Expand Up @@ -11,6 +11,7 @@ Carlos Dávila
Christian Ferreira
Faunalia (http://www.faunalia.it)
Fernando Pacheco
Florian El Ahdab
Frank Warmerdam
Hyao (IRC nickname)
Jean-Denis Giguere
Expand Down
2 changes: 2 additions & 0 deletions src/app/CMakeLists.txt
Expand Up @@ -39,6 +39,7 @@ SET(QGIS_APP_SRCS
qgsmeasuretool.cpp
qgsnewhttpconnection.cpp
qgsnumericsortlistviewitem.cpp
qgsogrsublayersdialog.cpp
qgsoptions.cpp
qgspastetransformations.cpp
qgspluginitem.cpp
Expand Down Expand Up @@ -113,6 +114,7 @@ SET (QGIS_APP_MOC_HDRS
qgsmeasuredialog.h
qgsnewhttpconnection.h
qgsoptions.h
qgsogrsublayersdialog.h
qgspastetransformations.h
qgspluginmanager.h
qgspythondialog.h
Expand Down
77 changes: 72 additions & 5 deletions src/app/qgisapp.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -800,7 +801,7 @@ void QgisApp::createActions()
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" ) );
Expand Down Expand Up @@ -2168,11 +2169,25 @@ bool QgisApp::addVectorLayers( QStringList const & theLayerQStringList, const QS
{
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 );
QStringList sublayers = layer->dataProvider()->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 ( sublayers.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
{
Expand Down Expand Up @@ -2203,7 +2218,59 @@ bool QgisApp::addVectorLayers( QStringList const & theLayerQStringList, const QS
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 (layer == NULL)
{
if (activeLayer() == NULL || activeLayer()->type() != QgsMapLayer::VectorLayer)
return;

layer = (QgsVectorLayer*) activeLayer();
if (layer->dataProvider()->name() != "ogr")
return;
}

QStringList sublayers = layer->dataProvider()->subLayers();

// We initialize a selection dialog and display it.
QgsOGRSublayersDialog chooseSublayersDialog( this );
chooseSublayersDialog.populateLayerTable( sublayers );

if (chooseSublayersDialog.exec())
{
QString uri = layer->source();
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 );
}

// the user has done his choice
loadOGRSublayers(uri, chooseSublayersDialog.getSelection());
}
}

// 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 )
Expand Down
7 changes: 7 additions & 0 deletions src/app/qgisapp.h
Expand Up @@ -63,6 +63,7 @@ class QgsVectorLayer;
#include "qgsconfig.h"
#include "qgspoint.h"


/*! \class QgisApp
* \brief Main window for the Qgis application
*/
Expand Down Expand Up @@ -342,6 +343,8 @@ class QgisApp : public QMainWindow
*/
void editPaste( QgsMapLayer * destinationLayer = 0 );

void loadOGRSublayers( QString uri, QStringList list );

protected:

//! Handle state changes (WindowTitleChange)
Expand Down Expand Up @@ -594,6 +597,10 @@ class QgisApp : public QMainWindow
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.
*/
Expand Down
54 changes: 54 additions & 0 deletions src/app/qgsogrsublayersdialog.cpp
@@ -0,0 +1,54 @@
/***************************************************************************
qgsogrsublayersdialog.cpp - dialog for selecting ogr sublayers
---------------------
begin : January 2009
copyright : (C) 2009 by Florian El Ahdab
email : felahdab at gmail dot 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. *
* *
***************************************************************************/
/* $Id$ */

#include "qgsogrsublayersdialog.h"

#include <QTableWidgetItem>


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()
{
}

QStringList QgsOGRSublayersDialog::getSelection()
{
QStringList list=QStringList();
for (int i = 0; i < layersTable-> selectedItems().size(); i++)
{
QString theItem =layersTable-> selectedItems().at(i)->text(1);
list.append(theItem);
}
return list;
}

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));
}
}
36 changes: 36 additions & 0 deletions src/app/qgsogrsublayersdialog.h
@@ -0,0 +1,36 @@
/***************************************************************************
qgsogrsublayersdialog.h - dialog for selecting ogr sublayers
---------------------
begin : January 2009
copyright : (C) 2009 by Florian El Ahdab
email : felahdab at gmail dot 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. *
* *
***************************************************************************/
/* $Id$ */

#ifndef QGSOGRSUBLAYERSDIALOG_H
#define QGSOGRSUBLAYERSDIALOG_H

#include <QDialog>
#include <ui_qgsogrsublayersdialogbase.h>



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();

};

#endif
102 changes: 98 additions & 4 deletions src/providers/ogr/qgsogrprovider.cpp
Expand Up @@ -73,14 +73,61 @@ QgsOgrProvider::QgsOgrProvider( QString const & uri )
// 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 ( theInstruction.at( 0 ) == QString( "layerid" ) )
{
bool ok;
theLayerIndex = theInstruction.at( 1 ).toInt( &ok );
if ( ! ok )
{
theLayerIndex = 0;
}
}
if ( theInstruction.at( 0 ) == QString( "layername" ) )
{
theLayerName = theInstruction.at( 1 );
}
}
}

QgsDebugMsg("mFilePath: " + mFilePath);
QgsDebugMsg("theLayerIndex: "+theLayerIndex);
QgsDebugMsg("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
Expand All @@ -95,8 +142,17 @@ QgsOgrProvider::QgsOgrProvider( QString const & uri )
valid = true;

ogrDriverName = OGR_Dr_GetName( ogrDriver );

ogrLayer = OGR_DS_GetLayer( ogrDataSource, 0 );

// We get the layer which was requested by the uri. The layername
// has precedence over the layerid if both are given.
if ( theLayerName.isNull() )
{
ogrLayer = OGR_DS_GetLayer( ogrDataSource, theLayerIndex );
}
else
{
ogrLayer = OGR_DS_GetLayerByName( ogrDataSource, (char*)(theLayerName.toLocal8Bit().data()) );
}

// get the extent_ (envelope) of the layer

Expand Down Expand Up @@ -145,6 +201,44 @@ QgsOgrProvider::~QgsOgrProvider()
}
}

QStringList QgsOgrProvider::subLayers() const
{
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 ))));
OGRwkbGeometryType layerGeomType = 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 wkbUnknown: geom = "Unknown"; break;
case wkbPoint: geom="Point"; break;
case wkbLineString: geom="LineString"; break;
case wkbPolygon: geom="Polygon"; break;
case wkbMultiPoint: geom="MultiPoint"; break;
case wkbMultiLineString: geom="MultiLineString"; break;
case wkbGeometryCollection: geom = "GeometryCollection"; break;
case wkbNone: geom = "None"; break;
case wkbPoint25D: geom="Point25D"; break;
case wkbLineString25D: geom="LineString25D"; break;
case wkbPolygon25D: geom="Polygon25D"; break;
case wkbMultiPoint25D: geom="MultiPoint25D"; break;
case wkbMultiLineString25D: geom="MultiLineString25D"; break;
case wkbMultiPolygon25D: geom="MultiPolygon25D"; break;
default: geom="Unknown WKB: " + QString::number(layerGeomType);
}
theList.append(QString::number(i)+":"+ theLayerName+":"+QString::number(theLayerFeatureCount)+":"+geom);
}
return theList;
}

void QgsOgrProvider::setEncoding( const QString& e )
{
QgsVectorDataProvider::setEncoding( e );
Expand Down

0 comments on commit 70bbe63

Please sign in to comment.