QGIS API Documentation  2.8.2-Wien
 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 "qgsclipper.h"
44 #include "qgscoordinatetransform.h"
45 #include "qgsdatasourceuri.h"
47 #include "qgsfeature.h"
48 #include "qgsfeaturerequest.h"
49 #include "qgsfield.h"
50 #include "qgsgeometrycache.h"
51 #include "qgsgeometry.h"
52 #include "qgslabel.h"
53 #include "qgslegacyhelpers.h"
54 #include "qgslogger.h"
55 #include "qgsmaplayerlegend.h"
56 #include "qgsmaplayerregistry.h"
57 #include "qgsmaptopixel.h"
58 #include "qgsmessagelog.h"
59 #include "qgsogcutils.h"
60 #include "qgspoint.h"
61 #include "qgsproject.h"
62 #include "qgsproviderregistry.h"
63 #include "qgsrectangle.h"
64 #include "qgsrelationmanager.h"
65 #include "qgsrendercontext.h"
66 #include "qgsvectordataprovider.h"
72 #include "qgsvectorlayerrenderer.h"
74 
75 #include "qgsrendererv2.h"
76 #include "qgssymbolv2.h"
77 #include "qgssymbollayerv2.h"
79 #include "qgsdiagramrendererv2.h"
80 #include "qgsstylev2.h"
82 #include "qgspallabeling.h"
83 #include "qgssimplifymethod.h"
84 
85 #include "diagram/qgsdiagram.h"
86 
87 #ifdef TESTPROVIDERLIB
88 #include <dlfcn.h>
89 #endif
90 
91 typedef bool saveStyle_t(
92  const QString& uri,
93  const QString& qmlStyle,
94  const QString& sldStyle,
95  const QString& styleName,
96  const QString& styleDescription,
97  const QString& uiFileContent,
98  bool useAsDefault,
99  QString& errCause
100 );
101 
102 typedef QString loadStyle_t(
103  const QString& uri,
104  QString& errCause
105 );
106 
107 typedef int listStyles_t(
108  const QString& uri,
109  QStringList &ids,
110  QStringList &names,
111  QStringList &descriptions,
112  QString& errCause
113 );
114 
115 typedef QString getStyleById_t(
116  const QString& uri,
117  QString styleID,
118  QString& errCause
119 );
120 
121 QgsVectorLayer::QgsVectorLayer( QString vectorLayerPath,
122  QString baseName,
123  QString providerKey,
124  bool loadDefaultStyleFlag )
125  : QgsMapLayer( VectorLayer, baseName, vectorLayerPath )
126  , mDataProvider( NULL )
127  , mProviderKey( providerKey )
128  , mReadOnly( false )
129  , mWkbType( QGis::WKBUnknown )
130  , mRendererV2( NULL )
131  , mLabel( 0 )
132  , mLabelOn( false )
133  , mLabelFontNotFoundNotified( false )
134  , mFeatureBlendMode( QPainter::CompositionMode_SourceOver ) // Default to normal feature blending
135  , mLayerTransparency( 0 )
136  , mVertexMarkerOnlyForSelection( false )
137  , mEditorLayout( GeneratedLayout )
138  , mFeatureFormSuppress( SuppressDefault )
139  , mCache( new QgsGeometryCache() )
140  , mEditBuffer( 0 )
141  , mJoinBuffer( 0 )
142  , mExpressionFieldBuffer( 0 )
143  , mDiagramRenderer( 0 )
144  , mDiagramLayerSettings( 0 )
145  , mValidExtent( false )
146  , mLazyExtent( true )
147  , mSymbolFeatureCounted( false )
148 {
149  mActions = new QgsAttributeAction( this );
150 
151  // if we're given a provider type, try to create and bind one to this layer
152  if ( ! mProviderKey.isEmpty() )
153  {
154  setDataProvider( mProviderKey );
155  }
156  if ( mValid )
157  {
158  // Always set crs
160 
161  // check if there is a default style / propertysheet defined
162  // for this layer and if so apply it
163  bool defaultLoadedFlag = false;
164  if ( loadDefaultStyleFlag )
165  {
166  loadDefaultStyle( defaultLoadedFlag );
167  }
168 
169  // if the default style failed to load or was disabled use some very basic defaults
170  if ( !defaultLoadedFlag && hasGeometryType() )
171  {
172  // add single symbol renderer
174  }
175 
177 
178  connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( checkJoinLayerRemove( QString ) ) );
179  }
180 
181  connect( this, SIGNAL( selectionChanged( QgsFeatureIds, QgsFeatureIds, bool ) ), this, SIGNAL( selectionChanged() ) );
182  connect( this, SIGNAL( selectionChanged( QgsFeatureIds, QgsFeatureIds, bool ) ), this, SIGNAL( repaintRequested() ) );
183  connect( QgsProject::instance()->relationManager(), SIGNAL( relationsLoaded() ), this, SLOT( onRelationsLoaded() ) );
184 
185  // Default simplify drawing settings
186  QSettings settings;
187  mSimplifyMethod.setSimplifyHints(( QgsVectorSimplifyMethod::SimplifyHints ) settings.value( "/qgis/simplifyDrawingHints", ( int ) mSimplifyMethod.simplifyHints() ).toInt() );
188  mSimplifyMethod.setThreshold( settings.value( "/qgis/simplifyDrawingTol", mSimplifyMethod.threshold() ).toFloat() );
189  mSimplifyMethod.setForceLocalOptimization( settings.value( "/qgis/simplifyLocal", mSimplifyMethod.forceLocalOptimization() ).toBool() );
190  mSimplifyMethod.setMaximumScale( settings.value( "/qgis/simplifyMaxScale", mSimplifyMethod.maximumScale() ).toFloat() );
191 } // QgsVectorLayer ctor
192 
193 
194 
196 {
197  QgsDebugMsg( "entered." );
198 
199  emit layerDeleted();
200 
201  mValid = false;
202 
203  delete mDataProvider;
204  delete mEditBuffer;
205  delete mJoinBuffer;
206  delete mExpressionFieldBuffer;
207  delete mCache;
208  delete mLabel;
209  delete mDiagramLayerSettings;
210 
211  delete mActions;
212 
213  delete mRendererV2;
214 }
215 
217 {
218  if ( mDataProvider )
219  {
220  return mDataProvider->storageType();
221  }
222  return 0;
223 }
224 
225 
227 {
228  if ( mDataProvider )
229  {
230  return mDataProvider->capabilitiesString();
231  }
232  return 0;
233 }
234 
236 {
237  if ( mDataProvider )
238  {
239  return mDataProvider->dataComment();
240  }
241  return QString();
242 }
243 
244 
246 {
247  return mProviderKey;
248 }
249 
253 void QgsVectorLayer::setDisplayField( QString fldName )
254 {
255  if ( !hasGeometryType() )
256  return;
257 
258  // If fldName is provided, use it as the display field, otherwise
259  // determine the field index for the feature column of the identify
260  // dialog. We look for fields containing "name" first and second for
261  // fields containing "id". If neither are found, the first field
262  // is used as the node.
263  QString idxName = "";
264  QString idxId = "";
265 
266  if ( !fldName.isEmpty() )
267  {
268  mDisplayField = fldName;
269  }
270  else
271  {
272  const QgsFields &fields = pendingFields();
273  int fieldsSize = fields.size();
274 
275  for ( int idx = 0; idx < fields.count(); ++idx )
276  {
277  QString fldName = fields[idx].name();
278  QgsDebugMsg( "Checking field " + fldName + " of " + QString::number( fieldsSize ) + " total" );
279 
280  // Check the fields and keep the first one that matches.
281  // We assume that the user has organized the data with the
282  // more "interesting" field names first. As such, name should
283  // be selected before oldname, othername, etc.
284  if ( fldName.indexOf( "name", 0, Qt::CaseInsensitive ) > -1 )
285  {
286  if ( idxName.isEmpty() )
287  {
288  idxName = fldName;
289  }
290  }
291  if ( fldName.indexOf( "descrip", 0, Qt::CaseInsensitive ) > -1 )
292  {
293  if ( idxName.isEmpty() )
294  {
295  idxName = fldName;
296  }
297  }
298  if ( fldName.indexOf( "id", 0, Qt::CaseInsensitive ) > -1 )
299  {
300  if ( idxId.isEmpty() )
301  {
302  idxId = fldName;
303  }
304  }
305  }
306 
307  //if there were no fields in the dbf just return - otherwise qgis segfaults!
308  if ( fieldsSize == 0 )
309  return;
310 
311  if ( idxName.length() > 0 )
312  {
313  mDisplayField = idxName;
314  }
315  else
316  {
317  if ( idxId.length() > 0 )
318  {
319  mDisplayField = idxId;
320  }
321  else
322  {
323  mDisplayField = fields[0].name();
324  }
325  }
326 
327  }
328 }
329 
330 // NOTE this is a temporary method added by Tim to prevent label clipping
331 // which was occurring when labeller was called in the main draw loop
332 // This method will probably be removed again in the near future!
334 {
335  if ( !hasGeometryType() )
336  return;
337 
338  QgsDebugMsg( "Starting draw of labels: " + id() );
339 
340  if ( mRendererV2 && mLabelOn && mLabel &&
341  ( !mLabel->scaleBasedVisibility() ||
342  ( mLabel->minScale() <= rendererContext.rendererScale() &&
343  rendererContext.rendererScale() <= mLabel->maxScale() ) ) )
344  {
345  QgsAttributeList attributes;
346  foreach ( QString attrName, mRendererV2->usedAttributes() )
347  {
348  int attrNum = fieldNameIndex( attrName );
349  attributes.append( attrNum );
350  }
351  // make sure the renderer is ready for classification ("symbolForFeature")
352  mRendererV2->startRender( rendererContext, pendingFields() );
353 
354  // Add fields required for labels
355  mLabel->addRequiredFields( attributes );
356 
357  QgsDebugMsg( "Selecting features based on view extent" );
358 
359  int featureCount = 0;
360 
361  try
362  {
363  // select the records in the extent. The provider sets a spatial filter
364  // and sets up the selection set for retrieval
366  .setFilterRect( rendererContext.extent() )
367  .setSubsetOfAttributes( attributes ) );
368 
369  QgsFeature fet;
370  while ( fit.nextFeature( fet ) )
371  {
372  if ( mRendererV2->willRenderFeature( fet ) )
373  {
374  bool sel = mSelectedFeatureIds.contains( fet.id() );
375  mLabel->renderLabel( rendererContext, fet, sel, 0 );
376  }
377  featureCount++;
378  }
379  }
380  catch ( QgsCsException &e )
381  {
382  Q_UNUSED( e );
383  QgsDebugMsg( "Error projecting label locations" );
384  }
385 
386  if ( mRendererV2 )
387  {
388  mRendererV2->stopRender( rendererContext );
389  }
390 
391  QgsDebugMsg( QString( "Total features processed %1" ).arg( featureCount ) );
392  }
393 }
394 
396 {
397  if ( mDataProvider )
398  {
399  mDataProvider->reloadData();
400  }
401 }
402 
404 {
405  return new QgsVectorLayerRenderer( this, rendererContext );
406 }
407 
408 bool QgsVectorLayer::draw( QgsRenderContext& rendererContext )
409 {
410  QgsVectorLayerRenderer renderer( this, rendererContext );
411  return renderer.render();
412 }
413 
414 void QgsVectorLayer::drawVertexMarker( double x, double y, QPainter& p, QgsVectorLayer::VertexMarkerType type, int m )
415 {
417  {
418  p.setPen( QColor( 50, 100, 120, 200 ) );
419  p.setBrush( QColor( 200, 200, 210, 120 ) );
420  p.drawEllipse( x - m, y - m, m * 2 + 1, m * 2 + 1 );
421  }
422  else if ( type == QgsVectorLayer::Cross )
423  {
424  p.setPen( QColor( 255, 0, 0 ) );
425  p.drawLine( x - m, y + m, x + m, y - m );
426  p.drawLine( x - m, y - m, x + m, y + m );
427  }
428 }
429 
431 {
432  mSelectedFeatureIds.insert( fid );
433 
434  emit selectionChanged( QgsFeatureIds() << fid, QgsFeatureIds(), false );
435 }
436 
437 void QgsVectorLayer::select( const QgsFeatureIds& featureIds )
438 {
439  mSelectedFeatureIds.unite( featureIds );
440 
441  emit selectionChanged( featureIds, QgsFeatureIds(), false );
442 }
443 
445 {
446  mSelectedFeatureIds.remove( fid );
447 
448  emit selectionChanged( QgsFeatureIds(), QgsFeatureIds() << fid, false );
449 }
450 
451 void QgsVectorLayer::deselect( const QgsFeatureIds& featureIds )
452 {
453  mSelectedFeatureIds.subtract( featureIds );
454 
455  emit selectionChanged( QgsFeatureIds(), featureIds, false );
456 }
457 
458 void QgsVectorLayer::select( QgsRectangle & rect, bool addToSelection )
459 {
460  // normalize the rectangle
461  rect.normalize();
462 
463  //select all the elements
465  .setFilterRect( rect )
467  .setSubsetOfAttributes( QgsAttributeList() ) );
468 
469  QgsFeatureIds ids;
470 
471  QgsFeature f;
472  while ( fit.nextFeature( f ) )
473  {
474  ids << f.id();
475  }
476 
477  if ( !addToSelection )
478  {
479  setSelectedFeatures( mSelectedFeatureIds + ids );
480  }
481  else
482  {
483  select( ids );
484  }
485 }
486 
488 {
489  QgsFeatureIds intersectingIds = selectIds & deselectIds;
490  if ( intersectingIds.count() > 0 )
491  {
492  QgsDebugMsg( "Trying to select and deselect the same item at the same time. Unsure what to do. Selecting dubious items." );
493  }
494 
495  mSelectedFeatureIds -= deselectIds;
496  mSelectedFeatureIds += selectIds;
497 
498  emit selectionChanged( selectIds, deselectIds - intersectingIds, false );
499 }
500 
502 {
504  ids.subtract( mSelectedFeatureIds );
505  setSelectedFeatures( ids );
506 }
507 
509 {
511 }
512 
514 {
516  .setFlags( QgsFeatureRequest::NoGeometry )
517  .setSubsetOfAttributes( QgsAttributeList() ) );
518 
519  QgsFeatureIds ids;
520 
521  QgsFeature fet;
522  while ( fit.nextFeature( fet ) )
523  {
524  ids << fet.id();
525  }
526 
527  return ids;
528 }
529 
531 {
532  // normalize the rectangle
533  rect.normalize();
534 
536  .setFilterRect( rect )
538  .setSubsetOfAttributes( QgsAttributeList() ) );
539 
540  QgsFeatureIds selectIds;
541  QgsFeatureIds deselectIds;
542 
543  QgsFeature fet;
544  while ( fit.nextFeature( fet ) )
545  {
546  if ( mSelectedFeatureIds.contains( fet.id() ) )
547  {
548  deselectIds << fet.id();
549  }
550  else
551  {
552  selectIds << fet.id();
553  }
554  }
555 
556  modifySelection( selectIds, deselectIds );
557 }
558 
560 {
561  if ( mSelectedFeatureIds.size() == 0 )
562  return;
563 
565 }
566 
568 {
569  return mDataProvider;
570 }
571 
573 {
574  return mDataProvider;
575 }
576 
577 void QgsVectorLayer::setProviderEncoding( const QString& encoding )
578 {
579  if ( mDataProvider && mDataProvider->encoding() != encoding )
580  {
581  mDataProvider->setEncoding( encoding );
582  updateFields();
583  }
584 }
585 
587 {
588  delete mDiagramRenderer;
589  mDiagramRenderer = r;
590 }
591 
593 {
594  if ( mDataProvider )
595  {
596  int type = mDataProvider->geometryType();
597  switch ( type )
598  {
599  case QGis::WKBPoint:
600  case QGis::WKBPoint25D:
601  return QGis::Point;
602 
603  case QGis::WKBLineString:
605  return QGis::Line;
606 
607  case QGis::WKBPolygon:
608  case QGis::WKBPolygon25D:
609  return QGis::Polygon;
610 
611  case QGis::WKBMultiPoint:
613  return QGis::Point;
614 
617  return QGis::Line;
618 
621  return QGis::Polygon;
622 
623  case QGis::WKBNoGeometry:
624  return QGis::NoGeometry;
625  }
626  QgsDebugMsg( QString( "Data Provider Geometry type is not recognised, is %1" ).arg( type ) );
627  }
628  else
629  {
630  QgsDebugMsg( "pointer to mDataProvider is null" );
631  }
632 
633  // We shouldn't get here, and if we have, other things are likely to
634  // go wrong. Code that uses the type() return value should be
635  // rewritten to cope with a value of QGis::Unknown. To make this
636  // need known, the following message is printed every time we get
637  // here.
638  QgsDebugMsg( "WARNING: This code should never be reached. Problems may occur..." );
639 
640  return QGis::UnknownGeometry;
641 }
642 
644 {
646  return ( t != QGis::NoGeometry && t != QGis::UnknownGeometry );
647 }
648 
650 {
651  return mWkbType;
652 }
653 
655 {
656  if ( mSelectedFeatureIds.size() == 0 ) //no selected features
657  {
658  return QgsRectangle( 0, 0, 0, 0 );
659  }
660 
661  QgsRectangle r, retval;
662  retval.setMinimal();
663 
664  QgsFeature fet;
665  if ( mDataProvider->capabilities() & QgsVectorDataProvider::SelectAtId )
666  {
667  foreach ( QgsFeatureId fid, mSelectedFeatureIds )
668  {
670  .setFilterFid( fid )
671  .setSubsetOfAttributes( QgsAttributeList() ) )
672  .nextFeature( fet ) &&
673  fet.geometry() )
674  {
675  r = fet.geometry()->boundingBox();
676  retval.combineExtentWith( &r );
677  }
678  }
679  }
680  else
681  {
683  .setSubsetOfAttributes( QgsAttributeList() ) );
684 
685  while ( fit.nextFeature( fet ) )
686  {
687  if ( mSelectedFeatureIds.contains( fet.id() ) )
688  {
689  if ( fet.geometry() )
690  {
691  r = fet.geometry()->boundingBox();
692  retval.combineExtentWith( &r );
693  }
694  }
695  }
696  }
697 
698  if ( retval.width() == 0.0 || retval.height() == 0.0 )
699  {
700  // If all of the features are at the one point, buffer the
701  // rectangle a bit. If they are all at zero, do something a bit
702  // more crude.
703 
704  if ( retval.xMinimum() == 0.0 && retval.xMaximum() == 0.0 &&
705  retval.yMinimum() == 0.0 && retval.yMaximum() == 0.0 )
706  {
707  retval.set( -1.0, -1.0, 1.0, 1.0 );
708  }
709  }
710 
711  return retval;
712 }
713 
715 {
716  if ( !mDataProvider )
717  {
718  QgsDebugMsg( "invoked with null mDataProvider" );
719  return 0;
720  }
721 
722  return mDataProvider->featureCount();
723 }
724 
726 {
727  if ( !mSymbolFeatureCounted ) return -1;
728  return mSymbolFeatureCountMap.value( symbol );
729 }
730 
731 bool QgsVectorLayer::countSymbolFeatures( bool showProgress )
732 {
733  if ( mSymbolFeatureCounted ) return true;
734  mSymbolFeatureCountMap.clear();
735 
736  if ( !mDataProvider )
737  {
738  QgsDebugMsg( "invoked with null mDataProvider" );
739  return false;
740  }
741  if ( !mRendererV2 )
742  {
743  QgsDebugMsg( "invoked with null mRendererV2" );
744  return false;
745  }
746 
747  QgsLegendSymbolList symbolList = mRendererV2->legendSymbolItems();
748  QgsLegendSymbolList::const_iterator symbolIt = symbolList.constBegin();
749 
750  for ( ; symbolIt != symbolList.constEnd(); ++symbolIt )
751  {
752  mSymbolFeatureCountMap.insert( symbolIt->second, 0 );
753  }
754 
755  long nFeatures = pendingFeatureCount();
756  QProgressDialog progressDialog( tr( "Updating feature count for layer %1" ).arg( name() ), tr( "Abort" ), 0, nFeatures );
757  progressDialog.setWindowModality( Qt::WindowModal );
758  int featuresCounted = 0;
759 
761 
762  // Renderer (rule based) may depend on context scale, with scale is ignored if 0
763  QgsRenderContext renderContext;
764  renderContext.setRendererScale( 0 );
765  mRendererV2->startRender( renderContext, pendingFields() );
766 
767  QgsFeature f;
768  while ( fit.nextFeature( f ) )
769  {
770  QgsSymbolV2List featureSymbolList = mRendererV2->originalSymbolsForFeature( f );
771  for ( QgsSymbolV2List::iterator symbolIt = featureSymbolList.begin(); symbolIt != featureSymbolList.end(); ++symbolIt )
772  {
773  mSymbolFeatureCountMap[*symbolIt] += 1;
774  }
775  ++featuresCounted;
776 
777  if ( showProgress )
778  {
779  if ( featuresCounted % 50 == 0 )
780  {
781  if ( featuresCounted > nFeatures ) //sometimes the feature count is not correct
782  {
783  progressDialog.setMaximum( 0 );
784  }
785  progressDialog.setValue( featuresCounted );
786  if ( progressDialog.wasCanceled() )
787  {
788  mSymbolFeatureCountMap.clear();
789  mRendererV2->stopRender( renderContext );
790  return false;
791  }
792  }
793  }
794  }
795  mRendererV2->stopRender( renderContext );
796  progressDialog.setValue( nFeatures );
797  mSymbolFeatureCounted = true;
798  return true;
799 }
800 
802 {
803  mValidExtent = false;
804 }
805 
807 {
809  mValidExtent = true;
810 }
811 
813 {
814  QgsRectangle rect;
815  rect.setMinimal();
816 
817  if ( !hasGeometryType() )
818  return rect;
819 
820  if ( !mValidExtent && mLazyExtent && mDataProvider )
821  {
822  // get the extent
823  QgsRectangle mbr = mDataProvider->extent();
824 
825  // show the extent
826  QString s = mbr.toString();
827 
828  QgsDebugMsg( "Extent of layer: " + s );
829  // store the extent
830  setExtent( mbr );
831 
832  mLazyExtent = false;
833  }
834 
835  if ( mValidExtent )
836  return QgsMapLayer::extent();
837 
838  if ( !mDataProvider )
839  {
840  QgsDebugMsg( "invoked with null mDataProvider" );
841  }
842 
843  if ( mDataProvider && mEditBuffer && mEditBuffer->mDeletedFeatureIds.isEmpty() && mEditBuffer->mChangedGeometries.isEmpty() )
844  {
845  mDataProvider->updateExtents();
846 
847  // get the extent of the layer from the provider
848  // but only when there are some features already
849  if ( mDataProvider->featureCount() != 0 )
850  {
851  QgsRectangle r = mDataProvider->extent();
852  rect.combineExtentWith( &r );
853  }
854 
855  for ( QgsFeatureMap::iterator it = mEditBuffer->mAddedFeatures.begin(); it != mEditBuffer->mAddedFeatures.end(); ++it )
856  {
857  if ( it->geometry() )
858  {
859  QgsRectangle r = it->geometry()->boundingBox();
860  rect.combineExtentWith( &r );
861  }
862  }
863  }
864  else
865  {
867  .setSubsetOfAttributes( QgsAttributeList() ) );
868 
869  QgsFeature fet;
870  while ( fit.nextFeature( fet ) )
871  {
872  if ( fet.geometry() && fet.geometry()->type() != QGis::UnknownGeometry )
873  {
874  QgsRectangle bb = fet.geometry()->boundingBox();
875  rect.combineExtentWith( &bb );
876  }
877  }
878  }
879 
880  if ( rect.xMinimum() > rect.xMaximum() && rect.yMinimum() > rect.yMaximum() )
881  {
882  // special case when there are no features in provider nor any added
883  rect = QgsRectangle(); // use rectangle with zero coordinates
884  }
885 
886  setExtent( rect );
887 
888  // Send this (hopefully) up the chain to the map canvas
889  emit recalculateExtents();
890 
891  return rect;
892 }
893 
895 {
896  if ( ! mDataProvider )
897  {
898  QgsDebugMsg( "invoked with null mDataProvider" );
899  return 0;
900  }
901  return mDataProvider->subsetString();
902 }
903 
904 bool QgsVectorLayer::setSubsetString( QString subset )
905 {
906  if ( ! mDataProvider )
907  {
908  QgsDebugMsg( "invoked with null mDataProvider" );
909  return false;
910  }
911 
912  bool res = mDataProvider->setSubsetString( subset );
913 
914  // get the updated data source string from the provider
915  mDataSource = mDataProvider->dataSourceUri();
916  updateExtents();
917 
918  if ( res )
919  emit repaintRequested();
920 
921  return res;
922 }
923 
925 {
926  if ( mDataProvider && !mEditBuffer && ( hasGeometryType() && geometryType() != QGis::Point ) && ( mSimplifyMethod.simplifyHints() & simplifyHint ) && renderContext.useRenderingOptimization() )
927  {
928  double maximumSimplificationScale = mSimplifyMethod.maximumScale();
929 
930  // check maximum scale at which generalisation should be carried out
931  if ( maximumSimplificationScale > 1 && renderContext.rendererScale() <= maximumSimplificationScale )
932  return false;
933 
934  return true;
935  }
936  return false;
937 }
938 
940 {
941  if ( !mDataProvider )
942  return QgsFeatureIterator();
943 
944  return QgsFeatureIterator( new QgsVectorLayerFeatureIterator( new QgsVectorLayerFeatureSource( this ), true, request ) );
945 }
946 
947 
948 bool QgsVectorLayer::addFeature( QgsFeature& f, bool alsoUpdateExtent )
949 {
950  Q_UNUSED( alsoUpdateExtent ); // TODO[MD]
951  if ( !mEditBuffer || !mDataProvider )
952  return false;
953 
954  bool success = mEditBuffer->addFeature( f );
955 
956  if ( success )
957  updateExtents();
958 
959  return success;
960 }
961 
963 {
964  QgsFeatureRequest req;
965  req.setFilterFid( f.id() );
966  if ( !f.geometry() )
968  if ( f.attributes().isEmpty() )
970 
971  QgsFeature current;
972  if ( !getFeatures( req ).nextFeature( current ) )
973  {
974  QgsDebugMsg( QString( "feature %1 could not be retrieved" ).arg( f.id() ) );
975  return false;
976  }
977 
978  if ( f.geometry() && current.geometry() && f.geometry() != current.geometry() && !f.geometry()->isGeosEqual( *current.geometry() ) )
979  {
980  if ( !changeGeometry( f.id(), f.geometry() ) )
981  {
982  QgsDebugMsg( QString( "geometry of feature %1 could not be changed." ).arg( f.id() ) );
983  return false;
984  }
985  }
986 
987  const QgsAttributes &fa = f.attributes();
988  const QgsAttributes &ca = current.attributes();
989 
990  for ( int attr = 0; attr < fa.count(); ++attr )
991  {
992  if ( fa[attr] != ca[attr] )
993  {
994  if ( !changeAttributeValue( f.id(), attr, fa[attr], ca[attr] ) )
995  {
996  QgsDebugMsg( QString( "attribute %1 of feature %2 could not be changed." ).arg( attr ).arg( f.id() ) );
997  return false;
998  }
999  }
1000  }
1001 
1002  return true;
1003 }
1004 
1005 
1006 bool QgsVectorLayer::insertVertex( double x, double y, QgsFeatureId atFeatureId, int beforeVertex )
1007 {
1008  if ( !mEditBuffer || !mDataProvider )
1009  return false;
1010 
1011  QgsVectorLayerEditUtils utils( this );
1012  return utils.insertVertex( x, y, atFeatureId, beforeVertex );
1013 }
1014 
1015 
1016 bool QgsVectorLayer::moveVertex( double x, double y, QgsFeatureId atFeatureId, int atVertex )
1017 {
1018  if ( !mEditBuffer || !mDataProvider )
1019  return false;
1020 
1021  QgsVectorLayerEditUtils utils( this );
1022  return utils.moveVertex( x, y, atFeatureId, atVertex );
1023 }
1024 
1025 
1026 bool QgsVectorLayer::deleteVertex( QgsFeatureId atFeatureId, int atVertex )
1027 {
1028  if ( !mEditBuffer || !mDataProvider )
1029  return false;
1030 
1031  QgsVectorLayerEditUtils utils( this );
1032  return utils.deleteVertex( atFeatureId, atVertex );
1033 }
1034 
1035 
1037 {
1038  if ( !( mDataProvider->capabilities() & QgsVectorDataProvider::DeleteFeatures ) )
1039  {
1040  return false;
1041  }
1042 
1043  if ( !isEditable() )
1044  {
1045  return false;
1046  }
1047 
1048  int deleted = 0;
1049  int count = mSelectedFeatureIds.size();
1050  // Make a copy since deleteFeature modifies mSelectedFeatureIds
1051  QgsFeatureIds selectedFeatures( mSelectedFeatureIds );
1052  foreach ( QgsFeatureId fid, selectedFeatures )
1053  {
1054  deleted += deleteFeature( fid ); // removes from selection
1055  }
1056 
1057  triggerRepaint();
1058  updateExtents();
1059 
1060  if ( deletedCount )
1061  {
1062  *deletedCount = deleted;
1063  }
1064 
1065  return deleted == count;
1066 }
1067 
1068 int QgsVectorLayer::addRing( const QList<QgsPoint>& ring )
1069 {
1070  if ( !mEditBuffer || !mDataProvider )
1071  return 6;
1072 
1073  QgsVectorLayerEditUtils utils( this );
1074  return utils.addRing( ring );
1075 }
1076 
1077 int QgsVectorLayer::addPart( const QList<QgsPoint> &points )
1078 {
1079  if ( !mEditBuffer || !mDataProvider )
1080  return 7;
1081 
1082  //number of selected features must be 1
1083 
1084  if ( mSelectedFeatureIds.size() < 1 )
1085  {
1086  QgsDebugMsg( "Number of selected features <1" );
1087  return 4;
1088  }
1089  else if ( mSelectedFeatureIds.size() > 1 )
1090  {
1091  QgsDebugMsg( "Number of selected features >1" );
1092  return 5;
1093  }
1094 
1095  QgsVectorLayerEditUtils utils( this );
1096  return utils.addPart( points, *mSelectedFeatureIds.constBegin() );
1097 }
1098 
1099 
1100 int QgsVectorLayer::translateFeature( QgsFeatureId featureId, double dx, double dy )
1101 {
1102  if ( !mEditBuffer || !mDataProvider )
1103  return -1;
1104 
1105  QgsVectorLayerEditUtils utils( this );
1106  return utils.translateFeature( featureId, dx, dy );
1107 }
1108 
1109 int QgsVectorLayer::splitParts( const QList<QgsPoint>& splitLine, bool topologicalEditing )
1110 {
1111  if ( !mEditBuffer || !mDataProvider )
1112  return -1;
1113 
1114  QgsVectorLayerEditUtils utils( this );
1115  return utils.splitParts( splitLine, topologicalEditing );
1116 }
1117 
1118 int QgsVectorLayer::splitFeatures( const QList<QgsPoint>& splitLine, bool topologicalEditing )
1119 {
1120  if ( !mEditBuffer || !mDataProvider )
1121  return -1;
1122 
1123  QgsVectorLayerEditUtils utils( this );
1124  return utils.splitFeatures( splitLine, topologicalEditing );
1125 }
1126 
1128 {
1129  if ( !hasGeometryType() )
1130  return 1;
1131 
1132  int returnValue = 0;
1133 
1134  //first test if geom really has type polygon or multipolygon
1135  if ( geom->type() != QGis::Polygon )
1136  {
1137  return 1;
1138  }
1139 
1140  //get bounding box of geom
1141  QgsRectangle geomBBox = geom->boundingBox();
1142 
1143  //get list of features that intersect this bounding box
1145  .setFilterRect( geomBBox )
1147  .setSubsetOfAttributes( QgsAttributeList() ) );
1148 
1149  QgsFeature f;
1150  while ( fit.nextFeature( f ) )
1151  {
1152  if ( ignoreFeatures.contains( f.id() ) )
1153  {
1154  continue;
1155  }
1156 
1157  //call geometry->makeDifference for each feature
1158  QgsGeometry *currentGeom = f.geometry();
1159  if ( currentGeom )
1160  {
1161  if ( geom->makeDifference( currentGeom ) != 0 )
1162  {
1163  returnValue = 2;
1164  }
1165  }
1166  }
1167 
1168  return returnValue;
1169 }
1170 
1172 {
1173  if ( !mEditBuffer || !mDataProvider )
1174  return -1;
1175 
1176  QgsVectorLayerEditUtils utils( this );
1177  return utils.addTopologicalPoints( geom );
1178 }
1179 
1181 {
1182  if ( !mEditBuffer || !mDataProvider )
1183  return -1;
1184 
1185  QgsVectorLayerEditUtils utils( this );
1186  return utils.addTopologicalPoints( p );
1187 }
1188 
1190 {
1191  return mLabel;
1192 }
1193 
1195 {
1196  return mLabel;
1197 }
1198 
1200 {
1201  mLabelOn = on;
1202 }
1203 
1205 {
1206  return mLabelOn;
1207 }
1208 
1210 {
1211  if ( !mDataProvider )
1212  {
1213  return false;
1214  }
1215 
1216  // allow editing if provider supports any of the capabilities
1217  if ( !( mDataProvider->capabilities() & QgsVectorDataProvider::EditingCapabilities ) )
1218  {
1219  return false;
1220  }
1221 
1222  if ( mReadOnly )
1223  {
1224  return false;
1225  }
1226 
1227  if ( mEditBuffer )
1228  {
1229  // editing already underway
1230  return false;
1231  }
1232 
1233  if ( mDataProvider->transaction() )
1234  {
1235  mEditBuffer = new QgsVectorLayerEditPassthrough( this );
1236  }
1237  else
1238  {
1239  mEditBuffer = new QgsVectorLayerEditBuffer( this );
1240  }
1241  // forward signals
1242  connect( mEditBuffer, SIGNAL( layerModified() ), this, SLOT( invalidateSymbolCountedFlag() ) );
1243  connect( mEditBuffer, SIGNAL( layerModified() ), this, SIGNAL( layerModified() ) ); // TODO[MD]: necessary?
1244  //connect( mEditBuffer, SIGNAL( layerModified() ), this, SLOT( triggerRepaint() ) ); // TODO[MD]: works well?
1245  connect( mEditBuffer, SIGNAL( featureAdded( QgsFeatureId ) ), this, SIGNAL( featureAdded( QgsFeatureId ) ) );
1246  connect( mEditBuffer, SIGNAL( featureDeleted( QgsFeatureId ) ), this, SIGNAL( featureDeleted( QgsFeatureId ) ) );
1247  connect( mEditBuffer, SIGNAL( geometryChanged( QgsFeatureId, QgsGeometry& ) ), this, SIGNAL( geometryChanged( QgsFeatureId, QgsGeometry& ) ) );
1248  connect( mEditBuffer, SIGNAL( attributeValueChanged( QgsFeatureId, int, QVariant ) ), this, SIGNAL( attributeValueChanged( QgsFeatureId, int, QVariant ) ) );
1249  connect( mEditBuffer, SIGNAL( attributeAdded( int ) ), this, SIGNAL( attributeAdded( int ) ) );
1250  connect( mEditBuffer, SIGNAL( attributeDeleted( int ) ), this, SIGNAL( attributeDeleted( int ) ) );
1251 
1252  connect( mEditBuffer, SIGNAL( committedAttributesDeleted( const QString &, const QgsAttributeList & ) ),
1253  this, SIGNAL( committedAttributesDeleted( const QString &, const QgsAttributeList & ) ) );
1254 
1255  connect( mEditBuffer, SIGNAL( committedAttributesAdded( const QString &, const QList<QgsField> & ) ),
1256  this, SIGNAL( committedAttributesAdded( const QString &, const QList<QgsField> & ) ) );
1257 
1258  connect( mEditBuffer, SIGNAL( committedFeaturesAdded( QString, QgsFeatureList ) ), this, SIGNAL( committedFeaturesAdded( QString, QgsFeatureList ) ) );
1259  connect( mEditBuffer, SIGNAL( committedFeaturesRemoved( QString, QgsFeatureIds ) ), this, SIGNAL( committedFeaturesRemoved( QString, QgsFeatureIds ) ) );
1260 
1261  connect( mEditBuffer, SIGNAL( committedAttributeValuesChanges( const QString &, const QgsChangedAttributesMap & ) ),
1262  this, SIGNAL( committedAttributeValuesChanges( const QString &, const QgsChangedAttributesMap & ) ) );
1263 
1264  connect( mEditBuffer, SIGNAL( committedGeometriesChanges( const QString &, const QgsGeometryMap & ) ),
1265  this, SIGNAL( committedGeometriesChanges( const QString &, const QgsGeometryMap & ) ) );
1266 
1267  updateFields();
1268 
1269  emit editingStarted();
1270 
1271  return true;
1272 }
1273 
1274 bool QgsVectorLayer::readXml( const QDomNode& layer_node )
1275 {
1276  QgsDebugMsg( QString( "Datasource in QgsVectorLayer::readXml: " ) + mDataSource.toLocal8Bit().data() );
1277 
1278  //process provider key
1279  QDomNode pkeyNode = layer_node.namedItem( "provider" );
1280 
1281  if ( pkeyNode.isNull() )
1282  {
1283  mProviderKey = "";
1284  }
1285  else
1286  {
1287  QDomElement pkeyElt = pkeyNode.toElement();
1288  mProviderKey = pkeyElt.text();
1289  }
1290 
1291  // determine type of vector layer
1292  if ( ! mProviderKey.isNull() )
1293  {
1294  // if the provider string isn't empty, then we successfully
1295  // got the stored provider
1296  }
1297  else if ( mDataSource.contains( "dbname=" ) )
1298  {
1299  mProviderKey = "postgres";
1300  }
1301  else
1302  {
1303  mProviderKey = "ogr";
1304  }
1305 
1306  if ( ! setDataProvider( mProviderKey ) )
1307  {
1308  return false;
1309  }
1310 
1311  QDomElement pkeyElem = pkeyNode.toElement();
1312  if ( !pkeyElem.isNull() )
1313  {
1314  QString encodingString = pkeyElem.attribute( "encoding" );
1315  if ( !encodingString.isEmpty() )
1316  {
1317  mDataProvider->setEncoding( encodingString );
1318  }
1319  }
1320 
1321  //load vector joins
1322  if ( !mJoinBuffer )
1323  {
1324  mJoinBuffer = new QgsVectorLayerJoinBuffer( this );
1325  connect( mJoinBuffer, SIGNAL( joinedFieldsChanged() ), this, SLOT( onJoinedFieldsChanged() ) );
1326  }
1327  mJoinBuffer->readXml( layer_node );
1328 
1329  if ( !mExpressionFieldBuffer )
1330  mExpressionFieldBuffer = new QgsExpressionFieldBuffer();
1331  mExpressionFieldBuffer->readXml( layer_node );
1332 
1333  updateFields();
1334  connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( checkJoinLayerRemove( QString ) ) );
1335 
1336  QDomNode prevExpNode = layer_node.namedItem( "previewExpression" );
1337 
1338  if ( prevExpNode.isNull() )
1339  {
1340  mDisplayExpression = "";
1341  }
1342  else
1343  {
1344  QDomElement prevExpElem = prevExpNode.toElement();
1345  mDisplayExpression = prevExpElem.text();
1346  }
1347 
1348  QString errorMsg;
1349  if ( !readSymbology( layer_node, errorMsg ) )
1350  {
1351  return false;
1352  }
1353 
1354  readStyleManager( layer_node );
1355 
1357 
1358  return mValid; // should be true if read successfully
1359 
1360 } // void QgsVectorLayer::readXml
1361 
1362 
1363 bool QgsVectorLayer::setDataProvider( QString const & provider )
1364 {
1365  // XXX should I check for and possibly delete any pre-existing providers?
1366  // XXX How often will that scenario occur?
1367 
1368  mProviderKey = provider; // XXX is this necessary? Usually already set
1369  // XXX when execution gets here.
1370 
1371  //XXX - This was a dynamic cast but that kills the Windows
1372  // version big-time with an abnormal termination error
1373  mDataProvider =
1375 
1376  if ( mDataProvider )
1377  {
1378  QgsDebugMsg( "Instantiated the data provider plugin" );
1379 
1380  mValid = mDataProvider->isValid();
1381  if ( mValid )
1382  {
1383  // TODO: Check if the provider has the capability to send fullExtentCalculated
1384  connect( mDataProvider, SIGNAL( fullExtentCalculated() ), this, SLOT( updateExtents() ) );
1385 
1386  // get and store the feature type
1387  mWkbType = mDataProvider->geometryType();
1388 
1389  mJoinBuffer = new QgsVectorLayerJoinBuffer( this );
1390  connect( mJoinBuffer, SIGNAL( joinedFieldsChanged() ), this, SLOT( onJoinedFieldsChanged() ) );
1391  mExpressionFieldBuffer = new QgsExpressionFieldBuffer();
1392  updateFields();
1393 
1394  // look at the fields in the layer and set the primary
1395  // display field using some real fuzzy logic
1396  setDisplayField();
1397 
1398  if ( mProviderKey == "postgres" )
1399  {
1400  QgsDebugMsg( "Beautifying layer name " + name() );
1401 
1402  // adjust the display name for postgres layers
1403  QRegExp reg( "\"[^\"]+\"\\.\"([^\"]+)\"( \\([^)]+\\))?" );
1404  if ( reg.indexIn( name() ) >= 0 )
1405  {
1406  QStringList stuff = reg.capturedTexts();
1407  QString lName = stuff[1];
1408 
1409  const QMap<QString, QgsMapLayer*> &layers = QgsMapLayerRegistry::instance()->mapLayers();
1410 
1411  QMap<QString, QgsMapLayer*>::const_iterator it;
1412  for ( it = layers.constBegin(); it != layers.constEnd() && ( *it )->name() != lName; ++it )
1413  ;
1414 
1415  if ( it != layers.constEnd() && stuff.size() > 2 )
1416  {
1417  lName += "." + stuff[2].mid( 2, stuff[2].length() - 3 );
1418  }
1419 
1420  if ( !lName.isEmpty() )
1421  setLayerName( lName );
1422  }
1423 
1424  QgsDebugMsg( "Beautified layer name " + name() );
1425 
1426  // deal with unnecessary schema qualification to make v.in.ogr happy
1427  mDataSource = mDataProvider->dataSourceUri();
1428  }
1429  else if ( mProviderKey == "osm" )
1430  {
1431  // make sure that the "observer" has been removed from URI to avoid crashes
1432  mDataSource = mDataProvider->dataSourceUri();
1433  }
1434  else if ( provider == "ogr" )
1435  {
1436  // make sure that the /vsigzip or /vsizip is added to uri, if applicable
1437  mDataSource = mDataProvider->dataSourceUri();
1438  if ( mDataSource.right( 10 ) == "|layerid=0" )
1439  mDataSource.chop( 10 );
1440  }
1441 
1442  // label
1443  mLabel = new QgsLabel( mDataProvider->fields() );
1444  mLabelOn = false;
1445  }
1446  else
1447  {
1448  QgsDebugMsg( "Invalid provider plugin " + QString( mDataSource.toUtf8() ) );
1449  return false;
1450  }
1451  }
1452  else
1453  {
1454  QgsDebugMsg( " unable to get data provider" );
1455  return false;
1456  }
1457 
1458  return true;
1459 
1460 } // QgsVectorLayer:: setDataProvider
1461 
1462 
1463 
1464 
1465 /* virtual */
1466 bool QgsVectorLayer::writeXml( QDomNode & layer_node,
1467  QDomDocument & document )
1468 {
1469  // first get the layer element so that we can append the type attribute
1470 
1471  QDomElement mapLayerNode = layer_node.toElement();
1472 
1473  if ( mapLayerNode.isNull() || ( "maplayer" != mapLayerNode.nodeName() ) )
1474  {
1475  QgsDebugMsg( "can't find <maplayer>" );
1476  return false;
1477  }
1478 
1479  mapLayerNode.setAttribute( "type", "vector" );
1480 
1481  // set the geometry type
1482  mapLayerNode.setAttribute( "geometry", QGis::vectorGeometryType( geometryType() ) );
1483 
1484  // add provider node
1485  if ( mDataProvider )
1486  {
1487  QDomElement provider = document.createElement( "provider" );
1488  provider.setAttribute( "encoding", mDataProvider->encoding() );
1489  QDomText providerText = document.createTextNode( providerType() );
1490  provider.appendChild( providerText );
1491  layer_node.appendChild( provider );
1492  }
1493 
1494  // save preview expression
1495  QDomElement prevExpElem = document.createElement( "previewExpression" );
1496  QDomText prevExpText = document.createTextNode( mDisplayExpression );
1497  prevExpElem.appendChild( prevExpText );
1498  layer_node.appendChild( prevExpElem );
1499 
1500  //save joins
1501  mJoinBuffer->writeXml( layer_node, document );
1502 
1503  // save expression fields
1504  mExpressionFieldBuffer->writeXml( layer_node, document );
1505 
1506  writeStyleManager( layer_node, document );
1507 
1508  // renderer specific settings
1509  QString errorMsg;
1510  return writeSymbology( layer_node, document, errorMsg );
1511 } // bool QgsVectorLayer::writeXml
1512 
1513 bool QgsVectorLayer::readSymbology( const QDomNode& node, QString& errorMessage )
1514 {
1515  emit readCustomSymbology( node.toElement(), errorMessage );
1516 
1517  if ( hasGeometryType() )
1518  {
1519  // try renderer v2 first
1520  QDomElement rendererElement = node.firstChildElement( RENDERER_TAG_NAME );
1521  if ( !rendererElement.isNull() )
1522  {
1523  QgsFeatureRendererV2* r = QgsFeatureRendererV2::load( rendererElement );
1524  if ( !r )
1525  return false;
1526 
1527  setRendererV2( r );
1528  }
1529  else
1530  {
1532  if ( !r )
1534 
1535  setRendererV2( r );
1536  }
1537 
1538  // get and set the display field if it exists.
1539  QDomNode displayFieldNode = node.namedItem( "displayfield" );
1540  if ( !displayFieldNode.isNull() )
1541  {
1542  QDomElement e = displayFieldNode.toElement();
1543  setDisplayField( e.text() );
1544  }
1545 
1546  // get and set the blend mode if it exists
1547  QDomNode blendModeNode = node.namedItem( "blendMode" );
1548  if ( !blendModeNode.isNull() )
1549  {
1550  QDomElement e = blendModeNode.toElement();
1552  }
1553 
1554  // get and set the feature blend mode if it exists
1555  QDomNode featureBlendModeNode = node.namedItem( "featureBlendMode" );
1556  if ( !featureBlendModeNode.isNull() )
1557  {
1558  QDomElement e = featureBlendModeNode.toElement();
1560  }
1561 
1562  // get and set the layer transparency if it exists
1563  QDomNode layerTransparencyNode = node.namedItem( "layerTransparency" );
1564  if ( !layerTransparencyNode.isNull() )
1565  {
1566  QDomElement e = layerTransparencyNode.toElement();
1567  setLayerTransparency( e.text().toInt() );
1568  }
1569 
1570  // use scale dependent visibility flag
1571  QDomElement e = node.toElement();
1572  if ( mLabel )
1573  {
1574  mLabel->setScaleBasedVisibility( e.attribute( "scaleBasedLabelVisibilityFlag", "0" ) == "1" );
1575  mLabel->setMinScale( e.attribute( "minLabelScale", "1" ).toFloat() );
1576  mLabel->setMaxScale( e.attribute( "maxLabelScale", "100000000" ).toFloat() );
1577  }
1578 
1579  // get the simplification drawing settings
1580  mSimplifyMethod.setSimplifyHints(( QgsVectorSimplifyMethod::SimplifyHints ) e.attribute( "simplifyDrawingHints", "1" ).toInt() );
1581  mSimplifyMethod.setThreshold( e.attribute( "simplifyDrawingTol", "1" ).toFloat() );
1582  mSimplifyMethod.setForceLocalOptimization( e.attribute( "simplifyLocal", "1" ).toInt() );
1583  mSimplifyMethod.setMaximumScale( e.attribute( "simplifyMaxScale", "1" ).toFloat() );
1584 
1585  //also restore custom properties (for labeling-ng)
1586  readCustomProperties( node, "labeling" );
1587 
1588  // Test if labeling is on or off
1589  QDomNode labelnode = node.namedItem( "label" );
1590  QDomElement element = labelnode.toElement();
1591  int hasLabelsEnabled = element.text().toInt();
1592  if ( hasLabelsEnabled < 1 )
1593  {
1594  enableLabels( false );
1595  }
1596  else
1597  {
1598  enableLabels( true );
1599  }
1600 
1601  QDomNode labelattributesnode = node.namedItem( "labelattributes" );
1602 
1603  if ( !labelattributesnode.isNull() && mLabel )
1604  {
1605  QgsDebugMsg( "calling readXML" );
1606  mLabel->readXML( labelattributesnode );
1607  }
1608 
1609  //diagram renderer and diagram layer settings
1610  delete mDiagramRenderer; mDiagramRenderer = 0;
1611  QDomElement singleCatDiagramElem = node.firstChildElement( "SingleCategoryDiagramRenderer" );
1612  if ( !singleCatDiagramElem.isNull() )
1613  {
1614  mDiagramRenderer = new QgsSingleCategoryDiagramRenderer();
1615  mDiagramRenderer->readXML( singleCatDiagramElem, this );
1616  }
1617  QDomElement linearDiagramElem = node.firstChildElement( "LinearlyInterpolatedDiagramRenderer" );
1618  if ( !linearDiagramElem.isNull() )
1619  {
1620  mDiagramRenderer = new QgsLinearlyInterpolatedDiagramRenderer();
1621  mDiagramRenderer->readXML( linearDiagramElem, this );
1622  }
1623 
1624  if ( mDiagramRenderer )
1625  {
1626  QDomElement diagramSettingsElem = node.firstChildElement( "DiagramLayerSettings" );
1627  if ( !diagramSettingsElem.isNull() )
1628  {
1629  mDiagramLayerSettings = new QgsDiagramLayerSettings();
1630  mDiagramLayerSettings->readXML( diagramSettingsElem, this );
1631  }
1632  }
1633  }
1634 
1635  // process the attribute actions
1636  mActions->readXML( node );
1637 
1638 
1639  QDomNode editFormNode = node.namedItem( "editform" );
1640  if ( !editFormNode.isNull() )
1641  {
1642  QDomElement e = editFormNode.toElement();
1643  mEditForm = QgsProject::instance()->readPath( e.text() );
1644  }
1645 
1646  QDomNode editFormInitNode = node.namedItem( "editforminit" );
1647  if ( !editFormInitNode.isNull() )
1648  {
1649  mEditFormInit = editFormInitNode.toElement().text();
1650  }
1651 
1652  QDomNode fFSuppNode = node.namedItem( "featformsuppress" );
1653  if ( fFSuppNode.isNull() )
1654  {
1655  mFeatureFormSuppress = SuppressDefault;
1656  }
1657  else
1658  {
1659  QDomElement e = fFSuppNode.toElement();
1660  mFeatureFormSuppress = ( QgsVectorLayer::FeatureFormSuppress )e.text().toInt();
1661  }
1662 
1663  QDomNode annotationFormNode = node.namedItem( "annotationform" );
1664  if ( !annotationFormNode.isNull() )
1665  {
1666  QDomElement e = annotationFormNode.toElement();
1667  mAnnotationForm = QgsProject::instance()->readPath( e.text() );
1668  }
1669 
1670  mAttributeAliasMap.clear();
1671  QDomNode aliasesNode = node.namedItem( "aliases" );
1672  if ( !aliasesNode.isNull() )
1673  {
1674  QDomElement aliasElem;
1675 
1676  QDomNodeList aliasNodeList = aliasesNode.toElement().elementsByTagName( "alias" );
1677  for ( int i = 0; i < aliasNodeList.size(); ++i )
1678  {
1679  aliasElem = aliasNodeList.at( i ).toElement();
1680 
1681  QString field;
1682  if ( aliasElem.hasAttribute( "field" ) )
1683  {
1684  field = aliasElem.attribute( "field" );
1685  }
1686  else
1687  {
1688  int index = aliasElem.attribute( "index" ).toInt();
1689 
1690  if ( index >= 0 && index < pendingFields().count() )
1691  field = pendingFields()[ index ].name();
1692  }
1693 
1694  mAttributeAliasMap.insert( field, aliasElem.attribute( "name" ) );
1695  }
1696  }
1697 
1698  // tab display
1699  QDomNode editorLayoutNode = node.namedItem( "editorlayout" );
1700  if ( editorLayoutNode.isNull() )
1701  {
1702  mEditorLayout = GeneratedLayout;
1703  }
1704  else
1705  {
1706  if ( editorLayoutNode.toElement().text() == "uifilelayout" )
1707  {
1708  mEditorLayout = UiFileLayout;
1709  }
1710  else if ( editorLayoutNode.toElement().text() == "tablayout" )
1711  {
1712  mEditorLayout = TabLayout;
1713  }
1714  else
1715  {
1716  mEditorLayout = GeneratedLayout;
1717  }
1718  }
1719 
1720  //Attributes excluded from WMS and WFS
1721  mExcludeAttributesWMS.clear();
1722  QDomNode excludeWMSNode = node.namedItem( "excludeAttributesWMS" );
1723  if ( !excludeWMSNode.isNull() )
1724  {
1725  QDomNodeList attributeNodeList = excludeWMSNode.toElement().elementsByTagName( "attribute" );
1726  for ( int i = 0; i < attributeNodeList.size(); ++i )
1727  {
1728  mExcludeAttributesWMS.insert( attributeNodeList.at( i ).toElement().text() );
1729  }
1730  }
1731 
1732  mExcludeAttributesWFS.clear();
1733  QDomNode excludeWFSNode = node.namedItem( "excludeAttributesWFS" );
1734  if ( !excludeWFSNode.isNull() )
1735  {
1736  QDomNodeList attributeNodeList = excludeWFSNode.toElement().elementsByTagName( "attribute" );
1737  for ( int i = 0; i < attributeNodeList.size(); ++i )
1738  {
1739  mExcludeAttributesWFS.insert( attributeNodeList.at( i ).toElement().text() );
1740  }
1741  }
1742 
1743  // tabs and groups display info
1744  mAttributeEditorElements.clear();
1745  QDomNode attributeEditorFormNode = node.namedItem( "attributeEditorForm" );
1746  QDomNodeList attributeEditorFormNodeList = attributeEditorFormNode.toElement().childNodes();
1747 
1748  for ( int i = 0; i < attributeEditorFormNodeList.size(); i++ )
1749  {
1750  QDomElement elem = attributeEditorFormNodeList.at( i ).toElement();
1751 
1752  QgsAttributeEditorElement *attributeEditorWidget = attributeEditorElementFromDomElement( elem, this );
1753  mAttributeEditorElements.append( attributeEditorWidget );
1754  }
1755 
1756  return true;
1757 }
1758 
1760 {
1761  QgsAttributeEditorElement* newElement = NULL;
1762 
1763  if ( elem.tagName() == "attributeEditorContainer" )
1764  {
1765  QgsAttributeEditorContainer* container = new QgsAttributeEditorContainer( elem.attribute( "name" ), parent );
1766 
1767  QDomNodeList childNodeList = elem.childNodes();
1768 
1769  for ( int i = 0; i < childNodeList.size(); i++ )
1770  {
1771  QDomElement childElem = childNodeList.at( i ).toElement();
1772  QgsAttributeEditorElement *myElem = attributeEditorElementFromDomElement( childElem, container );
1773  if ( myElem )
1774  container->addChildElement( myElem );
1775  }
1776 
1777  newElement = container;
1778  }
1779  else if ( elem.tagName() == "attributeEditorField" )
1780  {
1781  QString name = elem.attribute( "name" );
1782  int idx = fieldNameIndex( name );
1783  newElement = new QgsAttributeEditorField( name, idx, parent );
1784  }
1785  else if ( elem.tagName() == "attributeEditorRelation" )
1786  {
1787  // At this time, the relations are not loaded
1788  // So we only grab the id and delegate the rest to onRelationsLoaded()
1789  QString name = elem.attribute( "name" );
1790  newElement = new QgsAttributeEditorRelation( name, elem.attribute( "relation", "[None]" ), parent );
1791  }
1792  return newElement;
1793 }
1794 
1795 bool QgsVectorLayer::writeSymbology( QDomNode& node, QDomDocument& doc, QString& errorMessage ) const
1796 {
1797  QDomElement mapLayerNode = node.toElement();
1798 
1799  emit writeCustomSymbology( mapLayerNode, doc, errorMessage );
1800 
1801  if ( hasGeometryType() )
1802  {
1803  QDomElement rendererElement = mRendererV2->save( doc );
1804  node.appendChild( rendererElement );
1805 
1806  // use scale dependent visibility flag
1807  if ( mLabel )
1808  {
1809  mapLayerNode.setAttribute( "scaleBasedLabelVisibilityFlag", mLabel->scaleBasedVisibility() ? 1 : 0 );
1810  mapLayerNode.setAttribute( "minLabelScale", QString::number( mLabel->minScale() ) );
1811  mapLayerNode.setAttribute( "maxLabelScale", QString::number( mLabel->maxScale() ) );
1812  }
1813 
1814  // save the simplification drawing settings
1815  mapLayerNode.setAttribute( "simplifyDrawingHints", QString::number( mSimplifyMethod.simplifyHints() ) );
1816  mapLayerNode.setAttribute( "simplifyDrawingTol", QString::number( mSimplifyMethod.threshold() ) );
1817  mapLayerNode.setAttribute( "simplifyLocal", mSimplifyMethod.forceLocalOptimization() ? 1 : 0 );
1818  mapLayerNode.setAttribute( "simplifyMaxScale", QString::number( mSimplifyMethod.maximumScale() ) );
1819 
1820  //save customproperties (for labeling ng)
1821  writeCustomProperties( node, doc );
1822 
1823  // add the blend mode field
1824  QDomElement blendModeElem = doc.createElement( "blendMode" );
1825  QDomText blendModeText = doc.createTextNode( QString::number( QgsMapRenderer::getBlendModeEnum( blendMode() ) ) );
1826  blendModeElem.appendChild( blendModeText );
1827  node.appendChild( blendModeElem );
1828 
1829  // add the feature blend mode field
1830  QDomElement featureBlendModeElem = doc.createElement( "featureBlendMode" );
1831  QDomText featureBlendModeText = doc.createTextNode( QString::number( QgsMapRenderer::getBlendModeEnum( featureBlendMode() ) ) );
1832  featureBlendModeElem.appendChild( featureBlendModeText );
1833  node.appendChild( featureBlendModeElem );
1834 
1835  // add the layer transparency
1836  QDomElement layerTransparencyElem = doc.createElement( "layerTransparency" );
1837  QDomText layerTransparencyText = doc.createTextNode( QString::number( layerTransparency() ) );
1838  layerTransparencyElem.appendChild( layerTransparencyText );
1839  node.appendChild( layerTransparencyElem );
1840 
1841  // add the display field
1842  QDomElement dField = doc.createElement( "displayfield" );
1843  QDomText dFieldText = doc.createTextNode( displayField() );
1844  dField.appendChild( dFieldText );
1845  node.appendChild( dField );
1846 
1847  // add label node
1848  QDomElement labelElem = doc.createElement( "label" );
1849  QDomText labelText = doc.createTextNode( "" );
1850 
1851  if ( hasLabelsEnabled() )
1852  {
1853  labelText.setData( "1" );
1854  }
1855  else
1856  {
1857  labelText.setData( "0" );
1858  }
1859  labelElem.appendChild( labelText );
1860 
1861  node.appendChild( labelElem );
1862 
1863  // Now we get to do all that all over again for QgsLabel
1864 
1865  if ( mLabel )
1866  {
1867  QString fieldname = mLabel->labelField( QgsLabel::Text );
1868  if ( fieldname != "" )
1869  {
1870  dField = doc.createElement( "labelfield" );
1871  dFieldText = doc.createTextNode( fieldname );
1872  dField.appendChild( dFieldText );
1873  node.appendChild( dField );
1874  }
1875 
1876  mLabel->writeXML( node, doc );
1877  }
1878 
1879  if ( mDiagramRenderer )
1880  {
1881  mDiagramRenderer->writeXML( mapLayerNode, doc, this );
1882  if ( mDiagramLayerSettings )
1883  mDiagramLayerSettings->writeXML( mapLayerNode, doc, this );
1884  }
1885  }
1886 
1887  // FIXME
1888  // edittypes are written to the layerNode
1889  // by slot QgsEditorWidgetRegistry::writeMapLayer()
1890  // triggered by signal QgsProject::writeMapLayer()
1891  // still other editing settings are written here,
1892  // although they are not part of symbology either
1893 
1894  QDomElement efField = doc.createElement( "editform" );
1895  QDomText efText = doc.createTextNode( QgsProject::instance()->writePath( mEditForm ) );
1896  efField.appendChild( efText );
1897  node.appendChild( efField );
1898 
1899  QDomElement efiField = doc.createElement( "editforminit" );
1900  if ( !mEditFormInit.isEmpty() )
1901  efiField.appendChild( doc.createTextNode( mEditFormInit ) );
1902  node.appendChild( efiField );
1903 
1904  QDomElement fFSuppElem = doc.createElement( "featformsuppress" );
1905  QDomText fFSuppText = doc.createTextNode( QString::number( featureFormSuppress() ) );
1906  fFSuppElem.appendChild( fFSuppText );
1907  node.appendChild( fFSuppElem );
1908 
1909  QDomElement afField = doc.createElement( "annotationform" );
1910  QDomText afText = doc.createTextNode( QgsProject::instance()->writePath( mAnnotationForm ) );
1911  afField.appendChild( afText );
1912  node.appendChild( afField );
1913 
1914  // tab display
1915  QDomElement editorLayoutElem = doc.createElement( "editorlayout" );
1916  switch ( mEditorLayout )
1917  {
1918  case UiFileLayout:
1919  editorLayoutElem.appendChild( doc.createTextNode( "uifilelayout" ) );
1920  break;
1921 
1922  case TabLayout:
1923  editorLayoutElem.appendChild( doc.createTextNode( "tablayout" ) );
1924  break;
1925 
1926  case GeneratedLayout:
1927  default:
1928  editorLayoutElem.appendChild( doc.createTextNode( "generatedlayout" ) );
1929  break;
1930  }
1931 
1932  node.appendChild( editorLayoutElem );
1933 
1934  //attribute aliases
1935  if ( mAttributeAliasMap.size() > 0 )
1936  {
1937  QDomElement aliasElem = doc.createElement( "aliases" );
1938  QMap<QString, QString>::const_iterator a_it = mAttributeAliasMap.constBegin();
1939  for ( ; a_it != mAttributeAliasMap.constEnd(); ++a_it )
1940  {
1941  int idx = fieldNameIndex( a_it.key() );
1942  if ( idx < 0 )
1943  continue;
1944 
1945  QDomElement aliasEntryElem = doc.createElement( "alias" );
1946  aliasEntryElem.setAttribute( "field", a_it.key() );
1947  aliasEntryElem.setAttribute( "index", idx );
1948  aliasEntryElem.setAttribute( "name", a_it.value() );
1949  aliasElem.appendChild( aliasEntryElem );
1950  }
1951  node.appendChild( aliasElem );
1952  }
1953 
1954  //exclude attributes WMS
1955  QDomElement excludeWMSElem = doc.createElement( "excludeAttributesWMS" );
1956  QSet<QString>::const_iterator attWMSIt = mExcludeAttributesWMS.constBegin();
1957  for ( ; attWMSIt != mExcludeAttributesWMS.constEnd(); ++attWMSIt )
1958  {
1959  QDomElement attrElem = doc.createElement( "attribute" );
1960  QDomText attrText = doc.createTextNode( *attWMSIt );
1961  attrElem.appendChild( attrText );
1962  excludeWMSElem.appendChild( attrElem );
1963  }
1964  node.appendChild( excludeWMSElem );
1965 
1966  //exclude attributes WFS
1967  QDomElement excludeWFSElem = doc.createElement( "excludeAttributesWFS" );
1968  QSet<QString>::const_iterator attWFSIt = mExcludeAttributesWFS.constBegin();
1969  for ( ; attWFSIt != mExcludeAttributesWFS.constEnd(); ++attWFSIt )
1970  {
1971  QDomElement attrElem = doc.createElement( "attribute" );
1972  QDomText attrText = doc.createTextNode( *attWFSIt );
1973  attrElem.appendChild( attrText );
1974  excludeWFSElem.appendChild( attrElem );
1975  }
1976  node.appendChild( excludeWFSElem );
1977 
1978  // tabs and groups of edit form
1979  if ( mAttributeEditorElements.size() > 0 )
1980  {
1981  QDomElement tabsElem = doc.createElement( "attributeEditorForm" );
1982 
1983  for ( QList< QgsAttributeEditorElement* >::const_iterator it = mAttributeEditorElements.begin(); it != mAttributeEditorElements.end(); ++it )
1984  {
1985  QDomElement attributeEditorWidgetElem = ( *it )->toDomElement( doc );
1986  tabsElem.appendChild( attributeEditorWidgetElem );
1987  }
1988 
1989  node.appendChild( tabsElem );
1990  }
1991 
1992  // add attribute actions
1993  mActions->writeXML( node, doc );
1994 
1995  return true;
1996 }
1997 
1998 bool QgsVectorLayer::readSld( const QDomNode& node, QString& errorMessage )
1999 {
2000  // get the Name element
2001  QDomElement nameElem = node.firstChildElement( "Name" );
2002  if ( nameElem.isNull() )
2003  {
2004  errorMessage = "Warning: Name element not found within NamedLayer while it's required.";
2005  }
2006 
2007  if ( hasGeometryType() )
2008  {
2009  QgsFeatureRendererV2* r = QgsFeatureRendererV2::loadSld( node, geometryType(), errorMessage );
2010  if ( !r )
2011  return false;
2012 
2013  setRendererV2( r );
2014 
2015  // labeling
2016  readSldLabeling( node );
2017  }
2018  return true;
2019 }
2020 
2021 
2022 bool QgsVectorLayer::writeSld( QDomNode& node, QDomDocument& doc, QString& errorMessage ) const
2023 {
2024  Q_UNUSED( errorMessage );
2025 
2026  // store the Name element
2027  QDomElement nameNode = doc.createElement( "se:Name" );
2028  nameNode.appendChild( doc.createTextNode( name() ) );
2029  node.appendChild( nameNode );
2030 
2031  if ( hasGeometryType() )
2032  {
2033  node.appendChild( mRendererV2->writeSld( doc, name() ) );
2034  }
2035  return true;
2036 }
2037 
2038 
2040 {
2041  if ( !mEditBuffer || !mDataProvider )
2042  {
2043  return false;
2044  }
2045 
2046  updateExtents();
2047 
2048  return mEditBuffer->changeGeometry( fid, geom );
2049 }
2050 
2051 
2052 bool QgsVectorLayer::changeAttributeValue( QgsFeatureId fid, int field, QVariant value, bool emitSignal )
2053 {
2054  Q_UNUSED( emitSignal );
2055  return changeAttributeValue( fid, field, value );
2056 }
2057 
2058 bool QgsVectorLayer::changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue )
2059 {
2060  if ( !mEditBuffer || !mDataProvider )
2061  return false;
2062 
2063  return mEditBuffer->changeAttributeValue( fid, field, newValue, oldValue );
2064 }
2065 
2067 {
2068  if ( !mEditBuffer || !mDataProvider )
2069  return false;
2070 
2071  return mEditBuffer->addAttribute( field );
2072 }
2073 
2075 {
2076  if ( attIndex < 0 || attIndex >= pendingFields().count() )
2077  return;
2078 
2079  QString name = pendingFields()[ attIndex ].name();
2080  if ( mAttributeAliasMap.contains( name ) )
2081  {
2082  mAttributeAliasMap.remove( name );
2083  emit layerModified();
2084  }
2085 }
2086 
2087 void QgsVectorLayer::addAttributeAlias( int attIndex, QString aliasString )
2088 {
2089  if ( attIndex < 0 || attIndex >= pendingFields().count() )
2090  return;
2091 
2092  QString name = pendingFields()[ attIndex ].name();
2093 
2094  mAttributeAliasMap.insert( name, aliasString );
2095  emit layerModified(); // TODO[MD]: should have a different signal?
2096 }
2097 
2099 {
2100  mAttributeEditorElements.append( data );
2101 }
2102 
2103 const QString QgsVectorLayer::editorWidgetV2( int fieldIdx ) const
2104 {
2105  if ( fieldIdx < 0 || fieldIdx >= mUpdatedFields.count() )
2106  return "TextEdit";
2107 
2108  return mEditorWidgetV2Types.value( mUpdatedFields[fieldIdx].name(), "TextEdit" );
2109 }
2110 
2111 const QString QgsVectorLayer::editorWidgetV2( const QString& fieldName ) const
2112 {
2113  return mEditorWidgetV2Types.value( fieldName, "TextEdit" );
2114 }
2115 
2117 {
2118  return mEditorWidgetV2Configs.value( mUpdatedFields[fieldIdx].name() );
2119 }
2120 
2121 const QgsEditorWidgetConfig QgsVectorLayer::editorWidgetV2Config( const QString& fieldName ) const
2122 {
2123  return mEditorWidgetV2Configs.value( fieldName );
2124 }
2125 
2126 QString QgsVectorLayer::attributeAlias( int attributeIndex ) const
2127 {
2128  if ( attributeIndex < 0 || attributeIndex >= pendingFields().count() )
2129  return "";
2130 
2131  QString name = pendingFields()[ attributeIndex ].name();
2132 
2133  return mAttributeAliasMap.value( name, "" );
2134 }
2135 
2136 QString QgsVectorLayer::attributeDisplayName( int attributeIndex ) const
2137 {
2138  QString displayName = attributeAlias( attributeIndex );
2139  if ( displayName.isEmpty() )
2140  {
2141  const QgsFields& fields = pendingFields();
2142  if ( attributeIndex >= 0 && attributeIndex < fields.count() )
2143  {
2144  displayName = fields[attributeIndex].name();
2145  }
2146  }
2147  return displayName;
2148 }
2149 
2151 {
2152  if ( index < 0 || index >= pendingFields().count() )
2153  return false;
2154 
2155  if ( mUpdatedFields.fieldOrigin( index ) == QgsFields::OriginExpression )
2156  {
2157  removeExpressionField( index );
2158  return true;
2159  }
2160 
2161  if ( !mEditBuffer || !mDataProvider )
2162  return false;
2163 
2164  return mEditBuffer->deleteAttribute( index );
2165 }
2166 
2167 bool QgsVectorLayer::deleteAttributes( QList<int> attrs )
2168 {
2169  bool deleted = false;
2170 
2171  // Remove multiple occurences of same attribute
2172  attrs = attrs.toSet().toList();
2173 
2174  qSort( attrs.begin(), attrs.end(), qGreater<int>() );
2175 
2176  Q_FOREACH ( int attr, attrs )
2177  {
2178  if ( deleteAttribute( attr ) )
2179  {
2180  deleted = true;
2181  }
2182  }
2183 
2184  return deleted;
2185 }
2186 
2188 {
2189  if ( !mEditBuffer )
2190  return false;
2191 
2192  bool res = mEditBuffer->deleteFeature( fid );
2193  if ( res )
2194  mSelectedFeatureIds.remove( fid ); // remove it from selection
2195 
2196  updateExtents();
2197 
2198  return res;
2199 }
2200 
2202 {
2203  return mUpdatedFields;
2204 }
2205 
2207 {
2208  return mUpdatedFields.allAttributesList();
2209 }
2210 
2212 {
2213  QgsAttributeList pkAttributesList;
2214 
2215  QgsAttributeList providerIndexes = mDataProvider->pkAttributeIndexes();
2216  for ( int i = 0; i < mUpdatedFields.count(); ++i )
2217  {
2218  if ( mUpdatedFields.fieldOrigin( i ) == QgsFields::OriginProvider &&
2219  providerIndexes.contains( mUpdatedFields.fieldOriginIndex( i ) ) )
2220  pkAttributesList << i;
2221  }
2222 
2223  return pkAttributesList;
2224 }
2225 
2227 {
2228  return mDataProvider->featureCount() +
2229  ( mEditBuffer ? mEditBuffer->mAddedFeatures.size() - mEditBuffer->mDeletedFeatureIds.size() : 0 );
2230 }
2231 
2233 {
2234  mCommitErrors.clear();
2235 
2236  if ( !mDataProvider )
2237  {
2238  mCommitErrors << tr( "ERROR: no provider" );
2239  return false;
2240  }
2241 
2242  if ( !mEditBuffer )
2243  {
2244  mCommitErrors << tr( "ERROR: layer not editable" );
2245  return false;
2246  }
2247 
2248  emit beforeCommitChanges();
2249 
2250  bool success = mEditBuffer->commitChanges( mCommitErrors );
2251 
2252  if ( success )
2253  {
2254  delete mEditBuffer;
2255  mEditBuffer = 0;
2256  undoStack()->clear();
2257  emit editingStopped();
2258  }
2259  else
2260  {
2261  QgsMessageLog::logMessage( tr( "Commit errors:\n %1" ).arg( mCommitErrors.join( "\n " ) ) );
2262  }
2263 
2264  if ( mCache )
2265  {
2266  mCache->deleteCachedGeometries();
2267  }
2268 
2269  updateFields();
2270  mDataProvider->updateExtents();
2271 
2272  emit repaintRequested();
2273 
2274  return success;
2275 }
2276 
2277 const QStringList &QgsVectorLayer::commitErrors()
2278 {
2279  return mCommitErrors;
2280 }
2281 
2282 bool QgsVectorLayer::rollBack( bool deleteBuffer )
2283 {
2284  if ( !mEditBuffer )
2285  {
2286  return false;
2287  }
2288 
2289  emit beforeRollBack();
2290 
2291  mEditBuffer->rollBack();
2292 
2293  if ( isModified() )
2294  {
2295  // new undo stack roll back method
2296  // old method of calling every undo could cause many canvas refreshes
2297  undoStack()->setIndex( 0 );
2298  }
2299 
2300  updateFields();
2301 
2302  if ( deleteBuffer )
2303  {
2304  delete mEditBuffer;
2305  mEditBuffer = 0;
2306  undoStack()->clear();
2307  }
2308  emit editingStopped();
2309 
2310  if ( mCache )
2311  {
2312  mCache->deleteCachedGeometries();
2313  }
2314 
2315  emit repaintRequested();
2316  return true;
2317 }
2318 
2320 {
2321  QgsFeatureIds deselectedFeatures = mSelectedFeatureIds - ids;
2322 
2323  mSelectedFeatureIds = ids;
2324 
2325  emit selectionChanged( ids, deselectedFeatures, true );
2326 }
2327 
2329 {
2330  return mSelectedFeatureIds.size();
2331 }
2332 
2334 {
2335  return mSelectedFeatureIds;
2336 }
2337 
2339 {
2340  QgsFeatureList features;
2341  QgsFeature f;
2342 
2343  if ( mSelectedFeatureIds.count() <= 8 )
2344  {
2345  // for small amount of selected features, fetch them directly
2346  // because request with FilterFids would go iterate over the whole layer
2347  foreach ( int fid, mSelectedFeatureIds )
2348  {
2349  getFeatures( QgsFeatureRequest( fid ) ).nextFeature( f );
2350  features << f;
2351  }
2352  }
2353  else
2354  {
2356 
2357  while ( it.nextFeature( f ) )
2358  {
2359  features.push_back( f );
2360  }
2361  }
2362 
2363  return features;
2364 }
2365 
2367 {
2368  if ( mSelectedFeatureIds.count() == 0 )
2369  return QgsFeatureIterator();
2370 
2371  if ( geometryType() == QGis::NoGeometry )
2373 
2374  if ( mSelectedFeatureIds.count() == 1 )
2375  request.setFilterFid( *mSelectedFeatureIds.constBegin() );
2376  else
2377  request.setFilterFids( mSelectedFeatureIds );
2378 
2379  return getFeatures( request );
2380 }
2381 
2382 bool QgsVectorLayer::addFeatures( QgsFeatureList features, bool makeSelected )
2383 {
2384  if ( !mEditBuffer || !mDataProvider )
2385  return false;
2386 
2387  bool res = mEditBuffer->addFeatures( features );
2388 
2389  if ( makeSelected )
2390  {
2391  QgsFeatureIds ids;
2392 
2393  for ( QgsFeatureList::iterator iter = features.begin(); iter != features.end(); ++iter )
2394  ids << iter->id();
2395 
2396  setSelectedFeatures( ids );
2397  }
2398 
2399  updateExtents();
2400 
2401  return res;
2402 }
2403 
2404 
2405 bool QgsVectorLayer::snapPoint( QgsPoint& point, double tolerance )
2406 {
2407  if ( !hasGeometryType() )
2408  return false;
2409 
2410  QMultiMap<double, QgsSnappingResult> snapResults;
2411  int result = snapWithContext( point, tolerance, snapResults, QgsSnapper::SnapToVertex );
2412 
2413  if ( result != 0 )
2414  {
2415  return false;
2416  }
2417 
2418  if ( snapResults.size() < 1 )
2419  {
2420  return false;
2421  }
2422 
2423  QMultiMap<double, QgsSnappingResult>::const_iterator snap_it = snapResults.constBegin();
2424  point.setX( snap_it.value().snappedVertex.x() );
2425  point.setY( snap_it.value().snappedVertex.y() );
2426  return true;
2427 }
2428 
2429 
2430 int QgsVectorLayer::snapWithContext( const QgsPoint& startPoint, double snappingTolerance,
2431  QMultiMap<double, QgsSnappingResult>& snappingResults,
2432  QgsSnapper::SnappingType snap_to )
2433 {
2434  if ( !hasGeometryType() )
2435  return 1;
2436 
2437  if ( snappingTolerance <= 0 || !mDataProvider )
2438  {
2439  return 1;
2440  }
2441 
2442  QList<QgsFeature> featureList;
2443  QgsRectangle searchRect( startPoint.x() - snappingTolerance, startPoint.y() - snappingTolerance,
2444  startPoint.x() + snappingTolerance, startPoint.y() + snappingTolerance );
2445  double sqrSnappingTolerance = snappingTolerance * snappingTolerance;
2446 
2447  int n = 0;
2448  QgsFeature f;
2449 
2450  if ( mCache->cachedGeometriesRect().contains( searchRect ) )
2451  {
2452  QgsGeometryMap& cachedGeometries = mCache->cachedGeometries();
2453  for ( QgsGeometryMap::iterator it = cachedGeometries.begin(); it != cachedGeometries.end() ; ++it )
2454  {
2455  QgsGeometry* g = &( it.value() );
2456  if ( g->boundingBox().intersects( searchRect ) )
2457  {
2458  snapToGeometry( startPoint, it.key(), g, sqrSnappingTolerance, snappingResults, snap_to );
2459  ++n;
2460  }
2461  }
2462  }
2463  else
2464  {
2465  // snapping outside cached area
2466 
2468  .setFilterRect( searchRect )
2470  .setSubsetOfAttributes( QgsAttributeList() ) );
2471 
2472  while ( fit.nextFeature( f ) )
2473  {
2474  snapToGeometry( startPoint, f.id(), f.geometry(), sqrSnappingTolerance, snappingResults, snap_to );
2475  ++n;
2476  }
2477  }
2478 
2479  return n == 0 ? 2 : 0;
2480 }
2481 
2482 void QgsVectorLayer::snapToGeometry( const QgsPoint& startPoint,
2483  QgsFeatureId featureId,
2484  QgsGeometry* geom,
2485  double sqrSnappingTolerance,
2486  QMultiMap<double, QgsSnappingResult>& snappingResults,
2487  QgsSnapper::SnappingType snap_to ) const
2488 {
2489  if ( !geom )
2490  {
2491  return;
2492  }
2493 
2494  int atVertex, beforeVertex, afterVertex;
2495  double sqrDistVertexSnap, sqrDistSegmentSnap;
2496  QgsPoint snappedPoint;
2497  QgsSnappingResult snappingResultVertex;
2498  QgsSnappingResult snappingResultSegment;
2499 
2500  if ( snap_to == QgsSnapper::SnapToVertex || snap_to == QgsSnapper::SnapToVertexAndSegment )
2501  {
2502  snappedPoint = geom->closestVertex( startPoint, atVertex, beforeVertex, afterVertex, sqrDistVertexSnap );
2503  if ( sqrDistVertexSnap < sqrSnappingTolerance )
2504  {
2505  snappingResultVertex.snappedVertex = snappedPoint;
2506  snappingResultVertex.snappedVertexNr = atVertex;
2507  snappingResultVertex.beforeVertexNr = beforeVertex;
2508  if ( beforeVertex != -1 ) // make sure the vertex is valid
2509  {
2510  snappingResultVertex.beforeVertex = geom->vertexAt( beforeVertex );
2511  }
2512  snappingResultVertex.afterVertexNr = afterVertex;
2513  if ( afterVertex != -1 ) // make sure the vertex is valid
2514  {
2515  snappingResultVertex.afterVertex = geom->vertexAt( afterVertex );
2516  }
2517  snappingResultVertex.snappedAtGeometry = featureId;
2518  snappingResultVertex.layer = this;
2519  snappingResults.insert( sqrt( sqrDistVertexSnap ), snappingResultVertex );
2520  return;
2521  }
2522  }
2523  if ( snap_to == QgsSnapper::SnapToSegment || snap_to == QgsSnapper::SnapToVertexAndSegment ) // snap to segment
2524  {
2525  if ( geometryType() != QGis::Point ) // cannot snap to segment for points/multipoints
2526  {
2527  sqrDistSegmentSnap = geom->closestSegmentWithContext( startPoint, snappedPoint, afterVertex, NULL, crs().geographicFlag() ? 1e-12 : 1e-8 );
2528 
2529  if ( sqrDistSegmentSnap < sqrSnappingTolerance )
2530  {
2531  snappingResultSegment.snappedVertex = snappedPoint;
2532  snappingResultSegment.snappedVertexNr = -1;
2533  snappingResultSegment.beforeVertexNr = afterVertex - 1;
2534  snappingResultSegment.afterVertexNr = afterVertex;
2535  snappingResultSegment.snappedAtGeometry = featureId;
2536  snappingResultSegment.beforeVertex = geom->vertexAt( afterVertex - 1 );
2537  snappingResultSegment.afterVertex = geom->vertexAt( afterVertex );
2538  snappingResultSegment.layer = this;
2539  snappingResults.insert( sqrt( sqrDistSegmentSnap ), snappingResultSegment );
2540  }
2541  }
2542  }
2543 }
2544 
2545 int QgsVectorLayer::insertSegmentVerticesForSnap( const QList<QgsSnappingResult>& snapResults )
2546 {
2547  QgsVectorLayerEditUtils utils( this );
2548  return utils.insertSegmentVerticesForSnap( snapResults );
2549 }
2550 
2551 
2553 {
2554  QgsDebugMsg( "----- Computing Coordinate System" );
2555 
2556  //
2557  // Get the layers project info and set up the QgsCoordinateTransform
2558  // for this layer
2559  //
2560 
2561  if ( hasGeometryType() )
2562  {
2563  // get CRS directly from provider
2564  setCrs( mDataProvider->crs() );
2565  }
2566  else
2567  {
2569  }
2570 }
2571 
2572 
2573 const QString QgsVectorLayer::displayField() const
2574 {
2575  return mDisplayField;
2576 }
2577 
2578 void QgsVectorLayer::setDisplayExpression( const QString &displayExpression )
2579 {
2580  mDisplayExpression = displayExpression;
2581 }
2582 
2584 {
2585  return mDisplayExpression;
2586 }
2587 
2589 {
2590  return ( mEditBuffer && mDataProvider );
2591 }
2592 
2594 {
2595  return mReadOnly;
2596 }
2597 
2598 bool QgsVectorLayer::setReadOnly( bool readonly )
2599 {
2600  // exit if the layer is in editing mode
2601  if ( readonly && mEditBuffer )
2602  return false;
2603 
2604  mReadOnly = readonly;
2605  return true;
2606 }
2607 
2609 {
2610  emit beforeModifiedCheck();
2611  return mEditBuffer && mEditBuffer->isModified();
2612 }
2613 
2615 {
2617  return QgsLegacyHelpers::convertEditType( editorWidgetV2( idx ), editorWidgetV2Config( idx ), this, mUpdatedFields[ idx ].name() );
2619 }
2620 
2622 {
2624 
2626  const QString widgetType = QgsLegacyHelpers::convertEditType( type, cfg, this, mUpdatedFields[idx].name() );
2628 
2629  setEditorWidgetV2( idx, widgetType );
2630  setEditorWidgetV2Config( idx, cfg );
2631 }
2632 
2634 {
2635  return mEditorLayout;
2636 }
2637 
2639 {
2640  mEditorLayout = editorLayout;
2641 }
2642 
2643 void QgsVectorLayer::setEditorWidgetV2( int attrIdx, const QString& widgetType )
2644 {
2645  mEditorWidgetV2Types[ mUpdatedFields[ attrIdx ].name()] = widgetType;
2646 }
2647 
2649 {
2650  mEditorWidgetV2Configs[ mUpdatedFields[ attrIdx ].name()] = config;
2651 }
2652 
2654 {
2655  return mEditForm;
2656 }
2657 
2659 {
2660  if ( ui.isEmpty() || ui.isNull() )
2661  {
2663  }
2664  else
2665  {
2667  }
2668  mEditForm = ui;
2669 }
2670 
2671 void QgsVectorLayer::setAnnotationForm( const QString& ui )
2672 {
2673  mAnnotationForm = ui;
2674 }
2675 
2677 {
2678  return mEditFormInit;
2679 }
2680 
2681 void QgsVectorLayer::setEditFormInit( QString function )
2682 {
2683  mEditFormInit = function;
2684 }
2685 
2686 QMap< QString, QVariant > QgsVectorLayer::valueMap( int idx )
2687 {
2688  return editorWidgetV2Config( idx );
2689 }
2690 
2692 {
2693  const QgsEditorWidgetConfig cfg = editorWidgetV2Config( idx );
2694  return RangeData(
2695  cfg.value( "Min" ),
2696  cfg.value( "Max" ),
2697  cfg.value( "Step" )
2698  );
2699 }
2700 
2701 QString QgsVectorLayer::dateFormat( int idx )
2702 {
2703  return editorWidgetV2Config( idx ).value( "DateFormat" ).toString();
2704 }
2705 
2707 {
2708  const QgsEditorWidgetConfig cfg = editorWidgetV2Config( idx );
2709  return QSize( cfg.value( "Width" ).toInt(), cfg.value( "Height" ).toInt() );
2710 }
2711 
2713 {
2714  const QgsFields &fields = pendingFields();
2715  if ( idx >= 0 && idx < fields.count() )
2716  {
2717  if ( mUpdatedFields.fieldOrigin( idx ) == QgsFields::OriginJoin
2718  || mUpdatedFields.fieldOrigin( idx ) == QgsFields::OriginExpression )
2719  return false;
2720  return mFieldEditables.value( fields[idx].name(), true );
2721  }
2722  else
2723  return true;
2724 }
2725 
2727 {
2728  const QgsFields &fields = pendingFields();
2729  if ( idx >= 0 && idx < fields.count() )
2730  return mLabelOnTop.value( fields[idx].name(), false );
2731  else
2732  return false;
2733 }
2734 
2735 void QgsVectorLayer::setFieldEditable( int idx, bool editable )
2736 {
2737  const QgsFields &fields = pendingFields();
2738  if ( idx >= 0 && idx < fields.count() )
2739  mFieldEditables[ fields[idx].name()] = editable;
2740 }
2741 
2742 void QgsVectorLayer::setLabelOnTop( int idx, bool onTop )
2743 {
2744  const QgsFields &fields = pendingFields();
2745  if ( idx >= 0 && idx < fields.count() )
2746  mLabelOnTop[ fields[idx].name()] = onTop;
2747 }
2748 
2750 {
2751  return mRendererV2;
2752 }
2753 
2755 {
2756  if ( !hasGeometryType() )
2757  return;
2758 
2759  if ( r != mRendererV2 )
2760  {
2761  delete mRendererV2;
2762  mRendererV2 = r;
2763  mSymbolFeatureCounted = false;
2764  mSymbolFeatureCountMap.clear();
2765 
2766  emit rendererChanged();
2767  }
2768 }
2769 
2770 
2771 
2773 {
2774  if ( !mDataProvider )
2775  {
2776  return;
2777  }
2778  if ( !mDataProvider->transaction() )
2779  {
2780  undoStack()->beginMacro( text );
2781  emit editCommandStarted( text );
2782  }
2783 }
2784 
2786 {
2787  if ( !mDataProvider )
2788  {
2789  return;
2790  }
2791  if ( !mDataProvider->transaction() )
2792  {
2793  undoStack()->endMacro();
2794  emit editCommandEnded();
2795  }
2796 }
2797 
2799 {
2800  if ( !mDataProvider )
2801  {
2802  return;
2803  }
2804  if ( !mDataProvider->transaction() )
2805  {
2806  undoStack()->endMacro();
2807  undoStack()->undo();
2808  emit editCommandDestroyed();
2809  }
2810 }
2811 
2812 
2813 void QgsVectorLayer::setCheckedState( int idx, QString checked, QString unchecked )
2814 {
2816  cfg["CheckedState"] = checked;
2817  cfg["UncheckedState"] = unchecked;
2818  setEditorWidgetV2Config( idx, cfg );
2819 }
2820 
2821 int QgsVectorLayer::fieldNameIndex( const QString& fieldName ) const
2822 {
2823  return pendingFields().fieldNameIndex( fieldName );
2824 }
2825 
2827 {
2828  return mJoinBuffer->addJoin( joinInfo );
2829 }
2830 
2831 void QgsVectorLayer::checkJoinLayerRemove( QString theLayerId )
2832 {
2833  removeJoin( theLayerId );
2834 }
2835 
2836 void QgsVectorLayer::removeJoin( const QString& joinLayerId )
2837 {
2838  mJoinBuffer->removeJoin( joinLayerId );
2839 }
2840 
2841 const QList< QgsVectorJoinInfo >& QgsVectorLayer::vectorJoins() const
2842 {
2843  return mJoinBuffer->vectorJoins();
2844 }
2845 
2846 void QgsVectorLayer::addExpressionField( const QString& exp, const QgsField& fld )
2847 {
2848  mExpressionFieldBuffer->addExpression( exp, fld );
2849  updateFields();
2850  int idx = mUpdatedFields.indexFromName( fld.name() );
2851  emit attributeAdded( idx );
2852 }
2853 
2855 {
2856  int oi = mUpdatedFields.fieldOriginIndex( index );
2857  mExpressionFieldBuffer->removeExpression( oi );
2858  updateFields();
2859  emit attributeDeleted( index );
2860 }
2861 
2863 {
2864  if ( !mDataProvider )
2865  return;
2866 
2867  QgsFields oldFields = mUpdatedFields;
2868 
2869  mUpdatedFields = mDataProvider->fields();
2870 
2871  // added / removed fields
2872  if ( mEditBuffer )
2873  mEditBuffer->updateFields( mUpdatedFields );
2874 
2875  // joined fields
2876  if ( mJoinBuffer && mJoinBuffer->containsJoins() )
2877  mJoinBuffer->updateFields( mUpdatedFields );
2878 
2879  if ( mExpressionFieldBuffer )
2880  mExpressionFieldBuffer->updateFields( mUpdatedFields );
2881 
2882  if ( oldFields != mUpdatedFields )
2883  emit updatedFields();
2884 }
2885 
2886 
2888 {
2889  if ( mJoinBuffer->containsJoins() )
2890  {
2891  mJoinBuffer->createJoinCaches();
2892  }
2893 }
2894 
2895 void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int limit )
2896 {
2897  uniqueValues.clear();
2898  if ( !mDataProvider )
2899  {
2900  return;
2901  }
2902 
2903  QgsFields::FieldOrigin origin = mUpdatedFields.fieldOrigin( index );
2904 
2905  if ( origin == QgsFields::OriginProvider ) //a provider field
2906  {
2907  mDataProvider->uniqueValues( index, uniqueValues, limit );
2908 
2909  if ( mEditBuffer )
2910  {
2911  QSet<QString> vals;
2912  Q_FOREACH ( const QVariant& v, uniqueValues )
2913  {
2914  vals << v.toString();
2915  }
2916 
2917  QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
2918  while ( it.hasNext() && ( limit < 0 || uniqueValues.count() < limit ) )
2919  {
2920  it.next();
2921  QVariant v = it.value().value( index );
2922  if ( v.isValid() )
2923  {
2924  QString vs = v.toString();
2925  if ( !vals.contains( vs ) )
2926  {
2927  vals << vs;
2928  uniqueValues << v;
2929  }
2930  }
2931  }
2932  }
2933 
2934  return;
2935  }
2936  else if ( origin == QgsFields::OriginJoin )
2937  {
2938  int sourceLayerIndex;
2939  const QgsVectorJoinInfo* join = mJoinBuffer->joinForFieldIndex( index, mUpdatedFields, sourceLayerIndex );
2940  Q_ASSERT( join );
2941 
2943 
2944  if ( vl )
2945  vl->dataProvider()->uniqueValues( sourceLayerIndex, uniqueValues, limit );
2946 
2947  return;
2948  }
2949  else if ( origin == QgsFields::OriginEdit || origin == QgsFields::OriginExpression )
2950  {
2951  // the layer is editable, but in certain cases it can still be avoided going through all features
2952  if ( origin == QgsFields::OriginEdit && mEditBuffer->mDeletedFeatureIds.isEmpty() && mEditBuffer->mAddedFeatures.isEmpty() && !mEditBuffer->mDeletedAttributeIds.contains( index ) && mEditBuffer->mChangedAttributeValues.isEmpty() )
2953  {
2954  mDataProvider->uniqueValues( index, uniqueValues, limit );
2955  return;
2956  }
2957 
2958  // we need to go through each feature
2959  QgsAttributeList attList;
2960  attList << index;
2961 
2963  .setFlags( QgsFeatureRequest::NoGeometry )
2964  .setSubsetOfAttributes( attList ) );
2965 
2966  QgsFeature f;
2967  QVariant currentValue;
2968  QHash<QString, QVariant> val;
2969  while ( fit.nextFeature( f ) )
2970  {
2971  currentValue = f.attribute( index );
2972  val.insert( currentValue.toString(), currentValue );
2973  if ( limit >= 0 && val.size() >= limit )
2974  {
2975  break;
2976  }
2977  }
2978 
2979  uniqueValues = val.values();
2980  return;
2981  }
2982 
2983  Q_ASSERT_X( false, "QgsVectorLayer::uniqueValues()", "Unknown source of the field!" );
2984 }
2985 
2987 {
2988  if ( !mDataProvider )
2989  {
2990  return QVariant();
2991  }
2992 
2993  QgsFields::FieldOrigin origin = mUpdatedFields.fieldOrigin( index );
2994 
2995  if ( origin == QgsFields::OriginProvider ) //a provider field
2996  {
2997  return mDataProvider->minimumValue( index );
2998  }
2999  else if ( origin == QgsFields::OriginJoin )
3000  {
3001  int sourceLayerIndex;
3002  const QgsVectorJoinInfo* join = mJoinBuffer->joinForFieldIndex( index, mUpdatedFields, sourceLayerIndex );
3003  Q_ASSERT( join );
3004 
3006  Q_ASSERT( vl );
3007 
3008  return vl->minimumValue( sourceLayerIndex );
3009  }
3010  else if ( origin == QgsFields::OriginEdit || origin == QgsFields::OriginExpression )
3011  {
3012  // the layer is editable, but in certain cases it can still be avoided going through all features
3013  if ( origin == QgsFields::OriginEdit &&
3014  mEditBuffer->mDeletedFeatureIds.isEmpty() &&
3015  mEditBuffer->mAddedFeatures.isEmpty() && !
3016  mEditBuffer->mDeletedAttributeIds.contains( index ) &&
3017  mEditBuffer->mChangedAttributeValues.isEmpty() )
3018  {
3019  return mDataProvider->minimumValue( index );
3020  }
3021 
3022  // we need to go through each feature
3023  QgsAttributeList attList;
3024  attList << index;
3025 
3027  .setFlags( QgsFeatureRequest::NoGeometry )
3028  .setSubsetOfAttributes( attList ) );
3029 
3030  QgsFeature f;
3032  double currentValue = 0;
3033  while ( fit.nextFeature( f ) )
3034  {
3035  currentValue = f.attribute( index ).toDouble();
3036  if ( currentValue < minimumValue )
3037  {
3038  minimumValue = currentValue;
3039  }
3040  }
3041  return QVariant( minimumValue );
3042  }
3043 
3044  Q_ASSERT_X( false, "QgsVectorLayer::minimumValue()", "Unknown source of the field!" );
3045  return QVariant();
3046 }
3047 
3049 {
3050  if ( !mDataProvider )
3051  {
3052  return QVariant();
3053  }
3054 
3055  QgsFields::FieldOrigin origin = mUpdatedFields.fieldOrigin( index );
3056 
3057  if ( origin == QgsFields::OriginProvider ) //a provider field
3058  {
3059  return mDataProvider->maximumValue( index );
3060  }
3061  else if ( origin == QgsFields::OriginJoin )
3062  {
3063  int sourceLayerIndex;
3064  const QgsVectorJoinInfo* join = mJoinBuffer->joinForFieldIndex( index, mUpdatedFields, sourceLayerIndex );
3065  Q_ASSERT( join );
3066 
3068  Q_ASSERT( vl );
3069 
3070  return vl->maximumValue( sourceLayerIndex );
3071  }
3072  else if ( origin == QgsFields::OriginEdit || origin == QgsFields::OriginExpression )
3073  {
3074  // the layer is editable, but in certain cases it can still be avoided going through all features
3075  if ( origin == QgsFields::OriginEdit &&
3076  mEditBuffer->mDeletedFeatureIds.isEmpty() &&
3077  mEditBuffer->mAddedFeatures.isEmpty() &&
3078  !mEditBuffer->mDeletedAttributeIds.contains( index ) &&
3079  mEditBuffer->mChangedAttributeValues.isEmpty() )
3080  {
3081  return mDataProvider->maximumValue( index );
3082  }
3083 
3084  // we need to go through each feature
3085  QgsAttributeList attList;
3086  attList << index;
3087 
3089  .setFlags( QgsFeatureRequest::NoGeometry )
3090  .setSubsetOfAttributes( attList ) );
3091 
3092  QgsFeature f;
3094  double currentValue = 0;
3095  while ( fit.nextFeature( f ) )
3096  {
3097  currentValue = f.attribute( index ).toDouble();
3098  if ( currentValue > maximumValue )
3099  {
3100  maximumValue = currentValue;
3101  }
3102  }
3103  return QVariant( maximumValue );
3104  }
3105 
3106  Q_ASSERT_X( false, "QgsVectorLayer::maximumValue()", "Unknown source of the field!" );
3107  return QVariant();
3108 }
3109 
3111 void QgsVectorLayer::setFeatureBlendMode( const QPainter::CompositionMode &featureBlendMode )
3112 {
3113  mFeatureBlendMode = featureBlendMode;
3114  emit featureBlendModeChanged( featureBlendMode );
3115 }
3116 
3118 QPainter::CompositionMode QgsVectorLayer::featureBlendMode() const
3119 {
3120  return mFeatureBlendMode;
3121 }
3122 
3124 void QgsVectorLayer::setLayerTransparency( int layerTransparency )
3125 {
3126  mLayerTransparency = layerTransparency;
3127  emit layerTransparencyChanged( layerTransparency );
3128 }
3129 
3132 {
3133  return mLayerTransparency;
3134 }
3135 
3136 
3137 
3138 void QgsVectorLayer::readSldLabeling( const QDomNode& node )
3139 {
3140  QDomElement element = node.toElement();
3141  if ( element.isNull() )
3142  return;
3143 
3144  QDomElement userStyleElem = element.firstChildElement( "UserStyle" );
3145  if ( userStyleElem.isNull() )
3146  {
3147  QgsDebugMsg( "Info: UserStyle element not found." );
3148  return;
3149  }
3150 
3151  QDomElement featureTypeStyleElem = userStyleElem.firstChildElement( "FeatureTypeStyle" );
3152  if ( featureTypeStyleElem.isNull() )
3153  {
3154  QgsDebugMsg( "Info: FeatureTypeStyle element not found." );
3155  return;
3156  }
3157 
3158  // use last rule
3159  QDomElement ruleElem = featureTypeStyleElem.lastChildElement( "Rule" );
3160  if ( ruleElem.isNull() )
3161  {
3162  QgsDebugMsg( "Info: Rule element not found." );
3163  return;
3164  }
3165 
3166  // use last text symbolizer
3167  QDomElement textSymbolizerElem = ruleElem.lastChildElement( "TextSymbolizer" );
3168  if ( textSymbolizerElem.isNull() )
3169  {
3170  QgsDebugMsg( "Info: TextSymbolizer element not found." );
3171  return;
3172  }
3173 
3174  // Label
3175  setCustomProperty( "labeling/enabled", false );
3176  QDomElement labelElem = textSymbolizerElem.firstChildElement( "Label" );
3177  if ( !labelElem.isNull() )
3178  {
3179  QDomElement propertyNameElem = labelElem.firstChildElement( "PropertyName" );
3180  if ( !propertyNameElem.isNull() )
3181  {
3182  // enable labeling
3183  setCustomProperty( "labeling", "pal" );
3184  setCustomProperty( "labeling/enabled", true );
3185 
3186  // set labeling defaults
3187  setCustomProperty( "labeling/fontFamily", "Sans-Serif" );
3188  setCustomProperty( "labeling/fontItalic", false );
3189  setCustomProperty( "labeling/fontSize", 10 );
3190  setCustomProperty( "labeling/fontSizeInMapUnits", false );
3191  setCustomProperty( "labeling/fontBold", false );
3192  setCustomProperty( "labeling/fontUnderline", false );
3193  setCustomProperty( "labeling/textColorR", 0 );
3194  setCustomProperty( "labeling/textColorG", 0 );
3195  setCustomProperty( "labeling/textColorB", 0 );
3196  setCustomProperty( "labeling/textTransp", 0 );
3197  setCustomProperty( "labeling/bufferDraw", false );
3198  setCustomProperty( "labeling/bufferSize", 1 );
3199  setCustomProperty( "labeling/bufferSizeInMapUnits", false );
3200  setCustomProperty( "labeling/bufferColorR", 255 );
3201  setCustomProperty( "labeling/bufferColorG", 255 );
3202  setCustomProperty( "labeling/bufferColorB", 255 );
3203  setCustomProperty( "labeling/bufferTransp", 0 );
3204  setCustomProperty( "labeling/placement", QgsPalLayerSettings::AroundPoint );
3205  setCustomProperty( "labeling/xOffset", 0 );
3206  setCustomProperty( "labeling/yOffset", 0 );
3207  setCustomProperty( "labeling/labelOffsetInMapUnits", false );
3208  setCustomProperty( "labeling/angleOffset", 0 );
3209 
3210  // label attribute
3211  QString labelAttribute = propertyNameElem.text();
3212  setCustomProperty( "labeling/fieldName", labelAttribute );
3213  setCustomProperty( "labeling/isExpression", false );
3214 
3215  int fieldIndex = fieldNameIndex( labelAttribute );
3216  if ( fieldIndex == -1 )
3217  {
3218  // label attribute is not in columns, check if it is an expression
3219  QgsExpression exp( labelAttribute );
3220  if ( !exp.hasEvalError() )
3221  {
3222  setCustomProperty( "labeling/isExpression", true );
3223  }
3224  else
3225  {
3226  QgsDebugMsg( "SLD label attribute error: " + exp.evalErrorString() );
3227  }
3228  }
3229  }
3230  else
3231  {
3232  QgsDebugMsg( "Info: PropertyName element not found." );
3233  return;
3234  }
3235  }
3236  else
3237  {
3238  QgsDebugMsg( "Info: Label element not found." );
3239  return;
3240  }
3241 
3242  // Font
3243  QDomElement fontElem = textSymbolizerElem.firstChildElement( "Font" );
3244  if ( !fontElem.isNull() )
3245  {
3246  QString cssName;
3247  QString elemText;
3248  QDomElement cssElem = fontElem.firstChildElement( "CssParameter" );
3249  while ( !cssElem.isNull() )
3250  {
3251  cssName = cssElem.attribute( "name", "not_found" );
3252  if ( cssName != "not_found" )
3253  {
3254  elemText = cssElem.text();
3255  if ( cssName == "font-family" )
3256  {
3257  setCustomProperty( "labeling/fontFamily", elemText );
3258  }
3259  else if ( cssName == "font-style" )
3260  {
3261  setCustomProperty( "labeling/fontItalic", ( elemText == "italic" ) || ( elemText == "Italic" ) );
3262  }
3263  else if ( cssName == "font-size" )
3264  {
3265  bool ok;
3266  int fontSize = elemText.toInt( &ok );
3267  if ( ok )
3268  {
3269  setCustomProperty( "labeling/fontSize", fontSize );
3270  }
3271  }
3272  else if ( cssName == "font-weight" )
3273  {
3274  setCustomProperty( "labeling/fontBold", ( elemText == "bold" ) || ( elemText == "Bold" ) );
3275  }
3276  else if ( cssName == "font-underline" )
3277  {
3278  setCustomProperty( "labeling/fontUnderline", ( elemText == "underline" ) || ( elemText == "Underline" ) );
3279  }
3280  }
3281 
3282  cssElem = cssElem.nextSiblingElement( "CssParameter" );
3283  }
3284  }
3285 
3286  // Fill
3287  QColor textColor = QgsOgcUtils::colorFromOgcFill( textSymbolizerElem.firstChildElement( "Fill" ) );
3288  if ( textColor.isValid() )
3289  {
3290  setCustomProperty( "labeling/textColorR", textColor.red() );
3291  setCustomProperty( "labeling/textColorG", textColor.green() );
3292  setCustomProperty( "labeling/textColorB", textColor.blue() );
3293  setCustomProperty( "labeling/textTransp", 100 - ( int )( 100 * textColor.alphaF() ) );
3294  }
3295 
3296  // Halo
3297  QDomElement haloElem = textSymbolizerElem.firstChildElement( "Halo" );
3298  if ( !haloElem.isNull() )
3299  {
3300  setCustomProperty( "labeling/bufferDraw", true );
3301  setCustomProperty( "labeling/bufferSize", 1 );
3302 
3303  QDomElement radiusElem = haloElem.firstChildElement( "Radius" );
3304  if ( !radiusElem.isNull() )
3305  {
3306  bool ok;
3307  double bufferSize = radiusElem.text().toDouble( &ok );
3308  if ( ok )
3309  {
3310  setCustomProperty( "labeling/bufferSize", bufferSize );
3311  }
3312  }
3313 
3314  QColor bufferColor = QgsOgcUtils::colorFromOgcFill( haloElem.firstChildElement( "Fill" ) );
3315  if ( bufferColor.isValid() )
3316  {
3317  setCustomProperty( "labeling/bufferColorR", bufferColor.red() );
3318  setCustomProperty( "labeling/bufferColorG", bufferColor.green() );
3319  setCustomProperty( "labeling/bufferColorB", bufferColor.blue() );
3320  setCustomProperty( "labeling/bufferTransp", 100 - ( int )( 100 * bufferColor.alphaF() ) );
3321  }
3322  }
3323 
3324  // LabelPlacement
3325  QDomElement labelPlacementElem = textSymbolizerElem.firstChildElement( "LabelPlacement" );
3326  if ( !labelPlacementElem.isNull() )
3327  {
3328  // PointPlacement
3329  QDomElement pointPlacementElem = labelPlacementElem.firstChildElement( "PointPlacement" );
3330  if ( !pointPlacementElem.isNull() )
3331  {
3332  setCustomProperty( "labeling/placement", QgsPalLayerSettings::OverPoint );
3333 
3334  QDomElement displacementElem = pointPlacementElem.firstChildElement( "Displacement" );
3335  if ( !displacementElem.isNull() )
3336  {
3337  QDomElement displacementXElem = displacementElem.firstChildElement( "DisplacementX" );
3338  if ( !displacementXElem.isNull() )
3339  {
3340  bool ok;
3341  double xOffset = displacementXElem.text().toDouble( &ok );
3342  if ( ok )
3343  {
3344  setCustomProperty( "labeling/xOffset", xOffset );
3345  }
3346  }
3347  QDomElement displacementYElem = displacementElem.firstChildElement( "DisplacementY" );
3348  if ( !displacementYElem.isNull() )
3349  {
3350  bool ok;
3351  double yOffset = displacementYElem.text().toDouble( &ok );
3352  if ( ok )
3353  {
3354  setCustomProperty( "labeling/yOffset", yOffset );
3355  }
3356  }
3357  }
3358 
3359  QDomElement rotationElem = pointPlacementElem.firstChildElement( "Rotation" );
3360  if ( !rotationElem.isNull() )
3361  {
3362  bool ok;
3363  double rotation = rotationElem.text().toDouble( &ok );
3364  if ( ok )
3365  {
3366  setCustomProperty( "labeling/angleOffset", rotation );
3367  }
3368  }
3369  }
3370  }
3371 }
3372 
3374 {
3375  if ( !mDiagramLayerSettings )
3376  mDiagramLayerSettings = new QgsDiagramLayerSettings();
3377  *mDiagramLayerSettings = s;
3378 }
3379 
3381 {
3382  QString myMetadata = "<html><body>";
3383 
3384  //-------------
3385 
3386  myMetadata += "<p class=\"subheaderglossy\">";
3387  myMetadata += tr( "General" );
3388  myMetadata += "</p>\n";
3389 
3390  // data comment
3391  if ( !( dataComment().isEmpty() ) )
3392  {
3393  myMetadata += "<p class=\"glossy\">" + tr( "Layer comment" ) + "</p>\n";
3394  myMetadata += "<p>";
3395  myMetadata += dataComment();
3396  myMetadata += "</p>\n";
3397  }
3398 
3399  //storage type
3400  myMetadata += "<p class=\"glossy\">" + tr( "Storage type of this layer" ) + "</p>\n";
3401  myMetadata += "<p>";
3402  myMetadata += storageType();
3403  myMetadata += "</p>\n";
3404 
3405  if ( dataProvider() )
3406  {
3407  //provider description
3408  myMetadata += "<p class=\"glossy\">" + tr( "Description of this provider" ) + "</p>\n";
3409  myMetadata += "<p>";
3410  myMetadata += dataProvider()->description().replace( "\n", "<br>" );
3411  myMetadata += "</p>\n";
3412  }
3413 
3414  // data source
3415  myMetadata += "<p class=\"glossy\">" + tr( "Source for this layer" ) + "</p>\n";
3416  myMetadata += "<p>";
3417  myMetadata += publicSource();
3418  myMetadata += "</p>\n";
3419 
3420  //geom type
3421 
3423 
3424  if ( type < 0 || type > QGis::NoGeometry )
3425  {
3426  QgsDebugMsg( "Invalid vector type" );
3427  }
3428  else
3429  {
3430  QString typeString( QGis::vectorGeometryType( geometryType() ) );
3431 
3432  myMetadata += "<p class=\"glossy\">" + tr( "Geometry type of the features in this layer" ) + "</p>\n";
3433  myMetadata += "<p>";
3434  myMetadata += typeString;
3435  myMetadata += "</p>\n";
3436  }
3437 
3439  if ( !pkAttrList.isEmpty() )
3440  {
3441  myMetadata += "<p class=\"glossy\">" + tr( "Primary key attributes" ) + "</p>\n";
3442  myMetadata += "<p>";
3443  foreach ( int idx, pkAttrList )
3444  {
3445  myMetadata += pendingFields()[ idx ].name() + " ";
3446  }
3447  myMetadata += "</p>\n";
3448  }
3449 
3450 
3451  //feature count
3452  myMetadata += "<p class=\"glossy\">" + tr( "The number of features in this layer" ) + "</p>\n";
3453  myMetadata += "<p>";
3454  myMetadata += QString::number( featureCount() );
3455  myMetadata += "</p>\n";
3456  //capabilities
3457  myMetadata += "<p class=\"glossy\">" + tr( "Editing capabilities of this layer" ) + "</p>\n";
3458  myMetadata += "<p>";
3459  myMetadata += capabilitiesString();
3460  myMetadata += "</p>\n";
3461 
3462  //-------------
3463 
3464  QgsRectangle myExtent = extent();
3465  myMetadata += "<p class=\"subheaderglossy\">";
3466  myMetadata += tr( "Extents" );
3467  myMetadata += "</p>\n";
3468 
3469  //extents in layer cs TODO...maybe make a little nested table to improve layout...
3470  myMetadata += "<p class=\"glossy\">" + tr( "In layer spatial reference system units" ) + "</p>\n";
3471  myMetadata += "<p>";
3472  // Try to be a bit clever over what number format we use for the
3473  // extents. Some people don't like it using scientific notation when the
3474  // numbers get large, but for small numbers this is the more practical
3475  // option (so we can't force the format to 'f' for all values).
3476  // The scheme:
3477  // - for all numbers with more than 5 digits, force non-scientific notation
3478  // and 2 digits after the decimal point.
3479  // - for all smaller numbers let the OS decide which format to use (it will
3480  // generally use non-scientific unless the number gets much less than 1).
3481 
3482  if ( !myExtent.isEmpty() )
3483  {
3484  QString xMin, yMin, xMax, yMax;
3485  double changeoverValue = 99999; // The 'largest' 5 digit number
3486  if ( qAbs( myExtent.xMinimum() ) > changeoverValue )
3487  {
3488  xMin = QString( "%1" ).arg( myExtent.xMinimum(), 0, 'f', 2 );
3489  }
3490  else
3491  {
3492  xMin = QString( "%1" ).arg( myExtent.xMinimum() );
3493  }
3494  if ( qAbs( myExtent.yMinimum() ) > changeoverValue )
3495  {
3496  yMin = QString( "%1" ).arg( myExtent.yMinimum(), 0, 'f', 2 );
3497  }
3498  else
3499  {
3500  yMin = QString( "%1" ).arg( myExtent.yMinimum() );
3501  }
3502  if ( qAbs( myExtent.xMaximum() ) > changeoverValue )
3503  {
3504  xMax = QString( "%1" ).arg( myExtent.xMaximum(), 0, 'f', 2 );
3505  }
3506  else
3507  {
3508  xMax = QString( "%1" ).arg( myExtent.xMaximum() );
3509  }
3510  if ( qAbs( myExtent.yMaximum() ) > changeoverValue )
3511  {
3512  yMax = QString( "%1" ).arg( myExtent.yMaximum(), 0, 'f', 2 );
3513  }
3514  else
3515  {
3516  yMax = QString( "%1" ).arg( myExtent.yMaximum() );
3517  }
3518 
3519  myMetadata += tr( "xMin,yMin %1,%2 : xMax,yMax %3,%4" )
3520  .arg( xMin ).arg( yMin ).arg( xMax ).arg( yMax );
3521  }
3522  else
3523  {
3524  myMetadata += tr( "unknown extent" );
3525  }
3526 
3527  myMetadata += "</p>\n";
3528 
3529  //extents in project cs
3530 
3531  try
3532  {
3533 #if 0
3534  // TODO: currently disabled, will revisit later [MD]
3535  QgsRectangle myProjectedExtent = coordinateTransform->transformBoundingBox( extent() );
3536  myMetadata += "<p class=\"glossy\">" + tr( "In project spatial reference system units" ) + "</p>\n";
3537  myMetadata += "<p>";
3538  myMetadata += tr( "xMin,yMin %1,%2 : xMax,yMax %3,%4" )
3539  .arg( myProjectedExtent.xMinimum() )
3540  .arg( myProjectedExtent.yMinimum() )
3541  .arg( myProjectedExtent.xMaximum() )
3542  .arg( myProjectedExtent.yMaximum() );
3543  myMetadata += "</p>\n";
3544 #endif
3545 
3546  //
3547  // Display layer spatial ref system
3548  //
3549  myMetadata += "<p class=\"glossy\">" + tr( "Layer Spatial Reference System" ) + "</p>\n";
3550  myMetadata += "<p>";
3551  myMetadata += crs().toProj4().replace( QRegExp( "\"" ), " \"" );
3552  myMetadata += "</p>\n";
3553 
3554  //
3555  // Display project (output) spatial ref system
3556  //
3557 #if 0
3558  // TODO: disabled for now, will revisit later [MD]
3559  //myMetadata += "<tr><td bgcolor=\"gray\">";
3560  myMetadata += "<p class=\"glossy\">" + tr( "Project (Output) Spatial Reference System" ) + "</p>\n";
3561  myMetadata += "<p>";
3562  myMetadata += coordinateTransform->destCRS().toProj4().replace( QRegExp( "\"" ), " \"" );
3563  myMetadata += "</p>\n";
3564 #endif
3565  }
3566  catch ( QgsCsException &cse )
3567  {
3568  Q_UNUSED( cse );
3569  QgsDebugMsg( cse.what() );
3570 
3571  myMetadata += "<p class=\"glossy\">" + tr( "In project spatial reference system units" ) + "</p>\n";
3572  myMetadata += "<p>";
3573  myMetadata += tr( "(Invalid transformation of layer extents)" );
3574  myMetadata += "</p>\n";
3575 
3576  }
3577 
3578 #if 0
3579  //
3580  // Add the info about each field in the attribute table
3581  //
3582  myMetadata += "<p class=\"glossy\">" + tr( "Attribute field info" ) + "</p>\n";
3583  myMetadata += "<p>";
3584 
3585  // Start a nested table in this trow
3586  myMetadata += "<table width=\"100%\">";
3587  myMetadata += "<tr><th>";
3588  myMetadata += tr( "Field" );
3589  myMetadata += "</th>";
3590  myMetadata += "<th>";
3591  myMetadata += tr( "Type" );
3592  myMetadata += "</th>";
3593  myMetadata += "<th>";
3594  myMetadata += tr( "Length" );
3595  myMetadata += "</th>";
3596  myMetadata += "<th>";
3597  myMetadata += tr( "Precision" );
3598  myMetadata += "</th>";
3599  myMetadata += "<th>";
3600  myMetadata += tr( "Comment" );
3601  myMetadata += "</th>";
3602 
3603  //get info for each field by looping through them
3604  const QgsFields& myFields = pendingFields();
3605  for ( int i = 0, n = myFields.size(); i < n; ++i )
3606  {
3607  const QgsField& myField = fields[i];
3608 
3609  myMetadata += "<tr><td>";
3610  myMetadata += myField.name();
3611  myMetadata += "</td>";
3612  myMetadata += "<td>";
3613  myMetadata += myField.typeName();
3614  myMetadata += "</td>";
3615  myMetadata += "<td>";
3616  myMetadata += QString( "%1" ).arg( myField.length() );
3617  myMetadata += "</td>";
3618  myMetadata += "<td>";
3619  myMetadata += QString( "%1" ).arg( myField.precision() );
3620  myMetadata += "</td>";
3621  myMetadata += "<td>";
3622  myMetadata += QString( "%1" ).arg( myField.comment() );
3623  myMetadata += "</td></tr>";
3624  }
3625 
3626  //close field list
3627  myMetadata += "</table>"; //end of nested table
3628 #endif
3629 
3630  myMetadata += "</body></html>";
3631  return myMetadata;
3632 }
3633 
3635 {
3636  mSymbolFeatureCounted = false;
3637 }
3638 
3639 void QgsVectorLayer::onRelationsLoaded()
3640 {
3641  Q_FOREACH ( QgsAttributeEditorElement* elem, mAttributeEditorElements )
3642  {
3644  {
3645  QgsAttributeEditorContainer* cont = dynamic_cast< QgsAttributeEditorContainer* >( elem );
3646  if ( !cont )
3647  continue;
3648 
3649  QList<QgsAttributeEditorElement*> relations = cont->findElements( QgsAttributeEditorElement::AeTypeRelation );
3650  Q_FOREACH ( QgsAttributeEditorElement* relElem, relations )
3651  {
3652  QgsAttributeEditorRelation* rel = dynamic_cast< QgsAttributeEditorRelation* >( relElem );
3653  if ( !rel )
3654  continue;
3655 
3656  rel->init( QgsProject::instance()->relationManager() );
3657  }
3658  }
3659  }
3660 }
3661 
3662 void QgsVectorLayer::onJoinedFieldsChanged()
3663 {
3664  // some of the fields of joined layers have changed -> we need to update this layer's fields too
3665  updateFields();
3666 }
3667 
3669 {
3670  if ( editorWidgetV2( idx ) == "ValueRelation" )
3671  {
3673 
3674  return ValueRelationData( cfg.value( "Layer" ).toString(),
3675  cfg.value( "Key" ).toString(),
3676  cfg.value( "Value" ).toString(),
3677  cfg.value( "AllowNull" ).toBool(),
3678  cfg.value( "OrderByValue" ).toBool(),
3679  cfg.value( "AllowMulti" ).toBool(),
3680  cfg.value( "FilterExpression" ).toString()
3681  );
3682  }
3683  else
3684  {
3685  return ValueRelationData();
3686  }
3687 }
3688 
3689 QList<QgsRelation> QgsVectorLayer::referencingRelations( int idx )
3690 {
3691  return QgsProject::instance()->relationManager()->referencingRelations( this, idx );
3692 }
3693 
3694 QList<QgsAttributeEditorElement*> &QgsVectorLayer::attributeEditorElements()
3695 {
3696  return mAttributeEditorElements;
3697 }
3698 
3700 {
3701  mAttributeEditorElements.clear();
3702 }
3703 
3704 QDomElement QgsAttributeEditorContainer::toDomElement( QDomDocument& doc ) const
3705 {
3706  QDomElement elem = doc.createElement( "attributeEditorContainer" );
3707  elem.setAttribute( "name", mName );
3708 
3709  Q_FOREACH ( QgsAttributeEditorElement* child, mChildren )
3710  {
3711  elem.appendChild( child->toDomElement( doc ) );
3712  }
3713  return elem;
3714 }
3715 
3717 {
3718  mChildren.append( widget );
3719 }
3720 
3722 {
3723  QList<QgsAttributeEditorElement*> results;
3724 
3725  Q_FOREACH ( QgsAttributeEditorElement* elem, mChildren )
3726  {
3727  if ( elem->type() == type )
3728  {
3729  results.append( elem );
3730  }
3731 
3732  if ( elem->type() == AeTypeContainer )
3733  {
3734  QgsAttributeEditorContainer* cont = dynamic_cast<QgsAttributeEditorContainer*>( elem );
3735  if ( cont )
3736  results += cont->findElements( type );
3737  }
3738  }
3739 
3740  return results;
3741 }
3742 
3743 QDomElement QgsAttributeEditorField::toDomElement( QDomDocument& doc ) const
3744 {
3745  QDomElement elem = doc.createElement( "attributeEditorField" );
3746  elem.setAttribute( "name", mName );
3747  elem.setAttribute( "index", mIdx );
3748  return elem;
3749 }
3750 
3751 int QgsVectorLayer::listStylesInDatabase( QStringList &ids, QStringList &names, QStringList &descriptions, QString &msgError )
3752 {
3754  QLibrary *myLib = pReg->providerLibrary( mProviderKey );
3755  if ( !myLib )
3756  {
3757  msgError = QObject::tr( "Unable to load %1 provider" ).arg( mProviderKey );
3758  return -1;
3759  }
3760  listStyles_t* listStylesExternalMethod = ( listStyles_t * ) cast_to_fptr( myLib->resolve( "listStyles" ) );
3761 
3762  if ( !listStylesExternalMethod )
3763  {
3764  delete myLib;
3765  msgError = QObject::tr( "Provider %1 has no %2 method" ).arg( mProviderKey ).arg( "listStyles" );
3766  return -1;
3767  }
3768 
3769  return listStylesExternalMethod( mDataSource, ids, names, descriptions, msgError );
3770 }
3771 
3772 QString QgsVectorLayer::getStyleFromDatabase( QString styleId, QString &msgError )
3773 {
3775  QLibrary *myLib = pReg->providerLibrary( mProviderKey );
3776  if ( !myLib )
3777  {
3778  msgError = QObject::tr( "Unable to load %1 provider" ).arg( mProviderKey );
3779  return QObject::tr( "" );
3780  }
3781  getStyleById_t* getStyleByIdMethod = ( getStyleById_t * ) cast_to_fptr( myLib->resolve( "getStyleById" ) );
3782 
3783  if ( !getStyleByIdMethod )
3784  {
3785  delete myLib;
3786  msgError = QObject::tr( "Provider %1 has no %2 method" ).arg( mProviderKey ).arg( "getStyleById" );
3787  return QObject::tr( "" );
3788  }
3789 
3790  return getStyleByIdMethod( mDataSource, styleId, msgError );
3791 }
3792 
3793 
3794 void QgsVectorLayer::saveStyleToDatabase( QString name, QString description,
3795  bool useAsDefault, QString uiFileContent, QString &msgError )
3796 {
3797 
3798  QString sldStyle, qmlStyle;
3800  QLibrary *myLib = pReg->providerLibrary( mProviderKey );
3801  if ( !myLib )
3802  {
3803  msgError = QObject::tr( "Unable to load %1 provider" ).arg( mProviderKey );
3804  return;
3805  }
3806  saveStyle_t* saveStyleExternalMethod = ( saveStyle_t * ) cast_to_fptr( myLib->resolve( "saveStyle" ) );
3807 
3808  if ( !saveStyleExternalMethod )
3809  {
3810  delete myLib;
3811  msgError = QObject::tr( "Provider %1 has no %2 method" ).arg( mProviderKey ).arg( "saveStyle" );
3812  return;
3813  }
3814 
3815  QDomDocument qmlDocument, sldDocument;
3816  this->exportNamedStyle( qmlDocument, msgError );
3817  if ( !msgError.isNull() )
3818  {
3819  return;
3820  }
3821  qmlStyle = qmlDocument.toString();
3822 
3823  this->exportSldStyle( sldDocument, msgError );
3824  if ( !msgError.isNull() )
3825  {
3826  return;
3827  }
3828  sldStyle = sldDocument.toString();
3829 
3830  saveStyleExternalMethod( mDataSource, qmlStyle, sldStyle, name,
3831  description, uiFileContent, useAsDefault, msgError );
3832 }
3833 
3834 
3835 
3836 QString QgsVectorLayer::loadNamedStyle( const QString &theURI, bool &theResultFlag )
3837 {
3838  return loadNamedStyle( theURI, theResultFlag, false );
3839 }
3840 
3841 QString QgsVectorLayer::loadNamedStyle( const QString &theURI, bool &theResultFlag, bool loadFromLocalDB )
3842 {
3843  QgsDataSourceURI dsUri( theURI );
3844  if ( !loadFromLocalDB && !dsUri.database().isEmpty() )
3845  {
3847  QLibrary *myLib = pReg->providerLibrary( mProviderKey );
3848  if ( myLib )
3849  {
3850  loadStyle_t* loadStyleExternalMethod = ( loadStyle_t * ) cast_to_fptr( myLib->resolve( "loadStyle" ) );
3851  if ( loadStyleExternalMethod )
3852  {
3853  QString qml, errorMsg;
3854  qml = loadStyleExternalMethod( mDataSource, errorMsg );
3855  if ( !qml.isEmpty() )
3856  {
3857  theResultFlag = this->applyNamedStyle( qml, errorMsg );
3858  return QObject::tr( "Loaded from Provider" );
3859  }
3860  }
3861  }
3862  }
3863 
3864  return QgsMapLayer::loadNamedStyle( theURI, theResultFlag );
3865 }
3866 
3867 bool QgsVectorLayer::applyNamedStyle( QString namedStyle, QString& errorMsg )
3868 {
3869  QDomDocument myDocument( "qgis" );
3870  myDocument.setContent( namedStyle );
3871 
3872  return importNamedStyle( myDocument, errorMsg );
3873 }
3874 
3875 
3876 QDomElement QgsAttributeEditorRelation::toDomElement( QDomDocument& doc ) const
3877 {
3878  QDomElement elem = doc.createElement( "attributeEditorRelation" );
3879  elem.setAttribute( "name", mName );
3880  elem.setAttribute( "relation", mRelation.id() );
3881  return elem;
3882 }
3883 
3885 {
3886  mRelation = relationManager->relation( mRelationId );
3887  return mRelation.isValid();
3888 }