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

« back to all changes in this revision

Viewing changes to src/plugins/spit/qgsspit.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
                         qgsspit.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: qgsspit.cpp 6290 2006-12-20 04:51:35Z telwertowski $ */
 
18
 
 
19
#include <QMessageBox>
 
20
#include <QComboBox>
 
21
#include <QFileDialog>
 
22
#include <QProgressDialog>
 
23
#include <QRegExp>
 
24
#include <QFile>
 
25
#include <QSettings>
 
26
#include <QPixmap>
 
27
#include <QHeaderView>
 
28
#include <QTextCodec>
 
29
 
 
30
#include <iostream>
 
31
    
 
32
#include "qgsencodingfiledialog.h"
 
33
 
 
34
#include "qgspgutil.h"
 
35
#include "qgsspit.h"
 
36
#include "qgsconnectiondialog.h"
 
37
#include "qgseditreservedwordsdialog.h"
 
38
#include "qgsmessageviewer.h"
 
39
#include "spiticon.xpm"
 
40
#include "spit_icons.h"
 
41
 
 
42
// Qt implementation of alignment() + changed the numeric types to be shown on the left as well
 
43
/* Is this still needed? Numbers in Qt4 table seem to be left justified by default.
 
44
int Q3TableItem::alignment() const
 
45
{
 
46
  bool num;
 
47
  bool ok1 = FALSE, ok2 = FALSE;
 
48
  ( void ) txt.toInt( &ok1 );
 
49
  if ( !ok1 )
 
50
    ( void ) txt.toDouble( &ok2 );
 
51
  num = ok1 || ok2;
 
52
 
 
53
  return ( num ? Qt::AlignLeft : Qt::AlignLeft ) | Qt::AlignVCenter;
 
54
}
 
55
*/
 
56
 
 
57
QgsSpit::QgsSpit( QWidget *parent, Qt::WFlags fl ) : QDialog( parent, fl )
 
58
{
 
59
  setupUi(this);
 
60
  QPixmap icon;
 
61
  icon = QPixmap( spitIcon );
 
62
  setIcon( icon );
 
63
 
 
64
  // Set up the table column headers
 
65
  tblShapefiles->setColumnCount(5);
 
66
  QStringList headerText;
 
67
  headerText << tr("File Name") << tr("Feature Class") << tr("Features") 
 
68
             << tr("DB Relation Name") << tr("Schema");
 
69
  tblShapefiles->setHorizontalHeaderLabels(headerText);
 
70
  tblShapefiles->verticalHeader()->hide();
 
71
  tblShapefiles->horizontalHeader()->setStretchLastSection(true);
 
72
 
 
73
  populateConnectionList();
 
74
  defSrid = -1;
 
75
  defGeom = "the_geom";
 
76
  total_features = 0;
 
77
 
 
78
  chkUseDefaultSrid->setChecked( true );
 
79
  chkUseDefaultGeom->setChecked( true );
 
80
  useDefaultSrid();
 
81
  useDefaultGeom();
 
82
 
 
83
  schema_list << "public";
 
84
  gl_key = "/PostgreSQL/connections/";
 
85
  getSchema();
 
86
 
 
87
  // Install a delegate that provides the combo box widget for
 
88
  // changing the schema (but there can only be one delegate per
 
89
  // table, so it also provides edit widgets for the textual columns).
 
90
  // This needs to be done after the call to getSchema() so that
 
91
  // schema_list is populated. 
 
92
  ShapefileTableDelegate* delegate = new ShapefileTableDelegate(tblShapefiles, schema_list);
 
93
  tblShapefiles->setItemDelegate(delegate);
 
94
 
 
95
  // Now that everything is in the table, adjust the column sizes
 
96
  tblShapefiles->resizeColumnsToContents();
 
97
}
 
98
 
 
99
QgsSpit::~QgsSpit()
 
100
{}
 
101
 
 
102
void QgsSpit::populateConnectionList()
 
103
{
 
104
  QSettings settings;
 
105
  QStringList keys = settings.subkeyList( "/PostgreSQL/connections" );
 
106
  QStringList::Iterator it = keys.begin();
 
107
  cmbConnections->clear();
 
108
  while ( it != keys.end() )
 
109
  {
 
110
    cmbConnections->insertItem( *it );
 
111
    ++it;
 
112
  }
 
113
}
 
114
 
 
115
void QgsSpit::newConnection()
 
116
{
 
117
  QgsConnectionDialog * con = new QgsConnectionDialog( this, tr("New Connection") );
 
118
 
 
119
  if ( con->exec() )
 
120
  {
 
121
    populateConnectionList();
 
122
    getSchema();
 
123
  }
 
124
}
 
125
 
 
126
void QgsSpit::editConnection()
 
127
{
 
128
  QgsConnectionDialog * con = new QgsConnectionDialog( this, cmbConnections->currentText() );
 
129
  if ( con->exec() )
 
130
  {
 
131
    con->saveConnection();
 
132
    getSchema();
 
133
  }
 
134
}
 
135
 
 
136
void QgsSpit::removeConnection()
 
137
{
 
138
  QSettings settings;
 
139
  QString key = "/PostgreSQL/connections/" + cmbConnections->currentText();
 
140
  QString msg = tr("Are you sure you want to remove the [") + cmbConnections->currentText() + tr("] connection and all associated settings?");
 
141
  int result = QMessageBox::information( this, tr("Confirm Delete"), msg, tr("Yes"), tr("No") );
 
142
  if ( result == 0 )
 
143
  {
 
144
    settings.removeEntry( key + "/host" );
 
145
    settings.removeEntry( key + "/database" );
 
146
    settings.removeEntry( key + "/port" );
 
147
    settings.removeEntry( key + "/username" );
 
148
    settings.removeEntry( key + "/password" );
 
149
    settings.removeEntry( key + "/save" );
 
150
 
 
151
    cmbConnections->removeItem( cmbConnections->currentItem() );
 
152
    getSchema();
 
153
  }
 
154
}
 
