~ubuntu-branches/ubuntu/hardy/qgis/hardy

« back to all changes in this revision

Viewing changes to src/gui/qgsvectorlayer.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
                               qgsvectorlayer.cpp
 
3
  This class implements a generic means to display vector layers. The features
 
4
  and attributes are read from the data store using a "data provider" plugin.
 
5
  QgsVectorLayer can be used with any data store for which an appropriate
 
6
  plugin is available.
 
7
                              -------------------
 
8
          begin                : Oct 29, 2003
 
9
          copyright            : (C) 2003 by Gary E.Sherman
 
10
          email                : sherman at mrcc.com
 
11
 
 
12
***************************************************************************/
 
13
 
 
14
/***************************************************************************
 
15
 *                                                                         *
 
16
 *   This program is free software; you can redistribute it and/or modify  *
 
17
 *   it under the terms of the GNU General Public License as published by  *
 
18
 *   the Free Software Foundation; either version 2 of the License, or     *
 
19
 *   (at your option) any later version.                                   *
 
20
 *                                                                         *
 
21
 ***************************************************************************/
 
22
/*  $Id: qgsvectorlayer.cpp 6320 2006-12-27 15:44:05Z mhugent $ */
 
23
 
 
24
#include <iostream>
 
25
#include <iosfwd>
 
26
#include <cfloat>
 
27
#include <cstring>
 
28
#include <cmath>
 
29
#include <sstream>
 
30
#include <memory>
 
31
#include <vector>
 
32
#include <utility>
 
33
#include <cassert>
 
34
#include <limits>
 
35
 
 
36
// for htonl
 
37
#ifdef WIN32
 
38
#include <winsock.h>
 
39
#else
 
40
#include <netinet/in.h>
 
41
#endif
 
42
 
 
43
#include <QApplication>
 
44
#include <QCursor>
 
45
#include <QLibrary>
 
46
#include <QMessageBox>
 
47
#include <QPainter>
 
48
#include <QPainterPath>
 
49
#include <QPixmap>
 
50
#include <QPolygonF>
 
51
#include <QProgressDialog>
 
52
#include <QString>
 
53
#include <QSettings>
 
54
 
 
55
#include "qgis.h" //for globals
 
56
#include "qgisapp.h"
 
57
#include "qgsapplication.h"
 
58
#include "qgsattributedialog.h"
 
59
#include "qgsattributetable.h"
 
60
#include "qgsattributetabledisplay.h"
 
61
#include "qgscontinuouscolorrenderer.h"
 
62
#include "qgscoordinatetransform.h"
 
63
#include "qgsdistancearea.h"
 
64
#include "qgsfeature.h"
 
65
#include "qgsfield.h"
 
66
#include "qgsgraduatedsymbolrenderer.h"
 
67
#include "qgslabel.h"
 
68
#include "qgslabelattributes.h"
 
69
#include "qgslegend.h"
 
70
#include "qgslogger.h"
 
71
#include "qgsmaplayerregistry.h"
 
72
#include "qgsmaptopixel.h"
 
73
#include "qgspoint.h"
 
74
#include "qgsproject.h"
 
75
#include "qgsproviderregistry.h"
 
76
#include "qgsrect.h"
 
77
#include "qgsrect.h"
 
78
#include "qgsrenderer.h"
 
79
#include "qgsrenderitem.h"
 
80
#include "qgssinglesymbolrenderer.h"
 
81
#include "qgsspatialrefsys.h"
 
82
#include "qgsuniquevaluerenderer.h"
 
83
#include "qgsvectordataprovider.h"
 
84
#include "qgsvectorlayer.h"
 
85
#include "qgsvectorlayerproperties.h"
 
86
#ifdef Q_WS_X11
 
87
#include "qgsclipper.h"
 
88
#endif
 
89
//#include "wkbheader.h"
 
90
 
 
91
#ifdef TESTPROVIDERLIB
 
92
#include <dlfcn.h>
 
93
#endif
 
94
 
 
95
 
 
96
static const char * const ident_ = "$Id: qgsvectorlayer.cpp 6320 2006-12-27 15:44:05Z mhugent $";
 
97
 
 
98
// typedef for the QgsDataProvider class factory
 
99
typedef QgsDataProvider * create_it(const QString* uri);
 
100
 
 
101
 
 
102
 
 
103
QgsVectorLayer::QgsVectorLayer(QString vectorLayerPath,
 
104
    QString baseName,
 
105
    QString providerKey)
 
106
: QgsMapLayer(VECTOR, baseName, vectorLayerPath),
 
107
  tabledisplay(0),
 
108
  m_renderer(0),
 
109
  mLabel(0),
 
110
  m_propertiesDialog(0),
 
111
  providerKey(providerKey),
 
112
  valid(false),
 
113
  myLib(0),
 
114
  updateThreshold(0),       // XXX better default value?
 
115
  mMinimumScale(0),
 
116
  mMaximumScale(0),
 
117
  mScaleDependentRender(false),
 
118
  mEditable(false),
 
119
  mModified(false),
 
120
  mToggleEditingAction(0)
 
121
{
 
122
  // if we're given a provider type, try to create and bind one to this layer
 
123
  if ( ! providerKey.isEmpty() )
 
124
  {
 
125
    setDataProvider( providerKey );
 
126
  }
 
127
  if(valid)
 
128
  {
 
129
    setCoordinateSystem();
 
130
 
 
131
    // Default for the popup menu
 
132
    popMenu = 0;
 
133
 
 
134
    // Get the update threshold from user settings. We
 
135
    // do this only on construction to avoid the penality of
 
136
    // fetching this each time the layer is drawn. If the user
 
137
    // changes the threshold from the preferences dialog, it will
 
138
    // have no effect on existing layers
 
139
    QSettings settings;
 
140
    updateThreshold = settings.readNumEntry("Map/updateThreshold", 1000);
 
141
  }
 
142
} // QgsVectorLayer ctor
 
143
 
 
144
 
 
145
 
 
146
QgsVectorLayer::~QgsVectorLayer()
 
147
{
 
148
  QgsDebugMsg("In QgsVectorLayer destructor");
 
149
 
 
150
  valid=false;
 
151
 
 
152
  if(isEditable())
 
153
  {
 
154
    stopEditing();
 
155
  }
 
156
 
 
157
  if (tabledisplay)
 
158
  {
 
159
    tabledisplay->close();
 
160
    delete tabledisplay;
 
161
  }
 
162
  if (m_renderer)
 
163
  {
 
164
    delete m_renderer;
 
165
  }
 
166
  if (m_propertiesDialog)
 
167
  {
 
168
    delete m_propertiesDialog;
 
169
  }
 
170
  // delete the provider object
 
171
  delete dataProvider;
 
172
  // delete the popu pmenu
 
173
  delete popMenu;
 
174
  // delete the provider lib pointer
 
175
  delete myLib;
 
176
  delete mLabel;
 
177
 
 
178
  // Destroy any cached geometries and clear the references to them
 
179
  deleteCachedGeometries();
 
180
}
 
181
 
 
182
QString QgsVectorLayer::storageType() const
 
183
{
 
184
  if (dataProvider)
 
185
  {
 
186
    return dataProvider->storageType();
 
187
  }
 
188
  return 0;
 
189
}
 
190
 
 
191
 
 
192
QString QgsVectorLayer::capabilitiesString() const
 
193
{
 
194
  if (dataProvider)
 
195
  {
 
196
    return dataProvider->capabilitiesString();
 
197
  }
 
198
  return 0;
 
199
}
 
200
 
 
201
int QgsVectorLayer::getProjectionSrid()
 
202
{
 
203
  //delegate to the provider
 
204
  if (valid)
 
205
  {
 
206
    QgsDebugMsg("Getting srid from provider...");
 
207
    return dataProvider->getSrid();
 
208
  }
 
209
  else
 
210
  {
 
211
    return 0;
 
212
  }
 
213
}
 
214
 
 
215
QString QgsVectorLayer::getProjectionWKT()
 
216
{
 
217
  //delegate to the provider
 
218
  if (valid)
 
219
  {
 
220
    return dataProvider->getProjectionWKT();
 
221
  }
 
222
  else
 
223
  {
 
224
    return NULL;
 
225
  }
 
226
}
 
227
 
 
228
QString QgsVectorLayer::providerType()
 
229
{
 
230
  return providerKey;
 
231
}
 
232
 
 
233
/**
 
234
 * sets the preferred display field based on some fuzzy logic
 
235
 */
 
236
void QgsVectorLayer::setDisplayField(QString fldName)
 
237
{
 
238
  // If fldName is provided, use it as the display field, otherwise
 
239
  // determine the field index for the feature column of the identify
 
240
  // dialog. We look for fields containing "name" first and second for
 
241
  // fields containing "id". If neither are found, the first field
 
242
  // is used as the node.
 
243
  QString idxName="";
 
244
  QString idxId="";
 
245
 
 
246
  std::vector < QgsField > fields = dataProvider->fields();
 
247
  if(!fldName.isEmpty())
 
248
  {
 
249
    // find the index for this field
 
250
    fieldIndex = fldName;
 
251
    /*
 
252
       for(int i = 0; i < fields.size(); i++)
 
253
       {
 
254
       if(QString(fields[i].name()) == fldName)
 
255
       {
 
256
       fieldIndex = i;
 
257
       break;
 
258
       }
 
259
       }
 
260
       */
 
261
  }
 
262
  else
 
263
  {
 
264
    int fieldsSize = fields.size();
 
265
    for (int j = 0; j < fieldsSize; j++)
 
266
    {
 
267
 
 
268
      QString fldName = fields[j].name();
 
269
      QgsDebugMsg("Checking field " + fldName + " of " + QString::number(fields.size()) + " total");
 
270
      
 
271
      // Check the fields and keep the first one that matches.
 
272
      // We assume that the user has organized the data with the
 
273
      // more "interesting" field names first. As such, name should
 
274
      // be selected before oldname, othername, etc.
 
275
      if (fldName.find("name", false) > -1)
 
276
      {
 
277
        if(idxName.isEmpty())
 
278
        {
 
279
          idxName = fldName;
 
280
        }
 
281
      }
 
282
      if (fldName.find("descrip", false) > -1)
 
283
      {
 
284
        if(idxName.isEmpty())
 
285
        {
 
286
          idxName = fldName;
 
287
        }
 
288
      }
 
289
      if (fldName.find("id", false) > -1)
 
290
      {
 
291
        if(idxId.isEmpty())
 
292
        {
 
293
          idxId = fldName;
 
294
        }
 
295
      }
 
296
    }
 
297
 
 
298
    //if there were no fields in the dbf just return - otherwise qgis segfaults!
 
299
    if (fields.size() == 0) return;
 
300
 
 
301
    if (idxName.length() > 0)
 
302
    {
 
303
      fieldIndex = idxName;
 
304
    }
 
305
    else
 
306
    {
 
307
      if (idxId.length() > 0)
 
308
      {
 
309
        fieldIndex = idxId;
 
310
      }
 
311
      else
 
312
      {
 
313
        fieldIndex = fields[0].name();
 
314
      }
 
315
    }
 
316
 
 
317
    // set this to be the label field as well
 
318
    setLabelField(fieldIndex);
 
319
  }
 
320
}
 
321
 
 
322
void QgsVectorLayer::drawLabels(QPainter * p, QgsRect * viewExtent, QgsMapToPixel * theMapToPixelTransform)
 
323
{
 
324
  drawLabels(p, viewExtent, theMapToPixelTransform, 1.);
 
325
}
 
326
 
 
327
// NOTE this is a temporary method added by Tim to prevent label clipping
 
328
// which was occurring when labeller was called in the main draw loop
 
329
// This method will probably be removed again in the near future!
 
330
void QgsVectorLayer::drawLabels(QPainter * p, QgsRect * viewExtent, QgsMapToPixel * theMapToPixelTransform, double scale)
 
331
{
 
332
  QgsDebugMsg("Starting draw of labels");
 
333
 
 
334
  if ( /*1 == 1 */ m_renderer && mLabelOn)
 
335
  {
 
336
    bool projectionsEnabledFlag = projectionsEnabled();
 
337
    std::list<int> attributes=m_renderer->classificationAttributes();
 
338
    // Add fields required for labels
 
339
    mLabel->addRequiredFields ( &attributes );
 
340
 
 
341
    QgsDebugMsg("Selecting features based on view extent");
 
342
 
 
343
    int featureCount = 0;
 
344
    // select the records in the extent. The provider sets a spatial filter
 
345
    // and sets up the selection set for retrieval
 
346
    dataProvider->reset();
 
347
    dataProvider->select(viewExtent);
 
348
 
 
349
    try
 
350
    {
 
351
      //main render loop
 
352
      QgsFeature *fet;
 
353
 
 
354
      while((fet = dataProvider->getNextFeature(attributes)))
 
355
      {
 
356
        // Render label
 
357
        if ( fet != 0 )
 
358
        {
 
359
          //don't render labels of deleted features
 
360
          if(mDeletedFeatureIds.find(fet->featureId())==mDeletedFeatureIds.end())
 
361
          {
 
362
            bool sel=mSelectedFeatureIds.find(fet->featureId()) != mSelectedFeatureIds.end();
 
363
            mLabel->renderLabel ( p, viewExtent, *mCoordinateTransform, 
 
364
                projectionsEnabledFlag,
 
365
                theMapToPixelTransform, fet, sel, 0, scale);
 
366
          }
 
367
        }
 
368
        delete fet;
 
369
        featureCount++;
 
370
      }
 
371
 
 
372
      //render labels of not-commited features
 
373
      //XXX changed from std::vector to std::list in merge from 0.7 to head (TS)
 
374
      for(std::vector<QgsFeature*>::iterator it=mAddedFeatures.begin();it!=mAddedFeatures.end();++it)
 
375
      {
 
376
        bool sel=mSelectedFeatureIds.find((*it)->featureId()) != mSelectedFeatureIds.end();
 
377
        mLabel->renderLabel ( p, viewExtent, *mCoordinateTransform, projectionsEnabledFlag,
 
378
            theMapToPixelTransform, *it, sel, 0, scale);
 
379
      }
 
380
    }
 
381
    catch (QgsCsException &e)
 
382
    {
 
383
      QgsLogger::critical("Error projecting label locations, caught in " + QString(__FILE__) + ", line " +QString(__LINE__));
 
384
    }
 
385
 
 
386
#ifdef QGISDEBUG
 
387
    QgsLogger::debug("Total features processed", featureCount, 1, __FILE__, __FUNCTION__, __LINE__);
 
388
#endif
 
389
    
 
390
    // XXX Something in our draw event is triggering an additional draw event when resizing [TE 01/26/06]
 
391
    // XXX Calling this will begin processing the next draw event causing image havoc and recursion crashes.
 
392
    //qApp->processEvents();
 
393
 
 
394
  }
 
395
}
 
396
 
 
397
QgsRect QgsVectorLayer::inverseProjectRect(const QgsRect& r) const
 
398
{
 
399
  // Undo a coordinate transformation if one was in effect
 
400
  if (projectionsEnabled())
 
401
  { 
 
402
    try
 
403
    {
 
404
      QgsPoint p1 = mCoordinateTransform->transform(r.xMin(), r.yMin(), 
 
405
          QgsCoordinateTransform::INVERSE);
 
406
      QgsPoint p2 = mCoordinateTransform->transform(r.xMax(), r.yMax(), 
 
407
          QgsCoordinateTransform::INVERSE);
 
408
#ifdef QGISDEBUG
 
409
      QgsDebugMsg("Projections are enabled");
 
410
      QgsDebugMsg("Rectangle was: "+r.stringRep(true));
 
411
      QgsRect tt(p1, p2);
 
412
      QgsDebugMsg("Inverse transformed to: "+tt.stringRep(true))
 
413
#endif
 
414
      return QgsRect(p1, p2);
 
415
 
 
416
    }
 
417
    catch (QgsCsException &e)
 
418
    {
 
419
      QgsLogger::critical("Inverse transform error in " + QString(__FILE__) + ", line " + QString(__LINE__));
 
420
    }
 
421
  }
 
422
  // fall through for all failures
 
423
  return QgsRect(r);
 
424
}
 
425
 
 
426
unsigned char* QgsVectorLayer::drawLineString(unsigned char* feature, 
 
427
    QPainter* p,
 
428
    QgsMapToPixel* mtp, 
 
429
    bool projectionsEnabledFlag,
 
430
    bool drawingToEditingCanvas)
 
431
{
 
432
  unsigned char *ptr = feature + 5;
 
433
  unsigned int wkbType = *((int*)(feature+1));
 
434
  unsigned int nPoints = *((int*)ptr);
 
435
  ptr = feature + 9;
 
436
  
 
437
  bool hasZValue = (wkbType == QGis::WKBLineString25D);
 
438
 
 
439
  std::vector<double> x(nPoints);
 
440
  std::vector<double> y(nPoints);
 
441
  std::vector<double> z(nPoints, 0.0);
 
442
  
 
443
  // Extract the points from the WKB format into the x and y vectors. 
 
444
  for (register unsigned int i = 0; i < nPoints; ++i)
 
445
  {
 
446
    x[i] = *((double *) ptr);
 
447
    ptr += sizeof(double);
 
448
    y[i] = *((double *) ptr);
 
449
    ptr += sizeof(double);
 
450
  
 
451
    if (hasZValue) // ignore Z value
 
452
      ptr += sizeof(double);
 
453
  }
 
454
 
 
455
  // Transform the points into map coordinates (and reproject if
 
456
  // necessary)
 
457
 
 
458
  transformPoints(x, y, z, mtp, projectionsEnabledFlag);
 
459
 
 
460
#if defined(Q_WS_X11)
 
461
  // Work around a +/- 32768 limitation on coordinates in X11
 
462
 
 
463
  // Look through the x and y coordinates and see if there are any
 
464
  // that need trimming. If one is found, there's no need to look at
 
465
  // the rest of them so end the loop at that point. 
 
466
  for (register unsigned int i = 0; i < nPoints; ++i)
 
467
    if (std::abs(x[i]) > QgsClipper::maxX ||
 
468
        std::abs(y[i]) > QgsClipper::maxY)
 
469
    {
 
470
      QgsClipper::trimFeature(x, y, true); // true = polyline
 
471
      nPoints = x.size(); // trimming may change nPoints.
 
472
      break;
 
473
    }
 
474
#endif
 
475
 
 
476
  // set up QPolygonF class with transformed points
 
477
  QPolygonF pa(nPoints);
 
478
  for (register unsigned int i = 0; i < nPoints; ++i)
 
479
  {
 
480
    pa[i].setX(x[i]);
 
481
    pa[i].setY(y[i]);
 
482
  }
 
483
  
 
484
#ifdef QGISDEBUGVERBOSE
 
485
  // this is only used for verbose debug output
 
486
  for (int i = 0; i < pa.size(); ++i)
 
487
    {
 
488
      QgsDebugMsgLevel("pa" + QString::number(pa.point(i).x()), 2);
 
489
      QgsDebugMsgLevel("pa" + QString::number(pa.point(i).y()), 2);
 
490
    }
 
491
#endif
 
492
 
 
493
  // The default pen gives bevelled joins between segements of the
 
494
  // polyline, which is good enough for the moment.
 
495
  //preserve a copy of the pen before we start fiddling with it
 
496
  QPen pen = p->pen(); // to be kept original
 
497
  //
 
498
  // experimental alpha transparency
 
499
  // 255 = opaque
 
500
  //
 
501
  QPen myTransparentPen = p->pen(); // store current pen
 
502
  QColor myColor = myTransparentPen.color();
 
503
  myColor.setAlpha(transparencyLevelInt);
 
504
  myTransparentPen.setColor(myColor);
 
505
  p->setPen(myTransparentPen);
 
506
  p->drawPolyline(pa);
 
507
 
 
508
  // draw vertex markers if in editing mode, but only to the main canvas
 
509
  if (
 
510
      (mEditable) &&
 
511
      (drawingToEditingCanvas)
 
512
     )
 
513
    {
 
514
      std::vector<double>::const_iterator xIt;
 
515
      std::vector<double>::const_iterator yIt;
 
516
      for(xIt = x.begin(), yIt = y.begin(); xIt != x.end(); ++xIt, ++yIt)
 
517
        {
 
518
          drawVertexMarker((int)(*xIt), (int)(*yIt), *p);
 
519
        }
 
520
    }
 
521
 
 
522
  //restore the pen
 
523
  p->setPen(pen);
 
524
  
 
525
  return ptr;
 
526
}
 
