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 }