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