527
 
 
528
unsigned char* QgsVectorLayer::drawPolygon(unsigned char* feature, 
 
529
    QPainter* p, 
 
530
    QgsMapToPixel* mtp, 
 
531
    bool projectionsEnabledFlag,
 
532
    bool drawingToEditingCanvas)
 
533
{
 
534
  typedef std::pair<std::vector<double>, std::vector<double> > ringType;
 
535
  typedef ringType* ringTypePtr;
 
536
  typedef std::vector<ringTypePtr> ringsType;
 
537
 
 
538
  // get number of rings in the polygon
 
539
  unsigned int numRings = *((int*)(feature + 1 + sizeof(int)));
 
540
 
 
541
  if ( numRings == 0 )  // sanity check for zero rings in polygon
 
542
    return feature + 9;
 
543
 
 
544
  unsigned int wkbType = *((int*)(feature+1));
 
545
  
 
546
  bool hasZValue = (wkbType == QGis::WKBPolygon25D);
 
547
  
 
548
  int total_points = 0;
 
549
 
 
550
  // A vector containing a pointer to a pair of double vectors.The
 
551
  // first vector in the pair contains the x coordinates, and the
 
552
  // second the y coordinates.
 
553
  ringsType rings;
 
554
 
 
555
  // Set pointer to the first ring
 
556
  unsigned char* ptr = feature + 1 + 2 * sizeof(int); 
 
557
 
 
558
  for (register unsigned int idx = 0; idx < numRings; idx++)
 
559
  {
 
560
    unsigned int nPoints = *((int*)ptr);
 
561
 
 
562
    ringTypePtr ring = new ringType(std::vector<double>(nPoints),
 
563
        std::vector<double>(nPoints));
 
564
    ptr += 4;
 
565
 
 
566
    // create a dummy vector for the z coordinate
 
567
    std::vector<double> zVector(nPoints, 0.0);
 
568
    // Extract the points from the WKB and store in a pair of
 
569
    // vectors.
 
570
    /*
 
571
#ifdef QGISDEBUG
 
572
std::cerr << "Points for ring " << idx << " ("
 
573
<< nPoints << " points)\n";
 
574
#endif
 
575
*/
 
576
    for (register unsigned int jdx = 0; jdx < nPoints; jdx++)
 
577
    {
 
578
      ring->first[jdx] = *((double *) ptr);
 
579
      ptr += sizeof(double);
 
580
      ring->second[jdx] = *((double *) ptr);
 
581
      ptr += sizeof(double);
 
582
      
 
583
      if (hasZValue)
 
584
        ptr += sizeof(double);
 
585
      
 
586
      /*
 
587
#ifdef QGISDEBUG
 
588
std::cerr << jdx << ": " 
 
589
<< ring->first[jdx] << ", " << ring->second[jdx] << '\n';
 
590
#endif
 
591
*/
 
592
    }
 
593
    // If ring has fewer than two points, what is it then?
 
594
    // Anyway, this check prevents a crash
 
595
    if (nPoints < 1) 
 
596
    {
 
597
      QgsDebugMsg("Ring has only " + QString::number(nPoints) + " points! Skipping this ring.");
 
598
      continue;
 
599
    }
 
600
 
 
601
    transformPoints(ring->first, ring->second, zVector, mtp, projectionsEnabledFlag);
 
602
 
 
603
#if defined(Q_WS_X11)
 
604
    // Work around a +/- 32768 limitation on coordinates in X11
 
605
 
 
606
    // Look through the x and y coordinates and see if there are any
 
607
    // that need trimming. If one is found, there's no need to look at
 
608
    // the rest of them so end the loop at that point. 
 
609
    for (register unsigned int i = 0; i < nPoints; ++i)
 
610
    {
 
611
      if (std::abs(ring->first[i]) > QgsClipper::maxX ||
 
612
          std::abs(ring->second[i]) > QgsClipper::maxY)
 
613
      {
 
614
        QgsClipper::trimFeature(ring->first, ring->second, false);
 
615
        /*
 
616
#ifdef QGISDEBUG
 
617
std::cerr << "Trimmed points (" << ring->first.size() << ")\n";
 
618
for (int i = 0; i < ring->first.size(); ++i)
 
619
std::cerr << i << ": " << ring->first[i] 
 
620
<< ", " << ring->second[i] << '\n';
 
621
#endif
 
622
*/
 
623
        break;
 
624
      }
 
625
      //std::cout << "POLYGONTRANSFORM: " << ring->first[i] << ", " << ring->second[i] << std::endl; 
 
626
    }
 
627
 
 
628
#endif
 
629
 
 
630
    // Don't bother keeping the ring if it has been trimmed out of
 
631
    // existence.
 
632
    if (ring->first.size() == 0)
 
633
      delete ring;
 
634
    else
 
635
    {
 
636
      rings.push_back(ring);
 
637
      total_points += ring->first.size();
 
638
    }
 
639
  }
 
640
 
 
641
  // Now we draw the polygons
 
642
 
 
643
  // use painter paths for drawing polygons with holes
 
644
  // when adding polygon to the path they invert the area
 
645
  // this means that adding inner rings to the path creates
 
646
  // holes in outer ring
 
647
  QPainterPath path; // OddEven fill rule by default
 
648
  
 
649
  // Only try to draw polygons if there is something to draw
 
650
  if (total_points > 0)
 
651
  {
 
652
    // Store size here and use it in the loop to avoid penalty of
 
653
    // multiple calls to size()
 
654
    int numRings = rings.size();
 
655
    for (register int i = 0; i < numRings; ++i)
 
656
    {
 
657
      // Store the pointer in a variable with a short name so as to make
 
658
      // the following code easier to type and read.
 
659
      ringTypePtr r = rings[i];
 
660
      // only do this once to avoid penalty of additional calls
 
661
      unsigned ringSize = r->first.size();
 
662
 
 
663
      // Transfer points to the array of QPointF
 
664
      QPolygonF pa(ringSize);
 
665
      for (register unsigned int j = 0; j != ringSize; ++j)
 
666
      {
 
667
        pa[j].setX(r->first[j]);
 
668
        pa[j].setY(r->second[j]);
 
669
      }
 
670
 
 
671
      path.addPolygon(pa);
 
672
 
 
673
      // Tidy up the pointed to pairs of vectors as we finish with them
 
674
      delete rings[i];
 
675
    }
 
676
 
 
677
#ifdef QGISDEBUGVERBOSE
 
678
    // this is only for verbose debug output -- no optimzation is 
 
679
    // needed :)
 
680
    QgsDebugMsg("Pixel points are:");
 
681
    for (int i = 0; i < pa.size(); ++i)
 
682
      {
 
683
        QgsDebugMsgLevel("i" + QString::number(i), 2);
 
684
        QgsDebugMsgLevel("pa[i].x()" + QString::number(pa[i].x()), 2);
 
685
        QgsDebugMsgLevel("pa[i].y()" + QString::number(pa[i].y()), 2);
 
686
      }
 
687
    std::cerr << "Ring positions are:\n";
 
688
    QgsDebugMsg("Ring positions are:");
 
689
    for (int i = 0; i < ringDetails.size(); ++i)
 
690
      {
 
691
        QgsDebugMsgLevel("ringDetails[i].first" + QString::number(ringDetails[i].first), 2);
 
692
        QgsDebugMsgLevel("ringDetails[i].second" + QString::number(ringDetails[i].second), 2);
 
693
      }
 
694
    QgsDebugMsg("Outer ring point is " + QString::number(outerRingPt.x()) + ", " + QString::number(outerRingPt.y()));
 
695
#endif
 
696
 
 
697
    /*
 
698
    // A bit of code to aid in working out what values of
 
699
    // QgsClipper::minX, etc cause the X11 zoom bug.
 
700
    int largestX  = -std::numeric_limits<int>::max();
 
701
    int smallestX = std::numeric_limits<int>::max();
 
702
    int largestY  = -std::numeric_limits<int>::max();
 
703
    int smallestY = std::numeric_limits<int>::max();
 
704
 
 
705
    for (int i = 0; i < pa.size(); ++i)
 
706
    {
 
707
    largestX  = std::max(largestX,  pa.point(i).x());
 
708
    smallestX = std::min(smallestX, pa.point(i).x());
 
709
    largestY  = std::max(largestY,  pa.point(i).y());
 
710
    smallestY = std::min(smallestY, pa.point(i).y());
 
711
    }
 
712
    std::cerr << "Largest  X coordinate was " << largestX  << '\n';
 
713
    std::cerr << "Smallest X coordinate was " << smallestX << '\n';
 
714
    std::cerr << "Largest  Y coordinate was " << largestY  << '\n';
 
715
    std::cerr << "Smallest Y coordinate was " << smallestY << '\n';
 
716
    */
 
717
 
 
718
    //preserve a copy of the brush and pen before we start fiddling with it
 
719
    QBrush brush = p->brush(); //to be kept as original
 
720
    QPen pen = p->pen(); // to be kept original
 
721
    //
 
722
    // experimental alpha transparency
 
723
    // 255 = opaque
 
724
    //
 
725
    QBrush myTransparentBrush = p->brush();
 
726
    QColor myColor = brush.color();
 
727
    myColor.setAlpha(transparencyLevelInt);
 
728
    myTransparentBrush.setColor(myColor);
 
729
    QPen myTransparentPen = p->pen(); // store current pen
 
730
    myColor = myTransparentPen.color();
 
731
    myColor.setAlpha(transparencyLevelInt);
 
732
    myTransparentPen.setColor(myColor);
 
733
    
 
734
    p->setBrush(myTransparentBrush);
 
735
    p->setPen (myTransparentPen);
 
736
    
 
737
    //
 
738
    // draw the polygon
 
739
    // 
 
740
    p->drawPath(path);
 
741
    
 
742
 
 
743
    // draw vertex markers if in editing mode, but only to the main canvas
 
744
    if (
 
745
        (mEditable) &&
 
746
        (drawingToEditingCanvas)
 
747
       )
 
748
      {
 
749
        for(int i = 0; i < path.elementCount(); ++i)
 
750
          {
 
751
            const QPainterPath::Element & e = path.elementAt(i);
 
752
            drawVertexMarker((int)e.x, (int)e.y, *p);
 
753
          }
 
754
      }
 
755
 
 
756
    //
 
757
    //restore brush and pen to original
 
758
    //
 
759
    p->setBrush ( brush );
 
760
    p->setPen ( pen );
 
761
  
 
762
  } // totalPoints > 0
 
763
  
 
764
  return ptr;
 
765
}
 
766
 
 
767
 
 
768
bool QgsVectorLayer::draw(QPainter * p,
 
769
                          QgsRect * viewExtent,
 
770
                          QgsMapToPixel * theMapToPixelTransform,
 
771
                          bool drawingToEditingCanvas)
 
772
{
 
773
  draw(p,
 
774
       viewExtent,
 
775
       theMapToPixelTransform,
 
776
       drawingToEditingCanvas,
 
777
       1.,
 
778
       1.);
 
779
 
 
780
  return TRUE; // Assume success always
 
781
}
 
782
 
 
783
void QgsVectorLayer::draw(QPainter * p,
 
784
                          QgsRect * viewExtent,
 
785
                          QgsMapToPixel * theMapToPixelTransform,
 
786
                          bool drawingToEditingCanvas,
 
787
                          double widthScale,
 
788
                          double symbolScale)
 
789
{
 
790
  if(m_renderer)
 
791
  {
 
792
    // painter is active (begin has been called
 
793
    /* Steps to draw the layer
 
794
       1. get the features in the view extent by SQL query
 
795
       2. read WKB for a feature
 
796
       3. transform
 
797
       4. draw
 
798
       */
 
799
 
 
800
    QPen pen;
 
801
    /*Pointer to a marker image*/
 
802
    QPixmap marker;
 
803
    /*Scale factor of the marker image*/
 
804
    double markerScaleFactor=1.;
 
805
 
 
806
    if(mEditable)
 
807
    {
 
808
      // Destroy all cached geometries and clear the references to them
 
809
      deleteCachedGeometries();
 
810
    }
 
811
 
 
812
    dataProvider->reset();
 
813
    dataProvider->select(viewExtent);
 
814
    dataProvider->updateFeatureCount();
 
815
    int totalFeatures = dataProvider->featureCount();
 
816
    int featureCount = 0;
 
817
    QgsFeature *fet;
 
818
 
 
819
    bool projectionsEnabledFlag = projectionsEnabled();
 
820
    std::list<int> attributes=m_renderer->classificationAttributes();
 
821
 
 
822
    mDrawingCancelled=false; //pressing esc will change this to true
 
823
 
 
824
    /*
 
825
       QTime t;
 
826
       t.start();
 
827
       */
 
828
 
 
829
    try
 
830
    {
 
831
      while (fet = dataProvider->getNextFeature(attributes, updateThreshold))
 
832
      {
 
833
        // XXX Something in our draw event is triggering an additional draw event when resizing [TE 01/26/06]
 
834
        // XXX Calling this will begin processing the next draw event causing image havoc and recursion crashes.
 
835
        //qApp->processEvents(); //so we can trap for esc press
 
836
        if (mDrawingCancelled) return;
 
837
        // If update threshold is greater than 0, check to see if
 
838
        // the threshold has been exceeded
 
839
        if(updateThreshold > 0)
 
840
        {
 
841
          // signal progress in drawing
 
842
          if(0 == featureCount % updateThreshold)
 
843
            emit drawingProgress(featureCount, totalFeatures);
 
844
        }
 
845
 
 
846
        if (fet == 0)
 
847
          {
 
848
            QgsDebugMsg("get next feature returned null");
 
849
            continue;
 
850
          }
 
851
        
 
852
        if(mEditable)
 
853
          {
 
854
            if (mDeletedFeatureIds.find(fet->featureId()) != mDeletedFeatureIds.end())
 
855
              {
 
856
                delete fet;
 
857
                continue; //dont't draw feature marked as deleted
 
858
              }
 
859
            if (mChangedGeometries.find(fet->featureId()) != mChangedGeometries.end())
 
860
            {
 
861
              // substitute the committed geometry with the modified one
 
862
              fet->setGeometry( mChangedGeometries[ fet->featureId() ] );
 
863
            }
 
864
            // Cache this for the use of (e.g.) modifying the feature's uncommitted geometry.
 
865
            mCachedGeometries[fet->featureId()] = fet->geometryAndOwnership();
 
866
          }
 
867
 
 
868
        // check if feature is selected
 
869
        // only show selections of the current layer
 
870
        bool sel;
 
871
        if (
 
872
            (mLegend && mLegend->currentLayer() == this) &&
 
873
            (mSelectedFeatureIds.find(fet->featureId()) != mSelectedFeatureIds.end())
 
874
           )
 
875
        {
 
876
          sel = TRUE;
 
877
        }
 
878
        else
 
879
        {
 
880
          sel = FALSE;
 
881
        }
 
882
 
 
883
        m_renderer->renderFeature(p, fet, &marker, &markerScaleFactor, sel, widthScale );
 
884
        double scale = markerScaleFactor * symbolScale;
 
885
        drawFeature(p,
 
886
                    fet,
 
887
                    theMapToPixelTransform,
 
888
                    &marker,
 
889
                    scale,
 
890
                    projectionsEnabledFlag,
 
891
                    drawingToEditingCanvas);
 
892
        ++featureCount;
 
893
        delete fet;
 
894
      } 
 
895
 
 
896
      //also draw the not yet commited features
 
897
      if(mEditable)
 
898
        {
 
899
          for(std::vector<QgsFeature*>::iterator it = mAddedFeatures.begin(); it != mAddedFeatures.end(); ++it)
 
900
            {
 
901
              bool sel=mSelectedFeatureIds.find((*it)->featureId()) != mSelectedFeatureIds.end();
 
902
              m_renderer->renderFeature(p, *it, &marker, &markerScaleFactor, sel, widthScale);
 
903
              double scale = markerScaleFactor * symbolScale;
 
904
              if (mChangedGeometries.find((*it)->featureId()) != mChangedGeometries.end())
 
905
                {
 
906
                  (*it)->setGeometry( mChangedGeometries[(*it)->featureId() ] );
 
907
                }
 
908
              //give a deep copy of the geometry to mCachedGeometry because it will be erased at each redraw
 
909
              QgsGeometry* deepCopy = new QgsGeometry(*((*it)->geometry()));
 
910
              mCachedGeometries.insert(std::make_pair((*it)->featureId(), deepCopy));
 
911
              drawFeature(p,
 
912
                          *it,
 
913
                          theMapToPixelTransform,
 
914
                          &marker,
 
915
                          scale,
 
916
                          projectionsEnabledFlag,
 
917
                          drawingToEditingCanvas);
 
918
            }
 
919
        }
 
920
    }
 
921
    catch (QgsCsException &cse)
 
922
    {
 
923
      QString msg("Failed to transform a point while drawing a feature of type '"
 
924
          + fet->typeName() + "'. Ignoring this feature.");
 
925
      msg += cse.what();
 
926
      qWarning(msg.toLocal8Bit().data());
 
927
    }
 
928
    QgsDebugMsg("Total features processed is " + QString::number(featureCount));
 
929
    // XXX Something in our draw event is triggering an additional draw event when resizing [TE 01/26/06]
 
930
    // XXX Calling this will begin processing the next draw event causing image havoc and recursion crashes.
 
931
    //qApp->processEvents();
 
932
  }
 
933
  else
 
934
  {
 
935
    QgsLogger::warning("QgsRenderer is null in QgsVectorLayer::draw()");
 
936
  }
 
937
}
 
