1
/***************************************************************************
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
9
copyright : (C) 2003 by Gary E.Sherman
10
email : sherman at mrcc.com
12
***************************************************************************/
14
/***************************************************************************
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. *
21
***************************************************************************/
22
/* $Id: qgsvectorlayer.cpp 6320 2006-12-27 15:44:05Z mhugent $ */
40
#include <netinet/in.h>
43
#include <QApplication>
46
#include <QMessageBox>
48
#include <QPainterPath>
51
#include <QProgressDialog>
55
#include "qgis.h" //for globals
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"
66
#include "qgsgraduatedsymbolrenderer.h"
68
#include "qgslabelattributes.h"
69
#include "qgslegend.h"
70
#include "qgslogger.h"
71
#include "qgsmaplayerregistry.h"
72
#include "qgsmaptopixel.h"
74
#include "qgsproject.h"
75
#include "qgsproviderregistry.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"
87
#include "qgsclipper.h"
89
//#include "wkbheader.h"
91
#ifdef TESTPROVIDERLIB
96
static const char * const ident_ = "$Id: qgsvectorlayer.cpp 6320 2006-12-27 15:44:05Z mhugent $";
98
// typedef for the QgsDataProvider class factory
99
typedef QgsDataProvider * create_it(const QString* uri);
103
QgsVectorLayer::QgsVectorLayer(QString vectorLayerPath,
106
: QgsMapLayer(VECTOR, baseName, vectorLayerPath),
110
m_propertiesDialog(0),
111
providerKey(providerKey),
114
updateThreshold(0), // XXX better default value?
117
mScaleDependentRender(false),
120
mToggleEditingAction(0)
122
// if we're given a provider type, try to create and bind one to this layer
123
if ( ! providerKey.isEmpty() )
125
setDataProvider( providerKey );
129
setCoordinateSystem();
131
// Default for the popup menu
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
140
updateThreshold = settings.readNumEntry("Map/updateThreshold", 1000);
142
} // QgsVectorLayer ctor
146
QgsVectorLayer::~QgsVectorLayer()
148
QgsDebugMsg("In QgsVectorLayer destructor");
159
tabledisplay->close();
166
if (m_propertiesDialog)
168
delete m_propertiesDialog;
170
// delete the provider object
172
// delete the popu pmenu
174
// delete the provider lib pointer
178
// Destroy any cached geometries and clear the references to them
179
deleteCachedGeometries();
182
QString QgsVectorLayer::storageType() const
186
return dataProvider->storageType();
192
QString QgsVectorLayer::capabilitiesString() const
196
return dataProvider->capabilitiesString();
201
int QgsVectorLayer::getProjectionSrid()
203
//delegate to the provider
206
QgsDebugMsg("Getting srid from provider...");
207
return dataProvider->getSrid();
215
QString QgsVectorLayer::getProjectionWKT()
217
//delegate to the provider
220
return dataProvider->getProjectionWKT();
228
QString QgsVectorLayer::providerType()
234
* sets the preferred display field based on some fuzzy logic
236
void QgsVectorLayer::setDisplayField(QString fldName)
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.
246
std::vector < QgsField > fields = dataProvider->fields();
247
if(!fldName.isEmpty())
249
// find the index for this field
250
fieldIndex = fldName;
252
for(int i = 0; i < fields.size(); i++)
254
if(QString(fields[i].name()) == fldName)
264
int fieldsSize = fields.size();
265
for (int j = 0; j < fieldsSize; j++)
268
QString fldName = fields[j].name();
269
QgsDebugMsg("Checking field " + fldName + " of " + QString::number(fields.size()) + " total");
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)
277
if(idxName.isEmpty())
282
if (fldName.find("descrip", false) > -1)
284
if(idxName.isEmpty())
289
if (fldName.find("id", false) > -1)
298
//if there were no fields in the dbf just return - otherwise qgis segfaults!
299
if (fields.size() == 0) return;
301
if (idxName.length() > 0)
303
fieldIndex = idxName;
307
if (idxId.length() > 0)
313
fieldIndex = fields[0].name();
317
// set this to be the label field as well
318
setLabelField(fieldIndex);
322
void QgsVectorLayer::drawLabels(QPainter * p, QgsRect * viewExtent, QgsMapToPixel * theMapToPixelTransform)
324
drawLabels(p, viewExtent, theMapToPixelTransform, 1.);
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)
332
QgsDebugMsg("Starting draw of labels");
334
if ( /*1 == 1 */ m_renderer && mLabelOn)
336
bool projectionsEnabledFlag = projectionsEnabled();
337
std::list<int> attributes=m_renderer->classificationAttributes();
338
// Add fields required for labels
339
mLabel->addRequiredFields ( &attributes );
341
QgsDebugMsg("Selecting features based on view extent");
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);
354
while((fet = dataProvider->getNextFeature(attributes)))
359
//don't render labels of deleted features
360
if(mDeletedFeatureIds.find(fet->featureId())==mDeletedFeatureIds.end())
362
bool sel=mSelectedFeatureIds.find(fet->featureId()) != mSelectedFeatureIds.end();
363
mLabel->renderLabel ( p, viewExtent, *mCoordinateTransform,
364
projectionsEnabledFlag,
365
theMapToPixelTransform, fet, sel, 0, scale);
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)
376
bool sel=mSelectedFeatureIds.find((*it)->featureId()) != mSelectedFeatureIds.end();
377
mLabel->renderLabel ( p, viewExtent, *mCoordinateTransform, projectionsEnabledFlag,
378
theMapToPixelTransform, *it, sel, 0, scale);
381
catch (QgsCsException &e)
383
QgsLogger::critical("Error projecting label locations, caught in " + QString(__FILE__) + ", line " +QString(__LINE__));
387
QgsLogger::debug("Total features processed", featureCount, 1, __FILE__, __FUNCTION__, __LINE__);
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();
397
QgsRect QgsVectorLayer::inverseProjectRect(const QgsRect& r) const
399
// Undo a coordinate transformation if one was in effect
400
if (projectionsEnabled())
404
QgsPoint p1 = mCoordinateTransform->transform(r.xMin(), r.yMin(),
405
QgsCoordinateTransform::INVERSE);
406
QgsPoint p2 = mCoordinateTransform->transform(r.xMax(), r.yMax(),
407
QgsCoordinateTransform::INVERSE);
409
QgsDebugMsg("Projections are enabled");
410
QgsDebugMsg("Rectangle was: "+r.stringRep(true));
412
QgsDebugMsg("Inverse transformed to: "+tt.stringRep(true))
414
return QgsRect(p1, p2);
417
catch (QgsCsException &e)
419
QgsLogger::critical("Inverse transform error in " + QString(__FILE__) + ", line " + QString(__LINE__));
422
// fall through for all failures
426
unsigned char* QgsVectorLayer::drawLineString(unsigned char* feature,
429
bool projectionsEnabledFlag,
430
bool drawingToEditingCanvas)
432
unsigned char *ptr = feature + 5;
433
unsigned int wkbType = *((int*)(feature+1));
434
unsigned int nPoints = *((int*)ptr);
437
bool hasZValue = (wkbType == QGis::WKBLineString25D);
439
std::vector<double> x(nPoints);
440
std::vector<double> y(nPoints);
441
std::vector<double> z(nPoints, 0.0);
443
// Extract the points from the WKB format into the x and y vectors.
444
for (register unsigned int i = 0; i < nPoints; ++i)
446
x[i] = *((double *) ptr);
447
ptr += sizeof(double);
448
y[i] = *((double *) ptr);
449
ptr += sizeof(double);
451
if (hasZValue) // ignore Z value
452
ptr += sizeof(double);
455
// Transform the points into map coordinates (and reproject if
458
transformPoints(x, y, z, mtp, projectionsEnabledFlag);
460
#if defined(Q_WS_X11)
461
// Work around a +/- 32768 limitation on coordinates in X11
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)
470
QgsClipper::trimFeature(x, y, true); // true = polyline
471
nPoints = x.size(); // trimming may change nPoints.
476
// set up QPolygonF class with transformed points
477
QPolygonF pa(nPoints);
478
for (register unsigned int i = 0; i < nPoints; ++i)
484
#ifdef QGISDEBUGVERBOSE
485
// this is only used for verbose debug output
486
for (int i = 0; i < pa.size(); ++i)
488
QgsDebugMsgLevel("pa" + QString::number(pa.point(i).x()), 2);
489
QgsDebugMsgLevel("pa" + QString::number(pa.point(i).y()), 2);
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
498
// experimental alpha transparency
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);
508
// draw vertex markers if in editing mode, but only to the main canvas
511
(drawingToEditingCanvas)
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)
518
drawVertexMarker((int)(*xIt), (int)(*yIt), *p);
528
unsigned char* QgsVectorLayer::drawPolygon(unsigned char* feature,
531
bool projectionsEnabledFlag,
532
bool drawingToEditingCanvas)
534
typedef std::pair<std::vector<double>, std::vector<double> > ringType;
535
typedef ringType* ringTypePtr;
536
typedef std::vector<ringTypePtr> ringsType;
538
// get number of rings in the polygon
539
unsigned int numRings = *((int*)(feature + 1 + sizeof(int)));
541
if ( numRings == 0 ) // sanity check for zero rings in polygon
544
unsigned int wkbType = *((int*)(feature+1));
546
bool hasZValue = (wkbType == QGis::WKBPolygon25D);
548
int total_points = 0;
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.
555
// Set pointer to the first ring
556
unsigned char* ptr = feature + 1 + 2 * sizeof(int);
558
for (register unsigned int idx = 0; idx < numRings; idx++)
560
unsigned int nPoints = *((int*)ptr);
562
ringTypePtr ring = new ringType(std::vector<double>(nPoints),
563
std::vector<double>(nPoints));
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
572
std::cerr << "Points for ring " << idx << " ("
573
<< nPoints << " points)\n";
576
for (register unsigned int jdx = 0; jdx < nPoints; jdx++)
578
ring->first[jdx] = *((double *) ptr);
579
ptr += sizeof(double);
580
ring->second[jdx] = *((double *) ptr);
581
ptr += sizeof(double);
584
ptr += sizeof(double);
588
std::cerr << jdx << ": "
589
<< ring->first[jdx] << ", " << ring->second[jdx] << '\n';
593
// If ring has fewer than two points, what is it then?
594
// Anyway, this check prevents a crash
597
QgsDebugMsg("Ring has only " + QString::number(nPoints) + " points! Skipping this ring.");
601
transformPoints(ring->first, ring->second, zVector, mtp, projectionsEnabledFlag);
603
#if defined(Q_WS_X11)
604
// Work around a +/- 32768 limitation on coordinates in X11
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)
611
if (std::abs(ring->first[i]) > QgsClipper::maxX ||
612
std::abs(ring->second[i]) > QgsClipper::maxY)
614
QgsClipper::trimFeature(ring->first, ring->second, false);
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';
625
//std::cout << "POLYGONTRANSFORM: " << ring->first[i] << ", " << ring->second[i] << std::endl;
630
// Don't bother keeping the ring if it has been trimmed out of
632
if (ring->first.size() == 0)
636
rings.push_back(ring);
637
total_points += ring->first.size();
641
// Now we draw the polygons
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
649
// Only try to draw polygons if there is something to draw
650
if (total_points > 0)
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)
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();
663
// Transfer points to the array of QPointF
664
QPolygonF pa(ringSize);
665
for (register unsigned int j = 0; j != ringSize; ++j)
667
pa[j].setX(r->first[j]);
668
pa[j].setY(r->second[j]);
673
// Tidy up the pointed to pairs of vectors as we finish with them
677
#ifdef QGISDEBUGVERBOSE
678
// this is only for verbose debug output -- no optimzation is
680
QgsDebugMsg("Pixel points are:");
681
for (int i = 0; i < pa.size(); ++i)
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);
687
std::cerr << "Ring positions are:\n";
688
QgsDebugMsg("Ring positions are:");
689
for (int i = 0; i < ringDetails.size(); ++i)
691
QgsDebugMsgLevel("ringDetails[i].first" + QString::number(ringDetails[i].first), 2);
692
QgsDebugMsgLevel("ringDetails[i].second" + QString::number(ringDetails[i].second), 2);
694
QgsDebugMsg("Outer ring point is " + QString::number(outerRingPt.x()) + ", " + QString::number(outerRingPt.y()));
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();
705
for (int i = 0; i < pa.size(); ++i)
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());
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';
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
722
// experimental alpha transparency
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);
734
p->setBrush(myTransparentBrush);
735
p->setPen (myTransparentPen);
743
// draw vertex markers if in editing mode, but only to the main canvas
746
(drawingToEditingCanvas)
749
for(int i = 0; i < path.elementCount(); ++i)
751
const QPainterPath::Element & e = path.elementAt(i);
752
drawVertexMarker((int)e.x, (int)e.y, *p);
757
//restore brush and pen to original
759
p->setBrush ( brush );
768
bool QgsVectorLayer::draw(QPainter * p,
769
QgsRect * viewExtent,
770
QgsMapToPixel * theMapToPixelTransform,
771
bool drawingToEditingCanvas)
775
theMapToPixelTransform,
776
drawingToEditingCanvas,
780
return TRUE; // Assume success always
783
void QgsVectorLayer::draw(QPainter * p,
784
QgsRect * viewExtent,
785
QgsMapToPixel * theMapToPixelTransform,
786
bool drawingToEditingCanvas,
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
801
/*Pointer to a marker image*/
803
/*Scale factor of the marker image*/
804
double markerScaleFactor=1.;
808
// Destroy all cached geometries and clear the references to them
809
deleteCachedGeometries();
812
dataProvider->reset();
813
dataProvider->select(viewExtent);
814
dataProvider->updateFeatureCount();
815
int totalFeatures = dataProvider->featureCount();
816
int featureCount = 0;
819
bool projectionsEnabledFlag = projectionsEnabled();
820
std::list<int> attributes=m_renderer->classificationAttributes();
822
mDrawingCancelled=false; //pressing esc will change this to true
831
while (fet = dataProvider->getNextFeature(attributes, updateThreshold))
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)
841
// signal progress in drawing
842
if(0 == featureCount % updateThreshold)
843
emit drawingProgress(featureCount, totalFeatures);
848
QgsDebugMsg("get next feature returned null");
854
if (mDeletedFeatureIds.find(fet->featureId()) != mDeletedFeatureIds.end())
857
continue; //dont't draw feature marked as deleted
859
if (mChangedGeometries.find(fet->featureId()) != mChangedGeometries.end())
861
// substitute the committed geometry with the modified one
862
fet->setGeometry( mChangedGeometries[ fet->featureId() ] );
864
// Cache this for the use of (e.g.) modifying the feature's uncommitted geometry.
865
mCachedGeometries[fet->featureId()] = fet->geometryAndOwnership();
868
// check if feature is selected
869
// only show selections of the current layer
872
(mLegend && mLegend->currentLayer() == this) &&
873
(mSelectedFeatureIds.find(fet->featureId()) != mSelectedFeatureIds.end())
883
m_renderer->renderFeature(p, fet, &marker, &markerScaleFactor, sel, widthScale );
884
double scale = markerScaleFactor * symbolScale;
887
theMapToPixelTransform,
890
projectionsEnabledFlag,
891
drawingToEditingCanvas);
896
//also draw the not yet commited features
899
for(std::vector<QgsFeature*>::iterator it = mAddedFeatures.begin(); it != mAddedFeatures.end(); ++it)
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())
906
(*it)->setGeometry( mChangedGeometries[(*it)->featureId() ] );
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));
913
theMapToPixelTransform,
916
projectionsEnabledFlag,
917
drawingToEditingCanvas);
921
catch (QgsCsException &cse)
923
QString msg("Failed to transform a point while drawing a feature of type '"
924
+ fet->typeName() + "'. Ignoring this feature.");
926
qWarning(msg.toLocal8Bit().data());
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();
935
QgsLogger::warning("QgsRenderer is null in QgsVectorLayer::draw()");
940
QgsVectorLayer::endian_t QgsVectorLayer::endian()
942
// char *chkEndian = new char[4];
943
// memset(chkEndian, '\0', 4);
944
// chkEndian[0] = 0xE8;
946
// int *ce = (int *) chkEndian;
953
// delete [] chkEndian;
955
return (htonl(1) == 1) ? QgsVectorLayer::XDR : QgsVectorLayer::NDR ;
958
void QgsVectorLayer::cacheGeometries()
964
dataProvider->reset();
966
while(f = dataProvider->getNextFeature(false))
968
mCachedGeometries.insert(std::make_pair(f->featureId(), f->geometryAndOwnership()));
974
void QgsVectorLayer::deleteCachedGeometries()
976
// Destroy any cached geometries and clear the references to them
978
for (std::map<int, QgsGeometry*>::iterator it = mCachedGeometries.begin(); it != mCachedGeometries.end(); ++it )
982
mCachedGeometries.clear();
985
void QgsVectorLayer::drawVertexMarker(int x, int y, QPainter& p)
987
//todo: let the user configure the size and appearance of the marker
990
p.drawLine(x-m, y+m, x+m, y-m);
991
p.drawLine(x-m, y-m, x+m, y+m);
994
void QgsVectorLayer::table(QgisApp * qgisApp)
998
tabledisplay->raise();
999
// Give the table the most recent copy of the actions for this
1001
tabledisplay->table()->setAttributeActions(mActions);
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);
1013
tabledisplay->setTitle(tr("Attribute table - ") + name());
1014
tabledisplay->show();
1015
tabledisplay->table()->clearSelection(); //deselect the first row
1017
// Give the table the most recent copy of the actions for this
1019
tabledisplay->table()->setAttributeActions(mActions);
1021
QObject::disconnect(tabledisplay->table(), SIGNAL(selectionChanged()), tabledisplay->table(), SLOT(handleChangedSelections()));
1023
for (std::set<int>::iterator it = mSelectedFeatureIds.begin(); it != mSelectedFeatureIds.end(); ++it)
1025
tabledisplay->table()->selectRowWithId(*it);//todo: avoid that the table gets repainted during each selection
1027
qWarning(("selecting row with id " + QString::number(*it)).toLocal8Bit().data());
1032
QObject::connect(tabledisplay->table(), SIGNAL(selectionChanged()), tabledisplay->table(), SLOT(handleChangedSelections()));
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();
1041
} // QgsVectorLayer::table
1043
void QgsVectorLayer::select(int number)
1045
mSelectedFeatureIds.insert(number);
1046
emit selectionChanged();
1049
void QgsVectorLayer::select(QgsRect * rect, bool lock)
1051
QApplication::setOverrideCursor(Qt::WaitCursor);
1052
// normalize the rectangle
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
1062
removeSelection(); //only if ctrl-button is not pressed
1065
tabledisplay->table()->clearSelection();
1069
QgsRect r = inverseProjectRect(*rect);
1070
dataProvider->select(&r, true);
1074
while (fet = dataProvider->getNextFeature(false))
1076
if(mDeletedFeatureIds.find(fet->featureId())==mDeletedFeatureIds.end())//don't select deleted features
1078
select(fet->featureId());
1081
tabledisplay->table()->selectRowWithId(fet->featureId());
1087
//also test the not commited features
1088
for(std::vector<QgsFeature*>::iterator it=mAddedFeatures.begin();it!=mAddedFeatures.end();++it)
1090
if((*it)->geometry()->intersects(rect))
1092
select((*it)->featureId());
1095
tabledisplay->table()->selectRowWithId((*it)->featureId());
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
1106
QApplication::restoreOverrideCursor();
1108
emit selectionChanged();
1111
void QgsVectorLayer::invertSelection()
1113
QApplication::setOverrideCursor(Qt::waitCursor);
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();
1122
//copy the ids of selected features to tmp
1124
for(std::set<int>::iterator iter=mSelectedFeatureIds.begin();iter!=mSelectedFeatureIds.end();++iter)
1126
tmp.push_back(*iter);
1132
tabledisplay->table()->clearSelection();
1136
dataProvider->reset();
1138
while (fet = dataProvider->getNextFeature(true))
1140
if(mDeletedFeatureIds.find(fet->featureId())==mDeletedFeatureIds.end())//don't select deleted features
1142
select(fet->featureId());
1146
for(std::vector<QgsFeature*>::iterator iter=mAddedFeatures.begin();iter!=mAddedFeatures.end();++iter)
1148
select((*iter)->featureId());
1151
for(std::list<int>::iterator iter=tmp.begin();iter!=tmp.end();++iter)
1153
mSelectedFeatureIds.erase(*iter);
1158
QProgressDialog progress( tr("Invert Selection..."), tr("Abort"), 0, mSelectedFeatureIds.size(), tabledisplay);
1160
for(std::set<int>::iterator iter=mSelectedFeatureIds.begin();iter!=mSelectedFeatureIds.end();++iter)
1163
progress.setValue(i);
1164
qApp->processEvents();
1165
if(progress.wasCanceled())
1167
//deselect the remaining features if action was canceled
1168
mSelectedFeatureIds.erase(iter,--mSelectedFeatureIds.end());
1171
tabledisplay->table()->selectRowWithId(*iter);//todo: avoid that the table gets repainted during each selection
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();
1183
QApplication::restoreOverrideCursor();
1185
emit selectionChanged();
1188
void QgsVectorLayer::removeSelection()
1190
mSelectedFeatureIds.clear();
1191
emit selectionChanged();
1194
void QgsVectorLayer::triggerRepaint()
1196
emit repaintRequested();
1199
void QgsVectorLayer::invalidateTableDisplay()
1204
QgsVectorDataProvider* QgsVectorLayer::getDataProvider()
1206
return dataProvider;
1209
const QgsVectorDataProvider* QgsVectorLayer::getDataProvider() const
1211
return dataProvider;
1214
void QgsVectorLayer::setProviderEncoding(const QString& encoding)
1218
dataProvider->setEncoding(encoding);
1223
void QgsVectorLayer::showLayerProperties()
1225
// Set wait cursor while the property dialog is created
1227
qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
1230
if (!m_propertiesDialog)
1233
std::cerr << "Creating new QgsVectorLayerProperties object\n";
1235
m_propertiesDialog = new QgsVectorLayerProperties(this);
1236
// Make sure that the UI starts out with the correct display
1239
std::cerr << "Setting display field in prop dialog\n";
1241
m_propertiesDialog->setDisplayField(displayField());
1244
std::cerr << "Raising prop dialog\n";
1246
m_propertiesDialog->raise();
1248
std::cerr << "Showing prop dialog\n";
1250
m_propertiesDialog->show();
1254
m_propertiesDialog->reset();
1255
m_propertiesDialog->show();
1256
m_propertiesDialog->raise();
1259
// restore normal cursor
1260
qApp->restoreOverrideCursor();
1264
const QgsRenderer* QgsVectorLayer::renderer() const
1269
void QgsVectorLayer::setRenderer(QgsRenderer * r)
1271
if (r != m_renderer)
1278
QGis::VectorType QgsVectorLayer::vectorType() const
1282
int type = dataProvider->geometryType();
1285
case QGis::WKBPoint:
1286
case QGis::WKBPoint25D:
1289
case QGis::WKBLineString:
1290
case QGis::WKBLineString25D:
1293
case QGis::WKBPolygon:
1294
case QGis::WKBPolygon25D:
1295
return QGis::Polygon;
1297
case QGis::WKBMultiPoint:
1298
case QGis::WKBMultiPoint25D:
1301
case QGis::WKBMultiLineString:
1302
case QGis::WKBMultiLineString25D:
1305
case QGis::WKBMultiPolygon:
1306
case QGis::WKBMultiPolygon25D:
1307
return QGis::Polygon;
1310
QgsLogger::debug("Warning: Data Provider Geometry type is not recognised, is", type, 1, __FILE__, __FUNCTION__, __LINE__);
1317
qWarning("warning, pointer to dataProvider is null in QgsVectorLayer::vectorType()");
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
1327
std::cerr << "WARNING: This code (file " << __FILE__ << ", line "
1328
<< __LINE__ << ") should never be reached. "
1329
<< "Problems may occur...\n";
1331
return QGis::Unknown;
1334
QGis::WKBTYPE QgsVectorLayer::getGeometryType() const
1336
return (QGis::WKBTYPE)(geometryType);
1339
QgsVectorLayerProperties *QgsVectorLayer::propertiesDialog()
1341
return m_propertiesDialog;
1345
void QgsVectorLayer::initContextMenu_(QgisApp * app)
1348
popMenu->addAction(tr("&Open attribute table"), app, SLOT(attributeTable()));
1350
popMenu->addSeparator();
1352
int cap=dataProvider->capabilities();
1353
if((cap&QgsVectorDataProvider::AddFeatures)
1354
||(cap&QgsVectorDataProvider::DeleteFeatures))
1356
mToggleEditingAction = popMenu->addAction(tr("Allow Editing"),this,SLOT(toggleEditing()));
1357
mToggleEditingAction->setCheckable(true);
1358
mToggleEditingAction->blockSignals(true);
1361
mToggleEditingAction->setChecked(true);
1365
mToggleEditingAction->setChecked(false);
1367
mToggleEditingAction->blockSignals(false);
1370
if(cap&QgsVectorDataProvider::SaveAsShapefile)
1372
// add the save as shapefile menu item
1373
popMenu->addSeparator();
1374
popMenu->addAction(tr("Save as shapefile..."), this, SLOT(saveAsShapefile()));
1377
} // QgsVectorLayer::initContextMenu_(QgisApp * app)
1379
QgsRect QgsVectorLayer::bBoxOfSelected()
1381
if(mSelectedFeatureIds.size()==0)//no selected features
1383
return QgsRect(0,0,0,0);
1388
dataProvider->reset();
1390
retval.setMinimal();
1391
while ((fet = dataProvider->getNextFeature(false)))
1393
if (mSelectedFeatureIds.find(fet->featureId()) != mSelectedFeatureIds.end())
1397
r=fet->boundingBox();
1398
retval.combineExtentWith(&r);
1403
//also go through the not commited features
1404
for(std::vector<QgsFeature*>::iterator iter=mAddedFeatures.begin();iter!=mAddedFeatures.end();++iter)
1406
if(mSelectedFeatureIds.find((*iter)->featureId())!=mSelectedFeatureIds.end())
1408
r=(*iter)->geometry()->boundingBox();
1409
retval.combineExtentWith(&r);
1413
if (retval.width() == 0.0 || retval.height() == 0.0)
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
1419
if (retval.xMin() == 0.0 && retval.xMax() == 0.0 &&
1420
retval.yMin() == 0.0 && retval.yMax() == 0.0)
1422
retval.set(-1.0, -1.0, 1.0, 1.0);
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);
1440
void QgsVectorLayer::setLayerProperties(QgsVectorLayerProperties * properties)
1442
m_propertiesDialog = properties;
1443
// Make sure that the UI gets the correct display
1446
if(m_propertiesDialog)
1448
m_propertiesDialog->setDisplayField(displayField());
1454
QgsFeature * QgsVectorLayer::getFirstFeature(bool fetchAttributes, bool selected) const
1456
if ( ! dataProvider )
1458
std::cerr << __FILE__ << ":" << __LINE__
1459
<< " QgsVectorLayer::getFirstFeature() invoked with null dataProvider\n";
1465
QgsFeature *fet = dataProvider->getFirstFeature(fetchAttributes);
1468
bool sel = mSelectedFeatureIds.find(fet->featureId()) != mSelectedFeatureIds.end();
1469
if ( sel ) return fet;
1470
fet = dataProvider->getNextFeature(fetchAttributes);
1475
return dataProvider->getFirstFeature( fetchAttributes );
1476
} // QgsVectorLayer::getFirstFeature
1479
QgsFeature * QgsVectorLayer::getNextFeature(bool fetchAttributes, bool selected) const
1481
if ( ! dataProvider )
1483
std::cerr << __FILE__ << ":" << __LINE__
1484
<< " QgsVectorLayer::getNextFeature() invoked with null dataProvider\n";
1491
while ( fet = dataProvider->getNextFeature(fetchAttributes) )
1493
bool sel = mSelectedFeatureIds.find(fet->featureId()) != mSelectedFeatureIds.end();
1494
if ( sel ) return fet;
1499
return dataProvider->getNextFeature( fetchAttributes );
1500
} // QgsVectorLayer::getNextFeature
1504
bool QgsVectorLayer::getNextFeature(QgsFeature &feature, bool fetchAttributes) const
1506
if ( ! dataProvider )
1508
std::cerr << __FILE__ << ":" << __LINE__
1509
<< " QgsVectorLayer::getNextFeature() invoked with null dataProvider\n";
1513
return dataProvider->getNextFeature( feature, fetchAttributes );
1514
} // QgsVectorLayer::getNextFeature
1518
long QgsVectorLayer::featureCount() const
1520
if ( ! dataProvider )
1522
std::cerr << __FILE__ << ":" << __LINE__
1523
<< " QgsVectorLayer::featureCount() invoked with null dataProvider\n";
1527
return dataProvider->featureCount();
1528
} // QgsVectorLayer::featureCount
1530
long QgsVectorLayer::updateFeatureCount() const
1532
if ( ! dataProvider )
1534
std::cerr << __FILE__ << ":" << __LINE__
1535
<< " QgsVectorLayer::updateFeatureCount() invoked with null dataProvider\n";
1538
return dataProvider->updateFeatureCount();
1541
void QgsVectorLayer::updateExtents()
1545
if(mDeletedFeatureIds.size()==0)
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());
1558
layerExtent.setMinimal();
1559
dataProvider->reset();
1560
while(fet=dataProvider->getNextFeature(false))
1562
if(mDeletedFeatureIds.find(fet->featureId())==mDeletedFeatureIds.end())
1566
bb=fet->boundingBox();
1567
layerExtent.combineExtentWith(&bb);
1576
std::cerr << __FILE__ << ":" << __LINE__
1577
<< " QgsVectorLayer::updateFeatureCount() invoked with null dataProvider\n";
1580
//todo: also consider the not commited features
1581
for(std::vector<QgsFeature*>::iterator iter=mAddedFeatures.begin();iter!=mAddedFeatures.end();++iter)
1583
QgsRect bb=(*iter)->boundingBox();
1584
layerExtent.combineExtentWith(&bb);
1588
// Send this (hopefully) up the chain to the map canvas
1589
emit recalculateExtents();
1592
QString QgsVectorLayer::subsetString()
1594
if ( ! dataProvider )
1596
std::cerr << __FILE__ << ":" << __LINE__
1597
<< " QgsVectorLayer::subsetString() invoked with null dataProvider\n";
1600
return dataProvider->subsetString();
1602
void QgsVectorLayer::setSubsetString(QString subset)
1604
if ( ! dataProvider )
1606
std::cerr << __FILE__ << ":" << __LINE__
1607
<< " QgsVectorLayer::setSubsetString() invoked with null dataProvider\n";
1611
dataProvider->setSubsetString(subset);
1612
// get the updated data source string from the provider
1613
dataSource = dataProvider->getDataSourceUri();
1616
//trigger a recalculate extents request to any attached canvases
1618
std::cout << "Subset query changed, emitting recalculateExtents() signal" << std::endl;
1620
// emit the signal to inform any listeners that the extent of this
1621
// layer has changed
1622
emit recalculateExtents();
1624
int QgsVectorLayer::fieldCount() const
1626
if ( ! dataProvider )
1628
std::cerr << __FILE__ << ":" << __LINE__
1629
<< " QgsVectorLayer::fieldCount() invoked with null dataProvider\n";
1633
return dataProvider->fieldCount();
1634
} // QgsVectorLayer::fieldCount
1637
std::vector<QgsField> const& QgsVectorLayer::fields() const
1639
if ( ! dataProvider )
1641
std::cerr << __FILE__ << ":" << __LINE__
1642
<< " QgsVectorLayer::fields() invoked with null dataProvider\n";
1644
static std::vector<QgsField> bogus; // empty, bogus container
1648
return dataProvider->fields();
1649
} // QgsVectorLayer::fields()
1652
bool QgsVectorLayer::addFeature(QgsFeature* f, bool alsoUpdateExtent)
1654
static int addedIdLowWaterMark = -1;
1658
if(!(dataProvider->capabilities() & QgsVectorDataProvider::AddFeatures))
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."));
1667
QMessageBox::information(0, tr("Layer not editable"),
1668
tr("The current layer is not editable. Choose 'Start editing' in the digitizing toolbar."));
1672
//assign a temporary id to the feature (use negative numbers)
1673
addedIdLowWaterMark--;
1676
qWarning("assigned feature id "+QString::number(addedIdLowWaterMark));
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();
1685
std::cout << "QgsVectorLayer::addFeature: about to traverse fields." << std::endl;
1687
for (std::map<int, QString>::iterator it = fields.begin(); it != fields.end(); ++it)
1690
std::cout << "QgsVectorLayer::addFeature: inspecting field '"
1691
<< (it->second).toLocal8Bit().data()
1692
<< "'." << std::endl;
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);
1704
//hide and delete the table because it is not up to date any more
1707
tabledisplay->close();
1708
delete tabledisplay;
1712
if (alsoUpdateExtent)
1723
bool QgsVectorLayer::insertVertexBefore(double x, double y, int atFeatureId, QgsGeometryVertexIndex beforeVertex)
1732
if(mChangedGeometries.find(atFeatureId) == mChangedGeometries.end())
1734
//first time this geometry has changed since last commit
1735
if(!mCachedGeometries[atFeatureId])
1739
mChangedGeometries[atFeatureId] = *(mCachedGeometries[atFeatureId]);
1742
mChangedGeometries[atFeatureId].insertVertexBefore(x, y, beforeVertex);
1750
bool QgsVectorLayer::moveVertexAt(double x, double y, int atFeatureId,
1751
QgsGeometryVertexIndex atVertex)
1760
if(mChangedGeometries.find(atFeatureId) == mChangedGeometries.end())
1762
// first time this geometry has changed since last commit
1763
if(mCachedGeometries.find(atFeatureId) == mCachedGeometries.end() || mCachedGeometries[atFeatureId] == 0)
1767
mChangedGeometries[atFeatureId] = *(mCachedGeometries[atFeatureId]);
1770
mChangedGeometries[atFeatureId].moveVertexAt(x, y, atVertex);
1778
bool QgsVectorLayer::deleteVertexAt(int atFeatureId,
1779
QgsGeometryVertexIndex atVertex)
1788
if(mChangedGeometries.find(atFeatureId) == mChangedGeometries.end())
1790
// first time this geometry has changed since last commit
1791
if(!mCachedGeometries[atFeatureId])
1795
mChangedGeometries[atFeatureId] = *(mCachedGeometries[atFeatureId]);
1798
mChangedGeometries[atFeatureId].deleteVertexAt(atVertex);
1806
QString QgsVectorLayer::getDefaultValue(const QString& attr,
1809
return dataProvider->getDefaultValue(attr, f);
1812
bool QgsVectorLayer::deleteSelectedFeatures()
1814
if(!(dataProvider->capabilities() & QgsVectorDataProvider::DeleteFeatures))
1816
QMessageBox::information(0, tr("Provider does not support deletion"),
1817
tr("Data provider does not support deleting features"));
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"));
1828
for(std::set<int>::iterator it=mSelectedFeatureIds.begin();it!=mSelectedFeatureIds.end();++it)
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)
1834
if((*it)==(*iter)->featureId())
1836
// Delete the feature itself before deleting the reference to it.
1838
mAddedFeatures.erase(iter);
1840
notcommitedfeature=true;
1844
if(!notcommitedfeature)
1846
mDeletedFeatureIds.insert(*it);
1850
if(mSelectedFeatureIds.size()>0)
1853
/* mSelectedFeatureIds.clear();*/
1858
//hide and delete the table because it is not up to date any more
1861
tabledisplay->close();
1862
delete tabledisplay;
1871
QgsLabel * QgsVectorLayer::label()
1876
void QgsVectorLayer::setLabelOn ( bool on )
1881
bool QgsVectorLayer::labelOn ( void )
1886
void QgsVectorLayer::toggleEditing()
1888
if(mToggleEditingAction)
1890
if (mToggleEditingAction->isChecked() ) //checking of the QAction is done before calling this slot
1902
void QgsVectorLayer::startEditing()
1906
if(!(dataProvider->capabilities()&QgsVectorDataProvider::AddFeatures))
1908
QMessageBox::information(0,tr("Start editing failed"),
1909
tr("Provider cannot be opened for editing"),
1914
// No longer need to cache all geometries
1915
// instead, mCachedGeometries is refreshed every time the
1916
// screen is redrawn.
1917
//cacheGeometries();
1923
if(mToggleEditingAction)
1925
mToggleEditingAction->setChecked(true);
1933
void QgsVectorLayer::stopEditing()
1935
bool commitSuccessful = FALSE;
1936
bool rollbackSuccessful = FALSE;
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);
1947
commitSuccessful = commitChanges();
1949
if(!commitSuccessful)
1951
QMessageBox::information(0,tr("Error"),tr("Could not commit changes"),QMessageBox::Ok);
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
1959
dataProvider->updateExtents();
1960
dataProvider->updateFeatureCount();
1961
//hide and delete the table because it is not up to date any more
1964
tabledisplay->close();
1965
delete tabledisplay;
1974
QMessageBox::information(0,tr("Error"),
1975
tr("Problems during roll back"),QMessageBox::Ok);
1977
//hide and delete the table because it is not up to date any more
1980
tabledisplay->close();
1981
delete tabledisplay;
1985
// Force this to TRUE otherwise the user will never be able
1986
// to get out of an ediitng session
1987
rollbackSuccessful = TRUE;
1989
emit editingStopped(true);
1991
else // if (!mModified)
1993
emit editingStopped(false);
2001
(commitSuccessful) ||
2002
(rollbackSuccessful)
2005
// convert state to non-editing mode
2006
deleteCachedGeometries();
2014
if(mToggleEditingAction)
2016
mToggleEditingAction->setChecked(false);
2023
// return state of scale dependent rendering. True if features should
2024
// only be rendered if between mMinimumScale and mMaximumScale
2025
bool QgsVectorLayer::scaleDependentRender()
2027
return mScaleDependentRender;
2031
// Return the minimum scale at which the layer is rendered
2032
int QgsVectorLayer::minimumScale()
2034
return mMinimumScale;
2036
// Return the maximum scale at which the layer is rendered
2037
int QgsVectorLayer::maximumScale()
2039
return mMaximumScale;
2044
bool QgsVectorLayer::readXML_( QDomNode & layer_node )
2047
std::cerr << "Datasource in QgsVectorLayer::readXML_: " << dataSource.toLocal8Bit().data() << std::endl;
2049
// process the attribute actions
2050
mActions.readXML(layer_node);
2052
//process provider key
2053
QDomNode pkeyNode = layer_node.namedItem("provider");
2055
if (pkeyNode.isNull())
2061
QDomElement pkeyElt = pkeyNode.toElement();
2062
providerKey = pkeyElt.text();
2065
// determine type of vector layer
2066
if ( ! providerKey.isNull() )
2068
// if the provider string isn't empty, then we successfully
2069
// got the stored provider
2071
else if ((dataSource.find("host=") > -1) &&
2072
(dataSource.find("dbname=") > -1))
2074
providerKey = "postgres";
2078
providerKey = "ogr";
2082
const char * dataproviderStr = providerKey.ascii(); // debugger probe
2085
if ( ! setDataProvider( providerKey ) )
2090
//read provider encoding
2091
QDomNode encodingNode = layer_node.namedItem("encoding");
2092
if( ! encodingNode.isNull() && dataProvider )
2094
dataProvider->setEncoding(encodingNode.toElement().text());
2097
// get and set the display field if it exists.
2098
QDomNode displayFieldNode = layer_node.namedItem("displayfield");
2099
if (!displayFieldNode.isNull())
2101
QDomElement e = displayFieldNode.toElement();
2102
setDisplayField(e.text());
2107
// create and bind a renderer to this layer
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");
2118
//std::auto_ptr<QgsRenderer> renderer; actually the renderer SHOULD NOT be
2119
//deleted when this function finishes, otherwise the application will
2121
// XXX this seems to be a dangerous implementation; should re-visit design
2122
QgsRenderer * renderer;
2127
// if we don't have a coordinate transform, get one
2130
// Im commenting this out - if the layer was serialied in a
2131
// >=0.7 project it should have been validated and have all
2135
//if ( ! coordinateTransform() )
2137
// setCoordinateSystem();
2140
if (!singlenode.isNull())
2142
renderer = new QgsSingleSymbolRenderer(vectorType());
2143
renderer->readXML(singlenode, *this);
2145
else if (!graduatednode.isNull())
2147
renderer = new QgsGraduatedSymbolRenderer(vectorType());
2148
renderer->readXML(graduatednode, *this);
2150
else if (!continuousnode.isNull())
2152
renderer = new QgsContinuousColorRenderer(vectorType());
2153
renderer->readXML(continuousnode, *this);
2155
else if (!uniquevaluenode.isNull())
2157
renderer = new QgsUniqueValueRenderer(vectorType());
2158
renderer->readXML(uniquevaluenode, *this);
2161
// Test if labeling is on or off
2162
QDomElement element = labelnode.toElement();
2163
int labelOn = element.text().toInt();
2174
std::cout << "Testing if qgsvectorlayer can call label readXML routine" << std::endl;
2177
QDomNode labelattributesnode = layer_node.namedItem("labelattributes");
2179
if(!labelattributesnode.isNull())
2182
std::cout << "qgsvectorlayer calling label readXML routine" << std::endl;
2184
mLabel->readXML(labelattributesnode);
2187
return valid; // should be true if read successfully
2189
} // void QgsVectorLayer::readXML_
2193
bool QgsVectorLayer::setDataProvider( QString const & provider )
2195
// XXX should I check for and possibly delete any pre-existing providers?
2196
// XXX How often will that scenario occur?
2198
providerKey = provider; // XXX is this necessary? Usually already set
2199
// XXX when execution gets here.
2201
//XXX - This was a dynamic cast but that kills the Windows
2202
// version big-time with an abnormal termination error
2204
(QgsVectorDataProvider*)(QgsProviderRegistry::instance()->getProvider(provider,dataSource));
2208
QgsDebug( "Instantiated the data provider plugin" );
2210
if (dataProvider->isValid())
2214
// TODO: Check if the provider has the capability to send fullExtentCalculated
2215
connect(dataProvider, SIGNAL( fullExtentCalculated() ),
2216
this, SLOT( updateExtents() )
2220
QgsRect *mbr = dataProvider->extent();
2223
QString s = mbr->stringRep();
2224
QgsDebugMsg("Extent of layer: " + s);
2226
layerExtent.setXmax(mbr->xMax());
2227
layerExtent.setXmin(mbr->xMin());
2228
layerExtent.setYmax(mbr->yMax());
2229
layerExtent.setYmin(mbr->yMin());
2231
// get and store the feature type
2232
geometryType = dataProvider->geometryType();
2234
// look at the fields in the layer and set the primary
2235
// display field using some real fuzzy logic
2238
if (providerKey == "postgres")
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
2248
setLayerName(lName);
2249
QgsDebugMsg("Beautifying layer name " + name());
2253
mLabel = new QgsLabel ( dataProvider->fields() );
2259
qDebug( "%s:%d invalid provider plugin %s",
2260
__FILE__, __LINE__, dataSource.ascii() );
2267
QgsDebug( " unable to get data provider" );
2274
} // QgsVectorLayer:: setDataProvider
2279
/* virtual */ bool QgsVectorLayer::writeXML_( QDomNode & layer_node,
2280
QDomDocument & document )
2282
// first get the layer element so that we can append the type attribute
2284
QDomElement mapLayerNode = layer_node.toElement();
2286
if ( mapLayerNode.isNull() || ("maplayer" != mapLayerNode.nodeName()) )
2288
qDebug( "QgsVectorLayer::writeXML() can't find <maplayer>" );
2292
mapLayerNode.setAttribute( "type", "vector" );
2294
// set the geometry type
2295
mapLayerNode.setAttribute( "geometry", QGis::qgisVectorGeometryType[vectorType()]);
2297
// add provider node
2299
QDomElement provider = document.createElement( "provider" );
2300
QDomText providerText = document.createTextNode( providerType() );
2301
provider.appendChild( providerText );
2302
layer_node.appendChild( provider );
2305
QDomElement encoding = document.createElement("encoding");
2306
QDomText encodingText = document.createTextNode(dataProvider->encoding());
2307
encoding.appendChild( encodingText );
2308
layer_node.appendChild( encoding );
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)
2315
QDomElement classificationElement = document.createElement("classificationattribute");
2316
QDomText classificationText = document.createTextNode(providerFields[*it].name());
2317
classificationElement.appendChild(classificationText);
2318
layer_node.appendChild(classificationElement);
2321
// add the display field
2323
QDomElement dField = document.createElement( "displayfield" );
2324
QDomText dFieldText = document.createTextNode( displayField() );
2325
dField.appendChild( dFieldText );
2326
layer_node.appendChild( dField );
2330
QDomElement label = document.createElement( "label" );
2331
QDomText labelText = document.createTextNode( "" );
2335
labelText.setData( "1" );
2339
labelText.setData( "0" );
2341
label.appendChild( labelText );
2343
layer_node.appendChild( label );
2345
// add attribute actions
2347
mActions.writeXML(layer_node, document);
2349
// renderer specific settings
2351
const QgsRenderer * myRenderer;
2352
if( myRenderer = renderer())
2354
myRenderer->writeXML(layer_node, document);
2358
std::cerr << __FILE__ << ":" << __LINE__
2359
<< " no renderer\n";
2361
// XXX return false?
2364
// Now we get to do all that all over again for QgsLabel
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.
2372
if ( myLabel = this->label() )
2374
std::stringstream labelXML;
2376
myLabel->writeXML(labelXML);
2378
QDomDocument labelDOM;
2381
std::string temp_str;
2386
// start with bogus XML header
2387
rawXML = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
2389
temp_str = labelXML.str();
2394
std::cout << rawXML << std::endl << std::flush;
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 ) )
2400
qDebug( ("XML import error at line %d column %d " + errorMsg).toLocal8Bit().data(), errorLine, errorColumn );
2405
// lastChild() because the first two nodes are the <xml> and
2406
// <!DOCTYPE> nodes; the label node follows that, and is (hopefully)
2408
QDomNode labelDOMNode = document.importNode( labelDOM.lastChild(), true );
2410
if ( ! labelDOMNode.isNull() )
2412
layer_node.appendChild( labelDOMNode );
2416
qDebug( "not able to import label DOM node" );
2418
// XXX return false?
2424
} // bool QgsVectorLayer::writeXML_
2427
/** we wouldn't have to do this if slots were inherited */
2428
void QgsVectorLayer::inOverview( bool b )
2430
QgsMapLayer::inOverview( b );
2433
int QgsVectorLayer::findFreeId()
2435
int freeid=-INT_MAX;
2439
dataProvider->reset();
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)))
2447
fid=fet->featureId();
2455
qWarning(("freeid is: "+QString::number(freeid+1)).toLocal8Bit().data());
2462
qWarning("Error, dataProvider is 0 in QgsVectorLayer::findFreeId");
2468
bool QgsVectorLayer::commitChanges()
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.
2482
// Attempt the commit of new features
2483
bool addedFeaturesOk = FALSE;
2484
if (mAddedFeatures.size() > 0)
2486
std::list<QgsFeature*> addedlist;
2487
for (std::vector<QgsFeature*>::iterator it = mAddedFeatures.begin(); it != mAddedFeatures.end(); ++it)
2489
addedlist.push_back(*it);
2492
if (!dataProvider->addFeatures(addedlist))
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.");
2498
QMessageBox::warning(0, tr("Error"), errorStrings.join(" "));
2503
// Added features committed OK, remove the in-memory changes
2505
// Delete the features themselves before deleting the references to them.
2506
for (std::vector<QgsFeature*>::iterator it = mAddedFeatures.begin(); it != mAddedFeatures.end(); ++it)
2510
mAddedFeatures.clear();
2511
addedFeaturesOk = TRUE;
2515
// Attempt the commit of changed attributes
2516
bool changedAttributesOk = FALSE;
2517
if (mChangedAttributes.size() > 0)
2519
if (!dataProvider->changeAttributeValues(mChangedAttributes))
2521
QStringList errorStrings;
2522
errorStrings += tr("Could not commit the changed attributes.");
2523
if (addedFeaturesOk)
2525
errorStrings += tr("However, the added features were committed OK.");
2527
errorStrings += tr("No other types of changes will be committed at this time.");
2529
QMessageBox::warning(0, tr("Error"), errorStrings.join(" "));
2534
// Changed attributes committed OK, remove the in-memory changes
2535
mChangedAttributes.clear();
2536
changedAttributesOk = TRUE;
2540
// Attempt the commit of changed geometries
2541
bool changedGeometriesOk = FALSE;
2542
if (mChangedGeometries.size() > 0)
2544
if (!dataProvider->changeGeometryValues(mChangedGeometries))
2546
QStringList errorStrings;
2547
errorStrings += tr("Could not commit the changed geometries.");
2548
if (addedFeaturesOk)
2550
errorStrings += tr("However, the added features were committed OK.");
2552
if (changedAttributesOk)
2554
errorStrings += tr("However, the changed attributes were committed OK.");
2556
errorStrings += tr("No other types of changes will be committed at this time.");
2558
QMessageBox::warning(0, tr("Error"), errorStrings.join(" "));
2563
// Changed geometries committed OK, remove the in-memory changes
2564
mChangedGeometries.clear();
2565
changedGeometriesOk = TRUE;
2569
// Attempt the commit of deleted features
2570
bool deletedFeaturesOk = FALSE;
2571
if (mDeletedFeatureIds.size() > 0)
2573
std::list<int> deletelist;
2574
for (std::set<int>::iterator it = mDeletedFeatureIds.begin(); it != mDeletedFeatureIds.end(); ++it)
2576
deletelist.push_back(*it);
2577
mSelectedFeatureIds.erase(*it);//just in case the feature is still selected
2580
if (!dataProvider->deleteFeatures(deletelist))
2582
QStringList errorStrings;
2583
errorStrings += tr("Could not commit the deleted features.");
2584
if (addedFeaturesOk)
2586
errorStrings += tr("However, the added features were committed OK.");
2588
if (changedAttributesOk)
2590
errorStrings += tr("However, the changed attributes were committed OK.");
2592
if (changedGeometriesOk)
2594
errorStrings += tr("However, the changed geometries were committed OK.");
2596
errorStrings += tr("No other types of changes will be committed at this time.");
2598
QMessageBox::warning(0, tr("Error"), errorStrings.join(" "));
2603
// Deleted features committed OK, remove the in-memory changes
2604
mDeletedFeatureIds.clear();
2605
deletedFeaturesOk = TRUE;
2612
bool QgsVectorLayer::rollBack()
2614
//Roll back changed features
2615
mChangedGeometries.clear(); // TODO: Does this leak memory?
2616
mChangedAttributes.clear();
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)
2624
mAddedFeatures.clear();
2626
// Roll back deleted features
2627
mDeletedFeatureIds.clear();
2634
int QgsVectorLayer::selectedFeatureCount()
2636
return mSelectedFeatureIds.size();
2640
std::vector<QgsFeature>* QgsVectorLayer::selectedFeatures()
2647
std::vector<QgsFeature>* features = new std::vector<QgsFeature>;
2649
if (mSelectedFeatureIds.size() == 0)
2655
// we don't need to cache features ... it just adds unnecessary time
2656
// as we don't need to pull *everything* from disk
2658
// Go through each selected feature ID and determine
2659
// its current geometry and attributes
2661
for (std::set<int>::iterator it = mSelectedFeatureIds.begin(); it != mSelectedFeatureIds.end(); ++it)
2663
QgsFeature* initialFeature;
2665
// Pull the original version of the feature from disk or memory
2668
// Check this selected item against the uncommitted added features
2669
bool selectionIsAddedFeature = FALSE;
2671
for (std::vector<QgsFeature*>::iterator iter = mAddedFeatures.begin();
2672
iter != mAddedFeatures.end();
2675
if ( (*it) == (*iter)->featureId() )
2678
std::cout << "QgsVectorLayer::selectedFeatures: found an added geometry: "
2681
initialFeature = new QgsFeature(**iter);
2682
selectionIsAddedFeature = TRUE;
2686
if (!selectionIsAddedFeature)
2688
// pull committed version from disk
2689
initialFeature = new QgsFeature(*it);
2691
int row = 0; //TODO: Get rid of this, but getFeatureAttributes()
2692
// needs it for some reason
2693
dataProvider->getFeatureAttributes(*it, row, initialFeature);
2695
if ( mChangedGeometries.find(*it) == mChangedGeometries.end() )
2697
// also pull committed geometry from disk as we will
2698
// not need to overwrite it later
2700
if (dataProvider->capabilities() & QgsVectorDataProvider::SelectGeometryAtId)
2702
dataProvider->getFeatureGeometry(*it, initialFeature);
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."));
2713
// Transform the feature to the "current" in-memory version
2714
QgsFeature finalFeature =
2715
QgsFeature(*initialFeature,
2717
mChangedGeometries);
2719
delete initialFeature;
2721
features->push_back(finalFeature);
2723
} // for each selected
2728
bool QgsVectorLayer::addFeatures(std::vector<QgsFeature*>* features, bool makeSelected)
2732
if(!(dataProvider->capabilities() & QgsVectorDataProvider::AddFeatures))
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."));
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."));
2749
mSelectedFeatureIds.clear();
2752
for (std::vector<QgsFeature*>::iterator iter = features->begin();
2753
iter != features->end();
2756
// TODO: Tidy these next two lines up
2758
// QgsFeature f = (*iter);
2759
// addFeature(&f, FALSE);
2765
mSelectedFeatureIds.insert((*iter)->featureId());
2774
QString QgsVectorLayer::layerTypeIconPath()
2776
QString myThemePath = QgsApplication::themePath();
2777
switch(vectorType())
2780
return (myThemePath+"/mIconPointLayer.png");
2783
return (myThemePath+"/mIconLineLayer.png");
2786
return (myThemePath+"/mIconPolygonLayer.png");
2788
return (myThemePath+"/mIconLayer.png");
2792
void QgsVectorLayer::refreshLegend()
2794
if(mLegend && m_renderer)
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)
2800
std::list<int> classfieldlist = m_renderer->classificationAttributes();
2801
for(std::list<int>::iterator it = classfieldlist.begin(); it!=classfieldlist.end(); ++it)
2803
const QgsField theField = (dataProvider->fields())[*it];
2804
QString classfieldname = theField.name();
2805
itemList.push_front(std::make_pair(classfieldname, QPixmap()));
2808
mLegend->changeSymbologySettings(getLayerID(), &itemList);
2812
bool QgsVectorLayer::copySymbologySettings(const QgsMapLayer& other)
2814
const QgsVectorLayer* vl = dynamic_cast<const QgsVectorLayer*>(&other);
2816
if(this == vl)//exit if both vectorlayer are the same
2827
QgsRenderer* r = vl->m_renderer;
2830
m_renderer = r->clone();
2839
bool QgsVectorLayer::isSymbologyCompatible(const QgsMapLayer& other) const
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
2844
const QgsVectorLayer* otherVectorLayer = dynamic_cast<const QgsVectorLayer*>(&other);
2845
if(otherVectorLayer)
2848
if(otherVectorLayer->vectorType() != vectorType())
2853
const std::vector<QgsField> fieldsThis = dataProvider->fields();
2854
const std::vector<QgsField> fieldsOther = otherVectorLayer ->dataProvider->fields();
2856
if(fieldsThis.size() != fieldsOther.size())
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)
2866
numericalThis.insert(*it);
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)
2873
numericalOther.insert(*it);
2876
std::set<QString>::const_iterator thisiter;
2877
std::set<QString>::const_iterator otheriter;
2878
int fieldsThisSize = fieldsThis.size();
2880
for(register int i = 0; i < fieldsThisSize; ++i)
2882
if(fieldsThis[i].name() != fieldsOther[i].name())//field names need to be the same
2886
thisiter = numericalThis.find(fieldsThis[i].name());
2887
otheriter = numericalOther.find(fieldsOther[i].name());
2888
if(thisiter == numericalThis.end())
2890
if(otheriter != numericalOther.end())
2897
if(otheriter == numericalOther.end())
2903
return true; //layers are symbology compatible if the code reaches this point
2908
bool QgsVectorLayer::snapPoint(QgsPoint& point, double tolerance)
2910
if(tolerance<=0||!dataProvider)
2914
double mindist=tolerance*tolerance;//current minimum distance
2915
double mindistx=point.x();
2916
double mindisty=point.y();
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)
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);
2928
if(projectionsEnabled() && coordinateTransform())
2930
//inverse tramsform point to layer SRS
2933
point = coordinateTransform()->transform(point, QgsCoordinateTransform::INVERSE);
2935
catch(QgsCsException &cse)
2941
//go to through the features reported by the spatial filter of the provider
2942
while ((fet = dataProvider->getNextFeature(false)))
2944
if(mChangedGeometries.find(fet->featureId()) != mChangedGeometries.end())//if geometry has been changed, use the new geometry
2946
vertexFeature = mChangedGeometries[fet->featureId()].closestVertex(point, vindex, rb1, rb2, minsquaredist);
2950
vertexFeature=fet->geometry()->closestVertex(point, vindex, rb1, rb2, minsquaredist);
2952
if(minsquaredist<mindist)
2954
mindistx=vertexFeature.x();
2955
mindisty=vertexFeature.y();
2956
mindist=minsquaredist;
2960
//also go through the not commited features
2961
for(std::vector<QgsFeature*>::iterator iter=mAddedFeatures.begin();iter!=mAddedFeatures.end();++iter)
2963
if(mChangedGeometries.find((*iter)->featureId()) != mChangedGeometries.end())//use the changed geometry
2965
vertexFeature = mChangedGeometries[(*iter)->featureId()].closestVertex(point, vindex, rb1, rb2, minsquaredist);
2969
vertexFeature=(*iter)->geometry()->closestVertex(point, vindex, rb1, rb2, minsquaredist);
2971
if(minsquaredist<mindist)
2973
mindistx=vertexFeature.x();
2974
mindisty=vertexFeature.y();
2975
mindist=minsquaredist;
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)
2982
vertexFeature = iter->second.closestVertex(point, vindex, rb1, rb2, minsquaredist);
2983
if(minsquaredist<mindist)
2985
mindistx=vertexFeature.x();
2986
mindisty=vertexFeature.y();
2987
mindist=minsquaredist;
2991
point.setX(mindistx);
2992
point.setY(mindisty);
2994
if(projectionsEnabled())
2996
//transform point to canvas SRC
2999
point = coordinateTransform()->transform(point);
3001
catch(QgsCsException &cse)
3011
bool QgsVectorLayer::snapVertexWithContext(QgsPoint& point, QgsGeometryVertexIndex& atVertex, int& beforeVertexIndex, int& afterVertexIndex,\
3012
int& snappedFeatureId, QgsGeometry& snappedGeometry, double tolerance)
3014
bool vertexFound = false; //flag to check if a meaningful result can be returned
3015
QgsGeometryVertexIndex atVertexTemp;
3016
int beforeVertexIndexTemp, afterVertexIndexTemp;
3018
QgsPoint origPoint = point;
3021
if ( tolerance<=0 || !dataProvider)
3026
QgsFeature* feature;
3027
QgsPoint minDistSegPoint; // the closest point
3028
double testSqrDist; // the squared distance between 'point' and 'snappedFeature'
3030
double minSqrDist = tolerance*tolerance; //current minimum distance
3032
QgsRect selectrect(origPoint.x()-tolerance, origPoint.y()-tolerance, origPoint.x()+tolerance, origPoint.y()+tolerance);
3033
dataProvider->reset();
3034
dataProvider->select(&selectrect);
3036
if(projectionsEnabled() && coordinateTransform())
3038
//inverse tramsform points to layer SRS
3041
origPoint = coordinateTransform()->transform(point, QgsCoordinateTransform::INVERSE);
3043
catch(QgsCsException &cse)
3049
// Go through the committed features
3050
while ((feature = dataProvider->getNextFeature(false)))
3052
if(mChangedGeometries.find(feature->featureId()) != mChangedGeometries.end())
3054
// ignore for this loop, let the loop below over mChangedGeometries
3055
// detect the changed geometry instead
3058
// // substitute the modified geometry for the committed version
3059
// feature->setGeometry(mChangedGeometries[feature->featureId()]);
3062
minDistSegPoint = feature->geometry()->closestVertex(origPoint, atVertexTemp, beforeVertexIndexTemp, afterVertexIndexTemp, testSqrDist);
3064
(testSqrDist < minSqrDist) ||
3066
// this test will "choose" the polygon that the origPoint is in:
3067
(testSqrDist == minSqrDist) &&
3068
(feature->geometry()->contains(&origPoint))
3072
point = minDistSegPoint;
3073
minSqrDist = testSqrDist;
3075
atVertex = atVertexTemp;
3076
beforeVertexIndex = beforeVertexIndexTemp;
3077
afterVertexIndex = afterVertexIndexTemp;
3078
snappedFeatureId = feature->featureId();
3079
snappedGeometry = *(feature->geometry());
3085
// Also go through the new features
3086
for (std::vector<QgsFeature*>::iterator iter = mAddedFeatures.begin(); iter != mAddedFeatures.end(); ++iter)
3088
if(mChangedGeometries.find((*iter)->featureId()) != mChangedGeometries.end())
3090
// ignore for this loop, let the loop below over mChangedGeometries
3091
// detect the changed geometry instead
3093
// //use the modified geometry
3094
// minDistSegPoint = mChangedGeometries[(*iter)->featureId()].closestVertex(origPoint, atVertexTemp, beforeVertexIndexTemp, afterVertexIndexTemp, testSqrDist);
3098
minDistSegPoint = (*iter)->geometry()->closestVertex(origPoint, atVertexTemp, beforeVertexIndexTemp, afterVertexIndexTemp, testSqrDist);
3101
(testSqrDist < minSqrDist) ||
3103
// this test will "choose" the polygon that the origPoint is in:
3104
(testSqrDist == minSqrDist) &&
3105
((*iter)->geometry()->contains(&origPoint))
3109
point = minDistSegPoint;
3110
minSqrDist = testSqrDist;
3112
atVertex = atVertexTemp;
3113
beforeVertexIndex = beforeVertexIndexTemp;
3114
afterVertexIndex = afterVertexIndexTemp;
3115
snappedFeatureId = (*iter)->featureId();
3116
snappedGeometry = *((*iter)->geometry());
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)
3124
minDistSegPoint = it->second.closestVertex(origPoint, atVertexTemp, beforeVertexIndexTemp, afterVertexIndexTemp, testSqrDist);
3126
(testSqrDist < minSqrDist) ||
3128
// this test will "choose" the polygon that the origPoint is in:
3129
(testSqrDist == minSqrDist) &&
3130
(it->second.contains(&origPoint))
3134
point = minDistSegPoint;
3135
minSqrDist = testSqrDist;
3136
atVertex = atVertexTemp;
3137
beforeVertexIndex = beforeVertexIndexTemp;
3138
afterVertexIndex = afterVertexIndexTemp;
3139
snappedFeatureId = it->first;
3140
snappedGeometry = it->second;
3147
beforeVertexIndex = -1;
3148
afterVertexIndex = -1;
3152
if(projectionsEnabled())
3154
//transform point to canvas SRC
3157
point = coordinateTransform()->transform(point);
3159
catch(QgsCsException &cse)
3168
bool QgsVectorLayer::snapSegmentWithContext(QgsPoint& point, QgsGeometryVertexIndex& beforeVertex, int& snappedFeatureId,\
3169
QgsGeometry& snappedGeometry, double tolerance)
3171
bool segmentFound = false; //flag to check if a reasonable result can be returned
3172
QgsGeometryVertexIndex beforeVertexTemp;
3174
QgsPoint origPoint = point;
3177
if ( tolerance<=0 || !dataProvider)
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
3187
QgsRect selectrect(point.x()-tolerance, point.y()-tolerance, point.x()+tolerance, point.y()+tolerance);
3188
dataProvider->reset();
3189
dataProvider->select(&selectrect);
3191
if(projectionsEnabled() && coordinateTransform())
3193
//inverse tramsform points to layer SRS
3196
origPoint = coordinateTransform()->transform(point, QgsCoordinateTransform::INVERSE);
3198
catch(QgsCsException &cse)
3204
// Go through the committed features
3205
while ((feature = dataProvider->getNextFeature(false)))
3207
if (mChangedGeometries.find(feature->featureId()) != mChangedGeometries.end())
3209
// ignore for this loop, let the loop below over mChangedGeometries
3210
// detect the changed geometry instead
3213
// // substitute the modified geometry for the committed version
3214
// feature->setGeometry( mChangedGeometries[ feature->featureId() ] );
3217
minDistSegPoint = feature->geometry()->closestSegmentWithContext(origPoint, beforeVertexTemp, testSqrDist);
3220
(testSqrDist < minSqrDist) ||
3222
// this test will "choose" the polygon that the origPoint is in:
3223
(testSqrDist == minSqrDist) &&
3224
(feature->geometry()->contains(&origPoint))
3228
point = minDistSegPoint;
3229
minSqrDist = testSqrDist;
3231
beforeVertex = beforeVertexTemp;
3232
snappedFeatureId = feature->featureId();
3233
snappedGeometry = *(feature->geometry());
3234
segmentFound = true;
3239
// Also go through the new features
3240
for (std::vector<QgsFeature*>::iterator iter = mAddedFeatures.begin(); iter != mAddedFeatures.end(); ++iter)
3242
if(mChangedGeometries.find((*iter)->featureId()) != mChangedGeometries.end())
3244
// ignore for this loop, let the loop below over mChangedGeometries
3245
// detect the changed geometry instead
3248
// //use the modified geometry
3249
// minDistSegPoint = mChangedGeometries[(*iter)->featureId()].closestSegmentWithContext(origPoint, beforeVertexTemp, testSqrDist);
3253
minDistSegPoint = (*iter)->geometry()->closestSegmentWithContext(origPoint, beforeVertexTemp, testSqrDist);
3257
(testSqrDist < minSqrDist) ||
3259
// this test will "choose" the polygon that the origPoint is in:
3260
(testSqrDist == minSqrDist) &&
3261
((*iter)->geometry()->contains(&origPoint))
3265
point = minDistSegPoint;
3266
minSqrDist = testSqrDist;
3268
beforeVertex = beforeVertexTemp;
3269
snappedFeatureId = (*iter)->featureId();
3270
snappedGeometry = *((*iter)->geometry());
3271
segmentFound = true;
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)
3278
minDistSegPoint = it->second.closestSegmentWithContext(origPoint, beforeVertexTemp, testSqrDist);
3280
(testSqrDist < minSqrDist) ||
3282
// this test will "choose" the polygon that the origPoint is in:
3283
(testSqrDist == minSqrDist) &&
3284
(it->second.contains(&origPoint))
3288
point = minDistSegPoint;
3289
minSqrDist = testSqrDist;
3290
beforeVertex = beforeVertexTemp;
3291
snappedFeatureId = it->first;
3292
snappedGeometry = it->second;
3293
segmentFound = true;
3297
return segmentFound;
3301
void QgsVectorLayer::drawFeature(QPainter* p,
3303
QgsMapToPixel * theMapToPixelTransform,
3305
double markerScaleFactor,
3306
bool projectionsEnabledFlag,
3307
bool drawingToEditingCanvas)
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
3314
#if defined(Q_WS_X11)
3315
bool needToTrim = false;
3318
unsigned char* feature = fet->getGeometry();
3320
unsigned int wkbType;
3321
memcpy(&wkbType, (feature+1), sizeof(wkbType));
3324
//std::cout <<"Entering drawFeature()" << std::endl;
3329
case QGis::WKBPoint:
3330
case QGis::WKBPoint25D:
3332
double x = *((double *) (feature + 5));
3333
double y = *((double *) (feature + 5 + sizeof(double)));
3336
// std::cout <<"...WKBPoint (" << x << ", " << y << ")" <<std::endl;
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));
3344
p->scale(markerScaleFactor,markerScaleFactor);
3345
p->drawPixmap(pt, *marker);
3350
case QGis::WKBMultiPoint:
3351
case QGis::WKBMultiPoint25D:
3353
unsigned char *ptr = feature + 5;
3354
unsigned int nPoints = *((int*)ptr);
3358
p->scale(markerScaleFactor, markerScaleFactor);
3360
for (register unsigned int i = 0; i < nPoints; ++i)
3363
double x = *((double *) ptr);
3364
ptr += sizeof(double);
3365
double y = *((double *) ptr);
3366
ptr += sizeof(double);
3368
if (wkbType == QGis::WKBMultiPoint25D) // ignore Z value
3369
ptr += sizeof(double);
3372
std::cout <<"...WKBMultiPoint (" << x << ", " << y << ")" <<std::endl;
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));
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)
3386
p->drawPixmap(pt, *marker);
3392
case QGis::WKBLineString:
3393
case QGis::WKBLineString25D:
3395
drawLineString(feature,
3397
theMapToPixelTransform,
3398
projectionsEnabledFlag,
3399
drawingToEditingCanvas);
3402
case QGis::WKBMultiLineString:
3403
case QGis::WKBMultiLineString25D:
3405
unsigned char* ptr = feature + 5;
3406
unsigned int numLineStrings = *((int*)ptr);
3409
for (register unsigned int jdx = 0; jdx < numLineStrings; jdx++)
3411
ptr = drawLineString(ptr,
3413
theMapToPixelTransform,
3414
projectionsEnabledFlag,
3415
drawingToEditingCanvas);
3419
case QGis::WKBPolygon:
3420
case QGis::WKBPolygon25D:
3422
drawPolygon(feature,
3424
theMapToPixelTransform,
3425
projectionsEnabledFlag,
3426
drawingToEditingCanvas);
3429
case QGis::WKBMultiPolygon:
3430
case QGis::WKBMultiPolygon25D:
3432
unsigned char *ptr = feature + 5;
3433
unsigned int numPolygons = *((int*)ptr);
3435
for (register unsigned int kdx = 0; kdx < numPolygons; kdx++)
3436
ptr = drawPolygon(ptr,
3438
theMapToPixelTransform,
3439
projectionsEnabledFlag,
3440
drawingToEditingCanvas);
3445
std::cout << "UNKNOWN WKBTYPE ENCOUNTERED\n";
3453
void QgsVectorLayer::saveAsShapefile()
3455
// call the dataproviders saveAsShapefile method
3456
dataProvider->saveAsShapefile();
3459
void QgsVectorLayer::setCoordinateSystem()
3461
delete mCoordinateTransform;
3462
mCoordinateTransform=new QgsCoordinateTransform();
3463
//slot is defined inthe maplayer superclass
3464
connect(mCoordinateTransform, SIGNAL(invalidTransformInput()), this, SLOT(invalidTransformInput()));
3466
QgsDebugMsg("QgsVectorLayer::setCoordinateSystem ------------------------------------------------start");
3467
QgsDebugMsg("QgsVectorLayer::setCoordinateSystem ----- Computing Coordinate System");
3469
// Get the layers project info and set up the QgsCoordinateTransform
3472
int srid = getProjectionSrid();
3476
QString mySourceWKT(getProjectionWKT());
3477
if (mySourceWKT.isNull())
3479
mySourceWKT=QString("");
3481
QgsDebugMsg("QgsVectorLayer::setCoordinateSystem --- using wkt " + mySourceWKT);
3482
mCoordinateTransform->sourceSRS().createFromWkt(mySourceWKT);
3483
//mCoordinateTransform->sourceSRS()->createFromWkt(getProjectionWKT());
3487
QgsDebugMsg("QgsVectorLayer::setCoordinateSystem --- using srid " + QString::number(srid));
3488
mCoordinateTransform->sourceSRS().createFromSrid(srid);
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())
3497
mCoordinateTransform->sourceSRS().validate();
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();
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
3508
QgsDebugMsg("Layer registry has " + QString::number(QgsMapLayerRegistry::instance()->count()) + " layers ");
3509
if (QgsMapLayerRegistry::instance()->count() ==0)
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());
3518
QgsProject::instance()->writeEntry("SpatialRefSys","/ProjectSRSID",mySrsId);
3523
mCoordinateTransform->destSRS().createFromSrsId(
3524
QgsProject::instance()->readNumEntry("SpatialRefSys","/ProjectSRSID",0));
3526
if (!mCoordinateTransform->destSRS().isValid())
3528
mCoordinateTransform->destSRS().validate();
3532
//initialise the transform - you should do this any time one of the SRS's changes
3534
mCoordinateTransform->initialise();
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)
3544
bool returnvalue=true;
3548
if(dataProvider->capabilities()&QgsVectorDataProvider::DeleteAttributes)
3550
//delete attributes in all not commited features
3551
for(std::vector<QgsFeature*>::iterator iter=mAddedFeatures.begin();iter!=mAddedFeatures.end();++iter)
3553
for(std::set<QString>::const_iterator it=deleted.begin();it!=deleted.end();++it)
3555
(*iter)->deleteAttribute(*it);
3558
//and then in the provider
3559
if(!dataProvider->deleteAttributes(deleted))
3565
if(dataProvider->capabilities()&QgsVectorDataProvider::AddAttributes)
3567
//add attributes in all not commited features
3568
for(std::vector<QgsFeature*>::iterator iter=mAddedFeatures.begin();iter!=mAddedFeatures.end();++iter)
3570
for(std::map<QString,QString>::const_iterator it=added.begin();it!=added.end();++it)
3572
(*iter)->addAttribute(it->first);
3575
//and then in the provider
3576
if(!dataProvider->addAttributes(added))
3582
if(dataProvider->capabilities()&QgsVectorDataProvider::ChangeAttributeValues)
3584
//change values of the not commited features
3585
for(std::vector<QgsFeature*>::iterator iter=mAddedFeatures.begin();iter!=mAddedFeatures.end();++iter)
3587
std::map<int,std::map<QString,QString> >::iterator it=changed.find((*iter)->featureId());
3588
if(it!=changed.end())
3590
for(std::map<QString,QString>::const_iterator iterat=it->second.begin();iterat!=it->second.end();++iterat)
3592
(*iter)->changeAttributeValue(iterat->first,iterat->second);
3598
//and then those of the commited ones
3599
if(!dataProvider->changeAttributeValues(changed))
3612
// Convenience function to transform the given point
3613
inline void QgsVectorLayer::transformPoint(double& x,
3616
bool projectionsEnabledFlag)
3618
// transform the point
3619
if (projectionsEnabledFlag)
3622
mCoordinateTransform->transformInPlace(x, y, z);
3625
// transform from projected coordinate system to pixel
3626
// position on map canvas
3627
mtp->transformInPlace(x, y);
3630
inline void QgsVectorLayer::transformPoints(
3631
std::vector<double>& x, std::vector<double>& y, std::vector<double>& z,
3632
QgsMapToPixel* mtp, bool projectionsEnabledFlag)
3634
// transform the point
3635
if (projectionsEnabledFlag)
3636
mCoordinateTransform->transformInPlace(x, y, z);
3638
// transform from projected coordinate system to pixel
3639
// position on map canvas
3640
mtp->transformInPlace(x, y);
3643
unsigned int QgsVectorLayer::getTransparency()
3645
return transparencyLevelInt;
3648
//should be between 0 and 255
3649
void QgsVectorLayer::setTransparency(unsigned int theInt)
3651
transparencyLevelInt=theInt;
3652
} // QgsRasterLayer::setTransparency(unsigned int theInt)