Skip to content

Commit

Permalink
- Fixed reading of text file (ticket #203). Seemed to be a problem wi…
Browse files Browse the repository at this point in the history
…th a

  combination of QFile and QTextStream which worked under Qt3, but not
  under Qt4
- fixed generation of wkb version of delimited text geometry. Again,
  it appeared to be a problem with code that worked under qt3, but
  not under qt4.
- corrected the calculation of the bounding rectangle for delimited
  text layers (was always including the (0,0) point).
- Bonus features: 
  - a default layer name is constructed from the filename
  - the user is told about lines that didn't yield x/y coords


git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@5698 c8812cc2-4d05-0410-92ff-de0c093fc19c
  • Loading branch information
g_j_m committed Aug 15, 2006
1 parent ef6e0dc commit 6e84284
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 107 deletions.
1 change: 1 addition & 0 deletions src/core/qgsgeometry.cpp
Expand Up @@ -2116,6 +2116,7 @@ bool QgsGeometry::exportToWkt(unsigned char * geom) const
double *x,*y;

mWkt="";
// Will this really work when geom[0] == 0 ???? I (gavin) think not.
wkbType = (geom[0] == 1) ? geom[1] : geom[4];
switch (wkbType)
{
Expand Down
3 changes: 0 additions & 3 deletions src/plugins/delimited_text/qgsdelimitedtextplugin.cpp
Expand Up @@ -134,9 +134,6 @@ void QgsDelimitedTextPlugin::run()
void QgsDelimitedTextPlugin::drawVectorLayer(QString thePathNameQString,
QString theBaseNameQString, QString theProviderQString)
{
std::cerr << "Calling addVectorLayer with:"
<< thePathNameQString.toLocal8Bit().data() << ", " << theBaseNameQString.toLocal8Bit().data()
<< ", " << theProviderQString.toLocal8Bit().data() << std::endl;
qGisInterface->addVectorLayer( thePathNameQString,
theBaseNameQString, theProviderQString);
}
Expand Down
5 changes: 4 additions & 1 deletion src/plugins/delimited_text/qgsdelimitedtextplugingui.cpp
Expand Up @@ -70,7 +70,7 @@ void QgsDelimitedTextPluginGui::on_pbnOK_clicked()
.arg(txtDelimiter->text())
.arg(cmbXField->currentText())
.arg(cmbYField->currentText());
std::cerr << "Adding layer using " << uri.toLocal8Bit().data() << std::endl;

// add the layer to the map
emit drawVectorLayer(uri,txtLayerName->text(),"delimitedtext");
// store the settings
Expand Down Expand Up @@ -150,6 +150,9 @@ void QgsDelimitedTextPluginGui::updateFieldLists()
}
// close the file
file->close();
// put a default layer name in the text entry
QFileInfo finfo(txtFilePath->text());
txtLayerName->setText(finfo.completeBaseName());
}

}
Expand Down
2 changes: 1 addition & 1 deletion src/providers/delimitedtext/Makefile.am
@@ -1,6 +1,6 @@
## $Id$

INCLUDES = -I../../core/ -I../../gui/
INCLUDES = -I../../core/ -I../../gui/ -I../../ui

plugindir = ${pkglibdir}
plugin_LTLIBRARIES = delimitedtextprovider.la
Expand Down
179 changes: 77 additions & 102 deletions src/providers/delimitedtext/qgsdelimitedtextprovider.cpp
Expand Up @@ -21,15 +21,14 @@
#include <cfloat>
#include <iostream>

#include <qfile.h>
#include <qdatastream.h>
#include <qtextstream.h>
#include <qstringlist.h>
#include <qmessagebox.h>
#include <qsettings.h>
#include <qregexp.h>
#include <QFile>
#include <QDataStream>
#include <QTextStream>
#include <QStringList>
#include <QMessageBox>
#include <QSettings>
#include <QRegExp>
#include <q3url.h>
#include <qglobal.h>

#include <ogrsf_frmts.h>

Expand All @@ -38,7 +37,8 @@
#include "qgsfeature.h"
#include "qgsfield.h"
#include "qgsrect.h"

#include "qgis.h"
#include "qgsmessageviewer.h"

#ifdef WIN32
#define QGISEXTERN extern "C" __declspec( dllexport )
Expand All @@ -54,7 +54,8 @@ static const QString TEXT_PROVIDER_DESCRIPTION = "Delimited text data provider";