938
 
 
939
 
 
940
QgsVectorLayer::endian_t QgsVectorLayer::endian()
 
941
{
 
942
  //     char *chkEndian = new char[4];
 
943
  //     memset(chkEndian, '\0', 4);
 
944
  //     chkEndian[0] = 0xE8;
 
945
 
 
946
  //     int *ce = (int *) chkEndian;
 
947
  //     int retVal;
 
948
  //     if (232 == *ce)
 
949
  //       retVal = NDR;
 
950
  //     else
 
951
  //       retVal = XDR;
 
952
 
 
953
  //     delete [] chkEndian;
 
954
 
 
955
  return (htonl(1) == 1) ? QgsVectorLayer::XDR : QgsVectorLayer::NDR ;
 
956
}
 
957
 
 
958
void QgsVectorLayer::cacheGeometries()
 
959
{
 
960
  if(dataProvider)
 
961
    {
 
962
      QgsFeature* f;
 
963
 
 
964
      dataProvider->reset();
 
965
 
 
966
      while(f = dataProvider->getNextFeature(false))
 
967
        {
 
968
          mCachedGeometries.insert(std::make_pair(f->featureId(), f->geometryAndOwnership()));
 
969
          delete f;
 
970
        }
 
971
    }
 
972
}
 
973
 
 
974
void QgsVectorLayer::deleteCachedGeometries()
 
975
{
 
976
  // Destroy any cached geometries and clear the references to them
 
977
 
 
978
  for (std::map<int, QgsGeometry*>::iterator it  = mCachedGeometries.begin(); it != mCachedGeometries.end(); ++it )
 
979
    {
 
980
      delete (*it).second;
 
981
    }
 
982
  mCachedGeometries.clear();
 
983
}
 
984
 
 
985
void QgsVectorLayer::drawVertexMarker(int x, int y, QPainter& p)
 
986
{
 
987
  //todo: let the user configure the size and appearance of the marker 
 
988
  int size = 15;
 
989
  int m = (size-1)/2;
 
990
  p.drawLine(x-m, y+m, x+m, y-m);
 
991
  p.drawLine(x-m, y-m, x+m, y+m);
 
992
}
 
993
 
 
994
void QgsVectorLayer::table(QgisApp * qgisApp)
 
995
{
 
996
  if (tabledisplay)
 
997
  {
 
998
    tabledisplay->raise();
 
999
    // Give the table the most recent copy of the actions for this
 
1000
    // layer.
 
1001
    tabledisplay->table()->setAttributeActions(mActions);
 
1002
  }
 
1003
  else
 
1004
  {
 
1005
    // display the attribute table
 
1006
    QApplication::setOverrideCursor(Qt::waitCursor);
 
1007
    tabledisplay = new QgsAttributeTableDisplay(this, qgisApp);
 
1008
    connect(tabledisplay, SIGNAL(deleted()), this, SLOT(invalidateTableDisplay()));
 
1009
    tabledisplay->table()->fillTable(this);
 
1010
    tabledisplay->table()->setSorting(true);
 
1011
 
 
1012
 
 
1013
    tabledisplay->setTitle(tr("Attribute table - ") + name());
 
1014
    tabledisplay->show();
 
1015
    tabledisplay->table()->clearSelection();  //deselect the first row
 
1016
 
 
1017
    // Give the table the most recent copy of the actions for this
 
1018
    // layer.
 
1019
    tabledisplay->table()->setAttributeActions(mActions);
 
1020
 
 
1021
    QObject::disconnect(tabledisplay->table(), SIGNAL(selectionChanged()), tabledisplay->table(), SLOT(handleChangedSelections()));
 
1022
 
 
1023
    for (std::set<int>::iterator it = mSelectedFeatureIds.begin(); it != mSelectedFeatureIds.end(); ++it)
 
1024
    {
 
1025
      tabledisplay->table()->selectRowWithId(*it);//todo: avoid that the table gets repainted during each selection
 
1026
#ifdef QGISDEBUG
 
1027
      qWarning(("selecting row with id " + QString::number(*it)).toLocal8Bit().data());
 
1028
#endif
 
1029
 
 
1030
    }
 
1031
 
 
1032
    QObject::connect(tabledisplay->table(), SIGNAL(selectionChanged()), tabledisplay->table(), SLOT(handleChangedSelections()));
 
1033
 
 
1034
    //etablish the necessary connections between the table and the shapefilelayer
 
1035
    QObject::connect(tabledisplay->table(), SIGNAL(selected(int)), this, SLOT(select(int)));
 
1036
    QObject::connect(tabledisplay->table(), SIGNAL(selectionRemoved()), this, SLOT(removeSelection()));
 
1037
    QObject::connect(tabledisplay->table(), SIGNAL(repaintRequested()), this, SLOT(triggerRepaint()));
 
1038
    QApplication::restoreOverrideCursor();
 
1039
  }
 
1040
 
 
1041
} // QgsVectorLayer::table
 
1042
 
 
1043
void QgsVectorLayer::select(int number)
 
1044
{
 
1045
  mSelectedFeatureIds.insert(number);
 
1046
  emit selectionChanged();
 
1047
}
 
1048
 
 
1049
void QgsVectorLayer::select(QgsRect * rect, bool lock)
 
1050
{
 
1051
  QApplication::setOverrideCursor(Qt::WaitCursor);
 
1052
  // normalize the rectangle
 
1053
  rect->normalize();
 
1054
  if (tabledisplay)
 
1055
  {
 
1056
    QObject::disconnect(tabledisplay->table(), SIGNAL(selectionChanged()), tabledisplay->table(), SLOT(handleChangedSelections()));
 
1057
    QObject::disconnect(tabledisplay->table(), SIGNAL(selected(int)), this, SLOT(select(int))); //disconnecting because of performance reason
 
1058
  }
 
1059
 
 
1060
  if (lock == false)
 
1061
  {
 
1062
    removeSelection();        //only if ctrl-button is not pressed
 
1063
    if (tabledisplay)
 
1064
    {
 
1065
      tabledisplay->table()->clearSelection();
 
1066
    }
 
1067
  }
 
1068
 
 
1069
  QgsRect r = inverseProjectRect(*rect);
 
1070
  dataProvider->select(&r, true);
 
1071
 
 
1072
  QgsFeature *fet;
 
1073
 
 
1074
  while (fet = dataProvider->getNextFeature(false))
 
1075
  {
 
1076
    if(mDeletedFeatureIds.find(fet->featureId())==mDeletedFeatureIds.end())//don't select deleted features
 
1077
    {
 
1078
      select(fet->featureId());
 
1079
      if (tabledisplay)
 
1080
      {
 
1081
        tabledisplay->table()->selectRowWithId(fet->featureId());
 
1082
      }
 
1083
    }
 
1084
    delete fet;
 
1085
  }
 
1086
 
 
1087
  //also test the not commited features
 
1088
  for(std::vector<QgsFeature*>::iterator it=mAddedFeatures.begin();it!=mAddedFeatures.end();++it)
 
1089
  {
 
1090
    if((*it)->geometry()->intersects(rect))
 
1091
    {
 
1092
      select((*it)->featureId());
 
1093
      if (tabledisplay)
 
1094
      {
 
1095
        tabledisplay->table()->selectRowWithId((*it)->featureId());
 
1096
      }
 
1097
    }
 
1098
  }
 
1099
 
 
1100
  if (tabledisplay)
 
1101
  {
 
1102
    QObject::connect(tabledisplay->table(), SIGNAL(selectionChanged()), tabledisplay->table(), SLOT(handleChangedSelections()));
 
1103
    QObject::connect(tabledisplay->table(), SIGNAL(selected(int)), this, SLOT(select(int)));  //disconnecting because of performance reason
 
1104
  }
 
1105
  triggerRepaint();
 
1106
  QApplication::restoreOverrideCursor();
 
1107
 
 
1108
  emit selectionChanged();
 
1109
}
 
1110
 
 
1111
void QgsVectorLayer::invertSelection()
 
1112
{
 
1113
  QApplication::setOverrideCursor(Qt::waitCursor);
 
1114
  if (tabledisplay)
 
1115
  {
 
1116
    QObject::disconnect(tabledisplay->table(), SIGNAL(selectionChanged()), tabledisplay->table(), SLOT(handleChangedSelections()));
 
1117
    QObject::disconnect(tabledisplay->table(), SIGNAL(selected(int)), this, SLOT(select(int))); //disconnecting because of performance reason
 
1118
    tabledisplay->hide();
 
1119
  }
 
1120
 
 
1121
 
 
1122
  //copy the ids of selected features to tmp
 
1123
  std::list<int> tmp;
 
1124
  for(std::set<int>::iterator iter=mSelectedFeatureIds.begin();iter!=mSelectedFeatureIds.end();++iter)
 
1125
  {
 
1126
    tmp.push_back(*iter);
 
1127
  }
 
1128
 
 
1129
  removeSelection();
 
1130
  if (tabledisplay)
 
1131
  {
 
1132
    tabledisplay->table()->clearSelection();
 
1133
  }
 
1134
 
 
1135
  QgsFeature *fet;
 
1136
  dataProvider->reset();
 
1137
 
 
1138
  while (fet = dataProvider->getNextFeature(true))
 
1139
  {
 
1140
    if(mDeletedFeatureIds.find(fet->featureId())==mDeletedFeatureIds.end())//don't select deleted features
 
1141
    {
 
1142
      select(fet->featureId());
 
1143
    }
 
1144
  }
 
1145
 
 
1146
  for(std::vector<QgsFeature*>::iterator iter=mAddedFeatures.begin();iter!=mAddedFeatures.end();++iter)
 
1147
  {
 
1148
    select((*iter)->featureId());
 
1149
  }
 
1150
 
 
1151
  for(std::list<int>::iterator iter=tmp.begin();iter!=tmp.end();++iter)
 
1152
  {
 
1153
    mSelectedFeatureIds.erase(*iter);
 
1154
  }
 
1155
 
 
1156
  if(tabledisplay)
 
1157
  {
 
1158
    QProgressDialog progress( tr("Invert Selection..."), tr("Abort"), 0, mSelectedFeatureIds.size(), tabledisplay);
 
1159
    int i=0;
 
1160
    for(std::set<int>::iterator iter=mSelectedFeatureIds.begin();iter!=mSelectedFeatureIds.end();++iter)
 
1161
    {
 
1162
      ++i;
 
1163
      progress.setValue(i);
 
1164
      qApp->processEvents();
 
1165
      if(progress.wasCanceled())
 
1166
      {
 
1167
        //deselect the remaining features if action was canceled
 
1168
        mSelectedFeatureIds.erase(iter,--mSelectedFeatureIds.end());
 
1169
        break;
 
1170
      }
 
1171
      tabledisplay->table()->selectRowWithId(*iter);//todo: avoid that the table gets repainted during each selection
 
1172
    }
 
1173
  }
 
1174
 
 
1175
  if (tabledisplay)
 
1176
  {
 
1177
    QObject::connect(tabledisplay->table(), SIGNAL(selectionChanged()), tabledisplay->table(), SLOT(handleChangedSelections()));
 
1178
    QObject::connect(tabledisplay->table(), SIGNAL(selected(int)), this, SLOT(select(int)));  //disconnecting because of performance reason
 
1179
    tabledisplay->show();
 
1180
  }
 
1181
 
 
1182
  triggerRepaint();
 
1183
  QApplication::restoreOverrideCursor();
 
1184
 
 
1185
  emit selectionChanged();
 
1186
}
 
1187
 
 
1188
void QgsVectorLayer::removeSelection()
 
1189
{
 
1190
  mSelectedFeatureIds.clear();
 
1191
  emit selectionChanged();
 
1192
}
 
1193
 
 
1194
void QgsVectorLayer::triggerRepaint()
 
1195
 
1196
  emit repaintRequested();
 
1197
}
 
1198
 
 
1199
void QgsVectorLayer::invalidateTableDisplay()
 
1200
{
 
1201
  tabledisplay = 0;
 
1202
}
 
1203
 
 
1204
QgsVectorDataProvider* QgsVectorLayer::getDataProvider()
 
1205
{
 
1206
  return dataProvider;
 
1207
}
 
1208
 
 
1209
const QgsVectorDataProvider* QgsVectorLayer::getDataProvider() const
 
1210
{
 
1211
  return dataProvider;
 
1212
}
 
1213
 
 
1214
void QgsVectorLayer::setProviderEncoding(const QString& encoding)
 
1215
{
 
1216
  if(dataProvider)
 
1217
  {
 
1218
    dataProvider->setEncoding(encoding);
 
1219
  }
 
1220
}
 
1221
 
 
1222
 
 
1223
void QgsVectorLayer::showLayerProperties()
 
1224
{
 
1225
  // Set wait cursor while the property dialog is created
 
1226
  // and initialized
 
1227
  qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
 
1228
 
 
1229
 
 
1230
  if (!m_propertiesDialog)
 
1231
  {
 
1232
#ifdef QGISDEBUG
 
1233
    std::cerr << "Creating new QgsVectorLayerProperties object\n";
 
1234
#endif
 
1235
    m_propertiesDialog = new QgsVectorLayerProperties(this);
 
1236
    // Make sure that the UI starts out with the correct display
 
1237
    // field value
 
1238
#ifdef QGISDEBUG
 
1239
    std::cerr << "Setting display field in prop dialog\n";
 
1240
#endif
 
1241
    m_propertiesDialog->setDisplayField(displayField());
 
1242
 
 
1243
#ifdef QGISDEBUG
 
1244
    std::cerr << "Raising prop dialog\n";
 
1245
#endif
 
1246
    m_propertiesDialog->raise();
 
1247
#ifdef QGISDEBUG
 
1248
    std::cerr << "Showing prop dialog\n";
 
1249
#endif
 
1250
    m_propertiesDialog->show();
 
1251
  }
 
1252
  else
 
1253
  {
 
1254
    m_propertiesDialog->reset();
 
1255
    m_propertiesDialog->show();
 
1256
    m_propertiesDialog->raise();
 
1257
  }
 
1258
 
 
1259
  // restore normal cursor
 
1260
  qApp->restoreOverrideCursor();
 
1261
}
 
1262
 
 
1263
 
 
1264
const QgsRenderer* QgsVectorLayer::renderer() const
 
1265
{
 
1266
  return m_renderer;
 
1267
}
 
1268
 
 
1269
void QgsVectorLayer::setRenderer(QgsRenderer * r)
 
1270
{
 
1271
  if (r != m_renderer)
 
1272
  {
 
1273
    delete m_renderer;
 
1274
    m_renderer = r;
 
1275
  }
 
1276
}
 
1277
 
 
1278
QGis::VectorType QgsVectorLayer::vectorType() const
 
1279
{
 
1280
  if (dataProvider)
 
1281
  {
 
1282
    int type = dataProvider->geometryType();
 
1283
    switch (type)
 
1284
    {
 
1285
      case QGis::WKBPoint:
 
1286
      case QGis::WKBPoint25D:
 
1287
        return QGis::Point;
 
1288
 
 
1289
      case QGis::WKBLineString:
 
1290
      case QGis::WKBLineString25D:
 
1291
        return QGis::Line;
 
1292
 
 
1293
      case QGis::WKBPolygon:
 
1294
      case QGis::WKBPolygon25D:
 
1295
        return QGis::Polygon;
 
1296
 
 
1297
      case QGis::WKBMultiPoint:
 
1298
      case QGis::WKBMultiPoint25D:
 
1299
        return QGis::Point;
 
1300
 
 
1301
      case QGis::WKBMultiLineString:
 
1302
      case QGis::WKBMultiLineString25D:
 
1303
        return QGis::Line;
 
1304
 
 
1305
      case QGis::WKBMultiPolygon:
 
1306
      case QGis::WKBMultiPolygon25D:
 
1307
        return QGis::Polygon;
 
1308
    }
 
1309
#ifdef QGISDEBUG
 
1310
    QgsLogger::debug("Warning: Data Provider Geometry type is not recognised, is", type, 1, __FILE__, __FUNCTION__, __LINE__);
 
1311
#endif
 
1312
 
 
1313
  }
 
1314
  else
 
1315
  {
 
1316
#ifdef QGISDEBUG
 
1317
    qWarning("warning, pointer to dataProvider is null in QgsVectorLayer::vectorType()");
 
1318
#endif
 
1319
 
 
1320
  }
 
1321
 
 
1322
  // We shouldn't get here, and if we have, other things are likely to
 
1323
  // go wrong. Code that uses the vectorType() return value should be
 
1324
  // rewritten to cope with a value of QGis::Unknown. To make this
 
1325
  // need known, the following message is printed every time we get
 
1326
  // here.
 
1327
  std::cerr << "WARNING: This code (file " << __FILE__ << ", line "
 
1328
            << __LINE__ << ") should never be reached. "
 
1329
            << "Problems may occur...\n";
 
1330
 
 
1331
  return QGis::Unknown;
 
1332
}
 
1333
 
 
1334
QGis::WKBTYPE QgsVectorLayer::getGeometryType() const
 
1335
{
 
1336
  return (QGis::WKBTYPE)(geometryType);
 
1337
}
 
1338
 
 
1339
QgsVectorLayerProperties *QgsVectorLayer::propertiesDialog()
 
1340
{
 
1341
  return m_propertiesDialog;
 
1342
}
 
1343
 
 
1344
 
 
1345
void QgsVectorLayer::initContextMenu_(QgisApp * app)
 
1346
{
 
1347
 
 
1348
  popMenu->addAction(tr("&Open attribute table"), app, SLOT(attributeTable()));
 
1349
 
 
1350
  popMenu->addSeparator();
 
1351
 
 
1352
  int cap=dataProvider->capabilities();
 
1353
  if((cap&QgsVectorDataProvider::AddFeatures)
 
1354
      ||(cap&QgsVectorDataProvider::DeleteFeatures))
 
1355
  {
 
1356
    mToggleEditingAction = popMenu->addAction(tr("Allow Editing"),this,SLOT(toggleEditing()));
 
1357
    mToggleEditingAction->setCheckable(true);
 
1358
    mToggleEditingAction->blockSignals(true);
 
1359
    if(mEditable)
 
1360
      {
 
1361
        mToggleEditingAction->setChecked(true);
 
1362
      }
 
1363
    else
 
1364
      {
 
1365
        mToggleEditingAction->setChecked(false);
 
1366
      }
 
1367
    mToggleEditingAction->blockSignals(false);
 
1368
  }
 
1369
 
 
1370
  if(cap&QgsVectorDataProvider::SaveAsShapefile)
 
1371
  {
 
1372
    // add the save as shapefile menu item
 
1373
    popMenu->addSeparator();
 
1374
    popMenu->addAction(tr("Save as shapefile..."), this, SLOT(saveAsShapefile()));
 
1375
  }
 
1376
 
 
1377
} // QgsVectorLayer::initContextMenu_(QgisApp * app)
 
1378
 
 
1379
QgsRect QgsVectorLayer::bBoxOfSelected()
 
