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

« back to all changes in this revision

Viewing changes to src/plugins/spit/qgsshapefile.cpp

  • Committer: Bazaar Package Importer
  • Author(s): William Grant
  • Date: 2007-05-06 13:42:32 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20070506134232-pyli6t388w5asd8x
Tags: 0.8.0-3ubuntu1
* Merge from Debian unstable. Remaining Ubuntu changes:
  - debian/rules, debian/qgis.install, debian/qgis.dirs debian/qgis.desktop:
    Add and install .desktop.
* debian/qgis.desktop: Remove Applications category; it's not real.
* Modify Maintainer value to match Debian-Maintainer-Field Spec

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
                          qgsshapefile.cpp  -  description
 
3
                             -------------------
 
4
    begin                : Fri Dec 19 2003
 
5
    copyright            : (C) 2003 by Denis Antipov
 
6
    email                : 
 
7
 ***************************************************************************/
 
8
 
 
9
/***************************************************************************
 
10
 *                                                                         *
 
11
 *   This program is free software; you can redistribute it and/or modify  *
 
12
 *   it under the terms of the GNU General Public License as published by  *
 
13
 *   the Free Software Foundation; either version 2 of the License, or     *
 
14
 *   (at your option) any later version.                                   *
 
15
 *                                                                         *
 
16
 ***************************************************************************/
 
17
/* $Id: qgsshapefile.cpp 6214 2006-12-08 19:24:11Z wonder $ */
 
18
 
 
19
#include <QApplication>
 
20
#include <ogrsf_frmts.h>
 
21
#include <ogr_geometry.h>
 
22
#include <string>
 
23
#include <iostream>
 
24
#include <fstream>
 
25
#include <cstdio>
 
26
 
 
27
#include <QFile>
 
28
#include <QProgressDialog>
 
29
#include <QString>
 
30
#include <QLabel>
 
31
#include <QTextCodec>
 
32
 
 
33
#include "qgsdbfbase.h"
 
34
#include "cpl_error.h"
 
35
#include "qgsshapefile.h"
 
36
#include "qgis.h"
 
37
 
 
38
// for htonl
 
39
#ifdef WIN32
 
40
#include <winsock.h>
 
41
#else
 
42
#include <netinet/in.h>
 
43
#endif    
 
44
 
 
45
 
 
46
QgsShapeFile::QgsShapeFile(QString name, QString encoding){
 
47
  filename = name;
 
48
  features = 0;
 
49
  OGRRegisterAll();
 
50
  ogrDataSource = OGRSFDriverRegistrar::Open(QFile::encodeName(filename).constData());
 
51
  if (ogrDataSource != NULL){
 
52
    valid = true;
 
53
    ogrLayer = ogrDataSource->GetLayer(0);
 
54
    features = ogrLayer->GetFeatureCount();
 
55
  }
 
56
  else
 
57
    valid = false;
 
58
  setDefaultTable();
 
59
  // init the geometry types
 
60
  geometries << "NULL" << "POINT" << "LINESTRING" << "POLYGON" << "MULTPOINT" 
 
61
    << "MULTILINESTRING" << "MULTIPOLYGON" << "GEOMETRYCOLLECTION";
 
62
  
 
63
  codec = QTextCodec::codecForName(encoding.toLocal8Bit().data());
 
64
  if (!codec)
 
65
    codec = QTextCodec::codecForLocale();
 
66
}
 
67
 
 
68
QgsShapeFile::~QgsShapeFile(){
 
69
  if(ogrDataSource != 0)
 
70
  {
 
71
    // don't delete the layer if the datasource is bad -- (causes crash)
 
72
    delete ogrLayer;
 
73
  }
 
74
  delete ogrDataSource;
 
75
  delete filename;
 
76
  delete geom_type;
 
77
}
 
78
 
 
79
int QgsShapeFile::getFeatureCount(){
 
80
  return features;
 
81
}
 
82
bool QgsShapeFile::scanGeometries()
 