155
 
 
156
void QgsSpit::addFile()
 
157
{
 
158
  QString error1 = "";
 
159
  QString error2 = "";
 
160
  bool exist;
 
161
  bool is_error = false;
 
162
  QSettings settings;
 
163
 
 
164
  QgsEncodingFileDialog dlg(this,
 
165
                        tr("Add Shapefiles"),
 
166
                        settings.readEntry( "/Plugin-Spit/last_directory" ),
 
167
                        tr("Shapefiles (*.shp);;All files (*.*)"),
 
168
                        settings.readEntry( "/Plugin-Spit/last_encoding" ) );
 
169
  dlg.setMode(QFileDialog::ExistingFiles);
 
170
  
 
171
  if (dlg.exec() != QDialog::Accepted)
 
172
    return;
 
173
  QStringList files = dlg.selectedFiles();
 
174
 
 
175
  if ( files.size() > 0 )
 
176
  {
 
177
    // Save the directory for future use
 
178
    QFileInfo fi( files[ 0 ] );
 
179
    settings.writeEntry( "/Plugin-Spit/last_directory", fi.dirPath( true ) );
 
180
    settings.writeEntry( "/Plugin-Spit/last_encoding", dlg.encoding());
 
181
  }
 
182
  // Process the files
 
183
  for ( QStringList::Iterator it = files.begin(); it != files.end(); ++it )
 
184
  {
 
185
    exist = false;
 
186
    is_error = false;
 
187
 
 
188
    // Check to ensure that we don't insert the same file twice
 
189
    QList<QTableWidgetItem*> items = tblShapefiles->findItems(*it, 
 
190
                                                        Qt::MatchExactly);
 
191
    if (items.count() > 0)
 
192
    {
 
193
      exist = true;
 
194
    }
 
195
 
 
196
    if ( !exist )
 
197
    {
 
198
      // check other files: file.dbf and file.shx
 
199
      QString name = *it;
 
200
      if ( !QFile::exists( name.left( name.length() - 3 ) + "dbf" ) )
 
201
      {
 
202
        is_error = true;
 
203
      }
 
204
      else if ( !QFile::exists( name.left( name.length() - 3 ) + "shx" ) )
 
205
      {
 
206
        is_error = true;
 
207
      }
 
208
 
 
209
      if ( !is_error )
 
210
      {
 
211
        QgsShapeFile * file = new QgsShapeFile( name, dlg.encoding() );
 
212
        if ( file->is_valid() )
 
213
        {
 
214
          /* XXX getFeatureClass actually does a whole bunch
 
215
           * of things and is probably better named 
 
216
           * something else
 
217
           */
 
218
          QString featureClass = file->getFeatureClass();
 
219
          fileList.push_back( file );
 
220
 
 
221
          QTableWidgetItem *filenameItem       = new QTableWidgetItem( name );
 
222
          QTableWidgetItem *featureClassItem   = new QTableWidgetItem( featureClass );
 
223
          QTableWidgetItem *featureCountItem   = new QTableWidgetItem( QString( "%1" ).arg( file->getFeatureCount() ) );
 
224
          // Sanitize the relation name to make it pg friendly
 
225
          QString relName = file->getTable().replace(QRegExp("\\s"), "_");
 
226
          QTableWidgetItem *dbRelationNameItem = new QTableWidgetItem( relName );
 
227
          QTableWidgetItem *dbSchemaNameItem   = new QTableWidgetItem( cmbSchema->currentText() );
 
228
 
 
229
          // All items are editable except for these two
 
230
          filenameItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
 
231
          featureCountItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
 
232
 
 
233
          int row = tblShapefiles->rowCount();
 
234
          tblShapefiles->insertRow( row );
 
235
          tblShapefiles->setItem( row, ColFILENAME, filenameItem );
 
236
          tblShapefiles->setItem( row, ColFEATURECLASS, featureClassItem );
 
237
          tblShapefiles->setItem( row, ColFEATURECOUNT, featureCountItem );
 
238
          tblShapefiles->setItem( row, ColDBRELATIONNAME, dbRelationNameItem );
 
239
          tblShapefiles->setItem( row, ColDBSCHEMA, dbSchemaNameItem );
 
240
 
 
241
          total_features += file->getFeatureCount();
 
242
 
 
243
          // check for postgresql reserved words
 
244
          // First get an instance of the PG utility class
 
245
          QgsPgUtil *pgu = QgsPgUtil::instance();
 
246
          bool hasReservedWords = false;
 
247
          // if a reserved word is found, set the flag so the "adjustment"
 
248
          // dialog can be presented to the user
 
249
          hasReservedWords = false;
 
250
          for ( int i = 0; i < file->column_names.size(); i++ )
 
251
          {
 
252
            if ( pgu->isReserved( file->column_names[ i ] ) )
 
253
            {
 
254
              hasReservedWords = true;
 
255
            }
 
256
          }
 
257
          // Why loop through all of them and then turn around and test
 
258
          // the flag? Because if there are reserved words, we want to
 
259
          // add all columns to the listview so the user can have the
 
260
          // opportunity to change them.
 
261
          if ( hasReservedWords )
 
262
          {
 
263
            // show the dialog for adjusting reserved words. Reserved
 
264
            // words are displayed differently so they are easy to spot
 
265
            QgsEditReservedWordsDialog * srw = new QgsEditReservedWordsDialog( this );
 
266
            srw->setCaption( file->getTable().upper() + tr(" - Edit Column Names") );
 
267
            // load the reserved words list
 
268
            srw->setReservedWords( pgu->reservedWords() );
 
269
            // load the columns and set their status
 
270
            for ( int i = 0; i < file->column_names.size(); i++ )
 
271
            {
 
272
              srw->addColumn( file->column_names[ i ],
 
273
                              pgu->isReserved( file->column_names[ i ] ), i );
 
274
            }
 
275
            if ( srw->exec() )
 
276
            {
 
277
              // get the new column specs from the listview control
 
278
              // and replace the existing column spec for the shapefile
 
279
              file->setColumnNames( srw->columnNames() );
 
280
            }
 
281
          }
 
282
 
 
283
 
 
284
        }
 
285
        else
 
286
        {
 
287
          error1 += name + "\n";
 
288
          is_error = true;
 
289
          delete file;
 
290
        }
 
291
      }
 
292
      else
 
293
      {
 
294
        error2 += name + "\n";
 
295
      }
 
296
    }
 
297
  }
 
298
 
 
299
  tblShapefiles->resizeColumnsToContents();
 
300
 
 
301
  if ( error1 != "" || error2 != "" )
 
302
  {
 
303
    QString message = tr("The following Shapefile(s) could not be loaded:\n\n");
 
304
    if ( error1 != "" )
 
305
    {
 
306
      error1 += "----------------------------------------------------------------------------------------";
 
307
      error1 += "\n" + tr("REASON: File cannot be opened") + "\n\n";
 
308
    }
 
309
    if ( error2 != "" )
 
310
    {
 
311
      error2 += "----------------------------------------------------------------------------------------";
 
312
      error2 += "\n" + tr("REASON: One or both of the Shapefile files (*.dbf, *.shx) missing") + "\n\n";
 
313
    }
 
314
    QgsMessageViewer * e = new QgsMessageViewer( this );
 
315
    e->setMessageAsPlainText( message + error1 + error2 );
 
316
    e->exec();
 
317
  }
 
318
}
 
