diff --git a/src/app/qgsprojectproperties.cpp b/src/app/qgsprojectproperties.cpp index 33ff2bd..109e783 100644 --- a/src/app/qgsprojectproperties.cpp +++ b/src/app/qgsprojectproperties.cpp @@ -33,6 +33,8 @@ #include "qgsrenderer.h" #include "qgssnappingdialog.h" #include "qgsrasterlayer.h" +#include "qgsvectorlayer.h" +#include "qgsvectordataprovider.h" #include "qgsscaleutils.h" #include "qgsgenericprojectionselector.h" #include "qgsstylev2.h" @@ -298,8 +300,20 @@ QgsProjectProperties::QgsProjectProperties( QgsMapCanvas* mapCanvas, QWidget *pa } QStringList wfsLayerIdList = QgsProject::instance()->readListEntry( "WFSLayers", "/" ); - - twWFSLayers->setColumnCount( 2 ); + QStringList wfstUpdateLayerIdList = QgsProject::instance()->readListEntry( "WFSTLayers", "Update" ); + QStringList wfstInsertLayerIdList = QgsProject::instance()->readListEntry( "WFSTLayers", "Insert" ); + QStringList wfstDeleteLayerIdList = QgsProject::instance()->readListEntry( "WFSTLayers", "Delete" ); + + QSignalMapper *smPublied = new QSignalMapper(this); + connect(smPublied, SIGNAL(mapped(int)), this, SLOT(on_cbxWFSPublied_stateChanged(int))); + QSignalMapper *smUpdate = new QSignalMapper(this); + connect(smUpdate, SIGNAL(mapped(int)), this, SLOT(on_cbxWFSUpdate_stateChanged(int))); + QSignalMapper *smInsert = new QSignalMapper(this); + connect(smInsert, SIGNAL(mapped(int)), this, SLOT(on_cbxWFSInsert_stateChanged(int))); + QSignalMapper *smDelete = new QSignalMapper(this); + connect(smDelete, SIGNAL(mapped(int)), this, SLOT(on_cbxWFSDelete_stateChanged(int))); + + twWFSLayers->setColumnCount( 5 ); twWFSLayers->horizontalHeader()->setVisible( true ); twWFSLayers->setRowCount( mapLayers.size() ); @@ -319,11 +333,44 @@ QgsProjectProperties::QgsProjectProperties( QgsMapCanvas* mapCanvas, QWidget *pa twi->setFlags( twi->flags() & ~Qt::ItemIsEditable ); twWFSLayers->setItem( j, 0, twi ); - QCheckBox *cb = new QCheckBox(); - cb->setChecked( wfsLayerIdList.contains( currentLayer->id() ) ); - twWFSLayers->setCellWidget( j, 1, cb ); - j++; + QCheckBox* cbp = new QCheckBox(); + cbp->setChecked( wfsLayerIdList.contains( currentLayer->id() ) ); + twWFSLayers->setCellWidget( j, 1, cbp ); + + smPublied->setMapping(cbp, j); + connect(cbp, SIGNAL(stateChanged(int)), smPublied, SLOT(map())); + + QgsVectorLayer* vlayer = qobject_cast( currentLayer ); + QgsVectorDataProvider* provider = vlayer->dataProvider(); + if ( (provider->capabilities() & QgsVectorDataProvider::ChangeAttributeValues ) && (provider->capabilities() & QgsVectorDataProvider::ChangeGeometries ) ) + { + QCheckBox* cbu = new QCheckBox(); + cbu->setChecked( wfstUpdateLayerIdList.contains( currentLayer->id() ) ); + twWFSLayers->setCellWidget( j, 2, cbu ); + + smUpdate->setMapping(cbu, j); + connect(cbu, SIGNAL(stateChanged(int)), smUpdate, SLOT(map())); + } + if ( ( provider->capabilities() & QgsVectorDataProvider::AddFeatures ) ) + { + QCheckBox* cbi = new QCheckBox(); + cbi->setChecked( wfstInsertLayerIdList.contains( currentLayer->id() ) ); + twWFSLayers->setCellWidget( j, 3, cbi ); + + smInsert->setMapping(cbi, j); + connect(cbi, SIGNAL(stateChanged(int)), smInsert, SLOT(map())); + } + if ( ( provider->capabilities() & QgsVectorDataProvider::DeleteFeatures ) ) + { + QCheckBox* cbd = new QCheckBox(); + cbd->setChecked( wfstDeleteLayerIdList.contains( currentLayer->id() ) ); + twWFSLayers->setCellWidget( j, 4, cbd ); + + smDelete->setMapping(cbd, j); + connect(cbd, SIGNAL(stateChanged(int)), smDelete, SLOT(map())); + } + j++; } } twWFSLayers->setRowCount( j ); @@ -610,16 +657,38 @@ void QgsProjectProperties::apply() } QStringList wfsLayerList; + QStringList wfstUpdateLayerList; + QStringList wfstInsertLayerList; + QStringList wfstDeleteLayerList; for ( int i = 0; i < twWFSLayers->rowCount(); i++ ) { - QCheckBox *cb = qobject_cast( twWFSLayers->cellWidget( i, 1 ) ); + QString id = twWFSLayers->item( i, 0 )->data( Qt::UserRole ).toString(); + QCheckBox* cb; + cb = qobject_cast( twWFSLayers->cellWidget( i, 1 ) ); if ( cb && cb->isChecked() ) { - QString id = twWFSLayers->item( i, 0 )->data( Qt::UserRole ).toString(); wfsLayerList << id; } + cb = qobject_cast( twWFSLayers->cellWidget( i, 2 ) ); + if ( cb && cb->isChecked() ) + { + wfstUpdateLayerList << id; + } + cb = qobject_cast( twWFSLayers->cellWidget( i, 3 ) ); + if ( cb && cb->isChecked() ) + { + wfstInsertLayerList << id; + } + cb = qobject_cast( twWFSLayers->cellWidget( i, 4 ) ); + if ( cb && cb->isChecked() ) + { + wfstDeleteLayerList << id; + } } QgsProject::instance()->writeEntry( "WFSLayers", "/", wfsLayerList ); + QgsProject::instance()->writeEntry( "WFSTLayers", "Update", wfstUpdateLayerList ); + QgsProject::instance()->writeEntry( "WFSTLayers", "Insert", wfstInsertLayerList ); + QgsProject::instance()->writeEntry( "WFSTLayers", "Delete", wfstDeleteLayerList ); // Default Styles QgsProject::instance()->writeEntry( "DefaultStyles", "/Marker", cboStyleMarker->currentText() ); @@ -691,6 +760,62 @@ void QgsProjectProperties::on_cbxProjectionEnabled_stateChanged( int state ) } } +void QgsProjectProperties::on_cbxWFSPublied_stateChanged( int aIdx ) +{ + QCheckBox* cb = qobject_cast( twWFSLayers->cellWidget( aIdx, 1 ) ); + if ( cb && !cb->isChecked() ) + { + QCheckBox* cbn = qobject_cast( twWFSLayers->cellWidget( aIdx, 2 ) ); + if ( cbn ) + cbn->setChecked(false); + } +} + +void QgsProjectProperties::on_cbxWFSUpdate_stateChanged( int aIdx ) +{ + QCheckBox* cb = qobject_cast( twWFSLayers->cellWidget( aIdx, 2 ) ); + if ( cb && cb->isChecked() ) + { + QCheckBox* cbn = qobject_cast( twWFSLayers->cellWidget( aIdx, 1 ) ); + if ( cbn ) + cbn->setChecked(true); + } + else if ( cb && !cb->isChecked() ) + { + QCheckBox* cbn = qobject_cast( twWFSLayers->cellWidget( aIdx, 3 ) ); + if ( cbn ) + cbn->setChecked(false); + } +} + +void QgsProjectProperties::on_cbxWFSInsert_stateChanged( int aIdx ) +{ + QCheckBox* cb = qobject_cast( twWFSLayers->cellWidget( aIdx, 3 ) ); + if ( cb && cb->isChecked() ) + { + QCheckBox* cbn = qobject_cast( twWFSLayers->cellWidget( aIdx, 2 ) ); + if ( cbn ) + cbn->setChecked(true); + } + else if ( cb && !cb->isChecked() ) + { + QCheckBox* cbn = qobject_cast( twWFSLayers->cellWidget( aIdx, 4 ) ); + if ( cbn ) + cbn->setChecked(false); + } +} + +void QgsProjectProperties::on_cbxWFSDelete_stateChanged( int aIdx ) +{ + QCheckBox* cb = qobject_cast( twWFSLayers->cellWidget( aIdx, 4 ) ); + if ( cb && cb->isChecked() ) + { + QCheckBox* cbn = qobject_cast( twWFSLayers->cellWidget( aIdx, 3 ) ); + if ( cbn ) + cbn->setChecked(true); + } +} + void QgsProjectProperties::setMapUnitsToCurrentProjection() { long myCRSID = projectionSelector->selectedCrsId(); diff --git a/src/app/qgsprojectproperties.h b/src/app/qgsprojectproperties.h index ace123d..cf23288 100644 --- a/src/app/qgsprojectproperties.h +++ b/src/app/qgsprojectproperties.h @@ -139,6 +139,14 @@ class QgsProjectProperties : public QDialog, private Ui::QgsProjectPropertiesBas void on_buttonBox_helpRequested() { QgsContextHelp::run( metaObject()->className() ); } void on_cbxProjectionEnabled_stateChanged( int state ); + + /*! + * Slot to link WFS checkboxes + */ + void on_cbxWFSPublied_stateChanged( int aIdx ); + void on_cbxWFSUpdate_stateChanged( int aIdx ); + void on_cbxWFSInsert_stateChanged( int aIdx ); + void on_cbxWFSDelete_stateChanged( int aIdx ); /*! * If user changes the CRS, set the corresponding map units diff --git a/src/core/qgsgeometry.cpp b/src/core/qgsgeometry.cpp index 1010aa7..9a1ea7f 100644 --- a/src/core/qgsgeometry.cpp +++ b/src/core/qgsgeometry.cpp @@ -32,6 +32,12 @@ email : morb at ozemail dot com dot au #include "qgsmessagelog.h" #include "qgsgeometryvalidator.h" +#ifndef Q_WS_WIN +#include +#else +#include +#endif + #define DEFAULT_QUADRANT_SEGMENTS 8 #define CATCH_GEOS(r) \ @@ -527,6 +533,601 @@ QgsGeometry* QgsGeometry::fromRect( const QgsRectangle& rect ) return fromPolygon( polygon ); } +static const QString GML_NAMESPACE = "http://www.opengis.net/gml"; +QgsGeometry* QgsGeometry::fromGML2( const QDomNode& geometryNode ) +{ + QDomNode geometryChild = geometryNode.firstChild(); + if ( geometryChild.isNull() ) + { + return 0; + } + QgsGeometry* g = new QgsGeometry(); + QDomElement geometryTypeElement = geometryChild.toElement(); + QString geomType = geometryTypeElement.tagName(); + if ( geomType == "Point" ) + { + g->setFromGML2Point( geometryTypeElement ); + } + else if ( geomType == "LineString" ) + { + g->setFromGML2LineString( geometryTypeElement ); + } + else if ( geomType == "Polygon" ) + { + g->setFromGML2Polygon( geometryTypeElement ); + } + else if ( geomType == "MultiPoint" ) + { + g->setFromGML2MultiPoint( geometryTypeElement ); + } + else if ( geomType == "MultiLineString" ) + { + g->setFromGML2MultiLineString( geometryTypeElement ); + } + else if ( geomType == "MultiPolygon" ) + { + g->setFromGML2MultiPolygon( geometryTypeElement ); + } + else //unknown type + { + return 0; + } + return g; +} + +bool QgsGeometry::setFromGML2Point( const QDomElement& geometryElement ) +{ + QDomNodeList coordList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); + if ( coordList.size() < 1 ) + { + return false; + } + QDomElement coordElement = coordList.at( 0 ).toElement(); + std::list pointCoordinate; + if ( readGML2Coordinates( pointCoordinate, coordElement ) != 0) + { + return false; + } + + if ( pointCoordinate.size() < 1 ) + { + return false; + } + + std::list::const_iterator point_it = pointCoordinate.begin(); + //char e = QgsApplication::endian(); + char e = ( htonl( 1 ) == 1 ) ? 0 : 1 ; + double x = point_it->x(); + double y = point_it->y(); + int size = 1 + sizeof( int ) + 2 * sizeof( double ); + + QGis::WkbType type = QGis::WKBPoint; + unsigned char* wkb = new unsigned char[size]; + + int wkbPosition = 0; //current offset from wkb beginning (in bytes) + memcpy( &( wkb )[wkbPosition], &e, 1 ); + wkbPosition += 1; + memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); + wkbPosition += sizeof( int ); + memcpy( &( wkb )[wkbPosition], &x, sizeof( double ) ); + wkbPosition += sizeof( double ); + memcpy( &( wkb )[wkbPosition], &y, sizeof( double ) ); + + fromWkb( wkb, size ); + return true; +} + +bool QgsGeometry::setFromGML2LineString( const QDomElement& geometryElement ) +{ + QDomNodeList coordinatesList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); + if ( coordinatesList.size() < 1 ) + { + return false; + } + QDomElement coordinatesElement = coordinatesList.at( 0 ).toElement(); + std::list lineCoordinates; + if ( readGML2Coordinates( lineCoordinates, coordinatesElement ) != 0 ) + { + return false; + } + + //char e = QgsApplication::endian(); + char e = ( htonl( 1 ) == 1 ) ? 0 : 1 ; + int size = 1 + 2 * sizeof( int ) + lineCoordinates.size() * 2 * sizeof( double ); + + QGis::WkbType type = QGis::WKBLineString; + unsigned char* wkb = new unsigned char[size]; + + int wkbPosition = 0; //current offset from wkb beginning (in bytes) + double x, y; + int nPoints = lineCoordinates.size(); + + //fill the contents into *wkb + memcpy( &( wkb )[wkbPosition], &e, 1 ); + wkbPosition += 1; + memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); + wkbPosition += sizeof( int ); + memcpy( &( wkb )[wkbPosition], &nPoints, sizeof( int ) ); + wkbPosition += sizeof( int ); + + std::list::const_iterator iter; + for ( iter = lineCoordinates.begin(); iter != lineCoordinates.end(); ++iter ) + { + x = iter->x(); + y = iter->y(); + memcpy( &( wkb )[wkbPosition], &x, sizeof( double ) ); + wkbPosition += sizeof( double ); + memcpy( &( wkb )[wkbPosition], &y, sizeof( double ) ); + wkbPosition += sizeof( double ); + } + + fromWkb( wkb, size ); + return true; +} + +bool QgsGeometry::setFromGML2Polygon( const QDomElement& geometryElement ) +{ + //read all the coordinates (as QgsPoint) into memory. Each linear ring has an entry in the vector + std::vector > ringCoordinates; + + //read coordinates for outer boundary + QDomNodeList outerBoundaryList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "outerBoundaryIs" ); + if ( outerBoundaryList.size() < 1 ) //outer ring is necessary + { + return false; + } + QDomElement coordinatesElement = outerBoundaryList.at( 0 ).firstChild().firstChild().toElement(); + if ( coordinatesElement.isNull() ) + { + return false; + } + std::list exteriorPointList; + if ( readGML2Coordinates( exteriorPointList, coordinatesElement ) != 0 ) + { + return false; + } + ringCoordinates.push_back( exteriorPointList ); + + //read coordinates for inner boundary + QDomNodeList innerBoundaryList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "innerBoundaryIs" ); + for ( int i = 0; i < innerBoundaryList.size(); ++i ) + { + std::list interiorPointList; + QDomElement coordinatesElement = innerBoundaryList.at( i ).firstChild().firstChild().toElement(); + if ( coordinatesElement.isNull() ) + { + return false; + } + if ( readGML2Coordinates( interiorPointList, coordinatesElement ) != 0 ) + { + return false; + } + ringCoordinates.push_back( interiorPointList ); + } + + //calculate number of bytes to allocate + int nrings = ringCoordinates.size(); + int npoints = 0;//total number of points + for ( std::vector >::const_iterator it = ringCoordinates.begin(); it != ringCoordinates.end(); ++it ) + { + npoints += it->size(); + } + int size = 1 + 2 * sizeof( int ) + nrings * sizeof( int ) + 2 * npoints * sizeof( double ); + + QGis::WkbType type = QGis::WKBPolygon; + unsigned char* wkb = new unsigned char[size]; + + //char e = QgsApplication::endian(); + char e = ( htonl( 1 ) == 1 ) ? 0 : 1 ; + int wkbPosition = 0; //current offset from wkb beginning (in bytes) + int nPointsInRing = 0; + double x, y; + + //fill the contents into *wkb + memcpy( &( wkb )[wkbPosition], &e, 1 ); + wkbPosition += 1; + memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); + wkbPosition += sizeof( int ); + memcpy( &( wkb )[wkbPosition], &nrings, sizeof( int ) ); + wkbPosition += sizeof( int ); + for ( std::vector >::const_iterator it = ringCoordinates.begin(); it != ringCoordinates.end(); ++it ) + { + nPointsInRing = it->size(); + memcpy( &( wkb )[wkbPosition], &nPointsInRing, sizeof( int ) ); + wkbPosition += sizeof( int ); + //iterate through the string list converting the strings to x-/y- doubles + std::list::const_iterator iter; + for ( iter = it->begin(); iter != it->end(); ++iter ) + { + x = iter->x(); + y = iter->y(); + //qWarning("currentCoordinate: " + QString::number(x) + " // " + QString::number(y)); + memcpy( &( wkb )[wkbPosition], &x, sizeof( double ) ); + wkbPosition += sizeof( double ); + memcpy( &( wkb )[wkbPosition], &y, sizeof( double ) ); + wkbPosition += sizeof( double ); + } + } + + fromWkb( wkb, size ); + return true; +} + +bool QgsGeometry::setFromGML2MultiPoint( const QDomElement& geometryElement ) +{ + std::list pointList; + std::list currentPoint; + QDomNodeList pointMemberList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "pointMember" ); + if ( pointMemberList.size() < 1 ) + { + return false; + } + QDomNodeList pointNodeList; + QDomNodeList coordinatesList; + for ( int i = 0; i < pointMemberList.size(); ++i ) + { + // element + pointNodeList = pointMemberList.at( i ).toElement().elementsByTagNameNS( GML_NAMESPACE, "Point" ); + if ( pointNodeList.size() < 1 ) + { + continue; + } + // element + coordinatesList = pointNodeList.at( 0 ).toElement().elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); + if ( coordinatesList.size() < 1 ) + { + continue; + } + currentPoint.clear(); + if ( readGML2Coordinates( currentPoint, coordinatesList.at( 0 ).toElement() ) != 0 ) + { + continue; + } + if ( currentPoint.size() < 1 ) + { + continue; + } + pointList.push_back(( *currentPoint.begin() ) ); + } + + //calculate the required wkb size + int size = 1 + 2 * sizeof( int ) + pointList.size() * ( 2 * sizeof( double ) + 1 + sizeof( int ) ); + + QGis::WkbType type = QGis::WKBMultiPoint; + unsigned char* wkb = new unsigned char[size]; + + //fill the wkb content + //char e = QgsApplication::endian(); + char e = ( htonl( 1 ) == 1 ) ? 0 : 1 ; + int wkbPosition = 0; //current offset from wkb beginning (in bytes) + int nPoints = pointList.size(); //number of points + double x, y; + memcpy( &( wkb )[wkbPosition], &e, 1 ); + wkbPosition += 1; + memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); + wkbPosition += sizeof( int ); + memcpy( &( wkb )[wkbPosition], &nPoints, sizeof( int ) ); + wkbPosition += sizeof( int ); + for ( std::list::const_iterator it = pointList.begin(); it != pointList.end(); ++it ) + { + memcpy( &( wkb )[wkbPosition], &e, 1 ); + wkbPosition += 1; + memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); + wkbPosition += sizeof( int ); + x = it->x(); + memcpy( &( wkb )[wkbPosition], &x, sizeof( double ) ); + wkbPosition += sizeof( double ); + y = it->y(); + memcpy( &( wkb )[wkbPosition], &y, sizeof( double ) ); + wkbPosition += sizeof( double ); + } + + fromWkb( wkb, size ); + return true; +} + +bool QgsGeometry::setFromGML2MultiLineString( const QDomElement& geometryElement ) +{ + //geoserver has + // + // + // + + //mapserver has directly + // > lineCoordinates; //first list: lines, second list: points of one line + QDomElement currentLineStringElement; + QDomNodeList currentCoordList; + + QDomNodeList lineStringMemberList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "lineStringMember" ); + if ( lineStringMemberList.size() > 0 ) //geoserver + { + for ( int i = 0; i < lineStringMemberList.size(); ++i ) + { + QDomNodeList lineStringNodeList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "LineString" ); + if ( lineStringNodeList.size() < 1 ) + { + return false; + } + currentLineStringElement = lineStringNodeList.at( 0 ).toElement(); + currentCoordList = currentLineStringElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); + if ( currentCoordList.size() < 1 ) + { + return false; + } + std::list currentPointList; + if ( readGML2Coordinates( currentPointList, currentCoordList.at( 0 ).toElement() ) != 0 ) + { + return false; + } + lineCoordinates.push_back( currentPointList ); + } + } + else + { + QDomNodeList lineStringList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "LineString" ); + if ( lineStringList.size() > 0 ) //mapserver + { + for ( int i = 0; i < lineStringList.size(); ++i ) + { + currentLineStringElement = lineStringList.at( i ).toElement(); + currentCoordList = currentLineStringElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); + if ( currentCoordList.size() < 1 ) + { + return false; + } + std::list currentPointList; + if ( readGML2Coordinates( currentPointList, currentCoordList.at( 0 ).toElement() ) != 0 ) + { + return false; + } + lineCoordinates.push_back( currentPointList ); + } + } + else + { + return false; + } + } + + + //calculate the required wkb size + int size = ( lineCoordinates.size() + 1 ) * ( 1 + 2 * sizeof( int ) ); + for ( std::list >::const_iterator it = lineCoordinates.begin(); it != lineCoordinates.end(); ++it ) + { + size += it->size() * 2 * sizeof( double ); + } + + QGis::WkbType type = QGis::WKBMultiLineString; + unsigned char* wkb = new unsigned char[size]; + + //fill the wkb content + //char e = QgsApplication::endian(); + char e = ( htonl( 1 ) == 1 ) ? 0 : 1 ; + int wkbPosition = 0; //current offset from wkb beginning (in bytes) + int nLines = lineCoordinates.size(); + int nPoints; //number of points in a line + double x, y; + memcpy( &( wkb )[wkbPosition], &e, 1 ); + wkbPosition += 1; + memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); + wkbPosition += sizeof( int ); + memcpy( &( wkb )[wkbPosition], &nLines, sizeof( int ) ); + wkbPosition += sizeof( int ); + for ( std::list >::const_iterator it = lineCoordinates.begin(); it != lineCoordinates.end(); ++it ) + { + memcpy( &( wkb )[wkbPosition], &e, 1 ); + wkbPosition += 1; + memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); + wkbPosition += sizeof( int ); + nPoints = it->size(); + memcpy( &( wkb )[wkbPosition], &nPoints, sizeof( int ) ); + wkbPosition += sizeof( int ); + for ( std::list::const_iterator iter = it->begin(); iter != it->end(); ++iter ) + { + x = iter->x(); + //qWarning("x is: " + QString::number(x)); + y = iter->y(); + //qWarning("y is: " + QString::number(y)); + memcpy( &( wkb )[wkbPosition], &x, sizeof( double ) ); + wkbPosition += sizeof( double ); + memcpy( &( wkb )[wkbPosition], &y, sizeof( double ) ); + wkbPosition += sizeof( double ); + } + } + + fromWkb( wkb, size ); + return true; +} + +bool QgsGeometry::setFromGML2MultiPolygon( const QDomElement& geometryElement ) +{ + //first list: different polygons, second list: different rings, third list: different points + std::list > > multiPolygonPoints; + QDomElement currentPolygonMemberElement; + QDomNodeList polygonList; + QDomElement currentPolygonElement; + QDomNodeList outerBoundaryList; + QDomElement currentOuterBoundaryElement; + QDomElement currentInnerBoundaryElement; + QDomNodeList innerBoundaryList; + QDomNodeList linearRingNodeList; + QDomElement currentLinearRingElement; + QDomNodeList currentCoordinateList; + + QDomNodeList polygonMemberList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "polygonMember" ); + for ( int i = 0; i < polygonMemberList.size(); ++i ) + { + std::list > currentPolygonList; + currentPolygonMemberElement = polygonMemberList.at( i ).toElement(); + polygonList = currentPolygonMemberElement.elementsByTagNameNS( GML_NAMESPACE, "Polygon" ); + if ( polygonList.size() < 1 ) + { + continue; + } + currentPolygonElement = polygonList.at( 0 ).toElement(); + + //find exterior ring + outerBoundaryList = currentPolygonElement.elementsByTagNameNS( GML_NAMESPACE, "outerBoundaryIs" ); + if ( outerBoundaryList.size() < 1 ) + { + continue; + } + + currentOuterBoundaryElement = outerBoundaryList.at( 0 ).toElement(); + std::list ringCoordinates; + + linearRingNodeList = currentOuterBoundaryElement.elementsByTagNameNS( GML_NAMESPACE, "LinearRing" ); + if ( linearRingNodeList.size() < 1 ) + { + continue; + } + currentLinearRingElement = linearRingNodeList.at( 0 ).toElement(); + currentCoordinateList = currentLinearRingElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); + if ( currentCoordinateList.size() < 1 ) + { + continue; + } + if ( readGML2Coordinates( ringCoordinates, currentCoordinateList.at( 0 ).toElement() ) != 0 ) + { + continue; + } + currentPolygonList.push_back( ringCoordinates ); + + //find interior rings + QDomNodeList innerBoundaryList = currentPolygonElement.elementsByTagNameNS( GML_NAMESPACE, "innerBoundaryIs" ); + for ( int j = 0; j < innerBoundaryList.size(); ++j ) + { + std::list ringCoordinates; + currentInnerBoundaryElement = innerBoundaryList.at( j ).toElement(); + linearRingNodeList = currentInnerBoundaryElement.elementsByTagNameNS( GML_NAMESPACE, "LinearRing" ); + if ( linearRingNodeList.size() < 1 ) + { + continue; + } + currentLinearRingElement = linearRingNodeList.at( 0 ).toElement(); + currentCoordinateList = currentLinearRingElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); + if ( currentCoordinateList.size() < 1 ) + { + continue; + } + if ( readGML2Coordinates( ringCoordinates, currentCoordinateList.at( 0 ).toElement() ) != 0 ) + { + continue; + } + currentPolygonList.push_back( ringCoordinates ); + } + multiPolygonPoints.push_back( currentPolygonList ); + } + + int size = 1 + 2 * sizeof( int ); + //calculate the wkb size + for ( std::list > >::const_iterator it = multiPolygonPoints.begin(); it != multiPolygonPoints.end(); ++it ) + { + size += 1 + 2 * sizeof( int ); + for ( std::list >::const_iterator iter = it->begin(); iter != it->end(); ++iter ) + { + size += sizeof( int ) + 2 * iter->size() * sizeof( double ); + } + } + + QGis::WkbType type = QGis::WKBMultiPolygon; + unsigned char* wkb = new unsigned char[size]; + + int polygonType = QGis::WKBPolygon; + //char e = QgsApplication::endian(); + char e = ( htonl( 1 ) == 1 ) ? 0 : 1 ; + int wkbPosition = 0; //current offset from wkb beginning (in bytes) + double x, y; + int nPolygons = multiPolygonPoints.size(); + int nRings; + int nPointsInRing; + + //fill the contents into *wkb + memcpy( &( wkb )[wkbPosition], &e, 1 ); + wkbPosition += 1; + memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); + wkbPosition += sizeof( int ); + memcpy( &( wkb )[wkbPosition], &nPolygons, sizeof( int ) ); + wkbPosition += sizeof( int ); + + for ( std::list > >::const_iterator it = multiPolygonPoints.begin(); it != multiPolygonPoints.end(); ++it ) + { + memcpy( &( wkb )[wkbPosition], &e, 1 ); + wkbPosition += 1; + memcpy( &( wkb )[wkbPosition], &polygonType, sizeof( int ) ); + wkbPosition += sizeof( int ); + nRings = it->size(); + memcpy( &( wkb )[wkbPosition], &nRings, sizeof( int ) ); + wkbPosition += sizeof( int ); + for ( std::list >::const_iterator iter = it->begin(); iter != it->end(); ++iter ) + { + nPointsInRing = iter->size(); + memcpy( &( wkb )[wkbPosition], &nPointsInRing, sizeof( int ) ); + wkbPosition += sizeof( int ); + for ( std::list::const_iterator iterator = iter->begin(); iterator != iter->end(); ++iterator ) + { + x = iterator->x(); + y = iterator->y(); + memcpy( &( wkb )[wkbPosition], &x, sizeof( double ) ); + wkbPosition += sizeof( double ); + memcpy( &( wkb )[wkbPosition], &y, sizeof( double ) ); + wkbPosition += sizeof( double ); + } + } + } + + fromWkb( wkb, size ); + return true; +} + +bool QgsGeometry::readGML2Coordinates( std::list& coords, const QDomElement elem ) const +{ + QString coordSeparator = ","; + QString tupelSeparator = " "; + //"decimal" has to be "." + + coords.clear(); + + if ( elem.hasAttribute( "cs" ) ) + { + coordSeparator = elem.attribute( "cs" ); + } + if ( elem.hasAttribute( "ts" ) ) + { + tupelSeparator = elem.attribute( "ts" ); + } + + QStringList tupels = elem.text().split( tupelSeparator, QString::SkipEmptyParts ); + QStringList tupel_coords; + double x, y; + bool conversionSuccess; + + QStringList::const_iterator it; + for ( it = tupels.constBegin(); it != tupels.constEnd(); ++it ) + { + tupel_coords = ( *it ).split( coordSeparator, QString::SkipEmptyParts ); + if ( tupel_coords.size() < 2 ) + { + continue; + } + x = tupel_coords.at( 0 ).toDouble( &conversionSuccess ); + if ( !conversionSuccess ) + { + return 1; + } + y = tupel_coords.at( 1 ).toDouble( &conversionSuccess ); + if ( !conversionSuccess ) + { + return 1; + } + coords.push_back( QgsPoint( x, y ) ); + } + return 0; +} + QgsGeometry & QgsGeometry::operator=( QgsGeometry const & rhs ) { if ( &rhs == this ) @@ -3946,10 +4547,10 @@ QString QgsGeometry::exportToWkt() { mWkt += "POINT("; x = ( double * )( mGeometry + 5 ); - mWkt += QString::number( *x, 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + mWkt += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); mWkt += " "; y = ( double * )( mGeometry + 5 + sizeof( double ) ); - mWkt += QString::number( *y, 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + mWkt += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); mWkt += ")"; return mWkt; } @@ -3975,11 +4576,11 @@ QString QgsGeometry::exportToWkt() mWkt += ", "; } x = ( double * ) ptr; - mWkt += QString::number( *x, 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + mWkt += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); mWkt += " "; ptr += sizeof( double ); y = ( double * ) ptr; - mWkt += QString::number( *y, 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + mWkt += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); ptr += sizeof( double ); if ( hasZValue ) { @@ -4030,11 +4631,11 @@ QString QgsGeometry::exportToWkt() mWkt += ","; } x = ( double * ) ptr; - mWkt += QString::number( *x, 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + mWkt += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); mWkt += " "; ptr += sizeof( double ); y = ( double * ) ptr; - mWkt += QString::number( *y, 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + mWkt += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); ptr += sizeof( double ); if ( hasZValue ) { @@ -4068,11 +4669,11 @@ QString QgsGeometry::exportToWkt() mWkt += ", "; } x = ( double * )( ptr ); - mWkt += QString::number( *x, 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + mWkt += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); mWkt += " "; ptr += sizeof( double ); y = ( double * )( ptr ); - mWkt += QString::number( *y, 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + mWkt += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); ptr += sizeof( double ); if ( hasZValue ) { @@ -4112,11 +4713,11 @@ QString QgsGeometry::exportToWkt() mWkt += ", "; } x = ( double * ) ptr; - mWkt += QString::number( *x, 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + mWkt += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); ptr += sizeof( double ); mWkt += " "; y = ( double * ) ptr; - mWkt += QString::number( *y, 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + mWkt += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); ptr += sizeof( double ); if ( hasZValue ) { @@ -4168,11 +4769,11 @@ QString QgsGeometry::exportToWkt() mWkt += ","; } x = ( double * ) ptr; - mWkt += QString::number( *x, 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + mWkt += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); ptr += sizeof( double ); mWkt += " "; y = ( double * ) ptr; - mWkt += QString::number( *y, 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + mWkt += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); ptr += sizeof( double ); if ( hasZValue ) { @@ -4226,10 +4827,10 @@ QString QgsGeometry::exportToGeoJSON() { mWkt += "{ \"type\": \"Point\", \"coordinates\": ["; x = ( double * )( mGeometry + 5 ); - mWkt += QString::number( *x, 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + mWkt += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); mWkt += ", "; y = ( double * )( mGeometry + 5 + sizeof( double ) ); - mWkt += QString::number( *y, 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + mWkt += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); mWkt += "] }"; return mWkt; } @@ -4256,11 +4857,11 @@ QString QgsGeometry::exportToGeoJSON() } mWkt += "["; x = ( double * ) ptr; - mWkt += QString::number( *x, 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + mWkt += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); mWkt += ", "; ptr += sizeof( double ); y = ( double * ) ptr; - mWkt += QString::number( *y, 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + mWkt += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); ptr += sizeof( double ); if ( hasZValue ) { @@ -4313,11 +4914,11 @@ QString QgsGeometry::exportToGeoJSON() } mWkt += "["; x = ( double * ) ptr; - mWkt += QString::number( *x, 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + mWkt += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); mWkt += ", "; ptr += sizeof( double ); y = ( double * ) ptr; - mWkt += QString::number( *y, 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + mWkt += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); ptr += sizeof( double ); if ( hasZValue ) { @@ -4353,11 +4954,11 @@ QString QgsGeometry::exportToGeoJSON() } mWkt += "["; x = ( double * )( ptr ); - mWkt += QString::number( *x, 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + mWkt += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); mWkt += ", "; ptr += sizeof( double ); y = ( double * )( ptr ); - mWkt += QString::number( *y, 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + mWkt += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); ptr += sizeof( double ); if ( hasZValue ) { @@ -4399,11 +5000,11 @@ QString QgsGeometry::exportToGeoJSON() } mWkt += "["; x = ( double * ) ptr; - mWkt += QString::number( *x, 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + mWkt += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); ptr += sizeof( double ); mWkt += ", "; y = ( double * ) ptr; - mWkt += QString::number( *y, 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + mWkt += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); ptr += sizeof( double ); if ( hasZValue ) { @@ -4457,11 +5058,11 @@ QString QgsGeometry::exportToGeoJSON() } mWkt += "["; x = ( double * ) ptr; - mWkt += QString::number( *x, 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + mWkt += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); ptr += sizeof( double ); mWkt += ", "; y = ( double * ) ptr; - mWkt += QString::number( *y, 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + mWkt += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); ptr += sizeof( double ); if ( hasZValue ) { @@ -4483,6 +5084,316 @@ QString QgsGeometry::exportToGeoJSON() } } +QDomElement QgsGeometry::exportToGML2( QDomDocument& doc ) +{ + QgsDebugMsg( "entered." ); + + // TODO: implement with GEOS + if ( mDirtyWkb ) + { + exportGeosToWkb(); + } + + if ( !mGeometry ) + { + QgsDebugMsg( "WKB geometry not available!" ); + return QDomElement(); + } + + QGis::WkbType wkbType; + bool hasZValue = false; + double *x, *y; + + QString mWkt; // TODO: rename + + // Will this really work when mGeometry[0] == 0 ???? I (gavin) think not. + //wkbType = (mGeometry[0] == 1) ? mGeometry[1] : mGeometry[4]; + memcpy( &wkbType, &( mGeometry[1] ), sizeof( int ) ); + + switch ( wkbType ) + { + case QGis::WKBPoint25D: + case QGis::WKBPoint: + { + QDomElement pointElem = doc.createElement( "gml:Point" ); + QDomElement coordElem = doc.createElement( "gml:coordinates" ); + coordElem.setAttribute( "cs", "," ); + coordElem.setAttribute( "ts", " " ); + QString coordString; + x = ( double * )( mGeometry + 5 ); + coordString += QString::number( *x, 'f', 8 ).remove( QRegExp("[0]{1,7}$") ); + coordString += ","; + y = ( double * )( mGeometry + 5 + sizeof( double ) ); + coordString += QString::number( *y, 'f', 8 ).remove( QRegExp("[0]{1,7}$") ); + QDomText coordText = doc.createTextNode( coordString ); + coordElem.appendChild( coordText ); + pointElem.appendChild( coordElem ); + return pointElem; + } + case QGis::WKBMultiPoint25D: + hasZValue = true; + case QGis::WKBMultiPoint: + { + unsigned char *ptr; + int idx; + int *nPoints; + + QDomElement multiPointElem = doc.createElement( "gml:MultiPoint" ); + nPoints = ( int* )( mGeometry + 5 ); + ptr = mGeometry + 5 + sizeof( int ); + for ( idx = 0; idx < *nPoints; ++idx ) + { + ptr += ( 1 + sizeof( int ) ); + QDomElement pointMemberElem = doc.createElement( "gml:pointMember" ); + QDomElement pointElem = doc.createElement( "gml:Point" ); + QDomElement coordElem = doc.createElement( "gml:coordinates" ); + coordElem.setAttribute( "cs", "," ); + coordElem.setAttribute( "ts", " " ); + QString coordString; + x = ( double * )( ptr ); + coordString += QString::number( *x, 'f', 8 ).remove( QRegExp("[0]{1,7}$") ); + coordString += ","; + ptr += sizeof( double ); + y = ( double * )( ptr ); + coordString += QString::number( *y, 'f', 8 ).remove( QRegExp("[0]{1,7}$") ); + QDomText coordText = doc.createTextNode( coordString ); + coordElem.appendChild( coordText ); + pointElem.appendChild( coordElem ); + + ptr += sizeof( double ); + if ( hasZValue ) + { + ptr += sizeof( double ); + } + pointMemberElem.appendChild( pointElem ); + multiPointElem.appendChild( pointMemberElem ); + } + return multiPointElem; + } + case QGis::WKBLineString25D: + hasZValue = true; + case QGis::WKBLineString: + { + QgsDebugMsg( "LINESTRING found" ); + unsigned char *ptr; + int *nPoints; + int idx; + + QDomElement lineStringElem = doc.createElement( "gml:LineString" ); + // get number of points in the line + ptr = mGeometry + 5; + nPoints = ( int * ) ptr; + ptr = mGeometry + 1 + 2 * sizeof( int ); + QDomElement coordElem = doc.createElement( "gml:coordinates" ); + coordElem.setAttribute( "cs", "," ); + coordElem.setAttribute( "ts", " " ); + QString coordString; + for ( idx = 0; idx < *nPoints; ++idx ) + { + if ( idx != 0 ) + { + coordString += " "; + } + x = ( double * ) ptr; + coordString += QString::number( *x, 'f', 8 ).remove( QRegExp("[0]{1,7}$") ); + coordString += ","; + ptr += sizeof( double ); + y = ( double * ) ptr; + coordString += QString::number( *y, 'f', 8 ).remove( QRegExp("[0]{1,7}$") ); + ptr += sizeof( double ); + if ( hasZValue ) + { + ptr += sizeof( double ); + } + } + QDomText coordText = doc.createTextNode( coordString ); + coordElem.appendChild( coordText ); + lineStringElem.appendChild( coordElem ); + return lineStringElem; + } + case QGis::WKBMultiLineString25D: + hasZValue = true; + case QGis::WKBMultiLineString: + { + QgsDebugMsg( "MULTILINESTRING found" ); + unsigned char *ptr; + int idx, jdx, numLineStrings; + int *nPoints; + + QDomElement multiLineStringElem = doc.createElement( "gml:MultiLineString" ); + numLineStrings = ( int )( mGeometry[5] ); + ptr = mGeometry + 9; + for ( jdx = 0; jdx < numLineStrings; jdx++ ) + { + QDomElement lineStringMemberElem = doc.createElement( "gml:lineStringMember" ); + QDomElement lineStringElem = doc.createElement( "gml:LineString" ); + ptr += 5; // skip type since we know its 2 + nPoints = ( int * ) ptr; + ptr += sizeof( int ); + QDomElement coordElem = doc.createElement( "gml:coordinates" ); + coordElem.setAttribute( "cs", "," ); + coordElem.setAttribute( "ts", " " ); + QString coordString; + for ( idx = 0; idx < *nPoints; idx++ ) + { + if ( idx != 0 ) + { + coordString += " "; + } + x = ( double * ) ptr; + coordString += QString::number( *x, 'f', 8 ).remove( QRegExp("[0]{1,7}$") ); + ptr += sizeof( double ); + coordString += ","; + y = ( double * ) ptr; + coordString += QString::number( *y, 'f', 8 ).remove( QRegExp("[0]{1,7}$") ); + ptr += sizeof( double ); + if ( hasZValue ) + { + ptr += sizeof( double ); + } + } + QDomText coordText = doc.createTextNode( coordString ); + coordElem.appendChild( coordText ); + lineStringElem.appendChild( coordElem ); + lineStringMemberElem.appendChild( lineStringElem ); + multiLineStringElem.appendChild( lineStringMemberElem ); + } + return multiLineStringElem; + } + case QGis::WKBPolygon25D: + hasZValue = true; + case QGis::WKBPolygon: + { + QgsDebugMsg( "POLYGON found" ); + unsigned char *ptr; + int idx, jdx; + int *numRings, *nPoints; + + QDomElement polygonElem = doc.createElement( "gml:Polygon" ); + // get number of rings in the polygon + numRings = ( int * )( mGeometry + 1 + sizeof( int ) ); + if ( !( *numRings ) ) // sanity check for zero rings in polygon + { + return QDomElement(); + } + int *ringStart; // index of first point for each ring + int *ringNumPoints; // number of points in each ring + ringStart = new int[*numRings]; + ringNumPoints = new int[*numRings]; + ptr = mGeometry + 1 + 2 * sizeof( int ); // set pointer to the first ring + for ( idx = 0; idx < *numRings; idx++ ) + { + QString boundaryName = "gml:outerBoundaryIs"; + if ( idx != 0 ) + { + boundaryName = "gml:innerBoundaryIs"; + } + QDomElement boundaryElem = doc.createElement( boundaryName ); + QDomElement ringElem = doc.createElement( "gml:LinearRing" ); + // get number of points in the ring + nPoints = ( int * ) ptr; + ringNumPoints[idx] = *nPoints; + ptr += 4; + QDomElement coordElem = doc.createElement( "gml:coordinates" ); + coordElem.setAttribute( "cs", "," ); + coordElem.setAttribute( "ts", " " ); + QString coordString; + for ( jdx = 0; jdx < *nPoints; jdx++ ) + { + if ( jdx != 0 ) + { + coordString += " "; + } + x = ( double * ) ptr; + coordString += QString::number( *x, 'f', 8 ).remove( QRegExp("[0]{1,7}$") ); + coordString += ","; + ptr += sizeof( double ); + y = ( double * ) ptr; + coordString += QString::number( *y, 'f', 8 ).remove( QRegExp("[0]{1,7}$") ); + ptr += sizeof( double ); + if ( hasZValue ) + { + ptr += sizeof( double ); + } + } + QDomText coordText = doc.createTextNode( coordString ); + coordElem.appendChild( coordText ); + ringElem.appendChild( coordElem ); + boundaryElem.appendChild( ringElem ); + polygonElem.appendChild( boundaryElem ); + } + delete [] ringStart; + delete [] ringNumPoints; + return polygonElem; + } + case QGis::WKBMultiPolygon25D: + hasZValue = true; + case QGis::WKBMultiPolygon: + { + QgsDebugMsg( "MULTIPOLYGON found" ); + unsigned char *ptr; + int idx, jdx, kdx; + int *numPolygons, *numRings, *nPoints; + + QDomElement multiPolygonElem = doc.createElement( "gml:MultiPolygon" ); + ptr = mGeometry + 5; + numPolygons = ( int * ) ptr; + ptr = mGeometry + 9; + for ( kdx = 0; kdx < *numPolygons; kdx++ ) + { + QDomElement polygonMemberElem = doc.createElement( "gml:polygonMember" ); + QDomElement polygonElem = doc.createElement( "gml:Polygon" ); + ptr += 5; + numRings = ( int * ) ptr; + ptr += 4; + for ( idx = 0; idx < *numRings; idx++ ) + { + QString boundaryName = "gml:outerBoundaryIs"; + if ( idx != 0 ) + { + boundaryName = "gml:innerBoundaryIs"; + } + QDomElement boundaryElem = doc.createElement( boundaryName ); + QDomElement ringElem = doc.createElement( "gml:LinearRing" ); + nPoints = ( int * ) ptr; + ptr += 4; + QDomElement coordElem = doc.createElement( "gml:coordinates" ); + coordElem.setAttribute( "cs", "," ); + coordElem.setAttribute( "ts", " " ); + QString coordString; + for ( jdx = 0; jdx < *nPoints; jdx++ ) + { + if ( jdx != 0 ) + { + coordString += " "; + } + x = ( double * ) ptr; + coordString += QString::number( *x, 'f', 8 ).remove( QRegExp("[0]{1,7}$") ); + ptr += sizeof( double ); + coordString += ","; + y = ( double * ) ptr; + coordString += QString::number( *y, 'f', 8 ).remove( QRegExp("[0]{1,7}$") ); + ptr += sizeof( double ); + if ( hasZValue ) + { + ptr += sizeof( double ); + } + } + QDomText coordText = doc.createTextNode( coordString ); + ringElem.appendChild( coordElem ); + boundaryElem.appendChild( ringElem ); + polygonElem.appendChild( boundaryElem ); + polygonMemberElem.appendChild( polygonElem ); + multiPolygonElem.appendChild( polygonMemberElem ); + } + } + return multiPolygonElem; + } + default: + return QDomElement(); + } +} + bool QgsGeometry::exportWkbToGeos() { QgsDebugMsgLevel( "entered.", 3 ); diff --git a/src/core/qgsgeometry.h b/src/core/qgsgeometry.h index c03b2ef..10e3d47 100644 --- a/src/core/qgsgeometry.h +++ b/src/core/qgsgeometry.h @@ -18,6 +18,7 @@ email : morb at ozemail dot com dot au #include #include +#include #include "qgis.h" @@ -88,6 +89,11 @@ class CORE_EXPORT QgsGeometry /** static method that creates geometry from Wkt */ static QgsGeometry* fromWkt( QString wkt ); + /** static method that creates geometry from GML2 + @note added in 1.9 + */ + static QgsGeometry* fromGML2( const QDomNode& geometryNode ); + /** construct geometry from a point */ static QgsGeometry* fromPoint( const QgsPoint& point ); /** construct geometry from a multipoint */ @@ -383,6 +389,12 @@ class CORE_EXPORT QgsGeometry */ QString exportToGeoJSON(); + /** Exports the geometry to mGML2 + @return true in case of success and false else + * @note added in 1.9 + */ + QDomElement exportToGML2( QDomDocument& doc ); + /* Accessor functions for getting geometry data */ /** return contents of the geometry as a point @@ -488,6 +500,24 @@ class CORE_EXPORT QgsGeometry // Private functions + /** static method that creates geometry from GML2 Point */ + bool setFromGML2Point( const QDomElement& geometryElement ); + /** static method that creates geometry from GML2 LineString */ + bool setFromGML2LineString( const QDomElement& geometryElement ); + /** static method that creates geometry from GML2 Polygon */ + bool setFromGML2Polygon( const QDomElement& geometryElement ); + /** static method that creates geometry from GML2 MultiPoint */ + bool setFromGML2MultiPoint( const QDomElement& geometryElement ); + /** static method that creates geometry from GML2 MultiLineString */ + bool setFromGML2MultiLineString( const QDomElement& geometryElement ); + /** static method that creates geometry from GML2 MultiPolygon */ + bool setFromGML2MultiPolygon( const QDomElement& geometryElement ); + /**Reads the element and extracts the coordinates as points + @param coords list where the found coordinates are appended + @param elem the element + @return boolean for success*/ + bool readGML2Coordinates( std::list& coords, const QDomElement elem ) const; + /** Converts from the WKB geometry to the GEOS geometry. @return true in case of success and false else */ diff --git a/src/mapserver/qgis_map_serv.cpp b/src/mapserver/qgis_map_serv.cpp index 2931318..8a71267 100644 --- a/src/mapserver/qgis_map_serv.cpp +++ b/src/mapserver/qgis_map_serv.cpp @@ -379,6 +379,26 @@ int main( int argc, char * argv[] ) continue; } } + else if ( request == "Transaction" ) + { + QDomDocument transactionDocument; + try + { + transactionDocument = theServer->transaction( parameterMap.value( "REQUEST_BODY" ) ); + } + catch ( QgsMapServiceException& ex ) + { + theRequestHandler->sendServiceException( ex ); + delete theRequestHandler; + delete theServer; + continue; + } + QgsDebugMsg( "sending Transaction response" ); + theRequestHandler->sendGetCapabilitiesResponse( transactionDocument ); + delete theRequestHandler; + delete theServer; + continue; + } return 0; } diff --git a/src/mapserver/qgsconfigparser.h b/src/mapserver/qgsconfigparser.h index e80b74a..813b565 100644 --- a/src/mapserver/qgsconfigparser.h +++ b/src/mapserver/qgsconfigparser.h @@ -97,6 +97,9 @@ class QgsConfigParser virtual QStringList identifyDisabledLayers() const { return QStringList(); } /**Returns an ID-list of layers which queryable in WFS service*/ virtual QStringList wfsLayers() const { return QStringList(); } + virtual QStringList wfstUpdateLayers() const { return QStringList(); } + virtual QStringList wfstInsertLayers() const { return QStringList(); } + virtual QStringList wfstDeleteLayers() const { return QStringList(); } /**Returns a set of supported epsg codes for the capabilities document. An empty list means that all possible CRS should be advertised (which could result in very long capabilities documents)*/ diff --git a/src/mapserver/qgspostrequesthandler.cpp b/src/mapserver/qgspostrequesthandler.cpp index b6116d3..855e847 100644 --- a/src/mapserver/qgspostrequesthandler.cpp +++ b/src/mapserver/qgspostrequesthandler.cpp @@ -17,6 +17,7 @@ #include "qgspostrequesthandler.h" #include "qgslogger.h" +#include QgsPostRequestHandler::QgsPostRequestHandler() { @@ -32,6 +33,36 @@ QMap QgsPostRequestHandler::parseInput() QMap parameters; QString inputString = readPostBody(); QgsDebugMsg( inputString ); - requestStringToParameterMap( inputString, parameters ); + + QDomDocument doc; + QString errorMsg; + if ( !doc.setContent( inputString, true, &errorMsg ) ) + { + requestStringToParameterMap( inputString, parameters ); + } + else + { + QString queryString; + const char* qs = getenv( "QUERY_STRING" ); + if ( qs ) + { + queryString = QString( qs ); + QgsDebugMsg( "query string is: " + queryString ); + } + else + { + QgsDebugMsg( "error, no query string found but a QDomDocument" ); + return parameters; //no query string? something must be wrong... + } + + requestStringToParameterMap( queryString, parameters ); + + QDomElement docElem = doc.documentElement(); + parameters.insert( "VERSION", docElem.attribute( "version" ) ); + parameters.insert( "SERVICE", docElem.attribute( "service" ) ); + parameters.insert( "REQUEST", docElem.localName() ); + parameters.insert( "REQUEST_BODY", inputString ); + } + return parameters; } diff --git a/src/mapserver/qgsprojectparser.cpp b/src/mapserver/qgsprojectparser.cpp index 5129c01..8d6374b 100644 --- a/src/mapserver/qgsprojectparser.cpp +++ b/src/mapserver/qgsprojectparser.cpp @@ -131,6 +131,9 @@ void QgsProjectParser::layersAndStylesCapabilities( QDomElement& parentElement, void QgsProjectParser::featureTypeList( QDomElement& parentElement, QDomDocument& doc ) const { QStringList wfsLayersId = wfsLayers(); + QStringList wfstUpdateLayersId = wfstUpdateLayers(); + QStringList wfstInsertLayersId = wfstInsertLayers(); + QStringList wfstDeleteLayersId = wfstDeleteLayers(); if ( mProjectLayerElements.size() < 1 ) { @@ -193,6 +196,37 @@ void QgsProjectParser::featureTypeList( QDomElement& parentElement, QDomDocument bBoxElement.setAttribute( "maxx", QString::number( layerExtent.xMaximum() ) ); bBoxElement.setAttribute( "maxy", QString::number( layerExtent.yMaximum() ) ); layerElem.appendChild( bBoxElement ); + + //wfs:Operations element + QDomElement operationsElement = doc.createElement( "Operations"/*wfs:Operations*/ ); + //wfs:Query element + QDomElement queryElement = doc.createElement( "Query"/*wfs:Query*/ ); + operationsElement.appendChild( queryElement ); + + QgsVectorLayer* vlayer = qobject_cast( layer ); + QgsVectorDataProvider* provider = vlayer->dataProvider(); + if ( ( provider->capabilities() & QgsVectorDataProvider::AddFeatures ) && wfstInsertLayersId.contains( layer->id() ) ) + { + //wfs:Insert element + QDomElement insertElement = doc.createElement( "Insert"/*wfs:Insert*/ ); + operationsElement.appendChild( insertElement ); + } + if ( (provider->capabilities() & QgsVectorDataProvider::ChangeAttributeValues ) && + (provider->capabilities() & QgsVectorDataProvider::ChangeGeometries ) && + wfstUpdateLayersId.contains( layer->id() ) ) + { + //wfs:Update element + QDomElement updateElement = doc.createElement( "Update"/*wfs:Update*/ ); + operationsElement.appendChild( updateElement ); + } + if ( ( provider->capabilities() & QgsVectorDataProvider::DeleteFeatures ) && wfstDeleteLayersId.contains( layer->id() ) ) + { + //wfs:Delete element + QDomElement deleteElement = doc.createElement( "Delete"/*wfs:Delete*/ ); + operationsElement.appendChild( deleteElement ); + } + + layerElem.appendChild( operationsElement ); parentElement.appendChild( layerElem ); } @@ -954,6 +988,123 @@ QStringList QgsProjectParser::wfsLayers() const return wfsList; } +QStringList QgsProjectParser::wfstUpdateLayers() const +{ + QStringList publiedIds = wfsLayers(); + QStringList wfsList; + if ( !mXMLDoc ) + { + return wfsList; + } + + QDomElement qgisElem = mXMLDoc->documentElement(); + if ( qgisElem.isNull() ) + { + return wfsList; + } + QDomElement propertiesElem = qgisElem.firstChildElement( "properties" ); + if ( propertiesElem.isNull() ) + { + return wfsList; + } + QDomElement wfstLayersElem = propertiesElem.firstChildElement( "WFSTLayers" ); + if ( wfstLayersElem.isNull() ) + { + return wfsList; + } + QDomElement wfstUpdateLayersElem = wfstLayersElem.firstChildElement( "Update" ); + if ( wfstUpdateLayersElem.isNull() ) + { + return wfsList; + } + QDomNodeList valueList = wfstUpdateLayersElem.elementsByTagName( "value" ); + for ( int i = 0; i < valueList.size(); ++i ) + { + QString id = valueList.at( i ).toElement().text(); + if ( publiedIds.contains( id ) ) + wfsList << id; + } + return wfsList; +} + +QStringList QgsProjectParser::wfstInsertLayers() const +{ + QStringList updateIds = wfstUpdateLayers(); + QStringList wfsList; + if ( !mXMLDoc ) + { + return wfsList; + } + + QDomElement qgisElem = mXMLDoc->documentElement(); + if ( qgisElem.isNull() ) + { + return wfsList; + } + QDomElement propertiesElem = qgisElem.firstChildElement( "properties" ); + if ( propertiesElem.isNull() ) + { + return wfsList; + } + QDomElement wfstLayersElem = propertiesElem.firstChildElement( "WFSTLayers" ); + if ( wfstLayersElem.isNull() ) + { + return wfsList; + } + QDomElement wfstInsertLayersElem = wfstLayersElem.firstChildElement( "Insert" ); + if ( wfstInsertLayersElem.isNull() ) + { + return wfsList; + } + QDomNodeList valueList = wfstInsertLayersElem.elementsByTagName( "value" ); + for ( int i = 0; i < valueList.size(); ++i ) + { + QString id = valueList.at( i ).toElement().text(); + if ( updateIds.contains( id ) ) + wfsList << id; + } + return wfsList; +} + +QStringList QgsProjectParser::wfstDeleteLayers() const +{ + QStringList insertIds = wfstInsertLayers(); + QStringList wfsList; + if ( !mXMLDoc ) + { + return wfsList; + } + + QDomElement qgisElem = mXMLDoc->documentElement(); + if ( qgisElem.isNull() ) + { + return wfsList; + } + QDomElement propertiesElem = qgisElem.firstChildElement( "properties" ); + if ( propertiesElem.isNull() ) + { + return wfsList; + } + QDomElement wfstLayersElem = propertiesElem.firstChildElement( "WFSTLayers" ); + if ( wfstLayersElem.isNull() ) + { + return wfsList; + } + QDomElement wfstDeleteLayersElem = wfstLayersElem.firstChildElement( "Delete" ); + if ( wfstDeleteLayersElem.isNull() ) + { + return wfsList; + } + QDomNodeList valueList = wfstDeleteLayersElem.elementsByTagName( "value" ); + for ( int i = 0; i < valueList.size(); ++i ) + { + QString id = valueList.at( i ).toElement().text(); + if ( insertIds.contains( id ) ) + wfsList << id; + } + return wfsList; +} + QStringList QgsProjectParser::supportedOutputCrsList() const { QStringList crsList; diff --git a/src/mapserver/qgsprojectparser.h b/src/mapserver/qgsprojectparser.h index 1a39b1a..eefcc3d 100644 --- a/src/mapserver/qgsprojectparser.h +++ b/src/mapserver/qgsprojectparser.h @@ -66,6 +66,9 @@ class QgsProjectParser: public QgsConfigParser /**Returns an ID-list of layers queryable for WFS service (comes from -> in the project file*/ virtual QStringList wfsLayers() const; + virtual QStringList wfstUpdateLayers() const; + virtual QStringList wfstInsertLayers() const; + virtual QStringList wfstDeleteLayers() const; /**Returns a set of supported epsg codes for the capabilities document. The list comes from the property in the project file. An empty set means that all possible CRS should be advertised (which could result in very long capabilities documents) diff --git a/src/mapserver/qgswfsserver.cpp b/src/mapserver/qgswfsserver.cpp index ee07efe..1228410 100644 --- a/src/mapserver/qgswfsserver.cpp +++ b/src/mapserver/qgswfsserver.cpp @@ -54,6 +54,17 @@ #include #include +#ifndef Q_WS_WIN +#include +#else +#include +#endif + +static const QString WFS_NAMESPACE = "http://www.opengis.net/wfs"; +static const QString GML_NAMESPACE = "http://www.opengis.net/gml"; +static const QString OGC_NAMESPACE = "http://www.opengis.net/ogc"; +static const QString QGS_NAMESPACE = "http://www.qgis.org/gml"; + QgsWFSServer::QgsWFSServer( QMap parameters ) : mParameterMap( parameters ) , mConfigParser( 0 ) @@ -74,11 +85,11 @@ QDomDocument QgsWFSServer::getCapabilities() QDomDocument doc; //wfs:WFS_Capabilities element QDomElement wfsCapabilitiesElement = doc.createElement( "WFS_Capabilities"/*wms:WFS_Capabilities*/ ); - wfsCapabilitiesElement.setAttribute( "xmlns", "http://www.opengis.net/wfs" ); + wfsCapabilitiesElement.setAttribute( "xmlns", WFS_NAMESPACE ); wfsCapabilitiesElement.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" ); - wfsCapabilitiesElement.setAttribute( "xsi:schemaLocation", "http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/wfs.xsd" ); - wfsCapabilitiesElement.setAttribute( "xmlns:ogc", "http://www.opengis.net/ogc" ); - wfsCapabilitiesElement.setAttribute( "xmlns:gml", "http://www.opengis.net/gml" ); + wfsCapabilitiesElement.setAttribute( "xsi:schemaLocation", WFS_NAMESPACE+" http://schemas.opengis.net/wfs/1.0.0/wfs.xsd" ); + wfsCapabilitiesElement.setAttribute( "xmlns:ogc", OGC_NAMESPACE ); + wfsCapabilitiesElement.setAttribute( "xmlns:gml", GML_NAMESPACE ); wfsCapabilitiesElement.setAttribute( "xmlns:ows", "http://www.opengis.net/ows" ); wfsCapabilitiesElement.setAttribute( "xmlns:xlink", "http://www.w3.org/1999/xlink" ); wfsCapabilitiesElement.setAttribute( "version", "1.0.0" ); @@ -195,6 +206,13 @@ QDomDocument QgsWFSServer::getCapabilities() QDomElement getFeatureDhcTypeElement = dcpTypeElement.cloneNode().toElement();//this is the same as for 'GetCapabilities' getFeatureElement.appendChild( getFeatureDhcTypeElement ); + //wfs:Transaction + QDomElement transactionElement = doc.createElement( "Transaction"/*wfs:Transaction*/ ); + requestElement.appendChild( transactionElement ); + QDomElement transactionDhcTypeElement = dcpTypeElement.cloneNode().toElement();//this is the same as for 'GetCapabilities' + transactionDhcTypeElement.firstChild().firstChild().toElement().setTagName( "Post" ); + transactionElement.appendChild( transactionDhcTypeElement ); + //wfs:FeatureTypeList element QDomElement featureTypeListElement = doc.createElement( "FeatureTypeList"/*wfs:FeatureTypeList*/ ); wfsCapabilitiesElement.appendChild( featureTypeListElement ); @@ -217,7 +235,7 @@ QDomDocument QgsWFSServer::getCapabilities() */ //ogc:Filter_Capabilities element QDomElement filterCapabilitiesElement = doc.createElement( "ogc:Filter_Capabilities"/*ogc:Filter_Capabilities*/ ); - capabilityElement.appendChild( filterCapabilitiesElement ); + wfsCapabilitiesElement.appendChild( filterCapabilitiesElement ); QDomElement spatialCapabilitiesElement = doc.createElement( "ogc:Spatial_Capabilities"/*ogc:Spatial_Capabilities*/ ); filterCapabilitiesElement.appendChild( spatialCapabilitiesElement ); QDomElement spatialOperatorsElement = doc.createElement( "ogc:Spatial_Operators"/*ogc:Spatial_Operators*/ ); @@ -241,17 +259,17 @@ QDomDocument QgsWFSServer::describeFeatureType() QDomElement schemaElement = doc.createElement( "schema"/*xsd:schema*/ ); schemaElement.setAttribute( "xmlns", "http://www.w3.org/2001/XMLSchema" ); schemaElement.setAttribute( "xmlns:xsd", "http://www.w3.org/2001/XMLSchema" ); - schemaElement.setAttribute( "xmlns:ogc", "http://www.opengis.net/ogc" ); - schemaElement.setAttribute( "xmlns:gml", "http://www.opengis.net/gml" ); - schemaElement.setAttribute( "xmlns:qgs", "http://www.qgis.org/gml" ); - schemaElement.setAttribute( "targetNamespace", "http://www.qgis.org/gml" ); + schemaElement.setAttribute( "xmlns:ogc", OGC_NAMESPACE ); + schemaElement.setAttribute( "xmlns:gml", GML_NAMESPACE ); + schemaElement.setAttribute( "xmlns:qgs", QGS_NAMESPACE ); + schemaElement.setAttribute( "targetNamespace", QGS_NAMESPACE ); schemaElement.setAttribute( "elementFromDefault", "qualified" ); schemaElement.setAttribute( "version", "1.0" ); doc.appendChild( schemaElement ); //xsd:import QDomElement importElement = doc.createElement( "import"/*xsd:import*/ ); - importElement.setAttribute( "namespace", "http://www.opengis.net/gml" ); + importElement.setAttribute( "namespace", GML_NAMESPACE ); importElement.setAttribute( "schemaLocation", "http://schemas.opengis.net/gml/2.1.2/feature.xsd" ); schemaElement.appendChild( importElement ); @@ -518,7 +536,7 @@ void QgsWFSServer::startGetFeature( QgsRequestHandler& request, const QString& f if ( format == "GeoJSON" ) { fcString = "{\"type\": \"FeatureCollection\",\n"; - fcString += " \"bbox\": [ " + QString::number( rect->xMinimum(), 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ) + ", " + QString::number( rect->yMinimum(), 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ) + ", " + QString::number( rect->xMaximum(), 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ) + ", " + QString::number( rect->yMaximum(), 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ) + "],\n"; + fcString += " \"bbox\": [ " + QString::number( rect->xMinimum(), 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ) + ", " + QString::number( rect->yMinimum(), 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ) + ", " + QString::number( rect->xMaximum(), 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ) + ", " + QString::number( rect->yMaximum(), 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ) + "],\n"; fcString += " \"features\": [\n"; result = fcString.toUtf8(); request.startGetFeatureResponse( &result, format ); @@ -601,23 +619,23 @@ void QgsWFSServer::startGetFeature( QgsRequestHandler& request, const QString& f mapUrl.addQueryItem( "OUTPUTFORMAT", "XMLSCHEMA" ); hrefString = mapUrl.toString(); - //wfs:FeatureCollection + //wfs:FeatureCollection valid fcString = " fields, QSet excludedAttributes ) /*const*/ +QDomDocument QgsWFSServer::transaction( const QString& requestBody ) +{ + // Getting the transaction document + QDomDocument doc; + QString errorMsg; + if ( !doc.setContent( requestBody, true, &errorMsg ) ) + { + throw QgsMapServiceException( "RequestNotWellFormed", errorMsg ); + } + + QDomElement docElem = doc.documentElement(); + QDomNodeList docChildNodes = docElem.childNodes(); + + // Re-organize the transaction document + QDomDocument mDoc; + QDomElement mDocElem = mDoc.createElement( "myTransactionDocument" ); + mDocElem.setAttribute( "xmlns", QGS_NAMESPACE ); + mDocElem.setAttribute( "xmlns:wfs", WFS_NAMESPACE ); + mDocElem.setAttribute( "xmlns:gml", GML_NAMESPACE ); + mDocElem.setAttribute( "xmlns:ogc", OGC_NAMESPACE ); + mDocElem.setAttribute( "xmlns:qgs", QGS_NAMESPACE ); + mDocElem.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" ); + mDoc.appendChild( mDocElem ); + + QDomElement actionElem; + QString actionName; + QDomElement typeNameElem; + QString typeName; + + for ( int i = docChildNodes.count(); 0 < i; --i ) + { + actionElem = docChildNodes.at( i-1 ).toElement(); + actionName = actionElem.localName(); + + if (actionName == "Insert" ) + { + QDomElement featureElem = actionElem.firstChild().toElement(); + typeName = featureElem.localName(); + } + else if ( actionName == "Update" ) + { + typeName = actionElem.attribute( "typeName" ); + } + else if ( actionName == "Delete" ) + { + typeName = actionElem.attribute( "typeName" ); + } + + QDomNodeList typeNameList = mDocElem.elementsByTagName( typeName ); + if ( typeNameList.count() == 0 ) + { + typeNameElem = mDoc.createElement( typeName ); + mDocElem.appendChild( typeNameElem ); + } + else + typeNameElem = typeNameList.at(0).toElement(); + + typeNameElem.appendChild( actionElem ); + } + + // It's time to make the transaction + // Create the response document + QDomDocument resp; + //wfs:WFS_TransactionRespone element + QDomElement respElem = resp.createElement( "WFS_TransactionResponse"/*wfs:WFS_TransactionResponse*/ ); + respElem.setAttribute( "xmlns", WFS_NAMESPACE ); + respElem.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" ); + respElem.setAttribute( "xsi:schemaLocation", WFS_NAMESPACE+" http://schemas.opengis.net/wfs/1.0.0/wfs.xsd" ); + respElem.setAttribute( "xmlns:ogc", OGC_NAMESPACE ); + respElem.setAttribute( "version", "1.0.0" ); + resp.appendChild( respElem ); + + // Store the created feature id + QgsFeatureIds insertResults; + // Get the WFS layers id + QStringList wfsLayersId = mConfigParser->wfsLayers(); + + QList layerList; + QgsMapLayer* currentLayer = 0; + + // Loop through the layer transaction elements + docChildNodes = mDocElem.childNodes(); + for ( int i = 0; i < docChildNodes.count(); ++i ) + { + // Get the vector layer + typeNameElem = docChildNodes.at( i ).toElement(); + typeName = typeNameElem.tagName(); + + layerList = mConfigParser->mapLayerFromStyle( typeName, "" ); + currentLayer = layerList.at( 0 ); + + QgsVectorLayer* layer = qobject_cast( currentLayer ); + // it's a vectorlayer and definy by the administrator as a WFS layer + if ( layer && wfsLayersId.contains( layer->id() ) ) + { + // Get the provider and it's capabilities + QgsVectorDataProvider* provider = layer->dataProvider(); + if ( !provider ) + { + continue; + } + int cap = provider->capabilities(); + + // Start the update transaction + layer->startEditing(); + if ( (cap & QgsVectorDataProvider::ChangeAttributeValues ) && (cap & QgsVectorDataProvider::ChangeGeometries ) ) + { + // Loop through the update elements for this layer + QDomNodeList upNodeList = typeNameElem.elementsByTagNameNS( WFS_NAMESPACE, "Update" ); + for ( int j = 0; j < upNodeList.count(); ++j ) + { + actionElem = upNodeList.at( j ).toElement(); + + // Get the Feature Ids for this filter on the layer + QDomElement filterElem = actionElem.elementsByTagName( "Filter" ).at( 0 ).toElement(); + QgsFeatureIds fids = getFeatureIdsFromFilter( filterElem, layer ); + + // Loop through the property elements + // Store properties and the geometry element + QDomNodeList propertyNodeList = actionElem.elementsByTagName( "Property" ); + QMap propertyMap; + QDomElement propertyElem; + QDomElement nameElem; + QDomElement valueElem; + QDomElement geometryElem; + + for ( int l = 0; l < propertyNodeList.count(); ++l ) + { + propertyElem = propertyNodeList.at( l ).toElement(); + nameElem = propertyElem.elementsByTagName( "Name" ).at( 0 ).toElement(); + valueElem = propertyElem.elementsByTagName( "Value" ).at( 0 ).toElement(); + if ( nameElem.text() != "geometry" ) + { + propertyMap.insert( nameElem.text(), valueElem.text() ); + } + else + { + geometryElem = valueElem; + } + } + + // Update the features + const QgsFieldMap& fields = provider->fields(); + QgsFieldMap::const_iterator fieldIt; + QMap fieldMap = provider->fieldNameMap(); + QMap::const_iterator fieldMapIt; + QString fieldName; + bool conversionSuccess; + + QgsFeatureIds::const_iterator fidIt = fids.constBegin(); + for ( ; fidIt != fids.constEnd(); ++fidIt ) + { + QMap< QString, QString >::const_iterator it = propertyMap.constBegin(); + for ( ; it != propertyMap.constEnd(); ++it ) + { + fieldName = it.key(); + fieldMapIt = fieldMap.find( fieldName ); + if ( fieldMapIt == fieldMap.constEnd() ) + { + continue; + } + fieldIt = fields.find( fieldMapIt.value() ); + if ( fieldIt == fields.constEnd() ) + { + continue; + } + if ( fieldIt.value().type() == 2 ) + layer->changeAttributeValue( *fidIt, fieldIt.key(), it.value().toInt( &conversionSuccess ) ); + else if ( fieldIt.value().type() == 6 ) + layer->changeAttributeValue( *fidIt, fieldIt.key(), it.value().toDouble( &conversionSuccess ) ); + else + layer->changeAttributeValue( *fidIt, fieldIt.key(), it.value() ); + } + + if ( !geometryElem.isNull() ) { + if (!layer->changeGeometry( *fidIt, QgsGeometry::fromGML2( geometryElem ) ) ) + throw QgsMapServiceException( "RequestNotWellFormed", "Error in change geometry" ); + } + } + } + } + // Commit the changes of the update elements + if ( !layer->commitChanges() ) + { + QDomElement trElem = doc.createElement( "TransactionResult" ); + QDomElement stElem = doc.createElement( "Status" ); + QDomElement successElem = doc.createElement( "PARTIAL" ); + stElem.appendChild( successElem ); + trElem.appendChild( stElem ); + respElem.appendChild( trElem ); + + QDomElement locElem = doc.createElement( "Locator" ); + locElem.appendChild( doc.createTextNode( "Update" ) ); + trElem.appendChild( locElem ); + + QDomElement mesElem = doc.createElement( "Message" ); + mesElem.appendChild( doc.createTextNode( layer->commitErrors().join( "\n " ) ) ); + trElem.appendChild( mesElem ); + + return resp; + } + // Start the delete transaction + layer->startEditing(); + if ( ( cap & QgsVectorDataProvider::DeleteFeatures ) ) + { + // Loop through the delete elements + QDomNodeList delNodeList = typeNameElem.elementsByTagNameNS( WFS_NAMESPACE, "Delete" ); + for ( int j = 0; j < delNodeList.count(); ++j ) + { + actionElem = delNodeList.at( j ).toElement(); + QDomElement filterElem = actionElem.firstChild().toElement(); + // Get Feature Ids for the Filter element + QgsFeatureIds fids = getFeatureIdsFromFilter( filterElem, layer ); + layer->setSelectedFeatures( fids ); + layer->deleteSelectedFeatures(); + } + } + // Commit the changes of the delete elements + if ( !layer->commitChanges() ) + { + QDomElement trElem = doc.createElement( "TransactionResult" ); + QDomElement stElem = doc.createElement( "Status" ); + QDomElement successElem = doc.createElement( "PARTIAL" ); + stElem.appendChild( successElem ); + trElem.appendChild( stElem ); + respElem.appendChild( trElem ); + + QDomElement locElem = doc.createElement( "Locator" ); + locElem.appendChild( doc.createTextNode( "Delete" ) ); + trElem.appendChild( locElem ); + + QDomElement mesElem = doc.createElement( "Message" ); + mesElem.appendChild( doc.createTextNode( layer->commitErrors().join( "\n " ) ) ); + trElem.appendChild( mesElem ); + + return resp; + } + // Start the insert transaction + layer->startEditing(); + // Store the inserted features + QgsFeatureList inFeatList; + if ( cap & QgsVectorDataProvider::AddFeatures ) + { + // Get Layer Field Information + const QgsFieldMap& fields = provider->fields(); + QgsFieldMap::const_iterator fieldIt; + QMap fieldMap = provider->fieldNameMap(); + QMap::const_iterator fieldMapIt; + QString fieldName; + + // Loop through the insert elements + QDomNodeList inNodeList = typeNameElem.elementsByTagNameNS( WFS_NAMESPACE, "Insert" ); + for ( int j = 0; j < inNodeList.count(); ++j ) + { + actionElem = inNodeList.at( j ).toElement(); + // Loop through the feature element + QDomNodeList featNodes = actionElem.childNodes(); + for ( int l = 0; l< featNodes.count(); l++ ) + { + // Create feature for this layer + QgsFeature* f = new QgsFeature(); + unsigned char* wkb = 0; + int wkbSize = 0; + QGis::WkbType currentType; + + QDomElement featureElem = featNodes.at(l).toElement(); + + QDomNode currentAttributeChild = featureElem.firstChild(); + + while ( !currentAttributeChild.isNull() ) + { + QDomElement currentAttributeElement = currentAttributeChild.toElement(); + QString attrName = currentAttributeElement.localName(); + + if ( attrName != "boundedBy" ) + { + if ( attrName != "geometry" ) //a normal attribute + { + fieldMapIt = fieldMap.find( attrName ); + if ( fieldMapIt == fieldMap.constEnd() ) + { + continue; + } + fieldIt = fields.find( fieldMapIt.value() ); + if ( fieldIt == fields.constEnd() ) + { + continue; + } + QString attrValue = currentAttributeElement.text(); + int attrType = fieldIt.value().type(); + if ( attrType == 2 ) + f->addAttribute( fieldIt.key(), attrValue.toInt() ); + else if ( attrType == 6 ) + f->addAttribute( fieldIt.key(), attrValue.toDouble() ); + else + f->addAttribute( fieldIt.key(), attrValue ); + } + else //a geometry attribute + { + f->setGeometry( QgsGeometry::fromGML2( currentAttributeElement ) ); + } + } + currentAttributeChild = currentAttributeChild.nextSibling(); + } + // Add the feature to th layer + // and store it to put it's Feature Id in the response + layer->addFeature( *f, true ); + inFeatList << *f; + } + } + } + // Commit the changes of the insert elements + if ( !layer->commitChanges() ) + { + QDomElement trElem = doc.createElement( "TransactionResult" ); + QDomElement stElem = doc.createElement( "Status" ); + QDomElement successElem = doc.createElement( "PARTIAL" ); + stElem.appendChild( successElem ); + trElem.appendChild( stElem ); + respElem.appendChild( trElem ); + + QDomElement locElem = doc.createElement( "Locator" ); + locElem.appendChild( doc.createTextNode( "Insert" ) ); + trElem.appendChild( locElem ); + + QDomElement mesElem = doc.createElement( "Message" ); + mesElem.appendChild( doc.createTextNode( layer->commitErrors().join( "\n " ) ) ); + trElem.appendChild( mesElem ); + + return resp; + } + // Get the Feature Ids of the inserted feature + for (int j = 0; j < inFeatList.size(); j++ ) + { + insertResults.insert( inFeatList[j].id() ); + } + } + } + + // Put the Feature Ids of the inserted feature + if ( insertResults.size() > 0 ) + { + QDomElement irsElem = doc.createElement( "InsertResults" ); + QgsFeatureIds::const_iterator irIt = insertResults.constBegin(); + for ( ; irIt != insertResults.constEnd(); ++irIt ) + { + QDomElement irElem = doc.createElement( "InsertResult" ); + QDomElement fiElem = doc.createElement( "ogc:FeatureId" ); + fiElem.setAttribute( "fid", *irIt ); + irElem.appendChild( fiElem ); + irsElem.appendChild( irElem ); + } + respElem.appendChild( irsElem ); + } + + // Set the transaction reposne for success + QDomElement trElem = doc.createElement( "TransactionResult" ); + QDomElement stElem = doc.createElement( "Status" ); + QDomElement successElem = doc.createElement( "SUCCESS" ); + stElem.appendChild( successElem ); + trElem.appendChild( stElem ); + respElem.appendChild( trElem ); + + return resp; +} + +QgsFeatureIds QgsWFSServer::getFeatureIdsFromFilter( QDomElement filter, QgsVectorLayer* layer ) +{ + QgsFeatureIds fids; + + QgsVectorDataProvider* provider = layer->dataProvider(); + QDomElement filterFirstElem = filter.firstChild().toElement(); + + if ( filterFirstElem.localName() == "FeatureId" ) + { + bool conversionSuccess; + fids.insert( filterFirstElem.attribute( "fid" ).toInt( &conversionSuccess ) ); + } + else + { + QgsFeature feature; + QgsFilter* mFilter = QgsFilter::createFilterFromXml( filter, layer ); + while ( provider->nextFeature( feature ) ) + { + if ( mFilter ) + { + if ( mFilter->evaluate( feature ) ) + { + fids.insert( feature.id() ); + } + } + } + } + + return fids; +} + +QString QgsWFSServer::createFeatureGeoJSON( QgsFeature* feat, QgsCoordinateReferenceSystem &, QMap< int, QgsField > fields, QSet hiddenAttributes ) /*const*/ { QString fStr = "{\"type\": \"Feature\",\n"; @@ -697,7 +1112,7 @@ QString QgsWFSServer::createFeatureGeoJSON( QgsFeature* feat, QgsCoordinateRefer { QgsRectangle box = geom->boundingBox(); - fStr += " \"bbox\": [ " + QString::number( box.xMinimum(), 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ) + ", " + QString::number( box.yMinimum(), 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ) + ", " + QString::number( box.xMaximum(), 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ) + ", " + QString::number( box.yMaximum(), 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ) + "],\n"; + fStr += " \"bbox\": [ " + QString::number( box.xMinimum(), 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ) + ", " + QString::number( box.yMinimum(), 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ) + ", " + QString::number( box.xMaximum(), 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ) + ", " + QString::number( box.yMaximum(), 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ) + "],\n"; fStr += " \"geometry\": "; fStr += geom->exportToGeoJSON(); @@ -744,7 +1159,7 @@ QString QgsWFSServer::createFeatureGeoJSON( QgsFeature* feat, QgsCoordinateRefer return fStr; } -QDomElement QgsWFSServer::createFeatureElem( QgsFeature* feat, QDomDocument& doc, QgsCoordinateReferenceSystem& crs, QMap< int, QgsField > fields, QSet excludedAttributes ) /*const*/ +QDomElement QgsWFSServer::createFeatureGML2( QgsFeature* feat, QDomDocument& doc, QgsCoordinateReferenceSystem& crs, QMap< int, QgsField > fields, QSet hiddenAttributes ) /*const*/ { //gml:FeatureMember QDomElement featureElement = doc.createElement( "gml:featureMember"/*wfs:FeatureMember*/ ); @@ -760,12 +1175,12 @@ QDomElement QgsWFSServer::createFeatureElem( QgsFeature* feat, QDomDocument& doc QgsGeometry* geom = feat->geometry(); QDomElement geomElem = doc.createElement( "qgs:geometry" ); - QDomElement gmlElem = createGeometryElem( geom, doc ); + QDomElement gmlElem = geom->exportToGML2( doc ); if ( !gmlElem.isNull() ) { QgsRectangle box = geom->boundingBox(); QDomElement bbElem = doc.createElement( "gml:boundedBy" ); - QDomElement boxElem = createBoxElem( &box, doc ); + QDomElement boxElem = createBoxGML2( &box, doc ); if ( crs.isValid() ) { @@ -802,7 +1217,7 @@ QDomElement QgsWFSServer::createFeatureElem( QgsFeature* feat, QDomDocument& doc return featureElement; } -QDomElement QgsWFSServer::createBoxElem( QgsRectangle* box, QDomDocument& doc ) /*const*/ +QDomElement QgsWFSServer::createBoxGML2( QgsRectangle* box, QDomDocument& doc ) /*const*/ { if ( !box ) { @@ -817,207 +1232,18 @@ QDomElement QgsWFSServer::createBoxElem( QgsRectangle* box, QDomDocument& doc ) QgsPoint p2; p2.set( box->xMaximum(), box->yMaximum() ); v.append( p2 ); - QDomElement coordElem = createCoordinateElem( v, doc ); + QDomElement coordElem = createCoordinateGML2( v, doc ); boxElem.appendChild( coordElem ); return boxElem; } -QDomElement QgsWFSServer::createGeometryElem( QgsGeometry* geom, QDomDocument& doc ) /*const*/ -{ - if ( !geom ) - { - return QDomElement(); - } - - QDomElement geomElement; - - QString geomTypeName; - QGis::WkbType wkbType = geom->wkbType(); - switch ( wkbType ) - { - case QGis::WKBPoint: - case QGis::WKBPoint25D: - geomElement = createPointElem( geom, doc ); - break; - case QGis::WKBMultiPoint: - case QGis::WKBMultiPoint25D: - geomElement = createMultiPointElem( geom, doc ); - break; - case QGis::WKBLineString: - case QGis::WKBLineString25D: - geomElement = createLineStringElem( geom, doc ); - break; - case QGis::WKBMultiLineString: - case QGis::WKBMultiLineString25D: - geomElement = createMultiLineStringElem( geom, doc ); - break; - case QGis::WKBPolygon: - case QGis::WKBPolygon25D: - geomElement = createPolygonElem( geom, doc ); - break; - case QGis::WKBMultiPolygon: - case QGis::WKBMultiPolygon25D: - geomElement = createMultiPolygonElem( geom, doc ); - break; - default: - return QDomElement(); - } - return geomElement; -} - -QDomElement QgsWFSServer::createLineStringElem( QgsGeometry* geom, QDomDocument& doc ) const -{ - if ( !geom ) - { - return QDomElement(); - } - - QDomElement lineStringElem = doc.createElement( "gml:LineString" ); - QDomElement coordElem = createCoordinateElem( geom->asPolyline(), doc ); - lineStringElem.appendChild( coordElem ); - return lineStringElem; -} - -QDomElement QgsWFSServer::createMultiLineStringElem( QgsGeometry* geom, QDomDocument& doc ) const -{ - if ( !geom ) - { - return QDomElement(); - } - - QDomElement multiLineStringElem = doc.createElement( "gml:MultiLineString" ); - QgsMultiPolyline multiline = geom->asMultiPolyline(); - - QgsMultiPolyline::const_iterator multiLineIt = multiline.constBegin(); - for ( ; multiLineIt != multiline.constEnd(); ++multiLineIt ) - { - QgsGeometry* lineGeom = QgsGeometry::fromPolyline( *multiLineIt ); - if ( lineGeom ) - { - QDomElement lineStringMemberElem = doc.createElement( "gml:lineStringMember" ); - QDomElement lineElem = createLineStringElem( lineGeom, doc ); - lineStringMemberElem.appendChild( lineElem ); - multiLineStringElem.appendChild( lineStringMemberElem ); - } - delete lineGeom; - } - - return multiLineStringElem; -} - -QDomElement QgsWFSServer::createPointElem( QgsGeometry* geom, QDomDocument& doc ) const -{ - if ( !geom ) - { - return QDomElement(); - } - - QDomElement pointElem = doc.createElement( "gml:Point" ); - QgsPoint p = geom->asPoint(); - QVector v; - v.append( p ); - QDomElement coordElem = createCoordinateElem( v, doc ); - pointElem.appendChild( coordElem ); - return pointElem; -} - -QDomElement QgsWFSServer::createMultiPointElem( QgsGeometry* geom, QDomDocument& doc ) const -{ - if ( !geom ) - { - return QDomElement(); - } - - QDomElement multiPointElem = doc.createElement( "gml:MultiPoint" ); - QgsMultiPoint multiPoint = geom->asMultiPoint(); - - QgsMultiPoint::const_iterator multiPointIt = multiPoint.constBegin(); - for ( ; multiPointIt != multiPoint.constEnd(); ++multiPointIt ) - { - QgsGeometry* pointGeom = QgsGeometry::fromPoint( *multiPointIt ); - if ( pointGeom ) - { - QDomElement multiPointMemberElem = doc.createElement( "gml:pointMember" ); - QDomElement pointElem = createPointElem( pointGeom, doc ); - multiPointMemberElem.appendChild( pointElem ); - multiPointElem.appendChild( multiPointMemberElem ); - } - } - return multiPointElem; -} - -QDomElement QgsWFSServer::createPolygonElem( QgsGeometry* geom, QDomDocument& doc ) const -{ - if ( !geom ) - { - return QDomElement(); - } - - QDomElement polygonElem = doc.createElement( "gml:Polygon" ); - QgsPolygon poly = geom->asPolygon(); - for ( int i = 0; i < poly.size(); ++i ) - { - QString boundaryName; - if ( i == 0 ) - { - boundaryName = "gml:outerBoundaryIs"; - } - else - { - boundaryName = "gml:innerBoundaryIs"; - } - QDomElement boundaryElem = doc.createElement( boundaryName ); - QDomElement ringElem = doc.createElement( "gml:LinearRing" ); - QDomElement coordElem = createCoordinateElem( poly.at( i ), doc ); - ringElem.appendChild( coordElem ); - boundaryElem.appendChild( ringElem ); - polygonElem.appendChild( boundaryElem ); - } - return polygonElem; -} - -QDomElement QgsWFSServer::createMultiPolygonElem( QgsGeometry* geom, QDomDocument& doc ) const -{ - if ( !geom ) - { - return QDomElement(); - } - QDomElement multiPolygonElem = doc.createElement( "gml:MultiPolygon" ); - QgsMultiPolygon multipoly = geom->asMultiPolygon(); - - QgsMultiPolygon::const_iterator polyIt = multipoly.constBegin(); - for ( ; polyIt != multipoly.constEnd(); ++polyIt ) - { - QgsGeometry* polygonGeom = QgsGeometry::fromPolygon( *polyIt ); - if ( polygonGeom ) - { - QDomElement polygonMemberElem = doc.createElement( "gml:polygonMember" ); - QDomElement polygonElem = createPolygonElem( polygonGeom, doc ); - delete polygonGeom; - polygonMemberElem.appendChild( polygonElem ); - multiPolygonElem.appendChild( polygonMemberElem ); - } - } - return multiPolygonElem; -} - -QDomElement QgsWFSServer::createCoordinateElem( const QVector points, QDomDocument& doc ) const +QDomElement QgsWFSServer::createCoordinateGML2( const QVector points, QDomDocument& doc ) const { QDomElement coordElem = doc.createElement( "gml:coordinates" ); coordElem.setAttribute( "cs", "," ); coordElem.setAttribute( "ts", " " ); -#if 0 - //precision 4 for meters / feet, precision 8 for degrees - int precision = 6; - if ( mSourceCRS.mapUnits() == QGis::Meters - || mSourceCRS.mapUnits() == QGis::Feet ) - { - precision = 4; - } -#endif - QString coordString; QVector::const_iterator pointIt = points.constBegin(); for ( ; pointIt != points.constEnd(); ++pointIt ) @@ -1026,9 +1252,9 @@ QDomElement QgsWFSServer::createCoordinateElem( const QVector points, { coordString += " "; } - coordString += QString::number( pointIt->x(), 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + coordString += QString::number( pointIt->x(), 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); coordString += ","; - coordString += QString::number( pointIt->y(), 'f', 6 ).remove( QRegExp( "[0]{1,5}$" ) ); + coordString += QString::number( pointIt->y(), 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); } QDomText coordText = doc.createTextNode( coordString ); diff --git a/src/mapserver/qgswfsserver.h b/src/mapserver/qgswfsserver.h index 69ceeb6..e2f9c06 100644 --- a/src/mapserver/qgswfsserver.h +++ b/src/mapserver/qgswfsserver.h @@ -22,6 +22,8 @@ #include #include #include +#include "qgis.h" +#include "qgsvectorlayer.h" class QgsCoordinateReferenceSystem; class QgsComposerLayerItem; @@ -66,6 +68,10 @@ class QgsWFSServer @return 0 in case of success*/ int getFeature( QgsRequestHandler& request, const QString& format ); + /**Read and apply the transaction + @return 0 in case of success*/ + QDomDocument transaction( const QString& requestBody ); + /**Sets configuration parser for administration settings. Does not take ownership*/ void setAdminConfigParser( QgsConfigParser* parser ) { mConfigParser = parser; } @@ -85,26 +91,22 @@ class QgsWFSServer void sendGetFeature( QgsRequestHandler& request, const QString& format, QgsFeature* feat, int featIdx, QgsCoordinateReferenceSystem& crs, QMap< int, QgsField > fields, QSet excludedAttributes ); void endGetFeature( QgsRequestHandler& request, const QString& format ); + //method for transaction + QgsFeatureIds getFeatureIdsFromFilter( QDomElement filter, QgsVectorLayer* layer ); + //methods to write GeoJSON QString createFeatureGeoJSON( QgsFeature* feat, QgsCoordinateReferenceSystem& crs, QMap< int, QgsField > fields, QSet excludedAttributes ) /*const*/; //methods to write GML2 - QDomElement createFeatureElem( QgsFeature* feat, QDomDocument& doc, QgsCoordinateReferenceSystem& crs, QMap< int, QgsField > fields, QSet excludedAttributes ) /*const*/; + QDomElement createFeatureGML2( QgsFeature* feat, QDomDocument& doc, QgsCoordinateReferenceSystem& crs, QMap< int, QgsField > fields, QSet hiddenAttributes ) /*const*/; - QDomElement createBoxElem( QgsRectangle* box, QDomDocument& doc ) /* const */; - QDomElement createGeometryElem( QgsGeometry* g, QDomDocument& doc ) /*const*/; - QDomElement createLineStringElem( QgsGeometry* geom, QDomDocument& doc ) const; - QDomElement createMultiLineStringElem( QgsGeometry* geom, QDomDocument& doc ) const; - QDomElement createPointElem( QgsGeometry* geom, QDomDocument& doc ) const; - QDomElement createMultiPointElem( QgsGeometry* geom, QDomDocument& doc ) const; - QDomElement createPolygonElem( QgsGeometry* geom, QDomDocument& doc ) const; - QDomElement createMultiPolygonElem( QgsGeometry* geom, QDomDocument& doc ) const; + QDomElement createBoxGML2( QgsRectangle* box, QDomDocument& doc ) /* const */; /**Create a GML coordinate string from a point list. @param points list of data points @param coordString out: GML coord string @return 0 in case of success*/ - QDomElement createCoordinateElem( const QVector points, QDomDocument& doc ) const; + QDomElement createCoordinateGML2( const QVector points, QDomDocument& doc ) const; }; #endif diff --git a/src/providers/wfs/qgswfsprovider.cpp b/src/providers/wfs/qgswfsprovider.cpp index 6721607..77c6bb2 100644 --- a/src/providers/wfs/qgswfsprovider.cpp +++ b/src/providers/wfs/qgswfsprovider.cpp @@ -423,7 +423,7 @@ bool QgsWFSProvider::addFeatures( QgsFeatureList &flist ) //add geometry column (as gml) QDomElement geomElem = transactionDoc.createElementNS( mWfsNamespace, mGeometryAttribute ); - QDomElement gmlElem = createGeometryElem( featureIt->geometry(), transactionDoc ); + QDomElement gmlElem = featureIt->geometry()->exportToGML2( transactionDoc ); if ( !gmlElem.isNull() ) { geomElem.appendChild( gmlElem ); @@ -574,7 +574,7 @@ bool QgsWFSProvider::changeGeometryValues( QgsGeometryMap & geometry_map ) nameElem.appendChild( nameText ); propertyElem.appendChild( nameElem ); QDomElement valueElem = transactionDoc.createElementNS( "http://www.opengis.net/wfs", "Value" ); - QDomElement gmlElem = createGeometryElem( &geomIt.value(), transactionDoc ); + QDomElement gmlElem = (&geomIt.value())->exportToGML2( transactionDoc ); valueElem.appendChild( gmlElem ); propertyElem.appendChild( valueElem ); updateElem.appendChild( propertyElem ); @@ -1295,9 +1295,7 @@ int QgsWFSProvider::getFeaturesFromGML2( const QDomElement& wfsCollectionElement } else //a geometry attribute { - getWkbFromGML2( currentAttributeElement, &wkb, &wkbSize, ¤tType ); - mWKBType = currentType; //a more sophisticated method is necessary - f->setGeometryAndOwnership( wkb, wkbSize ); + f->setGeometry( QgsGeometry::fromGML2( currentAttributeElement ) ); } } currentAttributeChild = currentAttributeChild.nextSibling(); @@ -1314,533 +1312,6 @@ int QgsWFSProvider::getFeaturesFromGML2( const QDomElement& wfsCollectionElement return 0; } -int QgsWFSProvider::getWkbFromGML2( const QDomNode& geometryElement, unsigned char** wkb, int* wkbSize, QGis::WkbType* type ) const -{ - QDomNode geometryChild = geometryElement.firstChild(); - if ( geometryChild.isNull() ) - { - return 1; - } - QDomElement geometryTypeElement = geometryChild.toElement(); - QString geomType = geometryTypeElement.localName(); - if ( geomType == "Point" ) - { - return getWkbFromGML2Point( geometryTypeElement, wkb, wkbSize, type ); - } - else if ( geomType == "LineString" ) - { - return getWkbFromGML2LineString( geometryTypeElement, wkb, wkbSize, type ); - } - else if ( geomType == "Polygon" ) - { - return getWkbFromGML2Polygon( geometryTypeElement, wkb, wkbSize, type ); - } - else if ( geomType == "MultiPoint" ) - { - return getWkbFromGML2MultiPoint( geometryTypeElement, wkb, wkbSize, type ); - } - else if ( geomType == "MultiLineString" ) - { - return getWkbFromGML2MultiLineString( geometryTypeElement, wkb, wkbSize, type ); - } - else if ( geomType == "MultiPolygon" ) - { - return getWkbFromGML2MultiPolygon( geometryTypeElement, wkb, wkbSize, type ); - } - else //unknown type - { - *wkb = 0; - *wkbSize = 0; - } - return 0; -} - -int QgsWFSProvider::getWkbFromGML2Point( const QDomElement& geometryElement, unsigned char** wkb, int* wkbSize, QGis::WkbType* type ) const -{ - QDomNodeList coordList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); - if ( coordList.size() < 1 ) - { - return 1; - } - QDomElement coordElement = coordList.at( 0 ).toElement(); - std::list pointCoordinate; - if ( readGML2Coordinates( pointCoordinate, coordElement ) != 0 ) - { - return 2; - } - - if ( pointCoordinate.size() < 1 ) - { - return 3; - } - - std::list::const_iterator point_it = pointCoordinate.begin(); - char e = QgsApplication::endian(); - double x = point_it->x(); - double y = point_it->y(); - int size = 1 + sizeof( int ) + 2 * sizeof( double ); - *wkb = new unsigned char[size]; - *wkbSize = size; - *type = QGis::WKBPoint; - int wkbPosition = 0; //current offset from wkb beginning (in bytes) - memcpy( &( *wkb )[wkbPosition], &e, 1 ); - wkbPosition += 1; - memcpy( &( *wkb )[wkbPosition], type, sizeof( int ) ); - wkbPosition += sizeof( int ); - memcpy( &( *wkb )[wkbPosition], &x, sizeof( double ) ); - wkbPosition += sizeof( double ); - memcpy( &( *wkb )[wkbPosition], &y, sizeof( double ) ); - return 0; -} - -int QgsWFSProvider::getWkbFromGML2Polygon( const QDomElement& geometryElement, unsigned char** wkb, int* wkbSize, QGis::WkbType* type ) const -{ - //read all the coordinates (as QgsPoint) into memory. Each linear ring has an entry in the vector - std::vector > ringCoordinates; - - //read coordinates for outer boundary - QDomNodeList outerBoundaryList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "outerBoundaryIs" ); - if ( outerBoundaryList.size() < 1 ) //outer ring is necessary - { - return 1; - } - QDomElement coordinatesElement = outerBoundaryList.at( 0 ).firstChild().firstChild().toElement(); - if ( coordinatesElement.isNull() ) - { - return 2; - } - std::list exteriorPointList; - if ( readGML2Coordinates( exteriorPointList, coordinatesElement ) != 0 ) - { - return 3; - } - ringCoordinates.push_back( exteriorPointList ); - - //read coordinates for inner boundary - QDomNodeList innerBoundaryList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "innerBoundaryIs" ); - for ( int i = 0; i < innerBoundaryList.size(); ++i ) - { - std::list interiorPointList; - QDomElement coordinatesElement = innerBoundaryList.at( i ).firstChild().firstChild().toElement(); - if ( coordinatesElement.isNull() ) - { - return 4; - } - if ( readGML2Coordinates( interiorPointList, coordinatesElement ) != 0 ) - { - return 5; - } - ringCoordinates.push_back( interiorPointList ); - } - - //calculate number of bytes to allocate - int nrings = ringCoordinates.size(); - int npoints = 0;//total number of points - for ( std::vector >::const_iterator it = ringCoordinates.begin(); it != ringCoordinates.end(); ++it ) - { - npoints += it->size(); - } - int size = 1 + 2 * sizeof( int ) + nrings * sizeof( int ) + 2 * npoints * sizeof( double ); - *wkb = new unsigned char[size]; - *wkbSize = size; - *type = QGis::WKBPolygon; - char e = QgsApplication::endian(); - int wkbPosition = 0; //current offset from wkb beginning (in bytes) - int nPointsInRing = 0; - double x, y; - - //fill the contents into *wkb - memcpy( &( *wkb )[wkbPosition], &e, 1 ); - wkbPosition += 1; - memcpy( &( *wkb )[wkbPosition], type, sizeof( int ) ); - wkbPosition += sizeof( int ); - memcpy( &( *wkb )[wkbPosition], &nrings, sizeof( int ) ); - wkbPosition += sizeof( int ); - for ( std::vector >::const_iterator it = ringCoordinates.begin(); it != ringCoordinates.end(); ++it ) - { - nPointsInRing = it->size(); - memcpy( &( *wkb )[wkbPosition], &nPointsInRing, sizeof( int ) ); - wkbPosition += sizeof( int ); - //iterate through the string list converting the strings to x-/y- doubles - std::list::const_iterator iter; - for ( iter = it->begin(); iter != it->end(); ++iter ) - { - x = iter->x(); - y = iter->y(); - //qWarning("currentCoordinate: " + QString::number(x) + " // " + QString::number(y)); - memcpy( &( *wkb )[wkbPosition], &x, sizeof( double ) ); - wkbPosition += sizeof( double ); - memcpy( &( *wkb )[wkbPosition], &y, sizeof( double ) ); - wkbPosition += sizeof( double ); - } - } - return 0; -} - -int QgsWFSProvider::getWkbFromGML2LineString( const QDomElement& geometryElement, unsigned char** wkb, int* wkbSize, QGis::WkbType* type ) const -{ - QDomNodeList coordinatesList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); - if ( coordinatesList.size() < 1 ) - { - return 1; - } - QDomElement coordinatesElement = coordinatesList.at( 0 ).toElement(); - std::list lineCoordinates; - if ( readGML2Coordinates( lineCoordinates, coordinatesElement ) != 0 ) - { - return 2; - } - - char e = QgsApplication::endian(); - int size = 1 + 2 * sizeof( int ) + lineCoordinates.size() * 2 * sizeof( double ); - *wkb = new unsigned char[size]; - *wkbSize = size; - *type = QGis::WKBLineString; - int wkbPosition = 0; //current offset from wkb beginning (in bytes) - double x, y; - int nPoints = lineCoordinates.size(); - - //fill the contents into *wkb - memcpy( &( *wkb )[wkbPosition], &e, 1 ); - wkbPosition += 1; - memcpy( &( *wkb )[wkbPosition], type, sizeof( int ) ); - wkbPosition += sizeof( int ); - memcpy( &( *wkb )[wkbPosition], &nPoints, sizeof( int ) ); - wkbPosition += sizeof( int ); - - std::list::const_iterator iter; - for ( iter = lineCoordinates.begin(); iter != lineCoordinates.end(); ++iter ) - { - x = iter->x(); - y = iter->y(); - memcpy( &( *wkb )[wkbPosition], &x, sizeof( double ) ); - wkbPosition += sizeof( double ); - memcpy( &( *wkb )[wkbPosition], &y, sizeof( double ) ); - wkbPosition += sizeof( double ); - } - return 0; -} - -int QgsWFSProvider::getWkbFromGML2MultiPoint( const QDomElement& geometryElement, unsigned char** wkb, int* wkbSize, QGis::WkbType* type ) const -{ - std::list pointList; - std::list currentPoint; - QDomNodeList pointMemberList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "pointMember" ); - if ( pointMemberList.size() < 1 ) - { - return 1; - } - QDomNodeList pointNodeList; - QDomNodeList coordinatesList; - for ( int i = 0; i < pointMemberList.size(); ++i ) - { - // element - pointNodeList = pointMemberList.at( i ).toElement().elementsByTagNameNS( GML_NAMESPACE, "Point" ); - if ( pointNodeList.size() < 1 ) - { - continue; - } - // element - coordinatesList = pointNodeList.at( 0 ).toElement().elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); - if ( coordinatesList.size() < 1 ) - { - continue; - } - currentPoint.clear(); - if ( readGML2Coordinates( currentPoint, coordinatesList.at( 0 ).toElement() ) != 0 ) - { - continue; - } - if ( currentPoint.size() < 1 ) - { - continue; - } - pointList.push_back(( *currentPoint.begin() ) ); - } - - //calculate the required wkb size - int size = 1 + 2 * sizeof( int ) + pointList.size() * ( 2 * sizeof( double ) + 1 + sizeof( int ) ); - *wkb = new unsigned char[size]; - *wkbSize = size; - *type = QGis::WKBMultiPoint; - - //fill the wkb content - char e = QgsApplication::endian(); - int wkbPosition = 0; //current offset from wkb beginning (in bytes) - int nPoints = pointList.size(); //number of points - double x, y; - memcpy( &( *wkb )[wkbPosition], &e, 1 ); - wkbPosition += 1; - memcpy( &( *wkb )[wkbPosition], type, sizeof( int ) ); - wkbPosition += sizeof( int ); - memcpy( &( *wkb )[wkbPosition], &nPoints, sizeof( int ) ); - wkbPosition += sizeof( int ); - for ( std::list::const_iterator it = pointList.begin(); it != pointList.end(); ++it ) - { - memcpy( &( *wkb )[wkbPosition], &e, 1 ); - wkbPosition += 1; - memcpy( &( *wkb )[wkbPosition], type, sizeof( int ) ); - wkbPosition += sizeof( int ); - x = it->x(); - memcpy( &( *wkb )[wkbPosition], &x, sizeof( double ) ); - wkbPosition += sizeof( double ); - y = it->y(); - memcpy( &( *wkb )[wkbPosition], &y, sizeof( double ) ); - wkbPosition += sizeof( double ); - } - return 0; -} - -int QgsWFSProvider::getWkbFromGML2MultiLineString( const QDomElement& geometryElement, unsigned char** wkb, int* wkbSize, QGis::WkbType* type ) const -{ - //geoserver has - // - // - // - - //mapserver has directly - // > lineCoordinates; //first list: lines, second list: points of one line - QDomElement currentLineStringElement; - QDomNodeList currentCoordList; - - QDomNodeList lineStringMemberList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "lineStringMember" ); - if ( lineStringMemberList.size() > 0 ) //geoserver - { - for ( int i = 0; i < lineStringMemberList.size(); ++i ) - { - QDomNodeList lineStringNodeList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "LineString" ); - if ( lineStringNodeList.size() < 1 ) - { - return 1; - } - currentLineStringElement = lineStringNodeList.at( 0 ).toElement(); - currentCoordList = currentLineStringElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); - if ( currentCoordList.size() < 1 ) - { - return 2; - } - std::list currentPointList; - if ( readGML2Coordinates( currentPointList, currentCoordList.at( 0 ).toElement() ) != 0 ) - { - return 3; - } - lineCoordinates.push_back( currentPointList ); - } - } - else - { - QDomNodeList lineStringList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "LineString" ); - if ( lineStringList.size() > 0 ) //mapserver - { - for ( int i = 0; i < lineStringList.size(); ++i ) - { - currentLineStringElement = lineStringList.at( i ).toElement(); - currentCoordList = currentLineStringElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); - if ( currentCoordList.size() < 1 ) - { - return 4; - } - std::list currentPointList; - if ( readGML2Coordinates( currentPointList, currentCoordList.at( 0 ).toElement() ) != 0 ) - { - return 5; - } - lineCoordinates.push_back( currentPointList ); - } - } - else - { - return 6; - } - } - - - //calculate the required wkb size - int size = ( lineCoordinates.size() + 1 ) * ( 1 + 2 * sizeof( int ) ); - for ( std::list >::const_iterator it = lineCoordinates.begin(); it != lineCoordinates.end(); ++it ) - { - size += it->size() * 2 * sizeof( double ); - } - *wkb = new unsigned char[size]; - *wkbSize = size; - *type = QGis::WKBMultiLineString; - - //fill the wkb content - char e = QgsApplication::endian(); - int wkbPosition = 0; //current offset from wkb beginning (in bytes) - int nLines = lineCoordinates.size(); - int nPoints; //number of points in a line - double x, y; - memcpy( &( *wkb )[wkbPosition], &e, 1 ); - wkbPosition += 1; - memcpy( &( *wkb )[wkbPosition], type, sizeof( int ) ); - wkbPosition += sizeof( int ); - memcpy( &( *wkb )[wkbPosition], &nLines, sizeof( int ) ); - wkbPosition += sizeof( int ); - for ( std::list >::const_iterator it = lineCoordinates.begin(); it != lineCoordinates.end(); ++it ) - { - memcpy( &( *wkb )[wkbPosition], &e, 1 ); - wkbPosition += 1; - memcpy( &( *wkb )[wkbPosition], type, sizeof( int ) ); - wkbPosition += sizeof( int ); - nPoints = it->size(); - memcpy( &( *wkb )[wkbPosition], &nPoints, sizeof( int ) ); - wkbPosition += sizeof( int ); - for ( std::list::const_iterator iter = it->begin(); iter != it->end(); ++iter ) - { - x = iter->x(); - //qWarning("x is: " + QString::number(x)); - y = iter->y(); - //qWarning("y is: " + QString::number(y)); - memcpy( &( *wkb )[wkbPosition], &x, sizeof( double ) ); - wkbPosition += sizeof( double ); - memcpy( &( *wkb )[wkbPosition], &y, sizeof( double ) ); - wkbPosition += sizeof( double ); - } - } - return 0; -} - -int QgsWFSProvider::getWkbFromGML2MultiPolygon( const QDomElement& geometryElement, unsigned char** wkb, int* wkbSize, QGis::WkbType* type ) const -{ - //first list: different polygons, second list: different rings, third list: different points - std::list > > multiPolygonPoints; - QDomElement currentPolygonMemberElement; - QDomNodeList polygonList; - QDomElement currentPolygonElement; - QDomNodeList outerBoundaryList; - QDomElement currentOuterBoundaryElement; - QDomElement currentInnerBoundaryElement; - QDomNodeList innerBoundaryList; - QDomNodeList linearRingNodeList; - QDomElement currentLinearRingElement; - QDomNodeList currentCoordinateList; - - QDomNodeList polygonMemberList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "polygonMember" ); - for ( int i = 0; i < polygonMemberList.size(); ++i ) - { - std::list > currentPolygonList; - currentPolygonMemberElement = polygonMemberList.at( i ).toElement(); - polygonList = currentPolygonMemberElement.elementsByTagNameNS( GML_NAMESPACE, "Polygon" ); - if ( polygonList.size() < 1 ) - { - continue; - } - currentPolygonElement = polygonList.at( 0 ).toElement(); - - //find exterior ring - outerBoundaryList = currentPolygonElement.elementsByTagNameNS( GML_NAMESPACE, "outerBoundaryIs" ); - if ( outerBoundaryList.size() < 1 ) - { - continue; - } - - currentOuterBoundaryElement = outerBoundaryList.at( 0 ).toElement(); - std::list ringCoordinates; - - linearRingNodeList = currentOuterBoundaryElement.elementsByTagNameNS( GML_NAMESPACE, "LinearRing" ); - if ( linearRingNodeList.size() < 1 ) - { - continue; - } - currentLinearRingElement = linearRingNodeList.at( 0 ).toElement(); - currentCoordinateList = currentLinearRingElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); - if ( currentCoordinateList.size() < 1 ) - { - continue; - } - if ( readGML2Coordinates( ringCoordinates, currentCoordinateList.at( 0 ).toElement() ) != 0 ) - { - continue; - } - currentPolygonList.push_back( ringCoordinates ); - - //find interior rings - QDomNodeList innerBoundaryList = currentPolygonElement.elementsByTagNameNS( GML_NAMESPACE, "innerBoundaryIs" ); - for ( int j = 0; j < innerBoundaryList.size(); ++j ) - { - std::list ringCoordinates; - currentInnerBoundaryElement = innerBoundaryList.at( j ).toElement(); - linearRingNodeList = currentInnerBoundaryElement.elementsByTagNameNS( GML_NAMESPACE, "LinearRing" ); - if ( linearRingNodeList.size() < 1 ) - { - continue; - } - currentLinearRingElement = linearRingNodeList.at( 0 ).toElement(); - currentCoordinateList = currentLinearRingElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); - if ( currentCoordinateList.size() < 1 ) - { - continue; - } - if ( readGML2Coordinates( ringCoordinates, currentCoordinateList.at( 0 ).toElement() ) != 0 ) - { - continue; - } - currentPolygonList.push_back( ringCoordinates ); - } - multiPolygonPoints.push_back( currentPolygonList ); - } - - int size = 1 + 2 * sizeof( int ); - //calculate the wkb size - for ( std::list > >::const_iterator it = multiPolygonPoints.begin(); it != multiPolygonPoints.end(); ++it ) - { - size += 1 + 2 * sizeof( int ); - for ( std::list >::const_iterator iter = it->begin(); iter != it->end(); ++iter ) - { - size += sizeof( int ) + 2 * iter->size() * sizeof( double ); - } - } - *wkb = new unsigned char[size]; - *wkbSize = size; - *type = QGis::WKBMultiPolygon; - int polygonType = QGis::WKBPolygon; - char e = QgsApplication::endian(); - int wkbPosition = 0; //current offset from wkb beginning (in bytes) - double x, y; - int nPolygons = multiPolygonPoints.size(); - int nRings; - int nPointsInRing; - - //fill the contents into *wkb - memcpy( &( *wkb )[wkbPosition], &e, 1 ); - wkbPosition += 1; - memcpy( &( *wkb )[wkbPosition], type, sizeof( int ) ); - wkbPosition += sizeof( int ); - memcpy( &( *wkb )[wkbPosition], &nPolygons, sizeof( int ) ); - wkbPosition += sizeof( int ); - - for ( std::list > >::const_iterator it = multiPolygonPoints.begin(); it != multiPolygonPoints.end(); ++it ) - { - memcpy( &( *wkb )[wkbPosition], &e, 1 ); - wkbPosition += 1; - memcpy( &( *wkb )[wkbPosition], &polygonType, sizeof( int ) ); - wkbPosition += sizeof( int ); - nRings = it->size(); - memcpy( &( *wkb )[wkbPosition], &nRings, sizeof( int ) ); - wkbPosition += sizeof( int ); - for ( std::list >::const_iterator iter = it->begin(); iter != it->end(); ++iter ) - { - nPointsInRing = iter->size(); - memcpy( &( *wkb )[wkbPosition], &nPointsInRing, sizeof( int ) ); - wkbPosition += sizeof( int ); - for ( std::list::const_iterator iterator = iter->begin(); iterator != iter->end(); ++iterator ) - { - x = iterator->x(); - y = iterator->y(); - memcpy( &( *wkb )[wkbPosition], &x, sizeof( double ) ); - wkbPosition += sizeof( double ); - memcpy( &( *wkb )[wkbPosition], &y, sizeof( double ) ); - wkbPosition += sizeof( double ); - } - } - } - return 0; -} - int QgsWFSProvider::readGML2Coordinates( std::list& coords, const QDomElement elem ) const { QString coordSeparator = ","; @@ -1901,221 +1372,6 @@ void QgsWFSProvider::handleWFSProgressMessage( int done, int total ) emit dataReadProgressMessage( message ); } -QDomElement QgsWFSProvider::createGeometryElem( QgsGeometry* geom, QDomDocument& doc ) /*const*/ -{ - if ( !geom ) - { - return QDomElement(); - } - - QDomElement geomElement; - - QString geomTypeName; - QGis::WkbType wkbType = geom->wkbType(); - switch ( wkbType ) - { - case QGis::WKBPoint: - geomElement = createPointElem( geom, doc ); - break; - case QGis::WKBMultiPoint: - geomElement = createMultiPointElem( geom, doc ); - break; - case QGis::WKBLineString: - geomElement = createLineStringElem( geom, doc ); - break; - case QGis::WKBMultiLineString: - geomElement = createMultiLineStringElem( geom, doc ); - break; - case QGis::WKBPolygon: - geomElement = createPolygonElem( geom, doc ); - break; - case QGis::WKBMultiPolygon: - geomElement = createMultiPolygonElem( geom, doc ); - break; - default: - return QDomElement(); - } - - if ( !geomElement.isNull() ) - { - //append layer srs - QgsCoordinateReferenceSystem layerCrs = crs(); - if ( layerCrs.isValid() ) - { - geomElement.setAttribute( "srsName", layerCrs.authid() ); - } - } - return geomElement; -} - -QDomElement QgsWFSProvider::createLineStringElem( QgsGeometry* geom, QDomDocument& doc ) const -{ - if ( !geom ) - { - return QDomElement(); - } - - QDomElement lineStringElem = doc.createElementNS( "http://www.opengis.net/gml", "LineString" ); - QDomElement coordElem = createCoordinateElem( geom->asPolyline(), doc ); - lineStringElem.appendChild( coordElem ); - return lineStringElem; -} - -QDomElement QgsWFSProvider::createMultiLineStringElem( QgsGeometry* geom, QDomDocument& doc ) const -{ - if ( !geom ) - { - return QDomElement(); - } - - QDomElement multiLineStringElem = doc.createElementNS( "http://www.opengis.net/gml", "MultiLineString" ); - QgsMultiPolyline multiline = geom->asMultiPolyline(); - - QgsMultiPolyline::const_iterator multiLineIt = multiline.constBegin(); - for ( ; multiLineIt != multiline.constEnd(); ++multiLineIt ) - { - QgsGeometry* lineGeom = QgsGeometry::fromPolyline( *multiLineIt ); - if ( lineGeom ) - { - QDomElement lineStringMemberElem = doc.createElementNS( "http://www.opengis.net/gml", "lineStringMember" ); - QDomElement lineElem = createLineStringElem( lineGeom, doc ); - lineStringMemberElem.appendChild( lineElem ); - multiLineStringElem.appendChild( lineStringMemberElem ); - } - delete lineGeom; - } - - return multiLineStringElem; -} - -QDomElement QgsWFSProvider::createPointElem( QgsGeometry* geom, QDomDocument& doc ) const -{ - if ( !geom ) - { - return QDomElement(); - } - - QDomElement pointElem = doc.createElementNS( "http://www.opengis.net/gml", "Point" ); - QgsPoint p = geom->asPoint(); - QVector v; - v.append( p ); - QDomElement coordElem = createCoordinateElem( v, doc ); - pointElem.appendChild( coordElem ); - return pointElem; -} - -QDomElement QgsWFSProvider::createMultiPointElem( QgsGeometry* geom, QDomDocument& doc ) const -{ - if ( !geom ) - { - return QDomElement(); - } - - QDomElement multiPointElem = doc.createElementNS( "http://www.opengis.net/gml", "MultiPoint" ); - QgsMultiPoint multiPoint = geom->asMultiPoint(); - - QgsMultiPoint::const_iterator multiPointIt = multiPoint.constBegin(); - for ( ; multiPointIt != multiPoint.constEnd(); ++multiPointIt ) - { - QgsGeometry* pointGeom = QgsGeometry::fromPoint( *multiPointIt ); - if ( pointGeom ) - { - QDomElement multiPointMemberElem = doc.createElementNS( "http://www.opengis.net/gml", "pointMember" ); - QDomElement pointElem = createPointElem( pointGeom, doc ); - multiPointMemberElem.appendChild( pointElem ); - multiPointElem.appendChild( multiPointMemberElem ); - } - } - return multiPointElem; -} - -QDomElement QgsWFSProvider::createPolygonElem( QgsGeometry* geom, QDomDocument& doc ) const -{ - if ( !geom ) - { - return QDomElement(); - } - - QDomElement polygonElem = doc.createElementNS( "http://www.opengis.net/gml", "Polygon" ); - QgsPolygon poly = geom->asPolygon(); - for ( int i = 0; i < poly.size(); ++i ) - { - QString boundaryName; - if ( i == 0 ) - { - boundaryName = "outerBoundaryIs"; - } - else - { - boundaryName = "innerBoundaryIs"; - } - QDomElement boundaryElem = doc.createElementNS( "http://www.opengis.net/gml", boundaryName ); - QDomElement ringElem = doc.createElementNS( "http://www.opengis.net/gml", "LinearRing" ); - QDomElement coordElem = createCoordinateElem( poly.at( i ), doc ); - ringElem.appendChild( coordElem ); - boundaryElem.appendChild( ringElem ); - polygonElem.appendChild( boundaryElem ); - } - return polygonElem; -} - -QDomElement QgsWFSProvider::createMultiPolygonElem( QgsGeometry* geom, QDomDocument& doc ) const -{ - if ( !geom ) - { - return QDomElement(); - } - QDomElement multiPolygonElem = doc.createElementNS( "http://www.opengis.net/gml", "MultiPolygon" ); - QgsMultiPolygon multipoly = geom->asMultiPolygon(); - - QgsMultiPolygon::const_iterator polyIt = multipoly.constBegin(); - for ( ; polyIt != multipoly.constEnd(); ++polyIt ) - { - QgsGeometry* polygonGeom = QgsGeometry::fromPolygon( *polyIt ); - if ( polygonGeom ) - { - QDomElement polygonMemberElem = doc.createElementNS( "http://www.opengis.net/gml", "polygonMember" ); - QDomElement polygonElem = createPolygonElem( polygonGeom, doc ); - delete polygonGeom; - polygonMemberElem.appendChild( polygonElem ); - multiPolygonElem.appendChild( polygonMemberElem ); - } - } - return multiPolygonElem; -} - -QDomElement QgsWFSProvider::createCoordinateElem( const QVector points, QDomDocument& doc ) const -{ - QDomElement coordElem = doc.createElementNS( "http://www.opengis.net/gml", "coordinates" ); - coordElem.setAttribute( "cs", "," ); - coordElem.setAttribute( "ts", " " ); - - //precision 4 for meters / feet, precision 8 for degrees - int precision = 8; - if ( mSourceCRS.mapUnits() == QGis::Meters - || mSourceCRS.mapUnits() == QGis::Feet ) - { - precision = 4; - } - - QString coordString; - QVector::const_iterator pointIt = points.constBegin(); - for ( ; pointIt != points.constEnd(); ++pointIt ) - { - if ( pointIt != points.constBegin() ) - { - coordString += " "; - } - coordString += QString::number( pointIt->x(), 'f', precision ); - coordString += ","; - coordString += QString::number( pointIt->y(), 'f', precision ); - } - - QDomText coordText = doc.createTextNode( coordString ); - coordElem.appendChild( coordText ); - return coordElem; -} - QString QgsWFSProvider::name() const { return TEXT_PROVIDER_KEY; @@ -2184,7 +1440,18 @@ bool QgsWFSProvider::sendTransactionDocument( const QDomDocument& doc, QDomDocum } mNetworkRequestFinished = false; - QString serverUrl = dataSourceUri().split( "?" ).at( 0 ); + + QUrl typeDetectionUri( dataSourceUri() ); + typeDetectionUri.removeQueryItem( "REQUEST" ); + typeDetectionUri.removeQueryItem( "TYPENAME" ); + typeDetectionUri.removeQueryItem( "BBOX" ); + typeDetectionUri.removeQueryItem( "FILTER" ); + typeDetectionUri.removeQueryItem( "FEATUREID" ); + typeDetectionUri.removeQueryItem( "PROPERTYNAME" ); + typeDetectionUri.removeQueryItem( "MAXFEATURES" ); + typeDetectionUri.removeQueryItem( "OUTPUTFORMAT" ); + QString serverUrl = typeDetectionUri.toString(); + QNetworkRequest request( serverUrl ); request.setHeader( QNetworkRequest::ContentTypeHeader, "text/xml" ); QNetworkReply* reply = QgsNetworkAccessManager::instance()->post( request, doc.toByteArray( -1 ) ); @@ -2216,6 +1483,7 @@ QDomElement QgsWFSProvider::createTransactionElement( QDomDocument& doc ) const { transactionElem.setAttribute( "xmlns:" + namespacePrefix, mWfsNamespace ); } + transactionElem.setAttribute( "xmlns:gml", GML_NAMESPACE ); return transactionElem; } diff --git a/src/providers/wfs/qgswfsprovider.h b/src/providers/wfs/qgswfsprovider.h index a59099a..b36f82c 100644 --- a/src/providers/wfs/qgswfsprovider.h +++ b/src/providers/wfs/qgswfsprovider.h @@ -226,20 +226,6 @@ class QgsWFSProvider: public QgsVectorDataProvider int getExtentFromGML2( QgsRectangle* extent, const QDomElement& wfsCollectionElement ) const; int getFeaturesFromGML2( const QDomElement& wfsCollectionElement, const QString& geometryAttribute ); - - int getWkbFromGML2( const QDomNode& geometryElement, unsigned char** wkb, int* wkbSize, QGis::WkbType* type ) const; - /**Creates WKB from a element*/ - int getWkbFromGML2Point( const QDomElement& geometryElement, unsigned char** wkb, int* wkbSize, QGis::WkbType* type ) const; - /**Creates WKB from a element*/ - int getWkbFromGML2Polygon( const QDomElement& geometryElement, unsigned char** wkb, int* wkbSize, QGis::WkbType* type ) const; - /**Creates WKB from a element*/ - int getWkbFromGML2LineString( const QDomElement& geometryElement, unsigned char** wkb, int* wkbSize, QGis::WkbType* type ) const; - /**Creates WKB from a element*/ - int getWkbFromGML2MultiPoint( const QDomElement& geometryElement, unsigned char** wkb, int* wkbSize, QGis::WkbType* type ) const; - /**Creates WKB from a element*/ - int getWkbFromGML2MultiLineString( const QDomElement& geometryElement, unsigned char** wkb, int* wkbSize, QGis::WkbType* type ) const; - /**Creates WKB from a element*/ - int getWkbFromGML2MultiPolygon( const QDomElement& geometryElement, unsigned char** wkb, int* wkbSize, QGis::WkbType* type ) const; /**Reads the element and extracts the coordinates as points @param coords list where the found coordinates are appended @param elem the element @@ -248,23 +234,6 @@ class QgsWFSProvider: public QgsVectorDataProvider /**Tries to create a QgsCoordinateReferenceSystem object and assign it to mSourceCRS. Returns 0 in case of success*/ int setCRSFromGML2( const QDomElement& wfsCollectionElement ); - - //methods to write GML2 - - QDomElement createGeometryElem( QgsGeometry* g, QDomDocument& doc ) /*const*/; - QDomElement createLineStringElem( QgsGeometry* geom, QDomDocument& doc ) const; - QDomElement createMultiLineStringElem( QgsGeometry* geom, QDomDocument& doc ) const; - QDomElement createPointElem( QgsGeometry* geom, QDomDocument& doc ) const; - QDomElement createMultiPointElem( QgsGeometry* geom, QDomDocument& doc ) const; - QDomElement createPolygonElem( QgsGeometry* geom, QDomDocument& doc ) const; - QDomElement createMultiPolygonElem( QgsGeometry* geom, QDomDocument& doc ) const; - - /**Create a GML coordinate string from a point list. - @param points list of data points - @param coordString out: GML coord string - @return 0 in case of success*/ - QDomElement createCoordinateElem( const QVector points, QDomDocument& doc ) const; - //helper methods for WFS-T /**Returns HTTP parameter value from url (or empty string if it does not exist)*/ diff --git a/src/ui/qgsprojectpropertiesbase.ui b/src/ui/qgsprojectpropertiesbase.ui index 4fd7321..2841138 100644 --- a/src/ui/qgsprojectpropertiesbase.ui +++ b/src/ui/qgsprojectpropertiesbase.ui @@ -1225,6 +1225,21 @@ Published + + + Update + + + + + Insert + + + + + Delete + +