kspread

kspread_style_manager.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2003 Norbert Andres, nandres@web.de
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include <tqdom.h>
21#include <tqstringlist.h>
22
23#include <kdebug.h>
24#include <tdelocale.h>
25
26#include <KoOasisStyles.h>
27#include <KoXmlNS.h>
28
29#include "kspread_doc.h"
30#include "kspread_style.h"
31#include "kspread_style_manager.h"
32
33using namespace KSpread;
34
35StyleManager::StyleManager()
36 : m_defaultStyle( new CustomStyle() )
37{
38}
39
40StyleManager::~StyleManager()
41{
42 delete m_defaultStyle;
43
44 Styles::iterator iter = m_styles.begin();
45 Styles::iterator end = m_styles.end();
46
47 while ( iter != end )
48 {
49 delete iter.data();
50
51 ++iter;
52 }
53}
54
55void StyleManager::saveOasis( KoGenStyles &mainStyles )
56{
57 kdDebug() << "StyleManager: Saving default cell style" << endl;
58 KoGenStyle defaultStyle = KoGenStyle( Doc::STYLE_CELL_USER, "table-cell" );
59 m_defaultStyle->saveOasis( defaultStyle, mainStyles );
60
61 Styles::iterator iter = m_styles.begin();
62 Styles::iterator end = m_styles.end();
63
64 while ( iter != end )
65 {
66 kdDebug() << "StyleManager: Saving common cell style " << iter.key() <<endl;
67 CustomStyle * styleData = iter.data();
68
69 KoGenStyle customStyle = KoGenStyle( Doc::STYLE_CELL_USER, "table-cell" );
70 styleData->saveOasis( customStyle, mainStyles );
71
72 ++iter;
73 }
74}
75
76void StyleManager::loadOasisStyleTemplate( KoOasisStyles& oasisStyles )
77{
78 // reset the map of OpenDocument Styles
79 m_oasisStyles.clear();
80
81 // loading default style first
82 const TQDomElement* defaultStyle = oasisStyles.defaultStyle( "table-cell" );
83 if ( defaultStyle )
84 {
85 kdDebug() << "StyleManager: Loading default cell style" << endl;
86 m_defaultStyle->loadOasis( oasisStyles, *defaultStyle, "Default" );
87 m_defaultStyle->setType( Style::BUILTIN );
88 }
89 else
90 {
91 delete m_defaultStyle;
92 m_defaultStyle = new CustomStyle();
93 }
94 // insert it into the the map sorted the OpenDocument name
95 m_oasisStyles["Default"] = m_defaultStyle;
96
97 uint nStyles = oasisStyles.userStyles().count();
98 for (unsigned int item = 0; item < nStyles; item++) {
99 TQDomElement styleElem = oasisStyles.userStyles()[item];
100
101 // assume the name assigned by the application
102 const TQString oasisName = styleElem.attributeNS( KoXmlNS::style, "name", TQString() );
103
104 // then replace by user-visible one (if any)
105 const TQString name = styleElem.attributeNS( KoXmlNS::style, "display-name", oasisName );
106 kdDebug() << " StyleManager: Loading common cell style: " << oasisName << " (display name: " << name << ")" << endl;
107
108 if ( !name.isEmpty() )
109 {
110 CustomStyle * style = 0;
111 if ( styleElem.hasAttributeNS( KoXmlNS::style, "parent-style-name" ) )
112 // The style's parent name will be set in Style::loadOasis(..).
113 // After all styles are loaded the pointer to the parent is set.
114 style = new CustomStyle( name, 0 );
115 else
116 style = new CustomStyle( name, m_defaultStyle );
117
118 //fixme test return;
119 style->loadOasis( oasisStyles, styleElem, name );
120 m_styles[name] = style;
121 // insert it into the the map sorted the OpenDocument name
122 m_oasisStyles[oasisName] = style;
123 kdDebug() << "Style " << name << ": " << style << endl;
124 }
125 }
126
127 // set the parent pointers after we loaded all styles
128 Styles::iterator iter = m_styles.begin();
129 Styles::iterator end = m_styles.end();
130 while ( iter != end )
131 {
132 CustomStyle * styleData = iter.data();
133
134 if ( styleData->name() != "Default" )
135 if ( !styleData->parent() && !styleData->parentName().isNull() )
136 styleData->setParent( m_oasisStyles[ styleData->parentName() ] );
137
138 ++iter;
139 }
140}
141
142TQDomElement StyleManager::save( TQDomDocument & doc )
143{
144 kdDebug() << "Saving styles" << endl;
145 TQDomElement styles = doc.createElement( "styles" );
146
147 kdDebug() << "Saving default style" << endl;
148 m_defaultStyle->save( doc, styles );
149
150 Styles::iterator iter = m_styles.begin();
151 Styles::iterator end = m_styles.end();
152
153 while ( iter != end )
154 {
155 kdDebug() << "Saving style" << endl;
156 CustomStyle * styleData = iter.data();
157
158 styleData->save( doc, styles );
159
160 ++iter;
161 }
162
163 kdDebug() << "End saving styles" << endl;
164 return styles;
165}
166
167bool StyleManager::loadXML( TQDomElement const & styles )
168{
169 TQDomElement e = styles.firstChild().toElement();
170 while ( !e.isNull() )
171 {
172 TQString name;
173 if ( e.hasAttribute( "name" ) )
174 name = e.attribute( "name" );
175
176 if ( name == "Default" )
177 {
178 if ( !m_defaultStyle->loadXML( e, name ) )
179 return false;
180 m_defaultStyle->setType( Style::BUILTIN );
181 }
182 else if ( !name.isNull() )
183 {
184 CustomStyle * style = 0;
185 if ( e.hasAttribute( "parent" ) && e.attribute( "parent" ) == "Default" )
186 style = new CustomStyle( name, m_defaultStyle );
187 else
188 style = new CustomStyle( name, 0 );
189
190 if ( !style->loadXML( e, name ) )
191 {
192 delete style;
193 return false;
194 }
195
196 if ( style->type() == Style::AUTO )
197 style->setType( Style::CUSTOM );
198 m_styles[name] = style;
199 kdDebug() << "Style " << name << ": " << style << endl;
200 }
201
202 e = e.nextSibling().toElement();
203 }
204
205 Styles::iterator iter = m_styles.begin();
206 Styles::iterator end = m_styles.end();
207
208 while ( iter != end )
209 {
210 CustomStyle * styleData = iter.data();
211
212 if ( !styleData->parent() && !styleData->parentName().isNull() )
213 styleData->setParent( m_styles[ styleData->parentName() ] );
214
215 ++iter;
216 }
217
218 m_defaultStyle->setName( "Default" );
219 m_defaultStyle->setType( Style::BUILTIN );
220
221 return true;
222}
223
224void StyleManager::createBuiltinStyles()
225{
226 CustomStyle * header1 = new CustomStyle( i18n( "Header" ), m_defaultStyle );
227 TQFont f( header1->font() );
228 f.setItalic( true );
229 f.setPointSize( f.pointSize() + 2 );
230 f.setBold( true );
231 header1->changeFont( f );
232 header1->setType( Style::BUILTIN );
233 m_styles[ header1->name() ] = header1;
234
235 CustomStyle * header2 = new CustomStyle( i18n( "Header1" ), header1 );
236 TQColor color( "#F0F0FF" );
237 header2->changeBgColor( color );
238 TQPen pen( TQt::black, 1, TQt::SolidLine );
239 header2->changeBottomBorderPen( pen );
240 header2->setType( Style::BUILTIN );
241
242 m_styles[ header2->name() ] = header2;
243}
244
245CustomStyle * StyleManager::style( TQString const & name ) const
246{
247 Styles::const_iterator iter( m_styles.find( name ) );
248
249 if ( iter != m_styles.end() )
250 return iter.data();
251
252 if ( name == "Default" )
253 return m_defaultStyle;
254
255 return 0;
256}
257
258void StyleManager::takeStyle( CustomStyle * style )
259{
260 CustomStyle * parent = style->parent();
261
262 Styles::iterator iter = m_styles.begin();
263 Styles::iterator end = m_styles.end();
264
265 while ( iter != end )
266 {
267 if ( iter.data()->parent() == style )
268 iter.data()->setParent( parent );
269
270 ++iter;
271 }
272
273 Styles::iterator i( m_styles.find( style->name() ) );
274
275 if ( i != m_styles.end() )
276 {
277 kdDebug() << "Erasing style entry for " << style->name() << endl;
278 m_styles.erase( i );
279 }
280}
281
282bool StyleManager::checkCircle( TQString const & name, TQString const & parent )
283{
284 CustomStyle * s = style( parent );
285 if ( !s || s->parent() == 0 )
286 return true;
287 if ( s->parentName() == name )
288 return false;
289 else
290 return checkCircle( name, s->parentName() );
291}
292
293bool StyleManager::validateStyleName( TQString const & name, CustomStyle * style )
294{
295 if ( m_defaultStyle->name() == name || name == "Default" )
296 return false;
297
298 Styles::const_iterator iter = m_styles.begin();
299 Styles::const_iterator end = m_styles.end();
300
301 while ( iter != end )
302 {
303 if ( iter.key() == name && iter.data() != style )
304 return false;
305
306 ++iter;
307 }
308
309 return true;
310}
311
312void StyleManager::changeName( TQString const & oldName, TQString const & newName )
313{
314 Styles::iterator iter = m_styles.begin();
315 Styles::iterator end = m_styles.end();
316
317 while ( iter != end )
318 {
319 if ( iter.data()->parentName() == oldName )
320 iter.data()->refreshParentName();
321
322 ++iter;
323 }
324
325 iter = m_styles.find( oldName );
326 if ( iter != end )
327 {
328 CustomStyle * s = iter.data();
329 m_styles.erase( iter );
330 m_styles[newName] = s;
331 }
332}
333
334TQStringList StyleManager::styleNames() const
335{
336 TQStringList list;
337
338 list.push_back( i18n("Default") );
339
340 Styles::const_iterator iter = m_styles.begin();
341 Styles::const_iterator end = m_styles.end();
342
343 while ( iter != end )
344 {
345 list.push_back( iter.key() );
346
347 ++iter;
348 }
349
350 return list;
351}
352
353TQDict<Style> StyleManager::loadOasisAutoStyles( KoOasisStyles& oasisStyles )
354{
355 TQDictIterator<TQDomElement> it( oasisStyles.styles("table-cell") );
356 TQDict<Style> autoStyles;
357 for (;it.current();++it)
358 {
359 if ( it.current()->hasAttributeNS( KoXmlNS::style , "name" ) )
360 {
361 TQString name = it.current()->attributeNS( KoXmlNS::style , "name" , TQString() );
362 kdDebug() << "StyleManager: Preloading automatic cell style: " << name << endl;
363 autoStyles.insert( name , new Style());
364 autoStyles[name]->loadOasisStyle( oasisStyles , *(it.current()) );
365
366 if ( it.current()->hasAttributeNS( KoXmlNS::style, "parent-style-name" ) )
367 {
368 TQString parentStyleName = it.current()->attributeNS( KoXmlNS::style, "parent-style-name", TQString() );
369 if ( m_oasisStyles.contains( parentStyleName ) )
370 {
371 autoStyles[name]->setParent( m_oasisStyles[parentStyleName] );
372 }
373 kdDebug() << "\t parent-style-name:" << parentStyleName << endl;
374 }
375 else
376 {
377 autoStyles[name]->setParent( m_defaultStyle );
378 }
379 }
380 }
381 return autoStyles;
382}
383
384void StyleManager::releaseUnusedAutoStyles( TQDict<Style> autoStyles )
385{
386 TQDictIterator<Style> styleIt( autoStyles );
387 for (;styleIt.current();++styleIt)
388 {
389 Style* style = styleIt.current();
390 if (style->release())
391 delete style;
392 }
393
394 // Now, we can clear the map of styles sorted by OpenDocument name.
395 m_oasisStyles.clear();
396}
Built-in or custom style defined in StyleManager dialog.
virtual TQString saveOasis(KoGenStyle &style, KoGenStyles &mainStyles)
@ BUILTIN
built-in style (the default style)
@ AUTO
automatically generated on cell format changes
@ CUSTOM
custom style (defined in the StyleManager dialog)
The KSpread namespace.
Definition commands.h:39