QGIS API Documentation  2.10.1-Pisa
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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 
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 
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 
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 
99 {
101  style.readFromLayer( mLayer );
102  return addStyle( name, style );
103 }
104 
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 
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 
165 {
166  if ( mOverriddenOriginalStyle )
167  return false; // cannot override the style more than once!
168 
169  mLayer->blockSignals( true );
170  if ( mStyles.contains( styleDef ) )
171  {
172  mOverriddenOriginalStyle = new QgsMapLayerStyle;
173  mOverriddenOriginalStyle->readFromLayer( mLayer );
174 
175  // apply style name
176  mStyles[styleDef].writeToLayer( mLayer );
177  }
178  else if ( styleDef.startsWith( '<' ) )
179  {
180  mOverriddenOriginalStyle = new QgsMapLayerStyle;
181  mOverriddenOriginalStyle->readFromLayer( mLayer );
182 
183  // apply style XML
184  QgsMapLayerStyle overrideStyle( styleDef );
185  overrideStyle.writeToLayer( mLayer );
186  }
187  mLayer->blockSignals( false );
188 
189  return true;
190 }
191 
193 {
194  if ( !mOverriddenOriginalStyle )
195  return false;
196 
197  mLayer->blockSignals( true );
198  mOverriddenOriginalStyle->writeToLayer( mLayer );
199  mLayer->blockSignals( false );
200 
201  delete mOverriddenOriginalStyle;
202  mOverriddenOriginalStyle = 0;
203  return true;
204 }
205 
206 
207 // -----
208 
210 {
211 }
212 
214  : mXmlData( xmlData )
215 {
216 }
217 
219 {
220  return !mXmlData.isEmpty();
221 }
222 
224 {
225  mXmlData.clear();
226 }
227 
229 {
230  return mXmlData;
231 }
232 
234 {
235  QString errorMsg;
236  QDomDocument doc;
237  layer->exportNamedStyle( doc, errorMsg );
238  if ( !errorMsg.isEmpty() )
239  {
240  QgsDebugMsg( "Failed to export style from layer: " + errorMsg );
241  return;
242  }
243 
244  mXmlData.clear();
245  QTextStream stream( &mXmlData );
246  doc.documentElement().save( stream, 0 );
247 }
248 
250 {
251  QDomDocument doc( "qgis" );
252  if ( !doc.setContent( mXmlData ) )
253  {
254  QgsDebugMsg( "Failed to parse XML of previously stored XML data - this should not happen!" );
255  return;
256  }
257 
258  QString errorMsg;
259  if ( !layer->importNamedStyle( doc, errorMsg ) )
260  {
261  QgsDebugMsg( "Failed to import style to layer: " + errorMsg );
262  }
263 }
264 
265 void QgsMapLayerStyle::readXml( const QDomElement& styleElement )
266 {
267  mXmlData.clear();
268  QTextStream stream( &mXmlData );
269  styleElement.firstChildElement().save( stream, 0 );
270 }
271 
272 void QgsMapLayerStyle::writeXml( QDomElement& styleElement ) const
273 {
274  // the currently selected style has no content stored here (layer has all the information inside)
275  if ( !isValid() )
276  return;
277 
278  QDomDocument docX;
279  docX.setContent( mXmlData );
280  styleElement.appendChild( docX.documentElement() );
281 }
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.
bool contains(const Key &key) const
QDomNode appendChild(const QDomNode &newChild)
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)
QString attribute(const QString &name, const QString &defValue) const
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
QDomElement nextSiblingElement(const QString &tagName) const
QDomElement documentElement() const
void clear()
void clear()
void styleAdded(const QString &name)
Emitted when a new style has been added.
void readFromLayer(QgsMapLayer *layer)
Store layer's active style information in the instance.
QList< Key > keys() const
Stores style information (renderer, transparency, labeling, diagrams etc.) applicable to a map layer...
const char * name() const
bool removeStyle(const QString &name)
Remove a stored style.
QDomDocument ownerDocument() const
void setAttribute(const QString &name, const QString &value)
void readXml(const QDomElement &mgrElement)
Read configuration (for project loading)
bool isEmpty() const
void styleRemoved(const QString &name)
Emitted when a style has been removed.
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
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.
bool blockSignals(bool block)
QString xmlData() const
Return XML content of the style.
QgsMapLayerStyle()
construct invalid style
bool isNull() const
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 save(QTextStream &str, int indent) const
QDomElement firstChildElement(const QString &tagName) const
void writeToLayer(QgsMapLayer *layer) const
Apply stored layer's style information to the layer.
iterator insert(const Key &key, const T &value)
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.
QDomElement createElement(const QString &tagName)
int count(const Key &key) const
bool setCurrentStyle(const QString &name)
Set a different style as the current style - will apply it to the layer.
bool setContent(const QByteArray &data, bool namespaceProcessing, QString *errorMsg, int *errorLine, int *errorColumn)
const T value(const Key &key) const
int remove(const Key &key)
void writeXml(QDomElement &mgrElement) const
Write configuration (for project saving)
QStringList styles() const
Return list of all defined style names.