25
25
#include < QtAlgorithms>
26
26
#include < QTextStream>
27
27
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 )
31
30
{
32
- P->mActiveIterators << this ;
33
31
34
32
// Determine mode to use based on request...
35
33
QgsDebugMsg ( " Setting up QgsDelimitedTextIterator" );
36
34
37
35
// Does the layer have geometry - will revise later to determine if we actually need to
38
36
// load it.
39
- bool hasGeometry = P ->mGeomRep != QgsDelimitedTextProvider::GeomNone;
37
+ bool hasGeometry = mSource ->mGeomRep != QgsDelimitedTextProvider::GeomNone;
40
38
41
39
// Does the layer have an explicit or implicit subset (implicit subset is if we have geometry which can
42
40
// be invalid)
43
41
44
- mTestSubset = P ->mSubsetExpression ;
42
+ mTestSubset = mSource ->mSubsetExpression ;
45
43
mTestGeometry = false ;
46
44
47
45
mMode = FileScan;
@@ -65,20 +63,20 @@ QgsDelimitedTextFeatureIterator::QgsDelimitedTextFeatureIterator( QgsDelimitedTe
65
63
mTestGeometry = true ;
66
64
// Exact intersection test only applies for WKT geometries
67
65
mTestGeometryExact = mRequest .flags () & QgsFeatureRequest::ExactIntersect
68
- && P ->mGeomRep == QgsDelimitedTextProvider::GeomAsWkt;
66
+ && mSource ->mGeomRep == QgsDelimitedTextProvider::GeomAsWkt;
69
67
70
68
QgsRectangle rect = request.filterRect ();
71
69
72
70
// If request doesn't overlap extents, then nothing to return
73
- if ( ! rect.intersects ( P-> extent () ) )
71
+ if ( ! rect.intersects ( mSource -> mExtent ) )
74
72
{
75
73
QgsDebugMsg ( " Rectangle outside layer extents - no features to return" );
76
74
mMode = FeatureIds;
77
75
}
78
76
// If the request extents include the entire layer, then revert to
79
77
// a file scan
80
78
81
- else if ( rect.contains ( P-> extent () ) )
79
+ else if ( rect.contains ( mSource -> mExtent ) )
82
80
{
83
81
QgsDebugMsg ( " Rectangle contains layer extents - bypass spatial filter" );
84
82
mTestGeometry = false ;
@@ -87,9 +85,9 @@ QgsDelimitedTextFeatureIterator::QgsDelimitedTextFeatureIterator( QgsDelimitedTe
87
85
// for the subset. Also means we don't have to test geometries unless doing exact
88
86
// intersection
89
87
90
- else if ( P ->mUseSpatialIndex )
88
+ else if ( mSource ->mUseSpatialIndex )
91
89
{
92
- mFeatureIds = P ->mSpatialIndex ->intersects ( rect );
90
+ mFeatureIds = mSource ->mSpatialIndex ->intersects ( rect );
93
91
// Sort for efficient sequential retrieval
94
92
qSort ( mFeatureIds .begin (), mFeatureIds .end () );
95
93
QgsDebugMsg ( QString ( " Layer has spatial index - selected %1 features from index" ).arg ( mFeatureIds .size () ) );
@@ -100,9 +98,9 @@ QgsDelimitedTextFeatureIterator::QgsDelimitedTextFeatureIterator( QgsDelimitedTe
100
98
}
101
99
102
100
// If we have a subset index then use it..
103
- if ( mMode == FileScan && P ->mUseSubsetIndex )
101
+ if ( mMode == FileScan && mSource ->mUseSubsetIndex )
104
102
{
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 () ) );
106
104
mTestSubset = false ;
107
105
mMode = SubsetIndex;
108
106
}
@@ -121,7 +119,7 @@ QgsDelimitedTextFeatureIterator::QgsDelimitedTextFeatureIterator( QgsDelimitedTe
121
119
&& (
122
120
!( mRequest .flags () & QgsFeatureRequest::NoGeometry )
123
121
|| mTestGeometry
124
- || ( mTestSubset && P ->mSubsetExpression ->needsGeometry () )
122
+ || ( mTestSubset && mSource ->mSubsetExpression ->needsGeometry () )
125
123
)
126
124
)
127
125
{
@@ -172,9 +170,9 @@ bool QgsDelimitedTextFeatureIterator::fetchFeature( QgsFeature& feature )
172
170
fid = mFeatureIds [mNextId ];
173
171
}
174
172
}
175
- else if ( mNextId < P ->mSubsetIndex .size () )
173
+ else if ( mNextId < mSource ->mSubsetIndex .size () )
176
174
{
177
- fid = P ->mSubsetIndex [mNextId ];
175
+ fid = mSource ->mSubsetIndex [mNextId ];
178
176
}
179
177
if ( fid < 0 ) break ;
180
178
mNextId ++;
@@ -200,7 +198,7 @@ bool QgsDelimitedTextFeatureIterator::rewind()
200
198
// Skip to first data record
201
199
if ( mMode == FileScan )
202
200
{
203
- P ->mFile ->reset ();
201
+ mSource ->mFile ->reset ();
204
202
}
205
203
else
206
204
{
@@ -214,7 +212,7 @@ bool QgsDelimitedTextFeatureIterator::close()
214
212
if ( mClosed )
215
213
return false ;
216
214
217
- P-> mActiveIterators . remove ( this );
215
+ iteratorClosed ( );
218
216
219
217
mFeatureIds = QList<QgsFeatureId>();
220
218
mClosed = true ;
@@ -252,7 +250,7 @@ bool QgsDelimitedTextFeatureIterator::nextFeatureInternal( QgsFeature& feature )
252
250
{
253
251
QStringList tokens;
254
252
255
- QgsDelimitedTextFile *file = P ->mFile ;
253
+ QgsDelimitedTextFile *file = mSource ->mFile ;
256
254
257
255
// If the iterator is not scanning the file, then it will have requested a specific
258
256
// record, so only need to load that one.
@@ -269,7 +267,6 @@ bool QgsDelimitedTextFeatureIterator::nextFeatureInternal( QgsFeature& feature )
269
267
// feature.
270
268
271
269
feature.setValid ( false );
272
- if ( ! P->mValid ) break ;
273
270
274
271
QgsDelimitedTextFile::Status status = file->nextRecord ( tokens );
275
272
if ( status == QgsDelimitedTextFile::RecordEOF ) break ;
@@ -281,7 +278,7 @@ bool QgsDelimitedTextFeatureIterator::nextFeatureInternal( QgsFeature& feature )
281
278
282
279
QgsFeatureId fid = file->recordId ();
283
280
284
- while ( tokens.size () < P ->mFieldCount )
281
+ while ( tokens.size () < mSource ->mFieldCount )
285
282
tokens.append ( QString::null );
286
283
287
284
QgsGeometry *geom = 0 ;
@@ -290,11 +287,11 @@ bool QgsDelimitedTextFeatureIterator::nextFeatureInternal( QgsFeature& feature )
290
287
291
288
if ( mLoadGeometry )
292
289
{
293
- if ( P ->mGeomRep == QgsDelimitedTextProvider::GeomAsWkt )
290
+ if ( mSource ->mGeomRep == QgsDelimitedTextProvider::GeomAsWkt )
294
291
{
295
292
geom = loadGeometryWkt ( tokens );
296
293
}
297
- else if ( P ->mGeomRep == QgsDelimitedTextProvider::GeomAsXy )
294
+ else if ( mSource ->mGeomRep == QgsDelimitedTextProvider::GeomAsXy )
298
295
{
299
296
geom = loadGeometryXY ( tokens );
300
297
}
@@ -308,9 +305,9 @@ bool QgsDelimitedTextFeatureIterator::nextFeatureInternal( QgsFeature& feature )
308
305
// At this point the current feature values are valid
309
306
310
307
feature.setValid ( true );
311
- feature.setFields ( &P-> attributeFields ); // allow name-based attribute lookups
308
+ feature.setFields ( &mSource -> mFields ); // allow name-based attribute lookups
312
309
feature.setFeatureId ( fid );
313
- feature.initAttributes ( P-> attributeFields .count () );
310
+ feature.initAttributes ( mSource -> mFields .count () );
314
311
315
312
if ( geom )
316
313
feature.setGeometry ( geom );
@@ -329,16 +326,16 @@ bool QgsDelimitedTextFeatureIterator::nextFeatureInternal( QgsFeature& feature )
329
326
}
330
327
else
331
328
{
332
- for ( int idx = 0 ; idx < P-> attributeFields .count (); ++idx )
329
+ for ( int idx = 0 ; idx < mSource -> mFields .count (); ++idx )
333
330
fetchAttribute ( feature, idx, tokens );
334
331
}
335
332
336
333
// If the iterator hasn't already filtered out the subset, then do it now
337
334
338
335
if ( mTestSubset )
339
336
{
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 ;
342
339
if ( ! isOk.toBool () ) continue ;
343
340
}
344
341
@@ -352,19 +349,19 @@ bool QgsDelimitedTextFeatureIterator::nextFeatureInternal( QgsFeature& feature )
352
349
353
350
bool QgsDelimitedTextFeatureIterator::setNextFeatureId ( qint64 fid )
354
351
{
355
- return P ->mFile ->setNextRecordId (( long ) fid );
352
+ return mSource ->mFile ->setNextRecordId (( long ) fid );
356
353
}
357
354
358
355
359
356
360
357
QgsGeometry* QgsDelimitedTextFeatureIterator::loadGeometryWkt ( const QStringList& tokens )
361
358
{
362
359
QgsGeometry* geom = 0 ;
363
- QString sWkt = tokens[P ->mWktFieldIndex ];
360
+ QString sWkt = tokens[mSource ->mWktFieldIndex ];
364
361
365
- geom = P-> geomFromWkt ( sWkt );
362
+ geom = QgsDelimitedTextProvider:: geomFromWkt ( sWkt , mSource -> mWktHasPrefix , mSource -> mWktHasZM );
366
363
367
- if ( geom && geom->type () != P ->mGeometryType )
364
+ if ( geom && geom->type () != mSource ->mGeometryType )
368
365
{
369
366
delete geom;
370
367
geom = 0 ;
@@ -379,10 +376,10 @@ QgsGeometry* QgsDelimitedTextFeatureIterator::loadGeometryWkt( const QStringList
379
376
380
377
QgsGeometry* QgsDelimitedTextFeatureIterator::loadGeometryXY ( const QStringList& tokens )
381
378
{
382
- QString sX = tokens[P ->mXFieldIndex ];
383
- QString sY = tokens[P ->mYFieldIndex ];
379
+ QString sX = tokens[mSource ->mXFieldIndex ];
380
+ QString sY = tokens[mSource ->mYFieldIndex ];
384
381
QgsPoint pt;
385
- bool ok = P-> pointFromXY ( sX , sY , pt );
382
+ bool ok = QgsDelimitedTextProvider:: pointFromXY ( sX , sY , pt, mSource -> mDecimalPoint , mSource -> mXyDms );
386
383
387
384
if ( ok && wantGeometry ( pt ) )
388
385
{
@@ -395,12 +392,12 @@ QgsGeometry* QgsDelimitedTextFeatureIterator::loadGeometryXY( const QStringList&
395
392
396
393
void QgsDelimitedTextFeatureIterator::fetchAttribute ( QgsFeature& feature, int fieldIdx, const QStringList& tokens )
397
394
{
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];
400
397
if ( column < 0 || column >= tokens.count () ) return ;
401
398
const QString &value = tokens[column];
402
399
QVariant val;
403
- switch ( P-> attributeFields [fieldIdx].type () )
400
+ switch ( mSource -> mFields [fieldIdx].type () )
404
401
{
405
402
case QVariant::Int:
406
403
{
@@ -410,7 +407,7 @@ void QgsDelimitedTextFeatureIterator::fetchAttribute( QgsFeature& feature, int f
410
407
if ( ok )
411
408
val = QVariant ( ivalue );
412
409
else
413
- val = QVariant ( P-> attributeFields [fieldIdx].type () );
410
+ val = QVariant ( mSource -> mFields [fieldIdx].type () );
414
411
break ;
415
412
}
416
413
case QVariant::Double:
@@ -419,13 +416,13 @@ void QgsDelimitedTextFeatureIterator::fetchAttribute( QgsFeature& feature, int f
419
416
bool ok = false ;
420
417
if ( ! value.isEmpty () )
421
418
{
422
- if ( P ->mDecimalPoint .isEmpty () )
419
+ if ( mSource ->mDecimalPoint .isEmpty () )
423
420
{
424
421
dvalue = value.toDouble ( &ok );
425
422
}
426
423
else
427
424
{
428
- dvalue = QString ( value ).replace ( P ->mDecimalPoint , " ." ).toDouble ( &ok );
425
+ dvalue = QString ( value ).replace ( mSource ->mDecimalPoint , " ." ).toDouble ( &ok );
429
426
}
430
427
}
431
428
if ( ok )
@@ -434,7 +431,7 @@ void QgsDelimitedTextFeatureIterator::fetchAttribute( QgsFeature& feature, int f
434
431
}
435
432
else
436
433
{
437
- val = QVariant ( P-> attributeFields [fieldIdx].type () );
434
+ val = QVariant ( mSource -> mFields [fieldIdx].type () );
438
435
}
439
436
break ;
440
437
}
@@ -444,3 +441,41 @@ void QgsDelimitedTextFeatureIterator::fetchAttribute( QgsFeature& feature, int f
444
441
}
445
442
feature.setAttribute ( fieldIdx, val );
446
443
}
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
+ }
0 commit comments