QGIS API Documentation  3.6.0-Noosa (5873452)
qgsmaplayerstylemanager.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmaplayerstylemanager.cpp
3  --------------------------------------
4  Date : January 2015
5  Copyright : (C) 2015 by Martin Dobias
6  Email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
17 #include "qgsmaplayerstyle.h"
18 #include "qgsmaplayer.h"
19 
20 #include "qgslogger.h"
21 
22 #include <QDomElement>
23 #include <QTextStream>
24 
26  : mLayer( layer )
27 
28 {
29  reset();
30 }
31 
32 QString QgsMapLayerStyleManager::defaultStyleName() const
33 {
34  return tr( "default" );
35 }
36 
37 
39 {
40  mStyles.insert( defaultStyleName(), QgsMapLayerStyle() ); // insert entry for the default current style
41  mCurrentStyle = defaultStyleName();
42 }
43 
44 void QgsMapLayerStyleManager::readXml( const QDomElement &mgrElement )
45 {
46  mCurrentStyle = mgrElement.attribute( QStringLiteral( "current" ) );
47  if ( mCurrentStyle.isEmpty() )
48  {
49  // For old project made with QGIS 2, we migrate to "default".
50  mCurrentStyle = defaultStyleName();
51  }
52 
53  mStyles.clear();
54  QDomElement ch = mgrElement.firstChildElement( QStringLiteral( "map-layer-style" ) );
55  while ( !ch.isNull() )
56  {
57  QString name = ch.attribute( QStringLiteral( "name" ) );
58  if ( name.isEmpty() )
59  {
60  // For old project made with QGIS 2, we migrate to "default".
61  name = defaultStyleName();
62  }
64  style.readXml( ch );
65  mStyles.insert( name, style );
66 
67  ch = ch.nextSiblingElement( QStringLiteral( "map-layer-style" ) );
68  }
69 }
70 
71 void QgsMapLayerStyleManager::writeXml( QDomElement &mgrElement ) const
72 {
73  QDomDocument doc = mgrElement.ownerDocument();
74  mgrElement.setAttribute( QStringLiteral( "current" ), mCurrentStyle );
75 
76  Q_FOREACH ( const QString &name, styles() )
77  {
78  QDomElement ch = doc.createElement( QStringLiteral( "map-layer-style" ) );
79  ch.setAttribute( QStringLiteral( "name" ), name );
80  mStyles[name].writeXml( ch );
81  mgrElement.appendChild( ch );
82  }
83 }
84 
86 {
87  return mStyles.keys();
88 }
89 
90 QMap<QString, QgsMapLayerStyle> QgsMapLayerStyleManager::mapLayerStyles() const
91 {
92  return mStyles;
93 }
94 
96 {
97  if ( name == mCurrentStyle )
98  {
99  // current style's entry is always kept invalid - get the style data from layer's properties
100  QgsMapLayerStyle curr;
101  curr.readFromLayer( mLayer );
102  return curr;
103  }
104 
105  return mStyles.value( name );
106 }
107 
108 bool QgsMapLayerStyleManager::addStyle( const QString &name, const QgsMapLayerStyle &style )
109 {
110  if ( mStyles.contains( name ) )
111  return false;
112  if ( !style.isValid() )
113  return false;
114 
115  mStyles.insert( name, style );
116  emit styleAdded( name );
117  return true;
118 }
119 
121 {
123  style.readFromLayer( mLayer );
124  return addStyle( name, style );
125 }
126 
127 bool QgsMapLayerStyleManager::removeStyle( const QString &name )
128 {
129  if ( !mStyles.contains( name ) )
130  return false;
131  if ( mStyles.count() == 1 )
132  return false; // cannot remove the last one
133 
134  // change to a different style if this one is the current
135  if ( mCurrentStyle == name )
136  {
137  QStringList keys = mStyles.keys();
138  QString newCurrent = keys[0];
139  if ( newCurrent == name )
140  newCurrent = keys[1]; // there must be at least one more
141  setCurrentStyle( newCurrent );
142  }
143 
144  mStyles.remove( name );
145  emit styleRemoved( name );
146  return true;
147 }
148 
149 bool QgsMapLayerStyleManager::renameStyle( const QString &name, const QString &newName )
150 {
151  if ( !mStyles.contains( name ) || mStyles.contains( newName ) )
152  return false;
153 
154  if ( name == mCurrentStyle )
155  mCurrentStyle = newName;
156 
157  mStyles[newName] = mStyles[name];
158  mStyles.remove( name );
159  emit styleRenamed( name, newName );
160  return true;
161 }
162 
164 {
165  return mCurrentStyle;
166 }
167 
168 bool QgsMapLayerStyleManager::setCurrentStyle( const QString &name )
169 {
170  if ( !mStyles.contains( name ) )
171  return false;
172 
173  if ( mCurrentStyle == name )
174  return true; // nothing to do
175 
176  mStyles[mCurrentStyle].readFromLayer( mLayer ); // sync before unloading it
177  mCurrentStyle = name;
178  mStyles[mCurrentStyle].writeToLayer( mLayer );
179  mStyles[mCurrentStyle].clear(); // current style does not keep any stored data
180  emit currentStyleChanged( mCurrentStyle );
181 
182  mLayer->triggerRepaint();
183  return true;
184 }
185 
186 bool QgsMapLayerStyleManager::setOverrideStyle( const QString &styleDef )
187 {
188  if ( mOverriddenOriginalStyle )
189  return false; // cannot override the style more than once!
190 
191  mLayer->blockSignals( true );
192  if ( mStyles.contains( styleDef ) )
193  {
194  mOverriddenOriginalStyle = new QgsMapLayerStyle;
195  mOverriddenOriginalStyle->readFromLayer( mLayer );
196 
197  // apply style name
198  mStyles[styleDef].writeToLayer( mLayer );
199  }
200  else if ( styleDef.startsWith( '<' ) )
201  {
202  mOverriddenOriginalStyle = new QgsMapLayerStyle;
203  mOverriddenOriginalStyle->readFromLayer( mLayer );
204 
205  // apply style XML
206  QgsMapLayerStyle overrideStyle( styleDef );
207  overrideStyle.writeToLayer( mLayer );
208  }
209  mLayer->blockSignals( false );
210 
211  return true;
212 }
213 
215 {
216  if ( !mOverriddenOriginalStyle )
217  return false;
218 
219  mLayer->blockSignals( true );
220  mOverriddenOriginalStyle->writeToLayer( mLayer );
221  mLayer->blockSignals( false );
222 
223  delete mOverriddenOriginalStyle;
224  mOverriddenOriginalStyle = nullptr;
225  return true;
226 }
227 
228 bool QgsMapLayerStyleManager::isDefault( const QString &styleName ) const
229 {
230  return styleName == defaultStyleName();
231 }
bool restoreOverrideStyle()
Restore the original store after a call to setOverrideStyle()
QgsMapLayerStyleManager(QgsMapLayer *layer)
Construct a style manager associated with a map layer (must not be null).
Base class for all map layer types.
Definition: qgsmaplayer.h:64
QStringList styles() const
Returns list of all defined style names.
void currentStyleChanged(const QString &currentName)
Emitted when the current style has been changed.
void styleRenamed(const QString &oldName, const QString &newName)
Emitted when a style has been renamed.
void reset()
Reset the style manager to a basic state - with one default style which is set as current...
void readXml(const QDomElement &styleElement)
Read style configuration (for project file reading)
bool isValid() const
Tell whether the style is valid (i.e. there is something stored in it)
void styleAdded(const QString &name)
Emitted when a new style has been added.
void readFromLayer(QgsMapLayer *layer)
Store layer&#39;s active style information in the instance.
Stores style information (renderer, opacity, labeling, diagrams etc.) applicable to a map layer...
bool removeStyle(const QString &name)
Remove a stored style.
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted...
void readXml(const QDomElement &mgrElement)
Read configuration (for project loading)
void styleRemoved(const QString &name)
Emitted when a style has been removed.
QgsMapLayerStyle style(const QString &name) const
Returns data of a stored style - accessed by its unique name.
void writeToLayer(QgsMapLayer *layer) const
Apply stored layer&#39;s style information to the layer.
bool addStyleFromLayer(const QString &name)
Add style by cloning the current one.
bool isDefault(const QString &styleName) const
Returns true if this is the default style.
QString currentStyle() const
Returns name of the current style.
bool renameStyle(const QString &name, const QString &newName)
Rename a stored style to a different name.
QMap< QString, QgsMapLayerStyle > mapLayerStyles() const
Gets available styles for the associated map layer.
bool addStyle(const QString &name, const QgsMapLayerStyle &style)
Add a style with given name and data.
bool setOverrideStyle(const QString &styleDef)
Temporarily apply a different style to the layer.
void writeXml(QDomElement &mgrElement) const
Write configuration (for project saving)
bool setCurrentStyle(const QString &name)
Set a different style as the current style - will apply it to the layer.