QGIS API Documentation  2.99.0-Master (dcec6bb)
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 "qgsapplication.h"
33 #include "qgsdatasourceuri.h"
34 #include "qgslogger.h"
35 #include "qgsauthmanager.h"
36 #include "qgsmaplayer.h"
37 #include "qgsmaplayerlegend.h"
39 #include "qgspathresolver.h"
41 #include "qgsproject.h"
42 #include "qgsproviderregistry.h"
43 #include "qgsrasterlayer.h"
44 #include "qgsreadwritecontext.h"
45 #include "qgsrectangle.h"
46 #include "qgsvectorlayer.h"
47 #include "qgsvectordataprovider.h"
48 #include "qgsxmlutils.h"
49 #include "qgssettings.h" // TODO: get rid of it [MD]
50 
51 
53  const QString &lyrname,
54  const QString &source )
55  : mValid( false ) // assume the layer is invalid
56  , mDataSource( source )
57  , mLayerOrigName( lyrname ) // store the original name
58  , mLayerType( type )
59  , mBlendMode( QPainter::CompositionMode_SourceOver ) // Default to normal blending
60  , mLegend( nullptr )
61  , mStyleManager( new QgsMapLayerStyleManager( this ) )
62 {
63  // Set the display name = internal name
65 
66  //mShortName.replace( QRegExp( "[\\W]" ), "_" );
67 
68  // Generate the unique ID of this layer
69  QString uuid = QUuid::createUuid().toString();
70  // trim { } from uuid
71  mID = lyrname + '_' + uuid.mid( 1, uuid.length() - 2 );
72 
73  // Tidy the ID up to avoid characters that may cause problems
74  // elsewhere (e.g in some parts of XML). Replaces every non-word
75  // character (word characters are the alphabet, numbers and
76  // underscore) with an underscore.
77  // Note that the first backslashe in the regular expression is
78  // there for the compiler, so the pattern is actually \W
79  mID.replace( QRegExp( "[\\W]" ), QStringLiteral( "_" ) );
80 
81  //set some generous defaults for scale based visibility
82  mMinScale = 0;
83  mMaxScale = 100000000;
84  mScaleBasedVisibility = false;
85 
87  connect( &mRefreshTimer, &QTimer::timeout, this, [ = ] { triggerRepaint( true ); } );
88 }
89 
91 {
92  delete mLegend;
93  delete mStyleManager;
94 }
95 
96 void QgsMapLayer::clone( QgsMapLayer *layer ) const
97 {
98  layer->setBlendMode( blendMode() );
99 
100  Q_FOREACH ( const QString &s, styleManager()->styles() )
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() );
124  layer->setCrs( crs() );
125  layer->setCustomProperties( mCustomProperties );
126 }
127 
129 {
130  return mLayerType;
131 }
132 
133 QString QgsMapLayer::id() const
134 {
135  return mID;
136 }
137 
138 void QgsMapLayer::setName( const QString &name )
139 {
140  QString newName = capitalizeLayerName( name );
141  if ( name == mLayerOrigName && newName == mLayerName )
142  return;
143 
144  mLayerOrigName = name; // store the new original name
145  mLayerName = newName;
146 
147  emit nameChanged();
148 }
149 
150 QString QgsMapLayer::name() const
151 {
152  QgsDebugMsgLevel( "returning name '" + mLayerName + '\'', 4 );
153  return mLayerName;
154 }
155 
157 {
158  return nullptr;
159 }
160 
162 {
163  return nullptr;
164 }
165 
167 {
168  return mLayerOrigName;
169 }
170 
172 {
173  // Redo this every time we're asked for it, as we don't know if
174  // dataSource has changed.
175  QString safeName = QgsDataSourceUri::removePassword( mDataSource );
176  return safeName;
177 }
178 
179 QString QgsMapLayer::source() const
180 {
181  return mDataSource;
182 }
183 
185 {
186  return mExtent;
187 }
188 
189 void QgsMapLayer::setBlendMode( QPainter::CompositionMode blendMode )
190 {
191  mBlendMode = blendMode;
192  emit blendModeChanged( blendMode );
193  emit styleChanged();
194 }
195 
196 QPainter::CompositionMode QgsMapLayer::blendMode() const
197 {
198  return mBlendMode;
199 }
200 
201 
202 bool QgsMapLayer::readLayerXml( const QDomElement &layerElement, const QgsReadWriteContext &context )
203 {
204  bool layerError;
205 
206  QDomNode mnl;
207  QDomElement mne;
208 
209  // read provider
210  QString provider;
211  mnl = layerElement.namedItem( QStringLiteral( "provider" ) );
212  mne = mnl.toElement();
213  provider = mne.text();
214 
215  // set data source
216  mnl = layerElement.namedItem( QStringLiteral( "datasource" ) );
217  mne = mnl.toElement();
218  mDataSource = mne.text();
219 
220  // if the layer needs authentication, ensure the master password is set
221  QRegExp rx( "authcfg=([a-z]|[A-Z]|[0-9]){7}" );
222  if ( ( rx.indexIn( mDataSource ) != -1 )
224  {
225  return false;
226  }
227 
228  // TODO: this should go to providers
229  if ( provider == QLatin1String( "spatialite" ) )
230  {
232  uri.setDatabase( context.pathResolver().readPath( uri.database() ) );
233  mDataSource = uri.uri();
234  }
235  else if ( provider == QLatin1String( "ogr" ) )
236  {
237  QStringList theURIParts = mDataSource.split( '|' );
238  theURIParts[0] = context.pathResolver().readPath( theURIParts[0] );
239  mDataSource = theURIParts.join( QStringLiteral( "|" ) );
240  }
241  else if ( provider == QLatin1String( "gpx" ) )
242  {
243  QStringList theURIParts = mDataSource.split( '?' );
244  theURIParts[0] = context.pathResolver().readPath( theURIParts[0] );
245  mDataSource = theURIParts.join( QStringLiteral( "?" ) );
246  }
247  else if ( provider == QLatin1String( "delimitedtext" ) )
248  {
249  QUrl urlSource = QUrl::fromEncoded( mDataSource.toLatin1() );
250 
251  if ( !mDataSource.startsWith( QLatin1String( "file:" ) ) )
252  {
253  QUrl file = QUrl::fromLocalFile( mDataSource.left( mDataSource.indexOf( '?' ) ) );
254  urlSource.setScheme( QStringLiteral( "file" ) );
255  urlSource.setPath( file.path() );
256  }
257 
258  QUrl urlDest = QUrl::fromLocalFile( context.pathResolver().readPath( urlSource.toLocalFile() ) );
259  urlDest.setQueryItems( urlSource.queryItems() );
260  mDataSource = QString::fromAscii( urlDest.toEncoded() );
261  }
262  else if ( provider == QLatin1String( "wms" ) )
263  {
264  // >>> BACKWARD COMPATIBILITY < 1.9
265  // For project file backward compatibility we must support old format:
266  // 1. mode: <url>
267  // example: http://example.org/wms?
268  // 2. mode: tiled=<width>;<height>;<resolution>;<resolution>...,ignoreUrl=GetMap;GetFeatureInfo,featureCount=<count>,username=<name>,password=<password>,url=<url>
269  // example: tiled=256;256;0.703;0.351,url=http://example.org/tilecache?
270  // example: featureCount=10,http://example.org/wms?
271  // example: ignoreUrl=GetMap;GetFeatureInfo,username=cimrman,password=jara,url=http://example.org/wms?
272  // This is modified version of old QgsWmsProvider::parseUri
273  // The new format has always params crs,format,layers,styles and that params
274  // should not appear in old format url -> use them to identify version
275  // XYZ tile layers do not need to contain crs,format params, but they have type=xyz
276  if ( !mDataSource.contains( QLatin1String( "type=" ) ) &&
277  !mDataSource.contains( QLatin1String( "crs=" ) ) && !mDataSource.contains( QLatin1String( "format=" ) ) )
278  {
279  QgsDebugMsg( "Old WMS URI format detected -> converting to new format" );
280  QgsDataSourceUri uri;
281  if ( !mDataSource.startsWith( QLatin1String( "http:" ) ) )
282  {
283  QStringList parts = mDataSource.split( ',' );
284  QStringListIterator iter( parts );
285  while ( iter.hasNext() )
286  {
287  QString item = iter.next();
288  if ( item.startsWith( QLatin1String( "username=" ) ) )
289  {
290  uri.setParam( QStringLiteral( "username" ), item.mid( 9 ) );
291  }
292  else if ( item.startsWith( QLatin1String( "password=" ) ) )
293  {
294  uri.setParam( QStringLiteral( "password" ), item.mid( 9 ) );
295  }
296  else if ( item.startsWith( QLatin1String( "tiled=" ) ) )
297  {
298  // in < 1.9 tiled= may apper in to variants:
299  // tiled=width;height - non tiled mode, specifies max width and max height
300  // tiled=width;height;resolutions-1;resolution2;... - tile mode
301 
302  QStringList params = item.mid( 6 ).split( ';' );
303 
304  if ( params.size() == 2 ) // non tiled mode
305  {
306  uri.setParam( QStringLiteral( "maxWidth" ), params.takeFirst() );
307  uri.setParam( QStringLiteral( "maxHeight" ), params.takeFirst() );
308  }
309  else if ( params.size() > 2 ) // tiled mode
310  {
311  // resolutions are no more needed and size limit is not used for tiles
312  // we have to tell to the provider however that it is tiled
313  uri.setParam( QStringLiteral( "tileMatrixSet" ), QLatin1String( "" ) );
314  }
315  }
316  else if ( item.startsWith( QLatin1String( "featureCount=" ) ) )
317  {
318  uri.setParam( QStringLiteral( "featureCount" ), item.mid( 13 ) );
319  }
320  else if ( item.startsWith( QLatin1String( "url=" ) ) )
321  {
322  uri.setParam( QStringLiteral( "url" ), item.mid( 4 ) );
323  }
324  else if ( item.startsWith( QLatin1String( "ignoreUrl=" ) ) )
325  {
326  uri.setParam( QStringLiteral( "ignoreUrl" ), item.mid( 10 ).split( ';' ) );
327  }
328  }
329  }
330  else
331  {
332  uri.setParam( QStringLiteral( "url" ), mDataSource );
333  }
334  mDataSource = uri.encodedUri();
335  // At this point, the URI is obviously incomplete, we add additional params
336  // in QgsRasterLayer::readXml
337  }
338  // <<< BACKWARD COMPATIBILITY < 1.9
339  }
340  else
341  {
342  bool handled = false;
343 
344  if ( provider == QLatin1String( "gdal" ) )
345  {
346  if ( mDataSource.startsWith( QLatin1String( "NETCDF:" ) ) )
347  {
348  // NETCDF:filename:variable
349  // filename can be quoted with " as it can contain colons
350  QRegExp r( "NETCDF:(.+):([^:]+)" );
351  if ( r.exactMatch( mDataSource ) )
352  {
353  QString filename = r.cap( 1 );
354  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
355  filename = filename.mid( 1, filename.length() - 2 );
356  mDataSource = "NETCDF:\"" + context.pathResolver().readPath( filename ) + "\":" + r.cap( 2 );
357  handled = true;
358  }
359  }
360  else if ( mDataSource.startsWith( QLatin1String( "HDF4_SDS:" ) ) )
361  {
362  // HDF4_SDS:subdataset_type:file_name:subdataset_index
363  // filename can be quoted with " as it can contain colons
364  QRegExp r( "HDF4_SDS:([^:]+):(.+):([^:]+)" );
365  if ( r.exactMatch( mDataSource ) )
366  {
367  QString filename = r.cap( 2 );
368  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
369  filename = filename.mid( 1, filename.length() - 2 );
370  mDataSource = "HDF4_SDS:" + r.cap( 1 ) + ":\"" + context.pathResolver().readPath( filename ) + "\":" + r.cap( 3 );
371  handled = true;
372  }
373  }
374  else if ( mDataSource.startsWith( QLatin1String( "HDF5:" ) ) )
375  {
376  // HDF5:file_name:subdataset
377  // filename can be quoted with " as it can contain colons
378  QRegExp r( "HDF5:(.+):([^:]+)" );
379  if ( r.exactMatch( mDataSource ) )
380  {
381  QString filename = r.cap( 1 );
382  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
383  filename = filename.mid( 1, filename.length() - 2 );
384  mDataSource = "HDF5:\"" + context.pathResolver().readPath( filename ) + "\":" + r.cap( 2 );
385  handled = true;
386  }
387  }
388  else if ( mDataSource.contains( QRegExp( "^(NITF_IM|RADARSAT_2_CALIB):" ) ) )
389  {
390  // NITF_IM:0:filename
391  // RADARSAT_2_CALIB:?:filename
392  QRegExp r( "([^:]+):([^:]+):(.+)" );
393  if ( r.exactMatch( mDataSource ) )
394  {
395  mDataSource = r.cap( 1 ) + ':' + r.cap( 2 ) + ':' + context.pathResolver().readPath( r.cap( 3 ) );
396  handled = true;
397  }
398  }
399  }
400 
401  if ( !handled )
403  }
404 
405  // Set the CRS from project file, asking the user if necessary.
406  // Make it the saved CRS to have WMS layer projected correctly.
407  // We will still overwrite whatever GDAL etc picks up anyway
408  // further down this function.
409  mnl = layerElement.namedItem( QStringLiteral( "layername" ) );
410  mne = mnl.toElement();
411 
413  CUSTOM_CRS_VALIDATION savedValidation;
414 
415  QDomNode srsNode = layerElement.namedItem( QStringLiteral( "srs" ) );
416  mCRS.readXml( srsNode );
417  mCRS.setValidationHint( tr( "Specify CRS for layer %1" ).arg( mne.text() ) );
418  mCRS.validate();
419  savedCRS = mCRS;
420 
421  // Do not validate any projections in children, they will be overwritten anyway.
422  // No need to ask the user for a projections when it is overwritten, is there?
425 
426  // read custom properties before passing reading further to a subclass, so that
427  // the subclass can also read custom properties
428  readCustomProperties( layerElement );
429 
430  // now let the children grab what they need from the Dom node.
431  layerError = !readXml( layerElement, context );
432 
433  // overwrite CRS with what we read from project file before the raster/vector
434  // file reading functions changed it. They will if projections is specified in the file.
435  // FIXME: is this necessary?
437  mCRS = savedCRS;
438 
439  // Abort if any error in layer, such as not found.
440  if ( layerError )
441  {
442  return false;
443  }
444 
445  // the internal name is just the data source basename
446  //QFileInfo dataSourceFileInfo( mDataSource );
447  //internalName = dataSourceFileInfo.baseName();
448 
449  // set ID
450  mnl = layerElement.namedItem( QStringLiteral( "id" ) );
451  if ( ! mnl.isNull() )
452  {
453  mne = mnl.toElement();
454  if ( ! mne.isNull() && mne.text().length() > 10 ) // should be at least 17 (yyyyMMddhhmmsszzz)
455  {
456  mID = mne.text();
457  }
458  }
459 
460  // use scale dependent visibility flag
461  setScaleBasedVisibility( layerElement.attribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ) ).toInt() == 1 );
462  if ( layerElement.hasAttribute( QStringLiteral( "minimumScale" ) ) )
463  {
464  // older element, when scales were reversed
465  setMaximumScale( layerElement.attribute( QStringLiteral( "minimumScale" ) ).toDouble() );
466  setMinimumScale( layerElement.attribute( QStringLiteral( "maximumScale" ) ).toDouble() );
467  }
468  else
469  {
470  setMaximumScale( layerElement.attribute( QStringLiteral( "maxScale" ) ).toDouble() );
471  setMinimumScale( layerElement.attribute( QStringLiteral( "minScale" ) ).toDouble() );
472  }
473 
474  setAutoRefreshInterval( layerElement.attribute( QStringLiteral( "autoRefreshTime" ), 0 ).toInt() );
475  setAutoRefreshEnabled( layerElement.attribute( QStringLiteral( "autoRefreshEnabled" ), QStringLiteral( "0" ) ).toInt() );
476 
477  QDomNode extentNode = layerElement.namedItem( QStringLiteral( "extent" ) );
478  if ( !extentNode.isNull() )
479  {
480  setExtent( QgsXmlUtils::readRectangle( extentNode.toElement() ) );
481  }
482 
483  // set name
484  mnl = layerElement.namedItem( QStringLiteral( "layername" ) );
485  mne = mnl.toElement();
486  setName( mne.text() );
487 
488  //short name
489  QDomElement shortNameElem = layerElement.firstChildElement( QStringLiteral( "shortname" ) );
490  if ( !shortNameElem.isNull() )
491  {
492  mShortName = shortNameElem.text();
493  }
494 
495  //title
496  QDomElement titleElem = layerElement.firstChildElement( QStringLiteral( "title" ) );
497  if ( !titleElem.isNull() )
498  {
499  mTitle = titleElem.text();
500  }
501 
502  //abstract
503  QDomElement abstractElem = layerElement.firstChildElement( QStringLiteral( "abstract" ) );
504  if ( !abstractElem.isNull() )
505  {
506  mAbstract = abstractElem.text();
507  }
508 
509  //keywordList
510  QDomElement keywordListElem = layerElement.firstChildElement( QStringLiteral( "keywordList" ) );
511  if ( !keywordListElem.isNull() )
512  {
513  QStringList kwdList;
514  for ( QDomNode n = keywordListElem.firstChild(); !n.isNull(); n = n.nextSibling() )
515  {
516  kwdList << n.toElement().text();
517  }
518  mKeywordList = kwdList.join( QStringLiteral( ", " ) );
519  }
520 
521  //metadataUrl
522  QDomElement dataUrlElem = layerElement.firstChildElement( QStringLiteral( "dataUrl" ) );
523  if ( !dataUrlElem.isNull() )
524  {
525  mDataUrl = dataUrlElem.text();
526  mDataUrlFormat = dataUrlElem.attribute( QStringLiteral( "format" ), QLatin1String( "" ) );
527  }
528 
529  //legendUrl
530  QDomElement legendUrlElem = layerElement.firstChildElement( QStringLiteral( "legendUrl" ) );
531  if ( !legendUrlElem.isNull() )
532  {
533  mLegendUrl = legendUrlElem.text();
534  mLegendUrlFormat = legendUrlElem.attribute( QStringLiteral( "format" ), QLatin1String( "" ) );
535  }
536 
537  //attribution
538  QDomElement attribElem = layerElement.firstChildElement( QStringLiteral( "attribution" ) );
539  if ( !attribElem.isNull() )
540  {
541  mAttribution = attribElem.text();
542  mAttributionUrl = attribElem.attribute( QStringLiteral( "href" ), QLatin1String( "" ) );
543  }
544 
545  //metadataUrl
546  QDomElement metaUrlElem = layerElement.firstChildElement( QStringLiteral( "metadataUrl" ) );
547  if ( !metaUrlElem.isNull() )
548  {
549  mMetadataUrl = metaUrlElem.text();
550  mMetadataUrlType = metaUrlElem.attribute( QStringLiteral( "type" ), QLatin1String( "" ) );
551  mMetadataUrlFormat = metaUrlElem.attribute( QStringLiteral( "format" ), QLatin1String( "" ) );
552  }
553 
554  mMetadata.readFromLayer( this );
555 
556  return true;
557 } // bool QgsMapLayer::readLayerXML
558 
559 
560 bool QgsMapLayer::readXml( const QDomNode &layer_node, const QgsReadWriteContext &context )
561 {
562  Q_UNUSED( layer_node );
563  Q_UNUSED( context );
564  // NOP by default; children will over-ride with behavior specific to them
565 
566  return true;
567 } // void QgsMapLayer::readXml
568 
569 
570 
571 bool QgsMapLayer::writeLayerXml( QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context ) const
572 {
573  // use scale dependent visibility flag
574  layerElement.setAttribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ), hasScaleBasedVisibility() ? 1 : 0 );
575  layerElement.setAttribute( QStringLiteral( "maxScale" ), QString::number( maximumScale() ) );
576  layerElement.setAttribute( QStringLiteral( "minScale" ), QString::number( minimumScale() ) );
577 
578  if ( !mExtent.isNull() )
579  {
580  layerElement.appendChild( QgsXmlUtils::writeRectangle( mExtent, document ) );
581  }
582 
583  layerElement.setAttribute( QStringLiteral( "autoRefreshTime" ), QString::number( mRefreshTimer.interval() ) );
584  layerElement.setAttribute( QStringLiteral( "autoRefreshEnabled" ), mRefreshTimer.isActive() ? 1 : 0 );
585 
586  // ID
587  QDomElement layerId = document.createElement( QStringLiteral( "id" ) );
588  QDomText layerIdText = document.createTextNode( id() );
589  layerId.appendChild( layerIdText );
590 
591  layerElement.appendChild( layerId );
592 
593  // data source
594  QDomElement dataSource = document.createElement( QStringLiteral( "datasource" ) );
595 
596  QString src = source();
597 
598  const QgsVectorLayer *vlayer = qobject_cast<const QgsVectorLayer *>( this );
599  // TODO: what about postgres, mysql and others, they should not go through writePath()
600  if ( vlayer && vlayer->providerType() == QLatin1String( "spatialite" ) )
601  {
602  QgsDataSourceUri uri( src );
603  QString database = context.pathResolver().writePath( uri.database() );
604  uri.setConnection( uri.host(), uri.port(), database, uri.username(), uri.password() );
605  src = uri.uri();
606  }
607  else if ( vlayer && vlayer->providerType() == QLatin1String( "ogr" ) )
608  {
609  QStringList theURIParts = src.split( '|' );
610  theURIParts[0] = context.pathResolver().writePath( theURIParts[0] );
611  src = theURIParts.join( QStringLiteral( "|" ) );
612  }
613  else if ( vlayer && vlayer->providerType() == QLatin1String( "gpx" ) )
614  {
615  QStringList theURIParts = src.split( '?' );
616  theURIParts[0] = context.pathResolver().writePath( theURIParts[0] );
617  src = theURIParts.join( QStringLiteral( "?" ) );
618  }
619  else if ( vlayer && vlayer->providerType() == QLatin1String( "delimitedtext" ) )
620  {
621  QUrl urlSource = QUrl::fromEncoded( src.toLatin1() );
622  QUrl urlDest = QUrl::fromLocalFile( context.pathResolver().writePath( urlSource.toLocalFile() ) );
623  urlDest.setQueryItems( urlSource.queryItems() );
624  src = QString::fromAscii( urlDest.toEncoded() );
625  }
626  else if ( vlayer && vlayer->providerType() == QLatin1String( "memory" ) )
627  {
628  // Refetch the source from the provider, because adding fields actually changes the source for this provider.
629  src = vlayer->dataProvider()->dataSourceUri();
630  }
631  else
632  {
633  bool handled = false;
634 
635  if ( !vlayer )
636  {
637  const QgsRasterLayer *rlayer = qobject_cast<const QgsRasterLayer *>( this );
638  // Update path for subdataset
639  if ( rlayer && rlayer->providerType() == QLatin1String( "gdal" ) )
640  {
641  if ( src.startsWith( QLatin1String( "NETCDF:" ) ) )
642  {
643  // NETCDF:filename:variable
644  // filename can be quoted with " as it can contain colons
645  QRegExp r( "NETCDF:(.+):([^:]+)" );
646  if ( r.exactMatch( src ) )
647  {
648  QString filename = r.cap( 1 );
649  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
650  filename = filename.mid( 1, filename.length() - 2 );
651  src = "NETCDF:\"" + context.pathResolver().writePath( filename ) + "\":" + r.cap( 2 );
652  handled = true;
653  }
654  }
655  else if ( src.startsWith( QLatin1String( "HDF4_SDS:" ) ) )
656  {
657  // HDF4_SDS:subdataset_type:file_name:subdataset_index
658  // filename can be quoted with " as it can contain colons
659  QRegExp r( "HDF4_SDS:([^:]+):(.+):([^:]+)" );
660  if ( r.exactMatch( src ) )
661  {
662  QString filename = r.cap( 2 );
663  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
664  filename = filename.mid( 1, filename.length() - 2 );
665  src = "HDF4_SDS:" + r.cap( 1 ) + ":\"" + context.pathResolver().writePath( filename ) + "\":" + r.cap( 3 );
666  handled = true;
667  }
668  }
669  else if ( src.startsWith( QLatin1String( "HDF5:" ) ) )
670  {
671  // HDF5:file_name:subdataset
672  // filename can be quoted with " as it can contain colons
673  QRegExp r( "HDF5:(.+):([^:]+)" );
674  if ( r.exactMatch( src ) )
675  {
676  QString filename = r.cap( 1 );
677  if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
678  filename = filename.mid( 1, filename.length() - 2 );
679  src = "HDF5:\"" + context.pathResolver().writePath( filename ) + "\":" + r.cap( 2 );
680  handled = true;
681  }
682  }
683  else if ( src.contains( QRegExp( "^(NITF_IM|RADARSAT_2_CALIB):" ) ) )
684  {
685  // NITF_IM:0:filename
686  // RADARSAT_2_CALIB:?:filename
687  QRegExp r( "([^:]+):([^:]+):(.+)" );
688  if ( r.exactMatch( src ) )
689  {
690  src = r.cap( 1 ) + ':' + r.cap( 2 ) + ':' + context.pathResolver().writePath( r.cap( 3 ) );
691  handled = true;
692  }
693  }
694  }
695  }
696 
697  if ( !handled )
698  src = context.pathResolver().writePath( src );
699  }
700 
701  QDomText dataSourceText = document.createTextNode( src );
702  dataSource.appendChild( dataSourceText );
703 
704  layerElement.appendChild( dataSource );
705 
706 
707  // layer name
708  QDomElement layerName = document.createElement( QStringLiteral( "layername" ) );
709  QDomText layerNameText = document.createTextNode( originalName() );
710  layerName.appendChild( layerNameText );
711  layerElement.appendChild( layerName );
712 
713  // layer short name
714  if ( !mShortName.isEmpty() )
715  {
716  QDomElement layerShortName = document.createElement( QStringLiteral( "shortname" ) );
717  QDomText layerShortNameText = document.createTextNode( mShortName );
718  layerShortName.appendChild( layerShortNameText );
719  layerElement.appendChild( layerShortName );
720  }
721 
722  // layer title
723  if ( !mTitle.isEmpty() )
724  {
725  QDomElement layerTitle = document.createElement( QStringLiteral( "title" ) );
726  QDomText layerTitleText = document.createTextNode( mTitle );
727  layerTitle.appendChild( layerTitleText );
728  layerElement.appendChild( layerTitle );
729  }
730 
731  // layer abstract
732  if ( !mAbstract.isEmpty() )
733  {
734  QDomElement layerAbstract = document.createElement( QStringLiteral( "abstract" ) );
735  QDomText layerAbstractText = document.createTextNode( mAbstract );
736  layerAbstract.appendChild( layerAbstractText );
737  layerElement.appendChild( layerAbstract );
738  }
739 
740  // layer keyword list
741  QStringList keywordStringList = keywordList().split( ',' );
742  if ( !keywordStringList.isEmpty() )
743  {
744  QDomElement layerKeywordList = document.createElement( QStringLiteral( "keywordList" ) );
745  for ( int i = 0; i < keywordStringList.size(); ++i )
746  {
747  QDomElement layerKeywordValue = document.createElement( QStringLiteral( "value" ) );
748  QDomText layerKeywordText = document.createTextNode( keywordStringList.at( i ).trimmed() );
749  layerKeywordValue.appendChild( layerKeywordText );
750  layerKeywordList.appendChild( layerKeywordValue );
751  }
752  layerElement.appendChild( layerKeywordList );
753  }
754 
755  // layer metadataUrl
756  QString aDataUrl = dataUrl();
757  if ( !aDataUrl.isEmpty() )
758  {
759  QDomElement layerDataUrl = document.createElement( QStringLiteral( "dataUrl" ) );
760  QDomText layerDataUrlText = document.createTextNode( aDataUrl );
761  layerDataUrl.appendChild( layerDataUrlText );
762  layerDataUrl.setAttribute( QStringLiteral( "format" ), dataUrlFormat() );
763  layerElement.appendChild( layerDataUrl );
764  }
765 
766  // layer legendUrl
767  QString aLegendUrl = legendUrl();
768  if ( !aLegendUrl.isEmpty() )
769  {
770  QDomElement layerLegendUrl = document.createElement( QStringLiteral( "legendUrl" ) );
771  QDomText layerLegendUrlText = document.createTextNode( aLegendUrl );
772  layerLegendUrl.appendChild( layerLegendUrlText );
773  layerLegendUrl.setAttribute( QStringLiteral( "format" ), legendUrlFormat() );
774  layerElement.appendChild( layerLegendUrl );
775  }
776 
777  // layer attribution
778  QString aAttribution = attribution();
779  if ( !aAttribution.isEmpty() )
780  {
781  QDomElement layerAttribution = document.createElement( QStringLiteral( "attribution" ) );
782  QDomText layerAttributionText = document.createTextNode( aAttribution );
783  layerAttribution.appendChild( layerAttributionText );
784  layerAttribution.setAttribute( QStringLiteral( "href" ), attributionUrl() );
785  layerElement.appendChild( layerAttribution );
786  }
787 
788  // layer metadataUrl
789  QString aMetadataUrl = metadataUrl();
790  if ( !aMetadataUrl.isEmpty() )
791  {
792  QDomElement layerMetadataUrl = document.createElement( QStringLiteral( "metadataUrl" ) );
793  QDomText layerMetadataUrlText = document.createTextNode( aMetadataUrl );
794  layerMetadataUrl.appendChild( layerMetadataUrlText );
795  layerMetadataUrl.setAttribute( QStringLiteral( "type" ), metadataUrlType() );
796  layerMetadataUrl.setAttribute( QStringLiteral( "format" ), metadataUrlFormat() );
797  layerElement.appendChild( layerMetadataUrl );
798  }
799 
800  // timestamp if supported
801  if ( timestamp() > QDateTime() )
802  {
803  QDomElement stamp = document.createElement( QStringLiteral( "timestamp" ) );
804  QDomText stampText = document.createTextNode( timestamp().toString( Qt::ISODate ) );
805  stamp.appendChild( stampText );
806  layerElement.appendChild( stamp );
807  }
808 
809  layerElement.appendChild( layerName );
810 
811  // zorder
812  // This is no longer stored in the project file. It is superfluous since the layers
813  // are written and read in the proper order.
814 
815  // spatial reference system id
816  QDomElement mySrsElement = document.createElement( QStringLiteral( "srs" ) );
817  mCRS.writeXml( mySrsElement, document );
818  layerElement.appendChild( mySrsElement );
819 
820  // now append layer node to map layer node
821 
822  writeCustomProperties( layerElement, document );
823 
824  return writeXml( layerElement, document, context );
825 
826 }
827 
828 
829 bool QgsMapLayer::writeXml( QDomNode &layer_node, QDomDocument &document, const QgsReadWriteContext &context ) const
830 {
831  Q_UNUSED( layer_node );
832  Q_UNUSED( document );
833  Q_UNUSED( context );
834  // NOP by default; children will over-ride with behavior specific to them
835 
836  return true;
837 } // void QgsMapLayer::writeXml
838 
839 
840 void QgsMapLayer::readCustomProperties( const QDomNode &layerNode, const QString &keyStartsWith )
841 {
842  mCustomProperties.readXml( layerNode, keyStartsWith );
843 }
844 
845 void QgsMapLayer::writeCustomProperties( QDomNode &layerNode, QDomDocument &doc ) const
846 {
847  mCustomProperties.writeXml( layerNode, doc );
848 }
849 
850 void QgsMapLayer::readStyleManager( const QDomNode &layerNode )
851 {
852  QDomElement styleMgrElem = layerNode.firstChildElement( QStringLiteral( "map-layer-style-manager" ) );
853  if ( !styleMgrElem.isNull() )
854  mStyleManager->readXml( styleMgrElem );
855  else
856  mStyleManager->reset();
857 }
858 
859 void QgsMapLayer::writeStyleManager( QDomNode &layerNode, QDomDocument &doc ) const
860 {
861  if ( mStyleManager )
862  {
863  QDomElement styleMgrElem = doc.createElement( QStringLiteral( "map-layer-style-manager" ) );
864  mStyleManager->writeXml( styleMgrElem );
865  layerNode.appendChild( styleMgrElem );
866  }
867 }
868 
870 {
871  return mValid;
872 }
873 
874 #if 0
875 void QgsMapLayer::connectNotify( const char *signal )
876 {
877  Q_UNUSED( signal );
878  QgsDebugMsgLevel( "QgsMapLayer connected to " + QString( signal ), 3 );
879 } // QgsMapLayer::connectNotify
880 #endif
881 
882 bool QgsMapLayer::isInScaleRange( double scale ) const
883 {
884  return !mScaleBasedVisibility ||
885  ( ( mMinScale == 0 || mMinScale * Qgis::SCALE_PRECISION < scale )
886  && ( mMaxScale == 0 || scale < mMaxScale ) );
887 }
888 
890 {
891  return mScaleBasedVisibility;
892 }
893 
895 {
896  return mRefreshTimer.isActive();
897 }
898 
900 {
901  return mRefreshTimer.interval();
902 }
903 
905 {
906  if ( interval <= 0 )
907  {
908  mRefreshTimer.stop();
909  mRefreshTimer.setInterval( 0 );
910  }
911  else
912  {
913  mRefreshTimer.setInterval( interval );
914  }
915  emit autoRefreshIntervalChanged( mRefreshTimer.isActive() ? mRefreshTimer.interval() : 0 );
916 }
917 
919 {
920  if ( !enabled )
921  mRefreshTimer.stop();
922  else if ( mRefreshTimer.interval() > 0 )
923  mRefreshTimer.start();
924 
925  emit autoRefreshIntervalChanged( mRefreshTimer.isActive() ? mRefreshTimer.interval() : 0 );
926 }
927 
929 {
930  return mMetadata;
931 }
932 
933 void QgsMapLayer::setMaximumScale( double scale )
934 {
935  mMinScale = scale;
936 }
937 
939 {
940  return mMinScale;
941 }
942 
943 
944 void QgsMapLayer::setMinimumScale( double scale )
945 {
946  mMaxScale = scale;
947 }
948 
949 void QgsMapLayer::setScaleBasedVisibility( const bool enabled )
950 {
951  mScaleBasedVisibility = enabled;
952 }
953 
955 {
956  return mMaxScale;
957 }
958 
959 QStringList QgsMapLayer::subLayers() const
960 {
961  return QStringList(); // Empty
962 }
963 
964 void QgsMapLayer::setLayerOrder( const QStringList &layers )
965 {
966  Q_UNUSED( layers );
967  // NOOP
968 }
969 
970 void QgsMapLayer::setSubLayerVisibility( const QString &name, bool vis )
971 {
972  Q_UNUSED( name );
973  Q_UNUSED( vis );
974  // NOOP
975 }
976 
978 {
979  return mCRS;
980 }
981 
982 void QgsMapLayer::setCrs( const QgsCoordinateReferenceSystem &srs, bool emitSignal )
983 {
984  mCRS = srs;
985 
986  if ( !mCRS.isValid() )
987  {
988  mCRS.setValidationHint( tr( "Specify CRS for layer %1" ).arg( name() ) );
989  mCRS.validate();
990  }
991 
992  if ( emitSignal )
993  emit crsChanged();
994 }
995 
996 QString QgsMapLayer::capitalizeLayerName( const QString &name )
997 {
998  // Capitalize the first letter of the layer name if requested
999  QgsSettings settings;
1000  bool capitalizeLayerName =
1001  settings.value( QStringLiteral( "qgis/capitalizeLayerName" ), QVariant( false ) ).toBool();
1002 
1003  QString layerName( name );
1004 
1005  if ( capitalizeLayerName && !layerName.isEmpty() )
1006  layerName = layerName.at( 0 ).toUpper() + layerName.mid( 1 );
1007 
1008  return layerName;
1009 }
1010 
1011 QString QgsMapLayer::styleURI() const
1012 {
1013  QString myURI = publicSource();
1014 
1015  // if file is using the VSIFILE mechanism, remove the prefix
1016  if ( myURI.startsWith( QLatin1String( "/vsigzip/" ), Qt::CaseInsensitive ) )
1017  {
1018  myURI.remove( 0, 9 );
1019  }
1020  else if ( myURI.startsWith( QLatin1String( "/vsizip/" ), Qt::CaseInsensitive ) &&
1021  myURI.endsWith( QLatin1String( ".zip" ), Qt::CaseInsensitive ) )
1022  {
1023  // ideally we should look for .qml file inside zip file
1024  myURI.remove( 0, 8 );
1025  }
1026  else if ( myURI.startsWith( QLatin1String( "/vsitar/" ), Qt::CaseInsensitive ) &&
1027  ( myURI.endsWith( QLatin1String( ".tar" ), Qt::CaseInsensitive ) ||
1028  myURI.endsWith( QLatin1String( ".tar.gz" ), Qt::CaseInsensitive ) ||
1029  myURI.endsWith( QLatin1String( ".tgz" ), Qt::CaseInsensitive ) ) )
1030  {
1031  // ideally we should look for .qml file inside tar file
1032  myURI.remove( 0, 8 );
1033  }
1034 
1035  QFileInfo myFileInfo( myURI );
1036  QString key;
1037 
1038  if ( myFileInfo.exists() )
1039  {
1040  // if file is using the /vsizip/ or /vsigzip/ mechanism, cleanup the name
1041  if ( myURI.endsWith( QLatin1String( ".gz" ), Qt::CaseInsensitive ) )
1042  myURI.chop( 3 );
1043  else if ( myURI.endsWith( QLatin1String( ".zip" ), Qt::CaseInsensitive ) )
1044  myURI.chop( 4 );
1045  else if ( myURI.endsWith( QLatin1String( ".tar" ), Qt::CaseInsensitive ) )
1046  myURI.chop( 4 );
1047  else if ( myURI.endsWith( QLatin1String( ".tar.gz" ), Qt::CaseInsensitive ) )
1048  myURI.chop( 7 );
1049  else if ( myURI.endsWith( QLatin1String( ".tgz" ), Qt::CaseInsensitive ) )
1050  myURI.chop( 4 );
1051  myFileInfo.setFile( myURI );
1052  // get the file name for our .qml style file
1053  key = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".qml";
1054  }
1055  else
1056  {
1057  key = publicSource();
1058  }
1059 
1060  return key;
1061 }
1062 
1063 QString QgsMapLayer::loadDefaultStyle( bool &resultFlag )
1064 {
1065  return loadNamedStyle( styleURI(), resultFlag );
1066 }
1067 
1068 bool QgsMapLayer::loadNamedStyleFromDatabase( const QString &db, const QString &uri, QString &qml )
1069 {
1070  QgsDebugMsg( QString( "db = %1 uri = %2" ).arg( db, uri ) );
1071 
1072  bool resultFlag = false;
1073 
1074  // read from database
1075  sqlite3 *myDatabase = nullptr;
1076  sqlite3_stmt *myPreparedStatement = nullptr;
1077  const char *myTail = nullptr;
1078  int myResult;
1079 
1080  QgsDebugMsg( QString( "Trying to load style for \"%1\" from \"%2\"" ).arg( uri, db ) );
1081 
1082  if ( db.isEmpty() || !QFile( db ).exists() )
1083  return false;
1084 
1085  myResult = sqlite3_open_v2( db.toUtf8().data(), &myDatabase, SQLITE_OPEN_READONLY, nullptr );
1086  if ( myResult != SQLITE_OK )
1087  {
1088  return false;
1089  }
1090 
1091  QString mySql = QStringLiteral( "select qml from tbl_styles where style=?" );
1092  myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
1093  if ( myResult == SQLITE_OK )
1094  {
1095  QByteArray param = uri.toUtf8();
1096 
1097  if ( sqlite3_bind_text( myPreparedStatement, 1, param.data(), param.length(), SQLITE_STATIC ) == SQLITE_OK &&
1098  sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
1099  {
1100  qml = QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 0 ) ) );
1101  resultFlag = true;
1102  }
1103 
1104  sqlite3_finalize( myPreparedStatement );
1105  }
1106 
1107  sqlite3_close( myDatabase );
1108 
1109  return resultFlag;
1110 }
1111 
1112 
1113 QString QgsMapLayer::loadNamedStyle( const QString &uri, bool &resultFlag )
1114 {
1115  QgsDebugMsg( QString( "uri = %1 myURI = %2" ).arg( uri, publicSource() ) );
1116 
1117  resultFlag = false;
1118 
1119  QDomDocument myDocument( QStringLiteral( "qgis" ) );
1120 
1121  // location of problem associated with errorMsg
1122  int line, column;
1123  QString myErrorMessage;
1124 
1125  QFile myFile( uri );
1126  if ( myFile.open( QFile::ReadOnly ) )
1127  {
1128  // read file
1129  resultFlag = myDocument.setContent( &myFile, &myErrorMessage, &line, &column );
1130  if ( !resultFlag )
1131  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1132  myFile.close();
1133  }
1134  else
1135  {
1136  QFileInfo project( QgsProject::instance()->fileName() );
1137  QgsDebugMsg( QString( "project fileName: %1" ).arg( project.absoluteFilePath() ) );
1138 
1139  QString qml;
1140  if ( loadNamedStyleFromDatabase( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ), uri, qml ) ||
1141  ( project.exists() && loadNamedStyleFromDatabase( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), uri, qml ) ) ||
1142  loadNamedStyleFromDatabase( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( QStringLiteral( "resources/qgis.qmldb" ) ), uri, qml ) )
1143  {
1144  resultFlag = myDocument.setContent( qml, &myErrorMessage, &line, &column );
1145  if ( !resultFlag )
1146  {
1147  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1148  }
1149  }
1150  else
1151  {
1152  myErrorMessage = tr( "Style not found in database" );
1153  }
1154  }
1155 
1156  if ( !resultFlag )
1157  {
1158  return myErrorMessage;
1159  }
1160 
1161  resultFlag = importNamedStyle( myDocument, myErrorMessage );
1162  if ( !resultFlag )
1163  myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( uri, myErrorMessage );
1164 
1165  return myErrorMessage;
1166 }
1167 
1168 
1169 bool QgsMapLayer::importNamedStyle( QDomDocument &myDocument, QString &myErrorMessage )
1170 {
1171  QDomElement myRoot = myDocument.firstChildElement( QStringLiteral( "qgis" ) );
1172  if ( myRoot.isNull() )
1173  {
1174  myErrorMessage = tr( "Root <qgis> element could not be found" );
1175  return false;
1176  }
1177 
1178  // get style file version string, if any
1179  QgsProjectVersion fileVersion( myRoot.attribute( QStringLiteral( "version" ) ) );
1180  QgsProjectVersion thisVersion( Qgis::QGIS_VERSION );
1181 
1182  if ( thisVersion > fileVersion )
1183  {
1184  QgsProjectFileTransform styleFile( myDocument, fileVersion );
1185  styleFile.updateRevision( thisVersion );
1186  }
1187 
1188  //Test for matching geometry type on vector layers when applying, if geometry type is given in the style
1189  if ( type() == QgsMapLayer::VectorLayer && !myRoot.firstChildElement( QStringLiteral( "layerGeometryType" ) ).isNull() )
1190  {
1191  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( this );
1192  QgsWkbTypes::GeometryType importLayerGeometryType = static_cast<QgsWkbTypes::GeometryType>( myRoot.firstChildElement( QStringLiteral( "layerGeometryType" ) ).text().toInt() );
1193  if ( vl->geometryType() != importLayerGeometryType )
1194  {
1195  myErrorMessage = tr( "Cannot apply style to layer with a different geometry type" );
1196  return false;
1197  }
1198  }
1199 
1200  // use scale dependent visibility flag
1201  setScaleBasedVisibility( myRoot.attribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ) ).toInt() == 1 );
1202  if ( myRoot.hasAttribute( QStringLiteral( "minimumScale" ) ) )
1203  {
1204  //older scale element, when min/max were reversed
1205  setMaximumScale( myRoot.attribute( QStringLiteral( "minimumScale" ) ).toDouble() );
1206  setMinimumScale( myRoot.attribute( QStringLiteral( "maximumScale" ) ).toDouble() );
1207  }
1208  else
1209  {
1210  setMaximumScale( myRoot.attribute( QStringLiteral( "maxScale" ) ).toDouble() );
1211  setMinimumScale( myRoot.attribute( QStringLiteral( "minScale" ) ).toDouble() );
1212  }
1213 
1214  return readSymbology( myRoot, myErrorMessage, QgsReadWriteContext() ); // TODO: support relative paths in QML?
1215 }
1216 
1217 void QgsMapLayer::exportNamedStyle( QDomDocument &doc, QString &errorMsg ) const
1218 {
1219  QDomImplementation DomImplementation;
1220  QDomDocumentType documentType = DomImplementation.createDocumentType( QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
1221  QDomDocument myDocument( documentType );
1222 
1223  QDomElement myRootNode = myDocument.createElement( QStringLiteral( "qgis" ) );
1224  myRootNode.setAttribute( QStringLiteral( "version" ), Qgis::QGIS_VERSION );
1225  myDocument.appendChild( myRootNode );
1226 
1227  myRootNode.setAttribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ), hasScaleBasedVisibility() ? 1 : 0 );
1228  myRootNode.setAttribute( QStringLiteral( "maxScale" ), QString::number( maximumScale() ) );
1229  myRootNode.setAttribute( QStringLiteral( "mincale" ), QString::number( minimumScale() ) );
1230 
1231  if ( !writeSymbology( myRootNode, myDocument, errorMsg, QgsReadWriteContext() ) ) // TODO: support relative paths in QML?
1232  {
1233  errorMsg = QObject::tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1234  return;
1235  }
1236 
1237  /*
1238  * Check to see if the layer is vector - in which case we should also export its geometryType
1239  * to avoid eventually pasting to a layer with a different geometry
1240  */
1241  if ( type() == QgsMapLayer::VectorLayer )
1242  {
1243  //Getting the selectionLayer geometry
1244  const QgsVectorLayer *vl = qobject_cast<const QgsVectorLayer *>( this );
1245  QString geoType = QString::number( vl->geometryType() );
1246 
1247  //Adding geometryinformation
1248  QDomElement layerGeometryType = myDocument.createElement( QStringLiteral( "layerGeometryType" ) );
1249  QDomText type = myDocument.createTextNode( geoType );
1250 
1251  layerGeometryType.appendChild( type );
1252  myRootNode.appendChild( layerGeometryType );
1253  }
1254 
1255  doc = myDocument;
1256 }
1257 
1258 QString QgsMapLayer::saveDefaultStyle( bool &resultFlag )
1259 {
1260  return saveNamedStyle( styleURI(), resultFlag );
1261 }
1262 
1263 QString QgsMapLayer::saveNamedStyle( const QString &uri, bool &resultFlag )
1264 {
1265  QString myErrorMessage;
1266  QDomDocument myDocument;
1267  exportNamedStyle( myDocument, myErrorMessage );
1268 
1269  // check if the uri is a file or ends with .qml,
1270  // which indicates that it should become one
1271  // everything else goes to the database
1272  QString filename;
1273 
1274  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this );
1275  if ( vlayer && vlayer->providerType() == QLatin1String( "ogr" ) )
1276  {
1277  QStringList theURIParts = uri.split( '|' );
1278  filename = theURIParts[0];
1279  }
1280  else if ( vlayer && vlayer->providerType() == QLatin1String( "gpx" ) )
1281  {
1282  QStringList theURIParts = uri.split( '?' );
1283  filename = theURIParts[0];
1284  }
1285  else if ( vlayer && vlayer->providerType() == QLatin1String( "delimitedtext" ) )
1286  {
1287  filename = QUrl::fromEncoded( uri.toLatin1() ).toLocalFile();
1288  // toLocalFile() returns an empty string if theURI is a plain Windows-path, e.g. "C:/style.qml"
1289  if ( filename.isEmpty() )
1290  filename = uri;
1291  }
1292  else
1293  {
1294  filename = uri;
1295  }
1296 
1297  QFileInfo myFileInfo( filename );
1298  if ( myFileInfo.exists() || filename.endsWith( QLatin1String( ".qml" ), Qt::CaseInsensitive ) )
1299  {
1300  QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
1301  if ( !myDirInfo.isWritable() )
1302  {
1303  return tr( "The directory containing your dataset needs to be writable!" );
1304  }
1305 
1306  // now construct the file name for our .qml style file
1307  QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".qml";
1308 
1309  QFile myFile( myFileName );
1310  if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
1311  {
1312  QTextStream myFileStream( &myFile );
1313  // save as utf-8 with 2 spaces for indents
1314  myDocument.save( myFileStream, 2 );
1315  myFile.close();
1316  resultFlag = true;
1317  return tr( "Created default style file as %1" ).arg( myFileName );
1318  }
1319  else
1320  {
1321  resultFlag = false;
1322  return tr( "ERROR: Failed to created default style file as %1. Check file permissions and retry." ).arg( myFileName );
1323  }
1324  }
1325  else
1326  {
1327  QString qml = myDocument.toString();
1328 
1329  // read from database
1330  sqlite3 *myDatabase = nullptr;
1331  sqlite3_stmt *myPreparedStatement = nullptr;
1332  const char *myTail = nullptr;
1333  int myResult;
1334 
1335  myResult = sqlite3_open( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ).toUtf8().data(), &myDatabase );
1336  if ( myResult != SQLITE_OK )
1337  {
1338  return tr( "User database could not be opened." );
1339  }
1340 
1341  QByteArray param0 = uri.toUtf8();
1342  QByteArray param1 = qml.toUtf8();
1343 
1344  QString mySql = QStringLiteral( "create table if not exists tbl_styles(style varchar primary key,qml varchar)" );
1345  myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
1346  if ( myResult == SQLITE_OK )
1347  {
1348  if ( sqlite3_step( myPreparedStatement ) != SQLITE_DONE )
1349  {
1350  sqlite3_finalize( myPreparedStatement );
1351  sqlite3_close( myDatabase );
1352  resultFlag = false;
1353  return tr( "The style table could not be created." );
1354  }
1355  }
1356 
1357  sqlite3_finalize( myPreparedStatement );
1358 
1359  mySql = QStringLiteral( "insert into tbl_styles(style,qml) values (?,?)" );
1360  myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
1361  if ( myResult == SQLITE_OK )
1362  {
1363  if ( sqlite3_bind_text( myPreparedStatement, 1, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
1364  sqlite3_bind_text( myPreparedStatement, 2, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
1365  sqlite3_step( myPreparedStatement ) == SQLITE_DONE )
1366  {
1367  resultFlag = true;
1368  myErrorMessage = tr( "The style %1 was saved to database" ).arg( uri );
1369  }
1370  }
1371 
1372  sqlite3_finalize( myPreparedStatement );
1373 
1374  if ( !resultFlag )
1375  {
1376  QString mySql = QStringLiteral( "update tbl_styles set qml=? where style=?" );
1377  myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
1378  if ( myResult == SQLITE_OK )
1379  {
1380  if ( sqlite3_bind_text( myPreparedStatement, 2, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
1381  sqlite3_bind_text( myPreparedStatement, 1, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
1382  sqlite3_step( myPreparedStatement ) == SQLITE_DONE )
1383  {
1384  resultFlag = true;
1385  myErrorMessage = tr( "The style %1 was updated in the database." ).arg( uri );
1386  }
1387  else
1388  {
1389  resultFlag = false;
1390  myErrorMessage = tr( "The style %1 could not be updated in the database." ).arg( uri );
1391  }
1392  }
1393  else
1394  {
1395  resultFlag = false;
1396  myErrorMessage = tr( "The style %1 could not be inserted into database." ).arg( uri );
1397  }
1398 
1399  sqlite3_finalize( myPreparedStatement );
1400  }
1401 
1402  sqlite3_close( myDatabase );
1403  }
1404 
1405  return myErrorMessage;
1406 }
1407 
1408 void QgsMapLayer::exportSldStyle( QDomDocument &doc, QString &errorMsg ) const
1409 {
1410  QDomDocument myDocument = QDomDocument();
1411 
1412  QDomNode header = myDocument.createProcessingInstruction( QStringLiteral( "xml" ), QStringLiteral( "version=\"1.0\" encoding=\"UTF-8\"" ) );
1413  myDocument.appendChild( header );
1414 
1415  // Create the root element
1416  QDomElement root = myDocument.createElementNS( QStringLiteral( "http://www.opengis.net/sld" ), QStringLiteral( "StyledLayerDescriptor" ) );
1417  root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.1.0" ) );
1418  root.setAttribute( QStringLiteral( "xsi:schemaLocation" ), QStringLiteral( "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" ) );
1419  root.setAttribute( QStringLiteral( "xmlns:ogc" ), QStringLiteral( "http://www.opengis.net/ogc" ) );
1420  root.setAttribute( QStringLiteral( "xmlns:se" ), QStringLiteral( "http://www.opengis.net/se" ) );
1421  root.setAttribute( QStringLiteral( "xmlns:xlink" ), QStringLiteral( "http://www.w3.org/1999/xlink" ) );
1422  root.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) );
1423  myDocument.appendChild( root );
1424 
1425  // Create the NamedLayer element
1426  QDomElement namedLayerNode = myDocument.createElement( QStringLiteral( "NamedLayer" ) );
1427  root.appendChild( namedLayerNode );
1428 
1429  const QgsVectorLayer *vlayer = qobject_cast<const QgsVectorLayer *>( this );
1430  if ( !vlayer )
1431  {
1432  errorMsg = tr( "Could not save symbology because:\n%1" )
1433  .arg( QStringLiteral( "Non-vector layers not supported yet" ) );
1434  return;
1435  }
1436 
1437  QgsStringMap props;
1438  if ( hasScaleBasedVisibility() )
1439  {
1440  props[ QStringLiteral( "scaleMinDenom" )] = QString::number( mMinScale );
1441  props[ QStringLiteral( "scaleMaxDenom" )] = QString::number( mMaxScale );
1442  }
1443  if ( !vlayer->writeSld( namedLayerNode, myDocument, errorMsg, props ) )
1444  {
1445  errorMsg = tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
1446  return;
1447  }
1448 
1449  doc = myDocument;
1450 }
1451 
1452 QString QgsMapLayer::saveSldStyle( const QString &uri, bool &resultFlag ) const
1453 {
1454  QString errorMsg;
1455  QDomDocument myDocument;
1456  exportSldStyle( myDocument, errorMsg );
1457  if ( !errorMsg.isNull() )
1458  {
1459  resultFlag = false;
1460  return errorMsg;
1461  }
1462  const QgsVectorLayer *vlayer = qobject_cast<const QgsVectorLayer *>( this );
1463 
1464  // check if the uri is a file or ends with .sld,
1465  // which indicates that it should become one
1466  QString filename;
1467  if ( vlayer->providerType() == QLatin1String( "ogr" ) )
1468  {
1469  QStringList theURIParts = uri.split( '|' );
1470  filename = theURIParts[0];
1471  }
1472  else if ( vlayer->providerType() == QLatin1String( "gpx" ) )
1473  {
1474  QStringList theURIParts = uri.split( '?' );
1475  filename = theURIParts[0];
1476  }
1477  else if ( vlayer->providerType() == QLatin1String( "delimitedtext" ) )
1478  {
1479  filename = QUrl::fromEncoded( uri.toLatin1() ).toLocalFile();
1480  // toLocalFile() returns an empty string if theURI is a plain Windows-path, e.g. "C:/style.qml"
1481  if ( filename.isEmpty() )
1482  filename = uri;
1483  }
1484  else
1485  {
1486  filename = uri;
1487  }
1488 
1489  QFileInfo myFileInfo( filename );
1490  if ( myFileInfo.exists() || filename.endsWith( QLatin1String( ".sld" ), Qt::CaseInsensitive ) )
1491  {
1492  QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
1493  if ( !myDirInfo.isWritable() )
1494  {
1495  return tr( "The directory containing your dataset needs to be writable!" );
1496  }
1497 
1498  // now construct the file name for our .sld style file
1499  QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".sld";
1500 
1501  QFile myFile( myFileName );
1502  if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
1503  {
1504  QTextStream myFileStream( &myFile );
1505  // save as utf-8 with 2 spaces for indents
1506  myDocument.save( myFileStream, 2 );
1507  myFile.close();
1508  resultFlag = true;
1509  return tr( "Created default style file as %1" ).arg( myFileName );
1510  }
1511  }
1512 
1513  resultFlag = false;
1514  return tr( "ERROR: Failed to created SLD style file as %1. Check file permissions and retry." ).arg( filename );
1515 }
1516 
1517 QString QgsMapLayer::loadSldStyle( const QString &uri, bool &resultFlag )
1518 {
1519  QgsDebugMsg( "Entered." );
1520 
1521  resultFlag = false;
1522 
1523  QDomDocument myDocument;
1524 
1525  // location of problem associated with errorMsg
1526  int line, column;
1527  QString myErrorMessage;
1528 
1529  QFile myFile( uri );
1530  if ( myFile.open( QFile::ReadOnly ) )
1531  {
1532  // read file
1533  resultFlag = myDocument.setContent( &myFile, true, &myErrorMessage, &line, &column );
1534  if ( !resultFlag )
1535  myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
1536  myFile.close();
1537  }
1538  else
1539  {
1540  myErrorMessage = tr( "Unable to open file %1" ).arg( uri );
1541  }
1542 
1543  if ( !resultFlag )
1544  {
1545  return myErrorMessage;
1546  }
1547 
1548  // check for root SLD element
1549  QDomElement myRoot = myDocument.firstChildElement( QStringLiteral( "StyledLayerDescriptor" ) );
1550  if ( myRoot.isNull() )
1551  {
1552  myErrorMessage = QStringLiteral( "Error: StyledLayerDescriptor element not found in %1" ).arg( uri );
1553  resultFlag = false;
1554  return myErrorMessage;
1555  }
1556 
1557  // now get the style node out and pass it over to the layer
1558  // to deserialise...
1559  QDomElement namedLayerElem = myRoot.firstChildElement( QStringLiteral( "NamedLayer" ) );
1560  if ( namedLayerElem.isNull() )
1561  {
1562  myErrorMessage = QStringLiteral( "Info: NamedLayer element not found." );
1563  resultFlag = false;
1564  return myErrorMessage;
1565  }
1566 
1567  QString errorMsg;
1568  resultFlag = readSld( namedLayerElem, errorMsg );
1569  if ( !resultFlag )
1570  {
1571  myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( uri, errorMsg );
1572  return myErrorMessage;
1573  }
1574 
1575  return QLatin1String( "" );
1576 }
1577 
1578 bool QgsMapLayer::readStyle( const QDomNode &node, QString &errorMessage, const QgsReadWriteContext &context )
1579 {
1580  Q_UNUSED( node );
1581  Q_UNUSED( errorMessage );
1582  Q_UNUSED( context );
1583  return false;
1584 }
1585 
1586 bool QgsMapLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context ) const
1587 {
1588  Q_UNUSED( node );
1589  Q_UNUSED( doc );
1590  Q_UNUSED( errorMessage );
1591  Q_UNUSED( context );
1592  return false;
1593 }
1594 
1595 
1597 {
1598  return &mUndoStack;
1599 }
1600 
1602 {
1603  return &mUndoStackStyles;
1604 }
1605 
1606 
1608 {
1609  return mCustomProperties.keys();
1610 }
1611 
1612 void QgsMapLayer::setCustomProperty( const QString &key, const QVariant &value )
1613 {
1614  mCustomProperties.setValue( key, value );
1615 }
1616 
1618 {
1619  mCustomProperties = properties;
1620 }
1621 
1622 QVariant QgsMapLayer::customProperty( const QString &value, const QVariant &defaultValue ) const
1623 {
1624  return mCustomProperties.value( value, defaultValue );
1625 }
1626 
1627 void QgsMapLayer::removeCustomProperty( const QString &key )
1628 {
1629  mCustomProperties.remove( key );
1630 }
1631 
1633 {
1634  return mError;
1635 }
1636 
1637 
1638 
1640 {
1641  return false;
1642 }
1643 
1645 {
1646  return true;
1647 }
1648 
1649 void QgsMapLayer::setValid( bool valid )
1650 {
1651  mValid = valid;
1652 }
1653 
1655 {
1656  if ( legend == mLegend )
1657  return;
1658 
1659  delete mLegend;
1660  mLegend = legend;
1661 
1662  if ( mLegend )
1663  connect( mLegend, &QgsMapLayerLegend::itemsChanged, this, &QgsMapLayer::legendChanged );
1664 
1665  emit legendChanged();
1666 }
1667 
1669 {
1670  return mLegend;
1671 }
1672 
1674 {
1675  return mStyleManager;
1676 }
1677 
1678 void QgsMapLayer::triggerRepaint( bool deferredUpdate )
1679 {
1680  emit repaintRequested( deferredUpdate );
1681 }
1682 
1684 {
1685  mMetadata = metadata;
1686  mMetadata.saveToLayer( this );
1687  emit metadataChanged();
1688 }
1689 
1691 {
1692  return QString();
1693 }
1694 
1695 QDateTime QgsMapLayer::timestamp() const
1696 {
1697  return QDateTime() ;
1698 }
1699 
1701 {
1702  emit styleChanged();
1703 }
1704 
1706 {
1707  mExtent = r;
1708 }
1709 
1710 static QList<const QgsMapLayer *> _depOutEdges( const QgsMapLayer *vl, const QgsMapLayer *that, const QSet<QgsMapLayerDependency> &layers )
1711 {
1712  QList<const QgsMapLayer *> lst;
1713  if ( vl == that )
1714  {
1715  Q_FOREACH ( const QgsMapLayerDependency &dep, layers )
1716  {
1717  if ( const QgsMapLayer *l = QgsProject::instance()->mapLayer( dep.layerId() ) )
1718  lst << l;
1719  }
1720  }
1721  else
1722  {
1723  Q_FOREACH ( const QgsMapLayerDependency &dep, vl->dependencies() )
1724  {
1725  if ( const QgsMapLayer *l = QgsProject::instance()->mapLayer( dep.layerId() ) )
1726  lst << l;
1727  }
1728  }
1729  return lst;
1730 }
1731 
1732 static bool _depHasCycleDFS( const QgsMapLayer *n, QHash<const QgsMapLayer *, int> &mark, const QgsMapLayer *that, const QSet<QgsMapLayerDependency> &layers )
1733 {
1734  if ( mark.value( n ) == 1 ) // temporary
1735  return true;
1736  if ( mark.value( n ) == 0 ) // not visited
1737  {
1738  mark[n] = 1; // temporary
1739  Q_FOREACH ( const QgsMapLayer *m, _depOutEdges( n, that, layers ) )
1740  {
1741  if ( _depHasCycleDFS( m, mark, that, layers ) )
1742  return true;
1743  }
1744  mark[n] = 2; // permanent
1745  }
1746  return false;
1747 }
1748 
1749 bool QgsMapLayer::hasDependencyCycle( const QSet<QgsMapLayerDependency> &layers ) const
1750 {
1751  QHash<const QgsMapLayer *, int> marks;
1752  return _depHasCycleDFS( this, marks, this, layers );
1753 }
1754 
1755 bool QgsMapLayer::isReadOnly() const
1756 {
1757  return true;
1758 }
1759 
1760 QSet<QgsMapLayerDependency> QgsMapLayer::dependencies() const
1761 {
1762  return mDependencies;
1763 }
1764 
1765 bool QgsMapLayer::setDependencies( const QSet<QgsMapLayerDependency> &oDeps )
1766 {
1767  QSet<QgsMapLayerDependency> deps;
1768  Q_FOREACH ( const QgsMapLayerDependency &dep, oDeps )
1769  {
1770  if ( dep.origin() == QgsMapLayerDependency::FromUser )
1771  deps << dep;
1772  }
1773  if ( hasDependencyCycle( deps ) )
1774  return false;
1775 
1776  mDependencies = deps;
1777  emit dependenciesChanged();
1778  return true;
1779 }
QString attributionUrl() const
Returns the attribution URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:279
Origin origin() const
Return the dependency origin.
QString mShortName
Definition: qgsmaplayer.h:1004
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:289
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:245
A rectangle specified with double values.
Definition: qgsrectangle.h:38
Base class for all map layer types.
Definition: qgsmaplayer.h:54
static const QString QGIS_VERSION
Version string.
Definition: qgis.h:60
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:162
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.
QString mAttributionUrl
Definition: qgsmaplayer.h:1017
static QgsAuthManager * instance()
Enforce singleton pattern.
QString mKeywordList
Definition: qgsmaplayer.h:1009
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...
This class is a composition of two QSettings instances:
Definition: qgssettings.h:54
QStringList customPropertyKeys() const
Returns list of all keys within custom properties.
void saveToLayer(QgsMapLayer *layer) const
Saves the metadata to a layer&#39;s custom properties (see QgsMapLayer::setCustomProperty() )...
QString shortName() const
Returns the short name of the layer used by QGIS Server to identify the layer.
Definition: qgsmaplayer.h:169
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
QgsMapLayerLegend * legend() const
Can be null.
virtual ~QgsMapLayer()
Definition: qgsmaplayer.cpp:90
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:1013
#define QgsDebugMsg(str)
Definition: qgslogger.h:37
virtual QgsError error() const
Get current status error.
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
void validate()
Perform some validation on this CRS.
QString dataUrl() const
Returns the DataUrl of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:229
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 ...
QString mLegendUrlFormat
Definition: qgsmaplayer.h:1026
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 bool readXml(const QDomNode &layer_node, const QgsReadWriteContext &context)
Called by readLayerXML(), used by children to read state specific to them from project files...
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.
bool isInScaleRange(double scale) const
Tests whether the layer should be visible at the specified scale.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
Return 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:305
static QString capitalizeLayerName(const QString &name)
A convenience function to (un)capitalize the layer name.
Abstract base class for spatial data provider implementations.
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.
bool isValid() const
Return the status of the layer.
void setBlendMode(QPainter::CompositionMode blendMode)
Set the blending mode used for rendering a layer.
void setConnection(const QString &aHost, const QString &aPort, const QString &aDatabase, const QString &aUsername, const QString &aPassword, SslMode sslmode=SslPrefer, const QString &authConfigId=QString())
Set all connection related members at once.
QgsMapLayer::LayerType type() const
Returns the type of the layer.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:340
void remove(const QString &key)
Remove a key (entry) from the store.
QString mLayerName
Name of the layer - used for display.
Definition: qgsmaplayer.h:998
QString username() const
Returns the username.
void styleChanged()
Signal emitted whenever a change affects the layer&#39;s style.
virtual bool readSymbology(const QDomNode &node, QString &errorMessage, const QgsReadWriteContext &context)=0
Read the symbology for the current layer from the Dom node supplied.
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:52
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
Get access to the layer&#39;s style manager.
QgsError mError
Error.
Definition: qgsmaplayer.h:1029
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:989
QString mMetadataUrl
MetadataUrl of the layer.
Definition: qgsmaplayer.h:1020
void setLegendUrlFormat(const QString &legendUrlFormat)
Sets the format for a URL based layer legend.
Definition: qgsmaplayer.h:656
QString host() const
Returns the host.
QString metadataUrlFormat() const
Returns the metadata format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:329
void setValidationHint(const QString &html)
Set user hint for validation.
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
void setKeywordList(const QString &keywords)
Sets the keyword list of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:204
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.
void setTitle(const QString &title)
Sets the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:176
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).
QString originalName() const
Returns the original name of the layer.
virtual void setSubLayerVisibility(const QString &name, bool visible)
Set the visibility of the given sublayer name.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:38
LayerType
Types of layers that can be added to a map.
Definition: qgsmaplayer.h:92
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:1032
void nameChanged()
Emitted when the name has been changed.
A class to describe the version of a project.
QString providerType() const
[ data provider interface ] Which provider is being used for this Raster Layer?
virtual void setExtent(const QgsRectangle &rect)
Set 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:211
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.
virtual QString dataSourceUri(bool expandAuthConfig=false) const
Get the data source specification.
QString mDataUrl
DataUrl of the layer.
Definition: qgsmaplayer.h:1012
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.
QString legendUrl() const
Returns the URL for the layer&#39;s legend.
Definition: qgsmaplayer.h:651
QgsCoordinateReferenceSystem crs() const
Returns the layer&#39;s spatial reference system.
QString publicSource() const
Gets a version of the internal layer definition that has sensitive bits removed (for example...
void setParam(const QString &key, const QString &value)
Set generic param (generic mode)
void removeCustomProperty(const QString &key)
Remove a custom property from layer.
virtual bool importNamedStyle(QDomDocument &doc, QString &errorMsg)
Import the properties of this layer from a QDomDocument.
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:992
QString port() const
Returns the port.
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:237
QStringList keys() const
Return list of stored keys.
QString mTitle
Definition: qgsmaplayer.h:1005
virtual bool readSld(const QDomNode &node, QString &errorMessage)
Definition: qgsmaplayer.h:592
QString legendUrlFormat() const
Returns the format for a URL based layer legend.
Definition: qgsmaplayer.h:661
QString mMetadataUrlFormat
Definition: qgsmaplayer.h:1022
void setLegendUrl(const QString &legendUrl)
Sets the URL for the layer&#39;s legend.
Definition: qgsmaplayer.h:646
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:321
QString title() const
Returns the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:183
static QString pkgDataPath()
Returns the common root path of all application data directories.
struct sqlite3 sqlite3
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 uri(bool expandAuthConfig=true) const
return complete uri
bool readLayerXml(const QDomElement &layerElement, const QgsReadWriteContext &context)
Sets state from Dom document.
QString mAttribution
Attribution of the layer.
Definition: qgsmaplayer.h:1016
QString mAbstract
Description of the layer.
Definition: qgsmaplayer.h:1008
void writeStyleManager(QDomNode &layerNode, QDomDocument &doc) const
Write style manager&#39;s configuration (if exists). To be called by subclasses.
void blendModeChanged(QPainter::CompositionMode blendMode)
Signal emitted when the blend mode is changed, through QgsMapLayer::setBlendMode() ...
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:136
virtual bool readStyle(const QDomNode &node, QString &errorMessage, const QgsReadWriteContext &context)
Read the style for the current layer from the Dom node supplied.
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:995
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:82
bool setMasterPassword(bool verify=false)
Main call to initially set or continually check master password is set.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), const Section section=NoSection) const
Returns the value for setting key.
void setMinimumScale(double scale)
Sets the minimum map scale (i.e.
QByteArray encodedUri() const
return complete encoded uri (generic mode)
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:377
QString mLegendUrl
WMS legend.
Definition: qgsmaplayer.h:1025
This class represents a coordinate reference system (CRS).
QString layerId() const
Return the ID of the layer this dependency depends on.
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
QgsVectorDataProvider * dataProvider() override
Returns the layer&#39;s data provider.
void legendChanged()
Signal emitted when legend of the layer has changed.
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
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:271
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 metadataUrl() const
Returns the metadata URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:297
void readFromLayer(const QgsMapLayer *layer)
Reads the metadata state from a layer&#39;s custom properties (see QgsMapLayer::customProperty() )...
void setAutoRefreshEnabled(bool enabled)
Sets whether auto refresh is enabled for the layer.
QUndoStack * undoStackStyles()
Return pointer to layer&#39;s style undo stack.
QString password() const
Returns the password.
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()
Return 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:255
void(* CUSTOM_CRS_VALIDATION)(QgsCoordinateReferenceSystem &)
QString providerType() const
Return the provider type for this layer.
bool hasAutoRefreshEnabled() const
Returns true if auto refresh is enabled for the layer.
void setLegend(QgsMapLayerLegend *legend)
Assign a legend controller to the map layer.
Class for storing the component parts of a PostgreSQL/RDBMS datasource URI.
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.
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:221
QString mLayerOrigName
Original name of the layer.
Definition: qgsmaplayer.h:1002
void setValid(bool valid)
Set whether layer is valid or not - should be used in constructor.
static QgsRectangle readRectangle(const QDomElement &element)
Definition: qgsxmlutils.cpp:36
QString mMetadataUrlType
Definition: qgsmaplayer.h:1021
QString database() const
Returns the database.
void setDatabase(const QString &database)
Set database.
void setAbstract(const QString &abstract)
Sets the abstract of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:190
static const double SCALE_PRECISION
Fudge factor used to compare two scales.
Definition: qgis.h:116
QString attribution() const
Returns the attribution of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:263
QString metadataUrlType() const
Returns the metadata type of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:313
void setScaleBasedVisibility(const bool enabled)
Sets whether scale based visibility is enabled for the layer.
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
static QString removePassword(const QString &aUri)
Removes password element from uris.
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.