QGIS API Documentation 3.41.0-Master (88383c3d16f)
Loading...
Searching...
No Matches
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->setLegendUrl( legendUrl() );
157 layer->setDependencies( dependencies() );
159 layer->setCrs( crs() );
160 layer->setCustomProperties( mCustomProperties );
161 layer->setOpacity( mLayerOpacity );
162 layer->setMetadata( mMetadata );
163 layer->serverProperties()->copyTo( mServerProperties.get() );
164}
165
167{
168 // because QgsVirtualLayerProvider is not anywhere NEAR thread safe:
170
171 return mLayerType;
172}
173
180
182{
184
185 if ( flags == mFlags )
186 return;
187
188 mFlags = flags;
189 emit flagsChanged();
190}
191
198
199QString QgsMapLayer::id() const
200{
201 // because QgsVirtualLayerProvider is not anywhere NEAR thread safe:
203
204 return mID;
205}
206
207bool QgsMapLayer::setId( const QString &id )
208{
210 if ( qobject_cast< QgsMapLayerStore * >( parent() ) )
211 {
212 // layer is already registered, cannot change id
213 return false;
214 }
215
216 if ( id == mID )
217 return false;
218
219 mID = id;
220 emit idChanged( id );
221 return true;
222}
223
224void QgsMapLayer::setName( const QString &name )
225{
227
228 if ( name == mLayerName )
229 return;
230
232
233 emit nameChanged();
234}
235
236QString QgsMapLayer::name() const
237{
238 // because QgsVirtualLayerProvider is not anywhere NEAR thread safe:
240
241 QgsDebugMsgLevel( "returning name '" + mLayerName + '\'', 4 );
242 return mLayerName;
243}
244
251
253{
255
256 return nullptr;
257}
258
263
264void QgsMapLayer::setShortName( const QString &shortName )
265{
267
268 mServerProperties->setShortName( shortName );
269}
270
272{
274
275 return mServerProperties->shortName();
276}
277
278void QgsMapLayer::setTitle( const QString &title )
279{
281
282 mServerProperties->setTitle( title );
283}
284
285QString QgsMapLayer::title() const
286{
288
289 return mServerProperties->title();
290}
291
292void QgsMapLayer::setAbstract( const QString &abstract )
293{
295
296 mServerProperties->setAbstract( abstract );
297}
298
300{
302
303 return mServerProperties->abstract();
304}
305
306void QgsMapLayer::setKeywordList( const QString &keywords )
307{
309
310 mServerProperties->setKeywordList( keywords );
311}
312
314{
316
317 return mServerProperties->keywordList();
318}
319
320void QgsMapLayer::setDataUrl( const QString &dataUrl )
321{
323
324 mServerProperties->setDataUrl( dataUrl );
325}
326
327QString QgsMapLayer::dataUrl() const
328{
330
331 return mServerProperties->dataUrl();
332}
333
334void QgsMapLayer::setDataUrlFormat( const QString &dataUrlFormat )
335{
337
338 mServerProperties->setDataUrlFormat( dataUrlFormat );
339}
340
342{
344
345 return mServerProperties->dataUrlFormat();
346}
347
348void QgsMapLayer::setAttribution( const QString &attrib )
349{
351
352 mServerProperties->setAttribution( attrib );
353}
354
356{
358
359 return mServerProperties->attribution();
360}
361
362void QgsMapLayer::setAttributionUrl( const QString &attribUrl )
363{
365
366 mServerProperties->setAttributionUrl( attribUrl );
367}
368
370{
372
373 return mServerProperties->attributionUrl();
374
375}
376
377void QgsMapLayer::setMetadataUrl( const QString &metaUrl )
378{
380
381 QList<QgsMapLayerServerProperties::MetadataUrl> urls = serverProperties()->metadataUrls();
382 if ( urls.isEmpty() )
383 {
384 const QgsMapLayerServerProperties::MetadataUrl newItem = QgsMapLayerServerProperties::MetadataUrl( metaUrl, QLatin1String(), QLatin1String() );
385 urls.prepend( newItem );
386 }
387 else
388 {
389 const QgsMapLayerServerProperties::MetadataUrl old = urls.takeFirst();
390 const QgsMapLayerServerProperties::MetadataUrl newItem( metaUrl, old.type, old.format );
391 urls.prepend( newItem );
392 }
394}
395
397{
399
400 if ( mServerProperties->metadataUrls().isEmpty() )
401 {
402 return QLatin1String();
403 }
404 else
405 {
406 return mServerProperties->metadataUrls().first().url;
407 }
408}
409
410void QgsMapLayer::setMetadataUrlType( const QString &metaUrlType )
411{
413
414 QList<QgsMapLayerServerProperties::MetadataUrl> urls = mServerProperties->metadataUrls();
415 if ( urls.isEmpty() )
416 {
417 const QgsMapLayerServerProperties::MetadataUrl newItem( QLatin1String(), metaUrlType, QLatin1String() );
418 urls.prepend( newItem );
419 }
420 else
421 {
422 const QgsMapLayerServerProperties::MetadataUrl old = urls.takeFirst();
423 const QgsMapLayerServerProperties::MetadataUrl newItem( old.url, metaUrlType, old.format );
424 urls.prepend( newItem );
425 }
426 mServerProperties->setMetadataUrls( urls );
427}
428
430{
432
433 if ( mServerProperties->metadataUrls().isEmpty() )
434 {
435 return QLatin1String();
436 }
437 else
438 {
439 return mServerProperties->metadataUrls().first().type;
440 }
441}
442
443void QgsMapLayer::setMetadataUrlFormat( const QString &metaUrlFormat )
444{
446
447 QList<QgsMapLayerServerProperties::MetadataUrl> urls = mServerProperties->metadataUrls();
448 if ( urls.isEmpty() )
449 {
450 const QgsMapLayerServerProperties::MetadataUrl newItem( QLatin1String(), QLatin1String(), metaUrlFormat );
451 urls.prepend( newItem );
452 }
453 else
454 {
455 const QgsMapLayerServerProperties::MetadataUrl old = urls.takeFirst( );
456 const QgsMapLayerServerProperties::MetadataUrl newItem( old.url, old.type, metaUrlFormat );
457 urls.prepend( newItem );
458 }
459 mServerProperties->setMetadataUrls( urls );
460}
461
463{
465
466 if ( mServerProperties->metadataUrls().isEmpty() )
467 {
468 return QString();
469 }
470 else
471 {
472 return mServerProperties->metadataUrls().first().format;
473 }
474}
475
476QString QgsMapLayer::publicSource( bool redactCredentials ) const
477{
479
480 // Redo this every time we're asked for it, as we don't know if
481 // dataSource has changed.
483 {
485 }
486 else
487 {
488 return QgsDataSourceUri::removePassword( mDataSource, redactCredentials );
489 }
490}
491
492QString QgsMapLayer::source() const
493{
495
496 return mDataSource;
497}
498
500{
502
503 return mExtent2D.isNull() ? mExtent3D.toRectangle() : mExtent2D;
504}
505
507{
509
510 return mExtent3D;
511}
512
513void QgsMapLayer::setBlendMode( const QPainter::CompositionMode blendMode )
514{
516
517 if ( mBlendMode == blendMode )
518 return;
519
520 mBlendMode = blendMode;
523}
524
525QPainter::CompositionMode QgsMapLayer::blendMode() const
526{
527 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
529
530 return mBlendMode;
531}
532
533void QgsMapLayer::setOpacity( double opacity )
534{
536
538 return;
540 emit opacityChanged( opacity );
542}
543
545{
546 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
548
549 return mLayerOpacity;
550}
551
552bool QgsMapLayer::readLayerXml( const QDomElement &layerElement, QgsReadWriteContext &context, QgsMapLayer::ReadFlags flags, QgsDataProvider *preloadedProvider )
553{
555
556 mPreloadedProvider.reset( preloadedProvider );
557
558 bool layerError;
560
561 QDomNode mnl;
562 QDomElement mne;
563
564 // read provider
565 QString provider;
566 mnl = layerElement.namedItem( QStringLiteral( "provider" ) );
567 mne = mnl.toElement();
568 provider = mne.text();
569
570 // set data source
571 mnl = layerElement.namedItem( QStringLiteral( "datasource" ) );
572 mne = mnl.toElement();
573 const QString dataSourceRaw = mne.text();
574
575 // if the layer needs authentication, ensure the master password is set
576 const thread_local QRegularExpression rx( "authcfg=([a-z]|[A-Z]|[0-9]){7}" );
577 if ( rx.match( dataSourceRaw ).hasMatch()
579 {
580 return false;
581 }
582
583 mDataSource = decodedSource( dataSourceRaw, provider, context );
584
585 // Set the CRS from project file, asking the user if necessary.
586 // Make it the saved CRS to have WMS layer projected correctly.
587 // We will still overwrite whatever GDAL etc picks up anyway
588 // further down this function.
589 mnl = layerElement.namedItem( QStringLiteral( "layername" ) );
590 mne = mnl.toElement();
591
593 CUSTOM_CRS_VALIDATION savedValidation;
594
595 const QDomNode srsNode = layerElement.namedItem( QStringLiteral( "srs" ) );
596 mCRS.readXml( srsNode );
597 mCRS.setValidationHint( tr( "Specify CRS for layer %1" ).arg( mne.text() ) );
599 mCRS.validate();
600 savedCRS = mCRS;
601
602 // Do not validate any projections in children, they will be overwritten anyway.
603 // No need to ask the user for a projections when it is overwritten, is there?
606
607 const QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Layer" ), mne.text() );
608
609 // the internal name is just the data source basename
610 //QFileInfo dataSourceFileInfo( mDataSource );
611 //internalName = dataSourceFileInfo.baseName();
612
613 // set ID
614 mnl = layerElement.namedItem( QStringLiteral( "id" ) );
615 if ( ! mnl.isNull() )
616 {
617 mne = mnl.toElement();
618 if ( ! mne.isNull() && mne.text().length() > 10 ) // should be at least 17 (yyyyMMddhhmmsszzz)
619 {
620 const QString newId = mne.text();
621 if ( newId != mID )
622 {
623 mID = mne.text();
624 emit idChanged( mID );
625 }
626 }
627 }
628
629 // set name
630 mnl = layerElement.namedItem( QStringLiteral( "layername" ) );
631 mne = mnl.toElement();
632
633 //name can be translated
634 setName( context.projectTranslator()->translate( QStringLiteral( "project:layers:%1" ).arg( layerElement.namedItem( QStringLiteral( "id" ) ).toElement().text() ), mne.text() ) );
635
636 // now let the children grab what they need from the Dom node.
637 layerError = !readXml( layerElement, context );
638
639 const QgsCoordinateReferenceSystem oldVerticalCrs = verticalCrs();
640 const QgsCoordinateReferenceSystem oldCrs3D = mCrs3D;
641
642 // overwrite CRS with what we read from project file before the raster/vector
643 // file reading functions changed it. They will if projections is specified in the file.
644 // FIXME: is this necessary? Yes, it is (autumn 2019)
646 mCRS = savedCRS;
647
648 //vertical CRS
649 {
651 const QDomNode verticalCrsNode = layerElement.firstChildElement( QStringLiteral( "verticalCrs" ) );
652 if ( !verticalCrsNode.isNull() )
653 {
654 verticalCrs.readXml( verticalCrsNode );
655 }
656 mVerticalCrs = verticalCrs;
657 }
658 rebuildCrs3D();
659
660 //legendUrl
661 const QDomElement legendUrlElem = layerElement.firstChildElement( QStringLiteral( "legendUrl" ) );
662 if ( !legendUrlElem.isNull() )
663 {
664 mLegendUrl = legendUrlElem.text();
665 mLegendUrlFormat = legendUrlElem.attribute( QStringLiteral( "format" ), QString() );
666 }
667
668 serverProperties()->readXml( layerElement );
669
670 if ( serverProperties()->metadataUrls().isEmpty() )
671 {
672 // metadataUrl is still empty, maybe it's a QGIS Project < 3.22
673 // keep for legacy
674 const QDomElement metaUrlElem = layerElement.firstChildElement( QStringLiteral( "metadataUrl" ) );
675 if ( !metaUrlElem.isNull() )
676 {
677 const QString url = metaUrlElem.text();
678 const QString type = metaUrlElem.attribute( QStringLiteral( "type" ), QString() );
679 const QString format = metaUrlElem.attribute( QStringLiteral( "format" ), QString() );
680 const QgsMapLayerServerProperties::MetadataUrl newItem( url, type, format );
681 mServerProperties->setMetadataUrls( QList<QgsMapLayerServerProperties::MetadataUrl>() << newItem );
682 }
683 }
684
685 // mMetadata.readFromLayer( this );
686 const QDomElement metadataElem = layerElement.firstChildElement( QStringLiteral( "resourceMetadata" ) );
687 mMetadata.readMetadataXml( metadataElem );
688
689 setAutoRefreshInterval( layerElement.attribute( QStringLiteral( "autoRefreshTime" ), QStringLiteral( "0" ) ).toInt() );
690 if ( layerElement.hasAttribute( QStringLiteral( "autoRefreshMode" ) ) )
691 {
692 setAutoRefreshMode( qgsEnumKeyToValue( layerElement.attribute( QStringLiteral( "autoRefreshMode" ) ), Qgis::AutoRefreshMode::Disabled ) );
693 }
694 else
695 {
696 setAutoRefreshMode( layerElement.attribute( QStringLiteral( "autoRefreshEnabled" ), QStringLiteral( "0" ) ).toInt() ? Qgis::AutoRefreshMode::RedrawOnly : Qgis::AutoRefreshMode::Disabled );
697 }
698 setRefreshOnNofifyMessage( layerElement.attribute( QStringLiteral( "refreshOnNotifyMessage" ), QString() ) );
699 setRefreshOnNotifyEnabled( layerElement.attribute( QStringLiteral( "refreshOnNotifyEnabled" ), QStringLiteral( "0" ) ).toInt() );
700
701 // geographic extent is read only if necessary
703 {
704 const QDomNode wgs84ExtentNode = layerElement.namedItem( QStringLiteral( "wgs84extent" ) );
705 if ( !wgs84ExtentNode.isNull() )
706 mWgs84Extent = QgsXmlUtils::readRectangle( wgs84ExtentNode.toElement() );
707 }
708
709 mLegendPlaceholderImage = layerElement.attribute( QStringLiteral( "legendPlaceholderImage" ) );
710
711 if ( verticalCrs() != oldVerticalCrs )
712 emit verticalCrsChanged();
713 if ( mCrs3D != oldCrs3D )
714 emit crs3DChanged();
715
716 return ! layerError;
717} // bool QgsMapLayer::readLayerXML
718
719
720bool QgsMapLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
721{
723
724 Q_UNUSED( layer_node )
725 Q_UNUSED( context )
726 // NOP by default; children will over-ride with behavior specific to them
727
728 // read Extent
730 {
731 const QDomNode extent3DNode = layer_node.namedItem( QStringLiteral( "extent3D" ) );
732 if ( extent3DNode.isNull() )
733 {
734 const QDomNode extentNode = layer_node.namedItem( QStringLiteral( "extent" ) );
735 if ( !extentNode.isNull() )
736 {
737 mExtent2D = QgsXmlUtils::readRectangle( extentNode.toElement() );
738 }
739 }
740 else
741 {
742 mExtent3D = QgsXmlUtils::readBox3D( extent3DNode.toElement() );
743 }
744 }
745
746 return true;
747} // void QgsMapLayer::readXml
748
749
750bool QgsMapLayer::writeLayerXml( QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context ) const
751{
753
754 if ( !mExtent3D.isNull() && dataProvider() && dataProvider()->elevationProperties() && dataProvider()->elevationProperties()->containsElevationData() )
755 layerElement.appendChild( QgsXmlUtils::writeBox3D( mExtent3D, document ) );
756 else if ( !mExtent2D.isNull() )
757 layerElement.appendChild( QgsXmlUtils::writeRectangle( mExtent2D, document ) );
758
759 if ( const QgsRectangle lWgs84Extent = wgs84Extent( true ); !lWgs84Extent.isNull() )
760 {
761 layerElement.appendChild( QgsXmlUtils::writeRectangle( lWgs84Extent, document, QStringLiteral( "wgs84extent" ) ) );
762 }
763
764 layerElement.setAttribute( QStringLiteral( "autoRefreshTime" ), QString::number( mRefreshTimer->interval() ) );
765 layerElement.setAttribute( QStringLiteral( "autoRefreshMode" ), qgsEnumValueToKey( mAutoRefreshMode ) );
766 layerElement.setAttribute( QStringLiteral( "refreshOnNotifyEnabled" ), mIsRefreshOnNofifyEnabled ? 1 : 0 );
767 layerElement.setAttribute( QStringLiteral( "refreshOnNotifyMessage" ), mRefreshOnNofifyMessage );
768
769 // ID
770 QDomElement layerId = document.createElement( QStringLiteral( "id" ) );
771 const QDomText layerIdText = document.createTextNode( id() );
772 layerId.appendChild( layerIdText );
773
774 layerElement.appendChild( layerId );
775
776 if ( mVerticalCrs.isValid() )
777 {
778 QDomElement verticalSrsNode = document.createElement( QStringLiteral( "verticalCrs" ) );
779 mVerticalCrs.writeXml( verticalSrsNode, document );
780 layerElement.appendChild( verticalSrsNode );
781 }
782
783 // data source
784 QDomElement dataSource = document.createElement( QStringLiteral( "datasource" ) );
785 const QString src = encodedSource( source(), context );
786 const QDomText dataSourceText = document.createTextNode( src );
787 dataSource.appendChild( dataSourceText );
788 layerElement.appendChild( dataSource );
789
790 // layer name
791 QDomElement layerName = document.createElement( QStringLiteral( "layername" ) );
792 const QDomText layerNameText = document.createTextNode( name() );
793 layerName.appendChild( layerNameText );
794 layerElement.appendChild( layerName );
795
796 // layer short name
797
798 // TODO -- ideally this would be in QgsMapLayerServerProperties::writeXml, but that's currently
799 // only called for SOME map layer subclasses!
800 if ( !mServerProperties->shortName().isEmpty() )
801 {
802 QDomElement layerShortName = document.createElement( QStringLiteral( "shortname" ) );
803 const QDomText layerShortNameText = document.createTextNode( mServerProperties->shortName() );
804 layerShortName.appendChild( layerShortNameText );
805 layerElement.appendChild( layerShortName );
806 }
807
808 // layer title
809 if ( !mServerProperties->title().isEmpty() )
810 {
811 QDomElement layerTitle = document.createElement( QStringLiteral( "title" ) );
812 const QDomText layerTitleText = document.createTextNode( mServerProperties->title() );
813 layerTitle.appendChild( layerTitleText );
814
815 if ( mServerProperties->title() != mServerProperties->wfsTitle() )
816 {
817 layerTitle.setAttribute( "wfs", mServerProperties->wfsTitle() );
818 }
819
820 layerElement.appendChild( layerTitle );
821 }
822
823 // layer abstract
824 if ( !mServerProperties->abstract().isEmpty() )
825 {
826 QDomElement layerAbstract = document.createElement( QStringLiteral( "abstract" ) );
827 const QDomText layerAbstractText = document.createTextNode( mServerProperties->abstract() );
828 layerAbstract.appendChild( layerAbstractText );
829 layerElement.appendChild( layerAbstract );
830 }
831
832 // layer keyword list
833 const QStringList keywordStringList = mServerProperties->keywordList().split( ',' );
834 if ( !keywordStringList.isEmpty() )
835 {
836 QDomElement layerKeywordList = document.createElement( QStringLiteral( "keywordList" ) );
837 for ( int i = 0; i < keywordStringList.size(); ++i )
838 {
839 QDomElement layerKeywordValue = document.createElement( QStringLiteral( "value" ) );
840 const QDomText layerKeywordText = document.createTextNode( keywordStringList.at( i ).trimmed() );
841 layerKeywordValue.appendChild( layerKeywordText );
842 layerKeywordList.appendChild( layerKeywordValue );
843 }
844 layerElement.appendChild( layerKeywordList );
845 }
846
847 // layer dataUrl
848 const QString aDataUrl = mServerProperties->dataUrl();
849 if ( !aDataUrl.isEmpty() )
850 {
851 QDomElement layerDataUrl = document.createElement( QStringLiteral( "dataUrl" ) );
852 const QDomText layerDataUrlText = document.createTextNode( aDataUrl );
853 layerDataUrl.appendChild( layerDataUrlText );
854 layerDataUrl.setAttribute( QStringLiteral( "format" ), mServerProperties->dataUrlFormat() );
855 layerElement.appendChild( layerDataUrl );
856 }
857
858 // layer legendUrl
859 const QString aLegendUrl = legendUrl();
860 if ( !aLegendUrl.isEmpty() )
861 {
862 QDomElement layerLegendUrl = document.createElement( QStringLiteral( "legendUrl" ) );
863 const QDomText layerLegendUrlText = document.createTextNode( aLegendUrl );
864 layerLegendUrl.appendChild( layerLegendUrlText );
865 layerLegendUrl.setAttribute( QStringLiteral( "format" ), legendUrlFormat() );
866 layerElement.appendChild( layerLegendUrl );
867 }
868
869 // layer attribution
870 const QString aAttribution = mServerProperties->attribution();
871 if ( !aAttribution.isEmpty() )
872 {
873 QDomElement layerAttribution = document.createElement( QStringLiteral( "attribution" ) );
874 const QDomText layerAttributionText = document.createTextNode( aAttribution );
875 layerAttribution.appendChild( layerAttributionText );
876 layerAttribution.setAttribute( QStringLiteral( "href" ), mServerProperties->attributionUrl() );
877 layerElement.appendChild( layerAttribution );
878 }
879
880 // timestamp if supported
881 if ( timestamp() > QDateTime() )
882 {
883 QDomElement stamp = document.createElement( QStringLiteral( "timestamp" ) );
884 const QDomText stampText = document.createTextNode( timestamp().toString( Qt::ISODate ) );
885 stamp.appendChild( stampText );
886 layerElement.appendChild( stamp );
887 }
888
889 layerElement.appendChild( layerName );
890
891 // zorder
892 // This is no longer stored in the project file. It is superfluous since the layers
893 // are written and read in the proper order.
894
895 // spatial reference system id
896 QDomElement mySrsElement = document.createElement( QStringLiteral( "srs" ) );
897 mCRS.writeXml( mySrsElement, document );
898 layerElement.appendChild( mySrsElement );
899
900 // layer metadata
901 QDomElement myMetadataElem = document.createElement( QStringLiteral( "resourceMetadata" ) );
902 mMetadata.writeMetadataXml( myMetadataElem, document );
903 layerElement.appendChild( myMetadataElem );
904
905 layerElement.setAttribute( QStringLiteral( "legendPlaceholderImage" ), mLegendPlaceholderImage );
906
907 // now append layer node to map layer node
908 return writeXml( layerElement, document, context );
909}
910
911void QgsMapLayer::writeCommonStyle( QDomElement &layerElement, QDomDocument &document,
912 const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
913{
915
916 // save categories
917 const QMetaEnum metaEnum = QMetaEnum::fromType<QgsMapLayer::StyleCategories>();
918 const QString categoriesKeys( metaEnum.valueToKeys( static_cast<int>( categories ) ) );
919 layerElement.setAttribute( QStringLiteral( "styleCategories" ), categoriesKeys );
920
921 if ( categories.testFlag( Rendering ) )
922 {
923 // use scale dependent visibility flag
924 layerElement.setAttribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ), hasScaleBasedVisibility() ? 1 : 0 );
925 layerElement.setAttribute( QStringLiteral( "maxScale" ), QString::number( maximumScale() ) );
926 layerElement.setAttribute( QStringLiteral( "minScale" ), QString::number( minimumScale() ) );
927 layerElement.setAttribute( QStringLiteral( "autoRefreshMode" ), qgsEnumValueToKey( mAutoRefreshMode ) );
928 layerElement.setAttribute( QStringLiteral( "autoRefreshTime" ), QString::number( autoRefreshInterval() ) );
929 }
930
931 if ( categories.testFlag( Symbology3D ) )
932 {
933 if ( m3DRenderer )
934 {
935 QDomElement renderer3DElem = document.createElement( QStringLiteral( "renderer-3d" ) );
936 renderer3DElem.setAttribute( QStringLiteral( "type" ), m3DRenderer->type() );
937 m3DRenderer->writeXml( renderer3DElem, context );
938 layerElement.appendChild( renderer3DElem );
939 }
940 }
941
942 if ( categories.testFlag( LayerConfiguration ) )
943 {
944 // flags
945 // this code is saving automatically all the flags entries
946 QDomElement layerFlagsElem = document.createElement( QStringLiteral( "flags" ) );
947 const auto enumMap = qgsEnumMap<QgsMapLayer::LayerFlag>();
948 for ( auto it = enumMap.constBegin(); it != enumMap.constEnd(); ++it )
949 {
950 const bool flagValue = mFlags.testFlag( it.key() );
951 QDomElement flagElem = document.createElement( it.value() );
952 flagElem.appendChild( document.createTextNode( QString::number( flagValue ) ) );
953 layerFlagsElem.appendChild( flagElem );
954 }
955 layerElement.appendChild( layerFlagsElem );
956 }
957
958 if ( categories.testFlag( Temporal ) )
959 {
961 properties->writeXml( layerElement, document, context );
962 }
963
964 if ( categories.testFlag( Elevation ) )
965 {
967 properties->writeXml( layerElement, document, context );
968 }
969
970 if ( categories.testFlag( Notes ) && QgsLayerNotesUtils::layerHasNotes( this ) )
971 {
972 QDomElement notesElem = document.createElement( QStringLiteral( "userNotes" ) );
973 notesElem.setAttribute( QStringLiteral( "value" ), QgsLayerNotesUtils::layerNotes( this ) );
974 layerElement.appendChild( notesElem );
975 }
976
977 // custom properties
978 if ( categories.testFlag( CustomProperties ) )
979 {
980 writeCustomProperties( layerElement, document );
981 }
982}
983
984
985bool QgsMapLayer::writeXml( QDomNode &layer_node, QDomDocument &document, const QgsReadWriteContext &context ) const
986{
988
989 Q_UNUSED( layer_node )
990 Q_UNUSED( document )
991 Q_UNUSED( context )
992 // NOP by default; children will over-ride with behavior specific to them
993
994 return true;
995}
996
997QString QgsMapLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
998{
1000
1001 Q_UNUSED( context )
1002 return source;
1003}
1004
1005QString QgsMapLayer::decodedSource( const QString &source, const QString &dataProvider, const QgsReadWriteContext &context ) const
1006{
1008
1009 Q_UNUSED( context )
1010 Q_UNUSED( dataProvider )
1011 return source;
1012}
1013
1015{
1017
1019 if ( m3DRenderer )
1020 m3DRenderer->resolveReferences( *project );
1021}
1022
1023
1024void QgsMapLayer::readCustomProperties( const QDomNode &layerNode, const QString &keyStartsWith )
1025{
1027
1028 const QgsObjectCustomProperties oldKeys = mCustomProperties;
1029
1030 mCustomProperties.readXml( layerNode, keyStartsWith );
1031
1032 for ( const QString &key : mCustomProperties.keys() )
1033 {
1034 if ( !oldKeys.contains( key ) || mCustomProperties.value( key ) != oldKeys.value( key ) )
1035 {
1036 emit customPropertyChanged( key );
1037 }
1038 }
1039}
1040
1041void QgsMapLayer::writeCustomProperties( QDomNode &layerNode, QDomDocument &doc ) const
1042{
1044
1045 mCustomProperties.writeXml( layerNode, doc );
1046}
1047
1048void QgsMapLayer::readStyleManager( const QDomNode &layerNode )
1049{
1051
1052 const QDomElement styleMgrElem = layerNode.firstChildElement( QStringLiteral( "map-layer-style-manager" ) );
1053 if ( !styleMgrElem.isNull() )
1054 mStyleManager->readXml( styleMgrElem );
1055 else
1056 mStyleManager->reset();
1057}
1058
1059void QgsMapLayer::writeStyleManager( QDomNode &layerNode, QDomDocument &doc ) const
1060{
1062
1063 if ( mStyleManager )
1064 {
1065 QDomElement styleMgrElem = doc.createElement( QStringLiteral( "map-layer-style-manager" ) );
1066 mStyleManager->writeXml( styleMgrElem );
1067 layerNode.appendChild( styleMgrElem );
1068 }
1069}
1070
1072{
1074
1075 return mMapTipTemplate;
1076}
1077
1078void QgsMapLayer::setMapTipTemplate( const QString &mapTip )
1079{
1081
1082 if ( mMapTipTemplate == mapTip )
1083 return;
1084
1085 mMapTipTemplate = mapTip;
1086 emit mapTipTemplateChanged();
1087}
1088
1090{
1092
1093 if ( mMapTipsEnabled == enabled )
1094 return;
1095
1096 mMapTipsEnabled = enabled;
1097 emit mapTipsEnabledChanged();
1098}
1099
1101{
1103
1104 return mMapTipsEnabled;
1105}
1106
1108{
1110 if ( layerReadFlags & QgsMapLayer::FlagTrustLayerMetadata )
1111 {
1113 }
1114 if ( layerReadFlags & QgsMapLayer::FlagForceReadOnly )
1115 {
1117 }
1118
1119 if ( layerReadFlags & QgsMapLayer::FlagReadExtentFromXml )
1120 {
1121 const QDomNode extent3DNode = layerNode.namedItem( QStringLiteral( "extent3D" ) );
1122 if ( extent3DNode.isNull() )
1123 {
1124 const QDomNode extentNode = layerNode.namedItem( QStringLiteral( "extent" ) );
1125 if ( !extentNode.isNull() )
1126 {
1128 }
1129 }
1130 else
1131 {
1133 }
1134 }
1135
1136 return flags;
1137}
1138
1140{
1141 // because QgsVirtualLayerProvider is not anywhere NEAR thread safe:
1143
1144 return mValid;
1145}
1146
1147#if 0
1148void QgsMapLayer::connectNotify( const char *signal )
1149{
1150 Q_UNUSED( signal )
1151 QgsDebugMsgLevel( "QgsMapLayer connected to " + QString( signal ), 3 );
1152} // QgsMapLayer::connectNotify
1153#endif
1154
1155bool QgsMapLayer::isInScaleRange( double scale ) const
1156{
1157 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
1159
1160 // mMinScale (denominator!) is inclusive ( >= --> In range )
1161 // mMaxScale (denominator!) is exclusive ( < --> In range )
1162 return !mScaleBasedVisibility
1163 || ( ( mMinScale == 0 || !QgsScaleUtils::lessThanMaximumScale( scale, mMinScale ) )
1164 && ( mMaxScale == 0 || !QgsScaleUtils::equalToOrGreaterThanMinimumScale( scale, mMaxScale ) ) );
1165}
1166
1168{
1169 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
1171
1172 return mScaleBasedVisibility;
1173}
1174
1176{
1178
1179 return mAutoRefreshMode != Qgis::AutoRefreshMode::Disabled;;
1180}
1181
1183{
1185
1186 return mAutoRefreshMode;
1187}
1188
1190{
1192
1193 return mRefreshTimer->interval();
1194}
1195
1197{
1199
1200 if ( interval <= 0 )
1201 {
1202 mRefreshTimer->stop();
1203 mRefreshTimer->setInterval( 0 );
1205 }
1206 else
1207 {
1208 mRefreshTimer->setInterval( interval );
1209 }
1210 emit autoRefreshIntervalChanged( mRefreshTimer->isActive() ? mRefreshTimer->interval() : 0 );
1211}
1212
1219
1221{
1223
1224 if ( mode == mAutoRefreshMode )
1225 return;
1226
1227 mAutoRefreshMode = mode;
1228 switch ( mAutoRefreshMode )
1229 {
1231 mRefreshTimer->stop();
1232 break;
1233
1236 if ( mRefreshTimer->interval() > 0 )
1237 mRefreshTimer->start();
1238 break;
1239 }
1240
1241 emit autoRefreshIntervalChanged( mRefreshTimer->isActive() ? mRefreshTimer->interval() : 0 );
1242}
1243
1245{
1247
1248 return mMetadata;
1249}
1250
1252{
1254
1255 mMinScale = scale;
1256}
1257
1259{
1261
1262 return mMinScale;
1263}
1264
1266{
1268
1269 mMaxScale = scale;
1270}
1271
1273{
1275
1276 mScaleBasedVisibility = enabled;
1277}
1278
1280{
1282
1283 return mMaxScale;
1284}
1285
1286QStringList QgsMapLayer::subLayers() const
1287{
1289
1290 return QStringList();
1291}
1292
1293void QgsMapLayer::setLayerOrder( const QStringList &layers )
1294{
1296
1297 Q_UNUSED( layers )
1298}
1299
1300void QgsMapLayer::setSubLayerVisibility( const QString &name, bool vis )
1301{
1303
1304 Q_UNUSED( name )
1305 Q_UNUSED( vis )
1306}
1307
1309{
1311
1312 return false;
1313}
1314
1316{
1317 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
1319
1320 return mCRS;
1321}
1322
1324{
1325 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
1327
1328 switch ( mCRS.type() )
1329 {
1330 case Qgis::CrsType::Vertical: // would hope this never happens!
1331 QgsDebugError( QStringLiteral( "Layer has a vertical CRS set as the horizontal CRS!" ) );
1332 return mCRS;
1333
1335 return mCRS.verticalCrs();
1336
1348 break;
1349 }
1350 return mVerticalCrs;
1351}
1352
1354{
1356
1357 return mCrs3D.isValid() ? mCrs3D : mCRS;
1358}
1359
1360void QgsMapLayer::setCrs( const QgsCoordinateReferenceSystem &srs, bool emitSignal )
1361{
1363 const bool needToValidateCrs = mShouldValidateCrs && isSpatial() && !srs.isValid() && type() != Qgis::LayerType::Annotation;
1364
1365 if ( mCRS == srs && !needToValidateCrs )
1366 return;
1367
1368 const QgsCoordinateReferenceSystem oldVerticalCrs = verticalCrs();
1369 const QgsCoordinateReferenceSystem oldCrs3D = mCrs3D;
1370 const QgsCoordinateReferenceSystem oldCrs = mCRS;
1371
1372 mCRS = srs;
1373
1374 if ( needToValidateCrs )
1375 {
1376 mCRS.setValidationHint( tr( "Specify CRS for layer %1" ).arg( name() ) );
1377 mCRS.validate();
1378 }
1379
1380 rebuildCrs3D();
1381
1382 if ( emitSignal && mCRS != oldCrs )
1383 emit crsChanged();
1384
1385 // Did vertical crs also change as a result of this? If so, emit signal
1386 if ( oldVerticalCrs != verticalCrs() )
1387 emit verticalCrsChanged();
1388 if ( oldCrs3D != mCrs3D )
1389 emit crs3DChanged();
1390}
1391
1393{
1395 bool res = true;
1396 if ( crs.isValid() )
1397 {
1398 // validate that passed crs is a vertical crs
1399 switch ( crs.type() )
1400 {
1402 break;
1403
1416 if ( errorMessage )
1417 *errorMessage = QObject::tr( "Specified CRS is a %1 CRS, not a Vertical CRS" ).arg( qgsEnumValueToKey( crs.type() ) );
1418 return false;
1419 }
1420 }
1421
1422 if ( crs != mVerticalCrs )
1423 {
1424 const QgsCoordinateReferenceSystem oldVerticalCrs = verticalCrs();
1425 const QgsCoordinateReferenceSystem oldCrs3D = mCrs3D;
1426
1427 switch ( mCRS.type() )
1428 {
1430 if ( crs != oldVerticalCrs )
1431 {
1432 if ( errorMessage )
1433 *errorMessage = QObject::tr( "Layer CRS is a Compound CRS, specified Vertical CRS will be ignored" );
1434 return false;
1435 }
1436 break;
1437
1439 if ( crs != oldVerticalCrs )
1440 {
1441 if ( errorMessage )
1442 *errorMessage = QObject::tr( "Layer CRS is a Geographic 3D CRS, specified Vertical CRS will be ignored" );
1443 return false;
1444 }
1445 break;
1446
1448 if ( crs != oldVerticalCrs )
1449 {
1450 if ( errorMessage )
1451 *errorMessage = QObject::tr( "Layer CRS is a Geocentric CRS, specified Vertical CRS will be ignored" );
1452 return false;
1453 }
1454 break;
1455
1457 if ( mCRS.hasVerticalAxis() && crs != oldVerticalCrs )
1458 {
1459 if ( errorMessage )
1460 *errorMessage = QObject::tr( "Layer CRS is a Projected 3D CRS, specified Vertical CRS will be ignored" );
1461 return false;
1462 }
1463 break;
1464
1474 break;
1475 }
1476
1477 mVerticalCrs = crs;
1478 res = rebuildCrs3D( errorMessage );
1479
1480 // only emit signal if vertical crs was actually changed, so eg if mCrs is compound
1481 // then we haven't actually changed the vertical crs by this call!
1482 if ( verticalCrs() != oldVerticalCrs )
1483 emit verticalCrsChanged();
1484 if ( mCrs3D != oldCrs3D )
1485 emit crs3DChanged();
1486 }
1487 return res;
1488}
1489
1491{
1493
1494 const QgsDataProvider *lDataProvider = dataProvider();
1495 return lDataProvider ? lDataProvider->transformContext() : QgsCoordinateTransformContext();
1496}
1497
1498QString QgsMapLayer::formatLayerName( const QString &name )
1499{
1500 QString layerName( name );
1501 layerName.replace( '_', ' ' );
1503 return layerName;
1504}
1505
1506QString QgsMapLayer::baseURI( PropertyType type ) const
1507{
1509
1510 QString myURI = publicSource();
1511
1512 // first get base path for delimited text, spatialite and OGR layers,
1513 // as in these cases URI may contain layer name and/or additional
1514 // information. This also strips prefix in case if VSIFILE mechanism
1515 // is used
1516 if ( providerType() == QLatin1String( "ogr" ) || providerType() == QLatin1String( "delimitedtext" )
1517 || providerType() == QLatin1String( "gdal" ) || providerType() == QLatin1String( "spatialite" ) )
1518 {
1519 QVariantMap components = QgsProviderRegistry::instance()->decodeUri( providerType(), myURI );
1520 myURI = components["path"].toString();
1521 }
1522
1523 QFileInfo myFileInfo( myURI );
1524 QString key;
1525
1526 if ( myFileInfo.exists() )
1527 {
1528 // if file is using the /vsizip/ or /vsigzip/ mechanism, cleanup the name
1529 if ( myURI.endsWith( QLatin1String( ".gz" ), Qt::CaseInsensitive ) )
1530 myURI.chop( 3 );
1531 else if ( myURI.endsWith( QLatin1String( ".zip" ), Qt::CaseInsensitive ) )
1532 myURI.chop( 4 );
1533 else if ( myURI.endsWith( QLatin1String( ".tar" ), Qt::CaseInsensitive ) )
1534 myURI.chop( 4 );
1535 else if ( myURI.endsWith( QLatin1String( ".tar.gz" ), Qt::CaseInsensitive ) )
1536 myURI.chop( 7 );
1537 else if ( myURI.endsWith( QLatin1String( ".tgz" ), Qt::CaseInsensitive ) )
1538 myURI.chop( 4 );
1539 myFileInfo.setFile( myURI );
1540 // get the file name for our .qml style file
1541 key = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + QgsMapLayer::extensionPropertyType( type );
1542 }
1543 else
1544 {
1545 key = publicSource();
1546 }
1547
1548 return key;
1549}
1550
1552{
1554
1555 return baseURI( PropertyType::Metadata );
1556}
1557
1558QString QgsMapLayer::saveDefaultMetadata( bool &resultFlag )
1559{
1561
1563 {
1564 if ( metadata->providerCapabilities() & QgsProviderMetadata::SaveLayerMetadata )
1565 {
1566 try
1567 {
1568 QString errorMessage;
1569 resultFlag = QgsProviderRegistry::instance()->saveLayerMetadata( providerType(), mDataSource, mMetadata, errorMessage );
1570 if ( resultFlag )
1571 return tr( "Successfully saved default layer metadata" );
1572 else
1573 return errorMessage;
1574 }
1575 catch ( QgsNotSupportedException &e )
1576 {
1577 resultFlag = false;
1578 return e.what();
1579 }
1580 }
1581 }
1582
1583 // fallback default metadata saving method, for providers which don't support (or implement) saveLayerMetadata
1584 return saveNamedMetadata( metadataUri(), resultFlag );
1585}
1586
1587QString QgsMapLayer::loadDefaultMetadata( bool &resultFlag )
1588{
1590
1591 return loadNamedMetadata( metadataUri(), resultFlag );
1592}
1593
1595{
1597
1598 return baseURI( PropertyType::Style );
1599}
1600
1607
1608bool QgsMapLayer::loadNamedMetadataFromDatabase( const QString &db, const QString &uri, QString &qmd )
1609{
1611
1612 return loadNamedPropertyFromDatabase( db, uri, qmd, PropertyType::Metadata );
1613}
1614
1615bool QgsMapLayer::loadNamedStyleFromDatabase( const QString &db, const QString &uri, QString &qml )
1616{
1618
1619 return loadNamedPropertyFromDatabase( db, uri, qml, PropertyType::Style );
1620}
1621
1622bool QgsMapLayer::loadNamedPropertyFromDatabase( const QString &db, const QString &uri, QString &xml, QgsMapLayer::PropertyType type )
1623{
1625
1626 QgsDebugMsgLevel( QStringLiteral( "db = %1 uri = %2" ).arg( db, uri ), 4 );
1627
1628 bool resultFlag = false;
1629
1630 // read from database
1633
1634 int myResult;
1635
1636 QgsDebugMsgLevel( QStringLiteral( "Trying to load style or metadata for \"%1\" from \"%2\"" ).arg( uri, db ), 4 );
1637
1638 if ( db.isEmpty() || !QFile( db ).exists() )
1639 return false;
1640
1641 myResult = database.open_v2( db, SQLITE_OPEN_READONLY, nullptr );
1642 if ( myResult != SQLITE_OK )
1643 {
1644 return false;
1645 }
1646
1647 QString mySql;
1648 switch ( type )
1649 {
1650 case Metadata:
1651 mySql = QStringLiteral( "select qmd from tbl_metadata where metadata=?" );
1652 break;
1653
1654 case Style:
1655 mySql = QStringLiteral( "select qml from tbl_styles where style=?" );
1656 break;
1657 }
1658
1659 statement = database.prepare( mySql, myResult );
1660 if ( myResult == SQLITE_OK )
1661 {
1662 QByteArray param = uri.toUtf8();
1663
1664 if ( sqlite3_bind_text( statement.get(), 1, param.data(), param.length(), SQLITE_STATIC ) == SQLITE_OK &&
1665 sqlite3_step( statement.get() ) == SQLITE_ROW )
1666 {
1667 xml = QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( statement.get(), 0 ) ) );
1668 resultFlag = true;
1669 }
1670 }
1671 return resultFlag;
1672}
1673
1674
1675QString QgsMapLayer::loadNamedStyle( const QString &uri, bool &resultFlag, QgsMapLayer::StyleCategories categories, Qgis::LoadStyleFlags flags )
1676{
1678
1679 return loadNamedStyle( uri, resultFlag, false, categories, flags );
1680}
1681
1682QString QgsMapLayer::loadNamedProperty( const QString &uri, QgsMapLayer::PropertyType type, bool &namedPropertyExists, bool &propertySuccessfullyLoaded, StyleCategories categories, Qgis::LoadStyleFlags flags )
1683{
1685
1686 QgsDebugMsgLevel( QStringLiteral( "uri = %1 myURI = %2" ).arg( uri, publicSource() ), 4 );
1687
1688 namedPropertyExists = false;
1689 propertySuccessfullyLoaded = false;
1690 if ( uri.isEmpty() )
1691 return QString();
1692
1693 QDomDocument myDocument( QStringLiteral( "qgis" ) );
1694
1695 // location of problem associated with errorMsg
1696 int line, column;
1697 QString myErrorMessage;
1698
1699 QFile myFile( uri );
1700 if ( myFile.open( QFile::ReadOnly ) )
1701 {
1702 QgsDebugMsgLevel( QStringLiteral( "file found %1" ).arg( uri ), 2 );
1703 namedPropertyExists = true;
1704
1705 // read file
1706 propertySuccessfullyLoaded = myDocument.setContent( &myFile, &myErrorMessage, &line, &column );
1707 if ( !propertySuccessfullyLoaded )
1708 myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1709 myFile.close();
1710 }
1711 else
1712 {
1713 const QFileInfo project( QgsProject::instance()->fileName() ); // skip-keyword-check
1714 QgsDebugMsgLevel( QStringLiteral( "project fileName: %1" ).arg( project.absoluteFilePath() ), 4 );
1715
1716 QString xml;
1717 switch ( type )
1718 {
1719 case QgsMapLayer::Style:
1720 {
1721 if ( loadNamedStyleFromDatabase( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ), uri, xml ) ||
1722 ( project.exists() && loadNamedStyleFromDatabase( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), uri, xml ) ) ||
1723 loadNamedStyleFromDatabase( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( QStringLiteral( "resources/qgis.qmldb" ) ), uri, xml ) )
1724 {
1725 namedPropertyExists = true;
1726 propertySuccessfullyLoaded = myDocument.setContent( xml, &myErrorMessage, &line, &column );
1727 if ( !propertySuccessfullyLoaded )
1728 {
1729 myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1730 }
1731 }
1732 else
1733 {
1735 {
1736 myErrorMessage = tr( "Style not found in database" );
1737 }
1738 }
1739 break;
1740 }
1742 {
1743 if ( loadNamedMetadataFromDatabase( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ), uri, xml ) ||
1744 ( project.exists() && loadNamedMetadataFromDatabase( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), uri, xml ) ) ||
1745 loadNamedMetadataFromDatabase( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( QStringLiteral( "resources/qgis.qmldb" ) ), uri, xml ) )
1746 {
1747 namedPropertyExists = true;
1748 propertySuccessfullyLoaded = myDocument.setContent( xml, &myErrorMessage, &line, &column );
1749 if ( !propertySuccessfullyLoaded )
1750 {
1751 myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1752 }
1753 }
1754 else
1755 {
1756 myErrorMessage = tr( "Metadata not found in database" );
1757 }
1758 break;
1759 }
1760 }
1761 }
1762
1763 if ( !propertySuccessfullyLoaded )
1764 {
1765 return myErrorMessage;
1766 }
1767
1768 switch ( type )
1769 {
1770 case QgsMapLayer::Style:
1771 propertySuccessfullyLoaded = importNamedStyle( myDocument, myErrorMessage, categories );
1772 if ( !propertySuccessfullyLoaded )
1773 myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( uri, myErrorMessage );
1774 break;
1776 propertySuccessfullyLoaded = importNamedMetadata( myDocument, myErrorMessage );
1777 if ( !propertySuccessfullyLoaded )
1778 myErrorMessage = tr( "Loading metadata file %1 failed because:\n%2" ).arg( uri, myErrorMessage );
1779 break;
1780 }
1781 return myErrorMessage;
1782}
1783
1784bool QgsMapLayer::importNamedMetadata( QDomDocument &document, QString &errorMessage )
1785{
1787
1788 const QDomElement myRoot = document.firstChildElement( QStringLiteral( "qgis" ) );
1789 if ( myRoot.isNull() )
1790 {
1791 errorMessage = tr( "Root <qgis> element could not be found" );
1792 return false;
1793 }
1794
1795 return mMetadata.readMetadataXml( myRoot );
1796}
1797
1798bool QgsMapLayer::importNamedStyle( QDomDocument &myDocument, QString &myErrorMessage, QgsMapLayer::StyleCategories categories )
1799{
1801
1802 const QDomElement myRoot = myDocument.firstChildElement( QStringLiteral( "qgis" ) );
1803 if ( myRoot.isNull() )
1804 {
1805 myErrorMessage = tr( "Root <qgis> element could not be found" );
1806 return false;
1807 }
1808
1809 // get style file version string, if any
1810 const QgsProjectVersion fileVersion( myRoot.attribute( QStringLiteral( "version" ) ) );
1811 const QgsProjectVersion thisVersion( Qgis::version() );
1812
1813 if ( thisVersion > fileVersion )
1814 {
1815 QgsProjectFileTransform styleFile( myDocument, fileVersion );
1816 styleFile.updateRevision( thisVersion );
1817 }
1818
1819 // Get source categories
1820 const QgsMapLayer::StyleCategories sourceCategories = QgsXmlUtils::readFlagAttribute( myRoot, QStringLiteral( "styleCategories" ), QgsMapLayer::AllStyleCategories );
1821
1822 //Test for matching geometry type on vector layers when applying, if geometry type is given in the style
1823 if ( ( sourceCategories.testFlag( QgsMapLayer::Symbology ) || sourceCategories.testFlag( QgsMapLayer::Symbology3D ) ) &&
1824 ( categories.testFlag( QgsMapLayer::Symbology ) || categories.testFlag( QgsMapLayer::Symbology3D ) ) )
1825 {
1826 if ( type() == Qgis::LayerType::Vector && !myRoot.firstChildElement( QStringLiteral( "layerGeometryType" ) ).isNull() )
1827 {
1828 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( this );
1829 const Qgis::GeometryType importLayerGeometryType = static_cast<Qgis::GeometryType>( myRoot.firstChildElement( QStringLiteral( "layerGeometryType" ) ).text().toInt() );
1830 if ( importLayerGeometryType != Qgis::GeometryType::Unknown && vl->geometryType() != importLayerGeometryType )
1831 {
1832 myErrorMessage = tr( "Cannot apply style with symbology to layer with a different geometry type" );
1833 return false;
1834 }
1835 }
1836 }
1837
1839 return readSymbology( myRoot, myErrorMessage, context, categories ); // TODO: support relative paths in QML?
1840}
1841
1842void QgsMapLayer::exportNamedMetadata( QDomDocument &doc, QString &errorMsg ) const
1843{
1845
1846 QDomImplementation DomImplementation;
1847 const QDomDocumentType documentType = DomImplementation.createDocumentType( QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
1848 QDomDocument myDocument( documentType );
1849
1850 QDomElement myRootNode = myDocument.createElement( QStringLiteral( "qgis" ) );
1851 myRootNode.setAttribute( QStringLiteral( "version" ), Qgis::version() );
1852 myDocument.appendChild( myRootNode );
1853
1854 if ( !mMetadata.writeMetadataXml( myRootNode, myDocument ) )
1855 {
1856 errorMsg = QObject::tr( "Could not save metadata" );
1857 return;
1858 }
1859
1860 doc = myDocument;
1861}
1862
1863void QgsMapLayer::exportNamedStyle( QDomDocument &doc, QString &errorMsg, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1864{
1866
1867 QDomImplementation DomImplementation;
1868 const QDomDocumentType documentType = DomImplementation.createDocumentType( QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
1869 QDomDocument myDocument( documentType );
1870
1871 QDomElement myRootNode = myDocument.createElement( QStringLiteral( "qgis" ) );
1872 myRootNode.setAttribute( QStringLiteral( "version" ), Qgis::version() );
1873 myDocument.appendChild( myRootNode );
1874
1875 if ( !writeSymbology( myRootNode, myDocument, errorMsg, context, categories ) ) // TODO: support relative paths in QML?
1876 {
1877 errorMsg = QObject::tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1878 return;
1879 }
1880
1881 /*
1882 * Check to see if the layer is vector - in which case we should also export its geometryType
1883 * to avoid eventually pasting to a layer with a different geometry
1884 */
1885 if ( type() == Qgis::LayerType::Vector )
1886 {
1887 //Getting the selectionLayer geometry
1888 const QgsVectorLayer *vl = qobject_cast<const QgsVectorLayer *>( this );
1889 const QString geoType = QString::number( static_cast<int>( vl->geometryType() ) );
1890
1891 //Adding geometryinformation
1892 QDomElement layerGeometryType = myDocument.createElement( QStringLiteral( "layerGeometryType" ) );
1893 const QDomText type = myDocument.createTextNode( geoType );
1894
1895 layerGeometryType.appendChild( type );
1896 myRootNode.appendChild( layerGeometryType );
1897 }
1898
1899 doc = myDocument;
1900}
1901
1902QString QgsMapLayer::saveDefaultStyle( bool &resultFlag )
1903{
1905
1906 return saveDefaultStyle( resultFlag, AllStyleCategories );
1907}
1908
1909QString QgsMapLayer::saveDefaultStyle( bool &resultFlag, StyleCategories categories )
1910{
1912
1913 return saveNamedStyle( styleURI(), resultFlag, categories );
1914}
1915
1916QString QgsMapLayer::saveNamedMetadata( const QString &uri, bool &resultFlag )
1917{
1919
1920 return saveNamedProperty( uri, QgsMapLayer::Metadata, resultFlag );
1921}
1922
1923QString QgsMapLayer::loadNamedMetadata( const QString &uri, bool &resultFlag )
1924{
1926
1927 bool metadataExists = false;
1928 bool metadataSuccessfullyLoaded = false;
1929 const QString message = loadNamedProperty( uri, QgsMapLayer::Metadata, metadataExists, metadataSuccessfullyLoaded );
1930
1931 // TODO QGIS 4.0 -- fix API for loadNamedMetadata so we can return metadataExists too
1932 ( void )metadataExists;
1933 resultFlag = metadataSuccessfullyLoaded;
1934 return message;
1935}
1936
1937QString QgsMapLayer::saveNamedProperty( const QString &uri, QgsMapLayer::PropertyType type, bool &resultFlag, StyleCategories categories )
1938{
1940
1941 // check if the uri is a file or ends with .qml/.qmd,
1942 // which indicates that it should become one
1943 // everything else goes to the database
1944 QString filename;
1945
1946 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this );
1947 if ( vlayer && vlayer->providerType() == QLatin1String( "ogr" ) )
1948 {
1949 QStringList theURIParts = uri.split( '|' );
1950 filename = theURIParts[0];
1951 }
1952 else if ( vlayer && vlayer->providerType() == QLatin1String( "gpx" ) )
1953 {
1954 QStringList theURIParts = uri.split( '?' );
1955 filename = theURIParts[0];
1956 }
1957 else if ( vlayer && vlayer->providerType() == QLatin1String( "delimitedtext" ) )
1958 {
1959 filename = QUrl::fromEncoded( uri.toLatin1() ).toLocalFile();
1960 // toLocalFile() returns an empty string if theURI is a plain Windows-path, e.g. "C:/style.qml"
1961 if ( filename.isEmpty() )
1962 filename = uri;
1963 }
1964 else
1965 {
1966 filename = uri;
1967 }
1968
1969 QString myErrorMessage;
1970 QDomDocument myDocument;
1971 switch ( type )
1972 {
1973 case Metadata:
1974 exportNamedMetadata( myDocument, myErrorMessage );
1975 break;
1976
1977 case Style:
1978 const QgsReadWriteContext context;
1979 exportNamedStyle( myDocument, myErrorMessage, context, categories );
1980 break;
1981 }
1982
1983 const QFileInfo myFileInfo( filename );
1984 if ( myFileInfo.exists() || filename.endsWith( QgsMapLayer::extensionPropertyType( type ), Qt::CaseInsensitive ) )
1985 {
1986 const QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
1987 if ( !myDirInfo.isWritable() )
1988 {
1989 resultFlag = false;
1990 return tr( "The directory containing your dataset needs to be writable!" );
1991 }
1992
1993 // now construct the file name for our .qml or .qmd file
1994 const QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + QgsMapLayer::extensionPropertyType( type );
1995
1996 QFile myFile( myFileName );
1997 if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
1998 {
1999 QTextStream myFileStream( &myFile );
2000 // save as utf-8 with 2 spaces for indents
2001 myDocument.save( myFileStream, 2 );
2002 myFile.close();
2003 resultFlag = true;
2004 switch ( type )
2005 {
2006 case Metadata:
2007 return tr( "Created default metadata file as %1" ).arg( myFileName );
2008
2009 case Style:
2010 return tr( "Created default style file as %1" ).arg( myFileName );
2011 }
2012
2013 }
2014 else
2015 {
2016 resultFlag = false;
2017 switch ( type )
2018 {
2019 case Metadata:
2020 return tr( "ERROR: Failed to created default metadata file as %1. Check file permissions and retry." ).arg( myFileName );
2021
2022 case Style:
2023 return tr( "ERROR: Failed to created default style file as %1. Check file permissions and retry." ).arg( myFileName );
2024 }
2025 }
2026 }
2027 else
2028 {
2029 const QString qml = myDocument.toString();
2030
2031 // read from database
2034
2035 int myResult = database.open( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ) );
2036 if ( myResult != SQLITE_OK )
2037 {
2038 return tr( "User database could not be opened." );
2039 }
2040
2041 QByteArray param0 = uri.toUtf8();
2042 QByteArray param1 = qml.toUtf8();
2043
2044 QString mySql;
2045 switch ( type )
2046 {
2047 case Metadata:
2048 mySql = QStringLiteral( "create table if not exists tbl_metadata(metadata varchar primary key,qmd varchar)" );
2049 break;
2050
2051 case Style:
2052 mySql = QStringLiteral( "create table if not exists tbl_styles(style varchar primary key,qml varchar)" );
2053 break;
2054 }
2055
2056 statement = database.prepare( mySql, myResult );
2057 if ( myResult == SQLITE_OK )
2058 {
2059 if ( sqlite3_step( statement.get() ) != SQLITE_DONE )
2060 {
2061 resultFlag = false;
2062 switch ( type )
2063 {
2064 case Metadata:
2065 return tr( "The metadata table could not be created." );
2066
2067 case Style:
2068 return tr( "The style table could not be created." );
2069 }
2070 }
2071 }
2072
2073 switch ( type )
2074 {
2075 case Metadata:
2076 mySql = QStringLiteral( "insert into tbl_metadata(metadata,qmd) values (?,?)" );
2077 break;
2078
2079 case Style:
2080 mySql = QStringLiteral( "insert into tbl_styles(style,qml) values (?,?)" );
2081 break;
2082 }
2083 statement = database.prepare( mySql, myResult );
2084 if ( myResult == SQLITE_OK )
2085 {
2086 if ( sqlite3_bind_text( statement.get(), 1, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
2087 sqlite3_bind_text( statement.get(), 2, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
2088 sqlite3_step( statement.get() ) == SQLITE_DONE )
2089 {
2090 resultFlag = true;
2091 switch ( type )
2092 {
2093 case Metadata:
2094 myErrorMessage = tr( "The metadata %1 was saved to database" ).arg( uri );
2095 break;
2096
2097 case Style:
2098 myErrorMessage = tr( "The style %1 was saved to database" ).arg( uri );
2099 break;
2100 }
2101 }
2102 }
2103
2104 if ( !resultFlag )
2105 {
2106 QString mySql;
2107 switch ( type )
2108 {
2109 case Metadata:
2110 mySql = QStringLiteral( "update tbl_metadata set qmd=? where metadata=?" );
2111 break;
2112
2113 case Style:
2114 mySql = QStringLiteral( "update tbl_styles set qml=? where style=?" );
2115 break;
2116 }
2117 statement = database.prepare( mySql, myResult );
2118 if ( myResult == SQLITE_OK )
2119 {
2120 if ( sqlite3_bind_text( statement.get(), 2, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
2121 sqlite3_bind_text( statement.get(), 1, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
2122 sqlite3_step( statement.get() ) == SQLITE_DONE )
2123 {
2124 resultFlag = true;
2125 switch ( type )
2126 {
2127 case Metadata:
2128 myErrorMessage = tr( "The metadata %1 was updated in the database." ).arg( uri );
2129 break;
2130
2131 case Style:
2132 myErrorMessage = tr( "The style %1 was updated in the database." ).arg( uri );
2133 break;
2134 }
2135 }
2136 else
2137 {
2138 resultFlag = false;
2139 switch ( type )
2140 {
2141 case Metadata:
2142 myErrorMessage = tr( "The metadata %1 could not be updated in the database." ).arg( uri );
2143 break;
2144
2145 case Style:
2146 myErrorMessage = tr( "The style %1 could not be updated in the database." ).arg( uri );
2147 break;
2148 }
2149 }
2150 }
2151 else
2152 {
2153 resultFlag = false;
2154 switch ( type )
2155 {
2156 case Metadata:
2157 myErrorMessage = tr( "The metadata %1 could not be inserted into database." ).arg( uri );
2158 break;
2159
2160 case Style:
2161 myErrorMessage = tr( "The style %1 could not be inserted into database." ).arg( uri );
2162 break;
2163 }
2164 }
2165 }
2166 }
2167
2168 return myErrorMessage;
2169}
2170
2171QString QgsMapLayer::saveNamedStyle( const QString &uri, bool &resultFlag, StyleCategories categories )
2172{
2174
2175 return saveNamedProperty( uri, QgsMapLayer::Style, resultFlag, categories );
2176}
2177
2178void QgsMapLayer::exportSldStyle( QDomDocument &doc, QString &errorMsg ) const
2179{
2180
2181 return exportSldStyleV2( doc, errorMsg, QgsSldExportContext() );
2182}
2183
2184void QgsMapLayer::exportSldStyleV2( QDomDocument &doc, QString &errorMsg, const QgsSldExportContext &exportContext ) const
2185{
2187
2188 QDomDocument myDocument = QDomDocument();
2189
2190 const QDomNode header = myDocument.createProcessingInstruction( QStringLiteral( "xml" ), QStringLiteral( "version=\"1.0\" encoding=\"UTF-8\"" ) );
2191 myDocument.appendChild( header );
2192
2193 const QgsVectorLayer *vlayer = qobject_cast<const QgsVectorLayer *>( this );
2194 const QgsRasterLayer *rlayer = qobject_cast<const QgsRasterLayer *>( this );
2195 if ( !vlayer && !rlayer )
2196 {
2197 errorMsg = tr( "Could not save symbology because:\n%1" )
2198 .arg( tr( "Only vector and raster layers are supported" ) );
2199 return;
2200 }
2201
2202 // Create the root element
2203 QDomElement root = myDocument.createElementNS( QStringLiteral( "http://www.opengis.net/sld" ), QStringLiteral( "StyledLayerDescriptor" ) );
2204 QDomElement layerNode;
2205 if ( vlayer )
2206 {
2207 root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.1.0" ) );
2208 root.setAttribute( QStringLiteral( "xsi:schemaLocation" ), QStringLiteral( "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" ) );
2209 root.setAttribute( QStringLiteral( "xmlns:ogc" ), QStringLiteral( "http://www.opengis.net/ogc" ) );
2210 root.setAttribute( QStringLiteral( "xmlns:se" ), QStringLiteral( "http://www.opengis.net/se" ) );
2211 root.setAttribute( QStringLiteral( "xmlns:xlink" ), QStringLiteral( "http://www.w3.org/1999/xlink" ) );
2212 root.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) );
2213 myDocument.appendChild( root );
2214
2215 // Create the NamedLayer element
2216 layerNode = myDocument.createElement( QStringLiteral( "NamedLayer" ) );
2217 root.appendChild( layerNode );
2218 }
2219
2220 // note: Only SLD 1.0 version is generated because seems none is using SE1.1.0 at least for rasters
2221 if ( rlayer )
2222 {
2223 // Create the root element
2224 root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0.0" ) );
2225 root.setAttribute( QStringLiteral( "xmlns:gml" ), QStringLiteral( "http://www.opengis.net/gml" ) );
2226 root.setAttribute( QStringLiteral( "xmlns:ogc" ), QStringLiteral( "http://www.opengis.net/ogc" ) );
2227 root.setAttribute( QStringLiteral( "xmlns:sld" ), QStringLiteral( "http://www.opengis.net/sld" ) );
2228 myDocument.appendChild( root );
2229
2230 // Create the NamedLayer element
2231 layerNode = myDocument.createElement( QStringLiteral( "UserLayer" ) );
2232 root.appendChild( layerNode );
2233 }
2234
2235 QVariantMap props;
2236
2237 QVariant context;
2238 context.setValue( exportContext );
2239
2240 props[ QStringLiteral( "SldExportContext" ) ] = context;
2241
2243 {
2244 props[ QStringLiteral( "scaleMinDenom" ) ] = QString::number( mMinScale );
2245 props[ QStringLiteral( "scaleMaxDenom" ) ] = QString::number( mMaxScale );
2246 }
2247
2248 if ( vlayer )
2249 {
2250 if ( !vlayer->writeSld( layerNode, myDocument, errorMsg, props ) )
2251 {
2252 errorMsg = tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
2253 return;
2254 }
2255 }
2256
2257 if ( rlayer )
2258 {
2259 if ( !rlayer->writeSld( layerNode, myDocument, errorMsg, props ) )
2260 {
2261 errorMsg = tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
2262 return;
2263 }
2264 }
2265
2266 doc = myDocument;
2267}
2268
2269QString QgsMapLayer::saveSldStyle( const QString &uri, bool &resultFlag ) const
2270{
2271 QgsSldExportContext context;
2272 context.setExportFilePath( uri );
2273 return saveSldStyleV2( resultFlag, context );
2274}
2275
2276QString QgsMapLayer::saveSldStyleV2( bool &resultFlag, const QgsSldExportContext &exportContext ) const
2277{
2279
2280 const QgsMapLayer *mlayer = qobject_cast<const QgsMapLayer *>( this );
2281
2282 const QString uri { exportContext.exportFilePath() };
2283
2284 // check if the uri is a file or ends with .sld,
2285 // which indicates that it should become one
2286 QString filename;
2287 if ( mlayer->providerType() == QLatin1String( "ogr" ) )
2288 {
2289 QStringList theURIParts = uri.split( '|' );
2290 filename = theURIParts[0];
2291 }
2292 else if ( mlayer->providerType() == QLatin1String( "gpx" ) )
2293 {
2294 QStringList theURIParts = uri.split( '?' );
2295 filename = theURIParts[0];
2296 }
2297 else if ( mlayer->providerType() == QLatin1String( "delimitedtext" ) )
2298 {
2299 filename = QUrl::fromEncoded( uri.toLatin1() ).toLocalFile();
2300 // toLocalFile() returns an empty string if theURI is a plain Windows-path, e.g. "C:/style.qml"
2301 if ( filename.isEmpty() )
2302 filename = uri;
2303 }
2304 else
2305 {
2306 filename = uri;
2307 }
2308
2309 const QFileInfo myFileInfo( filename );
2310 if ( myFileInfo.exists() || filename.endsWith( QLatin1String( ".sld" ), Qt::CaseInsensitive ) )
2311 {
2312 const QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
2313 if ( !myDirInfo.isWritable() )
2314 {
2315 resultFlag = false;
2316 return tr( "The directory containing your dataset needs to be writable!" );
2317 }
2318
2319 // now construct the file name for our .sld style file
2320 const QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".sld";
2321
2322 QString errorMsg;
2323 QDomDocument myDocument;
2324
2325 QgsSldExportContext context { exportContext };
2326 context.setExportFilePath( myFileName );
2327
2328 mlayer->exportSldStyleV2( myDocument, errorMsg, context );
2329
2330 if ( !errorMsg.isNull() )
2331 {
2332 resultFlag = false;
2333 return errorMsg;
2334 }
2335
2336 QFile myFile( myFileName );
2337 if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
2338 {
2339 QTextStream myFileStream( &myFile );
2340 // save as utf-8 with 2 spaces for indents
2341 myDocument.save( myFileStream, 2 );
2342 myFile.close();
2343 resultFlag = true;
2344 return tr( "Created default style file as %1" ).arg( myFileName );
2345 }
2346 }
2347
2348 resultFlag = false;
2349 return tr( "ERROR: Failed to created SLD style file as %1. Check file permissions and retry." ).arg( filename );
2350
2351}
2352
2353QString QgsMapLayer::loadSldStyle( const QString &uri, bool &resultFlag )
2354{
2356
2357 resultFlag = false;
2358
2359 QDomDocument myDocument;
2360
2361 // location of problem associated with errorMsg
2362 int line, column;
2363 QString myErrorMessage;
2364
2365 QFile myFile( uri );
2366 if ( myFile.open( QFile::ReadOnly ) )
2367 {
2368 // read file
2369 resultFlag = myDocument.setContent( &myFile, true, &myErrorMessage, &line, &column );
2370 if ( !resultFlag )
2371 myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
2372 myFile.close();
2373 }
2374 else
2375 {
2376 myErrorMessage = tr( "Unable to open file %1" ).arg( uri );
2377 }
2378
2379 if ( !resultFlag )
2380 {
2381 return myErrorMessage;
2382 }
2383
2384 // check for root SLD element
2385 const QDomElement myRoot = myDocument.firstChildElement( QStringLiteral( "StyledLayerDescriptor" ) );
2386 if ( myRoot.isNull() )
2387 {
2388 myErrorMessage = QStringLiteral( "Error: StyledLayerDescriptor element not found in %1" ).arg( uri );
2389 resultFlag = false;
2390 return myErrorMessage;
2391 }
2392
2393 // now get the style node out and pass it over to the layer
2394 // to deserialise...
2395 const QDomElement namedLayerElem = myRoot.firstChildElement( QStringLiteral( "NamedLayer" ) );
2396 if ( namedLayerElem.isNull() )
2397 {
2398 myErrorMessage = QStringLiteral( "Info: NamedLayer element not found." );
2399 resultFlag = false;
2400 return myErrorMessage;
2401 }
2402
2403 QString errorMsg;
2404 resultFlag = readSld( namedLayerElem, errorMsg );
2405 if ( !resultFlag )
2406 {
2407 myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( uri, errorMsg );
2408 return myErrorMessage;
2409 }
2410
2411 return QString();
2412}
2413
2414bool QgsMapLayer::readStyle( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
2415{
2417
2418 Q_UNUSED( node )
2419 Q_UNUSED( errorMessage )
2420 Q_UNUSED( context )
2421 Q_UNUSED( categories )
2422 return false;
2423}
2424
2425bool QgsMapLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage,
2426 const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
2427{
2429
2430 Q_UNUSED( node )
2431 Q_UNUSED( doc )
2432 Q_UNUSED( errorMessage )
2433 Q_UNUSED( context )
2434 Q_UNUSED( categories )
2435 return false;
2436}
2437
2438
2439void QgsMapLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider,
2440 bool loadDefaultStyleFlag )
2441{
2443
2445
2447 if ( loadDefaultStyleFlag )
2448 {
2450 }
2451
2453 {
2455 }
2456 setDataSource( dataSource,
2457 baseName.isEmpty() ? mLayerName : baseName,
2458 provider.isEmpty() ? mProviderKey : provider,
2459 options, flags );
2460}
2461
2462void QgsMapLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider,
2463 const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag )
2464{
2466
2468 if ( loadDefaultStyleFlag )
2469 {
2471 }
2472
2474 {
2476 }
2477 setDataSource( dataSource, baseName, provider, options, flags );
2478}
2479
2480void QgsMapLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider,
2482{
2484
2487 {
2489 }
2490 setDataSourcePrivate( dataSource, baseName, provider, options, flags );
2491 emit dataSourceChanged();
2492 emit dataChanged();
2494}
2495
2496
2497void QgsMapLayer::setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider,
2499{
2501
2502 Q_UNUSED( dataSource )
2503 Q_UNUSED( baseName )
2504 Q_UNUSED( provider )
2505 Q_UNUSED( options )
2506 Q_UNUSED( flags )
2507}
2508
2509
2511{
2513
2514 return mProviderKey;
2515}
2516
2517void QgsMapLayer::readCommonStyle( const QDomElement &layerElement, const QgsReadWriteContext &context,
2518 QgsMapLayer::StyleCategories categories )
2519{
2521
2522 if ( categories.testFlag( Symbology3D ) )
2523 {
2524 const QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "3D Symbology" ) );
2525
2526 QgsAbstract3DRenderer *r3D = nullptr;
2527 QDomElement renderer3DElem = layerElement.firstChildElement( QStringLiteral( "renderer-3d" ) );
2528 if ( !renderer3DElem.isNull() )
2529 {
2530 const QString type3D = renderer3DElem.attribute( QStringLiteral( "type" ) );
2532 if ( meta3D )
2533 {
2534 r3D = meta3D->createRenderer( renderer3DElem, context );
2535 }
2536 }
2537 setRenderer3D( r3D );
2538 }
2539
2540 if ( categories.testFlag( CustomProperties ) )
2541 {
2542 // read custom properties before passing reading further to a subclass, so that
2543 // the subclass can also read custom properties
2544 readCustomProperties( layerElement );
2545 }
2546
2547 // use scale dependent visibility flag
2548 if ( categories.testFlag( Rendering ) )
2549 {
2550 setScaleBasedVisibility( layerElement.attribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ) ).toInt() == 1 );
2551 if ( layerElement.hasAttribute( QStringLiteral( "minimumScale" ) ) )
2552 {
2553 // older element, when scales were reversed
2554 setMaximumScale( layerElement.attribute( QStringLiteral( "minimumScale" ) ).toDouble() );
2555 setMinimumScale( layerElement.attribute( QStringLiteral( "maximumScale" ) ).toDouble() );
2556 }
2557 else
2558 {
2559 setMaximumScale( layerElement.attribute( QStringLiteral( "maxScale" ) ).toDouble() );
2560 setMinimumScale( layerElement.attribute( QStringLiteral( "minScale" ) ).toDouble() );
2561 }
2562 if ( layerElement.hasAttribute( QStringLiteral( "autoRefreshMode" ) ) )
2563 {
2564 setAutoRefreshMode( qgsEnumKeyToValue( layerElement.attribute( QStringLiteral( "autoRefreshMode" ) ), Qgis::AutoRefreshMode::Disabled ) );
2565 setAutoRefreshInterval( layerElement.attribute( QStringLiteral( "autoRefreshTime" ) ).toInt() );
2566 }
2567 }
2568
2569 if ( categories.testFlag( LayerConfiguration ) )
2570 {
2571 // flags
2572 const QDomElement flagsElem = layerElement.firstChildElement( QStringLiteral( "flags" ) );
2573 LayerFlags flags = mFlags;
2574 const auto enumMap = qgsEnumMap<QgsMapLayer::LayerFlag>();
2575 for ( auto it = enumMap.constBegin(); it != enumMap.constEnd(); ++it )
2576 {
2577 const QDomNode flagNode = flagsElem.namedItem( it.value() );
2578 if ( flagNode.isNull() )
2579 continue;
2580 const bool flagValue = flagNode.toElement().text() == "1" ? true : false;
2581 if ( flags.testFlag( it.key() ) && !flagValue )
2582 flags &= ~it.key();
2583 else if ( !flags.testFlag( it.key() ) && flagValue )
2584 flags |= it.key();
2585 }
2586 setFlags( flags );
2587 }
2588
2589 if ( categories.testFlag( Temporal ) )
2590 {
2591 const QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Temporal" ) );
2592
2594 properties->readXml( layerElement.toElement(), context );
2595 }
2596
2597 if ( categories.testFlag( Elevation ) )
2598 {
2599 const QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Elevation" ) );
2600
2602 properties->readXml( layerElement.toElement(), context );
2603 }
2604
2605 if ( categories.testFlag( Notes ) )
2606 {
2607 const QDomElement notesElem = layerElement.firstChildElement( QStringLiteral( "userNotes" ) );
2608 if ( !notesElem.isNull() )
2609 {
2610 const QString notes = notesElem.attribute( QStringLiteral( "value" ) );
2611 QgsLayerNotesUtils::setLayerNotes( this, notes );
2612 }
2613 }
2614}
2615
2617{
2619
2620 return mUndoStack;
2621}
2622
2624{
2626
2627 return mUndoStackStyles;
2628}
2629
2631{
2633
2634 return mCustomProperties.keys();
2635}
2636
2637void QgsMapLayer::setCustomProperty( const QString &key, const QVariant &value )
2638{
2640
2641 if ( !mCustomProperties.contains( key ) || mCustomProperties.value( key ) != value )
2642 {
2643 mCustomProperties.setValue( key, value );
2644 emit customPropertyChanged( key );
2645 }
2646}
2647
2649{
2651
2652 mCustomProperties = properties;
2653 for ( const QString &key : mCustomProperties.keys() )
2654 {
2655 emit customPropertyChanged( key );
2656 }
2657}
2658
2660{
2662
2663 return mCustomProperties;
2664}
2665
2666QVariant QgsMapLayer::customProperty( const QString &value, const QVariant &defaultValue ) const
2667{
2668 // non fatal for now -- the "rasterize" processing algorithm is not thread safe and calls this
2670
2671 return mCustomProperties.value( value, defaultValue );
2672}
2673
2674void QgsMapLayer::removeCustomProperty( const QString &key )
2675{
2677
2678 if ( mCustomProperties.contains( key ) )
2679 {
2680 mCustomProperties.remove( key );
2681 emit customPropertyChanged( key );
2682 }
2683}
2684
2685int QgsMapLayer::listStylesInDatabase( QStringList &ids, QStringList &names, QStringList &descriptions, QString &msgError )
2686{
2688
2689 return QgsProviderRegistry::instance()->listStyles( mProviderKey, mDataSource, ids, names, descriptions, msgError );
2690}
2691
2692QString QgsMapLayer::getStyleFromDatabase( const QString &styleId, QString &msgError )
2693{
2695
2696 return QgsProviderRegistry::instance()->getStyleById( mProviderKey, mDataSource, styleId, msgError );
2697}
2698
2699bool QgsMapLayer::deleteStyleFromDatabase( const QString &styleId, QString &msgError )
2700{
2702
2704}
2705
2706void QgsMapLayer::saveStyleToDatabase( const QString &name, const QString &description,
2707 bool useAsDefault, const QString &uiFileContent, QString &msgError, QgsMapLayer::StyleCategories categories )
2708{
2710
2711 QString sldStyle, qmlStyle;
2712 QDomDocument qmlDocument, sldDocument;
2713 QgsReadWriteContext context;
2714 exportNamedStyle( qmlDocument, msgError, context, categories );
2715 if ( !msgError.isNull() )
2716 {
2717 return;
2718 }
2719 qmlStyle = qmlDocument.toString();
2720
2721 this->exportSldStyle( sldDocument, msgError );
2722 if ( !msgError.isNull() )
2723 {
2724 return;
2725 }
2726 sldStyle = sldDocument.toString();
2727
2729 mDataSource, qmlStyle, sldStyle, name,
2730 description, uiFileContent, useAsDefault, msgError );
2731}
2732
2733QString QgsMapLayer::loadNamedStyle( const QString &theURI, bool &resultFlag, bool loadFromLocalDB, QgsMapLayer::StyleCategories categories, Qgis::LoadStyleFlags flags )
2734{
2736
2737 QString returnMessage;
2738 QString qml, errorMsg;
2739 QString styleName;
2740 if ( !loadFromLocalDB && dataProvider() && dataProvider()->styleStorageCapabilities().testFlag( Qgis::ProviderStyleStorageCapability::LoadFromDatabase ) )
2741 {
2743 }
2744
2745 // Style was successfully loaded from provider storage
2746 if ( !qml.isEmpty() )
2747 {
2748 QDomDocument myDocument( QStringLiteral( "qgis" ) );
2749 myDocument.setContent( qml );
2750 resultFlag = importNamedStyle( myDocument, errorMsg );
2751 returnMessage = QObject::tr( "Loaded from Provider" );
2752 }
2753 else
2754 {
2756
2757 bool styleExists = false;
2758 bool styleSuccessfullyLoaded = false;
2759
2760 returnMessage = loadNamedProperty( theURI, PropertyType::Style, styleExists, styleSuccessfullyLoaded, categories, flags );
2761
2762 // TODO QGIS 4.0 -- fix API for loadNamedStyle so we can return styleExists too
2763 ( void )styleExists;
2764 resultFlag = styleSuccessfullyLoaded;
2765 }
2766
2767 if ( ! styleName.isEmpty() )
2768 {
2769 styleManager()->renameStyle( styleManager()->currentStyle(), styleName );
2770 }
2771
2772 if ( resultFlag )
2773 emit styleLoaded( categories );
2774
2775 return returnMessage;
2776}
2777
2784
2786{
2788
2789 return false;
2790}
2791
2793{
2795
2796 return false;
2797}
2798
2800{
2802
2803 return true;
2804}
2805
2807{
2809
2810 // invalid layers are temporary? -- who knows?!
2811 if ( !isValid() )
2812 return false;
2813
2814 if ( mProviderKey == QLatin1String( "memory" ) )
2815 return true;
2816
2817 const QVariantMap sourceParts = QgsProviderRegistry::instance()->decodeUri( mProviderKey, mDataSource );
2818 const QString path = sourceParts.value( QStringLiteral( "path" ) ).toString();
2819 if ( path.isEmpty() )
2820 return false;
2821
2822 // check if layer path is inside one of the standard temporary file locations for this platform
2823 const QStringList tempPaths = QStandardPaths::standardLocations( QStandardPaths::TempLocation );
2824 for ( const QString &tempPath : tempPaths )
2825 {
2826 if ( path.startsWith( tempPath ) )
2827 return true;
2828 }
2829
2830 return false;
2831}
2832
2833void QgsMapLayer::setValid( bool valid )
2834{
2836
2837 if ( mValid == valid )
2838 return;
2839
2840 mValid = valid;
2841 emit isValidChanged();
2842}
2843
2845{
2847
2848 if ( legend == mLegend )
2849 return;
2850
2851 delete mLegend;
2852 mLegend = legend;
2853
2854 if ( mLegend )
2855 {
2856 mLegend->setParent( this );
2857 connect( mLegend, &QgsMapLayerLegend::itemsChanged, this, &QgsMapLayer::legendChanged, Qt::UniqueConnection );
2858 }
2859
2860 emit legendChanged();
2861}
2862
2864{
2866
2867 return mLegend;
2868}
2869
2871{
2873
2874 return mStyleManager;
2875}
2876
2878{
2880
2881 if ( renderer == m3DRenderer )
2882 return;
2883
2884 delete m3DRenderer;
2885 m3DRenderer = renderer;
2886 emit renderer3DChanged();
2887 emit repaintRequested();
2889}
2890
2892{
2894
2895 return m3DRenderer;
2896}
2897
2898void QgsMapLayer::triggerRepaint( bool deferredUpdate )
2899{
2901
2902 if ( mRepaintRequestedFired )
2903 return;
2904 mRepaintRequestedFired = true;
2905 emit repaintRequested( deferredUpdate );
2906 mRepaintRequestedFired = false;
2907}
2908
2915
2917{
2919
2920 mMetadata = metadata;
2921// mMetadata.saveToLayer( this );
2922 emit metadataChanged();
2923}
2924
2926{
2928
2929 return QString();
2930}
2931
2932QDateTime QgsMapLayer::timestamp() const
2933{
2935
2936 return QDateTime();
2937}
2938
2946
2948{
2949 updateExtent( extent );
2950}
2951
2953{
2955
2956 updateExtent( extent );
2957}
2958
2959bool QgsMapLayer::isReadOnly() const
2960{
2962
2963 return true;
2964}
2965
2967{
2969
2970 return mOriginalXmlProperties;
2971}
2972
2973void QgsMapLayer::setOriginalXmlProperties( const QString &originalXmlProperties )
2974{
2976
2977 mOriginalXmlProperties = originalXmlProperties;
2978}
2979
2980QString QgsMapLayer::generateId( const QString &layerName )
2981{
2982 // Generate the unique ID of this layer
2983 const QString uuid = QUuid::createUuid().toString();
2984 // trim { } from uuid
2985 QString id = layerName + '_' + uuid.mid( 1, uuid.length() - 2 );
2986 // Tidy the ID up to avoid characters that may cause problems
2987 // elsewhere (e.g in some parts of XML). Replaces every non-word
2988 // character (word characters are the alphabet, numbers and
2989 // underscore) with an underscore.
2990 // Note that the first backslash in the regular expression is
2991 // there for the compiler, so the pattern is actually \W
2992 const thread_local QRegularExpression idRx( QStringLiteral( "[\\W]" ) );
2993 id.replace( idRx, QStringLiteral( "_" ) );
2994 return id;
2995}
2996
2998{
3000
3001 return true;
3002}
3003
3005{
3007
3008 return mapTipsEnabled() && !mMapTipTemplate.isEmpty();
3009}
3010
3011void QgsMapLayer::setProviderType( const QString &providerType )
3012{
3014
3016}
3017
3018QSet<QgsMapLayerDependency> QgsMapLayer::dependencies() const
3019{
3021
3022 return mDependencies;
3023}
3024
3025bool QgsMapLayer::setDependencies( const QSet<QgsMapLayerDependency> &oDeps )
3026{
3028
3029 QSet<QgsMapLayerDependency> deps;
3030 const auto constODeps = oDeps;
3031 for ( const QgsMapLayerDependency &dep : constODeps )
3032 {
3033 if ( dep.origin() == QgsMapLayerDependency::FromUser )
3034 deps << dep;
3035 }
3036
3037 mDependencies = deps;
3038 emit dependenciesChanged();
3039 return true;
3040}
3041
3043{
3045
3046 QgsDataProvider *lDataProvider = dataProvider();
3047
3048 if ( !lDataProvider )
3049 return;
3050
3051 if ( enabled && !isRefreshOnNotifyEnabled() )
3052 {
3053 lDataProvider->setListening( enabled );
3054 connect( lDataProvider, &QgsDataProvider::notify, this, &QgsMapLayer::onNotified );
3055 }
3056 else if ( !enabled && isRefreshOnNotifyEnabled() )
3057 {
3058 // we don't want to disable provider listening because someone else could need it (e.g. actions)
3059 disconnect( lDataProvider, &QgsDataProvider::notify, this, &QgsMapLayer::onNotified );
3060 }
3061 mIsRefreshOnNofifyEnabled = enabled;
3062}
3063
3065{
3067
3068 if ( QgsMapLayerStore *store = qobject_cast<QgsMapLayerStore *>( parent() ) )
3069 {
3070 return qobject_cast<QgsProject *>( store->parent() );
3071 }
3072 return nullptr;
3073}
3074
3075void QgsMapLayer::onNotified( const QString &message )
3076{
3078
3079 if ( refreshOnNotifyMessage().isEmpty() || refreshOnNotifyMessage() == message )
3080 {
3082 emit dataChanged();
3083 }
3084}
3085
3086QgsRectangle QgsMapLayer::wgs84Extent( bool forceRecalculate ) const
3087{
3089
3091
3092 if ( ! forceRecalculate && ! mWgs84Extent.isNull() )
3093 {
3094 wgs84Extent = mWgs84Extent;
3095 }
3096 else if ( ! mExtent2D.isNull() || ! mExtent3D.isNull() )
3097 {
3099 transformer.setBallparkTransformsAreAppropriate( true );
3100 try
3101 {
3102 if ( mExtent2D.isNull() )
3103 wgs84Extent = transformer.transformBoundingBox( mExtent3D.toRectangle() );
3104 else
3105 wgs84Extent = transformer.transformBoundingBox( mExtent2D );
3106 }
3107 catch ( const QgsCsException &cse )
3108 {
3109 QgsMessageLog::logMessage( tr( "Error transforming extent: %1" ).arg( cse.what() ) );
3111 }
3112 }
3113 return wgs84Extent;
3114}
3115
3116void QgsMapLayer::updateExtent( const QgsRectangle &extent ) const
3117{
3119
3120 if ( extent == mExtent2D )
3121 return;
3122
3123 mExtent2D = extent;
3124
3125 // do not update the wgs84 extent if we trust layer metadata
3127 return;
3128
3129 mWgs84Extent = wgs84Extent( true );
3130}
3131
3132void QgsMapLayer::updateExtent( const QgsBox3D &extent ) const
3133{
3135
3136 if ( extent == mExtent3D )
3137 return;
3138
3139 if ( extent.isNull() )
3140 {
3141 if ( !extent.toRectangle().isNull() )
3142 {
3143 // bad 3D extent param but valid in 2d --> update 2D extent
3144 updateExtent( extent.toRectangle() );
3145 }
3146 else
3147 {
3148 QgsDebugMsgLevel( QStringLiteral( "Unable to update extent with empty parameter" ), 1 );
3149 }
3150 }
3151 else
3152 {
3153 mExtent3D = extent;
3154
3155 // do not update the wgs84 extent if we trust layer metadata
3157 return;
3158
3159 mWgs84Extent = wgs84Extent( true );
3160 }
3161}
3162
3163bool QgsMapLayer::rebuildCrs3D( QString *error )
3164{
3165 bool res = true;
3166 if ( !mCRS.isValid() )
3167 {
3169 }
3170 else if ( !mVerticalCrs.isValid() )
3171 {
3172 mCrs3D = mCRS;
3173 }
3174 else
3175 {
3176 switch ( mCRS.type() )
3177 {
3181 mCrs3D = mCRS;
3182 break;
3183
3185 {
3186 QString tempError;
3187 mCrs3D = mCRS.hasVerticalAxis() ? mCRS : QgsCoordinateReferenceSystem::createCompoundCrs( mCRS, mVerticalCrs, error ? *error : tempError );
3188 res = mCrs3D.isValid();
3189 break;
3190 }
3191
3193 // nonsense situation
3195 res = false;
3196 break;
3197
3206 {
3207 QString tempError;
3208 mCrs3D = QgsCoordinateReferenceSystem::createCompoundCrs( mCRS, mVerticalCrs, error ? *error : tempError );
3209 res = mCrs3D.isValid();
3210 break;
3211 }
3212 }
3213 }
3214 return res;
3215}
3216
3218{
3220
3221 // do not update the wgs84 extent if we trust layer metadata
3223 return;
3224
3225 mWgs84Extent = QgsRectangle();
3226}
3227
3229{
3231
3232 QString metadata = QStringLiteral( "<h1>" ) + tr( "General" ) + QStringLiteral( "</h1>\n<hr>\n" ) + QStringLiteral( "<table class=\"list-view\">\n" );
3233
3234 // name
3235 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Name" ) + QStringLiteral( "</td><td>" ) + name() + QStringLiteral( "</td></tr>\n" );
3236
3237 const QString lPublicSource = publicSource();
3238
3239 QString path;
3240 bool isLocalPath = false;
3241 if ( dataProvider() )
3242 {
3243 // local path
3244 QVariantMap uriComponents = QgsProviderRegistry::instance()->decodeUri( dataProvider()->name(), lPublicSource );
3245 if ( uriComponents.contains( QStringLiteral( "path" ) ) )
3246 {
3247 path = uriComponents[QStringLiteral( "path" )].toString();
3248 QFileInfo fi( path );
3249 if ( fi.exists() )
3250 {
3251 isLocalPath = true;
3252 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" );
3253
3254 QDateTime lastModified = fi.lastModified();
3255 QString lastModifiedFileName;
3256 QSet<QString> sidecarFiles = QgsFileUtils::sidecarFilesForPath( path );
3257 if ( fi.isFile() )
3258 {
3259 qint64 fileSize = fi.size();
3260 if ( !sidecarFiles.isEmpty() )
3261 {
3262 lastModifiedFileName = fi.fileName();
3263 QStringList sidecarFileNames;
3264 for ( const QString &sidecarFile : sidecarFiles )
3265 {
3266 QFileInfo sidecarFi( sidecarFile );
3267 fileSize += sidecarFi.size();
3268 if ( sidecarFi.lastModified() > lastModified )
3269 {
3270 lastModified = sidecarFi.lastModified();
3271 lastModifiedFileName = sidecarFi.fileName();
3272 }
3273 sidecarFileNames << sidecarFi.fileName();
3274 }
3275 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" );
3276 }
3277 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" );
3278 }
3279 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" );
3280 }
3281 }
3282 if ( uriComponents.contains( QStringLiteral( "url" ) ) )
3283 {
3284 const QString url = uriComponents[QStringLiteral( "url" )].toString();
3285 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" );
3286 }
3287 }
3288
3289 // data source
3290 if ( lPublicSource != path || !isLocalPath )
3291 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Source" ) + QStringLiteral( "</td><td>%1" ).arg( lPublicSource != path ? lPublicSource : path ) + QStringLiteral( "</td></tr>\n" );
3292
3293 // provider
3294 if ( dataProvider() )
3295 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Provider" ) + QStringLiteral( "</td><td>%1" ).arg( dataProvider()->name() ) + QStringLiteral( "</td></tr>\n" );
3296
3297 metadata += QLatin1String( "</table>\n<br><br>" );
3298
3299 return metadata;
3300}
3301
3303{
3304 QString metadata;
3305 // custom properties
3306 if ( const auto keys = customPropertyKeys(); !keys.isEmpty() )
3307 {
3308 metadata += QStringLiteral( "<h1>" ) + tr( "Custom properties" ) + QStringLiteral( "</h1>\n<hr>\n" );
3309 metadata += QLatin1String( "<table class=\"list-view\">\n<tbody>" );
3310 for ( const QString &key : keys )
3311 {
3312 // keys prefaced with _ are considered private/internal details
3313 if ( key.startsWith( '_' ) )
3314 continue;
3315
3316 const QVariant propValue = customProperty( key );
3317 QString stringValue;
3318 if ( propValue.type() == QVariant::List || propValue.type() == QVariant::StringList )
3319 {
3320 for ( const QString &s : propValue.toStringList() )
3321 {
3322 stringValue += "<p style=\"margin: 0;\">" + s.toHtmlEscaped() + "</p>";
3323 }
3324 }
3325 else
3326 {
3327 stringValue = propValue.toString().toHtmlEscaped();
3328
3329 //if the result string is empty but propValue is not, the conversion has failed
3330 if ( stringValue.isEmpty() && !QgsVariantUtils::isNull( propValue ) )
3331 stringValue = tr( "<i>value cannot be displayed</i>" );
3332 }
3333
3334 metadata += QStringLiteral( "<tr><td class=\"highlight\">%1</td><td>%2</td></tr>" ).arg( key.toHtmlEscaped(), stringValue );
3335 }
3336 metadata += QLatin1String( "</tbody></table>\n" );
3337 metadata += QLatin1String( "<br><br>\n" );
3338 }
3339 return metadata;
3340}
3341
3343{
3345 QString metadata;
3346
3347 auto addCrsInfo = [&metadata]( const QgsCoordinateReferenceSystem & c, bool includeType, bool includeOperation, bool includeCelestialBody )
3348 {
3349 if ( !c.isValid() )
3350 metadata += QStringLiteral( "<tr><td colspan=\"2\" class=\"highlight\">" ) + tr( "Unknown" ) + QStringLiteral( "</td></tr>\n" );
3351 else
3352 {
3353 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Name" ) + QStringLiteral( "</td><td>" ) + c.userFriendlyIdentifier( Qgis::CrsIdentifierType::FullString ) + QStringLiteral( "</td></tr>\n" );
3354
3355 // map units
3356 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Units" ) + QStringLiteral( "</td><td>" )
3357 + ( c.isGeographic() ? tr( "Geographic (uses latitude and longitude for coordinates)" ) : QgsUnitTypes::toString( c.mapUnits() ) )
3358 + QStringLiteral( "</td></tr>\n" );
3359
3360 if ( includeType )
3361 {
3362 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Type" ) + QStringLiteral( "</td><td>" ) + QgsCoordinateReferenceSystemUtils::crsTypeToString( c.type() ) + QStringLiteral( "</td></tr>\n" );
3363 }
3364
3365 if ( includeOperation )
3366 {
3367 // operation
3368 const QgsProjOperation operation = c.operation();
3369 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Method" ) + QStringLiteral( "</td><td>" ) + operation.description() + QStringLiteral( "</td></tr>\n" );
3370 }
3371
3372 if ( includeCelestialBody )
3373 {
3374 // celestial body
3375 try
3376 {
3377 const QString celestialBody = c.celestialBodyName();
3378 if ( !celestialBody.isEmpty() )
3379 {
3380 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Celestial Body" ) + QStringLiteral( "</td><td>" ) + celestialBody + QStringLiteral( "</td></tr>\n" );
3381 }
3382 }
3383 catch ( QgsNotSupportedException & )
3384 {
3385
3386 }
3387 }
3388
3389 QString accuracyString;
3390 // dynamic crs with no epoch?
3391 if ( c.isDynamic() && std::isnan( c.coordinateEpoch() ) )
3392 {
3393 accuracyString = tr( "Based on a dynamic CRS, but no coordinate epoch is set. Coordinates are ambiguous and of limited accuracy." );
3394 }
3395
3396 // based on datum ensemble?
3397 try
3398 {
3399 const QgsDatumEnsemble ensemble = c.datumEnsemble();
3400 if ( ensemble.isValid() )
3401 {
3402 QString id;
3403 if ( !ensemble.code().isEmpty() )
3404 id = QStringLiteral( "<i>%1</i> (%2:%3)" ).arg( ensemble.name(), ensemble.authority(), ensemble.code() );
3405 else
3406 id = QStringLiteral( "<i>%</i>”" ).arg( ensemble.name() );
3407
3408 if ( ensemble.accuracy() > 0 )
3409 {
3410 accuracyString = tr( "Based on %1, which has a limited accuracy of <b>at best %2 meters</b>." ).arg( id ).arg( ensemble.accuracy() );
3411 }
3412 else
3413 {
3414 accuracyString = tr( "Based on %1, which has a limited accuracy." ).arg( id );
3415 }
3416 }
3417 }
3418 catch ( QgsNotSupportedException & )
3419 {
3420
3421 }
3422
3423 if ( !accuracyString.isEmpty() )
3424 {
3425 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Accuracy" ) + QStringLiteral( "</td><td>" ) + accuracyString + QStringLiteral( "</td></tr>\n" );
3426 }
3427
3428 // static/dynamic
3429 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)" ) );
3430
3431 // coordinate epoch
3432 if ( !std::isnan( c.coordinateEpoch() ) )
3433 {
3434 metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Coordinate Epoch" ) + QStringLiteral( "</td><td>%1</td></tr>\n" ).arg( qgsDoubleToString( c.coordinateEpoch(), 3 ) );
3435 }
3436 }
3437 };
3438
3439 metadata += QStringLiteral( "<h1>" ) + tr( "Coordinate Reference System (CRS)" ) + QStringLiteral( "</h1>\n<hr>\n" );
3440 metadata += QLatin1String( "<table class=\"list-view\">\n" );
3441 addCrsInfo( crs().horizontalCrs(), true, true, true );
3442 metadata += QLatin1String( "</table>\n<br><br>\n" );
3443
3444 if ( verticalCrs().isValid() )
3445 {
3446 metadata += QStringLiteral( "<h1>" ) + tr( "Vertical Coordinate Reference System (CRS)" ) + QStringLiteral( "</h1>\n<hr>\n" );
3447 metadata += QLatin1String( "<table class=\"list-view\">\n" );
3448 addCrsInfo( verticalCrs(), false, false, false );
3449 metadata += QLatin1String( "</table>\n<br><br>\n" );
3450 }
3451
3452 return metadata;
3453}
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:2201
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:2211
@ 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:394
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.
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.
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.
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
QString mLegendUrl
WMS legend.
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.
QString mLegendUrlFormat
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.
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...
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:6335
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:6042
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:6316
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:6125
CONSTLATIN1STRING geoEpsgCrsAuthId()
Geographic coord sys from EPSG authority.
Definition qgis.h:6614
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.