~ubuntu-branches/ubuntu/quantal/qgis/quantal

« back to all changes in this revision

Viewing changes to providers/delimitedtext/qgsdelimitedtextprovider.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Steve Halasz
  • Date: 2005-11-05 16:04:45 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20051105160445-l0g4isz5bc9yehet
Tags: 0.7.4-1
* New upstream release
* Build GRASS support in qgis-plugin-grass package (Closes: #248649)

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
 *   (at your option) any later version.                                   *
15
15
 *                                                                         *
16
16
 ***************************************************************************/
17
 
/* $Id: qgsdelimitedtextprovider.cpp,v 1.18.2.1 2004/12/14 20:50:06 gsherman Exp $ */
18
 
 
 
17
/* $Id: qgsdelimitedtextprovider.cpp,v 1.23.2.2 2005/07/21 22:18:45 timlinux Exp $ */
 
18
 
 
19
#include "qgsdelimitedtextprovider.h"
 
20
 
 
21
#include <cfloat>
19
22
#include <iostream>
 
23
 
20
24
#include <qfile.h>
 
25
#include <qdatastream.h>
21
26
#include <qtextstream.h>
22
27
#include <qstringlist.h>
23
28
#include <qmessagebox.h>
24
29
#include <qfiledialog.h>
25
30
#include <qsettings.h>
26
31
#include <qregexp.h>
 
32
#include <qurl.h>
 
33
 
27
34
#include <ogrsf_frmts.h>
 
35
 
28
36
#include "../../src/qgsdataprovider.h"
 
37
#include "../../src/qgsencodingfiledialog.h"
29
38
#include "../../src/qgsfeature.h"
30
39
#include "../../src/qgsfield.h"
31
40
#include "../../src/qgsrect.h"
32
 
#include "qgsdelimitedtextprovider.h"
33
 
#include <cfloat>
 
41
 
34
42
 
35
43
#ifdef WIN32
36
44
#define QGISEXTERN extern "C" __declspec( dllexport )
38
46
#define QGISEXTERN extern "C"
39
47
#endif
40
48
 
41
 
  QgsDelimitedTextProvider::QgsDelimitedTextProvider(QString uri)
42
 
:mDataSourceUri(uri), mMinMaxCacheDirty(true)
 
49
QgsDelimitedTextProvider::QgsDelimitedTextProvider(QString uri)
 
50
    : mDataSourceUri(uri),
 
51
      mMinMaxCacheDirty(true)
43
52
{
44
53
  // Get the file name and mDelimiter out of the uri
45
54
  mFileName = uri.left(uri.find("?"));
46
55
  // split the string up on & to get the individual parameters
47
56
  QStringList parameters = QStringList::split("&", uri.mid(uri.find("?")));
48
57
#ifdef QGISDEBUG
49
 
  std::cerr << "Parameter count after split on &" << parameters.size() << std::endl; 
 
58
  std::cerr << "Parameter count after split on &" << parameters.
 
59
    size() << std::endl;
50
60
#endif
51
61
  // get the individual parameters and assign values
52
62
  QStringList temp = parameters.grep("delimiter=");
53
 
  mDelimiter = temp.size() ?temp[0].mid(temp[0].find("=") +1):"";
 
63
  mDelimiter = temp.size()? temp[0].mid(temp[0].find("=") + 1) : "";
54
64
  temp = parameters.grep("xField=");
55
 
  mXField = temp.size() ?temp[0].mid(temp[0].find("=") +1):"";
 
65
  mXField = temp.size()? temp[0].mid(temp[0].find("=") + 1) : "";
56
66
  temp = parameters.grep("yField=");
57
 
  mYField = temp.size() ?temp[0].mid(temp[0].find("=") +1):"";
 
67
  mYField = temp.size()? temp[0].mid(temp[0].find("=") + 1) : "";
 
68
  // Decode the parts of the uri. Good if someone entered '=' as a delimiter, for instance.
 
69
  QUrl::decode(mFileName);
 
70
  QUrl::decode(mDelimiter);
 
71
  QUrl::decode(mXField);
 
72
  QUrl::decode(mYField);
58
73
#ifdef QGISDEBUG
59
 
  std::cerr << "Data source uri is " << uri << std::endl;
60
 
  std::cerr << "Delimited text file is: " << mFileName << std::endl;
61
 
  std::cerr << "Delimiter is: " << mDelimiter << std::endl;
62
 
  std::cerr << "xField is: " << mXField << std::endl; 
63
 
  std::cerr << "yField is: " << mYField << std::endl; 
 
74
  std::cerr << "Data source uri is " << (const char *)uri.local8Bit() << std::endl;
 
75
  std::cerr << "Delimited text file is: " << (const char *)mFileName.local8Bit() << std::endl;
 
76
  std::cerr << "Delimiter is: " << (const char *)mDelimiter.local8Bit() << std::endl;
 
77
  std::cerr << "xField is: " << (const char *)mXField.local8Bit() << std::endl;
 
78
  std::cerr << "yField is: " << (const char *)mYField.local8Bit() << std::endl;
64
79
#endif
65
80
  // Set the selection rectangle to null
66
81
  mSelectionRectangle = 0;
67
82
  // assume the layer is invalid until proven otherwise
68
83
  mValid = false;
69
 
  if(!mFileName.isEmpty() && !mDelimiter.isEmpty() && !mXField.isEmpty() && !mYField.isEmpty()){
 
84
  if (!mFileName.isEmpty() && !mDelimiter.isEmpty() && !mXField.isEmpty() &&
 
85
      !mYField.isEmpty())
 
86
  {
70
87
    // check to see that the file exists and perform some sanity checks
71
 
    if(QFile::exists(mFileName)){
 
88
    if (QFile::exists(mFileName))
 
89
    {
72
90
      // Open the file and get number of rows, etc. We assume that the
73
91
      // file has a header row and process accordingly. Caller should make
74
92
      // sure the the delimited file is properly formed.
75
93
      mFile = new QFile(mFileName);
76
 
      if ( mFile->open( IO_ReadOnly ) ) {
77
 
        QTextStream stream( mFile );
 
94
      if (mFile->open(IO_ReadOnly))
 
95
      {
 
96
        QTextStream stream(mFile);
78
97
        QString line;
79
98
        mNumberFeatures = 0;
80
99
        int xyCount = 0;
81
100
        int lineNumber = 0;
82
101
        // set the initial extent
83
 
        mExtent = new QgsRect(9999999999999.0,9999999999999.0,-9999999999999.0,-9999999999999.0);
84
 
        while ( !stream.atEnd() ) {
 
102
        mExtent = new QgsRect();
 
103
        mExtent->setMinimal(); // This defeats normalization
 
104
        while (!stream.atEnd())
 
105
        {
85
106
          lineNumber++;
86
 
          line = stream.readLine(); // line of text excluding '\n'
87
 
          if(mNumberFeatures++ == 0){
 
107
          line = stream.readLine(); // line of text excluding '\n', default local 8 bit encoding.
 
108
          if (mNumberFeatures++ == 0)
 
109
          {
88
110
            // Get the fields from the header row and store them in the 
89
111
            // fields vector
90
112
#ifdef QGISDEBUG
91
 
            std::cerr << "Attempting to split the input line: " << line <<
92
 
              " using delimiter " << mDelimiter << std::endl;
 
113
            std::
 
114
              cerr << "Attempting to split the input line: " << (const char *)line.local8Bit() <<
 
115
              " using delimiter " << (const char *)mDelimiter.local8Bit() << std::endl;
93
116
#endif
94
 
            QStringList fieldList = QStringList::split(QRegExp(mDelimiter), line, true);
 
117
            QStringList fieldList =
 
118
              QStringList::split(QRegExp(mDelimiter), line, true);
95
119
#ifdef QGISDEBUG
96
 
            std::cerr << "Split line into " << fieldList.size() << " parts" << std::endl; 
 
120
            std::cerr << "Split line into " << fieldList.
 
121
              size() << " parts" << std::endl;
97
122
#endif
98
123
            // We don't know anything about a text based field other
99
124
            // than its name. All fields are assumed to be text
100
125
            int fieldPos = 0;
101
 
            for ( QStringList::Iterator it = fieldList.begin(); it != fieldList.end(); ++it ) 
 
126
            for (QStringList::Iterator it = fieldList.begin();
 
127
                 it != fieldList.end(); ++it)
102
128
            {
103
129
              QString field = *it;
104
 
              if(field.length() > 0)
105
 
              {
106
 
              attributeFields.push_back(QgsField(*it, "Text"));
107
 
              fieldPositions[*it] = fieldPos++;
108
 
              // check to see if this field matches either the x or y field
109
 
              if(mXField == *it)
110
 
              {
111
 
#ifdef QGISDEBUG
112
 
                std::cerr << "Found x field " <<  *it << std::endl; 
113
 
#endif
114
 
                xyCount++;
115
 
              }
116
 
              if(mYField == *it)
117
 
              {
118
 
#ifdef QGISDEBUG
119
 
                std::cerr << "Found y field " <<  *it << std::endl; 
120
 
#endif
121
 
                xyCount++;
122
 
              }
123
 
#ifdef QGISDEBUG
124
 
              std::cerr << "Adding field: " << *it << std::endl; 
 
130
              if (field.length() > 0)
 
131
              {
 
132
                attributeFields.push_back(QgsField(*it, "Text"));
 
133
                fieldPositions[*it] = fieldPos++;
 
134
                // check to see if this field matches either the x or y field 
 
135
                if (mXField == *it)
 
136
                {
 
137
#ifdef QGISDEBUG
 
138
                  std::cerr << "Found x field " << (const char *)(*it).local8Bit() << std::endl;
 
139
#endif
 
140
                  xyCount++;
 
141
                }
 
142
                if (mYField == *it)
 
143
                {
 
144
#ifdef QGISDEBUG
 
145
                  std::cerr << "Found y field " << (const char *)(*it).local8Bit() << std::endl;
 
146
#endif
 
147
                  xyCount++;
 
148
                }
 
149
#ifdef QGISDEBUG
 
150
                std::cerr << "Adding field: " << (const char *)(*it).local8Bit() << std::endl;
125
151
#endif
126
152
 
 
153
              }
127
154
            }
128
 
            }           
129
 
#ifdef QGISDEBUG 
130
 
            std::cerr << "Field count for the delimited text file is " << attributeFields.size() << std::endl; 
131
 
#endif 
132
 
          }else
 
155
#ifdef QGISDEBUG
 
156
            std::
 
157
              cerr << "Field count for the delimited text file is " <<
 
158
              attributeFields.size() << std::endl;
 
159
#endif
 
160
          }
 
161
          else
133
162
          {
134
163
            // examine the x,y and update extents
135
164
            //  std::cout << line << std::endl; 
136
165
            // split the line on the delimiter
137
 
            QStringList parts = QStringList::split(QRegExp(mDelimiter), line, true);
 
166
            QStringList parts =
 
167
              QStringList::split(QRegExp(mDelimiter), line, true);
138
168
            //if(parts.size() == attributeFields.size())
139
169
            //{
140
170
            //  // we can populate attributes if required
147
177
               std::cout << "Record hit line " << lineNumber << ": " <<
148
178
               parts[fieldPositions[mXField]] << ", " <<
149
179
               parts[fieldPositions[mYField]] << std::endl;
150
 
               */
 
180
             */
151
181
            // Get the x and y values, first checking to make sure they
152
182
            // aren't null.
153
183
            QString sX = parts[fieldPositions[mXField]];
157
187
            bool yOk = true;
158
188
            double x = sX.toDouble(&xOk);
159
189
            double y = sY.toDouble(&yOk);
160
 
            if(xOk && yOk)
 
190
            if (xOk && yOk)
161
191
            {
162
 
              if(x > mExtent->xMax())
163
 
              { 
 
192
              if (x > mExtent->xMax())
 
193
              {
164
194
                mExtent->setXmax(x);
165
195
              }
166
 
              if(x < mExtent->xMin())
 
196
              if (x < mExtent->xMin())
167
197
              {
168
198
                mExtent->setXmin(x);
169
199
              }
170
 
              if(y > mExtent->yMax())
 
200
              if (y > mExtent->yMax())
171
201
              {
172
202
                mExtent->setYmax(y);
173
203
              }
174
 
              if(y < mExtent->yMin())
 
204
              if (y < mExtent->yMin())
175
205
              {
176
206
                mExtent->setYmin(y);
177
207
              }
181
211
        reset();
182
212
        mNumberFeatures--;
183
213
 
184
 
        if(xyCount == 2)
 
214
        if (xyCount == 2)
185
215
        {
186
216
#ifdef QGISDEBUG
187
 
          std::cerr << "Data store is valid" << std::endl; 
188
 
          std::cerr << "Number of features " << mNumberFeatures << std::endl; 
189
 
          std::cerr << "Extents " << mExtent->stringRep() << std::endl; 
 
217
          std::cerr << "Data store is valid" << std::endl;
 
218
          std::cerr << "Number of features " << mNumberFeatures << std::endl;
 
219
          std::cerr << "Extents " << (const char *)mExtent->stringRep().local8Bit() << std::endl;
190
220
#endif
191
221
          mValid = true;
192
 
        }else
 
222
        }
 
223
        else
193
224
        {
194
 
          std::cerr << "Data store is invalid. Specified x,y fields do not match\n"
 
225
          std::
 
226
            cerr << "Data store is invalid. Specified x,y fields do not match\n"
195
227
            << "those in the database (xyCount=" << xyCount << ")" << std::endl;
196
228
        }
197
 
      } 
198
 
 
 
229
      }
199
230
#ifdef QGISDEBUG
200
231
      std::cerr << "Done checking validity\n";
201
232
#endif
202
233
 
203
234
      //resize the cache matrix
204
 
      mMinMaxCache=new double*[attributeFields.size()];
205
 
      for(int i=0;i<attributeFields.size();i++)
 
235
      mMinMaxCache = new double *[attributeFields.size()];
 
236
      for (int i = 0; i < attributeFields.size(); i++)
206
237
      {
207
 
        mMinMaxCache[i]=new double[2];
 
238
        mMinMaxCache[i] = new double[2];
208
239
      }
209
 
    }else
 
240
    }
 
241
    else
210
242
      // file does not exist
211
 
      std::cerr << "Data source " << mDataSourceUri << " could not be opened" << std::endl; 
 
243
      std::
 
244
        cerr << "Data source " << (const char *)mDataSourceUri.local8Bit() << " could not be opened" <<
 
245
        std::endl;
212
246
 
213
 
  }else
 
247
  }
 
248
  else
214
249
  {
215
250
    // uri is invalid so the layer must be too...
216
251
    std::cerr << "Data source is invalid" << std::endl;
222
257
{
223
258
  mFile->close();
224
259
  delete mFile;
225
 
  for(int i=0;i<fieldCount();i++)
 
260
  for (int i = 0; i < fieldCount(); i++)
226
261
  {
227
262
    delete mMinMaxCache[i];
228
263
  }
229
 
  delete[] mMinMaxCache;
 
264
  delete[]mMinMaxCache;
230
265
}
231
266
 
232
267
/**
233
268
 * Get the first feature resutling from a select operation
234
269
 * @return QgsFeature
235
270
 */
236
 
QgsFeature *QgsDelimitedTextProvider::getFirstFeature( bool fetchAttributes)
 
271
QgsFeature * QgsDelimitedTextProvider::getFirstFeature(bool fetchAttributes)
237
272
{
238
 
  QgsFeature *f = 0;
239
 
  if(mValid){
240
 
    /*
241
 
#ifdef QGISDEBUG
242
 
std::cerr << "getting first feature\n";
243
 
#endif
244
 
ogrLayer->ResetReading();
245
 
OGRFeature *feat = ogrLayer->GetNextFeature();
246
 
if(feat){
247
 
#ifdef QGISDEBUG
248
 
std::cerr << "First feature is not null\n";
249
 
#endif
250
 
}else{
251
 
#ifdef QGISDEBUG
252
 
std::cerr << "First feature is null\n";
253
 
#endif
254
 
}
255
 
f = new QgsFeature(feat->GetFID());
256
 
f->setGeometry(getGeometryPointer(feat));
257
 
if(fetchAttributes){
258
 
getFeatureAttributes(feat, f);
259
 
}
260
 
}
 
273
    QgsFeature *f = new QgsFeature;
 
274
 
 
275
    reset();                    // reset back to first feature
 
276
 
 
277
    if ( getNextFeature_( *f, fetchAttributes ) )
 
278
    {
 
279
        return f;
 
280
    }
 
281
 
 
282
    delete f;
 
283
 
 
284
    return 0x0;
 
285
} // QgsDelimitedTextProvider::getFirstFeature(bool fetchAttributes)
 
286
 
 
287
/**
 
288
 
 
289
  insure double value is properly translated into locate endian-ness
 
290
 
261
291
*/
262
 
  }
263
 
return f;
264
 
}
265
 
 
266
 
/**
267
 
 * Get the next feature resulting from a select operation
268
 
 * Return 0 if there are no features in the selection set
269
 
 * @return QgsFeature
270
 
 */
271
 
bool QgsDelimitedTextProvider::getNextFeature(QgsFeature &feature, bool fetchAttributes)
272
 
{
273
 
  // We must manually check each point to see if it is within the
274
 
  // selection rectangle
275
 
  bool returnValue;
276
 
 
277
 
  bool processPoint;
278
 
  if(mValid){
279
 
    // read the line
280
 
    QTextStream stream( mFile );
281
 
    QString line;
282
 
    if ( !stream.atEnd() ) {
283
 
#ifdef QGISDEBUG
284
 
      std::cerr << "Stream read" << std::endl; 
285
 
#endif
286
 
      line = stream.readLine(); // line of text excluding '\n'
287
 
      // create the geometry from the x, y fields
288
 
      QStringList parts = QStringList::split(QRegExp(mDelimiter), line, true);
289
 
      // Get the x and y values, first checking to make sure they
290
 
      // aren't null.
291
 
      QString sX = parts[fieldPositions[mXField]];
292
 
      QString sY = parts[fieldPositions[mYField]];
293
 
      std::cerr << "x ,y " << sX << ", " << sY << std::endl; 
294
 
      bool xOk = true;
295
 
      bool yOk = true;
296
 
      double x = sX.toDouble(&xOk);
297
 
      double y = sY.toDouble(&yOk);
298
 
      if(xOk && yOk)
299
 
      {
300
 
        if(mSelectionRectangle == 0)
301
 
        {
302
 
          // no selection in place
303
 
          processPoint = true;
304
 
        }else
305
 
        {
306
 
          // check to see if point is in bounds
307
 
          processPoint = boundsCheck(x, y);
308
 
        }
309
 
        if(processPoint)
310
 
        {
311
 
          std::cerr << "Processing " << x << ", " << y << std::endl; 
312
 
          // create WKBPoint
313
 
          wkbPoint *geometry = new wkbPoint;
314
 
          geometry->byteOrder = endian();
315
 
          geometry->wkbType = 1;
316
 
          geometry->x = x;
317
 
          geometry->y = y;
318
 
          feature.setGeometry((unsigned char *)geometry, sizeof(wkbPoint));
319
 
          feature.setValid(true);
320
 
          // get the attributes if requested
321
 
          if(fetchAttributes){
322
 
            for(int fi =0; fi < attributeFields.size(); fi++)
323
 
            {
324
 
              feature.addAttribute(attributeFields.at(fi).name(), parts[fi]);
325
 
 
326
 
            }
327
 
 
328
 
            QString sX = parts[fieldPositions[mXField]];
329
 
          }
330
 
        }else
331
 
        {
332
 
          feature.setValid(false);
333
 
        }
334
 
 
335
 
      }
336
 
      // Return true since the read was successful. The feature itself
337
 
      // may be invalid for various reasons
338
 
      returnValue = true;
339
 
    }else
340
 
    {
341
 
#ifdef QGISDEBUG
342
 
      std::cerr << "Stream is at end" << std::endl; 
343
 
#endif
344
 
      // Return false since read of next feature failed
345
 
      returnValue = false;
346
 
      // Set the feature to invalid
347
 
      feature.setValid(false);
348
 
    }
349
 
 
350
 
  }
351
 
#ifdef QGISDEBUG
352
 
  QString sReturn = returnValue?"true":"false" ;
353
 
  std::cerr << "Returning " << sReturn << " from getNextFeature" << std::endl;
354
 
#endif
355
 
  return returnValue;
356
 
}
357
 
 
358
 
/**
359
 
 * Get the next feature resulting from a select operation
360
 
 * Return 0 if there are no features in the selection set
361
 
 * @return QgsFeature
362
 
 */
363
 
QgsFeature *QgsDelimitedTextProvider::getNextFeature(bool fetchAttributes)
364
 
{
365
 
  // We must manually check each point to see if it is within the
366
 
  // selection rectangle
367
 
  QgsFeature *f = 0;
368
 
  bool processPoint;
369
 
  if(mValid){
370
 
    // read the line
371
 
    QTextStream stream( mFile );
372
 
    QString line;
373
 
    if ( !stream.atEnd() ) {
374
 
      line = stream.readLine(); // line of text excluding '\n'
375
 
      // create the geometry from the x, y fields
376
 
      QStringList parts = QStringList::split(QRegExp(mDelimiter), line, true);
377
 
      // Get the x and y values, first checking to make sure they
378
 
      // aren't null.
379
 
      QString sX = parts[fieldPositions[mXField]];
380
 
      QString sY = parts[fieldPositions[mYField]];
381
 
      //std::cout << "x ,y " << sX << ", " << sY << std::endl; 
382
 
      bool xOk = true;
383
 
      bool yOk = true;
384
 
      double x = sX.toDouble(&xOk);
385
 
      double y = sY.toDouble(&yOk);
386
 
      if(xOk && yOk)
387
 
      {
388
 
        if(mSelectionRectangle == 0)
389
 
        {
390
 
          // no selection in place
391
 
          processPoint = true;
392
 
        }else
393
 
        {
394
 
          // check to see if point is in bounds
395
 
          processPoint = boundsCheck(x, y);
396
 
          if(!processPoint)
397
 
          {
398
 
            // we need to continue to read until we get a hit in the
399
 
            // selection rectangle or the EOF is reached
400
 
            while(!stream.atEnd() && !processPoint)
401
 
            {
402
 
                ++mFid;
403
 
              line = stream.readLine();
404
 
 
405
 
              // create the geometry from the x, y fields
406
 
              parts = QStringList::split(QRegExp(mDelimiter), line, true);
407
 
              // Get the x and y values, first checking to make sure they
408
 
              // aren't null.
409
 
              sX = parts[fieldPositions[mXField]];
410
 
              sY = parts[fieldPositions[mYField]];
411
 
              //std::cout << "x ,y " << sX << ", " << sY << std::endl; 
412
 
              xOk = true;
413
 
              yOk = true;
414
 
              x = sX.toDouble(&xOk);
415
 
              y = sY.toDouble(&yOk);
416
 
              if(xOk && yOk)
417
 
              {
418
 
                processPoint = boundsCheck(x, y);
419
 
              }
420
 
 
421
 
            }
422
 
          }
423
 
        }
424
 
        if(processPoint)
425
 
        {
426
 
          //std::cout << "Processing " << x << ", " << y << std::endl; 
427
 
          // create WKBPoint
428
 
          wkbPoint wkbPt;
429
 
          unsigned char * geometry = new unsigned char[sizeof(wkbPt)];
430
 
          geometry[0] = endian();
431
 
          int type = 1;
432
 
          void *ptr = geometry+1;
433
 
          memcpy((void*)(geometry +1), &type, 4);
434
 
          memcpy((void*)(geometry +5), &x, sizeof(x));
435
 
          memcpy((void*)(geometry +13), &y, sizeof(y));
436
 
          /*
437
 
             geometry->byteOrder = endian();
438
 
             geometry->wkbType = 1;
439
 
             geometry->x = x;
440
 
             geometry->y = y;
441
 
             */
442
 
          f = new QgsFeature();
443
 
          f->setGeometry(geometry, sizeof(wkbPt));
444
 
          //std::cerr << "Setting feature id to " << mFid << std::endl; 
445
 
          f->setFeatureId(mFid++);
446
 
          // get the attributes if requested
447
 
          if(fetchAttributes){
448
 
            // add the attributes to the attribute map
449
 
            for(int fi =0; fi < attributeFields.size(); fi++)
450
 
            {
451
 
              f->addAttribute(attributeFields.at(fi).name(), parts[fi]);
452
 
 
453
 
            }
454
 
 
455
 
          }
456
 
        }
457
 
      }
458
 
    }
459
 
 
460
 
  }
461
 
  return f;
462
 
}
463
 
 
464
 
QgsFeature * QgsDelimitedTextProvider::getNextFeature(std::list<int>& attlist)
465
 
{
466
 
     // We must manually check each point to see if it is within the
467
 
  // selection rectangle
468
 
  QgsFeature *f = 0;
469
 
  bool processPoint;
470
 
  if(mValid){
471
 
    // read the line
472
 
    QTextStream stream( mFile );
473
 
    QString line;
474
 
    if ( !stream.atEnd() ) {
475
 
      line = stream.readLine(); // line of text excluding '\n'
476
 
      // create the geometry from the x, y fields
477
 
      QStringList parts = QStringList::split(QRegExp(mDelimiter), line, true);
478
 
      // Get the x and y values, first checking to make sure they
479
 
      // aren't null.
480
 
      QString sX = parts[fieldPositions[mXField]];
481
 
      QString sY = parts[fieldPositions[mYField]];
482
 
      //std::cout << "x ,y " << sX << ", " << sY << std::endl; 
483
 
      bool xOk = true;
484
 
      bool yOk = true;
485
 
      double x = sX.toDouble(&xOk);
486
 
      double y = sY.toDouble(&yOk);
487
 
      if(xOk && yOk)
488
 
      {
489
 
        if(mSelectionRectangle == 0)
490
 
        {
491
 
          // no selection in place
492
 
          processPoint = true;
493
 
        }else
494
 
        {
495
 
          // check to see if point is in bounds
496
 
          processPoint = boundsCheck(x, y);
497
 
          if(!processPoint)
498
 
          {
499
 
            // we need to continue to read until we get a hit in the
500
 
            // selection rectangle or the EOF is reached
501
 
            while(!stream.atEnd() && !processPoint)
502
 
            {
503
 
                ++mFid;
504
 
              line = stream.readLine();
505
 
 
506
 
              // create the geometry from the x, y fields
507
 
              parts = QStringList::split(QRegExp(mDelimiter), line, true);
508
 
              // Get the x and y values, first checking to make sure they
509
 
              // aren't null.
510
 
              sX = parts[fieldPositions[mXField]];
511
 
              sY = parts[fieldPositions[mYField]];
512
 
              //std::cout << "x ,y " << sX << ", " << sY << std::endl; 
513
 
              xOk = true;
514
 
              yOk = true;
515
 
              x = sX.toDouble(&xOk);
516
 
              y = sY.toDouble(&yOk);
517
 
              if(xOk && yOk)
518
 
              {
519
 
                processPoint = boundsCheck(x, y);
520
 
              }
521
 
 
522
 
            }
523
 
          }
524
 
        }
525
 
        if(processPoint)
526
 
        {
527
 
          //std::cout << "Processing " << x << ", " << y << std::endl; 
528
 
          // create WKBPoint
529
 
          wkbPoint wkbPt;
530
 
          unsigned char * geometry = new unsigned char[sizeof(wkbPt)];
531
 
          geometry[0] = endian();
532
 
          int type = 1;
533
 
          void *ptr = geometry+1;
534
 
          memcpy((void*)(geometry +1), &type, 4);
535
 
          memcpy((void*)(geometry +5), &x, sizeof(x));
536
 
          memcpy((void*)(geometry +13), &y, sizeof(y));
537
 
          /*
538
 
             geometry->byteOrder = endian();
539
 
             geometry->wkbType = 1;
540
 
             geometry->x = x;
541
 
             geometry->y = y;
542
 
             */
543
 
          f = new QgsFeature();
544
 
          f->setGeometry(geometry, sizeof(wkbPt));
545
 
          //std::cerr << "Setting feature id to " << mFid << std::endl; 
546
 
          f->setFeatureId(mFid++);
547
 
          
548
 
          // add the attributes to the attribute map
549
 
              for(std::list<int>::iterator iter=attlist.begin();iter!=attlist.end();++iter)
550
 
              {
551
 
                  f->addAttribute(attributeFields.at(*iter).name(), parts[*iter]);
552
 
              }
553
 
        }
554
 
      }
555
 
    }
556
 
 
557
 
  }
558
 
  return f;
559
 
}
 
292
static
 
293
double
 
294
translateDouble_( double d )
 
295
{
 
296
    union
 
297
    {
 
298
        double fpval;
 
299
        char   char_val[8];
 
300
    } from, to;
 
301
 
 
302
    // break double into byte sized chunks
 
303
    from.fpval = d;
 
304
 
 
305
    to.char_val[7] = from.char_val[0];
 
306
    to.char_val[6] = from.char_val[1];
 
307
    to.char_val[5] = from.char_val[2];
 
308
    to.char_val[4] = from.char_val[3];
 
309
    to.char_val[3] = from.char_val[4];
 
310
    to.char_val[2] = from.char_val[5];
 
311
    to.char_val[1] = from.char_val[6];
 
312
    to.char_val[0] = from.char_val[7];
 
313
 
 
314
    return to.fpval;
 
315
 
 
316
} // translateDouble_
 
317
 
 
318
 
 
319
bool
 
320
QgsDelimitedTextProvider::getNextFeature_( QgsFeature & feature, 
 
321
                                           bool getAttributes,
 
322
                                           std::list<int> const * desiredAttributes )
 
323
{
 
324
    // before we do anything else, assume that there's something wrong with
 
325
    // the feature
 
326
    feature.setValid( false );
 
327
 
 
328
    QTextStream textStream( mFile );
 
329
 
 
330
    if ( ! textStream.atEnd() )
 
331
    {
 
332
      QString line = textStream.readLine(); // Default local 8 bit encoding
 
333
 
 
334
        // lex the tokens from the current data line
 
335
        QStringList tokens = QStringList::split(QRegExp(mDelimiter), line, true);
 
336
 
 
337
        bool xOk = false;
 
338
        bool yOk = false;
 
339
 
 
340
        int xFieldPos = fieldPositions[mXField];
 
341
        int yFieldPos = fieldPositions[mYField];
 
342
 
 
343
        double x = tokens[xFieldPos].toDouble( &xOk );
 
344
        double y = tokens[yFieldPos].toDouble( &yOk );
 
345
 
 
346
        if ( xOk && yOk )
 
347
        {
 
348
            // if the user has selected an area, constrain iterator to
 
349
            // features that are within that area
 
350
            if ( mSelectionRectangle && ! boundsCheck(x,y) )
 
351
            {
 
352
                bool foundFeature = false;
 
353
 
 
354
                while ( ! textStream.atEnd() && 
 
355
                        (xOk && yOk) )
 
356
                {
 
357
                    if ( boundsCheck(x,y) )
 
358
                    {
 
359
                        foundFeature = true;
 
360
                        break;
 
361
                    }
 
362
 
 
363
                    ++mFid;     // since we're skipping to next feature,
 
364
                                // increment ID
 
365
 
 
366
                    line = textStream.readLine();
 
367
 
 
368
                    tokens = QStringList::split(QRegExp(mDelimiter), line, true);
 
369
 
 
370
                    x = tokens[xFieldPos].toDouble( &xOk );
 
371
                    y = tokens[yFieldPos].toDouble( &yOk );
 
372
                }
 
373
 
 
374
                // there were no other features from the current one forward
 
375
                // that were within the selection region
 
376
                if ( ! foundFeature )
 
377
                {
 
378
                    return false;
 
379
                }
 
380
            }
 
381
 
 
382
            // at this point, one way or another, the current feature values
 
383
            // are valid
 
384
           feature.setValid( true );
 
385
 
 
386
           ++mFid;             // increment to next feature ID
 
387
 
 
388
           feature.setFeatureId( mFid );
 
389
 
 
390
           unsigned char * geometry = new unsigned char[sizeof(wkbPoint)];
 
391
           QByteArray  buffer;
 
392
           buffer.setRawData( (const char*)geometry, sizeof(wkbPoint) ); // buffer
 
393
                                                                         // points
 
394
                                                                         // to
 
395
                                                                         // geometry
 
396
 
 
397
           QDataStream s( buffer, IO_WriteOnly ); // open on buffers's data
 
398
 
 
399
           switch ( endian() )
 
400
           {
 
401
               case QgsDataProvider::NDR :
 
402
                   // we're on a little-endian platform, so tell the data
 
403
                   // stream to use that
 
404
                   s.setByteOrder( QDataStream::LittleEndian );
 
405
                   s << (Q_UINT8)1; // 1 is for little-endian
 
406
                   break;
 
407
               case QgsDataProvider::XDR :
 
408
                   // don't change byte order since QDataStream is big endian by default
 
409
                   s << (Q_UINT8)0; // 0 is for big-endian
 
410
                   break;
 
411
               default :
 
412
                   qDebug( "%s:%d unknown endian", __FILE__, __LINE__ );
 
413
                   delete [] geometry;
 
414
                   return false;
 
415
           }
 
416
 
 
417
           s << (Q_UINT32)1; // 1 is for WKBPoint
 
418
           s << x;
 
419
           s << y;
 
420
 
 
421
 
 
422
           // XXX Umm, does the feature own the wkbPoint now?
 
423
           feature.setGeometry( geometry, sizeof(wkbPoint) );
 
424
 
 
425
           // ensure that the buffer doesn't delete the data on us
 
426
           buffer.resetRawData( (const char*)geometry, sizeof(wkbPoint) );
 
427
 
 
428
           if ( getAttributes && ! desiredAttributes )
 
429
           {
 
430
               for (int fi = 0; fi < attributeFields.size(); fi++)
 
431
               {
 
432
                   feature.addAttribute(attributeFields[fi].name(), tokens[fi]);
 
433
               }
 
434
           }
 
435
           // regardless of whether getAttributes is true or not, if the
 
436
           // programmer went through the trouble of passing in such a list of
 
437
           // attribute fields, then obviously they want them
 
438
           else if ( desiredAttributes )
 
439
           {
 
440
               for ( std::list<int>::const_iterator i = desiredAttributes->begin();
 
441
                     i != desiredAttributes->end();
 
442
                     ++i )
 
443
               {
 
444
                   feature.addAttribute(attributeFields[*i].name(), tokens[*i]);
 
445
               }
 
446
           }
 
447
 
 
448
           return true;
 
449
 
 
450
        } // if able to get x and y coordinates
 
451
 
 
452
    } // ! textStream EOF
 
453
 
 
454
    return false;
 
455
 
 
456
} // getNextFeature_( QgsFeature & feature )
 
457
 
 
458
 
 
459
 
 
460
/**
 
461
  Get the next feature resulting from a select operation
 
462
  Return 0 if there are no features in the selection set
 
463
 * @return false if unable to get the next feature
 
464
 */
 
465
bool QgsDelimitedTextProvider::getNextFeature(QgsFeature & feature,
 
466
                                              bool fetchAttributes)
 
467
{
 
468
    return getNextFeature_( feature, fetchAttributes );
 
469
} // QgsDelimitedTextProvider::getNextFeature
 
470
 
 
471
 
 
472
 
 
473
QgsFeature * QgsDelimitedTextProvider::getNextFeature(bool fetchAttributes)
 
474
{
 
475
    QgsFeature * f = new QgsFeature;
 
476
 
 
477
    if ( getNextFeature( *f, fetchAttributes ) )
 
478
    {
 
479
        return f;
 
480
    }
 
481
    
 
482
    delete f;
 
483
 
 
484
    return 0x0;
 
485
} // QgsDelimitedTextProvider::getNextFeature(bool fetchAttributes)
 
486
 
 
487
 
 
488
 
 
489
QgsFeature * QgsDelimitedTextProvider::getNextFeature(std::list<int> const & desiredAttributes )
 
490
{
 
491
    QgsFeature * f = new QgsFeature;
 
492
 
 
493
    if ( getNextFeature_( *f, true, &desiredAttributes ) )
 
494
    {
 
495
        return f;
 
496
    }
 
497
    
 
498
    delete f;
 
499
 
 
500
    return 0x0;
 
501
 
 
502
} // QgsDelimitedTextProvider::getNextFeature(std::list < int >&attlist)
 
503
 
 
504
 
 
505
 
560
506
 
561
507
/**
562
508
 * Select features based on a bounding rectangle. Features can be retrieved
563
509
 * with calls to getFirstFeature and getNextFeature.
564
510
 * @param mbr QgsRect containing the extent to use in selecting features
565
511
 */
566
 
void QgsDelimitedTextProvider::select(QgsRect *rect, bool useIntersect)
 
512
void QgsDelimitedTextProvider::select(QgsRect * rect, bool useIntersect)
567
513
{
568
514
 
569
515
  // Setting a spatial filter doesn't make much sense since we have to
603
549
 * @param rect Bounding rectangle of search radius
604
550
 * @return std::vector containing QgsFeature objects that intersect rect
605
551
 */
606
 
std::vector<QgsFeature>& QgsDelimitedTextProvider::identify(QgsRect * rect)
 
552
std::vector < QgsFeature > &QgsDelimitedTextProvider::identify(QgsRect * rect)
607
553
{
608
554
  // reset the data source since we need to be able to read through
609
555
  // all features
610
556
  reset();
611
 
  std::cerr << "Attempting to identify features falling within "
612
 
    << rect->stringRep() << std::endl; 
 
557
  std::cerr << "Attempting to identify features falling within " << (const char *)rect->
 
558
    stringRep().local8Bit() << std::endl;
613
559
  // select the features
614
560
  select(rect);
615
561
#ifdef WIN32
616
562
  //TODO fix this later for win32
617
 
  std::vector<QgsFeature> feat;
 
563
  std::vector < QgsFeature > feat;
618
564
  return feat;
619
565
#endif
620
566
 
630
576
 
631
577
}
632
578
*/
633
 
int QgsDelimitedTextProvider::endian()
634
 
{
635
 
  char *chkEndian = new char[4];
636
 
  memset(chkEndian, '\0', 4);
637
 
  chkEndian[0] = 0xE8;
638
579
 
639
 
  int *ce = (int *) chkEndian;
640
 
  int retVal;
641
 
  if (232 == *ce)
642
 
    retVal = NDR;
643
 
  else
644
 
    retVal = XDR;
645
 
  delete[]chkEndian;
646
 
  return retVal;
647
 
}
648
580
 
649
581
// Return the extent of the layer
650
582
QgsRect *QgsDelimitedTextProvider::extent()
651
583
{
652
 
  return new QgsRect(mExtent->xMin(), mExtent->yMin(), mExtent->xMax(), mExtent->yMax());
653
 
}
654
 
 
655
 
/** 
656
 
 * Return the feature type
657
 
 */
658
 
int QgsDelimitedTextProvider::geometryType(){
659
 
  return 1; // WKBPoint
660
 
}
661
 
/** 
662
 
 * Return the feature type
663
 
 */
664
 
long QgsDelimitedTextProvider::featureCount(){
 
584
  return new QgsRect(mExtent->xMin(), mExtent->yMin(), mExtent->xMax(),
 
585
                     mExtent->yMax());
 
586
}
 
587
 
 
588
/** 
 
589
 * Return the feature type
 
590
 */
 
591
int QgsDelimitedTextProvider::geometryType() const
 
592
{
 
593
  return 1;                     // WKBPoint
 
594
}
 
595
 
 
596
/** 
 
597
 * Return the feature type
 
598
 */
 
599
long QgsDelimitedTextProvider::featureCount() const
 
600
{
665
601
  return mNumberFeatures;
666
602
}
667
603
 
668
604
/**
669
605
 * Return the number of fields
670
606
 */
671
 
int QgsDelimitedTextProvider::fieldCount(){
 
607
int QgsDelimitedTextProvider::fieldCount() const
 
608
{
672
609
  return attributeFields.size();
673
610
}
 
611
 
674
612
/**
675
613
 * Fetch attributes for a selected feature
676
614
 */
677
 
void QgsDelimitedTextProvider::getFeatureAttributes(int key, QgsFeature *f){
 
615
void QgsDelimitedTextProvider::getFeatureAttributes(int key, QgsFeature * f)
 
616
{
678
617
  //for (int i = 0; i < ogrFet->GetFieldCount(); i++) {
679
618
 
680
619
  //  // add the feature attributes to the tree
688
627
  //}
689
628
}
690
629
 
691
 
std::vector<QgsField>& QgsDelimitedTextProvider::fields(){
 
630
std::vector<QgsField> const & QgsDelimitedTextProvider::fields() const
 
631
{
692
632
  return attributeFields;
693
633
}
694
634
 
695
 
void QgsDelimitedTextProvider::reset(){
 
635
void QgsDelimitedTextProvider::reset()
 
636
{
696
637
  // Reset the file pointer to BOF
697
638
  mFile->reset();
698
639
  // Reset feature id to 0
699
640
  mFid = 0;
700
641
  // Skip ahead one line since first record is always assumed to be
701
642
  // the header record
702
 
  QTextStream stream( mFile );
 
643
  QTextStream stream(mFile);
703
644
  stream.readLine();
704
645
}
705
646
 
706
647
QString QgsDelimitedTextProvider::minValue(int position)
707
648
{
708
 
  if(position>=fieldCount())
 
649
  if (position >= fieldCount())
709
650
  {
710
 
    std::cerr << "Warning: access requested to invalid position "
711
 
      << "in QgsDelimitedTextProvider::minValue(..)" << std::endl;
 
651
    std::
 
652
      cerr << "Warning: access requested to invalid position " <<
 
653
      "in QgsDelimitedTextProvider::minValue(..)" << std::endl;
712
654
  }
713
 
  if(mMinMaxCacheDirty)
 
655
  if (mMinMaxCacheDirty)
714
656
  {
715
657
    fillMinMaxCash();
716
658
  }
717
 
  return QString::number(mMinMaxCache[position][0],'f',2);
 
659
  return QString::number(mMinMaxCache[position][0], 'f', 2);
718
660
}
719
661
 
720
662
 
721
663
QString QgsDelimitedTextProvider::maxValue(int position)
722
664
{
723
 
  if(position>=fieldCount())
 
665
  if (position >= fieldCount())
724
666
  {
725
 
    std::cerr << "Warning: access requested to invalid position "
726
 
      << "in QgsDelimitedTextProvider::maxValue(..)" << std::endl;
 
667
    std::
 
668
      cerr << "Warning: access requested to invalid position " <<
 
669
      "in QgsDelimitedTextProvider::maxValue(..)" << std::endl;
727
670
  }
728
 
  if(mMinMaxCacheDirty)
 
671
  if (mMinMaxCacheDirty)
729
672
  {
730
673
    fillMinMaxCash();
731
674
  }
732
 
  return QString::number(mMinMaxCache[position][1],'f',2);
 
675
  return QString::number(mMinMaxCache[position][1], 'f', 2);
733
676
}
734
677
 
735
678
void QgsDelimitedTextProvider::fillMinMaxCash()
736
679
{
737
 
  for(int i=0;i<fieldCount();i++)
 
680
  for (int i = 0; i < fieldCount(); i++)
738
681
  {
739
 
    mMinMaxCache[i][0]=DBL_MAX;
740
 
    mMinMaxCache[i][1]=-DBL_MAX;
 
682
    mMinMaxCache[i][0] = DBL_MAX;
 
683
    mMinMaxCache[i][1] = -DBL_MAX;
741
684
  }
742
685
 
743
686
  QgsFeature f;
746
689
  getNextFeature(f, true);
747
690
  do
748
691
  {
749
 
    for(int i=0;i<fieldCount();i++)
 
692
    for (int i = 0; i < fieldCount(); i++)
750
693
    {
751
 
      double value=(f.attributeMap())[i].fieldValue().toDouble();
752
 
      if(value<mMinMaxCache[i][0])
753
 
      {
754
 
        mMinMaxCache[i][0]=value;  
755
 
      }  
756
 
      if(value>mMinMaxCache[i][1])
757
 
      {
758
 
        mMinMaxCache[i][1]=value;  
 
694
      double value = (f.attributeMap())[i].fieldValue().toDouble();
 
695
      if (value < mMinMaxCache[i][0])
 
696
      {
 
697
        mMinMaxCache[i][0] = value;
 
698
      }
 
699
      if (value > mMinMaxCache[i][1])
 
700
      {
 
701
        mMinMaxCache[i][1] = value;
759
702
      }
760
703
    }
761
 
  }while(getNextFeature(f, true));
 
704
  }
 
705
  while (getNextFeature(f, true));
762
706
 
763
 
  mMinMaxCacheDirty=false;
 
707
  mMinMaxCacheDirty = false;
764
708
}
 
709
 
765
710
//TODO - add sanity check for shape file layers, to include cheking to
766
711
//       see if the .shp, .dbf, .shx files are all present and the layer
767
712
//       actually has features
768
 
bool QgsDelimitedTextProvider::isValid(){
 
713
bool QgsDelimitedTextProvider::isValid()
 
714
{
769
715
  return mValid;
770
716
}
771
717
 
775
721
bool QgsDelimitedTextProvider::boundsCheck(double x, double y)
776
722
{
777
723
  bool inBounds = (((x < mSelectionRectangle->xMax()) &&
778
 
        (x > mSelectionRectangle->xMin())) &&
779
 
      ((y < mSelectionRectangle->yMax()) &&
780
 
       (y > mSelectionRectangle->yMin())));
781
 
 // QString hit = inBounds?"true":"false";
 
724
                    (x > mSelectionRectangle->xMin())) &&
 
725
                   ((y < mSelectionRectangle->yMax()) &&
 
726
                    (y > mSelectionRectangle->yMin())));
 
727
  // QString hit = inBounds?"true":"false";
782
728
 
783
 
 // std::cerr << "Checking if " << x << ", " << y << " is in " << 
784
 
 //mSelectionRectangle->stringRep().ascii() << ": " << hit.ascii() << std::endl; 
 
729
  // std::cerr << "Checking if " << x << ", " << y << " is in " << 
 
730
  //mSelectionRectangle->stringRep().ascii() << ": " << hit.ascii() << std::endl; 
785
731
  return inBounds;
786
732
}
787
 
bool QgsDelimitedTextProvider::supportsSaveAsShapefile()
 
733
 
 
734
int QgsDelimitedTextProvider::capabilities() const
788
735
{
789
 
  return true;
 
736
    return QgsVectorDataProvider::SaveAsShapefile;
790
737
}
791
738
 
 
739
 
792
740
bool QgsDelimitedTextProvider::saveAsShapefile()
793
741
{
794
742
  // save the layer as a shapefile
795
743
  QString driverName = "ESRI Shapefile";
796
744
  OGRSFDriver *poDriver;
797
745
  OGRRegisterAll();
798
 
  poDriver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName((const char *)driverName );
 
746
  poDriver =
 
747
    OGRSFDriverRegistrar::GetRegistrar()->
 
748
    GetDriverByName((const char *)driverName.local8Bit());
799
749
  bool returnValue = true;
800
 
  if( poDriver != NULL )
 
750
  if (poDriver != NULL)
801
751
  {
802
752
    // get a name for the shapefile
803
753
    // Get a file to process, starting at the current directory
804
754
    // Set inital dir to last used in delimited text plugin
805
755
    QSettings settings;
806
 
 
807
 
    QString shapefileName = QFileDialog::getSaveFileName(
808
 
        settings.readEntry("/Qgis/delimited_text_plugin/text_path","./"),
809
 
        "Shapefiles (*.shp)",
810
 
        0,
811
 
        "open file dialog",
812
 
        "Save delimited text layer as shapefile" );
813
 
 
814
 
    if(!shapefileName.isNull())
 
756
    QString enc;
 
757
    QString shapefileName;
 
758
    QString filter =  QString("Shapefiles (*.shp)");
 
759
    QString dirName = settings.readEntry("/Qgis/delimited_text_plugin/text_path", "./");
 
760
 
 
761
    QgsEncodingFileDialog* openFileDialog = new QgsEncodingFileDialog(dirName,
 
762
                                                                      filter,
 
763
                                                                      0,
 
764
                                                                      QString("save file dialog"),
 
765
                                                                      QString("UTF-8"));
 
766
 
 
767
    // allow for selection of more than one file
 
768
    openFileDialog->setMode(QFileDialog::AnyFile);
 
769
    openFileDialog->setCaption(tr("Save layer as..."));
 
770
 
 
771
 
 
772
    if (openFileDialog->exec() == QDialog::Accepted)
 
773
    {
 
774
        shapefileName = openFileDialog->selectedFile();
 
775
        enc = openFileDialog->encoding();
 
776
    }
 
777
    else
 
778
    {
 
779
      return returnValue;
 
780
    }
 
781
 
 
782
    if (!shapefileName.isNull())
815
783
    {
816
784
      // add the extension if not present
817
 
      if(shapefileName.find(".shp") == -1)
 
785
      if (shapefileName.find(".shp") == -1)
818
786
      {
819
787
        shapefileName += ".shp";
820
788
      }
821
789
      OGRDataSource *poDS;
822
 
      // create the data source
823
 
      poDS = poDriver->CreateDataSource( (const char *)shapefileName, NULL );
824
 
      if( poDS != NULL )
 
790
      // create the data source, use local8Bit() for filename
 
791
      poDS = poDriver->CreateDataSource((const char *) shapefileName.local8Bit(), NULL);
 
792
      if (poDS != NULL)
825
793
      {
826
 
        std::cerr << "created datasource" << std::endl; 
827
 
        // datasource created, now create the output layer
 
794
        QTextCodec* saveCodec = QTextCodec::codecForName(enc.local8Bit());
 
795
        if(!saveCodec)
 
796
        {
 
797
#ifdef QGISDEBUG
 
798
          qWarning("error finding QTextCodec in QgsDelimitedTextProvider::saveAsShapefile()");
 
799
#endif
 
800
          saveCodec = QTextCodec::codecForLocale();
 
801
        }
 
802
 
 
803
        std::cerr << "created datasource" << std::endl;
 
804
        // datasource created, now create the output layer, use selected encoding.
828
805
        OGRLayer *poLayer;
829
 
        poLayer = poDS->CreateLayer((const char *)shapefileName.left(shapefileName.find(".shp")), NULL, static_cast<OGRwkbGeometryType>(1), NULL );
830
 
        if( poLayer != NULL )
 
806
        poLayer = poDS->CreateLayer(saveCodec->fromUnicode(shapefileName.
 
807
                            left(shapefileName.find(".shp"))), NULL,
 
808
                            static_cast < OGRwkbGeometryType > (1), NULL);
 
809
        if (poLayer != NULL)
831
810
        {
832
 
          std::cerr << "created layer" << std::endl; 
 
811
          std::cerr << "created layer" << std::endl;
833
812
          // calculate the field lengths
834
813
          int *lengths = getFieldLengths();
835
814
          // create the fields
836
 
          std::cerr << "creating " << attributeFields.size() << " fields" << std::endl; 
837
 
          for(int i = 0; i < attributeFields.size(); i++)
 
815
          std::cerr << "creating " << attributeFields.
 
816
            size() << " fields" << std::endl;
 
817
          for (int i = 0; i < attributeFields.size(); i++)
838
818
          {
839
819
            // check the field length - if > 10 we need to truncate it
840
820
            QgsField attrField = attributeFields[i];
841
 
            if(attrField.name().length() > 10)
 
821
            if (attrField.name().length() > 10)
842
822
            {
843
823
              attrField = attrField.name().left(10);
844
824
            }
845
825
            // all fields are created as string (for now)
846
 
            OGRFieldDefn fld(attrField.name(), OFTString);
 
826
            OGRFieldDefn fld(saveCodec->fromUnicode(attrField.name()), OFTString);
847
827
            // set the length for the field -- but we don't know what it is...
848
828
            fld.SetWidth(lengths[i]);
849
829
            // create the field
850
 
            std::cerr << "creating field " << attrField.name() << " width length " << lengths[i] << std::endl; 
851
 
            if(poLayer->CreateField(&fld) != OGRERR_NONE)
 
830
            std::cerr << "creating field " << (const char *)attrField.
 
831
              name().local8Bit() << " width length " << lengths[i] << std::endl;
 
832
            if (poLayer->CreateField(&fld) != OGRERR_NONE)
852
833
            {
853
 
              QMessageBox::warning(0, "Error", "Error creating field " + attrField.name());
 
834
              QMessageBox::warning(0, "Error",
 
835
                                   "Error creating field " + attrField.name());
854
836
            }
855
837
          }
856
838
          // read the delimited text file and create the features
857
 
          std::cerr << "Done creating fields" << std::endl; 
 
839
          std::cerr << "Done creating fields" << std::endl;
858
840
          // read the line
859
841
          reset();
860
 
          QTextStream stream( mFile );
 
842
          QTextStream stream(mFile);
861
843
          QString line;
862
 
          while ( !stream.atEnd() ) {
 
844
          while (!stream.atEnd())
 
845
          {
863
846
            line = stream.readLine(); // line of text excluding '\n'
864
 
            std::cerr << line << std::endl; 
 
847
            std::cerr << (const char *)line.local8Bit() << std::endl;
865
848
            // split the line
866
 
            QStringList parts = QStringList::split(QRegExp(mDelimiter), line, true);
867
 
            std::cerr << "Split line into " << parts.size() << std::endl; 
 
849
            QStringList parts =
 
850
              QStringList::split(QRegExp(mDelimiter), line, true);
 
851
            std::cerr << "Split line into " << parts.size() << std::endl;
868
852
 
869
853
            // create the feature
870
854
            OGRFeature *poFeature;
871
855
 
872
 
            poFeature = new OGRFeature( poLayer->GetLayerDefn() );
 
856
            poFeature = new OGRFeature(poLayer->GetLayerDefn());
873
857
 
874
858
            // iterate over the parts and set the fields
875
 
            std::cerr << "Setting the field values" << std::endl; 
 
859
            std::cerr << "Setting the field values" << std::endl;
876
860
            // set limit - we will ignore extra fields on the line
877
861
            int limit = attributeFields.size();
878
862
 
879
 
            if(parts.size() < limit){
880
 
            
 
863
            if (parts.size() < limit)
 
864
            {
 
865
 
881
866
              // this is bad - not enough values where supplied on the line
882
867
              // TODO We should inform the user about this...
883
868
            }
884
869
            else
885
870
            {
886
871
 
887
 
            for ( int i = 0; i < limit; i++ ) 
888
 
            {
889
 
              if(parts[i] != QString::null)
890
 
              {
891
 
                std::cerr << "Setting " << i << " "  << attributeFields[i].name() << " to " << parts[i] << std::endl; 
892
 
                poFeature->SetField(attributeFields[i].name(), parts[i]);
893
 
 
 
872
              for (int i = 0; i < limit; i++)
 
873
              {
 
874
                if (parts[i] != QString::null)
 
875
                {
 
876
                  std::cerr << "Setting " << i << " " << (const char *)attributeFields[i].
 
877
                    name().local8Bit() << " to " << (const char *)parts[i].local8Bit() << std::endl;
 
878
                  poFeature->SetField(saveCodec->fromUnicode(attributeFields[i].name()),
 
879
                                      saveCodec->fromUnicode(parts[i]));
 
880
 
 
881
                }
 
882
                else
 
883
                {
 
884
                  poFeature->SetField(saveCodec->fromUnicode(attributeFields[i].name()), "");
 
885
                }
 
886
              }
 
887
              std::cerr << "Field values set" << std::endl;
 
888
              // create the point
 
889
              OGRPoint *poPoint = new OGRPoint();
 
890
              QString sX = parts[fieldPositions[mXField]];
 
891
              QString sY = parts[fieldPositions[mYField]];
 
892
              poPoint->setX(sX.toDouble());
 
893
              poPoint->setY(sY.toDouble());
 
894
              std::cerr << "Setting geometry" << std::endl;
 
895
 
 
896
              poFeature->SetGeometryDirectly(poPoint);
 
897
              if (poLayer->CreateFeature(poFeature) != OGRERR_NONE)
 
898
              {
 
899
                std::cerr << "Failed to create feature in shapefile" << std::
 
900
                  endl;
894
901
              }
895
902
              else
896
903
              {
897
 
                poFeature->SetField(attributeFields[i].name(), "");
 
904
                std::cerr << "Added feature" << std::endl;
898
905
              }
899
 
            }
900
 
            std::cerr << "Field values set" << std::endl; 
901
 
            // create the point
902
 
            OGRPoint *poPoint = new OGRPoint();
903
 
            QString sX = parts[fieldPositions[mXField]];
904
 
            QString sY = parts[fieldPositions[mYField]];
905
 
            poPoint->setX(sX.toDouble());
906
 
            poPoint->setY(sY.toDouble());
907
 
            std::cerr << "Setting geometry" << std::endl; 
908
 
 
909
 
            poFeature->SetGeometryDirectly(poPoint);
910
 
            if(poLayer->CreateFeature(poFeature) != OGRERR_NONE)
911
 
            {
912
 
              std::cerr << "Failed to create feature in shapefile" << std::endl; 
913
 
            }
914
 
            else
915
 
            {
916
 
              std::cerr << "Added feature" << std::endl; 
917
 
            }
918
 
 
919
 
            delete poFeature;
920
 
          }
 
906
 
 
907
              delete poFeature;
 
908
            }
921
909
          }
922
910
          delete poDS;
923
911
        }
924
912
        else
925
913
        {
926
 
          QMessageBox::warning(0,"Error", "Layer creation failed");
 
914
          QMessageBox::warning(0, "Error", "Layer creation failed");
927
915
        }
928
916
 
929
917
      }
930
918
      else
931
919
      {
932
 
        QMessageBox::warning(0, "Error creating shapefile", 
933
 
            "The shapefile could not be created (" + shapefileName + ")");
 
920
        QMessageBox::warning(0, "Error creating shapefile",
 
921
                             "The shapefile could not be created (" +
 
922
                             shapefileName + ")");
934
923
      }
935
924
 
936
925
    }
938
927
  }
939
928
  else
940
929
  {
941
 
    QMessageBox::warning(0, "Driver not found", driverName +  " driver is not available");
 
930
    QMessageBox::warning(0, "Driver not found",
 
931
                         driverName + " driver is not available");
942
932
    returnValue = false;
943
933
  }
944
934
  return returnValue;
945
935
}
946
936
 
947
937
 
948
 
int* QgsDelimitedTextProvider::getFieldLengths()
 
938
int *QgsDelimitedTextProvider::getFieldLengths()
949
939
{
950
940
  // this function parses the entire data file and calculates the
951
941
  // max for each
954
944
  // empty)
955
945
  int *lengths = new int[attributeFields.size()];
956
946
  // init the lengths to zero
957
 
  for(int il=0; il < attributeFields.size(); il++)
 
947
  for (int il = 0; il < attributeFields.size(); il++)
958
948
  {
959
949
    lengths[il] = 0;
960
950
  }
961
 
  if(mValid){
 
951
  if (mValid)
 
952
  {
962
953
    reset();
963
954
    // read the line
964
 
    QTextStream stream( mFile );
 
955
    QTextStream stream(mFile);
965
956
    QString line;
966
 
    while ( !stream.atEnd() ) {
 
957
    while (!stream.atEnd())
 
958
    {
967
959
      line = stream.readLine(); // line of text excluding '\n'
968
960
      // split the line
969
961
      QStringList parts = QStringList::split(QRegExp(mDelimiter), line, true);
970
962
      // iterate over the parts and update the max value
971
 
      for ( int i = 0; i < parts.size(); i++ ) 
 
963
      for (int i = 0; i < parts.size(); i++)
972
964
      {
973
 
       if(parts[i] != QString::null)
974
 
       { 
975
 
       // std::cerr << "comparing length for " << parts[i] << " against max len of " << lengths[i] << std::endl; 
976
 
        if(parts[i].length() > lengths[i])
 
965
        if (parts[i] != QString::null)
977
966
        {
978
 
          lengths[i] = parts[i].length();
 
967
          // std::cerr << "comparing length for " << parts[i] << " against max len of " << lengths[i] << std::endl; 
 
968
          if (parts[i].length() > lengths[i])
 
969
          {
 
970
            lengths[i] = parts[i].length();
 
971
          }
979
972
        }
980
 
       }
981
973
 
982
974
      }
983
975
    }
984
976
  }
985
977
  return lengths;
986
978
}
 
979
 
987
980
/**
988
981
 * Class factory to return a pointer to a newly created 
989
982
 * QgsDelimitedTextProvider object
990
983
 */
991
 
QGISEXTERN QgsDelimitedTextProvider * classFactory(const char *uri)
 
984
QGISEXTERN QgsDelimitedTextProvider *classFactory(const QString *uri)
992
985
{
993
 
  return new QgsDelimitedTextProvider(uri);
 
986
  return new QgsDelimitedTextProvider(*uri);
994
987
}
 
988
 
995
989
/** Required key function (used to map the plugin to a data store type)
996
990
*/
997
 
QGISEXTERN QString providerKey(){
 
991
QGISEXTERN QString providerKey()
 
992
{
998
993
  return QString("delimitedtext");
999
994
}
 
995
 
1000
996
/**
1001
997
 * Required description function 
1002
998
 */
1003
 
QGISEXTERN QString description(){
 
999
QGISEXTERN QString description()
 
1000
{
1004
1001
  return QString("Delimited text data provider");
1005
 
 
1002
}
 
1003
 
1006
1004
/**
1007
1005
 * Required isProvider function. Used to determine if this shared library
1008
1006
 * is a data provider plugin
1009
1007
 */
1010
 
QGISEXTERN bool isProvider(){
 
1008
QGISEXTERN bool isProvider()
 
1009
{
1011
1010
  return true;
1012
1011
}
1013