QGIS API Documentation  3.0.2-Girona (307d082)
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 <QDir>
20 #include <QDomDocument>
21 #include <QDomElement>
22 #include <QDomImplementation>
23 #include <QDomNode>
24 #include <QFile>
25 #include <QFileInfo>
26 #include <QTextStream>
27 #include <QUrl>
28 
29 #include <sqlite3.h>
30 
31 #include "qgssqliteutils.h"
32 
33 #include "qgssqliteutils.h"
34 #include "qgs3drendererregistry.h"
35 #include "qgsabstract3drenderer.h"
36 #include "qgsapplication.h"
38 #include "qgsdatasourceuri.h"
39 #include "qgslogger.h"
40 #include "qgsauthmanager.h"
41 #include "qgsmaplayer.h"
42 #include "qgsmaplayerlegend.h"
44 #include "qgspathresolver.h"
46 #include "qgsproject.h"
47 #include "qgsproviderregistry.h"
48 #include "qgsrasterlayer.h"
49 #include "qgsreadwritecontext.h"
50 #include "qgsrectangle.h"
51 #include "qgsvectorlayer.h"
52 #include "qgsvectordataprovider.h"
53 #include "qgsxmlutils.h"
54 #include "qgsstringutils.h"
55 
57 {
58  switch ( type )
59  {
60  case Metadata:
61  return QStringLiteral( ".qmd" );
62 
63  case Style:
64  return QStringLiteral( ".qml" );
65  }
66  return QString();
67 }
68 
70  const QString &lyrname,
71  const QString &source )
72  : mDataSource( source )
73  , mLayerName( lyrname )
74  , mLayerType( type )
75  , mUndoStack( new QUndoStack( this ) )
76  , mUndoStackStyles( new QUndoStack( this ) )
77  , mStyleManager( new QgsMapLayerStyleManager( this ) )
78  , mRefreshTimer( new QTimer( this ) )
79 {
80  //mShortName.replace( QRegExp( "[\\W]" ), "_" );
81 
82  // Generate the unique ID of this layer
83  QString uuid = QUuid::createUuid().toString();
84  // trim { } from uuid
85  mID = lyrname + '_' + uuid.mid( 1, uuid.length() - 2 );
86 
87  // Tidy the ID up to avoid characters that may cause problems
88  // elsewhere (e.g in some parts of XML). Replaces every non-word
89  // character (word characters are the alphabet, numbers and
90  // underscore) with an underscore.
91  // Note that the first backslashe in the regular expression is
92  // there for the compiler, so the pattern is actually \W
93  mID.replace( QRegExp( "[\\W]" ), QStringLiteral( "_" ) );
94 
96  connect( mRefreshTimer, &QTimer::timeout, this, [ = ] { triggerRepaint( true ); } );
97 }
98 
100 {
101  delete m3DRenderer;
102  delete mLegend;
103  delete mStyleManager;
104 }
105 
106 void QgsMapLayer::clone( QgsMapLayer *layer ) const
107 {
108  layer->setBlendMode( blendMode() );
109 
110  Q_FOREACH ( const QString &s, styleManager()->styles() )
111  {
112  layer->styleManager()->addStyle( s, styleManager()->style( s ) );
113  }
114 
115  layer->setName( name() );
116  layer->setShortName( shortName() );
117  layer->setExtent( extent() );
118  layer->setMaximumScale( maximumScale() );
119  layer->setMinimumScale( minimumScale() );
121  layer->setTitle( title() );
122  layer->setAbstract( abstract() );
123  layer->setKeywordList( keywordList() );
124  layer->setDataUrl( dataUrl() );
125  layer->setDataUrlFormat( dataUrlFormat() );
126  layer->setAttribution( attribution() );
127  layer->setAttributionUrl( attributionUrl() );
128  layer->setMetadataUrl( metadataUrl() );
131  layer->setLegendUrl( legendUrl() );
133  layer->setDependencies( dependencies() );
134  layer->setCrs( crs() );
135  layer->setCustomProperties( mCustomProperties );
136 }
137 
139 {
140  return mLayerType;
141 }
142 
143 QString QgsMapLayer::id() const
144 {
145  return mID;
146 }
147 
148 void QgsMapLayer::setName( const QString &name )
149 {
150  if ( name == mLayerName )
151  return;
152 
153  mLayerName = name;
154 
155  emit nameChanged();
156 }
157 
158 QString QgsMapLayer::name() const
159 {
160  QgsDebugMsgLevel( "returning name '" + mLayerName + '\'', 4 );
161  return mLayerName;
162 }
163 
165 {
166  return nullptr;
167 }
168 
170 {
171  return nullptr;
172 }
173 
175 {
176  // Redo this every time we're asked for it, as we don't know if
177  // dataSource has changed.
178  QString safeName = QgsDataSourceUri::removePassword( mDataSource );
179  return safeName;
180 }
181 
182 QString QgsMapLayer::source() const
183 {
184  return mDataSource;
185 }
186 
188 {
189  return mExtent;
190 }
191 
192 void QgsMapLayer::setBlendMode( QPainter::CompositionMode blendMode )
193 {
194  mBlendMode = blendMode;
195  emit blendModeChanged( blendMode );
196  emit styleChanged();
197 }
198 
199 QPainter::CompositionMode QgsMapLayer::blendMode() const
200 {
201  return mBlendMode;
202 }
203 
204 
205 bool QgsMapLayer::readLayerXml( const QDomElement &layerElement, const QgsReadWriteContext &context )
206 {
207  bool layerError;
208 
209  QDomNode mnl;
210  QDomElement mne;
211 
212  // read provider
213  QString provider;
214  mnl = layerElement.namedItem( QStringLiteral( "provider" ) );
215  mne = mnl.toElement();
216  provider = mne.text();
217 
218  // set data source
219  mnl = layerElement.namedItem( QStringLiteral( "datasource" ) );
220  mne = mnl.toElement();
221  mDataSource = mne.text();
222 
223  // if the layer needs authentication, ensure the master password is set
224  QRegExp rx( "authcfg=([a-z]|[A-Z]|[0-9]){7}" );
225  if ( ( rx.indexIn( mDataSource ) != -1 )
227  {
228  return false;
229  }
230 
231  // TODO: this should go to providers
232  if ( provider == QLatin1String( "spatialite" ) )
233  {
235  uri.setDatabase( context.pathResolver().readPath( uri.database() ) );
236  mDataSource = uri.uri();
237  }
238  else if ( provider == QLatin1String( "ogr" ) )
239  {
240  QStringList theURIParts = mDataSource.split( '|' );
241  theURIParts[0] = context.pathResolver().readPath( theURIParts[0] );
242  mDataSource = theURIParts.join( QStringLiteral( "|" ) );
243  }
244  else if ( provider == QLatin1String( "gpx" ) )
245  {
246  QStringList theURIParts = mDataSource.split( '?' );
247  theURIParts[0] = context.pathResolver().readPath( theURIParts[0] );
248  mDataSource = theURIParts.join( QStringLiteral( "?" ) );
249  }
250  else if ( provider == QLatin1String( "delimitedtext" ) )
251  {
252  QUrl urlSource = QUrl::fromEncoded( mDataSource.toLatin1() );
253 
254  if ( !mDataSource.startsWith( QLatin1String( "file:" ) ) )
255  {
256  QUrl file = QUrl::fromLocalFile( mDataSource.left( mDataSource.indexOf( '?' ) ) );
257  urlSource.setScheme( QStringLiteral( "file" ) );
258  urlSource.setPath( file.path() );
259  }
260 
261  QUrl urlDest = QUrl::fromLocalFile( context.pathResolver().readPath( urlSource.toLocalFile() ) );
262  urlDest.setQueryItems( urlSource.queryItems() );
263  mDataSource = QString::fromLatin1( urlDest.toEncoded() );
264  }
265  else if ( provider == QLatin1String( "wms" ) )
266  {
267  // >>> BACKWARD COMPATIBILITY < 1.9
268  // For project file backward compatibility we must support old format:
269  // 1. mode: <url>
270  // example: http://example.org/wms?
271  // 2. mode: tiled=<width>;<height>;<resolution>;<resolution>...,ignoreUrl=GetMap;GetFeatureInfo,featureCount=<count>,username=<name>,password=<password>,url=<url>
272  // example: tiled=256;256;0.703;0.351,url=http://example.org/tilecache?
273  // example: featureCount=10,http://example.org/wms?
274  // example: ignoreUrl=GetMap;GetFeatureInfo,username=cimrman,password=jara,url=http://example.org/wms?
275  // This is modified version of old QgsWmsProvider::parseUri
276  // The new format has always params crs,format,layers,styles and that params
277  // should not appear in old format url -> use them to identify version
278  // XYZ tile layers do not need to contain crs,format params, but they have type=xyz
279  if ( !mDataSource.contains( QLatin1String( "type=" ) ) &&
280  !mDataSource.contains( QLatin1String( "crs=" ) ) && !mDataSource.contains( QLatin1String( "format=" ) ) )
281  {
282  QgsDebugMsg( "Old WMS URI format detected -> converting to new format" );
283  QgsDataSourceUri uri;
284  if ( !mDataSource.startsWith( QLatin1String( "http:" ) ) )
285  {
286  QStringList parts = mDataSource.split( ',' );
287  QStringListIterator iter( parts );
288  while ( iter.hasNext() )
289  {
290  QString item = iter.next();
291  if ( item.startsWith( QLatin1String( "username=" ) ) )
292  {
293  uri.setParam( QStringLiteral( "username" ), item.mid( 9 ) );
294  }
295  else if ( item.startsWith( QLatin1String( "password=" ) ) )
296  {
297  uri.setParam( QStringLiteral( "password" ), item.mid( 9 ) );
298  }
299  else if ( item.startsWith( QLatin1String( "tiled=" ) ) )
300  {
301  // in < 1.9 tiled= may apper in to variants:
302  // tiled=width;height - non tiled mode, specifies max width and max height
303  // tiled=width;height;resolutions-1;resolution2;... - tile mode
304 
305  QStringList params = item.mid( 6 ).split( ';' );
306 
307  if ( params.size() == 2 ) // non tiled mode
308  {
309  uri.setParam( QStringLiteral( "maxWidth" ), params.takeFirst() );
310  uri.setParam( QStringLiteral( "maxHeight" ), params.takeFirst() );
311  }
312  else if ( params.size() > 2 ) // tiled mode
313  {
314  // resolutions are no more needed and size limit is not used for tiles
315  // we have to tell to the provider however that it is tiled
316  uri.setParam( QStringLiteral( "tileMatrixSet" ), QLatin1String( "" ) );
317  }
318  }
319  else if ( item.startsWith( QLatin1String( "featureCount=" ) ) )
320  {
321  uri.setParam( QStringLiteral( "featureCount" ), item.mid( 13 ) );
322  }
323  else if ( item.startsWith( QLatin1String( "url=" ) ) )
324  {
325  uri.setParam( QStringLiteral( "url" ), item.mid( 4 ) );
326  }
327  else if ( item.startsWith( QLatin1String( "ignoreUrl=" ) ) )
328  {
329  uri.setParam( QStringLiteral( "ignoreUrl" ), item.mid( 10 ).split( ';' ) );
330  }
331  }
332  }
333  else
334  {
335  uri.setParam( QStringLiteral( "url" ), mDataSource );
336  }
337  mDataSource = uri.encodedUri();
338  // At this point, the URI is obviously incomplete, we add additional params
339  // in QgsRasterLayer::readXml
340  }
341  // <<< BACKWARD COMPATIBILITY < 1.9
342  }
343  else
344  {
345  bool handled = false;
346 
347  if ( provider == QLatin1String( "gdal" ) )
348  {
349  if ( mDataSource.startsWith( QLatin1String( "NETCDF:" ) ) )
350  {
351  // NETCDF:filename:variable
352  // filename can be quoted with " as it can contain colons
353  QRegExp r( "NETCDF:(.+):([^:]+)" );
354  if ( r.exactMatch( mDataSource ) )
355  {
356  QString filename = r.cap( 1 );
357  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
358  filename = filename.mid( 1, filename.length() - 2 );
359  mDataSource = "NETCDF:\"" + context.pathResolver().readPath( filename ) + "\":" + r.cap( 2 );
360  handled = true;
361  }
362  }
363  else if ( mDataSource.startsWith( QLatin1String( "HDF4_SDS:" ) ) )
364  {
365  // HDF4_SDS:subdataset_type:file_name:subdataset_index
366  // filename can be quoted with " as it can contain colons
367  QRegExp r( "HDF4_SDS:([^:]+):(.+):([^:]+)" );
368  if ( r.exactMatch( mDataSource ) )
369  {
370  QString filename = r.cap( 2 );
371  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
372  filename = filename.mid( 1, filename.length() - 2 );
373  mDataSource = "HDF4_SDS:" + r.cap( 1 ) + ":\"" + context.pathResolver().readPath( filename ) + "\":" + r.cap( 3 );
374  handled = true;
375  }
376  }
377  else if ( mDataSource.startsWith( QLatin1String( "HDF5:" ) ) )
378  {
379  // HDF5:file_name:subdataset
380  // filename can be quoted with " as it can contain colons
381  QRegExp r( "HDF5:(.+):([^:]+)" );
382  if ( r.exactMatch( mDataSource ) )
383  {
384  QString filename = r.cap( 1 );
385  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
386  filename = filename.mid( 1, filename.length() - 2 );
387  mDataSource = "HDF5:\"" + context.pathResolver().readPath( filename ) + "\":" + r.cap( 2 );
388  handled = true;
389  }
390  }
391  else if ( mDataSource.contains( QRegExp( "^(NITF_IM|RADARSAT_2_CALIB):" ) ) )
392  {
393  // NITF_IM:0:filename
394  // RADARSAT_2_CALIB:?:filename
395  QRegExp r( "([^:]+):([^:]+):(.+)" );
396  if ( r.exactMatch( mDataSource ) )
397  {
398  mDataSource = r.cap( 1 ) + ':' + r.cap( 2 ) + ':' + context.pathResolver().readPath( r.cap( 3 ) );
399  handled = true;
400  }
401  }
402  }
403 
404  if ( !handled )
406  }
407 
408  // Set the CRS from project file, asking the user if necessary.
409  // Make it the saved CRS to have WMS layer projected correctly.
410  // We will still overwrite whatever GDAL etc picks up anyway
411  // further down this function.
412  mnl = layerElement.namedItem( QStringLiteral( "layername" ) );
413  mne = mnl.toElement();
414 
416  CUSTOM_CRS_VALIDATION savedValidation;
417 
418  QDomNode srsNode = layerElement.namedItem( QStringLiteral( "srs" ) );
419  mCRS.readXml( srsNode );
420  mCRS.setValidationHint( tr( "Specify CRS for layer %1" ).arg( mne.text() ) );
421  mCRS.validate();
422  savedCRS = mCRS;
423 
424  // Do not validate any projections in children, they will be overwritten anyway.
425  // No need to ask the user for a projections when it is overwritten, is there?
428 
429  // read custom properties before passing reading further to a subclass, so that
430  // the subclass can also read custom properties
431  readCustomProperties( layerElement );
432 
433  // now let the children grab what they need from the Dom node.
434  layerError = !readXml( layerElement, context );
435 
436  // overwrite CRS with what we read from project file before the raster/vector
437  // file reading functions changed it. They will if projections is specified in the file.
438  // FIXME: is this necessary?
440  mCRS = savedCRS;
441 
442  // Abort if any error in layer, such as not found.
443  if ( layerError )
444  {
445  return false;
446  }
447 
448  // the internal name is just the data source basename
449  //QFileInfo dataSourceFileInfo( mDataSource );
450  //internalName = dataSourceFileInfo.baseName();
451 
452  // set ID
453  mnl = layerElement.namedItem( QStringLiteral( "id" ) );
454  if ( ! mnl.isNull() )
455  {
456  mne = mnl.toElement();
457  if ( ! mne.isNull() && mne.text().length() > 10 ) // should be at least 17 (yyyyMMddhhmmsszzz)
458  {
459  mID = mne.text();
460  }
461  }
462 
463  // use scale dependent visibility flag
464  setScaleBasedVisibility( layerElement.attribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ) ).toInt() == 1 );
465  if ( layerElement.hasAttribute( QStringLiteral( "minimumScale" ) ) )
466  {
467  // older element, when scales were reversed
468  setMaximumScale( layerElement.attribute( QStringLiteral( "minimumScale" ) ).toDouble() );
469  setMinimumScale( layerElement.attribute( QStringLiteral( "maximumScale" ) ).toDouble() );
470  }
471  else
472  {
473  setMaximumScale( layerElement.attribute( QStringLiteral( "maxScale" ) ).toDouble() );
474  setMinimumScale( layerElement.attribute( QStringLiteral( "minScale" ) ).toDouble() );
475  }
476 
477  setAutoRefreshInterval( layerElement.attribute( QStringLiteral( "autoRefreshTime" ), QStringLiteral( "0" ) ).toInt() );
478  setAutoRefreshEnabled( layerElement.attribute( QStringLiteral( "autoRefreshEnabled" ), QStringLiteral( "0" ) ).toInt() );
479  setRefreshOnNofifyMessage( layerElement.attribute( QStringLiteral( "refreshOnNotifyMessage" ), QString() ) );
480  setRefreshOnNotifyEnabled( layerElement.attribute( QStringLiteral( "refreshOnNotifyEnabled" ), QStringLiteral( "0" ) ).toInt() );
481 
482 
483  // set name
484  mnl = layerElement.namedItem( QStringLiteral( "layername" ) );
485  mne = mnl.toElement();
486  setName( mne.text() );
487 
488  //short name
489  QDomElement shortNameElem = layerElement.firstChildElement( QStringLiteral( "shortname" ) );
490  if ( !shortNameElem.isNull() )
491  {
492  mShortName = shortNameElem.text();
493  }
494 
495  //title
496  QDomElement titleElem = layerElement.firstChildElement( QStringLiteral( "title" ) );
497  if ( !titleElem.isNull() )
498  {
499  mTitle = titleElem.text();
500  }
501 
502  //abstract
503  QDomElement abstractElem = layerElement.firstChildElement( QStringLiteral( "abstract" ) );
504  if ( !abstractElem.isNull() )
505  {
506  mAbstract = abstractElem.text();
507  }
508 
509  //keywordList
510  QDomElement keywordListElem = layerElement.firstChildElement( QStringLiteral( "keywordList" ) );
511  if ( !keywordListElem.isNull() )
512  {
513  QStringList kwdList;
514  for ( QDomNode n = keywordListElem.firstChild(); !n.isNull(); n = n.nextSibling() )
515  {
516  kwdList << n.toElement().text();
517  }
518  mKeywordList = kwdList.join( QStringLiteral( ", " ) );
519  }
520 
521  //metadataUrl
522  QDomElement dataUrlElem = layerElement.firstChildElement( QStringLiteral( "dataUrl" ) );
523  if ( !dataUrlElem.isNull() )
524  {
525  mDataUrl = dataUrlElem.text();
526  mDataUrlFormat = dataUrlElem.attribute( QStringLiteral( "format" ), QLatin1String( "" ) );
527  }
528 
529  //legendUrl
530  QDomElement legendUrlElem = layerElement.firstChildElement( QStringLiteral( "legendUrl" ) );
531  if ( !legendUrlElem.isNull() )
532  {
533  mLegendUrl = legendUrlElem.text();
534  mLegendUrlFormat = legendUrlElem.attribute( QStringLiteral( "format" ), QLatin1String( "" ) );
535  }
536 
537  //attribution
538  QDomElement attribElem = layerElement.firstChildElement( QStringLiteral( "attribution" ) );
539  if ( !attribElem.isNull() )
540  {
541  mAttribution = attribElem.text();
542  mAttributionUrl = attribElem.attribute( QStringLiteral( "href" ), QLatin1String( "" ) );
543  }
544 
545  //metadataUrl
546  QDomElement metaUrlElem = layerElement.firstChildElement( QStringLiteral( "metadataUrl" ) );
547  if ( !metaUrlElem.isNull() )
548  {
549  mMetadataUrl = metaUrlElem.text();
550  mMetadataUrlType = metaUrlElem.attribute( QStringLiteral( "type" ), QLatin1String( "" ) );
551  mMetadataUrlFormat = metaUrlElem.attribute( QStringLiteral( "format" ), QLatin1String( "" ) );
552  }
553 
554  // mMetadata.readFromLayer( this );
555  QDomElement metadataElem = layerElement.firstChildElement( QStringLiteral( "resourceMetadata" ) );
556  mMetadata.readMetadataXml( metadataElem );
557 
558  return true;
559 } // bool QgsMapLayer::readLayerXML
560 
561 
562 bool QgsMapLayer::readXml( const QDomNode &layer_node, const QgsReadWriteContext &context )
563 {
564  Q_UNUSED( layer_node );
565  Q_UNUSED( context );
566  // NOP by default; children will over-ride with behavior specific to them
567 
568  return true;
569 } // void QgsMapLayer::readXml
570 
571 
572 
573 bool QgsMapLayer::writeLayerXml( QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context ) const
574 {
575  // use scale dependent visibility flag
576  layerElement.setAttribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ), hasScaleBasedVisibility() ? 1 : 0 );
577  layerElement.setAttribute( QStringLiteral( "maxScale" ), QString::number( maximumScale() ) );
578  layerElement.setAttribute( QStringLiteral( "minScale" ), QString::number( minimumScale() ) );
579 
580  if ( !extent().isNull() )
581  {
582  layerElement.appendChild( QgsXmlUtils::writeRectangle( mExtent, document ) );
583  }
584 
585  layerElement.setAttribute( QStringLiteral( "autoRefreshTime" ), QString::number( mRefreshTimer->interval() ) );
586  layerElement.setAttribute( QStringLiteral( "autoRefreshEnabled" ), mRefreshTimer->isActive() ? 1 : 0 );
587  layerElement.setAttribute( QStringLiteral( "refreshOnNotifyEnabled" ), mIsRefreshOnNofifyEnabled ? 1 : 0 );
588  layerElement.setAttribute( QStringLiteral( "refreshOnNotifyMessage" ), mRefreshOnNofifyMessage );
589 
590 
591  // ID
592  QDomElement layerId = document.createElement( QStringLiteral( "id" ) );
593  QDomText layerIdText = document.createTextNode( id() );
594  layerId.appendChild( layerIdText );
595 
596  layerElement.appendChild( layerId );
597 
598  // data source
599  QDomElement dataSource = document.createElement( QStringLiteral( "datasource" ) );
600 
601  QString src = source();
602 
603  const QgsVectorLayer *vlayer = qobject_cast<const QgsVectorLayer *>( this );
604  // TODO: what about postgres, mysql and others, they should not go through writePath()
605  if ( vlayer && vlayer->providerType() == QLatin1String( "spatialite" ) )
606  {
607  QgsDataSourceUri uri( src );
608  QString database = context.pathResolver().writePath( uri.database() );
609  uri.setConnection( uri.host(), uri.port(), database, uri.username(), uri.password() );
610  src = uri.uri();
611  }
612  else if ( vlayer && vlayer->providerType() == QLatin1String( "ogr" ) )
613  {
614  QStringList theURIParts = src.split( '|' );
615  theURIParts[0] = context.pathResolver().writePath( theURIParts[0] );
616  src = theURIParts.join( QStringLiteral( "|" ) );
617  }
618  else if ( vlayer && vlayer->providerType() == QLatin1String( "gpx" ) )
619  {
620  QStringList theURIParts = src.split( '?' );
621  theURIParts[0] = context.pathResolver().writePath( theURIParts[0] );
622  src = theURIParts.join( QStringLiteral( "?" ) );
623  }
624  else if ( vlayer && vlayer->providerType() == QLatin1String( "delimitedtext" ) )
625  {
626  QUrl urlSource = QUrl::fromEncoded( src.toLatin1() );
627  QUrl urlDest = QUrl::fromLocalFile( context.pathResolver().writePath( urlSource.toLocalFile() ) );
628  urlDest.setQueryItems( urlSource.queryItems() );
629  src = QString::fromLatin1( urlDest.toEncoded() );
630  }
631  else if ( vlayer && vlayer->providerType() == QLatin1String( "memory" ) )
632  {
633  // Refetch the source from the provider, because adding fields actually changes the source for this provider.
634  src = vlayer->dataProvider()->dataSourceUri();
635  }
636  else
637  {
638  bool handled = false;
639 
640  if ( !vlayer )
641  {
642  const QgsRasterLayer *rlayer = qobject_cast<const QgsRasterLayer *>( this );
643  // Update path for subdataset
644  if ( rlayer && rlayer->providerType() == QLatin1String( "gdal" ) )
645  {
646  if ( src.startsWith( QLatin1String( "NETCDF:" ) ) )
647  {
648  // NETCDF:filename:variable
649  // filename can be quoted with " as it can contain colons
650  QRegExp r( "NETCDF:(.+):([^:]+)" );
651  if ( r.exactMatch( src ) )
652  {
653  QString filename = r.cap( 1 );
654  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
655  filename = filename.mid( 1, filename.length() - 2 );
656  src = "NETCDF:\"" + context.pathResolver().writePath( filename ) + "\":" + r.cap( 2 );
657  handled = true;
658  }
659  }
660  else if ( src.startsWith( QLatin1String( "HDF4_SDS:" ) ) )
661  {
662  // HDF4_SDS:subdataset_type:file_name:subdataset_index
663  // filename can be quoted with " as it can contain colons
664  QRegExp r( "HDF4_SDS:([^:]+):(.+):([^:]+)" );
665  if ( r.exactMatch( src ) )
666  {
667  QString filename = r.cap( 2 );
668  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
669  filename = filename.mid( 1, filename.length() - 2 );
670  src = "HDF4_SDS:" + r.cap( 1 ) + ":\"" + context.pathResolver().writePath( filename ) + "\":" + r.cap( 3 );
671  handled = true;
672  }
673  }
674  else if ( src.startsWith( QLatin1String( "HDF5:" ) ) )
675  {
676  // HDF5:file_name:subdataset
677  // filename can be quoted with " as it can contain colons
678  QRegExp r( "HDF5:(.+):([^:]+)" );
679  if ( r.exactMatch( src ) )
680  {
681  QString filename = r.cap( 1 );
682  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
683  filename = filename.mid( 1, filename.length() - 2 );
684  src = "HDF5:\"" + context.pathResolver().writePath( filename ) + "\":" + r.cap( 2 );
685  handled = true;
686  }
687  }
688  else if ( src.contains( QRegExp( "^(NITF_IM|RADARSAT_2_CALIB):" ) ) )
689  {
690  // NITF_IM:0:filename
691  // RADARSAT_2_CALIB:?:filename
692  QRegExp r( "([^:]+):([^:]+):(.+)" );
693  if ( r.exactMatch( src ) )
694  {
695  src = r.cap( 1 ) + ':' + r.cap( 2 ) + ':' + context.pathResolver().writePath( r.cap( 3 ) );
696  handled = true;
697  }
698  }
699  }
700  }
701 
702  if ( !handled )
703  src = context.pathResolver().writePath( src );
704  }
705 
706  QDomText dataSourceText = document.createTextNode( src );
707  dataSource.appendChild( dataSourceText );
708 
709  layerElement.appendChild( dataSource );
710 
711 
712  // layer name
713  QDomElement layerName = document.createElement( QStringLiteral( "layername" ) );
714  QDomText layerNameText = document.createTextNode( name() );
715  layerName.appendChild( layerNameText );
716  layerElement.appendChild( layerName );
717 
718  // layer short name
719  if ( !mShortName.isEmpty() )
720  {
721  QDomElement layerShortName = document.createElement( QStringLiteral( "shortname" ) );
722  QDomText layerShortNameText = document.createTextNode( mShortName );
723  layerShortName.appendChild( layerShortNameText );
724  layerElement.appendChild( layerShortName );
725  }
726 
727  // layer title
728  if ( !mTitle.isEmpty() )
729  {
730  QDomElement layerTitle = document.createElement( QStringLiteral( "title" ) );
731  QDomText layerTitleText = document.createTextNode( mTitle );
732  layerTitle.appendChild( layerTitleText );
733  layerElement.appendChild( layerTitle );
734  }
735 
736  // layer abstract
737  if ( !mAbstract.isEmpty() )
738  {
739  QDomElement layerAbstract = document.createElement( QStringLiteral( "abstract" ) );
740  QDomText layerAbstractText = document.createTextNode( mAbstract );
741  layerAbstract.appendChild( layerAbstractText );
742  layerElement.appendChild( layerAbstract );
743  }
744 
745  // layer keyword list
746  QStringList keywordStringList = keywordList().split( ',' );
747  if ( !keywordStringList.isEmpty() )
748  {
749  QDomElement layerKeywordList = document.createElement( QStringLiteral( "keywordList" ) );
750  for ( int i = 0; i < keywordStringList.size(); ++i )
751  {
752  QDomElement layerKeywordValue = document.createElement( QStringLiteral( "value" ) );
753  QDomText layerKeywordText = document.createTextNode( keywordStringList.at( i ).trimmed() );
754  layerKeywordValue.appendChild( layerKeywordText );
755  layerKeywordList.appendChild( layerKeywordValue );
756  }
757  layerElement.appendChild( layerKeywordList );
758  }
759 
760  // layer metadataUrl
761  QString aDataUrl = dataUrl();
762  if ( !aDataUrl.isEmpty() )
763  {
764  QDomElement layerDataUrl = document.createElement( QStringLiteral( "dataUrl" ) );
765  QDomText layerDataUrlText = document.createTextNode( aDataUrl );
766  layerDataUrl.appendChild( layerDataUrlText );
767  layerDataUrl.setAttribute( QStringLiteral( "format" ), dataUrlFormat() );
768  layerElement.appendChild( layerDataUrl );
769  }
770 
771  // layer legendUrl
772  QString aLegendUrl = legendUrl();
773  if ( !aLegendUrl.isEmpty() )
774  {
775  QDomElement layerLegendUrl = document.createElement( QStringLiteral( "legendUrl" ) );
776  QDomText layerLegendUrlText = document.createTextNode( aLegendUrl );
777  layerLegendUrl.appendChild( layerLegendUrlText );
778  layerLegendUrl.setAttribute( QStringLiteral( "format" ), legendUrlFormat() );
779  layerElement.appendChild( layerLegendUrl );
780  }
781 
782  // layer attribution
783  QString aAttribution = attribution();
784  if ( !aAttribution.isEmpty() )
785  {
786  QDomElement layerAttribution = document.createElement( QStringLiteral( "attribution" ) );
787  QDomText layerAttributionText = document.createTextNode( aAttribution );
788  layerAttribution.appendChild( layerAttributionText );
789  layerAttribution.setAttribute( QStringLiteral( "href" ), attributionUrl() );
790  layerElement.appendChild( layerAttribution );
791  }
792 
793  // layer metadataUrl
794  QString aMetadataUrl = metadataUrl();
795  if ( !aMetadataUrl.isEmpty() )
796  {
797  QDomElement layerMetadataUrl = document.createElement( QStringLiteral( "metadataUrl" ) );
798  QDomText layerMetadataUrlText = document.createTextNode( aMetadataUrl );
799  layerMetadataUrl.appendChild( layerMetadataUrlText );
800  layerMetadataUrl.setAttribute( QStringLiteral( "type" ), metadataUrlType() );
801  layerMetadataUrl.setAttribute( QStringLiteral( "format" ), metadataUrlFormat() );
802  layerElement.appendChild( layerMetadataUrl );
803  }
804 
805  // timestamp if supported
806  if ( timestamp() > QDateTime() )
807  {
808  QDomElement stamp = document.createElement( QStringLiteral( "timestamp" ) );
809  QDomText stampText = document.createTextNode( timestamp().toString( Qt::ISODate ) );
810  stamp.appendChild( stampText );
811  layerElement.appendChild( stamp );
812  }
813 
814  layerElement.appendChild( layerName );
815 
816  // zorder
817  // This is no longer stored in the project file. It is superfluous since the layers
818  // are written and read in the proper order.
819 
820  // spatial reference system id
821  QDomElement mySrsElement = document.createElement( QStringLiteral( "srs" ) );
822  mCRS.writeXml( mySrsElement, document );
823  layerElement.appendChild( mySrsElement );
824 
825  // layer metadata
826  QDomElement myMetadataElem = document.createElement( QStringLiteral( "resourceMetadata" ) );
827  mMetadata.writeMetadataXml( myMetadataElem, document );
828  layerElement.appendChild( myMetadataElem );
829 
830  // now append layer node to map layer node
831 
832  writeCustomProperties( layerElement, document );
833 
834  return writeXml( layerElement, document, context );
835 
836 }
837 
838 
839 bool QgsMapLayer::writeXml( QDomNode &layer_node, QDomDocument &document, const QgsReadWriteContext &context ) const
840 {
841  Q_UNUSED( layer_node );
842  Q_UNUSED( document );
843  Q_UNUSED( context );
844  // NOP by default; children will over-ride with behavior specific to them
845 
846  return true;
847 } // void QgsMapLayer::writeXml
848 
850 {
851  if ( m3DRenderer )
852  m3DRenderer->resolveReferences( *project );
853 }
854 
855 
856 void QgsMapLayer::readCustomProperties( const QDomNode &layerNode, const QString &keyStartsWith )
857 {
858  mCustomProperties.readXml( layerNode, keyStartsWith );
859 }
860 
861 void QgsMapLayer::writeCustomProperties( QDomNode &layerNode, QDomDocument &doc ) const
862 {
863  mCustomProperties.writeXml( layerNode, doc );
864 }
865 
866 void QgsMapLayer::readStyleManager( const QDomNode &layerNode )
867 {
868  QDomElement styleMgrElem = layerNode.firstChildElement( QStringLiteral( "map-layer-style-manager" ) );
869  if ( !styleMgrElem.isNull() )
870  mStyleManager->readXml( styleMgrElem );
871  else
872  mStyleManager->reset();
873 }
874 
875 void QgsMapLayer::writeStyleManager( QDomNode &layerNode, QDomDocument &doc ) const
876 {
877  if ( mStyleManager )
878  {
879  QDomElement styleMgrElem = doc.createElement( QStringLiteral( "map-layer-style-manager" ) );
880  mStyleManager->writeXml( styleMgrElem );
881  layerNode.appendChild( styleMgrElem );
882  }
883 }
884 
886 {
887  return mValid;
888 }
889 
890 #if 0
891 void QgsMapLayer::connectNotify( const char *signal )
892 {
893  Q_UNUSED( signal );
894  QgsDebugMsgLevel( "QgsMapLayer connected to " + QString( signal ), 3 );
895 } // QgsMapLayer::connectNotify
896 #endif
897 
898 bool QgsMapLayer::isInScaleRange( double scale ) const
899 {
900  return !mScaleBasedVisibility ||
901  ( ( mMinScale == 0 || mMinScale * Qgis::SCALE_PRECISION < scale )
902  && ( mMaxScale == 0 || scale < mMaxScale ) );
903 }
904 
906 {
907  return mScaleBasedVisibility;
908 }
909 
911 {
912  return mRefreshTimer->isActive();
913 }
914 
916 {
917  return mRefreshTimer->interval();
918 }
919 
921 {
922  if ( interval <= 0 )
923  {
924  mRefreshTimer->stop();
925  mRefreshTimer->setInterval( 0 );
926  }
927  else
928  {
929  mRefreshTimer->setInterval( interval );
930  }
931  emit autoRefreshIntervalChanged( mRefreshTimer->isActive() ? mRefreshTimer->interval() : 0 );
932 }
933 
935 {
936  if ( !enabled )
937  mRefreshTimer->stop();
938  else if ( mRefreshTimer->interval() > 0 )
939  mRefreshTimer->start();
940 
941  emit autoRefreshIntervalChanged( mRefreshTimer->isActive() ? mRefreshTimer->interval() : 0 );
942 }
943 
945 {
946  return mMetadata;
947 }
948 
949 void QgsMapLayer::setMaximumScale( double scale )
950 {
951  mMinScale = scale;
952 }
953 
955 {
956  return mMinScale;
957 }
958 
959 
960 void QgsMapLayer::setMinimumScale( double scale )
961 {
962  mMaxScale = scale;
963 }
964 
965 void QgsMapLayer::setScaleBasedVisibility( const bool enabled )
966 {
967  mScaleBasedVisibility = enabled;
968 }
969 
971 {
972  return mMaxScale;
973 }
974 
975 QStringList QgsMapLayer::subLayers() const
976 {
977  return QStringList(); // Empty
978 }
979 
980 void QgsMapLayer::setLayerOrder( const QStringList &layers )
981 {
982  Q_UNUSED( layers );
983  // NOOP
984 }
985 
986 void QgsMapLayer::setSubLayerVisibility( const QString &name, bool vis )
987 {
988  Q_UNUSED( name );
989  Q_UNUSED( vis );
990  // NOOP
991 }
992 
994 {
995  return mCRS;
996 }
997 
998 void QgsMapLayer::setCrs( const QgsCoordinateReferenceSystem &srs, bool emitSignal )
999 {
1000  mCRS = srs;
1001 
1002  if ( !mCRS.isValid() )
1003  {
1004  mCRS.setValidationHint( tr( "Specify CRS for layer %1" ).arg( name() ) );
1005  mCRS.validate();
1006  }
1007 
1008  if ( emitSignal )
1009  emit crsChanged();
1010 }
1011 
1012 QString QgsMapLayer::formatLayerName( const QString &name )
1013 {
1014  QString layerName( name );
1015  layerName.replace( '_', ' ' );
1017  return layerName;
1018 }
1019 
1020 QString QgsMapLayer::baseURI( PropertyType type ) const
1021 {
1022  QString myURI = publicSource();
1023 
1024  // if file is using the VSIFILE mechanism, remove the prefix
1025  if ( myURI.startsWith( QLatin1String( "/vsigzip/" ), Qt::CaseInsensitive ) )
1026  {
1027  myURI.remove( 0, 9 );
1028  }
1029  else if ( myURI.startsWith( QLatin1String( "/vsizip/" ), Qt::CaseInsensitive ) &&
1030  myURI.endsWith( QLatin1String( ".zip" ), Qt::CaseInsensitive ) )
1031  {
1032  // ideally we should look for .qml file inside zip file
1033  myURI.remove( 0, 8 );
1034  }
1035  else if ( myURI.startsWith( QLatin1String( "/vsitar/" ), Qt::CaseInsensitive ) &&
1036  ( myURI.endsWith( QLatin1String( ".tar" ), Qt::CaseInsensitive ) ||
1037  myURI.endsWith( QLatin1String( ".tar.gz" ), Qt::CaseInsensitive ) ||
1038  myURI.endsWith( QLatin1String( ".tgz" ), Qt::CaseInsensitive ) ) )
1039  {
1040  // ideally we should look for .qml file inside tar file
1041  myURI.remove( 0, 8 );
1042  }
1043 
1044  QFileInfo myFileInfo( myURI );
1045  QString key;
1046 
1047  if ( myFileInfo.exists() )
1048  {
1049  // if file is using the /vsizip/ or /vsigzip/ mechanism, cleanup the name
1050  if ( myURI.endsWith( QLatin1String( ".gz" ), Qt::CaseInsensitive ) )
1051  myURI.chop( 3 );
1052  else if ( myURI.endsWith( QLatin1String( ".zip" ), Qt::CaseInsensitive ) )
1053  myURI.chop( 4 );
1054  else if ( myURI.endsWith( QLatin1String( ".tar" ), Qt::CaseInsensitive ) )
1055  myURI.chop( 4 );
1056  else if ( myURI.endsWith( QLatin1String( ".tar.gz" ), Qt::CaseInsensitive ) )
1057  myURI.chop( 7 );
1058  else if ( myURI.endsWith( QLatin1String( ".tgz" ), Qt::CaseInsensitive ) )
1059  myURI.chop( 4 );
1060  myFileInfo.setFile( myURI );
1061  // get the file name for our .qml style file
1062  key = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + QgsMapLayer::extensionPropertyType( type );
1063  }
1064  else
1065  {
1066  key = publicSource();
1067  }
1068 
1069  return key;
1070 }
1071 
1073 {
1074  return baseURI( PropertyType::Metadata );
1075 }
1076 
1077 QString QgsMapLayer::saveDefaultMetadata( bool &resultFlag )
1078 {
1079  return saveNamedMetadata( metadataUri(), resultFlag );
1080 }
1081 
1082 QString QgsMapLayer::loadDefaultMetadata( bool &resultFlag )
1083 {
1084  return loadNamedMetadata( metadataUri(), resultFlag );
1085 }
1086 
1087 QString QgsMapLayer::styleURI() const
1088 {
1089  return baseURI( PropertyType::Style );
1090 }
1091 
1092 QString QgsMapLayer::loadDefaultStyle( bool &resultFlag )
1093 {
1094  return loadNamedStyle( styleURI(), resultFlag );
1095 }
1096 
1097 bool QgsMapLayer::loadNamedMetadataFromDatabase( const QString &db, const QString &uri, QString &qmd )
1098 {
1099  return loadNamedPropertyFromDatabase( db, uri, qmd, PropertyType::Metadata );
1100 }
1101 
1102 bool QgsMapLayer::loadNamedStyleFromDatabase( const QString &db, const QString &uri, QString &qml )
1103 {
1104  return loadNamedPropertyFromDatabase( db, uri, qml, PropertyType::Style );
1105 }
1106 
1107 bool QgsMapLayer::loadNamedPropertyFromDatabase( const QString &db, const QString &uri, QString &xml, QgsMapLayer::PropertyType type )
1108 {
1109  QgsDebugMsgLevel( QString( "db = %1 uri = %2" ).arg( db, uri ), 4 );
1110 
1111  bool resultFlag = false;
1112 
1113  // read from database
1114  sqlite3_database_unique_ptr database;
1115  sqlite3_statement_unique_ptr statement;
1116 
1117  int myResult;
1118 
1119  QgsDebugMsgLevel( QString( "Trying to load style or metadata for \"%1\" from \"%2\"" ).arg( uri, db ), 4 );
1120 
1121  if ( db.isEmpty() || !QFile( db ).exists() )
1122  return false;
1123 
1124  myResult = database.open_v2( db, SQLITE_OPEN_READONLY, nullptr );
1125  if ( myResult != SQLITE_OK )
1126  {
1127  return false;
1128  }
1129 
1130  QString mySql;
1131  switch ( type )
1132  {
1133  case Metadata:
1134  mySql = QStringLiteral( "select qmd from tbl_metadata where metadata=?" );
1135  break;
1136 
1137  case Style:
1138  mySql = QStringLiteral( "select qml from tbl_styles where style=?" );
1139  break;
1140  }
1141 
1142  statement = database.prepare( mySql, myResult );
1143  if ( myResult == SQLITE_OK )
1144  {
1145  QByteArray param = uri.toUtf8();
1146 
1147  if ( sqlite3_bind_text( statement.get(), 1, param.data(), param.length(), SQLITE_STATIC ) == SQLITE_OK &&
1148  sqlite3_step( statement.get() ) == SQLITE_ROW )
1149  {
1150  xml = QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( statement.get(), 0 ) ) );
1151  resultFlag = true;
1152  }
1153  }
1154  return resultFlag;
1155 }
1156 
1157 
1158 QString QgsMapLayer::loadNamedStyle( const QString &uri, bool &resultFlag )
1159 {
1160  return loadNamedProperty( uri, PropertyType::Style, resultFlag );
1161 }
1162 
1163 QString QgsMapLayer::loadNamedProperty( const QString &uri, QgsMapLayer::PropertyType type, bool &resultFlag )
1164 {
1165  QgsDebugMsgLevel( QString( "uri = %1 myURI = %2" ).arg( uri, publicSource() ), 4 );
1166 
1167  QgsDebugMsg( "loadNamedProperty" );
1168  resultFlag = false;
1169 
1170  QDomDocument myDocument( QStringLiteral( "qgis" ) );
1171 
1172  // location of problem associated with errorMsg
1173  int line, column;
1174  QString myErrorMessage;
1175 
1176  QFile myFile( uri );
1177  if ( myFile.open( QFile::ReadOnly ) )
1178  {
1179  QgsDebugMsg( QString( "file found %1" ).arg( uri ) );
1180  // read file
1181  resultFlag = myDocument.setContent( &myFile, &myErrorMessage, &line, &column );
1182  if ( !resultFlag )
1183  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1184  myFile.close();
1185  }
1186  else
1187  {
1188  QFileInfo project( QgsProject::instance()->fileName() );
1189  QgsDebugMsgLevel( QString( "project fileName: %1" ).arg( project.absoluteFilePath() ), 4 );
1190 
1191  QString xml;
1192  switch ( type )
1193  {
1194  case QgsMapLayer::Style:
1195  {
1196  if ( loadNamedStyleFromDatabase( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ), uri, xml ) ||
1197  ( project.exists() && loadNamedStyleFromDatabase( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), uri, xml ) ) ||
1198  loadNamedStyleFromDatabase( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( QStringLiteral( "resources/qgis.qmldb" ) ), uri, xml ) )
1199  {
1200  resultFlag = myDocument.setContent( xml, &myErrorMessage, &line, &column );
1201  if ( !resultFlag )
1202  {
1203  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1204  }
1205  }
1206  else
1207  {
1208  myErrorMessage = tr( "Style not found in database" );
1209  resultFlag = false;
1210  }
1211  break;
1212  }
1213  case QgsMapLayer::Metadata:
1214  {
1215  if ( loadNamedMetadataFromDatabase( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ), uri, xml ) ||
1216  ( project.exists() && loadNamedMetadataFromDatabase( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), uri, xml ) ) ||
1217  loadNamedMetadataFromDatabase( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( QStringLiteral( "resources/qgis.qmldb" ) ), uri, xml ) )
1218  {
1219  resultFlag = myDocument.setContent( xml, &myErrorMessage, &line, &column );
1220  if ( !resultFlag )
1221  {
1222  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1223  }
1224  }
1225  else
1226  {
1227  myErrorMessage = tr( "Metadata not found in database" );
1228  resultFlag = false;
1229  }
1230  break;
1231  }
1232  }
1233  }
1234 
1235  if ( !resultFlag )
1236  {
1237  return myErrorMessage;
1238  }
1239 
1240  switch ( type )
1241  {
1242  case QgsMapLayer::Style:
1243  resultFlag = importNamedStyle( myDocument, myErrorMessage );
1244  if ( !resultFlag )
1245  myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( uri, myErrorMessage );
1246  break;
1247  case QgsMapLayer::Metadata:
1248  resultFlag = importNamedMetadata( myDocument, myErrorMessage );
1249  if ( !resultFlag )
1250  myErrorMessage = tr( "Loading metadata file %1 failed because:\n%2" ).arg( uri, myErrorMessage );
1251  break;
1252  }
1253  return myErrorMessage;
1254 }
1255 
1256 bool QgsMapLayer::importNamedMetadata( QDomDocument &document, QString &errorMessage )
1257 {
1258  QDomElement myRoot = document.firstChildElement( QStringLiteral( "qgis" ) );
1259  if ( myRoot.isNull() )
1260  {
1261  errorMessage = tr( "Root <qgis> element could not be found" );
1262  return false;
1263  }
1264 
1265  return mMetadata.readMetadataXml( myRoot );
1266 }
1267 
1268 bool QgsMapLayer::importNamedStyle( QDomDocument &myDocument, QString &myErrorMessage )
1269 {
1270  QDomElement myRoot = myDocument.firstChildElement( QStringLiteral( "qgis" ) );
1271  if ( myRoot.isNull() )
1272  {
1273  myErrorMessage = tr( "Root <qgis> element could not be found" );
1274  return false;
1275  }
1276 
1277  // get style file version string, if any
1278  QgsProjectVersion fileVersion( myRoot.attribute( QStringLiteral( "version" ) ) );
1279  QgsProjectVersion thisVersion( Qgis::QGIS_VERSION );
1280 
1281  if ( thisVersion > fileVersion )
1282  {
1283  QgsProjectFileTransform styleFile( myDocument, fileVersion );
1284  styleFile.updateRevision( thisVersion );
1285  }
1286 
1287  //Test for matching geometry type on vector layers when applying, if geometry type is given in the style
1288  if ( type() == QgsMapLayer::VectorLayer && !myRoot.firstChildElement( QStringLiteral( "layerGeometryType" ) ).isNull() )
1289  {
1290  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( this );
1291  QgsWkbTypes::GeometryType importLayerGeometryType = static_cast<QgsWkbTypes::GeometryType>( myRoot.firstChildElement( QStringLiteral( "layerGeometryType" ) ).text().toInt() );
1292  if ( vl->geometryType() != importLayerGeometryType )
1293  {
1294  myErrorMessage = tr( "Cannot apply style to layer with a different geometry type" );
1295  return false;
1296  }
1297  }
1298 
1299  // use scale dependent visibility flag
1300  setScaleBasedVisibility( myRoot.attribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ) ).toInt() == 1 );
1301  if ( myRoot.hasAttribute( QStringLiteral( "minimumScale" ) ) )
1302  {
1303  //older scale element, when min/max were reversed
1304  setMaximumScale( myRoot.attribute( QStringLiteral( "minimumScale" ) ).toDouble() );
1305  setMinimumScale( myRoot.attribute( QStringLiteral( "maximumScale" ) ).toDouble() );
1306  }
1307  else
1308  {
1309  setMaximumScale( myRoot.attribute( QStringLiteral( "maxScale" ) ).toDouble() );
1310  setMinimumScale( myRoot.attribute( QStringLiteral( "minScale" ) ).toDouble() );
1311  }
1312 
1313  return readSymbology( myRoot, myErrorMessage, QgsReadWriteContext() ); // TODO: support relative paths in QML?
1314 }
1315 
1316 void QgsMapLayer::exportNamedMetadata( QDomDocument &doc, QString &errorMsg ) const
1317 {
1318  QDomImplementation DomImplementation;
1319  QDomDocumentType documentType = DomImplementation.createDocumentType( QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
1320  QDomDocument myDocument( documentType );
1321 
1322  QDomElement myRootNode = myDocument.createElement( QStringLiteral( "qgis" ) );
1323  myRootNode.setAttribute( QStringLiteral( "version" ), Qgis::QGIS_VERSION );
1324  myDocument.appendChild( myRootNode );
1325 
1326  if ( !mMetadata.writeMetadataXml( myRootNode, myDocument ) )
1327  {
1328  errorMsg = QObject::tr( "Could not save metadata" );
1329  return;
1330  }
1331 
1332  doc = myDocument;
1333 }
1334 
1335 void QgsMapLayer::exportNamedStyle( QDomDocument &doc, QString &errorMsg ) const
1336 {
1337  QDomImplementation DomImplementation;
1338  QDomDocumentType documentType = DomImplementation.createDocumentType( QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
1339  QDomDocument myDocument( documentType );
1340 
1341  QDomElement myRootNode = myDocument.createElement( QStringLiteral( "qgis" ) );
1342  myRootNode.setAttribute( QStringLiteral( "version" ), Qgis::QGIS_VERSION );
1343  myDocument.appendChild( myRootNode );
1344 
1345  myRootNode.setAttribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ), hasScaleBasedVisibility() ? 1 : 0 );
1346  myRootNode.setAttribute( QStringLiteral( "maxScale" ), QString::number( maximumScale() ) );
1347  myRootNode.setAttribute( QStringLiteral( "minScale" ), QString::number( minimumScale() ) );
1348 
1349  if ( !writeSymbology( myRootNode, myDocument, errorMsg, QgsReadWriteContext() ) ) // TODO: support relative paths in QML?
1350  {
1351  errorMsg = QObject::tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1352  return;
1353  }
1354 
1355  /*
1356  * Check to see if the layer is vector - in which case we should also export its geometryType
1357  * to avoid eventually pasting to a layer with a different geometry
1358  */
1359  if ( type() == QgsMapLayer::VectorLayer )
1360  {
1361  //Getting the selectionLayer geometry
1362  const QgsVectorLayer *vl = qobject_cast<const QgsVectorLayer *>( this );
1363  QString geoType = QString::number( vl->geometryType() );
1364 
1365  //Adding geometryinformation
1366  QDomElement layerGeometryType = myDocument.createElement( QStringLiteral( "layerGeometryType" ) );
1367  QDomText type = myDocument.createTextNode( geoType );
1368 
1369  layerGeometryType.appendChild( type );
1370  myRootNode.appendChild( layerGeometryType );
1371  }
1372 
1373  doc = myDocument;
1374 }
1375 
1376 QString QgsMapLayer::saveDefaultStyle( bool &resultFlag )
1377 {
1378  return saveNamedStyle( styleURI(), resultFlag );
1379 }
1380 
1381 QString QgsMapLayer::saveNamedMetadata( const QString &uri, bool &resultFlag )
1382 {
1383  return saveNamedProperty( uri, QgsMapLayer::Metadata, resultFlag );
1384 }
1385 
1386 QString QgsMapLayer::loadNamedMetadata( const QString &uri, bool &resultFlag )
1387 {
1388  return loadNamedProperty( uri, QgsMapLayer::Metadata, resultFlag );
1389 }
1390 
1391 QString QgsMapLayer::saveNamedProperty( const QString &uri, QgsMapLayer::PropertyType type, bool &resultFlag )
1392 {
1393  // check if the uri is a file or ends with .qml/.qmd,
1394  // which indicates that it should become one
1395  // everything else goes to the database
1396  QString filename;
1397 
1398  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this );
1399  if ( vlayer && vlayer->providerType() == QLatin1String( "ogr" ) )
1400  {
1401  QStringList theURIParts = uri.split( '|' );
1402  filename = theURIParts[0];
1403  }
1404  else if ( vlayer && vlayer->providerType() == QLatin1String( "gpx" ) )
1405  {
1406  QStringList theURIParts = uri.split( '?' );
1407  filename = theURIParts[0];
1408  }
1409  else if ( vlayer && vlayer->providerType() == QLatin1String( "delimitedtext" ) )
1410  {
1411  filename = QUrl::fromEncoded( uri.toLatin1() ).toLocalFile();
1412  // toLocalFile() returns an empty string if theURI is a plain Windows-path, e.g. "C:/style.qml"
1413  if ( filename.isEmpty() )
1414  filename = uri;
1415  }
1416  else
1417  {
1418  filename = uri;
1419  }
1420 
1421  QString myErrorMessage;
1422  QDomDocument myDocument;
1423  switch ( type )
1424  {
1425  case Metadata:
1426  exportNamedMetadata( myDocument, myErrorMessage );
1427  break;
1428 
1429  case Style:
1430  exportNamedStyle( myDocument, myErrorMessage );
1431  break;
1432  }
1433 
1434  QFileInfo myFileInfo( filename );
1435  if ( myFileInfo.exists() || filename.endsWith( QgsMapLayer::extensionPropertyType( type ), Qt::CaseInsensitive ) )
1436  {
1437  QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
1438  if ( !myDirInfo.isWritable() )
1439  {
1440  return tr( "The directory containing your dataset needs to be writable!" );
1441  }
1442 
1443  // now construct the file name for our .qml or .qmd file
1444  QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + QgsMapLayer::extensionPropertyType( type );
1445 
1446  QFile myFile( myFileName );
1447  if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
1448  {
1449  QTextStream myFileStream( &myFile );
1450  // save as utf-8 with 2 spaces for indents
1451  myDocument.save( myFileStream, 2 );
1452  myFile.close();
1453  resultFlag = true;
1454  switch ( type )
1455  {
1456  case Metadata:
1457  return tr( "Created default metadata file as %1" ).arg( myFileName );
1458 
1459  case Style:
1460  return tr( "Created default style file as %1" ).arg( myFileName );
1461  }
1462 
1463  }
1464  else
1465  {
1466  resultFlag = false;
1467  switch ( type )
1468  {
1469  case Metadata:
1470  return tr( "ERROR: Failed to created default metadata file as %1. Check file permissions and retry." ).arg( myFileName );
1471 
1472  case Style:
1473  return tr( "ERROR: Failed to created default style file as %1. Check file permissions and retry." ).arg( myFileName );
1474  }
1475  }
1476  }
1477  else
1478  {
1479  QString qml = myDocument.toString();
1480 
1481  // read from database
1482  sqlite3_database_unique_ptr database;
1483  sqlite3_statement_unique_ptr statement;
1484 
1485  int myResult = database.open( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ) );
1486  if ( myResult != SQLITE_OK )
1487  {
1488  return tr( "User database could not be opened." );
1489  }
1490 
1491  QByteArray param0 = uri.toUtf8();
1492  QByteArray param1 = qml.toUtf8();
1493 
1494  QString mySql;
1495  switch ( type )
1496  {
1497  case Metadata:
1498  mySql = QStringLiteral( "create table if not exists tbl_metadata(metadata varchar primary key,qmd varchar)" );
1499  break;
1500 
1501  case Style:
1502  mySql = QStringLiteral( "create table if not exists tbl_styles(style varchar primary key,qml varchar)" );
1503  break;
1504  }
1505 
1506  statement = database.prepare( mySql, myResult );
1507  if ( myResult == SQLITE_OK )
1508  {
1509  if ( sqlite3_step( statement.get() ) != SQLITE_DONE )
1510  {
1511  resultFlag = false;
1512  switch ( type )
1513  {
1514  case Metadata:
1515  return tr( "The metadata table could not be created." );
1516 
1517  case Style:
1518  return tr( "The style table could not be created." );
1519  }
1520  }
1521  }
1522 
1523  switch ( type )
1524  {
1525  case Metadata:
1526  mySql = QStringLiteral( "insert into tbl_metadata(metadata,qmd) values (?,?)" );
1527  break;
1528 
1529  case Style:
1530  mySql = QStringLiteral( "insert into tbl_styles(style,qml) values (?,?)" );
1531  break;
1532  }
1533  statement = database.prepare( mySql, myResult );
1534  if ( myResult == SQLITE_OK )
1535  {
1536  if ( sqlite3_bind_text( statement.get(), 1, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
1537  sqlite3_bind_text( statement.get(), 2, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
1538  sqlite3_step( statement.get() ) == SQLITE_DONE )
1539  {
1540  resultFlag = true;
1541  switch ( type )
1542  {
1543  case Metadata:
1544  myErrorMessage = tr( "The metadata %1 was saved to database" ).arg( uri );
1545  break;
1546 
1547  case Style:
1548  myErrorMessage = tr( "The style %1 was saved to database" ).arg( uri );
1549  break;
1550  }
1551  }
1552  }
1553 
1554  if ( !resultFlag )
1555  {
1556  QString mySql;
1557  switch ( type )
1558  {
1559  case Metadata:
1560  mySql = QStringLiteral( "update tbl_metadata set qmd=? where metadata=?" );
1561  break;
1562 
1563  case Style:
1564  mySql = QStringLiteral( "update tbl_styles set qml=? where style=?" );
1565  break;
1566  }
1567  statement = database.prepare( mySql, myResult );
1568  if ( myResult == SQLITE_OK )
1569  {
1570  if ( sqlite3_bind_text( statement.get(), 2, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
1571  sqlite3_bind_text( statement.get(), 1, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
1572  sqlite3_step( statement.get() ) == SQLITE_DONE )
1573  {
1574  resultFlag = true;
1575  switch ( type )
1576  {
1577  case Metadata:
1578  myErrorMessage = tr( "The metadata %1 was updated in the database." ).arg( uri );
1579  break;
1580 
1581  case Style:
1582  myErrorMessage = tr( "The style %1 was updated in the database." ).arg( uri );
1583  break;
1584  }
1585  }
1586  else
1587  {
1588  resultFlag = false;
1589  switch ( type )
1590  {
1591  case Metadata:
1592  myErrorMessage = tr( "The metadata %1 could not be updated in the database." ).arg( uri );
1593  break;
1594 
1595  case Style:
1596  myErrorMessage = tr( "The style %1 could not be updated in the database." ).arg( uri );
1597  break;
1598  }
1599  }
1600  }
1601  else
1602  {
1603  resultFlag = false;
1604  switch ( type )
1605  {
1606  case Metadata:
1607  myErrorMessage = tr( "The metadata %1 could not be inserted into database." ).arg( uri );
1608  break;
1609 
1610  case Style:
1611  myErrorMessage = tr( "The style %1 could not be inserted into database." ).arg( uri );
1612  break;
1613  }
1614  }
1615  }
1616  }
1617 
1618  return myErrorMessage;
1619 }
1620 
1621 QString QgsMapLayer::saveNamedStyle( const QString &uri, bool &resultFlag )
1622 {
1623  return saveNamedProperty( uri, QgsMapLayer::Style, resultFlag );
1624 }
1625 
1626 void QgsMapLayer::exportSldStyle( QDomDocument &doc, QString &errorMsg ) const
1627 {
1628  QDomDocument myDocument = QDomDocument();
1629 
1630  QDomNode header = myDocument.createProcessingInstruction( QStringLiteral( "xml" ), QStringLiteral( "version=\"1.0\" encoding=\"UTF-8\"" ) );
1631  myDocument.appendChild( header );
1632 
1633  // Create the root element
1634  QDomElement root = myDocument.createElementNS( QStringLiteral( "http://www.opengis.net/sld" ), QStringLiteral( "StyledLayerDescriptor" ) );
1635  root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.1.0" ) );
1636  root.setAttribute( QStringLiteral( "xsi:schemaLocation" ), QStringLiteral( "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" ) );
1637  root.setAttribute( QStringLiteral( "xmlns:ogc" ), QStringLiteral( "http://www.opengis.net/ogc" ) );
1638  root.setAttribute( QStringLiteral( "xmlns:se" ), QStringLiteral( "http://www.opengis.net/se" ) );
1639  root.setAttribute( QStringLiteral( "xmlns:xlink" ), QStringLiteral( "http://www.w3.org/1999/xlink" ) );
1640  root.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) );
1641  myDocument.appendChild( root );
1642 
1643  // Create the NamedLayer element
1644  QDomElement namedLayerNode = myDocument.createElement( QStringLiteral( "NamedLayer" ) );
1645  root.appendChild( namedLayerNode );
1646 
1647  const QgsVectorLayer *vlayer = qobject_cast<const QgsVectorLayer *>( this );
1648  if ( !vlayer )
1649  {
1650  errorMsg = tr( "Could not save symbology because:\n%1" )
1651  .arg( QStringLiteral( "Non-vector layers not supported yet" ) );
1652  return;
1653  }
1654 
1655  QgsStringMap props;
1656  if ( hasScaleBasedVisibility() )
1657  {
1658  props[ QStringLiteral( "scaleMinDenom" )] = QString::number( mMinScale );
1659  props[ QStringLiteral( "scaleMaxDenom" )] = QString::number( mMaxScale );
1660  }
1661  if ( !vlayer->writeSld( namedLayerNode, myDocument, errorMsg, props ) )
1662  {
1663  errorMsg = tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1664  return;
1665  }
1666 
1667  doc = myDocument;
1668 }
1669 
1670 QString QgsMapLayer::saveSldStyle( const QString &uri, bool &resultFlag ) const
1671 {
1672  QString errorMsg;
1673  QDomDocument myDocument;
1674  exportSldStyle( myDocument, errorMsg );
1675  if ( !errorMsg.isNull() )
1676  {
1677  resultFlag = false;
1678  return errorMsg;
1679  }
1680  const QgsVectorLayer *vlayer = qobject_cast<const QgsVectorLayer *>( this );
1681 
1682  // check if the uri is a file or ends with .sld,
1683  // which indicates that it should become one
1684  QString filename;
1685  if ( vlayer->providerType() == QLatin1String( "ogr" ) )
1686  {
1687  QStringList theURIParts = uri.split( '|' );
1688  filename = theURIParts[0];
1689  }
1690  else if ( vlayer->providerType() == QLatin1String( "gpx" ) )
1691  {
1692  QStringList theURIParts = uri.split( '?' );
1693  filename = theURIParts[0];
1694  }
1695  else if ( vlayer->providerType() == QLatin1String( "delimitedtext" ) )
1696  {
1697  filename = QUrl::fromEncoded( uri.toLatin1() ).toLocalFile();
1698  // toLocalFile() returns an empty string if theURI is a plain Windows-path, e.g. "C:/style.qml"
1699  if ( filename.isEmpty() )
1700  filename = uri;
1701  }
1702  else
1703  {
1704  filename = uri;
1705  }
1706 
1707  QFileInfo myFileInfo( filename );
1708  if ( myFileInfo.exists() || filename.endsWith( QLatin1String( ".sld" ), Qt::CaseInsensitive ) )
1709  {
1710  QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
1711  if ( !myDirInfo.isWritable() )
1712  {
1713  return tr( "The directory containing your dataset needs to be writable!" );
1714  }
1715 
1716  // now construct the file name for our .sld style file
1717  QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".sld";
1718 
1719  QFile myFile( myFileName );
1720  if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
1721  {
1722  QTextStream myFileStream( &myFile );
1723  // save as utf-8 with 2 spaces for indents
1724  myDocument.save( myFileStream, 2 );
1725  myFile.close();
1726  resultFlag = true;
1727  return tr( "Created default style file as %1" ).arg( myFileName );
1728  }
1729  }
1730 
1731  resultFlag = false;
1732  return tr( "ERROR: Failed to created SLD style file as %1. Check file permissions and retry." ).arg( filename );
1733 }
1734 
1735 QString QgsMapLayer::loadSldStyle( const QString &uri, bool &resultFlag )
1736 {
1737  resultFlag = false;
1738 
1739  QDomDocument myDocument;
1740 
1741  // location of problem associated with errorMsg
1742  int line, column;
1743  QString myErrorMessage;
1744 
1745  QFile myFile( uri );
1746  if ( myFile.open( QFile::ReadOnly ) )
1747  {
1748  // read file
1749  resultFlag = myDocument.setContent( &myFile, true, &myErrorMessage, &line, &column );
1750  if ( !resultFlag )
1751  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1752  myFile.close();
1753  }
1754  else
1755  {
1756  myErrorMessage = tr( "Unable to open file %1" ).arg( uri );
1757  }
1758 
1759  if ( !resultFlag )
1760  {
1761  return myErrorMessage;
1762  }
1763 
1764  // check for root SLD element
1765  QDomElement myRoot = myDocument.firstChildElement( QStringLiteral( "StyledLayerDescriptor" ) );
1766  if ( myRoot.isNull() )
1767  {
1768  myErrorMessage = QStringLiteral( "Error: StyledLayerDescriptor element not found in %1" ).arg( uri );
1769  resultFlag = false;
1770  return myErrorMessage;
1771  }
1772 
1773  // now get the style node out and pass it over to the layer
1774  // to deserialise...
1775  QDomElement namedLayerElem = myRoot.firstChildElement( QStringLiteral( "NamedLayer" ) );
1776  if ( namedLayerElem.isNull() )
1777  {
1778  myErrorMessage = QStringLiteral( "Info: NamedLayer element not found." );
1779  resultFlag = false;
1780  return myErrorMessage;
1781  }
1782 
1783  QString errorMsg;
1784  resultFlag = readSld( namedLayerElem, errorMsg );
1785  if ( !resultFlag )
1786  {
1787  myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( uri, errorMsg );
1788  return myErrorMessage;
1789  }
1790 
1791  return QLatin1String( "" );
1792 }
1793 
1794 bool QgsMapLayer::readStyle( const QDomNode &node, QString &errorMessage, const QgsReadWriteContext &context )
1795 {
1796  Q_UNUSED( node );
1797  Q_UNUSED( errorMessage );
1798  Q_UNUSED( context );
1799  return false;
1800 }
1801 
1802 bool QgsMapLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context ) const
1803 {
1804  Q_UNUSED( node );
1805  Q_UNUSED( doc );
1806  Q_UNUSED( errorMessage );
1807  Q_UNUSED( context );
1808  return false;
1809 }
1810 
1811 
1812 void QgsMapLayer::writeCommonStyle( QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context ) const
1813 {
1814  if ( m3DRenderer )
1815  {
1816  QDomElement renderer3DElem = document.createElement( QStringLiteral( "renderer-3d" ) );
1817  renderer3DElem.setAttribute( QStringLiteral( "type" ), m3DRenderer->type() );
1818  m3DRenderer->writeXml( renderer3DElem, context );
1819  layerElement.appendChild( renderer3DElem );
1820  }
1821 }
1822 
1823 void QgsMapLayer::readCommonStyle( const QDomElement &layerElement, const QgsReadWriteContext &context )
1824 {
1825  QgsAbstract3DRenderer *r3D = nullptr;
1826  QDomElement renderer3DElem = layerElement.firstChildElement( QStringLiteral( "renderer-3d" ) );
1827  if ( !renderer3DElem.isNull() )
1828  {
1829  QString type3D = renderer3DElem.attribute( QStringLiteral( "type" ) );
1831  if ( meta3D )
1832  {
1833  r3D = meta3D->createRenderer( renderer3DElem, context );
1834  }
1835  }
1836  setRenderer3D( r3D );
1837 }
1838 
1840 {
1841  return mUndoStack;
1842 }
1843 
1845 {
1846  return mUndoStackStyles;
1847 }
1848 
1850 {
1851  return mCustomProperties.keys();
1852 }
1853 
1854 void QgsMapLayer::setCustomProperty( const QString &key, const QVariant &value )
1855 {
1856  mCustomProperties.setValue( key, value );
1857 }
1858 
1860 {
1861  mCustomProperties = properties;
1862 }
1863 
1864 QVariant QgsMapLayer::customProperty( const QString &value, const QVariant &defaultValue ) const
1865 {
1866  return mCustomProperties.value( value, defaultValue );
1867 }
1868 
1869 void QgsMapLayer::removeCustomProperty( const QString &key )
1870 {
1871  mCustomProperties.remove( key );
1872 }
1873 
1875 {
1876  return mError;
1877 }
1878 
1879 
1880 
1882 {
1883  return false;
1884 }
1885 
1887 {
1888  return true;
1889 }
1890 
1891 void QgsMapLayer::setValid( bool valid )
1892 {
1893  mValid = valid;
1894 }
1895 
1897 {
1898  if ( legend == mLegend )
1899  return;
1900 
1901  delete mLegend;
1902  mLegend = legend;
1903 
1904  if ( mLegend )
1905  {
1906  mLegend->setParent( this );
1907  connect( mLegend, &QgsMapLayerLegend::itemsChanged, this, &QgsMapLayer::legendChanged );
1908  }
1909 
1910  emit legendChanged();
1911 }
1912 
1914 {
1915  return mLegend;
1916 }
1917 
1919 {
1920  return mStyleManager;
1921 }
1922 
1924 {
1925  if ( renderer == m3DRenderer )
1926  return;
1927 
1928  delete m3DRenderer;
1929  m3DRenderer = renderer;
1930  emit renderer3DChanged();
1931 }
1932 
1934 {
1935  return m3DRenderer;
1936 }
1937 
1938 void QgsMapLayer::triggerRepaint( bool deferredUpdate )
1939 {
1940  emit repaintRequested( deferredUpdate );
1941 }
1942 
1944 {
1945  mMetadata = metadata;
1946 // mMetadata.saveToLayer( this );
1947  emit metadataChanged();
1948 }
1949 
1951 {
1952  return QString();
1953 }
1954 
1955 QDateTime QgsMapLayer::timestamp() const
1956 {
1957  return QDateTime();
1958 }
1959 
1961 {
1962  emit styleChanged();
1963 }
1964 
1966 {
1967  mExtent = r;
1968 }
1969 
1970 static QList<const QgsMapLayer *> _depOutEdges( const QgsMapLayer *vl, const QgsMapLayer *that, const QSet<QgsMapLayerDependency> &layers )
1971 {
1972  QList<const QgsMapLayer *> lst;
1973  if ( vl == that )
1974  {
1975  Q_FOREACH ( const QgsMapLayerDependency &dep, layers )
1976  {
1977  if ( const QgsMapLayer *l = QgsProject::instance()->mapLayer( dep.layerId() ) )
1978  lst << l;
1979  }
1980  }
1981  else
1982  {
1983  Q_FOREACH ( const QgsMapLayerDependency &dep, vl->dependencies() )
1984  {
1985  if ( const QgsMapLayer *l = QgsProject::instance()->mapLayer( dep.layerId() ) )
1986  lst << l;
1987  }
1988  }
1989  return lst;
1990 }
1991 
1992 static bool _depHasCycleDFS( const QgsMapLayer *n, QHash<const QgsMapLayer *, int> &mark, const QgsMapLayer *that, const QSet<QgsMapLayerDependency> &layers )
1993 {
1994  if ( mark.value( n ) == 1 ) // temporary
1995  return true;
1996  if ( mark.value( n ) == 0 ) // not visited
1997  {
1998  mark[n] = 1; // temporary
1999  Q_FOREACH ( const QgsMapLayer *m, _depOutEdges( n, that, layers ) )
2000  {
2001  if ( _depHasCycleDFS( m, mark, that, layers ) )
2002  return true;
2003  }
2004  mark[n] = 2; // permanent
2005  }
2006  return false;
2007 }
2008 
2009 bool QgsMapLayer::hasDependencyCycle( const QSet<QgsMapLayerDependency> &layers ) const
2010 {
2011  QHash<const QgsMapLayer *, int> marks;
2012  return _depHasCycleDFS( this, marks, this, layers );
2013 }
2014 
2015 bool QgsMapLayer::isReadOnly() const
2016 {
2017  return true;
2018 }
2019 
2020 QSet<QgsMapLayerDependency> QgsMapLayer::dependencies() const
2021 {
2022  return mDependencies;
2023 }
2024 
2025 bool QgsMapLayer::setDependencies( const QSet<QgsMapLayerDependency> &oDeps )
2026 {
2027  QSet<QgsMapLayerDependency> deps;
2028  Q_FOREACH ( const QgsMapLayerDependency &dep, oDeps )
2029  {
2030  if ( dep.origin() == QgsMapLayerDependency::FromUser )
2031  deps << dep;
2032  }
2033  if ( hasDependencyCycle( deps ) )
2034  return false;
2035 
2036  mDependencies = deps;
2037  emit dependenciesChanged();
2038  return true;
2039 }
2040 
2042 {
2043  if ( !dataProvider() )
2044  return;
2045 
2046  if ( enabled && !isRefreshOnNotifyEnabled() )
2047  {
2048  dataProvider()->setListening( enabled );
2049  connect( dataProvider(), &QgsVectorDataProvider::notify, this, &QgsMapLayer::onNotifiedTriggerRepaint );
2050  }
2051  else if ( !enabled && isRefreshOnNotifyEnabled() )
2052  {
2053  // we don't want to disable provider listening because someone else could need it (e.g. actions)
2054  disconnect( dataProvider(), &QgsVectorDataProvider::notify, this, &QgsMapLayer::onNotifiedTriggerRepaint );
2055  }
2056  mIsRefreshOnNofifyEnabled = enabled;
2057 }
2058 
2059 void QgsMapLayer::onNotifiedTriggerRepaint( const QString &message )
2060 {
2061  if ( refreshOnNotifyMessage().isEmpty() || refreshOnNotifyMessage() == message )
2062  triggerRepaint();
2063 }
2064 
QString attributionUrl() const
Returns the attribution URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:309
Origin origin() const
Return the dependency origin.
QString mShortName
Definition: qgsmaplayer.h:1241
virtual QStringList subLayers() const
Returns the sublayers of this layer.
void writeCommonStyle(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context) const
Write style data common to all layer types.
void setMetadataUrl(const QString &metaUrl)
Sets the metadata URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:320
The class is used as a container of context for various read/write operations on other objects...
QString dataUrlFormat() const
Returns the DataUrl format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:271
A rectangle specified with double values.
Definition: qgsrectangle.h:39
Base class for all map layer types.
Definition: qgsmaplayer.h:56
static QString formatLayerName(const QString &name)
A convenience function to capitalize and format a layer name.
static Qgs3DRendererRegistry * renderer3DRegistry()
Returns registry of available 3D renderers.
static const QString QGIS_VERSION
Version string.
Definition: qgis.h:63
void currentStyleChanged(const QString &currentName)
Emitted when the current style has been changed.
void setShortName(const QString &shortName)
Sets the short name of the layer used by QGIS Server to identify the layer.
Definition: qgsmaplayer.h:179
virtual void resolveReferences(const QgsProject &project)
Resolves references to other objects - second phase of loading - after readXml()
virtual void exportSldStyle(QDomDocument &doc, QString &errorMsg) const
Export the properties of this layer as SLD style in a QDomDocument.
virtual QgsMapLayer * clone() const =0
Returns a new instance equivalent to this one except for the id which is still unique.
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.
Base class for all renderers that may to participate in 3D view.
QString mAttributionUrl
Definition: qgsmaplayer.h:1254
QString mKeywordList
Definition: qgsmaplayer.h:1246
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.
virtual QgsDataProvider * dataProvider()
Returns the layer&#39;s data provider.
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...
QStringList customPropertyKeys() const
Returns list of all keys within custom properties.
QString shortName() const
Returns the short name of the layer used by QGIS Server to identify the layer.
Definition: qgsmaplayer.h:186
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
QgsMapLayerLegend * legend() const
Can be null.
Unique pointer for sqlite3 prepared statements, which automatically finalizes the statement when the ...
void setCustomProperties(const QgsObjectCustomProperties &properties)
Set custom properties for layer.
void metadataChanged()
Emitted when the layer&#39;s metadata is changed.
QString mDataUrlFormat
Definition: qgsmaplayer.h:1250
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
virtual QgsError error() const
Get current status error.
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:253
void readCommonStyle(const QDomElement &layerElement, const QgsReadWriteContext &context)
Read style data common to all layer types.
bool updateRevision(const QgsProjectVersion &version)
void emitStyleChanged()
Triggers an emission of the styleChanged() signal.
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 ...
PropertyType
Maplayer has a style and a metadata property.
Definition: qgsmaplayer.h:105
QString mLegendUrlFormat
Definition: qgsmaplayer.h:1263
void setRefreshOnNotifyEnabled(bool enabled)
Set whether provider notification is connected to triggerRepaint.
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.
void readCustomProperties(const QDomNode &layerNode, const QString &keyStartsWith=QString())
Read custom properties from project file.
virtual bool loadNamedStyleFromDatabase(const QString &db, const QString &uri, QString &qml)
Retrieve a named style for this layer from a sqlite database.
virtual void resolveReferences(QgsProject *project)
Resolve references to other layers (kept as layer IDs after reading XML) into layer objects...
virtual bool readXml(const QDomNode &layer_node, const QgsReadWriteContext &context)
Called by readLayerXML(), used by children to read state specific to them from project files...
virtual bool writeXml(QDomNode &layer_node, QDomDocument &document, const QgsReadWriteContext &context) const
Called by writeLayerXML(), used by children to write state specific to them to project files...
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.
virtual const QgsLayerMetadata & metadata() const
Returns a reference to the layer&#39;s metadata store.
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.
void setMetadataUrlType(const QString &metaUrlType)
Set the metadata type of the layer used by QGIS Server in GetCapabilities request MetadataUrlType ind...
Definition: qgsmaplayer.h:338
bool writeMetadataXml(QDomElement &metadataElement, QDomDocument &document) const
Stores state in Dom node.
Abstract base class for spatial data provider implementations.
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.
QString saveNamedMetadata(const QString &uri, bool &resultFlag)
Save the current metadata of this layer as a named metadata (either as a .qmd file on disk or as a re...
bool isValid() const
Return the status of the layer.
void notify(const QString &msg)
Emitted when datasource issues a notification.
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.
bool mIsRefreshOnNofifyEnabled
Definition: qgsmaplayer.h:1274
QgsMapLayer::LayerType type() const
Returns the type of the layer.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:479
void remove(const QString &key)
Remove a key (entry) from the store.
void exportNamedMetadata(QDomDocument &doc, QString &errorMsg) const
Export the current metadata of this layer as named metadata in a QDomDocument.
QString mLayerName
Name of the layer - used for display.
Definition: qgsmaplayer.h:1239
QString username() const
Returns the username.
bool isRefreshOnNotifyEnabled() const
Returns true if the refresh on provider nofification is enabled.
Definition: qgsmaplayer.h:990
void styleChanged()
Signal emitted whenever a change affects the layer&#39;s style.
bool loadNamedMetadataFromDatabase(const QString &db, const QString &uri, QString &qmd)
Retrieve a named metadata for this layer from a sqlite database.
virtual bool readSymbology(const QDomNode &node, QString &errorMessage, const QgsReadWriteContext &context)=0
Read the symbology for the current layer from the Dom node supplied.
virtual QString htmlMetadata() const
Obtain a formatted HTML string containing assorted metadata for this layer.
virtual QgsRectangle extent() const
Returns the extent of the layer.
QgsMapLayer(QgsMapLayer::LayerType type=VectorLayer, const QString &name=QString(), const QString &source=QString())
Constructor for QgsMapLayer.
Definition: qgsmaplayer.cpp:69
void writeCustomProperties(QDomNode &layerNode, QDomDocument &doc) const
Write custom properties to project file.
void setMaximumScale(double scale)
Sets the maximum map scale (i.e.
QgsMapLayerStyleManager * styleManager() const
Get access to the layer&#39;s style manager.
QgsError mError
Error.
Definition: qgsmaplayer.h:1266
virtual bool writeSymbology(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context) const =0
Write the symbology for the layer into the docment provided.
QgsRectangle mExtent
Extent of the layer.
Definition: qgsmaplayer.h:1230
virtual void writeXml(QDomElement &elem, const QgsReadWriteContext &context) const =0
Writes renderer&#39;s properties to given XML element.
QString mMetadataUrl
MetadataUrl of the layer.
Definition: qgsmaplayer.h:1257
void setLegendUrlFormat(const QString &legendUrlFormat)
Sets the format for a URL based layer legend.
Definition: qgsmaplayer.h:823
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:365
void setValidationHint(const QString &html)
Set user hint for validation.
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
void setKeywordList(const QString &keywords)
Sets the keyword list of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:225
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.
static QString capitalize(const QString &string, Capitalization capitalization)
Converts a string by applying capitalization rules to the string.
void setTitle(const QString &title)
Sets the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:193
void readStyleManager(const QDomNode &layerNode)
Read style manager&#39;s configuration (if any). To be called by subclasses.
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted...
int autoRefreshInterval() const
Returns the auto refresh interval (in milliseconds).
virtual void setSubLayerVisibility(const QString &name, bool visible)
Set the visibility of the given sublayer name.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
virtual QString type() const =0
Returns unique identifier of the renderer class (used to identify subclass)
LayerType
Types of layers that can be added to a map.
Definition: qgsmaplayer.h:94
virtual void setMetadata(const QgsLayerMetadata &metadata)
Sets the layer&#39;s metadata store.
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:1269
virtual void setListening(bool isListening)
Set whether the provider will listen to datasource notifications If set, the provider will issue noti...
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?
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:233
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:1249
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.
virtual QString saveDefaultMetadata(bool &resultFlag)
Save the current metadata of this layer as the default metadata (either as a .qmd file on disk or as ...
QString legendUrl() const
Returns the URL for the layer&#39;s legend.
Definition: qgsmaplayer.h:818
QgsCoordinateReferenceSystem crs() const
Returns the layer&#39;s spatial reference system.
Reads and writes project states.
Definition: qgsproject.h:82
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 setRenderer3D(QgsAbstract3DRenderer *renderer)
Sets 3D renderer for the layer.
void removeCustomProperty(const QString &key)
Remove a custom property from layer.
static QString extensionPropertyType(PropertyType type)
Returns the extension of a Property.
Definition: qgsmaplayer.cpp:56
virtual bool importNamedStyle(QDomDocument &doc, QString &errorMsg)
Import the properties of this layer from a QDomDocument.
sqlite3_statement_unique_ptr prepare(const QString &sql, int &resultCode) const
Prepares a sql statement, returning the result.
double minimumScale() const
Returns the minimum map scale (i.e.
double maximumScale() const
Returns the maximum map scale (i.e.
bool mValid
Indicates if the layer is valid and can be drawn.
Definition: qgsmaplayer.h:1233
QString port() const
Returns the port.
void setName(const QString &name)
Set the display name of the layer.
void setDataUrlFormat(const QString &dataUrlFormat)
Sets the DataUrl format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:262
int open(const QString &path)
Opens the database at the specified file path.
QStringList keys() const
Return list of stored keys.
QgsAbstract3DRenderer * renderer3D() const
Returns 3D renderer associated with the layer.
QString mTitle
Definition: qgsmaplayer.h:1242
virtual bool readSld(const QDomNode &node, QString &errorMessage)
Definition: qgsmaplayer.h:754
QString legendUrlFormat() const
Returns the format for a URL based layer legend.
Definition: qgsmaplayer.h:828
Convert just the first letter of each word to uppercase, leave the rest untouched.
QString mMetadataUrlFormat
Definition: qgsmaplayer.h:1259
void setLegendUrl(const QString &legendUrl)
Sets the URL for the layer&#39;s legend.
Definition: qgsmaplayer.h:813
bool hasDependencyCycle(const QSet< QgsMapLayerDependency > &layers) const
Checks whether a new set of dependencies will introduce a cycle.
void setMetadataUrlFormat(const QString &metaUrlFormat)
Sets the metadata format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:356
QString title() const
Returns the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:201
static QString pkgDataPath()
Returns the common root path of all application data directories.
static CUSTOM_CRS_VALIDATION customCrsValidation()
Gets custom function.
void repaintRequested(bool deferredUpdate=false)
By emitting this signal the layer tells that either appearance or content have been changed and any v...
QString uri(bool expandAuthConfig=true) const
return complete uri
bool readLayerXml(const QDomElement &layerElement, const QgsReadWriteContext &context)
Sets state from Dom document.
QString mAttribution
Attribution of the layer.
Definition: qgsmaplayer.h:1253
QString mAbstract
Description of the layer.
Definition: qgsmaplayer.h:1245
void writeStyleManager(QDomNode &layerNode, QDomDocument &doc) const
Write style manager&#39;s configuration (if exists). To be called by subclasses.
Unique pointer for sqlite3 databases, which automatically closes the database when the pointer goes o...
bool readMetadataXml(const QDomElement &metadataElement)
Sets state from Dom document.
void blendModeChanged(QPainter::CompositionMode blendMode)
Signal emitted when the blend mode is changed, through QgsMapLayer::setBlendMode() ...
A structured metadata store for a map layer.
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:137
QString mRefreshOnNofifyMessage
Definition: qgsmaplayer.h:1275
static QgsAuthManager * authManager()
Returns the application&#39;s authentication manager instance.
virtual bool readStyle(const QDomNode &node, QString &errorMessage, const QgsReadWriteContext &context)
Read the style for the current layer from the Dom node supplied.
int open_v2(const QString &path, int flags, const char *zVfs)
Opens the database at the specified file path.
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:1236
QString source() const
Returns the source for the layer.
bool hasScaleBasedVisibility() const
Returns whether scale based visibility is enabled for the layer.
QgsError is container for error messages (report).
Definition: qgserror.h:80
bool setMasterPassword(bool verify=false)
Main call to initially set or continually check master password is set.
void setMinimumScale(double scale)
Sets the minimum map scale (i.e.
QByteArray encodedUri() const
return complete encoded uri (generic mode)
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:383
Qgs3DRendererAbstractMetadata * rendererMetadata(const QString &type) const
Returns metadata for a 3D renderer type (may be used to create a new instance of the type) ...
QString mLegendUrl
WMS legend.
Definition: qgsmaplayer.h:1262
This class represents a coordinate reference system (CRS).
QString layerId() const
Return the ID of the layer this dependency depends on.
QgsVectorDataProvider * dataProvider() override
Returns the layer&#39;s data provider.
void legendChanged()
Signal emitted when legend of the layer has changed.
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
Simple key-value store (keys = strings, values = variants) that supports loading/saving to/from XML i...
void setAutoRefreshInterval(int interval)
Sets the auto refresh interval (in milliseconds) for the layer.
virtual bool isSpatial() const
Returns true if the layer is considered a spatial layer, ie it has some form of geometry associated w...
bool readXml(const QDomNode &node)
Restores state from the given DOM node.
void setAttributionUrl(const QString &attribUrl)
Sets the attribution URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:300
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...
QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
virtual bool writeStyle(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context) const
Write just the style information for the layer into the document.
QString loadDefaultMetadata(bool &resultFlag)
Retrieve the default metadata for this layer if one exists (either as a .qmd file on disk or as a rec...
QString metadataUrl() const
Returns the metadata URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:329
void setAutoRefreshEnabled(bool enabled)
Sets whether auto refresh is enabled for the layer.
QUndoStack * undoStackStyles()
Return pointer to layer&#39;s style undo stack.
QString password() const
Returns the password.
bool addStyle(const QString &name, const QgsMapLayerStyle &style)
Add a style with given name and data.
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 setAttribution(const QString &attrib)
Sets the attribution of the layer used by QGIS Server in GetCapabilities request. ...
Definition: qgsmaplayer.h:282
void(* CUSTOM_CRS_VALIDATION)(QgsCoordinateReferenceSystem &)
QString providerType() const
Return the provider type for this layer.
void setRefreshOnNofifyMessage(const QString &message)
Set the notification message that triggers repaine If refresh on notification is enabled, the notification will triggerRepaint only if the notification message is equal to.
Definition: qgsmaplayer.h:1065
virtual QString loadNamedMetadata(const QString &uri, bool &resultFlag)
Retrieve a named metadata for this layer if one exists (either as a .qmd file on disk or as a record ...
bool hasAutoRefreshEnabled() const
Returns true if auto refresh is enabled for the layer.
Base metadata class for 3D renderers.
void setLegend(QgsMapLayerLegend *legend)
Assign a legend controller to the map layer.
Class for storing the component parts of a PostgreSQL/RDBMS datasource URI.
bool writeXml(QDomNode &node, QDomDocument &doc) const
Stores state to the given Dom node in the given document.
void autoRefreshIntervalChanged(int interval)
Emitted when the auto refresh interval changes.
This class models dependencies with or between map layers.
Management of styles for use with one map layer.
QString refreshOnNotifyMessage() const
Returns the message that should be notified by the provider to triggerRepaint.
Definition: qgsmaplayer.h:983
Represents a vector layer which manages a vector based data sets.
virtual QDateTime timestamp() const
Time stamp of data source in the moment when data/metadata were loaded by provider.
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)
bool writeLayerXml(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context) const
Stores state in Dom node.
void setDataUrl(const QString &dataUrl)
Sets the DataUrl of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:244
void setValid(bool valid)
Set whether layer is valid or not - should be used in constructor.
QString mMetadataUrlType
Definition: qgsmaplayer.h:1258
QString database() const
Returns the database.
virtual QgsAbstract3DRenderer * createRenderer(QDomElement &elem, const QgsReadWriteContext &context)=0
Returns new instance of the renderer given the DOM element.
void setDatabase(const QString &database)
Set database.
void setAbstract(const QString &abstract)
Sets the abstract of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:209
static const double SCALE_PRECISION
Fudge factor used to compare two scales.
Definition: qgis.h:138
QString attribution() const
Returns the attribution of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:291
QString metadataUrlType() const
Returns the metadata type of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:347
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.
void renderer3DChanged()
Signal emitted when 3D renderer associated with the layer has changed.
static QString removePassword(const QString &aUri)
Removes password element from uris.
~QgsMapLayer() override
Definition: qgsmaplayer.cpp:99
bool importNamedMetadata(QDomDocument &document, QString &errorMessage)
Import the metadata of this layer from a QDomDocument.
virtual QString metadataUri() const
Retrieve the metadata URI for this layer (either as a .qmd file on disk or as a record in the users s...
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.