Skip to content

Commit e08418b

Browse files
author
wonder
committedApr 17, 2007
Delimited text provider:
- code cleanups - distinguish between int/double/text field types (#684) git-svn-id: http://svn.osgeo.org/qgis/trunk@6893 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent a4cf54a commit e08418b

File tree

2 files changed

+287
-393
lines changed

2 files changed

+287
-393
lines changed
 

‎src/providers/delimitedtext/qgsdelimitedtextprovider.cpp

Lines changed: 279 additions & 372 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
#include "qgsdelimitedtextprovider.h"
2020

21-
#include <iostream>
2221

2322
#include <QtGlobal>
2423
#include <QFile>
@@ -35,11 +34,11 @@
3534
#include "qgsdataprovider.h"
3635
#include "qgsfeature.h"
3736
#include "qgsfield.h"
37+
#include "qgslogger.h"
3838
#include "qgsmessageoutput.h"
3939
#include "qgsrect.h"
4040
#include "qgsspatialrefsys.h"
4141
#include "qgis.h"
42-
#include "qgslogger.h"
4342

4443
#ifdef WIN32
4544
#define QGISEXTERN extern "C" __declspec( dllexport )
@@ -55,35 +54,34 @@ static const QString TEXT_PROVIDER_DESCRIPTION = "Delimited text data provider";
5554

5655
QgsDelimitedTextProvider::QgsDelimitedTextProvider(QString uri)
5756
: QgsVectorDataProvider(uri),
57+
mXFieldIndex(-1), mYFieldIndex(-1),
5858
mShowInvalidLines(true)
5959
{
6060
// Get the file name and mDelimiter out of the uri
6161
mFileName = uri.left(uri.find("?"));
6262
// split the string up on & to get the individual parameters
6363
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+
6867
// get the individual parameters and assign values
6968
QStringList temp = parameters.grep("delimiter=");
7069
mDelimiter = temp.size()? temp[0].mid(temp[0].find("=") + 1) : "";
7170
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) : "";
7372
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) : "";
7574
// Decode the parts of the uri. Good if someone entered '=' as a delimiter, for instance.
7675
mFileName = QUrl::fromPercentEncoding(mFileName.toUtf8());
7776
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);
8785

8886
// if delimiter contains some special characters, convert them
8987
// (we no longer use delimiter as regexp as it introduces problems with special characters)
@@ -93,186 +91,173 @@ QgsDelimitedTextProvider::QgsDelimitedTextProvider(QString uri)
9391
mSelectionRectangle = QgsRect();
9492
// assume the layer is invalid until proven otherwise
9593
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))
98113
{
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)
101138
{
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)
107151
{
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)
119154
{
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)
123160
{
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;
173163
}
174-
else
164+
else if (yField == *it)
175165
{
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;
237168
}
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++;
238175
}
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);
241186

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)
243206
{
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);
250208
}
251209
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])
252221
{
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]);
256227
}
257228
}
258-
#ifdef QGISDEBUG
259-
std::cerr << "Done checking validity\n";
260-
#endif
261-
262229
}
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+
}
268246

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;
269254
}
270255
else
271256
{
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");
275258
}
259+
QgsDebugMsg("Done checking validity");
260+
276261
}
277262

278263
QgsDelimitedTextProvider::~QgsDelimitedTextProvider()
@@ -289,167 +274,136 @@ QString QgsDelimitedTextProvider::storageType() const
289274
}
290275

291276

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)
301278
{
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())
303296
{
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+
}
307312

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
310316

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;
319320

320-
return to.fpval;
321+
// at this point, one way or another, the current feature values
322+
// are valid
323+
feature.setValid( true );
321324

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 );
339326

340-
bool xOk = false;
341-
bool yOk = false;
327+
QByteArray buffer;
328+
QDataStream s( &buffer, QIODevice::WriteOnly ); // open on buffers's data
342329

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+
}
346347

347-
int xFieldPos = fieldPositions[mXField];
348-
int yFieldPos = fieldPositions[mYField];
348+
s << (Q_UINT32)QGis::WKBPoint;
349+
s << x;
350+
s << y;
349351

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());
352354

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) );
365356

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 )
428360
{
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+
}
438376

439-
output->showMessage();
377+
// We have a good line, so return
378+
return true;
379+
380+
} // ! textStream EOF
440381

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.
444384

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+
}
446402

447-
} // getNextFeature_( QgsFeature & feature )
403+
return false;
404+
405+
} // getNextFeature
448406

449-
bool QgsDelimitedTextProvider::getNextFeature(QgsFeature& feature)
450-
{
451-
return getNextFeature_(feature, mAttributesToFetch);
452-
}
453407

454408
void QgsDelimitedTextProvider::select(QgsAttributeList fetchAttributes,
455409
QgsRect rect,
@@ -476,8 +430,7 @@ void QgsDelimitedTextProvider::select(QgsAttributeList fetchAttributes,
476430
// Return the extent of the layer
477431
QgsRect QgsDelimitedTextProvider::extent()
478432
{
479-
return QgsRect(mExtent.xMin(), mExtent.yMin(), mExtent.xMax(),
480-
mExtent.yMax());
433+
return mExtent;
481434
}
482435

483436
/**
@@ -530,17 +483,12 @@ bool QgsDelimitedTextProvider::isValid()
530483
*/
531484
bool QgsDelimitedTextProvider::boundsCheck(double x, double y)
532485
{
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());
544492
}
545493

546494
int QgsDelimitedTextProvider::capabilities() const
@@ -549,47 +497,6 @@ int QgsDelimitedTextProvider::capabilities() const
549497
}
550498

551499

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-
593500
QgsSpatialRefSys QgsDelimitedTextProvider::getSRS()
594501
{
595502
// TODO: make provider projection-aware

‎src/providers/delimitedtext/qgsdelimitedtextprovider.h

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ class QgsDelimitedTextProvider : public QgsVectorDataProvider
7474
* Get the next feature resulting from a select operation.
7575
* @param feature feature which will receive data from the provider
7676
* @return true when there was a feature to fetch, false when end was hit
77+
*
78+
* mFile should be open with the file pointer at the record of the next
79+
* feature, or EOF. The feature found on the current line is parsed.
7780
*/
7881
virtual bool getNextFeature(QgsFeature& feature);
7982

@@ -169,32 +172,16 @@ class QgsDelimitedTextProvider : public QgsVectorDataProvider
169172

170173
private:
171174

172-
/** get the next feature, if any
173-
174-
mFile should be open with the file pointer at the record of the next
175-
feature, or EOF. The feature found on the current line is parsed.
176-
177-
@param feature the feature object to be populated with next feature
178-
179-
@param desiredAttributes attributes fields to be collected for the feature
180-
as denoted by their position
181-
182-
@return false if unable to get the next feature
183-
*/
184-
bool getNextFeature_( QgsFeature & feature, QgsAttributeList desiredAttributes);
185-
186-
int *getFieldLengths();
187-
188175
//! Fields
189176
QgsFieldMap attributeFields;
190-
191-
//! Map to store field position by name
192-
std::map < QString, int >fieldPositions;
177+
178+
QgsAttributeList mAttributesToFetch;
193179

194180
QString mFileName;
195181
QString mDelimiter;
196-
QString mXField;
197-
QString mYField;
182+
183+
int mXFieldIndex;
184+
int mYFieldIndex;
198185

199186
//! Layer extent
200187
QgsRect mExtent;

0 commit comments

Comments
 (0)
Please sign in to comment.