QGIS API Documentation  3.21.0-Master (56b4176581)
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 "qgssqliteutils.h"
20 #include "qgs3drendererregistry.h"
21 #include "qgsabstract3drenderer.h"
22 #include "qgsapplication.h"
24 #include "qgsdatasourceuri.h"
25 #include "qgsfileutils.h"
26 #include "qgslogger.h"
27 #include "qgsauthmanager.h"
28 #include "qgsmaplayer.h"
29 #include "qgsmaplayerlegend.h"
31 #include "qgsmeshlayer.h"
32 #include "qgspathresolver.h"
34 #include "qgsproject.h"
35 #include "qgsproviderregistry.h"
36 #include "qgsrasterlayer.h"
37 #include "qgsreadwritecontext.h"
38 #include "qgsrectangle.h"
39 #include "qgsvectorlayer.h"
40 #include "qgsvectordataprovider.h"
41 #include "qgsxmlutils.h"
42 #include "qgsstringutils.h"
43 #include "qgsmessagelog.h"
46 #include "qgsprovidermetadata.h"
47 #include "qgslayernotesutils.h"
48 #include "qgsdatums.h"
49 #include "qgsprojoperation.h"
50 
51 #include <QDir>
52 #include <QDomDocument>
53 #include <QDomElement>
54 #include <QDomImplementation>
55 #include <QDomNode>
56 #include <QFile>
57 #include <QFileInfo>
58 #include <QLocale>
59 #include <QTextStream>
60 #include <QUrl>
61 #include <QTimer>
62 #include <QStandardPaths>
63 #include <QUuid>
64 #include <QRegularExpression>
65 
66 #include <sqlite3.h>
67 
69 {
70  switch ( type )
71  {
72  case Metadata:
73  return QStringLiteral( ".qmd" );
74 
75  case Style:
76  return QStringLiteral( ".qml" );
77  }
78  return QString();
79 }
80 
82  const QString &lyrname,
83  const QString &source )
84  : mDataSource( source )
85  , mLayerName( lyrname )
86  , mLayerType( type )
87  , mServerProperties( std::make_unique<QgsMapLayerServerProperties>( this ) )
88  , mUndoStack( new QUndoStack( this ) )
89  , mUndoStackStyles( new QUndoStack( this ) )
90  , mStyleManager( new QgsMapLayerStyleManager( this ) )
91  , mRefreshTimer( new QTimer( this ) )
92 {
93  mID = generateId( lyrname );
94  connect( this, &QgsMapLayer::crsChanged, this, &QgsMapLayer::configChanged );
95  connect( this, &QgsMapLayer::nameChanged, this, &QgsMapLayer::configChanged );
96  connect( mRefreshTimer, &QTimer::timeout, this, [ = ] { triggerRepaint( true ); } );
97 }
98 
100 {
101  delete m3DRenderer;
102  delete mLegend;
103  delete mStyleManager;
104 }
105 
106 void QgsMapLayer::clone( QgsMapLayer *layer ) const
107 {
108  layer->setBlendMode( blendMode() );
109 
110  const auto constStyles = styleManager()->styles();
111  for ( const QString &s : constStyles )
112  {
113  layer->styleManager()->addStyle( s, styleManager()->style( s ) );
114  }
115 
116  layer->setName( name() );
117  layer->setShortName( shortName() );
118  layer->setExtent( extent() );
119  layer->setMaximumScale( maximumScale() );
120  layer->setMinimumScale( minimumScale() );
122  layer->setTitle( title() );
123  layer->setAbstract( abstract() );
124  layer->setKeywordList( keywordList() );
125  layer->setDataUrl( dataUrl() );
126  layer->setDataUrlFormat( dataUrlFormat() );
127  layer->setAttribution( attribution() );
128  layer->setAttributionUrl( attributionUrl() );
129  layer->setLegendUrl( legendUrl() );
131  layer->setDependencies( dependencies() );
133  layer->setCrs( crs() );
134  layer->setCustomProperties( mCustomProperties );
135  layer->setOpacity( mLayerOpacity );
136  layer->setMetadata( mMetadata );
137  layer->serverProperties()->copyTo( mServerProperties.get() );
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 Qgis::MapLayerProperties QgsMapLayer::properties() const
160 {
161  return Qgis::MapLayerProperties();
162 }
163 
164 QString QgsMapLayer::id() const
165 {
166  return mID;
167 }
168 
169 void QgsMapLayer::setName( const QString &name )
170 {
171  if ( name == mLayerName )
172  return;
173 
174  mLayerName = name;
175 
176  emit nameChanged();
177 }
178 
179 QString QgsMapLayer::name() const
180 {
181  QgsDebugMsgLevel( "returning name '" + mLayerName + '\'', 4 );
182  return mLayerName;
183 }
184 
186 {
187  return nullptr;
188 }
189 
191 {
192  return nullptr;
193 }
194 
195 QString QgsMapLayer::shortName() const
196 {
197  return mShortName;
198 }
199 
200 void QgsMapLayer::setMetadataUrl( const QString &metaUrl )
201 {
202  QList<QgsMapLayerServerProperties::MetadataUrl> urls = serverProperties()->metadataUrls();
203  if ( urls.isEmpty() )
204  {
205  const QgsMapLayerServerProperties::MetadataUrl newItem = QgsMapLayerServerProperties::MetadataUrl( metaUrl, QLatin1String(), QLatin1String() );
206  urls.prepend( newItem );
207  }
208  else
209  {
210  const QgsMapLayerServerProperties::MetadataUrl old = urls.takeFirst();
211  const QgsMapLayerServerProperties::MetadataUrl newItem( metaUrl, old.type, old.format );
212  urls.prepend( newItem );
213  }
215 }
216 
218 {
219  if ( mServerProperties->metadataUrls().isEmpty() )
220  {
221  return QLatin1String();
222  }
223  else
224  {
225  return mServerProperties->metadataUrls().first().url;
226  }
227 }
228 
229 void QgsMapLayer::setMetadataUrlType( const QString &metaUrlType )
230 {
231  QList<QgsMapLayerServerProperties::MetadataUrl> urls = mServerProperties->metadataUrls();
232  if ( urls.isEmpty() )
233  {
234  const QgsMapLayerServerProperties::MetadataUrl newItem( QLatin1String(), metaUrlType, QLatin1String() );
235  urls.prepend( newItem );
236  }
237  else
238  {
239  const QgsMapLayerServerProperties::MetadataUrl old = urls.takeFirst();
240  const QgsMapLayerServerProperties::MetadataUrl newItem( old.url, metaUrlType, old.format );
241  urls.prepend( newItem );
242  }
243  mServerProperties->setMetadataUrls( urls );
244 }
245 
247 {
248  if ( mServerProperties->metadataUrls().isEmpty() )
249  {
250  return QLatin1String();
251  }
252  else
253  {
254  return mServerProperties->metadataUrls().first().type;
255  }
256 }
257 
258 void QgsMapLayer::setMetadataUrlFormat( const QString &metaUrlFormat )
259 {
260  QList<QgsMapLayerServerProperties::MetadataUrl> urls = mServerProperties->metadataUrls();
261  if ( urls.isEmpty() )
262  {
263  const QgsMapLayerServerProperties::MetadataUrl newItem( QLatin1String(), QLatin1String(), metaUrlFormat );
264  urls.prepend( newItem );
265  }
266  else
267  {
268  const QgsMapLayerServerProperties::MetadataUrl old = urls.takeFirst( );
269  const QgsMapLayerServerProperties::MetadataUrl newItem( old.url, old.type, metaUrlFormat );
270  urls.prepend( newItem );
271  }
272  mServerProperties->setMetadataUrls( urls );
273 }
274 
276 {
277  if ( mServerProperties->metadataUrls().isEmpty() )
278  {
279  return QString();
280  }
281  else
282  {
283  return mServerProperties->metadataUrls().first().format;
284  }
285 }
286 
288 {
289  // Redo this every time we're asked for it, as we don't know if
290  // dataSource has changed.
291  QString safeName = QgsDataSourceUri::removePassword( mDataSource );
292  return safeName;
293 }
294 
295 QString QgsMapLayer::source() const
296 {
297  return mDataSource;
298 }
299 
301 {
302  return mExtent;
303 }
304 
305 void QgsMapLayer::setBlendMode( const QPainter::CompositionMode blendMode )
306 {
307  if ( mBlendMode == blendMode )
308  return;
309 
310  mBlendMode = blendMode;
311  emit blendModeChanged( blendMode );
313 }
314 
315 QPainter::CompositionMode QgsMapLayer::blendMode() const
316 {
317  return mBlendMode;
318 }
319 
320 void QgsMapLayer::setOpacity( double opacity )
321 {
323  return;
325  emit opacityChanged( opacity );
327 }
328 
329 double QgsMapLayer::opacity() const
330 {
331  return mLayerOpacity;
332 }
333 
334 bool QgsMapLayer::readLayerXml( const QDomElement &layerElement, QgsReadWriteContext &context, QgsMapLayer::ReadFlags flags )
335 {
336  bool layerError;
337  mReadFlags = flags;
338 
339  QDomNode mnl;
340  QDomElement mne;
341 
342  // read provider
343  QString provider;
344  mnl = layerElement.namedItem( QStringLiteral( "provider" ) );
345  mne = mnl.toElement();
346  provider = mne.text();
347 
348  // set data source
349  mnl = layerElement.namedItem( QStringLiteral( "datasource" ) );
350  mne = mnl.toElement();
351  mDataSource = context.pathResolver().readPath( mne.text() );
352 
353  // if the layer needs authentication, ensure the master password is set
354  const thread_local QRegularExpression rx( "authcfg=([a-z]|[A-Z]|[0-9]){7}" );
355  if ( rx.match( mDataSource ).hasMatch()
357  {
358  return false;
359  }
360 
361  mDataSource = decodedSource( mDataSource, provider, context );
362 
363  // Set the CRS from project file, asking the user if necessary.
364  // Make it the saved CRS to have WMS layer projected correctly.
365  // We will still overwrite whatever GDAL etc picks up anyway
366  // further down this function.
367  mnl = layerElement.namedItem( QStringLiteral( "layername" ) );
368  mne = mnl.toElement();
369 
371  CUSTOM_CRS_VALIDATION savedValidation;
372 
373  const QDomNode srsNode = layerElement.namedItem( QStringLiteral( "srs" ) );
374  mCRS.readXml( srsNode );
375  mCRS.setValidationHint( tr( "Specify CRS for layer %1" ).arg( mne.text() ) );
377  mCRS.validate();
378  savedCRS = mCRS;
379 
380  // Do not validate any projections in children, they will be overwritten anyway.
381  // No need to ask the user for a projections when it is overwritten, is there?
384 
385  const QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Layer" ), mne.text() );
386 
387  // the internal name is just the data source basename
388  //QFileInfo dataSourceFileInfo( mDataSource );
389  //internalName = dataSourceFileInfo.baseName();
390 
391  // set ID
392  mnl = layerElement.namedItem( QStringLiteral( "id" ) );
393  if ( ! mnl.isNull() )
394  {
395  mne = mnl.toElement();
396  if ( ! mne.isNull() && mne.text().length() > 10 ) // should be at least 17 (yyyyMMddhhmmsszzz)
397  {
398  mID = mne.text();
399  }
400  }
401 
402  // set name
403  mnl = layerElement.namedItem( QStringLiteral( "layername" ) );
404  mne = mnl.toElement();
405 
406  //name can be translated
407  setName( context.projectTranslator()->translate( QStringLiteral( "project:layers:%1" ).arg( layerElement.namedItem( QStringLiteral( "id" ) ).toElement().text() ), mne.text() ) );
408 
409  // now let the children grab what they need from the Dom node.
410  layerError = !readXml( layerElement, context );
411 
412  // overwrite CRS with what we read from project file before the raster/vector
413  // file reading functions changed it. They will if projections is specified in the file.
414  // FIXME: is this necessary? Yes, it is (autumn 2019)
416  mCRS = savedCRS;
417 
418  //short name
419  const QDomElement shortNameElem = layerElement.firstChildElement( QStringLiteral( "shortname" ) );
420  if ( !shortNameElem.isNull() )
421  {
422  mShortName = shortNameElem.text();
423  }
424 
425  //title
426  const QDomElement titleElem = layerElement.firstChildElement( QStringLiteral( "title" ) );
427  if ( !titleElem.isNull() )
428  {
429  mTitle = titleElem.text();
430  }
431 
432  //abstract
433  const QDomElement abstractElem = layerElement.firstChildElement( QStringLiteral( "abstract" ) );
434  if ( !abstractElem.isNull() )
435  {
436  mAbstract = abstractElem.text();
437  }
438 
439  //keywordList
440  const QDomElement keywordListElem = layerElement.firstChildElement( QStringLiteral( "keywordList" ) );
441  if ( !keywordListElem.isNull() )
442  {
443  QStringList kwdList;
444  for ( QDomNode n = keywordListElem.firstChild(); !n.isNull(); n = n.nextSibling() )
445  {
446  kwdList << n.toElement().text();
447  }
448  mKeywordList = kwdList.join( QLatin1String( ", " ) );
449  }
450 
451  //dataUrl
452  const QDomElement dataUrlElem = layerElement.firstChildElement( QStringLiteral( "dataUrl" ) );
453  if ( !dataUrlElem.isNull() )
454  {
455  mDataUrl = dataUrlElem.text();
456  mDataUrlFormat = dataUrlElem.attribute( QStringLiteral( "format" ), QString() );
457  }
458 
459  //legendUrl
460  const QDomElement legendUrlElem = layerElement.firstChildElement( QStringLiteral( "legendUrl" ) );
461  if ( !legendUrlElem.isNull() )
462  {
463  mLegendUrl = legendUrlElem.text();
464  mLegendUrlFormat = legendUrlElem.attribute( QStringLiteral( "format" ), QString() );
465  }
466 
467  //attribution
468  const QDomElement attribElem = layerElement.firstChildElement( QStringLiteral( "attribution" ) );
469  if ( !attribElem.isNull() )
470  {
471  mAttribution = attribElem.text();
472  mAttributionUrl = attribElem.attribute( QStringLiteral( "href" ), QString() );
473  }
474 
475  serverProperties()->readXml( layerElement );
476 
477  if ( serverProperties()->metadataUrls().isEmpty() )
478  {
479  // metadataUrl is still empty, maybe it's a QGIS Project < 3.22
480  // keep for legacy
481  const QDomElement metaUrlElem = layerElement.firstChildElement( QStringLiteral( "metadataUrl" ) );
482  if ( !metaUrlElem.isNull() )
483  {
484  const QString url = metaUrlElem.text();
485  const QString type = metaUrlElem.attribute( QStringLiteral( "type" ), QString() );
486  const QString format = metaUrlElem.attribute( QStringLiteral( "format" ), QString() );
487  const QgsMapLayerServerProperties::MetadataUrl newItem( url, type, format );
488  mServerProperties->setMetadataUrls( QList<QgsMapLayerServerProperties::MetadataUrl>() << newItem );
489  }
490  }
491 
492  // mMetadata.readFromLayer( this );
493  const QDomElement metadataElem = layerElement.firstChildElement( QStringLiteral( "resourceMetadata" ) );
494  mMetadata.readMetadataXml( metadataElem );
495 
496  setAutoRefreshInterval( layerElement.attribute( QStringLiteral( "autoRefreshTime" ), QStringLiteral( "0" ) ).toInt() );
497  setAutoRefreshEnabled( layerElement.attribute( QStringLiteral( "autoRefreshEnabled" ), QStringLiteral( "0" ) ).toInt() );
498  setRefreshOnNofifyMessage( layerElement.attribute( QStringLiteral( "refreshOnNotifyMessage" ), QString() ) );
499  setRefreshOnNotifyEnabled( layerElement.attribute( QStringLiteral( "refreshOnNotifyEnabled" ), QStringLiteral( "0" ) ).toInt() );
500 
501  // geographic extent is read only if necessary
502  if ( mReadFlags & QgsMapLayer::ReadFlag::FlagTrustLayerMetadata )
503  {
504  const QDomNode wgs84ExtentNode = layerElement.namedItem( QStringLiteral( "wgs84extent" ) );
505  if ( !wgs84ExtentNode.isNull() )
506  mWgs84Extent = QgsXmlUtils::readRectangle( wgs84ExtentNode.toElement() );
507  }
508 
509  mLegendPlaceholderImage = layerElement.attribute( QStringLiteral( "legendPlaceholderImage" ) );
510 
511  return ! layerError;
512 } // bool QgsMapLayer::readLayerXML
513 
514 
515 bool QgsMapLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
516 {
517  Q_UNUSED( layer_node )
518  Q_UNUSED( context )
519  // NOP by default; children will over-ride with behavior specific to them
520 
521  // read Extent
523  {
524  const QDomNode extentNode = layer_node.namedItem( QStringLiteral( "extent" ) );
525  if ( !extentNode.isNull() )
526  {
527  mExtent = QgsXmlUtils::readRectangle( extentNode.toElement() );
528  }
529  }
530 
531  return true;
532 } // void QgsMapLayer::readXml
533 
534 
535 bool QgsMapLayer::writeLayerXml( QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context ) const
536 {
537  if ( !extent().isNull() )
538  {
539  layerElement.appendChild( QgsXmlUtils::writeRectangle( mExtent, document ) );
540  layerElement.appendChild( QgsXmlUtils::writeRectangle( wgs84Extent( true ), document, QStringLiteral( "wgs84extent" ) ) );
541  }
542 
543  layerElement.setAttribute( QStringLiteral( "autoRefreshTime" ), QString::number( mRefreshTimer->interval() ) );
544  layerElement.setAttribute( QStringLiteral( "autoRefreshEnabled" ), mRefreshTimer->isActive() ? 1 : 0 );
545  layerElement.setAttribute( QStringLiteral( "refreshOnNotifyEnabled" ), mIsRefreshOnNofifyEnabled ? 1 : 0 );
546  layerElement.setAttribute( QStringLiteral( "refreshOnNotifyMessage" ), mRefreshOnNofifyMessage );
547 
548  // ID
549  QDomElement layerId = document.createElement( QStringLiteral( "id" ) );
550  const QDomText layerIdText = document.createTextNode( id() );
551  layerId.appendChild( layerIdText );
552 
553  layerElement.appendChild( layerId );
554 
555  // data source
556  QDomElement dataSource = document.createElement( QStringLiteral( "datasource" ) );
557  const QString src = context.pathResolver().writePath( encodedSource( source(), context ) );
558  const QDomText dataSourceText = document.createTextNode( src );
559  dataSource.appendChild( dataSourceText );
560  layerElement.appendChild( dataSource );
561 
562  // layer name
563  QDomElement layerName = document.createElement( QStringLiteral( "layername" ) );
564  const QDomText layerNameText = document.createTextNode( name() );
565  layerName.appendChild( layerNameText );
566  layerElement.appendChild( layerName );
567 
568  // layer short name
569  if ( !mShortName.isEmpty() )
570  {
571  QDomElement layerShortName = document.createElement( QStringLiteral( "shortname" ) );
572  const QDomText layerShortNameText = document.createTextNode( mShortName );
573  layerShortName.appendChild( layerShortNameText );
574  layerElement.appendChild( layerShortName );
575  }
576 
577  // layer title
578  if ( !mTitle.isEmpty() )
579  {
580  QDomElement layerTitle = document.createElement( QStringLiteral( "title" ) );
581  const QDomText layerTitleText = document.createTextNode( mTitle );
582  layerTitle.appendChild( layerTitleText );
583  layerElement.appendChild( layerTitle );
584  }
585 
586  // layer abstract
587  if ( !mAbstract.isEmpty() )
588  {
589  QDomElement layerAbstract = document.createElement( QStringLiteral( "abstract" ) );
590  const QDomText layerAbstractText = document.createTextNode( mAbstract );
591  layerAbstract.appendChild( layerAbstractText );
592  layerElement.appendChild( layerAbstract );
593  }
594 
595  // layer keyword list
596  const QStringList keywordStringList = keywordList().split( ',' );
597  if ( !keywordStringList.isEmpty() )
598  {
599  QDomElement layerKeywordList = document.createElement( QStringLiteral( "keywordList" ) );
600  for ( int i = 0; i < keywordStringList.size(); ++i )
601  {
602  QDomElement layerKeywordValue = document.createElement( QStringLiteral( "value" ) );
603  const QDomText layerKeywordText = document.createTextNode( keywordStringList.at( i ).trimmed() );
604  layerKeywordValue.appendChild( layerKeywordText );
605  layerKeywordList.appendChild( layerKeywordValue );
606  }
607  layerElement.appendChild( layerKeywordList );
608  }
609 
610  // layer dataUrl
611  const QString aDataUrl = dataUrl();
612  if ( !aDataUrl.isEmpty() )
613  {
614  QDomElement layerDataUrl = document.createElement( QStringLiteral( "dataUrl" ) );
615  const QDomText layerDataUrlText = document.createTextNode( aDataUrl );
616  layerDataUrl.appendChild( layerDataUrlText );
617  layerDataUrl.setAttribute( QStringLiteral( "format" ), dataUrlFormat() );
618  layerElement.appendChild( layerDataUrl );
619  }
620 
621  // layer legendUrl
622  const QString aLegendUrl = legendUrl();
623  if ( !aLegendUrl.isEmpty() )
624  {
625  QDomElement layerLegendUrl = document.createElement( QStringLiteral( "legendUrl" ) );
626  const QDomText layerLegendUrlText = document.createTextNode( aLegendUrl );
627  layerLegendUrl.appendChild( layerLegendUrlText );
628  layerLegendUrl.setAttribute( QStringLiteral( "format" ), legendUrlFormat() );
629  layerElement.appendChild( layerLegendUrl );
630  }
631 
632  // layer attribution
633  const QString aAttribution = attribution();
634  if ( !aAttribution.isEmpty() )
635  {
636  QDomElement layerAttribution = document.createElement( QStringLiteral( "attribution" ) );
637  const QDomText layerAttributionText = document.createTextNode( aAttribution );
638  layerAttribution.appendChild( layerAttributionText );
639  layerAttribution.setAttribute( QStringLiteral( "href" ), attributionUrl() );
640  layerElement.appendChild( layerAttribution );
641  }
642 
643  // timestamp if supported
644  if ( timestamp() > QDateTime() )
645  {
646  QDomElement stamp = document.createElement( QStringLiteral( "timestamp" ) );
647  const QDomText stampText = document.createTextNode( timestamp().toString( Qt::ISODate ) );
648  stamp.appendChild( stampText );
649  layerElement.appendChild( stamp );
650  }
651 
652  layerElement.appendChild( layerName );
653 
654  // zorder
655  // This is no longer stored in the project file. It is superfluous since the layers
656  // are written and read in the proper order.
657 
658  // spatial reference system id
659  QDomElement mySrsElement = document.createElement( QStringLiteral( "srs" ) );
660  mCRS.writeXml( mySrsElement, document );
661  layerElement.appendChild( mySrsElement );
662 
663  // layer metadata
664  QDomElement myMetadataElem = document.createElement( QStringLiteral( "resourceMetadata" ) );
665  mMetadata.writeMetadataXml( myMetadataElem, document );
666  layerElement.appendChild( myMetadataElem );
667 
668  layerElement.setAttribute( QStringLiteral( "legendPlaceholderImage" ), mLegendPlaceholderImage );
669 
670  // now append layer node to map layer node
671  return writeXml( layerElement, document, context );
672 }
673 
674 void QgsMapLayer::writeCommonStyle( QDomElement &layerElement, QDomDocument &document,
675  const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
676 {
677  // save categories
678  const QMetaEnum metaEnum = QMetaEnum::fromType<QgsMapLayer::StyleCategories>();
679  const QString categoriesKeys( metaEnum.valueToKeys( static_cast<int>( categories ) ) );
680  layerElement.setAttribute( QStringLiteral( "styleCategories" ), categoriesKeys );
681 
682  if ( categories.testFlag( Rendering ) )
683  {
684  // use scale dependent visibility flag
685  layerElement.setAttribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ), hasScaleBasedVisibility() ? 1 : 0 );
686  layerElement.setAttribute( QStringLiteral( "maxScale" ), QString::number( maximumScale() ) );
687  layerElement.setAttribute( QStringLiteral( "minScale" ), QString::number( minimumScale() ) );
688  }
689 
690  if ( categories.testFlag( Symbology3D ) )
691  {
692  if ( m3DRenderer )
693  {
694  QDomElement renderer3DElem = document.createElement( QStringLiteral( "renderer-3d" ) );
695  renderer3DElem.setAttribute( QStringLiteral( "type" ), m3DRenderer->type() );
696  m3DRenderer->writeXml( renderer3DElem, context );
697  layerElement.appendChild( renderer3DElem );
698  }
699  }
700 
701  if ( categories.testFlag( LayerConfiguration ) )
702  {
703  // flags
704  // this code is saving automatically all the flags entries
705  QDomElement layerFlagsElem = document.createElement( QStringLiteral( "flags" ) );
706  const auto enumMap = qgsEnumMap<QgsMapLayer::LayerFlag>();
707  for ( auto it = enumMap.constBegin(); it != enumMap.constEnd(); ++it )
708  {
709  const bool flagValue = mFlags.testFlag( it.key() );
710  QDomElement flagElem = document.createElement( it.value() );
711  flagElem.appendChild( document.createTextNode( QString::number( flagValue ) ) );
712  layerFlagsElem.appendChild( flagElem );
713  }
714  layerElement.appendChild( layerFlagsElem );
715  }
716 
717  if ( categories.testFlag( Temporal ) )
718  {
719  if ( QgsMapLayerTemporalProperties *properties = const_cast< QgsMapLayer * >( this )->temporalProperties() )
720  properties->writeXml( layerElement, document, context );
721  }
722 
723  if ( categories.testFlag( Elevation ) )
724  {
725  if ( QgsMapLayerElevationProperties *properties = const_cast< QgsMapLayer * >( this )->elevationProperties() )
726  properties->writeXml( layerElement, document, context );
727  }
728 
729  if ( categories.testFlag( Notes ) && QgsLayerNotesUtils::layerHasNotes( this ) )
730  {
731  QDomElement notesElem = document.createElement( QStringLiteral( "userNotes" ) );
732  notesElem.setAttribute( QStringLiteral( "value" ), QgsLayerNotesUtils::layerNotes( this ) );
733  layerElement.appendChild( notesElem );
734  }
735 
736  // custom properties
737  if ( categories.testFlag( CustomProperties ) )
738  {
739  writeCustomProperties( layerElement, document );
740  }
741 }
742 
743 
744 bool QgsMapLayer::writeXml( QDomNode &layer_node, QDomDocument &document, const QgsReadWriteContext &context ) const
745 {
746  Q_UNUSED( layer_node )
747  Q_UNUSED( document )
748  Q_UNUSED( context )
749  // NOP by default; children will over-ride with behavior specific to them
750 
751  return true;
752 }
753 
754 QString QgsMapLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
755 {
756  Q_UNUSED( context )
757  return source;
758 }
759 
760 QString QgsMapLayer::decodedSource( const QString &source, const QString &dataProvider, const QgsReadWriteContext &context ) const
761 {
762  Q_UNUSED( context )
763  Q_UNUSED( dataProvider )
764  return source;
765 }
766 
768 {
770  if ( m3DRenderer )
771  m3DRenderer->resolveReferences( *project );
772 }
773 
774 
775 void QgsMapLayer::readCustomProperties( const QDomNode &layerNode, const QString &keyStartsWith )
776 {
777  mCustomProperties.readXml( layerNode, keyStartsWith );
778 }
779 
780 void QgsMapLayer::writeCustomProperties( QDomNode &layerNode, QDomDocument &doc ) const
781 {
782  mCustomProperties.writeXml( layerNode, doc );
783 }
784 
785 void QgsMapLayer::readStyleManager( const QDomNode &layerNode )
786 {
787  const QDomElement styleMgrElem = layerNode.firstChildElement( QStringLiteral( "map-layer-style-manager" ) );
788  if ( !styleMgrElem.isNull() )
789  mStyleManager->readXml( styleMgrElem );
790  else
791  mStyleManager->reset();
792 }
793 
794 void QgsMapLayer::writeStyleManager( QDomNode &layerNode, QDomDocument &doc ) const
795 {
796  if ( mStyleManager )
797  {
798  QDomElement styleMgrElem = doc.createElement( QStringLiteral( "map-layer-style-manager" ) );
799  mStyleManager->writeXml( styleMgrElem );
800  layerNode.appendChild( styleMgrElem );
801  }
802 }
803 
805 {
806  return mValid;
807 }
808 
809 #if 0
810 void QgsMapLayer::connectNotify( const char *signal )
811 {
812  Q_UNUSED( signal )
813  QgsDebugMsgLevel( "QgsMapLayer connected to " + QString( signal ), 3 );
814 } // QgsMapLayer::connectNotify
815 #endif
816 
817 bool QgsMapLayer::isInScaleRange( double scale ) const
818 {
819  return !mScaleBasedVisibility ||
820  ( ( mMinScale == 0 || mMinScale * Qgis::SCALE_PRECISION < scale )
821  && ( mMaxScale == 0 || scale < mMaxScale ) );
822 }
823 
825 {
826  return mScaleBasedVisibility;
827 }
828 
830 {
831  return mRefreshTimer->isActive();
832 }
833 
835 {
836  return mRefreshTimer->interval();
837 }
838 
840 {
841  if ( interval <= 0 )
842  {
843  mRefreshTimer->stop();
844  mRefreshTimer->setInterval( 0 );
845  }
846  else
847  {
848  mRefreshTimer->setInterval( interval );
849  }
850  emit autoRefreshIntervalChanged( mRefreshTimer->isActive() ? mRefreshTimer->interval() : 0 );
851 }
852 
854 {
855  if ( !enabled )
856  mRefreshTimer->stop();
857  else if ( mRefreshTimer->interval() > 0 )
858  mRefreshTimer->start();
859 
860  emit autoRefreshIntervalChanged( mRefreshTimer->isActive() ? mRefreshTimer->interval() : 0 );
861 }
862 
864 {
865  return mMetadata;
866 }
867 
868 void QgsMapLayer::setMaximumScale( double scale )
869 {
870  mMinScale = scale;
871 }
872 
874 {
875  return mMinScale;
876 }
877 
878 
879 void QgsMapLayer::setMinimumScale( double scale )
880 {
881  mMaxScale = scale;
882 }
883 
884 void QgsMapLayer::setScaleBasedVisibility( const bool enabled )
885 {
886  mScaleBasedVisibility = enabled;
887 }
888 
890 {
891  return mMaxScale;
892 }
893 
894 QStringList QgsMapLayer::subLayers() const
895 {
896  return QStringList(); // Empty
897 }
898 
899 void QgsMapLayer::setLayerOrder( const QStringList &layers )
900 {
901  Q_UNUSED( layers )
902  // NOOP
903 }
904 
905 void QgsMapLayer::setSubLayerVisibility( const QString &name, bool vis )
906 {
907  Q_UNUSED( name )
908  Q_UNUSED( vis )
909  // NOOP
910 }
911 
913 {
914  return false;
915 }
916 
918 {
919  return mCRS;
920 }
921 
922 void QgsMapLayer::setCrs( const QgsCoordinateReferenceSystem &srs, bool emitSignal )
923 {
924  mCRS = srs;
925 
927  {
928  mCRS.setValidationHint( tr( "Specify CRS for layer %1" ).arg( name() ) );
929  mCRS.validate();
930  }
931 
932  if ( emitSignal )
933  emit crsChanged();
934 }
935 
937 {
938  const QgsDataProvider *lDataProvider = dataProvider();
939  return lDataProvider ? lDataProvider->transformContext() : QgsCoordinateTransformContext();
940 }
941 
942 QString QgsMapLayer::formatLayerName( const QString &name )
943 {
944  QString layerName( name );
945  layerName.replace( '_', ' ' );
947  return layerName;
948 }
949 
950 QString QgsMapLayer::baseURI( PropertyType type ) const
951 {
952  QString myURI = publicSource();
953 
954  // first get base path for delimited text, spatialite and OGR layers,
955  // as in these cases URI may contain layer name and/or additional
956  // information. This also strips prefix in case if VSIFILE mechanism
957  // is used
958  if ( providerType() == QLatin1String( "ogr" ) || providerType() == QLatin1String( "delimitedtext" ) ||
959  providerType() == QLatin1String( "spatialite" ) )
960  {
961  QVariantMap components = QgsProviderRegistry::instance()->decodeUri( providerType(), myURI );
962  myURI = components["path"].toString();
963  }
964 
965  QFileInfo myFileInfo( myURI );
966  QString key;
967 
968  if ( myFileInfo.exists() )
969  {
970  // if file is using the /vsizip/ or /vsigzip/ mechanism, cleanup the name
971  if ( myURI.endsWith( QLatin1String( ".gz" ), Qt::CaseInsensitive ) )
972  myURI.chop( 3 );
973  else if ( myURI.endsWith( QLatin1String( ".zip" ), Qt::CaseInsensitive ) )
974  myURI.chop( 4 );
975  else if ( myURI.endsWith( QLatin1String( ".tar" ), Qt::CaseInsensitive ) )
976  myURI.chop( 4 );
977  else if ( myURI.endsWith( QLatin1String( ".tar.gz" ), Qt::CaseInsensitive ) )
978  myURI.chop( 7 );
979  else if ( myURI.endsWith( QLatin1String( ".tgz" ), Qt::CaseInsensitive ) )
980  myURI.chop( 4 );
981  myFileInfo.setFile( myURI );
982  // get the file name for our .qml style file
983  key = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + QgsMapLayer::extensionPropertyType( type );
984  }
985  else
986  {
987  key = publicSource();
988  }
989 
990  return key;
991 }
992 
994 {
995  return baseURI( PropertyType::Metadata );
996 }
997 
998 QString QgsMapLayer::saveDefaultMetadata( bool &resultFlag )
999 {
1000  if ( const QgsProviderMetadata *metadata = QgsProviderRegistry::instance()->providerMetadata( providerType() ) )
1001  {
1002  if ( metadata->providerCapabilities() & QgsProviderMetadata::SaveLayerMetadata )
1003  {
1004  try
1005  {
1006  QString errorMessage;
1007  resultFlag = QgsProviderRegistry::instance()->saveLayerMetadata( providerType(), mDataSource, mMetadata, errorMessage );
1008  if ( resultFlag )
1009  return tr( "Successfully saved default layer metadata" );
1010  else
1011  return errorMessage;
1012  }
1013  catch ( QgsNotSupportedException &e )
1014  {
1015  resultFlag = false;
1016  return e.what();
1017  }
1018  }
1019  }
1020 
1021  // fallback default metadata saving method, for providers which don't support (or implement) saveLayerMetadata
1022  return saveNamedMetadata( metadataUri(), resultFlag );
1023 }
1024 
1025 QString QgsMapLayer::loadDefaultMetadata( bool &resultFlag )
1026 {
1027  return loadNamedMetadata( metadataUri(), resultFlag );
1028 }
1029 
1030 QString QgsMapLayer::styleURI() const
1031 {
1032  return baseURI( PropertyType::Style );
1033 }
1034 
1035 QString QgsMapLayer::loadDefaultStyle( bool &resultFlag )
1036 {
1037  return loadNamedStyle( styleURI(), resultFlag );
1038 }
1039 
1040 bool QgsMapLayer::loadNamedMetadataFromDatabase( const QString &db, const QString &uri, QString &qmd )
1041 {
1042  return loadNamedPropertyFromDatabase( db, uri, qmd, PropertyType::Metadata );
1043 }
1044 
1045 bool QgsMapLayer::loadNamedStyleFromDatabase( const QString &db, const QString &uri, QString &qml )
1046 {
1047  return loadNamedPropertyFromDatabase( db, uri, qml, PropertyType::Style );
1048 }
1049 
1050 bool QgsMapLayer::loadNamedPropertyFromDatabase( const QString &db, const QString &uri, QString &xml, QgsMapLayer::PropertyType type )
1051 {
1052  QgsDebugMsgLevel( QStringLiteral( "db = %1 uri = %2" ).arg( db, uri ), 4 );
1053 
1054  bool resultFlag = false;
1055 
1056  // read from database
1057  sqlite3_database_unique_ptr database;
1058  sqlite3_statement_unique_ptr statement;
1059 
1060  int myResult;
1061 
1062  QgsDebugMsgLevel( QStringLiteral( "Trying to load style or metadata for \"%1\" from \"%2\"" ).arg( uri, db ), 4 );
1063 
1064  if ( db.isEmpty() || !QFile( db ).exists() )
1065  return false;
1066 
1067  myResult = database.open_v2( db, SQLITE_OPEN_READONLY, nullptr );
1068  if ( myResult != SQLITE_OK )
1069  {
1070  return false;
1071  }
1072 
1073  QString mySql;
1074  switch ( type )
1075  {
1076  case Metadata:
1077  mySql = QStringLiteral( "select qmd from tbl_metadata where metadata=?" );
1078  break;
1079 
1080  case Style:
1081  mySql = QStringLiteral( "select qml from tbl_styles where style=?" );
1082  break;
1083  }
1084 
1085  statement = database.prepare( mySql, myResult );
1086  if ( myResult == SQLITE_OK )
1087  {
1088  QByteArray param = uri.toUtf8();
1089 
1090  if ( sqlite3_bind_text( statement.get(), 1, param.data(), param.length(), SQLITE_STATIC ) == SQLITE_OK &&
1091  sqlite3_step( statement.get() ) == SQLITE_ROW )
1092  {
1093  xml = QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( statement.get(), 0 ) ) );
1094  resultFlag = true;
1095  }
1096  }
1097  return resultFlag;
1098 }
1099 
1100 
1101 QString QgsMapLayer::loadNamedStyle( const QString &uri, bool &resultFlag, QgsMapLayer::StyleCategories categories )
1102 {
1103  return loadNamedProperty( uri, PropertyType::Style, resultFlag, categories );
1104 }
1105 
1106 QString QgsMapLayer::loadNamedProperty( const QString &uri, QgsMapLayer::PropertyType type, bool &resultFlag, StyleCategories categories )
1107 {
1108  QgsDebugMsgLevel( QStringLiteral( "uri = %1 myURI = %2" ).arg( uri, publicSource() ), 4 );
1109 
1110  resultFlag = false;
1111 
1112  QDomDocument myDocument( QStringLiteral( "qgis" ) );
1113 
1114  // location of problem associated with errorMsg
1115  int line, column;
1116  QString myErrorMessage;
1117 
1118  QFile myFile( uri );
1119  if ( myFile.open( QFile::ReadOnly ) )
1120  {
1121  QgsDebugMsgLevel( QStringLiteral( "file found %1" ).arg( uri ), 2 );
1122  // read file
1123  resultFlag = myDocument.setContent( &myFile, &myErrorMessage, &line, &column );
1124  if ( !resultFlag )
1125  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1126  myFile.close();
1127  }
1128  else
1129  {
1130  const QFileInfo project( QgsProject::instance()->fileName() );
1131  QgsDebugMsgLevel( QStringLiteral( "project fileName: %1" ).arg( project.absoluteFilePath() ), 4 );
1132 
1133  QString xml;
1134  switch ( type )
1135  {
1136  case QgsMapLayer::Style:
1137  {
1138  if ( loadNamedStyleFromDatabase( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ), uri, xml ) ||
1139  ( project.exists() && loadNamedStyleFromDatabase( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), uri, xml ) ) ||
1140  loadNamedStyleFromDatabase( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( QStringLiteral( "resources/qgis.qmldb" ) ), uri, xml ) )
1141  {
1142  resultFlag = myDocument.setContent( xml, &myErrorMessage, &line, &column );
1143  if ( !resultFlag )
1144  {
1145  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1146  }
1147  }
1148  else
1149  {
1150  myErrorMessage = tr( "Style not found in database" );
1151  resultFlag = false;
1152  }
1153  break;
1154  }
1155  case QgsMapLayer::Metadata:
1156  {
1157  if ( loadNamedMetadataFromDatabase( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ), uri, xml ) ||
1158  ( project.exists() && loadNamedMetadataFromDatabase( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), uri, xml ) ) ||
1159  loadNamedMetadataFromDatabase( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( QStringLiteral( "resources/qgis.qmldb" ) ), uri, xml ) )
1160  {
1161  resultFlag = myDocument.setContent( xml, &myErrorMessage, &line, &column );
1162  if ( !resultFlag )
1163  {
1164  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1165  }
1166  }
1167  else
1168  {
1169  myErrorMessage = tr( "Metadata not found in database" );
1170  resultFlag = false;
1171  }
1172  break;
1173  }
1174  }
1175  }
1176 
1177  if ( !resultFlag )
1178  {
1179  return myErrorMessage;
1180  }
1181 
1182  switch ( type )
1183  {
1184  case QgsMapLayer::Style:
1185  resultFlag = importNamedStyle( myDocument, myErrorMessage, categories );
1186  if ( !resultFlag )
1187  myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( uri, myErrorMessage );
1188  break;
1189  case QgsMapLayer::Metadata:
1190  resultFlag = importNamedMetadata( myDocument, myErrorMessage );
1191  if ( !resultFlag )
1192  myErrorMessage = tr( "Loading metadata file %1 failed because:\n%2" ).arg( uri, myErrorMessage );
1193  break;
1194  }
1195  return myErrorMessage;
1196 }
1197 
1198 bool QgsMapLayer::importNamedMetadata( QDomDocument &document, QString &errorMessage )
1199 {
1200  const QDomElement myRoot = document.firstChildElement( QStringLiteral( "qgis" ) );
1201  if ( myRoot.isNull() )
1202  {
1203  errorMessage = tr( "Root <qgis> element could not be found" );
1204  return false;
1205  }
1206 
1207  return mMetadata.readMetadataXml( myRoot );
1208 }
1209 
1210 bool QgsMapLayer::importNamedStyle( QDomDocument &myDocument, QString &myErrorMessage, QgsMapLayer::StyleCategories categories )
1211 {
1212  const QDomElement myRoot = myDocument.firstChildElement( QStringLiteral( "qgis" ) );
1213  if ( myRoot.isNull() )
1214  {
1215  myErrorMessage = tr( "Root <qgis> element could not be found" );
1216  return false;
1217  }
1218 
1219  // get style file version string, if any
1220  const QgsProjectVersion fileVersion( myRoot.attribute( QStringLiteral( "version" ) ) );
1221  const QgsProjectVersion thisVersion( Qgis::version() );
1222 
1223  if ( thisVersion > fileVersion )
1224  {
1225  QgsProjectFileTransform styleFile( myDocument, fileVersion );
1226  styleFile.updateRevision( thisVersion );
1227  }
1228 
1229  // Get source categories
1230  const QgsMapLayer::StyleCategories sourceCategories = QgsXmlUtils::readFlagAttribute( myRoot, QStringLiteral( "styleCategories" ), QgsMapLayer::AllStyleCategories );
1231 
1232  //Test for matching geometry type on vector layers when applying, if geometry type is given in the style
1233  if ( ( sourceCategories.testFlag( QgsMapLayer::Symbology ) || sourceCategories.testFlag( QgsMapLayer::Symbology3D ) ) &&
1234  ( categories.testFlag( QgsMapLayer::Symbology ) || categories.testFlag( QgsMapLayer::Symbology3D ) ) )
1235  {
1236  if ( type() == QgsMapLayerType::VectorLayer && !myRoot.firstChildElement( QStringLiteral( "layerGeometryType" ) ).isNull() )
1237  {
1238  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( this );
1239  const QgsWkbTypes::GeometryType importLayerGeometryType = static_cast<QgsWkbTypes::GeometryType>( myRoot.firstChildElement( QStringLiteral( "layerGeometryType" ) ).text().toInt() );
1240  if ( importLayerGeometryType != QgsWkbTypes::GeometryType::UnknownGeometry && vl->geometryType() != importLayerGeometryType )
1241  {
1242  myErrorMessage = tr( "Cannot apply style with symbology to layer with a different geometry type" );
1243  return false;
1244  }
1245  }
1246  }
1247 
1249  return readSymbology( myRoot, myErrorMessage, context, categories ); // TODO: support relative paths in QML?
1250 }
1251 
1252 void QgsMapLayer::exportNamedMetadata( QDomDocument &doc, QString &errorMsg ) const
1253 {
1254  QDomImplementation DomImplementation;
1255  const QDomDocumentType documentType = DomImplementation.createDocumentType( QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
1256  QDomDocument myDocument( documentType );
1257 
1258  QDomElement myRootNode = myDocument.createElement( QStringLiteral( "qgis" ) );
1259  myRootNode.setAttribute( QStringLiteral( "version" ), Qgis::version() );
1260  myDocument.appendChild( myRootNode );
1261 
1262  if ( !mMetadata.writeMetadataXml( myRootNode, myDocument ) )
1263  {
1264  errorMsg = QObject::tr( "Could not save metadata" );
1265  return;
1266  }
1267 
1268  doc = myDocument;
1269 }
1270 
1271 void QgsMapLayer::exportNamedStyle( QDomDocument &doc, QString &errorMsg, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1272 {
1273  QDomImplementation DomImplementation;
1274  const QDomDocumentType documentType = DomImplementation.createDocumentType( QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
1275  QDomDocument myDocument( documentType );
1276 
1277  QDomElement myRootNode = myDocument.createElement( QStringLiteral( "qgis" ) );
1278  myRootNode.setAttribute( QStringLiteral( "version" ), Qgis::version() );
1279  myDocument.appendChild( myRootNode );
1280 
1281  if ( !writeSymbology( myRootNode, myDocument, errorMsg, context, categories ) ) // TODO: support relative paths in QML?
1282  {
1283  errorMsg = QObject::tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1284  return;
1285  }
1286 
1287  /*
1288  * Check to see if the layer is vector - in which case we should also export its geometryType
1289  * to avoid eventually pasting to a layer with a different geometry
1290  */
1292  {
1293  //Getting the selectionLayer geometry
1294  const QgsVectorLayer *vl = qobject_cast<const QgsVectorLayer *>( this );
1295  const QString geoType = QString::number( vl->geometryType() );
1296 
1297  //Adding geometryinformation
1298  QDomElement layerGeometryType = myDocument.createElement( QStringLiteral( "layerGeometryType" ) );
1299  const QDomText type = myDocument.createTextNode( geoType );
1300 
1301  layerGeometryType.appendChild( type );
1302  myRootNode.appendChild( layerGeometryType );
1303  }
1304 
1305  doc = myDocument;
1306 }
1307 
1308 QString QgsMapLayer::saveDefaultStyle( bool &resultFlag )
1309 {
1310  return saveNamedStyle( styleURI(), resultFlag );
1311 }
1312 
1313 QString QgsMapLayer::saveNamedMetadata( const QString &uri, bool &resultFlag )
1314 {
1315  return saveNamedProperty( uri, QgsMapLayer::Metadata, resultFlag );
1316 }
1317 
1318 QString QgsMapLayer::loadNamedMetadata( const QString &uri, bool &resultFlag )
1319 {
1320  return loadNamedProperty( uri, QgsMapLayer::Metadata, resultFlag );
1321 }
1322 
1323 QString QgsMapLayer::saveNamedProperty( const QString &uri, QgsMapLayer::PropertyType type, bool &resultFlag, StyleCategories categories )
1324 {
1325  // check if the uri is a file or ends with .qml/.qmd,
1326  // which indicates that it should become one
1327  // everything else goes to the database
1328  QString filename;
1329 
1330  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this );
1331  if ( vlayer && vlayer->providerType() == QLatin1String( "ogr" ) )
1332  {
1333  QStringList theURIParts = uri.split( '|' );
1334  filename = theURIParts[0];
1335  }
1336  else if ( vlayer && vlayer->providerType() == QLatin1String( "gpx" ) )
1337  {
1338  QStringList theURIParts = uri.split( '?' );
1339  filename = theURIParts[0];
1340  }
1341  else if ( vlayer && vlayer->providerType() == QLatin1String( "delimitedtext" ) )
1342  {
1343  filename = QUrl::fromEncoded( uri.toLatin1() ).toLocalFile();
1344  // toLocalFile() returns an empty string if theURI is a plain Windows-path, e.g. "C:/style.qml"
1345  if ( filename.isEmpty() )
1346  filename = uri;
1347  }
1348  else
1349  {
1350  filename = uri;
1351  }
1352 
1353  QString myErrorMessage;
1354  QDomDocument myDocument;
1355  switch ( type )
1356  {
1357  case Metadata:
1358  exportNamedMetadata( myDocument, myErrorMessage );
1359  break;
1360 
1361  case Style:
1362  const QgsReadWriteContext context;
1363  exportNamedStyle( myDocument, myErrorMessage, context, categories );
1364  break;
1365  }
1366 
1367  const QFileInfo myFileInfo( filename );
1368  if ( myFileInfo.exists() || filename.endsWith( QgsMapLayer::extensionPropertyType( type ), Qt::CaseInsensitive ) )
1369  {
1370  const QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
1371  if ( !myDirInfo.isWritable() )
1372  {
1373  return tr( "The directory containing your dataset needs to be writable!" );
1374  }
1375 
1376  // now construct the file name for our .qml or .qmd file
1377  const QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + QgsMapLayer::extensionPropertyType( type );
1378 
1379  QFile myFile( myFileName );
1380  if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
1381  {
1382  QTextStream myFileStream( &myFile );
1383  // save as utf-8 with 2 spaces for indents
1384  myDocument.save( myFileStream, 2 );
1385  myFile.close();
1386  resultFlag = true;
1387  switch ( type )
1388  {
1389  case Metadata:
1390  return tr( "Created default metadata file as %1" ).arg( myFileName );
1391 
1392  case Style:
1393  return tr( "Created default style file as %1" ).arg( myFileName );
1394  }
1395 
1396  }
1397  else
1398  {
1399  resultFlag = false;
1400  switch ( type )
1401  {
1402  case Metadata:
1403  return tr( "ERROR: Failed to created default metadata file as %1. Check file permissions and retry." ).arg( myFileName );
1404 
1405  case Style:
1406  return tr( "ERROR: Failed to created default style file as %1. Check file permissions and retry." ).arg( myFileName );
1407  }
1408  }
1409  }
1410  else
1411  {
1412  const QString qml = myDocument.toString();
1413 
1414  // read from database
1415  sqlite3_database_unique_ptr database;
1416  sqlite3_statement_unique_ptr statement;
1417 
1418  int myResult = database.open( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ) );
1419  if ( myResult != SQLITE_OK )
1420  {
1421  return tr( "User database could not be opened." );
1422  }
1423 
1424  QByteArray param0 = uri.toUtf8();
1425  QByteArray param1 = qml.toUtf8();
1426 
1427  QString mySql;
1428  switch ( type )
1429  {
1430  case Metadata:
1431  mySql = QStringLiteral( "create table if not exists tbl_metadata(metadata varchar primary key,qmd varchar)" );
1432  break;
1433 
1434  case Style:
1435  mySql = QStringLiteral( "create table if not exists tbl_styles(style varchar primary key,qml varchar)" );
1436  break;
1437  }
1438 
1439  statement = database.prepare( mySql, myResult );
1440  if ( myResult == SQLITE_OK )
1441  {
1442  if ( sqlite3_step( statement.get() ) != SQLITE_DONE )
1443  {
1444  resultFlag = false;
1445  switch ( type )
1446  {
1447  case Metadata:
1448  return tr( "The metadata table could not be created." );
1449 
1450  case Style:
1451  return tr( "The style table could not be created." );
1452  }
1453  }
1454  }
1455 
1456  switch ( type )
1457  {
1458  case Metadata:
1459  mySql = QStringLiteral( "insert into tbl_metadata(metadata,qmd) values (?,?)" );
1460  break;
1461 
1462  case Style:
1463  mySql = QStringLiteral( "insert into tbl_styles(style,qml) values (?,?)" );
1464  break;
1465  }
1466  statement = database.prepare( mySql, myResult );
1467  if ( myResult == SQLITE_OK )
1468  {
1469  if ( sqlite3_bind_text( statement.get(), 1, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
1470  sqlite3_bind_text( statement.get(), 2, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
1471  sqlite3_step( statement.get() ) == SQLITE_DONE )
1472  {
1473  resultFlag = true;
1474  switch ( type )
1475  {
1476  case Metadata:
1477  myErrorMessage = tr( "The metadata %1 was saved to database" ).arg( uri );
1478  break;
1479 
1480  case Style:
1481  myErrorMessage = tr( "The style %1 was saved to database" ).arg( uri );
1482  break;
1483  }
1484  }
1485  }
1486 
1487  if ( !resultFlag )
1488  {
1489  QString mySql;
1490  switch ( type )
1491  {
1492  case Metadata:
1493  mySql = QStringLiteral( "update tbl_metadata set qmd=? where metadata=?" );
1494  break;
1495 
1496  case Style:
1497  mySql = QStringLiteral( "update tbl_styles set qml=? where style=?" );
1498  break;
1499  }
1500  statement = database.prepare( mySql, myResult );
1501  if ( myResult == SQLITE_OK )
1502  {
1503  if ( sqlite3_bind_text( statement.get(), 2, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
1504  sqlite3_bind_text( statement.get(), 1, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
1505  sqlite3_step( statement.get() ) == SQLITE_DONE )
1506  {
1507  resultFlag = true;
1508  switch ( type )
1509  {
1510  case Metadata:
1511  myErrorMessage = tr( "The metadata %1 was updated in the database." ).arg( uri );
1512  break;
1513 
1514  case Style:
1515  myErrorMessage = tr( "The style %1 was updated in the database." ).arg( uri );
1516  break;
1517  }
1518  }
1519  else
1520  {
1521  resultFlag = false;
1522  switch ( type )
1523  {
1524  case Metadata:
1525  myErrorMessage = tr( "The metadata %1 could not be updated in the database." ).arg( uri );
1526  break;
1527 
1528  case Style:
1529  myErrorMessage = tr( "The style %1 could not be updated in the database." ).arg( uri );
1530  break;
1531  }
1532  }
1533  }
1534  else
1535  {
1536  resultFlag = false;
1537  switch ( type )
1538  {
1539  case Metadata:
1540  myErrorMessage = tr( "The metadata %1 could not be inserted into database." ).arg( uri );
1541  break;
1542 
1543  case Style:
1544  myErrorMessage = tr( "The style %1 could not be inserted into database." ).arg( uri );
1545  break;
1546  }
1547  }
1548  }
1549  }
1550 
1551  return myErrorMessage;
1552 }
1553 
1554 QString QgsMapLayer::saveNamedStyle( const QString &uri, bool &resultFlag, StyleCategories categories )
1555 {
1556  return saveNamedProperty( uri, QgsMapLayer::Style, resultFlag, categories );
1557 }
1558 
1559 void QgsMapLayer::exportSldStyle( QDomDocument &doc, QString &errorMsg ) const
1560 {
1561  QDomDocument myDocument = QDomDocument();
1562 
1563  const QDomNode header = myDocument.createProcessingInstruction( QStringLiteral( "xml" ), QStringLiteral( "version=\"1.0\" encoding=\"UTF-8\"" ) );
1564  myDocument.appendChild( header );
1565 
1566  const QgsVectorLayer *vlayer = qobject_cast<const QgsVectorLayer *>( this );
1567  const QgsRasterLayer *rlayer = qobject_cast<const QgsRasterLayer *>( this );
1568  if ( !vlayer && !rlayer )
1569  {
1570  errorMsg = tr( "Could not save symbology because:\n%1" )
1571  .arg( tr( "Only vector and raster layers are supported" ) );
1572  return;
1573  }
1574 
1575  // Create the root element
1576  QDomElement root = myDocument.createElementNS( QStringLiteral( "http://www.opengis.net/sld" ), QStringLiteral( "StyledLayerDescriptor" ) );
1577  QDomElement layerNode;
1578  if ( vlayer )
1579  {
1580  root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.1.0" ) );
1581  root.setAttribute( QStringLiteral( "xsi:schemaLocation" ), QStringLiteral( "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" ) );
1582  root.setAttribute( QStringLiteral( "xmlns:ogc" ), QStringLiteral( "http://www.opengis.net/ogc" ) );
1583  root.setAttribute( QStringLiteral( "xmlns:se" ), QStringLiteral( "http://www.opengis.net/se" ) );
1584  root.setAttribute( QStringLiteral( "xmlns:xlink" ), QStringLiteral( "http://www.w3.org/1999/xlink" ) );
1585  root.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) );
1586  myDocument.appendChild( root );
1587 
1588  // Create the NamedLayer element
1589  layerNode = myDocument.createElement( QStringLiteral( "NamedLayer" ) );
1590  root.appendChild( layerNode );
1591  }
1592 
1593  // note: Only SLD 1.0 version is generated because seems none is using SE1.1.0 at least for rasters
1594  if ( rlayer )
1595  {
1596  // Create the root element
1597  root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0.0" ) );
1598  root.setAttribute( QStringLiteral( "xmlns:gml" ), QStringLiteral( "http://www.opengis.net/gml" ) );
1599  root.setAttribute( QStringLiteral( "xmlns:ogc" ), QStringLiteral( "http://www.opengis.net/ogc" ) );
1600  root.setAttribute( QStringLiteral( "xmlns:sld" ), QStringLiteral( "http://www.opengis.net/sld" ) );
1601  myDocument.appendChild( root );
1602 
1603  // Create the NamedLayer element
1604  layerNode = myDocument.createElement( QStringLiteral( "UserLayer" ) );
1605  root.appendChild( layerNode );
1606  }
1607 
1608  QVariantMap props;
1609  if ( hasScaleBasedVisibility() )
1610  {
1611  props[ QStringLiteral( "scaleMinDenom" ) ] = QString::number( mMinScale );
1612  props[ QStringLiteral( "scaleMaxDenom" ) ] = QString::number( mMaxScale );
1613  }
1614 
1615  if ( vlayer )
1616  {
1617  if ( !vlayer->writeSld( layerNode, myDocument, errorMsg, props ) )
1618  {
1619  errorMsg = tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1620  return;
1621  }
1622  }
1623 
1624  if ( rlayer )
1625  {
1626  if ( !rlayer->writeSld( layerNode, myDocument, errorMsg, props ) )
1627  {
1628  errorMsg = tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1629  return;
1630  }
1631  }
1632 
1633  doc = myDocument;
1634 }
1635 
1636 QString QgsMapLayer::saveSldStyle( const QString &uri, bool &resultFlag ) const
1637 {
1638  const QgsMapLayer *mlayer = qobject_cast<const QgsMapLayer *>( this );
1639 
1640  QString errorMsg;
1641  QDomDocument myDocument;
1642  mlayer->exportSldStyle( myDocument, errorMsg );
1643  if ( !errorMsg.isNull() )
1644  {
1645  resultFlag = false;
1646  return errorMsg;
1647  }
1648  // check if the uri is a file or ends with .sld,
1649  // which indicates that it should become one
1650  QString filename;
1651  if ( mlayer->providerType() == QLatin1String( "ogr" ) )
1652  {
1653  QStringList theURIParts = uri.split( '|' );
1654  filename = theURIParts[0];
1655  }
1656  else if ( mlayer->providerType() == QLatin1String( "gpx" ) )
1657  {
1658  QStringList theURIParts = uri.split( '?' );
1659  filename = theURIParts[0];
1660  }
1661  else if ( mlayer->providerType() == QLatin1String( "delimitedtext" ) )
1662  {
1663  filename = QUrl::fromEncoded( uri.toLatin1() ).toLocalFile();
1664  // toLocalFile() returns an empty string if theURI is a plain Windows-path, e.g. "C:/style.qml"
1665  if ( filename.isEmpty() )
1666  filename = uri;
1667  }
1668  else
1669  {
1670  filename = uri;
1671  }
1672 
1673  const QFileInfo myFileInfo( filename );
1674  if ( myFileInfo.exists() || filename.endsWith( QLatin1String( ".sld" ), Qt::CaseInsensitive ) )
1675  {
1676  const QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
1677  if ( !myDirInfo.isWritable() )
1678  {
1679  return tr( "The directory containing your dataset needs to be writable!" );
1680  }
1681 
1682  // now construct the file name for our .sld style file
1683  const QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".sld";
1684 
1685  QFile myFile( myFileName );
1686  if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
1687  {
1688  QTextStream myFileStream( &myFile );
1689  // save as utf-8 with 2 spaces for indents
1690  myDocument.save( myFileStream, 2 );
1691  myFile.close();
1692  resultFlag = true;
1693  return tr( "Created default style file as %1" ).arg( myFileName );
1694  }
1695  }
1696 
1697  resultFlag = false;
1698  return tr( "ERROR: Failed to created SLD style file as %1. Check file permissions and retry." ).arg( filename );
1699 }
1700 
1701 QString QgsMapLayer::loadSldStyle( const QString &uri, bool &resultFlag )
1702 {
1703  resultFlag = false;
1704 
1705  QDomDocument myDocument;
1706 
1707  // location of problem associated with errorMsg
1708  int line, column;
1709  QString myErrorMessage;
1710 
1711  QFile myFile( uri );
1712  if ( myFile.open( QFile::ReadOnly ) )
1713  {
1714  // read file
1715  resultFlag = myDocument.setContent( &myFile, true, &myErrorMessage, &line, &column );
1716  if ( !resultFlag )
1717  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1718  myFile.close();
1719  }
1720  else
1721  {
1722  myErrorMessage = tr( "Unable to open file %1" ).arg( uri );
1723  }
1724 
1725  if ( !resultFlag )
1726  {
1727  return myErrorMessage;
1728  }
1729 
1730  // check for root SLD element
1731  const QDomElement myRoot = myDocument.firstChildElement( QStringLiteral( "StyledLayerDescriptor" ) );
1732  if ( myRoot.isNull() )
1733  {
1734  myErrorMessage = QStringLiteral( "Error: StyledLayerDescriptor element not found in %1" ).arg( uri );
1735  resultFlag = false;
1736  return myErrorMessage;
1737  }
1738 
1739  // now get the style node out and pass it over to the layer
1740  // to deserialise...
1741  const QDomElement namedLayerElem = myRoot.firstChildElement( QStringLiteral( "NamedLayer" ) );
1742  if ( namedLayerElem.isNull() )
1743  {
1744  myErrorMessage = QStringLiteral( "Info: NamedLayer element not found." );
1745  resultFlag = false;
1746  return myErrorMessage;
1747  }
1748 
1749  QString errorMsg;
1750  resultFlag = readSld( namedLayerElem, errorMsg );
1751  if ( !resultFlag )
1752  {
1753  myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( uri, errorMsg );
1754  return myErrorMessage;
1755  }
1756 
1757  return QString();
1758 }
1759 
1760 bool QgsMapLayer::readStyle( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
1761 {
1762  Q_UNUSED( node )
1763  Q_UNUSED( errorMessage )
1764  Q_UNUSED( context )
1765  Q_UNUSED( categories )
1766  return false;
1767 }
1768 
1769 bool QgsMapLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage,
1770  const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1771 {
1772  Q_UNUSED( node )
1773  Q_UNUSED( doc )
1774  Q_UNUSED( errorMessage )
1775  Q_UNUSED( context )
1776  Q_UNUSED( categories )
1777  return false;
1778 }
1779 
1780 
1781 void QgsMapLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider,
1782  bool loadDefaultStyleFlag )
1783 {
1784  const QgsDataProvider::ProviderOptions options;
1785 
1786  QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags();
1787  if ( loadDefaultStyleFlag )
1788  {
1790  }
1791 
1793  {
1795  }
1796  setDataSource( dataSource, baseName, provider, options, flags );
1797 }
1798 
1799 void QgsMapLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider,
1800  const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag )
1801 {
1802  QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags();
1803  if ( loadDefaultStyleFlag )
1804  {
1806  }
1807 
1809  {
1811  }
1812  setDataSource( dataSource, baseName, provider, options, flags );
1813 }
1814 
1815 void QgsMapLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider,
1816  const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
1817 {
1818 
1821  {
1823  }
1824  setDataSourcePrivate( dataSource, baseName, provider, options, flags );
1825  emit dataSourceChanged();
1826  emit dataChanged();
1827  triggerRepaint();
1828 }
1829 
1830 
1831 void QgsMapLayer::setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider,
1832  const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
1833 {
1834  Q_UNUSED( dataSource )
1835  Q_UNUSED( baseName )
1836  Q_UNUSED( provider )
1837  Q_UNUSED( options )
1838  Q_UNUSED( flags )
1839 }
1840 
1841 
1843 {
1844  return mProviderKey;
1845 }
1846 
1847 void QgsMapLayer::readCommonStyle( const QDomElement &layerElement, const QgsReadWriteContext &context,
1848  QgsMapLayer::StyleCategories categories )
1849 {
1850  if ( categories.testFlag( Symbology3D ) )
1851  {
1852  const QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "3D Symbology" ) );
1853 
1854  QgsAbstract3DRenderer *r3D = nullptr;
1855  QDomElement renderer3DElem = layerElement.firstChildElement( QStringLiteral( "renderer-3d" ) );
1856  if ( !renderer3DElem.isNull() )
1857  {
1858  const QString type3D = renderer3DElem.attribute( QStringLiteral( "type" ) );
1860  if ( meta3D )
1861  {
1862  r3D = meta3D->createRenderer( renderer3DElem, context );
1863  }
1864  }
1865  setRenderer3D( r3D );
1866  }
1867 
1868  if ( categories.testFlag( CustomProperties ) )
1869  {
1870  // read custom properties before passing reading further to a subclass, so that
1871  // the subclass can also read custom properties
1872  readCustomProperties( layerElement );
1873  }
1874 
1875  // use scale dependent visibility flag
1876  if ( categories.testFlag( Rendering ) )
1877  {
1878  setScaleBasedVisibility( layerElement.attribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ) ).toInt() == 1 );
1879  if ( layerElement.hasAttribute( QStringLiteral( "minimumScale" ) ) )
1880  {
1881  // older element, when scales were reversed
1882  setMaximumScale( layerElement.attribute( QStringLiteral( "minimumScale" ) ).toDouble() );
1883  setMinimumScale( layerElement.attribute( QStringLiteral( "maximumScale" ) ).toDouble() );
1884  }
1885  else
1886  {
1887  setMaximumScale( layerElement.attribute( QStringLiteral( "maxScale" ) ).toDouble() );
1888  setMinimumScale( layerElement.attribute( QStringLiteral( "minScale" ) ).toDouble() );
1889  }
1890  }
1891 
1892  if ( categories.testFlag( LayerConfiguration ) )
1893  {
1894  // flags
1895  const QDomElement flagsElem = layerElement.firstChildElement( QStringLiteral( "flags" ) );
1896  LayerFlags flags = mFlags;
1897  const auto enumMap = qgsEnumMap<QgsMapLayer::LayerFlag>();
1898  for ( auto it = enumMap.constBegin(); it != enumMap.constEnd(); ++it )
1899  {
1900  const QDomNode flagNode = flagsElem.namedItem( it.value() );
1901  if ( flagNode.isNull() )
1902  continue;
1903  const bool flagValue = flagNode.toElement().text() == "1" ? true : false;
1904  if ( flags.testFlag( it.key() ) && !flagValue )
1905  flags &= ~it.key();
1906  else if ( !flags.testFlag( it.key() ) && flagValue )
1907  flags |= it.key();
1908  }
1909  setFlags( flags );
1910  }
1911 
1912  if ( categories.testFlag( Temporal ) )
1913  {
1914  const QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Temporal" ) );
1915 
1917  properties->readXml( layerElement.toElement(), context );
1918  }
1919 
1920  if ( categories.testFlag( Elevation ) )
1921  {
1922  const QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Elevation" ) );
1923 
1925  properties->readXml( layerElement.toElement(), context );
1926  }
1927 
1928  if ( categories.testFlag( Notes ) )
1929  {
1930  const QDomElement notesElem = layerElement.firstChildElement( QStringLiteral( "userNotes" ) );
1931  if ( !notesElem.isNull() )
1932  {
1933  const QString notes = notesElem.attribute( QStringLiteral( "value" ) );
1934  QgsLayerNotesUtils::setLayerNotes( this, notes );
1935  }
1936  }
1937 }
1938 
1940 {
1941  return mUndoStack;
1942 }
1943 
1945 {
1946  return mUndoStackStyles;
1947 }
1948 
1950 {
1951  return mCustomProperties.keys();
1952 }
1953 
1954 void QgsMapLayer::setCustomProperty( const QString &key, const QVariant &value )
1955 {
1956  if ( !mCustomProperties.contains( key ) || mCustomProperties.value( key ) != value )
1957  {
1958  mCustomProperties.setValue( key, value );
1959  emit customPropertyChanged( key );
1960  }
1961 }
1962 
1964 {
1965  mCustomProperties = properties;
1966 }
1967 
1969 {
1970  return mCustomProperties;
1971 }
1972 
1973 QVariant QgsMapLayer::customProperty( const QString &value, const QVariant &defaultValue ) const
1974 {
1975  return mCustomProperties.value( value, defaultValue );
1976 }
1977 
1978 void QgsMapLayer::removeCustomProperty( const QString &key )
1979 {
1980 
1981  if ( mCustomProperties.contains( key ) )
1982  {
1983  mCustomProperties.remove( key );
1984  emit customPropertyChanged( key );
1985  }
1986 }
1987 
1989 {
1990  return mError;
1991 }
1992 
1993 
1994 
1996 {
1997  return false;
1998 }
1999 
2001 {
2002  return false;
2003 }
2004 
2006 {
2007  return true;
2008 }
2009 
2011 {
2012  // invalid layers are temporary? -- who knows?!
2013  if ( !isValid() )
2014  return false;
2015 
2016  if ( mProviderKey == QLatin1String( "memory" ) )
2017  return true;
2018 
2019  const QVariantMap sourceParts = QgsProviderRegistry::instance()->decodeUri( mProviderKey, mDataSource );
2020  const QString path = sourceParts.value( QStringLiteral( "path" ) ).toString();
2021  if ( path.isEmpty() )
2022  return false;
2023 
2024  // check if layer path is inside one of the standard temporary file locations for this platform
2025  const QStringList tempPaths = QStandardPaths::standardLocations( QStandardPaths::TempLocation );
2026  for ( const QString &tempPath : tempPaths )
2027  {
2028  if ( path.startsWith( tempPath ) )
2029  return true;
2030  }
2031 
2032  return false;
2033 }
2034 
2035 void QgsMapLayer::setValid( bool valid )
2036 {
2037  if ( mValid == valid )
2038  return;
2039 
2040  mValid = valid;
2041  emit isValidChanged();
2042 }
2043 
2045 {
2046  if ( legend == mLegend )
2047  return;
2048 
2049  delete mLegend;
2050  mLegend = legend;
2051 
2052  if ( mLegend )
2053  {
2054  mLegend->setParent( this );
2055  connect( mLegend, &QgsMapLayerLegend::itemsChanged, this, &QgsMapLayer::legendChanged, Qt::UniqueConnection );
2056  }
2057 
2058  emit legendChanged();
2059 }
2060 
2062 {
2063  return mLegend;
2064 }
2065 
2067 {
2068  return mStyleManager;
2069 }
2070 
2072 {
2073  if ( renderer == m3DRenderer )
2074  return;
2075 
2076  delete m3DRenderer;
2077  m3DRenderer = renderer;
2078  emit renderer3DChanged();
2079  emit repaintRequested();
2080  trigger3DUpdate();
2081 }
2082 
2084 {
2085  return m3DRenderer;
2086 }
2087 
2088 void QgsMapLayer::triggerRepaint( bool deferredUpdate )
2089 {
2090  if ( mRepaintRequestedFired )
2091  return;
2092  mRepaintRequestedFired = true;
2093  emit repaintRequested( deferredUpdate );
2094  mRepaintRequestedFired = false;
2095 }
2096 
2098 {
2099  emit request3DUpdate();
2100 }
2101 
2103 {
2104  mMetadata = metadata;
2105 // mMetadata.saveToLayer( this );
2106  emit metadataChanged();
2107 }
2108 
2110 {
2111  return QString();
2112 }
2113 
2114 QDateTime QgsMapLayer::timestamp() const
2115 {
2116  return QDateTime();
2117 }
2118 
2120 {
2121  if ( !mBlockStyleChangedSignal )
2122  emit styleChanged();
2123 }
2124 
2126 {
2127  updateExtent( extent );
2128 }
2129 
2130 bool QgsMapLayer::isReadOnly() const
2131 {
2132  return true;
2133 }
2134 
2136 {
2137  return mOriginalXmlProperties;
2138 }
2139 
2140 void QgsMapLayer::setOriginalXmlProperties( const QString &originalXmlProperties )
2141 {
2142  mOriginalXmlProperties = originalXmlProperties;
2143 }
2144 
2145 QString QgsMapLayer::generateId( const QString &layerName )
2146 {
2147  // Generate the unique ID of this layer
2148  const QString uuid = QUuid::createUuid().toString();
2149  // trim { } from uuid
2150  QString id = layerName + '_' + uuid.mid( 1, uuid.length() - 2 );
2151  // Tidy the ID up to avoid characters that may cause problems
2152  // elsewhere (e.g in some parts of XML). Replaces every non-word
2153  // character (word characters are the alphabet, numbers and
2154  // underscore) with an underscore.
2155  // Note that the first backslash in the regular expression is
2156  // there for the compiler, so the pattern is actually \W
2157  id.replace( QRegularExpression( "[\\W]" ), QStringLiteral( "_" ) );
2158  return id;
2159 }
2160 
2162 {
2163  return true;
2164 }
2165 
2166 void QgsMapLayer::setProviderType( const QString &providerType )
2167 {
2169 }
2170 
2171 QSet<QgsMapLayerDependency> QgsMapLayer::dependencies() const
2172 {
2173  return mDependencies;
2174 }
2175 
2176 bool QgsMapLayer::setDependencies( const QSet<QgsMapLayerDependency> &oDeps )
2177 {
2178  QSet<QgsMapLayerDependency> deps;
2179  const auto constODeps = oDeps;
2180  for ( const QgsMapLayerDependency &dep : constODeps )
2181  {
2182  if ( dep.origin() == QgsMapLayerDependency::FromUser )
2183  deps << dep;
2184  }
2185 
2186  mDependencies = deps;
2187  emit dependenciesChanged();
2188  return true;
2189 }
2190 
2192 {
2193  QgsDataProvider *lDataProvider = dataProvider();
2194 
2195  if ( !lDataProvider )
2196  return;
2197 
2198  if ( enabled && !isRefreshOnNotifyEnabled() )
2199  {
2200  lDataProvider->setListening( enabled );
2201  connect( lDataProvider, &QgsDataProvider::notify, this, &QgsMapLayer::onNotified );
2202  }
2203  else if ( !enabled && isRefreshOnNotifyEnabled() )
2204  {
2205  // we don't want to disable provider listening because someone else could need it (e.g. actions)
2206  disconnect( lDataProvider, &QgsDataProvider::notify, this, &QgsMapLayer::onNotified );
2207  }
2208  mIsRefreshOnNofifyEnabled = enabled;
2209 }
2210 
2212 {
2213  if ( QgsMapLayerStore *store = qobject_cast<QgsMapLayerStore *>( parent() ) )
2214  {
2215  return qobject_cast<QgsProject *>( store->parent() );
2216  }
2217  return nullptr;
2218 }
2219 
2220 void QgsMapLayer::onNotified( const QString &message )
2221 {
2222  if ( refreshOnNotifyMessage().isEmpty() || refreshOnNotifyMessage() == message )
2223  {
2224  triggerRepaint();
2225  emit dataChanged();
2226  }
2227 }
2228 
2229 QgsRectangle QgsMapLayer::wgs84Extent( bool forceRecalculate ) const
2230 {
2232 
2233  if ( ! forceRecalculate && ! mWgs84Extent.isNull() )
2234  {
2235  wgs84Extent = mWgs84Extent;
2236  }
2237  else if ( ! mExtent.isNull() )
2238  {
2240  try
2241  {
2242  wgs84Extent = transformer.transformBoundingBox( mExtent );
2243  }
2244  catch ( const QgsCsException &cse )
2245  {
2246  QgsMessageLog::logMessage( tr( "Error transforming extent: %1" ).arg( cse.what() ) );
2248  }
2249  }
2250  return wgs84Extent;
2251 }
2252 
2253 void QgsMapLayer::updateExtent( const QgsRectangle &extent ) const
2254 {
2255  if ( extent == mExtent )
2256  return;
2257 
2258  mExtent = extent;
2259 
2260  // do not update the wgs84 extent if we trust layer metadata
2261  if ( mReadFlags & QgsMapLayer::ReadFlag::FlagTrustLayerMetadata )
2262  return;
2263 
2264  mWgs84Extent = wgs84Extent( true );
2265 }
2266 
2268 {
2269  // do not update the wgs84 extent if we trust layer metadata
2270  if ( mReadFlags & QgsMapLayer::ReadFlag::FlagTrustLayerMetadata )
2271  return;
2272 
2273  mWgs84Extent = QgsRectangle();
2274 }
2275 
2277 {
2278  QString metadata = QStringLiteral( "<h1>" ) + tr( "General" ) + QStringLiteral( "</h1>\n<hr>\n" ) + QStringLiteral( "<table class=\"list-view\">\n" );
2279 
2280  // name
2281  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Name" ) + QStringLiteral( "</td><td>" ) + name() + QStringLiteral( "</td></tr>\n" );
2282 
2283  QString path;
2284  bool isLocalPath = false;
2285  if ( dataProvider() )
2286  {
2287  // local path
2288  QVariantMap uriComponents = QgsProviderRegistry::instance()->decodeUri( dataProvider()->name(), publicSource() );
2289  if ( uriComponents.contains( QStringLiteral( "path" ) ) )
2290  {
2291  path = uriComponents[QStringLiteral( "path" )].toString();
2292  QFileInfo fi( path );
2293  if ( fi.exists() )
2294  {
2295  isLocalPath = true;
2296  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Path" ) + QStringLiteral( "</td><td>%1" ).arg( QStringLiteral( "<a href=\"%1\">%2</a>" ).arg( QUrl::fromLocalFile( path ).toString(), QDir::toNativeSeparators( path ) ) ) + QStringLiteral( "</td></tr>\n" );
2297 
2298  QDateTime lastModified = fi.lastModified();
2299  QString lastModifiedFileName;
2300  QSet<QString> sidecarFiles = QgsFileUtils::sidecarFilesForPath( path );
2301  if ( fi.isFile() )
2302  {
2303  qint64 fileSize = fi.size();
2304  if ( !sidecarFiles.isEmpty() )
2305  {
2306  lastModifiedFileName = fi.fileName();
2307  QStringList sidecarFileNames;
2308  for ( const QString &sidecarFile : sidecarFiles )
2309  {
2310  QFileInfo sidecarFi( sidecarFile );
2311  fileSize += sidecarFi.size();
2312  if ( sidecarFi.lastModified() > lastModified )
2313  {
2314  lastModified = sidecarFi.lastModified();
2315  lastModifiedFileName = sidecarFi.fileName();
2316  }
2317  sidecarFileNames << sidecarFi.fileName();
2318  }
2319  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + ( sidecarFiles.size() > 1 ? tr( "Sidecar files" ) : tr( "Sidecar file" ) ) + QStringLiteral( "</td><td>%1" ).arg( sidecarFileNames.join( QLatin1String( ", " ) ) ) + QStringLiteral( "</td></tr>\n" );
2320  }
2321  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + ( !sidecarFiles.isEmpty() ? tr( "Total size" ) : tr( "Size" ) ) + QStringLiteral( "</td><td>%1" ).arg( QgsFileUtils::representFileSize( fileSize ) ) + QStringLiteral( "</td></tr>\n" );
2322  }
2323  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Last modified" ) + QStringLiteral( "</td><td>%1" ).arg( QLocale().toString( fi.lastModified() ) ) + ( !lastModifiedFileName.isEmpty() ? QStringLiteral( " (%1)" ).arg( lastModifiedFileName ) : QString() ) + QStringLiteral( "</td></tr>\n" );
2324  }
2325  }
2326  if ( uriComponents.contains( QStringLiteral( "url" ) ) )
2327  {
2328  const QString url = uriComponents[QStringLiteral( "url" )].toString();
2329  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "URL" ) + QStringLiteral( "</td><td>%1" ).arg( QStringLiteral( "<a href=\"%1\">%2</a>" ).arg( QUrl( url ).toString(), url ) ) + QStringLiteral( "</td></tr>\n" );
2330  }
2331  }
2332 
2333  // data source
2334  if ( publicSource() != path || !isLocalPath )
2335  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Source" ) + QStringLiteral( "</td><td>%1" ).arg( publicSource() != path ? publicSource() : path ) + QStringLiteral( "</td></tr>\n" );
2336 
2337  // provider
2338  if ( dataProvider() )
2339  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Provider" ) + QStringLiteral( "</td><td>%1" ).arg( dataProvider()->name() ) + QStringLiteral( "</td></tr>\n" );
2340 
2341  metadata += QStringLiteral( "</table>\n<br><br>" );
2342  return metadata;
2343 }
2344 
2346 {
2347  QString metadata = QStringLiteral( "<h1>" ) + tr( "Coordinate Reference System (CRS)" ) + QStringLiteral( "</h1>\n<hr>\n" );
2348  metadata += QLatin1String( "<table class=\"list-view\">\n" );
2349 
2350  // Identifier
2352  if ( !c.isValid() )
2353  metadata += QStringLiteral( "<tr><td colspan=\"2\" class=\"highlight\">" ) + tr( "Unknown" ) + QStringLiteral( "</td></tr>\n" );
2354  else
2355  {
2356  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Name" ) + QStringLiteral( "</td><td>" ) + c.userFriendlyIdentifier( QgsCoordinateReferenceSystem::FullString ) + QStringLiteral( "</td></tr>\n" );
2357 
2358  // map units
2359  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Units" ) + QStringLiteral( "</td><td>" )
2360  + ( c.isGeographic() ? tr( "Geographic (uses latitude and longitude for coordinates)" ) : QgsUnitTypes::toString( c.mapUnits() ) )
2361  + QStringLiteral( "</td></tr>\n" );
2362 
2363 
2364  // operation
2365  const QgsProjOperation operation = c.operation();
2366  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Method" ) + QStringLiteral( "</td><td>" ) + operation.description() + QStringLiteral( "</td></tr>\n" );
2367 
2368  // celestial body
2369  try
2370  {
2371  const QString celestialBody = c.celestialBodyName();
2372  if ( !celestialBody.isEmpty() )
2373  {
2374  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Celestial body" ) + QStringLiteral( "</td><td>" ) + celestialBody + QStringLiteral( "</td></tr>\n" );
2375  }
2376  }
2377  catch ( QgsNotSupportedException & )
2378  {
2379 
2380  }
2381 
2382  QString accuracyString;
2383  // dynamic crs with no epoch?
2384  if ( c.isDynamic() && std::isnan( c.coordinateEpoch() ) )
2385  {
2386  accuracyString = tr( "Based on a dynamic CRS, but no coordinate epoch is set. Coordinates are ambiguous and of limited accuracy." );
2387  }
2388 
2389  // based on datum ensemble?
2390  try
2391  {
2392  const QgsDatumEnsemble ensemble = c.datumEnsemble();
2393  if ( ensemble.isValid() )
2394  {
2395  QString id;
2396  if ( !ensemble.code().isEmpty() )
2397  id = QStringLiteral( "<i>%1</i> (%2:%3)" ).arg( ensemble.name(), ensemble.authority(), ensemble.code() );
2398  else
2399  id = QStringLiteral( "<i>%</i>”" ).arg( ensemble.name() );
2400 
2401  if ( ensemble.accuracy() > 0 )
2402  {
2403  accuracyString = tr( "Based on %1, which has a limited accuracy of <b>at best %2 meters</b>." ).arg( id ).arg( ensemble.accuracy() );
2404  }
2405  else
2406  {
2407  accuracyString = tr( "Based on %1, which has a limited accuracy." ).arg( id );
2408  }
2409  }
2410  }
2411  catch ( QgsNotSupportedException & )
2412  {
2413 
2414  }
2415 
2416  if ( !accuracyString.isEmpty() )
2417  {
2418  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Accuracy" ) + QStringLiteral( "</td><td>" ) + accuracyString + QStringLiteral( "</td></tr>\n" );
2419  }
2420 
2421  // static/dynamic
2422  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)" ) );
2423 
2424  // coordinate epoch
2425  if ( !std::isnan( c.coordinateEpoch() ) )
2426  {
2427  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Coordinate epoch" ) + QStringLiteral( "</td><td>%1</td></tr>\n" ).arg( c.coordinateEpoch() );
2428  }
2429  }
2430 
2431  metadata += QLatin1String( "</table>\n<br><br>\n" );
2432  return metadata;
2433 }
static QString version()
Version string.
Definition: qgis.cpp:285
static const double SCALE_PRECISION
Fudge factor used to compare two scales.
Definition: qgis.h:921
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
static QSet< QString > sidecarFilesForPath(const QString &path)
Returns a list of the sidecar files which exist for the dataset a the specified path.
static QString representFileSize(qint64 bytes)
Returns the human size from bytes.
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.
Manages QGIS Server properties for a map layer.
void readXml(const QDomNode &layer_node)
Reads server properties from project file.
void copyTo(QgsMapLayerServerProperties *properties) const
Copy properties to another instance.
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:72
QString mKeywordList
Definition: qgsmaplayer.h:1934
void setShortName(const QString &shortName)
Sets the short name of the layer used by QGIS Server to identify the layer.
Definition: qgsmaplayer.h:284
bool importNamedMetadata(QDomDocument &document, QString &errorMessage)
Import the metadata of this layer from a QDomDocument.
QString name
Definition: qgsmaplayer.h:75
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 document provided.
QString legendUrlFormat() const
Returns the format for a URL based layer legend.
Definition: qgsmaplayer.h:1280
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:314
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:1265
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:1949
int mBlockStyleChangedSignal
If non-zero, the styleChanged signal should not be emitted.
Definition: qgsmaplayer.h:1991
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:79
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:81
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:78
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:396
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:1962
QString mLegendUrl
WMS legend.
Definition: qgsmaplayer.h:1945
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:1927
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:405
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:77
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:376
QgsMapLayerServerProperties * serverProperties()
Returns QGIS Server Properties for the map layer.
Definition: qgsmaplayer.h:422
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
QString mTitle
Definition: qgsmaplayer.h:1930
void setDataUrl(const QString &dataUrl)
Sets the DataUrl of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:349
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:330
void setAttribution(const QString &attrib)
Sets the attribution of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:387
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:1442
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:1952
void readCustomProperties(const QDomNode &layerNode, const QString &keyStartsWith=QString())
Read custom properties from project file.
virtual Qgis::MapLayerProperties properties() const
Returns the map layer properties of this layer.
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 ...
virtual bool supportsEditing() const
Returns whether the layer supports editing or not.
void setDataUrlFormat(const QString &dataUrlFormat)
Sets the DataUrl format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:367
QString mLegendUrlFormat
Definition: qgsmaplayer.h:1946
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:1965
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:306
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:1942
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:358
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.
Q_DECL_DEPRECATED QString metadataUrlFormat() const
Returns the metadata format of the layer used by QGIS Server in GetCapabilities request.
void setRefreshOnNofifyMessage(const QString &message)
Set the notification message that triggers repaint If refresh on notification is enabled,...
Definition: qgsmaplayer.h:1589
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 (...
virtual bool isModified() const
Returns true if the layer has been modified since last commit/save.
void emitStyleChanged()
Triggers an emission of the styleChanged() signal.
QString mShortName
Definition: qgsmaplayer.h:1929
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.
virtual QString htmlMetadata() const
Obtain a formatted HTML string containing assorted metadata for this layer.
Q_DECL_DEPRECATED void setMetadataUrlFormat(const QString &metaUrlFormat)
Sets the metadata format of the layer used by QGIS Server in GetCapabilities request.
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:68
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.
Q_DECL_DEPRECATED QString metadataUrl() const
Returns the metadata URL of the layer used by QGIS Server in GetCapabilities request.
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:80
QString mDataSource
Data source description string, varies by layer type.
Definition: qgsmaplayer.h:1924
QString refreshOnNotifyMessage() const
Returns the message that should be notified by the provider to triggerRepaint.
Definition: qgsmaplayer.h:1435
virtual bool readSld(const QDomNode &node, QString &errorMessage)
Definition: qgsmaplayer.h:1143
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:638
@ FlagTrustLayerMetadata
Trust layer metadata. Improves layer load time by skipping expensive checks like primary key unicity,...
Definition: qgsmaplayer.h:637
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:414
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:1933
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:1970
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:1270
QString mDataUrlFormat
Definition: qgsmaplayer.h:1938
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:1275
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...
Q_DECL_DEPRECATED void setMetadataUrl(const QString &metaUrl)
Sets the metadata URL of the layer used by QGIS Server in GetCapabilities request.
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.
Q_DECL_DEPRECATED void setMetadataUrlType(const QString &metaUrlType)
Set the metadata type of the layer used by QGIS Server in GetCapabilities request MetadataUrlType ind...
void setLegend(QgsMapLayerLegend *legend)
Assign a legend controller to the map layer.
virtual QgsMapLayerElevationProperties * elevationProperties()
Returns the layer's elevation properties.
Definition: qgsmaplayer.h:1492
double opacity
Definition: qgsmaplayer.h:81
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:76
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:1961
QString mDataUrl
DataUrl of the layer.
Definition: qgsmaplayer.h:1937
virtual Q_INVOKABLE QgsDataProvider * dataProvider()
Returns the layer's data provider, it may be nullptr.
double mLayerOpacity
Layer opacity.
Definition: qgsmaplayer.h:1984
bool mValid
Indicates if the layer is valid and can be drawn.
Definition: qgsmaplayer.h:1921
@ AllStyleCategories
Definition: qgsmaplayer.h:174
@ LayerConfiguration
General configuration: identifiable, removable, searchable, display expression, read-only.
Definition: qgsmaplayer.h:156
@ Symbology
Symbology.
Definition: qgsmaplayer.h:157
@ Notes
Layer user notes (since QGIS 3.20)
Definition: qgsmaplayer.h:173
@ Temporal
Temporal properties (since QGIS 3.14)
Definition: qgsmaplayer.h:170
@ Rendering
Rendering: scale visibility, simplify method, opacity.
Definition: qgsmaplayer.h:166
@ Elevation
Elevation settings (since QGIS 3.18)
Definition: qgsmaplayer.h:172
@ Symbology3D
3D symbology
Definition: qgsmaplayer.h:158
@ CustomProperties
Custom properties (by plugins for instance)
Definition: qgsmaplayer.h:167
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:1485
void setRenderer3D(QgsAbstract3DRenderer *renderer)
Sets 3D renderer for the layer.
QString mAttribution
Attribution of the layer.
Definition: qgsmaplayer.h:1941
~QgsMapLayer() override
Definition: qgsmaplayer.cpp:99
const QgsObjectCustomProperties & customProperties() const
Read all custom properties from layer.
QString generalHtmlMetadata() const
Returns an HTML fragment containing general metadata information, for use in the htmlMetadata() metho...
Q_DECL_DEPRECATED QString metadataUrlType() const
Returns the metadata type of the layer used by QGIS Server in GetCapabilities request.
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:338
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:298
PropertyType
Maplayer has a style and a metadata property.
Definition: qgsmaplayer.h:129
bool mShouldValidateCrs
true if the layer's CRS should be validated and invalid CRSes are not permitted.
Definition: qgsmaplayer.h:1977
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.
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
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:101
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.
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
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
void setMetadataUrls(const QList< QgsServerMetadataUrlProperties::MetadataUrl > &metaUrls)
Sets a the list of metadata URL for the layer.
QList< QgsServerMetadataUrlProperties::MetadataUrl > metadataUrls() const
Returns a list of metadataUrl resources associated for the layer.
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:47
@ 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:1133
CONSTLATIN1STRING geoEpsgCrsAuthId()
Geographic coord sys from EPSG authority.
Definition: qgis.h:1541
void(* CUSTOM_CRS_VALIDATION)(QgsCoordinateReferenceSystem &)
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
Setting options for creating vector data providers.
QString format
Format specification of online resource.