Skip to content
Permalink
Browse files
Applied patch from ticket #767 by Florian El Ahdab.
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.
@@ -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
@@ -39,6 +39,7 @@ SET(QGIS_APP_SRCS
qgsmeasuretool.cpp
qgsnewhttpconnection.cpp
qgsnumericsortlistviewitem.cpp
qgsogrsublayersdialog.cpp
qgsoptions.cpp
qgspastetransformations.cpp
qgspluginitem.cpp
@@ -113,6 +114,7 @@ SET (QGIS_APP_MOC_HDRS
qgsmeasuredialog.h
qgsnewhttpconnection.h
qgsoptions.h
qgsogrsublayersdialog.h
qgspastetransformations.h
qgspluginmanager.h
qgspythondialog.h
@@ -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 @@ 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" ) );
@@ -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
{
@@ -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 )
@@ -63,6 +63,7 @@ class QgsVectorLayer;
#include "qgsconfig.h"
#include "qgspoint.h"


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

void loadOGRSublayers( QString uri, QStringList list );

protected:

//! Handle state changes (WindowTitleChange)
@@ -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.
*/
@@ -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));
}
}
@@ -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
@@ -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
@@ -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

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

0 comments on commit 70bbe63

Please sign in to comment.