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