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