From b28c910186303cc2726a7a3a873f1203d52022a9 Mon Sep 17 00:00:00 2001 From: Martin Dobias Date: Tue, 18 Oct 2011 22:49:08 -0300 Subject: [PATCH] Separate OGR data items from provider code --- src/providers/ogr/CMakeLists.txt | 4 +- src/providers/ogr/qgsogrdataitems.cpp | 284 ++++++++++++++++++++++++++ src/providers/ogr/qgsogrdataitems.h | 43 ++++ src/providers/ogr/qgsogrprovider.cpp | 260 +---------------------- src/providers/ogr/qgsogrprovider.h | 35 ++-- 5 files changed, 344 insertions(+), 282 deletions(-) create mode 100644 src/providers/ogr/qgsogrdataitems.cpp create mode 100644 src/providers/ogr/qgsogrdataitems.h diff --git a/src/providers/ogr/CMakeLists.txt b/src/providers/ogr/CMakeLists.txt index 609376ac7c41..2c727b27ecb4 100644 --- a/src/providers/ogr/CMakeLists.txt +++ b/src/providers/ogr/CMakeLists.txt @@ -1,7 +1,7 @@ -SET (OGR_SRCS qgsogrprovider.cpp) +SET (OGR_SRCS qgsogrprovider.cpp qgsogrdataitems.cpp) -SET(OGR_MOC_HDRS qgsogrprovider.h) +SET(OGR_MOC_HDRS qgsogrprovider.h qgsogrdataitems.h) ######################################################## # Build diff --git a/src/providers/ogr/qgsogrdataitems.cpp b/src/providers/ogr/qgsogrdataitems.cpp new file mode 100644 index 000000000000..7b7c29da5a9c --- /dev/null +++ b/src/providers/ogr/qgsogrdataitems.cpp @@ -0,0 +1,284 @@ +/*************************************************************************** + qgsogrdataitems.cpp + ------------------- + begin : 2011-04-01 + copyright : (C) 2011 Radim Blazek + email : radim dot blazek 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. * + * * + ***************************************************************************/ + +#include "qgsogrdataitems.h" + +#include "qgslogger.h" + +#include +#include + +#include +#include +#include + +// these are defined in qgsogrprovider.cpp +QGISEXTERN QStringList fileExtensions(); +QGISEXTERN QStringList wildcards(); + + +QgsOgrLayerItem::QgsOgrLayerItem( QgsDataItem* parent, + QString name, QString path, QString uri, LayerType layerType ) + : QgsLayerItem( parent, name, path, uri, layerType, "ogr" ) +{ + mToolTip = uri; + mPopulated = true; // children are not expected +} + +QgsOgrLayerItem::~QgsOgrLayerItem() +{ +} + +QgsLayerItem::Capability QgsOgrLayerItem::capabilities() +{ + QgsDebugMsg( "mPath = " + mPath ); + OGRRegisterAll(); + OGRSFDriverH hDriver; + OGRDataSourceH hDataSource = OGROpen( TO8F( mPath ), true, &hDriver ); + + if ( !hDataSource ) + return NoCapabilities; + + QString driverName = OGR_Dr_GetName( hDriver ); + OGR_DS_Destroy( hDataSource ); + + if ( driverName == "ESRI Shapefile" ) + return SetCrs; + + return NoCapabilities; +} + +bool QgsOgrLayerItem::setCrs( QgsCoordinateReferenceSystem crs ) +{ + QgsDebugMsg( "mPath = " + mPath ); + OGRRegisterAll(); + OGRSFDriverH hDriver; + OGRDataSourceH hDataSource = OGROpen( TO8F( mPath ), true, &hDriver ); + + if ( !hDataSource ) + return false; + + QString driverName = OGR_Dr_GetName( hDriver ); + OGR_DS_Destroy( hDataSource ); + + // we are able to assign CRS only to shapefiles :-( + if ( driverName == "ESRI Shapefile" ) + { + QString layerName = mPath.left( mPath.indexOf( ".shp", Qt::CaseInsensitive ) ); + QString wkt = crs.toWkt(); + + // save ordinary .prj file + OGRSpatialReferenceH hSRS = OSRNewSpatialReference( wkt.toLocal8Bit().data() ); + OSRMorphToESRI( hSRS ); // this is the important stuff for shapefile .prj + char* pszOutWkt = NULL; + OSRExportToWkt( hSRS, &pszOutWkt ); + QFile prjFile( layerName + ".prj" ); + if ( prjFile.open( QIODevice::WriteOnly ) ) + { + QTextStream prjStream( &prjFile ); + prjStream << pszOutWkt << endl; + prjFile.close(); + } + else + { + QgsDebugMsg( "Couldn't open file " + layerName + ".prj" ); + return false; + } + OSRDestroySpatialReference( hSRS ); + CPLFree( pszOutWkt ); + + // save qgis-specific .qpj file (maybe because of better wkt compatibility?) + QFile qpjFile( layerName + ".qpj" ); + if ( qpjFile.open( QIODevice::WriteOnly ) ) + { + QTextStream qpjStream( &qpjFile ); + qpjStream << wkt.toLocal8Bit().data() << endl; + qpjFile.close(); + } + else + { + QgsDebugMsg( "Couldn't open file " + layerName + ".qpj" ); + return false; + } + + return true; + } + + // It it is impossible to assign a crs to an existing layer + // No OGR_L_SetSpatialRef : http://trac.osgeo.org/gdal/ticket/4032 + return false; +} + +// ------- + +static QgsOgrLayerItem* dataItemForLayer( QgsDataItem* parentItem, QString name, QString path, OGRDataSourceH hDataSource, int layerId ) +{ + OGRLayerH hLayer = OGR_DS_GetLayer( hDataSource, layerId ); + OGRFeatureDefnH hDef = OGR_L_GetLayerDefn( hLayer ); + + QgsLayerItem::LayerType layerType = QgsLayerItem::Vector; + int ogrType = QgsOgrProvider::getOgrGeomType( hLayer ); + switch ( ogrType ) + { + case wkbUnknown: + case wkbGeometryCollection: + break; + case wkbNone: + layerType = QgsLayerItem::TableLayer; + break; + case wkbPoint: + case wkbMultiPoint: + case wkbPoint25D: + case wkbMultiPoint25D: + layerType = QgsLayerItem::Point; + break; + case wkbLineString: + case wkbMultiLineString: + case wkbLineString25D: + case wkbMultiLineString25D: + layerType = QgsLayerItem::Line; + break; + case wkbPolygon: + case wkbMultiPolygon: + case wkbPolygon25D: + case wkbMultiPolygon25D: + layerType = QgsLayerItem::Polygon; + break; + default: + break; + } + + QgsDebugMsg( QString( "ogrType = %1 layertype = %2" ).arg( ogrType ).arg( layerType ) ); + + QString layerUri = path; + + if ( name.isEmpty() ) + { + // we are in a collection + name = FROM8( OGR_FD_GetName( hDef ) ); + QgsDebugMsg( "OGR layer name : " + name ); + + layerUri += "|layerid=" + QString::number( layerId ); + + path += "/" + name; + } + + QgsDebugMsg( "OGR layer uri : " + layerUri ); + + return new QgsOgrLayerItem( parentItem, name, path, layerUri, layerType ); +} + +// ---- + +QgsOgrDataCollectionItem::QgsOgrDataCollectionItem( QgsDataItem* parent, QString name, QString path ) + : QgsDataCollectionItem( parent, name, path ) +{ +} + +QgsOgrDataCollectionItem::~QgsOgrDataCollectionItem() +{ +} + +QVector QgsOgrDataCollectionItem::createChildren() +{ + QVector children; + + OGRSFDriverH hDriver; + OGRDataSourceH hDataSource = OGROpen( TO8F( mPath ), false, &hDriver ); + if ( !hDataSource ) + return children; + int numLayers = OGR_DS_GetLayerCount( hDataSource ); + + for ( int i = 0; i < numLayers; i++ ) + { + QgsOgrLayerItem* item = dataItemForLayer( this, QString(), mPath, hDataSource, i ); + children.append( item ); + } + + OGR_DS_Destroy( hDataSource ); + + return children; +} + +// --------------------------------------------------------------------------- + +QGISEXTERN int dataCapabilities() +{ + return QgsDataProvider::File | QgsDataProvider::Dir; +} + +QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem ) +{ + if ( thePath.isEmpty() ) + return 0; + + QFileInfo info( thePath ); + if ( !info.isFile() ) + return 0; + + // We have to filter by extensions, otherwise e.g. all Shapefile files are displayed + // because OGR drive can open also .dbf, .shx. + QStringList myExtensions = fileExtensions(); + if ( myExtensions.indexOf( info.suffix().toLower() ) < 0 ) + { + bool matches = false; + foreach( QString wildcard, wildcards() ) + { + QRegExp rx( wildcard, Qt::CaseInsensitive, QRegExp::Wildcard ); + if ( rx.exactMatch( info.fileName() ) ) + { + matches = true; + break; + } + } + if ( !matches ) + return 0; + } + + // .dbf should probably appear if .shp is not present + if ( info.suffix().toLower() == "dbf" ) + { + QString pathShp = thePath.left( thePath.count() - 4 ) + ".shp"; + if ( QFileInfo( pathShp ).exists() ) + return 0; + } + + OGRRegisterAll(); + OGRSFDriverH hDriver; + OGRDataSourceH hDataSource = OGROpen( TO8F( thePath ), false, &hDriver ); + + if ( !hDataSource ) + return 0; + + QString driverName = OGR_Dr_GetName( hDriver ); + QgsDebugMsg( "OGR Driver : " + driverName ); + + int numLayers = OGR_DS_GetLayerCount( hDataSource ); + + QgsDataItem* item = 0; + + if ( numLayers == 1 ) + { + QString name = info.completeBaseName(); + item = dataItemForLayer( parentItem, name, thePath, hDataSource, 0 ); + } + else if ( numLayers > 1 ) + { + item = new QgsOgrDataCollectionItem( parentItem, info.fileName(), thePath ); + } + + OGR_DS_Destroy( hDataSource ); + return item; +} diff --git a/src/providers/ogr/qgsogrdataitems.h b/src/providers/ogr/qgsogrdataitems.h new file mode 100644 index 000000000000..53d860771431 --- /dev/null +++ b/src/providers/ogr/qgsogrdataitems.h @@ -0,0 +1,43 @@ +/*************************************************************************** + qgsogrdataitems.h + ------------------- + begin : 2011-04-01 + copyright : (C) 2011 Radim Blazek + email : radim dot blazek 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. * + * * + ***************************************************************************/ + +#ifndef QGSOGRDATAITEMS_H +#define QGSOGRDATAITEMS_H + +#include "qgsdataitem.h" +#include "qgsogrprovider.h" + +class QgsOgrLayerItem : public QgsLayerItem +{ + Q_OBJECT + public: + QgsOgrLayerItem( QgsDataItem* parent, QString name, QString path, QString uri, LayerType layerType ); + ~QgsOgrLayerItem(); + + bool setCrs( QgsCoordinateReferenceSystem crs ); + Capability capabilities(); +}; + +class QgsOgrDataCollectionItem : public QgsDataCollectionItem +{ + Q_OBJECT + public: + QgsOgrDataCollectionItem( QgsDataItem* parent, QString name, QString path ); + ~QgsOgrDataCollectionItem(); + + QVector createChildren(); +}; + +#endif // QGSOGRDATAITEMS_H diff --git a/src/providers/ogr/qgsogrprovider.cpp b/src/providers/ogr/qgsogrprovider.cpp index 89e475943d51..341bb1785094 100644 --- a/src/providers/ogr/qgsogrprovider.cpp +++ b/src/providers/ogr/qgsogrprovider.cpp @@ -53,15 +53,6 @@ static const QString TEXT_PROVIDER_DESCRIPTION = + GDALVersionInfo( "RELEASE_NAME" ) + ")"; -#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1800 -#define TO8(x) (x).toUtf8().constData() -#define TO8F(x) (x).toUtf8().constData() -#define FROM8(x) QString::fromUtf8(x) -#else -#define TO8(x) (x).toLocal8Bit().constData() -#define TO8F(x) QFile::encodeName( x ).constData() -#define FROM8(x) QString::fromLocal8Bit(x) -#endif class QgsCPLErrorHandler { @@ -470,7 +461,7 @@ void QgsOgrProvider::setEncoding( const QString& e ) } // This is reused by dataItem -int getOgrGeomType( OGRLayerH ogrLayer ) +int QgsOgrProvider::getOgrGeomType( OGRLayerH ogrLayer ) { OGRFeatureDefnH fdef = OGR_L_GetLayerDefn( ogrLayer ); int geomType = wkbUnknown; @@ -2262,254 +2253,7 @@ void QgsOgrProvider::recalculateFeatureCount() } } -QGISEXTERN int dataCapabilities() -{ - return QgsDataProvider::File | QgsDataProvider::Dir; -} - -QgsOgrLayerItem::QgsOgrLayerItem( QgsDataItem* parent, - QString name, QString path, QString uri, LayerType layerType ) - : QgsLayerItem( parent, name, path, uri, layerType, "ogr" ) -{ - mToolTip = uri; - mPopulated = true; // children are not expected -} - -QgsOgrLayerItem::~QgsOgrLayerItem() -{ -} - -QgsLayerItem::Capability QgsOgrLayerItem::capabilities() -{ - QgsDebugMsg( "mPath = " + mPath ); - OGRRegisterAll(); - OGRSFDriverH hDriver; - OGRDataSourceH hDataSource = OGROpen( TO8F( mPath ), true, &hDriver ); - - if ( !hDataSource ) - return NoCapabilities; - - QString driverName = OGR_Dr_GetName( hDriver ); - OGR_DS_Destroy( hDataSource ); - - if ( driverName == "ESRI Shapefile" ) - return SetCrs; - - return NoCapabilities; -} - -bool QgsOgrLayerItem::setCrs( QgsCoordinateReferenceSystem crs ) -{ - QgsDebugMsg( "mPath = " + mPath ); - OGRRegisterAll(); - OGRSFDriverH hDriver; - OGRDataSourceH hDataSource = OGROpen( TO8F( mPath ), true, &hDriver ); - - if ( !hDataSource ) - return false; - - QString driverName = OGR_Dr_GetName( hDriver ); - OGR_DS_Destroy( hDataSource ); - - // we are able to assign CRS only to shapefiles :-( - if ( driverName == "ESRI Shapefile" ) - { - QString layerName = mPath.left( mPath.indexOf( ".shp", Qt::CaseInsensitive ) ); - QString wkt = crs.toWkt(); - - // save ordinary .prj file - OGRSpatialReferenceH hSRS = OSRNewSpatialReference( wkt.toLocal8Bit().data() ); - OSRMorphToESRI( hSRS ); // this is the important stuff for shapefile .prj - char* pszOutWkt = NULL; - OSRExportToWkt( hSRS, &pszOutWkt ); - QFile prjFile( layerName + ".prj" ); - if ( prjFile.open( QIODevice::WriteOnly ) ) - { - QTextStream prjStream( &prjFile ); - prjStream << pszOutWkt << endl; - prjFile.close(); - } - else - { - QgsDebugMsg( "Couldn't open file " + layerName + ".prj" ); - return false; - } - OSRDestroySpatialReference( hSRS ); - CPLFree( pszOutWkt ); - - // save qgis-specific .qpj file (maybe because of better wkt compatibility?) - QFile qpjFile( layerName + ".qpj" ); - if ( qpjFile.open( QIODevice::WriteOnly ) ) - { - QTextStream qpjStream( &qpjFile ); - qpjStream << wkt.toLocal8Bit().data() << endl; - qpjFile.close(); - } - else - { - QgsDebugMsg( "Couldn't open file " + layerName + ".qpj" ); - return false; - } - - return true; - } - - // It it is impossible to assign a crs to an existing layer - // No OGR_L_SetSpatialRef : http://trac.osgeo.org/gdal/ticket/4032 - return false; -} - - -static QgsOgrLayerItem* dataItemForLayer( QgsDataItem* parentItem, QString name, QString path, OGRDataSourceH hDataSource, int layerId ) -{ - OGRLayerH hLayer = OGR_DS_GetLayer( hDataSource, layerId ); - OGRFeatureDefnH hDef = OGR_L_GetLayerDefn( hLayer ); - - QgsLayerItem::LayerType layerType = QgsLayerItem::Vector; - int ogrType = getOgrGeomType( hLayer ); - switch ( ogrType ) - { - case wkbUnknown: - case wkbGeometryCollection: - break; - case wkbNone: - layerType = QgsLayerItem::TableLayer; - break; - case wkbPoint: - case wkbMultiPoint: - case wkbPoint25D: - case wkbMultiPoint25D: - layerType = QgsLayerItem::Point; - break; - case wkbLineString: - case wkbMultiLineString: - case wkbLineString25D: - case wkbMultiLineString25D: - layerType = QgsLayerItem::Line; - break; - case wkbPolygon: - case wkbMultiPolygon: - case wkbPolygon25D: - case wkbMultiPolygon25D: - layerType = QgsLayerItem::Polygon; - break; - default: - break; - } - - QgsDebugMsg( QString( "ogrType = %1 layertype = %2" ).arg( ogrType ).arg( layerType ) ); - - QString layerUri = path; - - if ( name.isEmpty() ) - { - // we are in a collection - name = FROM8( OGR_FD_GetName( hDef ) ); - QgsDebugMsg( "OGR layer name : " + name ); - - layerUri += "|layerid=" + QString::number( layerId ); - - path += "/" + name; - } - - QgsDebugMsg( "OGR layer uri : " + layerUri ); - - return new QgsOgrLayerItem( parentItem, name, path, layerUri, layerType ); -} - -QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem ) -{ - if ( thePath.isEmpty() ) - return 0; - - QFileInfo info( thePath ); - if ( !info.isFile() ) - return 0; - - // We have to filter by extensions, otherwise e.g. all Shapefile files are displayed - // because OGR drive can open also .dbf, .shx. - QStringList myExtensions = fileExtensions(); - if ( myExtensions.indexOf( info.suffix().toLower() ) < 0 ) - { - bool matches = false; - foreach( QString wildcard, wildcards() ) - { - QRegExp rx( wildcard, Qt::CaseInsensitive, QRegExp::Wildcard ); - if ( rx.exactMatch( info.fileName() ) ) - { - matches = true; - break; - } - } - if ( !matches ) - return 0; - } - - // .dbf should probably appear if .shp is not present - if ( info.suffix().toLower() == "dbf" ) - { - QString pathShp = thePath.left( thePath.count() - 4 ) + ".shp"; - if ( QFileInfo( pathShp ).exists() ) - return 0; - } - - OGRRegisterAll(); - OGRSFDriverH hDriver; - OGRDataSourceH hDataSource = OGROpen( TO8F( thePath ), false, &hDriver ); - - if ( !hDataSource ) - return 0; - - QString driverName = OGR_Dr_GetName( hDriver ); - QgsDebugMsg( "OGR Driver : " + driverName ); - - int numLayers = OGR_DS_GetLayerCount( hDataSource ); - - QgsDataItem* item = 0; - - if ( numLayers == 1 ) - { - QString name = info.completeBaseName(); - item = dataItemForLayer( parentItem, name, thePath, hDataSource, 0 ); - } - else if ( numLayers > 1 ) - { - item = new QgsOgrDataCollectionItem( parentItem, info.fileName(), thePath ); - } - - OGR_DS_Destroy( hDataSource ); - return item; -} - -QgsOgrDataCollectionItem::QgsOgrDataCollectionItem( QgsDataItem* parent, QString name, QString path ) - : QgsDataCollectionItem( parent, name, path ) -{ -} - -QgsOgrDataCollectionItem::~QgsOgrDataCollectionItem() -{ -} - -QVector QgsOgrDataCollectionItem::createChildren() -{ - QVector children; - - OGRSFDriverH hDriver; - OGRDataSourceH hDataSource = OGROpen( TO8F( mPath ), false, &hDriver ); - if ( !hDataSource ) - return children; - int numLayers = OGR_DS_GetLayerCount( hDataSource ); - - for ( int i = 0; i < numLayers; i++ ) - { - QgsOgrLayerItem* item = dataItemForLayer( this, QString(), mPath, hDataSource, i ); - children.append( item ); - } - - OGR_DS_Destroy( hDataSource ); - - return children; -} +// --------------------------------------------------------------------------- QGISEXTERN QgsVectorLayerImport::ImportError createEmptyLayer( const QString& uri, diff --git a/src/providers/ogr/qgsogrprovider.h b/src/providers/ogr/qgsogrprovider.h index 300c37e9a585..bf7126fa5481 100644 --- a/src/providers/ogr/qgsogrprovider.h +++ b/src/providers/ogr/qgsogrprovider.h @@ -15,7 +15,6 @@ email : sherman at mrcc.com * * ***************************************************************************/ -#include "qgsdataitem.h" #include "qgsrectangle.h" #include "qgsvectordataprovider.h" #include "qgsvectorfilewriter.h" @@ -26,6 +25,16 @@ class QgsVectorLayerImport; #include +#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1800 +#define TO8(x) (x).toUtf8().constData() +#define TO8F(x) (x).toUtf8().constData() +#define FROM8(x) QString::fromUtf8(x) +#else +#define TO8(x) (x).toLocal8Bit().constData() +#define TO8F(x) QFile::encodeName( x ).constData() +#define FROM8(x) QString::fromLocal8Bit(x) +#endif + /** \class QgsOgrProvider \brief Data provider for ESRI shapefiles @@ -255,6 +264,9 @@ class QgsOgrProvider : public QgsVectorDataProvider @note: added in version 1.4*/ virtual bool doesStrictFeatureTypeCheck() const { return false;} + /** return OGR geometry type */ + static int getOgrGeomType( OGRLayerH ogrLayer ); + protected: /** loads fields from input file to member attributeFields */ void loadFields(); @@ -323,24 +335,3 @@ class QgsOgrProvider : public QgsVectorDataProvider /**Calls OGR_L_SyncToDisk and recreates the spatial index if present*/ bool syncToDisc(); }; - -class QgsOgrLayerItem : public QgsLayerItem -{ - Q_OBJECT - public: - QgsOgrLayerItem( QgsDataItem* parent, QString name, QString path, QString uri, LayerType layerType ); - ~QgsOgrLayerItem(); - - bool setCrs( QgsCoordinateReferenceSystem crs ); - Capability capabilities(); -}; - -class QgsOgrDataCollectionItem : public QgsDataCollectionItem -{ - Q_OBJECT - public: - QgsOgrDataCollectionItem( QgsDataItem* parent, QString name, QString path ); - ~QgsOgrDataCollectionItem(); - - QVector createChildren(); -};