185void QTextOdfWriter::writeFrame(QXmlStreamWriter &writer,
const QTextFrame *frame)
188 const QTextTable *table = qobject_cast<
const QTextTable*> (frame);
191 writer.writeStartElement(tableNS, QString::fromLatin1(
"table"));
192 writer.writeAttribute(tableNS, QString::fromLatin1(
"style-name"),
193 QString::fromLatin1(
"Table%1").arg(table->formatIndex()));
195 if (m_tableFormatsWithColWidthConstraints.contains(table->formatIndex())) {
196 for (
int colit = 0; colit < table->columns(); ++colit) {
197 writer.writeStartElement(tableNS, QString::fromLatin1(
"table-column"));
198 writer.writeAttribute(tableNS, QString::fromLatin1(
"style-name"),
199 QString::fromLatin1(
"Table%1.%2").arg(table->formatIndex()).arg(colit));
200 writer.writeEndElement();
203 writer.writeEmptyElement(tableNS, QString::fromLatin1(
"table-column"));
204 writer.writeAttribute(tableNS, QString::fromLatin1(
"number-columns-repeated"),
205 QString::number(table->columns()));
207 }
else if (frame->document() && frame->document()->rootFrame() != frame) {
208 writer.writeStartElement(textNS, QString::fromLatin1(
"section"));
211 QTextFrame::iterator iterator = frame->begin();
212 QTextFrame *child =
nullptr;
215 while (! iterator.atEnd()) {
216 if (iterator.currentFrame() && child != iterator.currentFrame())
217 writeFrame(writer, iterator.currentFrame());
219 QTextBlock block = iterator.currentBlock();
221 QTextTableCell cell = table->cellAt(block.position());
222 if (tableRow < cell.row()) {
224 writer.writeEndElement();
225 tableRow = cell.row();
226 writer.writeStartElement(tableNS, QString::fromLatin1(
"table-row"));
228 writer.writeStartElement(tableNS, QString::fromLatin1(
"table-cell"));
229 if (cell.columnSpan() > 1)
230 writer.writeAttribute(tableNS, QString::fromLatin1(
"number-columns-spanned"), QString::number(cell.columnSpan()));
231 if (cell.rowSpan() > 1)
232 writer.writeAttribute(tableNS, QString::fromLatin1(
"number-rows-spanned"), QString::number(cell.rowSpan()));
233 if (cell.format().isTableCellFormat()) {
234 writer.writeAttribute(tableNS,
"style-name"_L1,
235 QString::fromLatin1(
"T%1").arg(cell.tableCellFormatIndex()));
238 writeBlock(writer, block);
240 writer.writeEndElement();
242 child = iterator.currentFrame();
246 writer.writeEndElement();
248 if (table || (frame->document() && frame->document()->rootFrame() != frame))
249 writer.writeEndElement();
252void QTextOdfWriter::writeBlock(QXmlStreamWriter &writer,
const QTextBlock &block)
254 if (block.textList()) {
255 const int listLevel = block.textList()->format().indent();
256 if (m_listStack.isEmpty() || m_listStack.top() != block.textList()) {
258 while (m_listStack.size() >= listLevel && !m_listStack.isEmpty() && m_listStack.top() != block.textList() ) {
260 writer.writeEndElement();
261 if (m_listStack.size())
262 writer.writeEndElement();
264 while (m_listStack.size() < listLevel) {
265 if (m_listStack.size())
266 writer.writeStartElement(textNS, QString::fromLatin1(
"list-item"));
267 writer.writeStartElement(textNS, QString::fromLatin1(
"list"));
268 if (m_listStack.size() == listLevel - 1) {
269 m_listStack.push(block.textList());
270 writer.writeAttribute(textNS, QString::fromLatin1(
"style-name"), QString::fromLatin1(
"L%1")
271 .arg(block.textList()->formatIndex()));
274 m_listStack.push(
nullptr);
278 writer.writeStartElement(textNS, QString::fromLatin1(
"list-item"));
281 while (! m_listStack.isEmpty()) {
283 writer.writeEndElement();
284 if (m_listStack.size())
285 writer.writeEndElement();
289 if (block.length() == 1) {
290 writer.writeEmptyElement(textNS, QString::fromLatin1(
"p"));
291 writer.writeAttribute(textNS, QString::fromLatin1(
"style-name"), QString::fromLatin1(
"p%1")
292 .arg(block.blockFormatIndex()));
293 if (block.textList())
294 writer.writeEndElement();
297 writer.writeStartElement(textNS, QString::fromLatin1(
"p"));
298 writer.writeAttribute(textNS, QString::fromLatin1(
"style-name"), QString::fromLatin1(
"p%1")
299 .arg(block.blockFormatIndex()));
300 for (QTextBlock::Iterator frag = block.begin(); !frag.atEnd(); ++frag) {
301 bool isHyperlink = frag.fragment().charFormat().hasProperty(QTextFormat::AnchorHref);
303 QString value = frag.fragment().charFormat().property(QTextFormat::AnchorHref).toString();
304 writer.writeStartElement(textNS, QString::fromLatin1(
"a"));
305 writer.writeAttribute(xlinkNS, QString::fromLatin1(
"href"), value);
307 writer.writeCharacters(QString());
308 writer.writeStartElement(textNS, QString::fromLatin1(
"span"));
310 QString fragmentText = frag.fragment().text();
311 if (fragmentText.size() == 1 && fragmentText[0] == u'\xFFFC') {
312 writeInlineCharacter(writer, frag.fragment());
313 writer.writeEndElement();
317 writer.writeAttribute(textNS, QString::fromLatin1(
"style-name"), QString::fromLatin1(
"c%1")
318 .arg(frag.fragment().charFormatIndex()));
319 bool escapeNextSpace =
true;
320 int precedingSpaces = 0;
321 int exportedIndex = 0;
322 for (
int i=0; i <= fragmentText.size(); ++i) {
323 QChar character = (i == fragmentText.size() ? QChar() : fragmentText.at(i));
324 bool isSpace = character.unicode() ==
' ';
327 if (!isSpace && escapeNextSpace && precedingSpaces > 1) {
328 const bool startParag = exportedIndex == 0 && i == precedingSpaces;
330 writer.writeCharacters(fragmentText.mid(exportedIndex, i - precedingSpaces + 1 - exportedIndex));
331 writer.writeEmptyElement(textNS, QString::fromLatin1(
"s"));
332 const int count = precedingSpaces - (startParag?0:1);
334 writer.writeAttribute(textNS, QString::fromLatin1(
"c"), QString::number(count));
339 if (i < fragmentText.size()) {
340 if (character.unicode() == 0x2028) {
342 writer.writeCharacters(fragmentText.mid(exportedIndex, i - exportedIndex));
345 writer.writeEmptyElement(textNS, QString::fromLatin1(
"tab"));
346 writer.writeEmptyElement(textNS, QString::fromLatin1(
"line-break"));
349 }
else if (character.unicode() ==
'\t') {
351 writer.writeCharacters(fragmentText.mid(exportedIndex, i - exportedIndex));
352 writer.writeEmptyElement(textNS, QString::fromLatin1(
"tab"));
355 }
else if (isSpace) {
357 escapeNextSpace =
true;
358 }
else if (!isSpace) {
364 writer.writeCharacters(fragmentText.mid(exportedIndex));
365 writer.writeEndElement();
366 writer.writeCharacters(QString());
368 writer.writeEndElement();
370 writer.writeCharacters(QString());
371 writer.writeEndElement();
372 if (block.textList())
373 writer.writeEndElement();
399void QTextOdfWriter::writeInlineCharacter(QXmlStreamWriter &writer,
const QTextFragment &fragment)
const
401 writer.writeStartElement(drawNS, QString::fromLatin1(
"frame"));
402 if (m_strategy ==
nullptr) {
405 else if (fragment.charFormat().isImageFormat()) {
406 QTextImageFormat imageFormat = fragment.charFormat().toImageFormat();
407 writer.writeAttribute(drawNS, QString::fromLatin1(
"name"), imageFormat.name());
415 QString name = imageFormat.name();
416 if (name.startsWith(
":/"_L1))
417 name.prepend(
"qrc"_L1);
418 QUrl url = QUrl(name);
419 const QVariant variant = m_document->resource(QTextDocument::ImageResource, url);
420 if (variant.userType() == QMetaType::QPixmap || variant.userType() == QMetaType::QImage) {
421 image = qvariant_cast<QImage>(variant);
422 }
else if (variant.userType() == QMetaType::QByteArray) {
423 data = variant.toByteArray();
425 QBuffer buffer(&data);
426 buffer.open(QIODevice::ReadOnly);
427 probeImageData(&buffer, &image, &mimeType, &width, &height);
430 QFile file(imageFormat.name());
431 if (file.open(QIODevice::ReadOnly) && !probeImageData(&file, &image, &mimeType, &width, &height)) {
433 data = file.readAll();
437 if (! image.isNull()) {
440 int imgQuality = imageFormat.quality();
441 if (imgQuality >= 100 || imgQuality <= 0 || image.hasAlphaChannel()) {
442 QImageWriter imageWriter(&imageBytes,
"png");
443 imageWriter.write(image);
445 data = imageBytes.data();
446 mimeType = QStringLiteral(
"image/png");
449 QImageWriter imageWriter(&imageBytes,
"jpg");
450 imageWriter.setQuality(imgQuality);
451 imageWriter.write(image);
453 data = imageBytes.data();
454 mimeType = QStringLiteral(
"image/jpg");
457 width = image.width();
458 height = image.height();
461 if (!data.isEmpty()) {
462 if (imageFormat.hasProperty(QTextFormat::ImageWidth)) {
463 width = imageFormat.width();
465 if (imageFormat.hasProperty(QTextFormat::ImageHeight)) {
466 height = imageFormat.height();
469 QString filename = m_strategy->createUniqueImageName();
471 m_strategy->addFile(filename, mimeType, data);
473 writer.writeAttribute(svgNS, QString::fromLatin1(
"width"), pixelToPoint(width));
474 writer.writeAttribute(svgNS, QString::fromLatin1(
"height"), pixelToPoint(height));
475 writer.writeAttribute(textNS, QStringLiteral(
"anchor-type"), QStringLiteral(
"as-char"));
476 writer.writeStartElement(drawNS, QString::fromLatin1(
"image"));
477 writer.writeAttribute(xlinkNS, QString::fromLatin1(
"href"), filename);
478 writer.writeEndElement();
481 writer.writeEndElement();
484void QTextOdfWriter::writeFormats(QXmlStreamWriter &writer,
const QSet<
int> &formats)
const
486 writer.writeStartElement(officeNS, QString::fromLatin1(
"automatic-styles"));
487 QList<QTextFormat> allStyles = m_document->allFormats();
488 for (
int formatIndex : formats) {
489 QTextFormat textFormat = allStyles.at(formatIndex);
490 switch (textFormat.type()) {
491 case QTextFormat::CharFormat:
492 if (textFormat.isTableCellFormat())
493 writeTableCellFormat(writer, textFormat.toTableCellFormat(), formatIndex, allStyles);
495 writeCharacterFormat(writer, textFormat.toCharFormat(), formatIndex);
497 case QTextFormat::BlockFormat:
498 writeBlockFormat(writer, textFormat.toBlockFormat(), formatIndex);
500 case QTextFormat::ListFormat:
501 writeListFormat(writer, textFormat.toListFormat(), formatIndex);
503 case QTextFormat::FrameFormat:
504 if (textFormat.isTableFormat())
505 writeTableFormat(writer, textFormat.toTableFormat(), formatIndex);
507 writeFrameFormat(writer, textFormat.toFrameFormat(), formatIndex);
512 writer.writeEndElement();
515void QTextOdfWriter::writeBlockFormat(QXmlStreamWriter &writer,
const QTextBlockFormat &format,
int formatIndex)
const
517 writer.writeStartElement(styleNS, QString::fromLatin1(
"style"));
518 writer.writeAttribute(styleNS, QString::fromLatin1(
"name"), QString::fromLatin1(
"p%1").arg(formatIndex));
519 writer.writeAttribute(styleNS, QString::fromLatin1(
"family"), QString::fromLatin1(
"paragraph"));
520 writer.writeStartElement(styleNS, QString::fromLatin1(
"paragraph-properties"));
522 if (format.hasProperty(QTextBlockFormat::LineHeightType)) {
523 const int blockLineHeightType = format.lineHeightType();
524 const qreal blockLineHeight = format.lineHeight();
526 switch (blockLineHeightType) {
527 case QTextBlockFormat::SingleHeight:
528 type = QString::fromLatin1(
"line-height");
529 value = QString::fromLatin1(
"100%");
531 case QTextBlockFormat::ProportionalHeight:
532 type = QString::fromLatin1(
"line-height");
533 value = QString::number(blockLineHeight) + QString::fromLatin1(
"%");
535 case QTextBlockFormat::FixedHeight:
536 type = QString::fromLatin1(
"line-height");
537 value = pixelToPoint(qMax(qreal(0.), blockLineHeight));
539 case QTextBlockFormat::MinimumHeight:
540 type = QString::fromLatin1(
"line-height-at-least");
541 value = pixelToPoint(qMax(qreal(0.), blockLineHeight));
543 case QTextBlockFormat::LineDistanceHeight:
544 type = QString::fromLatin1(
"line-spacing");
545 value = pixelToPoint(qMax(qreal(0.), blockLineHeight));
549 writer.writeAttribute(styleNS, type, value);
552 if (format.hasProperty(QTextFormat::BlockAlignment)) {
553 const Qt::Alignment alignment = format.alignment() & Qt::AlignHorizontal_Mask;
555 if (alignment == Qt::AlignLeading)
556 value = QString::fromLatin1(
"start");
557 else if (alignment == Qt::AlignTrailing)
558 value = QString::fromLatin1(
"end");
559 else if (alignment == (Qt::AlignLeft | Qt::AlignAbsolute))
560 value = QString::fromLatin1(
"left");
561 else if (alignment == (Qt::AlignRight | Qt::AlignAbsolute))
562 value = QString::fromLatin1(
"right");
563 else if (alignment == Qt::AlignHCenter)
564 value = QString::fromLatin1(
"center");
565 else if (alignment == Qt::AlignJustify)
566 value = QString::fromLatin1(
"justify");
568 qWarning() <<
"QTextOdfWriter: unsupported paragraph alignment; " << format.alignment();
569 if (! value.isNull())
570 writer.writeAttribute(foNS, QString::fromLatin1(
"text-align"), value);
573 if (format.hasProperty(QTextFormat::BlockTopMargin))
574 writer.writeAttribute(foNS, QString::fromLatin1(
"margin-top"), pixelToPoint(qMax(qreal(0.), format.topMargin())) );
575 if (format.hasProperty(QTextFormat::BlockBottomMargin))
576 writer.writeAttribute(foNS, QString::fromLatin1(
"margin-bottom"), pixelToPoint(qMax(qreal(0.), format.bottomMargin())) );
577 if (format.hasProperty(QTextFormat::BlockLeftMargin) || format.hasProperty(QTextFormat::BlockIndent))
578 writer.writeAttribute(foNS, QString::fromLatin1(
"margin-left"), pixelToPoint(qMax(qreal(0.),
579 format.leftMargin() + format.indent())));
580 if (format.hasProperty(QTextFormat::BlockRightMargin))
581 writer.writeAttribute(foNS, QString::fromLatin1(
"margin-right"), pixelToPoint(qMax(qreal(0.), format.rightMargin())) );
582 if (format.hasProperty(QTextFormat::TextIndent))
583 writer.writeAttribute(foNS, QString::fromLatin1(
"text-indent"), pixelToPoint(format.textIndent()));
584 if (format.hasProperty(QTextFormat::PageBreakPolicy)) {
585 if (format.pageBreakPolicy() & QTextFormat::PageBreak_AlwaysBefore)
586 writer.writeAttribute(foNS, QString::fromLatin1(
"break-before"), QString::fromLatin1(
"page"));
587 if (format.pageBreakPolicy() & QTextFormat::PageBreak_AlwaysAfter)
588 writer.writeAttribute(foNS, QString::fromLatin1(
"break-after"), QString::fromLatin1(
"page"));
590 if (format.hasProperty(QTextFormat::BackgroundBrush)) {
591 QBrush brush = format.background();
592 writer.writeAttribute(foNS, QString::fromLatin1(
"background-color"), brush.color().name());
594 if (format.hasProperty(QTextFormat::BlockNonBreakableLines))
595 writer.writeAttribute(foNS, QString::fromLatin1(
"keep-together"),
596 format.nonBreakableLines() ? QString::fromLatin1(
"true") : QString::fromLatin1(
"false"));
597 if (format.hasProperty(QTextFormat::TabPositions)) {
598 QList<QTextOption::Tab> tabs = format.tabPositions();
599 writer.writeStartElement(styleNS, QString::fromLatin1(
"tab-stops"));
600 QList<QTextOption::Tab>::Iterator iterator = tabs.begin();
601 while(iterator != tabs.end()) {
602 writer.writeEmptyElement(styleNS, QString::fromLatin1(
"tab-stop"));
603 writer.writeAttribute(styleNS, QString::fromLatin1(
"position"), pixelToPoint(iterator->position) );
605 switch(iterator->type) {
606 case QTextOption::DelimiterTab: type = QString::fromLatin1(
"char");
break;
607 case QTextOption::LeftTab: type = QString::fromLatin1(
"left");
break;
608 case QTextOption::RightTab: type = QString::fromLatin1(
"right");
break;
609 case QTextOption::CenterTab: type = QString::fromLatin1(
"center");
break;
611 writer.writeAttribute(styleNS, QString::fromLatin1(
"type"), type);
612 if (!iterator->delimiter.isNull())
613 writer.writeAttribute(styleNS, QString::fromLatin1(
"char"), iterator->delimiter);
617 writer.writeEndElement();
620 writer.writeEndElement();
621 writer.writeEndElement();
624void QTextOdfWriter::writeCharacterFormat(QXmlStreamWriter &writer,
const QTextCharFormat &format,
int formatIndex)
const
626 writer.writeStartElement(styleNS, QString::fromLatin1(
"style"));
627 writer.writeAttribute(styleNS, QString::fromLatin1(
"name"), QString::fromLatin1(
"c%1").arg(formatIndex));
628 writer.writeAttribute(styleNS, QString::fromLatin1(
"family"), QString::fromLatin1(
"text"));
629 writer.writeEmptyElement(styleNS, QString::fromLatin1(
"text-properties"));
631 const QFont defaultFont = m_document->defaultFont();
632 const uint defaultFontResolveMask = defaultFont.resolveMask();
634 if (format.hasProperty(QTextFormat::FontItalic)
635 || (defaultFontResolveMask & QFont::StyleResolved)) {
636 const bool italic = format.hasProperty(QTextFormat::FontItalic) ? format.fontItalic() : defaultFont.italic();
638 writer.writeAttribute(foNS, QString::fromLatin1(
"font-style"), QString::fromLatin1(
"italic"));
641 if (format.hasProperty(QTextFormat::FontWeight)
642 || (defaultFontResolveMask & QFont::WeightResolved)) {
643 int weight = format.hasProperty(QTextFormat::FontWeight)
644 ? format.fontWeight()
645 : defaultFont.weight();
647 if (weight != QFont::Normal) {
649 if (weight == QFont::Bold)
650 value = QString::fromLatin1(
"bold");
652 value = QString::number(weight);
653 writer.writeAttribute(foNS, QString::fromLatin1(
"font-weight"), value);
657 if (format.hasProperty(QTextFormat::OldFontFamily)
658 || format.hasProperty(QTextFormat::FontFamilies)
659 || (defaultFontResolveMask & QFont::FamiliesResolved)) {
660 const QString fontFamily = (format.hasProperty(QTextFormat::OldFontFamily)
661 || format.hasProperty(QTextFormat::FontFamilies))
662 ? format.fontFamilies().toStringList().value(0, QString())
663 : defaultFont.family();
664 writer.writeAttribute(foNS, QString::fromLatin1(
"font-family"), fontFamily);
666 writer.writeAttribute(foNS, QString::fromLatin1(
"font-family"), QString::fromLatin1(
"Sans"));
669 if (format.hasProperty(QTextFormat::FontPointSize)
670 || (defaultFontResolveMask & QFont::SizeResolved)) {
671 const qreal pointSize = format.hasProperty(QTextFormat::FontPointSize)
672 ? format.fontPointSize()
673 : defaultFont.pointSizeF();
674 writer.writeAttribute(foNS, QString::fromLatin1(
"font-size"), QString::fromLatin1(
"%1pt").arg(pointSize));
677 if (format.hasProperty(QTextFormat::FontCapitalization)
678 || (defaultFontResolveMask & QFont::CapitalizationResolved)) {
679 QFont::Capitalization capitalization = format.hasProperty(QTextFormat::FontCapitalization)
680 ? format.fontCapitalization()
681 : defaultFont.capitalization();
682 switch(capitalization) {
683 case QFont::MixedCase:
684 writer.writeAttribute(foNS, QString::fromLatin1(
"text-transform"), QString::fromLatin1(
"none"));
break;
685 case QFont::AllUppercase:
686 writer.writeAttribute(foNS, QString::fromLatin1(
"text-transform"), QString::fromLatin1(
"uppercase"));
break;
687 case QFont::AllLowercase:
688 writer.writeAttribute(foNS, QString::fromLatin1(
"text-transform"), QString::fromLatin1(
"lowercase"));
break;
689 case QFont::Capitalize:
690 writer.writeAttribute(foNS, QString::fromLatin1(
"text-transform"), QString::fromLatin1(
"capitalize"));
break;
691 case QFont::SmallCaps:
692 writer.writeAttribute(foNS, QString::fromLatin1(
"font-variant"), QString::fromLatin1(
"small-caps"));
break;
696 if (format.hasProperty(QTextFormat::FontLetterSpacing) ||
697 (defaultFontResolveMask & QFont::LetterSpacingResolved)) {
698 const qreal letterSpacing = format.hasProperty(QTextFormat::FontLetterSpacing)
699 ? format.fontLetterSpacing()
700 : defaultFont.letterSpacing();
701 writer.writeAttribute(foNS, QString::fromLatin1(
"letter-spacing"), pixelToPoint(letterSpacing));
704 if (format.hasProperty(QTextFormat::FontWordSpacing)
705 || (defaultFontResolveMask & QFont::WordSpacingResolved)) {
706 const qreal wordSpacing = format.hasProperty(QTextFormat::FontWordSpacing)
707 ? format.fontWordSpacing()
708 : defaultFont.wordSpacing();
709 if (wordSpacing != 0)
710 writer.writeAttribute(foNS, QString::fromLatin1(
"word-spacing"), pixelToPoint(wordSpacing));
713 if (format.hasProperty(QTextFormat::FontUnderline)
714 || ((defaultFontResolveMask & QFont::UnderlineResolved)
715 && !format.hasProperty(QTextFormat::TextUnderlineStyle))) {
716 const bool underline = format.hasProperty(QTextFormat::FontUnderline)
717 ? format.fontUnderline()
718 : defaultFont.underline();
719 writer.writeAttribute(styleNS, QString::fromLatin1(
"text-underline-type"),
720 underline ? QString::fromLatin1(
"single") : QString::fromLatin1(
"none"));
723 if (format.hasProperty(QTextFormat::FontOverline)) {
727 if (format.hasProperty(QTextFormat::FontStrikeOut)
728 || (defaultFontResolveMask & QFont::StrikeOutResolved)) {
729 const bool strikeOut = format.hasProperty(QTextFormat::FontStrikeOut)
730 ? format.fontStrikeOut()
731 : defaultFont.strikeOut();
732 writer.writeAttribute(styleNS,QString::fromLatin1(
"text-line-through-type"),
733 strikeOut ? QString::fromLatin1(
"single") : QString::fromLatin1(
"none"));
736 if (format.hasProperty(QTextFormat::TextUnderlineColor))
737 writer.writeAttribute(styleNS, QString::fromLatin1(
"text-underline-color"), format.underlineColor().name());
738 if (format.hasProperty(QTextFormat::FontFixedPitch)) {
741 if (format.hasProperty(QTextFormat::TextUnderlineStyle)) {
743 switch (format.underlineStyle()) {
744 case QTextCharFormat::NoUnderline: value = QString::fromLatin1(
"none");
break;
745 case QTextCharFormat::SingleUnderline: value = QString::fromLatin1(
"solid");
break;
746 case QTextCharFormat::DashUnderline: value = QString::fromLatin1(
"dash");
break;
747 case QTextCharFormat::DotLine: value = QString::fromLatin1(
"dotted");
break;
748 case QTextCharFormat::DashDotLine: value = QString::fromLatin1(
"dash-dot");
break;
749 case QTextCharFormat::DashDotDotLine: value = QString::fromLatin1(
"dot-dot-dash");
break;
750 case QTextCharFormat::WaveUnderline: value = QString::fromLatin1(
"wave");
break;
751 case QTextCharFormat::SpellCheckUnderline: value = QString::fromLatin1(
"none");
break;
753 writer.writeAttribute(styleNS, QString::fromLatin1(
"text-underline-style"), value);
755 if (format.hasProperty(QTextFormat::TextVerticalAlignment)) {
757 switch (format.verticalAlignment()) {
758 case QTextCharFormat::AlignMiddle:
759 case QTextCharFormat::AlignNormal: value = QString::fromLatin1(
"0%");
break;
760 case QTextCharFormat::AlignSuperScript: value = QString::fromLatin1(
"super");
break;
761 case QTextCharFormat::AlignSubScript: value = QString::fromLatin1(
"sub");
break;
762 case QTextCharFormat::AlignTop: value = QString::fromLatin1(
"100%");
break;
763 case QTextCharFormat::AlignBottom : value = QString::fromLatin1(
"-100%");
break;
764 case QTextCharFormat::AlignBaseline:
break;
766 writer.writeAttribute(styleNS, QString::fromLatin1(
"text-position"), value);
768 if (format.hasProperty(QTextFormat::TextOutline))
769 writer.writeAttribute(styleNS, QString::fromLatin1(
"text-outline"), QString::fromLatin1(
"true"));
770 if (format.hasProperty(QTextFormat::TextToolTip)) {
773 if (format.hasProperty(QTextFormat::IsAnchor)) {
776 if (format.hasProperty(QTextFormat::AnchorHref)) {
779 if (format.hasProperty(QTextFormat::AnchorName)) {
782 if (format.hasProperty(QTextFormat::ForegroundBrush)) {
783 QBrush brush = format.foreground();
784 writer.writeAttribute(foNS, QString::fromLatin1(
"color"), brush.color().name());
786 if (format.hasProperty(QTextFormat::BackgroundBrush)) {
787 QBrush brush = format.background();
788 writer.writeAttribute(foNS, QString::fromLatin1(
"background-color"), brush.color().name());
791 writer.writeEndElement();
794void QTextOdfWriter::writeListFormat(QXmlStreamWriter &writer,
const QTextListFormat &format,
int formatIndex)
const
796 writer.writeStartElement(textNS, QString::fromLatin1(
"list-style"));
797 writer.writeAttribute(styleNS, QString::fromLatin1(
"name"), QString::fromLatin1(
"L%1").arg(formatIndex));
799 QTextListFormat::Style style = format.style();
800 if (style == QTextListFormat::ListDecimal || style == QTextListFormat::ListLowerAlpha
801 || style == QTextListFormat::ListUpperAlpha
802 || style == QTextListFormat::ListLowerRoman
803 || style == QTextListFormat::ListUpperRoman) {
804 writer.writeStartElement(textNS, QString::fromLatin1(
"list-level-style-number"));
805 writer.writeAttribute(styleNS, QString::fromLatin1(
"num-format"), bulletChar(style));
807 if (format.hasProperty(QTextFormat::ListNumberSuffix))
808 writer.writeAttribute(styleNS, QString::fromLatin1(
"num-suffix"), format.numberSuffix());
810 writer.writeAttribute(styleNS, QString::fromLatin1(
"num-suffix"), QString::fromLatin1(
"."));
812 if (format.hasProperty(QTextFormat::ListNumberPrefix))
813 writer.writeAttribute(styleNS, QString::fromLatin1(
"num-prefix"), format.numberPrefix());
816 writer.writeStartElement(textNS, QString::fromLatin1(
"list-level-style-bullet"));
817 writer.writeAttribute(textNS, QString::fromLatin1(
"bullet-char"), bulletChar(style));
820 writer.writeAttribute(textNS, QString::fromLatin1(
"level"), QString::number(format.indent()));
821 writer.writeEmptyElement(styleNS, QString::fromLatin1(
"list-level-properties"));
822 writer.writeAttribute(foNS, QString::fromLatin1(
"text-align"), QString::fromLatin1(
"start"));
823 QString spacing = QString::fromLatin1(
"%1mm").arg(format.indent() * 8);
824 writer.writeAttribute(textNS, QString::fromLatin1(
"space-before"), spacing);
827 writer.writeEndElement();
828 writer.writeEndElement();
831void QTextOdfWriter::writeFrameFormat(QXmlStreamWriter &writer,
const QTextFrameFormat &format,
int formatIndex)
const
833 writer.writeStartElement(styleNS, QString::fromLatin1(
"style"));
834 writer.writeAttribute(styleNS, QString::fromLatin1(
"name"), QString::fromLatin1(
"s%1").arg(formatIndex));
835 writer.writeAttribute(styleNS, QString::fromLatin1(
"family"), QString::fromLatin1(
"section"));
836 writer.writeEmptyElement(styleNS, QString::fromLatin1(
"section-properties"));
837 if (format.hasProperty(QTextFormat::FrameTopMargin))
838 writer.writeAttribute(foNS, QString::fromLatin1(
"margin-top"), pixelToPoint(qMax(qreal(0.), format.topMargin())) );
839 if (format.hasProperty(QTextFormat::FrameBottomMargin))
840 writer.writeAttribute(foNS, QString::fromLatin1(
"margin-bottom"), pixelToPoint(qMax(qreal(0.), format.bottomMargin())) );
841 if (format.hasProperty(QTextFormat::FrameLeftMargin))
842 writer.writeAttribute(foNS, QString::fromLatin1(
"margin-left"), pixelToPoint(qMax(qreal(0.), format.leftMargin())) );
843 if (format.hasProperty(QTextFormat::FrameRightMargin))
844 writer.writeAttribute(foNS, QString::fromLatin1(
"margin-right"), pixelToPoint(qMax(qreal(0.), format.rightMargin())) );
846 writer.writeEndElement();
859void QTextOdfWriter::writeTableFormat(QXmlStreamWriter &writer,
const QTextTableFormat &format,
int formatIndex)
const
862 writer.writeStartElement(styleNS, QString::fromLatin1(
"style"));
863 writer.writeAttribute(styleNS, QString::fromLatin1(
"name"),
864 QString::fromLatin1(
"Table%1").arg(formatIndex));
865 writer.writeAttribute(styleNS, QString::fromLatin1(
"family"), QString::fromLatin1(
"table"));
866 writer.writeEmptyElement(styleNS, QString::fromLatin1(
"table-properties"));
868 if (m_tableFormatsWithBorders.contains(formatIndex)) {
870 writer.writeAttribute(tableNS, QString::fromLatin1(
"border-model"),
871 QString::fromLatin1(
"collapsing"));
873 const char* align =
nullptr;
874 switch (format.alignment()) {
881 case Qt::AlignHCenter:
884 case Qt::AlignJustify:
889 writer.writeAttribute(tableNS, QString::fromLatin1(
"align"), QString::fromLatin1(align));
890 if (format.width().rawValue()) {
891 writer.writeAttribute(styleNS, QString::fromLatin1(
"width"),
892 QString::number(format.width().rawValue()) +
"pt"_L1);
894 writer.writeEndElement();
896 if (format.columnWidthConstraints().size()) {
898 m_tableFormatsWithColWidthConstraints.insert(formatIndex);
899 for (
int colit = 0; colit < format.columnWidthConstraints().size(); ++colit) {
900 writer.writeStartElement(styleNS, QString::fromLatin1(
"style"));
901 writer.writeAttribute(styleNS, QString::fromLatin1(
"name"),
902 QString::fromLatin1(
"Table%1.%2").arg(formatIndex).arg(colit));
903 writer.writeAttribute(styleNS, QString::fromLatin1(
"family"), QString::fromLatin1(
"table-column"));
904 writer.writeEmptyElement(styleNS, QString::fromLatin1(
"table-column-properties"));
906 if (format.columnWidthConstraints().at(colit).type() == QTextLength::PercentageLength) {
907 columnWidth = QString::number(format.columnWidthConstraints().at(colit).rawValue())
909 }
else if (format.columnWidthConstraints().at(colit).type() == QTextLength::FixedLength) {
910 columnWidth = QString::number(format.columnWidthConstraints().at(colit).rawValue())
914 columnWidth = QString::number(100 / format.columnWidthConstraints().size())
917 writer.writeAttribute(styleNS, QString::fromLatin1(
"column-width"), columnWidth);
918 writer.writeEndElement();
943void QTextOdfWriter::tableCellStyleElement(QXmlStreamWriter &writer,
int formatIndex,
944 const QTextTableCellFormat &format,
bool hasBorder,
945 const QTextTableFormat &tableFormatTmp)
const {
946 writer.writeStartElement(styleNS, QString::fromLatin1(
"style"));
947 writer.writeAttribute(styleNS, QString::fromLatin1(
"name"), QString::fromLatin1(
"T%1").arg(formatIndex));
948 writer.writeAttribute(styleNS, QString::fromLatin1(
"family"), QString::fromLatin1(
"table-cell"));
949 writer.writeEmptyElement(styleNS, QString::fromLatin1(
"table-cell-properties"));
951 writer.writeAttribute(foNS, QString::fromLatin1(
"border"),
952 pixelToPoint(tableFormatTmp.border()) +
" "_L1
953 + borderStyleName(tableFormatTmp.borderStyle()) +
" "_L1
954 + tableFormatTmp.borderBrush().color().name(QColor::HexRgb));
956 qreal topPadding = format.topPadding();
957 qreal padding = topPadding + tableFormatTmp.cellPadding();
958 if (padding > 0 && topPadding == format.bottomPadding()
959 && topPadding == format.leftPadding() && topPadding == format.rightPadding()) {
960 writer.writeAttribute(foNS, QString::fromLatin1(
"padding"), pixelToPoint(padding));
964 writer.writeAttribute(foNS, QString::fromLatin1(
"padding-top"), pixelToPoint(padding));
965 padding = format.bottomPadding() + tableFormatTmp.cellPadding();
967 writer.writeAttribute(foNS, QString::fromLatin1(
"padding-bottom"),
968 pixelToPoint(padding));
969 padding = format.leftPadding() + tableFormatTmp.cellPadding();
971 writer.writeAttribute(foNS, QString::fromLatin1(
"padding-left"),
972 pixelToPoint(padding));
973 padding = format.rightPadding() + tableFormatTmp.cellPadding();
975 writer.writeAttribute(foNS, QString::fromLatin1(
"padding-right"),
976 pixelToPoint(padding));
979 if (format.hasProperty(QTextFormat::TextVerticalAlignment)) {
981 switch (format.verticalAlignment()) {
982 case QTextCharFormat::AlignMiddle:
983 pos = QString::fromLatin1(
"middle");
break;
984 case QTextCharFormat::AlignTop:
985 pos = QString::fromLatin1(
"top");
break;
986 case QTextCharFormat::AlignBottom:
987 pos = QString::fromLatin1(
"bottom");
break;
989 pos = QString::fromLatin1(
"automatic");
break;
991 writer.writeAttribute(styleNS, QString::fromLatin1(
"vertical-align"), pos);
998 writer.writeEndElement();
1019bool QTextOdfWriter::writeAll()
1021 if (m_createArchive)
1022 m_strategy =
new QZipStreamStrategy(m_device);
1024 m_strategy =
new QXmlStreamStrategy(m_device);
1026 if (!m_device->isWritable() && ! m_device->open(QIODevice::WriteOnly)) {
1027 qWarning(
"QTextOdfWriter::writeAll: the device cannot be opened for writing");
1030 QXmlStreamWriter writer(m_strategy->contentStream);
1032 writer.setAutoFormatting(
true);
1033 writer.setAutoFormattingIndent(2);
1035 writer.writeNamespace(officeNS, QString::fromLatin1(
"office"));
1036 writer.writeNamespace(textNS, QString::fromLatin1(
"text"));
1037 writer.writeNamespace(styleNS, QString::fromLatin1(
"style"));
1038 writer.writeNamespace(foNS, QString::fromLatin1(
"fo"));
1039 writer.writeNamespace(tableNS, QString::fromLatin1(
"table"));
1040 writer.writeNamespace(drawNS, QString::fromLatin1(
"draw"));
1041 writer.writeNamespace(xlinkNS, QString::fromLatin1(
"xlink"));
1042 writer.writeNamespace(svgNS, QString::fromLatin1(
"svg"));
1043 writer.writeStartDocument();
1044 writer.writeStartElement(officeNS, QString::fromLatin1(
"document-content"));
1045 writer.writeAttribute(officeNS, QString::fromLatin1(
"version"), QString::fromLatin1(
"1.2"));
1048 QTextDocumentPrivate::FragmentIterator fragIt = QTextDocumentPrivate::get(m_document)->begin();
1050 while (fragIt != QTextDocumentPrivate::get(m_document)->end()) {
1051 const QTextFragmentData *
const frag = fragIt.value();
1052 formats << frag->format;
1057 QTextDocumentPrivate::BlockMap &blocks =
const_cast<QTextDocumentPrivate *>(QTextDocumentPrivate::get(m_document))->blockMap();
1058 QTextDocumentPrivate::BlockMap::Iterator blockIt = blocks.begin();
1059 while (blockIt != blocks.end()) {
1060 const QTextBlockData *
const block = blockIt.value();
1061 formats << block->format;
1066 const QList<QTextFormat> allFormats = m_document->allFormats();
1067 const QList<
int> copy = formats.values();
1068 for (
auto index : copy) {
1069 QTextObject *object = m_document->objectForFormat(allFormats[index]);
1071 formats << object->formatIndex();
1072 if (
auto *tableobject = qobject_cast<QTextTable *>(object)) {
1073 if (tableobject->format().borderStyle()) {
1074 int tableID = tableobject->formatIndex();
1075 m_tableFormatsWithBorders.insert(tableID);
1078 for (
int rowindex = 0; rowindex < tableobject->rows(); ++rowindex) {
1079 for (
int colindex = 0; colindex < tableobject->columns(); ++colindex) {
1080 const int cellFormatID = tableobject->cellAt(rowindex, colindex).tableCellFormatIndex();
1081 QList<
int> tableIdsTmp;
1082 if (m_cellFormatsInTablesWithBorders.contains(cellFormatID))
1083 tableIdsTmp = m_cellFormatsInTablesWithBorders.value(cellFormatID);
1084 if (!tableIdsTmp.contains(tableID))
1085 tableIdsTmp.append(tableID);
1086 m_cellFormatsInTablesWithBorders.insert(cellFormatID, tableIdsTmp);
1094 writeFormats(writer, formats);
1096 writer.writeStartElement(officeNS, QString::fromLatin1(
"body"));
1097 writer.writeStartElement(officeNS, QString::fromLatin1(
"text"));
1098 QTextFrame *rootFrame = m_document->rootFrame();
1099 writeFrame(writer, rootFrame);
1100 writer.writeEndElement();
1101 writer.writeEndElement();
1102 writer.writeEndElement();
1103 writer.writeEndDocument();
1105 m_strategy =
nullptr;