319
 
 
320
void QgsSpit::removeFile()
 
321
{
 
322
  std::vector <int> temp;
 
323
  for ( int n = 0; n < tblShapefiles->rowCount(); n++ )
 
324
    if ( tblShapefiles->isItemSelected( tblShapefiles->item( n, 0 ) ) )
 
325
    {
 
326
      for ( std::vector<QgsShapeFile *>::iterator vit = fileList.begin(); vit != fileList.end(); vit++ )
 
327
      {
 
328
        if ( ( *vit ) ->getName() == tblShapefiles->item( n, 0 )->text() )
 
329
        {
 
330
          total_features -= ( *vit ) ->getFeatureCount();
 
331
          fileList.erase( vit );
 
332
          temp.push_back( n );
 
333
          break;
 
334
        }
 
335
      }
 
336
    }
 
337
 
 
338
  for ( int i = temp.size()-1; i >= 0; --i )
 
339
    tblShapefiles->removeRow( temp[ i ] );
 
340
 
 
341
  tblShapefiles->setCurrentCell( -1, 0 );
 
342
}
 
343
 
 
344
void QgsSpit::removeAllFiles()
 
345
{
 
346
  int i = tblShapefiles->rowCount() - 1;
 
347
  for (; i >= 0; --i)
 
348
    tblShapefiles->removeRow(i);
 
349
 
 
350
  fileList.clear();
 
351
  total_features = 0;
 
352
}
 
353
 
 
354
void QgsSpit::useDefaultSrid()
 
355
{
 
356
  if ( chkUseDefaultSrid->isChecked() )
 
357
  {
 
358
    defaultSridValue = spinSrid->value();
 
359
    spinSrid->setValue( defSrid );
 
360
    spinSrid->setEnabled( false );
 
361
  }
 
362
  else
 
363
  {
 
364
    spinSrid->setEnabled( true );
 
365
    spinSrid->setValue( defaultSridValue );
 
366
  }
 
367
}
 
368
 
 
369
void QgsSpit::useDefaultGeom()
 
370
{
 
371
  if ( chkUseDefaultGeom->isChecked() )
 
372
  {
 
373
    defaultGeomValue = txtGeomName->text();
 
374
    txtGeomName->setText( defGeom );
 
375
    txtGeomName->setEnabled( false );
 
376
  }
 
377
  else
 
378
  {
 
379
    txtGeomName->setEnabled( true );
 
380
    txtGeomName->setText( defaultGeomValue );
 
381
  }
 
382
}
 
383
 
 
384
// TODO: make translation of helpinfo
 
385
void QgsSpit::helpInfo()
 
