QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
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  const QgsObjectCustomProperties oldKeys = mCustomProperties;
778 
779  mCustomProperties.readXml( layerNode, keyStartsWith );
780 
781  for ( const QString &key : mCustomProperties.keys() )
782  {
783  if ( !oldKeys.contains( key ) || mCustomProperties.value( key ) != oldKeys.value( key ) )
784  {
785  emit customPropertyChanged( key );
786  }
787  }
788 }
789 
790 void QgsMapLayer::writeCustomProperties( QDomNode &layerNode, QDomDocument &doc ) const
791 {
792  mCustomProperties.writeXml( layerNode, doc );
793 }
794 
795 void QgsMapLayer::readStyleManager( const QDomNode &layerNode )
796 {
797  const QDomElement styleMgrElem = layerNode.firstChildElement( QStringLiteral( "map-layer-style-manager" ) );
798  if ( !styleMgrElem.isNull() )
799  mStyleManager->readXml( styleMgrElem );
800  else
801  mStyleManager->reset();
802 }
803 
804 void QgsMapLayer::writeStyleManager( QDomNode &layerNode, QDomDocument &doc ) const
805 {
806  if ( mStyleManager )
807  {
808  QDomElement styleMgrElem = doc.createElement( QStringLiteral( "map-layer-style-manager" ) );
809  mStyleManager->writeXml( styleMgrElem );
810  layerNode.appendChild( styleMgrElem );
811  }
812 }
813 
815 {
816  return mValid;
817 }
818 
819 #if 0
820 void QgsMapLayer::connectNotify( const char *signal )
821 {
822  Q_UNUSED( signal )
823  QgsDebugMsgLevel( "QgsMapLayer connected to " + QString( signal ), 3 );
824 } // QgsMapLayer::connectNotify
825 #endif
826 
827 bool QgsMapLayer::isInScaleRange( double scale ) const
828 {
829  return !mScaleBasedVisibility ||
830  ( ( mMinScale == 0 || mMinScale * Qgis::SCALE_PRECISION < scale )
831  && ( mMaxScale == 0 || scale < mMaxScale ) );
832 }
833 
835 {
836  return mScaleBasedVisibility;
837 }
838 
840 {
841  return mRefreshTimer->isActive();
842 }
843 
845 {
846  return mRefreshTimer->interval();
847 }
848 
850 {
851  if ( interval <= 0 )
852  {
853  mRefreshTimer->stop();
854  mRefreshTimer->setInterval( 0 );
855  }
856  else
857  {
858  mRefreshTimer->setInterval( interval );
859  }
860  emit autoRefreshIntervalChanged( mRefreshTimer->isActive() ? mRefreshTimer->interval() : 0 );
861 }
862 
864 {
865  if ( !enabled )
866  mRefreshTimer->stop();
867  else if ( mRefreshTimer->interval() > 0 )
868  mRefreshTimer->start();
869 
870  emit autoRefreshIntervalChanged( mRefreshTimer->isActive() ? mRefreshTimer->interval() : 0 );
871 }
872 
874 {
875  return mMetadata;
876 }
877 
878 void QgsMapLayer::setMaximumScale( double scale )
879 {
880  mMinScale = scale;
881 }
882 
884 {
885  return mMinScale;
886 }
887 
888 
889 void QgsMapLayer::setMinimumScale( double scale )
890 {
891  mMaxScale = scale;
892 }
893 
894 void QgsMapLayer::setScaleBasedVisibility( const bool enabled )
895 {
896  mScaleBasedVisibility = enabled;
897 }
898 
900 {
901  return mMaxScale;
902 }
903 
904 QStringList QgsMapLayer::subLayers() const
905 {
906  return QStringList(); // Empty
907 }
908 
909 void QgsMapLayer::setLayerOrder( const QStringList &layers )
910 {
911  Q_UNUSED( layers )
912  // NOOP
913 }
914 
915 void QgsMapLayer::setSubLayerVisibility( const QString &name, bool vis )
916 {
917  Q_UNUSED( name )
918  Q_UNUSED( vis )
919  // NOOP
920 }
921 
923 {
924  return false;
925 }
926 
928 {
929  return mCRS;
930 }
931 
932 void QgsMapLayer::setCrs( const QgsCoordinateReferenceSystem &srs, bool emitSignal )
933 {
934  mCRS = srs;
935 
937  {
938  mCRS.setValidationHint( tr( "Specify CRS for layer %1" ).arg( name() ) );
939  mCRS.validate();
940  }
941 
942  if ( emitSignal )
943  emit crsChanged();
944 }
945 
947 {
948  const QgsDataProvider *lDataProvider = dataProvider();
949  return lDataProvider ? lDataProvider->transformContext() : QgsCoordinateTransformContext();
950 }
951 
952 QString QgsMapLayer::formatLayerName( const QString &name )
953 {
954  QString layerName( name );
955  layerName.replace( '_', ' ' );
957  return layerName;
958 }
959 
960 QString QgsMapLayer::baseURI( PropertyType type ) const
961 {
962  QString myURI = publicSource();
963 
964  // first get base path for delimited text, spatialite and OGR layers,
965  // as in these cases URI may contain layer name and/or additional
966  // information. This also strips prefix in case if VSIFILE mechanism
967  // is used
968  if ( providerType() == QLatin1String( "ogr" ) || providerType() == QLatin1String( "delimitedtext" ) ||
969  providerType() == QLatin1String( "spatialite" ) )
970  {
971  QVariantMap components = QgsProviderRegistry::instance()->decodeUri( providerType(), myURI );
972  myURI = components["path"].toString();
973  }
974 
975  QFileInfo myFileInfo( myURI );
976  QString key;
977 
978  if ( myFileInfo.exists() )
979  {
980  // if file is using the /vsizip/ or /vsigzip/ mechanism, cleanup the name
981  if ( myURI.endsWith( QLatin1String( ".gz" ), Qt::CaseInsensitive ) )
982  myURI.chop( 3 );
983  else if ( myURI.endsWith( QLatin1String( ".zip" ), Qt::CaseInsensitive ) )
984  myURI.chop( 4 );
985  else if ( myURI.endsWith( QLatin1String( ".tar" ), Qt::CaseInsensitive ) )
986  myURI.chop( 4 );
987  else if ( myURI.endsWith( QLatin1String( ".tar.gz" ), Qt::CaseInsensitive ) )
988  myURI.chop( 7 );
989  else if ( myURI.endsWith( QLatin1String( ".tgz" ), Qt::CaseInsensitive ) )
990  myURI.chop( 4 );
991  myFileInfo.setFile( myURI );
992  // get the file name for our .qml style file
993  key = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + QgsMapLayer::extensionPropertyType( type );
994  }
995  else
996  {
997  key = publicSource();
998  }
999 
1000  return key;
1001 }
1002 
1004 {
1005  return baseURI( PropertyType::Metadata );
1006 }
1007 
1008 QString QgsMapLayer::saveDefaultMetadata( bool &resultFlag )
1009 {
1010  if ( const QgsProviderMetadata *metadata = QgsProviderRegistry::instance()->providerMetadata( providerType() ) )
1011  {
1012  if ( metadata->providerCapabilities() & QgsProviderMetadata::SaveLayerMetadata )
1013  {
1014  try
1015  {
1016  QString errorMessage;
1017  resultFlag = QgsProviderRegistry::instance()->saveLayerMetadata( providerType(), mDataSource, mMetadata, errorMessage );
1018  if ( resultFlag )
1019  return tr( "Successfully saved default layer metadata" );
1020  else
1021  return errorMessage;
1022  }
1023  catch ( QgsNotSupportedException &e )
1024  {
1025  resultFlag = false;
1026  return e.what();
1027  }
1028  }
1029  }
1030 
1031  // fallback default metadata saving method, for providers which don't support (or implement) saveLayerMetadata
1032  return saveNamedMetadata( metadataUri(), resultFlag );
1033 }
1034 
1035 QString QgsMapLayer::loadDefaultMetadata( bool &resultFlag )
1036 {
1037  return loadNamedMetadata( metadataUri(), resultFlag );
1038 }
1039 
1040 QString QgsMapLayer::styleURI() const
1041 {
1042  return baseURI( PropertyType::Style );
1043 }
1044 
1045 QString QgsMapLayer::loadDefaultStyle( bool &resultFlag )
1046 {
1047  return loadNamedStyle( styleURI(), resultFlag );
1048 }
1049 
1050 bool QgsMapLayer::loadNamedMetadataFromDatabase( const QString &db, const QString &uri, QString &qmd )
1051 {
1052  return loadNamedPropertyFromDatabase( db, uri, qmd, PropertyType::Metadata );
1053 }
1054 
1055 bool QgsMapLayer::loadNamedStyleFromDatabase( const QString &db, const QString &uri, QString &qml )
1056 {
1057  return loadNamedPropertyFromDatabase( db, uri, qml, PropertyType::Style );
1058 }
1059 
1060 bool QgsMapLayer::loadNamedPropertyFromDatabase( const QString &db, const QString &uri, QString &xml, QgsMapLayer::PropertyType type )
1061 {
1062  QgsDebugMsgLevel( QStringLiteral( "db = %1 uri = %2" ).arg( db, uri ), 4 );
1063 
1064  bool resultFlag = false;
1065 
1066  // read from database
1067  sqlite3_database_unique_ptr database;
1068  sqlite3_statement_unique_ptr statement;
1069 
1070  int myResult;
1071 
1072  QgsDebugMsgLevel( QStringLiteral( "Trying to load style or metadata for \"%1\" from \"%2\"" ).arg( uri, db ), 4 );
1073 
1074  if ( db.isEmpty() || !QFile( db ).exists() )
1075  return false;
1076 
1077  myResult = database.open_v2( db, SQLITE_OPEN_READONLY, nullptr );
1078  if ( myResult != SQLITE_OK )
1079  {
1080  return false;
1081  }
1082 
1083  QString mySql;
1084  switch ( type )
1085  {
1086  case Metadata:
1087  mySql = QStringLiteral( "select qmd from tbl_metadata where metadata=?" );
1088  break;
1089 
1090  case Style:
1091  mySql = QStringLiteral( "select qml from tbl_styles where style=?" );
1092  break;
1093  }
1094 
1095  statement = database.prepare( mySql, myResult );
1096  if ( myResult == SQLITE_OK )
1097  {
1098  QByteArray param = uri.toUtf8();
1099 
1100  if ( sqlite3_bind_text( statement.get(), 1, param.data(), param.length(), SQLITE_STATIC ) == SQLITE_OK &&
1101  sqlite3_step( statement.get() ) == SQLITE_ROW )
1102  {
1103  xml = QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( statement.get(), 0 ) ) );
1104  resultFlag = true;
1105  }
1106  }
1107  return resultFlag;
1108 }
1109 
1110 
1111 QString QgsMapLayer::loadNamedStyle( const QString &uri, bool &resultFlag, QgsMapLayer::StyleCategories categories )
1112 {
1113  return loadNamedProperty( uri, PropertyType::Style, resultFlag, categories );
1114 }
1115 
1116 QString QgsMapLayer::loadNamedProperty( const QString &uri, QgsMapLayer::PropertyType type, bool &resultFlag, StyleCategories categories )
1117 {
1118  QgsDebugMsgLevel( QStringLiteral( "uri = %1 myURI = %2" ).arg( uri, publicSource() ), 4 );
1119 
1120  resultFlag = false;
1121 
1122  QDomDocument myDocument( QStringLiteral( "qgis" ) );
1123 
1124  // location of problem associated with errorMsg
1125  int line, column;
1126  QString myErrorMessage;
1127 
1128  QFile myFile( uri );
1129  if ( myFile.open( QFile::ReadOnly ) )
1130  {
1131  QgsDebugMsgLevel( QStringLiteral( "file found %1" ).arg( uri ), 2 );
1132  // read file
1133  resultFlag = myDocument.setContent( &myFile, &myErrorMessage, &line, &column );
1134  if ( !resultFlag )
1135  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1136  myFile.close();
1137  }
1138  else
1139  {
1140  const QFileInfo project( QgsProject::instance()->fileName() );
1141  QgsDebugMsgLevel( QStringLiteral( "project fileName: %1" ).arg( project.absoluteFilePath() ), 4 );
1142 
1143  QString xml;
1144  switch ( type )
1145  {
1146  case QgsMapLayer::Style:
1147  {
1148  if ( loadNamedStyleFromDatabase( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ), uri, xml ) ||
1149  ( project.exists() && loadNamedStyleFromDatabase( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), uri, xml ) ) ||
1150  loadNamedStyleFromDatabase( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( QStringLiteral( "resources/qgis.qmldb" ) ), uri, xml ) )
1151  {
1152  resultFlag = myDocument.setContent( xml, &myErrorMessage, &line, &column );
1153  if ( !resultFlag )
1154  {
1155  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1156  }
1157  }
1158  else
1159  {
1160  myErrorMessage = tr( "Style not found in database" );
1161  resultFlag = false;
1162  }
1163  break;
1164  }
1165  case QgsMapLayer::Metadata:
1166  {
1167  if ( loadNamedMetadataFromDatabase( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ), uri, xml ) ||
1168  ( project.exists() && loadNamedMetadataFromDatabase( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), uri, xml ) ) ||
1169  loadNamedMetadataFromDatabase( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( QStringLiteral( "resources/qgis.qmldb" ) ), uri, xml ) )
1170  {
1171  resultFlag = myDocument.setContent( xml, &myErrorMessage, &line, &column );
1172  if ( !resultFlag )
1173  {
1174  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1175  }
1176  }
1177  else
1178  {
1179  myErrorMessage = tr( "Metadata not found in database" );
1180  resultFlag = false;
1181  }
1182  break;
1183  }
1184  }
1185  }
1186 
1187  if ( !resultFlag )
1188  {
1189  return myErrorMessage;
1190  }
1191 
1192  switch ( type )
1193  {
1194  case QgsMapLayer::Style:
1195  resultFlag = importNamedStyle( myDocument, myErrorMessage, categories );
1196  if ( !resultFlag )
1197  myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( uri, myErrorMessage );
1198  break;
1199  case QgsMapLayer::Metadata:
1200  resultFlag = importNamedMetadata( myDocument, myErrorMessage );
1201  if ( !resultFlag )
1202  myErrorMessage = tr( "Loading metadata file %1 failed because:\n%2" ).arg( uri, myErrorMessage );
1203  break;
1204  }
1205  return myErrorMessage;
1206 }
1207 
1208 bool QgsMapLayer::importNamedMetadata( QDomDocument &document, QString &errorMessage )
1209 {
1210  const QDomElement myRoot = document.firstChildElement( QStringLiteral( "qgis" ) );
1211  if ( myRoot.isNull() )
1212  {
1213  errorMessage = tr( "Root <qgis> element could not be found" );
1214  return false;
1215  }
1216 
1217  return mMetadata.readMetadataXml( myRoot );
1218 }
1219 
1220 bool QgsMapLayer::importNamedStyle( QDomDocument &myDocument, QString &myErrorMessage, QgsMapLayer::StyleCategories categories )
1221 {
1222  const QDomElement myRoot = myDocument.firstChildElement( QStringLiteral( "qgis" ) );
1223  if ( myRoot.isNull() )
1224  {
1225  myErrorMessage = tr( "Root <qgis> element could not be found" );
1226  return false;
1227  }
1228 
1229  // get style file version string, if any
1230  const QgsProjectVersion fileVersion( myRoot.attribute( QStringLiteral( "version" ) ) );
1231  const QgsProjectVersion thisVersion( Qgis::version() );
1232 
1233  if ( thisVersion > fileVersion )
1234  {
1235  QgsProjectFileTransform styleFile( myDocument, fileVersion );
1236  styleFile.updateRevision( thisVersion );
1237  }
1238 
1239  // Get source categories
1240  const QgsMapLayer::StyleCategories sourceCategories = QgsXmlUtils::readFlagAttribute( myRoot, QStringLiteral( "styleCategories" ), QgsMapLayer::AllStyleCategories );
1241 
1242  //Test for matching geometry type on vector layers when applying, if geometry type is given in the style
1243  if ( ( sourceCategories.testFlag( QgsMapLayer::Symbology ) || sourceCategories.testFlag( QgsMapLayer::Symbology3D ) ) &&
1244  ( categories.testFlag( QgsMapLayer::Symbology ) || categories.testFlag( QgsMapLayer::Symbology3D ) ) )
1245  {
1246  if ( type() == QgsMapLayerType::VectorLayer && !myRoot.firstChildElement( QStringLiteral( "layerGeometryType" ) ).isNull() )
1247  {
1248  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( this );
1249  const QgsWkbTypes::GeometryType importLayerGeometryType = static_cast<QgsWkbTypes::GeometryType>( myRoot.firstChildElement( QStringLiteral( "layerGeometryType" ) ).text().toInt() );
1250  if ( importLayerGeometryType != QgsWkbTypes::GeometryType::UnknownGeometry && vl->geometryType() != importLayerGeometryType )
1251  {
1252  myErrorMessage = tr( "Cannot apply style with symbology to layer with a different geometry type" );
1253  return false;
1254  }
1255  }
1256  }
1257 
1259  return readSymbology( myRoot, myErrorMessage, context, categories ); // TODO: support relative paths in QML?
1260 }
1261 
1262 void QgsMapLayer::exportNamedMetadata( QDomDocument &doc, QString &errorMsg ) const
1263 {
1264  QDomImplementation DomImplementation;
1265  const QDomDocumentType documentType = DomImplementation.createDocumentType( QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
1266  QDomDocument myDocument( documentType );
1267 
1268  QDomElement myRootNode = myDocument.createElement( QStringLiteral( "qgis" ) );
1269  myRootNode.setAttribute( QStringLiteral( "version" ), Qgis::version() );
1270  myDocument.appendChild( myRootNode );
1271 
1272  if ( !mMetadata.writeMetadataXml( myRootNode, myDocument ) )
1273  {
1274  errorMsg = QObject::tr( "Could not save metadata" );
1275  return;
1276  }
1277 
1278  doc = myDocument;
1279 }
1280 
1281 void QgsMapLayer::exportNamedStyle( QDomDocument &doc, QString &errorMsg, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1282 {
1283  QDomImplementation DomImplementation;
1284  const QDomDocumentType documentType = DomImplementation.createDocumentType( QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
1285  QDomDocument myDocument( documentType );
1286 
1287  QDomElement myRootNode = myDocument.createElement( QStringLiteral( "qgis" ) );
1288  myRootNode.setAttribute( QStringLiteral( "version" ), Qgis::version() );
1289  myDocument.appendChild( myRootNode );
1290 
1291  if ( !writeSymbology( myRootNode, myDocument, errorMsg, context, categories ) ) // TODO: support relative paths in QML?
1292  {
1293  errorMsg = QObject::tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1294  return;
1295  }
1296 
1297  /*
1298  * Check to see if the layer is vector - in which case we should also export its geometryType
1299  * to avoid eventually pasting to a layer with a different geometry
1300  */
1302  {
1303  //Getting the selectionLayer geometry
1304  const QgsVectorLayer *vl = qobject_cast<const QgsVectorLayer *>( this );
1305  const QString geoType = QString::number( vl->geometryType() );
1306 
1307  //Adding geometryinformation
1308  QDomElement layerGeometryType = myDocument.createElement( QStringLiteral( "layerGeometryType" ) );
1309  const QDomText type = myDocument.createTextNode( geoType );
1310 
1311  layerGeometryType.appendChild( type );
1312  myRootNode.appendChild( layerGeometryType );
1313  }
1314 
1315  doc = myDocument;
1316 }
1317 
1318 QString QgsMapLayer::saveDefaultStyle( bool &resultFlag )
1319 {
1320  return saveNamedStyle( styleURI(), resultFlag );
1321 }
1322 
1323 QString QgsMapLayer::saveNamedMetadata( const QString &uri, bool &resultFlag )
1324 {
1325  return saveNamedProperty( uri, QgsMapLayer::Metadata, resultFlag );
1326 }
1327 
1328 QString QgsMapLayer::loadNamedMetadata( const QString &uri, bool &resultFlag )
1329 {
1330  return loadNamedProperty( uri, QgsMapLayer::Metadata, resultFlag );
1331 }
1332 
1333 QString QgsMapLayer::saveNamedProperty( const QString &uri, QgsMapLayer::PropertyType type, bool &resultFlag, StyleCategories categories )
1334 {
1335  // check if the uri is a file or ends with .qml/.qmd,
1336  // which indicates that it should become one
1337  // everything else goes to the database
1338  QString filename;
1339 
1340  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this );
1341  if ( vlayer && vlayer->providerType() == QLatin1String( "ogr" ) )
1342  {
1343  QStringList theURIParts = uri.split( '|' );
1344  filename = theURIParts[0];
1345  }
1346  else if ( vlayer && vlayer->providerType() == QLatin1String( "gpx" ) )
1347  {
1348  QStringList theURIParts = uri.split( '?' );
1349  filename = theURIParts[0];
1350  }
1351  else if ( vlayer && vlayer->providerType() == QLatin1String( "delimitedtext" ) )
1352  {
1353  filename = QUrl::fromEncoded( uri.toLatin1() ).toLocalFile();
1354  // toLocalFile() returns an empty string if theURI is a plain Windows-path, e.g. "C:/style.qml"
1355  if ( filename.isEmpty() )
1356  filename = uri;
1357  }
1358  else
1359  {
1360  filename = uri;
1361  }
1362 
1363  QString myErrorMessage;
1364  QDomDocument myDocument;
1365  switch ( type )
1366  {
1367  case Metadata:
1368  exportNamedMetadata( myDocument, myErrorMessage );
1369  break;
1370 
1371  case Style:
1372  const QgsReadWriteContext context;
1373  exportNamedStyle( myDocument, myErrorMessage, context, categories );
1374  break;
1375  }
1376 
1377  const QFileInfo myFileInfo( filename );
1378  if ( myFileInfo.exists() || filename.endsWith( QgsMapLayer::extensionPropertyType( type ), Qt::CaseInsensitive ) )
1379  {
1380  const QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
1381  if ( !myDirInfo.isWritable() )
1382  {
1383  return tr( "The directory containing your dataset needs to be writable!" );
1384  }
1385 
1386  // now construct the file name for our .qml or .qmd file
1387  const QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + QgsMapLayer::extensionPropertyType( type );
1388 
1389  QFile myFile( myFileName );
1390  if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
1391  {
1392  QTextStream myFileStream( &myFile );
1393  // save as utf-8 with 2 spaces for indents
1394  myDocument.save( myFileStream, 2 );
1395  myFile.close();
1396  resultFlag = true;
1397  switch ( type )
1398  {
1399  case Metadata:
1400  return tr( "Created default metadata file as %1" ).arg( myFileName );
1401 
1402  case Style:
1403  return tr( "Created default style file as %1" ).arg( myFileName );
1404  }
1405 
1406  }
1407  else
1408  {
1409  resultFlag = false;
1410  switch ( type )
1411  {
1412  case Metadata:
1413  return tr( "ERROR: Failed to created default metadata file as %1. Check file permissions and retry." ).arg( myFileName );
1414 
1415  case Style:
1416  return tr( "ERROR: Failed to created default style file as %1. Check file permissions and retry." ).arg( myFileName );
1417  }
1418  }
1419  }
1420  else
1421  {
1422  const QString qml = myDocument.toString();
1423 
1424  // read from database
1425  sqlite3_database_unique_ptr database;
1426  sqlite3_statement_unique_ptr statement;
1427 
1428  int myResult = database.open( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ) );
1429  if ( myResult != SQLITE_OK )
1430  {
1431  return tr( "User database could not be opened." );
1432  }
1433 
1434  QByteArray param0 = uri.toUtf8();
1435  QByteArray param1 = qml.toUtf8();
1436 
1437  QString mySql;
1438  switch ( type )
1439  {
1440  case Metadata:
1441  mySql = QStringLiteral( "create table if not exists tbl_metadata(metadata varchar primary key,qmd varchar)" );
1442  break;
1443 
1444  case Style:
1445  mySql = QStringLiteral( "create table if not exists tbl_styles(style varchar primary key,qml varchar)" );
1446  break;
1447  }
1448 
1449  statement = database.prepare( mySql, myResult );
1450  if ( myResult == SQLITE_OK )
1451  {
1452  if ( sqlite3_step( statement.get() ) != SQLITE_DONE )
1453  {
1454  resultFlag = false;
1455  switch ( type )
1456  {
1457  case Metadata:
1458  return tr( "The metadata table could not be created." );
1459 
1460  case Style:
1461  return tr( "The style table could not be created." );
1462  }
1463  }
1464  }
1465 
1466  switch ( type )
1467  {
1468  case Metadata:
1469  mySql = QStringLiteral( "insert into tbl_metadata(metadata,qmd) values (?,?)" );
1470  break;
1471 
1472  case Style:
1473  mySql = QStringLiteral( "insert into tbl_styles(style,qml) values (?,?)" );
1474  break;
1475  }
1476  statement = database.prepare( mySql, myResult );
1477  if ( myResult == SQLITE_OK )
1478  {
1479  if ( sqlite3_bind_text( statement.get(), 1, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
1480  sqlite3_bind_text( statement.get(), 2, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
1481  sqlite3_step( statement.get() ) == SQLITE_DONE )
1482  {
1483  resultFlag = true;
1484  switch ( type )
1485  {
1486  case Metadata:
1487  myErrorMessage = tr( "The metadata %1 was saved to database" ).arg( uri );
1488  break;
1489 
1490  case Style:
1491  myErrorMessage = tr( "The style %1 was saved to database" ).arg( uri );
1492  break;
1493  }
1494  }
1495  }
1496 
1497  if ( !resultFlag )
1498  {
1499  QString mySql;
1500  switch ( type )
1501  {
1502  case Metadata:
1503  mySql = QStringLiteral( "update tbl_metadata set qmd=? where metadata=?" );
1504  break;
1505 
1506  case Style:
1507  mySql = QStringLiteral( "update tbl_styles set qml=? where style=?" );
1508  break;
1509  }
1510  statement = database.prepare( mySql, myResult );
1511  if ( myResult == SQLITE_OK )
1512  {
1513  if ( sqlite3_bind_text( statement.get(), 2, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
1514  sqlite3_bind_text( statement.get(), 1, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
1515  sqlite3_step( statement.get() ) == SQLITE_DONE )
1516  {
1517  resultFlag = true;
1518  switch ( type )
1519  {
1520  case Metadata:
1521  myErrorMessage = tr( "The metadata %1 was updated in the database." ).arg( uri );
1522  break;
1523 
1524  case Style:
1525  myErrorMessage = tr( "The style %1 was updated in the database." ).arg( uri );
1526  break;
1527  }
1528  }
1529  else
1530  {
1531  resultFlag = false;
1532  switch ( type )
1533  {
1534  case Metadata:
1535  myErrorMessage = tr( "The metadata %1 could not be updated in the database." ).arg( uri );
1536  break;
1537 
1538  case Style:
1539  myErrorMessage = tr( "The style %1 could not be updated in the database." ).arg( uri );
1540  break;
1541  }
1542  }
1543  }
1544  else
1545  {
1546  resultFlag = false;
1547  switch ( type )
1548  {
1549  case Metadata:
1550  myErrorMessage = tr( "The metadata %1 could not be inserted into database." ).arg( uri );
1551  break;
1552 
1553  case Style:
1554  myErrorMessage = tr( "The style %1 could not be inserted into database." ).arg( uri );
1555  break;
1556  }
1557  }
1558  }
1559  }
1560 
1561  return myErrorMessage;
1562 }
1563 
1564 QString QgsMapLayer::saveNamedStyle( const QString &uri, bool &resultFlag, StyleCategories categories )
1565 {
1566  return saveNamedProperty( uri, QgsMapLayer::Style, resultFlag, categories );
1567 }
1568 
1569 void QgsMapLayer::exportSldStyle( QDomDocument &doc, QString &errorMsg ) const
1570 {
1571  QDomDocument myDocument = QDomDocument();
1572 
1573  const QDomNode header = myDocument.createProcessingInstruction( QStringLiteral( "xml" ), QStringLiteral( "version=\"1.0\" encoding=\"UTF-8\"" ) );
1574  myDocument.appendChild( header );
1575 
1576  const QgsVectorLayer *vlayer = qobject_cast<const QgsVectorLayer *>( this );
1577  const QgsRasterLayer *rlayer = qobject_cast<const QgsRasterLayer *>( this );
1578  if ( !vlayer && !rlayer )
1579  {
1580  errorMsg = tr( "Could not save symbology because:\n%1" )
1581  .arg( tr( "Only vector and raster layers are supported" ) );
1582  return;
1583  }
1584 
1585  // Create the root element
1586  QDomElement root = myDocument.createElementNS( QStringLiteral( "http://www.opengis.net/sld" ), QStringLiteral( "StyledLayerDescriptor" ) );
1587  QDomElement layerNode;
1588  if ( vlayer )
1589  {
1590  root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.1.0" ) );
1591  root.setAttribute( QStringLiteral( "xsi:schemaLocation" ), QStringLiteral( "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" ) );
1592  root.setAttribute( QStringLiteral( "xmlns:ogc" ), QStringLiteral( "http://www.opengis.net/ogc" ) );
1593  root.setAttribute( QStringLiteral( "xmlns:se" ), QStringLiteral( "http://www.opengis.net/se" ) );
1594  root.setAttribute( QStringLiteral( "xmlns:xlink" ), QStringLiteral( "http://www.w3.org/1999/xlink" ) );
1595  root.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) );
1596  myDocument.appendChild( root );
1597 
1598  // Create the NamedLayer element
1599  layerNode = myDocument.createElement( QStringLiteral( "NamedLayer" ) );
1600  root.appendChild( layerNode );
1601  }
1602 
1603  // note: Only SLD 1.0 version is generated because seems none is using SE1.1.0 at least for rasters
1604  if ( rlayer )
1605  {
1606  // Create the root element
1607  root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0.0" ) );
1608  root.setAttribute( QStringLiteral( "xmlns:gml" ), QStringLiteral( "http://www.opengis.net/gml" ) );
1609  root.setAttribute( QStringLiteral( "xmlns:ogc" ), QStringLiteral( "http://www.opengis.net/ogc" ) );
1610  root.setAttribute( QStringLiteral( "xmlns:sld" ), QStringLiteral( "http://www.opengis.net/sld" ) );
1611  myDocument.appendChild( root );
1612 
1613  // Create the NamedLayer element
1614  layerNode = myDocument.createElement( QStringLiteral( "UserLayer" ) );
1615  root.appendChild( layerNode );
1616  }
1617 
1618  QVariantMap props;
1619  if ( hasScaleBasedVisibility() )
1620  {
1621  props[ QStringLiteral( "scaleMinDenom" ) ] = QString::number( mMinScale );
1622  props[ QStringLiteral( "scaleMaxDenom" ) ] = QString::number( mMaxScale );
1623  }
1624 
1625  if ( vlayer )
1626  {
1627  if ( !vlayer->writeSld( layerNode, myDocument, errorMsg, props ) )
1628  {
1629  errorMsg = tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1630  return;
1631  }
1632  }
1633 
1634  if ( rlayer )
1635  {
1636  if ( !rlayer->writeSld( layerNode, myDocument, errorMsg, props ) )
1637  {
1638  errorMsg = tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1639  return;
1640  }
1641  }
1642 
1643  doc = myDocument;
1644 }
1645 
1646 QString QgsMapLayer::saveSldStyle( const QString &uri, bool &resultFlag ) const
1647 {
1648  const QgsMapLayer *mlayer = qobject_cast<const QgsMapLayer *>( this );
1649 
1650  QString errorMsg;
1651  QDomDocument myDocument;
1652  mlayer->exportSldStyle( myDocument, errorMsg );
1653  if ( !errorMsg.isNull() )
1654  {
1655  resultFlag = false;
1656  return errorMsg;
1657  }
1658  // check if the uri is a file or ends with .sld,
1659  // which indicates that it should become one
1660  QString filename;
1661  if ( mlayer->providerType() == QLatin1String( "ogr" ) )
1662  {
1663  QStringList theURIParts = uri.split( '|' );
1664  filename = theURIParts[0];
1665  }
1666  else if ( mlayer->providerType() == QLatin1String( "gpx" ) )
1667  {
1668  QStringList theURIParts = uri.split( '?' );
1669  filename = theURIParts[0];
1670  }
1671  else if ( mlayer->providerType() == QLatin1String( "delimitedtext" ) )
1672  {
1673  filename = QUrl::fromEncoded( uri.toLatin1() ).toLocalFile();
1674  // toLocalFile() returns an empty string if theURI is a plain Windows-path, e.g. "C:/style.qml"
1675  if ( filename.isEmpty() )
1676  filename = uri;
1677  }
1678  else
1679  {
1680  filename = uri;
1681  }
1682 
1683  const QFileInfo myFileInfo( filename );
1684  if ( myFileInfo.exists() || filename.endsWith( QLatin1String( ".sld" ), Qt::CaseInsensitive ) )
1685  {
1686  const QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
1687  if ( !myDirInfo.isWritable() )
1688  {
1689  return tr( "The directory containing your dataset needs to be writable!" );
1690  }
1691 
1692  // now construct the file name for our .sld style file
1693  const QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".sld";
1694 
1695  QFile myFile( myFileName );
1696  if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
1697  {
1698  QTextStream myFileStream( &myFile );
1699  // save as utf-8 with 2 spaces for indents
1700  myDocument.save( myFileStream, 2 );
1701  myFile.close();
1702  resultFlag = true;
1703  return tr( "Created default style file as %1" ).arg( myFileName );
1704  }
1705  }
1706 
1707  resultFlag = false;
1708  return tr( "ERROR: Failed to created SLD style file as %1. Check file permissions and retry." ).arg( filename );
1709 }
1710 
1711 QString QgsMapLayer::loadSldStyle( const QString &uri, bool &resultFlag )
1712 {
1713  resultFlag = false;
1714 
1715  QDomDocument myDocument;
1716 
1717  // location of problem associated with errorMsg
1718  int line, column;
1719  QString myErrorMessage;
1720 
1721  QFile myFile( uri );
1722  if ( myFile.open( QFile::ReadOnly ) )
1723  {
1724  // read file
1725  resultFlag = myDocument.setContent( &myFile, true, &myErrorMessage, &line, &column );
1726  if ( !resultFlag )
1727  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1728  myFile.close();
1729  }
1730  else
1731  {
1732  myErrorMessage = tr( "Unable to open file %1" ).arg( uri );
1733  }
1734 
1735  if ( !resultFlag )
1736  {
1737  return myErrorMessage;
1738  }
1739 
1740  // check for root SLD element
1741  const QDomElement myRoot = myDocument.firstChildElement( QStringLiteral( "StyledLayerDescriptor" ) );
1742  if ( myRoot.isNull() )
1743  {
1744  myErrorMessage = QStringLiteral( "Error: StyledLayerDescriptor element not found in %1" ).arg( uri );
1745  resultFlag = false;
1746  return myErrorMessage;
1747  }
1748 
1749  // now get the style node out and pass it over to the layer
1750  // to deserialise...
1751  const QDomElement namedLayerElem = myRoot.firstChildElement( QStringLiteral( "NamedLayer" ) );
1752  if ( namedLayerElem.isNull() )
1753  {
1754  myErrorMessage = QStringLiteral( "Info: NamedLayer element not found." );
1755  resultFlag = false;
1756  return myErrorMessage;
1757  }
1758 
1759  QString errorMsg;
1760  resultFlag = readSld( namedLayerElem, errorMsg );
1761  if ( !resultFlag )
1762  {
1763  myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( uri, errorMsg );
1764  return myErrorMessage;
1765  }
1766 
1767  return QString();
1768 }
1769 
1770 bool QgsMapLayer::readStyle( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
1771 {
1772  Q_UNUSED( node )
1773  Q_UNUSED( errorMessage )
1774  Q_UNUSED( context )
1775  Q_UNUSED( categories )
1776  return false;
1777 }
1778 
1779 bool QgsMapLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage,
1780  const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1781 {
1782  Q_UNUSED( node )
1783  Q_UNUSED( doc )
1784  Q_UNUSED( errorMessage )
1785  Q_UNUSED( context )
1786  Q_UNUSED( categories )
1787  return false;
1788 }
1789 
1790 
1791 void QgsMapLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider,
1792  bool loadDefaultStyleFlag )
1793 {
1794  const QgsDataProvider::ProviderOptions options;
1795 
1796  QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags();
1797  if ( loadDefaultStyleFlag )
1798  {
1800  }
1801 
1803  {
1805  }
1806  setDataSource( dataSource, baseName, provider, options, flags );
1807 }
1808 
1809 void QgsMapLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider,
1810  const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag )
1811 {
1812  QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags();
1813  if ( loadDefaultStyleFlag )
1814  {
1816  }
1817 
1819  {
1821  }
1822  setDataSource( dataSource, baseName, provider, options, flags );
1823 }
1824 
1825 void QgsMapLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider,
1826  const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
1827 {
1828 
1831  {
1833  }
1834  setDataSourcePrivate( dataSource, baseName, provider, options, flags );
1835  emit dataSourceChanged();
1836  emit dataChanged();
1837  triggerRepaint();
1838 }
1839 
1840 
1841 void QgsMapLayer::setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider,
1842  const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
1843 {
1844  Q_UNUSED( dataSource )
1845  Q_UNUSED( baseName )
1846  Q_UNUSED( provider )
1847  Q_UNUSED( options )
1848  Q_UNUSED( flags )
1849 }
1850 
1851 
1853 {
1854  return mProviderKey;
1855 }
1856 
1857 void QgsMapLayer::readCommonStyle( const QDomElement &layerElement, const QgsReadWriteContext &context,
1858  QgsMapLayer::StyleCategories categories )
1859 {
1860  if ( categories.testFlag( Symbology3D ) )
1861  {
1862  const QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "3D Symbology" ) );
1863 
1864  QgsAbstract3DRenderer *r3D = nullptr;
1865  QDomElement renderer3DElem = layerElement.firstChildElement( QStringLiteral( "renderer-3d" ) );
1866  if ( !renderer3DElem.isNull() )
1867  {
1868  const QString type3D = renderer3DElem.attribute( QStringLiteral( "type" ) );
1870  if ( meta3D )
1871  {
1872  r3D = meta3D->createRenderer( renderer3DElem, context );
1873  }
1874  }
1875  setRenderer3D( r3D );
1876  }
1877 
1878  if ( categories.testFlag( CustomProperties ) )
1879  {
1880  // read custom properties before passing reading further to a subclass, so that
1881  // the subclass can also read custom properties
1882  readCustomProperties( layerElement );
1883  }
1884 
1885  // use scale dependent visibility flag
1886  if ( categories.testFlag( Rendering ) )
1887  {
1888  setScaleBasedVisibility( layerElement.attribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ) ).toInt() == 1 );
1889  if ( layerElement.hasAttribute( QStringLiteral( "minimumScale" ) ) )
1890  {
1891  // older element, when scales were reversed
1892  setMaximumScale( layerElement.attribute( QStringLiteral( "minimumScale" ) ).toDouble() );
1893  setMinimumScale( layerElement.attribute( QStringLiteral( "maximumScale" ) ).toDouble() );
1894  }
1895  else
1896  {
1897  setMaximumScale( layerElement.attribute( QStringLiteral( "maxScale" ) ).toDouble() );
1898  setMinimumScale( layerElement.attribute( QStringLiteral( "minScale" ) ).toDouble() );
1899  }
1900  }
1901 
1902  if ( categories.testFlag( LayerConfiguration ) )
1903  {
1904  // flags
1905  const QDomElement flagsElem = layerElement.firstChildElement( QStringLiteral( "flags" ) );
1906  LayerFlags flags = mFlags;
1907  const auto enumMap = qgsEnumMap<QgsMapLayer::LayerFlag>();
1908  for ( auto it = enumMap.constBegin(); it != enumMap.constEnd(); ++it )
1909  {
1910  const QDomNode flagNode = flagsElem.namedItem( it.value() );
1911  if ( flagNode.isNull() )
1912  continue;
1913  const bool flagValue = flagNode.toElement().text() == "1" ? true : false;
1914  if ( flags.testFlag( it.key() ) && !flagValue )
1915  flags &= ~it.key();
1916  else if ( !flags.testFlag( it.key() ) && flagValue )
1917  flags |= it.key();
1918  }
1919  setFlags( flags );
1920  }
1921 
1922  if ( categories.testFlag( Temporal ) )
1923  {
1924  const QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Temporal" ) );
1925 
1927  properties->readXml( layerElement.toElement(), context );
1928  }
1929 
1930  if ( categories.testFlag( Elevation ) )
1931  {
1932  const QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Elevation" ) );
1933 
1935  properties->readXml( layerElement.toElement(), context );
1936  }
1937 
1938  if ( categories.testFlag( Notes ) )
1939  {
1940  const QDomElement notesElem = layerElement.firstChildElement( QStringLiteral( "userNotes" ) );
1941  if ( !notesElem.isNull() )
1942  {
1943  const QString notes = notesElem.attribute( QStringLiteral( "value" ) );
1944  QgsLayerNotesUtils::setLayerNotes( this, notes );
1945  }
1946  }
1947 }
1948 
1950 {
1951  return mUndoStack;
1952 }
1953 
1955 {
1956  return mUndoStackStyles;
1957 }
1958 
1960 {
1961  return mCustomProperties.keys();
1962 }
1963 
1964 void QgsMapLayer::setCustomProperty( const QString &key, const QVariant &value )
1965 {
1966  if ( !mCustomProperties.contains( key ) || mCustomProperties.value( key ) != value )
1967  {
1968  mCustomProperties.setValue( key, value );
1969  emit customPropertyChanged( key );
1970  }
1971 }
1972 
1974 {
1975  mCustomProperties = properties;
1976  for ( const QString &key : mCustomProperties.keys() )
1977  {
1978  emit customPropertyChanged( key );
1979  }
1980 }
1981 
1983 {
1984  return mCustomProperties;
1985 }
1986 
1987 QVariant QgsMapLayer::customProperty( const QString &value, const QVariant &defaultValue ) const
1988 {
1989  return mCustomProperties.value( value, defaultValue );
1990 }
1991 
1992 void QgsMapLayer::removeCustomProperty( const QString &key )
1993 {
1994 
1995  if ( mCustomProperties.contains( key ) )
1996  {
1997  mCustomProperties.remove( key );
1998  emit customPropertyChanged( key );
1999  }
2000 }
2001 
2003 {
2004  return mError;
2005 }
2006 
2007 
2008 
2010 {
2011  return false;
2012 }
2013 
2015 {
2016  return false;
2017 }
2018 
2020 {
2021  return true;
2022 }
2023 
2025 {
2026  // invalid layers are temporary? -- who knows?!
2027  if ( !isValid() )
2028  return false;
2029 
2030  if ( mProviderKey == QLatin1String( "memory" ) )
2031  return true;
2032 
2033  const QVariantMap sourceParts = QgsProviderRegistry::instance()->decodeUri( mProviderKey, mDataSource );
2034  const QString path = sourceParts.value( QStringLiteral( "path" ) ).toString();
2035  if ( path.isEmpty() )
2036  return false;
2037 
2038  // check if layer path is inside one of the standard temporary file locations for this platform
2039  const QStringList tempPaths = QStandardPaths::standardLocations( QStandardPaths::TempLocation );
2040  for ( const QString &tempPath : tempPaths )
2041  {
2042  if ( path.startsWith( tempPath ) )
2043  return true;
2044  }
2045 
2046  return false;
2047 }
2048 
2049 void QgsMapLayer::setValid( bool valid )
2050 {
2051  if ( mValid == valid )
2052  return;
2053 
2054  mValid = valid;
2055  emit isValidChanged();
2056 }
2057 
2059 {
2060  if ( legend == mLegend )
2061  return;
2062 
2063  delete mLegend;
2064  mLegend = legend;
2065 
2066  if ( mLegend )
2067  {
2068  mLegend->setParent( this );
2069  connect( mLegend, &QgsMapLayerLegend::itemsChanged, this, &QgsMapLayer::legendChanged, Qt::UniqueConnection );
2070  }
2071 
2072  emit legendChanged();
2073 }
2074 
2076 {
2077  return mLegend;
2078 }
2079 
2081 {
2082  return mStyleManager;
2083 }
2084 
2086 {
2087  if ( renderer == m3DRenderer )
2088  return;
2089 
2090  delete m3DRenderer;
2091  m3DRenderer = renderer;
2092  emit renderer3DChanged();
2093  emit repaintRequested();
2094  trigger3DUpdate();
2095 }
2096 
2098 {
2099  return m3DRenderer;
2100 }
2101 
2102 void QgsMapLayer::triggerRepaint( bool deferredUpdate )
2103 {
2104  if ( mRepaintRequestedFired )
2105  return;
2106  mRepaintRequestedFired = true;
2107  emit repaintRequested( deferredUpdate );
2108  mRepaintRequestedFired = false;
2109 }
2110 
2112 {
2113  emit request3DUpdate();
2114 }
2115 
2117 {
2118  mMetadata = metadata;
2119 // mMetadata.saveToLayer( this );
2120  emit metadataChanged();
2121 }
2122 
2124 {
2125  return QString();
2126 }
2127 
2128 QDateTime QgsMapLayer::timestamp() const
2129 {
2130  return QDateTime();
2131 }
2132 
2134 {
2135  if ( !mBlockStyleChangedSignal )
2136  emit styleChanged();
2137 }
2138 
2140 {
2141  updateExtent( extent );
2142 }
2143 
2144 bool QgsMapLayer::isReadOnly() const
2145 {
2146  return true;
2147 }
2148 
2150 {
2151  return mOriginalXmlProperties;
2152 }
2153 
2154 void QgsMapLayer::setOriginalXmlProperties( const QString &originalXmlProperties )
2155 {
2156  mOriginalXmlProperties = originalXmlProperties;
2157 }
2158 
2159 QString QgsMapLayer::generateId( const QString &layerName )
2160 {
2161  // Generate the unique ID of this layer
2162  const QString uuid = QUuid::createUuid().toString();
2163  // trim { } from uuid
2164  QString id = layerName + '_' + uuid.mid( 1, uuid.length() - 2 );
2165  // Tidy the ID up to avoid characters that may cause problems
2166  // elsewhere (e.g in some parts of XML). Replaces every non-word
2167  // character (word characters are the alphabet, numbers and
2168  // underscore) with an underscore.
2169  // Note that the first backslash in the regular expression is
2170  // there for the compiler, so the pattern is actually \W
2171  id.replace( QRegularExpression( "[\\W]" ), QStringLiteral( "_" ) );
2172  return id;
2173 }
2174 
2176 {
2177  return true;
2178 }
2179 
2180 void QgsMapLayer::setProviderType( const QString &providerType )
2181 {
2183 }
2184 
2185 QSet<QgsMapLayerDependency> QgsMapLayer::dependencies() const
2186 {
2187  return mDependencies;
2188 }
2189 
2190 bool QgsMapLayer::setDependencies( const QSet<QgsMapLayerDependency> &oDeps )
2191 {
2192  QSet<QgsMapLayerDependency> deps;
2193  const auto constODeps = oDeps;
2194  for ( const QgsMapLayerDependency &dep : constODeps )
2195  {
2196  if ( dep.origin() == QgsMapLayerDependency::FromUser )
2197  deps << dep;
2198  }
2199 
2200  mDependencies = deps;
2201  emit dependenciesChanged();
2202  return true;
2203 }
2204 
2206 {
2207  QgsDataProvider *lDataProvider = dataProvider();
2208 
2209  if ( !lDataProvider )
2210  return;
2211 
2212  if ( enabled && !isRefreshOnNotifyEnabled() )
2213  {
2214  lDataProvider->setListening( enabled );
2215  connect( lDataProvider, &QgsDataProvider::notify, this, &QgsMapLayer::onNotified );
2216  }
2217  else if ( !enabled && isRefreshOnNotifyEnabled() )
2218  {
2219  // we don't want to disable provider listening because someone else could need it (e.g. actions)
2220  disconnect( lDataProvider, &QgsDataProvider::notify, this, &QgsMapLayer::onNotified );
2221  }
2222  mIsRefreshOnNofifyEnabled = enabled;
2223 }
2224 
2226 {
2227  if ( QgsMapLayerStore *store = qobject_cast<QgsMapLayerStore *>( parent() ) )
2228  {
2229  return qobject_cast<QgsProject *>( store->parent() );
2230  }
2231  return nullptr;
2232 }
2233 
2234 void QgsMapLayer::onNotified( const QString &message )
2235 {
2236  if ( refreshOnNotifyMessage().isEmpty() || refreshOnNotifyMessage() == message )
2237  {
2238  triggerRepaint();
2239  emit dataChanged();
2240  }
2241 }
2242 
2243 QgsRectangle QgsMapLayer::wgs84Extent( bool forceRecalculate ) const
2244 {
2246 
2247  if ( ! forceRecalculate && ! mWgs84Extent.isNull() )
2248  {
2249  wgs84Extent = mWgs84Extent;
2250  }
2251  else if ( ! mExtent.isNull() )
2252  {
2254  transformer.setBallparkTransformsAreAppropriate( true );
2255  try
2256  {
2257  wgs84Extent = transformer.transformBoundingBox( mExtent );
2258  }
2259  catch ( const QgsCsException &cse )
2260  {
2261  QgsMessageLog::logMessage( tr( "Error transforming extent: %1" ).arg( cse.what() ) );
2263  }
2264  }
2265  return wgs84Extent;
2266 }
2267 
2268 void QgsMapLayer::updateExtent( const QgsRectangle &extent ) const
2269 {
2270  if ( extent == mExtent )
2271  return;
2272 
2273  mExtent = extent;
2274 
2275  // do not update the wgs84 extent if we trust layer metadata
2276  if ( mReadFlags & QgsMapLayer::ReadFlag::FlagTrustLayerMetadata )
2277  return;
2278 
2279  mWgs84Extent = wgs84Extent( true );
2280 }
2281 
2283 {
2284  // do not update the wgs84 extent if we trust layer metadata
2285  if ( mReadFlags & QgsMapLayer::ReadFlag::FlagTrustLayerMetadata )
2286  return;
2287 
2288  mWgs84Extent = QgsRectangle();
2289 }
2290 
2292 {
2293  QString metadata = QStringLiteral( "<h1>" ) + tr( "General" ) + QStringLiteral( "</h1>\n<hr>\n" ) + QStringLiteral( "<table class=\"list-view\">\n" );
2294 
2295  // name
2296  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Name" ) + QStringLiteral( "</td><td>" ) + name() + QStringLiteral( "</td></tr>\n" );
2297 
2298  QString path;
2299  bool isLocalPath = false;
2300  if ( dataProvider() )
2301  {
2302  // local path
2303  QVariantMap uriComponents = QgsProviderRegistry::instance()->decodeUri( dataProvider()->name(), publicSource() );
2304  if ( uriComponents.contains( QStringLiteral( "path" ) ) )
2305  {
2306  path = uriComponents[QStringLiteral( "path" )].toString();
2307  QFileInfo fi( path );
2308  if ( fi.exists() )
2309  {
2310  isLocalPath = true;
2311  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" );
2312 
2313  QDateTime lastModified = fi.lastModified();
2314  QString lastModifiedFileName;
2315  QSet<QString> sidecarFiles = QgsFileUtils::sidecarFilesForPath( path );
2316  if ( fi.isFile() )
2317  {
2318  qint64 fileSize = fi.size();
2319  if ( !sidecarFiles.isEmpty() )
2320  {
2321  lastModifiedFileName = fi.fileName();
2322  QStringList sidecarFileNames;
2323  for ( const QString &sidecarFile : sidecarFiles )
2324  {
2325  QFileInfo sidecarFi( sidecarFile );
2326  fileSize += sidecarFi.size();
2327  if ( sidecarFi.lastModified() > lastModified )
2328  {
2329  lastModified = sidecarFi.lastModified();
2330  lastModifiedFileName = sidecarFi.fileName();
2331  }
2332  sidecarFileNames << sidecarFi.fileName();
2333  }
2334  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" );
2335  }
2336  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" );
2337  }
2338  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" );
2339  }
2340  }
2341  if ( uriComponents.contains( QStringLiteral( "url" ) ) )
2342  {
2343  const QString url = uriComponents[QStringLiteral( "url" )].toString();
2344  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" );
2345  }
2346  }
2347 
2348  // data source
2349  if ( publicSource() != path || !isLocalPath )
2350  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Source" ) + QStringLiteral( "</td><td>%1" ).arg( publicSource() != path ? publicSource() : path ) + QStringLiteral( "</td></tr>\n" );
2351 
2352  // provider
2353  if ( dataProvider() )
2354  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Provider" ) + QStringLiteral( "</td><td>%1" ).arg( dataProvider()->name() ) + QStringLiteral( "</td></tr>\n" );
2355 
2356  metadata += QLatin1String( "</table>\n<br><br>" );
2357  return metadata;
2358 }
2359 
2361 {
2362  QString metadata = QStringLiteral( "<h1>" ) + tr( "Coordinate Reference System (CRS)" ) + QStringLiteral( "</h1>\n<hr>\n" );
2363  metadata += QLatin1String( "<table class=\"list-view\">\n" );
2364 
2365  // Identifier
2367  if ( !c.isValid() )
2368  metadata += QStringLiteral( "<tr><td colspan=\"2\" class=\"highlight\">" ) + tr( "Unknown" ) + QStringLiteral( "</td></tr>\n" );
2369  else
2370  {
2371  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Name" ) + QStringLiteral( "</td><td>" ) + c.userFriendlyIdentifier( QgsCoordinateReferenceSystem::FullString ) + QStringLiteral( "</td></tr>\n" );
2372 
2373  // map units
2374  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Units" ) + QStringLiteral( "</td><td>" )
2375  + ( c.isGeographic() ? tr( "Geographic (uses latitude and longitude for coordinates)" ) : QgsUnitTypes::toString( c.mapUnits() ) )
2376  + QStringLiteral( "</td></tr>\n" );
2377 
2378 
2379  // operation
2380  const QgsProjOperation operation = c.operation();
2381  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Method" ) + QStringLiteral( "</td><td>" ) + operation.description() + QStringLiteral( "</td></tr>\n" );
2382 
2383  // celestial body
2384  try
2385  {
2386  const QString celestialBody = c.celestialBodyName();
2387  if ( !celestialBody.isEmpty() )
2388  {
2389  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Celestial body" ) + QStringLiteral( "</td><td>" ) + celestialBody + QStringLiteral( "</td></tr>\n" );
2390  }
2391  }
2392  catch ( QgsNotSupportedException & )
2393  {
2394 
2395  }
2396 
2397  QString accuracyString;
2398  // dynamic crs with no epoch?
2399  if ( c.isDynamic() && std::isnan( c.coordinateEpoch() ) )
2400  {
2401  accuracyString = tr( "Based on a dynamic CRS, but no coordinate epoch is set. Coordinates are ambiguous and of limited accuracy." );
2402  }
2403 
2404  // based on datum ensemble?
2405  try
2406  {
2407  const QgsDatumEnsemble ensemble = c.datumEnsemble();
2408  if ( ensemble.isValid() )
2409  {
2410  QString id;
2411  if ( !ensemble.code().isEmpty() )
2412  id = QStringLiteral( "<i>%1</i> (%2:%3)" ).arg( ensemble.name(), ensemble.authority(), ensemble.code() );
2413  else
2414  id = QStringLiteral( "<i>%</i>”" ).arg( ensemble.name() );
2415 
2416  if ( ensemble.accuracy() > 0 )
2417  {
2418  accuracyString = tr( "Based on %1, which has a limited accuracy of <b>at best %2 meters</b>." ).arg( id ).arg( ensemble.accuracy() );
2419  }
2420  else
2421  {
2422  accuracyString = tr( "Based on %1, which has a limited accuracy." ).arg( id );
2423  }
2424  }
2425  }
2426  catch ( QgsNotSupportedException & )
2427  {
2428 
2429  }
2430 
2431  if ( !accuracyString.isEmpty() )
2432  {
2433  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Accuracy" ) + QStringLiteral( "</td><td>" ) + accuracyString + QStringLiteral( "</td></tr>\n" );
2434  }
2435 
2436  // static/dynamic
2437  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)" ) );
2438 
2439  // coordinate epoch
2440  if ( !std::isnan( c.coordinateEpoch() ) )
2441  {
2442  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Coordinate epoch" ) + QStringLiteral( "</td><td>%1</td></tr>\n" ).arg( c.coordinateEpoch() );
2443  }
2444  }
2445 
2446  metadata += QLatin1String( "</table>\n<br><br>\n" );
2447  return metadata;
2448 }
static QString version()
Version string.
Definition: qgis.cpp:285
static const double SCALE_PRECISION
Fudge factor used to compare two scales.
Definition: qgis.h:1031
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:73
QString mKeywordList
Definition: qgsmaplayer.h:1935
void setShortName(const QString &shortName)
Sets the short name of the layer used by QGIS Server to identify the layer.
Definition: qgsmaplayer.h:285
bool importNamedMetadata(QDomDocument &document, QString &errorMessage)
Import the metadata of this layer from a QDomDocument.
QString name
Definition: qgsmaplayer.h:76
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:1281
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:315
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:1266
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:1950
int mBlockStyleChangedSignal
If non-zero, the styleChanged signal should not be emitted.
Definition: qgsmaplayer.h:1992
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:80
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:79
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:397
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:1963
QString mLegendUrl
WMS legend.
Definition: qgsmaplayer.h:1946
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:1928
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:406
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:78
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:377
QgsMapLayerServerProperties * serverProperties()
Returns QGIS Server Properties for the map layer.
Definition: qgsmaplayer.h:423
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
QString mTitle
Definition: qgsmaplayer.h:1931
void setDataUrl(const QString &dataUrl)
Sets the DataUrl of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:350
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:331
void setAttribution(const QString &attrib)
Sets the attribution of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:388
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:1443
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:1953
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:368
QString mLegendUrlFormat
Definition: qgsmaplayer.h:1947
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:1966
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:307
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:1943
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:359
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:1590
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:1930
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:81
QString mDataSource
Data source description string, varies by layer type.
Definition: qgsmaplayer.h:1925
QString refreshOnNotifyMessage() const
Returns the message that should be notified by the provider to triggerRepaint.
Definition: qgsmaplayer.h:1436
virtual bool readSld(const QDomNode &node, QString &errorMessage)
Definition: qgsmaplayer.h:1144
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:639
@ FlagTrustLayerMetadata
Trust layer metadata. Improves layer load time by skipping expensive checks like primary key unicity,...
Definition: qgsmaplayer.h:638
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:415
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:1934
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:1971
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:1271
QString mDataUrlFormat
Definition: qgsmaplayer.h:1939
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:1276
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:1493
double opacity
Definition: qgsmaplayer.h:82
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:77
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:1962
QString mDataUrl
DataUrl of the layer.
Definition: qgsmaplayer.h:1938
virtual Q_INVOKABLE QgsDataProvider * dataProvider()
Returns the layer's data provider, it may be nullptr.
double mLayerOpacity
Layer opacity.
Definition: qgsmaplayer.h:1985
bool mValid
Indicates if the layer is valid and can be drawn.
Definition: qgsmaplayer.h:1922
@ AllStyleCategories
Definition: qgsmaplayer.h:175
@ LayerConfiguration
General configuration: identifiable, removable, searchable, display expression, read-only.
Definition: qgsmaplayer.h:157
@ Symbology
Symbology.
Definition: qgsmaplayer.h:158
@ Notes
Layer user notes (since QGIS 3.20)
Definition: qgsmaplayer.h:174
@ Temporal
Temporal properties (since QGIS 3.14)
Definition: qgsmaplayer.h:171
@ Rendering
Rendering: scale visibility, simplify method, opacity.
Definition: qgsmaplayer.h:167
@ Elevation
Elevation settings (since QGIS 3.18)
Definition: qgsmaplayer.h:173
@ Symbology3D
3D symbology
Definition: qgsmaplayer.h:159
@ CustomProperties
Custom properties (by plugins for instance)
Definition: qgsmaplayer.h:168
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:1486
void setRenderer3D(QgsAbstract3DRenderer *renderer)
Sets 3D renderer for the layer.
QString mAttribution
Attribution of the layer.
Definition: qgsmaplayer.h:1942
~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:339
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:299
PropertyType
Maplayer has a style and a metadata property.
Definition: qgsmaplayer.h:130
bool mShouldValidateCrs
true if the layer's CRS should be validated and invalid CRSes are not permitted.
Definition: qgsmaplayer.h:1978
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:1246
CONSTLATIN1STRING geoEpsgCrsAuthId()
Geographic coord sys from EPSG authority.
Definition: qgis.h:1654
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.