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