1380
{
 
1381
  if(mSelectedFeatureIds.size()==0)//no selected features
 
1382
  {
 
1383
    return QgsRect(0,0,0,0);
 
1384
  }
 
1385
 
 
1386
  QgsRect r, retval;
 
1387
  QgsFeature* fet;
 
1388
  dataProvider->reset();
 
1389
 
 
1390
  retval.setMinimal();
 
1391
  while ((fet = dataProvider->getNextFeature(false)))
 
1392
  {
 
1393
    if (mSelectedFeatureIds.find(fet->featureId()) != mSelectedFeatureIds.end())
 
1394
    {
 
1395
      if(fet->geometry())
 
1396
        {
 
1397
          r=fet->boundingBox();
 
1398
          retval.combineExtentWith(&r);
 
1399
        }
 
1400
    }
 
1401
    delete fet;
 
1402
  }
 
1403
  //also go through the not commited features
 
1404
  for(std::vector<QgsFeature*>::iterator iter=mAddedFeatures.begin();iter!=mAddedFeatures.end();++iter)
 
1405
  {
 
1406
    if(mSelectedFeatureIds.find((*iter)->featureId())!=mSelectedFeatureIds.end())
 
1407
    {
 
1408
      r=(*iter)->geometry()->boundingBox();
 
1409
      retval.combineExtentWith(&r);
 
1410
    }
 
1411
  }
 
1412
 
 
1413
  if (retval.width() == 0.0 || retval.height() == 0.0)
 
1414
  {
 
1415
    // If all of the features are at the one point, buffer the
 
1416
    // rectangle a bit. If they are all at zero, do something a bit
 
1417
    // more crude.
 
1418
 
 
1419
    if (retval.xMin() == 0.0 && retval.xMax() == 0.0 &&
 
1420
        retval.yMin() == 0.0 && retval.yMax() == 0.0)
 
1421
    {
 
1422
      retval.set(-1.0, -1.0, 1.0, 1.0);
 
1423
    }
 
1424
    else
 
1425
    {
 
1426
      const double padFactor = 1e-8;
 
1427
      double widthPad = retval.xMin() * padFactor;
 
1428
      double heightPad = retval.yMin() * padFactor;
 
1429
      double xmin = retval.xMin() - widthPad;
 
1430
      double xmax = retval.xMax() + widthPad;
 
1431
      double ymin = retval.yMin() - heightPad;
 
1432
      double ymax = retval.yMax() + heightPad;
 
1433
      retval.set(xmin, ymin, xmax, ymax);
 
1434
    }
 
1435
  }
 
1436
 
 
1437
  return retval;
 
1438
}
 
1439
 
 
1440
void QgsVectorLayer::setLayerProperties(QgsVectorLayerProperties * properties)
 
1441
{
 
1442
  m_propertiesDialog = properties;
 
1443
  // Make sure that the UI gets the correct display
 
1444
  // field value
 
1445
 
 
1446
  if(m_propertiesDialog)
 
1447
  {
 
1448
    m_propertiesDialog->setDisplayField(displayField());
 
1449
  }
 
1450
}
 
1451
 
 
1452
 
 
1453
 
 
1454
QgsFeature * QgsVectorLayer::getFirstFeature(bool fetchAttributes, bool selected) const
 
1455
{
 
1456
  if ( ! dataProvider )
 
1457
  {
 
1458
    std::cerr << __FILE__ << ":" << __LINE__
 
1459
      << " QgsVectorLayer::getFirstFeature() invoked with null dataProvider\n";
 
1460
    return 0x0;
 
1461
  }
 
1462
 
 
1463
  if ( selected )
 
1464
  {
 
1465
    QgsFeature *fet = dataProvider->getFirstFeature(fetchAttributes);
 
1466
    while(fet)
 
1467
    {
 
1468
      bool sel = mSelectedFeatureIds.find(fet->featureId()) != mSelectedFeatureIds.end();
 
1469
      if ( sel ) return fet;
 
1470
      fet = dataProvider->getNextFeature(fetchAttributes);
 
1471
    }
 
1472
    return 0;
 
1473
  }
 
1474
 
 
1475
  return dataProvider->getFirstFeature( fetchAttributes );
 
1476
} // QgsVectorLayer::getFirstFeature
 
1477
 
 
1478
 
 
1479
QgsFeature * QgsVectorLayer::getNextFeature(bool fetchAttributes, bool selected) const
 
1480
{
 
1481
  if ( ! dataProvider )
 
1482
  {
 
1483
    std::cerr << __FILE__ << ":" << __LINE__
 
1484
      << " QgsVectorLayer::getNextFeature() invoked with null dataProvider\n";
 
1485
    return 0x0;
 
1486
  }
 
1487
 
 
1488
  if ( selected )
 
1489
  {
 
1490
    QgsFeature *fet;
 
1491
    while ( fet = dataProvider->getNextFeature(fetchAttributes) )
 
1492
    {
 
1493
      bool sel = mSelectedFeatureIds.find(fet->featureId()) != mSelectedFeatureIds.end();
 
1494
      if ( sel ) return fet;
 
1495
    }
 
1496
    return 0;
 
1497
  }
 
1498
 
 
1499
  return dataProvider->getNextFeature( fetchAttributes );
 
1500
} // QgsVectorLayer::getNextFeature
 
1501
 
 
1502
 
 
1503
 
 
1504
bool QgsVectorLayer::getNextFeature(QgsFeature &feature, bool fetchAttributes) const
 
1505
{
 
1506
  if ( ! dataProvider )
 
1507
  {
 
1508
    std::cerr << __FILE__ << ":" << __LINE__
 
1509
      << " QgsVectorLayer::getNextFeature() invoked with null dataProvider\n";
 
1510
    return false;
 
1511
  }
 
1512
 
 
1513
  return dataProvider->getNextFeature( feature, fetchAttributes );
 
1514
} // QgsVectorLayer::getNextFeature
 
1515
 
 
1516
 
 
1517
 
 
1518
long QgsVectorLayer::featureCount() const
 
1519
{
 
1520
  if ( ! dataProvider )
 
1521
  {
 
1522
    std::cerr << __FILE__ << ":" << __LINE__
 
1523
      << " QgsVectorLayer::featureCount() invoked with null dataProvider\n";
 
1524
    return 0;
 
1525
  }
 
1526
 
 
1527
  return dataProvider->featureCount();
 
1528
} // QgsVectorLayer::featureCount
 
1529
 
 
1530
long QgsVectorLayer::updateFeatureCount() const
 
1531
{
 
1532
  if ( ! dataProvider )
 
1533
  {
 
1534
    std::cerr << __FILE__ << ":" << __LINE__
 
1535
      << " QgsVectorLayer::updateFeatureCount() invoked with null dataProvider\n";
 
1536
    return 0;
 
1537
  }
 
1538
  return dataProvider->updateFeatureCount();
 
1539
}
 
1540
 
 
1541
void QgsVectorLayer::updateExtents()
 
1542
{
 
1543
  if(dataProvider)
 
1544
  {
 
1545
    if(mDeletedFeatureIds.size()==0)
 
1546
    {
 
1547
      // get the extent of the layer from the provider
 
1548
      layerExtent.setXmin(dataProvider->extent()->xMin());
 
1549
      layerExtent.setYmin(dataProvider->extent()->yMin());
 
1550
      layerExtent.setXmax(dataProvider->extent()->xMax());
 
1551
      layerExtent.setYmax(dataProvider->extent()->yMax());
 
1552
    }
 
1553
    else
 
1554
    {
 
1555
      QgsFeature* fet=0;
 
1556
      QgsRect bb;
 
1557
 
 
1558
      layerExtent.setMinimal();
 
1559
      dataProvider->reset();
 
1560
      while(fet=dataProvider->getNextFeature(false))
 
1561
      {
 
1562
        if(mDeletedFeatureIds.find(fet->featureId())==mDeletedFeatureIds.end())
 
1563
        {
 
1564
          if(fet->geometry())
 
1565
            {
 
1566
              bb=fet->boundingBox();
 
1567
              layerExtent.combineExtentWith(&bb);
 
1568
            }
 
1569
        }
 
1570
        delete fet;
 
1571
      }
 
1572
    }
 
1573
  }
 
1574
  else
 
1575
  {
 
1576
    std::cerr << __FILE__ << ":" << __LINE__
 
1577
      << " QgsVectorLayer::updateFeatureCount() invoked with null dataProvider\n";
 
1578
  }
 
1579
 
 
1580
  //todo: also consider the not commited features
 
1581
  for(std::vector<QgsFeature*>::iterator iter=mAddedFeatures.begin();iter!=mAddedFeatures.end();++iter)
 
1582
  {
 
1583
    QgsRect bb=(*iter)->boundingBox();
 
1584
    layerExtent.combineExtentWith(&bb);
 
1585
 
 
1586
  }
 
1587
 
 
1588
  // Send this (hopefully) up the chain to the map canvas
 
1589
  emit recalculateExtents();
 
1590
}
 
1591
 
 
1592
QString QgsVectorLayer::subsetString()
 
1593
{
 
1594
  if ( ! dataProvider )
 
1595
  {
 
1596
    std::cerr << __FILE__ << ":" << __LINE__
 
1597
      << " QgsVectorLayer::subsetString() invoked with null dataProvider\n";
 
1598
    return 0;
 
1599
  }
 
1600
  return dataProvider->subsetString();
 
1601
}
 
1602
void QgsVectorLayer::setSubsetString(QString subset)
 
1603
{
 
1604
  if ( ! dataProvider )
 
1605
  {
 
1606
    std::cerr << __FILE__ << ":" << __LINE__
 
1607
      << " QgsVectorLayer::setSubsetString() invoked with null dataProvider\n";
 
1608
  }
 
1609
  else
 
1610
  {
 
1611
    dataProvider->setSubsetString(subset);
 
1612
    // get the updated data source string from the provider
 
1613
    dataSource = dataProvider->getDataSourceUri();
 
1614
    updateExtents();
 
1615
  }
 
1616
  //trigger a recalculate extents request to any attached canvases
 
1617
#ifdef QGISDEBUG
 
1618
  std::cout << "Subset query changed, emitting recalculateExtents() signal" << std::endl;
 
1619
#endif
 
1620
  // emit the signal  to inform any listeners that the extent of this
 
1621
  // layer has changed
 
1622
  emit recalculateExtents();
 
1623
}
 
1624
int QgsVectorLayer::fieldCount() const
 
1625
{
 
1626
  if ( ! dataProvider )
 
1627
  {
 
1628
    std::cerr << __FILE__ << ":" << __LINE__
 
1629
      << " QgsVectorLayer::fieldCount() invoked with null dataProvider\n";
 
1630
    return 0;
 
1631
  }
 
1632
 
 
1633
  return dataProvider->fieldCount();
 
1634
} // QgsVectorLayer::fieldCount
 
1635
 
 
1636
 
 
1637
std::vector<QgsField> const& QgsVectorLayer::fields() const
 
1638
{
 
1639
  if ( ! dataProvider )
 
1640
  {
 
1641
    std::cerr << __FILE__ << ":" << __LINE__
 
1642
      << " QgsVectorLayer::fields() invoked with null dataProvider\n";
 
1643
 
 
1644
    static std::vector<QgsField> bogus; // empty, bogus container
 
1645
    return bogus;
 
1646
  }
 
1647
 
 
1648
  return dataProvider->fields();
 
1649
} // QgsVectorLayer::fields()
 
1650
 
 
1651
 
 
1652
bool QgsVectorLayer::addFeature(QgsFeature* f, bool alsoUpdateExtent)
 
1653
{
 
1654
  static int addedIdLowWaterMark = -1;
 
1655
 
 
1656
  if(dataProvider)
 
1657
  {
 
1658
    if(!(dataProvider->capabilities() & QgsVectorDataProvider::AddFeatures))
 
1659
    {
 
1660
      QMessageBox::information(0, tr("Layer cannot be added to"), 
 
1661
          tr("The data provider for this layer does not support the addition of features."));
 
1662
      return false;
 
1663
    }
 
1664
 
 
1665
    if(!isEditable())
 
1666
    {
 
1667
      QMessageBox::information(0, tr("Layer not editable"), 
 
1668
          tr("The current layer is not editable. Choose 'Start editing' in the digitizing toolbar."));
 
1669
      return false;
 
1670
    }
 
1671
 
 
1672
    //assign a temporary id to the feature (use negative numbers)
 
1673
    addedIdLowWaterMark--;
 
1674
 
 
1675
#ifdef QGISDEBUG
 
1676
    qWarning("assigned feature id "+QString::number(addedIdLowWaterMark));
 
1677
#endif
 
1678
 
 
1679
    // Change the fields on the feature to suit the destination
 
1680
    // in the paste transformation transfer.
 
1681
    // TODO: Could be done more efficiently for large pastes
 
1682
    std::map<int, QString> fields = f->fields();
 
1683
 
 
1684
#ifdef QGISDEBUG
 
1685
    std::cout << "QgsVectorLayer::addFeature: about to traverse fields." << std::endl;
 
1686
#endif
 
1687
    for (std::map<int, QString>::iterator it  = fields.begin(); it != fields.end(); ++it)
 
1688
    {
 
1689
#ifdef QGISDEBUG
 
1690
      std::cout << "QgsVectorLayer::addFeature: inspecting field '"
 
1691
        << (it->second).toLocal8Bit().data()
 
1692
        << "'." << std::endl;
 
1693
#endif
 
1694
 
 
1695
    }
 
1696
 
 
1697
    // Force a feature ID (to keep other functions in QGIS happy,
 
1698
    // providers will use their own new feature ID when we commit the new feature)
 
1699
    // and add to the known added features.
 
1700
    f->setFeatureId(addedIdLowWaterMark);
 
1701
    mAddedFeatures.push_back(f);
 
1702
    mModified=true;
 
1703
 
 
1704
    //hide and delete the table because it is not up to date any more
 
1705
    if (tabledisplay)
 
1706
    {
 
1707
      tabledisplay->close();
 
1708
      delete tabledisplay;
 
1709
      tabledisplay=0;
 
1710
    }
 
1711
 
 
1712
    if (alsoUpdateExtent)
 
1713
    {
 
1714
      updateExtents();
 
1715
    }  
 
1716
 
 
1717
    return true;
 
1718
  }
 
1719
  return false;
 
1720
}
 
1721
 
 
1722
 
 
1723
bool QgsVectorLayer::insertVertexBefore(double x, double y, int atFeatureId, QgsGeometryVertexIndex beforeVertex)
 
1724
{
 
1725
  if(!mEditable)
 
1726
    {
 
1727
      return false;
 
1728
    }
 
1729
 
 
1730
  if(dataProvider)
 
1731
  {
 
1732
    if(mChangedGeometries.find(atFeatureId) == mChangedGeometries.end())
 
1733
    {
 
1734
      //first time this geometry has changed since last commit
 
1735
      if(!mCachedGeometries[atFeatureId])
 
1736
        {
 
1737
          return false;
 
1738
        }
 
1739
      mChangedGeometries[atFeatureId] = *(mCachedGeometries[atFeatureId]);
 
1740
    }
 
1741
    
 
1742
    mChangedGeometries[atFeatureId].insertVertexBefore(x, y, beforeVertex);
 
1743
    mModified=true;
 
1744
    return true;
 
1745
  }
 
1746
  return false;
 
1747
}
 
1748
 
 
1749
 
 
1750
bool QgsVectorLayer::moveVertexAt(double x, double y, int atFeatureId,
 
1751
    QgsGeometryVertexIndex atVertex)
 
1752
{
 
1753
  if(!mEditable)
 
1754
    {
 
1755
      return false;
 
1756
    }
 
1757
 
 
1758
  if(dataProvider)
 
1759
  {
 
1760
    if(mChangedGeometries.find(atFeatureId) == mChangedGeometries.end())
 
1761
    {
 
1762
      // first time this geometry has changed since last commit
 
1763
      if(mCachedGeometries.find(atFeatureId) == mCachedGeometries.end() || mCachedGeometries[atFeatureId] == 0)
 
1764
        {
 
1765
          return false;
 
1766
        }
 
1767
      mChangedGeometries[atFeatureId] = *(mCachedGeometries[atFeatureId]);
 
1768
    }
 
1769
 
 
1770
    mChangedGeometries[atFeatureId].moveVertexAt(x, y, atVertex);
 
1771
    mModified=true;
 
1772
    return true;
 
1773
  }
 
1774
  return false;
 
1775
}
 
1776
 
 
1777
 
 
1778
bool QgsVectorLayer::deleteVertexAt(int atFeatureId,
 
1779
    QgsGeometryVertexIndex atVertex)
 
1780
{
 
1781
  if(!mEditable)
 
1782
    {
 
1783
      return false;
 
1784
    }
 
1785
 
 
1786
  if(dataProvider)
 
1787
  {
 
1788
    if(mChangedGeometries.find(atFeatureId) == mChangedGeometries.end())
 
1789
    {
 
1790
      // first time this geometry has changed since last commit
 
1791
      if(!mCachedGeometries[atFeatureId])
 
1792
        {
 
1793
          return false;
 
1794
        }
 
1795
      mChangedGeometries[atFeatureId] = *(mCachedGeometries[atFeatureId]);
 
1796
    }
 
1797
 
 
1798
    mChangedGeometries[atFeatureId].deleteVertexAt(atVertex);
 
1799
    mModified=true;
 
1800
    return true;
 
1801
  }
 
1802
  return false;
 
1803
}
 
1804
 
 
1805
 
 
1806
QString QgsVectorLayer::getDefaultValue(const QString& attr,
 
1807
    QgsFeature* f)
 
1808
{
 
1809
  return dataProvider->getDefaultValue(attr, f);
 
1810
}
 
1811
 
 
1812
bool QgsVectorLayer::deleteSelectedFeatures()
 
1813
{
 
1814
  if(!(dataProvider->capabilities() & QgsVectorDataProvider::DeleteFeatures))
 
1815
  {
 
1816
    QMessageBox::information(0, tr("Provider does not support deletion"), 
 
1817
        tr("Data provider does not support deleting features"));
 
1818
    return false;
 
1819
  }
 
1820
 
 
1821
  if(!isEditable())
 
1822
  {
 
1823
    QMessageBox::information(0, tr("Layer not editable"), 
 
1824
        tr("The current layer is not editable. Choose 'Allow editing' in the legend item right click menu"));
 
1825
    return false;
 
1826
  }
 
1827
 
 
1828
  for(std::set<int>::iterator it=mSelectedFeatureIds.begin();it!=mSelectedFeatureIds.end();++it)
 
1829
  {
 
1830
    bool notcommitedfeature=false;
 
1831
    //first test, if the feature with this id is a not-commited feature
 
1832
    for(std::vector<QgsFeature*>::iterator iter=mAddedFeatures.begin();iter!=mAddedFeatures.end();++iter)
 
1833
    {
 
1834
      if((*it)==(*iter)->featureId())
 
1835
      {
 
1836
        // Delete the feature itself before deleting the reference to it.
 
1837
        delete *iter;
 
1838
        mAddedFeatures.erase(iter);
 
1839
 
 
1840
        notcommitedfeature=true;
 
1841
        break;
 
1842
      }
 
1843
    }
 
1844
    if(!notcommitedfeature)
 
1845
    {
 
1846
      mDeletedFeatureIds.insert(*it);
 
1847
    }
 
1848
  }
 
1849
 
 
1850
  if(mSelectedFeatureIds.size()>0)
 
1851
  {
 
1852
    mModified=true;
 
1853
    /*      mSelectedFeatureIds.clear();*/
 
1854
    removeSelection();
 
1855
    triggerRepaint();
 
1856
    updateExtents();
 
1857
 
 
1858
    //hide and delete the table because it is not up to date any more
 
1859
    if (tabledisplay)
 
1860
    {
 
1861
      tabledisplay->close();
 
1862
      delete tabledisplay;
 
1863
      tabledisplay=0;
 
1864
    }
 
1865
 
 
1866
  }
 
1867
 
 
1868
  return true;
 
1869
}
 
