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