Quantum GIS API Documentation  1.8
src/core/qgsvectorlayer.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                                qgsvectorlayer.cpp
00003                               --------------------
00004           begin                : Oct 29, 2003
00005           copyright            : (C) 2003 by Gary E.Sherman
00006           email                : sherman at mrcc.com
00007 
00008   This class implements a generic means to display vector layers. The features
00009   and attributes are read from the data store using a "data provider" plugin.
00010   QgsVectorLayer can be used with any data store for which an appropriate
00011   plugin is available.
00012 
00013 ***************************************************************************/
00014 
00015 /***************************************************************************
00016  *                                                                         *
00017  *   This program is free software; you can redistribute it and/or modify  *
00018  *   it under the terms of the GNU General Public License as published by  *
00019  *   the Free Software Foundation; either version 2 of the License, or     *
00020  *   (at your option) any later version.                                   *
00021  *                                                                         *
00022  ***************************************************************************/
00023 
00024 #include <limits>
00025 
00026 #include <QImage>
00027 #include <QPainter>
00028 #include <QPainterPath>
00029 #include <QPolygonF>
00030 #include <QSettings>
00031 #include <QString>
00032 #include <QDomNode>
00033 
00034 #include "qgsvectorlayer.h"
00035 
00036 // renderers
00037 #include "qgscontinuouscolorrenderer.h"
00038 #include "qgsgraduatedsymbolrenderer.h"
00039 #include "qgsrenderer.h"
00040 #include "qgssinglesymbolrenderer.h"
00041 #include "qgsuniquevaluerenderer.h"
00042 
00043 #include "qgsattributeaction.h"
00044 
00045 #include "qgis.h" //for globals
00046 #include "qgsapplication.h"
00047 #include "qgscoordinatetransform.h"
00048 #include "qgsfeature.h"
00049 #include "qgsfield.h"
00050 #include "qgsgeometry.h"
00051 #include "qgslabel.h"
00052 #include "qgslogger.h"
00053 #include "qgsmessagelog.h"
00054 #include "qgsmaptopixel.h"
00055 #include "qgspoint.h"
00056 #include "qgsproviderregistry.h"
00057 #include "qgsrectangle.h"
00058 #include "qgsrendercontext.h"
00059 #include "qgscoordinatereferencesystem.h"
00060 #include "qgsvectordataprovider.h"
00061 #include "qgsvectorlayerjoinbuffer.h"
00062 #include "qgsvectorlayerundocommand.h"
00063 #include "qgsvectoroverlay.h"
00064 #include "qgsmaplayerregistry.h"
00065 #include "qgsclipper.h"
00066 #include "qgsproject.h"
00067 
00068 #include "qgsrendererv2.h"
00069 #include "qgssymbolv2.h"
00070 #include "qgssymbollayerv2.h"
00071 #include "qgssinglesymbolrendererv2.h"
00072 #include "qgsdiagramrendererv2.h"
00073 
00074 #ifdef TESTPROVIDERLIB
00075 #include <dlfcn.h>
00076 #endif
00077 
00078 
00079 // typedef for the QgsDataProvider class factory
00080 typedef QgsDataProvider * create_it( const QString* uri );
00081 
00082 
00083 
00084 QgsVectorLayer::QgsVectorLayer( QString vectorLayerPath,
00085                                 QString baseName,
00086                                 QString providerKey,
00087                                 bool loadDefaultStyleFlag )
00088     : QgsMapLayer( VectorLayer, baseName, vectorLayerPath )
00089     , mUpdateThreshold( 0 )     // XXX better default value?
00090     , mDataProvider( NULL )
00091     , mProviderKey( providerKey )
00092     , mEditable( false )
00093     , mReadOnly( false )
00094     , mModified( false )
00095     , mMaxUpdatedIndex( -1 )
00096     , mActiveCommand( NULL )
00097     , mRenderer( 0 )
00098     , mRendererV2( NULL )
00099     , mUsingRendererV2( false )
00100     , mLabel( 0 )
00101     , mLabelOn( false )
00102     , mVertexMarkerOnlyForSelection( false )
00103     , mFetching( false )
00104     , mJoinBuffer( 0 )
00105     , mDiagramRenderer( 0 )
00106     , mDiagramLayerSettings( 0 )
00107 {
00108   mActions = new QgsAttributeAction( this );
00109 
00110   // if we're given a provider type, try to create and bind one to this layer
00111   if ( ! mProviderKey.isEmpty() )
00112   {
00113     setDataProvider( mProviderKey );
00114   }
00115   if ( mValid )
00116   {
00117     // Always set crs
00118     setCoordinateSystem();
00119 
00120     QSettings settings;
00121     //Changed to default to true as of QGIS 1.7
00122     //TODO: remove hack when http://hub.qgis.org/issues/5170 is fixed
00123 #ifdef ANDROID
00124     bool use_symbology_ng_default = false;
00125 #else
00126     bool use_symbology_ng_default = true;
00127 #endif
00128     if ( settings.value( "/qgis/use_symbology_ng", use_symbology_ng_default ).toBool() && hasGeometryType() )
00129     {
00130       // using symbology-ng!
00131       setUsingRendererV2( true );
00132     }
00133 
00134     // check if there is a default style / propertysheet defined
00135     // for this layer and if so apply it
00136     bool defaultLoadedFlag = false;
00137     if ( loadDefaultStyleFlag )
00138     {
00139       loadDefaultStyle( defaultLoadedFlag );
00140     }
00141 
00142     // if the default style failed to load or was disabled use some very basic defaults
00143     if ( !defaultLoadedFlag && hasGeometryType() )
00144     {
00145       // add single symbol renderer
00146       if ( mUsingRendererV2 )
00147       {
00148         setRendererV2( QgsFeatureRendererV2::defaultRenderer( geometryType() ) );
00149       }
00150       else
00151       {
00152         QgsSingleSymbolRenderer *renderer = new QgsSingleSymbolRenderer( geometryType() );
00153         setRenderer( renderer );
00154       }
00155     }
00156 
00157     mJoinBuffer = new QgsVectorLayerJoinBuffer();
00158 
00159     connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( checkJoinLayerRemove( QString ) ) );
00160     updateFieldMap();
00161 
00162     // Get the update threshold from user settings. We
00163     // do this only on construction to avoid the penality of
00164     // fetching this each time the layer is drawn. If the user
00165     // changes the threshold from the preferences dialog, it will
00166     // have no effect on existing layers
00167     // TODO: load this setting somewhere else [MD]
00168     //QSettings settings;
00169     //mUpdateThreshold = settings.readNumEntry("Map/updateThreshold", 1000);
00170   }
00171 } // QgsVectorLayer ctor
00172 
00173 
00174 
00175 QgsVectorLayer::~QgsVectorLayer()
00176 {
00177   QgsDebugMsg( "entered." );
00178 
00179   emit layerDeleted();
00180 
00181   mValid = false;
00182 
00183   delete mRenderer;
00184   delete mDataProvider;
00185   delete mJoinBuffer;
00186   delete mLabel;
00187   delete mDiagramLayerSettings;
00188 
00189   // Destroy any cached geometries and clear the references to them
00190   deleteCachedGeometries();
00191 
00192   delete mActions;
00193 
00194   //delete remaining overlays
00195 
00196   QList<QgsVectorOverlay*>::iterator overlayIt = mOverlays.begin();
00197   for ( ; overlayIt != mOverlays.end(); ++overlayIt )
00198   {
00199     delete *overlayIt;
00200   }
00201 }
00202 
00203 QString QgsVectorLayer::storageType() const
00204 {
00205   if ( mDataProvider )
00206   {
00207     return mDataProvider->storageType();
00208   }
00209   return 0;
00210 }
00211 
00212 
00213 QString QgsVectorLayer::capabilitiesString() const
00214 {
00215   if ( mDataProvider )
00216   {
00217     return mDataProvider->capabilitiesString();
00218   }
00219   return 0;
00220 }
00221 
00222 QString QgsVectorLayer::dataComment() const
00223 {
00224   if ( mDataProvider )
00225   {
00226     return mDataProvider->dataComment();
00227   }
00228   return QString();
00229 }
00230 
00231 
00232 QString QgsVectorLayer::providerType() const
00233 {
00234   return mProviderKey;
00235 }
00236 
00240 void QgsVectorLayer::setDisplayField( QString fldName )
00241 {
00242   if ( !hasGeometryType() )
00243     return;
00244 
00245   // If fldName is provided, use it as the display field, otherwise
00246   // determine the field index for the feature column of the identify
00247   // dialog. We look for fields containing "name" first and second for
00248   // fields containing "id". If neither are found, the first field
00249   // is used as the node.
00250   QString idxName = "";
00251   QString idxId = "";
00252 
00253   if ( !fldName.isEmpty() )
00254   {
00255     mDisplayField = fldName;
00256   }
00257   else
00258   {
00259     const QgsFieldMap &fields = pendingFields();
00260     int fieldsSize = fields.size();
00261 
00262     for ( QgsFieldMap::const_iterator it = fields.begin(); it != fields.end(); ++it )
00263     {
00264       QString fldName = it.value().name();
00265       QgsDebugMsg( "Checking field " + fldName + " of " + QString::number( fieldsSize ) + " total" );
00266 
00267       // Check the fields and keep the first one that matches.
00268       // We assume that the user has organized the data with the
00269       // more "interesting" field names first. As such, name should
00270       // be selected before oldname, othername, etc.
00271       if ( fldName.indexOf( "name", false ) > -1 )
00272       {
00273         if ( idxName.isEmpty() )
00274         {
00275           idxName = fldName;
00276         }
00277       }
00278       if ( fldName.indexOf( "descrip", false ) > -1 )
00279       {
00280         if ( idxName.isEmpty() )
00281         {
00282           idxName = fldName;
00283         }
00284       }
00285       if ( fldName.indexOf( "id", false ) > -1 )
00286       {
00287         if ( idxId.isEmpty() )
00288         {
00289           idxId = fldName;
00290         }
00291       }
00292     }
00293 
00294     //if there were no fields in the dbf just return - otherwise qgis segfaults!
00295     if ( fieldsSize == 0 )
00296       return;
00297 
00298     if ( idxName.length() > 0 )
00299     {
00300       mDisplayField = idxName;
00301     }
00302     else
00303     {
00304       if ( idxId.length() > 0 )
00305       {
00306         mDisplayField = idxId;
00307       }
00308       else
00309       {
00310         mDisplayField = fields[0].name();
00311       }
00312     }
00313 
00314   }
00315 }
00316 
00317 // NOTE this is a temporary method added by Tim to prevent label clipping
00318 // which was occurring when labeller was called in the main draw loop
00319 // This method will probably be removed again in the near future!
00320 void QgsVectorLayer::drawLabels( QgsRenderContext& rendererContext )
00321 {
00322   if ( !hasGeometryType() )
00323     return;
00324 
00325   QgsDebugMsg( "Starting draw of labels: " + id() );
00326 
00327   if (( mRenderer || mRendererV2 ) && mLabelOn &&
00328       ( !mLabel->scaleBasedVisibility() ||
00329         ( mLabel->minScale() <= rendererContext.rendererScale() &&
00330           rendererContext.rendererScale() <= mLabel->maxScale() ) ) )
00331   {
00332     QgsAttributeList attributes;
00333     if ( mRenderer )
00334     {
00335       attributes = mRenderer->classificationAttributes();
00336     }
00337     else if ( mRendererV2 )
00338     {
00339       foreach( QString attrName, mRendererV2->usedAttributes() )
00340       {
00341         int attrNum = fieldNameIndex( attrName );
00342         attributes.append( attrNum );
00343       }
00344       // make sure the renderer is ready for classification ("symbolForFeature")
00345       mRendererV2->startRender( rendererContext, this );
00346     }
00347 
00348     // Add fields required for labels
00349     mLabel->addRequiredFields( attributes );
00350 
00351     QgsDebugMsg( "Selecting features based on view extent" );
00352 
00353     int featureCount = 0;
00354 
00355     try
00356     {
00357       // select the records in the extent. The provider sets a spatial filter
00358       // and sets up the selection set for retrieval
00359       select( attributes, rendererContext.extent() );
00360 
00361       QgsFeature fet;
00362       while ( nextFeature( fet ) )
00363       {
00364         if (( mRenderer && mRenderer->willRenderFeature( &fet ) )
00365             || ( mRendererV2 && mRendererV2->willRenderFeature( fet ) ) )
00366         {
00367           bool sel = mSelectedFeatureIds.contains( fet.id() );
00368           mLabel->renderLabel( rendererContext, fet, sel, 0 );
00369         }
00370         featureCount++;
00371       }
00372     }
00373     catch ( QgsCsException &e )
00374     {
00375       Q_UNUSED( e );
00376       QgsDebugMsg( "Error projecting label locations" );
00377     }
00378 
00379     if ( mRendererV2 )
00380     {
00381       mRendererV2->stopRender( rendererContext );
00382     }
00383 
00384     QgsDebugMsg( QString( "Total features processed %1" ).arg( featureCount ) );
00385 
00386     // XXX Something in our draw event is triggering an additional draw event when resizing [TE 01/26/06]
00387     // XXX Calling this will begin processing the next draw event causing image havoc and recursion crashes.
00388     //qApp->processEvents();
00389 
00390   }
00391 }
00392 
00393 
00394 unsigned char *QgsVectorLayer::drawLineString( unsigned char *feature, QgsRenderContext &renderContext )
00395 {
00396   QPainter *p = renderContext.painter();
00397   unsigned char *ptr = feature + 5;
00398   unsigned int wkbType = *(( int* )( feature + 1 ) );
00399   unsigned int nPoints = *(( int* )ptr );
00400   ptr = feature + 9;
00401 
00402   bool hasZValue = ( wkbType == QGis::WKBLineString25D );
00403 
00404   std::vector<double> x( nPoints );
00405   std::vector<double> y( nPoints );
00406   std::vector<double> z( nPoints, 0.0 );
00407 
00408   // Extract the points from the WKB format into the x and y vectors.
00409   for ( register unsigned int i = 0; i < nPoints; ++i )
00410   {
00411     x[i] = *(( double * ) ptr );
00412     ptr += sizeof( double );
00413     y[i] = *(( double * ) ptr );
00414     ptr += sizeof( double );
00415 
00416     if ( hasZValue ) // ignore Z value
00417       ptr += sizeof( double );
00418   }
00419 
00420   // Transform the points into map coordinates (and reproject if
00421   // necessary)
00422 
00423   transformPoints( x, y, z, renderContext );
00424 
00425   // Work around a +/- 32768 limitation on coordinates
00426   // Look through the x and y coordinates and see if there are any
00427   // that need trimming. If one is found, there's no need to look at
00428   // the rest of them so end the loop at that point.
00429   for ( register unsigned int i = 0; i < nPoints; ++i )
00430   {
00431     if ( qAbs( x[i] ) > QgsClipper::MAX_X ||
00432          qAbs( y[i] ) > QgsClipper::MAX_Y )
00433     {
00434       QgsClipper::trimFeature( x, y, true ); // true = polyline
00435       nPoints = x.size(); // trimming may change nPoints.
00436       break;
00437     }
00438   }
00439 
00440   // set up QPolygonF class with transformed points
00441   QPolygonF pa( nPoints );
00442   for ( register unsigned int i = 0; i < nPoints; ++i )
00443   {
00444     pa[i].setX( x[i] );
00445     pa[i].setY( y[i] );
00446   }
00447 
00448   // The default pen gives bevelled joins between segements of the
00449   // polyline, which is good enough for the moment.
00450   //preserve a copy of the pen before we start fiddling with it
00451   QPen pen = p->pen(); // to be kept original
00452 
00453   //
00454   // experimental alpha transparency
00455   // 255 = opaque
00456   //
00457   QPen myTransparentPen = p->pen(); // store current pen
00458   QColor myColor = myTransparentPen.color();
00459   //only set transparency from layer level if renderer does not provide
00460   //transparency on class level
00461   if ( !mRenderer->usesTransparency() )
00462   {
00463     myColor.setAlpha( mTransparencyLevel );
00464   }
00465   myTransparentPen.setColor( myColor );
00466   p->setPen( myTransparentPen );
00467   p->drawPolyline( pa );
00468 
00469   // draw vertex markers if in editing mode, but only to the main canvas
00470   if ( mEditable && renderContext.drawEditingInformation() )
00471   {
00472 
00473     std::vector<double>::const_iterator xIt;
00474     std::vector<double>::const_iterator yIt;
00475     for ( xIt = x.begin(), yIt = y.begin(); xIt != x.end(); ++xIt, ++yIt )
00476     {
00477       drawVertexMarker( *xIt, *yIt, *p, mCurrentVertexMarkerType, mCurrentVertexMarkerSize );
00478     }
00479   }
00480 
00481   //restore the pen
00482   p->setPen( pen );
00483 
00484   return ptr;
00485 }
00486 
00487 unsigned char *QgsVectorLayer::drawPolygon( unsigned char *feature, QgsRenderContext &renderContext )
00488 {
00489   QPainter *p = renderContext.painter();
00490   typedef std::pair<std::vector<double>, std::vector<double> > ringType;
00491   typedef ringType* ringTypePtr;
00492   typedef std::vector<ringTypePtr> ringsType;
00493 
00494   // get number of rings in the polygon
00495   unsigned int numRings = *(( int* )( feature + 1 + sizeof( int ) ) );
00496 
00497   if ( numRings == 0 )  // sanity check for zero rings in polygon
00498     return feature + 9;
00499 
00500   unsigned int wkbType = *(( int* )( feature + 1 ) );
00501 
00502   bool hasZValue = ( wkbType == QGis::WKBPolygon25D );
00503 
00504   int total_points = 0;
00505 
00506   // A vector containing a pointer to a pair of double vectors.The
00507   // first vector in the pair contains the x coordinates, and the
00508   // second the y coordinates.
00509   ringsType rings;
00510 
00511   // Set pointer to the first ring
00512   unsigned char* ptr = feature + 1 + 2 * sizeof( int );
00513 
00514   for ( register unsigned int idx = 0; idx < numRings; idx++ )
00515   {
00516     unsigned int nPoints = *(( int* )ptr );
00517 
00518     ringTypePtr ring = new ringType( std::vector<double>( nPoints ), std::vector<double>( nPoints ) );
00519     ptr += 4;
00520 
00521     // create a dummy vector for the z coordinate
00522     std::vector<double> zVector( nPoints, 0.0 );
00523     // Extract the points from the WKB and store in a pair of
00524     // vectors.
00525     for ( register unsigned int jdx = 0; jdx < nPoints; jdx++ )
00526     {
00527       ring->first[jdx] = *(( double * ) ptr );
00528       ptr += sizeof( double );
00529       ring->second[jdx] = *(( double * ) ptr );
00530       ptr += sizeof( double );
00531 
00532       if ( hasZValue )
00533         ptr += sizeof( double );
00534     }
00535     // If ring has fewer than two points, what is it then?
00536     // Anyway, this check prevents a crash
00537     if ( nPoints < 1 )
00538     {
00539       QgsDebugMsg( "Ring has only " + QString::number( nPoints ) + " points! Skipping this ring." );
00540       continue;
00541     }
00542 
00543     transformPoints( ring->first, ring->second, zVector, renderContext );
00544 
00545     // Work around a +/- 32768 limitation on coordinates
00546     // Look through the x and y coordinates and see if there are any
00547     // that need trimming. If one is found, there's no need to look at
00548     // the rest of them so end the loop at that point.
00549     for ( register unsigned int i = 0; i < nPoints; ++i )
00550     {
00551       if ( qAbs( ring->first[i] ) > QgsClipper::MAX_X ||
00552            qAbs( ring->second[i] ) > QgsClipper::MAX_Y )
00553       {
00554         QgsClipper::trimFeature( ring->first, ring->second, false );
00555         break;
00556       }
00557     }
00558 
00559     // Don't bother keeping the ring if it has been trimmed out of
00560     // existence.
00561     if ( ring->first.size() == 0 )
00562       delete ring;
00563     else
00564     {
00565       rings.push_back( ring );
00566       total_points += ring->first.size();
00567     }
00568   }
00569 
00570   // Now we draw the polygons
00571 
00572   // use painter paths for drawing polygons with holes
00573   // when adding polygon to the path they invert the area
00574   // this means that adding inner rings to the path creates
00575   // holes in outer ring
00576   QPainterPath path; // OddEven fill rule by default
00577 
00578   // Only try to draw polygons if there is something to draw
00579   if ( total_points > 0 )
00580   {
00581     //preserve a copy of the brush and pen before we start fiddling with it
00582     QBrush brush = p->brush(); //to be kept as original
00583     QPen pen = p->pen(); // to be kept original
00584     //
00585     // experimental alpha transparency
00586     // 255 = opaque
00587     //
00588     QBrush myTransparentBrush = p->brush();
00589     QColor myColor = brush.color();
00590 
00591     //only set transparency from layer level if renderer does not provide
00592     //transparency on class level
00593     if ( !mRenderer->usesTransparency() )
00594     {
00595       myColor.setAlpha( mTransparencyLevel );
00596     }
00597     myTransparentBrush.setColor( myColor );
00598     QPen myTransparentPen = p->pen(); // store current pen
00599     myColor = myTransparentPen.color();
00600 
00601     //only set transparency from layer level if renderer does not provide
00602     //transparency on class level
00603     if ( !mRenderer->usesTransparency() )
00604     {
00605       myColor.setAlpha( mTransparencyLevel );
00606     }
00607     myTransparentPen.setColor( myColor );
00608 
00609     p->setBrush( myTransparentBrush );
00610     p->setPen( myTransparentPen );
00611 
00612     if ( numRings == 1 )
00613     {
00614       ringTypePtr r = rings[0];
00615       unsigned ringSize = r->first.size();
00616 
00617       QPolygonF pa( ringSize );
00618       for ( register unsigned int j = 0; j != ringSize; ++j )
00619       {
00620         pa[j].setX( r->first[j] );
00621         pa[j].setY( r->second[j] );
00622       }
00623       p->drawPolygon( pa );
00624 
00625       // draw vertex markers if in editing mode, but only to the main canvas
00626       if ( mEditable && renderContext.drawEditingInformation() )
00627       {
00628         for ( register unsigned int j = 0; j != ringSize; ++j )
00629         {
00630           drawVertexMarker( r->first[j], r->second[j], *p, mCurrentVertexMarkerType, mCurrentVertexMarkerSize );
00631         }
00632       }
00633 
00634       delete rings[0];
00635     }
00636     else
00637     {
00638       // Store size here and use it in the loop to avoid penalty of
00639       // multiple calls to size()
00640       int numRings = rings.size();
00641       for ( register int i = 0; i < numRings; ++i )
00642       {
00643         // Store the pointer in a variable with a short name so as to make
00644         // the following code easier to type and read.
00645         ringTypePtr r = rings[i];
00646         // only do this once to avoid penalty of additional calls
00647         unsigned ringSize = r->first.size();
00648 
00649         // Transfer points to the array of QPointF
00650         QPolygonF pa( ringSize );
00651         for ( register unsigned int j = 0; j != ringSize; ++j )
00652         {
00653           pa[j].setX( r->first[j] );
00654           pa[j].setY( r->second[j] );
00655         }
00656 
00657         path.addPolygon( pa );
00658 
00659         // Tidy up the pointed to pairs of vectors as we finish with them
00660         delete rings[i];
00661       }
00662 
00663 #if 0
00664       // A bit of code to aid in working out what values of
00665       // QgsClipper::minX, etc cause the X11 zoom bug.
00666       int largestX  = -std::numeric_limits<int>::max();
00667       int smallestX = std::numeric_limits<int>::max();
00668       int largestY  = -std::numeric_limits<int>::max();
00669       int smallestY = std::numeric_limits<int>::max();
00670 
00671       for ( int i = 0; i < pa.size(); ++i )
00672       {
00673         largestX  = qMax( largestX,  pa.point( i ).x() );
00674         smallestX = qMin( smallestX, pa.point( i ).x() );
00675         largestY  = qMax( largestY,  pa.point( i ).y() );
00676         smallestY = qMin( smallestY, pa.point( i ).y() );
00677       }
00678       QgsDebugMsg( QString( "Largest  X coordinate was %1" ).arg( largestX ) );
00679       QgsDebugMsg( QString( "Smallest X coordinate was %1" ).arg( smallestX ) );
00680       QgsDebugMsg( QString( "Largest  Y coordinate was %1" ).arg( largestY ) );
00681       QgsDebugMsg( QString( "Smallest Y coordinate was %1" ).arg( smallestY ) );
00682 #endif
00683 
00684       //
00685       // draw the polygon
00686       //
00687       p->drawPath( path );
00688 
00689       // draw vertex markers if in editing mode, but only to the main canvas
00690       if ( mEditable && renderContext.drawEditingInformation() )
00691       {
00692         for ( int i = 0; i < path.elementCount(); ++i )
00693         {
00694           const QPainterPath::Element & e = path.elementAt( i );
00695           drawVertexMarker( e.x, e.y, *p, mCurrentVertexMarkerType, mCurrentVertexMarkerSize );
00696         }
00697       }
00698     }
00699 
00700     //
00701     //restore brush and pen to original
00702     //
00703     p->setBrush( brush );
00704     p->setPen( pen );
00705 
00706   } // totalPoints > 0
00707 
00708   return ptr;
00709 }
00710 
00711 void QgsVectorLayer::drawRendererV2( QgsRenderContext& rendererContext, bool labeling )
00712 {
00713   if ( !hasGeometryType() )
00714     return;
00715 
00716   QSettings settings;
00717   bool vertexMarkerOnlyForSelection = settings.value( "/qgis/digitizing/marker_only_for_selected", false ).toBool();
00718 
00719   mRendererV2->startRender( rendererContext, this );
00720 
00721 #ifndef Q_WS_MAC
00722   int featureCount = 0;
00723 #endif //Q_WS_MAC
00724 
00725   QgsFeature fet;
00726   while ( nextFeature( fet ) )
00727   {
00728     try
00729     {
00730       if ( rendererContext.renderingStopped() )
00731       {
00732         break;
00733       }
00734 
00735 #ifndef Q_WS_MAC //MH: disable this on Mac for now to avoid problems with resizing
00736       if ( mUpdateThreshold > 0 && 0 == featureCount % mUpdateThreshold )
00737       {
00738         emit screenUpdateRequested();
00739         // emit drawingProgress( featureCount, totalFeatures );
00740         qApp->processEvents();
00741       }
00742       else if ( featureCount % 1000 == 0 )
00743       {
00744         // emit drawingProgress( featureCount, totalFeatures );
00745         qApp->processEvents();
00746       }
00747 #endif //Q_WS_MAC
00748 
00749       bool sel = mSelectedFeatureIds.contains( fet.id() );
00750       bool drawMarker = ( mEditable && ( !vertexMarkerOnlyForSelection || sel ) );
00751 
00752       // render feature
00753       bool rendered = mRendererV2->renderFeature( fet, rendererContext, -1, sel, drawMarker );
00754 
00755       if ( mEditable )
00756       {
00757         // Cache this for the use of (e.g.) modifying the feature's uncommitted geometry.
00758         mCachedGeometries[fet.id()] = *fet.geometry();
00759       }
00760 
00761       // labeling - register feature
00762       if ( rendered && rendererContext.labelingEngine() )
00763       {
00764         if ( labeling )
00765         {
00766           rendererContext.labelingEngine()->registerFeature( this, fet, rendererContext );
00767         }
00768         if ( mDiagramRenderer )
00769         {
00770           rendererContext.labelingEngine()->registerDiagramFeature( this, fet, rendererContext );
00771         }
00772       }
00773     }
00774     catch ( const QgsCsException &cse )
00775     {
00776       Q_UNUSED( cse );
00777       QgsDebugMsg( QString( "Failed to transform a point while drawing a feature of type '%1'. Ignoring this feature. %2" )
00778                    .arg( fet.typeName() ).arg( cse.what() ) );
00779     }
00780 #ifndef Q_WS_MAC
00781     ++featureCount;
00782 #endif //Q_WS_MAC
00783   }
00784 
00785   stopRendererV2( rendererContext, NULL );
00786 
00787 #ifndef Q_WS_MAC
00788   QgsDebugMsg( QString( "Total features processed %1" ).arg( featureCount ) );
00789 #endif
00790 }
00791 
00792 void QgsVectorLayer::drawRendererV2Levels( QgsRenderContext& rendererContext, bool labeling )
00793 {
00794   if ( !hasGeometryType() )
00795     return;
00796 
00797   QHash< QgsSymbolV2*, QList<QgsFeature> > features; // key = symbol, value = array of features
00798 
00799   QSettings settings;
00800   bool vertexMarkerOnlyForSelection = settings.value( "/qgis/digitizing/marker_only_for_selected", false ).toBool();
00801 
00802   // startRender must be called before symbolForFeature() calls to make sure renderer is ready
00803   mRendererV2->startRender( rendererContext, this );
00804 
00805   QgsSingleSymbolRendererV2* selRenderer = NULL;
00806   if ( !mSelectedFeatureIds.isEmpty() )
00807   {
00808     selRenderer = new QgsSingleSymbolRendererV2( QgsSymbolV2::defaultSymbol( geometryType() ) );
00809     selRenderer->symbol()->setColor( QgsRenderer::selectionColor() );
00810     selRenderer->setVertexMarkerAppearance( currentVertexMarkerType(), currentVertexMarkerSize() );
00811     selRenderer->startRender( rendererContext, this );
00812   }
00813 
00814   // 1. fetch features
00815   QgsFeature fet;
00816 #ifndef Q_WS_MAC
00817   int featureCount = 0;
00818 #endif //Q_WS_MAC
00819   while ( nextFeature( fet ) )
00820   {
00821     if ( rendererContext.renderingStopped() )
00822     {
00823       stopRendererV2( rendererContext, selRenderer );
00824       return;
00825     }
00826 #ifndef Q_WS_MAC
00827     if ( featureCount % 1000 == 0 )
00828     {
00829       qApp->processEvents();
00830     }
00831 #endif //Q_WS_MAC
00832     QgsSymbolV2* sym = mRendererV2->symbolForFeature( fet );
00833     if ( !sym )
00834     {
00835       continue;
00836     }
00837 
00838     if ( !features.contains( sym ) )
00839     {
00840       features.insert( sym, QList<QgsFeature>() );
00841     }
00842     features[sym].append( fet );
00843 
00844     if ( mEditable )
00845     {
00846       // Cache this for the use of (e.g.) modifying the feature's uncommitted geometry.
00847       mCachedGeometries[fet.id()] = *fet.geometry();
00848     }
00849 
00850     if ( sym && rendererContext.labelingEngine() )
00851     {
00852       if ( labeling )
00853       {
00854         rendererContext.labelingEngine()->registerFeature( this, fet, rendererContext );
00855       }
00856       if ( mDiagramRenderer )
00857       {
00858         rendererContext.labelingEngine()->registerDiagramFeature( this, fet, rendererContext );
00859       }
00860     }
00861 
00862 #ifndef Q_WS_MAC
00863     ++featureCount;
00864 #endif //Q_WS_MAC
00865   }
00866 
00867   // find out the order
00868   QgsSymbolV2LevelOrder levels;
00869   QgsSymbolV2List symbols = mRendererV2->symbols();
00870   for ( int i = 0; i < symbols.count(); i++ )
00871   {
00872     QgsSymbolV2* sym = symbols[i];
00873     for ( int j = 0; j < sym->symbolLayerCount(); j++ )
00874     {
00875       int level = sym->symbolLayer( j )->renderingPass();
00876       if ( level < 0 || level >= 1000 ) // ignore invalid levels
00877         continue;
00878       QgsSymbolV2LevelItem item( sym, j );
00879       while ( level >= levels.count() ) // append new empty levels
00880         levels.append( QgsSymbolV2Level() );
00881       levels[level].append( item );
00882     }
00883   }
00884 
00885   // 2. draw features in correct order
00886   for ( int l = 0; l < levels.count(); l++ )
00887   {
00888     QgsSymbolV2Level& level = levels[l];
00889     for ( int i = 0; i < level.count(); i++ )
00890     {
00891       QgsSymbolV2LevelItem& item = level[i];
00892       if ( !features.contains( item.symbol() ) )
00893       {
00894         QgsDebugMsg( "level item's symbol not found!" );
00895         continue;
00896       }
00897       int layer = item.layer();
00898       QList<QgsFeature>& lst = features[item.symbol()];
00899       QList<QgsFeature>::iterator fit;
00900 #ifndef Q_WS_MAC
00901       featureCount = 0;
00902 #endif //Q_WS_MAC
00903       for ( fit = lst.begin(); fit != lst.end(); ++fit )
00904       {
00905         if ( rendererContext.renderingStopped() )
00906         {
00907           stopRendererV2( rendererContext, selRenderer );
00908           return;
00909         }
00910 #ifndef Q_WS_MAC
00911         if ( featureCount % 1000 == 0 )
00912         {
00913           qApp->processEvents();
00914         }
00915 #endif //Q_WS_MAC
00916         bool sel = mSelectedFeatureIds.contains( fit->id() );
00917         // maybe vertex markers should be drawn only during the last pass...
00918         bool drawMarker = ( mEditable && ( !vertexMarkerOnlyForSelection || sel ) );
00919 
00920         try
00921         {
00922           mRendererV2->renderFeature( *fit, rendererContext, layer, sel, drawMarker );
00923         }
00924         catch ( const QgsCsException &cse )
00925         {
00926           Q_UNUSED( cse );
00927           QgsDebugMsg( QString( "Failed to transform a point while drawing a feature of type '%1'. Ignoring this feature. %2" )
00928                        .arg( fet.typeName() ).arg( cse.what() ) );
00929         }
00930 #ifndef Q_WS_MAC
00931         ++featureCount;
00932 #endif //Q_WS_MAC
00933       }
00934     }
00935   }
00936 
00937   stopRendererV2( rendererContext, selRenderer );
00938 }
00939 
00940 void QgsVectorLayer::reload()
00941 {
00942   if ( mDataProvider )
00943   {
00944     mDataProvider->reloadData();
00945   }
00946 }
00947 
00948 bool QgsVectorLayer::draw( QgsRenderContext& rendererContext )
00949 {
00950   if ( !hasGeometryType() )
00951     return true;
00952 
00953   //set update threshold before each draw to make sure the current setting is picked up
00954   QSettings settings;
00955   mUpdateThreshold = settings.value( "Map/updateThreshold", 0 ).toInt();
00956 
00957   if ( mUsingRendererV2 )
00958   {
00959     if ( !mRendererV2 )
00960       return false;
00961 
00962     QgsDebugMsg( "rendering v2:\n" + mRendererV2->dump() );
00963 
00964     if ( mEditable )
00965     {
00966       // Destroy all cached geometries and clear the references to them
00967       deleteCachedGeometries();
00968       mCachedGeometriesRect = rendererContext.extent();
00969 
00970       // set editing vertex markers style
00971       mRendererV2->setVertexMarkerAppearance( currentVertexMarkerType(), currentVertexMarkerSize() );
00972     }
00973 
00974     QgsAttributeList attributes;
00975     foreach( QString attrName, mRendererV2->usedAttributes() )
00976     {
00977       int attrNum = fieldNameIndex( attrName );
00978       attributes.append( attrNum );
00979       QgsDebugMsg( "attrs: " + attrName + " - " + QString::number( attrNum ) );
00980     }
00981 
00982     bool labeling = false;
00983     //register label and diagram layer to the labeling engine
00984     prepareLabelingAndDiagrams( rendererContext, attributes, labeling );
00985 
00986     select( attributes, rendererContext.extent() );
00987 
00988     if (( mRendererV2->capabilities() & QgsFeatureRendererV2::SymbolLevels )
00989         && mRendererV2->usingSymbolLevels() )
00990       drawRendererV2Levels( rendererContext, labeling );
00991     else
00992       drawRendererV2( rendererContext, labeling );
00993 
00994     return true;
00995   }
00996 
00997   //draw ( p, viewExtent, theMapToPixelTransform, ct, drawingToEditingCanvas, 1., 1.);
00998 
00999   if ( mRenderer )
01000   {
01001     // painter is active (begin has been called
01002     /* Steps to draw the layer
01003        1. get the features in the view extent by SQL query
01004        2. read WKB for a feature
01005        3. transform
01006        4. draw
01007     */
01008 
01009     QPen pen;
01010     /*Pointer to a marker image*/
01011     QImage marker;
01012     //vertex marker type for selection
01013     QgsVectorLayer::VertexMarkerType vertexMarker = QgsVectorLayer::NoMarker;
01014     int vertexMarkerSize = 7;
01015 
01016     if ( mEditable )
01017     {
01018       // Destroy all cached geometries and clear the references to them
01019       deleteCachedGeometries();
01020       mCachedGeometriesRect = rendererContext.extent();
01021       vertexMarker = currentVertexMarkerType();
01022       vertexMarkerSize = currentVertexMarkerSize();
01023       mVertexMarkerOnlyForSelection = settings.value( "/qgis/digitizing/marker_only_for_selected", false ).toBool();
01024     }
01025 
01026     // int totalFeatures = pendingFeatureCount();
01027     int featureCount = 0;
01028     QgsFeature fet;
01029     QgsAttributeList attributes = mRenderer->classificationAttributes();
01030 
01031     bool labeling = false;
01032     prepareLabelingAndDiagrams( rendererContext, attributes, labeling );
01033 
01034     select( attributes, rendererContext.extent() );
01035 
01036     try
01037     {
01038       while ( nextFeature( fet ) )
01039       {
01040 
01041         if ( rendererContext.renderingStopped() )
01042         {
01043           break;
01044         }
01045 
01046 #ifndef Q_WS_MAC //MH: disable this on Mac for now to avoid problems with resizing
01047         if ( mUpdateThreshold > 0 && 0 == featureCount % mUpdateThreshold )
01048         {
01049           emit screenUpdateRequested();
01050           // emit drawingProgress( featureCount, totalFeatures );
01051           qApp->processEvents();
01052         }
01053         else if ( featureCount % 1000 == 0 )
01054         {
01055           // emit drawingProgress( featureCount, totalFeatures );
01056           qApp->processEvents();
01057         }
01058 // #else
01059 //         Q_UNUSED( totalFeatures );
01060 #endif //Q_WS_MAC
01061 
01062         // check if feature is selected
01063         // only show selections of the current layer
01064         // TODO: create a mechanism to let layer know whether it's current layer or not [MD]
01065         bool sel = mSelectedFeatureIds.contains( fet.id() );
01066 
01067         mCurrentVertexMarkerType = QgsVectorLayer::NoMarker;
01068         mCurrentVertexMarkerSize = 7;
01069 
01070         if ( mEditable )
01071         {
01072           // Cache this for the use of (e.g.) modifying the feature's uncommitted geometry.
01073           mCachedGeometries[fet.id()] = *fet.geometry();
01074 
01075           if ( !mVertexMarkerOnlyForSelection || sel )
01076           {
01077             mCurrentVertexMarkerType = vertexMarker;
01078             mCurrentVertexMarkerSize = vertexMarkerSize;
01079           }
01080         }
01081 
01082         //QgsDebugMsg(QString("markerScale before renderFeature(): %1").arg(markerScaleFactor));
01083         // markerScalerFactore reflects the wanted scaling of the marker
01084 
01085         double opacity = 1.0;
01086         if ( !mRenderer->usesTransparency() )
01087         {
01088           opacity = ( mTransparencyLevel * 1.0 ) / 255.0;
01089         }
01090         mRenderer->renderFeature( rendererContext, fet, &marker, sel, opacity );
01091 
01092         // markerScalerFactore now reflects the actual scaling of the marker that the render performed.
01093         //QgsDebugMsg(QString("markerScale after renderFeature(): %1").arg(markerScaleFactor));
01094 
01095         //double scale = rendererContext.scaleFactor() /  markerScaleFactor;
01096         drawFeature( rendererContext, fet, &marker );
01097 
01098         if ( mRenderer->willRenderFeature( &fet ) && rendererContext.labelingEngine() )
01099         {
01100           if ( labeling )
01101           {
01102             rendererContext.labelingEngine()->registerFeature( this, fet, rendererContext );
01103           }
01104           if ( mDiagramRenderer )
01105           {
01106             rendererContext.labelingEngine()->registerDiagramFeature( this, fet, rendererContext );
01107           }
01108         }
01109         ++featureCount;
01110       }
01111     }
01112     catch ( QgsCsException &cse )
01113     {
01114       Q_UNUSED( cse );
01115       QgsDebugMsg( QString( "Failed to transform a point while drawing a feature of type '%1'. Rendering stopped. %2" )
01116                    .arg( fet.typeName() ).arg( cse.what() ) );
01117       return false;
01118     }
01119 
01120     QgsDebugMsg( QString( "Total features processed %1" ).arg( featureCount ) );
01121   }
01122   else
01123   {
01124     QgsDebugMsg( "QgsRenderer is null" );
01125   }
01126 
01127   if ( mEditable )
01128   {
01129     QgsDebugMsg( QString( "Cached %1 geometries." ).arg( mCachedGeometries.count() ) );
01130   }
01131 
01132   return true; // Assume success always
01133 }
01134 
01135 void QgsVectorLayer::deleteCachedGeometries()
01136 {
01137   // Destroy any cached geometries
01138   mCachedGeometries.clear();
01139   mCachedGeometriesRect = QgsRectangle();
01140 }
01141 
01142 void QgsVectorLayer::drawVertexMarker( double x, double y, QPainter& p, QgsVectorLayer::VertexMarkerType type, int m )
01143 {
01144   if ( type == QgsVectorLayer::SemiTransparentCircle )
01145   {
01146     p.setPen( QColor( 50, 100, 120, 200 ) );
01147     p.setBrush( QColor( 200, 200, 210, 120 ) );
01148     p.drawEllipse( x - m, y - m, m * 2 + 1, m * 2 + 1 );
01149   }
01150   else if ( type == QgsVectorLayer::Cross )
01151   {
01152     p.setPen( QColor( 255, 0, 0 ) );
01153     p.drawLine( x - m, y + m, x + m, y - m );
01154     p.drawLine( x - m, y - m, x + m, y + m );
01155   }
01156 }
01157 
01158 void QgsVectorLayer::select( QgsFeatureId fid, bool emitSignal )
01159 {
01160   mSelectedFeatureIds.insert( fid );
01161 
01162   if ( emitSignal )
01163   {
01164     // invalidate cache
01165     setCacheImage( 0 );
01166 
01167     emit selectionChanged();
01168   }
01169 }
01170 
01171 void QgsVectorLayer::deselect( QgsFeatureId fid, bool emitSignal )
01172 {
01173   mSelectedFeatureIds.remove( fid );
01174 
01175   if ( emitSignal )
01176   {
01177     // invalidate cache
01178     setCacheImage( 0 );
01179 
01180     emit selectionChanged();
01181   }
01182 }
01183 
01184 void QgsVectorLayer::select( QgsRectangle & rect, bool lock )
01185 {
01186   // normalize the rectangle
01187   rect.normalize();
01188 
01189   if ( !lock )
01190   {
01191     removeSelection( false ); // don't emit signal
01192   }
01193 
01194   //select all the elements
01195   select( QgsAttributeList(), rect, false, true );
01196 
01197   QgsFeature f;
01198   while ( nextFeature( f ) )
01199   {
01200     select( f.id(), false ); // don't emit signal (not to redraw it everytime)
01201   }
01202 
01203   // invalidate cache
01204   setCacheImage( 0 );
01205 
01206   emit selectionChanged(); // now emit signal to redraw layer
01207 }
01208 
01209 void QgsVectorLayer::invertSelection()
01210 {
01211   // copy the ids of selected features to tmp
01212   QgsFeatureIds tmp = mSelectedFeatureIds;
01213 
01214   removeSelection( false ); // don't emit signal
01215 
01216   select( QgsAttributeList(), QgsRectangle(), false );
01217 
01218   QgsFeature fet;
01219   while ( nextFeature( fet ) )
01220   {
01221     select( fet.id(), false ); // don't emit signal
01222   }
01223 
01224   for ( QgsFeatureIds::iterator iter = tmp.begin(); iter != tmp.end(); ++iter )
01225   {
01226     mSelectedFeatureIds.remove( *iter );
01227   }
01228 
01229   // invalidate cache
01230   setCacheImage( 0 );
01231 
01232   emit selectionChanged();
01233 }
01234 
01235 void QgsVectorLayer::invertSelectionInRectangle( QgsRectangle & rect )
01236 {
01237   // normalize the rectangle
01238   rect.normalize();
01239 
01240   select( QgsAttributeList(), rect, false, true );
01241 
01242   QgsFeature fet;
01243   while ( nextFeature( fet ) )
01244   {
01245     if ( mSelectedFeatureIds.contains( fet.id() ) )
01246     {
01247       deselect( fet.id(), false ); // don't emit signal
01248     }
01249     else
01250     {
01251       select( fet.id(), false ); // don't emit signal
01252     }
01253   }
01254 
01255   // invalidate cache
01256   setCacheImage( 0 );
01257 
01258   emit selectionChanged();
01259 }
01260 
01261 void QgsVectorLayer::removeSelection( bool emitSignal )
01262 {
01263   if ( mSelectedFeatureIds.size() == 0 )
01264     return;
01265 
01266   mSelectedFeatureIds.clear();
01267 
01268   if ( emitSignal )
01269   {
01270     // invalidate cache
01271     setCacheImage( 0 );
01272 
01273     emit selectionChanged();
01274   }
01275 }
01276 
01277 void QgsVectorLayer::triggerRepaint()
01278 {
01279   emit repaintRequested();
01280 }
01281 
01282 QgsVectorDataProvider* QgsVectorLayer::dataProvider()
01283 {
01284   return mDataProvider;
01285 }
01286 
01287 const QgsVectorDataProvider* QgsVectorLayer::dataProvider() const
01288 {
01289   return mDataProvider;
01290 }
01291 
01292 void QgsVectorLayer::setProviderEncoding( const QString& encoding )
01293 {
01294   if ( mDataProvider )
01295   {
01296     mDataProvider->setEncoding( encoding );
01297   }
01298 }
01299 
01300 
01301 const QgsRenderer* QgsVectorLayer::renderer() const
01302 {
01303   return mRenderer;
01304 }
01305 
01306 void QgsVectorLayer::setRenderer( QgsRenderer *r )
01307 {
01308   if ( !hasGeometryType() )
01309     return;
01310 
01311   if ( r != mRenderer )
01312   {
01313     if ( r )
01314       setUsingRendererV2( false );
01315     delete mRenderer;
01316     mRenderer = r;
01317   }
01318 }
01319 
01320 void QgsVectorLayer::setDiagramRenderer( QgsDiagramRendererV2* r )
01321 {
01322   delete mDiagramRenderer;
01323   mDiagramRenderer = r;
01324 }
01325 
01326 QGis::GeometryType QgsVectorLayer::geometryType() const
01327 {
01328   if ( mDataProvider )
01329   {
01330     int type = mDataProvider->geometryType();
01331     switch ( type )
01332     {
01333       case QGis::WKBPoint:
01334       case QGis::WKBPoint25D:
01335         return QGis::Point;
01336 
01337       case QGis::WKBLineString:
01338       case QGis::WKBLineString25D:
01339         return QGis::Line;
01340 
01341       case QGis::WKBPolygon:
01342       case QGis::WKBPolygon25D:
01343         return QGis::Polygon;
01344 
01345       case QGis::WKBMultiPoint:
01346       case QGis::WKBMultiPoint25D:
01347         return QGis::Point;
01348 
01349       case QGis::WKBMultiLineString:
01350       case QGis::WKBMultiLineString25D:
01351         return QGis::Line;
01352 
01353       case QGis::WKBMultiPolygon:
01354       case QGis::WKBMultiPolygon25D:
01355         return QGis::Polygon;
01356 
01357       case QGis::WKBNoGeometry:
01358         return QGis::NoGeometry;
01359     }
01360     QgsDebugMsg( QString( "Data Provider Geometry type is not recognised, is %1" ).arg( type ) );
01361   }
01362   else
01363   {
01364     QgsDebugMsg( "pointer to mDataProvider is null" );
01365   }
01366 
01367   // We shouldn't get here, and if we have, other things are likely to
01368   // go wrong. Code that uses the type() return value should be
01369   // rewritten to cope with a value of QGis::Unknown. To make this
01370   // need known, the following message is printed every time we get
01371   // here.
01372   QgsDebugMsg( "WARNING: This code should never be reached. Problems may occur..." );
01373 
01374   return QGis::UnknownGeometry;
01375 }
01376 
01377 bool QgsVectorLayer::hasGeometryType() const
01378 {
01379   QGis::GeometryType t = geometryType();
01380   return ( t != QGis::NoGeometry && t != QGis::UnknownGeometry );
01381 }
01382 
01383 QGis::WkbType QgsVectorLayer::wkbType() const
01384 {
01385   return ( QGis::WkbType )( mWkbType );
01386 }
01387 
01388 QgsRectangle QgsVectorLayer::boundingBoxOfSelected()
01389 {
01390   if ( mSelectedFeatureIds.size() == 0 ) //no selected features
01391   {
01392     return QgsRectangle( 0, 0, 0, 0 );
01393   }
01394 
01395   QgsRectangle r, retval;
01396   retval.setMinimal();
01397 
01398   QgsFeature fet;
01399   if ( mDataProvider->capabilities() & QgsVectorDataProvider::SelectAtId )
01400   {
01401     foreach( QgsFeatureId fid, mSelectedFeatureIds )
01402     {
01403       if ( featureAtId( fid, fet, true, false ) && fet.geometry() )
01404       {
01405         r = fet.geometry()->boundingBox();
01406         retval.combineExtentWith( &r );
01407       }
01408     }
01409   }
01410   else
01411   {
01412     select( QgsAttributeList(), QgsRectangle(), true );
01413 
01414     while ( nextFeature( fet ) )
01415     {
01416       if ( mSelectedFeatureIds.contains( fet.id() ) )
01417       {
01418         if ( fet.geometry() )
01419         {
01420           r = fet.geometry()->boundingBox();
01421           retval.combineExtentWith( &r );
01422         }
01423       }
01424     }
01425   }
01426 
01427   if ( retval.width() == 0.0 || retval.height() == 0.0 )
01428   {
01429     // If all of the features are at the one point, buffer the
01430     // rectangle a bit. If they are all at zero, do something a bit
01431     // more crude.
01432 
01433     if ( retval.xMinimum() == 0.0 && retval.xMaximum() == 0.0 &&
01434          retval.yMinimum() == 0.0 && retval.yMaximum() == 0.0 )
01435     {
01436       retval.set( -1.0, -1.0, 1.0, 1.0 );
01437     }
01438   }
01439 
01440   return retval;
01441 }
01442 
01443 
01444 
01445 long QgsVectorLayer::featureCount() const
01446 {
01447   if ( !mDataProvider )
01448   {
01449     QgsDebugMsg( "invoked with null mDataProvider" );
01450     return 0;
01451   }
01452 
01453   return mDataProvider->featureCount();
01454 }
01455 
01456 long QgsVectorLayer::updateFeatureCount() const
01457 {
01458   return -1;
01459 }
01460 
01461 void QgsVectorLayer::updateExtents()
01462 {
01463   if ( !hasGeometryType() )
01464     return;
01465 
01466   mLayerExtent.setMinimal();
01467 
01468   if ( !mDataProvider )
01469   {
01470     QgsDebugMsg( "invoked with null mDataProvider" );
01471   }
01472 
01473   if ( mDeletedFeatureIds.isEmpty() && mChangedGeometries.isEmpty() )
01474   {
01475     mDataProvider->updateExtents();
01476 
01477     // get the extent of the layer from the provider
01478     // but only when there are some features already
01479     if ( mDataProvider->featureCount() != 0 )
01480     {
01481       QgsRectangle r = mDataProvider->extent();
01482       mLayerExtent.combineExtentWith( &r );
01483     }
01484 
01485     for ( QgsFeatureList::iterator it = mAddedFeatures.begin(); it != mAddedFeatures.end(); it++ )
01486     {
01487       QgsRectangle r = it->geometry()->boundingBox();
01488       mLayerExtent.combineExtentWith( &r );
01489     }
01490   }
01491   else
01492   {
01493     select( QgsAttributeList(), QgsRectangle(), true );
01494 
01495     QgsFeature fet;
01496     while ( nextFeature( fet ) )
01497     {
01498       if ( fet.geometry() )
01499       {
01500         QgsRectangle bb = fet.geometry()->boundingBox();
01501         mLayerExtent.combineExtentWith( &bb );
01502       }
01503     }
01504   }
01505 
01506   if ( mLayerExtent.xMinimum() > mLayerExtent.xMaximum() && mLayerExtent.yMinimum() > mLayerExtent.yMaximum() )
01507   {
01508     // special case when there are no features in provider nor any added
01509     mLayerExtent = QgsRectangle(); // use rectangle with zero coordinates
01510   }
01511 
01512   // Send this (hopefully) up the chain to the map canvas
01513   emit recalculateExtents();
01514 }
01515 
01516 QString QgsVectorLayer::subsetString()
01517 {
01518   if ( ! mDataProvider )
01519   {
01520     QgsDebugMsg( "invoked with null mDataProvider" );
01521     return 0;
01522   }
01523   return mDataProvider->subsetString();
01524 }
01525 
01526 bool QgsVectorLayer::setSubsetString( QString subset )
01527 {
01528   if ( ! mDataProvider )
01529   {
01530     QgsDebugMsg( "invoked with null mDataProvider" );
01531     return false;
01532   }
01533 
01534   bool res = mDataProvider->setSubsetString( subset );
01535 
01536   // get the updated data source string from the provider
01537   mDataSource = mDataProvider->dataSourceUri();
01538   updateExtents();
01539 
01540   if ( res )
01541     setCacheImage( 0 );
01542 
01543   return res;
01544 }
01545 
01546 void QgsVectorLayer::updateFeatureAttributes( QgsFeature &f, bool all )
01547 {
01548   if ( mDataProvider && ( all || ( mFetchAttributes.size() > 0 && mJoinBuffer->containsFetchJoins() ) ) )
01549   {
01550     int index = 0;
01551     QgsVectorLayerJoinBuffer::maximumIndex( mDataProvider->fields(), index );
01552     mJoinBuffer->updateFeatureAttributes( f, index, all );
01553   }
01554 
01555 
01556   // do not update when we aren't in editing mode
01557   if ( !mEditable )
01558     return;
01559 
01560   if ( mChangedAttributeValues.contains( f.id() ) )
01561   {
01562     const QgsAttributeMap &map = mChangedAttributeValues[f.id()];
01563     for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); it++ )
01564       f.changeAttribute( it.key(), it.value() );
01565   }
01566 
01567   // remove all attributes that will disappear
01568   QgsAttributeMap map = f.attributeMap();
01569   for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); it++ )
01570     if ( !mUpdatedFields.contains( it.key() ) )
01571       f.deleteAttribute( it.key() );
01572 
01573   // null/add all attributes that were added, but don't exist in the feature yet
01574   for ( QgsFieldMap::const_iterator it = mUpdatedFields.begin(); it != mUpdatedFields.end(); it++ )
01575     if ( !map.contains( it.key() ) && ( all || mFetchAttributes.contains( it.key() ) ) )
01576       f.changeAttribute( it.key(), QVariant( QString::null ) );
01577 }
01578 
01579 void QgsVectorLayer::addJoinedFeatureAttributes( QgsFeature& f, const QgsVectorJoinInfo& joinInfo, const QString& joinFieldName,
01580     const QVariant& joinValue, const QgsAttributeList& attributes, int attributeIndexOffset )
01581 {
01582   const QHash< QString, QgsAttributeMap>& memoryCache = joinInfo.cachedAttributes;
01583   if ( !memoryCache.isEmpty() ) //use join memory cache
01584   {
01585     QgsAttributeMap featureAttributes = memoryCache.value( joinValue.toString() );
01586     bool found = !featureAttributes.isEmpty();
01587     QgsAttributeList::const_iterator attIt = attributes.constBegin();
01588     for ( ; attIt != attributes.constEnd(); ++attIt )
01589     {
01590       if ( found )
01591       {
01592         f.addAttribute( *attIt + attributeIndexOffset, featureAttributes.value( *attIt ) );
01593       }
01594       else
01595       {
01596         f.addAttribute( *attIt + attributeIndexOffset, QVariant() );
01597       }
01598     }
01599   }
01600   else //work with subset string
01601   {
01602     QgsVectorLayer* joinLayer = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( joinInfo.joinLayerId ) );
01603     if ( !joinLayer )
01604     {
01605       return;
01606     }
01607 
01608     //no memory cache, query the joined values by setting substring
01609     QString subsetString = joinLayer->dataProvider()->subsetString(); //provider might already have a subset string
01610     QString bkSubsetString = subsetString;
01611     if ( !subsetString.isEmpty() )
01612     {
01613       subsetString.append( " AND " );
01614     }
01615 
01616     subsetString.append( "\"" + joinFieldName + "\"" + " = " + "\"" + joinValue.toString() + "\"" );
01617     joinLayer->dataProvider()->setSubsetString( subsetString, false );
01618 
01619     //select (no geometry)
01620     joinLayer->select( attributes, QgsRectangle(), false, false );
01621 
01622     //get first feature
01623     QgsFeature fet;
01624     if ( joinLayer->nextFeature( fet ) )
01625     {
01626       QgsAttributeMap attMap = fet.attributeMap();
01627       QgsAttributeMap::const_iterator attIt = attMap.constBegin();
01628       for ( ; attIt != attMap.constEnd(); ++attIt )
01629       {
01630         f.addAttribute( attIt.key() + attributeIndexOffset, attIt.value() );
01631       }
01632     }
01633     else //no suitable join feature found, insert invalid variants
01634     {
01635       QgsAttributeList::const_iterator attIt = attributes.constBegin();
01636       for ( ; attIt != attributes.constEnd(); ++attIt )
01637       {
01638         f.addAttribute( *attIt + attributeIndexOffset, QVariant() );
01639       }
01640     }
01641 
01642     joinLayer->dataProvider()->setSubsetString( bkSubsetString, false );
01643   }
01644 }
01645 
01646 void QgsVectorLayer::updateFeatureGeometry( QgsFeature &f )
01647 {
01648   if ( mChangedGeometries.contains( f.id() ) )
01649     f.setGeometry( mChangedGeometries[f.id()] );
01650 }
01651 
01652 
01653 void QgsVectorLayer::select( QgsAttributeList attributes, QgsRectangle rect, bool fetchGeometries, bool useIntersect )
01654 {
01655   if ( !mDataProvider )
01656     return;
01657 
01658   mFetching        = true;
01659   mFetchRect       = rect;
01660   mFetchAttributes = attributes;
01661   mFetchGeometry   = fetchGeometries;
01662   mFetchConsidered = mDeletedFeatureIds;
01663   QgsAttributeList targetJoinFieldList;
01664 
01665   if ( mEditable )
01666   {
01667     mFetchAddedFeaturesIt = mAddedFeatures.begin();
01668     mFetchChangedGeomIt = mChangedGeometries.begin();
01669   }
01670 
01671   //look in the normal features of the provider
01672   if ( mFetchAttributes.size() > 0 )
01673   {
01674     if ( mEditable || mJoinBuffer->containsJoins() )
01675     {
01676       QgsAttributeList joinFields;
01677 
01678       int maxProviderIndex = 0;
01679       if ( mDataProvider )
01680       {
01681         QgsVectorLayerJoinBuffer::maximumIndex( mDataProvider->fields(), maxProviderIndex );
01682       }
01683 
01684       mJoinBuffer->select( mFetchAttributes, joinFields, maxProviderIndex );
01685       QgsAttributeList::const_iterator joinFieldIt = joinFields.constBegin();
01686       for ( ; joinFieldIt != joinFields.constEnd(); ++joinFieldIt )
01687       {
01688         if ( !mFetchAttributes.contains( *joinFieldIt ) )
01689         {
01690           mFetchAttributes.append( *joinFieldIt );
01691         }
01692       }
01693 
01694       //detect which fields are from the provider
01695       mFetchProvAttributes.clear();
01696       for ( QgsAttributeList::iterator it = mFetchAttributes.begin(); it != mFetchAttributes.end(); it++ )
01697       {
01698         if ( mDataProvider->fields().contains( *it ) )
01699         {
01700           mFetchProvAttributes << *it;
01701         }
01702       }
01703 
01704       mDataProvider->select( mFetchProvAttributes, rect, fetchGeometries, useIntersect );
01705     }
01706     else
01707     {
01708       mDataProvider->select( mFetchAttributes, rect, fetchGeometries, useIntersect );
01709     }
01710   }
01711   else //we don't need any attributes at all
01712   {
01713     mDataProvider->select( QgsAttributeList(), rect, fetchGeometries, useIntersect );
01714   }
01715 }
01716 
01717 bool QgsVectorLayer::nextFeature( QgsFeature &f )
01718 {
01719   if ( !mFetching )
01720     return false;
01721 
01722   if ( mEditable )
01723   {
01724     if ( !mFetchRect.isEmpty() )
01725     {
01726       // check if changed geometries are in rectangle
01727       for ( ; mFetchChangedGeomIt != mChangedGeometries.end(); mFetchChangedGeomIt++ )
01728       {
01729         QgsFeatureId fid = mFetchChangedGeomIt.key();
01730 
01731         if ( mFetchConsidered.contains( fid ) )
01732           // skip deleted features
01733           continue;
01734 
01735         mFetchConsidered << fid;
01736 
01737         if ( !mFetchChangedGeomIt->intersects( mFetchRect ) )
01738           // skip changed geometries not in rectangle and don't check again
01739           continue;
01740 
01741         f.setFeatureId( fid );
01742         f.setValid( true );
01743 
01744         if ( mFetchGeometry )
01745           f.setGeometry( mFetchChangedGeomIt.value() );
01746 
01747         if ( mFetchAttributes.size() > 0 )
01748         {
01749           if ( fid < 0 )
01750           {
01751             // fid<0 => in mAddedFeatures
01752             bool found = false;
01753 
01754             for ( QgsFeatureList::iterator it = mAddedFeatures.begin(); it != mAddedFeatures.end(); it++ )
01755             {
01756               if ( fid == it->id() )
01757               {
01758                 found = true;
01759                 f.setAttributeMap( it->attributeMap() );
01760                 updateFeatureAttributes( f );
01761                 break;
01762               }
01763             }
01764 
01765             if ( !found )
01766             {
01767               QgsDebugMsg( QString( "No attributes for the added feature %1 found" ).arg( f.id() ) );
01768             }
01769           }
01770           else
01771           {
01772             // retrieve attributes from provider
01773             QgsFeature tmp;
01774             mDataProvider->featureAtId( fid, tmp, false, mFetchProvAttributes );
01775             updateFeatureAttributes( tmp );
01776             f.setAttributeMap( tmp.attributeMap() );
01777           }
01778         }
01779 
01780         // return complete feature
01781         mFetchChangedGeomIt++;
01782         return true;
01783       }
01784 
01785       // no more changed geometries
01786     }
01787 
01788     for ( ; mFetchAddedFeaturesIt != mAddedFeatures.end(); mFetchAddedFeaturesIt++ )
01789     {
01790       QgsFeatureId fid = mFetchAddedFeaturesIt->id();
01791 
01792       if ( mFetchConsidered.contains( fid ) )
01793         // must have changed geometry outside rectangle
01794         continue;
01795 
01796       if ( !mFetchRect.isEmpty() &&
01797            mFetchAddedFeaturesIt->geometry() &&
01798            !mFetchAddedFeaturesIt->geometry()->intersects( mFetchRect ) )
01799         // skip added features not in rectangle
01800         continue;
01801 
01802       f.setFeatureId( fid );
01803       f.setValid( true );
01804 
01805       if ( mFetchGeometry )
01806         f.setGeometry( *mFetchAddedFeaturesIt->geometry() );
01807 
01808       if ( mFetchAttributes.size() > 0 )
01809       {
01810         f.setAttributeMap( mFetchAddedFeaturesIt->attributeMap() );
01811         updateFeatureAttributes( f );
01812       }
01813 
01814       mFetchAddedFeaturesIt++;
01815       return true;
01816     }
01817 
01818     // no more added features
01819   }
01820 
01821   while ( dataProvider()->nextFeature( f ) )
01822   {
01823     if ( mFetchConsidered.contains( f.id() ) )
01824     {
01825       continue;
01826     }
01827     if ( mFetchAttributes.size() > 0 )
01828     {
01829       updateFeatureAttributes( f ); //check joined attributes / changed attributes
01830     }
01831     if ( mEditable && mFetchGeometry )
01832     {
01833       updateFeatureGeometry( f );
01834     }
01835 
01836     return true;
01837   }
01838 
01839   mFetching = false;
01840   return false;
01841 }
01842 
01843 bool QgsVectorLayer::featureAtId( QgsFeatureId featureId, QgsFeature& f, bool fetchGeometries, bool fetchAttributes )
01844 {
01845   if ( !mDataProvider )
01846     return false;
01847 
01848   if ( mDeletedFeatureIds.contains( featureId ) )
01849     return false;
01850 
01851   if ( fetchGeometries && mChangedGeometries.contains( featureId ) )
01852   {
01853     f.setFeatureId( featureId );
01854     f.setValid( true );
01855     f.setGeometry( mChangedGeometries[featureId] );
01856 
01857     if ( fetchAttributes )
01858     {
01859       if ( featureId < 0 )
01860       {
01861         // featureId<0 => in mAddedFeatures
01862         bool found = false;
01863 
01864         for ( QgsFeatureList::iterator it = mAddedFeatures.begin(); it != mAddedFeatures.end(); it++ )
01865         {
01866           if ( featureId != it->id() )
01867           {
01868             found = true;
01869             f.setAttributeMap( it->attributeMap() );
01870             break;
01871           }
01872         }
01873 
01874         if ( !found )
01875         {
01876           QgsDebugMsg( QString( "No attributes for the added feature %1 found" ).arg( f.id() ) );
01877         }
01878       }
01879       else
01880       {
01881         // retrieve attributes from provider
01882         QgsFeature tmp;
01883         mDataProvider->featureAtId( featureId, tmp, false, mDataProvider->attributeIndexes() );
01884         f.setAttributeMap( tmp.attributeMap() );
01885       }
01886       updateFeatureAttributes( f, true );
01887     }
01888     return true;
01889   }
01890 
01891   //added features
01892   for ( QgsFeatureList::iterator iter = mAddedFeatures.begin(); iter != mAddedFeatures.end(); ++iter )
01893   {
01894     if ( iter->id() == featureId )
01895     {
01896       f.setFeatureId( iter->id() );
01897       f.setValid( true );
01898       if ( fetchGeometries )
01899         f.setGeometry( *iter->geometry() );
01900 
01901       if ( fetchAttributes )
01902         f.setAttributeMap( iter->attributeMap() );
01903 
01904       return true;
01905     }
01906   }
01907 
01908   // regular features
01909   if ( fetchAttributes )
01910   {
01911     if ( mDataProvider->featureAtId( featureId, f, fetchGeometries, mDataProvider->attributeIndexes() ) )
01912     {
01913       updateFeatureAttributes( f, true );
01914       return true;
01915     }
01916   }
01917   else
01918   {
01919     if ( mDataProvider->featureAtId( featureId, f, fetchGeometries, QgsAttributeList() ) )
01920     {
01921       return true;
01922     }
01923   }
01924   return false;
01925 }
01926 
01927 bool QgsVectorLayer::addFeature( QgsFeature& f, bool alsoUpdateExtent )
01928 {
01929   static int addedIdLowWaterMark = -1;
01930 
01931   if ( !mDataProvider )
01932   {
01933     return false;
01934   }
01935 
01936   if ( !( mDataProvider->capabilities() & QgsVectorDataProvider::AddFeatures ) )
01937   {
01938     return false;
01939   }
01940 
01941   if ( !isEditable() )
01942   {
01943     return false;
01944   }
01945 
01946   //assign a temporary id to the feature (use negative numbers)
01947   addedIdLowWaterMark--;
01948 
01949   QgsDebugMsg( "Assigned feature id " + QString::number( addedIdLowWaterMark ) );
01950 
01951   // Force a feature ID (to keep other functions in QGIS happy,
01952   // providers will use their own new feature ID when we commit the new feature)
01953   // and add to the known added features.
01954   f.setFeatureId( addedIdLowWaterMark );
01955   editFeatureAdd( f );
01956 
01957   if ( f.geometry() )
01958     mCachedGeometries[f.id()] = *f.geometry();
01959 
01960   setModified( true );
01961 
01962   if ( alsoUpdateExtent )
01963   {
01964     updateExtents();
01965   }
01966 
01967   emit featureAdded( f.id() );
01968 
01969   return true;
01970 }
01971 
01972 bool QgsVectorLayer::updateFeature( QgsFeature &f )
01973 {
01974   QgsFeature current;
01975   if ( !featureAtId( f.id(), current, f.geometry(), !f.attributeMap().isEmpty() ) )
01976   {
01977     QgsDebugMsg( QString( "feature %1 could not be retrieved" ).arg( f.id() ) );
01978     return false;
01979   }
01980 
01981   if ( f.geometry() && current.geometry() && f.geometry() != current.geometry() && !f.geometry()->isGeosEqual( *current.geometry() ) )
01982   {
01983     if ( !changeGeometry( f.id(), f.geometry() ) )
01984     {
01985       QgsDebugMsg( QString( "geometry of feature %1 could not be changed." ).arg( f.id() ) );
01986       return false;
01987     }
01988   }
01989 
01990   const QgsAttributeMap &fa = f.attributeMap();
01991   const QgsAttributeMap &ca = current.attributeMap();
01992 
01993   foreach( int attr, fa.keys() )
01994   {
01995     if ( fa.contains( attr ) && ca.contains( attr ) && fa[attr] != ca[attr] )
01996     {
01997       if ( !changeAttributeValue( f.id(), attr, fa[attr] ) )
01998       {
01999         QgsDebugMsg( QString( "attribute %1 of feature %2 could not be changed." ).arg( attr ).arg( f.id() ) );
02000         return false;
02001       }
02002     }
02003   }
02004 
02005   return true;
02006 }
02007 
02008 
02009 bool QgsVectorLayer::insertVertex( double x, double y, QgsFeatureId atFeatureId, int beforeVertex )
02010 {
02011   if ( !hasGeometryType() )
02012     return false;
02013 
02014   if ( !mEditable )
02015   {
02016     return false;
02017   }
02018 
02019   if ( mDataProvider )
02020   {
02021     QgsGeometry geometry;
02022     if ( !mChangedGeometries.contains( atFeatureId ) )
02023     {
02024       // first time this geometry has changed since last commit
02025       if ( !mCachedGeometries.contains( atFeatureId ) )
02026       {
02027         return false;
02028       }
02029       geometry = mCachedGeometries[atFeatureId];
02030       //mChangedGeometries[atFeatureId] = mCachedGeometries[atFeatureId];
02031     }
02032     else
02033     {
02034       geometry = mChangedGeometries[atFeatureId];
02035     }
02036     geometry.insertVertex( x, y, beforeVertex );
02037     mCachedGeometries[atFeatureId] = geometry;
02038     editGeometryChange( atFeatureId, geometry );
02039 
02040     setModified( true, true ); // only geometry was changed
02041 
02042     return true;
02043   }
02044   return false;
02045 }
02046 
02047 
02048 bool QgsVectorLayer::moveVertex( double x, double y, QgsFeatureId atFeatureId, int atVertex )
02049 {
02050   if ( !hasGeometryType() )
02051     return false;
02052 
02053   if ( !mEditable )
02054   {
02055     return false;
02056   }
02057 
02058   if ( mDataProvider )
02059   {
02060     QgsGeometry geometry;
02061     if ( !mChangedGeometries.contains( atFeatureId ) )
02062     {
02063       // first time this geometry has changed since last commit
02064       if ( !mCachedGeometries.contains( atFeatureId ) )
02065       {
02066         return false;
02067       }
02068       geometry = mCachedGeometries[atFeatureId];
02069       //mChangedGeometries[atFeatureId] = mCachedGeometries[atFeatureId];
02070     }
02071     else
02072     {
02073       geometry = mChangedGeometries[atFeatureId];
02074     }
02075 
02076     geometry.moveVertex( x, y, atVertex );
02077     mCachedGeometries[atFeatureId] = geometry;
02078     editGeometryChange( atFeatureId, geometry );
02079 
02080     setModified( true, true ); // only geometry was changed
02081 
02082     return true;
02083   }
02084   return false;
02085 }
02086 
02087 
02088 bool QgsVectorLayer::deleteVertex( QgsFeatureId atFeatureId, int atVertex )
02089 {
02090   if ( !hasGeometryType() )
02091     return false;
02092 
02093   if ( !mEditable )
02094   {
02095     return false;
02096   }
02097 
02098   if ( mDataProvider )
02099   {
02100     QgsGeometry geometry;
02101     if ( !mChangedGeometries.contains( atFeatureId ) )
02102     {
02103       // first time this geometry has changed since last commit
02104       if ( !mCachedGeometries.contains( atFeatureId ) )
02105       {
02106         return false;
02107       }
02108       geometry = mCachedGeometries[atFeatureId];
02109     }
02110     else
02111     {
02112       geometry = mChangedGeometries[atFeatureId];
02113     }
02114 
02115     if ( !geometry.deleteVertex( atVertex ) )
02116     {
02117       return false;
02118     }
02119     mCachedGeometries[atFeatureId] = geometry;
02120     editGeometryChange( atFeatureId, geometry );
02121 
02122     setModified( true, true ); // only geometry was changed
02123 
02124     return true;
02125   }
02126   return false;
02127 }
02128 
02129 
02130 bool QgsVectorLayer::deleteSelectedFeatures()
02131 {
02132   if ( !( mDataProvider->capabilities() & QgsVectorDataProvider::DeleteFeatures ) )
02133   {
02134     return false;
02135   }
02136 
02137   if ( !isEditable() )
02138   {
02139     return false;
02140   }
02141 
02142   if ( mSelectedFeatureIds.size() == 0 )
02143     return true;
02144 
02145   while ( mSelectedFeatureIds.size() > 0 )
02146   {
02147     QgsFeatureId fid = *mSelectedFeatureIds.begin();
02148     deleteFeature( fid );  // removes from selection
02149   }
02150 
02151   // invalidate cache
02152   setCacheImage( 0 );
02153 
02154   emit selectionChanged();
02155 
02156   triggerRepaint();
02157   updateExtents();
02158 
02159   return true;
02160 }
02161 
02162 int QgsVectorLayer::addRing( const QList<QgsPoint>& ring )
02163 {
02164   if ( !hasGeometryType() )
02165     return 5;
02166 
02167   int addRingReturnCode = 5; //default: return code for 'ring not inserted'
02168   double xMin, yMin, xMax, yMax;
02169   QgsRectangle bBox;
02170 
02171   if ( boundingBoxFromPointList( ring, xMin, yMin, xMax, yMax ) == 0 )
02172   {
02173     bBox.setXMinimum( xMin ); bBox.setYMinimum( yMin );
02174     bBox.setXMaximum( xMax ); bBox.setYMaximum( yMax );
02175   }
02176   else
02177   {
02178     return 3; //ring not valid
02179   }
02180 
02181   select( QgsAttributeList(), bBox, true, true );
02182 
02183   QgsFeature f;
02184   while ( nextFeature( f ) )
02185   {
02186     addRingReturnCode = f.geometry()->addRing( ring );
02187     if ( addRingReturnCode == 0 )
02188     {
02189       editGeometryChange( f.id(), *f.geometry() );
02190 
02191       setModified( true, true );
02192       break;
02193     }
02194   }
02195 
02196   return addRingReturnCode;
02197 }
02198 
02199 int QgsVectorLayer::addPart( const QList<QgsPoint> &points )
02200 {
02201   if ( !hasGeometryType() )
02202     return 6;
02203 
02204   //number of selected features must be 1
02205 
02206   if ( mSelectedFeatureIds.size() < 1 )
02207   {
02208     QgsDebugMsg( "Number of selected features <1" );
02209     return 4;
02210   }
02211   else if ( mSelectedFeatureIds.size() > 1 )
02212   {
02213     QgsDebugMsg( "Number of selected features >1" );
02214     return 5;
02215   }
02216 
02217   QgsFeatureId selectedFeatureId = *mSelectedFeatureIds.constBegin();
02218 
02219   //look if geometry of selected feature already contains geometry changes
02220   QgsGeometryMap::iterator changedIt = mChangedGeometries.find( selectedFeatureId );
02221   if ( changedIt != mChangedGeometries.end() )
02222   {
02223     QgsGeometry geom = *changedIt;
02224     int returnValue = geom.addPart( points );
02225     editGeometryChange( selectedFeatureId, geom );
02226     mCachedGeometries[selectedFeatureId] = geom;
02227     return returnValue;
02228   }
02229 
02230   //look if id of selected feature belongs to an added feature
02231 #if 0
02232   for ( QgsFeatureList::iterator addedIt = mAddedFeatures.begin(); addedIt != mAddedFeatures.end(); ++addedIt )
02233   {
02234     if ( addedIt->id() == selectedFeatureId )
02235     {
02236       return addedIt->geometry()->addPart( ring );
02237       mCachedGeometries[selectedFeatureId] = *addedIt->geometry();
02238     }
02239   }
02240 #endif
02241 
02242   //is the feature contained in the view extent (mCachedGeometries) ?
02243   QgsGeometryMap::iterator cachedIt = mCachedGeometries.find( selectedFeatureId );
02244   if ( cachedIt != mCachedGeometries.end() )
02245   {
02246     int errorCode = cachedIt->addPart( points );
02247     if ( errorCode == 0 )
02248     {
02249       editGeometryChange( selectedFeatureId, *cachedIt );
02250       mCachedGeometries[selectedFeatureId] = *cachedIt;
02251       setModified( true, true );
02252     }
02253     return errorCode;
02254   }
02255   else //maybe the selected feature has been moved outside the visible area and therefore is not contained in mCachedGeometries
02256   {
02257     QgsFeature f;
02258     QgsGeometry* fGeom = 0;
02259     if ( featureAtId( selectedFeatureId, f, true, false ) )
02260     {
02261       fGeom = f.geometryAndOwnership();
02262       if ( fGeom )
02263       {
02264         int errorCode = fGeom->addPart( points );
02265         editGeometryChange( selectedFeatureId, *fGeom );
02266         setModified( true, true );
02267         delete fGeom;
02268         return errorCode;
02269       }
02270     }
02271   }
02272 
02273   return 6; //geometry not found
02274 }
02275 
02276 int QgsVectorLayer::translateFeature( QgsFeatureId featureId, double dx, double dy )
02277 {
02278   if ( !hasGeometryType() )
02279     return 1;
02280 
02281   //look if geometry of selected feature already contains geometry changes
02282   QgsGeometryMap::iterator changedIt = mChangedGeometries.find( featureId );
02283   if ( changedIt != mChangedGeometries.end() )
02284   {
02285     QgsGeometry geom = *changedIt;
02286     int errorCode = geom.translate( dx, dy );
02287     editGeometryChange( featureId, geom );
02288     return errorCode;
02289   }
02290 
02291   //look if id of selected feature belongs to an added feature
02292 #if 0
02293   for ( QgsFeatureList::iterator addedIt = mAddedFeatures.begin(); addedIt != mAddedFeatures.end(); ++addedIt )
02294   {
02295     if ( addedIt->id() == featureId )
02296     {
02297       return addedIt->geometry()->translate( dx, dy );
02298     }
02299   }
02300 #endif
02301 
02302   //else look in mCachedGeometries to make access faster
02303   QgsGeometryMap::iterator cachedIt = mCachedGeometries.find( featureId );
02304   if ( cachedIt != mCachedGeometries.end() )
02305   {
02306     int errorCode = cachedIt->translate( dx, dy );
02307     if ( errorCode == 0 )
02308     {
02309       editGeometryChange( featureId, *cachedIt );
02310       setModified( true, true );
02311     }
02312     return errorCode;
02313   }
02314 
02315   //else get the geometry from provider (may be slow)
02316   QgsFeature f;
02317   if ( mDataProvider && mDataProvider->featureAtId( featureId, f, true ) )
02318   {
02319     if ( f.geometry() )
02320     {
02321       QgsGeometry translateGeom( *( f.geometry() ) );
02322       int errorCode = translateGeom.translate( dx, dy );
02323       if ( errorCode == 0 )
02324       {
02325         editGeometryChange( featureId, translateGeom );
02326         setModified( true, true );
02327       }
02328       return errorCode;
02329     }
02330   }
02331   return 1; //geometry not found
02332 }
02333 
02334 int QgsVectorLayer::splitFeatures( const QList<QgsPoint>& splitLine, bool topologicalEditing )
02335 {
02336   if ( !hasGeometryType() )
02337     return 4;
02338 
02339   QgsFeatureList newFeatures; //store all the newly created features
02340   double xMin, yMin, xMax, yMax;
02341   QgsRectangle bBox; //bounding box of the split line
02342   int returnCode = 0;
02343   int splitFunctionReturn; //return code of QgsGeometry::splitGeometry
02344   int numberOfSplittedFeatures = 0;
02345 
02346   QgsFeatureList featureList;
02347   const QgsFeatureIds selectedIds = selectedFeaturesIds();
02348 
02349   if ( selectedIds.size() > 0 ) //consider only the selected features if there is a selection
02350   {
02351     featureList = selectedFeatures();
02352   }
02353   else //else consider all the feature that intersect the bounding box of the split line
02354   {
02355     if ( boundingBoxFromPointList( splitLine, xMin, yMin, xMax, yMax ) == 0 )
02356     {
02357       bBox.setXMinimum( xMin ); bBox.setYMinimum( yMin );
02358       bBox.setXMaximum( xMax ); bBox.setYMaximum( yMax );
02359     }
02360     else
02361     {
02362       return 1;
02363     }
02364 
02365     if ( bBox.isEmpty() )
02366     {
02367       //if the bbox is a line, try to make a square out of it
02368       if ( bBox.width() == 0.0 && bBox.height() > 0 )
02369       {
02370         bBox.setXMinimum( bBox.xMinimum() - bBox.height() / 2 );
02371         bBox.setXMaximum( bBox.xMaximum() + bBox.height() / 2 );
02372       }
02373       else if ( bBox.height() == 0.0 && bBox.width() > 0 )
02374       {
02375         bBox.setYMinimum( bBox.yMinimum() - bBox.width() / 2 );
02376         bBox.setYMaximum( bBox.yMaximum() + bBox.width() / 2 );
02377       }
02378       else
02379       {
02380         return 2;
02381       }
02382     }
02383 
02384     select( pendingAllAttributesList(), bBox, true, true );
02385 
02386     QgsFeature f;
02387     while ( nextFeature( f ) )
02388       featureList << QgsFeature( f );
02389   }
02390 
02391   QgsFeatureList::iterator select_it = featureList.begin();
02392   for ( ; select_it != featureList.end(); ++select_it )
02393   {
02394     QList<QgsGeometry*> newGeometries;
02395     QList<QgsPoint> topologyTestPoints;
02396     QgsGeometry* newGeometry = 0;
02397     splitFunctionReturn = select_it->geometry()->splitGeometry( splitLine, newGeometries, topologicalEditing, topologyTestPoints );
02398     if ( splitFunctionReturn == 0 )
02399     {
02400       //change this geometry
02401       editGeometryChange( select_it->id(), *( select_it->geometry() ) );
02402       //update of cached geometries is necessary because we use addTopologicalPoints() later
02403       mCachedGeometries[select_it->id()] = *( select_it->geometry() );
02404 
02405       //insert new features
02406       for ( int i = 0; i < newGeometries.size(); ++i )
02407       {
02408         newGeometry = newGeometries.at( i );
02409         QgsFeature newFeature;
02410         newFeature.setGeometry( newGeometry );
02411 
02412         //use default value where possible (primary key issue), otherwise the value from the original (splitted) feature
02413         QgsAttributeMap newAttributes = select_it->attributeMap();
02414         QVariant defaultValue;
02415         for ( int j = 0; j < newAttributes.size(); ++j )
02416         {
02417           if ( mDataProvider )
02418           {
02419             defaultValue = mDataProvider->defaultValue( j );
02420             if ( !defaultValue.isNull() )
02421             {
02422               newAttributes.insert( j, defaultValue );
02423             }
02424           }
02425         }
02426 
02427         newFeature.setAttributeMap( newAttributes );
02428         newFeatures.append( newFeature );
02429       }
02430 
02431       setModified( true, true );
02432       if ( topologicalEditing )
02433       {
02434         QList<QgsPoint>::const_iterator topol_it = topologyTestPoints.constBegin();
02435         for ( ; topol_it != topologyTestPoints.constEnd(); ++topol_it )
02436         {
02437           addTopologicalPoints( *topol_it );
02438         }
02439       }
02440       ++numberOfSplittedFeatures;
02441     }
02442     else if ( splitFunctionReturn > 1 ) //1 means no split but also no error
02443     {
02444       returnCode = splitFunctionReturn;
02445     }
02446   }
02447 
02448   if ( numberOfSplittedFeatures == 0 && selectedIds.size() > 0 )
02449   {
02450     //There is a selection but no feature has been split.
02451     //Maybe user forgot that only the selected features are split
02452     returnCode = 4;
02453   }
02454 
02455 
02456   //now add the new features to this vectorlayer
02457   addFeatures( newFeatures, false );
02458 
02459   return returnCode;
02460 }
02461 
02462 int QgsVectorLayer::removePolygonIntersections( QgsGeometry* geom )
02463 {
02464   if ( !hasGeometryType() )
02465     return 1;
02466 
02467   int returnValue = 0;
02468 
02469   //first test if geom really has type polygon or multipolygon
02470   if ( geom->type() != QGis::Polygon )
02471   {
02472     return 1;
02473   }
02474 
02475   //get bounding box of geom
02476   QgsRectangle geomBBox = geom->boundingBox();
02477 
02478   //get list of features that intersect this bounding box
02479   select( QgsAttributeList(), geomBBox, true, true );
02480 
02481   QgsFeature f;
02482   while ( nextFeature( f ) )
02483   {
02484     //call geometry->makeDifference for each feature
02485     QgsGeometry *currentGeom = f.geometry();
02486     if ( currentGeom )
02487     {
02488       if ( geom->makeDifference( currentGeom ) != 0 )
02489       {
02490         returnValue = 2;
02491       }
02492     }
02493   }
02494   return returnValue;
02495 }
02496 
02497 int QgsVectorLayer::addTopologicalPoints( QgsGeometry* geom )
02498 {
02499   if ( !hasGeometryType() )
02500     return 1;
02501 
02502   if ( !geom )
02503   {
02504     return 1;
02505   }
02506 
02507   int returnVal = 0;
02508 
02509   QGis::WkbType wkbType = geom->wkbType();
02510 
02511   switch ( wkbType )
02512   {
02513       //line
02514     case QGis::WKBLineString25D:
02515     case QGis::WKBLineString:
02516     {
02517       QgsPolyline theLine = geom->asPolyline();
02518       QgsPolyline::const_iterator line_it = theLine.constBegin();
02519       for ( ; line_it != theLine.constEnd(); ++line_it )
02520       {
02521         if ( addTopologicalPoints( *line_it ) != 0 )
02522         {
02523           returnVal = 2;
02524         }
02525       }
02526       break;
02527     }
02528 
02529     //multiline
02530     case QGis::WKBMultiLineString25D:
02531     case QGis::WKBMultiLineString:
02532     {
02533       QgsMultiPolyline theMultiLine = geom->asMultiPolyline();
02534       QgsPolyline currentPolyline;
02535 
02536       for ( int i = 0; i < theMultiLine.size(); ++i )
02537       {
02538         QgsPolyline::const_iterator line_it = currentPolyline.constBegin();
02539         for ( ; line_it != currentPolyline.constEnd(); ++line_it )
02540         {
02541           if ( addTopologicalPoints( *line_it ) != 0 )
02542           {
02543             returnVal = 2;
02544           }
02545         }
02546       }
02547       break;
02548     }
02549 
02550     //polygon
02551     case QGis::WKBPolygon25D:
02552     case QGis::WKBPolygon:
02553     {
02554       QgsPolygon thePolygon = geom->asPolygon();
02555       QgsPolyline currentRing;
02556 
02557       for ( int i = 0; i < thePolygon.size(); ++i )
02558       {
02559         currentRing = thePolygon.at( i );
02560         QgsPolyline::const_iterator line_it = currentRing.constBegin();
02561         for ( ; line_it != currentRing.constEnd(); ++line_it )
02562         {
02563           if ( addTopologicalPoints( *line_it ) != 0 )
02564           {
02565             returnVal = 2;
02566           }
02567         }
02568       }
02569       break;
02570     }
02571 
02572     //multipolygon
02573     case QGis::WKBMultiPolygon25D:
02574     case QGis::WKBMultiPolygon:
02575     {
02576       QgsMultiPolygon theMultiPolygon = geom->asMultiPolygon();
02577       QgsPolygon currentPolygon;
02578       QgsPolyline currentRing;
02579 
02580       for ( int i = 0; i < theMultiPolygon.size(); ++i )
02581       {
02582         currentPolygon = theMultiPolygon.at( i );
02583         for ( int j = 0; j < currentPolygon.size(); ++j )
02584         {
02585           currentRing = currentPolygon.at( j );
02586           QgsPolyline::const_iterator line_it = currentRing.constBegin();
02587           for ( ; line_it != currentRing.constEnd(); ++line_it )
02588           {
02589             if ( addTopologicalPoints( *line_it ) != 0 )
02590             {
02591               returnVal = 2;
02592             }
02593           }
02594         }
02595       }
02596       break;
02597     }
02598     default:
02599       break;
02600   }
02601   return returnVal;
02602 }
02603 
02604 int QgsVectorLayer::addTopologicalPoints( const QgsPoint& p )
02605 {
02606   if ( !hasGeometryType() )
02607     return 1;
02608 
02609   QMultiMap<double, QgsSnappingResult> snapResults; //results from the snapper object
02610   //we also need to snap to vertex to make sure the vertex does not already exist in this geometry
02611   QMultiMap<double, QgsSnappingResult> vertexSnapResults;
02612 
02613   QList<QgsSnappingResult> filteredSnapResults; //we filter out the results that are on existing vertices
02614 
02615   //work with a tolerance because coordinate projection may introduce some rounding
02616   double threshold =  0.0000001;
02617   if ( crs().mapUnits() == QGis::Meters )
02618   {
02619     threshold = 0.001;
02620   }
02621   else if ( crs().mapUnits() == QGis::Feet )
02622   {
02623     threshold = 0.0001;
02624   }
02625 
02626 
02627   if ( snapWithContext( p, threshold, snapResults, QgsSnapper::SnapToSegment ) != 0 )
02628   {
02629     return 2;
02630   }
02631 
02632   QMultiMap<double, QgsSnappingResult>::const_iterator snap_it = snapResults.constBegin();
02633   QMultiMap<double, QgsSnappingResult>::const_iterator vertex_snap_it;
02634   for ( ; snap_it != snapResults.constEnd(); ++snap_it )
02635   {
02636     //test if p is already a vertex of this geometry. If yes, don't insert it
02637     bool vertexAlreadyExists = false;
02638     if ( snapWithContext( p, threshold, vertexSnapResults, QgsSnapper::SnapToVertex ) != 0 )
02639     {
02640       continue;
02641     }
02642 
02643     vertex_snap_it = vertexSnapResults.constBegin();
02644     for ( ; vertex_snap_it != vertexSnapResults.constEnd(); ++vertex_snap_it )
02645     {
02646       if ( snap_it.value().snappedAtGeometry == vertex_snap_it.value().snappedAtGeometry )
02647       {
02648         vertexAlreadyExists = true;
02649       }
02650     }
02651 
02652     if ( !vertexAlreadyExists )
02653     {
02654       filteredSnapResults.push_back( *snap_it );
02655     }
02656   }
02657   insertSegmentVerticesForSnap( filteredSnapResults );
02658   return 0;
02659 }
02660 
02661 QgsLabel *QgsVectorLayer::label()
02662 {
02663   return mLabel;
02664 }
02665 
02666 const QgsLabel *QgsVectorLayer::label() const
02667 {
02668   return mLabel;
02669 }
02670 
02671 void QgsVectorLayer::enableLabels( bool on )
02672 {
02673   mLabelOn = on;
02674 }
02675 
02676 bool QgsVectorLayer::hasLabelsEnabled( void ) const
02677 {
02678   return mLabelOn;
02679 }
02680 
02681 bool QgsVectorLayer::startEditing()
02682 {
02683   if ( !mDataProvider )
02684   {
02685     return false;
02686   }
02687 
02688   // allow editing if provider supports any of the capabilities
02689   if ( !( mDataProvider->capabilities() & QgsVectorDataProvider::EditingCapabilities ) )
02690   {
02691     return false;
02692   }
02693 
02694   if ( mReadOnly )
02695   {
02696     return false;
02697   }
02698 
02699   if ( mEditable )
02700   {
02701     // editing already underway
02702     return false;
02703   }
02704 
02705   mEditable = true;
02706 
02707   mAddedAttributeIds.clear();
02708   mDeletedAttributeIds.clear();
02709   updateFieldMap();
02710 
02711   for ( QgsFieldMap::const_iterator it = mUpdatedFields.begin(); it != mUpdatedFields.end(); it++ )
02712     if ( it.key() > mMaxUpdatedIndex )
02713       mMaxUpdatedIndex = it.key();
02714 
02715   emit editingStarted();
02716 
02717   return true;
02718 }
02719 
02720 bool QgsVectorLayer::readXml( const QDomNode& layer_node )
02721 {
02722   QgsDebugMsg( QString( "Datasource in QgsVectorLayer::readXml: " ) + mDataSource.toLocal8Bit().data() );
02723 
02724   //process provider key
02725   QDomNode pkeyNode = layer_node.namedItem( "provider" );
02726 
02727   if ( pkeyNode.isNull() )
02728   {
02729     mProviderKey = "";
02730   }
02731   else
02732   {
02733     QDomElement pkeyElt = pkeyNode.toElement();
02734     mProviderKey = pkeyElt.text();
02735   }
02736 
02737   // determine type of vector layer
02738   if ( ! mProviderKey.isNull() )
02739   {
02740     // if the provider string isn't empty, then we successfully
02741     // got the stored provider
02742   }
02743   else if ( mDataSource.contains( "dbname=" ) )
02744   {
02745     mProviderKey = "postgres";
02746   }
02747   else
02748   {
02749     mProviderKey = "ogr";
02750   }
02751 
02752   if ( ! setDataProvider( mProviderKey ) )
02753   {
02754     return false;
02755   }
02756 
02757   QDomElement pkeyElem = pkeyNode.toElement();
02758   if ( !pkeyElem.isNull() )
02759   {
02760     QString encodingString = pkeyElem.attribute( "encoding" );
02761     if ( !encodingString.isEmpty() )
02762     {
02763       mDataProvider->setEncoding( encodingString );
02764     }
02765   }
02766 
02767   //load vector joins
02768   if ( !mJoinBuffer )
02769   {
02770     mJoinBuffer = new QgsVectorLayerJoinBuffer();
02771   }
02772   mJoinBuffer->readXml( layer_node );
02773 
02774   updateFieldMap();
02775   connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( checkJoinLayerRemove( QString ) ) );
02776 
02777   QString errorMsg;
02778   if ( !readSymbology( layer_node, errorMsg ) )
02779   {
02780     return false;
02781   }
02782 
02783   return mValid;               // should be true if read successfully
02784 
02785 } // void QgsVectorLayer::readXml
02786 
02787 
02788 
02789 bool QgsVectorLayer::setDataProvider( QString const & provider )
02790 {
02791   // XXX should I check for and possibly delete any pre-existing providers?
02792   // XXX How often will that scenario occur?
02793 
02794   mProviderKey = provider;     // XXX is this necessary?  Usually already set
02795   // XXX when execution gets here.
02796 
02797   //XXX - This was a dynamic cast but that kills the Windows
02798   //      version big-time with an abnormal termination error
02799   mDataProvider =
02800     ( QgsVectorDataProvider* )( QgsProviderRegistry::instance()->provider( provider, mDataSource ) );
02801 
02802   if ( mDataProvider )
02803   {
02804     QgsDebugMsg( "Instantiated the data provider plugin" );
02805 
02806     mValid = mDataProvider->isValid();
02807     if ( mValid )
02808     {
02809 
02810       // TODO: Check if the provider has the capability to send fullExtentCalculated
02811       connect( mDataProvider, SIGNAL( fullExtentCalculated() ), this, SLOT( updateExtents() ) );
02812 
02813       // get the extent
02814       QgsRectangle mbr = mDataProvider->extent();
02815 
02816       // show the extent
02817       QString s = mbr.toString();
02818       QgsDebugMsg( "Extent of layer: " +  s );
02819       // store the extent
02820       mLayerExtent.setXMaximum( mbr.xMaximum() );
02821       mLayerExtent.setXMinimum( mbr.xMinimum() );
02822       mLayerExtent.setYMaximum( mbr.yMaximum() );
02823       mLayerExtent.setYMinimum( mbr.yMinimum() );
02824 
02825       // get and store the feature type
02826       mWkbType = mDataProvider->geometryType();
02827 
02828       // look at the fields in the layer and set the primary
02829       // display field using some real fuzzy logic
02830       setDisplayField();
02831 
02832       if ( mProviderKey == "postgres" )
02833       {
02834         QgsDebugMsg( "Beautifying layer name " + name() );
02835 
02836         // adjust the display name for postgres layers
02837         QRegExp reg( "\"[^\"]+\"\\.\"([^\"]+)\"( \\([^)]+\\))?" );
02838         if ( reg.indexIn( name() ) >= 0 )
02839         {
02840           QStringList stuff = reg.capturedTexts();
02841           QString lName = stuff[1];
02842 
02843           const QMap<QString, QgsMapLayer*> &layers = QgsMapLayerRegistry::instance()->mapLayers();
02844 
02845           QMap<QString, QgsMapLayer*>::const_iterator it;
02846           for ( it = layers.constBegin(); it != layers.constEnd() && ( *it )->name() != lName; it++ )
02847             ;
02848 
02849           if ( it != layers.constEnd() && stuff.size() > 2 )
02850           {
02851             lName += "." + stuff[2].mid( 2, stuff[2].length() - 3 );
02852           }
02853 
02854           if ( !lName.isEmpty() )
02855             setLayerName( lName );
02856         }
02857 
02858         QgsDebugMsg( "Beautified layer name " + name() );
02859 
02860         // deal with unnecessary schema qualification to make v.in.ogr happy
02861         mDataSource = mDataProvider->dataSourceUri();
02862       }
02863       else if ( mProviderKey == "osm" )
02864       {
02865         // make sure that the "observer" has been removed from URI to avoid crashes
02866         mDataSource = mDataProvider->dataSourceUri();
02867       }
02868       else if ( provider == "ogr" )
02869       {
02870         // make sure that the /vsigzip or /vsizip is added to uri, if applicable
02871         mDataSource = mDataProvider->dataSourceUri();
02872         if ( mDataSource.right( 10 ) == "|layerid=0" )
02873           mDataSource.chop( 10 );
02874       }
02875 
02876       // label
02877       mLabel = new QgsLabel( mDataProvider->fields() );
02878       mLabelOn = false;
02879     }
02880     else
02881     {
02882       QgsDebugMsg( "Invalid provider plugin " + QString( mDataSource.toUtf8() ) );
02883       return false;
02884     }
02885   }
02886   else
02887   {
02888     QgsDebugMsg( " unable to get data provider" );
02889     return false;
02890   }
02891 
02892   return true;
02893 
02894 } // QgsVectorLayer:: setDataProvider
02895 
02896 
02897 
02898 
02899 /* virtual */
02900 bool QgsVectorLayer::writeXml( QDomNode & layer_node,
02901                                QDomDocument & document )
02902 {
02903   // first get the layer element so that we can append the type attribute
02904 
02905   QDomElement mapLayerNode = layer_node.toElement();
02906 
02907   if ( mapLayerNode.isNull() || ( "maplayer" != mapLayerNode.nodeName() ) )
02908   {
02909     QgsDebugMsg( "can't find <maplayer>" );
02910     return false;
02911   }
02912 
02913   mapLayerNode.setAttribute( "type", "vector" );
02914 
02915   // set the geometry type
02916   mapLayerNode.setAttribute( "geometry", QGis::qgisVectorGeometryType[geometryType()] );
02917 
02918   // add provider node
02919   if ( mDataProvider )
02920   {
02921     QDomElement provider  = document.createElement( "provider" );
02922     provider.setAttribute( "encoding", mDataProvider->encoding() );
02923     QDomText providerText = document.createTextNode( providerType() );
02924     provider.appendChild( providerText );
02925     layer_node.appendChild( provider );
02926   }
02927 
02928   //save joins
02929   mJoinBuffer->writeXml( layer_node, document );
02930 
02931   // renderer specific settings
02932   QString errorMsg;
02933   return writeSymbology( layer_node, document, errorMsg );
02934 } // bool QgsVectorLayer::writeXml
02935 
02936 bool QgsVectorLayer::readSymbology( const QDomNode& node, QString& errorMessage )
02937 {
02938   if ( hasGeometryType() )
02939   {
02940     // try renderer v2 first
02941     QDomElement rendererElement = node.firstChildElement( RENDERER_TAG_NAME );
02942     if ( !rendererElement.isNull() )
02943     {
02944       // using renderer v2
02945       setUsingRendererV2( true );
02946 
02947       QgsFeatureRendererV2* r = QgsFeatureRendererV2::load( rendererElement );
02948       if ( !r )
02949         return false;
02950 
02951       setRendererV2( r );
02952     }
02953     else
02954     {
02955       // using renderer v1
02956       setUsingRendererV2( false );
02957 
02958       // create and bind a renderer to this layer
02959 
02960       QDomNode singlenode = node.namedItem( "singlesymbol" );
02961       QDomNode graduatednode = node.namedItem( "graduatedsymbol" );
02962       QDomNode continuousnode = node.namedItem( "continuoussymbol" );
02963       QDomNode uniquevaluenode = node.namedItem( "uniquevalue" );
02964 
02965       QgsRenderer * renderer = 0;
02966       int returnCode = 1;
02967 
02968       if ( !singlenode.isNull() )
02969       {
02970         renderer = new QgsSingleSymbolRenderer( geometryType() );
02971         returnCode = renderer->readXML( singlenode, *this );
02972       }
02973       else if ( !graduatednode.isNull() )
02974       {
02975         renderer = new QgsGraduatedSymbolRenderer( geometryType() );
02976         returnCode = renderer->readXML( graduatednode, *this );
02977       }
02978       else if ( !continuousnode.isNull() )
02979       {
02980         renderer = new QgsContinuousColorRenderer( geometryType() );
02981         returnCode = renderer->readXML( continuousnode, *this );
02982       }
02983       else if ( !uniquevaluenode.isNull() )
02984       {
02985         renderer = new QgsUniqueValueRenderer( geometryType() );
02986         returnCode = renderer->readXML( uniquevaluenode, *this );
02987       }
02988 
02989       if ( !renderer )
02990       {
02991         errorMessage = tr( "Unknown renderer" );
02992         return false;
02993       }
02994 
02995       if ( returnCode == 1 )
02996       {
02997         errorMessage = tr( "No renderer object" );
02998         delete renderer;
02999         return false;
03000       }
03001       else if ( returnCode == 2 )
03002       {
03003         errorMessage = tr( "Classification field not found" );
03004         delete renderer;
03005         return false;
03006       }
03007 
03008       mRenderer = renderer;
03009     }
03010 
03011     // get and set the display field if it exists.
03012     QDomNode displayFieldNode = node.namedItem( "displayfield" );
03013     if ( !displayFieldNode.isNull() )
03014     {
03015       QDomElement e = displayFieldNode.toElement();
03016       setDisplayField( e.text() );
03017     }
03018 
03019     // use scale dependent visibility flag
03020     QDomElement e = node.toElement();
03021     mLabel->setScaleBasedVisibility( e.attribute( "scaleBasedLabelVisibilityFlag", "0" ) == "1" );
03022     mLabel->setMinScale( e.attribute( "minLabelScale", "1" ).toFloat() );
03023     mLabel->setMaxScale( e.attribute( "maxLabelScale", "100000000" ).toFloat() );
03024 
03025     //also restore custom properties (for labeling-ng)
03026     readCustomProperties( node, "labeling" );
03027 
03028     // Test if labeling is on or off
03029     QDomNode labelnode = node.namedItem( "label" );
03030     QDomElement element = labelnode.toElement();
03031     int hasLabelsEnabled = element.text().toInt();
03032     if ( hasLabelsEnabled < 1 )
03033     {
03034       enableLabels( false );
03035     }
03036     else
03037     {
03038       enableLabels( true );
03039     }
03040 
03041     QDomNode labelattributesnode = node.namedItem( "labelattributes" );
03042 
03043     if ( !labelattributesnode.isNull() )
03044     {
03045       QgsDebugMsg( "calling readXML" );
03046       mLabel->readXML( labelattributesnode );
03047     }
03048 
03049     //diagram renderer and diagram layer settings
03050     delete mDiagramRenderer; mDiagramRenderer = 0;
03051     QDomElement singleCatDiagramElem = node.firstChildElement( "SingleCategoryDiagramRenderer" );
03052     if ( !singleCatDiagramElem.isNull() )
03053     {
03054       mDiagramRenderer = new QgsSingleCategoryDiagramRenderer();
03055       mDiagramRenderer->readXML( singleCatDiagramElem );
03056     }
03057     QDomElement linearDiagramElem = node.firstChildElement( "LinearlyInterpolatedDiagramRenderer" );
03058     if ( !linearDiagramElem.isNull() )
03059     {
03060       mDiagramRenderer = new QgsLinearlyInterpolatedDiagramRenderer();
03061       mDiagramRenderer->readXML( linearDiagramElem );
03062     }
03063 
03064     if ( mDiagramRenderer )
03065     {
03066       QDomElement diagramSettingsElem = node.firstChildElement( "DiagramLayerSettings" );
03067       if ( !diagramSettingsElem.isNull() )
03068       {
03069         mDiagramLayerSettings = new QgsDiagramLayerSettings();
03070         mDiagramLayerSettings->readXML( diagramSettingsElem );
03071       }
03072     }
03073   }
03074 
03075   // process the attribute actions
03076   mActions->readXML( node );
03077 
03078   mEditTypes.clear();
03079   QDomNode editTypesNode = node.namedItem( "edittypes" );
03080   if ( !editTypesNode.isNull() )
03081   {
03082     QDomNodeList editTypeNodes = editTypesNode.childNodes();
03083 
03084     for ( int i = 0; i < editTypeNodes.size(); i++ )
03085     {
03086       QDomNode editTypeNode = editTypeNodes.at( i );
03087       QDomElement editTypeElement = editTypeNode.toElement();
03088 
03089       QString name = editTypeElement.attribute( "name" );
03090       if ( fieldNameIndex( name ) < -1 )
03091         continue;
03092 
03093       EditType editType = ( EditType ) editTypeElement.attribute( "type" ).toInt();
03094       mEditTypes.insert( name, editType );
03095 
03096       switch ( editType )
03097       {
03098         case ValueMap:
03099           if ( editTypeNode.hasChildNodes() )
03100           {
03101             mValueMaps.insert( name, QMap<QString, QVariant>() );
03102 
03103             QDomNodeList valueMapNodes = editTypeNode.childNodes();
03104             for ( int j = 0; j < valueMapNodes.size(); j++ )
03105             {
03106               QDomElement value = valueMapNodes.at( j ).toElement();
03107               mValueMaps[ name ].insert( value.attribute( "key" ), value.attribute( "value" ) );
03108             }
03109           }
03110           break;
03111 
03112         case EditRange:
03113         case SliderRange:
03114         case DialRange:
03115         {
03116           QVariant min = editTypeElement.attribute( "min" );
03117           QVariant max = editTypeElement.attribute( "max" );
03118           QVariant step = editTypeElement.attribute( "step" );
03119 
03120           mRanges[ name ] = RangeData( min, max, step );
03121         }
03122         break;
03123 
03124         case CheckBox:
03125           mCheckedStates[ name ] = QPair<QString, QString>( editTypeElement.attribute( "checked" ), editTypeElement.attribute( "unchecked" ) );
03126           break;
03127 
03128         case ValueRelation:
03129         {
03130           QString id = editTypeElement.attribute( "layer" );
03131           QString key = editTypeElement.attribute( "key" );
03132           QString value = editTypeElement.attribute( "value" );
03133           bool allowNull = editTypeElement.attribute( "allowNull" ) == "true";
03134           bool orderByValue = editTypeElement.attribute( "orderByValue" ) == "true";
03135           mValueRelations[ name ] = ValueRelationData( id, key, value, allowNull, orderByValue );
03136         }
03137         break;
03138 
03139         case Classification:
03140         case FileName:
03141         case Immutable:
03142         case Hidden:
03143         case LineEdit:
03144         case TextEdit:
03145         case Calendar:
03146         case Enumeration:
03147         case UniqueValues:
03148         case UniqueValuesEditable:
03149         case UuidGenerator:
03150           break;
03151       }
03152     }
03153   }
03154 
03155   QDomNode editFormNode = node.namedItem( "editform" );
03156   if ( !editFormNode.isNull() )
03157   {
03158     QDomElement e = editFormNode.toElement();
03159     mEditForm = QgsProject::instance()->readPath( e.text() );
03160   }
03161 
03162   QDomNode editFormInitNode = node.namedItem( "editforminit" );
03163   if ( !editFormInitNode.isNull() )
03164   {
03165     mEditFormInit = editFormInitNode.toElement().text();
03166   }
03167 
03168   QDomNode annotationFormNode = node.namedItem( "annotationform" );
03169   if ( !annotationFormNode.isNull() )
03170   {
03171     QDomElement e = annotationFormNode.toElement();
03172     mAnnotationForm = QgsProject::instance()->readPath( e.text() );
03173   }
03174 
03175   mAttributeAliasMap.clear();
03176   QDomNode aliasesNode = node.namedItem( "aliases" );
03177   if ( !aliasesNode.isNull() )
03178   {
03179     QDomElement aliasElem;
03180     QString name;
03181 
03182     QDomNodeList aliasNodeList = aliasesNode.toElement().elementsByTagName( "alias" );
03183     for ( int i = 0; i < aliasNodeList.size(); ++i )
03184     {
03185       aliasElem = aliasNodeList.at( i ).toElement();
03186 
03187       QString field;
03188       if ( aliasElem.hasAttribute( "field" ) )
03189       {
03190         field = aliasElem.attribute( "field" );
03191       }
03192       else
03193       {
03194         int index = aliasElem.attribute( "index" ).toInt();
03195 
03196         if ( pendingFields().contains( index ) )
03197           field = pendingFields()[ index ].name();
03198       }
03199 
03200       mAttributeAliasMap.insert( field, aliasElem.attribute( "name" ) );
03201     }
03202   }
03203 
03204   return true;
03205 }
03206 
03207 bool QgsVectorLayer::writeSymbology( QDomNode& node, QDomDocument& doc, QString& errorMessage ) const
03208 {
03209   QDomElement mapLayerNode = node.toElement();
03210 
03211   if ( hasGeometryType() )
03212   {
03213     if ( mUsingRendererV2 )
03214     {
03215       QDomElement rendererElement = mRendererV2->save( doc );
03216       node.appendChild( rendererElement );
03217     }
03218     else
03219     {
03220       // use scale dependent visibility flag
03221       mapLayerNode.setAttribute( "scaleBasedLabelVisibilityFlag", mLabel->scaleBasedVisibility() ? 1 : 0 );
03222       mapLayerNode.setAttribute( "minLabelScale", QString::number( mLabel->minScale() ) );
03223       mapLayerNode.setAttribute( "maxLabelScale", QString::number( mLabel->maxScale() ) );
03224 
03225       //classification field(s)
03226       QgsAttributeList attributes = mRenderer->classificationAttributes();
03227       const QgsFieldMap providerFields = mDataProvider->fields();
03228       for ( QgsAttributeList::const_iterator it = attributes.begin(); it != attributes.end(); ++it )
03229       {
03230         QDomElement classificationElement = doc.createElement( "classificationattribute" );
03231         QDomText classificationText = doc.createTextNode( providerFields[*it].name() );
03232         classificationElement.appendChild( classificationText );
03233         node.appendChild( classificationElement );
03234       }
03235 
03236       // renderer settings
03237       const QgsRenderer * myRenderer = renderer();
03238       if ( myRenderer )
03239       {
03240         if ( !myRenderer->writeXML( node, doc, *this ) )
03241         {
03242           errorMessage = tr( "renderer failed to save" );
03243           return false;
03244         }
03245       }
03246       else
03247       {
03248         QgsDebugMsg( "no renderer" );
03249         errorMessage = tr( "no renderer" );
03250         return false;
03251       }
03252     }
03253 
03254     //save customproperties (for labeling ng)
03255     writeCustomProperties( node, doc );
03256 
03257     // add the display field
03258     QDomElement dField  = doc.createElement( "displayfield" );
03259     QDomText dFieldText = doc.createTextNode( displayField() );
03260     dField.appendChild( dFieldText );
03261     node.appendChild( dField );
03262 
03263     // add label node
03264     QDomElement labelElem = doc.createElement( "label" );
03265     QDomText labelText = doc.createTextNode( "" );
03266 
03267     if ( hasLabelsEnabled() )
03268     {
03269       labelText.setData( "1" );
03270     }
03271     else
03272     {
03273       labelText.setData( "0" );
03274     }
03275     labelElem.appendChild( labelText );
03276 
03277     node.appendChild( labelElem );
03278 
03279     // Now we get to do all that all over again for QgsLabel
03280 
03281     QString fieldname = mLabel->labelField( QgsLabel::Text );
03282     if ( fieldname != "" )
03283     {
03284       dField  = doc.createElement( "labelfield" );
03285       dFieldText = doc.createTextNode( fieldname );
03286       dField.appendChild( dFieldText );
03287       node.appendChild( dField );
03288     }
03289 
03290     mLabel->writeXML( node, doc );
03291 
03292     if ( mDiagramRenderer )
03293     {
03294       mDiagramRenderer->writeXML( mapLayerNode, doc );
03295       if ( mDiagramLayerSettings )
03296         mDiagramLayerSettings->writeXML( mapLayerNode, doc );
03297     }
03298   }
03299 
03300   //edit types
03301   if ( mEditTypes.size() > 0 )
03302   {
03303     QDomElement editTypesElement = doc.createElement( "edittypes" );
03304 
03305     for ( QMap<QString, EditType>::const_iterator it = mEditTypes.begin(); it != mEditTypes.end(); ++it )
03306     {
03307       QDomElement editTypeElement = doc.createElement( "edittype" );
03308       editTypeElement.setAttribute( "name", it.key() );
03309       editTypeElement.setAttribute( "type", it.value() );
03310 
03311       switch (( EditType ) it.value() )
03312       {
03313         case ValueMap:
03314           if ( mValueMaps.contains( it.key() ) )
03315           {
03316             const QMap<QString, QVariant> &map = mValueMaps[ it.key()];
03317 
03318             for ( QMap<QString, QVariant>::const_iterator vmit = map.begin(); vmit != map.end(); vmit++ )
03319             {
03320               QDomElement value = doc.createElement( "valuepair" );
03321               value.setAttribute( "key", vmit.key() );
03322               value.setAttribute( "value", vmit.value().toString() );
03323               editTypeElement.appendChild( value );
03324             }
03325           }
03326           break;
03327 
03328         case EditRange:
03329         case SliderRange:
03330         case DialRange:
03331           if ( mRanges.contains( it.key() ) )
03332           {
03333             editTypeElement.setAttribute( "min", mRanges[ it.key()].mMin.toString() );
03334             editTypeElement.setAttribute( "max", mRanges[ it.key()].mMax.toString() );
03335             editTypeElement.setAttribute( "step", mRanges[ it.key()].mStep.toString() );
03336           }
03337           break;
03338 
03339         case CheckBox:
03340           if ( mCheckedStates.contains( it.key() ) )
03341           {
03342             editTypeElement.setAttribute( "checked", mCheckedStates[ it.key()].first );
03343             editTypeElement.setAttribute( "unchecked", mCheckedStates[ it.key()].second );
03344           }
03345           break;
03346 
03347         case ValueRelation:
03348           if ( mValueRelations.contains( it.key() ) )
03349           {
03350             const ValueRelationData &data = mValueRelations[ it.key()];
03351             editTypeElement.setAttribute( "layer", data.mLayer );
03352             editTypeElement.setAttribute( "key", data.mKey );
03353             editTypeElement.setAttribute( "value", data.mValue );
03354             editTypeElement.setAttribute( "allowNull", data.mAllowNull ? "true" : "false" );
03355             editTypeElement.setAttribute( "orderByValue", data.mOrderByValue ? "true" : "false" );
03356           }
03357           break;
03358 
03359         case LineEdit:
03360         case UniqueValues:
03361         case UniqueValuesEditable:
03362         case Classification:
03363         case FileName:
03364         case Hidden:
03365         case TextEdit:
03366         case Calendar:
03367         case Enumeration:
03368         case Immutable:
03369         case UuidGenerator:
03370           break;
03371       }
03372 
03373       editTypesElement.appendChild( editTypeElement );
03374     }
03375 
03376     node.appendChild( editTypesElement );
03377   }
03378 
03379   QDomElement efField  = doc.createElement( "editform" );
03380   QDomText efText = doc.createTextNode( QgsProject::instance()->writePath( mEditForm ) );
03381   efField.appendChild( efText );
03382   node.appendChild( efField );
03383 
03384   QDomElement efiField  = doc.createElement( "editforminit" );
03385   QDomText efiText = doc.createTextNode( mEditFormInit );
03386   efiField.appendChild( efiText );
03387   node.appendChild( efiField );
03388 
03389   QDomElement afField = doc.createElement( "annotationform" );
03390   QDomText afText = doc.createTextNode( QgsProject::instance()->writePath( mAnnotationForm ) );
03391   afField.appendChild( afText );
03392   node.appendChild( afField );
03393 
03394   //attribute aliases
03395   if ( mAttributeAliasMap.size() > 0 )
03396   {
03397     QDomElement aliasElem = doc.createElement( "aliases" );
03398     QMap<QString, QString>::const_iterator a_it = mAttributeAliasMap.constBegin();
03399     for ( ; a_it != mAttributeAliasMap.constEnd(); ++a_it )
03400     {
03401       int idx = fieldNameIndex( a_it.key() );
03402       if ( idx < 0 )
03403         continue;
03404 
03405       QDomElement aliasEntryElem = doc.createElement( "alias" );
03406       aliasEntryElem.setAttribute( "field", a_it.key() );
03407       aliasEntryElem.setAttribute( "index", idx );
03408       aliasEntryElem.setAttribute( "name", a_it.value() );
03409       aliasElem.appendChild( aliasEntryElem );
03410     }
03411     node.appendChild( aliasElem );
03412   }
03413 
03414   // add attribute actions
03415   mActions->writeXML( node, doc );
03416 
03417   //save vector overlays (e.g. diagrams)
03418   QList<QgsVectorOverlay*>::const_iterator overlay_it = mOverlays.constBegin();
03419   for ( ; overlay_it != mOverlays.constEnd(); ++overlay_it )
03420   {
03421     if ( *overlay_it )
03422     {
03423       ( *overlay_it )->writeXML( mapLayerNode, doc );
03424     }
03425   }
03426 
03427   return true;
03428 }
03429 
03430 bool QgsVectorLayer::readSld( const QDomNode& node, QString& errorMessage )
03431 {
03432   // get the Name element
03433   QDomElement nameElem = node.firstChildElement( "Name" );
03434   if ( nameElem.isNull() )
03435   {
03436     errorMessage = "Warning: Name element not found within NamedLayer while it's required.";
03437   }
03438 
03439   if ( hasGeometryType() )
03440   {
03441     setUsingRendererV2( true );
03442 
03443     QgsFeatureRendererV2* r = QgsFeatureRendererV2::loadSld( node, geometryType(), errorMessage );
03444     if ( !r )
03445       return false;
03446 
03447     setRendererV2( r );
03448   }
03449   return true;
03450 }
03451 
03452 
03453 bool QgsVectorLayer::writeSld( QDomNode& node, QDomDocument& doc, QString& errorMessage ) const
03454 {
03455   Q_UNUSED( errorMessage );
03456 
03457   // store the Name element
03458   QDomElement nameNode = doc.createElement( "se:Name" );
03459   nameNode.appendChild( doc.createTextNode( name() ) );
03460   node.appendChild( nameNode );
03461 
03462   if ( hasGeometryType() )
03463   {
03464     if ( mUsingRendererV2 )
03465     {
03466       node.appendChild( mRendererV2->writeSld( doc, *this ) );
03467     }
03468     else
03469     {
03470       node.appendChild( doc.createComment( "Old Renderer not supported yet" ) );
03471       return false;
03472     }
03473   }
03474   return true;
03475 }
03476 
03477 
03478 bool QgsVectorLayer::changeGeometry( QgsFeatureId fid, QgsGeometry* geom )
03479 {
03480   if ( !mEditable || !mDataProvider || !hasGeometryType() )
03481   {
03482     return false;
03483   }
03484 
03485   editGeometryChange( fid, *geom );
03486   mCachedGeometries[fid] = *geom;
03487   setModified( true, true );
03488 
03489   return true;
03490 }
03491 
03492 
03493 bool QgsVectorLayer::changeAttributeValue( QgsFeatureId fid, int field, QVariant value, bool emitSignal )
03494 {
03495   if ( !isEditable() )
03496     return false;
03497 
03498   editAttributeChange( fid, field, value );
03499   setModified( true, false );
03500 
03501   if ( emitSignal )
03502     emit attributeValueChanged( fid, field, value );
03503 
03504   return true;
03505 }
03506 
03507 bool QgsVectorLayer::addAttribute( const QgsField &field )
03508 {
03509   if ( !isEditable() )
03510     return false;
03511 
03512   if ( field.name().isEmpty() )
03513     return false;
03514 
03515   for ( QgsFieldMap::const_iterator it = mUpdatedFields.begin(); it != mUpdatedFields.end(); it++ )
03516   {
03517     if ( it.value().name() == field.name() )
03518       return false;
03519   }
03520 
03521   if ( !mDataProvider->supportedType( field ) )
03522     return false;
03523 
03524   mMaxUpdatedIndex++;
03525 
03526   if ( mActiveCommand != NULL )
03527   {
03528     mActiveCommand->storeAttributeAdd( mMaxUpdatedIndex, field );
03529   }
03530 
03531   mUpdatedFields.insert( mMaxUpdatedIndex, field );
03532   mAddedAttributeIds.insert( mMaxUpdatedIndex );
03533 
03534   setModified( true, false );
03535 
03536   emit attributeAdded( mMaxUpdatedIndex );
03537 
03538   return true;
03539 }
03540 
03541 bool QgsVectorLayer::addAttribute( QString name, QString type )
03542 {
03543   const QList< QgsVectorDataProvider::NativeType > &types = mDataProvider->nativeTypes();
03544 
03545   int i;
03546   for ( i = 0; i < types.size() && types[i].mTypeName != type; i++ )
03547     ;
03548 
03549   return i < types.size() && addAttribute( QgsField( name, types[i].mType, type ) );
03550 }
03551 
03552 void QgsVectorLayer::addAttributeAlias( int attIndex, QString aliasString )
03553 {
03554   if ( !pendingFields().contains( attIndex ) )
03555     return;
03556 
03557   QString name = pendingFields()[ attIndex ].name();
03558 
03559   mAttributeAliasMap.insert( name, aliasString );
03560   emit layerModified( false );
03561 }
03562 
03563 QString QgsVectorLayer::attributeAlias( int attributeIndex ) const
03564 {
03565   if ( !pendingFields().contains( attributeIndex ) )
03566     return "";
03567 
03568   QString name = pendingFields()[ attributeIndex ].name();
03569 
03570   return mAttributeAliasMap.value( name, "" );
03571 }
03572 
03573 QString QgsVectorLayer::attributeDisplayName( int attributeIndex ) const
03574 {
03575   QString displayName = attributeAlias( attributeIndex );
03576   if ( displayName.isEmpty() )
03577   {
03578     const QgsFieldMap& fields = pendingFields();
03579     QgsFieldMap::const_iterator fieldIt = fields.find( attributeIndex );
03580     if ( fieldIt != fields.constEnd() )
03581     {
03582       displayName = fieldIt->name();
03583     }
03584   }
03585   return displayName;
03586 }
03587 
03588 bool QgsVectorLayer::deleteAttribute( int index )
03589 {
03590   if ( !isEditable() )
03591     return false;
03592 
03593   if ( mDeletedAttributeIds.contains( index ) )
03594     return false;
03595 
03596   if ( !mAddedAttributeIds.contains( index ) &&
03597        !mDataProvider->fields().contains( index ) )
03598     return false;
03599 
03600   if ( mActiveCommand != NULL )
03601   {
03602     mActiveCommand->storeAttributeDelete( index, mUpdatedFields[index] );
03603   }
03604 
03605   mDeletedAttributeIds.insert( index );
03606   mAddedAttributeIds.remove( index );
03607   mUpdatedFields.remove( index );
03608 
03609   setModified( true, false );
03610 
03611   emit attributeDeleted( index );
03612 
03613   return true;
03614 }
03615 
03616 bool QgsVectorLayer::deleteFeature( QgsFeatureId fid )
03617 {
03618   if ( !isEditable() )
03619     return false;
03620 
03621   if ( mDeletedFeatureIds.contains( fid ) )
03622     return true;
03623 
03624   mSelectedFeatureIds.remove( fid ); // remove it from selection
03625   editFeatureDelete( fid );
03626 
03627   setModified( true, false );
03628 
03629   emit featureDeleted( fid );
03630 
03631   return true;
03632 }
03633 
03634 const QgsFieldMap &QgsVectorLayer::pendingFields() const
03635 {
03636   return mUpdatedFields;
03637 }
03638 
03639 QgsAttributeList QgsVectorLayer::pendingAllAttributesList()
03640 {
03641   return mUpdatedFields.keys();
03642 }
03643 
03644 int QgsVectorLayer::pendingFeatureCount()
03645 {
03646   return mDataProvider->featureCount()
03647          + mAddedFeatures.size()
03648          - mDeletedFeatureIds.size();
03649 }
03650 
03651 bool QgsVectorLayer::commitChanges()
03652 {
03653   bool success = true;
03654 
03655   //clear the cache image so markers don't appear anymore on next draw
03656   setCacheImage( 0 );
03657 
03658   mCommitErrors.clear();
03659 
03660   if ( !mDataProvider )
03661   {
03662     mCommitErrors << tr( "ERROR: no provider" );
03663     return false;
03664   }
03665 
03666   if ( !isEditable() )
03667   {
03668     mCommitErrors << tr( "ERROR: layer not editable" );
03669     return false;
03670   }
03671 
03672   int cap = mDataProvider->capabilities();
03673 
03674   //
03675   // delete attributes
03676   //
03677   bool attributesChanged = false;
03678   if ( mDeletedAttributeIds.size() > 0 )
03679   {
03680     if (( cap & QgsVectorDataProvider::DeleteAttributes ) && mDataProvider->deleteAttributes( mDeletedAttributeIds ) )
03681     {
03682       mCommitErrors << tr( "SUCCESS: %n attribute(s) deleted.", "deleted attributes count", mDeletedAttributeIds.size() );
03683 
03684       emit committedAttributesDeleted( id(), mDeletedAttributeIds );
03685 
03686       mDeletedAttributeIds.clear();
03687       attributesChanged = true;
03688     }
03689     else
03690     {
03691       mCommitErrors << tr( "ERROR: %n attribute(s) not deleted.", "not deleted attributes count", mDeletedAttributeIds.size() );
03692       success = false;
03693     }
03694   }
03695 
03696   //
03697   // add attributes
03698   //
03699   if ( mAddedAttributeIds.size() > 0 )
03700   {
03701     QList<QgsField> addedAttributes;
03702     for ( QgsAttributeIds::const_iterator it = mAddedAttributeIds.constBegin(); it != mAddedAttributeIds.constEnd(); it++ )
03703     {
03704       addedAttributes << mUpdatedFields[*it];
03705     }
03706 
03707 
03708     if (( cap & QgsVectorDataProvider::AddAttributes ) && mDataProvider->addAttributes( addedAttributes ) )
03709     {
03710       mCommitErrors << tr( "SUCCESS: %n attribute(s) added.", "added attributes count", mAddedAttributeIds.size() );
03711 
03712       emit committedAttributesAdded( id(), addedAttributes );
03713 
03714       mAddedAttributeIds.clear();
03715       attributesChanged = true;
03716     }
03717     else
03718     {
03719       mCommitErrors << tr( "ERROR: %n new attribute(s) not added", "not added attributes count", mAddedAttributeIds.size() );
03720       success = false;
03721     }
03722   }
03723 
03724   //
03725   // remap changed and attributes of added features
03726   //
03727   bool attributeChangesOk = true;
03728   if ( attributesChanged )
03729   {
03730     // map updates field indexes to names
03731     QMap<int, QString> src;
03732     for ( QgsFieldMap::const_iterator it = mUpdatedFields.begin(); it != mUpdatedFields.end(); it++ )
03733     {
03734       src[ it.key()] = it.value().name();
03735     }
03736 
03737     int maxAttrIdx = -1;
03738     const QgsFieldMap &pFields = mDataProvider->fields();
03739 
03740     // map provider table names to field indexes
03741     QMap<QString, int> dst;
03742     for ( QgsFieldMap::const_iterator it = pFields.begin(); it != pFields.end(); it++ )
03743     {
03744       dst[ it.value().name()] = it.key();
03745       if ( it.key() > maxAttrIdx )
03746         maxAttrIdx = it.key();
03747     }
03748 
03749     // if adding attributes failed add fields that are now missing
03750     // (otherwise we'll loose updates when doing the remapping)
03751     if ( mAddedAttributeIds.size() > 0 )
03752     {
03753       for ( QgsAttributeIds::const_iterator it = mAddedAttributeIds.constBegin(); it != mAddedAttributeIds.constEnd(); it++ )
03754       {
03755         QString name =  mUpdatedFields[ *it ].name();
03756         if ( dst.contains( name ) )
03757         {
03758           // it's there => so we don't need to add it anymore
03759           mAddedAttributeIds.remove( *it );
03760           mCommitErrors << tr( "SUCCESS: attribute %1 was added." ).arg( name );
03761         }
03762         else
03763         {
03764           // field not there => put it behind the existing attributes
03765           dst[ name ] = ++maxAttrIdx;
03766           attributeChangesOk = false;   // don't try attribute updates - they'll fail.
03767           mCommitErrors << tr( "ERROR: attribute %1 not added" ).arg( name );
03768         }
03769       }
03770     }
03771 
03772     // map updated fields to provider fields
03773     QMap<int, int> remap;
03774     for ( QMap<int, QString>::const_iterator it = src.begin(); it != src.end(); it++ )
03775     {
03776       if ( dst.contains( it.value() ) )
03777       {
03778         remap[ it.key()] = dst[ it.value()];
03779       }
03780     }
03781 
03782     // remap changed attributes
03783     for ( QgsChangedAttributesMap::iterator fit = mChangedAttributeValues.begin(); fit != mChangedAttributeValues.end(); fit++ )
03784     {
03785       QgsAttributeMap &src = fit.value();
03786       QgsAttributeMap dst;
03787 
03788       for ( QgsAttributeMap::const_iterator it = src.begin(); it != src.end(); it++ )
03789       {
03790         if ( remap.contains( it.key() ) )
03791         {
03792           dst[ remap[it.key()] ] = it.value();
03793         }
03794       }
03795       src = dst;
03796     }
03797 
03798     // remap attributes of added features
03799     for ( QgsFeatureList::iterator fit = mAddedFeatures.begin(); fit != mAddedFeatures.end(); fit++ )
03800     {
03801       const QgsAttributeMap &src = fit->attributeMap();
03802       QgsAttributeMap dst;
03803 
03804       for ( QgsAttributeMap::const_iterator it = src.begin(); it != src.end(); it++ )
03805         if ( remap.contains( it.key() ) )
03806           dst[ remap[it.key()] ] = it.value();
03807 
03808       fit->setAttributeMap( dst );
03809     }
03810 
03811     QgsFieldMap attributes;
03812 
03813     // update private field map
03814     for ( QMap<int, int>::iterator it = remap.begin(); it != remap.end(); it++ )
03815       attributes[ it.value()] = mUpdatedFields[ it.key()];
03816 
03817     mUpdatedFields = attributes;
03818   }
03819 
03820   if ( attributeChangesOk )
03821   {
03822     //
03823     // change attributes
03824     //
03825     if ( mChangedAttributeValues.size() > 0 )
03826     {
03827       if (( cap & QgsVectorDataProvider::ChangeAttributeValues ) && mDataProvider->changeAttributeValues( mChangedAttributeValues ) )
03828       {
03829         mCommitErrors << tr( "SUCCESS: %n attribute value(s) changed.", "changed attribute values count", mChangedAttributeValues.size() );
03830 
03831         emit committedAttributeValuesChanges( id(), mChangedAttributeValues );
03832 
03833         mChangedAttributeValues.clear();
03834       }
03835       else
03836       {
03837         mCommitErrors << tr( "ERROR: %n attribute value change(s) not applied.", "not changed attribute values count", mChangedAttributeValues.size() );
03838         success = false;
03839       }
03840     }
03841 
03842     //
03843     //  add features
03844     //
03845     if ( mAddedFeatures.size() > 0 )
03846     {
03847       for ( int i = 0; i < mAddedFeatures.size(); i++ )
03848       {
03849         QgsFeature &f = mAddedFeatures[i];
03850 
03851         if ( mDeletedFeatureIds.contains( f.id() ) )
03852         {
03853           mDeletedFeatureIds.remove( f.id() );
03854 
03855           if ( mChangedGeometries.contains( f.id() ) )
03856             mChangedGeometries.remove( f.id() );
03857 
03858           mAddedFeatures.removeAt( i-- );
03859           continue;
03860         }
03861 
03862         if ( mChangedGeometries.contains( f.id() ) )
03863         {
03864           f.setGeometry( mChangedGeometries.take( f.id() ) );
03865         }
03866       }
03867 
03868       if ( cap & QgsVectorDataProvider::AddFeatures )
03869       {
03870         QList<QgsFeatureId> ids;
03871         foreach( const QgsFeature &f, mAddedFeatures )
03872         {
03873           ids << f.id();
03874         }
03875 
03876         if ( mDataProvider->addFeatures( mAddedFeatures ) )
03877         {
03878           mCommitErrors << tr( "SUCCESS: %n feature(s) added.", "added features count", mAddedFeatures.size() );
03879 
03880           emit committedFeaturesAdded( id(), mAddedFeatures );
03881 
03882           // notify everyone that the features with temporary ids were updated with permanent ids
03883           for ( int i = 0; i < mAddedFeatures.size(); i++ )
03884           {
03885             if ( mAddedFeatures[i].id() != ids[i] )
03886             {
03887               emit featureDeleted( ids[i] );
03888               emit featureAdded( mAddedFeatures[i].id() );
03889             }
03890           }
03891 
03892           mAddedFeatures.clear();
03893         }
03894         else
03895         {
03896           mCommitErrors << tr( "ERROR: %n feature(s) not added.", "not added features count", mAddedFeatures.size() );
03897           success = false;
03898         }
03899       }
03900       else
03901       {
03902         mCommitErrors << tr( "ERROR: %n feature(s) not added - provider doesn't support adding features.", "not added features count", mAddedFeatures.size() );
03903         success = false;
03904       }
03905     }
03906   }
03907 
03908   //
03909   // update geometries
03910   //
03911   if ( mChangedGeometries.size() > 0 )
03912   {
03913     if (( cap & QgsVectorDataProvider::ChangeGeometries ) && mDataProvider->changeGeometryValues( mChangedGeometries ) )
03914     {
03915       mCommitErrors << tr( "SUCCESS: %n geometries were changed.", "changed geometries count", mChangedGeometries.size() );
03916 
03917       emit committedGeometriesChanges( id(), mChangedGeometries );
03918 
03919       mChangedGeometries.clear();
03920     }
03921     else
03922     {
03923       mCommitErrors << tr( "ERROR: %n geometries not changed.", "not changed geometries count", mChangedGeometries.size() );
03924       success = false;
03925     }
03926   }
03927 
03928   //
03929   // delete features
03930   //
03931   if ( mDeletedFeatureIds.size() > 0 )
03932   {
03933     if (( cap & QgsVectorDataProvider::DeleteFeatures ) && mDataProvider->deleteFeatures( mDeletedFeatureIds ) )
03934     {
03935       mCommitErrors << tr( "SUCCESS: %n feature(s) deleted.", "deleted features count", mDeletedFeatureIds.size() );
03936       for ( QgsFeatureIds::const_iterator it = mDeletedFeatureIds.begin(); it != mDeletedFeatureIds.end(); it++ )
03937       {
03938         mChangedAttributeValues.remove( *it );
03939         mChangedGeometries.remove( *it );
03940       }
03941 
03942       emit committedFeaturesRemoved( id(), mDeletedFeatureIds );
03943 
03944       mDeletedFeatureIds.clear();
03945     }
03946     else
03947     {
03948       mCommitErrors << tr( "ERROR: %n feature(s) not deleted.", "not deleted features count", mDeletedFeatureIds.size() );
03949       success = false;
03950     }
03951   }
03952 
03953   if ( !success )
03954   {
03955     if ( mDataProvider->hasErrors() )
03956     {
03957       mCommitErrors << tr( "\n  Provider errors:" ) << mDataProvider->errors();
03958       mDataProvider->clearErrors();
03959     }
03960 
03961     QgsMessageLog::logMessage( tr( "Commit errors:\n  %1" ).arg( mCommitErrors.join( "\n  " ) ) );
03962   }
03963 
03964   deleteCachedGeometries();
03965 
03966   if ( success )
03967   {
03968     mEditable = false;
03969     setModified( false );
03970     undoStack()->clear();
03971     emit editingStopped();
03972   }
03973 
03974   updateFieldMap();
03975   mDataProvider->updateExtents();
03976 
03977   return success;
03978 }
03979 
03980 const QStringList &QgsVectorLayer::commitErrors()
03981 {
03982   return mCommitErrors;
03983 }
03984 
03985 bool QgsVectorLayer::rollBack()
03986 {
03987   if ( !isEditable() )
03988   {
03989     return false;
03990   }
03991 
03992   if ( isModified() )
03993   {
03994     while ( undoStack()->canUndo() )
03995     {
03996       undoStack()->undo();
03997     }
03998 
03999     Q_ASSERT( mAddedAttributeIds.isEmpty() );
04000     Q_ASSERT( mDeletedAttributeIds.isEmpty() );
04001     Q_ASSERT( mChangedAttributeValues.isEmpty() );
04002     Q_ASSERT( mChangedGeometries.isEmpty() );
04003     Q_ASSERT( mAddedFeatures.isEmpty() );
04004 
04005     updateFieldMap();
04006   }
04007 
04008   deleteCachedGeometries();
04009 
04010   mEditable = false;
04011   emit editingStopped();
04012 
04013   setModified( false );
04014   // invalidate the cache so the layer updates properly to show its original
04015   // after the rollback
04016   setCacheImage( 0 );
04017   return true;
04018 }
04019 
04020 void QgsVectorLayer::setSelectedFeatures( const QgsFeatureIds& ids )
04021 {
04022   // TODO: check whether features with these ID exist
04023   mSelectedFeatureIds = ids;
04024 
04025   // invalidate cache
04026   setCacheImage( 0 );
04027 
04028   emit selectionChanged();
04029 }
04030 
04031 int QgsVectorLayer::selectedFeatureCount()
04032 {
04033   return mSelectedFeatureIds.size();
04034 }
04035 
04036 const QgsFeatureIds& QgsVectorLayer::selectedFeaturesIds() const
04037 {
04038   return mSelectedFeatureIds;
04039 }
04040 
04041 
04042 QgsFeatureList QgsVectorLayer::selectedFeatures()
04043 {
04044   QgsFeatureList features;
04045 
04046   foreach( QgsFeatureId fid, mSelectedFeatureIds )
04047   {
04048     features.push_back( QgsFeature() );
04049     featureAtId( fid, features.back(), geometryType() != QGis::NoGeometry, true );
04050   }
04051 
04052   return features;
04053 }
04054 
04055 bool QgsVectorLayer::addFeatures( QgsFeatureList features, bool makeSelected )
04056 {
04057   if ( !mDataProvider )
04058   {
04059     return false;
04060   }
04061 
04062   if ( !( mDataProvider->capabilities() & QgsVectorDataProvider::AddFeatures ) )
04063   {
04064     return false;
04065   }
04066 
04067   if ( !isEditable() )
04068   {
04069     return false;
04070   }
04071 
04072   if ( makeSelected )
04073   {
04074     mSelectedFeatureIds.clear();
04075   }
04076 
04077   for ( QgsFeatureList::iterator iter = features.begin(); iter != features.end(); ++iter )
04078   {
04079     addFeature( *iter );
04080 
04081     if ( makeSelected )
04082     {
04083       mSelectedFeatureIds.insert( iter->id() );
04084     }
04085   }
04086 
04087   updateExtents();
04088 
04089   if ( makeSelected )
04090   {
04091     // invalidate cache
04092     setCacheImage( 0 );
04093 
04094     emit selectionChanged();
04095   }
04096 
04097   return true;
04098 }
04099 
04100 
04101 bool QgsVectorLayer::copySymbologySettings( const QgsMapLayer& other )
04102 {
04103   if ( !hasGeometryType() )
04104     return false;
04105 
04106   const QgsVectorLayer* vl = qobject_cast<const QgsVectorLayer *>( &other );
04107 
04108   // exit if both vectorlayer are the same
04109   if ( this == vl )
04110   {
04111     return false;
04112   }
04113 
04114   if ( !vl )
04115   {
04116     return false;
04117   }
04118   delete mRenderer;
04119 
04120   QgsRenderer* r = vl->mRenderer;
04121   if ( r )
04122   {
04123     mRenderer = r->clone();
04124     return true;
04125   }
04126   else
04127   {
04128     return false;
04129   }
04130 }
04131 
04132 bool QgsVectorLayer::hasCompatibleSymbology( const QgsMapLayer& other ) const
04133 {
04134   // vector layers are symbology compatible if they have the same type, the same sequence of numerical/ non numerical fields and the same field names
04135 
04136   const QgsVectorLayer* otherVectorLayer = qobject_cast<const QgsVectorLayer *>( &other );
04137   if ( otherVectorLayer )
04138   {
04139     if ( otherVectorLayer->type() != type() )
04140     {
04141       return false;
04142     }
04143 
04144     const QgsFieldMap& fieldsThis = mDataProvider->fields();
04145     const QgsFieldMap& fieldsOther = otherVectorLayer ->mDataProvider->fields();
04146 
04147     if ( fieldsThis.size() != fieldsOther.size() )
04148     {
04149       return false;
04150     }
04151 
04152     // TODO: fill two sets with the numerical types for both layers
04153 
04154     uint fieldsThisSize = fieldsThis.size();
04155 
04156     for ( uint i = 0; i < fieldsThisSize; ++i )
04157     {
04158       if ( fieldsThis[i].name() != fieldsOther[i].name() ) // field names need to be the same
04159       {
04160         return false;
04161       }
04162       // TODO: compare types of the fields
04163     }
04164     return true; // layers are symbology compatible if the code reaches this point
04165   }
04166   return false;
04167 }
04168 
04169 bool QgsVectorLayer::snapPoint( QgsPoint& point, double tolerance )
04170 {
04171   if ( !hasGeometryType() )
04172     return false;
04173 
04174   QMultiMap<double, QgsSnappingResult> snapResults;
04175   int result = snapWithContext( point, tolerance, snapResults, QgsSnapper::SnapToVertex );
04176 
04177   if ( result != 0 )
04178   {
04179     return false;
04180   }
04181 
04182   if ( snapResults.size() < 1 )
04183   {
04184     return false;
04185   }
04186 
04187   QMultiMap<double, QgsSnappingResult>::const_iterator snap_it = snapResults.constBegin();
04188   point.setX( snap_it.value().snappedVertex.x() );
04189   point.setY( snap_it.value().snappedVertex.y() );
04190   return true;
04191 }
04192 
04193 
04194 int QgsVectorLayer::snapWithContext( const QgsPoint& startPoint, double snappingTolerance,
04195                                      QMultiMap<double, QgsSnappingResult>& snappingResults,
04196                                      QgsSnapper::SnappingType snap_to )
04197 {
04198   if ( !hasGeometryType() )
04199     return 1;
04200 
04201   if ( snappingTolerance <= 0 || !mDataProvider )
04202   {
04203     return 1;
04204   }
04205 
04206   QList<QgsFeature> featureList;
04207   QgsRectangle searchRect( startPoint.x() - snappingTolerance, startPoint.y() - snappingTolerance,
04208                            startPoint.x() + snappingTolerance, startPoint.y() + snappingTolerance );
04209   double sqrSnappingTolerance = snappingTolerance * snappingTolerance;
04210 
04211   int n = 0;
04212   QgsFeature f;
04213 
04214   if ( mCachedGeometriesRect.contains( searchRect ) )
04215   {
04216     QgsGeometryMap::iterator it = mCachedGeometries.begin();
04217     for ( ; it != mCachedGeometries.end() ; ++it )
04218     {
04219       QgsGeometry* g = &( it.value() );
04220       if ( g->boundingBox().intersects( searchRect ) )
04221       {
04222         snapToGeometry( startPoint, it.key(), g, sqrSnappingTolerance, snappingResults, snap_to );
04223         ++n;
04224       }
04225     }
04226   }
04227   else
04228   {
04229     // snapping outside cached area
04230 
04231     select( QgsAttributeList(), searchRect, true, true );
04232 
04233     while ( nextFeature( f ) )
04234     {
04235       snapToGeometry( startPoint, f.id(), f.geometry(), sqrSnappingTolerance, snappingResults, snap_to );
04236       ++n;
04237     }
04238   }
04239 
04240   return n == 0 ? 2 : 0;
04241 }
04242 
04243 void QgsVectorLayer::snapToGeometry( const QgsPoint& startPoint,
04244                                      QgsFeatureId featureId,
04245                                      QgsGeometry* geom,
04246                                      double sqrSnappingTolerance,
04247                                      QMultiMap<double, QgsSnappingResult>& snappingResults,
04248                                      QgsSnapper::SnappingType snap_to ) const
04249 {
04250   if ( !geom )
04251   {
04252     return;
04253   }
04254 
04255   int atVertex, beforeVertex, afterVertex;
04256   double sqrDistVertexSnap, sqrDistSegmentSnap;
04257   QgsPoint snappedPoint;
04258   QgsSnappingResult snappingResultVertex;
04259   QgsSnappingResult snappingResultSegment;
04260 
04261   if ( snap_to == QgsSnapper::SnapToVertex || snap_to == QgsSnapper::SnapToVertexAndSegment )
04262   {
04263     snappedPoint = geom->closestVertex( startPoint, atVertex, beforeVertex, afterVertex, sqrDistVertexSnap );
04264     if ( sqrDistVertexSnap < sqrSnappingTolerance )
04265     {
04266       snappingResultVertex.snappedVertex = snappedPoint;
04267       snappingResultVertex.snappedVertexNr = atVertex;
04268       snappingResultVertex.beforeVertexNr = beforeVertex;
04269       if ( beforeVertex != -1 ) // make sure the vertex is valid
04270       {
04271         snappingResultVertex.beforeVertex = geom->vertexAt( beforeVertex );
04272       }
04273       snappingResultVertex.afterVertexNr = afterVertex;
04274       if ( afterVertex != -1 ) // make sure the vertex is valid
04275       {
04276         snappingResultVertex.afterVertex = geom->vertexAt( afterVertex );
04277       }
04278       snappingResultVertex.snappedAtGeometry = featureId;
04279       snappingResultVertex.layer = this;
04280       snappingResults.insert( sqrt( sqrDistVertexSnap ), snappingResultVertex );
04281       return;
04282     }
04283   }
04284   if ( snap_to == QgsSnapper::SnapToSegment || snap_to == QgsSnapper::SnapToVertexAndSegment ) // snap to segment
04285   {
04286     if ( geometryType() != QGis::Point ) // cannot snap to segment for points/multipoints
04287     {
04288       sqrDistSegmentSnap = geom->closestSegmentWithContext( startPoint, snappedPoint, afterVertex, NULL, crs().geographicFlag() ? 1e-12 : 1e-8 );
04289 
04290       if ( sqrDistSegmentSnap < sqrSnappingTolerance )
04291       {
04292         snappingResultSegment.snappedVertex = snappedPoint;
04293         snappingResultSegment.snappedVertexNr = -1;
04294         snappingResultSegment.beforeVertexNr = afterVertex - 1;
04295         snappingResultSegment.afterVertexNr = afterVertex;
04296         snappingResultSegment.snappedAtGeometry = featureId;
04297         snappingResultSegment.beforeVertex = geom->vertexAt( afterVertex - 1 );
04298         snappingResultSegment.afterVertex = geom->vertexAt( afterVertex );
04299         snappingResultSegment.layer = this;
04300         snappingResults.insert( sqrt( sqrDistSegmentSnap ), snappingResultSegment );
04301       }
04302     }
04303   }
04304 }
04305 
04306 int QgsVectorLayer::insertSegmentVerticesForSnap( const QList<QgsSnappingResult>& snapResults )
04307 {
04308   if ( !hasGeometryType() )
04309     return 1;
04310 
04311   int returnval = 0;
04312   QgsPoint layerPoint;
04313 
04314   QList<QgsSnappingResult>::const_iterator it = snapResults.constBegin();
04315   for ( ; it != snapResults.constEnd(); ++it )
04316   {
04317     if ( it->snappedVertexNr == -1 ) // segment snap
04318     {
04319       layerPoint = it->snappedVertex;
04320       if ( !insertVertex( layerPoint.x(), layerPoint.y(), it->snappedAtGeometry, it->afterVertexNr ) )
04321       {
04322         returnval = 3;
04323       }
04324     }
04325   }
04326   return returnval;
04327 }
04328 
04329 int QgsVectorLayer::boundingBoxFromPointList( const QList<QgsPoint>& list, double& xmin, double& ymin, double& xmax, double& ymax ) const
04330 {
04331   if ( list.size() < 1 )
04332   {
04333     return 1;
04334   }
04335 
04336   xmin = std::numeric_limits<double>::max();
04337   xmax = -std::numeric_limits<double>::max();
04338   ymin = std::numeric_limits<double>::max();
04339   ymax = -std::numeric_limits<double>::max();
04340 
04341   for ( QList<QgsPoint>::const_iterator it = list.constBegin(); it != list.constEnd(); ++it )
04342   {
04343     if ( it->x() < xmin )
04344     {
04345       xmin = it->x();
04346     }
04347     if ( it->x() > xmax )
04348     {
04349       xmax = it->x();
04350     }
04351     if ( it->y() < ymin )
04352     {
04353       ymin = it->y();
04354     }
04355     if ( it->y() > ymax )
04356     {
04357       ymax = it->y();
04358     }
04359   }
04360 
04361   return 0;
04362 }
04363 
04364 QgsVectorLayer::VertexMarkerType QgsVectorLayer::currentVertexMarkerType()
04365 {
04366   QSettings settings;
04367   QString markerTypeString = settings.value( "/qgis/digitizing/marker_style", "Cross" ).toString();
04368   if ( markerTypeString == "Cross" )
04369   {
04370     return QgsVectorLayer::Cross;
04371   }
04372   else if ( markerTypeString == "SemiTransparentCircle" )
04373   {
04374     return QgsVectorLayer::SemiTransparentCircle;
04375   }
04376   else
04377   {
04378     return QgsVectorLayer::NoMarker;
04379   }
04380 }
04381 
04382 int QgsVectorLayer::currentVertexMarkerSize()
04383 {
04384   QSettings settings;
04385   return settings.value( "/qgis/digitizing/marker_size", 3 ).toInt();
04386 }
04387 
04388 void QgsVectorLayer::drawFeature( QgsRenderContext &renderContext,
04389                                   QgsFeature& fet,
04390                                   QImage * marker )
04391 {
04392   QPainter *p = renderContext.painter();
04393   // Only have variables, etc outside the switch() statement that are
04394   // used in all cases of the statement (otherwise they may get
04395   // executed, but never used, in a bit of code where performance is
04396   // critical).
04397   if ( ! fet.isValid() )
04398   {
04399     return;
04400   }
04401 
04402   QgsGeometry* geom = fet.geometry();
04403   if ( !geom )
04404   {
04405     return;
04406   }
04407   unsigned char* feature = geom->asWkb();
04408 
04409   QGis::WkbType wkbType = geom->wkbType();
04410 
04411   switch ( wkbType )
04412   {
04413     case QGis::WKBPoint:
04414     case QGis::WKBPoint25D:
04415     {
04416       double x = *(( double * )( feature + 5 ) );
04417       double y = *(( double * )( feature + 5 + sizeof( double ) ) );
04418 
04419       transformPoint( x, y, &renderContext.mapToPixel(), renderContext.coordinateTransform() );
04420       if ( qAbs( x ) > QgsClipper::MAX_X ||
04421            qAbs( y ) > QgsClipper::MAX_Y )
04422       {
04423         break;
04424       }
04425 
04426       //QPointF pt(x - (marker->width()/2),  y - (marker->height()/2));
04427       QPointF pt( x * renderContext.rasterScaleFactor() - ( marker->width() / 2 ),
04428                   y * renderContext.rasterScaleFactor() - ( marker->height() / 2 ) );
04429 
04430       p->save();
04431       //p->scale(markerScaleFactor,markerScaleFactor);
04432       p->scale( 1.0 / renderContext.rasterScaleFactor(), 1.0 / renderContext.rasterScaleFactor() );
04433       p->drawImage( pt, *marker );
04434       p->restore();
04435 
04436       break;
04437     }
04438     case QGis::WKBMultiPoint:
04439     case QGis::WKBMultiPoint25D:
04440     {
04441       unsigned char *ptr = feature + 5;
04442       unsigned int nPoints = *(( int* )ptr );
04443       ptr += 4;
04444 
04445       p->save();
04446       //p->scale(markerScaleFactor, markerScaleFactor);
04447       p->scale( 1.0 / renderContext.rasterScaleFactor(), 1.0 / renderContext.rasterScaleFactor() );
04448 
04449       for ( register unsigned int i = 0; i < nPoints; ++i )
04450       {
04451         ptr += 5;
04452         double x = *(( double * ) ptr );
04453         ptr += sizeof( double );
04454         double y = *(( double * ) ptr );
04455         ptr += sizeof( double );
04456 
04457         if ( wkbType == QGis::WKBMultiPoint25D ) // ignore Z value
04458           ptr += sizeof( double );
04459 
04460         transformPoint( x, y, &renderContext.mapToPixel(), renderContext.coordinateTransform() );
04461         //QPointF pt(x - (marker->width()/2),  y - (marker->height()/2));
04462         //QPointF pt(x/markerScaleFactor - (marker->width()/2),  y/markerScaleFactor - (marker->height()/2));
04463         QPointF pt( x * renderContext.rasterScaleFactor() - ( marker->width() / 2 ),
04464                     y * renderContext.rasterScaleFactor() - ( marker->height() / 2 ) );
04465         //QPointF pt( x, y );
04466 
04467         // Work around a +/- 32768 limitation on coordinates
04468         if ( qAbs( x ) <= QgsClipper::MAX_X &&
04469              qAbs( y ) <= QgsClipper::MAX_Y )
04470           p->drawImage( pt, *marker );
04471       }
04472       p->restore();
04473 
04474       break;
04475     }
04476     case QGis::WKBLineString:
04477     case QGis::WKBLineString25D:
04478     {
04479       drawLineString( feature, renderContext );
04480       break;
04481     }
04482     case QGis::WKBMultiLineString:
04483     case QGis::WKBMultiLineString25D:
04484     {
04485       unsigned char* ptr = feature + 5;
04486       unsigned int numLineStrings = *(( int* )ptr );
04487       ptr = feature + 9;
04488 
04489       for ( register unsigned int jdx = 0; jdx < numLineStrings; jdx++ )
04490       {
04491         ptr = drawLineString( ptr, renderContext );
04492       }
04493       break;
04494     }
04495     case QGis::WKBPolygon:
04496     case QGis::WKBPolygon25D:
04497     {
04498       drawPolygon( feature, renderContext );
04499       break;
04500     }
04501     case QGis::WKBMultiPolygon:
04502     case QGis::WKBMultiPolygon25D:
04503     {
04504       unsigned char *ptr = feature + 5;
04505       unsigned int numPolygons = *(( int* )ptr );
04506       ptr = feature + 9;
04507       for ( register unsigned int kdx = 0; kdx < numPolygons; kdx++ )
04508         ptr = drawPolygon( ptr, renderContext );
04509       break;
04510     }
04511     default:
04512       QgsDebugMsg( "Unknown WkbType ENCOUNTERED" );
04513       break;
04514   }
04515 }
04516 
04517 
04518 
04519 void QgsVectorLayer::setCoordinateSystem()
04520 {
04521   QgsDebugMsg( "----- Computing Coordinate System" );
04522 
04523   //
04524   // Get the layers project info and set up the QgsCoordinateTransform
04525   // for this layer
04526   //
04527 
04528   if ( hasGeometryType() )
04529   {
04530     // get CRS directly from provider
04531     setCrs( mDataProvider->crs() );
04532   }
04533   else
04534   {
04535     setCrs( QgsCoordinateReferenceSystem( GEO_EPSG_CRS_AUTHID ) );
04536   }
04537 }
04538 
04539 // Convenience function to transform the given point
04540 inline void QgsVectorLayer::transformPoint(
04541   double& x, double& y,
04542   const QgsMapToPixel* mtp,
04543   const QgsCoordinateTransform* ct )
04544 {
04545   // transform the point
04546   if ( ct )
04547   {
04548     double z = 0;
04549     ct->transformInPlace( x, y, z );
04550   }
04551 
04552   // transform from projected coordinate system to pixel
04553   // position on map canvas
04554   mtp->transformInPlace( x, y );
04555 }
04556 
04557 inline void QgsVectorLayer::transformPoints(
04558   std::vector<double>& x, std::vector<double>& y, std::vector<double>& z,
04559   QgsRenderContext &renderContext )
04560 {
04561   // transform the point
04562   if ( renderContext.coordinateTransform() )
04563     renderContext.coordinateTransform()->transformInPlace( x, y, z );
04564 
04565   // transform from projected coordinate system to pixel
04566   // position on map canvas
04567   renderContext.mapToPixel().transformInPlace( x, y );
04568 }
04569 
04570 
04571 const QString QgsVectorLayer::displayField() const
04572 {
04573   return mDisplayField;
04574 }
04575 
04576 bool QgsVectorLayer::isEditable() const
04577 {
04578   return ( mEditable && mDataProvider );
04579 }
04580 
04581 bool QgsVectorLayer::isReadOnly() const
04582 {
04583   return mReadOnly;
04584 }
04585 
04586 bool QgsVectorLayer::setReadOnly( bool readonly )
04587 {
04588   // exit if the layer is in editing mode
04589   if ( readonly && mEditable )
04590     return false;
04591 
04592   mReadOnly = readonly;
04593   return true;
04594 }
04595 
04596 bool QgsVectorLayer::isModified() const
04597 {
04598   return mModified;
04599 }
04600 
04601 void QgsVectorLayer::setModified( bool modified, bool onlyGeometry )
04602 {
04603   mModified = modified;
04604   emit layerModified( onlyGeometry );
04605 }
04606 
04607 QgsVectorLayer::EditType QgsVectorLayer::editType( int idx )
04608 {
04609   const QgsFieldMap &fields = pendingFields();
04610   if ( fields.contains( idx ) && mEditTypes.contains( fields[idx].name() ) )
04611     return mEditTypes[ fields[idx].name()];
04612   else
04613     return LineEdit;
04614 }
04615 
04616 void QgsVectorLayer::setEditType( int idx, EditType type )
04617 {
04618   const QgsFieldMap &fields = pendingFields();
04619   if ( fields.contains( idx ) )
04620     mEditTypes[ fields[idx].name()] = type;
04621 }
04622 
04623 QString QgsVectorLayer::editForm()
04624 {
04625   return mEditForm;
04626 }
04627 
04628 void QgsVectorLayer::setEditForm( QString ui )
04629 {
04630   mEditForm = ui;
04631 }
04632 
04633 void QgsVectorLayer::setAnnotationForm( const QString& ui )
04634 {
04635   mAnnotationForm = ui;
04636 }
04637 
04638 QString QgsVectorLayer::editFormInit()
04639 {
04640   return mEditFormInit;
04641 }
04642 
04643 void QgsVectorLayer::setEditFormInit( QString function )
04644 {
04645   mEditFormInit = function;
04646 }
04647 
04648 QMap< QString, QVariant > &QgsVectorLayer::valueMap( int idx )
04649 {
04650   const QgsFieldMap &fields = pendingFields();
04651 
04652   // FIXME: throw an exception!?
04653   if ( !fields.contains( idx ) )
04654   {
04655     QgsDebugMsg( QString( "field %1 not found" ).arg( idx ) );
04656   }
04657 
04658   if ( !mValueMaps.contains( fields[idx].name() ) )
04659     mValueMaps[ fields[idx].name()] = QMap<QString, QVariant>();
04660 
04661   return mValueMaps[ fields[idx].name()];
04662 }
04663 
04664 QgsVectorLayer::RangeData &QgsVectorLayer::range( int idx )
04665 {
04666   const QgsFieldMap &fields = pendingFields();
04667 
04668   // FIXME: throw an exception!?
04669   if ( fields.contains( idx ) )
04670   {
04671     QgsDebugMsg( QString( "field %1 not found" ).arg( idx ) );
04672   }
04673 
04674   if ( !mRanges.contains( fields[idx].name() ) )
04675     mRanges[ fields[idx].name()] = RangeData();
04676 
04677   return mRanges[ fields[idx].name()];
04678 }
04679 
04680 void QgsVectorLayer::addOverlay( QgsVectorOverlay* overlay )
04681 {
04682   mOverlays.push_back( overlay );
04683 }
04684 
04685 void QgsVectorLayer::removeOverlay( const QString& typeName )
04686 {
04687   for ( int i = mOverlays.size() - 1; i >= 0; --i )
04688   {
04689     if ( mOverlays.at( i )->typeName() == typeName )
04690     {
04691       mOverlays.removeAt( i );
04692     }
04693   }
04694 }
04695 
04696 void QgsVectorLayer::vectorOverlays( QList<QgsVectorOverlay*>& overlayList )
04697 {
04698   overlayList = mOverlays;
04699 }
04700 
04701 QgsVectorOverlay* QgsVectorLayer::findOverlayByType( const QString& typeName )
04702 {
04703   QList<QgsVectorOverlay*>::iterator it = mOverlays.begin();
04704   for ( ; it != mOverlays.end(); ++it )
04705   {
04706     if (( *it )->typeName() == typeName )
04707     {
04708       return *it;
04709     }
04710   }
04711   return 0; //not found
04712 }
04713 
04714 
04715 QgsFeatureRendererV2* QgsVectorLayer::rendererV2()
04716 {
04717   return mRendererV2;
04718 }
04719 
04720 void QgsVectorLayer::setRendererV2( QgsFeatureRendererV2 *r )
04721 {
04722   if ( !hasGeometryType() )
04723     return;
04724 
04725   if ( r != mRendererV2 )
04726   {
04727     if ( r )
04728       setUsingRendererV2( true );
04729     delete mRendererV2;
04730     mRendererV2 = r;
04731   }
04732 }
04733 bool QgsVectorLayer::isUsingRendererV2()
04734 {
04735   return mUsingRendererV2;
04736 }
04737 void QgsVectorLayer::setUsingRendererV2( bool usingRendererV2 )
04738 {
04739   if ( !hasGeometryType() )
04740     return;
04741 
04742   mUsingRendererV2 = usingRendererV2;
04743 }
04744 
04745 
04746 void QgsVectorLayer::editGeometryChange( QgsFeatureId featureId, QgsGeometry& geometry )
04747 {
04748   if ( mActiveCommand )
04749   {
04750     mActiveCommand->storeGeometryChange( featureId, mChangedGeometries[ featureId ], geometry );
04751   }
04752   mChangedGeometries[ featureId ] = geometry;
04753   emit geometryChanged( featureId, geometry );
04754 }
04755 
04756 
04757 void QgsVectorLayer::editFeatureAdd( QgsFeature& feature )
04758 {
04759   if ( mActiveCommand )
04760   {
04761     mActiveCommand->storeFeatureAdd( feature );
04762   }
04763   mAddedFeatures.append( feature );
04764 }
04765 
04766 void QgsVectorLayer::editFeatureDelete( QgsFeatureId featureId )
04767 {
04768   if ( mActiveCommand )
04769   {
04770     mActiveCommand->storeFeatureDelete( featureId );
04771   }
04772   mDeletedFeatureIds.insert( featureId );
04773 }
04774 
04775 void QgsVectorLayer::editAttributeChange( QgsFeatureId featureId, int field, QVariant value )
04776 {
04777   if ( mActiveCommand != NULL )
04778   {
04779     QVariant original;
04780     bool isFirstChange = true;
04781     if ( featureId < 0 )
04782     {
04783       // work with added feature
04784       for ( int i = 0; i < mAddedFeatures.size(); i++ )
04785       {
04786         if ( mAddedFeatures[i].id() == featureId && mAddedFeatures[i].attributeMap().contains( field ) )
04787         {
04788           original = mAddedFeatures[i].attributeMap()[field];
04789           isFirstChange = false;
04790           break;
04791         }
04792       }
04793     }
04794     else
04795     {
04796       if ( mChangedAttributeValues.contains( featureId ) && mChangedAttributeValues[featureId].contains( field ) )
04797       {
04798         original = mChangedAttributeValues[featureId][field];
04799         isFirstChange = false;
04800       }
04801     }
04802     mActiveCommand->storeAttributeChange( featureId, field, original, value, isFirstChange );
04803   }
04804 
04805   if ( !FID_IS_NEW( featureId ) )
04806   {
04807     // changed attribute of existing feature
04808     if ( !mChangedAttributeValues.contains( featureId ) )
04809     {
04810       mChangedAttributeValues.insert( featureId, QgsAttributeMap() );
04811     }
04812 
04813     mChangedAttributeValues[featureId].insert( field, value );
04814   }
04815   else
04816   {
04817     // updated added feature
04818     for ( int i = 0; i < mAddedFeatures.size(); i++ )
04819     {
04820       if ( mAddedFeatures[i].id() == featureId )
04821       {
04822         mAddedFeatures[i].changeAttribute( field, value );
04823         break;
04824       }
04825     }
04826   }
04827 }
04828 
04829 void QgsVectorLayer::beginEditCommand( QString text )
04830 {
04831   if ( !mActiveCommand )
04832   {
04833     mActiveCommand = new QgsUndoCommand( this, text );
04834   }
04835 }
04836 
04837 void QgsVectorLayer::endEditCommand()
04838 {
04839   if ( mActiveCommand )
04840   {
04841     undoStack()->push( mActiveCommand );
04842     mActiveCommand = 0;
04843   }
04844 
04845 }
04846 
04847 void QgsVectorLayer::destroyEditCommand()
04848 {
04849   if ( mActiveCommand )
04850   {
04851     undoEditCommand( mActiveCommand );
04852     delete mActiveCommand;
04853     mActiveCommand = 0;
04854   }
04855 
04856 }
04857 
04858 void QgsVectorLayer::redoEditCommand( QgsUndoCommand* cmd )
04859 {
04860   QMap<QgsFeatureId, QgsUndoCommand::GeometryChangeEntry>& geometryChange = cmd->mGeometryChange;
04861   QgsFeatureIds& deletedFeatureIdChange = cmd->mDeletedFeatureIdChange;
04862   QgsFeatureList& addedFeatures = cmd->mAddedFeatures;
04863   QMap<QgsFeatureId, QgsUndoCommand::AttributeChanges>& attributeChange = cmd->mAttributeChange;
04864   QgsFieldMap& addedAttributes = cmd->mAddedAttributes;
04865   QgsFieldMap& deletedAttributes = cmd->mDeletedAttributes;
04866 
04867 
04868   // geometry changes
04869   QMap<QgsFeatureId, QgsUndoCommand::GeometryChangeEntry>::iterator it = geometryChange.begin();
04870   for ( ; it != geometryChange.end(); ++it )
04871   {
04872     if ( !it.value().target )
04873     {
04874       mChangedGeometries.remove( it.key() );
04875 
04876       QgsFeature f;
04877       if ( featureAtId( it.key(), f, true, false ) && f.geometry() )
04878       {
04879         emit geometryChanged( it.key(), *f.geometry() );
04880       }
04881     }
04882     else
04883     {
04884       mChangedGeometries[it.key()] = *it.value().target;
04885       emit geometryChanged( it.key(), *it.value().target );
04886     }
04887   }
04888 
04889   // deleted features
04890   QgsFeatureIds::iterator delIt = deletedFeatureIdChange.begin();
04891   for ( ; delIt != deletedFeatureIdChange.end(); ++delIt )
04892   {
04893     mDeletedFeatureIds.insert( *delIt );
04894     emit featureDeleted( *delIt );
04895   }
04896 
04897   // added features
04898   QgsFeatureList::iterator addIt = addedFeatures.begin();
04899   for ( ; addIt != addedFeatures.end(); ++addIt )
04900   {
04901     mAddedFeatures.append( *addIt );
04902     emit featureAdded( addIt->id() );
04903   }
04904 
04905   // changed attributes
04906   QMap<QgsFeatureId, QgsUndoCommand::AttributeChanges>::iterator attrFeatIt = attributeChange.begin();
04907   for ( ; attrFeatIt != attributeChange.end(); ++attrFeatIt )
04908   {
04909     QgsFeatureId fid = attrFeatIt.key();
04910     // for every changed attribute in feature
04911     QMap<int, QgsUndoCommand::AttributeChangeEntry>::iterator attrChIt = attrFeatIt.value().begin();
04912     for ( ; attrChIt != attrFeatIt.value().end(); ++attrChIt )
04913     {
04914       if ( !FID_IS_NEW( fid ) )
04915       {
04916         // existing feature
04917         if ( attrChIt.value().target.isNull() )
04918         {
04919           mChangedAttributeValues[fid].remove( attrChIt.key() );
04920           if ( mChangedAttributeValues[fid].isEmpty() )
04921             mChangedAttributeValues.remove( fid );
04922         }
04923         else
04924         {
04925           mChangedAttributeValues[fid][attrChIt.key()] = attrChIt.value().target;
04926         }
04927       }
04928       else
04929       {
04930         // added feature
04931         for ( int i = 0; i < mAddedFeatures.size(); i++ )
04932         {
04933           if ( mAddedFeatures[i].id() == fid )
04934           {
04935             mAddedFeatures[i].changeAttribute( attrChIt.key(), attrChIt.value().target );
04936             break;
04937           }
04938         }
04939       }
04940       emit attributeValueChanged( fid, attrChIt.key(), attrChIt.value().target );
04941     }
04942   }
04943 
04944   // added attributes
04945   QgsFieldMap::iterator attrIt = addedAttributes.begin();
04946   for ( ; attrIt != addedAttributes.end(); ++attrIt )
04947   {
04948     int attrIndex = attrIt.key();
04949     mAddedAttributeIds.insert( attrIndex );
04950     mUpdatedFields.insert( attrIndex, attrIt.value() );
04951     emit attributeAdded( attrIndex );
04952   }
04953 
04954   // deleted attributes
04955   QgsFieldMap::iterator dAttrIt = deletedAttributes.begin();
04956   for ( ; dAttrIt != deletedAttributes.end(); ++dAttrIt )
04957   {
04958     int attrIndex = dAttrIt.key();
04959     mDeletedAttributeIds.insert( attrIndex );
04960     mUpdatedFields.remove( attrIndex );
04961     emit attributeDeleted( attrIndex );
04962   }
04963   setModified( true );
04964 
04965   // it's not ideal to trigger refresh from here
04966   triggerRepaint();
04967 }
04968 
04969 void QgsVectorLayer::undoEditCommand( QgsUndoCommand* cmd )
04970 {
04971   QMap<QgsFeatureId, QgsUndoCommand::GeometryChangeEntry>& geometryChange = cmd->mGeometryChange;
04972   QgsFeatureIds& deletedFeatureIdChange = cmd->mDeletedFeatureIdChange;
04973   QgsFeatureList& addedFeatures = cmd->mAddedFeatures;
04974   QMap<QgsFeatureId, QgsUndoCommand::AttributeChanges>& attributeChange = cmd->mAttributeChange;
04975   QgsFieldMap& addedAttributes = cmd->mAddedAttributes;
04976   QgsFieldMap& deletedAttributes = cmd->mDeletedAttributes;
04977 
04978   // deleted attributes
04979   QgsFieldMap::iterator dAttrIt = deletedAttributes.begin();
04980   for ( ; dAttrIt != deletedAttributes.end(); ++dAttrIt )
04981   {
04982     int attrIndex = dAttrIt.key();
04983     mDeletedAttributeIds.remove( attrIndex );
04984     mUpdatedFields.insert( attrIndex, dAttrIt.value() );
04985     emit attributeAdded( attrIndex );
04986   }
04987 
04988   // added attributes
04989   QgsFieldMap::iterator attrIt = addedAttributes.begin();
04990   for ( ; attrIt != addedAttributes.end(); ++attrIt )
04991   {
04992     int attrIndex = attrIt.key();
04993     mAddedAttributeIds.remove( attrIndex );
04994     mUpdatedFields.remove( attrIndex );
04995     emit attributeDeleted( attrIndex );
04996   }
04997 
04998   // geometry changes
04999   QMap<QgsFeatureId, QgsUndoCommand::GeometryChangeEntry>::iterator it = geometryChange.begin();
05000   for ( ; it != geometryChange.end(); ++it )
05001   {
05002     if ( !it.value().original )
05003     {
05004       mChangedGeometries.remove( it.key() );
05005 
05006       QgsFeature f;
05007       if ( featureAtId( it.key(), f, true, false ) && f.geometry() )
05008       {
05009         emit geometryChanged( it.key(), *f.geometry() );
05010       }
05011     }
05012     else
05013     {
05014       mChangedGeometries[it.key()] = *( it.value().original );
05015       emit geometryChanged( it.key(), *it.value().original );
05016     }
05017   }
05018 
05019   // deleted features
05020   QgsFeatureIds::iterator delIt = deletedFeatureIdChange.begin();
05021   for ( ; delIt != deletedFeatureIdChange.end(); ++delIt )
05022   {
05023     mDeletedFeatureIds.remove( *delIt );
05024     emit featureAdded( *delIt );
05025   }
05026 
05027   // added features
05028   QgsFeatureList::iterator addIt = addedFeatures.begin();
05029   for ( ; addIt != addedFeatures.end(); ++addIt )
05030   {
05031     QgsFeatureList::iterator addedIt = mAddedFeatures.begin();
05032     for ( ; addedIt != mAddedFeatures.end(); ++addedIt )
05033     {
05034       if ( addedIt->id() == addIt->id() )
05035       {
05036         mAddedFeatures.erase( addedIt );
05037         emit featureDeleted( addIt->id() );
05038         break; // feature was found so move to next one
05039       }
05040     }
05041   }
05042 
05043   // updated attributes
05044   QMap<QgsFeatureId, QgsUndoCommand::AttributeChanges>::iterator attrFeatIt = attributeChange.begin();
05045   for ( ; attrFeatIt != attributeChange.end(); ++attrFeatIt )
05046   {
05047     QgsFeatureId fid = attrFeatIt.key();
05048     QMap<int, QgsUndoCommand::AttributeChangeEntry>::iterator  attrChIt = attrFeatIt.value().begin();
05049     for ( ; attrChIt != attrFeatIt.value().end(); ++attrChIt )
05050     {
05051       if ( !FID_IS_NEW( fid ) )
05052       {
05053         if ( attrChIt.value().isFirstChange )
05054         {
05055           mChangedAttributeValues[fid].remove( attrChIt.key() );
05056           if ( mChangedAttributeValues[fid].isEmpty() )
05057             mChangedAttributeValues.remove( fid );
05058         }
05059         else
05060         {
05061           mChangedAttributeValues[fid][attrChIt.key()] = attrChIt.value().original;
05062         }
05063       }
05064       else
05065       {
05066         // added feature TODO:
05067         for ( int i = 0; i < mAddedFeatures.size(); i++ )
05068         {
05069           if ( mAddedFeatures[i].id() == fid )
05070           {
05071             mAddedFeatures[i].changeAttribute( attrChIt.key(), attrChIt.value().original );
05072             break;
05073           }
05074         }
05075       }
05076       QVariant original = attrChIt.value().original;
05077       if ( attrChIt.value().isFirstChange )
05078       {
05079         QgsFeature tmp;
05080         mDataProvider->featureAtId( fid, tmp, false, QgsAttributeList() << attrChIt.key() );
05081         original = tmp.attributeMap()[ attrChIt.key()];
05082       }
05083       emit attributeValueChanged( fid, attrChIt.key(), original );
05084     }
05085   }
05086   setModified( true );
05087 
05088   // it's not ideal to trigger refresh from here
05089   triggerRepaint();
05090 }
05091 
05092 void QgsVectorLayer::setCheckedState( int idx, QString checked, QString unchecked )
05093 {
05094   const QgsFieldMap &fields = pendingFields();
05095   if ( fields.contains( idx ) )
05096     mCheckedStates[ fields[idx].name()] = QPair<QString, QString>( checked, unchecked );
05097 }
05098 
05099 QPair<QString, QString> QgsVectorLayer::checkedState( int idx )
05100 {
05101   const QgsFieldMap &fields = pendingFields();
05102   if ( fields.contains( idx ) && mCheckedStates.contains( fields[idx].name() ) )
05103     return mCheckedStates[ fields[idx].name()];
05104   else
05105     return QPair<QString, QString>( "1", "0" );
05106 }
05107 
05108 int QgsVectorLayer::fieldNameIndex( const QString& fieldName ) const
05109 {
05110   const QgsFieldMap &theFields = pendingFields();
05111 
05112   for ( QgsFieldMap::const_iterator it = theFields.constBegin(); it != theFields.constEnd(); ++it )
05113   {
05114     if ( QString::compare( it->name(), fieldName, Qt::CaseInsensitive ) == 0 )
05115     {
05116       return it.key();
05117     }
05118   }
05119   return -1;
05120 }
05121 
05122 void QgsVectorLayer::addJoin( QgsVectorJoinInfo joinInfo )
05123 {
05124   mJoinBuffer->addJoin( joinInfo );
05125   updateFieldMap();
05126 }
05127 
05128 void QgsVectorLayer::checkJoinLayerRemove( QString theLayerId )
05129 {
05130   removeJoin( theLayerId );
05131 }
05132 
05133 void QgsVectorLayer::removeJoin( const QString& joinLayerId )
05134 {
05135   mJoinBuffer->removeJoin( joinLayerId );
05136   updateFieldMap();
05137 }
05138 
05139 const QList< QgsVectorJoinInfo >& QgsVectorLayer::vectorJoins() const
05140 {
05141   return mJoinBuffer->vectorJoins();
05142 }
05143 
05144 void QgsVectorLayer::updateFieldMap()
05145 {
05146   //first backup mAddedAttributes
05147   QgsFieldMap bkAddedAttributes;
05148   QgsAttributeIds::const_iterator attIdIt = mAddedAttributeIds.constBegin();
05149   for ( ; attIdIt != mAddedAttributeIds.constEnd(); ++attIdIt )
05150   {
05151     bkAddedAttributes.insert( *attIdIt, mUpdatedFields.value( *attIdIt ) );
05152   }
05153 
05154   mUpdatedFields = QgsFieldMap();
05155   if ( mDataProvider )
05156   {
05157     mUpdatedFields = mDataProvider->fields();
05158   }
05159 
05160   int currentMaxIndex = 0; //maximum index of current layer
05161   if ( !QgsVectorLayerJoinBuffer::maximumIndex( mUpdatedFields, currentMaxIndex ) )
05162   {
05163     return;
05164   }
05165 
05166   mMaxUpdatedIndex = currentMaxIndex;
05167 
05168   //joined fields
05169   if ( mJoinBuffer->containsJoins() )
05170   {
05171     mJoinBuffer->updateFieldMap( mUpdatedFields, mMaxUpdatedIndex );
05172   }
05173 
05174   //insert added attributes after provider fields and joined fields
05175   mAddedAttributeIds.clear();
05176   QgsFieldMap::const_iterator fieldIt = bkAddedAttributes.constBegin();
05177   for ( ; fieldIt != bkAddedAttributes.constEnd(); ++fieldIt )
05178   {
05179     ++mMaxUpdatedIndex;
05180     mUpdatedFields.insert( mMaxUpdatedIndex, fieldIt.value() );
05181     mAddedAttributeIds.insert( mMaxUpdatedIndex );
05182 
05183     //go through the changed attributes map and adapt indices of added attributes
05184     for ( int i = 0; i < mChangedAttributeValues.size(); ++i )
05185     {
05186       updateAttributeMapIndex( mChangedAttributeValues[i], fieldIt.key(), mMaxUpdatedIndex );
05187     }
05188 
05189     //go through added features and adapt attribute maps
05190     QgsFeatureList::iterator featureIt = mAddedFeatures.begin();
05191     for ( ; featureIt != mAddedFeatures.end(); ++featureIt )
05192     {
05193       QgsAttributeMap attMap = featureIt->attributeMap();
05194       updateAttributeMapIndex( attMap, fieldIt.key(), mMaxUpdatedIndex );
05195       featureIt->setAttributeMap( attMap );
05196     }
05197   }
05198 
05199   //remove deleted attributes
05200   QgsAttributeIds::const_iterator deletedIt = mDeletedAttributeIds.constBegin();
05201   for ( ; deletedIt != mDeletedAttributeIds.constEnd(); ++deletedIt )
05202   {
05203     mUpdatedFields.remove( *deletedIt );
05204   }
05205 }
05206 
05207 void QgsVectorLayer::createJoinCaches()
05208 {
05209   if ( mJoinBuffer->containsJoins() )
05210   {
05211     mJoinBuffer->createJoinCaches();
05212   }
05213 }
05214 
05215 void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int limit )
05216 {
05217   uniqueValues.clear();
05218   if ( !mDataProvider )
05219   {
05220     return;
05221   }
05222 
05223   int maxProviderIndex;
05224   QgsVectorLayerJoinBuffer::maximumIndex( mDataProvider->fields(), maxProviderIndex );
05225 
05226   if ( index <= maxProviderIndex && !mEditable ) //a provider field
05227   {
05228     return mDataProvider->uniqueValues( index, uniqueValues, limit );
05229   }
05230   else // a joined field?
05231   {
05232     if ( mJoinBuffer )
05233     {
05234       int indexOffset; //offset between layer index and joined provider index
05235       const QgsVectorJoinInfo* join = mJoinBuffer->joinForFieldIndex( index, maxProviderIndex, indexOffset );
05236       if ( join )
05237       {
05238         QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( join->joinLayerId ) );
05239         if ( vl && vl->dataProvider() )
05240         {
05241           return vl->dataProvider()->uniqueValues( index - indexOffset, uniqueValues, limit );
05242         }
05243       }
05244     }
05245   }
05246 
05247 
05248   //the layer is editable, but in certain cases it can still be avoided going through all features
05249   if ( mDeletedFeatureIds.size() < 1 && mAddedFeatures.size() < 1 && !mDeletedAttributeIds.contains( index ) && mChangedAttributeValues.size() < 1 )
05250   {
05251     return mDataProvider->uniqueValues( index, uniqueValues, limit );
05252   }
05253 
05254   //we need to go through each feature
05255   QgsAttributeList attList;
05256   attList << index;
05257 
05258   select( attList, QgsRectangle(), false, false );
05259 
05260   QgsFeature f;
05261   QVariant currentValue;
05262   QHash<QString, QVariant> val;
05263   while ( nextFeature( f ) )
05264   {
05265     currentValue = f.attributeMap()[index];
05266     val.insert( currentValue.toString(), currentValue );
05267     if ( limit >= 0 && val.size() >= limit )
05268     {
05269       break;
05270     }
05271   }
05272 
05273   uniqueValues = val.values();
05274 }
05275 
05276 QVariant QgsVectorLayer::minimumValue( int index )
05277 {
05278   if ( !mDataProvider )
05279   {
05280     return QVariant();
05281   }
05282 
05283   int maxProviderIndex;
05284   QgsVectorLayerJoinBuffer::maximumIndex( mDataProvider->fields(), maxProviderIndex );
05285 
05286   if ( index <= maxProviderIndex && !mEditable ) //a provider field
05287   {
05288     return mDataProvider->minimumValue( index );
05289   }
05290   else // a joined field?
05291   {
05292     int indexOffset; //offset between layer index and joined provider index
05293     const QgsVectorJoinInfo* join = mJoinBuffer->joinForFieldIndex( index, maxProviderIndex, indexOffset );
05294     if ( join )
05295     {
05296       QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( join->joinLayerId ) );
05297       if ( vl )
05298       {
05299         return vl->minimumValue( index );
05300       }
05301     }
05302   }
05303 
05304   //the layer is editable, but in certain cases it can still be avoided going through all features
05305   if ( mDeletedFeatureIds.size() < 1 && mAddedFeatures.size() < 1 && !mDeletedAttributeIds.contains( index ) && mChangedAttributeValues.size() < 1 )
05306   {
05307     return mDataProvider->minimumValue( index );
05308   }
05309 
05310   //we need to go through each feature
05311   QgsAttributeList attList;
05312   attList << index;
05313 
05314   select( attList, QgsRectangle(), false, false );
05315 
05316   QgsFeature f;
05317   double minimumValue = std::numeric_limits<double>::max();
05318   double currentValue = 0;
05319   while ( nextFeature( f ) )
05320   {
05321     currentValue = f.attributeMap()[index].toDouble();
05322     if ( currentValue < minimumValue )
05323     {
05324       minimumValue = currentValue;
05325     }
05326   }
05327   return QVariant( minimumValue );
05328 }
05329 
05330 QVariant QgsVectorLayer::maximumValue( int index )
05331 {
05332   if ( !mDataProvider )
05333   {
05334     return QVariant();
05335   }
05336 
05337   int maxProviderIndex;
05338   QgsVectorLayerJoinBuffer::maximumIndex( mDataProvider->fields(), maxProviderIndex );
05339 
05340   if ( index <= maxProviderIndex && !mEditable ) //a provider field
05341   {
05342     return mDataProvider->maximumValue( index );
05343   }
05344   else // a joined field?
05345   {
05346     int indexOffset; //offset between layer index and joined provider index
05347     const QgsVectorJoinInfo* join = mJoinBuffer->joinForFieldIndex( index, maxProviderIndex, indexOffset );
05348     if ( join )
05349     {
05350       QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( join->joinLayerId ) );
05351       if ( vl )
05352       {
05353         return vl->maximumValue( index );
05354       }
05355     }
05356   }
05357 
05358   //the layer is editable, but in certain cases it can still be avoided going through all features
05359   if ( mDeletedFeatureIds.size() < 1 && mAddedFeatures.size() < 1 && !mDeletedAttributeIds.contains( index ) && mChangedAttributeValues.size() < 1 )
05360   {
05361     return mDataProvider->maximumValue( index );
05362   }
05363 
05364   //we need to go through each feature
05365   QgsAttributeList attList;
05366   attList << index;
05367 
05368   select( attList, QgsRectangle(), false, false );
05369 
05370   QgsFeature f;
05371   double maximumValue = -std::numeric_limits<double>::max();
05372   double currentValue = 0;
05373   while ( nextFeature( f ) )
05374   {
05375     currentValue = f.attributeMap()[index].toDouble();
05376     if ( currentValue > maximumValue )
05377     {
05378       maximumValue = currentValue;
05379     }
05380   }
05381   return QVariant( maximumValue );
05382 }
05383 
05384 void QgsVectorLayer::stopRendererV2( QgsRenderContext& rendererContext, QgsSingleSymbolRendererV2* selRenderer )
05385 {
05386   mRendererV2->stopRender( rendererContext );
05387   if ( selRenderer )
05388   {
05389     selRenderer->stopRender( rendererContext );
05390     delete selRenderer;
05391   }
05392 }
05393 
05394 void QgsVectorLayer::updateAttributeMapIndex( QgsAttributeMap& map, int oldIndex, int newIndex ) const
05395 {
05396   QgsAttributeMap::const_iterator it = map.find( oldIndex );
05397   if ( it == map.constEnd() )
05398   {
05399     return;
05400   }
05401 
05402   map.insert( newIndex, it.value() );
05403   map.remove( oldIndex );
05404 }
05405 
05406 void QgsVectorLayer::prepareLabelingAndDiagrams( QgsRenderContext& rendererContext, QgsAttributeList& attributes, bool& labeling )
05407 {
05408   if ( !rendererContext.labelingEngine() )
05409     return;
05410 
05411   QSet<int> attrIndex;
05412   if ( rendererContext.labelingEngine()->prepareLayer( this, attrIndex, rendererContext ) )
05413   {
05414     QSet<int>::const_iterator attIt = attrIndex.constBegin();
05415     for ( ; attIt != attrIndex.constEnd(); ++attIt )
05416     {
05417       if ( !attributes.contains( *attIt ) )
05418       {
05419         attributes << *attIt;
05420       }
05421     }
05422     labeling = true;
05423   }
05424 
05425   //register diagram layers
05426   if ( mDiagramRenderer && mDiagramLayerSettings )
05427   {
05428     mDiagramLayerSettings->renderer = mDiagramRenderer;
05429     rendererContext.labelingEngine()->addDiagramLayer( this, mDiagramLayerSettings );
05430     //add attributes needed by the diagram renderer
05431     QList<int> att = mDiagramRenderer->diagramAttributes();
05432     QList<int>::const_iterator attIt = att.constBegin();
05433     for ( ; attIt != att.constEnd(); ++attIt )
05434     {
05435       if ( !attributes.contains( *attIt ) )
05436       {
05437         attributes << *attIt;
05438       }
05439     }
05440     //and the ones needed for data defined diagram positions
05441     if ( mDiagramLayerSettings->xPosColumn >= 0 && !attributes.contains( mDiagramLayerSettings->xPosColumn ) )
05442     {
05443       attributes << mDiagramLayerSettings->xPosColumn;
05444     }
05445     if ( mDiagramLayerSettings->yPosColumn >= 0 && !attributes.contains( mDiagramLayerSettings->yPosColumn ) )
05446     {
05447       attributes << mDiagramLayerSettings->yPosColumn;
05448     }
05449   }
05450 }
05451 
05452 void QgsVectorLayer::setDiagramLayerSettings( const QgsDiagramLayerSettings& s )
05453 {
05454   if ( !mDiagramLayerSettings )
05455     mDiagramLayerSettings = new QgsDiagramLayerSettings();
05456   *mDiagramLayerSettings = s;
05457 }
05458 
05459 QString QgsVectorLayer::metadata()
05460 {
05461   QString myMetadata = "<html><body>";
05462   myMetadata += "<table width=\"100%\">";
05463 
05464   //-------------
05465 
05466   myMetadata += "<tr class=\"glossy\"><td>";
05467   myMetadata += tr( "General:" );
05468   myMetadata += "</td></tr>";
05469 
05470   // data comment
05471   if ( !( dataComment().isEmpty() ) )
05472   {
05473     myMetadata += "<tr><td>";
05474     myMetadata += tr( "Layer comment: %1" ).arg( dataComment() );
05475     myMetadata += "</td></tr>";
05476   }
05477 
05478   //storage type
05479   myMetadata += "<tr><td>";
05480   myMetadata += tr( "Storage type of this layer: %1" ).arg( storageType() );
05481   myMetadata += "</td></tr>";
05482 
05483   // data source
05484   myMetadata += "<tr><td>";
05485   myMetadata += tr( "Source for this layer: %1" ).arg( publicSource() );
05486   myMetadata += "</td></tr>";
05487 
05488   //geom type
05489 
05490   QGis::GeometryType type = geometryType();
05491 
05492   if ( type < 0 || type > QGis::NoGeometry )
05493   {
05494     QgsDebugMsg( "Invalid vector type" );
05495   }
05496   else
05497   {
05498     QString typeString( QGis::qgisVectorGeometryType[geometryType()] );
05499 
05500     myMetadata += "<tr><td>";
05501     myMetadata += tr( "Geometry type of the features in this layer: %1" ).arg( typeString );
05502     myMetadata += "</td></tr>";
05503   }
05504 
05505 
05506   //feature count
05507   myMetadata += "<tr><td>";
05508   myMetadata += tr( "The number of features in this layer: %1" ).arg( featureCount() );
05509   myMetadata += "</td></tr>";
05510   //capabilities
05511   myMetadata += "<tr><td>";
05512   myMetadata += tr( "Editing capabilities of this layer: %1" ).arg( capabilitiesString() );
05513   myMetadata += "</td></tr>";
05514 
05515   //-------------
05516 
05517   QgsRectangle myExtent = extent();
05518   myMetadata += "<tr class=\"glossy\"><td>";
05519   myMetadata += tr( "Extents:" );
05520   myMetadata += "</td></tr>";
05521   //extents in layer cs  TODO...maybe make a little nested table to improve layout...
05522   myMetadata += "<tr><td>" + tr( "In layer spatial reference system units : " );
05523 
05524   // Try to be a bit clever over what number format we use for the
05525   // extents. Some people don't like it using scientific notation when the
05526   // numbers get large, but for small numbers this is the more practical
05527   // option (so we can't force the format to 'f' for all values).
05528   // The scheme:
05529   // - for all numbers with more than 5 digits, force non-scientific notation
05530   // and 2 digits after the decimal point.
05531   // - for all smaller numbers let the OS decide which format to use (it will
05532   // generally use non-scientific unless the number gets much less than 1).
05533 
05534   if ( !myExtent.isEmpty() )
05535   {
05536     QString xMin, yMin, xMax, yMax;
05537     double changeoverValue = 99999; // The 'largest' 5 digit number
05538     if ( qAbs( myExtent.xMinimum() ) > changeoverValue )
05539     {
05540       xMin = QString( "%1" ).arg( myExtent.xMinimum(), 0, 'f', 2 );
05541     }
05542     else
05543     {
05544       xMin = QString( "%1" ).arg( myExtent.xMinimum() );
05545     }
05546     if ( qAbs( myExtent.yMinimum() ) > changeoverValue )
05547     {
05548       yMin = QString( "%1" ).arg( myExtent.yMinimum(), 0, 'f', 2 );
05549     }
05550     else
05551     {
05552       yMin = QString( "%1" ).arg( myExtent.yMinimum() );
05553     }
05554     if ( qAbs( myExtent.xMaximum() ) > changeoverValue )
05555     {
05556       xMax = QString( "%1" ).arg( myExtent.xMaximum(), 0, 'f', 2 );
05557     }
05558     else
05559     {
05560       xMax = QString( "%1" ).arg( myExtent.xMaximum() );
05561     }
05562     if ( qAbs( myExtent.yMaximum() ) > changeoverValue )
05563     {
05564       yMax = QString( "%1" ).arg( myExtent.yMaximum(), 0, 'f', 2 );
05565     }
05566     else
05567     {
05568       yMax = QString( "%1" ).arg( myExtent.yMaximum() );
05569     }
05570 
05571     myMetadata += tr( "xMin,yMin %1,%2 : xMax,yMax %3,%4" )
05572                   .arg( xMin ).arg( yMin ).arg( xMax ).arg( yMax );
05573   }
05574   else
05575   {
05576     myMetadata += tr( "unknown extent" );
05577   }
05578 
05579   myMetadata += "</td></tr>";
05580 
05581   //extents in project cs
05582 
05583   try
05584   {
05585 #if 0
05586     // TODO: currently disabled, will revisit later [MD]
05587     QgsRectangle myProjectedExtent = coordinateTransform->transformBoundingBox( extent() );
05588     myMetadata += "<tr><td>";
05589     myMetadata += tr( "In project spatial reference system units : " )
05590                   + tr( "xMin,yMin %1,%2 : xMax,yMax %3,%4" )
05591                   .arg( myProjectedExtent.xMinimum() )
05592                   .arg( myProjectedExtent.yMinimum() )
05593                   .arg( myProjectedExtent.xMaximum() )
05594                   .arg( myProjectedExtent.yMaximum() );
05595     myMetadata += "</td></tr>";
05596 #endif
05597 
05598     //
05599     // Display layer spatial ref system
05600     //
05601     myMetadata += "<tr class=\"glossy\"><td>";
05602     myMetadata += tr( "Layer Spatial Reference System:" );
05603     myMetadata += "</td></tr>";
05604     myMetadata += "<tr><td>";
05605     myMetadata += crs().toProj4().replace( QRegExp( "\"" ), " \"" );
05606     myMetadata += "</td></tr>";
05607 
05608     //
05609     // Display project (output) spatial ref system
05610     //
05611 #if 0
05612     // TODO: disabled for now, will revisit later [MD]
05613     myMetadata += "<tr><td bgcolor=\"gray\">";
05614     myMetadata += tr( "Project (Output) Spatial Reference System:" );
05615     myMetadata += "</td></tr>";
05616     myMetadata += "<tr><td>";
05617     myMetadata += coordinateTransform->destCRS().toProj4().replace( QRegExp( "\"" ), " \"" );
05618     myMetadata += "</td></tr>";
05619 #endif
05620   }
05621   catch ( QgsCsException &cse )
05622   {
05623     Q_UNUSED( cse );
05624     QgsDebugMsg( cse.what() );
05625 
05626     myMetadata += "<tr><td>";
05627     myMetadata += tr( "In project spatial reference system units : " )
05628                   + tr( "(Invalid transformation of layer extents)" );
05629     myMetadata += "</td></tr>";
05630 
05631   }
05632 
05633 #if 0
05634   //
05635   // Add the info about each field in the attribute table
05636   //
05637   myMetadata += "<tr class=\"glossy\"><td>";
05638   myMetadata += tr( "Attribute field info:" );
05639   myMetadata += "</td></tr>";
05640   myMetadata += "<tr><td>";
05641 
05642   // Start a nested table in this trow
05643   myMetadata += "<table width=\"100%\">";
05644   myMetadata += "<tr><th>";
05645   myMetadata += tr( "Field" );
05646   myMetadata += "</th>";
05647   myMetadata += "<th>";
05648   myMetadata += tr( "Type" );
05649   myMetadata += "</th>";
05650   myMetadata += "<th>";
05651   myMetadata += tr( "Length" );
05652   myMetadata += "</th>";
05653   myMetadata += "<th>";
05654   myMetadata += tr( "Precision" );
05655   myMetadata += "</th>";
05656   myMetadata += "<th>";
05657   myMetadata += tr( "Comment" );
05658   myMetadata += "</th>";
05659 
05660   //get info for each field by looping through them
05661   const QgsFieldMap& myFields = pendingFields();
05662   for ( QgsFieldMap::const_iterator it = myFields.begin(); it != myFields.end(); ++it )
05663   {
05664     const QgsField& myField = *it;
05665 
05666     myMetadata += "<tr><td>";
05667     myMetadata += myField.name();
05668     myMetadata += "</td>";
05669     myMetadata += "<td>";
05670     myMetadata += myField.typeName();
05671     myMetadata += "</td>";
05672     myMetadata += "<td>";
05673     myMetadata += QString( "%1" ).arg( myField.length() );
05674     myMetadata += "</td>";
05675     myMetadata += "<td>";
05676     myMetadata += QString( "%1" ).arg( myField.precision() );
05677     myMetadata += "</td>";
05678     myMetadata += "<td>";
05679     myMetadata += QString( "%1" ).arg( myField.comment() );
05680     myMetadata += "</td></tr>";
05681   }
05682 
05683   //close field list
05684   myMetadata += "</table>"; //end of nested table
05685 #endif
05686 
05687   myMetadata += "</td></tr>"; //end of stats container table row
05688   //
05689   // Close the table
05690   //
05691 
05692   myMetadata += "</table>";
05693 
05694   myMetadata += "</body></html>";
05695   return myMetadata;
05696 }
05697 
05698 QgsVectorLayer::ValueRelationData &QgsVectorLayer::valueRelation( int idx )
05699 {
05700   const QgsFieldMap &fields = pendingFields();
05701 
05702   // FIXME: throw an exception!?
05703   if ( fields.contains( idx ) )
05704   {
05705     QgsDebugMsg( QString( "field %1 not found" ).arg( idx ) );
05706   }
05707 
05708   if ( !mValueRelations.contains( fields[idx].name() ) )
05709   {
05710     mValueRelations[ fields[idx].name()] = ValueRelationData();
05711   }
05712 
05713   return mValueRelations[ fields[idx].name()];
05714 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines