QGIS API Documentation  2.8.2-Wien
 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 
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 }