1870
 
 
1871
QgsLabel * QgsVectorLayer::label()
 
1872
{
 
1873
  return mLabel;
 
1874
}
 
1875
 
 
1876
void QgsVectorLayer::setLabelOn ( bool on )
 
1877
{
 
1878
  mLabelOn = on;
 
1879
}
 
1880
 
 
1881
bool QgsVectorLayer::labelOn ( void )
 
1882
{
 
1883
  return mLabelOn;
 
1884
}
 
1885
 
 
1886
void QgsVectorLayer::toggleEditing()
 
1887
{
 
1888
  if(mToggleEditingAction)
 
1889
  {
 
1890
    if (mToggleEditingAction->isChecked() ) //checking of the QAction is done before calling this slot
 
1891
    {
 
1892
      startEditing();
 
1893
    }
 
1894
    else
 
1895
    {
 
1896
      stopEditing();
 
1897
    }
 
1898
  }
 
1899
}
 
1900
 
 
1901
 
 
1902
void QgsVectorLayer::startEditing()
 
1903
{
 
1904
  if(dataProvider)
 
1905
  {
 
1906
    if(!(dataProvider->capabilities()&QgsVectorDataProvider::AddFeatures))
 
1907
    {
 
1908
      QMessageBox::information(0,tr("Start editing failed"),
 
1909
                               tr("Provider cannot be opened for editing"),
 
1910
                               QMessageBox::Ok);
 
1911
    }
 
1912
    else
 
1913
    {
 
1914
      // No longer need to cache all geometries
 
1915
      // instead, mCachedGeometries is refreshed every time the 
 
1916
      // screen is redrawn.
 
1917
      //cacheGeometries();
 
1918
 
 
1919
      mEditable=true;
 
1920
      if(isValid())
 
1921
      {
 
1922
        updateItemPixmap();
 
1923
        if(mToggleEditingAction)
 
1924
        {
 
1925
          mToggleEditingAction->setChecked(true);
 
1926
        }
 
1927
        triggerRepaint();
 
1928
      }
 
1929
    }
 
1930
  }
 
1931
}
 
1932
 
 
1933
void QgsVectorLayer::stopEditing()
 
1934
{
 
1935
  bool commitSuccessful = FALSE;
 
1936
  bool rollbackSuccessful = FALSE;
 
1937
 
 
1938
  if(dataProvider)
 
1939
  {
 
1940
    if(mModified)
 
1941
    {
 
1942
      //commit or roll back?
 
1943
      int commit=QMessageBox::information(0,tr("Stop editing"),tr("Do you want to save the changes?"),tr("&Yes"),tr("&No"),QString::null,0,1);  
 
1944
 
 
1945
      if(commit==0)
 
1946
      {
 
1947
        commitSuccessful = commitChanges();
 
1948
 
 
1949
        if(!commitSuccessful)
 
1950
        {
 
1951
          QMessageBox::information(0,tr("Error"),tr("Could not commit changes"),QMessageBox::Ok);
 
1952
 
 
1953
          // Leave the in-memory editing state alone,
 
1954
          // to give the user a chance to enter different values
 
1955
          // and try the commit again later
 
1956
        }
 
1957
        else
 
1958
        {
 
1959
          dataProvider->updateExtents();
 
1960
          dataProvider->updateFeatureCount();
 
1961
          //hide and delete the table because it is not up to date any more
 
1962
          if (tabledisplay)
 
1963
          {
 
1964
            tabledisplay->close();
 
1965
            delete tabledisplay;
 
1966
            tabledisplay=0;
 
1967
          }
 
1968
        }
 
1969
      }
 
1970
      else if(commit==1)
 
1971
      {
 
1972
        if(!rollBack())
 
1973
        {
 
1974
          QMessageBox::information(0,tr("Error"),
 
1975
              tr("Problems during roll back"),QMessageBox::Ok);
 
1976
        }
 
1977
        //hide and delete the table because it is not up to date any more
 
1978
        if (tabledisplay)
 
1979
        {
 
1980
          tabledisplay->close();
 
1981
          delete tabledisplay;
 
1982
          tabledisplay=0;
 
1983
        }
 
1984
 
 
1985
        // Force this to TRUE otherwise the user will never be able
 
1986
        // to get out of an ediitng session
 
1987
        rollbackSuccessful = TRUE;
 
1988
      }
 
1989
      emit editingStopped(true);
 
1990
    }
 
1991
    else  // if (!mModified)
 
1992
    {
 
1993
      emit editingStopped(false);
 
1994
    }
 
1995
 
 
1996
  }
 
1997
 
 
1998
  if (
 
1999
      (!dataProvider) ||
 
2000
      (!mModified) ||
 
2001
      (commitSuccessful) ||
 
2002
      (rollbackSuccessful)
 
2003
     )
 
2004
  {
 
2005
    // convert state to non-editing mode
 
2006
    deleteCachedGeometries();
 
2007
 
 
2008
    mEditable=false;
 
2009
    triggerRepaint();
 
2010
    mModified=false;
 
2011
    if(isValid())
 
2012
    {
 
2013
      updateItemPixmap();
 
2014
      if(mToggleEditingAction)
 
2015
      {
 
2016
        mToggleEditingAction->setChecked(false);
 
2017
      }
 
2018
    }
 
2019
  }
 
2020
 
 
2021
}
 
2022
 
 
2023
// return state of scale dependent rendering. True if features should
 
2024
// only be rendered if between mMinimumScale and mMaximumScale
 
2025
bool QgsVectorLayer::scaleDependentRender()
 
2026
{
 
2027
  return mScaleDependentRender;
 
2028
}
 
2029
 
 
2030
 
 
2031
// Return the minimum scale at which the layer is rendered
 
2032
int QgsVectorLayer::minimumScale()
 
2033
{
 
2034
  return mMinimumScale;
 
2035
}
 
2036
// Return the maximum scale at which the layer is rendered
 
2037
int QgsVectorLayer::maximumScale()
 
2038
{
 
2039
  return mMaximumScale;
 
2040
}
 
2041
 
 
2042
 
 
2043
 
 
2044
bool QgsVectorLayer::readXML_( QDomNode & layer_node )
 
2045
{
 
2046
#ifdef QGISDEBUG
 
2047
  std::cerr << "Datasource in QgsVectorLayer::readXML_: " << dataSource.toLocal8Bit().data() << std::endl;
 
2048
#endif
 
2049
  // process the attribute actions
 
2050
  mActions.readXML(layer_node);
 
2051
 
 
2052
  //process provider key
 
2053
  QDomNode pkeyNode = layer_node.namedItem("provider");
 
2054
 
 
2055
  if (pkeyNode.isNull())
 
2056
  {
 
2057
    providerKey = "";
 
2058
  }
 
2059
  else
 
2060
  {
 
2061
    QDomElement pkeyElt = pkeyNode.toElement();
 
2062
    providerKey = pkeyElt.text();
 
2063
  }
 
2064
 
 
2065
  // determine type of vector layer
 
2066
  if ( ! providerKey.isNull() )
 
2067
  {
 
2068
    // if the provider string isn't empty, then we successfully
 
2069
    // got the stored provider
 
2070
  }
 
2071
  else if ((dataSource.find("host=") > -1) &&
 
2072
      (dataSource.find("dbname=") > -1))
 
2073
  {
 
2074
    providerKey = "postgres";
 
2075
  }
 
2076
  else
 
2077
  {
 
2078
    providerKey = "ogr";
 
2079
  }
 
2080
 
 
2081
#ifdef QGISDEBUG
 
2082
  const char * dataproviderStr = providerKey.ascii(); // debugger probe
 
2083
#endif
 
2084
 
 
2085
  if ( ! setDataProvider( providerKey ) )
 
2086
  {
 
2087
    return false;
 
2088
  }
 
2089
 
 
2090
  //read provider encoding
 
2091
  QDomNode encodingNode = layer_node.namedItem("encoding");
 
2092
  if( ! encodingNode.isNull() && dataProvider )
 
2093
  {
 
2094
    dataProvider->setEncoding(encodingNode.toElement().text());
 
2095
  }
 
2096
 
 
2097
  // get and set the display field if it exists.
 
2098
  QDomNode displayFieldNode = layer_node.namedItem("displayfield");
 
2099
  if (!displayFieldNode.isNull())
 
2100
  {
 
2101
    QDomElement e = displayFieldNode.toElement();
 
2102
    setDisplayField(e.text());
 
2103
  }
 
2104
 
 
2105
 
 
2106
 
 
2107
  // create and bind a renderer to this layer
 
2108
 
 
2109
  QDomNode singlenode = layer_node.namedItem("singlesymbol");
 
2110
  QDomNode graduatednode = layer_node.namedItem("graduatedsymbol");
 
2111
  QDomNode continuousnode = layer_node.namedItem("continuoussymbol");
 
2112
  QDomNode singlemarkernode = layer_node.namedItem("singlemarker");
 
2113
  QDomNode graduatedmarkernode = layer_node.namedItem("graduatedmarker");
 
2114
  QDomNode uniquevaluenode = layer_node.namedItem("uniquevalue");
 
2115
  QDomNode labelnode = layer_node.namedItem("label");
 
2116
  QDomNode uniquemarkernode = layer_node.namedItem("uniquevaluemarker");
 
2117
 
 
2118
  //std::auto_ptr<QgsRenderer> renderer; actually the renderer SHOULD NOT be
 
2119
  //deleted when this function finishes, otherwise the application will
 
2120
  //crash
 
2121
  // XXX this seems to be a dangerous implementation; should re-visit design
 
2122
  QgsRenderer * renderer;
 
2123
 
 
2124
  // XXX Kludge!
 
2125
 
 
2126
 
 
2127
  // if we don't have a coordinate transform, get one
 
2128
 
 
2129
  //
 
2130
  // Im commenting this out - if the layer was serialied in a 
 
2131
  //  >=0.7 project it should have been validated and have all
 
2132
  // coord xform info
 
2133
  //
 
2134
 
 
2135
  //if ( ! coordinateTransform() )
 
2136
  //{
 
2137
  //    setCoordinateSystem();
 
2138
  //}
 
2139
 
 
2140
  if (!singlenode.isNull())
 
2141
  {
 
2142
    renderer = new QgsSingleSymbolRenderer(vectorType());
 
2143
    renderer->readXML(singlenode, *this);
 
2144
  }
 
2145
  else if (!graduatednode.isNull())
 
2146
  {
 
2147
    renderer = new QgsGraduatedSymbolRenderer(vectorType());
 
2148
    renderer->readXML(graduatednode, *this);
 
2149
  }
 
2150
  else if (!continuousnode.isNull())
 
2151
  {
 
2152
    renderer = new QgsContinuousColorRenderer(vectorType());
 
2153
    renderer->readXML(continuousnode, *this);
 
2154
  }
 
2155
  else if (!uniquevaluenode.isNull())
 
2156
  {
 
2157
    renderer = new QgsUniqueValueRenderer(vectorType());
 
2158
    renderer->readXML(uniquevaluenode, *this);
 
2159
  }
 
2160
 
 
2161
  // Test if labeling is on or off
 
2162
  QDomElement element = labelnode.toElement();
 
2163
  int labelOn = element.text().toInt();
 
2164
  if (labelOn < 1)
 
2165
  {
 
2166
    setLabelOn(false);
 
2167
  }
 
2168
  else
 
2169
  {
 
2170
    setLabelOn(true);
 
2171
  }
 
2172
 
 
2173
#ifdef QGISDEBUG
 
2174
  std::cout << "Testing if qgsvectorlayer can call label readXML routine" << std::endl;
 
2175
#endif
 
2176
 
 
2177
  QDomNode labelattributesnode = layer_node.namedItem("labelattributes");
 
2178
 
 
2179
  if(!labelattributesnode.isNull())
 
2180
  {
 
2181
#ifdef QGISDEBUG
 
2182
    std::cout << "qgsvectorlayer calling label readXML routine" << std::endl;
 
2183
#endif
 
2184
    mLabel->readXML(labelattributesnode);
 
2185
  }
 
2186
 
 
2187
  return valid;               // should be true if read successfully
 
2188
 
 
2189
} // void QgsVectorLayer::readXML_
 
2190
 
 
2191
 
 
2192
 
 
2193
bool QgsVectorLayer::setDataProvider( QString const & provider )
 
2194
{
 
2195
  // XXX should I check for and possibly delete any pre-existing providers?
 
2196
  // XXX How often will that scenario occur?
 
2197
 
 
2198
  providerKey = provider;     // XXX is this necessary?  Usually already set
 
2199
  // XXX when execution gets here.
 
2200
 
 
2201
  //XXX - This was a dynamic cast but that kills the Windows
 
2202
  //      version big-time with an abnormal termination error
 
2203
  dataProvider = 
 
2204
    (QgsVectorDataProvider*)(QgsProviderRegistry::instance()->getProvider(provider,dataSource));
 
2205
 
 
2206
  if (dataProvider)
 
2207
  {
 
2208
    QgsDebug( "Instantiated the data provider plugin" );
 
2209
 
 
2210
    if (dataProvider->isValid())
 
2211
    {
 
2212
      valid = true;
 
2213
 
 
2214
      // TODO: Check if the provider has the capability to send fullExtentCalculated
 
2215
      connect(dataProvider, SIGNAL( fullExtentCalculated() ), 
 
2216
          this,           SLOT( updateExtents() ) 
 
2217
          );
 
2218
 
 
2219
      // get the extent
 
2220
      QgsRect *mbr = dataProvider->extent();
 
2221
 
 
2222
      // show the extent
 
2223
      QString s = mbr->stringRep();
 
2224
      QgsDebugMsg("Extent of layer: " +  s);
 
2225
      // store the extent
 
2226
      layerExtent.setXmax(mbr->xMax());
 
2227
      layerExtent.setXmin(mbr->xMin());
 
2228
      layerExtent.setYmax(mbr->yMax());
 
2229
      layerExtent.setYmin(mbr->yMin());
 
2230
 
 
2231
      // get and store the feature type
 
2232
      geometryType = dataProvider->geometryType();
 
2233
 
 
2234
      // look at the fields in the layer and set the primary
 
2235
      // display field using some real fuzzy logic
 
2236
      setDisplayField();
 
2237
 
 
2238
      if (providerKey == "postgres")
 
2239
      {
 
2240
        QgsDebugMsg("Beautifying layer name " + name());
 
2241
        // adjust the display name for postgres layers
 
2242
        QRegExp reg("\".+\"\\.\"(.+)\"");
 
2243
        reg.indexIn(name());
 
2244
        QStringList stuff = reg.capturedTexts();
 
2245
        QString lName = stuff[1];
 
2246
        if (lName.length() == 0) // fallback
 
2247
          lName = name();
 
2248
        setLayerName(lName);
 
2249
        QgsDebugMsg("Beautifying layer name " + name());
 
2250
      }
 
2251
 
 
2252
      // label
 
2253
      mLabel = new QgsLabel ( dataProvider->fields() );
 
2254
      mLabelOn = false;
 
2255
    }
 
2256
    else
 
2257
    {
 
2258
#ifdef QGISDEBUG
 
2259
      qDebug( "%s:%d invalid provider plugin %s", 
 
2260
          __FILE__, __LINE__, dataSource.ascii() );
 
2261
      return false;
 
2262
#endif
 
2263
    }
 
2264
  }
 
2265
  else
 
2266
  {
 
2267
    QgsDebug( " unable to get data provider" );
 
2268
 
 
2269
    return false;
 
2270
  }
 
2271
 
 
2272
  return true;
 
2273
 
 
2274
} // QgsVectorLayer:: setDataProvider
 
2275
 
 
2276
 
 
2277
 
 
2278
 
 
2279
/* virtual */ bool QgsVectorLayer::writeXML_( QDomNode & layer_node,
 
2280
    QDomDocument & document )
 
