27 #include <QNetworkRequest> 28 #include <QNetworkReply> 29 #include <QProgressDialog> 41 const QString& geometryAttribute,
44 , mTypeName( typeName )
45 , mGeometryAttribute( geometryAttribute )
48 , mCurrentFeature( nullptr )
50 , mCurrentWKB( nullptr, 0 )
52 , mCoorMode(
QgsGml::coordinate )
55 mThematicAttributes.
clear();
56 for (
int i = 0; i < fields.
size(); i++ )
58 mThematicAttributes.
insert( fields[i].
name(), qMakePair( i, fields[i] ) );
64 if ( index != -1 && index < mTypeName.
length() )
66 mTypeName = mTypeName.
mid( index + 1 );
79 XML_Parser p = XML_ParserCreateNS(
nullptr,
NS_SEPARATOR );
80 XML_SetUserData( p,
this );
81 XML_SetElementHandler( p, QgsGml::start, QgsGml::end );
82 XML_SetCharacterDataHandler( p, QgsGml::chars );
93 tr(
"GML Getfeature network request update failed for authcfg %1" ).arg( authcfg ),
102 request.
setRawHeader(
"Authorization",
"Basic " +
QString(
"%1:%2" ).arg( userName, password ).toAscii().toBase64() );
112 tr(
"GML Getfeature network reply update failed for authcfg %1" ).arg( authcfg ),
120 connect( reply, SIGNAL( finished() ),
this, SLOT( setFinished() ) );
121 connect( reply, SIGNAL( downloadProgress( qint64, qint64 ) ),
this, SLOT( handleProgressEvent( qint64, qint64 ) ) );
126 QWidgetList topLevelWidgets = qApp->topLevelWidgets();
127 for ( QWidgetList::const_iterator it = topLevelWidgets.constBegin(); it != topLevelWidgets.constEnd(); ++it )
129 if (( *it )->objectName() ==
"QgisApp" )
137 progressDialog =
new QProgressDialog(
tr(
"Loading GML data\n%1" ).arg( mTypeName ),
tr(
"Abort" ), 0, 0, mainWindow );
141 connect( progressDialog, SIGNAL( canceled() ),
this, SLOT( setFinished() ) );
142 progressDialog->
show();
155 if ( XML_Parse( p, readData.
constData(), readData.
size(), atEnd ) == 0 )
157 XML_Error errorCode = XML_GetErrorCode( p );
158 QString errorString =
tr(
"Error: %1 on line %2, column %3" )
159 .
arg( XML_ErrorString( errorCode ) )
160 .
arg( XML_GetCurrentLineNumber( p ) )
161 .
arg( XML_GetCurrentColumnNumber( p ) );
168 QNetworkReply::NetworkError replyError = reply->
error();
172 delete progressDialog;
177 tr(
"GML Getfeature network request failed with error: %1" ).arg( replyErrorString ),
189 calculateExtentFromFeatures();
206 XML_Parser p = XML_ParserCreateNS(
nullptr,
NS_SEPARATOR );
207 XML_SetUserData( p,
this );
208 XML_SetElementHandler( p, QgsGml::start, QgsGml::end );
209 XML_SetCharacterDataHandler( p, QgsGml::chars );
219 void QgsGml::setFinished()
224 void QgsGml::handleProgressEvent( qint64 progress, qint64 totalSteps )
226 if ( totalSteps < 0 )
236 void QgsGml::startElement(
const XML_Char* el,
const XML_Char** attr )
239 ParseMode theParseMode( mParseModeStack.isEmpty() ? none : mParseModeStack.
top() );
241 QString localName = splitName.last();
242 QString ns = splitName.
size() > 1 ? splitName.first() :
"";
244 if ( elementName == GML_NAMESPACE +
NS_SEPARATOR +
"coordinates" )
246 mParseModeStack.
push( QgsGml::coordinate );
247 mCoorMode = QgsGml::coordinate;
249 mCoordinateSeparator = readAttribute(
"cs", attr );
250 if ( mCoordinateSeparator.
isEmpty() )
252 mCoordinateSeparator =
',';
254 mTupleSeparator = readAttribute(
"ts", attr );
255 if ( mTupleSeparator.
isEmpty() )
257 mTupleSeparator =
' ';
260 if ( elementName == GML_NAMESPACE +
NS_SEPARATOR +
"pos" 261 || elementName == GML_NAMESPACE +
NS_SEPARATOR +
"posList" )
263 mParseModeStack.
push( QgsGml::posList );
264 mCoorMode = QgsGml::posList;
266 QString dimension = readAttribute(
"srsDimension", attr );
268 mDimension = dimension.
toInt( &ok );
269 if ( dimension.
isEmpty() || !ok )
274 else if ( localName == mGeometryAttribute )
276 mParseModeStack.
push( QgsGml::geometry );
279 else if ( elementName == GML_NAMESPACE +
NS_SEPARATOR +
"boundedBy" )
281 mParseModeStack.
push( QgsGml::boundingBox );
283 else if ( theParseMode == none && localName == mTypeName )
285 Q_ASSERT( !mCurrentFeature );
286 mCurrentFeature =
new QgsFeature( mFeatureCount );
289 mParseModeStack.
push( QgsGml::feature );
290 mCurrentFeatureId = readAttribute(
"fid", attr );
293 else if ( theParseMode == boundingBox && elementName == GML_NAMESPACE +
NS_SEPARATOR +
"Box" )
297 if ( readEpsgFromAttribute( epsgNr, attr ) != 0 )
302 else if ( elementName == GML_NAMESPACE +
NS_SEPARATOR +
"Polygon" )
306 else if ( elementName == GML_NAMESPACE +
NS_SEPARATOR +
"MultiPoint" )
308 mParseModeStack.
push( QgsGml::multiPoint );
312 else if ( elementName == GML_NAMESPACE +
NS_SEPARATOR +
"MultiLineString" )
314 mParseModeStack.
push( QgsGml::multiLine );
318 else if ( elementName == GML_NAMESPACE +
NS_SEPARATOR +
"MultiPolygon" )
320 mParseModeStack.
push( QgsGml::multiPolygon );
322 else if ( theParseMode == feature && mThematicAttributes.
contains( localName ) )
324 mParseModeStack.
push( QgsGml::attribute );
325 mAttributeName = localName;
330 else if ( theParseMode == feature
331 && localName.
compare(
"attribute", Qt::CaseInsensitive ) == 0 )
334 if ( mThematicAttributes.
contains( name ) )
336 QString value = readAttribute(
"value", attr );
337 setAttribute( name, value );
341 if ( mEpsg == 0 && ( localName ==
"Point" || localName ==
"MultiPoint" ||
342 localName ==
"LineString" || localName ==
"MultiLineString" ||
343 localName ==
"Polygon" || localName ==
"MultiPolygon" ) )
345 if ( readEpsgFromAttribute( mEpsg, attr ) != 0 )
356 void QgsGml::endElement(
const XML_Char* el )
359 ParseMode theParseMode( mParseModeStack.isEmpty() ? none : mParseModeStack.
top() );
361 QString localName = splitName.last();
362 QString ns = splitName.
size() > 1 ? splitName.first() :
"";
364 if (( theParseMode == coordinate && elementName == GML_NAMESPACE +
NS_SEPARATOR +
"coordinates" )
365 || ( theParseMode == posList && (
367 || elementName == GML_NAMESPACE +
NS_SEPARATOR +
"posList" ) ) )
369 mParseModeStack.
pop();
371 else if ( theParseMode == attribute && localName == mAttributeName )
373 mParseModeStack.
pop();
375 setAttribute( mAttributeName, mStringCash );
377 else if ( theParseMode == geometry && localName == mGeometryAttribute )
379 mParseModeStack.
pop();
381 else if ( theParseMode == boundingBox && elementName == GML_NAMESPACE +
NS_SEPARATOR +
"boundedBy" )
384 if ( createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) != 0 )
389 mParseModeStack.
pop();
391 else if ( theParseMode == feature && localName == mTypeName )
393 Q_ASSERT( mCurrentFeature );
394 if ( mCurrentWKB.
size() > 0 )
401 else if ( !mCurrentExtent.
isEmpty() )
411 mFeatures.
insert( mCurrentFeature->
id(), mCurrentFeature );
412 if ( !mCurrentFeatureId.
isEmpty() )
414 mIdMap.
insert( mCurrentFeature->
id(), mCurrentFeatureId );
416 mCurrentFeature =
nullptr;
418 mParseModeStack.
pop();
420 else if ( elementName == GML_NAMESPACE +
NS_SEPARATOR +
"Point" )
423 if ( pointsFromString( pointList, mStringCash ) != 0 )
431 if ( theParseMode == QgsGml::geometry )
434 if ( getPointWKB( mCurrentWKB, *( pointList.
constBegin() ) ) != 0 )
447 if ( getPointWKB( wkbPtr, *( pointList.
constBegin() ) ) != 0 )
451 if ( !mCurrentWKBFragments.
isEmpty() )
453 mCurrentWKBFragments.
last().push_back( wkbPtr );
462 else if ( elementName == GML_NAMESPACE +
NS_SEPARATOR +
"LineString" )
467 if ( pointsFromString( pointList, mStringCash ) != 0 )
471 if ( theParseMode == QgsGml::geometry )
473 if ( getLineWKB( mCurrentWKB, pointList ) != 0 )
486 if ( getLineWKB( wkbPtr, pointList ) != 0 )
490 if ( !mCurrentWKBFragments.
isEmpty() )
492 mCurrentWKBFragments.
last().push_back( wkbPtr );
501 else if (( theParseMode == geometry || theParseMode == multiPolygon ) && elementName == GML_NAMESPACE +
NS_SEPARATOR +
"LinearRing" )
504 if ( pointsFromString( pointList, mStringCash ) != 0 )
510 if ( getRingWKB( wkbPtr, pointList ) != 0 )
515 if ( !mCurrentWKBFragments.
isEmpty() )
517 mCurrentWKBFragments.
last().push_back( wkbPtr );
525 else if (( theParseMode == geometry || theParseMode == multiPolygon ) && elementName == GML_NAMESPACE +
NS_SEPARATOR +
"Polygon" )
532 if ( theParseMode == geometry )
534 createPolygonFromFragments();
537 else if ( theParseMode == multiPoint && elementName == GML_NAMESPACE +
NS_SEPARATOR +
"MultiPoint" )
540 mParseModeStack.
pop();
541 createMultiPointFromFragments();
543 else if ( theParseMode == multiLine && elementName == GML_NAMESPACE +
NS_SEPARATOR +
"MultiLineString" )
546 mParseModeStack.
pop();
547 createMultiLineFromFragments();
549 else if ( theParseMode == multiPolygon && elementName == GML_NAMESPACE +
NS_SEPARATOR +
"MultiPolygon" )
552 mParseModeStack.
pop();
553 createMultiPolygonFromFragments();
557 void QgsGml::characters(
const XML_Char* chars,
int len )
560 if ( mParseModeStack.isEmpty() )
565 QgsGml::ParseMode theParseMode = mParseModeStack.
top();
566 if ( theParseMode == QgsGml::attribute || theParseMode == QgsGml::coordinate || theParseMode == QgsGml::posList )
576 if ( att_it != mThematicAttributes.
constEnd() )
579 switch ( att_it.
value().second.type() )
581 case QVariant::Double:
587 case QVariant::LongLong:
594 Q_ASSERT( mCurrentFeature );
599 int QgsGml::readEpsgFromAttribute(
int& epsgNr,
const XML_Char** attr )
const 604 if ( strcmp( attr[i],
"srsName" ) == 0 )
606 QString epsgString( attr[i+1] );
610 epsgNrString = epsgString.
section(
'#', 1, 1 );
614 epsgNrString = epsgString.
section(
':', 1, 1 );
617 int eNr = epsgNrString.
toInt( &conversionOk );
630 QString QgsGml::readAttribute(
const QString& attributeName,
const XML_Char** attr )
const 635 if ( attributeName.
compare( attr[i] ) == 0 )
644 int QgsGml::createBBoxFromCoordinateString(
QgsRectangle &r,
const QString& coordString )
const 647 if ( pointsFromCoordinateString( points, coordString ) != 0 )
652 if ( points.
size() < 2 )
657 r.
set( points[0], points[1] );
665 QStringList tuples = coordString.
split( mTupleSeparator, QString::SkipEmptyParts );
668 bool conversionSuccess;
671 for ( tupleIterator = tuples.
constBegin(); tupleIterator != tuples.
constEnd(); ++tupleIterator )
673 tuples_coordinates = tupleIterator->split( mCoordinateSeparator, QString::SkipEmptyParts );
674 if ( tuples_coordinates.
size() < 2 )
678 x = tuples_coordinates.
at( 0 ).toDouble( &conversionSuccess );
679 if ( !conversionSuccess )
683 y = tuples_coordinates.
at( 1 ).toDouble( &conversionSuccess );
684 if ( !conversionSuccess )
693 int QgsGml::pointsFromPosListString(
QList<QgsPoint>& points,
const QString& coordString,
int dimension )
const 696 QStringList coordinates = coordString.
split(
' ', QString::SkipEmptyParts );
698 if ( coordinates.
size() % dimension != 0 )
703 int ncoor = coordinates.
size() / dimension;
704 for (
int i = 0; i < ncoor; i++ )
706 bool conversionSuccess;
707 double x = coordinates.
value( i * dimension ).toDouble( &conversionSuccess );
708 if ( !conversionSuccess )
712 double y = coordinates.
value( i * dimension + 1 ).toDouble( &conversionSuccess );
713 if ( !conversionSuccess )
724 if ( mCoorMode == QgsGml::coordinate )
726 return pointsFromCoordinateString( points, coordString );
728 else if ( mCoorMode == QgsGml::posList )
730 return pointsFromPosListString( points, coordString, mDimension );
737 int wkbSize = 1 +
sizeof( int ) + 2 *
sizeof(
double );
738 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
748 int wkbSize = 1 + 2 *
sizeof( int ) + lineCoordinates.
size() * 2 *
sizeof( double );
749 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
756 for ( iter = lineCoordinates.
constBegin(); iter != lineCoordinates.
constEnd(); ++iter )
758 fillPtr << iter->x() << iter->y();
766 int wkbSize =
sizeof( int ) + ringCoordinates.
size() * 2 *
sizeof( double );
767 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
771 fillPtr << ringCoordinates.
size();
774 for ( iter = ringCoordinates.
constBegin(); iter != ringCoordinates.
constEnd(); ++iter )
776 fillPtr << iter->x() << iter->y();
782 int QgsGml::createMultiLineFromFragments()
784 int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
785 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
793 for ( ; wkbIt != mCurrentWKBFragments.
constBegin()->constEnd(); ++wkbIt )
795 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
796 wkbPtr += wkbIt->size();
800 mCurrentWKBFragments.
clear();
805 int QgsGml::createMultiPointFromFragments()
807 int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
808 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
814 for ( ; wkbIt != mCurrentWKBFragments.
constBegin()->constEnd(); ++wkbIt )
816 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
817 wkbPtr += wkbIt->size();
821 mCurrentWKBFragments.
clear();
827 int QgsGml::createPolygonFromFragments()
829 int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
830 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
836 for ( ; wkbIt != mCurrentWKBFragments.
constBegin()->constEnd(); ++wkbIt )
838 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
839 wkbPtr += wkbIt->size();
843 mCurrentWKBFragments.
clear();
848 int QgsGml::createMultiPolygonFromFragments()
851 size += 1 + 2 *
sizeof( int );
852 size += totalWKBFragmentSize();
853 size += mCurrentWKBFragments.
size() * ( 1 + 2 *
sizeof( int ) );
855 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
863 for ( ; outerWkbIt != mCurrentWKBFragments.
constEnd(); ++outerWkbIt )
869 for ( ; innerWkbIt != outerWkbIt->
constEnd(); ++innerWkbIt )
871 memcpy( wkbPtr, *innerWkbIt, innerWkbIt->size() );
872 wkbPtr += innerWkbIt->size();
873 delete[] *innerWkbIt;
877 mCurrentWKBFragments.
clear();
882 int QgsGml::totalWKBFragmentSize()
const 895 void QgsGml::calculateExtentFromFeatures()
897 if ( mFeatures.
size() < 1 )
904 bool bboxInitialised =
false;
906 for (
int i = 0; i < mFeatures.
size(); ++i )
908 currentFeature = mFeatures[i];
909 if ( !currentFeature )
914 if ( currentGeometry )
916 if ( !bboxInitialised )
919 bboxInitialised =
true;
void unionRect(const QgsRectangle &rect)
Updates rectangle to include passed argument.
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
A rectangle specified with double values.
QString & append(QChar ch)
int size() const
Return number of items.
void setMinimal()
Set a rectangle so that min corner is at max and max corner is at min.
bool contains(const Key &key) const
static QgsAuthManager * instance()
Enforce singleton pattern.
void push_back(const T &value)
void fromWkb(unsigned char *wkb, int length)
Set the geometry, feeding in the buffer containing OGC Well-Known Binary and the buffer's length...
QString errorString() const
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
const T & at(int i) const
Container of fields for a vector layer.
A geometry is the spatial representation of a feature.
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
bool setAttribute(int field, const QVariant &attr)
Set an attribute's value by field index.
WkbType
Used for symbology operations.
void dataReadProgress(int progress)
const_iterator constFind(const Key &key) const
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
double toDouble(bool *ok) const
static endian_t endian()
Returns whether this machine uses big or little endian.
QString tr(const char *sourceText, const char *disambiguation, int n)
double y() const
Get the y value of the point.
void totalStepsUpdate(int totalSteps)
void set(const QgsPoint &p1, const QgsPoint &p2)
Set the rectangle from two QgsPoints.
bool createFromOgcWmsCrs(QString theCrs)
Set up this CRS from the given OGC CRS.
const char * name() const
void setGeometry(const QgsGeometry &geom)
Set this feature's geometry from another QgsGeometry object.
void processEvents(QFlags< QEventLoop::ProcessEventsFlag > flags)
void append(const T &value)
QString fromUtf8(const char *str, int size)
int getFeatures(const QString &uri, QGis::WkbType *wkbType, QgsRectangle *extent=nullptr, const QString &userName=QString(), const QString &password=QString(), const QString &authcfg=QString())
Does the Http GET request to the wfs server Supports only UTF-8, UTF-16, ISO-8859-1, ISO-8859-1 XML encodings.
void dataProgressAndSteps(int progress, int totalSteps)
bool isEmpty() const
test if rectangle is empty.
This class reads data from a WFS server or alternatively from a GML file.
QgsGml(const QString &typeName, const QString &geometryAttribute, const QgsFields &fields)
int toInt(bool *ok, int base) const
const_iterator constEnd() const
const char * constData() const
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
static void logMessage(const QString &message, const QString &tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
A class to represent a point.
QgsFeatureId id() const
Get the feature ID for this feature.
const QString GML_NAMESPACE
void setValid(bool validity)
Sets the validity of the feature.
QString mid(int position, int n) const
bool updateNetworkRequest(QNetworkRequest &request, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QNetworkRequest with an authentication config.
static QgsNetworkAccessManager * instance()
returns a pointer to the single instance
QgsRectangle boundingBox() const
Returns the bounding box of this feature.
Class for storing a coordinate reference system (CRS)
static QgsGeometry * fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
QString section(QChar sep, int start, int end, QFlags< QString::SectionFlag > flags) const
NetworkError error() const
QgsCoordinateReferenceSystem crs() const
Returns features spatial reference system.
iterator insert(const Key &key, const T &value)
QNetworkReply * get(const QNetworkRequest &request)
bool updateNetworkReply(QNetworkReply *reply, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QNetworkReply with an authentication config (used to skip known SSL errors...
const_iterator constEnd() const
const_iterator constBegin() const
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
int compare(const QString &other) const
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
qlonglong toLongLong(bool *ok, int base) const
double x() const
Get the x value of the point.
const T value(const Key &key) const