QGIS API Documentation  3.21.0-Master (5b68dc587e)
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  const 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 }
233 
235 {
236  const QStringList styleNames = other->mStyles.keys();
237 
238  for ( const QString &styleName : styleNames )
239  {
240  mStyles.remove( styleName );
241  addStyle( styleName, other->style( styleName ) );
242  }
243 }
Management of styles for use with one map layer.
bool addStyle(const QString &name, const QgsMapLayerStyle &style)
Add a style with given name and data.
QString currentStyle() const
Returns name of the current style.
bool removeStyle(const QString &name)
Remove a stored style.
void copyStylesFrom(QgsMapLayerStyleManager *other)
Copies all styles from other.
QStringList styles() const
Returns list of all defined style names.
bool setCurrentStyle(const QString &name)
Set a different style as the current style - will apply it to the layer.
void styleAdded(const QString &name)
Emitted when a new style has been added.
void writeXml(QDomElement &mgrElement) const
Write configuration (for project saving)
void reset()
Reset the style manager to a basic state - with one default style which is set as current.
bool isDefault(const QString &styleName) const
Returns true if this is the default style.
void styleRenamed(const QString &oldName, const QString &newName)
Emitted when a style has been renamed.
bool restoreOverrideStyle()
Restore the original store after a call to setOverrideStyle()
bool addStyleFromLayer(const QString &name)
Add style by cloning the current one.
bool renameStyle(const QString &name, const QString &newName)
Rename a stored style to a different name.
QgsMapLayerStyleManager(QgsMapLayer *layer)
Construct a style manager associated with a map layer (must not be nullptr).
QMap< QString, QgsMapLayerStyle > mapLayerStyles() const
Gets available styles for the associated map layer.
bool setOverrideStyle(const QString &styleDef)
Temporarily apply a different style to the layer.
QgsMapLayerStyle style(const QString &name) const
Returns data of a stored style - accessed by its unique name.
void readXml(const QDomElement &mgrElement)
Read configuration (for project loading)
void currentStyleChanged(const QString &currentName)
Emitted when the current style has been changed.
void styleRemoved(const QString &name)
Emitted when a style has been removed.
Stores style information (renderer, opacity, labeling, diagrams etc.) applicable to a map layer.
void readXml(const QDomElement &styleElement)
Read style configuration (for project file reading)
void readFromLayer(QgsMapLayer *layer)
Store layer's active style information in the instance.
void writeToLayer(QgsMapLayer *layer) const
Apply stored layer's style information to the layer.
bool isValid() const
Tell whether the style is valid (i.e. there is something stored in it)
Base class for all map layer types.
Definition: qgsmaplayer.h:73
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.