Warning, file /office/calligra/libs/odf/KoStyleStack.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* This file is part of the KDE project 0002 Copyright (c) 2003 Lukas Tinkl <lukas@kde.org> 0003 Copyright (c) 2003 David Faure <faure@kde.org> 0004 0005 This library is free software; you can redistribute it and/or 0006 modify it under the terms of the GNU Library General Public 0007 License as published by the Free Software Foundation; either 0008 version 2 of the License, or (at your option) any later version. 0009 0010 This library is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 Library General Public License for more details. 0014 0015 You should have received a copy of the GNU Library General Public License 0016 along with this library; see the file COPYING.LIB. If not, write to 0017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 * Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #include "KoStyleStack.h" 0022 #include "KoUnit.h" 0023 #include "KoXmlNS.h" 0024 0025 #include <OdfDebug.h> 0026 0027 //#define DEBUG_STYLESTACK 0028 0029 class KoStyleStack::KoStyleStackPrivate 0030 { 0031 }; 0032 0033 KoStyleStack::KoStyleStack() 0034 : m_styleNSURI(KoXmlNS::style), m_foNSURI(KoXmlNS::fo), d(0) 0035 { 0036 clear(); 0037 } 0038 0039 KoStyleStack::KoStyleStack(const char* styleNSURI, const char* foNSURI) 0040 : m_styleNSURI(styleNSURI), m_foNSURI(foNSURI), d(0) 0041 { 0042 m_propertiesTagNames.append("properties"); 0043 clear(); 0044 } 0045 0046 KoStyleStack::~KoStyleStack() 0047 { 0048 delete d; 0049 } 0050 0051 void KoStyleStack::clear() 0052 { 0053 m_stack.clear(); 0054 #ifdef DEBUG_STYLESTACK 0055 debugOdf << "clear!"; 0056 #endif 0057 } 0058 0059 void KoStyleStack::save() 0060 { 0061 m_marks.push(m_stack.count()); 0062 #ifdef DEBUG_STYLESTACK 0063 debugOdf << "save (level" << m_marks.count() << ") -> index" << m_stack.count(); 0064 #endif 0065 } 0066 0067 void KoStyleStack::restore() 0068 { 0069 Q_ASSERT(!m_marks.isEmpty()); 0070 int toIndex = m_marks.pop(); 0071 #ifdef DEBUG_STYLESTACK 0072 debugOdf << "restore (level" << m_marks.count() + 1 << ") -> to index" << toIndex; 0073 #endif 0074 Q_ASSERT(toIndex > -1); 0075 Q_ASSERT(toIndex <= (int)m_stack.count()); // If equal, nothing to remove. If greater, bug. 0076 for (int index = (int)m_stack.count() - 1; index >= toIndex; --index) 0077 m_stack.pop_back(); 0078 } 0079 0080 void KoStyleStack::pop() 0081 { 0082 Q_ASSERT(!m_stack.isEmpty()); 0083 m_stack.pop_back(); 0084 #ifdef DEBUG_STYLESTACK 0085 debugOdf << "pop -> count=" << m_stack.count(); 0086 #endif 0087 } 0088 0089 void KoStyleStack::push(const KoXmlElement& style) 0090 { 0091 m_stack.append(style); 0092 #ifdef DEBUG_STYLESTACK 0093 debugOdf << "pushed" << style.attributeNS(m_styleNSURI, "name", QString()) << " -> count=" << m_stack.count(); 0094 #endif 0095 } 0096 0097 QString KoStyleStack::property(const QString &nsURI, const QString &name) const 0098 { 0099 return property(nsURI, name, 0); 0100 } 0101 QString KoStyleStack::property(const QString &nsURI, const QString &name, const QString &detail) const 0102 { 0103 return property(nsURI, name, &detail); 0104 } 0105 0106 inline QString KoStyleStack::property(const QString &nsURI, const QString &name, const QString *detail) const 0107 { 0108 QString fullName(name); 0109 if (detail) { 0110 fullName += '-' + *detail; 0111 } 0112 QList<KoXmlElement>::ConstIterator it = m_stack.end(); 0113 while (it != m_stack.begin()) { 0114 --it; 0115 foreach (const QString &propertyTagName, m_propertiesTagNames) { 0116 KoXmlElement properties = KoXml::namedItemNS(*it, m_styleNSURI, propertyTagName); 0117 if (detail) { 0118 QString attribute(properties.attributeNS(nsURI, fullName)); 0119 if (!attribute.isEmpty()) { 0120 return attribute; 0121 } 0122 } 0123 QString attribute(properties.attributeNS(nsURI, name)); 0124 if (!attribute.isEmpty()) { 0125 return attribute; 0126 } 0127 } 0128 } 0129 return QString(); 0130 } 0131 0132 bool KoStyleStack::hasProperty(const QString &nsURI, const QString &name) const 0133 { 0134 return hasProperty(nsURI, name, 0); 0135 } 0136 0137 bool KoStyleStack::hasProperty(const QString &nsURI, const QString &name, const QString &detail) const 0138 { 0139 return hasProperty(nsURI, name, &detail); 0140 } 0141 0142 inline bool KoStyleStack::hasProperty(const QString &nsURI, const QString &name, const QString *detail) const 0143 { 0144 QString fullName(name); 0145 if (detail) { 0146 fullName += '-' + *detail; 0147 } 0148 QList<KoXmlElement>::ConstIterator it = m_stack.end(); 0149 while (it != m_stack.begin()) { 0150 --it; 0151 foreach (const QString &propertiesTagName, m_propertiesTagNames) { 0152 const KoXmlElement properties = KoXml::namedItemNS(*it, m_styleNSURI, propertiesTagName); 0153 if (properties.hasAttributeNS(nsURI, name) || 0154 (detail && properties.hasAttributeNS(nsURI, fullName))) 0155 return true; 0156 } 0157 } 0158 return false; 0159 } 0160 0161 // Font size is a bit special. "115%" applies to "the fontsize of the parent style". 0162 // This can be generalized though (hasPropertyThatCanBePercentOfParent() ? :) 0163 QPair<qreal,qreal> KoStyleStack::fontSize(const qreal defaultFontPointSize) const 0164 { 0165 const QString name = "font-size"; 0166 qreal percent = 100; 0167 QList<KoXmlElement>::ConstIterator it = m_stack.end(); // reverse iterator 0168 0169 while (it != m_stack.begin()) { 0170 --it; 0171 foreach (const QString &propertiesTagName, m_propertiesTagNames) { 0172 KoXmlElement properties = KoXml::namedItemNS(*it, m_styleNSURI, propertiesTagName).toElement(); 0173 if (properties.hasAttributeNS(m_foNSURI, name)) { 0174 const QString value = properties.attributeNS(m_foNSURI, name, QString()); 0175 if (value.endsWith('%')) { 0176 //sebsauer, 20070609, the specs don't say that we have to calc them together but 0177 //just that we are looking for a valid parent fontsize. So, let's only take the 0178 //first percent definition into account and keep on to seek for a valid parent, 0179 //percent *= value.left( value.length() - 1 ).toDouble() / 100.0; 0180 if (percent == 100) 0181 percent = value.leftRef(value.length() - 1).toDouble(); 0182 } else { 0183 // e.g. 12pt and indicate that there was not percentage there 0184 return QPair<qreal,qreal> ((percent * KoUnit::parseValue(value))/100.0, 0.0); 0185 } 0186 break; 0187 } 0188 } 0189 } 0190 0191 //if there was no valid parent, we return the default fontsize together with an optional calculated percent-value. 0192 return QPair<qreal,qreal> ((percent * defaultFontPointSize)/100.0, percent); 0193 } 0194 0195 bool KoStyleStack::hasChildNode(const QString &nsURI, const QString &localName) const 0196 { 0197 QList<KoXmlElement>::ConstIterator it = m_stack.end(); 0198 while (it != m_stack.begin()) { 0199 --it; 0200 foreach (const QString &propertiesTagName, m_propertiesTagNames) { 0201 KoXmlElement properties = KoXml::namedItemNS(*it, m_styleNSURI, propertiesTagName); 0202 if (!KoXml::namedItemNS(properties, nsURI, localName).isNull()) 0203 return true; 0204 } 0205 } 0206 0207 return false; 0208 } 0209 0210 KoXmlElement KoStyleStack::childNode(const QString &nsURI, const QString &localName) const 0211 { 0212 QList<KoXmlElement>::ConstIterator it = m_stack.end(); 0213 0214 while (it != m_stack.begin()) { 0215 --it; 0216 foreach (const QString &propertiesTagName, m_propertiesTagNames) { 0217 KoXmlElement properties = KoXml::namedItemNS(*it, m_styleNSURI, propertiesTagName); 0218 KoXmlElement e = KoXml::namedItemNS(properties, nsURI, localName); 0219 if (!e.isNull()) 0220 return e; 0221 } 0222 } 0223 0224 return KoXmlElement(); // a null element 0225 } 0226 0227 bool KoStyleStack::isUserStyle(const KoXmlElement& e, const QString& family) const 0228 { 0229 if (e.attributeNS(m_styleNSURI, "family", QString()) != family) 0230 return false; 0231 const KoXmlElement parent = e.parentNode().toElement(); 0232 //debugOdf <<"tagName=" << e.tagName() <<" parent-tagName=" << parent.tagName(); 0233 return parent.localName() == "styles" /*&& parent.namespaceURI() == KoXmlNS::office*/; 0234 } 0235 0236 QString KoStyleStack::userStyleName(const QString& family) const 0237 { 0238 QList<KoXmlElement>::ConstIterator it = m_stack.end(); 0239 while (it != m_stack.begin()) { 0240 --it; 0241 //debugOdf << (*it).attributeNS( m_styleNSURI,"name", QString()); 0242 if (isUserStyle(*it, family)) 0243 return (*it).attributeNS(m_styleNSURI, "name", QString()); 0244 } 0245 // Can this ever happen? 0246 return "Standard"; 0247 } 0248 0249 QString KoStyleStack::userStyleDisplayName(const QString& family) const 0250 { 0251 QList<KoXmlElement>::ConstIterator it = m_stack.end(); 0252 while (it != m_stack.begin()) { 0253 --it; 0254 //debugOdf << (*it).attributeNS( m_styleNSURI,"display-name"); 0255 if (isUserStyle(*it, family)) 0256 return (*it).attributeNS(m_styleNSURI, "display-name", QString()); 0257 } 0258 return QString(); // no display name, this can happen since it's optional 0259 } 0260 0261 void KoStyleStack::setTypeProperties(const char* typeProperties) 0262 { 0263 m_propertiesTagNames.clear(); 0264 m_propertiesTagNames.append(typeProperties == 0 || qstrlen(typeProperties) == 0 ? QString("properties") : (QString(typeProperties) + "-properties")); 0265 } 0266 0267 void KoStyleStack::setTypeProperties(const QList<QString> &typeProperties) 0268 { 0269 m_propertiesTagNames.clear(); 0270 foreach (const QString &typeProperty, typeProperties) { 0271 if (!typeProperty.isEmpty()) { 0272 m_propertiesTagNames.append(typeProperty + "-properties"); 0273 } 0274 } 0275 if (m_propertiesTagNames.empty()) { 0276 m_propertiesTagNames.append("properties"); 0277 } 0278 }