83
{
 
84
  int progressThreshold = 5;
 
85
  int progressCount = 0;
 
86
  QProgressDialog *sg = new QProgressDialog();
 
87
  sg->setMinimum(0);
 
88
  sg->setMaximum(0);
 
89
  QString label = "Scanning ";
 
90
  label += filename;
 
91
  sg->setLabel(new QLabel(label));
 
92
  sg->show();
 
93
  qApp->processEvents();
 
94
 
 
95
  OGRFeature *feat;
 
96
  int currentType = 0;
 
97
  bool multi = false;
 
98
  while((feat = ogrLayer->GetNextFeature()))
 
99
  {
 
100
      qApp->processEvents();
 
101
 
 
102
    //    feat->DumpReadable(NULL);
 
103
    OGRGeometry *geom = feat->GetGeometryRef();
 
104
    if(geom)
 
105
    {
 
106
      QString gml =  geom->exportToGML();
 
107
      //      std::cerr << gml << std::endl; 
 
108
      if(gml.find("gml:Multi") > -1)
 
109
      {
 
110
        //   std::cerr << "MULTI Part Feature detected" << std::endl; 
 
111
        multi = true;
 
112
      }
 
113
      OGRFeatureDefn *fDef = feat->GetDefnRef();
 
114
      OGRwkbGeometryType gType = fDef->GetGeomType();
 
115
      //      std::cerr << fDef->GetGeomType() << std::endl; 
 
116
      if(gType > currentType)
 
117
      {
 
118
        currentType = gType;
 
119
      }
 
120
      if(gType < currentType)
 
121
      {
 
122
        std::cerr << "Encountered inconsistent geometry type " << gType << std::endl; 
 
123
      }
 
124
 
 
125
    }
 
126
  }
 
127
  ogrLayer->ResetReading();
 
128
  geom_type = geometries[currentType];
 
129
  if(multi && (geom_type.find("MULTI") == -1))
 
130
  {
 
131
    geom_type = "MULTI" + geom_type;
 
132
  }
 
133
  delete sg;
 
134
  //  std::cerr << "Geometry type is " << currentType << " (" << geometries[currentType] << ")" << std::endl; 
 
135
  return multi;
 
136
}
 
137
QString QgsShapeFile::getFeatureClass(){
 
138
  // scan the whole layer to try to determine the geometry
 
139
  // type. 
 
140
  qApp->processEvents();
 
141
  isMulti = scanGeometries();
 
142
  OGRFeature *feat;
 
143
  // skip features without geometry
 
144
  while ((feat = ogrLayer->GetNextFeature()) != NULL) {
 
145
    if (feat->GetGeometryRef())
 
146
      break;
 
147
  }
 
148
  if(feat){
 
149
    OGRGeometry *geom = feat->GetGeometryRef();
 
150
    if(geom){
 
151
      /* OGR doesn't appear to report geometry type properly
 
152
       * for a layer containing both polygon and multipolygon
 
153
       * entities
 
154
       *
 
155
      // get the feature type from the layer
 
156
      OGRFeatureDefn * gDef = ogrLayer->GetLayerDefn();
 
157
      OGRwkbGeometryType gType = gDef->GetGeomType();
 
158
      geom_type = QGis::qgisFeatureTypes[gType];
 
159
      */
 
160
      //geom_type = QString(geom->getGeometryName());
 
161
      //geom_type = "GEOMETRY";
 
162
      std::cerr << "Preparing to escape " << geom_type.toLocal8Bit().data() << std::endl; 
 
163
      char * esc_str = new char[geom_type.length()*2+1];
 
164
      PQescapeString(esc_str, (const char *)geom_type, geom_type.length());
 
165
      geom_type = QString(esc_str);
 
166
      std::cerr << "After escaping, geom_type is : " << geom_type.toLocal8Bit().data() << std::endl;  
 
167
      delete[] esc_str;
 
168
      
 
169
      QString file(filename);
 
170
      file.replace(file.length()-3, 3, "dbf");
 
171
      // open the dbf file
 
172
      std::ifstream dbf((const char*)file, std::ios::in | std::ios::binary);
 
173
      // read header
 
174
      DbaseHeader dbh;
 
175
      dbf.read((char *)&dbh, sizeof(dbh));
 
176
      // Check byte order
 
177
      if(htonl(1) == 1) 
 
178
      {
 
179
        /* DbaseHeader is stored in little-endian format.
 
180
         * The num_recs, size_hdr and size_rec fields must be byte-swapped when read
 
181
         * on a big-endian processor. Currently only size_hdr is used.
 
182
         */
 
183
        unsigned char *byte = reinterpret_cast<unsigned char *>(&dbh.size_hdr);
 
184
        unsigned char t = *byte; *byte = *(byte+1); *(byte+1) = t;
 
185
      }
 
186
 
 
187
      Fda fda;
 
188
      QString str_type = "varchar(";
 
189
      for(int field_count = 0, bytes_read = sizeof(dbh); bytes_read < dbh.size_hdr-1; field_count++, bytes_read +=sizeof(fda)){
 
190
        dbf.read((char *)&fda, sizeof(fda));
 
191
        switch(fda.field_type){
 
192
          case 'N': if((int)fda.field_decimal>0)
 
193
                      column_types.push_back("float");
 
194
                    else
 
195
                      column_types.push_back("int");          
 
196
                    break;
 
197
          case 'F': column_types.push_back("float");
 
198
                    break;                    
 
199
          case 'D': column_types.push_back("date");
 
200
                    break;
 
201
          case 'C': 
 
202
                    str_type= QString("varchar(%1)").arg(fda.field_length);
 
203
                    column_types.push_back(str_type);
 
204
                    break;
 
205
          case 'L': column_types.push_back("boolean");
 
206
                    break;
 
207
          default:
 
208
                    column_types.push_back("varchar(256)");
 
209
                    break;
 
210
        }
 
211
      }
 
212
      dbf.close();
 
213
      int numFields = feat->GetFieldCount();
 
214
      for(int n=0; n<numFields; n++)
 
215
      {
 
216
        QString s = codec->toUnicode(feat->GetFieldDefnRef(n)->GetNameRef());
 
217
        column_names.push_back(s);
 
218
      }
 
219
      
 
220
    }else valid = false;
 
221
    delete feat;
 
222
  }else valid = false;
 
223
  
 
224
  ogrLayer->ResetReading();    
 
225
  return valid?geom_type:QString::null;
 
226
}
 
