QGIS API Documentation  master-6227475
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 <QProgressDialog>
00031 #include <QSettings>
00032 #include <QString>
00033 #include <QDomNode>
00034 #include <QVector>
00035 
00036 #include "qgsvectorlayer.h"
00037 
00038 #include "qgsattributeaction.h"
00039 
00040 #include "qgis.h" //for globals
00041 #include "qgsapplication.h"
00042 #include "qgscoordinatetransform.h"
00043 #include "qgsdatasourceuri.h"
00044 #include "qgsfeature.h"
00045 #include "qgsfeaturerequest.h"
00046 #include "qgsfield.h"
00047 #include "qgsgeometry.h"
00048 #include "qgslabel.h"
00049 #include "qgslogger.h"
00050 #include "qgsmessagelog.h"
00051 #include "qgsmaptopixel.h"
00052 #include "qgspoint.h"
00053 #include "qgsproviderregistry.h"
00054 #include "qgsrectangle.h"
00055 #include "qgsrendercontext.h"
00056 #include "qgscoordinatereferencesystem.h"
00057 #include "qgsvectordataprovider.h"
00058 #include "qgsgeometrycache.h"
00059 #include "qgsvectorlayereditbuffer.h"
00060 #include "qgsvectorlayereditutils.h"
00061 #include "qgsvectorlayerfeatureiterator.h"
00062 #include "qgsvectorlayerjoinbuffer.h"
00063 #include "qgsvectorlayerundocommand.h"
00064 #include "qgsvectoroverlay.h"
00065 #include "qgsmaplayerregistry.h"
00066 #include "qgsclipper.h"
00067 #include "qgsproject.h"
00068 
00069 #include "qgsrendererv2.h"
00070 #include "qgssymbolv2.h"
00071 #include "qgssymbollayerv2.h"
00072 #include "qgssinglesymbolrendererv2.h"
00073 #include "qgsdiagramrendererv2.h"
00074 #include "qgsstylev2.h"
00075 #include "qgssymbologyv2conversion.h"
00076 #include "qgspallabeling.h"
00077 
00078 #ifdef TESTPROVIDERLIB
00079 #include <dlfcn.h>
00080 #endif
00081 
00082 typedef bool saveStyle_t(
00083   const QString& uri,
00084   const QString& qmlStyle,
00085   const QString& sldStyle,
00086   const QString& styleName,
00087   const QString& styleDescription,
00088   const QString& uiFileContent,
00089   bool useAsDefault,
00090   QString& errCause
00091 );
00092 
00093 typedef QString loadStyle_t(
00094   const QString& uri,
00095   QString& errCause
00096 );
00097 
00098 typedef int listStyles_t(
00099   const QString& uri,
00100   QStringList &ids,
00101   QStringList &names,
00102   QStringList &descriptions,
00103   QString& errCause
00104 );
00105 
00106 typedef QString getStyleById_t(
00107   const QString& uri,
00108   QString styleID,
00109   QString& errCause
00110 );
00111 
00112 
00113 QgsVectorLayer::QgsVectorLayer( QString vectorLayerPath,
00114                                 QString baseName,
00115                                 QString providerKey,
00116                                 bool loadDefaultStyleFlag )
00117     : QgsMapLayer( VectorLayer, baseName, vectorLayerPath )
00118     , mUpdateThreshold( 0 )     // XXX better default value?
00119     , mDataProvider( NULL )
00120     , mProviderKey( providerKey )
00121     , mReadOnly( false )
00122     , mRendererV2( NULL )
00123     , mLabel( 0 )
00124     , mLabelOn( false )
00125     , mFeatureBlendMode( QPainter::CompositionMode_SourceOver ) // Default to normal feature blending
00126     , mLayerTransparency( 0 )
00127     , mVertexMarkerOnlyForSelection( false )
00128     , mCache( new QgsGeometryCache( this ) )
00129     , mEditBuffer( 0 )
00130     , mJoinBuffer( 0 )
00131     , mDiagramRenderer( 0 )
00132     , mDiagramLayerSettings( 0 )
00133     , mValidExtent( false )
00134     , mSymbolFeatureCounted( false )
00135     , mCurrentRendererContext( 0 )
00136 
00137 {
00138   mActions = new QgsAttributeAction( this );
00139 
00140   // if we're given a provider type, try to create and bind one to this layer
00141   if ( ! mProviderKey.isEmpty() )
00142   {
00143     setDataProvider( mProviderKey );
00144   }
00145   if ( mValid )
00146   {
00147     // Always set crs
00148     setCoordinateSystem();
00149 
00150     mJoinBuffer = new QgsVectorLayerJoinBuffer();
00151 
00152     updateFields();
00153 
00154     // check if there is a default style / propertysheet defined
00155     // for this layer and if so apply it
00156     bool defaultLoadedFlag = false;
00157     if ( loadDefaultStyleFlag )
00158     {
00159       loadDefaultStyle( defaultLoadedFlag );
00160     }
00161 
00162     // if the default style failed to load or was disabled use some very basic defaults
00163     if ( !defaultLoadedFlag && hasGeometryType() )
00164     {
00165       // add single symbol renderer
00166       setRendererV2( QgsFeatureRendererV2::defaultRenderer( geometryType() ) );
00167     }
00168 
00169     connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( checkJoinLayerRemove( QString ) ) );
00170 
00171     // Get the update threshold from user settings. We
00172     // do this only on construction to avoid the penality of
00173     // fetching this each time the layer is drawn. If the user
00174     // changes the threshold from the preferences dialog, it will
00175     // have no effect on existing layers
00176     // TODO: load this setting somewhere else [MD]
00177     //QSettings settings;
00178     //mUpdateThreshold = settings.readNumEntry("Map/updateThreshold", 1000);
00179   }
00180 
00181   connect( this, SIGNAL( selectionChanged( QgsFeatureIds, QgsFeatureIds, bool ) ), this, SIGNAL( selectionChanged() ) );
00182 } // QgsVectorLayer ctor
00183 
00184 
00185 
00186 QgsVectorLayer::~QgsVectorLayer()
00187 {
00188   QgsDebugMsg( "entered." );
00189 
00190   emit layerDeleted();
00191 
00192   mValid = false;
00193 
00194   delete mDataProvider;
00195   delete mEditBuffer;
00196   delete mJoinBuffer;
00197   delete mCache;
00198   delete mLabel;
00199   delete mDiagramLayerSettings;
00200 
00201   delete mActions;
00202 
00203   //delete remaining overlays
00204 
00205   QList<QgsVectorOverlay*>::iterator overlayIt = mOverlays.begin();
00206   for ( ; overlayIt != mOverlays.end(); ++overlayIt )
00207   {
00208     delete *overlayIt;
00209   }
00210 }
00211 
00212 QString QgsVectorLayer::storageType() const
00213 {
00214   if ( mDataProvider )
00215   {
00216     return mDataProvider->storageType();
00217   }
00218   return 0;
00219 }
00220 
00221 
00222 QString QgsVectorLayer::capabilitiesString() const
00223 {
00224   if ( mDataProvider )
00225   {
00226     return mDataProvider->capabilitiesString();
00227   }
00228   return 0;
00229 }
00230 
00231 QString QgsVectorLayer::dataComment() const
00232 {
00233   if ( mDataProvider )
00234   {
00235     return mDataProvider->dataComment();
00236   }
00237   return QString();
00238 }
00239 
00240 
00241 QString QgsVectorLayer::providerType() const
00242 {
00243   return mProviderKey;
00244 }
00245 
00249 void QgsVectorLayer::setDisplayField( QString fldName )
00250 {
00251   if ( !hasGeometryType() )
00252     return;
00253 
00254   // If fldName is provided, use it as the display field, otherwise
00255   // determine the field index for the feature column of the identify
00256   // dialog. We look for fields containing "name" first and second for
00257   // fields containing "id". If neither are found, the first field
00258   // is used as the node.
00259   QString idxName = "";
00260   QString idxId = "";
00261 
00262   if ( !fldName.isEmpty() )
00263   {
00264     mDisplayField = fldName;
00265   }
00266   else
00267   {
00268     const QgsFields &fields = pendingFields();
00269     int fieldsSize = fields.size();
00270 
00271     for ( int idx = 0; idx < fields.count(); ++idx )
00272     {
00273       QString fldName = fields[idx].name();
00274       QgsDebugMsg( "Checking field " + fldName + " of " + QString::number( fieldsSize ) + " total" );
00275 
00276       // Check the fields and keep the first one that matches.
00277       // We assume that the user has organized the data with the
00278       // more "interesting" field names first. As such, name should
00279       // be selected before oldname, othername, etc.
00280       if ( fldName.indexOf( "name", false ) > -1 )
00281       {
00282         if ( idxName.isEmpty() )
00283         {
00284           idxName = fldName;
00285         }
00286       }
00287       if ( fldName.indexOf( "descrip", false ) > -1 )
00288       {
00289         if ( idxName.isEmpty() )
00290         {
00291           idxName = fldName;
00292         }
00293       }
00294       if ( fldName.indexOf( "id", false ) > -1 )
00295       {
00296         if ( idxId.isEmpty() )
00297         {
00298           idxId = fldName;
00299         }
00300       }
00301     }
00302 
00303     //if there were no fields in the dbf just return - otherwise qgis segfaults!
00304     if ( fieldsSize == 0 )
00305       return;
00306 
00307     if ( idxName.length() > 0 )
00308     {
00309       mDisplayField = idxName;
00310     }
00311     else
00312     {
00313       if ( idxId.length() > 0 )
00314       {
00315         mDisplayField = idxId;
00316       }
00317       else
00318       {
00319         mDisplayField = fields[0].name();
00320       }
00321     }
00322 
00323   }
00324 }
00325 
00326 // NOTE this is a temporary method added by Tim to prevent label clipping
00327 // which was occurring when labeller was called in the main draw loop
00328 // This method will probably be removed again in the near future!
00329 void QgsVectorLayer::drawLabels( QgsRenderContext& rendererContext )
00330 {
00331   if ( !hasGeometryType() )
00332     return;
00333 
00334   QgsDebugMsg( "Starting draw of labels: " + id() );
00335 
00336   if ( mRendererV2 && mLabelOn &&
00337        ( !mLabel->scaleBasedVisibility() ||
00338          ( mLabel->minScale() <= rendererContext.rendererScale() &&
00339            rendererContext.rendererScale() <= mLabel->maxScale() ) ) )
00340   {
00341     QgsAttributeList attributes;
00342     foreach ( QString attrName, mRendererV2->usedAttributes() )
00343     {
00344       int attrNum = fieldNameIndex( attrName );
00345       attributes.append( attrNum );
00346     }
00347     // make sure the renderer is ready for classification ("symbolForFeature")
00348     mRendererV2->startRender( rendererContext, this );
00349 
00350     // Add fields required for labels
00351     mLabel->addRequiredFields( attributes );
00352 
00353     QgsDebugMsg( "Selecting features based on view extent" );
00354 
00355     int featureCount = 0;
00356 
00357     try
00358     {
00359       // select the records in the extent. The provider sets a spatial filter
00360       // and sets up the selection set for retrieval
00361       QgsFeatureIterator fit = getFeatures( QgsFeatureRequest()
00362                                             .setFilterRect( rendererContext.extent() )
00363                                             .setSubsetOfAttributes( attributes ) );
00364 
00365       QgsFeature fet;
00366       while ( fit.nextFeature( fet ) )
00367       {
00368         if ( mRendererV2->willRenderFeature( fet ) )
00369         {
00370           bool sel = mSelectedFeatureIds.contains( fet.id() );
00371           mLabel->renderLabel( rendererContext, fet, sel, 0 );
00372         }
00373         featureCount++;
00374       }
00375     }
00376     catch ( QgsCsException &e )
00377     {
00378       Q_UNUSED( e );
00379       QgsDebugMsg( "Error projecting label locations" );
00380     }
00381 
00382     if ( mRendererV2 )
00383     {
00384       mRendererV2->stopRender( rendererContext );
00385     }
00386 
00387     QgsDebugMsg( QString( "Total features processed %1" ).arg( featureCount ) );
00388 
00389     // XXX Something in our draw event is triggering an additional draw event when resizing [TE 01/26/06]
00390     // XXX Calling this will begin processing the next draw event causing image havoc and recursion crashes.
00391     //qApp->processEvents();
00392 
00393   }
00394 }
00395 
00396 
00397 
00398 void QgsVectorLayer::drawRendererV2( QgsFeatureIterator &fit, QgsRenderContext& rendererContext, bool labeling )
00399 {
00400   if ( !hasGeometryType() )
00401     return;
00402 
00403   mCurrentRendererContext = &rendererContext;
00404 
00405   QSettings settings;
00406   bool vertexMarkerOnlyForSelection = settings.value( "/qgis/digitizing/marker_only_for_selected", false ).toBool();
00407 
00408 #ifndef Q_WS_MAC
00409   int featureCount = 0;
00410 #endif //Q_WS_MAC
00411 
00412   QgsFeature fet;
00413   while ( fit.nextFeature( fet ) )
00414   {
00415     try
00416     {
00417       if ( !fet.geometry() )
00418         continue; // skip features without geometry
00419 
00420 #ifndef Q_WS_MAC //MH: disable this on Mac for now to avoid problems with resizing
00421 #ifdef Q_WS_X11
00422       if ( !mEnableBackbuffer ) // do not handle events, as we're already inside a paint event
00423       {
00424 #endif // Q_WS_X11
00425         if ( mUpdateThreshold > 0 && 0 == featureCount % mUpdateThreshold )
00426         {
00427           emit screenUpdateRequested();
00428           // emit drawingProgress( featureCount, totalFeatures );
00429           qApp->processEvents();
00430         }
00431         else if ( featureCount % 1000 == 0 )
00432         {
00433           // emit drawingProgress( featureCount, totalFeatures );
00434           qApp->processEvents();
00435         }
00436 #ifdef Q_WS_X11
00437       }
00438 #endif // Q_WS_X11
00439 #endif // Q_WS_MAC
00440 
00441       if ( rendererContext.renderingStopped() )
00442       {
00443         break;
00444       }
00445 
00446       bool sel = mSelectedFeatureIds.contains( fet.id() );
00447       bool drawMarker = ( mEditBuffer && ( !vertexMarkerOnlyForSelection || sel ) );
00448 
00449       // render feature
00450       bool rendered = mRendererV2->renderFeature( fet, rendererContext, -1, sel, drawMarker );
00451 
00452       if ( mEditBuffer )
00453       {
00454         // Cache this for the use of (e.g.) modifying the feature's uncommitted geometry.
00455         mCache->cacheGeometry( fet.id(), *fet.geometry() );
00456       }
00457 
00458       // labeling - register feature
00459       if ( rendered && rendererContext.labelingEngine() )
00460       {
00461         if ( labeling )
00462         {
00463           rendererContext.labelingEngine()->registerFeature( this, fet, rendererContext );
00464         }
00465         if ( mDiagramRenderer )
00466         {
00467           rendererContext.labelingEngine()->registerDiagramFeature( this, fet, rendererContext );
00468         }
00469       }
00470     }
00471     catch ( const QgsCsException &cse )
00472     {
00473       Q_UNUSED( cse );
00474       QgsDebugMsg( QString( "Failed to transform a point while drawing a feature with ID '%1'. Ignoring this feature. %2" )
00475                    .arg( fet.id() ).arg( cse.what() ) );
00476     }
00477 #ifndef Q_WS_MAC
00478     ++featureCount;
00479 #endif //Q_WS_MAC
00480   }
00481 
00482   stopRendererV2( rendererContext, NULL );
00483 
00484   mCurrentRendererContext = NULL;
00485 
00486 #ifndef Q_WS_MAC
00487   QgsDebugMsg( QString( "Total features processed %1" ).arg( featureCount ) );
00488 #endif
00489 }
00490 
00491 void QgsVectorLayer::drawRendererV2Levels( QgsFeatureIterator &fit, QgsRenderContext& rendererContext, bool labeling )
00492 {
00493   if ( !hasGeometryType() )
00494     return;
00495 
00496   QHash< QgsSymbolV2*, QList<QgsFeature> > features; // key = symbol, value = array of features
00497 
00498   QSettings settings;
00499   bool vertexMarkerOnlyForSelection = settings.value( "/qgis/digitizing/marker_only_for_selected", false ).toBool();
00500 
00501   QgsSingleSymbolRendererV2* selRenderer = NULL;
00502   if ( !mSelectedFeatureIds.isEmpty() )
00503   {
00504     selRenderer = new QgsSingleSymbolRendererV2( QgsSymbolV2::defaultSymbol( geometryType() ) );
00505     selRenderer->symbol()->setColor( rendererContext.selectionColor() );
00506     selRenderer->setVertexMarkerAppearance( currentVertexMarkerType(), currentVertexMarkerSize() );
00507     selRenderer->startRender( rendererContext, this );
00508   }
00509 
00510   // 1. fetch features
00511   QgsFeature fet;
00512 #ifndef Q_WS_MAC
00513   int featureCount = 0;
00514 #endif //Q_WS_MAC
00515   while ( fit.nextFeature( fet ) )
00516   {
00517     if ( !fet.geometry() )
00518       continue; // skip features without geometry
00519 
00520     if ( rendererContext.renderingStopped() )
00521     {
00522       stopRendererV2( rendererContext, selRenderer );
00523       return;
00524     }
00525 #ifndef Q_WS_MAC
00526     if ( featureCount % 1000 == 0 )
00527     {
00528       qApp->processEvents();
00529     }
00530 #endif //Q_WS_MAC
00531     QgsSymbolV2* sym = mRendererV2->symbolForFeature( fet );
00532     if ( !sym )
00533     {
00534       continue;
00535     }
00536 
00537     if ( !features.contains( sym ) )
00538     {
00539       features.insert( sym, QList<QgsFeature>() );
00540     }
00541     features[sym].append( fet );
00542 
00543     if ( mEditBuffer )
00544     {
00545       // Cache this for the use of (e.g.) modifying the feature's uncommitted geometry.
00546       mCache->cacheGeometry( fet.id(), *fet.geometry() );
00547     }
00548 
00549     if ( sym && rendererContext.labelingEngine() )
00550     {
00551       if ( labeling )
00552       {
00553         rendererContext.labelingEngine()->registerFeature( this, fet, rendererContext );
00554       }
00555       if ( mDiagramRenderer )
00556       {
00557         rendererContext.labelingEngine()->registerDiagramFeature( this, fet, rendererContext );
00558       }
00559     }
00560 
00561 #ifndef Q_WS_MAC
00562     ++featureCount;
00563 #endif //Q_WS_MAC
00564   }
00565 
00566   // find out the order
00567   QgsSymbolV2LevelOrder levels;
00568   QgsSymbolV2List symbols = mRendererV2->symbols();
00569   for ( int i = 0; i < symbols.count(); i++ )
00570   {
00571     QgsSymbolV2* sym = symbols[i];
00572     for ( int j = 0; j < sym->symbolLayerCount(); j++ )
00573     {
00574       int level = sym->symbolLayer( j )->renderingPass();
00575       if ( level < 0 || level >= 1000 ) // ignore invalid levels
00576         continue;
00577       QgsSymbolV2LevelItem item( sym, j );
00578       while ( level >= levels.count() ) // append new empty levels
00579         levels.append( QgsSymbolV2Level() );
00580       levels[level].append( item );
00581     }
00582   }
00583 
00584   // 2. draw features in correct order
00585   for ( int l = 0; l < levels.count(); l++ )
00586   {
00587     QgsSymbolV2Level& level = levels[l];
00588     for ( int i = 0; i < level.count(); i++ )
00589     {
00590       QgsSymbolV2LevelItem& item = level[i];
00591       if ( !features.contains( item.symbol() ) )
00592       {
00593         QgsDebugMsg( "level item's symbol not found!" );
00594         continue;
00595       }
00596       int layer = item.layer();
00597       QList<QgsFeature>& lst = features[item.symbol()];
00598       QList<QgsFeature>::iterator fit;
00599 #ifndef Q_WS_MAC
00600       featureCount = 0;
00601 #endif //Q_WS_MAC
00602       for ( fit = lst.begin(); fit != lst.end(); ++fit )
00603       {
00604         if ( rendererContext.renderingStopped() )
00605         {
00606           stopRendererV2( rendererContext, selRenderer );
00607           return;
00608         }
00609 #ifndef Q_WS_MAC
00610         if ( featureCount % 1000 == 0 )
00611         {
00612           qApp->processEvents();
00613         }
00614 #endif //Q_WS_MAC
00615         bool sel = mSelectedFeatureIds.contains( fit->id() );
00616         // maybe vertex markers should be drawn only during the last pass...
00617         bool drawMarker = ( mEditBuffer && ( !vertexMarkerOnlyForSelection || sel ) );
00618 
00619         try
00620         {
00621           mRendererV2->renderFeature( *fit, rendererContext, layer, sel, drawMarker );
00622         }
00623         catch ( const QgsCsException &cse )
00624         {
00625           Q_UNUSED( cse );
00626           QgsDebugMsg( QString( "Failed to transform a point while drawing a feature with ID '%1'. Ignoring this feature. %2" )
00627                        .arg( fet.id() ).arg( cse.what() ) );
00628         }
00629 #ifndef Q_WS_MAC
00630         ++featureCount;
00631 #endif //Q_WS_MAC
00632       }
00633     }
00634   }
00635 
00636   stopRendererV2( rendererContext, selRenderer );
00637 }
00638 
00639 void QgsVectorLayer::reload()
00640 {
00641   if ( mDataProvider )
00642   {
00643     mDataProvider->reloadData();
00644   }
00645 }
00646 
00647 bool QgsVectorLayer::draw( QgsRenderContext& rendererContext )
00648 {
00649   if ( !hasGeometryType() )
00650     return true;
00651 
00652   //set update threshold before each draw to make sure the current setting is picked up
00653   QSettings settings;
00654   mUpdateThreshold = settings.value( "Map/updateThreshold", 0 ).toInt();
00655 #ifdef Q_WS_X11
00656   mEnableBackbuffer = settings.value( "/Map/enableBackbuffer", 1 ).toBool();
00657 #endif
00658 
00659   if ( !mRendererV2 )
00660     return false;
00661 
00662   QgsDebugMsg( "rendering v2:\n" + mRendererV2->dump() );
00663 
00664   if ( mEditBuffer )
00665   {
00666     // Destroy all cached geometries and clear the references to them
00667     mCache->deleteCachedGeometries();
00668     mCache->setCachedGeometriesRect( rendererContext.extent() );
00669 
00670     // set editing vertex markers style
00671     mRendererV2->setVertexMarkerAppearance( currentVertexMarkerType(), currentVertexMarkerSize() );
00672   }
00673 
00674   QgsAttributeList attributes;
00675   foreach ( QString attrName, mRendererV2->usedAttributes() )
00676   {
00677     int attrNum = fieldNameIndex( attrName );
00678     attributes.append( attrNum );
00679     QgsDebugMsg( "attrs: " + attrName + " - " + QString::number( attrNum ) );
00680   }
00681 
00682   bool labeling = false;
00683   //register label and diagram layer to the labeling engine
00684   prepareLabelingAndDiagrams( rendererContext, attributes, labeling );
00685 
00686   //do startRender before getFeatures to give renderers the possibility of querying features in the startRender method
00687   mRendererV2->startRender( rendererContext, this );
00688 
00689   QgsFeatureIterator fit = getFeatures( QgsFeatureRequest()
00690                                         .setFilterRect( rendererContext.extent() )
00691                                         .setSubsetOfAttributes( attributes ) );
00692 
00693   if (( mRendererV2->capabilities() & QgsFeatureRendererV2::SymbolLevels )
00694       && mRendererV2->usingSymbolLevels() )
00695     drawRendererV2Levels( fit, rendererContext, labeling );
00696   else
00697     drawRendererV2( fit, rendererContext, labeling );
00698 
00699   return true;
00700 }
00701 
00702 void QgsVectorLayer::drawVertexMarker( double x, double y, QPainter& p, QgsVectorLayer::VertexMarkerType type, int m )
00703 {
00704   if ( type == QgsVectorLayer::SemiTransparentCircle )
00705   {
00706     p.setPen( QColor( 50, 100, 120, 200 ) );
00707     p.setBrush( QColor( 200, 200, 210, 120 ) );
00708     p.drawEllipse( x - m, y - m, m * 2 + 1, m * 2 + 1 );
00709   }
00710   else if ( type == QgsVectorLayer::Cross )
00711   {
00712     p.setPen( QColor( 255, 0, 0 ) );
00713     p.drawLine( x - m, y + m, x + m, y - m );
00714     p.drawLine( x - m, y - m, x + m, y + m );
00715   }
00716 }
00717 
00718 void QgsVectorLayer::select( const QgsFeatureId& fid )
00719 {
00720   mSelectedFeatureIds.insert( fid );
00721 
00722   setCacheImage( 0 );
00723   emit selectionChanged( QgsFeatureIds() << fid, QgsFeatureIds(), false );
00724 }
00725 
00726 void QgsVectorLayer::select( const QgsFeatureIds& featureIds )
00727 {
00728   mSelectedFeatureIds.unite( featureIds );
00729 
00730   setCacheImage( 0 );
00731   emit selectionChanged( featureIds, QgsFeatureIds(), false );
00732 }
00733 
00734 void QgsVectorLayer::deselect( const QgsFeatureId fid )
00735 {
00736   mSelectedFeatureIds.remove( fid );
00737 
00738   setCacheImage( 0 );
00739   emit selectionChanged( QgsFeatureIds(), QgsFeatureIds() << fid, false );
00740 }
00741 
00742 void QgsVectorLayer::deselect( const QgsFeatureIds& featureIds )
00743 {
00744   mSelectedFeatureIds.subtract( featureIds );
00745 
00746   setCacheImage( 0 );
00747   emit selectionChanged( QgsFeatureIds(), featureIds, false );
00748 }
00749 
00750 void QgsVectorLayer::select( QgsRectangle & rect, bool addToSelection )
00751 {
00752   // normalize the rectangle
00753   rect.normalize();
00754 
00755   //select all the elements
00756   QgsFeatureIterator fit = getFeatures( QgsFeatureRequest()
00757                                         .setFilterRect( rect )
00758                                         .setFlags( QgsFeatureRequest::ExactIntersect | QgsFeatureRequest::NoGeometry )
00759                                         .setSubsetOfAttributes( QgsAttributeList() ) );
00760 
00761   QgsFeatureIds ids;
00762 
00763   QgsFeature f;
00764   while ( fit.nextFeature( f ) )
00765   {
00766     ids << f.id();
00767   }
00768 
00769   if ( !addToSelection )
00770   {
00771     setSelectedFeatures( mSelectedFeatureIds + ids );
00772   }
00773   else
00774   {
00775     select( ids );
00776   }
00777 }
00778 
00779 void QgsVectorLayer::modifySelection( QgsFeatureIds selectIds, QgsFeatureIds deselectIds )
00780 {
00781   QgsFeatureIds intersectingIds = selectIds & deselectIds;
00782   if ( intersectingIds.count() > 0 )
00783   {
00784     QgsDebugMsg( "Trying to select and deselect the same item at the same time. Unsure what to do. Selecting dubious items." );
00785   }
00786 
00787   mSelectedFeatureIds -= deselectIds;
00788   mSelectedFeatureIds += selectIds;
00789 
00790   emit selectionChanged( selectIds, deselectIds - intersectingIds, false );
00791 }
00792 
00793 void QgsVectorLayer::invertSelection()
00794 {
00795   // copy the ids of selected features to tmp
00796   QgsFeatureIds tmp = mSelectedFeatureIds;
00797 
00798   QgsFeatureIterator fit = getFeatures( QgsFeatureRequest()
00799                                         .setFlags( QgsFeatureRequest::NoGeometry )
00800                                         .setSubsetOfAttributes( QgsAttributeList() ) );
00801 
00802   QgsFeatureIds ids;
00803 
00804   QgsFeature fet;
00805   while ( fit.nextFeature( fet ) )
00806   {
00807     ids << fet.id();
00808   }
00809 
00810   ids.subtract( mSelectedFeatureIds );
00811 
00812   setSelectedFeatures( ids );
00813 }
00814 
00815 void QgsVectorLayer::selectAll()
00816 {
00817     QgsFeatureIterator fit = getFeatures( QgsFeatureRequest()
00818                                           .setFlags( QgsFeatureRequest::NoGeometry )
00819                                           .setSubsetOfAttributes( QgsAttributeList() ) );
00820 
00821     QgsFeatureIds ids;
00822 
00823     QgsFeature fet;
00824     while ( fit.nextFeature( fet ) )
00825     {
00826       ids << fet.id();
00827     }
00828 
00829     setSelectedFeatures( ids );
00830 }
00831 
00832 void QgsVectorLayer::invertSelectionInRectangle( QgsRectangle & rect )
00833 {
00834   // normalize the rectangle
00835   rect.normalize();
00836 
00837   QgsFeatureIterator fit = getFeatures( QgsFeatureRequest()
00838                                         .setFilterRect( rect )
00839                                         .setFlags( QgsFeatureRequest::NoGeometry | QgsFeatureRequest::ExactIntersect )
00840                                         .setSubsetOfAttributes( QgsAttributeList() ) );
00841 
00842   QgsFeatureIds selectIds;
00843   QgsFeatureIds deselectIds;
00844 
00845   QgsFeature fet;
00846   while ( fit.nextFeature( fet ) )
00847   {
00848     if ( mSelectedFeatureIds.contains( fet.id() ) )
00849     {
00850       deselectIds << fet.id();
00851     }
00852     else
00853     {
00854       selectIds << fet.id();
00855     }
00856   }
00857 
00858   modifySelection( selectIds, deselectIds );
00859 }
00860 
00861 void QgsVectorLayer::removeSelection()
00862 {
00863   if ( mSelectedFeatureIds.size() == 0 )
00864     return;
00865 
00866   setSelectedFeatures( QgsFeatureIds() );
00867 }
00868 
00869 void QgsVectorLayer::triggerRepaint()
00870 {
00871   emit repaintRequested();
00872 }
00873 
00874 QgsVectorDataProvider* QgsVectorLayer::dataProvider()
00875 {
00876   return mDataProvider;
00877 }
00878 
00879 const QgsVectorDataProvider* QgsVectorLayer::dataProvider() const
00880 {
00881   return mDataProvider;
00882 }
00883 
00884 void QgsVectorLayer::setProviderEncoding( const QString& encoding )
00885 {
00886   if ( mDataProvider )
00887   {
00888     mDataProvider->setEncoding( encoding );
00889     updateFields();
00890   }
00891 }
00892 
00893 void QgsVectorLayer::setDiagramRenderer( QgsDiagramRendererV2* r )
00894 {
00895   delete mDiagramRenderer;
00896   mDiagramRenderer = r;
00897 }
00898 
00899 QGis::GeometryType QgsVectorLayer::geometryType() const
00900 {
00901   if ( mDataProvider )
00902   {
00903     int type = mDataProvider->geometryType();
00904     switch ( type )
00905     {
00906       case QGis::WKBPoint:
00907       case QGis::WKBPoint25D:
00908         return QGis::Point;
00909 
00910       case QGis::WKBLineString:
00911       case QGis::WKBLineString25D:
00912         return QGis::Line;
00913 
00914       case QGis::WKBPolygon:
00915       case QGis::WKBPolygon25D:
00916         return QGis::Polygon;
00917 
00918       case QGis::WKBMultiPoint:
00919       case QGis::WKBMultiPoint25D:
00920         return QGis::Point;
00921 
00922       case QGis::WKBMultiLineString:
00923       case QGis::WKBMultiLineString25D:
00924         return QGis::Line;
00925 
00926       case QGis::WKBMultiPolygon:
00927       case QGis::WKBMultiPolygon25D:
00928         return QGis::Polygon;
00929 
00930       case QGis::WKBNoGeometry:
00931         return QGis::NoGeometry;
00932     }
00933     QgsDebugMsg( QString( "Data Provider Geometry type is not recognised, is %1" ).arg( type ) );
00934   }
00935   else
00936   {
00937     QgsDebugMsg( "pointer to mDataProvider is null" );
00938   }
00939 
00940   // We shouldn't get here, and if we have, other things are likely to
00941   // go wrong. Code that uses the type() return value should be
00942   // rewritten to cope with a value of QGis::Unknown. To make this
00943   // need known, the following message is printed every time we get
00944   // here.
00945   QgsDebugMsg( "WARNING: This code should never be reached. Problems may occur..." );
00946 
00947   return QGis::UnknownGeometry;
00948 }
00949 
00950 bool QgsVectorLayer::hasGeometryType() const
00951 {
00952   QGis::GeometryType t = geometryType();
00953   return ( t != QGis::NoGeometry && t != QGis::UnknownGeometry );
00954 }
00955 
00956 QGis::WkbType QgsVectorLayer::wkbType() const
00957 {
00958   return ( QGis::WkbType )( mWkbType );
00959 }
00960 
00961 QgsRectangle QgsVectorLayer::boundingBoxOfSelected()
00962 {
00963   if ( mSelectedFeatureIds.size() == 0 ) //no selected features
00964   {
00965     return QgsRectangle( 0, 0, 0, 0 );
00966   }
00967 
00968   QgsRectangle r, retval;
00969   retval.setMinimal();
00970 
00971   QgsFeature fet;
00972   if ( mDataProvider->capabilities() & QgsVectorDataProvider::SelectAtId )
00973   {
00974     foreach ( QgsFeatureId fid, mSelectedFeatureIds )
00975     {
00976       if ( getFeatures( QgsFeatureRequest()
00977                         .setFilterFid( fid )
00978                         .setSubsetOfAttributes( QgsAttributeList() ) )
00979            .nextFeature( fet ) &&
00980            fet.geometry() )
00981       {
00982         r = fet.geometry()->boundingBox();
00983         retval.combineExtentWith( &r );
00984       }
00985     }
00986   }
00987   else
00988   {
00989     QgsFeatureIterator fit = getFeatures( QgsFeatureRequest()
00990                                           .setSubsetOfAttributes( QgsAttributeList() ) );
00991 
00992     while ( fit.nextFeature( fet ) )
00993     {
00994       if ( mSelectedFeatureIds.contains( fet.id() ) )
00995       {
00996         if ( fet.geometry() )
00997         {
00998           r = fet.geometry()->boundingBox();
00999           retval.combineExtentWith( &r );
01000         }
01001       }
01002     }
01003   }
01004 
01005   if ( retval.width() == 0.0 || retval.height() == 0.0 )
01006   {
01007     // If all of the features are at the one point, buffer the
01008     // rectangle a bit. If they are all at zero, do something a bit
01009     // more crude.
01010 
01011     if ( retval.xMinimum() == 0.0 && retval.xMaximum() == 0.0 &&
01012          retval.yMinimum() == 0.0 && retval.yMaximum() == 0.0 )
01013     {
01014       retval.set( -1.0, -1.0, 1.0, 1.0 );
01015     }
01016   }
01017 
01018   return retval;
01019 }
01020 
01021 long QgsVectorLayer::featureCount() const
01022 {
01023   if ( !mDataProvider )
01024   {
01025     QgsDebugMsg( "invoked with null mDataProvider" );
01026     return 0;
01027   }
01028 
01029   return mDataProvider->featureCount();
01030 }
01031 
01032 long QgsVectorLayer::featureCount( QgsSymbolV2* symbol )
01033 {
01034   if ( !mSymbolFeatureCounted ) return -1;
01035   return mSymbolFeatureCountMap.value( symbol );
01036 }
01037 
01038 bool QgsVectorLayer::countSymbolFeatures( bool showProgress )
01039 {
01040   if ( mSymbolFeatureCounted ) return true;
01041   mSymbolFeatureCountMap.clear();
01042 
01043   if ( !mDataProvider )
01044   {
01045     QgsDebugMsg( "invoked with null mDataProvider" );
01046     return false;
01047   }
01048   if ( !mRendererV2 )
01049   {
01050     QgsDebugMsg( "invoked with null mRendererV2" );
01051     return false;
01052   }
01053 
01054   QgsLegendSymbolList symbolList = mRendererV2->legendSymbolItems();
01055   QgsLegendSymbolList::const_iterator symbolIt = symbolList.constBegin();
01056 
01057   for ( ; symbolIt != symbolList.constEnd(); ++symbolIt )
01058   {
01059     mSymbolFeatureCountMap.insert( symbolIt->second, 0 );
01060   }
01061 
01062   long nFeatures = pendingFeatureCount();
01063   QProgressDialog progressDialog( tr( "Updating feature count for layer %1" ).arg( name() ), tr( "Abort" ), 0, nFeatures );
01064   progressDialog.setWindowModality( Qt::WindowModal );
01065   int featuresCounted = 0;
01066 
01067   QgsFeatureIterator fit = getFeatures( QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ) );
01068 
01069   // Renderer (rule based) may depend on context scale, with scale is ignored if 0
01070   QgsRenderContext renderContext;
01071   renderContext.setRendererScale( 0 );
01072   mRendererV2->startRender( renderContext, this );
01073 
01074   QgsFeature f;
01075   while ( fit.nextFeature( f ) )
01076   {
01077     QgsSymbolV2List featureSymbolList = mRendererV2->symbolsForFeature( f );
01078     for ( QgsSymbolV2List::iterator symbolIt = featureSymbolList.begin(); symbolIt != featureSymbolList.end(); ++symbolIt )
01079     {
01080       mSymbolFeatureCountMap[*symbolIt] += 1;
01081     }
01082     ++featuresCounted;
01083 
01084     if ( showProgress )
01085     {
01086       if ( featuresCounted % 50 == 0 )
01087       {
01088         if ( featuresCounted > nFeatures ) //sometimes the feature count is not correct
01089         {
01090           progressDialog.setMaximum( 0 );
01091         }
01092         progressDialog.setValue( featuresCounted );
01093         if ( progressDialog.wasCanceled() )
01094         {
01095           mSymbolFeatureCountMap.clear();
01096           mRendererV2->stopRender( renderContext );
01097           return false;
01098         }
01099       }
01100     }
01101   }
01102   mRendererV2->stopRender( renderContext );
01103   progressDialog.setValue( nFeatures );
01104   mSymbolFeatureCounted = true;
01105   return true;
01106 }
01107 
01108 void QgsVectorLayer::updateExtents()
01109 {
01110   mValidExtent = false;
01111 }
01112 
01113 void QgsVectorLayer::setExtent( const QgsRectangle &r )
01114 {
01115   QgsMapLayer::setExtent( r );
01116   mValidExtent = true;
01117 }
01118 
01119 QgsRectangle QgsVectorLayer::extent()
01120 {
01121   if ( mValidExtent )
01122     return QgsMapLayer::extent();
01123 
01124   QgsRectangle rect;
01125   rect.setMinimal();
01126 
01127   if ( !hasGeometryType() )
01128     return rect;
01129 
01130   if ( !mDataProvider )
01131   {
01132     QgsDebugMsg( "invoked with null mDataProvider" );
01133   }
01134 
01135   if ( mEditBuffer && mEditBuffer->mDeletedFeatureIds.isEmpty() && mEditBuffer->mChangedGeometries.isEmpty() )
01136   {
01137     mDataProvider->updateExtents();
01138 
01139     // get the extent of the layer from the provider
01140     // but only when there are some features already
01141     if ( mDataProvider->featureCount() != 0 )
01142     {
01143       QgsRectangle r = mDataProvider->extent();
01144       rect.combineExtentWith( &r );
01145     }
01146 
01147     for ( QgsFeatureMap::iterator it = mEditBuffer->mAddedFeatures.begin(); it != mEditBuffer->mAddedFeatures.end(); it++ )
01148     {
01149       QgsRectangle r = it->geometry()->boundingBox();
01150       rect.combineExtentWith( &r );
01151     }
01152   }
01153   else
01154   {
01155     QgsFeatureIterator fit = getFeatures( QgsFeatureRequest()
01156                                           .setSubsetOfAttributes( QgsAttributeList() ) );
01157 
01158     QgsFeature fet;
01159     while ( fit.nextFeature( fet ) )
01160     {
01161       if ( fet.geometry() )
01162       {
01163         QgsRectangle bb = fet.geometry()->boundingBox();
01164         rect.combineExtentWith( &bb );
01165       }
01166     }
01167   }
01168 
01169   if ( rect.xMinimum() > rect.xMaximum() && rect.yMinimum() > rect.yMaximum() )
01170   {
01171     // special case when there are no features in provider nor any added
01172     rect = QgsRectangle(); // use rectangle with zero coordinates
01173   }
01174 
01175   setExtent( rect );
01176 
01177   // Send this (hopefully) up the chain to the map canvas
01178   emit recalculateExtents();
01179 
01180   return rect;
01181 }
01182 
01183 QString QgsVectorLayer::subsetString()
01184 {
01185   if ( ! mDataProvider )
01186   {
01187     QgsDebugMsg( "invoked with null mDataProvider" );
01188     return 0;
01189   }
01190   return mDataProvider->subsetString();
01191 }
01192 
01193 bool QgsVectorLayer::setSubsetString( QString subset )
01194 {
01195   if ( ! mDataProvider )
01196   {
01197     QgsDebugMsg( "invoked with null mDataProvider" );
01198     return false;
01199   }
01200 
01201   bool res = mDataProvider->setSubsetString( subset );
01202 
01203   // get the updated data source string from the provider
01204   mDataSource = mDataProvider->dataSourceUri();
01205   updateExtents();
01206 
01207   if ( res )
01208     setCacheImage( 0 );
01209 
01210   return res;
01211 }
01212 
01213 
01214 QgsFeatureIterator QgsVectorLayer::getFeatures( const QgsFeatureRequest& request )
01215 {
01216   if ( !mDataProvider )
01217     return QgsFeatureIterator();
01218 
01219   return QgsFeatureIterator( new QgsVectorLayerFeatureIterator( this, request ) );
01220 }
01221 
01222 
01223 bool QgsVectorLayer::addFeature( QgsFeature& f, bool alsoUpdateExtent )
01224 {
01225   Q_UNUSED( alsoUpdateExtent ); // TODO[MD]
01226   if ( !mEditBuffer || !mDataProvider )
01227     return false;
01228 
01229   return mEditBuffer->addFeature( f );
01230 }
01231 
01232 bool QgsVectorLayer::updateFeature( QgsFeature &f )
01233 {
01234   QgsFeatureRequest req;
01235   req.setFilterFid( f.id() );
01236   if ( !f.geometry() )
01237     req.setFlags( QgsFeatureRequest::NoGeometry );
01238   if ( f.attributes().isEmpty() )
01239     req.setSubsetOfAttributes( QgsAttributeList() );
01240 
01241   QgsFeature current;
01242   if ( !getFeatures( req ).nextFeature( current ) )
01243   {
01244     QgsDebugMsg( QString( "feature %1 could not be retrieved" ).arg( f.id() ) );
01245     return false;
01246   }
01247 
01248   if ( f.geometry() && current.geometry() && f.geometry() != current.geometry() && !f.geometry()->isGeosEqual( *current.geometry() ) )
01249   {
01250     if ( !changeGeometry( f.id(), f.geometry() ) )
01251     {
01252       QgsDebugMsg( QString( "geometry of feature %1 could not be changed." ).arg( f.id() ) );
01253       return false;
01254     }
01255   }
01256 
01257   const QgsAttributes &fa = f.attributes();
01258   const QgsAttributes &ca = current.attributes();
01259 
01260   for ( int attr = 0; attr < fa.count(); ++attr )
01261   {
01262     if ( fa[attr] != ca[attr] )
01263     {
01264       if ( !changeAttributeValue( f.id(), attr, fa[attr] ) )
01265       {
01266         QgsDebugMsg( QString( "attribute %1 of feature %2 could not be changed." ).arg( attr ).arg( f.id() ) );
01267         return false;
01268       }
01269     }
01270   }
01271 
01272   return true;
01273 }
01274 
01275 
01276 bool QgsVectorLayer::insertVertex( double x, double y, QgsFeatureId atFeatureId, int beforeVertex )
01277 {
01278   if ( !mEditBuffer || !mDataProvider )
01279     return false;
01280 
01281   QgsVectorLayerEditUtils utils( this );
01282   return utils.insertVertex( x, y, atFeatureId, beforeVertex );
01283 }
01284 
01285 
01286 bool QgsVectorLayer::moveVertex( double x, double y, QgsFeatureId atFeatureId, int atVertex )
01287 {
01288   if ( !mEditBuffer || !mDataProvider )
01289     return false;
01290 
01291   QgsVectorLayerEditUtils utils( this );
01292   return utils.moveVertex( x, y, atFeatureId, atVertex );
01293 }
01294 
01295 
01296 bool QgsVectorLayer::deleteVertex( QgsFeatureId atFeatureId, int atVertex )
01297 {
01298   if ( !mEditBuffer || !mDataProvider )
01299     return false;
01300 
01301   QgsVectorLayerEditUtils utils( this );
01302   return utils.deleteVertex( atFeatureId, atVertex );
01303 }
01304 
01305 
01306 bool QgsVectorLayer::deleteSelectedFeatures()
01307 {
01308   if ( !( mDataProvider->capabilities() & QgsVectorDataProvider::DeleteFeatures ) )
01309   {
01310     return false;
01311   }
01312 
01313   if ( !isEditable() )
01314   {
01315     return false;
01316   }
01317 
01318   if ( mSelectedFeatureIds.size() == 0 )
01319     return true;
01320 
01321   while ( mSelectedFeatureIds.size() > 0 )
01322   {
01323     QgsFeatureId fid = *mSelectedFeatureIds.begin();
01324     deleteFeature( fid );  // removes from selection
01325   }
01326 
01327   // invalidate cache
01328   setCacheImage( 0 );
01329   triggerRepaint();
01330   updateExtents();
01331 
01332   return true;
01333 }
01334 
01335 int QgsVectorLayer::addRing( const QList<QgsPoint>& ring )
01336 {
01337   if ( !mEditBuffer || !mDataProvider )
01338     return 6;
01339 
01340   QgsVectorLayerEditUtils utils( this );
01341   return utils.addRing( ring );
01342 }
01343 
01344 int QgsVectorLayer::addPart( const QList<QgsPoint> &points )
01345 {
01346   if ( !mEditBuffer || !mDataProvider )
01347     return 7;
01348 
01349   //number of selected features must be 1
01350 
01351   if ( mSelectedFeatureIds.size() < 1 )
01352   {
01353     QgsDebugMsg( "Number of selected features <1" );
01354     return 4;
01355   }
01356   else if ( mSelectedFeatureIds.size() > 1 )
01357   {
01358     QgsDebugMsg( "Number of selected features >1" );
01359     return 5;
01360   }
01361 
01362   QgsVectorLayerEditUtils utils( this );
01363   return utils.addPart( points, *mSelectedFeatureIds.constBegin() );
01364 }
01365 
01366 
01367 int QgsVectorLayer::translateFeature( QgsFeatureId featureId, double dx, double dy )
01368 {
01369   if ( !mEditBuffer || !mDataProvider )
01370     return -1;
01371 
01372   QgsVectorLayerEditUtils utils( this );
01373   return utils.translateFeature( featureId, dx, dy );
01374 }
01375 
01376 int QgsVectorLayer::splitFeatures( const QList<QgsPoint>& splitLine, bool topologicalEditing )
01377 {
01378   if ( !mEditBuffer || !mDataProvider )
01379     return -1;
01380 
01381   QgsVectorLayerEditUtils utils( this );
01382   return utils.splitFeatures( splitLine, topologicalEditing );
01383 }
01384 
01385 int QgsVectorLayer::removePolygonIntersections( QgsGeometry* geom, QgsFeatureIds ignoreFeatures )
01386 {
01387   if ( !hasGeometryType() )
01388     return 1;
01389 
01390   int returnValue = 0;
01391 
01392   //first test if geom really has type polygon or multipolygon
01393   if ( geom->type() != QGis::Polygon )
01394   {
01395     return 1;
01396   }
01397 
01398   //get bounding box of geom
01399   QgsRectangle geomBBox = geom->boundingBox();
01400 
01401   //get list of features that intersect this bounding box
01402   QgsFeatureIterator fit = getFeatures( QgsFeatureRequest()
01403                                         .setFilterRect( geomBBox )
01404                                         .setFlags( QgsFeatureRequest::ExactIntersect )
01405                                         .setSubsetOfAttributes( QgsAttributeList() ) );
01406 
01407   QgsFeature f;
01408   while ( fit.nextFeature( f ) )
01409   {
01410     if ( ignoreFeatures.contains( f.id() ) )
01411     {
01412       continue;
01413     }
01414 
01415     //call geometry->makeDifference for each feature
01416     QgsGeometry *currentGeom = f.geometry();
01417     if ( currentGeom )
01418     {
01419       if ( geom->makeDifference( currentGeom ) != 0 )
01420       {
01421         returnValue = 2;
01422       }
01423     }
01424   }
01425 
01426   return returnValue;
01427 }
01428 
01429 int QgsVectorLayer::addTopologicalPoints( QgsGeometry* geom )
01430 {
01431   if ( !mEditBuffer || !mDataProvider )
01432     return -1;
01433 
01434   QgsVectorLayerEditUtils utils( this );
01435   return utils.addTopologicalPoints( geom );
01436 }
01437 
01438 int QgsVectorLayer::addTopologicalPoints( const QgsPoint& p )
01439 {
01440   if ( !mEditBuffer || !mDataProvider )
01441     return -1;
01442 
01443   QgsVectorLayerEditUtils utils( this );
01444   return utils.addTopologicalPoints( p );
01445 }
01446 
01447 QgsLabel *QgsVectorLayer::label()
01448 {
01449   return mLabel;
01450 }
01451 
01452 const QgsLabel *QgsVectorLayer::label() const
01453 {
01454   return mLabel;
01455 }
01456 
01457 void QgsVectorLayer::enableLabels( bool on )
01458 {
01459   mLabelOn = on;
01460 }
01461 
01462 bool QgsVectorLayer::hasLabelsEnabled( void ) const
01463 {
01464   return mLabelOn;
01465 }
01466 
01467 bool QgsVectorLayer::startEditing()
01468 {
01469   if ( !mDataProvider )
01470   {
01471     return false;
01472   }
01473 
01474   // allow editing if provider supports any of the capabilities
01475   if ( !( mDataProvider->capabilities() & QgsVectorDataProvider::EditingCapabilities ) )
01476   {
01477     return false;
01478   }
01479 
01480   if ( mReadOnly )
01481   {
01482     return false;
01483   }
01484 
01485   if ( mEditBuffer )
01486   {
01487     // editing already underway
01488     return false;
01489   }
01490 
01491   mEditBuffer = new QgsVectorLayerEditBuffer( this );
01492   // forward signals
01493   connect( mEditBuffer, SIGNAL( layerModified() ), this, SIGNAL( layerModified() ) ); // TODO[MD]: necessary?
01494   //connect( mEditBuffer, SIGNAL( layerModified() ), this, SLOT( triggerRepaint() ) ); // TODO[MD]: works well?
01495   connect( mEditBuffer, SIGNAL( featureAdded( QgsFeatureId ) ), this, SIGNAL( featureAdded( QgsFeatureId ) ) );
01496   connect( mEditBuffer, SIGNAL( featureDeleted( QgsFeatureId ) ), this, SIGNAL( featureDeleted( QgsFeatureId ) ) );
01497   connect( mEditBuffer, SIGNAL( geometryChanged( QgsFeatureId, QgsGeometry& ) ), this, SIGNAL( geometryChanged( QgsFeatureId, QgsGeometry& ) ) );
01498   connect( mEditBuffer, SIGNAL( attributeValueChanged( QgsFeatureId, int, QVariant ) ), this, SIGNAL( attributeValueChanged( QgsFeatureId, int, QVariant ) ) );
01499   connect( mEditBuffer, SIGNAL( attributeAdded( int ) ), this, SIGNAL( attributeAdded( int ) ) );
01500   connect( mEditBuffer, SIGNAL( attributeDeleted( int ) ), this, SIGNAL( attributeDeleted( int ) ) );
01501   connect( mEditBuffer, SIGNAL( committedFeaturesAdded( QString, QgsFeatureList ) ), this, SIGNAL( committedFeaturesAdded( QString, QgsFeatureList ) ) );
01502   connect( mEditBuffer, SIGNAL( committedFeaturesRemoved( QString, QgsFeatureIds ) ), this, SIGNAL( committedFeaturesRemoved( QString, QgsFeatureIds ) ) );
01503 
01504   updateFields();
01505 
01506   emit editingStarted();
01507 
01508   return true;
01509 }
01510 
01511 bool QgsVectorLayer::readXml( const QDomNode& layer_node )
01512 {
01513   QgsDebugMsg( QString( "Datasource in QgsVectorLayer::readXml: " ) + mDataSource.toLocal8Bit().data() );
01514 
01515   //process provider key
01516   QDomNode pkeyNode = layer_node.namedItem( "provider" );
01517 
01518   if ( pkeyNode.isNull() )
01519   {
01520     mProviderKey = "";
01521   }
01522   else
01523   {
01524     QDomElement pkeyElt = pkeyNode.toElement();
01525     mProviderKey = pkeyElt.text();
01526   }
01527 
01528   // determine type of vector layer
01529   if ( ! mProviderKey.isNull() )
01530   {
01531     // if the provider string isn't empty, then we successfully
01532     // got the stored provider
01533   }
01534   else if ( mDataSource.contains( "dbname=" ) )
01535   {
01536     mProviderKey = "postgres";
01537   }
01538   else
01539   {
01540     mProviderKey = "ogr";
01541   }
01542 
01543   if ( ! setDataProvider( mProviderKey ) )
01544   {
01545     return false;
01546   }
01547 
01548   QDomElement pkeyElem = pkeyNode.toElement();
01549   if ( !pkeyElem.isNull() )
01550   {
01551     QString encodingString = pkeyElem.attribute( "encoding" );
01552     if ( !encodingString.isEmpty() )
01553     {
01554       mDataProvider->setEncoding( encodingString );
01555     }
01556   }
01557 
01558   //load vector joins
01559   if ( !mJoinBuffer )
01560   {
01561     mJoinBuffer = new QgsVectorLayerJoinBuffer();
01562   }
01563   mJoinBuffer->readXml( layer_node );
01564 
01565   updateFields();
01566   connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( checkJoinLayerRemove( QString ) ) );
01567 
01568   QDomNode prevExpNode = layer_node.namedItem( "previewExpression" );
01569 
01570   if ( prevExpNode.isNull() )
01571   {
01572     mDisplayExpression = "";
01573   }
01574   else
01575   {
01576     QDomElement prevExpElem = prevExpNode.toElement();
01577     mDisplayExpression = prevExpElem.text();
01578   }
01579 
01580   QString errorMsg;
01581   if ( !readSymbology( layer_node, errorMsg ) )
01582   {
01583     return false;
01584   }
01585 
01586   return mValid;               // should be true if read successfully
01587 
01588 } // void QgsVectorLayer::readXml
01589 
01590 
01591 bool QgsVectorLayer::setDataProvider( QString const & provider )
01592 {
01593   // XXX should I check for and possibly delete any pre-existing providers?
01594   // XXX How often will that scenario occur?
01595 
01596   mProviderKey = provider;     // XXX is this necessary?  Usually already set
01597   // XXX when execution gets here.
01598 
01599   //XXX - This was a dynamic cast but that kills the Windows
01600   //      version big-time with an abnormal termination error
01601   mDataProvider =
01602     ( QgsVectorDataProvider* )( QgsProviderRegistry::instance()->provider( provider, mDataSource ) );
01603 
01604   if ( mDataProvider )
01605   {
01606     QgsDebugMsg( "Instantiated the data provider plugin" );
01607 
01608     mValid = mDataProvider->isValid();
01609     if ( mValid )
01610     {
01611 
01612       // TODO: Check if the provider has the capability to send fullExtentCalculated
01613       connect( mDataProvider, SIGNAL( fullExtentCalculated() ), this, SLOT( updateExtents() ) );
01614 
01615       // get the extent
01616       QgsRectangle mbr = mDataProvider->extent();
01617 
01618       // show the extent
01619       QString s = mbr.toString();
01620       QgsDebugMsg( "Extent of layer: " +  s );
01621       // store the extent
01622       setExtent( mbr );
01623 
01624       // get and store the feature type
01625       mWkbType = mDataProvider->geometryType();
01626 
01627       // look at the fields in the layer and set the primary
01628       // display field using some real fuzzy logic
01629       setDisplayField();
01630 
01631       if ( mProviderKey == "postgres" )
01632       {
01633         QgsDebugMsg( "Beautifying layer name " + name() );
01634 
01635         // adjust the display name for postgres layers
01636         QRegExp reg( "\"[^\"]+\"\\.\"([^\"]+)\"( \\([^)]+\\))?" );
01637         if ( reg.indexIn( name() ) >= 0 )
01638         {
01639           QStringList stuff = reg.capturedTexts();
01640           QString lName = stuff[1];
01641 
01642           const QMap<QString, QgsMapLayer*> &layers = QgsMapLayerRegistry::instance()->mapLayers();
01643 
01644           QMap<QString, QgsMapLayer*>::const_iterator it;
01645           for ( it = layers.constBegin(); it != layers.constEnd() && ( *it )->name() != lName; it++ )
01646             ;
01647 
01648           if ( it != layers.constEnd() && stuff.size() > 2 )
01649           {
01650             lName += "." + stuff[2].mid( 2, stuff[2].length() - 3 );
01651           }
01652 
01653           if ( !lName.isEmpty() )
01654             setLayerName( lName );
01655         }
01656 
01657         QgsDebugMsg( "Beautified layer name " + name() );
01658 
01659         // deal with unnecessary schema qualification to make v.in.ogr happy
01660         mDataSource = mDataProvider->dataSourceUri();
01661       }
01662       else if ( mProviderKey == "osm" )
01663       {
01664         // make sure that the "observer" has been removed from URI to avoid crashes
01665         mDataSource = mDataProvider->dataSourceUri();
01666       }
01667       else if ( provider == "ogr" )
01668       {
01669         // make sure that the /vsigzip or /vsizip is added to uri, if applicable
01670         mDataSource = mDataProvider->dataSourceUri();
01671         if ( mDataSource.right( 10 ) == "|layerid=0" )
01672           mDataSource.chop( 10 );
01673       }
01674 
01675       // label
01676       mLabel = new QgsLabel( mDataProvider->fields() );
01677       mLabelOn = false;
01678     }
01679     else
01680     {
01681       QgsDebugMsg( "Invalid provider plugin " + QString( mDataSource.toUtf8() ) );
01682       return false;
01683     }
01684   }
01685   else
01686   {
01687     QgsDebugMsg( " unable to get data provider" );
01688     return false;
01689   }
01690 
01691   return true;
01692 
01693 } // QgsVectorLayer:: setDataProvider
01694 
01695 
01696 
01697 
01698 /* virtual */
01699 bool QgsVectorLayer::writeXml( QDomNode & layer_node,
01700                                QDomDocument & document )
01701 {
01702   // first get the layer element so that we can append the type attribute
01703 
01704   QDomElement mapLayerNode = layer_node.toElement();
01705 
01706   if ( mapLayerNode.isNull() || ( "maplayer" != mapLayerNode.nodeName() ) )
01707   {
01708     QgsDebugMsg( "can't find <maplayer>" );
01709     return false;
01710   }
01711 
01712   mapLayerNode.setAttribute( "type", "vector" );
01713 
01714   // set the geometry type
01715   mapLayerNode.setAttribute( "geometry", QGis::vectorGeometryType( geometryType() ) );
01716 
01717   // add provider node
01718   if ( mDataProvider )
01719   {
01720     QDomElement provider  = document.createElement( "provider" );
01721     provider.setAttribute( "encoding", mDataProvider->encoding() );
01722     QDomText providerText = document.createTextNode( providerType() );
01723     provider.appendChild( providerText );
01724     layer_node.appendChild( provider );
01725   }
01726 
01727   // save preview expression
01728   QDomElement prevExpElem = document.createElement( "previewExpression" );
01729   QDomText prevExpText = document.createTextNode( mDisplayExpression );
01730   prevExpElem.appendChild( prevExpText );
01731   layer_node.appendChild( prevExpElem );
01732 
01733   //save joins
01734   mJoinBuffer->writeXml( layer_node, document );
01735 
01736   // renderer specific settings
01737   QString errorMsg;
01738   return writeSymbology( layer_node, document, errorMsg );
01739 } // bool QgsVectorLayer::writeXml
01740 
01741 bool QgsVectorLayer::readSymbology( const QDomNode& node, QString& errorMessage )
01742 {
01743   Q_UNUSED( errorMessage );
01744   if ( hasGeometryType() )
01745   {
01746     // try renderer v2 first
01747     QDomElement rendererElement = node.firstChildElement( RENDERER_TAG_NAME );
01748     if ( !rendererElement.isNull() )
01749     {
01750       QgsFeatureRendererV2* r = QgsFeatureRendererV2::load( rendererElement );
01751       if ( !r )
01752         return false;
01753 
01754       setRendererV2( r );
01755     }
01756     else
01757     {
01758       QgsFeatureRendererV2* r = QgsSymbologyV2Conversion::readOldRenderer( node, geometryType() );
01759       if ( !r )
01760         r = QgsFeatureRendererV2::defaultRenderer( geometryType() );
01761 
01762       setRendererV2( r );
01763     }
01764 
01765     // get and set the display field if it exists.
01766     QDomNode displayFieldNode = node.namedItem( "displayfield" );
01767     if ( !displayFieldNode.isNull() )
01768     {
01769       QDomElement e = displayFieldNode.toElement();
01770       setDisplayField( e.text() );
01771     }
01772 
01773     // get and set the blend mode if it exists
01774     QDomNode blendModeNode = node.namedItem( "blendMode" );
01775     if ( !blendModeNode.isNull() )
01776     {
01777       QDomElement e = blendModeNode.toElement();
01778       setBlendMode( QgsMapRenderer::getCompositionMode(( QgsMapRenderer::BlendMode ) e.text().toInt() ) );
01779     }
01780 
01781     // get and set the feature blend mode if it exists
01782     QDomNode featureBlendModeNode = node.namedItem( "featureBlendMode" );
01783     if ( !featureBlendModeNode.isNull() )
01784     {
01785       QDomElement e = featureBlendModeNode.toElement();
01786       setFeatureBlendMode( QgsMapRenderer::getCompositionMode(( QgsMapRenderer::BlendMode ) e.text().toInt() ) );
01787     }
01788 
01789     // get and set the layer transparency if it exists
01790     QDomNode layerTransparencyNode = node.namedItem( "layerTransparency" );
01791     if ( !layerTransparencyNode.isNull() )
01792     {
01793       QDomElement e = layerTransparencyNode.toElement();
01794       setLayerTransparency( e.text().toInt() );
01795     }
01796 
01797     // use scale dependent visibility flag
01798     QDomElement e = node.toElement();
01799     mLabel->setScaleBasedVisibility( e.attribute( "scaleBasedLabelVisibilityFlag", "0" ) == "1" );
01800     mLabel->setMinScale( e.attribute( "minLabelScale", "1" ).toFloat() );
01801     mLabel->setMaxScale( e.attribute( "maxLabelScale", "100000000" ).toFloat() );
01802 
01803     //also restore custom properties (for labeling-ng)
01804     readCustomProperties( node, "labeling" );
01805 
01806     // Test if labeling is on or off
01807     QDomNode labelnode = node.namedItem( "label" );
01808     QDomElement element = labelnode.toElement();
01809     int hasLabelsEnabled = element.text().toInt();
01810     if ( hasLabelsEnabled < 1 )
01811     {
01812       enableLabels( false );
01813     }
01814     else
01815     {
01816       enableLabels( true );
01817     }
01818 
01819     QDomNode labelattributesnode = node.namedItem( "labelattributes" );
01820 
01821     if ( !labelattributesnode.isNull() )
01822     {
01823       QgsDebugMsg( "calling readXML" );
01824       mLabel->readXML( labelattributesnode );
01825     }
01826 
01827     //diagram renderer and diagram layer settings
01828     delete mDiagramRenderer; mDiagramRenderer = 0;
01829     QDomElement singleCatDiagramElem = node.firstChildElement( "SingleCategoryDiagramRenderer" );
01830     if ( !singleCatDiagramElem.isNull() )
01831     {
01832       mDiagramRenderer = new QgsSingleCategoryDiagramRenderer();
01833       mDiagramRenderer->readXML( singleCatDiagramElem );
01834     }
01835     QDomElement linearDiagramElem = node.firstChildElement( "LinearlyInterpolatedDiagramRenderer" );
01836     if ( !linearDiagramElem.isNull() )
01837     {
01838       mDiagramRenderer = new QgsLinearlyInterpolatedDiagramRenderer();
01839       mDiagramRenderer->readXML( linearDiagramElem );
01840     }
01841 
01842     if ( mDiagramRenderer )
01843     {
01844       QDomElement diagramSettingsElem = node.firstChildElement( "DiagramLayerSettings" );
01845       if ( !diagramSettingsElem.isNull() )
01846       {
01847         mDiagramLayerSettings = new QgsDiagramLayerSettings();
01848         mDiagramLayerSettings->readXML( diagramSettingsElem );
01849       }
01850     }
01851   }
01852 
01853   // process the attribute actions
01854   mActions->readXML( node );
01855 
01856   mEditTypes.clear();
01857   QDomNode editTypesNode = node.namedItem( "edittypes" );
01858   if ( !editTypesNode.isNull() )
01859   {
01860     QDomNodeList editTypeNodes = editTypesNode.childNodes();
01861 
01862     for ( int i = 0; i < editTypeNodes.size(); i++ )
01863     {
01864       QDomNode editTypeNode = editTypeNodes.at( i );
01865       QDomElement editTypeElement = editTypeNode.toElement();
01866 
01867       QString name = editTypeElement.attribute( "name" );
01868       if ( fieldNameIndex( name ) < -1 )
01869         continue;
01870 
01871       EditType editType = ( EditType ) editTypeElement.attribute( "type" ).toInt();
01872       mEditTypes.insert( name, editType );
01873 
01874       int editable = editTypeElement.attribute( "editable" , "1" ).toInt();
01875       mFieldEditables.insert( name, editable == 1 );
01876 
01877       switch ( editType )
01878       {
01879         case ValueMap:
01880           if ( editTypeNode.hasChildNodes() )
01881           {
01882             mValueMaps.insert( name, QMap<QString, QVariant>() );
01883 
01884             QDomNodeList valueMapNodes = editTypeNode.childNodes();
01885             for ( int j = 0; j < valueMapNodes.size(); j++ )
01886             {
01887               QDomElement value = valueMapNodes.at( j ).toElement();
01888               mValueMaps[ name ].insert( value.attribute( "key" ), value.attribute( "value" ) );
01889             }
01890           }
01891           break;
01892 
01893         case EditRange:
01894         case SliderRange:
01895         case DialRange:
01896         {
01897           QVariant min = editTypeElement.attribute( "min" );
01898           QVariant max = editTypeElement.attribute( "max" );
01899           QVariant step = editTypeElement.attribute( "step" );
01900 
01901           mRanges[ name ] = RangeData( min, max, step );
01902         }
01903         break;
01904 
01905         case CheckBox:
01906           mCheckedStates[ name ] = QPair<QString, QString>( editTypeElement.attribute( "checked" ), editTypeElement.attribute( "unchecked" ) );
01907           break;
01908 
01909         case ValueRelation:
01910         {
01911           QString id = editTypeElement.attribute( "layer" );
01912           QString key = editTypeElement.attribute( "key" );
01913           QString value = editTypeElement.attribute( "value" );
01914           bool allowNull = editTypeElement.attribute( "allowNull" ) == "true";
01915           bool orderByValue = editTypeElement.attribute( "orderByValue" ) == "true";
01916           bool allowMulti = editTypeElement.attribute( "allowMulti", "false" ) == "true";
01917 
01918           QString filterExpression;
01919           if ( editTypeElement.hasAttribute( "filterAttributeColumn" ) &&
01920                editTypeElement.hasAttribute( "filterAttributeValue" ) )
01921           {
01922             filterExpression = QString( "\"%1\"='%2'" )
01923                                .arg( editTypeElement.attribute( "filterAttributeColumn" ) )
01924                                .arg( editTypeElement.attribute( "filterAttributeValue" ) );
01925           }
01926           else
01927           {
01928             filterExpression  = editTypeElement.attribute( "filterExpression", QString::null );
01929           }
01930 
01931           mValueRelations[ name ] = ValueRelationData( id, key, value, allowNull, orderByValue, allowMulti, filterExpression );
01932         }
01933         break;
01934 
01935         case Calendar:
01936           mDateFormats[ name ] = editTypeElement.attribute( "dateFormat" );
01937           break;
01938 
01939         case Photo:
01940           mWidgetSize[ name ] = QSize( editTypeElement.attribute( "widgetWidth" ).toInt(), editTypeElement.attribute( "widgetHeight" ).toInt() );
01941           break;
01942 
01943         case Classification:
01944         case FileName:
01945         case Immutable:
01946         case Hidden:
01947         case LineEdit:
01948         case TextEdit:
01949         case Enumeration:
01950         case UniqueValues:
01951         case UniqueValuesEditable:
01952         case UuidGenerator:
01953         case WebView:
01954         case Color:
01955           break;
01956       }
01957     }
01958   }
01959 
01960   QDomNode editFormNode = node.namedItem( "editform" );
01961   if ( !editFormNode.isNull() )
01962   {
01963     QDomElement e = editFormNode.toElement();
01964     mEditForm = QgsProject::instance()->readPath( e.text() );
01965   }
01966 
01967   QDomNode editFormInitNode = node.namedItem( "editforminit" );
01968   if ( !editFormInitNode.isNull() )
01969   {
01970     mEditFormInit = editFormInitNode.toElement().text();
01971   }
01972 
01973   QDomNode annotationFormNode = node.namedItem( "annotationform" );
01974   if ( !annotationFormNode.isNull() )
01975   {
01976     QDomElement e = annotationFormNode.toElement();
01977     mAnnotationForm = QgsProject::instance()->readPath( e.text() );
01978   }
01979 
01980   mAttributeAliasMap.clear();
01981   QDomNode aliasesNode = node.namedItem( "aliases" );
01982   if ( !aliasesNode.isNull() )
01983   {
01984     QDomElement aliasElem;
01985     QString name;
01986 
01987     QDomNodeList aliasNodeList = aliasesNode.toElement().elementsByTagName( "alias" );
01988     for ( int i = 0; i < aliasNodeList.size(); ++i )
01989     {
01990       aliasElem = aliasNodeList.at( i ).toElement();
01991 
01992       QString field;
01993       if ( aliasElem.hasAttribute( "field" ) )
01994       {
01995         field = aliasElem.attribute( "field" );
01996       }
01997       else
01998       {
01999         int index = aliasElem.attribute( "index" ).toInt();
02000 
02001         if ( index >= 0 && index < pendingFields().count() )
02002           field = pendingFields()[ index ].name();
02003       }
02004 
02005       mAttributeAliasMap.insert( field, aliasElem.attribute( "name" ) );
02006     }
02007   }
02008 
02009   // tab display
02010   QDomNode editorLayoutNode = node.namedItem( "editorlayout" );
02011   if ( editorLayoutNode.isNull() )
02012   {
02013     mEditorLayout = GeneratedLayout;
02014   }
02015   else
02016   {
02017     if ( editorLayoutNode.toElement().text() == "uifilelayout" )
02018     {
02019       mEditorLayout = UiFileLayout;
02020     }
02021     else if ( editorLayoutNode.toElement().text() == "tablayout" )
02022     {
02023       mEditorLayout = TabLayout;
02024     }
02025     else
02026     {
02027       mEditorLayout = GeneratedLayout;
02028     }
02029   }
02030 
02031   //Attributes excluded from WMS and WFS
02032   mExcludeAttributesWMS.clear();
02033   QDomNode excludeWMSNode = node.namedItem( "excludeAttributesWMS" );
02034   if ( !excludeWMSNode.isNull() )
02035   {
02036     QDomNodeList attributeNodeList = excludeWMSNode.toElement().elementsByTagName( "attribute" );
02037     for ( int i = 0; i < attributeNodeList.size(); ++i )
02038     {
02039       mExcludeAttributesWMS.insert( attributeNodeList.at( i ).toElement().text() );
02040     }
02041   }
02042 
02043   mExcludeAttributesWFS.clear();
02044   QDomNode excludeWFSNode = node.namedItem( "excludeAttributesWFS" );
02045   if ( !excludeWFSNode.isNull() )
02046   {
02047     QDomNodeList attributeNodeList = excludeWFSNode.toElement().elementsByTagName( "attribute" );
02048     for ( int i = 0; i < attributeNodeList.size(); ++i )
02049     {
02050       mExcludeAttributesWFS.insert( attributeNodeList.at( i ).toElement().text() );
02051     }
02052   }
02053 
02054   // tabs and groups display info
02055   mAttributeEditorElements.clear();
02056   QDomNode attributeEditorFormNode = node.namedItem( "attributeEditorForm" );
02057   QDomNodeList attributeEditorFormNodeList = attributeEditorFormNode.toElement().childNodes();
02058 
02059   for ( int i = 0; i < attributeEditorFormNodeList.size(); i++ )
02060   {
02061     QDomElement elem = attributeEditorFormNodeList.at( i ).toElement();
02062 
02063     QgsAttributeEditorElement *attributeEditorWidget = attributeEditorElementFromDomElement( elem, this );
02064     mAttributeEditorElements.append( attributeEditorWidget );
02065   }
02066   return true;
02067 }
02068 
02069 QgsAttributeEditorElement* QgsVectorLayer::attributeEditorElementFromDomElement( QDomElement &elem, QObject* parent )
02070 {
02071   QgsAttributeEditorElement* newElement = NULL;
02072 
02073   if ( elem.tagName() == "attributeEditorContainer" )
02074   {
02075     QgsAttributeEditorContainer* container = new QgsAttributeEditorContainer( elem.attribute( "name" ), parent );
02076 
02077     QDomNodeList childNodeList = elem.childNodes();
02078 
02079     for ( int i = 0; i < childNodeList.size(); i++ )
02080     {
02081       QDomElement childElem = childNodeList.at( i ).toElement();
02082       QgsAttributeEditorElement* myElem = attributeEditorElementFromDomElement( childElem, container );
02083       container->addChildElement( myElem );
02084     }
02085 
02086     newElement = container;
02087   }
02088   else if ( elem.tagName() == "attributeEditorField" )
02089   {
02090     QString name = elem.attribute( "name" );
02091     int idx = *( dataProvider()->fieldNameMap() ).find( name );
02092     newElement = new QgsAttributeEditorField( name, idx, parent );
02093   }
02094 
02095   return newElement;
02096 }
02097 
02098 bool QgsVectorLayer::writeSymbology( QDomNode& node, QDomDocument& doc, QString& errorMessage ) const
02099 {
02100   Q_UNUSED( errorMessage );
02101   QDomElement mapLayerNode = node.toElement();
02102 
02103   if ( hasGeometryType() )
02104   {
02105     QDomElement rendererElement = mRendererV2->save( doc );
02106     node.appendChild( rendererElement );
02107 
02108     // use scale dependent visibility flag
02109     mapLayerNode.setAttribute( "scaleBasedLabelVisibilityFlag", mLabel->scaleBasedVisibility() ? 1 : 0 );
02110     mapLayerNode.setAttribute( "minLabelScale", QString::number( mLabel->minScale() ) );
02111     mapLayerNode.setAttribute( "maxLabelScale", QString::number( mLabel->maxScale() ) );
02112 
02113     //save customproperties (for labeling ng)
02114     writeCustomProperties( node, doc );
02115 
02116     // add the blend mode field
02117     QDomElement blendModeElem  = doc.createElement( "blendMode" );
02118     QDomText blendModeText = doc.createTextNode( QString::number( QgsMapRenderer::getBlendModeEnum( blendMode() ) ) );
02119     blendModeElem.appendChild( blendModeText );
02120     node.appendChild( blendModeElem );
02121 
02122     // add the feature blend mode field
02123     QDomElement featureBlendModeElem  = doc.createElement( "featureBlendMode" );
02124     QDomText featureBlendModeText = doc.createTextNode( QString::number( QgsMapRenderer::getBlendModeEnum( featureBlendMode() ) ) );
02125     featureBlendModeElem.appendChild( featureBlendModeText );
02126     node.appendChild( featureBlendModeElem );
02127 
02128     // add the layer transparency
02129     QDomElement layerTransparencyElem  = doc.createElement( "layerTransparency" );
02130     QDomText layerTransparencyText = doc.createTextNode( QString::number( layerTransparency() ) );
02131     layerTransparencyElem.appendChild( layerTransparencyText );
02132     node.appendChild( layerTransparencyElem );
02133 
02134     // add the display field
02135     QDomElement dField  = doc.createElement( "displayfield" );
02136     QDomText dFieldText = doc.createTextNode( displayField() );
02137     dField.appendChild( dFieldText );
02138     node.appendChild( dField );
02139 
02140     // add label node
02141     QDomElement labelElem = doc.createElement( "label" );
02142     QDomText labelText = doc.createTextNode( "" );
02143 
02144     if ( hasLabelsEnabled() )
02145     {
02146       labelText.setData( "1" );
02147     }
02148     else
02149     {
02150       labelText.setData( "0" );
02151     }
02152     labelElem.appendChild( labelText );
02153 
02154     node.appendChild( labelElem );
02155 
02156     // Now we get to do all that all over again for QgsLabel
02157 
02158     QString fieldname = mLabel->labelField( QgsLabel::Text );
02159     if ( fieldname != "" )
02160     {
02161       dField  = doc.createElement( "labelfield" );
02162       dFieldText = doc.createTextNode( fieldname );
02163       dField.appendChild( dFieldText );
02164       node.appendChild( dField );
02165     }
02166 
02167     mLabel->writeXML( node, doc );
02168 
02169     if ( mDiagramRenderer )
02170     {
02171       mDiagramRenderer->writeXML( mapLayerNode, doc );
02172       if ( mDiagramLayerSettings )
02173         mDiagramLayerSettings->writeXML( mapLayerNode, doc );
02174     }
02175   }
02176 
02177   //edit types
02178   if ( mEditTypes.size() > 0 )
02179   {
02180     QDomElement editTypesElement = doc.createElement( "edittypes" );
02181 
02182     for ( QMap<QString, EditType>::const_iterator it = mEditTypes.begin(); it != mEditTypes.end(); ++it )
02183     {
02184       QDomElement editTypeElement = doc.createElement( "edittype" );
02185       editTypeElement.setAttribute( "name", it.key() );
02186       editTypeElement.setAttribute( "type", it.value() );
02187       editTypeElement.setAttribute( "editable", mFieldEditables[ it.key()] ? 1 : 0 );
02188 
02189       switch (( EditType ) it.value() )
02190       {
02191         case ValueMap:
02192           if ( mValueMaps.contains( it.key() ) )
02193           {
02194             const QMap<QString, QVariant> &map = mValueMaps[ it.key()];
02195 
02196             for ( QMap<QString, QVariant>::const_iterator vmit = map.begin(); vmit != map.end(); vmit++ )
02197             {
02198               QDomElement value = doc.createElement( "valuepair" );
02199               value.setAttribute( "key", vmit.key() );
02200               value.setAttribute( "value", vmit.value().toString() );
02201               editTypeElement.appendChild( value );
02202             }
02203           }
02204           break;
02205 
02206         case EditRange:
02207         case SliderRange:
02208         case DialRange:
02209           if ( mRanges.contains( it.key() ) )
02210           {
02211             editTypeElement.setAttribute( "min", mRanges[ it.key()].mMin.toString() );
02212             editTypeElement.setAttribute( "max", mRanges[ it.key()].mMax.toString() );
02213             editTypeElement.setAttribute( "step", mRanges[ it.key()].mStep.toString() );
02214           }
02215           break;
02216 
02217         case CheckBox:
02218           if ( mCheckedStates.contains( it.key() ) )
02219           {
02220             editTypeElement.setAttribute( "checked", mCheckedStates[ it.key()].first );
02221             editTypeElement.setAttribute( "unchecked", mCheckedStates[ it.key()].second );
02222           }
02223           break;
02224 
02225         case ValueRelation:
02226           if ( mValueRelations.contains( it.key() ) )
02227           {
02228             const ValueRelationData &data = mValueRelations[ it.key()];
02229             editTypeElement.setAttribute( "layer", data.mLayer );
02230             editTypeElement.setAttribute( "key", data.mKey );
02231             editTypeElement.setAttribute( "value", data.mValue );
02232             editTypeElement.setAttribute( "allowNull", data.mAllowNull ? "true" : "false" );
02233             editTypeElement.setAttribute( "orderByValue", data.mOrderByValue ? "true" : "false" );
02234             editTypeElement.setAttribute( "allowMulti", data.mAllowMulti ? "true" : "false" );
02235             if ( !data.mFilterExpression.isNull() )
02236               editTypeElement.setAttribute( "filterExpression", data.mFilterExpression );
02237           }
02238           break;
02239 
02240         case Calendar:
02241           editTypeElement.setAttribute( "dateFormat", mDateFormats[ it.key()] );
02242           break;
02243 
02244         case Photo:
02245           editTypeElement.setAttribute( "widgetWidth", mWidgetSize[ it.key()].width() );
02246           editTypeElement.setAttribute( "widgetHeight", mWidgetSize[ it.key()].height() );
02247           break;
02248 
02249         case LineEdit:
02250         case UniqueValues:
02251         case UniqueValuesEditable:
02252         case Classification:
02253         case FileName:
02254         case Hidden:
02255         case TextEdit:
02256         case Enumeration:
02257         case Immutable:
02258         case UuidGenerator:
02259         case WebView:
02260         case Color:
02261           break;
02262       }
02263 
02264       editTypesElement.appendChild( editTypeElement );
02265     }
02266 
02267     node.appendChild( editTypesElement );
02268   }
02269 
02270   QDomElement efField  = doc.createElement( "editform" );
02271   QDomText efText = doc.createTextNode( QgsProject::instance()->writePath( mEditForm ) );
02272   efField.appendChild( efText );
02273   node.appendChild( efField );
02274 
02275   QDomElement efiField  = doc.createElement( "editforminit" );
02276   QDomText efiText = doc.createTextNode( mEditFormInit );
02277   efiField.appendChild( efiText );
02278   node.appendChild( efiField );
02279 
02280   QDomElement afField = doc.createElement( "annotationform" );
02281   QDomText afText = doc.createTextNode( QgsProject::instance()->writePath( mAnnotationForm ) );
02282   afField.appendChild( afText );
02283   node.appendChild( afField );
02284 
02285   // tab display
02286   QDomElement editorLayoutElem  = doc.createElement( "editorlayout" );
02287   switch ( mEditorLayout )
02288   {
02289     case UiFileLayout:
02290       editorLayoutElem.appendChild( doc.createTextNode( "uifilelayout" ) );
02291       break;
02292 
02293     case TabLayout:
02294       editorLayoutElem.appendChild( doc.createTextNode( "tablayout" ) );
02295       break;
02296 
02297     case GeneratedLayout:
02298     default:
02299       editorLayoutElem.appendChild( doc.createTextNode( "generatedlayout" ) );
02300       break;
02301   }
02302 
02303   node.appendChild( editorLayoutElem );
02304 
02305   //attribute aliases
02306   if ( mAttributeAliasMap.size() > 0 )
02307   {
02308     QDomElement aliasElem = doc.createElement( "aliases" );
02309     QMap<QString, QString>::const_iterator a_it = mAttributeAliasMap.constBegin();
02310     for ( ; a_it != mAttributeAliasMap.constEnd(); ++a_it )
02311     {
02312       int idx = fieldNameIndex( a_it.key() );
02313       if ( idx < 0 )
02314         continue;
02315 
02316       QDomElement aliasEntryElem = doc.createElement( "alias" );
02317       aliasEntryElem.setAttribute( "field", a_it.key() );
02318       aliasEntryElem.setAttribute( "index", idx );
02319       aliasEntryElem.setAttribute( "name", a_it.value() );
02320       aliasElem.appendChild( aliasEntryElem );
02321     }
02322     node.appendChild( aliasElem );
02323   }
02324 
02325   //exclude attributes WMS
02326   QDomElement excludeWMSElem = doc.createElement( "excludeAttributesWMS" );
02327   QSet<QString>::const_iterator attWMSIt = mExcludeAttributesWMS.constBegin();
02328   for ( ; attWMSIt != mExcludeAttributesWMS.constEnd(); ++attWMSIt )
02329   {
02330     QDomElement attrElem = doc.createElement( "attribute" );
02331     QDomText attrText = doc.createTextNode( *attWMSIt );
02332     attrElem.appendChild( attrText );
02333     excludeWMSElem.appendChild( attrElem );
02334   }
02335   node.appendChild( excludeWMSElem );
02336 
02337   //exclude attributes WFS
02338   QDomElement excludeWFSElem = doc.createElement( "excludeAttributesWFS" );
02339   QSet<QString>::const_iterator attWFSIt = mExcludeAttributesWFS.constBegin();
02340   for ( ; attWFSIt != mExcludeAttributesWFS.constEnd(); ++attWFSIt )
02341   {
02342     QDomElement attrElem = doc.createElement( "attribute" );
02343     QDomText attrText = doc.createTextNode( *attWFSIt );
02344     attrElem.appendChild( attrText );
02345     excludeWFSElem.appendChild( attrElem );
02346   }
02347   node.appendChild( excludeWFSElem );
02348 
02349   // tabs and groups of edit form
02350   if ( mAttributeEditorElements.size() > 0 )
02351   {
02352     QDomElement tabsElem = doc.createElement( "attributeEditorForm" );
02353 
02354     for ( QList< QgsAttributeEditorElement* >::const_iterator it = mAttributeEditorElements.begin(); it != mAttributeEditorElements.end(); it++ )
02355     {
02356       QDomElement attributeEditorWidgetElem = ( *it )->toDomElement( doc );
02357       tabsElem.appendChild( attributeEditorWidgetElem );
02358     }
02359 
02360     node.appendChild( tabsElem );
02361   }
02362 
02363   // add attribute actions
02364   mActions->writeXML( node, doc );
02365 
02366   //save vector overlays (e.g. diagrams)
02367   QList<QgsVectorOverlay*>::const_iterator overlay_it = mOverlays.constBegin();
02368   for ( ; overlay_it != mOverlays.constEnd(); ++overlay_it )
02369   {
02370     if ( *overlay_it )
02371     {
02372       ( *overlay_it )->writeXML( mapLayerNode, doc );
02373     }
02374   }
02375 
02376   return true;
02377 }
02378 
02379 bool QgsVectorLayer::readSld( const QDomNode& node, QString& errorMessage )
02380 {
02381   // get the Name element
02382   QDomElement nameElem = node.firstChildElement( "Name" );
02383   if ( nameElem.isNull() )
02384   {
02385     errorMessage = "Warning: Name element not found within NamedLayer while it's required.";
02386   }
02387 
02388   if ( hasGeometryType() )
02389   {
02390     QgsFeatureRendererV2* r = QgsFeatureRendererV2::loadSld( node, geometryType(), errorMessage );
02391     if ( !r )
02392       return false;
02393 
02394     setRendererV2( r );
02395   }
02396   return true;
02397 }
02398 
02399 
02400 bool QgsVectorLayer::writeSld( QDomNode& node, QDomDocument& doc, QString& errorMessage ) const
02401 {
02402   Q_UNUSED( errorMessage );
02403 
02404   // store the Name element
02405   QDomElement nameNode = doc.createElement( "se:Name" );
02406   nameNode.appendChild( doc.createTextNode( name() ) );
02407   node.appendChild( nameNode );
02408 
02409   if ( hasGeometryType() )
02410   {
02411     node.appendChild( mRendererV2->writeSld( doc, *this ) );
02412   }
02413   return true;
02414 }
02415 
02416 
02417 bool QgsVectorLayer::changeGeometry( QgsFeatureId fid, QgsGeometry* geom )
02418 {
02419   if ( !mEditBuffer || !mDataProvider )
02420   {
02421     return false;
02422   }
02423 
02424   return mEditBuffer->changeGeometry( fid, geom );
02425 }
02426 
02427 
02428 bool QgsVectorLayer::changeAttributeValue( QgsFeatureId fid, int field, QVariant value, bool emitSignal )
02429 {
02430   Q_UNUSED( emitSignal ); // TODO[MD] - see also QgsFieldCalculator and #7071
02431   if ( !mEditBuffer || !mDataProvider )
02432     return false;
02433 
02434   return mEditBuffer->changeAttributeValue( fid, field, value );
02435 }
02436 
02437 bool QgsVectorLayer::addAttribute( const QgsField &field )
02438 {
02439   if ( !mEditBuffer || !mDataProvider )
02440     return false;
02441 
02442   return mEditBuffer->addAttribute( field );
02443 }
02444 
02445 void QgsVectorLayer::addAttributeAlias( int attIndex, QString aliasString )
02446 {
02447   if ( attIndex < 0 || attIndex >= pendingFields().count() )
02448     return;
02449 
02450   QString name = pendingFields()[ attIndex ].name();
02451 
02452   mAttributeAliasMap.insert( name, aliasString );
02453   emit layerModified(); // TODO[MD]: should have a different signal?
02454 }
02455 
02456 void QgsVectorLayer::addAttributeEditorWidget( QgsAttributeEditorElement* data )
02457 {
02458   mAttributeEditorElements.append( data );
02459 }
02460 
02461 QString QgsVectorLayer::attributeAlias( int attributeIndex ) const
02462 {
02463   if ( attributeIndex < 0 || attributeIndex >= pendingFields().count() )
02464     return "";
02465 
02466   QString name = pendingFields()[ attributeIndex ].name();
02467 
02468   return mAttributeAliasMap.value( name, "" );
02469 }
02470 
02471 QString QgsVectorLayer::attributeDisplayName( int attributeIndex ) const
02472 {
02473   QString displayName = attributeAlias( attributeIndex );
02474   if ( displayName.isEmpty() )
02475   {
02476     const QgsFields& fields = pendingFields();
02477     if ( attributeIndex >= 0 && attributeIndex < fields.count() )
02478     {
02479       displayName = fields[attributeIndex].name();
02480     }
02481   }
02482   return displayName;
02483 }
02484 
02485 bool QgsVectorLayer::deleteAttribute( int index )
02486 {
02487   if ( !mEditBuffer || !mDataProvider )
02488     return false;
02489 
02490   return mEditBuffer->deleteAttribute( index );
02491 }
02492 
02493 bool QgsVectorLayer::deleteAttributes( QList<int> attrs )
02494 {
02495   bool deleted = false;
02496 
02497   // Remove multiple occurences of same attribute
02498   attrs = attrs.toSet().toList();
02499 
02500   qSort( attrs.begin(), attrs.end(), qGreater<int>() );
02501 
02502   foreach ( int attr, attrs )
02503   {
02504     if ( deleteAttribute( attr ) )
02505     {
02506       deleted = true;
02507     }
02508   }
02509 
02510   return deleted;
02511 }
02512 
02513 bool QgsVectorLayer::deleteFeature( QgsFeatureId fid )
02514 {
02515   if ( !mEditBuffer )
02516     return false;
02517 
02518   bool res = mEditBuffer->deleteFeature( fid );
02519   if ( res )
02520     mSelectedFeatureIds.remove( fid ); // remove it from selection
02521 
02522   return res;
02523 }
02524 
02525 const QgsFields &QgsVectorLayer::pendingFields() const
02526 {
02527   return mUpdatedFields;
02528 }
02529 
02530 QgsAttributeList QgsVectorLayer::pendingAllAttributesList()
02531 {
02532   QgsAttributeList lst;
02533   for ( int i = 0; i < mUpdatedFields.count(); ++i )
02534     lst.append( i );
02535   return lst;
02536 }
02537 
02538 QgsAttributeList QgsVectorLayer::pendingPkAttributesList()
02539 {
02540   QgsAttributeList pkAttributesList;
02541 
02542   QgsAttributeList providerIndexes = mDataProvider->pkAttributeIndexes();
02543   for ( int i = 0; i < mUpdatedFields.count(); ++i )
02544   {
02545     if ( mUpdatedFields.fieldOrigin( i ) == QgsFields::OriginProvider &&
02546          providerIndexes.contains( mUpdatedFields.fieldOriginIndex( i ) ) )
02547       pkAttributesList << i;
02548   }
02549 
02550   return pkAttributesList;
02551 }
02552 
02553 int QgsVectorLayer::pendingFeatureCount()
02554 {
02555   return mDataProvider->featureCount() +
02556          ( mEditBuffer ? mEditBuffer->mAddedFeatures.size() - mEditBuffer->mDeletedFeatureIds.size() : 0 );
02557 }
02558 
02559 bool QgsVectorLayer::commitChanges()
02560 {
02561   mCommitErrors.clear();
02562 
02563   if ( !mDataProvider )
02564   {
02565     mCommitErrors << tr( "ERROR: no provider" );
02566     return false;
02567   }
02568 
02569   if ( !mEditBuffer )
02570   {
02571     mCommitErrors << tr( "ERROR: layer not editable" );
02572     return false;
02573   }
02574 
02575   emit beforeCommitChanges();
02576 
02577   bool success = mEditBuffer->commitChanges( mCommitErrors );
02578 
02579   if ( success )
02580   {
02581     delete mEditBuffer;
02582     mEditBuffer = 0;
02583     undoStack()->clear();
02584     emit editingStopped();
02585   }
02586   else
02587   {
02588     QgsMessageLog::logMessage( tr( "Commit errors:\n  %1" ).arg( mCommitErrors.join( "\n  " ) ) );
02589   }
02590 
02591   updateFields();
02592   mDataProvider->updateExtents();
02593 
02594   //clear the cache image so markers don't appear anymore on next draw
02595   setCacheImage( 0 );
02596 
02597   return success;
02598 }
02599 
02600 const QStringList &QgsVectorLayer::commitErrors()
02601 {
02602   return mCommitErrors;
02603 }
02604 
02605 bool QgsVectorLayer::rollBack( bool deleteBuffer )
02606 {
02607   if ( !mEditBuffer )
02608   {
02609     return false;
02610   }
02611 
02612   mEditBuffer->rollBack();
02613 
02614   if ( isModified() )
02615   {
02616     // new undo stack roll back method
02617     // old method of calling every undo could cause many canvas refreshes
02618     undoStack()->setIndex( 0 );
02619   }
02620 
02621   updateFields();
02622 
02623   if ( deleteBuffer )
02624   {
02625     delete mEditBuffer;
02626     mEditBuffer = 0;
02627     undoStack()->clear();
02628   }
02629   emit editingStopped();
02630 
02631   // invalidate the cache so the layer updates properly to show its original
02632   // after the rollback
02633   setCacheImage( 0 );
02634   return true;
02635 }
02636 
02637 void QgsVectorLayer::setSelectedFeatures( const QgsFeatureIds& ids )
02638 {
02639   QgsFeatureIds deselectedFeatures = mSelectedFeatureIds - ids;
02640   // TODO: check whether features with these ID exist
02641   mSelectedFeatureIds = ids;
02642 
02643   // invalidate cache
02644   setCacheImage( 0 );
02645 
02646   emit selectionChanged( ids, deselectedFeatures, true );
02647 }
02648 
02649 int QgsVectorLayer::selectedFeatureCount()
02650 {
02651   return mSelectedFeatureIds.size();
02652 }
02653 
02654 const QgsFeatureIds& QgsVectorLayer::selectedFeaturesIds() const
02655 {
02656   return mSelectedFeatureIds;
02657 }
02658 
02659 
02660 QgsFeatureList QgsVectorLayer::selectedFeatures()
02661 {
02662   QgsFeatureList features;
02663 
02664   QgsFeatureRequest req;
02665   if ( geometryType() == QGis::NoGeometry )
02666     req.setFlags( QgsFeatureRequest::NoGeometry );
02667 
02668   foreach ( QgsFeatureId fid, mSelectedFeatureIds )
02669   {
02670     features.push_back( QgsFeature() );
02671     getFeatures( req.setFilterFid( fid ) ).nextFeature( features.back() );
02672   }
02673 
02674   return features;
02675 }
02676 
02677 bool QgsVectorLayer::addFeatures( QgsFeatureList features, bool makeSelected )
02678 {
02679   if ( !mEditBuffer || !mDataProvider )
02680     return false;
02681 
02682   bool res = mEditBuffer->addFeatures( features );
02683 
02684   if ( makeSelected )
02685   {
02686     QgsFeatureIds ids;
02687 
02688     for ( QgsFeatureList::iterator iter = features.begin(); iter != features.end(); ++iter )
02689       ids << iter->id();
02690 
02691     setSelectedFeatures( ids );
02692   }
02693 
02694   return res;
02695 }
02696 
02697 
02698 bool QgsVectorLayer::snapPoint( QgsPoint& point, double tolerance )
02699 {
02700   if ( !hasGeometryType() )
02701     return false;
02702 
02703   QMultiMap<double, QgsSnappingResult> snapResults;
02704   int result = snapWithContext( point, tolerance, snapResults, QgsSnapper::SnapToVertex );
02705 
02706   if ( result != 0 )
02707   {
02708     return false;
02709   }
02710 
02711   if ( snapResults.size() < 1 )
02712   {
02713     return false;
02714   }
02715 
02716   QMultiMap<double, QgsSnappingResult>::const_iterator snap_it = snapResults.constBegin();
02717   point.setX( snap_it.value().snappedVertex.x() );
02718   point.setY( snap_it.value().snappedVertex.y() );
02719   return true;
02720 }
02721 
02722 
02723 int QgsVectorLayer::snapWithContext( const QgsPoint& startPoint, double snappingTolerance,
02724                                      QMultiMap<double, QgsSnappingResult>& snappingResults,
02725                                      QgsSnapper::SnappingType snap_to )
02726 {
02727   if ( !hasGeometryType() )
02728     return 1;
02729 
02730   if ( snappingTolerance <= 0 || !mDataProvider )
02731   {
02732     return 1;
02733   }
02734 
02735   QList<QgsFeature> featureList;
02736   QgsRectangle searchRect( startPoint.x() - snappingTolerance, startPoint.y() - snappingTolerance,
02737                            startPoint.x() + snappingTolerance, startPoint.y() + snappingTolerance );
02738   double sqrSnappingTolerance = snappingTolerance * snappingTolerance;
02739 
02740   int n = 0;
02741   QgsFeature f;
02742 
02743   if ( mCache->cachedGeometriesRect().contains( searchRect ) )
02744   {
02745     QgsGeometryMap& cachedGeometries = mCache->cachedGeometries();
02746     for ( QgsGeometryMap::iterator it = cachedGeometries.begin(); it != cachedGeometries.end() ; ++it )
02747     {
02748       QgsGeometry* g = &( it.value() );
02749       if ( g->boundingBox().intersects( searchRect ) )
02750       {
02751         snapToGeometry( startPoint, it.key(), g, sqrSnappingTolerance, snappingResults, snap_to );
02752         ++n;
02753       }
02754     }
02755   }
02756   else
02757   {
02758     // snapping outside cached area
02759 
02760     QgsFeatureIterator fit = getFeatures( QgsFeatureRequest()
02761                                           .setFilterRect( searchRect )
02762                                           .setFlags( QgsFeatureRequest::ExactIntersect )
02763                                           .setSubsetOfAttributes( QgsAttributeList() ) );
02764 
02765     while ( fit.nextFeature( f ) )
02766     {
02767       snapToGeometry( startPoint, f.id(), f.geometry(), sqrSnappingTolerance, snappingResults, snap_to );
02768       ++n;
02769     }
02770   }
02771 
02772   return n == 0 ? 2 : 0;
02773 }
02774 
02775 void QgsVectorLayer::snapToGeometry( const QgsPoint& startPoint,
02776                                      QgsFeatureId featureId,
02777                                      QgsGeometry* geom,
02778                                      double sqrSnappingTolerance,
02779                                      QMultiMap<double, QgsSnappingResult>& snappingResults,
02780                                      QgsSnapper::SnappingType snap_to ) const
02781 {
02782   if ( !geom )
02783   {
02784     return;
02785   }
02786 
02787   int atVertex, beforeVertex, afterVertex;
02788   double sqrDistVertexSnap, sqrDistSegmentSnap;
02789   QgsPoint snappedPoint;
02790   QgsSnappingResult snappingResultVertex;
02791   QgsSnappingResult snappingResultSegment;
02792 
02793   if ( snap_to == QgsSnapper::SnapToVertex || snap_to == QgsSnapper::SnapToVertexAndSegment )
02794   {
02795     snappedPoint = geom->closestVertex( startPoint, atVertex, beforeVertex, afterVertex, sqrDistVertexSnap );
02796     if ( sqrDistVertexSnap < sqrSnappingTolerance )
02797     {
02798       snappingResultVertex.snappedVertex = snappedPoint;
02799       snappingResultVertex.snappedVertexNr = atVertex;
02800       snappingResultVertex.beforeVertexNr = beforeVertex;
02801       if ( beforeVertex != -1 ) // make sure the vertex is valid
02802       {
02803         snappingResultVertex.beforeVertex = geom->vertexAt( beforeVertex );
02804       }
02805       snappingResultVertex.afterVertexNr = afterVertex;
02806       if ( afterVertex != -1 ) // make sure the vertex is valid
02807       {
02808         snappingResultVertex.afterVertex = geom->vertexAt( afterVertex );
02809       }
02810       snappingResultVertex.snappedAtGeometry = featureId;
02811       snappingResultVertex.layer = this;
02812       snappingResults.insert( sqrt( sqrDistVertexSnap ), snappingResultVertex );
02813       return;
02814     }
02815   }
02816   if ( snap_to == QgsSnapper::SnapToSegment || snap_to == QgsSnapper::SnapToVertexAndSegment ) // snap to segment
02817   {
02818     if ( geometryType() != QGis::Point ) // cannot snap to segment for points/multipoints
02819     {
02820       sqrDistSegmentSnap = geom->closestSegmentWithContext( startPoint, snappedPoint, afterVertex, NULL, crs().geographicFlag() ? 1e-12 : 1e-8 );
02821 
02822       if ( sqrDistSegmentSnap < sqrSnappingTolerance )
02823       {
02824         snappingResultSegment.snappedVertex = snappedPoint;
02825         snappingResultSegment.snappedVertexNr = -1;
02826         snappingResultSegment.beforeVertexNr = afterVertex - 1;
02827         snappingResultSegment.afterVertexNr = afterVertex;
02828         snappingResultSegment.snappedAtGeometry = featureId;
02829         snappingResultSegment.beforeVertex = geom->vertexAt( afterVertex - 1 );
02830         snappingResultSegment.afterVertex = geom->vertexAt( afterVertex );
02831         snappingResultSegment.layer = this;
02832         snappingResults.insert( sqrt( sqrDistSegmentSnap ), snappingResultSegment );
02833       }
02834     }
02835   }
02836 }
02837 
02838 int QgsVectorLayer::insertSegmentVerticesForSnap( const QList<QgsSnappingResult>& snapResults )
02839 {
02840   QgsVectorLayerEditUtils utils( this );
02841   return utils.insertSegmentVerticesForSnap( snapResults );
02842 }
02843 
02844 
02845 QgsVectorLayer::VertexMarkerType QgsVectorLayer::currentVertexMarkerType()
02846 {
02847   QSettings settings;
02848   QString markerTypeString = settings.value( "/qgis/digitizing/marker_style", "Cross" ).toString();
02849   if ( markerTypeString == "Cross" )
02850   {
02851     return QgsVectorLayer::Cross;
02852   }
02853   else if ( markerTypeString == "SemiTransparentCircle" )
02854   {
02855     return QgsVectorLayer::SemiTransparentCircle;
02856   }
02857   else
02858   {
02859     return QgsVectorLayer::NoMarker;
02860   }
02861 }
02862 
02863 int QgsVectorLayer::currentVertexMarkerSize()
02864 {
02865   QSettings settings;
02866   return settings.value( "/qgis/digitizing/marker_size", 3 ).toInt();
02867 }
02868 
02869 
02870 
02871 void QgsVectorLayer::setCoordinateSystem()
02872 {
02873   QgsDebugMsg( "----- Computing Coordinate System" );
02874 
02875   //
02876   // Get the layers project info and set up the QgsCoordinateTransform
02877   // for this layer
02878   //
02879 
02880   if ( hasGeometryType() )
02881   {
02882     // get CRS directly from provider
02883     setCrs( mDataProvider->crs() );
02884   }
02885   else
02886   {
02887     setCrs( QgsCoordinateReferenceSystem( GEO_EPSG_CRS_AUTHID ) );
02888   }
02889 }
02890 
02891 
02892 const QString QgsVectorLayer::displayField() const
02893 {
02894   return mDisplayField;
02895 }
02896 
02897 void QgsVectorLayer::setDisplayExpression( const QString displayExpression )
02898 {
02899   mDisplayExpression = displayExpression;
02900 }
02901 
02902 const QString QgsVectorLayer::displayExpression()
02903 {
02904   return mDisplayExpression;
02905 }
02906 
02907 bool QgsVectorLayer::isEditable() const
02908 {
02909   return ( mEditBuffer && mDataProvider );
02910 }
02911 
02912 bool QgsVectorLayer::isReadOnly() const
02913 {
02914   return mReadOnly;
02915 }
02916 
02917 bool QgsVectorLayer::setReadOnly( bool readonly )
02918 {
02919   // exit if the layer is in editing mode
02920   if ( readonly && mEditBuffer )
02921     return false;
02922 
02923   mReadOnly = readonly;
02924   return true;
02925 }
02926 
02927 bool QgsVectorLayer::isModified() const
02928 {
02929   return mEditBuffer && mEditBuffer->isModified();
02930 }
02931 
02932 QgsVectorLayer::EditType QgsVectorLayer::editType( int idx )
02933 {
02934   const QgsFields &fields = pendingFields();
02935   if ( idx >= 0 && idx < fields.count() && mEditTypes.contains( fields[idx].name() ) )
02936     return mEditTypes[ fields[idx].name()];
02937   else
02938     return LineEdit;
02939 }
02940 
02941 void QgsVectorLayer::setEditType( int idx, EditType type )
02942 {
02943   const QgsFields &fields = pendingFields();
02944   if ( idx >= 0 && idx < fields.count() )
02945     mEditTypes[ fields[idx].name()] = type;
02946 }
02947 
02948 QgsVectorLayer::EditorLayout QgsVectorLayer::editorLayout()
02949 {
02950   return mEditorLayout;
02951 }
02952 
02953 void QgsVectorLayer::setEditorLayout( EditorLayout editorLayout )
02954 {
02955   mEditorLayout = editorLayout;
02956 }
02957 
02958 QString QgsVectorLayer::editForm()
02959 {
02960   return mEditForm;
02961 }
02962 
02963 void QgsVectorLayer::setEditForm( QString ui )
02964 {
02965   mEditForm = ui;
02966 }
02967 
02968 void QgsVectorLayer::setAnnotationForm( const QString& ui )
02969 {
02970   mAnnotationForm = ui;
02971 }
02972 
02973 QString QgsVectorLayer::editFormInit()
02974 {
02975   return mEditFormInit;
02976 }
02977 
02978 void QgsVectorLayer::setEditFormInit( QString function )
02979 {
02980   mEditFormInit = function;
02981 }
02982 
02983 QMap< QString, QVariant > &QgsVectorLayer::valueMap( int idx )
02984 {
02985   const QgsFields &fields = pendingFields();
02986 
02987   // FIXME: throw an exception!?
02988   static QMap< QString, QVariant > invalidMap;
02989   if ( idx < 0 || idx >= fields.count() )
02990   {
02991     QgsDebugMsg( QString( "field %1 not found" ).arg( idx ) );
02992     return invalidMap;
02993   }
02994   QString fieldName = fields[idx].name();
02995 
02996   if ( !mValueMaps.contains( fieldName ) )
02997     mValueMaps[fieldName] = QMap<QString, QVariant>();
02998 
02999   return mValueMaps[fieldName];
03000 }
03001 
03002 QgsVectorLayer::RangeData &QgsVectorLayer::range( int idx )
03003 {
03004   const QgsFields &fields = pendingFields();
03005 
03006   // FIXME: throw an exception!?
03007   static QgsVectorLayer::RangeData invalidRange;
03008   if ( idx < 0 || idx >= fields.count() )
03009   {
03010     QgsDebugMsg( QString( "field %1 not found" ).arg( idx ) );
03011     return invalidRange;
03012   }
03013   QString fieldName = fields[idx].name();
03014 
03015   if ( !mRanges.contains( fieldName ) )
03016     mRanges[fieldName] = RangeData();
03017 
03018   return mRanges[fieldName];
03019 }
03020 
03021 QString &QgsVectorLayer::dateFormat( int idx )
03022 {
03023   const QgsFields &fields = pendingFields();
03024 
03025   QString fieldName = fields[idx].name();
03026 
03027   if ( !mDateFormats.contains( fieldName ) )
03028     mDateFormats[fieldName] = "yyyy-MM-dd";
03029 
03030   return mDateFormats[fieldName];
03031 }
03032 
03033 QSize &QgsVectorLayer::widgetSize( int idx )
03034 {
03035   const QgsFields &fields = pendingFields();
03036 
03037   QString fieldName = fields[idx].name();
03038 
03039   if ( !mWidgetSize.contains( fieldName ) )
03040     mWidgetSize[fieldName] = QSize( 0, 0 );
03041 
03042   return mWidgetSize[fieldName];
03043 }
03044 
03045 bool QgsVectorLayer::fieldEditable( int idx )
03046 {
03047   const QgsFields &fields = pendingFields();
03048   if ( idx >= 0 && idx < fields.count() )
03049     return mFieldEditables.value( fields[idx].name(), true );
03050   else
03051     return true;
03052 }
03053 
03054 void QgsVectorLayer::setFieldEditable( int idx, bool editable )
03055 {
03056   const QgsFields &fields = pendingFields();
03057   if ( idx >= 0 && idx < fields.count() )
03058     mFieldEditables[ fields[idx].name()] = editable;
03059 }
03060 
03061 void QgsVectorLayer::addOverlay( QgsVectorOverlay* overlay )
03062 {
03063   mOverlays.push_back( overlay );
03064 }
03065 
03066 void QgsVectorLayer::removeOverlay( const QString& typeName )
03067 {
03068   for ( int i = mOverlays.size() - 1; i >= 0; --i )
03069   {
03070     if ( mOverlays.at( i )->typeName() == typeName )
03071     {
03072       mOverlays.removeAt( i );
03073     }
03074   }
03075 }
03076 
03077 void QgsVectorLayer::vectorOverlays( QList<QgsVectorOverlay*>& overlayList )
03078 {
03079   overlayList = mOverlays;
03080 }
03081 
03082 QgsVectorOverlay* QgsVectorLayer::findOverlayByType( const QString& typeName )
03083 {
03084   QList<QgsVectorOverlay*>::iterator it = mOverlays.begin();
03085   for ( ; it != mOverlays.end(); ++it )
03086   {
03087     if (( *it )->typeName() == typeName )
03088     {
03089       return *it;
03090     }
03091   }
03092   return 0; //not found
03093 }
03094 
03095 
03096 QgsFeatureRendererV2* QgsVectorLayer::rendererV2()
03097 {
03098   return mRendererV2;
03099 }
03100 
03101 void QgsVectorLayer::setRendererV2( QgsFeatureRendererV2 *r )
03102 {
03103   if ( !hasGeometryType() )
03104     return;
03105 
03106   if ( r != mRendererV2 )
03107   {
03108     delete mRendererV2;
03109     mRendererV2 = r;
03110     mSymbolFeatureCounted = false;
03111     mSymbolFeatureCountMap.clear();
03112   }
03113 }
03114 
03115 
03116 
03117 void QgsVectorLayer::beginEditCommand( QString text )
03118 {
03119   undoStack()->beginMacro( text );
03120 }
03121 
03122 void QgsVectorLayer::endEditCommand()
03123 {
03124   undoStack()->endMacro();
03125 }
03126 
03127 void QgsVectorLayer::destroyEditCommand()
03128 {
03129   undoStack()->endMacro();
03130   undoStack()->undo();
03131 }
03132 
03133 
03134 void QgsVectorLayer::setCheckedState( int idx, QString checked, QString unchecked )
03135 {
03136   const QgsFields &fields = pendingFields();
03137   if ( idx >= 0 && idx < fields.count() )
03138     mCheckedStates[ fields[idx].name()] = QPair<QString, QString>( checked, unchecked );
03139 }
03140 
03141 QPair<QString, QString> QgsVectorLayer::checkedState( int idx )
03142 {
03143   const QgsFields &fields = pendingFields();
03144   if ( idx >= 0 && idx < fields.count() && mCheckedStates.contains( fields[idx].name() ) )
03145     return mCheckedStates[ fields[idx].name()];
03146   else
03147     return QPair<QString, QString>( "1", "0" );
03148 }
03149 
03150 int QgsVectorLayer::fieldNameIndex( const QString& fieldName ) const
03151 {
03152   const QgsFields &theFields = pendingFields();
03153 
03154   for ( int idx = 0; idx < theFields.count(); ++idx )
03155   {
03156     if ( QString::compare( theFields[idx].name(), fieldName, Qt::CaseInsensitive ) == 0 )
03157     {
03158       return idx;
03159     }
03160   }
03161   return -1;
03162 }
03163 
03164 void QgsVectorLayer::addJoin( const QgsVectorJoinInfo& joinInfo )
03165 {
03166   mJoinBuffer->addJoin( joinInfo );
03167   updateFields();
03168 }
03169 
03170 void QgsVectorLayer::checkJoinLayerRemove( QString theLayerId )
03171 {
03172   removeJoin( theLayerId );
03173 }
03174 
03175 void QgsVectorLayer::removeJoin( const QString& joinLayerId )
03176 {
03177   mJoinBuffer->removeJoin( joinLayerId );
03178   updateFields();
03179 }
03180 
03181 const QList< QgsVectorJoinInfo >& QgsVectorLayer::vectorJoins() const
03182 {
03183   return mJoinBuffer->vectorJoins();
03184 }
03185 
03186 void QgsVectorLayer::updateFields()
03187 {
03188   if ( !mDataProvider )
03189     return;
03190 
03191   mUpdatedFields = mDataProvider->fields();
03192 
03193   // added / removed fields
03194   if ( mEditBuffer )
03195     mEditBuffer->updateFields( mUpdatedFields );
03196 
03197   // joined fields
03198   if ( mJoinBuffer && mJoinBuffer->containsJoins() )
03199     mJoinBuffer->updateFields( mUpdatedFields );
03200 
03201   emit updatedFields();
03202 }
03203 
03204 
03205 void QgsVectorLayer::createJoinCaches()
03206 {
03207   if ( mJoinBuffer->containsJoins() )
03208   {
03209     mJoinBuffer->createJoinCaches();
03210   }
03211 }
03212 
03213 void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int limit )
03214 {
03215   uniqueValues.clear();
03216   if ( !mDataProvider )
03217   {
03218     return;
03219   }
03220 
03221   QgsFields::FieldOrigin origin = mUpdatedFields.fieldOrigin( index );
03222 
03223   if ( origin == QgsFields::OriginProvider ) //a provider field
03224   {
03225     return mDataProvider->uniqueValues( index, uniqueValues, limit );
03226   }
03227   else if ( origin == QgsFields::OriginJoin )
03228   {
03229     int sourceLayerIndex;
03230     const QgsVectorJoinInfo* join = mJoinBuffer->joinForFieldIndex( index, mUpdatedFields, sourceLayerIndex );
03231     Q_ASSERT( join );
03232 
03233     QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( join->joinLayerId ) );
03234     Q_ASSERT( vl );
03235 
03236     return vl->dataProvider()->uniqueValues( sourceLayerIndex, uniqueValues, limit );
03237   }
03238   else if ( origin == QgsFields::OriginEdit )
03239   {
03240     // the layer is editable, but in certain cases it can still be avoided going through all features
03241     if ( mEditBuffer->mDeletedFeatureIds.isEmpty() && mEditBuffer->mAddedFeatures.isEmpty() && !mEditBuffer->mDeletedAttributeIds.contains( index ) && mEditBuffer->mChangedAttributeValues.isEmpty() )
03242     {
03243       return mDataProvider->uniqueValues( index, uniqueValues, limit );
03244     }
03245 
03246     // we need to go through each feature
03247     QgsAttributeList attList;
03248     attList << index;
03249 
03250     QgsFeatureIterator fit = getFeatures( QgsFeatureRequest()
03251                                           .setFlags( QgsFeatureRequest::NoGeometry )
03252                                           .setSubsetOfAttributes( attList ) );
03253 
03254     QgsFeature f;
03255     QVariant currentValue;
03256     QHash<QString, QVariant> val;
03257     while ( fit.nextFeature( f ) )
03258     {
03259       currentValue = f.attribute( index );
03260       val.insert( currentValue.toString(), currentValue );
03261       if ( limit >= 0 && val.size() >= limit )
03262       {
03263         break;
03264       }
03265     }
03266 
03267     uniqueValues = val.values();
03268     return;
03269   }
03270 
03271   Q_ASSERT_X( false, "QgsVectorLayer::uniqueValues()", "Unknown source of the field!" );
03272 }
03273 
03274 QVariant QgsVectorLayer::minimumValue( int index )
03275 {
03276   if ( !mDataProvider )
03277   {
03278     return QVariant();
03279   }
03280 
03281   QgsFields::FieldOrigin origin = mUpdatedFields.fieldOrigin( index );
03282 
03283   if ( origin == QgsFields::OriginProvider ) //a provider field
03284   {
03285     return mDataProvider->minimumValue( index );
03286   }
03287   else if ( origin == QgsFields::OriginJoin )
03288   {
03289     int sourceLayerIndex;
03290     const QgsVectorJoinInfo* join = mJoinBuffer->joinForFieldIndex( index, mUpdatedFields, sourceLayerIndex );
03291     Q_ASSERT( join );
03292 
03293     QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( join->joinLayerId ) );
03294     Q_ASSERT( vl );
03295 
03296     return vl->minimumValue( sourceLayerIndex );
03297   }
03298   else if ( origin == QgsFields::OriginEdit )
03299   {
03300     // the layer is editable, but in certain cases it can still be avoided going through all features
03301     if ( mEditBuffer->mDeletedFeatureIds.isEmpty() && mEditBuffer->mAddedFeatures.isEmpty() && !mEditBuffer->mDeletedAttributeIds.contains( index ) && mEditBuffer->mChangedAttributeValues.isEmpty() )
03302     {
03303       return mDataProvider->minimumValue( index );
03304     }
03305 
03306     // we need to go through each feature
03307     QgsAttributeList attList;
03308     attList << index;
03309 
03310     QgsFeatureIterator fit = getFeatures( QgsFeatureRequest()
03311                                           .setFlags( QgsFeatureRequest::NoGeometry )
03312                                           .setSubsetOfAttributes( attList ) );
03313 
03314     QgsFeature f;
03315     double minimumValue = std::numeric_limits<double>::max();
03316     double currentValue = 0;
03317     while ( fit.nextFeature( f ) )
03318     {
03319       currentValue = f.attribute( index ).toDouble();
03320       if ( currentValue < minimumValue )
03321       {
03322         minimumValue = currentValue;
03323       }
03324     }
03325     return QVariant( minimumValue );
03326   }
03327 
03328   Q_ASSERT_X( false, "QgsVectorLayer::minimumValue()", "Unknown source of the field!" );
03329   return QVariant();
03330 }
03331 
03332 QVariant QgsVectorLayer::maximumValue( int index )
03333 {
03334   if ( !mDataProvider )
03335   {
03336     return QVariant();
03337   }
03338 
03339   QgsFields::FieldOrigin origin = mUpdatedFields.fieldOrigin( index );
03340 
03341   if ( origin == QgsFields::OriginProvider ) //a provider field
03342   {
03343     return mDataProvider->maximumValue( index );
03344   }
03345   else if ( origin == QgsFields::OriginJoin )
03346   {
03347     int sourceLayerIndex;
03348     const QgsVectorJoinInfo* join = mJoinBuffer->joinForFieldIndex( index, mUpdatedFields, sourceLayerIndex );
03349     Q_ASSERT( join );
03350 
03351     QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( join->joinLayerId ) );
03352     Q_ASSERT( vl );
03353 
03354     return vl->maximumValue( sourceLayerIndex );
03355   }
03356   else if ( origin == QgsFields::OriginEdit )
03357   {
03358     // the layer is editable, but in certain cases it can still be avoided going through all features
03359     if ( mEditBuffer->mDeletedFeatureIds.isEmpty() &&
03360          mEditBuffer->mAddedFeatures.isEmpty() &&
03361          !mEditBuffer->mDeletedAttributeIds.contains( index ) &&
03362          mEditBuffer->mChangedAttributeValues.isEmpty() )
03363     {
03364       return mDataProvider->maximumValue( index );
03365     }
03366 
03367     // we need to go through each feature
03368     QgsAttributeList attList;
03369     attList << index;
03370 
03371     QgsFeatureIterator fit = getFeatures( QgsFeatureRequest()
03372                                           .setFlags( QgsFeatureRequest::NoGeometry )
03373                                           .setSubsetOfAttributes( attList ) );
03374 
03375     QgsFeature f;
03376     double maximumValue = -std::numeric_limits<double>::max();
03377     double currentValue = 0;
03378     while ( fit.nextFeature( f ) )
03379     {
03380       currentValue = f.attribute( index ).toDouble();
03381       if ( currentValue > maximumValue )
03382       {
03383         maximumValue = currentValue;
03384       }
03385     }
03386     return QVariant( maximumValue );
03387   }
03388 
03389   Q_ASSERT_X( false, "QgsVectorLayer::maximumValue()", "Unknown source of the field!" );
03390   return QVariant();
03391 }
03392 
03394 void QgsVectorLayer::setFeatureBlendMode( const QPainter::CompositionMode featureBlendMode )
03395 {
03396   mFeatureBlendMode = featureBlendMode;
03397 }
03398 
03400 QPainter::CompositionMode QgsVectorLayer::featureBlendMode() const
03401 {
03402   return mFeatureBlendMode;
03403 }
03404 
03406 void QgsVectorLayer::setLayerTransparency( int layerTransparency )
03407 {
03408   mLayerTransparency = layerTransparency;
03409 }
03410 
03412 int QgsVectorLayer::layerTransparency() const
03413 {
03414   return mLayerTransparency;
03415 }
03416 
03417 void QgsVectorLayer::stopRendererV2( QgsRenderContext& rendererContext, QgsSingleSymbolRendererV2* selRenderer )
03418 {
03419   mRendererV2->stopRender( rendererContext );
03420   if ( selRenderer )
03421   {
03422     selRenderer->stopRender( rendererContext );
03423     delete selRenderer;
03424   }
03425 }
03426 
03427 void QgsVectorLayer::prepareLabelingAndDiagrams( QgsRenderContext& rendererContext, QgsAttributeList& attributes, bool& labeling )
03428 {
03429   if ( !rendererContext.labelingEngine() )
03430     return;
03431 
03432   QSet<int> attrIndex;
03433   if ( rendererContext.labelingEngine()->prepareLayer( this, attrIndex, rendererContext ) )
03434   {
03435     QSet<int>::const_iterator attIt = attrIndex.constBegin();
03436     for ( ; attIt != attrIndex.constEnd(); ++attIt )
03437     {
03438       if ( !attributes.contains( *attIt ) )
03439       {
03440         attributes << *attIt;
03441       }
03442     }
03443     labeling = true;
03444   }
03445 
03446   if ( labeling )
03447   {
03448     // see if feature count limit is set for labeling
03449     QgsPalLayerSettings& palyr = rendererContext.labelingEngine()->layer( this->id() );
03450     if ( palyr.limitNumLabels && palyr.maxNumLabels > 0 )
03451     {
03452       QgsFeatureIterator fit = getFeatures( QgsFeatureRequest()
03453                                             .setFilterRect( rendererContext.extent() )
03454                                             .setSubsetOfAttributes( QgsAttributeList() ) );
03455 
03456       // total number of features that may be labeled
03457       QgsFeature f;
03458       int nFeatsToLabel = 0;
03459       while ( fit.nextFeature( f ) )
03460       {
03461         nFeatsToLabel++;
03462       }
03463       palyr.mFeaturesToLabel = nFeatsToLabel;
03464     }
03465   }
03466 
03467   //register diagram layers
03468   if ( mDiagramRenderer && mDiagramLayerSettings )
03469   {
03470     mDiagramLayerSettings->renderer = mDiagramRenderer;
03471     rendererContext.labelingEngine()->addDiagramLayer( this, mDiagramLayerSettings );
03472     //add attributes needed by the diagram renderer
03473     QList<int> att = mDiagramRenderer->diagramAttributes();
03474     QList<int>::const_iterator attIt = att.constBegin();
03475     for ( ; attIt != att.constEnd(); ++attIt )
03476     {
03477       if ( !attributes.contains( *attIt ) )
03478       {
03479         attributes << *attIt;
03480       }
03481     }
03482     //and the ones needed for data defined diagram positions
03483     if ( mDiagramLayerSettings->xPosColumn >= 0 && !attributes.contains( mDiagramLayerSettings->xPosColumn ) )
03484     {
03485       attributes << mDiagramLayerSettings->xPosColumn;
03486     }
03487     if ( mDiagramLayerSettings->yPosColumn >= 0 && !attributes.contains( mDiagramLayerSettings->yPosColumn ) )
03488     {
03489       attributes << mDiagramLayerSettings->yPosColumn;
03490     }
03491   }
03492 }
03493 
03494 void QgsVectorLayer::setDiagramLayerSettings( const QgsDiagramLayerSettings& s )
03495 {
03496   if ( !mDiagramLayerSettings )
03497     mDiagramLayerSettings = new QgsDiagramLayerSettings();
03498   *mDiagramLayerSettings = s;
03499 }
03500 
03501 QString QgsVectorLayer::metadata()
03502 {
03503   QString myMetadata = "<html><body>";
03504 
03505   //-------------
03506 
03507   myMetadata += "<p class=\"subheaderglossy\">";
03508   myMetadata += tr( "General" );
03509   myMetadata += "</p>\n";
03510 
03511   // data comment
03512   if ( !( dataComment().isEmpty() ) )
03513   {
03514     myMetadata += "<p class=\"glossy\">" + tr( "Layer comment" ) + "</p>\n";
03515     myMetadata += "<p>";
03516     myMetadata += dataComment();
03517     myMetadata += "</p>\n";
03518   }
03519 
03520   //storage type
03521   myMetadata += "<p class=\"glossy\">" + tr( "Storage type of this layer" ) + "</p>\n";
03522   myMetadata += "<p>";
03523   myMetadata += storageType();
03524   myMetadata += "</p>\n";
03525 
03526   // data source
03527   myMetadata += "<p class=\"glossy\">" + tr( "Source for this layer" ) + "</p>\n";
03528   myMetadata += "<p>";
03529   myMetadata += publicSource();
03530   myMetadata += "</p>\n";
03531 
03532   //geom type
03533 
03534   QGis::GeometryType type = geometryType();
03535 
03536   if ( type < 0 || type > QGis::NoGeometry )
03537   {
03538     QgsDebugMsg( "Invalid vector type" );
03539   }
03540   else
03541   {
03542     QString typeString( QGis::vectorGeometryType( geometryType() ) );
03543 
03544     myMetadata += "<p class=\"glossy\">" + tr( "Geometry type of the features in this layer" ) + "</p>\n";
03545     myMetadata += "<p>";
03546     myMetadata += typeString;
03547     myMetadata += "</p>\n";
03548   }
03549 
03550   QgsAttributeList pkAttrList = pendingPkAttributesList();
03551   if ( !pkAttrList.isEmpty() )
03552   {
03553     myMetadata += "<p class=\"glossy\">" + tr( "Primary key attributes" ) + "</p>\n";
03554     myMetadata += "<p>";
03555     foreach ( int idx, pkAttrList )
03556     {
03557       myMetadata += pendingFields()[ idx ].name() + " ";
03558     }
03559     myMetadata += "</p>\n";
03560   }
03561 
03562 
03563   //feature count
03564   myMetadata += "<p class=\"glossy\">" + tr( "The number of features in this layer" ) + "</p>\n";
03565   myMetadata += "<p>";
03566   myMetadata += QString::number( featureCount() );
03567   myMetadata += "</p>\n";
03568   //capabilities
03569   myMetadata += "<p class=\"glossy\">" + tr( "Editing capabilities of this layer" ) + "</p>\n";
03570   myMetadata += "<p>";
03571   myMetadata += capabilitiesString();
03572   myMetadata += "</p>\n";
03573 
03574   //-------------
03575 
03576   QgsRectangle myExtent = extent();
03577   myMetadata += "<p class=\"subheaderglossy\">";
03578   myMetadata += tr( "Extents" );
03579   myMetadata += "</p>\n";
03580 
03581   //extents in layer cs  TODO...maybe make a little nested table to improve layout...
03582   myMetadata += "<p class=\"glossy\">" + tr( "In layer spatial reference system units" ) + "</p>\n";
03583   myMetadata += "<p>";
03584   // Try to be a bit clever over what number format we use for the
03585   // extents. Some people don't like it using scientific notation when the
03586   // numbers get large, but for small numbers this is the more practical
03587   // option (so we can't force the format to 'f' for all values).
03588   // The scheme:
03589   // - for all numbers with more than 5 digits, force non-scientific notation
03590   // and 2 digits after the decimal point.
03591   // - for all smaller numbers let the OS decide which format to use (it will
03592   // generally use non-scientific unless the number gets much less than 1).
03593 
03594   if ( !myExtent.isEmpty() )
03595   {
03596     QString xMin, yMin, xMax, yMax;
03597     double changeoverValue = 99999; // The 'largest' 5 digit number
03598     if ( qAbs( myExtent.xMinimum() ) > changeoverValue )
03599     {
03600       xMin = QString( "%1" ).arg( myExtent.xMinimum(), 0, 'f', 2 );
03601     }
03602     else
03603     {
03604       xMin = QString( "%1" ).arg( myExtent.xMinimum() );
03605     }
03606     if ( qAbs( myExtent.yMinimum() ) > changeoverValue )
03607     {
03608       yMin = QString( "%1" ).arg( myExtent.yMinimum(), 0, 'f', 2 );
03609     }
03610     else
03611     {
03612       yMin = QString( "%1" ).arg( myExtent.yMinimum() );
03613     }
03614     if ( qAbs( myExtent.xMaximum() ) > changeoverValue )
03615     {
03616       xMax = QString( "%1" ).arg( myExtent.xMaximum(), 0, 'f', 2 );
03617     }
03618     else
03619     {
03620       xMax = QString( "%1" ).arg( myExtent.xMaximum() );
03621     }
03622     if ( qAbs( myExtent.yMaximum() ) > changeoverValue )
03623     {
03624       yMax = QString( "%1" ).arg( myExtent.yMaximum(), 0, 'f', 2 );
03625     }
03626     else
03627     {
03628       yMax = QString( "%1" ).arg( myExtent.yMaximum() );
03629     }
03630 
03631     myMetadata += tr( "xMin,yMin %1,%2 : xMax,yMax %3,%4" )
03632                   .arg( xMin ).arg( yMin ).arg( xMax ).arg( yMax );
03633   }
03634   else
03635   {
03636     myMetadata += tr( "unknown extent" );
03637   }
03638 
03639   myMetadata += "</p>\n";
03640 
03641   //extents in project cs
03642 
03643   try
03644   {
03645 #if 0
03646     // TODO: currently disabled, will revisit later [MD]
03647     QgsRectangle myProjectedExtent = coordinateTransform->transformBoundingBox( extent() );
03648     myMetadata += "<p class=\"glossy\">" + tr( "In project spatial reference system units" ) + "</p>\n";
03649     myMetadata += "<p>";
03650     myMetadata += tr( "xMin,yMin %1,%2 : xMax,yMax %3,%4" )
03651                   .arg( myProjectedExtent.xMinimum() )
03652                   .arg( myProjectedExtent.yMinimum() )
03653                   .arg( myProjectedExtent.xMaximum() )
03654                   .arg( myProjectedExtent.yMaximum() );
03655     myMetadata += "</p>\n";
03656 #endif
03657 
03658     //
03659     // Display layer spatial ref system
03660     //
03661     myMetadata += "<p class=\"glossy\">" + tr( "Layer Spatial Reference System" ) + "</p>\n";
03662     myMetadata += "<p>";
03663     myMetadata += crs().toProj4().replace( QRegExp( "\"" ), " \"" );
03664     myMetadata += "</p>\n";
03665 
03666     //
03667     // Display project (output) spatial ref system
03668     //
03669 #if 0
03670     // TODO: disabled for now, will revisit later [MD]
03671     //myMetadata += "<tr><td bgcolor=\"gray\">";
03672     myMetadata += "<p class=\"glossy\">" + tr( "Project (Output) Spatial Reference System" ) + "</p>\n";
03673     myMetadata += "<p>";
03674     myMetadata += coordinateTransform->destCRS().toProj4().replace( QRegExp( "\"" ), " \"" );
03675     myMetadata += "</p>\n";
03676 #endif
03677   }
03678   catch ( QgsCsException &cse )
03679   {
03680     Q_UNUSED( cse );
03681     QgsDebugMsg( cse.what() );
03682 
03683     myMetadata += "<p class=\"glossy\">" + tr( "In project spatial reference system units" ) + "</p>\n";
03684     myMetadata += "<p>";
03685     myMetadata += tr( "(Invalid transformation of layer extents)" );
03686     myMetadata += "</p>\n";
03687 
03688   }
03689 
03690 #if 0
03691   //
03692   // Add the info about each field in the attribute table
03693   //
03694   myMetadata += "<p class=\"glossy\">" + tr( "Attribute field info" ) + "</p>\n";
03695   myMetadata += "<p>";
03696 
03697   // Start a nested table in this trow
03698   myMetadata += "<table width=\"100%\">";
03699   myMetadata += "<tr><th>";
03700   myMetadata += tr( "Field" );
03701   myMetadata += "</th>";
03702   myMetadata += "<th>";
03703   myMetadata += tr( "Type" );
03704   myMetadata += "</th>";
03705   myMetadata += "<th>";
03706   myMetadata += tr( "Length" );
03707   myMetadata += "</th>";
03708   myMetadata += "<th>";
03709   myMetadata += tr( "Precision" );
03710   myMetadata += "</th>";
03711   myMetadata += "<th>";
03712   myMetadata += tr( "Comment" );
03713   myMetadata += "</th>";
03714 
03715   //get info for each field by looping through them
03716   const QgsFieldMap& myFields = pendingFields();
03717   for ( QgsFieldMap::const_iterator it = myFields.begin(); it != myFields.end(); ++it )
03718   {
03719     const QgsField& myField = *it;
03720 
03721     myMetadata += "<tr><td>";
03722     myMetadata += myField.name();
03723     myMetadata += "</td>";
03724     myMetadata += "<td>";
03725     myMetadata += myField.typeName();
03726     myMetadata += "</td>";
03727     myMetadata += "<td>";
03728     myMetadata += QString( "%1" ).arg( myField.length() );
03729     myMetadata += "</td>";
03730     myMetadata += "<td>";
03731     myMetadata += QString( "%1" ).arg( myField.precision() );
03732     myMetadata += "</td>";
03733     myMetadata += "<td>";
03734     myMetadata += QString( "%1" ).arg( myField.comment() );
03735     myMetadata += "</td></tr>";
03736   }
03737 
03738   //close field list
03739   myMetadata += "</table>"; //end of nested table
03740 #endif
03741 
03742   myMetadata += "</body></html>";
03743   return myMetadata;
03744 }
03745 
03746 void QgsVectorLayer::onCacheImageDelete()
03747 {
03748   if ( mCurrentRendererContext )
03749     mCurrentRendererContext->setRenderingStopped( true );
03750 }
03751 
03752 QgsVectorLayer::ValueRelationData &QgsVectorLayer::valueRelation( int idx )
03753 {
03754   const QgsFields &fields = pendingFields();
03755 
03756   // FIXME: throw an exception!?
03757   static QgsVectorLayer::ValueRelationData invalidData;
03758   if ( idx < 0 || idx >= fields.count() )
03759   {
03760     QgsDebugMsg( QString( "field %1 not found" ).arg( idx ) );
03761     return invalidData;
03762   }
03763   QString fieldName = fields[idx].name();
03764 
03765   if ( !mValueRelations.contains( fieldName ) )
03766   {
03767     mValueRelations[fieldName] = ValueRelationData();
03768   }
03769 
03770   return mValueRelations[fieldName];
03771 }
03772 
03773 QList<QgsAttributeEditorElement*> &QgsVectorLayer::attributeEditorElements()
03774 {
03775   return mAttributeEditorElements;
03776 }
03777 
03778 void QgsVectorLayer::clearAttributeEditorWidgets()
03779 {
03780   mAttributeEditorElements.clear();
03781 }
03782 
03783 QDomElement QgsAttributeEditorContainer::toDomElement( QDomDocument& doc ) const
03784 {
03785   QDomElement elem = doc.createElement( "attributeEditorContainer" );
03786   elem.setAttribute( "name", mName );
03787   for ( QList< QgsAttributeEditorElement* >::const_iterator it = mChildren.begin(); it != mChildren.end(); ++it )
03788   {
03789     elem.appendChild(( *it )->toDomElement( doc ) );
03790   }
03791   return elem;
03792 }
03793 
03794 
03795 void QgsAttributeEditorContainer::addChildElement( QgsAttributeEditorElement *widget )
03796 {
03797   mChildren.append( widget );
03798 }
03799 
03800 QDomElement QgsAttributeEditorField::toDomElement( QDomDocument& doc ) const
03801 {
03802   QDomElement elem = doc.createElement( "attributeEditorField" );
03803   elem.setAttribute( "name", mName );
03804   elem.setAttribute( "index", mIdx );
03805   return elem;
03806 }
03807 
03808 int QgsVectorLayer::listStylesInDatabase( QStringList &ids, QStringList &names, QStringList &descriptions, QString &msgError )
03809 {
03810   QgsProviderRegistry * pReg = QgsProviderRegistry::instance();
03811   QLibrary *myLib = pReg->providerLibrary( mProviderKey );
03812   if ( !myLib )
03813   {
03814     msgError = QObject::tr( "Unable to load %1 provider" ).arg( mProviderKey );
03815     return -1;
03816   }
03817   listStyles_t* listStylesExternalMethod = ( listStyles_t * ) cast_to_fptr( myLib->resolve( "listStyles" ) );
03818 
03819   if ( !listStylesExternalMethod )
03820   {
03821     delete myLib;
03822     msgError = QObject::tr( "Provider %1 has no %2 method" ).arg( mProviderKey ).arg( "listStyles" );
03823     return -1;
03824   }
03825 
03826   return listStylesExternalMethod( mDataSource, ids, names, descriptions, msgError );
03827 }
03828 
03829 QString QgsVectorLayer::getStyleFromDatabase( QString styleId, QString &msgError )
03830 {
03831   QgsProviderRegistry * pReg = QgsProviderRegistry::instance();
03832   QLibrary *myLib = pReg->providerLibrary( mProviderKey );
03833   if ( !myLib )
03834   {
03835     msgError = QObject::tr( "Unable to load %1 provider" ).arg( mProviderKey );
03836     return QObject::tr( "" );
03837   }
03838   getStyleById_t* getStyleByIdMethod = ( getStyleById_t * ) cast_to_fptr( myLib->resolve( "getStyleById" ) );
03839 
03840   if ( !getStyleByIdMethod )
03841   {
03842     delete myLib;
03843     msgError = QObject::tr( "Provider %1 has no %2 method" ).arg( mProviderKey ).arg( "getStyleById" );
03844     return QObject::tr( "" );
03845   }
03846 
03847   return getStyleByIdMethod( mDataSource, styleId, msgError );
03848 }
03849 
03850 
03851 void QgsVectorLayer::saveStyleToDatabase( QString name, QString description,
03852     bool useAsDefault, QString uiFileContent,  QString &msgError )
03853 {
03854 
03855   QString sldStyle, qmlStyle;
03856   QgsProviderRegistry * pReg = QgsProviderRegistry::instance();
03857   QLibrary *myLib = pReg->providerLibrary( mProviderKey );
03858   if ( !myLib )
03859   {
03860     msgError = QObject::tr( "Unable to load %1 provider" ).arg( mProviderKey );
03861     return;
03862   }
03863   saveStyle_t* saveStyleExternalMethod = ( saveStyle_t * ) cast_to_fptr( myLib->resolve( "saveStyle" ) );
03864 
03865   if ( !saveStyleExternalMethod )
03866   {
03867     delete myLib;
03868     msgError = QObject::tr( "Provider %1 has no %2 method" ).arg( mProviderKey ).arg( "saveStyle" );
03869     return;
03870   }
03871 
03872   QDomDocument qmlDocument, sldDocument;
03873   this->exportNamedStyle( qmlDocument, msgError );
03874   if ( !msgError.isNull() )
03875   {
03876     return;
03877   }
03878   qmlStyle = qmlDocument.toString();
03879 
03880   this->exportSldStyle( sldDocument, msgError );
03881   if ( !msgError.isNull() )
03882   {
03883     return;
03884   }
03885   sldStyle = sldDocument.toString();
03886 
03887   saveStyleExternalMethod( mDataSource, qmlStyle, sldStyle, name,
03888                            description, uiFileContent, useAsDefault, msgError );
03889 }
03890 
03891 
03892 
03893 QString QgsVectorLayer::loadNamedStyle( const QString theURI, bool &theResultFlag )
03894 {
03895   return loadNamedStyle( theURI, theResultFlag, false );
03896 }
03897 
03898 QString QgsVectorLayer::loadNamedStyle( const QString theURI, bool &theResultFlag , bool loadFromLocalDB )
03899 {
03900   QgsDataSourceURI dsUri( theURI );
03901   if ( !loadFromLocalDB && !dsUri.database().isEmpty() )
03902   {
03903     QgsProviderRegistry * pReg = QgsProviderRegistry::instance();
03904     QLibrary *myLib = pReg->providerLibrary( mProviderKey );
03905     if ( myLib )
03906     {
03907       loadStyle_t* loadStyleExternalMethod = ( loadStyle_t * ) cast_to_fptr( myLib->resolve( "loadStyle" ) );
03908       if ( loadStyleExternalMethod )
03909       {
03910         QString qml, errorMsg;
03911         qml = loadStyleExternalMethod( mDataSource, errorMsg );
03912         if ( !qml.isEmpty() )
03913         {
03914           theResultFlag = this->applyNamedStyle( qml, errorMsg );
03915         }
03916       }
03917     }
03918 
03919   }
03920   if ( !theResultFlag )
03921   {
03922     return QgsMapLayer::loadNamedStyle( theURI, theResultFlag );
03923   }
03924   return QObject::tr( "Loaded from Provider" );
03925 }
03926 
03927 bool QgsVectorLayer::applyNamedStyle( QString namedStyle, QString errorMsg )
03928 {
03929   QDomDocument myDocument( "qgis" );
03930   myDocument.setContent( namedStyle );
03931 
03932   QDomElement myRoot = myDocument.firstChildElement( "qgis" );
03933 
03934   if ( myRoot.isNull() )
03935   {
03936     errorMsg = tr( "Error: qgis element could not be found" );
03937     return false;
03938   }
03939   toggleScaleBasedVisibility( myRoot.attribute( "hasScaleBasedVisibilityFlag" ).toInt() == 1 );
03940   setMinimumScale( myRoot.attribute( "minimumScale" ).toFloat() );
03941   setMaximumScale( myRoot.attribute( "maximumScale" ).toFloat() );
03942 
03943 #if 0
03944   //read transparency level
03945   QDomNode transparencyNode = myRoot.namedItem( "transparencyLevelInt" );
03946   if ( ! transparencyNode.isNull() )
03947   {
03948     // set transparency level only if it's in project
03949     // (otherwise it sets the layer transparent)
03950     QDomElement myElement = transparencyNode.toElement();
03951     setTransparency( myElement.text().toInt() );
03952   }
03953 #endif
03954 
03955   return readSymbology( myRoot, errorMsg );
03956 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines