18
18
19
19
#include " qgsdelimitedtextprovider.h"
20
20
21
- #include < iostream>
22
21
23
22
#include < QtGlobal>
24
23
#include < QFile>
35
34
#include " qgsdataprovider.h"
36
35
#include " qgsfeature.h"
37
36
#include " qgsfield.h"
37
+ #include " qgslogger.h"
38
38
#include " qgsmessageoutput.h"
39
39
#include " qgsrect.h"
40
40
#include " qgsspatialrefsys.h"
41
41
#include " qgis.h"
42
- #include " qgslogger.h"
43
42
44
43
#ifdef WIN32
45
44
#define QGISEXTERN extern " C" __declspec( dllexport )
@@ -55,35 +54,34 @@ static const QString TEXT_PROVIDER_DESCRIPTION = "Delimited text data provider";
55
54
56
55
QgsDelimitedTextProvider::QgsDelimitedTextProvider (QString uri)
57
56
: QgsVectorDataProvider(uri),
57
+ mXFieldIndex(-1 ), mYFieldIndex(-1 ),
58
58
mShowInvalidLines(true )
59
59
{
60
60
// Get the file name and mDelimiter out of the uri
61
61
mFileName = uri.left (uri.find (" ?" ));
62
62
// split the string up on & to get the individual parameters
63
63
QStringList parameters = QStringList::split (" &" , uri.mid (uri.find (" ?" )));
64
- #ifdef QGISDEBUG
65
- std::cerr << " Parameter count after split on &" << parameters.
66
- size () << std::endl;
67
- #endif
64
+
65
+ QgsDebugMsg (" Parameter count after split on &" + QString::number (parameters.size ()));
66
+
68
67
// get the individual parameters and assign values
69
68
QStringList temp = parameters.grep (" delimiter=" );
70
69
mDelimiter = temp.size ()? temp[0 ].mid (temp[0 ].find (" =" ) + 1 ) : " " ;
71
70
temp = parameters.grep (" xField=" );
72
- mXField = temp.size ()? temp[0 ].mid (temp[0 ].find (" =" ) + 1 ) : " " ;
71
+ QString xField = temp.size ()? temp[0 ].mid (temp[0 ].find (" =" ) + 1 ) : " " ;
73
72
temp = parameters.grep (" yField=" );
74
- mYField = temp.size ()? temp[0 ].mid (temp[0 ].find (" =" ) + 1 ) : " " ;
73
+ QString yField = temp.size ()? temp[0 ].mid (temp[0 ].find (" =" ) + 1 ) : " " ;
75
74
// Decode the parts of the uri. Good if someone entered '=' as a delimiter, for instance.
76
75
mFileName = QUrl::fromPercentEncoding (mFileName .toUtf8 ());
77
76
mDelimiter = QUrl::fromPercentEncoding (mDelimiter .toUtf8 ());
78
- mXField = QUrl::fromPercentEncoding (mXField .toUtf8 ());
79
- mYField = QUrl::fromPercentEncoding (mYField .toUtf8 ());
80
- #ifdef QGISDEBUG
81
- std::cerr << " Data source uri is " << (const char *)uri.toLocal8Bit ().data () << std::endl;
82
- std::cerr << " Delimited text file is: " << (const char *)mFileName .toLocal8Bit ().data () << std::endl;
83
- std::cerr << " Delimiter is: " << (const char *)mDelimiter .toLocal8Bit ().data () << std::endl;
84
- std::cerr << " xField is: " << (const char *)mXField .toLocal8Bit ().data () << std::endl;
85
- std::cerr << " yField is: " << (const char *)mYField .toLocal8Bit ().data () << std::endl;
86
- #endif
77
+ xField = QUrl::fromPercentEncoding (xField.toUtf8 ());
78
+ yField = QUrl::fromPercentEncoding (yField.toUtf8 ());
79
+
80
+ QgsDebugMsg (" Data source uri is " + uri);
81
+ QgsDebugMsg (" Delimited text file is: " + mFileName );
82
+ QgsDebugMsg (" Delimiter is: " + mDelimiter );
83
+ QgsDebugMsg (" xField is: " + xField);
84
+ QgsDebugMsg (" yField is: " + yField);
87
85
88
86
// if delimiter contains some special characters, convert them
89
87
// (we no longer use delimiter as regexp as it introduces problems with special characters)
@@ -93,186 +91,173 @@ QgsDelimitedTextProvider::QgsDelimitedTextProvider(QString uri)
93
91
mSelectionRectangle = QgsRect ();
94
92
// assume the layer is invalid until proven otherwise
95
93
mValid = false ;
96
- if (!mFileName .isEmpty () && !mDelimiter .isEmpty () && !mXField .isEmpty () &&
97
- !mYField .isEmpty ())
94
+ if (mFileName .isEmpty () || mDelimiter .isEmpty () || xField.isEmpty () || yField.isEmpty ())
95
+ {
96
+ // uri is invalid so the layer must be too...
97
+ QString (" Data source is invalid" );
98
+ return ;
99
+ }
100
+
101
+ // check to see that the file exists and perform some sanity checks
102
+ if (!QFile::exists (mFileName ))
103
+ {
104
+ QgsDebugMsg (" Data source " + dataSourceUri () + " doesn't exist" );
105
+ return ;
106
+ }
107
+
108
+ // Open the file and get number of rows, etc. We assume that the
109
+ // file has a header row and process accordingly. Caller should make
110
+ // sure the the delimited file is properly formed.
111
+ mFile = new QFile (mFileName );
112
+ if (!mFile ->open (QIODevice::ReadOnly))
98
113
{
99
- // check to see that the file exists and perform some sanity checks
100
- if (QFile::exists (mFileName ))
114
+ QgsDebugMsg (" Data source " + dataSourceUri () + " could not be opened" );
115
+ delete mFile ;
116
+ return ;
117
+ }
118
+
119
+ // now we have the file opened and ready for parsing
120
+
121
+ // set the initial extent
122
+ mExtent = QgsRect ();
123
+
124
+ QMap<int , bool > couldBeInt;
125
+ QMap<int , bool > couldBeDouble;
126
+
127
+ mStream = new QTextStream (mFile );
128
+ QString line;
129
+ mNumberFeatures = 0 ;
130
+ int lineNumber = 0 ;
131
+ bool firstPoint = true ;
132
+ bool hasFields = false ;
133
+ while (!mStream ->atEnd ())
134
+ {
135
+ lineNumber++;
136
+ line = mStream ->readLine (); // line of text excluding '\n', default local 8 bit encoding.
137
+ if (!hasFields)
101
138
{
102
- // Open the file and get number of rows, etc. We assume that the
103
- // file has a header row and process accordingly. Caller should make
104
- // sure the the delimited file is properly formed.
105
- mFile = new QFile (mFileName );
106
- if (mFile ->open (QIODevice::ReadOnly))
139
+ // Get the fields from the header row and store them in the
140
+ // fields vector
141
+ QgsDebugMsg (" Attempting to split the input line: " + line + " using delimiter " + mDelimiter );
142
+
143
+ QStringList fieldList = QStringList::split (mDelimiter , line, true );
144
+ QgsDebugMsg (" Split line into " + QString::number (fieldList.size ()) + " parts" );
145
+
146
+ // We don't know anything about a text based field other
147
+ // than its name. All fields are assumed to be text
148
+ int fieldPos = 0 ;
149
+ for (QStringList::Iterator it = fieldList.begin ();
150
+ it != fieldList.end (); ++it)
107
151
{
108
- mStream = new QTextStream (mFile );
109
- QString line;
110
- mNumberFeatures = 0 ;
111
- int xyCount = 0 ;
112
- int lineNumber = 0 ;
113
- // set the initial extent
114
- mExtent = QgsRect ();
115
- // commented out by Tim for now - setMinimal needs to be merged in from 0.7 branch
116
- // mExtent->setMinimal(); // This defeats normalization
117
- bool firstPoint = true ;
118
- while (!mStream ->atEnd ())
152
+ QString field = *it;
153
+ if (field.length () > 0 )
119
154
{
120
- lineNumber++;
121
- line = mStream ->readLine (); // line of text excluding '\n', default local 8 bit encoding.
122
- if (mNumberFeatures ++ == 0 )
155
+ // for now, let's set field type as text
156
+ attributeFields[fieldPos] = QgsField (*it, QVariant::String, " Text" );
157
+
158
+ // check to see if this field matches either the x or y field
159
+ if (xField == *it)
123
160
{
124
- // Get the fields from the header row and store them in the
125
- // fields vector
126
- #ifdef QGISDEBUG
127
- std::
128
- cerr << " Attempting to split the input line: " << (const char *)line.toLocal8Bit ().data () <<
129
- " using delimiter " << (const char *)mDelimiter .toLocal8Bit ().data () << std::endl;
130
- #endif
131
- QStringList fieldList = QStringList::split (mDelimiter , line, true );
132
- #ifdef QGISDEBUG
133
- std::cerr << " Split line into "
134
- << fieldList.size () << " parts" << std::endl;
135
- #endif
136
- // We don't know anything about a text based field other
137
- // than its name. All fields are assumed to be text
138
- int fieldPos = 0 ;
139
- for (QStringList::Iterator it = fieldList.begin ();
140
- it != fieldList.end (); ++it)
141
- {
142
- QString field = *it;
143
- if (field.length () > 0 )
144
- {
145
- attributeFields[fieldPos] = QgsField (*it, QVariant::String, " Text" );
146
- fieldPositions[*it] = fieldPos++;
147
- // check to see if this field matches either the x or y field
148
- if (mXField == *it)
149
- {
150
- #ifdef QGISDEBUG
151
- std::cerr << " Found x field " << (const char *)(*it).toLocal8Bit ().data () << std::endl;
152
- #endif
153
- xyCount++;
154
- }
155
- if (mYField == *it)
156
- {
157
- #ifdef QGISDEBUG
158
- std::cerr << " Found y field " << (const char *)(*it).toLocal8Bit ().data () << std::endl;
159
- #endif
160
- xyCount++;
161
- }
162
- #ifdef QGISDEBUG
163
- std::cerr << " Adding field: " << (const char *)(*it).toLocal8Bit ().data () << std::endl;
164
- #endif
165
-
166
- }
167
- }
168
- #ifdef QGISDEBUG
169
- std::
170
- cerr << " Field count for the delimited text file is " <<
171
- attributeFields.size () << std::endl;
172
- #endif
161
+ QgsDebugMsg (" Found x field: " + (*it));
162
+ mXFieldIndex = fieldPos;
173
163
}
174
- else
164
+ else if (yField == *it)
175
165
{
176
- // examine the x,y and update extents
177
- // std::cout << line << std::endl;
178
- // split the line on the delimiter
179
- QStringList parts =
180
- QStringList::split (mDelimiter , line, true );
181
-
182
- // Skip malformed lines silently. Report line number with getNextFeature()
183
- if ( (parts.size () <= fieldPositions[mXField ]) || (parts.size () <= fieldPositions[mYField ]) )
184
- {
185
- continue ;
186
- }
187
- // if(parts.size() == attributeFields.size())
188
- // {
189
- // // we can populate attributes if required
190
- // fieldsMatch = true;
191
- // }else
192
- // {
193
- // fieldsMatch = false;
194
- // }
195
- /*
196
- std::cout << "Record hit line " << lineNumber << ": " <<
197
- parts[fieldPositions[mXField]] << ", " <<
198
- parts[fieldPositions[mYField]] << std::endl;
199
- */
200
- // Get the x and y values, first checking to make sure they
201
- // aren't null.
202
- QString sX = parts[fieldPositions[mXField ]];
203
- QString sY = parts[fieldPositions[mYField ]];
204
- // std::cout << "x ,y " << sX << ", " << sY << std::endl;
205
- bool xOk = true ;
206
- bool yOk = true ;
207
- double x = sX .toDouble (&xOk);
208
- double y = sY .toDouble (&yOk);
209
-
210
- if (xOk && yOk)
211
- {
212
- if (!firstPoint)
213
- {
214
- if (x > mExtent .xMax ())
215
- {
216
- mExtent .setXmax (x);
217
- }
218
- if (x < mExtent .xMin ())
219
- {
220
- mExtent .setXmin (x);
221
- }
222
- if (y > mExtent .yMax ())
223
- {
224
- mExtent .setYmax (y);
225
- }
226
- if (y < mExtent .yMin ())
227
- {
228
- mExtent .setYmin (y);
229
- }
230
- }
231
- else
232
- { // Extent for the first point is just the first point
233
- mExtent .set (x,y,x,y);
234
- firstPoint = false ;
235
- }
236
- }
166
+ QgsDebugMsg (" Found y field: " + (*it));
167
+ mYFieldIndex = fieldPos;
237
168
}
169
+
170
+ QgsDebugMsg (" Adding field: " + (*it));
171
+ // assume that the field could be integer or double
172
+ couldBeInt.insert (fieldPos, true );
173
+ couldBeDouble.insert (fieldPos, true );
174
+ fieldPos++;
238
175
}
239
- reset ();
240
- mNumberFeatures --;
176
+ }
177
+ QgsDebugMsg (" Field count for the delimited text file is " + QString::number (attributeFields.size ()));
178
+ hasFields = true ;
179
+ }
180
+ else
181
+ {
182
+ mNumberFeatures ++;
183
+
184
+ // split the line on the delimiter
185
+ QStringList parts = QStringList::split (mDelimiter , line, true );
241
186
242
- if (xyCount == 2 )
187
+ // Skip malformed lines silently. Report line number with getNextFeature()
188
+ if (attributeFields.size () != parts.size ())
189
+ {
190
+ continue ;
191
+ }
192
+
193
+ // Get the x and y values, first checking to make sure they
194
+ // aren't null.
195
+ QString sX = parts[mXFieldIndex ];
196
+ QString sY = parts[mYFieldIndex ];
197
+
198
+ bool xOk = true ;
199
+ bool yOk = true ;
200
+ double x = sX .toDouble (&xOk);
201
+ double y = sY .toDouble (&yOk);
202
+
203
+ if (xOk && yOk)
204
+ {
205
+ if (!firstPoint)
243
206
{
244
- #ifdef QGISDEBUG
245
- std::cerr << " Data store is valid" << std::endl;
246
- std::cerr << " Number of features " << mNumberFeatures << std::endl;
247
- std::cerr << " Extents " << (const char *)mExtent .stringRep ().toLocal8Bit ().data () << std::endl;
248
- #endif
249
- mValid = true ;
207
+ mExtent .combineExtentWith (x,y);
250
208
}
251
209
else
210
+ { // Extent for the first point is just the first point
211
+ mExtent .set (x,y,x,y);
212
+ firstPoint = false ;
213
+ }
214
+ }
215
+
216
+ int i = 0 ;
217
+ for (QStringList::iterator it = parts.begin (); it != parts.end (); ++it, ++i)
218
+ {
219
+ // try to convert attribute values to integer and double
220
+ if (couldBeInt[i])
252
221
{
253
- std::
254
- cerr << " Data store is invalid. Specified x,y fields do not match\n "
255
- << " those in the database (xyCount=" << xyCount << " )" << std::endl;
222
+ it->toInt (&couldBeInt[i]);
223
+ }
224
+ if (couldBeDouble[i])
225
+ {
226
+ it->toDouble (&couldBeDouble[i]);
256
227
}
257
228
}
258
- #ifdef QGISDEBUG
259
- std::cerr << " Done checking validity\n " ;
260
- #endif
261
-
262
229
}
263
- else
264
- // file does not exist
265
- std::
266
- cerr << " Data source " << (const char *)dataSourceUri ().toLocal8Bit ().data () << " could not be opened" <<
267
- std::endl;
230
+ }
231
+
232
+ // now it's time to decide the types for the fields
233
+ for (QgsFieldMap::iterator it = attributeFields.begin (); it != attributeFields.end (); ++it)
234
+ {
235
+ if (couldBeInt[it.key ()])
236
+ {
237
+ it->setType (QVariant::Int);
238
+ it->setTypeName (" integer" );
239
+ }
240
+ else if (couldBeDouble[it.key ()])
241
+ {
242
+ it->setType (QVariant::Double);
243
+ it->setTypeName (" double" );
244
+ }
245
+ }
268
246
247
+ if (mXFieldIndex != -1 && mYFieldIndex != -1 )
248
+ {
249
+ QgsDebugMsg (" Data store is valid" );
250
+ QgsDebugMsg (" Number of features " + QString::number (mNumberFeatures ));
251
+ QgsDebugMsg (" Extents " + mExtent .stringRep ());
252
+
253
+ mValid = true ;
269
254
}
270
255
else
271
256
{
272
- // uri is invalid so the layer must be too...
273
- std::cerr << " Data source is invalid" << std::endl;
274
-
257
+ QgsDebugMsg (" Data store is invalid. Specified x,y fields do not match those in the database" );
275
258
}
259
+ QgsDebugMsg (" Done checking validity" );
260
+
276
261
}
277
262
278
263
QgsDelimitedTextProvider::~QgsDelimitedTextProvider ()
@@ -289,167 +274,136 @@ QString QgsDelimitedTextProvider::storageType() const
289
274
}
290
275
291
276
292
- /* *
293
-
294
- insure double value is properly translated into locate endian-ness
295
-
296
- */
297
- /*
298
- static
299
- double
300
- translateDouble_( double d )
277
+ bool QgsDelimitedTextProvider::getNextFeature (QgsFeature& feature)
301
278
{
302
- union
279
+ // before we do anything else, assume that there's something wrong with
280
+ // the feature
281
+ feature.setValid ( false );
282
+ while ( ! mStream ->atEnd () )
283
+ {
284
+ double x = 0.0 ;
285
+ double y = 0.0 ;
286
+ QString line = mStream ->readLine (); // Default local 8 bit encoding
287
+
288
+ // lex the tokens from the current data line
289
+ QStringList tokens = QStringList::split (mDelimiter , line, true );
290
+
291
+ bool xOk = false ;
292
+ bool yOk = false ;
293
+
294
+ // Skip indexing malformed lines.
295
+ if (attributeFields.size () == tokens.size ())
303
296
{
304
- double fpval;
305
- char char_val[8];
306
- } from, to;
297
+ x = tokens[mXFieldIndex ].toDouble ( &xOk );
298
+ y = tokens[mYFieldIndex ].toDouble ( &yOk );
299
+ }
300
+
301
+ if (! (xOk && yOk))
302
+ {
303
+ // Accumulate any lines that weren't ok, to report on them
304
+ // later, and look at the next line in the file, but only if
305
+ // we need to.
306
+ QgsDebugMsg (" Malformed line : " + line);
307
+ if (mShowInvalidLines )
308
+ mInvalidLines << line;
309
+
310
+ continue ;
311
+ }
307
312
308
- // break double into byte sized chunks
309
- from.fpval = d;
313
+ // Give every valid line in the file an id, even if it's not
314
+ // in the current extent or bounds.
315
+ ++mFid ; // increment to next feature ID
310
316
311
- to.char_val[7] = from.char_val[0];
312
- to.char_val[6] = from.char_val[1];
313
- to.char_val[5] = from.char_val[2];
314
- to.char_val[4] = from.char_val[3];
315
- to.char_val[3] = from.char_val[4];
316
- to.char_val[2] = from.char_val[5];
317
- to.char_val[1] = from.char_val[6];
318
- to.char_val[0] = from.char_val[7];
317
+ // skip the feature if it's out of current bounds
318
+ if (! boundsCheck (x,y))
319
+ continue ;
319
320
320
- return to.fpval;
321
+ // at this point, one way or another, the current feature values
322
+ // are valid
323
+ feature.setValid ( true );
321
324
322
- } // translateDouble_
323
- */
324
-
325
- bool
326
- QgsDelimitedTextProvider::getNextFeature_ ( QgsFeature & feature,
327
- QgsAttributeList desiredAttributes )
328
- {
329
- // before we do anything else, assume that there's something wrong with
330
- // the feature
331
- feature.setValid ( false );
332
- while ( ! mStream ->atEnd () )
333
- {
334
- double x = 0.0 ;
335
- double y = 0.0 ;
336
- QString line = mStream ->readLine (); // Default local 8 bit encoding
337
- // lex the tokens from the current data line
338
- QStringList tokens = QStringList::split (mDelimiter , line, true );
325
+ feature.setFeatureId ( mFid );
339
326
340
- bool xOk = false ;
341
- bool yOk = false ;
327
+ QByteArray buffer ;
328
+ QDataStream s ( &buffer, QIODevice::WriteOnly ); // open on buffers's data
342
329
343
- // Skip indexing malformed lines.
344
- if ( ! ((tokens.size () <= fieldPositions[mXField ]) || (tokens.size () <= fieldPositions[mXField ])) )
345
- {
330
+ switch ( QgsApplication::endian () )
331
+ {
332
+ case QgsApplication::NDR :
333
+ // we're on a little-endian platform, so tell the data
334
+ // stream to use that
335
+ s.setByteOrder ( QDataStream::LittleEndian );
336
+ s << (Q_UINT8)1 ; // 1 is for little-endian
337
+ break ;
338
+ case QgsApplication::XDR :
339
+ // don't change byte order since QDataStream is big endian by default
340
+ s << (Q_UINT8)0 ; // 0 is for big-endian
341
+ break ;
342
+ default :
343
+ qDebug ( " %s:%d unknown endian" , __FILE__, __LINE__ );
344
+ // delete [] geometry;
345
+ return false ;
346
+ }
346
347
347
- int xFieldPos = fieldPositions[mXField ];
348
- int yFieldPos = fieldPositions[mYField ];
348
+ s << (Q_UINT32)QGis::WKBPoint;
349
+ s << x;
350
+ s << y;
349
351
350
- x = tokens[xFieldPos]. toDouble ( &xOk ) ;
351
- y = tokens[yFieldPos]. toDouble ( &yOk );
352
+ unsigned char * geometry = new unsigned char [buffer. size ()] ;
353
+ memcpy (geometry, buffer. data (), buffer. size () );
352
354
353
- }
354
- if (! (xOk && yOk))
355
- {
356
- // Accumulate any lines that weren't ok, to report on them
357
- // later, and look at the next line in the file, but only if
358
- // we need to.
359
- QgsDebugMsg (" Malformed line : " + line);
360
- if (mShowInvalidLines )
361
- mInvalidLines << line;
362
-
363
- continue ;
364
- }
355
+ feature.setGeometryAndOwnership ( geometry, sizeof (wkbPoint) );
365
356
366
- // Give every valid line in the file an id, even if it's not
367
- // in the current extent or bounds.
368
- ++mFid ; // increment to next feature ID
369
-
370
- if (! boundsCheck (x,y))
371
- continue ;
372
-
373
- // at this point, one way or another, the current feature values
374
- // are valid
375
- feature.setValid ( true );
376
-
377
- feature.setFeatureId ( mFid );
378
-
379
- QByteArray buffer;
380
- QDataStream s ( &buffer, QIODevice::WriteOnly ); // open on buffers's data
381
-
382
- switch ( QgsApplication::endian () )
383
- {
384
- case QgsApplication::NDR :
385
- // we're on a little-endian platform, so tell the data
386
- // stream to use that
387
- s.setByteOrder ( QDataStream::LittleEndian );
388
- s << (Q_UINT8)1 ; // 1 is for little-endian
389
- break ;
390
- case QgsApplication::XDR :
391
- // don't change byte order since QDataStream is big endian by default
392
- s << (Q_UINT8)0 ; // 0 is for big-endian
393
- break ;
394
- default :
395
- qDebug ( " %s:%d unknown endian" , __FILE__, __LINE__ );
396
- // delete [] geometry;
397
- return false ;
398
- }
399
-
400
- s << (Q_UINT32)QGis::WKBPoint;
401
- s << x;
402
- s << y;
403
-
404
- unsigned char * geometry = new unsigned char [buffer.size ()];
405
- memcpy (geometry, buffer.data (), buffer.size ());
406
-
407
- feature.setGeometryAndOwnership ( geometry, sizeof (wkbPoint) );
408
-
409
- if ( desiredAttributes.size () > 0 )
410
- {
411
- for ( QgsAttributeList::const_iterator i = desiredAttributes.begin ();
412
- i != desiredAttributes.end ();
413
- ++i )
414
- {
415
- feature.addAttribute (*i, QVariant (tokens[*i]) );
416
- }
417
- }
418
-
419
- // We have a good line, so return
420
- return true ;
421
-
422
- } // ! textStream EOF
423
-
424
- // End of the file. If there are any lines that couldn't be
425
- // loaded, display them now.
426
-
427
- if (mShowInvalidLines && !mInvalidLines .isEmpty ())
357
+ for ( QgsAttributeList::const_iterator i = mAttributesToFetch .begin ();
358
+ i != mAttributesToFetch .end ();
359
+ ++i )
428
360
{
429
- mShowInvalidLines = false ;
430
- QgsMessageOutput* output = QgsMessageOutput::createMessageOutput ();
431
- output->setTitle (tr (" Error" ));
432
- output->setMessage (tr (" Note: the following lines were not loaded because Qgis was "
433
- " unable to determine values for the x and y coordinates:\n " ),
434
- QgsMessageOutput::MessageText);
435
-
436
- for (int i = 0 ; i < mInvalidLines .size (); ++i)
437
- output->appendMessage (mInvalidLines .at (i));
361
+ QVariant val;
362
+ switch (attributeFields[*i].type ())
363
+ {
364
+ case QVariant::Int:
365
+ val = QVariant (tokens[*i].toInt ());
366
+ break ;
367
+ case QVariant::Double:
368
+ val = QVariant (tokens[*i].toDouble ());
369
+ break ;
370
+ default :
371
+ val = QVariant (tokens[*i]);
372
+ break ;
373
+ }
374
+ feature.addAttribute (*i, val);
375
+ }
438
376
439
- output->showMessage ();
377
+ // We have a good line, so return
378
+ return true ;
379
+
380
+ } // ! textStream EOF
440
381
441
- // We no longer need these lines.
442
- mInvalidLines .empty ();
443
- }
382
+ // End of the file. If there are any lines that couldn't be
383
+ // loaded, display them now.
444
384
445
- return false ;
385
+ if (mShowInvalidLines && !mInvalidLines .isEmpty ())
386
+ {
387
+ mShowInvalidLines = false ;
388
+ QgsMessageOutput* output = QgsMessageOutput::createMessageOutput ();
389
+ output->setTitle (tr (" Error" ));
390
+ output->setMessage (tr (" Note: the following lines were not loaded because Qgis was "
391
+ " unable to determine values for the x and y coordinates:\n " ),
392
+ QgsMessageOutput::MessageText);
393
+
394
+ for (int i = 0 ; i < mInvalidLines .size (); ++i)
395
+ output->appendMessage (mInvalidLines .at (i));
396
+
397
+ output->showMessage ();
398
+
399
+ // We no longer need these lines.
400
+ mInvalidLines .empty ();
401
+ }
446
402
447
- } // getNextFeature_( QgsFeature & feature )
403
+ return false ;
404
+
405
+ } // getNextFeature
448
406
449
- bool QgsDelimitedTextProvider::getNextFeature (QgsFeature& feature)
450
- {
451
- return getNextFeature_ (feature, mAttributesToFetch );
452
- }
453
407
454
408
void QgsDelimitedTextProvider::select (QgsAttributeList fetchAttributes,
455
409
QgsRect rect,
@@ -476,8 +430,7 @@ void QgsDelimitedTextProvider::select(QgsAttributeList fetchAttributes,
476
430
// Return the extent of the layer
477
431
QgsRect QgsDelimitedTextProvider::extent ()
478
432
{
479
- return QgsRect (mExtent .xMin (), mExtent .yMin (), mExtent .xMax (),
480
- mExtent .yMax ());
433
+ return mExtent ;
481
434
}
482
435
483
436
/* *
@@ -530,17 +483,12 @@ bool QgsDelimitedTextProvider::isValid()
530
483
*/
531
484
bool QgsDelimitedTextProvider::boundsCheck (double x, double y)
532
485
{
533
- bool inBounds (true );
534
- if (!mSelectionRectangle .isEmpty ())
535
- inBounds = (((x <= mSelectionRectangle .xMax ()) &&
536
- (x >= mSelectionRectangle .xMin ())) &&
537
- ((y <= mSelectionRectangle .yMax ()) &&
538
- (y >= mSelectionRectangle .yMin ())));
539
- // QString hit = inBounds?"true":"false";
540
-
541
- // std::cerr << "Checking if " << x << ", " << y << " is in " <<
542
- // mSelectionRectangle->stringRep().ascii() << ": " << hit.ascii() << std::endl;
543
- return inBounds;
486
+ // no selection rectangle => always in the bounds
487
+ if (mSelectionRectangle .isEmpty ())
488
+ return true ;
489
+
490
+ return (x <= mSelectionRectangle .xMax ()) && (x >= mSelectionRectangle .xMin ()) &&
491
+ (y <= mSelectionRectangle .yMax ()) && (y >= mSelectionRectangle .yMin ());
544
492
}
545
493
546
494
int QgsDelimitedTextProvider::capabilities () const
@@ -549,47 +497,6 @@ int QgsDelimitedTextProvider::capabilities() const
549
497
}
550
498
551
499
552
- int *QgsDelimitedTextProvider::getFieldLengths ()
553
- {
554
- // this function parses the entire data file and calculates the
555
- // max for each
556
-
557
- // Only do this if we haven't done it already (ie. the vector is
558
- // empty)
559
- int *lengths = new int [attributeFields.size ()];
560
- // init the lengths to zero
561
- for (int il = 0 ; il < attributeFields.size (); il++)
562
- {
563
- lengths[il] = 0 ;
564
- }
565
- if (mValid )
566
- {
567
- reset ();
568
- // read the line
569
- QString line;
570
- while (!mStream ->atEnd ())
571
- {
572
- line = mStream ->readLine (); // line of text excluding '\n'
573
- // split the line
574
- QStringList parts = QStringList::split (mDelimiter , line, true );
575
- // iterate over the parts and update the max value
576
- for (int i = 0 ; i < parts.size (); i++)
577
- {
578
- if (parts[i] != QString::null)
579
- {
580
- // std::cerr << "comparing length for " << parts[i] << " against max len of " << lengths[i] << std::endl;
581
- if (parts[i].length () > lengths[i])
582
- {
583
- lengths[i] = parts[i].length ();
584
- }
585
- }
586
-
587
- }
588
- }
589
- }
590
- return lengths;
591
- }
592
-
593
500
QgsSpatialRefSys QgsDelimitedTextProvider::getSRS ()
594
501
{
595
502
// TODO: make provider projection-aware
0 commit comments