227
 
 
228
bool QgsShapeFile::is_valid(){
 
229
  return valid;
 
230
}
 
231
 
 
232
QString QgsShapeFile::getName(){
 
233
  return filename;
 
234
}
 
235
 
 
236
QString QgsShapeFile::getTable(){
 
237
  return table_name;
 
238
}
 
239
 
 
240
void QgsShapeFile::setTable(QString new_table){
 
241
  new_table.replace("\'","\\'");
 
242
  new_table.replace("\\","\\\\");
 
243
  table_name = new_table;
 
244
}
 
245
 
 
246
void QgsShapeFile::setDefaultTable(){
 
247
  QString name(filename);
 
248
  name = name.section('/', -1);
 
249
  table_name = name.section('.', 0, 0);
 
250
}
 
251
 
 
252
void QgsShapeFile::setColumnNames(QStringList columns)
 
253
{
 
254
  column_names.clear();
 
255
  for (QStringList::Iterator it = columns.begin(); it != columns.end(); ++it) 
 
256
  {
 
257
    column_names.push_back(*it);       
 
258
  }
 
259
}
 
260
 
 
261
bool QgsShapeFile::insertLayer(QString dbname, QString schema, QString geom_col, QString srid, PGconn * conn, QProgressDialog& pro, bool &fin){
 
262
  connect(&pro, SIGNAL(cancelled()), this, SLOT(cancelImport()));
 
263
  import_cancelled = false;
 
264
  bool result = true;
 
265
  // Mangle the table name to make it PG compliant by replacing spaces with 
 
266
  // underscores
 
267
  table_name = table_name.replace(" ","_");
 
268
  QString query = "CREATE TABLE "+schema+"."+table_name+"(gid int4 PRIMARY KEY, ";
 
269
  for(int n=0; n<column_names.size() && result; n++){
 
270
    if(!column_names[n][0].isLetter())
 
271
      result = false;
 
272
    char * esc_str = new char[column_names[n].length()*2+1];
 
273
    std::cerr << "Escaping " << column_names[n].toLocal8Bit().data() << " to ";
 
274
    PQescapeString(esc_str, (const char *)column_names[n].lower(), column_names[n].length());
 
275
    std::cerr << esc_str << std::endl; 
 
276
    query += esc_str;
 
277
    std::cerr << query.toLocal8Bit().data() << std::endl; 
 
278
    query += " ";
 
279
    std::cerr << query.toLocal8Bit().data() << std::endl; 
 
280
    query += column_types[n];
 
281
    std::cerr << query.toLocal8Bit().data() << std::endl; 
 
282
    if(n<column_names.size()-1)
 
283
    {
 
284
      query += ", ";
 
285
      std::cerr << query.toLocal8Bit().data() << std::endl; 
 
286
    }
 
287
    delete[] esc_str;
 
288
  }
 
289
  query += " )";
 
290
      std::cerr << query.toLocal8Bit().data() << std::endl; 
 
291
 
 
292
  PGresult *res = PQexec(conn, (const char *)query);
 
293
  qWarning(query);
 
294
  if(PQresultStatus(res)!=PGRES_COMMAND_OK){
 
295
    // flag error and send query and error message to stdout on debug
 
296
    result = false;
 
297
    qWarning(PQresultErrorMessage(res));
 
298
  }
 
299
  else {
 
300
    PQclear(res);
 
301
  }
 
302
 
 
303
  query = "SELECT AddGeometryColumn(\'" + schema + "\', \'" + table_name + "\', \'"+geom_col+"\', " + srid +
 
304
    ", \'" + geom_type + "\', 2)";            
 
305
  if(result) res = PQexec(conn, (const char *)query);
 
306
  if(PQresultStatus(res)!=PGRES_TUPLES_OK){
 
307
    result = false;    
 
308
  }
 
309
  else{
 
310
    qWarning(query);
 
311
    qWarning(PQresultErrorMessage(res));
 
312
    PQclear(res);
 
313
  }
 
314
  if(isMulti)
 
315
  {
 
316
    // drop the check constraint 
 
317
    // TODO This whole concept needs to be changed to either
 
318
    // convert the geometries to the same type or allow
 
319
    // multiple types in the check constraint. For now, we
 
320
    // just drop the constraint...
 
321
    query = "alter table " + table_name + " drop constraint \"$2\"";
 
322
    // XXX tacky - we don't even check the result...
 
323
    PQexec(conn, (const char*)query);
 
324
  }
 
325
      
 
326
  //adding the data into the table
 
327
  for(int m=0;m<features && result; m++){
 
328
    if(import_cancelled){
 
329
      fin = true;
 
330
      break;
 
331
    }
 
332
 
 
333
    OGRFeature *feat = ogrLayer->GetNextFeature();
 
334
    if(feat){
 
335
      OGRGeometry *geom = feat->GetGeometryRef();
 
336
      if(geom){
 
337
        query = "INSERT INTO "+schema+"."+table_name+QString(" VALUES( %1, ").arg(m);
 
338
 
 
339
        int num = geom->WkbSize();
 
340
        char * geo_temp = new char[num*3];
 
341
        geom->exportToWkt(&geo_temp);
 
342
        QString geometry(geo_temp);
 
343
 
 
344
        QString quotes;
 
345
        for(int n=0; n<column_types.size(); n++){
 
346
          if(column_types[n] == "int" || column_types[n] == "float")
 
347
            quotes = " ";
 
348
          else
 
349
            quotes = "\'";
 
350
          query += quotes;
 
351
 
 
352
          // escape the string value
 
353
          QString val = codec->toUnicode(feat->GetFieldAsString(n));
 
354
          val.replace("'", "''");
 
355
          //char * esc_str = new char[val.length()*2+1];
 
356
          //PQescapeString(esc_str, (const char *)val.lower().utf8(), val.length());
 
357
 
 
358
          // add escaped value to the query 
 
359
          query += val; //esc_str;
 
360
          query += QString(quotes + ", ");
 
361
 
 
362
          //delete[] esc_str;
 
363
        }
 
364
        query += QString("GeometryFromText(\'")+geometry+QString("\', ")+srid+QString("))");
 
365
    //    std::cerr << query << std::endl; 
 
366
 
 
367
        if(result)
 
368
          res = PQexec(conn, (const char *)query.utf8());
 
369
        if(PQresultStatus(res)!=PGRES_COMMAND_OK){
 
370
          // flag error and send query and error message to stdout on debug
 
371
          result = false;
 
372
          qWarning(PQresultErrorMessage(res));
 
373
        }
 
374
        else {
 
375
          PQclear(res);
 
376
        }
 
377
 
 
378
        pro.setValue(pro.value()+1);
 
379
        qApp->processEvents();
 
380
        delete[] geo_temp;
 
381
      }
 
382
      delete feat;
 
383
    }
 
384
  }
 
385
  // create the GIST index if the the load was successful
 
386
  if(result)
 
387
  {
 
388
    // prompt user to see if they want to build the index and warn
 
389
    // them about the potential time-cost
 
390
  }
 
391
  ogrLayer->ResetReading();
 
392
  return result;
 
393
}
 
394
 
 
395
void QgsShapeFile::cancelImport(){
 
396
  import_cancelled = true;
 
397
}