QGIS API Documentation 3.32.0-Lima (311a8cb8a6)
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"
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 "qgspathresolver.h"
33#include "qgsproject.h"
34#include "qgsproviderregistry.h"
35#include "qgsrasterlayer.h"
36#include "qgsreadwritecontext.h"
37#include "qgsrectangle.h"
38#include "qgssldexportcontext.h"
39#include "qgsvectorlayer.h"
40#include "qgsxmlutils.h"
41#include "qgsstringutils.h"
42#include "qgsmessagelog.h"
45#include "qgsprovidermetadata.h"
46#include "qgslayernotesutils.h"
47#include "qgsdatums.h"
48#include "qgsprojoperation.h"
49#include "qgsthreadingutils.h"
50#include "qgsunittypes.h"
51
52#include <QDir>
53#include <QDomDocument>
54#include <QDomElement>
55#include <QDomImplementation>
56#include <QDomNode>
57#include <QFile>
58#include <QFileInfo>
59#include <QLocale>
60#include <QTextStream>
61#include <QUrl>
62#include <QTimer>
63#include <QStandardPaths>
64#include <QUuid>
65#include <QRegularExpression>
66
67#include <sqlite3.h>
68
70{
71 switch ( type )
72 {
73 case Metadata:
74 return QStringLiteral( ".qmd" );
75
76 case Style:
77 return QStringLiteral( ".qml" );
78 }
79 return QString();
80}
81
83 const QString &lyrname,
84 const QString &source )
85 : mDataSource( source )
86 , mLayerName( lyrname )
87 , mLayerType( type )
88 , mServerProperties( std::make_unique<QgsMapLayerServerProperties>( this ) )
89 , mUndoStack( new QUndoStack( this ) )
90 , mUndoStackStyles( new QUndoStack( this ) )
91 , mStyleManager( new QgsMapLayerStyleManager( this ) )
92 , mRefreshTimer( new QTimer( this ) )
93{
94 mID = generateId( lyrname );
97 connect( mRefreshTimer, &QTimer::timeout, this, [ = ] { triggerRepaint( true ); } );
98}
99
101{
102 if ( project() && project()->pathResolver().writePath( mDataSource ).startsWith( "attachment:" ) )
103 {
105 }
106
107 delete m3DRenderer;
108 delete mLegend;
109 delete mStyleManager;
110}
111
112void QgsMapLayer::clone( QgsMapLayer *layer ) const
113{
115
116 layer->setBlendMode( blendMode() );
117
118 const auto constStyles = styleManager()->styles();
119 for ( const QString &s : constStyles )
120 {
121 layer->styleManager()->addStyle( s, styleManager()->style( s ) );
122 }
123
124 layer->setName( name() );
125 layer->setShortName( shortName() );
126 layer->setExtent( extent() );
127 layer->setMaximumScale( maximumScale() );
128 layer->setMinimumScale( minimumScale() );
130 layer->setTitle( title() );
131 layer->setAbstract( abstract() );
132 layer->setKeywordList( keywordList() );
133 layer->setDataUrl( dataUrl() );
135 layer->setAttribution( attribution() );
137 layer->setLegendUrl( legendUrl() );
139 layer->setDependencies( dependencies() );
141 layer->setCrs( crs() );
142 layer->setCustomProperties( mCustomProperties );
143 layer->setOpacity( mLayerOpacity );
144 layer->setMetadata( mMetadata );
145 layer->serverProperties()->copyTo( mServerProperties.get() );
146}
147
149{
150 // because QgsVirtualLayerProvider is not anywhere NEAR thread safe:
152
153 return mLayerType;
154}
155
156QgsMapLayer::LayerFlags QgsMapLayer::flags() const
157{
159
160 return mFlags;
161}
162
163void QgsMapLayer::setFlags( QgsMapLayer::LayerFlags flags )
164{
166
167 if ( flags == mFlags )
168 return;
169
170 mFlags = flags;
171 emit flagsChanged();
172}
173
174Qgis::MapLayerProperties QgsMapLayer::properties() const
175{
177
178 return Qgis::MapLayerProperties();
179}
180
181QString QgsMapLayer::id() const
182{
183 // because QgsVirtualLayerProvider is not anywhere NEAR thread safe:
185
186 return mID;
187}
188
189void QgsMapLayer::setName( const QString &name )
190{
192
193 if ( name == mLayerName )
194 return;
195
197
198 emit nameChanged();
199}
200
201QString QgsMapLayer::name() const
202{
203 // because QgsVirtualLayerProvider is not anywhere NEAR thread safe:
205
206 QgsDebugMsgLevel( "returning name '" + mLayerName + '\'', 4 );
207 return mLayerName;
208}
209
211{
213
214 return nullptr;
215}
216
218{
220
221 return nullptr;
222}
223
225{
227
228 return mShortName;
229}
230
231void QgsMapLayer::setMetadataUrl( const QString &metaUrl )
232{
234
235 QList<QgsMapLayerServerProperties::MetadataUrl> urls = serverProperties()->metadataUrls();
236 if ( urls.isEmpty() )
237 {
238 const QgsMapLayerServerProperties::MetadataUrl newItem = QgsMapLayerServerProperties::MetadataUrl( metaUrl, QLatin1String(), QLatin1String() );
239 urls.prepend( newItem );
240 }
241 else
242 {
243 const QgsMapLayerServerProperties::MetadataUrl old = urls.takeFirst();
244 const QgsMapLayerServerProperties::MetadataUrl newItem( metaUrl, old.type, old.format );
245 urls.prepend( newItem );
246 }
248}
249
251{
253
254 if ( mServerProperties->metadataUrls().isEmpty() )
255 {
256 return QLatin1String();
257 }
258 else
259 {
260 return mServerProperties->metadataUrls().first().url;
261 }
262}
263
264void QgsMapLayer::setMetadataUrlType( const QString &metaUrlType )
265{
267
268 QList<QgsMapLayerServerProperties::MetadataUrl> urls = mServerProperties->metadataUrls();
269 if ( urls.isEmpty() )
270 {
271 const QgsMapLayerServerProperties::MetadataUrl newItem( QLatin1String(), metaUrlType, QLatin1String() );
272 urls.prepend( newItem );
273 }
274 else
275 {
276 const QgsMapLayerServerProperties::MetadataUrl old = urls.takeFirst();
277 const QgsMapLayerServerProperties::MetadataUrl newItem( old.url, metaUrlType, old.format );
278 urls.prepend( newItem );
279 }
280 mServerProperties->setMetadataUrls( urls );
281}
282
284{
286
287 if ( mServerProperties->metadataUrls().isEmpty() )
288 {
289 return QLatin1String();
290 }
291 else
292 {
293 return mServerProperties->metadataUrls().first().type;
294 }
295}
296
297void QgsMapLayer::setMetadataUrlFormat( const QString &metaUrlFormat )
298{
300
301 QList<QgsMapLayerServerProperties::MetadataUrl> urls = mServerProperties->metadataUrls();
302 if ( urls.isEmpty() )
303 {
304 const QgsMapLayerServerProperties::MetadataUrl newItem( QLatin1String(), QLatin1String(), metaUrlFormat );
305 urls.prepend( newItem );
306 }
307 else
308 {
309 const QgsMapLayerServerProperties::MetadataUrl old = urls.takeFirst( );
310 const QgsMapLayerServerProperties::MetadataUrl newItem( old.url, old.type, metaUrlFormat );
311 urls.prepend( newItem );
312 }
313 mServerProperties->setMetadataUrls( urls );
314}
315
317{
319
320 if ( mServerProperties->metadataUrls().isEmpty() )
321 {
322 return QString();
323 }
324 else
325 {
326 return mServerProperties->metadataUrls().first().format;
327 }
328}
329
331{
333
334 // Redo this every time we're asked for it, as we don't know if
335 // dataSource has changed.
336 QString safeName = QgsDataSourceUri::removePassword( mDataSource );
337 return safeName;
338}
339
340QString QgsMapLayer::source() const
341{
343
344 return mDataSource;
345}
346
348{
350
351 return mExtent;
352}
353
354void QgsMapLayer::setBlendMode( const QPainter::CompositionMode blendMode )
355{
357
358 if ( mBlendMode == blendMode )
359 return;
360
361 mBlendMode = blendMode;
364}
365
366QPainter::CompositionMode QgsMapLayer::blendMode() const
367{
368 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
370
371 return mBlendMode;
372}
373
374void QgsMapLayer::setOpacity( double opacity )
375{
377
379 return;
381 emit opacityChanged( opacity );
383}
384
386{
387 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
389
390 return mLayerOpacity;
391}
392
393bool QgsMapLayer::readLayerXml( const QDomElement &layerElement, QgsReadWriteContext &context, QgsMapLayer::ReadFlags flags, QgsDataProvider *preloadedProvider )
394{
396
397 mPreloadedProvider.reset( preloadedProvider );
398
399 bool layerError;
401
402 QDomNode mnl;
403 QDomElement mne;
404
405 // read provider
406 QString provider;
407 mnl = layerElement.namedItem( QStringLiteral( "provider" ) );
408 mne = mnl.toElement();
409 provider = mne.text();
410
411 // set data source
412 mnl = layerElement.namedItem( QStringLiteral( "datasource" ) );
413 mne = mnl.toElement();
414 mDataSource = context.pathResolver().readPath( mne.text() );
415
416 // if the layer needs authentication, ensure the master password is set
417 const thread_local QRegularExpression rx( "authcfg=([a-z]|[A-Z]|[0-9]){7}" );
418 if ( rx.match( mDataSource ).hasMatch()
420 {
421 return false;
422 }
423
424 mDataSource = decodedSource( mDataSource, provider, context );
425
426 // Set the CRS from project file, asking the user if necessary.
427 // Make it the saved CRS to have WMS layer projected correctly.
428 // We will still overwrite whatever GDAL etc picks up anyway
429 // further down this function.
430 mnl = layerElement.namedItem( QStringLiteral( "layername" ) );
431 mne = mnl.toElement();
432
434 CUSTOM_CRS_VALIDATION savedValidation;
435
436 const QDomNode srsNode = layerElement.namedItem( QStringLiteral( "srs" ) );
437 mCRS.readXml( srsNode );
438 mCRS.setValidationHint( tr( "Specify CRS for layer %1" ).arg( mne.text() ) );
439 if ( isSpatial() && type() != Qgis::LayerType::Annotation )
440 mCRS.validate();
441 savedCRS = mCRS;
442
443 // Do not validate any projections in children, they will be overwritten anyway.
444 // No need to ask the user for a projections when it is overwritten, is there?
447
448 const QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Layer" ), mne.text() );
449
450 // the internal name is just the data source basename
451 //QFileInfo dataSourceFileInfo( mDataSource );
452 //internalName = dataSourceFileInfo.baseName();
453
454 // set ID
455 mnl = layerElement.namedItem( QStringLiteral( "id" ) );
456 if ( ! mnl.isNull() )
457 {
458 mne = mnl.toElement();
459 if ( ! mne.isNull() && mne.text().length() > 10 ) // should be at least 17 (yyyyMMddhhmmsszzz)
460 {
461 mID = mne.text();
462 }
463 }
464
465 // set name
466 mnl = layerElement.namedItem( QStringLiteral( "layername" ) );
467 mne = mnl.toElement();
468
469 //name can be translated
470 setName( context.projectTranslator()->translate( QStringLiteral( "project:layers:%1" ).arg( layerElement.namedItem( QStringLiteral( "id" ) ).toElement().text() ), mne.text() ) );
471
472 // now let the children grab what they need from the Dom node.
473 layerError = !readXml( layerElement, context );
474
475 // overwrite CRS with what we read from project file before the raster/vector
476 // file reading functions changed it. They will if projections is specified in the file.
477 // FIXME: is this necessary? Yes, it is (autumn 2019)
479 mCRS = savedCRS;
480
481 //short name
482 const QDomElement shortNameElem = layerElement.firstChildElement( QStringLiteral( "shortname" ) );
483 if ( !shortNameElem.isNull() )
484 {
485 mShortName = shortNameElem.text();
486 }
487
488 //title
489 const QDomElement titleElem = layerElement.firstChildElement( QStringLiteral( "title" ) );
490 if ( !titleElem.isNull() )
491 {
492 mTitle = titleElem.text();
493 }
494
495 //abstract
496 const QDomElement abstractElem = layerElement.firstChildElement( QStringLiteral( "abstract" ) );
497 if ( !abstractElem.isNull() )
498 {
499 mAbstract = abstractElem.text();
500 }
501
502 //keywordList
503 const QDomElement keywordListElem = layerElement.firstChildElement( QStringLiteral( "keywordList" ) );
504 if ( !keywordListElem.isNull() )
505 {
506 QStringList kwdList;
507 for ( QDomNode n = keywordListElem.firstChild(); !n.isNull(); n = n.nextSibling() )
508 {
509 kwdList << n.toElement().text();
510 }
511 mKeywordList = kwdList.join( QLatin1String( ", " ) );
512 }
513
514 //dataUrl
515 const QDomElement dataUrlElem = layerElement.firstChildElement( QStringLiteral( "dataUrl" ) );
516 if ( !dataUrlElem.isNull() )
517 {
518 mDataUrl = dataUrlElem.text();
519 mDataUrlFormat = dataUrlElem.attribute( QStringLiteral( "format" ), QString() );
520 }
521
522 //legendUrl
523 const QDomElement legendUrlElem = layerElement.firstChildElement( QStringLiteral( "legendUrl" ) );
524 if ( !legendUrlElem.isNull() )
525 {
526 mLegendUrl = legendUrlElem.text();
527 mLegendUrlFormat = legendUrlElem.attribute( QStringLiteral( "format" ), QString() );
528 }
529
530 //attribution
531 const QDomElement attribElem = layerElement.firstChildElement( QStringLiteral( "attribution" ) );
532 if ( !attribElem.isNull() )
533 {
534 mAttribution = attribElem.text();
535 mAttributionUrl = attribElem.attribute( QStringLiteral( "href" ), QString() );
536 }
537
538 serverProperties()->readXml( layerElement );
539
540 if ( serverProperties()->metadataUrls().isEmpty() )
541 {
542 // metadataUrl is still empty, maybe it's a QGIS Project < 3.22
543 // keep for legacy
544 const QDomElement metaUrlElem = layerElement.firstChildElement( QStringLiteral( "metadataUrl" ) );
545 if ( !metaUrlElem.isNull() )
546 {
547 const QString url = metaUrlElem.text();
548 const QString type = metaUrlElem.attribute( QStringLiteral( "type" ), QString() );
549 const QString format = metaUrlElem.attribute( QStringLiteral( "format" ), QString() );
550 const QgsMapLayerServerProperties::MetadataUrl newItem( url, type, format );
551 mServerProperties->setMetadataUrls( QList<QgsMapLayerServerProperties::MetadataUrl>() << newItem );
552 }
553 }
554
555 // mMetadata.readFromLayer( this );
556 const QDomElement metadataElem = layerElement.firstChildElement( QStringLiteral( "resourceMetadata" ) );
557 mMetadata.readMetadataXml( metadataElem );
558
559 setAutoRefreshInterval( layerElement.attribute( QStringLiteral( "autoRefreshTime" ), QStringLiteral( "0" ) ).toInt() );
560 setAutoRefreshEnabled( layerElement.attribute( QStringLiteral( "autoRefreshEnabled" ), QStringLiteral( "0" ) ).toInt() );
561 setRefreshOnNofifyMessage( layerElement.attribute( QStringLiteral( "refreshOnNotifyMessage" ), QString() ) );
562 setRefreshOnNotifyEnabled( layerElement.attribute( QStringLiteral( "refreshOnNotifyEnabled" ), QStringLiteral( "0" ) ).toInt() );
563
564 // geographic extent is read only if necessary
565 if ( mReadFlags & QgsMapLayer::ReadFlag::FlagTrustLayerMetadata )
566 {
567 const QDomNode wgs84ExtentNode = layerElement.namedItem( QStringLiteral( "wgs84extent" ) );
568 if ( !wgs84ExtentNode.isNull() )
569 mWgs84Extent = QgsXmlUtils::readRectangle( wgs84ExtentNode.toElement() );
570 }
571
572 mLegendPlaceholderImage = layerElement.attribute( QStringLiteral( "legendPlaceholderImage" ) );
573
574 return ! layerError;
575} // bool QgsMapLayer::readLayerXML
576
577
578bool QgsMapLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
579{
581
582 Q_UNUSED( layer_node )
583 Q_UNUSED( context )
584 // NOP by default; children will over-ride with behavior specific to them
585
586 // read Extent
588 {
589 const QDomNode extentNode = layer_node.namedItem( QStringLiteral( "extent" ) );
590 if ( !extentNode.isNull() )
591 {
592 mExtent = QgsXmlUtils::readRectangle( extentNode.toElement() );
593 }
594 }
595
596 return true;
597} // void QgsMapLayer::readXml
598
599
600bool QgsMapLayer::writeLayerXml( QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context ) const
601{
603
604 if ( !extent().isNull() )
605 {
606 layerElement.appendChild( QgsXmlUtils::writeRectangle( mExtent, document ) );
607 layerElement.appendChild( QgsXmlUtils::writeRectangle( wgs84Extent( true ), document, QStringLiteral( "wgs84extent" ) ) );
608 }
609
610 layerElement.setAttribute( QStringLiteral( "autoRefreshTime" ), QString::number( mRefreshTimer->interval() ) );
611 layerElement.setAttribute( QStringLiteral( "autoRefreshEnabled" ), mRefreshTimer->isActive() ? 1 : 0 );
612 layerElement.setAttribute( QStringLiteral( "refreshOnNotifyEnabled" ), mIsRefreshOnNofifyEnabled ? 1 : 0 );
613 layerElement.setAttribute( QStringLiteral( "refreshOnNotifyMessage" ), mRefreshOnNofifyMessage );
614
615 // ID
616 QDomElement layerId = document.createElement( QStringLiteral( "id" ) );
617 const QDomText layerIdText = document.createTextNode( id() );
618 layerId.appendChild( layerIdText );
619
620 layerElement.appendChild( layerId );
621
622 // data source
623 QDomElement dataSource = document.createElement( QStringLiteral( "datasource" ) );
624 const QString src = context.pathResolver().writePath( encodedSource( source(), context ) );
625 const QDomText dataSourceText = document.createTextNode( src );
626 dataSource.appendChild( dataSourceText );
627 layerElement.appendChild( dataSource );
628
629 // layer name
630 QDomElement layerName = document.createElement( QStringLiteral( "layername" ) );
631 const QDomText layerNameText = document.createTextNode( name() );
632 layerName.appendChild( layerNameText );
633 layerElement.appendChild( layerName );
634
635 // layer short name
636 if ( !mShortName.isEmpty() )
637 {
638 QDomElement layerShortName = document.createElement( QStringLiteral( "shortname" ) );
639 const QDomText layerShortNameText = document.createTextNode( mShortName );
640 layerShortName.appendChild( layerShortNameText );
641 layerElement.appendChild( layerShortName );
642 }
643
644 // layer title
645 if ( !mTitle.isEmpty() )
646 {
647 QDomElement layerTitle = document.createElement( QStringLiteral( "title" ) );
648 const QDomText layerTitleText = document.createTextNode( mTitle );
649 layerTitle.appendChild( layerTitleText );
650 layerElement.appendChild( layerTitle );
651 }
652
653 // layer abstract
654 if ( !mAbstract.isEmpty() )
655 {
656 QDomElement layerAbstract = document.createElement( QStringLiteral( "abstract" ) );
657 const QDomText layerAbstractText = document.createTextNode( mAbstract );
658 layerAbstract.appendChild( layerAbstractText );
659 layerElement.appendChild( layerAbstract );
660 }
661
662 // layer keyword list
663 const QStringList keywordStringList = keywordList().split( ',' );
664 if ( !keywordStringList.isEmpty() )
665 {
666 QDomElement layerKeywordList = document.createElement( QStringLiteral( "keywordList" ) );
667 for ( int i = 0; i < keywordStringList.size(); ++i )
668 {
669 QDomElement layerKeywordValue = document.createElement( QStringLiteral( "value" ) );
670 const QDomText layerKeywordText = document.createTextNode( keywordStringList.at( i ).trimmed() );
671 layerKeywordValue.appendChild( layerKeywordText );
672 layerKeywordList.appendChild( layerKeywordValue );
673 }
674 layerElement.appendChild( layerKeywordList );
675 }
676
677 // layer dataUrl
678 const QString aDataUrl = dataUrl();
679 if ( !aDataUrl.isEmpty() )
680 {
681 QDomElement layerDataUrl = document.createElement( QStringLiteral( "dataUrl" ) );
682 const QDomText layerDataUrlText = document.createTextNode( aDataUrl );
683 layerDataUrl.appendChild( layerDataUrlText );
684 layerDataUrl.setAttribute( QStringLiteral( "format" ), dataUrlFormat() );
685 layerElement.appendChild( layerDataUrl );
686 }
687
688 // layer legendUrl
689 const QString aLegendUrl = legendUrl();
690 if ( !aLegendUrl.isEmpty() )
691 {
692 QDomElement layerLegendUrl = document.createElement( QStringLiteral( "legendUrl" ) );
693 const QDomText layerLegendUrlText = document.createTextNode( aLegendUrl );
694 layerLegendUrl.appendChild( layerLegendUrlText );
695 layerLegendUrl.setAttribute( QStringLiteral( "format" ), legendUrlFormat() );
696 layerElement.appendChild( layerLegendUrl );
697 }
698
699 // layer attribution
700 const QString aAttribution = attribution();
701 if ( !aAttribution.isEmpty() )
702 {
703 QDomElement layerAttribution = document.createElement( QStringLiteral( "attribution" ) );
704 const QDomText layerAttributionText = document.createTextNode( aAttribution );
705 layerAttribution.appendChild( layerAttributionText );
706 layerAttribution.setAttribute( QStringLiteral( "href" ), attributionUrl() );
707 layerElement.appendChild( layerAttribution );
708 }
709
710 // timestamp if supported
711 if ( timestamp() > QDateTime() )
712 {
713 QDomElement stamp = document.createElement( QStringLiteral( "timestamp" ) );
714 const QDomText stampText = document.createTextNode( timestamp().toString( Qt::ISODate ) );
715 stamp.appendChild( stampText );
716 layerElement.appendChild( stamp );
717 }
718
719 layerElement.appendChild( layerName );
720
721 // zorder
722 // This is no longer stored in the project file. It is superfluous since the layers
723 // are written and read in the proper order.
724
725 // spatial reference system id
726 QDomElement mySrsElement = document.createElement( QStringLiteral( "srs" ) );
727 mCRS.writeXml( mySrsElement, document );
728 layerElement.appendChild( mySrsElement );
729
730 // layer metadata
731 QDomElement myMetadataElem = document.createElement( QStringLiteral( "resourceMetadata" ) );
732 mMetadata.writeMetadataXml( myMetadataElem, document );
733 layerElement.appendChild( myMetadataElem );
734
735 layerElement.setAttribute( QStringLiteral( "legendPlaceholderImage" ), mLegendPlaceholderImage );
736
737 // now append layer node to map layer node
738 return writeXml( layerElement, document, context );
739}
740
741void QgsMapLayer::writeCommonStyle( QDomElement &layerElement, QDomDocument &document,
742 const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
743{
745
746 // save categories
747 const QMetaEnum metaEnum = QMetaEnum::fromType<QgsMapLayer::StyleCategories>();
748 const QString categoriesKeys( metaEnum.valueToKeys( static_cast<int>( categories ) ) );
749 layerElement.setAttribute( QStringLiteral( "styleCategories" ), categoriesKeys );
750
751 if ( categories.testFlag( Rendering ) )
752 {
753 // use scale dependent visibility flag
754 layerElement.setAttribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ), hasScaleBasedVisibility() ? 1 : 0 );
755 layerElement.setAttribute( QStringLiteral( "maxScale" ), QString::number( maximumScale() ) );
756 layerElement.setAttribute( QStringLiteral( "minScale" ), QString::number( minimumScale() ) );
757 }
758
759 if ( categories.testFlag( Symbology3D ) )
760 {
761 if ( m3DRenderer )
762 {
763 QDomElement renderer3DElem = document.createElement( QStringLiteral( "renderer-3d" ) );
764 renderer3DElem.setAttribute( QStringLiteral( "type" ), m3DRenderer->type() );
765 m3DRenderer->writeXml( renderer3DElem, context );
766 layerElement.appendChild( renderer3DElem );
767 }
768 }
769
770 if ( categories.testFlag( LayerConfiguration ) )
771 {
772 // flags
773 // this code is saving automatically all the flags entries
774 QDomElement layerFlagsElem = document.createElement( QStringLiteral( "flags" ) );
775 const auto enumMap = qgsEnumMap<QgsMapLayer::LayerFlag>();
776 for ( auto it = enumMap.constBegin(); it != enumMap.constEnd(); ++it )
777 {
778 const bool flagValue = mFlags.testFlag( it.key() );
779 QDomElement flagElem = document.createElement( it.value() );
780 flagElem.appendChild( document.createTextNode( QString::number( flagValue ) ) );
781 layerFlagsElem.appendChild( flagElem );
782 }
783 layerElement.appendChild( layerFlagsElem );
784 }
785
786 if ( categories.testFlag( Temporal ) )
787 {
789 properties->writeXml( layerElement, document, context );
790 }
791
792 if ( categories.testFlag( Elevation ) )
793 {
795 properties->writeXml( layerElement, document, context );
796 }
797
798 if ( categories.testFlag( Notes ) && QgsLayerNotesUtils::layerHasNotes( this ) )
799 {
800 QDomElement notesElem = document.createElement( QStringLiteral( "userNotes" ) );
801 notesElem.setAttribute( QStringLiteral( "value" ), QgsLayerNotesUtils::layerNotes( this ) );
802 layerElement.appendChild( notesElem );
803 }
804
805 // custom properties
806 if ( categories.testFlag( CustomProperties ) )
807 {
808 writeCustomProperties( layerElement, document );
809 }
810}
811
812
813bool QgsMapLayer::writeXml( QDomNode &layer_node, QDomDocument &document, const QgsReadWriteContext &context ) const
814{
816
817 Q_UNUSED( layer_node )
818 Q_UNUSED( document )
819 Q_UNUSED( context )
820 // NOP by default; children will over-ride with behavior specific to them
821
822 return true;
823}
824
825QString QgsMapLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
826{
828
829 Q_UNUSED( context )
830 return source;
831}
832
833QString QgsMapLayer::decodedSource( const QString &source, const QString &dataProvider, const QgsReadWriteContext &context ) const
834{
836
837 Q_UNUSED( context )
838 Q_UNUSED( dataProvider )
839 return source;
840}
841
843{
845
847 if ( m3DRenderer )
848 m3DRenderer->resolveReferences( *project );
849}
850
851
852void QgsMapLayer::readCustomProperties( const QDomNode &layerNode, const QString &keyStartsWith )
853{
855
856 const QgsObjectCustomProperties oldKeys = mCustomProperties;
857
858 mCustomProperties.readXml( layerNode, keyStartsWith );
859
860 for ( const QString &key : mCustomProperties.keys() )
861 {
862 if ( !oldKeys.contains( key ) || mCustomProperties.value( key ) != oldKeys.value( key ) )
863 {
864 emit customPropertyChanged( key );
865 }
866 }
867}
868
869void QgsMapLayer::writeCustomProperties( QDomNode &layerNode, QDomDocument &doc ) const
870{
872
873 mCustomProperties.writeXml( layerNode, doc );
874}
875
876void QgsMapLayer::readStyleManager( const QDomNode &layerNode )
877{
879
880 const QDomElement styleMgrElem = layerNode.firstChildElement( QStringLiteral( "map-layer-style-manager" ) );
881 if ( !styleMgrElem.isNull() )
882 mStyleManager->readXml( styleMgrElem );
883 else
884 mStyleManager->reset();
885}
886
887void QgsMapLayer::writeStyleManager( QDomNode &layerNode, QDomDocument &doc ) const
888{
890
891 if ( mStyleManager )
892 {
893 QDomElement styleMgrElem = doc.createElement( QStringLiteral( "map-layer-style-manager" ) );
894 mStyleManager->writeXml( styleMgrElem );
895 layerNode.appendChild( styleMgrElem );
896 }
897}
898
900{
902
903 return mMapTipTemplate;
904}
905
906void QgsMapLayer::setMapTipTemplate( const QString &mapTip )
907{
909
910 if ( mMapTipTemplate == mapTip )
911 return;
912
913 mMapTipTemplate = mapTip;
915}
916
918{
920
921 if ( mMapTipsEnabled == enabled )
922 return;
923
924 mMapTipsEnabled = enabled;
926}
927
929{
931
932 return mMapTipsEnabled;
933}
934
935QgsDataProvider::ReadFlags QgsMapLayer::providerReadFlags( const QDomNode &layerNode, QgsMapLayer::ReadFlags layerReadFlags )
936{
937 QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags();
938 if ( layerReadFlags & QgsMapLayer::FlagTrustLayerMetadata )
939 {
941 }
942 if ( layerReadFlags & QgsMapLayer::FlagForceReadOnly )
943 {
945 }
946
947 if ( layerReadFlags & QgsMapLayer::FlagReadExtentFromXml )
948 {
949 const QDomNode extentNode = layerNode.namedItem( QStringLiteral( "extent" ) );
950 if ( !extentNode.isNull() )
951 {
953 }
954 }
955
956 return flags;
957}
958
960{
961 // because QgsVirtualLayerProvider is not anywhere NEAR thread safe:
963
964 return mValid;
965}
966
967#if 0
968void QgsMapLayer::connectNotify( const char *signal )
969{
970 Q_UNUSED( signal )
971 QgsDebugMsgLevel( "QgsMapLayer connected to " + QString( signal ), 3 );
972} // QgsMapLayer::connectNotify
973#endif
974
975bool QgsMapLayer::isInScaleRange( double scale ) const
976{
977 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
979
980 return !mScaleBasedVisibility ||
981 ( ( mMinScale == 0 || mMinScale * Qgis::SCALE_PRECISION < scale )
982 && ( mMaxScale == 0 || scale < mMaxScale ) );
983}
984
986{
987 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
989
990 return mScaleBasedVisibility;
991}
992
994{
996
997 return mRefreshTimer->isActive();
998}
999
1001{
1003
1004 return mRefreshTimer->interval();
1005}
1006
1008{
1010
1011 if ( interval <= 0 )
1012 {
1013 mRefreshTimer->stop();
1014 mRefreshTimer->setInterval( 0 );
1015 }
1016 else
1017 {
1018 mRefreshTimer->setInterval( interval );
1019 }
1020 emit autoRefreshIntervalChanged( mRefreshTimer->isActive() ? mRefreshTimer->interval() : 0 );
1021}
1022
1024{
1026
1027 if ( !enabled )
1028 mRefreshTimer->stop();
1029 else if ( mRefreshTimer->interval() > 0 )
1030 mRefreshTimer->start();
1031
1032 emit autoRefreshIntervalChanged( mRefreshTimer->isActive() ? mRefreshTimer->interval() : 0 );
1033}
1034
1036{
1038
1039 return mMetadata;
1040}
1041
1043{
1045
1046 mMinScale = scale;
1047}
1048
1050{
1052
1053 return mMinScale;
1054}
1055
1057{
1059
1060 mMaxScale = scale;
1061}
1062
1064{
1066
1067 mScaleBasedVisibility = enabled;
1068}
1069
1071{
1073
1074 return mMaxScale;
1075}
1076
1077QStringList QgsMapLayer::subLayers() const
1078{
1080
1081 return QStringList();
1082}
1083
1084void QgsMapLayer::setLayerOrder( const QStringList &layers )
1085{
1087
1088 Q_UNUSED( layers )
1089}
1090
1091void QgsMapLayer::setSubLayerVisibility( const QString &name, bool vis )
1092{
1094
1095 Q_UNUSED( name )
1096 Q_UNUSED( vis )
1097}
1098
1100{
1102
1103 return false;
1104}
1105
1107{
1108 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
1110
1111 return mCRS;
1112}
1113
1114void QgsMapLayer::setCrs( const QgsCoordinateReferenceSystem &srs, bool emitSignal )
1115{
1117
1118 mCRS = srs;
1119
1120 if ( mShouldValidateCrs && isSpatial() && !mCRS.isValid() && type() != Qgis::LayerType::Annotation )
1121 {
1122 mCRS.setValidationHint( tr( "Specify CRS for layer %1" ).arg( name() ) );
1123 mCRS.validate();
1124 }
1125
1126 if ( emitSignal )
1127 emit crsChanged();
1128}
1129
1131{
1133
1134 const QgsDataProvider *lDataProvider = dataProvider();
1135 return lDataProvider ? lDataProvider->transformContext() : QgsCoordinateTransformContext();
1136}
1137
1138QString QgsMapLayer::formatLayerName( const QString &name )
1139{
1140 QString layerName( name );
1141 layerName.replace( '_', ' ' );
1143 return layerName;
1144}
1145
1146QString QgsMapLayer::baseURI( PropertyType type ) const
1147{
1149
1150 QString myURI = publicSource();
1151
1152 // first get base path for delimited text, spatialite and OGR layers,
1153 // as in these cases URI may contain layer name and/or additional
1154 // information. This also strips prefix in case if VSIFILE mechanism
1155 // is used
1156 if ( providerType() == QLatin1String( "ogr" ) || providerType() == QLatin1String( "delimitedtext" )
1157 || providerType() == QLatin1String( "gdal" ) || providerType() == QLatin1String( "spatialite" ) )
1158 {
1159 QVariantMap components = QgsProviderRegistry::instance()->decodeUri( providerType(), myURI );
1160 myURI = components["path"].toString();
1161 }
1162
1163 QFileInfo myFileInfo( myURI );
1164 QString key;
1165
1166 if ( myFileInfo.exists() )
1167 {
1168 // if file is using the /vsizip/ or /vsigzip/ mechanism, cleanup the name
1169 if ( myURI.endsWith( QLatin1String( ".gz" ), Qt::CaseInsensitive ) )
1170 myURI.chop( 3 );
1171 else if ( myURI.endsWith( QLatin1String( ".zip" ), Qt::CaseInsensitive ) )
1172 myURI.chop( 4 );
1173 else if ( myURI.endsWith( QLatin1String( ".tar" ), Qt::CaseInsensitive ) )
1174 myURI.chop( 4 );
1175 else if ( myURI.endsWith( QLatin1String( ".tar.gz" ), Qt::CaseInsensitive ) )
1176 myURI.chop( 7 );
1177 else if ( myURI.endsWith( QLatin1String( ".tgz" ), Qt::CaseInsensitive ) )
1178 myURI.chop( 4 );
1179 myFileInfo.setFile( myURI );
1180 // get the file name for our .qml style file
1181 key = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + QgsMapLayer::extensionPropertyType( type );
1182 }
1183 else
1184 {
1185 key = publicSource();
1186 }
1187
1188 return key;
1189}
1190
1192{
1194
1195 return baseURI( PropertyType::Metadata );
1196}
1197
1198QString QgsMapLayer::saveDefaultMetadata( bool &resultFlag )
1199{
1201
1202 if ( const QgsProviderMetadata *metadata = QgsProviderRegistry::instance()->providerMetadata( providerType() ) )
1203 {
1204 if ( metadata->providerCapabilities() & QgsProviderMetadata::SaveLayerMetadata )
1205 {
1206 try
1207 {
1208 QString errorMessage;
1209 resultFlag = QgsProviderRegistry::instance()->saveLayerMetadata( providerType(), mDataSource, mMetadata, errorMessage );
1210 if ( resultFlag )
1211 return tr( "Successfully saved default layer metadata" );
1212 else
1213 return errorMessage;
1214 }
1215 catch ( QgsNotSupportedException &e )
1216 {
1217 resultFlag = false;
1218 return e.what();
1219 }
1220 }
1221 }
1222
1223 // fallback default metadata saving method, for providers which don't support (or implement) saveLayerMetadata
1224 return saveNamedMetadata( metadataUri(), resultFlag );
1225}
1226
1227QString QgsMapLayer::loadDefaultMetadata( bool &resultFlag )
1228{
1230
1231 return loadNamedMetadata( metadataUri(), resultFlag );
1232}
1233
1235{
1237
1238 return baseURI( PropertyType::Style );
1239}
1240
1241QString QgsMapLayer::loadDefaultStyle( bool &resultFlag )
1242{
1244
1245 return loadNamedStyle( styleURI(), resultFlag );
1246}
1247
1248bool QgsMapLayer::loadNamedMetadataFromDatabase( const QString &db, const QString &uri, QString &qmd )
1249{
1251
1252 return loadNamedPropertyFromDatabase( db, uri, qmd, PropertyType::Metadata );
1253}
1254
1255bool QgsMapLayer::loadNamedStyleFromDatabase( const QString &db, const QString &uri, QString &qml )
1256{
1258
1259 return loadNamedPropertyFromDatabase( db, uri, qml, PropertyType::Style );
1260}
1261
1262bool QgsMapLayer::loadNamedPropertyFromDatabase( const QString &db, const QString &uri, QString &xml, QgsMapLayer::PropertyType type )
1263{
1265
1266 QgsDebugMsgLevel( QStringLiteral( "db = %1 uri = %2" ).arg( db, uri ), 4 );
1267
1268 bool resultFlag = false;
1269
1270 // read from database
1273
1274 int myResult;
1275
1276 QgsDebugMsgLevel( QStringLiteral( "Trying to load style or metadata for \"%1\" from \"%2\"" ).arg( uri, db ), 4 );
1277
1278 if ( db.isEmpty() || !QFile( db ).exists() )
1279 return false;
1280
1281 myResult = database.open_v2( db, SQLITE_OPEN_READONLY, nullptr );
1282 if ( myResult != SQLITE_OK )
1283 {
1284 return false;
1285 }
1286
1287 QString mySql;
1288 switch ( type )
1289 {
1290 case Metadata:
1291 mySql = QStringLiteral( "select qmd from tbl_metadata where metadata=?" );
1292 break;
1293
1294 case Style:
1295 mySql = QStringLiteral( "select qml from tbl_styles where style=?" );
1296 break;
1297 }
1298
1299 statement = database.prepare( mySql, myResult );
1300 if ( myResult == SQLITE_OK )
1301 {
1302 QByteArray param = uri.toUtf8();
1303
1304 if ( sqlite3_bind_text( statement.get(), 1, param.data(), param.length(), SQLITE_STATIC ) == SQLITE_OK &&
1305 sqlite3_step( statement.get() ) == SQLITE_ROW )
1306 {
1307 xml = QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( statement.get(), 0 ) ) );
1308 resultFlag = true;
1309 }
1310 }
1311 return resultFlag;
1312}
1313
1314
1315QString QgsMapLayer::loadNamedStyle( const QString &uri, bool &resultFlag, QgsMapLayer::StyleCategories categories )
1316{
1318
1319 return loadNamedProperty( uri, PropertyType::Style, resultFlag, categories );
1320}
1321
1322QString QgsMapLayer::loadNamedProperty( const QString &uri, QgsMapLayer::PropertyType type, bool &resultFlag, StyleCategories categories )
1323{
1325
1326 QgsDebugMsgLevel( QStringLiteral( "uri = %1 myURI = %2" ).arg( uri, publicSource() ), 4 );
1327
1328 resultFlag = false;
1329 if ( uri.isEmpty() )
1330 return QString();
1331
1332 QDomDocument myDocument( QStringLiteral( "qgis" ) );
1333
1334 // location of problem associated with errorMsg
1335 int line, column;
1336 QString myErrorMessage;
1337
1338 QFile myFile( uri );
1339 if ( myFile.open( QFile::ReadOnly ) )
1340 {
1341 QgsDebugMsgLevel( QStringLiteral( "file found %1" ).arg( uri ), 2 );
1342 // read file
1343 resultFlag = myDocument.setContent( &myFile, &myErrorMessage, &line, &column );
1344 if ( !resultFlag )
1345 myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1346 myFile.close();
1347 }
1348 else
1349 {
1350 const QFileInfo project( QgsProject::instance()->fileName() );
1351 QgsDebugMsgLevel( QStringLiteral( "project fileName: %1" ).arg( project.absoluteFilePath() ), 4 );
1352
1353 QString xml;
1354 switch ( type )
1355 {
1356 case QgsMapLayer::Style:
1357 {
1358 if ( loadNamedStyleFromDatabase( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ), uri, xml ) ||
1359 ( project.exists() && loadNamedStyleFromDatabase( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), uri, xml ) ) ||
1360 loadNamedStyleFromDatabase( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( QStringLiteral( "resources/qgis.qmldb" ) ), uri, xml ) )
1361 {
1362 resultFlag = myDocument.setContent( xml, &myErrorMessage, &line, &column );
1363 if ( !resultFlag )
1364 {
1365 myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1366 }
1367 }
1368 else
1369 {
1370 myErrorMessage = tr( "Style not found in database" );
1371 resultFlag = false;
1372 }
1373 break;
1374 }
1376 {
1377 if ( loadNamedMetadataFromDatabase( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ), uri, xml ) ||
1378 ( project.exists() && loadNamedMetadataFromDatabase( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), uri, xml ) ) ||
1379 loadNamedMetadataFromDatabase( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( QStringLiteral( "resources/qgis.qmldb" ) ), uri, xml ) )
1380 {
1381 resultFlag = myDocument.setContent( xml, &myErrorMessage, &line, &column );
1382 if ( !resultFlag )
1383 {
1384 myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1385 }
1386 }
1387 else
1388 {
1389 myErrorMessage = tr( "Metadata not found in database" );
1390 resultFlag = false;
1391 }
1392 break;
1393 }
1394 }
1395 }
1396
1397 if ( !resultFlag )
1398 {
1399 return myErrorMessage;
1400 }
1401
1402 switch ( type )
1403 {
1404 case QgsMapLayer::Style:
1405 resultFlag = importNamedStyle( myDocument, myErrorMessage, categories );
1406 if ( !resultFlag )
1407 myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( uri, myErrorMessage );
1408 break;
1410 resultFlag = importNamedMetadata( myDocument, myErrorMessage );
1411 if ( !resultFlag )
1412 myErrorMessage = tr( "Loading metadata file %1 failed because:\n%2" ).arg( uri, myErrorMessage );
1413 break;
1414 }
1415 return myErrorMessage;
1416}
1417
1418bool QgsMapLayer::importNamedMetadata( QDomDocument &document, QString &errorMessage )
1419{
1421
1422 const QDomElement myRoot = document.firstChildElement( QStringLiteral( "qgis" ) );
1423 if ( myRoot.isNull() )
1424 {
1425 errorMessage = tr( "Root <qgis> element could not be found" );
1426 return false;
1427 }
1428
1429 return mMetadata.readMetadataXml( myRoot );
1430}
1431
1432bool QgsMapLayer::importNamedStyle( QDomDocument &myDocument, QString &myErrorMessage, QgsMapLayer::StyleCategories categories )
1433{
1435
1436 const QDomElement myRoot = myDocument.firstChildElement( QStringLiteral( "qgis" ) );
1437 if ( myRoot.isNull() )
1438 {
1439 myErrorMessage = tr( "Root <qgis> element could not be found" );
1440 return false;
1441 }
1442
1443 // get style file version string, if any
1444 const QgsProjectVersion fileVersion( myRoot.attribute( QStringLiteral( "version" ) ) );
1445 const QgsProjectVersion thisVersion( Qgis::version() );
1446
1447 if ( thisVersion > fileVersion )
1448 {
1449 QgsProjectFileTransform styleFile( myDocument, fileVersion );
1450 styleFile.updateRevision( thisVersion );
1451 }
1452
1453 // Get source categories
1454 const QgsMapLayer::StyleCategories sourceCategories = QgsXmlUtils::readFlagAttribute( myRoot, QStringLiteral( "styleCategories" ), QgsMapLayer::AllStyleCategories );
1455
1456 //Test for matching geometry type on vector layers when applying, if geometry type is given in the style
1457 if ( ( sourceCategories.testFlag( QgsMapLayer::Symbology ) || sourceCategories.testFlag( QgsMapLayer::Symbology3D ) ) &&
1458 ( categories.testFlag( QgsMapLayer::Symbology ) || categories.testFlag( QgsMapLayer::Symbology3D ) ) )
1459 {
1460 if ( type() == Qgis::LayerType::Vector && !myRoot.firstChildElement( QStringLiteral( "layerGeometryType" ) ).isNull() )
1461 {
1462 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( this );
1463 const Qgis::GeometryType importLayerGeometryType = static_cast<Qgis::GeometryType>( myRoot.firstChildElement( QStringLiteral( "layerGeometryType" ) ).text().toInt() );
1464 if ( importLayerGeometryType != Qgis::GeometryType::Unknown && vl->geometryType() != importLayerGeometryType )
1465 {
1466 myErrorMessage = tr( "Cannot apply style with symbology to layer with a different geometry type" );
1467 return false;
1468 }
1469 }
1470 }
1471
1473 return readSymbology( myRoot, myErrorMessage, context, categories ); // TODO: support relative paths in QML?
1474}
1475
1476void QgsMapLayer::exportNamedMetadata( QDomDocument &doc, QString &errorMsg ) const
1477{
1479
1480 QDomImplementation DomImplementation;
1481 const QDomDocumentType documentType = DomImplementation.createDocumentType( QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
1482 QDomDocument myDocument( documentType );
1483
1484 QDomElement myRootNode = myDocument.createElement( QStringLiteral( "qgis" ) );
1485 myRootNode.setAttribute( QStringLiteral( "version" ), Qgis::version() );
1486 myDocument.appendChild( myRootNode );
1487
1488 if ( !mMetadata.writeMetadataXml( myRootNode, myDocument ) )
1489 {
1490 errorMsg = QObject::tr( "Could not save metadata" );
1491 return;
1492 }
1493
1494 doc = myDocument;
1495}
1496
1497void QgsMapLayer::exportNamedStyle( QDomDocument &doc, QString &errorMsg, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1498{
1500
1501 QDomImplementation DomImplementation;
1502 const QDomDocumentType documentType = DomImplementation.createDocumentType( QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
1503 QDomDocument myDocument( documentType );
1504
1505 QDomElement myRootNode = myDocument.createElement( QStringLiteral( "qgis" ) );
1506 myRootNode.setAttribute( QStringLiteral( "version" ), Qgis::version() );
1507 myDocument.appendChild( myRootNode );
1508
1509 if ( !writeSymbology( myRootNode, myDocument, errorMsg, context, categories ) ) // TODO: support relative paths in QML?
1510 {
1511 errorMsg = QObject::tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1512 return;
1513 }
1514
1515 /*
1516 * Check to see if the layer is vector - in which case we should also export its geometryType
1517 * to avoid eventually pasting to a layer with a different geometry
1518 */
1519 if ( type() == Qgis::LayerType::Vector )
1520 {
1521 //Getting the selectionLayer geometry
1522 const QgsVectorLayer *vl = qobject_cast<const QgsVectorLayer *>( this );
1523 const QString geoType = QString::number( static_cast<int>( vl->geometryType() ) );
1524
1525 //Adding geometryinformation
1526 QDomElement layerGeometryType = myDocument.createElement( QStringLiteral( "layerGeometryType" ) );
1527 const QDomText type = myDocument.createTextNode( geoType );
1528
1529 layerGeometryType.appendChild( type );
1530 myRootNode.appendChild( layerGeometryType );
1531 }
1532
1533 doc = myDocument;
1534}
1535
1536QString QgsMapLayer::saveDefaultStyle( bool &resultFlag )
1537{
1539
1540 return saveDefaultStyle( resultFlag, AllStyleCategories );
1541}
1542
1543QString QgsMapLayer::saveDefaultStyle( bool &resultFlag, StyleCategories categories )
1544{
1546
1547 return saveNamedStyle( styleURI(), resultFlag, categories );
1548}
1549
1550QString QgsMapLayer::saveNamedMetadata( const QString &uri, bool &resultFlag )
1551{
1553
1554 return saveNamedProperty( uri, QgsMapLayer::Metadata, resultFlag );
1555}
1556
1557QString QgsMapLayer::loadNamedMetadata( const QString &uri, bool &resultFlag )
1558{
1560
1561 return loadNamedProperty( uri, QgsMapLayer::Metadata, resultFlag );
1562}
1563
1564QString QgsMapLayer::saveNamedProperty( const QString &uri, QgsMapLayer::PropertyType type, bool &resultFlag, StyleCategories categories )
1565{
1567
1568 // check if the uri is a file or ends with .qml/.qmd,
1569 // which indicates that it should become one
1570 // everything else goes to the database
1571 QString filename;
1572
1573 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this );
1574 if ( vlayer && vlayer->providerType() == QLatin1String( "ogr" ) )
1575 {
1576 QStringList theURIParts = uri.split( '|' );
1577 filename = theURIParts[0];
1578 }
1579 else if ( vlayer && vlayer->providerType() == QLatin1String( "gpx" ) )
1580 {
1581 QStringList theURIParts = uri.split( '?' );
1582 filename = theURIParts[0];
1583 }
1584 else if ( vlayer && vlayer->providerType() == QLatin1String( "delimitedtext" ) )
1585 {
1586 filename = QUrl::fromEncoded( uri.toLatin1() ).toLocalFile();
1587 // toLocalFile() returns an empty string if theURI is a plain Windows-path, e.g. "C:/style.qml"
1588 if ( filename.isEmpty() )
1589 filename = uri;
1590 }
1591 else
1592 {
1593 filename = uri;
1594 }
1595
1596 QString myErrorMessage;
1597 QDomDocument myDocument;
1598 switch ( type )
1599 {
1600 case Metadata:
1601 exportNamedMetadata( myDocument, myErrorMessage );
1602 break;
1603
1604 case Style:
1605 const QgsReadWriteContext context;
1606 exportNamedStyle( myDocument, myErrorMessage, context, categories );
1607 break;
1608 }
1609
1610 const QFileInfo myFileInfo( filename );
1611 if ( myFileInfo.exists() || filename.endsWith( QgsMapLayer::extensionPropertyType( type ), Qt::CaseInsensitive ) )
1612 {
1613 const QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
1614 if ( !myDirInfo.isWritable() )
1615 {
1616 return tr( "The directory containing your dataset needs to be writable!" );
1617 }
1618
1619 // now construct the file name for our .qml or .qmd file
1620 const QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + QgsMapLayer::extensionPropertyType( type );
1621
1622 QFile myFile( myFileName );
1623 if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
1624 {
1625 QTextStream myFileStream( &myFile );
1626 // save as utf-8 with 2 spaces for indents
1627 myDocument.save( myFileStream, 2 );
1628 myFile.close();
1629 resultFlag = true;
1630 switch ( type )
1631 {
1632 case Metadata:
1633 return tr( "Created default metadata file as %1" ).arg( myFileName );
1634
1635 case Style:
1636 return tr( "Created default style file as %1" ).arg( myFileName );
1637 }
1638
1639 }
1640 else
1641 {
1642 resultFlag = false;
1643 switch ( type )
1644 {
1645 case Metadata:
1646 return tr( "ERROR: Failed to created default metadata file as %1. Check file permissions and retry." ).arg( myFileName );
1647
1648 case Style:
1649 return tr( "ERROR: Failed to created default style file as %1. Check file permissions and retry." ).arg( myFileName );
1650 }
1651 }
1652 }
1653 else
1654 {
1655 const QString qml = myDocument.toString();
1656
1657 // read from database
1660
1661 int myResult = database.open( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ) );
1662 if ( myResult != SQLITE_OK )
1663 {
1664 return tr( "User database could not be opened." );
1665 }
1666
1667 QByteArray param0 = uri.toUtf8();
1668 QByteArray param1 = qml.toUtf8();
1669
1670 QString mySql;
1671 switch ( type )
1672 {
1673 case Metadata:
1674 mySql = QStringLiteral( "create table if not exists tbl_metadata(metadata varchar primary key,qmd varchar)" );
1675 break;
1676
1677 case Style:
1678 mySql = QStringLiteral( "create table if not exists tbl_styles(style varchar primary key,qml varchar)" );
1679 break;
1680 }
1681
1682 statement = database.prepare( mySql, myResult );
1683 if ( myResult == SQLITE_OK )
1684 {
1685 if ( sqlite3_step( statement.get() ) != SQLITE_DONE )
1686 {
1687 resultFlag = false;
1688 switch ( type )
1689 {
1690 case Metadata:
1691 return tr( "The metadata table could not be created." );
1692
1693 case Style:
1694 return tr( "The style table could not be created." );
1695 }
1696 }
1697 }
1698
1699 switch ( type )
1700 {
1701 case Metadata:
1702 mySql = QStringLiteral( "insert into tbl_metadata(metadata,qmd) values (?,?)" );
1703 break;
1704
1705 case Style:
1706 mySql = QStringLiteral( "insert into tbl_styles(style,qml) values (?,?)" );
1707 break;
1708 }
1709 statement = database.prepare( mySql, myResult );
1710 if ( myResult == SQLITE_OK )
1711 {
1712 if ( sqlite3_bind_text( statement.get(), 1, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
1713 sqlite3_bind_text( statement.get(), 2, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
1714 sqlite3_step( statement.get() ) == SQLITE_DONE )
1715 {
1716 resultFlag = true;
1717 switch ( type )
1718 {
1719 case Metadata:
1720 myErrorMessage = tr( "The metadata %1 was saved to database" ).arg( uri );
1721 break;
1722
1723 case Style:
1724 myErrorMessage = tr( "The style %1 was saved to database" ).arg( uri );
1725 break;
1726 }
1727 }
1728 }
1729
1730 if ( !resultFlag )
1731 {
1732 QString mySql;
1733 switch ( type )
1734 {
1735 case Metadata:
1736 mySql = QStringLiteral( "update tbl_metadata set qmd=? where metadata=?" );
1737 break;
1738
1739 case Style:
1740 mySql = QStringLiteral( "update tbl_styles set qml=? where style=?" );
1741 break;
1742 }
1743 statement = database.prepare( mySql, myResult );
1744 if ( myResult == SQLITE_OK )
1745 {
1746 if ( sqlite3_bind_text( statement.get(), 2, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
1747 sqlite3_bind_text( statement.get(), 1, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
1748 sqlite3_step( statement.get() ) == SQLITE_DONE )
1749 {
1750 resultFlag = true;
1751 switch ( type )
1752 {
1753 case Metadata:
1754 myErrorMessage = tr( "The metadata %1 was updated in the database." ).arg( uri );
1755 break;
1756
1757 case Style:
1758 myErrorMessage = tr( "The style %1 was updated in the database." ).arg( uri );
1759 break;
1760 }
1761 }
1762 else
1763 {
1764 resultFlag = false;
1765 switch ( type )
1766 {
1767 case Metadata:
1768 myErrorMessage = tr( "The metadata %1 could not be updated in the database." ).arg( uri );
1769 break;
1770
1771 case Style:
1772 myErrorMessage = tr( "The style %1 could not be updated in the database." ).arg( uri );
1773 break;
1774 }
1775 }
1776 }
1777 else
1778 {
1779 resultFlag = false;
1780 switch ( type )
1781 {
1782 case Metadata:
1783 myErrorMessage = tr( "The metadata %1 could not be inserted into database." ).arg( uri );
1784 break;
1785
1786 case Style:
1787 myErrorMessage = tr( "The style %1 could not be inserted into database." ).arg( uri );
1788 break;
1789 }
1790 }
1791 }
1792 }
1793
1794 return myErrorMessage;
1795}
1796
1797QString QgsMapLayer::saveNamedStyle( const QString &uri, bool &resultFlag, StyleCategories categories )
1798{
1800
1801 return saveNamedProperty( uri, QgsMapLayer::Style, resultFlag, categories );
1802}
1803
1804void QgsMapLayer::exportSldStyle( QDomDocument &doc, QString &errorMsg ) const
1805{
1806
1807 return exportSldStyleV2( doc, errorMsg, QgsSldExportContext() );
1808}
1809
1810void QgsMapLayer::exportSldStyleV2( QDomDocument &doc, QString &errorMsg, const QgsSldExportContext &exportContext ) const
1811{
1813
1814 QDomDocument myDocument = QDomDocument();
1815
1816 const QDomNode header = myDocument.createProcessingInstruction( QStringLiteral( "xml" ), QStringLiteral( "version=\"1.0\" encoding=\"UTF-8\"" ) );
1817 myDocument.appendChild( header );
1818
1819 const QgsVectorLayer *vlayer = qobject_cast<const QgsVectorLayer *>( this );
1820 const QgsRasterLayer *rlayer = qobject_cast<const QgsRasterLayer *>( this );
1821 if ( !vlayer && !rlayer )
1822 {
1823 errorMsg = tr( "Could not save symbology because:\n%1" )
1824 .arg( tr( "Only vector and raster layers are supported" ) );
1825 return;
1826 }
1827
1828 // Create the root element
1829 QDomElement root = myDocument.createElementNS( QStringLiteral( "http://www.opengis.net/sld" ), QStringLiteral( "StyledLayerDescriptor" ) );
1830 QDomElement layerNode;
1831 if ( vlayer )
1832 {
1833 root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.1.0" ) );
1834 root.setAttribute( QStringLiteral( "xsi:schemaLocation" ), QStringLiteral( "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" ) );
1835 root.setAttribute( QStringLiteral( "xmlns:ogc" ), QStringLiteral( "http://www.opengis.net/ogc" ) );
1836 root.setAttribute( QStringLiteral( "xmlns:se" ), QStringLiteral( "http://www.opengis.net/se" ) );
1837 root.setAttribute( QStringLiteral( "xmlns:xlink" ), QStringLiteral( "http://www.w3.org/1999/xlink" ) );
1838 root.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) );
1839 myDocument.appendChild( root );
1840
1841 // Create the NamedLayer element
1842 layerNode = myDocument.createElement( QStringLiteral( "NamedLayer" ) );
1843 root.appendChild( layerNode );
1844 }
1845
1846 // note: Only SLD 1.0 version is generated because seems none is using SE1.1.0 at least for rasters
1847 if ( rlayer )
1848 {
1849 // Create the root element
1850 root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0.0" ) );
1851 root.setAttribute( QStringLiteral( "xmlns:gml" ), QStringLiteral( "http://www.opengis.net/gml" ) );
1852 root.setAttribute( QStringLiteral( "xmlns:ogc" ), QStringLiteral( "http://www.opengis.net/ogc" ) );
1853 root.setAttribute( QStringLiteral( "xmlns:sld" ), QStringLiteral( "http://www.opengis.net/sld" ) );
1854 myDocument.appendChild( root );
1855
1856 // Create the NamedLayer element
1857 layerNode = myDocument.createElement( QStringLiteral( "UserLayer" ) );
1858 root.appendChild( layerNode );
1859 }
1860
1861 QVariantMap props;
1862
1863 QVariant context;
1864 context.setValue( exportContext );
1865
1866 props[ QStringLiteral( "SldExportContext" ) ] = context;
1867
1869 {
1870 props[ QStringLiteral( "scaleMinDenom" ) ] = QString::number( mMinScale );
1871 props[ QStringLiteral( "scaleMaxDenom" ) ] = QString::number( mMaxScale );
1872 }
1873
1874 if ( vlayer )
1875 {
1876 if ( !vlayer->writeSld( layerNode, myDocument, errorMsg, props ) )
1877 {
1878 errorMsg = tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1879 return;
1880 }
1881 }
1882
1883 if ( rlayer )
1884 {
1885 if ( !rlayer->writeSld( layerNode, myDocument, errorMsg, props ) )
1886 {
1887 errorMsg = tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1888 return;
1889 }
1890 }
1891
1892 doc = myDocument;
1893}
1894
1895QString QgsMapLayer::saveSldStyle( const QString &uri, bool &resultFlag ) const
1896{
1897 QgsSldExportContext context;
1898 context.setExportFilePath( uri );
1899 return saveSldStyleV2( resultFlag, context );
1900}
1901
1902QString QgsMapLayer::saveSldStyleV2( bool &resultFlag, const QgsSldExportContext &exportContext ) const
1903{
1905
1906 const QgsMapLayer *mlayer = qobject_cast<const QgsMapLayer *>( this );
1907
1908 const QString uri { exportContext.exportFilePath() };
1909
1910 // check if the uri is a file or ends with .sld,
1911 // which indicates that it should become one
1912 QString filename;
1913 if ( mlayer->providerType() == QLatin1String( "ogr" ) )
1914 {
1915 QStringList theURIParts = uri.split( '|' );
1916 filename = theURIParts[0];
1917 }
1918 else if ( mlayer->providerType() == QLatin1String( "gpx" ) )
1919 {
1920 QStringList theURIParts = uri.split( '?' );
1921 filename = theURIParts[0];
1922 }
1923 else if ( mlayer->providerType() == QLatin1String( "delimitedtext" ) )
1924 {
1925 filename = QUrl::fromEncoded( uri.toLatin1() ).toLocalFile();
1926 // toLocalFile() returns an empty string if theURI is a plain Windows-path, e.g. "C:/style.qml"
1927 if ( filename.isEmpty() )
1928 filename = uri;
1929 }
1930 else
1931 {
1932 filename = uri;
1933 }
1934
1935 const QFileInfo myFileInfo( filename );
1936 if ( myFileInfo.exists() || filename.endsWith( QLatin1String( ".sld" ), Qt::CaseInsensitive ) )
1937 {
1938 const QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
1939 if ( !myDirInfo.isWritable() )
1940 {
1941 return tr( "The directory containing your dataset needs to be writable!" );
1942 }
1943
1944 // now construct the file name for our .sld style file
1945 const QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".sld";
1946
1947 QString errorMsg;
1948 QDomDocument myDocument;
1949
1950 QgsSldExportContext context { exportContext };
1951 context.setExportFilePath( myFileName );
1952
1953 mlayer->exportSldStyleV2( myDocument, errorMsg, context );
1954
1955 if ( !errorMsg.isNull() )
1956 {
1957 resultFlag = false;
1958 return errorMsg;
1959 }
1960
1961 QFile myFile( myFileName );
1962 if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
1963 {
1964 QTextStream myFileStream( &myFile );
1965 // save as utf-8 with 2 spaces for indents
1966 myDocument.save( myFileStream, 2 );
1967 myFile.close();
1968 resultFlag = true;
1969 return tr( "Created default style file as %1" ).arg( myFileName );
1970 }
1971 }
1972
1973 resultFlag = false;
1974 return tr( "ERROR: Failed to created SLD style file as %1. Check file permissions and retry." ).arg( filename );
1975
1976}
1977
1978QString QgsMapLayer::loadSldStyle( const QString &uri, bool &resultFlag )
1979{
1981
1982 resultFlag = false;
1983
1984 QDomDocument myDocument;
1985
1986 // location of problem associated with errorMsg
1987 int line, column;
1988 QString myErrorMessage;
1989
1990 QFile myFile( uri );
1991 if ( myFile.open( QFile::ReadOnly ) )
1992 {
1993 // read file
1994 resultFlag = myDocument.setContent( &myFile, true, &myErrorMessage, &line, &column );
1995 if ( !resultFlag )
1996 myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1997 myFile.close();
1998 }
1999 else
2000 {
2001 myErrorMessage = tr( "Unable to open file %1" ).arg( uri );
2002 }
2003
2004 if ( !resultFlag )
2005 {
2006 return myErrorMessage;
2007 }
2008
2009 // check for root SLD element
2010 const QDomElement myRoot = myDocument.firstChildElement( QStringLiteral( "StyledLayerDescriptor" ) );
2011 if ( myRoot.isNull() )
2012 {
2013 myErrorMessage = QStringLiteral( "Error: StyledLayerDescriptor element not found in %1" ).arg( uri );
2014 resultFlag = false;
2015 return myErrorMessage;
2016 }
2017
2018 // now get the style node out and pass it over to the layer
2019 // to deserialise...
2020 const QDomElement namedLayerElem = myRoot.firstChildElement( QStringLiteral( "NamedLayer" ) );
2021 if ( namedLayerElem.isNull() )
2022 {
2023 myErrorMessage = QStringLiteral( "Info: NamedLayer element not found." );
2024 resultFlag = false;
2025 return myErrorMessage;
2026 }
2027
2028 QString errorMsg;
2029 resultFlag = readSld( namedLayerElem, errorMsg );
2030 if ( !resultFlag )
2031 {
2032 myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( uri, errorMsg );
2033 return myErrorMessage;
2034 }
2035
2036 return QString();
2037}
2038
2039bool QgsMapLayer::readStyle( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
2040{
2042
2043 Q_UNUSED( node )
2044 Q_UNUSED( errorMessage )
2045 Q_UNUSED( context )
2046 Q_UNUSED( categories )
2047 return false;
2048}
2049
2050bool QgsMapLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage,
2051 const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
2052{
2054
2055 Q_UNUSED( node )
2056 Q_UNUSED( doc )
2057 Q_UNUSED( errorMessage )
2058 Q_UNUSED( context )
2059 Q_UNUSED( categories )
2060 return false;
2061}
2062
2063
2064void QgsMapLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider,
2065 bool loadDefaultStyleFlag )
2066{
2068
2070
2071 QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags();
2072 if ( loadDefaultStyleFlag )
2073 {
2075 }
2076
2078 {
2080 }
2081 setDataSource( dataSource, baseName, provider, options, flags );
2082}
2083
2084void QgsMapLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider,
2085 const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag )
2086{
2088
2089 QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags();
2090 if ( loadDefaultStyleFlag )
2091 {
2093 }
2094
2096 {
2098 }
2099 setDataSource( dataSource, baseName, provider, options, flags );
2100}
2101
2102void QgsMapLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider,
2103 const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
2104{
2106
2109 {
2111 }
2112 setDataSourcePrivate( dataSource, baseName, provider, options, flags );
2113 emit dataSourceChanged();
2114 emit dataChanged();
2116}
2117
2118
2119void QgsMapLayer::setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider,
2120 const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
2121{
2123
2124 Q_UNUSED( dataSource )
2125 Q_UNUSED( baseName )
2126 Q_UNUSED( provider )
2127 Q_UNUSED( options )
2128 Q_UNUSED( flags )
2129}
2130
2131
2133{
2135
2136 return mProviderKey;
2137}
2138
2139void QgsMapLayer::readCommonStyle( const QDomElement &layerElement, const QgsReadWriteContext &context,
2140 QgsMapLayer::StyleCategories categories )
2141{
2143
2144 if ( categories.testFlag( Symbology3D ) )
2145 {
2146 const QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "3D Symbology" ) );
2147
2148 QgsAbstract3DRenderer *r3D = nullptr;
2149 QDomElement renderer3DElem = layerElement.firstChildElement( QStringLiteral( "renderer-3d" ) );
2150 if ( !renderer3DElem.isNull() )
2151 {
2152 const QString type3D = renderer3DElem.attribute( QStringLiteral( "type" ) );
2154 if ( meta3D )
2155 {
2156 r3D = meta3D->createRenderer( renderer3DElem, context );
2157 }
2158 }
2159 setRenderer3D( r3D );
2160 }
2161
2162 if ( categories.testFlag( CustomProperties ) )
2163 {
2164 // read custom properties before passing reading further to a subclass, so that
2165 // the subclass can also read custom properties
2166 readCustomProperties( layerElement );
2167 }
2168
2169 // use scale dependent visibility flag
2170 if ( categories.testFlag( Rendering ) )
2171 {
2172 setScaleBasedVisibility( layerElement.attribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ) ).toInt() == 1 );
2173 if ( layerElement.hasAttribute( QStringLiteral( "minimumScale" ) ) )
2174 {
2175 // older element, when scales were reversed
2176 setMaximumScale( layerElement.attribute( QStringLiteral( "minimumScale" ) ).toDouble() );
2177 setMinimumScale( layerElement.attribute( QStringLiteral( "maximumScale" ) ).toDouble() );
2178 }
2179 else
2180 {
2181 setMaximumScale( layerElement.attribute( QStringLiteral( "maxScale" ) ).toDouble() );
2182 setMinimumScale( layerElement.attribute( QStringLiteral( "minScale" ) ).toDouble() );
2183 }
2184 }
2185
2186 if ( categories.testFlag( LayerConfiguration ) )
2187 {
2188 // flags
2189 const QDomElement flagsElem = layerElement.firstChildElement( QStringLiteral( "flags" ) );
2190 LayerFlags flags = mFlags;
2191 const auto enumMap = qgsEnumMap<QgsMapLayer::LayerFlag>();
2192 for ( auto it = enumMap.constBegin(); it != enumMap.constEnd(); ++it )
2193 {
2194 const QDomNode flagNode = flagsElem.namedItem( it.value() );
2195 if ( flagNode.isNull() )
2196 continue;
2197 const bool flagValue = flagNode.toElement().text() == "1" ? true : false;
2198 if ( flags.testFlag( it.key() ) && !flagValue )
2199 flags &= ~it.key();
2200 else if ( !flags.testFlag( it.key() ) && flagValue )
2201 flags |= it.key();
2202 }
2203 setFlags( flags );
2204 }
2205
2206 if ( categories.testFlag( Temporal ) )
2207 {
2208 const QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Temporal" ) );
2209
2211 properties->readXml( layerElement.toElement(), context );
2212 }
2213
2214 if ( categories.testFlag( Elevation ) )
2215 {
2216 const QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Elevation" ) );
2217
2219 properties->readXml( layerElement.toElement(), context );
2220 }
2221
2222 if ( categories.testFlag( Notes ) )
2223 {
2224 const QDomElement notesElem = layerElement.firstChildElement( QStringLiteral( "userNotes" ) );
2225 if ( !notesElem.isNull() )
2226 {
2227 const QString notes = notesElem.attribute( QStringLiteral( "value" ) );
2228 QgsLayerNotesUtils::setLayerNotes( this, notes );
2229 }
2230 }
2231}
2232
2234{
2236
2237 return mUndoStack;
2238}
2239
2241{
2243
2244 return mUndoStackStyles;
2245}
2246
2248{
2250
2251 return mCustomProperties.keys();
2252}
2253
2254void QgsMapLayer::setCustomProperty( const QString &key, const QVariant &value )
2255{
2257
2258 if ( !mCustomProperties.contains( key ) || mCustomProperties.value( key ) != value )
2259 {
2260 mCustomProperties.setValue( key, value );
2261 emit customPropertyChanged( key );
2262 }
2263}
2264
2266{
2268
2269 mCustomProperties = properties;
2270 for ( const QString &key : mCustomProperties.keys() )
2271 {
2272 emit customPropertyChanged( key );
2273 }
2274}
2275
2277{
2279
2280 return mCustomProperties;
2281}
2282
2283QVariant QgsMapLayer::customProperty( const QString &value, const QVariant &defaultValue ) const
2284{
2285 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
2287
2288 return mCustomProperties.value( value, defaultValue );
2289}
2290
2291void QgsMapLayer::removeCustomProperty( const QString &key )
2292{
2294
2295 if ( mCustomProperties.contains( key ) )
2296 {
2297 mCustomProperties.remove( key );
2298 emit customPropertyChanged( key );
2299 }
2300}
2301
2303{
2305
2306 return mError;
2307}
2308
2310{
2312
2313 return false;
2314}
2315
2317{
2319
2320 return false;
2321}
2322
2324{
2326
2327 return true;
2328}
2329
2331{
2333
2334 // invalid layers are temporary? -- who knows?!
2335 if ( !isValid() )
2336 return false;
2337
2338 if ( mProviderKey == QLatin1String( "memory" ) )
2339 return true;
2340
2341 const QVariantMap sourceParts = QgsProviderRegistry::instance()->decodeUri( mProviderKey, mDataSource );
2342 const QString path = sourceParts.value( QStringLiteral( "path" ) ).toString();
2343 if ( path.isEmpty() )
2344 return false;
2345
2346 // check if layer path is inside one of the standard temporary file locations for this platform
2347 const QStringList tempPaths = QStandardPaths::standardLocations( QStandardPaths::TempLocation );
2348 for ( const QString &tempPath : tempPaths )
2349 {
2350 if ( path.startsWith( tempPath ) )
2351 return true;
2352 }
2353
2354 return false;
2355}
2356
2357void QgsMapLayer::setValid( bool valid )
2358{
2360
2361 if ( mValid == valid )
2362 return;
2363
2364 mValid = valid;
2365 emit isValidChanged();
2366}
2367
2369{
2371
2372 if ( legend == mLegend )
2373 return;
2374
2375 delete mLegend;
2376 mLegend = legend;
2377
2378 if ( mLegend )
2379 {
2380 mLegend->setParent( this );
2381 connect( mLegend, &QgsMapLayerLegend::itemsChanged, this, &QgsMapLayer::legendChanged, Qt::UniqueConnection );
2382 }
2383
2384 emit legendChanged();
2385}
2386
2388{
2390
2391 return mLegend;
2392}
2393
2395{
2397
2398 return mStyleManager;
2399}
2400
2402{
2404
2405 if ( renderer == m3DRenderer )
2406 return;
2407
2408 delete m3DRenderer;
2409 m3DRenderer = renderer;
2410 emit renderer3DChanged();
2411 emit repaintRequested();
2413}
2414
2416{
2418
2419 return m3DRenderer;
2420}
2421
2422void QgsMapLayer::triggerRepaint( bool deferredUpdate )
2423{
2425
2426 if ( mRepaintRequestedFired )
2427 return;
2428 mRepaintRequestedFired = true;
2429 emit repaintRequested( deferredUpdate );
2430 mRepaintRequestedFired = false;
2431}
2432
2434{
2436
2437 emit request3DUpdate();
2438}
2439
2441{
2443
2444 mMetadata = metadata;
2445// mMetadata.saveToLayer( this );
2446 emit metadataChanged();
2447}
2448
2450{
2452
2453 return QString();
2454}
2455
2456QDateTime QgsMapLayer::timestamp() const
2457{
2459
2460 return QDateTime();
2461}
2462
2464{
2466
2468 emit styleChanged();
2469}
2470
2472{
2474
2475 updateExtent( extent );
2476}
2477
2478bool QgsMapLayer::isReadOnly() const
2479{
2481
2482 return true;
2483}
2484
2486{
2488
2489 return mOriginalXmlProperties;
2490}
2491
2492void QgsMapLayer::setOriginalXmlProperties( const QString &originalXmlProperties )
2493{
2495
2496 mOriginalXmlProperties = originalXmlProperties;
2497}
2498
2499QString QgsMapLayer::generateId( const QString &layerName )
2500{
2501 // Generate the unique ID of this layer
2502 const QString uuid = QUuid::createUuid().toString();
2503 // trim { } from uuid
2504 QString id = layerName + '_' + uuid.mid( 1, uuid.length() - 2 );
2505 // Tidy the ID up to avoid characters that may cause problems
2506 // elsewhere (e.g in some parts of XML). Replaces every non-word
2507 // character (word characters are the alphabet, numbers and
2508 // underscore) with an underscore.
2509 // Note that the first backslash in the regular expression is
2510 // there for the compiler, so the pattern is actually \W
2511 const thread_local QRegularExpression idRx( QStringLiteral( "[\\W]" ) );
2512 id.replace( idRx, QStringLiteral( "_" ) );
2513 return id;
2514}
2515
2517{
2519
2520 return true;
2521}
2522
2524{
2526
2527 return mapTipsEnabled() && !mMapTipTemplate.isEmpty();
2528}
2529
2530void QgsMapLayer::setProviderType( const QString &providerType )
2531{
2533
2535}
2536
2537QSet<QgsMapLayerDependency> QgsMapLayer::dependencies() const
2538{
2540
2541 return mDependencies;
2542}
2543
2544bool QgsMapLayer::setDependencies( const QSet<QgsMapLayerDependency> &oDeps )
2545{
2547
2548 QSet<QgsMapLayerDependency> deps;
2549 const auto constODeps = oDeps;
2550 for ( const QgsMapLayerDependency &dep : constODeps )
2551 {
2552 if ( dep.origin() == QgsMapLayerDependency::FromUser )
2553 deps << dep;
2554 }
2555
2556 mDependencies = deps;
2557 emit dependenciesChanged();
2558 return true;
2559}
2560
2562{
2564
2565 QgsDataProvider *lDataProvider = dataProvider();
2566
2567 if ( !lDataProvider )
2568 return;
2569
2570 if ( enabled && !isRefreshOnNotifyEnabled() )
2571 {
2572 lDataProvider->setListening( enabled );
2573 connect( lDataProvider, &QgsDataProvider::notify, this, &QgsMapLayer::onNotified );
2574 }
2575 else if ( !enabled && isRefreshOnNotifyEnabled() )
2576 {
2577 // we don't want to disable provider listening because someone else could need it (e.g. actions)
2578 disconnect( lDataProvider, &QgsDataProvider::notify, this, &QgsMapLayer::onNotified );
2579 }
2580 mIsRefreshOnNofifyEnabled = enabled;
2581}
2582
2584{
2586
2587 if ( QgsMapLayerStore *store = qobject_cast<QgsMapLayerStore *>( parent() ) )
2588 {
2589 return qobject_cast<QgsProject *>( store->parent() );
2590 }
2591 return nullptr;
2592}
2593
2594void QgsMapLayer::onNotified( const QString &message )
2595{
2597
2598 if ( refreshOnNotifyMessage().isEmpty() || refreshOnNotifyMessage() == message )
2599 {
2601 emit dataChanged();
2602 }
2603}
2604
2605QgsRectangle QgsMapLayer::wgs84Extent( bool forceRecalculate ) const
2606{
2608
2610
2611 if ( ! forceRecalculate && ! mWgs84Extent.isNull() )
2612 {
2613 wgs84Extent = mWgs84Extent;
2614 }
2615 else if ( ! mExtent.isNull() )
2616 {
2618 transformer.setBallparkTransformsAreAppropriate( true );
2619 try
2620 {
2621 wgs84Extent = transformer.transformBoundingBox( mExtent );
2622 }
2623 catch ( const QgsCsException &cse )
2624 {
2625 QgsMessageLog::logMessage( tr( "Error transforming extent: %1" ).arg( cse.what() ) );
2627 }
2628 }
2629 return wgs84Extent;
2630}
2631
2632void QgsMapLayer::updateExtent( const QgsRectangle &extent ) const
2633{
2635
2636 if ( extent == mExtent )
2637 return;
2638
2639 mExtent = extent;
2640
2641 // do not update the wgs84 extent if we trust layer metadata
2642 if ( mReadFlags & QgsMapLayer::ReadFlag::FlagTrustLayerMetadata )
2643 return;
2644
2645 mWgs84Extent = wgs84Extent( true );
2646}
2647
2649{
2651
2652 // do not update the wgs84 extent if we trust layer metadata
2653 if ( mReadFlags & QgsMapLayer::ReadFlag::FlagTrustLayerMetadata )
2654 return;
2655
2656 mWgs84Extent = QgsRectangle();
2657}
2658
2660{
2662
2663 QString metadata = QStringLiteral( "<h1>" ) + tr( "General" ) + QStringLiteral( "</h1>\n<hr>\n" ) + QStringLiteral( "<table class=\"list-view\">\n" );
2664
2665 // name
2666 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Name" ) + QStringLiteral( "</td><td>" ) + name() + QStringLiteral( "</td></tr>\n" );
2667
2668 QString path;
2669 bool isLocalPath = false;
2670 if ( dataProvider() )
2671 {
2672 // local path
2673 QVariantMap uriComponents = QgsProviderRegistry::instance()->decodeUri( dataProvider()->name(), publicSource() );
2674 if ( uriComponents.contains( QStringLiteral( "path" ) ) )
2675 {
2676 path = uriComponents[QStringLiteral( "path" )].toString();
2677 QFileInfo fi( path );
2678 if ( fi.exists() )
2679 {
2680 isLocalPath = true;
2681 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" );
2682
2683 QDateTime lastModified = fi.lastModified();
2684 QString lastModifiedFileName;
2685 QSet<QString> sidecarFiles = QgsFileUtils::sidecarFilesForPath( path );
2686 if ( fi.isFile() )
2687 {
2688 qint64 fileSize = fi.size();
2689 if ( !sidecarFiles.isEmpty() )
2690 {
2691 lastModifiedFileName = fi.fileName();
2692 QStringList sidecarFileNames;
2693 for ( const QString &sidecarFile : sidecarFiles )
2694 {
2695 QFileInfo sidecarFi( sidecarFile );
2696 fileSize += sidecarFi.size();
2697 if ( sidecarFi.lastModified() > lastModified )
2698 {
2699 lastModified = sidecarFi.lastModified();
2700 lastModifiedFileName = sidecarFi.fileName();
2701 }
2702 sidecarFileNames << sidecarFi.fileName();
2703 }
2704 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" );
2705 }
2706 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" );
2707 }
2708 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" );
2709 }
2710 }
2711 if ( uriComponents.contains( QStringLiteral( "url" ) ) )
2712 {
2713 const QString url = uriComponents[QStringLiteral( "url" )].toString();
2714 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" );
2715 }
2716 }
2717
2718 // data source
2719 if ( publicSource() != path || !isLocalPath )
2720 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Source" ) + QStringLiteral( "</td><td>%1" ).arg( publicSource() != path ? publicSource() : path ) + QStringLiteral( "</td></tr>\n" );
2721
2722 // provider
2723 if ( dataProvider() )
2724 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Provider" ) + QStringLiteral( "</td><td>%1" ).arg( dataProvider()->name() ) + QStringLiteral( "</td></tr>\n" );
2725
2726 metadata += QLatin1String( "</table>\n<br><br>" );
2727 return metadata;
2728}
2729
2731{
2733
2734 QString metadata = QStringLiteral( "<h1>" ) + tr( "Coordinate Reference System (CRS)" ) + QStringLiteral( "</h1>\n<hr>\n" );
2735 metadata += QLatin1String( "<table class=\"list-view\">\n" );
2736
2737 // Identifier
2739 if ( !c.isValid() )
2740 metadata += QStringLiteral( "<tr><td colspan=\"2\" class=\"highlight\">" ) + tr( "Unknown" ) + QStringLiteral( "</td></tr>\n" );
2741 else
2742 {
2743 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Name" ) + QStringLiteral( "</td><td>" ) + c.userFriendlyIdentifier( QgsCoordinateReferenceSystem::FullString ) + QStringLiteral( "</td></tr>\n" );
2744
2745 // map units
2746 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Units" ) + QStringLiteral( "</td><td>" )
2747 + ( c.isGeographic() ? tr( "Geographic (uses latitude and longitude for coordinates)" ) : QgsUnitTypes::toString( c.mapUnits() ) )
2748 + QStringLiteral( "</td></tr>\n" );
2749
2750
2751 // operation
2752 const QgsProjOperation operation = c.operation();
2753 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Method" ) + QStringLiteral( "</td><td>" ) + operation.description() + QStringLiteral( "</td></tr>\n" );
2754
2755 // celestial body
2756 try
2757 {
2758 const QString celestialBody = c.celestialBodyName();
2759 if ( !celestialBody.isEmpty() )
2760 {
2761 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Celestial body" ) + QStringLiteral( "</td><td>" ) + celestialBody + QStringLiteral( "</td></tr>\n" );
2762 }
2763 }
2764 catch ( QgsNotSupportedException & )
2765 {
2766
2767 }
2768
2769 QString accuracyString;
2770 // dynamic crs with no epoch?
2771 if ( c.isDynamic() && std::isnan( c.coordinateEpoch() ) )
2772 {
2773 accuracyString = tr( "Based on a dynamic CRS, but no coordinate epoch is set. Coordinates are ambiguous and of limited accuracy." );
2774 }
2775
2776 // based on datum ensemble?
2777 try
2778 {
2779 const QgsDatumEnsemble ensemble = c.datumEnsemble();
2780 if ( ensemble.isValid() )
2781 {
2782 QString id;
2783 if ( !ensemble.code().isEmpty() )
2784 id = QStringLiteral( "<i>%1</i> (%2:%3)" ).arg( ensemble.name(), ensemble.authority(), ensemble.code() );
2785 else
2786 id = QStringLiteral( "<i>%</i>”" ).arg( ensemble.name() );
2787
2788 if ( ensemble.accuracy() > 0 )
2789 {
2790 accuracyString = tr( "Based on %1, which has a limited accuracy of <b>at best %2 meters</b>." ).arg( id ).arg( ensemble.accuracy() );
2791 }
2792 else
2793 {
2794 accuracyString = tr( "Based on %1, which has a limited accuracy." ).arg( id );
2795 }
2796 }
2797 }
2798 catch ( QgsNotSupportedException & )
2799 {
2800
2801 }
2802
2803 if ( !accuracyString.isEmpty() )
2804 {
2805 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Accuracy" ) + QStringLiteral( "</td><td>" ) + accuracyString + QStringLiteral( "</td></tr>\n" );
2806 }
2807
2808 // static/dynamic
2809 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)" ) );
2810
2811 // coordinate epoch
2812 if ( !std::isnan( c.coordinateEpoch() ) )
2813 {
2814 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Coordinate epoch" ) + QStringLiteral( "</td><td>%1</td></tr>\n" ).arg( c.coordinateEpoch() );
2815 }
2816 }
2817
2818 metadata += QLatin1String( "</table>\n<br><br>\n" );
2819 return metadata;
2820}
static QString version()
Version string.
Definition: qgis.cpp:258
static const double SCALE_PRECISION
Fudge factor used to compare two scales.
Definition: qgis.h:3728
@ ForceFirstLetterToCapital
Convert just the first letter of each word to uppercase, leave the rest untouched.
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
Definition: qgis.h:227
LayerType
Types of layers that can be added to a map.
Definition: qgis.h:114
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.
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:67
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...
@ ForceReadOnly
Open layer in a read-only mode (since QGIS 3.28)
@ SkipGetExtent
Skip the extent from provider.
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:49
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:2042
void setShortName(const QString &shortName)
Sets the short name of the layer used by QGIS Server to identify the layer.
Definition: qgsmaplayer.h:289
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:1321
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.
virtual bool hasMapTips() const
Returns true if the layer contains map tips.
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:318
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:1306
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:2057
int mBlockStyleChangedSignal
If non-zero, the styleChanged signal should not be emitted.
Definition: qgsmaplayer.h:2099
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.
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...
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.
QgsMapLayerServerProperties * serverProperties()
Returns QGIS Server Properties for the map layer.
Definition: qgsmaplayer.h:421
QString attribution() const
Returns the attribution of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:396
void setOriginalXmlProperties(const QString &originalXmlProperties)
Sets the original XML properties for the layer to originalXmlProperties.
void writeCustomProperties(QDomNode &layerNode, QDomDocument &doc) const
Write custom properties to project file.
QString mRefreshOnNofifyMessage
Definition: qgsmaplayer.h:2070
QString mLegendUrl
WMS legend.
Definition: qgsmaplayer.h:2053
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:2035
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 mapTipTemplateChanged()
Emitted when the map tip template changes.
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:404
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 abstract() const
Returns the abstract of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:326
QgsMapLayer(Qgis::LayerType type=Qgis::LayerType::Vector, const QString &name=QString(), const QString &source=QString())
Constructor for QgsMapLayer.
Definition: qgsmaplayer.cpp:82
QString originalXmlProperties() const
Returns the XML properties of the original layer as they were when the layer was first read from the ...
Qgis::LayerType type
Definition: qgsmaplayer.h:80
QString dataUrlFormat() const
Returns the DataUrl format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:377
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
QString mTitle
Definition: qgsmaplayer.h:2038
void setDataUrl(const QString &dataUrl)
Sets the DataUrl of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:351
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:333
void setAttribution(const QString &attrib)
Sets the attribution of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:387
void setFlags(QgsMapLayer::LayerFlags flags)
Returns the flags for this layer.
bool isRefreshOnNotifyEnabled() const
Returns true if the refresh on provider nofification is enabled.
Definition: qgsmaplayer.h:1483
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:2060
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:2054
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:2073
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.
std::unique_ptr< QgsDataProvider > mPreloadedProvider
Optionally used when loading a project, it is released when the layer is effectively created.
Definition: qgsmaplayer.h:2136
QString title() const
Returns the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:311
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:2050
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:360
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 ...
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:1681
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.
virtual QgsMapLayerTemporalProperties * temporalProperties()
Returns the layer's temporal properties.
Definition: qgsmaplayer.h:1526
QString mShortName
Definition: qgsmaplayer.h:2037
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:69
virtual QgsMapLayer * clone() const =0
Returns a new instance equivalent to this one except for the id which is still unique.
void blendModeChanged(QPainter::CompositionMode blendMode)
Signal emitted when the blend mode is changed, through QgsMapLayer::setBlendMode()
virtual QString saveSldStyleV2(bool &resultFlag, const QgsSldExportContext &exportContext) const
Saves the properties of this layer to an SLD format file.
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:2032
QString refreshOnNotifyMessage() const
Returns the message that should be notified by the provider to triggerRepaint.
Definition: qgsmaplayer.h:1476
virtual bool readSld(const QDomNode &node, QString &errorMessage)
Definition: qgsmaplayer.h:1184
void setMapTipsEnabled(bool enabled)
Enable or disable map tips for this layer.
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:636
@ FlagTrustLayerMetadata
Trust layer metadata. Improves layer load time by skipping expensive checks like primary key unicity,...
Definition: qgsmaplayer.h:635
@ FlagForceReadOnly
Force open as read only.
Definition: qgsmaplayer.h:637
void setValid(bool valid)
Sets whether layer is valid or not.
QString attributionUrl() const
Returns the attribution URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:413
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:2041
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:2078
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:1311
QString mDataUrlFormat
Definition: qgsmaplayer.h:2046
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:1316
void exportNamedMetadata(QDomDocument &doc, QString &errorMsg) const
Export the current metadata of this layer as named metadata in a QDomDocument.
virtual QString saveNamedStyle(const QString &uri, bool &resultFlag, StyleCategories categories=AllStyleCategories)
Save the properties of this layer as a named style (either as a .qml file on disk or as a record in t...
virtual void exportSldStyle(QDomDocument &doc, QString &errorMsg) const
Export the properties of this layer as SLD style in a QDomDocument.
void beforeResolveReferences(QgsProject *project)
Emitted when all layers are loaded and references can be resolved, just before the references of this...
void setMapTipTemplate(const QString &mapTipTemplate)
The mapTip is a pretty, html representation for feature information.
Q_DECL_DEPRECATED void setMetadataUrl(const QString &metaUrl)
Sets the metadata URL of the layer used by QGIS Server in GetCapabilities request.
virtual QgsMapLayerElevationProperties * elevationProperties()
Returns the layer's elevation properties.
Definition: qgsmaplayer.h:1533
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...
bool mapTipsEnabled
Definition: qgsmaplayer.h:84
bool readLayerXml(const QDomElement &layerElement, QgsReadWriteContext &context, QgsMapLayer::ReadFlags flags=QgsMapLayer::ReadFlags(), QgsDataProvider *preloadedProvider=nullptr)
Sets state from DOM document.
void setLegend(QgsMapLayerLegend *legend)
Assign a legend controller to the map layer.
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:2069
QString mDataUrl
DataUrl of the layer.
Definition: qgsmaplayer.h:2045
virtual Q_INVOKABLE QgsDataProvider * dataProvider()
Returns the layer's data provider, it may be nullptr.
double mLayerOpacity
Layer opacity.
Definition: qgsmaplayer.h:2092
bool mValid
Indicates if the layer is valid and can be drawn.
Definition: qgsmaplayer.h:2029
@ AllStyleCategories
Definition: qgsmaplayer.h:180
@ LayerConfiguration
General configuration: identifiable, removable, searchable, display expression, read-only.
Definition: qgsmaplayer.h:162
@ Symbology
Symbology.
Definition: qgsmaplayer.h:163
@ Notes
Layer user notes (since QGIS 3.20)
Definition: qgsmaplayer.h:179
@ Temporal
Temporal properties (since QGIS 3.14)
Definition: qgsmaplayer.h:176
@ Rendering
Rendering: scale visibility, simplify method, opacity.
Definition: qgsmaplayer.h:172
@ Elevation
Elevation settings (since QGIS 3.18)
Definition: qgsmaplayer.h:178
@ Symbology3D
3D symbology
Definition: qgsmaplayer.h:164
@ CustomProperties
Custom properties (by plugins for instance)
Definition: qgsmaplayer.h:173
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)
void mapTipsEnabledChanged()
Emitted when map tips are enabled or disabled for the layer.
virtual QString saveDefaultStyle(bool &resultFlag, StyleCategories categories)
Save the properties of this layer as the default style (either as a .qml file on disk or as a record ...
void setRenderer3D(QgsAbstract3DRenderer *renderer)
Sets 3D renderer for the layer.
QString mAttribution
Attribution of the layer.
Definition: qgsmaplayer.h:2049
~QgsMapLayer() override
const QgsObjectCustomProperties & customProperties() const
Read all custom properties from layer.
virtual void exportSldStyleV2(QDomDocument &doc, QString &errorMsg, const QgsSldExportContext &exportContext) const
Export the properties of this layer as SLD style in a QDomDocument.
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:341
virtual void setLayerOrder(const QStringList &layers)
Reorders the previously selected sublayers of this layer from bottom to top.
void invalidateWgs84Extent()
Invalidates the WGS84 extent.
QString mapTipTemplate
Definition: qgsmaplayer.h:83
void setTitle(const QString &title)
Sets the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:303
PropertyType
Maplayer has a style and a metadata property.
Definition: qgsmaplayer.h:135
bool mShouldValidateCrs
true if the layer's CRS should be validated and invalid CRSes are not permitted.
Definition: qgsmaplayer.h:2085
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
static QgsDataProvider::ReadFlags providerReadFlags(const QDomNode &layerNode, QgsMapLayer::ReadFlags layerReadFlags)
Returns provider read flag deduced from layer read flags layerReadFlags and a dom node layerNode that...
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:119
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:107
bool removeAttachedFile(const QString &path)
Removes the attached file.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:484
QString baseName() const
Returns the base name of the project file without the path and without extension - derived from fileN...
Definition: qgsproject.cpp:900
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:886
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.
The QgsSldExportContext class holds SLD export options and other information related to SLD export of...
QString exportFilePath() const
Returns the export file path for the SLD.
void setExportFilePath(const QString &exportFilePath)
Sets the export file path for the SLD to exportFilePath.
static QString capitalize(const QString &string, Qgis::Capitalization capitalization)
Converts a string by applying capitalization rules to the string.
An interface for classes which can visit style entity (e.g.
static Q_INVOKABLE QString toString(Qgis::DistanceUnit unit)
Returns a translated string representing a distance unit.
Represents a vector layer which manages a vector based data sets.
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.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
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 ...
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:3988
CONSTLATIN1STRING geoEpsgCrsAuthId()
Geographic coord sys from EPSG authority.
Definition: qgis.h:4484
void(* CUSTOM_CRS_VALIDATION)(QgsCoordinateReferenceSystem &)
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QGIS_PROTECT_QOBJECT_THREAD_ACCESS_NON_FATAL
#define QGIS_PROTECT_QOBJECT_THREAD_ACCESS
Setting options for creating vector data providers.
QString format
Format specification of online resource.