386
{
 
387
  QString message = tr("General Interface Help:") + "\n\n";
 
388
  message += QString(
 
389
               tr("PostgreSQL Connections:") + "\n" ) + QString(
 
390
               "----------------------------------------------------------------------------------------\n" ) + QString(
 
391
               tr("[New ...] - create a new connection") + "\n" ) + QString(
 
392
               tr("[Edit ...] - edit the currently selected connection") + "\n" ) + QString(
 
393
               tr("[Remove] - remove the currently selected connection") + "\n" ) + QString(
 
394
               tr("-you need to select a connection that works (connects properly) in order to import files") + "\n" ) + QString(
 
395
               tr("-when changing connections Global Schema also changes accordingly") + "\n\n" ) + QString(
 
396
               tr("Shapefile List:") + "\n" ) + QString(
 
397
               "----------------------------------------------------------------------------------------\n" ) + QString(
 
398
               tr("[Add ...] - open a File dialog and browse to the desired file(s) to import") + "\n" ) + QString(
 
399
               tr("[Remove] - remove the currently selected file(s) from the list") + "\n" ) + QString(
 
400
               tr("[Remove All] - remove all the files in the list") + "\n" ) + QString(
 
401
               tr("[SRID] - Reference ID for the shapefiles to be imported") + "\n" ) + QString(
 
402
               tr("[Use Default (SRID)] - set SRID to -1") + "\n" ) + QString(
 
403
               tr("[Geometry Column Name] - name of the geometry column in the database") + "\n" ) + QString(
 
404
               tr("[Use Default (Geometry Column Name)] - set column name to \'the_geom\'") + "\n" ) + QString(
 
405
               tr("[Glogal Schema] - set the schema for all files to be imported into") + "\n\n" ) + QString(
 
406
               "----------------------------------------------------------------------------------------\n" ) + QString(
 
407
               tr("[Import] - import the current shapefiles in the list") + "\n" ) + QString(
 
408
               tr("[Quit] - quit the program\n") ) + QString(
 
409
               tr("[Help] - display this help dialog") + "\n\n" );
 
410
  QgsMessageViewer * e = new QgsMessageViewer( this );
 
411
  e->setMessageAsPlainText( message );
 
412
  e->exec();
 
413
}
 
414
 
 
415
PGconn* QgsSpit::checkConnection()
 
416
{
 
417
  QSettings settings;
 
418
  PGconn * pd;
 
419
  bool result = true;
 
420
  QString connName = cmbConnections->currentText();
 
421
  if ( connName.isEmpty() )
 
422
  {
 
423
    QMessageBox::warning( this, tr("Import Shapefiles"), tr("You need to specify a Connection first") );
 
424
    result = false;
 
425
  }
 
426
  else
 
427
  {
 
428
    QString connInfo = "host=" + settings.readEntry( gl_key + connName + "/host" ) +
 
429
                       " dbname=" + settings.readEntry( gl_key + connName + "/database" ) +
 
430
                       " port=" + settings.readEntry( gl_key + connName + "/port" ) +
 
431
                       " user=" + settings.readEntry( gl_key + connName + "/username" ) +
 
432
                       " password=" + settings.readEntry( gl_key + connName + "/password" );
 
433
    pd = PQconnectdb( ( const char * ) connInfo );
 
434
 
 
435
    if ( PQstatus( pd ) != CONNECTION_OK )
 
436
    {
 
437
      QMessageBox::warning( this, tr("Import Shapefiles"), tr("Connection failed - Check settings and try again") );
 
438
      result = false;
 
439
    }
 
440
  
 
441
    int errcode = PQsetClientEncoding(pd, "UNICODE");
 
442
#ifdef QGISDEBUG
 
443
    if(errcode==0)
 
444
      qWarning("encoding successfully set");
 
445
    else if(errcode==-1)
 
446
      qWarning("error in setting encoding");
 
447
    else
 
448
      qWarning("undefined return value from encoding setting");
 
449
#endif
 
450
  
 
451
  }
 
452
 
 
453
  if (result )
 
454
  {
 
455
    // Check that the database actually has postgis in it.
 
456
    QString sql1 = "SELECT postgis_lib_version()"; // available from v 0.9.0 onwards
 
457
    QString sql2 = "SELECT postgis_version()"; // depreciated 
 
458
 
 
459
    PGresult* ver = PQexec(pd, sql1.toLocal8Bit().data());
 
460
    if ( PQresultStatus(ver) != PGRES_TUPLES_OK)
 
461
    {
 
462
      // In case the version of postgis is older than 0.9.0, try the
 
463
      // depreciated call before erroring out.
 
464
      PQclear(ver);
 
465
      ver = PQexec(pd, sql2.toLocal8Bit().data());
 
466
      if ( PQresultStatus(ver) != PGRES_TUPLES_OK)
 
467
      {
 
468
        QMessageBox::warning( this, tr("PostGIS not available"),
 
469
                              tr("<p>The chosen database does not have PostGIS installed, "
 
470
                                 "but this is required for storage of spatial data.</p>"));
 
471
        return NULL;
 
472
      }
 
473
    }
 
474
    return pd;
 
475
  }
 
476
  else
 
477
    return NULL;
 
478
}
 
479
 
 
480
void QgsSpit::getSchema()
 
481
{
 
482
  QSettings settings;
 
483
  schema_list.clear();
 
484
  schema_list << "public";
 
485
  PGconn* pd = checkConnection();
 
486
  if ( pd != NULL )
 
487
  {
 
488
    QString connName = cmbConnections->currentText();
 
489
    QString user = settings.readEntry( gl_key + connName + "/username" );
 
490
    QString schemaSql = QString( "select nspname from pg_namespace,pg_user where nspowner = usesysid and usename = '%1'" ).arg( user );
 
491
    PGresult *schemas = PQexec( pd, ( const char * ) schemaSql );
 
492
    // get the schema names
 
493
    if ( PQresultStatus( schemas ) == PGRES_TUPLES_OK )
 
494
    {
 
495
      for ( int i = 0; i < PQntuples( schemas ); i++ )
 
496
      {
 
497
        if ( QString( PQgetvalue( schemas, i, 0 ) ) != "public" )
 
498
          schema_list << QString( PQgetvalue( schemas, i, 0 ) );
 
499
      }
 
500
    }
 
501
    PQclear( schemas );
 
502
  }
 
503
 
 
504
  PQfinish(pd);
 
505
 
 
506
  // install a new delegate with an updated schema list (rather than
 
507
  // update the existing delegate because delegates don't seem able to
 
508
  // store modifiable data). 
 
509
  ShapefileTableDelegate* delegate = new ShapefileTableDelegate(tblShapefiles, schema_list);
 
510
  tblShapefiles->setItemDelegate(delegate);
 
511
 
 
512
  cmbSchema->clear();
 
513
  cmbSchema->insertItems( 0, schema_list );
 
514
  cmbSchema->setCurrentIndex( 0 ); // index 0 is always "public"
 
515
}
 
