Skip to content

Commit 78841d9

Browse files
committed
delimitedtext: add support for featureSource()
1 parent 6d3f1b8 commit 78841d9

6 files changed

+145
-80
lines changed

src/providers/delimitedtext/qgsdelimitedtextfeatureiterator.cpp

+77-42
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,21 @@
2525
#include <QtAlgorithms>
2626
#include <QTextStream>
2727

28-
QgsDelimitedTextFeatureIterator::QgsDelimitedTextFeatureIterator( QgsDelimitedTextProvider* p, const QgsFeatureRequest& request )
29-
: QgsAbstractFeatureIterator( request )
30-
, P( p )
28+
QgsDelimitedTextFeatureIterator::QgsDelimitedTextFeatureIterator( QgsDelimitedTextFeatureSource* source, bool ownSource, const QgsFeatureRequest& request )
29+
: QgsAbstractFeatureIteratorFromSource( source, ownSource, request )
3130
{
32-
P->mActiveIterators << this;
3331

3432
// Determine mode to use based on request...
3533
QgsDebugMsg( "Setting up QgsDelimitedTextIterator" );
3634

3735
// Does the layer have geometry - will revise later to determine if we actually need to
3836
// load it.
39-
bool hasGeometry = P->mGeomRep != QgsDelimitedTextProvider::GeomNone;
37+
bool hasGeometry = mSource->mGeomRep != QgsDelimitedTextProvider::GeomNone;
4038

4139
// Does the layer have an explicit or implicit subset (implicit subset is if we have geometry which can
4240
// be invalid)
4341

44-
mTestSubset = P->mSubsetExpression;
42+
mTestSubset = mSource->mSubsetExpression;
4543
mTestGeometry = false;
4644

4745
mMode = FileScan;
@@ -65,20 +63,20 @@ QgsDelimitedTextFeatureIterator::QgsDelimitedTextFeatureIterator( QgsDelimitedTe
6563
mTestGeometry = true;
6664
// Exact intersection test only applies for WKT geometries
6765
mTestGeometryExact = mRequest.flags() & QgsFeatureRequest::ExactIntersect
68-
&& P->mGeomRep == QgsDelimitedTextProvider::GeomAsWkt;
66+
&& mSource->mGeomRep == QgsDelimitedTextProvider::GeomAsWkt;
6967

7068
QgsRectangle rect = request.filterRect();
7169

7270
// If request doesn't overlap extents, then nothing to return
73-
if ( ! rect.intersects( P->extent() ) )
71+
if ( ! rect.intersects( mSource->mExtent ) )
7472
{
7573
QgsDebugMsg( "Rectangle outside layer extents - no features to return" );
7674
mMode = FeatureIds;
7775
}
7876
// If the request extents include the entire layer, then revert to
7977
// a file scan
8078

81-
else if ( rect.contains( P->extent() ) )
79+
else if ( rect.contains( mSource->mExtent ) )
8280
{
8381
QgsDebugMsg( "Rectangle contains layer extents - bypass spatial filter" );
8482
mTestGeometry = false;
@@ -87,9 +85,9 @@ QgsDelimitedTextFeatureIterator::QgsDelimitedTextFeatureIterator( QgsDelimitedTe
8785
// for the subset. Also means we don't have to test geometries unless doing exact
8886
// intersection
8987

90-
else if ( P->mUseSpatialIndex )
88+
else if ( mSource->mUseSpatialIndex )
9189
{
92-
mFeatureIds = P->mSpatialIndex->intersects( rect );
90+
mFeatureIds = mSource->mSpatialIndex->intersects( rect );
9391
// Sort for efficient sequential retrieval
9492
qSort( mFeatureIds.begin(), mFeatureIds.end() );
9593
QgsDebugMsg( QString( "Layer has spatial index - selected %1 features from index" ).arg( mFeatureIds.size() ) );
@@ -100,9 +98,9 @@ QgsDelimitedTextFeatureIterator::QgsDelimitedTextFeatureIterator( QgsDelimitedTe
10098
}
10199

102100
// If we have a subset index then use it..
103-
if ( mMode == FileScan && P->mUseSubsetIndex )
101+
if ( mMode == FileScan && mSource->mUseSubsetIndex )
104102
{
105-
QgsDebugMsg( QString( "Layer has subset index - use %1 items from subset index" ).arg( P->mSubsetIndex.size() ) );
103+
QgsDebugMsg( QString( "Layer has subset index - use %1 items from subset index" ).arg( mSource->mSubsetIndex.size() ) );
106104
mTestSubset = false;
107105
mMode = SubsetIndex;
108106
}
@@ -121,7 +119,7 @@ QgsDelimitedTextFeatureIterator::QgsDelimitedTextFeatureIterator( QgsDelimitedTe
121119
&& (
122120
!( mRequest.flags() & QgsFeatureRequest::NoGeometry )
123121
|| mTestGeometry
124-
|| ( mTestSubset && P->mSubsetExpression->needsGeometry() )
122+
|| ( mTestSubset && mSource->mSubsetExpression->needsGeometry() )
125123
)
126124
)
127125
{
@@ -172,9 +170,9 @@ bool QgsDelimitedTextFeatureIterator::fetchFeature( QgsFeature& feature )
172170
fid = mFeatureIds[mNextId];
173171
}
174172
}
175-
else if ( mNextId < P->mSubsetIndex.size() )
173+
else if ( mNextId < mSource->mSubsetIndex.size() )
176174
{
177-
fid = P->mSubsetIndex[mNextId];
175+
fid = mSource->mSubsetIndex[mNextId];
178176
}
179177
if ( fid < 0 ) break;
180178
mNextId++;
@@ -200,7 +198,7 @@ bool QgsDelimitedTextFeatureIterator::rewind()
200198
// Skip to first data record
201199
if ( mMode == FileScan )
202200
{
203-
P->mFile->reset();
201+
mSource->mFile->reset();
204202
}
205203
else
206204
{
@@ -214,7 +212,7 @@ bool QgsDelimitedTextFeatureIterator::close()
214212
if ( mClosed )
215213
return false;
216214

217-
P->mActiveIterators.remove( this );
215+
iteratorClosed();
218216

219217
mFeatureIds = QList<QgsFeatureId>();
220218
mClosed = true;
@@ -252,7 +250,7 @@ bool QgsDelimitedTextFeatureIterator::nextFeatureInternal( QgsFeature& feature )
252250
{
253251
QStringList tokens;
254252

255-
QgsDelimitedTextFile *file = P->mFile;
253+
QgsDelimitedTextFile *file = mSource->mFile;
256254

257255
// If the iterator is not scanning the file, then it will have requested a specific
258256
// record, so only need to load that one.
@@ -269,7 +267,6 @@ bool QgsDelimitedTextFeatureIterator::nextFeatureInternal( QgsFeature& feature )
269267
// feature.
270268

271269
feature.setValid( false );
272-
if ( ! P->mValid ) break;
273270

274271
QgsDelimitedTextFile::Status status = file->nextRecord( tokens );
275272
if ( status == QgsDelimitedTextFile::RecordEOF ) break;
@@ -281,7 +278,7 @@ bool QgsDelimitedTextFeatureIterator::nextFeatureInternal( QgsFeature& feature )
281278

282279
QgsFeatureId fid = file->recordId();
283280

284-
while ( tokens.size() < P->mFieldCount )
281+
while ( tokens.size() < mSource->mFieldCount )
285282
tokens.append( QString::null );
286283

287284
QgsGeometry *geom = 0;
@@ -290,11 +287,11 @@ bool QgsDelimitedTextFeatureIterator::nextFeatureInternal( QgsFeature& feature )
290287

291288
if ( mLoadGeometry )
292289
{
293-
if ( P->mGeomRep == QgsDelimitedTextProvider::GeomAsWkt )
290+
if ( mSource->mGeomRep == QgsDelimitedTextProvider::GeomAsWkt )
294291
{
295292
geom = loadGeometryWkt( tokens );
296293
}
297-
else if ( P->mGeomRep == QgsDelimitedTextProvider::GeomAsXy )
294+
else if ( mSource->mGeomRep == QgsDelimitedTextProvider::GeomAsXy )
298295
{
299296
geom = loadGeometryXY( tokens );
300297
}
@@ -308,9 +305,9 @@ bool QgsDelimitedTextFeatureIterator::nextFeatureInternal( QgsFeature& feature )
308305
// At this point the current feature values are valid
309306

310307
feature.setValid( true );
311-
feature.setFields( &P->attributeFields ); // allow name-based attribute lookups
308+
feature.setFields( &mSource->mFields ); // allow name-based attribute lookups
312309
feature.setFeatureId( fid );
313-
feature.initAttributes( P->attributeFields.count() );
310+
feature.initAttributes( mSource->mFields.count() );
314311

315312
if ( geom )
316313
feature.setGeometry( geom );
@@ -329,16 +326,16 @@ bool QgsDelimitedTextFeatureIterator::nextFeatureInternal( QgsFeature& feature )
329326
}
330327
else
331328
{
332-
for ( int idx = 0; idx < P->attributeFields.count(); ++idx )
329+
for ( int idx = 0; idx < mSource->mFields.count(); ++idx )
333330
fetchAttribute( feature, idx, tokens );
334331
}
335332

336333
// If the iterator hasn't already filtered out the subset, then do it now
337334

338335
if ( mTestSubset )
339336
{
340-
QVariant isOk = P->mSubsetExpression->evaluate( &feature );
341-
if ( P->mSubsetExpression->hasEvalError() ) continue;
337+
QVariant isOk = mSource->mSubsetExpression->evaluate( &feature );
338+
if ( mSource->mSubsetExpression->hasEvalError() ) continue;
342339
if ( ! isOk.toBool() ) continue;
343340
}
344341

@@ -352,19 +349,19 @@ bool QgsDelimitedTextFeatureIterator::nextFeatureInternal( QgsFeature& feature )
352349

353350
bool QgsDelimitedTextFeatureIterator::setNextFeatureId( qint64 fid )
354351
{
355-
return P->mFile->setNextRecordId(( long ) fid );
352+
return mSource->mFile->setNextRecordId(( long ) fid );
356353
}
357354

358355

359356

360357
QgsGeometry* QgsDelimitedTextFeatureIterator::loadGeometryWkt( const QStringList& tokens )
361358
{
362359
QgsGeometry* geom = 0;
363-
QString sWkt = tokens[P->mWktFieldIndex];
360+
QString sWkt = tokens[mSource->mWktFieldIndex];
364361

365-
geom = P->geomFromWkt( sWkt );
362+
geom = QgsDelimitedTextProvider::geomFromWkt( sWkt, mSource->mWktHasPrefix, mSource->mWktHasZM );
366363

367-
if ( geom && geom->type() != P->mGeometryType )
364+
if ( geom && geom->type() != mSource->mGeometryType )
368365
{
369366
delete geom;
370367
geom = 0;
@@ -379,10 +376,10 @@ QgsGeometry* QgsDelimitedTextFeatureIterator::loadGeometryWkt( const QStringList
379376

380377
QgsGeometry* QgsDelimitedTextFeatureIterator::loadGeometryXY( const QStringList& tokens )
381378
{
382-
QString sX = tokens[P->mXFieldIndex];
383-
QString sY = tokens[P->mYFieldIndex];
379+
QString sX = tokens[mSource->mXFieldIndex];
380+
QString sY = tokens[mSource->mYFieldIndex];
384381
QgsPoint pt;
385-
bool ok = P->pointFromXY( sX, sY, pt );
382+
bool ok = QgsDelimitedTextProvider::pointFromXY( sX, sY, pt, mSource->mDecimalPoint, mSource->mXyDms );
386383

387384
if ( ok && wantGeometry( pt ) )
388385
{
@@ -395,12 +392,12 @@ QgsGeometry* QgsDelimitedTextFeatureIterator::loadGeometryXY( const QStringList&
395392

396393
void QgsDelimitedTextFeatureIterator::fetchAttribute( QgsFeature& feature, int fieldIdx, const QStringList& tokens )
397394
{
398-
if ( fieldIdx < 0 || fieldIdx >= P->attributeColumns.count() ) return;
399-
int column = P->attributeColumns[fieldIdx];
395+
if ( fieldIdx < 0 || fieldIdx >= mSource->attributeColumns.count() ) return;
396+
int column = mSource->attributeColumns[fieldIdx];
400397
if ( column < 0 || column >= tokens.count() ) return;
401398
const QString &value = tokens[column];
402399
QVariant val;
403-
switch ( P->attributeFields[fieldIdx].type() )
400+
switch ( mSource->mFields[fieldIdx].type() )
404401
{
405402
case QVariant::Int:
406403
{
@@ -410,7 +407,7 @@ void QgsDelimitedTextFeatureIterator::fetchAttribute( QgsFeature& feature, int f
410407
if ( ok )
411408
val = QVariant( ivalue );
412409
else
413-
val = QVariant( P->attributeFields[fieldIdx].type() );
410+
val = QVariant( mSource->mFields[fieldIdx].type() );
414411
break;
415412
}
416413
case QVariant::Double:
@@ -419,13 +416,13 @@ void QgsDelimitedTextFeatureIterator::fetchAttribute( QgsFeature& feature, int f
419416
bool ok = false;
420417
if ( ! value.isEmpty() )
421418
{
422-
if ( P->mDecimalPoint.isEmpty() )
419+
if ( mSource->mDecimalPoint.isEmpty() )
423420
{
424421
dvalue = value.toDouble( &ok );
425422
}
426423
else
427424
{
428-
dvalue = QString( value ).replace( P->mDecimalPoint, "." ).toDouble( &ok );
425+
dvalue = QString( value ).replace( mSource->mDecimalPoint, "." ).toDouble( &ok );
429426
}
430427
}
431428
if ( ok )
@@ -434,7 +431,7 @@ void QgsDelimitedTextFeatureIterator::fetchAttribute( QgsFeature& feature, int f
434431
}
435432
else
436433
{
437-
val = QVariant( P->attributeFields[fieldIdx].type() );
434+
val = QVariant( mSource->mFields[fieldIdx].type() );
438435
}
439436
break;
440437
}
@@ -444,3 +441,41 @@ void QgsDelimitedTextFeatureIterator::fetchAttribute( QgsFeature& feature, int f
444441
}
445442
feature.setAttribute( fieldIdx, val );
446443
}
444+
445+
// ------------
446+
447+
QgsDelimitedTextFeatureSource::QgsDelimitedTextFeatureSource( const QgsDelimitedTextProvider* p )
448+
: mGeomRep( p->mGeomRep )
449+
, mSubsetExpression( p->mSubsetExpression )
450+
, mExtent( p->mExtent )
451+
, mUseSpatialIndex( p->mUseSpatialIndex )
452+
, mSpatialIndex( p->mSpatialIndex ? new QgsSpatialIndex( *p->mSpatialIndex ) : 0 )
453+
, mUseSubsetIndex( p->mUseSubsetIndex )
454+
, mSubsetIndex( p->mSubsetIndex )
455+
, mFile( 0 )
456+
, mFields( p->attributeFields )
457+
, mFieldCount( p->mFieldCount )
458+
, mXFieldIndex( p->mXFieldIndex )
459+
, mYFieldIndex( p->mYFieldIndex )
460+
, mWktFieldIndex( p->mWktFieldIndex )
461+
, mWktHasZM( p->mWktHasZM )
462+
, mWktHasPrefix( p->mWktHasPrefix )
463+
, mGeometryType( p->mGeometryType )
464+
, mDecimalPoint( p->mDecimalPoint )
465+
, mXyDms( p->mXyDms )
466+
, attributeColumns( p->attributeColumns )
467+
{
468+
mFile = new QgsDelimitedTextFile();
469+
mFile->setFromUrl( p->mFile->url() );
470+
}
471+
472+
QgsDelimitedTextFeatureSource::~QgsDelimitedTextFeatureSource()
473+
{
474+
delete mSpatialIndex;
475+
delete mFile;
476+
}
477+
478+
QgsFeatureIterator QgsDelimitedTextFeatureSource::getFeatures( const QgsFeatureRequest& request )
479+
{
480+
return QgsFeatureIterator( new QgsDelimitedTextFeatureIterator( this, false, request ) );
481+
}

src/providers/delimitedtext/qgsdelimitedtextfeatureiterator.h

+36-4
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,42 @@
1919
#include "qgsfeatureiterator.h"
2020
#include "qgsfeature.h"
2121

22-
class QgsDelimitedTextProvider;
22+
#include "qgsdelimitedtextprovider.h"
2323

24-
class QgsDelimitedTextFeatureIterator : public QgsAbstractFeatureIterator
24+
class QgsDelimitedTextFeatureSource : public QgsAbstractFeatureSource
25+
{
26+
public:
27+
QgsDelimitedTextFeatureSource( const QgsDelimitedTextProvider* p );
28+
~QgsDelimitedTextFeatureSource();
29+
30+
virtual QgsFeatureIterator getFeatures( const QgsFeatureRequest& request );
31+
32+
protected:
33+
QgsDelimitedTextProvider::GeomRepresentationType mGeomRep;
34+
QgsExpression *mSubsetExpression;
35+
QgsRectangle mExtent;
36+
bool mUseSpatialIndex;
37+
QgsSpatialIndex *mSpatialIndex;
38+
bool mUseSubsetIndex;
39+
QList<quintptr> mSubsetIndex;
40+
QgsDelimitedTextFile *mFile;
41+
QgsFields mFields;
42+
int mFieldCount; // Note: this includes field count for wkt field
43+
int mXFieldIndex;
44+
int mYFieldIndex;
45+
int mWktFieldIndex;
46+
bool mWktHasZM;
47+
bool mWktHasPrefix;
48+
QGis::GeometryType mGeometryType;
49+
QString mDecimalPoint;
50+
bool mXyDms;
51+
QList<int> attributeColumns;
52+
53+
friend class QgsDelimitedTextFeatureIterator;
54+
};
55+
56+
57+
class QgsDelimitedTextFeatureIterator : public QgsAbstractFeatureIteratorFromSource<QgsDelimitedTextFeatureSource>
2558
{
2659
enum IteratorMode
2760
{
@@ -30,7 +63,7 @@ class QgsDelimitedTextFeatureIterator : public QgsAbstractFeatureIterator
3063
FeatureIds
3164
};
3265
public:
33-
QgsDelimitedTextFeatureIterator( QgsDelimitedTextProvider* p, const QgsFeatureRequest& request );
66+
QgsDelimitedTextFeatureIterator( QgsDelimitedTextFeatureSource* source, bool ownSource, const QgsFeatureRequest& request );
3467

3568
~QgsDelimitedTextFeatureIterator();
3669

@@ -55,7 +88,6 @@ class QgsDelimitedTextFeatureIterator : public QgsAbstractFeatureIterator
5588
QgsGeometry* loadGeometryXY( const QStringList& tokens );
5689
void fetchAttribute( QgsFeature& feature, int fieldIdx, const QStringList& tokens );
5790

58-
QgsDelimitedTextProvider* P;
5991
QList<QgsFeatureId> mFeatureIds;
6092
IteratorMode mMode;
6193
long mNextId;

0 commit comments

Comments
 (0)