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 }