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