1 /* This file is part of the KDE project
2    Copyright (C) 2004-2006 David Faure <faure@kde.org>
3    Copyright (C) 2007-2008 Thorsten Zachmann <zachmann@kde.org>
4    Copyright (C) 2009 Thomas Zander <zander@kde.org>
5    Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
6    Copyright (C) 2009 Inge Wallin <inge@lysator.liu.se>
7    Copyright (C) 2010 KO GmbH <jos.van.den.oever@kogmbh.com>
8    Copyright (C) 2010 Jarosław Staniek <staniek@kde.org>
9 
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Library General Public
12    License version 2 as published by the Free Software Foundation.
13 
14    This library is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    Library General Public License for more details.
18 
19    You should have received a copy of the GNU Library General Public License
20    along with this library; see the file COPYING.LIB.  If not, write to
21    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23 */
24 
25 #include "KoGenStyles.h"
26 
27 #include <KoStore.h>
28 #include <KoStoreDevice.h>
29 #include <KoXmlWriter.h>
30 #include "KoOdfWriteStore.h"
31 #include "KoFontFace.h"
32 #include <float.h>
33 #include <OdfDebug.h>
34 
35 static const struct {
36     KoGenStyle::Type m_type;
37     const char * m_elementName;
38     const char * m_propertiesElementName;
39     bool m_drawElement;
40 } styleData[] = {
41     { KoGenStyle::TextStyle,            "style:style", "style:text-properties",         false  },
42     { KoGenStyle::ParagraphStyle,       "style:style", "style:paragraph-properties",    false  },
43     { KoGenStyle::SectionStyle,         "style:style", "style:section-properties",      false  },
44     { KoGenStyle::RubyStyle,            "style:style", "style:ruby-properties",         false  },
45     { KoGenStyle::TableStyle,           "style:style", "style:table-properties",        false  },
46     { KoGenStyle::TableColumnStyle,     "style:style", "style:table-column-properties", false  },
47     { KoGenStyle::TableRowStyle,        "style:style", "style:table-row-properties",    false  },
48     { KoGenStyle::TableCellStyle,       "style:style", "style:table-cell-properties",   false  },
49     { KoGenStyle::GraphicStyle,         "style:style", "style:graphic-properties",      false  },
50     { KoGenStyle::PresentationStyle,    "style:style", "style:graphic-properties",      false  },
51     { KoGenStyle::DrawingPageStyle,     "style:style", "style:drawing-page-properties", false  },
52     { KoGenStyle::ChartStyle,           "style:style", "style:chart-properties",        false  },
53     { KoGenStyle::ListStyle,            "text:list-style", 0, false  },
54     { KoGenStyle::LinearGradientStyle,  "svg:linearGradient", 0, true  },
55     { KoGenStyle::RadialGradientStyle,  "svg:radialGradient", 0, true  },
56     { KoGenStyle::ConicalGradientStyle, "calligra:conicalGradient", 0, true  },
57     { KoGenStyle::StrokeDashStyle,      "draw:stroke-dash", 0, true  },
58     { KoGenStyle::FillImageStyle,       "draw:fill-image", 0, true  },
59     { KoGenStyle::HatchStyle,           "draw:hatch", "style:graphic-properties", true  },
60     { KoGenStyle::GradientStyle,        "draw:gradient", "style:graphic-properties", true  },
61     { KoGenStyle::MarkerStyle,          "draw:marker", "style:graphic-properties", true  },
62     { KoGenStyle::PresentationPageLayoutStyle, "style:presentation-page-layout", 0, false  },
63     { KoGenStyle::OutlineLevelStyle,    "text:outline-style", 0, false }
64 };
65 
66 static const unsigned int numStyleData = sizeof(styleData) / sizeof(*styleData);
67 
68 static const struct {
69     KoGenStyle::Type m_type;
70     const char * m_elementName;
71     const char * m_propertiesElementName;
72     bool m_drawElement;
73 } autoStyleData[] = {
74     { KoGenStyle::TextAutoStyle,         "style:style", "style:text-properties",         false  },
75     { KoGenStyle::ParagraphAutoStyle,    "style:style", "style:paragraph-properties",    false  },
76     { KoGenStyle::SectionAutoStyle,      "style:style", "style:section-properties",      false  },
77     { KoGenStyle::RubyAutoStyle,         "style:style", "style:ruby-properties",         false  },
78     { KoGenStyle::TableAutoStyle,        "style:style", "style:table-properties",        false  },
79     { KoGenStyle::TableColumnAutoStyle,  "style:style", "style:table-column-properties", false  },
80     { KoGenStyle::TableRowAutoStyle,     "style:style", "style:table-row-properties",    false  },
81     { KoGenStyle::TableCellAutoStyle,    "style:style", "style:table-cell-properties",   false  },
82     { KoGenStyle::GraphicAutoStyle,      "style:style", "style:graphic-properties",      false  },
83     { KoGenStyle::PresentationAutoStyle, "style:style", "style:graphic-properties",      false  },
84     { KoGenStyle::DrawingPageAutoStyle,  "style:style", "style:drawing-page-properties", false  },
85     { KoGenStyle::ChartAutoStyle,        "style:style", "style:chart-properties",        false  },
86     { KoGenStyle::PageLayoutStyle, "style:page-layout", "style:page-layout-properties",  false  },
87     { KoGenStyle::ListAutoStyle, "text:list-style", 0, false  },
88     { KoGenStyle::NumericNumberStyle, "number:number-style", 0, false  },
89     { KoGenStyle::NumericFractionStyle, "number:number-style", 0, false  },
90     { KoGenStyle::NumericScientificStyle, "number:number-style", 0, false  },
91     { KoGenStyle::NumericDateStyle, "number:date-style", 0, false  },
92     { KoGenStyle::NumericTimeStyle, "number:time-style", 0, false  },
93     { KoGenStyle::NumericPercentageStyle, "number:percentage-style", 0, false  },
94     { KoGenStyle::NumericCurrencyStyle, "number:currency-style", 0, false  },
95     { KoGenStyle::NumericBooleanStyle, "number:boolean-style", 0, false  },
96     { KoGenStyle::NumericTextStyle, "number:text-style", 0, false  }
97 };
98 
99 static const unsigned int numAutoStyleData = sizeof(autoStyleData) / sizeof(*autoStyleData);
100 
insertRawOdfStyles(const QByteArray & xml,QByteArray & styles)101 static void insertRawOdfStyles(const QByteArray& xml, QByteArray& styles)
102 {
103     if (xml.isEmpty())
104         return;
105     if (!styles.isEmpty() && !styles.endsWith('\n') && !xml.startsWith('\n')) {
106         styles.append('\n');
107     }
108     styles.append(xml);
109 }
110 
111 class Q_DECL_HIDDEN KoGenStyles::Private
112 {
113 public:
Private(KoGenStyles * q)114     Private(KoGenStyles *q) : q(q)
115     {
116     }
117 
~Private()118     ~Private()
119     {
120     }
121 
122     QList<KoGenStyles::NamedStyle> styles(bool autoStylesInStylesDotXml, KoGenStyle::Type type) const;
123     void saveOdfAutomaticStyles(KoXmlWriter* xmlWriter, bool autoStylesInStylesDotXml,
124                                 const QByteArray& rawOdfAutomaticStyles) const;
125     void saveOdfDocumentStyles(KoXmlWriter* xmlWriter) const;
126     void saveOdfMasterStyles(KoXmlWriter* xmlWriter) const;
127     QString makeUniqueName(const QString& base, const QByteArray &family, InsertionFlags flags) const;
128 
129     /**
130      * Save font face declarations
131      *
132      * This creates the office:font-face-decls tag containing all font face
133      * declarations
134      */
135     void saveOdfFontFaceDecls(KoXmlWriter* xmlWriter) const;
136 
137     /// style definition -> name
138     StyleMap styleMap;
139 
140     /// Map with the style name as key.
141     /// This map is mainly used to check for name uniqueness
142     QMap<QByteArray, QSet<QString> > styleNames;
143     QMap<QByteArray, QSet<QString> > autoStylesInStylesDotXml;
144 
145     /// List of styles (used to preserve ordering)
146     QList<KoGenStyles::NamedStyle> styleList;
147 
148     /// map for saving default styles
149     QMap<int, KoGenStyle> defaultStyles;
150 
151     /// font faces
152     QMap<QString, KoFontFace> fontFaces;
153 
154     StyleMap::iterator insertStyle(const KoGenStyle &style, const QString &name, InsertionFlags flags);
155 
156     struct RelationTarget {
157         QString target; // the style we point to
158         QString attribute; // the attribute name used for the relation
159     };
160     QHash<QString, RelationTarget> relations; // key is the name of the source style
161 
162     QByteArray rawOdfDocumentStyles;
163     QByteArray rawOdfAutomaticStyles_stylesDotXml;
164     QByteArray rawOdfAutomaticStyles_contentDotXml;
165     QByteArray rawOdfMasterStyles;
166     QByteArray rawOdfFontFaceDecls;
167 
168     KoGenStyles *q;
169 };
170 
styles(bool autoStylesInStylesDotXml,KoGenStyle::Type type) const171 QList<KoGenStyles::NamedStyle> KoGenStyles::Private::styles(bool autoStylesInStylesDotXml, KoGenStyle::Type type) const
172 {
173     QList<KoGenStyles::NamedStyle> lst;
174     QList<KoGenStyles::NamedStyle>::const_iterator it = styleList.constBegin();
175     const QList<KoGenStyles::NamedStyle>::const_iterator end = styleList.constEnd();
176     for (; it != end ; ++it) {
177         if ((*it).style->type() == type && (*it).style->autoStyleInStylesDotXml() == autoStylesInStylesDotXml) {
178             lst.append(*it);
179         }
180     }
181     return lst;
182 }
183 
saveOdfAutomaticStyles(KoXmlWriter * xmlWriter,bool autoStylesInStylesDotXml,const QByteArray & rawOdfAutomaticStyles) const184 void KoGenStyles::Private::saveOdfAutomaticStyles(KoXmlWriter* xmlWriter, bool autoStylesInStylesDotXml,
185                                                   const QByteArray& rawOdfAutomaticStyles) const
186 {
187     xmlWriter->startElement("office:automatic-styles");
188 
189     for (uint i = 0; i < numAutoStyleData; ++i) {
190         QList<KoGenStyles::NamedStyle> stylesList = styles(autoStylesInStylesDotXml, autoStyleData[i].m_type);
191         QList<KoGenStyles::NamedStyle>::const_iterator it = stylesList.constBegin();
192         for (; it != stylesList.constEnd() ; ++it) {
193             (*it).style->writeStyle(xmlWriter, *q, autoStyleData[i].m_elementName, (*it).name,
194                                     autoStyleData[i].m_propertiesElementName, true, autoStyleData[i].m_drawElement);
195         }
196     }
197 
198     if (!rawOdfAutomaticStyles.isEmpty()) {
199         xmlWriter->addCompleteElement(rawOdfAutomaticStyles.constData());
200     }
201 
202     xmlWriter->endElement(); // office:automatic-styles
203 }
204 
saveOdfDocumentStyles(KoXmlWriter * xmlWriter) const205 void KoGenStyles::Private::saveOdfDocumentStyles(KoXmlWriter* xmlWriter) const
206 {
207     xmlWriter->startElement("office:styles");
208 
209     for (uint i = 0; i < numStyleData; ++i) {
210         const QMap<int, KoGenStyle>::const_iterator it(defaultStyles.constFind(styleData[i].m_type));
211         if (it != defaultStyles.constEnd()) {
212             it.value().writeStyle(xmlWriter, *q, "style:default-style", "",
213                                   styleData[i].m_propertiesElementName, true, styleData[i].m_drawElement);
214         }
215     }
216 
217     for (uint i = 0; i < numStyleData; ++i) {
218         QList<KoGenStyles::NamedStyle> stylesList(styles(false, styleData[i].m_type));
219         QList<KoGenStyles::NamedStyle>::const_iterator it = stylesList.constBegin();
220         for (; it != stylesList.constEnd() ; ++it) {
221             if (relations.contains(it->name)) {
222                 KoGenStyles::Private::RelationTarget relation = relations.value(it->name);
223                 KoGenStyle styleCopy = *(*it).style;
224                 styleCopy.addAttribute(relation.attribute, relation.target);
225                 styleCopy.writeStyle(xmlWriter, *q, styleData[i].m_elementName, (*it).name,
226                                     styleData[i].m_propertiesElementName, true, styleData[i].m_drawElement);
227             } else {
228                 (*it).style->writeStyle(xmlWriter, *q, styleData[i].m_elementName, (*it).name,
229                                     styleData[i].m_propertiesElementName, true, styleData[i].m_drawElement);
230             }
231         }
232     }
233 
234     if (!rawOdfDocumentStyles.isEmpty()) {
235         xmlWriter->addCompleteElement(rawOdfDocumentStyles.constData());
236     }
237 
238     xmlWriter->endElement(); // office:styles
239 }
240 
saveOdfMasterStyles(KoXmlWriter * xmlWriter) const241 void KoGenStyles::Private::saveOdfMasterStyles(KoXmlWriter* xmlWriter) const
242 {
243     xmlWriter->startElement("office:master-styles");
244 
245     QList<KoGenStyles::NamedStyle> stylesList = styles(false, KoGenStyle::MasterPageStyle);
246     QList<KoGenStyles::NamedStyle>::const_iterator it = stylesList.constBegin();
247     for (; it != stylesList.constEnd() ; ++it) {
248         (*it).style->writeStyle(xmlWriter, *q, "style:master-page", (*it).name, 0);
249     }
250 
251     if (!rawOdfMasterStyles.isEmpty()) {
252         xmlWriter->addCompleteElement(rawOdfMasterStyles.constData());
253     }
254 
255     xmlWriter->endElement(); // office:master-styles
256 }
257 
saveOdfFontFaceDecls(KoXmlWriter * xmlWriter) const258 void KoGenStyles::Private::saveOdfFontFaceDecls(KoXmlWriter* xmlWriter) const
259 {
260     if (fontFaces.isEmpty())
261         return;
262 
263     xmlWriter->startElement("office:font-face-decls");
264     for (QMap<QString, KoFontFace>::ConstIterator it(fontFaces.constBegin());
265          it != fontFaces.constEnd(); ++it)
266     {
267         it.value().saveOdf(xmlWriter);
268     }
269 
270     if (!rawOdfFontFaceDecls.isEmpty()) {
271         xmlWriter->addCompleteElement(rawOdfFontFaceDecls.constData());
272     }
273 
274     xmlWriter->endElement(); // office:font-face-decls
275 }
276 
makeUniqueName(const QString & base,const QByteArray & family,InsertionFlags flags) const277 QString KoGenStyles::Private::makeUniqueName(const QString& base, const QByteArray &family, InsertionFlags flags) const
278 {
279     // If this name is not used yet, and numbering isn't forced, then the given name is ok.
280     if ((flags & DontAddNumberToName)
281             && !autoStylesInStylesDotXml[family].contains(base)
282             && !styleNames[family].contains(base))
283         return base;
284     int num = 1;
285     QString name;
286     do {
287         name = base + QString::number(num++);
288     } while (autoStylesInStylesDotXml[family].contains(name)
289              || styleNames[family].contains(name));
290     return name;
291 }
292 
293 //------------------------
294 
KoGenStyles()295 KoGenStyles::KoGenStyles()
296         : d(new Private(this))
297 {
298 }
299 
~KoGenStyles()300 KoGenStyles::~KoGenStyles()
301 {
302     delete d;
303 }
304 
insert(const KoGenStyle & style,const QString & baseName,InsertionFlags flags)305 QString KoGenStyles::insert(const KoGenStyle& style, const QString& baseName, InsertionFlags flags)
306 {
307     // if it is a default style it has to be saved differently
308     if (style.isDefaultStyle()) {
309         // we can have only one default style per type
310         Q_ASSERT(!d->defaultStyles.contains(style.type()));
311         // default style is only possible for style:style in office:style types
312         Q_ASSERT(style.type() == KoGenStyle::TextStyle ||
313                  style.type() == KoGenStyle::ParagraphStyle ||
314                  style.type() == KoGenStyle::SectionStyle ||
315                  style.type() == KoGenStyle::RubyStyle ||
316                  style.type() == KoGenStyle::TableStyle ||
317                  style.type() == KoGenStyle::TableColumnStyle ||
318                  style.type() == KoGenStyle::TableRowStyle ||
319                  style.type() == KoGenStyle::TableCellStyle ||
320                  style.type() == KoGenStyle::GraphicStyle ||
321                  style.type() == KoGenStyle::PresentationStyle ||
322                  style.type() == KoGenStyle::DrawingPageStyle ||
323                  style.type() == KoGenStyle::ChartStyle);
324 
325         d->defaultStyles.insert(style.type(), style);
326         // default styles don't have a name
327         return QString();
328     }
329 
330     if (flags & AllowDuplicates) {
331         StyleMap::iterator it = d->insertStyle(style, baseName, flags);
332         return it.value();
333     }
334 
335     StyleMap::iterator it = d->styleMap.find(style);
336     if (it == d->styleMap.end()) {
337         // Not found, try if this style is in fact equal to its parent (the find above
338         // wouldn't have found it, due to m_parentName being set).
339         if (!style.parentName().isEmpty()) {
340             KoGenStyle testStyle(style);
341             const KoGenStyle* parentStyle = this->style(style.parentName(), style.familyName());   // ## linear search
342             if (!parentStyle) {
343                 debugOdf << "baseName=" << baseName << "parent style" << style.parentName()
344                               << "not found in collection";
345             } else {
346                 // TODO remove
347                 if (testStyle.m_familyName != parentStyle->m_familyName) {
348                     warnOdf << "baseName=" << baseName << "family=" << testStyle.m_familyName
349                                     << "parent style" << style.parentName() << "has a different family:"
350                                     << parentStyle->m_familyName;
351                 }
352 
353                 testStyle.m_parentName = parentStyle->m_parentName;
354                 // Exclude the type from the comparison. It's ok for an auto style
355                 // to have a user style as parent; they can still be identical
356                 testStyle.m_type = parentStyle->m_type;
357                 // Also it's ok to not have the display name of the parent style
358                 // in the auto style
359                 QMap<QString, QString>::const_iterator it = parentStyle->m_attributes.find("style:display-name");
360                 if (it != parentStyle->m_attributes.end())
361                     testStyle.addAttribute("style:display-name", *it);
362 
363                 if (*parentStyle == testStyle)
364                     return style.parentName();
365             }
366         }
367 
368         it = d->insertStyle(style, baseName, flags);
369     }
370     return it.value();
371 }
372 
insertStyle(const KoGenStyle & style,const QString & baseName,InsertionFlags flags)373 KoGenStyles::StyleMap::iterator KoGenStyles::Private::insertStyle(const KoGenStyle &style,
374                                                                   const QString& baseName, InsertionFlags flags)
375 {
376     QString styleName(baseName);
377     if (styleName.isEmpty()) {
378         switch (style.type()) {
379         case KoGenStyle::ParagraphAutoStyle: styleName = 'P'; break;
380         case KoGenStyle::ListAutoStyle: styleName = 'L'; break;
381         case KoGenStyle::TextAutoStyle: styleName = 'T'; break;
382         default:
383             styleName = 'A'; // for "auto".
384         }
385         flags &= ~DontAddNumberToName; // i.e. force numbering
386     }
387     styleName = makeUniqueName(styleName, style.m_familyName, flags);
388     if (style.autoStyleInStylesDotXml())
389         autoStylesInStylesDotXml[style.m_familyName].insert(styleName);
390     else
391         styleNames[style.m_familyName].insert(styleName);
392     KoGenStyles::StyleMap::iterator it = styleMap.insert(style, styleName);
393     NamedStyle s;
394     s.style = &it.key();
395     s.name = styleName;
396     styleList.append(s);
397     return it;
398 }
399 
styles() const400 KoGenStyles::StyleMap KoGenStyles::styles() const
401 {
402     return d->styleMap;
403 }
404 
styles(KoGenStyle::Type type) const405 QList<KoGenStyles::NamedStyle> KoGenStyles::styles(KoGenStyle::Type type) const
406 {
407     return d->styles(false, type);
408 }
409 
style(const QString & name,const QByteArray & family) const410 const KoGenStyle* KoGenStyles::style(const QString &name, const QByteArray &family) const
411 {
412     QList<KoGenStyles::NamedStyle>::const_iterator it = d->styleList.constBegin();
413     const QList<KoGenStyles::NamedStyle>::const_iterator end = d->styleList.constEnd();
414     for (; it != end ; ++it) {
415         if ((*it).name == name && (*it).style->familyName() == family) {
416             return (*it).style;
417         }
418     }
419     return 0;
420 }
421 
styleForModification(const QString & name,const QByteArray & family)422 KoGenStyle* KoGenStyles::styleForModification(const QString &name, const QByteArray &family)
423 {
424     return const_cast<KoGenStyle *>(style(name, family));
425 }
426 
markStyleForStylesXml(const QString & name,const QByteArray & family)427 void KoGenStyles::markStyleForStylesXml(const QString &name, const QByteArray &family)
428 {
429     Q_ASSERT(d->styleNames[family].contains(name));
430     d->styleNames[family].remove(name);
431     d->autoStylesInStylesDotXml[family].insert(name);
432     styleForModification(name, family)->setAutoStyleInStylesDotXml(true);
433 }
434 
insertFontFace(const KoFontFace & face)435 void KoGenStyles::insertFontFace(const KoFontFace &face)
436 {
437     Q_ASSERT(!face.isNull());
438     if (face.isNull()) {
439         warnOdf << "This font face is null and will not be added to styles: set at least the name";
440         return;
441     }
442     d->fontFaces.insert(face.name(), face); // replaces prev item
443 }
444 
fontFace(const QString & name) const445 KoFontFace KoGenStyles::fontFace(const QString& name) const
446 {
447     return d->fontFaces.value(name);
448 }
449 
saveOdfStylesDotXml(KoStore * store,KoXmlWriter * manifestWriter) const450 bool KoGenStyles::saveOdfStylesDotXml(KoStore* store, KoXmlWriter* manifestWriter) const
451 {
452     if (!store->open("styles.xml"))
453         return false;
454 
455     manifestWriter->addManifestEntry("styles.xml",  "text/xml");
456 
457     KoStoreDevice stylesDev(store);
458     KoXmlWriter* stylesWriter = KoOdfWriteStore::createOasisXmlWriter(&stylesDev, "office:document-styles");
459 
460     d->saveOdfFontFaceDecls(stylesWriter);
461     d->saveOdfDocumentStyles(stylesWriter);
462     d->saveOdfAutomaticStyles(stylesWriter, true, d->rawOdfAutomaticStyles_stylesDotXml);
463     d->saveOdfMasterStyles(stylesWriter);
464 
465     stylesWriter->endElement(); // root element (office:document-styles)
466     stylesWriter->endDocument();
467     delete stylesWriter;
468 
469     if (!store->close())   // done with styles.xml
470         return false;
471 
472     return true;
473 }
474 
saveOdfStyles(StylesPlacement placement,KoXmlWriter * xmlWriter) const475 void KoGenStyles::saveOdfStyles(StylesPlacement placement, KoXmlWriter* xmlWriter) const
476 {
477     switch (placement) {
478     case DocumentStyles:
479         d->saveOdfDocumentStyles(xmlWriter);
480         break;
481     case MasterStyles:
482         d->saveOdfMasterStyles(xmlWriter);
483         break;
484     case DocumentAutomaticStyles:
485         d->saveOdfAutomaticStyles(xmlWriter, false, d->rawOdfAutomaticStyles_contentDotXml);
486         break;
487     case StylesXmlAutomaticStyles:
488         d->saveOdfAutomaticStyles(xmlWriter, true, d->rawOdfAutomaticStyles_stylesDotXml);
489         break;
490     case FontFaceDecls:
491         d->saveOdfFontFaceDecls(xmlWriter);
492         break;
493     }
494 }
495 
insertRawOdfStyles(StylesPlacement placement,const QByteArray & xml)496 void KoGenStyles::insertRawOdfStyles(StylesPlacement placement, const QByteArray& xml)
497 {
498     switch (placement) {
499     case DocumentStyles:
500         ::insertRawOdfStyles(xml, d->rawOdfDocumentStyles);
501         break;
502     case MasterStyles:
503         ::insertRawOdfStyles(xml, d->rawOdfMasterStyles);
504         break;
505     case DocumentAutomaticStyles:
506         ::insertRawOdfStyles(xml, d->rawOdfAutomaticStyles_contentDotXml);
507         break;
508     case StylesXmlAutomaticStyles:
509         ::insertRawOdfStyles(xml, d->rawOdfAutomaticStyles_stylesDotXml);
510         break;
511     case FontFaceDecls:
512         ::insertRawOdfStyles(xml, d->rawOdfFontFaceDecls);
513         break;
514     }
515 }
516 
insertStyleRelation(const QString & source,const QString & target,const char * tagName)517 void KoGenStyles::insertStyleRelation(const QString &source, const QString &target, const char *tagName)
518 {
519     KoGenStyles::Private::RelationTarget relation;
520     relation.target = target;
521     relation.attribute = QString(tagName);
522     d->relations.insert(source, relation);
523 }
524 
operator <<(QDebug dbg,const KoGenStyles & styles)525 QDebug operator<<(QDebug dbg, const KoGenStyles& styles)
526 {
527     dbg.nospace() << "KoGenStyles:";
528     QList<KoGenStyles::NamedStyle>::const_iterator it = styles.d->styleList.constBegin();
529     const QList<KoGenStyles::NamedStyle>::const_iterator end = styles.d->styleList.constEnd();
530     for (; it != end ; ++it) {
531         dbg.nospace() << (*it).name;
532     }
533     for (QMap<QByteArray, QSet<QString> >::const_iterator familyIt(styles.d->styleNames.constBegin()); familyIt != styles.d->styleNames.constEnd(); ++familyIt) {
534         for (QSet<QString>::const_iterator it(familyIt.value().constBegin()); it != familyIt.value().constEnd(); ++it) {
535             dbg.space() << "style:" << *it;
536         }
537     }
538 #ifndef NDEBUG
539     for (QMap<QByteArray, QSet<QString> >::const_iterator familyIt(styles.d->autoStylesInStylesDotXml.constBegin()); familyIt != styles.d->autoStylesInStylesDotXml.constEnd(); ++familyIt) {
540         for (QSet<QString>::const_iterator it(familyIt.value().constBegin()); it != familyIt.value().constEnd(); ++it) {
541             dbg.space() << "auto style for style.xml:" << *it;
542         }
543     }
544 #endif
545     return dbg.space();
546 }
547