src/core/qgsvectorlayer.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                                qgsvectorlayer.cpp
00003   This class implements a generic means to display vector layers. The features
00004   and attributes are read from the data store using a "data provider" plugin.
00005   QgsVectorLayer can be used with any data store for which an appropriate
00006   plugin is available.
00007                               -------------------
00008           begin                : Oct 29, 2003
00009           copyright            : (C) 2003 by Gary E.Sherman
00010           email                : sherman at mrcc.com
00011 
00012 ***************************************************************************/
00013 
00014 /***************************************************************************
00015  *                                                                         *
00016  *   This program is free software; you can redistribute it and/or modify  *
00017  *   it under the terms of the GNU General Public License as published by  *
00018  *   the Free Software Foundation; either version 2 of the License, or     *
00019  *   (at your option) any later version.                                   *
00020  *                                                                         *
00021  ***************************************************************************/
00022 /*  $Id: qgsvectorlayer.cpp 9897 2008-12-26 21:07:03Z jef $ */
00023 
00024 #include <cassert>
00025 #include <cfloat>
00026 #include <cstring>
00027 #include <climits>
00028 #include <cmath>
00029 #include <iosfwd>
00030 #include <limits>
00031 #include <memory>
00032 #include <set>
00033 #include <sstream>
00034 #include <utility>
00035 
00036 #include <QImage>
00037 #include <QPainter>
00038 #include <QPainterPath>
00039 #include <QPolygonF>
00040 #include <QSettings>
00041 #include <QString>
00042 
00043 #include "qgsvectorlayer.h"
00044 
00045 // renderers
00046 #include "qgscontinuouscolorrenderer.h"
00047 #include "qgsgraduatedsymbolrenderer.h"
00048 #include "qgsrenderer.h"
00049 #include "qgssinglesymbolrenderer.h"
00050 #include "qgsuniquevaluerenderer.h"
00051 
00052 #include "qgsattributeaction.h"
00053 
00054 #include "qgis.h" //for globals
00055 #include "qgsapplication.h"
00056 #include "qgscoordinatetransform.h"
00057 #include "qgsfeature.h"
00058 #include "qgsfield.h"
00059 #include "qgsgeometry.h"
00060 #include "qgslabel.h"
00061 #include "qgslogger.h"
00062 #include "qgsmaptopixel.h"
00063 #include "qgspoint.h"
00064 #include "qgsproviderregistry.h"
00065 #include "qgsrectangle.h"
00066 #include "qgsrendercontext.h"
00067 #include "qgssinglesymbolrenderer.h"
00068 #include "qgscoordinatereferencesystem.h"
00069 #include "qgsvectordataprovider.h"
00070 #include "qgslogger.h"
00071 
00072 #ifdef Q_WS_X11
00073 #include "qgsclipper.h"
00074 #endif
00075 
00076 #ifdef TESTPROVIDERLIB
00077 #include <dlfcn.h>
00078 #endif
00079 
00080 
00081 static const char * const ident_ = "$Id: qgsvectorlayer.cpp 9897 2008-12-26 21:07:03Z jef $";
00082 
00083 // typedef for the QgsDataProvider class factory
00084 typedef QgsDataProvider * create_it( const QString* uri );
00085 
00086 
00087 
00088 QgsVectorLayer::QgsVectorLayer( QString vectorLayerPath,
00089                                 QString baseName,
00090                                 QString providerKey,
00091                                 bool loadDefaultStyleFlag )
00092     : QgsMapLayer( VectorLayer, baseName, vectorLayerPath ),
00093     mUpdateThreshold( 0 ),     // XXX better default value?
00094     mDataProvider( NULL ),
00095     mProviderKey( providerKey ),
00096     mEditable( false ),
00097     mModified( false ),
00098     mMaxUpdatedIndex( -1 ),
00099     mRenderer( 0 ),
00100     mLabel( 0 ),
00101     mLabelOn( false ),
00102     mFetching( false )
00103 {
00104   mActions = new QgsAttributeAction;
00105 
00106   // if we're given a provider type, try to create and bind one to this layer
00107   if ( ! mProviderKey.isEmpty() )
00108   {
00109     setDataProvider( mProviderKey );
00110   }
00111   if ( mValid )
00112   {
00113     // check if there is a default style / propertysheet defined
00114     // for this layer and if so apply it
00115     //
00116     if ( loadDefaultStyleFlag )
00117     {
00118       bool defaultLoadedFlag = false;
00119       loadDefaultStyle( defaultLoadedFlag );
00120       if ( !defaultLoadedFlag )
00121       {
00122         setCoordinateSystem();
00123         // add single symbol renderer as default
00124         QgsSingleSymbolRenderer *renderer = new QgsSingleSymbolRenderer( geometryType() );
00125         setRenderer( renderer );
00126       }
00127     }
00128     else  // Otherwise use some very basic defaults
00129     {
00130       setCoordinateSystem();
00131       // add single symbol renderer as default
00132       QgsSingleSymbolRenderer *renderer = new QgsSingleSymbolRenderer( geometryType() );
00133       setRenderer( renderer );
00134     }
00135     // Get the update threshold from user settings. We
00136     // do this only on construction to avoid the penality of
00137     // fetching this each time the layer is drawn. If the user
00138     // changes the threshold from the preferences dialog, it will
00139     // have no effect on existing layers
00140     // TODO: load this setting somewhere else [MD]
00141     //QSettings settings;
00142     //mUpdateThreshold = settings.readNumEntry("Map/updateThreshold", 1000);
00143   }
00144 } // QgsVectorLayer ctor
00145 
00146 
00147 
00148 QgsVectorLayer::~QgsVectorLayer()
00149 {
00150   QgsDebugMsg( "In QgsVectorLayer destructor" );
00151 
00152   emit layerDeleted();
00153 
00154   mValid = false;
00155 
00156   if ( mRenderer )
00157   {
00158     delete mRenderer;
00159   }
00160   // delete the provider object
00161   delete mDataProvider;
00162 
00163   delete mLabel;
00164 
00165   // Destroy any cached geometries and clear the references to them
00166   deleteCachedGeometries();
00167 
00168   delete mActions;
00169 }
00170 
00171 QString QgsVectorLayer::storageType() const
00172 {
00173   if ( mDataProvider )
00174   {
00175     return mDataProvider->storageType();
00176   }
00177   return 0;
00178 }
00179 
00180 
00181 QString QgsVectorLayer::capabilitiesString() const
00182 {
00183   if ( mDataProvider )
00184   {
00185     return mDataProvider->capabilitiesString();
00186   }
00187   return 0;
00188 }
00189 
00190 QString QgsVectorLayer::dataComment() const
00191 {
00192   if ( mDataProvider )
00193   {
00194     return mDataProvider->dataComment();
00195   }
00196   return QString();
00197 }
00198 
00199 
00200 QString QgsVectorLayer::providerType() const
00201 {
00202   return mProviderKey;
00203 }
00204 
00208 void QgsVectorLayer::setDisplayField( QString fldName )
00209 {
00210   // If fldName is provided, use it as the display field, otherwise
00211   // determine the field index for the feature column of the identify
00212   // dialog. We look for fields containing "name" first and second for
00213   // fields containing "id". If neither are found, the first field
00214   // is used as the node.
00215   QString idxName = "";
00216   QString idxId = "";
00217 
00218   if ( !fldName.isEmpty() )
00219   {
00220     mDisplayField = fldName;
00221   }
00222   else
00223   {
00224     const QgsFieldMap &fields = pendingFields();
00225     int fieldsSize = fields.size();
00226 
00227     for ( QgsFieldMap::const_iterator it = fields.begin(); it != fields.end(); ++it )
00228     {
00229       QString fldName = it.value().name();
00230       QgsDebugMsg( "Checking field " + fldName + " of " + QString::number( fieldsSize ) + " total" );
00231 
00232       // Check the fields and keep the first one that matches.
00233       // We assume that the user has organized the data with the
00234       // more "interesting" field names first. As such, name should
00235       // be selected before oldname, othername, etc.
00236       if ( fldName.indexOf( "name", false ) > -1 )
00237       {
00238         if ( idxName.isEmpty() )
00239         {
00240           idxName = fldName;
00241         }
00242       }
00243       if ( fldName.indexOf( "descrip", false ) > -1 )
00244       {
00245         if ( idxName.isEmpty() )
00246         {
00247           idxName = fldName;
00248         }
00249       }
00250       if ( fldName.indexOf( "id", false ) > -1 )
00251       {
00252         if ( idxId.isEmpty() )
00253         {
00254           idxId = fldName;
00255         }
00256       }
00257     }
00258 
00259     //if there were no fields in the dbf just return - otherwise qgis segfaults!
00260     if ( fieldsSize == 0 )
00261       return;
00262 
00263     if ( idxName.length() > 0 )
00264     {
00265       mDisplayField = idxName;
00266     }
00267     else
00268     {
00269       if ( idxId.length() > 0 )
00270       {
00271         mDisplayField = idxId;
00272       }
00273       else
00274       {
00275         mDisplayField = fields[0].name();
00276       }
00277     }
00278 
00279   }
00280 }
00281 
00282 // NOTE this is a temporary method added by Tim to prevent label clipping
00283 // which was occurring when labeller was called in the main draw loop
00284 // This method will probably be removed again in the near future!
00285 void QgsVectorLayer::drawLabels( QgsRenderContext& rendererContext )
00286 {
00287   QgsDebugMsg( "Starting draw of labels" );
00288 
00289   if ( mRenderer && mLabelOn &&
00290        ( !label()->scaleBasedVisibility() ||
00291          ( label()->minScale() <= rendererContext.rendererScale() &&
00292            rendererContext.rendererScale() <= label()->maxScale() ) ) )
00293   {
00294     QgsAttributeList attributes = mRenderer->classificationAttributes();
00295 
00296     // Add fields required for labels
00297     mLabel->addRequiredFields( attributes );
00298 
00299     QgsDebugMsg( "Selecting features based on view extent" );
00300 
00301     int featureCount = 0;
00302 
00303     try
00304     {
00305       // select the records in the extent. The provider sets a spatial filter
00306       // and sets up the selection set for retrieval
00307       select( attributes, rendererContext.extent() );
00308 
00309       QgsFeature fet;
00310       while ( nextFeature( fet ) )
00311       {
00312         if ( mRenderer->willRenderFeature( &fet ) )
00313         {
00314           bool sel = mSelectedFeatureIds.contains( fet.id() );
00315           mLabel->renderLabel( rendererContext.painter(), rendererContext.extent(), rendererContext.coordinateTransform(), &( rendererContext.mapToPixel() ), fet, sel, 0, rendererContext.scaleFactor(), rendererContext.rasterScaleFactor() );
00316         }
00317         featureCount++;
00318       }
00319     }
00320     catch ( QgsCsException &e )
00321     {
00322       Q_UNUSED( e );
00323       QgsLogger::critical( "Error projecting label locations, caught in " + QString( __FILE__ ) + ", line " + QString( __LINE__ ) );
00324     }
00325 
00326 #ifdef QGISDEBUG
00327     QgsLogger::debug( "Total features processed", featureCount, 1, __FILE__, __FUNCTION__, __LINE__ );
00328 #endif
00329 
00330     // XXX Something in our draw event is triggering an additional draw event when resizing [TE 01/26/06]
00331     // XXX Calling this will begin processing the next draw event causing image havoc and recursion crashes.
00332     //qApp->processEvents();
00333 
00334   }
00335 }
00336 
00337 
00338 unsigned char* QgsVectorLayer::drawLineString(
00339   unsigned char *feature,
00340   QPainter* p,
00341   const QgsMapToPixel* mtp,
00342   const QgsCoordinateTransform* ct,
00343   bool drawingToEditingCanvas )
00344 {
00345   unsigned char *ptr = feature + 5;
00346   unsigned int wkbType = *(( int* )( feature + 1 ) );
00347   unsigned int nPoints = *(( int* )ptr );
00348   ptr = feature + 9;
00349 
00350   bool hasZValue = ( wkbType == QGis::WKBLineString25D );
00351 
00352   std::vector<double> x( nPoints );
00353   std::vector<double> y( nPoints );
00354   std::vector<double> z( nPoints, 0.0 );
00355 
00356   // Extract the points from the WKB format into the x and y vectors.
00357   for ( register unsigned int i = 0; i < nPoints; ++i )
00358   {
00359     x[i] = *(( double * ) ptr );
00360     ptr += sizeof( double );
00361     y[i] = *(( double * ) ptr );
00362     ptr += sizeof( double );
00363 
00364     if ( hasZValue ) // ignore Z value
00365       ptr += sizeof( double );
00366   }
00367 
00368   // Transform the points into map coordinates (and reproject if
00369   // necessary)
00370 
00371   transformPoints( x, y, z, mtp, ct );
00372 
00373 #if defined(Q_WS_X11)
00374   // Work around a +/- 32768 limitation on coordinates in X11
00375 
00376   // Look through the x and y coordinates and see if there are any
00377   // that need trimming. If one is found, there's no need to look at
00378   // the rest of them so end the loop at that point.
00379   for ( register unsigned int i = 0; i < nPoints; ++i )
00380   {
00381     if ( std::abs( x[i] ) > QgsClipper::MAX_X ||
00382          std::abs( y[i] ) > QgsClipper::MAX_Y )
00383     {
00384       QgsClipper::trimFeature( x, y, true ); // true = polyline
00385       nPoints = x.size(); // trimming may change nPoints.
00386       break;
00387     }
00388   }
00389 #endif
00390 
00391   // set up QPolygonF class with transformed points
00392   QPolygonF pa( nPoints );
00393   for ( register unsigned int i = 0; i < nPoints; ++i )
00394   {
00395     pa[i].setX( x[i] );
00396     pa[i].setY( y[i] );
00397   }
00398 
00399 #ifdef QGISDEBUGVERBOSE
00400   // this is only used for verbose debug output
00401   for ( int i = 0; i < pa.size(); ++i )
00402   {
00403     QgsDebugMsgLevel( "pa" + QString::number( pa.point( i ).x() ), 2 );
00404     QgsDebugMsgLevel( "pa" + QString::number( pa.point( i ).y() ), 2 );
00405   }
00406 #endif
00407 
00408   // The default pen gives bevelled joins between segements of the
00409   // polyline, which is good enough for the moment.
00410   //preserve a copy of the pen before we start fiddling with it
00411   QPen pen = p->pen(); // to be kept original
00412 
00413   //
00414   // experimental alpha transparency
00415   // 255 = opaque
00416   //
00417   QPen myTransparentPen = p->pen(); // store current pen
00418   QColor myColor = myTransparentPen.color();
00419   //only set transparency from layer level if renderer does not provide
00420   //transparency on class level
00421   if ( !mRenderer->usesTransparency() )
00422   {
00423     myColor.setAlpha( mTransparencyLevel );
00424   }
00425   myTransparentPen.setColor( myColor );
00426   p->setPen( myTransparentPen );
00427   p->drawPolyline( pa );
00428 
00429   // draw vertex markers if in editing mode, but only to the main canvas
00430   if ( mEditable && drawingToEditingCanvas )
00431   {
00432     QgsVectorLayer::VertexMarkerType markerType = currentVertexMarkerType();
00433 
00434     std::vector<double>::const_iterator xIt;
00435     std::vector<double>::const_iterator yIt;
00436     for ( xIt = x.begin(), yIt = y.begin(); xIt != x.end(); ++xIt, ++yIt )
00437     {
00438       drawVertexMarker(( int )( *xIt ), ( int )( *yIt ), *p, markerType );
00439     }
00440   }
00441 
00442   //restore the pen
00443   p->setPen( pen );
00444 
00445   return ptr;
00446 }
00447 
00448 unsigned char *QgsVectorLayer::drawPolygon(
00449   unsigned char *feature,
00450   QPainter *p,
00451   const QgsMapToPixel *mtp,
00452   const QgsCoordinateTransform *ct,
00453   bool drawingToEditingCanvas )
00454 {
00455   typedef std::pair<std::vector<double>, std::vector<double> > ringType;
00456   typedef ringType* ringTypePtr;
00457   typedef std::vector<ringTypePtr> ringsType;
00458 
00459   // get number of rings in the polygon
00460   unsigned int numRings = *(( int* )( feature + 1 + sizeof( int ) ) );
00461 
00462   if ( numRings == 0 )  // sanity check for zero rings in polygon
00463     return feature + 9;
00464 
00465   unsigned int wkbType = *(( int* )( feature + 1 ) );
00466 
00467   bool hasZValue = ( wkbType == QGis::WKBPolygon25D );
00468 
00469   int total_points = 0;
00470 
00471   // A vector containing a pointer to a pair of double vectors.The
00472   // first vector in the pair contains the x coordinates, and the
00473   // second the y coordinates.
00474   ringsType rings;
00475 
00476   // Set pointer to the first ring
00477   unsigned char* ptr = feature + 1 + 2 * sizeof( int );
00478 
00479   for ( register unsigned int idx = 0; idx < numRings; idx++ )
00480   {
00481     unsigned int nPoints = *(( int* )ptr );
00482 
00483     ringTypePtr ring = new ringType( std::vector<double>( nPoints ), std::vector<double>( nPoints ) );
00484     ptr += 4;
00485 
00486     // create a dummy vector for the z coordinate
00487     std::vector<double> zVector( nPoints, 0.0 );
00488     // Extract the points from the WKB and store in a pair of
00489     // vectors.
00490     for ( register unsigned int jdx = 0; jdx < nPoints; jdx++ )
00491     {
00492       ring->first[jdx] = *(( double * ) ptr );
00493       ptr += sizeof( double );
00494       ring->second[jdx] = *(( double * ) ptr );
00495       ptr += sizeof( double );
00496 
00497       if ( hasZValue )
00498         ptr += sizeof( double );
00499     }
00500     // If ring has fewer than two points, what is it then?
00501     // Anyway, this check prevents a crash
00502     if ( nPoints < 1 )
00503     {
00504       QgsDebugMsg( "Ring has only " + QString::number( nPoints ) + " points! Skipping this ring." );
00505       continue;
00506     }
00507 
00508     transformPoints( ring->first, ring->second, zVector, mtp, ct );
00509 
00510 #if defined(Q_WS_X11)
00511     // Work around a +/- 32768 limitation on coordinates in X11
00512 
00513     // Look through the x and y coordinates and see if there are any
00514     // that need trimming. If one is found, there's no need to look at
00515     // the rest of them so end the loop at that point.
00516     for ( register unsigned int i = 0; i < nPoints; ++i )
00517     {
00518       if ( std::abs( ring->first[i] ) > QgsClipper::MAX_X ||
00519            std::abs( ring->second[i] ) > QgsClipper::MAX_Y )
00520       {
00521         QgsClipper::trimFeature( ring->first, ring->second, false );
00522         break;
00523       }
00524     }
00525 #endif
00526 
00527     // Don't bother keeping the ring if it has been trimmed out of
00528     // existence.
00529     if ( ring->first.size() == 0 )
00530       delete ring;
00531     else
00532     {
00533       rings.push_back( ring );
00534       total_points += ring->first.size();
00535     }
00536   }
00537 
00538   // Now we draw the polygons
00539 
00540   // use painter paths for drawing polygons with holes
00541   // when adding polygon to the path they invert the area
00542   // this means that adding inner rings to the path creates
00543   // holes in outer ring
00544   QPainterPath path; // OddEven fill rule by default
00545 
00546   // Only try to draw polygons if there is something to draw
00547   if ( total_points > 0 )
00548   {
00549     // Store size here and use it in the loop to avoid penalty of
00550     // multiple calls to size()
00551     int numRings = rings.size();
00552     for ( register int i = 0; i < numRings; ++i )
00553     {
00554       // Store the pointer in a variable with a short name so as to make
00555       // the following code easier to type and read.
00556       ringTypePtr r = rings[i];
00557       // only do this once to avoid penalty of additional calls
00558       unsigned ringSize = r->first.size();
00559 
00560       // Transfer points to the array of QPointF
00561       QPolygonF pa( ringSize );
00562       for ( register unsigned int j = 0; j != ringSize; ++j )
00563       {
00564         pa[j].setX( r->first[j] );
00565         pa[j].setY( r->second[j] );
00566       }
00567 
00568       path.addPolygon( pa );
00569 
00570       // Tidy up the pointed to pairs of vectors as we finish with them
00571       delete rings[i];
00572     }
00573 
00574 #ifdef QGISDEBUGVERBOSE
00575     // this is only for verbose debug output -- no optimzation is
00576     // needed :)
00577     QgsDebugMsg( "Pixel points are:" );
00578     for ( int i = 0; i < pa.size(); ++i )
00579     {
00580       QgsDebugMsgLevel( "i" + QString::number( i ), 2 );
00581       QgsDebugMsgLevel( "pa[i].x()" + QString::number( pa[i].x() ), 2 );
00582       QgsDebugMsgLevel( "pa[i].y()" + QString::number( pa[i].y() ), 2 );
00583     }
00584     QgsDebugMsg( "Ring positions are:" );
00585     QgsDebugMsg( "Ring positions are:" );
00586     for ( int i = 0; i < ringDetails.size(); ++i )
00587     {
00588       QgsDebugMsgLevel( "ringDetails[i].first" + QString::number( ringDetails[i].first ), 2 );
00589       QgsDebugMsgLevel( "ringDetails[i].second" + QString::number( ringDetails[i].second ), 2 );
00590     }
00591     QgsDebugMsg( "Outer ring point is " + QString::number( outerRingPt.x() ) + ", " + QString::number( outerRingPt.y() ) );
00592 #endif
00593 
00594 #if 0
00595     // A bit of code to aid in working out what values of
00596     // QgsClipper::minX, etc cause the X11 zoom bug.
00597     int largestX  = -std::numeric_limits<int>::max();
00598     int smallestX = std::numeric_limits<int>::max();
00599     int largestY  = -std::numeric_limits<int>::max();
00600     int smallestY = std::numeric_limits<int>::max();
00601 
00602     for ( int i = 0; i < pa.size(); ++i )
00603     {
00604       largestX  = std::max( largestX,  pa.point( i ).x() );
00605       smallestX = std::min( smallestX, pa.point( i ).x() );
00606       largestY  = std::max( largestY,  pa.point( i ).y() );
00607       smallestY = std::min( smallestY, pa.point( i ).y() );
00608     }
00609     QgsDebugMsg( QString( "Largest  X coordinate was %1" ).arg( largestX ) );
00610     QgsDebugMsg( QString( "Smallest X coordinate was %1" ).arg( smallestX ) );
00611     QgsDebugMsg( QString( "Largest  Y coordinate was %1" ).arg( largestY ) );
00612     QgsDebugMsg( QString( "Smallest Y coordinate was %1" ).arg( smallestY ) );
00613 #endif
00614 
00615     //preserve a copy of the brush and pen before we start fiddling with it
00616     QBrush brush = p->brush(); //to be kept as original
00617     QPen pen = p->pen(); // to be kept original
00618     //
00619     // experimental alpha transparency
00620     // 255 = opaque
00621     //
00622     QBrush myTransparentBrush = p->brush();
00623     QColor myColor = brush.color();
00624 
00625     //only set transparency from layer level if renderer does not provide
00626     //transparency on class level
00627     if ( !mRenderer->usesTransparency() )
00628     {
00629       myColor.setAlpha( mTransparencyLevel );
00630     }
00631     myTransparentBrush.setColor( myColor );
00632     QPen myTransparentPen = p->pen(); // store current pen
00633     myColor = myTransparentPen.color();
00634 
00635     //only set transparency from layer level if renderer does not provide
00636     //transparency on class level
00637     if ( !mRenderer->usesTransparency() )
00638     {
00639       myColor.setAlpha( mTransparencyLevel );
00640     }
00641     myTransparentPen.setColor( myColor );
00642 
00643     p->setBrush( myTransparentBrush );
00644     p->setPen( myTransparentPen );
00645 
00646     //
00647     // draw the polygon
00648     //
00649     p->drawPath( path );
00650 
00651 
00652     // draw vertex markers if in editing mode, but only to the main canvas
00653     if ( mEditable && drawingToEditingCanvas )
00654     {
00655       QgsVectorLayer::VertexMarkerType markerType = currentVertexMarkerType();
00656 
00657       for ( int i = 0; i < path.elementCount(); ++i )
00658       {
00659         const QPainterPath::Element & e = path.elementAt( i );
00660         drawVertexMarker(( int )e.x, ( int )e.y, *p, markerType );
00661       }
00662     }
00663 
00664     //
00665     //restore brush and pen to original
00666     //
00667     p->setBrush( brush );
00668     p->setPen( pen );
00669 
00670   } // totalPoints > 0
00671 
00672   return ptr;
00673 }
00674 
00675 bool QgsVectorLayer::draw( QgsRenderContext& rendererContext )
00676 {
00677   //set update threshold before each draw to make sure the current setting is picked up
00678   QSettings settings;
00679   mUpdateThreshold = settings.value( "Map/updateThreshold", 0 ).toInt();
00680   //draw ( p, viewExtent, theMapToPixelTransform, ct, drawingToEditingCanvas, 1., 1.);
00681 
00682   if ( mRenderer )
00683   {
00684     // painter is active (begin has been called
00685     /* Steps to draw the layer
00686        1. get the features in the view extent by SQL query
00687        2. read WKB for a feature
00688        3. transform
00689        4. draw
00690     */
00691 
00692     QPen pen;
00693     /*Pointer to a marker image*/
00694     QImage marker;
00695 
00696     if ( mEditable )
00697     {
00698       // Destroy all cached geometries and clear the references to them
00699       deleteCachedGeometries();
00700     }
00701 
00702     updateFeatureCount();
00703     int totalFeatures = pendingFeatureCount();
00704     int featureCount = 0;
00705     QgsFeature fet;
00706     QgsAttributeList attributes = mRenderer->classificationAttributes();
00707     select( attributes, rendererContext.extent() );
00708 
00709     try
00710     {
00711       while ( nextFeature( fet ) )
00712       {
00713 
00714         if ( rendererContext.renderingStopped() )
00715         {
00716           break;
00717         }
00718 
00719 #ifndef Q_WS_MAC //MH: disable this on Mac for now to avoid problems with resizing
00720         if ( mUpdateThreshold > 0 && 0 == featureCount % mUpdateThreshold )
00721         {
00722           emit screenUpdateRequested();
00723           emit drawingProgress( featureCount, totalFeatures );
00724           qApp->processEvents();
00725         }
00726         else if ( featureCount % 1000 == 0 )
00727         {
00728           emit drawingProgress( featureCount, totalFeatures );
00729           qApp->processEvents();
00730         }
00731 #else
00732         Q_UNUSED( totalFeatures );
00733 #endif //Q_WS_MAC
00734 
00735         if ( mEditable )
00736         {
00737           // Cache this for the use of (e.g.) modifying the feature's uncommitted geometry.
00738           mCachedGeometries[fet.id()] = *fet.geometry();
00739         }
00740 
00741         // check if feature is selected
00742         // only show selections of the current layer
00743         // TODO: create a mechanism to let layer know whether it's current layer or not [MD]
00744         bool sel = mSelectedFeatureIds.contains( fet.id() );
00745 
00746         //QgsDebugMsg(QString("markerScale before renderFeature(): %1").arg(markerScaleFactor));
00747         // markerScalerFactore reflects the wanted scaling of the marker
00748         mRenderer->renderFeature(
00749           rendererContext.painter(),
00750           fet,
00751           &marker,
00752           sel,
00753           rendererContext.scaleFactor(),
00754           rendererContext.rasterScaleFactor() );
00755         // markerScalerFactore now reflects the actual scaling of the marker that the render performed.
00756         //QgsDebugMsg(QString("markerScale after renderFeature(): %1").arg(markerScaleFactor));
00757 
00758         //double scale = rendererContext.scaleFactor() /  markerScaleFactor;
00759         drawFeature(
00760           rendererContext.painter(),
00761           fet,
00762           &rendererContext.mapToPixel(),
00763           rendererContext.coordinateTransform(),
00764           &marker,
00765           rendererContext.scaleFactor(),
00766           rendererContext.rasterScaleFactor(),
00767           rendererContext.drawEditingInformation() );
00768 
00769         ++featureCount;
00770       }
00771     }
00772     catch ( QgsCsException &cse )
00773     {
00774       QString msg( "Failed to transform a point while drawing a feature of type '"
00775                    + fet.typeName() + "'. Ignoring this feature." );
00776       msg += cse.what();
00777       QgsLogger::warning( msg );
00778     }
00779 
00780   }
00781   else
00782   {
00783     QgsLogger::warning( "QgsRenderer is null in QgsVectorLayer::draw()" );
00784   }
00785 
00786   return TRUE; // Assume success always
00787 }
00788 
00789 void QgsVectorLayer::deleteCachedGeometries()
00790 {
00791   // Destroy any cached geometries
00792   mCachedGeometries.clear();
00793 }
00794 
00795 void QgsVectorLayer::drawVertexMarker( int x, int y, QPainter& p, QgsVectorLayer::VertexMarkerType type )
00796 {
00797   if ( type == QgsVectorLayer::SemiTransparentCircle )
00798   {
00799     p.setPen( QColor( 50, 100, 120, 200 ) );
00800     p.setBrush( QColor( 200, 200, 210, 120 ) );
00801     p.drawEllipse( QRectF( x - 7, y - 7, 14, 14 ) );
00802   }
00803   else
00804   {
00805     int size = 15;
00806     int m = ( size - 1 ) / 2;
00807     p.setPen( QColor( 255, 0, 0 ) );
00808     p.drawLine( x - m, y + m, x + m, y - m );
00809     p.drawLine( x - m, y - m, x + m, y + m );
00810   }
00811 }
00812 
00813 void QgsVectorLayer::select( int number, bool emitSignal )
00814 {
00815   mSelectedFeatureIds.insert( number );
00816 
00817   if ( emitSignal )
00818   {
00819     emit selectionChanged();
00820   }
00821 }
00822 
00823 void QgsVectorLayer::deselect( int number, bool emitSignal )
00824 {
00825   mSelectedFeatureIds.remove( number );
00826 
00827   if ( emitSignal )
00828   {
00829     emit selectionChanged();
00830   }
00831 }
00832 
00833 void QgsVectorLayer::select( QgsRectangle & rect, bool lock )
00834 {
00835   // normalize the rectangle
00836   rect.normalize();
00837 
00838   if ( lock == false )
00839   {
00840     removeSelection( FALSE ); // don't emit signal
00841   }
00842 
00843   //select all the elements
00844   select( QgsAttributeList(), rect, false, true );
00845 
00846   QgsFeature f;
00847   while ( nextFeature( f ) )
00848   {
00849     select( f.id(), false ); // don't emit signal (not to redraw it everytime)
00850   }
00851 
00852   emit selectionChanged(); // now emit signal to redraw layer
00853 }
00854 
00855 void QgsVectorLayer::invertSelection()
00856 {
00857   // copy the ids of selected features to tmp
00858   QgsFeatureIds tmp = mSelectedFeatureIds;
00859 
00860   removeSelection( FALSE ); // don't emit signal
00861 
00862   select( QgsAttributeList(), QgsRectangle(), false );
00863 
00864   QgsFeature fet;
00865   while ( nextFeature( fet ) )
00866   {
00867     select( fet.id(), false ); // don't emit signal
00868   }
00869 
00870   for ( QgsFeatureIds::iterator iter = tmp.begin(); iter != tmp.end(); ++iter )
00871   {
00872     mSelectedFeatureIds.remove( *iter );
00873   }
00874 
00875   emit selectionChanged();
00876 }
00877 
00878 void QgsVectorLayer::invertSelectionInRectangle( QgsRectangle & rect )
00879 {
00880   // normalize the rectangle
00881   rect.normalize();
00882 
00883   select( QgsAttributeList(), rect, false, true );
00884 
00885   QgsFeature fet;
00886   while ( nextFeature( fet ) )
00887   {
00888     if ( mSelectedFeatureIds.contains( fet.id() ) )
00889     {
00890       deselect( fet.id(), false ); // don't emit signal
00891     }
00892     else
00893     {
00894       select( fet.id(), false ); // don't emit signal
00895     }
00896   }
00897 
00898   emit selectionChanged();
00899 }
00900 
00901 void QgsVectorLayer::removeSelection( bool emitSignal )
00902 {
00903   mSelectedFeatureIds.clear();
00904 
00905   if ( emitSignal )
00906     emit selectionChanged();
00907 }
00908 
00909 void QgsVectorLayer::triggerRepaint()
00910 {
00911   emit repaintRequested();
00912 }
00913 
00914 QgsVectorDataProvider* QgsVectorLayer::dataProvider()
00915 {
00916   return mDataProvider;
00917 }
00918 
00919 const QgsVectorDataProvider* QgsVectorLayer::dataProvider() const
00920 {
00921   return mDataProvider;
00922 }
00923 
00924 void QgsVectorLayer::setProviderEncoding( const QString& encoding )
00925 {
00926   if ( mDataProvider )
00927   {
00928     mDataProvider->setEncoding( encoding );
00929   }
00930 }
00931 
00932 
00933 const QgsRenderer* QgsVectorLayer::renderer() const
00934 {
00935   return mRenderer;
00936 }
00937 
00938 void QgsVectorLayer::setRenderer( QgsRenderer * r )
00939 {
00940   if ( r != mRenderer )
00941   {
00942     delete mRenderer;
00943     mRenderer = r;
00944   }
00945 }
00946 
00947 QGis::GeometryType QgsVectorLayer::geometryType() const
00948 {
00949   if ( mDataProvider )
00950   {
00951     int type = mDataProvider->geometryType();
00952     switch ( type )
00953     {
00954       case QGis::WKBPoint:
00955       case QGis::WKBPoint25D:
00956         return QGis::Point;
00957 
00958       case QGis::WKBLineString:
00959       case QGis::WKBLineString25D:
00960         return QGis::Line;
00961 
00962       case QGis::WKBPolygon:
00963       case QGis::WKBPolygon25D:
00964         return QGis::Polygon;
00965 
00966       case QGis::WKBMultiPoint:
00967       case QGis::WKBMultiPoint25D:
00968         return QGis::Point;
00969 
00970       case QGis::WKBMultiLineString:
00971       case QGis::WKBMultiLineString25D:
00972         return QGis::Line;
00973 
00974       case QGis::WKBMultiPolygon:
00975       case QGis::WKBMultiPolygon25D:
00976         return QGis::Polygon;
00977     }
00978 #ifdef QGISDEBUG
00979     QgsLogger::debug( "Warning: Data Provider Geometry type is not recognised, is", type, 1, __FILE__, __FUNCTION__, __LINE__ );
00980 #endif
00981 
00982   }
00983   else
00984   {
00985 #ifdef QGISDEBUG
00986     qWarning( "warning, pointer to mDataProvider is null in QgsVectorLayer::type()" );
00987 #endif
00988 
00989   }
00990 
00991   // We shouldn't get here, and if we have, other things are likely to
00992   // go wrong. Code that uses the type() return value should be
00993   // rewritten to cope with a value of QGis::Unknown. To make this
00994   // need known, the following message is printed every time we get
00995   // here.
00996   QgsDebugMsg( "WARNING: This code should never be reached. Problems may occur..." );
00997 
00998   return QGis::UnknownGeometry;
00999 }
01000 
01001 QGis::WkbType QgsVectorLayer::wkbType() const
01002 {
01003   return ( QGis::WkbType )( mWkbType );
01004 }
01005 
01006 QgsRectangle QgsVectorLayer::boundingBoxOfSelected()
01007 {
01008   if ( mSelectedFeatureIds.size() == 0 )//no selected features
01009   {
01010     return QgsRectangle( 0, 0, 0, 0 );
01011   }
01012 
01013   QgsRectangle r, retval;
01014 
01015 
01016   select( QgsAttributeList(), QgsRectangle(), true );
01017 
01018   retval.setMinimal();
01019 
01020   QgsFeature fet;
01021   while ( nextFeature( fet ) )
01022   {
01023     if ( mSelectedFeatureIds.contains( fet.id() ) )
01024     {
01025       if ( fet.geometry() )
01026       {
01027         r = fet.geometry()->boundingBox();
01028         retval.combineExtentWith( &r );
01029       }
01030     }
01031   }
01032 
01033   if ( retval.width() == 0.0 || retval.height() == 0.0 )
01034   {
01035     // If all of the features are at the one point, buffer the
01036     // rectangle a bit. If they are all at zero, do something a bit
01037     // more crude.
01038 
01039     if ( retval.xMinimum() == 0.0 && retval.xMaximum() == 0.0 &&
01040          retval.yMinimum() == 0.0 && retval.yMaximum() == 0.0 )
01041     {
01042       retval.set( -1.0, -1.0, 1.0, 1.0 );
01043     }
01044     else
01045     {
01046       const double padFactor = 1e-8;
01047       double widthPad = retval.xMinimum() * padFactor;
01048       double heightPad = retval.yMinimum() * padFactor;
01049       double xmin = retval.xMinimum() - widthPad;
01050       double xmax = retval.xMaximum() + widthPad;
01051       double ymin = retval.yMinimum() - heightPad;
01052       double ymax = retval.yMaximum() + heightPad;
01053       retval.set( xmin, ymin, xmax, ymax );
01054     }
01055   }
01056 
01057   return retval;
01058 }
01059 
01060 
01061 
01062 long QgsVectorLayer::featureCount() const
01063 {
01064   if ( !mDataProvider )
01065   {
01066     QgsLogger::warning( " QgsVectorLayer::featureCount() invoked with null mDataProvider" );
01067     return 0;
01068   }
01069 
01070   return mDataProvider->featureCount();
01071 } // QgsVectorLayer::featureCount
01072 
01073 long QgsVectorLayer::updateFeatureCount() const
01074 {
01075   if ( !mDataProvider )
01076   {
01077     QgsLogger::warning( " QgsVectorLayer::updateFeatureCount() invoked with null mDataProvider" );
01078     return 0;
01079   }
01080   return mDataProvider->updateFeatureCount();
01081 }
01082 
01083 void QgsVectorLayer::updateExtents()
01084 {
01085   mLayerExtent.setMinimal();
01086 
01087   if ( !mDataProvider )
01088     QgsLogger::warning( " QgsVectorLayer::updateExtents() invoked with null mDataProvider" );
01089 
01090   if ( mDeletedFeatureIds.isEmpty() && mChangedGeometries.isEmpty() )
01091   {
01092     // get the extent of the layer from the provider
01093     // but only when there are some features already
01094     if ( mDataProvider->featureCount() != 0 )
01095     {
01096       QgsRectangle r = mDataProvider->extent();
01097       mLayerExtent.combineExtentWith( &r );
01098     }
01099 
01100     for ( QgsFeatureList::iterator it = mAddedFeatures.begin(); it != mAddedFeatures.end(); it++ )
01101     {
01102       QgsRectangle r = it->geometry()->boundingBox();
01103       mLayerExtent.combineExtentWith( &r );
01104     }
01105   }
01106   else
01107   {
01108     select( QgsAttributeList(), QgsRectangle(), true );
01109 
01110     QgsFeature fet;
01111     while ( nextFeature( fet ) )
01112     {
01113       if ( fet.geometry() )
01114       {
01115         QgsRectangle bb = fet.geometry()->boundingBox();
01116         mLayerExtent.combineExtentWith( &bb );
01117       }
01118     }
01119   }
01120 
01121   if ( mLayerExtent.xMinimum() > mLayerExtent.xMaximum() && mLayerExtent.yMinimum() > mLayerExtent.yMaximum() )
01122   {
01123     // special case when there are no features in provider nor any added
01124     mLayerExtent = QgsRectangle(); // use rectangle with zero coordinates
01125   }
01126 
01127   // Send this (hopefully) up the chain to the map canvas
01128   emit recalculateExtents();
01129 }
01130 
01131 QString QgsVectorLayer::subsetString()
01132 {
01133   if ( ! mDataProvider )
01134   {
01135     QgsLogger::warning( " QgsVectorLayer::subsetString() invoked with null mDataProvider" );
01136     return 0;
01137   }
01138   return mDataProvider->subsetString();
01139 }
01140 
01141 void QgsVectorLayer::setSubsetString( QString subset )
01142 {
01143   if ( ! mDataProvider )
01144   {
01145     QgsLogger::warning( " QgsVectorLayer::setSubsetString() invoked with null mDataProvider" );
01146     return;
01147   }
01148 
01149   mDataProvider->setSubsetString( subset );
01150   // get the updated data source string from the provider
01151   mDataSource = mDataProvider->dataSourceUri();
01152   updateExtents();
01153 }
01154 
01155 void QgsVectorLayer::updateFeatureAttributes( QgsFeature &f )
01156 {
01157   // do not update when we aren't in editing mode
01158   if ( ! mEditable )
01159     return;
01160 
01161   if ( mChangedAttributeValues.contains( f.id() ) )
01162   {
01163     const QgsAttributeMap &map = mChangedAttributeValues[f.id()];
01164     for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); it++ )
01165       f.changeAttribute( it.key(), it.value() );
01166   }
01167 
01168   // remove all attributes that will disappear
01169   const QgsAttributeMap &map = f.attributeMap();
01170   for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); it++ )
01171     if ( !mUpdatedFields.contains( it.key() ) )
01172       f.deleteAttribute( it.key() );
01173 
01174   // null/add all attributes that were added, but don't exist in the feature yet
01175   for ( QgsFieldMap::const_iterator it = mUpdatedFields.begin(); it != mUpdatedFields.end(); it++ )
01176     if ( !map.contains( it.key() ) )
01177       f.changeAttribute( it.key(), QVariant( QString::null ) );
01178 }
01179 
01180 void QgsVectorLayer::updateFeatureGeometry( QgsFeature &f )
01181 {
01182   if ( mChangedGeometries.contains( f.id() ) )
01183     f.setGeometry( mChangedGeometries[f.id()] );
01184 }
01185 
01186 
01187 void QgsVectorLayer::select( QgsAttributeList attributes, QgsRectangle rect, bool fetchGeometries, bool useIntersect )
01188 {
01189   if ( !mDataProvider )
01190     return;
01191 
01192   mFetching        = true;
01193   mFetchRect       = rect;
01194   mFetchAttributes = attributes;
01195   mFetchGeometry   = fetchGeometries;
01196 
01197   mFetchConsidered = mDeletedFeatureIds;
01198 
01199   if ( mEditable )
01200   {
01201     mFetchAddedFeaturesIt = mAddedFeatures.begin();
01202     mFetchChangedGeomIt = mChangedGeometries.begin();
01203   }
01204 
01205   //look in the normal features of the provider
01206   if ( mFetchAttributes.size() > 0 )
01207   {
01208     if ( mEditable )
01209     {
01210       // fetch only available field from provider
01211       QgsAttributeList provAttributes;
01212       for ( QgsAttributeList::iterator it = mFetchAttributes.begin(); it != mFetchAttributes.end(); it++ )
01213       {
01214         if ( !mUpdatedFields.contains( *it ) || mAddedAttributeIds.contains( *it ) )
01215           continue;
01216 
01217         provAttributes << *it;
01218       }
01219 
01220       mDataProvider->select(