QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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  // first get base path for delimited text, spatialite and OGR layers,
803  // as in these cases URI may contain layer name and/or additional
804  // information. This also strips prefix in case if VSIFILE mechanism
805  // is used
806  QString providerType = dataProvider()->name();
807  if ( providerType == QLatin1String( "ogr" ) || providerType == QLatin1String( "delimitedtext" ) ||
808  providerType == QLatin1String( "spatialite" ) )
809  {
810  QVariantMap components = QgsProviderRegistry::instance()->decodeUri( providerType, myURI );
811  myURI = components["path"].toString();
812  }
813 
814  QFileInfo myFileInfo( myURI );
815  QString key;
816 
817  if ( myFileInfo.exists() )
818  {
819  // if file is using the /vsizip/ or /vsigzip/ mechanism, cleanup the name
820  if ( myURI.endsWith( QLatin1String( ".gz" ), Qt::CaseInsensitive ) )
821  myURI.chop( 3 );
822  else if ( myURI.endsWith( QLatin1String( ".zip" ), Qt::CaseInsensitive ) )
823  myURI.chop( 4 );
824  else if ( myURI.endsWith( QLatin1String( ".tar" ), Qt::CaseInsensitive ) )
825  myURI.chop( 4 );
826  else if ( myURI.endsWith( QLatin1String( ".tar.gz" ), Qt::CaseInsensitive ) )
827  myURI.chop( 7 );
828  else if ( myURI.endsWith( QLatin1String( ".tgz" ), Qt::CaseInsensitive ) )
829  myURI.chop( 4 );
830  myFileInfo.setFile( myURI );
831  // get the file name for our .qml style file
832  key = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + QgsMapLayer::extensionPropertyType( type );
833  }
834  else
835  {
836  key = publicSource();
837  }
838 
839  return key;
840 }
841 
843 {
844  return baseURI( PropertyType::Metadata );
845 }
846 
847 QString QgsMapLayer::saveDefaultMetadata( bool &resultFlag )
848 {
849  return saveNamedMetadata( metadataUri(), resultFlag );
850 }
851 
852 QString QgsMapLayer::loadDefaultMetadata( bool &resultFlag )
853 {
854  return loadNamedMetadata( metadataUri(), resultFlag );
855 }
856 
857 QString QgsMapLayer::styleURI() const
858 {
859  return baseURI( PropertyType::Style );
860 }
861 
862 QString QgsMapLayer::loadDefaultStyle( bool &resultFlag )
863 {
864  return loadNamedStyle( styleURI(), resultFlag );
865 }
866 
867 bool QgsMapLayer::loadNamedMetadataFromDatabase( const QString &db, const QString &uri, QString &qmd )
868 {
869  return loadNamedPropertyFromDatabase( db, uri, qmd, PropertyType::Metadata );
870 }
871 
872 bool QgsMapLayer::loadNamedStyleFromDatabase( const QString &db, const QString &uri, QString &qml )
873 {
874  return loadNamedPropertyFromDatabase( db, uri, qml, PropertyType::Style );
875 }
876 
877 bool QgsMapLayer::loadNamedPropertyFromDatabase( const QString &db, const QString &uri, QString &xml, QgsMapLayer::PropertyType type )
878 {
879  QgsDebugMsgLevel( QStringLiteral( "db = %1 uri = %2" ).arg( db, uri ), 4 );
880 
881  bool resultFlag = false;
882 
883  // read from database
886 
887  int myResult;
888 
889  QgsDebugMsgLevel( QStringLiteral( "Trying to load style or metadata for \"%1\" from \"%2\"" ).arg( uri, db ), 4 );
890 
891  if ( db.isEmpty() || !QFile( db ).exists() )
892  return false;
893 
894  myResult = database.open_v2( db, SQLITE_OPEN_READONLY, nullptr );
895  if ( myResult != SQLITE_OK )
896  {
897  return false;
898  }
899 
900  QString mySql;
901  switch ( type )
902  {
903  case Metadata:
904  mySql = QStringLiteral( "select qmd from tbl_metadata where metadata=?" );
905  break;
906 
907  case Style:
908  mySql = QStringLiteral( "select qml from tbl_styles where style=?" );
909  break;
910  }
911 
912  statement = database.prepare( mySql, myResult );
913  if ( myResult == SQLITE_OK )
914  {
915  QByteArray param = uri.toUtf8();
916 
917  if ( sqlite3_bind_text( statement.get(), 1, param.data(), param.length(), SQLITE_STATIC ) == SQLITE_OK &&
918  sqlite3_step( statement.get() ) == SQLITE_ROW )
919  {
920  xml = QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( statement.get(), 0 ) ) );
921  resultFlag = true;
922  }
923  }
924  return resultFlag;
925 }
926 
927 
928 QString QgsMapLayer::loadNamedStyle( const QString &uri, bool &resultFlag, QgsMapLayer::StyleCategories categories )
929 {
930  return loadNamedProperty( uri, PropertyType::Style, resultFlag, categories );
931 }
932 
933 QString QgsMapLayer::loadNamedProperty( const QString &uri, QgsMapLayer::PropertyType type, bool &resultFlag, StyleCategories categories )
934 {
935  QgsDebugMsgLevel( QStringLiteral( "uri = %1 myURI = %2" ).arg( uri, publicSource() ), 4 );
936 
937  resultFlag = false;
938 
939  QDomDocument myDocument( QStringLiteral( "qgis" ) );
940 
941  // location of problem associated with errorMsg
942  int line, column;
943  QString myErrorMessage;
944 
945  QFile myFile( uri );
946  if ( myFile.open( QFile::ReadOnly ) )
947  {
948  QgsDebugMsgLevel( QStringLiteral( "file found %1" ).arg( uri ), 2 );
949  // read file
950  resultFlag = myDocument.setContent( &myFile, &myErrorMessage, &line, &column );
951  if ( !resultFlag )
952  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
953  myFile.close();
954  }
955  else
956  {
957  QFileInfo project( QgsProject::instance()->fileName() );
958  QgsDebugMsgLevel( QStringLiteral( "project fileName: %1" ).arg( project.absoluteFilePath() ), 4 );
959 
960  QString xml;
961  switch ( type )
962  {
963  case QgsMapLayer::Style:
964  {
965  if ( loadNamedStyleFromDatabase( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ), uri, xml ) ||
966  ( project.exists() && loadNamedStyleFromDatabase( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), uri, xml ) ) ||
967  loadNamedStyleFromDatabase( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( QStringLiteral( "resources/qgis.qmldb" ) ), uri, xml ) )
968  {
969  resultFlag = myDocument.setContent( xml, &myErrorMessage, &line, &column );
970  if ( !resultFlag )
971  {
972  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
973  }
974  }
975  else
976  {
977  myErrorMessage = tr( "Style not found in database" );
978  resultFlag = false;
979  }
980  break;
981  }
983  {
984  if ( loadNamedMetadataFromDatabase( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ), uri, xml ) ||
985  ( project.exists() && loadNamedMetadataFromDatabase( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), uri, xml ) ) ||
986  loadNamedMetadataFromDatabase( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( QStringLiteral( "resources/qgis.qmldb" ) ), uri, xml ) )
987  {
988  resultFlag = myDocument.setContent( xml, &myErrorMessage, &line, &column );
989  if ( !resultFlag )
990  {
991  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
992  }
993  }
994  else
995  {
996  myErrorMessage = tr( "Metadata not found in database" );
997  resultFlag = false;
998  }
999  break;
1000  }
1001  }
1002  }
1003 
1004  if ( !resultFlag )
1005  {
1006  return myErrorMessage;
1007  }
1008 
1009  switch ( type )
1010  {
1011  case QgsMapLayer::Style:
1012  resultFlag = importNamedStyle( myDocument, myErrorMessage, categories );
1013  if ( !resultFlag )
1014  myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( uri, myErrorMessage );
1015  break;
1016  case QgsMapLayer::Metadata:
1017  resultFlag = importNamedMetadata( myDocument, myErrorMessage );
1018  if ( !resultFlag )
1019  myErrorMessage = tr( "Loading metadata file %1 failed because:\n%2" ).arg( uri, myErrorMessage );
1020  break;
1021  }
1022  return myErrorMessage;
1023 }
1024 
1025 bool QgsMapLayer::importNamedMetadata( QDomDocument &document, QString &errorMessage )
1026 {
1027  QDomElement myRoot = document.firstChildElement( QStringLiteral( "qgis" ) );
1028  if ( myRoot.isNull() )
1029  {
1030  errorMessage = tr( "Root <qgis> element could not be found" );
1031  return false;
1032  }
1033 
1034  return mMetadata.readMetadataXml( myRoot );
1035 }
1036 
1037 bool QgsMapLayer::importNamedStyle( QDomDocument &myDocument, QString &myErrorMessage, QgsMapLayer::StyleCategories categories )
1038 {
1039  QDomElement myRoot = myDocument.firstChildElement( QStringLiteral( "qgis" ) );
1040  if ( myRoot.isNull() )
1041  {
1042  myErrorMessage = tr( "Root <qgis> element could not be found" );
1043  return false;
1044  }
1045 
1046  // get style file version string, if any
1047  QgsProjectVersion fileVersion( myRoot.attribute( QStringLiteral( "version" ) ) );
1048  QgsProjectVersion thisVersion( Qgis::QGIS_VERSION );
1049 
1050  if ( thisVersion > fileVersion )
1051  {
1052  QgsProjectFileTransform styleFile( myDocument, fileVersion );
1053  styleFile.updateRevision( thisVersion );
1054  }
1055 
1056  // Get source categories
1057  QgsMapLayer::StyleCategories sourceCategories = QgsXmlUtils::readFlagAttribute( myRoot, QStringLiteral( "styleCategories" ), QgsMapLayer::AllStyleCategories );
1058 
1059  //Test for matching geometry type on vector layers when applying, if geometry type is given in the style
1060  if ( ( sourceCategories.testFlag( QgsMapLayer::Symbology ) || sourceCategories.testFlag( QgsMapLayer::Symbology3D ) ) &&
1061  ( categories.testFlag( QgsMapLayer::Symbology ) || categories.testFlag( QgsMapLayer::Symbology3D ) ) )
1062  {
1063  if ( type() == QgsMapLayer::VectorLayer && !myRoot.firstChildElement( QStringLiteral( "layerGeometryType" ) ).isNull() )
1064  {
1065  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( this );
1066  QgsWkbTypes::GeometryType importLayerGeometryType = static_cast<QgsWkbTypes::GeometryType>( myRoot.firstChildElement( QStringLiteral( "layerGeometryType" ) ).text().toInt() );
1067  if ( vl->geometryType() != importLayerGeometryType )
1068  {
1069  myErrorMessage = tr( "Cannot apply style with symbology to layer with a different geometry type" );
1070  return false;
1071  }
1072  }
1073  }
1074 
1076  return readSymbology( myRoot, myErrorMessage, context, categories ); // TODO: support relative paths in QML?
1077 }
1078 
1079 void QgsMapLayer::exportNamedMetadata( QDomDocument &doc, QString &errorMsg ) const
1080 {
1081  QDomImplementation DomImplementation;
1082  QDomDocumentType documentType = DomImplementation.createDocumentType( QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
1083  QDomDocument myDocument( documentType );
1084 
1085  QDomElement myRootNode = myDocument.createElement( QStringLiteral( "qgis" ) );
1086  myRootNode.setAttribute( QStringLiteral( "version" ), Qgis::QGIS_VERSION );
1087  myDocument.appendChild( myRootNode );
1088 
1089  if ( !mMetadata.writeMetadataXml( myRootNode, myDocument ) )
1090  {
1091  errorMsg = QObject::tr( "Could not save metadata" );
1092  return;
1093  }
1094 
1095  doc = myDocument;
1096 }
1097 
1098 void QgsMapLayer::exportNamedStyle( QDomDocument &doc, QString &errorMsg, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1099 {
1100  QDomImplementation DomImplementation;
1101  QDomDocumentType documentType = DomImplementation.createDocumentType( QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
1102  QDomDocument myDocument( documentType );
1103 
1104  QDomElement myRootNode = myDocument.createElement( QStringLiteral( "qgis" ) );
1105  myRootNode.setAttribute( QStringLiteral( "version" ), Qgis::QGIS_VERSION );
1106  myDocument.appendChild( myRootNode );
1107 
1108  if ( !writeSymbology( myRootNode, myDocument, errorMsg, context, categories ) ) // TODO: support relative paths in QML?
1109  {
1110  errorMsg = QObject::tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1111  return;
1112  }
1113 
1114  /*
1115  * Check to see if the layer is vector - in which case we should also export its geometryType
1116  * to avoid eventually pasting to a layer with a different geometry
1117  */
1118  if ( type() == QgsMapLayer::VectorLayer )
1119  {
1120  //Getting the selectionLayer geometry
1121  const QgsVectorLayer *vl = qobject_cast<const QgsVectorLayer *>( this );
1122  QString geoType = QString::number( vl->geometryType() );
1123 
1124  //Adding geometryinformation
1125  QDomElement layerGeometryType = myDocument.createElement( QStringLiteral( "layerGeometryType" ) );
1126  QDomText type = myDocument.createTextNode( geoType );
1127 
1128  layerGeometryType.appendChild( type );
1129  myRootNode.appendChild( layerGeometryType );
1130  }
1131 
1132  doc = myDocument;
1133 }
1134 
1135 QString QgsMapLayer::saveDefaultStyle( bool &resultFlag )
1136 {
1137  return saveNamedStyle( styleURI(), resultFlag );
1138 }
1139 
1140 QString QgsMapLayer::saveNamedMetadata( const QString &uri, bool &resultFlag )
1141 {
1142  return saveNamedProperty( uri, QgsMapLayer::Metadata, resultFlag );
1143 }
1144 
1145 QString QgsMapLayer::loadNamedMetadata( const QString &uri, bool &resultFlag )
1146 {
1147  return loadNamedProperty( uri, QgsMapLayer::Metadata, resultFlag );
1148 }
1149 
1150 QString QgsMapLayer::saveNamedProperty( const QString &uri, QgsMapLayer::PropertyType type, bool &resultFlag, StyleCategories categories )
1151 {
1152  // check if the uri is a file or ends with .qml/.qmd,
1153  // which indicates that it should become one
1154  // everything else goes to the database
1155  QString filename;
1156 
1157  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this );
1158  if ( vlayer && vlayer->providerType() == QLatin1String( "ogr" ) )
1159  {
1160  QStringList theURIParts = uri.split( '|' );
1161  filename = theURIParts[0];
1162  }
1163  else if ( vlayer && vlayer->providerType() == QLatin1String( "gpx" ) )
1164  {
1165  QStringList theURIParts = uri.split( '?' );
1166  filename = theURIParts[0];
1167  }
1168  else if ( vlayer && vlayer->providerType() == QLatin1String( "delimitedtext" ) )
1169  {
1170  filename = QUrl::fromEncoded( uri.toLatin1() ).toLocalFile();
1171  // toLocalFile() returns an empty string if theURI is a plain Windows-path, e.g. "C:/style.qml"
1172  if ( filename.isEmpty() )
1173  filename = uri;
1174  }
1175  else
1176  {
1177  filename = uri;
1178  }
1179 
1180  QString myErrorMessage;
1181  QDomDocument myDocument;
1182  switch ( type )
1183  {
1184  case Metadata:
1185  exportNamedMetadata( myDocument, myErrorMessage );
1186  break;
1187 
1188  case Style:
1189  QgsReadWriteContext context;
1190  exportNamedStyle( myDocument, myErrorMessage, context, categories );
1191  break;
1192  }
1193 
1194  QFileInfo myFileInfo( filename );
1195  if ( myFileInfo.exists() || filename.endsWith( QgsMapLayer::extensionPropertyType( type ), Qt::CaseInsensitive ) )
1196  {
1197  QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
1198  if ( !myDirInfo.isWritable() )
1199  {
1200  return tr( "The directory containing your dataset needs to be writable!" );
1201  }
1202 
1203  // now construct the file name for our .qml or .qmd file
1204  QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + QgsMapLayer::extensionPropertyType( type );
1205 
1206  QFile myFile( myFileName );
1207  if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
1208  {
1209  QTextStream myFileStream( &myFile );
1210  // save as utf-8 with 2 spaces for indents
1211  myDocument.save( myFileStream, 2 );
1212  myFile.close();
1213  resultFlag = true;
1214  switch ( type )
1215  {
1216  case Metadata:
1217  return tr( "Created default metadata file as %1" ).arg( myFileName );
1218 
1219  case Style:
1220  return tr( "Created default style file as %1" ).arg( myFileName );
1221  }
1222 
1223  }
1224  else
1225  {
1226  resultFlag = false;
1227  switch ( type )
1228  {
1229  case Metadata:
1230  return tr( "ERROR: Failed to created default metadata file as %1. Check file permissions and retry." ).arg( myFileName );
1231 
1232  case Style:
1233  return tr( "ERROR: Failed to created default style file as %1. Check file permissions and retry." ).arg( myFileName );
1234  }
1235  }
1236  }
1237  else
1238  {
1239  QString qml = myDocument.toString();
1240 
1241  // read from database
1242  sqlite3_database_unique_ptr database;
1243  sqlite3_statement_unique_ptr statement;
1244 
1245  int myResult = database.open( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ) );
1246  if ( myResult != SQLITE_OK )
1247  {
1248  return tr( "User database could not be opened." );
1249  }
1250 
1251  QByteArray param0 = uri.toUtf8();
1252  QByteArray param1 = qml.toUtf8();
1253 
1254  QString mySql;
1255  switch ( type )
1256  {
1257  case Metadata:
1258  mySql = QStringLiteral( "create table if not exists tbl_metadata(metadata varchar primary key,qmd varchar)" );
1259  break;
1260 
1261  case Style:
1262  mySql = QStringLiteral( "create table if not exists tbl_styles(style varchar primary key,qml varchar)" );
1263  break;
1264  }
1265 
1266  statement = database.prepare( mySql, myResult );
1267  if ( myResult == SQLITE_OK )
1268  {
1269  if ( sqlite3_step( statement.get() ) != SQLITE_DONE )
1270  {
1271  resultFlag = false;
1272  switch ( type )
1273  {
1274  case Metadata:
1275  return tr( "The metadata table could not be created." );
1276 
1277  case Style:
1278  return tr( "The style table could not be created." );
1279  }
1280  }
1281  }
1282 
1283  switch ( type )
1284  {
1285  case Metadata:
1286  mySql = QStringLiteral( "insert into tbl_metadata(metadata,qmd) values (?,?)" );
1287  break;
1288 
1289  case Style:
1290  mySql = QStringLiteral( "insert into tbl_styles(style,qml) values (?,?)" );
1291  break;
1292  }
1293  statement = database.prepare( mySql, myResult );
1294  if ( myResult == SQLITE_OK )
1295  {
1296  if ( sqlite3_bind_text( statement.get(), 1, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
1297  sqlite3_bind_text( statement.get(), 2, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
1298  sqlite3_step( statement.get() ) == SQLITE_DONE )
1299  {
1300  resultFlag = true;
1301  switch ( type )
1302  {
1303  case Metadata:
1304  myErrorMessage = tr( "The metadata %1 was saved to database" ).arg( uri );
1305  break;
1306 
1307  case Style:
1308  myErrorMessage = tr( "The style %1 was saved to database" ).arg( uri );
1309  break;
1310  }
1311  }
1312  }
1313 
1314  if ( !resultFlag )
1315  {
1316  QString mySql;
1317  switch ( type )
1318  {
1319  case Metadata:
1320  mySql = QStringLiteral( "update tbl_metadata set qmd=? where metadata=?" );
1321  break;
1322 
1323  case Style:
1324  mySql = QStringLiteral( "update tbl_styles set qml=? where style=?" );
1325  break;
1326  }
1327  statement = database.prepare( mySql, myResult );
1328  if ( myResult == SQLITE_OK )
1329  {
1330  if ( sqlite3_bind_text( statement.get(), 2, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
1331  sqlite3_bind_text( statement.get(), 1, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
1332  sqlite3_step( statement.get() ) == SQLITE_DONE )
1333  {
1334  resultFlag = true;
1335  switch ( type )
1336  {
1337  case Metadata:
1338  myErrorMessage = tr( "The metadata %1 was updated in the database." ).arg( uri );
1339  break;
1340 
1341  case Style:
1342  myErrorMessage = tr( "The style %1 was updated in the database." ).arg( uri );
1343  break;
1344  }
1345  }
1346  else
1347  {
1348  resultFlag = false;
1349  switch ( type )
1350  {
1351  case Metadata:
1352  myErrorMessage = tr( "The metadata %1 could not be updated in the database." ).arg( uri );
1353  break;
1354 
1355  case Style:
1356  myErrorMessage = tr( "The style %1 could not be updated in the database." ).arg( uri );
1357  break;
1358  }
1359  }
1360  }
1361  else
1362  {
1363  resultFlag = false;
1364  switch ( type )
1365  {
1366  case Metadata:
1367  myErrorMessage = tr( "The metadata %1 could not be inserted into database." ).arg( uri );
1368  break;
1369 
1370  case Style:
1371  myErrorMessage = tr( "The style %1 could not be inserted into database." ).arg( uri );
1372  break;
1373  }
1374  }
1375  }
1376  }
1377 
1378  return myErrorMessage;
1379 }
1380 
1381 QString QgsMapLayer::saveNamedStyle( const QString &uri, bool &resultFlag, StyleCategories categories )
1382 {
1383  return saveNamedProperty( uri, QgsMapLayer::Style, resultFlag, categories );
1384 }
1385 
1386 void QgsMapLayer::exportSldStyle( QDomDocument &doc, QString &errorMsg ) const
1387 {
1388  QDomDocument myDocument = QDomDocument();
1389 
1390  QDomNode header = myDocument.createProcessingInstruction( QStringLiteral( "xml" ), QStringLiteral( "version=\"1.0\" encoding=\"UTF-8\"" ) );
1391  myDocument.appendChild( header );
1392 
1393  const QgsVectorLayer *vlayer = qobject_cast<const QgsVectorLayer *>( this );
1394  const QgsRasterLayer *rlayer = qobject_cast<const QgsRasterLayer *>( this );
1395  if ( !vlayer && !rlayer )
1396  {
1397  errorMsg = tr( "Could not save symbology because:\n%1" )
1398  .arg( tr( "Only vector and raster layers are supported" ) );
1399  return;
1400  }
1401 
1402  // Create the root element
1403  QDomElement root = myDocument.createElementNS( QStringLiteral( "http://www.opengis.net/sld" ), QStringLiteral( "StyledLayerDescriptor" ) );
1404  QDomElement layerNode;
1405  if ( vlayer )
1406  {
1407  root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.1.0" ) );
1408  root.setAttribute( QStringLiteral( "xsi:schemaLocation" ), QStringLiteral( "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" ) );
1409  root.setAttribute( QStringLiteral( "xmlns:ogc" ), QStringLiteral( "http://www.opengis.net/ogc" ) );
1410  root.setAttribute( QStringLiteral( "xmlns:se" ), QStringLiteral( "http://www.opengis.net/se" ) );
1411  root.setAttribute( QStringLiteral( "xmlns:xlink" ), QStringLiteral( "http://www.w3.org/1999/xlink" ) );
1412  root.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) );
1413  myDocument.appendChild( root );
1414 
1415  // Create the NamedLayer element
1416  layerNode = myDocument.createElement( QStringLiteral( "NamedLayer" ) );
1417  root.appendChild( layerNode );
1418  }
1419 
1420  // note: Only SLD 1.0 version is generated because seems none is using SE1.1.0 at least for rasters
1421  if ( rlayer )
1422  {
1423  // Create the root element
1424  root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0.0" ) );
1425  root.setAttribute( QStringLiteral( "xmlns:gml" ), QStringLiteral( "http://www.opengis.net/gml" ) );
1426  root.setAttribute( QStringLiteral( "xmlns:ogc" ), QStringLiteral( "http://www.opengis.net/ogc" ) );
1427  root.setAttribute( QStringLiteral( "xmlns:sld" ), QStringLiteral( "http://www.opengis.net/sld" ) );
1428  myDocument.appendChild( root );
1429 
1430  // Create the NamedLayer element
1431  layerNode = myDocument.createElement( QStringLiteral( "UserLayer" ) );
1432  root.appendChild( layerNode );
1433  }
1434 
1435  QgsStringMap props;
1436  if ( hasScaleBasedVisibility() )
1437  {
1438  props[ QStringLiteral( "scaleMinDenom" ) ] = QString::number( mMinScale );
1439  props[ QStringLiteral( "scaleMaxDenom" ) ] = QString::number( mMaxScale );
1440  }
1441 
1442  if ( vlayer )
1443  {
1444  if ( !vlayer->writeSld( layerNode, myDocument, errorMsg, props ) )
1445  {
1446  errorMsg = tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1447  return;
1448  }
1449  }
1450 
1451  if ( rlayer )
1452  {
1453  if ( !rlayer->writeSld( layerNode, myDocument, errorMsg, props ) )
1454  {
1455  errorMsg = tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1456  return;
1457  }
1458  }
1459 
1460  doc = myDocument;
1461 }
1462 
1463 QString QgsMapLayer::saveSldStyle( const QString &uri, bool &resultFlag ) const
1464 {
1465  const QgsMapLayer *mlayer = qobject_cast<const QgsMapLayer *>( this );
1466 
1467  QString errorMsg;
1468  QDomDocument myDocument;
1469  mlayer->exportSldStyle( myDocument, errorMsg );
1470  if ( !errorMsg.isNull() )
1471  {
1472  resultFlag = false;
1473  return errorMsg;
1474  }
1475  // check if the uri is a file or ends with .sld,
1476  // which indicates that it should become one
1477  QString filename;
1478  if ( mlayer->dataProvider()->name() == QLatin1String( "ogr" ) )
1479  {
1480  QStringList theURIParts = uri.split( '|' );
1481  filename = theURIParts[0];
1482  }
1483  else if ( mlayer->dataProvider()->name() == QLatin1String( "gpx" ) )
1484  {
1485  QStringList theURIParts = uri.split( '?' );
1486  filename = theURIParts[0];
1487  }
1488  else if ( mlayer->dataProvider()->name() == QLatin1String( "delimitedtext" ) )
1489  {
1490  filename = QUrl::fromEncoded( uri.toLatin1() ).toLocalFile();
1491  // toLocalFile() returns an empty string if theURI is a plain Windows-path, e.g. "C:/style.qml"
1492  if ( filename.isEmpty() )
1493  filename = uri;
1494  }
1495  else
1496  {
1497  filename = uri;
1498  }
1499 
1500  QFileInfo myFileInfo( filename );
1501  if ( myFileInfo.exists() || filename.endsWith( QLatin1String( ".sld" ), Qt::CaseInsensitive ) )
1502  {
1503  QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
1504  if ( !myDirInfo.isWritable() )
1505  {
1506  return tr( "The directory containing your dataset needs to be writable!" );
1507  }
1508 
1509  // now construct the file name for our .sld style file
1510  QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".sld";
1511 
1512  QFile myFile( myFileName );
1513  if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
1514  {
1515  QTextStream myFileStream( &myFile );
1516  // save as utf-8 with 2 spaces for indents
1517  myDocument.save( myFileStream, 2 );
1518  myFile.close();
1519  resultFlag = true;
1520  return tr( "Created default style file as %1" ).arg( myFileName );
1521  }
1522  }
1523 
1524  resultFlag = false;
1525  return tr( "ERROR: Failed to created SLD style file as %1. Check file permissions and retry." ).arg( filename );
1526 }
1527 
1528 QString QgsMapLayer::loadSldStyle( const QString &uri, bool &resultFlag )
1529 {
1530  resultFlag = false;
1531 
1532  QDomDocument myDocument;
1533 
1534  // location of problem associated with errorMsg
1535  int line, column;
1536  QString myErrorMessage;
1537 
1538  QFile myFile( uri );
1539  if ( myFile.open( QFile::ReadOnly ) )
1540  {
1541  // read file
1542  resultFlag = myDocument.setContent( &myFile, true, &myErrorMessage, &line, &column );
1543  if ( !resultFlag )
1544  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1545  myFile.close();
1546  }
1547  else
1548  {
1549  myErrorMessage = tr( "Unable to open file %1" ).arg( uri );
1550  }
1551 
1552  if ( !resultFlag )
1553  {
1554  return myErrorMessage;
1555  }
1556 
1557  // check for root SLD element
1558  QDomElement myRoot = myDocument.firstChildElement( QStringLiteral( "StyledLayerDescriptor" ) );
1559  if ( myRoot.isNull() )
1560  {
1561  myErrorMessage = QStringLiteral( "Error: StyledLayerDescriptor element not found in %1" ).arg( uri );
1562  resultFlag = false;
1563  return myErrorMessage;
1564  }
1565 
1566  // now get the style node out and pass it over to the layer
1567  // to deserialise...
1568  QDomElement namedLayerElem = myRoot.firstChildElement( QStringLiteral( "NamedLayer" ) );
1569  if ( namedLayerElem.isNull() )
1570  {
1571  myErrorMessage = QStringLiteral( "Info: NamedLayer element not found." );
1572  resultFlag = false;
1573  return myErrorMessage;
1574  }
1575 
1576  QString errorMsg;
1577  resultFlag = readSld( namedLayerElem, errorMsg );
1578  if ( !resultFlag )
1579  {
1580  myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( uri, errorMsg );
1581  return myErrorMessage;
1582  }
1583 
1584  return QString();
1585 }
1586 
1587 bool QgsMapLayer::readStyle( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
1588 {
1589  Q_UNUSED( node );
1590  Q_UNUSED( errorMessage );
1591  Q_UNUSED( context );
1592  Q_UNUSED( categories );
1593  return false;
1594 }
1595 
1596 bool QgsMapLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage,
1597  const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
1598 {
1599  Q_UNUSED( node );
1600  Q_UNUSED( doc );
1601  Q_UNUSED( errorMessage );
1602  Q_UNUSED( context );
1603  Q_UNUSED( categories );
1604  return false;
1605 }
1606 
1607 void QgsMapLayer::readCommonStyle( const QDomElement &layerElement, const QgsReadWriteContext &context,
1608  QgsMapLayer::StyleCategories categories )
1609 {
1610  if ( categories.testFlag( Symbology3D ) )
1611  {
1612  QgsAbstract3DRenderer *r3D = nullptr;
1613  QDomElement renderer3DElem = layerElement.firstChildElement( QStringLiteral( "renderer-3d" ) );
1614  if ( !renderer3DElem.isNull() )
1615  {
1616  QString type3D = renderer3DElem.attribute( QStringLiteral( "type" ) );
1618  if ( meta3D )
1619  {
1620  r3D = meta3D->createRenderer( renderer3DElem, context );
1621  }
1622  }
1623  setRenderer3D( r3D );
1624  }
1625 
1626  if ( categories.testFlag( CustomProperties ) )
1627  {
1628  // read custom properties before passing reading further to a subclass, so that
1629  // the subclass can also read custom properties
1630  readCustomProperties( layerElement );
1631  }
1632 
1633  // use scale dependent visibility flag
1634  if ( categories.testFlag( Rendering ) )
1635  {
1636  setScaleBasedVisibility( layerElement.attribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ) ).toInt() == 1 );
1637  if ( layerElement.hasAttribute( QStringLiteral( "minimumScale" ) ) )
1638  {
1639  // older element, when scales were reversed
1640  setMaximumScale( layerElement.attribute( QStringLiteral( "minimumScale" ) ).toDouble() );
1641  setMinimumScale( layerElement.attribute( QStringLiteral( "maximumScale" ) ).toDouble() );
1642  }
1643  else
1644  {
1645  setMaximumScale( layerElement.attribute( QStringLiteral( "maxScale" ) ).toDouble() );
1646  setMinimumScale( layerElement.attribute( QStringLiteral( "minScale" ) ).toDouble() );
1647  }
1648  }
1649 
1650  if ( categories.testFlag( LayerConfiguration ) )
1651  {
1652  // flags
1653  QDomElement flagsElem = layerElement.firstChildElement( QStringLiteral( "flags" ) );
1654  LayerFlags flags = mFlags;
1655  auto enumMap = qgsEnumMap<QgsMapLayer::LayerFlag>();
1656  for ( auto it = enumMap.constBegin(); it != enumMap.constEnd(); ++it )
1657  {
1658  QDomNode flagNode = flagsElem.namedItem( it.value() );
1659  if ( flagNode.isNull() )
1660  continue;
1661  bool flagValue = flagNode.toElement().text() == "1" ? true : false;
1662  if ( flags.testFlag( it.key() ) && !flagValue )
1663  flags &= ~it.key();
1664  else if ( !flags.testFlag( it.key() ) && flagValue )
1665  flags |= it.key();
1666  }
1667  setFlags( flags );
1668  }
1669 }
1670 
1672 {
1673  return mUndoStack;
1674 }
1675 
1677 {
1678  return mUndoStackStyles;
1679 }
1680 
1682 {
1683  return mCustomProperties.keys();
1684 }
1685 
1686 void QgsMapLayer::setCustomProperty( const QString &key, const QVariant &value )
1687 {
1688  mCustomProperties.setValue( key, value );
1689 }
1690 
1692 {
1693  mCustomProperties = properties;
1694 }
1695 
1696 QVariant QgsMapLayer::customProperty( const QString &value, const QVariant &defaultValue ) const
1697 {
1698  return mCustomProperties.value( value, defaultValue );
1699 }
1700 
1701 void QgsMapLayer::removeCustomProperty( const QString &key )
1702 {
1703  mCustomProperties.remove( key );
1704 }
1705 
1707 {
1708  return mError;
1709 }
1710 
1711 
1712 
1714 {
1715  return false;
1716 }
1717 
1719 {
1720  return true;
1721 }
1722 
1723 void QgsMapLayer::setValid( bool valid )
1724 {
1725  mValid = valid;
1726 }
1727 
1729 {
1730  if ( legend == mLegend )
1731  return;
1732 
1733  delete mLegend;
1734  mLegend = legend;
1735 
1736  if ( mLegend )
1737  {
1738  mLegend->setParent( this );
1739  connect( mLegend, &QgsMapLayerLegend::itemsChanged, this, &QgsMapLayer::legendChanged );
1740  }
1741 
1742  emit legendChanged();
1743 }
1744 
1746 {
1747  return mLegend;
1748 }
1749 
1751 {
1752  return mStyleManager;
1753 }
1754 
1756 {
1757  if ( renderer == m3DRenderer )
1758  return;
1759 
1760  delete m3DRenderer;
1761  m3DRenderer = renderer;
1762  emit renderer3DChanged();
1763 }
1764 
1766 {
1767  return m3DRenderer;
1768 }
1769 
1770 void QgsMapLayer::triggerRepaint( bool deferredUpdate )
1771 {
1772  emit repaintRequested( deferredUpdate );
1773 }
1774 
1776 {
1777  mMetadata = metadata;
1778 // mMetadata.saveToLayer( this );
1779  emit metadataChanged();
1780 }
1781 
1783 {
1784  return QString();
1785 }
1786 
1787 QDateTime QgsMapLayer::timestamp() const
1788 {
1789  return QDateTime();
1790 }
1791 
1793 {
1794  emit styleChanged();
1795 }
1796 
1798 {
1799  mExtent = r;
1800 }
1801 
1802 static QList<const QgsMapLayer *> _depOutEdges( const QgsMapLayer *vl, const QgsMapLayer *that, const QSet<QgsMapLayerDependency> &layers )
1803 {
1804  QList<const QgsMapLayer *> lst;
1805  if ( vl == that )
1806  {
1807  Q_FOREACH ( const QgsMapLayerDependency &dep, layers )
1808  {
1809  if ( const QgsMapLayer *l = QgsProject::instance()->mapLayer( dep.layerId() ) )
1810  lst << l;
1811  }
1812  }
1813  else
1814  {
1815  Q_FOREACH ( const QgsMapLayerDependency &dep, vl->dependencies() )
1816  {
1817  if ( const QgsMapLayer *l = QgsProject::instance()->mapLayer( dep.layerId() ) )
1818  lst << l;
1819  }
1820  }
1821  return lst;
1822 }
1823 
1824 static bool _depHasCycleDFS( const QgsMapLayer *n, QHash<const QgsMapLayer *, int> &mark, const QgsMapLayer *that, const QSet<QgsMapLayerDependency> &layers )
1825 {
1826  if ( mark.value( n ) == 1 ) // temporary
1827  return true;
1828  if ( mark.value( n ) == 0 ) // not visited
1829  {
1830  mark[n] = 1; // temporary
1831  Q_FOREACH ( const QgsMapLayer *m, _depOutEdges( n, that, layers ) )
1832  {
1833  if ( _depHasCycleDFS( m, mark, that, layers ) )
1834  return true;
1835  }
1836  mark[n] = 2; // permanent
1837  }
1838  return false;
1839 }
1840 
1841 bool QgsMapLayer::hasDependencyCycle( const QSet<QgsMapLayerDependency> &layers ) const
1842 {
1843  QHash<const QgsMapLayer *, int> marks;
1844  return _depHasCycleDFS( this, marks, this, layers );
1845 }
1846 
1847 bool QgsMapLayer::isReadOnly() const
1848 {
1849  return true;
1850 }
1851 
1852 QSet<QgsMapLayerDependency> QgsMapLayer::dependencies() const
1853 {
1854  return mDependencies;
1855 }
1856 
1857 bool QgsMapLayer::setDependencies( const QSet<QgsMapLayerDependency> &oDeps )
1858 {
1859  QSet<QgsMapLayerDependency> deps;
1860  Q_FOREACH ( const QgsMapLayerDependency &dep, oDeps )
1861  {
1862  if ( dep.origin() == QgsMapLayerDependency::FromUser )
1863  deps << dep;
1864  }
1865  if ( hasDependencyCycle( deps ) )
1866  return false;
1867 
1868  mDependencies = deps;
1869  emit dependenciesChanged();
1870  return true;
1871 }
1872 
1874 {
1875  if ( !dataProvider() )
1876  return;
1877 
1878  if ( enabled && !isRefreshOnNotifyEnabled() )
1879  {
1880  dataProvider()->setListening( enabled );
1881  connect( dataProvider(), &QgsVectorDataProvider::notify, this, &QgsMapLayer::onNotifiedTriggerRepaint );
1882  }
1883  else if ( !enabled && isRefreshOnNotifyEnabled() )
1884  {
1885  // we don't want to disable provider listening because someone else could need it (e.g. actions)
1886  disconnect( dataProvider(), &QgsVectorDataProvider::notify, this, &QgsMapLayer::onNotifiedTriggerRepaint );
1887  }
1888  mIsRefreshOnNofifyEnabled = enabled;
1889 }
1890 
1891 void QgsMapLayer::onNotifiedTriggerRepaint( const QString &message )
1892 {
1893  if ( refreshOnNotifyMessage().isEmpty() || refreshOnNotifyMessage() == message )
1894  triggerRepaint();
1895 }
1896 
bool hasAutoRefreshEnabled() const
Returns true if auto refresh is enabled for the layer.
QString mShortName
Definition: qgsmaplayer.h:1367
virtual QStringList subLayers() const
Returns the sublayers of this layer.
virtual bool isEditable() const
Returns true if the layer can be edited.
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...
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
QgsMapLayer::LayerType type() const
Returns the type of the layer.
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()
QString shortName() const
Returns the short name of the layer used by QGIS Server to identify the layer.
Definition: qgsmaplayer.h:257
bool isValid() const
Returns the status of the layer.
virtual QString saveSldStyle(const QString &uri, bool &resultFlag) const
Saves the properties of this layer to an SLD format file.
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...
QString name() const
Returns the display name of the layer.
QString publicSource() const
Gets a version of the internal layer definition that has sensitive bits removed (for example...
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.
bool isRefreshOnNotifyEnabled() const
Returns true if the refresh on provider nofification is enabled.
Definition: qgsmaplayer.h:1078
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...
MAYBE_UNUSED NODISCARD QgsReadWriteContextCategoryPopper enterCategory(const QString &category, const QString &details=QString())
Push a category to the stack.
QString refreshOnNotifyMessage() const
Returns the message that should be notified by the provider to triggerRepaint.
Definition: qgsmaplayer.h:1071
bool writeXml(QDomNode &node, QDomDocument &doc) const
Stores state to the given Dom node in the given document.
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
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
void validate()
Perform some validation on this CRS.
Qgs3DRendererAbstractMetadata * rendererMetadata(const QString &type) const
Returns metadata for a 3D renderer type (may be used to create a new instance of the type) ...
double maximumScale() const
Returns the maximum map scale (i.e.
QgsMapLayerStyleManager * styleManager() const
Gets access to the layer&#39;s style manager.
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 writeCommonStyle(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const
Write style data common to all layer types.
void readCustomProperties(const QDomNode &layerNode, const QString &keyStartsWith=QString())
Read custom properties from project file.
bool writeLayerXml(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context) const
Stores state in DOM node.
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...
QString title() const
Returns the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:272
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.
void configChanged()
Emitted whenever the configuration is changed.
int autoRefreshInterval() const
Returns the auto refresh interval (in milliseconds).
bool readLayerXml(const QDomElement &layerElement, QgsReadWriteContext &context)
Sets state from DOM document.
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
QString source() const
Returns the source for the layer.
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)
Returns the components (e.g.
Abstract base class for spatial data provider implementations.
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.
sqlite3_statement_unique_ptr prepare(const QString &sql, int &resultCode) const
Prepares a sql statement, returning the result.
QString dataUrl() const
Returns the DataUrl of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:324
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...
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
QMap< QString, QString > QgsStringMap
Definition: qgis.h:577
void remove(const QString &key)
Remove a key (entry) from the store.
QString mLayerName
Name of the layer - used for display.
Definition: qgsmaplayer.h:1365
virtual QString name() const =0
Returns a provider name.
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.
QgsMapLayer(QgsMapLayer::LayerType type=VectorLayer, const QString &name=QString(), const QString &source=QString())
Constructor for QgsMapLayer.
Definition: qgsmaplayer.cpp:70
QStringList customPropertyKeys() const
Returns list of all keys within custom properties.
void setMaximumScale(double scale)
Sets the maximum map scale (i.e.
QgsError mError
Error.
Definition: qgsmaplayer.h:1392
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...
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.
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
void setValidationHint(const QString &html)
Set user hint for validation.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
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.
bool readMetadataXml(const QDomElement &metadataElement) override
Sets state from DOM document.
bool hasScaleBasedVisibility() const
Returns whether scale based visibility is enabled for the layer.
static QString capitalize(const QString &string, Capitalization capitalization)
Converts a string by applying capitalization rules to the string.
bool isInScaleRange(double scale) const
Tests whether the layer should be visible at the specified scale.
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...
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 QgsRectangle extent() const
Returns the extent of the layer.
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...
const QgsProjectTranslator * projectTranslator() const
Returns the project translator.
void writeStyleManager(QDomNode &layerNode, QDomDocument &doc) const
Write style manager&#39;s configuration (if exists). To be called by subclasses.
void nameChanged()
Emitted when the name has been changed.
A class to describe the version of a project.
virtual void exportSldStyle(QDomDocument &doc, QString &errorMsg) const
Export the properties of this layer as SLD style in a QDomDocument.
virtual void setExtent(const QgsRectangle &rect)
Sets the extent.
void readXml(const QDomElement &mgrElement)
Read configuration (for project loading)
QStringList keys() const
Returns list of stored keys.
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 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 id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
Reads and writes project states.
Definition: qgsproject.h:89
QString attributionUrl() const
Returns the attribution URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:380
void writeCustomProperties(QDomNode &layerNode, QDomDocument &doc) const
Write custom properties to project file.
QString dataUrlFormat() const
Returns the DataUrl format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:342
virtual QDateTime timestamp() const
Time stamp of data source in the moment when data/metadata were loaded by provider.
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...
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
QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
QString layerId() const
Returns the ID of the layer this dependency depends on.
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...
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
Origin origin() const
Returns the dependency origin.
int open(const QString &path)
Opens the database at the specified file path.
QString mTitle
Definition: qgsmaplayer.h:1368
virtual bool readSld(const QDomNode &node, QString &errorMessage)
Definition: qgsmaplayer.h:832
double minimumScale() const
Returns the minimum map scale (i.e.
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
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...
static QString pkgDataPath()
Returns the common root path of all application data directories.
QgsAbstract3DRenderer * renderer3D() const
Returns 3D renderer associated with the layer.
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 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.
virtual const QgsLayerMetadata & metadata() const
Returns a reference to the layer&#39;s metadata store.
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.
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.
QString metadataUrl() const
Returns the metadata URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:400
QgsMapLayerLegend * legend() const
Can be null.
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.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
QString providerType() const
Returns the provider type for this layer.
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
QString legendUrlFormat() const
Returns the format for a URL based layer legend.
Definition: qgsmaplayer.h:916
void itemsChanged()
Emitted when existing items/nodes got invalid and should be replaced by new ones. ...
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...
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.
bool hasDependencyCycle(const QSet< QgsMapLayerDependency > &layers) const
Checks whether a new set of dependencies will introduce a cycle.
QString mDataSource
Data source description string, varies by layer type.
Definition: qgsmaplayer.h:1362
virtual QgsError error() const
Gets current status error.
void writeXml(QDomNode &parentNode, QDomDocument &doc) const
Write store contents to XML.
QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
QString legendUrl() const
Returns the URL for the layer&#39;s legend.
Definition: qgsmaplayer.h:906
QgsMapLayer::LayerFlags flags() const
Returns the flags for this 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
virtual QSet< QgsMapLayerDependency > dependencies() const
Gets the list of dependencies.
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).
void legendChanged()
Signal emitted when legend of the layer has changed.
QString metadataUrlType() const
Returns the metadata type of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:418
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...
Simple key-value store (keys = strings, values = variants) that supports loading/saving to/from XML i...
virtual QString htmlMetadata() const
Obtain a formatted HTML string containing assorted metadata for this layer.
void setAutoRefreshInterval(int interval)
Sets the auto refresh interval (in milliseconds) for the layer.
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
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...
void setAutoRefreshEnabled(bool enabled)
Sets whether auto refresh is enabled for the layer.
virtual void exportNamedStyle(QDomDocument &doc, QString &errorMsg, const QgsReadWriteContext &context=QgsReadWriteContext(), QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) const
Export the properties of this layer as named style in a QDomDocument.
QUndoStack * undoStackStyles()
Returns pointer to layer&#39;s style undo stack.
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
bool addStyle(const QString &name, const QgsMapLayerStyle &style)
Add a style with given name and data.
QgsCoordinateReferenceSystem crs() const
Returns the layer&#39;s spatial reference system.
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 keywordList() const
Returns the keyword list of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:304
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 ...
Base metadata class for 3D renderers.
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.
void exportNamedMetadata(QDomDocument &doc, QString &errorMsg) const
Export the current metadata of this layer as named metadata in a QDomDocument.
void setLegend(QgsMapLayerLegend *legend)
Assign a legend controller to the map layer.
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.
Represents a vector layer which manages a vector based data sets.
QString attribution() const
Returns the attribution of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:362
virtual void setLayerOrder(const QStringList &layers)
Reorders the previously selected sublayers of this layer from bottom to top.
virtual bool isSpatial() const
Returns true if the layer is considered a spatial layer, ie it has some form of geometry associated w...
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
QString metadataUrlFormat() const
Returns the metadata format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:436
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
void setFlags(QgsMapLayer::LayerFlags flags)
Returns the flags for this layer.
void flagsChanged()
Emitted when layer&#39;s flags have been modified.
void readCommonStyle(const QDomElement &layerElement, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories)
Read style data common to all layer types.
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.
void writeXml(QDomElement &mgrElement) const
Write configuration (for project saving)
virtual bool setDependencies(const QSet< QgsMapLayerDependency > &layers)
Sets the list of dependencies.