516
 
 
517
void QgsSpit::updateSchema()
 
518
{
 
519
  // install a new delegate with an updated schema list (rather than
 
520
  // update the existing delegate because delegates don't seem able to
 
521
  // store modifiable data). 
 
522
  ShapefileTableDelegate* delegate = new ShapefileTableDelegate(tblShapefiles, schema_list);
 
523
  tblShapefiles->setItemDelegate(delegate);
 
524
}
 
525
 
 
526
void QgsSpit::import()
 
527
{
 
528
  tblShapefiles->setCurrentCell( -1, 0 );
 
529
 
 
530
  QString connName = cmbConnections->currentText();
 
531
  QSettings settings;
 
532
  bool cancelled = false;
 
533
  PGconn* pd = checkConnection();
 
534
  QString query;
 
535
 
 
536
  if ( total_features == 0 )
 
537
  {
 
538
    QMessageBox::warning( this, tr("Import Shapefiles"), 
 
539
                         tr("You need to add shapefiles to the list first") );
 
540
  }
 
541
  else if ( pd != NULL )
 
542
  {
 
543
    PGresult * res;
 
544
    QProgressDialog pro( tr("Importing files"), tr("Cancel"), 
 
545
                         0, total_features, this);
 
546
 
 
547
    pro.setValue( 0 );
 
548
    pro.setLabelText(tr("Progress"));
 
549
    pro.setAutoClose( true );
 
550
    //pro->show();
 
551
    qApp->processEvents();
 
552
 
 
553
    for ( int i = 0; i < fileList.size() ; i++ )
 
554
    {
 
555
      QString error = tr("Problem inserting features from file:") + "\n" + 
 
556
                      tblShapefiles->item( i, ColFILENAME )->text();
 
557
                      
 
558
      // if a name starts with invalid character
 
559
      if ( ! tblShapefiles->item( i, ColDBRELATIONNAME )->text()[ 0 ].isLetter() )
 
560
      {
 
561
        QMessageBox::warning( &pro, tr("Import Shapefiles"), 
 
562
                             error + "\n" + tr("Invalid table name.") );
 
563
        pro.setValue( pro.value() 
 
564
                      + tblShapefiles->item( i, ColFEATURECOUNT )->text().toInt() );
 
565
        continue;
 
566
      }
 
567
 
 
568
      // if no fields detected
 
569
      if ( ( fileList[ i ] ->column_names ).size() == 0 )
 
570
      {
 
571
        QMessageBox::warning( &pro, tr("Import Shapefiles"), 
 
572
                            error + "\n" + tr("No fields detected.") );
 
573
        pro.setValue( pro.value() + 
 
574
                      tblShapefiles->item( i, ColFEATURECOUNT )->text().toInt() );
 
575
        continue;
 
576
      }
 
577
 
 
578
      // duplicate field check
 
579
      std::vector<QString> names_copy = fileList[ i ] ->column_names;
 
580
      std::cerr << "Size of names_copy before sort: " << names_copy.size() << std::endl;
 
581
      QString dupl = "";
 
582
      std::sort( names_copy.begin(), names_copy.end() );
 
583
      std::cerr << "Size of names_copy after sort: " << names_copy.size() << std::endl;
 
584
 
 
585
      for ( int k = 1; k < names_copy.size(); k++ )
 
586
      {
 
587
        std::cerr << "USING :" << names_copy[ k ].toLocal8Bit().data() << " index " << k << std::endl;
 
588
        qWarning( tr("Checking to see if ") + names_copy[ k ] + " == " + names_copy[ k - 1 ] );
 
589
        if ( names_copy[ k ] == names_copy[ k - 1 ] )
 
590
          dupl += names_copy[ k ] + "\n";
 
591
      }
 
592
      // if duplicate field names exist
 
593
      if ( dupl != "" )
 
594
      {
 
595
        QMessageBox::warning( &pro, tr("Import Shapefiles"), error +
 
596
                              "\n" + tr("The following fields are duplicates:") + "\n" + dupl );
 
597
        pro.setValue( pro.value() + tblShapefiles->item( i, ColFEATURECOUNT )->text().toInt() );
 
598
        continue;
 
599
      }
 
600
 
 
601
      // Check and set destination table 
 
602
      fileList[ i ] ->setTable( tblShapefiles->item( i, ColDBRELATIONNAME )->text() );
 
603
      pro.setLabelText( tr("Importing files") + "\n" 
 
604
                      + tblShapefiles->item(i, ColFILENAME)->text() );
 
605
      bool rel_exists1 = false;
 
606
      bool rel_exists2 = false;
 
607
      query = "SELECT f_table_name FROM geometry_columns WHERE f_table_name=\'" 
 
608
              + tblShapefiles->item( i, ColDBRELATIONNAME )->text() +
 
609
              "\' AND f_table_schema=\'" 
 
610
              + tblShapefiles->item( i, ColDBSCHEMA )->text() + "\'";
 
611
      res = PQexec( pd, ( const char * ) query );
 
612
      rel_exists1 = ( PQntuples( res ) > 0 );
 
613
      if ( PQresultStatus( res ) != PGRES_TUPLES_OK )
 
614
      {
 
615
        QString err = PQresultErrorMessage( res );
 
616
        qWarning( err );
 
617
        QMessageBox::warning( &pro, tr("Import Shapefiles"), error + "\n" +
 
618
                              tr("<p>Error while executing the SQL:</p><p>") +
 
619
                              query + tr("</p><p>The database said:") +
 
620
                              err + "</p>" );
 
621
        pro.setValue( pro.value() + tblShapefiles->item( i, ColFEATURECOUNT )->text().toInt() );
 
622
        continue;
 
623
      }
 
624
      else
 
625
      {
 
626
        PQclear( res );
 
627
      }
 
628
 
 
629
      query = "SELECT tablename FROM pg_tables WHERE tablename=\'" + tblShapefiles->item( i, ColDBRELATIONNAME )->text() + "\' AND schemaname=\'" +
 
630
              tblShapefiles->item( i, ColDBSCHEMA )->text() + "\'";
 
631
      res = PQexec( pd, ( const char * ) query );
 
632
      qWarning( query );
 
633
      rel_exists2 = ( PQntuples( res ) > 0 );
 
634
      if ( PQresultStatus( res ) != PGRES_TUPLES_OK )
 
635
      {
 
636
        QString err = PQresultErrorMessage( res );
 
637
        qWarning( err );
 
638
        QMessageBox::warning( &pro, tr("Import Shapefiles"), error + "\n" +
 
639
                              tr("<p>Error while executing the SQL:</p><p>") +
 
640
                              query + tr("</p><p>The database said:") +
 
641
                              err + "</p>" );
 
642
 
 
643
        pro.setValue( pro.value() + tblShapefiles->item( i, ColFEATURECOUNT )->text().toInt() );
 
644
        continue;
 
645
      }
 
646
      else
 
647
      {
 
648
        PQclear( res );
 
649
      }
 
650
 
 
651
      // begin session
 
652
      query = "BEGIN";
 
653
      res = PQexec( pd, query );
 
654
      if ( PQresultStatus( res ) != PGRES_COMMAND_OK )
 
655
      {
 
656
        QString err = PQresultErrorMessage( res );
 
657
        qWarning( err );
 
658
        QMessageBox::warning( &pro, tr("Import Shapefiles"), error + "\n" +
 
659
                              tr("<p>Error while executing the SQL:</p><p>") +
 
660
                              query + tr("</p><p>The database said:") +
 
661
                              err + "</p>" );
 
662
        pro.setValue( pro.value() + tblShapefiles->item( i, ColFEATURECOUNT )->text().toInt() );
 
663
        continue;
 
664
      }
 
665
      else
 
666
      {
 
667
        PQclear( res );
 
668
      }
 
669
 
 
670
      query = "SET SEARCH_PATH TO \'";
 
671
      if ( tblShapefiles->item( i, ColDBSCHEMA )->text() == "public" )
 
672
        query += "public\'";
 
673
      else
 
674
        query += tblShapefiles->item( i, ColDBSCHEMA )->text() + "\', \'public\'";
 
675
      res = PQexec( pd, query );
 
676
      qWarning( query );
 
677
      if ( PQresultStatus( res ) != PGRES_COMMAND_OK )
 
678
      {
 
679
        QString err = PQresultErrorMessage( res );
 
680
        qWarning( err );
 
681
        qWarning( PQresStatus( PQresultStatus( res ) ) );
 
682
        QMessageBox::warning( &pro, tr("Import Shapefiles"), error + "\n" +
 
683
                              tr("<p>Error while executing the SQL:</p><p>") +
 
684
                              query + tr("</p><p>The database said:") +
 
685
                              err + "</p>" );
 
686
        pro.setValue( pro.value() + tblShapefiles->item( i, ColFEATURECOUNT )->text().toInt() );
 
687
        continue;
 
688
      }
 
689
      else
 
690
      {
 
691
        PQclear( res );
 
692
      }
 
693
 
 
694
      QMessageBox *del_confirm;
 
695
      if ( rel_exists1 || rel_exists2 )
 
696
      {
 
697
        del_confirm = new QMessageBox( tr("Import Shapefiles - Relation Exists"),
 
698
                                       tr("The Shapefile:" ) + "\n" + tblShapefiles->item( i, 0 )->text() + "\n" + tr("will use [") +
 
699
                                       tblShapefiles->item( i, ColDBRELATIONNAME )->text() + tr("] relation for its data,") + "\n" + tr("which already exists and possibly contains data.") + "\n" +
 
700
                                       tr("To avoid data loss change the \"DB Relation Name\"") + "\n" + tr("for this Shapefile in the main dialog file list.") + "\n\n" +
 
701
                                       tr("Do you want to overwrite the [") + tblShapefiles->item( i, ColDBRELATIONNAME )->text() + tr("] relation?"),
 
702
                                       QMessageBox::Warning,
 
703
                                       QMessageBox::Yes | QMessageBox::Default,
 
704
                                       QMessageBox::No | QMessageBox::Escape,
 
705
                                       Qt::NoButton, 
 
706
                                       this
 
707
//                                       tr("Relation Exists") 
 
708
                                     );
 
709
 
 
710
        if ( del_confirm->exec() == QMessageBox::Yes )
 
711
        {
 
712
          if ( rel_exists2 )
 
713
          {
 
714
            query = "DROP TABLE " + tblShapefiles->item( i, ColDBRELATIONNAME )->text();
 
715
            qWarning( query );
 
716
            res = PQexec( pd, ( const char * ) query );
 
717
            if ( PQresultStatus( res ) != PGRES_COMMAND_OK )
 
718
            {
 
719
              QString err = PQresultErrorMessage( res );
 
720
              qWarning( err );
 
721
              QMessageBox::warning( &pro, tr("Import Shapefiles"), error + "\n" +
 
722
                                    tr("<p>Error while executing the SQL:</p><p>") +
 
723
                                    query + tr("</p><p>The database said:") +
 
724
                                    err + "</p>" );
 
725
              pro.setValue( pro.value() + tblShapefiles->item( i, ColFEATURECOUNT )->text().toInt() );
 
726
              continue;
 
727
            }
 
728
            else
 
729
            {
 
730
              PQclear( res );
 
731
            }
 
732
          }
 
733
 
 
734
          if ( rel_exists1 )
 
735
          {
 
736
            /*query = "SELECT DropGeometryColumn(\'"+QString(settings.readEntry(key + "/database"))+"\', \'"+
 
737
              fileList[i]->getTable()+"\', \'"+txtGeomName->text()+"')";*/
 
738
            query = "DELETE FROM geometry_columns WHERE f_table_schema=\'" + tblShapefiles->item( i, ColDBSCHEMA )->text() + "\' AND " +
 
739
                    "f_table_name=\'" + tblShapefiles->item( i, ColDBRELATIONNAME )->text() + "\'";
 
740
            qWarning( query );
 
741
            res = PQexec( pd, ( const char * ) query );
 
742
            if ( PQresultStatus( res ) != PGRES_COMMAND_OK )
 
743
            {
 
744
              QString err = PQresultErrorMessage( res );
 
745
              qWarning( err );
 
746
              QMessageBox::warning( &pro, tr("Import Shapefiles"), error + "\n" +
 
747
                                    tr("<p>Error while executing the SQL:</p><p>") +
 
748
                                    query + tr("</p><p>The database said:") +
 
749
                                    err + "</p>" );
 
750
              pro.setValue( pro.value() + tblShapefiles->item( i, ColFEATURECOUNT )->text().toInt() );
 
751
              continue;
 
752
            }
 
753
            else
 
754
            {
 
755
              PQclear( res );
 
756
            }
 
757
          }
 
758
        }
 
759
        else
 
760
        {
 
761
          query = "ROLLBACK";
 
762
          res = PQexec( pd, query );
 
763
          if ( PQresultStatus( res ) != PGRES_COMMAND_OK )
 
764
          {
 
765
            QString err = PQresultErrorMessage( res );
 
766
            qWarning( err );
 
767
            QMessageBox::warning( &pro, tr("Import Shapefiles"), error + "\n" +
 
768
                                  tr("<p>Error while executing the SQL:</p><p>") +
 
769
                                  query + tr("</p><p>The database said:") +
 
770
                                  err + "</p>" );
 
771
          }
 
772
          else
 
773
          {
 
774
            PQclear( res );
 
775
          }
 
776
          pro.setValue( pro.value() + tblShapefiles->item( i, 2 )->text().toInt() );
 
777
          continue;
 
778
        }
 
779
      }
 
780
 
 
781
      // importing file here
 
782
      int temp_progress = pro.value();
 
783
      cancelled = false;
 
784
      if ( fileList[ i ] ->insertLayer( settings.readEntry( gl_key + connName + "/database" ), tblShapefiles->item( i, ColDBSCHEMA )->text(),
 
785
                                        txtGeomName->text(), QString( "%1" ).arg( spinSrid->value() ), pd, pro, cancelled ) && !cancelled )
 
786
      { // if file has been imported successfully
 
787
        query = "COMMIT";
 
788
        res = PQexec( pd, query );
 
789
        if ( PQresultStatus( res ) != PGRES_COMMAND_OK )
 
790
        {
 
791
          QString err = PQresultErrorMessage( res );
 
792
          qWarning( err );
 
793
          QMessageBox::warning( &pro, tr("Import Shapefiles"), error + "\n" +
 
794
                                tr("<p>Error while executing the SQL:</p><p>") +
 
795
                                query + tr("</p><p>The database said:") +
 
796
                                err + "</p>" );
 
797
          continue;
 
798
        }
 
799
        else
 
800
        {
 
801
          PQclear( res );
 
802
        }
 
803
 
 
804
        // remove file
 
805
        for ( int j = 0; j < tblShapefiles->rowCount(); j++ )
 
806
        {
 
807
          if ( tblShapefiles->item( j, ColFILENAME )->text() == QString( fileList[ i ] ->getName() ) )
 
808
          {
 
809
            tblShapefiles->selectRow( j );
 
810
            removeFile();
 
811
            i--;
 
812
            break;
 
813
          }
 
814
        }
 
815
 
 
816
      }
 
817
      else if ( !cancelled )
 
818
      { // if problem importing file occured
 
819
        pro.setValue( temp_progress + tblShapefiles->item( i, ColFEATURECOUNT )->text().toInt() );
 
820
        QMessageBox::warning( this, tr("Import Shapefiles"), error );
 
821
        query = "ROLLBACK";
 
822
        res = PQexec( pd, query );
 
823
        if ( PQresultStatus( res ) != PGRES_COMMAND_OK )
 
824
        {
 
825
          QString err = PQresultErrorMessage( res );
 
826
          qWarning( err );
 
827
          QMessageBox::warning( &pro, tr("Import Shapefiles"), error + "\n" +
 
828
                                tr("<p>Error while executing the SQL:</p><p>") +
 
829
                                query + tr("</p><p>The database said:") +
 
830
                                err + "</p>" );
 
831
        }
 
832
        else
 
833
        {
 
834
          PQclear( res );
 
835
        }
 
836
      }
 
837
      else
 
838
      { // if import was actually cancelled
 
839
        break;
 
840
      }
 
841
    }
 
842
  }
 
843
  PQfinish( pd );
 
844
}
 
