21
21
#include < cfloat>
22
22
#include < iostream>
23
23
24
- #include < qfile.h >
25
- #include < qdatastream.h >
26
- #include < qtextstream.h >
27
- #include < qstringlist.h >
28
- #include < qmessagebox.h >
29
- #include < qsettings.h >
30
- #include < qregexp.h >
24
+ #include < QFile >
25
+ #include < QDataStream >
26
+ #include < QTextStream >
27
+ #include < QStringList >
28
+ #include < QMessageBox >
29
+ #include < QSettings >
30
+ #include < QRegExp >
31
31
#include < q3url.h>
32
- #include < qglobal.h>
33
32
34
33
#include < ogrsf_frmts.h>
35
34
38
37
#include " qgsfeature.h"
39
38
#include " qgsfield.h"
40
39
#include " qgsrect.h"
41
-
40
+ #include " qgis.h"
41
+ #include " qgsmessageviewer.h"
42
42
43
43
#ifdef WIN32
44
44
#define QGISEXTERN extern " C" __declspec( dllexport )
@@ -54,7 +54,8 @@ static const QString TEXT_PROVIDER_DESCRIPTION = "Delimited text data provider";
54
54
55
55
QgsDelimitedTextProvider::QgsDelimitedTextProvider (QString const &uri)
56
56
: QgsVectorDataProvider(uri),
57
- mMinMaxCacheDirty(true )
57
+ mMinMaxCacheDirty(true ),
58
+ mShowInvalidLines(true )
58
59
{
59
60
// Get the file name and mDelimiter out of the uri
60
61
mFileName = uri.left (uri.find (" ?" ));
@@ -99,7 +100,7 @@ QgsDelimitedTextProvider::QgsDelimitedTextProvider(QString const &uri)
99
100
mFile = new QFile (mFileName );
100
101
if (mFile ->open (QIODevice::ReadOnly))
101
102
{
102
- QTextStream stream (mFile );
103
+ mStream = new QTextStream (mFile );
103
104
QString line;
104
105
mNumberFeatures = 0 ;
105
106
int xyCount = 0 ;
@@ -108,10 +109,11 @@ QgsDelimitedTextProvider::QgsDelimitedTextProvider(QString const &uri)
108
109
mExtent = new QgsRect ();
109
110
// commented out by Tim for now - setMinimal needs to be merged in from 0.7 branch
110
111
// mExtent->setMinimal(); // This defeats normalization
111
- while (!stream.atEnd ())
112
+ bool firstPoint = true ;
113
+ while (!mStream ->atEnd ())
112
114
{
113
115
lineNumber++;
114
- line = stream. readLine (); // line of text excluding '\n', default local 8 bit encoding.
116
+ line = mStream -> readLine (); // line of text excluding '\n', default local 8 bit encoding.
115
117
if (mNumberFeatures ++ == 0 )
116
118
{
117
119
// Get the fields from the header row and store them in the
@@ -124,8 +126,8 @@ QgsDelimitedTextProvider::QgsDelimitedTextProvider(QString const &uri)
124
126
QStringList fieldList =
125
127
QStringList::split (QRegExp (mDelimiter ), line, true );
126
128
#ifdef QGISDEBUG
127
- std::cerr << " Split line into " << fieldList.
128
- size () << " parts" << std::endl;
129
+ std::cerr << " Split line into "
130
+ << fieldList. size () << " parts" << std::endl;
129
131
#endif
130
132
// We don't know anything about a text based field other
131
133
// than its name. All fields are assumed to be text
@@ -194,23 +196,32 @@ QgsDelimitedTextProvider::QgsDelimitedTextProvider(QString const &uri)
194
196
bool yOk = true ;
195
197
double x = sX .toDouble (&xOk);
196
198
double y = sY .toDouble (&yOk);
199
+
197
200
if (xOk && yOk)
198
201
{
199
- if (x > mExtent ->xMax ())
200
- {
201
- mExtent ->setXmax (x);
202
- }
203
- if (x < mExtent ->xMin ())
204
- {
205
- mExtent ->setXmin (x);
206
- }
207
- if (y > mExtent ->yMax ())
202
+ if (!firstPoint)
208
203
{
209
- mExtent ->setYmax (y);
204
+ if (x > mExtent ->xMax ())
205
+ {
206
+ mExtent ->setXmax (x);
207
+ }
208
+ if (x < mExtent ->xMin ())
209
+ {
210
+ mExtent ->setXmin (x);
211
+ }
212
+ if (y > mExtent ->yMax ())
213
+ {
214
+ mExtent ->setYmax (y);
215
+ }
216
+ if (y < mExtent ->yMin ())
217
+ {
218
+ mExtent ->setYmin (y);
219
+ }
210
220
}
211
- if (y < mExtent ->yMin ())
212
- {
213
- mExtent ->setYmin (y);
221
+ else
222
+ { // Extent for the first point is just the first point
223
+ mExtent ->set (x,y,x,y);
224
+ firstPoint = false ;
214
225
}
215
226
}
216
227
}
@@ -264,6 +275,7 @@ QgsDelimitedTextProvider::~QgsDelimitedTextProvider()
264
275
{
265
276
mFile ->close ();
266
277
delete mFile ;
278
+ delete mStream ;
267
279
for (int i = 0 ; i < fieldCount (); i++)
268
280
{
269
281
delete mMinMaxCache [i];
@@ -338,13 +350,9 @@ QgsDelimitedTextProvider::getNextFeature_( QgsFeature & feature,
338
350
// before we do anything else, assume that there's something wrong with
339
351
// the feature
340
352
feature.setValid ( false );
341
-
342
- QTextStream textStream ( mFile );
343
-
344
- if ( ! textStream.atEnd () )
353
+ while ( ! mStream ->atEnd () )
345
354
{
346
- QString line = textStream.readLine (); // Default local 8 bit encoding
347
-
355
+ QString line = mStream ->readLine (); // Default local 8 bit encoding
348
356
// lex the tokens from the current data line
349
357
QStringList tokens = QStringList::split (QRegExp (mDelimiter ), line, true );
350
358
@@ -357,62 +365,27 @@ QgsDelimitedTextProvider::getNextFeature_( QgsFeature & feature,
357
365
double x = tokens[xFieldPos].toDouble ( &xOk );
358
366
double y = tokens[yFieldPos].toDouble ( &yOk );
359
367
360
- if ( xOk && yOk )
368
+ if (! ( xOk && yOk) )
361
369
{
362
- // if the user has selected an area, constrain iterator to
363
- // features that are within that area
364
- if ( mSelectionRectangle && ! boundsCheck (x,y) )
365
- {
366
- bool foundFeature = false ;
367
-
368
- while ( ! textStream.atEnd () &&
369
- (xOk && yOk) )
370
- {
371
- if ( boundsCheck (x,y) )
372
- {
373
- foundFeature = true ;
374
- break ;
375
- }
376
-
377
- ++mFid ; // since we're skipping to next feature,
378
- // increment ID
379
-
380
- line = textStream.readLine ();
381
-
382
- tokens = QStringList::split (QRegExp (mDelimiter ), line, true );
383
-
384
- x = tokens[xFieldPos].toDouble ( &xOk );
385
- y = tokens[yFieldPos].toDouble ( &yOk );
386
- }
370
+ // Accumulate any lines that weren't ok, to report on them
371
+ // later, and look at the next line in the file.
372
+ mInvalidLines << line;
373
+ continue ;
374
+ }
387
375
388
- // there were no other features from the current one forward
389
- // that were within the selection region
390
- if ( ! foundFeature )
391
- {
392
- return false ;
393
- }
394
- }
376
+ if (! boundsCheck (x,y))
377
+ continue ;
395
378
396
- // at this point, one way or another, the current feature values
397
- // are valid
379
+ // at this point, one way or another, the current feature values
380
+ // are valid
398
381
feature.setValid ( true );
399
382
400
383
++mFid ; // increment to next feature ID
401
384
402
385
feature.setFeatureId ( mFid );
403
386
404
- unsigned char * geometry = new unsigned char [sizeof (wkbPoint)];
405
387
QByteArray buffer;
406
- buffer.setRawData ( (const char *)geometry, sizeof (wkbPoint) ); // buffer
407
- // points
408
- // to
409
- // geometry
410
-
411
- #if QT_VERSION < 0x040000
412
- QDataStream s ( buffer, QIODevice::WriteOnly ); // open on buffers's data
413
- #else
414
388
QDataStream s ( &buffer, QIODevice::WriteOnly ); // open on buffers's data
415
- #endif
416
389
417
390
switch ( endian () )
418
391
{
@@ -428,20 +401,19 @@ QgsDelimitedTextProvider::getNextFeature_( QgsFeature & feature,
428
401
break ;
429
402
default :
430
403
qDebug ( " %s:%d unknown endian" , __FILE__, __LINE__ );
431
- delete [] geometry;
404
+ // delete [] geometry;
432
405
return false ;
433
406
}
434
407
435
- s << (Q_UINT32)1 ; // 1 is for WKBPoint
408
+ s << (Q_UINT32)QGis:: WKBPoint;
436
409
s << x;
437
410
s << y;
438
411
412
+ unsigned char * geometry = new unsigned char [buffer.size ()];
413
+ memcpy (geometry, buffer.data (), buffer.size ());
439
414
440
415
feature.setGeometryAndOwnership ( geometry, sizeof (wkbPoint) );
441
416
442
- // ensure that the buffer doesn't delete the data on us
443
- buffer.resetRawData ( (const char *)geometry, sizeof (wkbPoint) );
444
-
445
417
if ( getAttributes && ! desiredAttributes )
446
418
{
447
419
for (int fi = 0 ; fi < attributeFields.size (); fi++)
@@ -461,13 +433,25 @@ QgsDelimitedTextProvider::getNextFeature_( QgsFeature & feature,
461
433
feature.addAttribute (attributeFields[*i].name (), tokens[*i]);
462
434
}
463
435
}
464
-
436
+ // We have a good line, so return
465
437
return true ;
466
438
467
- } // if able to get x and y coordinates
468
-
469
439
} // ! textStream EOF
470
440
441
+ // End of the file. If there are any lines that couldn't be
442
+ // loaded, display them now, but only once.
443
+
444
+ if (mShowInvalidLines && !mInvalidLines .isEmpty ())
445
+ {
446
+ mShowInvalidLines = false ;
447
+ QgsMessageViewer lineViewer;
448
+ lineViewer.setMessageAsPlainText (tr (" Note: the following lines were not loaded because Qgis was unable to determine values for the x and y coordinates:\n " ));
449
+ for (int i = 0 ; i < mInvalidLines .size (); ++i)
450
+ lineViewer.appendMessage (mInvalidLines .at (i));
451
+
452
+ lineViewer.exec ();
453
+ }
454
+
471
455
return false ;
472
456
473
457
} // getNextFeature_( QgsFeature & feature )
@@ -632,14 +616,12 @@ std::vector<QgsField> const & QgsDelimitedTextProvider::fields() const
632
616
633
617
void QgsDelimitedTextProvider::reset ()
634
618
{
635
- // Reset the file pointer to BOF
636
- mFile ->reset ();
637
619
// Reset feature id to 0
638
620
mFid = 0 ;
639
621
// Skip ahead one line since first record is always assumed to be
640
622
// the header record
641
- QTextStream stream ( mFile );
642
- stream. readLine ();
623
+ mStream -> seek ( 0 );
624
+ mStream -> readLine ();
643
625
}
644
626
645
627
QString QgsDelimitedTextProvider::minValue (int position)
@@ -837,24 +819,20 @@ bool QgsDelimitedTextProvider::saveAsShapefile()
837
819
std::cerr << " Done creating fields" << std::endl;
838
820
// read the line
839
821
reset ();
840
- QTextStream stream (mFile );
841
822
QString line;
842
- while (!stream. atEnd ())
823
+ while (!mStream -> atEnd ())
843
824
{
844
- line = stream.readLine (); // line of text excluding '\n'
845
- std::cerr << (const char *)line.toLocal8Bit ().data () << std::endl;
825
+ line = mStream ->readLine (); // line of text excluding '\n'
846
826
// split the line
847
827
QStringList parts =
848
828
QStringList::split (QRegExp (mDelimiter ), line, true );
849
- std::cerr << " Split line into " << parts.size () << std::endl;
850
829
851
830
// create the feature
852
831
OGRFeature *poFeature;
853
832
854
833
poFeature = new OGRFeature (poLayer->GetLayerDefn ());
855
834
856
835
// iterate over the parts and set the fields
857
- std::cerr << " Setting the field values" << std::endl;
858
836
// set limit - we will ignore extra fields on the line
859
837
int limit = attributeFields.size ();
860
838
@@ -871,8 +849,6 @@ bool QgsDelimitedTextProvider::saveAsShapefile()
871
849
{
872
850
if (parts[i] != QString::null)
873
851
{
874
- std::cerr << " Setting " << i << " " << (const char *)attributeFields[i].
875
- name ().toLocal8Bit ().data () << " to " << (const char *)parts[i].toLocal8Bit ().data () << std::endl;
876
852
poFeature->SetField (saveCodec->fromUnicode (attributeFields[i].name ()).data (),
877
853
saveCodec->fromUnicode (parts[i]).data ());
878
854
@@ -958,11 +934,10 @@ int *QgsDelimitedTextProvider::getFieldLengths()
958
934
{
959
935
reset ();
960
936
// read the line
961
- QTextStream stream (mFile );
962
937
QString line;
963
- while (!stream. atEnd ())
938
+ while (!mStream -> atEnd ())
964
939
{
965
- line = stream. readLine (); // line of text excluding '\n'
940
+ line = mStream -> readLine (); // line of text excluding '\n'
966
941
// split the line
967
942
QStringList parts = QStringList::split (QRegExp (mDelimiter ), line, true );
968
943
// iterate over the parts and update the max value
0 commit comments