190 changes: 88 additions & 102 deletions src/core/qgsgml.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/***************************************************************************
qgsgml.cpp
--------------------------------------
Date : Sun Sep 16 12:19:51 AKDT 2007
Copyright : (C) 2007 by Gary E. Sherman
Email : sherman at mrcc dot com
qgsgml.cpp
---------------------
begin : February 2013
copyright : (C) 2013 by Radim Blazek
email : radim dot blazek at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
Expand Down Expand Up @@ -36,11 +36,12 @@ QgsGml::QgsGml(
const QString& typeName,
const QString& geometryAttribute,
const QgsFields & fields )
: QObject(),
mTypeName( typeName ),
mGeometryAttribute( geometryAttribute ),
mFinished( false ),
mFeatureCount( 0 )
: QObject()
, mTypeName( typeName )
, mGeometryAttribute( geometryAttribute )
, mFinished( false )
, mFeatureCount( 0 )
, mCurrentWKBSize( 0 )
{
mThematicAttributes.clear();
for ( int i = 0; i < fields.size(); i++ )
Expand All @@ -59,18 +60,14 @@ int QgsGml::getFeatures( const QString& uri, QGis::WkbType* wkbType, QgsRectangl
{
mUri = uri;
mWkbType = wkbType;
mExtent = extent;

XML_Parser p = XML_ParserCreateNS( NULL, NS_SEPARATOR );
XML_SetUserData( p, this );
XML_SetElementHandler( p, QgsGml::start, QgsGml::end );
XML_SetCharacterDataHandler( p, QgsGml::chars );

//start with empty extent
if ( mExtent )
{
mExtent->set( 0, 0, 0, 0 );
}
mExtent.setMinimal();

QNetworkRequest request( mUri );
QNetworkReply* reply = QgsNetworkAccessManager::instance()->get( request );
Expand All @@ -80,11 +77,10 @@ int QgsGml::getFeatures( const QString& uri, QGis::WkbType* wkbType, QgsRectangl

//find out if there is a QGIS main window. If yes, display a progress dialog
QProgressDialog* progressDialog = 0;
QWidget* mainWindow = findMainWindow();

QWidget* mainWindow = qApp->activeWindow();
if ( mainWindow )
{
progressDialog = new QProgressDialog( tr( "Loading WFS data\n%1" ).arg( mTypeName ), tr( "Abort" ), 0, 0, mainWindow );
progressDialog = new QProgressDialog( tr( "Loading GML data\n%1" ).arg( mTypeName ), tr( "Abort" ), 0, 0, mainWindow );
progressDialog->setWindowModality( Qt::ApplicationModal );
connect( this, SIGNAL( dataReadProgress( int ) ), progressDialog, SLOT( setValue( int ) ) );
connect( this, SIGNAL( totalStepsUpdate( int ) ), progressDialog, SLOT( setMaximum( int ) ) );
Expand All @@ -110,34 +106,39 @@ int QgsGml::getFeatures( const QString& uri, QGis::WkbType* wkbType, QgsRectangl
delete reply;
delete progressDialog;

if ( mExtent && *mWkbType != QGis::WKBNoGeometry )
if ( *mWkbType != QGis::WKBNoGeometry )
{
if ( mExtent->isEmpty() )
if ( mExtent.isEmpty() )
{
//reading of bbox from the server failed, so we calculate it less efficiently by evaluating the features
calculateExtentFromFeatures();
}
}

XML_ParserFree( p );

if ( extent )
*extent = mExtent;

return 0;
}

int QgsGml::getFeatures( const QByteArray &data, QGis::WkbType* wkbType, QgsRectangle* extent )
{
QgsDebugMsg( "Entered" );
mWkbType = wkbType;
mExtent = extent;
if ( mExtent )
{
mExtent->set( 0, 0, 0, 0 );
}
mExtent.setMinimal();

XML_Parser p = XML_ParserCreateNS( NULL, NS_SEPARATOR );
XML_SetUserData( p, this );
XML_SetElementHandler( p, QgsGml::start, QgsGml::end );
XML_SetCharacterDataHandler( p, QgsGml::chars );
int atEnd = 1;
XML_Parse( p, data.constData(), data.size(), atEnd );

if ( extent )
*extent = mExtent;

return 0;
}

Expand Down Expand Up @@ -197,6 +198,7 @@ void QgsGml::startElement( const XML_Char* el, const XML_Char** attr )
mParseModeStack.push( QgsGml::feature );
mCurrentFeatureId = readAttribute( "fid", attr );
}

else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "Box" && mParseModeStack.top() == QgsGml::boundingBox )
{
//read attribute srsName="EPSG:26910"
Expand All @@ -208,34 +210,33 @@ void QgsGml::startElement( const XML_Char* el, const XML_Char** attr )
}
else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "Polygon" )
{
std::list<unsigned char*> wkbList;
std::list<int> wkbSizeList;
QList<unsigned char*> wkbList;
QList<int> wkbSizeList;
mCurrentWKBFragments.push_back( wkbList );
mCurrentWKBFragmentSizes.push_back( wkbSizeList );
}
else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "MultiPoint" )
{
mParseModeStack.push( QgsGml::multiPoint );
//we need one nested list for intermediate WKB
std::list<unsigned char*> wkbList;
std::list<int> wkbSizeList;
QList<unsigned char*> wkbList;
QList<int> wkbSizeList;
mCurrentWKBFragments.push_back( wkbList );
mCurrentWKBFragmentSizes.push_back( wkbSizeList );
}
else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "MultiLineString" )
{
mParseModeStack.push( QgsGml::multiLine );
//we need one nested list for intermediate WKB
std::list<unsigned char*> wkbList;
std::list<int> wkbSizeList;
QList<unsigned char*> wkbList;
QList<int> wkbSizeList;
mCurrentWKBFragments.push_back( wkbList );
mCurrentWKBFragmentSizes.push_back( wkbSizeList );
}
else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "MultiPolygon" )
{
mParseModeStack.push( QgsGml::multiPolygon );
}

else if ( mParseModeStack.size() == 1 && mParseModeStack.top() == QgsGml::feature && mThematicAttributes.find( localName ) != mThematicAttributes.end() )
{
mParseModeStack.push( QgsGml::attribute );
Expand Down Expand Up @@ -294,10 +295,10 @@ void QgsGml::endElement( const XML_Char* el )
mParseModeStack.pop();
}
}
else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "boundedBy" && mParseModeStack.top() == QgsGml::boundingBox )
else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "boundedBy" )
{
//create bounding box from mStringCash
if ( createBBoxFromCoordinateString( mExtent, mStringCash ) != 0 )
if ( createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) != 0 )
{
QgsDebugMsg( "creation of bounding box failed" );
}
Expand All @@ -313,20 +314,31 @@ void QgsGml::endElement( const XML_Char* el )
if ( mCurrentWKBSize > 0 )
{
mCurrentFeature->setGeometryAndOwnership( mCurrentWKB, mCurrentWKBSize );
// TODO: what QgsFfeature.isValid() really means? Feature could be valid even without geometry?
mCurrentFeature->setValid( true );
}
else if ( !mCurrentExtent.isEmpty() )
{
mCurrentFeature->setGeometry( QgsGeometry::fromRect( mCurrentExtent ) );
}
else
{
mCurrentFeature->setGeometry( 0 );
}
mCurrentFeature->setValid( true );

mFeatures.insert( mCurrentFeature->id(), mCurrentFeature );
if ( !mCurrentFeatureId.isEmpty() )
{
mIdMap.insert( mCurrentFeature->id(), mCurrentFeatureId );
}
++mFeatureCount;
mParseModeStack.pop();
if ( !mParseModeStack.empty() )
{
mParseModeStack.pop();
}
}
else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "Point" )
{
std::list<QgsPoint> pointList;
QList<QgsPoint> pointList;
if ( pointsFromCoordinateString( pointList, mStringCash ) != 0 )
{
//error
Expand All @@ -349,14 +361,14 @@ void QgsGml::endElement( const XML_Char* el )
{
unsigned char* wkb = 0;
int wkbSize = 0;
std::list<unsigned char*> wkbList;
std::list<int> wkbSizeList;
QList<unsigned char*> wkbList;
QList<int> wkbSizeList;
if ( getPointWKB( &wkb, &wkbSize, *( pointList.begin() ) ) != 0 )
{
//error
}
mCurrentWKBFragments.rbegin()->push_back( wkb );
mCurrentWKBFragmentSizes.rbegin()->push_back( wkbSize );
mCurrentWKBFragments.begin()->push_back( wkb );
mCurrentWKBFragmentSizes.begin()->push_back( wkbSize );
//wkbList.push_back(wkb);
//wkbSizeList.push_back(wkbSize);
//mCurrentWKBFragments.push_back(wkbList);
Expand All @@ -367,7 +379,7 @@ void QgsGml::endElement( const XML_Char* el )
{
//add WKB point to the feature

std::list<QgsPoint> pointList;
QList<QgsPoint> pointList;
if ( pointsFromCoordinateString( pointList, mStringCash ) != 0 )
{
//error
Expand All @@ -388,14 +400,14 @@ void QgsGml::endElement( const XML_Char* el )
{
unsigned char* wkb = 0;
int wkbSize = 0;
std::list<unsigned char*> wkbList;
std::list<int> wkbSizeList;
QList<unsigned char*> wkbList;
QList<int> wkbSizeList;
if ( getLineWKB( &wkb, &wkbSize, pointList ) != 0 )
{
//error
}
mCurrentWKBFragments.rbegin()->push_back( wkb );
mCurrentWKBFragmentSizes.rbegin()->push_back( wkbSize );
mCurrentWKBFragments.begin()->push_back( wkb );
mCurrentWKBFragmentSizes.begin()->push_back( wkbSize );
//wkbList.push_back(wkb);
//wkbSizeList.push_back(wkbSize);
//mCurrentWKBFragments.push_back(wkbList);
Expand All @@ -404,7 +416,7 @@ void QgsGml::endElement( const XML_Char* el )
}
else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "LinearRing" )
{
std::list<QgsPoint> pointList;
QList<QgsPoint> pointList;
if ( pointsFromCoordinateString( pointList, mStringCash ) != 0 )
{
//error
Expand All @@ -415,8 +427,8 @@ void QgsGml::endElement( const XML_Char* el )
{
//error
}
mCurrentWKBFragments.rbegin()->push_back( wkb );
mCurrentWKBFragmentSizes.rbegin()->push_back( wkbSize );
mCurrentWKBFragments.begin()->push_back( wkb );
mCurrentWKBFragmentSizes.begin()->push_back( wkbSize );
}
else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "Polygon" )
{
Expand Down Expand Up @@ -518,31 +530,25 @@ QString QgsGml::readAttribute( const QString& attributeName, const XML_Char** at
return QString();
}

int QgsGml::createBBoxFromCoordinateString( QgsRectangle* bb, const QString& coordString ) const
int QgsGml::createBBoxFromCoordinateString( QgsRectangle &r, const QString& coordString ) const
{
if ( !bb )
{
return 1;
}

std::list<QgsPoint> points;
QList<QgsPoint> points;
if ( pointsFromCoordinateString( points, coordString ) != 0 )
{
return 2;
}

if ( points.size() < 2 )
{
return 3;
}

std::list<QgsPoint>::const_iterator firstPointIt = points.begin();
std::list<QgsPoint>::const_iterator secondPointIt = points.begin();
++secondPointIt;
bb->set( *firstPointIt, *secondPointIt );
r.set( points[0], points[1] );

return 0;
}

int QgsGml::pointsFromCoordinateString( std::list<QgsPoint>& points, const QString& coordString ) const
int QgsGml::pointsFromCoordinateString( QList<QgsPoint>& points, const QString& coordString ) const
{
//tuples are separated by space, x/y by ','
QStringList tuples = coordString.split( mTupleSeparator, QString::SkipEmptyParts );
Expand Down Expand Up @@ -593,7 +599,7 @@ int QgsGml::getPointWKB( unsigned char** wkb, int* size, const QgsPoint& point )
return 0;
}

int QgsGml::getLineWKB( unsigned char** wkb, int* size, const std::list<QgsPoint>& lineCoordinates ) const
int QgsGml::getLineWKB( unsigned char** wkb, int* size, const QList<QgsPoint>& lineCoordinates ) const
{
int wkbSize = 1 + 2 * sizeof( int ) + lineCoordinates.size() * 2 * sizeof( double );
*size = wkbSize;
Expand All @@ -611,7 +617,7 @@ int QgsGml::getLineWKB( unsigned char** wkb, int* size, const std::list<QgsPoint
memcpy( &( *wkb )[wkbPosition], &nPoints, sizeof( int ) );
wkbPosition += sizeof( int );

std::list<QgsPoint>::const_iterator iter;
QList<QgsPoint>::const_iterator iter;
for ( iter = lineCoordinates.begin(); iter != lineCoordinates.end(); ++iter )
{
x = iter->x();
Expand All @@ -624,7 +630,7 @@ int QgsGml::getLineWKB( unsigned char** wkb, int* size, const std::list<QgsPoint
return 0;
}

int QgsGml::getRingWKB( unsigned char** wkb, int* size, const std::list<QgsPoint>& ringCoordinates ) const
int QgsGml::getRingWKB( unsigned char** wkb, int* size, const QList<QgsPoint>& ringCoordinates ) const
{
int wkbSize = sizeof( int ) + ringCoordinates.size() * 2 * sizeof( double );
*size = wkbSize;
Expand All @@ -635,7 +641,7 @@ int QgsGml::getRingWKB( unsigned char** wkb, int* size, const std::list<QgsPoint
memcpy( &( *wkb )[wkbPosition], &nPoints, sizeof( int ) );
wkbPosition += sizeof( int );

std::list<QgsPoint>::const_iterator iter;
QList<QgsPoint>::const_iterator iter;
for ( iter = ringCoordinates.begin(); iter != ringCoordinates.end(); ++iter )
{
x = iter->x();
Expand Down Expand Up @@ -665,8 +671,8 @@ int QgsGml::createMultiLineFromFragments()
pos += sizeof( int );
memcpy( &( mCurrentWKB[pos] ), &numLines, sizeof( int ) );
pos += sizeof( int );
std::list<unsigned char*>::iterator wkbIt = mCurrentWKBFragments.begin()->begin();
std::list<int>::iterator sizeIt = mCurrentWKBFragmentSizes.begin()->begin();
QList<unsigned char*>::iterator wkbIt = mCurrentWKBFragments.begin()->begin();
QList<int>::iterator sizeIt = mCurrentWKBFragmentSizes.begin()->begin();

//copy (and delete) all the wkb fragments
for ( ; wkbIt != mCurrentWKBFragments.begin()->end(); ++wkbIt, ++sizeIt )
Expand Down Expand Up @@ -700,8 +706,8 @@ int QgsGml::createMultiPointFromFragments()
memcpy( &( mCurrentWKB[pos] ), &numPoints, sizeof( int ) );
pos += sizeof( int );

std::list<unsigned char*>::iterator wkbIt = mCurrentWKBFragments.begin()->begin();
std::list<int>::iterator sizeIt = mCurrentWKBFragmentSizes.begin()->begin();
QList<unsigned char*>::iterator wkbIt = mCurrentWKBFragments.begin()->begin();
QList<int>::iterator sizeIt = mCurrentWKBFragmentSizes.begin()->begin();

for ( ; wkbIt != mCurrentWKBFragments.begin()->end(); ++wkbIt, ++sizeIt )
{
Expand Down Expand Up @@ -734,8 +740,8 @@ int QgsGml::createPolygonFromFragments()
memcpy( &( mCurrentWKB[pos] ), &numRings, sizeof( int ) );
pos += sizeof( int );

std::list<unsigned char*>::iterator wkbIt = mCurrentWKBFragments.begin()->begin();
std::list<int>::iterator sizeIt = mCurrentWKBFragmentSizes.begin()->begin();
QList<unsigned char*>::iterator wkbIt = mCurrentWKBFragments.begin()->begin();
QList<int>::iterator sizeIt = mCurrentWKBFragmentSizes.begin()->begin();
for ( ; wkbIt != mCurrentWKBFragments.begin()->end(); ++wkbIt, ++sizeIt )
{
memcpy( &( mCurrentWKB[pos] ), *wkbIt, *sizeIt );
Expand Down Expand Up @@ -770,10 +776,10 @@ int QgsGml::createMultiPolygonFromFragments()
pos += sizeof( int );

//have outer and inner iterators
std::list<std::list<unsigned char*> >::iterator outerWkbIt;
std::list<std::list<int> >::iterator outerSizeIt;
std::list<unsigned char*>::iterator innerWkbIt;
std::list<int>::iterator innerSizeIt;
QList< QList<unsigned char*> >::iterator outerWkbIt;
QList< QList<int> >::iterator outerSizeIt;
QList< unsigned char* >::iterator innerWkbIt;
QList< int >::iterator innerSizeIt;

outerWkbIt = mCurrentWKBFragments.begin();
outerSizeIt = mCurrentWKBFragmentSizes.begin();
Expand Down Expand Up @@ -808,42 +814,23 @@ int QgsGml::createMultiPolygonFromFragments()
int QgsGml::totalWKBFragmentSize() const
{
int result = 0;
for ( std::list<std::list<int> >::const_iterator it = mCurrentWKBFragmentSizes.begin(); it != mCurrentWKBFragmentSizes.end(); ++it )
foreach ( const QList<int> &list, mCurrentWKBFragmentSizes )
{
for ( std::list<int>::const_iterator iter = it->begin(); iter != it->end(); ++iter )
foreach ( int i, list )
{
result += *iter;
result += i;
}
}
return result;
}

QWidget* QgsGml::findMainWindow() const
{
QWidget* mainWindow = 0;

QWidgetList topLevelWidgets = qApp->topLevelWidgets();
QWidgetList::iterator it = topLevelWidgets.begin();
for ( ; it != topLevelWidgets.end(); ++it )
{
if (( *it )->objectName() == "QgisApp" )
{
mainWindow = *it;
break;
}
}
return mainWindow;
}

void QgsGml::calculateExtentFromFeatures() const
void QgsGml::calculateExtentFromFeatures()
{
if ( mFeatures.size() < 1 )
{
return;
}

QgsRectangle bbox;

QgsFeature* currentFeature = 0;
QgsGeometry* currentGeometry = 0;
bool bboxInitialised = false; //gets true once bbox has been set to the first geometry
Expand All @@ -860,14 +847,13 @@ void QgsGml::calculateExtentFromFeatures() const
{
if ( !bboxInitialised )
{
bbox = currentGeometry->boundingBox();
mExtent = currentGeometry->boundingBox();
bboxInitialised = true;
}
else
{
bbox.unionRect( currentGeometry->boundingBox() );
mExtent.unionRect( currentGeometry->boundingBox() );
}
}
}
( *mExtent ) = bbox;
}
34 changes: 17 additions & 17 deletions src/core/qgsgml.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/***************************************************************************
qgsgml.h
--------------------------------------
Date : Sun Sep 16 12:19:55 AKDT 2007
Copyright : (C) 2007 by Gary E. Sherman
Email : sherman at mrcc dot com
qgsgml.h
---------------------
begin : February 2013
copyright : (C) 2013 by Radim Blazek
email : radim dot blazek at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
Expand All @@ -23,14 +23,14 @@
#include "qgsfield.h"
#include "qgslogger.h"
#include "qgspoint.h"
#include <list>
#include <set>
#include <stack>
#include "qgsrectangle.h"

#include <QPair>
#include <QByteArray>
#include <QDomElement>
#include <QStringList>
#include <QStack>

class QgsRectangle;
class QgsCoordinateReferenceSystem;

Expand Down Expand Up @@ -124,16 +124,16 @@ class CORE_EXPORT QgsGml: public QObject
QString readAttribute( const QString& attributeName, const XML_Char** attr ) const;
/**Creates a rectangle from a coordinate string.
@return 0 in case of success*/
int createBBoxFromCoordinateString( QgsRectangle* bb, const QString& coordString ) const;
int createBBoxFromCoordinateString( QgsRectangle &bb, const QString& coordString ) const;
/**Creates a set of points from a coordinate string.
@param points list that will contain the created points
@param coordString the text containing the coordinates
@return 0 in case of success*/
int pointsFromCoordinateString( std::list<QgsPoint>& points, const QString& coordString ) const;
int pointsFromCoordinateString( QList<QgsPoint>& points, const QString& coordString ) const;