2281
{
 
2282
  // first get the layer element so that we can append the type attribute
 
2283
 
 
2284
  QDomElement mapLayerNode = layer_node.toElement();
 
2285
 
 
2286
  if ( mapLayerNode.isNull() || ("maplayer" != mapLayerNode.nodeName()) )
 
2287
  {
 
2288
    qDebug( "QgsVectorLayer::writeXML() can't find <maplayer>" );
 
2289
    return false;
 
2290
  }
 
2291
 
 
2292
  mapLayerNode.setAttribute( "type", "vector" );
 
2293
 
 
2294
  // set the geometry type
 
2295
  mapLayerNode.setAttribute( "geometry", QGis::qgisVectorGeometryType[vectorType()]);
 
2296
 
 
2297
  // add provider node
 
2298
 
 
2299
  QDomElement provider  = document.createElement( "provider" );
 
2300
  QDomText providerText = document.createTextNode( providerType() );
 
2301
  provider.appendChild( providerText );
 
2302
  layer_node.appendChild( provider );
 
2303
 
 
2304
  //provider encoding
 
2305
  QDomElement encoding = document.createElement("encoding");
 
2306
  QDomText encodingText = document.createTextNode(dataProvider->encoding());
 
2307
  encoding.appendChild( encodingText );
 
2308
  layer_node.appendChild( encoding );
 
2309
 
 
2310
  //classification field(s)
 
2311
  std::list<int> attributes=m_renderer->classificationAttributes();
 
2312
  const std::vector<QgsField> providerFields = dataProvider->fields();
 
2313
  for(std::list<int>::const_iterator it = attributes.begin(); it != attributes.end(); ++it)
 
2314
    {
 
2315
      QDomElement classificationElement = document.createElement("classificationattribute");
 
2316
      QDomText classificationText = document.createTextNode(providerFields[*it].name());
 
2317
      classificationElement.appendChild(classificationText);
 
2318
      layer_node.appendChild(classificationElement);
 
2319
    }
 
2320
 
 
2321
  // add the display field
 
2322
 
 
2323
  QDomElement dField  = document.createElement( "displayfield" );
 
2324
  QDomText dFieldText = document.createTextNode( displayField() );
 
2325
  dField.appendChild( dFieldText );
 
2326
  layer_node.appendChild( dField );
 
2327
 
 
2328
  // add label node
 
2329
 
 
2330
  QDomElement label  = document.createElement( "label" );
 
2331
  QDomText labelText = document.createTextNode( "" );
 
2332
 
 
2333
  if ( labelOn() )
 
2334
  {
 
2335
    labelText.setData( "1" );
 
2336
  }
 
2337
  else
 
2338
  {
 
2339
    labelText.setData( "0" );
 
2340
  }
 
2341
  label.appendChild( labelText );
 
2342
 
 
2343
  layer_node.appendChild( label );
 
2344
 
 
2345
  // add attribute actions
 
2346
 
 
2347
  mActions.writeXML(layer_node, document);
 
2348
 
 
2349
  // renderer specific settings
 
2350
 
 
2351
  const QgsRenderer * myRenderer;
 
2352
  if( myRenderer = renderer())
 
2353
  {
 
2354
    myRenderer->writeXML(layer_node, document);
 
2355
  }
 
2356
  else
 
2357
  {
 
2358
    std::cerr << __FILE__ << ":" << __LINE__
 
2359
      << " no renderer\n";
 
2360
 
 
2361
    // XXX return false?
 
2362
  }
 
2363
 
 
2364
  // Now we get to do all that all over again for QgsLabel
 
2365
 
 
2366
  // XXX Since this is largely a cut-n-paste from the previous, this
 
2367
  // XXX therefore becomes a candidate to be generalized into a separate
 
2368
  // XXX function.  I think.
 
2369
 
 
2370
  QgsLabel * myLabel;
 
2371
 
 
2372
  if ( myLabel = this->label() )
 
2373
  {
 
2374
    std::stringstream labelXML;
 
2375
 
 
2376
    myLabel->writeXML(labelXML);
 
2377
 
 
2378
    QDomDocument labelDOM;
 
2379
 
 
2380
    std::string rawXML;
 
2381
    std::string temp_str;
 
2382
    QString     errorMsg;
 
2383
    int         errorLine;
 
2384
    int         errorColumn;
 
2385
 
 
2386
    // start with bogus XML header
 
2387
    rawXML  = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
 
2388
 
 
2389
    temp_str = labelXML.str();
 
2390
 
 
2391
    rawXML   += temp_str;
 
2392
 
 
2393
#ifdef QGISDEBUG
 
2394
    std::cout << rawXML << std::endl << std::flush;
 
2395
#endif
 
2396
    const char * s = rawXML.c_str(); // debugger probe
 
2397
    // Use the const char * form of the xml to make non-stl qt happy
 
2398
    if ( ! labelDOM.setContent( QString::fromUtf8(s), &errorMsg, &errorLine, &errorColumn ) )
 
2399
    {
 
2400
      qDebug( ("XML import error at line %d column %d " + errorMsg).toLocal8Bit().data(), errorLine, errorColumn );
 
2401
 
 
2402
      return false;
 
2403
    }
 
2404
 
 
2405
    // lastChild() because the first two nodes are the <xml> and
 
2406
    // <!DOCTYPE> nodes; the label node follows that, and is (hopefully)
 
2407
    // the last node.
 
2408
    QDomNode labelDOMNode = document.importNode( labelDOM.lastChild(), true );
 
2409
 
 
2410
    if ( ! labelDOMNode.isNull() )
 
2411
    {
 
2412
      layer_node.appendChild( labelDOMNode );
 
2413
    }
 
2414
    else
 
2415
    {
 
2416
      qDebug( "not able to import label DOM node" );
 
2417
 
 
2418
      // XXX return false?
 
2419
    }
 
2420
 
 
2421
  }
 
2422
 
 
2423
  return true;
 
2424
} // bool QgsVectorLayer::writeXML_
 
2425
 
 
2426
 
 
2427
/** we wouldn't have to do this if slots were inherited */
 
2428
void QgsVectorLayer::inOverview( bool b )
 
2429
{
 
2430
  QgsMapLayer::inOverview( b );
 
2431
}
 
2432
 
 
2433
int QgsVectorLayer::findFreeId()
 
2434
{
 
2435
  int freeid=-INT_MAX;
 
2436
  int fid;
 
2437
  if(dataProvider)
 
2438
  {
 
2439
    dataProvider->reset();
 
2440
    QgsFeature *fet;
 
2441
 
 
2442
    //TODO: Is there an easier way of doing this other than iteration?
 
2443
    //TODO: Also, what about race conditions between this code and a competing mapping client?
 
2444
    //TODO: Maybe push this to the data provider?
 
2445
    while ((fet = dataProvider->getNextFeature(true)))
 
2446
    {
 
2447
      fid=fet->featureId();
 
2448
      if(fid>freeid)
 
2449
      {
 
2450
        freeid=fid;
 
2451
      }
 
2452
      delete fet;
 
2453
    }
 
2454
#ifdef QGISDEBUG
 
2455
    qWarning(("freeid is: "+QString::number(freeid+1)).toLocal8Bit().data());
 
2456
#endif
 
2457
    return freeid+1;
 
2458
  }
 
2459
  else
 
2460
  {
 
2461
#ifdef QGISDEBUG
 
2462
    qWarning("Error, dataProvider is 0 in QgsVectorLayer::findFreeId");
 
2463
#endif
 
2464
    return -1;
 
2465
  }
 
2466
}
 
2467
 
 
2468
bool QgsVectorLayer::commitChanges()
 
2469
{
 
2470
  /*
 
2471
     Unfortunately the commits occur in four distinct stages,
 
2472
     (add features, change attributes, change geometries, delete features)
 
2473
     so if a stage fails, it's difficult to roll back cleanly.
 
2474
     Therefore the error messages become a bit complicated to generate.
 
2475
   */
 
2476
 
 
2477
  if(!dataProvider)
 
2478
  {
 
2479
    return FALSE;
 
2480
  }
 
2481
 
 
2482
  // Attempt the commit of new features
 
2483
  bool addedFeaturesOk = FALSE;
 
2484
  if (mAddedFeatures.size() > 0)
 
2485
  {
 
2486
    std::list<QgsFeature*> addedlist;
 
2487
    for (std::vector<QgsFeature*>::iterator it = mAddedFeatures.begin(); it != mAddedFeatures.end(); ++it)
 
2488
    {
 
2489
      addedlist.push_back(*it);
 
2490
    }
 
2491
 
 
2492
    if (!dataProvider->addFeatures(addedlist))
 
2493
    {
 
2494
      QStringList errorStrings;
 
2495
      errorStrings += tr("Could not commit the added features.");
 
2496
      errorStrings += tr("No other types of changes will be committed at this time.");
 
2497
 
 
2498
      QMessageBox::warning(0, tr("Error"), errorStrings.join(" "));
 
2499
      return FALSE;
 
2500
    }
 
2501
    else
 
2502
    {
 
2503
      // Added features committed OK, remove the in-memory changes
 
2504
 
 
2505
      // Delete the features themselves before deleting the references to them.
 
2506
      for (std::vector<QgsFeature*>::iterator it = mAddedFeatures.begin(); it != mAddedFeatures.end(); ++it)
 
2507
      {
 
2508
        delete *it;
 
2509
      }
 
2510
      mAddedFeatures.clear();
 
2511
      addedFeaturesOk = TRUE;
 
2512
    }
 
2513
  }
 
2514
 
 
2515
  // Attempt the commit of changed attributes
 
2516
  bool changedAttributesOk = FALSE;
 
2517
  if (mChangedAttributes.size() > 0)
 
2518
  {
 
2519
    if (!dataProvider->changeAttributeValues(mChangedAttributes))
 
2520
    {
 
2521
      QStringList errorStrings;
 
2522
      errorStrings += tr("Could not commit the changed attributes.");
 
2523
      if (addedFeaturesOk)
 
2524
      {
 
2525
        errorStrings += tr("However, the added features were committed OK.");
 
2526
      }
 
2527
      errorStrings += tr("No other types of changes will be committed at this time.");
 
2528
 
 
2529
      QMessageBox::warning(0, tr("Error"), errorStrings.join(" "));
 
2530
      return FALSE;
 
2531
    }
 
2532
    else
 
2533
    {
 
2534
      // Changed attributes committed OK, remove the in-memory changes
 
2535
      mChangedAttributes.clear();
 
2536
      changedAttributesOk = TRUE;
 
2537
    }
 
2538
  }
 
2539
 
 
2540
  // Attempt the commit of changed geometries
 
2541
  bool changedGeometriesOk = FALSE;
 
2542
  if (mChangedGeometries.size() > 0)
 
2543
  {
 
2544
    if (!dataProvider->changeGeometryValues(mChangedGeometries))
 
2545
    {
 
2546
      QStringList errorStrings;
 
2547
      errorStrings += tr("Could not commit the changed geometries.");
 
2548
      if (addedFeaturesOk)
 
2549
      {
 
2550
        errorStrings += tr("However, the added features were committed OK.");
 
2551
      }
 
2552
      if (changedAttributesOk)
 
2553
      {
 
2554
        errorStrings += tr("However, the changed attributes were committed OK.");
 
2555
      }
 
2556
      errorStrings += tr("No other types of changes will be committed at this time.");
 
2557
 
 
2558
      QMessageBox::warning(0, tr("Error"), errorStrings.join(" "));
 
2559
      return FALSE;
 
2560
    }
 
2561
    else
 
2562
    {
 
2563
      // Changed geometries committed OK, remove the in-memory changes
 
2564
      mChangedGeometries.clear();
 
2565
      changedGeometriesOk = TRUE;
 
2566
    }
 
2567
  }
 
2568
 
 
2569
  // Attempt the commit of deleted features
 
2570
  bool deletedFeaturesOk = FALSE;
 
2571
  if (mDeletedFeatureIds.size() > 0)
 
2572
  {
 
2573
    std::list<int> deletelist;
 
2574
    for (std::set<int>::iterator it = mDeletedFeatureIds.begin(); it != mDeletedFeatureIds.end(); ++it)
 
2575
    {
 
2576
      deletelist.push_back(*it);
 
2577
      mSelectedFeatureIds.erase(*it);//just in case the feature is still selected
 
2578
    }
 
2579
 
 
2580
    if (!dataProvider->deleteFeatures(deletelist))
 
2581
    {
 
2582
      QStringList errorStrings;
 
2583
      errorStrings += tr("Could not commit the deleted features.");
 
2584
      if (addedFeaturesOk)
 
2585
      {
 
2586
        errorStrings += tr("However, the added features were committed OK.");
 
2587
      }
 
2588
      if (changedAttributesOk)
 
2589
      {
 
2590
        errorStrings += tr("However, the changed attributes were committed OK.");
 
2591
      }
 
2592
      if (changedGeometriesOk)
 
2593
      {
 
2594
        errorStrings += tr("However, the changed geometries were committed OK.");
 
2595
      }
 
2596
      errorStrings += tr("No other types of changes will be committed at this time.");
 
2597
 
 
2598
      QMessageBox::warning(0, tr("Error"), errorStrings.join(" "));
 
2599
      return FALSE;
 
2600
    }
 
2601
    else
 
2602
    {
 
2603
      // Deleted features committed OK, remove the in-memory changes
 
2604
      mDeletedFeatureIds.clear();
 
2605
      deletedFeaturesOk = TRUE;
 
2606
    }
 
2607
  }
 
2608
 
 
2609
  return TRUE;
 
2610
}
 
2611
 
 
2612
bool QgsVectorLayer::rollBack()
 
2613
{
 
2614
  //Roll back changed features
 
2615
  mChangedGeometries.clear();   // TODO: Does this leak memory?
 
2616
  mChangedAttributes.clear();
 
2617
 
 
2618
  // Roll back added features
 
2619
  // Delete the features themselves before deleting the references to them.
 
2620
  for(std::vector<QgsFeature*>::iterator it=mAddedFeatures.begin();it!=mAddedFeatures.end();++it)
 
2621
  {
 
2622
    delete *it;
 
2623
  }
 
2624
  mAddedFeatures.clear();
 
2625
 
 
2626
  // Roll back deleted features
 
2627
  mDeletedFeatureIds.clear();
 
2628
 
 
2629
  updateExtents();
 
2630
  return true;
 
2631
}
 
2632
 
 
2633
 
 
2634
int QgsVectorLayer::selectedFeatureCount()
 
2635
{
 
2636
  return mSelectedFeatureIds.size();
 
2637
}
 
2638
 
 
2639
 
 
2640
std::vector<QgsFeature>* QgsVectorLayer::selectedFeatures()
 
2641
{
 
2642
  if (!dataProvider)
 
2643
  {
 
2644
    return 0;
 
2645
  }
 
2646
  
 
2647
  std::vector<QgsFeature>* features = new std::vector<QgsFeature>;
 
2648
 
 
2649
  if (mSelectedFeatureIds.size() == 0)
 
2650
  {
 
2651
    // short cut
 
2652
    return features;
 
2653
  }
 
2654
 
 
2655
  // we don't need to cache features ... it just adds unnecessary time
 
2656
  // as we don't need to pull *everything* from disk
 
2657
 
 
2658
  // Go through each selected feature ID and determine
 
2659
  // its current geometry and attributes
 
2660
 
 
2661
  for (std::set<int>::iterator it  = mSelectedFeatureIds.begin(); it != mSelectedFeatureIds.end(); ++it)
 
2662
  {
 
2663
    QgsFeature* initialFeature;
 
2664
 
 
2665
    // Pull the original version of the feature from disk or memory
 
2666
    // as appropriate
 
2667
 
 
2668
    // Check this selected item against the uncommitted added features
 
2669
    bool selectionIsAddedFeature = FALSE;
 
2670
 
 
2671
    for (std::vector<QgsFeature*>::iterator iter  = mAddedFeatures.begin();
 
2672
        iter != mAddedFeatures.end();
 
2673
        ++iter)
 
2674
    {
 
2675
      if ( (*it) == (*iter)->featureId() )
 
2676
      {
 
2677
#ifdef QGISDEBUG
 
2678
        std::cout << "QgsVectorLayer::selectedFeatures: found an added geometry: " 
 
2679
          << std::endl;
 
2680
#endif
 
2681
        initialFeature = new QgsFeature(**iter);
 
2682
        selectionIsAddedFeature = TRUE;
 
2683
      }
 
2684
    }
 
2685
 
 
2686
    if (!selectionIsAddedFeature)
 
2687
    {
 
2688
      // pull committed version from disk
 
2689
      initialFeature = new QgsFeature(*it);
 
2690
 
 
2691
      int row = 0;  //TODO: Get rid of this, but getFeatureAttributes()
 
2692
                    //      needs it for some reason
 
2693
      dataProvider->getFeatureAttributes(*it, row, initialFeature);
 
2694
 
 
2695
      if ( mChangedGeometries.find(*it) == mChangedGeometries.end() )
 
2696
      {
 
2697
        // also pull committed geometry from disk as we will
 
2698
        // not need to overwrite it later
 
2699
 
 
2700
        if (dataProvider->capabilities() & QgsVectorDataProvider::SelectGeometryAtId)
 
2701
        {
 
2702
          dataProvider->getFeatureGeometry(*it, initialFeature);
 
2703
        }
 
2704
        else
 
2705
        {
 
2706
          QMessageBox::information(0, tr("Cannot retrieve features"),
 
2707
              tr("The provider for the current layer cannot retrieve geometry for the selected features.  This version of the provider does not have this capability."));
 
2708
        }
 
2709
      }
 
2710
 
 
2711
    }
 
2712
 
 
2713
    // Transform the feature to the "current" in-memory version
 
2714
    QgsFeature finalFeature =
 
2715
      QgsFeature(*initialFeature,
 
2716
                 mChangedAttributes,
 
2717
                 mChangedGeometries);
 
2718
 
 
2719
    delete initialFeature;
 
2720
 
 
2721
    features->push_back(finalFeature);
 
2722
 
 
2723
  } // for each selected
 
2724
 
 
2725
  return features;
 
2726
}
 
2727
 
 
2728
bool QgsVectorLayer::addFeatures(std::vector<QgsFeature*>* features, bool makeSelected)
 
2729
{
 
2730
  if (dataProvider)
 
2731
  {  
 
2732
    if(!(dataProvider->capabilities() & QgsVectorDataProvider::AddFeatures))
 
2733
    {
 
2734
      QMessageBox::information(0, tr("Layer cannot be added to"), 
 
2735
          tr("The data provider for this layer does not support the addition of features."));
 
2736
      return false;
 
2737
    }
 
2738
 
 
2739
    if(!isEditable())
 
2740
    {
 
2741
      QMessageBox::information(0, tr("Layer not editable"), 
 
2742
          tr("The current layer is not editable. Choose 'Allow editing' in the legend item right click menu."));
 
2743
      return false;
 
2744
    }
 
2745
 
 
2746
 
 
2747
    if (makeSelected)
 
2748
    {
 
2749
      mSelectedFeatureIds.clear();
 
2750
    }
 
2751
 
 
2752
    for (std::vector<QgsFeature*>::iterator iter  = features->begin();
 
2753
        iter != features->end();
 
2754
        ++iter)
 
2755
    {
 
2756
      // TODO: Tidy these next two lines up
 
2757
 
 
2758
      //      QgsFeature f = (*iter);
 
2759
      //      addFeature(&f, FALSE);
 
2760
 
 
2761
      addFeature(*iter);
 
2762
 
 
2763
      if (makeSelected)
 
2764
      {
 
2765
        mSelectedFeatureIds.insert((*iter)->featureId());
 
2766
      }
 
2767
    }
 
2768
 
 
2769
    updateExtents();
 
2770
  }  
 
2771
  return true;
 
2772
}
 
2773
 
 
2774
QString QgsVectorLayer::layerTypeIconPath()
 
2775
{
 
2776
  QString myThemePath = QgsApplication::themePath();
 
2777
  switch(vectorType())
 
2778
    {
 
2779
    case Point:
 
2780
      return (myThemePath+"/mIconPointLayer.png");
 
2781
      break;
 
2782
    case Line:
 
2783
      return (myThemePath+"/mIconLineLayer.png");
 
2784
      break;
 
2785
    case Polygon:
 
2786
      return (myThemePath+"/mIconPolygonLayer.png");
 
2787
    default:
 
2788
      return (myThemePath+"/mIconLayer.png");
 
2789
    }
 
2790
}
 
2791
 
 
2792
void QgsVectorLayer::refreshLegend()
 
2793
{
 
2794
  if(mLegend && m_renderer)
 
2795
    {
 
2796
      std::list< std::pair<QString, QPixmap> > itemList;
 
2797
      m_renderer->refreshLegend(&itemList);
 
2798
      if(m_renderer->needsAttributes()) //create an item for each classification field (only one for most renderers)
 
2799
        {
 
2800
          std::list<int> classfieldlist = m_renderer->classificationAttributes();
 
2801
          for(std::list<int>::iterator it = classfieldlist.begin(); it!=classfieldlist.end(); ++it)
 
2802
            {
 
2803
              const QgsField theField = (dataProvider->fields())[*it];
 
2804
              QString classfieldname = theField.name();
 
2805
              itemList.push_front(std::make_pair(classfieldname, QPixmap()));
 
2806
            }
 
2807
        }
 
2808
      mLegend->changeSymbologySettings(getLayerID(), &itemList);
 
2809
    }
 
2810
}
 
