QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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  const auto constStyles = styles();
77  for ( const QString &name : constStyles )
78  {
79  QDomElement ch = doc.createElement( QStringLiteral( "map-layer-style" ) );
80  ch.setAttribute( QStringLiteral( "name" ), name );
81  mStyles[name].writeXml( ch );
82  mgrElement.appendChild( ch );
83  }
84 }
85 
87 {
88  return mStyles.keys();
89 }
90 
91 QMap<QString, QgsMapLayerStyle> QgsMapLayerStyleManager::mapLayerStyles() const
92 {
93  return mStyles;
94 }
95 
97 {
98  if ( name == mCurrentStyle )
99  {
100  // current style's entry is always kept invalid - get the style data from layer's properties
101  QgsMapLayerStyle curr;
102  curr.readFromLayer( mLayer );
103  return curr;
104  }
105 
106  return mStyles.value( name );
107 }
108 
109 bool QgsMapLayerStyleManager::addStyle( const QString &name, const QgsMapLayerStyle &style )
110 {
111  if ( mStyles.contains( name ) )
112  return false;
113  if ( !style.isValid() )
114  return false;
115 
116  mStyles.insert( name, style );
117  emit styleAdded( name );
118  return true;
119 }
120 
122 {
124  style.readFromLayer( mLayer );
125  return addStyle( name, style );
126 }
127 
128 bool QgsMapLayerStyleManager::removeStyle( const QString &name )
129 {
130  if ( !mStyles.contains( name ) )
131  return false;
132  if ( mStyles.count() == 1 )
133  return false; // cannot remove the last one
134 
135  // change to a different style if this one is the current
136  if ( mCurrentStyle == name )
137  {
138  QStringList keys = mStyles.keys();
139  QString newCurrent = keys[0];
140  if ( newCurrent == name )
141  newCurrent = keys[1]; // there must be at least one more
142  setCurrentStyle( newCurrent );
143  }
144 
145  mStyles.remove( name );
146  emit styleRemoved( name );
147  return true;
148 }
149 
150 bool QgsMapLayerStyleManager::renameStyle( const QString &name, const QString &newName )
151 {
152  if ( !mStyles.contains( name ) || mStyles.contains( newName ) )
153  return false;
154 
155  if ( name == mCurrentStyle )
156  mCurrentStyle = newName;
157 
158  mStyles[newName] = mStyles[name];
159  mStyles.remove( name );
160  emit styleRenamed( name, newName );
161  return true;
162 }
163 
165 {
166  return mCurrentStyle;
167 }
168 
169 bool QgsMapLayerStyleManager::setCurrentStyle( const QString &name )
170 {
171  if ( !mStyles.contains( name ) )
172  return false;
173 
174  if ( mCurrentStyle == name )
175  return true; // nothing to do
176 
177  mStyles[mCurrentStyle].readFromLayer( mLayer ); // sync before unloading it
178  mCurrentStyle = name;
179  mStyles[mCurrentStyle].writeToLayer( mLayer );
180  mStyles[mCurrentStyle].clear(); // current style does not keep any stored data
181  emit currentStyleChanged( mCurrentStyle );
182 
183  mLayer->triggerRepaint();
184  return true;
185 }
186 
187 bool QgsMapLayerStyleManager::setOverrideStyle( const QString &styleDef )
188 {
189  if ( mOverriddenOriginalStyle )
190  return false; // cannot override the style more than once!
191 
192  mLayer->blockSignals( true );
193  if ( mStyles.contains( styleDef ) )
194  {
195  mOverriddenOriginalStyle = new QgsMapLayerStyle;
196  mOverriddenOriginalStyle->readFromLayer( mLayer );
197 
198  // apply style name
199  mStyles[styleDef].writeToLayer( mLayer );
200  }
201  else if ( styleDef.startsWith( '<' ) )
202  {
203  mOverriddenOriginalStyle = new QgsMapLayerStyle;
204  mOverriddenOriginalStyle->readFromLayer( mLayer );
205 
206  // apply style XML
207  QgsMapLayerStyle overrideStyle( styleDef );
208  overrideStyle.writeToLayer( mLayer );
209  }
210  mLayer->blockSignals( false );
211 
212  return true;
213 }
214 
216 {
217  if ( !mOverriddenOriginalStyle )
218  return false;
219 
220  mLayer->blockSignals( true );
221  mOverriddenOriginalStyle->writeToLayer( mLayer );
222  mLayer->blockSignals( false );
223 
224  delete mOverriddenOriginalStyle;
225  mOverriddenOriginalStyle = nullptr;
226  return true;
227 }
228 
229 bool QgsMapLayerStyleManager::isDefault( const QString &styleName ) const
230 {
231  return styleName == defaultStyleName();
232 }
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 nullptr).
Base class for all map layer types.
Definition: qgsmaplayer.h:79
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.