lib

KoStyleStack.cpp
1/* This file is part of the KDE project
2 Copyright (c) 2003 Lukas Tinkl <lukas@kde.org>
3 Copyright (c) 2003 David Faure <faure@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19*/
20
21#include "KoStyleStack.h"
22#include "KoUnit.h"
23#include "KoDom.h"
24#include "KoXmlNS.h"
25
26#include <kdebug.h>
27
28//#define DEBUG_STYLESTACK
29
31 : m_styleNSURI( KoXmlNS::style ), m_foNSURI( KoXmlNS::fo )
32{
33 clear();
34}
35
36KoStyleStack::KoStyleStack( const char* styleNSURI, const char* foNSURI )
37 : m_propertiesTagName( "properties" ), m_styleNSURI( styleNSURI ), m_foNSURI( foNSURI )
38{
39 clear();
40}
41
42KoStyleStack::~KoStyleStack()
43{
44}
45
47{
48 m_stack.clear();
49#ifdef DEBUG_STYLESTACK
50 kdDebug(30003) << "clear!" << endl;
51#endif
52}
53
55{
56 m_marks.push( m_stack.count() );
57#ifdef DEBUG_STYLESTACK
58 kdDebug(30003) << "save (level " << m_marks.count() << ") -> index " << m_stack.count() << endl;
59#endif
60}
61
63{
64 Q_ASSERT( !m_marks.isEmpty() );
65 int toIndex = m_marks.pop();
66#ifdef DEBUG_STYLESTACK
67 kdDebug(30003) << "restore (level " << m_marks.count()+1 << ") -> to index " << toIndex << endl;
68#endif
69 Q_ASSERT( toIndex > -1 );
70 Q_ASSERT( toIndex <= (int)m_stack.count() ); // If equal, nothing to remove. If greater, bug.
71 for ( int index = (int)m_stack.count() - 1; index >= toIndex; --index )
72 m_stack.pop_back();
73}
74
76{
77 Q_ASSERT( !m_stack.isEmpty() );
78 m_stack.pop_back();
79#ifdef DEBUG_STYLESTACK
80 kdDebug(30003) << "pop -> count=" << m_stack.count() << endl;
81#endif
82}
83
84void KoStyleStack::push( const TQDomElement& style )
85{
86 m_stack.append( style );
87#ifdef DEBUG_STYLESTACK
88 kdDebug(30003) << "pushed " << style.attributeNS( m_styleNSURI, "name", TQString() ) << " -> count=" << m_stack.count() << endl;
89#endif
90}
91
92bool KoStyleStack::hasAttribute( const TQString& name, const TQString& detail ) const
93{
94 TQString fullName( name );
95 if ( !detail.isEmpty() )
96 {
97 fullName += '-';
98 fullName += detail;
99 }
100 TQValueList<TQDomElement>::ConstIterator it = m_stack.end();
101 while ( it != m_stack.begin() )
102 {
103 --it;
104 TQDomElement properties = (*it).namedItem( "style:"+m_propertiesTagName ).toElement();
105 if ( properties.hasAttribute( name ) ||
106 ( !detail.isEmpty() && properties.hasAttribute( fullName ) ) )
107 return true;
108 }
109 return false;
110}
111
112TQString KoStyleStack::attribute( const TQString& name, const TQString& detail ) const
113{
114 TQString fullName( name );
115 if ( !detail.isEmpty() )
116 {
117 fullName += '-';
118 fullName += detail;
119 }
120 TQValueList<TQDomElement>::ConstIterator it = m_stack.end();
121 while ( it != m_stack.begin() )
122 {
123 --it;
124 TQDomElement properties = (*it).namedItem( "style:"+m_propertiesTagName ).toElement();
125 if ( properties.hasAttribute( name ) )
126 return properties.attribute( name );
127 if ( !detail.isEmpty() && properties.hasAttribute( fullName ) )
128 return properties.attribute( fullName );
129 }
130 return TQString();
131}
132
133TQString KoStyleStack::attributeNS( const char* nsURI, const char* name, const char* detail ) const
134{
135 TQString fullName( name );
136 if ( detail )
137 {
138 fullName += '-';
139 fullName += detail;
140 }
141 TQValueList<TQDomElement>::ConstIterator it = m_stack.end();
142 while ( it != m_stack.begin() )
143 {
144 --it;
145 TQDomElement properties = KoDom::namedItemNS( *it, m_styleNSURI, m_propertiesTagName );
146 if ( properties.hasAttributeNS( nsURI, name ) )
147 return properties.attributeNS( nsURI, name, TQString() );
148 if ( detail && properties.hasAttributeNS( nsURI, fullName ) )
149 return properties.attributeNS( nsURI, fullName, TQString() );
150 }
151 return TQString();
152}
153
154bool KoStyleStack::hasAttributeNS( const char* nsURI, const char* name, const char* detail ) const
155{
156 TQString fullName( name );
157 if ( detail )
158 {
159 fullName += '-';
160 fullName += detail;
161 }
162 TQValueList<TQDomElement>::ConstIterator it = m_stack.end();
163 while ( it != m_stack.begin() )
164 {
165 --it;
166 TQDomElement properties = KoDom::namedItemNS( *it, m_styleNSURI, m_propertiesTagName );
167 if ( properties.hasAttributeNS( nsURI, name ) ||
168 ( detail && properties.hasAttributeNS( nsURI, fullName ) ) )
169 return true;
170 }
171 return false;
172}
173
174// Font size is a bit special. "115%" applies to "the fontsize of the parent style".
175// This can be generalized though (hasAttributeThatCanBePercentOfParent() ? :)
176// Although, if we also add support for fo:font-size-rel here then it's not general anymore.
178{
179 const TQString name = "font-size";
180 double percent = 1;
181 TQValueList<TQDomElement>::ConstIterator it = m_stack.end(); // reverse iterator
182
183 while ( it != m_stack.begin() )
184 {
185 --it;
186 TQDomElement properties = KoDom::namedItemNS( *it, m_styleNSURI, m_propertiesTagName ).toElement();
187 if ( properties.hasAttributeNS( m_foNSURI, name ) ) {
188 const TQString value = properties.attributeNS( m_foNSURI, name, TQString() );
189 if ( value.endsWith( "%" ) )
190 percent *= value.left( value.length() - 1 ).toDouble() / 100.0;
191 else
192 return percent * KoUnit::parseValue( value ); // e.g. 12pt
193 }
194 }
195 return 0;
196}
197
198bool KoStyleStack::hasChildNode(const TQString & name) const
199{
200 TQValueList<TQDomElement>::ConstIterator it = m_stack.end();
201 while ( it != m_stack.begin() )
202 {
203 --it;
204 TQDomElement properties = (*it).namedItem( "style:"+m_propertiesTagName ).toElement();
205 if ( !properties.namedItem( name ).isNull() )
206 return true;
207 }
208
209 return false;
210}
211
212TQDomElement KoStyleStack::childNode(const TQString & name) const
213{
214 TQValueList<TQDomElement>::ConstIterator it = m_stack.end();
215
216 while ( it != m_stack.begin() )
217 {
218 --it;
219 TQDomElement properties = (*it).namedItem( "style:"+m_propertiesTagName ).toElement();
220 if ( !properties.namedItem( name ).isNull() )
221 return properties.namedItem( name ).toElement();
222 }
223
224 return TQDomElement(); // a null element
225}
226
227bool KoStyleStack::hasChildNodeNS( const char* nsURI, const char* localName ) const
228{
229 TQValueList<TQDomElement>::ConstIterator it = m_stack.end();
230 while ( it != m_stack.begin() )
231 {
232 --it;
233 TQDomElement properties = KoDom::namedItemNS( *it, m_styleNSURI, m_propertiesTagName );
234 if ( !KoDom::namedItemNS( properties, nsURI, localName ).isNull() )
235 return true;
236 }
237
238 return false;
239}
240
241TQDomElement KoStyleStack::childNodeNS( const char* nsURI, const char* localName) const
242{
243 TQValueList<TQDomElement>::ConstIterator it = m_stack.end();
244
245 while ( it != m_stack.begin() )
246 {
247 --it;
248 TQDomElement properties = KoDom::namedItemNS( *it, m_styleNSURI, m_propertiesTagName );
249 TQDomElement e = KoDom::namedItemNS( properties, nsURI, localName );
250 if ( !e.isNull() )
251 return e;
252 }
253
254 return TQDomElement(); // a null element
255}
256
257bool KoStyleStack::isUserStyle( const TQDomElement& e, const TQString& family ) const
258{
259 if ( e.attributeNS( m_styleNSURI, "family", TQString() ) != family )
260 return false;
261 const TQDomElement parent = e.parentNode().toElement();
262 //kdDebug(30003) << k_funcinfo << "tagName=" << e.tagName() << " parent-tagName=" << parent.tagName() << endl;
263 return parent.localName() == "styles" /*&& parent.namespaceURI() == KoXmlNS::office*/;
264}
265
266TQString KoStyleStack::userStyleName( const TQString& family ) const
267{
268 TQValueList<TQDomElement>::ConstIterator it = m_stack.end();
269 while ( it != m_stack.begin() )
270 {
271 --it;
272 //kdDebug(30003) << k_funcinfo << (*it).attributeNS( m_styleNSURI, "name", TQString()) << endl;
273 if ( isUserStyle( *it, family ) )
274 return (*it).attributeNS( m_styleNSURI, "name", TQString() );
275 }
276 // Can this ever happen?
277 return "Standard";
278}
279
280TQString KoStyleStack::userStyleDisplayName( const TQString& family ) const
281{
282 TQValueList<TQDomElement>::ConstIterator it = m_stack.end();
283 while ( it != m_stack.begin() )
284 {
285 --it;
286 //kdDebug(30003) << k_funcinfo << (*it).attributeNS( m_styleNSURI, "display-name") << endl;
287 if ( isUserStyle( *it, family ) )
288 return (*it).attributeNS( m_styleNSURI, "display-name", TQString() );
289 }
290 return TQString(); // no display name, this can happen since it's optional
291}
292
293void KoStyleStack::setTypeProperties( const char* typeProperties )
294{
295 m_propertiesTagName = typeProperties == 0 ? TQCString( "properties" ) : ( TQCString( typeProperties ) + "-properties" );
296}
KoStyleStack()
Create a OASIS style stack.
bool hasAttributeNS(const char *nsURI, const char *localName, const char *detail=0) const
Check if any of the styles on the stack has an attribute called 'name'-'detail' where detail is e....
TQDomElement childNode(const TQString &name) const TDE_DEPRECATED
Search for a child node called 'name', starting on top of the stack, and return it.
void save()
Save the current state of the stack.
void clear()
Clears the complete stack.
TQDomElement childNodeNS(const char *nsURI, const char *localName) const
Search for a child element which has a child element called 'localName' in the namespace 'nsURI' star...
void setTypeProperties(const char *typeProperties)
Set the type of properties that will be looked for.
bool hasChildNode(const TQString &name) const TDE_DEPRECATED
Check if any of the styles on the stack has a child node called 'name'.
double fontSize() const
Special case for the current font size, due to special handling of fo:font-size="115%".
void push(const TQDomElement &style)
Pushes the new style onto the stack.
bool hasAttribute(const TQString &name, const TQString &detail=TQString()) const TDE_DEPRECATED
Check if any of the styles on the stack has an attribute called 'name'-'detail' where detail is e....
TQString attribute(const TQString &name, const TQString &detail=TQString()) const TDE_DEPRECATED
Search for the attribute called 'name', starting on top of the stack, and return it.
TQString attributeNS(const char *nsURI, const char *localName, const char *detail=0) const
Search for the attribute called 'name', starting on top of the stack, and return it.
bool hasChildNodeNS(const char *nsURI, const char *localName) const
Check if any of the styles on the stack has a child element called 'localName' in the namespace 'nsUR...
void pop()
Removes the style on top of the stack.
void restore()
Restore the stack to the state it was at the corresponding save() call.
TQString userStyleDisplayName(const TQString &family) const
Return the display name of the style specified by the user, i.e.
TQString userStyleName(const TQString &family) const
Return the name of the style specified by the user, i.e.
static double parseValue(TQString value, double defaultVal=0.0)
parse common KOffice and OO values, like "10cm", "5mm" to pt
Definition KoUnit.cpp:148
Repository of XML namespaces used for OASIS documents.
Definition KoXmlNS.h:29
KOFFICECORE_EXPORT TQDomElement namedItemNS(const TQDomNode &node, const char *nsURI, const char *localName)
A namespace-aware version of TQDomNode::namedItem(), which also takes care of casting to a TQDomEleme...
Definition KoDom.cpp:22