int getPointWKB( unsigned char** wkb, int* size, const QgsPoint& ) const;
int getLineWKB( unsigned char** wkb, int* size, const std::list<QgsPoint>& lineCoordinates ) const;
int getRingWKB( unsigned char** wkb, int* size, const std::list<QgsPoint>& ringCoordinates ) const;
int getLineWKB( unsigned char** wkb, int* size, const QList<QgsPoint>& lineCoordinates ) const;
int getRingWKB( unsigned char** wkb, int* size, const QList<QgsPoint>& ringCoordinates ) const;
/**Creates a multiline from the information in mCurrentWKBFragments and mCurrentWKBFragmentSizes. Assign the result. The multiline is in mCurrentWKB and mCurrentWKBSize. The function deletes the memory in mCurrentWKBFragments. Returns 0 in case of success.*/
int createMultiLineFromFragments();
int createMultiPointFromFragments();
Expand All @@ -147,7 +147,7 @@ class CORE_EXPORT QgsGml: public QObject
/**This function evaluates the layer bounding box from the features and sets it to mExtent.
Less efficient compared to reading the bbox from the provider, so it is only done if the wfs server
does not provider extent information.*/
void calculateExtentFromFeatures() const;
void calculateExtentFromFeatures();

/** Get safely (if empty) top from mode stack */
ParseMode modeStackTop() { return mParseModeStack.isEmpty() ? none : mParseModeStack.top(); }
Expand All @@ -159,7 +159,7 @@ class CORE_EXPORT QgsGml: public QObject
QString mUri;
//results are members such that handler routines are able to manipulate them
/**Bounding box of the layer*/
QgsRectangle* mExtent;
QgsRectangle mExtent;
/**The features of the layer, map of feature maps for each feature type*/
//QMap<QgsFeatureId, QgsFeature* > &mFeatures;
QMap<QgsFeatureId, QgsFeature* > mFeatures;
Expand All @@ -177,7 +177,6 @@ class CORE_EXPORT QgsGml: public QObject
/**True if the request is finished*/
bool mFinished;
/**Keep track about the most important nested elements*/
//std::stack<ParseMode> mParseModeStack;
QStack<ParseMode> mParseModeStack;
/**This contains the character data if an important element has been encountered*/
QString mStringCash;
Expand All @@ -189,10 +188,11 @@ class CORE_EXPORT QgsGml: public QObject
unsigned char* mCurrentWKB;
/**The total WKB size for a feature*/
int mCurrentWKBSize;
QgsRectangle mCurrentExtent;
/**WKB intermediate storage during parsing. For points and lines, no intermediate WKB is stored at all. For multipoins and multilines and polygons, only one nested list is used. For multipolygons, both nested lists are used*/
std::list< std::list<unsigned char*> > mCurrentWKBFragments;
QList< QList<unsigned char*> > mCurrentWKBFragments;
/**Similar to mCurrentWKB, but only the size*/
std::list< std::list<int> > mCurrentWKBFragmentSizes;
QList< QList<int> > mCurrentWKBFragmentSizes;
QString mAttributeName;
QgsApplication::endian_t mEndian;
/**Coordinate separator for coordinate strings. Usually "," */
Expand Down
6 changes: 1 addition & 5 deletions src/core/qgsnetworkreplyparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,5 @@ bool QgsNetworkReplyParser::isMultipart( QNetworkReply *reply )
// Multipart content type examples:
// multipart/mixed; boundary=wcs
// multipart/mixed; boundary="wcs"\n
if ( contentType.startsWith( "multipart/", Qt::CaseInsensitive ) )
{
return true;
}
return false;
return contentType.startsWith( "multipart/", Qt::CaseInsensitive );
}
16 changes: 11 additions & 5 deletions src/gui/qgsmaptoolidentify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -288,16 +288,23 @@ QMap< QString, QString > QgsMapToolIdentify::featureDerivedAttributes( QgsFeatur
calc.setEllipsoid( ellipsoid );
calc.setSourceCrs( layer->crs().srsid() );

QGis::GeometryType geometryType = feature->geometry()->type();
QGis::WkbType wkbType = QGis::WKBNoGeometry;
QGis::GeometryType geometryType = QGis::NoGeometry;

if ( feature->geometry() )
{
geometryType = feature->geometry()->type();
wkbType = feature->geometry()->wkbType();
}

if ( geometryType == QGis::Line )
{
double dist = calc.measure( feature->geometry() );
QGis::UnitType myDisplayUnits;
convertMeasurement( calc, dist, myDisplayUnits, false );
QString str = calc.textUnit( dist, 3, myDisplayUnits, false ); // dist and myDisplayUnits are out params
derivedAttributes.insert( tr( "Length" ), str );
if ( feature->geometry()->wkbType() == QGis::WKBLineString ||
feature->geometry()->wkbType() == QGis::WKBLineString25D )
if ( wkbType == QGis::WKBLineString || wkbType == QGis::WKBLineString25D )
{
// Add the start and end points in as derived attributes
QgsPoint pnt = mCanvas->mapRenderer()->layerToMapCoordinates( layer, feature->geometry()->asPolyline().first() );
Expand Down Expand Up @@ -325,8 +332,7 @@ QMap< QString, QString > QgsMapToolIdentify::featureDerivedAttributes( QgsFeatur
derivedAttributes.insert( tr( "Perimeter" ), str );
}
else if ( geometryType == QGis::Point &&
( feature->geometry()->wkbType() == QGis::WKBPoint ||
feature->geometry()->wkbType() == QGis::WKBPoint25D ) )
( wkbType == QGis::WKBPoint || wkbType == QGis::WKBPoint25D ) )
{
// Include the x and y coordinates of the point as a derived attribute
QgsPoint pnt = mCanvas->mapRenderer()->layerToMapCoordinates( layer, feature->geometry()->asPoint() );
Expand Down
133 changes: 85 additions & 48 deletions src/providers/wms/qgswmsprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1399,22 +1399,33 @@ bool QgsWmsProvider::retrieveServerCapabilities( bool forceRefresh )
foreach ( QString f, mCapabilities.capability.request.getFeatureInfo.format )
{
// Don't use mSupportedGetFeatureFormats, there are too many possibilities
//if ( mSupportedGetFeatureFormats.contains( f ) )
//{
QgsDebugMsg( "supported format = " + f );
// 1.0: MIME - server shall choose format, we presume it to be plain text
// GML.1, GML.2, or GML.3
// 1.1.0, 1.3.0 - mime types, GML should use application/vnd.ogc.gml
// but in UMN Mapserver it may be also OUTPUTFORMAT, e.g. OGRGML
IdentifyFormat format;
if ( f == "MIME" ) format = IdentifyFormatText; // 1.0
else if ( f == "text/plain" ) format = IdentifyFormatText;
else if ( f == "text/html" ) format = IdentifyFormatHtml;
else if ( f.startsWith( "GML." ) ) format = IdentifyFormatFeature; // 1.0
else if ( f == "application/vnd.ogc.gml" ) format = IdentifyFormatFeature;
else if ( f.contains( "gml", Qt::CaseInsensitive ) ) format = IdentifyFormatFeature;
mIdentifyFormats.insert( format, f );
//}
#if 0
if ( mSupportedGetFeatureFormats.contains( f ) )
{
#endif
QgsDebugMsg( "supported format = " + f );
// 1.0: MIME - server shall choose format, we presume it to be plain text
// GML.1, GML.2, or GML.3
// 1.1.0, 1.3.0 - mime types, GML should use application/vnd.ogc.gml
// but in UMN Mapserver it may be also OUTPUTFORMAT, e.g. OGRGML
IdentifyFormat format;
if ( f == "MIME" )
format = IdentifyFormatText; // 1.0
else if ( f == "text/plain" )
format = IdentifyFormatText;
else if ( f == "text/html" )
format = IdentifyFormatHtml;
else if ( f.startsWith( "GML." ) )
format = IdentifyFormatFeature; // 1.0
else if ( f == "application/vnd.ogc.gml" )
format = IdentifyFormatFeature;
else if ( f.contains( "gml", Qt::CaseInsensitive ) )
format = IdentifyFormatFeature;

mIdentifyFormats.insert( format, f );
#if 0
}
#endif
}
}
}
Expand Down Expand Up @@ -3006,6 +3017,7 @@ void QgsWmsProvider::parseServiceException( QDomElement const & e )
QString seCode = e.attribute( "code" );
QString seText = e.text();

mErrorCaption = tr( "Service Exception" );
mErrorFormat = "text/plain";

// set up friendly descriptions for the service exception
Expand Down Expand Up @@ -3075,12 +3087,9 @@ void QgsWmsProvider::parseServiceException( QDomElement const & e )

// TODO = e.attribute("locator");

QgsMessageLog::logMessage( tr( "composed error message '%1'." ).arg( mError ), tr( "WMS" ) );
QgsDebugMsg( "exiting." );
QgsDebugMsg( QString( "exiting with composed error message '%1'." ).arg( mError ) );
}