845
void QgsSpit::editColumns( int row, int col, int button, const QPoint &mousePos )
 
846
{
 
847
  // get the shapefile - table row maps directly to the fileList array
 
848
  QgsPgUtil * pgu = QgsPgUtil::instance();
 
849
  // show the dialog for adjusting reserved words. Reserved
 
850
  // words are displayed differently so they are easy to spot
 
851
  QgsEditReservedWordsDialog *srw = new QgsEditReservedWordsDialog( this );
 
852
  srw->setCaption( fileList[ row ] ->getTable().upper() + tr(" - Edit Column Names") );
 
853
  // set the description to indicate that we are editing column names, not
 
854
  // necessarily dealing with reserved words (although that is a possibility too)
 
855
  srw->setDescription(tr("Use the table below to edit column names. Make sure that none of the columns are named using a PostgreSQL reserved word"));
 
856
  // load the reserved words list
 
857
  srw->setReservedWords( pgu->reservedWords() );
 
858
  // load the columns and set their status
 
859
  for ( int i = 0; i < fileList[ row ] ->column_names.size(); i++ )
 
860
  {
 
861
    srw->addColumn( fileList[ row ] ->column_names[ i ],
 
862
                    pgu->isReserved( fileList[ row ] ->column_names[ i ] ), i );
 
863
  }
 
864
  if ( srw->exec() )
 
865
  {
 
866
    // get the new column specs from the listview control
 
867
    // and replace the existing column spec for the shapefile
 
868
    fileList[ row ] ->setColumnNames( srw->columnNames() );
 
869
  }
 
870
 
 
871
}
 
