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