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