QGIS API Documentation  2.2.0-Valmiera
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsvectorlayer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectorlayer.cpp
3  --------------------
4  begin : Oct 29, 2003
5  copyright : (C) 2003 by Gary E.Sherman
6  email : sherman at mrcc.com
7 
8  This class implements a generic means to display vector layers. The features
9  and attributes are read from the data store using a "data provider" plugin.
10  QgsVectorLayer can be used with any data store for which an appropriate
11  plugin is available.
12 
13 ***************************************************************************/
14 
15 /***************************************************************************
16  * *
17  * This program is free software; you can redistribute it and/or modify *
18  * it under the terms of the GNU General Public License as published by *
19  * the Free Software Foundation; either version 2 of the License, or *
20  * (at your option) any later version. *
21  * *
22  ***************************************************************************/
23 
24 #include <limits>
25 
26 #include <QImage>
27 #include <QPainter>
28 #include <QPainterPath>
29 #include <QPolygonF>
30 #include <QProgressDialog>
31 #include <QSettings>
32 #include <QString>
33 #include <QDomNode>
34 #include <QVector>
35 
36 #include "qgsvectorlayer.h"
37 
38 #include "qgsattributeaction.h"
39 
40 #include "qgis.h" //for globals
41 #include "qgsapplication.h"
42 #include "qgscoordinatetransform.h"
43 #include "qgsdatasourceuri.h"
44 #include "qgsfeature.h"
45 #include "qgsfeaturerequest.h"
46 #include "qgsfield.h"
47 #include "qgsgeometry.h"
48 #include "qgslabel.h"
49 #include "qgslogger.h"
50 #include "qgsmessagelog.h"
51 #include "qgsmaptopixel.h"
52 #include "qgsogcutils.h"
53 #include "qgspoint.h"
54 #include "qgsproviderregistry.h"
55 #include "qgsrectangle.h"
56 #include "qgsrelationmanager.h"
57 #include "qgsrendercontext.h"
59 #include "qgsvectordataprovider.h"
60 #include "qgsgeometrycache.h"
66 #include "qgsmaplayerregistry.h"
67 #include "qgsclipper.h"
68 #include "qgsproject.h"
69 
70 #include "qgsrendererv2.h"
71 #include "qgssymbolv2.h"
72 #include "qgssymbollayerv2.h"
74 #include "qgsdiagramrendererv2.h"
75 #include "qgsstylev2.h"
77 #include "qgspallabeling.h"
78 #include "qgssimplifymethod.h"
79 
80 #include "diagram/qgsdiagram.h"
81 
82 #ifdef TESTPROVIDERLIB
83 #include <dlfcn.h>
84 #endif
85 
86 typedef bool saveStyle_t(
87  const QString& uri,
88  const QString& qmlStyle,
89  const QString& sldStyle,
90  const QString& styleName,
91  const QString& styleDescription,
92  const QString& uiFileContent,
93  bool useAsDefault,
94  QString& errCause
95 );
96 
97 typedef QString loadStyle_t(
98  const QString& uri,
99  QString& errCause
100 );
101 
102 typedef int listStyles_t(
103  const QString& uri,
104  QStringList &ids,
105  QStringList &names,
106  QStringList &descriptions,
107  QString& errCause
108 );
109 
110 typedef QString getStyleById_t(
111  const QString& uri,
112  QString styleID,
113  QString& errCause
114 );
115 
116 QgsVectorLayer::QgsVectorLayer( QString vectorLayerPath,
117  QString baseName,
118  QString providerKey,
119  bool loadDefaultStyleFlag )
120  : QgsMapLayer( VectorLayer, baseName, vectorLayerPath )
121  , mUpdateThreshold( 0 ) // XXX better default value?
122  , mDataProvider( NULL )
123  , mProviderKey( providerKey )
124  , mReadOnly( false )
125  , mRendererV2( NULL )
126  , mLabel( 0 )
127  , mLabelOn( false )
128  , mLabelFontNotFoundNotified( false )
129  , mFeatureBlendMode( QPainter::CompositionMode_SourceOver ) // Default to normal feature blending
130  , mLayerTransparency( 0 )
131  , mVertexMarkerOnlyForSelection( false )
132  , mFeatureFormSuppress( SuppressDefault )
133  , mCache( new QgsGeometryCache( this ) )
134  , mEditBuffer( 0 )
135  , mJoinBuffer( 0 )
136  , mDiagramRenderer( 0 )
137  , mDiagramLayerSettings( 0 )
138  , mValidExtent( false )
139  , mLazyExtent( true )
140  , mSymbolFeatureCounted( false )
141  , mCurrentRendererContext( 0 )
142 
143 {
144  mActions = new QgsAttributeAction( this );
145 
146  // if we're given a provider type, try to create and bind one to this layer
147  if ( ! mProviderKey.isEmpty() )
148  {
150  }
151  if ( mValid )
152  {
153  // Always set crs
155 
156  // check if there is a default style / propertysheet defined
157  // for this layer and if so apply it
158  bool defaultLoadedFlag = false;
159  if ( loadDefaultStyleFlag )
160  {
161  loadDefaultStyle( defaultLoadedFlag );
162  }
163 
164  // if the default style failed to load or was disabled use some very basic defaults
165  if ( !defaultLoadedFlag && hasGeometryType() )
166  {
167  // add single symbol renderer
169  }
170 
171  connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( checkJoinLayerRemove( QString ) ) );
172 
173  // Get the update threshold from user settings. We
174  // do this only on construction to avoid the penality of
175  // fetching this each time the layer is drawn. If the user
176  // changes the threshold from the preferences dialog, it will
177  // have no effect on existing layers
178  // TODO: load this setting somewhere else [MD]
179  //QSettings settings;
180  //mUpdateThreshold = settings.readNumEntry("Map/updateThreshold", 1000);
181  }
182 
183  connect( this, SIGNAL( selectionChanged( QgsFeatureIds, QgsFeatureIds, bool ) ), this, SIGNAL( selectionChanged() ) );
184 
185  connect( QgsProject::instance()->relationManager(), SIGNAL( relationsLoaded() ), this, SLOT( onRelationsLoaded() ) );
186 
187  // Default simplify drawing settings
188  QSettings settings;
189  mSimplifyMethod.setSimplifyHints( ( QgsVectorSimplifyMethod::SimplifyHints ) settings.value( "/qgis/simplifyDrawingHints", ( int ) mSimplifyMethod.simplifyHints() ).toInt() );
190  mSimplifyMethod.setThreshold( settings.value( "/qgis/simplifyDrawingTol", mSimplifyMethod.threshold() ).toFloat() );
191  mSimplifyMethod.setForceLocalOptimization( settings.value( "/qgis/simplifyLocal", mSimplifyMethod.forceLocalOptimization() ).toBool() );
192  mSimplifyMethod.setMaximumScale( settings.value( "/qgis/simplifyMaxScale", mSimplifyMethod.maximumScale() ).toFloat() );
193 
194 } // QgsVectorLayer ctor
195 
196 
197 
199 {
200  QgsDebugMsg( "entered." );
201 
202  emit layerDeleted();
203 
204  mValid = false;
205 
206  delete mDataProvider;
207  delete mEditBuffer;
208  delete mJoinBuffer;
209  delete mCache;
210  delete mLabel;
211  delete mDiagramLayerSettings;
212 
213  delete mActions;
214 
215  delete mRendererV2;
216 }
217 
219 {
220  if ( mDataProvider )
221  {
222  return mDataProvider->storageType();
223  }
224  return 0;
225 }
226 
227 
229 {
230  if ( mDataProvider )
231  {
233  }
234  return 0;
235 }
236 
238 {
239  if ( mDataProvider )
240  {
241  return mDataProvider->dataComment();
242  }
243  return QString();
244 }
245 
246 
248 {
249  return mProviderKey;
250 }
251 
255 void QgsVectorLayer::setDisplayField( QString fldName )
256 {
257  if ( !hasGeometryType() )
258  return;
259 
260  // If fldName is provided, use it as the display field, otherwise
261  // determine the field index for the feature column of the identify
262  // dialog. We look for fields containing "name" first and second for
263  // fields containing "id". If neither are found, the first field
264  // is used as the node.
265  QString idxName = "";
266  QString idxId = "";
267 
268  if ( !fldName.isEmpty() )
269  {
270  mDisplayField = fldName;
271  }
272  else
273  {
274  const QgsFields &fields = pendingFields();
275  int fieldsSize = fields.size();
276 
277  for ( int idx = 0; idx < fields.count(); ++idx )
278  {
279  QString fldName = fields[idx].name();
280  QgsDebugMsg( "Checking field " + fldName + " of " + QString::number( fieldsSize ) + " total" );
281 
282  // Check the fields and keep the first one that matches.
283  // We assume that the user has organized the data with the
284  // more "interesting" field names first. As such, name should
285  // be selected before oldname, othername, etc.
286  if ( fldName.indexOf( "name", 0, Qt::CaseInsensitive ) > -1 )
287  {
288  if ( idxName.isEmpty() )
289  {
290  idxName = fldName;
291  }
292  }
293  if ( fldName.indexOf( "descrip", 0, Qt::CaseInsensitive ) > -1 )
294  {
295  if ( idxName.isEmpty() )
296  {
297  idxName = fldName;
298  }
299  }
300  if ( fldName.indexOf( "id", 0, Qt::CaseInsensitive ) > -1 )
301  {
302  if ( idxId.isEmpty() )
303  {
304  idxId = fldName;
305  }
306  }
307  }
308 
309  //if there were no fields in the dbf just return - otherwise qgis segfaults!
310  if ( fieldsSize == 0 )
311  return;
312 
313  if ( idxName.length() > 0 )
314  {
315  mDisplayField = idxName;
316  }
317  else
318  {
319  if ( idxId.length() > 0 )
320  {
321  mDisplayField = idxId;
322  }
323  else
324  {
325  mDisplayField = fields[0].name();
326  }
327  }
328 
329  }
330 }
331 
332 // NOTE this is a temporary method added by Tim to prevent label clipping
333 // which was occurring when labeller was called in the main draw loop
334 // This method will probably be removed again in the near future!
336 {
337  if ( !hasGeometryType() )
338  return;
339 
340  QgsDebugMsg( "Starting draw of labels: " + id() );
341 
342  if ( mRendererV2 && mLabelOn && mLabel &&
344  ( mLabel->minScale() <= rendererContext.rendererScale() &&
345  rendererContext.rendererScale() <= mLabel->maxScale() ) ) )
346  {
347  QgsAttributeList attributes;
348  foreach ( QString attrName, mRendererV2->usedAttributes() )
349  {
350  int attrNum = fieldNameIndex( attrName );
351  attributes.append( attrNum );
352  }
353  // make sure the renderer is ready for classification ("symbolForFeature")
354  mRendererV2->startRender( rendererContext, this );
355 
356  // Add fields required for labels
357  mLabel->addRequiredFields( attributes );
358 
359  QgsDebugMsg( "Selecting features based on view extent" );
360 
361  int featureCount = 0;
362 
363  try
364  {
365  // select the records in the extent. The provider sets a spatial filter
366  // and sets up the selection set for retrieval
368  .setFilterRect( rendererContext.extent() )
369  .setSubsetOfAttributes( attributes ) );
370 
371  QgsFeature fet;
372  while ( fit.nextFeature( fet ) )
373  {
374  if ( mRendererV2->willRenderFeature( fet ) )
375  {
376  bool sel = mSelectedFeatureIds.contains( fet.id() );
377  mLabel->renderLabel( rendererContext, fet, sel, 0 );
378  }
379  featureCount++;
380  }
381  }
382  catch ( QgsCsException &e )
383  {
384  Q_UNUSED( e );
385  QgsDebugMsg( "Error projecting label locations" );
386  }
387 
388  if ( mRendererV2 )
389  {
390  mRendererV2->stopRender( rendererContext );
391  }
392 
393  QgsDebugMsg( QString( "Total features processed %1" ).arg( featureCount ) );
394 
395  // XXX Something in our draw event is triggering an additional draw event when resizing [TE 01/26/06]
396  // XXX Calling this will begin processing the next draw event causing image havoc and recursion crashes.
397  //qApp->processEvents();
398 
399  }
400 }
401 
402 
403 
404 void QgsVectorLayer::drawRendererV2( QgsFeatureIterator &fit, QgsRenderContext& rendererContext, bool labeling )
405 {
406  if ( !hasGeometryType() )
407  return;
408 
409  mCurrentRendererContext = &rendererContext;
410 
411  QSettings settings;
412  bool vertexMarkerOnlyForSelection = settings.value( "/qgis/digitizing/marker_only_for_selected", false ).toBool();
413 
414 #ifndef Q_WS_MAC
415  int featureCount = 0;
416 #endif //Q_WS_MAC
417 
418  QgsFeature fet;
419  while ( fit.nextFeature( fet ) )
420  {
421  try
422  {
423  if ( !fet.geometry() )
424  continue; // skip features without geometry
425 
426 #ifndef Q_WS_MAC //MH: disable this on Mac for now to avoid problems with resizing
427 #ifdef Q_WS_X11
428  if ( !mEnableBackbuffer ) // do not handle events, as we're already inside a paint event
429  {
430 #endif // Q_WS_X11
431  if ( mUpdateThreshold > 0 && 0 == featureCount % mUpdateThreshold )
432  {
433  emit screenUpdateRequested();
434  // emit drawingProgress( featureCount, totalFeatures );
435  qApp->processEvents();
436  }
437  else if ( featureCount % 1000 == 0 )
438  {
439  // emit drawingProgress( featureCount, totalFeatures );
440  qApp->processEvents();
441  }
442 #ifdef Q_WS_X11
443  }
444 #endif // Q_WS_X11
445 #endif // Q_WS_MAC
446 
447  if ( rendererContext.renderingStopped() )
448  {
449  break;
450  }
451 
452  bool sel = mSelectedFeatureIds.contains( fet.id() );
453  bool drawMarker = ( mEditBuffer && ( !vertexMarkerOnlyForSelection || sel ) );
454 
455  // render feature
456  bool rendered = mRendererV2->renderFeature( fet, rendererContext, -1, sel, drawMarker );
457 
458  if ( mEditBuffer )
459  {
460  // Cache this for the use of (e.g.) modifying the feature's uncommitted geometry.
461  mCache->cacheGeometry( fet.id(), *fet.geometry() );
462  }
463 
464  // labeling - register feature
465  if ( rendered && rendererContext.labelingEngine() )
466  {
467  if ( labeling )
468  {
469  rendererContext.labelingEngine()->registerFeature( this, fet, rendererContext );
470  }
471  if ( mDiagramRenderer )
472  {
473  rendererContext.labelingEngine()->registerDiagramFeature( this, fet, rendererContext );
474  }
475  }
476  }
477  catch ( const QgsCsException &cse )
478  {
479  Q_UNUSED( cse );
480  QgsDebugMsg( QString( "Failed to transform a point while drawing a feature with ID '%1'. Ignoring this feature. %2" )
481  .arg( fet.id() ).arg( cse.what() ) );
482  }
483 #ifndef Q_WS_MAC
484  ++featureCount;
485 #endif //Q_WS_MAC
486  }
487 
488  stopRendererV2( rendererContext, NULL );
489 
491 
492 #ifndef Q_WS_MAC
493  QgsDebugMsg( QString( "Total features processed %1" ).arg( featureCount ) );
494 #endif
495 }
496 
497 void QgsVectorLayer::drawRendererV2Levels( QgsFeatureIterator &fit, QgsRenderContext& rendererContext, bool labeling )
498 {
499  if ( !hasGeometryType() )
500  return;
501 
502  QHash< QgsSymbolV2*, QList<QgsFeature> > features; // key = symbol, value = array of features
503 
504  QSettings settings;
505  bool vertexMarkerOnlyForSelection = settings.value( "/qgis/digitizing/marker_only_for_selected", false ).toBool();
506 
507  QgsSingleSymbolRendererV2* selRenderer = NULL;
508  if ( !mSelectedFeatureIds.isEmpty() )
509  {
511  selRenderer->symbol()->setColor( rendererContext.selectionColor() );
513  selRenderer->startRender( rendererContext, this );
514  }
515 
516  // 1. fetch features
517  QgsFeature fet;
518 #ifndef Q_WS_MAC
519  int featureCount = 0;
520 #endif //Q_WS_MAC
521  while ( fit.nextFeature( fet ) )
522  {
523  if ( !fet.geometry() )
524  continue; // skip features without geometry
525 
526  if ( rendererContext.renderingStopped() )
527  {
528  stopRendererV2( rendererContext, selRenderer );
529  return;
530  }
531 #ifndef Q_WS_MAC
532  if ( featureCount % 1000 == 0 )
533  {
534  qApp->processEvents();
535  }
536 #endif //Q_WS_MAC
538  if ( !sym )
539  {
540  continue;
541  }
542 
543  if ( !features.contains( sym ) )
544  {
545  features.insert( sym, QList<QgsFeature>() );
546  }
547  features[sym].append( fet );
548 
549  if ( mEditBuffer )
550  {
551  // Cache this for the use of (e.g.) modifying the feature's uncommitted geometry.
552  mCache->cacheGeometry( fet.id(), *fet.geometry() );
553  }
554 
555  if ( sym && rendererContext.labelingEngine() )
556  {
557  if ( labeling )
558  {
559  rendererContext.labelingEngine()->registerFeature( this, fet, rendererContext );
560  }
561  if ( mDiagramRenderer )
562  {
563  rendererContext.labelingEngine()->registerDiagramFeature( this, fet, rendererContext );
564  }
565  }
566 
567 #ifndef Q_WS_MAC
568  ++featureCount;
569 #endif //Q_WS_MAC
570  }
571 
572  // find out the order
573  QgsSymbolV2LevelOrder levels;
574  QgsSymbolV2List symbols = mRendererV2->symbols();
575  for ( int i = 0; i < symbols.count(); i++ )
576  {
577  QgsSymbolV2* sym = symbols[i];
578  for ( int j = 0; j < sym->symbolLayerCount(); j++ )
579  {
580  int level = sym->symbolLayer( j )->renderingPass();
581  if ( level < 0 || level >= 1000 ) // ignore invalid levels
582  continue;
583  QgsSymbolV2LevelItem item( sym, j );
584  while ( level >= levels.count() ) // append new empty levels
585  levels.append( QgsSymbolV2Level() );
586  levels[level].append( item );
587  }
588  }
589 
590  // 2. draw features in correct order
591  for ( int l = 0; l < levels.count(); l++ )
592  {
593  QgsSymbolV2Level& level = levels[l];
594  for ( int i = 0; i < level.count(); i++ )
595  {
596  QgsSymbolV2LevelItem& item = level[i];
597  if ( !features.contains( item.symbol() ) )
598  {
599  QgsDebugMsg( "level item's symbol not found!" );
600  continue;
601  }
602  int layer = item.layer();
603  QList<QgsFeature>& lst = features[item.symbol()];
604  QList<QgsFeature>::iterator fit;
605 #ifndef Q_WS_MAC
606  featureCount = 0;
607 #endif //Q_WS_MAC
608  for ( fit = lst.begin(); fit != lst.end(); ++fit )
609  {
610  if ( rendererContext.renderingStopped() )
611  {
612  stopRendererV2( rendererContext, selRenderer );
613  return;
614  }
615 #ifndef Q_WS_MAC
616  if ( featureCount % 1000 == 0 )
617  {
618  qApp->processEvents();
619  }
620 #endif //Q_WS_MAC
621  bool sel = mSelectedFeatureIds.contains( fit->id() );
622  // maybe vertex markers should be drawn only during the last pass...
623  bool drawMarker = ( mEditBuffer && ( !vertexMarkerOnlyForSelection || sel ) );
624 
625  try
626  {
627  mRendererV2->renderFeature( *fit, rendererContext, layer, sel, drawMarker );
628  }
629  catch ( const QgsCsException &cse )
630  {
631  Q_UNUSED( cse );
632  QgsDebugMsg( QString( "Failed to transform a point while drawing a feature with ID '%1'. Ignoring this feature. %2" )
633  .arg( fet.id() ).arg( cse.what() ) );
634  }
635 #ifndef Q_WS_MAC
636  ++featureCount;
637 #endif //Q_WS_MAC
638  }
639  }
640  }
641 
642  stopRendererV2( rendererContext, selRenderer );
643 }
644 
646 {
647  if ( mDataProvider )
648  {
650  }
651 }
652 
653 bool QgsVectorLayer::draw( QgsRenderContext& rendererContext )
654 {
655  if ( !hasGeometryType() )
656  return true;
657 
658  //set update threshold before each draw to make sure the current setting is picked up
659  QSettings settings;
660  mUpdateThreshold = settings.value( "Map/updateThreshold", 0 ).toInt();
661  // users could accidently set updateThreshold threshold to a small value
662  // and complain about bad performance -> force min 1000 here
663  if ( mUpdateThreshold > 0 && mUpdateThreshold < 1000 )
664  {
665  mUpdateThreshold = 1000;
666  }
667 
668 #ifdef Q_WS_X11
669  mEnableBackbuffer = settings.value( "/Map/enableBackbuffer", 1 ).toBool();
670 #endif
671 
672  if ( !mRendererV2 )
673  return false;
674 
675  QgsDebugMsg( "rendering v2:\n" + mRendererV2->dump() );
676 
677  if ( mEditBuffer )
678  {
679  // Destroy all cached geometries and clear the references to them
681  mCache->setCachedGeometriesRect( rendererContext.extent() );
682 
683  // set editing vertex markers style
685  }
686 
687  QgsAttributeList attributes;
688  foreach ( QString attrName, mRendererV2->usedAttributes() )
689  {
690  int attrNum = fieldNameIndex( attrName );
691  attributes.append( attrNum );
692  QgsDebugMsg( "attrs: " + attrName + " - " + QString::number( attrNum ) );
693  }
694 
695  bool labeling = false;
696  //register label and diagram layer to the labeling engine
697  prepareLabelingAndDiagrams( rendererContext, attributes, labeling );
698 
699  //do startRender before getFeatures to give renderers the possibility of querying features in the startRender method
700  mRendererV2->startRender( rendererContext, this );
701 
702  QgsFeatureRequest featureRequest = QgsFeatureRequest()
703  .setFilterRect( rendererContext.extent() )
704  .setSubsetOfAttributes( attributes );
705 
706  // enable the simplification of the geometries (Using the current map2pixel context) before send it to renderer engine.
708  {
709  QPainter* p = rendererContext.painter();
710  double dpi = ( p->device()->logicalDpiX() + p->device()->logicalDpiY() ) / 2;
711  double map2pixelTol = mSimplifyMethod.threshold() * 96.0f / dpi;
712 
713  const QgsMapToPixel& mtp = rendererContext.mapToPixel();
714  map2pixelTol *= mtp.mapUnitsPerPixel();
715  const QgsCoordinateTransform* ct = rendererContext.coordinateTransform();
716 
717  // resize the tolerance using the change of size of an 1-BBOX from the source CoordinateSystem to the target CoordinateSystem
718  if ( ct && !(( QgsCoordinateTransform* )ct )->isShortCircuited() )
719  {
720  try
721  {
722  QgsPoint center = rendererContext.extent().center();
723  double rectSize = ct->sourceCrs().geographicFlag() ? 0.0008983 /* ~100/(40075014/360=111319.4833) */ : 100;
724 
725  QgsRectangle sourceRect = QgsRectangle( center.x(), center.y(), center.x() + rectSize, center.y() + rectSize );
726  QgsRectangle targetRect = ct->transform( sourceRect );
727 
728  QgsDebugMsg( QString( "Simplify - SourceTransformRect=%1" ).arg( sourceRect.toString( 16 ) ) );
729  QgsDebugMsg( QString( "Simplify - TargetTransformRect=%1" ).arg( targetRect.toString( 16 ) ) );
730 
731  if ( !sourceRect.isEmpty() && sourceRect.isFinite() && !targetRect.isEmpty() && targetRect.isFinite() )
732  {
733  QgsPoint minimumSrcPoint( sourceRect.xMinimum(), sourceRect.yMinimum() );
734  QgsPoint maximumSrcPoint( sourceRect.xMaximum(), sourceRect.yMaximum() );
735  QgsPoint minimumDstPoint( targetRect.xMinimum(), targetRect.yMinimum() );
736  QgsPoint maximumDstPoint( targetRect.xMaximum(), targetRect.yMaximum() );
737 
738  double sourceHypothenuse = sqrt( minimumSrcPoint.sqrDist( maximumSrcPoint ) );
739  double targetHypothenuse = sqrt( minimumDstPoint.sqrDist( maximumDstPoint ) );
740 
741  QgsDebugMsg( QString( "Simplify - SourceHypothenuse=%1" ).arg( sourceHypothenuse ) );
742  QgsDebugMsg( QString( "Simplify - TargetHypothenuse=%1" ).arg( targetHypothenuse ) );
743 
744  if ( targetHypothenuse != 0 )
745  map2pixelTol *= ( sourceHypothenuse / targetHypothenuse );
746  }
747  }
748  catch ( QgsCsException &cse )
749  {
750  QgsMessageLog::logMessage( tr( "Simplify transform error caught: %1" ).arg( cse.what() ), tr( "CRS" ) );
751  }
752  }
753 
756  simplifyMethod.setTolerance( map2pixelTol );
758 
759  featureRequest.setSimplifyMethod( simplifyMethod );
760  }
761 
762  QgsFeatureIterator fit = getFeatures( featureRequest );
763 
765  drawRendererV2Levels( fit, rendererContext, labeling );
766  else
767  drawRendererV2( fit, rendererContext, labeling );
768 
769  return true;
770 }
771 
772 void QgsVectorLayer::drawVertexMarker( double x, double y, QPainter& p, QgsVectorLayer::VertexMarkerType type, int m )
773 {
775  {
776  p.setPen( QColor( 50, 100, 120, 200 ) );
777  p.setBrush( QColor( 200, 200, 210, 120 ) );
778  p.drawEllipse( x - m, y - m, m * 2 + 1, m * 2 + 1 );
779  }
780  else if ( type == QgsVectorLayer::Cross )
781  {
782  p.setPen( QColor( 255, 0, 0 ) );
783  p.drawLine( x - m, y + m, x + m, y - m );
784  p.drawLine( x - m, y - m, x + m, y + m );
785  }
786 }
787 
789 {
790  mSelectedFeatureIds.insert( fid );
791 
792  setCacheImage( 0 );
793  emit selectionChanged( QgsFeatureIds() << fid, QgsFeatureIds(), false );
794 }
795 
796 void QgsVectorLayer::select( const QgsFeatureIds& featureIds )
797 {
798  mSelectedFeatureIds.unite( featureIds );
799 
800  setCacheImage( 0 );
801  emit selectionChanged( featureIds, QgsFeatureIds(), false );
802 }
803 
805 {
806  mSelectedFeatureIds.remove( fid );
807 
808  setCacheImage( 0 );
809  emit selectionChanged( QgsFeatureIds(), QgsFeatureIds() << fid, false );
810 }
811 
812 void QgsVectorLayer::deselect( const QgsFeatureIds& featureIds )
813 {
814  mSelectedFeatureIds.subtract( featureIds );
815 
816  setCacheImage( 0 );
817  emit selectionChanged( QgsFeatureIds(), featureIds, false );
818 }
819 
820 void QgsVectorLayer::select( QgsRectangle & rect, bool addToSelection )
821 {
822  // normalize the rectangle
823  rect.normalize();
824 
825  //select all the elements
827  .setFilterRect( rect )
829  .setSubsetOfAttributes( QgsAttributeList() ) );
830 
831  QgsFeatureIds ids;
832 
833  QgsFeature f;
834  while ( fit.nextFeature( f ) )
835  {
836  ids << f.id();
837  }
838 
839  if ( !addToSelection )
840  {
842  }
843  else
844  {
845  select( ids );
846  }
847 }
848 
850 {
851  QgsFeatureIds intersectingIds = selectIds & deselectIds;
852  if ( intersectingIds.count() > 0 )
853  {
854  QgsDebugMsg( "Trying to select and deselect the same item at the same time. Unsure what to do. Selecting dubious items." );
855  }
856 
857  mSelectedFeatureIds -= deselectIds;
858  mSelectedFeatureIds += selectIds;
859 
860  setCacheImage( 0 );
861 
862  emit selectionChanged( selectIds, deselectIds - intersectingIds, false );
863 }
864 
866 {
868  ids.subtract( mSelectedFeatureIds );
869  setSelectedFeatures( ids );
870 }
871 
873 {
875 }
876 
878 {
880  .setFlags( QgsFeatureRequest::NoGeometry )
881  .setSubsetOfAttributes( QgsAttributeList() ) );
882 
883  QgsFeatureIds ids;
884 
885  QgsFeature fet;
886  while ( fit.nextFeature( fet ) )
887  {
888  ids << fet.id();
889  }
890 
891  return ids;
892 }
893 
895 {
896  // normalize the rectangle
897  rect.normalize();
898 
900  .setFilterRect( rect )
902  .setSubsetOfAttributes( QgsAttributeList() ) );
903 
904  QgsFeatureIds selectIds;
905  QgsFeatureIds deselectIds;
906 
907  QgsFeature fet;
908  while ( fit.nextFeature( fet ) )
909  {
910  if ( mSelectedFeatureIds.contains( fet.id() ) )
911  {
912  deselectIds << fet.id();
913  }
914  else
915  {
916  selectIds << fet.id();
917  }
918  }
919 
920  modifySelection( selectIds, deselectIds );
921 }
922 
924 {
925  if ( mSelectedFeatureIds.size() == 0 )
926  return;
927 
929 }
930 
932 {
933  emit repaintRequested();
934 }
935 
937 {
938  return mDataProvider;
939 }
940 
942 {
943  return mDataProvider;
944 }
945 
946 void QgsVectorLayer::setProviderEncoding( const QString& encoding )
947 {
948  if ( mDataProvider )
949  {
950  mDataProvider->setEncoding( encoding );
951  updateFields();
952  }
953 }
954 
956 {
957  delete mDiagramRenderer;
958  mDiagramRenderer = r;
959 }
960 
962 {
963  if ( mDataProvider )
964  {
966  switch ( type )
967  {
968  case QGis::WKBPoint:
969  case QGis::WKBPoint25D:
970  return QGis::Point;
971 
972  case QGis::WKBLineString:
974  return QGis::Line;
975 
976  case QGis::WKBPolygon:
977  case QGis::WKBPolygon25D:
978  return QGis::Polygon;
979 
980  case QGis::WKBMultiPoint:
982  return QGis::Point;
983 
986  return QGis::Line;
987 
990  return QGis::Polygon;
991 
992  case QGis::WKBNoGeometry:
993  return QGis::NoGeometry;
994  }
995  QgsDebugMsg( QString( "Data Provider Geometry type is not recognised, is %1" ).arg( type ) );
996  }
997  else
998  {
999  QgsDebugMsg( "pointer to mDataProvider is null" );
1000  }
1001 
1002  // We shouldn't get here, and if we have, other things are likely to
1003  // go wrong. Code that uses the type() return value should be
1004  // rewritten to cope with a value of QGis::Unknown. To make this
1005  // need known, the following message is printed every time we get
1006  // here.
1007  QgsDebugMsg( "WARNING: This code should never be reached. Problems may occur..." );
1008 
1009  return QGis::UnknownGeometry;
1010 }
1011 
1013 {
1015  return ( t != QGis::NoGeometry && t != QGis::UnknownGeometry );
1016 }
1017 
1019 {
1020  return ( QGis::WkbType )( mWkbType );
1021 }
1022 
1024 {
1025  if ( mSelectedFeatureIds.size() == 0 ) //no selected features
1026  {
1027  return QgsRectangle( 0, 0, 0, 0 );
1028  }
1029 
1030  QgsRectangle r, retval;
1031  retval.setMinimal();
1032 
1033  QgsFeature fet;
1035  {
1036  foreach ( QgsFeatureId fid, mSelectedFeatureIds )
1037  {
1039  .setFilterFid( fid )
1040  .setSubsetOfAttributes( QgsAttributeList() ) )
1041  .nextFeature( fet ) &&
1042  fet.geometry() )
1043  {
1044  r = fet.geometry()->boundingBox();
1045  retval.combineExtentWith( &r );
1046  }
1047  }
1048  }
1049  else
1050  {
1052  .setSubsetOfAttributes( QgsAttributeList() ) );
1053 
1054  while ( fit.nextFeature( fet ) )
1055  {
1056  if ( mSelectedFeatureIds.contains( fet.id() ) )
1057  {
1058  if ( fet.geometry() )
1059  {
1060  r = fet.geometry()->boundingBox();
1061  retval.combineExtentWith( &r );
1062  }
1063  }
1064  }
1065  }
1066 
1067  if ( retval.width() == 0.0 || retval.height() == 0.0 )
1068  {
1069  // If all of the features are at the one point, buffer the
1070  // rectangle a bit. If they are all at zero, do something a bit
1071  // more crude.
1072 
1073  if ( retval.xMinimum() == 0.0 && retval.xMaximum() == 0.0 &&
1074  retval.yMinimum() == 0.0 && retval.yMaximum() == 0.0 )
1075  {
1076  retval.set( -1.0, -1.0, 1.0, 1.0 );
1077  }
1078  }
1079 
1080  return retval;
1081 }
1082 
1084 {
1085  if ( !mDataProvider )
1086  {
1087  QgsDebugMsg( "invoked with null mDataProvider" );
1088  return 0;
1089  }
1090 
1091  return mDataProvider->featureCount();
1092 }
1093 
1095 {
1096  if ( !mSymbolFeatureCounted ) return -1;
1097  return mSymbolFeatureCountMap.value( symbol );
1098 }
1099 
1100 bool QgsVectorLayer::countSymbolFeatures( bool showProgress )
1101 {
1102  if ( mSymbolFeatureCounted ) return true;
1103  mSymbolFeatureCountMap.clear();
1104 
1105  if ( !mDataProvider )
1106  {
1107  QgsDebugMsg( "invoked with null mDataProvider" );
1108  return false;
1109  }
1110  if ( !mRendererV2 )
1111  {
1112  QgsDebugMsg( "invoked with null mRendererV2" );
1113  return false;
1114  }
1115 
1117  QgsLegendSymbolList::const_iterator symbolIt = symbolList.constBegin();
1118 
1119  for ( ; symbolIt != symbolList.constEnd(); ++symbolIt )
1120  {
1121  mSymbolFeatureCountMap.insert( symbolIt->second, 0 );
1122  }
1123 
1124  long nFeatures = pendingFeatureCount();
1125  QProgressDialog progressDialog( tr( "Updating feature count for layer %1" ).arg( name() ), tr( "Abort" ), 0, nFeatures );
1126  progressDialog.setWindowModality( Qt::WindowModal );
1127  int featuresCounted = 0;
1128 
1130 
1131  // Renderer (rule based) may depend on context scale, with scale is ignored if 0
1132  QgsRenderContext renderContext;
1133  renderContext.setRendererScale( 0 );
1134  mRendererV2->startRender( renderContext, this );
1135 
1136  QgsFeature f;
1137  while ( fit.nextFeature( f ) )
1138  {
1139  QgsSymbolV2List featureSymbolList = mRendererV2->symbolsForFeature( f );
1140  for ( QgsSymbolV2List::iterator symbolIt = featureSymbolList.begin(); symbolIt != featureSymbolList.end(); ++symbolIt )
1141  {
1142  mSymbolFeatureCountMap[*symbolIt] += 1;
1143  }
1144  ++featuresCounted;
1145 
1146  if ( showProgress )
1147  {
1148  if ( featuresCounted % 50 == 0 )
1149  {
1150  if ( featuresCounted > nFeatures ) //sometimes the feature count is not correct
1151  {
1152  progressDialog.setMaximum( 0 );
1153  }
1154  progressDialog.setValue( featuresCounted );
1155  if ( progressDialog.wasCanceled() )
1156  {
1157  mSymbolFeatureCountMap.clear();
1158  mRendererV2->stopRender( renderContext );
1159  return false;
1160  }
1161  }
1162  }
1163  }
1164  mRendererV2->stopRender( renderContext );
1165  progressDialog.setValue( nFeatures );
1166  mSymbolFeatureCounted = true;
1167  return true;
1168 }
1169 
1171 {
1172  mValidExtent = false;
1173 }
1174 
1176 {
1178  mValidExtent = true;
1179 }
1180 
1182 {
1183  QgsRectangle rect;
1184  rect.setMinimal();
1185 
1186  if ( !hasGeometryType() )
1187  return rect;
1188 
1189  if ( !mValidExtent && mLazyExtent && mDataProvider )
1190  {
1191  // get the extent
1193 
1194  // show the extent
1195  QString s = mbr.toString();
1196 
1197  QgsDebugMsg( "Extent of layer: " + s );
1198  // store the extent
1199  setExtent( mbr );
1200 
1201  mLazyExtent = false;
1202  }
1203 
1204  if( mValidExtent )
1205  return QgsMapLayer::extent();
1206 
1207  if ( !mDataProvider )
1208  {
1209  QgsDebugMsg( "invoked with null mDataProvider" );
1210  }
1211 
1212  if ( mEditBuffer && mEditBuffer->mDeletedFeatureIds.isEmpty() && mEditBuffer->mChangedGeometries.isEmpty() )
1213  {
1215 
1216  // get the extent of the layer from the provider
1217  // but only when there are some features already
1218  if ( mDataProvider->featureCount() != 0 )
1219  {
1221  rect.combineExtentWith( &r );
1222  }
1223 
1224  for ( QgsFeatureMap::iterator it = mEditBuffer->mAddedFeatures.begin(); it != mEditBuffer->mAddedFeatures.end(); ++it )
1225  {
1226  if ( it->geometry() )
1227  {
1228  QgsRectangle r = it->geometry()->boundingBox();
1229  rect.combineExtentWith( &r );
1230  }
1231  }
1232  }
1233  else
1234  {
1236  .setSubsetOfAttributes( QgsAttributeList() ) );
1237 
1238  QgsFeature fet;
1239  while ( fit.nextFeature( fet ) )
1240  {
1241  if ( fet.geometry() && fet.geometry()->type() != QGis::UnknownGeometry )
1242  {
1243  QgsRectangle bb = fet.geometry()->boundingBox();
1244  rect.combineExtentWith( &bb );
1245  }
1246  }
1247  }
1248 
1249  if ( rect.xMinimum() > rect.xMaximum() && rect.yMinimum() > rect.yMaximum() )
1250  {
1251  // special case when there are no features in provider nor any added
1252  rect = QgsRectangle(); // use rectangle with zero coordinates
1253  }
1254 
1255  setExtent( rect );
1256 
1257  // Send this (hopefully) up the chain to the map canvas
1258  emit recalculateExtents();
1259 
1260  return rect;
1261 }
1262 
1264 {
1265  if ( ! mDataProvider )
1266  {
1267  QgsDebugMsg( "invoked with null mDataProvider" );
1268  return 0;
1269  }
1270  return mDataProvider->subsetString();
1271 }
1272 
1273 bool QgsVectorLayer::setSubsetString( QString subset )
1274 {
1275  if ( ! mDataProvider )
1276  {
1277  QgsDebugMsg( "invoked with null mDataProvider" );
1278  return false;
1279  }
1280 
1281  bool res = mDataProvider->setSubsetString( subset );
1282 
1283  // get the updated data source string from the provider
1285  updateExtents();
1286 
1287  if ( res )
1288  setCacheImage( 0 );
1289 
1290  return res;
1291 }
1292 
1294 {
1295  if ( mDataProvider && !mEditBuffer && ( hasGeometryType() && geometryType() != QGis::Point ) && ( mSimplifyMethod.simplifyHints() & simplifyHint ) && renderContext.useRenderingOptimization() )
1296  {
1297  double maximumSimplificationScale = mSimplifyMethod.maximumScale();
1298 
1299  // check maximum scale at which generalisation should be carried out
1300  if ( maximumSimplificationScale > 1 && renderContext.rendererScale() <= maximumSimplificationScale )
1301  return false;
1302 
1303  return true;
1304  }
1305  return false;
1306 }
1307 
1309 {
1310  if ( !mDataProvider )
1311  return QgsFeatureIterator();
1312 
1313  return QgsFeatureIterator( new QgsVectorLayerFeatureIterator( this, request ) );
1314 }
1315 
1316 
1317 bool QgsVectorLayer::addFeature( QgsFeature& f, bool alsoUpdateExtent )
1318 {
1319  Q_UNUSED( alsoUpdateExtent ); // TODO[MD]
1320  if ( !mEditBuffer || !mDataProvider )
1321  return false;
1322 
1323  bool success = mEditBuffer->addFeature( f );
1324 
1325  if ( success )
1326  updateExtents();
1327 
1328  return success;
1329 }
1330 
1332 {
1333  QgsFeatureRequest req;
1334  req.setFilterFid( f.id() );
1335  if ( !f.geometry() )
1337  if ( f.attributes().isEmpty() )
1339 
1340  QgsFeature current;
1341  if ( !getFeatures( req ).nextFeature( current ) )
1342  {
1343  QgsDebugMsg( QString( "feature %1 could not be retrieved" ).arg( f.id() ) );
1344  return false;
1345  }
1346 
1347  if ( f.geometry() && current.geometry() && f.geometry() != current.geometry() && !f.geometry()->isGeosEqual( *current.geometry() ) )
1348  {
1349  if ( !changeGeometry( f.id(), f.geometry() ) )
1350  {
1351  QgsDebugMsg( QString( "geometry of feature %1 could not be changed." ).arg( f.id() ) );
1352  return false;
1353  }
1354  }
1355 
1356  const QgsAttributes &fa = f.attributes();
1357  const QgsAttributes &ca = current.attributes();
1358 
1359  for ( int attr = 0; attr < fa.count(); ++attr )
1360  {
1361  if ( fa[attr] != ca[attr] )
1362  {
1363  if ( !changeAttributeValue( f.id(), attr, fa[attr], ca[attr] ) )
1364  {
1365  QgsDebugMsg( QString( "attribute %1 of feature %2 could not be changed." ).arg( attr ).arg( f.id() ) );
1366  return false;
1367  }
1368  }
1369  }
1370 
1371  return true;
1372 }
1373 
1374 
1375 bool QgsVectorLayer::insertVertex( double x, double y, QgsFeatureId atFeatureId, int beforeVertex )
1376 {
1377  if ( !mEditBuffer || !mDataProvider )
1378  return false;
1379 
1380  QgsVectorLayerEditUtils utils( this );
1381  return utils.insertVertex( x, y, atFeatureId, beforeVertex );
1382 }
1383 
1384 
1385 bool QgsVectorLayer::moveVertex( double x, double y, QgsFeatureId atFeatureId, int atVertex )
1386 {
1387  if ( !mEditBuffer || !mDataProvider )
1388  return false;
1389 
1390  QgsVectorLayerEditUtils utils( this );
1391  return utils.moveVertex( x, y, atFeatureId, atVertex );
1392 }
1393 
1394 
1395 bool QgsVectorLayer::deleteVertex( QgsFeatureId atFeatureId, int atVertex )
1396 {
1397  if ( !mEditBuffer || !mDataProvider )
1398  return false;
1399 
1400  QgsVectorLayerEditUtils utils( this );
1401  return utils.deleteVertex( atFeatureId, atVertex );
1402 }
1403 
1404 
1406 {
1408  {
1409  return false;
1410  }
1411 
1412  if ( !isEditable() )
1413  {
1414  return false;
1415  }
1416 
1417  if ( mSelectedFeatureIds.size() == 0 )
1418  return true;
1419 
1420  while ( mSelectedFeatureIds.size() > 0 )
1421  {
1422  QgsFeatureId fid = *mSelectedFeatureIds.begin();
1423  deleteFeature( fid ); // removes from selection
1424  }
1425 
1426  // invalidate cache
1427  setCacheImage( 0 );
1428  triggerRepaint();
1429  updateExtents();
1430 
1431  return true;
1432 }
1433 
1434 int QgsVectorLayer::addRing( const QList<QgsPoint>& ring )
1435 {
1436  if ( !mEditBuffer || !mDataProvider )
1437  return 6;
1438 
1439  QgsVectorLayerEditUtils utils( this );
1440  return utils.addRing( ring );
1441 }
1442 
1443 int QgsVectorLayer::addPart( const QList<QgsPoint> &points )
1444 {
1445  if ( !mEditBuffer || !mDataProvider )
1446  return 7;
1447 
1448  //number of selected features must be 1
1449 
1450  if ( mSelectedFeatureIds.size() < 1 )
1451  {
1452  QgsDebugMsg( "Number of selected features <1" );
1453  return 4;
1454  }
1455  else if ( mSelectedFeatureIds.size() > 1 )
1456  {
1457  QgsDebugMsg( "Number of selected features >1" );
1458  return 5;
1459  }
1460 
1461  QgsVectorLayerEditUtils utils( this );
1462  return utils.addPart( points, *mSelectedFeatureIds.constBegin() );
1463 }
1464 
1465 
1466 int QgsVectorLayer::translateFeature( QgsFeatureId featureId, double dx, double dy )
1467 {
1468  if ( !mEditBuffer || !mDataProvider )
1469  return -1;
1470 
1471  QgsVectorLayerEditUtils utils( this );
1472  return utils.translateFeature( featureId, dx, dy );
1473 }
1474 
1475 int QgsVectorLayer::splitParts( const QList<QgsPoint>& splitLine, bool topologicalEditing )
1476 {
1477  if ( !mEditBuffer || !mDataProvider )
1478  return -1;
1479 
1480  QgsVectorLayerEditUtils utils( this );
1481  return utils.splitParts( splitLine, topologicalEditing );
1482 }
1483 
1484 int QgsVectorLayer::splitFeatures( const QList<QgsPoint>& splitLine, bool topologicalEditing )
1485 {
1486  if ( !mEditBuffer || !mDataProvider )
1487  return -1;
1488 
1489  QgsVectorLayerEditUtils utils( this );
1490  return utils.splitFeatures( splitLine, topologicalEditing );
1491 }
1492 
1494 {
1495  if ( !hasGeometryType() )
1496  return 1;
1497 
1498  int returnValue = 0;
1499 
1500  //first test if geom really has type polygon or multipolygon
1501  if ( geom->type() != QGis::Polygon )
1502  {
1503  return 1;
1504  }
1505 
1506  //get bounding box of geom
1507  QgsRectangle geomBBox = geom->boundingBox();
1508 
1509  //get list of features that intersect this bounding box
1511  .setFilterRect( geomBBox )
1513  .setSubsetOfAttributes( QgsAttributeList() ) );
1514 
1515  QgsFeature f;
1516  while ( fit.nextFeature( f ) )
1517  {
1518  if ( ignoreFeatures.contains( f.id() ) )
1519  {
1520  continue;
1521  }
1522 
1523  //call geometry->makeDifference for each feature
1524  QgsGeometry *currentGeom = f.geometry();
1525  if ( currentGeom )
1526  {
1527  if ( geom->makeDifference( currentGeom ) != 0 )
1528  {
1529  returnValue = 2;
1530  }
1531  }
1532  }
1533 
1534  return returnValue;
1535 }
1536 
1538 {
1539  if ( !mEditBuffer || !mDataProvider )
1540  return -1;
1541 
1542  QgsVectorLayerEditUtils utils( this );
1543  return utils.addTopologicalPoints( geom );
1544 }
1545 
1547 {
1548  if ( !mEditBuffer || !mDataProvider )
1549  return -1;
1550 
1551  QgsVectorLayerEditUtils utils( this );
1552  return utils.addTopologicalPoints( p );
1553 }
1554 
1556 {
1557  return mLabel;
1558 }
1559 
1561 {
1562  return mLabel;
1563 }
1564 
1566 {
1567  mLabelOn = on;
1568 }
1569 
1571 {
1572  return mLabelOn;
1573 }
1574 
1576 {
1577  if ( !mDataProvider )
1578  {
1579  return false;
1580  }
1581 
1582  // allow editing if provider supports any of the capabilities
1584  {
1585  return false;
1586  }
1587 
1588  if ( mReadOnly )
1589  {
1590  return false;
1591  }
1592 
1593  if ( mEditBuffer )
1594  {
1595  // editing already underway
1596  return false;
1597  }
1598 
1599  mEditBuffer = new QgsVectorLayerEditBuffer( this );
1600  // forward signals
1601  connect( mEditBuffer, SIGNAL( layerModified() ), this, SLOT( invalidateSymbolCountedFlag() ) );
1602  connect( mEditBuffer, SIGNAL( layerModified() ), this, SIGNAL( layerModified() ) ); // TODO[MD]: necessary?
1603  //connect( mEditBuffer, SIGNAL( layerModified() ), this, SLOT( triggerRepaint() ) ); // TODO[MD]: works well?
1604  connect( mEditBuffer, SIGNAL( featureAdded( QgsFeatureId ) ), this, SIGNAL( featureAdded( QgsFeatureId ) ) );
1605  connect( mEditBuffer, SIGNAL( featureDeleted( QgsFeatureId ) ), this, SIGNAL( featureDeleted( QgsFeatureId ) ) );
1606  connect( mEditBuffer, SIGNAL( geometryChanged( QgsFeatureId, QgsGeometry& ) ), this, SIGNAL( geometryChanged( QgsFeatureId, QgsGeometry& ) ) );
1607  connect( mEditBuffer, SIGNAL( attributeValueChanged( QgsFeatureId, int, QVariant ) ), this, SIGNAL( attributeValueChanged( QgsFeatureId, int, QVariant ) ) );
1608  connect( mEditBuffer, SIGNAL( attributeAdded( int ) ), this, SIGNAL( attributeAdded( int ) ) );
1609  connect( mEditBuffer, SIGNAL( attributeDeleted( int ) ), this, SIGNAL( attributeDeleted( int ) ) );
1610  connect( mEditBuffer, SIGNAL( committedFeaturesAdded( QString, QgsFeatureList ) ), this, SIGNAL( committedFeaturesAdded( QString, QgsFeatureList ) ) );
1611  connect( mEditBuffer, SIGNAL( committedFeaturesRemoved( QString, QgsFeatureIds ) ), this, SIGNAL( committedFeaturesRemoved( QString, QgsFeatureIds ) ) );
1612 
1613  updateFields();
1614 
1615  emit editingStarted();
1616 
1617  return true;
1618 }
1619 
1620 bool QgsVectorLayer::readXml( const QDomNode& layer_node )
1621 {
1622  QgsDebugMsg( QString( "Datasource in QgsVectorLayer::readXml: " ) + mDataSource.toLocal8Bit().data() );
1623 
1624  //process provider key
1625  QDomNode pkeyNode = layer_node.namedItem( "provider" );
1626 
1627  if ( pkeyNode.isNull() )
1628  {
1629  mProviderKey = "";
1630  }
1631  else
1632  {
1633  QDomElement pkeyElt = pkeyNode.toElement();
1634  mProviderKey = pkeyElt.text();
1635  }
1636 
1637  // determine type of vector layer
1638  if ( ! mProviderKey.isNull() )
1639  {
1640  // if the provider string isn't empty, then we successfully
1641  // got the stored provider
1642  }
1643  else if ( mDataSource.contains( "dbname=" ) )
1644  {
1645  mProviderKey = "postgres";
1646  }
1647  else
1648  {
1649  mProviderKey = "ogr";
1650  }
1651 
1652  if ( ! setDataProvider( mProviderKey ) )
1653  {
1654  return false;
1655  }
1656 
1657  QDomElement pkeyElem = pkeyNode.toElement();
1658  if ( !pkeyElem.isNull() )
1659  {
1660  QString encodingString = pkeyElem.attribute( "encoding" );
1661  if ( !encodingString.isEmpty() )
1662  {
1663  mDataProvider->setEncoding( encodingString );
1664  }
1665  }
1666 
1667  //load vector joins
1668  if ( !mJoinBuffer )
1669  {
1671  }
1672  mJoinBuffer->readXml( layer_node );
1673 
1674  updateFields();
1675  connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( checkJoinLayerRemove( QString ) ) );
1676 
1677  QDomNode prevExpNode = layer_node.namedItem( "previewExpression" );
1678 
1679  if ( prevExpNode.isNull() )
1680  {
1681  mDisplayExpression = "";
1682  }
1683  else
1684  {
1685  QDomElement prevExpElem = prevExpNode.toElement();
1686  mDisplayExpression = prevExpElem.text();
1687  }
1688 
1689  QString errorMsg;
1690  if ( !readSymbology( layer_node, errorMsg ) )
1691  {
1692  return false;
1693  }
1694 
1695  return mValid; // should be true if read successfully
1696 
1697 } // void QgsVectorLayer::readXml
1698 
1699 
1700 bool QgsVectorLayer::setDataProvider( QString const & provider )
1701 {
1702  // XXX should I check for and possibly delete any pre-existing providers?
1703  // XXX How often will that scenario occur?
1704 
1705  mProviderKey = provider; // XXX is this necessary? Usually already set
1706  // XXX when execution gets here.
1707 
1708  //XXX - This was a dynamic cast but that kills the Windows
1709  // version big-time with an abnormal termination error
1710  mDataProvider =
1712 
1713  if ( mDataProvider )
1714  {
1715  QgsDebugMsg( "Instantiated the data provider plugin" );
1716 
1718  if ( mValid )
1719  {
1720  // TODO: Check if the provider has the capability to send fullExtentCalculated
1721  connect( mDataProvider, SIGNAL( fullExtentCalculated() ), this, SLOT( updateExtents() ) );
1722 
1723  // get and store the feature type
1725 
1727 
1728  updateFields();
1729 
1730  // look at the fields in the layer and set the primary
1731  // display field using some real fuzzy logic
1732  setDisplayField();
1733 
1734  if ( mProviderKey == "postgres" )
1735  {
1736  QgsDebugMsg( "Beautifying layer name " + name() );
1737 
1738  // adjust the display name for postgres layers
1739  QRegExp reg( "\"[^\"]+\"\\.\"([^\"]+)\"( \\([^)]+\\))?" );
1740  if ( reg.indexIn( name() ) >= 0 )
1741  {
1742  QStringList stuff = reg.capturedTexts();
1743  QString lName = stuff[1];
1744 
1745  const QMap<QString, QgsMapLayer*> &layers = QgsMapLayerRegistry::instance()->mapLayers();
1746 
1747  QMap<QString, QgsMapLayer*>::const_iterator it;
1748  for ( it = layers.constBegin(); it != layers.constEnd() && ( *it )->name() != lName; ++it )
1749  ;
1750 
1751  if ( it != layers.constEnd() && stuff.size() > 2 )
1752  {
1753  lName += "." + stuff[2].mid( 2, stuff[2].length() - 3 );
1754  }
1755 
1756  if ( !lName.isEmpty() )
1757  setLayerName( lName );
1758  }
1759 
1760  QgsDebugMsg( "Beautified layer name " + name() );
1761 
1762  // deal with unnecessary schema qualification to make v.in.ogr happy
1764  }
1765  else if ( mProviderKey == "osm" )
1766  {
1767  // make sure that the "observer" has been removed from URI to avoid crashes
1769  }
1770  else if ( provider == "ogr" )
1771  {
1772  // make sure that the /vsigzip or /vsizip is added to uri, if applicable
1774  if ( mDataSource.right( 10 ) == "|layerid=0" )
1775  mDataSource.chop( 10 );
1776  }
1777 
1778  // label
1779  mLabel = new QgsLabel( mDataProvider->fields() );
1780  mLabelOn = false;
1781  }
1782  else
1783  {
1784  QgsDebugMsg( "Invalid provider plugin " + QString( mDataSource.toUtf8() ) );
1785  return false;
1786  }
1787  }
1788  else
1789  {
1790  QgsDebugMsg( " unable to get data provider" );
1791  return false;
1792  }
1793 
1794  return true;
1795 
1796 } // QgsVectorLayer:: setDataProvider
1797 
1798 
1799 
1800 
1801 /* virtual */
1802 bool QgsVectorLayer::writeXml( QDomNode & layer_node,
1803  QDomDocument & document )
1804 {
1805  // first get the layer element so that we can append the type attribute
1806 
1807  QDomElement mapLayerNode = layer_node.toElement();
1808 
1809  if ( mapLayerNode.isNull() || ( "maplayer" != mapLayerNode.nodeName() ) )
1810  {
1811  QgsDebugMsg( "can't find <maplayer>" );
1812  return false;
1813  }
1814 
1815  mapLayerNode.setAttribute( "type", "vector" );
1816 
1817  // set the geometry type
1818  mapLayerNode.setAttribute( "geometry", QGis::vectorGeometryType( geometryType() ) );
1819 
1820  // add provider node
1821  if ( mDataProvider )
1822  {
1823  QDomElement provider = document.createElement( "provider" );
1824  provider.setAttribute( "encoding", mDataProvider->encoding() );
1825  QDomText providerText = document.createTextNode( providerType() );
1826  provider.appendChild( providerText );
1827  layer_node.appendChild( provider );
1828  }
1829 
1830  // save preview expression
1831  QDomElement prevExpElem = document.createElement( "previewExpression" );
1832  QDomText prevExpText = document.createTextNode( mDisplayExpression );
1833  prevExpElem.appendChild( prevExpText );
1834  layer_node.appendChild( prevExpElem );
1835 
1836  //save joins
1837  mJoinBuffer->writeXml( layer_node, document );
1838 
1839  // renderer specific settings
1840  QString errorMsg;
1841  return writeSymbology( layer_node, document, errorMsg );
1842 } // bool QgsVectorLayer::writeXml
1843 
1844 bool QgsVectorLayer::readSymbology( const QDomNode& node, QString& errorMessage )
1845 {
1846  Q_UNUSED( errorMessage );
1847  if ( hasGeometryType() )
1848  {
1849  // try renderer v2 first
1850  QDomElement rendererElement = node.firstChildElement( RENDERER_TAG_NAME );
1851  if ( !rendererElement.isNull() )
1852  {
1853  QgsFeatureRendererV2* r = QgsFeatureRendererV2::load( rendererElement );
1854  if ( !r )
1855  return false;
1856 
1857  setRendererV2( r );
1858  }
1859  else
1860  {
1862  if ( !r )
1864 
1865  setRendererV2( r );
1866  }
1867 
1868  // get and set the display field if it exists.
1869  QDomNode displayFieldNode = node.namedItem( "displayfield" );
1870  if ( !displayFieldNode.isNull() )
1871  {
1872  QDomElement e = displayFieldNode.toElement();
1873  setDisplayField( e.text() );
1874  }
1875 
1876  // get and set the blend mode if it exists
1877  QDomNode blendModeNode = node.namedItem( "blendMode" );
1878  if ( !blendModeNode.isNull() )
1879  {
1880  QDomElement e = blendModeNode.toElement();
1882  }
1883 
1884  // get and set the feature blend mode if it exists
1885  QDomNode featureBlendModeNode = node.namedItem( "featureBlendMode" );
1886  if ( !featureBlendModeNode.isNull() )
1887  {
1888  QDomElement e = featureBlendModeNode.toElement();
1890  }
1891 
1892  // get and set the layer transparency if it exists
1893  QDomNode layerTransparencyNode = node.namedItem( "layerTransparency" );
1894  if ( !layerTransparencyNode.isNull() )
1895  {
1896  QDomElement e = layerTransparencyNode.toElement();
1897  setLayerTransparency( e.text().toInt() );
1898  }
1899 
1900  // use scale dependent visibility flag
1901  QDomElement e = node.toElement();
1902  if ( mLabel )
1903  {
1904  mLabel->setScaleBasedVisibility( e.attribute( "scaleBasedLabelVisibilityFlag", "0" ) == "1" );
1905  mLabel->setMinScale( e.attribute( "minLabelScale", "1" ).toFloat() );
1906  mLabel->setMaxScale( e.attribute( "maxLabelScale", "100000000" ).toFloat() );
1907  }
1908 
1909  // get the simplification drawing settings
1910  mSimplifyMethod.setSimplifyHints( ( QgsVectorSimplifyMethod::SimplifyHints ) e.attribute( "simplifyDrawingHints", "1" ).toInt() );
1911  mSimplifyMethod.setThreshold( e.attribute( "simplifyDrawingTol", "1" ).toFloat() );
1912  mSimplifyMethod.setForceLocalOptimization( e.attribute( "simplifyLocal", "1" ).toInt() );
1913  mSimplifyMethod.setMaximumScale( e.attribute( "simplifyMaxScale", "1" ).toFloat() );
1914 
1915  //also restore custom properties (for labeling-ng)
1916  readCustomProperties( node, "labeling" );
1917 
1918  // Test if labeling is on or off
1919  QDomNode labelnode = node.namedItem( "label" );
1920  QDomElement element = labelnode.toElement();
1921  int hasLabelsEnabled = element.text().toInt();
1922  if ( hasLabelsEnabled < 1 )
1923  {
1924  enableLabels( false );
1925  }
1926  else
1927  {
1928  enableLabels( true );
1929  }
1930 
1931  QDomNode labelattributesnode = node.namedItem( "labelattributes" );
1932 
1933  if ( !labelattributesnode.isNull() && mLabel )
1934  {
1935  QgsDebugMsg( "calling readXML" );
1936  mLabel->readXML( labelattributesnode );
1937  }
1938 
1939  //diagram renderer and diagram layer settings
1940  delete mDiagramRenderer; mDiagramRenderer = 0;
1941  QDomElement singleCatDiagramElem = node.firstChildElement( "SingleCategoryDiagramRenderer" );
1942  if ( !singleCatDiagramElem.isNull() )
1943  {
1945  mDiagramRenderer->readXML( singleCatDiagramElem, this );
1946  }
1947  QDomElement linearDiagramElem = node.firstChildElement( "LinearlyInterpolatedDiagramRenderer" );
1948  if ( !linearDiagramElem.isNull() )
1949  {
1951  mDiagramRenderer->readXML( linearDiagramElem, this );
1952  }
1953 
1954  if ( mDiagramRenderer )
1955  {
1956  QDomElement diagramSettingsElem = node.firstChildElement( "DiagramLayerSettings" );
1957  if ( !diagramSettingsElem.isNull() )
1958  {
1960  mDiagramLayerSettings->readXML( diagramSettingsElem, this );
1961  }
1962  }
1963  }
1964 
1965  // process the attribute actions
1966  mActions->readXML( node );
1967 
1968  mEditTypes.clear();
1969  QDomNode editTypesNode = node.namedItem( "edittypes" );
1970  if ( !editTypesNode.isNull() )
1971  {
1972  QDomNodeList editTypeNodes = editTypesNode.childNodes();
1973 
1974  for ( int i = 0; i < editTypeNodes.size(); i++ )
1975  {
1976  QDomNode editTypeNode = editTypeNodes.at( i );
1977  QDomElement editTypeElement = editTypeNode.toElement();
1978 
1979  QString name = editTypeElement.attribute( "name" );
1980  if ( fieldNameIndex( name ) < -1 )
1981  continue;
1982 
1983  EditType editType = ( EditType ) editTypeElement.attribute( "type" ).toInt();
1984  mEditTypes.insert( name, editType );
1985 
1986  int editable = editTypeElement.attribute( "editable" , "1" ).toInt();
1987  mFieldEditables.insert( name, editable == 1 );
1988 
1989  int labelOnTop = editTypeElement.attribute( "labelontop" , "0" ).toInt();
1990  mLabelOnTop.insert( name, labelOnTop == 1 );
1991 
1992  switch ( editType )
1993  {
1994  case ValueMap:
1995  if ( editTypeNode.hasChildNodes() )
1996  {
1997  mValueMaps.insert( name, QMap<QString, QVariant>() );
1998 
1999  QDomNodeList valueMapNodes = editTypeNode.childNodes();
2000  for ( int j = 0; j < valueMapNodes.size(); j++ )
2001  {
2002  QDomElement value = valueMapNodes.at( j ).toElement();
2003  mValueMaps[ name ].insert( value.attribute( "key" ), value.attribute( "value" ) );
2004  }
2005  }
2006  break;
2007 
2008  case EditRange:
2009  case SliderRange:
2010  case DialRange:
2011  {
2012  QVariant min = editTypeElement.attribute( "min" );
2013  QVariant max = editTypeElement.attribute( "max" );
2014  QVariant step = editTypeElement.attribute( "step" );
2015 
2016  mRanges[ name ] = RangeData( min, max, step );
2017  }
2018  break;
2019 
2020  case CheckBox:
2021  mCheckedStates[ name ] = QPair<QString, QString>( editTypeElement.attribute( "checked" ), editTypeElement.attribute( "unchecked" ) );
2022  break;
2023 
2024  case ValueRelation:
2025  {
2026  QString id = editTypeElement.attribute( "layer" );
2027  QString key = editTypeElement.attribute( "key" );
2028  QString value = editTypeElement.attribute( "value" );
2029  bool allowNull = editTypeElement.attribute( "allowNull" ) == "true";
2030  bool orderByValue = editTypeElement.attribute( "orderByValue" ) == "true";
2031  bool allowMulti = editTypeElement.attribute( "allowMulti", "false" ) == "true";
2032 
2033  QString filterExpression;
2034  if ( editTypeElement.hasAttribute( "filterAttributeColumn" ) &&
2035  editTypeElement.hasAttribute( "filterAttributeValue" ) )
2036  {
2037  filterExpression = QString( "\"%1\"='%2'" )
2038  .arg( editTypeElement.attribute( "filterAttributeColumn" ) )
2039  .arg( editTypeElement.attribute( "filterAttributeValue" ) );
2040  }
2041  else
2042  {
2043  filterExpression = editTypeElement.attribute( "filterExpression", QString::null );
2044  }
2045 
2046  mValueRelations[ name ] = ValueRelationData( id, key, value, allowNull, orderByValue, allowMulti, filterExpression );
2047  }
2048  break;
2049 
2050  case Calendar:
2051  mDateFormats[ name ] = editTypeElement.attribute( "dateFormat" );
2052  break;
2053 
2054  case Photo:
2055  case WebView:
2056  mWidgetSize[ name ] = QSize( editTypeElement.attribute( "widgetWidth" ).toInt(), editTypeElement.attribute( "widgetHeight" ).toInt() );
2057  break;
2058 
2059  case Classification:
2060  case FileName:
2061  case Immutable:
2062  case Hidden:
2063  case LineEdit:
2064  case TextEdit:
2065  case Enumeration:
2066  case UniqueValues:
2067  case UniqueValuesEditable:
2068  case UuidGenerator:
2069  case Color:
2070  case EditorWidgetV2: // Will get a signal and read there
2071  break;
2072  }
2073  }
2074  }
2075 
2076  QDomNode editFormNode = node.namedItem( "editform" );
2077  if ( !editFormNode.isNull() )
2078  {
2079  QDomElement e = editFormNode.toElement();
2080  mEditForm = QgsProject::instance()->readPath( e.text() );
2081  }
2082 
2083  QDomNode editFormInitNode = node.namedItem( "editforminit" );
2084  if ( !editFormInitNode.isNull() )
2085  {
2086  mEditFormInit = editFormInitNode.toElement().text();
2087  }
2088 
2089  QDomNode fFSuppNode = node.namedItem( "featformsuppress" );
2090  if ( fFSuppNode.isNull() )
2091  {
2093  }
2094  else
2095  {
2096  QDomElement e = fFSuppNode.toElement();
2098  }
2099 
2100  QDomNode annotationFormNode = node.namedItem( "annotationform" );
2101  if ( !annotationFormNode.isNull() )
2102  {
2103  QDomElement e = annotationFormNode.toElement();
2105  }
2106 
2107  mAttributeAliasMap.clear();
2108  QDomNode aliasesNode = node.namedItem( "aliases" );
2109  if ( !aliasesNode.isNull() )
2110  {
2111  QDomElement aliasElem;
2112  QString name;
2113 
2114  QDomNodeList aliasNodeList = aliasesNode.toElement().elementsByTagName( "alias" );
2115  for ( int i = 0; i < aliasNodeList.size(); ++i )
2116  {
2117  aliasElem = aliasNodeList.at( i ).toElement();
2118 
2119  QString field;
2120  if ( aliasElem.hasAttribute( "field" ) )
2121  {
2122  field = aliasElem.attribute( "field" );
2123  }
2124  else
2125  {
2126  int index = aliasElem.attribute( "index" ).toInt();
2127 
2128  if ( index >= 0 && index < pendingFields().count() )
2129  field = pendingFields()[ index ].name();
2130  }
2131 
2132  mAttributeAliasMap.insert( field, aliasElem.attribute( "name" ) );
2133  }
2134  }
2135 
2136  // tab display
2137  QDomNode editorLayoutNode = node.namedItem( "editorlayout" );
2138  if ( editorLayoutNode.isNull() )
2139  {
2141  }
2142  else
2143  {
2144  if ( editorLayoutNode.toElement().text() == "uifilelayout" )
2145  {
2147  }
2148  else if ( editorLayoutNode.toElement().text() == "tablayout" )
2149  {
2151  }
2152  else
2153  {
2155  }
2156  }
2157 
2158  //Attributes excluded from WMS and WFS
2159  mExcludeAttributesWMS.clear();
2160  QDomNode excludeWMSNode = node.namedItem( "excludeAttributesWMS" );
2161  if ( !excludeWMSNode.isNull() )
2162  {
2163  QDomNodeList attributeNodeList = excludeWMSNode.toElement().elementsByTagName( "attribute" );
2164  for ( int i = 0; i < attributeNodeList.size(); ++i )
2165  {
2166  mExcludeAttributesWMS.insert( attributeNodeList.at( i ).toElement().text() );
2167  }
2168  }
2169 
2170  mExcludeAttributesWFS.clear();
2171  QDomNode excludeWFSNode = node.namedItem( "excludeAttributesWFS" );
2172  if ( !excludeWFSNode.isNull() )
2173  {
2174  QDomNodeList attributeNodeList = excludeWFSNode.toElement().elementsByTagName( "attribute" );
2175  for ( int i = 0; i < attributeNodeList.size(); ++i )
2176  {
2177  mExcludeAttributesWFS.insert( attributeNodeList.at( i ).toElement().text() );
2178  }
2179  }
2180 
2181  // tabs and groups display info
2182  mAttributeEditorElements.clear();
2183  QDomNode attributeEditorFormNode = node.namedItem( "attributeEditorForm" );
2184  QDomNodeList attributeEditorFormNodeList = attributeEditorFormNode.toElement().childNodes();
2185 
2186  for ( int i = 0; i < attributeEditorFormNodeList.size(); i++ )
2187  {
2188  QDomElement elem = attributeEditorFormNodeList.at( i ).toElement();
2189 
2190  QgsAttributeEditorElement *attributeEditorWidget = attributeEditorElementFromDomElement( elem, this );
2191  mAttributeEditorElements.append( attributeEditorWidget );
2192  }
2193 
2194  return true;
2195 }
2196 
2198 {
2199  QgsAttributeEditorElement* newElement = NULL;
2200 
2201  if ( elem.tagName() == "attributeEditorContainer" )
2202  {
2203  QgsAttributeEditorContainer* container = new QgsAttributeEditorContainer( elem.attribute( "name" ), parent );
2204 
2205  QDomNodeList childNodeList = elem.childNodes();
2206 
2207  for ( int i = 0; i < childNodeList.size(); i++ )
2208  {
2209  QDomElement childElem = childNodeList.at( i ).toElement();
2210  QgsAttributeEditorElement* myElem = attributeEditorElementFromDomElement( childElem, container );
2211  if ( myElem )
2212  container->addChildElement( myElem );
2213  }
2214 
2215  newElement = container;
2216  }
2217  else if ( elem.tagName() == "attributeEditorField" )
2218  {
2219  QString name = elem.attribute( "name" );
2220  int idx = *( dataProvider()->fieldNameMap() ).find( name );
2221  newElement = new QgsAttributeEditorField( name, idx, parent );
2222  }
2223  else if ( elem.tagName() == "attributeEditorRelation" )
2224  {
2225  // At this time, the relations are not loaded
2226  // So we only grab the id and delegate the rest to onRelationsLoaded()
2227  QString name = elem.attribute( "name" );
2228  newElement = new QgsAttributeEditorRelation( name, elem.attribute( "relation", "[None]" ), parent );
2229  }
2230  return newElement;
2231 }
2232 
2233 bool QgsVectorLayer::writeSymbology( QDomNode& node, QDomDocument& doc, QString& errorMessage ) const
2234 {
2235  Q_UNUSED( errorMessage );
2236  QDomElement mapLayerNode = node.toElement();
2237 
2238  if ( hasGeometryType() )
2239  {
2240  QDomElement rendererElement = mRendererV2->save( doc );
2241  node.appendChild( rendererElement );
2242 
2243  // use scale dependent visibility flag
2244  if ( mLabel )
2245  {
2246  mapLayerNode.setAttribute( "scaleBasedLabelVisibilityFlag", mLabel->scaleBasedVisibility() ? 1 : 0 );
2247  mapLayerNode.setAttribute( "minLabelScale", QString::number( mLabel->minScale() ) );
2248  mapLayerNode.setAttribute( "maxLabelScale", QString::number( mLabel->maxScale() ) );
2249  }
2250 
2251  // save the simplification drawing settings
2252  mapLayerNode.setAttribute( "simplifyDrawingHints", QString::number( mSimplifyMethod.simplifyHints() ) );
2253  mapLayerNode.setAttribute( "simplifyDrawingTol", QString::number( mSimplifyMethod.threshold() ) );
2254  mapLayerNode.setAttribute( "simplifyLocal", mSimplifyMethod.forceLocalOptimization() ? 1 : 0 );
2255  mapLayerNode.setAttribute( "simplifyMaxScale", QString::number( mSimplifyMethod.maximumScale() ) );
2256 
2257  //save customproperties (for labeling ng)
2258  writeCustomProperties( node, doc );
2259 
2260  // add the blend mode field
2261  QDomElement blendModeElem = doc.createElement( "blendMode" );
2262  QDomText blendModeText = doc.createTextNode( QString::number( QgsMapRenderer::getBlendModeEnum( blendMode() ) ) );
2263  blendModeElem.appendChild( blendModeText );
2264  node.appendChild( blendModeElem );
2265 
2266  // add the feature blend mode field
2267  QDomElement featureBlendModeElem = doc.createElement( "featureBlendMode" );
2268  QDomText featureBlendModeText = doc.createTextNode( QString::number( QgsMapRenderer::getBlendModeEnum( featureBlendMode() ) ) );
2269  featureBlendModeElem.appendChild( featureBlendModeText );
2270  node.appendChild( featureBlendModeElem );
2271 
2272  // add the layer transparency
2273  QDomElement layerTransparencyElem = doc.createElement( "layerTransparency" );
2274  QDomText layerTransparencyText = doc.createTextNode( QString::number( layerTransparency() ) );
2275  layerTransparencyElem.appendChild( layerTransparencyText );
2276  node.appendChild( layerTransparencyElem );
2277 
2278  // add the display field
2279  QDomElement dField = doc.createElement( "displayfield" );
2280  QDomText dFieldText = doc.createTextNode( displayField() );
2281  dField.appendChild( dFieldText );
2282  node.appendChild( dField );
2283 
2284  // add label node
2285  QDomElement labelElem = doc.createElement( "label" );
2286  QDomText labelText = doc.createTextNode( "" );
2287 
2288  if ( hasLabelsEnabled() )
2289  {
2290  labelText.setData( "1" );
2291  }
2292  else
2293  {
2294  labelText.setData( "0" );
2295  }
2296  labelElem.appendChild( labelText );
2297 
2298  node.appendChild( labelElem );
2299 
2300  // Now we get to do all that all over again for QgsLabel
2301 
2302  if ( mLabel )
2303  {
2304  QString fieldname = mLabel->labelField( QgsLabel::Text );
2305  if ( fieldname != "" )
2306  {
2307  dField = doc.createElement( "labelfield" );
2308  dFieldText = doc.createTextNode( fieldname );
2309  dField.appendChild( dFieldText );
2310  node.appendChild( dField );
2311  }
2312 
2313  mLabel->writeXML( node, doc );
2314  }
2315 
2316  if ( mDiagramRenderer )
2317  {
2318  mDiagramRenderer->writeXML( mapLayerNode, doc, this );
2319  if ( mDiagramLayerSettings )
2320  mDiagramLayerSettings->writeXML( mapLayerNode, doc, this );
2321  }
2322  }
2323 
2324  //edit types
2325  if ( mEditTypes.size() > 0 )
2326  {
2327  QDomElement editTypesElement = doc.createElement( "edittypes" );
2328 
2329  for ( QMap<QString, EditType>::const_iterator it = mEditTypes.begin(); it != mEditTypes.end(); ++it )
2330  {
2331  QDomElement editTypeElement = doc.createElement( "edittype" );
2332  editTypeElement.setAttribute( "name", it.key() );
2333  editTypeElement.setAttribute( "type", it.value() );
2334  editTypeElement.setAttribute( "editable", mFieldEditables[ it.key()] ? 1 : 0 );
2335  editTypeElement.setAttribute( "labelontop", mLabelOnTop[ it.key()] ? 1 : 0 );
2336 
2337  switch (( EditType ) it.value() )
2338  {
2339  case ValueMap:
2340  if ( mValueMaps.contains( it.key() ) )
2341  {
2342  const QMap<QString, QVariant> &map = mValueMaps[ it.key()];
2343 
2344  for ( QMap<QString, QVariant>::const_iterator vmit = map.begin(); vmit != map.end(); ++vmit )
2345  {
2346  QDomElement value = doc.createElement( "valuepair" );
2347  value.setAttribute( "key", vmit.key() );
2348  value.setAttribute( "value", vmit.value().toString() );
2349  editTypeElement.appendChild( value );
2350  }
2351  }
2352  break;
2353 
2354  case EditRange:
2355  case SliderRange:
2356  case DialRange:
2357  if ( mRanges.contains( it.key() ) )
2358  {
2359  editTypeElement.setAttribute( "min", mRanges[ it.key()].mMin.toString() );
2360  editTypeElement.setAttribute( "max", mRanges[ it.key()].mMax.toString() );
2361  editTypeElement.setAttribute( "step", mRanges[ it.key()].mStep.toString() );
2362  }
2363  break;
2364 
2365  case CheckBox:
2366  if ( mCheckedStates.contains( it.key() ) )
2367  {
2368  editTypeElement.setAttribute( "checked", mCheckedStates[ it.key()].first );
2369  editTypeElement.setAttribute( "unchecked", mCheckedStates[ it.key()].second );
2370  }
2371  break;
2372 
2373  case ValueRelation:
2374  if ( mValueRelations.contains( it.key() ) )
2375  {
2376  const ValueRelationData &data = mValueRelations[ it.key()];
2377  editTypeElement.setAttribute( "layer", data.mLayer );
2378  editTypeElement.setAttribute( "key", data.mKey );
2379  editTypeElement.setAttribute( "value", data.mValue );
2380  editTypeElement.setAttribute( "allowNull", data.mAllowNull ? "true" : "false" );
2381  editTypeElement.setAttribute( "orderByValue", data.mOrderByValue ? "true" : "false" );
2382  editTypeElement.setAttribute( "allowMulti", data.mAllowMulti ? "true" : "false" );
2383  if ( !data.mFilterExpression.isNull() )
2384  editTypeElement.setAttribute( "filterExpression", data.mFilterExpression );
2385  }
2386  break;
2387 
2388  case Calendar:
2389  editTypeElement.setAttribute( "dateFormat", mDateFormats[ it.key()] );
2390  break;
2391 
2392  case Photo:
2393  case WebView:
2394  editTypeElement.setAttribute( "widgetWidth", mWidgetSize[ it.key()].width() );
2395  editTypeElement.setAttribute( "widgetHeight", mWidgetSize[ it.key()].height() );
2396  break;
2397 
2398  case LineEdit:
2399  case UniqueValues:
2400  case UniqueValuesEditable:
2401  case Classification:
2402  case FileName:
2403  case Hidden:
2404  case TextEdit:
2405  case Enumeration:
2406  case Immutable:
2407  case UuidGenerator:
2408  case Color:
2409  case EditorWidgetV2: // Will get a signal and save there
2410  break;
2411  }
2412 
2413  editTypesElement.appendChild( editTypeElement );
2414  }
2415 
2416  node.appendChild( editTypesElement );
2417  }
2418 
2419  QDomElement efField = doc.createElement( "editform" );
2420  QDomText efText = doc.createTextNode( QgsProject::instance()->writePath( mEditForm ) );
2421  efField.appendChild( efText );
2422  node.appendChild( efField );
2423 
2424  QDomElement efiField = doc.createElement( "editforminit" );
2425  QDomText efiText = doc.createTextNode( mEditFormInit );
2426  efiField.appendChild( efiText );
2427  node.appendChild( efiField );
2428 
2429  QDomElement fFSuppElem = doc.createElement( "featformsuppress" );
2430  QDomText fFSuppText = doc.createTextNode( QString::number( featureFormSuppress() ) );
2431  fFSuppElem.appendChild( fFSuppText );
2432  node.appendChild( fFSuppElem );
2433 
2434  QDomElement afField = doc.createElement( "annotationform" );
2435  QDomText afText = doc.createTextNode( QgsProject::instance()->writePath( mAnnotationForm ) );
2436  afField.appendChild( afText );
2437  node.appendChild( afField );
2438 
2439  // tab display
2440  QDomElement editorLayoutElem = doc.createElement( "editorlayout" );
2441  switch ( mEditorLayout )
2442  {
2443  case UiFileLayout:
2444  editorLayoutElem.appendChild( doc.createTextNode( "uifilelayout" ) );
2445  break;
2446 
2447  case TabLayout:
2448  editorLayoutElem.appendChild( doc.createTextNode( "tablayout" ) );
2449  break;
2450 
2451  case GeneratedLayout:
2452  default:
2453  editorLayoutElem.appendChild( doc.createTextNode( "generatedlayout" ) );
2454  break;
2455  }
2456 
2457  node.appendChild( editorLayoutElem );
2458 
2459  //attribute aliases
2460  if ( mAttributeAliasMap.size() > 0 )
2461  {
2462  QDomElement aliasElem = doc.createElement( "aliases" );
2463  QMap<QString, QString>::const_iterator a_it = mAttributeAliasMap.constBegin();
2464  for ( ; a_it != mAttributeAliasMap.constEnd(); ++a_it )
2465  {
2466  int idx = fieldNameIndex( a_it.key() );
2467  if ( idx < 0 )
2468  continue;
2469 
2470  QDomElement aliasEntryElem = doc.createElement( "alias" );
2471  aliasEntryElem.setAttribute( "field", a_it.key() );
2472  aliasEntryElem.setAttribute( "index", idx );
2473  aliasEntryElem.setAttribute( "name", a_it.value() );
2474  aliasElem.appendChild( aliasEntryElem );
2475  }
2476  node.appendChild( aliasElem );
2477  }
2478 
2479  //exclude attributes WMS
2480  QDomElement excludeWMSElem = doc.createElement( "excludeAttributesWMS" );
2481  QSet<QString>::const_iterator attWMSIt = mExcludeAttributesWMS.constBegin();
2482  for ( ; attWMSIt != mExcludeAttributesWMS.constEnd(); ++attWMSIt )
2483  {
2484  QDomElement attrElem = doc.createElement( "attribute" );
2485  QDomText attrText = doc.createTextNode( *attWMSIt );
2486  attrElem.appendChild( attrText );
2487  excludeWMSElem.appendChild( attrElem );
2488  }
2489  node.appendChild( excludeWMSElem );
2490 
2491  //exclude attributes WFS
2492  QDomElement excludeWFSElem = doc.createElement( "excludeAttributesWFS" );
2493  QSet<QString>::const_iterator attWFSIt = mExcludeAttributesWFS.constBegin();
2494  for ( ; attWFSIt != mExcludeAttributesWFS.constEnd(); ++attWFSIt )
2495  {
2496  QDomElement attrElem = doc.createElement( "attribute" );
2497  QDomText attrText = doc.createTextNode( *attWFSIt );
2498  attrElem.appendChild( attrText );
2499  excludeWFSElem.appendChild( attrElem );
2500  }
2501  node.appendChild( excludeWFSElem );
2502 
2503  // tabs and groups of edit form
2504  if ( mAttributeEditorElements.size() > 0 )
2505  {
2506  QDomElement tabsElem = doc.createElement( "attributeEditorForm" );
2507 
2508  for ( QList< QgsAttributeEditorElement* >::const_iterator it = mAttributeEditorElements.begin(); it != mAttributeEditorElements.end(); ++it )
2509  {
2510  QDomElement attributeEditorWidgetElem = ( *it )->toDomElement( doc );
2511  tabsElem.appendChild( attributeEditorWidgetElem );
2512  }
2513 
2514  node.appendChild( tabsElem );
2515  }
2516 
2517  // add attribute actions
2518  mActions->writeXML( node, doc );
2519 
2520  return true;
2521 }
2522 
2523 bool QgsVectorLayer::readSld( const QDomNode& node, QString& errorMessage )
2524 {
2525  // get the Name element
2526  QDomElement nameElem = node.firstChildElement( "Name" );
2527  if ( nameElem.isNull() )
2528  {
2529  errorMessage = "Warning: Name element not found within NamedLayer while it's required.";
2530  }
2531 
2532  if ( hasGeometryType() )
2533  {
2534  QgsFeatureRendererV2* r = QgsFeatureRendererV2::loadSld( node, geometryType(), errorMessage );
2535  if ( !r )
2536  return false;
2537 
2538  setRendererV2( r );
2539 
2540  // labeling
2541  readSldLabeling( node );
2542  }
2543  return true;
2544 }
2545 
2546 
2547 bool QgsVectorLayer::writeSld( QDomNode& node, QDomDocument& doc, QString& errorMessage ) const
2548 {
2549  Q_UNUSED( errorMessage );
2550 
2551  // store the Name element
2552  QDomElement nameNode = doc.createElement( "se:Name" );
2553  nameNode.appendChild( doc.createTextNode( name() ) );
2554  node.appendChild( nameNode );
2555 
2556  if ( hasGeometryType() )
2557  {
2558  node.appendChild( mRendererV2->writeSld( doc, *this ) );
2559  }
2560  return true;
2561 }
2562 
2563 
2565 {
2566  if ( !mEditBuffer || !mDataProvider )
2567  {
2568  return false;
2569  }
2570 
2571  updateExtents();
2572 
2573  return mEditBuffer->changeGeometry( fid, geom );
2574 }
2575 
2576 
2577 bool QgsVectorLayer::changeAttributeValue( QgsFeatureId fid, int field, QVariant value, bool emitSignal )
2578 {
2579  Q_UNUSED( emitSignal );
2580  return changeAttributeValue( fid, field, value );
2581 }
2582 
2583 bool QgsVectorLayer::changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue )
2584 {
2585  if ( !mEditBuffer || !mDataProvider )
2586  return false;
2587 
2588  return mEditBuffer->changeAttributeValue( fid, field, newValue, oldValue );
2589 }
2590 
2592 {
2593  if ( !mEditBuffer || !mDataProvider )
2594  return false;
2595 
2596  return mEditBuffer->addAttribute( field );
2597 }
2598 
2599 void QgsVectorLayer::addAttributeAlias( int attIndex, QString aliasString )
2600 {
2601  if ( attIndex < 0 || attIndex >= pendingFields().count() )
2602  return;
2603 
2604  QString name = pendingFields()[ attIndex ].name();
2605 
2606  mAttributeAliasMap.insert( name, aliasString );
2607  emit layerModified(); // TODO[MD]: should have a different signal?
2608 }
2609 
2611 {
2612  mAttributeEditorElements.append( data );
2613 }
2614 
2615 const QString QgsVectorLayer::editorWidgetV2( int fieldIdx )
2616 {
2617  return mEditorWidgetV2Types.value( fieldIdx );
2618 }
2619 
2621 {
2622  return mEditorWidgetV2Configs.value( fieldIdx );
2623 }
2624 
2625 QString QgsVectorLayer::attributeAlias( int attributeIndex ) const
2626 {
2627  if ( attributeIndex < 0 || attributeIndex >= pendingFields().count() )
2628  return "";
2629 
2630  QString name = pendingFields()[ attributeIndex ].name();
2631 
2632  return mAttributeAliasMap.value( name, "" );
2633 }
2634 
2635 QString QgsVectorLayer::attributeDisplayName( int attributeIndex ) const
2636 {
2637  QString displayName = attributeAlias( attributeIndex );
2638  if ( displayName.isEmpty() )
2639  {
2640  const QgsFields& fields = pendingFields();
2641  if ( attributeIndex >= 0 && attributeIndex < fields.count() )
2642  {
2643  displayName = fields[attributeIndex].name();
2644  }
2645  }
2646  return displayName;
2647 }
2648 
2650 {
2651  if ( !mEditBuffer || !mDataProvider )
2652  return false;
2653 
2654  return mEditBuffer->deleteAttribute( index );
2655 }
2656 
2657 bool QgsVectorLayer::deleteAttributes( QList<int> attrs )
2658 {
2659  bool deleted = false;
2660 
2661  // Remove multiple occurences of same attribute
2662  attrs = attrs.toSet().toList();
2663 
2664  qSort( attrs.begin(), attrs.end(), qGreater<int>() );
2665 
2666  foreach ( int attr, attrs )
2667  {
2668  if ( deleteAttribute( attr ) )
2669  {
2670  deleted = true;
2671  }
2672  }
2673 
2674  return deleted;
2675 }
2676 
2678 {
2679  if ( !mEditBuffer )
2680  return false;
2681 
2682  bool res = mEditBuffer->deleteFeature( fid );
2683  if ( res )
2684  mSelectedFeatureIds.remove( fid ); // remove it from selection
2685 
2686  updateExtents();
2687 
2688  return res;
2689 }
2690 
2692 {
2693  return mUpdatedFields;
2694 }
2695 
2697 {
2698  QgsAttributeList lst;
2699  for ( int i = 0; i < mUpdatedFields.count(); ++i )
2700  lst.append( i );
2701  return lst;
2702 }
2703 
2705 {
2706  QgsAttributeList pkAttributesList;
2707 
2708  QgsAttributeList providerIndexes = mDataProvider->pkAttributeIndexes();
2709  for ( int i = 0; i < mUpdatedFields.count(); ++i )
2710  {
2712  providerIndexes.contains( mUpdatedFields.fieldOriginIndex( i ) ) )
2713  pkAttributesList << i;
2714  }
2715 
2716  return pkAttributesList;
2717 }
2718 
2720 {
2721  return mDataProvider->featureCount() +
2723 }
2724 
2726 {
2727  mCommitErrors.clear();
2728 
2729  if ( !mDataProvider )
2730  {
2731  mCommitErrors << tr( "ERROR: no provider" );
2732  return false;
2733  }
2734 
2735  if ( !mEditBuffer )
2736  {
2737  mCommitErrors << tr( "ERROR: layer not editable" );
2738  return false;
2739  }
2740 
2741  emit beforeCommitChanges();
2742 
2743  bool success = mEditBuffer->commitChanges( mCommitErrors );
2744 
2745  if ( success )
2746  {
2747  delete mEditBuffer;
2748  mEditBuffer = 0;
2749  undoStack()->clear();
2750  emit editingStopped();
2751  }
2752  else
2753  {
2754  QgsMessageLog::logMessage( tr( "Commit errors:\n %1" ).arg( mCommitErrors.join( "\n " ) ) );
2755  }
2756 
2757  if ( mCache )
2758  {
2760  }
2761 
2762  updateFields();
2764 
2765  //clear the cache image so markers don't appear anymore on next draw
2766  setCacheImage( 0 );
2767 
2768  return success;
2769 }
2770 
2771 const QStringList &QgsVectorLayer::commitErrors()
2772 {
2773  return mCommitErrors;
2774 }
2775 
2776 bool QgsVectorLayer::rollBack( bool deleteBuffer )
2777 {
2778  if ( !mEditBuffer )
2779  {
2780  return false;
2781  }
2782 
2783  emit beforeRollBack();
2784 
2785  mEditBuffer->rollBack();
2786 
2787  if ( isModified() )
2788  {
2789  // new undo stack roll back method
2790  // old method of calling every undo could cause many canvas refreshes
2791  undoStack()->setIndex( 0 );
2792  }
2793 
2794  updateFields();
2795 
2796  if ( deleteBuffer )
2797  {
2798  delete mEditBuffer;
2799  mEditBuffer = 0;
2800  undoStack()->clear();
2801  }
2802  emit editingStopped();
2803 
2804  if ( mCache )
2805  {
2807  }
2808 
2809  // invalidate the cache so the layer updates properly to show its original
2810  // after the rollback
2811  setCacheImage( 0 );
2812  return true;
2813 }
2814 
2816 {
2817  QgsFeatureIds deselectedFeatures = mSelectedFeatureIds - ids;
2818 
2819  mSelectedFeatureIds = ids;
2820 
2821  // invalidate cache
2822  setCacheImage( 0 );
2823 
2824  emit selectionChanged( ids, deselectedFeatures, true );
2825 }
2826 
2828 {
2829  return mSelectedFeatureIds.size();
2830 }
2831 
2833 {
2834  return mSelectedFeatureIds;
2835 }
2836 
2837 
2839 {
2840  QgsFeatureList features;
2841 
2842  QgsFeatureRequest req;
2843  if ( geometryType() == QGis::NoGeometry )
2845 
2846  foreach ( QgsFeatureId fid, mSelectedFeatureIds )
2847  {
2848  features.push_back( QgsFeature() );
2849  getFeatures( req.setFilterFid( fid ) ).nextFeature( features.back() );
2850  }
2851 
2852  return features;
2853 }
2854 
2855 bool QgsVectorLayer::addFeatures( QgsFeatureList features, bool makeSelected )
2856 {
2857  if ( !mEditBuffer || !mDataProvider )
2858  return false;
2859 
2860  bool res = mEditBuffer->addFeatures( features );
2861 
2862  if ( makeSelected )
2863  {
2864  QgsFeatureIds ids;
2865 
2866  for ( QgsFeatureList::iterator iter = features.begin(); iter != features.end(); ++iter )
2867  ids << iter->id();
2868 
2869  setSelectedFeatures( ids );
2870  }
2871 
2872  updateExtents();
2873 
2874  return res;
2875 }
2876 
2877 
2878 bool QgsVectorLayer::snapPoint( QgsPoint& point, double tolerance )
2879 {
2880  if ( !hasGeometryType() )
2881  return false;
2882 
2883  QMultiMap<double, QgsSnappingResult> snapResults;
2884  int result = snapWithContext( point, tolerance, snapResults, QgsSnapper::SnapToVertex );
2885 
2886  if ( result != 0 )
2887  {
2888  return false;
2889  }
2890 
2891  if ( snapResults.size() < 1 )
2892  {
2893  return false;
2894  }
2895 
2896  QMultiMap<double, QgsSnappingResult>::const_iterator snap_it = snapResults.constBegin();
2897  point.setX( snap_it.value().snappedVertex.x() );
2898  point.setY( snap_it.value().snappedVertex.y() );
2899  return true;
2900 }
2901 
2902 
2903 int QgsVectorLayer::snapWithContext( const QgsPoint& startPoint, double snappingTolerance,
2904  QMultiMap<double, QgsSnappingResult>& snappingResults,
2905  QgsSnapper::SnappingType snap_to )
2906 {
2907  if ( !hasGeometryType() )
2908  return 1;
2909 
2910  if ( snappingTolerance <= 0 || !mDataProvider )
2911  {
2912  return 1;
2913  }
2914 
2915  QList<QgsFeature> featureList;
2916  QgsRectangle searchRect( startPoint.x() - snappingTolerance, startPoint.y() - snappingTolerance,
2917  startPoint.x() + snappingTolerance, startPoint.y() + snappingTolerance );
2918  double sqrSnappingTolerance = snappingTolerance * snappingTolerance;
2919 
2920  int n = 0;
2921  QgsFeature f;
2922 
2923  if ( mCache->cachedGeometriesRect().contains( searchRect ) )
2924  {
2925  QgsGeometryMap& cachedGeometries = mCache->cachedGeometries();
2926  for ( QgsGeometryMap::iterator it = cachedGeometries.begin(); it != cachedGeometries.end() ; ++it )
2927  {
2928  QgsGeometry* g = &( it.value() );
2929  if ( g->boundingBox().intersects( searchRect ) )
2930  {
2931  snapToGeometry( startPoint, it.key(), g, sqrSnappingTolerance, snappingResults, snap_to );
2932  ++n;
2933  }
2934  }
2935  }
2936  else
2937  {
2938  // snapping outside cached area
2939 
2941  .setFilterRect( searchRect )
2943  .setSubsetOfAttributes( QgsAttributeList() ) );
2944 
2945  while ( fit.nextFeature( f ) )
2946  {
2947  snapToGeometry( startPoint, f.id(), f.geometry(), sqrSnappingTolerance, snappingResults, snap_to );
2948  ++n;
2949  }
2950  }
2951 
2952  return n == 0 ? 2 : 0;
2953 }
2954 
2956  QgsFeatureId featureId,
2957  QgsGeometry* geom,
2958  double sqrSnappingTolerance,
2959  QMultiMap<double, QgsSnappingResult>& snappingResults,
2960  QgsSnapper::SnappingType snap_to ) const
2961 {
2962  if ( !geom )
2963  {
2964  return;
2965  }
2966 
2967  int atVertex, beforeVertex, afterVertex;
2968  double sqrDistVertexSnap, sqrDistSegmentSnap;
2969  QgsPoint snappedPoint;
2970  QgsSnappingResult snappingResultVertex;
2971  QgsSnappingResult snappingResultSegment;
2972 
2973  if ( snap_to == QgsSnapper::SnapToVertex || snap_to == QgsSnapper::SnapToVertexAndSegment )
2974  {
2975  snappedPoint = geom->closestVertex( startPoint, atVertex, beforeVertex, afterVertex, sqrDistVertexSnap );
2976  if ( sqrDistVertexSnap < sqrSnappingTolerance )
2977  {
2978  snappingResultVertex.snappedVertex = snappedPoint;
2979  snappingResultVertex.snappedVertexNr = atVertex;
2980  snappingResultVertex.beforeVertexNr = beforeVertex;
2981  if ( beforeVertex != -1 ) // make sure the vertex is valid
2982  {
2983  snappingResultVertex.beforeVertex = geom->vertexAt( beforeVertex );
2984  }
2985  snappingResultVertex.afterVertexNr = afterVertex;
2986  if ( afterVertex != -1 ) // make sure the vertex is valid
2987  {
2988  snappingResultVertex.afterVertex = geom->vertexAt( afterVertex );
2989  }
2990  snappingResultVertex.snappedAtGeometry = featureId;
2991  snappingResultVertex.layer = this;
2992  snappingResults.insert( sqrt( sqrDistVertexSnap ), snappingResultVertex );
2993  return;
2994  }
2995  }
2996  if ( snap_to == QgsSnapper::SnapToSegment || snap_to == QgsSnapper::SnapToVertexAndSegment ) // snap to segment
2997  {
2998  if ( geometryType() != QGis::Point ) // cannot snap to segment for points/multipoints
2999  {
3000  sqrDistSegmentSnap = geom->closestSegmentWithContext( startPoint, snappedPoint, afterVertex, NULL, crs().geographicFlag() ? 1e-12 : 1e-8 );
3001 
3002  if ( sqrDistSegmentSnap < sqrSnappingTolerance )
3003  {
3004  snappingResultSegment.snappedVertex = snappedPoint;
3005  snappingResultSegment.snappedVertexNr = -1;
3006  snappingResultSegment.beforeVertexNr = afterVertex - 1;
3007  snappingResultSegment.afterVertexNr = afterVertex;
3008  snappingResultSegment.snappedAtGeometry = featureId;
3009  snappingResultSegment.beforeVertex = geom->vertexAt( afterVertex - 1 );
3010  snappingResultSegment.afterVertex = geom->vertexAt( afterVertex );
3011  snappingResultSegment.layer = this;
3012  snappingResults.insert( sqrt( sqrDistSegmentSnap ), snappingResultSegment );
3013  }
3014  }
3015  }
3016 }
3017 
3018 int QgsVectorLayer::insertSegmentVerticesForSnap( const QList<QgsSnappingResult>& snapResults )
3019 {
3020  QgsVectorLayerEditUtils utils( this );
3021  return utils.insertSegmentVerticesForSnap( snapResults );
3022 }
3023 
3024 
3026 {
3027  QSettings settings;
3028  QString markerTypeString = settings.value( "/qgis/digitizing/marker_style", "Cross" ).toString();
3029  if ( markerTypeString == "Cross" )
3030  {
3031  return QgsVectorLayer::Cross;
3032  }
3033  else if ( markerTypeString == "SemiTransparentCircle" )
3034  {
3036  }
3037  else
3038  {
3039  return QgsVectorLayer::NoMarker;
3040  }
3041 }
3042 
3044 {
3045  QSettings settings;
3046  return settings.value( "/qgis/digitizing/marker_size", 3 ).toInt();
3047 }
3048 
3049 
3050 
3052 {
3053  QgsDebugMsg( "----- Computing Coordinate System" );
3054 
3055  //
3056  // Get the layers project info and set up the QgsCoordinateTransform
3057  // for this layer
3058  //
3059 
3060  if ( hasGeometryType() )
3061  {
3062  // get CRS directly from provider
3063  setCrs( mDataProvider->crs() );
3064  }
3065  else
3066  {
3068  }
3069 }
3070 
3071 
3072 const QString QgsVectorLayer::displayField() const
3073 {
3074  return mDisplayField;
3075 }
3076 
3077 void QgsVectorLayer::setDisplayExpression( const QString &displayExpression )
3078 {
3080 }
3081 
3083 {
3084  return mDisplayExpression;
3085 }
3086 
3088 {
3089  return ( mEditBuffer && mDataProvider );
3090 }
3091 
3093 {
3094  return mReadOnly;
3095 }
3096 
3097 bool QgsVectorLayer::setReadOnly( bool readonly )
3098 {
3099  // exit if the layer is in editing mode
3100  if ( readonly && mEditBuffer )
3101  return false;
3102 
3103  mReadOnly = readonly;
3104  return true;
3105 }
3106 
3108 {
3109  return mEditBuffer && mEditBuffer->isModified();
3110 }
3111 
3113 {
3114  const QgsFields &fields = pendingFields();
3115  if ( idx >= 0 && idx < fields.count() && mEditTypes.contains( fields[idx].name() ) )
3116  return mEditTypes[ fields[idx].name()];
3117  else
3118  return LineEdit;
3119 }
3120 
3122 {
3123  const QgsFields &fields = pendingFields();
3124  if ( idx >= 0 && idx < fields.count() )
3125  mEditTypes[ fields[idx].name()] = type;
3126 }
3127 
3129 {
3130  return mEditorLayout;
3131 }
3132 
3134 {
3136 }
3137 
3138 void QgsVectorLayer::setEditorWidgetV2( int attrIdx, const QString& widgetType )
3139 {
3140  mEditorWidgetV2Types[ attrIdx ] = widgetType;
3141 }
3142 
3143 void QgsVectorLayer::setEditorWidgetV2Config( int attrIdx, const QMap<QString, QVariant>& config )
3144 {
3145  mEditorWidgetV2Configs[ attrIdx ] = config;
3146 }
3147 
3149 {
3150  return mEditForm;
3151 }
3152 
3154 {
3155  mEditForm = ui;
3156 }
3157 
3158 void QgsVectorLayer::setAnnotationForm( const QString& ui )
3159 {
3160  mAnnotationForm = ui;
3161 }
3162 
3164 {
3165  return mEditFormInit;
3166 }
3167 
3168 void QgsVectorLayer::setEditFormInit( QString function )
3169 {
3170  mEditFormInit = function;
3171 }
3172 
3173 QMap< QString, QVariant > &QgsVectorLayer::valueMap( int idx )
3174 {
3175  const QgsFields &fields = pendingFields();
3176 
3177  // FIXME: throw an exception!?
3178  static QMap< QString, QVariant > invalidMap;
3179  if ( idx < 0 || idx >= fields.count() )
3180  {
3181  QgsDebugMsg( QString( "field %1 not found" ).arg( idx ) );
3182  return invalidMap;
3183  }
3184  QString fieldName = fields[idx].name();
3185 
3186  if ( !mValueMaps.contains( fieldName ) )
3187  mValueMaps[fieldName] = QMap<QString, QVariant>();
3188 
3189  return mValueMaps[fieldName];
3190 }
3191 
3193 {
3194  const QgsFields &fields = pendingFields();
3195 
3196  // FIXME: throw an exception!?
3197  static QgsVectorLayer::RangeData invalidRange;
3198  if ( idx < 0 || idx >= fields.count() )
3199  {
3200  QgsDebugMsg( QString( "field %1 not found" ).arg( idx ) );
3201  return invalidRange;
3202  }
3203  QString fieldName = fields[idx].name();
3204 
3205  if ( !mRanges.contains( fieldName ) )
3206  mRanges[fieldName] = RangeData();
3207 
3208  return mRanges[fieldName];
3209 }
3210 
3211 QString &QgsVectorLayer::dateFormat( int idx )
3212 {
3213  const QgsFields &fields = pendingFields();
3214 
3215  QString fieldName = fields[idx].name();
3216 
3217  if ( !mDateFormats.contains( fieldName ) )
3218  mDateFormats[fieldName] = "yyyy-MM-dd";
3219 
3220  return mDateFormats[fieldName];
3221 }
3222 
3224 {
3225  const QgsFields &fields = pendingFields();
3226 
3227  QString fieldName = fields[idx].name();
3228 
3229  if ( !mWidgetSize.contains( fieldName ) )
3230  mWidgetSize[fieldName] = QSize( 0, 0 );
3231 
3232  return mWidgetSize[fieldName];
3233 }
3234 
3236 {
3237  const QgsFields &fields = pendingFields();
3238  if ( idx >= 0 && idx < fields.count() )
3239  {
3241  return false;
3242  return mFieldEditables.value( fields[idx].name(), true );
3243  }
3244  else
3245  return true;
3246 }
3247 
3249 {
3250  const QgsFields &fields = pendingFields();
3251  if ( idx >= 0 && idx < fields.count() )
3252  return mLabelOnTop.value( fields[idx].name(), false );
3253  else
3254  return false;
3255 }
3256 
3257 void QgsVectorLayer::setFieldEditable( int idx, bool editable )
3258 {
3259  const QgsFields &fields = pendingFields();
3260  if ( idx >= 0 && idx < fields.count() )
3261  mFieldEditables[ fields[idx].name()] = editable;
3262 }
3263 
3264 void QgsVectorLayer::setLabelOnTop( int idx, bool onTop )
3265 {
3266  const QgsFields &fields = pendingFields();
3267  if ( idx >= 0 && idx < fields.count() )
3268  mLabelOnTop[ fields[idx].name()] = onTop;
3269 }
3270 
3272 {
3273  return mRendererV2;
3274 }
3275 
3277 {
3278  if ( !hasGeometryType() )
3279  return;
3280 
3281  if ( r != mRendererV2 )
3282  {
3283  delete mRendererV2;
3284  mRendererV2 = r;
3285  mSymbolFeatureCounted = false;
3286  mSymbolFeatureCountMap.clear();
3287 
3288  emit rendererChanged();
3289  }
3290 }
3291 
3292 
3293 
3295 {
3296  undoStack()->beginMacro( text );
3297  emit editCommandStarted( text );
3298 }
3299 
3301 {
3302  undoStack()->endMacro();
3303  emit editCommandEnded();
3304 }
3305 
3307 {
3308  undoStack()->endMacro();
3309  undoStack()->undo();
3310  emit editCommandDestroyed();
3311 }
3312 
3313 
3314 void QgsVectorLayer::setCheckedState( int idx, QString checked, QString unchecked )
3315 {
3316  const QgsFields &fields = pendingFields();
3317  if ( idx >= 0 && idx < fields.count() )
3318  mCheckedStates[ fields[idx].name()] = QPair<QString, QString>( checked, unchecked );
3319 }
3320 
3321 QPair<QString, QString> QgsVectorLayer::checkedState( int idx )
3322 {
3323  const QgsFields &fields = pendingFields();
3324  if ( idx >= 0 && idx < fields.count() && mCheckedStates.contains( fields[idx].name() ) )
3325  return mCheckedStates[ fields[idx].name()];
3326  else
3327  return QPair<QString, QString>( "1", "0" );
3328 }
3329 
3330 int QgsVectorLayer::fieldNameIndex( const QString& fieldName ) const
3331 {
3332  const QgsFields &theFields = pendingFields();
3333 
3334  for ( int idx = 0; idx < theFields.count(); ++idx )
3335  {
3336  if ( QString::compare( theFields[idx].name(), fieldName, Qt::CaseInsensitive ) == 0 )
3337  {
3338  return idx;
3339  }
3340  }
3341  return -1;
3342 }
3343 
3345 {
3346  mJoinBuffer->addJoin( joinInfo );
3347  updateFields();
3348 }
3349 
3350 void QgsVectorLayer::checkJoinLayerRemove( QString theLayerId )
3351 {
3352  removeJoin( theLayerId );
3353 }
3354 
3355 void QgsVectorLayer::removeJoin( const QString& joinLayerId )
3356 {
3357  mJoinBuffer->removeJoin( joinLayerId );
3358  updateFields();
3359 }
3360 
3361 const QList< QgsVectorJoinInfo >& QgsVectorLayer::vectorJoins() const
3362 {
3363  return mJoinBuffer->vectorJoins();
3364 }
3365 
3367 {
3368  if ( !mDataProvider )
3369  return;
3370 
3372 
3373  // added / removed fields
3374  if ( mEditBuffer )
3376 
3377  // joined fields
3380 
3381  emit updatedFields();
3382 }
3383 
3384 
3386 {
3387  if ( mJoinBuffer->containsJoins() )
3388  {
3390  }
3391 }
3392 
3393 void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int limit )
3394 {
3395  uniqueValues.clear();
3396  if ( !mDataProvider )
3397  {
3398  return;
3399  }
3400 
3402 
3403  if ( origin == QgsFields::OriginProvider ) //a provider field
3404  {
3405  return mDataProvider->uniqueValues( index, uniqueValues, limit );
3406  }
3407  else if ( origin == QgsFields::OriginJoin )
3408  {
3409  int sourceLayerIndex;
3410  const QgsVectorJoinInfo* join = mJoinBuffer->joinForFieldIndex( index, mUpdatedFields, sourceLayerIndex );
3411  Q_ASSERT( join );
3412 
3414  Q_ASSERT( vl );
3415 
3416  return vl->dataProvider()->uniqueValues( sourceLayerIndex, uniqueValues, limit );
3417  }
3418  else if ( origin == QgsFields::OriginEdit )
3419  {
3420  // the layer is editable, but in certain cases it can still be avoided going through all features
3421  if ( mEditBuffer->mDeletedFeatureIds.isEmpty() && mEditBuffer->mAddedFeatures.isEmpty() && !mEditBuffer->mDeletedAttributeIds.contains( index ) && mEditBuffer->mChangedAttributeValues.isEmpty() )
3422  {
3423  return mDataProvider->uniqueValues( index, uniqueValues, limit );
3424  }
3425 
3426  // we need to go through each feature
3427  QgsAttributeList attList;
3428  attList << index;
3429 
3431  .setFlags( QgsFeatureRequest::NoGeometry )
3432  .setSubsetOfAttributes( attList ) );
3433 
3434  QgsFeature f;
3435  QVariant currentValue;
3436  QHash<QString, QVariant> val;
3437  while ( fit.nextFeature( f ) )
3438  {
3439  currentValue = f.attribute( index );
3440  val.insert( currentValue.toString(), currentValue );
3441  if ( limit >= 0 && val.size() >= limit )
3442  {
3443  break;
3444  }
3445  }
3446 
3447  uniqueValues = val.values();
3448  return;
3449  }
3450 
3451  Q_ASSERT_X( false, "QgsVectorLayer::uniqueValues()", "Unknown source of the field!" );
3452 }
3453 
3455 {
3456  if ( !mDataProvider )
3457  {
3458  return QVariant();
3459  }
3460 
3462 
3463  if ( origin == QgsFields::OriginProvider ) //a provider field
3464  {
3465  return mDataProvider->minimumValue( index );
3466  }
3467  else if ( origin == QgsFields::OriginJoin )
3468  {
3469  int sourceLayerIndex;
3470  const QgsVectorJoinInfo* join = mJoinBuffer->joinForFieldIndex( index, mUpdatedFields, sourceLayerIndex );
3471  Q_ASSERT( join );
3472 
3474  Q_ASSERT( vl );
3475 
3476  return vl->minimumValue( sourceLayerIndex );
3477  }
3478  else if ( origin == QgsFields::OriginEdit )
3479  {
3480  // the layer is editable, but in certain cases it can still be avoided going through all features
3481  if ( mEditBuffer->mDeletedFeatureIds.isEmpty() && mEditBuffer->mAddedFeatures.isEmpty() && !mEditBuffer->mDeletedAttributeIds.contains( index ) && mEditBuffer->mChangedAttributeValues.isEmpty() )
3482  {
3483  return mDataProvider->minimumValue( index );
3484  }
3485 
3486  // we need to go through each feature
3487  QgsAttributeList attList;
3488  attList << index;
3489 
3491  .setFlags( QgsFeatureRequest::NoGeometry )
3492  .setSubsetOfAttributes( attList ) );
3493 
3494  QgsFeature f;
3496  double currentValue = 0;
3497  while ( fit.nextFeature( f ) )
3498  {
3499  currentValue = f.attribute( index ).toDouble();
3500  if ( currentValue < minimumValue )
3501  {
3502  minimumValue = currentValue;
3503  }
3504  }
3505  return QVariant( minimumValue );
3506  }
3507 
3508  Q_ASSERT_X( false, "QgsVectorLayer::minimumValue()", "Unknown source of the field!" );
3509  return QVariant();
3510 }
3511 
3513 {
3514  if ( !mDataProvider )
3515  {
3516  return QVariant();
3517  }
3518 
3520 
3521  if ( origin == QgsFields::OriginProvider ) //a provider field
3522  {
3523  return mDataProvider->maximumValue( index );
3524  }
3525  else if ( origin == QgsFields::OriginJoin )
3526  {
3527  int sourceLayerIndex;
3528  const QgsVectorJoinInfo* join = mJoinBuffer->joinForFieldIndex( index, mUpdatedFields, sourceLayerIndex );
3529  Q_ASSERT( join );
3530 
3532  Q_ASSERT( vl );
3533 
3534  return vl->maximumValue( sourceLayerIndex );
3535  }
3536  else if ( origin == QgsFields::OriginEdit )
3537  {
3538  // the layer is editable, but in certain cases it can still be avoided going through all features
3539  if ( mEditBuffer->mDeletedFeatureIds.isEmpty() &&
3540  mEditBuffer->mAddedFeatures.isEmpty() &&
3541  !mEditBuffer->mDeletedAttributeIds.contains( index ) &&
3543  {
3544  return mDataProvider->maximumValue( index );
3545  }
3546 
3547  // we need to go through each feature
3548  QgsAttributeList attList;
3549  attList << index;
3550 
3552  .setFlags( QgsFeatureRequest::NoGeometry )
3553  .setSubsetOfAttributes( attList ) );
3554 
3555  QgsFeature f;
3557  double currentValue = 0;
3558  while ( fit.nextFeature( f ) )
3559  {
3560  currentValue = f.attribute( index ).toDouble();
3561  if ( currentValue > maximumValue )
3562  {
3563  maximumValue = currentValue;
3564  }
3565  }
3566  return QVariant( maximumValue );
3567  }
3568 
3569  Q_ASSERT_X( false, "QgsVectorLayer::maximumValue()", "Unknown source of the field!" );
3570  return QVariant();
3571 }
3572 
3574 void QgsVectorLayer::setFeatureBlendMode( const QPainter::CompositionMode &featureBlendMode )
3575 {
3577  emit featureBlendModeChanged( featureBlendMode );
3578 }
3579 
3581 QPainter::CompositionMode QgsVectorLayer::featureBlendMode() const
3582 {
3583  return mFeatureBlendMode;
3584 }
3585 
3587 void QgsVectorLayer::setLayerTransparency( int layerTransparency )
3588 {
3590  emit layerTransparencyChanged( layerTransparency );
3591 }
3592 
3595 {
3596  return mLayerTransparency;
3597 }
3598 
3600 {
3601  mRendererV2->stopRender( rendererContext );
3602  if ( selRenderer )
3603  {
3604  selRenderer->stopRender( rendererContext );
3605  delete selRenderer;
3606  }
3607 }
3608 
3609 void QgsVectorLayer::prepareLabelingAndDiagrams( QgsRenderContext& rendererContext, QgsAttributeList& attributes, bool& labeling )
3610 {
3611  if ( !rendererContext.labelingEngine() )
3612  return;
3613 
3614  QSet<int> attrIndex;
3615  if ( rendererContext.labelingEngine()->prepareLayer( this, attrIndex, rendererContext ) )
3616  {
3617  QSet<int>::const_iterator attIt = attrIndex.constBegin();
3618  for ( ; attIt != attrIndex.constEnd(); ++attIt )
3619  {
3620  if ( !attributes.contains( *attIt ) )
3621  {
3622  attributes << *attIt;
3623  }
3624  }
3625  labeling = true;
3626  }
3627 
3628  if ( labeling )
3629  {
3630  QgsPalLayerSettings& palyr = rendererContext.labelingEngine()->layer( this->id() );
3631 
3632  // see if feature count limit is set for labeling
3633  if ( palyr.limitNumLabels && palyr.maxNumLabels > 0 )
3634  {
3636  .setFilterRect( rendererContext.extent() )
3637  .setSubsetOfAttributes( QgsAttributeList() ) );
3638 
3639  // total number of features that may be labeled
3640  QgsFeature f;
3641  int nFeatsToLabel = 0;
3642  while ( fit.nextFeature( f ) )
3643  {
3644  nFeatsToLabel++;
3645  }
3646  palyr.mFeaturesToLabel = nFeatsToLabel;
3647  }
3648 
3649  // notify user about any font substitution
3650  if ( !palyr.mTextFontFound && !mLabelFontNotFoundNotified )
3651  {
3652  emit labelingFontNotFound( this, palyr.mTextFontFamily );
3654  }
3655  }
3656 
3657  //register diagram layers
3659  {
3661  rendererContext.labelingEngine()->addDiagramLayer( this, mDiagramLayerSettings );
3662  //add attributes needed by the diagram renderer
3663  QList<QString> att = mDiagramRenderer->diagramAttributes();
3664  QList<QString>::const_iterator attIt = att.constBegin();
3665  for ( ; attIt != att.constEnd(); ++attIt )
3666  {
3667  QgsExpression* expression = mDiagramRenderer->diagram()->getExpression( *attIt, &pendingFields() );
3668  QStringList columns = expression->referencedColumns();
3669  QStringList::const_iterator columnsIterator = columns.constBegin();
3670  for ( ; columnsIterator != columns.constEnd(); ++columnsIterator )
3671  {
3672  int index = fieldNameIndex( *columnsIterator );
3673  if ( !attributes.contains( index ) )
3674  {
3675  attributes << index;
3676  }
3677  }
3678  }
3679 
3680  QgsLinearlyInterpolatedDiagramRenderer* mLinearlyInterpolatedDiagramRenderer = dynamic_cast<QgsLinearlyInterpolatedDiagramRenderer*>( mDiagramRenderer );
3681  if ( mLinearlyInterpolatedDiagramRenderer != NULL )
3682  {
3683  if ( mLinearlyInterpolatedDiagramRenderer->classificationAttributeIsExpression() )
3684  {
3685  QgsExpression* expression = mDiagramRenderer->diagram()->getExpression( mLinearlyInterpolatedDiagramRenderer->classificationAttributeExpression(), &pendingFields() );
3686  QStringList columns = expression->referencedColumns();
3687  QStringList::const_iterator columnsIterator = columns.constBegin();
3688  for ( ; columnsIterator != columns.constEnd(); ++columnsIterator )
3689  {
3690  int index = fieldNameIndex( *columnsIterator );
3691  if ( !attributes.contains( index ) )
3692  {
3693  attributes << index;
3694  }
3695  }
3696  }
3697  else
3698  {
3699  if ( !attributes.contains( mLinearlyInterpolatedDiagramRenderer->classificationAttribute() ) )
3700  {
3701  attributes << mLinearlyInterpolatedDiagramRenderer->classificationAttribute();
3702  }
3703  }
3704  }
3705 
3706  //and the ones needed for data defined diagram positions
3707  if ( mDiagramLayerSettings->xPosColumn >= 0 && !attributes.contains( mDiagramLayerSettings->xPosColumn ) )
3708  {
3709  attributes << mDiagramLayerSettings->xPosColumn;
3710  }
3711  if ( mDiagramLayerSettings->yPosColumn >= 0 && !attributes.contains( mDiagramLayerSettings->yPosColumn ) )
3712  {
3713  attributes << mDiagramLayerSettings->yPosColumn;
3714  }
3715  }
3716 }
3717 
3718 void QgsVectorLayer::readSldLabeling( const QDomNode& node )
3719 {
3720  QDomElement element = node.toElement();
3721  if ( element.isNull() )
3722  return;
3723 
3724  QDomElement userStyleElem = element.firstChildElement( "UserStyle" );
3725  if ( userStyleElem.isNull() )
3726  {
3727  QgsDebugMsg( "Info: UserStyle element not found." );
3728  return;
3729  }
3730 
3731  QDomElement featureTypeStyleElem = userStyleElem.firstChildElement( "FeatureTypeStyle" );
3732  if ( featureTypeStyleElem.isNull() )
3733  {
3734  QgsDebugMsg( "Info: FeatureTypeStyle element not found." );
3735  return;
3736  }
3737 
3738  // use last rule
3739  QDomElement ruleElem = featureTypeStyleElem.lastChildElement( "Rule" );
3740  if ( ruleElem.isNull() )
3741  {
3742  QgsDebugMsg( "Info: Rule element not found." );
3743  return;
3744  }
3745 
3746  // use last text symbolizer
3747  QDomElement textSymbolizerElem = ruleElem.lastChildElement( "TextSymbolizer" );
3748  if ( textSymbolizerElem.isNull() )
3749  {
3750  QgsDebugMsg( "Info: TextSymbolizer element not found." );
3751  return;
3752  }
3753 
3754  // Label
3755  setCustomProperty( "labeling/enabled", false );
3756  QDomElement labelElem = textSymbolizerElem.firstChildElement( "Label" );
3757  if ( !labelElem.isNull() )
3758  {
3759  QDomElement propertyNameElem = labelElem.firstChildElement( "PropertyName" );
3760  if ( !propertyNameElem.isNull() )
3761  {
3762  // enable labeling
3763  setCustomProperty( "labeling", "pal" );
3764  setCustomProperty( "labeling/enabled", true );
3765 
3766  // set labeling defaults
3767  setCustomProperty( "labeling/fontFamily", "Sans-Serif" );
3768  setCustomProperty( "labeling/fontItalic", false );
3769  setCustomProperty( "labeling/fontSize", 10 );
3770  setCustomProperty( "labeling/fontSizeInMapUnits", false );
3771  setCustomProperty( "labeling/fontBold", false );
3772  setCustomProperty( "labeling/fontUnderline", false );
3773  setCustomProperty( "labeling/textColorR", 0 );
3774  setCustomProperty( "labeling/textColorG", 0 );
3775  setCustomProperty( "labeling/textColorB", 0 );
3776  setCustomProperty( "labeling/textTransp", 0 );
3777  setCustomProperty( "labeling/bufferDraw", false );
3778  setCustomProperty( "labeling/bufferSize", 1 );
3779  setCustomProperty( "labeling/bufferSizeInMapUnits", false );
3780  setCustomProperty( "labeling/bufferColorR", 255 );
3781  setCustomProperty( "labeling/bufferColorG", 255 );
3782  setCustomProperty( "labeling/bufferColorB", 255 );
3783  setCustomProperty( "labeling/bufferTransp", 0 );
3784  setCustomProperty( "labeling/placement", QgsPalLayerSettings::AroundPoint );
3785  setCustomProperty( "labeling/xOffset", 0 );
3786  setCustomProperty( "labeling/yOffset", 0 );
3787  setCustomProperty( "labeling/labelOffsetInMapUnits", false );
3788  setCustomProperty( "labeling/angleOffset", 0 );
3789 
3790  // label attribute
3791  QString labelAttribute = propertyNameElem.text();
3792  setCustomProperty( "labeling/fieldName", labelAttribute );
3793  setCustomProperty( "labeling/isExpression", false );
3794 
3795  int fieldIndex = fieldNameIndex( labelAttribute );
3796  if ( fieldIndex == -1 )
3797  {
3798  // label attribute is not in columns, check if it is an expression
3799  QgsExpression exp( labelAttribute );
3800  if ( !exp.hasEvalError() )
3801  {
3802  setCustomProperty( "labeling/isExpression", true );
3803  }
3804  else
3805  {
3806  QgsDebugMsg( "SLD label attribute error: " + exp.evalErrorString() );
3807  }
3808  }
3809  }
3810  else
3811  {
3812  QgsDebugMsg( "Info: PropertyName element not found." );
3813  return;
3814  }
3815  }
3816  else
3817  {
3818  QgsDebugMsg( "Info: Label element not found." );
3819  return;
3820  }
3821 
3822  // Font
3823  QDomElement fontElem = textSymbolizerElem.firstChildElement( "Font" );
3824  if ( !fontElem.isNull() )
3825  {
3826  QString cssName;
3827  QString elemText;
3828  QDomElement cssElem = fontElem.firstChildElement( "CssParameter" );
3829  while ( !cssElem.isNull() )
3830  {
3831  cssName = cssElem.attribute( "name", "not_found" );
3832  if ( cssName != "not_found" )
3833  {
3834  elemText = cssElem.text();
3835  if ( cssName == "font-family" )
3836  {
3837  setCustomProperty( "labeling/fontFamily", elemText );
3838  }
3839  else if ( cssName == "font-style" )
3840  {
3841  setCustomProperty( "labeling/fontItalic", ( elemText == "italic" ) || ( elemText == "Italic" ) );
3842  }
3843  else if ( cssName == "font-size" )
3844  {
3845  bool ok;
3846  int fontSize = elemText.toInt( &ok );
3847  if ( ok )
3848  {
3849  setCustomProperty( "labeling/fontSize", fontSize );
3850  }
3851  }
3852  else if ( cssName == "font-weight" )
3853  {
3854  setCustomProperty( "labeling/fontBold", ( elemText == "bold" ) || ( elemText == "Bold" ) );
3855  }
3856  else if ( cssName == "font-underline" )
3857  {
3858  setCustomProperty( "labeling/fontUnderline", ( elemText == "underline" ) || ( elemText == "Underline" ) );
3859  }
3860  }
3861 
3862  cssElem = cssElem.nextSiblingElement( "CssParameter" );
3863  }
3864  }
3865 
3866  // Fill
3867  QColor textColor = QgsOgcUtils::colorFromOgcFill( textSymbolizerElem.firstChildElement( "Fill" ) );
3868  if ( textColor.isValid() )
3869  {
3870  setCustomProperty( "labeling/textColorR", textColor.red() );
3871  setCustomProperty( "labeling/textColorG", textColor.green() );
3872  setCustomProperty( "labeling/textColorB", textColor.blue() );
3873  setCustomProperty( "labeling/textTransp", 100 - ( int )( 100 * textColor.alphaF() ) );
3874  }
3875 
3876  // Halo
3877  QDomElement haloElem = textSymbolizerElem.firstChildElement( "Halo" );
3878  if ( !haloElem.isNull() )
3879  {
3880  setCustomProperty( "labeling/bufferDraw", true );
3881  setCustomProperty( "labeling/bufferSize", 1 );
3882 
3883  QDomElement radiusElem = haloElem.firstChildElement( "Radius" );
3884  if ( !radiusElem.isNull() )
3885  {
3886  bool ok;
3887  double bufferSize = radiusElem.text().toDouble( &ok );
3888  if ( ok )
3889  {
3890  setCustomProperty( "labeling/bufferSize", bufferSize );
3891  }
3892  }
3893 
3894  QColor bufferColor = QgsOgcUtils::colorFromOgcFill( haloElem.firstChildElement( "Fill" ) );
3895  if ( bufferColor.isValid() )
3896  {
3897  setCustomProperty( "labeling/bufferColorR", bufferColor.red() );
3898  setCustomProperty( "labeling/bufferColorG", bufferColor.green() );
3899  setCustomProperty( "labeling/bufferColorB", bufferColor.blue() );
3900  setCustomProperty( "labeling/bufferTransp", 100 - ( int )( 100 * bufferColor.alphaF() ) );
3901  }
3902  }
3903 
3904  // LabelPlacement
3905  QDomElement labelPlacementElem = textSymbolizerElem.firstChildElement( "LabelPlacement" );
3906  if ( !labelPlacementElem.isNull() )
3907  {
3908  // PointPlacement
3909  QDomElement pointPlacementElem = labelPlacementElem.firstChildElement( "PointPlacement" );
3910  if ( !pointPlacementElem.isNull() )
3911  {
3912  setCustomProperty( "labeling/placement", QgsPalLayerSettings::OverPoint );
3913 
3914  QDomElement displacementElem = pointPlacementElem.firstChildElement( "Displacement" );
3915  if ( !displacementElem.isNull() )
3916  {
3917  QDomElement displacementXElem = displacementElem.firstChildElement( "DisplacementX" );
3918  if ( !displacementXElem.isNull() )
3919  {
3920  bool ok;
3921  double xOffset = displacementXElem.text().toDouble( &ok );
3922  if ( ok )
3923  {
3924  setCustomProperty( "labeling/xOffset", xOffset );
3925  }
3926  }
3927  QDomElement displacementYElem = displacementElem.firstChildElement( "DisplacementY" );
3928  if ( !displacementYElem.isNull() )
3929  {
3930  bool ok;
3931  double yOffset = displacementYElem.text().toDouble( &ok );
3932  if ( ok )
3933  {
3934  setCustomProperty( "labeling/yOffset", yOffset );
3935  }
3936  }
3937  }
3938 
3939  QDomElement rotationElem = pointPlacementElem.firstChildElement( "Rotation" );
3940  if ( !rotationElem.isNull() )
3941  {
3942  bool ok;
3943  double rotation = rotationElem.text().toDouble( &ok );
3944  if ( ok )
3945  {
3946  setCustomProperty( "labeling/angleOffset", rotation );
3947  }
3948  }
3949  }
3950  }
3951 }
3952 
3954 {
3955  if ( !mDiagramLayerSettings )
3957  *mDiagramLayerSettings = s;
3958 }
3959 
3961 {
3962  QString myMetadata = "<html><body>";
3963 
3964  //-------------
3965 
3966  myMetadata += "<p class=\"subheaderglossy\">";
3967  myMetadata += tr( "General" );
3968  myMetadata += "</p>\n";
3969 
3970  // data comment
3971  if ( !( dataComment().isEmpty() ) )
3972  {
3973  myMetadata += "<p class=\"glossy\">" + tr( "Layer comment" ) + "</p>\n";
3974  myMetadata += "<p>";
3975  myMetadata += dataComment();
3976  myMetadata += "</p>\n";
3977  }
3978 
3979  //storage type
3980  myMetadata += "<p class=\"glossy\">" + tr( "Storage type of this layer" ) + "</p>\n";
3981  myMetadata += "<p>";
3982  myMetadata += storageType();
3983  myMetadata += "</p>\n";
3984 
3985  if ( dataProvider() )
3986  {
3987  //provider description
3988  myMetadata += "<p class=\"glossy\">" + tr( "Description of this provider" ) + "</p>\n";
3989  myMetadata += "<p>";
3990  myMetadata += dataProvider()->description().replace( "\n", "<br>" );
3991  myMetadata += "</p>\n";
3992  }
3993 
3994  // data source
3995  myMetadata += "<p class=\"glossy\">" + tr( "Source for this layer" ) + "</p>\n";
3996  myMetadata += "<p>";
3997  myMetadata += publicSource();
3998  myMetadata += "</p>\n";
3999 
4000  //geom type
4001 
4003 
4004  if ( type < 0 || type > QGis::NoGeometry )
4005  {
4006  QgsDebugMsg( "Invalid vector type" );
4007  }
4008  else
4009  {
4010  QString typeString( QGis::vectorGeometryType( geometryType() ) );
4011 
4012  myMetadata += "<p class=\"glossy\">" + tr( "Geometry type of the features in this layer" ) + "</p>\n";
4013  myMetadata += "<p>";
4014  myMetadata += typeString;
4015  myMetadata += "</p>\n";
4016  }
4017 
4019  if ( !pkAttrList.isEmpty() )
4020  {
4021  myMetadata += "<p class=\"glossy\">" + tr( "Primary key attributes" ) + "</p>\n";
4022  myMetadata += "<p>";
4023  foreach ( int idx, pkAttrList )
4024  {
4025  myMetadata += pendingFields()[ idx ].name() + " ";
4026  }
4027  myMetadata += "</p>\n";
4028  }
4029 
4030 
4031  //feature count
4032  myMetadata += "<p class=\"glossy\">" + tr( "The number of features in this layer" ) + "</p>\n";
4033  myMetadata += "<p>";
4034  myMetadata += QString::number( featureCount() );
4035  myMetadata += "</p>\n";
4036  //capabilities
4037  myMetadata += "<p class=\"glossy\">" + tr( "Editing capabilities of this layer" ) + "</p>\n";
4038  myMetadata += "<p>";
4039  myMetadata += capabilitiesString();
4040  myMetadata += "</p>\n";
4041 
4042  //-------------
4043 
4044  QgsRectangle myExtent = extent();
4045  myMetadata += "<p class=\"subheaderglossy\">";
4046  myMetadata += tr( "Extents" );
4047  myMetadata += "</p>\n";
4048 
4049  //extents in layer cs TODO...maybe make a little nested table to improve layout...
4050  myMetadata += "<p class=\"glossy\">" + tr( "In layer spatial reference system units" ) + "</p>\n";
4051  myMetadata += "<p>";
4052  // Try to be a bit clever over what number format we use for the
4053  // extents. Some people don't like it using scientific notation when the
4054  // numbers get large, but for small numbers this is the more practical
4055  // option (so we can't force the format to 'f' for all values).
4056  // The scheme:
4057  // - for all numbers with more than 5 digits, force non-scientific notation
4058  // and 2 digits after the decimal point.
4059  // - for all smaller numbers let the OS decide which format to use (it will
4060  // generally use non-scientific unless the number gets much less than 1).
4061 
4062  if ( !myExtent.isEmpty() )
4063  {
4064  QString xMin, yMin, xMax, yMax;
4065  double changeoverValue = 99999; // The 'largest' 5 digit number
4066  if ( qAbs( myExtent.xMinimum() ) > changeoverValue )
4067  {
4068  xMin = QString( "%1" ).arg( myExtent.xMinimum(), 0, 'f', 2 );
4069  }
4070  else
4071  {
4072  xMin = QString( "%1" ).arg( myExtent.xMinimum() );
4073  }
4074  if ( qAbs( myExtent.yMinimum() ) > changeoverValue )
4075  {
4076  yMin = QString( "%1" ).arg( myExtent.yMinimum(), 0, 'f', 2 );
4077  }
4078  else
4079  {
4080  yMin = QString( "%1" ).arg( myExtent.yMinimum() );
4081  }
4082  if ( qAbs( myExtent.xMaximum() ) > changeoverValue )
4083  {
4084  xMax = QString( "%1" ).arg( myExtent.xMaximum(), 0, 'f', 2 );
4085  }
4086  else
4087  {
4088  xMax = QString( "%1" ).arg( myExtent.xMaximum() );
4089  }
4090  if ( qAbs( myExtent.yMaximum() ) > changeoverValue )
4091  {
4092  yMax = QString( "%1" ).arg( myExtent.yMaximum(), 0, 'f', 2 );
4093  }
4094  else
4095  {
4096  yMax = QString( "%1" ).arg( myExtent.yMaximum() );
4097  }
4098 
4099  myMetadata += tr( "xMin,yMin %1,%2 : xMax,yMax %3,%4" )
4100  .arg( xMin ).arg( yMin ).arg( xMax ).arg( yMax );
4101  }
4102  else
4103  {
4104  myMetadata += tr( "unknown extent" );
4105  }
4106 
4107  myMetadata += "</p>\n";
4108 
4109  //extents in project cs
4110 
4111  try
4112  {
4113 #if 0
4114  // TODO: currently disabled, will revisit later [MD]
4115  QgsRectangle myProjectedExtent = coordinateTransform->transformBoundingBox( extent() );
4116  myMetadata += "<p class=\"glossy\">" + tr( "In project spatial reference system units" ) + "</p>\n";
4117  myMetadata += "<p>";
4118  myMetadata += tr( "xMin,yMin %1,%2 : xMax,yMax %3,%4" )
4119  .arg( myProjectedExtent.xMinimum() )
4120  .arg( myProjectedExtent.yMinimum() )
4121  .arg( myProjectedExtent.xMaximum() )
4122  .arg( myProjectedExtent.yMaximum() );
4123  myMetadata += "</p>\n";
4124 #endif
4125 
4126  //
4127  // Display layer spatial ref system
4128  //
4129  myMetadata += "<p class=\"glossy\">" + tr( "Layer Spatial Reference System" ) + "</p>\n";
4130  myMetadata += "<p>";
4131  myMetadata += crs().toProj4().replace( QRegExp( "\"" ), " \"" );
4132  myMetadata += "</p>\n";
4133 
4134  //
4135  // Display project (output) spatial ref system
4136  //
4137 #if 0
4138  // TODO: disabled for now, will revisit later [MD]
4139  //myMetadata += "<tr><td bgcolor=\"gray\">";
4140  myMetadata += "<p class=\"glossy\">" + tr( "Project (Output) Spatial Reference System" ) + "</p>\n";
4141  myMetadata += "<p>";
4142  myMetadata += coordinateTransform->destCRS().toProj4().replace( QRegExp( "\"" ), " \"" );
4143  myMetadata += "</p>\n";
4144 #endif
4145  }
4146  catch ( QgsCsException &cse )
4147  {
4148  Q_UNUSED( cse );
4149  QgsDebugMsg( cse.what() );
4150 
4151  myMetadata += "<p class=\"glossy\">" + tr( "In project spatial reference system units" ) + "</p>\n";
4152  myMetadata += "<p>";
4153  myMetadata += tr( "(Invalid transformation of layer extents)" );
4154  myMetadata += "</p>\n";
4155 
4156  }
4157 
4158 #if 0
4159  //
4160  // Add the info about each field in the attribute table
4161  //
4162  myMetadata += "<p class=\"glossy\">" + tr( "Attribute field info" ) + "</p>\n";
4163  myMetadata += "<p>";
4164 
4165  // Start a nested table in this trow
4166  myMetadata += "<table width=\"100%\">";
4167  myMetadata += "<tr><th>";
4168  myMetadata += tr( "Field" );
4169  myMetadata += "</th>";
4170  myMetadata += "<th>";
4171  myMetadata += tr( "Type" );
4172  myMetadata += "</th>";
4173  myMetadata += "<th>";
4174  myMetadata += tr( "Length" );
4175  myMetadata += "</th>";
4176  myMetadata += "<th>";
4177  myMetadata += tr( "Precision" );
4178  myMetadata += "</th>";
4179  myMetadata += "<th>";
4180  myMetadata += tr( "Comment" );
4181  myMetadata += "</th>";
4182 
4183  //get info for each field by looping through them
4184  const QgsFieldMap& myFields = pendingFields();
4185  for ( QgsFieldMap::const_iterator it = myFields.begin(); it != myFields.end(); ++it )
4186  {
4187  const QgsField& myField = *it;
4188 
4189  myMetadata += "<tr><td>";
4190  myMetadata += myField.name();
4191  myMetadata += "</td>";
4192  myMetadata += "<td>";
4193  myMetadata += myField.typeName();
4194  myMetadata += "</td>";
4195  myMetadata += "<td>";
4196  myMetadata += QString( "%1" ).arg( myField.length() );
4197  myMetadata += "</td>";
4198  myMetadata += "<td>";
4199  myMetadata += QString( "%1" ).arg( myField.precision() );
4200  myMetadata += "</td>";
4201  myMetadata += "<td>";
4202  myMetadata += QString( "%1" ).arg( myField.comment() );
4203  myMetadata += "</td></tr>";
4204  }
4205 
4206  //close field list
4207  myMetadata += "</table>"; //end of nested table
4208 #endif
4209 
4210  myMetadata += "</body></html>";
4211  return myMetadata;
4212 }
4213 
4215 {
4218 }
4219 
4221 {
4222  mSymbolFeatureCounted = false;
4223 }
4224 
4226 {
4228  {
4230  {
4231  QgsAttributeEditorContainer* cont = dynamic_cast< QgsAttributeEditorContainer* >( elem );
4232  QList<QgsAttributeEditorElement*> relations = cont->findElements( QgsAttributeEditorElement::AeTypeRelation );
4233  Q_FOREACH( QgsAttributeEditorElement* relElem, relations )
4234  {
4235  QgsAttributeEditorRelation* rel = dynamic_cast< QgsAttributeEditorRelation* >( relElem );
4236  rel->init( QgsProject::instance()->relationManager() );
4237  }
4238  }
4239  }
4240 }
4241 
4243 {
4244  const QgsFields &fields = pendingFields();
4245 
4246  // FIXME: throw an exception!?
4247  static QgsVectorLayer::ValueRelationData invalidData;
4248  if ( idx < 0 || idx >= fields.count() )
4249  {
4250  QgsDebugMsg( QString( "field %1 not found" ).arg( idx ) );
4251  return invalidData;
4252  }
4253  QString fieldName = fields[idx].name();
4254 
4255  if ( !mValueRelations.contains( fieldName ) )
4256  {
4257  mValueRelations[fieldName] = ValueRelationData();
4258  }
4259 
4260  return mValueRelations[fieldName];
4261 }
4262 
4263 QList<QgsRelation> QgsVectorLayer::referencingRelations( int idx )
4264 {
4265  return QgsProject::instance()->relationManager()->referencingRelations( this, idx );
4266 }
4267 
4268 QList<QgsAttributeEditorElement*> &QgsVectorLayer::attributeEditorElements()
4269 {
4270  return mAttributeEditorElements;
4271 }
4272 
4274 {
4275  mAttributeEditorElements.clear();
4276 }
4277 
4278 QDomElement QgsAttributeEditorContainer::toDomElement( QDomDocument& doc ) const
4279 {
4280  QDomElement elem = doc.createElement( "attributeEditorContainer" );
4281  elem.setAttribute( "name", mName );
4282 
4283  Q_FOREACH( QgsAttributeEditorElement* child, mChildren )
4284  {
4285  elem.appendChild( child->toDomElement( doc ) );
4286  }
4287  return elem;
4288 }
4289 
4291 {
4292  mChildren.append( widget );
4293 }
4294 
4296 {
4297  QList<QgsAttributeEditorElement*> results;
4298 
4299  Q_FOREACH( QgsAttributeEditorElement* elem, mChildren )
4300  {
4301  if ( elem->type() == type )
4302  {
4303  results.append( elem );
4304  }
4305 
4306  if ( elem->type() == AeTypeContainer )
4307  {
4308  QgsAttributeEditorContainer* cont = dynamic_cast<QgsAttributeEditorContainer*>( elem );
4309  results += cont->findElements( type );
4310  }
4311  }
4312 
4313  return results;
4314 }
4315 
4316 QDomElement QgsAttributeEditorField::toDomElement( QDomDocument& doc ) const
4317 {
4318  QDomElement elem = doc.createElement( "attributeEditorField" );
4319  elem.setAttribute( "name", mName );
4320  elem.setAttribute( "index", mIdx );
4321  return elem;
4322 }
4323 
4324 int QgsVectorLayer::listStylesInDatabase( QStringList &ids, QStringList &names, QStringList &descriptions, QString &msgError )
4325 {
4327  QLibrary *myLib = pReg->providerLibrary( mProviderKey );
4328  if ( !myLib )
4329  {
4330  msgError = QObject::tr( "Unable to load %1 provider" ).arg( mProviderKey );
4331  return -1;
4332  }
4333  listStyles_t* listStylesExternalMethod = ( listStyles_t * ) cast_to_fptr( myLib->resolve( "listStyles" ) );
4334 
4335  if ( !listStylesExternalMethod )
4336  {
4337  delete myLib;
4338  msgError = QObject::tr( "Provider %1 has no %2 method" ).arg( mProviderKey ).arg( "listStyles" );
4339  return -1;
4340  }
4341 
4342  return listStylesExternalMethod( mDataSource, ids, names, descriptions, msgError );
4343 }
4344 
4345 QString QgsVectorLayer::getStyleFromDatabase( QString styleId, QString &msgError )
4346 {
4348  QLibrary *myLib = pReg->providerLibrary( mProviderKey );
4349  if ( !myLib )
4350  {
4351  msgError = QObject::tr( "Unable to load %1 provider" ).arg( mProviderKey );
4352  return QObject::tr( "" );
4353  }
4354  getStyleById_t* getStyleByIdMethod = ( getStyleById_t * ) cast_to_fptr( myLib->resolve( "getStyleById" ) );
4355 
4356  if ( !getStyleByIdMethod )
4357  {
4358  delete myLib;
4359  msgError = QObject::tr( "Provider %1 has no %2 method" ).arg( mProviderKey ).arg( "getStyleById" );
4360  return QObject::tr( "" );
4361  }
4362 
4363  return getStyleByIdMethod( mDataSource, styleId, msgError );
4364 }
4365 
4366 
4367 void QgsVectorLayer::saveStyleToDatabase( QString name, QString description,
4368  bool useAsDefault, QString uiFileContent, QString &msgError )
4369 {
4370 
4371  QString sldStyle, qmlStyle;
4373  QLibrary *myLib = pReg->providerLibrary( mProviderKey );
4374  if ( !myLib )
4375  {
4376  msgError = QObject::tr( "Unable to load %1 provider" ).arg( mProviderKey );
4377  return;
4378  }
4379  saveStyle_t* saveStyleExternalMethod = ( saveStyle_t * ) cast_to_fptr( myLib->resolve( "saveStyle" ) );
4380 
4381  if ( !saveStyleExternalMethod )
4382  {
4383  delete myLib;
4384  msgError = QObject::tr( "Provider %1 has no %2 method" ).arg( mProviderKey ).arg( "saveStyle" );
4385  return;
4386  }
4387 
4388  QDomDocument qmlDocument, sldDocument;
4389  this->exportNamedStyle( qmlDocument, msgError );
4390  if ( !msgError.isNull() )
4391  {
4392  return;
4393  }
4394  qmlStyle = qmlDocument.toString();
4395 
4396  this->exportSldStyle( sldDocument, msgError );
4397  if ( !msgError.isNull() )
4398  {
4399  return;
4400  }
4401  sldStyle = sldDocument.toString();
4402 
4403  saveStyleExternalMethod( mDataSource, qmlStyle, sldStyle, name,
4404  description, uiFileContent, useAsDefault, msgError );
4405 }
4406 
4407 
4408 
4409 QString QgsVectorLayer::loadNamedStyle( const QString &theURI, bool &theResultFlag )
4410 {
4411  return loadNamedStyle( theURI, theResultFlag, false );
4412 }
4413 
4414 QString QgsVectorLayer::loadNamedStyle( const QString &theURI, bool &theResultFlag, bool loadFromLocalDB )
4415 {
4416  QgsDataSourceURI dsUri( theURI );
4417  if ( !loadFromLocalDB && !dsUri.database().isEmpty() )
4418  {
4420  QLibrary *myLib = pReg->providerLibrary( mProviderKey );
4421  if ( myLib )
4422  {
4423  loadStyle_t* loadStyleExternalMethod = ( loadStyle_t * ) cast_to_fptr( myLib->resolve( "loadStyle" ) );
4424  if ( loadStyleExternalMethod )
4425  {
4426  QString qml, errorMsg;
4427  qml = loadStyleExternalMethod( mDataSource, errorMsg );
4428  if ( !qml.isEmpty() )
4429  {
4430  theResultFlag = this->applyNamedStyle( qml, errorMsg );
4431  return QObject::tr( "Loaded from Provider" );
4432  }
4433  }
4434  }
4435  }
4436 
4437  return QgsMapLayer::loadNamedStyle( theURI, theResultFlag );
4438 }
4439 
4440 bool QgsVectorLayer::applyNamedStyle( QString namedStyle, QString errorMsg )
4441 {
4442  QDomDocument myDocument( "qgis" );
4443  myDocument.setContent( namedStyle );
4444 
4445  QDomElement myRoot = myDocument.firstChildElement( "qgis" );
4446 
4447  if ( myRoot.isNull() )
4448  {
4449  errorMsg = tr( "Error: qgis element could not be found" );
4450  return false;
4451  }
4452  toggleScaleBasedVisibility( myRoot.attribute( "hasScaleBasedVisibilityFlag" ).toInt() == 1 );
4453  setMinimumScale( myRoot.attribute( "minimumScale" ).toFloat() );
4454  setMaximumScale( myRoot.attribute( "maximumScale" ).toFloat() );
4455 
4456 #if 0
4457  //read transparency level
4458  QDomNode transparencyNode = myRoot.namedItem( "transparencyLevelInt" );
4459  if ( ! transparencyNode.isNull() )
4460  {
4461  // set transparency level only if it's in project
4462  // (otherwise it sets the layer transparent)
4463  QDomElement myElement = transparencyNode.toElement();
4464  setTransparency( myElement.text().toInt() );
4465  }
4466 #endif
4467 
4468  return readSymbology( myRoot, errorMsg );
4469 }
4470 
4471 
4472 QDomElement QgsAttributeEditorRelation::toDomElement( QDomDocument& doc ) const
4473 {
4474  QDomElement elem = doc.createElement( "attributeEditorRelation" );
4475  elem.setAttribute( "name", mName );
4476  elem.setAttribute( "relation", mRelation.id() );
4477  return elem;
4478 }
4479 
4481 {
4482  mRelation = relationManager->relation( mRelationId );
4483  return mRelation.isValid();
4484 }