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