QgsRectangle QgsWmsProvider::extent()
{
if ( mExtentDirty )
Expand Down Expand Up @@ -3850,7 +3859,7 @@ QMap<int, QVariant> QgsWmsProvider::identify( const QgsPoint & thePoint, Identif
format = mIdentifyFormats.value( theFormat );
if ( format.isEmpty() ) return results;

QgsDebugMsg( "format = " + format );
QgsDebugMsg( QString( "theFormat = %1 format = %2" ).arg( theFormat ).arg( format ) );

if ( !extent().contains( thePoint ) )
{
Expand Down Expand Up @@ -3998,6 +4007,43 @@ QMap<int, QVariant> QgsWmsProvider::identify( const QgsPoint & thePoint, Identif
QgsDebugMsg( "mIdentifyResultBodies is empty" );
continue;
}
else if ( mIdentifyResultBodies.size() == 1 )
{
// Check for service exceptions (exceptions with ogr/gml are in the body)
bool isXml = false;
bool isGml = false;

const QgsNetworkReplyParser::RawHeaderMap &headers = mIdentifyResultHeaders.value( 0 );
foreach ( const QByteArray &v, headers.keys() )
{
if ( QString( v ).compare( "Content-Type", Qt::CaseInsensitive ) == 0 )
{
isXml = QString( headers.value( v ) ).compare( "text/xml", Qt::CaseInsensitive ) == 0;
isGml = QString( headers.value( v ) ).compare( "ogr/gml", Qt::CaseInsensitive ) == 0;
if ( isXml || isGml )
break;
}
}

if ( isGml || isXml )
{
QByteArray body = mIdentifyResultBodies.value( 0 );

if ( isGml && body.startsWith( "Content-Type: text/xml\r\n\r\n" ) )
{
body = body.data() + strlen( "Content-Type: text/xml\r\n\r\n" );
isXml = true;
}

if ( isXml && parseServiceExceptionReportDom( body ) )
{
QgsMessageLog::logMessage( tr( "Get feature info request error (Title:%1; Error:%2; URL: %3)" )
.arg( mErrorCaption ).arg( mError )
.arg( requestUrl.toString() ), tr( "WMS" ) );
continue;
}
}
}

if ( theFormat == IdentifyFormatHtml || theFormat == IdentifyFormatText )
{
Expand Down Expand Up @@ -4046,7 +4092,7 @@ QMap<int, QVariant> QgsWmsProvider::identify( const QgsPoint & thePoint, Identif
// How to find which part is GML and which XSD? Both have
// Content-Type: application/binary
// different are Content-Disposition but it is not reliable.
// We could analyze begining of bodies...
// We could analyze beginning of bodies...
gmlPart = 0;
xsdPart = 1;
}
Expand Down Expand Up @@ -4150,18 +4196,20 @@ QMap<int, QVariant> QgsWmsProvider::identify( const QgsPoint & thePoint, Identif
}
}

#if 0
QString str;

if ( theFormat == IdentifyFormatHtml )
{
//str = "<table>\n<tr><td>" + resultStrings.join( "</td></tr>\n<tr><td>" ) + "</td></tr>\n</table>";
//results.insert( 1, str );
str = "<table>\n<tr><td>" + resultStrings.join( "</td></tr>\n<tr><td>" ) + "</td></tr>\n</table>";
results.insert( 1, str );
}
else if ( theFormat == IdentifyFormatText )
{
//str = resultStrings.join( "\n-------------\n" );
//results.insert( 1, str );
str = resultStrings.join( "\n-------------\n" );
results.insert( 1, str );
}
#endif

return results;
}
Expand Down Expand Up @@ -4199,32 +4247,21 @@ void QgsWmsProvider::identifyReplyFinished()
//mIdentifyResult = "";
}

if ( QgsNetworkReplyParser::isMultipart( mIdentifyReply ) )
QgsNetworkReplyParser parser( mIdentifyReply );
if ( !parser.isValid() )
{
QgsNetworkReplyParser parser( mIdentifyReply );
if ( !parser.isValid() )
{
QgsDebugMsg( "Cannot parse multipart" );
mErrorFormat = "text/plain";
mError = tr( "Cannot parse multipart getfeatureinfo: %1" ).arg( parser.error() );
emit statusChanged( mError );
//mIdentifyResult = "";
}
else
{
// TODO: check headers, xsd ...
// take first body - GML for now
QgsDebugMsg( QString( "%1 parts in multipart" ).arg( parser.parts() ) );
//mIdentifyResult = parser.body( 0 );
//mIdentifyResultXsd = parser.body( 1 );
mIdentifyResultBodies = parser.bodies();
mIdentifyResultHeaders = parser.headers();
}
QgsDebugMsg( "Cannot parse reply" );
mErrorFormat = "text/plain";
mError = tr( "Cannot parse getfeatureinfo: %1" ).arg( parser.error() );
emit statusChanged( mError );
//mIdentifyResult = "";
}
else
{
//mIdentifyResult = QString::fromUtf8( mIdentifyReply->readAll() );
mIdentifyResultBodies << mIdentifyReply->readAll();
// TODO: check headers, xsd ...
QgsDebugMsg( QString( "%1 parts" ).arg( parser.parts() ) );
mIdentifyResultBodies = parser.bodies();
mIdentifyResultHeaders = parser.headers();
}
}
else
Expand Down