File indexing completed on 2024-12-08 12:56:11

0001 /* This file is part of the KDE project
0002  *
0003  * Copyright (C) 2013 Inge Wallin <inge@lysator.liu.se>
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 // Own
0022 #include "KoOdfStyleManager.h"
0023 
0024 // Qt
0025 #include <QHash>
0026 #include <QString>
0027 #include <QPair>
0028 
0029 // odf lib
0030 #include "KoStore.h"
0031 #include <KoXmlStreamReader.h>
0032 #include <KoXmlNS.h>
0033 #include <KoXmlWriter.h>
0034 
0035 #include "KoOdfStyle.h"
0036 #include "KoOdfListStyle.h"
0037 #include "Odf2Debug.h"
0038 
0039 
0040 // ================================================================
0041 //                 class KoOdfStyleManager
0042 
0043 
0044 class Q_DECL_HIDDEN KoOdfStyleManager::Private
0045 {
0046 public:
0047     Private() {};
0048 
0049     QHash<QPair<QString, QString>, KoOdfStyle*> styles;         // <name, family>, style
0050     QHash<QString, KoOdfStyle*> defaultStyles;  // family, style
0051     QHash<QString, KoOdfListStyle*> listStyles; // list-style styles
0052 };
0053 
0054 
0055 // ----------------------------------------------------------------
0056 
0057 
0058 KoOdfStyleManager::KoOdfStyleManager()
0059     : d(new KoOdfStyleManager::Private())
0060 {
0061 }
0062 
0063 KoOdfStyleManager::~KoOdfStyleManager()
0064 {
0065     delete d;
0066 }
0067 
0068 KoOdfStyle *KoOdfStyleManager::style(const QString &name, const QString &family) const
0069 {
0070     debugOdf2 << d->styles.value(qMakePair(name, family), 0);
0071     return d->styles.value(qMakePair(name, family), 0);
0072 }
0073 
0074 void KoOdfStyleManager::setStyle(const QString &name, KoOdfStyle *style)
0075 {
0076     d->styles.insert(qMakePair(name, style->family()), style);
0077 }
0078 
0079 KoOdfListStyle *KoOdfStyleManager::listStyle(const QString &name) const
0080 {
0081     return d->listStyles.value(name, 0);
0082 }
0083 
0084 void KoOdfStyleManager::setListStyle(const QString &name, KoOdfListStyle *style)
0085 {
0086     d->listStyles.insert(name, style);
0087 }
0088 
0089 
0090 KoOdfStyle *KoOdfStyleManager::defaultStyle(const QString &family) const
0091 {
0092     return d->defaultStyles.value(family, 0);
0093 }
0094 
0095 void KoOdfStyleManager::setDefaultStyle(const QString &family, KoOdfStyle *style)
0096 {
0097     d->defaultStyles.insert(family, style);
0098 }
0099 
0100 QList<KoOdfStyle*> KoOdfStyleManager::styles() const
0101 {
0102     return d->styles.values();
0103 }
0104 
0105 QList<KoOdfStyle*> KoOdfStyleManager::defaultStyles() const
0106 {
0107     return d->defaultStyles.values();
0108 }
0109 
0110 void KoOdfStyleManager::clear()
0111 {
0112     // The style manager owns the styles so we should delete them, not
0113     // just empty the lists.
0114     qDeleteAll(d->styles);
0115     d->styles.clear();
0116 
0117     qDeleteAll(d->defaultStyles);
0118     d->defaultStyles.clear();
0119 }
0120 
0121 
0122 // ----------------------------------------------------------------
0123 
0124 
0125 bool KoOdfStyleManager::loadStyles(KoStore *odfStore)
0126 {
0127     QString errorMsg;
0128     //int errorLine;
0129     //int errorColumn;
0130 
0131     KoXmlStreamReader reader;
0132     prepareForOdf(reader);
0133 
0134     // ----------------------------------------------------------------
0135     // Get styles from styles.xml.
0136 
0137     debugOdf2 << "================================================================\n"
0138              << "Loading styles from styles.xml";
0139 
0140     // Try to open and set styles.xml as a KoXmlDocument. Return if it failed.
0141     if (!odfStore->open("styles.xml")) {
0142         errorOdf2 << "Unable to open input file styles.xml" << endl;
0143         return false;
0144     }
0145 
0146     reader.setDevice(odfStore->device());
0147     // FIXME: Error handling
0148 
0149     // Collect the styles.
0150     collectStyleSet(reader, true /*fromStylesXml*/);
0151     odfStore->close();
0152 
0153     // ----------------------------------------------------------------
0154     // Get styles from content.xml.
0155 
0156     // Try to open content.xml. Return if it failed.
0157     //debugOdf2 << "parse content.xml styles";
0158     if (!odfStore->open("content.xml")) {
0159         errorOdf2 << "Unable to open input file content.xml" << endl;
0160         return false;
0161     }
0162 
0163     debugOdf2 << "================================================================\n"
0164              << "Loading styles from content.xml";
0165 
0166     reader.setDevice(odfStore->device());
0167     // FIXME: Error handling
0168 
0169     // Collect the styles.
0170     collectStyleSet(reader, false /*!fromStylesXml*/);
0171 
0172     odfStore->close(); // end of parsing styles in content.xml
0173 
0174     return true;
0175 }
0176 
0177 void KoOdfStyleManager::collectStyleSet(KoXmlStreamReader &reader, bool fromStylesXml)
0178 {
0179     debugOdf2 << "incoming element:" << reader.qualifiedName().toString();
0180 
0181     while (!reader.atEnd() && !reader.isEndDocument ()) {
0182         reader.readNext();
0183         if (!reader.isStartElement()) {
0184             continue;
0185         }
0186         debugOdf2 << "---------------- style element:" << reader.qualifiedName().toString();
0187         QString tagName = reader.qualifiedName().toString();
0188 
0189             if (tagName == "office:styles"
0190                 || tagName == "office:automatic-styles"
0191                 || tagName == "office:document-content"
0192                 || tagName == "office:document-styles")
0193             {
0194                 continue;
0195             }
0196 
0197             // For now: handle style:style and style:default-style and text:list-style
0198             // and only the text, paragraph and graphic families.
0199             if (tagName != "style:style" && tagName != "style:default-style" && tagName != "text:list-style") {
0200                 reader.skipCurrentElement();
0201                 continue;
0202             }
0203 
0204             KoXmlStreamAttributes  attrs = reader.attributes();
0205 #if 0  // debug
0206             debugOdf2 << "Attributes:";
0207             for (int i = 0; i < attrs.size(); ++i) {
0208                 debugOdf2 << "  " << attrs[i].qualifiedName().toString()
0209                          << attrs[i].value().toString();
0210             }
0211 #endif
0212 
0213             if ( tagName == "style:style" || tagName == "style:default-style") {
0214                 QString family = attrs.value("style:family").toString();
0215                 if (family == "text" || family == "paragraph" || family == "graphic") {
0216                     // FIXME: In the future, create style per type (family).
0217                     KoOdfStyle *style = new KoOdfStyle;
0218 
0219                     style->setIsFromStylesXml(fromStylesXml);
0220                     //debugOdf2 << "This style should be loaded:" << tagName << "Family:" <<family;
0221 
0222                     style->setIsDefaultStyle(tagName == "style:default-style");
0223                     style->readOdf(reader);
0224 #if 0 // debug
0225                     debugOdf2 << "==" << styleName << ":\t"
0226                                   << style->family()
0227                                   << style->parent()
0228                                   << style->isDefaultStyle;
0229 #endif
0230                     if (style->isDefaultStyle()) {
0231                         QString family = style->family();
0232                         setDefaultStyle(family, style);
0233                     }
0234                     else {
0235                         QString styleName = style->name();
0236                         setStyle(styleName, style);
0237                     }
0238                 }
0239             }
0240             else if (tagName == "text:list-style"){
0241                 KoOdfListStyle *listStyle = new KoOdfListStyle;
0242                 listStyle->readOdf(reader);
0243                 QString styleName = listStyle->name();
0244                 setListStyle(styleName, listStyle);
0245             }
0246             else {
0247                 reader.skipCurrentElement();
0248                 continue;
0249             }
0250     }
0251 }
0252 
0253 
0254 bool KoOdfStyleManager::saveNamedStyles(KoXmlWriter *writer)
0255 {
0256     foreach(KoOdfStyle *style, d->defaultStyles) {
0257         style->saveOdf(writer);
0258     }
0259     foreach(KoOdfStyle *style, d->styles) {
0260         // FIXME: When we support named styles of types that may use
0261         //        automatic styles, e.g. page layouts (with
0262         //        headers/footers), then this logic needs to be more
0263         //        advanced.
0264         if (!style->displayName().isEmpty()) {
0265             style->saveOdf(writer);
0266         }
0267     }
0268     return true;
0269 }