QgsDelimitedTextProvider::QgsDelimitedTextProvider(QString const &uri)
: QgsVectorDataProvider(uri),
mMinMaxCacheDirty(true)
mMinMaxCacheDirty(true),
mShowInvalidLines(true)
{
// Get the file name and mDelimiter out of the uri
mFileName = uri.left(uri.find("?"));
Expand Down Expand Up @@ -99,7 +100,7 @@ QgsDelimitedTextProvider::QgsDelimitedTextProvider(QString const &uri)
mFile = new QFile(mFileName);
if (mFile->open(QIODevice::ReadOnly))
{
QTextStream stream(mFile);
mStream = new QTextStream(mFile);
QString line;
mNumberFeatures = 0;
int xyCount = 0;
Expand All @@ -108,10 +109,11 @@ QgsDelimitedTextProvider::QgsDelimitedTextProvider(QString const &uri)
mExtent = new QgsRect();
//commented out by Tim for now - setMinimal needs to be merged in from 0.7 branch
//mExtent->setMinimal(); // This defeats normalization
while (!stream.atEnd())
bool firstPoint = true;
while (!mStream->atEnd())
{
lineNumber++;
line = stream.readLine(); // line of text excluding '\n', default local 8 bit encoding.
line = mStream->readLine(); // line of text excluding '\n', default local 8 bit encoding.
if (mNumberFeatures++ == 0)
{
// Get the fields from the header row and store them in the
Expand All @@ -124,8 +126,8 @@ QgsDelimitedTextProvider::QgsDelimitedTextProvider(QString const &uri)
QStringList fieldList =
QStringList::split(QRegExp(mDelimiter), line, true);
#ifdef QGISDEBUG
std::cerr << "Split line into " << fieldList.
size() << " parts" << std::endl;
std::cerr << "Split line into "
<< fieldList.size() << " parts" << std::endl;
#endif
// We don't know anything about a text based field other
// than its name. All fields are assumed to be text
Expand Down Expand Up @@ -194,23 +196,32 @@ QgsDelimitedTextProvider::QgsDelimitedTextProvider(QString const &uri)
bool yOk = true;
double x = sX.toDouble(&xOk);
double y = sY.toDouble(&yOk);

if (xOk && yOk)
{
if (x > mExtent->xMax())
{
mExtent->setXmax(x);
}
if (x < mExtent->xMin())
{
mExtent->setXmin(x);
}
if (y > mExtent->yMax())
if (!firstPoint)
{
mExtent->setYmax(y);
if (x > mExtent->xMax())
{
mExtent->setXmax(x);
}
if (x < mExtent->xMin())
{
mExtent->setXmin(x);
}
if (y > mExtent->yMax())
{
mExtent->setYmax(y);
}
if (y < mExtent->yMin())
{
mExtent->setYmin(y);
}
}
if (y < mExtent->yMin())
{
mExtent->setYmin(y);
else
{ // Extent for the first point is just the first point
mExtent->set(x,y,x,y);
firstPoint = false;
}
}
}
Expand Down Expand Up @@ -264,6 +275,7 @@ QgsDelimitedTextProvider::~QgsDelimitedTextProvider()
{
mFile->close();
delete mFile;
delete mStream;
for (int i = 0; i < fieldCount(); i++)
{
delete mMinMaxCache[i];
Expand Down Expand Up @@ -338,13 +350,9 @@ QgsDelimitedTextProvider::getNextFeature_( QgsFeature & feature,
// before we do anything else, assume that there's something wrong with
// the feature
feature.setValid( false );

QTextStream textStream( mFile );

if ( ! textStream.atEnd() )
while ( ! mStream->atEnd() )
{
QString line = textStream.readLine(); // Default local 8 bit encoding

QString line = mStream->readLine(); // Default local 8 bit encoding
// lex the tokens from the current data line
QStringList tokens = QStringList::split(QRegExp(mDelimiter), line, true);

Expand All @@ -357,62 +365,27 @@ QgsDelimitedTextProvider::getNextFeature_( QgsFeature & feature,
double x = tokens[xFieldPos].toDouble( &xOk );
double y = tokens[yFieldPos].toDouble( &yOk );

if ( xOk && yOk )
if (! (xOk && yOk))
{
// if the user has selected an area, constrain iterator to
// features that are within that area
if ( mSelectionRectangle && ! boundsCheck(x,y) )
{
bool foundFeature = false;

while ( ! textStream.atEnd() &&
(xOk && yOk) )
{
if ( boundsCheck(x,y) )
{
foundFeature = true;
break;
}

++mFid; // since we're skipping to next feature,
// increment ID

line = textStream.readLine();

tokens = QStringList::split(QRegExp(mDelimiter), line, true);

x = tokens[xFieldPos].toDouble( &xOk );
y = tokens[yFieldPos].toDouble( &yOk );
}
// Accumulate any lines that weren't ok, to report on them
// later, and look at the next line in the file.
mInvalidLines << line;
continue;
}

// there were no other features from the current one forward
// that were within the selection region
if ( ! foundFeature )
{
return false;
}
}
if (! boundsCheck(x,y))
continue;

// at this point, one way or another, the current feature values
// are valid
// at this point, one way or another, the current feature values
// are valid
feature.setValid( true );

++mFid; // increment to next feature ID

feature.setFeatureId( mFid );

unsigned char * geometry = new unsigned char[sizeof(wkbPoint)];
QByteArray buffer;
buffer.setRawData( (const char*)geometry, sizeof(wkbPoint) ); // buffer
// points
// to
// geometry

#if QT_VERSION < 0x040000
QDataStream s( buffer, QIODevice::WriteOnly ); // open on buffers's data
#else
QDataStream s( &buffer, QIODevice::WriteOnly ); // open on buffers's data
#endif

switch ( endian() )
{
Expand All @@ -428,20 +401,19 @@ QgsDelimitedTextProvider::getNextFeature_( QgsFeature & feature,
break;
default :
qDebug( "%s:%d unknown endian", __FILE__, __LINE__ );
delete [] geometry;
//delete [] geometry;
return false;
}

s << (Q_UINT32)1; // 1 is for WKBPoint
s << (Q_UINT32)QGis::WKBPoint;
s << x;
s << y;

unsigned char* geometry = new unsigned char[buffer.size()];
memcpy(geometry, buffer.data(), buffer.size());

feature.setGeometryAndOwnership( geometry, sizeof(wkbPoint) );

// ensure that the buffer doesn't delete the data on us
buffer.resetRawData( (const char*)geometry, sizeof(wkbPoint) );

if ( getAttributes && ! desiredAttributes )
{
for (int fi = 0; fi < attributeFields.size(); fi++)
Expand All @@ -461,13 +433,25 @@ QgsDelimitedTextProvider::getNextFeature_( QgsFeature & feature,
feature.addAttribute(attributeFields[*i].name(), tokens[*i]);
}
}

// We have a good line, so return
return true;

} // if able to get x and y coordinates

} // ! textStream EOF

// End of the file. If there are any lines that couldn't be
// loaded, display them now, but only once.

if (mShowInvalidLines && !mInvalidLines.isEmpty())
{
mShowInvalidLines = false;
QgsMessageViewer lineViewer;
lineViewer.setMessageAsPlainText(tr("Note: the following lines were not loaded because Qgis was unable to determine values for the x and y coordinates:\n"));
for (int i = 0; i < mInvalidLines.size(); ++i)
lineViewer.appendMessage(mInvalidLines.at(i));

lineViewer.exec();
}

return false;

} // getNextFeature_( QgsFeature & feature )
Expand Down Expand Up @@ -632,14 +616,12 @@ std::vector<QgsField> const & QgsDelimitedTextProvider::fields() const

void QgsDelimitedTextProvider::reset()
{
// Reset the file pointer to BOF
mFile->reset();
// Reset feature id to 0
mFid = 0;
// Skip ahead one line since first record is always assumed to be
// the header record
QTextStream stream(mFile);
stream.readLine();
mStream->seek(0);
mStream->readLine();
}

QString QgsDelimitedTextProvider::minValue(int position)
Expand Down Expand Up @@ -837,24 +819,20 @@ bool QgsDelimitedTextProvider::saveAsShapefile()
std::cerr << "Done creating fields" << std::endl;
// read the line
reset();
QTextStream stream(mFile);
QString line;
while (!stream.atEnd())
while (!mStream->atEnd())
{
line = stream.readLine(); // line of text excluding '\n'
std::cerr << (const char *)line.toLocal8Bit().data() << std::endl;
line = mStream->readLine(); // line of text excluding '\n'
// split the line
QStringList parts =
QStringList::split(QRegExp(mDelimiter), line, true);
std::cerr << "Split line into " << parts.size() << std::endl;

// create the feature
OGRFeature *poFeature;

poFeature = new OGRFeature(poLayer->GetLayerDefn());

// iterate over the parts and set the fields
std::cerr << "Setting the field values" << std::endl;
// set limit - we will ignore extra fields on the line
int limit = attributeFields.size();

Expand All @@ -871,8 +849,6 @@ bool QgsDelimitedTextProvider::saveAsShapefile()
{
if (parts[i] != QString::null)
{
std::cerr << "Setting " << i << " " << (const char *)attributeFields[i].
name().toLocal8Bit().data() << " to " << (const char *)parts[i].toLocal8Bit().data() << std::endl;
poFeature->SetField(saveCodec->fromUnicode(attributeFields[i].name()).data(),
saveCodec->fromUnicode(parts[i]).data());

Expand Down Expand Up @@ -958,11 +934,10 @@ int *QgsDelimitedTextProvider::getFieldLengths()
{
reset();
// read the line
QTextStream stream(mFile);
QString line;
while (!stream.atEnd())
while (!mStream->atEnd())
{
line = stream.readLine(); // line of text excluding '\n'
line = mStream->readLine(); // line of text excluding '\n'
// split the line
QStringList parts = QStringList::split(QRegExp(mDelimiter), line, true);
// iterate over the parts and update the max value
Expand Down

0 comments on commit 6e84284

Please sign in to comment.