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