872
 
 
873
void QgsSpit::editShapefile(int row, int col, int button, const QPoint& mousePos)
 
874
{
 
875
  // FIXME Is this necessary any more?
 
876
  /*
 
877
  if (ColFEATURECLASS == col || ColDBRELATIONNAME == col)
 
878
  {
 
879
    tblShapefiles->editCell(row, col, FALSE);
 
880
  }
 
881
  */
 
882
}
 
883
 
 
884
 
 
885
QWidget *ShapefileTableDelegate::createEditor(QWidget *parent,
 
886
                                        const QStyleOptionViewItem &,
 
887
                                        const QModelIndex & index) const
 
888
{
 
889
  switch(index.column())
 
890
  {
 
891
  case 4:
 
892
    {
 
893
      QComboBox* editor = new QComboBox(parent);
 
894
      editor->setSizeAdjustPolicy(QComboBox::AdjustToContents);
 
895
      editor->installEventFilter(const_cast<ShapefileTableDelegate*>(this));
 
896
      return editor;
 
897
      break;
 
898
    }
 
899
  case 1:
 
900
  case 3:
 
901
    {
 
902
      QLineEdit* editor = new QLineEdit(parent);
 
903
      editor->installEventFilter(const_cast<ShapefileTableDelegate*>(this));
 
904
      return editor;
 
905
      break;
 
906
    }
 
907
  }
 
908
}
 
