2121#include < cfloat>
2222#include < iostream>
2323
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 >
3131#include < q3url.h>
32- #include < qglobal.h>
3332
3433#include < ogrsf_frmts.h>
3534
3837#include " qgsfeature.h"
3938#include " qgsfield.h"
4039#include " qgsrect.h"
41-
40+ #include " qgis.h"
41+ #include " qgsmessageviewer.h"
4242
4343#ifdef WIN32
4444#define QGISEXTERN extern " C" __declspec( dllexport )
@@ -54,7 +54,8 @@ static const QString TEXT_PROVIDER_DESCRIPTION = "Delimited text data provider";
5454
5555QgsDelimitedTextProvider::QgsDelimitedTextProvider (QString const &uri)
5656 : QgsVectorDataProvider(uri),
57- mMinMaxCacheDirty(true )
57+ mMinMaxCacheDirty(true ),
58+ mShowInvalidLines(true )
5859{
5960 // Get the file name and mDelimiter out of the uri
6061 mFileName = uri.left (uri.find (" ?" ));
@@ -99,7 +100,7 @@ QgsDelimitedTextProvider::QgsDelimitedTextProvider(QString const &uri)
99100 mFile = new QFile (mFileName );
100101 if (mFile ->open (QIODevice::ReadOnly))
101102 {
102- QTextStream stream (mFile );
103+ mStream = new QTextStream (mFile );
103104 QString line;
104105 mNumberFeatures = 0 ;
105106 int xyCount = 0 ;
@@ -108,10 +109,11 @@ QgsDelimitedTextProvider::QgsDelimitedTextProvider(QString const &uri)
108109 mExtent = new QgsRect ();
109110 // commented out by Tim for now - setMinimal needs to be merged in from 0.7 branch
110111 // mExtent->setMinimal(); // This defeats normalization
111- while (!stream.atEnd ())
112+ bool firstPoint = true ;
113+ while (!mStream ->atEnd ())
112114 {
113115 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.
115117 if (mNumberFeatures ++ == 0 )
116118 {
117119 // Get the fields from the header row and store them in the
@@ -124,8 +126,8 @@ QgsDelimitedTextProvider::QgsDelimitedTextProvider(QString const &uri)
124126 QStringList fieldList =
125127 QStringList::split (QRegExp (mDelimiter ), line, true );
126128#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;
129131#endif
130132 // We don't know anything about a text based field other
131133 // than its name. All fields are assumed to be text
@@ -194,23 +196,32 @@ QgsDelimitedTextProvider::QgsDelimitedTextProvider(QString const &uri)
194196 bool yOk = true ;
195197 double x = sX .toDouble (&xOk);
196198 double y = sY .toDouble (&yOk);
199+
197200 if (xOk && yOk)
198201 {
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)
208203 {
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+ }
210220 }
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 ;
214225 }
215226 }
216227 }
@@ -264,6 +275,7 @@ QgsDelimitedTextProvider::~QgsDelimitedTextProvider()
264275{
265276 mFile ->close ();
266277 delete mFile ;
278+ delete mStream ;
267279 for (int i = 0 ; i < fieldCount (); i++)
268280 {
269281 delete mMinMaxCache [i];
@@ -338,13 +350,9 @@ QgsDelimitedTextProvider::getNextFeature_( QgsFeature & feature,
338350 // before we do anything else, assume that there's something wrong with
339351 // the feature
340352 feature.setValid ( false );
341-
342- QTextStream textStream ( mFile );
343-
344- if ( ! textStream.atEnd () )
353+ while ( ! mStream ->atEnd () )
345354 {
346- QString line = textStream.readLine (); // Default local 8 bit encoding
347-
355+ QString line = mStream ->readLine (); // Default local 8 bit encoding
348356 // lex the tokens from the current data line
349357 QStringList tokens = QStringList::split (QRegExp (mDelimiter ), line, true );
350358
@@ -357,62 +365,27 @@ QgsDelimitedTextProvider::getNextFeature_( QgsFeature & feature,
357365 double x = tokens[xFieldPos].toDouble ( &xOk );
358366 double y = tokens[yFieldPos].toDouble ( &yOk );
359367
360- if ( xOk && yOk )
368+ if (! ( xOk && yOk) )
361369 {
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+ }
387375
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 ;
395378
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
398381 feature.setValid ( true );
399382
400383 ++mFid ; // increment to next feature ID
401384
402385 feature.setFeatureId ( mFid );
403386
404- unsigned char * geometry = new unsigned char [sizeof (wkbPoint)];
405387 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
414388 QDataStream s ( &buffer, QIODevice::WriteOnly ); // open on buffers's data
415- #endif
416389
417390 switch ( endian () )
418391 {
@@ -428,20 +401,19 @@ QgsDelimitedTextProvider::getNextFeature_( QgsFeature & feature,
428401 break ;
429402 default :
430403 qDebug ( " %s:%d unknown endian" , __FILE__, __LINE__ );
431- delete [] geometry;
404+ // delete [] geometry;
432405 return false ;
433406 }
434407
435- s << (Q_UINT32)1 ; // 1 is for WKBPoint
408+ s << (Q_UINT32)QGis:: WKBPoint;
436409 s << x;
437410 s << y;
438411
412+ unsigned char * geometry = new unsigned char [buffer.size ()];
413+ memcpy (geometry, buffer.data (), buffer.size ());
439414
440415 feature.setGeometryAndOwnership ( geometry, sizeof (wkbPoint) );
441416
442- // ensure that the buffer doesn't delete the data on us
443- buffer.resetRawData ( (const char *)geometry, sizeof (wkbPoint) );
444-
445417 if ( getAttributes && ! desiredAttributes )
446418 {
447419 for (int fi = 0 ; fi < attributeFields.size (); fi++)
@@ -461,13 +433,25 @@ QgsDelimitedTextProvider::getNextFeature_( QgsFeature & feature,
461433 feature.addAttribute (attributeFields[*i].name (), tokens[*i]);
462434 }
463435 }
464-
436+ // We have a good line, so return
465437 return true ;
466438
467- } // if able to get x and y coordinates
468-
469439 } // ! textStream EOF
470440
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+
471455 return false ;
472456
473457} // getNextFeature_( QgsFeature & feature )
@@ -632,14 +616,12 @@ std::vector<QgsField> const & QgsDelimitedTextProvider::fields() const
632616
633617void QgsDelimitedTextProvider::reset ()
634618{
635- // Reset the file pointer to BOF
636- mFile ->reset ();
637619 // Reset feature id to 0
638620 mFid = 0 ;
639621 // Skip ahead one line since first record is always assumed to be
640622 // the header record
641- QTextStream stream ( mFile );
642- stream. readLine ();
623+ mStream -> seek ( 0 );
624+ mStream -> readLine ();
643625}
644626
645627QString QgsDelimitedTextProvider::minValue (int position)
@@ -837,24 +819,20 @@ bool QgsDelimitedTextProvider::saveAsShapefile()
837819 std::cerr << " Done creating fields" << std::endl;
838820 // read the line
839821 reset ();
840- QTextStream stream (mFile );
841822 QString line;
842- while (!stream. atEnd ())
823+ while (!mStream -> atEnd ())
843824 {
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'
846826 // split the line
847827 QStringList parts =
848828 QStringList::split (QRegExp (mDelimiter ), line, true );
849- std::cerr << " Split line into " << parts.size () << std::endl;
850829
851830 // create the feature
852831 OGRFeature *poFeature;
853832
854833 poFeature = new OGRFeature (poLayer->GetLayerDefn ());
855834
856835 // iterate over the parts and set the fields
857- std::cerr << " Setting the field values" << std::endl;
858836 // set limit - we will ignore extra fields on the line
859837 int limit = attributeFields.size ();
860838
@@ -871,8 +849,6 @@ bool QgsDelimitedTextProvider::saveAsShapefile()
871849 {
872850 if (parts[i] != QString::null)
873851 {
874- std::cerr << " Setting " << i << " " << (const char *)attributeFields[i].
875- name ().toLocal8Bit ().data () << " to " << (const char *)parts[i].toLocal8Bit ().data () << std::endl;
876852 poFeature->SetField (saveCodec->fromUnicode (attributeFields[i].name ()).data (),
877853 saveCodec->fromUnicode (parts[i]).data ());
878854
@@ -958,11 +934,10 @@ int *QgsDelimitedTextProvider::getFieldLengths()
958934 {
959935 reset ();
960936 // read the line
961- QTextStream stream (mFile );
962937 QString line;
963- while (!stream. atEnd ())
938+ while (!mStream -> atEnd ())
964939 {
965- line = stream. readLine (); // line of text excluding '\n'
940+ line = mStream -> readLine (); // line of text excluding '\n'
966941 // split the line
967942 QStringList parts = QStringList::split (QRegExp (mDelimiter ), line, true );
968943 // iterate over the parts and update the max value
0 commit comments