void OdtWriter::writeAutomaticStyles(const QTextDocument* document) { m_xml.writeStartElement(QString::fromLatin1("office:automatic-styles")); QVector<QTextFormat> formats = document->allFormats(); // Find all used styles QVector<int> text_styles; QVector<int> paragraph_styles; int index = 0; for (QTextBlock block = document->begin(); block.isValid(); block = block.next()) { index = block.blockFormatIndex(); if (!paragraph_styles.contains(index)) { int heading = block.blockFormat().property(QTextFormat::UserProperty).toInt(); if (!heading) { paragraph_styles.append(index); } else { m_styles.insert(index, QString("Heading-%1").arg(heading)); } } for (QTextBlock::iterator iter = block.begin(); !(iter.atEnd()); ++iter) { index = iter.fragment().charFormatIndex(); if (!text_styles.contains(index) && formats.at(index).propertyCount()) { text_styles.append(index); } } } // Write text styles int text_style = 1; for (int i = 0; i < text_styles.size(); ++i) { int index = text_styles.at(i); const QTextFormat& format = formats.at(index); QString name = QString::fromLatin1("T") + QString::number(text_style); if (writeTextStyle(format.toCharFormat(), name)) { m_styles.insert(index, name); ++text_style; } } // Write paragraph styles int paragraph_style = 1; for (int i = 0; i < paragraph_styles.size(); ++i) { int index = paragraph_styles.at(i); const QTextFormat& format = formats.at(index); QString name = QString::fromLatin1("P") + QString::number(paragraph_style); if (writeParagraphStyle(format.toBlockFormat(), name)) { m_styles.insert(index, name); ++paragraph_style; } else { m_styles.insert(index, "Normal"); } } m_xml.writeEndElement(); }
void QTextOdfWriter::writeBlock(QXmlStreamWriter &writer, const QTextBlock &block) { if (block.textList()) { // its a list-item const int listLevel = block.textList()->format().indent(); if (m_listStack.isEmpty() || m_listStack.top() != block.textList()) { // not the same list we were in. while (m_listStack.count() >= listLevel && !m_listStack.isEmpty() && m_listStack.top() != block.textList() ) { // we need to close tags m_listStack.pop(); writer.writeEndElement(); // list if (m_listStack.count()) writer.writeEndElement(); // list-item } while (m_listStack.count() < listLevel) { if (m_listStack.count()) writer.writeStartElement(textNS, QString::fromLatin1("list-item")); writer.writeStartElement(textNS, QString::fromLatin1("list")); if (m_listStack.count() == listLevel - 1) { m_listStack.push(block.textList()); writer.writeAttribute(textNS, QString::fromLatin1("style-name"), QString::fromLatin1("L%1") .arg(block.textList()->formatIndex())); } else { m_listStack.push(0); } } } writer.writeStartElement(textNS, QString::fromLatin1("list-item")); } else { while (! m_listStack.isEmpty()) { m_listStack.pop(); writer.writeEndElement(); // list if (m_listStack.count()) writer.writeEndElement(); // list-item } } if (block.length() == 1) { // only a linefeed writer.writeEmptyElement(textNS, QString::fromLatin1("p")); writer.writeAttribute(textNS, QString::fromLatin1("style-name"), QString::fromLatin1("p%1") .arg(block.blockFormatIndex())); if (block.textList()) writer.writeEndElement(); // numbered-paragraph return; } writer.writeStartElement(textNS, QString::fromLatin1("p")); writer.writeAttribute(textNS, QString::fromLatin1("style-name"), QString::fromLatin1("p%1") .arg(block.blockFormatIndex())); for (QTextBlock::Iterator frag= block.begin(); !frag.atEnd(); frag++) { writer.writeCharacters(QString()); // Trick to make sure that the span gets no linefeed in front of it. writer.writeStartElement(textNS, QString::fromLatin1("span")); QString fragmentText = frag.fragment().text(); if (fragmentText.length() == 1 && fragmentText[0] == 0xFFFC) { // its an inline character. writeInlineCharacter(writer, frag.fragment()); writer.writeEndElement(); // span continue; } writer.writeAttribute(textNS, QString::fromLatin1("style-name"), QString::fromLatin1("c%1") .arg(frag.fragment().charFormatIndex())); bool escapeNextSpace = true; int precedingSpaces = 0; int exportedIndex = 0; for (int i=0; i <= fragmentText.count(); ++i) { QChar character = fragmentText[i]; bool isSpace = character.unicode() == ' '; // find more than one space. -> <text:s text:c="2" /> if (!isSpace && escapeNextSpace && precedingSpaces > 1) { const bool startParag = exportedIndex == 0 && i == precedingSpaces; if (!startParag) writer.writeCharacters(fragmentText.mid(exportedIndex, i - precedingSpaces + 1 - exportedIndex)); writer.writeEmptyElement(textNS, QString::fromLatin1("s")); const int count = precedingSpaces - (startParag?0:1); if (count > 1) writer.writeAttribute(textNS, QString::fromLatin1("c"), QString::number(count)); precedingSpaces = 0; exportedIndex = i; } if (i < fragmentText.count()) { if (character.unicode() == 0x2028) { // soft-return //if (exportedIndex < i) writer.writeCharacters(fragmentText.mid(exportedIndex, i - exportedIndex)); writer.writeEmptyElement(textNS, QString::fromLatin1("line-break")); exportedIndex = i+1; continue; } else if (character.unicode() == '\t') { // Tab //if (exportedIndex < i) writer.writeCharacters(fragmentText.mid(exportedIndex, i - exportedIndex)); writer.writeEmptyElement(textNS, QString::fromLatin1("tab")); exportedIndex = i+1; precedingSpaces = 0; } else if (isSpace) { ++precedingSpaces; escapeNextSpace = true; } else if (!isSpace) { precedingSpaces = 0; } } } writer.writeCharacters(fragmentText.mid(exportedIndex)); writer.writeEndElement(); // span } writer.writeCharacters(QString()); // Trick to make sure that the span gets no linefeed behind it. writer.writeEndElement(); // p if (block.textList()) writer.writeEndElement(); // list-item }
void OdtWriter::writeBody(const QTextDocument* document) { m_xml.writeStartElement(QString::fromLatin1("office:body")); m_xml.writeStartElement(QString::fromLatin1("office:text")); for (QTextBlock block = document->begin(); block.isValid(); block = block.next()) { int heading = block.blockFormat().property(QTextFormat::UserProperty).toInt(); if (!heading) { m_xml.writeStartElement(QString::fromLatin1("text:p")); } else { m_xml.writeStartElement(QString::fromLatin1("text:h")); m_xml.writeAttribute(QString::fromLatin1("text:outline-level"), QString::number(heading)); } m_xml.writeAttribute(QString::fromLatin1("text:style-name"), m_styles.value(block.blockFormatIndex())); m_xml.setAutoFormatting(false); for (QTextBlock::iterator iter = block.begin(); !(iter.atEnd()); ++iter) { QTextFragment fragment = iter.fragment(); QString style = m_styles.value(fragment.charFormatIndex()); if (!style.isEmpty()) { m_xml.writeStartElement(QString::fromLatin1("text:span")); m_xml.writeAttribute(QString::fromLatin1("text:style-name"), style); } QString text = fragment.text(); int start = 0; int spaces = -1; for (int i = 0; i < text.length(); ++i) { QChar c = text.at(i); if (c.unicode() == 0x0009) { m_xml.writeCharacters(text.mid(start, i - start)); m_xml.writeEmptyElement(QString::fromLatin1("text:tab")); start = i + 1; } else if (c.unicode() == 0x2028) { m_xml.writeCharacters(text.mid(start, i - start)); m_xml.writeEmptyElement(QString::fromLatin1("text:line-break")); start = i + 1; } else if (c.unicode() == 0x0020) { ++spaces; } else if (spaces > 0) { m_xml.writeCharacters(text.mid(start, i - spaces - start)); m_xml.writeEmptyElement(QString::fromLatin1("text:s")); m_xml.writeAttribute(QString::fromLatin1("text:c"), QString::number(spaces)); spaces = -1; start = i; } else { spaces = -1; } } if (spaces > 0) { m_xml.writeCharacters(text.mid(start, text.length() - spaces - start)); m_xml.writeEmptyElement(QString::fromLatin1("text:s")); m_xml.writeAttribute(QString::fromLatin1("text:c"), QString::number(spaces)); } else { m_xml.writeCharacters(text.mid(start)); } if (!style.isEmpty()) { m_xml.writeEndElement(); } } m_xml.writeEndElement(); m_xml.setAutoFormatting(true); } m_xml.writeEndElement(); m_xml.writeEndElement(); }