909
 
 
910
void ShapefileTableDelegate::setEditorData(QWidget *editor,
 
911
                                     const QModelIndex &index) const
 
912
{
 
913
  switch(index.column())
 
914
  {
 
915
  case 4:
 
916
    {
 
917
      // Create a combobox and populate with the list of schemas
 
918
      QComboBox *comboBox = static_cast<QComboBox*>(editor);
 
919
      comboBox->insertItems(0, mSchemaList);
 
920
      // Get the text from the table and use to set the selected text
 
921
      // in the combo box.
 
922
      QString text = index.model()->data(index, Qt::DisplayRole).toString();
 
923
      comboBox->setCurrentIndex(mSchemaList.indexOf(text));
 
924
      break;
 
925
    }
 
926
  case 1:
 
927
  case 3:
 
928
    {
 
929
      QString text = index.model()->data(index, Qt::DisplayRole).toString();
 
930
      QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
 
931
      lineEdit->setText(text);
 
932
      break;
 
933
    }
 
934
  }
 
935
}
 
936
 
 
937
void ShapefileTableDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
 
938
                                    const QModelIndex &index) const
 
939
{
 
940
  switch(index.column())
 
941
  {
 
942
  case 4:
 
943
    {
 
944
      QComboBox *comboBox = static_cast<QComboBox*>(editor);
 
945
      QString text = comboBox->currentText();
 
946
      model->setData(index, text);
 
947
      break;
 
948
    }
 
949
  case 1:
 
950
  case 3:
 
951
    {
 
952
      QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
 
953
      QString text = lineEdit->text();
 
954
 
 
955
      model->setData(index, text);
 
956
      break;
 
957
    }
 
958
  }
 
959
}
 
960
 
 
961
void ShapefileTableDelegate::updateEditorGeometry(QWidget *editor,
 
962
        const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
 
963
{
 
964
  editor->setGeometry(option.rect);
 
965
}
 
966