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