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