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