QGIS API Documentation  3.12.1-BucureČ™ti (121cc00ff0)
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 <QDir>
20 #include <QDomDocument>
21 #include <QDomElement>
22 #include <QDomImplementation>
23 #include <QDomNode>
24 #include <QFile>
25 #include <QFileInfo>
26 #include <QTextStream>
27 #include <QUrl>
28 
29 #include <sqlite3.h>
30 
31 #include "qgssqliteutils.h"
32 
33 #include "qgssqliteutils.h"
34 #include "qgs3drendererregistry.h"
35 #include "qgsabstract3drenderer.h"
36 #include "qgsapplication.h"
38 #include "qgsdatasourceuri.h"
39 #include "qgslogger.h"
40 #include "qgsauthmanager.h"
41 #include "qgsmaplayer.h"
42 #include "qgsmaplayerlegend.h"
44 #include "qgsmeshlayer.h"
45 #include "qgspathresolver.h"
47 #include "qgsproject.h"
48 #include "qgsproviderregistry.h"
49 #include "qgsrasterlayer.h"
50 #include "qgsreadwritecontext.h"
51 #include "qgsrectangle.h"
52 #include "qgsvectorlayer.h"
53 #include "qgsvectordataprovider.h"
54 #include "qgsxmlutils.h"
55 #include "qgsstringutils.h"
56 
58 {
59  switch ( type )
60  {
61  case Metadata:
62  return QStringLiteral( ".qmd" );
63 
64  case Style:
65  return QStringLiteral( ".qml" );
66  }
67  return QString();
68 }
69 
71  const QString &lyrname,
72  const QString &source )
73  : mDataSource( source )
74  , mLayerName( lyrname )
75  , mLayerType( type )
76  , mUndoStack( new QUndoStack( this ) )
77  , mUndoStackStyles( new QUndoStack( this ) )
78  , mStyleManager( new QgsMapLayerStyleManager( this ) )
79  , mRefreshTimer( new QTimer( this ) )
80 {
81  mID = generateId( lyrname );
82  connect( this, &QgsMapLayer::crsChanged, this, &QgsMapLayer::configChanged );
83  connect( this, &QgsMapLayer::nameChanged, this, &QgsMapLayer::configChanged );
84  connect( mRefreshTimer, &QTimer::timeout, this, [ = ] { triggerRepaint( true ); } );
85 }
86 
88 {
89  delete m3DRenderer;
90  delete mLegend;
91  delete mStyleManager;
92 }
93 
94 void QgsMapLayer::clone( QgsMapLayer *layer ) const
95 {
96  layer->setBlendMode( blendMode() );
97 
98  const auto constStyles = styleManager()->styles();
99  for ( const QString &s : constStyles )
100  {
101  layer->styleManager()->addStyle( s, styleManager()->style( s ) );
102  }
103 
104  layer->setName( name() );
105  layer->setShortName( shortName() );
106  layer->setExtent( extent() );
107  layer->setMaximumScale( maximumScale() );
108  layer->setMinimumScale( minimumScale() );
110  layer->setTitle( title() );
111  layer->setAbstract( abstract() );
112  layer->setKeywordList( keywordList() );
113  layer->setDataUrl( dataUrl() );
114  layer->setDataUrlFormat( dataUrlFormat() );
115  layer->setAttribution( attribution() );
116  layer->setAttributionUrl( attributionUrl() );
117  layer->setMetadataUrl( metadataUrl() );
120  layer->setLegendUrl( legendUrl() );
122  layer->setDependencies( dependencies() );
124  layer->setCrs( crs() );
125  layer->setCustomProperties( mCustomProperties );
126 }
127 
129 {
130  return mLayerType;
131 }
132 
133 QgsMapLayer::LayerFlags QgsMapLayer::flags() const
134 {
135  return mFlags;
136 }
137 
138 void QgsMapLayer::setFlags( QgsMapLayer::LayerFlags flags )
139 {
140  if ( flags == mFlags )
141  return;
142 
143  mFlags = flags;
144  emit flagsChanged();
145 }
146 
147 QString QgsMapLayer::id() const
148 {
149  return mID;
150 }
151 
152 void QgsMapLayer::setName( const QString &name )
153 {
154  if ( name == mLayerName )
155  return;
156 
157  mLayerName = name;
158 
159  emit nameChanged();
160 }
161 
162 QString QgsMapLayer::name() const
163 {
164  QgsDebugMsgLevel( "returning name '" + mLayerName + '\'', 4 );
165  return mLayerName;
166 }
167 
169 {
170  return nullptr;
171 }
172 
174 {
175  return nullptr;
176 }
177 
178 QString QgsMapLayer::shortName() const
179 {
180  return mShortName;
181 }
182 
184 {
185  // Redo this every time we're asked for it, as we don't know if
186  // dataSource has changed.
187  QString safeName = QgsDataSourceUri::removePassword( mDataSource );
188  return safeName;
189 }
190 
191 QString QgsMapLayer::source() const
192 {
193  return mDataSource;
194 }
195 
197 {
198  return mExtent;
199 }
200 
201 void QgsMapLayer::setBlendMode( const QPainter::CompositionMode blendMode )
202 {
203  if ( mBlendMode == blendMode )
204  return;
205 
206  mBlendMode = blendMode;
207  emit blendModeChanged( blendMode );
208  emit styleChanged();
209 }
210 
211 QPainter::CompositionMode QgsMapLayer::blendMode() const
212 {
213  return mBlendMode;
214 }
215 
216 
217 bool QgsMapLayer::readLayerXml( const QDomElement &layerElement, QgsReadWriteContext &context, QgsMapLayer::ReadFlags flags )
218 {
219  bool layerError;
220  mReadFlags = flags;
221 
222  QDomNode mnl;
223  QDomElement mne;
224 
225  // read provider
226  QString provider;
227  mnl = layerElement.namedItem( QStringLiteral( "provider" ) );
228  mne = mnl.toElement();
229  provider = mne.text();
230 
231  // set data source
232  mnl = layerElement.namedItem( QStringLiteral( "datasource" ) );
233  mne = mnl.toElement();
234  mDataSource = mne.text();
235 
236  // if the layer needs authentication, ensure the master password is set
237  QRegExp rx( "authcfg=([a-z]|[A-Z]|[0-9]){7}" );
238  if ( ( rx.indexIn( mDataSource ) != -1 )
240  {
241  return false;
242  }
243 
244  mDataSource = decodedSource( mDataSource, provider, context );
245 
246  // Set the CRS from project file, asking the user if necessary.
247  // Make it the saved CRS to have WMS layer projected correctly.
248  // We will still overwrite whatever GDAL etc picks up anyway
249  // further down this function.
250  mnl = layerElement.namedItem( QStringLiteral( "layername" ) );
251  mne = mnl.toElement();
252 
254  CUSTOM_CRS_VALIDATION savedValidation;
255 
256  QDomNode srsNode = layerElement.namedItem( QStringLiteral( "srs" ) );
257  mCRS.readXml( srsNode );
258  mCRS.setValidationHint( tr( "Specify CRS for layer %1" ).arg( mne.text() ) );
259  if ( isSpatial() )
260  mCRS.validate();
261  savedCRS = mCRS;
262 
263  // Do not validate any projections in children, they will be overwritten anyway.
264  // No need to ask the user for a projections when it is overwritten, is there?
267 
268  QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Layer" ), mne.text() );
269 
270  // the internal name is just the data source basename
271  //QFileInfo dataSourceFileInfo( mDataSource );
272  //internalName = dataSourceFileInfo.baseName();
273 
274  // set ID
275  mnl = layerElement.namedItem( QStringLiteral( "id" ) );
276  if ( ! mnl.isNull() )
277  {
278  mne = mnl.toElement();
279  if ( ! mne.isNull() && mne.text().length() > 10 ) // should be at least 17 (yyyyMMddhhmmsszzz)
280  {
281  mID = mne.text();
282  }
283  }
284 
285  setAutoRefreshInterval( layerElement.attribute( QStringLiteral( "autoRefreshTime" ), QStringLiteral( "0" ) ).toInt() );
286  setAutoRefreshEnabled( layerElement.attribute( QStringLiteral( "autoRefreshEnabled" ), QStringLiteral( "0" ) ).toInt() );
287  setRefreshOnNofifyMessage( layerElement.attribute( QStringLiteral( "refreshOnNotifyMessage" ), QString() ) );
288  setRefreshOnNotifyEnabled( layerElement.attribute( QStringLiteral( "refreshOnNotifyEnabled" ), QStringLiteral( "0" ) ).toInt() );
289 
290  // set name
291  mnl = layerElement.namedItem( QStringLiteral( "layername" ) );
292  mne = mnl.toElement();
293 
294  //name can be translated
295  setName( context.projectTranslator()->translate( QStringLiteral( "project:layers:%1" ).arg( layerElement.namedItem( QStringLiteral( "id" ) ).toElement().text() ), mne.text() ) );
296 
297  // now let the children grab what they need from the Dom node.
298  layerError = !readXml( layerElement, context );
299 
300  // overwrite CRS with what we read from project file before the raster/vector
301  // file reading functions changed it. They will if projections is specified in the file.
302  // FIXME: is this necessary? Yes, it is (autumn 2019)
304  mCRS = savedCRS;
305 
306  //short name
307  QDomElement shortNameElem = layerElement.firstChildElement( QStringLiteral( "shortname" ) );
308  if ( !shortNameElem.isNull() )
309  {
310  mShortName = shortNameElem.text();
311  }
312 
313  //title
314  QDomElement titleElem = layerElement.firstChildElement( QStringLiteral( "title" ) );
315  if ( !titleElem.isNull() )
316  {
317  mTitle = titleElem.text();
318  }
319 
320  //abstract
321  QDomElement abstractElem = layerElement.firstChildElement( QStringLiteral( "abstract" ) );
322  if ( !abstractElem.isNull() )
323  {
324  mAbstract = abstractElem.text();
325  }
326 
327  //keywordList
328  QDomElement keywordListElem = layerElement.firstChildElement( QStringLiteral( "keywordList" ) );
329  if ( !keywordListElem.isNull() )
330  {
331  QStringList kwdList;
332  for ( QDomNode n = keywordListElem.firstChild(); !n.isNull(); n = n.nextSibling() )
333  {
334  kwdList << n.toElement().text();
335  }
336  mKeywordList = kwdList.join( QStringLiteral( ", " ) );
337  }
338 
339  //metadataUrl
340  QDomElement dataUrlElem = layerElement.firstChildElement( QStringLiteral( "dataUrl" ) );
341  if ( !dataUrlElem.isNull() )
342  {
343  mDataUrl = dataUrlElem.text();
344  mDataUrlFormat = dataUrlElem.attribute( QStringLiteral( "format" ), QString() );
345  }
346 
347  //legendUrl
348  QDomElement legendUrlElem = layerElement.firstChildElement( QStringLiteral( "legendUrl" ) );
349  if ( !legendUrlElem.isNull() )
350  {
351  mLegendUrl = legendUrlElem.text();
352  mLegendUrlFormat = legendUrlElem.attribute( QStringLiteral( "format" ), QString() );
353  }
354 
355  //attribution
356  QDomElement attribElem = layerElement.firstChildElement( QStringLiteral( "attribution" ) );
357  if ( !attribElem.isNull() )
358  {
359  mAttribution = attribElem.text();
360  mAttributionUrl = attribElem.attribute( QStringLiteral( "href" ), QString() );
361  }
362 
363  //metadataUrl
364  QDomElement metaUrlElem = layerElement.firstChildElement( QStringLiteral( "metadataUrl" ) );
365  if ( !metaUrlElem.isNull() )
366  {
367  mMetadataUrl = metaUrlElem.text();
368  mMetadataUrlType = metaUrlElem.attribute( QStringLiteral( "type" ), QString() );
369  mMetadataUrlFormat = metaUrlElem.attribute( QStringLiteral( "format" ), QString() );
370  }
371 
372  // mMetadata.readFromLayer( this );
373  QDomElement metadataElem = layerElement.firstChildElement( QStringLiteral( "resourceMetadata" ) );
374  mMetadata.readMetadataXml( metadataElem );
375 
376  return ! layerError;
377 } // bool QgsMapLayer::readLayerXML
378 
379 
380 bool QgsMapLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
381 {
382  Q_UNUSED( layer_node )
383  Q_UNUSED( context )
384  // NOP by default; children will over-ride with behavior specific to them
385 
386  return true;
387 } // void QgsMapLayer::readXml
388 
389 
390 bool QgsMapLayer::writeLayerXml( QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context ) const
391 {
392  if ( !extent().isNull() )
393  {
394  layerElement.appendChild( QgsXmlUtils::writeRectangle( mExtent, document ) );
395  }
396 
397  layerElement.setAttribute( QStringLiteral( "autoRefreshTime" ), QString::number( mRefreshTimer->interval() ) );
398  layerElement.setAttribute( QStringLiteral( "autoRefreshEnabled" ), mRefreshTimer->isActive() ? 1 : 0 );
399  layerElement.setAttribute( QStringLiteral( "refreshOnNotifyEnabled" ), mIsRefreshOnNofifyEnabled ? 1 : 0 );
400  layerElement.setAttribute( QStringLiteral( "refreshOnNotifyMessage" ), mRefreshOnNofifyMessage );
401 
402 
403  // ID
404  QDomElement layerId = document.createElement( QStringLiteral( "id" ) );
405  QDomText layerIdText = document.createTextNode( id() );
406  layerId.appendChild( layerIdText );
407 
408  layerElement.appendChild( layerId );
409 
410  // data source
411  QDomElement dataSource = document.createElement( QStringLiteral( "datasource" ) );
412  QString src = encodedSource( source(), context );
413  QDomText dataSourceText = document.createTextNode( src );
414  dataSource.appendChild( dataSourceText );
415  layerElement.appendChild( dataSource );
416 
417  // layer name
418  QDomElement layerName = document.createElement( QStringLiteral( "layername" ) );
419  QDomText layerNameText = document.createTextNode( name() );
420  layerName.appendChild( layerNameText );
421  layerElement.appendChild( layerName );
422 
423  // layer short name
424  if ( !mShortName.isEmpty() )
425  {
426  QDomElement layerShortName = document.createElement( QStringLiteral( "shortname" ) );
427  QDomText layerShortNameText = document.createTextNode( mShortName );
428  layerShortName.appendChild( layerShortNameText );
429  layerElement.appendChild( layerShortName );
430  }
431 
432  // layer title
433  if ( !mTitle.isEmpty() )
434  {
435  QDomElement layerTitle = document.createElement( QStringLiteral( "title" ) );
436  QDomText layerTitleText = document.createTextNode( mTitle );
437  layerTitle.appendChild( layerTitleText );
438  layerElement.appendChild( layerTitle );
439  }
440 
441  // layer abstract
442  if ( !mAbstract.isEmpty() )
443  {
444  QDomElement layerAbstract = document.createElement( QStringLiteral( "abstract" ) );
445  QDomText layerAbstractText = document.createTextNode( mAbstract );
446  layerAbstract.appendChild( layerAbstractText );
447  layerElement.appendChild( layerAbstract );
448  }
449 
450  // layer keyword list
451  QStringList keywordStringList = keywordList().split( ',' );
452  if ( !keywordStringList.isEmpty() )
453  {
454  QDomElement layerKeywordList = document.createElement( QStringLiteral( "keywordList" ) );
455  for ( int i = 0; i < keywordStringList.size(); ++i )
456  {
457  QDomElement layerKeywordValue = document.createElement( QStringLiteral( "value" ) );
458  QDomText layerKeywordText = document.createTextNode( keywordStringList.at( i ).trimmed() );
459  layerKeywordValue.appendChild( layerKeywordText );
460  layerKeywordList.appendChild( layerKeywordValue );
461  }
462  layerElement.appendChild( layerKeywordList );
463  }
464 
465  // layer metadataUrl
466  QString aDataUrl = dataUrl();
467  if ( !aDataUrl.isEmpty() )
468  {
469  QDomElement layerDataUrl = document.createElement( QStringLiteral( "dataUrl" ) );
470  QDomText layerDataUrlText = document.createTextNode( aDataUrl );
471  layerDataUrl.appendChild( layerDataUrlText );
472  layerDataUrl.setAttribute( QStringLiteral( "format" ), dataUrlFormat() );
473  layerElement.appendChild( layerDataUrl );
474  }
475 
476  // layer legendUrl
477  QString aLegendUrl = legendUrl();
478  if ( !aLegendUrl.isEmpty() )
479  {
480  QDomElement layerLegendUrl = document.createElement( QStringLiteral( "legendUrl" ) );
481  QDomText layerLegendUrlText = document.createTextNode( aLegendUrl );
482  layerLegendUrl.appendChild( layerLegendUrlText );
483  layerLegendUrl.setAttribute( QStringLiteral( "format" ), legendUrlFormat() );
484  layerElement.appendChild( layerLegendUrl );
485  }
486 
487  // layer attribution
488  QString aAttribution = attribution();
489  if ( !aAttribution.isEmpty() )
490  {
491  QDomElement layerAttribution = document.createElement( QStringLiteral( "attribution" ) );
492  QDomText layerAttributionText = document.createTextNode( aAttribution );
493  layerAttribution.appendChild( layerAttributionText );
494  layerAttribution.setAttribute( QStringLiteral( "href" ), attributionUrl() );
495  layerElement.appendChild( layerAttribution );
496  }
497 
498  // layer metadataUrl
499  QString aMetadataUrl = metadataUrl();
500  if ( !aMetadataUrl.isEmpty() )
501  {
502  QDomElement layerMetadataUrl = document.createElement( QStringLiteral( "metadataUrl" ) );
503  QDomText layerMetadataUrlText = document.createTextNode( aMetadataUrl );
504  layerMetadataUrl.appendChild( layerMetadataUrlText );
505  layerMetadataUrl.setAttribute( QStringLiteral( "type" ), metadataUrlType() );
506  layerMetadataUrl.setAttribute( QStringLiteral( "format" ), metadataUrlFormat() );
507  layerElement.appendChild( layerMetadataUrl );
508  }
509 
510  // timestamp if supported
511  if ( timestamp() > QDateTime() )
512  {
513  QDomElement stamp = document.createElement( QStringLiteral( "timestamp" ) );
514  QDomText stampText = document.createTextNode( timestamp().toString( Qt::ISODate ) );
515  stamp.appendChild( stampText );
516  layerElement.appendChild( stamp );
517  }
518 
519  layerElement.appendChild( layerName );
520 
521  // zorder
522  // This is no longer stored in the project file. It is superfluous since the layers
523  // are written and read in the proper order.
524 
525  // spatial reference system id
526  QDomElement mySrsElement = document.createElement( QStringLiteral( "srs" ) );
527  mCRS.writeXml( mySrsElement, document );
528  layerElement.appendChild( mySrsElement );
529 
530  // layer metadata
531  QDomElement myMetadataElem = document.createElement( QStringLiteral( "resourceMetadata" ) );
532  mMetadata.writeMetadataXml( myMetadataElem, document );
533  layerElement.appendChild( myMetadataElem );
534 
535  // now append layer node to map layer node
536  return writeXml( layerElement, document, context );
537 }
538 
539 void QgsMapLayer::writeCommonStyle( QDomElement &layerElement, QDomDocument &document,
540  const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
541 {
542  // save categories
543  QMetaEnum metaEnum = QMetaEnum::fromType<QgsMapLayer::StyleCategories>();
544  QString categoriesKeys( metaEnum.valueToKeys( static_cast<int>( categories ) ) );
545  layerElement.setAttribute( QStringLiteral( "styleCategories" ), categoriesKeys );
546 
547  if ( categories.testFlag( Rendering ) )
548  {
549  // use scale dependent visibility flag
550  layerElement.setAttribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ), hasScaleBasedVisibility() ? 1 : 0 );
551  layerElement.setAttribute( QStringLiteral( "maxScale" ), QString::number( maximumScale() ) );
552  layerElement.setAttribute( QStringLiteral( "minScale" ), QString::number( minimumScale() ) );
553  }
554 
555  if ( categories.testFlag( Symbology3D ) )
556  {
557  if ( m3DRenderer )
558  {
559  QDomElement renderer3DElem = document.createElement( QStringLiteral( "renderer-3d" ) );
560  renderer3DElem.setAttribute( QStringLiteral( "type" ), m3DRenderer->type() );
561  m3DRenderer->writeXml( renderer3DElem, context );
562  layerElement.appendChild( renderer3DElem );
563  }
564  }
565 
566  if ( categories.testFlag( LayerConfiguration ) )
567  {
568  // flags
569  // this code is saving automatically all the flags entries
570  QDomElement layerFlagsElem = document.createElement( QStringLiteral( "flags" ) );
571  auto enumMap = qgsEnumMap<QgsMapLayer::LayerFlag>();
572  for ( auto it = enumMap.constBegin(); it != enumMap.constEnd(); ++it )
573  {
574  bool flagValue = mFlags.testFlag( it.key() );
575  QDomElement flagElem = document.createElement( it.value() );
576  flagElem.appendChild( document.createTextNode( QString::number( flagValue ) ) );
577  layerFlagsElem.appendChild( flagElem );
578  }
579  layerElement.appendChild( layerFlagsElem );
580  }
581 
582  // custom properties
583  if ( categories.testFlag( CustomProperties ) )
584  {
585  writeCustomProperties( layerElement, document );
586  }
587 }
588 
589 
590 bool QgsMapLayer::writeXml( QDomNode &layer_node, QDomDocument &document, const QgsReadWriteContext &context ) const
591 {
592  Q_UNUSED( layer_node )
593  Q_UNUSED( document )
594  Q_UNUSED( context )
595  // NOP by default; children will over-ride with behavior specific to them
596 
597  return true;
598 }
599 
600 QString QgsMapLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
601 {
602  Q_UNUSED( context )
603  return source;
604 }
605 
606 QString QgsMapLayer::decodedSource( const QString &source, const QString &dataProvider, const QgsReadWriteContext &context ) const
607 {
608  Q_UNUSED( context )
609  Q_UNUSED( dataProvider )
610  return source;
611 }
612 
614 {
615  emit beforeResolveReferences( project );
616  if ( m3DRenderer )
617  m3DRenderer->resolveReferences( *project );
618 }
619 
620 
621 void QgsMapLayer::readCustomProperties( const QDomNode &layerNode, const QString &keyStartsWith )
622 {
623  mCustomProperties.readXml( layerNode, keyStartsWith );
624 }
625 
626 void QgsMapLayer::writeCustomProperties( QDomNode &layerNode, QDomDocument &doc ) const
627 {
628  mCustomProperties.writeXml( layerNode, doc );
629 }
630 
631 void QgsMapLayer::readStyleManager( const QDomNode &layerNode )
632 {
633  QDomElement styleMgrElem = layerNode.firstChildElement( QStringLiteral( "map-layer-style-manager" ) );
634  if ( !styleMgrElem.isNull() )
635  mStyleManager->readXml( styleMgrElem );
636  else
637  mStyleManager->reset();
638 }
639 
640 void QgsMapLayer::writeStyleManager( QDomNode &layerNode, QDomDocument &doc ) const
641 {
642  if ( mStyleManager )
643  {
644  QDomElement styleMgrElem = doc.createElement( QStringLiteral( "map-layer-style-manager" ) );
645  mStyleManager->writeXml( styleMgrElem );
646  layerNode.appendChild( styleMgrElem );
647  }
648 }
649 
651 {
652  return mValid;
653 }
654 
655 #if 0
656 void QgsMapLayer::connectNotify( const char *signal )
657 {
658  Q_UNUSED( signal )
659  QgsDebugMsgLevel( "QgsMapLayer connected to " + QString( signal ), 3 );
660 } // QgsMapLayer::connectNotify
661 #endif
662 
663 bool QgsMapLayer::isInScaleRange( double scale ) const
664 {
665  return !mScaleBasedVisibility ||
666  ( ( mMinScale == 0 || mMinScale * Qgis::SCALE_PRECISION < scale )
667  && ( mMaxScale == 0 || scale < mMaxScale ) );
668 }
669 
671 {
672  return mScaleBasedVisibility;
673 }
674 
676 {
677  return mRefreshTimer->isActive();
678 }
679 
681 {
682  return mRefreshTimer->interval();
683 }
684 
686 {
687  if ( interval <= 0 )
688  {
689  mRefreshTimer->stop();
690  mRefreshTimer->setInterval( 0 );
691  }
692  else
693  {
694  mRefreshTimer->setInterval( interval );
695  }
696  emit autoRefreshIntervalChanged( mRefreshTimer->isActive() ? mRefreshTimer->interval() : 0 );
697 }
698 
700 {
701  if ( !enabled )
702  mRefreshTimer->stop();
703  else if ( mRefreshTimer->interval() > 0 )
704  mRefreshTimer->start();
705 
706  emit autoRefreshIntervalChanged( mRefreshTimer->isActive() ? mRefreshTimer->interval() : 0 );
707 }
708 
710 {
711  return mMetadata;
712 }
713 
714 void QgsMapLayer::setMaximumScale( double scale )
715 {
716  mMinScale = scale;
717 }
718 
720 {
721  return mMinScale;
722 }
723 
724 
725 void QgsMapLayer::setMinimumScale( double scale )
726 {
727  mMaxScale = scale;
728 }
729 
730 void QgsMapLayer::setScaleBasedVisibility( const bool enabled )
731 {
732  mScaleBasedVisibility = enabled;
733 }
734 
736 {
737  return mMaxScale;
738 }
739 
740 QStringList QgsMapLayer::subLayers() const
741 {
742  return QStringList(); // Empty
743 }
744 
745 void QgsMapLayer::setLayerOrder( const QStringList &layers )
746 {
747  Q_UNUSED( layers )
748  // NOOP
749 }
750 
751 void QgsMapLayer::setSubLayerVisibility( const QString &name, bool vis )
752 {
753  Q_UNUSED( name )
754  Q_UNUSED( vis )
755  // NOOP
756 }
757 
759 {
760  return mCRS;
761 }
762 
763 void QgsMapLayer::setCrs( const QgsCoordinateReferenceSystem &srs, bool emitSignal )
764 {
765  mCRS = srs;
766 
767  if ( mShouldValidateCrs && isSpatial() && !mCRS.isValid() )
768  {
769  mCRS.setValidationHint( tr( "Specify CRS for layer %1" ).arg( name() ) );
770  mCRS.validate();
771  }
772 
773  if ( emitSignal )
774  emit crsChanged();
775 }
776 
778 {
780 }
781 
782 QString QgsMapLayer::formatLayerName( const QString &name )
783 {
784  QString layerName( name );
785  layerName.replace( '_', ' ' );
787  return layerName;
788 }
789 
790 QString QgsMapLayer::baseURI( PropertyType type ) const
791 {
792  QString myURI = publicSource();
793 
794  // first get base path for delimited text, spatialite and OGR layers,
795  // as in these cases URI may contain layer name and/or additional
796  // information. This also strips prefix in case if VSIFILE mechanism
797  // is used
798  if ( providerType() == QLatin1String( "ogr" ) || providerType() == QLatin1String( "delimitedtext" ) ||
799  providerType() == QLatin1String( "spatialite" ) )
800  {
801  QVariantMap components = QgsProviderRegistry::instance()->decodeUri( providerType(), myURI );
802  myURI = components["path"].toString();
803  }
804 
805  QFileInfo myFileInfo( myURI );
806  QString key;
807 
808  if ( myFileInfo.exists() )
809  {
810  // if file is using the /vsizip/ or /vsigzip/ mechanism, cleanup the name
811  if ( myURI.endsWith( QLatin1String( ".gz" ), Qt::CaseInsensitive ) )
812  myURI.chop( 3 );
813  else if ( myURI.endsWith( QLatin1String( ".zip" ), Qt::CaseInsensitive ) )
814  myURI.chop( 4 );
815  else if ( myURI.endsWith( QLatin1String( ".tar" ), Qt::CaseInsensitive ) )
816  myURI.chop( 4 );
817  else if ( myURI.endsWith( QLatin1String( ".tar.gz" ), Qt::CaseInsensitive ) )
818  myURI.chop( 7 );
819  else if ( myURI.endsWith( QLatin1String( ".tgz" ), Qt::CaseInsensitive ) )
820  myURI.chop( 4 );
821  myFileInfo.setFile( myURI );
822  // get the file name for our .qml style file
823  key = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + QgsMapLayer::extensionPropertyType( type );
824  }
825  else
826  {
827  key = publicSource();
828  }
829 
830  return key;
831 }
832 
834 {
835  return baseURI( PropertyType::Metadata );
836 }
837 
838 QString QgsMapLayer::saveDefaultMetadata( bool &resultFlag )
839 {
840  return saveNamedMetadata( metadataUri(), resultFlag );
841 }
842 
843 QString QgsMapLayer::loadDefaultMetadata( bool &resultFlag )
844 {
845  return loadNamedMetadata( metadataUri(), resultFlag );
846 }
847 
848 QString QgsMapLayer::styleURI() const
849 {
850  return baseURI( PropertyType::Style );
851 }
852 
853 QString QgsMapLayer::loadDefaultStyle( bool &resultFlag )
854 {
855  return loadNamedStyle( styleURI(), resultFlag );
856 }
857 
858 bool QgsMapLayer::loadNamedMetadataFromDatabase( const QString &db, const QString &uri, QString &qmd )
859 {
860  return loadNamedPropertyFromDatabase( db, uri, qmd, PropertyType::Metadata );
861 }
862 
863 bool QgsMapLayer::loadNamedStyleFromDatabase( const QString &db, const QString &uri, QString &qml )
864 {
865  return loadNamedPropertyFromDatabase( db, uri, qml, PropertyType::Style );
866 }
867 
868 bool QgsMapLayer::loadNamedPropertyFromDatabase( const QString &db, const QString &uri, QString &xml, QgsMapLayer::PropertyType type )
869 {
870  QgsDebugMsgLevel( QStringLiteral( "db = %1 uri = %2" ).arg( db, uri ), 4 );
871 
872  bool resultFlag = false;
873 
874  // read from database
877 
878  int myResult;
879 
880  QgsDebugMsgLevel( QStringLiteral( "Trying to load style or metadata for \"%1\" from \"%2\"" ).arg( uri, db ), 4 );
881 
882  if ( db.isEmpty() || !QFile( db ).exists() )
883  return false;
884 
885  myResult = database.open_v2( db, SQLITE_OPEN_READONLY, nullptr );
886  if ( myResult != SQLITE_OK )
887  {
888  return false;
889  }
890 
891  QString mySql;
892  switch ( type )
893  {
894  case Metadata:
895  mySql = QStringLiteral( "select qmd from tbl_metadata where metadata=?" );
896  break;
897 
898  case Style:
899  mySql = QStringLiteral( "select qml from tbl_styles where style=?" );
900  break;
901  }
902 
903  statement = database.prepare( mySql, myResult );
904  if ( myResult == SQLITE_OK )
905  {
906  QByteArray param = uri.toUtf8();
907 
908  if ( sqlite3_bind_text( statement.get(), 1, param.data(), param.length(), SQLITE_STATIC ) == SQLITE_OK &&
909  sqlite3_step( statement.get() ) == SQLITE_ROW )
910  {
911  xml = QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( statement.get(), 0 ) ) );
912  resultFlag = true;
913  }
914  }
915  return resultFlag;
916 }
917 
918 
919 QString QgsMapLayer::loadNamedStyle( const QString &uri, bool &resultFlag, QgsMapLayer::StyleCategories categories )
920 {
921  return loadNamedProperty( uri, PropertyType::Style, resultFlag, categories );
922 }
923 
924 QString QgsMapLayer::loadNamedProperty( const QString &uri, QgsMapLayer::PropertyType type, bool &resultFlag, StyleCategories categories )
925 {
926  QgsDebugMsgLevel( QStringLiteral( "uri = %1 myURI = %2" ).arg( uri, publicSource() ), 4 );
927 
928  resultFlag = false;
929 
930  QDomDocument myDocument( QStringLiteral( "qgis" ) );
931 
932  // location of problem associated with errorMsg
933  int line, column;
934  QString myErrorMessage;
935 
936  QFile myFile( uri );
937  if ( myFile.open( QFile::ReadOnly ) )
938  {
939  QgsDebugMsgLevel( QStringLiteral( "file found %1" ).arg( uri ), 2 );
940  // read file
941  resultFlag = myDocument.setContent( &myFile, &myErrorMessage, &line, &column );
942  if ( !resultFlag )
943  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
944  myFile.close();
945  }
946  else
947  {
948  QFileInfo project( QgsProject::instance()->fileName() );
949  QgsDebugMsgLevel( QStringLiteral( "project fileName: %1" ).arg( project.absoluteFilePath() ), 4 );
950 
951  QString xml;
952  switch ( type )
953  {
954  case QgsMapLayer::Style:
955  {
956  if ( loadNamedStyleFromDatabase( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ), uri, xml ) ||
957  ( project.exists() && loadNamedStyleFromDatabase( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), uri, xml ) ) ||
958  loadNamedStyleFromDatabase( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( QStringLiteral( "resources/qgis.qmldb" ) ), uri, xml ) )
959  {
960  resultFlag = myDocument.setContent( xml, &myErrorMessage, &line, &column );
961  if ( !resultFlag )
962  {
963  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
964  }
965  }
966  else
967  {
968  myErrorMessage = tr( "Style not found in database" );
969  resultFlag = false;
970  }
971  break;
972  }
974  {
975  if ( loadNamedMetadataFromDatabase( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ), uri, xml ) ||
976  ( project.exists() && loadNamedMetadataFromDatabase( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), uri, xml ) ) ||
977  loadNamedMetadataFromDatabase( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( QStringLiteral( "resources/qgis.qmldb" ) ), uri, xml ) )
978  {
979  resultFlag = myDocument.setContent( xml, &myErrorMessage, &line, &column );
980  if ( !resultFlag )
981  {
982  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
983  }
984  }
985  else
986  {
987  myErrorMessage = tr( "Metadata not found in database" );
988  resultFlag = false;
989  }
990  break;
991  }
992  }
993  }
994 
995  if ( !resultFlag )
996  {
997  return myErrorMessage;
998  }
999 
1000  switch ( type )
1001  {
1002  case QgsMapLayer::Style:
1003  resultFlag = importNamedStyle( myDocument, myErrorMessage, categories );
1004  if ( !resultFlag )
1005  myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( uri, myErrorMessage );
1006  break;
1007  case QgsMapLayer::Metadata:
1008  resultFlag = importNamedMetadata( myDocument, myErrorMessage );
1009  if ( !resultFlag )
1010  myErrorMessage = tr( "Loading metadata file %1 failed because:\n%2" ).arg( uri, myErrorMessage );
1011  break;
1012  }
1013  return myErrorMessage;
1014 }
1015 
1016 bool QgsMapLayer::importNamedMetadata( QDomDocument &document, QString &errorMessage )
1017 {
1018  QDomElement myRoot = document.firstChildElement( QStringLiteral( "qgis" ) );
1019  if ( myRoot.isNull() )
1020  {
1021  errorMessage = tr( "Root <qgis> element could not be found" );
1022  return false;
1023  }
1024 
1025  return mMetadata.readMetadataXml( myRoot );
1026 }
1027 
1028 bool QgsMapLayer::importNamedStyle( QDomDocument &myDocument, QString &myErrorMessage, QgsMapLayer::StyleCategories categories )
1029 {
1030  QDomElement myRoot = myDocument.firstChildElement( QStringLiteral( "qgis" ) );
1031  if ( myRoot.isNull() )
1032  {
1033  myErrorMessage = tr( "Root <qgis> element could not be found" );
1034  return false;
1035  }
1036 
1037  // get style file version string, if any
1038  QgsProjectVersion fileVersion( myRoot.attribute( QStringLiteral( "version" ) ) );
1039  QgsProjectVersion thisVersion( Qgis::version() );
1040 
1041  if ( thisVersion > fileVersion )
1042  {
1043  QgsProjectFileTransform styleFile( myDocument, fileVersion );
1044  styleFile.updateRevision( thisVersion );
1045  }
1046 
1047  // Get source categories
1048  QgsMapLayer::StyleCategories sourceCategories = QgsXmlUtils::readFlagAttribute( myRoot, QStringLiteral( "styleCategories" ), QgsMapLayer::AllStyleCategories );
1049 
1050  //Test for matching geometry type on vector layers when applying, if geometry type is given in the style
1051  if ( ( sourceCategories.testFlag( QgsMapLayer::Symbology ) || sourceCategories.testFlag( QgsMapLayer::Symbology3D ) ) &&
1052  ( categories.testFlag( QgsMapLayer::Symbology ) || categories.testFlag( QgsMapLayer::Symbology3D ) ) )
1053  {
1054  if ( type() == QgsMapLayerType::VectorLayer && !myRoot.firstChildElement( QStringLiteral( "layerGeometryType" ) ).isNull() )
1055  {
1056  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( this );
1057  QgsWkbTypes::GeometryType importLayerGeometryType = static_cast<QgsWkbTypes::GeometryType>( myRoot.firstChildElement( QStringLiteral( "layerGeometryType" ) ).text().toInt() );
1058  if ( vl->geometryType() != importLayerGeometryType )
1059  {
1060  myErrorMessage = tr( "Cannot apply style with symbology to layer with a different geometry type" );
1061  return false;
1062  }
1063  }
1064  }
1065 
1067  return readSymbology( myRoot, myErrorMessage, context, categories ); // TODO: support relative paths in QML?
1068 }
1069 
1070 void QgsMapLayer::exportNamedMetadata( QDomDocument &doc, QString &errorMsg ) const
1071 {
1072  QDomImplementation DomImplementation;
1073  QDomDocumentType documentType = DomImplementation.createDocumentType( QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
1074  QDomDocument myDocument( documentType );
1075 
1076  QDomElement myRootNode = myDocument.createElement( QStringLiteral( "qgis" ) );
1077  myRootNode.setAttribute( QStringLiteral( "version" ), Qgis::version() );
1078  myDocument.appendChild( myRootNode );
1079 
1080  if ( !mMetadata.writeMetadataXml( myRootNode, myDocument ) )
1081  {
1082  errorMsg = QObject::tr( "Could not save metadata" );
1083  return;
1084  }
1085 
1086  doc = myDocument;
1087 }
1088 
1089 void QgsMapLayer::exportNamedStyle( QDomDocument &doc, QString &errorMsg, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1090 {
1091  QDomImplementation DomImplementation;
1092  QDomDocumentType documentType = DomImplementation.createDocumentType( QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
1093  QDomDocument myDocument( documentType );
1094 
1095  QDomElement myRootNode = myDocument.createElement( QStringLiteral( "qgis" ) );
1096  myRootNode.setAttribute( QStringLiteral( "version" ), Qgis::version() );
1097  myDocument.appendChild( myRootNode );
1098 
1099  if ( !writeSymbology( myRootNode, myDocument, errorMsg, context, categories ) ) // TODO: support relative paths in QML?
1100  {
1101  errorMsg = QObject::tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1102  return;
1103  }
1104 
1105  /*
1106  * Check to see if the layer is vector - in which case we should also export its geometryType
1107  * to avoid eventually pasting to a layer with a different geometry
1108  */
1110  {
1111  //Getting the selectionLayer geometry
1112  const QgsVectorLayer *vl = qobject_cast<const QgsVectorLayer *>( this );
1113  QString geoType = QString::number( vl->geometryType() );
1114 
1115  //Adding geometryinformation
1116  QDomElement layerGeometryType = myDocument.createElement( QStringLiteral( "layerGeometryType" ) );
1117  QDomText type = myDocument.createTextNode( geoType );
1118 
1119  layerGeometryType.appendChild( type );
1120  myRootNode.appendChild( layerGeometryType );
1121  }
1122 
1123  doc = myDocument;
1124 }
1125 
1126 QString QgsMapLayer::saveDefaultStyle( bool &resultFlag )
1127 {
1128  return saveNamedStyle( styleURI(), resultFlag );
1129 }
1130 
1131 QString QgsMapLayer::saveNamedMetadata( const QString &uri, bool &resultFlag )
1132 {
1133  return saveNamedProperty( uri, QgsMapLayer::Metadata, resultFlag );
1134 }
1135 
1136 QString QgsMapLayer::loadNamedMetadata( const QString &uri, bool &resultFlag )
1137 {
1138  return loadNamedProperty( uri, QgsMapLayer::Metadata, resultFlag );
1139 }
1140 
1141 QString QgsMapLayer::saveNamedProperty( const QString &uri, QgsMapLayer::PropertyType type, bool &resultFlag, StyleCategories categories )
1142 {
1143  // check if the uri is a file or ends with .qml/.qmd,
1144  // which indicates that it should become one
1145  // everything else goes to the database
1146  QString filename;
1147 
1148  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this );
1149  if ( vlayer && vlayer->providerType() == QLatin1String( "ogr" ) )
1150  {
1151  QStringList theURIParts = uri.split( '|' );
1152  filename = theURIParts[0];
1153  }
1154  else if ( vlayer && vlayer->providerType() == QLatin1String( "gpx" ) )
1155  {
1156  QStringList theURIParts = uri.split( '?' );
1157  filename = theURIParts[0];
1158  }
1159  else if ( vlayer && vlayer->providerType() == QLatin1String( "delimitedtext" ) )
1160  {
1161  filename = QUrl::fromEncoded( uri.toLatin1() ).toLocalFile();
1162  // toLocalFile() returns an empty string if theURI is a plain Windows-path, e.g. "C:/style.qml"
1163  if ( filename.isEmpty() )
1164  filename = uri;
1165  }
1166  else
1167  {
1168  filename = uri;
1169  }
1170 
1171  QString myErrorMessage;
1172  QDomDocument myDocument;
1173  switch ( type )
1174  {
1175  case Metadata:
1176  exportNamedMetadata( myDocument, myErrorMessage );
1177  break;
1178 
1179  case Style:
1180  QgsReadWriteContext context;
1181  exportNamedStyle( myDocument, myErrorMessage, context, categories );
1182  break;
1183  }
1184 
1185  QFileInfo myFileInfo( filename );
1186  if ( myFileInfo.exists() || filename.endsWith( QgsMapLayer::extensionPropertyType( type ), Qt::CaseInsensitive ) )
1187  {
1188  QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
1189  if ( !myDirInfo.isWritable() )
1190  {
1191  return tr( "The directory containing your dataset needs to be writable!" );
1192  }
1193 
1194  // now construct the file name for our .qml or .qmd file
1195  QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + QgsMapLayer::extensionPropertyType( type );
1196 
1197  QFile myFile( myFileName );
1198  if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
1199  {
1200  QTextStream myFileStream( &myFile );
1201  // save as utf-8 with 2 spaces for indents
1202  myDocument.save( myFileStream, 2 );
1203  myFile.close();
1204  resultFlag = true;
1205  switch ( type )
1206  {
1207  case Metadata:
1208  return tr( "Created default metadata file as %1" ).arg( myFileName );
1209 
1210  case Style:
1211  return tr( "Created default style file as %1" ).arg( myFileName );
1212  }
1213 
1214  }
1215  else
1216  {
1217  resultFlag = false;
1218  switch ( type )
1219  {
1220  case Metadata:
1221  return tr( "ERROR: Failed to created default metadata file as %1. Check file permissions and retry." ).arg( myFileName );
1222 
1223  case Style:
1224  return tr( "ERROR: Failed to created default style file as %1. Check file permissions and retry." ).arg( myFileName );
1225  }
1226  }
1227  }
1228  else
1229  {
1230  QString qml = myDocument.toString();
1231 
1232  // read from database
1233  sqlite3_database_unique_ptr database;
1234  sqlite3_statement_unique_ptr statement;
1235 
1236  int myResult = database.open( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ) );
1237  if ( myResult != SQLITE_OK )
1238  {
1239  return tr( "User database could not be opened." );
1240  }
1241 
1242  QByteArray param0 = uri.toUtf8();
1243  QByteArray param1 = qml.toUtf8();
1244 
1245  QString mySql;
1246  switch ( type )
1247  {
1248  case Metadata:
1249  mySql = QStringLiteral( "create table if not exists tbl_metadata(metadata varchar primary key,qmd varchar)" );
1250  break;
1251 
1252  case Style:
1253  mySql = QStringLiteral( "create table if not exists tbl_styles(style varchar primary key,qml varchar)" );
1254  break;
1255  }
1256 
1257  statement = database.prepare( mySql, myResult );
1258  if ( myResult == SQLITE_OK )
1259  {
1260  if ( sqlite3_step( statement.get() ) != SQLITE_DONE )
1261  {
1262  resultFlag = false;
1263  switch ( type )
1264  {
1265  case Metadata:
1266  return tr( "The metadata table could not be created." );
1267 
1268  case Style:
1269  return tr( "The style table could not be created." );
1270  }
1271  }
1272  }
1273 
1274  switch ( type )
1275  {
1276  case Metadata:
1277  mySql = QStringLiteral( "insert into tbl_metadata(metadata,qmd) values (?,?)" );
1278  break;
1279 
1280  case Style:
1281  mySql = QStringLiteral( "insert into tbl_styles(style,qml) values (?,?)" );
1282  break;
1283  }
1284  statement = database.prepare( mySql, myResult );
1285  if ( myResult == SQLITE_OK )
1286  {
1287  if ( sqlite3_bind_text( statement.get(), 1, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
1288  sqlite3_bind_text( statement.get(), 2, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
1289  sqlite3_step( statement.get() ) == SQLITE_DONE )
1290  {
1291  resultFlag = true;
1292  switch ( type )
1293  {
1294  case Metadata:
1295  myErrorMessage = tr( "The metadata %1 was saved to database" ).arg( uri );
1296  break;
1297 
1298  case Style:
1299  myErrorMessage = tr( "The style %1 was saved to database" ).arg( uri );
1300  break;
1301  }
1302  }
1303  }
1304 
1305  if ( !resultFlag )
1306  {
1307  QString mySql;
1308  switch ( type )
1309  {
1310  case Metadata:
1311  mySql = QStringLiteral( "update tbl_metadata set qmd=? where metadata=?" );
1312  break;
1313 
1314  case Style:
1315  mySql = QStringLiteral( "update tbl_styles set qml=? where style=?" );
1316  break;
1317  }
1318  statement = database.prepare( mySql, myResult );
1319  if ( myResult == SQLITE_OK )
1320  {
1321  if ( sqlite3_bind_text( statement.get(), 2, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
1322  sqlite3_bind_text( statement.get(), 1, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
1323  sqlite3_step( statement.get() ) == SQLITE_DONE )
1324  {
1325  resultFlag = true;
1326  switch ( type )
1327  {
1328  case Metadata:
1329  myErrorMessage = tr( "The metadata %1 was updated in the database." ).arg( uri );
1330  break;
1331 
1332  case Style:
1333  myErrorMessage = tr( "The style %1 was updated in the database." ).arg( uri );
1334  break;
1335  }
1336  }
1337  else
1338  {
1339  resultFlag = false;
1340  switch ( type )
1341  {
1342  case Metadata:
1343  myErrorMessage = tr( "The metadata %1 could not be updated in the database." ).arg( uri );
1344  break;
1345 
1346  case Style:
1347  myErrorMessage = tr( "The style %1 could not be updated in the database." ).arg( uri );
1348  break;
1349  }
1350  }
1351  }
1352  else
1353  {
1354  resultFlag = false;
1355  switch ( type )
1356  {
1357  case Metadata:
1358  myErrorMessage = tr( "The metadata %1 could not be inserted into database." ).arg( uri );
1359  break;
1360 
1361  case Style:
1362  myErrorMessage = tr( "The style %1 could not be inserted into database." ).arg( uri );
1363  break;
1364  }
1365  }
1366  }
1367  }
1368 
1369  return myErrorMessage;
1370 }
1371 
1372 QString QgsMapLayer::saveNamedStyle( const QString &uri, bool &resultFlag, StyleCategories categories )
1373 {
1374  return saveNamedProperty( uri, QgsMapLayer::Style, resultFlag, categories );
1375 }
1376 
1377 void QgsMapLayer::exportSldStyle( QDomDocument &doc, QString &errorMsg ) const
1378 {
1379  QDomDocument myDocument = QDomDocument();
1380 
1381  QDomNode header = myDocument.createProcessingInstruction( QStringLiteral( "xml" ), QStringLiteral( "version=\"1.0\" encoding=\"UTF-8\"" ) );
1382  myDocument.appendChild( header );
1383 
1384  const QgsVectorLayer *vlayer = qobject_cast<const QgsVectorLayer *>( this );
1385  const QgsRasterLayer *rlayer = qobject_cast<const QgsRasterLayer *>( this );
1386  if ( !vlayer && !rlayer )
1387  {
1388  errorMsg = tr( "Could not save symbology because:\n%1" )
1389  .arg( tr( "Only vector and raster layers are supported" ) );
1390  return;
1391  }
1392 
1393  // Create the root element
1394  QDomElement root = myDocument.createElementNS( QStringLiteral( "http://www.opengis.net/sld" ), QStringLiteral( "StyledLayerDescriptor" ) );
1395  QDomElement layerNode;
1396  if ( vlayer )
1397  {
1398  root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.1.0" ) );
1399  root.setAttribute( QStringLiteral( "xsi:schemaLocation" ), QStringLiteral( "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" ) );
1400  root.setAttribute( QStringLiteral( "xmlns:ogc" ), QStringLiteral( "http://www.opengis.net/ogc" ) );
1401  root.setAttribute( QStringLiteral( "xmlns:se" ), QStringLiteral( "http://www.opengis.net/se" ) );
1402  root.setAttribute( QStringLiteral( "xmlns:xlink" ), QStringLiteral( "http://www.w3.org/1999/xlink" ) );
1403  root.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) );
1404  myDocument.appendChild( root );
1405 
1406  // Create the NamedLayer element
1407  layerNode = myDocument.createElement( QStringLiteral( "NamedLayer" ) );
1408  root.appendChild( layerNode );
1409  }
1410 
1411  // note: Only SLD 1.0 version is generated because seems none is using SE1.1.0 at least for rasters
1412  if ( rlayer )
1413  {
1414  // Create the root element
1415  root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0.0" ) );
1416  root.setAttribute( QStringLiteral( "xmlns:gml" ), QStringLiteral( "http://www.opengis.net/gml" ) );
1417  root.setAttribute( QStringLiteral( "xmlns:ogc" ), QStringLiteral( "http://www.opengis.net/ogc" ) );
1418  root.setAttribute( QStringLiteral( "xmlns:sld" ), QStringLiteral( "http://www.opengis.net/sld" ) );
1419  myDocument.appendChild( root );
1420 
1421  // Create the NamedLayer element
1422  layerNode = myDocument.createElement( QStringLiteral( "UserLayer" ) );
1423  root.appendChild( layerNode );
1424  }
1425 
1426  QgsStringMap props;
1427  if ( hasScaleBasedVisibility() )
1428  {
1429  props[ QStringLiteral( "scaleMinDenom" ) ] = QString::number( mMinScale );
1430  props[ QStringLiteral( "scaleMaxDenom" ) ] = QString::number( mMaxScale );
1431  }
1432 
1433  if ( vlayer )
1434  {
1435  if ( !vlayer->writeSld( layerNode, myDocument, errorMsg, props ) )
1436  {
1437  errorMsg = tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1438  return;
1439  }
1440  }
1441 
1442  if ( rlayer )
1443  {
1444  if ( !rlayer->writeSld( layerNode, myDocument, errorMsg, props ) )
1445  {
1446  errorMsg = tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1447  return;
1448  }
1449  }
1450 
1451  doc = myDocument;
1452 }
1453 
1454 QString QgsMapLayer::saveSldStyle( const QString &uri, bool &resultFlag ) const
1455 {
1456  const QgsMapLayer *mlayer = qobject_cast<const QgsMapLayer *>( this );
1457 
1458  QString errorMsg;
1459  QDomDocument myDocument;
1460  mlayer->exportSldStyle( myDocument, errorMsg );
1461  if ( !errorMsg.isNull() )
1462  {
1463  resultFlag = false;
1464  return errorMsg;
1465  }
1466  // check if the uri is a file or ends with .sld,
1467  // which indicates that it should become one
1468  QString filename;
1469  if ( mlayer->providerType() == QLatin1String( "ogr" ) )
1470  {
1471  QStringList theURIParts = uri.split( '|' );
1472  filename = theURIParts[0];
1473  }
1474  else if ( mlayer->providerType() == QLatin1String( "gpx" ) )
1475  {
1476  QStringList theURIParts = uri.split( '?' );
1477  filename = theURIParts[0];
1478  }
1479  else if ( mlayer->providerType() == QLatin1String( "delimitedtext" ) )
1480  {
1481  filename = QUrl::fromEncoded( uri.toLatin1() ).toLocalFile();
1482  // toLocalFile() returns an empty string if theURI is a plain Windows-path, e.g. "C:/style.qml"
1483  if ( filename.isEmpty() )
1484  filename = uri;
1485  }
1486  else
1487  {
1488  filename = uri;
1489  }
1490 
1491  QFileInfo myFileInfo( filename );
1492  if ( myFileInfo.exists() || filename.endsWith( QLatin1String( ".sld" ), Qt::CaseInsensitive ) )
1493  {
1494  QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
1495  if ( !myDirInfo.isWritable() )
1496  {
1497  return tr( "The directory containing your dataset needs to be writable!" );
1498  }
1499 
1500  // now construct the file name for our .sld style file
1501  QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".sld";
1502 
1503  QFile myFile( myFileName );
1504  if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
1505  {
1506  QTextStream myFileStream( &myFile );
1507  // save as utf-8 with 2 spaces for indents
1508  myDocument.save( myFileStream, 2 );
1509  myFile.close();
1510  resultFlag = true;
1511  return tr( "Created default style file as %1" ).arg( myFileName );
1512  }
1513  }
1514 
1515  resultFlag = false;
1516  return tr( "ERROR: Failed to created SLD style file as %1. Check file permissions and retry." ).arg( filename );
1517 }
1518 
1519 QString QgsMapLayer::loadSldStyle( const QString &uri, bool &resultFlag )
1520 {
1521  resultFlag = false;
1522 
1523  QDomDocument myDocument;
1524 
1525  // location of problem associated with errorMsg
1526  int line, column;
1527  QString myErrorMessage;
1528 
1529  QFile myFile( uri );
1530  if ( myFile.open( QFile::ReadOnly ) )
1531  {
1532  // read file
1533  resultFlag = myDocument.setContent( &myFile, true, &myErrorMessage, &line, &column );
1534  if ( !resultFlag )
1535  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1536  myFile.close();
1537  }
1538  else
1539  {
1540  myErrorMessage = tr( "Unable to open file %1" ).arg( uri );
1541  }
1542 
1543  if ( !resultFlag )
1544  {
1545  return myErrorMessage;
1546  }
1547 
1548  // check for root SLD element
1549  QDomElement myRoot = myDocument.firstChildElement( QStringLiteral( "StyledLayerDescriptor" ) );
1550  if ( myRoot.isNull() )
1551  {
1552  myErrorMessage = QStringLiteral( "Error: StyledLayerDescriptor element not found in %1" ).arg( uri );
1553  resultFlag = false;
1554  return myErrorMessage;
1555  }
1556 
1557  // now get the style node out and pass it over to the layer
1558  // to deserialise...
1559  QDomElement namedLayerElem = myRoot.firstChildElement( QStringLiteral( "NamedLayer" ) );
1560  if ( namedLayerElem.isNull() )
1561  {
1562  myErrorMessage = QStringLiteral( "Info: NamedLayer element not found." );
1563  resultFlag = false;
1564  return myErrorMessage;
1565  }
1566 
1567  QString errorMsg;
1568  resultFlag = readSld( namedLayerElem, errorMsg );
1569  if ( !resultFlag )
1570  {
1571  myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( uri, errorMsg );
1572  return myErrorMessage;
1573  }
1574 
1575  return QString();
1576 }
1577 
1578 bool QgsMapLayer::readStyle( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
1579 {
1580  Q_UNUSED( node )
1581  Q_UNUSED( errorMessage )
1582  Q_UNUSED( context )
1583  Q_UNUSED( categories )
1584  return false;
1585 }
1586 
1587 bool QgsMapLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage,
1588  const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1589 {
1590  Q_UNUSED( node )
1591  Q_UNUSED( doc )
1592  Q_UNUSED( errorMessage )
1593  Q_UNUSED( context )
1594  Q_UNUSED( categories )
1595  return false;
1596 }
1597 
1598 void QgsMapLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag )
1599 {
1600  Q_UNUSED( dataSource )
1601  Q_UNUSED( baseName )
1602  Q_UNUSED( provider )
1603  Q_UNUSED( options )
1604  Q_UNUSED( loadDefaultStyleFlag )
1605 }
1606 
1607 
1609 {
1610  return mProviderKey;
1611 }
1612 
1613 void QgsMapLayer::readCommonStyle( const QDomElement &layerElement, const QgsReadWriteContext &context,
1614  QgsMapLayer::StyleCategories categories )
1615 {
1616  if ( categories.testFlag( Symbology3D ) )
1617  {
1618  QgsAbstract3DRenderer *r3D = nullptr;
1619  QDomElement renderer3DElem = layerElement.firstChildElement( QStringLiteral( "renderer-3d" ) );
1620  if ( !renderer3DElem.isNull() )
1621  {
1622  QString type3D = renderer3DElem.attribute( QStringLiteral( "type" ) );
1624  if ( meta3D )
1625  {
1626  r3D = meta3D->createRenderer( renderer3DElem, context );
1627  }
1628  }
1629  setRenderer3D( r3D );
1630  }
1631 
1632  if ( categories.testFlag( CustomProperties ) )
1633  {
1634  // read custom properties before passing reading further to a subclass, so that
1635  // the subclass can also read custom properties
1636  readCustomProperties( layerElement );
1637  }
1638 
1639  // use scale dependent visibility flag
1640  if ( categories.testFlag( Rendering ) )
1641  {
1642  setScaleBasedVisibility( layerElement.attribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ) ).toInt() == 1 );
1643  if ( layerElement.hasAttribute( QStringLiteral( "minimumScale" ) ) )
1644  {
1645  // older element, when scales were reversed
1646  setMaximumScale( layerElement.attribute( QStringLiteral( "minimumScale" ) ).toDouble() );
1647  setMinimumScale( layerElement.attribute( QStringLiteral( "maximumScale" ) ).toDouble() );
1648  }
1649  else
1650  {
1651  setMaximumScale( layerElement.attribute( QStringLiteral( "maxScale" ) ).toDouble() );
1652  setMinimumScale( layerElement.attribute( QStringLiteral( "minScale" ) ).toDouble() );
1653  }
1654  }
1655 
1656  if ( categories.testFlag( LayerConfiguration ) )
1657  {
1658  // flags
1659  QDomElement flagsElem = layerElement.firstChildElement( QStringLiteral( "flags" ) );
1660  LayerFlags flags = mFlags;
1661  auto enumMap = qgsEnumMap<QgsMapLayer::LayerFlag>();
1662  for ( auto it = enumMap.constBegin(); it != enumMap.constEnd(); ++it )
1663  {
1664  QDomNode flagNode = flagsElem.namedItem( it.value() );
1665  if ( flagNode.isNull() )
1666  continue;
1667  bool flagValue = flagNode.toElement().text() == "1" ? true : false;
1668  if ( flags.testFlag( it.key() ) && !flagValue )
1669  flags &= ~it.key();
1670  else if ( !flags.testFlag( it.key() ) && flagValue )
1671  flags |= it.key();
1672  }
1673  setFlags( flags );
1674  }
1675 }
1676 
1678 {
1679  return mUndoStack;
1680 }
1681 
1683 {
1684  return mUndoStackStyles;
1685 }
1686 
1688 {
1689  return mCustomProperties.keys();
1690 }
1691 
1692 void QgsMapLayer::setCustomProperty( const QString &key, const QVariant &value )
1693 {
1694  mCustomProperties.setValue( key, value );
1695 }
1696 
1698 {
1699  mCustomProperties = properties;
1700 }
1701 
1702 QVariant QgsMapLayer::customProperty( const QString &value, const QVariant &defaultValue ) const
1703 {
1704  return mCustomProperties.value( value, defaultValue );
1705 }
1706 
1707 void QgsMapLayer::removeCustomProperty( const QString &key )
1708 {
1709  mCustomProperties.remove( key );
1710 }
1711 
1713 {
1714  return mError;
1715 }
1716 
1717 
1718 
1720 {
1721  return false;
1722 }
1723 
1725 {
1726  return true;
1727 }
1728 
1730 {
1731  // invalid layers are temporary? -- who knows?!
1732  if ( !isValid() )
1733  return false;
1734 
1735  if ( mProviderKey == QLatin1String( "memory" ) )
1736  return true;
1737 
1738  const QVariantMap sourceParts = QgsProviderRegistry::instance()->decodeUri( mProviderKey, mDataSource );
1739  const QString path = sourceParts.value( QStringLiteral( "path" ) ).toString();
1740  if ( path.isEmpty() )
1741  return false;
1742 
1743  // check if layer path is inside one of the standard temporary file locations for this platform
1744  const QStringList tempPaths = QStandardPaths::standardLocations( QStandardPaths::TempLocation );
1745  for ( const QString &tempPath : tempPaths )
1746  {
1747  if ( path.startsWith( tempPath ) )
1748  return true;
1749  }
1750 
1751  return false;
1752 }
1753 
1754 void QgsMapLayer::setValid( bool valid )
1755 {
1756  mValid = valid;
1757 }
1758 
1760 {
1761  if ( legend == mLegend )
1762  return;
1763 
1764  delete mLegend;
1765  mLegend = legend;
1766 
1767  if ( mLegend )
1768  {
1769  mLegend->setParent( this );
1770  connect( mLegend, &QgsMapLayerLegend::itemsChanged, this, &QgsMapLayer::legendChanged );
1771  }
1772 
1773  emit legendChanged();
1774 }
1775 
1777 {
1778  return mLegend;
1779 }
1780 
1782 {
1783  return mStyleManager;
1784 }
1785 
1787 {
1788  if ( renderer == m3DRenderer )
1789  return;
1790 
1791  delete m3DRenderer;
1792  m3DRenderer = renderer;
1793  emit renderer3DChanged();
1794 }
1795 
1797 {
1798  return m3DRenderer;
1799 }
1800 
1801 void QgsMapLayer::triggerRepaint( bool deferredUpdate )
1802 {
1803  if ( mRepaintRequestedFired )
1804  return;
1805 
1806  mRepaintRequestedFired = true;
1807  emit repaintRequested( deferredUpdate );
1808  mRepaintRequestedFired = false;
1809 }
1810 
1812 {
1813  mMetadata = metadata;
1814 // mMetadata.saveToLayer( this );
1815  emit metadataChanged();
1816 }
1817 
1819 {
1820  return QString();
1821 }
1822 
1823 QDateTime QgsMapLayer::timestamp() const
1824 {
1825  return QDateTime();
1826 }
1827 
1829 {
1830  emit styleChanged();
1831 }
1832 
1834 {
1835  mExtent = r;
1836 }
1837 
1838 bool QgsMapLayer::isReadOnly() const
1839 {
1840  return true;
1841 }
1842 
1844 {
1845  return mOriginalXmlProperties;
1846 }
1847 
1849 {
1850  mOriginalXmlProperties = originalXmlProperties;
1851 }
1852 
1853 QString QgsMapLayer::generateId( const QString &layerName )
1854 {
1855  // Generate the unique ID of this layer
1856  QString uuid = QUuid::createUuid().toString();
1857  // trim { } from uuid
1858  QString id = layerName + '_' + uuid.mid( 1, uuid.length() - 2 );
1859  // Tidy the ID up to avoid characters that may cause problems
1860  // elsewhere (e.g in some parts of XML). Replaces every non-word
1861  // character (word characters are the alphabet, numbers and
1862  // underscore) with an underscore.
1863  // Note that the first backslash in the regular expression is
1864  // there for the compiler, so the pattern is actually \W
1865  id.replace( QRegExp( "[\\W]" ), QStringLiteral( "_" ) );
1866  return id;
1867 }
1868 
1870 {
1871  return true;
1872 }
1873 
1875 {
1877 }
1878 
1879 QSet<QgsMapLayerDependency> QgsMapLayer::dependencies() const
1880 {
1881  return mDependencies;
1882 }
1883 
1884 bool QgsMapLayer::setDependencies( const QSet<QgsMapLayerDependency> &oDeps )
1885 {
1886  QSet<QgsMapLayerDependency> deps;
1887  const auto constODeps = oDeps;
1888  for ( const QgsMapLayerDependency &dep : constODeps )
1889  {
1890  if ( dep.origin() == QgsMapLayerDependency::FromUser )
1891  deps << dep;
1892  }
1893 
1894  mDependencies = deps;
1895  emit dependenciesChanged();
1896  return true;
1897 }
1898 
1900 {
1901  if ( !dataProvider() )
1902  return;
1903 
1904  if ( enabled && !isRefreshOnNotifyEnabled() )
1905  {
1906  dataProvider()->setListening( enabled );
1907  connect( dataProvider(), &QgsVectorDataProvider::notify, this, &QgsMapLayer::onNotifiedTriggerRepaint );
1908  }
1909  else if ( !enabled && isRefreshOnNotifyEnabled() )
1910  {
1911  // we don't want to disable provider listening because someone else could need it (e.g. actions)
1912  disconnect( dataProvider(), &QgsVectorDataProvider::notify, this, &QgsMapLayer::onNotifiedTriggerRepaint );
1913  }
1914  mIsRefreshOnNofifyEnabled = enabled;
1915 }
1916 
1917 void QgsMapLayer::onNotifiedTriggerRepaint( const QString &message )
1918 {
1919  if ( refreshOnNotifyMessage().isEmpty() || refreshOnNotifyMessage() == message )
1920  triggerRepaint();
1921 }
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.
QString attributionUrl() const
Returns the attribution URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:388
QString mShortName
Definition: qgsmaplayer.h:1506
virtual QStringList subLayers() const
Returns the sublayers of this layer.
void setMetadataUrl(const QString &metaUrl)
Sets the metadata URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:399
The class is used as a container of context for various read/write operations on other objects...
QString dataUrlFormat() const
Returns the DataUrl format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:350
static QString generateId(const QString &layerName)
Generates an unique identifier for this layer, the generate ID is prefixed by layerName.
A rectangle specified with double values.
Definition: qgsrectangle.h:41
Base class for all map layer types.
Definition: qgsmaplayer.h:79
static QString formatLayerName(const QString &name)
A convenience function to capitalize and format a layer name.
static Qgs3DRendererRegistry * renderer3DRegistry()
Returns registry of available 3D renderers.
QStringList styles() const
Returns list of all defined style names.
void setShortName(const QString &shortName)
Sets the short name of the layer used by QGIS Server to identify the layer.
Definition: qgsmaplayer.h:258
virtual void resolveReferences(const QgsProject &project)
Resolves references to other objects - second phase of loading - after readXml()
virtual void exportSldStyle(QDomDocument &doc, QString &errorMsg) const
Export the properties of this layer as SLD style in a QDomDocument.
void setProviderType(const QString &providerType)
Sets the providerType (provider key)
virtual QgsMapLayer * clone() const =0
Returns a new instance equivalent to this one except for the id which is still unique.
void dependenciesChanged()
Emitted when dependencies are changed.
virtual QString loadSldStyle(const QString &uri, bool &resultFlag)
Attempts to style the layer using the formatting from an SLD type file.
Base class for all renderers that may to participate in 3D view.
QgsMapLayerType type() const
Returns the type of the layer.
QString mAttributionUrl
Definition: qgsmaplayer.h:1519
QString mKeywordList
Definition: qgsmaplayer.h:1511
static QString qgisSettingsDirPath()
Returns the path to the settings directory in user&#39;s home dir.
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 QSet< QgsMapLayerDependency > dependencies() const
Gets the list of dependencies.
bool readLayerXml(const QDomElement &layerElement, QgsReadWriteContext &context, QgsMapLayer::ReadFlags flags=nullptr)
Sets state from DOM document.
virtual bool importNamedStyle(QDomDocument &doc, QString &errorMsg, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories)
Import the properties of this layer from a QDomDocument.
virtual QgsDataProvider * dataProvider()
Returns the layer&#39;s data provider, it may be nullptr.
void readXml(const QDomNode &parentNode, const QString &keyStartsWith=QString())
Read store contents from XML.
void reset()
Reset the style manager to a basic state - with one default style which is set as current...
Q_INVOKABLE QStringList customPropertyKeys() const
Returns list of all keys within custom properties.
MAYBE_UNUSED NODISCARD QgsReadWriteContextCategoryPopper enterCategory(const QString &category, const QString &details=QString())
Push a category to the stack.
QString shortName() const
Returns the short name of the layer used by QGIS Server to identify the layer.
QgsMapLayerLegend * legend() const
Can be nullptr.
Unique pointer for sqlite3 prepared statements, which automatically finalizes the statement when the ...
void setCustomProperties(const QgsObjectCustomProperties &properties)
Set custom properties for layer.
void metadataChanged()
Emitted when the layer&#39;s metadata is changed.
QString mDataUrlFormat
Definition: qgsmaplayer.h:1515
virtual QgsError error() const
Gets current status error.
Represents a raster layer.
void validate()
Perform some validation on this CRS.
bool mShouldValidateCrs
true if the layer&#39;s CRS should be validated and invalid CRSes are not permitted.
Definition: qgsmaplayer.h:1559
QString dataUrl() const
Returns the DataUrl of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:332
QString mProviderKey
Data provider key (name of the data provider)
Definition: qgsmaplayer.h:1547
bool updateRevision(const QgsProjectVersion &version)
void emitStyleChanged()
Triggers an emission of the styleChanged() signal.
QString providerType() const
Returns the provider type (provider key) for this layer.
PropertyType
Maplayer has a style and a metadata property.
Definition: qgsmaplayer.h:124
QString mLegendUrlFormat
Definition: qgsmaplayer.h:1528
void setRefreshOnNotifyEnabled(bool enabled)
Set whether provider notification is connected to triggerRepaint.
Q_INVOKABLE void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for layer.
static void setCustomCrsValidation(CUSTOM_CRS_VALIDATION f)
Sets custom function to force valid CRS.
void readCustomProperties(const QDomNode &layerNode, const QString &keyStartsWith=QString())
Read custom properties from project file.
virtual bool loadNamedStyleFromDatabase(const QString &db, const QString &uri, QString &qml)
Retrieve a named style for this layer from a sqlite database.
virtual void resolveReferences(QgsProject *project)
Resolve references to other layers (kept as layer IDs after reading XML) into layer objects...
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...
virtual QString saveSldStyle(const QString &uri, bool &resultFlag) const
Saves the properties of this layer to an SLD format file.
static QDomElement writeRectangle(const QgsRectangle &rect, QDomDocument &doc)
Definition: qgsxmlutils.cpp:79
void crsChanged()
Emit a signal that layer&#39;s CRS has been reset.
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
virtual const QgsLayerMetadata & metadata() const
Returns a reference to the layer&#39;s metadata store.
void configChanged()
Emitted whenever the configuration is changed.
bool isInScaleRange(double scale) const
Tests whether the layer should be visible at the specified scale.
virtual bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified symbology visitor, causing it to visit all symbols associated with the layer...
QgsMapLayer::LayerFlags flags() const
Returns the flags for this layer.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
Returns value for the given key. If the key is not stored, default value will be used.
void setMetadataUrlType(const QString &metaUrlType)
Set the metadata type of the layer used by QGIS Server in GetCapabilities request MetadataUrlType ind...
Definition: qgsmaplayer.h:417
Allows entering a context category and takes care of leaving this category on deletion of the class...
QVariantMap decodeUri(const QString &providerKey, const QString &uri)
Breaks a provider data source URI into its component paths (e.g.
Abstract base class for spatial data provider implementations.
virtual QString encodedSource(const QString &source, const QgsReadWriteContext &context) const
Called by writeLayerXML(), used by derived classes to encode provider&#39;s specific data source to proje...
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 writeXml(QDomNode &parentNode, QDomDocument &doc) const
Write store contents to XML.
QString saveNamedMetadata(const QString &uri, bool &resultFlag)
Save the current metadata of this layer as a named metadata (either as a .qmd file on disk or as a re...
bool isValid() const
Returns the status of the layer.
An interface for classes which can visit style entity (e.g.
void notify(const QString &msg)
Emitted when the datasource issues a notification.
void setBlendMode(QPainter::CompositionMode blendMode)
Set the blending mode used for rendering a layer.
bool mIsRefreshOnNofifyEnabled
Definition: qgsmaplayer.h:1543
QMap< QString, QString > QgsStringMap
Definition: qgis.h:694
void remove(const QString &key)
Remove a key (entry) from the store.
void exportNamedMetadata(QDomDocument &doc, QString &errorMsg) const
Export the current metadata of this layer as named metadata in a QDomDocument.
QString mLayerName
Name of the layer - used for display.
Definition: qgsmaplayer.h:1504
bool isRefreshOnNotifyEnabled() const
Returns true if the refresh on provider nofification is enabled.
Definition: qgsmaplayer.h:1138
void styleChanged()
Signal emitted whenever a change affects the layer&#39;s style.
bool loadNamedMetadataFromDatabase(const QString &db, const QString &uri, QString &qmd)
Retrieve a named metadata for this layer from a sqlite database.
virtual QString htmlMetadata() const
Obtain a formatted HTML string containing assorted metadata for this layer.
virtual QgsRectangle extent() const
Returns the extent of the layer.
void writeCustomProperties(QDomNode &layerNode, QDomDocument &doc) const
Write custom properties to project file.
const QgsProjectTranslator * projectTranslator() const
Returns the project translator.
void setMaximumScale(double scale)
Sets the maximum map scale (i.e.
QgsMapLayerStyleManager * styleManager() const
Gets access to the layer&#39;s style manager.
QgsError mError
Error.
Definition: qgsmaplayer.h:1531
QgsRectangle mExtent
Extent of the layer.
Definition: qgsmaplayer.h:1495
virtual void writeXml(QDomElement &elem, const QgsReadWriteContext &context) const =0
Writes renderer&#39;s properties to given XML element.
static T readFlagAttribute(const QDomElement &element, const QString &attributeName, T defaultValue)
Read a flag value from an attribute of the element.
Definition: qgsxmlutils.h:92
QString mMetadataUrl
MetadataUrl of the layer.
Definition: qgsmaplayer.h:1522
void setLegendUrlFormat(const QString &legendUrlFormat)
Sets the format for a URL based layer legend.
Definition: qgsmaplayer.h:971
QString metadataUrlFormat() const
Returns the metadata format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:444
void setValidationHint(const QString &html)
Set user hint for validation.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
void setKeywordList(const QString &keywords)
Sets the keyword list of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:304
void setValue(const QString &key, const QVariant &value)
Add an entry to the store. If the entry with the keys exists already, it will be overwritten.
static QString version()
Version string.
Definition: qgis.cpp:276
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
bool readMetadataXml(const QDomElement &metadataElement) override
Sets state from DOM document.
static QString capitalize(const QString &string, Capitalization capitalization)
Converts a string by applying capitalization rules to the string.
void writeCommonStyle(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const
Write style data common to all layer types.
void setTitle(const QString &title)
Sets the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:272
void readStyleManager(const QDomNode &layerNode)
Read style manager&#39;s configuration (if any). To be called by subclasses.
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted...
int autoRefreshInterval() const
Returns the auto refresh interval (in milliseconds).
virtual void setSubLayerVisibility(const QString &name, bool visible)
Set the visibility of the given sublayer name.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
virtual QString type() const =0
Returns unique identifier of the renderer class (used to identify subclass)
virtual QString decodedSource(const QString &source, const QString &dataProvider, const QgsReadWriteContext &context) const
Called by readLayerXML(), used by derived classes to decode provider&#39;s specific data source from proj...
void setOriginalXmlProperties(const QString &originalXmlProperties)
Sets the original XML properties for the layer to originalXmlProperties.
Rendering: scale visibility, simplify method, opacity.
Definition: qgsmaplayer.h:161
virtual void setMetadata(const QgsLayerMetadata &metadata)
Sets the layer&#39;s metadata store.
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer&#39;s spatial reference system.
QSet< QgsMapLayerDependency > mDependencies
List of layers that may modify this layer on modification.
Definition: qgsmaplayer.h:1534
virtual void setListening(bool isListening)
Set whether the provider will listen to datasource notifications If set, the provider will issue noti...
void nameChanged()
Emitted when the name has been changed.
A class to describe the version of a project.
virtual void setExtent(const QgsRectangle &rect)
Sets the extent.
void readXml(const QDomElement &mgrElement)
Read configuration (for project loading)
QString keywordList() const
Returns the keyword list of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:312
bool writeSld(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsStringMap &props=QgsStringMap()) const
Writes the symbology of the layer into the document provided in SLD 1.1 format.
QString mDataUrl
DataUrl of the layer.
Definition: qgsmaplayer.h:1514
The QgsMapLayerLegend class is abstract interface for implementations of legends for one map layer...
virtual bool isEditable() const
Returns true if the layer can be edited.
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 ...
QString legendUrl() const
Returns the URL for the layer&#39;s legend.
Definition: qgsmaplayer.h:966
QgsCoordinateReferenceSystem crs() const
Returns the layer&#39;s spatial reference system.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts, annotations, canvases, etc.
Definition: qgsproject.h:91
QString publicSource() const
Gets a version of the internal layer definition that has sensitive bits removed (for example...
void setRenderer3D(QgsAbstract3DRenderer *renderer)
Sets 3D renderer for the layer.
void removeCustomProperty(const QString &key)
Remove a custom property from layer.
static QString extensionPropertyType(PropertyType type)
Returns the extension of a Property.
Definition: qgsmaplayer.cpp:57
QgsCoordinateTransformContext transformContext() const
Returns the layer data provider coordinate transform context or a default transform context if the la...
sqlite3_statement_unique_ptr prepare(const QString &sql, int &resultCode) const
Prepares a sql statement, returning the result.
double minimumScale() const
Returns the minimum map scale (i.e.
Contains information about the context in which a coordinate transform is executed.
double maximumScale() const
Returns the maximum map scale (i.e.
bool mValid
Indicates if the layer is valid and can be drawn.
Definition: qgsmaplayer.h:1498
void setName(const QString &name)
Set the display name of the layer.
void setDataUrlFormat(const QString &dataUrlFormat)
Sets the DataUrl format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:341
int open(const QString &path)
Opens the database at the specified file path.
QStringList keys() const
Returns list of stored keys.
QgsAbstract3DRenderer * renderer3D() const
Returns 3D renderer associated with the layer.
QString mTitle
Definition: qgsmaplayer.h:1507
virtual bool readSld(const QDomNode &node, QString &errorMessage)
Definition: qgsmaplayer.h:869
QString legendUrlFormat() const
Returns the format for a URL based layer legend.
Definition: qgsmaplayer.h:976
Convert just the first letter of each word to uppercase, leave the rest untouched.
QString mMetadataUrlFormat
Definition: qgsmaplayer.h:1524
void setLegendUrl(const QString &legendUrl)
Sets the URL for the layer&#39;s legend.
Definition: qgsmaplayer.h:961
void setMetadataUrlFormat(const QString &metaUrlFormat)
Sets the metadata format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:435
virtual bool readXml(const QDomNode &layer_node, QgsReadWriteContext &context)
Called by readLayerXML(), used by children to read state specific to them from project files...
QString title() const
Returns the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:280
static QString pkgDataPath()
Returns the common root path of all application data directories.
static CUSTOM_CRS_VALIDATION customCrsValidation()
Gets custom function.
void repaintRequested(bool deferredUpdate=false)
By emitting this signal the layer tells that either appearance or content have been changed and any v...
virtual void exportNamedStyle(QDomDocument &doc, QString &errorMsg, const QgsReadWriteContext &context=QgsReadWriteContext(), QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) const
Export the properties of this layer as named style in a QDomDocument.
virtual QString translate(const QString &context, const QString &sourceText, const char *disambiguation=nullptr, int n=-1) const =0
The derived translate() translates with QTranslator and qm file the sourceText.
QString mAttribution
Attribution of the layer.
Definition: qgsmaplayer.h:1518
QString mAbstract
Description of the layer.
Definition: qgsmaplayer.h:1510
General configuration: identifiable, removable, searchable, display expression, read-only.
Definition: qgsmaplayer.h:151
void setScaleBasedVisibility(bool enabled)
Sets whether scale based visibility is enabled for the layer.
void writeStyleManager(QDomNode &layerNode, QDomDocument &doc) const
Write style manager&#39;s configuration (if exists). To be called by subclasses.
Unique pointer for sqlite3 databases, which automatically closes the database when the pointer goes o...
QString originalXmlProperties() const
Returns the XML properties of the original layer as they were when the layer was first read from the ...
void blendModeChanged(QPainter::CompositionMode blendMode)
Signal emitted when the blend mode is changed, through QgsMapLayer::setBlendMode() ...
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 docment provided.
bool writeMetadataXml(QDomElement &metadataElement, QDomDocument &document) const override
Stores state in a DOM node.
A structured metadata store for a map layer.
QgsCoordinateTransformContext transformContext() const
Returns data provider coordinate transform context.
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:139
QString mRefreshOnNofifyMessage
Definition: qgsmaplayer.h:1544
static QgsAuthManager * authManager()
Returns the application&#39;s authentication manager instance.
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.
int open_v2(const QString &path, int flags, const char *zVfs)
Opens the database at the specified file path.
void beforeResolveReferences(QgsProject *project)
Emitted when all layers are loaded and references can be resolved, just before the references of this...
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...
virtual QString saveDefaultStyle(bool &resultFlag)
Save the properties of this layer as the default style (either as a .qml file on disk or as a record ...
Custom properties (by plugins for instance)
Definition: qgsmaplayer.h:162
void itemsChanged()
Emitted when existing items/nodes got invalid and should be replaced by new ones. ...
Setting options for creating vector data providers.
QString name() const
Returns the display name of the layer.
QgsMapLayer(QgsMapLayerType type=QgsMapLayerType::VectorLayer, const QString &name=QString(), const QString &source=QString())
Constructor for QgsMapLayer.
Definition: qgsmaplayer.cpp:70
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.
QString mDataSource
Data source description string, varies by layer type.
Definition: qgsmaplayer.h:1501
QString source() const
Returns the source for the layer.
bool hasScaleBasedVisibility() const
Returns whether scale based visibility is enabled for the layer.
QgsError is container for error messages (report).
Definition: qgserror.h:80
bool setMasterPassword(bool verify=false)
Main call to initially set or continually check master password is set.
void setMinimumScale(double scale)
Sets the minimum map scale (i.e.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:450
Qgs3DRendererAbstractMetadata * rendererMetadata(const QString &type) const
Returns metadata for a 3D renderer type (may be used to create a new instance of the type) ...
QString mLegendUrl
WMS legend.
Definition: qgsmaplayer.h:1527
virtual QString loadNamedStyle(const QString &uri, bool &resultFlag, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories)
Retrieve a named style for this layer if one exists (either as a .qml file on disk or as a record in ...
This class represents a coordinate reference system (CRS).
void legendChanged()
Signal emitted when legend of the layer has changed.
Simple key-value store (keys = strings, values = variants) that supports loading/saving to/from XML i...
void setAutoRefreshInterval(int interval)
Sets the auto refresh interval (in milliseconds) for the layer.
virtual bool isTemporary() const
Returns true if the layer is considered a temporary layer.
virtual bool isSpatial() const
Returns true if the layer is considered a spatial layer, ie it has some form of geometry associated w...
bool readXml(const QDomNode &node)
Restores state from the given DOM node.
void setAttributionUrl(const QString &attribUrl)
Sets the attribution URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:379
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...
QString metadataUrl() const
Returns the metadata URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:408
virtual void setDataSource(const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag=false)
Updates the data source of the layer.
void setAutoRefreshEnabled(bool enabled)
Sets whether auto refresh is enabled for the layer.
QUndoStack * undoStackStyles()
Returns pointer to layer&#39;s style undo stack.
QgsMapLayerType
Types of layers that can be added to a map.
Definition: qgsmaplayer.h:66
bool addStyle(const QString &name, const QgsMapLayerStyle &style)
Add a style with given name and data.
Q_INVOKABLE QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
QUndoStack * undoStack()
Returns pointer to layer&#39;s undo stack.
void setAttribution(const QString &attrib)
Sets the attribution of the layer used by QGIS Server in GetCapabilities request. ...
Definition: qgsmaplayer.h:361
void(* CUSTOM_CRS_VALIDATION)(QgsCoordinateReferenceSystem &)
void setRefreshOnNofifyMessage(const QString &message)
Set the notification message that triggers repaint If refresh on notification is enabled, the notification will triggerRepaint only if the notification message is equal to.
Definition: qgsmaplayer.h:1249
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 ...
bool hasAutoRefreshEnabled() const
Returns true if auto refresh is enabled for the layer.
Base metadata class for 3D renderers.
void setLegend(QgsMapLayerLegend *legend)
Assign a legend controller to the map layer.
bool writeXml(QDomNode &node, QDomDocument &doc) const
Stores state to the given Dom node in the given document.
void autoRefreshIntervalChanged(int interval)
Emitted when the auto refresh interval changes.
This class models dependencies with or between map layers.
Management of styles for use with one map layer.
QString refreshOnNotifyMessage() const
Returns the message that should be notified by the provider to triggerRepaint.
Definition: qgsmaplayer.h:1131
Represents a vector layer which manages a vector based data sets.
virtual QDateTime timestamp() const
Time stamp of data source in the moment when data/metadata were loaded by provider.
virtual void setLayerOrder(const QStringList &layers)
Reorders the previously selected sublayers of this layer from bottom to top.
void writeXml(QDomElement &mgrElement) const
Write configuration (for project saving)
bool writeLayerXml(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context) const
Stores state in DOM node.
void setDataUrl(const QString &dataUrl)
Sets the DataUrl of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:323
void setValid(bool valid)
Sets whether layer is valid or not - should be used in constructor.
QString mMetadataUrlType
Definition: qgsmaplayer.h:1523
virtual QgsAbstract3DRenderer * createRenderer(QDomElement &elem, const QgsReadWriteContext &context)=0
Returns new instance of the renderer given the DOM element.
void setAbstract(const QString &abstract)
Sets the abstract of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:288
static const double SCALE_PRECISION
Fudge factor used to compare two scales.
Definition: qgis.h:168
QString attribution() const
Returns the attribution of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:370
void setFlags(QgsMapLayer::LayerFlags flags)
Returns the flags for this layer.
void flagsChanged()
Emitted when layer&#39;s flags have been modified.
QString metadataUrlType() const
Returns the metadata type of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:426
void readCommonStyle(const QDomElement &layerElement, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories)
Read style data common to all layer types.
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
void renderer3DChanged()
Signal emitted when 3D renderer associated with the layer has changed.
static QString removePassword(const QString &aUri)
Removes the password element from a URI.
QgsMapLayer::ReadFlags mReadFlags
Read flags. It&#39;s up to the subclass to respect these when restoring state from XML.
Definition: qgsmaplayer.h:1552
~QgsMapLayer() override
Definition: qgsmaplayer.cpp:87
bool importNamedMetadata(QDomDocument &document, QString &errorMessage)
Import the metadata of this layer from a QDomDocument.
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...
virtual bool setDependencies(const QSet< QgsMapLayerDependency > &layers)
Sets the list of dependencies.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.