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