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