QGIS API Documentation  2.8.6-Wien
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 
18 #include "qgslogger.h"
19 #include "qgsmaplayer.h"
20 
21 #include <QDomElement>
22 #include <QTextStream>
23 
25  : mLayer( layer )
26  , mOverriddenOriginalStyle( 0 )
27 {
28  reset();
29 }
30 
32 {
33  mStyles.insert( QString(), QgsMapLayerStyle() ); // insert entry for the default current style
34  mCurrentStyle.clear();
35 }
36 
37 void QgsMapLayerStyleManager::readXml( const QDomElement& mgrElement )
38 {
39  mCurrentStyle = mgrElement.attribute( "current" );
40 
41  mStyles.clear();
42  QDomElement ch = mgrElement.firstChildElement( "map-layer-style" );
43  while ( !ch.isNull() )
44  {
45  QString name = ch.attribute( "name" );
47  style.readXml( ch );
48  mStyles.insert( name, style );
49 
50  ch = ch.nextSiblingElement( "map-layer-style" );
51  }
52 }
53 
54 void QgsMapLayerStyleManager::writeXml( QDomElement& mgrElement ) const
55 {
56  QDomDocument doc = mgrElement.ownerDocument();
57  mgrElement.setAttribute( "current", mCurrentStyle );
58 
59  foreach ( const QString& name, styles() )
60  {
61  QDomElement ch = doc.createElement( "map-layer-style" );
62  ch.setAttribute( "name", name );
63  mStyles[name].writeXml( ch );
64  mgrElement.appendChild( ch );
65  }
66 }
67 
69 {
70  return mStyles.keys();
71 }
72 
74 {
75  if ( name == mCurrentStyle )
76  {
77  // current style's entry is always kept invalid - get the style data from layer's properties
78  QgsMapLayerStyle curr;
79  curr.readFromLayer( mLayer );
80  return curr;
81  }
82 
83  return mStyles.value( name );
84 }
85 
86 bool QgsMapLayerStyleManager::addStyle( const QString& name, const QgsMapLayerStyle& style )
87 {
88  if ( mStyles.contains( name ) )
89  return false;
90  if ( !style.isValid() )
91  return false;
92 
93  mStyles.insert( name, style );
94  emit styleAdded( name );
95  return true;
96 }
97 
98 bool QgsMapLayerStyleManager::addStyleFromLayer( const QString& name )
99 {
101  style.readFromLayer( mLayer );
102  return addStyle( name, style );
103 }
104 
105 bool QgsMapLayerStyleManager::removeStyle( const QString& name )
106 {
107  if ( !mStyles.contains( name ) )
108  return false;
109  if ( mStyles.count() == 1 )
110  return false; // cannot remove the last one
111 
112  // change to a different style if this one is the current
113  if ( mCurrentStyle == name )
114  {
115  QStringList keys = mStyles.keys();
116  QString newCurrent = keys[0];
117  if ( newCurrent == name )
118  newCurrent = keys[1]; // there must be at least one more
119  setCurrentStyle( newCurrent );
120  }
121 
122  mStyles.remove( name );
123  emit styleRemoved( name );
124  return true;
125 }
126 
127 bool QgsMapLayerStyleManager::renameStyle( const QString& name, const QString& newName )
128 {
129  if ( !mStyles.contains( name ) || mStyles.contains( newName ) )
130  return false;
131 
132  if ( name == mCurrentStyle )
133  mCurrentStyle = newName;
134 
135  mStyles[newName] = mStyles[name];
136  mStyles.remove( name );
137  emit styleRenamed( name, newName );
138  return true;
139 }
140 
142 {
143  return mCurrentStyle;
144 }
145 
146 bool QgsMapLayerStyleManager::setCurrentStyle( const QString& name )
147 {
148  if ( !mStyles.contains( name ) )
149  return false;
150 
151  if ( mCurrentStyle == name )
152  return true; // nothing to do
153 
154  mStyles[mCurrentStyle].readFromLayer( mLayer ); // sync before unloading it
155  mCurrentStyle = name;
156  mStyles[mCurrentStyle].writeToLayer( mLayer );
157  mStyles[mCurrentStyle].clear(); // current style does not keep any stored data
158  emit currentStyleChanged( mCurrentStyle );
159 
160  mLayer->triggerRepaint();
161  return true;
162 }
163 
164 bool QgsMapLayerStyleManager::setOverrideStyle( const QString& styleDef )
165 {
166  if ( mOverriddenOriginalStyle )
167  return false; // cannot override the style more than once!
168 
169  if ( mStyles.contains( styleDef ) )
170  {
171  mOverriddenOriginalStyle = new QgsMapLayerStyle;
172  mOverriddenOriginalStyle->readFromLayer( mLayer );
173 
174  // apply style name
175  mStyles[styleDef].writeToLayer( mLayer );
176  }
177  else if ( styleDef.startsWith( '<' ) )
178  {
179  mOverriddenOriginalStyle = new QgsMapLayerStyle;
180  mOverriddenOriginalStyle->readFromLayer( mLayer );
181 
182  // apply style XML
183  QgsMapLayerStyle overrideStyle( styleDef );
184  overrideStyle.writeToLayer( mLayer );
185  }
186 
187  return false;
188 }
189 
191 {
192  if ( !mOverriddenOriginalStyle )
193  return false;
194 
195  mOverriddenOriginalStyle->writeToLayer( mLayer );
196  delete mOverriddenOriginalStyle;
197  mOverriddenOriginalStyle = 0;
198  return true;
199 }
200 
201 
202 // -----
203 
205 {
206 }
207 
208 QgsMapLayerStyle::QgsMapLayerStyle( const QString& xmlData )
209  : mXmlData( xmlData )
210 {
211 }
212 
214 {
215  return !mXmlData.isEmpty();
216 }
217 
219 {
220  mXmlData.clear();
221 }
222 
224 {
225  return mXmlData;
226 }
227 
229 {
230  QString errorMsg;
231  QDomDocument doc;
232  layer->exportNamedStyle( doc, errorMsg );
233  if ( !errorMsg.isEmpty() )
234  {
235  QgsDebugMsg( "Failed to export style from layer: " + errorMsg );
236  return;
237  }
238 
239  mXmlData.clear();
240  QTextStream stream( &mXmlData );
241  doc.documentElement().save( stream, 0 );
242 }
243 
245 {
246  QDomDocument doc( "qgis" );
247  if ( !doc.setContent( mXmlData ) )
248  {
249  QgsDebugMsg( "Failed to parse XML of previously stored XML data - this should not happen!" );
250  return;
251  }
252 
253  QString errorMsg;
254  if ( !layer->importNamedStyle( doc, errorMsg ) )
255  {
256  QgsDebugMsg( "Failed to import style to layer: " + errorMsg );
257  }
258 }
259 
260 void QgsMapLayerStyle::readXml( const QDomElement& styleElement )
261 {
262  mXmlData.clear();
263  QTextStream stream( &mXmlData );
264  styleElement.firstChildElement().save( stream, 0 );
265 }
266 
267 void QgsMapLayerStyle::writeXml( QDomElement& styleElement ) const
268 {
269  // the currently selected style has no content stored here (layer has all the information inside)
270  if ( !isValid() )
271  return;
272 
273  QDomDocument docX;
274  docX.setContent( mXmlData );
275  styleElement.appendChild( docX.documentElement() );
276 }
bool restoreOverrideStyle()
Restore the original store after a call to setOverrideStyle()
void clear()
Remove any stored style data (will get invalid)
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:49
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)
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
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, transparency, labeling, diagrams etc.) applicable to a map layer...
bool removeStyle(const QString &name)
Remove a stored style.
void readXml(const QDomElement &mgrElement)
Read configuration (for project loading)
void styleRemoved(const QString &name)
Emitted when a style has been removed.
void triggerRepaint()
Will advice the map canvas (and any other interested party) that this layer requires to be repainted...
QString currentStyle() const
Return name of the current style.
virtual bool importNamedStyle(QDomDocument &doc, QString &errorMsg)
Import the properties of this layer from a QDomDocument.
bool addStyleFromLayer(const QString &name)
Add style by cloning the current one.
QString xmlData() const
Return XML content of the style.
QgsMapLayerStyle()
construct invalid style
bool isValid() const
Tell whether the style is valid (i.e. there is something stored in it)
QgsMapLayerStyle style(const QString &name) const
Return data of a stored style - accessed by its unique name.
virtual void exportNamedStyle(QDomDocument &doc, QString &errorMsg)
Export the properties of this layer as named style in a QDomDocument.
void writeXml(QDomElement &styleElement) const
Write style configuration (for project file writing)
bool renameStyle(const QString &name, const QString &newName)
Rename a stored style to a different name.
void writeToLayer(QgsMapLayer *layer) const
Apply stored layer&#39;s style information to the 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.
bool setCurrentStyle(const QString &name)
Set a different style as the current style - will apply it to the layer.
void writeXml(QDomElement &mgrElement) const
Write configuration (for project saving)
QStringList styles() const
Return list of all defined style names.