Warning, file /office/calligra/libs/odf/KoOdfStylesReader.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) 2004-2006 David Faure <faure@kde.org>
0003    Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
0004    Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
0005 
0006    This library is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU Library General Public
0008    License version 2 as published by the Free Software Foundation.
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 "KoOdfStylesReader.h"
0022 
0023 #include "KoXmlNS.h"
0024 #include "KoOdfNotesConfiguration.h"
0025 #include "KoOdfNumberDefinition.h"
0026 #include "KoOdfLineNumberingConfiguration.h"
0027 #include "KoOdfBibliographyConfiguration.h"
0028 
0029 #include <OdfDebug.h>
0030 
0031 class Q_DECL_HIDDEN KoOdfStylesReader::Private
0032 {
0033 public:
0034 
0035     Private()
0036         : globalFootnoteConfiguration(KoOdfNotesConfiguration::Footnote)
0037         , globalEndnoteConfiguration(KoOdfNotesConfiguration::Endnote)
0038     {
0039     }
0040 
0041     QHash < QString /*family*/, QHash < QString /*name*/, KoXmlElement* > > customStyles;
0042     // auto-styles in content.xml
0043     QHash < QString /*family*/, QHash < QString /*name*/, KoXmlElement* > > contentAutoStyles;
0044     // auto-styles in styles.xml
0045     QHash < QString /*family*/, QHash < QString /*name*/, KoXmlElement* > > stylesAutoStyles;
0046     QHash < QString /*family*/, KoXmlElement* > defaultStyles;
0047 
0048     QHash < QString /*name*/, KoXmlElement* > styles; // page-layout, font-face etc.
0049     QHash < QString /*name*/, KoXmlElement* > masterPages;
0050     QHash < QString /*name*/, KoXmlElement* > presentationPageLayouts;
0051     QHash < QString /*drawType*/, QHash< QString /*name*/, KoXmlElement* > > drawStyles;
0052 
0053     QList <KoXmlElement* > tableTemplates;
0054 
0055     KoXmlElement           officeStyle;
0056     KoXmlElement           layerSet;
0057 
0058     DataFormatsMap         dataFormats;
0059 
0060     // XXX: there can also be notes configuration objects _per_ section.
0061     KoOdfNotesConfiguration globalFootnoteConfiguration;
0062     KoOdfNotesConfiguration globalEndnoteConfiguration;
0063 
0064     KoOdfBibliographyConfiguration globalBibliographyConfiguration;
0065 
0066     KoOdfLineNumberingConfiguration lineNumberingConfiguration;
0067 
0068 };
0069 
0070 KoOdfStylesReader::KoOdfStylesReader()
0071     : d(new Private)
0072 {
0073 }
0074 
0075 KoOdfStylesReader::~KoOdfStylesReader()
0076 {
0077     typedef QHash<QString, KoXmlElement*> AutoStylesMap;
0078     foreach(const AutoStylesMap& map, d->customStyles)
0079         qDeleteAll(map);
0080     foreach(const AutoStylesMap& map, d->contentAutoStyles)
0081         qDeleteAll(map);
0082     foreach(const AutoStylesMap& map, d->stylesAutoStyles)
0083         qDeleteAll(map);
0084     foreach(const DataFormatsMap::mapped_type& dataFormat, d->dataFormats)
0085         delete dataFormat.second;
0086     qDeleteAll(d->defaultStyles);
0087     qDeleteAll(d->styles);
0088     qDeleteAll(d->masterPages);
0089     qDeleteAll(d->presentationPageLayouts);
0090     qDeleteAll(d->tableTemplates);
0091     foreach(const AutoStylesMap& map, d->drawStyles) {
0092         qDeleteAll(map);
0093     }
0094     delete d;
0095 }
0096 
0097 void KoOdfStylesReader::createStyleMap(const KoXmlDocument& doc, bool stylesDotXml)
0098 {
0099     const KoXmlElement docElement  = doc.documentElement();
0100     // We used to have the office:version check here, but better let the apps do that
0101     KoXmlElement fontStyles = KoXml::namedItemNS(docElement, KoXmlNS::office, "font-face-decls");
0102 
0103     if (!fontStyles.isNull()) {
0104         //debugOdf <<"Starting reading in font-face-decls...";
0105         insertStyles(fontStyles, stylesDotXml ? AutomaticInStyles : AutomaticInContent);
0106     }// else
0107     //   debugOdf <<"No items found";
0108 
0109     //debugOdf <<"Starting reading in office:automatic-styles. stylesDotXml=" << stylesDotXml;
0110 
0111     KoXmlElement autoStyles = KoXml::namedItemNS(docElement, KoXmlNS::office, "automatic-styles");
0112     if (!autoStyles.isNull()) {
0113         insertStyles(autoStyles, stylesDotXml ? AutomaticInStyles : AutomaticInContent);
0114     }// else
0115     //    debugOdf <<"No items found";
0116 
0117 
0118     //debugOdf <<"Reading in master styles";
0119 
0120     KoXmlNode masterStyles = KoXml::namedItemNS(docElement, KoXmlNS::office, "master-styles");
0121     if (!masterStyles.isNull()) {
0122         KoXmlElement master;
0123         forEachElement(master, masterStyles) {
0124             if (master.localName() == "master-page" &&
0125                 master.namespaceURI() == KoXmlNS::style) {
0126                 const QString name = master.attributeNS(KoXmlNS::style, "name", QString());
0127                 debugOdf << "Master style: '" << name << "' loaded";
0128                 d->masterPages.insert(name, new KoXmlElement(master));
0129             } else if (master.localName() == "layer-set" && master.namespaceURI() == KoXmlNS::draw) {
0130                 debugOdf << "Master style: layer-set loaded";
0131                 d->layerSet = master;
0132             } else
0133                 // OASIS docu mentions style:handout-master and draw:layer-set here
0134                 warnOdf << "Unknown tag " << master.tagName() << " in office:master-styles";
0135         }
0136     }
0137 
0138 
0139     debugOdf << "Starting reading in office:styles";
0140 
0141     const KoXmlElement officeStyle = KoXml::namedItemNS(docElement, KoXmlNS::office, "styles");
0142 
0143     if (!officeStyle.isNull()) {
0144         d->officeStyle = officeStyle;
0145         insertOfficeStyles(officeStyle);
0146     }
0147 
0148     //debugOdf <<"Styles read in.";
0149 }
0150 
0151 QHash<QString, KoXmlElement*> KoOdfStylesReader::customStyles(const QString& family) const
0152 {
0153     if (family.isNull())
0154         return QHash<QString, KoXmlElement*>();
0155     return d->customStyles.value(family);
0156 }
0157 
0158 QHash<QString, KoXmlElement*> KoOdfStylesReader::autoStyles(const QString& family, bool stylesDotXml) const
0159 {
0160     if (family.isNull())
0161         return QHash<QString, KoXmlElement*>();
0162     return stylesDotXml ? d->stylesAutoStyles.value(family) : d->contentAutoStyles.value(family);
0163 }
0164 
0165 KoOdfStylesReader::DataFormatsMap KoOdfStylesReader::dataFormats() const
0166 {
0167     return d->dataFormats;
0168 }
0169 
0170 KoOdfNotesConfiguration KoOdfStylesReader::globalNotesConfiguration(KoOdfNotesConfiguration::NoteClass noteClass) const
0171 {
0172     switch (noteClass) {
0173     case (KoOdfNotesConfiguration::Endnote):
0174         return d->globalEndnoteConfiguration;
0175     case (KoOdfNotesConfiguration::Footnote):
0176     default:
0177         return d->globalFootnoteConfiguration;
0178     }
0179 }
0180 
0181 KoOdfBibliographyConfiguration KoOdfStylesReader::globalBibliographyConfiguration() const
0182 {
0183     return d->globalBibliographyConfiguration;
0184 }
0185 
0186 KoOdfLineNumberingConfiguration KoOdfStylesReader::lineNumberingConfiguration() const
0187 {
0188     return d->lineNumberingConfiguration;
0189 }
0190 
0191 
0192 void KoOdfStylesReader::insertOfficeStyles(const KoXmlElement& styles)
0193 {
0194     KoXmlElement e;
0195     forEachElement(e, styles) {
0196         const QString localName = e.localName();
0197         const QString ns = e.namespaceURI();
0198         if ((ns == KoXmlNS::svg && (
0199                 localName == "linearGradient"
0200                 || localName == "radialGradient"))
0201             || (ns == KoXmlNS::draw && (
0202                     localName == "gradient"
0203                     || localName == "hatch"
0204                     || localName == "fill-image"
0205                     || localName == "marker"
0206                     || localName == "stroke-dash"
0207                     || localName == "opacity"))
0208             || (ns == KoXmlNS::calligra && (
0209                     localName == "conicalGradient"))
0210             ) {
0211             QString drawType = localName;
0212             if (drawType.endsWith(QLatin1String("Gradient"))) {
0213                 drawType = "gradient";
0214             }
0215             const QString name = e.attributeNS(KoXmlNS::draw, "name", QString());
0216             Q_ASSERT(!name.isEmpty());
0217             KoXmlElement* ep = new KoXmlElement(e);
0218             d->drawStyles[drawType].insert(name, ep);
0219         }else if(ns == KoXmlNS::table && localName == "table-template") {
0220             d->tableTemplates.append(new KoXmlElement(e));
0221         } else {
0222             insertStyle(e, CustomInStyles);
0223         }
0224     }
0225 }
0226 
0227 void KoOdfStylesReader::insertStyles(const KoXmlElement& styles, TypeAndLocation typeAndLocation)
0228 {
0229     //debugOdf <<"Inserting styles from" << styles.tagName();
0230     KoXmlElement e;
0231     forEachElement(e, styles)
0232             insertStyle(e, typeAndLocation);
0233 }
0234 
0235 void KoOdfStylesReader::insertStyle(const KoXmlElement& e, TypeAndLocation typeAndLocation)
0236 {
0237     const QString localName = e.localName();
0238     const QString ns = e.namespaceURI();
0239     const QString name = e.attributeNS(KoXmlNS::style, "name", QString());
0240 
0241     if ((ns == KoXmlNS::style && localName == "style")
0242         || (ns == KoXmlNS::text && localName == "list-style")) {
0243         const QString family = localName == "list-style" ? "list" : e.attributeNS(KoXmlNS::style, "family", QString());
0244 
0245         if (typeAndLocation == AutomaticInContent) {
0246             QHash<QString, KoXmlElement*>& dict = d->contentAutoStyles[ family ];
0247             if (dict.contains(name)) {
0248                 debugOdf << "Auto-style: '" << name << "' already exists";
0249                 delete dict.take(name);
0250             }
0251             dict.insert(name, new KoXmlElement(e));
0252             //debugOdf <<"Style: '" << name <<"' loaded as a style auto style";
0253         } else if (typeAndLocation == AutomaticInStyles) {
0254             QHash<QString, KoXmlElement*>& dict = d->stylesAutoStyles[ family ];
0255             if (dict.contains(name)) {
0256                 debugOdf << "Auto-style: '" << name << "' already exists";
0257                 delete dict.take(name);
0258             }
0259             dict.insert(name, new KoXmlElement(e));
0260             //debugOdf <<"Style: '" << name <<"' loaded as a style auto style";
0261         } else {
0262             QHash<QString, KoXmlElement*>& dict = d->customStyles[ family ];
0263             if (dict.contains(name)) {
0264                 debugOdf << "Style: '" << name << "' already exists";
0265                 delete dict.take(name);
0266             }
0267             dict.insert(name, new KoXmlElement(e));
0268             //debugOdf <<"Style: '" << name <<"' loaded";
0269         }
0270     } else if (ns == KoXmlNS::style && (
0271             localName == "page-layout"
0272             || localName == "font-face")) {
0273         if (d->styles.contains(name)) {
0274             debugOdf << "Style: '" << name << "' already exists";
0275             delete d->styles.take(name);
0276         }
0277         d->styles.insert(name, new KoXmlElement(e));
0278     } else if (localName == "presentation-page-layout" && ns == KoXmlNS::style) {
0279         if (d->presentationPageLayouts.contains(name)) {
0280             debugOdf << "Presentation page layout: '" << name << "' already exists";
0281             delete d->presentationPageLayouts.take(name);
0282         }
0283         d->presentationPageLayouts.insert(name, new KoXmlElement(e));
0284     } else if (localName == "default-style" && ns == KoXmlNS::style) {
0285         const QString family = e.attributeNS(KoXmlNS::style, "family", QString());
0286         if (!family.isEmpty())
0287             d->defaultStyles.insert(family, new KoXmlElement(e));
0288     } else if (ns == KoXmlNS::number && (
0289                    localName == "number-style"
0290                    || localName == "currency-style"
0291                    || localName == "percentage-style"
0292                    || localName == "boolean-style"
0293                    || localName == "text-style"
0294                    || localName == "date-style"
0295                    || localName == "time-style")) {
0296         QPair<QString, KoOdfNumberStyles::NumericStyleFormat> numberStyle = KoOdfNumberStyles::loadOdfNumberStyle(e);
0297         d->dataFormats.insert(numberStyle.first, qMakePair(numberStyle.second, new KoXmlElement(e)));
0298     } else if (ns == KoXmlNS::text && localName == "notes-configuration") {
0299         if (e.attributeNS(KoXmlNS::text, "note-class", "footnote") == "footnote") {
0300             d->globalFootnoteConfiguration.loadOdf(e);
0301         } else  {
0302             d->globalEndnoteConfiguration.loadOdf(e);
0303         }
0304     } else if (ns == KoXmlNS::text && localName == "linenumbering-configuration") {
0305         d->lineNumberingConfiguration.loadOdf(e);
0306     } else if (ns == KoXmlNS::text && localName == "bibliography-configuration") {
0307         KoOdfBibliographyConfiguration bibConfiguration;
0308         bibConfiguration.loadOdf(e);
0309         d->globalBibliographyConfiguration = bibConfiguration;
0310     }
0311 }
0312 
0313 KoXmlElement *KoOdfStylesReader::defaultStyle(const QString &family) const
0314 {
0315     return d->defaultStyles[family];
0316 }
0317 
0318 KoXmlElement KoOdfStylesReader::officeStyle() const
0319 {
0320     return d->officeStyle;
0321 }
0322 
0323 KoXmlElement KoOdfStylesReader::layerSet() const
0324 {
0325     return d->layerSet;
0326 }
0327 
0328 QHash<QString, KoXmlElement*> KoOdfStylesReader::masterPages() const
0329 {
0330     return d->masterPages;
0331 }
0332 
0333 QHash<QString, KoXmlElement*> KoOdfStylesReader::presentationPageLayouts() const
0334 {
0335     return d->presentationPageLayouts;
0336 }
0337 
0338 QHash<QString, KoXmlElement*> KoOdfStylesReader::drawStyles(const QString &drawType) const
0339 {
0340     return d->drawStyles.value(drawType);
0341 }
0342 
0343 const KoXmlElement* KoOdfStylesReader::findStyle(const QString& name) const
0344 {
0345     return d->styles[ name ];
0346 }
0347 
0348 const KoXmlElement* KoOdfStylesReader::findStyle(const QString& styleName, const QString& family) const
0349 {
0350     const KoXmlElement* style = findStyleCustomStyle(styleName, family);
0351     if (!style)
0352         style = findAutoStyleStyle(styleName, family);
0353     if (!style)
0354         style = findContentAutoStyle(styleName, family);
0355     return style;
0356 }
0357 
0358 const KoXmlElement* KoOdfStylesReader::findStyle(const QString& styleName, const QString& family, bool stylesDotXml) const
0359 {
0360     const KoXmlElement* style = findStyleCustomStyle(styleName, family);
0361     if (!style && !stylesDotXml) {
0362         style = findContentAutoStyle(styleName, family);
0363     }
0364     if (!style && stylesDotXml) {
0365         style = findAutoStyleStyle(styleName, family);
0366     }
0367     return style;
0368 
0369 }
0370 
0371 const KoXmlElement* KoOdfStylesReader::findStyleCustomStyle(const QString& styleName, const QString& family) const
0372 {
0373     const KoXmlElement* style = d->customStyles.value(family).value(styleName);
0374     if (style && !family.isEmpty()) {
0375         const QString styleFamily = style->attributeNS(KoXmlNS::style, "family", QString());
0376         if (styleFamily != family) {
0377             warnOdf << "KoOdfStylesReader: was looking for style " << styleName
0378                     << " in family " << family << " but got " << styleFamily << endl;
0379         }
0380     }
0381     return style;
0382 }
0383 
0384 const KoXmlElement* KoOdfStylesReader::findAutoStyleStyle(const QString& styleName, const QString& family) const
0385 {
0386     const KoXmlElement* style = d->stylesAutoStyles.value(family).value(styleName);
0387     if (style) {
0388         const QString styleFamily = style->attributeNS(KoXmlNS::style, "family", QString());
0389         if (styleFamily != family) {
0390             warnOdf << "KoOdfStylesReader: was looking for style " << styleName
0391                     << " in family " << family << " but got " << styleFamily << endl;
0392         }
0393     }
0394     return style;
0395 }
0396 
0397 const KoXmlElement* KoOdfStylesReader::findContentAutoStyle(const QString& styleName, const QString& family) const
0398 {
0399     const KoXmlElement* style = d->contentAutoStyles.value(family).value(styleName);
0400     if (style) {
0401         const QString styleFamily = style->attributeNS(KoXmlNS::style, "family", QString());
0402         if (styleFamily != family) {
0403             warnOdf << "KoOdfStylesReader: was looking for style " << styleName
0404                     << " in family " << family << " but got " << styleFamily << endl;
0405         }
0406     }
0407     return style;
0408 }
0409 
0410 QList<KoXmlElement*> KoOdfStylesReader::tableTemplates() const
0411 {
0412     return d->tableTemplates;
0413 }