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