diff --git a/filters/words/docx/DocxXmlDocumentReader.cpp b/filters/words/docx/DocxXmlDocumentReader.cpp index dcdae7592e2..9c14377c4ac 100644 --- a/filters/words/docx/DocxXmlDocumentReader.cpp +++ b/filters/words/docx/DocxXmlDocumentReader.cpp @@ -1,7107 +1,7106 @@ /* * This file is part of Office 2007 Filters for Calligra * * Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies). * Copyright (C) 2010 KoGmbh (casper.boemann@kogmbh.com). * * Contact: Suresh Chande suresh.chande@nokia.com * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include #include "DocxXmlDocumentReader.h" #include "DocxXmlHeaderReader.h" #include "DocxXmlFooterReader.h" #include "DocxImport.h" #include #include #include #include #include #include #include #include #include #include #include #define MSOOXML_CURRENT_NS "w" #define MSOOXML_CURRENT_CLASS DocxXmlDocumentReader #define BIND_READ_CLASS MSOOXML_CURRENT_CLASS #define DOCXXMLDOCREADER_CPP //#define DOCXXML_DEBUG_TABLES #include #include #include #include #include #include namespace { class BorderMap : public QMap { public: BorderMap() { insert(QString(), KoBorder::BorderNone); insert("nil", KoBorder::BorderNone); insert("none", KoBorder::BorderSolid); insert("single", KoBorder::BorderSolid); insert("thick", KoBorder::BorderSolid); //FIXME find a better representation insert("double", KoBorder::BorderDouble); insert("dotted", KoBorder::BorderDotted); insert("dashed", KoBorder::BorderDashed); insert("dotDash", KoBorder::BorderDashDot); insert("dotDotDash", KoBorder::BorderDashDotDot); insert("triple", KoBorder::BorderDouble); //FIXME insert("thinThickSmallGap", KoBorder::BorderSolid); //FIXME insert("thickThinSmallGap", KoBorder::BorderSolid); //FIXME insert("thinThickThinSmallGap", KoBorder::BorderSolid); //FIXME insert("thinThickMediumGap", KoBorder::BorderSolid); //FIXME insert("thickThinMediumGap", KoBorder::BorderSolid); //FIXME insert("thinThickThinMediumGap", KoBorder::BorderSolid); //FIXME insert("thinThickLargeGap", KoBorder::BorderSolid); //FIXME insert("thickThinLargeGap", KoBorder::BorderSolid); //FIXME insert("thinThickThinLargeGap", KoBorder::BorderSolid); //FIXME insert("wave", KoBorder::BorderSolid); //FIXME insert("dobleWave", KoBorder::BorderSolid); //FIXME insert("dashSmallGap", KoBorder::BorderSolid); //FIXME insert("dashDotStroked", KoBorder::BorderSolid); //FIXME insert("threeDEmboss", KoBorder::BorderSolid); //FIXME insert("threeDEngrave", KoBorder::BorderSolid); //FIXME insert("outset", KoBorder::BorderOutset); insert("inset", KoBorder::BorderInset); } } borderMap; } DocxXmlDocumentReaderContext::DocxXmlDocumentReaderContext( DocxImport& _import, const QString& _path, const QString& _file, MSOOXML::MsooXmlRelationships& _relationships, MSOOXML::DrawingMLTheme* _themes) : MSOOXML::MsooXmlReaderContext(&_relationships), import(&_import), path(_path), file(_file), themes(_themes) { } // --------------------------------------------------------------------- class DocxXmlDocumentReader::Private { public: Private() { } ~Private() { } }; DocxXmlDocumentReader::DocxXmlDocumentReader(KoOdfWriters *writers) : MSOOXML::MsooXmlCommonReader(writers) , m_pDocBkgImageWriter(0) , m_writers(writers) , d(new Private) { init(); } DocxXmlDocumentReader::~DocxXmlDocumentReader() { if (m_pDocBkgImageWriter) { delete m_pDocBkgImageWriter->device(); delete m_pDocBkgImageWriter; } doneInternal(); // MsooXmlCommonReaderImpl.h delete d; delete m_dropCapWriter; m_dropCapWriter = 0; } void DocxXmlDocumentReader::init() { initInternal(); // MsooXmlCommonReaderImpl.h initDrawingML(); m_defaultNamespace = QLatin1String(MSOOXML_CURRENT_NS ":"); m_complexCharType = NoComplexFieldCharType; m_complexCharStatus = NoneAllowed; m_dropCapStatus = NoDropCap; m_dropCapWriter = 0; m_currentTableNumber = 0; m_wasCaption = false; m_closeHyperlink = false; m_listFound = false; m_insideParagraph = false; m_createSectionStyle = false; m_createSectionToNext = false; m_currentVMLProperties.insideGroup = false; m_outputFrames = true; m_currentNumId = ""; m_prevListLevel = 0; qsrand(QTime::currentTime().msec()); } KoFilter::ConversionStatus DocxXmlDocumentReader::read(MSOOXML::MsooXmlReaderContext* context) { m_context = dynamic_cast(context); Q_ASSERT(m_context); m_createSectionStyle = true; kDebug() << "============================="; readNext(); if (!isStartDocument()) { return KoFilter::WrongFormat; } //w:document readNext(); kDebug() << *this << namespaceUri(); if (!expectEl("w:document")) { return KoFilter::WrongFormat; } if (!expectNS(MSOOXML::Schemas::wordprocessingml)) { return KoFilter::WrongFormat; } /* const QXmlStreamAttributes attrs( attributes() ); for (int i=0; ipos() / device()->size(); m_context->import->reportProgress(progress); counter = 0; } ++counter; TRY_READ_IF(p) ELSE_TRY_READ_IF(del) ELSE_TRY_READ_IF(ins) ELSE_TRY_READ_IF(sdt) ELSE_TRY_READ_IF(sectPr) ELSE_TRY_READ_IF(tbl) ELSE_TRY_READ_IF(bookmarkStart) ELSE_TRY_READ_IF(bookmarkEnd) SKIP_UNKNOWN //! @todo add ELSE_WRONG_FORMAT } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL sectPr //! w:sectPr handler (Section Properties) /*! ECMA-376, 17.6.17, p. 667. Parent elements: - [done] body (§17.2.2) - docPartBody (§17.12.6) Chils elements: - bidi (Right to Left Section Layout) §17.6.1 - [done] cols (Column Definitions) §17.6.4 - docGrid (Document Grid) §17.6.5 - [done] endnotePr (Section-Wide Endnote Properties) §17.11.5 - [done] footerReference (Footer Reference) §17.10.2 - [done] footnotePr (Section-Wide Footnote Properties) §17.11.11 - formProt (Only Allow Editing of Form Fields) §17.6.6 - [done] headerReference (Header Reference) §17.10.5 - [done] lnNumType (Line Numbering Settings) §17.6.8 - noEndnote (Suppress Endnotes In Document) §17.11.16 - paperSrc (Paper Source Information) §17.6.9 - [done] pgBorders (Page Borders) §17.6.10 - [done] pgMar (Page Margins) §17.6.11 - pgNumType (Page Numbering Settings) §17.6.12 - [done] pgSz (Page Size) §17.6.13 - printerSettings (Reference to Printer Settings Data) §17.6.14 - rtlGutter (Gutter on Right Side of Page) §17.6.16 - sectPrChange (Revision Information for Section Properties) §17.13.5.32 - [done] textDirection (Text Flow Direction) §17.6.20 - titlePg (Different First Page Headers and Footers) §17.10.6 - type (Section Type) §17.6.22 - vAlign (Vertical Text Alignment on Page) §17.6.23 */ //! @todo support all elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_sectPr() { READ_PROLOGUE m_footerActive = false; m_headerActive = false; m_currentPageStyle = KoGenStyle(KoGenStyle::PageLayoutStyle); m_currentPageStyle.setAutoStyleInStylesDotXml(true); m_currentPageStyle.addProperty("style:writing-mode", "lr-tb"); //! @todo handle all valued of style:print-orientation m_currentPageStyle.addProperty("style:print-orientation", "portrait"); if (m_backgroundColor.isValid()) m_currentPageStyle.addProperty("fo:background-color", m_backgroundColor.name()); if (m_pDocBkgImageWriter) { QString contents = QString::fromUtf8(((QBuffer*)m_pDocBkgImageWriter->device())->buffer(), ((QBuffer*)m_pDocBkgImageWriter->device())->buffer().size()); m_currentPageStyle.addChildElement("0", contents); } m_masterPageStyle = KoGenStyle(KoGenStyle::MasterPageStyle); m_footers.clear(); m_headers.clear(); m_pageMargins.clear(); m_pageBorderStyles.clear(); m_pageBorderPaddings.clear(); m_pageBorderOffsetFrom = "text"; while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF(pgSz) ELSE_TRY_READ_IF(pgMar) ELSE_TRY_READ_IF(pgBorders) ELSE_TRY_READ_IF(textDirection) ELSE_TRY_READ_IF(headerReference) ELSE_TRY_READ_IF(footerReference) ELSE_TRY_READ_IF(cols) ELSE_TRY_READ_IF(footnotePr) ELSE_TRY_READ_IF(endnotePr) ELSE_TRY_READ_IF(lnNumType) SKIP_UNKNOWN } } applyPageBorders(m_currentPageStyle, m_pageMargins, m_pageBorderStyles, m_pageBorderPaddings, m_pageBorderOffsetFrom); // Currently if there are 3 header/footer styles, the one with 'first' is ignored bool useEvenAndOddHeaders = false; if (m_context->import->documentSettings().contains("evenAndOddHeaders")) { QString val = m_context->import->documentSettings()["evenAndOddHeaders"].toString(); useEvenAndOddHeaders = (val != "off" && val != "0" && val != "false"); } // the numbering in addChildElement is needed to correctly sort the element when writing out the values. if (!m_headers.isEmpty()) { bool odd = false; if (useEvenAndOddHeaders && m_headers["even"] != "") { m_masterPageStyle.addChildElement("2 style:header-left", m_headers["even"]); } if (m_headers["default"] != "") { odd = true; m_masterPageStyle.addChildElement("1 style:header", m_headers["default"]); } if (!odd) { m_masterPageStyle.addChildElement("1 style:header", m_headers["first"]); } } if (!m_footers.isEmpty()) { bool odd = false; if (useEvenAndOddHeaders && m_footers["even"] != "") { m_masterPageStyle.addChildElement("4 style:footer-left", m_footers["even"]); } if (m_footers["default"] != "") { odd = true; m_masterPageStyle.addChildElement("3 style:footer", m_footers["default"]); } if (!odd) { m_masterPageStyle.addChildElement("3 style:footer", m_footers["first"]); } } QString pageLayoutStyleName("Mpm"); pageLayoutStyleName = mainStyles->insert(m_currentPageStyle, pageLayoutStyleName); QString masterStyleName("Standard"); //! @todo style:display-name // masterStyle->addAttribute("style:display-name", masterStyleName); m_masterPageStyle.addAttribute("style:page-layout-name", pageLayoutStyleName); QString currentMasterPageName = mainStyles->insert(m_masterPageStyle, masterStyleName); // Because sectPr is always in the last bit of a section, it means that next paragraph/whatever // Needs to have a style which is modified by next sectPr m_createSectionToNext = true; KoGenStyle *sectionStyle = mainStyles->styleForModification(m_currentSectionStyleName); // There might not be a style to modify if the document is completely empty if (sectionStyle) { sectionStyle->addAttribute("style:master-page-name", currentMasterPageName); } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL pgSz //! w:pgSz handler (Page Size) /*! ECMA-376, 17.6.13, p. 655. Parent elements: - [done] sectPr (§17.6.17) - [done] sectPr (§17.6.18) - [done] sectPr (§17.6.19) No child elements. */ //! @todo support all elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_pgSz() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(w) if (!w.isEmpty()) { const QString s(MSOOXML::Utils::TWIP_to_ODF(w)); if (!s.isEmpty()) { m_currentPageStyle.addProperty("fo:page-width", s); } } TRY_READ_ATTR(h) if (!h.isEmpty()) { const QString s(MSOOXML::Utils::TWIP_to_ODF(h)); if (!s.isEmpty()) { m_currentPageStyle.addProperty("fo:page-height", s); } } TRY_READ_ATTR(orient) if (!orient.isEmpty()) { m_currentPageStyle.addProperty("style:print-orientation", orient); } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL textDirection //! w:textDirection handler (Text Direction) /*! Parent elements: - [done] sectPr (§17.6.17) - [done] sectPr (§17.6.18) - [done] sectPr (§17.6.19) No child elements. */ //! @todo support all elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_textDirection() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(val) if (!val.isEmpty() && val.size() == 4) { const QString left = val.left(2).toLower(); const QString right = val.right(2).toLower(); m_currentPageStyle.addProperty("style:writing-mode", left + "-" + right); } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL pgMar //! w:pgMar handler (Page Margins) /*! ECMA-376, 17.6.11, p. 649. Parent elements: - [done] sectPr (§17.6.17) - [done] sectPr (§17.6.18) - [done] sectPr (§17.6.19) No child elements. */ //! @todo support all elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_pgMar() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(right) if (!right.isEmpty()) { int rightNum = 0; STRING_TO_INT(right, rightNum, QString("w:right")); m_pageMargins.insert(MarginRight,TWIP_TO_POINT(rightNum)); } TRY_READ_ATTR(left) if (!left.isEmpty()) { int leftNum = 0; STRING_TO_INT(left, leftNum, QString("w:left")); m_pageMargins.insert(MarginLeft,TWIP_TO_POINT(leftNum)); } TRY_READ_ATTR(footer) TRY_READ_ATTR(header) TRY_READ_ATTR(top) TRY_READ_ATTR(bottom) int topNum = 0; int bottomNum = 0; int headerNum = 0; int footerNum = 0; topNum = top.toInt(); bottomNum = bottom.toInt(); headerNum = header.toInt(); footerNum = footer.toInt(); if (!m_headerActive) { m_pageMargins.insert(MarginTop, TWIP_TO_POINT(topNum)); } else { m_pageMargins.insert(MarginTop, TWIP_TO_POINT(headerNum)); } if (!m_footerActive) { m_pageMargins.insert(MarginBottom, TWIP_TO_POINT(bottomNum)); } else { m_pageMargins.insert(MarginBottom, TWIP_TO_POINT(footerNum)); } QBuffer headerBuffer; headerBuffer.open( QIODevice::WriteOnly ); KoXmlWriter headerWriter(&headerBuffer, 3); headerWriter.startElement("style:header-style"); headerWriter.startElement("style:header-footer-properties"); headerWriter.addAttribute("style:dynamic-spacing", "true"); if (m_headerActive) { if (topNum > headerNum) { headerWriter.addAttributePt("fo:min-height", TWIP_TO_POINT(topNum - headerNum)); } } headerWriter.endElement(); // style:header-footer-properties headerWriter.endElement(); // style:header-style QString headerContents = QString::fromUtf8(headerBuffer.buffer(), headerBuffer.buffer().size() ); // the style elements need to be sorted correctly so that the created odf is valid // therefore we use footer-header-style-1 and footer-header-style-2 to sort header before footer m_currentPageStyle.addStyleChildElement("footer-header-style-1", headerContents); QBuffer footerBuffer; footerBuffer.open( QIODevice::WriteOnly ); KoXmlWriter footerWriter(&footerBuffer, 3); footerWriter.startElement("style:footer-style"); footerWriter.startElement("style:header-footer-properties"); footerWriter.addAttribute("style:dynamic-spacing", "true"); if (m_footerActive) { if (bottomNum > footerNum) { footerWriter.addAttributePt("fo:min-height", TWIP_TO_POINT(bottomNum - footerNum)); } } footerWriter.endElement(); // style:header-footer-properties footerWriter.endElement(); // style:footer-style QString footerContents = QString::fromUtf8(footerBuffer.buffer(), footerBuffer.buffer().size() ); m_currentPageStyle.addStyleChildElement("footer-header-style-2", footerContents); readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL pict //! pict handler (VML Object) /*! ECMA-376 Part 4, 9.2.2.2, p.31. This element specifies that an object is located at this position in the run’s contents. The layout properties of this object are specified using the VML syntax (§14.1). Parent elements: - r (Part 1, §22.1.2.87) - Shared ML - [done] r (Part 1, §17.3.2.25) - Shared ML Child elements: - control (Floating Embedded Control) §9.2.2.1 - movie (Embedded Video) Part 1, §17.3.3.17 - Any element in the urn:schemas-microsoft-com:vml namespace §14.1 - Any element in the urn:schemas-microsoft-com:office:office namespace §14.2 */ //! @todo support all elements KoFilter::ConversionStatus MSOOXML_CURRENT_CLASS::read_pict() { READ_PROLOGUE while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF_NS(v, rect) ELSE_TRY_READ_IF_NS(v, roundrect) ELSE_TRY_READ_IF_NS(v, shapetype) ELSE_TRY_READ_IF_NS(v, shape) ELSE_TRY_READ_IF_NS(v, group) ELSE_TRY_READ_IF_NS(v, oval) ELSE_TRY_READ_IF_NS(v, line) SKIP_UNKNOWN //! @todo add ELSE_WRONG_FORMAT } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL footerReference //! w:footerReference handler (Footer Reference) /*! Parent elements: - [done] sectPr (§17.6.17) - [done] sectPr (§17.6.8) Child elements: - None */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_footerReference() { READ_PROLOGUE m_footerActive = true; const QXmlStreamAttributes attrs(attributes()); QString link_target; TRY_READ_ATTR_WITH_NS(r, id) if (r_id.isEmpty()) { link_target.clear(); } else { link_target = m_context->relationships->target(m_context->path, m_context->file, r_id); } DocxXmlFooterReader reader(this); QString errorMessage; MSOOXML::MsooXmlRelationships relationships(*m_context->import, m_writers, errorMessage); QString fileName = link_target; fileName.remove(0, m_context->path.length()); DocxXmlDocumentReaderContext context(*m_context->import, m_context->path, fileName, relationships, m_context->themes); context.m_tableStyles = m_context->m_tableStyles; context.m_bulletStyles = m_context->m_bulletStyles; context.m_namedDefaultStyles = m_context->m_namedDefaultStyles; const KoFilter::ConversionStatus status = m_context->import->loadAndParseDocument(&reader, link_target, errorMessage, &context); if (status != KoFilter::OK) { reader.raiseError(errorMessage); } QString footerContent = ""; TRY_READ_ATTR(type) if (!type.isEmpty()) { if (type == "even") { footerContent = ""; footerContent.append(reader.content()); footerContent.append(""); } else { footerContent = ""; footerContent.append(reader.content()); footerContent.append(""); } m_footers[type] = footerContent; } else { footerContent = ""; footerContent.append(reader.content()); footerContent.append(""); m_footers["default"] = footerContent; } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL headerReference //! w:headerReference handler (Header Reference) /*! Parent elements: - [done] sectPr (§17.6.17) - [done] sectPr (§17.6.8) Child elements: - None */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_headerReference() { READ_PROLOGUE m_headerActive = true; const QXmlStreamAttributes attrs(attributes()); QString link_target; TRY_READ_ATTR_WITH_NS(r, id) if (r_id.isEmpty()) { link_target.clear(); } else { link_target = m_context->relationships->target(m_context->path, m_context->file, r_id); } DocxXmlHeaderReader reader(this); QString errorMessage; MSOOXML::MsooXmlRelationships relationships(*m_context->import, m_writers, errorMessage); QString fileName = link_target; fileName.remove(0, m_context->path.length()); DocxXmlDocumentReaderContext context(*m_context->import, m_context->path, fileName, relationships, m_context->themes); context.m_tableStyles = m_context->m_tableStyles; context.m_bulletStyles = m_context->m_bulletStyles; context.m_namedDefaultStyles = m_context->m_namedDefaultStyles; const KoFilter::ConversionStatus status = m_context->import->loadAndParseDocument(&reader, link_target, errorMessage, &context); if (status != KoFilter::OK) { reader.raiseError(errorMessage); } QString headerContent = ""; TRY_READ_ATTR(type) if (!type.isEmpty()) { if (type == "even") { headerContent = ""; headerContent.append(reader.content()); headerContent.append(""); } else { headerContent = ""; headerContent.append(reader.content()); headerContent.append(""); } m_headers[type] = headerContent; } else { headerContent = ""; headerContent.append(reader.content()); headerContent.append(""); m_headers["default"] = headerContent; } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL lnNumType //! w:lnNumType handler (Line Numbering type) /* Parents elements: - [done] sectPr (§17.6.17) - [done] sectPr (§17.6.18) - [done] sectPr (§17.6.19) Child elements: - none */ //! @todo support all elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_lnNumType() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(countBy) //TRY_READ_ATTR(restart) //TRY_READ_ATTR(start) QBuffer buffer; KoXmlWriter temp(&buffer); temp.startElement("text:linenumbering-configuration"); // These should maybe be somehow determined from attributes temp.addAttribute("text:number-position", "left"); temp.addAttribute("style:num-format", "1"); temp.addAttribute("text:offset", "0.1965in"); if (!countBy.isEmpty()) { temp.addAttribute("text:increment", countBy); } temp.endElement(); // text:linenumbering-configuration QString lineStyle = QString::fromUtf8(buffer.buffer(), buffer.buffer().size()); mainStyles->insertRawOdfStyles(KoGenStyles::DocumentStyles, lineStyle.toUtf8()); readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL endnotePr //! w:endonotePr handler (Endnote properties) /* Parent elements: - [done] sectPr (§17.6.17) - [done] sectPr (§17.6.18) - [done] sectPr (§17.6.19) Child elements: - [done] numFmt (Footnote Numbering Format) §17.11.18 - numRestart (Footnote and Endnote Numbering Restart Location) §17.11.19 - numStart (Footnote and Endnote Numbering Starting Value) §17.11.20 - pos (Footnote Placement) §17.11.21 */ //! @todo support all elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_endnotePr() { READ_PROLOGUE QBuffer buffer; KoXmlWriter *oldBody = body; body = new KoXmlWriter(&buffer); body->startElement("text:notes-configuration"); body->addAttribute("text:note-class", "endnote"); while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF(numFmt) SKIP_UNKNOWN } } body->endElement(); // text:notes-configuration QString endStyle = QString::fromUtf8(buffer.buffer(), buffer.buffer().size()); delete body; body = oldBody; mainStyles->insertRawOdfStyles(KoGenStyles::DocumentStyles, endStyle.toUtf8()); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL footnotePr //! w:footnotePr handler (Footnote properties) /* Parent elements: - [done] sectPr (§17.6.17) - [done] sectPr (§17.6.18) - [done] sectPr (§17.6.19) Child elements: - [done] numFmt (Footnote Numbering Format) §17.11.18 - numRestart (Footnote and Endnote Numbering Restart Location) §17.11.19 - numStart (Footnote and Endnote Numbering Starting Value) §17.11.20 - pos (Footnote Placement) §17.11.21 */ //! @todo support all elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_footnotePr() { READ_PROLOGUE QBuffer buffer; KoXmlWriter *oldBody = body; body = new KoXmlWriter(&buffer); body->startElement("text:notes-configuration"); body->addAttribute("text:note-class", "footnote"); body->addAttribute("text:footnotes-position", "page"); body->addAttribute("text:start-numbering-at", "document"); while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF(numFmt) SKIP_UNKNOWN } } body->endElement(); // text:notes-configuration QString footStyle = QString::fromUtf8(buffer.buffer(), buffer.buffer().size()); delete body; body = oldBody; mainStyles->insertRawOdfStyles(KoGenStyles::DocumentStyles, footStyle.toUtf8()); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL numFmt //! w:numFmt handler (Footnote Numbering format) /* Parent elements: - [done] footnotePr (§17.11.12) - [done] footnotePr (§17.11.11) Child elements: - none */ //! @toodo support all elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_numFmt() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(val) if (!val.isEmpty()) { if (val == "upperLetter") { body->addAttribute("style:num-format", "A"); } else if (val == "decimal") { body->addAttribute("style:num-format", "1"); } } else { // For now let's use letter format as the default body->addAttribute("style:num-format", "A"); } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL cols //! w:cols handler (Column definitions) /* Parents elements: - [done] sectPr (§17.6.17) - [done] sectPr (§17.6.18) - [done] sectPr (§17.6.19) Child Elements: - col (Single Column Definition) §17.6.3 */ //! @todo support all elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_cols() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(num) TRY_READ_ATTR(space) QBuffer columnBuffer; KoXmlWriter columnWriter(&columnBuffer); columnWriter.startElement("style:columns"); if (!num.isEmpty()) { columnWriter.addAttribute("fo:column-count", num); } if (!space.isEmpty()) { bool ok; const qreal distance = qreal(TWIP_TO_POINT(space.toDouble(&ok))); if (ok) { columnWriter.addAttributePt("fo:column-gap", distance); } } while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { } } columnWriter.endElement(); // style:columns; const QString elementContents = QString::fromUtf8(columnBuffer.buffer(), columnBuffer.buffer().size()); if (!num.isEmpty()) { m_currentPageStyle.addChildElement("style:columns", elementContents); } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL pgBorders //! w:pgBorders handler (Page Borders) /*! ECMA-376, 17.6.10, p. 646. Parent elements: - [done] sectPr (§17.6.17) - [done] sectPr (§17.6.18) - [done] sectPr (§17.6.19) Child elements: - [done] bottom (Bottom Border) §17.6.2 - [done] left (Left Border) §17.6.7 - [done] right (Right Border) §17.6.15 - [done] top (Top Border) §17.6.21 */ //! @todo support all elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_pgBorders() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(offsetFrom) m_pageBorderOffsetFrom = offsetFrom; while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { if (QUALIFIED_NAME_IS(top)) { RETURN_IF_ERROR(readBorderElement(TopBorder, "top", m_pageBorderStyles, m_pageBorderPaddings)); } else if (QUALIFIED_NAME_IS(left)) { RETURN_IF_ERROR(readBorderElement(LeftBorder, "left", m_pageBorderStyles, m_pageBorderPaddings)); } else if (QUALIFIED_NAME_IS(bottom)) { RETURN_IF_ERROR(readBorderElement(BottomBorder, "bottom", m_pageBorderStyles, m_pageBorderPaddings)); } else if (QUALIFIED_NAME_IS(right)) { RETURN_IF_ERROR(readBorderElement(RightBorder, "right", m_pageBorderStyles, m_pageBorderPaddings)); } ELSE_WRONG_FORMAT } } READ_EPILOGUE } void DocxXmlDocumentReader::applyBorders(KoGenStyle *style, QMap sourceBorder, QMap sourcePadding) { const QString topBorder = sourceBorder.value(TopBorder,QString()); const QString leftBorder = sourceBorder.value(LeftBorder,QString()); const QString bottomBorder = sourceBorder.value(BottomBorder,QString()); const QString rightBorder = sourceBorder.value(RightBorder,QString()); if (!topBorder.isEmpty() && leftBorder == topBorder && bottomBorder == topBorder && rightBorder == topBorder) { style->addProperty("fo:border", topBorder); // all sides the same } else { if (!topBorder.isEmpty()) { style->addProperty("fo:border-top", topBorder); } if (!leftBorder.isEmpty()) { style->addProperty("fo:border-left", leftBorder); } if (!bottomBorder.isEmpty()) { style->addProperty("fo:border-bottom", bottomBorder); } if (!rightBorder.isEmpty()) { style->addProperty("fo:border-right", rightBorder); } } sourceBorder.clear(); const qreal topPadding = sourcePadding.value(TopBorder); const qreal leftPadding = sourcePadding.value(LeftBorder); const qreal bottomPadding = sourcePadding.value(BottomBorder); const qreal rightPadding = sourcePadding.value(RightBorder); if (sourcePadding.contains(TopBorder) && leftPadding == topPadding && bottomPadding == topPadding && rightPadding == topPadding) { style->addPropertyPt("fo:padding", topPadding); // all sides the same } else { if (sourcePadding.contains(TopBorder)) { style->addPropertyPt("fo:padding-top", topPadding); } if (sourcePadding.contains(LeftBorder)) { style->addPropertyPt("fo:padding-left", leftPadding); } if (sourcePadding.contains(BottomBorder)) { style->addPropertyPt("fo:padding-bottom", bottomPadding); } if (sourcePadding.contains(RightBorder)) { style->addPropertyPt("fo:padding-right", rightPadding); } } sourcePadding.clear(); } void DocxXmlDocumentReader::applyPageBorders(KoGenStyle &style, QMap &pageMargins, QMap &pageBorder, QMap &pagePadding, QString & offsetFrom) { if (pageMargins.contains(MarginTop)) { if (pagePadding.contains(TopBorder)) { qreal margin = pageMargins.value(MarginTop); qreal padding = pagePadding.value(TopBorder); if(offsetFrom == "page") { style.addPropertyPt("fo:margin-top", padding); style.addPropertyPt("fo:padding-top", margin - padding); } else { style.addPropertyPt("fo:margin-top", margin - padding); style.addPropertyPt("fo:padding-top", padding); } } else { style.addPropertyPt("fo:margin-top", pageMargins.value(MarginTop)); } } if (pageMargins.contains(MarginBottom)) { if (pagePadding.contains(BottomBorder)) { qreal margin = pageMargins.value(MarginBottom); qreal padding = pagePadding.value(BottomBorder); if(offsetFrom == "page") { style.addPropertyPt("fo:margin-bottom", padding); style.addPropertyPt("fo:padding-bottom", margin - padding); } else { style.addPropertyPt("fo:margin-bottom", margin - padding); style.addPropertyPt("fo:padding-bottom", padding); } } else { style.addPropertyPt("fo:margin-bottom", pageMargins.value(MarginBottom)); } } if (pageMargins.contains(MarginLeft)) { if (pagePadding.contains(LeftBorder)) { qreal margin = pageMargins.value(MarginLeft); qreal padding = pagePadding.value(LeftBorder); if(offsetFrom == "page") { style.addPropertyPt("fo:margin-left", padding); style.addPropertyPt("fo:padding-left", margin - padding); } else { style.addPropertyPt("fo:margin-left", margin - padding); style.addPropertyPt("fo:padding-left", padding); } } else { style.addPropertyPt("fo:margin-left", pageMargins.value(MarginLeft)); } } if (pageMargins.contains(MarginRight)) { if (pagePadding.contains(RightBorder)) { qreal margin = pageMargins.value(MarginRight); qreal padding = pagePadding.value(RightBorder); if(offsetFrom == "page") { style.addPropertyPt("fo:margin-right", padding); style.addPropertyPt("fo:padding-right", margin - padding); } else { style.addPropertyPt("fo:margin-right", margin - padding); style.addPropertyPt("fo:padding-right", padding); } } else { style.addPropertyPt("fo:margin-right", pageMargins.value(MarginRight)); } } pageMargins.clear(); pagePadding.clear(); const QString topBorder = pageBorder.value(TopBorder,QString()); const QString leftBorder = pageBorder.value(LeftBorder,QString()); const QString bottomBorder = pageBorder.value(BottomBorder,QString()); const QString rightBorder = pageBorder.value(RightBorder,QString()); if (!topBorder.isEmpty() && leftBorder == topBorder && bottomBorder == topBorder && rightBorder == topBorder) { style.addProperty("fo:border", topBorder); // all sides the same } else { if (!topBorder.isEmpty()) { style.addProperty("fo:border-top", topBorder); } if (!leftBorder.isEmpty()) { style.addProperty("fo:border-left", leftBorder); } if (!bottomBorder.isEmpty()) { style.addProperty("fo:border-bottom", bottomBorder); } if (!rightBorder.isEmpty()) { style.addProperty("fo:border-right", rightBorder); } } pageBorder.clear(); } //! Converts 17.18.2 ST_Border (Border Styles, p. 1462, 4357) value to W3C CSS2 border-style value //! @see http://www.w3.org/TR/CSS2/box.html#value-def-border-style //! @see http://www.w3.org/TR/CSS2/box.html#value-def-border-width static QString ST_Border_to_ODF(const QString& s) { if (s == "nil" || s == "none" || s.isEmpty()) return QString(); else if (s == "thick") return QLatin1String("solid thick"); else if (s == "single") return QLatin1String("solid"); else if (s == "dashed" || s == "dotted" || s == "double") return s; return QLatin1String("solid"); } KoFilter::ConversionStatus DocxXmlDocumentReader::readBorderElement(BorderSide borderSide, const char *borderSideName, QMap &sourceBorder, QMap &sourcePadding) { const QXmlStreamAttributes attrs(attributes()); READ_ATTR(val) TRY_READ_ATTR(sz) TRY_READ_ATTR(color) createBorderStyle(sz, color, val, borderSide, sourceBorder); TRY_READ_ATTR(space) if (!space.isEmpty()) { int sp; STRING_TO_INT(space, sp, QString("w:%1@space").arg(borderSideName)); sourcePadding.insertMulti(borderSide, sp); } readNext(); return KoFilter::OK; } void DocxXmlDocumentReader::createBorderStyle(const QString& size, const QString& color, const QString& lineStyle, BorderSide borderSide, QMap &sourceBorder) { const QString odfLineStyle(ST_Border_to_ODF(lineStyle)); if (odfLineStyle.isEmpty()) return; QString border; if (!size.isEmpty()) border += MSOOXML::Utils::ST_EighthPointMeasure_to_ODF(size) + " "; border.append(odfLineStyle + " "); if (!color.isEmpty()) { if (color == "auto") { // The documentation for auto value says that it leaves the color up to the application // to decide, here we make a decision to use window color text MSOOXML::DrawingMLColorSchemeItemBase *colorItem = 0; colorItem = m_context->themes->colorScheme.value("dk1"); QColor col = Qt::black; if (colorItem) { col = colorItem->value(); } border.append(col.name()); } else { border.append('#'); border.append(color); } } else { border.append(QLatin1String("#000000")); } sourceBorder.insertMulti(borderSide,border); } #undef CURRENT_EL #define CURRENT_EL object //! object handler (Embedded Object) /*! ECMA-376, 17.3.3.19, p.371. */ //! @todo support all elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_object() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(dxaOrig) m_currentObjectWidthCm = MSOOXML::Utils::ST_TwipsMeasure_to_cm(dxaOrig); TRY_READ_ATTR(dyaOrig) m_currentObjectHeightCm = MSOOXML::Utils::ST_TwipsMeasure_to_cm(dyaOrig); // Protecting in case the object is inside a textbox inside a shape VMLShapeProperties oldProperties = m_currentVMLProperties; while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF_NS(v, shapetype) else if (name() == "shape") { m_outputFrames = false; TRY_READ(shape) m_outputFrames = true; } ELSE_TRY_READ_IF_NS(o, OLEObject) ELSE_TRY_READ_IF(control) SKIP_UNKNOWN //! @todo add ELSE_WRONG_FORMAT } } m_currentVMLProperties = oldProperties; READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL commentRangeStart //! commentRangeStart handler /*! Parent elements: - bdo (§17.3.2.3) - body (§17.2.2) - comment (§17.13.4.2) - customXml (§17.5.1.6) - customXml (§17.5.1.4) - customXml (§17.5.1.5) - customXml (§17.5.1.3) - deg (§22.1.2.26) - del (§17.13.5.14) - den (§22.1.2.28) - dir (§17.3.2.8) - docPartBody (§17.12.6) - e (§22.1.2.32) - endnote (§17.11.2) - fldSimple (§17.16.19) - fName (§22.1.2.37) - footnote (§17.11.10) - ftr (§17.10.3) - hdr (§17.10.4) - hyperlink (§17.16.22) - ins (§17.13.5.18) - lim (§22.1.2.52) - moveFrom (§17.13.5.22) - moveTo (§17.13.5.25) - num (§22.1.2.75) - oMath (§22.1.2.77) - [done] p (§17.3.1.22) - rt (§17.3.3.24) - rubyBase (§17.3.3.27) - sdtContent (§17.5.2.34) - sdtContent (§17.5.2.33) - sdtContent (§17.5.2.35) - sdtContent (§17.5.2.36) - [done] smartTag (§17.5.1.9) - sub (§22.1.2.112) - sup (§22.1.2.114) - tbl (§17.4.38) - tc (§17.4.66) - tr (§17.4.79) Child elements: - none */ //! @todo support all attributes etc. KoFilter::ConversionStatus DocxXmlDocumentReader::read_commentRangeStart() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); READ_ATTR(id) body->startElement("office:annotation"); body->addCompleteElement(m_context->m_comments[id].toUtf8()); body->endElement(); // office:annotation readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL endnoteReference //! endnoteReference handler /*! Parent elements: - [done] r (§17.3.2.25) - [done] r (§22.1.2.87) Child elements: - none */ //! @todo support all attributes etc. KoFilter::ConversionStatus DocxXmlDocumentReader::read_endnoteReference() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); READ_ATTR(id) // # example endnote from odt document converted with OpenOffice // // 1 // // // studies // // // body->startElement("text:note"); body->addAttribute("text:id", QString("endn").append(id)); body->addAttribute("text:note-class", "endnote"); body->startElement("text:note-citation"); // NOTE: This line is meaningless in the sense that office // programs are supposed to autogenerate the value based on the // footnote style, it is hardcoded for the moment as calligra has // no support for it. body->addTextSpan(id); body->endElement(); // text:note-citation body->startElement("text:note-body"); body->addCompleteElement(m_context->m_endnotes[id].toUtf8()); body->endElement(); // text:note-body body->endElement(); // text:note readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL footnoteReference //! footnoteReference handler /*! Parent elements: - [done] r (§17.3.2.25) - [done] r (§22.1.2.87) Child elements: - none */ //! @todo support all attributes etc. KoFilter::ConversionStatus DocxXmlDocumentReader::read_footnoteReference() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); READ_ATTR(id) // # example endnote from odt document converted with OpenOffice // // 1 // // // studies // // // body->startElement("text:note"); body->addAttribute("text:id", QString("ftn").append(id)); body->addAttribute("text:note-class", "footnote"); body->startElement("text:note-citation"); // NOTE: This line is meaningless in the sense that office // programs are supposed to autogenerate the value based on the // footnote style, it is hardcoded for the moment as calligra has // no support for it. body->addTextSpan(id); body->endElement(); // text:note-citation body->startElement("text:note-body"); body->addCompleteElement(m_context->m_footnotes[id].toUtf8()); body->endElement(); // text:note-body body->endElement(); // text:note readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL fldChar //! fldChar handler /*! Complex field character Parent elements: - [done] r (§17.3.2.25) - [done] r (§22.1.2.87) Child elements: - ffData (Form Field Properties) §17.16.17 */ //! @todo support all attributes etc. KoFilter::ConversionStatus DocxXmlDocumentReader::read_fldChar() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(fldCharType) if (!fldCharType.isEmpty()) { if (fldCharType == "begin") { m_complexCharStatus = InstrAllowed; } else if (fldCharType == "separate") { m_complexCharStatus = InstrExecute; } else if (fldCharType == "end") { m_complexCharStatus = NoneAllowed; m_complexCharType = NoComplexFieldCharType; m_complexCharValue.clear(); } } while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL); } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL br //! br handler /* Parent elements: - [done] r (§17.3.2.25) - [done] r (§22.1.2.87) */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_br() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(type) if (type == "column") { m_currentParagraphStyle.addProperty("fo:break-before", "column"); } else if (type == "page") { m_currentParagraphStyle.addProperty("fo:break-before", "page"); } else { body->startElement("text:line-break"); body->endElement(); } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL lastRenderedPageBreak //! lastRenderedPageBreak handler /* Parent elements: - [done] r (§17.3.2.25) - [done] r (§22.1.2.87) */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_lastRenderedPageBreak() { READ_PROLOGUE body->startElement("text:soft-page-break"); body->endElement(); // text:soft-page-break readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL instrText //! instrText handler /* Parent elements: - [done] r (§17.3.2.25) - [done] r (§22.1.2.87) */ //! @todo support all attributes etc. KoFilter::ConversionStatus DocxXmlDocumentReader::read_instrText() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (m_complexCharStatus == InstrAllowed) { QString instruction = text().toString().trimmed(); if (instruction.startsWith("HYPERLINK")) { // Removes hyperlink, spaces and extra " chars instruction.remove(0, 11); instruction.truncate(instruction.size() - 1); m_complexCharType = HyperlinkComplexFieldCharType; m_complexCharValue = instruction; } else if (instruction.startsWith("PAGEREF")) { instruction.remove(0, 8); // removes PAGEREF m_complexCharType = ReferenceComplexFieldCharType; m_complexCharValue = instruction.left(instruction.indexOf(' ')); } else if (instruction.startsWith("GOTOBUTTON")) { instruction.remove(0, 12); // removes GOTOBUTTON m_complexCharType = InternalHyperlinkComplexFieldCharType; m_complexCharValue = instruction; } else if (instruction.startsWith("MACROBUTTON")) { m_complexCharType = MacroButtonFieldCharType; m_complexCharValue = "["; } else { m_complexCharValue = instruction; } } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL hyperlink //! hyperlink handler (Hyperlink) /*! ECMA-376, 17.3.3.31, p.1431. Parent elements: - bdo (§17.3.2.3) - customXml (§17.5.1.3) - dir (§17.3.2.8) - [done] fldSimple (§17.16.19) - [done] hyperlink (§17.16.22) - [done] p (§17.3.1.22) - [done] sdtContent (§17.5.2.36) - [done] smartTag (§17.5.1.9) Child elements: - bdo (Bidirectional Override) §17.3.2.3 - [done] bookmarkEnd (Bookmark End) §17.13.6.1 - [done] bookmarkStart (Bookmark Start) §17.13.6.2 - commentRangeEnd (Comment Anchor Range End) §17.13.4.3 - commentRangeStart (Comment Anchor Range Start) §17.13.4.4 - customXml (Inline-Level Custom XML Element) §17.5.1.3 - customXmlDelRangeEnd (Custom XML Markup Deletion End) §17.13.5.4 - customXmlDelRangeStart (Custom XML Markup Deletion Start) §17.13.5.5 - customXmlInsRangeEnd (Custom XML Markup Insertion End) §17.13.5.6 - customXmlInsRangeStart (Custom XML Markup Insertion Start) §17.13.5.7 - customXmlMoveFromRangeEnd (Custom XML Markup Move Source End) §17.13.5.8 - customXmlMoveFromRangeStart (Custom XML Markup Move Source Start) §17.13.5.9 - customXmlMoveToRangeEnd (Custom XML Markup Move Destination Location End) §17.13.5.10 - customXmlMoveToRangeStart (Custom XML Markup Move Destination Location Start) §17.13.5.11 - [done] del (Deleted Run Content) §17.13.5.14 - dir (Bidirectional Embedding Level) §17.3.2.8 - [done] fldSimple (Simple Field) §17.16.19 - [done] hyperlink (Hyperlink) §17.16.22 - [done] ins (Inserted Run Content) §17.13.5.18 - moveFrom (Move Source Run Content) §17.13.5.22 - moveFromRangeEnd (Move Source Location Container - End) §17.13.5.23 - moveFromRangeStart (Move Source Location Container - Start) §17.13.5.24 - moveTo (Move Destination Run Content) §17.13.5.25 - moveToRangeEnd (Move Destination Location Container - End) §17.13.5.27 - moveToRangeStart (Move Destination Location Container - Start) §17.13.5.28 - oMath (Office Math) §22.1.2.77 - oMathPara (Office Math Paragraph) §22.1.2.78 - permEnd (Range Permission End) §17.13.7.1 - permStart (Range Permission Start) §17.13.7.2 - proofErr (Proofing Error Anchor) §17.13.8.1 - [done] r (Text Run) §17.3.2.25 - [done] sdt (Inline-Level Structured Document Tag) §17.5.2.31 - [done] smartTag (Inline-Level Smart Tag) §17.5.1.9 - subDoc (Anchor for Subdocument Location) §17.17.1.1 */ //! @todo support all elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_hyperlink() { READ_PROLOGUE QString link_target; const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR_WITH_NS(r, id) if (r_id.isEmpty()) { link_target.clear(); } else { link_target = m_context->relationships->target(m_context->path, m_context->file, r_id); // The return value also contains the path in the start and directory separator, we need to remove them link_target.remove(0, m_context->path.size() + 1); } bool closeTag = false; TRY_READ_ATTR(anchor) MSOOXML::Utils::XmlWriteBuffer hlinkBuffer; body = hlinkBuffer.setWriter(body); while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF(r) ELSE_TRY_READ_IF(sdt) ELSE_TRY_READ_IF(hyperlink) ELSE_TRY_READ_IF(bookmarkStart) ELSE_TRY_READ_IF(bookmarkEnd) ELSE_TRY_READ_IF(fldSimple) ELSE_TRY_READ_IF(del) ELSE_TRY_READ_IF(ins) ELSE_TRY_READ_IF(smartTag) SKIP_UNKNOWN //! @todo add ELSE_WRONG_FORMAT } } body = hlinkBuffer.originalWriter(); //NOTE: Workaround until text:display="none" support. if ((m_currentParagraphStyle.property("text:display", KoGenStyle::TextType) == "none") && hlinkBuffer.isEmpty()) { READ_EPILOGUE } if (!link_target.isEmpty() || !anchor.isEmpty()) { body->startElement("text:a", false); body->addAttribute("xlink:type", "simple"); closeTag = true; if (!anchor.isEmpty()) { body->addAttribute("xlink:href", QString("#%1").arg(anchor)); } else { body->addAttribute("xlink:href", QUrl(link_target).toEncoded()); } } hlinkBuffer.releaseWriter(); if (closeTag) { body->endElement(); // text:bookmark, text:a } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL del //! del (Deleted Run Content) /*! ECMA-376, 17.13.5.18, p.959. This element specifies that the inline-level content contained within it shall be treated as deleted content which has been tracked as a revision. Parent elements, Child elements: sync to ins (Inserted Run Content) */ //! @todo: read more attributes and child emenets KoFilter::ConversionStatus DocxXmlDocumentReader::read_del() { READ_PROLOGUE m_changeTrackingState.push(DeletedRunContent); while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF(r) ELSE_TRY_READ_IF(bookmarkStart) ELSE_TRY_READ_IF(bookmarkEnd) ELSE_TRY_READ_IF(del) ELSE_TRY_READ_IF(ins) ELSE_TRY_READ_IF_NS(m, oMath) ELSE_TRY_READ_IF_NS(m, oMathPara) ELSE_TRY_READ_IF(sdt) ELSE_TRY_READ_IF(smartTag) SKIP_UNKNOWN } } if (m_changeTrackingState.isEmpty()) { kWarning() << "Error: ChangeTrackingState stack is corrupt!"; } else { m_changeTrackingState.pop(); } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL ins //! ins (Inserted Run Content) /*! ECMA-376, 17.13.5.18, p.959. This element specifies that the inline-level content contained within it shall be treated as inserted content which has been tracked as a revision. Parent elements: - bdo (§17.3.2.3) - [done] body (§17.2.2) - comment (§17.13.4.2) - customXml (§17.5.1.3) - deg (§22.1.2.26) - del (§17.13.5.14) - den (§22.1.2.28) - dir (§17.3.2.8) - docPartBody (§17.12.6) - e (§22.1.2.32) - [done] endnote (§17.11.2) - [done] fldSimple (§17.16.19) - fName (§22.1.2.37) - [done] footnote (§17.11.10) - [done] ftr (§17.10.3) - [done] hdr (§17.10.4) - [done] hyperlink (§17.16.22) - lim (§22.1.2.52 - moveFrom (§17.13.5.22) - moveTo (§17.13.5.25) - num (§22.1.2.75) - [done] oMath (§22.1.2.77) - [done] p (§17.3.1.22) - rt (§17.3.3.24 - rubyBase (§17.3.3.27) - sdtContent (§17.5.2.36) - [done] smartTag (§17.5.1.9) - sub (§22.1.2.112) - sup (§22.1.2.114) - tbl (§17.4.38) - tc (§17.4.66) - tr (§17.4.79) Child elements: - acc (Accent) §22.1.2.1 - bar (Bar) §22.1.2.7 - bdo (Bidirectional Override) §17.3.2.3 - [done] bookmarkEnd (Bookmark End) §17.13.6.1 - [done] bookmarkStart (Bookmark Start) §17.13.6.2 - borderBox (Border-Box Object) §22.1.2.11 - box (Box Object) §22.1.2.13 - commentRangeEnd (Comment Anchor Range End) §17.13.4.3 - commentRangeStart (Comment Anchor Range Start) §17.13.4.4 - customXml (Inline-Level Custom XML Element) §17.5.1.3 - customXmlDelRangeEnd (Custom XML Markup Deletion End) §17.13.5.4 - customXmlDelRangeStart (Custom XML Markup Deletion Start) §17.13.5.5 - customXmlInsRangeEnd (Custom XML Markup Insertion End) §17.13.5.6 - customXmlInsRangeStart (Custom XML Markup Insertion Start) §17.13.5.7 - customXmlMoveFromRangeEnd (Custom XML Markup Move Source End) §17.13.5.8 - customXmlMoveFromRangeStart (Custom XML Markup Move Source Start) §17.13.5.9 - customXmlMoveToRangeEnd (Custom XML Markup Move Destination Location End) §17.13.5.10 - customXmlMoveToRangeStart (Custom XML Markup Move Destination Location Start) §17.13.5.11 - d (Delimiter Object) §22.1.2.24 - [done] del (Deleted Run Content) §17.13.5.14 - dir (Bidirectional Embedding Level) §17.3.2.8 - eqArr (Array Object) §22.1.2.34 - f (Fraction Object) §22.1.2.36 - func (Function Apply Object) §22.1.2.39 - groupChr (Group-Character Object) §22.1.2.41 - [done] ins (Inserted Run Content) §17.13.5.18 - limLow (Lower-Limit Object) §22.1.2.54 - limUpp (Upper-Limit Object) §22.1.2.56 - m (Matrix Object) §22.1.2.60 - moveFrom (Move Source Run Content) §17.13.5.22 - moveFromRangeEnd (Move Source Location Container - End) §17.13.5.23 - moveFromRangeStart (Move Source Location Container - Start) §17.13.5.24 - moveTo (Move Destination Run Content) §17.13.5.25 - moveToRangeEnd (Move Destination Location Container - End) §17.13.5.27 - moveToRangeStart (Move Destination Location Container - Start) §17.13.5.28 - nary (n-ary Operator Object) §22.1.2.70 - [done] oMath (Office Math) §22.1.2.77 - [done] oMathPara (Office Math Paragraph) §22.1.2.78 - permEnd (Range Permission End) §17.13.7.1 - permStart (Range Permission Start) §17.13.7.2 - phant (Phantom Object) §22.1.2.81 - proofErr (Proofing Error Anchor) §17.13.8.1 - [done] r (Run) §22.1.2.87 - [done] r (Text Run) §17.3.2.25 - rad (Radical Object) §22.1.2.88 - [done] sdt (Inline-Level Structured Document Tag) §17.5.2.31 - [done] smartTag (Inline-Level Smart Tag) §17.5.1.9 - sPre (Pre-Sub-Superscript Object) §22.1.2.99 - sSub (Subscript Object) §22.1.2.101 - sSubSup (Sub-Superscript Object) §22.1.2.103 - sSup (Superscript Object) §22.1.2.105 */ //! @todo: read more attributes and child emenets KoFilter::ConversionStatus DocxXmlDocumentReader::read_ins() { READ_PROLOGUE m_changeTrackingState.push(InsertedRunContent); while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF(r) ELSE_TRY_READ_IF(bookmarkStart) ELSE_TRY_READ_IF(bookmarkEnd) ELSE_TRY_READ_IF(del) ELSE_TRY_READ_IF(ins) ELSE_TRY_READ_IF_NS(m, oMath) ELSE_TRY_READ_IF_NS(m, oMathPara) ELSE_TRY_READ_IF(sdt) ELSE_TRY_READ_IF(smartTag) SKIP_UNKNOWN } } if (m_changeTrackingState.isEmpty()) { kWarning() << "Error: ChangeTrackingState stack is corrupt!"; } else { m_changeTrackingState.pop(); } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL sdtContent /*! sdt handler //! @todo support properly */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_sdtContent() { READ_PROLOGUE // FIXME: This is not properly supported at all atm. while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF(p) ELSE_TRY_READ_IF(tbl) ELSE_TRY_READ_IF(sdt) ELSE_TRY_READ_IF(fldSimple) ELSE_TRY_READ_IF(hyperlink) ELSE_TRY_READ_IF_NS(m, oMath) ELSE_TRY_READ_IF_NS(m, oMathPara) ELSE_TRY_READ_IF(r) ELSE_TRY_READ_IF(bookmarkStart) ELSE_TRY_READ_IF(bookmarkEnd) ELSE_TRY_READ_IF(smartTag) ELSE_TRY_READ_IF(tc) SKIP_UNKNOWN } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL sdt /*! sdt handler //! @todo support properly */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_sdt() { READ_PROLOGUE while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL); if (isStartElement()) { TRY_READ_IF(sdtContent) SKIP_UNKNOWN } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL txbxContent /*! txbxContent handler (Textbox content) Parent elements: - [done] textbox (§14.1.2.19) */ //! @todo support all elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_txbxContent() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF(p) ELSE_TRY_READ_IF(tbl) ELSE_TRY_READ_IF(sdt) SKIP_UNKNOWN } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL p //! [1] p handler (Paragraph) ECMA-376, WML 17.3.1.22, p. 251, //! This element specifies a paragraph of content in the document. //! [2] p handler (Text Paragraphs) ECMA-376, DrawingML 21.1.2.2.6, p. 3587. //! This element specifies the presence of a paragraph of text within the containing text body. /*! Parent elements: - [done] body (§17.2.2) - [done] comment (§17.13.4.2) - customXml (§17.5.1.6) - docPartBody (§17.12.6) - [done] endnote (§17.11.2) - [done] footnote (§17.11.10) - [done] ftr (§17.10.3) - [done] hdr (§17.10.4) - [done] sdtContent (§17.5.2.34) - [done] tc (§17.4.66) - [done] p (§17.3.1.22) Child elements: - bdo (Bidirectional Override) §17.3.2.3 - [done] bookmarkEnd (Bookmark End) §17.13.6.1 - [done] bookmarkStart (Bookmark Start) §17.13.6.2 - commentRangeEnd (Comment Anchor Range End) §17.13.4.3 - [done] commentRangeStart (Comment Anchor Range Start) §17.13.4.4 - WML only - customXml (Inline-Level Custom XML Element) §17.5.1.3 - customXmlDelRangeEnd (Custom XML Markup Deletion End) §17.13.5.4 - customXmlDelRangeStart (Custom XML Markup Deletion Start) §17.13.5.5 - customXmlInsRangeEnd (Custom XML Markup Insertion End) §17.13.5.6 - customXmlInsRangeStart (Custom XML Markup Insertion Start) §17.13.5.7 - customXmlMoveFromRangeEnd (Custom XML Markup Move Source End) §17.13.5.8 - customXmlMoveFromRangeStart (Custom XML Markup Move Source Start) §17.13.5.9 - customXmlMoveToRangeEnd (Custom XML Markup Move Destination Location End) §17.13.5.10 - customXmlMoveToRangeStart (Custom XML Markup Move Destination Location Start) §17.13.5.11 - [done] del (Deleted Run Content) §17.13.5.14 - dir (Bidirectional Embedding Level) §17.3.2.8 - [done] fldSimple (Simple Field) §17.16.19 - [done] hyperlink (Hyperlink) §17.16.22 - WML only - [done] ins (Inserted Run Content) §17.13.5.18 - moveFrom (Move Source Run Content) §17.13.5.22 - moveFromRangeEnd (Move Source Location Container - End) §17.13.5.23 - moveFromRangeStart (Move Source Location Container - Start) §17.13.5.24 - moveTo (Move Destination Run Content) §17.13.5.25 - moveToRangeEnd (Move Destination Location Container - End) §17.13.5.27 - moveToRangeStart (Move Destination Location Container - Start) §17.13.5.28 - [done] oMath (Office Math) §22.1.2.77 - [done] oMathPara (Office Math Paragraph) §22.1.2.78 - permEnd (Range Permission End) §17.13.7.1 - permStart (Range Permission Start) §17.13.7.2 - [done] pPr (Paragraph Properties) §17.3.1.26 - proofErr (Proofing Error Anchor) §17.13.8.1 - [done] r (Text Run) §17.3.2.25 - [done] sdt (Inline-Level Structured Document Tag) §17.5.2.31 - [done] smartTag (Inline-Level Smart Tag) §17.5.1.9 - subDoc (Anchor for Subdocument Location) §17.17.1.1 */ //! @todo support all elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_p() { READ_PROLOGUE m_insideParagraph = true; m_paragraphStyleNameWritten = false; m_currentStyleName.clear(); m_listFound = false; m_closeHyperlink = false; // It is possible that one of the child elements of p has p element // Therefore we push the current style to vector and pop it out when we // come out To make sure in that case we don't lose the previous style QVector activeStyles; activeStyles.push_back(m_currentParagraphStyle); MSOOXML::Utils::XmlWriteBuffer textPBuf; bool oldWasCaption = m_wasCaption; m_wasCaption = false; if (oldWasCaption) { kDebug() << "SKIP!"; } else { body = textPBuf.setWriter(body); m_currentParagraphStyle = KoGenStyle(KoGenStyle::ParagraphAutoStyle, "paragraph"); if (m_moveToStylesXml) { m_currentParagraphStyle.setAutoStyleInStylesDotXml(true); } // MS2007 has a different way of marking drop cap, it divides them to // two paragraphs here we apply the status to current paragraph if // previous one had dropCap if (m_dropCapStatus == DropCapDone) { QBuffer frameBuffer; frameBuffer.open(QIODevice::WriteOnly); KoXmlWriter elementWriter(&frameBuffer); elementWriter.startElement("style:drop-cap"); elementWriter.addAttribute("style:lines", m_dropCapLines); elementWriter.addAttributePt("style:distance", m_dropCapDistance); elementWriter.endElement(); // style-drop-cap QString drop = QString::fromUtf8(frameBuffer.buffer(), frameBuffer.buffer().size()); m_currentParagraphStyle.addChildElement("style:tab-stops", drop); } } // Whether section starts from this paragraph bool sectionAdded = false; if (m_createSectionStyle) { // To avoid the style to become a duplicate or being duplicated. m_currentParagraphStyle.addAttribute("style:master-page-name", "placeholder"); m_createSectionStyle = false; sectionAdded = true; } while (!atEnd()) { readNext(); kDebug() << *this; BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { //ELSE_TRY_READ_IF(commentRangeEnd) TRY_READ_IF(sdt) ELSE_TRY_READ_IF(hyperlink) ELSE_TRY_READ_IF(del) ELSE_TRY_READ_IF(ins) ELSE_TRY_READ_IF(commentRangeStart) ELSE_TRY_READ_IF(bookmarkStart) ELSE_TRY_READ_IF(bookmarkEnd) ELSE_TRY_READ_IF(pPr) // CASE #400.1 ELSE_TRY_READ_IF(r) // CASE #400.2 ELSE_TRY_READ_IF(fldSimple) ELSE_TRY_READ_IF_NS(m, oMathPara) ELSE_TRY_READ_IF_NS(m, oMath) ELSE_TRY_READ_IF(smartTag) SKIP_UNKNOWN //! @todo add ELSE_WRONG_FORMAT } } //--------------------------------------------- // Prepare for the List Style //--------------------------------------------- if (m_listFound && m_currentBulletList.size() > m_currentListLevel) { m_currentBulletProperties = m_currentBulletList.at(m_currentListLevel); KoGenStyle textStyle = KoGenStyle(KoGenStyle::TextStyle, "text"); KoGenStyle::copyPropertiesFromStyle(m_currentParagraphStyle, textStyle, KoGenStyle::TextType); if (!textStyle.isEmpty()) { //MSWord: A bullet/picture label does not inherit font information //from the paragraph mark. if (m_currentBulletProperties.m_type != MSOOXML::Utils::ParagraphBulletProperties::NumberType) { textStyle.removeProperty("style:font-name"); textStyle.removeProperty("style:font-name-complex"); } //MSWord: A label does NOT inherit Underline from text-properties //of the paragraph style. A bullet/picture does not inherit //{Italics, Bold}. if (m_currentBulletProperties.m_type != MSOOXML::Utils::ParagraphBulletProperties::NumberType) { textStyle.removeProperty("fo:font-style"); textStyle.removeProperty("fo:font-weight"); } textStyle.removeProperty("style:text-underline-color"); textStyle.removeProperty("style:text-underline-mode"); textStyle.removeProperty("style:text-underline-style"); textStyle.removeProperty("style:text-underline-type"); textStyle.removeProperty("style:text-underline-width"); KoGenStyle::copyPropertiesFromStyle(m_currentBulletProperties.textStyle(), textStyle); m_currentBulletProperties.setTextStyle(textStyle); } } //--------------------------------------------- // Fine-tune Paragraph Style //--------------------------------------------- if (m_currentParagraphStyle.parentName().isEmpty()) { if (m_context->m_namedDefaultStyles.contains("paragraph")) { m_currentParagraphStyle.setParentName(m_context->m_namedDefaultStyles.value("paragraph")); } } //NOTE: Workaround until text:display="none" support. bool isHidden = (m_currentParagraphStyle.property("text:display", KoGenStyle::TextType) == "none"); // rPr (Run Properties for the Paragraph Mark), ECMA-376, 17.3.1.29, p.253 // This element specifies the set of run properties applied to the // glyph used to represent the physical location of the paragraph // mark for this paragraph. ODF: The paragraph mark formatting // does not affect other runs of text so it can NOT be saved into // text-properties of the paragraph style. // if (!textPBuf.isEmpty()) { m_currentParagraphStyle.removeAllProperties(KoGenStyle::TextType); } if (oldWasCaption || (isHidden && textPBuf.isEmpty())) { //nothing body = textPBuf.originalWriter(); } else { if (m_dropCapStatus == DropCapRead) { body = textPBuf.releaseWriter(); // If we read a drop cap but there was no text there might as well // be no drop cap m_dropCapStatus = NoDropCap; } else if (m_dropCapStatus == DropCapDone) { // In case of drop cap, we do not wish there to be a paragraph at // this point, this because two ooxml paragraphs with drop cap in // first, trasnfer to one paragraph in odt with drop cap as style. body = textPBuf.releaseWriter(); } else { body = textPBuf.originalWriter(); // In ooxml it seems that nothing should be created if sectPr was present if (!m_createSectionToNext) { if (m_listFound) { // update the size of a bullet picture if ((m_currentBulletProperties.m_type == MSOOXML::Utils::ParagraphBulletProperties::PictureType) && (m_currentBulletProperties.bulletSizePt() == "UNUSED")) { int percent = 100; if (m_currentBulletProperties.bulletRelativeSize() != "UNUSED") { STRING_TO_INT(m_currentBulletProperties.bulletRelativeSize(), percent, QString("PictureType: processing bulletRelativeSize")); } QString fontSize = m_currentParagraphStyle.property("fo:font-size",KoGenStyle::TextType); // Using the default font size at the moment if (fontSize.isEmpty()) { fontSize = m_context->m_defaultFontSizePt; } qreal base = 10; //fair enough if (!fontSize.isEmpty() && fontSize.endsWith("pt")) { fontSize.chop(2); STRING_TO_QREAL(fontSize, base, QString("PictureType: processing font-size")); } m_currentBulletProperties.setBulletSizePt(percent * base / 100); } // update automatic numbering info if (m_currentBulletProperties.m_type == MSOOXML::Utils::ParagraphBulletProperties::NumberType) { bool listOpen = false; if (m_continueListNum.contains(m_currentNumId)) { listOpen = true; } else if (!m_currentBulletProperties.startOverride()) { // TODO: The most recent one is required to check // against the correct prevListLevel. // // Check if any of the lists that inherit numbering // from the abstract numbering definition was opened. QStringList numIDs = m_context->m_abstractNumIDs.keys(m_context->m_abstractNumIDs[m_currentNumId]); QStringList::const_iterator i; for (i = numIDs.constBegin(); i != numIDs.constEnd(); ++i) { if (m_continueListNum.contains(*i)) { listOpen = true; m_currentNumId = *i; break; } } } if (listOpen) { if (m_currentListLevel <= m_continueListNum[m_currentNumId].first) { m_continueListNum[m_currentNumId].second = true; } else { m_continueListNum[m_currentNumId].second = false; QString key; int i = m_continueListNum[m_currentNumId].first; while (i > m_currentListLevel) { key = m_currentNumId; key.append(QString(".lvl%1").arg(i)); m_numIdXmlId.remove(key); --i; } } } } m_currentListStyle = KoGenStyle(KoGenStyle::ListAutoStyle); if (m_moveToStylesXml) { m_currentListStyle.setAutoStyleInStylesDotXml(true); } m_currentListStyle.addChildElement("list-style-properties", m_currentBulletProperties.convertToListProperties(*mainStyles, MSOOXML::Utils::DocxFilter)); QString listStyleName = mainStyles->insert(m_currentListStyle, QString()); Q_ASSERT(!listStyleName.isEmpty()); //TODO: continue an opened list based on this information // m_usedListStyles.insertMulti(m_currentNumId, listStyleName); // Start a new list body->startElement("text:list"); body->addAttribute("text:style-name", listStyleName); // continue numbering if applicable if (m_currentBulletProperties.m_type == MSOOXML::Utils::ParagraphBulletProperties::NumberType) { QString key = m_currentNumId; key.append(QString(".lvl%1").arg(m_currentListLevel)); // Keeping the id readable for debugging purpose QString xmlId = key; xmlId.append(QString("_%1").arg(m_numIdXmlId[key].first)).prepend("lst"); xmlId.append(QString("_%1").arg(qrand())); body->addAttribute("xml:id", xmlId); if (m_continueListNum.contains(m_currentNumId)) { if (m_continueListNum[m_currentNumId].second) { body->addAttribute("text:continue-list", m_numIdXmlId[key].second); } } m_numIdXmlId[key].first++; m_numIdXmlId[key].second = xmlId; } body->startElement("text:list-item"); for (int i = 0; i < m_currentListLevel; ++i) { body->startElement("text:list"); body->startElement("text:list-item"); } // restart numbering if applicable if (m_currentBulletProperties.m_type == MSOOXML::Utils::ParagraphBulletProperties::NumberType) { if (!m_continueListNum.contains(m_currentNumId) || (m_continueListNum.contains(m_currentNumId) && !m_continueListNum[m_currentNumId].second)) { body->addAttribute("text:start-value", m_currentBulletProperties.startValue()); } m_continueListNum[m_currentNumId] = qMakePair(m_currentListLevel, false); } m_currentParagraphStyle.addAttribute("style:list-style-name", listStyleName); } body->startElement("text:p", false); if (m_currentStyleName.isEmpty()) { QString currentParagraphStyleName; if (sectionAdded) { currentParagraphStyleName = (mainStyles->insert(m_currentParagraphStyle)); m_currentSectionStyleName = currentParagraphStyleName; } else { currentParagraphStyleName = (mainStyles->insert(m_currentParagraphStyle)); } body->addAttribute("text:style-name", currentParagraphStyleName); } else { body->addAttribute("text:style-name", m_currentStyleName); if (m_currentStyleName == "Caption") { m_wasCaption = true; } } //insert the bookmark-start/bookmark-end XML snippet if (!m_bookmarkSnippet.isEmpty()) { body->addCompleteElement(m_bookmarkSnippet.toUtf8()); } //insert the floating table XML snippet if (!m_floatingTable.isEmpty()) { body->addCompleteElement(m_floatingTable.toUtf8()); m_floatingTable.clear(); } (void)textPBuf.releaseWriter(); body->endElement(); //text:p if (m_listFound) { for (int i = 0; i <= m_currentListLevel; ++i) { body->endElement(); //text:list-item body->endElement(); //text:list } } kDebug() << "/text:p"; } } } // True if this was last paragraph of the section, if we were then it means // that next paragraph/table should have a new section identifier if (m_createSectionToNext) { m_createSectionStyle = true; m_createSectionToNext = false; } m_currentStyleName.clear(); m_insideParagraph = false; m_currentParagraphStyle = activeStyles.last(); activeStyles.pop_back(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL smartTag //! smartTag Handler (Smart Tag) /* Parent elements: - bdo (§17.3.2.3); - customXml (§17.5.1.3); - del (§17.13.5.14); dir (§17.3.2.8); - [done] fldSimple (§17.16.19); - [done] hyperlink (§17.16.22); - ins (§17.13.5.18); - moveFrom (§17.13.5.22); - moveTo (§17.13.5.25); - [done] p (§17.3.1.22); - [done] sdtContent (§17.5.2.36); - [done] smartTag (§17.5.1.9) Child elements: - bdo (Bidirectional Override) §17.3.2.3 - [done] bookmarkEnd (Bookmark End) §17.13.6.1 - [done] bookmarkStart (Bookmark Start) §17.13.6.2 - commentRangeEnd (Comment Anchor Range End) §17.13.4.3 - [done] commentRangeStart (Comment Anchor Range Start) §17.13.4.4 - customXml (Inline-Level Custom XML Element) §17.5.1.3 - customXmlDelRangeEnd (Custom XML Markup Deletion End) §17.13.5.4 - customXmlDelRangeStart (Custom XML Markup Deletion Start) §17.13.5.5 - customXmlInsRangeEnd (Custom XML Markup Insertion End) §17.13.5.6 - customXmlInsRangeStart (Custom XML Markup Insertion Start) §17.13.5.7 - customXmlMoveFromRangeEnd (Custom XML Markup Move Source End) §17.13.5.8 - customXmlMoveFromRangeStart (Custom XML Markup Move Source Start) §17.13.5.9 - customXmlMoveToRangeEnd (Custom XML Markup Move Destination Location End) §17.13.5.10 - customXmlMoveToRangeStart (Custom XML Markup Move Destination Location Start) §17.13.5.11 - [done] del (Deleted Run Content) §17.13.5.14 - dir (Bidirectional Embedding Level) §17.3.2.8 - [done] fldSimple (Simple Field) §17.16.19 - [done] hyperlink (Hyperlink) §17.16.22 - [done] ins (Inserted Run Content) §17.13.5.18 - moveFrom (Move Source Run Content) §17.13.5.22 - moveFromRangeEnd (Move Source Location Container - End) §17.13.5.23 - moveFromRangeStart (Move Source Location Container - Start) §17.13.5.24 - moveTo (Move Destination Run Content) §17.13.5.25 - moveToRangeEnd (Move Destination Location Container - End) §17.13.5.27 - moveToRangeStart (Move Destination Location Container - Start) §17.13.5.28 - [done] oMath (Office Math) §22.1.2.77 - [done] oMathPara (Office Math Paragraph) §22.1.2.78 - permEnd (Range Permission End) §17.13.7.1 - permStart (Range Permission Start) §17.13.7.2 - proofErr (Proofing Error Anchor) §17.13.8.1 - [done] r (Text Run) §17.3.2.25 - [done] sdt (Inline-Level Structured Document Tag) §17.5.2.31 - [done] smartTag (Inline-Level Smart Tag) §17.5.1.9 - smartTagPr (Smart Tag Properties) §17.5.1.10 - subDoc (Anchor for Subdocument Location) §17.17.1.1 */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_smartTag() { READ_PROLOGUE // todo, use as RDF info? while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF(r) ELSE_TRY_READ_IF(smartTag) ELSE_TRY_READ_IF(bookmarkStart) ELSE_TRY_READ_IF(bookmarkEnd) ELSE_TRY_READ_IF(fldSimple) ELSE_TRY_READ_IF(hyperlink) ELSE_TRY_READ_IF(commentRangeStart) ELSE_TRY_READ_IF(r) ELSE_TRY_READ_IF_NS(m, oMathPara) ELSE_TRY_READ_IF_NS(m, oMath) ELSE_TRY_READ_IF(del) ELSE_TRY_READ_IF(ins) ELSE_TRY_READ_IF(sdt) SKIP_UNKNOWN } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL r //! r handler (Text Run) /*! ECMA-376, 17.3.2.25, p.320. Parent elements: - bdo (§17.3.2.3) - customXml (§17.5.1.3) - del (§17.13.5.14) - dir (§17.3.2.8) - [done] fldSimple (§17.16.19) - [done] hyperlink (§17.16.22) - ins (§17.13.5.18) - moveFrom (§17.13.5.22) - moveTo (§17.13.5.25) - [done] p (§17.3.1.22) - rt (§17.3.3.24) - rubyBase (§17.3.3.27) - [done] sdtContent (§17.5.2.36) - [done] smartTag (§17.5.1.9) Child elements: - annotationRef (Comment Information Block) §17.13.4.1 - [done] br (Break) §17.3.3.1 - commentReference (Comment Content Reference Mark) §17.13.4.5 - contentPart (Content Part) §17.3.3.2 - continuationSeparator (Continuation Separator Mark) §17.11.1 - cr (Carriage Return) §17.3.3.4 - dayLong (Date Block - Long Day Format) §17.3.3.5 - dayShort (Date Block - Short Day Format) §17.3.3.6 - delInstrText (Deleted Field Code) §17.16.13 - [done] delText (Deleted Text) §17.3.3.7 - [done] drawing (DrawingML Object) §17.3.3.9 - endnoteRef (Endnote Reference Mark) §17.11.6 - [done] endnoteReference (Endnote Reference) §17.11.7 - [done] fldChar (Complex Field Character) §17.16.18 - footnoteRef (Footnote Reference Mark) §17.11.13 - [done] footnoteReference (Footnote Reference) §17.11.14 - [done] instrText (Field Code) §17.16.23 - [done] lastRenderedPageBreak (Position of Last Calculated Page Break) §17.3.3.13 - monthLong (Date Block - Long Month Format) §17.3.3.15 - monthShort (Date Block - Short Month Format) §17.3.3.16 - noBreakHyphen (Non Breaking Hyphen Character) §17.3.3.18 - [done] object (Embedded Object) §17.3.3.19 - pgNum (Page Number Block) §17.3.3.22 - [done] ptab (Absolute Position Tab Character) §17.3.3.23 - [done] rPr (Run Properties) §17.3.2.28 - ruby (Phonetic Guide) §17.3.3.25 - separator (Footnote/Endnote Separator Mark) §17.11.23 - softHyphen (Optional Hyphen Character) §17.3.3.29 - sym (Symbol Character) §17.3.3.30 - [done] t (Text) §17.3.3.31 - [done] tab (Tab Character) §17.3.3.32 - yearLong (Date Block - Long Year Format) §17.3.3.33 - yearShort (Date Block - Short Year Format) §17.3.3.34 VML child elements (see Part 4): - [done] pict (VML Object) §9.2.2.2 */ //! @todo support all elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_r() { READ_PROLOGUE m_currentTextStyle = KoGenStyle(KoGenStyle::TextAutoStyle, "text"); if (m_moveToStylesXml) { m_currentTextStyle.setAutoStyleInStylesDotXml(true); } KoXmlWriter* oldWriter = body; // DropCapRead means we have read the w:dropCap attribute on this // paragraph and now have to save the text. // DropCapDone means we are in the next paragraph and want to add // the saved text to this paragraph. if (m_dropCapStatus == DropCapRead) { m_dropCapStatus = DropCapDone; m_dropCapBuffer = new QBuffer; m_dropCapBuffer->open(QIODevice::ReadWrite); m_dropCapWriter = new KoXmlWriter(m_dropCapBuffer); body = m_dropCapWriter; } else if (m_dropCapStatus == DropCapDone) { body->addCompleteElement(m_dropCapBuffer); delete m_dropCapWriter; delete m_dropCapBuffer; m_dropCapBuffer = 0; m_dropCapWriter = 0; m_dropCapStatus = NoDropCap; } MSOOXML::Utils::XmlWriteBuffer buffer; body = buffer.setWriter(body); while (!atEnd()) { readNext(); kDebug() << *this; BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF(rPr) ELSE_TRY_READ_IF(t) ELSE_TRY_READ_IF(ptab) ELSE_TRY_READ_IF(delText) ELSE_TRY_READ_IF(drawing) ELSE_TRY_READ_IF(endnoteReference) ELSE_TRY_READ_IF(footnoteReference) ELSE_TRY_READ_IF(object) else if (name() == "pict") { // Protecting in case the object is inside a textbox inside a shape VMLShapeProperties oldProperties = m_currentVMLProperties; TRY_READ(pict) m_currentVMLProperties = oldProperties; } ELSE_TRY_READ_IF(instrText) ELSE_TRY_READ_IF(fldChar) ELSE_TRY_READ_IF(lastRenderedPageBreak) ELSE_TRY_READ_IF(br) ELSE_TRY_READ_IF_NS(mc, AlternateContent) else if (qualifiedName() == "w:tab") { body->startElement("text:tab"); body->endElement(); // text:tab } SKIP_UNKNOWN //! @todo add ELSE_WRONG_FORMAT } } //NOTE: Workaround until text:display="none" support. if (m_currentTextStyle.property("text:display") == "none") { body = buffer.originalWriter(); READ_EPILOGUE } if (m_currentTextStyle.parentName().isEmpty()) { if (m_context->m_namedDefaultStyles.contains("text")) { m_currentTextStyle.setParentName(m_context->m_namedDefaultStyles.value("text")); } } // inserted/deleted run content, use a different color and // underline/line-through if (!m_changeTrackingState.isEmpty()) { if (m_changeTrackingState.top() == InsertedRunContent) { m_currentTextStyle.addProperty("style:text-underline-mode", "continuous"); m_currentTextStyle.addProperty("style:text-underline-style", "solid"); m_currentTextStyle.addProperty("style:text-underline-type", "single"); m_currentTextStyle.addProperty("style:text-underline-width", "auto"); } else { m_currentTextStyle.addProperty("style:text-line-through-mode", "continuous"); m_currentTextStyle.addProperty("style:text-line-through-style", "solid"); m_currentTextStyle.addProperty("style:text-line-through-type", "single"); m_currentTextStyle.addProperty("style:text-line-through-width", "auto"); } m_currentTextStyle.addProperty("style:text-underline-color", "#800080"); m_currentTextStyle.addProperty("fo:color", "#800080"); } // We want to write to the higher body level body = buffer.originalWriter(); QString currentTextStyleName; if (!m_currentTextStyle.isEmpty() || !m_currentTextStyle.parentName().isEmpty()) { currentTextStyleName = mainStyles->insert(m_currentTextStyle); } if (m_complexCharStatus == ExecuteInstrNow || m_complexCharType == InternalHyperlinkComplexFieldCharType) { if (m_complexCharType == HyperlinkComplexFieldCharType || m_complexCharType == InternalHyperlinkComplexFieldCharType) { body->startElement("text:a", false); body->addAttribute("xlink:type", "simple"); if (m_complexCharType == HyperlinkComplexFieldCharType) { body->addAttribute("xlink:href", QUrl(m_complexCharValue).toEncoded()); } else { int spacePosition = m_complexCharValue.indexOf(' '); QString textValue = "#"; textValue.append(m_complexCharValue.left(spacePosition)); m_complexCharValue.remove(0, textValue.length()); body->addAttribute("xlink:href", QUrl(textValue).toEncoded()); } } } if (!currentTextStyleName.isEmpty()) { body->startElement("text:span", false); body->addAttribute("text:style-name", currentTextStyleName); } m_closeHyperlink = handleSpecialField(); if (m_complexCharStatus == ExecuteInstrNow) { if (m_complexCharType == ReferenceNextComplexFieldCharType) { body->startElement("text:bookmark-ref"); body->addAttribute("text:reference-format", "page"); body->addAttribute("text:ref-name", m_complexCharValue); m_closeHyperlink = true; } else { m_specialCharacters = m_complexCharValue; m_closeHyperlink = handleSpecialField(); } } if (m_complexCharType == InternalHyperlinkComplexFieldCharType || m_complexCharType == MacroButtonFieldCharType) { body->addTextSpan(m_complexCharValue); } // Writing the internal body of read_t now body = buffer.releaseWriter(); if (m_closeHyperlink) { body->endElement(); //either text:bookmark-ref or text:a or text:page-number etc. m_closeHyperlink = false; } if (!currentTextStyleName.isEmpty()) { body->endElement(); //text:span } if (m_complexCharStatus == InstrExecute) { if (m_complexCharType == ReferenceComplexFieldCharType) { m_complexCharType = ReferenceNextComplexFieldCharType; } } if (m_complexCharStatus == ExecuteInstrNow && m_complexCharType == HyperlinkComplexFieldCharType) { body->endElement(); // text:a } else if (m_complexCharType == InternalHyperlinkComplexFieldCharType) { body->endElement(); // text:a } // Case where there's hyperlink with read_instrText, we only want to use the link // with the next r element, not this. if (m_complexCharStatus == InstrExecute) { m_complexCharStatus = ExecuteInstrNow; } if (m_dropCapStatus == DropCapDone) { body = oldWriter; } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL rPr //! [1] rPr handler (Run Properties for the Paragraph Mark) WML ECMA-376, 17.3.1.29, p.263, //! This element specifies a set of run properties which shall be applied to the contents //! of the parent run after all style formatting has been applied to the text. //! [2] rPr handler (Run Properties) WML ECMA-376, 17.3.2.28, p.331, //! This element specifies a set of run properties which shall be applied to the contents //! of the parent run after all style formatting has been applied to the text. /*! Parent elements: - [1] pPr (§17.3.1.26) - [2] ctrlPr (§22.1.2.23) - [2] r (§22.1.2.87) - Shared ML - [2] r (§17.3.2.25) Child elements: - [done] b (Bold) §17.3.2.1 - bCs (Complex Script Bold) §17.3.2.2 - [done] bdr (Text Border) §17.3.2.4 - [done] caps (Display All Characters As Capital Letters) §17.3.2.5 - [done] color (Run Content Color) §17.3.2.6 - cs (Use Complex Script Formatting on Run) §17.3.2.7 - del (Deleted Paragraph) §17.13.5.15 - [done] dstrike (Double Strikethrough) §17.3.2.9 - eastAsianLayout (East Asian Typography Settings) §17.3.2.10 - effect (Animated Text Effect) §17.3.2.11 - em (Emphasis Mark) §17.3.2.12 - emboss (Embossing) §17.3.2.13 - fitText (Manual Run Width) §17.3.2.14 - [done] highlight (Text Highlighting) §17.3.2.15 - [done] i (Italics) §17.3.2.16 - iCs (Complex Script Italics) §17.3.2.17 - imprint (Imprinting) §17.3.2.18 - ins (Inserted Paragraph) §17.13.5.20 - kern (Font Kerning) §17.3.2.19 - [done] lang (Languages for Run Content) §17.3.2.20 - moveFrom (Move Source Paragraph) §17.13.5.21 - moveTo (Move Destination Paragraph) §17.13.5.26 - noProof (Do Not Check Spelling or Grammar) §17.3.2.21 - oMath (Office Open XML Math) §17.3.2.22 - [done] outline (Display Character Outline) §17.3.2.23 - position (Vertically Raised or Lowered Text) §17.3.2.24 - [done] rFonts (Run Fonts) §17.3.2.26 - rPrChange (Revision Information for Run Properties on the Paragraph Mark) §17.13.5.30 - [done] rStyle (Referenced Character Style) §17.3.2.29 - rtl (Right To Left Text) §17.3.2.30 - shadow (Shadow) §17.3.2.31 - [done] shd (Run Shading) §17.3.2.32 - [done] smallCaps (Small Caps) §17.3.2.33 - snapToGrid (Use Document Grid Settings For Inter-Character Spacing) §17.3.2.34 - [done] spacing (Character Spacing Adjustment) §17.3.2.35 - specVanish (Paragraph Mark Is Always Hidden) §17.3.2.36 - [done] strike (Single Strikethrough) §17.3.2.37 - [done] sz (Non-Complex Script Font Size) §17.3.2.38 - szCs (Complex Script Font Size) §17.3.2.39 - [done] u (Underline) §17.3.2.40 - [done] vanish (Hidden Text) §17.3.2.41 - [done] vertAlign (Subscript/Superscript Text) §17.3.2.42 - [done] w (Expanded/Compressed Text) §17.3.2.43 - [done] webHidden (Web Hidden Text) §17.3.2.44 */ //! @todo support all elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_rPr() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); Q_ASSERT(m_currentTextStyleProperties == 0); m_currentTextStyleProperties = new KoCharacterStyle(); while (!atEnd()) { readNext(); kDebug() << *this; BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF(b) ELSE_TRY_READ_IF(i) ELSE_TRY_READ_IF(u) ELSE_TRY_READ_IF(sz) ELSE_TRY_READ_IF(strike) ELSE_TRY_READ_IF(dstrike) ELSE_TRY_READ_IF(rStyle) ELSE_TRY_READ_IF(color) ELSE_TRY_READ_IF(highlight) ELSE_TRY_READ_IF(lang) ELSE_TRY_READ_IF_IN_CONTEXT(shd) ELSE_TRY_READ_IF(vertAlign) ELSE_TRY_READ_IF(rFonts) ELSE_TRY_READ_IF(spacing) ELSE_TRY_READ_IF(outline) ELSE_TRY_READ_IF(caps) ELSE_TRY_READ_IF(smallCaps) ELSE_TRY_READ_IF(w) ELSE_TRY_READ_IF(webHidden) ELSE_TRY_READ_IF(bdr) ELSE_TRY_READ_IF(vanish) SKIP_UNKNOWN //! @todo add ELSE_WRONG_FORMAT } } m_currentTextStyleProperties->saveOdf(m_currentTextStyle); delete m_currentTextStyleProperties; m_currentTextStyleProperties = 0; READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL pPr //! pPr handler (Paragraph Properties) /*! 1. pPr (Paragraph Properties) 17.3.1.26, p.259. Parent elements: - [done] p (§17.3.1.22) - common reader 2. pPr (Paragraph Properties) 17.7.5.2, p.725. Parent elements: - [done] pPrDefault - DocxXmlStylesReader 3. pPr (Table Style Conditional Formatting Paragraph Properties) 17.7.6.1, p.733. Parent elements: - tblStylePr (§17.7.6.6) 4. pPr (Style Paragraph Properties) 17.7.8.2, p.752. Parent elements: - [done] style (§17.7.4.17) - DocxXmlStylesReader 5. pPr (Numbering Level Associated Paragraph Properties) 17.9.23, p.818. Parent elements: - lvl (§17.9.6) - lvl (§17.9.7) Child elements: - adjustRightInd (Automatically Adjust Right Indent When Using Document Grid) §17.3.1.1 - autoSpaceDE (Automatically Adjust Spacing of Latin and East Asian Text) §17.3.1.2 - autoSpaceDN (Automatically Adjust Spacing of East Asian Text and Numbers) §17.3.1.3 - bidi (Right to Left Paragraph Layout) §17.3.1.6 - cnfStyle (Paragraph Conditional Formatting) §17.3.1.8 - contextualSpacing (Ignore Spacing Above and Below When Using Identical Styles) §17.3.1.9 - divId (Associated HTML div ID) §17.3.1.10 - [done] framePr (Text Frame Properties) §17.3.1.11 - ind (Paragraph Indentation) §17.3.1.12 - [done] jc (Paragraph Alignment) §17.3.1.13 - keepLines (Keep All Lines On One Page) §17.3.1.14 - keepNext (Keep Paragraph With Next Paragraph) §17.3.1.15 - kinsoku (Use East Asian Typography Rules for First and Last Character per Line) §17.3.1.16 - mirrorIndents (Use Left/Right Indents as Inside/Outside Indents) §17.3.1.18 - [done] numPr (Numbering Definition Instance Reference) §17.3.1.19 - outlineLvl (Associated Outline Level) §17.3.1.20 - overflowPunct (Allow Punctuation to Extend Past Text Extents) §17.3.1.21 - pageBreakBefore (Start Paragraph on Next Page) §17.3.1.23 - [done] pBdr (Paragraph Borders) §17.3.1.24 - pPrChange (Revision Information for Paragraph Properties) §17.13.5.29 - [done] pStyle (Referenced Paragraph Style) §17.3.1.27 - [done] rPr (Run Properties for the Paragraph Mark) §17.3.1.29 - [done] sectPr (Section Properties) §17.6.18 - [done] shd (Paragraph Shading) §17.3.1.31 - snapToGrid (Use Document Grid Settings for Inter-Line Paragraph Spacing) §17.3.1.32 - [done] spacing (Spacing Between Lines and Above/Below Paragraph) §17.3.1.33 - suppressAutoHyphens (Suppress Hyphenation for Paragraph) §17.3.1.34 - [done] suppressLineNumbers (Suppress Line Numbers for Paragraph) §17.3.1.35 - suppressOverlap (Prevent Text Frames From Overlapping) §17.3.1.36 - [done] tabs (Set of Custom Tab Stops) §17.3.1.38 - textAlignment (Vertical Character Alignment on Line) §17.3.1.39 - textboxTightWrap (Allow Surrounding Paragraphs to Tight Wrap to Text Box Contents) §17.3.1.40 - textDirection (Paragraph Text Flow Direction) §17.3.1.41 - topLinePunct (Compress Punctuation at Start of a Line) §17.3.1.43 - widowControl (Allow First/Last Line to Display on a Separate Page) §17.3.1.44 - wordWrap (Allow Line Breaking At Character Level) §17.3.1.45 */ //! CASE #850 -> CASE #853 //! @todo support all elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_pPr() { READ_PROLOGUE while (!atEnd()) { readNext(); kDebug() << *this; BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { if (name() == "rPr") { m_currentTextStyle = KoGenStyle(KoGenStyle::TextAutoStyle, "text"); TRY_READ(rPr) KoGenStyle::copyPropertiesFromStyle(m_currentTextStyle, m_currentParagraphStyle, KoGenStyle::TextType); } ELSE_TRY_READ_IF_IN_CONTEXT(shd) ELSE_TRY_READ_IF_IN_CONTEXT(jc) ELSE_TRY_READ_IF(tabs) ELSE_TRY_READ_IF(spacing) ELSE_TRY_READ_IF(pStyle) ELSE_TRY_READ_IF(numPr) ELSE_TRY_READ_IF(pBdr) ELSE_TRY_READ_IF(framePr) ELSE_TRY_READ_IF(ind) ELSE_TRY_READ_IF(suppressLineNumbers) ELSE_TRY_READ_IF(sectPr) SKIP_UNKNOWN //! @todo add ELSE_WRONG_FORMAT } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL webHidden //! webHidden handler (Web Hidden Text) /*! Parent elements: - [done] rPr (§17.3.1.29) - [done] rPr (§17.3.1.30) - [done] rPr (§17.5.2.28) - [done] rPr (§17.9.25) - [done] rPr (§17.7.9.1) - [done] rPr (§17.7.5.4) - [done] rPr (§17.3.2.28) - [done] rPr (§17.5.2.27) - [done] rPr (§17.7.6.2) - [done] rPr (§17.3.2.27) Child elements: - none */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_webHidden() { READ_PROLOGUE //! TODO: implement hidden readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL bookmarkStart //! bookmarkStart handler (Bookmark Start) /*! Parent elements: - bdo (§17.3.2.3) - body (§17.2.2) - comment (§17.13.4.2) - customXml (§17.5.1.6) - customXml (§17.5.1.4) - customXml (§17.5.1.5) - customXml (§17.5.1.3) - deg (§22.1.2.26) - del (§17.13.5.14) - den (§22.1.2.28) - dir (§17.3.2.8) - docPartBody (§17.12.6) - e (§22.1.2.32) - [done] endnote (§17.11.2) - fldSimple (§17.16.19) - fName (§22.1.2.37) - [done] footnote (§17.11.10) - [done] ftr (§17.10.3) - [done] hdr (§17.10.4) - [done] hyperlink (§17.16.22) - ins (§17.13.5.18) - lim (§22.1.2.52) - moveFrom (§17.13.5.22) - moveTo (§17.13.5.25) - num (§22.1.2.75) - oMath (§22.1.2.77) - [done p (§17.3.1.22) - rt (§17.3.3.24) - rubyBase (§17.3.3.27) - sdtContent (§17.5.2.34) - sdtContent (§17.5.2.33) - sdtContent (§17.5.2.35) - sdtContent (§17.5.2.36) - [done] smartTag (§17.5.1.9) - sub (§22.1.2.112) - sup (§22.1.2.114) - tbl (§17.4.38) - tc (§17.4.66) - tr (§17.4.79) Child elements: - none */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_bookmarkStart() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(name) TRY_READ_ATTR(id) if (!name.isEmpty() && !id.isEmpty()) { MSOOXML::Utils::XmlWriteBuffer buffer; //bookmark presence limitation by ODF 1.2 if (!m_insideParagraph) { body = buffer.setWriter(body); } body->startElement("text:bookmark-start"); body->addAttribute("text:name", name); body->endElement(); // text:bookmark-start m_bookmarks[id] = name; if (!m_insideParagraph) { body = buffer.releaseWriter(m_bookmarkSnippet); } } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL bookmarkEnd //! bookmarkEnd handler (Bookmark End) /*! Parent elements: - bdo (§17.3.2.3) - body (§17.2.2) - comment (§17.13.4.2) - customXml (§17.5.1.6) - customXml (§17.5.1.4) - customXml (§17.5.1.5) - customXml (§17.5.1.3) - deg (§22.1.2.26) - del (§17.13.5.14) - den (§22.1.2.28) - dir (§17.3.2.8) - docPartBody (§17.12.6) - e (§22.1.2.32) - [done] endnote (§17.11.2) - fldSimple (§17.16.19) - fName (§22.1.2.37) - [done] footnote (§17.11.10) - [done] ftr (§17.10.3) - [done] hdr (§17.10.4) - [done] hyperlink (§17.16.22) - ins (§17.13.5.18) - lim (§22.1.2.52) - moveFrom (§17.13.5.22) - moveTo (§17.13.5.25) - num (§22.1.2.75) - oMath (§22.1.2.77) - [done p (§17.3.1.22) - rt (§17.3.3.24) - rubyBase (§17.3.3.27) - sdtContent (§17.5.2.34) - sdtContent (§17.5.2.33) - sdtContent (§17.5.2.35) - sdtContent (§17.5.2.36) - [done] smartTag (§17.5.1.9) - sub (§22.1.2.112) - sup (§22.1.2.114) - tbl (§17.4.38) - tc (§17.4.66) - tr (§17.4.79) Child elements: - none */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_bookmarkEnd() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(id) if (!id.isEmpty()) { MSOOXML::Utils::XmlWriteBuffer buffer; //bookmark presence limitation by ODF 1.2 if (!m_insideParagraph) { body = buffer.setWriter(body); } body->startElement("text:bookmark-end"); body->addAttribute("text:name", m_bookmarks[id]); body->endElement(); // text:bookmark-end if (!m_insideParagraph) { body = buffer.releaseWriter(m_bookmarkSnippet); } } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL numPr //! numPr handler (Numbering Definition Instance Reference) /*! This element specifies that the current paragraph references a numbering definition instance in the current document. The presence of this element specifies that the paragraph will inherit the properties specified by the numbering definition in the num element (§2.9.16) at the level specified by the level specified in the lvl element (§2.9.7) and shall have an associated number positioned before the beginning of the text flow in this paragraph. When this element appears as part of the paragraph formatting for a paragraph style, then any numbering level defined using the ilvl element shall be ignored, and the pStyle element (§2.9.25) on the associated abstract numbering definition shall be used instead. Parent elements: - [done] pPr (§17.3.1.26); - [done] pPr (§17.3.1.25); - [done] pPr (§17.7.5.2); - [done] pPr (§17.7.6.1); - [done] pPr (§17.9.23); - [done] pPr (§17.7.8.2) Child elements: - [done] ilvl (Numbering Level Reference) §17.9.3 - ins (Inserted Numbering Properties) §17.13.5.19 - [done] numId (Numbering Definition Instance Reference) §17.9.19 */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_numPr() { READ_PROLOGUE m_listFound = true; m_currentListLevel = 0; while (!atEnd()) { readNext(); kDebug() << *this; BREAK_IF_END_OF(CURRENT_EL); if (isStartElement()) { TRY_READ_IF(numId) ELSE_TRY_READ_IF(ilvl) SKIP_UNKNOWN //! @todo add ELSE_WRONG_FORMAT } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL ilvl //! ilvl handler (Numbering Level Reference) /*! This element specifies the numbering level of the numbering definition instance which shall be applied to the parent paragraph. This numbering level is specified on either the abstract numbering definition's lvl element (§2.9.7), and may be overridden by a numbering definition instance level override's lvl element (§2.9.6). */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_ilvl() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(val) if (!val.isEmpty()) { bool ok = false; uint listValue = val.toUInt(&ok); if (ok) { m_currentListLevel = listValue; } } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL numId //! numPr handler (Numbering Definition Instance Reference) /*! This element specifies that the current paragraph references a numbering definition instance in the current document. The presence of this element specifies that the paragraph will inherit the properties specified by the numbering definition in the num element (§2.9.16) at the level specified by the level specified in the lvl element (§2.9.7) and shall have an associated number positioned before the beginning of the text flow in this paragraph. When this element appears as part of the paragraph formatting for a paragraph style, then any numbering level defined using the ilvl element shall be ignored, and the pStyle element (§2.9.25) on the associated abstract numbering definition shall be used instead. Parent elements: - [done] numPr (§17.3.1.19) Child elements: - none */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_numId() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(val) // In docx, this value defines a predetermined style from numbering xml, // The styles from numbering have to be given some name, NumStyle has been // chosen here if (!val.isEmpty()) { if (val == "0") { m_listFound = false; // spec says that this means deleted list } else { m_currentBulletList = m_context->m_bulletStyles[val]; m_currentNumId = val; } } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL delText //! delText (Deleted Text) /*! ECMA-376, 17.3.3.7, p.351. This element specifies that this run contains literal text which shall be displayed in the document. The delText element shall be used for all text runs which are part of a region of text that is contained in a deleted region using the del element. Parent Elements: - [done] r (§22.1.2.87) - [done] r (§17.3.2.25) @todo: attribute xml:space */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_delText() { READ_PROLOGUE while (!atEnd()) { readNext(); if (isCharacters()) { body->addTextSpan(text().toString()); } BREAK_IF_END_OF(CURRENT_EL) } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL drawing //! drawing handler (DrawingML Object) /*! ECMA-376, 17.3.3.9, p.362. This element specifies that a DrawingML object is located at this position in the run’s contents. The layout properties of this DrawingML object are specified using the WordprocessingML Drawing syntax (§20.4, p. 3466). Parent elements: - background (§17.2.1) - numPicBullet (§17.9.21) - object (§17.3.3.19) - r (§22.1.2.87) - Shared ML - [done] r (§17.3.2.25) Child elements: - [done] anchor (Anchor for Floating DrawingML Object) §20.4.2.3 - [done] inline (Inline DrawingML Object) §20.4.2.8 */ //! CASE #1300 //! CASE #1301 //! CASE #1380 KoFilter::ConversionStatus DocxXmlDocumentReader::read_drawing() { READ_PROLOGUE m_hyperLink = false; m_hasPosOffsetH = false; m_hasPosOffsetV = false; m_rot = 0; m_z_index = 0; pushCurrentDrawStyle(new KoGenStyle(KoGenStyle::GraphicAutoStyle, "graphic")); if (m_moveToStylesXml) { m_currentDrawStyle->setAutoStyleInStylesDotXml(true); } applyBorders(m_currentDrawStyle, m_textBorderStyles, m_textBorderPaddings); m_drawing_anchor = false; m_drawing_inline = false; MSOOXML::Utils::XmlWriteBuffer buffer; body = buffer.setWriter(body); while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF_NS(wp, anchor) ELSE_TRY_READ_IF_NS(wp, inline) ELSE_WRONG_FORMAT } } body = buffer.originalWriter(); if (m_hyperLink) { body->startElement("text:a"); body->addAttribute("xlink:type", "simple"); body->addAttribute("xlink:href", QUrl(m_hyperLinkTarget).toEncoded()); } if (m_context->graphicObjectIsGroup) { body->startElement("draw:g"); } else { body->startElement("draw:frame"); + body->addAttribute("draw:layer", "layout"); + + if (m_hasPosOffsetH) { + kDebug() << "m_posOffsetH" << m_posOffsetH; + m_svgX += m_posOffsetH; + } + if (m_hasPosOffsetV) { + kDebug() << "m_posOffsetV" << m_posOffsetV; + m_svgY += m_posOffsetV; + } + + if (!m_docPrName.isEmpty()) { // from docPr/@name + body->addAttribute("draw:name", m_docPrName); + } + + if (m_rot == 0) { + body->addAttribute("svg:x", EMU_TO_CM_STRING(m_svgX)); + body->addAttribute("svg:y", EMU_TO_CM_STRING(m_svgY)); + } else { + // m_rot is in 1/60,000th of a degree + qreal angle, xDiff, yDiff; + MSOOXML::Utils::rotateString(m_rot, m_svgWidth, m_svgHeight, angle, xDiff, yDiff); + QString rotString = QString("rotate(%1) translate(%2cm %3cm)") + .arg(angle).arg((m_svgX + xDiff)/360000).arg((m_svgY + yDiff)/360000); + body->addAttribute("draw:transform", rotString); + } + + body->addAttribute("svg:width", EMU_TO_CM_STRING(m_svgWidth)); + body->addAttribute("svg:height", EMU_TO_CM_STRING(m_svgHeight)); } +//! @todo add more cases for text:anchor-type! use m_drawing_inline and see CASE #1343 if (m_drawing_inline) { body->addAttribute("text:anchor-type", "as-char"); m_currentDrawStyle->addProperty("style:vertical-rel", "baseline"); } else { body->addAttribute("draw:z-index", m_z_index); if (m_alignH.isEmpty()) { m_currentDrawStyle->addProperty("style:horizontal-pos", "from-left"); } else { m_currentDrawStyle->addProperty("style:horizontal-pos", m_alignH); } if (m_alignV.isEmpty()) { m_currentDrawStyle->addProperty("style:vertical-pos", "from-top"); } else if (m_alignV == "center") { m_currentDrawStyle->addProperty("style:vertical-pos", "middle"); } else if (m_alignV == "bottom") { m_currentDrawStyle->addProperty("style:vertical-pos", "bottom"); } else if (m_alignV == "top") { m_currentDrawStyle->addProperty("style:vertical-pos", "top"); } else if (m_alignV == "outside") { m_currentDrawStyle->addProperty("style:vertical-pos", "bottom"); } else if (m_alignV == "inside") { m_currentDrawStyle->addProperty("style:vertical-pos", "top"); } if (m_relativeFromV == "column") { m_currentDrawStyle->addProperty("style:vertical-rel", "paragraph"); } else if (m_relativeFromV == "bottomMargin") { // Not supported propery by ODF, making a best guess m_currentDrawStyle->addProperty("style:vertical-rel", "page"); m_currentDrawStyle->addProperty("style:vertical-pos", "bottom"); } else if (m_relativeFromV == "insideMargin") { // Not supported propery by ODF, making a best guess m_currentDrawStyle->addProperty("style:vertical-rel", "page"); m_currentDrawStyle->addProperty("style:vertical-pos", "top"); } else if (m_relativeFromV == "line") { m_currentDrawStyle->addProperty("style:vertical-rel", "paragraph"); } else if (m_relativeFromV == "margin") { if (m_headerActive || m_footerActive) { m_currentDrawStyle->addProperty("style:vertical-rel", "frame-content"); } else { m_currentDrawStyle->addProperty("style:vertical-rel", "page-content"); } } else if (m_relativeFromV == "outsideMargin") { // Not supported propery by ODF, making a best guess m_currentDrawStyle->addProperty("style:vertical-rel", "page"); m_currentDrawStyle->addProperty("style:vertical-pos", "bottom"); } else if (m_relativeFromV == "page") { if (m_headerActive || m_footerActive) { m_currentDrawStyle->addProperty("style:vertical-rel", "frame"); } else { m_currentDrawStyle->addProperty("style:vertical-rel", "page"); } } else if (m_relativeFromV == "paragraph") { m_currentDrawStyle->addProperty("style:vertical-rel", "paragraph"); } else if (m_relativeFromV == "topMargin") { m_currentDrawStyle->addProperty("style:vertical-rel", "page"); m_currentDrawStyle->addProperty("style:vertical-pos", "top"); } if (m_relativeFromH == "character") { m_currentDrawStyle->addProperty("style:horizontal-rel", "char"); body->addAttribute("text:anchor-type", "char"); } else if (m_relativeFromH == "column") { m_currentDrawStyle->addProperty("style:horizontal-rel", "paragraph"); body->addAttribute("text:anchor-type", "paragraph"); } else if (m_relativeFromH == "insideMargin") { m_currentDrawStyle->addProperty("style:horizontal-rel", "page-start-margin"); body->addAttribute("text:anchor-type", "paragraph"); } else if (m_relativeFromH == "leftMargin") { m_currentDrawStyle->addProperty("style:horizontal-rel", "page-start-margin"); body->addAttribute("text:anchor-type", "paragraph"); } else if (m_relativeFromH == "margin") { m_currentDrawStyle->addProperty("style:horizontal-rel", "page-content"); body->addAttribute("text:anchor-type", "paragraph"); } else if (m_relativeFromH == "outsideMargin") { m_currentDrawStyle->addProperty("style:horizontal-rel", "page-end-margin"); body->addAttribute("text:anchor-type", "paragraph"); } else if (m_relativeFromH == "page") { m_currentDrawStyle->addProperty("style:horizontal-rel", "page"); body->addAttribute("text:anchor-type", "paragraph"); } else if (m_relativeFromH == "rightMargin") { m_currentDrawStyle->addProperty("style:horizontal-rel", "page-end-margin"); body->addAttribute("text:anchor-type", "paragraph"); } } const QString styleName(mainStyles->insert(*m_currentDrawStyle, "gr")); body->addAttribute("draw:style-name", styleName); -//! @todo add more cases for text:anchor-type! use m_drawing_inline and see CASE #1343 - if (m_hasPosOffsetH) { - kDebug() << "m_posOffsetH" << m_posOffsetH; - m_svgX += m_posOffsetH; - } - if (m_hasPosOffsetV) { - kDebug() << "m_posOffsetV" << m_posOffsetV; - m_svgY += m_posOffsetV; - } - - if (!m_docPrName.isEmpty()) { // from docPr/@name - body->addAttribute("draw:name", m_docPrName); - } - body->addAttribute("draw:layer", "layout"); - - if (m_rot == 0) { - body->addAttribute("svg:x", EMU_TO_CM_STRING(m_svgX)); - body->addAttribute("svg:y", EMU_TO_CM_STRING(m_svgY)); - } - else { - // m_rot is in 1/60,000th of a degree - qreal angle, xDiff, yDiff; - MSOOXML::Utils::rotateString(m_rot, m_svgWidth, m_svgHeight, angle, xDiff, yDiff); - QString rotString = QString("rotate(%1) translate(%2cm %3cm)") - .arg(angle).arg((m_svgX + xDiff)/360000).arg((m_svgY + yDiff)/360000); - body->addAttribute("draw:transform", rotString); - } - - body->addAttribute("svg:width", EMU_TO_CM_STRING(m_svgWidth)); - body->addAttribute("svg:height", EMU_TO_CM_STRING(m_svgHeight)); - popCurrentDrawStyle(); (void)buffer.releaseWriter(); - body->endElement(); // draw:frame + body->endElement(); // draw:frame/draw:g if (m_hyperLink) { body->endElement(); // text:a } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL framePr //! framePr handler (Text Frame Properties) /*! Parent elements: - [done] pPr (§17.3.1.26) - [done] pPr (§17.3.1.25) - [done] pPr (§17.7.5.2) - [done] pPr (§17.7.6.1) - [done] pPr (§17.9.23) - [done] pPr (§17.7.8.2) No child elements. */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_framePr() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(dropCap) TRY_READ_ATTR(lines) TRY_READ_ATTR(hSpace) // MS 2007 behaves so that it ignores text and paragraph styles in // case of drop cap for the first letter(s), here we set a // variable to show we have encountered a drop cap. if (!dropCap.isEmpty()) { m_dropCapStatus = DropCapRead; m_dropCapDistance = 0; m_dropCapLines.clear(); if (!lines.isEmpty()) { m_dropCapLines = lines; } if (!hSpace.isEmpty()) { bool ok; const qreal distance = qreal(TWIP_TO_POINT(hSpace.toDouble(&ok))); if (ok) { m_dropCapDistance = distance; } } } //! @todo more attributes readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL suppressLineNumbers //! w:suppressLineNumbers handler /* Parent elements: - [done] pPr (§17.3.1.26) - [done] pPr (§17.3.1.25) - [done] pPr (§17.7.5.2) - [done] pPr (§17.7.6.1) - [done] pPr (§17.9.23) - [done] pPr (§17.7.8.2) */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_suppressLineNumbers() { READ_PROLOGUE m_currentParagraphStyle.addProperty("text:number-lines", "false"); readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL ind //! ind handler //! CASE KoFilter::ConversionStatus DocxXmlDocumentReader::read_ind() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(left) bool ok = false; const qreal leftInd = qreal(TWIP_TO_POINT(left.toDouble(&ok))); if (ok) { m_currentParagraphStyle.addPropertyPt("fo:margin-left", leftInd); } // TODO: Values in {none, first-line, hanging) are from the // "Special" field of the Paragraph dialog in MS Word. The // tab-stop position in case of a list item and the implicit // tab-stop for a paragraph with hanging indent depend on this. // Check the MsooXmlUtils::convertToListProperties function. TRY_READ_ATTR(firstLine) TRY_READ_ATTR(hanging) if (!hanging.isEmpty()) { const qreal firstInd = qreal(TWIP_TO_POINT(hanging.toDouble(&ok))); if (ok) { m_currentParagraphStyle.addPropertyPt("fo:text-indent", -firstInd); } } else if (!firstLine.isEmpty()) { const qreal firstInd = qreal(TWIP_TO_POINT(firstLine.toDouble(&ok))); if (ok) { m_currentParagraphStyle.addPropertyPt("fo:text-indent", firstInd); } } TRY_READ_ATTR(right) const int rightInd = qreal(TWIP_TO_POINT(right.toDouble(&ok))); if (ok) { m_currentParagraphStyle.addPropertyPt("fo:margin-right", rightInd); } //! @todo more attributes readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL b //! b handler //! CASE #1112 KoFilter::ConversionStatus DocxXmlDocumentReader::read_b() { READ_PROLOGUE if (READ_BOOLEAN_VAL) { m_currentTextStyle.addProperty("fo:font-weight", "bold"); } else { m_currentTextStyle.addProperty("fo:font-weight", "normal"); } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL i //! i handler //! CASE #1112 KoFilter::ConversionStatus DocxXmlDocumentReader::read_i() { READ_PROLOGUE if (READ_BOOLEAN_VAL) { m_currentTextStyle.addProperty("fo:font-style", "italic"); } else { m_currentTextStyle.addProperty("fo:font-style", "normal"); } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL u //! u handler //! CASE #1149 KoFilter::ConversionStatus DocxXmlDocumentReader::read_u() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(val) //! @todo more styles MSOOXML::Utils::setupUnderLineStyle(val, m_currentTextStyleProperties); TRY_READ_ATTR(color) QColor c(MSOOXML::Utils::ST_HexColorRGB_to_QColor(color)); if (c.isValid()) { m_currentTextStyleProperties->setUnderlineColor(c); } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL sz //! sz handler (Non-Complex Script Font Size) ECMA-376, 17.3.2.38, p.342 /*! This element specifies the font size which shall be applied to all non complex script characters in the contents of this run when displayed. */ /*! Parent elements: - [done] rPr (§17.3.1.29) - rPr (§17.3.1.30) - rPr (§17.5.2.28) - rPr (§17.9.25) - [done] rPr (§17.7.9.1) - [done] rPr (§17.7.5.4) (within style) - [done] rPr (§17.3.2.28) - [done] rPr (§17.5.2.27) - [done] rPr (§17.7.6.2) - [done] rPr (§17.3.2.27) No child elements. */ //! @todo support all elements //! CASE #1162 KoFilter::ConversionStatus DocxXmlDocumentReader::read_sz() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); READ_ATTR(val) bool ok; const qreal pointSize = qreal(val.toUInt(&ok)) / 2.0; /* half-points */ if (ok) { // In case of drop cap, text size should not be read if (m_dropCapStatus != DropCapDone) { m_currentTextStyleProperties->setFontPointSize(pointSize); } } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL jc //! Paragraph Alignment /*! ECMA-376, 17.3.1.13, p.239 */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_jc(jcCaller caller) { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); READ_ATTR(val) // Does ODF support high/low/medium kashida ? val = val.toLower(); if ((val == "both") || (val == "distribute")) { if (caller == jc_pPr) { m_currentParagraphStyle.addProperty("fo:text-align", "justify"); } else { m_tableMainStyle->setHorizontalAlign(KoTblStyle::CenterAlign); } } else if (val == "center") { if (caller == jc_pPr) { m_currentParagraphStyle.addProperty("fo:text-align", val); } else { m_tableMainStyle->setHorizontalAlign(KoTblStyle::CenterAlign); } } else if ((val == "start") || (val == "left")) { if (caller == jc_pPr) { m_currentParagraphStyle.addProperty("fo:text-align", val); } else { m_tableMainStyle->setHorizontalAlign(KoTblStyle::LeftAlign); } } else if ((val == "right") || (val == "end")) { if (caller == jc_pPr) { m_currentParagraphStyle.addProperty("fo:text-align", val); } else { m_tableMainStyle->setHorizontalAlign(KoTblStyle::RightAlign); } } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL spacing //! spacing handler (Spacing Between Lines and Above/Below Paragraph) /*! ECMA-376, 17.3.1.33, p.269. This element specifies the inter-line and inter-paragraph spacing which shall be applied to the contents of this paragraph when it is displayed by a consumer. Parent elements: - [done] pPr (§17.3.1.26) - [done] pPr (§17.3.1.25) - [done] pPr (§17.7.5.2) - [done] pPr (§17.7.6.1) - [done] pPr (§17.9.23) - [done] pPr (§17.7.8.2) No child elements. @todo support all elements */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_spacing() { //TODO: afterLines, beforeLines are critical. READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); bool ok = true; int marginBottom = 10; bool afterAutospacing = MSOOXML::Utils::convertBooleanAttr(attrs.value("w:afterAutospacing").toString()); if (!afterAutospacing) { TRY_READ_ATTR(after) marginBottom = TWIP_TO_POINT(after.toDouble(&ok)); } if (ok) { m_currentParagraphStyle.addPropertyPt("fo:margin-bottom", marginBottom); } ok = true; int marginTop = 5; bool beforeAutospacing = MSOOXML::Utils::convertBooleanAttr(attrs.value("w:beforeAutospacing").toString()); if (!beforeAutospacing) { TRY_READ_ATTR(before) marginTop = TWIP_TO_POINT(before.toDouble(&ok)); } if (ok) { m_currentParagraphStyle.addPropertyPt("fo:margin-top", marginTop); } // for rPr TRY_READ_ATTR(val) const qreal pointSize = (TWIP_TO_POINT(val.toDouble(&ok))); if (ok) { m_currentTextStyle.addPropertyPt("fo:letter-spacing", qreal(pointSize) / 100.0); } TRY_READ_ATTR(lineRule) TRY_READ_ATTR(line) qreal lineSpace = line.toDouble(&ok); if (ok) { if (lineRule == "atLeast") { lineSpace = TWIP_TO_POINT(lineSpace); m_currentParagraphStyle.addPropertyPt("style:line-height-at-least", lineSpace); } else if (lineRule == "exact") { lineSpace = TWIP_TO_POINT(lineSpace); m_currentParagraphStyle.addPropertyPt("fo:line-height", lineSpace); } else { lineSpace = lineSpace / 2.4; // converting to percentage QString space = "%1"; space = space.arg(lineSpace); space.append('%'); m_currentParagraphStyle.addProperty("fo:line-height", space); } } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL shd //! Shading handler (object's shading attributes) /*! ECMA-376, 17.3.5, p.399 Parent Elements: - [done] pPr (Paragraph Properties) §17.3.1.26 - [done] tcPr (Table Cell Properties) §17.4.70 Attributes: - color (Shading Pattern Color) - fill (Shading Background Color) - themeColor (Shading Pattern Theme Color) - themeFill (Shading Background Theme Color) - themeFillShade (Shading Background Theme Color Shade) - themeFillTint (Shading Background Theme Color Tint) - themeShade (Shading Pattern Theme Color Shade) - themeTint (Shading Pattern Theme Color Tint) - [done] val (Shading Pattern) */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_shd(shdCaller caller) { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); READ_ATTR(val) val = val.toLower(); TRY_READ_ATTR(color) //kDebug() << m_callsNames; if (!color.isEmpty() && color != MsooXmlReader::constAuto) { QColor clr(MSOOXML::Utils::ST_HexColorRGB_to_QColor(color)); if (caller == shd_rPr && clr.isValid() && val == "solid") { m_currentTextStyleProperties->setBackground(clr); } } TRY_READ_ATTR(fill) QString fillColor = fill.toLower(); if (!fillColor.isEmpty() && fillColor != MsooXmlReader::constAuto) { fillColor.prepend("#"); if (caller == shd_pPr) { m_currentParagraphStyle.addProperty("fo:background-color", fillColor); } if (caller == shd_tcPr) { m_currentTableStyleProperties->backgroundColor = fillColor; m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::BackgroundColor; } if (caller == shd_rPr && val == "clear") { if (m_currentTextStyleProperties->background() == QBrush()) { QColor clr(fillColor); m_currentTextStyleProperties->setBackground(clr); } } } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL rFonts //! w:lang handler (Run Fonts) /*! ECMA-376, 17.3.2.26, p.323. Parent elements: - rPr (§17.3.1.29) (within p) - rPr (§17.3.1.30) - rPr (§17.5.2.28) - rPr (§17.9.25) - rPr (§17.7.9.1) - rPr (§17.7.5.4) (within style) - rPr (§17.3.2.28) - rPr (§17.5.2.27) - rPr (§17.7.6.2) - rPr (§17.3.2.27) No child elements. CASE #850 -> CASE #858 -> CASE #861 -> CASE #1150 @todo support all elements */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_rFonts() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); // CASE #1153 TRY_READ_ATTR(ascii) if (!ascii.isEmpty()) { m_currentTextStyle.addProperty("style:font-name", ascii, KoGenStyle::TextType); } // CASE #1152 if (ascii.isEmpty()) { TRY_READ_ATTR(asciiTheme) if (!asciiTheme.isEmpty()) { QString font = asciiTheme; if (font.startsWith("major")) { font = m_context->themes->fontScheme.majorFonts.latinTypeface; } else if (font.startsWith("minor")) { font = m_context->themes->fontScheme.minorFonts.latinTypeface; } m_currentTextStyle.addProperty("style:font-name", font); } } // CASE #1155 TRY_READ_ATTR(cs) if (!cs.isEmpty()) { m_currentTextStyle.addProperty("style:font-name-complex", cs, KoGenStyle::TextType); } // CASE #1154 if (cs.isEmpty()) { TRY_READ_ATTR(cstheme) if (!cstheme.isEmpty()) { //! @todo } } // CASE #1157 TRY_READ_ATTR(eastAsia) if (!eastAsia.isEmpty()) { m_currentTextStyle.addProperty("style:font-name-asian", eastAsia, KoGenStyle::TextType); } // CASE #1156 if (eastAsia.isEmpty()) { TRY_READ_ATTR(eastAsiaTheme) if (!eastAsiaTheme.isEmpty()) { //! @todo } } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL pStyle //! pStyle handler (Referenced Paragraph Style) /*! ECMA-376, WML, 17.3.1.27, p.260. This element specifies the style ID of the paragraph style which shall be used to format the contents of this paragraph. This formatting is applied at the following location in the style hierarchy: - Document defaults - Table styles - Numbering styles - Paragraph styles (this element) - Character styles - Direct Formatting This means that all properties specified in the style element (§17.7.4.17) with a styleId which corresponds to the value in this element's val attribute are applied to the paragraph at the appropriate level in the hierarchy. Parent elements: - [done] pPr (§17.3.1.26) - [done] pPr (§17.3.1.25) - [done] pPr (§17.7.5.2) - [done] pPr (§17.7.6.1) - [done] pPr (§17.9.23) - [done] pPr (§17.7.8.2) No child elements. */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_pStyle() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(val) m_currentParagraphStyle.setParentName(val); readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL tcMar //! tcMar (cell margin) /*! Parent elements: - .... Child elements: - ... @todo support all elements */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_tcMar() { READ_PROLOGUE while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { const QXmlStreamAttributes attrs(attributes()); if (QUALIFIED_NAME_IS(top)) { READ_ATTR(w) m_currentTableStyleProperties->topMargin = TWIP_TO_POINT(w.toDouble()); m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::TopMargin; } else if (QUALIFIED_NAME_IS(left)) { READ_ATTR(w) m_currentTableStyleProperties->leftMargin = TWIP_TO_POINT(w.toDouble()); m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::LeftMargin; } else if (QUALIFIED_NAME_IS(bottom)) { READ_ATTR(w) m_currentTableStyleProperties->bottomMargin = TWIP_TO_POINT(w.toDouble()); m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::BottomMargin; } else if (QUALIFIED_NAME_IS(right)) { READ_ATTR(w) m_currentTableStyleProperties->rightMargin = TWIP_TO_POINT(w.toDouble()); m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::RightMargin; } } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL tblCellMar //! tblCellMar (cell margin defaults) /*! Parent elements: - [done] tblPr (§17.4.60) - [done] tblPr (§17.4.59) - [done] tblPr (§17.7.6.4) - [done] tblPr (§17.7.6.3) Child elements: - ... @todo support all elements */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_tblCellMar() { READ_PROLOGUE while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { const QXmlStreamAttributes attrs(attributes()); if (QUALIFIED_NAME_IS(top)) { READ_ATTR(w) m_currentTableStyleProperties->topMargin = TWIP_TO_POINT(w.toDouble()); m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::TopMargin; } else if (QUALIFIED_NAME_IS(left)) { READ_ATTR(w) m_currentTableStyleProperties->leftMargin = TWIP_TO_POINT(w.toDouble()); m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::LeftMargin; } else if (QUALIFIED_NAME_IS(bottom)) { READ_ATTR(w) m_currentTableStyleProperties->bottomMargin = TWIP_TO_POINT(w.toDouble()); m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::BottomMargin; } else if (QUALIFIED_NAME_IS(right)) { READ_ATTR(w) m_currentTableStyleProperties->rightMargin = TWIP_TO_POINT(w.toDouble()); m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::RightMargin; } } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL tblBorders //! tblBorders handler (Table borders) /*! Parent elements: - [done] tblPr (§17.4.60) - [done] tblPr (§17.4.59) - [done] tblPr (§17.7.6.4) - [done] tblPr (§17.7.6.3) Child elements: - [done] bottom (Table Bottom Border) §17.4.4 - [done] end (Table Trailing Edge Border) §17.4.13 - [done] insideH (Table Inside Horizontal Edges Border) §17.4.23 - [done] insideV (Table Inside Vertical Edges Border) §17.4.25 - [done] start (Table Leading Edge Border) §17.4.37 - [done] top (Table Top Border) §17.4.77 */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_tblBorders() { READ_PROLOGUE while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { if (QUALIFIED_NAME_IS(top)) { m_currentTableStyleProperties->top = getBorderData(); m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::TopBorder; } else if (QUALIFIED_NAME_IS(bottom)) { m_currentTableStyleProperties->bottom = getBorderData(); m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::BottomBorder; } else if (QUALIFIED_NAME_IS(left)) { m_currentTableStyleProperties->left = getBorderData(); m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::LeftBorder; } else if (QUALIFIED_NAME_IS(right)) { m_currentTableStyleProperties->right = getBorderData(); m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::RightBorder; } else if (QUALIFIED_NAME_IS(insideV)) { m_currentTableStyleProperties->insideV = getBorderData(); m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::InsideVBorder; } else if (QUALIFIED_NAME_IS(insideH)) { m_currentTableStyleProperties->insideH = getBorderData(); m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::InsideHBorder; } } } READ_EPILOGUE } KoBorder::BorderData DocxXmlDocumentReader::getBorderData() { const QXmlStreamAttributes attrs(attributes()); KoBorder::BorderData borderData; TRY_READ_ATTR(val) borderData.style = borderMap.value(val); TRY_READ_ATTR(themeColor) TRY_READ_ATTR(color) if (!color.isEmpty()) { QString colorString = QString("#").append(color); borderData.innerPen.setColor(QColor(colorString)); borderData.outerPen.setColor(QColor(colorString)); } // Fallback to theme if (!borderData.innerPen.color().isValid() && !themeColor.isEmpty()) { MSOOXML::DrawingMLColorSchemeItemBase *colorItem = 0; colorItem = m_context->themes->colorScheme.value(themeColor); if (colorItem) { borderData.innerPen.setColor(colorItem->value()); borderData.outerPen.setColor(colorItem->value()); } } TRY_READ_ATTR(sz) borderData.outerPen.setWidthF(sz.toDouble() / 8.0); return borderData; } #undef CURRENT_EL #define CURRENT_EL tblpPr //! tblpPr handler (Floating Table Positioning) /*! ECMA-376, 17.4.58, p. 475. Parent elements: - [done] tblPr (§17.4.60) - [done] tblPr (§17.4.59) - [done] tblPr (§17.7.6.4) - [done] tblPr (§17.7.6.3) Child elements: - none */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_tblpPr() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(bottomFromText) TRY_READ_ATTR(leftFromText) TRY_READ_ATTR(rightFromText) TRY_READ_ATTR(topFromText) TRY_READ_ATTR(horzAnchor) TRY_READ_ATTR(vertAnchor) TRY_READ_ATTR(tblpX) TRY_READ_ATTR(tblpXSpec) TRY_READ_ATTR(tblpY) TRY_READ_ATTR(tblpYSpec) //If the tblpYSpecX/tblpYSpec attribute is also specified, then tblpX/tblpY //value is ignored. m_svgX = m_svgY = 0; if (tblpXSpec.isEmpty()) { STRING_TO_INT(tblpX, m_svgX, QString("w:tblpX")); } if (tblpYSpec.isEmpty()) { STRING_TO_INT(tblpY, m_svgY, QString("w:tblpY")); } int bottom = 0, left =0, right = 0, top = 0; STRING_TO_INT(bottomFromText, bottom, QString("w:bottomFromText")); STRING_TO_INT(leftFromText, left, QString("w:leftFromText")); STRING_TO_INT(rightFromText, right, QString("w:rightFromText")); STRING_TO_INT(topFromText, top, QString("w:topFromText")); pushCurrentDrawStyle(new KoGenStyle(KoGenStyle::GraphicAutoStyle, "graphic")); if (m_moveToStylesXml) { m_currentDrawStyle->setAutoStyleInStylesDotXml(true); } //fo:margin m_currentDrawStyle->addPropertyPt("fo:margin-bottom", TWIP_TO_POINT(bottom)); m_currentDrawStyle->addPropertyPt("fo:margin-left", TWIP_TO_POINT(left)); m_currentDrawStyle->addPropertyPt("fo:margin-right", TWIP_TO_POINT(right)); m_currentDrawStyle->addPropertyPt("fo:margin-top", TWIP_TO_POINT(top)); //style:horizontal-rel if (horzAnchor.isEmpty()) { m_currentDrawStyle->addProperty("style:horizontal-rel", "page"); } else if (horzAnchor == "margin") { m_currentDrawStyle->addProperty("style:horizontal-rel", "page-content"); } else if (horzAnchor == "page") { m_currentDrawStyle->addProperty("style:horizontal-rel", "page"); } else if (horzAnchor == "text") { m_currentDrawStyle->addProperty("style:horizontal-rel", "paragraph"); } //style:vertical-rel if (vertAnchor.isEmpty()) { if (m_headerActive || m_footerActive) { m_currentDrawStyle->addProperty("style:vertical-rel", "frame"); } else { m_currentDrawStyle->addProperty("style:vertical-rel", "page"); } } else if (vertAnchor == "margin") { m_currentDrawStyle->addProperty("style:vertical-rel", "page-content"); } else if (vertAnchor == "page") { if (m_headerActive || m_footerActive) { m_currentDrawStyle->addProperty("style:vertical-rel", "frame"); } else { m_currentDrawStyle->addProperty("style:vertical-rel", "page"); } } else if (vertAnchor == "text") { m_currentDrawStyle->addProperty("style:vertical-rel", "paragraph"); } //style:horizontal-pos if (tblpXSpec.isEmpty()) { m_currentDrawStyle->addProperty("style:horizontal-pos", "from-left"); } else { m_currentDrawStyle->addProperty("style:horizontal-pos", tblpXSpec); } //style:vertical-pos if (tblpYSpec.isEmpty()) { m_currentDrawStyle->addProperty("style:vertical-pos", "from-top"); } else if (tblpYSpec == "center") { m_currentDrawStyle->addProperty("style:vertical-pos", "middle"); } else if (tblpYSpec == "top") { m_currentDrawStyle->addProperty("style:vertical-pos", "top"); } else if (tblpYSpec == "inside") { m_currentDrawStyle->addProperty("style:vertical-pos", "top"); } else if (tblpYSpec == "bottom") { m_currentDrawStyle->addProperty("style:vertical-pos", "bottom"); } else if (tblpYSpec == "outside") { m_currentDrawStyle->addProperty("style:vertical-pos", "bottom"); } //style:wrap if (tblpXSpec.isEmpty() || (tblpXSpec == "left")) { m_currentDrawStyle->addProperty("style:wrap", "right"); } else if (tblpXSpec == "right") { m_currentDrawStyle->addProperty("style:wrap", "left"); } else { m_currentDrawStyle->addProperty("style:wrap", "parallel"); } m_currentDrawStyle->addProperty("style:number-wrapped-paragraphs", "no-limit"); //draw:auto-grow-height m_currentDrawStyle->addProperty("draw:auto-grow-height", "true"); m_currentDrawStyleName = mainStyles->insert(*m_currentDrawStyle); popCurrentDrawStyle(); readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL tblStyle //! tblStyle handler (Referenced table style) /*! Parent elements: - [done] tblPr (§17.4.60) - [done] tblPr (§17.4.59) - [done] tblPr (§17.7.6.4) - [done] tblPr (§17.7.6.3) Child elements: - none */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_tblStyle() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(val) m_currentTableStyleName = val; //Inheriting values from the defined style MSOOXML::DrawingTableStyle* tableStyle = m_context->m_tableStyles.value(m_currentTableStyleName); Q_ASSERT(tableStyle); if (tableStyle) { m_tableMainStyle->setHorizontalAlign(tableStyle->mainStyle->horizontalAlign()); } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL rStyle //! rStyle handler (Referenced run Style) /*! Parent elements: - rPr (§17.3.1.29) - rPr (§17.3.1.30) - rPr (§17.5.2.28) - rPr (§17.9.25) - rPr (§17.7.9.1) - rPr (§17.7.5.4) - rPr (§17.3.2.28) - rPr (§17.5.2.27) - rPr (§17.7.6.2) - rPr (§17.3.2.27) No child elements. */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_rStyle() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(val) m_currentTextStyle.setParentName(val); readNext(); READ_EPILOGUE } bool DocxXmlDocumentReader::handleSpecialField() { if (m_specialCharacters.isEmpty()) { return false; } QString instr = m_specialCharacters.trimmed(); m_specialCharacters = QString(); QVector instructions; while (instr.indexOf(' ') > 0) { int place = instr.indexOf(' '); instructions.push_back(instr.left(place)); instr = instr.mid(place + 1); } instructions.push_back(instr); QString command = instructions.at(0); bool returnTrue = true; if (command == "AUTHOR") { body->startElement("text:author-name"); } else if (command == "CREATEDATE") { body->startElement("text:creation-date"); } else if (command == "DATE") { body->startElement("text:date"); } else if (command == "EDITIME") { body->startElement("text:modification-time"); } else if (command == "FILENAME") { body->startElement("text:file-name"); } else if (command == "NUMPAGES") { body->startElement("text:page-count"); } else if (command == "NUMWORDS") { body->startElement("text:word-count"); } else if (command == "PAGE") { body->startElement("text:page-number"); body->addAttribute("text:select-page", "current"); } else if (command == "PRINTDATE") { body->startElement("text:print-date"); } else if (command == "REF") { if ((instructions.size() > 3) && instructions.contains("\\h")) { body->startElement("text:bookmark-ref"); body->addAttribute("text:reference-format", "page"); body->addAttribute("text:ref-name", instructions.at(1)); } else { returnTrue = false; } } else if (command == "TIME") { body->startElement("text:time"); } else if (command == "SAVEDATE") { body->startElement("text:modification-date"); } else { returnTrue = false; } return returnTrue; } #undef CURRENT_EL #define CURRENT_EL fldSimple //! fldSimple handler (Simple Field) /*! Parent elements: - bdo (§17.3.2.3) - customXml (§17.5.1.3) - dir (§17.3.2.8) - [done] fldSimple (§17.16.19) - hyperlink (§17.16.22) - [done] p (§17.3.1.22) - [done] sdtContent (§17.5.2.36) - [done] smartTag (§17.5.1.9) Child elements: - bdo (Bidirectional Override) §17.3.2.3 - [done] bookmarkEnd (Bookmark End) §17.13.6.1 - [done] bookmarkStart (Bookmark Start) §17.13.6.2 - commentRangeEnd (Comment Anchor Range End) §17.13.4.3 - commentRangeStart (Comment Anchor Range Start) §17.13.4.4 - customXml (Inline-Level Custom XML Element) §17.5.1.3 - customXmlDelRangeEnd (Custom XML Markup Deletion End) §17.13.5.4 - customXmlDelRangeStart (Custom XML Markup Deletion Start) §17.13.5.5 - customXmlInsRangeEnd (Custom XML Markup Insertion End) §17.13.5.6 - customXmlInsRangeStart (Custom XML Markup Insertion Start) §17.13.5.7 - customXmlMoveFromRangeEnd (Custom XML Markup Move Source End) §17.13.5.8 - customXmlMoveFromRangeStart (Custom XML Markup Move Source Start) §17.13.5.9 - customXmlMoveToRangeEnd (Custom XML Markup Move Destination Location End) §17.13.5.10 - customXmlMoveToRangeStart (Custom XML Markup Move Destination Location Start) §17.13.5.11 - [done] del (Deleted Run Content) §17.13.5.14 - dir (Bidirectional Embedding Level) §17.3.2.8 - [done] fldSimple (Simple Field) §17.16.19 - [done] hyperlink (Hyperlink) §17.16.22 - [done] ins (Inserted Run Content) §17.13.5.18 - moveFrom (Move Source Run Content) §17.13.5.22 - moveFromRangeEnd (Move Source Location Container - End) §17.13.5.23 - moveFromRangeStart (Move Source Location Container - Start) §17.13.5.24 - moveTo (Move Destination Run Content) §17.13.5.25 - moveToRangeEnd (Move Destination Location Container - End) §17.13.5.27 - moveToRangeStart (Move Destination Location Container - Start) §17.13.5.28 - [done] oMath (Office Math) §22.1.2.77 - [done] oMathPara (Office Math Paragraph) §22.1.2.78 - permEnd (Range Permission End) §17.13.7.1 - permStart (Range Permission Start) §17.13.7.2 - proofErr (Proofing Error Anchor) §17.13.8.1 - [done] r (Text Run) §17.3.2.25 - [done] sdt (Inline-Level Structured Document Tag) §17.5.2.31 - [done] smartTag (Inline-Level Smart Tag) §17.5.1.9 - subDoc (Anchor for Subdocument Location) §17.17.1.1 @todo support all elements */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_fldSimple() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(instr) m_specialCharacters = instr; // @todo support all attributes while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF(fldSimple) ELSE_TRY_READ_IF(r) ELSE_TRY_READ_IF(sdt) ELSE_TRY_READ_IF(hyperlink) ELSE_TRY_READ_IF(del) ELSE_TRY_READ_IF(ins) ELSE_TRY_READ_IF(bookmarkStart) ELSE_TRY_READ_IF(bookmarkEnd) ELSE_TRY_READ_IF_NS(m, oMathPara) ELSE_TRY_READ_IF_NS(m, oMath) ELSE_TRY_READ_IF(smartTag) SKIP_UNKNOWN } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL tabs //! tabs handler (Set of Custom Tab Stops) /*! ECMA-376, 17.3.1.38, p.269 This element specifies a sequence of custom tab stops which shall be used for any tab characters in the current paragraph. If this element is omitted on a given paragraph, its value is determined by the setting previously set at any level of the style hierarchy (i.e. that previous setting remains unchanged). If this setting is never specified in the style hierarchy, then no custom tab stops shall be used for this paragraph. As well, this property is additive - tab stops at each level in the style hierarchy are added to each other to determine the full set of tab stops for the paragraph. A hanging indent specified via the hanging attribute on the ind element (§17.3.1.12) shall also always implicitly create a custom tab stop at its location. Parent elements: - [done] pPr (§17.3.1.26) - [done] pPr (§17.3.1.25) - [done] pPr (§17.7.5.2) - [done] pPr (§17.7.6.1) - [done] pPr (§17.9.23) - [done] pPr (§17.7.8.2) Child elements: - [done] tab (§17.3.137) */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_tabs() { READ_PROLOGUE QBuffer tabs; tabs.open(QIODevice::WriteOnly); KoXmlWriter elementWriter(&tabs, 4 /*proper indentation*/); elementWriter.startElement("style:tab-stops"); QBuffer buffer; buffer.open(QIODevice::WriteOnly); KoXmlWriter *oldBody = body; body = new KoXmlWriter(&buffer); while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF(tab) ELSE_WRONG_FORMAT } } elementWriter.addCompleteElement(&buffer); delete body; body = oldBody; elementWriter.endElement(); // style-tab-stops QString tabStops = QString::fromUtf8(tabs.buffer(), tabs.buffer().size()); kDebug() << tabStops; m_currentParagraphStyle.addChildElement("style:tab-stops", tabStops); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL tab //! tab (Custom Tab Stop) /*! ECMA-376, 17.3.1.37, p.267 Specifies a single custom tab stop defined within a set of paragraph properties in a document. A tab stop location shall always be measured relative to the leading edge of the paragraph in which it is used (that is, the left edge for a left-to-right paragraph, and the right edge for a right-to-left paragraph). Parent elements: - [done] tabs (§17.3.1.38) Child elements: - None */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_tab() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(leader) TRY_READ_ATTR(pos) TRY_READ_ATTR(val) // "clear" - Specifies that the current tab stop is cleared and // shall be removed and ignored when processing the contents of // this document. // // NOTE: This is a workaround! The correct approach would be to // clear the tab-stop inherited from the parent named style at the // specified position. But this must be done during ODF loading // and it's not supported by ODF. The solution for a viewer would // be to not save tab-stop elements to the named style and only // save the final set into each "child" style. if (val == "clear") { readNext(); READ_EPILOGUE } body->startElement("style:tab-stop"); // ST_TabJc (Custom Tab Stop Type) in {bar, center, clear, // decimal, end, num, start} - there's (left, right) instead of // (start, end) according to test files. // // ODF: The default value for this attribute is left. if (!val.isEmpty()) { if (val == "center") { body->addAttribute("style:type", "center"); } else if (val == "decimal") { body->addAttribute("style:type", "char"); body->addAttribute("style:char", "." ); } else if (val == "end" || val == "right") { body->addAttribute("style:type", "right"); } else if (val == "bar" || val == "num") { kDebug() << "Unhandled tab justification code:" << val; } } bool ok = false; const qreal value = qreal(TWIP_TO_POINT(pos.toDouble(&ok))); if (ok) { body->addAttributePt("style:position", value); } // ST_TabTlc (Custom Tab Stop Leader Character) in {dot, heavy, // hyphen, middleDot, none, underscore} // // ODF: The default value for this attribute is “ “ (U+0020). QChar text; if (!leader.isEmpty()) { if (leader == "dot" || leader == "middleDot") { text = QChar('.'); } else if (leader == "hyphen") { text = QChar('-'); } else if (leader == "underscore" || leader == "heavy") { text = QChar('_'); } else if (leader == "none") { text = QChar(); } } if (!text.isNull()) { body->addAttribute("style:leader-text", text); } body->endElement(); // style:tab-stop readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL ptab //! ptab handler (absolute tab) /*! Parent elements: - [done] r (§22.1.2.87); - [done] r (§17.3.2.25) Child elements: - none @todo support all attributes */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_ptab() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); //! @todo: support all attributes properly body->startElement("text:tab"); body->endElement(); // text:tab readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL pBdr //! pBdr handler (Paragraph Borders) /*! ECMA-376, WML, 17.3.1.24, p.256. This element specifies the borders for the parent paragraph. Each child element shall specify a specific kind of border (left, right, bottom, top, and between). Parent elements: - [done] pPr (§17.3.1.26) - [done] pPr (§17.3.1.25) - [done] pPr (§17.7.5.2) - [done] pPr (§17.7.6.1) - [done] pPr (§17.9.23) - [done] pPr (§17.7.8.2) Child elements: - bar (Paragraph Border Between Facing Pages) §17.3.1.4 - between (Paragraph Border Between Identical Paragraphs) §17.3.1.5 - [done] bottom (Paragraph Border Below Identical Paragraphs) §17.3.1.7 - [done] left (Left Paragraph Border) §17.3.1.17 - [done] right (Right Paragraph Border) §17.3.1.28 - [done] top (Paragraph Border Above Identical Paragraphs) §17.3.1.42 @todo support all elements */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_pBdr() { READ_PROLOGUE m_borderStyles.clear(); m_borderPaddings.clear(); while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { if (QUALIFIED_NAME_IS(top)) { RETURN_IF_ERROR(readBorderElement(TopBorder, "top", m_borderStyles, m_borderPaddings)); } else if (QUALIFIED_NAME_IS(left)) { RETURN_IF_ERROR(readBorderElement(LeftBorder, "left", m_borderStyles, m_borderPaddings)); } else if (QUALIFIED_NAME_IS(bottom)) { RETURN_IF_ERROR(readBorderElement(BottomBorder, "bottom", m_borderStyles, m_borderPaddings)); } else if (QUALIFIED_NAME_IS(right)) { RETURN_IF_ERROR(readBorderElement(RightBorder, "right", m_borderStyles, m_borderPaddings)); } SKIP_UNKNOWN //! @todo add ELSE_WRONG_FORMAT } } applyBorders(&m_currentParagraphStyle, m_borderStyles, m_borderPaddings); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL bdr //! bbdr handler (Text Border) /*! Parent elements: - [done] rPr (§17.3.1.29); - [done] rPr (§17.3.1.30); - [done] rPr (§17.5.2.28); - [done] rPr (§17.9.25); - [done] rPr (§17.7.9.1); - [done] rPr (§17.7.5.4); - [done] rPr (§17.3.2.28); - [done] rPr (§17.5.2.27); - [done] rPr (§17.7.6.2); - [done] rPr (§17.3.2.27) Child elements: - none (?) @todo support all elements */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_bdr() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); m_textBorderStyles.clear(); m_textBorderPaddings.clear(); READ_ATTR(val) TRY_READ_ATTR(sz) TRY_READ_ATTR(color) createBorderStyle(sz, color, val, TopBorder, m_textBorderStyles); createBorderStyle(sz, color, val, LeftBorder, m_textBorderStyles); createBorderStyle(sz, color, val, BottomBorder, m_textBorderStyles); createBorderStyle(sz, color, val, RightBorder, m_textBorderStyles); TRY_READ_ATTR(space) if (!space.isEmpty()) { bool ok = false; const qreal sp = qreal(TWIP_TO_POINT(space.toDouble(&ok))); if (ok) { m_textBorderPaddings.insertMulti(TopBorder, sp); m_textBorderPaddings.insertMulti(LeftBorder, sp); m_textBorderPaddings.insertMulti(RightBorder, sp); m_textBorderPaddings.insertMulti(BottomBorder, sp); } } // Note that styles are not applied to anything, odf does not support // border around normal text run, but ooxml uses this element also to determine // borders for example to pictures readNext(); READ_EPILOGUE } void DocxXmlDocumentReader::readStrikeElement(KoCharacterStyle::LineType type) { const QXmlStreamAttributes attrs(attributes()); if (READ_BOOLEAN_VAL) { m_currentTextStyleProperties->setStrikeOutType(type); m_currentTextStyleProperties->setStrikeOutStyle(KoCharacterStyle::SolidLine); //! @todo m_currentTextStyleProperties->strikeOutWidth() ?? //! @todo m_currentTextStyleProperties->setStrikeOutColor() ?? //! @todo m_currentTextStyleProperties->setStrikeOutMode() ?? //! @todo m_currentTextStyleProperties->setStrikeOutText() ?? } } #undef CURRENT_EL #define CURRENT_EL strike //! strike handler //! CASE #1050 KoFilter::ConversionStatus DocxXmlDocumentReader::read_strike() { READ_PROLOGUE readStrikeElement(KoCharacterStyle::SingleLine); readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL dstrike //! dstrike handler //! CASE #1051 KoFilter::ConversionStatus DocxXmlDocumentReader::read_dstrike() { READ_PROLOGUE readStrikeElement(KoCharacterStyle::DoubleLine); readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL caps //! caps handler /*! Parent elements: - [done] rPr (many) */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_caps() { READ_PROLOGUE if (READ_BOOLEAN_VAL) { m_currentTextStyleProperties->setFontCapitalization(QFont::AllUppercase); } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL outline //! outline handler /*! Parent Elements: - [done] rPr (many) */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_outline() { READ_PROLOGUE m_currentTextStyleProperties->setTextOutline(QPen(Qt::SolidLine)); readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL smallCaps //! smallCaps handler /*! Parent elements: - [done] rPr (many) */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_smallCaps() { READ_PROLOGUE if (READ_BOOLEAN_VAL) { m_currentTextStyleProperties->setFontCapitalization(QFont::SmallCaps); } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL w //! w handler (Expanded/Compressed Text) /*! ECMA-376, 17.3.2.43, p.350 This element specifies the amount by which each character shall be expanded or when the character is rendered in the document. Parent elements: - [done] rPr (§17.3.1.29) - rPr (§17.3.1.30) - rPr (§17.5.2.28) - rPr (§17.9.25) - rPr (§17.7.9.1) - rPr (§17.7.5.4) - [done] rPr (§17.3.2.28) - rPr (§17.5.2.27) - rPr (§17.7.6.2) - rPr (§17.3.2.27) No child elements. */ //! @todo support all elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_w() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); READ_ATTR(val) if (!val.isEmpty()) { int wNumber; STRING_TO_INT(val, wNumber, "w@val") m_currentTextStyleProperties->setTextScale(wNumber); } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL vanish //! vanish handler (Hidden text) /* Parent elements: - [done] rPr (§17.3.1.29); - [done] rPr (§17.3.1.30); - [done] rPr (§17.5.2.28); - [done] rPr (§17.9.25); . [done] rPr (§17.7.9.1); - [done] rPr (§17.7.5.4); - [done] rPr (§17.3.2.28); - [done] rPr (§17.5.2.27); - [done] rPr (§17.7.6.2); - [done] rPr (§17.3.2.27) No child elements */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_vanish() { READ_PROLOGUE m_currentTextStyle.addProperty("text:display", "none"); readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL color //! color handler //! CASE #1158 KoFilter::ConversionStatus DocxXmlDocumentReader::read_color() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); READ_ATTR(val) //! @todo more styles if (val == MsooXmlReader::constAuto) { m_currentTextStyle.addProperty("style:use-window-font-color", "true"); } else { QColor color(MSOOXML::Utils::ST_HexColorRGB_to_QColor(val)); if (color.isValid()) { m_currentTextStyleProperties->setForeground(QBrush(color)); } } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL highlight //! highlight handler (Text Highlighting) /*! ECMA-376, 17.3.2.15, p.310 */ //! CASE #1158 KoFilter::ConversionStatus DocxXmlDocumentReader::read_highlight() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); READ_ATTR(val) m_currentTextStyleProperties->setBackground(MSOOXML::Utils::ST_HighlightColor_to_QColor(val)); readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL vertAlign //! vertAlign handler (Subscript/Superscript Text) ECMA-376, 17.3.2.42, p.349 /*! This element specifies the alignment which shall be applied to the contents of this run when displayed. */ /*! Parent elements: - [done] rPr No child elements. */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_vertAlign() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(val) val = val.toLower(); if (val == "superscript") { m_currentTextStyleProperties->setVerticalAlignment(QTextCharFormat::AlignSuperScript); } else if (val == "subscript") { m_currentTextStyleProperties->setVerticalAlignment(QTextCharFormat::AlignSubScript); } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL lang //! w:lang handler (Languages for Run Content) /*! ECMA-376, 17.3.2.20, p.314. Parent elements: - [done] rPr (§17.3.1.29) (within pPr §17.3.1.26) - rPr (§17.3.1.30) (within rPrChange §17.13.5.30) - rPr (§17.3.2.27) (within del §17.13.5.13, ins §17.13.5.16, rPrChange §17.13.5.31) - [done] rPr (§17.3.2.28) (witin ctrlPr §22.1.2.23, r §22.1.2.87, r §17.3.2.25) - rPr (§17.5.2.27) (within sdtPr §17.5.2.38) - rPr (§17.5.2.28) (within sdtEndPr §17.5.2.37) - [done] rPr (§17.7.9.1) (within style §17.7.4.17 - styles) - [done] rPr (§17.7.5.4) (within rPrDefault §17.7.5.5 - styles) - rPr (§17.7.6.2) (within tblStylePr §17.7.6.6 - styles) - rPr (§17.9.25) (within lvl §17.9.6, lvl §17.9.7 - numbering) No child elements. CASE #850 -> CASE #858 -> CASE #861 -> CASE #1100 @todo support all elements */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_lang() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); // CASE #1100 TRY_READ_ATTR(bidi) QString language, country; if (!bidi.isEmpty()) { if (MSOOXML::Utils::ST_Lang_to_languageAndCountry(bidi, language, country)) { m_currentTextStyle.addProperty("style:language-complex", language, KoGenStyle::TextType); m_currentTextStyle.addProperty("style:country-complex", country, KoGenStyle::TextType); } else { kWarning() << "invalid value of \"bidi\" attribute:" << bidi << " - skipping"; } } TRY_READ_ATTR(val) if (MSOOXML::Utils::ST_Lang_to_languageAndCountry(val, language, country)) { m_currentTextStyle.addProperty("fo:language", language, KoGenStyle::TextType); m_currentTextStyle.addProperty("fo:country", country, KoGenStyle::TextType); } else { kWarning() << "invalid value of \"val\" attribute:" << val << " - skipping"; } TRY_READ_ATTR(eastAsia) if (!eastAsia.isEmpty()) { if (MSOOXML::Utils::ST_Lang_to_languageAndCountry(eastAsia, language, country)) { m_currentTextStyle.addProperty("style:language-asian", language, KoGenStyle::TextType); m_currentTextStyle.addProperty("style:country-asian", country, KoGenStyle::TextType); } else { kWarning() << "invalid value of \"eastAsia\" attribute:" << eastAsia << " - skipping"; } } kDebug() << "bidi:" << bidi << "val:" << val << "eastAsia:" << eastAsia; readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL background //! w:background handler (Document Background) /*! ECMA-376, 17.2.1, p. 189. This element specifies the background for every page of the document containing the background element. Child element: - [done] drawing (§17.3.3.9) Attributes: - [done] color (Background Color) - themeColor (Background Theme Color) - themeTint (Border Theme Color Tint) - themeShade (Border Theme Color Shade) */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_background() { READ_PROLOGUE // The specs say that the background will not be shown in the default view but only in the fullscreen-view except the // displayBackgroundShape is defined. Since we cannot (and don't want to) make such assumptions about the available // views we only take over whatever is displayed in that default view. That's inline with what OO.org does too. bool displayBackgroundShape = m_context->import->documentSettings().contains("displayBackgroundShape"); if (displayBackgroundShape) { QString val = m_context->import->documentSetting("displayBackgroundShape").toString(); displayBackgroundShape = (val != "off" && val != "0" && val != "false"); } if (displayBackgroundShape) { const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(color) QColor tmpColor(MSOOXML::Utils::ST_HexColorRGB_to_QColor(color)); if (tmpColor.isValid()) m_backgroundColor = tmpColor; while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { if (qualifiedName() == "v:background") { TRY_READ(VML_background) } ELSE_TRY_READ_IF(drawing) SKIP_UNKNOWN } } } else { while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL tbl //! tbl handler (Table) /*! ECMA-376, 17.4.38, p. 460. This element specifies the contents of a table present in the document. A table is a set of paragraphs (and other block-level content) arranged in rows and columns. Parent elements: - [done] body (§17.2.2) - comment (§17.13.4.2) - customXml (§17.5.1.6) - docPartBody (§17.12.6) - [done] endnote (§17.11.2); - [done] footnote (§17.11.10) - [done] ftr (§17.10.3) - [done] hdr (§17.10.4) - sdtContent (§17.5.2.34) - [done] tc (§17.4.66) Child elements: - [done] bookmarkEnd (Bookmark End) §17.13.6.1 - [done] bookmarkStart (Bookmark Start) §17.13.6.2 - commentRangeEnd (Comment Anchor Range End) §17.13.4.3 - commentRangeStart (Comment Anchor Range Start) §17.13.4.4 - customXml (Row-Level Custom XML Element) §17.5.1.5 - customXmlDelRangeEnd (Custom XML Markup Deletion End) §17.13.5.4 - customXmlDelRangeStart (Custom XML Markup Deletion Start) §17.13.5.5 - customXmlInsRangeEnd (Custom XML Markup Insertion End) §17.13.5.6 - customXmlInsRangeStart (Custom XML Markup Insertion Start) §17.13.5.7 - customXmlMoveFromRangeEnd (Custom XML Markup Move Source End) §17.13.5.8 - customXmlMoveFromRangeStart (Custom XML Markup Move Source Start) §17.13.5.9 - customXmlMoveToRangeEnd (Custom XML Markup Move Destination Location End) §17.13.5.10 - customXmlMoveToRangeStart (Custom XML Markup Move Destination Location Start) §17.13.5.11 - del (Deleted Run Content) §17.13.5.14 - ins (Inserted Run Content) §17.13.5.18 - moveFrom (Move Source Run Content) §17.13.5.22 - moveFromRangeEnd (Move Source Location Container - End) §17.13.5.23 - moveFromRangeStart (Move Source Location Container - Start) §17.13.5.24 - moveTo (Move Destination Run Content) §17.13.5.25 - moveToRangeEnd (Move Destination Location Container - End) §17.13.5.27 - moveToRangeStart (Move Destination Location Container - Start) §17.13.5.28 - oMath (Office Math) §22.1.2.77 - oMathPara (Office Math Paragraph) §22.1.2.78 - permEnd (Range Permission End) §17.13.7.1 - permStart (Range Permission Start) §17.13.7.2 - proofErr (Proofing Error Anchor) §17.13.8.1 - sdt (Row-Level Structured Document Tag) §17.5.2.30 - [done] tblGrid (Table Grid) §17.4.49 - [done] tblPr (Table Properties) §17.4.60 - [done] tr (Table Row) §17.4.79 */ //! @todo support all child elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_tbl() { READ_PROLOGUE // save current state of lists processing saveState(); KoTable table; m_table = &table; m_table->setName(QLatin1String("Table") + QString::number(++m_currentTableNumber)); m_currentTableRowNumber = 0; m_currentTableColumnNumber = 0; m_currentDefaultCellStyle = 0; m_currentTableStyleProperties = 0; m_currentLocalTableStyles = new MSOOXML::LocalTableStyles; m_currentTableStyleName.clear(); m_currentDrawStyleName.clear(); m_tableMainStyle = KoTblStyle::create(); if (m_moveToStylesXml) { m_tableMainStyle->setAutoStyleInStylesDotXml(true); } //Disable to get a style of type TableAutoStyle. // m_tableMainStyle->setName("TableMainStyle" + QString::number(m_currentTableNumber - 1)); bool sectionAdded = false; if (m_createSectionStyle) { m_createSectionStyle = false; sectionAdded = true; // To avoid the style to become a duplicate or being duplicated. m_tableMainStyle->setMasterPageName("placeholder"); } // Fix me, for tables inside tables this might not work m_activeRoles = 0; MSOOXML::Utils::XmlWriteBuffer buffer; body = buffer.setWriter(body); while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { if(QUALIFIED_NAME_IS(tblPr)) { //tblPr/tblBorders m_currentTableStyleProperties = new MSOOXML::TableStyleProperties; TRY_READ(tblPr) m_currentDefaultCellStyle = m_currentTableStyleProperties; m_currentTableStyleProperties = 0; //debug border information #ifdef DOCXXML_DEBUG_TABLES kDebug() << "==> [tblBorders] information: <===================="; kDebug() << "top:" << m_currentDefaultCellStyle->top.style; kDebug() << "bottom:" << m_currentDefaultCellStyle->bottom.style; kDebug() << "left:" << m_currentDefaultCellStyle->left.style; kDebug() << "right:" << m_currentDefaultCellStyle->right.style; kDebug() << "insideH:" << m_currentDefaultCellStyle->insideH.style; kDebug() << "insideV:" << m_currentDefaultCellStyle->insideV.style; #endif } ELSE_TRY_READ_IF(tblGrid) ELSE_TRY_READ_IF(tr) SKIP_UNKNOWN // ELSE_TRY_READ_IF(bookmarkStart) // ELSE_TRY_READ_IF(bookmarkEnd) // ELSE_WRONG_FORMAT } } //reference to the default parent style from styles.xml if (m_currentTableStyleName.isEmpty() && m_context->m_namedDefaultStyles.contains("table")) { m_currentTableStyleName = m_context->m_namedDefaultStyles.value("table"); MSOOXML::DrawingTableStyle* tableStyle = m_context->m_tableStyles.value(m_currentTableStyleName); Q_ASSERT(tableStyle); if (tableStyle) { m_tableMainStyle->setHorizontalAlign(tableStyle->mainStyle->horizontalAlign()); } } //Floating Table if (!m_currentDrawStyleName.isEmpty()) { body->startElement("draw:frame"); body->addAttribute("draw:style-name", m_currentDrawStyleName.toUtf8()); body->addAttribute("text:anchor-type", "paragraph"); body->addAttributePt("svg:width", TWIP_TO_POINT(m_svgWidth)); if (m_svgX != 0) { body->addAttributePt("svg:x", TWIP_TO_POINT(m_svgX)); } if (m_svgY != 0) { body->addAttributePt("svg:y", TWIP_TO_POINT(m_svgY)); } body->startElement("draw:text-box"); } m_table->setTableStyle(m_tableMainStyle); defineTableStyles(); #ifdef DOCXXML_DEBUG_TABLES kDebug() << "----------------------------------------"; #endif m_table->saveOdf(*body, *mainStyles); if (sectionAdded) { m_currentSectionStyleName = m_table->tableStyle()->name(); } delete m_currentLocalTableStyles; //Floating Table if (!m_currentDrawStyleName.isEmpty()) { body->endElement(); //draw:text-box body->endElement(); //draw:frame body = buffer.releaseWriter(m_floatingTable); } else { body = buffer.releaseWriter(); } // restore previous state of lists processing restoreState(); READ_EPILOGUE } void DocxXmlDocumentReader::defineTableStyles() { const int rowCount = m_table->rowCount(); const int columnCount = m_table->columnCount(); MSOOXML::DrawingTableStyleConverterProperties converterProperties; converterProperties.setRowCount(rowCount); converterProperties.setColumnCount(columnCount); converterProperties.setRoles(m_activeRoles); converterProperties.setLocalStyles(*m_currentLocalTableStyles); converterProperties.setLocalDefaulCelltStyle(m_currentDefaultCellStyle); MSOOXML::DrawingTableStyle* tableStyle = m_context->m_tableStyles.value(m_currentTableStyleName); MSOOXML::DrawingTableStyleConverter styleConverter(converterProperties, tableStyle); QPair spans; for(int row = 0; row < rowCount; ++row ) { #ifdef DOCXXML_DEBUG_TABLES kDebug() << "----- [ROW" << row +1 << "] ----------"; #endif for(int column = 0; column < columnCount; ++column ) { #ifdef DOCXXML_DEBUG_TABLES kDebug() << "----- [COLUMN" << column +1 << "] ----------"; #endif spans.first = m_table->cellAt(row, column)->rowSpan(); spans.second = m_table->cellAt(row, column)->columnSpan(); KoCellStyle::Ptr style = styleConverter.style(row, column, spans); if (m_moveToStylesXml) { style->setAutoStyleInStylesDotXml(true); } m_table->cellAt(row, column)->setStyle(style); #ifdef DOCXXML_DEBUG_TABLES style = m_table->cellAt(row, column)->style(); kDebug() << "[check] top:" << style->borders()->topBorderData().style; kDebug() << "[check] bottom:" << style->borders()->bottomBorderData().style; kDebug() << "[check] left:" << style->borders()->leftBorderData().style; kDebug() << "[check] right:" << style->borders()->rightBorderData().style; #endif } } } #undef CURRENT_EL #define CURRENT_EL tblPr //! tblPr handler (Table Properties) /*! ECMA-376, 17.4.60, p. 492. This element specifies the set of table-wide properties applied to the current table. These properties affect the appearance of all rows and cells within the parent table, but can be overridden by individual table-level exception, row, and cell level properties as defined by each property. Parent elements: - [done] tbl (§17.4.38) Child elements: - bidiVisual (Visually Right to Left Table) §17.4.1 - [done] jc (Table Alignment) §17.4.29 - shd (Table Shading) §17.4.32 - [done] tblBorders (Table Borders) §17.4.39 - tblCaption (Table Caption) §17.4.41 - [done] tblCellMar (Table Cell Margin Defaults) §17.4.43 - tblCellSpacing (Table Cell Spacing Default) §17.4.46 - tblDescription (Table Description) §17.4.47 - tblInd (Table Indent from Leading Margin) §17.4.51 - tblLayout (Table Layout) §17.4.53 - tblLook (Table Style Conditional Formatting Settings) §17.4.56 - tblOverlap (Floating Table Allows Other Tables to Overlap) §17.4.57 - [done] tblpPr (Floating Table Positioning) §17.4.58 - tblPrChange (Revision Information for Table Properties) §17.13.5.34 - [done] tblStyle (Referenced Table Style) §17.4.63 - tblStyleColBandSize (Number of Columns in Column Band) §17.7.6.5 - tblStyleRowBandSize (Number of Rows in Row Band) §17.7.6.7 - tblW (Preferred Table Width) §17.4.64 */ //! @todo support all child elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_tblPr() { READ_PROLOGUE while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF(tblStyle) ELSE_TRY_READ_IF(tblpPr) ELSE_TRY_READ_IF(tblBorders) ELSE_TRY_READ_IF(tblCellMar) ELSE_TRY_READ_IF_IN_CONTEXT(jc) SKIP_UNKNOWN //! @todo add ELSE_WRONG_FORMAT } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL tblPrEx //! tblPrEx (Table-Level Property Exceptions) /*! ECMA-376, 17.4.61, p. 484. Parent elements: - [done] tr (§17.4.79) Child elements - jc (Table Alignment Exception) §17.4.27 - shd (Table Shading Exception) §17.4.31 - [done] tblBorders (Table Borders Exceptions) §17.4.40 - tblCellMar (Table Cell Margin Exceptions) §17.4.42 - tblCellSpacing (Table Cell Spacing Exception) §17.4.45 - tblInd (Table Indent from Leading Margin Exception) §17.4.52 - tblLayout (Table Layout Exception) §17.4.54 - tblLook (Table Style Conditional Formatting Settings Exception) §17.4.55 - tblPrExChange (Revision Information for Table-Level Property Exceptions) §17.13.5.35 - tblW (Preferred Table Width Exception) §17.4.65 */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_tblPrEx() { READ_PROLOGUE while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { if (QUALIFIED_NAME_IS(tblBorders)) { m_currentTableStyleProperties = new MSOOXML::TableStyleProperties; TRY_READ_IF(tblBorders) m_currentTableStyleProperties->target = MSOOXML::TableStyleProperties::TableRow; m_currentLocalTableStyles->setLocalStyle(m_currentTableStyleProperties, m_currentTableRowNumber, -1); #ifdef DOCXXML_DEBUG_TABLES kDebug() << "====> [Row" << m_currentTableRowNumber << " Column (-1)" << "] Border information:"; kDebug() << "top:" << m_currentTableStyleProperties->top.style; kDebug() << "bottom:" << m_currentTableStyleProperties->bottom.style; kDebug() << "left:" << m_currentTableStyleProperties->left.style; kDebug() << "right:" << m_currentTableStyleProperties->right.style; #endif m_currentTableStyleProperties = 0; } SKIP_UNKNOWN //! @todo add ELSE_WRONG_FORMAT } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL tblGrid //! tblGrid handler (Table Grid) /*! ECMA-376, 17.4.49, p. 474. This element specifies the table grid for the current table. The table grid is a definition of the set of grid columns which define all of the shared vertical edges of the table, as well as default widths for each of these grid columns. These grid column widths are then used to determine the size of the table based on the table layout algorithm used (§17.4.53;§17.4.54). Parent elements: - [done] tbl (§17.4.38) Child elements: - [done] gridCol (Grid Column Definition) §17.4.16 - tblGridChange (Revision Information for Table Grid Column Definitions) §17.13.5.33 */ //! @todo support all child elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_tblGrid() { READ_PROLOGUE m_currentTableColumnNumber = 0; m_svgWidth = 0; while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF(gridCol) SKIP_UNKNOWN //! @todo add ELSE_WRONG_FORMAT } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL gridCol //! gridCol handler (Grid Column Definition) /*! ECMA-376, 17.4.16, p. 433. This element specifies the presence and details about a single grid column within a table grid. A grid column is a logical column in a table used to specify the presence of a shared vertical edge in the table. When table cells are then added to this table, these shared edges (or grid columns, looking at the column between those shared edges) determine how table cells are placed into the table grid. Parent elements: - tblGrid (§17.4.48) - [done] tblGrid (§17.4.49) No child elements. */ //! @todo support all child elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_gridCol() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(w) int width = 0; STRING_TO_INT(w, width, QString("w:w")); m_svgWidth += width; const qreal columnWidth = width / 20.0; KoColumn* column = m_table->columnAt(m_currentTableColumnNumber++); KoColumnStyle::Ptr style = KoColumnStyle::create(); if (m_moveToStylesXml) { style->setAutoStyleInStylesDotXml(true); } style->setWidth(columnWidth); column->setStyle(style); readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL tr //! tr handler (Table Row) /*! ECMA-376, 17.4.79, p. 492. This element specifies a single table row, which contains the table’s cells. Table rows in WordprocessingML are analogous to HTML tr elements. Parent elements: - customXml (§17.5.1.5) - sdtContent (§17.5.2.35) - [done] tbl (§17.4.38) Child elements: - [done] bookmarkEnd (Bookmark End) §17.13.6.1 - [done] bookmarkStart (Bookmark Start) §17.13.6.2 - commentRangeEnd (Comment Anchor Range End) §17.13.4.3 - commentRangeStart (Comment Anchor Range Start) §17.13.4.4 - customXml (Cell-Level Custom XML Element) §17.5.1.4 - customXmlDelRangeEnd (Custom XML Markup Deletion End) §17.13.5.4 - customXmlDelRangeStart (Custom XML Markup Deletion Start) §17.13.5.5 - customXmlInsRangeEnd (Custom XML Markup Insertion End) §17.13.5.6 - customXmlInsRangeStart (Custom XML Markup Insertion Start) §17.13.5.7 - customXmlMoveFromRangeEnd (Custom XML Markup Move Source End) §17.13.5.8 - customXmlMoveFromRangeStart (Custom XML Markup Move Source Start) §17.13.5.9 - customXmlMoveToRangeEnd (Custom XML Markup Move Destination Location End) §17.13.5.10 - customXmlMoveToRangeStart (Custom XML Markup Move Destination Location Start) §17.13.5.11 - del (Deleted Run Content) §17.13.5.14 - ins (Inserted Run Content) §17.13.5.18 - moveFrom (Move Source Run Content) §17.13.5.22 - moveFromRangeEnd (Move Source Location Container - End) §17.13.5.23 - moveFromRangeStart (Move Source Location Container - Start) §17.13.5.24 - moveTo (Move Destination Run Content) §17.13.5.25 - moveToRangeEnd (Move Destination Location Container - End) §17.13.5.27 - moveToRangeStart (Move Destination Location Container - Start) §17.13.5.28 - oMath (Office Math) §22.1.2.77 - oMathPara (Office Math Paragraph) §22.1.2.78 - permEnd (Range Permission End) §17.13.7.1 - permStart (Range Permission Start) §17.13.7.2 - proofErr (Proofing Error Anchor) §17.13.8.1 - [done] sdt (Cell-Level Structured Document Tag) §17.5.2.32 - [done] tblPrEx (Table-Level Property Exceptions) §17.4.61 - tc (Table Cell) §17.4.66 - [done]trPr (Table Row Properties) §17.4.82 */ //! @todo support all child elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_tr() { READ_PROLOGUE m_currentTableColumnNumber = 0; while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF(tc) ELSE_TRY_READ_IF(trPr) ELSE_TRY_READ_IF(bookmarkStart) ELSE_TRY_READ_IF(bookmarkEnd) ELSE_TRY_READ_IF(sdt) ELSE_TRY_READ_IF(tblPrEx) SKIP_UNKNOWN //! @todo add ELSE_WRONG_FORMAT } } m_currentTableRowNumber++; READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL trPr /* Parent elements: - [done] tr (§17.4.79) child elements: - cantSplit (Table Row Cannot Break Across Pages) §17.4.6 - [done] cnfStyle (Table Row Conditional Formatting) §17.4.7 - del (Deleted Table Row)§17.13.5.12 - divId (Associated HTML div ID)§17.4.9 - gridAfter (Grid Columns After Last Cell)§17.4.14 - gridBefore (Grid Columns Before First Cell) §17.4.15 - hidden (Hidden Table Row Marker)§17.4.20 - ins (Inserted Table Row) §17.13.5.17 - jc (Table Row Alignment) §17.4.28 - tblCellSpacing (Table Row Cell Spacing) §17.4.44 - tblHeader (Repeat Table Row on Every New Page) §17.4.50 - [done] trHeight (Table Row Height) §17.4.81 - trPrChange (Revision Information for Table Row Properties) §17.13.5.37 - wAfter (Preferred Width After Table Row) §17.4.86 - wBefore (Preferred Width Before Table Row) §17.4.87 */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_trPr() { READ_PROLOGUE while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF(trHeight) ELSE_TRY_READ_IF(cnfStyle) SKIP_UNKNOWN } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL cnfStyle /* Parent elements: - many, eg. tr, tc, ppr child elements: - none */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_cnfStyle() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); // Note this parameter does not follow ooxml spec at all at least in office2007 but // produces values from office 2003 ie. val with binary // FirstRow, LastRow, FirstColumn, LastColumn, Band1Vertical, Band2Vertical, // Band1Horizontal, Band2Horizontal, NE Cell, NW Cell, SE Cell, SW Cell. TRY_READ_ATTR(val) if (val.length() == 12) { if (val.at(0) == '1') { m_activeRoles |= MSOOXML::DrawingTableStyleConverterProperties::FirstRow; } if (val.at(1) == '1') { m_activeRoles |= MSOOXML::DrawingTableStyleConverterProperties::LastRow; } if (val.at(2) == '1') { m_activeRoles |= MSOOXML::DrawingTableStyleConverterProperties::FirstCol; } if (val.at(3) == '1') { m_activeRoles |= MSOOXML::DrawingTableStyleConverterProperties::LastCol; } if (val.at(4) == '1') { m_activeRoles |= MSOOXML::DrawingTableStyleConverterProperties::ColumnBanded; } if (val.at(5) == '1') { m_activeRoles |= MSOOXML::DrawingTableStyleConverterProperties::ColumnBanded; } if (val.at(6) == '1') { m_activeRoles |= MSOOXML::DrawingTableStyleConverterProperties::RowBanded; } if (val.at(7) == '1') { m_activeRoles |= MSOOXML::DrawingTableStyleConverterProperties::RowBanded; } if (val.at(8) == '1') { m_activeRoles |= MSOOXML::DrawingTableStyleConverterProperties::NeCell; } if (val.at(9) == '1') { m_activeRoles |= MSOOXML::DrawingTableStyleConverterProperties::NwCell; } if (val.at(10) == '1') { m_activeRoles |= MSOOXML::DrawingTableStyleConverterProperties::SeCell; } if (val.at(11) == '1') { m_activeRoles |= MSOOXML::DrawingTableStyleConverterProperties::SwCell; } } readNext(); READ_EPILOGUE } /* Parent elements: - [done]trPr (§17.4.82) - trPr (§17.7.6.10) - trPr (§17.7.6.11) - trPr (§17.4.83) */ #undef CURRENT_EL #define CURRENT_EL trHeight KoFilter::ConversionStatus DocxXmlDocumentReader::read_trHeight() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(val) TRY_READ_ATTR(hRule) KoRow* row = m_table->rowAt(m_currentTableRowNumber); KoRowStyle::Ptr style = KoRowStyle::create(); if (m_moveToStylesXml) { style->setAutoStyleInStylesDotXml(true); } style->setHeight(TWIP_TO_POINT(val.toFloat())); if (hRule == QLatin1String("exact")) { style->setHeightType(KoRowStyle::ExactHeight); } else if (hRule == QLatin1String("atLeast")) { style->setHeightType(KoRowStyle::MinimumHeight); } else { style->setHeightType(KoRowStyle::MinimumHeight); } row->setStyle(style); readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL tc //! tc handler (Table Cell) /*! ECMA-376, 17.4.66, p. 502. This element specifies a single cell in a table row, which contains the table’s content. Table cells in WordprocessingML are analogous to HTML td elements. Parent elements: - customXml (§17.5.1.4) - sdtContent (§17.5.2.33) - [done] tr (§17.4.79) Child elements: - altChunk (Anchor for Imported External Content) §17.17.2.1 - [done] bookmarkEnd (Bookmark End) §17.13.6.1 - [done] bookmarkStart (Bookmark Start) §17.13.6.2 - commentRangeEnd (Comment Anchor Range End) §17.13.4.3 - commentRangeStart (Comment Anchor Range Start) §17.13.4.4 - customXml (Block-Level Custom XML Element) §17.5.1.6 - customXmlDelRangeEnd (Custom XML Markup Deletion End) §17.13.5.4 - customXmlDelRangeStart (Custom XML Markup Deletion Start) §17.13.5.5 - customXmlInsRangeEnd (Custom XML Markup Insertion End) §17.13.5.6 - customXmlInsRangeStart (Custom XML Markup Insertion Start) §17.13.5.7 - customXmlMoveFromRangeEnd (Custom XML Markup Move Source End) §17.13.5.8 - customXmlMoveFromRangeStart (Custom XML Markup Move Source Start) §17.13.5.9 - customXmlMoveToRangeEnd (Custom XML Markup Move Destination Location End) §17.13.5.10 - customXmlMoveToRangeStart (Custom XML Markup Move Destination Location Start) §17.13.5.11 - del (Deleted Run Content) §17.13.5.14 - ins (Inserted Run Content) §17.13.5.18 - moveFrom (Move Source Run Content) §17.13.5.22 - moveFromRangeEnd (Move Source Location Container - End) §17.13.5.23 - moveFromRangeStart (Move Source Location Container - Start) §17.13.5.24 - moveTo (Move Destination Run Content) §17.13.5.25 - moveToRangeEnd (Move Destination Location Container - End) §17.13.5.27 - moveToRangeStart (Move Destination Location Container - Start) §17.13.5.28 - oMath (Office Math) §22.1.2.77 - oMathPara (Office Math Paragraph) §22.1.2.78 - [done] p (Paragraph) §17.3.1.22 - permEnd (Range Permission End) §17.13.7.1 - permStart (Range Permission Start) §17.13.7.2 - proofErr (Proofing Error Anchor) §17.13.8.1 - sdt (Block-Level Structured Document Tag) §17.5.2.29 - [done] tbl (Table) §17.4.38 - [done] tcPr (Table Cell Properties) §17.4.70 */ //! @todo support all child elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_tc() { READ_PROLOGUE while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { if(qualifiedName() == "w:p") { KoCell* cell = m_table->cellAt(m_currentTableRowNumber, m_currentTableColumnNumber); QBuffer buffer; KoXmlWriter* oldBody = body; KoXmlWriter newBody(&buffer, oldBody->indentLevel()+1); body = &newBody; TRY_READ(p) KoRawCellChild* textChild = new KoRawCellChild(buffer.data()); cell->appendChild(textChild); body = oldBody; } else if(QUALIFIED_NAME_IS(tbl)) { KoTable* currentTable = m_table; int currentRow = m_currentTableRowNumber; int currentColumn = m_currentTableColumnNumber; MSOOXML::TableStyleProperties* currentDefaultCellStyle = m_currentDefaultCellStyle; MSOOXML::TableStyleProperties* currentStyleProperties = m_currentTableStyleProperties; MSOOXML::LocalTableStyles* currentLocalStyles = m_currentLocalTableStyles; QString currentTableStyle = m_currentTableStyleName; KoCell* cell = m_table->cellAt(m_currentTableRowNumber, m_currentTableColumnNumber); QBuffer buffer; KoXmlWriter* oldBody = body; KoXmlWriter newBody(&buffer, oldBody->indentLevel()+1); body = &newBody; TRY_READ(tbl) KoRawCellChild* textChild = new KoRawCellChild(buffer.data()); cell->appendChild(textChild); body = oldBody; m_table = currentTable; m_currentTableRowNumber = currentRow; m_currentTableColumnNumber = currentColumn; m_currentDefaultCellStyle = currentDefaultCellStyle; m_currentTableStyleProperties = currentStyleProperties; m_currentLocalTableStyles = currentLocalStyles; m_currentTableStyleName = currentTableStyle; } else if(QUALIFIED_NAME_IS(tcPr)) { m_currentTableStyleProperties = new MSOOXML::TableStyleProperties; TRY_READ(tcPr) m_currentTableStyleProperties->target = MSOOXML::TableStyleProperties::TableCell; m_currentLocalTableStyles->setLocalStyle(m_currentTableStyleProperties, m_currentTableRowNumber, m_currentTableColumnNumber); #ifdef DOCXXML_DEBUG_TABLES kDebug() << "====> [Row" << m_currentTableRowNumber << " Column" << m_currentTableColumnNumber << "] Border information:"; kDebug() << "top:" << m_currentTableStyleProperties->top.style; kDebug() << "bottom:" << m_currentTableStyleProperties->bottom.style; kDebug() << "left:" << m_currentTableStyleProperties->left.style; kDebug() << "right:" << m_currentTableStyleProperties->right.style; #endif m_currentTableStyleProperties = 0; } // ELSE_TRY_READ_IF(bookmarkStart) // ELSE_TRY_READ_IF(bookmarkEnd) //! @todo add ELSE_WRONG_FORMAT } } // Setting cell covers in case of cell span in horizontal KoCell* const cell = m_table->cellAt(m_currentTableRowNumber, m_currentTableColumnNumber); int columnSpan = cell->columnSpan(); if (columnSpan > 1) { int columnIndex = 1; while (columnIndex < columnSpan) { ++m_currentTableColumnNumber; KoCell* coveredCell = m_table->cellAt(m_currentTableRowNumber, m_currentTableColumnNumber); coveredCell->setCovered(true); ++columnIndex; } } m_currentTableColumnNumber++; return KoFilter::OK; } #undef CURRENT_EL #define CURRENT_EL tcPr //! tcPr handler (Table Cell Properties) /*! ECMA-376, 17.4.70, p. 510. This element specifies the set of properties which shall be applied a specific table cell. Each unique property is specified by a child element of this element. In any instance where there is a conflict between the table level, table-level exception, or row level properties with a corresponding table cell property, these properties shall overwrite the table or row wide properties. Parent elements: - [done] tc (§17.4.66) Child elements: - cellDel (Table Cell Deletion) §17.13.5.1 - cellIns (Table Cell Insertion) §17.13.5.2 - cellMerge (Vertically Merged/Split Table Cells) §17.13.5.3 - [done] cnfStyle (Table Cell Conditional Formatting) §17.4.8 - [done] gridSpan (Grid Columns Spanned by Current Table Cell) §17.4.17 - headers (Header Cells Associated With Table Cell) §17.4.19 - hideMark (Ignore End Of Cell Marker In Row Height Calculation) §17.4.21 - hMerge (Horizontally Merged Cell) §17.4.22 - noWrap (Don't Wrap Cell Content) §17.4.30 - [done] shd (Table Cell Shading) §17.4.33 - [done] tcBorders (Table Cell Borders) §17.4.67 - tcFitText (Fit Text Within Cell) §17.4.68 - [done] tcMar (Single Table Cell Margins) §17.4.69 - tcPrChange (Revision Information for Table Cell Properties) §17.13.5.36 - tcW (Preferred Table Cell Width) §17.4.72 - [done] textDirection (Table Cell Text Flow Direction) §17.4.73 - [done] vAlign (Table Cell Vertical Alignment) §17.4.84 - [done] vMerge (Vertically Merged Cell) §17.4.85 */ //! @todo support all child elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_tcPr() { READ_PROLOGUE while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF(gridSpan) ELSE_TRY_READ_IF(cnfStyle) ELSE_TRY_READ_IF_IN_CONTEXT(shd) ELSE_TRY_READ_IF(tcBorders) ELSE_TRY_READ_IF(tcMar) ELSE_TRY_READ_IF(vMerge) ELSE_TRY_READ_IF(vAlign) else if (name() == "textDirection") { TRY_READ(textDirectionTc) } SKIP_UNKNOWN //! @todo add ELSE_WRONG_FORMAT } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL vAlign //! vAlign Handler (Table Cell Vertical Alignment) /*! ECMA-376, 17.4.84, p. 519. Parent elements: - [done] tcPr (§17.7.6.8); - [done] tcPr (§17.7.6.9); - [done] tcPr (§17.4.70); - [done] tcPr (§17.4.71) Child elements: - none */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_vAlign() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(val) if (!val.isEmpty()) { if (val == "both" || val == "center") { m_currentTableStyleProperties->verticalAlign = "middle"; } else if (val == "top" || val == "bottom") { m_currentTableStyleProperties->verticalAlign = val; } else { m_currentTableStyleProperties->verticalAlign = "automatic"; } m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::VerticalAlign; } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL textDirection //! textDirection Handler (Table Cell Text Flow Direction) /* Parent elements: - [done] tcPr (§17.7.6.8); - [done] tcPr (§17.7.6.9); - [done] tcPr (§17.4.70); - [done] tcPr (§17.4.71) Child elements: - none */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_textDirectionTc() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(val) if (!val.isEmpty()) { m_currentTableStyleProperties->glyphOrientation = false; m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::GlyphOrientation; } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL vMerge //! vMerge Handler (vertically merged cell) /* Parent elements: - [done] tcPr (§17.7.6.8); - [done] tcPr (§17.7.6.9); - [done] tcPr (§17.4.70); - [done] tcPr (§17.4.71) Child elements: - none */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_vMerge() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(val) if (!val.isEmpty()) { // Not empty value marks the start of the vertical merging KoCell* cell = m_table->cellAt(m_currentTableRowNumber, m_currentTableColumnNumber); cell->setRowSpan(1); } else { // In this case, it should continue from which ever cell above was the starter KoCell* cell = m_table->cellAt(m_currentTableRowNumber, m_currentTableColumnNumber); cell->setCovered(true); int previousRow = m_currentTableRowNumber - 1; while (previousRow > -1) { KoCell* previousRowCell = m_table->cellAt(previousRow, m_currentTableColumnNumber); if (!previousRowCell->isCovered()) { previousRowCell->setRowSpan(previousRowCell->rowSpan() + 1); // This current cell should be replaced with cell->setCovered(true); break; } --previousRow; } } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL tcBorders //! tcBorders handlers (table cell borders) /*! ECMA-376, 17.4.67, p.494. Parent elements: - [done] tcPr (§17.7.6.8); - [done] tcPr (§17.7.6.9); - [done] tcPr (§17.4.70); - [done] tcPr (§17.4.71) Child elements: - [done] bottom (Table Cell Bottom Border) §17.4.3 - [done] end (Table Cell Trailing Edge Border) §17.4.12 - [done] insideH (Table Cell Inside Horizontal Edges Border) §17.4.24 - [done] insideV (Table Cell Inside Vertical Edges Border) §17.4.26 - [done] start (Table Cell Leading Edge Border) §17.4.34 - [done] tl2br (Table Cell Top Left to Bottom Right Diagonal Border) §17.4.74 - [done] top (Table Cell Top Border) §17.4.75 - [done] tr2bl (Table Cell Top Right to Bottom Left Diagonal Border) §17.4.80 */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_tcBorders() { READ_PROLOGUE while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { if (QUALIFIED_NAME_IS(top)) { m_currentTableStyleProperties->top = getBorderData(); m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::TopBorder; } else if (QUALIFIED_NAME_IS(bottom)) { m_currentTableStyleProperties->bottom = getBorderData(); m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::BottomBorder; } else if (QUALIFIED_NAME_IS(left)) { m_currentTableStyleProperties->left = getBorderData(); m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::LeftBorder; } else if (QUALIFIED_NAME_IS(right)) { m_currentTableStyleProperties->right = getBorderData(); m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::RightBorder; } else if (QUALIFIED_NAME_IS(insideV)) { m_currentTableStyleProperties->insideV = getBorderData(); m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::InsideVBorder; } else if (QUALIFIED_NAME_IS(insideH)) { m_currentTableStyleProperties->insideH = getBorderData(); m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::InsideHBorder; } else if (QUALIFIED_NAME_IS(tl2br)) { m_currentTableStyleProperties->tl2br = getBorderData(); m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::Tl2brBorder; } else if (QUALIFIED_NAME_IS(tr2bl)) { m_currentTableStyleProperties->tr2bl = getBorderData(); m_currentTableStyleProperties->setProperties |= MSOOXML::TableStyleProperties::Tr2blBorder; } SKIP_UNKNOWN } } m_currentTableStyleProperties->target = MSOOXML::TableStyleProperties::TableCell; READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL gridSpan //! gridSpan handler (Grid Columns Spanned by Current Table Cell) /*! Parent elements: - [done]tcPr (§17.7.6.8); - [done] tcPr (§17.7.6.9); - [done] tcPr (§17.4.70); - [done] tcPr (§17.4.71) Child elements: - none */ //! @todo support all child elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_gridSpan() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(val) if (!val.isEmpty()) { int span = 0; STRING_TO_INT(val, span, "gridSpan"); KoCell* const cell = m_table->cellAt(m_currentTableRowNumber, m_currentTableColumnNumber); cell->setColumnSpan(span); } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL control //! Reads a activeX control object /* Parent elements: - [done] object (§17.3.3.19) Child elements: - none */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_control() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); body->startElement("draw:frame"); body->addAttribute("svg:width", m_currentObjectWidthCm); body->addAttribute("svg:height", m_currentObjectHeightCm); body->addAttribute("text:anchor-type", "as-char"); // default for these // Do we even want to try anything with activeX controls? /* TRY_READ_ATTR_WITH_NS(r, id) const QString oleName(m_context->relationships->target(m_context->path, m_context->file, r_id)); kDebug() << "oleName:" << oleName; */ // Replacement image body->startElement("draw:image"); body->addAttribute("xlink:type", "simple"); body->addAttribute("xlink:show", "embed"); body->addAttribute("xlink:actuate", "onLoad"); body->addAttribute("xlink:href", m_currentVMLProperties.imagedataPath); body->endElement(); // draw:image body->endElement(); // draw:frame readNext(); READ_EPILOGUE } // --------------------------------------------------------------------------- #include // this adds w:p, w:pPr, w:t, w:r, etc. // --------------------------------------------------------------------------- #undef MSOOXML_CURRENT_NS #define MSOOXML_CURRENT_NS "o" // urn:schemas-microsoft-com:office:office #undef CURRENT_EL #define CURRENT_EL OLEObject //! Reads an OLE object KoFilter::ConversionStatus DocxXmlDocumentReader::read_OLEObject() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); // example: // body->startElement("draw:frame"); body->addAttribute("svg:width", m_currentObjectWidthCm); body->addAttribute("svg:height", m_currentObjectHeightCm); body->addAttribute("text:anchor-type", "as-char"); // default for these TRY_READ_ATTR_WITH_NS(r, id) const QString oleName(m_context->relationships->target(m_context->path, m_context->file, r_id)); kDebug() << "oleName:" << oleName; QString destinationName = QLatin1String("") + oleName.mid(oleName.lastIndexOf('/') + 1); KoFilter::ConversionStatus stat = m_context->import->copyFile(oleName, destinationName, false); if (stat == KoFilter::OK) { body->startElement("draw:object-ole"); addManifestEntryForFile(destinationName); body->addAttribute("xlink:href", destinationName); body->addAttribute("xlink:type", "simple"); body->endElement(); // draw:object-ole } // Replacement image body->startElement("draw:image"); body->addAttribute("xlink:type", "simple"); body->addAttribute("xlink:show", "embed"); body->addAttribute("xlink:actuate", "onLoad"); body->addAttribute("xlink:href", m_currentVMLProperties.imagedataPath); body->endElement(); // draw:image while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) } body->endElement(); // draw:frame READ_EPILOGUE } #undef MSOOXML_CURRENT_NS #define MSOOXML_CURRENT_NS "wp" #undef CURRENT_EL #define CURRENT_EL anchor //! anchor handler (Anchor for Floating DrawingML Object) /*! ECMA-376, 20.4.2.3, p.3469. This element specifies that the DrawingML object located at this position in the document is a floating object. Within a WordprocessingML document, drawing objects can exist in two states: - Inline - The drawing object is in line with the text, and affects the line height and layout of its line (like a character glyph of similar size). - Floating - The drawing object is anchored within the text, but can be absolutely positioned in the document relative to the page. When this element encapsulates the DrawingML object's information, then all child elements shall dictate the positioning of this object as a floating object on the page. Parent elements: - [done] drawing (§17.3.3.9) Child elements: - cNvGraphicFramePr (Common DrawingML Non-Visual Properties) §20.4.2.4 - [done] docPr (Drawing Object Non-Visual Properties) §20.4.2.5 - effectExtent (Object Extents Including Effects) §20.4.2.6 - extent (Drawing Object Size) §20.4.2.7 - [done] graphic (Graphic Object) §20.1.2.2.16 - [done] positionH (Horizontal Positioning) §20.4.2.10 - [done] positionV (Vertical Positioning) §20.4.2.11 - simplePos (Simple Positioning Coordinates) §20.4.2.13 - [done] wrapNone (No Text Wrapping) §20.4.2.15 - [done] wrapSquare (Square Wrapping) §20.4.2.17 - [done] wrapThrough (Through Wrapping) §20.4.2.18 - [done] wrapTight (Tight Wrapping) §20.4.2.19 - [done] wrapTopAndBottom (Top and Bottom Wrapping) §20.4.2.20 Attributes: - [done] allowOverlap (Allow Objects to Overlap) - [done] behindDoc (Display Behind Document Text) - [done] distB (Distance From Text on Bottom Edge) (see also: inline) - [done] distL (Distance From Text on Left Edge) (see also: inline) - [done] distR (Distance From Text on Right Edge) (see also: inline) - [done] distT (Distance From Text on Top Edge) (see also: inline) - hidden (Hidden) - [done] layoutInCell (Layout In Table Cell) - locked (Lock Anchor) - [done] relativeHeight (Relative Z-Ordering Position) - simplePos (Page Positioning) */ //! @todo support all elements //! CASE #1340 //! CASE #1410 //! CASE #1420 KoFilter::ConversionStatus DocxXmlDocumentReader::read_anchor() { READ_PROLOGUE m_docPrName.clear(); m_docPrDescr.clear(); m_drawing_anchor = true; // for pic:pic bool behindDoc = false; bool allowOverlap = false; m_alignH.clear(); m_alignV.clear(); const QXmlStreamAttributes attrs(attributes()); //! @todo parse 20.4.3.4 ST_RelFromH (Horizontal Relative Positioning), p. 3511 READ_ATTR_WITHOUT_NS(distT) distToODF("fo:margin-top", distT); READ_ATTR_WITHOUT_NS(distB) distToODF("fo:margin-bottom", distB); READ_ATTR_WITHOUT_NS(distL) distToODF("fo:margin-left", distL); READ_ATTR_WITHOUT_NS(distR) distToODF("fo:margin-right", distR); TRY_READ_ATTR_WITHOUT_NS(relativeHeight) if (!relativeHeight.isEmpty()) { m_z_index = relativeHeight.toInt(); } TRY_READ_ATTR_WITHOUT_NS(layoutInCell) m_currentDrawStyle->addProperty("style:flow-with-text", MSOOXML::Utils::convertBooleanAttr(layoutInCell, false)); behindDoc = MSOOXML::Utils::convertBooleanAttr(attrs.value("behindDoc").toString()); allowOverlap = MSOOXML::Utils::convertBooleanAttr(attrs.value("allowOverlap").toString()); while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF_NS(a, graphic) ELSE_TRY_READ_IF(positionH) ELSE_TRY_READ_IF(positionV) ELSE_TRY_READ_IF(docPr) ELSE_TRY_READ_IF(wrapSquare) ELSE_TRY_READ_IF(wrapTight) ELSE_TRY_READ_IF(wrapThrough) else if (QUALIFIED_NAME_IS(wrapNone)) { // wrapNone (No Text Wrapping), ECMA-376, 20.4.2.15 // This element specifies that the parent DrawingML object shall // not cause any text wrapping within the contents of the host // WordprocessingML document based on its display location. // CASE #1410 readNext(); if (!expectElEnd(QUALIFIED_NAME(wrapNone))) { return KoFilter::WrongFormat; } if (allowOverlap) { m_currentDrawStyle->addProperty("style:wrap", "run-through"); if (behindDoc) { m_currentDrawStyle->addProperty("style:run-through", "background"); } else { m_currentDrawStyle->addProperty("style:run-through", "foreground"); } } else { saveStyleWrap("none"); } } else if (QUALIFIED_NAME_IS(wrapTopAndBottom)) { // 20.4.2.20 wrapTopAndBottom (Top and Bottom Wrapping) // This element specifies that text shall wrap around the top // and bottom of this object, but not its left or right edges. // CASE #1410 readNext(); if (!expectElEnd(QUALIFIED_NAME(wrapTopAndBottom))) { return KoFilter::WrongFormat; } saveStyleWrap("none"); } SKIP_UNKNOWN //! @todo add ELSE_WRONG_FORMAT } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL inline //! inline handler (Inline DrawingML Object) /*! ECMA-376, 20.4.2.8, p.3485. This element specifies that the DrawingML object located at this position in the document is a floating object. Within a WordprocessingML document, drawing objects can exist in two states: - Inline - The drawing object is in line with the text, and affects the line height and layout of its line (like a character glyph of similar size). - Floating - The drawing object is anchored within the text, but can be absolutely positioned in the document relative to the page. When this element encapsulates the DrawingML object's information, then all child elements shall dictate the positioning of this object as a floating object on the page. Parent elements: - [done] drawing (§17.3.3.9) Child elements: - cNvGraphicFramePr (Common DrawingML Non-Visual Properties) §20.4.2.4 - [done] docPr (Drawing Object Non-Visual Properties) §20.4.2.5 - effectExtent (Object Extents Including Effects) §20.4.2.6 - [done] extent (Drawing Object Size) §20.4.2.7 - [done] graphic (Graphic Object) §20.1.2.2.16 Attributes: - distB (Distance From Text on Bottom Edge) - distL (Distance From Text on Left Edge) - distR (Distance From Text on Right Edge) - distT (Distance From Text on Top Edge) */ //! @todo support all elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_inline() { READ_PROLOGUE m_docPrName.clear(); m_docPrDescr.clear(); m_drawing_inline = true; // for pic m_svgX = m_svgY = m_svgWidth = m_svgHeight = 0; while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF_NS(wp, extent) ELSE_TRY_READ_IF(docPr) ELSE_TRY_READ_IF_NS(a, graphic) SKIP_UNKNOWN //! @todo add ELSE_WRONG_FORMAT } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL extent KoFilter::ConversionStatus DocxXmlDocumentReader::read_extent() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); READ_ATTR_WITHOUT_NS(cx) STRING_TO_INT(cx, m_svgWidth, "ext@cx") READ_ATTR_WITHOUT_NS(cy) STRING_TO_INT(cy, m_svgHeight, "ext@cy") while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL docPr //! docPr handler (Drawing Object Non-Visual Properties) /*! ECMA-376, 20.4.2.5, p.3478. This element specifies non-visual object properties for the parent DrawingML object. These properties are specified as child elements of this element. Parent elements: - [done] anchor (§20.4.2.3) - [done] inline (§20.4.2.8) Child elements: - extLst (Extension List) §20.1.2.2.15 - [done] hlinkClick (Click Hyperlink) §21.1.2.3.5 - hlinkHover (Hyperlink for Hover) §20.1.2.2.23 Attributes: - [done] descr (Alternative Text for Object) - hidden (Hidden) - id (Unique Identifier) - [done] name (Name) */ //! CASE #1340 //! @todo support all elements KoFilter::ConversionStatus DocxXmlDocumentReader::read_docPr() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR_WITHOUT_NS_INTO(name, m_docPrName) TRY_READ_ATTR_WITHOUT_NS_INTO(descr, m_docPrDescr) //! @todo support docPr/@hidden (maybe to style:text-properties/@text:display) while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF_NS(a, hlinkClick) SKIP_UNKNOWN //! @todo add ELSE_WRONG_FORMAT } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL positionH //! positionH handler (Horizontal Positioning) /*! ECMA-376, 20.4.2.10, p.3490. This element specifies the horizontal positioning of a floating DrawingML object within a WordprocessingML document. This positioning is specified in two parts: - Positioning Base - The relativeFrom attribute on this element specifies the part of the document from which the positioning shall be calculated. - Positioning - The child element of this element (align or posOffset) specifies how the object is positioned relative to that base. Parent elements: - [done] anchor (§20.4.2.3) Child elements: - [done] align (Relative Horizontal Alignment) §20.4.2.1 - [done] posOffset (Absolute Position Offset) §20.4.2.12 Attributes: - [done] relativeFrom (Horizontal Position Relative Base) */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_positionH() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); //! @todo parse 20.4.3.4 ST_RelFromH (Horizontal Relative Positioning), p. 3511 READ_ATTR_WITHOUT_NS_INTO(relativeFrom, m_relativeFromH) while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF_IN_CONTEXT(align) ELSE_TRY_READ_IF_IN_CONTEXT(posOffset) ELSE_WRONG_FORMAT } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL positionV //! positionV handler (Vertical Positioning) /*! ECMA-376, 20.4.2.11, p.3491. This element specifies the vertical positioning of a floating DrawingML object within a WordprocessingML document. This positioning is specified in two parts: - Positioning Base - The relativeFrom attribute on this element specifies the part of the document from which the positioning shall be calculated. - Positioning - The child element of this element (align or posOffset) specifies how the object is positioned relative to that base. Parent elements: - [done] anchor (§20.4.2.3) Child elements: - [done] align (Relative Vertical Alignment) §20.4.2.2 - [done] posOffset (Absolute Position Offset) §20.4.2.12 Attributes: - [done] relativeFrom (Horizontal Position Relative Base) */ KoFilter::ConversionStatus DocxXmlDocumentReader::read_positionV() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); //! @todo parse 20.4.3.5 ST_RelFromV (Vertical Relative Positioning), p. 3512 READ_ATTR_WITHOUT_NS_INTO(relativeFrom, m_relativeFromV) while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF_IN_CONTEXT(align) ELSE_TRY_READ_IF_IN_CONTEXT(posOffset) ELSE_WRONG_FORMAT } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL posOffset //! posOffset handler (Absolute Position Offset) /*! ECMA-376, 20.4.2.12, p.3492. This element specifies an absolute measurement for the positioning of a floating DrawingML object within a WordprocessingML document. This measurement shall be calculated relative to the top left edge of the positioning base specified by the parent element's relativeFrom attribute. Parent elements: - [done] positionH (§20.4.2.10) - [done] positionV (§20.4.2.11) No child elements. */ //! CASE #1360 KoFilter::ConversionStatus DocxXmlDocumentReader::read_posOffset(posOffsetCaller caller) { READ_PROLOGUE readNext(); if (isCharacters()) { switch (caller) { case posOffset_positionH: STRING_TO_INT(text().toString(), m_posOffsetH, "positionH/posOffset text") m_hasPosOffsetH = true; break; case posOffset_positionV: STRING_TO_INT(text().toString(), m_posOffsetV, "positionV/posOffset text") m_hasPosOffsetV = true; break; default: return KoFilter::WrongFormat; } } ELSE_WRONG_FORMAT readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL wrapSquare //! wrapSquare handler (Square Wrapping) /*! ECMA-376, 20.4.2.17, p.3497. This element specifies that text shall wrap around a virtual rectangle bounding this object. The bounds of the wrapping rectangle shall be dictated by the extents including the addition of the effectExtent element as a child of this element (if present) or the effectExtent present on the parent element. Parent elements: - [done] anchor (§20.4.2.3) Child elements: - effectExtent (Object Extents Including Effects) Attributes: - distB (Distance From Text on Bottom Edge) - distL (Distance From Text on Left Edge) - distR (Distance From Text on Right Edge) - distT (Distance From Text (Top)) - [done] wrapText (Text Wrapping Location) */ //! CASE #1410 KoFilter::ConversionStatus DocxXmlDocumentReader::read_wrapSquare() { READ_PROLOGUE readWrap(); while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) // if (isStartElement()) { //! @todo effectExtent // } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL wrapTight //! wrapTight handler (Tight Wrapping) /*! ECMA-376, 20.4.2.17, p.3497. This element specifies that text shall wrap around the wrapping polygon bounding this object as defined by the child wrapPolygon element. When this element specifies a wrapping polygon, it shall not allow text to wrap within the object's maximum left and right extents. Parent elements: - [done] anchor (§20.4.2.3) Child elements: - wrapPolygon (Wrapping Polygon) Attributes: - distL (Distance From Text on Left Edge) - distR (Distance From Text on Right Edge) - [done] wrapText (Text Wrapping Location) */ //! CASE #1410 KoFilter::ConversionStatus DocxXmlDocumentReader::read_wrapTight() { READ_PROLOGUE readWrap(); while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL); // if (isStartElement()) { //! @todo effectExtent // } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL wrapThrough //! wrapThrough handler (Through Wrapping) /*! ECMA-376, 20.4.2.18, p.3500. This element specifies that text shall wrap around the wrapping polygon bounding this object as defined by the child wrapPolygon element. When this element specifies a wrapping polygon, it shall allow text to wrap within the object's maximum left and right extents. Parent elements: - [done] anchor (§20.4.2.3) Child elements: - wrapPolygon (Wrapping Polygon) Attributes: - distL (Distance From Text on Left Edge) - distR (Distance From Text on Right Edge) - [done] wrapText (Text Wrapping Location) */ //! CASE #1410 KoFilter::ConversionStatus DocxXmlDocumentReader::read_wrapThrough() { READ_PROLOGUE readWrap(); // Note that the name wrapThrough is misleading, it does not mean run-through it just means that wrapping // happens potentially inside the container while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) // if (isStartElement()) { //! @todo effectExtent // } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL align //! align handler (Relative Horizontal Alignment, Relative Vertical Alignment) /*! ECMA-376, 20.4.2.1, 20.4.2.2, p.3468, 3469. This element specifies how a DrawingML object shall be horizontally/vertically aligned relative to the horizontal alignment base defined by the parent element. Once an alignment base is defined, this element shall determine how the DrawingML object shall be aligned relative to that location. Parent elements: - [done] positionH (§20.4.2.10) - [done] positionV (§20.4.2.11) No child elements. */ //! CASE #1340 KoFilter::ConversionStatus DocxXmlDocumentReader::read_align(alignCaller caller) { READ_PROLOGUE readNext(); if (!isEndElement()) {// was text switch (caller) { case align_positionH: //! 20.4.3.1 ST_AlignH (Relative Horizontal Alignment Positions), p. 3508. /*center inside left outside right*/ m_alignH = text().toString(); break; case align_positionV: //! 20.4.3.2 ST_AlignV (Vertical Alignment Definition), p. 3509. /*bottom center inside outside top*/ m_alignV = text().toString(); break; } readNext(); } READ_EPILOGUE } #undef MSOOXML_CURRENT_NS #define MSOOXML_CURRENT_NS "m" #undef CURRENT_EL #define CURRENT_EL oMathPara //! oMathPara handler // @todo implement... KoFilter::ConversionStatus DocxXmlDocumentReader::read_oMathPara() { READ_PROLOGUE while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF(oMath) ELSE_TRY_READ_IF(oMathParaPr) SKIP_UNKNOWN } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL oMathParaPr //! oMathParaPr handler (paragraph properties) // @todo support fully KoFilter::ConversionStatus DocxXmlDocumentReader::read_oMathParaPr() { READ_PROLOGUE while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { if (qualifiedName() == "m:jc") { TRY_READ(jc_m) } } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL oMath //! oMath handler // @todo implement... KoFilter::ConversionStatus DocxXmlDocumentReader::read_oMath() { READ_PROLOGUE while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { if (qualifiedName() == "m:r") { TRY_READ(r_m) } ELSE_TRY_READ_IF(del) ELSE_TRY_READ_IF(ins) SKIP_UNKNOWN } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL jc //! jc handler for math // @todo implement.. KoFilter::ConversionStatus DocxXmlDocumentReader::read_jc_m() { READ_PROLOGUE const QXmlStreamAttributes attrs(attributes()); TRY_READ_ATTR(val) if (!val.isEmpty()) { if (val == "centerGroup") { m_currentParagraphStyle.addProperty("fo:text-align", "center"); } else { // Fix this based on possible values, m_currentParagraphStyle.addProperty("fo:text-align", "left"); } } readNext(); READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL t //! t handler for math // @todo implement... KoFilter::ConversionStatus DocxXmlDocumentReader::read_t_m() { READ_PROLOGUE while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) kDebug() << *this; if (isCharacters()) { body->addTextSpan(text().toString()); } } READ_EPILOGUE } #undef CURRENT_EL #define CURRENT_EL r //! r handler in math // @todo implement fully. KoFilter::ConversionStatus DocxXmlDocumentReader::read_r_m() { READ_PROLOGUE m_currentTextStyle = KoGenStyle(KoGenStyle::TextAutoStyle, "text"); if (m_moveToStylesXml) { m_currentTextStyle.setAutoStyleInStylesDotXml(true); } MSOOXML::Utils::XmlWriteBuffer buffer; body = buffer.setWriter(body); while (!atEnd()) { readNext(); BREAK_IF_END_OF(CURRENT_EL) if (isStartElement()) { TRY_READ_IF_NS(w, rPr) else if (qualifiedName() == "m:t") { TRY_READ(t_m) } SKIP_UNKNOWN } } body = buffer.originalWriter(); QString currentTextStyleName = mainStyles->insert(m_currentTextStyle); body->startElement("text:span", false); body->addAttribute("text:style-name", currentTextStyleName); bool closeHyperLink = handleSpecialField(); // Writing the internal body of read_t now body = buffer.releaseWriter(); if (closeHyperLink) { body->endElement(); // some special field } body->endElement(); //text:span READ_EPILOGUE } // ************************************************ // State // ************************************************ void DocxXmlDocumentReader::saveState() { DocumentReaderState state(m_usedListStyles, m_continueListNum, m_numIdXmlId); m_statesBkp.push(state); m_usedListStyles.clear(); m_continueListNum.clear(); m_numIdXmlId.clear(); } void DocxXmlDocumentReader::restoreState() { if (m_statesBkp.isEmpty()) { kWarning() << "Error: DocumentReaderState stack is corrupt!"; return; } DocumentReaderState s = m_statesBkp.pop(); m_usedListStyles = s.usedListStyles; m_continueListNum = s.continueListNum; m_numIdXmlId = s.numIdXmlId; } #define DRAWINGML_NS "a" #define DRAWINGML_PIC_NS "pic" // DrawingML/Picture #include // this adds pic:pic, etc. #include // this adds w:pict, etc.