2811
 
 
2812
bool QgsVectorLayer::copySymbologySettings(const QgsMapLayer& other)
 
2813
{
 
2814
  const QgsVectorLayer* vl = dynamic_cast<const QgsVectorLayer*>(&other);
 
2815
 
 
2816
  if(this == vl)//exit if both vectorlayer are the same
 
2817
  {
 
2818
    return false;
 
2819
  }
 
2820
 
 
2821
  if(!vl)
 
2822
  {
 
2823
    return false;
 
2824
  }
 
2825
  delete m_renderer;
 
2826
 
 
2827
  QgsRenderer* r = vl->m_renderer;
 
2828
  if(r)
 
2829
  {
 
2830
    m_renderer = r->clone();
 
2831
    return true;
 
2832
  }
 
2833
  else
 
2834
  {
 
2835
    return false;
 
2836
  }
 
2837
}
 
2838
 
 
2839
bool QgsVectorLayer::isSymbologyCompatible(const QgsMapLayer& other) const
 
2840
{
 
2841
  //vector layers are symbology compatible if they have the same type, the same sequence of numerical/ non numerical fields and the same field names
 
2842
 
 
2843
 
 
2844
  const QgsVectorLayer* otherVectorLayer = dynamic_cast<const QgsVectorLayer*>(&other);
 
2845
  if(otherVectorLayer)
 
2846
  {
 
2847
 
 
2848
    if(otherVectorLayer->vectorType() != vectorType())
 
2849
      {
 
2850
        return false;
 
2851
      }
 
2852
 
 
2853
    const std::vector<QgsField> fieldsThis = dataProvider->fields();
 
2854
    const std::vector<QgsField> fieldsOther = otherVectorLayer ->dataProvider->fields();
 
2855
 
 
2856
    if(fieldsThis.size() != fieldsOther.size())
 
2857
    {
 
2858
      return false;
 
2859
    }
 
2860
 
 
2861
    //fill two sets with the numerical types for both layers
 
2862
    const std::list<QString> numAttThis = dataProvider->numericalTypes();
 
2863
    std::set<QString> numericalThis; //the set of numerical types for this vector layer
 
2864
    for(std::list<QString>::const_iterator it = numAttThis.begin(); it != numAttThis.end(); ++it)
 
2865
    {
 
2866
      numericalThis.insert(*it);
 
2867
    }
 
2868
 
 
2869
    const std::list<QString> numAttOther = otherVectorLayer ->dataProvider->numericalTypes();
 
2870
    std::set<QString> numericalOther; //the set of numerical types for the other vector layer
 
2871
    for(std::list<QString>::const_iterator it = numAttOther.begin(); it != numAttOther.end(); ++it)
 
2872
    {
 
2873
      numericalOther.insert(*it);
 
2874
    }
 
2875
 
 
2876
    std::set<QString>::const_iterator thisiter;
 
2877
    std::set<QString>::const_iterator otheriter;
 
2878
    int fieldsThisSize = fieldsThis.size();
 
2879
 
 
2880
    for(register int i = 0; i < fieldsThisSize; ++i)
 
2881
    {
 
2882
      if(fieldsThis[i].name() != fieldsOther[i].name())//field names need to be the same
 
2883
      {
 
2884
        return false;
 
2885
      }
 
2886
      thisiter = numericalThis.find(fieldsThis[i].name());
 
2887
      otheriter = numericalOther.find(fieldsOther[i].name());
 
2888
      if(thisiter == numericalThis.end())
 
2889
      {
 
2890
        if(otheriter != numericalOther.end())
 
2891
        {
 
2892
          return false;
 
2893
        }
 
2894
      }
 
2895
      else
 
2896
      {
 
2897
        if(otheriter == numericalOther.end())
 
2898
        {
 
2899
          return false;
 
2900
        }
 
2901
      }
 
2902
    }
 
2903
    return true; //layers are symbology compatible if the code reaches this point
 
2904
  }
 
2905
  return false;
 
2906
}
 
2907
 
 
2908
bool QgsVectorLayer::snapPoint(QgsPoint& point, double tolerance)
 
2909
{
 
2910
  if(tolerance<=0||!dataProvider)
 
2911
  {
 
2912
    return false;
 
2913
  }
 
2914
  double mindist=tolerance*tolerance;//current minimum distance
 
2915
  double mindistx=point.x();
 
2916
  double mindisty=point.y();
 
2917
  QgsFeature* fet;
 
2918
  QgsPoint vertexFeature;//the closest vertex of a feature
 
2919
  QgsGeometryVertexIndex vindex;
 
2920
  double minsquaredist;
 
2921
  int rb1, rb2; //rubberband indexes (not used in this method)
 
2922
 
 
2923
  QgsRect selectrect(point.x()-tolerance,point.y()-tolerance,point.x()+tolerance,point.y()+tolerance);
 
2924
  selectrect = inverseProjectRect(selectrect);
 
2925
  dataProvider->reset();
 
2926
  dataProvider->select(&selectrect);
 
2927
 
 
2928
  if(projectionsEnabled() && coordinateTransform())
 
2929
    {
 
2930
      //inverse tramsform point to layer SRS
 
2931
      try
 
2932
        {
 
2933
          point = coordinateTransform()->transform(point, QgsCoordinateTransform::INVERSE);
 
2934
        }
 
2935
      catch(QgsCsException &cse)
 
2936
        {
 
2937
          return false;
 
2938
        }
 
2939
    }
 
2940
 
 
2941
  //go to through the features reported by the spatial filter of the provider
 
2942
  while ((fet = dataProvider->getNextFeature(false)))
 
2943
  {
 
2944
    if(mChangedGeometries.find(fet->featureId()) != mChangedGeometries.end())//if geometry has been changed, use the new geometry
 
2945
    {
 
2946
      vertexFeature = mChangedGeometries[fet->featureId()].closestVertex(point, vindex, rb1, rb2, minsquaredist);
 
2947
    }
 
2948
    else
 
2949
    {
 
2950
      vertexFeature=fet->geometry()->closestVertex(point, vindex, rb1, rb2, minsquaredist);
 
2951
    }
 
2952
    if(minsquaredist<mindist)
 
2953
    {
 
2954
      mindistx=vertexFeature.x();
 
2955
      mindisty=vertexFeature.y();
 
2956
      mindist=minsquaredist;
 
2957
    }
 
2958
  }
 
2959
 
 
2960
  //also go through the not commited features
 
2961
  for(std::vector<QgsFeature*>::iterator iter=mAddedFeatures.begin();iter!=mAddedFeatures.end();++iter)
 
2962
  {
 
2963
    if(mChangedGeometries.find((*iter)->featureId()) != mChangedGeometries.end())//use the changed geometry
 
2964
    {
 
2965
      vertexFeature = mChangedGeometries[(*iter)->featureId()].closestVertex(point, vindex, rb1, rb2, minsquaredist);
 
2966
    }
 
2967
    else
 
2968
    {
 
2969
      vertexFeature=(*iter)->geometry()->closestVertex(point, vindex, rb1, rb2, minsquaredist);
 
2970
    }
 
2971
    if(minsquaredist<mindist)
 
2972
    {
 
2973
      mindistx=vertexFeature.x();
 
2974
      mindisty=vertexFeature.y();
 
2975
      mindist=minsquaredist;
 
2976
    }
 
2977
  }
 
2978
 
 
2979
  //and also go through the changed geometries, because the spatial filter of the provider did not consider feature changes
 
2980
  for(std::map<int, QgsGeometry>::const_iterator iter = mChangedGeometries.begin(); iter != mChangedGeometries.end(); ++iter)
 
2981
  {
 
2982
    vertexFeature = iter->second.closestVertex(point, vindex, rb1, rb2, minsquaredist);
 
2983
    if(minsquaredist<mindist)
 
2984
    {
 
2985
      mindistx=vertexFeature.x();
 
2986
      mindisty=vertexFeature.y();
 
2987
      mindist=minsquaredist;
 
2988
    }
 
2989
  }
 
2990
 
 
2991
  point.setX(mindistx);
 
2992
  point.setY(mindisty);
 
2993
 
 
2994
  if(projectionsEnabled())
 
2995
    {
 
2996
      //transform point to canvas SRC
 
2997
      try
 
2998
        {
 
2999
          point = coordinateTransform()->transform(point);
 
3000
        }
 
3001
      catch(QgsCsException &cse)
 
3002
        {
 
3003
          return false;
 
3004
        }
 
3005
    }
 
3006
 
 
3007
  return true;
 
3008
}
 
3009
 
 
3010
 
 
3011
bool QgsVectorLayer::snapVertexWithContext(QgsPoint& point, QgsGeometryVertexIndex& atVertex, int& beforeVertexIndex, int& afterVertexIndex,\
 
3012
int& snappedFeatureId, QgsGeometry& snappedGeometry, double tolerance)
 
3013
{
 
3014
  bool vertexFound = false; //flag to check if a meaningful result can be returned
 
3015
  QgsGeometryVertexIndex atVertexTemp;
 
3016
  int beforeVertexIndexTemp, afterVertexIndexTemp;
 
3017
 
 
3018
  QgsPoint origPoint = point;
 
3019
 
 
3020
  // Sanity checking
 
3021
  if ( tolerance<=0 || !dataProvider)
 
3022
  {
 
3023
    return false;
 
3024
  }
 
3025
 
 
3026
  QgsFeature* feature;
 
3027
  QgsPoint minDistSegPoint;  // the closest point
 
3028
  double testSqrDist;        // the squared distance between 'point' and 'snappedFeature'
 
3029
 
 
3030
  double minSqrDist  = tolerance*tolerance; //current minimum distance
 
3031
 
 
3032
  QgsRect selectrect(origPoint.x()-tolerance, origPoint.y()-tolerance, origPoint.x()+tolerance, origPoint.y()+tolerance);
 
3033
  dataProvider->reset();
 
3034
  dataProvider->select(&selectrect);
 
3035
 
 
3036
  if(projectionsEnabled() && coordinateTransform())
 
3037
    {
 
3038
      //inverse tramsform points to layer SRS
 
3039
      try
 
3040
        {
 
3041
          origPoint = coordinateTransform()->transform(point, QgsCoordinateTransform::INVERSE);
 
3042
        }
 
3043
      catch(QgsCsException &cse)
 
3044
        {
 
3045
          return false;
 
3046
        }
 
3047
    }
 
3048
 
 
3049
  // Go through the committed features
 
3050
  while ((feature = dataProvider->getNextFeature(false)))
 
3051
  {
 
3052
    if(mChangedGeometries.find(feature->featureId()) != mChangedGeometries.end())
 
3053
    {
 
3054
      // ignore for this loop, let the loop below over mChangedGeometries
 
3055
      // detect the changed geometry instead
 
3056
      continue;
 
3057
 
 
3058
      // // substitute the modified geometry for the committed version
 
3059
      // feature->setGeometry(mChangedGeometries[feature->featureId()]);
 
3060
    }
 
3061
 
 
3062
    minDistSegPoint = feature->geometry()->closestVertex(origPoint, atVertexTemp, beforeVertexIndexTemp, afterVertexIndexTemp, testSqrDist);
 
3063
    if (
 
3064
        (testSqrDist < minSqrDist) ||
 
3065
        (
 
3066
         // this test will "choose" the polygon that the origPoint is in:
 
3067
         (testSqrDist == minSqrDist) && 
 
3068
         (feature->geometry()->contains(&origPoint))
 
3069
        )
 
3070
       )
 
3071
    {
 
3072
      point = minDistSegPoint;
 
3073
      minSqrDist = testSqrDist;
 
3074
 
 
3075
      atVertex          = atVertexTemp;
 
3076
      beforeVertexIndex = beforeVertexIndexTemp;
 
3077
      afterVertexIndex = afterVertexIndexTemp;
 
3078
      snappedFeatureId  = feature->featureId();
 
3079
      snappedGeometry   = *(feature->geometry());
 
3080
      vertexFound = true;
 
3081
    }
 
3082
    delete feature;
 
3083
  }
 
3084
 
 
3085
  // Also go through the new features
 
3086
  for (std::vector<QgsFeature*>::iterator iter  = mAddedFeatures.begin(); iter != mAddedFeatures.end(); ++iter)
 
3087
  {
 
3088
    if(mChangedGeometries.find((*iter)->featureId()) != mChangedGeometries.end())
 
3089
      {
 
3090
        // ignore for this loop, let the loop below over mChangedGeometries
 
3091
        // detect the changed geometry instead
 
3092
        continue;
 
3093
        // //use the modified geometry
 
3094
        // minDistSegPoint = mChangedGeometries[(*iter)->featureId()].closestVertex(origPoint, atVertexTemp, beforeVertexIndexTemp, afterVertexIndexTemp, testSqrDist);
 
3095
      }
 
3096
    else
 
3097
      {
 
3098
        minDistSegPoint = (*iter)->geometry()->closestVertex(origPoint, atVertexTemp, beforeVertexIndexTemp, afterVertexIndexTemp, testSqrDist);
 
3099
      }
 
3100
    if (
 
3101
        (testSqrDist < minSqrDist) ||
 
3102
        (
 
3103
         // this test will "choose" the polygon that the origPoint is in:
 
3104
         (testSqrDist == minSqrDist) && 
 
3105
         ((*iter)->geometry()->contains(&origPoint))
 
3106
        )
 
3107
       )
 
3108
    {
 
3109
      point = minDistSegPoint;
 
3110
      minSqrDist = testSqrDist;
 
3111
 
 
3112
      atVertex      = atVertexTemp;
 
3113
      beforeVertexIndex = beforeVertexIndexTemp;
 
3114
      afterVertexIndex = afterVertexIndexTemp;
 
3115
      snappedFeatureId  =   (*iter)->featureId();
 
3116
      snappedGeometry   = *((*iter)->geometry());
 
3117
      vertexFound = true;
 
3118
    }
 
3119
  }
 
3120
 
 
3121
  //and also go through the changed geometries, because the spatial filter of the provider did not consider feature changes
 
3122
  for(std::map<int, QgsGeometry>::iterator it = mChangedGeometries.begin(); it != mChangedGeometries.end(); ++it)
 
3123
    {
 
3124
      minDistSegPoint = it->second.closestVertex(origPoint, atVertexTemp, beforeVertexIndexTemp, afterVertexIndexTemp, testSqrDist);
 
3125
      if (
 
3126
          (testSqrDist < minSqrDist) ||
 
3127
          (
 
3128
           // this test will "choose" the polygon that the origPoint is in:
 
3129
           (testSqrDist == minSqrDist) && 
 
3130
           (it->second.contains(&origPoint))
 
3131
          )
 
3132
         )
 
3133
        {
 
3134
          point = minDistSegPoint;
 
3135
          minSqrDist = testSqrDist;
 
3136
          atVertex      = atVertexTemp;
 
3137
          beforeVertexIndex = beforeVertexIndexTemp;
 
3138
          afterVertexIndex = afterVertexIndexTemp;
 
3139
          snappedFeatureId  = it->first;
 
3140
          snappedGeometry   = it->second;
 
3141
          vertexFound = true;
 
3142
        }
 
3143
    }
 
3144
 
 
3145
  if(!vertexFound)
 
3146
    {
 
3147
      beforeVertexIndex = -1;
 
3148
      afterVertexIndex = -1;
 
3149
      return false;
 
3150
    }
 
3151
 
 
3152
   if(projectionsEnabled())
 
3153
    {
 
3154
      //transform point to canvas SRC
 
3155
      try
 
3156
        {
 
3157
          point = coordinateTransform()->transform(point);
 
3158
        }
 
3159
      catch(QgsCsException &cse)
 
3160
        {
 
3161
          return false;
 
3162
        }
 
3163
    }
 
3164
  return true;
 
3165
}
 
3166
 
 
3167
 
 
3168
bool QgsVectorLayer::snapSegmentWithContext(QgsPoint& point, QgsGeometryVertexIndex& beforeVertex, int& snappedFeatureId,\
 
3169
QgsGeometry& snappedGeometry, double tolerance)
 
