QGIS API Documentation  2.99.0-Master (283d45a)
qgsmaplayer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmaplayer.cpp - description
3  -------------------
4  begin : Fri Jun 28 2002
5  copyright : (C) 2002 by Gary E.Sherman
6  email : sherman at mrcc.com
7 ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 
19 #include <QDateTime>
20 #include <QDir>
21 #include <QDomDocument>
22 #include <QDomElement>
23 #include <QDomImplementation>
24 #include <QDomNode>
25 #include <QFile>
26 #include <QFileInfo>
27 #include <QSettings> // TODO: get rid of it [MD]
28 #include <QTextStream>
29 #include <QUrl>
30 
31 #include <sqlite3.h>
32 
33 #include "qgsapplication.h"
35 #include "qgsdatasourceuri.h"
36 #include "qgslogger.h"
37 #include "qgsauthmanager.h"
38 #include "qgsmaplayer.h"
39 #include "qgsmaplayerlegend.h"
41 #include "qgspluginlayer.h"
42 #include "qgspluginlayerregistry.h"
44 #include "qgsproject.h"
45 #include "qgsproviderregistry.h"
46 #include "qgsrasterlayer.h"
47 #include "qgsrectangle.h"
48 #include "qgsvectorlayer.h"
49 #include "qgsvectordataprovider.h"
50 #include "qgsxmlutils.h"
51 
52 
54  const QString& lyrname,
55  const QString& source )
56  : mValid( false ) // assume the layer is invalid
57  , mDataSource( source )
58  , mLayerOrigName( lyrname ) // store the original name
59  , mID( QLatin1String( "" ) )
60  , mLayerType( type )
61  , mBlendMode( QPainter::CompositionMode_SourceOver ) // Default to normal blending
62  , mLegend( nullptr )
63  , mStyleManager( new QgsMapLayerStyleManager( this ) )
64 {
65  // Set the display name = internal name
67 
68  mShortName = QLatin1String( "" );
69  //mShortName.replace( QRegExp( "[\\W]" ), "_" );
70 
71  // Generate the unique ID of this layer
72  QDateTime dt = QDateTime::currentDateTime();
73  mID = lyrname + dt.toString( QStringLiteral( "yyyyMMddhhmmsszzz" ) );
74  // Tidy the ID up to avoid characters that may cause problems
75  // elsewhere (e.g in some parts of XML). Replaces every non-word
76  // character (word characters are the alphabet, numbers and
77  // underscore) with an underscore.
78  // Note that the first backslashe in the regular expression is
79  // there for the compiler, so the pattern is actually \W
80  mID.replace( QRegExp( "[\\W]" ), QStringLiteral( "_" ) );
81 
82  //set some generous defaults for scale based visibility
83  mMinScale = 0;
84  mMaxScale = 100000000;
85  mScaleBasedVisibility = false;
86 
88 }
89 
91 {
92  delete mLegend;
93  delete mStyleManager;
94 }
95 
97 {
98  return mLayerType;
99 }
100 
102 QString QgsMapLayer::id() const
103 {
104  return mID;
105 }
106 
107 void QgsMapLayer::setName( const QString& name )
108 {
109  QString newName = capitalizeLayerName( name );
110  if ( name == mLayerOrigName && newName == mLayerName )
111  return;
112 
113  mLayerOrigName = name; // store the new original name
114  mLayerName = newName;
115 
116  emit nameChanged();
117 }
118 
120 QString QgsMapLayer::name() const
121 {
122  QgsDebugMsgLevel( "returning name '" + mLayerName + '\'', 4 );
123  return mLayerName;
124 }
125 
127 {
128  // Redo this every time we're asked for it, as we don't know if
129  // dataSource has changed.
130  QString safeName = QgsDataSourceUri::removePassword( mDataSource );
131  return safeName;
132 }
133 
134 QString QgsMapLayer::source() const
135 {
136  return mDataSource;
137 }
138 
140 {
141  return mExtent;
142 }
143 
145 void QgsMapLayer::setBlendMode( QPainter::CompositionMode blendMode )
146 {
147  mBlendMode = blendMode;
148  emit blendModeChanged( blendMode );
149  emit styleChanged();
150 }
151 
153 QPainter::CompositionMode QgsMapLayer::blendMode() const
154 {
155  return mBlendMode;
156 }
157 
158 
159 bool QgsMapLayer::readLayerXml( const QDomElement& layerElement )
160 {
161  bool layerError;
162 
163  QDomNode mnl;
164  QDomElement mne;
165 
166  // read provider
167  QString provider;
168  mnl = layerElement.namedItem( QStringLiteral( "provider" ) );
169  mne = mnl.toElement();
170  provider = mne.text();
171 
172  // set data source
173  mnl = layerElement.namedItem( QStringLiteral( "datasource" ) );
174  mne = mnl.toElement();
175  mDataSource = mne.text();
176 
177  // if the layer needs authentication, ensure the master password is set
178  QRegExp rx( "authcfg=([a-z]|[A-Z]|[0-9]){7}" );
179  if (( rx.indexIn( mDataSource ) != -1 )
181  {
182  return false;
183  }
184 
185  // TODO: this should go to providers
186  // see also QgsProject::createEmbeddedLayer
187  if ( provider == QLatin1String( "spatialite" ) )
188  {
190  uri.setDatabase( QgsProject::instance()->readPath( uri.database() ) );
191  mDataSource = uri.uri();
192  }
193  else if ( provider == QLatin1String( "ogr" ) )
194  {
195  QStringList theURIParts = mDataSource.split( '|' );
196  theURIParts[0] = QgsProject::instance()->readPath( theURIParts[0] );
197  mDataSource = theURIParts.join( QStringLiteral( "|" ) );
198  }
199  else if ( provider == QLatin1String( "gpx" ) )
200  {
201  QStringList theURIParts = mDataSource.split( '?' );
202  theURIParts[0] = QgsProject::instance()->readPath( theURIParts[0] );
203  mDataSource = theURIParts.join( QStringLiteral( "?" ) );
204  }
205  else if ( provider == QLatin1String( "delimitedtext" ) )
206  {
207  QUrl urlSource = QUrl::fromEncoded( mDataSource.toLatin1() );
208 
209  if ( !mDataSource.startsWith( QLatin1String( "file:" ) ) )
210  {
211  QUrl file = QUrl::fromLocalFile( mDataSource.left( mDataSource.indexOf( '?' ) ) );
212  urlSource.setScheme( QStringLiteral( "file" ) );
213  urlSource.setPath( file.path() );
214  }
215 
216  QUrl urlDest = QUrl::fromLocalFile( QgsProject::instance()->readPath( urlSource.toLocalFile() ) );
217  urlDest.setQueryItems( urlSource.queryItems() );
218  mDataSource = QString::fromAscii( urlDest.toEncoded() );
219  }
220  else if ( provider == QLatin1String( "wms" ) )
221  {
222  // >>> BACKWARD COMPATIBILITY < 1.9
223  // For project file backward compatibility we must support old format:
224  // 1. mode: <url>
225  // example: http://example.org/wms?
226  // 2. mode: tiled=<width>;<height>;<resolution>;<resolution>...,ignoreUrl=GetMap;GetFeatureInfo,featureCount=<count>,username=<name>,password=<password>,url=<url>
227  // example: tiled=256;256;0.703;0.351,url=http://example.org/tilecache?
228  // example: featureCount=10,http://example.org/wms?
229  // example: ignoreUrl=GetMap;GetFeatureInfo,username=cimrman,password=jara,url=http://example.org/wms?
230  // This is modified version of old QgsWmsProvider::parseUri
231  // The new format has always params crs,format,layers,styles and that params
232  // should not appear in old format url -> use them to identify version
233  // XYZ tile layers do not need to contain crs,format params, but they have type=xyz
234  if ( !mDataSource.contains( QLatin1String( "type=" ) ) &&
235  !mDataSource.contains( QLatin1String( "crs=" ) ) && !mDataSource.contains( QLatin1String( "format=" ) ) )
236  {
237  QgsDebugMsg( "Old WMS URI format detected -> converting to new format" );
238  QgsDataSourceUri uri;
239  if ( !mDataSource.startsWith( QLatin1String( "http:" ) ) )
240  {
241  QStringList parts = mDataSource.split( ',' );
242  QStringListIterator iter( parts );
243  while ( iter.hasNext() )
244  {
245  QString item = iter.next();
246  if ( item.startsWith( QLatin1String( "username=" ) ) )
247  {
248  uri.setParam( QStringLiteral( "username" ), item.mid( 9 ) );
249  }
250  else if ( item.startsWith( QLatin1String( "password=" ) ) )
251  {
252  uri.setParam( QStringLiteral( "password" ), item.mid( 9 ) );
253  }
254  else if ( item.startsWith( QLatin1String( "tiled=" ) ) )
255  {
256  // in < 1.9 tiled= may apper in to variants:
257  // tiled=width;height - non tiled mode, specifies max width and max height
258  // tiled=width;height;resolutions-1;resolution2;... - tile mode
259 
260  QStringList params = item.mid( 6 ).split( ';' );
261 
262  if ( params.size() == 2 ) // non tiled mode
263  {
264  uri.setParam( QStringLiteral( "maxWidth" ), params.takeFirst() );
265  uri.setParam( QStringLiteral( "maxHeight" ), params.takeFirst() );
266  }
267  else if ( params.size() > 2 ) // tiled mode
268  {
269  // resolutions are no more needed and size limit is not used for tiles
270  // we have to tell to the provider however that it is tiled
271  uri.setParam( QStringLiteral( "tileMatrixSet" ), QLatin1String( "" ) );
272  }
273  }
274  else if ( item.startsWith( QLatin1String( "featureCount=" ) ) )
275  {
276  uri.setParam( QStringLiteral( "featureCount" ), item.mid( 13 ) );
277  }
278  else if ( item.startsWith( QLatin1String( "url=" ) ) )
279  {
280  uri.setParam( QStringLiteral( "url" ), item.mid( 4 ) );
281  }
282  else if ( item.startsWith( QLatin1String( "ignoreUrl=" ) ) )
283  {
284  uri.setParam( QStringLiteral( "ignoreUrl" ), item.mid( 10 ).split( ';' ) );
285  }
286  }
287  }
288  else
289  {
290  uri.setParam( QStringLiteral( "url" ), mDataSource );
291  }
292  mDataSource = uri.encodedUri();
293  // At this point, the URI is obviously incomplete, we add additional params
294  // in QgsRasterLayer::readXml
295  }
296  // <<< BACKWARD COMPATIBILITY < 1.9
297  }
298  else
299  {
300  bool handled = false;
301 
302  if ( provider == QLatin1String( "gdal" ) )
303  {
304  if ( mDataSource.startsWith( QLatin1String( "NETCDF:" ) ) )
305  {
306  // NETCDF:filename:variable
307  // filename can be quoted with " as it can contain colons
308  QRegExp r( "NETCDF:(.+):([^:]+)" );
309  if ( r.exactMatch( mDataSource ) )
310  {
311  QString filename = r.cap( 1 );
312  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
313  filename = filename.mid( 1, filename.length() - 2 );
314  mDataSource = "NETCDF:\"" + QgsProject::instance()->readPath( filename ) + "\":" + r.cap( 2 );
315  handled = true;
316  }
317  }
318  else if ( mDataSource.startsWith( QLatin1String( "HDF4_SDS:" ) ) )
319  {
320  // HDF4_SDS:subdataset_type:file_name:subdataset_index
321  // filename can be quoted with " as it can contain colons
322  QRegExp r( "HDF4_SDS:([^:]+):(.+):([^:]+)" );
323  if ( r.exactMatch( mDataSource ) )
324  {
325  QString filename = r.cap( 2 );
326  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
327  filename = filename.mid( 1, filename.length() - 2 );
328  mDataSource = "HDF4_SDS:" + r.cap( 1 ) + ":\"" + QgsProject::instance()->readPath( filename ) + "\":" + r.cap( 3 );
329  handled = true;
330  }
331  }
332  else if ( mDataSource.startsWith( QLatin1String( "HDF5:" ) ) )
333  {
334  // HDF5:file_name:subdataset
335  // filename can be quoted with " as it can contain colons
336  QRegExp r( "HDF5:(.+):([^:]+)" );
337  if ( r.exactMatch( mDataSource ) )
338  {
339  QString filename = r.cap( 1 );
340  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
341  filename = filename.mid( 1, filename.length() - 2 );
342  mDataSource = "HDF5:\"" + QgsProject::instance()->readPath( filename ) + "\":" + r.cap( 2 );
343  handled = true;
344  }
345  }
346  else if ( mDataSource.contains( QRegExp( "^(NITF_IM|RADARSAT_2_CALIB):" ) ) )
347  {
348  // NITF_IM:0:filename
349  // RADARSAT_2_CALIB:?:filename
350  QRegExp r( "([^:]+):([^:]+):(.+)" );
351  if ( r.exactMatch( mDataSource ) )
352  {
353  mDataSource = r.cap( 1 ) + ':' + r.cap( 2 ) + ':' + QgsProject::instance()->readPath( r.cap( 3 ) );
354  handled = true;
355  }
356  }
357  }
358 
359  if ( !handled )
361  }
362 
363  // Set the CRS from project file, asking the user if necessary.
364  // Make it the saved CRS to have WMS layer projected correctly.
365  // We will still overwrite whatever GDAL etc picks up anyway
366  // further down this function.
367  mnl = layerElement.namedItem( QStringLiteral( "layername" ) );
368  mne = mnl.toElement();
369 
371  CUSTOM_CRS_VALIDATION savedValidation;
372 
373  QDomNode srsNode = layerElement.namedItem( QStringLiteral( "srs" ) );
374  mCRS.readXml( srsNode );
375  mCRS.setValidationHint( tr( "Specify CRS for layer %1" ).arg( mne.text() ) );
376  mCRS.validate();
377  savedCRS = mCRS;
378 
379  // Do not validate any projections in children, they will be overwritten anyway.
380  // No need to ask the user for a projections when it is overwritten, is there?
383 
384  // now let the children grab what they need from the Dom node.
385  layerError = !readXml( layerElement );
386 
387  // overwrite CRS with what we read from project file before the raster/vector
388  // file readnig functions changed it. They will if projections is specfied in the file.
389  // FIXME: is this necessary?
391  mCRS = savedCRS;
392 
393  // Abort if any error in layer, such as not found.
394  if ( layerError )
395  {
396  return false;
397  }
398 
399  // the internal name is just the data source basename
400  //QFileInfo dataSourceFileInfo( mDataSource );
401  //internalName = dataSourceFileInfo.baseName();
402 
403  // set ID
404  mnl = layerElement.namedItem( QStringLiteral( "id" ) );
405  if ( ! mnl.isNull() )
406  {
407  mne = mnl.toElement();
408  if ( ! mne.isNull() && mne.text().length() > 10 ) // should be at least 17 (yyyyMMddhhmmsszzz)
409  {
410  mID = mne.text();
411  }
412  }
413 
414  // use scale dependent visibility flag
415  setScaleBasedVisibility( layerElement.attribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ) ).toInt() == 1 );
416  setMinimumScale( layerElement.attribute( QStringLiteral( "minimumScale" ) ).toDouble() );
417  setMaximumScale( layerElement.attribute( QStringLiteral( "maximumScale" ) ).toDouble() );
418 
419  QDomNode extentNode = layerElement.namedItem( QStringLiteral( "extent" ) );
420  if ( !extentNode.isNull() )
421  {
422  setExtent( QgsXmlUtils::readRectangle( extentNode.toElement() ) );
423  }
424 
425  // set name
426  mnl = layerElement.namedItem( QStringLiteral( "layername" ) );
427  mne = mnl.toElement();
428  setName( mne.text() );
429 
430  //short name
431  QDomElement shortNameElem = layerElement.firstChildElement( QStringLiteral( "shortname" ) );
432  if ( !shortNameElem.isNull() )
433  {
434  mShortName = shortNameElem.text();
435  }
436 
437  //title
438  QDomElement titleElem = layerElement.firstChildElement( QStringLiteral( "title" ) );
439  if ( !titleElem.isNull() )
440  {
441  mTitle = titleElem.text();
442  }
443 
444  //abstract
445  QDomElement abstractElem = layerElement.firstChildElement( QStringLiteral( "abstract" ) );
446  if ( !abstractElem.isNull() )
447  {
448  mAbstract = abstractElem.text();
449  }
450 
451  //keywordList
452  QDomElement keywordListElem = layerElement.firstChildElement( QStringLiteral( "keywordList" ) );
453  if ( !keywordListElem.isNull() )
454  {
455  QStringList kwdList;
456  for ( QDomNode n = keywordListElem.firstChild(); !n.isNull(); n = n.nextSibling() )
457  {
458  kwdList << n.toElement().text();
459  }
460  mKeywordList = kwdList.join( QStringLiteral( ", " ) );
461  }
462 
463  //metadataUrl
464  QDomElement dataUrlElem = layerElement.firstChildElement( QStringLiteral( "dataUrl" ) );
465  if ( !dataUrlElem.isNull() )
466  {
467  mDataUrl = dataUrlElem.text();
468  mDataUrlFormat = dataUrlElem.attribute( QStringLiteral( "format" ), QLatin1String( "" ) );
469  }
470 
471  //legendUrl
472  QDomElement legendUrlElem = layerElement.firstChildElement( QStringLiteral( "legendUrl" ) );
473  if ( !legendUrlElem.isNull() )
474  {
475  mLegendUrl = legendUrlElem.text();
476  mLegendUrlFormat = legendUrlElem.attribute( QStringLiteral( "format" ), QLatin1String( "" ) );
477  }
478 
479  //attribution
480  QDomElement attribElem = layerElement.firstChildElement( QStringLiteral( "attribution" ) );
481  if ( !attribElem.isNull() )
482  {
483  mAttribution = attribElem.text();
484  mAttributionUrl = attribElem.attribute( QStringLiteral( "href" ), QLatin1String( "" ) );
485  }
486 
487  //metadataUrl
488  QDomElement metaUrlElem = layerElement.firstChildElement( QStringLiteral( "metadataUrl" ) );
489  if ( !metaUrlElem.isNull() )
490  {
491  mMetadataUrl = metaUrlElem.text();
492  mMetadataUrlType = metaUrlElem.attribute( QStringLiteral( "type" ), QLatin1String( "" ) );
493  mMetadataUrlFormat = metaUrlElem.attribute( QStringLiteral( "format" ), QLatin1String( "" ) );
494  }
495 
496 #if 0
497  //read transparency level
498  QDomNode transparencyNode = layer_node.namedItem( "transparencyLevelInt" );
499  if ( ! transparencyNode.isNull() )
500  {
501  // set transparency level only if it's in project
502  // (otherwise it sets the layer transparent)
503  QDomElement myElement = transparencyNode.toElement();
504  setTransparency( myElement.text().toInt() );
505  }
506 #endif
507 
508  readCustomProperties( layerElement );
509 
510  return true;
511 } // bool QgsMapLayer::readLayerXML
512 
513 
514 bool QgsMapLayer::readXml( const QDomNode& layer_node )
515 {
516  Q_UNUSED( layer_node );
517  // NOP by default; children will over-ride with behavior specific to them
518 
519  return true;
520 } // void QgsMapLayer::readXml
521 
522 
523 
524 bool QgsMapLayer::writeLayerXml( QDomElement& layerElement, QDomDocument& document, const QString& relativeBasePath ) const
525 {
526  // use scale dependent visibility flag
527  layerElement.setAttribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ), hasScaleBasedVisibility() ? 1 : 0 );
528  layerElement.setAttribute( QStringLiteral( "minimumScale" ), QString::number( minimumScale() ) );
529  layerElement.setAttribute( QStringLiteral( "maximumScale" ), QString::number( maximumScale() ) );
530 
531  if ( !mExtent.isNull() )
532  {
533  layerElement.appendChild( QgsXmlUtils::writeRectangle( mExtent, document ) );
534  }
535 
536  // ID
537  QDomElement layerId = document.createElement( QStringLiteral( "id" ) );
538  QDomText layerIdText = document.createTextNode( id() );
539  layerId.appendChild( layerIdText );
540 
541  layerElement.appendChild( layerId );
542 
543  // data source
544  QDomElement dataSource = document.createElement( QStringLiteral( "datasource" ) );
545 
546  QString src = source();
547 
548  const QgsVectorLayer *vlayer = qobject_cast<const QgsVectorLayer *>( this );
549  // TODO: what about postgres, mysql and others, they should not go through writePath()
550  if ( vlayer && vlayer->providerType() == QLatin1String( "spatialite" ) )
551  {
552  QgsDataSourceUri uri( src );
553  QString database = QgsProject::instance()->writePath( uri.database(), relativeBasePath );
554  uri.setConnection( uri.host(), uri.port(), database, uri.username(), uri.password() );
555  src = uri.uri();
556  }
557  else if ( vlayer && vlayer->providerType() == QLatin1String( "ogr" ) )
558  {
559  QStringList theURIParts = src.split( '|' );
560  theURIParts[0] = QgsProject::instance()->writePath( theURIParts[0], relativeBasePath );
561  src = theURIParts.join( QStringLiteral( "|" ) );
562  }
563  else if ( vlayer && vlayer->providerType() == QLatin1String( "gpx" ) )
564  {
565  QStringList theURIParts = src.split( '?' );
566  theURIParts[0] = QgsProject::instance()->writePath( theURIParts[0], relativeBasePath );
567  src = theURIParts.join( QStringLiteral( "?" ) );
568  }
569  else if ( vlayer && vlayer->providerType() == QLatin1String( "delimitedtext" ) )
570  {
571  QUrl urlSource = QUrl::fromEncoded( src.toLatin1() );
572  QUrl urlDest = QUrl::fromLocalFile( QgsProject::instance()->writePath( urlSource.toLocalFile(), relativeBasePath ) );
573  urlDest.setQueryItems( urlSource.queryItems() );
574  src = QString::fromAscii( urlDest.toEncoded() );
575  }
576  else if ( vlayer && vlayer->providerType() == QLatin1String( "memory" ) )
577  {
578  // Refetch the source from the provider, because adding fields actually changes the source for this provider.
579  src = vlayer->dataProvider()->dataSourceUri();
580  }
581  else
582  {
583  bool handled = false;
584 
585  if ( !vlayer )
586  {
587  const QgsRasterLayer *rlayer = qobject_cast<const QgsRasterLayer *>( this );
588  // Update path for subdataset
589  if ( rlayer && rlayer->providerType() == QLatin1String( "gdal" ) )
590  {
591  if ( src.startsWith( QLatin1String( "NETCDF:" ) ) )
592  {
593  // NETCDF:filename:variable
594  // filename can be quoted with " as it can contain colons
595  QRegExp r( "NETCDF:(.+):([^:]+)" );
596  if ( r.exactMatch( src ) )
597  {
598  QString filename = r.cap( 1 );
599  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
600  filename = filename.mid( 1, filename.length() - 2 );
601  src = "NETCDF:\"" + QgsProject::instance()->writePath( filename, relativeBasePath ) + "\":" + r.cap( 2 );
602  handled = true;
603  }
604  }
605  else if ( src.startsWith( QLatin1String( "HDF4_SDS:" ) ) )
606  {
607  // HDF4_SDS:subdataset_type:file_name:subdataset_index
608  // filename can be quoted with " as it can contain colons
609  QRegExp r( "HDF4_SDS:([^:]+):(.+):([^:]+)" );
610  if ( r.exactMatch( src ) )
611  {
612  QString filename = r.cap( 2 );
613  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
614  filename = filename.mid( 1, filename.length() - 2 );
615  src = "HDF4_SDS:" + r.cap( 1 ) + ":\"" + QgsProject::instance()->writePath( filename, relativeBasePath ) + "\":" + r.cap( 3 );
616  handled = true;
617  }
618  }
619  else if ( src.startsWith( QLatin1String( "HDF5:" ) ) )
620  {
621  // HDF5:file_name:subdataset
622  // filename can be quoted with " as it can contain colons
623  QRegExp r( "HDF5:(.+):([^:]+)" );
624  if ( r.exactMatch( src ) )
625  {
626  QString filename = r.cap( 1 );
627  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
628  filename = filename.mid( 1, filename.length() - 2 );
629  src = "HDF5:\"" + QgsProject::instance()->writePath( filename, relativeBasePath ) + "\":" + r.cap( 2 );
630  handled = true;
631  }
632  }
633  else if ( src.contains( QRegExp( "^(NITF_IM|RADARSAT_2_CALIB):" ) ) )
634  {
635  // NITF_IM:0:filename
636  // RADARSAT_2_CALIB:?:filename
637  QRegExp r( "([^:]+):([^:]+):(.+)" );
638  if ( r.exactMatch( src ) )
639  {
640  src = r.cap( 1 ) + ':' + r.cap( 2 ) + ':' + QgsProject::instance()->writePath( r.cap( 3 ), relativeBasePath );
641  handled = true;
642  }
643  }
644  }
645  }
646 
647  if ( !handled )
648  src = QgsProject::instance()->writePath( src, relativeBasePath );
649  }
650 
651  QDomText dataSourceText = document.createTextNode( src );
652  dataSource.appendChild( dataSourceText );
653 
654  layerElement.appendChild( dataSource );
655 
656 
657  // layer name
658  QDomElement layerName = document.createElement( QStringLiteral( "layername" ) );
659  QDomText layerNameText = document.createTextNode( originalName() );
660  layerName.appendChild( layerNameText );
661  layerElement.appendChild( layerName );
662 
663  // layer short name
664  if ( !mShortName.isEmpty() )
665  {
666  QDomElement layerShortName = document.createElement( QStringLiteral( "shortname" ) );
667  QDomText layerShortNameText = document.createTextNode( mShortName );
668  layerShortName.appendChild( layerShortNameText );
669  layerElement.appendChild( layerShortName );
670  }
671 
672  // layer title
673  if ( !mTitle.isEmpty() )
674  {
675  QDomElement layerTitle = document.createElement( QStringLiteral( "title" ) );
676  QDomText layerTitleText = document.createTextNode( mTitle );
677  layerTitle.appendChild( layerTitleText );
678  layerElement.appendChild( layerTitle );
679  }
680 
681  // layer abstract
682  if ( !mAbstract.isEmpty() )
683  {
684  QDomElement layerAbstract = document.createElement( QStringLiteral( "abstract" ) );
685  QDomText layerAbstractText = document.createTextNode( mAbstract );
686  layerAbstract.appendChild( layerAbstractText );
687  layerElement.appendChild( layerAbstract );
688  }
689 
690  // layer keyword list
691  QStringList keywordStringList = keywordList().split( ',' );
692  if ( !keywordStringList.isEmpty() )
693  {
694  QDomElement layerKeywordList = document.createElement( QStringLiteral( "keywordList" ) );
695  for ( int i = 0; i < keywordStringList.size(); ++i )
696  {
697  QDomElement layerKeywordValue = document.createElement( QStringLiteral( "value" ) );
698  QDomText layerKeywordText = document.createTextNode( keywordStringList.at( i ).trimmed() );
699  layerKeywordValue.appendChild( layerKeywordText );
700  layerKeywordList.appendChild( layerKeywordValue );
701  }
702  layerElement.appendChild( layerKeywordList );
703  }
704 
705  // layer metadataUrl
706  QString aDataUrl = dataUrl();
707  if ( !aDataUrl.isEmpty() )
708  {
709  QDomElement layerDataUrl = document.createElement( QStringLiteral( "dataUrl" ) );
710  QDomText layerDataUrlText = document.createTextNode( aDataUrl );
711  layerDataUrl.appendChild( layerDataUrlText );
712  layerDataUrl.setAttribute( QStringLiteral( "format" ), dataUrlFormat() );
713  layerElement.appendChild( layerDataUrl );
714  }
715 
716  // layer legendUrl
717  QString aLegendUrl = legendUrl();
718  if ( !aLegendUrl.isEmpty() )
719  {
720  QDomElement layerLegendUrl = document.createElement( QStringLiteral( "legendUrl" ) );
721  QDomText layerLegendUrlText = document.createTextNode( aLegendUrl );
722  layerLegendUrl.appendChild( layerLegendUrlText );
723  layerLegendUrl.setAttribute( QStringLiteral( "format" ), legendUrlFormat() );
724  layerElement.appendChild( layerLegendUrl );
725  }
726 
727  // layer attribution
728  QString aAttribution = attribution();
729  if ( !aAttribution.isEmpty() )
730  {
731  QDomElement layerAttribution = document.createElement( QStringLiteral( "attribution" ) );
732  QDomText layerAttributionText = document.createTextNode( aAttribution );
733  layerAttribution.appendChild( layerAttributionText );
734  layerAttribution.setAttribute( QStringLiteral( "href" ), attributionUrl() );
735  layerElement.appendChild( layerAttribution );
736  }
737 
738  // layer metadataUrl
739  QString aMetadataUrl = metadataUrl();
740  if ( !aMetadataUrl.isEmpty() )
741  {
742  QDomElement layerMetadataUrl = document.createElement( QStringLiteral( "metadataUrl" ) );
743  QDomText layerMetadataUrlText = document.createTextNode( aMetadataUrl );
744  layerMetadataUrl.appendChild( layerMetadataUrlText );
745  layerMetadataUrl.setAttribute( QStringLiteral( "type" ), metadataUrlType() );
746  layerMetadataUrl.setAttribute( QStringLiteral( "format" ), metadataUrlFormat() );
747  layerElement.appendChild( layerMetadataUrl );
748  }
749 
750  // timestamp if supported
751  if ( timestamp() > QDateTime() )
752  {
753  QDomElement stamp = document.createElement( QStringLiteral( "timestamp" ) );
754  QDomText stampText = document.createTextNode( timestamp().toString( Qt::ISODate ) );
755  stamp.appendChild( stampText );
756  layerElement.appendChild( stamp );
757  }
758 
759  layerElement.appendChild( layerName );
760 
761  // zorder
762  // This is no longer stored in the project file. It is superfluous since the layers
763  // are written and read in the proper order.
764 
765  // spatial reference system id
766  QDomElement mySrsElement = document.createElement( QStringLiteral( "srs" ) );
767  mCRS.writeXml( mySrsElement, document );
768  layerElement.appendChild( mySrsElement );
769 
770 #if 0
771  // <transparencyLevelInt>
772  QDomElement transparencyLevelIntElement = document.createElement( "transparencyLevelInt" );
773  QDomText transparencyLevelIntText = document.createTextNode( QString::number( getTransparency() ) );
774  transparencyLevelIntElement.appendChild( transparencyLevelIntText );
775  maplayer.appendChild( transparencyLevelIntElement );
776 #endif
777 
778  // now append layer node to map layer node
779 
780  writeCustomProperties( layerElement, document );
781 
782  return writeXml( layerElement, document );
783 
784 } // bool QgsMapLayer::writeXml
785 
786 QDomDocument QgsMapLayer::asLayerDefinition( const QList<QgsMapLayer *>& layers, const QString& relativeBasePath )
787 {
788  QDomDocument doc( QStringLiteral( "qgis-layer-definition" ) );
789  QDomElement qgiselm = doc.createElement( QStringLiteral( "qlr" ) );
790  doc.appendChild( qgiselm );
791  QDomElement layerselm = doc.createElement( QStringLiteral( "maplayers" ) );
792  Q_FOREACH ( QgsMapLayer* layer, layers )
793  {
794  QDomElement layerelm = doc.createElement( QStringLiteral( "maplayer" ) );
795  layer->writeLayerXml( layerelm, doc, relativeBasePath );
796  layerselm.appendChild( layerelm );
797  }
798  qgiselm.appendChild( layerselm );
799  return doc;
800 }
801 
802 QList<QgsMapLayer*> QgsMapLayer::fromLayerDefinition( QDomDocument& document, bool addToRegistry, bool addToLegend )
803 {
804  QList<QgsMapLayer*> layers;
805  QDomNodeList layernodes = document.elementsByTagName( QStringLiteral( "maplayer" ) );
806  for ( int i = 0; i < layernodes.size(); ++i )
807  {
808  QDomNode layernode = layernodes.at( i );
809  QDomElement layerElem = layernode.toElement();
810 
811  QString type = layerElem.attribute( QStringLiteral( "type" ) );
812  QgsDebugMsg( type );
813  QgsMapLayer *layer = nullptr;
814 
815  if ( type == QLatin1String( "vector" ) )
816  {
817  layer = new QgsVectorLayer;
818  }
819  else if ( type == QLatin1String( "raster" ) )
820  {
821  layer = new QgsRasterLayer;
822  }
823  else if ( type == QLatin1String( "plugin" ) )
824  {
825  QString typeName = layerElem.attribute( QStringLiteral( "name" ) );
826  layer = QgsApplication::pluginLayerRegistry()->createLayer( typeName );
827  }
828 
829  if ( !layer )
830  continue;
831 
832  bool ok = layer->readLayerXml( layerElem );
833  if ( ok )
834  {
835  layers << layer;
836  if ( addToRegistry )
837  QgsProject::instance()->addMapLayer( layer, addToLegend );
838  }
839  }
840  return layers;
841 }
842 
843 QList<QgsMapLayer *> QgsMapLayer::fromLayerDefinitionFile( const QString &qlrfile )
844 {
845  QFile file( qlrfile );
846  if ( !file.open( QIODevice::ReadOnly ) )
847  {
848  QgsDebugMsg( "Can't open file" );
849  return QList<QgsMapLayer*>();
850  }
851 
852  QDomDocument doc;
853  if ( !doc.setContent( &file ) )
854  {
855  QgsDebugMsg( "Can't set content" );
856  return QList<QgsMapLayer*>();
857  }
858 
859  QFileInfo fileinfo( file );
860  QDir::setCurrent( fileinfo.absoluteDir().path() );
861  return QgsMapLayer::fromLayerDefinition( doc );
862 }
863 
864 
865 bool QgsMapLayer::writeXml( QDomNode & layer_node, QDomDocument & document ) const
866 {
867  Q_UNUSED( layer_node );
868  Q_UNUSED( document );
869  // NOP by default; children will over-ride with behavior specific to them
870 
871  return true;
872 } // void QgsMapLayer::writeXml
873 
874 
875 void QgsMapLayer::readCustomProperties( const QDomNode &layerNode, const QString &keyStartsWith )
876 {
877  mCustomProperties.readXml( layerNode, keyStartsWith );
878 }
879 
880 void QgsMapLayer::writeCustomProperties( QDomNode &layerNode, QDomDocument &doc ) const
881 {
882  mCustomProperties.writeXml( layerNode, doc );
883 }
884 
885 void QgsMapLayer::readStyleManager( const QDomNode& layerNode )
886 {
887  QDomElement styleMgrElem = layerNode.firstChildElement( QStringLiteral( "map-layer-style-manager" ) );
888  if ( !styleMgrElem.isNull() )
889  mStyleManager->readXml( styleMgrElem );
890  else
891  mStyleManager->reset();
892 }
893 
894 void QgsMapLayer::writeStyleManager( QDomNode& layerNode, QDomDocument& doc ) const
895 {
896  if ( mStyleManager )
897  {
898  QDomElement styleMgrElem = doc.createElement( QStringLiteral( "map-layer-style-manager" ) );
899  mStyleManager->writeXml( styleMgrElem );
900  layerNode.appendChild( styleMgrElem );
901  }
902 }
903 
905 {
906  return mValid;
907 }
908 
909 
911 {
912  QgsDebugMsg( "called" );
913  // TODO: emit a signal - it will be used to update legend
914 }
915 
916 #if 0
917 void QgsMapLayer::connectNotify( const char * signal )
918 {
919  Q_UNUSED( signal );
920  QgsDebugMsgLevel( "QgsMapLayer connected to " + QString( signal ), 3 );
921 } // QgsMapLayer::connectNotify
922 #endif
923 
924 bool QgsMapLayer::isInScaleRange( double scale ) const
925 {
926  return !mScaleBasedVisibility || ( mMinScale * Qgis::SCALE_PRECISION < scale && scale < mMaxScale );
927 }
928 
930 {
931  return mScaleBasedVisibility;
932 }
933 
934 void QgsMapLayer::setMinimumScale( double scale )
935 {
936  mMinScale = scale;
937 }
938 
940 {
941  return mMinScale;
942 }
943 
944 
945 void QgsMapLayer::setMaximumScale( double scale )
946 {
947  mMaxScale = scale;
948 }
949 
950 void QgsMapLayer::setScaleBasedVisibility( const bool enabled )
951 {
952  mScaleBasedVisibility = enabled;
953 }
954 
956 {
957  return mMaxScale;
958 }
959 
960 QStringList QgsMapLayer::subLayers() const
961 {
962  return QStringList(); // Empty
963 }
964 
965 void QgsMapLayer::setLayerOrder( const QStringList &layers )
966 {
967  Q_UNUSED( layers );
968  // NOOP
969 }
970 
971 void QgsMapLayer::setSubLayerVisibility( const QString& name, bool vis )
972 {
973  Q_UNUSED( name );
974  Q_UNUSED( vis );
975  // NOOP
976 }
977 
979 {
980  return mCRS;
981 }
982 
983 void QgsMapLayer::setCrs( const QgsCoordinateReferenceSystem& srs, bool emitSignal )
984 {
985  mCRS = srs;
986 
987  if ( !mCRS.isValid() )
988  {
989  mCRS.setValidationHint( tr( "Specify CRS for layer %1" ).arg( name() ) );
990  mCRS.validate();
991  }
992 
993  if ( emitSignal )
994  emit crsChanged();
995 }
996 
997 QString QgsMapLayer::capitalizeLayerName( const QString& name )
998 {
999  // Capitalize the first letter of the layer name if requested
1000  QSettings settings;
1001  bool capitalizeLayerName =
1002  settings.value( QStringLiteral( "/qgis/capitalizeLayerName" ), QVariant( false ) ).toBool();
1003 
1004  QString layerName( name );
1005 
1006  if ( capitalizeLayerName && !layerName.isEmpty() )
1007  layerName = layerName.at( 0 ).toUpper() + layerName.mid( 1 );
1008 
1009  return layerName;
1010 }
1011 
1012 QString QgsMapLayer::styleURI() const
1013 {
1014  QString myURI = publicSource();
1015 
1016  // if file is using the VSIFILE mechanism, remove the prefix
1017  if ( myURI.startsWith( QLatin1String( "/vsigzip/" ), Qt::CaseInsensitive ) )
1018  {
1019  myURI.remove( 0, 9 );
1020  }
1021  else if ( myURI.startsWith( QLatin1String( "/vsizip/" ), Qt::CaseInsensitive ) &&
1022  myURI.endsWith( QLatin1String( ".zip" ), Qt::CaseInsensitive ) )
1023  {
1024  // ideally we should look for .qml file inside zip file
1025  myURI.remove( 0, 8 );
1026  }
1027  else if ( myURI.startsWith( QLatin1String( "/vsitar/" ), Qt::CaseInsensitive ) &&
1028  ( myURI.endsWith( QLatin1String( ".tar" ), Qt::CaseInsensitive ) ||
1029  myURI.endsWith( QLatin1String( ".tar.gz" ), Qt::CaseInsensitive ) ||
1030  myURI.endsWith( QLatin1String( ".tgz" ), Qt::CaseInsensitive ) ) )
1031  {
1032  // ideally we should look for .qml file inside tar file
1033  myURI.remove( 0, 8 );
1034  }
1035 
1036  QFileInfo myFileInfo( myURI );
1037  QString key;
1038 
1039  if ( myFileInfo.exists() )
1040  {
1041  // if file is using the /vsizip/ or /vsigzip/ mechanism, cleanup the name
1042  if ( myURI.endsWith( QLatin1String( ".gz" ), Qt::CaseInsensitive ) )
1043  myURI.chop( 3 );
1044  else if ( myURI.endsWith( QLatin1String( ".zip" ), Qt::CaseInsensitive ) )
1045  myURI.chop( 4 );
1046  else if ( myURI.endsWith( QLatin1String( ".tar" ), Qt::CaseInsensitive ) )
1047  myURI.chop( 4 );
1048  else if ( myURI.endsWith( QLatin1String( ".tar.gz" ), Qt::CaseInsensitive ) )
1049  myURI.chop( 7 );
1050  else if ( myURI.endsWith( QLatin1String( ".tgz" ), Qt::CaseInsensitive ) )
1051  myURI.chop( 4 );
1052  myFileInfo.setFile( myURI );
1053  // get the file name for our .qml style file
1054  key = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".qml";
1055  }
1056  else
1057  {
1058  key = publicSource();
1059  }
1060 
1061  return key;
1062 }
1063 
1064 QString QgsMapLayer::loadDefaultStyle( bool & resultFlag )
1065 {
1066  return loadNamedStyle( styleURI(), resultFlag );
1067 }
1068 
1069 bool QgsMapLayer::loadNamedStyleFromDb( const QString &db, const QString &uri, QString &qml )
1070 {
1071  QgsDebugMsg( QString( "db = %1 uri = %2" ).arg( db, uri ) );
1072 
1073  bool theResultFlag = false;
1074 
1075  // read from database
1076  sqlite3 *myDatabase;
1077  sqlite3_stmt *myPreparedStatement;
1078  const char *myTail;
1079  int myResult;
1080 
1081  QgsDebugMsg( QString( "Trying to load style for \"%1\" from \"%2\"" ).arg( uri, db ) );
1082 
1083  if ( db.isEmpty() || !QFile( db ).exists() )
1084  return false;
1085 
1086  myResult = sqlite3_open_v2( db.toUtf8().data(), &myDatabase, SQLITE_OPEN_READONLY, nullptr );
1087  if ( myResult != SQLITE_OK )
1088  {
1089  return false;
1090  }
1091 
1092  QString mySql = QStringLiteral( "select qml from tbl_styles where style=?" );
1093  myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
1094  if ( myResult == SQLITE_OK )
1095  {
1096  QByteArray param = uri.toUtf8();
1097 
1098  if ( sqlite3_bind_text( myPreparedStatement, 1, param.data(), param.length(), SQLITE_STATIC ) == SQLITE_OK &&
1099  sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
1100  {
1101  qml = QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 0 ) ) );
1102  theResultFlag = true;
1103  }
1104 
1105  sqlite3_finalize( myPreparedStatement );
1106  }
1107 
1108  sqlite3_close( myDatabase );
1109 
1110  return theResultFlag;
1111 }
1112 
1113 
1114 QString QgsMapLayer::loadNamedStyle( const QString &uri, bool &resultFlag )
1115 {
1116  QgsDebugMsg( QString( "uri = %1 myURI = %2" ).arg( uri, publicSource() ) );
1117 
1118  resultFlag = false;
1119 
1120  QDomDocument myDocument( QStringLiteral( "qgis" ) );
1121 
1122  // location of problem associated with errorMsg
1123  int line, column;
1124  QString myErrorMessage;
1125 
1126  QFile myFile( uri );
1127  if ( myFile.open( QFile::ReadOnly ) )
1128  {
1129  // read file
1130  resultFlag = myDocument.setContent( &myFile, &myErrorMessage, &line, &column );
1131  if ( !resultFlag )
1132  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1133  myFile.close();
1134  }
1135  else
1136  {
1137  QFileInfo project( QgsProject::instance()->fileName() );
1138  QgsDebugMsg( QString( "project fileName: %1" ).arg( project.absoluteFilePath() ) );
1139 
1140  QString qml;
1141  if ( loadNamedStyleFromDb( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ), uri, qml ) ||
1142  ( project.exists() && loadNamedStyleFromDb( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), uri, qml ) ) ||
1143  loadNamedStyleFromDb( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( QStringLiteral( "resources/qgis.qmldb" ) ), uri, qml ) )
1144  {
1145  resultFlag = myDocument.setContent( qml, &myErrorMessage, &line, &column );
1146  if ( !resultFlag )
1147  {
1148  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1149  }
1150  }
1151  else
1152  {
1153  myErrorMessage = tr( "Style not found in database" );
1154  }
1155  }
1156 
1157  if ( !resultFlag )
1158  {
1159  return myErrorMessage;
1160  }
1161 
1162  resultFlag = importNamedStyle( myDocument, myErrorMessage );
1163  if ( !resultFlag )
1164  myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( uri, myErrorMessage );
1165 
1166  return myErrorMessage;
1167 }
1168 
1169 
1170 bool QgsMapLayer::importNamedStyle( QDomDocument& myDocument, QString& myErrorMessage )
1171 {
1172  QDomElement myRoot = myDocument.firstChildElement( QStringLiteral( "qgis" ) );
1173  if ( myRoot.isNull() )
1174  {
1175  myErrorMessage = tr( "Root <qgis> element could not be found" );
1176  return false;
1177  }
1178 
1179  // get style file version string, if any
1180  QgsProjectVersion fileVersion( myRoot.attribute( QStringLiteral( "version" ) ) );
1181  QgsProjectVersion thisVersion( Qgis::QGIS_VERSION );
1182 
1183  if ( thisVersion > fileVersion )
1184  {
1185  QgsProjectFileTransform styleFile( myDocument, fileVersion );
1186  styleFile.updateRevision( thisVersion );
1187  }
1188 
1189  //Test for matching geometry type on vector layers when applying, if geometry type is given in the style
1190  if ( type() == QgsMapLayer::VectorLayer && !myRoot.firstChildElement( QStringLiteral( "layerGeometryType" ) ).isNull() )
1191  {
1192  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer*>( this );
1193  QgsWkbTypes::GeometryType importLayerGeometryType = static_cast<QgsWkbTypes::GeometryType>( myRoot.firstChildElement( QStringLiteral( "layerGeometryType" ) ).text().toInt() );
1194  if ( vl->geometryType() != importLayerGeometryType )
1195  {
1196  myErrorMessage = tr( "Cannot apply style to layer with a different geometry type" );
1197  return false;
1198  }
1199  }
1200 
1201  // use scale dependent visibility flag
1202  setScaleBasedVisibility( myRoot.attribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ) ).toInt() == 1 );
1203  setMinimumScale( myRoot.attribute( QStringLiteral( "minimumScale" ) ).toDouble() );
1204  setMaximumScale( myRoot.attribute( QStringLiteral( "maximumScale" ) ).toDouble() );
1205 
1206 #if 0
1207  //read transparency level
1208  QDomNode transparencyNode = myRoot.namedItem( "transparencyLevelInt" );
1209  if ( ! transparencyNode.isNull() )
1210  {
1211  // set transparency level only if it's in project
1212  // (otherwise it sets the layer transparent)
1213  QDomElement myElement = transparencyNode.toElement();
1214  setTransparency( myElement.text().toInt() );
1215  }
1216 #endif
1217 
1218  return readSymbology( myRoot, myErrorMessage );
1219 }
1220 
1221 void QgsMapLayer::exportNamedStyle( QDomDocument &doc, QString &errorMsg ) const
1222 {
1223  QDomImplementation DomImplementation;
1224  QDomDocumentType documentType = DomImplementation.createDocumentType( QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
1225  QDomDocument myDocument( documentType );
1226 
1227  QDomElement myRootNode = myDocument.createElement( QStringLiteral( "qgis" ) );
1228  myRootNode.setAttribute( QStringLiteral( "version" ), Qgis::QGIS_VERSION );
1229  myDocument.appendChild( myRootNode );
1230 
1231  myRootNode.setAttribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ), hasScaleBasedVisibility() ? 1 : 0 );
1232  myRootNode.setAttribute( QStringLiteral( "minimumScale" ), QString::number( minimumScale() ) );
1233  myRootNode.setAttribute( QStringLiteral( "maximumScale" ), QString::number( maximumScale() ) );
1234 
1235 #if 0
1236  // <transparencyLevelInt>
1237  QDomElement transparencyLevelIntElement = myDocument.createElement( "transparencyLevelInt" );
1238  QDomText transparencyLevelIntText = myDocument.createTextNode( QString::number( getTransparency() ) );
1239  transparencyLevelIntElement.appendChild( transparencyLevelIntText );
1240  myRootNode.appendChild( transparencyLevelIntElement );
1241 #endif
1242 
1243  if ( !writeSymbology( myRootNode, myDocument, errorMsg ) )
1244  {
1245  errorMsg = QObject::tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1246  return;
1247  }
1248 
1249  /*
1250  * Check to see if the layer is vector - in which case we should also export its geometryType
1251  * to avoid eventually pasting to a layer with a different geometry
1252  */
1253  if ( type() == QgsMapLayer::VectorLayer )
1254  {
1255  //Getting the selectionLayer geometry
1256  const QgsVectorLayer *vl = qobject_cast<const QgsVectorLayer*>( this );
1257  QString geoType = QString::number( vl->geometryType() );
1258 
1259  //Adding geometryinformation
1260  QDomElement layerGeometryType = myDocument.createElement( QStringLiteral( "layerGeometryType" ) );
1261  QDomText type = myDocument.createTextNode( geoType );
1262 
1263  layerGeometryType.appendChild( type );
1264  myRootNode.appendChild( layerGeometryType );
1265  }
1266 
1267  doc = myDocument;
1268 }
1269 
1270 QString QgsMapLayer::saveDefaultStyle( bool & resultFlag )
1271 {
1272  return saveNamedStyle( styleURI(), resultFlag );
1273 }
1274 
1275 QString QgsMapLayer::saveNamedStyle( const QString &uri, bool &resultFlag )
1276 {
1277  QString myErrorMessage;
1278  QDomDocument myDocument;
1279  exportNamedStyle( myDocument, myErrorMessage );
1280 
1281  // check if the uri is a file or ends with .qml,
1282  // which indicates that it should become one
1283  // everything else goes to the database
1284  QString filename;
1285 
1286  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this );
1287  if ( vlayer && vlayer->providerType() == QLatin1String( "ogr" ) )
1288  {
1289  QStringList theURIParts = uri.split( '|' );
1290  filename = theURIParts[0];
1291  }
1292  else if ( vlayer && vlayer->providerType() == QLatin1String( "gpx" ) )
1293  {
1294  QStringList theURIParts = uri.split( '?' );
1295  filename = theURIParts[0];
1296  }
1297  else if ( vlayer && vlayer->providerType() == QLatin1String( "delimitedtext" ) )
1298  {
1299  filename = QUrl::fromEncoded( uri.toLatin1() ).toLocalFile();
1300  // toLocalFile() returns an empty string if theURI is a plain Windows-path, e.g. "C:/style.qml"
1301  if ( filename.isEmpty() )
1302  filename = uri;
1303  }
1304  else
1305  {
1306  filename = uri;
1307  }
1308 
1309  QFileInfo myFileInfo( filename );
1310  if ( myFileInfo.exists() || filename.endsWith( QLatin1String( ".qml" ), Qt::CaseInsensitive ) )
1311  {
1312  QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
1313  if ( !myDirInfo.isWritable() )
1314  {
1315  return tr( "The directory containing your dataset needs to be writable!" );
1316  }
1317 
1318  // now construct the file name for our .qml style file
1319  QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".qml";
1320 
1321  QFile myFile( myFileName );
1322  if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
1323  {
1324  QTextStream myFileStream( &myFile );
1325  // save as utf-8 with 2 spaces for indents
1326  myDocument.save( myFileStream, 2 );
1327  myFile.close();
1328  resultFlag = true;
1329  return tr( "Created default style file as %1" ).arg( myFileName );
1330  }
1331  else
1332  {
1333  resultFlag = false;
1334  return tr( "ERROR: Failed to created default style file as %1. Check file permissions and retry." ).arg( myFileName );
1335  }
1336  }
1337  else
1338  {
1339  QString qml = myDocument.toString();
1340 
1341  // read from database
1342  sqlite3 *myDatabase;
1343  sqlite3_stmt *myPreparedStatement;
1344  const char *myTail;
1345  int myResult;
1346 
1347  myResult = sqlite3_open( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ).toUtf8().data(), &myDatabase );
1348  if ( myResult != SQLITE_OK )
1349  {
1350  return tr( "User database could not be opened." );
1351  }
1352 
1353  QByteArray param0 = uri.toUtf8();
1354  QByteArray param1 = qml.toUtf8();
1355 
1356  QString mySql = QStringLiteral( "create table if not exists tbl_styles(style varchar primary key,qml varchar)" );
1357  myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
1358  if ( myResult == SQLITE_OK )
1359  {
1360  if ( sqlite3_step( myPreparedStatement ) != SQLITE_DONE )
1361  {
1362  sqlite3_finalize( myPreparedStatement );
1363  sqlite3_close( myDatabase );
1364  resultFlag = false;
1365  return tr( "The style table could not be created." );
1366  }
1367  }
1368 
1369  sqlite3_finalize( myPreparedStatement );
1370 
1371  mySql = QStringLiteral( "insert into tbl_styles(style,qml) values (?,?)" );
1372  myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
1373  if ( myResult == SQLITE_OK )
1374  {
1375  if ( sqlite3_bind_text( myPreparedStatement, 1, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
1376  sqlite3_bind_text( myPreparedStatement, 2, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
1377  sqlite3_step( myPreparedStatement ) == SQLITE_DONE )
1378  {
1379  resultFlag = true;
1380  myErrorMessage = tr( "The style %1 was saved to database" ).arg( uri );
1381  }
1382  }
1383 
1384  sqlite3_finalize( myPreparedStatement );
1385 
1386  if ( !resultFlag )
1387  {
1388  QString mySql = QStringLiteral( "update tbl_styles set qml=? where style=?" );
1389  myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
1390  if ( myResult == SQLITE_OK )
1391  {
1392  if ( sqlite3_bind_text( myPreparedStatement, 2, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
1393  sqlite3_bind_text( myPreparedStatement, 1, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
1394  sqlite3_step( myPreparedStatement ) == SQLITE_DONE )
1395  {
1396  resultFlag = true;
1397  myErrorMessage = tr( "The style %1 was updated in the database." ).arg( uri );
1398  }
1399  else
1400  {
1401  resultFlag = false;
1402  myErrorMessage = tr( "The style %1 could not be updated in the database." ).arg( uri );
1403  }
1404  }
1405  else
1406  {
1407  resultFlag = false;
1408  myErrorMessage = tr( "The style %1 could not be inserted into database." ).arg( uri );
1409  }
1410 
1411  sqlite3_finalize( myPreparedStatement );
1412  }
1413 
1414  sqlite3_close( myDatabase );
1415  }
1416 
1417  return myErrorMessage;
1418 }
1419 
1420 void QgsMapLayer::exportSldStyle( QDomDocument &doc, QString &errorMsg ) const
1421 {
1422  QDomDocument myDocument = QDomDocument();
1423 
1424  QDomNode header = myDocument.createProcessingInstruction( QStringLiteral( "xml" ), QStringLiteral( "version=\"1.0\" encoding=\"UTF-8\"" ) );
1425  myDocument.appendChild( header );
1426 
1427  // Create the root element
1428  QDomElement root = myDocument.createElementNS( QStringLiteral( "http://www.opengis.net/sld" ), QStringLiteral( "StyledLayerDescriptor" ) );
1429  root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.1.0" ) );
1430  root.setAttribute( QStringLiteral( "xsi:schemaLocation" ), QStringLiteral( "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" ) );
1431  root.setAttribute( QStringLiteral( "xmlns:ogc" ), QStringLiteral( "http://www.opengis.net/ogc" ) );
1432  root.setAttribute( QStringLiteral( "xmlns:se" ), QStringLiteral( "http://www.opengis.net/se" ) );
1433  root.setAttribute( QStringLiteral( "xmlns:xlink" ), QStringLiteral( "http://www.w3.org/1999/xlink" ) );
1434  root.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) );
1435  myDocument.appendChild( root );
1436 
1437  // Create the NamedLayer element
1438  QDomElement namedLayerNode = myDocument.createElement( QStringLiteral( "NamedLayer" ) );
1439  root.appendChild( namedLayerNode );
1440 
1441  const QgsVectorLayer *vlayer = qobject_cast<const QgsVectorLayer *>( this );
1442  if ( !vlayer )
1443  {
1444  errorMsg = tr( "Could not save symbology because:\n%1" )
1445  .arg( QStringLiteral( "Non-vector layers not supported yet" ) );
1446  return;
1447  }
1448 
1449  QgsStringMap props;
1450  if ( hasScaleBasedVisibility() )
1451  {
1452  props[ QStringLiteral( "scaleMinDenom" )] = QString::number( mMinScale );
1453  props[ QStringLiteral( "scaleMaxDenom" )] = QString::number( mMaxScale );
1454  }
1455  if ( !vlayer->writeSld( namedLayerNode, myDocument, errorMsg, props ) )
1456  {
1457  errorMsg = tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1458  return;
1459  }
1460 
1461  doc = myDocument;
1462 }
1463 
1464 QString QgsMapLayer::saveSldStyle( const QString &uri, bool &resultFlag ) const
1465 {
1466  QString errorMsg;
1467  QDomDocument myDocument;
1468  exportSldStyle( myDocument, errorMsg );
1469  if ( !errorMsg.isNull() )
1470  {
1471  resultFlag = false;
1472  return errorMsg;
1473  }
1474  const QgsVectorLayer *vlayer = qobject_cast<const QgsVectorLayer *>( this );
1475 
1476  // check if the uri is a file or ends with .sld,
1477  // which indicates that it should become one
1478  QString filename;
1479  if ( vlayer->providerType() == QLatin1String( "ogr" ) )
1480  {
1481  QStringList theURIParts = uri.split( '|' );
1482  filename = theURIParts[0];
1483  }
1484  else if ( vlayer->providerType() == QLatin1String( "gpx" ) )
1485  {
1486  QStringList theURIParts = uri.split( '?' );
1487  filename = theURIParts[0];
1488  }
1489  else if ( vlayer->providerType() == QLatin1String( "delimitedtext" ) )
1490  {
1491  filename = QUrl::fromEncoded( uri.toLatin1() ).toLocalFile();
1492  // toLocalFile() returns an empty string if theURI is a plain Windows-path, e.g. "C:/style.qml"
1493  if ( filename.isEmpty() )
1494  filename = uri;
1495  }
1496  else
1497  {
1498  filename = uri;
1499  }
1500 
1501  QFileInfo myFileInfo( filename );
1502  if ( myFileInfo.exists() || filename.endsWith( QLatin1String( ".sld" ), Qt::CaseInsensitive ) )
1503  {
1504  QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
1505  if ( !myDirInfo.isWritable() )
1506  {
1507  return tr( "The directory containing your dataset needs to be writable!" );
1508  }
1509 
1510  // now construct the file name for our .sld style file
1511  QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".sld";
1512 
1513  QFile myFile( myFileName );
1514  if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
1515  {
1516  QTextStream myFileStream( &myFile );
1517  // save as utf-8 with 2 spaces for indents
1518  myDocument.save( myFileStream, 2 );
1519  myFile.close();
1520  resultFlag = true;
1521  return tr( "Created default style file as %1" ).arg( myFileName );
1522  }
1523  }
1524 
1525  resultFlag = false;
1526  return tr( "ERROR: Failed to created SLD style file as %1. Check file permissions and retry." ).arg( filename );
1527 }
1528 
1529 QString QgsMapLayer::loadSldStyle( const QString &uri, bool &resultFlag )
1530 {
1531  QgsDebugMsg( "Entered." );
1532 
1533  resultFlag = false;
1534 
1535  QDomDocument myDocument;
1536 
1537  // location of problem associated with errorMsg
1538  int line, column;
1539  QString myErrorMessage;
1540 
1541  QFile myFile( uri );
1542  if ( myFile.open( QFile::ReadOnly ) )
1543  {
1544  // read file
1545  resultFlag = myDocument.setContent( &myFile, true, &myErrorMessage, &line, &column );
1546  if ( !resultFlag )
1547  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1548  myFile.close();
1549  }
1550  else
1551  {
1552  myErrorMessage = tr( "Unable to open file %1" ).arg( uri );
1553  }
1554 
1555  if ( !resultFlag )
1556  {
1557  return myErrorMessage;
1558  }
1559 
1560  // check for root SLD element
1561  QDomElement myRoot = myDocument.firstChildElement( QStringLiteral( "StyledLayerDescriptor" ) );
1562  if ( myRoot.isNull() )
1563  {
1564  myErrorMessage = QStringLiteral( "Error: StyledLayerDescriptor element not found in %1" ).arg( uri );
1565  resultFlag = false;
1566  return myErrorMessage;
1567  }
1568 
1569  // now get the style node out and pass it over to the layer
1570  // to deserialise...
1571  QDomElement namedLayerElem = myRoot.firstChildElement( QStringLiteral( "NamedLayer" ) );
1572  if ( namedLayerElem.isNull() )
1573  {
1574  myErrorMessage = QStringLiteral( "Info: NamedLayer element not found." );
1575  resultFlag = false;
1576  return myErrorMessage;
1577  }
1578 
1579  QString errorMsg;
1580  resultFlag = readSld( namedLayerElem, errorMsg );
1581  if ( !resultFlag )
1582  {
1583  myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( uri, errorMsg );
1584  return myErrorMessage;
1585  }
1586 
1587  return QLatin1String( "" );
1588 }
1589 
1590 bool QgsMapLayer::readStyle( const QDomNode& node, QString& errorMessage )
1591 {
1592  Q_UNUSED( node );
1593  Q_UNUSED( errorMessage );
1594  return false;
1595 }
1596 
1597 bool QgsMapLayer::writeStyle( QDomNode& node, QDomDocument& doc, QString& errorMessage ) const
1598 {
1599  Q_UNUSED( node );
1600  Q_UNUSED( doc );
1601  Q_UNUSED( errorMessage );
1602  return false;
1603 }
1604 
1605 
1607 {
1608  return &mUndoStack;
1609 }
1610 
1612 {
1613  return &mUndoStackStyles;
1614 }
1615 
1616 
1617 void QgsMapLayer::setCustomProperty( const QString& key, const QVariant& value )
1618 {
1619  mCustomProperties.setValue( key, value );
1620 }
1621 
1622 QVariant QgsMapLayer::customProperty( const QString& value, const QVariant& defaultValue ) const
1623 {
1624  return mCustomProperties.value( value, defaultValue );
1625 }
1626 
1627 void QgsMapLayer::removeCustomProperty( const QString& key )
1628 {
1629  mCustomProperties.remove( key );
1630 }
1631 
1632 
1633 
1635 {
1636  return false;
1637 }
1638 
1639 void QgsMapLayer::setValid( bool valid )
1640 {
1641  mValid = valid;
1642 }
1643 
1645 {
1646  if ( legend == mLegend )
1647  return;
1648 
1649  delete mLegend;
1650  mLegend = legend;
1651 
1652  if ( mLegend )
1653  connect( mLegend, &QgsMapLayerLegend::itemsChanged, this, &QgsMapLayer::legendChanged );
1654 
1655  emit legendChanged();
1656 }
1657 
1659 {
1660  return mLegend;
1661 }
1662 
1664 {
1665  return mStyleManager;
1666 }
1667 
1669 {
1670  emit repaintRequested();
1671 }
1672 
1673 QString QgsMapLayer::metadata() const
1674 {
1675  return QString();
1676 }
1677 
1679 {
1680  emit styleChanged();
1681 }
1682 
1684 {
1685  mExtent = r;
1686 }
1687 
1688 static QList<const QgsMapLayer*> _depOutEdges( const QgsMapLayer* vl, const QgsMapLayer* that, const QSet<QgsMapLayerDependency>& layers )
1689 {
1690  QList<const QgsMapLayer*> lst;
1691  if ( vl == that )
1692  {
1693  Q_FOREACH ( const QgsMapLayerDependency& dep, layers )
1694  {
1695  if ( const QgsMapLayer* l = QgsProject::instance()->mapLayer( dep.layerId() ) )
1696  lst << l;
1697  }
1698  }
1699  else
1700  {
1701  Q_FOREACH ( const QgsMapLayerDependency& dep, vl->dependencies() )
1702  {
1703  if ( const QgsMapLayer* l = QgsProject::instance()->mapLayer( dep.layerId() ) )
1704  lst << l;
1705  }
1706  }
1707  return lst;
1708 }
1709 
1710 static bool _depHasCycleDFS( const QgsMapLayer* n, QHash<const QgsMapLayer*, int>& mark, const QgsMapLayer* that, const QSet<QgsMapLayerDependency>& layers )
1711 {
1712  if ( mark.value( n ) == 1 ) // temporary
1713  return true;
1714  if ( mark.value( n ) == 0 ) // not visited
1715  {
1716  mark[n] = 1; // temporary
1717  Q_FOREACH ( const QgsMapLayer* m, _depOutEdges( n, that, layers ) )
1718  {
1719  if ( _depHasCycleDFS( m, mark, that, layers ) )
1720  return true;
1721  }
1722  mark[n] = 2; // permanent
1723  }
1724  return false;
1725 }
1726 
1727 bool QgsMapLayer::hasDependencyCycle( const QSet<QgsMapLayerDependency>& layers ) const
1728 {
1729  QHash<const QgsMapLayer*, int> marks;
1730  return _depHasCycleDFS( this, marks, this, layers );
1731 }
1732 
1733 QSet<QgsMapLayerDependency> QgsMapLayer::dependencies() const
1734 {
1735  return mDependencies;
1736 }
1737 
1738 bool QgsMapLayer::setDependencies( const QSet<QgsMapLayerDependency>& oDeps )
1739 {
1740  QSet<QgsMapLayerDependency> deps;
1741  Q_FOREACH ( const QgsMapLayerDependency& dep, oDeps )
1742  {
1743  if ( dep.origin() == QgsMapLayerDependency::FromUser )
1744  deps << dep;
1745  }
1746  if ( hasDependencyCycle( deps ) )
1747  return false;
1748 
1749  mDependencies = deps;
1750  emit dependenciesChanged();
1751  return true;
1752 }
QString attributionUrl() const
Returns the attribution URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:228
Origin origin() const
Return the dependency origin.
QString mShortName
Definition: qgsmaplayer.h:838
virtual QStringList subLayers() const
Returns the sublayers of this layer.
QgsMapLayer * addMapLayer(QgsMapLayer *theMapLayer, bool addToLegend=true, bool takeOwnership=true)
Add a layer to the map of loaded layers.
QString dataUrlFormat() const
Returns the DataUrl format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:194
A rectangle specified with double values.
Definition: qgsrectangle.h:36
Base class for all map layer types.
Definition: qgsmaplayer.h:50
static const QString QGIS_VERSION
Version string.
Definition: qgis.h:47
void currentStyleChanged(const QString &currentName)
Emitted when the current style has been changed.
virtual void exportSldStyle(QDomDocument &doc, QString &errorMsg) const
Export the properties of this layer as SLD style in a QDomDocument.
void dependenciesChanged()
Emitted when dependencies are changed.
virtual QString loadSldStyle(const QString &uri, bool &resultFlag)
Attempts to style the layer using the formatting from an SLD type file.
QString mAttributionUrl
Definition: qgsmaplayer.h:851
static QgsAuthManager * instance()
Enforce singleton pattern.
QString mKeywordList
Definition: qgsmaplayer.h:843
void readCustomProperties(const QDomNode &layerNode, const QString &keyStartsWith="")
Read custom properties from project file.
static QString qgisSettingsDirPath()
Returns the path to the settings directory in user&#39;s home dir.
virtual QSet< QgsMapLayerDependency > dependencies() const
Gets the list of dependencies.
QgsMapLayer * mapLayer(const QString &theLayerId) const
Retrieve a pointer to a registered layer by layer ID.
void readXml(const QDomNode &parentNode, const QString &keyStartsWith=QString())
Read store contents from XML.
void reset()
Reset the style manager to a basic state - with one default style which is set as current...
QgsMapLayerLegend * legend() const
Can be null.
virtual ~QgsMapLayer()
Definition: qgsmaplayer.cpp:90
QString mDataUrlFormat
Definition: qgsmaplayer.h:847
bool readLayerXml(const QDomElement &layerElement)
Sets state from Dom document.
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
void validate()
Perform some validation on this CRS.
QString dataUrl() const
Returns the DataUrl of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:178
static QList< const QgsMapLayer * > _depOutEdges(const QgsMapLayer *vl, const QgsMapLayer *that, const QSet< QgsMapLayerDependency > &layers)
bool updateRevision(const QgsProjectVersion &version)
void emitStyleChanged()
Triggers an emission of the styleChanged() signal.
virtual bool readSymbology(const QDomNode &node, QString &errorMessage)=0
Read the symbology for the current layer from the Dom node supplied.
virtual QString loadNamedStyle(const QString &uri, bool &resultFlag)
Retrieve a named style for this layer if one exists (either as a .qml file on disk or as a record in ...
QString mLegendUrlFormat
Definition: qgsmaplayer.h:860
void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for layer.
static void setCustomCrsValidation(CUSTOM_CRS_VALIDATION f)
Sets custom function to force valid CRS QGIS uses implementation in QgisGui::customSrsValidation.
QString writePath(const QString &filename, const QString &relativeBasePath=QString::null) const
Prepare a filename to save it to the project file.
virtual QString saveSldStyle(const QString &uri, bool &resultFlag) const
Saves the properties of this layer to an SLD format file.
static QDomElement writeRectangle(const QgsRectangle &rect, QDomDocument &doc)
Definition: qgsxmlutils.cpp:78
void crsChanged()
Emit a signal that layer&#39;s CRS has been reset.
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
bool isInScaleRange(double scale) const
Tests whether the layer should be visible at the specified scale.
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.
static QgsPluginLayerRegistry * pluginLayerRegistry()
Returns the application&#39;s plugin layer registry, used for managing plugin layer types.
static QString capitalizeLayerName(const QString &name)
A convenience function to (un)capitalize the layer name.
virtual QString styleURI() const
Retrieve the style URI for this layer (either as a .qml file on disk or as a record in the users styl...
void writeXml(QDomNode &parentNode, QDomDocument &doc) const
Write store contents to XML.
virtual QDateTime timestamp() const
Time stamp of data source in the moment when data/metadata were loaded by provider.
Definition: qgsmaplayer.h:696
bool writeXml(QDomNode &theNode, QDomDocument &theDoc) const
Stores state to the given Dom node in the given document.
bool isValid() const
Return the status of the layer.
void setBlendMode(QPainter::CompositionMode blendMode)
Set the blending mode used for rendering a layer.
void setConnection(const QString &aHost, const QString &aPort, const QString &aDatabase, const QString &aUsername, const QString &aPassword, SslMode sslmode=SslPrefer, const QString &authConfigId=QString())
Set all connection related members at once.
QgsMapLayer::LayerType type() const
Returns the type of the layer.
Definition: qgsmaplayer.cpp:96
static bool _depHasCycleDFS(const QgsMapLayer *n, QHash< const QgsMapLayer *, int > &mark, const QgsMapLayer *that, const QSet< QgsMapLayerDependency > &layers)
QMap< QString, QString > QgsStringMap
Definition: qgis.h:325
void remove(const QString &key)
Remove a key (entry) from the store.
QString mLayerName
Name of the layer - used for display.
Definition: qgsmaplayer.h:832
QString username() const
Returns the username.
void styleChanged()
Signal emitted whenever a change affects the layer&#39;s style.
virtual bool writeSymbology(QDomNode &node, QDomDocument &doc, QString &errorMessage) const =0
Write the symbology for the layer into the docment provided.
virtual QgsRectangle extent() const
Returns the extent of the layer.
void writeCustomProperties(QDomNode &layerNode, QDomDocument &doc) const
Write custom properties to project file.
void setMaximumScale(double scale)
Sets the maximum scale denominator at which the layer will be visible.
QgsMapLayerStyleManager * styleManager() const
Get access to the layer&#39;s style manager.
QgsRectangle mExtent
Extent of the layer.
Definition: qgsmaplayer.h:823
QString mMetadataUrl
MetadataUrl of the layer.
Definition: qgsmaplayer.h:854
QString host() const
Returns the host.
QString metadataUrlFormat() const
Returns the metadata format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:278
void setValidationHint(const QString &html)
Set user hint for validation.
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.
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
void readStyleManager(const QDomNode &layerNode)
Read style manager&#39;s configuration (if any). To be called by subclasses.
virtual bool writeXml(QDomNode &layer_node, QDomDocument &document) const
Called by writeLayerXML(), used by children to write state specific to them to project files...
QString originalName() const
Returns the original name of the layer.
Definition: qgsmaplayer.h:104
virtual void setSubLayerVisibility(const QString &name, bool visible)
Set the visibility of the given sublayer name.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:37
LayerType
Types of layers that can be added to a map.
Definition: qgsmaplayer.h:59
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer&#39;s spatial reference system.
QSet< QgsMapLayerDependency > mDependencies
List of layers that may modify this layer on modification.
Definition: qgsmaplayer.h:866
void nameChanged()
Emitted when the name has been changed.
A class to describe the version of a project.
QString providerType() const
[ data provider interface ] Which provider is being used for this Raster Layer?
static QList< QgsMapLayer * > fromLayerDefinition(QDomDocument &document, bool addToRegistry=false, bool addToLegend=false)
Creates a new layer from a layer defininition document.
virtual void setExtent(const QgsRectangle &rect)
Set the extent.
void readXml(const QDomElement &mgrElement)
Read configuration (for project loading)
QString keywordList() const
Returns the keyword list of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:160
bool writeSld(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsStringMap &props=QgsStringMap()) const
Writes the symbology of the layer into the document provided in SLD 1.1 format.
virtual QString dataSourceUri(bool expandAuthConfig=false) const
Get the data source specification.
QString mDataUrl
DataUrl of the layer.
Definition: qgsmaplayer.h:846
void triggerRepaint()
Will advice the map canvas (and any other interested party) that this layer requires to be repainted...
The QgsMapLayerLegend class is abstract interface for implementations of legends for one map layer...
virtual bool isEditable() const
Returns true if the layer can be edited.
QString legendUrl() const
Definition: qgsmaplayer.h:591
QgsCoordinateReferenceSystem crs() const
Returns the layer&#39;s spatial reference system.
QString publicSource() const
Gets a version of the internal layer definition that has sensitive bits removed (for example...
void setParam(const QString &key, const QString &value)
Set generic param (generic mode)
void removeCustomProperty(const QString &key)
Remove a custom property from layer.
virtual bool importNamedStyle(QDomDocument &doc, QString &errorMsg)
Import the properties of this layer from a QDomDocument.
virtual bool readStyle(const QDomNode &node, QString &errorMessage)
Read the style for the current layer from the Dom node supplied.
double minimumScale() const
Returns the minimum scale denominator at which the layer is visible.
double maximumScale() const
Returns the maximum scale denominator at which the layer is visible.
bool mValid
Indicates if the layer is valid and can be drawn.
Definition: qgsmaplayer.h:826
static QList< QgsMapLayer * > fromLayerDefinitionFile(const QString &qlrfile)
QString port() const
Returns the port.
void setName(const QString &name)
Set the display name of the layer.
QString mTitle
Definition: qgsmaplayer.h:839
virtual bool writeStyle(QDomNode &node, QDomDocument &doc, QString &errorMessage) const
Write just the style information for the layer into the document.
virtual bool readSld(const QDomNode &node, QString &errorMessage)
Definition: qgsmaplayer.h:542
QString legendUrlFormat() const
Definition: qgsmaplayer.h:593
QString mMetadataUrlFormat
Definition: qgsmaplayer.h:856
bool hasDependencyCycle(const QSet< QgsMapLayerDependency > &layers) const
Checks whether a new set of dependencies will introduce a cycle.
static QString pkgDataPath()
Returns the common root path of all application data directories.
struct sqlite3 sqlite3
static CUSTOM_CRS_VALIDATION customCrsValidation()
Gets custom function.
QString uri(bool expandAuthConfig=true) const
return complete uri
QString mAttribution
Attribution of the layer.
Definition: qgsmaplayer.h:850
QString mAbstract
Description of the layer.
Definition: qgsmaplayer.h:842
void writeStyleManager(QDomNode &layerNode, QDomDocument &doc) const
Write style manager&#39;s configuration (if exists). To be called by subclasses.
void blendModeChanged(QPainter::CompositionMode blendMode)
Signal emitted when the blend mode is changed, through QgsMapLayer::setBlendMode() ...
QgsMapLayer(QgsMapLayer::LayerType type=VectorLayer, const QString &name=QString::null, const QString &source=QString::null)
Constructor for QgsMapLayer.
Definition: qgsmaplayer.cpp:53
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:131
virtual QString loadDefaultStyle(bool &resultFlag)
Retrieve the default style for this layer if one exists (either as a .qml file on disk or as a record...
virtual QString saveDefaultStyle(bool &resultFlag)
Save the properties of this layer as the default style (either as a .qml file on disk or as a record ...
void itemsChanged()
Emitted when existing items/nodes got invalid and should be replaced by new ones. ...
QString name() const
Returns the display name of the layer.
QString mDataSource
Data source description string, varies by layer type.
Definition: qgsmaplayer.h:829
QString source() const
Returns the source for the layer.
bool hasScaleBasedVisibility() const
Returns whether scale based visibility is enabled for the layer.
bool setMasterPassword(bool verify=false)
Main call to initially set or continually check master password is set.
virtual void invalidTransformInput()
Event handler for when a coordinate transform fails due to bad vertex error.
void setMinimumScale(double scale)
Sets the minimum scale denominator at which the layer will be visible.
QByteArray encodedUri() const
return complete encoded uri (generic mode)
void repaintRequested()
By emitting this signal the layer tells that either appearance or content have been changed and any v...
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:350
virtual bool readXml(const QDomNode &layer_node)
Called by readLayerXML(), used by children to read state specific to them from project files...
QString mLegendUrl
WMS legend.
Definition: qgsmaplayer.h:859
This class represents a coordinate reference system (CRS).
QString layerId() const
Return the ID of the layer this dependency depends on.
bool isNull() const
test if the rectangle is null (all coordinates zero or after call to setMinimal()).
static QDomDocument asLayerDefinition(const QList< QgsMapLayer *> &layers, const QString &relativeBasePath=QString::null)
Returns the given layer as a layer definition document Layer definitions store the data source as wel...
void legendChanged()
Signal emitted when legend of the layer has changed.
QString readPath(QString filename) const
Turn filename read from the project file to an absolute path.
bool writeLayerXml(QDomElement &layerElement, QDomDocument &document, const QString &relativeBasePath=QString::null) const
Stores state in Dom node.
virtual QString saveNamedStyle(const QString &uri, bool &resultFlag)
Save the properties of this layer as a named style (either as a .qml file on disk or as a record in t...
QString metadataUrl() const
Returns the metadata URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:246
QUndoStack * undoStackStyles()
Return pointer to layer&#39;s style undo stack.
QString password() const
Returns the password.
virtual bool loadNamedStyleFromDb(const QString &db, const QString &uri, QString &qml)
Retrieve a named style for this layer from a sqlite database.
QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
QUndoStack * undoStack()
Return pointer to layer&#39;s undo stack.
void(* CUSTOM_CRS_VALIDATION)(QgsCoordinateReferenceSystem &)
QgsVectorDataProvider * dataProvider()
Returns the data provider.
QString providerType() const
Return the provider type for this layer.
virtual QString metadata() const
Obtain Metadata for this layer.
void setLegend(QgsMapLayerLegend *legend)
Assign a legend controller to the map layer.
Class for storing the component parts of a PostgreSQL/RDBMS datasource URI.
This class models dependencies with or between map layers.
Management of styles for use with one map 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.
void writeXml(QDomElement &mgrElement) const
Write configuration (for project saving)
QString mLayerOrigName
Original name of the layer.
Definition: qgsmaplayer.h:836
void setValid(bool valid)
Set whether layer is valid or not - should be used in constructor.
static QgsRectangle readRectangle(const QDomElement &element)
Definition: qgsxmlutils.cpp:36
bool readXml(const QDomNode &theNode)
Restores state from the given DOM node.
QString mMetadataUrlType
Definition: qgsmaplayer.h:855
QString database() const
Returns the database.
QgsPluginLayer * createLayer(const QString &typeName, const QString &uri=QString())
Return new layer if corresponding plugin has been found, else return NULL.
void setDatabase(const QString &database)
Set database.
static const double SCALE_PRECISION
Fudge factor used to compare two scales.
Definition: qgis.h:115
QString attribution() const
Returns the attribution of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:212
QString metadataUrlType() const
Returns the metadata type of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:262
void setScaleBasedVisibility(const bool enabled)
Sets whether scale based visibility is enabled for the layer.
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
static QString removePassword(const QString &aUri)
Removes password element from uris.
virtual bool setDependencies(const QSet< QgsMapLayerDependency > &layers)
Sets the list of dependencies.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
virtual void exportNamedStyle(QDomDocument &doc, QString &errorMsg) const
Export the properties of this layer as named style in a QDomDocument.