QGIS API Documentation  2.9.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 <QDir>
21 #include <QDomDocument>
22 #include <QDomElement>
23 #include <QDomImplementation>
24 #include <QDomNode>
25 #include <QFile>
26 #include <QFileInfo>
27 #include <QSettings> // TODO: get rid of it [MD]
28 #include <QTextStream>
29 #include <QUrl>
30 
31 #include <sqlite3.h>
32 
33 #include "qgsapplication.h"
35 #include "qgsdatasourceuri.h"
36 #include "qgslogger.h"
37 #include "qgsmaplayer.h"
38 #include "qgsmaplayerlegend.h"
40 #include "qgspluginlayer.h"
41 #include "qgspluginlayerregistry.h"
43 #include "qgsproject.h"
44 #include "qgsproviderregistry.h"
45 #include "qgsrasterlayer.h"
46 #include "qgsrectangle.h"
47 #include "qgsvectorlayer.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 = 0;
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  if ( !layer )
661  continue;
662 
663  bool ok = layer->readLayerXML( layerElem );
664  if ( ok )
665  layers << layer;
666  }
667  return layers;
668 }
669 
670 QList<QgsMapLayer *> QgsMapLayer::fromLayerDefinitionFile( const QString &qlrfile )
671 {
672  QFile file( qlrfile );
673  if ( !file.open( QIODevice::ReadOnly ) )
674  {
675  QgsDebugMsg( "Can't open file" );
676  return QList<QgsMapLayer*>();
677  }
678 
679  QDomDocument doc;
680  if ( !doc.setContent( &file ) )
681  {
682  QgsDebugMsg( "Can't set content" );
683  return QList<QgsMapLayer*>();
684  }
685 
686  QFileInfo fileinfo( file );
687  QDir::setCurrent( fileinfo.absoluteDir().path() );
688  return QgsMapLayer::fromLayerDefinition( doc );
689 }
690 
691 
692 bool QgsMapLayer::writeXml( QDomNode & layer_node, QDomDocument & document )
693 {
694  Q_UNUSED( layer_node );
695  Q_UNUSED( document );
696  // NOP by default; children will over-ride with behavior specific to them
697 
698  return true;
699 } // void QgsMapLayer::writeXml
700 
701 
702 void QgsMapLayer::readCustomProperties( const QDomNode &layerNode, const QString &keyStartsWith )
703 {
704  mCustomProperties.readXml( layerNode, keyStartsWith );
705 }
706 
707 void QgsMapLayer::writeCustomProperties( QDomNode &layerNode, QDomDocument &doc ) const
708 {
709  mCustomProperties.writeXml( layerNode, doc );
710 }
711 
712 void QgsMapLayer::readStyleManager( const QDomNode& layerNode )
713 {
714  QDomElement styleMgrElem = layerNode.firstChildElement( "map-layer-style-manager" );
715  if ( !styleMgrElem.isNull() )
716  mStyleManager->readXml( styleMgrElem );
717  else
718  mStyleManager->reset();
719 }
720 
721 void QgsMapLayer::writeStyleManager( QDomNode& layerNode, QDomDocument& doc ) const
722 {
723  if ( mStyleManager )
724  {
725  QDomElement styleMgrElem = doc.createElement( "map-layer-style-manager" );
726  mStyleManager->writeXml( styleMgrElem );
727  layerNode.appendChild( styleMgrElem );
728  }
729 }
730 
731 
732 
733 
735 {
736  return mValid;
737 }
738 
739 
741 {
742  QgsDebugMsg( "called" );
743  // TODO: emit a signal - it will be used to update legend
744 }
745 
746 
748 {
749  return QString();
750 }
751 
753 {
754  return QString();
755 }
756 
757 #if 0
758 void QgsMapLayer::connectNotify( const char * signal )
759 {
760  Q_UNUSED( signal );
761  QgsDebugMsgLevel( "QgsMapLayer connected to " + QString( signal ), 3 );
762 } // QgsMapLayer::connectNotify
763 #endif
764 
765 
766 void QgsMapLayer::toggleScaleBasedVisibility( bool theVisibilityFlag )
767 {
768  setScaleBasedVisibility( theVisibilityFlag );
769 }
770 
772 {
773  return mScaleBasedVisibility;
774 }
775 
776 void QgsMapLayer::setMinimumScale( const float theMinScale )
777 {
778  mMinScale = theMinScale;
779 }
780 
782 {
783  return mMinScale;
784 }
785 
786 
787 void QgsMapLayer::setMaximumScale( const float theMaxScale )
788 {
789  mMaxScale = theMaxScale;
790 }
791 
792 void QgsMapLayer::setScaleBasedVisibility( const bool enabled )
793 {
794  mScaleBasedVisibility = enabled;
795 }
796 
798 {
799  return mMaxScale;
800 }
801 
802 QStringList QgsMapLayer::subLayers() const
803 {
804  return QStringList(); // Empty
805 }
806 
807 void QgsMapLayer::setLayerOrder( const QStringList &layers )
808 {
809  Q_UNUSED( layers );
810  // NOOP
811 }
812 
813 void QgsMapLayer::setSubLayerVisibility( QString name, bool vis )
814 {
815  Q_UNUSED( name );
816  Q_UNUSED( vis );
817  // NOOP
818 }
819 
821 {
822  return *mCRS;
823 }
824 
825 void QgsMapLayer::setCrs( const QgsCoordinateReferenceSystem& srs, bool emitSignal )
826 {
827  *mCRS = srs;
828 
829  if ( !mCRS->isValid() )
830  {
831  mCRS->setValidationHint( tr( "Specify CRS for layer %1" ).arg( name() ) );
832  mCRS->validate();
833  }
834 
835  if ( emitSignal )
836  emit layerCrsChanged();
837 }
838 
839 QString QgsMapLayer::capitaliseLayerName( const QString& name )
840 {
841  // Capitalise the first letter of the layer name if requested
842  QSettings settings;
843  bool capitaliseLayerName =
844  settings.value( "/qgis/capitaliseLayerName", QVariant( false ) ).toBool();
845 
846  QString layerName( name );
847 
848  if ( capitaliseLayerName )
849  layerName = layerName.left( 1 ).toUpper() + layerName.mid( 1 );
850 
851  return layerName;
852 }
853 
855 {
856  QString myURI = publicSource();
857 
858  // if file is using the VSIFILE mechanism, remove the prefix
859  if ( myURI.startsWith( "/vsigzip/", Qt::CaseInsensitive ) )
860  {
861  myURI.remove( 0, 9 );
862  }
863  else if ( myURI.startsWith( "/vsizip/", Qt::CaseInsensitive ) &&
864  myURI.endsWith( ".zip", Qt::CaseInsensitive ) )
865  {
866  // ideally we should look for .qml file inside zip file
867  myURI.remove( 0, 8 );
868  }
869  else if ( myURI.startsWith( "/vsitar/", Qt::CaseInsensitive ) &&
870  ( myURI.endsWith( ".tar", Qt::CaseInsensitive ) ||
871  myURI.endsWith( ".tar.gz", Qt::CaseInsensitive ) ||
872  myURI.endsWith( ".tgz", Qt::CaseInsensitive ) ) )
873  {
874  // ideally we should look for .qml file inside tar file
875  myURI.remove( 0, 8 );
876  }
877 
878  QFileInfo myFileInfo( myURI );
879  QString key;
880 
881  if ( myFileInfo.exists() )
882  {
883  // if file is using the /vsizip/ or /vsigzip/ mechanism, cleanup the name
884  if ( myURI.endsWith( ".gz", Qt::CaseInsensitive ) )
885  myURI.chop( 3 );
886  else if ( myURI.endsWith( ".zip", Qt::CaseInsensitive ) )
887  myURI.chop( 4 );
888  else if ( myURI.endsWith( ".tar", Qt::CaseInsensitive ) )
889  myURI.chop( 4 );
890  else if ( myURI.endsWith( ".tar.gz", Qt::CaseInsensitive ) )
891  myURI.chop( 7 );
892  else if ( myURI.endsWith( ".tgz", Qt::CaseInsensitive ) )
893  myURI.chop( 4 );
894  myFileInfo.setFile( myURI );
895  // get the file name for our .qml style file
896  key = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".qml";
897  }
898  else
899  {
900  key = publicSource();
901  }
902 
903  return key;
904 }
905 
906 QString QgsMapLayer::loadDefaultStyle( bool & theResultFlag )
907 {
908  return loadNamedStyle( styleURI(), theResultFlag );
909 }
910 
911 bool QgsMapLayer::loadNamedStyleFromDb( const QString &db, const QString &theURI, QString &qml )
912 {
913  QgsDebugMsg( QString( "db = %1 uri = %2" ).arg( db ).arg( theURI ) );
914 
915  bool theResultFlag = false;
916 
917  // read from database
918  sqlite3 *myDatabase;
919  sqlite3_stmt *myPreparedStatement;
920  const char *myTail;
921  int myResult;
922 
923  QgsDebugMsg( QString( "Trying to load style for \"%1\" from \"%2\"" ).arg( theURI ).arg( db ) );
924 
925  if ( db.isEmpty() || !QFile( db ).exists() )
926  return false;
927 
928  myResult = sqlite3_open_v2( db.toUtf8().data(), &myDatabase, SQLITE_OPEN_READONLY, NULL );
929  if ( myResult != SQLITE_OK )
930  {
931  return false;
932  }
933 
934  QString mySql = "select qml from tbl_styles where style=?";
935  myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
936  if ( myResult == SQLITE_OK )
937  {
938  QByteArray param = theURI.toUtf8();
939 
940  if ( sqlite3_bind_text( myPreparedStatement, 1, param.data(), param.length(), SQLITE_STATIC ) == SQLITE_OK &&
941  sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
942  {
943  qml = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) );
944  theResultFlag = true;
945  }
946 
947  sqlite3_finalize( myPreparedStatement );
948  }
949 
950  sqlite3_close( myDatabase );
951 
952  return theResultFlag;
953 }
954 
955 
956 QString QgsMapLayer::loadNamedStyle( const QString &theURI, bool &theResultFlag )
957 {
958  QgsDebugMsg( QString( "uri = %1 myURI = %2" ).arg( theURI ).arg( publicSource() ) );
959 
960  theResultFlag = false;
961 
962  QDomDocument myDocument( "qgis" );
963 
964  // location of problem associated with errorMsg
965  int line, column;
966  QString myErrorMessage;
967 
968  QFile myFile( theURI );
969  if ( myFile.open( QFile::ReadOnly ) )
970  {
971  // read file
972  theResultFlag = myDocument.setContent( &myFile, &myErrorMessage, &line, &column );
973  if ( !theResultFlag )
974  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
975  myFile.close();
976  }
977  else
978  {
979  QFileInfo project( QgsProject::instance()->fileName() );
980  QgsDebugMsg( QString( "project fileName: %1" ).arg( project.absoluteFilePath() ) );
981 
982  QString qml;
983  if ( loadNamedStyleFromDb( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( "qgis.qmldb" ), theURI, qml ) ||
984  ( project.exists() && loadNamedStyleFromDb( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), theURI, qml ) ) ||
985  loadNamedStyleFromDb( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( "resources/qgis.qmldb" ), theURI, qml ) )
986  {
987  theResultFlag = myDocument.setContent( qml, &myErrorMessage, &line, &column );
988  if ( !theResultFlag )
989  {
990  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
991  }
992  }
993  else
994  {
995  myErrorMessage = tr( "Style not found in database" );
996  }
997  }
998 
999  if ( !theResultFlag )
1000  {
1001  return myErrorMessage;
1002  }
1003 
1004  theResultFlag = importNamedStyle( myDocument, myErrorMessage );
1005  if ( !theResultFlag )
1006  myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( theURI ).arg( myErrorMessage );
1007 
1008  return myErrorMessage;
1009 }
1010 
1011 
1012 bool QgsMapLayer::importNamedStyle( QDomDocument& myDocument, QString& myErrorMessage )
1013 {
1014  // get style file version string, if any
1015  QgsProjectVersion fileVersion( myDocument.firstChildElement( "qgis" ).attribute( "version" ) );
1016  QgsProjectVersion thisVersion( QGis::QGIS_VERSION );
1017 
1018  if ( thisVersion > fileVersion )
1019  {
1020  QgsLogger::warning( "Loading a style file that was saved with an older "
1021  "version of qgis (saved in " + fileVersion.text() +
1022  ", loaded in " + QGis::QGIS_VERSION +
1023  "). Problems may occur." );
1024 
1025  QgsProjectFileTransform styleFile( myDocument, fileVersion );
1026  // styleFile.dump();
1027  styleFile.updateRevision( thisVersion );
1028  // styleFile.dump();
1029  }
1030 
1031  // now get the layer node out and pass it over to the layer
1032  // to deserialise...
1033  QDomElement myRoot = myDocument.firstChildElement( "qgis" );
1034  if ( myRoot.isNull() )
1035  {
1036  myErrorMessage = tr( "Root <qgis> element could not be found" );
1037  return false;
1038  }
1039 
1040  // use scale dependent visibility flag
1041  setScaleBasedVisibility( myRoot.attribute( "hasScaleBasedVisibilityFlag" ).toInt() == 1 );
1042  setMinimumScale( myRoot.attribute( "minimumScale" ).toFloat() );
1043  setMaximumScale( myRoot.attribute( "maximumScale" ).toFloat() );
1044 
1045 #if 0
1046  //read transparency level
1047  QDomNode transparencyNode = myRoot.namedItem( "transparencyLevelInt" );
1048  if ( ! transparencyNode.isNull() )
1049  {
1050  // set transparency level only if it's in project
1051  // (otherwise it sets the layer transparent)
1052  QDomElement myElement = transparencyNode.toElement();
1053  setTransparency( myElement.text().toInt() );
1054  }
1055 #endif
1056 
1057  return readSymbology( myRoot, myErrorMessage );
1058 }
1059 
1060 void QgsMapLayer::exportNamedStyle( QDomDocument &doc, QString &errorMsg )
1061 {
1062  QDomImplementation DomImplementation;
1063  QDomDocumentType documentType = DomImplementation.createDocumentType( "qgis", "http://mrcc.com/qgis.dtd", "SYSTEM" );
1064  QDomDocument myDocument( documentType );
1065 
1066  QDomElement myRootNode = myDocument.createElement( "qgis" );
1067  myRootNode.setAttribute( "version", QString( "%1" ).arg( QGis::QGIS_VERSION ) );
1068  myDocument.appendChild( myRootNode );
1069 
1070  myRootNode.setAttribute( "hasScaleBasedVisibilityFlag", hasScaleBasedVisibility() ? 1 : 0 );
1071  myRootNode.setAttribute( "minimumScale", QString::number( minimumScale() ) );
1072  myRootNode.setAttribute( "maximumScale", QString::number( maximumScale() ) );
1073 
1074 #if 0
1075  // <transparencyLevelInt>
1076  QDomElement transparencyLevelIntElement = myDocument.createElement( "transparencyLevelInt" );
1077  QDomText transparencyLevelIntText = myDocument.createTextNode( QString::number( getTransparency() ) );
1078  transparencyLevelIntElement.appendChild( transparencyLevelIntText );
1079  myRootNode.appendChild( transparencyLevelIntElement );
1080 #endif
1081 
1082  if ( !writeSymbology( myRootNode, myDocument, errorMsg ) )
1083  {
1084  errorMsg = QObject::tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1085  return;
1086  }
1087  doc = myDocument;
1088 }
1089 
1090 QString QgsMapLayer::saveDefaultStyle( bool & theResultFlag )
1091 {
1092  return saveNamedStyle( styleURI(), theResultFlag );
1093 }
1094 
1095 QString QgsMapLayer::saveNamedStyle( const QString &theURI, bool &theResultFlag )
1096 {
1097  QString myErrorMessage;
1098  QDomDocument myDocument;
1099  exportNamedStyle( myDocument, myErrorMessage );
1100 
1101  // check if the uri is a file or ends with .qml,
1102  // which indicates that it should become one
1103  // everything else goes to the database
1104  QString filename;
1105 
1106  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this );
1107  if ( vlayer && vlayer->providerType() == "ogr" )
1108  {
1109  QStringList theURIParts = theURI.split( "|" );
1110  filename = theURIParts[0];
1111  }
1112  else if ( vlayer && vlayer->providerType() == "gpx" )
1113  {
1114  QStringList theURIParts = theURI.split( "?" );
1115  filename = theURIParts[0];
1116  }
1117  else if ( vlayer && vlayer->providerType() == "delimitedtext" )
1118  {
1119  filename = QUrl::fromEncoded( theURI.toAscii() ).toLocalFile();
1120  }
1121  else
1122  {
1123  filename = theURI;
1124  }
1125 
1126  QFileInfo myFileInfo( filename );
1127  if ( myFileInfo.exists() || filename.endsWith( ".qml", Qt::CaseInsensitive ) )
1128  {
1129  QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
1130  if ( !myDirInfo.isWritable() )
1131  {
1132  return tr( "The directory containing your dataset needs to be writable!" );
1133  }
1134 
1135  // now construct the file name for our .qml style file
1136  QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".qml";
1137 
1138  QFile myFile( myFileName );
1139  if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
1140  {
1141  QTextStream myFileStream( &myFile );
1142  // save as utf-8 with 2 spaces for indents
1143  myDocument.save( myFileStream, 2 );
1144  myFile.close();
1145  theResultFlag = true;
1146  return tr( "Created default style file as %1" ).arg( myFileName );
1147  }
1148  else
1149  {
1150  theResultFlag = false;
1151  return tr( "ERROR: Failed to created default style file as %1. Check file permissions and retry." ).arg( myFileName );
1152  }
1153  }
1154  else
1155  {
1156  QString qml = myDocument.toString();
1157 
1158  // read from database
1159  sqlite3 *myDatabase;
1160  sqlite3_stmt *myPreparedStatement;
1161  const char *myTail;
1162  int myResult;
1163 
1164  myResult = sqlite3_open( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( "qgis.qmldb" ).toUtf8().data(), &myDatabase );
1165  if ( myResult != SQLITE_OK )
1166  {
1167  return tr( "User database could not be opened." );
1168  }
1169 
1170  QByteArray param0 = theURI.toUtf8();
1171  QByteArray param1 = qml.toUtf8();
1172 
1173  QString mySql = "create table if not exists tbl_styles(style varchar primary key,qml varchar)";
1174  myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
1175  if ( myResult == SQLITE_OK )
1176  {
1177  if ( sqlite3_step( myPreparedStatement ) != SQLITE_DONE )
1178  {
1179  sqlite3_finalize( myPreparedStatement );
1180  sqlite3_close( myDatabase );
1181  theResultFlag = false;
1182  return tr( "The style table could not be created." );
1183  }
1184  }
1185 
1186  sqlite3_finalize( myPreparedStatement );
1187 
1188  mySql = "insert into tbl_styles(style,qml) values (?,?)";
1189  myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
1190  if ( myResult == SQLITE_OK )
1191  {
1192  if ( sqlite3_bind_text( myPreparedStatement, 1, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
1193  sqlite3_bind_text( myPreparedStatement, 2, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
1194  sqlite3_step( myPreparedStatement ) == SQLITE_DONE )
1195  {
1196  theResultFlag = true;
1197  myErrorMessage = tr( "The style %1 was saved to database" ).arg( theURI );
1198  }
1199  }
1200 
1201  sqlite3_finalize( myPreparedStatement );
1202 
1203  if ( !theResultFlag )
1204  {
1205  QString mySql = "update tbl_styles set qml=? where style=?";
1206  myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
1207  if ( myResult == SQLITE_OK )
1208  {
1209  if ( sqlite3_bind_text( myPreparedStatement, 2, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
1210  sqlite3_bind_text( myPreparedStatement, 1, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
1211  sqlite3_step( myPreparedStatement ) == SQLITE_DONE )
1212  {
1213  theResultFlag = true;
1214  myErrorMessage = tr( "The style %1 was updated in the database." ).arg( theURI );
1215  }
1216  else
1217  {
1218  theResultFlag = false;
1219  myErrorMessage = tr( "The style %1 could not be updated in the database." ).arg( theURI );
1220  }
1221  }
1222  else
1223  {
1224  theResultFlag = false;
1225  myErrorMessage = tr( "The style %1 could not be inserted into database." ).arg( theURI );
1226  }
1227 
1228  sqlite3_finalize( myPreparedStatement );
1229  }
1230 
1231  sqlite3_close( myDatabase );
1232  }
1233 
1234  return myErrorMessage;
1235 }
1236 
1237 void QgsMapLayer::exportSldStyle( QDomDocument &doc, QString &errorMsg )
1238 {
1239  QDomDocument myDocument = QDomDocument();
1240 
1241  QDomNode header = myDocument.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" );
1242  myDocument.appendChild( header );
1243 
1244  // Create the root element
1245  QDomElement root = myDocument.createElementNS( "http://www.opengis.net/sld", "StyledLayerDescriptor" );
1246  root.setAttribute( "version", "1.1.0" );
1247  root.setAttribute( "xsi:schemaLocation", "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" );
1248  root.setAttribute( "xmlns:ogc", "http://www.opengis.net/ogc" );
1249  root.setAttribute( "xmlns:se", "http://www.opengis.net/se" );
1250  root.setAttribute( "xmlns:xlink", "http://www.w3.org/1999/xlink" );
1251  root.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" );
1252  myDocument.appendChild( root );
1253 
1254  // Create the NamedLayer element
1255  QDomElement namedLayerNode = myDocument.createElement( "NamedLayer" );
1256  root.appendChild( namedLayerNode );
1257 
1258  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this );
1259  if ( !vlayer )
1260  {
1261  errorMsg = tr( "Could not save symbology because:\n%1" )
1262  .arg( "Non-vector layers not supported yet" );
1263  return;
1264  }
1265 
1266  if ( !vlayer->writeSld( namedLayerNode, myDocument, errorMsg ) )
1267  {
1268  errorMsg = tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1269  return;
1270  }
1271 
1272  doc = myDocument;
1273 }
1274 
1275 QString QgsMapLayer::saveSldStyle( const QString &theURI, bool &theResultFlag )
1276 {
1277  QString errorMsg;
1278  QDomDocument myDocument;
1279  exportSldStyle( myDocument, errorMsg );
1280  if ( !errorMsg.isNull() )
1281  {
1282  theResultFlag = false;
1283  return errorMsg;
1284  }
1285  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this );
1286 
1287  // check if the uri is a file or ends with .sld,
1288  // which indicates that it should become one
1289  QString filename;
1290  if ( vlayer->providerType() == "ogr" )
1291  {
1292  QStringList theURIParts = theURI.split( "|" );
1293  filename = theURIParts[0];
1294  }
1295  else if ( vlayer->providerType() == "gpx" )
1296  {
1297  QStringList theURIParts = theURI.split( "?" );
1298  filename = theURIParts[0];
1299  }
1300  else if ( vlayer->providerType() == "delimitedtext" )
1301  {
1302  filename = QUrl::fromEncoded( theURI.toAscii() ).toLocalFile();
1303  }
1304  else
1305  {
1306  filename = theURI;
1307  }
1308 
1309  QFileInfo myFileInfo( filename );
1310  if ( myFileInfo.exists() || filename.endsWith( ".sld", Qt::CaseInsensitive ) )
1311  {
1312  QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
1313  if ( !myDirInfo.isWritable() )
1314  {
1315  return tr( "The directory containing your dataset needs to be writable!" );
1316  }
1317 
1318  // now construct the file name for our .sld style file
1319  QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".sld";
1320 
1321  QFile myFile( myFileName );
1322  if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
1323  {
1324  QTextStream myFileStream( &myFile );
1325  // save as utf-8 with 2 spaces for indents
1326  myDocument.save( myFileStream, 2 );
1327  myFile.close();
1328  theResultFlag = true;
1329  return tr( "Created default style file as %1" ).arg( myFileName );
1330  }
1331  }
1332 
1333  theResultFlag = false;
1334  return tr( "ERROR: Failed to created SLD style file as %1. Check file permissions and retry." ).arg( filename );
1335 }
1336 
1337 QString QgsMapLayer::loadSldStyle( const QString &theURI, bool &theResultFlag )
1338 {
1339  QgsDebugMsg( "Entered." );
1340 
1341  theResultFlag = false;
1342 
1343  QDomDocument myDocument;
1344 
1345  // location of problem associated with errorMsg
1346  int line, column;
1347  QString myErrorMessage;
1348 
1349  QFile myFile( theURI );
1350  if ( myFile.open( QFile::ReadOnly ) )
1351  {
1352  // read file
1353  theResultFlag = myDocument.setContent( &myFile, true, &myErrorMessage, &line, &column );
1354  if ( !theResultFlag )
1355  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1356  myFile.close();
1357  }
1358  else
1359  {
1360  myErrorMessage = tr( "Unable to open file %1" ).arg( theURI );
1361  }
1362 
1363  if ( !theResultFlag )
1364  {
1365  return myErrorMessage;
1366  }
1367 
1368  // check for root SLD element
1369  QDomElement myRoot = myDocument.firstChildElement( "StyledLayerDescriptor" );
1370  if ( myRoot.isNull() )
1371  {
1372  myErrorMessage = QString( "Error: StyledLayerDescriptor element not found in %1" ).arg( theURI );
1373  theResultFlag = false;
1374  return myErrorMessage;
1375  }
1376 
1377  // now get the style node out and pass it over to the layer
1378  // to deserialise...
1379  QDomElement namedLayerElem = myRoot.firstChildElement( "NamedLayer" );
1380  if ( namedLayerElem.isNull() )
1381  {
1382  myErrorMessage = QString( "Info: NamedLayer element not found." );
1383  theResultFlag = false;
1384  return myErrorMessage;
1385  }
1386 
1387  QString errorMsg;
1388  theResultFlag = readSld( namedLayerElem, errorMsg );
1389  if ( !theResultFlag )
1390  {
1391  myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( theURI ).arg( errorMsg );
1392  return myErrorMessage;
1393  }
1394 
1395  return "";
1396 }
1397 
1398 
1400 {
1401  return &mUndoStack;
1402 }
1403 
1404 
1405 void QgsMapLayer::setCustomProperty( const QString& key, const QVariant& value )
1406 {
1407  mCustomProperties.setValue( key, value );
1408 }
1409 
1410 QVariant QgsMapLayer::customProperty( const QString& value, const QVariant& defaultValue ) const
1411 {
1412  return mCustomProperties.value( value, defaultValue );
1413 }
1414 
1415 void QgsMapLayer::removeCustomProperty( const QString& key )
1416 {
1417  mCustomProperties.remove( key );
1418 }
1419 
1420 
1421 
1423 {
1424  return false;
1425 }
1426 
1427 void QgsMapLayer::setValid( bool valid )
1428 {
1429  mValid = valid;
1430 }
1431 
1433 {
1434  emit repaintRequested();
1435 }
1436 
1438 {
1439  if ( legend == mLegend )
1440  return;
1441 
1442  delete mLegend;
1443  mLegend = legend;
1444 
1445  if ( mLegend )
1446  connect( mLegend, SIGNAL( itemsChanged() ), this, SIGNAL( legendChanged() ) );
1447 
1448  emit legendChanged();
1449 }
1450 
1452 {
1453  return mLegend;
1454 }
1455 
1457 {
1458  return mStyleManager;
1459 }
1460 
1462 {
1463  emit repaintRequested();
1464 }
1465 
1467 {
1468  emit repaintRequested();
1469 }
1470 
1472 {
1473  return QString();
1474 }
1475 
1477 {
1478  mExtent = r;
1479 }
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
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:595
QString mKeywordList
Definition: qgsmaplayer.h:587
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:591
#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:604
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.
QgsPluginLayer * createLayer(QString typeName, const QString &uri=QString())
return new layer if corresponding plugin has been found, else return NULL.
QString mLayerName
Name of the layer - used for display.
Definition: qgsmaplayer.h:577
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:568
QString mMetadataUrl
MetadataUrl of the layer.
Definition: qgsmaplayer.h:598
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:590
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:571
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:583
virtual bool readSld(const QDomNode &node, QString &errorMessage)
Definition: qgsmaplayer.h:353
QString mMetadataUrlFormat
Definition: qgsmaplayer.h:600
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:594
QString mAbstract
Description of the layer.
Definition: qgsmaplayer.h:586
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:574
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:351
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:603
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...
const QString & title() const
Definition: qgsmaplayer.h:94
QString mLayerOrigName
Original name of the layer.
Definition: qgsmaplayer.h:581
void setValid(bool valid)
set whether layer is valid or not - should be used in constructor.
QString username() const
QString mMetadataUrlType
Definition: qgsmaplayer.h:599
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)