3170
{
 
3171
  bool segmentFound = false; //flag to check if a reasonable result can be returned
 
3172
  QgsGeometryVertexIndex beforeVertexTemp;
 
3173
 
 
3174
  QgsPoint origPoint = point;
 
3175
 
 
3176
  // Sanity checking
 
3177
  if ( tolerance<=0 || !dataProvider)
 
3178
  {
 
3179
    return false;
 
3180
  }
 
3181
 
 
3182
  QgsFeature* feature;
 
3183
  QgsPoint minDistSegPoint;  // the closest point on the segment
 
3184
  double testSqrDist;        // the squared distance between 'point' and 'snappedFeature'
 
3185
  double minSqrDist  = tolerance*tolerance; //current minimum distance
 
3186
 
 
3187
  QgsRect selectrect(point.x()-tolerance, point.y()-tolerance, point.x()+tolerance, point.y()+tolerance);
 
3188
  dataProvider->reset();
 
3189
  dataProvider->select(&selectrect);
 
3190
 
 
3191
  if(projectionsEnabled() && coordinateTransform())
 
3192
    {
 
3193
      //inverse tramsform points to layer SRS
 
3194
      try
 
3195
        {
 
3196
          origPoint = coordinateTransform()->transform(point, QgsCoordinateTransform::INVERSE);
 
3197
        }
 
3198
      catch(QgsCsException &cse)
 
3199
        {
 
3200
          return false;
 
3201
        }
 
3202
    }
 
3203
 
 
3204
  // Go through the committed features
 
3205
  while ((feature = dataProvider->getNextFeature(false)))
 
3206
  {
 
3207
    if (mChangedGeometries.find(feature->featureId()) != mChangedGeometries.end())
 
3208
    {
 
3209
      // ignore for this loop, let the loop below over mChangedGeometries
 
3210
      // detect the changed geometry instead
 
3211
      continue;
 
3212
 
 
3213
      // // substitute the modified geometry for the committed version
 
3214
      // feature->setGeometry( mChangedGeometries[ feature->featureId() ] );
 
3215
    }
 
3216
 
 
3217
    minDistSegPoint = feature->geometry()->closestSegmentWithContext(origPoint, beforeVertexTemp, testSqrDist);
 
3218
 
 
3219
    if (
 
3220
        (testSqrDist < minSqrDist) ||
 
3221
        (
 
3222
         // this test will "choose" the polygon that the origPoint is in:
 
3223
         (testSqrDist == minSqrDist) && 
 
3224
         (feature->geometry()->contains(&origPoint))
 
3225
        )
 
3226
       )
 
3227
    {
 
3228
      point = minDistSegPoint;
 
3229
      minSqrDist = testSqrDist;
 
3230
 
 
3231
      beforeVertex      = beforeVertexTemp;
 
3232
      snappedFeatureId  = feature->featureId();
 
3233
      snappedGeometry   = *(feature->geometry());
 
3234
      segmentFound = true;
 
3235
    }
 
3236
    delete feature;
 
3237
  }
 
3238
 
 
3239
  // Also go through the new features
 
3240
  for (std::vector<QgsFeature*>::iterator iter  = mAddedFeatures.begin(); iter != mAddedFeatures.end(); ++iter)
 
3241
  {
 
3242
    if(mChangedGeometries.find((*iter)->featureId()) != mChangedGeometries.end())
 
3243
      {
 
3244
        // ignore for this loop, let the loop below over mChangedGeometries
 
3245
        // detect the changed geometry instead
 
3246
        continue;
 
3247
 
 
3248
        // //use the modified geometry
 
3249
        // minDistSegPoint = mChangedGeometries[(*iter)->featureId()].closestSegmentWithContext(origPoint, beforeVertexTemp, testSqrDist);
 
3250
      }
 
3251
    else
 
3252
      {
 
3253
        minDistSegPoint = (*iter)->geometry()->closestSegmentWithContext(origPoint, beforeVertexTemp, testSqrDist);
 
3254
      }
 
3255
 
 
3256
    if (
 
3257
        (testSqrDist < minSqrDist) ||
 
3258
        (
 
3259
         // this test will "choose" the polygon that the origPoint is in:
 
3260
         (testSqrDist == minSqrDist) && 
 
3261
         ((*iter)->geometry()->contains(&origPoint))
 
3262
        )
 
3263
       )
 
3264
    {
 
3265
      point = minDistSegPoint;
 
3266
      minSqrDist = testSqrDist;
 
3267
 
 
3268
      beforeVertex      = beforeVertexTemp;
 
3269
      snappedFeatureId  =   (*iter)->featureId();
 
3270
      snappedGeometry   = *((*iter)->geometry());
 
3271
      segmentFound = true;
 
3272
    }
 
3273
  }
 
3274
 
 
3275
  //and also go through the changed geometries, because the spatial filter of the provider did not consider feature changes
 
3276
  for(std::map<int, QgsGeometry>::iterator it = mChangedGeometries.begin(); it != mChangedGeometries.end(); ++it)
 
3277
    {
 
3278
      minDistSegPoint = it->second.closestSegmentWithContext(origPoint, beforeVertexTemp, testSqrDist);
 
3279
      if (
 
3280
          (testSqrDist < minSqrDist) ||
 
3281
          (
 
3282
           // this test will "choose" the polygon that the origPoint is in:
 
3283
           (testSqrDist == minSqrDist) && 
 
3284
           (it->second.contains(&origPoint))
 
3285
          )
 
3286
        )
 
3287
        {
 
3288
          point = minDistSegPoint;
 
3289
          minSqrDist = testSqrDist;
 
3290
          beforeVertex      = beforeVertexTemp;
 
3291
          snappedFeatureId  = it->first;
 
3292
          snappedGeometry   = it->second;
 
3293
          segmentFound = true;
 
3294
        }
 
3295
    }
 
3296
 
 
3297
  return segmentFound;
 
3298
}
 
3299
 
 
3300
 
 
3301
void QgsVectorLayer::drawFeature(QPainter* p,
 
3302
                                 QgsFeature* fet,
 
3303
                                 QgsMapToPixel * theMapToPixelTransform,
 
3304
                                 QPixmap * marker,
 
3305
                                 double markerScaleFactor,
 
3306
                                 bool projectionsEnabledFlag,
 
3307
                                 bool drawingToEditingCanvas)
 
3308
{
 
3309
  // Only have variables, etc outside the switch() statement that are
 
3310
  // used in all cases of the statement (otherwise they may get
 
3311
  // executed, but never used, in a bit of code where performance is
 
3312
  // critical).
 
3313
 
 
3314
#if defined(Q_WS_X11)
 
3315
  bool needToTrim = false;
 
3316
#endif
 
3317
 
 
3318
  unsigned char* feature = fet->getGeometry();
 
3319
 
 
3320
  unsigned int wkbType;
 
3321
  memcpy(&wkbType, (feature+1), sizeof(wkbType));
 
3322
 
 
3323
#ifdef QGISDEBUG
 
3324
  //std::cout <<"Entering drawFeature()" << std::endl;
 
3325
#endif
 
3326
 
 
3327
  switch (wkbType)
 
3328
  {
 
3329
    case QGis::WKBPoint:
 
3330
    case QGis::WKBPoint25D:
 
3331
      {
 
3332
        double x = *((double *) (feature + 5));
 
3333
        double y = *((double *) (feature + 5 + sizeof(double)));
 
3334
 
 
3335
#ifdef QGISDEBUG 
 
3336
        //  std::cout <<"...WKBPoint (" << x << ", " << y << ")" <<std::endl;
 
3337
#endif
 
3338
 
 
3339
        transformPoint(x, y, theMapToPixelTransform, projectionsEnabledFlag);
 
3340
        //QPointF pt(x - (marker->width()/2),  y - (marker->height()/2));
 
3341
        QPointF pt(x/markerScaleFactor - (marker->width()/2),  y/markerScaleFactor - (marker->height()/2));
 
3342
 
 
3343
        p->save();
 
3344
        p->scale(markerScaleFactor,markerScaleFactor);
 
3345
        p->drawPixmap(pt, *marker);
 
3346
        p->restore();
 
3347
 
 
3348
        break;
 
3349
      }
 
3350
    case QGis::WKBMultiPoint:
 
3351
    case QGis::WKBMultiPoint25D:
 
3352
      {
 
3353
        unsigned char *ptr = feature + 5;
 
3354
        unsigned int nPoints = *((int*)ptr);
 
3355
        ptr += 4;
 
3356
 
 
3357
        p->save();
 
3358
        p->scale(markerScaleFactor, markerScaleFactor);
 
3359
 
 
3360
        for (register unsigned int i = 0; i < nPoints; ++i)
 
3361
        {
 
3362
          ptr += 5;
 
3363
          double x = *((double *) ptr);
 
3364
          ptr += sizeof(double);
 
3365
          double y = *((double *) ptr);
 
3366
          ptr += sizeof(double);
 
3367
          
 
3368
          if (wkbType == QGis::WKBMultiPoint25D) // ignore Z value
 
3369
            ptr += sizeof(double);
 
3370
 
 
3371
#ifdef QGISDEBUG 
 
3372
          std::cout <<"...WKBMultiPoint (" << x << ", " << y << ")" <<std::endl;
 
3373
#endif
 
3374
 
 
3375
          transformPoint(x, y, theMapToPixelTransform, projectionsEnabledFlag);
 
3376
          //QPointF pt(x - (marker->width()/2),  y - (marker->height()/2));
 
3377
          QPointF pt(x/markerScaleFactor - (marker->width()/2),  y/markerScaleFactor - (marker->height()/2));
 
3378
          
 
3379
#if defined(Q_WS_X11)
 
3380
          // Work around a +/- 32768 limitation on coordinates in X11
 
3381
          if (std::abs(x) > QgsClipper::maxX ||
 
3382
              std::abs(y) > QgsClipper::maxY)
 
3383
            needToTrim = true;
 
3384
          else
 
3385
#endif
 
3386
          p->drawPixmap(pt, *marker);
 
3387
        }
 
3388
        p->restore();
 
3389
 
 
3390
        break;
 
3391
      }
 
3392
    case QGis::WKBLineString:
 
3393
    case QGis::WKBLineString25D:
 
3394
      {
 
3395
        drawLineString(feature,
 
3396
                       p,
 
3397
                       theMapToPixelTransform,
 
3398
                       projectionsEnabledFlag,
 
3399
                       drawingToEditingCanvas);
 
3400
        break;
 
3401
      }
 
3402
    case QGis::WKBMultiLineString:
 
3403
    case QGis::WKBMultiLineString25D:
 
3404
    {
 
3405
        unsigned char* ptr = feature + 5;
 
3406
        unsigned int numLineStrings = *((int*)ptr);
 
3407
        ptr = feature + 9;
 
3408
        
 
3409
        for (register unsigned int jdx = 0; jdx < numLineStrings; jdx++)
 
3410
        {
 
3411
          ptr = drawLineString(ptr,
 
3412
                               p,
 
3413
                               theMapToPixelTransform,
 
3414
                               projectionsEnabledFlag,
 
3415
                               drawingToEditingCanvas);
 
3416
        }
 
3417
        break;
 
3418
      }
 
3419
    case QGis::WKBPolygon:
 
3420
    case QGis::WKBPolygon25D:
 
3421
    {
 
3422
        drawPolygon(feature,
 
3423
                    p,
 
3424
                    theMapToPixelTransform,
 
3425
                    projectionsEnabledFlag,
 
3426
                    drawingToEditingCanvas);
 
3427
        break;
 
3428
      }
 
3429
    case QGis::WKBMultiPolygon:
 
3430
    case QGis::WKBMultiPolygon25D:
 
3431
    {
 
3432
        unsigned char *ptr = feature + 5;
 
3433
        unsigned int numPolygons = *((int*)ptr);
 
3434
        ptr = feature + 9;
 
3435
        for (register unsigned int kdx = 0; kdx < numPolygons; kdx++)
 
3436
          ptr = drawPolygon(ptr,
 
3437
                            p,
 
3438
                            theMapToPixelTransform, 
 
3439
                            projectionsEnabledFlag,
 
3440
                            drawingToEditingCanvas);
 
3441
        break;
 
3442
      }
 
3443
    default:
 
3444
#ifdef QGISDEBUG
 
3445
      std::cout << "UNKNOWN WKBTYPE ENCOUNTERED\n";
 
3446
#endif
 
3447
      break;
 
3448
  }
 
3449
}
 
3450
 
 
3451
 
 
3452
 
 
3453
void QgsVectorLayer::saveAsShapefile()
 
3454
{
 
3455
  // call the dataproviders saveAsShapefile method
 
3456
  dataProvider->saveAsShapefile();
 
3457
}
 
3458
 
 
3459
void QgsVectorLayer::setCoordinateSystem()
 
3460
{
 
3461
  delete mCoordinateTransform;
 
3462
  mCoordinateTransform=new QgsCoordinateTransform();
 
3463
  //slot is defined inthe maplayer superclass
 
3464
  connect(mCoordinateTransform, SIGNAL(invalidTransformInput()), this, SLOT(invalidTransformInput()));
 
3465
 
 
3466
  QgsDebugMsg("QgsVectorLayer::setCoordinateSystem ------------------------------------------------start");
 
3467
  QgsDebugMsg("QgsVectorLayer::setCoordinateSystem ----- Computing Coordinate System");
 
3468
  //
 
3469
  // Get the layers project info and set up the QgsCoordinateTransform 
 
3470
  // for this layer
 
3471
  //
 
3472
  int srid = getProjectionSrid();
 
3473
 
 
3474
  if(srid == 0)
 
3475
  {
 
3476
    QString mySourceWKT(getProjectionWKT());
 
3477
    if (mySourceWKT.isNull())
 
3478
    {
 
3479
      mySourceWKT=QString("");
 
3480
    }
 
3481
    QgsDebugMsg("QgsVectorLayer::setCoordinateSystem --- using wkt " + mySourceWKT);
 
3482
    mCoordinateTransform->sourceSRS().createFromWkt(mySourceWKT);
 
3483
    //mCoordinateTransform->sourceSRS()->createFromWkt(getProjectionWKT());
 
3484
  }
 
3485
  else
 
3486
  {
 
3487
    QgsDebugMsg("QgsVectorLayer::setCoordinateSystem --- using srid " + QString::number(srid));
 
3488
    mCoordinateTransform->sourceSRS().createFromSrid(srid);
 
3489
  }
 
3490
 
 
3491
  //QgsSpatialRefSys provides a mechanism for FORCE a srs to be valid
 
3492
  //which is inolves falling back to system, project or user selected
 
3493
  //defaults if the srs is not properly intialised.
 
3494
  //we only nee to do that if the srs is not alreay valid
 
3495
  if (!mCoordinateTransform->sourceSRS().isValid())
 
3496
  {
 
3497
    mCoordinateTransform->sourceSRS().validate();
 
3498
  }
 
3499
  //get the project projections WKT, defaulting to this layer's projection
 
3500
  //if none exists....
 
3501
  //First get the SRS for the default projection WGS 84
 
3502
  //QString defaultWkt = QgsSpatialReferences::instance()->getSrsBySrid("4326")->srText();
 
3503
 
 
3504
  // if no other layers exist, set the output projection to be
 
3505
  // the same as the input projection, otherwise set the output to the
 
3506
  // project srs
 
3507
 
 
3508
  QgsDebugMsg("Layer registry has " + QString::number(QgsMapLayerRegistry::instance()->count()) + " layers ");
 
3509
  if (QgsMapLayerRegistry::instance()->count() ==0)
 
3510
  {
 
3511
    mCoordinateTransform->destSRS().createFromProj4(
 
3512
        mCoordinateTransform->sourceSRS().proj4String());
 
3513
    //first layer added will set the default project level projection
 
3514
    //TODO remove cast if poss!
 
3515
    int mySrsId = static_cast<int>(mCoordinateTransform->sourceSRS().srsid());
 
3516
    if (mySrsId)
 
3517
    {
 
3518
      QgsProject::instance()->writeEntry("SpatialRefSys","/ProjectSRSID",mySrsId);
 
3519
    }
 
3520
  }
 
3521
  else 
 
3522
  {
 
3523
    mCoordinateTransform->destSRS().createFromSrsId(
 
3524
        QgsProject::instance()->readNumEntry("SpatialRefSys","/ProjectSRSID",0));
 
3525
  }
 
3526
  if (!mCoordinateTransform->destSRS().isValid())
 
3527
  {
 
3528
    mCoordinateTransform->destSRS().validate();  
 
3529
  }
 
3530
 
 
3531
 
 
3532
  //initialise the transform - you should do this any time one of the SRS's changes
 
3533
 
 
3534
  mCoordinateTransform->initialise();
 
3535
 
 
3536
 
 
3537
 
 
3538
}
 
3539
 
 
3540
bool QgsVectorLayer::commitAttributeChanges(const std::set<QString>& deleted,
 
3541
    const std::map<QString,QString>& added,
 
3542
    std::map<int,std::map<QString,QString> >& changed)
 
3543
{
 
3544
  bool returnvalue=true;
 
3545
 
 
3546
  if(dataProvider)
 
3547
  {
 
3548
    if(dataProvider->capabilities()&QgsVectorDataProvider::DeleteAttributes)
 
3549
    {
 
3550
      //delete attributes in all not commited features
 
3551
      for(std::vector<QgsFeature*>::iterator iter=mAddedFeatures.begin();iter!=mAddedFeatures.end();++iter)
 
3552
      {
 
3553
        for(std::set<QString>::const_iterator it=deleted.begin();it!=deleted.end();++it)
 
3554
        {
 
3555
          (*iter)->deleteAttribute(*it);
 
3556
        }
 
3557
      }
 
3558
      //and then in the provider
 
3559
      if(!dataProvider->deleteAttributes(deleted))
 
3560
      {
 
3561
        returnvalue=false;
 
3562
      }
 
3563
    }
 
3564
 
 
3565
    if(dataProvider->capabilities()&QgsVectorDataProvider::AddAttributes)
 
3566
    {
 
3567
      //add attributes in all not commited features
 
3568
      for(std::vector<QgsFeature*>::iterator iter=mAddedFeatures.begin();iter!=mAddedFeatures.end();++iter)
 
3569
      {
 
3570
        for(std::map<QString,QString>::const_iterator it=added.begin();it!=added.end();++it)
 
3571
        {
 
3572
          (*iter)->addAttribute(it->first);
 
3573
        }
 
3574
      }
 
3575
      //and then in the provider
 
3576
      if(!dataProvider->addAttributes(added))
 
3577
      {
 
3578
        returnvalue=false;
 
3579
      }
 
3580
    }
 
3581
 
 
3582
    if(dataProvider->capabilities()&QgsVectorDataProvider::ChangeAttributeValues)
 
3583
    {
 
3584
      //change values of the not commited features
 
3585
      for(std::vector<QgsFeature*>::iterator iter=mAddedFeatures.begin();iter!=mAddedFeatures.end();++iter)
 
3586
      {
 
3587
        std::map<int,std::map<QString,QString> >::iterator it=changed.find((*iter)->featureId());
 
3588
        if(it!=changed.end())
 
3589
        {
 
3590
          for(std::map<QString,QString>::const_iterator iterat=it->second.begin();iterat!=it->second.end();++iterat)
 
3591
          {
 
3592
            (*iter)->changeAttributeValue(iterat->first,iterat->second);
 
3593
          }
 
3594
          changed.erase(it);
 
3595
        }
 
3596
      }
 
3597
 
 
3598
      //and then those of the commited ones
 
3599
      if(!dataProvider->changeAttributeValues(changed))
 
3600
      {
 
3601
        returnvalue=false;
 
3602
      }
 
3603
    }
 
3604
  }
 
3605
  else
 
3606
  {
 
3607
    returnvalue=false;
 
3608
  }
 
3609
  return returnvalue;
 
3610
}
 
3611
 
 
3612
// Convenience function to transform the given point
 
3613
inline void QgsVectorLayer::transformPoint(double& x, 
 
3614
    double& y, 
 
3615
    QgsMapToPixel* mtp,
 
3616
    bool projectionsEnabledFlag)
 
3617
{
 
3618
  // transform the point
 
3619
  if (projectionsEnabledFlag)
 
3620
  {
 
3621
    double z = 0;
 
3622
    mCoordinateTransform->transformInPlace(x, y, z);
 
3623
  }
 
3624
 
 
3625
  // transform from projected coordinate system to pixel 
 
3626
  // position on map canvas
 
3627
  mtp->transformInPlace(x, y);
 
3628
}
 
3629
 
 
3630
inline void QgsVectorLayer::transformPoints(
 
3631
    std::vector<double>& x, std::vector<double>& y, std::vector<double>& z,
 
3632
    QgsMapToPixel* mtp, bool projectionsEnabledFlag)
 
3633
{
 
3634
  // transform the point
 
3635
  if (projectionsEnabledFlag)
 
3636
    mCoordinateTransform->transformInPlace(x, y, z);
 
3637
 
 
3638
  // transform from projected coordinate system to pixel 
 
3639
  // position on map canvas
 
3640
  mtp->transformInPlace(x, y);
 
3641
}
 
3642
 
 
3643
unsigned int QgsVectorLayer::getTransparency()
 
3644
{
 
3645
  return transparencyLevelInt;
 
3646
}
 
3647
 
 
3648
//should be between 0 and 255
 
3649
void QgsVectorLayer::setTransparency(unsigned int theInt)
 
3650
{
 
3651
  transparencyLevelInt=theInt;
 
3652
} //  QgsRasterLayer::setTransparency(unsigned int theInt)
 
3653