qtextodfwriter.cpp

Absolute File Name:/home/qt/qt5_coco/qt5/qtbase/src/gui/text/qtextodfwriter.cpp
Source codeSwitch to Preprocessed file
LineSourceCount
1/****************************************************************************-
2**-
3** Copyright (C) 2016 The Qt Company Ltd.-
4** Contact: https://www.qt.io/licensing/-
5**-
6** This file is part of the QtGui module of the Qt Toolkit.-
7**-
8** $QT_BEGIN_LICENSE:LGPL$-
9** Commercial License Usage-
10** Licensees holding valid commercial Qt licenses may use this file in-
11** accordance with the commercial license agreement provided with the-
12** Software or, alternatively, in accordance with the terms contained in-
13** a written agreement between you and The Qt Company. For licensing terms-
14** and conditions see https://www.qt.io/terms-conditions. For further-
15** information use the contact form at https://www.qt.io/contact-us.-
16**-
17** GNU Lesser General Public License Usage-
18** Alternatively, this file may be used under the terms of the GNU Lesser-
19** General Public License version 3 as published by the Free Software-
20** Foundation and appearing in the file LICENSE.LGPL3 included in the-
21** packaging of this file. Please review the following information to-
22** ensure the GNU Lesser General Public License version 3 requirements-
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.-
24**-
25** GNU General Public License Usage-
26** Alternatively, this file may be used under the terms of the GNU-
27** General Public License version 2.0 or (at your option) the GNU General-
28** Public license version 3 or any later version approved by the KDE Free-
29** Qt Foundation. The licenses are as published by the Free Software-
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3-
31** included in the packaging of this file. Please review the following-
32** information to ensure the GNU General Public License requirements will-
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and-
34** https://www.gnu.org/licenses/gpl-3.0.html.-
35**-
36** $QT_END_LICENSE$-
37**-
38****************************************************************************/-
39-
40#include <qglobal.h>-
41-
42#ifndef QT_NO_TEXTODFWRITER-
43-
44#include "qtextodfwriter_p.h"-
45-
46#include <QImageWriter>-
47#include <QTextListFormat>-
48#include <QTextList>-
49#include <QBuffer>-
50#include <QUrl>-
51-
52#include "qtextdocument_p.h"-
53#include "qtexttable.h"-
54#include "qtextcursor.h"-
55#include "qtextimagehandler_p.h"-
56#include "qzipwriter_p.h"-
57-
58#include <QDebug>-
59-
60QT_BEGIN_NAMESPACE-
61-
62/// Convert pixels to postscript point units-
63static QString pixelToPoint(qreal pixels)-
64{-
65 // we hardcode 96 DPI, we do the same in the ODF importer to have a perfect roundtrip.-
66 return QString::number(pixels * 72 / 96) + QString::fromLatin1("pt");-
67}-
68-
69// strategies-
70class QOutputStrategy {-
71public:-
72 QOutputStrategy() : contentStream(0), counter(1) { }-
73 virtual ~QOutputStrategy() {}-
74 virtual void addFile(const QString &fileName, const QString &mimeType, const QByteArray &bytes) = 0;-
75-
76 QString createUniqueImageName()-
77 {-
78 return QString::fromLatin1("Pictures/Picture%1").arg(counter++);-
79 }-
80-
81 QIODevice *contentStream;-
82 int counter;-
83};-
84-
85class QXmlStreamStrategy : public QOutputStrategy {-
86public:-
87 QXmlStreamStrategy(QIODevice *device)-
88 {-
89 contentStream = device;-
90 }-
91-
92 virtual ~QXmlStreamStrategy()-
93 {-
94 if (contentStream)-
95 contentStream->close();-
96 }-
97 virtual void addFile(const QString &, const QString &, const QByteArray &) Q_DECL_OVERRIDE-
98 {-
99 // we ignore this...-
100 }-
101};-
102-
103class QZipStreamStrategy : public QOutputStrategy {-
104public:-
105 QZipStreamStrategy(QIODevice *device)-
106 : zip(device),-
107 manifestWriter(&manifest)-
108 {-
109 QByteArray mime("application/vnd.oasis.opendocument.text");-
110 zip.setCompressionPolicy(QZipWriter::NeverCompress);-
111 zip.addFile(QString::fromLatin1("mimetype"), mime); // for mime-magick-
112 zip.setCompressionPolicy(QZipWriter::AutoCompress);-
113 contentStream = &content;-
114 content.open(QIODevice::WriteOnly);-
115 manifest.open(QIODevice::WriteOnly);-
116-
117 manifestNS = QString::fromLatin1("urn:oasis:names:tc:opendocument:xmlns:manifest:1.0");-
118 // prettyfy-
119 manifestWriter.setAutoFormatting(true);-
120 manifestWriter.setAutoFormattingIndent(1);-
121-
122 manifestWriter.writeNamespace(manifestNS, QString::fromLatin1("manifest"));-
123 manifestWriter.writeStartDocument();-
124 manifestWriter.writeStartElement(manifestNS, QString::fromLatin1("manifest"));-
125 manifestWriter.writeAttribute(manifestNS, QString::fromLatin1("version"), QString::fromLatin1("1.2"));-
126 addFile(QString::fromLatin1("/"), QString::fromLatin1("application/vnd.oasis.opendocument.text"));-
127 addFile(QString::fromLatin1("content.xml"), QString::fromLatin1("text/xml"));-
128 }-
129-
130 ~QZipStreamStrategy()-
131 {-
132 manifestWriter.writeEndDocument();-
133 manifest.close();-
134 zip.addFile(QString::fromLatin1("META-INF/manifest.xml"), &manifest);-
135 content.close();-
136 zip.addFile(QString::fromLatin1("content.xml"), &content);-
137 zip.close();-
138 }-
139-
140 virtual void addFile(const QString &fileName, const QString &mimeType, const QByteArray &bytes) Q_DECL_OVERRIDE-
141 {-
142 zip.addFile(fileName, bytes);-
143 addFile(fileName, mimeType);-
144 }-
145-
146private:-
147 void addFile(const QString &fileName, const QString &mimeType)-
148 {-
149 manifestWriter.writeEmptyElement(manifestNS, QString::fromLatin1("file-entry"));-
150 manifestWriter.writeAttribute(manifestNS, QString::fromLatin1("media-type"), mimeType);-
151 manifestWriter.writeAttribute(manifestNS, QString::fromLatin1("full-path"), fileName);-
152 }-
153-
154 QBuffer content;-
155 QBuffer manifest;-
156 QZipWriter zip;-
157 QXmlStreamWriter manifestWriter;-
158 QString manifestNS;-
159};-
160-
161static QString bulletChar(QTextListFormat::Style style)-
162{-
163 switch(style) {-
164 case QTextListFormat::ListDisc:-
165 return QChar(0x25cf); // bullet character-
166 case QTextListFormat::ListCircle:-
167 return QChar(0x25cb); // white circle-
168 case QTextListFormat::ListSquare:-
169 return QChar(0x25a1); // white square-
170 case QTextListFormat::ListDecimal:-
171 return QString::fromLatin1("1");-
172 case QTextListFormat::ListLowerAlpha:-
173 return QString::fromLatin1("a");-
174 case QTextListFormat::ListUpperAlpha:-
175 return QString::fromLatin1("A");-
176 case QTextListFormat::ListLowerRoman:-
177 return QString::fromLatin1("i");-
178 case QTextListFormat::ListUpperRoman:-
179 return QString::fromLatin1("I");-
180 default:-
181 case QTextListFormat::ListStyleUndefined:-
182 return QString();-
183 }-
184}-
185-
186void QTextOdfWriter::writeFrame(QXmlStreamWriter &writer, const QTextFrame *frame)-
187{-
188 Q_ASSERT(frame);-
189 const QTextTable *table = qobject_cast<const QTextTable*> (frame);-
190-
191 if (table) { // Start a table.-
192 writer.writeStartElement(tableNS, QString::fromLatin1("table"));-
193 writer.writeEmptyElement(tableNS, QString::fromLatin1("table-column"));-
194 writer.writeAttribute(tableNS, QString::fromLatin1("number-columns-repeated"), QString::number(table->columns()));-
195 } else if (frame->document() && frame->document()->rootFrame() != frame) { // start a section-
196 writer.writeStartElement(textNS, QString::fromLatin1("section"));-
197 }-
198-
199 QTextFrame::iterator iterator = frame->begin();-
200 QTextFrame *child = 0;-
201-
202 int tableRow = -1;-
203 while (! iterator.atEnd()) {-
204 if (iterator.currentFrame() && child != iterator.currentFrame())-
205 writeFrame(writer, iterator.currentFrame());-
206 else { // no frame, its a block-
207 QTextBlock block = iterator.currentBlock();-
208 if (table) {-
209 QTextTableCell cell = table->cellAt(block.position());-
210 if (tableRow < cell.row()) {-
211 if (tableRow >= 0)-
212 writer.writeEndElement(); // close table row-
213 tableRow = cell.row();-
214 writer.writeStartElement(tableNS, QString::fromLatin1("table-row"));-
215 }-
216 writer.writeStartElement(tableNS, QString::fromLatin1("table-cell"));-
217 if (cell.columnSpan() > 1)-
218 writer.writeAttribute(tableNS, QString::fromLatin1("number-columns-spanned"), QString::number(cell.columnSpan()));-
219 if (cell.rowSpan() > 1)-
220 writer.writeAttribute(tableNS, QString::fromLatin1("number-rows-spanned"), QString::number(cell.rowSpan()));-
221 if (cell.format().isTableCellFormat()) {-
222 writer.writeAttribute(tableNS, QString::fromLatin1("style-name"), QString::fromLatin1("T%1").arg(cell.tableCellFormatIndex()));-
223 }-
224 }-
225 writeBlock(writer, block);-
226 if (table)-
227 writer.writeEndElement(); // table-cell-
228 }-
229 child = iterator.currentFrame();-
230 ++iterator;-
231 }-
232 if (tableRow >= 0)-
233 writer.writeEndElement(); // close table-row-
234-
235 if (table || (frame->document() && frame->document()->rootFrame() != frame))-
236 writer.writeEndElement(); // close table or section element-
237}-
238-
239void QTextOdfWriter::writeBlock(QXmlStreamWriter &writer, const QTextBlock &block)-
240{-
241 if (block.textList()) { // its a list-item-
242 const int listLevel = block.textList()->format().indent();-
243 if (m_listStack.isEmpty() || m_listStack.top() != block.textList()) {-
244 // not the same list we were in.-
245 while (m_listStack.count() >= listLevel && !m_listStack.isEmpty() && m_listStack.top() != block.textList() ) { // we need to close tags-
246 m_listStack.pop();-
247 writer.writeEndElement(); // list-
248 if (m_listStack.count())-
249 writer.writeEndElement(); // list-item-
250 }-
251 while (m_listStack.count() < listLevel) {-
252 if (m_listStack.count())-
253 writer.writeStartElement(textNS, QString::fromLatin1("list-item"));-
254 writer.writeStartElement(textNS, QString::fromLatin1("list"));-
255 if (m_listStack.count() == listLevel - 1) {-
256 m_listStack.push(block.textList());-
257 writer.writeAttribute(textNS, QString::fromLatin1("style-name"), QString::fromLatin1("L%1")-
258 .arg(block.textList()->formatIndex()));-
259 }-
260 else {-
261 m_listStack.push(0);-
262 }-
263 }-
264 }-
265 writer.writeStartElement(textNS, QString::fromLatin1("list-item"));-
266 }-
267 else {-
268 while (! m_listStack.isEmpty()) {-
269 m_listStack.pop();-
270 writer.writeEndElement(); // list-
271 if (m_listStack.count())-
272 writer.writeEndElement(); // list-item-
273 }-
274 }-
275-
276 if (block.length() == 1) { // only a linefeed-
277 writer.writeEmptyElement(textNS, QString::fromLatin1("p"));-
278 writer.writeAttribute(textNS, QString::fromLatin1("style-name"), QString::fromLatin1("p%1")-
279 .arg(block.blockFormatIndex()));-
280 if (block.textList())-
281 writer.writeEndElement(); // numbered-paragraph-
282 return;-
283 }-
284 writer.writeStartElement(textNS, QString::fromLatin1("p"));-
285 writer.writeAttribute(textNS, QString::fromLatin1("style-name"), QString::fromLatin1("p%1")-
286 .arg(block.blockFormatIndex()));-
287 for (QTextBlock::Iterator frag = block.begin(); !frag.atEnd(); ++frag) {-
288 bool isHyperlink = frag.fragment().charFormat().hasProperty(QTextFormat::AnchorHref);-
289 if (isHyperlink) {-
290 QString value = frag.fragment().charFormat().property(QTextFormat::AnchorHref).toString();-
291 writer.writeStartElement(textNS, QString::fromLatin1("a"));-
292 writer.writeAttribute(xlinkNS, QString::fromLatin1("href"), value);-
293 }-
294 writer.writeCharacters(QString()); // Trick to make sure that the span gets no linefeed in front of it.-
295 writer.writeStartElement(textNS, QString::fromLatin1("span"));-
296-
297 QString fragmentText = frag.fragment().text();-
298 if (fragmentText.length() == 1 && fragmentText[0] == 0xFFFC) { // its an inline character.-
299 writeInlineCharacter(writer, frag.fragment());-
300 writer.writeEndElement(); // span-
301 continue;-
302 }-
303-
304 writer.writeAttribute(textNS, QString::fromLatin1("style-name"), QString::fromLatin1("c%1")-
305 .arg(frag.fragment().charFormatIndex()));-
306 bool escapeNextSpace = true;-
307 int precedingSpaces = 0;-
308 int exportedIndex = 0;-
309 for (int i=0; i <= fragmentText.count(); ++i) {-
310 QChar character = fragmentText[i];-
311 bool isSpace = character.unicode() == ' ';-
312-
313 // find more than one space. -> <text:s text:c="2" />-
314 if (!isSpace && escapeNextSpace && precedingSpaces > 1) {-
315 const bool startParag = exportedIndex == 0 && i == precedingSpaces;-
316 if (!startParag)-
317 writer.writeCharacters(fragmentText.mid(exportedIndex, i - precedingSpaces + 1 - exportedIndex));-
318 writer.writeEmptyElement(textNS, QString::fromLatin1("s"));-
319 const int count = precedingSpaces - (startParag?0:1);-
320 if (count > 1)-
321 writer.writeAttribute(textNS, QString::fromLatin1("c"), QString::number(count));-
322 precedingSpaces = 0;-
323 exportedIndex = i;-
324 }-
325-
326 if (i < fragmentText.count()) {-
327 if (character.unicode() == 0x2028) { // soft-return-
328 //if (exportedIndex < i)-
329 writer.writeCharacters(fragmentText.mid(exportedIndex, i - exportedIndex));-
330 writer.writeEmptyElement(textNS, QString::fromLatin1("line-break"));-
331 exportedIndex = i+1;-
332 continue;-
333 } else if (character.unicode() == '\t') { // Tab-
334 //if (exportedIndex < i)-
335 writer.writeCharacters(fragmentText.mid(exportedIndex, i - exportedIndex));-
336 writer.writeEmptyElement(textNS, QString::fromLatin1("tab"));-
337 exportedIndex = i+1;-
338 precedingSpaces = 0;-
339 } else if (isSpace) {-
340 ++precedingSpaces;-
341 escapeNextSpace = true;-
342 } else if (!isSpace) {-
343 precedingSpaces = 0;-
344 }-
345 }-
346 }-
347-
348 writer.writeCharacters(fragmentText.mid(exportedIndex));-
349 writer.writeEndElement(); // span-
350 writer.writeCharacters(QString()); // Trick to make sure that the span gets no linefeed behind it.-
351 if (isHyperlink)-
352 writer.writeEndElement(); // a-
353 }-
354 writer.writeCharacters(QString()); // Trick to make sure that the span gets no linefeed behind it.-
355 writer.writeEndElement(); // p-
356 if (block.textList())-
357 writer.writeEndElement(); // list-item-
358}-
359-
360void QTextOdfWriter::writeInlineCharacter(QXmlStreamWriter &writer, const QTextFragment &fragment) const-
361{-
362 writer.writeStartElement(drawNS, QString::fromLatin1("frame"));-
363 if (m_strategy == 0) {-
364 // don't do anything.-
365 }-
366 else if (fragment.charFormat().isImageFormat()) {-
367 QTextImageFormat imageFormat = fragment.charFormat().toImageFormat();-
368 writer.writeAttribute(drawNS, QString::fromLatin1("name"), imageFormat.name());-
369-
370 // vvv Copy pasted mostly from Qt =================-
371 QImage image;-
372 QString name = imageFormat.name();-
373 if (name.startsWith(QLatin1String(":/"))) // auto-detect resources-
374 name.prepend(QLatin1String("qrc"));-
375 QUrl url = QUrl(name);-
376 const QVariant data = m_document->resource(QTextDocument::ImageResource, url);-
377 if (data.type() == QVariant::Image) {-
378 image = qvariant_cast<QImage>(data);-
379 } else if (data.type() == QVariant::ByteArray) {-
380 image.loadFromData(data.toByteArray());-
381 }-
382-
383 if (image.isNull()) {-
384 QString context;-
385 if (image.isNull()) { // try direct loading-
386 name = imageFormat.name(); // remove qrc:/ prefix again-
387 image.load(name);-
388 }-
389 }-
390-
391 // ^^^ Copy pasted mostly from Qt =================-
392 if (! image.isNull()) {-
393 QBuffer imageBytes;-
394 QImageWriter imageWriter(&imageBytes, "png");-
395 imageWriter.write(image);-
396 QString filename = m_strategy->createUniqueImageName();-
397 m_strategy->addFile(filename, QString::fromLatin1("image/png"), imageBytes.data());-
398-
399 // get the width/height from the format.-
400 qreal width = (imageFormat.hasProperty(QTextFormat::ImageWidth)) ? imageFormat.width() : image.width();-
401 writer.writeAttribute(svgNS, QString::fromLatin1("width"), pixelToPoint(width));-
402 qreal height = (imageFormat.hasProperty(QTextFormat::ImageHeight)) ? imageFormat.height() : image.height();-
403 writer.writeAttribute(svgNS, QString::fromLatin1("height"), pixelToPoint(height));-
404-
405 writer.writeStartElement(drawNS, QString::fromLatin1("image"));-
406 writer.writeAttribute(xlinkNS, QString::fromLatin1("href"), filename);-
407 writer.writeEndElement(); // image-
408 }-
409 }-
410-
411 writer.writeEndElement(); // frame-
412}-
413-
414void QTextOdfWriter::writeFormats(QXmlStreamWriter &writer, const QSet<int> &formats) const-
415{-
416 writer.writeStartElement(officeNS, QString::fromLatin1("automatic-styles"));-
417 QVector<QTextFormat> allStyles = m_document->allFormats();-
418 QSetIterator<int> formatId(formats);-
419 while(formatId.hasNext()) {-
420 int formatIndex = formatId.next();-
421 QTextFormat textFormat = allStyles.at(formatIndex);-
422 switch (textFormat.type()) {-
423 case QTextFormat::CharFormat:-
424 if (textFormat.isTableCellFormat())-
425 writeTableCellFormat(writer, textFormat.toTableCellFormat(), formatIndex);-
426 else-
427 writeCharacterFormat(writer, textFormat.toCharFormat(), formatIndex);-
428 break;-
429 case QTextFormat::BlockFormat:-
430 writeBlockFormat(writer, textFormat.toBlockFormat(), formatIndex);-
431 break;-
432 case QTextFormat::ListFormat:-
433 writeListFormat(writer, textFormat.toListFormat(), formatIndex);-
434 break;-
435 case QTextFormat::FrameFormat:-
436 writeFrameFormat(writer, textFormat.toFrameFormat(), formatIndex);-
437 break;-
438 case QTextFormat::TableFormat:-
439 ;break;-
440 }-
441 }-
442-
443 writer.writeEndElement(); // automatic-styles-
444}-
445-
446void QTextOdfWriter::writeBlockFormat(QXmlStreamWriter &writer, QTextBlockFormat format, int formatIndex) const-
447{-
448 writer.writeStartElement(styleNS, QString::fromLatin1("style"));-
449 writer.writeAttribute(styleNS, QString::fromLatin1("name"), QString::fromLatin1("p%1").arg(formatIndex));-
450 writer.writeAttribute(styleNS, QString::fromLatin1("family"), QString::fromLatin1("paragraph"));-
451 writer.writeStartElement(styleNS, QString::fromLatin1("paragraph-properties"));-
452-
453 if (format.hasProperty(QTextFormat::BlockAlignment)) {-
454 const Qt::Alignment alignment = format.alignment() & Qt::AlignHorizontal_Mask;-
455 QString value;-
456 if (alignment == Qt::AlignLeading)-
457 value = QString::fromLatin1("start");-
458 else if (alignment == Qt::AlignTrailing)-
459 value = QString::fromLatin1("end");-
460 else if (alignment == (Qt::AlignLeft | Qt::AlignAbsolute))-
461 value = QString::fromLatin1("left");-
462 else if (alignment == (Qt::AlignRight | Qt::AlignAbsolute))-
463 value = QString::fromLatin1("right");-
464 else if (alignment == Qt::AlignHCenter)-
465 value = QString::fromLatin1("center");-
466 else if (alignment == Qt::AlignJustify)-
467 value = QString::fromLatin1("justify");-
468 else-
469 qWarning() << "QTextOdfWriter: unsupported paragraph alignment; " << format.alignment();-
470 if (! value.isNull())-
471 writer.writeAttribute(foNS, QString::fromLatin1("text-align"), value);-
472 }-
473-
474 if (format.hasProperty(QTextFormat::BlockTopMargin))-
475 writer.writeAttribute(foNS, QString::fromLatin1("margin-top"), pixelToPoint(qMax(qreal(0.), format.topMargin())) );-
476 if (format.hasProperty(QTextFormat::BlockBottomMargin))-
477 writer.writeAttribute(foNS, QString::fromLatin1("margin-bottom"), pixelToPoint(qMax(qreal(0.), format.bottomMargin())) );-
478 if (format.hasProperty(QTextFormat::BlockLeftMargin) || format.hasProperty(QTextFormat::BlockIndent))-
479 writer.writeAttribute(foNS, QString::fromLatin1("margin-left"), pixelToPoint(qMax(qreal(0.),-
480 format.leftMargin() + format.indent())));-
481 if (format.hasProperty(QTextFormat::BlockRightMargin))-
482 writer.writeAttribute(foNS, QString::fromLatin1("margin-right"), pixelToPoint(qMax(qreal(0.), format.rightMargin())) );-
483 if (format.hasProperty(QTextFormat::TextIndent))-
484 writer.writeAttribute(foNS, QString::fromLatin1("text-indent"), pixelToPoint(format.textIndent()));-
485 if (format.hasProperty(QTextFormat::PageBreakPolicy)) {-
486 if (format.pageBreakPolicy() & QTextFormat::PageBreak_AlwaysBefore)-
487 writer.writeAttribute(foNS, QString::fromLatin1("break-before"), QString::fromLatin1("page"));-
488 if (format.pageBreakPolicy() & QTextFormat::PageBreak_AlwaysAfter)-
489 writer.writeAttribute(foNS, QString::fromLatin1("break-after"), QString::fromLatin1("page"));-
490 }-
491 if (format.hasProperty(QTextFormat::BackgroundBrush)) {-
492 QBrush brush = format.background();-
493 writer.writeAttribute(foNS, QString::fromLatin1("background-color"), brush.color().name());-
494 }-
495 if (format.hasProperty(QTextFormat::BlockNonBreakableLines))-
496 writer.writeAttribute(foNS, QString::fromLatin1("keep-together"),-
497 format.nonBreakableLines() ? QString::fromLatin1("true") : QString::fromLatin1("false"));-
498 if (format.hasProperty(QTextFormat::TabPositions)) {-
499 QList<QTextOption::Tab> tabs = format.tabPositions();-
500 writer.writeStartElement(styleNS, QString::fromLatin1("tab-stops"));-
501 QList<QTextOption::Tab>::Iterator iterator = tabs.begin();-
502 while(iterator != tabs.end()) {-
503 writer.writeEmptyElement(styleNS, QString::fromLatin1("tab-stop"));-
504 writer.writeAttribute(styleNS, QString::fromLatin1("position"), pixelToPoint(iterator->position) );-
505 QString type;-
506 switch(iterator->type) {-
507 case QTextOption::DelimiterTab: type = QString::fromLatin1("char"); break;-
508 case QTextOption::LeftTab: type = QString::fromLatin1("left"); break;-
509 case QTextOption::RightTab: type = QString::fromLatin1("right"); break;-
510 case QTextOption::CenterTab: type = QString::fromLatin1("center"); break;-
511 }-
512 writer.writeAttribute(styleNS, QString::fromLatin1("type"), type);-
513 if (iterator->delimiter != 0)-
514 writer.writeAttribute(styleNS, QString::fromLatin1("char"), iterator->delimiter);-
515 ++iterator;-
516 }-
517-
518 writer.writeEndElement(); // tab-stops-
519 }-
520-
521 writer.writeEndElement(); // paragraph-properties-
522 writer.writeEndElement(); // style-
523}-
524-
525void QTextOdfWriter::writeCharacterFormat(QXmlStreamWriter &writer, QTextCharFormat format, int formatIndex) const-
526{-
527 writer.writeStartElement(styleNS, QString::fromLatin1("style"));-
528 writer.writeAttribute(styleNS, QString::fromLatin1("name"), QString::fromLatin1("c%1").arg(formatIndex));-
529 writer.writeAttribute(styleNS, QString::fromLatin1("family"), QString::fromLatin1("text"));-
530 writer.writeEmptyElement(styleNS, QString::fromLatin1("text-properties"));-
531 if (format.fontItalic())-
532 writer.writeAttribute(foNS, QString::fromLatin1("font-style"), QString::fromLatin1("italic"));-
533 if (format.hasProperty(QTextFormat::FontWeight) && format.fontWeight() != QFont::Normal) {-
534 QString value;-
535 if (format.fontWeight() == QFont::Bold)-
536 value = QString::fromLatin1("bold");-
537 else-
538 value = QString::number(format.fontWeight() * 10);-
539 writer.writeAttribute(foNS, QString::fromLatin1("font-weight"), value);-
540 }-
541 if (format.hasProperty(QTextFormat::FontFamily))-
542 writer.writeAttribute(foNS, QString::fromLatin1("font-family"), format.fontFamily());-
543 else-
544 writer.writeAttribute(foNS, QString::fromLatin1("font-family"), QString::fromLatin1("Sans")); // Qt default-
545 if (format.hasProperty(QTextFormat::FontPointSize))-
546 writer.writeAttribute(foNS, QString::fromLatin1("font-size"), QString::fromLatin1("%1pt").arg(format.fontPointSize()));-
547 if (format.hasProperty(QTextFormat::FontCapitalization)) {-
548 switch(format.fontCapitalization()) {-
549 case QFont::MixedCase:-
550 writer.writeAttribute(foNS, QString::fromLatin1("text-transform"), QString::fromLatin1("none")); break;-
551 case QFont::AllUppercase:-
552 writer.writeAttribute(foNS, QString::fromLatin1("text-transform"), QString::fromLatin1("uppercase")); break;-
553 case QFont::AllLowercase:-
554 writer.writeAttribute(foNS, QString::fromLatin1("text-transform"), QString::fromLatin1("lowercase")); break;-
555 case QFont::Capitalize:-
556 writer.writeAttribute(foNS, QString::fromLatin1("text-transform"), QString::fromLatin1("capitalize")); break;-
557 case QFont::SmallCaps:-
558 writer.writeAttribute(foNS, QString::fromLatin1("font-variant"), QString::fromLatin1("small-caps")); break;-
559 }-
560 }-
561 if (format.hasProperty(QTextFormat::FontLetterSpacing))-
562 writer.writeAttribute(foNS, QString::fromLatin1("letter-spacing"), pixelToPoint(format.fontLetterSpacing()));-
563 if (format.hasProperty(QTextFormat::FontWordSpacing) && format.fontWordSpacing() != 0)-
564 writer.writeAttribute(foNS, QString::fromLatin1("word-spacing"), pixelToPoint(format.fontWordSpacing()));-
565 if (format.hasProperty(QTextFormat::FontUnderline))-
566 writer.writeAttribute(styleNS, QString::fromLatin1("text-underline-type"),-
567 format.fontUnderline() ? QString::fromLatin1("single") : QString::fromLatin1("none"));-
568 if (format.hasProperty(QTextFormat::FontOverline)) {-
569 // bool fontOverline () const TODO-
570 }-
571 if (format.hasProperty(QTextFormat::FontStrikeOut))-
572 writer.writeAttribute(styleNS,QString::fromLatin1( "text-line-through-type"),-
573 format.fontStrikeOut() ? QString::fromLatin1("single") : QString::fromLatin1("none"));-
574 if (format.hasProperty(QTextFormat::TextUnderlineColor))-
575 writer.writeAttribute(styleNS, QString::fromLatin1("text-underline-color"), format.underlineColor().name());-
576 if (format.hasProperty(QTextFormat::FontFixedPitch)) {-
577 // bool fontFixedPitch () const TODO-
578 }-
579 if (format.hasProperty(QTextFormat::TextUnderlineStyle)) {-
580 QString value;-
581 switch (format.underlineStyle()) {-
582 case QTextCharFormat::NoUnderline: value = QString::fromLatin1("none"); break;-
583 case QTextCharFormat::SingleUnderline: value = QString::fromLatin1("solid"); break;-
584 case QTextCharFormat::DashUnderline: value = QString::fromLatin1("dash"); break;-
585 case QTextCharFormat::DotLine: value = QString::fromLatin1("dotted"); break;-
586 case QTextCharFormat::DashDotLine: value = QString::fromLatin1("dash-dot"); break;-
587 case QTextCharFormat::DashDotDotLine: value = QString::fromLatin1("dot-dot-dash"); break;-
588 case QTextCharFormat::WaveUnderline: value = QString::fromLatin1("wave"); break;-
589 case QTextCharFormat::SpellCheckUnderline: value = QString::fromLatin1("none"); break;-
590 }-
591 writer.writeAttribute(styleNS, QString::fromLatin1("text-underline-style"), value);-
592 }-
593 if (format.hasProperty(QTextFormat::TextVerticalAlignment)) {-
594 QString value;-
595 switch (format.verticalAlignment()) {-
596 case QTextCharFormat::AlignMiddle:-
597 case QTextCharFormat::AlignNormal: value = QString::fromLatin1("0%"); break;-
598 case QTextCharFormat::AlignSuperScript: value = QString::fromLatin1("super"); break;-
599 case QTextCharFormat::AlignSubScript: value = QString::fromLatin1("sub"); break;-
600 case QTextCharFormat::AlignTop: value = QString::fromLatin1("100%"); break;-
601 case QTextCharFormat::AlignBottom : value = QString::fromLatin1("-100%"); break;-
602 case QTextCharFormat::AlignBaseline: break;-
603 }-
604 writer.writeAttribute(styleNS, QString::fromLatin1("text-position"), value);-
605 }-
606 if (format.hasProperty(QTextFormat::TextOutline))-
607 writer.writeAttribute(styleNS, QString::fromLatin1("text-outline"), QString::fromLatin1("true"));-
608 if (format.hasProperty(QTextFormat::TextToolTip)) {-
609 // QString toolTip () const TODO-
610 }-
611 if (format.hasProperty(QTextFormat::IsAnchor)) {-
612 // bool isAnchor () const TODO-
613 }-
614 if (format.hasProperty(QTextFormat::AnchorHref)) {-
615 // QString anchorHref () const TODO-
616 }-
617 if (format.hasProperty(QTextFormat::AnchorName)) {-
618 // QString anchorName () const TODO-
619 }-
620 if (format.hasProperty(QTextFormat::ForegroundBrush)) {-
621 QBrush brush = format.foreground();-
622 writer.writeAttribute(foNS, QString::fromLatin1("color"), brush.color().name());-
623 }-
624 if (format.hasProperty(QTextFormat::BackgroundBrush)) {-
625 QBrush brush = format.background();-
626 writer.writeAttribute(foNS, QString::fromLatin1("background-color"), brush.color().name());-
627 }-
628-
629 writer.writeEndElement(); // style-
630}-
631-
632void QTextOdfWriter::writeListFormat(QXmlStreamWriter &writer, QTextListFormat format, int formatIndex) const-
633{-
634 writer.writeStartElement(textNS, QString::fromLatin1("list-style"));-
635 writer.writeAttribute(styleNS, QString::fromLatin1("name"), QString::fromLatin1("L%1").arg(formatIndex));-
636-
637 QTextListFormat::Style style = format.style();-
638 if (style == QTextListFormat::ListDecimal || style == QTextListFormat::ListLowerAlpha-
639 || style == QTextListFormat::ListUpperAlpha-
640 || style == QTextListFormat::ListLowerRoman-
641 || style == QTextListFormat::ListUpperRoman) {-
642 writer.writeStartElement(textNS, QString::fromLatin1("list-level-style-number"));-
643 writer.writeAttribute(styleNS, QString::fromLatin1("num-format"), bulletChar(style));-
644-
645 if (format.hasProperty(QTextFormat::ListNumberSuffix))-
646 writer.writeAttribute(styleNS, QString::fromLatin1("num-suffix"), format.numberSuffix());-
647 else-
648 writer.writeAttribute(styleNS, QString::fromLatin1("num-suffix"), QString::fromLatin1("."));-
649-
650 if (format.hasProperty(QTextFormat::ListNumberPrefix))-
651 writer.writeAttribute(styleNS, QString::fromLatin1("num-prefix"), format.numberPrefix());-
652-
653 } else {-
654 writer.writeStartElement(textNS, QString::fromLatin1("list-level-style-bullet"));-
655 writer.writeAttribute(textNS, QString::fromLatin1("bullet-char"), bulletChar(style));-
656 }-
657-
658 writer.writeAttribute(textNS, QString::fromLatin1("level"), QString::number(format.indent()));-
659 writer.writeEmptyElement(styleNS, QString::fromLatin1("list-level-properties"));-
660 writer.writeAttribute(foNS, QString::fromLatin1("text-align"), QString::fromLatin1("start"));-
661 QString spacing = QString::fromLatin1("%1mm").arg(format.indent() * 8);-
662 writer.writeAttribute(textNS, QString::fromLatin1("space-before"), spacing);-
663 //writer.writeAttribute(textNS, QString::fromLatin1("min-label-width"), spacing);-
664-
665 writer.writeEndElement(); // list-level-style-*-
666 writer.writeEndElement(); // list-style-
667}-
668-
669void QTextOdfWriter::writeFrameFormat(QXmlStreamWriter &writer, QTextFrameFormat format, int formatIndex) const-
670{-
671 writer.writeStartElement(styleNS, QString::fromLatin1("style"));-
672 writer.writeAttribute(styleNS, QString::fromLatin1("name"), QString::fromLatin1("s%1").arg(formatIndex));-
673 writer.writeAttribute(styleNS, QString::fromLatin1("family"), QString::fromLatin1("section"));-
674 writer.writeEmptyElement(styleNS, QString::fromLatin1("section-properties"));-
675 if (format.hasProperty(QTextFormat::FrameTopMargin))-
676 writer.writeAttribute(foNS, QString::fromLatin1("margin-top"), pixelToPoint(qMax(qreal(0.), format.topMargin())) );-
677 if (format.hasProperty(QTextFormat::FrameBottomMargin))-
678 writer.writeAttribute(foNS, QString::fromLatin1("margin-bottom"), pixelToPoint(qMax(qreal(0.), format.bottomMargin())) );-
679 if (format.hasProperty(QTextFormat::FrameLeftMargin))-
680 writer.writeAttribute(foNS, QString::fromLatin1("margin-left"), pixelToPoint(qMax(qreal(0.), format.leftMargin())) );-
681 if (format.hasProperty(QTextFormat::FrameRightMargin))-
682 writer.writeAttribute(foNS, QString::fromLatin1("margin-right"), pixelToPoint(qMax(qreal(0.), format.rightMargin())) );-
683-
684 writer.writeEndElement(); // style-
685-
686// TODO consider putting the following properties in a qt-namespace.-
687// Position position () const-
688// qreal border () const-
689// QBrush borderBrush () const-
690// BorderStyle borderStyle () const-
691// qreal padding () const-
692// QTextLength width () const-
693// QTextLength height () const-
694// PageBreakFlags pageBreakPolicy () const-
695}-
696-
697void QTextOdfWriter::writeTableCellFormat(QXmlStreamWriter &writer, QTextTableCellFormat format, int formatIndex) const-
698{-
699 writer.writeStartElement(styleNS, QString::fromLatin1("style"));-
700 writer.writeAttribute(styleNS, QString::fromLatin1("name"), QString::fromLatin1("T%1").arg(formatIndex));-
701 writer.writeAttribute(styleNS, QString::fromLatin1("family"), QString::fromLatin1("table"));-
702 writer.writeEmptyElement(styleNS, QString::fromLatin1("table-properties"));-
703-
704-
705 qreal padding = format.topPadding();-
706 if (padding > 0 && padding == format.bottomPadding()-
707 && padding == format.leftPadding() && padding == format.rightPadding()) {-
708 writer.writeAttribute(foNS, QString::fromLatin1("padding"), pixelToPoint(padding));-
709 }-
710 else {-
711 if (padding > 0)-
712 writer.writeAttribute(foNS, QString::fromLatin1("padding-top"), pixelToPoint(padding));-
713 if (format.bottomPadding() > 0)-
714 writer.writeAttribute(foNS, QString::fromLatin1("padding-bottom"), pixelToPoint(format.bottomPadding()));-
715 if (format.leftPadding() > 0)-
716 writer.writeAttribute(foNS, QString::fromLatin1("padding-left"), pixelToPoint(format.leftPadding()));-
717 if (format.rightPadding() > 0)-
718 writer.writeAttribute(foNS, QString::fromLatin1("padding-right"), pixelToPoint(format.rightPadding()));-
719 }-
720-
721 if (format.hasProperty(QTextFormat::TextVerticalAlignment)) {-
722 QString pos;-
723 switch (format.verticalAlignment()) {-
724 case QTextCharFormat::AlignMiddle:-
725 pos = QString::fromLatin1("middle"); break;-
726 case QTextCharFormat::AlignTop:-
727 pos = QString::fromLatin1("top"); break;-
728 case QTextCharFormat::AlignBottom:-
729 pos = QString::fromLatin1("bottom"); break;-
730 default:-
731 pos = QString::fromLatin1("automatic"); break;-
732 }-
733 writer.writeAttribute(styleNS, QString::fromLatin1("vertical-align"), pos);-
734 }-
735-
736 // TODO-
737 // ODF just search for style-table-cell-properties-attlist)-
738 // QTextFormat::BackgroundImageUrl-
739 // format.background-
740 // QTextFormat::FrameBorder-
741-
742 writer.writeEndElement(); // style-
743}-
744-
745///////////////////////-
746-
747QTextOdfWriter::QTextOdfWriter(const QTextDocument &document, QIODevice *device)-
748 : officeNS (QLatin1String("urn:oasis:names:tc:opendocument:xmlns:office:1.0")),-
749 textNS (QLatin1String("urn:oasis:names:tc:opendocument:xmlns:text:1.0")),-
750 styleNS (QLatin1String("urn:oasis:names:tc:opendocument:xmlns:style:1.0")),-
751 foNS (QLatin1String("urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0")),-
752 tableNS (QLatin1String("urn:oasis:names:tc:opendocument:xmlns:table:1.0")),-
753 drawNS (QLatin1String("urn:oasis:names:tc:opendocument:xmlns:drawing:1.0")),-
754 xlinkNS (QLatin1String("http://www.w3.org/1999/xlink")),-
755 svgNS (QLatin1String("urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0")),-
756 m_document(&document),-
757 m_device(device),-
758 m_strategy(0),-
759 m_codec(0),-
760 m_createArchive(true)-
761{-
762}-
763-
764bool QTextOdfWriter::writeAll()-
765{-
766 if (m_createArchive)
m_createArchiveDescription
TRUEnever evaluated
FALSEnever evaluated
0
767 m_strategy = new QZipStreamStrategy(m_device);
never executed: m_strategy = new QZipStreamStrategy(m_device);
0
768 else-
769 m_strategy = new QXmlStreamStrategy(m_device);
never executed: m_strategy = new QXmlStreamStrategy(m_device);
0
770-
771 if (!m_device->isWritable() && ! m_device->open(QIODevice::WriteOnly)) {
!m_device->isWritable()Description
TRUEnever evaluated
FALSEnever evaluated
! m_device->op...ce::WriteOnly)Description
TRUEnever evaluated
FALSEnever evaluated
0
772 qWarning() << ("QTextOdfWriter::writeAll: the device can not be opened for writing";);-
773 return false;
never executed: return false;
0
774 }-
775 QXmlStreamWriter writer(m_strategy->contentStream);-
776#ifndef QT_NO_TEXTCODEC-
777 if (m_codec)
m_codecDescription
TRUEnever evaluated
FALSEnever evaluated
0
778 writer.setCodec(m_codec);
never executed: writer.setCodec(m_codec);
0
779#endif-
780 // prettyfy-
781 writer.setAutoFormatting(true);-
782 writer.setAutoFormattingIndent(2);-
783-
784 writer.writeNamespace(officeNS, QString::fromLatin1("office"));-
785 writer.writeNamespace(textNS, QString::fromLatin1("text"));-
786 writer.writeNamespace(styleNS, QString::fromLatin1("style"));-
787 writer.writeNamespace(foNS, QString::fromLatin1("fo"));-
788 writer.writeNamespace(tableNS, QString::fromLatin1("table"));-
789 writer.writeNamespace(drawNS, QString::fromLatin1("draw"));-
790 writer.writeNamespace(xlinkNS, QString::fromLatin1("xlink"));-
791 writer.writeNamespace(svgNS, QString::fromLatin1("svg"));-
792 writer.writeStartDocument();-
793 writer.writeStartElement(officeNS, QString::fromLatin1("document-content"));-
794 writer.writeAttribute(officeNS, QString::fromLatin1("version"), QString::fromLatin1("1.2"));-
795-
796 // add fragments. (for character formats)-
797 QTextDocumentPrivate::FragmentIterator fragIt = m_document->docHandle()->begin();-
798 QSet<int> formats;-
799 while (fragIt != m_document->docHandle()->end()) {
fragIt != m_do...andle()->end()Description
TRUEnever evaluated
FALSEnever evaluated
0
800 const QTextFragmentData * const frag = fragIt.value();-
801 formats << frag->format;-
802 ++fragIt;-
803 }
never executed: end of block
0
804-
805 // add blocks (for blockFormats)-
806 QTextDocumentPrivate::BlockMap &blocks = m_document->docHandle()->blockMap();-
807 QTextDocumentPrivate::BlockMap::Iterator blockIt = blocks.begin();-
808 while (blockIt != blocks.end()) {
blockIt != blocks.end()Description
TRUEnever evaluated
FALSEnever evaluated
0
809 const QTextBlockData * const block = blockIt.value();-
810 formats << block->format;-
811 ++blockIt;-
812 }
never executed: end of block
0
813-
814 // add objects for lists, frames and tables-
815 const QVector<QTextFormat> allFormats = m_document->allFormats();-
816 const QList<int> copy = formats.toList();-
817 for (QList<int>::Iterator iter = copy.begin(); iter !=auto index : copy.end(); ++iter) {-
818 QTextObject *object = m_document->objectForFormat(allFormats[*iter[index]);-
819 if (object)
objectDescription
TRUEnever evaluated
FALSEnever evaluated
0
820 formats << object->formatIndex();
never executed: formats << object->formatIndex();
0
821 }
never executed: end of block
0
822-
823 writeFormats(writer, formats);-
824-
825 writer.writeStartElement(officeNS, QString::fromLatin1("body"));-
826 writer.writeStartElement(officeNS, QString::fromLatin1("text"));-
827 QTextFrame *rootFrame = m_document->rootFrame();-
828 writeFrame(writer, rootFrame);-
829 writer.writeEndElement(); // text-
830 writer.writeEndElement(); // body-
831 writer.writeEndElement(); // document-content-
832 writer.writeEndDocument();-
833 delete m_strategy;-
834 m_strategy = 0;-
835-
836 return true;
never executed: return true;
0
837}-
838-
839QT_END_NAMESPACE-
840-
841#endif // QT_NO_TEXTODFWRITER-
Source codeSwitch to Preprocessed file

Generated by Squish Coco Non-Commercial 4.3.0-BETA-master-30-08-2018-4cb69e9