QGIS API Documentation  2.3.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsmaplayer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmaplayer.cpp - description
3  -------------------
4  begin : Fri Jun 28 2002
5  copyright : (C) 2002 by Gary E.Sherman
6  email : sherman at mrcc.com
7 ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 
19 #include <QDateTime>
20 #include <QDomNode>
21 #include <QFileInfo>
22 #include <QSettings> // TODO: get rid of it [MD]
23 #include <QDir>
24 #include <QFile>
25 #include <QDomDocument>
26 #include <QDomElement>
27 #include <QDomImplementation>
28 #include <QTextStream>
29 #include <QUrl>
30 
31 #include <sqlite3.h>
32 
33 #include "qgslogger.h"
34 #include "qgsrectangle.h"
35 #include "qgsmaplayer.h"
37 #include "qgsapplication.h"
38 #include "qgsproject.h"
39 #include "qgspluginlayerregistry.h"
41 #include "qgsdatasourceuri.h"
42 #include "qgsvectorlayer.h"
43 #include "qgsrasterlayer.h"
44 #include "qgspluginlayer.h"
45 #include "qgsproviderregistry.h"
46 
48  QString lyrname,
49  QString source ) :
50  mValid( false ), // assume the layer is invalid
51  mDataSource( source ),
52  mLayerOrigName( lyrname ), // store the original name
53  mID( "" ),
54  mLayerType( type ),
55  mBlendMode( QPainter::CompositionMode_SourceOver ) // Default to normal blending
56 {
58 
59  // Set the display name = internal name
60  QgsDebugMsg( "original name: '" + mLayerOrigName + "'" );
62  QgsDebugMsg( "display name: '" + mLayerName + "'" );
63 
64  // Generate the unique ID of this layer
65  QDateTime dt = QDateTime::currentDateTime();
66  mID = lyrname + dt.toString( "yyyyMMddhhmmsszzz" );
67  // Tidy the ID up to avoid characters that may cause problems
68  // elsewhere (e.g in some parts of XML). Replaces every non-word
69  // character (word characters are the alphabet, numbers and
70  // underscore) with an underscore.
71  // Note that the first backslashe in the regular expression is
72  // there for the compiler, so the pattern is actually \W
73  mID.replace( QRegExp( "[\\W]" ), "_" );
74 
75  //set some generous defaults for scale based visibility
76  mMinScale = 0;
77  mMaxScale = 100000000;
78  mScaleBasedVisibility = false;
79 }
80 
82 {
83  delete mCRS;
84 }
85 
87 {
88  return mLayerType;
89 }
90 
92 QString QgsMapLayer::id() const
93 {
94  return mID;
95 }
96 
98 void QgsMapLayer::setLayerName( const QString & name )
99 {
100  QgsDebugMsg( "new original name: '" + name + "'" );
101  QString newName = capitaliseLayerName( name );
102  QgsDebugMsg( "new display name: '" + name + "'" );
103  if ( name == mLayerOrigName && newName == mLayerName ) return;
104  mLayerOrigName = name; // store the new original name
105  mLayerName = newName;
106  emit layerNameChanged();
107 }
108 
110 QString const & QgsMapLayer::name() const
111 {
112  QgsDebugMsgLevel( "returning name '" + mLayerName + "'", 3 );
113  return mLayerName;
114 }
115 
117 {
118  // Redo this every time we're asked for it, as we don't know if
119  // dataSource has changed.
120  QString safeName = QgsDataSourceURI::removePassword( mDataSource );
121  return safeName;
122 }
123 
124 QString const & QgsMapLayer::source() const
125 {
126  return mDataSource;
127 }
128 
130 {
131  return mExtent;
132 }
133 
135 void QgsMapLayer::setBlendMode( const QPainter::CompositionMode &blendMode )
136 {
138  emit blendModeChanged( blendMode );
139 }
140 
142 QPainter::CompositionMode QgsMapLayer::blendMode() const
143 {
144  return mBlendMode;
145 }
146 
147 bool QgsMapLayer::draw( QgsRenderContext& rendererContext )
148 {
149  Q_UNUSED( rendererContext );
150  return false;
151 }
152 
154 {
155  Q_UNUSED( rendererContext );
156 }
157 
158 bool QgsMapLayer::readLayerXML( const QDomElement& layerElement )
159 {
161  CUSTOM_CRS_VALIDATION savedValidation;
162  bool layerError;
163 
164  QDomNode mnl;
165  QDomElement mne;
166 
167  // read provider
168  QString provider;
169  mnl = layerElement.namedItem( "provider" );
170  mne = mnl.toElement();
171  provider = mne.text();
172 
173  // set data source
174  mnl = layerElement.namedItem( "datasource" );
175  mne = mnl.toElement();
176  mDataSource = mne.text();
177 
178  // TODO: this should go to providers
179  if ( provider == "spatialite" )
180  {
182  uri.setDatabase( QgsProject::instance()->readPath( uri.database() ) );
183  mDataSource = uri.uri();
184  }
185  else if ( provider == "ogr" )
186  {
187  QStringList theURIParts = mDataSource.split( "|" );
188  theURIParts[0] = QgsProject::instance()->readPath( theURIParts[0] );
189  mDataSource = theURIParts.join( "|" );
190  }
191  else if ( provider == "delimitedtext" )
192  {
193  QUrl urlSource = QUrl::fromEncoded( mDataSource.toAscii() );
194 
195  if ( !mDataSource.startsWith( "file:" ) )
196  {
197  QUrl file = QUrl::fromLocalFile( mDataSource.left( mDataSource.indexOf( "?" ) ) );
198  urlSource.setScheme( "file" );
199  urlSource.setPath( file.path() );
200  }
201 
202  QUrl urlDest = QUrl::fromLocalFile( QgsProject::instance()->readPath( urlSource.toLocalFile() ) );
203  urlDest.setQueryItems( urlSource.queryItems() );
204  mDataSource = QString::fromAscii( urlDest.toEncoded() );
205  }
206  else if ( provider == "wms" )
207  {
208  // >>> BACKWARD COMPATIBILITY < 1.9
209  // For project file backward compatibility we must support old format:
210  // 1. mode: <url>
211  // example: http://example.org/wms?
212  // 2. mode: tiled=<width>;<height>;<resolution>;<resolution>...,ignoreUrl=GetMap;GetFeatureInfo,featureCount=<count>,username=<name>,password=<password>,url=<url>
213  // example: tiled=256;256;0.703;0.351,url=http://example.org/tilecache?
214  // example: featureCount=10,http://example.org/wms?
215  // example: ignoreUrl=GetMap;GetFeatureInfo,username=cimrman,password=jara,url=http://example.org/wms?
216  // This is modified version of old QgsWmsProvider::parseUri
217  // The new format has always params crs,format,layers,styles and that params
218  // should not appear in old format url -> use them to identify version
219  if ( !mDataSource.contains( "crs=" ) && !mDataSource.contains( "format=" ) )
220  {
221  QgsDebugMsg( "Old WMS URI format detected -> converting to new format" );
222  QgsDataSourceURI uri;
223  if ( !mDataSource.startsWith( "http:" ) )
224  {
225  QStringList parts = mDataSource.split( "," );
226  QStringListIterator iter( parts );
227  while ( iter.hasNext() )
228  {
229  QString item = iter.next();
230  if ( item.startsWith( "username=" ) )
231  {
232  uri.setParam( "username", item.mid( 9 ) );
233  }
234  else if ( item.startsWith( "password=" ) )
235  {
236  uri.setParam( "password", item.mid( 9 ) );
237  }
238  else if ( item.startsWith( "tiled=" ) )
239  {
240  // in < 1.9 tiled= may apper in to variants:
241  // tiled=width;height - non tiled mode, specifies max width and max height
242  // tiled=width;height;resolutions-1;resolution2;... - tile mode
243 
244  QStringList params = item.mid( 6 ).split( ";" );
245 
246  if ( params.size() == 2 ) // non tiled mode
247  {
248  uri.setParam( "maxWidth", params.takeFirst() );
249  uri.setParam( "maxHeight", params.takeFirst() );
250  }
251  else if ( params.size() > 2 ) // tiled mode
252  {
253  // resolutions are no more needed and size limit is not used for tiles
254  // we have to tell to the provider however that it is tiled
255  uri.setParam( "tileMatrixSet", "" );
256  }
257  }
258  else if ( item.startsWith( "featureCount=" ) )
259  {
260  uri.setParam( "featureCount", item.mid( 13 ) );
261  }
262  else if ( item.startsWith( "url=" ) )
263  {
264  uri.setParam( "url", item.mid( 4 ) );
265  }
266  else if ( item.startsWith( "ignoreUrl=" ) )
267  {
268  uri.setParam( "ignoreUrl", item.mid( 10 ).split( ";" ) );
269  }
270  }
271  }
272  else
273  {
274  uri.setParam( "url", mDataSource );
275  }
276  mDataSource = uri.encodedUri();
277  // At this point, the URI is obviously incomplete, we add additional params
278  // in QgsRasterLayer::readXml
279  }
280  // <<< BACKWARD COMPATIBILITY < 1.9
281  }
282  else
283  {
285  }
286 
287  // Set the CRS from project file, asking the user if necessary.
288  // Make it the saved CRS to have WMS layer projected correctly.
289  // We will still overwrite whatever GDAL etc picks up anyway
290  // further down this function.
291  mnl = layerElement.namedItem( "layername" );
292  mne = mnl.toElement();
293 
294  QDomNode srsNode = layerElement.namedItem( "srs" );
295  mCRS->readXML( srsNode );
296  mCRS->setValidationHint( tr( "Specify CRS for layer %1" ).arg( mne.text() ) );
297  mCRS->validate();
298  savedCRS = *mCRS;
299 
300  // Do not validate any projections in children, they will be overwritten anyway.
301  // No need to ask the user for a projections when it is overwritten, is there?
304 
305  // now let the children grab what they need from the Dom node.
306  layerError = !readXml( layerElement );
307 
308  // overwrite CRS with what we read from project file before the raster/vector
309  // file readnig functions changed it. They will if projections is specfied in the file.
310  // FIXME: is this necessary?
312  *mCRS = savedCRS;
313 
314  // Abort if any error in layer, such as not found.
315  if ( layerError )
316  {
317  return false;
318  }
319 
320  // the internal name is just the data source basename
321  //QFileInfo dataSourceFileInfo( mDataSource );
322  //internalName = dataSourceFileInfo.baseName();
323 
324  // set ID
325  mnl = layerElement.namedItem( "id" );
326  if ( ! mnl.isNull() )
327  {
328  mne = mnl.toElement();
329  if ( ! mne.isNull() && mne.text().length() > 10 ) // should be at least 17 (yyyyMMddhhmmsszzz)
330  {
331  mID = mne.text();
332  }
333  }
334 
335  // use scale dependent visibility flag
336  toggleScaleBasedVisibility( layerElement.attribute( "hasScaleBasedVisibilityFlag" ).toInt() == 1 );
337  setMinimumScale( layerElement.attribute( "minimumScale" ).toFloat() );
338  setMaximumScale( layerElement.attribute( "maximumScale" ).toFloat() );
339 
340  // set name
341  mnl = layerElement.namedItem( "layername" );
342  mne = mnl.toElement();
343  setLayerName( mne.text() );
344 
345  //title
346  QDomElement titleElem = layerElement.firstChildElement( "title" );
347  if ( !titleElem.isNull() )
348  {
349  mTitle = titleElem.text();
350  }
351 
352  //abstract
353  QDomElement abstractElem = layerElement.firstChildElement( "abstract" );
354  if ( !abstractElem.isNull() )
355  {
356  mAbstract = abstractElem.text();
357  }
358 
359  //keywordList
360  QDomElement keywordListElem = layerElement.firstChildElement( "keywordList" );
361  if ( !keywordListElem.isNull() )
362  {
363  QStringList kwdList;
364  for ( QDomNode n = keywordListElem.firstChild(); !n.isNull(); n = n.nextSibling() )
365  {
366  kwdList << n.toElement().text();
367  }
368  mKeywordList = kwdList.join( ", " );
369  }
370 
371  //metadataUrl
372  QDomElement dataUrlElem = layerElement.firstChildElement( "dataUrl" );
373  if ( !dataUrlElem.isNull() )
374  {
375  mDataUrl = dataUrlElem.text();
376  mDataUrlFormat = dataUrlElem.attribute( "format", "" );
377  }
378 
379  //attribution
380  QDomElement attribElem = layerElement.firstChildElement( "attribution" );
381  if ( !attribElem.isNull() )
382  {
383  mAttribution = attribElem.text();
384  mAttributionUrl = attribElem.attribute( "href", "" );
385  }
386 
387  //metadataUrl
388  QDomElement metaUrlElem = layerElement.firstChildElement( "metadataUrl" );
389  if ( !metaUrlElem.isNull() )
390  {
391  mMetadataUrl = metaUrlElem.text();
392  mMetadataUrlType = metaUrlElem.attribute( "type", "" );
393  mMetadataUrlFormat = metaUrlElem.attribute( "format", "" );
394  }
395 
396 #if 0
397  //read transparency level
398  QDomNode transparencyNode = layer_node.namedItem( "transparencyLevelInt" );
399  if ( ! transparencyNode.isNull() )
400  {
401  // set transparency level only if it's in project
402  // (otherwise it sets the layer transparent)
403  QDomElement myElement = transparencyNode.toElement();
404  setTransparency( myElement.text().toInt() );
405  }
406 #endif
407 
408  readCustomProperties( layerElement );
409 
410  return true;
411 } // bool QgsMapLayer::readLayerXML
412 
413 
414 bool QgsMapLayer::readXml( const QDomNode& layer_node )
415 {
416  Q_UNUSED( layer_node );
417  // NOP by default; children will over-ride with behavior specific to them
418 
419  return true;
420 } // void QgsMapLayer::readXml
421 
422 
423 
424 bool QgsMapLayer::writeLayerXML( QDomElement& layerElement, QDomDocument& document )
425 {
426  // use scale dependent visibility flag
427  layerElement.setAttribute( "hasScaleBasedVisibilityFlag", hasScaleBasedVisibility() ? 1 : 0 );
428  layerElement.setAttribute( "minimumScale", QString::number( minimumScale() ) );
429  layerElement.setAttribute( "maximumScale", QString::number( maximumScale() ) );
430 
431  // ID
432  QDomElement layerId = document.createElement( "id" );
433  QDomText layerIdText = document.createTextNode( id() );
434  layerId.appendChild( layerIdText );
435 
436  layerElement.appendChild( layerId );
437 
438  // data source
439  QDomElement dataSource = document.createElement( "datasource" );
440 
441  QString src = source();
442 
443  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this );
444  // TODO: what about postgres, mysql and others, they should not go through writePath()
445  if ( vlayer && vlayer->providerType() == "spatialite" )
446  {
447  QgsDataSourceURI uri( src );
448  QString database = QgsProject::instance()->writePath( uri.database() );
449  uri.setConnection( uri.host(), uri.port(), database, uri.username(), uri.password() );
450  src = uri.uri();
451  }
452  else if ( vlayer && vlayer->providerType() == "ogr" )
453  {
454  QStringList theURIParts = src.split( "|" );
455  theURIParts[0] = QgsProject::instance()->writePath( theURIParts[0] );
456  src = theURIParts.join( "|" );
457  }
458  else if ( vlayer && vlayer->providerType() == "delimitedtext" )
459  {
460  QUrl urlSource = QUrl::fromEncoded( src.toAscii() );
461  QUrl urlDest = QUrl::fromLocalFile( QgsProject::instance()->writePath( urlSource.toLocalFile() ) );
462  urlDest.setQueryItems( urlSource.queryItems() );
463  src = QString::fromAscii( urlDest.toEncoded() );
464  }
465  else
466  {
467  src = QgsProject::instance()->writePath( src );
468  }
469 
470  QDomText dataSourceText = document.createTextNode( src );
471  dataSource.appendChild( dataSourceText );
472 
473  layerElement.appendChild( dataSource );
474 
475 
476  // layer name
477  QDomElement layerName = document.createElement( "layername" );
478  QDomText layerNameText = document.createTextNode( originalName() );
479  layerName.appendChild( layerNameText );
480 
481  // layer title
482  QDomElement layerTitle = document.createElement( "title" ) ;
483  QDomText layerTitleText = document.createTextNode( title() );
484  layerTitle.appendChild( layerTitleText );
485 
486  // layer abstract
487  QDomElement layerAbstract = document.createElement( "abstract" );
488  QDomText layerAbstractText = document.createTextNode( abstract() );
489  layerAbstract.appendChild( layerAbstractText );
490 
491  layerElement.appendChild( layerName );
492  layerElement.appendChild( layerTitle );
493  layerElement.appendChild( layerAbstract );
494 
495  // layer keyword list
496  QStringList keywordStringList = keywordList().split( "," );
497  if ( keywordStringList.size() > 0 )
498  {
499  QDomElement layerKeywordList = document.createElement( "keywordList" );
500  for ( int i = 0; i < keywordStringList.size(); ++i )
501  {
502  QDomElement layerKeywordValue = document.createElement( "value" );
503  QDomText layerKeywordText = document.createTextNode( keywordStringList.at( i ).trimmed() );
504  layerKeywordValue.appendChild( layerKeywordText );
505  layerKeywordList.appendChild( layerKeywordValue );
506  }
507  layerElement.appendChild( layerKeywordList );
508  }
509 
510  // layer metadataUrl
511  QString aDataUrl = dataUrl();
512  if ( !aDataUrl.isEmpty() )
513  {
514  QDomElement layerDataUrl = document.createElement( "dataUrl" ) ;
515  QDomText layerDataUrlText = document.createTextNode( aDataUrl );
516  layerDataUrl.appendChild( layerDataUrlText );
517  layerDataUrl.setAttribute( "format", dataUrlFormat() );
518  layerElement.appendChild( layerDataUrl );
519  }
520 
521  // layer attribution
522  QString aAttribution = attribution();
523  if ( !aAttribution.isEmpty() )
524  {
525  QDomElement layerAttribution = document.createElement( "attribution" ) ;
526  QDomText layerAttributionText = document.createTextNode( aAttribution );
527  layerAttribution.appendChild( layerAttributionText );
528  layerAttribution.setAttribute( "href", attributionUrl() );
529  layerElement.appendChild( layerAttribution );
530  }
531 
532  // layer metadataUrl
533  QString aMetadataUrl = metadataUrl();
534  if ( !aMetadataUrl.isEmpty() )
535  {
536  QDomElement layerMetadataUrl = document.createElement( "metadataUrl" ) ;
537  QDomText layerMetadataUrlText = document.createTextNode( aMetadataUrl );
538  layerMetadataUrl.appendChild( layerMetadataUrlText );
539  layerMetadataUrl.setAttribute( "type", metadataUrlType() );
540  layerMetadataUrl.setAttribute( "format", metadataUrlFormat() );
541  layerElement.appendChild( layerMetadataUrl );
542  }
543 
544  // timestamp if supported
545  if ( timestamp() > QDateTime() )
546  {
547  QDomElement stamp = document.createElement( "timestamp" );
548  QDomText stampText = document.createTextNode( timestamp().toString( Qt::ISODate ) );
549  stamp.appendChild( stampText );
550  layerElement.appendChild( stamp );
551  }
552 
553  layerElement.appendChild( layerName );
554 
555  // zorder
556  // This is no longer stored in the project file. It is superfluous since the layers
557  // are written and read in the proper order.
558 
559  // spatial reference system id
560  QDomElement mySrsElement = document.createElement( "srs" );
561  mCRS->writeXML( mySrsElement, document );
562  layerElement.appendChild( mySrsElement );
563 
564 #if 0
565  // <transparencyLevelInt>
566  QDomElement transparencyLevelIntElement = document.createElement( "transparencyLevelInt" );
567  QDomText transparencyLevelIntText = document.createTextNode( QString::number( getTransparency() ) );
568  transparencyLevelIntElement.appendChild( transparencyLevelIntText );
569  maplayer.appendChild( transparencyLevelIntElement );
570 #endif
571 
572  // now append layer node to map layer node
573 
574  writeCustomProperties( layerElement, document );
575 
576  return writeXml( layerElement, document );
577 
578 } // bool QgsMapLayer::writeXML
579 
581 {
582  QDomDocument doc( "qgis-layer-definition" );
583  QDomElement maplayer = doc.createElement( "maplayer" );
584  this->writeLayerXML( maplayer, doc );
585  maplayer.removeChild( maplayer.firstChildElement( "id" ) );
586  doc.appendChild( maplayer );
587  return doc;
588 }
589 
591 {
592  QDomNode layernode = document.elementsByTagName( "maplayer" ).at( 0 );
593  QDomElement layerElem = layernode.toElement();
594 
595  QString type = layerElem.attribute( "type" );
596  QgsDebugMsg( type );
597  QgsMapLayer *layer = NULL;
598 
599  if ( type == "vector" )
600  {
601  layer = new QgsVectorLayer;
602  }
603  else if ( type == "raster" )
604  {
605  layer = new QgsRasterLayer;
606  }
607  else if ( type == "plugin" )
608  {
609  QString typeName = layerElem.attribute( "name" );
610  layer = QgsPluginLayerRegistry::instance()->createLayer( typeName );
611  }
612 
613  bool ok = layer->readLayerXML( layerElem );
614  if ( ok )
615  return layer;
616 
617  delete layer;
618  return 0;
619 }
620 
622 {
623  QFile file( qlrfile );
624  if ( !file.open( QIODevice::ReadOnly ) )
625  {
626  QgsDebugMsg( "Can't open file" );
627  return 0;
628  }
629 
630  QDomDocument doc;
631  if ( !doc.setContent( &file ) )
632  {
633  QgsDebugMsg( "Can't set content" );
634  return 0;
635  }
636 
637  return QgsMapLayer::fromLayerDefinition( doc );
638 }
639 
640 
641 bool QgsMapLayer::writeXml( QDomNode & layer_node, QDomDocument & document )
642 {
643  Q_UNUSED( layer_node );
644  Q_UNUSED( document );
645  // NOP by default; children will over-ride with behavior specific to them
646 
647  return true;
648 } // void QgsMapLayer::writeXml
649 
650 
651 
652 
654 {
655  return mValid;
656 }
657 
658 
660 {
661  QgsDebugMsg( "called" );
662  // TODO: emit a signal - it will be used to update legend
663 }
664 
665 
667 {
668  return QString();
669 }
670 
672 {
673  return QString();
674 }
675 
676 void QgsMapLayer::connectNotify( const char * signal )
677 {
678  Q_UNUSED( signal );
679  QgsDebugMsgLevel( "QgsMapLayer connected to " + QString( signal ), 3 );
680 } // QgsMapLayer::connectNotify
681 
682 
683 
684 void QgsMapLayer::toggleScaleBasedVisibility( bool theVisibilityFlag )
685 {
686  mScaleBasedVisibility = theVisibilityFlag;
687 }
688 
690 {
691  return mScaleBasedVisibility;
692 }
693 
694 void QgsMapLayer::setMinimumScale( float theMinScale )
695 {
696  mMinScale = theMinScale;
697 }
698 
700 {
701  return mMinScale;
702 }
703 
704 
705 void QgsMapLayer::setMaximumScale( float theMaxScale )
706 {
707  mMaxScale = theMaxScale;
708 }
709 
711 {
712  return mMaxScale;
713 }
714 
715 
716 QStringList QgsMapLayer::subLayers() const
717 {
718  return QStringList(); // Empty
719 }
720 
721 void QgsMapLayer::setLayerOrder( const QStringList &layers )
722 {
723  Q_UNUSED( layers );
724  // NOOP
725 }
726 
727 void QgsMapLayer::setSubLayerVisibility( QString name, bool vis )
728 {
729  Q_UNUSED( name );
730  Q_UNUSED( vis );
731  // NOOP
732 }
733 
735 {
736  return *mCRS;
737 }
738 
739 void QgsMapLayer::setCrs( const QgsCoordinateReferenceSystem& srs, bool emitSignal )
740 {
741  *mCRS = srs;
742 
743  if ( !mCRS->isValid() )
744  {
745  mCRS->setValidationHint( tr( "Specify CRS for layer %1" ).arg( name() ) );
746  mCRS->validate();
747  }
748 
749  if ( emitSignal )
750  emit layerCrsChanged();
751 }
752 
753 QString QgsMapLayer::capitaliseLayerName( const QString& name )
754 {
755  // Capitalise the first letter of the layer name if requested
756  QSettings settings;
757  bool capitaliseLayerName =
758  settings.value( "/qgis/capitaliseLayerName", QVariant( false ) ).toBool();
759 
760  QString layerName( name );
761 
762  if ( capitaliseLayerName )
763  layerName = layerName.left( 1 ).toUpper() + layerName.mid( 1 );
764 
765  return layerName;
766 }
767 
769 {
770  QString myURI = publicSource();
771 
772  // if file is using the VSIFILE mechanism, remove the prefix
773  if ( myURI.startsWith( "/vsigzip/", Qt::CaseInsensitive ) )
774  {
775  myURI.remove( 0, 9 );
776  }
777  else if ( myURI.startsWith( "/vsizip/", Qt::CaseInsensitive ) &&
778  myURI.endsWith( ".zip", Qt::CaseInsensitive ) )
779  {
780  // ideally we should look for .qml file inside zip file
781  myURI.remove( 0, 8 );
782  }
783  else if ( myURI.startsWith( "/vsitar/", Qt::CaseInsensitive ) &&
784  ( myURI.endsWith( ".tar", Qt::CaseInsensitive ) ||
785  myURI.endsWith( ".tar.gz", Qt::CaseInsensitive ) ||
786  myURI.endsWith( ".tgz", Qt::CaseInsensitive ) ) )
787  {
788  // ideally we should look for .qml file inside tar file
789  myURI.remove( 0, 8 );
790  }
791 
792  QFileInfo myFileInfo( myURI );
793  QString key;
794 
795  if ( myFileInfo.exists() )
796  {
797  // if file is using the /vsizip/ or /vsigzip/ mechanism, cleanup the name
798  if ( myURI.endsWith( ".gz", Qt::CaseInsensitive ) )
799  myURI.chop( 3 );
800  else if ( myURI.endsWith( ".zip", Qt::CaseInsensitive ) )
801  myURI.chop( 4 );
802  else if ( myURI.endsWith( ".tar", Qt::CaseInsensitive ) )
803  myURI.chop( 4 );
804  else if ( myURI.endsWith( ".tar.gz", Qt::CaseInsensitive ) )
805  myURI.chop( 7 );
806  else if ( myURI.endsWith( ".tgz", Qt::CaseInsensitive ) )
807  myURI.chop( 4 );
808  else if ( myURI.endsWith( ".gz", Qt::CaseInsensitive ) )
809  myURI.chop( 3 );
810  myFileInfo.setFile( myURI );
811  // get the file name for our .qml style file
812  key = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".qml";
813  }
814  else
815  {
816  key = publicSource();
817  }
818 
819  return key;
820 }
821 
822 QString QgsMapLayer::loadDefaultStyle( bool & theResultFlag )
823 {
824  return loadNamedStyle( styleURI(), theResultFlag );
825 }
826 
827 bool QgsMapLayer::loadNamedStyleFromDb( const QString &db, const QString &theURI, QString &qml )
828 {
829  QgsDebugMsg( QString( "db = %1 uri = %2" ).arg( db ).arg( theURI ) );
830 
831  bool theResultFlag = false;
832 
833  // read from database
834  sqlite3 *myDatabase;
835  sqlite3_stmt *myPreparedStatement;
836  const char *myTail;
837  int myResult;
838 
839  QgsDebugMsg( QString( "Trying to load style for \"%1\" from \"%2\"" ).arg( theURI ).arg( db ) );
840 
841  if ( !QFile( db ).exists() )
842  return false;
843 
844  myResult = sqlite3_open_v2( db.toUtf8().data(), &myDatabase, SQLITE_OPEN_READONLY, NULL );
845  if ( myResult != SQLITE_OK )
846  {
847  return false;
848  }
849 
850  QString mySql = "select qml from tbl_styles where style=?";
851  myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
852  if ( myResult == SQLITE_OK )
853  {
854  QByteArray param = theURI.toUtf8();
855 
856  if ( sqlite3_bind_text( myPreparedStatement, 1, param.data(), param.length(), SQLITE_STATIC ) == SQLITE_OK &&
857  sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
858  {
859  qml = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) );
860  theResultFlag = true;
861  }
862 
863  sqlite3_finalize( myPreparedStatement );
864  }
865 
866  sqlite3_close( myDatabase );
867 
868  return theResultFlag;
869 }
870 
871 QString QgsMapLayer::loadNamedStyle( const QString &theURI, bool &theResultFlag )
872 {
873  QgsDebugMsg( QString( "uri = %1 myURI = %2" ).arg( theURI ).arg( publicSource() ) );
874 
875  theResultFlag = false;
876 
877  QDomDocument myDocument( "qgis" );
878 
879  // location of problem associated with errorMsg
880  int line, column;
881  QString myErrorMessage;
882 
883  QFile myFile( theURI );
884  if ( myFile.open( QFile::ReadOnly ) )
885  {
886  // read file
887  theResultFlag = myDocument.setContent( &myFile, &myErrorMessage, &line, &column );
888  if ( !theResultFlag )
889  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
890  myFile.close();
891  }
892  else
893  {
894  QFileInfo project( QgsProject::instance()->fileName() );
895  QgsDebugMsg( QString( "project fileName: %1" ).arg( project.absoluteFilePath() ) );
896 
897  QString qml;
898  if ( loadNamedStyleFromDb( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( "qgis.qmldb" ), theURI, qml ) ||
899  ( project.exists() && loadNamedStyleFromDb( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), theURI, qml ) ) ||
900  loadNamedStyleFromDb( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( "resources/qgis.qmldb" ), theURI, qml ) )
901  {
902  theResultFlag = myDocument.setContent( qml, &myErrorMessage, &line, &column );
903  if ( !theResultFlag )
904  {
905  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
906  }
907  }
908  else
909  {
910  myErrorMessage = tr( "style not found in database" );
911  }
912  }
913 
914  if ( !theResultFlag )
915  {
916  return myErrorMessage;
917  }
918 
919  // get style file version string, if any
920  QgsProjectVersion fileVersion( myDocument.firstChildElement( "qgis" ).attribute( "version" ) );
921  QgsProjectVersion thisVersion( QGis::QGIS_VERSION );
922 
923  if ( thisVersion > fileVersion )
924  {
925  QgsLogger::warning( "Loading a style file that was saved with an older "
926  "version of qgis (saved in " + fileVersion.text() +
927  ", loaded in " + QGis::QGIS_VERSION +
928  "). Problems may occur." );
929 
930  QgsProjectFileTransform styleFile( myDocument, fileVersion );
931  // styleFile.dump();
932  styleFile.updateRevision( thisVersion );
933  // styleFile.dump();
934  }
935 
936  // now get the layer node out and pass it over to the layer
937  // to deserialise...
938  QDomElement myRoot = myDocument.firstChildElement( "qgis" );
939  if ( myRoot.isNull() )
940  {
941  myErrorMessage = tr( "Error: qgis element could not be found in %1" ).arg( theURI );
942  theResultFlag = false;
943  return myErrorMessage;
944  }
945 
946  // use scale dependent visibility flag
947  toggleScaleBasedVisibility( myRoot.attribute( "hasScaleBasedVisibilityFlag" ).toInt() == 1 );
948  setMinimumScale( myRoot.attribute( "minimumScale" ).toFloat() );
949  setMaximumScale( myRoot.attribute( "maximumScale" ).toFloat() );
950 
951 #if 0
952  //read transparency level
953  QDomNode transparencyNode = myRoot.namedItem( "transparencyLevelInt" );
954  if ( ! transparencyNode.isNull() )
955  {
956  // set transparency level only if it's in project
957  // (otherwise it sets the layer transparent)
958  QDomElement myElement = transparencyNode.toElement();
959  setTransparency( myElement.text().toInt() );
960  }
961 #endif
962 
963  QString errorMsg;
964  theResultFlag = readSymbology( myRoot, errorMsg );
965  if ( !theResultFlag )
966  {
967  myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( theURI ).arg( errorMsg );
968  return myErrorMessage;
969  }
970 
971  return "";
972 }
973 
974 void QgsMapLayer::exportNamedStyle( QDomDocument &doc, QString &errorMsg )
975 {
976  QDomImplementation DomImplementation;
977  QDomDocumentType documentType = DomImplementation.createDocumentType( "qgis", "http://mrcc.com/qgis.dtd", "SYSTEM" );
978  QDomDocument myDocument( documentType );
979 
980  QDomElement myRootNode = myDocument.createElement( "qgis" );
981  myRootNode.setAttribute( "version", QString( "%1" ).arg( QGis::QGIS_VERSION ) );
982  myDocument.appendChild( myRootNode );
983 
984  myRootNode.setAttribute( "hasScaleBasedVisibilityFlag", hasScaleBasedVisibility() ? 1 : 0 );
985  myRootNode.setAttribute( "minimumScale", QString::number( minimumScale() ) );
986  myRootNode.setAttribute( "maximumScale", QString::number( maximumScale() ) );
987 
988 #if 0
989  // <transparencyLevelInt>
990  QDomElement transparencyLevelIntElement = myDocument.createElement( "transparencyLevelInt" );
991  QDomText transparencyLevelIntText = myDocument.createTextNode( QString::number( getTransparency() ) );
992  transparencyLevelIntElement.appendChild( transparencyLevelIntText );
993  myRootNode.appendChild( transparencyLevelIntElement );
994 #endif
995 
996  if ( !writeSymbology( myRootNode, myDocument, errorMsg ) )
997  {
998  errorMsg = QObject::tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
999  return;
1000  }
1001  doc = myDocument;
1002 }
1003 
1004 QString QgsMapLayer::saveDefaultStyle( bool & theResultFlag )
1005 {
1006  return saveNamedStyle( styleURI(), theResultFlag );
1007 }
1008 
1009 QString QgsMapLayer::saveNamedStyle( const QString &theURI, bool &theResultFlag )
1010 {
1011  QString myErrorMessage;
1012  QDomDocument myDocument;
1013  exportNamedStyle( myDocument, myErrorMessage );
1014 
1015  // check if the uri is a file or ends with .qml,
1016  // which indicates that it should become one
1017  // everything else goes to the database
1018  QString filename;
1019 
1020  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this );
1021  if ( vlayer && vlayer->providerType() == "ogr" )
1022  {
1023  QStringList theURIParts = theURI.split( "|" );
1024  filename = theURIParts[0];
1025  }
1026  else if ( vlayer && vlayer->providerType() == "delimitedtext" )
1027  {
1028  filename = QUrl::fromEncoded( theURI.toAscii() ).toLocalFile();
1029  }
1030  else
1031  {
1032  filename = theURI;
1033  }
1034 
1035  QFileInfo myFileInfo( filename );
1036  if ( myFileInfo.exists() || filename.endsWith( ".qml", Qt::CaseInsensitive ) )
1037  {
1038  QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
1039  if ( !myDirInfo.isWritable() )
1040  {
1041  return tr( "The directory containing your dataset needs to be writable!" );
1042  }
1043 
1044  // now construct the file name for our .qml style file
1045  QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".qml";
1046 
1047  QFile myFile( myFileName );
1048  if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
1049  {
1050  QTextStream myFileStream( &myFile );
1051  // save as utf-8 with 2 spaces for indents
1052  myDocument.save( myFileStream, 2 );
1053  myFile.close();
1054  theResultFlag = true;
1055  return tr( "Created default style file as %1" ).arg( myFileName );
1056  }
1057  else
1058  {
1059  theResultFlag = false;
1060  return tr( "ERROR: Failed to created default style file as %1. Check file permissions and retry." ).arg( myFileName );
1061  }
1062  }
1063  else
1064  {
1065  QString qml = myDocument.toString();
1066 
1067  // read from database
1068  sqlite3 *myDatabase;
1069  sqlite3_stmt *myPreparedStatement;
1070  const char *myTail;
1071  int myResult;
1072 
1073  myResult = sqlite3_open( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( "qgis.qmldb" ).toUtf8().data(), &myDatabase );
1074  if ( myResult != SQLITE_OK )
1075  {
1076  return tr( "User database could not be opened." );
1077  }
1078 
1079  QByteArray param0 = theURI.toUtf8();
1080  QByteArray param1 = qml.toUtf8();
1081 
1082  QString mySql = "create table if not exists tbl_styles(style varchar primary key,qml varchar)";
1083  myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
1084  if ( myResult == SQLITE_OK )
1085  {
1086  if ( sqlite3_step( myPreparedStatement ) != SQLITE_DONE )
1087  {
1088  sqlite3_finalize( myPreparedStatement );
1089  sqlite3_close( myDatabase );
1090  theResultFlag = false;
1091  return tr( "The style table could not be created." );
1092  }
1093  }
1094 
1095  sqlite3_finalize( myPreparedStatement );
1096 
1097  mySql = "insert into tbl_styles(style,qml) values (?,?)";
1098  myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
1099  if ( myResult == SQLITE_OK )
1100  {
1101  if ( sqlite3_bind_text( myPreparedStatement, 1, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
1102  sqlite3_bind_text( myPreparedStatement, 2, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
1103  sqlite3_step( myPreparedStatement ) == SQLITE_DONE )
1104  {
1105  theResultFlag = true;
1106  myErrorMessage = tr( "The style %1 was saved to database" ).arg( theURI );
1107  }
1108  }
1109 
1110  sqlite3_finalize( myPreparedStatement );
1111 
1112  if ( !theResultFlag )
1113  {
1114  QString mySql = "update tbl_styles set qml=? where style=?";
1115  myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
1116  if ( myResult == SQLITE_OK )
1117  {
1118  if ( sqlite3_bind_text( myPreparedStatement, 2, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
1119  sqlite3_bind_text( myPreparedStatement, 1, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
1120  sqlite3_step( myPreparedStatement ) == SQLITE_DONE )
1121  {
1122  theResultFlag = true;
1123  myErrorMessage = tr( "The style %1 was updated in the database." ).arg( theURI );
1124  }
1125  else
1126  {
1127  theResultFlag = false;
1128  myErrorMessage = tr( "The style %1 could not be updated in the database." ).arg( theURI );
1129  }
1130  }
1131  else
1132  {
1133  theResultFlag = false;
1134  myErrorMessage = tr( "The style %1 could not be inserted into database." ).arg( theURI );
1135  }
1136 
1137  sqlite3_finalize( myPreparedStatement );
1138  }
1139 
1140  sqlite3_close( myDatabase );
1141  }
1142 
1143  return myErrorMessage;
1144 }
1145 
1146 void QgsMapLayer::exportSldStyle( QDomDocument &doc, QString &errorMsg )
1147 {
1148  QDomDocument myDocument = QDomDocument();
1149 
1150  QDomNode header = myDocument.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" );
1151  myDocument.appendChild( header );
1152 
1153  // Create the root element
1154  QDomElement root = myDocument.createElementNS( "http://www.opengis.net/sld", "StyledLayerDescriptor" );
1155  root.setAttribute( "version", "1.1.0" );
1156  root.setAttribute( "xsi:schemaLocation", "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" );
1157  root.setAttribute( "xmlns:ogc", "http://www.opengis.net/ogc" );
1158  root.setAttribute( "xmlns:se", "http://www.opengis.net/se" );
1159  root.setAttribute( "xmlns:xlink", "http://www.w3.org/1999/xlink" );
1160  root.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" );
1161  myDocument.appendChild( root );
1162 
1163  // Create the NamedLayer element
1164  QDomElement namedLayerNode = myDocument.createElement( "NamedLayer" );
1165  root.appendChild( namedLayerNode );
1166 
1167  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this );
1168  if ( !vlayer )
1169  {
1170  errorMsg = tr( "Could not save symbology because:\n%1" )
1171  .arg( "Non-vector layers not supported yet" );
1172  return;
1173  }
1174 
1175  if ( !vlayer->writeSld( namedLayerNode, myDocument, errorMsg ) )
1176  {
1177  errorMsg = tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1178  return;
1179  }
1180 
1181  doc = myDocument;
1182 }
1183 
1184 QString QgsMapLayer::saveSldStyle( const QString &theURI, bool &theResultFlag )
1185 {
1186  QString errorMsg;
1187  QDomDocument myDocument;
1188  exportSldStyle( myDocument, errorMsg );
1189  if ( !errorMsg.isNull() )
1190  {
1191  theResultFlag = false;
1192  return errorMsg;
1193  }
1194  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this );
1195 
1196  // check if the uri is a file or ends with .sld,
1197  // which indicates that it should become one
1198  QString filename;
1199  if ( vlayer->providerType() == "ogr" )
1200  {
1201  QStringList theURIParts = theURI.split( "|" );
1202  filename = theURIParts[0];
1203  }
1204  else if ( vlayer->providerType() == "delimitedtext" )
1205  {
1206  filename = QUrl::fromEncoded( theURI.toAscii() ).toLocalFile();
1207  }
1208  else
1209  {
1210  filename = theURI;
1211  }
1212 
1213  QFileInfo myFileInfo( filename );
1214  if ( myFileInfo.exists() || filename.endsWith( ".sld", Qt::CaseInsensitive ) )
1215  {
1216  QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
1217  if ( !myDirInfo.isWritable() )
1218  {
1219  return tr( "The directory containing your dataset needs to be writable!" );
1220  }
1221 
1222  // now construct the file name for our .sld style file
1223  QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".sld";
1224 
1225  QFile myFile( myFileName );
1226  if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
1227  {
1228  QTextStream myFileStream( &myFile );
1229  // save as utf-8 with 2 spaces for indents
1230  myDocument.save( myFileStream, 2 );
1231  myFile.close();
1232  theResultFlag = true;
1233  return tr( "Created default style file as %1" ).arg( myFileName );
1234  }
1235  }
1236 
1237  theResultFlag = false;
1238  return tr( "ERROR: Failed to created SLD style file as %1. Check file permissions and retry." ).arg( filename );
1239 }
1240 
1241 QString QgsMapLayer::loadSldStyle( const QString &theURI, bool &theResultFlag )
1242 {
1243  QgsDebugMsg( "Entered." );
1244 
1245  theResultFlag = false;
1246 
1247  QDomDocument myDocument;
1248 
1249  // location of problem associated with errorMsg
1250  int line, column;
1251  QString myErrorMessage;
1252 
1253  QFile myFile( theURI );
1254  if ( myFile.open( QFile::ReadOnly ) )
1255  {
1256  // read file
1257  theResultFlag = myDocument.setContent( &myFile, true, &myErrorMessage, &line, &column );
1258  if ( !theResultFlag )
1259  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1260  myFile.close();
1261  }
1262  else
1263  {
1264  myErrorMessage = tr( "Unable to open file %1" ).arg( theURI );
1265  }
1266 
1267  if ( !theResultFlag )
1268  {
1269  return myErrorMessage;
1270  }
1271 
1272  // check for root SLD element
1273  QDomElement myRoot = myDocument.firstChildElement( "StyledLayerDescriptor" );
1274  if ( myRoot.isNull() )
1275  {
1276  myErrorMessage = QString( "Error: StyledLayerDescriptor element not found in %1" ).arg( theURI );
1277  theResultFlag = false;
1278  return myErrorMessage;
1279  }
1280 
1281  // now get the style node out and pass it over to the layer
1282  // to deserialise...
1283  QDomElement namedLayerElem = myRoot.firstChildElement( "NamedLayer" );
1284  if ( namedLayerElem.isNull() )
1285  {
1286  myErrorMessage = QString( "Info: NamedLayer element not found." );
1287  theResultFlag = false;
1288  return myErrorMessage;
1289  }
1290 
1291  QString errorMsg;
1292  theResultFlag = readSld( namedLayerElem, errorMsg );
1293  if ( !theResultFlag )
1294  {
1295  myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( theURI ).arg( errorMsg );
1296  return myErrorMessage;
1297  }
1298 
1299  return "";
1300 }
1301 
1302 
1304 {
1305  return &mUndoStack;
1306 }
1307 
1308 
1309 void QgsMapLayer::setCustomProperty( const QString& key, const QVariant& value )
1310 {
1311  mCustomProperties[key] = value;
1312 }
1313 
1314 QVariant QgsMapLayer::customProperty( const QString& value, const QVariant& defaultValue ) const
1315 {
1316  return mCustomProperties.value( value, defaultValue );
1317 }
1318 
1319 void QgsMapLayer::removeCustomProperty( const QString& key )
1320 {
1321  mCustomProperties.remove( key );
1322 }
1323 
1324 void QgsMapLayer::readCustomProperties( const QDomNode& layerNode, const QString& keyStartsWith )
1325 {
1326  QDomNode propsNode = layerNode.namedItem( "customproperties" );
1327  if ( propsNode.isNull() ) // no properties stored...
1328  return;
1329 
1330  if ( !keyStartsWith.isEmpty() )
1331  {
1332  //remove old keys
1333  QStringList keysToRemove;
1334  QMap<QString, QVariant>::const_iterator pIt = mCustomProperties.constBegin();
1335  for ( ; pIt != mCustomProperties.constEnd(); ++pIt )
1336  {
1337  if ( pIt.key().startsWith( keyStartsWith ) )
1338  {
1339  keysToRemove.push_back( pIt.key() );
1340  }
1341  }
1342 
1343  QStringList::const_iterator sIt = keysToRemove.constBegin();
1344  for ( ; sIt != keysToRemove.constEnd(); ++sIt )
1345  {
1346  mCustomProperties.remove( *sIt );
1347  }
1348  }
1349  else
1350  {
1351  mCustomProperties.clear();
1352  }
1353 
1354  QDomNodeList nodes = propsNode.childNodes();
1355 
1356  for ( int i = 0; i < nodes.size(); i++ )
1357  {
1358  QDomNode propNode = nodes.at( i );
1359  if ( propNode.isNull() || propNode.nodeName() != "property" )
1360  continue;
1361  QDomElement propElement = propNode.toElement();
1362 
1363  QString key = propElement.attribute( "key" );
1364  if ( key.isEmpty() || key.startsWith( keyStartsWith ) )
1365  {
1366  QString value = propElement.attribute( "value" );
1367  mCustomProperties[key] = QVariant( value );
1368  }
1369  }
1370 
1371 }
1372 
1373 void QgsMapLayer::writeCustomProperties( QDomNode & layerNode, QDomDocument & doc ) const
1374 {
1375  //remove already existing <customproperties> tags
1376  QDomNodeList propertyList = layerNode.toElement().elementsByTagName( "customproperties" );
1377  for ( int i = 0; i < propertyList.size(); ++i )
1378  {
1379  layerNode.removeChild( propertyList.at( i ) );
1380  }
1381 
1382  QDomElement propsElement = doc.createElement( "customproperties" );
1383 
1384  for ( QMap<QString, QVariant>::const_iterator it = mCustomProperties.constBegin(); it != mCustomProperties.constEnd(); ++it )
1385  {
1386  QDomElement propElement = doc.createElement( "property" );
1387  propElement.setAttribute( "key", it.key() );
1388  propElement.setAttribute( "value", it.value().toString() );
1389  propsElement.appendChild( propElement );
1390  }
1391 
1392  layerNode.appendChild( propsElement );
1393 }
1394 
1396 {
1397  return false;
1398 }
1399 
1400 void QgsMapLayer::setValid( bool valid )
1401 {
1402  mValid = valid;
1403 }
1404 
1406 {
1407  emit repaintRequested();
1408 }
1409 
1411 {
1412  emit repaintRequested();
1413 }
1414 
1416 {
1417  return QString();
1418 }
1419 
1421 {
1422  mExtent = r;
1423 }
static const char * QGIS_VERSION
Definition: qgis.h:40
virtual QStringList subLayers() const
Returns the sublayers of this layer (Useful for providers that manage their own layers, such as WMS)
virtual bool isEditable() const
True if the layer can be edited.
static const QString pkgDataPath()
Returns the common root path of all application data directories.
virtual QString saveNamedStyle(const QString &theURI, bool &theResultFlag)
Save the properties of this layer as a named style (either as a .qml file on disk or as a record in t...
QString database() const
A rectangle specified with double values.
Definition: qgsrectangle.h:35
Base class for all map layer types.
Definition: qgsmaplayer.h:46
QString mID
Unique ID of this layer - used to refer to this layer in map layer registry.
Definition: qgsmaplayer.h:525
QgsPluginLayer * createLayer(QString typeName)
return new layer if corresponding plugin has been found, else return NULL
QgsMapLayer::LayerType type() const
Get the type of the layer.
Definition: qgsmaplayer.cpp:86
virtual QString metadata()
Obtain Metadata for this layer.
virtual void drawLabels(QgsRenderContext &rendererContext)
Draw labels.
virtual QString loadSldStyle(const QString &theURI, bool &theResultFlag)
QString mAttributionUrl
Definition: qgsmaplayer.h:503
QString mKeywordList
Definition: qgsmaplayer.h:495
void readCustomProperties(const QDomNode &layerNode, const QString &keyStartsWith="")
Read custom properties from project file.
QString publicSource() const
virtual ~QgsMapLayer()
Destructor.
Definition: qgsmaplayer.cpp:81
QString mDataUrlFormat
Definition: qgsmaplayer.h:499
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
static QString removePassword(const QString &aUri)
Removes password element from uris.
virtual Q_DECL_DEPRECATED QString lastError()
const QString & originalName() const
Get the original name of the layer.
Definition: qgsmaplayer.h:92
static void warning(const QString &msg)
Goes to qWarning.
Definition: qgslogger.cpp:162
QString password() const
virtual bool readSymbology(const QDomNode &node, QString &errorMessage)=0
Read the symbology for the current layer from the Dom node supplied.
void layerNameChanged()
Emit a signal that the layer name has been changed.
void setDatabase(const QString &database)
Set database.
void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for layer.
bool mScaleBasedVisibility
A flag that tells us whether to use the above vars to restrict layer visibility.
Definition: qgsmaplayer.h:541
float minimumScale() const
void blendModeChanged(const QPainter::CompositionMode &blendMode)
Signal emitted when the blend mode is changed, through QgsMapLayer::setBlendMode() ...
const QString & attribution() const
Definition: qgsmaplayer.h:111
static CUSTOM_CRS_VALIDATION customSrsValidation()
Gets custom function.
virtual QString saveDefaultStyle(bool &theResultFlag)
Save the properties of this layer as the default style (either as a .qml file on disk or as a record ...
QUndoStack mUndoStack
Collection of undoable operations for this layer.
Definition: qgsmaplayer.h:544
QDomDocument asLayerDefinition()
Returns the layer as a layer definition document Layer definitions store the data source as well as s...
static const QString qgisSettingsDirPath()
Returns the path to the settings directory in user's home dir.
QString readPath(QString filename) const
turn filename read from the project file to an absolute path
void setBlendMode(const QPainter::CompositionMode &blendMode)
Write blend mode for layer.
QString mLayerName
Name of the layer - used for display.
Definition: qgsmaplayer.h:484
void setMaximumScale(float theMaxScale)
Accessor and mutator for the maximum scale denominator member.
virtual bool writeSymbology(QDomNode &node, QDomDocument &doc, QString &errorMessage) const =0
Write the symbology for the layer into the docment provided.
static QgsMapLayer * fromLayerDefinition(QDomDocument &document)
Creates a new layer from a layer defininition document.
static void setCustomSrsValidation(CUSTOM_CRS_VALIDATION f)
Sets custom function to force valid CRS QGIS uses implementation in QgisGui::customSrsValidation.
virtual bool draw(QgsRenderContext &rendererContext)
This is the method that does the actual work of drawing the layer onto a paint device.
static QString capitaliseLayerName(const QString &name)
A convenience function to (un)capitalise the layer name.
void setConnection(const QString &aHost, const QString &aPort, const QString &aDatabase, const QString &aUsername, const QString &aPassword, SSLmode sslmode=SSLprefer)
Set all connection related members at once.
const QString & name() const
Get the display name of the layer.
QgsRectangle mExtent
Extent of the layer.
Definition: qgsmaplayer.h:475
QPainter::CompositionMode mBlendMode
Blend mode for the layer.
Definition: qgsmaplayer.h:531
QString mMetadataUrl
MetadataUrl of the layer.
Definition: qgsmaplayer.h:506
QPainter::CompositionMode blendMode() const
Read blend mode for layer.
bool hasScaleBasedVisibility() const
bool writeSld(QDomNode &node, QDomDocument &doc, QString &errorMessage) const
void layerCrsChanged()
Emit a signal that layer's CRS has been reset added in 1.4.
const QString & dataUrl() const
Definition: qgsmaplayer.h:105
virtual bool loadNamedStyleFromDb(const QString &db, const QString &theURI, QString &qml)
virtual bool writeXml(QDomNode &layer_node, QDomDocument &document)
called by writeLayerXML(), used by children to write state specific to them to project files...
QString uri() const
return complete uri
bool writeLayerXML(QDomElement &layerElement, QDomDocument &document)
stores state in Dom node
const QString & metadataUrlType() const
Definition: qgsmaplayer.h:119
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:37
Q_DECL_DEPRECATED void setCacheImage(QImage *)
const QString & source() const
Returns the source for the layer.
LayerType
Layers enum defining the types of layers that can be added to a map.
Definition: qgsmaplayer.h:52
void setParam(const QString &key, const QString &value)
Set generic param (generic mode)
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
A class to describe the version of a project.
float maximumScale() const
virtual void setExtent(const QgsRectangle &rect)
Set the extent.
QString mDataUrl
DataUrl of the layer.
Definition: qgsmaplayer.h:498
const QString & metadataUrl() const
Definition: qgsmaplayer.h:117
QString writePath(QString filename) const
prepare a filename to save it to the project file
QString id() const
Get this layer's unique ID, this ID is used to access this layer from map layer registry.
Definition: qgsmaplayer.cpp:92
virtual void setSubLayerVisibility(QString name, bool vis)
Set the visibility of the given sublayer name.
void writeCustomProperties(QDomNode &layerNode, QDomDocument &doc) const
Write custom properties to project file.
virtual Q_DECL_DEPRECATED QString lastErrorTitle()
void removeCustomProperty(const QString &key)
Remove a custom property from layer.
QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
virtual QString saveSldStyle(const QString &theURI, bool &theResultFlag)
bool isValid()
bool mValid
Indicates if the layer is valid and can be drawn.
Definition: qgsmaplayer.h:478
QString host() const
QString mTitle
Definition: qgsmaplayer.h:491
virtual bool readSld(const QDomNode &node, QString &errorMessage)
Definition: qgsmaplayer.h:349
QString mMetadataUrlFormat
Definition: qgsmaplayer.h:508
Class for storing the component parts of a PostgreSQL/RDBMS datasource URI.
struct sqlite3 sqlite3
QString mAttribution
Attribution of the layer.
Definition: qgsmaplayer.h:502
QString mAbstract
Description of the layer.
Definition: qgsmaplayer.h:494
QMap< QString, QVariant > mCustomProperties
Definition: qgsmaplayer.h:546
QString file
Definition: qgssvgcache.cpp:76
virtual void exportNamedStyle(QDomDocument &doc, QString &errorMsg)
Export the properties of this layer as named style in a QDomDocument.
QString providerType() const
Return the provider type for this layer.
void connectNotify(const char *signal)
debugging member - invoked when a connect() is made to this object
bool writeXML(QDomNode &theNode, QDomDocument &theDoc) const
Contains information about the context of a rendering operation.
Q_DECL_DEPRECATED void clearCacheImage()
Clear cached image.
QString mDataSource
data source description string, varies by layer type
Definition: qgsmaplayer.h:481
virtual QString loadDefaultStyle(bool &theResultFlag)
Retrieve the default style for this layer if one exists (either as a .qml file on disk or as a record...
static QgsMapLayer * fromLayerDefinitionFile(const QString qlrfile)
virtual void invalidTransformInput()
Event handler for when a coordinate transform fails due to bad vertex error.
void repaintRequested()
By emitting this signal the layer tells that either appearance or content have been changed and any v...
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:362
virtual bool readXml(const QDomNode &layer_node)
called by readLayerXML(), used by children to read state specific to them from project files...
float mMaxScale
Maximum scale denominator at which this layer should be displayed.
Definition: qgsmaplayer.h:539
Class for storing a coordinate reference system (CRS)
bool readLayerXML(const QDomElement &layerElement)
sets state from Dom document
void setLayerName(const QString &name)
Set the display name of the layer.
Definition: qgsmaplayer.cpp:98
const QgsCoordinateReferenceSystem & crs() const
Returns layer's spatial reference system.
virtual QString loadNamedStyle(const QString &theURI, bool &theResultFlag)
Retrieve a named style for this layer if one exists (either as a .qml file on disk or as a record in ...
QByteArray encodedUri() const
return complete encoded uri (generic mode)
QgsMapLayer::LayerType mLayerType
Type of the layer (eg.
Definition: qgsmaplayer.h:528
QgsCoordinateReferenceSystem * mCRS
layer's spatial reference system.
Definition: qgsmaplayer.h:516
static QgsPluginLayerRegistry * instance()
means of accessing canonical single instance
QUndoStack * undoStack()
Return pointer to layer's undo stack.
virtual QDateTime timestamp() const
Time stamp of data source in the moment when data/metadata were loaded by provider.
Definition: qgsmaplayer.h:403
const QString & attributionUrl() const
Definition: qgsmaplayer.h:113
void(* CUSTOM_CRS_VALIDATION)(QgsCoordinateReferenceSystem &)
virtual QString styleURI()
Retrieve the style URI for this layer (either as a .qml file on disk or as a record in the users styl...
const QString & metadataUrlFormat() const
Definition: qgsmaplayer.h:121
virtual QgsRectangle extent()
Return the extent of the layer.
Represents a vector layer which manages a vector based data sets.
virtual void setLayerOrder(const QStringList &layers)
Reorders the previously selected sublayers of this layer from bottom to top (Useful for providers tha...
const QString & title() const
Definition: qgsmaplayer.h:95
QString mLayerOrigName
Original name of the layer.
Definition: qgsmaplayer.h:489
void setValid(bool valid)
set whether layer is valid or not - should be used in constructor.
QString username() const
QString mMetadataUrlType
Definition: qgsmaplayer.h:507
const QString & keywordList() const
Definition: qgsmaplayer.h:101
float mMinScale
Minimum scale denominator at which this layer should be displayed.
Definition: qgsmaplayer.h:537
virtual void exportSldStyle(QDomDocument &doc, QString &errorMsg)
Export the properties of this layer as SLD style in a QDomDocument.
QString port() const
const QString & dataUrlFormat() const
Definition: qgsmaplayer.h:107
void toggleScaleBasedVisibility(bool theVisibilityFlag)
Accessor and mutator for the scale based visilibility flag.
QgsMapLayer(QgsMapLayer::LayerType type=VectorLayer, QString lyrname=QString::null, QString source=QString::null)
Constructor.
Definition: qgsmaplayer.cpp:47
void setMinimumScale(float theMinScale)
Accessor and mutator for the minimum scale denominator member.
#define tr(sourceText)