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