1
/***************************************************************************
2
qgsshapefile.cpp - description
4
begin : Fri Dec 19 2003
5
copyright : (C) 2003 by Denis Antipov
7
***************************************************************************/
9
/***************************************************************************
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. *
16
***************************************************************************/
17
/* $Id: qgsshapefile.cpp 6214 2006-12-08 19:24:11Z wonder $ */
19
#include <QApplication>
20
#include <ogrsf_frmts.h>
21
#include <ogr_geometry.h>
28
#include <QProgressDialog>
33
#include "qgsdbfbase.h"
34
#include "cpl_error.h"
35
#include "qgsshapefile.h"
42
#include <netinet/in.h>
46
QgsShapeFile::QgsShapeFile(QString name, QString encoding){
50
ogrDataSource = OGRSFDriverRegistrar::Open(QFile::encodeName(filename).constData());
51
if (ogrDataSource != NULL){
53
ogrLayer = ogrDataSource->GetLayer(0);
54
features = ogrLayer->GetFeatureCount();
59
// init the geometry types
60
geometries << "NULL" << "POINT" << "LINESTRING" << "POLYGON" << "MULTPOINT"
61
<< "MULTILINESTRING" << "MULTIPOLYGON" << "GEOMETRYCOLLECTION";
63
codec = QTextCodec::codecForName(encoding.toLocal8Bit().data());
65
codec = QTextCodec::codecForLocale();
68
QgsShapeFile::~QgsShapeFile(){
69
if(ogrDataSource != 0)
71
// don't delete the layer if the datasource is bad -- (causes crash)
79
int QgsShapeFile::getFeatureCount(){
82
bool QgsShapeFile::scanGeometries()
84
int progressThreshold = 5;
85
int progressCount = 0;
86
QProgressDialog *sg = new QProgressDialog();
89
QString label = "Scanning ";
91
sg->setLabel(new QLabel(label));
93
qApp->processEvents();
98
while((feat = ogrLayer->GetNextFeature()))
100
qApp->processEvents();
102
// feat->DumpReadable(NULL);
103
OGRGeometry *geom = feat->GetGeometryRef();
106
QString gml = geom->exportToGML();
107
// std::cerr << gml << std::endl;
108
if(gml.find("gml:Multi") > -1)
110
// std::cerr << "MULTI Part Feature detected" << std::endl;
113
OGRFeatureDefn *fDef = feat->GetDefnRef();
114
OGRwkbGeometryType gType = fDef->GetGeomType();
115
// std::cerr << fDef->GetGeomType() << std::endl;
116
if(gType > currentType)
120
if(gType < currentType)
122
std::cerr << "Encountered inconsistent geometry type " << gType << std::endl;
127
ogrLayer->ResetReading();
128
geom_type = geometries[currentType];
129
if(multi && (geom_type.find("MULTI") == -1))
131
geom_type = "MULTI" + geom_type;
134
// std::cerr << "Geometry type is " << currentType << " (" << geometries[currentType] << ")" << std::endl;
137
QString QgsShapeFile::getFeatureClass(){
138
// scan the whole layer to try to determine the geometry
140
qApp->processEvents();
141
isMulti = scanGeometries();
143
// skip features without geometry
144
while ((feat = ogrLayer->GetNextFeature()) != NULL) {
145
if (feat->GetGeometryRef())
149
OGRGeometry *geom = feat->GetGeometryRef();
151
/* OGR doesn't appear to report geometry type properly
152
* for a layer containing both polygon and multipolygon
155
// get the feature type from the layer
156
OGRFeatureDefn * gDef = ogrLayer->GetLayerDefn();
157
OGRwkbGeometryType gType = gDef->GetGeomType();
158
geom_type = QGis::qgisFeatureTypes[gType];
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;
169
QString file(filename);
170
file.replace(file.length()-3, 3, "dbf");
172
std::ifstream dbf((const char*)file, std::ios::in | std::ios::binary);
175
dbf.read((char *)&dbh, sizeof(dbh));
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.
183
unsigned char *byte = reinterpret_cast<unsigned char *>(&dbh.size_hdr);
184
unsigned char t = *byte; *byte = *(byte+1); *(byte+1) = t;
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");
195
column_types.push_back("int");
197
case 'F': column_types.push_back("float");
199
case 'D': column_types.push_back("date");
202
str_type= QString("varchar(%1)").arg(fda.field_length);
203
column_types.push_back(str_type);
205
case 'L': column_types.push_back("boolean");
208
column_types.push_back("varchar(256)");
213
int numFields = feat->GetFieldCount();
214
for(int n=0; n<numFields; n++)
216
QString s = codec->toUnicode(feat->GetFieldDefnRef(n)->GetNameRef());
217
column_names.push_back(s);
224
ogrLayer->ResetReading();
225
return valid?geom_type:QString::null;
228
bool QgsShapeFile::is_valid(){
232
QString QgsShapeFile::getName(){
236
QString QgsShapeFile::getTable(){
240
void QgsShapeFile::setTable(QString new_table){
241
new_table.replace("\'","\\'");
242
new_table.replace("\\","\\\\");
243
table_name = new_table;
246
void QgsShapeFile::setDefaultTable(){
247
QString name(filename);
248
name = name.section('/', -1);
249
table_name = name.section('.', 0, 0);
252
void QgsShapeFile::setColumnNames(QStringList columns)
254
column_names.clear();
255
for (QStringList::Iterator it = columns.begin(); it != columns.end(); ++it)
257
column_names.push_back(*it);
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;
265
// Mangle the table name to make it PG compliant by replacing spaces with
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())
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;
277
std::cerr << query.toLocal8Bit().data() << std::endl;
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)
285
std::cerr << query.toLocal8Bit().data() << std::endl;
290
std::cerr << query.toLocal8Bit().data() << std::endl;
292
PGresult *res = PQexec(conn, (const char *)query);
294
if(PQresultStatus(res)!=PGRES_COMMAND_OK){
295
// flag error and send query and error message to stdout on debug
297
qWarning(PQresultErrorMessage(res));
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){
311
qWarning(PQresultErrorMessage(res));
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);
326
//adding the data into the table
327
for(int m=0;m<features && result; m++){
328
if(import_cancelled){
333
OGRFeature *feat = ogrLayer->GetNextFeature();
335
OGRGeometry *geom = feat->GetGeometryRef();
337
query = "INSERT INTO "+schema+"."+table_name+QString(" VALUES( %1, ").arg(m);
339
int num = geom->WkbSize();
340
char * geo_temp = new char[num*3];
341
geom->exportToWkt(&geo_temp);
342
QString geometry(geo_temp);
345
for(int n=0; n<column_types.size(); n++){
346
if(column_types[n] == "int" || column_types[n] == "float")
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());
358
// add escaped value to the query
359
query += val; //esc_str;
360
query += QString(quotes + ", ");
364
query += QString("GeometryFromText(\'")+geometry+QString("\', ")+srid+QString("))");
365
// std::cerr << query << std::endl;
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
372
qWarning(PQresultErrorMessage(res));
378
pro.setValue(pro.value()+1);
379
qApp->processEvents();
385
// create the GIST index if the the load was successful
388
// prompt user to see if they want to build the index and warn
389
// them about the potential time-cost
391
ogrLayer->ResetReading();
395
void QgsShapeFile::cancelImport(){
396
import_cancelled = true;