QGIS API Documentation  3.20.0-Odense (decaadbb31)
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 #include <QTimer>
29 #include <QStandardPaths>
30 #include <QUuid>
31 
32 #include <sqlite3.h>
33 
34 #include "qgssqliteutils.h"
35 
36 #include "qgssqliteutils.h"
37 #include "qgs3drendererregistry.h"
38 #include "qgsabstract3drenderer.h"
39 #include "qgsapplication.h"
41 #include "qgsdatasourceuri.h"
42 #include "qgslogger.h"
43 #include "qgsauthmanager.h"
44 #include "qgsmaplayer.h"
45 #include "qgsmaplayerlegend.h"
47 #include "qgsmeshlayer.h"
48 #include "qgspathresolver.h"
50 #include "qgsproject.h"
51 #include "qgsproviderregistry.h"
52 #include "qgsrasterlayer.h"
53 #include "qgsreadwritecontext.h"
54 #include "qgsrectangle.h"
55 #include "qgsvectorlayer.h"
56 #include "qgsvectordataprovider.h"
57 #include "qgsxmlutils.h"
58 #include "qgsstringutils.h"
59 #include "qgsmessagelog.h"
62 #include "qgsprovidermetadata.h"
63 #include "qgslayernotesutils.h"
64 #include "qgsdatums.h"
65 #include "qgsprojoperation.h"
66 
68 {
69  switch ( type )
70  {
71  case Metadata:
72  return QStringLiteral( ".qmd" );
73 
74  case Style:
75  return QStringLiteral( ".qml" );
76  }
77  return QString();
78 }
79 
81  const QString &lyrname,
82  const QString &source )
83  : mDataSource( source )
84  , mLayerName( lyrname )
85  , mLayerType( type )
86  , mUndoStack( new QUndoStack( this ) )
87  , mUndoStackStyles( new QUndoStack( this ) )
88  , mStyleManager( new QgsMapLayerStyleManager( this ) )
89  , mRefreshTimer( new QTimer( this ) )
90 {
91  mID = generateId( lyrname );
92  connect( this, &QgsMapLayer::crsChanged, this, &QgsMapLayer::configChanged );
93  connect( this, &QgsMapLayer::nameChanged, this, &QgsMapLayer::configChanged );
94  connect( mRefreshTimer, &QTimer::timeout, this, [ = ] { triggerRepaint( true ); } );
95 }
96 
98 {
99  delete m3DRenderer;
100  delete mLegend;
101  delete mStyleManager;
102 }
103 
104 void QgsMapLayer::clone( QgsMapLayer *layer ) const
105 {
106  layer->setBlendMode( blendMode() );
107 
108  const auto constStyles = styleManager()->styles();
109  for ( const QString &s : constStyles )
110  {
111  layer->styleManager()->addStyle( s, styleManager()->style( s ) );
112  }
113 
114  layer->setName( name() );
115  layer->setShortName( shortName() );
116  layer->setExtent( extent() );
117  layer->setMaximumScale( maximumScale() );
118  layer->setMinimumScale( minimumScale() );
120  layer->setTitle( title() );
121  layer->setAbstract( abstract() );
122  layer->setKeywordList( keywordList() );
123  layer->setDataUrl( dataUrl() );
124  layer->setDataUrlFormat( dataUrlFormat() );
125  layer->setAttribution( attribution() );
126  layer->setAttributionUrl( attributionUrl() );
127  layer->setMetadataUrl( metadataUrl() );
130  layer->setLegendUrl( legendUrl() );
132  layer->setDependencies( dependencies() );
134  layer->setCrs( crs() );
135  layer->setCustomProperties( mCustomProperties );
136  layer->setOpacity( mLayerOpacity );
137  layer->setMetadata( mMetadata );
138 }
139 
141 {
142  return mLayerType;
143 }
144 
145 QgsMapLayer::LayerFlags QgsMapLayer::flags() const
146 {
147  return mFlags;
148 }
149 
150 void QgsMapLayer::setFlags( QgsMapLayer::LayerFlags flags )
151 {
152  if ( flags == mFlags )
153  return;
154 
155  mFlags = flags;
156  emit flagsChanged();
157 }
158 
159 QString QgsMapLayer::id() const
160 {
161  return mID;
162 }
163 
164 void QgsMapLayer::setName( const QString &name )
165 {
166  if ( name == mLayerName )
167  return;
168 
169  mLayerName = name;
170 
171  emit nameChanged();
172 }
173 
174 QString QgsMapLayer::name() const
175 {
176  QgsDebugMsgLevel( "returning name '" + mLayerName + '\'', 4 );
177  return mLayerName;
178 }
179 
181 {
182  return nullptr;
183 }
184 
186 {
187  return nullptr;
188 }
189 
190 QString QgsMapLayer::shortName() const
191 {
192  return mShortName;
193 }
194 
196 {
197  // Redo this every time we're asked for it, as we don't know if
198  // dataSource has changed.
199  QString safeName = QgsDataSourceUri::removePassword( mDataSource );
200  return safeName;
201 }
202 
203 QString QgsMapLayer::source() const
204 {
205  return mDataSource;
206 }
207 
209 {
210  return mExtent;
211 }
212 
213 void QgsMapLayer::setBlendMode( const QPainter::CompositionMode blendMode )
214 {
215  if ( mBlendMode == blendMode )
216  return;
217 
218  mBlendMode = blendMode;
219  emit blendModeChanged( blendMode );
221 }
222 
223 QPainter::CompositionMode QgsMapLayer::blendMode() const
224 {
225  return mBlendMode;
226 }
227 
228 void QgsMapLayer::setOpacity( double opacity )
229 {
231  return;
233  emit opacityChanged( opacity );
235 }
236 
237 double QgsMapLayer::opacity() const
238 {
239  return mLayerOpacity;
240 }
241 
242 bool QgsMapLayer::readLayerXml( const QDomElement &layerElement, QgsReadWriteContext &context, QgsMapLayer::ReadFlags flags )
243 {
244  bool layerError;
245  mReadFlags = flags;
246 
247  QDomNode mnl;
248  QDomElement mne;
249 
250  // read provider
251  QString provider;
252  mnl = layerElement.namedItem( QStringLiteral( "provider" ) );
253  mne = mnl.toElement();
254  provider = mne.text();
255 
256  // set data source
257  mnl = layerElement.namedItem( QStringLiteral( "datasource" ) );
258  mne = mnl.toElement();
259  mDataSource = mne.text();
260 
261  // if the layer needs authentication, ensure the master password is set
262  QRegExp rx( "authcfg=([a-z]|[A-Z]|[0-9]){7}" );
263  if ( ( rx.indexIn( mDataSource ) != -1 )
265  {
266  return false;
267  }
268 
269  mDataSource = decodedSource( mDataSource, provider, context );
270 
271  // Set the CRS from project file, asking the user if necessary.
272  // Make it the saved CRS to have WMS layer projected correctly.
273  // We will still overwrite whatever GDAL etc picks up anyway
274  // further down this function.
275  mnl = layerElement.namedItem( QStringLiteral( "layername" ) );
276  mne = mnl.toElement();
277 
279  CUSTOM_CRS_VALIDATION savedValidation;
280 
281  QDomNode srsNode = layerElement.namedItem( QStringLiteral( "srs" ) );
282  mCRS.readXml( srsNode );
283  mCRS.setValidationHint( tr( "Specify CRS for layer %1" ).arg( mne.text() ) );
285  mCRS.validate();
286  savedCRS = mCRS;
287 
288  // Do not validate any projections in children, they will be overwritten anyway.
289  // No need to ask the user for a projections when it is overwritten, is there?
292 
293  QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Layer" ), mne.text() );
294 
295  // the internal name is just the data source basename
296  //QFileInfo dataSourceFileInfo( mDataSource );
297  //internalName = dataSourceFileInfo.baseName();
298 
299  // set ID
300  mnl = layerElement.namedItem( QStringLiteral( "id" ) );
301  if ( ! mnl.isNull() )
302  {
303  mne = mnl.toElement();
304  if ( ! mne.isNull() && mne.text().length() > 10 ) // should be at least 17 (yyyyMMddhhmmsszzz)
305  {
306  mID = mne.text();
307  }
308  }
309 
310  // set name
311  mnl = layerElement.namedItem( QStringLiteral( "layername" ) );
312  mne = mnl.toElement();
313 
314  //name can be translated
315  setName( context.projectTranslator()->translate( QStringLiteral( "project:layers:%1" ).arg( layerElement.namedItem( QStringLiteral( "id" ) ).toElement().text() ), mne.text() ) );
316 
317  // now let the children grab what they need from the Dom node.
318  layerError = !readXml( layerElement, context );
319 
320  // overwrite CRS with what we read from project file before the raster/vector
321  // file reading functions changed it. They will if projections is specified in the file.
322  // FIXME: is this necessary? Yes, it is (autumn 2019)
324  mCRS = savedCRS;
325 
326  //short name
327  QDomElement shortNameElem = layerElement.firstChildElement( QStringLiteral( "shortname" ) );
328  if ( !shortNameElem.isNull() )
329  {
330  mShortName = shortNameElem.text();
331  }
332 
333  //title
334  QDomElement titleElem = layerElement.firstChildElement( QStringLiteral( "title" ) );
335  if ( !titleElem.isNull() )
336  {
337  mTitle = titleElem.text();
338  }
339 
340  //abstract
341  QDomElement abstractElem = layerElement.firstChildElement( QStringLiteral( "abstract" ) );
342  if ( !abstractElem.isNull() )
343  {
344  mAbstract = abstractElem.text();
345  }
346 
347  //keywordList
348  QDomElement keywordListElem = layerElement.firstChildElement( QStringLiteral( "keywordList" ) );
349  if ( !keywordListElem.isNull() )
350  {
351  QStringList kwdList;
352  for ( QDomNode n = keywordListElem.firstChild(); !n.isNull(); n = n.nextSibling() )
353  {
354  kwdList << n.toElement().text();
355  }
356  mKeywordList = kwdList.join( QLatin1String( ", " ) );
357  }
358 
359  //metadataUrl
360  QDomElement dataUrlElem = layerElement.firstChildElement( QStringLiteral( "dataUrl" ) );
361  if ( !dataUrlElem.isNull() )
362  {
363  mDataUrl = dataUrlElem.text();
364  mDataUrlFormat = dataUrlElem.attribute( QStringLiteral( "format" ), QString() );
365  }
366 
367  //legendUrl
368  QDomElement legendUrlElem = layerElement.firstChildElement( QStringLiteral( "legendUrl" ) );
369  if ( !legendUrlElem.isNull() )
370  {
371  mLegendUrl = legendUrlElem.text();
372  mLegendUrlFormat = legendUrlElem.attribute( QStringLiteral( "format" ), QString() );
373  }
374 
375  //attribution
376  QDomElement attribElem = layerElement.firstChildElement( QStringLiteral( "attribution" ) );
377  if ( !attribElem.isNull() )
378  {
379  mAttribution = attribElem.text();
380  mAttributionUrl = attribElem.attribute( QStringLiteral( "href" ), QString() );
381  }
382 
383  //metadataUrl
384  QDomElement metaUrlElem = layerElement.firstChildElement( QStringLiteral( "metadataUrl" ) );
385  if ( !metaUrlElem.isNull() )
386  {
387  mMetadataUrl = metaUrlElem.text();
388  mMetadataUrlType = metaUrlElem.attribute( QStringLiteral( "type" ), QString() );
389  mMetadataUrlFormat = metaUrlElem.attribute( QStringLiteral( "format" ), QString() );
390  }
391 
392  // mMetadata.readFromLayer( this );
393  QDomElement metadataElem = layerElement.firstChildElement( QStringLiteral( "resourceMetadata" ) );
394  mMetadata.readMetadataXml( metadataElem );
395 
396  setAutoRefreshInterval( layerElement.attribute( QStringLiteral( "autoRefreshTime" ), QStringLiteral( "0" ) ).toInt() );
397  setAutoRefreshEnabled( layerElement.attribute( QStringLiteral( "autoRefreshEnabled" ), QStringLiteral( "0" ) ).toInt() );
398  setRefreshOnNofifyMessage( layerElement.attribute( QStringLiteral( "refreshOnNotifyMessage" ), QString() ) );
399  setRefreshOnNotifyEnabled( layerElement.attribute( QStringLiteral( "refreshOnNotifyEnabled" ), QStringLiteral( "0" ) ).toInt() );
400 
401  // geographic extent is read only if necessary
402  if ( mReadFlags & QgsMapLayer::ReadFlag::FlagTrustLayerMetadata )
403  {
404  const QDomNode wgs84ExtentNode = layerElement.namedItem( QStringLiteral( "wgs84extent" ) );
405  if ( !wgs84ExtentNode.isNull() )
406  mWgs84Extent = QgsXmlUtils::readRectangle( wgs84ExtentNode.toElement() );
407  }
408 
409  return ! layerError;
410 } // bool QgsMapLayer::readLayerXML
411 
412 
413 bool QgsMapLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
414 {
415  Q_UNUSED( layer_node )
416  Q_UNUSED( context )
417  // NOP by default; children will over-ride with behavior specific to them
418 
419  // read Extent
421  {
422  const QDomNode extentNode = layer_node.namedItem( QStringLiteral( "extent" ) );
423  if ( !extentNode.isNull() )
424  {
425  mExtent = QgsXmlUtils::readRectangle( extentNode.toElement() );
426  }
427  }
428 
429  return true;
430 } // void QgsMapLayer::readXml
431 
432 
433 bool QgsMapLayer::writeLayerXml( QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context ) const
434 {
435  if ( !extent().isNull() )
436  {
437  layerElement.appendChild( QgsXmlUtils::writeRectangle( mExtent, document ) );
438  layerElement.appendChild( QgsXmlUtils::writeRectangle( wgs84Extent( true ), document, QStringLiteral( "wgs84extent" ) ) );
439  }
440 
441  layerElement.setAttribute( QStringLiteral( "autoRefreshTime" ), QString::number( mRefreshTimer->interval() ) );
442  layerElement.setAttribute( QStringLiteral( "autoRefreshEnabled" ), mRefreshTimer->isActive() ? 1 : 0 );
443  layerElement.setAttribute( QStringLiteral( "refreshOnNotifyEnabled" ), mIsRefreshOnNofifyEnabled ? 1 : 0 );
444  layerElement.setAttribute( QStringLiteral( "refreshOnNotifyMessage" ), mRefreshOnNofifyMessage );
445 
446 
447  // ID
448  QDomElement layerId = document.createElement( QStringLiteral( "id" ) );
449  QDomText layerIdText = document.createTextNode( id() );
450  layerId.appendChild( layerIdText );
451 
452  layerElement.appendChild( layerId );
453 
454  // data source
455  QDomElement dataSource = document.createElement( QStringLiteral( "datasource" ) );
456  QString src = encodedSource( source(), context );
457  QDomText dataSourceText = document.createTextNode( src );
458  dataSource.appendChild( dataSourceText );
459  layerElement.appendChild( dataSource );
460 
461  // layer name
462  QDomElement layerName = document.createElement( QStringLiteral( "layername" ) );
463  QDomText layerNameText = document.createTextNode( name() );
464  layerName.appendChild( layerNameText );
465  layerElement.appendChild( layerName );
466 
467  // layer short name
468  if ( !mShortName.isEmpty() )
469  {
470  QDomElement layerShortName = document.createElement( QStringLiteral( "shortname" ) );
471  QDomText layerShortNameText = document.createTextNode( mShortName );
472  layerShortName.appendChild( layerShortNameText );
473  layerElement.appendChild( layerShortName );
474  }
475 
476  // layer title
477  if ( !mTitle.isEmpty() )
478  {
479  QDomElement layerTitle = document.createElement( QStringLiteral( "title" ) );
480  QDomText layerTitleText = document.createTextNode( mTitle );
481  layerTitle.appendChild( layerTitleText );
482  layerElement.appendChild( layerTitle );
483  }
484 
485  // layer abstract
486  if ( !mAbstract.isEmpty() )
487  {
488  QDomElement layerAbstract = document.createElement( QStringLiteral( "abstract" ) );
489  QDomText layerAbstractText = document.createTextNode( mAbstract );
490  layerAbstract.appendChild( layerAbstractText );
491  layerElement.appendChild( layerAbstract );
492  }
493 
494  // layer keyword list
495  QStringList keywordStringList = keywordList().split( ',' );
496  if ( !keywordStringList.isEmpty() )
497  {
498  QDomElement layerKeywordList = document.createElement( QStringLiteral( "keywordList" ) );
499  for ( int i = 0; i < keywordStringList.size(); ++i )
500  {
501  QDomElement layerKeywordValue = document.createElement( QStringLiteral( "value" ) );
502  QDomText layerKeywordText = document.createTextNode( keywordStringList.at( i ).trimmed() );
503  layerKeywordValue.appendChild( layerKeywordText );
504  layerKeywordList.appendChild( layerKeywordValue );
505  }
506  layerElement.appendChild( layerKeywordList );
507  }
508 
509  // layer metadataUrl
510  QString aDataUrl = dataUrl();
511  if ( !aDataUrl.isEmpty() )
512  {
513  QDomElement layerDataUrl = document.createElement( QStringLiteral( "dataUrl" ) );
514  QDomText layerDataUrlText = document.createTextNode( aDataUrl );
515  layerDataUrl.appendChild( layerDataUrlText );
516  layerDataUrl.setAttribute( QStringLiteral( "format" ), dataUrlFormat() );
517  layerElement.appendChild( layerDataUrl );
518  }
519 
520  // layer legendUrl
521  QString aLegendUrl = legendUrl();
522  if ( !aLegendUrl.isEmpty() )
523  {
524  QDomElement layerLegendUrl = document.createElement( QStringLiteral( "legendUrl" ) );
525  QDomText layerLegendUrlText = document.createTextNode( aLegendUrl );
526  layerLegendUrl.appendChild( layerLegendUrlText );
527  layerLegendUrl.setAttribute( QStringLiteral( "format" ), legendUrlFormat() );
528  layerElement.appendChild( layerLegendUrl );
529  }
530 
531  // layer attribution
532  QString aAttribution = attribution();
533  if ( !aAttribution.isEmpty() )
534  {
535  QDomElement layerAttribution = document.createElement( QStringLiteral( "attribution" ) );
536  QDomText layerAttributionText = document.createTextNode( aAttribution );
537  layerAttribution.appendChild( layerAttributionText );
538  layerAttribution.setAttribute( QStringLiteral( "href" ), attributionUrl() );
539  layerElement.appendChild( layerAttribution );
540  }
541 
542  // layer metadataUrl
543  QString aMetadataUrl = metadataUrl();
544  if ( !aMetadataUrl.isEmpty() )
545  {
546  QDomElement layerMetadataUrl = document.createElement( QStringLiteral( "metadataUrl" ) );
547  QDomText layerMetadataUrlText = document.createTextNode( aMetadataUrl );
548  layerMetadataUrl.appendChild( layerMetadataUrlText );
549  layerMetadataUrl.setAttribute( QStringLiteral( "type" ), metadataUrlType() );
550  layerMetadataUrl.setAttribute( QStringLiteral( "format" ), metadataUrlFormat() );
551  layerElement.appendChild( layerMetadataUrl );
552  }
553 
554  // timestamp if supported
555  if ( timestamp() > QDateTime() )
556  {
557  QDomElement stamp = document.createElement( QStringLiteral( "timestamp" ) );
558  QDomText stampText = document.createTextNode( timestamp().toString( Qt::ISODate ) );
559  stamp.appendChild( stampText );
560  layerElement.appendChild( stamp );
561  }
562 
563  layerElement.appendChild( layerName );
564 
565  // zorder
566  // This is no longer stored in the project file. It is superfluous since the layers
567  // are written and read in the proper order.
568 
569  // spatial reference system id
570  QDomElement mySrsElement = document.createElement( QStringLiteral( "srs" ) );
571  mCRS.writeXml( mySrsElement, document );
572  layerElement.appendChild( mySrsElement );
573 
574  // layer metadata
575  QDomElement myMetadataElem = document.createElement( QStringLiteral( "resourceMetadata" ) );
576  mMetadata.writeMetadataXml( myMetadataElem, document );
577  layerElement.appendChild( myMetadataElem );
578 
579  // now append layer node to map layer node
580  return writeXml( layerElement, document, context );
581 }
582 
583 void QgsMapLayer::writeCommonStyle( QDomElement &layerElement, QDomDocument &document,
584  const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
585 {
586  // save categories
587  QMetaEnum metaEnum = QMetaEnum::fromType<QgsMapLayer::StyleCategories>();
588  QString categoriesKeys( metaEnum.valueToKeys( static_cast<int>( categories ) ) );
589  layerElement.setAttribute( QStringLiteral( "styleCategories" ), categoriesKeys );
590 
591  if ( categories.testFlag( Rendering ) )
592  {
593  // use scale dependent visibility flag
594  layerElement.setAttribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ), hasScaleBasedVisibility() ? 1 : 0 );
595  layerElement.setAttribute( QStringLiteral( "maxScale" ), QString::number( maximumScale() ) );
596  layerElement.setAttribute( QStringLiteral( "minScale" ), QString::number( minimumScale() ) );
597  }
598 
599  if ( categories.testFlag( Symbology3D ) )
600  {
601  if ( m3DRenderer )
602  {
603  QDomElement renderer3DElem = document.createElement( QStringLiteral( "renderer-3d" ) );
604  renderer3DElem.setAttribute( QStringLiteral( "type" ), m3DRenderer->type() );
605  m3DRenderer->writeXml( renderer3DElem, context );
606  layerElement.appendChild( renderer3DElem );
607  }
608  }
609 
610  if ( categories.testFlag( LayerConfiguration ) )
611  {
612  // flags
613  // this code is saving automatically all the flags entries
614  QDomElement layerFlagsElem = document.createElement( QStringLiteral( "flags" ) );
615  auto enumMap = qgsEnumMap<QgsMapLayer::LayerFlag>();
616  for ( auto it = enumMap.constBegin(); it != enumMap.constEnd(); ++it )
617  {
618  bool flagValue = mFlags.testFlag( it.key() );
619  QDomElement flagElem = document.createElement( it.value() );
620  flagElem.appendChild( document.createTextNode( QString::number( flagValue ) ) );
621  layerFlagsElem.appendChild( flagElem );
622  }
623  layerElement.appendChild( layerFlagsElem );
624  }
625 
626  if ( categories.testFlag( Temporal ) )
627  {
628  if ( QgsMapLayerTemporalProperties *properties = const_cast< QgsMapLayer * >( this )->temporalProperties() )
629  properties->writeXml( layerElement, document, context );
630  }
631 
632  if ( categories.testFlag( Elevation ) )
633  {
634  if ( QgsMapLayerElevationProperties *properties = const_cast< QgsMapLayer * >( this )->elevationProperties() )
635  properties->writeXml( layerElement, document, context );
636  }
637 
638  if ( categories.testFlag( Notes ) && QgsLayerNotesUtils::layerHasNotes( this ) )
639  {
640  QDomElement notesElem = document.createElement( QStringLiteral( "userNotes" ) );
641  notesElem.setAttribute( QStringLiteral( "value" ), QgsLayerNotesUtils::layerNotes( this ) );
642  layerElement.appendChild( notesElem );
643  }
644 
645  // custom properties
646  if ( categories.testFlag( CustomProperties ) )
647  {
648  writeCustomProperties( layerElement, document );
649  }
650 }
651 
652 
653 bool QgsMapLayer::writeXml( QDomNode &layer_node, QDomDocument &document, const QgsReadWriteContext &context ) const
654 {
655  Q_UNUSED( layer_node )
656  Q_UNUSED( document )
657  Q_UNUSED( context )
658  // NOP by default; children will over-ride with behavior specific to them
659 
660  return true;
661 }
662 
663 QString QgsMapLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
664 {
665  Q_UNUSED( context )
666  return source;
667 }
668 
669 QString QgsMapLayer::decodedSource( const QString &source, const QString &dataProvider, const QgsReadWriteContext &context ) const
670 {
671  Q_UNUSED( context )
672  Q_UNUSED( dataProvider )
673  return source;
674 }
675 
677 {
679  if ( m3DRenderer )
680  m3DRenderer->resolveReferences( *project );
681 }
682 
683 
684 void QgsMapLayer::readCustomProperties( const QDomNode &layerNode, const QString &keyStartsWith )
685 {
686  mCustomProperties.readXml( layerNode, keyStartsWith );
687 }
688 
689 void QgsMapLayer::writeCustomProperties( QDomNode &layerNode, QDomDocument &doc ) const
690 {
691  mCustomProperties.writeXml( layerNode, doc );
692 }
693 
694 void QgsMapLayer::readStyleManager( const QDomNode &layerNode )
695 {
696  QDomElement styleMgrElem = layerNode.firstChildElement( QStringLiteral( "map-layer-style-manager" ) );
697  if ( !styleMgrElem.isNull() )
698  mStyleManager->readXml( styleMgrElem );
699  else
700  mStyleManager->reset();
701 }
702 
703 void QgsMapLayer::writeStyleManager( QDomNode &layerNode, QDomDocument &doc ) const
704 {
705  if ( mStyleManager )
706  {
707  QDomElement styleMgrElem = doc.createElement( QStringLiteral( "map-layer-style-manager" ) );
708  mStyleManager->writeXml( styleMgrElem );
709  layerNode.appendChild( styleMgrElem );
710  }
711 }
712 
714 {
715  return mValid;
716 }
717 
718 #if 0
719 void QgsMapLayer::connectNotify( const char *signal )
720 {
721  Q_UNUSED( signal )
722  QgsDebugMsgLevel( "QgsMapLayer connected to " + QString( signal ), 3 );
723 } // QgsMapLayer::connectNotify
724 #endif
725 
726 bool QgsMapLayer::isInScaleRange( double scale ) const
727 {
728  return !mScaleBasedVisibility ||
729  ( ( mMinScale == 0 || mMinScale * Qgis::SCALE_PRECISION < scale )
730  && ( mMaxScale == 0 || scale < mMaxScale ) );
731 }
732 
734 {
735  return mScaleBasedVisibility;
736 }
737 
739 {
740  return mRefreshTimer->isActive();
741 }
742 
744 {
745  return mRefreshTimer->interval();
746 }
747 
749 {
750  if ( interval <= 0 )
751  {
752  mRefreshTimer->stop();
753  mRefreshTimer->setInterval( 0 );
754  }
755  else
756  {
757  mRefreshTimer->setInterval( interval );
758  }
759  emit autoRefreshIntervalChanged( mRefreshTimer->isActive() ? mRefreshTimer->interval() : 0 );
760 }
761 
763 {
764  if ( !enabled )
765  mRefreshTimer->stop();
766  else if ( mRefreshTimer->interval() > 0 )
767  mRefreshTimer->start();
768 
769  emit autoRefreshIntervalChanged( mRefreshTimer->isActive() ? mRefreshTimer->interval() : 0 );
770 }
771 
773 {
774  return mMetadata;
775 }
776 
777 void QgsMapLayer::setMaximumScale( double scale )
778 {
779  mMinScale = scale;
780 }
781 
783 {
784  return mMinScale;
785 }
786 
787 
788 void QgsMapLayer::setMinimumScale( double scale )
789 {
790  mMaxScale = scale;
791 }
792 
793 void QgsMapLayer::setScaleBasedVisibility( const bool enabled )
794 {
795  mScaleBasedVisibility = enabled;
796 }
797 
799 {
800  return mMaxScale;
801 }
802 
803 QStringList QgsMapLayer::subLayers() const
804 {
805  return QStringList(); // Empty
806 }
807 
808 void QgsMapLayer::setLayerOrder( const QStringList &layers )
809 {
810  Q_UNUSED( layers )
811  // NOOP
812 }
813 
814 void QgsMapLayer::setSubLayerVisibility( const QString &name, bool vis )
815 {
816  Q_UNUSED( name )
817  Q_UNUSED( vis )
818  // NOOP
819 }
820 
822 {
823  return mCRS;
824 }
825 
826 void QgsMapLayer::setCrs( const QgsCoordinateReferenceSystem &srs, bool emitSignal )
827 {
828  mCRS = srs;
829 
831  {
832  mCRS.setValidationHint( tr( "Specify CRS for layer %1" ).arg( name() ) );
833  mCRS.validate();
834  }
835 
836  if ( emitSignal )
837  emit crsChanged();
838 }
839 
841 {
842  const QgsDataProvider *lDataProvider = dataProvider();
843  return lDataProvider ? lDataProvider->transformContext() : QgsCoordinateTransformContext();
844 }
845 
846 QString QgsMapLayer::formatLayerName( const QString &name )
847 {
848  QString layerName( name );
849  layerName.replace( '_', ' ' );
851  return layerName;
852 }
853 
854 QString QgsMapLayer::baseURI( PropertyType type ) const
855 {
856  QString myURI = publicSource();
857 
858  // first get base path for delimited text, spatialite and OGR layers,
859  // as in these cases URI may contain layer name and/or additional
860  // information. This also strips prefix in case if VSIFILE mechanism
861  // is used
862  if ( providerType() == QLatin1String( "ogr" ) || providerType() == QLatin1String( "delimitedtext" ) ||
863  providerType() == QLatin1String( "spatialite" ) )
864  {
865  QVariantMap components = QgsProviderRegistry::instance()->decodeUri( providerType(), myURI );
866  myURI = components["path"].toString();
867  }
868 
869  QFileInfo myFileInfo( myURI );
870  QString key;
871 
872  if ( myFileInfo.exists() )
873  {
874  // if file is using the /vsizip/ or /vsigzip/ mechanism, cleanup the name
875  if ( myURI.endsWith( QLatin1String( ".gz" ), Qt::CaseInsensitive ) )
876  myURI.chop( 3 );
877  else if ( myURI.endsWith( QLatin1String( ".zip" ), Qt::CaseInsensitive ) )
878  myURI.chop( 4 );
879  else if ( myURI.endsWith( QLatin1String( ".tar" ), Qt::CaseInsensitive ) )
880  myURI.chop( 4 );
881  else if ( myURI.endsWith( QLatin1String( ".tar.gz" ), Qt::CaseInsensitive ) )
882  myURI.chop( 7 );
883  else if ( myURI.endsWith( QLatin1String( ".tgz" ), Qt::CaseInsensitive ) )
884  myURI.chop( 4 );
885  myFileInfo.setFile( myURI );
886  // get the file name for our .qml style file
887  key = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + QgsMapLayer::extensionPropertyType( type );
888  }
889  else
890  {
891  key = publicSource();
892  }
893 
894  return key;
895 }
896 
898 {
899  return baseURI( PropertyType::Metadata );
900 }
901 
902 QString QgsMapLayer::saveDefaultMetadata( bool &resultFlag )
903 {
904  if ( const QgsProviderMetadata *metadata = QgsProviderRegistry::instance()->providerMetadata( providerType() ) )
905  {
906  if ( metadata->providerCapabilities() & QgsProviderMetadata::SaveLayerMetadata )
907  {
908  try
909  {
910  QString errorMessage;
911  resultFlag = QgsProviderRegistry::instance()->saveLayerMetadata( providerType(), mDataSource, mMetadata, errorMessage );
912  if ( resultFlag )
913  return tr( "Successfully saved default layer metadata" );
914  else
915  return errorMessage;
916  }
917  catch ( QgsNotSupportedException &e )
918  {
919  resultFlag = false;
920  return e.what();
921  }
922  }
923  }
924 
925  // fallback default metadata saving method, for providers which don't support (or implement) saveLayerMetadata
926  return saveNamedMetadata( metadataUri(), resultFlag );
927 }
928 
929 QString QgsMapLayer::loadDefaultMetadata( bool &resultFlag )
930 {
931  return loadNamedMetadata( metadataUri(), resultFlag );
932 }
933 
934 QString QgsMapLayer::styleURI() const
935 {
936  return baseURI( PropertyType::Style );
937 }
938 
939 QString QgsMapLayer::loadDefaultStyle( bool &resultFlag )
940 {
941  return loadNamedStyle( styleURI(), resultFlag );
942 }
943 
944 bool QgsMapLayer::loadNamedMetadataFromDatabase( const QString &db, const QString &uri, QString &qmd )
945 {
946  return loadNamedPropertyFromDatabase( db, uri, qmd, PropertyType::Metadata );
947 }
948 
949 bool QgsMapLayer::loadNamedStyleFromDatabase( const QString &db, const QString &uri, QString &qml )
950 {
951  return loadNamedPropertyFromDatabase( db, uri, qml, PropertyType::Style );
952 }
953 
954 bool QgsMapLayer::loadNamedPropertyFromDatabase( const QString &db, const QString &uri, QString &xml, QgsMapLayer::PropertyType type )
955 {
956  QgsDebugMsgLevel( QStringLiteral( "db = %1 uri = %2" ).arg( db, uri ), 4 );
957 
958  bool resultFlag = false;
959 
960  // read from database
963 
964  int myResult;
965 
966  QgsDebugMsgLevel( QStringLiteral( "Trying to load style or metadata for \"%1\" from \"%2\"" ).arg( uri, db ), 4 );
967 
968  if ( db.isEmpty() || !QFile( db ).exists() )
969  return false;
970 
971  myResult = database.open_v2( db, SQLITE_OPEN_READONLY, nullptr );
972  if ( myResult != SQLITE_OK )
973  {
974  return false;
975  }
976 
977  QString mySql;
978  switch ( type )
979  {
980  case Metadata:
981  mySql = QStringLiteral( "select qmd from tbl_metadata where metadata=?" );
982  break;
983 
984  case Style:
985  mySql = QStringLiteral( "select qml from tbl_styles where style=?" );
986  break;
987  }
988 
989  statement = database.prepare( mySql, myResult );
990  if ( myResult == SQLITE_OK )
991  {
992  QByteArray param = uri.toUtf8();
993 
994  if ( sqlite3_bind_text( statement.get(), 1, param.data(), param.length(), SQLITE_STATIC ) == SQLITE_OK &&
995  sqlite3_step( statement.get() ) == SQLITE_ROW )
996  {
997  xml = QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( statement.get(), 0 ) ) );
998  resultFlag = true;
999  }
1000  }
1001  return resultFlag;
1002 }
1003 
1004 
1005 QString QgsMapLayer::loadNamedStyle( const QString &uri, bool &resultFlag, QgsMapLayer::StyleCategories categories )
1006 {
1007  return loadNamedProperty( uri, PropertyType::Style, resultFlag, categories );
1008 }
1009 
1010 QString QgsMapLayer::loadNamedProperty( const QString &uri, QgsMapLayer::PropertyType type, bool &resultFlag, StyleCategories categories )
1011 {
1012  QgsDebugMsgLevel( QStringLiteral( "uri = %1 myURI = %2" ).arg( uri, publicSource() ), 4 );
1013 
1014  resultFlag = false;
1015 
1016  QDomDocument myDocument( QStringLiteral( "qgis" ) );
1017 
1018  // location of problem associated with errorMsg
1019  int line, column;
1020  QString myErrorMessage;
1021 
1022  QFile myFile( uri );
1023  if ( myFile.open( QFile::ReadOnly ) )
1024  {
1025  QgsDebugMsgLevel( QStringLiteral( "file found %1" ).arg( uri ), 2 );
1026  // read file
1027  resultFlag = myDocument.setContent( &myFile, &myErrorMessage, &line, &column );
1028  if ( !resultFlag )
1029  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1030  myFile.close();
1031  }
1032  else
1033  {
1034  QFileInfo project( QgsProject::instance()->fileName() );
1035  QgsDebugMsgLevel( QStringLiteral( "project fileName: %1" ).arg( project.absoluteFilePath() ), 4 );
1036 
1037  QString xml;
1038  switch ( type )
1039  {
1040  case QgsMapLayer::Style:
1041  {
1042  if ( loadNamedStyleFromDatabase( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ), uri, xml ) ||
1043  ( project.exists() && loadNamedStyleFromDatabase( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), uri, xml ) ) ||
1044  loadNamedStyleFromDatabase( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( QStringLiteral( "resources/qgis.qmldb" ) ), uri, xml ) )
1045  {
1046  resultFlag = myDocument.setContent( xml, &myErrorMessage, &line, &column );
1047  if ( !resultFlag )
1048  {
1049  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1050  }
1051  }
1052  else
1053  {
1054  myErrorMessage = tr( "Style not found in database" );
1055  resultFlag = false;
1056  }
1057  break;
1058  }
1059  case QgsMapLayer::Metadata:
1060  {
1061  if ( loadNamedMetadataFromDatabase( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ), uri, xml ) ||
1062  ( project.exists() && loadNamedMetadataFromDatabase( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), uri, xml ) ) ||
1063  loadNamedMetadataFromDatabase( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( QStringLiteral( "resources/qgis.qmldb" ) ), uri, xml ) )
1064  {
1065  resultFlag = myDocument.setContent( xml, &myErrorMessage, &line, &column );
1066  if ( !resultFlag )
1067  {
1068  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1069  }
1070  }
1071  else
1072  {
1073  myErrorMessage = tr( "Metadata not found in database" );
1074  resultFlag = false;
1075  }
1076  break;
1077  }
1078  }
1079  }
1080 
1081  if ( !resultFlag )
1082  {
1083  return myErrorMessage;
1084  }
1085 
1086  switch ( type )
1087  {
1088  case QgsMapLayer::Style:
1089  resultFlag = importNamedStyle( myDocument, myErrorMessage, categories );
1090  if ( !resultFlag )
1091  myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( uri, myErrorMessage );
1092  break;
1093  case QgsMapLayer::Metadata:
1094  resultFlag = importNamedMetadata( myDocument, myErrorMessage );
1095  if ( !resultFlag )
1096  myErrorMessage = tr( "Loading metadata file %1 failed because:\n%2" ).arg( uri, myErrorMessage );
1097  break;
1098  }
1099  return myErrorMessage;
1100 }
1101 
1102 bool QgsMapLayer::importNamedMetadata( QDomDocument &document, QString &errorMessage )
1103 {
1104  QDomElement myRoot = document.firstChildElement( QStringLiteral( "qgis" ) );
1105  if ( myRoot.isNull() )
1106  {
1107  errorMessage = tr( "Root <qgis> element could not be found" );
1108  return false;
1109  }
1110 
1111  return mMetadata.readMetadataXml( myRoot );
1112 }
1113 
1114 bool QgsMapLayer::importNamedStyle( QDomDocument &myDocument, QString &myErrorMessage, QgsMapLayer::StyleCategories categories )
1115 {
1116  QDomElement myRoot = myDocument.firstChildElement( QStringLiteral( "qgis" ) );
1117  if ( myRoot.isNull() )
1118  {
1119  myErrorMessage = tr( "Root <qgis> element could not be found" );
1120  return false;
1121  }
1122 
1123  // get style file version string, if any
1124  QgsProjectVersion fileVersion( myRoot.attribute( QStringLiteral( "version" ) ) );
1125  QgsProjectVersion thisVersion( Qgis::version() );
1126 
1127  if ( thisVersion > fileVersion )
1128  {
1129  QgsProjectFileTransform styleFile( myDocument, fileVersion );
1130  styleFile.updateRevision( thisVersion );
1131  }
1132 
1133  // Get source categories
1134  QgsMapLayer::StyleCategories sourceCategories = QgsXmlUtils::readFlagAttribute( myRoot, QStringLiteral( "styleCategories" ), QgsMapLayer::AllStyleCategories );
1135 
1136  //Test for matching geometry type on vector layers when applying, if geometry type is given in the style
1137  if ( ( sourceCategories.testFlag( QgsMapLayer::Symbology ) || sourceCategories.testFlag( QgsMapLayer::Symbology3D ) ) &&
1138  ( categories.testFlag( QgsMapLayer::Symbology ) || categories.testFlag( QgsMapLayer::Symbology3D ) ) )
1139  {
1140  if ( type() == QgsMapLayerType::VectorLayer && !myRoot.firstChildElement( QStringLiteral( "layerGeometryType" ) ).isNull() )
1141  {
1142  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( this );
1143  QgsWkbTypes::GeometryType importLayerGeometryType = static_cast<QgsWkbTypes::GeometryType>( myRoot.firstChildElement( QStringLiteral( "layerGeometryType" ) ).text().toInt() );
1144  if ( importLayerGeometryType != QgsWkbTypes::GeometryType::UnknownGeometry && vl->geometryType() != importLayerGeometryType )
1145  {
1146  myErrorMessage = tr( "Cannot apply style with symbology to layer with a different geometry type" );
1147  return false;
1148  }
1149  }
1150  }
1151 
1153  return readSymbology( myRoot, myErrorMessage, context, categories ); // TODO: support relative paths in QML?
1154 }
1155 
1156 void QgsMapLayer::exportNamedMetadata( QDomDocument &doc, QString &errorMsg ) const
1157 {
1158  QDomImplementation DomImplementation;
1159  QDomDocumentType documentType = DomImplementation.createDocumentType( QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
1160  QDomDocument myDocument( documentType );
1161 
1162  QDomElement myRootNode = myDocument.createElement( QStringLiteral( "qgis" ) );
1163  myRootNode.setAttribute( QStringLiteral( "version" ), Qgis::version() );
1164  myDocument.appendChild( myRootNode );
1165 
1166  if ( !mMetadata.writeMetadataXml( myRootNode, myDocument ) )
1167  {
1168  errorMsg = QObject::tr( "Could not save metadata" );
1169  return;
1170  }
1171 
1172  doc = myDocument;
1173 }
1174 
1175 void QgsMapLayer::exportNamedStyle( QDomDocument &doc, QString &errorMsg, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1176 {
1177  QDomImplementation DomImplementation;
1178  QDomDocumentType documentType = DomImplementation.createDocumentType( QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
1179  QDomDocument myDocument( documentType );
1180 
1181  QDomElement myRootNode = myDocument.createElement( QStringLiteral( "qgis" ) );
1182  myRootNode.setAttribute( QStringLiteral( "version" ), Qgis::version() );
1183  myDocument.appendChild( myRootNode );
1184 
1185  if ( !writeSymbology( myRootNode, myDocument, errorMsg, context, categories ) ) // TODO: support relative paths in QML?
1186  {
1187  errorMsg = QObject::tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1188  return;
1189  }
1190 
1191  /*
1192  * Check to see if the layer is vector - in which case we should also export its geometryType
1193  * to avoid eventually pasting to a layer with a different geometry
1194  */
1196  {
1197  //Getting the selectionLayer geometry
1198  const QgsVectorLayer *vl = qobject_cast<const QgsVectorLayer *>( this );
1199  QString geoType = QString::number( vl->geometryType() );
1200 
1201  //Adding geometryinformation
1202  QDomElement layerGeometryType = myDocument.createElement( QStringLiteral( "layerGeometryType" ) );
1203  QDomText type = myDocument.createTextNode( geoType );
1204 
1205  layerGeometryType.appendChild( type );
1206  myRootNode.appendChild( layerGeometryType );
1207  }
1208 
1209  doc = myDocument;
1210 }
1211 
1212 QString QgsMapLayer::saveDefaultStyle( bool &resultFlag )
1213 {
1214  return saveNamedStyle( styleURI(), resultFlag );
1215 }
1216 
1217 QString QgsMapLayer::saveNamedMetadata( const QString &uri, bool &resultFlag )
1218 {
1219  return saveNamedProperty( uri, QgsMapLayer::Metadata, resultFlag );
1220 }
1221 
1222 QString QgsMapLayer::loadNamedMetadata( const QString &uri, bool &resultFlag )
1223 {
1224  return loadNamedProperty( uri, QgsMapLayer::Metadata, resultFlag );
1225 }
1226 
1227 QString QgsMapLayer::saveNamedProperty( const QString &uri, QgsMapLayer::PropertyType type, bool &resultFlag, StyleCategories categories )
1228 {
1229  // check if the uri is a file or ends with .qml/.qmd,
1230  // which indicates that it should become one
1231  // everything else goes to the database
1232  QString filename;
1233 
1234  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this );
1235  if ( vlayer && vlayer->providerType() == QLatin1String( "ogr" ) )
1236  {
1237  QStringList theURIParts = uri.split( '|' );
1238  filename = theURIParts[0];
1239  }
1240  else if ( vlayer && vlayer->providerType() == QLatin1String( "gpx" ) )
1241  {
1242  QStringList theURIParts = uri.split( '?' );
1243  filename = theURIParts[0];
1244  }
1245  else if ( vlayer && vlayer->providerType() == QLatin1String( "delimitedtext" ) )
1246  {
1247  filename = QUrl::fromEncoded( uri.toLatin1() ).toLocalFile();
1248  // toLocalFile() returns an empty string if theURI is a plain Windows-path, e.g. "C:/style.qml"
1249  if ( filename.isEmpty() )
1250  filename = uri;
1251  }
1252  else
1253  {
1254  filename = uri;
1255  }
1256 
1257  QString myErrorMessage;
1258  QDomDocument myDocument;
1259  switch ( type )
1260  {
1261  case Metadata:
1262  exportNamedMetadata( myDocument, myErrorMessage );
1263  break;
1264 
1265  case Style:
1266  QgsReadWriteContext context;
1267  exportNamedStyle( myDocument, myErrorMessage, context, categories );
1268  break;
1269  }
1270 
1271  QFileInfo myFileInfo( filename );
1272  if ( myFileInfo.exists() || filename.endsWith( QgsMapLayer::extensionPropertyType( type ), Qt::CaseInsensitive ) )
1273  {
1274  QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
1275  if ( !myDirInfo.isWritable() )
1276  {
1277  return tr( "The directory containing your dataset needs to be writable!" );
1278  }
1279 
1280  // now construct the file name for our .qml or .qmd file
1281  QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + QgsMapLayer::extensionPropertyType( type );
1282 
1283  QFile myFile( myFileName );
1284  if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
1285  {
1286  QTextStream myFileStream( &myFile );
1287  // save as utf-8 with 2 spaces for indents
1288  myDocument.save( myFileStream, 2 );
1289  myFile.close();
1290  resultFlag = true;
1291  switch ( type )
1292  {
1293  case Metadata:
1294  return tr( "Created default metadata file as %1" ).arg( myFileName );
1295 
1296  case Style:
1297  return tr( "Created default style file as %1" ).arg( myFileName );
1298  }
1299 
1300  }
1301  else
1302  {
1303  resultFlag = false;
1304  switch ( type )
1305  {
1306  case Metadata:
1307  return tr( "ERROR: Failed to created default metadata file as %1. Check file permissions and retry." ).arg( myFileName );
1308 
1309  case Style:
1310  return tr( "ERROR: Failed to created default style file as %1. Check file permissions and retry." ).arg( myFileName );
1311  }
1312  }
1313  }
1314  else
1315  {
1316  QString qml = myDocument.toString();
1317 
1318  // read from database
1319  sqlite3_database_unique_ptr database;
1320  sqlite3_statement_unique_ptr statement;
1321 
1322  int myResult = database.open( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ) );
1323  if ( myResult != SQLITE_OK )
1324  {
1325  return tr( "User database could not be opened." );
1326  }
1327 
1328  QByteArray param0 = uri.toUtf8();
1329  QByteArray param1 = qml.toUtf8();
1330 
1331  QString mySql;
1332  switch ( type )
1333  {
1334  case Metadata:
1335  mySql = QStringLiteral( "create table if not exists tbl_metadata(metadata varchar primary key,qmd varchar)" );
1336  break;
1337 
1338  case Style:
1339  mySql = QStringLiteral( "create table if not exists tbl_styles(style varchar primary key,qml varchar)" );
1340  break;
1341  }
1342 
1343  statement = database.prepare( mySql, myResult );
1344  if ( myResult == SQLITE_OK )
1345  {
1346  if ( sqlite3_step( statement.get() ) != SQLITE_DONE )
1347  {
1348  resultFlag = false;
1349  switch ( type )
1350  {
1351  case Metadata:
1352  return tr( "The metadata table could not be created." );
1353 
1354  case Style:
1355  return tr( "The style table could not be created." );
1356  }
1357  }
1358  }
1359 
1360  switch ( type )
1361  {
1362  case Metadata:
1363  mySql = QStringLiteral( "insert into tbl_metadata(metadata,qmd) values (?,?)" );
1364  break;
1365 
1366  case Style:
1367  mySql = QStringLiteral( "insert into tbl_styles(style,qml) values (?,?)" );
1368  break;
1369  }
1370  statement = database.prepare( mySql, myResult );
1371  if ( myResult == SQLITE_OK )
1372  {
1373  if ( sqlite3_bind_text( statement.get(), 1, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
1374  sqlite3_bind_text( statement.get(), 2, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
1375  sqlite3_step( statement.get() ) == SQLITE_DONE )
1376  {
1377  resultFlag = true;
1378  switch ( type )
1379  {
1380  case Metadata:
1381  myErrorMessage = tr( "The metadata %1 was saved to database" ).arg( uri );
1382  break;
1383 
1384  case Style:
1385  myErrorMessage = tr( "The style %1 was saved to database" ).arg( uri );
1386  break;
1387  }
1388  }
1389  }
1390 
1391  if ( !resultFlag )
1392  {
1393  QString mySql;
1394  switch ( type )
1395  {
1396  case Metadata:
1397  mySql = QStringLiteral( "update tbl_metadata set qmd=? where metadata=?" );
1398  break;
1399 
1400  case Style:
1401  mySql = QStringLiteral( "update tbl_styles set qml=? where style=?" );
1402  break;
1403  }
1404  statement = database.prepare( mySql, myResult );
1405  if ( myResult == SQLITE_OK )
1406  {
1407  if ( sqlite3_bind_text( statement.get(), 2, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
1408  sqlite3_bind_text( statement.get(), 1, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
1409  sqlite3_step( statement.get() ) == SQLITE_DONE )
1410  {
1411  resultFlag = true;
1412  switch ( type )
1413  {
1414  case Metadata:
1415  myErrorMessage = tr( "The metadata %1 was updated in the database." ).arg( uri );
1416  break;
1417 
1418  case Style:
1419  myErrorMessage = tr( "The style %1 was updated in the database." ).arg( uri );
1420  break;
1421  }
1422  }
1423  else
1424  {
1425  resultFlag = false;
1426  switch ( type )
1427  {
1428  case Metadata:
1429  myErrorMessage = tr( "The metadata %1 could not be updated in the database." ).arg( uri );
1430  break;
1431 
1432  case Style:
1433  myErrorMessage = tr( "The style %1 could not be updated in the database." ).arg( uri );
1434  break;
1435  }
1436  }
1437  }
1438  else
1439  {
1440  resultFlag = false;
1441  switch ( type )
1442  {
1443  case Metadata:
1444  myErrorMessage = tr( "The metadata %1 could not be inserted into database." ).arg( uri );
1445  break;
1446 
1447  case Style:
1448  myErrorMessage = tr( "The style %1 could not be inserted into database." ).arg( uri );
1449  break;
1450  }
1451  }
1452  }
1453  }
1454 
1455  return myErrorMessage;
1456 }
1457 
1458 QString QgsMapLayer::saveNamedStyle( const QString &uri, bool &resultFlag, StyleCategories categories )
1459 {
1460  return saveNamedProperty( uri, QgsMapLayer::Style, resultFlag, categories );
1461 }
1462 
1463 void QgsMapLayer::exportSldStyle( QDomDocument &doc, QString &errorMsg ) const
1464 {
1465  QDomDocument myDocument = QDomDocument();
1466 
1467  QDomNode header = myDocument.createProcessingInstruction( QStringLiteral( "xml" ), QStringLiteral( "version=\"1.0\" encoding=\"UTF-8\"" ) );
1468  myDocument.appendChild( header );
1469 
1470  const QgsVectorLayer *vlayer = qobject_cast<const QgsVectorLayer *>( this );
1471  const QgsRasterLayer *rlayer = qobject_cast<const QgsRasterLayer *>( this );
1472  if ( !vlayer && !rlayer )
1473  {
1474  errorMsg = tr( "Could not save symbology because:\n%1" )
1475  .arg( tr( "Only vector and raster layers are supported" ) );
1476  return;
1477  }
1478 
1479  // Create the root element
1480  QDomElement root = myDocument.createElementNS( QStringLiteral( "http://www.opengis.net/sld" ), QStringLiteral( "StyledLayerDescriptor" ) );
1481  QDomElement layerNode;
1482  if ( vlayer )
1483  {
1484  root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.1.0" ) );
1485  root.setAttribute( QStringLiteral( "xsi:schemaLocation" ), QStringLiteral( "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" ) );
1486  root.setAttribute( QStringLiteral( "xmlns:ogc" ), QStringLiteral( "http://www.opengis.net/ogc" ) );
1487  root.setAttribute( QStringLiteral( "xmlns:se" ), QStringLiteral( "http://www.opengis.net/se" ) );
1488  root.setAttribute( QStringLiteral( "xmlns:xlink" ), QStringLiteral( "http://www.w3.org/1999/xlink" ) );
1489  root.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) );
1490  myDocument.appendChild( root );
1491 
1492  // Create the NamedLayer element
1493  layerNode = myDocument.createElement( QStringLiteral( "NamedLayer" ) );
1494  root.appendChild( layerNode );
1495  }
1496 
1497  // note: Only SLD 1.0 version is generated because seems none is using SE1.1.0 at least for rasters
1498  if ( rlayer )
1499  {
1500  // Create the root element
1501  root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0.0" ) );
1502  root.setAttribute( QStringLiteral( "xmlns:gml" ), QStringLiteral( "http://www.opengis.net/gml" ) );
1503  root.setAttribute( QStringLiteral( "xmlns:ogc" ), QStringLiteral( "http://www.opengis.net/ogc" ) );
1504  root.setAttribute( QStringLiteral( "xmlns:sld" ), QStringLiteral( "http://www.opengis.net/sld" ) );
1505  myDocument.appendChild( root );
1506 
1507  // Create the NamedLayer element
1508  layerNode = myDocument.createElement( QStringLiteral( "UserLayer" ) );
1509  root.appendChild( layerNode );
1510  }
1511 
1512  QVariantMap props;
1513  if ( hasScaleBasedVisibility() )
1514  {
1515  props[ QStringLiteral( "scaleMinDenom" ) ] = QString::number( mMinScale );
1516  props[ QStringLiteral( "scaleMaxDenom" ) ] = QString::number( mMaxScale );
1517  }
1518 
1519  if ( vlayer )
1520  {
1521  if ( !vlayer->writeSld( layerNode, myDocument, errorMsg, props ) )
1522  {
1523  errorMsg = tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1524  return;
1525  }
1526  }
1527 
1528  if ( rlayer )
1529  {
1530  if ( !rlayer->writeSld( layerNode, myDocument, errorMsg, props ) )
1531  {
1532  errorMsg = tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1533  return;
1534  }
1535  }
1536 
1537  doc = myDocument;
1538 }
1539 
1540 QString QgsMapLayer::saveSldStyle( const QString &uri, bool &resultFlag ) const
1541 {
1542  const QgsMapLayer *mlayer = qobject_cast<const QgsMapLayer *>( this );
1543 
1544  QString errorMsg;
1545  QDomDocument myDocument;
1546  mlayer->exportSldStyle( myDocument, errorMsg );
1547  if ( !errorMsg.isNull() )
1548  {
1549  resultFlag = false;
1550  return errorMsg;
1551  }
1552  // check if the uri is a file or ends with .sld,
1553  // which indicates that it should become one
1554  QString filename;
1555  if ( mlayer->providerType() == QLatin1String( "ogr" ) )
1556  {
1557  QStringList theURIParts = uri.split( '|' );
1558  filename = theURIParts[0];
1559  }
1560  else if ( mlayer->providerType() == QLatin1String( "gpx" ) )
1561  {
1562  QStringList theURIParts = uri.split( '?' );
1563  filename = theURIParts[0];
1564  }
1565  else if ( mlayer->providerType() == QLatin1String( "delimitedtext" ) )
1566  {
1567  filename = QUrl::fromEncoded( uri.toLatin1() ).toLocalFile();
1568  // toLocalFile() returns an empty string if theURI is a plain Windows-path, e.g. "C:/style.qml"
1569  if ( filename.isEmpty() )
1570  filename = uri;
1571  }
1572  else
1573  {
1574  filename = uri;
1575  }
1576 
1577  QFileInfo myFileInfo( filename );
1578  if ( myFileInfo.exists() || filename.endsWith( QLatin1String( ".sld" ), Qt::CaseInsensitive ) )
1579  {
1580  QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
1581  if ( !myDirInfo.isWritable() )
1582  {
1583  return tr( "The directory containing your dataset needs to be writable!" );
1584  }
1585 
1586  // now construct the file name for our .sld style file
1587  QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".sld";
1588 
1589  QFile myFile( myFileName );
1590  if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
1591  {
1592  QTextStream myFileStream( &myFile );
1593  // save as utf-8 with 2 spaces for indents
1594  myDocument.save( myFileStream, 2 );
1595  myFile.close();
1596  resultFlag = true;
1597  return tr( "Created default style file as %1" ).arg( myFileName );
1598  }
1599  }
1600 
1601  resultFlag = false;
1602  return tr( "ERROR: Failed to created SLD style file as %1. Check file permissions and retry." ).arg( filename );
1603 }
1604 
1605 QString QgsMapLayer::loadSldStyle( const QString &uri, bool &resultFlag )
1606 {
1607  resultFlag = false;
1608 
1609  QDomDocument myDocument;
1610 
1611  // location of problem associated with errorMsg
1612  int line, column;
1613  QString myErrorMessage;
1614 
1615  QFile myFile( uri );
1616  if ( myFile.open( QFile::ReadOnly ) )
1617  {
1618  // read file
1619  resultFlag = myDocument.setContent( &myFile, true, &myErrorMessage, &line, &column );
1620  if ( !resultFlag )
1621  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1622  myFile.close();
1623  }
1624  else
1625  {
1626  myErrorMessage = tr( "Unable to open file %1" ).arg( uri );
1627  }
1628 
1629  if ( !resultFlag )
1630  {
1631  return myErrorMessage;
1632  }
1633 
1634  // check for root SLD element
1635  QDomElement myRoot = myDocument.firstChildElement( QStringLiteral( "StyledLayerDescriptor" ) );
1636  if ( myRoot.isNull() )
1637  {
1638  myErrorMessage = QStringLiteral( "Error: StyledLayerDescriptor element not found in %1" ).arg( uri );
1639  resultFlag = false;
1640  return myErrorMessage;
1641  }
1642 
1643  // now get the style node out and pass it over to the layer
1644  // to deserialise...
1645  QDomElement namedLayerElem = myRoot.firstChildElement( QStringLiteral( "NamedLayer" ) );
1646  if ( namedLayerElem.isNull() )
1647  {
1648  myErrorMessage = QStringLiteral( "Info: NamedLayer element not found." );
1649  resultFlag = false;
1650  return myErrorMessage;
1651  }
1652 
1653  QString errorMsg;
1654  resultFlag = readSld( namedLayerElem, errorMsg );
1655  if ( !resultFlag )
1656  {
1657  myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( uri, errorMsg );
1658  return myErrorMessage;
1659  }
1660 
1661  return QString();
1662 }
1663 
1664 bool QgsMapLayer::readStyle( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
1665 {
1666  Q_UNUSED( node )
1667  Q_UNUSED( errorMessage )
1668  Q_UNUSED( context )
1669  Q_UNUSED( categories )
1670  return false;
1671 }
1672 
1673 bool QgsMapLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage,
1674  const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1675 {
1676  Q_UNUSED( node )
1677  Q_UNUSED( doc )
1678  Q_UNUSED( errorMessage )
1679  Q_UNUSED( context )
1680  Q_UNUSED( categories )
1681  return false;
1682 }
1683 
1684 
1685 void QgsMapLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider,
1686  bool loadDefaultStyleFlag )
1687 {
1689 
1690  QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags();
1691  if ( loadDefaultStyleFlag )
1692  {
1694  }
1695 
1697  {
1699  }
1700  setDataSource( dataSource, baseName, provider, options, flags );
1701 }
1702 
1703 void QgsMapLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider,
1704  const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag )
1705 {
1706  QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags();
1707  if ( loadDefaultStyleFlag )
1708  {
1710  }
1711 
1713  {
1715  }
1716  setDataSource( dataSource, baseName, provider, options, flags );
1717 }
1718 
1719 void QgsMapLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider,
1720  const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
1721 {
1722 
1725  {
1727  }
1728  setDataSourcePrivate( dataSource, baseName, provider, options, flags );
1729  emit dataSourceChanged();
1730  emit dataChanged();
1731  triggerRepaint();
1732 }
1733 
1734 
1735 void QgsMapLayer::setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider,
1736  const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
1737 {
1738  Q_UNUSED( dataSource )
1739  Q_UNUSED( baseName )
1740  Q_UNUSED( provider )
1741  Q_UNUSED( options )
1742  Q_UNUSED( flags )
1743 }
1744 
1745 
1747 {
1748  return mProviderKey;
1749 }
1750 
1751 void QgsMapLayer::readCommonStyle( const QDomElement &layerElement, const QgsReadWriteContext &context,
1752  QgsMapLayer::StyleCategories categories )
1753 {
1754  if ( categories.testFlag( Symbology3D ) )
1755  {
1756  QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "3D Symbology" ) );
1757 
1758  QgsAbstract3DRenderer *r3D = nullptr;
1759  QDomElement renderer3DElem = layerElement.firstChildElement( QStringLiteral( "renderer-3d" ) );
1760  if ( !renderer3DElem.isNull() )
1761  {
1762  QString type3D = renderer3DElem.attribute( QStringLiteral( "type" ) );
1764  if ( meta3D )
1765  {
1766  r3D = meta3D->createRenderer( renderer3DElem, context );
1767  }
1768  }
1769  setRenderer3D( r3D );
1770  }
1771 
1772  if ( categories.testFlag( CustomProperties ) )
1773  {
1774  // read custom properties before passing reading further to a subclass, so that
1775  // the subclass can also read custom properties
1776  readCustomProperties( layerElement );
1777  }
1778 
1779  // use scale dependent visibility flag
1780  if ( categories.testFlag( Rendering ) )
1781  {
1782  setScaleBasedVisibility( layerElement.attribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ) ).toInt() == 1 );
1783  if ( layerElement.hasAttribute( QStringLiteral( "minimumScale" ) ) )
1784  {
1785  // older element, when scales were reversed
1786  setMaximumScale( layerElement.attribute( QStringLiteral( "minimumScale" ) ).toDouble() );
1787  setMinimumScale( layerElement.attribute( QStringLiteral( "maximumScale" ) ).toDouble() );
1788  }
1789  else
1790  {
1791  setMaximumScale( layerElement.attribute( QStringLiteral( "maxScale" ) ).toDouble() );
1792  setMinimumScale( layerElement.attribute( QStringLiteral( "minScale" ) ).toDouble() );
1793  }
1794  }
1795 
1796  if ( categories.testFlag( LayerConfiguration ) )
1797  {
1798  // flags
1799  QDomElement flagsElem = layerElement.firstChildElement( QStringLiteral( "flags" ) );
1800  LayerFlags flags = mFlags;
1801  auto enumMap = qgsEnumMap<QgsMapLayer::LayerFlag>();
1802  for ( auto it = enumMap.constBegin(); it != enumMap.constEnd(); ++it )
1803  {
1804  QDomNode flagNode = flagsElem.namedItem( it.value() );
1805  if ( flagNode.isNull() )
1806  continue;
1807  bool flagValue = flagNode.toElement().text() == "1" ? true : false;
1808  if ( flags.testFlag( it.key() ) && !flagValue )
1809  flags &= ~it.key();
1810  else if ( !flags.testFlag( it.key() ) && flagValue )
1811  flags |= it.key();
1812  }
1813  setFlags( flags );
1814  }
1815 
1816  if ( categories.testFlag( Temporal ) )
1817  {
1818  QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Temporal" ) );
1819 
1820  if ( QgsMapLayerTemporalProperties *properties = temporalProperties() )
1821  properties->readXml( layerElement.toElement(), context );
1822  }
1823 
1824  if ( categories.testFlag( Elevation ) )
1825  {
1826  QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Elevation" ) );
1827 
1829  properties->readXml( layerElement.toElement(), context );
1830  }
1831 
1832  if ( categories.testFlag( Notes ) )
1833  {
1834  const QDomElement notesElem = layerElement.firstChildElement( QStringLiteral( "userNotes" ) );
1835  if ( !notesElem.isNull() )
1836  {
1837  const QString notes = notesElem.attribute( QStringLiteral( "value" ) );
1838  QgsLayerNotesUtils::setLayerNotes( this, notes );
1839  }
1840  }
1841 }
1842 
1844 {
1845  return mUndoStack;
1846 }
1847 
1849 {
1850  return mUndoStackStyles;
1851 }
1852 
1854 {
1855  return mCustomProperties.keys();
1856 }
1857 
1858 void QgsMapLayer::setCustomProperty( const QString &key, const QVariant &value )
1859 {
1860  if ( !mCustomProperties.contains( key ) || mCustomProperties.value( key ) != value )
1861  {
1862  mCustomProperties.setValue( key, value );
1863  emit customPropertyChanged( key );
1864  }
1865 }
1866 
1868 {
1869  mCustomProperties = properties;
1870 }
1871 
1873 {
1874  return mCustomProperties;
1875 }
1876 
1877 QVariant QgsMapLayer::customProperty( const QString &value, const QVariant &defaultValue ) const
1878 {
1879  return mCustomProperties.value( value, defaultValue );
1880 }
1881 
1882 void QgsMapLayer::removeCustomProperty( const QString &key )
1883 {
1884 
1885  if ( mCustomProperties.contains( key ) )
1886  {
1887  mCustomProperties.remove( key );
1888  emit customPropertyChanged( key );
1889  }
1890 }
1891 
1893 {
1894  return mError;
1895 }
1896 
1897 
1898 
1900 {
1901  return false;
1902 }
1903 
1905 {
1906  return true;
1907 }
1908 
1910 {
1911  // invalid layers are temporary? -- who knows?!
1912  if ( !isValid() )
1913  return false;
1914 
1915  if ( mProviderKey == QLatin1String( "memory" ) )
1916  return true;
1917 
1918  const QVariantMap sourceParts = QgsProviderRegistry::instance()->decodeUri( mProviderKey, mDataSource );
1919  const QString path = sourceParts.value( QStringLiteral( "path" ) ).toString();
1920  if ( path.isEmpty() )
1921  return false;
1922 
1923  // check if layer path is inside one of the standard temporary file locations for this platform
1924  const QStringList tempPaths = QStandardPaths::standardLocations( QStandardPaths::TempLocation );
1925  for ( const QString &tempPath : tempPaths )
1926  {
1927  if ( path.startsWith( tempPath ) )
1928  return true;
1929  }
1930 
1931  return false;
1932 }
1933 
1934 void QgsMapLayer::setValid( bool valid )
1935 {
1936  if ( mValid == valid )
1937  return;
1938 
1939  mValid = valid;
1940  emit isValidChanged();
1941 }
1942 
1944 {
1945  if ( legend == mLegend )
1946  return;
1947 
1948  delete mLegend;
1949  mLegend = legend;
1950 
1951  if ( mLegend )
1952  {
1953  mLegend->setParent( this );
1954  connect( mLegend, &QgsMapLayerLegend::itemsChanged, this, &QgsMapLayer::legendChanged );
1955  }
1956 
1957  emit legendChanged();
1958 }
1959 
1961 {
1962  return mLegend;
1963 }
1964 
1966 {
1967  return mStyleManager;
1968 }
1969 
1971 {
1972  if ( renderer == m3DRenderer )
1973  return;
1974 
1975  delete m3DRenderer;
1976  m3DRenderer = renderer;
1977  emit renderer3DChanged();
1978  trigger3DUpdate();
1979 }
1980 
1982 {
1983  return m3DRenderer;
1984 }
1985 
1986 void QgsMapLayer::triggerRepaint( bool deferredUpdate )
1987 {
1988  if ( mRepaintRequestedFired )
1989  return;
1990 
1991  mRepaintRequestedFired = true;
1992  emit repaintRequested( deferredUpdate );
1993  mRepaintRequestedFired = false;
1994 }
1995 
1997 {
1998  emit request3DUpdate();
1999 }
2000 
2002 {
2003  mMetadata = metadata;
2004 // mMetadata.saveToLayer( this );
2005  emit metadataChanged();
2006 }
2007 
2009 {
2010  return QString();
2011 }
2012 
2013 QDateTime QgsMapLayer::timestamp() const
2014 {
2015  return QDateTime();
2016 }
2017 
2019 {
2020  if ( !mBlockStyleChangedSignal )
2021  emit styleChanged();
2022 }
2023 
2025 {
2026  updateExtent( extent );
2027 }
2028 
2029 bool QgsMapLayer::isReadOnly() const
2030 {
2031  return true;
2032 }
2033 
2035 {
2036  return mOriginalXmlProperties;
2037 }
2038 
2039 void QgsMapLayer::setOriginalXmlProperties( const QString &originalXmlProperties )
2040 {
2041  mOriginalXmlProperties = originalXmlProperties;
2042 }
2043 
2044 QString QgsMapLayer::generateId( const QString &layerName )
2045 {
2046  // Generate the unique ID of this layer
2047  QString uuid = QUuid::createUuid().toString();
2048  // trim { } from uuid
2049  QString id = layerName + '_' + uuid.mid( 1, uuid.length() - 2 );
2050  // Tidy the ID up to avoid characters that may cause problems
2051  // elsewhere (e.g in some parts of XML). Replaces every non-word
2052  // character (word characters are the alphabet, numbers and
2053  // underscore) with an underscore.
2054  // Note that the first backslash in the regular expression is
2055  // there for the compiler, so the pattern is actually \W
2056  id.replace( QRegExp( "[\\W]" ), QStringLiteral( "_" ) );
2057  return id;
2058 }
2059 
2061 {
2062  return true;
2063 }
2064 
2065 void QgsMapLayer::setProviderType( const QString &providerType )
2066 {
2068 }
2069 
2070 QSet<QgsMapLayerDependency> QgsMapLayer::dependencies() const
2071 {
2072  return mDependencies;
2073 }
2074 
2075 bool QgsMapLayer::setDependencies( const QSet<QgsMapLayerDependency> &oDeps )
2076 {
2077  QSet<QgsMapLayerDependency> deps;
2078  const auto constODeps = oDeps;
2079  for ( const QgsMapLayerDependency &dep : constODeps )
2080  {
2081  if ( dep.origin() == QgsMapLayerDependency::FromUser )
2082  deps << dep;
2083  }
2084 
2085  mDependencies = deps;
2086  emit dependenciesChanged();
2087  return true;
2088 }
2089 
2091 {
2092  QgsDataProvider *lDataProvider = dataProvider();
2093 
2094  if ( !lDataProvider )
2095  return;
2096 
2097  if ( enabled && !isRefreshOnNotifyEnabled() )
2098  {
2099  lDataProvider->setListening( enabled );
2100  connect( lDataProvider, &QgsDataProvider::notify, this, &QgsMapLayer::onNotified );
2101  }
2102  else if ( !enabled && isRefreshOnNotifyEnabled() )
2103  {
2104  // we don't want to disable provider listening because someone else could need it (e.g. actions)
2105  disconnect( lDataProvider, &QgsDataProvider::notify, this, &QgsMapLayer::onNotified );
2106  }
2107  mIsRefreshOnNofifyEnabled = enabled;
2108 }
2109 
2111 {
2112  if ( QgsMapLayerStore *store = qobject_cast<QgsMapLayerStore *>( parent() ) )
2113  {
2114  return qobject_cast<QgsProject *>( store->parent() );
2115  }
2116  return nullptr;
2117 }
2118 
2119 void QgsMapLayer::onNotified( const QString &message )
2120 {
2121  if ( refreshOnNotifyMessage().isEmpty() || refreshOnNotifyMessage() == message )
2122  {
2123  triggerRepaint();
2124  emit dataChanged();
2125  }
2126 }
2127 
2128 QgsRectangle QgsMapLayer::wgs84Extent( bool forceRecalculate ) const
2129 {
2131 
2132  if ( ! forceRecalculate && ! mWgs84Extent.isNull() )
2133  {
2134  wgs84Extent = mWgs84Extent;
2135  }
2136  else if ( ! mExtent.isNull() )
2137  {
2139  try
2140  {
2141  wgs84Extent = transformer.transformBoundingBox( mExtent );
2142  }
2143  catch ( const QgsCsException &cse )
2144  {
2145  QgsMessageLog::logMessage( tr( "Error transforming extent: %1" ).arg( cse.what() ) );
2147  }
2148  }
2149  return wgs84Extent;
2150 }
2151 
2152 void QgsMapLayer::updateExtent( const QgsRectangle &extent ) const
2153 {
2154  if ( extent == mExtent )
2155  return;
2156 
2157  mExtent = extent;
2158 
2159  // do not update the wgs84 extent if we trust layer metadata
2160  if ( mReadFlags & QgsMapLayer::ReadFlag::FlagTrustLayerMetadata )
2161  return;
2162 
2163  mWgs84Extent = wgs84Extent( true );
2164 }
2165 
2167 {
2168  // do not update the wgs84 extent if we trust layer metadata
2169  if ( mReadFlags & QgsMapLayer::ReadFlag::FlagTrustLayerMetadata )
2170  return;
2171 
2172  mWgs84Extent = QgsRectangle();
2173 }
2174 
2176 {
2177  QString metadata = QStringLiteral( "<h1>" ) + tr( "Coordinate Reference System (CRS)" ) + QStringLiteral( "</h1>\n<hr>\n" );
2178  metadata += QLatin1String( "<table class=\"list-view\">\n" );
2179 
2180  // Identifier
2182  if ( !c.isValid() )
2183  metadata += QStringLiteral( "<tr><td colspan=\"2\" class=\"highlight\">" ) + tr( "Unknown" ) + QStringLiteral( "</td></tr>\n" );
2184  else
2185  {
2186  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Name" ) + QStringLiteral( "</td><td>" ) + c.userFriendlyIdentifier( QgsCoordinateReferenceSystem::FullString ) + QStringLiteral( "</td></tr>\n" );
2187 
2188  // map units
2189  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Units" ) + QStringLiteral( "</td><td>" )
2190  + ( c.isGeographic() ? tr( "Geographic (uses latitude and longitude for coordinates)" ) : QgsUnitTypes::toString( c.mapUnits() ) )
2191  + QStringLiteral( "</td></tr>\n" );
2192 
2193 
2194  // operation
2195  const QgsProjOperation operation = c.operation();
2196  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Method" ) + QStringLiteral( "</td><td>" ) + operation.description() + QStringLiteral( "</td></tr>\n" );
2197 
2198  // celestial body
2199  try
2200  {
2201  const QString celestialBody = c.celestialBodyName();
2202  if ( !celestialBody.isEmpty() )
2203  {
2204  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Celestial body" ) + QStringLiteral( "</td><td>" ) + celestialBody + QStringLiteral( "</td></tr>\n" );
2205  }
2206  }
2207  catch ( QgsNotSupportedException & )
2208  {
2209 
2210  }
2211 
2212  QString accuracyString;
2213  // dynamic crs with no epoch?
2214  if ( c.isDynamic() && std::isnan( c.coordinateEpoch() ) )
2215  {
2216  accuracyString = tr( "Based on a dynamic CRS, but no coordinate epoch is set. Coordinates are ambiguous and of limited accuracy." );
2217  }
2218 
2219  // based on datum ensemble?
2220  try
2221  {
2222  const QgsDatumEnsemble ensemble = c.datumEnsemble();
2223  if ( ensemble.isValid() )
2224  {
2225  QString id;
2226  if ( !ensemble.code().isEmpty() )
2227  id = QStringLiteral( "<i>%1</i> (%2:%3)" ).arg( ensemble.name(), ensemble.authority(), ensemble.code() );
2228  else
2229  id = QStringLiteral( "<i>%</i>”" ).arg( ensemble.name() );
2230 
2231  if ( ensemble.accuracy() > 0 )
2232  {
2233  accuracyString = tr( "Based on %1, which has a limited accuracy of <b>at best %2 meters</b>." ).arg( id ).arg( ensemble.accuracy() );
2234  }
2235  else
2236  {
2237  accuracyString = tr( "Based on %1, which has a limited accuracy." ).arg( id );
2238  }
2239  }
2240  }
2241  catch ( QgsNotSupportedException & )
2242  {
2243 
2244  }
2245 
2246  if ( !accuracyString.isEmpty() )
2247  {
2248  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Accuracy" ) + QStringLiteral( "</td><td>" ) + accuracyString + QStringLiteral( "</td></tr>\n" );
2249  }
2250 
2251  // static/dynamic
2252  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Reference" ) + QStringLiteral( "</td><td>%1</td></tr>\n" ).arg( c.isDynamic() ? tr( "Dynamic (relies on a datum which is not plate-fixed)" ) : tr( "Static (relies on a datum which is plate-fixed)" ) );
2253 
2254  // coordinate epoch
2255  if ( !std::isnan( c.coordinateEpoch() ) )
2256  {
2257  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Coordinate epoch" ) + QStringLiteral( "</td><td>%1</td></tr>\n" ).arg( c.coordinateEpoch() );
2258  }
2259  }
2260 
2261  metadata += QLatin1String( "</table>\n<br><br>\n" );
2262  return metadata;
2263 }
static QString version()
Version string.
Definition: qgis.cpp:285
static const double SCALE_PRECISION
Fudge factor used to compare two scales.
Definition: qgis.h:395
Base metadata class for 3D renderers.
virtual QgsAbstract3DRenderer * createRenderer(QDomElement &elem, const QgsReadWriteContext &context)=0
Returns new instance of the renderer given the DOM element.
Qgs3DRendererAbstractMetadata * rendererMetadata(const QString &type) const
Returns metadata for a 3D renderer type (may be used to create a new instance of the type)
Base class for all renderers that may to participate in 3D view.
virtual QString type() const =0
Returns unique identifier of the renderer class (used to identify subclass)
virtual void writeXml(QDomElement &elem, const QgsReadWriteContext &context) const =0
Writes renderer's properties to given XML element.
virtual void resolveReferences(const QgsProject &project)
Resolves references to other objects - second phase of loading - after readXml()
static QString pkgDataPath()
Returns the common root path of all application data directories.
static QString qgisSettingsDirPath()
Returns the path to the settings directory in user's home dir.
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
static Qgs3DRendererRegistry * renderer3DRegistry()
Returns registry of available 3D renderers.
bool setMasterPassword(bool verify=false)
Main call to initially set or continually check master password is set.
This class represents a coordinate reference system (CRS).
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
void validate()
Perform some validation on this CRS.
static CUSTOM_CRS_VALIDATION customCrsValidation()
Gets custom function.
bool readXml(const QDomNode &node)
Restores state from the given DOM node.
static void setCustomCrsValidation(CUSTOM_CRS_VALIDATION f)
Sets custom function to force valid CRS.
void setValidationHint(const QString &html)
Set user hint for validation.
@ FullString
Full definition – possibly a very lengthy string, e.g. with no truncation of custom WKT definitions.
bool writeXml(QDomNode &node, QDomDocument &doc) const
Stores state to the given Dom node in the given document.
Contains information about the context in which a coordinate transform is executed.
Class for doing transforms between two map coordinate systems.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:66
Abstract base class for spatial data provider implementations.
@ FlagLoadDefaultStyle
Reset the layer's style to the default for the datasource.
@ FlagTrustDataSource
Trust datasource config (primary key unicity, geometry type and srid, etc). Improves provider load ti...
QgsCoordinateTransformContext transformContext() const
Returns data provider coordinate transform context.
virtual void setListening(bool isListening)
Set whether the provider will listen to datasource notifications If set, the provider will issue noti...
void notify(const QString &msg)
Emitted when the datasource issues a notification.
static QString removePassword(const QString &aUri)
Removes the password element from a URI.
Contains information about a datum ensemble.
Definition: qgsdatums.h:95
QString code() const
Identification code, e.g.
Definition: qgsdatums.h:122
QString authority() const
Authority name, e.g.
Definition: qgsdatums.h:117
bool isValid() const
Returns true if the datum ensemble is a valid object, or false if it is a null/invalid object.
Definition: qgsdatums.h:102
QString name() const
Display name of datum ensemble.
Definition: qgsdatums.h:107
double accuracy() const
Positional accuracy (in meters).
Definition: qgsdatums.h:112
QgsError is container for error messages (report).
Definition: qgserror.h:81
QString what() const
Definition: qgsexception.h:48
A structured metadata store for a map layer.
bool readMetadataXml(const QDomElement &metadataElement) override
Sets state from DOM document.
bool writeMetadataXml(QDomElement &metadataElement, QDomDocument &document) const override
Stores state in a DOM node.
static void setLayerNotes(QgsMapLayer *layer, const QString &notes)
Sets the notes for the specified layer, where notes is a HTML formatted string.
static bool layerHasNotes(const QgsMapLayer *layer)
Returns true if the specified layer has notes available.
static QString layerNotes(const QgsMapLayer *layer)
Returns the notes for the specified layer.
This class models dependencies with or between map layers.
Base class for storage of map layer elevation properties.
The QgsMapLayerLegend class is abstract interface for implementations of legends for one map layer.
void itemsChanged()
Emitted when existing items/nodes got invalid and should be replaced by new ones.
A storage object for map layers, in which the layers are owned by the store and have their lifetime b...
Management of styles for use with one map layer.
bool addStyle(const QString &name, const QgsMapLayerStyle &style)
Add a style with given name and data.
QStringList styles() const
Returns list of all defined style names.
void writeXml(QDomElement &mgrElement) const
Write configuration (for project saving)
void reset()
Reset the style manager to a basic state - with one default style which is set as current.
void readXml(const QDomElement &mgrElement)
Read configuration (for project loading)
Base class for storage of map layer temporal properties.
Base class for all map layer types.
Definition: qgsmaplayer.h:70
QString mKeywordList
Definition: qgsmaplayer.h:1675
void setShortName(const QString &shortName)
Sets the short name of the layer used by QGIS Server to identify the layer.
Definition: qgsmaplayer.h:265
bool importNamedMetadata(QDomDocument &document, QString &errorMessage)
Import the metadata of this layer from a QDomDocument.
QString name
Definition: qgsmaplayer.h:73
void readStyleManager(const QDomNode &layerNode)
Read style manager's configuration (if any). To be called by subclasses.
virtual bool writeSymbology(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const =0
Write the style for the layer into the docment provided.
QString legendUrlFormat() const
Returns the format for a URL based layer legend.
Definition: qgsmaplayer.h:1053
QgsRectangle wgs84Extent(bool forceRecalculate=false) const
Returns the WGS84 extent (EPSG:4326) of the layer according to ReadFlag::FlagTrustLayerMetadata.
void setRefreshOnNotifyEnabled(bool enabled)
Set whether provider notification is connected to triggerRepaint.
virtual bool isSpatial() const
Returns true if the layer is considered a spatial layer, ie it has some form of geometry associated w...
QgsAbstract3DRenderer * renderer3D() const
Returns 3D renderer associated with the layer.
virtual bool isTemporary() const
Returns true if the layer is considered a temporary layer.
virtual void exportNamedStyle(QDomDocument &doc, QString &errorMsg, const QgsReadWriteContext &context=QgsReadWriteContext(), QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) const
Export the properties of this layer as named style in a QDomDocument.
virtual bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified symbology visitor, causing it to visit all symbols associated with the layer.
void dependenciesChanged()
Emitted when dependencies are changed.
bool isInScaleRange(double scale) const
Tests whether the layer should be visible at the specified scale.
void legendChanged()
Signal emitted when legend of the layer has changed.
void writeStyleManager(QDomNode &layerNode, QDomDocument &doc) const
Write style manager's configuration (if exists). To be called by subclasses.
QgsMapLayerLegend * legend() const
Can be nullptr.
virtual bool importNamedStyle(QDomDocument &doc, QString &errorMsg, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories)
Import the properties of this layer from a QDomDocument.
void setAbstract(const QString &abstract)
Sets the abstract of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:295
void metadataChanged()
Emitted when the layer's metadata is changed.
virtual QgsRectangle extent() const
Returns the extent of the layer.
virtual QString saveSldStyle(const QString &uri, bool &resultFlag) const
Saves the properties of this layer to an SLD format file.
QString source() const
Returns the source for the layer.
void setLegendUrl(const QString &legendUrl)
Sets the URL for the layer's legend.
Definition: qgsmaplayer.h:1038
virtual bool setDependencies(const QSet< QgsMapLayerDependency > &layers)
Sets the list of dependencies.
void request3DUpdate()
Signal emitted when a layer requires an update in any 3D maps.
Q_INVOKABLE QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
QgsError mError
Error.
Definition: qgsmaplayer.h:1695
int mBlockStyleChangedSignal
If non-zero, the styleChanged signal should not be emitted.
Definition: qgsmaplayer.h:1737
QString providerType() const
Returns the provider type (provider key) for this layer.
void removeCustomProperty(const QString &key)
Remove a custom property from layer.
void setBlendMode(QPainter::CompositionMode blendMode)
Set the blending mode used for rendering a layer.
QgsMapLayerType type
Definition: qgsmaplayer.h:77
void configChanged()
Emitted whenever the configuration is changed.
void trigger3DUpdate()
Will advise any 3D maps that this layer requires to be updated in the scene.
void autoRefreshIntervalChanged(int interval)
Emitted when the auto refresh interval changes.
void setMinimumScale(double scale)
Sets the minimum map scale (i.e.
virtual QSet< QgsMapLayerDependency > dependencies() const
Gets the list of dependencies.
void setCustomProperties(const QgsObjectCustomProperties &properties)
Set custom properties for layer.
virtual QString encodedSource(const QString &source, const QgsReadWriteContext &context) const
Called by writeLayerXML(), used by derived classes to encode provider's specific data source to proje...
QgsMapLayer(QgsMapLayerType type=QgsMapLayerType::VectorLayer, const QString &name=QString(), const QString &source=QString())
Constructor for QgsMapLayer.
Definition: qgsmaplayer.cpp:80
QString publicSource() const
Gets a version of the internal layer definition that has sensitive bits removed (for example,...
QgsMapLayer::LayerFlags flags() const
Returns the flags for this layer.
virtual void setSubLayerVisibility(const QString &name, bool visible)
Set the visibility of the given sublayer name.
void isValidChanged()
Emitted when the validity of this layer changed.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:76
bool loadNamedMetadataFromDatabase(const QString &db, const QString &uri, QString &qmd)
Retrieve a named metadata for this layer from a sqlite database.
virtual bool readXml(const QDomNode &layer_node, QgsReadWriteContext &context)
Called by readLayerXML(), used by children to read state specific to them from project files.
QString attribution() const
Returns the attribution of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:377
void setOriginalXmlProperties(const QString &originalXmlProperties)
Sets the original XML properties for the layer to originalXmlProperties.
void writeCustomProperties(QDomNode &layerNode, QDomDocument &doc) const
Write custom properties to project file.
QString mRefreshOnNofifyMessage
Definition: qgsmaplayer.h:1708
QString mLegendUrl
WMS legend.
Definition: qgsmaplayer.h:1691
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
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...
QString mLayerName
Name of the layer - used for display.
Definition: qgsmaplayer.h:1668
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 ...
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.
bool hasAutoRefreshEnabled() const
Returns true if auto refresh is enabled for the layer.
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
QString crsHtmlMetadata() const
Returns a HTML fragment containing the layer's CRS metadata, for use in the htmlMetadata() method.
void setAttributionUrl(const QString &attribUrl)
Sets the attribution URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:386
void setAutoRefreshEnabled(bool enabled)
Sets whether auto refresh is enabled for the layer.
void setMaximumScale(double scale)
Sets the maximum map scale (i.e.
QgsLayerMetadata metadata
Definition: qgsmaplayer.h:75
static QString formatLayerName(const QString &name)
A convenience function to capitalize and format a layer name.
void renderer3DChanged()
Signal emitted when 3D renderer associated with the layer has changed.
QString originalXmlProperties() const
Returns the XML properties of the original layer as they were when the layer was first read from the ...
QString dataUrlFormat() const
Returns the DataUrl format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:357
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
QString mTitle
Definition: qgsmaplayer.h:1671
void setDataUrl(const QString &dataUrl)
Sets the DataUrl of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:330
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 ...
virtual void setOpacity(double opacity)
Sets the opacity for the layer, where opacity is a value between 0 (totally transparent) and 1....
void setKeywordList(const QString &keywords)
Sets the keyword list of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:311
void setAttribution(const QString &attrib)
Sets the attribution of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:368
void setFlags(QgsMapLayer::LayerFlags flags)
Returns the flags for this layer.
bool isRefreshOnNotifyEnabled() const
Returns true if the refresh on provider nofification is enabled.
Definition: qgsmaplayer.h:1215
QString shortName() const
Returns the short name of the layer used by QGIS Server to identify the layer.
QSet< QgsMapLayerDependency > mDependencies
List of layers that may modify this layer on modification.
Definition: qgsmaplayer.h:1698
void readCustomProperties(const QDomNode &layerNode, const QString &keyStartsWith=QString())
Read custom properties from project file.
virtual QString loadSldStyle(const QString &uri, bool &resultFlag)
Attempts to style the layer using the formatting from an SLD type file.
virtual void setMetadata(const QgsLayerMetadata &metadata)
Sets the layer's metadata store.
virtual bool readStyle(const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories)
Read the style for the current layer from the DOM node supplied.
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 ...
void setDataUrlFormat(const QString &dataUrlFormat)
Sets the DataUrl format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:348
QString mLegendUrlFormat
Definition: qgsmaplayer.h:1692
Q_INVOKABLE void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for layer.
QString mProviderKey
Data provider key (name of the data provider)
Definition: qgsmaplayer.h:1711
QString mMetadataUrlType
Definition: qgsmaplayer.h:1687
QgsCoordinateTransformContext transformContext() const
Returns the layer data provider coordinate transform context or a default transform context if the la...
void styleChanged()
Signal emitted whenever a change affects the layer's style.
virtual bool isEditable() const
Returns true if the layer can be edited.
QUndoStack * undoStack()
Returns pointer to layer's undo stack.
QString title() const
Returns the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:287
void crsChanged()
Emit a signal that layer's CRS has been reset.
virtual QgsError error() const
Gets current status error.
bool writeLayerXml(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context) const
Stores state in DOM node.
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...
QString mAttributionUrl
Definition: qgsmaplayer.h:1683
void setScaleBasedVisibility(bool enabled)
Sets whether scale based visibility is enabled for the layer.
void dataSourceChanged()
Emitted whenever the layer's data source has been changed.
QString dataUrl() const
Returns the DataUrl of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:339
bool readLayerXml(const QDomElement &layerElement, QgsReadWriteContext &context, QgsMapLayer::ReadFlags flags=QgsMapLayer::ReadFlags())
Sets state from DOM document.
bool hasScaleBasedVisibility() const
Returns whether scale based visibility is enabled for the layer.
virtual QString loadNamedStyle(const QString &uri, bool &resultFlag, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories)
Retrieve a named style for this layer if one exists (either as a .qml file on disk or as a record in ...
virtual QgsMapLayer * clone() const =0
Returns a new instance equivalent to this one except for the id which is still unique.
QString metadataUrlFormat() const
Returns the metadata format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:451
void setRefreshOnNofifyMessage(const QString &message)
Set the notification message that triggers repaint If refresh on notification is enabled,...
Definition: qgsmaplayer.h:1348
static QString generateId(const QString &layerName)
Generates an unique identifier for this layer, the generate ID is prefixed by layerName.
void opacityChanged(double opacity)
Emitted when the layer's opacity is changed, where opacity is a value between 0 (transparent) and 1 (...
void emitStyleChanged()
Triggers an emission of the styleChanged() signal.
QString mShortName
Definition: qgsmaplayer.h:1670
QUndoStack * undoStackStyles()
Returns pointer to layer's style undo stack.
void dataChanged()
Data of layer changed.
virtual QStringList subLayers() const
Returns the sublayers of this layer.
QString mMetadataUrlFormat
Definition: qgsmaplayer.h:1688
virtual QString htmlMetadata() const
Obtain a formatted HTML string containing assorted metadata for this layer.
void setMetadataUrlFormat(const QString &metaUrlFormat)
Sets the metadata format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:442
virtual bool loadNamedStyleFromDatabase(const QString &db, const QString &uri, QString &qml)
Retrieve a named style for this layer from a sqlite database.
static QString extensionPropertyType(PropertyType type)
Returns the extension of a Property.
Definition: qgsmaplayer.cpp:67
void blendModeChanged(QPainter::CompositionMode blendMode)
Signal emitted when the blend mode is changed, through QgsMapLayer::setBlendMode()
void setName(const QString &name)
Set the display name of the layer.
void setAutoRefreshInterval(int interval)
Sets the auto refresh interval (in milliseconds) for the layer.
virtual bool readSymbology(const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories)=0
Read the symbology for the current layer from the DOM node supplied.
QString metadataUrl() const
Returns the metadata URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:415
virtual void setExtent(const QgsRectangle &rect)
Sets the extent.
virtual void resolveReferences(QgsProject *project)
Resolve references to other layers (kept as layer IDs after reading XML) into layer objects.
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
Definition: qgsmaplayer.h:78
QString mMetadataUrl
MetadataUrl of the layer.
Definition: qgsmaplayer.h:1686
QString mDataSource
Data source description string, varies by layer type.
Definition: qgsmaplayer.h:1665
QString refreshOnNotifyMessage() const
Returns the message that should be notified by the provider to triggerRepaint.
Definition: qgsmaplayer.h:1208
virtual bool readSld(const QDomNode &node, QString &errorMessage)
Definition: qgsmaplayer.h:916
virtual 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...
@ FlagReadExtentFromXml
Read extent from xml and skip get extent from provider.
Definition: qgsmaplayer.h:582
@ FlagTrustLayerMetadata
Trust layer metadata. Improves layer load time by skipping expensive checks like primary key unicity,...
Definition: qgsmaplayer.h:581
void setValid(bool valid)
Sets whether layer is valid or not.
QString attributionUrl() const
Returns the attribution URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:395
void readCommonStyle(const QDomElement &layerElement, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories)
Read style data common to all layer types.
QString mAbstract
Description of the layer.
Definition: qgsmaplayer.h:1674
void customPropertyChanged(const QString &key)
Emitted when a custom property of the layer has been changed or removed.
QgsMapLayer::ReadFlags mReadFlags
Read flags. It's up to the subclass to respect these when restoring state from XML.
Definition: qgsmaplayer.h:1716
void setDataSource(const QString &dataSource, const QString &baseName, const QString &provider, bool loadDefaultStyleFlag=false)
Updates the data source of the layer.
double minimumScale() const
Returns the minimum map scale (i.e.
QgsMapLayerStyleManager * styleManager() const
Gets access to the layer's style manager.
QString legendUrl() const
Returns the URL for the layer's legend.
Definition: qgsmaplayer.h:1043
QString mDataUrlFormat
Definition: qgsmaplayer.h:1679
void flagsChanged()
Emitted when layer's flags have been modified.
void repaintRequested(bool deferredUpdate=false)
By emitting this signal the layer tells that either appearance or content have been changed and any v...
void setLegendUrlFormat(const QString &legendUrlFormat)
Sets the format for a URL based layer legend.
Definition: qgsmaplayer.h:1048
void exportNamedMetadata(QDomDocument &doc, QString &errorMsg) const
Export the current metadata of this layer as named metadata in a QDomDocument.
virtual QString saveNamedStyle(const QString &uri, bool &resultFlag, StyleCategories categories=AllStyleCategories)
Save the properties of this layer as a named style (either as a .qml file on disk or as a record in t...
virtual void exportSldStyle(QDomDocument &doc, QString &errorMsg) const
Export the properties of this layer as SLD style in a QDomDocument.
void beforeResolveReferences(QgsProject *project)
Emitted when all layers are loaded and references can be resolved, just before the references of this...
void setMetadataUrl(const QString &metaUrl)
Sets the metadata URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:406
Q_INVOKABLE QStringList customPropertyKeys() const
Returns list of all keys within custom properties.
QgsProject * project() const
Returns the parent project if this map layer is added to a project.
void setMetadataUrlType(const QString &metaUrlType)
Set the metadata type of the layer used by QGIS Server in GetCapabilities request MetadataUrlType ind...
Definition: qgsmaplayer.h:424
void setLegend(QgsMapLayerLegend *legend)
Assign a legend controller to the map layer.
virtual QgsMapLayerElevationProperties * elevationProperties()
Returns the layer's elevation properties.
Definition: qgsmaplayer.h:1265
double opacity
Definition: qgsmaplayer.h:79
virtual QString decodedSource(const QString &source, const QString &dataProvider, const QgsReadWriteContext &context) const
Called by readLayerXML(), used by derived classes to decode provider's specific data source from proj...
void nameChanged()
Emitted when the name has been changed.
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...
int autoRefreshInterval
Definition: qgsmaplayer.h:74
virtual bool writeStyle(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const
Write just the symbology information for the layer into the document.
bool mIsRefreshOnNofifyEnabled
Definition: qgsmaplayer.h:1707
QString mDataUrl
DataUrl of the layer.
Definition: qgsmaplayer.h:1678
virtual Q_INVOKABLE QgsDataProvider * dataProvider()
Returns the layer's data provider, it may be nullptr.
double mLayerOpacity
Layer opacity.
Definition: qgsmaplayer.h:1730
bool mValid
Indicates if the layer is valid and can be drawn.
Definition: qgsmaplayer.h:1662
@ AllStyleCategories
Definition: qgsmaplayer.h:172
@ LayerConfiguration
General configuration: identifiable, removable, searchable, display expression, read-only.
Definition: qgsmaplayer.h:154
@ Symbology
Symbology.
Definition: qgsmaplayer.h:155
@ Notes
Layer user notes (since QGIS 3.20)
Definition: qgsmaplayer.h:171
@ Temporal
Temporal properties (since QGIS 3.14)
Definition: qgsmaplayer.h:168
@ Rendering
Rendering: scale visibility, simplify method, opacity.
Definition: qgsmaplayer.h:164
@ Elevation
Elevation settings (since QGIS 3.18)
Definition: qgsmaplayer.h:170
@ Symbology3D
3D symbology
Definition: qgsmaplayer.h:156
@ CustomProperties
Custom properties (by plugins for instance)
Definition: qgsmaplayer.h:165
virtual QDateTime timestamp() const
Time stamp of data source in the moment when data/metadata were loaded by provider.
void setProviderType(const QString &providerType)
Sets the providerType (provider key)
virtual QgsMapLayerTemporalProperties * temporalProperties()
Returns the layer's temporal properties.
Definition: qgsmaplayer.h:1258
void setRenderer3D(QgsAbstract3DRenderer *renderer)
Sets 3D renderer for the layer.
QString mAttribution
Attribution of the layer.
Definition: qgsmaplayer.h:1682
~QgsMapLayer() override
Definition: qgsmaplayer.cpp:97
const QgsObjectCustomProperties & customProperties() const
Read all custom properties from layer.
QString metadataUrlType() const
Returns the metadata type of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:433
void writeCommonStyle(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const
Write style data common to all layer types.
double maximumScale() const
Returns the maximum map scale (i.e.
QString keywordList() const
Returns the keyword list of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:319
virtual void setLayerOrder(const QStringList &layers)
Reorders the previously selected sublayers of this layer from bottom to top.
void invalidateWgs84Extent()
Invalidates the WGS84 extent.
void setTitle(const QString &title)
Sets the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:279
PropertyType
Maplayer has a style and a metadata property.
Definition: qgsmaplayer.h:127
bool mShouldValidateCrs
true if the layer's CRS should be validated and invalid CRSes are not permitted.
Definition: qgsmaplayer.h:1723
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Custom exception class which is raised when an operation is not supported.
Definition: qgsexception.h:118
Simple key-value store (keys = strings, values = variants) that supports loading/saving to/from XML i...
void setValue(const QString &key, const QVariant &value)
Add an entry to the store with the specified key.
QStringList keys() const
Returns a list of all stored keys.
void writeXml(QDomNode &parentNode, QDomDocument &doc) const
Writes the store contents to an XML node.
void remove(const QString &key)
Removes a key (entry) from the store.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
Returns the value for the given key.
void readXml(const QDomNode &parentNode, const QString &keyStartsWith=QString())
Read store contents from an XML node.
bool contains(const QString &key) const
Returns true if the properties contains a key with the specified name.
Contains information about a PROJ operation.
QString description() const
Description.
Class to convert from older project file versions to newer.
bool updateRevision(const QgsProjectVersion &version)
virtual QString translate(const QString &context, const QString &sourceText, const char *disambiguation=nullptr, int n=-1) const =0
The derived translate() translates with QTranslator and qm file the sourceText.
A class to describe the version of a project.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:99
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:467
QString baseName() const
Returns the base name of the project file without the path and without extension - derived from fileN...
Definition: qgsproject.cpp:709
QString absoluteFilePath() const
Returns full absolute path to the project file if the project is stored in a file system - derived fr...
Definition: qgsproject.cpp:698
Holds data provider key, description, and associated shared library file or function pointer informat...
@ SaveLayerMetadata
Indicates that the provider supports saving native layer metadata (since QGIS 3.20)
QVariantMap decodeUri(const QString &providerKey, const QString &uri)
Breaks a provider data source URI into its component paths (e.g.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
bool saveLayerMetadata(const QString &providerKey, const QString &uri, const QgsLayerMetadata &metadata, QString &errorMessage) SIP_THROW(QgsNotSupportedException)
Saves metadata to the layer corresponding to the specified uri.
Represents a raster layer.
bool writeSld(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QVariantMap &props=QVariantMap()) const
Writes the symbology of the layer into the document provided in SLD 1.0.0 format.
Allows entering a context category and takes care of leaving this category on deletion of the class.
The class is used as a container of context for various read/write operations on other objects.
MAYBE_UNUSED NODISCARD QgsReadWriteContextCategoryPopper enterCategory(const QString &category, const QString &details=QString()) const
Push a category to the stack.
const QgsProjectTranslator * projectTranslator() const
Returns the project translator.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:479
static QString capitalize(const QString &string, Capitalization capitalization)
Converts a string by applying capitalization rules to the string.
@ ForceFirstLetterToCapital
Convert just the first letter of each word to uppercase, leave the rest untouched.
An interface for classes which can visit style entity (e.g.
static Q_INVOKABLE QString toString(QgsUnitTypes::DistanceUnit unit)
Returns a translated string representing a distance unit.
Represents a vector layer which manages a vector based data sets.
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
bool writeSld(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QVariantMap &props=QVariantMap()) const
Writes the symbology of the layer into the document provided in SLD 1.1 format.
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:141
static T readFlagAttribute(const QDomElement &element, const QString &attributeName, T defaultValue)
Read a flag value from an attribute of the element.
Definition: qgsxmlutils.h:99
static QDomElement writeRectangle(const QgsRectangle &rect, QDomDocument &doc, const QString &elementName=QStringLiteral("extent"))
Encodes a rectangle to a DOM element.
Definition: qgsxmlutils.cpp:81
static QgsRectangle readRectangle(const QDomElement &element)
Definition: qgsxmlutils.cpp:39
Unique pointer for sqlite3 databases, which automatically closes the database when the pointer goes o...
sqlite3_statement_unique_ptr prepare(const QString &sql, int &resultCode) const
Prepares a sql statement, returning the result.
int open(const QString &path)
Opens the database at the specified file path.
int open_v2(const QString &path, int flags, const char *zVfs)
Opens the database at the specified file path.
Unique pointer for sqlite3 prepared statements, which automatically finalizes the statement when the ...
QgsMapLayerType
Types of layers that can be added to a map.
Definition: qgis.h:46
@ AnnotationLayer
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:598
CONSTLATIN1STRING geoEpsgCrsAuthId()
Geographic coord sys from EPSG authority.
Definition: qgis.h:992
void(* CUSTOM_CRS_VALIDATION)(QgsCoordinateReferenceSystem &)
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
Setting options for creating vector data providers.