1 /* This file is part of the KDE project
2  * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
3  * Copyright (C) 2009 Elvis Stansvik <elvstone@gmail.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #include "KoTextDebug.h"
22 
23 #include <QTextDocument>
24 #include <QTextDocumentFragment>
25 #include <QTextFrame>
26 #include <QTextBlock>
27 #include <QTextTable>
28 #include <QTextFragment>
29 #include <QTextList>
30 #include <QTextStream>
31 #include <QTextCursor>
32 
33 #include "styles/KoParagraphStyle.h"
34 #include "styles/KoCharacterStyle.h"
35 #include "styles/KoListStyle.h"
36 #include "styles/KoTableStyle.h"
37 #include "styles/KoTableCellStyle.h"
38 #include "styles/KoStyleManager.h"
39 #include "KoTextDocument.h"
40 #include "KoTextBlockData.h"
41 #include <KoInlineTextObjectManager.h>
42 #include <KoInlineNote.h>
43 #include <KoImageData.h>
44 
45 #define PARAGRAPH_BORDER_DEBUG
46 
47 int KoTextDebug::depth = 0;
48 const int KoTextDebug::INDENT = 2;
49 const QTextDocument *KoTextDebug::document = 0;
50 
51 #define dumpIndent(T) { for (int i=0; i<T; ++i) out << ' '; }
52 #define dumpList(T) { foreach (const QString &x, T) out << x << ' '; }
53 
Q_DECLARE_METATYPE(QVector<KoText::Tab>)54 Q_DECLARE_METATYPE(QVector<KoText::Tab>)
55 
56 static QString fontProperties(const QTextCharFormat &textFormat)
57 {
58     QMap<int, QVariant> properties = textFormat.properties();
59     QStringList fontProps;
60     // add only font properties here
61     foreach(int id, properties.keys()) {
62         switch (id) {
63         case QTextFormat::FontFamily:
64             fontProps.append(properties[id].toString());
65             break;
66         case QTextFormat::FontPointSize:
67             fontProps.append(QString("%1pt").arg(properties[id].toDouble()));
68             break;
69         case QTextFormat::FontSizeAdjustment:
70             fontProps.append(QString("%1adj").arg(properties[id].toDouble()));
71             break;
72         case QTextFormat::FontWeight:
73             fontProps.append(QString("weight %1").arg(properties[id].toInt()));
74             break;
75         case QTextFormat::FontItalic:
76             fontProps.append(properties[id].toBool() ? "italic" : "non-italic");
77             break;
78         case QTextFormat::FontPixelSize:
79             fontProps.append(QString("%1px").arg(properties[id].toDouble()));
80             break;
81         case QTextFormat::FontFixedPitch:
82             fontProps.append(properties[id].toBool() ? "fixedpitch" : "varpitch");
83             break;
84         case QTextFormat::FontCapitalization:
85             fontProps.append(QString("caps %1").arg(properties[id].toInt()));
86             break;
87         case KoCharacterStyle::FontCharset:
88             fontProps.append(properties[id].toString());
89             break;
90         case QTextFormat::FontStyleHint:
91             fontProps.append(QString::number(properties[id].toInt()));
92             break;
93         case QTextFormat::FontKerning:
94             fontProps.append(QString("kerning %1").arg(properties[id].toInt()));
95             break;
96         default:
97             break;
98         }
99     }
100     return fontProps.join(",");
101 }
102 
dumpDocument(const QTextDocument * doc,QTextStream & out)103 void KoTextDebug::dumpDocument(const QTextDocument *doc, QTextStream &out)
104 {
105     Q_ASSERT(doc);
106     document = doc;
107     out << QString("<document defaultfont=\"%1\">").arg(doc->defaultFont().toString());
108     dumpFrame(document->rootFrame(), out);
109     out << "</document>";
110     document = 0;
111 }
112 
textAttributes(const KoCharacterStyle & style)113 QString KoTextDebug::textAttributes(const KoCharacterStyle &style)
114 {
115     QTextCharFormat format;
116     style.applyStyle(format);
117     return textAttributes(format);
118 }
119 
inlineObjectAttributes(const QTextCharFormat & textFormat)120 QString KoTextDebug::inlineObjectAttributes(const QTextCharFormat &textFormat)
121 {
122     QString attrs;
123 
124     if (textFormat.objectType() == QTextFormat::UserObject + 1) {
125         KoInlineTextObjectManager *inlineObjectManager = KoTextDocument(document).inlineTextObjectManager();
126         KoInlineObject *inlineObject = inlineObjectManager->inlineTextObject(textFormat);
127         if (KoInlineNote *note = dynamic_cast<KoInlineNote *>(inlineObject)) {
128             attrs.append(QString(" id=\"%1\"").arg(note->id()));
129             if (note->type() == KoInlineNote::Footnote) {
130                 attrs.append(" type=\"footnote\"");
131             } else if (note->type() == KoInlineNote::Endnote) {
132                 attrs.append(" type=\"endnote\"");
133             }
134             attrs.append(QString(" label=\"%1\"").arg(note->label()));
135         } else {
136             attrs.append(" type=\"inlineobject\">");
137         }
138     }
139 
140     return attrs;
141 }
142 
textAttributes(const QTextCharFormat & textFormat)143 QString KoTextDebug::textAttributes(const QTextCharFormat &textFormat)
144 {
145     QString attrs;
146 
147     QTextImageFormat imageFormat = textFormat.toImageFormat();
148 
149     if (imageFormat.isValid()) {
150         attrs.append(" type=\"image\">");
151         return attrs;
152     }
153 
154     KoStyleManager *styleManager = document ? KoTextDocument(document).styleManager() : 0;
155     if (styleManager && textFormat.hasProperty(KoCharacterStyle::StyleId)) {
156         int id = textFormat.intProperty(KoCharacterStyle::StyleId);
157         KoCharacterStyle *characterStyle = styleManager->characterStyle(id);
158         attrs.append(" characterStyle=\"id:").append(QString::number(id));
159         if (characterStyle)
160             attrs.append(" name:").append(characterStyle->name());
161         attrs.append("\"");
162     }
163 
164     QMap<int, QVariant> properties = textFormat.properties();
165     attrs.append(" type=\"char\"");
166     QString fontProps = fontProperties(textFormat);
167     if (!fontProps.isEmpty())
168         attrs.append(QString(" font=\"%1\"").arg(fontProps));
169 
170     if (textFormat.isAnchor()) {
171         attrs.append(QString(" achorHref=\"%1\"").arg(textFormat.anchorHref()));
172         attrs.append(QString(" achorName=\"%1\"").arg(textFormat.anchorName()));
173     }
174 
175     foreach(int id, properties.keys()) {
176         QString key, value;
177         switch (id) {
178         case QTextFormat::TextOutline: {
179             key = "outline";
180             QPen pen = qvariant_cast<QPen>(properties[id]);
181             if (pen.style() == Qt::NoPen)
182                 value = "false";
183             else
184                 value = pen.color().name();
185             break;
186         }
187         case KoCharacterStyle::UnderlineStyle:
188             key = "underlinestyle";
189             value = QString::number(properties[id].toInt());
190             break;
191         case QTextFormat::TextUnderlineColor:
192             key = "underlinecolor";
193             value = qvariant_cast<QColor>(properties[id]).name();
194             break;
195         case KoCharacterStyle::UnderlineType:
196             key = "underlinetype";
197             value = QString::number(properties[id].toInt());
198             break;
199         case KoCharacterStyle::UnderlineMode:
200             key = "underlinemode";
201             value = QString::number(properties[id].toInt());
202             break;
203         case KoCharacterStyle::UnderlineWeight:
204             key = "underlineweight";
205             value = QString::number(properties[id].toInt());
206             break;
207         case KoCharacterStyle::UnderlineWidth:
208             key = "underlinewidth";
209             value = QString::number(properties[id].toDouble());
210             break;
211         case KoCharacterStyle::StrikeOutStyle:
212             key = "strikeoutstyle";
213             value = QString::number(properties[id].toInt());
214             break;
215         case KoCharacterStyle::StrikeOutColor:
216             key = "strikeoutcolor";
217             value = qvariant_cast<QColor>(properties[id]).name();
218             break;
219         case KoCharacterStyle::StrikeOutType:
220             key = "strikeouttype";
221             value = QString::number(properties[id].toInt());
222             break;
223         case KoCharacterStyle::StrikeOutMode:
224             key = "strikeoutmode";
225             value = QString::number(properties[id].toInt());
226             break;
227         case KoCharacterStyle::StrikeOutWeight:
228             key = "strikeoutweight";
229             value = QString::number(properties[id].toInt());
230             break;
231         case KoCharacterStyle::StrikeOutWidth:
232             key = "strikeoutwidth";
233             value = QString::number(properties[id].toDouble());
234             break;
235         case QTextFormat::ForegroundBrush:
236             key = "foreground";
237             value = qvariant_cast<QBrush>(properties[id]).color().name(); // beware!
238             break;
239         case QTextFormat::BackgroundBrush:
240             key = "background";
241             value = qvariant_cast<QBrush>(properties[id]).color().name(); // beware!
242             break;
243         case QTextFormat::BlockAlignment:
244             key = "align";
245             value = QString::number(properties[id].toInt());
246             break;
247         case QTextFormat::TextIndent:
248             key = "textindent";
249             value = QString::number(properties[id].toInt());
250             break;
251         case QTextFormat::BlockIndent:
252             key = "indent";
253             value = QString::number(properties[id].toInt());
254             break;
255         case KoCharacterStyle::Country:
256             key = "country";
257             value = properties[id].toString();
258             break;
259         case KoCharacterStyle::Language:
260             key = "language";
261             value = properties[id].toString();
262             break;
263         case KoCharacterStyle::HasHyphenation:
264             key = "hyphenation";
265             value = properties[id].toBool();
266             break;
267         case KoCharacterStyle::StrikeOutText:
268             key = "strikeout-text";
269             value = properties[id].toString();
270             break;
271         case KoCharacterStyle::FontCharset:
272             key = "font-charset";
273             value = properties[id].toString();
274             break;
275         case KoCharacterStyle::TextRotationAngle:
276             key = "rotation-angle";
277             value = QString::number(properties[id].toInt());
278             break;
279         case KoCharacterStyle::TextRotationScale:
280             key = "text-rotation-scale";
281             value = properties[id].toInt() == KoCharacterStyle::Fixed ? "Fixed" : "LineHeight";
282             break;
283         case KoCharacterStyle::TextScale:
284             key = "text-scale";
285             value = QString::number(properties[id].toInt());
286             break;
287         case KoCharacterStyle::InlineRdf:
288             key = "inline-rdf";
289             value = QString::number(properties[id].toInt());
290             break;
291         default:
292             key = "unknown"+QString::number(id);
293             value = QString::number(properties[id].toInt());
294             break;
295         }
296         if (!key.isEmpty())
297             attrs.append(" ").append(key).append("=\"").append(value).append("\"");
298     }
299     return attrs;
300 }
301 
paraAttributes(const KoParagraphStyle & style)302 QString KoTextDebug::paraAttributes(const KoParagraphStyle &style)
303 {
304     QTextBlockFormat format;
305     style.applyStyle(format);
306     return paraAttributes(format);
307 }
308 
paraAttributes(const QTextBlockFormat & blockFormat)309 QString KoTextDebug::paraAttributes(const QTextBlockFormat &blockFormat)
310 {
311     QString attrs;
312     KoStyleManager *styleManager = document ? KoTextDocument(document).styleManager() : 0;
313     if (styleManager && blockFormat.hasProperty(KoParagraphStyle::StyleId)) {
314         int id = blockFormat.intProperty(KoParagraphStyle::StyleId);
315         KoParagraphStyle *paragraphStyle = styleManager->paragraphStyle(id);
316         attrs.append(" paragraphStyle=\"id:").append(QString::number(id));
317         if (paragraphStyle)
318             attrs.append(" name:").append(paragraphStyle->name());
319         attrs.append("\"");
320     }
321 
322     QMap<int, QVariant> properties = blockFormat.properties();
323     foreach(int id, properties.keys()) {
324         QString key, value;
325         switch (id) {
326         // the following are 'todo'
327         case KoParagraphStyle::PercentLineHeight:
328         case KoParagraphStyle::FixedLineHeight:
329         case KoParagraphStyle::MinimumLineHeight:
330         case KoParagraphStyle::LineSpacing:
331         case KoParagraphStyle::LineSpacingFromFont:
332         case KoParagraphStyle::AlignLastLine:
333         case KoParagraphStyle::WidowThreshold:
334         case KoParagraphStyle::OrphanThreshold:
335         case KoParagraphStyle::DropCapsTextStyle:
336         case KoParagraphStyle::FollowDocBaseline:
337         case KoParagraphStyle::HasLeftBorder:
338         case KoParagraphStyle::HasTopBorder:
339         case KoParagraphStyle::HasRightBorder:
340         case KoParagraphStyle::HasBottomBorder:
341         case KoParagraphStyle::BorderLineWidth:
342         case KoParagraphStyle::SecondBorderLineWidth:
343         case KoParagraphStyle::DistanceToSecondBorder:
344         case KoParagraphStyle::LeftPadding:
345         case KoParagraphStyle::TopPadding:
346         case KoParagraphStyle::RightPadding:
347         case KoParagraphStyle::BottomPadding:
348         case KoParagraphStyle::LeftBorderColor:
349         case KoParagraphStyle::TopInnerBorderWidth:
350         case KoParagraphStyle::TopBorderSpacing:
351         case KoParagraphStyle::TopBorderStyle:
352         case KoParagraphStyle::TopBorderColor:
353         case KoParagraphStyle::RightInnerBorderWidth:
354         case KoParagraphStyle::RightBorderSpacing:
355         case KoParagraphStyle::RightBorderStyle:
356         case KoParagraphStyle::RightBorderColor:
357         case KoParagraphStyle::BottomInnerBorderWidth:
358         case KoParagraphStyle::BottomBorderSpacing:
359         case KoParagraphStyle::BottomBorderStyle:
360         case KoParagraphStyle::BottomBorderColor:
361         case KoParagraphStyle::ListStyleId:
362         case KoParagraphStyle::ListStartValue:
363         case KoParagraphStyle::RestartListNumbering:
364         case KoParagraphStyle::TextProgressionDirection:
365         case KoParagraphStyle::MasterPageName:
366         case KoParagraphStyle::OutlineLevel:
367             break;
368         case KoParagraphStyle::AutoTextIndent:
369             key = "autotextindent";
370             value = properties[id].toBool() ? "true" : "false" ;
371             break;
372 #ifdef PARAGRAPH_BORDER_DEBUG // because it tends to get annoyingly long :)
373         case KoParagraphStyle::LeftBorderWidth:
374             key = "border-width-left";
375             value = QString::number(properties[id].toDouble()) ;
376             break;
377         case KoParagraphStyle::TopBorderWidth:
378             key = "border-width-top";
379             value = QString::number(properties[id].toDouble()) ;
380             break;
381         case KoParagraphStyle::RightBorderWidth:
382             key = "border-width-right";
383             value = QString::number(properties[id].toDouble()) ;
384             break;
385         case KoParagraphStyle::BottomBorderWidth:
386             key = "border-width-bottom";
387             value = QString::number(properties[id].toDouble()) ;
388             break;
389         case KoParagraphStyle::LeftBorderStyle:
390             key = "border-style-left";
391             value = QString::number(properties[id].toDouble()) ;
392             break;
393         case KoParagraphStyle::LeftBorderSpacing:
394             key = "inner-border-spacing-left";
395             value = QString::number(properties[id].toDouble()) ;
396             break;
397         case KoParagraphStyle::LeftInnerBorderWidth:
398             key = "inner-border-width-left";
399             value = QString::number(properties[id].toDouble()) ;
400             break;
401 #endif
402         case KoParagraphStyle::TabStopDistance:
403             key = "tab-stop-distance";
404             value = QString::number(properties[id].toDouble());
405             break;
406         case KoParagraphStyle::TabPositions:
407             key = "tab-stops";
408             value.clear();
409             foreach(const QVariant & qvtab, qvariant_cast<QList<QVariant> >(properties[id])) {
410                 KoText::Tab tab = qvtab.value<KoText::Tab>();
411                 value.append("{");
412                 value.append(" pos:").append(QString::number(tab.position));
413                 value.append(" type:").append(QString::number(tab.type));
414                 if (! tab.delimiter.isNull())
415                     value.append(" delim:").append(QString(tab.delimiter));
416                 value.append(" leadertype:").append(QString::number(tab.leaderType));
417                 value.append(" leaderstyle:").append(QString::number(tab.leaderStyle));
418                 value.append(" leaderweight:").append(QString::number(tab.leaderWeight));
419                 value.append(" leaderwidth:").append(QString().setNum(tab.leaderWidth));
420                 value.append(" leadercolor:").append(tab.leaderColor.name());
421                 if (! tab.leaderText.isEmpty())
422                     value.append(" leadertext:").append(QString(tab.leaderText));
423                 value.append("}, ");
424             }
425             break;
426         case KoParagraphStyle::DropCaps:
427             key = "drop-caps";
428             value = QString::number(properties[id].toBool());
429             break;
430         case KoParagraphStyle::DropCapsLines:
431             key = "drop-caps-lines";
432             value = QString::number(properties[id].toInt());
433             break;
434         case KoParagraphStyle::DropCapsLength:
435             key = "drop-caps-length";
436             value = QString::number(properties[id].toInt());
437             break;
438         case KoParagraphStyle::DropCapsDistance:
439             key = "drop-caps-distance";
440             value = QString::number(properties[id].toDouble());
441             break;
442         case QTextFormat::BlockBottomMargin:
443             value = QString::number(properties[id].toDouble());
444             if (value != "0")
445                 key = "block-bottom-margin";
446             break;
447         case QTextFormat::BlockTopMargin:
448             value = QString::number(properties[id].toDouble());
449             if (value != "0")
450                 key = "block-top-margin";
451             break;
452         case QTextFormat::BlockLeftMargin:
453             value = QString::number(properties[id].toDouble());
454             if (value != "0")
455                 key = "block-left-margin";
456             break;
457         case QTextFormat::BlockRightMargin:
458             value = QString::number(properties[id].toDouble());
459             if (value != "0")
460                 key = "block-right-margin";
461             break;
462         case KoParagraphStyle::UnnumberedListItem:
463             key = "unnumbered-list-item";
464             value = QString::number(properties[id].toBool());
465             break;
466         case KoParagraphStyle::IsListHeader:
467             key = "list-header";
468             value = '1';
469             break;
470         case KoParagraphStyle::ListLevel:
471             key = "list-level";
472             value = QString::number(properties[id].toInt());
473             break;
474         default:
475             break;
476         }
477         if (!key.isEmpty())
478             attrs.append(" ").append(key).append("=\"").append(value).append("\"");
479     }
480     return attrs;
481 }
482 
listAttributes(const QTextListFormat & listFormat)483 QString KoTextDebug::listAttributes(const QTextListFormat &listFormat)
484 {
485     QString attrs;
486     KoStyleManager *styleManager = document ? KoTextDocument(document).styleManager() : 0;
487     if (styleManager && listFormat.hasProperty(KoListStyle::StyleId)) {
488         int id = listFormat.intProperty(KoListStyle::StyleId);
489         KoListStyle *listStyle = styleManager->listStyle(id);
490         attrs.append(" listStyle=\"id:").append(QString::number(id));
491         if (listStyle)
492             attrs.append(" name:").append(listStyle->name());
493         attrs.append("\"");
494     }
495 
496     QMap<int, QVariant> properties = listFormat.properties();
497     foreach(int id, properties.keys()) {
498         QString key, value;
499         switch (id) {
500         case QTextListFormat::ListStyle:
501             key = "type";
502             value = QString::number(properties[id].toInt());
503             break;
504         case QTextListFormat::ListIndent:
505             key = "indent";
506             value = QString::number(properties[id].toDouble());
507             break;
508         case KoListStyle::ListItemPrefix:
509             key = "prefix";
510             value = properties[id].toString();
511             break;
512         case KoListStyle::ListItemSuffix:
513             key = "suffix";
514             value = properties[id].toString();
515             break;
516         case KoListStyle::StartValue:
517             key = "start-value";
518             value = QString::number(properties[id].toInt());
519             break;
520         case KoListStyle::Level:
521             key = "level";
522             value = QString::number(properties[id].toInt());
523             break;
524         case KoListStyle::DisplayLevel:
525             key = "display-level";
526             value = QString::number(properties[id].toInt());
527             break;
528         case KoListStyle::Alignment:
529             key = "alignment";
530             value = QString::number(properties[id].toInt());
531             break;
532         case KoListStyle::RelativeBulletSize:
533             key = "bullet-size";
534             value = QString::number(properties[id].toInt());
535             break;
536         case KoListStyle::BulletCharacter:
537             key = "bullet-char";
538             value = properties[id].toString();
539             break;
540         case KoListStyle::LetterSynchronization:
541             key = "letter-sync";
542             value = QString::number(properties[id].toInt());
543             break;
544         case KoListStyle::StyleId:
545             key = "styleid";
546             value = QString::number(properties[id].toInt());
547             break;
548         case KoListStyle::MinimumWidth:
549             key = "minimum-width";
550             value = QString::number(properties[id].toDouble());
551             break;
552         case KoListStyle::ListId:
553             key = "list-id";
554             value = QString::number(properties[id].toInt());
555             break;
556         case KoListStyle::IsOutline:
557             key = "is-outline";
558             value = properties[id].toBool();
559             break;
560         case KoListStyle::Indent:
561             key = "indent";
562             value = QString::number(properties[id].toInt());
563             break;
564         case KoListStyle::MinimumDistance:
565             key = "minimum-distance";
566             value = QString::number(properties[id].toDouble());
567             break;
568         case KoListStyle::Width:
569             key = "width";
570             value = QString::number(properties[id].toDouble());
571             break;
572         case KoListStyle::Height:
573             key = "height";
574             value = QString::number(properties[id].toDouble());
575             break;
576         case KoListStyle::BulletImage:
577             key = "bullet-image";
578             value = QString::number((quintptr)(properties[id].value<KoImageData*>()));
579             break;
580         case KoListStyle::Margin:
581             key="margin-left";
582             value =QString::number(properties[id].toInt());
583             break;
584         case KoListStyle::TextIndent:
585             key="text-indent";
586             value =QString::number(properties[id].toInt());
587             break;
588         case KoListStyle::AlignmentMode:
589             key="label-alignment";
590             value=QString(properties[id].toBool()? "true":"false");
591             break;
592         case KoListStyle::LabelFollowedBy:
593             key="label-followed-by";
594             value =QString::number(properties[id].toInt());
595             break;
596         case KoListStyle::TabStopPosition:
597             key="tab-stop-position";
598             value =QString::number(properties[id].toInt());
599             break;
600         default:
601             break;
602         }
603         if (!key.isEmpty())
604             attrs.append(" ").append(key).append("=\"").append(value).append("\"");
605     }
606     return attrs;
607 }
608 
tableAttributes(const KoTableStyle & tableStyle)609 QString KoTextDebug::tableAttributes(const KoTableStyle &tableStyle)
610 {
611     QTextTableFormat format;
612     tableStyle.applyStyle(format);
613     return tableAttributes(format);
614 }
615 
tableAttributes(const QTextTableFormat & tableFormat)616 QString KoTextDebug::tableAttributes(const QTextTableFormat &tableFormat)
617 {
618     QString attrs;
619     KoStyleManager *styleManager = document ? KoTextDocument(document).styleManager() : 0;
620     if (styleManager) {
621         int id = tableFormat.intProperty(KoTableStyle::StyleId);
622         KoTableStyle *tableStyle = styleManager->tableStyle(id);
623         attrs.append(" tableStyle=\"id:").append(QString::number(id));
624         if (tableStyle)
625             attrs.append(" name:").append(tableStyle->name());
626         attrs.append("\"");
627     }
628 
629     QMap<int, QVariant> properties = tableFormat.properties();
630     foreach(int id, properties.keys()) {
631         QString key, value;
632         switch (id) {
633         case QTextTableFormat::TableColumnWidthConstraints:
634         case QTextFormat::BackgroundBrush:
635             key = "background";
636             value = qvariant_cast<QBrush>(properties[id]).color().name(); // beware!
637             break;
638         case QTextFormat::BlockAlignment:
639             key = "alignment";
640             switch (properties[id].toInt()) {
641                 case Qt::AlignLeft:
642                     value = "left";
643                     break;
644                 case Qt::AlignRight:
645                     value = "right";
646                     break;
647                 case Qt::AlignHCenter:
648                     value = "center";
649                     break;
650                 case Qt::AlignJustify:
651                     value = "justify";
652                     break;
653                 default:
654                     value.clear();
655                     break;
656             }
657             break;
658         case KoTableStyle::KeepWithNext:
659             key = "keep-with-next";
660             value = properties[id].toBool() ? "true" : "false";
661             break;
662         case KoTableStyle::BreakBefore:
663             key = "break-before";
664             value = properties[id].toBool() ? "true" : "false";
665             break;
666         case KoTableStyle::BreakAfter:
667             key = "break-after";
668             value = properties[id].toBool() ? "true" : "false";
669             break;
670         case KoTableStyle::MayBreakBetweenRows:
671             key = "may-break-between-rows";
672             value = properties[id].toBool() ? "true" : "false";
673             break;
674         case KoTableStyle::MasterPageName:
675             key = "master-page-name";
676             value = properties[id].toString();
677             break;
678         case QTextTableFormat::TableColumns:
679             key = "columns";
680             value = QString::number(properties[id].toInt());
681             break;
682         case QTextTableFormat::TableCellSpacing:
683             key = "cell-spacing";
684             value = QString::number(properties[id].toDouble());
685             break;
686         case QTextTableFormat::TableHeaderRowCount:
687             key = "header-row-count";
688             value = QString::number(properties[id].toInt());
689             break;
690         default:
691             break;
692         }
693         if (!key.isEmpty())
694             attrs.append(" ").append(key).append("=\"").append(value).append("\"");
695     }
696     return attrs;
697 }
698 
frameAttributes(const QTextFrameFormat & frameFormat)699 QString KoTextDebug::frameAttributes(const QTextFrameFormat &frameFormat)
700 {
701     QString attrs;
702 
703     QMap<int, QVariant> properties = frameFormat.properties();
704     foreach(int id, properties.keys()) {
705         QString key, value;
706         switch (id) {
707         case QTextFrameFormat::FrameBorderBrush:
708             break;
709         case QTextFrameFormat::FrameBorderStyle:
710             key = "border-style";
711             // determine border style.
712             switch (properties[id].toInt()) {
713             case QTextFrameFormat::BorderStyle_None:
714                 value = "None";
715                 break;
716             case QTextFrameFormat::BorderStyle_Dotted:
717                 value = "Dotted";
718                 break;
719             case QTextFrameFormat::BorderStyle_Dashed:
720                 value = "Dashed";
721                 break;
722             case QTextFrameFormat::BorderStyle_Solid:
723                 value = "Solid";
724                 break;
725             case QTextFrameFormat::BorderStyle_Double:
726                 value = "Double";
727                 break;
728             case QTextFrameFormat::BorderStyle_DotDash:
729                 value = "DotDash";
730                 break;
731             case QTextFrameFormat::BorderStyle_DotDotDash:
732                 value = "DotDotDash";
733                 break;
734             case QTextFrameFormat::BorderStyle_Groove:
735                 value = "Groove";
736                 break;
737             case QTextFrameFormat::BorderStyle_Ridge:
738                 value = "Ridge";
739                 break;
740             case QTextFrameFormat::BorderStyle_Inset:
741                 value = "Inset";
742                 break;
743             case QTextFrameFormat::BorderStyle_Outset:
744                 value = "Outset";
745                 break;
746             default:
747                 value = "Unknown";
748                 break;
749             }
750             break;
751         case QTextFrameFormat::FrameBorder:
752             key = "border";
753             value = QString::number(properties[id].toDouble());
754             break;
755         case QTextFrameFormat::FrameMargin:
756             key = "margin";
757             value = QString::number(properties[id].toDouble());
758             break;
759         case QTextFrameFormat::FramePadding:
760             key = "padding";
761             value = QString::number(properties[id].toDouble());
762             break;
763         case QTextFrameFormat::FrameWidth:
764             key = "width";
765             value = QString::number(properties[id].toDouble());
766             break;
767         case QTextFrameFormat::FrameHeight:
768             key = "height";
769             value = QString::number(properties[id].toDouble());
770             break;
771         case QTextFrameFormat::FrameTopMargin:
772             key = "top-margin";
773             value = QString::number(properties[id].toDouble());
774             break;
775         case QTextFrameFormat::FrameBottomMargin:
776             key = "bottom-margin";
777             value = QString::number(properties[id].toDouble());
778             break;
779         case QTextFrameFormat::FrameLeftMargin:
780             key = "left-margin";
781             value = QString::number(properties[id].toDouble());
782             break;
783         case QTextFrameFormat::FrameRightMargin:
784             key = "right-margin";
785             value = QString::number(properties[id].toDouble());
786             break;
787         default:
788             break;
789         }
790         if (!key.isEmpty())
791             attrs.append(" ").append(key).append("=\"").append(value).append("\"");
792     }
793     return attrs;
794 }
795 
tableCellAttributes(const KoTableCellStyle & tableCellStyle)796 QString KoTextDebug::tableCellAttributes(const KoTableCellStyle &tableCellStyle)
797 {
798     QTextTableCellFormat format;
799     tableCellStyle.applyStyle(format);
800     return tableCellAttributes(format);
801 }
802 
tableCellAttributes(const QTextTableCellFormat & tableCellFormat)803 QString KoTextDebug::tableCellAttributes(const QTextTableCellFormat &tableCellFormat)
804 {
805     QString attrs;
806     KoStyleManager *styleManager = document ? KoTextDocument(document).styleManager() : 0;
807     if (styleManager) {
808         int id = tableCellFormat.intProperty(KoTableCellStyle::StyleId);
809         KoTableCellStyle *tableCellStyle = styleManager->tableCellStyle(id);
810         attrs.append(" tableCellStyle=\"id:").append(QString::number(id));
811         if (tableCellStyle)
812             attrs.append(" name:").append(tableCellStyle->name());
813         attrs.append("\"");
814     }
815 
816     QMap<int, QVariant> properties = tableCellFormat.properties();
817     foreach(int id, properties.keys()) {
818         QString key, value;
819         switch (id) {
820         case QTextTableCellFormat::TableCellRowSpan:
821             key = "row-span";
822             value = QString::number(properties[id].toInt());
823             break;
824         case QTextTableCellFormat::TableCellColumnSpan:
825             key = "column-span";
826             value = QString::number(properties[id].toInt());
827             break;
828         case QTextFormat::TableCellTopPadding:
829             key = "top-padding";
830             value = QString::number(properties[id].toDouble());
831             break;
832         case QTextFormat::TableCellBottomPadding:
833             key = "bottom-padding";
834             value = QString::number(properties[id].toDouble());
835             break;
836         case QTextFormat::TableCellLeftPadding:
837             key = "left-padding";
838             value = QString::number(properties[id].toDouble());
839             break;
840         case QTextFormat::TableCellRightPadding:
841             key = "right-padding";
842             value = QString::number(properties[id].toDouble());
843             break;
844         case KoTableCellStyle::MasterPageName:
845             key = "master-page-name";
846             value = properties[id].toString();
847             break;
848         default:
849             break;
850         }
851         if (!key.isEmpty())
852             attrs.append(" ").append(key).append("=\"").append(value).append("\"");
853     }
854     return attrs;
855 }
856 
dumpFrame(const QTextFrame * frame,QTextStream & out)857 void KoTextDebug::dumpFrame(const QTextFrame *frame, QTextStream &out)
858 {
859     depth += INDENT;
860 
861     dumpIndent(depth);
862     out << "<frame" << frameAttributes(frame->frameFormat()) << '>' << endl;
863 
864     QTextFrame::iterator iterator = frame->begin();
865 
866     for (; !iterator.atEnd() && !iterator.atEnd(); ++iterator) {
867         QTextFrame *childFrame = iterator.currentFrame();
868         QTextBlock textBlock = iterator.currentBlock();
869 
870         if (childFrame) {
871             QTextTable *table = qobject_cast<QTextTable *>(childFrame);
872             if (table) {
873                 dumpTable(table, out);
874             } else {
875                 dumpFrame(frame, out);
876             }
877         } else if (textBlock.isValid()) {
878             dumpBlock(textBlock, out);
879         }
880     }
881 
882     dumpIndent(depth);
883     out << "</frame>" << endl;
884     depth -= INDENT;
885 }
886 
dumpBlock(const QTextBlock & block,QTextStream & out)887 void KoTextDebug::dumpBlock(const QTextBlock &block, QTextStream &out)
888 {
889     depth += INDENT;
890 
891     QString attrs;
892     attrs.append(paraAttributes(block.blockFormat()));
893     //attrs.append(" blockcharformat=\"").append(textAttributes(QTextCursor(block).blockCharFormat())).append('\"');
894     attrs.append(textAttributes(QTextCursor(block).blockCharFormat()));
895 
896     QTextList *list = block.textList();
897     if (list) {
898         attrs.append(" list=\"item:").append(QString::number(list->itemNumber(block) + 1)).append('/')
899         .append(QString::number(list->count()));
900         attrs.append('"');
901         attrs.append(listAttributes(list->format()));
902     }
903 
904     dumpIndent(depth);
905     out << "<block" << attrs << '>' << endl;
906 
907     QTextBlock::Iterator iterator = block.begin();
908     for (; !iterator.atEnd() && !iterator.atEnd(); ++iterator) {
909         QTextFragment fragment = iterator.fragment();
910         if (fragment.isValid()) {
911             dumpFragment(fragment, out);
912         }
913     }
914     dumpIndent(depth);
915     out << "</block>" << endl;
916     depth -= INDENT;
917     if (block.next().isValid())
918         out << ' ';
919 }
920 
dumpTable(const QTextTable * table,QTextStream & out)921 void KoTextDebug::dumpTable(const QTextTable *table, QTextStream &out)
922 {
923     depth += INDENT;
924 
925     QString attrs;
926     attrs.append(tableAttributes(table->format()));
927     attrs.append(frameAttributes(table->frameFormat())); // include frame attributes too.
928 
929     dumpIndent(depth);
930     out << "<table" << attrs << '>' << endl;
931 
932     // loop through all the cells in the table and dump the cells.
933     for (int row = 0; row < table->rows(); ++row) {
934         for (int column = 0; column < table->columns(); ++column) {
935             dumpTableCell(table->cellAt(row, column), out);
936         }
937     }
938 
939     dumpIndent(depth);
940     out << "</table>" << endl;
941     depth -= INDENT;
942 }
943 
dumpTableCell(const QTextTableCell & cell,QTextStream & out)944 void KoTextDebug::dumpTableCell(const QTextTableCell &cell, QTextStream &out)
945 {
946     depth += INDENT;
947 
948     QString attrs;
949     attrs.append(textAttributes(cell.format()));
950     attrs.append(tableCellAttributes(cell.format().toTableCellFormat()));
951 
952     dumpIndent(depth);
953     out << "<cell" << attrs << '>' << endl;
954 
955     // iterate through the cell content.
956     QTextFrame::iterator cellIter = cell.begin();
957     while (!cellIter.atEnd()) {
958         if (cellIter.currentFrame() != 0) {
959             // content is a frame or table.
960             dumpFrame(cellIter.currentFrame(), out);
961         } else {
962             // content is a block.
963             dumpBlock(cellIter.currentBlock(), out);
964         }
965         ++cellIter;
966     }
967 
968     dumpIndent(depth);
969     out << "</cell>\n";
970 
971     depth -= INDENT;
972 }
973 
dumpFragment(const QTextFragment & fragment,QTextStream & out)974 void KoTextDebug::dumpFragment(const QTextFragment &fragment, QTextStream &out)
975 {
976     depth += INDENT;
977 
978     QTextCharFormat charFormat = fragment.charFormat();
979     KoInlineObject *inlineObject = KoTextDocument(document).inlineTextObjectManager()->inlineTextObject(charFormat);
980     if (inlineObject) {
981         QString cf = inlineObjectAttributes(charFormat);
982 
983         dumpIndent(depth);
984         out << "<fragment" << cf << ">\n";
985     } else {
986         QString cf = textAttributes(charFormat);
987 
988         dumpIndent(depth);
989         out << "<fragment" << cf << ">\n";
990         dumpIndent(depth + INDENT);
991         out << '|' << fragment.text() << "|\n";
992         dumpIndent(depth);
993         out << "</fragment>\n";
994     }
995 
996     depth -= INDENT;
997 }
998 
999