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