QGIS API Documentation 3.43.0-Master (3ee7834ace6)
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"
25#include "qgsdatasourceuri.h"
26#include "qgsfileutils.h"
27#include "qgslogger.h"
28#include "qgsauthmanager.h"
29#include "qgsmaplayer.h"
30#include "moc_qgsmaplayer.cpp"
31#include "qgsmaplayerlegend.h"
33#include "qgspathresolver.h"
35#include "qgsproject.h"
36#include "qgsproviderregistry.h"
37#include "qgsprovidermetadata.h"
38#include "qgsrasterlayer.h"
39#include "qgsreadwritecontext.h"
40#include "qgsrectangle.h"
41#include "qgsscaleutils.h"
42#include "qgssldexportcontext.h"
43#include "qgsvectorlayer.h"
44#include "qgsxmlutils.h"
45#include "qgsstringutils.h"
46#include "qgsmessagelog.h"
49#include "qgslayernotesutils.h"
50#include "qgsdatums.h"
51#include "qgsprojoperation.h"
52#include "qgsthreadingutils.h"
53#include "qgsunittypes.h"
54
55#include <QDir>
56#include <QDomDocument>
57#include <QDomElement>
58#include <QDomImplementation>
59#include <QDomNode>
60#include <QFile>
61#include <QFileInfo>
62#include <QLocale>
63#include <QTextStream>
64#include <QUrl>
65#include <QTimer>
66#include <QStandardPaths>
67#include <QUuid>
68#include <QRegularExpression>
69
70#include <sqlite3.h>
71
73{
74 switch ( type )
75 {
76 case Metadata:
77 return QStringLiteral( ".qmd" );
78
79 case Style:
80 return QStringLiteral( ".qml" );
81 }
82 return QString();
83}
84
86 const QString &lyrname,
87 const QString &source )
88 : mDataSource( source )
89 , mLayerName( lyrname )
90 , mLayerType( type )
91 , mServerProperties( std::make_unique<QgsMapLayerServerProperties>( this ) )
92 , mUndoStack( new QUndoStack( this ) )
93 , mUndoStackStyles( new QUndoStack( this ) )
94 , mStyleManager( new QgsMapLayerStyleManager( this ) )
95 , mRefreshTimer( new QTimer( this ) )
96{
97 mID = generateId( lyrname );
100 connect( mRefreshTimer, &QTimer::timeout, this, [this]
101 {
102
103 switch ( mAutoRefreshMode )
104 {
106 break;
108 triggerRepaint( true );
109 break;
111 reload();
112 break;
113 }
114 } );
115}
116
118{
119 if ( project() && project()->pathResolver().writePath( mDataSource ).startsWith( "attachment:" ) )
120 {
122 }
123
124 delete m3DRenderer;
125 delete mLegend;
126 delete mStyleManager;
127}
128
129void QgsMapLayer::clone( QgsMapLayer *layer ) const
130{
132
133 QgsDebugMsgLevel( QStringLiteral( "Cloning layer '%1'" ).arg( name() ), 3 );
134 layer->setBlendMode( blendMode() );
135
136 const auto constStyles = styleManager()->styles();
137 for ( const QString &s : constStyles )
138 {
139 layer->styleManager()->addStyle( s, styleManager()->style( s ) );
140 }
141
142 layer->setName( name() );
143
144 if ( layer->dataProvider() && layer->dataProvider()->elevationProperties() )
145 {
147 layer->mExtent3D = mExtent3D;
148 else
149 layer->mExtent2D = mExtent2D;
150 }
151
152 layer->setMaximumScale( maximumScale() );
153 layer->setMinimumScale( minimumScale() );
155 layer->setDependencies( dependencies() );
157 layer->setCrs( crs() );
158 layer->setCustomProperties( mCustomProperties );
159 layer->setOpacity( mLayerOpacity );
160 layer->setMetadata( mMetadata );
161 layer->serverProperties()->copyTo( mServerProperties.get() );
162}
163
165{
166 // because QgsVirtualLayerProvider is not anywhere NEAR thread safe:
168
169 return mLayerType;
170}
171
178
180{
182
183 if ( flags == mFlags )
184 return;
185
186 mFlags = flags;
187 emit flagsChanged();
188}
189
196
197QString QgsMapLayer::id() const
198{
199 // because QgsVirtualLayerProvider is not anywhere NEAR thread safe:
201
202 return mID;
203}
204
205bool QgsMapLayer::setId( const QString &id )
206{
208 if ( qobject_cast< QgsMapLayerStore * >( parent() ) )
209 {
210 // layer is already registered, cannot change id
211 return false;
212 }
213
214 if ( id == mID )
215 return false;
216
217 mID = id;
218 emit idChanged( id );
219 return true;
220}
221
222void QgsMapLayer::setName( const QString &name )
223{
225
226 if ( name == mLayerName )
227 return;
228
230
231 emit nameChanged();
232}
233
234QString QgsMapLayer::name() const
235{
236 // because QgsVirtualLayerProvider is not anywhere NEAR thread safe:
238
239 QgsDebugMsgLevel( "returning name '" + mLayerName + '\'', 4 );
240 return mLayerName;
241}
242
249
251{
253
254 return nullptr;
255}
256
261
262void QgsMapLayer::setShortName( const QString &shortName )
263{
265
266 mServerProperties->setShortName( shortName );
267}
268
270{
272
273 return mServerProperties->shortName();
274}
275
276void QgsMapLayer::setTitle( const QString &title )
277{
279
280 mServerProperties->setTitle( title );
281}
282
283QString QgsMapLayer::title() const
284{
286
287 return mServerProperties->title();
288}
289
290void QgsMapLayer::setAbstract( const QString &abstract )
291{
293
294 mServerProperties->setAbstract( abstract );
295}
296
298{
300
301 return mServerProperties->abstract();
302}
303
304void QgsMapLayer::setKeywordList( const QString &keywords )
305{
307
308 mServerProperties->setKeywordList( keywords );
309}
310
312{
314
315 return mServerProperties->keywordList();
316}
317
318void QgsMapLayer::setDataUrl( const QString &dataUrl )
319{
321
322 mServerProperties->setDataUrl( dataUrl );
323}
324
325QString QgsMapLayer::dataUrl() const
326{
328
329 return mServerProperties->dataUrl();
330}
331
332void QgsMapLayer::setDataUrlFormat( const QString &dataUrlFormat )
333{
335
336 mServerProperties->setDataUrlFormat( dataUrlFormat );
337}
338
340{
342
343 return mServerProperties->dataUrlFormat();
344}
345
346void QgsMapLayer::setAttribution( const QString &attrib )
347{
349
350 mServerProperties->setAttribution( attrib );
351}
352
354{
356
357 return mServerProperties->attribution();
358}
359
360void QgsMapLayer::setAttributionUrl( const QString &attribUrl )
361{
363
364 mServerProperties->setAttributionUrl( attribUrl );
365}
366
368{
370
371 return mServerProperties->attributionUrl();
372}
373
374void QgsMapLayer::setLegendUrl( const QString &legendUrl )
375{
377
378 mServerProperties->setLegendUrl( legendUrl );
379}
380
382{
384
385 return mServerProperties->legendUrl();
386}
387
388void QgsMapLayer::setLegendUrlFormat( const QString &legendUrlFormat )
389{
391
392 mServerProperties->setLegendUrlFormat( legendUrlFormat );
393}
394
396{
398
399 return mServerProperties->legendUrlFormat();
400}
401
402void QgsMapLayer::setMetadataUrl( const QString &metaUrl )
403{
405
406 QList<QgsMapLayerServerProperties::MetadataUrl> urls = serverProperties()->metadataUrls();
407 if ( urls.isEmpty() )
408 {
409 const QgsMapLayerServerProperties::MetadataUrl newItem = QgsMapLayerServerProperties::MetadataUrl( metaUrl, QLatin1String(), QLatin1String() );
410 urls.prepend( newItem );
411 }
412 else
413 {
414 const QgsMapLayerServerProperties::MetadataUrl old = urls.takeFirst();
415 const QgsMapLayerServerProperties::MetadataUrl newItem( metaUrl, old.type, old.format );
416 urls.prepend( newItem );
417 }
419}
420
422{
424
425 if ( mServerProperties->metadataUrls().isEmpty() )
426 {
427 return QLatin1String();
428 }
429 else
430 {
431 return mServerProperties->metadataUrls().first().url;
432 }
433}
434
435void QgsMapLayer::setMetadataUrlType( const QString &metaUrlType )
436{
438
439 QList<QgsMapLayerServerProperties::MetadataUrl> urls = mServerProperties->metadataUrls();
440 if ( urls.isEmpty() )
441 {
442 const QgsMapLayerServerProperties::MetadataUrl newItem( QLatin1String(), metaUrlType, QLatin1String() );
443 urls.prepend( newItem );
444 }
445 else
446 {
447 const QgsMapLayerServerProperties::MetadataUrl old = urls.takeFirst();
448 const QgsMapLayerServerProperties::MetadataUrl newItem( old.url, metaUrlType, old.format );
449 urls.prepend( newItem );
450 }
451 mServerProperties->setMetadataUrls( urls );
452}
453
455{
457
458 if ( mServerProperties->metadataUrls().isEmpty() )
459 {
460 return QLatin1String();
461 }
462 else
463 {
464 return mServerProperties->metadataUrls().first().type;
465 }
466}
467
468void QgsMapLayer::setMetadataUrlFormat( const QString &metaUrlFormat )
469{
471
472 QList<QgsMapLayerServerProperties::MetadataUrl> urls = mServerProperties->metadataUrls();
473 if ( urls.isEmpty() )
474 {
475 const QgsMapLayerServerProperties::MetadataUrl newItem( QLatin1String(), QLatin1String(), metaUrlFormat );
476 urls.prepend( newItem );
477 }
478 else
479 {
480 const QgsMapLayerServerProperties::MetadataUrl old = urls.takeFirst( );
481 const QgsMapLayerServerProperties::MetadataUrl newItem( old.url, old.type, metaUrlFormat );
482 urls.prepend( newItem );
483 }
484 mServerProperties->setMetadataUrls( urls );
485}
486
488{
490
491 if ( mServerProperties->metadataUrls().isEmpty() )
492 {
493 return QString();
494 }
495 else
496 {
497 return mServerProperties->metadataUrls().first().format;
498 }
499}
500
501QString QgsMapLayer::publicSource( bool redactCredentials ) const
502{
504
505 // Redo this every time we're asked for it, as we don't know if
506 // dataSource has changed.
508 {
510 }
511 else
512 {
513 return QgsDataSourceUri::removePassword( mDataSource, redactCredentials );
514 }
515}
516
517QString QgsMapLayer::source() const
518{
520
521 return mDataSource;
522}
523
525{
527
528 return mExtent2D.isNull() ? mExtent3D.toRectangle() : mExtent2D;
529}
530
532{
534
535 return mExtent3D;
536}
537
538void QgsMapLayer::setBlendMode( const QPainter::CompositionMode blendMode )
539{
541
542 if ( mBlendMode == blendMode )
543 return;
544
545 mBlendMode = blendMode;
548}
549
550QPainter::CompositionMode QgsMapLayer::blendMode() const
551{
552 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
554
555 return mBlendMode;
556}
557
558void QgsMapLayer::setOpacity( double opacity )
559{
561
563 return;
565 emit opacityChanged( opacity );
567}
568
570{
571 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
573
574 return mLayerOpacity;
575}
576
577bool QgsMapLayer::readLayerXml( const QDomElement &layerElement, QgsReadWriteContext &context, QgsMapLayer::ReadFlags flags, QgsDataProvider *preloadedProvider )
578{
580
581 mPreloadedProvider.reset( preloadedProvider );
582
583 bool layerError;
585
586 QDomNode mnl;
587 QDomElement mne;
588
589 // read provider
590 QString provider;
591 mnl = layerElement.namedItem( QStringLiteral( "provider" ) );
592 mne = mnl.toElement();
593 provider = mne.text();
594
595 // set data source
596 mnl = layerElement.namedItem( QStringLiteral( "datasource" ) );
597 mne = mnl.toElement();
598 const QString dataSourceRaw = mne.text();
599
600 // if the layer needs authentication, ensure the master password is set
601 const thread_local QRegularExpression rx( "authcfg=([a-z]|[A-Z]|[0-9]){7}" );
602 if ( rx.match( dataSourceRaw ).hasMatch()
604 {
605 return false;
606 }
607
608 mDataSource = decodedSource( dataSourceRaw, provider, context );
609
610 // Set the CRS from project file, asking the user if necessary.
611 // Make it the saved CRS to have WMS layer projected correctly.
612 // We will still overwrite whatever GDAL etc picks up anyway
613 // further down this function.
614 mnl = layerElement.namedItem( QStringLiteral( "layername" ) );
615 mne = mnl.toElement();
616
618 CUSTOM_CRS_VALIDATION savedValidation;
619
620 const QDomNode srsNode = layerElement.namedItem( QStringLiteral( "srs" ) );
621 mCRS.readXml( srsNode );
622 mCRS.setValidationHint( tr( "Specify CRS for layer %1" ).arg( mne.text() ) );
624 mCRS.validate();
625 savedCRS = mCRS;
626
627 // Do not validate any projections in children, they will be overwritten anyway.
628 // No need to ask the user for a projections when it is overwritten, is there?
631
632 const QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Layer" ), mne.text() );
633
634 // the internal name is just the data source basename
635 //QFileInfo dataSourceFileInfo( mDataSource );
636 //internalName = dataSourceFileInfo.baseName();
637
638 // set ID
639 mnl = layerElement.namedItem( QStringLiteral( "id" ) );
640 if ( ! mnl.isNull() )
641 {
642 mne = mnl.toElement();
643 if ( ! mne.isNull() && mne.text().length() > 10 ) // should be at least 17 (yyyyMMddhhmmsszzz)
644 {
645 const QString newId = mne.text();
646 if ( newId != mID )
647 {
648 mID = mne.text();
649 emit idChanged( mID );
650 }
651 }
652 }
653
654 // set name
655 mnl = layerElement.namedItem( QStringLiteral( "layername" ) );
656 mne = mnl.toElement();
657
658 //name can be translated
659 setName( context.projectTranslator()->translate( QStringLiteral( "project:layers:%1" ).arg( layerElement.namedItem( QStringLiteral( "id" ) ).toElement().text() ), mne.text() ) );
660
661 // now let the children grab what they need from the Dom node.
662 layerError = !readXml( layerElement, context );
663
664 const QgsCoordinateReferenceSystem oldVerticalCrs = verticalCrs();
665 const QgsCoordinateReferenceSystem oldCrs3D = mCrs3D;
666
667 // overwrite CRS with what we read from project file before the raster/vector
668 // file reading functions changed it. They will if projections is specified in the file.
669 // FIXME: is this necessary? Yes, it is (autumn 2019)
671 mCRS = savedCRS;
672
673 //vertical CRS
674 {
676 const QDomNode verticalCrsNode = layerElement.firstChildElement( QStringLiteral( "verticalCrs" ) );
677 if ( !verticalCrsNode.isNull() )
678 {
679 verticalCrs.readXml( verticalCrsNode );
680 }
681 mVerticalCrs = verticalCrs;
682 }
683 rebuildCrs3D();
684
685 serverProperties()->readXml( layerElement );
686
687 // mMetadata.readFromLayer( this );
688 const QDomElement metadataElem = layerElement.firstChildElement( QStringLiteral( "resourceMetadata" ) );
689 mMetadata.readMetadataXml( metadataElem );
690
691 setAutoRefreshInterval( layerElement.attribute( QStringLiteral( "autoRefreshTime" ), QStringLiteral( "0" ) ).toInt() );
692 if ( layerElement.hasAttribute( QStringLiteral( "autoRefreshMode" ) ) )
693 {
694 setAutoRefreshMode( qgsEnumKeyToValue( layerElement.attribute( QStringLiteral( "autoRefreshMode" ) ), Qgis::AutoRefreshMode::Disabled ) );
695 }
696 else
697 {
698 setAutoRefreshMode( layerElement.attribute( QStringLiteral( "autoRefreshEnabled" ), QStringLiteral( "0" ) ).toInt() ? Qgis::AutoRefreshMode::RedrawOnly : Qgis::AutoRefreshMode::Disabled );
699 }
700 setRefreshOnNofifyMessage( layerElement.attribute( QStringLiteral( "refreshOnNotifyMessage" ), QString() ) );
701 setRefreshOnNotifyEnabled( layerElement.attribute( QStringLiteral( "refreshOnNotifyEnabled" ), QStringLiteral( "0" ) ).toInt() );
702
703 // geographic extent is read only if necessary
705 {
706 const QDomNode wgs84ExtentNode = layerElement.namedItem( QStringLiteral( "wgs84extent" ) );
707 if ( !wgs84ExtentNode.isNull() )
708 mWgs84Extent = QgsXmlUtils::readRectangle( wgs84ExtentNode.toElement() );
709 }
710
711 mLegendPlaceholderImage = layerElement.attribute( QStringLiteral( "legendPlaceholderImage" ) );
712
713 if ( verticalCrs() != oldVerticalCrs )
714 emit verticalCrsChanged();
715 if ( mCrs3D != oldCrs3D )
716 emit crs3DChanged();
717
718 return ! layerError;
719} // bool QgsMapLayer::readLayerXML
720
721
722bool QgsMapLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
723{
725
726 Q_UNUSED( layer_node )
727 Q_UNUSED( context )
728 // NOP by default; children will over-ride with behavior specific to them
729
730 // read Extent
732 {
733 const QDomNode extent3DNode = layer_node.namedItem( QStringLiteral( "extent3D" ) );
734 if ( extent3DNode.isNull() )
735 {
736 const QDomNode extentNode = layer_node.namedItem( QStringLiteral( "extent" ) );
737 if ( !extentNode.isNull() )
738 {
739 mExtent2D = QgsXmlUtils::readRectangle( extentNode.toElement() );
740 }
741 }
742 else
743 {
744 mExtent3D = QgsXmlUtils::readBox3D( extent3DNode.toElement() );
745 }
746 }
747
748 return true;
749} // void QgsMapLayer::readXml
750
751
752bool QgsMapLayer::writeLayerXml( QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context ) const
753{
755
756 if ( !mExtent3D.isNull() && dataProvider() && dataProvider()->elevationProperties() && dataProvider()->elevationProperties()->containsElevationData() )
757 layerElement.appendChild( QgsXmlUtils::writeBox3D( mExtent3D, document ) );
758 else if ( !mExtent2D.isNull() )
759 layerElement.appendChild( QgsXmlUtils::writeRectangle( mExtent2D, document ) );
760
761 if ( const QgsRectangle lWgs84Extent = wgs84Extent( true ); !lWgs84Extent.isNull() )
762 {
763 layerElement.appendChild( QgsXmlUtils::writeRectangle( lWgs84Extent, document, QStringLiteral( "wgs84extent" ) ) );
764 }
765
766 layerElement.setAttribute( QStringLiteral( "autoRefreshTime" ), QString::number( mRefreshTimer->interval() ) );
767 layerElement.setAttribute( QStringLiteral( "autoRefreshMode" ), qgsEnumValueToKey( mAutoRefreshMode ) );
768 layerElement.setAttribute( QStringLiteral( "refreshOnNotifyEnabled" ), mIsRefreshOnNofifyEnabled ? 1 : 0 );
769 layerElement.setAttribute( QStringLiteral( "refreshOnNotifyMessage" ), mRefreshOnNofifyMessage );
770
771 // ID
772 QDomElement layerId = document.createElement( QStringLiteral( "id" ) );
773 const QDomText layerIdText = document.createTextNode( id() );
774 layerId.appendChild( layerIdText );
775
776 layerElement.appendChild( layerId );
777
778 if ( mVerticalCrs.isValid() )
779 {
780 QDomElement verticalSrsNode = document.createElement( QStringLiteral( "verticalCrs" ) );
781 mVerticalCrs.writeXml( verticalSrsNode, document );
782 layerElement.appendChild( verticalSrsNode );
783 }
784
785 // data source
786 QDomElement dataSource = document.createElement( QStringLiteral( "datasource" ) );
787 const QString src = encodedSource( source(), context );
788 const QDomText dataSourceText = document.createTextNode( src );
789 dataSource.appendChild( dataSourceText );
790 layerElement.appendChild( dataSource );
791
792 // layer name
793 QDomElement layerName = document.createElement( QStringLiteral( "layername" ) );
794 const QDomText layerNameText = document.createTextNode( name() );
795 layerName.appendChild( layerNameText );
796 layerElement.appendChild( layerName );
797
798 // timestamp if supported
799 if ( timestamp() > QDateTime() )
800 {
801 QDomElement stamp = document.createElement( QStringLiteral( "timestamp" ) );
802 const QDomText stampText = document.createTextNode( timestamp().toString( Qt::ISODate ) );
803 stamp.appendChild( stampText );
804 layerElement.appendChild( stamp );
805 }
806
807 layerElement.appendChild( layerName );
808
809 // zorder
810 // This is no longer stored in the project file. It is superfluous since the layers
811 // are written and read in the proper order.
812
813 // spatial reference system id
814 QDomElement mySrsElement = document.createElement( QStringLiteral( "srs" ) );
815 mCRS.writeXml( mySrsElement, document );
816 layerElement.appendChild( mySrsElement );
817
818 // layer metadata
819 QDomElement myMetadataElem = document.createElement( QStringLiteral( "resourceMetadata" ) );
820 mMetadata.writeMetadataXml( myMetadataElem, document );
821 layerElement.appendChild( myMetadataElem );
822
823 layerElement.setAttribute( QStringLiteral( "legendPlaceholderImage" ), mLegendPlaceholderImage );
824
825 serverProperties()->writeXml( layerElement, document );
826
827 // now append layer node to map layer node
828 return writeXml( layerElement, document, context );
829}
830
831void QgsMapLayer::writeCommonStyle( QDomElement &layerElement, QDomDocument &document,
832 const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
833{
835
836 // save categories
837 const QMetaEnum metaEnum = QMetaEnum::fromType<QgsMapLayer::StyleCategories>();
838 const QString categoriesKeys( metaEnum.valueToKeys( static_cast<int>( categories ) ) );
839 layerElement.setAttribute( QStringLiteral( "styleCategories" ), categoriesKeys );
840
841 if ( categories.testFlag( Rendering ) )
842 {
843 // use scale dependent visibility flag
844 layerElement.setAttribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ), hasScaleBasedVisibility() ? 1 : 0 );
845 layerElement.setAttribute( QStringLiteral( "maxScale" ), QString::number( maximumScale() ) );
846 layerElement.setAttribute( QStringLiteral( "minScale" ), QString::number( minimumScale() ) );
847 layerElement.setAttribute( QStringLiteral( "autoRefreshMode" ), qgsEnumValueToKey( mAutoRefreshMode ) );
848 layerElement.setAttribute( QStringLiteral( "autoRefreshTime" ), QString::number( autoRefreshInterval() ) );
849 }
850
851 if ( categories.testFlag( Symbology3D ) )
852 {
853 if ( m3DRenderer )
854 {
855 QDomElement renderer3DElem = document.createElement( QStringLiteral( "renderer-3d" ) );
856 renderer3DElem.setAttribute( QStringLiteral( "type" ), m3DRenderer->type() );
857 m3DRenderer->writeXml( renderer3DElem, context );
858 layerElement.appendChild( renderer3DElem );
859 }
860 }
861
862 if ( categories.testFlag( LayerConfiguration ) )
863 {
864 // flags
865 // this code is saving automatically all the flags entries
866 QDomElement layerFlagsElem = document.createElement( QStringLiteral( "flags" ) );
867 const auto enumMap = qgsEnumMap<QgsMapLayer::LayerFlag>();
868 for ( auto it = enumMap.constBegin(); it != enumMap.constEnd(); ++it )
869 {
870 const bool flagValue = mFlags.testFlag( it.key() );
871 QDomElement flagElem = document.createElement( it.value() );
872 flagElem.appendChild( document.createTextNode( QString::number( flagValue ) ) );
873 layerFlagsElem.appendChild( flagElem );
874 }
875 layerElement.appendChild( layerFlagsElem );
876 }
877
878 if ( categories.testFlag( Temporal ) )
879 {
881 properties->writeXml( layerElement, document, context );
882 }
883
884 if ( categories.testFlag( Elevation ) )
885 {
887 properties->writeXml( layerElement, document, context );
888 }
889
890 if ( categories.testFlag( Notes ) && QgsLayerNotesUtils::layerHasNotes( this ) )
891 {
892 QDomElement notesElem = document.createElement( QStringLiteral( "userNotes" ) );
893 notesElem.setAttribute( QStringLiteral( "value" ), QgsLayerNotesUtils::layerNotes( this ) );
894 layerElement.appendChild( notesElem );
895 }
896
897 // custom properties
898 if ( categories.testFlag( CustomProperties ) )
899 {
900 writeCustomProperties( layerElement, document );
901 }
902}
903
904
905bool QgsMapLayer::writeXml( QDomNode &layer_node, QDomDocument &document, const QgsReadWriteContext &context ) const
906{
908
909 Q_UNUSED( layer_node )
910 Q_UNUSED( document )
911 Q_UNUSED( context )
912 // NOP by default; children will over-ride with behavior specific to them
913
914 return true;
915}
916
917QString QgsMapLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
918{
920
921 Q_UNUSED( context )
922 return source;
923}
924
925QString QgsMapLayer::decodedSource( const QString &source, const QString &dataProvider, const QgsReadWriteContext &context ) const
926{
928
929 Q_UNUSED( context )
930 Q_UNUSED( dataProvider )
931 return source;
932}
933
935{
937
939 if ( m3DRenderer )
940 m3DRenderer->resolveReferences( *project );
941}
942
943
944void QgsMapLayer::readCustomProperties( const QDomNode &layerNode, const QString &keyStartsWith )
945{
947
948 const QgsObjectCustomProperties oldKeys = mCustomProperties;
949
950 mCustomProperties.readXml( layerNode, keyStartsWith );
951
952 for ( const QString &key : mCustomProperties.keys() )
953 {
954 if ( !oldKeys.contains( key ) || mCustomProperties.value( key ) != oldKeys.value( key ) )
955 {
956 emit customPropertyChanged( key );
957 }
958 }
959}
960
961void QgsMapLayer::writeCustomProperties( QDomNode &layerNode, QDomDocument &doc ) const
962{
964
965 mCustomProperties.writeXml( layerNode, doc );
966}
967
968void QgsMapLayer::readStyleManager( const QDomNode &layerNode )
969{
971
972 const QDomElement styleMgrElem = layerNode.firstChildElement( QStringLiteral( "map-layer-style-manager" ) );
973 if ( !styleMgrElem.isNull() )
974 mStyleManager->readXml( styleMgrElem );
975 else
976 mStyleManager->reset();
977}
978
979void QgsMapLayer::writeStyleManager( QDomNode &layerNode, QDomDocument &doc ) const
980{
982
983 if ( mStyleManager )
984 {
985 QDomElement styleMgrElem = doc.createElement( QStringLiteral( "map-layer-style-manager" ) );
986 mStyleManager->writeXml( styleMgrElem );
987 layerNode.appendChild( styleMgrElem );
988 }
989}
990
992{
994
995 return mMapTipTemplate;
996}
997
998void QgsMapLayer::setMapTipTemplate( const QString &mapTip )
999{
1001
1002 if ( mMapTipTemplate == mapTip )
1003 return;
1004
1005 mMapTipTemplate = mapTip;
1006 emit mapTipTemplateChanged();
1007}
1008
1010{
1012
1013 if ( mMapTipsEnabled == enabled )
1014 return;
1015
1016 mMapTipsEnabled = enabled;
1017 emit mapTipsEnabledChanged();
1018}
1019
1021{
1023
1024 return mMapTipsEnabled;
1025}
1026
1028{
1030 if ( layerReadFlags & QgsMapLayer::FlagTrustLayerMetadata )
1031 {
1033 }
1034 if ( layerReadFlags & QgsMapLayer::FlagForceReadOnly )
1035 {
1037 }
1038
1039 if ( layerReadFlags & QgsMapLayer::FlagReadExtentFromXml )
1040 {
1041 const QDomNode extent3DNode = layerNode.namedItem( QStringLiteral( "extent3D" ) );
1042 if ( extent3DNode.isNull() )
1043 {
1044 const QDomNode extentNode = layerNode.namedItem( QStringLiteral( "extent" ) );
1045 if ( !extentNode.isNull() )
1046 {
1048 }
1049 }
1050 else
1051 {
1053 }
1054 }
1055
1056 return flags;
1057}
1058
1060{
1061 // because QgsVirtualLayerProvider is not anywhere NEAR thread safe:
1063
1064 return mValid;
1065}
1066
1067#if 0
1068void QgsMapLayer::connectNotify( const char *signal )
1069{
1070 Q_UNUSED( signal )
1071 QgsDebugMsgLevel( "QgsMapLayer connected to " + QString( signal ), 3 );
1072} // QgsMapLayer::connectNotify
1073#endif
1074
1075bool QgsMapLayer::isInScaleRange( double scale ) const
1076{
1077 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
1079
1080 // mMinScale (denominator!) is inclusive ( >= --> In range )
1081 // mMaxScale (denominator!) is exclusive ( < --> In range )
1082 return !mScaleBasedVisibility
1083 || ( ( mMinScale == 0 || !QgsScaleUtils::lessThanMaximumScale( scale, mMinScale ) )
1084 && ( mMaxScale == 0 || !QgsScaleUtils::equalToOrGreaterThanMinimumScale( scale, mMaxScale ) ) );
1085}
1086
1088{
1089 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
1091
1092 return mScaleBasedVisibility;
1093}
1094
1096{
1098
1099 return mAutoRefreshMode != Qgis::AutoRefreshMode::Disabled;;
1100}
1101
1103{
1105
1106 return mAutoRefreshMode;
1107}
1108
1110{
1112
1113 return mRefreshTimer->interval();
1114}
1115
1117{
1119
1120 if ( interval <= 0 )
1121 {
1122 mRefreshTimer->stop();
1123 mRefreshTimer->setInterval( 0 );
1125 }
1126 else
1127 {
1128 mRefreshTimer->setInterval( interval );
1129 }
1130 emit autoRefreshIntervalChanged( mRefreshTimer->isActive() ? mRefreshTimer->interval() : 0 );
1131}
1132
1139
1141{
1143
1144 if ( mode == mAutoRefreshMode )
1145 return;
1146
1147 mAutoRefreshMode = mode;
1148 switch ( mAutoRefreshMode )
1149 {
1151 mRefreshTimer->stop();
1152 break;
1153
1156 if ( mRefreshTimer->interval() > 0 )
1157 mRefreshTimer->start();
1158 break;
1159 }
1160
1161 emit autoRefreshIntervalChanged( mRefreshTimer->isActive() ? mRefreshTimer->interval() : 0 );
1162}
1163
1165{
1167
1168 return mMetadata;
1169}
1170
1172{
1174
1175 mMinScale = scale;
1176}
1177
1179{
1181
1182 return mMinScale;
1183}
1184
1186{
1188
1189 mMaxScale = scale;
1190}
1191
1193{
1195
1196 mScaleBasedVisibility = enabled;
1197}
1198
1200{
1202
1203 return mMaxScale;
1204}
1205
1206QStringList QgsMapLayer::subLayers() const
1207{
1209
1210 return QStringList();
1211}
1212
1213void QgsMapLayer::setLayerOrder( const QStringList &layers )
1214{
1216
1217 Q_UNUSED( layers )
1218}
1219
1220void QgsMapLayer::setSubLayerVisibility( const QString &name, bool vis )
1221{
1223
1224 Q_UNUSED( name )
1225 Q_UNUSED( vis )
1226}
1227
1229{
1231
1232 return false;
1233}
1234
1236{
1237 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
1239
1240 return mCRS;
1241}
1242
1244{
1245 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
1247
1248 switch ( mCRS.type() )
1249 {
1250 case Qgis::CrsType::Vertical: // would hope this never happens!
1251 QgsDebugError( QStringLiteral( "Layer has a vertical CRS set as the horizontal CRS!" ) );
1252 return mCRS;
1253
1255 return mCRS.verticalCrs();
1256
1268 break;
1269 }
1270 return mVerticalCrs;
1271}
1272
1274{
1276
1277 return mCrs3D.isValid() ? mCrs3D : mCRS;
1278}
1279
1280void QgsMapLayer::setCrs( const QgsCoordinateReferenceSystem &srs, bool emitSignal )
1281{
1283 const bool needToValidateCrs = mShouldValidateCrs && isSpatial() && !srs.isValid() && type() != Qgis::LayerType::Annotation;
1284
1285 if ( mCRS == srs && !needToValidateCrs )
1286 return;
1287
1288 const QgsCoordinateReferenceSystem oldVerticalCrs = verticalCrs();
1289 const QgsCoordinateReferenceSystem oldCrs3D = mCrs3D;
1290 const QgsCoordinateReferenceSystem oldCrs = mCRS;
1291
1292 mCRS = srs;
1293
1294 if ( needToValidateCrs )
1295 {
1296 mCRS.setValidationHint( tr( "Specify CRS for layer %1" ).arg( name() ) );
1297 mCRS.validate();
1298 }
1299
1300 rebuildCrs3D();
1301
1302 if ( emitSignal && mCRS != oldCrs )
1303 emit crsChanged();
1304
1305 // Did vertical crs also change as a result of this? If so, emit signal
1306 if ( oldVerticalCrs != verticalCrs() )
1307 emit verticalCrsChanged();
1308 if ( oldCrs3D != mCrs3D )
1309 emit crs3DChanged();
1310}
1311
1313{
1315 bool res = true;
1316 if ( crs.isValid() )
1317 {
1318 // validate that passed crs is a vertical crs
1319 switch ( crs.type() )
1320 {
1322 break;
1323
1336 if ( errorMessage )
1337 *errorMessage = QObject::tr( "Specified CRS is a %1 CRS, not a Vertical CRS" ).arg( qgsEnumValueToKey( crs.type() ) );
1338 return false;
1339 }
1340 }
1341
1342 if ( crs != mVerticalCrs )
1343 {
1344 const QgsCoordinateReferenceSystem oldVerticalCrs = verticalCrs();
1345 const QgsCoordinateReferenceSystem oldCrs3D = mCrs3D;
1346
1347 switch ( mCRS.type() )
1348 {
1350 if ( crs != oldVerticalCrs )
1351 {
1352 if ( errorMessage )
1353 *errorMessage = QObject::tr( "Layer CRS is a Compound CRS, specified Vertical CRS will be ignored" );
1354 return false;
1355 }
1356 break;
1357
1359 if ( crs != oldVerticalCrs )
1360 {
1361 if ( errorMessage )
1362 *errorMessage = QObject::tr( "Layer CRS is a Geographic 3D CRS, specified Vertical CRS will be ignored" );
1363 return false;
1364 }
1365 break;
1366
1368 if ( crs != oldVerticalCrs )
1369 {
1370 if ( errorMessage )
1371 *errorMessage = QObject::tr( "Layer CRS is a Geocentric CRS, specified Vertical CRS will be ignored" );
1372 return false;
1373 }
1374 break;
1375
1377 if ( mCRS.hasVerticalAxis() && crs != oldVerticalCrs )
1378 {
1379 if ( errorMessage )
1380 *errorMessage = QObject::tr( "Layer CRS is a Projected 3D CRS, specified Vertical CRS will be ignored" );
1381 return false;
1382 }
1383 break;
1384
1394 break;
1395 }
1396
1397 mVerticalCrs = crs;
1398 res = rebuildCrs3D( errorMessage );
1399
1400 // only emit signal if vertical crs was actually changed, so eg if mCrs is compound
1401 // then we haven't actually changed the vertical crs by this call!
1402 if ( verticalCrs() != oldVerticalCrs )
1403 emit verticalCrsChanged();
1404 if ( mCrs3D != oldCrs3D )
1405 emit crs3DChanged();
1406 }
1407 return res;
1408}
1409
1411{
1413
1414 const QgsDataProvider *lDataProvider = dataProvider();
1415 return lDataProvider ? lDataProvider->transformContext() : QgsCoordinateTransformContext();
1416}
1417
1418QString QgsMapLayer::formatLayerName( const QString &name )
1419{
1420 QString layerName( name );
1421 layerName.replace( '_', ' ' );
1423 return layerName;
1424}
1425
1426QString QgsMapLayer::baseURI( PropertyType type ) const
1427{
1429
1430 QString myURI = publicSource();
1431
1432 // first get base path for delimited text, spatialite and OGR layers,
1433 // as in these cases URI may contain layer name and/or additional
1434 // information. This also strips prefix in case if VSIFILE mechanism
1435 // is used
1436 if ( providerType() == QLatin1String( "ogr" ) || providerType() == QLatin1String( "delimitedtext" )
1437 || providerType() == QLatin1String( "gdal" ) || providerType() == QLatin1String( "spatialite" ) )
1438 {
1439 QVariantMap components = QgsProviderRegistry::instance()->decodeUri( providerType(), myURI );
1440 myURI = components["path"].toString();
1441 }
1442
1443 QFileInfo myFileInfo( myURI );
1444 QString key;
1445
1446 if ( myFileInfo.exists() )
1447 {
1448 // if file is using the /vsizip/ or /vsigzip/ mechanism, cleanup the name
1449 if ( myURI.endsWith( QLatin1String( ".gz" ), Qt::CaseInsensitive ) )
1450 myURI.chop( 3 );
1451 else if ( myURI.endsWith( QLatin1String( ".zip" ), Qt::CaseInsensitive ) )
1452 myURI.chop( 4 );
1453 else if ( myURI.endsWith( QLatin1String( ".tar" ), Qt::CaseInsensitive ) )
1454 myURI.chop( 4 );
1455 else if ( myURI.endsWith( QLatin1String( ".tar.gz" ), Qt::CaseInsensitive ) )
1456 myURI.chop( 7 );
1457 else if ( myURI.endsWith( QLatin1String( ".tgz" ), Qt::CaseInsensitive ) )
1458 myURI.chop( 4 );
1459 myFileInfo.setFile( myURI );
1460 // get the file name for our .qml style file
1461 key = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + QgsMapLayer::extensionPropertyType( type );
1462 }
1463 else
1464 {
1465 key = publicSource();
1466 }
1467
1468 return key;
1469}
1470
1472{
1474
1475 return baseURI( PropertyType::Metadata );
1476}
1477
1478QString QgsMapLayer::saveDefaultMetadata( bool &resultFlag )
1479{
1481
1483 {
1484 if ( metadata->providerCapabilities() & QgsProviderMetadata::SaveLayerMetadata )
1485 {
1486 try
1487 {
1488 QString errorMessage;
1489 resultFlag = QgsProviderRegistry::instance()->saveLayerMetadata( providerType(), mDataSource, mMetadata, errorMessage );
1490 if ( resultFlag )
1491 return tr( "Successfully saved default layer metadata" );
1492 else
1493 return errorMessage;
1494 }
1495 catch ( QgsNotSupportedException &e )
1496 {
1497 resultFlag = false;
1498 return e.what();
1499 }
1500 }
1501 }
1502
1503 // fallback default metadata saving method, for providers which don't support (or implement) saveLayerMetadata
1504 return saveNamedMetadata( metadataUri(), resultFlag );
1505}
1506
1507QString QgsMapLayer::loadDefaultMetadata( bool &resultFlag )
1508{
1510
1511 return loadNamedMetadata( metadataUri(), resultFlag );
1512}
1513
1515{
1517
1518 return baseURI( PropertyType::Style );
1519}
1520
1527
1528bool QgsMapLayer::loadNamedMetadataFromDatabase( const QString &db, const QString &uri, QString &qmd )
1529{
1531
1532 return loadNamedPropertyFromDatabase( db, uri, qmd, PropertyType::Metadata );
1533}
1534
1535bool QgsMapLayer::loadNamedStyleFromDatabase( const QString &db, const QString &uri, QString &qml )
1536{
1538
1539 return loadNamedPropertyFromDatabase( db, uri, qml, PropertyType::Style );
1540}
1541
1542bool QgsMapLayer::loadNamedPropertyFromDatabase( const QString &db, const QString &uri, QString &xml, QgsMapLayer::PropertyType type )
1543{
1545
1546 QgsDebugMsgLevel( QStringLiteral( "db = %1 uri = %2" ).arg( db, uri ), 4 );
1547
1548 bool resultFlag = false;
1549
1550 // read from database
1553
1554 int myResult;
1555
1556 QgsDebugMsgLevel( QStringLiteral( "Trying to load style or metadata for \"%1\" from \"%2\"" ).arg( uri, db ), 4 );
1557
1558 if ( db.isEmpty() || !QFile( db ).exists() )
1559 return false;
1560
1561 myResult = database.open_v2( db, SQLITE_OPEN_READONLY, nullptr );
1562 if ( myResult != SQLITE_OK )
1563 {
1564 return false;
1565 }
1566
1567 QString mySql;
1568 switch ( type )
1569 {
1570 case Metadata:
1571 mySql = QStringLiteral( "select qmd from tbl_metadata where metadata=?" );
1572 break;
1573
1574 case Style:
1575 mySql = QStringLiteral( "select qml from tbl_styles where style=?" );
1576 break;
1577 }
1578
1579 statement = database.prepare( mySql, myResult );
1580 if ( myResult == SQLITE_OK )
1581 {
1582 QByteArray param = uri.toUtf8();
1583
1584 if ( sqlite3_bind_text( statement.get(), 1, param.data(), param.length(), SQLITE_STATIC ) == SQLITE_OK &&
1585 sqlite3_step( statement.get() ) == SQLITE_ROW )
1586 {
1587 xml = QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( statement.get(), 0 ) ) );
1588 resultFlag = true;
1589 }
1590 }
1591 return resultFlag;
1592}
1593
1594
1595QString QgsMapLayer::loadNamedStyle( const QString &uri, bool &resultFlag, QgsMapLayer::StyleCategories categories, Qgis::LoadStyleFlags flags )
1596{
1598
1599 return loadNamedStyle( uri, resultFlag, false, categories, flags );
1600}
1601
1602QString QgsMapLayer::loadNamedProperty( const QString &uri, QgsMapLayer::PropertyType type, bool &namedPropertyExists, bool &propertySuccessfullyLoaded, StyleCategories categories, Qgis::LoadStyleFlags flags )
1603{
1605
1606 QgsDebugMsgLevel( QStringLiteral( "uri = %1 myURI = %2" ).arg( uri, publicSource() ), 4 );
1607
1608 namedPropertyExists = false;
1609 propertySuccessfullyLoaded = false;
1610 if ( uri.isEmpty() )
1611 return QString();
1612
1613 QDomDocument myDocument( QStringLiteral( "qgis" ) );
1614
1615 // location of problem associated with errorMsg
1616 int line, column;
1617 QString myErrorMessage;
1618
1619 QFile myFile( uri );
1620 if ( myFile.open( QFile::ReadOnly ) )
1621 {
1622 QgsDebugMsgLevel( QStringLiteral( "file found %1" ).arg( uri ), 2 );
1623 namedPropertyExists = true;
1624
1625 // read file
1626 propertySuccessfullyLoaded = myDocument.setContent( &myFile, &myErrorMessage, &line, &column );
1627 if ( !propertySuccessfullyLoaded )
1628 myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1629 myFile.close();
1630 }
1631 else
1632 {
1633 const QFileInfo project( QgsProject::instance()->fileName() ); // skip-keyword-check
1634 QgsDebugMsgLevel( QStringLiteral( "project fileName: %1" ).arg( project.absoluteFilePath() ), 4 );
1635
1636 QString xml;
1637 switch ( type )
1638 {
1639 case QgsMapLayer::Style:
1640 {
1641 if ( loadNamedStyleFromDatabase( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ), uri, xml ) ||
1642 ( project.exists() && loadNamedStyleFromDatabase( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), uri, xml ) ) ||
1643 loadNamedStyleFromDatabase( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( QStringLiteral( "resources/qgis.qmldb" ) ), uri, xml ) )
1644 {
1645 namedPropertyExists = true;
1646 propertySuccessfullyLoaded = myDocument.setContent( xml, &myErrorMessage, &line, &column );
1647 if ( !propertySuccessfullyLoaded )
1648 {
1649 myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1650 }
1651 }
1652 else
1653 {
1655 {
1656 myErrorMessage = tr( "Style not found in database" );
1657 }
1658 }
1659 break;
1660 }
1662 {
1663 if ( loadNamedMetadataFromDatabase( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ), uri, xml ) ||
1664 ( project.exists() && loadNamedMetadataFromDatabase( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), uri, xml ) ) ||
1665 loadNamedMetadataFromDatabase( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( QStringLiteral( "resources/qgis.qmldb" ) ), uri, xml ) )
1666 {
1667 namedPropertyExists = true;
1668 propertySuccessfullyLoaded = myDocument.setContent( xml, &myErrorMessage, &line, &column );
1669 if ( !propertySuccessfullyLoaded )
1670 {
1671 myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1672 }
1673 }
1674 else
1675 {
1676 myErrorMessage = tr( "Metadata not found in database" );
1677 }
1678 break;
1679 }
1680 }
1681 }
1682
1683 if ( !propertySuccessfullyLoaded )
1684 {
1685 return myErrorMessage;
1686 }
1687
1688 switch ( type )
1689 {
1690 case QgsMapLayer::Style:
1691 propertySuccessfullyLoaded = importNamedStyle( myDocument, myErrorMessage, categories );
1692 if ( !propertySuccessfullyLoaded )
1693 myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( uri, myErrorMessage );
1694 break;
1696 propertySuccessfullyLoaded = importNamedMetadata( myDocument, myErrorMessage );
1697 if ( !propertySuccessfullyLoaded )
1698 myErrorMessage = tr( "Loading metadata file %1 failed because:\n%2" ).arg( uri, myErrorMessage );
1699 break;
1700 }
1701 return myErrorMessage;
1702}
1703
1704bool QgsMapLayer::importNamedMetadata( QDomDocument &document, QString &errorMessage )
1705{
1707
1708 const QDomElement myRoot = document.firstChildElement( QStringLiteral( "qgis" ) );
1709 if ( myRoot.isNull() )
1710 {
1711 errorMessage = tr( "Root <qgis> element could not be found" );
1712 return false;
1713 }
1714
1715 return mMetadata.readMetadataXml( myRoot );
1716}
1717
1718bool QgsMapLayer::importNamedStyle( QDomDocument &myDocument, QString &myErrorMessage, QgsMapLayer::StyleCategories categories )
1719{
1721
1722 const QDomElement myRoot = myDocument.firstChildElement( QStringLiteral( "qgis" ) );
1723 if ( myRoot.isNull() )
1724 {
1725 myErrorMessage = tr( "Root <qgis> element could not be found" );
1726 return false;
1727 }
1728
1729 // get style file version string, if any
1730 const QgsProjectVersion fileVersion( myRoot.attribute( QStringLiteral( "version" ) ) );
1731 const QgsProjectVersion thisVersion( Qgis::version() );
1732
1733 if ( thisVersion > fileVersion )
1734 {
1735 QgsProjectFileTransform styleFile( myDocument, fileVersion );
1736 styleFile.updateRevision( thisVersion );
1737 }
1738
1739 // Get source categories
1740 const QgsMapLayer::StyleCategories sourceCategories = QgsXmlUtils::readFlagAttribute( myRoot, QStringLiteral( "styleCategories" ), QgsMapLayer::AllStyleCategories );
1741
1742 //Test for matching geometry type on vector layers when applying, if geometry type is given in the style
1743 if ( ( sourceCategories.testFlag( QgsMapLayer::Symbology ) || sourceCategories.testFlag( QgsMapLayer::Symbology3D ) ) &&
1744 ( categories.testFlag( QgsMapLayer::Symbology ) || categories.testFlag( QgsMapLayer::Symbology3D ) ) )
1745 {
1746 if ( type() == Qgis::LayerType::Vector && !myRoot.firstChildElement( QStringLiteral( "layerGeometryType" ) ).isNull() )
1747 {
1748 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( this );
1749 const Qgis::GeometryType importLayerGeometryType = static_cast<Qgis::GeometryType>( myRoot.firstChildElement( QStringLiteral( "layerGeometryType" ) ).text().toInt() );
1750 if ( importLayerGeometryType != Qgis::GeometryType::Unknown && vl->geometryType() != importLayerGeometryType )
1751 {
1752 myErrorMessage = tr( "Cannot apply style with symbology to layer with a different geometry type" );
1753 return false;
1754 }
1755 }
1756 }
1757
1759 return readSymbology( myRoot, myErrorMessage, context, categories ); // TODO: support relative paths in QML?
1760}
1761
1762void QgsMapLayer::exportNamedMetadata( QDomDocument &doc, QString &errorMsg ) const
1763{
1765
1766 QDomImplementation DomImplementation;
1767 const QDomDocumentType documentType = DomImplementation.createDocumentType( QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
1768 QDomDocument myDocument( documentType );
1769
1770 QDomElement myRootNode = myDocument.createElement( QStringLiteral( "qgis" ) );
1771 myRootNode.setAttribute( QStringLiteral( "version" ), Qgis::version() );
1772 myDocument.appendChild( myRootNode );
1773
1774 if ( !mMetadata.writeMetadataXml( myRootNode, myDocument ) )
1775 {
1776 errorMsg = QObject::tr( "Could not save metadata" );
1777 return;
1778 }
1779
1780 doc = myDocument;
1781}
1782
1783void QgsMapLayer::exportNamedStyle( QDomDocument &doc, QString &errorMsg, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1784{
1786
1787 QDomImplementation DomImplementation;
1788 const QDomDocumentType documentType = DomImplementation.createDocumentType( QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
1789 QDomDocument myDocument( documentType );
1790
1791 QDomElement myRootNode = myDocument.createElement( QStringLiteral( "qgis" ) );
1792 myRootNode.setAttribute( QStringLiteral( "version" ), Qgis::version() );
1793 myDocument.appendChild( myRootNode );
1794
1795 if ( !writeSymbology( myRootNode, myDocument, errorMsg, context, categories ) ) // TODO: support relative paths in QML?
1796 {
1797 errorMsg = QObject::tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1798 return;
1799 }
1800
1801 /*
1802 * Check to see if the layer is vector - in which case we should also export its geometryType
1803 * to avoid eventually pasting to a layer with a different geometry
1804 */
1805 if ( type() == Qgis::LayerType::Vector )
1806 {
1807 //Getting the selectionLayer geometry
1808 const QgsVectorLayer *vl = qobject_cast<const QgsVectorLayer *>( this );
1809 const QString geoType = QString::number( static_cast<int>( vl->geometryType() ) );
1810
1811 //Adding geometryinformation
1812 QDomElement layerGeometryType = myDocument.createElement( QStringLiteral( "layerGeometryType" ) );
1813 const QDomText type = myDocument.createTextNode( geoType );
1814
1815 layerGeometryType.appendChild( type );
1816 myRootNode.appendChild( layerGeometryType );
1817 }
1818
1819 doc = myDocument;
1820}
1821
1822QString QgsMapLayer::saveDefaultStyle( bool &resultFlag )
1823{
1825
1826 return saveDefaultStyle( resultFlag, AllStyleCategories );
1827}
1828
1829QString QgsMapLayer::saveDefaultStyle( bool &resultFlag, StyleCategories categories )
1830{
1832
1833 return saveNamedStyle( styleURI(), resultFlag, categories );
1834}
1835
1836QString QgsMapLayer::saveNamedMetadata( const QString &uri, bool &resultFlag )
1837{
1839
1840 return saveNamedProperty( uri, QgsMapLayer::Metadata, resultFlag );
1841}
1842
1843QString QgsMapLayer::loadNamedMetadata( const QString &uri, bool &resultFlag )
1844{
1846
1847 bool metadataExists = false;
1848 bool metadataSuccessfullyLoaded = false;
1849 const QString message = loadNamedProperty( uri, QgsMapLayer::Metadata, metadataExists, metadataSuccessfullyLoaded );
1850
1851 // TODO QGIS 4.0 -- fix API for loadNamedMetadata so we can return metadataExists too
1852 ( void )metadataExists;
1853 resultFlag = metadataSuccessfullyLoaded;
1854 return message;
1855}
1856
1857QString QgsMapLayer::saveNamedProperty( const QString &uri, QgsMapLayer::PropertyType type, bool &resultFlag, StyleCategories categories )
1858{
1860
1861 // check if the uri is a file or ends with .qml/.qmd,
1862 // which indicates that it should become one
1863 // everything else goes to the database
1864 QString filename;
1865
1866 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this );
1867 if ( vlayer && vlayer->providerType() == QLatin1String( "ogr" ) )
1868 {
1869 QStringList theURIParts = uri.split( '|' );
1870 filename = theURIParts[0];
1871 }
1872 else if ( vlayer && vlayer->providerType() == QLatin1String( "gpx" ) )
1873 {
1874 QStringList theURIParts = uri.split( '?' );
1875 filename = theURIParts[0];
1876 }
1877 else if ( vlayer && vlayer->providerType() == QLatin1String( "delimitedtext" ) )
1878 {
1879 filename = QUrl::fromEncoded( uri.toLatin1() ).toLocalFile();
1880 // toLocalFile() returns an empty string if theURI is a plain Windows-path, e.g. "C:/style.qml"
1881 if ( filename.isEmpty() )
1882 filename = uri;
1883 }
1884 else
1885 {
1886 filename = uri;
1887 }
1888
1889 QString myErrorMessage;
1890 QDomDocument myDocument;
1891 switch ( type )
1892 {
1893 case Metadata:
1894 exportNamedMetadata( myDocument, myErrorMessage );
1895 break;
1896
1897 case Style:
1898 const QgsReadWriteContext context;
1899 exportNamedStyle( myDocument, myErrorMessage, context, categories );
1900 break;
1901 }
1902
1903 const QFileInfo myFileInfo( filename );
1904 if ( myFileInfo.exists() || filename.endsWith( QgsMapLayer::extensionPropertyType( type ), Qt::CaseInsensitive ) )
1905 {
1906 const QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
1907 if ( !myDirInfo.isWritable() )
1908 {
1909 resultFlag = false;
1910 return tr( "The directory containing your dataset needs to be writable!" );
1911 }
1912
1913 // now construct the file name for our .qml or .qmd file
1914 const QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + QgsMapLayer::extensionPropertyType( type );
1915
1916 QFile myFile( myFileName );
1917 if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
1918 {
1919 QTextStream myFileStream( &myFile );
1920 // save as utf-8 with 2 spaces for indents
1921 myDocument.save( myFileStream, 2 );
1922 myFile.close();
1923 resultFlag = true;
1924 switch ( type )
1925 {
1926 case Metadata:
1927 return tr( "Created default metadata file as %1" ).arg( myFileName );
1928
1929 case Style:
1930 return tr( "Created default style file as %1" ).arg( myFileName );
1931 }
1932
1933 }
1934 else
1935 {
1936 resultFlag = false;
1937 switch ( type )
1938 {
1939 case Metadata:
1940 return tr( "ERROR: Failed to created default metadata file as %1. Check file permissions and retry." ).arg( myFileName );
1941
1942 case Style:
1943 return tr( "ERROR: Failed to created default style file as %1. Check file permissions and retry." ).arg( myFileName );
1944 }
1945 }
1946 }
1947 else
1948 {
1949 const QString qml = myDocument.toString();
1950
1951 // read from database
1954
1955 int myResult = database.open( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ) );
1956 if ( myResult != SQLITE_OK )
1957 {
1958 return tr( "User database could not be opened." );
1959 }
1960
1961 QByteArray param0 = uri.toUtf8();
1962 QByteArray param1 = qml.toUtf8();
1963
1964 QString mySql;
1965 switch ( type )
1966 {
1967 case Metadata:
1968 mySql = QStringLiteral( "create table if not exists tbl_metadata(metadata varchar primary key,qmd varchar)" );
1969 break;
1970
1971 case Style:
1972 mySql = QStringLiteral( "create table if not exists tbl_styles(style varchar primary key,qml varchar)" );
1973 break;
1974 }
1975
1976 statement = database.prepare( mySql, myResult );
1977 if ( myResult == SQLITE_OK )
1978 {
1979 if ( sqlite3_step( statement.get() ) != SQLITE_DONE )
1980 {
1981 resultFlag = false;
1982 switch ( type )
1983 {
1984 case Metadata:
1985 return tr( "The metadata table could not be created." );
1986
1987 case Style:
1988 return tr( "The style table could not be created." );
1989 }
1990 }
1991 }
1992
1993 switch ( type )
1994 {
1995 case Metadata:
1996 mySql = QStringLiteral( "insert into tbl_metadata(metadata,qmd) values (?,?)" );
1997 break;
1998
1999 case Style:
2000 mySql = QStringLiteral( "insert into tbl_styles(style,qml) values (?,?)" );
2001 break;
2002 }
2003 statement = database.prepare( mySql, myResult );
2004 if ( myResult == SQLITE_OK )
2005 {
2006 if ( sqlite3_bind_text( statement.get(), 1, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
2007 sqlite3_bind_text( statement.get(), 2, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
2008 sqlite3_step( statement.get() ) == SQLITE_DONE )
2009 {
2010 resultFlag = true;
2011 switch ( type )
2012 {
2013 case Metadata:
2014 myErrorMessage = tr( "The metadata %1 was saved to database" ).arg( uri );
2015 break;
2016
2017 case Style:
2018 myErrorMessage = tr( "The style %1 was saved to database" ).arg( uri );
2019 break;
2020 }
2021 }
2022 }
2023
2024 if ( !resultFlag )
2025 {
2026 QString mySql;
2027 switch ( type )
2028 {
2029 case Metadata:
2030 mySql = QStringLiteral( "update tbl_metadata set qmd=? where metadata=?" );
2031 break;
2032
2033 case Style:
2034 mySql = QStringLiteral( "update tbl_styles set qml=? where style=?" );
2035 break;
2036 }
2037 statement = database.prepare( mySql, myResult );
2038 if ( myResult == SQLITE_OK )
2039 {
2040 if ( sqlite3_bind_text( statement.get(), 2, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
2041 sqlite3_bind_text( statement.get(), 1, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
2042 sqlite3_step( statement.get() ) == SQLITE_DONE )
2043 {
2044 resultFlag = true;
2045 switch ( type )
2046 {
2047 case Metadata:
2048 myErrorMessage = tr( "The metadata %1 was updated in the database." ).arg( uri );
2049 break;
2050
2051 case Style:
2052 myErrorMessage = tr( "The style %1 was updated in the database." ).arg( uri );
2053 break;
2054 }
2055 }
2056 else
2057 {
2058 resultFlag = false;
2059 switch ( type )
2060 {
2061 case Metadata:
2062 myErrorMessage = tr( "The metadata %1 could not be updated in the database." ).arg( uri );
2063 break;
2064
2065 case Style:
2066 myErrorMessage = tr( "The style %1 could not be updated in the database." ).arg( uri );
2067 break;
2068 }
2069 }
2070 }
2071 else
2072 {
2073 resultFlag = false;
2074 switch ( type )
2075 {
2076 case Metadata:
2077 myErrorMessage = tr( "The metadata %1 could not be inserted into database." ).arg( uri );
2078 break;
2079
2080 case Style:
2081 myErrorMessage = tr( "The style %1 could not be inserted into database." ).arg( uri );
2082 break;
2083 }
2084 }
2085 }
2086 }
2087
2088 return myErrorMessage;
2089}
2090
2091QString QgsMapLayer::saveNamedStyle( const QString &uri, bool &resultFlag, StyleCategories categories )
2092{
2094
2095 return saveNamedProperty( uri, QgsMapLayer::Style, resultFlag, categories );
2096}
2097
2098void QgsMapLayer::exportSldStyle( QDomDocument &doc, QString &errorMsg ) const
2099{
2100
2101 return exportSldStyleV2( doc, errorMsg, QgsSldExportContext() );
2102}
2103
2104void QgsMapLayer::exportSldStyleV2( QDomDocument &doc, QString &errorMsg, const QgsSldExportContext &exportContext ) const
2105{
2107
2108 QDomDocument myDocument = QDomDocument();
2109
2110 const QDomNode header = myDocument.createProcessingInstruction( QStringLiteral( "xml" ), QStringLiteral( "version=\"1.0\" encoding=\"UTF-8\"" ) );
2111 myDocument.appendChild( header );
2112
2113 const QgsVectorLayer *vlayer = qobject_cast<const QgsVectorLayer *>( this );
2114 const QgsRasterLayer *rlayer = qobject_cast<const QgsRasterLayer *>( this );
2115 if ( !vlayer && !rlayer )
2116 {
2117 errorMsg = tr( "Could not save symbology because:\n%1" )
2118 .arg( tr( "Only vector and raster layers are supported" ) );
2119 return;
2120 }
2121
2122 // Create the root element
2123 QDomElement root = myDocument.createElementNS( QStringLiteral( "http://www.opengis.net/sld" ), QStringLiteral( "StyledLayerDescriptor" ) );
2124 QDomElement layerNode;
2125 if ( vlayer )
2126 {
2127 root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.1.0" ) );
2128 root.setAttribute( QStringLiteral( "xsi:schemaLocation" ), QStringLiteral( "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" ) );
2129 root.setAttribute( QStringLiteral( "xmlns:ogc" ), QStringLiteral( "http://www.opengis.net/ogc" ) );
2130 root.setAttribute( QStringLiteral( "xmlns:se" ), QStringLiteral( "http://www.opengis.net/se" ) );
2131 root.setAttribute( QStringLiteral( "xmlns:xlink" ), QStringLiteral( "http://www.w3.org/1999/xlink" ) );
2132 root.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) );
2133 myDocument.appendChild( root );
2134
2135 // Create the NamedLayer element
2136 layerNode = myDocument.createElement( QStringLiteral( "NamedLayer" ) );
2137 root.appendChild( layerNode );
2138 }
2139
2140 // note: Only SLD 1.0 version is generated because seems none is using SE1.1.0 at least for rasters
2141 if ( rlayer )
2142 {
2143 // Create the root element
2144 root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0.0" ) );
2145 root.setAttribute( QStringLiteral( "xmlns:gml" ), QStringLiteral( "http://www.opengis.net/gml" ) );
2146 root.setAttribute( QStringLiteral( "xmlns:ogc" ), QStringLiteral( "http://www.opengis.net/ogc" ) );
2147 root.setAttribute( QStringLiteral( "xmlns:sld" ), QStringLiteral( "http://www.opengis.net/sld" ) );
2148 myDocument.appendChild( root );
2149
2150 // Create the NamedLayer element
2151 layerNode = myDocument.createElement( QStringLiteral( "UserLayer" ) );
2152 root.appendChild( layerNode );
2153 }
2154
2155 QVariantMap props;
2156
2157 QVariant context;
2158 context.setValue( exportContext );
2159
2160 props[ QStringLiteral( "SldExportContext" ) ] = context;
2161
2163 {
2164 props[ QStringLiteral( "scaleMinDenom" ) ] = QString::number( mMinScale );
2165 props[ QStringLiteral( "scaleMaxDenom" ) ] = QString::number( mMaxScale );
2166 }
2167
2168 if ( vlayer )
2169 {
2170 if ( !vlayer->writeSld( layerNode, myDocument, errorMsg, props ) )
2171 {
2172 errorMsg = tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
2173 return;
2174 }
2175 }
2176
2177 if ( rlayer )
2178 {
2179 if ( !rlayer->writeSld( layerNode, myDocument, errorMsg, props ) )
2180 {
2181 errorMsg = tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
2182 return;
2183 }
2184 }
2185
2186 doc = myDocument;
2187}
2188
2189QString QgsMapLayer::saveSldStyle( const QString &uri, bool &resultFlag ) const
2190{
2191 QgsSldExportContext context;
2192 context.setExportFilePath( uri );
2193 return saveSldStyleV2( resultFlag, context );
2194}
2195
2196QString QgsMapLayer::saveSldStyleV2( bool &resultFlag, const QgsSldExportContext &exportContext ) const
2197{
2199
2200 const QgsMapLayer *mlayer = qobject_cast<const QgsMapLayer *>( this );
2201
2202 const QString uri { exportContext.exportFilePath() };
2203
2204 // check if the uri is a file or ends with .sld,
2205 // which indicates that it should become one
2206 QString filename;
2207 if ( mlayer->providerType() == QLatin1String( "ogr" ) )
2208 {
2209 QStringList theURIParts = uri.split( '|' );
2210 filename = theURIParts[0];
2211 }
2212 else if ( mlayer->providerType() == QLatin1String( "gpx" ) )
2213 {
2214 QStringList theURIParts = uri.split( '?' );
2215 filename = theURIParts[0];
2216 }
2217 else if ( mlayer->providerType() == QLatin1String( "delimitedtext" ) )
2218 {
2219 filename = QUrl::fromEncoded( uri.toLatin1() ).toLocalFile();
2220 // toLocalFile() returns an empty string if theURI is a plain Windows-path, e.g. "C:/style.qml"
2221 if ( filename.isEmpty() )
2222 filename = uri;
2223 }
2224 else
2225 {
2226 filename = uri;
2227 }
2228
2229 const QFileInfo myFileInfo( filename );
2230 if ( myFileInfo.exists() || filename.endsWith( QLatin1String( ".sld" ), Qt::CaseInsensitive ) )
2231 {
2232 const QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
2233 if ( !myDirInfo.isWritable() )
2234 {
2235 resultFlag = false;
2236 return tr( "The directory containing your dataset needs to be writable!" );
2237 }
2238
2239 // now construct the file name for our .sld style file
2240 const QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".sld";
2241
2242 QString errorMsg;
2243 QDomDocument myDocument;
2244
2245 QgsSldExportContext context { exportContext };
2246 context.setExportFilePath( myFileName );
2247
2248 mlayer->exportSldStyleV2( myDocument, errorMsg, context );
2249
2250 if ( !errorMsg.isNull() )
2251 {
2252 resultFlag = false;
2253 return errorMsg;
2254 }
2255
2256 QFile myFile( myFileName );
2257 if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
2258 {
2259 QTextStream myFileStream( &myFile );
2260 // save as utf-8 with 2 spaces for indents
2261 myDocument.save( myFileStream, 2 );
2262 myFile.close();
2263 resultFlag = true;
2264 return tr( "Created default style file as %1" ).arg( myFileName );
2265 }
2266 }
2267
2268 resultFlag = false;
2269 return tr( "ERROR: Failed to created SLD style file as %1. Check file permissions and retry." ).arg( filename );
2270
2271}
2272
2273QString QgsMapLayer::loadSldStyle( const QString &uri, bool &resultFlag )
2274{
2276
2277 resultFlag = false;
2278
2279 QDomDocument myDocument;
2280
2281 // location of problem associated with errorMsg
2282 int line, column;
2283 QString myErrorMessage;
2284
2285 QFile myFile( uri );
2286 if ( myFile.open( QFile::ReadOnly ) )
2287 {
2288 // read file
2289 resultFlag = myDocument.setContent( &myFile, true, &myErrorMessage, &line, &column );
2290 if ( !resultFlag )
2291 myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
2292 myFile.close();
2293 }
2294 else
2295 {
2296 myErrorMessage = tr( "Unable to open file %1" ).arg( uri );
2297 }
2298
2299 if ( !resultFlag )
2300 {
2301 return myErrorMessage;
2302 }
2303
2304 // check for root SLD element
2305 const QDomElement myRoot = myDocument.firstChildElement( QStringLiteral( "StyledLayerDescriptor" ) );
2306 if ( myRoot.isNull() )
2307 {
2308 myErrorMessage = QStringLiteral( "Error: StyledLayerDescriptor element not found in %1" ).arg( uri );
2309 resultFlag = false;
2310 return myErrorMessage;
2311 }
2312
2313 // now get the style node out and pass it over to the layer
2314 // to deserialise...
2315 const QDomElement namedLayerElem = myRoot.firstChildElement( QStringLiteral( "NamedLayer" ) );
2316 if ( namedLayerElem.isNull() )
2317 {
2318 myErrorMessage = QStringLiteral( "Info: NamedLayer element not found." );
2319 resultFlag = false;
2320 return myErrorMessage;
2321 }
2322
2323 QString errorMsg;
2324 resultFlag = readSld( namedLayerElem, errorMsg );
2325 if ( !resultFlag )
2326 {
2327 myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( uri, errorMsg );
2328 return myErrorMessage;
2329 }
2330
2331 return QString();
2332}
2333
2334bool QgsMapLayer::readStyle( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
2335{
2337
2338 Q_UNUSED( node )
2339 Q_UNUSED( errorMessage )
2340 Q_UNUSED( context )
2341 Q_UNUSED( categories )
2342 return false;
2343}
2344
2345bool QgsMapLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage,
2346 const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
2347{
2349
2350 Q_UNUSED( node )
2351 Q_UNUSED( doc )
2352 Q_UNUSED( errorMessage )
2353 Q_UNUSED( context )
2354 Q_UNUSED( categories )
2355 return false;
2356}
2357
2358
2359void QgsMapLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider,
2360 bool loadDefaultStyleFlag )
2361{
2363
2365
2367 if ( loadDefaultStyleFlag )
2368 {
2370 }
2371
2373 {
2375 }
2376 setDataSource( dataSource,
2377 baseName.isEmpty() ? mLayerName : baseName,
2378 provider.isEmpty() ? mProviderKey : provider,
2379 options, flags );
2380}
2381
2382void QgsMapLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider,
2383 const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag )
2384{
2386
2388 if ( loadDefaultStyleFlag )
2389 {
2391 }
2392
2394 {
2396 }
2397 setDataSource( dataSource, baseName, provider, options, flags );
2398}
2399
2400void QgsMapLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider,
2402{
2404
2407 {
2409 }
2410 setDataSourcePrivate( dataSource, baseName, provider, options, flags );
2411 emit dataSourceChanged();
2412 emit dataChanged();
2414}
2415
2416
2417void QgsMapLayer::setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider,
2419{
2421
2422 Q_UNUSED( dataSource )
2423 Q_UNUSED( baseName )
2424 Q_UNUSED( provider )
2425 Q_UNUSED( options )
2426 Q_UNUSED( flags )
2427}
2428
2429
2431{
2433
2434 return mProviderKey;
2435}
2436
2437void QgsMapLayer::readCommonStyle( const QDomElement &layerElement, const QgsReadWriteContext &context,
2438 QgsMapLayer::StyleCategories categories )
2439{
2441
2442 if ( categories.testFlag( Symbology3D ) )
2443 {
2444 const QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "3D Symbology" ) );
2445
2446 QgsAbstract3DRenderer *r3D = nullptr;
2447 QDomElement renderer3DElem = layerElement.firstChildElement( QStringLiteral( "renderer-3d" ) );
2448 if ( !renderer3DElem.isNull() )
2449 {
2450 const QString type3D = renderer3DElem.attribute( QStringLiteral( "type" ) );
2452 if ( meta3D )
2453 {
2454 r3D = meta3D->createRenderer( renderer3DElem, context );
2455 }
2456 }
2457 setRenderer3D( r3D );
2458 }
2459
2460 if ( categories.testFlag( CustomProperties ) )
2461 {
2462 // read custom properties before passing reading further to a subclass, so that
2463 // the subclass can also read custom properties
2464 readCustomProperties( layerElement );
2465 }
2466
2467 // use scale dependent visibility flag
2468 if ( categories.testFlag( Rendering ) )
2469 {
2470 setScaleBasedVisibility( layerElement.attribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ) ).toInt() == 1 );
2471 if ( layerElement.hasAttribute( QStringLiteral( "minimumScale" ) ) )
2472 {
2473 // older element, when scales were reversed
2474 setMaximumScale( layerElement.attribute( QStringLiteral( "minimumScale" ) ).toDouble() );
2475 setMinimumScale( layerElement.attribute( QStringLiteral( "maximumScale" ) ).toDouble() );
2476 }
2477 else
2478 {
2479 setMaximumScale( layerElement.attribute( QStringLiteral( "maxScale" ) ).toDouble() );
2480 setMinimumScale( layerElement.attribute( QStringLiteral( "minScale" ) ).toDouble() );
2481 }
2482 if ( layerElement.hasAttribute( QStringLiteral( "autoRefreshMode" ) ) )
2483 {
2484 setAutoRefreshMode( qgsEnumKeyToValue( layerElement.attribute( QStringLiteral( "autoRefreshMode" ) ), Qgis::AutoRefreshMode::Disabled ) );
2485 setAutoRefreshInterval( layerElement.attribute( QStringLiteral( "autoRefreshTime" ) ).toInt() );
2486 }
2487 }
2488
2489 if ( categories.testFlag( LayerConfiguration ) )
2490 {
2491 // flags
2492 const QDomElement flagsElem = layerElement.firstChildElement( QStringLiteral( "flags" ) );
2493 LayerFlags flags = mFlags;
2494 const auto enumMap = qgsEnumMap<QgsMapLayer::LayerFlag>();
2495 for ( auto it = enumMap.constBegin(); it != enumMap.constEnd(); ++it )
2496 {
2497 const QDomNode flagNode = flagsElem.namedItem( it.value() );
2498 if ( flagNode.isNull() )
2499 continue;
2500 const bool flagValue = flagNode.toElement().text() == "1" ? true : false;
2501 if ( flags.testFlag( it.key() ) && !flagValue )
2502 flags &= ~it.key();
2503 else if ( !flags.testFlag( it.key() ) && flagValue )
2504 flags |= it.key();
2505 }
2506 setFlags( flags );
2507 }
2508
2509 if ( categories.testFlag( Temporal ) )
2510 {
2511 const QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Temporal" ) );
2512
2514 properties->readXml( layerElement.toElement(), context );
2515 }
2516
2517 if ( categories.testFlag( Elevation ) )
2518 {
2519 const QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Elevation" ) );
2520
2522 properties->readXml( layerElement.toElement(), context );
2523 }
2524
2525 if ( categories.testFlag( Notes ) )
2526 {
2527 const QDomElement notesElem = layerElement.firstChildElement( QStringLiteral( "userNotes" ) );
2528 if ( !notesElem.isNull() )
2529 {
2530 const QString notes = notesElem.attribute( QStringLiteral( "value" ) );
2531 QgsLayerNotesUtils::setLayerNotes( this, notes );
2532 }
2533 }
2534}
2535
2537{
2539
2540 return mUndoStack;
2541}
2542
2544{
2546
2547 return mUndoStackStyles;
2548}
2549
2551{
2553
2554 return mCustomProperties.keys();
2555}
2556
2557void QgsMapLayer::setCustomProperty( const QString &key, const QVariant &value )
2558{
2560
2561 if ( !mCustomProperties.contains( key ) || mCustomProperties.value( key ) != value )
2562 {
2563 mCustomProperties.setValue( key, value );
2564 emit customPropertyChanged( key );
2565 }
2566}
2567
2569{
2571
2572 mCustomProperties = properties;
2573 for ( const QString &key : mCustomProperties.keys() )
2574 {
2575 emit customPropertyChanged( key );
2576 }
2577}
2578
2580{
2582
2583 return mCustomProperties;
2584}
2585
2586QVariant QgsMapLayer::customProperty( const QString &value, const QVariant &defaultValue ) const
2587{
2588 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
2590
2591 return mCustomProperties.value( value, defaultValue );
2592}
2593
2594void QgsMapLayer::removeCustomProperty( const QString &key )
2595{
2597
2598 if ( mCustomProperties.contains( key ) )
2599 {
2600 mCustomProperties.remove( key );
2601 emit customPropertyChanged( key );
2602 }
2603}
2604
2605int QgsMapLayer::listStylesInDatabase( QStringList &ids, QStringList &names, QStringList &descriptions, QString &msgError )
2606{
2608
2609 return QgsProviderRegistry::instance()->listStyles( mProviderKey, mDataSource, ids, names, descriptions, msgError );
2610}
2611
2612QString QgsMapLayer::getStyleFromDatabase( const QString &styleId, QString &msgError )
2613{
2615
2616 return QgsProviderRegistry::instance()->getStyleById( mProviderKey, mDataSource, styleId, msgError );
2617}
2618
2619bool QgsMapLayer::deleteStyleFromDatabase( const QString &styleId, QString &msgError )
2620{
2622
2624}
2625
2626void QgsMapLayer::saveStyleToDatabase( const QString &name, const QString &description,
2627 bool useAsDefault, const QString &uiFileContent, QString &msgError, QgsMapLayer::StyleCategories categories )
2628{
2630
2631 QString sldStyle, qmlStyle;
2632 QDomDocument qmlDocument, sldDocument;
2633 QgsReadWriteContext context;
2634 exportNamedStyle( qmlDocument, msgError, context, categories );
2635 if ( !msgError.isNull() )
2636 {
2637 return;
2638 }
2639 qmlStyle = qmlDocument.toString();
2640
2641 this->exportSldStyle( sldDocument, msgError );
2642 if ( !msgError.isNull() )
2643 {
2644 return;
2645 }
2646 sldStyle = sldDocument.toString();
2647
2649 mDataSource, qmlStyle, sldStyle, name,
2650 description, uiFileContent, useAsDefault, msgError );
2651}
2652
2653QString QgsMapLayer::loadNamedStyle( const QString &theURI, bool &resultFlag, bool loadFromLocalDB, QgsMapLayer::StyleCategories categories, Qgis::LoadStyleFlags flags )
2654{
2656
2657 QString returnMessage;
2658 QString qml, errorMsg;
2659 QString styleName;
2660 if ( !loadFromLocalDB && dataProvider() && dataProvider()->styleStorageCapabilities().testFlag( Qgis::ProviderStyleStorageCapability::LoadFromDatabase ) )
2661 {
2663 }
2664
2665 // Style was successfully loaded from provider storage
2666 if ( !qml.isEmpty() )
2667 {
2668 QDomDocument myDocument( QStringLiteral( "qgis" ) );
2669 myDocument.setContent( qml );
2670 resultFlag = importNamedStyle( myDocument, errorMsg );
2671 returnMessage = QObject::tr( "Loaded from Provider" );
2672 }
2673 else
2674 {
2676
2677 bool styleExists = false;
2678 bool styleSuccessfullyLoaded = false;
2679
2680 returnMessage = loadNamedProperty( theURI, PropertyType::Style, styleExists, styleSuccessfullyLoaded, categories, flags );
2681
2682 // TODO QGIS 4.0 -- fix API for loadNamedStyle so we can return styleExists too
2683 ( void )styleExists;
2684 resultFlag = styleSuccessfullyLoaded;
2685 }
2686
2687 if ( ! styleName.isEmpty() )
2688 {
2689 styleManager()->renameStyle( styleManager()->currentStyle(), styleName );
2690 }
2691
2692 if ( resultFlag )
2693 emit styleLoaded( categories );
2694
2695 return returnMessage;
2696}
2697
2704
2706{
2708
2709 return false;
2710}
2711
2713{
2715
2716 return false;
2717}
2718
2720{
2722
2723 return true;
2724}
2725
2727{
2729
2730 // invalid layers are temporary? -- who knows?!
2731 if ( !isValid() )
2732 return false;
2733
2734 if ( mProviderKey == QLatin1String( "memory" ) )
2735 return true;
2736
2737 const QVariantMap sourceParts = QgsProviderRegistry::instance()->decodeUri( mProviderKey, mDataSource );
2738 const QString path = sourceParts.value( QStringLiteral( "path" ) ).toString();
2739 if ( path.isEmpty() )
2740 return false;
2741
2742 // check if layer path is inside one of the standard temporary file locations for this platform
2743 const QStringList tempPaths = QStandardPaths::standardLocations( QStandardPaths::TempLocation );
2744 for ( const QString &tempPath : tempPaths )
2745 {
2746 if ( path.startsWith( tempPath ) )
2747 return true;
2748 }
2749
2750 return false;
2751}
2752
2753void QgsMapLayer::setValid( bool valid )
2754{
2756
2757 if ( mValid == valid )
2758 return;
2759
2760 mValid = valid;
2761 emit isValidChanged();
2762}
2763
2765{
2767
2768 if ( legend == mLegend )
2769 return;
2770
2771 delete mLegend;
2772 mLegend = legend;
2773
2774 if ( mLegend )
2775 {
2776 mLegend->setParent( this );
2777 connect( mLegend, &QgsMapLayerLegend::itemsChanged, this, &QgsMapLayer::legendChanged, Qt::UniqueConnection );
2778 }
2779
2780 emit legendChanged();
2781}
2782
2784{
2786
2787 return mLegend;
2788}
2789
2791{
2793
2794 return mStyleManager;
2795}
2796
2798{
2800
2801 if ( renderer == m3DRenderer )
2802 return;
2803
2804 delete m3DRenderer;
2805 m3DRenderer = renderer;
2806 emit renderer3DChanged();
2807 emit repaintRequested();
2809}
2810
2812{
2814
2815 return m3DRenderer;
2816}
2817
2818void QgsMapLayer::triggerRepaint( bool deferredUpdate )
2819{
2821
2822 if ( mRepaintRequestedFired )
2823 return;
2824 mRepaintRequestedFired = true;
2825 emit repaintRequested( deferredUpdate );
2826 mRepaintRequestedFired = false;
2827}
2828
2835
2837{
2839
2840 mMetadata = metadata;
2841// mMetadata.saveToLayer( this );
2842 emit metadataChanged();
2843}
2844
2846{
2848
2849 return QString();
2850}
2851
2852QDateTime QgsMapLayer::timestamp() const
2853{
2855
2856 return QDateTime();
2857}
2858
2866
2868{
2869 updateExtent( extent );
2870}
2871
2873{
2875
2876 updateExtent( extent );
2877}
2878
2879bool QgsMapLayer::isReadOnly() const
2880{
2882
2883 return true;
2884}
2885
2887{
2889
2890 return mOriginalXmlProperties;
2891}
2892
2893void QgsMapLayer::setOriginalXmlProperties( const QString &originalXmlProperties )
2894{
2896
2897 mOriginalXmlProperties = originalXmlProperties;
2898}
2899
2900QString QgsMapLayer::generateId( const QString &layerName )
2901{
2902 // Generate the unique ID of this layer
2903 const QString uuid = QUuid::createUuid().toString();
2904 // trim { } from uuid
2905 QString id = layerName + '_' + uuid.mid( 1, uuid.length() - 2 );
2906 // Tidy the ID up to avoid characters that may cause problems
2907 // elsewhere (e.g in some parts of XML). Replaces every non-word
2908 // character (word characters are the alphabet, numbers and
2909 // underscore) with an underscore.
2910 // Note that the first backslash in the regular expression is
2911 // there for the compiler, so the pattern is actually \W
2912 const thread_local QRegularExpression idRx( QStringLiteral( "[\\W]" ) );
2913 id.replace( idRx, QStringLiteral( "_" ) );
2914 return id;
2915}
2916
2918{
2920
2921 return true;
2922}
2923
2925{
2927
2928 return mapTipsEnabled() && !mMapTipTemplate.isEmpty();
2929}
2930
2931void QgsMapLayer::setProviderType( const QString &providerType )
2932{
2934
2936}
2937
2938QSet<QgsMapLayerDependency> QgsMapLayer::dependencies() const
2939{
2941
2942 return mDependencies;
2943}
2944
2945bool QgsMapLayer::setDependencies( const QSet<QgsMapLayerDependency> &oDeps )
2946{
2948
2949 QSet<QgsMapLayerDependency> deps;
2950 const auto constODeps = oDeps;
2951 for ( const QgsMapLayerDependency &dep : constODeps )
2952 {
2953 if ( dep.origin() == QgsMapLayerDependency::FromUser )
2954 deps << dep;
2955 }
2956
2957 mDependencies = deps;
2958 emit dependenciesChanged();
2959 return true;
2960}
2961
2963{
2965
2966 QgsDataProvider *lDataProvider = dataProvider();
2967
2968 if ( !lDataProvider )
2969 return;
2970
2971 if ( enabled && !isRefreshOnNotifyEnabled() )
2972 {
2973 lDataProvider->setListening( enabled );
2974 connect( lDataProvider, &QgsDataProvider::notify, this, &QgsMapLayer::onNotified );
2975 }
2976 else if ( !enabled && isRefreshOnNotifyEnabled() )
2977 {
2978 // we don't want to disable provider listening because someone else could need it (e.g. actions)
2979 disconnect( lDataProvider, &QgsDataProvider::notify, this, &QgsMapLayer::onNotified );
2980 }
2981 mIsRefreshOnNofifyEnabled = enabled;
2982}
2983
2985{
2987
2988 if ( QgsMapLayerStore *store = qobject_cast<QgsMapLayerStore *>( parent() ) )
2989 {
2990 return qobject_cast<QgsProject *>( store->parent() );
2991 }
2992 return nullptr;
2993}
2994
2995void QgsMapLayer::onNotified( const QString &message )
2996{
2998
2999 if ( refreshOnNotifyMessage().isEmpty() || refreshOnNotifyMessage() == message )
3000 {
3002 emit dataChanged();
3003 }
3004}
3005
3006QgsRectangle QgsMapLayer::wgs84Extent( bool forceRecalculate ) const
3007{
3009
3011
3012 if ( ! forceRecalculate && ! mWgs84Extent.isNull() )
3013 {
3014 wgs84Extent = mWgs84Extent;
3015 }
3016 else if ( ! mExtent2D.isNull() || ! mExtent3D.isNull() )
3017 {
3019 transformer.setBallparkTransformsAreAppropriate( true );
3020 try
3021 {
3022 if ( mExtent2D.isNull() )
3023 wgs84Extent = transformer.transformBoundingBox( mExtent3D.toRectangle() );
3024 else
3025 wgs84Extent = transformer.transformBoundingBox( mExtent2D );
3026 }
3027 catch ( const QgsCsException &cse )
3028 {
3029 QgsMessageLog::logMessage( tr( "Error transforming extent: %1" ).arg( cse.what() ) );
3031 }
3032 }
3033 return wgs84Extent;
3034}
3035
3036void QgsMapLayer::updateExtent( const QgsRectangle &extent ) const
3037{
3039
3040 if ( extent == mExtent2D )
3041 return;
3042
3043 mExtent2D = extent;
3044
3045 // do not update the wgs84 extent if we trust layer metadata
3047 return;
3048
3049 mWgs84Extent = wgs84Extent( true );
3050}
3051
3052void QgsMapLayer::updateExtent( const QgsBox3D &extent ) const
3053{
3055
3056 if ( extent == mExtent3D )
3057 return;
3058
3059 if ( extent.isNull() )
3060 {
3061 if ( !extent.toRectangle().isNull() )
3062 {
3063 // bad 3D extent param but valid in 2d --> update 2D extent
3064 updateExtent( extent.toRectangle() );
3065 }
3066 else
3067 {
3068 QgsDebugMsgLevel( QStringLiteral( "Unable to update extent with empty parameter" ), 1 );
3069 }
3070 }
3071 else
3072 {
3073 mExtent3D = extent;
3074
3075 // do not update the wgs84 extent if we trust layer metadata
3077 return;
3078
3079 mWgs84Extent = wgs84Extent( true );
3080 }
3081}
3082
3083bool QgsMapLayer::rebuildCrs3D( QString *error )
3084{
3085 bool res = true;
3086 if ( !mCRS.isValid() )
3087 {
3089 }
3090 else if ( !mVerticalCrs.isValid() )
3091 {
3092 mCrs3D = mCRS;
3093 }
3094 else
3095 {
3096 switch ( mCRS.type() )
3097 {
3101 mCrs3D = mCRS;
3102 break;
3103
3105 {
3106 QString tempError;
3107 mCrs3D = mCRS.hasVerticalAxis() ? mCRS : QgsCoordinateReferenceSystem::createCompoundCrs( mCRS, mVerticalCrs, error ? *error : tempError );
3108 res = mCrs3D.isValid();
3109 break;
3110 }
3111
3113 // nonsense situation
3115 res = false;
3116 break;
3117
3126 {
3127 QString tempError;
3128 mCrs3D = QgsCoordinateReferenceSystem::createCompoundCrs( mCRS, mVerticalCrs, error ? *error : tempError );
3129 res = mCrs3D.isValid();
3130 break;
3131 }
3132 }
3133 }
3134 return res;
3135}
3136
3138{
3140
3141 // do not update the wgs84 extent if we trust layer metadata
3143 return;
3144
3145 mWgs84Extent = QgsRectangle();
3146}
3147
3149{
3151
3152 QString metadata = QStringLiteral( "<h1>" ) + tr( "General" ) + QStringLiteral( "</h1>\n<hr>\n" ) + QStringLiteral( "<table class=\"list-view\">\n" );
3153
3154 // name
3155 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Name" ) + QStringLiteral( "</td><td>" ) + name() + QStringLiteral( "</td></tr>\n" );
3156
3157 const QString lPublicSource = publicSource();
3158
3159 QString path;
3160 bool isLocalPath = false;
3161 if ( dataProvider() )
3162 {
3163 // local path
3164 QVariantMap uriComponents = QgsProviderRegistry::instance()->decodeUri( dataProvider()->name(), lPublicSource );
3165 if ( uriComponents.contains( QStringLiteral( "path" ) ) )
3166 {
3167 path = uriComponents[QStringLiteral( "path" )].toString();
3168 QFileInfo fi( path );
3169 if ( fi.exists() )
3170 {
3171 isLocalPath = true;
3172 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" );
3173
3174 QDateTime lastModified = fi.lastModified();
3175 QString lastModifiedFileName;
3176 QSet<QString> sidecarFiles = QgsFileUtils::sidecarFilesForPath( path );
3177 if ( fi.isFile() )
3178 {
3179 qint64 fileSize = fi.size();
3180 if ( !sidecarFiles.isEmpty() )
3181 {
3182 lastModifiedFileName = fi.fileName();
3183 QStringList sidecarFileNames;
3184 for ( const QString &sidecarFile : sidecarFiles )
3185 {
3186 QFileInfo sidecarFi( sidecarFile );
3187 fileSize += sidecarFi.size();
3188 if ( sidecarFi.lastModified() > lastModified )
3189 {
3190 lastModified = sidecarFi.lastModified();
3191 lastModifiedFileName = sidecarFi.fileName();
3192 }
3193 sidecarFileNames << sidecarFi.fileName();
3194 }
3195 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" );
3196 }
3197 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" );
3198 }
3199 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" );
3200 }
3201 }
3202 if ( uriComponents.contains( QStringLiteral( "url" ) ) )
3203 {
3204 const QString url = uriComponents[QStringLiteral( "url" )].toString();
3205 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" );
3206 }
3207 }
3208
3209 // data source
3210 if ( lPublicSource != path || !isLocalPath )
3211 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Source" ) + QStringLiteral( "</td><td>%1" ).arg( lPublicSource != path ? lPublicSource : path ) + QStringLiteral( "</td></tr>\n" );
3212
3213 // provider
3214 if ( dataProvider() )
3215 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Provider" ) + QStringLiteral( "</td><td>%1" ).arg( dataProvider()->name() ) + QStringLiteral( "</td></tr>\n" );
3216
3217 metadata += QLatin1String( "</table>\n<br><br>" );
3218
3219 return metadata;
3220}
3221
3223{
3224 QString metadata;
3225 // custom properties
3226 if ( const auto keys = customPropertyKeys(); !keys.isEmpty() )
3227 {
3228 metadata += QStringLiteral( "<h1>" ) + tr( "Custom properties" ) + QStringLiteral( "</h1>\n<hr>\n" );
3229 metadata += QLatin1String( "<table class=\"list-view\">\n<tbody>" );
3230 for ( const QString &key : keys )
3231 {
3232 // keys prefaced with _ are considered private/internal details
3233 if ( key.startsWith( '_' ) )
3234 continue;
3235
3236 const QVariant propValue = customProperty( key );
3237 QString stringValue;
3238 if ( propValue.type() == QVariant::List || propValue.type() == QVariant::StringList )
3239 {
3240 for ( const QString &s : propValue.toStringList() )
3241 {
3242 stringValue += "<p style=\"margin: 0;\">" + s.toHtmlEscaped() + "</p>";
3243 }
3244 }
3245 else
3246 {
3247 stringValue = propValue.toString().toHtmlEscaped();
3248
3249 //if the result string is empty but propValue is not, the conversion has failed
3250 if ( stringValue.isEmpty() && !QgsVariantUtils::isNull( propValue ) )
3251 stringValue = tr( "<i>value cannot be displayed</i>" );
3252 }
3253
3254 metadata += QStringLiteral( "<tr><td class=\"highlight\">%1</td><td>%2</td></tr>" ).arg( key.toHtmlEscaped(), stringValue );
3255 }
3256 metadata += QLatin1String( "</tbody></table>\n" );
3257 metadata += QLatin1String( "<br><br>\n" );
3258 }
3259 return metadata;
3260}
3261
3263{
3265 QString metadata;
3266
3267 auto addCrsInfo = [&metadata]( const QgsCoordinateReferenceSystem & c, bool includeType, bool includeOperation, bool includeCelestialBody )
3268 {
3269 if ( !c.isValid() )
3270 metadata += QStringLiteral( "<tr><td colspan=\"2\" class=\"highlight\">" ) + tr( "Unknown" ) + QStringLiteral( "</td></tr>\n" );
3271 else
3272 {
3273 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Name" ) + QStringLiteral( "</td><td>" ) + c.userFriendlyIdentifier( Qgis::CrsIdentifierType::FullString ) + QStringLiteral( "</td></tr>\n" );
3274
3275 // map units
3276 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Units" ) + QStringLiteral( "</td><td>" )
3277 + ( c.isGeographic() ? tr( "Geographic (uses latitude and longitude for coordinates)" ) : QgsUnitTypes::toString( c.mapUnits() ) )
3278 + QStringLiteral( "</td></tr>\n" );
3279
3280 if ( includeType )
3281 {
3282 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Type" ) + QStringLiteral( "</td><td>" ) + QgsCoordinateReferenceSystemUtils::crsTypeToString( c.type() ) + QStringLiteral( "</td></tr>\n" );
3283 }
3284
3285 if ( includeOperation )
3286 {
3287 // operation
3288 const QgsProjOperation operation = c.operation();
3289 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Method" ) + QStringLiteral( "</td><td>" ) + operation.description() + QStringLiteral( "</td></tr>\n" );
3290 }
3291
3292 if ( includeCelestialBody )
3293 {
3294 // celestial body
3295 try
3296 {
3297 const QString celestialBody = c.celestialBodyName();
3298 if ( !celestialBody.isEmpty() )
3299 {
3300 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Celestial Body" ) + QStringLiteral( "</td><td>" ) + celestialBody + QStringLiteral( "</td></tr>\n" );
3301 }
3302 }
3303 catch ( QgsNotSupportedException & )
3304 {
3305
3306 }
3307 }
3308
3309 QString accuracyString;
3310 // dynamic crs with no epoch?
3311 if ( c.isDynamic() && std::isnan( c.coordinateEpoch() ) )
3312 {
3313 accuracyString = tr( "Based on a dynamic CRS, but no coordinate epoch is set. Coordinates are ambiguous and of limited accuracy." );
3314 }
3315
3316 // based on datum ensemble?
3317 try
3318 {
3319 const QgsDatumEnsemble ensemble = c.datumEnsemble();
3320 if ( ensemble.isValid() )
3321 {
3322 QString id;
3323 if ( !ensemble.code().isEmpty() )
3324 id = QStringLiteral( "<i>%1</i> (%2:%3)" ).arg( ensemble.name(), ensemble.authority(), ensemble.code() );
3325 else
3326 id = QStringLiteral( "<i>%</i>”" ).arg( ensemble.name() );
3327
3328 if ( ensemble.accuracy() > 0 )
3329 {
3330 accuracyString = tr( "Based on %1, which has a limited accuracy of <b>at best %2 meters</b>." ).arg( id ).arg( ensemble.accuracy() );
3331 }
3332 else
3333 {
3334 accuracyString = tr( "Based on %1, which has a limited accuracy." ).arg( id );
3335 }
3336 }
3337 }
3338 catch ( QgsNotSupportedException & )
3339 {
3340
3341 }
3342
3343 if ( !accuracyString.isEmpty() )
3344 {
3345 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Accuracy" ) + QStringLiteral( "</td><td>" ) + accuracyString + QStringLiteral( "</td></tr>\n" );
3346 }
3347
3348 // static/dynamic
3349 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)" ) );
3350
3351 // coordinate epoch
3352 if ( !std::isnan( c.coordinateEpoch() ) )
3353 {
3354 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Coordinate Epoch" ) + QStringLiteral( "</td><td>%1</td></tr>\n" ).arg( qgsDoubleToString( c.coordinateEpoch(), 3 ) );
3355 }
3356 }
3357 };
3358
3359 metadata += QStringLiteral( "<h1>" ) + tr( "Coordinate Reference System (CRS)" ) + QStringLiteral( "</h1>\n<hr>\n" );
3360 metadata += QLatin1String( "<table class=\"list-view\">\n" );
3361 addCrsInfo( crs().horizontalCrs(), true, true, true );
3362 metadata += QLatin1String( "</table>\n<br><br>\n" );
3363
3364 if ( verticalCrs().isValid() )
3365 {
3366 metadata += QStringLiteral( "<h1>" ) + tr( "Vertical Coordinate Reference System (CRS)" ) + QStringLiteral( "</h1>\n<hr>\n" );
3367 metadata += QLatin1String( "<table class=\"list-view\">\n" );
3368 addCrsInfo( verticalCrs(), false, false, false );
3369 metadata += QLatin1String( "</table>\n<br><br>\n" );
3370 }
3371
3372 return metadata;
3373}
static QString version()
Version string.
Definition qgis.cpp:259
@ FullString
Full definition – possibly a very lengthy string, e.g. with no truncation of custom WKT definitions.
@ Vertical
Vertical CRS.
@ Temporal
Temporal CRS.
@ Compound
Compound (horizontal + vertical) CRS.
@ Projected
Projected CRS.
@ Other
Other type.
@ Bound
Bound CRS.
@ DerivedProjected
Derived projected CRS.
@ Unknown
Unknown type.
@ Engineering
Engineering CRS.
@ Geographic3d
3D geopraphic CRS
@ Geodetic
Geodetic CRS.
@ Geographic2d
2D geographic CRS
@ Geocentric
Geocentric CRS.
@ RemoveCredentials
Completely remove credentials (eg passwords) from the URI. This flag is not compatible with the Redac...
@ RedactCredentials
Replace the value of credentials (eg passwords) with 'xxxxxxxx'. This flag is not compatible with the...
@ 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:337
@ Unknown
Unknown types.
QFlags< DataProviderReadFlag > DataProviderReadFlags
Flags which control data provider construction.
Definition qgis.h:450
LayerType
Types of layers that can be added to a map.
Definition qgis.h:169
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ Vector
Vector layer.
QFlags< MapLayerProperty > MapLayerProperties
Map layer properties.
Definition qgis.h:2234
QFlags< LoadStyleFlag > LoadStyleFlags
Flags for loading layer styles.
Definition qgis.h:225
@ LoadDefaultStyle
Reset the layer's style to the default for the datasource.
@ ForceReadOnly
Open layer in a read-only mode.
@ SkipGetExtent
Skip the extent from provider.
@ TrustDataSource
Trust datasource config (primary key unicity, geometry type and srid, etc). Improves provider load ti...
@ IgnoreMissingStyleErrors
If the style is missing, then don't flag it as an error. This flag can be used when the caller is not...
AutoRefreshMode
Map layer automatic refresh modes.
Definition qgis.h:2244
@ RedrawOnly
Redraw current data only.
@ ReloadData
Reload data (and draw the new data)
@ Disabled
Automatic refreshing is disabled.
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.
A 3-dimensional box composed of x, y, z coordinates.
Definition qgsbox3d.h:43
QgsRectangle toRectangle() const
Converts the box to a 2D rectangle.
Definition qgsbox3d.h:379
bool isNull() const
Test if the box is null (holding no spatial information).
Definition qgsbox3d.cpp:310
static QString crsTypeToString(Qgis::CrsType type)
Returns a translated string representing a CRS type.
This class represents a coordinate reference system (CRS).
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
bool hasVerticalAxis() const
Returns true if the CRS has a vertical axis.
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 QgsCoordinateReferenceSystem createCompoundCrs(const QgsCoordinateReferenceSystem &horizontalCrs, const QgsCoordinateReferenceSystem &verticalCrs, QString &error)
Given a horizontal and vertical CRS, attempts to create a compound CRS from them.
static void setCustomCrsValidation(CUSTOM_CRS_VALIDATION f)
Sets custom function to force valid CRS.
void setValidationHint(const QString &html)
Set user hint for validation.
QgsCoordinateReferenceSystem verticalCrs() const
Returns the vertical CRS associated with this CRS object.
bool writeXml(QDomNode &node, QDomDocument &doc) const
Stores state to the given Dom node in the given document.
Qgis::CrsType type() const
Returns the type of the CRS.
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.
virtual bool containsElevationData() const
Returns true if the data provider definitely contains elevation related data.
Abstract base class for spatial data provider implementations.
void notify(const QString &msg)
Emitted when the datasource issues a notification.
virtual QgsDataProviderElevationProperties * elevationProperties()
Returns the provider's elevation properties.
static QString removePassword(const QString &aUri, bool hide=false)
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
A container for error messages.
Definition qgserror.h:81
QString what() const
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.
void writeXml(QDomNode &layer_node, QDomDocument &document) const
Saves server properties to xml under the layer node.
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.
bool renameStyle(const QString &name, const QString &newName)
Rename a stored style to a different name.
QgsMapLayerStyle style(const QString &name) const
Returns data of a stored style - accessed by its unique name.
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:76
void crs3DChanged()
Emitted when the crs3D() of the layer has changed.
Q_DECL_DEPRECATED void setShortName(const QString &shortName)
Sets the short name of the layer used by QGIS Server to identify the layer.
virtual bool deleteStyleFromDatabase(const QString &styleId, QString &msgError)
Deletes a style from the database.
bool importNamedMetadata(QDomDocument &document, QString &errorMessage)
Import the metadata of this layer from a QDomDocument.
QString name
Definition qgsmaplayer.h:80
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.
Q_DECL_DEPRECATED QString legendUrlFormat() const
Returns the format for a URL based layer legend.
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.
bool setId(const QString &id)
Sets the layer's id.
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.
QFlags< ReadFlag > ReadFlags
QFlags< LayerFlag > LayerFlags
virtual bool importNamedStyle(QDomDocument &doc, QString &errorMsg, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories)
Import the properties of this layer from a QDomDocument.
Q_DECL_DEPRECATED void setAbstract(const QString &abstract)
Sets the abstract of the layer used by QGIS Server in GetCapabilities request.
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.
Q_DECL_DEPRECATED void setLegendUrl(const QString &legendUrl)
Sets the URL for the layer's legend.
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.
int mBlockStyleChangedSignal
If non-zero, the styleChanged signal should not be emitted.
QString providerType() const
Returns the provider type (provider key) for this layer.
virtual void setExtent3D(const QgsBox3D &box)
Sets the extent.
void removeCustomProperty(const QString &key)
Remove a custom property from layer.
Qgis::AutoRefreshMode autoRefreshMode() const
Returns the layer's automatic refresh mode.
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.
static Qgis::DataProviderReadFlags providerReadFlags(const QDomNode &layerNode, QgsMapLayer::ReadFlags layerReadFlags)
Returns provider read flag deduced from layer read flags layerReadFlags and a dom node layerNode that...
virtual QString loadNamedStyle(const QString &theURI, bool &resultFlag, bool loadFromLocalDb, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories, Qgis::LoadStyleFlags flags=Qgis::LoadStyleFlags())
Loads a named style from file/local db/datasource db.
virtual QString encodedSource(const QString &source, const QgsReadWriteContext &context) const
Called by writeLayerXML(), used by derived classes to encode provider's specific data source to proje...
QgsMapLayer::LayerFlags flags() const
Returns the flags for this layer.
QgsCoordinateReferenceSystem crs3D
Definition qgsmaplayer.h:85
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:83
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.
Q_DECL_DEPRECATED QString attribution() const
Returns the attribution of the layer used by QGIS Server in GetCapabilities request.
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
virtual int listStylesInDatabase(QStringList &ids, QStringList &names, QStringList &descriptions, QString &msgError)
Lists all the style in db split into related to the layer and not related to.
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...
void setDataSource(const QString &dataSource, const QString &baseName=QString(), const QString &provider=QString(), bool loadDefaultStyleFlag=false)
Updates the data source of the layer.
QString mLayerName
Name of the layer - used for display.
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.
Q_DECL_DEPRECATED bool hasAutoRefreshEnabled() const
Returns true if auto refresh is enabled for the layer.
QString id
Definition qgsmaplayer.h:79
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.
Q_DECL_DEPRECATED void setAttributionUrl(const QString &attribUrl)
Sets the attribution URL of the layer used by QGIS Server in GetCapabilities request.
Q_DECL_DEPRECATED 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:82
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.
Q_DECL_DEPRECATED QString abstract() const
Returns the abstract of the layer used by QGIS Server in GetCapabilities request.
QgsMapLayer(Qgis::LayerType type=Qgis::LayerType::Vector, const QString &name=QString(), const QString &source=QString())
Constructor for QgsMapLayer.
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:86
Q_DECL_DEPRECATED QString dataUrlFormat() const
Returns the DataUrl format of the layer used by QGIS Server in GetCapabilities request.
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
Q_DECL_DEPRECATED void setDataUrl(const QString &dataUrl)
Sets the DataUrl of the layer used by QGIS Server in GetCapabilities request.
virtual void setOpacity(double opacity)
Sets the opacity for the layer, where opacity is a value between 0 (totally transparent) and 1....
Q_DECL_DEPRECATED void setKeywordList(const QString &keywords)
Sets the keyword list of the layerused by QGIS Server in GetCapabilities request.
Q_DECL_DEPRECATED void setAttribution(const QString &attrib)
Sets the attribution of the layerused by QGIS Server in GetCapabilities request.
void setFlags(QgsMapLayer::LayerFlags flags)
Returns the flags for this layer.
bool isRefreshOnNotifyEnabled() const
Returns true if the refresh on provider nofification is enabled.
QString publicSource(bool hidePassword=false) const
Gets a version of the internal layer definition that has sensitive bits removed (for example,...
Q_DECL_DEPRECATED 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.
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.
Q_DECL_DEPRECATED void setDataUrlFormat(const QString &dataUrlFormat)
Sets the DataUrl format of the layer used by QGIS Server in GetCapabilities request.
QFlags< StyleCategory > StyleCategories
virtual void saveStyleToDatabase(const QString &name, const QString &description, bool useAsDefault, const QString &uiFileContent, QString &msgError, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories)
Saves named and sld style of the layer to the style table in the db.
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)
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.
Q_DECL_DEPRECATED QString title() const
Returns the title of the layer used by QGIS Server in GetCapabilities request.
void crsChanged()
Emitted when the crs() of the layer has changed.
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...
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.
void idChanged(const QString &id)
Emitted when the layer's ID has been changed.
Q_DECL_DEPRECATED QString dataUrl() const
Returns the DataUrl of the layer used by QGIS Server in GetCapabilities request.
bool hasScaleBasedVisibility() const
Returns whether scale based visibility is enabled for the layer.
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,...
static QString generateId(const QString &layerName)
Generates an unique identifier for this layer, the generate ID is prefixed by layerName.
QgsProviderMetadata * providerMetadata() const
Returns the layer data provider's metadata, it may be nullptr.
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 styleLoaded(QgsMapLayer::StyleCategories categories)
Emitted when a style has been loaded.
virtual QString getStyleFromDatabase(const QString &styleId, QString &msgError)
Returns the named style corresponding to style id provided.
void emitStyleChanged()
Triggers an emission of the styleChanged() signal.
virtual QgsMapLayerTemporalProperties * temporalProperties()
Returns the layer's temporal properties.
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.
void verticalCrsChanged()
Emitted when the verticalCrs() of the layer has changed.
virtual QgsBox3D extent3D() const
Returns the 3D extent of the layer.
static QString extensionPropertyType(PropertyType type)
Returns the extension of a Property.
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...
QString mDataSource
Data source description string, varies by layer type.
void setAutoRefreshMode(Qgis::AutoRefreshMode mode)
Sets the automatic refresh mode for the layer.
QString refreshOnNotifyMessage() const
Returns the message that should be notified by the provider to triggerRepaint.
virtual bool readSld(const QDomNode &node, QString &errorMessage)
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.
@ FlagTrustLayerMetadata
Trust layer metadata. Improves layer load time by skipping expensive checks like primary key unicity,...
@ FlagForceReadOnly
Force open as read only.
void setValid(bool valid)
Sets whether layer is valid or not.
Q_DECL_DEPRECATED QString attributionUrl() const
Returns the attribution URL of the layer used by QGIS Server in GetCapabilities request.
void readCommonStyle(const QDomElement &layerElement, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories)
Read style data common to all layer types.
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.
double minimumScale() const
Returns the minimum map scale (i.e.
QgsMapLayerStyleManager * styleManager() const
Gets access to the layer's style manager.
Q_DECL_DEPRECATED QString legendUrl() const
Returns the URL for the layer's legend.
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...
Q_DECL_DEPRECATED void setLegendUrlFormat(const QString &legendUrlFormat)
Sets the format for a URL based layer legend.
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.
bool setVerticalCrs(const QgsCoordinateReferenceSystem &crs, QString *errorMessage=nullptr)
Sets the layer's vertical coordinate reference system.
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:90
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:88
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:81
QgsCoordinateReferenceSystem verticalCrs
Definition qgsmaplayer.h:84
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
virtual Q_INVOKABLE QgsDataProvider * dataProvider()
Returns the layer's data provider, it may be nullptr.
double mLayerOpacity
Layer opacity.
bool mValid
Indicates if the layer is valid and can be drawn.
@ LayerConfiguration
General configuration: identifiable, removable, searchable, display expression, read-only.
@ Symbology
Symbology.
@ Notes
Layer user notes.
@ Temporal
Temporal properties.
@ Rendering
Rendering: scale visibility, simplify method, opacity.
@ Elevation
Elevation settings.
@ Symbology3D
3D symbology
@ CustomProperties
Custom properties (by plugins for instance)
virtual Q_INVOKABLE void reload()
Synchronises with changes in the datasource.
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.
~QgsMapLayer() override
QString customPropertyHtmlMetadata() const
Returns an HTML fragment containing custom property information, for use in the htmlMetadata() method...
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.
Q_DECL_DEPRECATED QString keywordList() const
Returns the keyword list of the layer used by QGIS Server in GetCapabilities request.
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:89
Q_DECL_DEPRECATED void setTitle(const QString &title)
Sets the title of the layer used by QGIS Server in GetCapabilities request.
PropertyType
Maplayer has a style and a metadata property.
bool mShouldValidateCrs
true if the layer's CRS should be validated and invalid CRSes are not permitted.
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
Custom exception class which is raised when an operation is not supported.
Simple key-value store (keys = strings, values = variants) that supports loading/saving to/from XML i...
void setValue(const QString &key, const QVariant &value)
Add an entry to the store with the specified key.
QStringList keys() const
Returns a list of all stored keys.
void writeXml(QDomNode &parentNode, QDomDocument &doc) const
Writes the store contents to an XML node.
void remove(const QString &key)
Removes a key (entry) from the store.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
Returns the value for the given key.
void readXml(const QDomNode &parentNode, const QString &keyStartsWith=QString())
Read store contents from an XML node.
bool contains(const QString &key) const
Returns true if the properties contains a key with the specified name.
Contains information about a PROJ operation.
QString description() const
Description.
Class to convert from older project file versions to newer.
bool updateRevision(const QgsProjectVersion &version)
virtual QString translate(const QString &context, const QString &sourceText, const char *disambiguation=nullptr, int n=-1) const =0
Translates a string using the Qt QTranslator mechanism.
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.
QString baseName() const
Returns the base name of the project file without the path and without extension - derived from fileN...
QString absoluteFilePath() const
Returns full absolute path to the project file if the project is stored in a file system - derived fr...
Holds data provider key, description, and associated shared library file or function pointer informat...
@ SaveLayerMetadata
Indicates that the provider supports saving native layer metadata.
QString getStyleById(const QString &providerKey, const QString &uri, const QString &styleId, QString &errCause)
Gets a layer style defined by styleId.
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)
Saves metadata to the layer corresponding to the specified uri.
bool deleteStyleById(const QString &providerKey, const QString &uri, const QString &styleId, QString &errCause)
Deletes a layer style defined by styleId.
QString loadStoredStyle(const QString &providerKey, const QString &uri, QString &styleName, QString &errCause)
Loads a layer style from the provider storage, reporting its name.
QgsProviderMetadata * providerMetadata(const QString &providerKey) const
Returns metadata of the provider or nullptr if not found.
int listStyles(const QString &providerKey, const QString &uri, QStringList &ids, QStringList &names, QStringList &descriptions, QString &errCause)
Lists stored layer styles in the provider defined by providerKey and uri.
bool saveStyle(const QString &providerKey, const QString &uri, const QString &qmlStyle, const QString &sldStyle, const QString &styleName, const QString &styleDescription, const QString &uiFileContent, bool useAsDefault, QString &errCause)
Saves a layer style to provider.
Represents a raster layer.
bool writeSld(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QVariantMap &props=QVariantMap()) const
Writes the symbology of the layer into the document provided in SLD 1.0.0 format.
Allows entering a context category and takes care of leaving this category on deletion of the class.
The class is used as a container of context for various read/write operations on other objects.
MAYBE_UNUSED NODISCARD QgsReadWriteContextCategoryPopper enterCategory(const QString &category, const QString &details=QString()) const
Push a category to the stack.
const QgsProjectTranslator * projectTranslator() const
Returns the project translator.
A rectangle specified with double values.
static bool equalToOrGreaterThanMinimumScale(const double scale, const double minScale)
Returns whether the scale is equal to or greater than the minScale, taking non-round numbers into acc...
static bool lessThanMaximumScale(const double scale, const double maxScale)
Returns whether the scale is less than the maxScale, taking non-round numbers into account.
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.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
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.
static QDomElement writeBox3D(const QgsBox3D &box, QDomDocument &doc, const QString &elementName=QStringLiteral("extent3D"))
Encodes a 3D box to a DOM element.
static QgsBox3D readBox3D(const QDomElement &element)
Decodes a DOM element to a 3D box.
static QDomElement writeRectangle(const QgsRectangle &rect, QDomDocument &doc, const QString &elementName=QStringLiteral("extent"))
Encodes a rectangle to a DOM element.
static QgsRectangle readRectangle(const QDomElement &element)
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
T qgsEnumKeyToValue(const QString &key, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given key of an enum.
Definition qgis.h:6429
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:6136
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:6410
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:6219
CONSTLATIN1STRING geoEpsgCrsAuthId()
Geographic coord sys from EPSG authority.
Definition qgis.h:6708
void(* CUSTOM_CRS_VALIDATION)(QgsCoordinateReferenceSystem &)
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:41
#define QgsDebugError(str)
Definition qgslogger.h:40
#define QGIS_PROTECT_QOBJECT_THREAD_ACCESS_NON_FATAL
#define QGIS_PROTECT_QOBJECT_THREAD_ACCESS
const QgsCoordinateReferenceSystem & crs
Setting options for creating vector data providers.
QString format
Format specification of online resource.