summaryrefslogtreecommitdiffstats
path: root/sw/source/filter/xml
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/filter/xml')
-rw-r--r--sw/source/filter/xml/XMLRedlineImportHelper.cxx842
-rw-r--r--sw/source/filter/xml/XMLRedlineImportHelper.hxx134
-rw-r--r--sw/source/filter/xml/swxml.cxx1017
-rw-r--r--sw/source/filter/xml/wrtxml.cxx586
-rw-r--r--sw/source/filter/xml/wrtxml.hxx87
-rw-r--r--sw/source/filter/xml/xmlbrsh.cxx194
-rw-r--r--sw/source/filter/xml/xmlbrshe.hxx41
-rw-r--r--sw/source/filter/xml/xmlbrshi.hxx77
-rw-r--r--sw/source/filter/xml/xmlexp.cxx623
-rw-r--r--sw/source/filter/xml/xmlexp.hxx146
-rw-r--r--sw/source/filter/xml/xmlexpit.cxx1137
-rw-r--r--sw/source/filter/xml/xmlexpit.hxx100
-rw-r--r--sw/source/filter/xml/xmlfmt.cxx1079
-rw-r--r--sw/source/filter/xml/xmlfmte.cxx389
-rw-r--r--sw/source/filter/xml/xmlfonte.cxx143
-rw-r--r--sw/source/filter/xml/xmlimp.cxx1924
-rw-r--r--sw/source/filter/xml/xmlimp.hxx187
-rw-r--r--sw/source/filter/xml/xmlimpit.cxx1056
-rw-r--r--sw/source/filter/xml/xmlimpit.hxx93
-rw-r--r--sw/source/filter/xml/xmlitem.cxx104
-rw-r--r--sw/source/filter/xml/xmlitem.hxx64
-rw-r--r--sw/source/filter/xml/xmliteme.cxx246
-rw-r--r--sw/source/filter/xml/xmlitemi.cxx278
-rw-r--r--sw/source/filter/xml/xmlitemm.cxx286
-rw-r--r--sw/source/filter/xml/xmlithlp.cxx333
-rw-r--r--sw/source/filter/xml/xmlithlp.hxx70
-rw-r--r--sw/source/filter/xml/xmlitmap.hxx87
-rw-r--r--sw/source/filter/xml/xmlitmpr.cxx39
-rw-r--r--sw/source/filter/xml/xmlmeta.cxx175
-rw-r--r--sw/source/filter/xml/xmlscript.cxx37
-rw-r--r--sw/source/filter/xml/xmltble.cxx1266
-rw-r--r--sw/source/filter/xml/xmltbli.cxx2757
-rw-r--r--sw/source/filter/xml/xmltbli.hxx214
-rw-r--r--sw/source/filter/xml/xmltext.cxx77
-rw-r--r--sw/source/filter/xml/xmltexte.cxx549
-rw-r--r--sw/source/filter/xml/xmltexte.hxx84
-rw-r--r--sw/source/filter/xml/xmltexti.cxx997
-rw-r--r--sw/source/filter/xml/xmltexti.hxx111
-rw-r--r--sw/source/filter/xml/zorder.hxx78
39 files changed, 17707 insertions, 0 deletions
diff --git a/sw/source/filter/xml/XMLRedlineImportHelper.cxx b/sw/source/filter/xml/XMLRedlineImportHelper.cxx
new file mode 100644
index 0000000000..1c7df7bee9
--- /dev/null
+++ b/sw/source/filter/xml/XMLRedlineImportHelper.cxx
@@ -0,0 +1,842 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <cstddef>
+
+#include "XMLRedlineImportHelper.hxx"
+#include <unotextcursor.hxx>
+#include <unotextrange.hxx>
+#include <unocrsr.hxx>
+#include <ndtxt.hxx>
+#include <doc.hxx>
+#include <IDocumentContentOperations.hxx>
+#include <IDocumentStylePoolAccess.hxx>
+#include <tools/datetime.hxx>
+#include <poolfmt.hxx>
+#include <fmtanchr.hxx>
+#include <ftnidx.hxx>
+#include <txtftn.hxx>
+#include <unoredline.hxx>
+#include <DocumentRedlineManager.hxx>
+#include "xmlimp.hxx"
+#include <comphelper/servicehelper.hxx>
+#include <o3tl/any.hxx>
+#include <xmloff/xmltoken.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::xmloff::token;
+
+using ::com::sun::star::text::XTextCursor;
+using ::com::sun::star::text::XTextRange;
+using ::com::sun::star::text::XWordCursor;
+using ::com::sun::star::beans::XPropertySet;
+using ::com::sun::star::beans::XPropertySetInfo;
+// collision with tools/DateTime: use UNO DateTime as util::DateTime
+// using util::DateTime;
+
+// a few helper functions
+static SwDoc* lcl_GetDocViaTunnel( Reference<XTextCursor> const & rCursor )
+{
+ OTextCursorHelper *const pXCursor =
+ dynamic_cast<OTextCursorHelper*>(rCursor.get());
+ OSL_ENSURE( pXCursor, "OTextCursorHelper missing" );
+ return pXCursor ? pXCursor->GetDoc() : nullptr;
+}
+
+static SwDoc* lcl_GetDocViaTunnel( Reference<XTextRange> const & rRange )
+{
+ SwXTextRange *const pXRange = dynamic_cast<SwXTextRange*>(rRange.get());
+ OSL_ENSURE(pXRange, "missing SwXTextRange for XTextRange");
+ // #i115174#: this may be a SvxUnoTextRange
+ // OSL_ENSURE( pXRange, "SwXTextRange missing" );
+ return pXRange ? &pXRange->GetDoc() : nullptr;
+}
+
+// XTextRangeOrNodeIndexPosition: store a position into the text
+// *either* as an XTextRange or as an SwNodeIndex. The reason is that
+// we must store either pointers to StartNodes (because redlines may
+// start on start nodes) or to a text position, and there appears to
+// be no existing type that could do both. Things are complicated by
+// the matter that (e.g in section import) we delete a few characters,
+// which may cause bookmarks (as used by XTextRange) to be deleted.
+
+namespace {
+
+class XTextRangeOrNodeIndexPosition
+{
+ Reference<XTextRange> m_xRange;
+ std::optional<SwNodeIndex> m_oIndex; // pIndex will point to the *previous* node
+
+public:
+ XTextRangeOrNodeIndexPosition();
+
+ void Set( Reference<XTextRange> const & rRange );
+ void Set( SwNode const & rIndex );
+ void SetAsNodeIndex( Reference<XTextRange> const & rRange );
+
+ void CopyPositionInto(SwPosition& rPos, SwDoc & rDoc);
+ SwDoc* GetDoc();
+
+ bool IsValid() const;
+};
+
+}
+
+XTextRangeOrNodeIndexPosition::XTextRangeOrNodeIndexPosition()
+{
+}
+
+void XTextRangeOrNodeIndexPosition::Set( Reference<XTextRange> const & rRange )
+{
+ m_xRange = rRange->getStart(); // set bookmark
+ m_oIndex.reset();
+}
+
+void XTextRangeOrNodeIndexPosition::Set( SwNode const & rIndex )
+{
+ m_oIndex = rIndex;
+ --(*m_oIndex) ; // previous node!!!
+ m_xRange = nullptr;
+}
+
+void XTextRangeOrNodeIndexPosition::SetAsNodeIndex(
+ Reference<XTextRange> const & rRange )
+{
+ // XTextRange -> XTunnel -> SwXTextRange
+ SwDoc* pDoc = lcl_GetDocViaTunnel(rRange);
+
+ if (!pDoc)
+ {
+ SAL_WARN("sw", "no SwDoc");
+ return;
+ }
+
+ // SwXTextRange -> PaM
+ SwUnoInternalPaM aPaM(*pDoc);
+ bool bSuccess = ::sw::XTextRangeToSwPaM(aPaM, rRange);
+ OSL_ENSURE(bSuccess, "illegal range");
+
+ // PaM -> Index
+ Set(aPaM.GetPoint()->GetNode());
+}
+
+void
+XTextRangeOrNodeIndexPosition::CopyPositionInto(SwPosition& rPos, SwDoc & rDoc)
+{
+ OSL_ENSURE(IsValid(), "Can't get Position");
+
+ // create PAM from start cursor (if no node index is present)
+ if (!m_oIndex.has_value())
+ {
+ SwUnoInternalPaM aUnoPaM(rDoc);
+ bool bSuccess = ::sw::XTextRangeToSwPaM(aUnoPaM, m_xRange);
+ OSL_ENSURE(bSuccess, "illegal range");
+
+ rPos = *aUnoPaM.GetPoint();
+ }
+ else
+ {
+ rPos.Assign( m_oIndex->GetNode(), SwNodeOffset(1) ); // pIndex points to previous index !!!
+ }
+}
+
+SwDoc* XTextRangeOrNodeIndexPosition::GetDoc()
+{
+ OSL_ENSURE(IsValid(), "Can't get Doc");
+
+ return m_oIndex.has_value() ? &m_oIndex->GetNodes().GetDoc() : lcl_GetDocViaTunnel(m_xRange);
+}
+
+bool XTextRangeOrNodeIndexPosition::IsValid() const
+{
+ return m_xRange.is() || m_oIndex.has_value();
+}
+
+// RedlineInfo: temporary storage for redline data
+class RedlineInfo
+{
+public:
+ RedlineInfo();
+ ~RedlineInfo();
+
+ // redline type (insert, delete, ...)
+ RedlineType eType;
+
+ // info fields:
+ OUString sAuthor; // change author string
+ OUString sComment; // change comment string
+ util::DateTime aDateTime; // change DateTime
+ OUString sMovedID; // change move id string
+ bool bMergeLastParagraph; // the SwRangeRedline::IsDelLastPara flag
+
+ // each position can may be either empty, an XTextRange, or an SwNodeIndex
+
+ // start pos of anchor (may be empty)
+ XTextRangeOrNodeIndexPosition aAnchorStart;
+
+ // end pos of anchor (may be empty)
+ XTextRangeOrNodeIndexPosition aAnchorEnd;
+
+ // index of content node (maybe NULL)
+ SwNodeIndex* pContentIndex;
+
+ // next redline info (for hierarchical redlines)
+ RedlineInfo* pNextRedline;
+
+ // store whether we expect an adjustment for this redline
+ bool bNeedsAdjustment;
+};
+
+RedlineInfo::RedlineInfo() :
+ eType(RedlineType::Insert),
+ bMergeLastParagraph( false ),
+ pContentIndex(nullptr),
+ pNextRedline(nullptr),
+ bNeedsAdjustment( false )
+{
+}
+
+RedlineInfo::~RedlineInfo()
+{
+ delete pContentIndex;
+ delete pNextRedline;
+}
+
+constexpr OUString g_sShowChanges = u"ShowChanges"_ustr;
+constexpr OUString g_sRecordChanges = u"RecordChanges"_ustr;
+constexpr OUString g_sRedlineProtectionKey = u"RedlineProtectionKey"_ustr;
+
+XMLRedlineImportHelper::XMLRedlineImportHelper(
+ SwXMLImport & rImport,
+ bool bNoRedlinesPlease,
+ const Reference<XPropertySet> & rModel,
+ const Reference<XPropertySet> & rImportInfo )
+ : m_rImport(rImport),
+ m_sInsertion( GetXMLToken( XML_INSERTION )),
+ m_sDeletion( GetXMLToken( XML_DELETION )),
+ m_sFormatChange( GetXMLToken( XML_FORMAT_CHANGE )),
+ m_bIgnoreRedlines(bNoRedlinesPlease),
+ m_xModelPropertySet(rModel),
+ m_xImportInfoPropertySet(rImportInfo)
+{
+ // check to see if redline mode is handled outside of component
+ bool bHandleShowChanges = true;
+ bool bHandleRecordChanges = true;
+ bool bHandleProtectionKey = true;
+ if ( m_xImportInfoPropertySet.is() )
+ {
+ Reference<XPropertySetInfo> xInfo =
+ m_xImportInfoPropertySet->getPropertySetInfo();
+
+ bHandleShowChanges = ! xInfo->hasPropertyByName( g_sShowChanges );
+ bHandleRecordChanges = ! xInfo->hasPropertyByName( g_sRecordChanges );
+ bHandleProtectionKey = ! xInfo->hasPropertyByName( g_sRedlineProtectionKey );
+ }
+
+ // get redline mode
+ m_bShowChanges = *o3tl::doAccess<bool>(
+ ( bHandleShowChanges ? m_xModelPropertySet : m_xImportInfoPropertySet )
+ ->getPropertyValue( g_sShowChanges ));
+ m_bRecordChanges = *o3tl::doAccess<bool>(
+ ( bHandleRecordChanges ? m_xModelPropertySet : m_xImportInfoPropertySet )
+ ->getPropertyValue( g_sRecordChanges ));
+ {
+ Any aAny = (bHandleProtectionKey ? m_xModelPropertySet
+ : m_xImportInfoPropertySet )
+ ->getPropertyValue( g_sRedlineProtectionKey );
+ aAny >>= m_aProtectionKey;
+ }
+
+ // set redline mode to "don't record changes"
+ if( bHandleRecordChanges )
+ {
+ m_xModelPropertySet->setPropertyValue( g_sRecordChanges, Any(false) );
+ }
+}
+
+XMLRedlineImportHelper::~XMLRedlineImportHelper()
+{
+ // delete all left over (and obviously incomplete) RedlineInfos (and map)
+ for( const auto& rEntry : m_aRedlineMap )
+ {
+ RedlineInfo* pInfo = rEntry.second;
+
+ // left-over redlines. Insert them if possible (but assert),
+ // and delete the incomplete ones. Finally, delete it.
+ if( IsReady(pInfo) )
+ {
+ OSL_FAIL("forgotten RedlineInfo; now inserted");
+ InsertIntoDocument( pInfo );
+ }
+ else
+ {
+ // try if only the adjustment was missing
+ pInfo->bNeedsAdjustment = false;
+ if( IsReady(pInfo) )
+ {
+ OSL_FAIL("RedlineInfo without adjustment; now inserted");
+ InsertIntoDocument( pInfo );
+ }
+ else
+ {
+ // this situation occurs if redlines aren't closed
+ // (i.e. end without start, or start without
+ // end). This may well be a problem in the file,
+ // rather than the code.
+ OSL_FAIL("incomplete redline (maybe file was corrupt); "
+ "now deleted");
+ }
+ }
+ delete pInfo;
+ }
+ m_aRedlineMap.clear();
+
+ // set redline mode, either to info property set, or directly to
+ // the document
+ bool bHandleShowChanges = true;
+ bool bHandleRecordChanges = true;
+ bool bHandleProtectionKey = true;
+ if ( m_xImportInfoPropertySet.is() )
+ {
+ Reference<XPropertySetInfo> xInfo =
+ m_xImportInfoPropertySet->getPropertySetInfo();
+
+ bHandleShowChanges = ! xInfo->hasPropertyByName( g_sShowChanges );
+ bHandleRecordChanges = ! xInfo->hasPropertyByName( g_sRecordChanges );
+ bHandleProtectionKey = ! xInfo->hasPropertyByName( g_sRedlineProtectionKey );
+ }
+
+ // set redline mode & key
+ try
+ {
+ Any aAny;
+
+ aAny <<= m_bShowChanges;
+ if ( bHandleShowChanges )
+ {
+ aAny <<= true;
+ m_xModelPropertySet->setPropertyValue( g_sShowChanges, aAny );
+ // TODO maybe we need some property for the view-setting?
+ SwDoc *const pDoc(m_rImport.getDoc());
+ assert(pDoc);
+ pDoc->GetDocumentRedlineManager().SetHideRedlines(!m_bShowChanges);
+ }
+ else
+ m_xImportInfoPropertySet->setPropertyValue( g_sShowChanges, aAny );
+
+ aAny <<= m_bRecordChanges;
+ if ( bHandleRecordChanges )
+ m_xModelPropertySet->setPropertyValue( g_sRecordChanges, aAny );
+ else
+ m_xImportInfoPropertySet->setPropertyValue( g_sRecordChanges, aAny );
+
+ aAny <<= m_aProtectionKey;
+ if ( bHandleProtectionKey )
+ m_xModelPropertySet->setPropertyValue( g_sRedlineProtectionKey, aAny );
+ else
+ m_xImportInfoPropertySet->setPropertyValue( g_sRedlineProtectionKey, aAny);
+ }
+ catch (const uno::RuntimeException &) // fdo#65882
+ {
+ SAL_WARN( "sw", "potentially benign ordering issue during shutdown" );
+ }
+}
+
+void XMLRedlineImportHelper::Add(
+ std::u16string_view rType,
+ const OUString& rId,
+ const OUString& rAuthor,
+ const OUString& rComment,
+ const util::DateTime& rDateTime,
+ const OUString& rMovedID,
+ bool bMergeLastPara)
+{
+ // we need to do the following:
+ // 1) parse type string
+ // 2) create RedlineInfo and fill it with data
+ // 3) check for existing redline with same ID
+ // 3a) insert redline into map
+ // 3b) attach to existing redline
+
+ // ad 1)
+ RedlineType eType;
+ if (rType == m_sInsertion)
+ {
+ eType = RedlineType::Insert;
+ }
+ else if (rType == m_sDeletion)
+ {
+ eType = RedlineType::Delete;
+ }
+ else if (rType == m_sFormatChange)
+ {
+ eType = RedlineType::Format;
+ }
+ else
+ {
+ // no proper type found: early out!
+ return;
+ }
+
+ // ad 2) create a new RedlineInfo
+ RedlineInfo* pInfo = new RedlineInfo();
+
+ // fill entries
+ pInfo->eType = eType;
+ pInfo->sAuthor = rAuthor;
+ pInfo->sComment = rComment;
+ pInfo->aDateTime = rDateTime;
+ pInfo->sMovedID = rMovedID;
+ pInfo->bMergeLastParagraph = bMergeLastPara;
+
+ //reserve MoveID so it won't be reused by others
+ if (!rMovedID.isEmpty())
+ {
+ SwDoc* const pDoc(m_rImport.getDoc());
+ assert(pDoc);
+ pDoc->GetDocumentRedlineManager().GetRedlineTable().setMovedIDIfNeeded(rMovedID.toInt32());
+ }
+
+ // ad 3)
+ auto itPair = m_aRedlineMap.emplace(rId, pInfo);
+ if (itPair.second)
+ return;
+
+ // 3b) we already have a redline with this name: hierarchical redlines
+ // insert pInfo as last element in the chain.
+ // (hierarchy sanity checking happens on inserting into the document)
+
+ // find last element
+ RedlineInfo* pInfoChain;
+ for( pInfoChain = itPair.first->second;
+ nullptr != pInfoChain->pNextRedline;
+ pInfoChain = pInfoChain->pNextRedline) ; // empty loop
+
+ // insert as last element
+ pInfoChain->pNextRedline = pInfo;
+}
+
+Reference<XTextCursor> XMLRedlineImportHelper::CreateRedlineTextSection(
+ Reference<XTextCursor> const & xOldCursor,
+ const OUString& rId)
+{
+ Reference<XTextCursor> xReturn;
+
+ // this method will modify the document directly -> lock SolarMutex
+ SolarMutexGuard aGuard;
+
+ // get RedlineInfo
+ RedlineMapType::iterator aFind = m_aRedlineMap.find(rId);
+ if (m_aRedlineMap.end() != aFind)
+ {
+ // get document from old cursor (via tunnel)
+ SwDoc* pDoc = lcl_GetDocViaTunnel(xOldCursor);
+
+ if (!pDoc)
+ {
+ SAL_WARN("sw", "no SwDoc => cannot create section.");
+ return nullptr;
+ }
+
+ // create text section for redline
+ SwTextFormatColl *pColl = pDoc->getIDocumentStylePoolAccess().GetTextCollFromPool
+ (RES_POOLCOLL_STANDARD, false );
+ SwStartNode* pRedlineNode = pDoc->GetNodes().MakeTextSection(
+ pDoc->GetNodes().GetEndOfRedlines(),
+ SwNormalStartNode,
+ pColl);
+
+ // remember node-index in RedlineInfo
+ SwNodeIndex aIndex(*pRedlineNode);
+ aFind->second->pContentIndex = new SwNodeIndex(aIndex);
+
+ // create XText for document
+ rtl::Reference<SwXRedlineText> pXText = new SwXRedlineText(pDoc, aIndex);
+
+ // create (UNO-) cursor
+ SwPosition aPos(*pRedlineNode);
+ rtl::Reference<SwXTextCursor> pXCursor =
+ new SwXTextCursor(*pDoc, pXText, CursorType::Redline, aPos);
+ pXCursor->GetCursor().Move(fnMoveForward, GoInNode);
+ // cast to avoid ambiguity
+ xReturn = static_cast<text::XWordCursor*>(pXCursor.get());
+ }
+ // else: unknown redline -> Ignore
+
+ return xReturn;
+}
+
+void XMLRedlineImportHelper::SetCursor(
+ const OUString& rId,
+ bool bStart,
+ Reference<XTextRange> const & rRange,
+ bool bIsOutsideOfParagraph)
+{
+ RedlineMapType::iterator aFind = m_aRedlineMap.find(rId);
+ if (m_aRedlineMap.end() == aFind)
+ return;
+
+ // RedlineInfo found; now set Cursor
+ RedlineInfo* pInfo = aFind->second;
+ if (bIsOutsideOfParagraph)
+ {
+ // outside of paragraph: remember SwNodeIndex
+ if (bStart)
+ {
+ pInfo->aAnchorStart.SetAsNodeIndex(rRange);
+ }
+ else
+ {
+ pInfo->aAnchorEnd.SetAsNodeIndex(rRange);
+ }
+
+ // also remember that we expect an adjustment for this redline
+ pInfo->bNeedsAdjustment = true;
+ }
+ else
+ {
+ // inside of a paragraph: use regular XTextRanges (bookmarks)
+ if (bStart)
+ pInfo->aAnchorStart.Set(rRange);
+ else
+ pInfo->aAnchorEnd.Set(rRange);
+ }
+
+ // if this Cursor was the last missing info, we insert the
+ // node into the document
+ // then we can remove the entry from the map and destroy the object
+ if (IsReady(pInfo))
+ {
+ InsertIntoDocument(pInfo);
+ m_aRedlineMap.erase(rId);
+ delete pInfo;
+ }
+ // else: unknown Id -> ignore
+}
+
+void XMLRedlineImportHelper::AdjustStartNodeCursor(
+ const OUString& rId) /// ID used in RedlineAdd() call
+{
+ // this method will modify the document directly -> lock SolarMutex
+ SolarMutexGuard aGuard;
+
+ // start + end nodes are treated the same. For either it's
+ // necessary that the target node already exists.
+
+ RedlineMapType::iterator aFind = m_aRedlineMap.find(rId);
+ if (m_aRedlineMap.end() == aFind)
+ return;
+
+ // RedlineInfo found; now set Cursor
+ RedlineInfo* pInfo = aFind->second;
+
+ pInfo->bNeedsAdjustment = false;
+
+ // if now ready, insert into document
+ if( IsReady(pInfo) )
+ {
+ InsertIntoDocument(pInfo);
+ m_aRedlineMap.erase(rId);
+ delete pInfo;
+ }
+ // else: can't find redline -> ignore
+}
+
+inline bool XMLRedlineImportHelper::IsReady(const RedlineInfo* pRedline)
+{
+ // we can insert a redline if we have start & end, and we don't
+ // expect adjustments for either of these
+ return ( pRedline->aAnchorEnd.IsValid() &&
+ pRedline->aAnchorStart.IsValid() &&
+ !pRedline->bNeedsAdjustment );
+}
+
+/// recursively check if rPos or its anchor (if in fly or footnote) is in redline section
+static auto RecursiveContains(SwStartNode const& rRedlineSection, SwNode const& rPos) -> bool
+{
+ if (rRedlineSection.GetIndex() <= rPos.GetIndex()
+ && rPos.GetIndex() <= rRedlineSection.EndOfSectionIndex())
+ {
+ return true;
+ }
+ // loop to iterate "up" in the node tree and find an anchored XText
+ for (SwStartNode const* pStartNode = rPos.StartOfSectionNode();
+ pStartNode != nullptr && pStartNode->GetIndex() != SwNodeOffset(0);
+ pStartNode = pStartNode->StartOfSectionNode())
+ {
+ switch (pStartNode->GetStartNodeType())
+ {
+ case SwNormalStartNode:
+ case SwTableBoxStartNode:
+ continue;
+ break;
+ case SwFlyStartNode:
+ {
+ SwFrameFormat const*const pFormat(pStartNode->GetFlyFormat());
+ assert(pFormat);
+ SwFormatAnchor const& rAnchor(pFormat->GetAnchor());
+ if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PAGE)
+ {
+ return false;
+ }
+ else if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_FLY)
+ { // anchor is on a start node, avoid skipping it:
+ pStartNode = rAnchor.GetAnchorNode()->GetStartNode();
+ assert(pStartNode);
+ // pass the next node to recursive call - it will call
+ // call StartOfSectionNode on it and go back to pStartNode
+ SwNodeIndex const next(*pStartNode, +1);
+ return RecursiveContains(rRedlineSection, next.GetNode());
+ }
+ else
+ {
+ return RecursiveContains(rRedlineSection, *rAnchor.GetAnchorNode());
+ }
+ }
+ break;
+ case SwFootnoteStartNode:
+ { // sigh ... need to search
+ for (SwTextFootnote const*const pFootnote : rRedlineSection.GetDoc().GetFootnoteIdxs())
+ {
+ if (pStartNode == pFootnote->GetStartNode()->GetNode().GetStartNode())
+ {
+ return RecursiveContains(rRedlineSection, pFootnote->GetTextNode());
+ }
+ }
+ assert(false);
+ }
+ break;
+ case SwHeaderStartNode:
+ case SwFooterStartNode:
+ return false; // headers aren't anchored
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ }
+ return false;
+}
+
+void XMLRedlineImportHelper::InsertIntoDocument(RedlineInfo* pRedlineInfo)
+{
+ OSL_ENSURE(nullptr != pRedlineInfo, "need redline info");
+ OSL_ENSURE(IsReady(pRedlineInfo), "redline info not complete yet!");
+
+ // this method will modify the document directly -> lock SolarMutex
+ SolarMutexGuard aGuard;
+
+ // Insert the Redline as described by pRedlineInfo into the
+ // document. If we are in insert mode, don't insert any redlines
+ // (and delete 'deleted' inline redlines)
+
+ // get the document (from one of the positions)
+ SwDoc* pDoc = pRedlineInfo->aAnchorStart.GetDoc();
+
+ if (!pDoc)
+ {
+ SAL_WARN("sw", "no SwDoc => cannot insert redline.");
+ return;
+ }
+
+ // now create the PaM for the redline
+ SwPaM aPaM(pDoc->GetNodes().GetEndOfContent());
+ pRedlineInfo->aAnchorStart.CopyPositionInto(*aPaM.GetPoint(), *pDoc);
+ aPaM.SetMark();
+ pRedlineInfo->aAnchorEnd.CopyPositionInto(*aPaM.GetPoint(), *pDoc);
+
+ // collapse PaM if (start == end)
+ if (*aPaM.GetPoint() == *aPaM.GetMark())
+ {
+ aPaM.DeleteMark();
+ }
+
+ // cover three cases:
+ // 1) empty redlines (no range, no content)
+ // 2) check for:
+ // a) bIgnoreRedline (e.g. insert mode)
+ // b) illegal PaM range (CheckNodesRange())
+ // c) redline with empty content section (quite useless)
+ // 3) normal case: insert redline
+ SwTextNode const* pTempNode(nullptr);
+ if( !aPaM.HasMark() && (pRedlineInfo->pContentIndex == nullptr) )
+ {
+ // these redlines have no function, and will thus be ignored (just as
+ // in sw3io), so no action here
+ }
+ else if ( m_bIgnoreRedlines ||
+ !CheckNodesRange( aPaM.GetPoint()->GetNode(),
+ aPaM.GetMark()->GetNode(),
+ true )
+ || (pRedlineInfo->pContentIndex
+ && (pRedlineInfo->pContentIndex->GetIndex() + 2
+ == pRedlineInfo->pContentIndex->GetNode().EndOfSectionIndex())
+ && (pTempNode = pDoc->GetNodes()[pRedlineInfo->pContentIndex->GetIndex() + 1]->GetTextNode()) != nullptr
+ && pTempNode->GetText().isEmpty()
+ && !pTempNode->GetpSwpHints()
+ && pTempNode->GetAnchoredFlys().empty()))
+ {
+ // ignore redline (e.g. file loaded in insert mode):
+ // delete 'deleted' redlines and forget about the whole thing
+ if (RedlineType::Delete == pRedlineInfo->eType)
+ {
+ pDoc->getIDocumentContentOperations().DeleteRange(aPaM);
+ // And what about the "deleted nodes"?
+ // They have to be deleted as well (#i80689)!
+ if( m_bIgnoreRedlines && pRedlineInfo->pContentIndex != nullptr )
+ {
+ const SwNodeIndex& rIdx( *pRedlineInfo->pContentIndex );
+ const SwNode* pEnd = rIdx.GetNode().EndOfSectionNode();
+ if( pEnd )
+ {
+ SwPaM aDel( rIdx.GetNode(), 0, *pEnd, 1 );
+ pDoc->getIDocumentContentOperations().DeleteRange(aDel);
+ }
+ }
+ }
+ }
+ else if (pRedlineInfo->pContentIndex != nullptr
+ // should be enough to check 1 position of aPaM bc CheckNodesRange() above
+ && RecursiveContains(*pRedlineInfo->pContentIndex->GetNode().GetStartNode(), aPaM.GetPoint()->GetNode()))
+ {
+ SAL_WARN("sw.xml", "Recursive change tracking, removing");
+ // reuse aPaM to remove it from nodes that will be deleted
+ aPaM.GetPoint()->Assign(pRedlineInfo->pContentIndex->GetNode());
+ aPaM.DeleteMark();
+ pDoc->getIDocumentContentOperations().DeleteSection(&aPaM.GetPoint()->GetNode());
+ }
+ else
+ {
+ // regular file loading: insert redline
+
+ // create redline (using pRedlineData which gets copied in SwRangeRedline())
+ SwRedlineData* pRedlineData = ConvertRedline(pRedlineInfo, pDoc);
+ SwRangeRedline* pRedline =
+ new SwRangeRedline( pRedlineData, *aPaM.GetPoint(),
+ !pRedlineInfo->bMergeLastParagraph );
+
+ // tdf#107292 fix order of delete redlines at the same position by removing
+ // the already inserted redlines temporarily and inserting them back in reverse
+ // order after inserting pRedline
+ std::vector<const SwRangeRedline*> aSwapRedlines;
+ if ( RedlineType::Delete == pRedlineInfo->eType )
+ {
+ SwRedlineTable::size_type n = 0;
+ while ( const SwRangeRedline* pRedline2 =
+ pDoc->getIDocumentRedlineAccess().GetRedline( *pRedline->Start(), &n ) )
+ {
+ SwRedlineTable& aRedlineTable = pDoc->getIDocumentRedlineAccess().GetRedlineTable();
+ aSwapRedlines.push_back(pRedline2);
+ aRedlineTable.Remove(n);
+ }
+ }
+
+ // set mark
+ if( aPaM.HasMark() )
+ {
+ pRedline->SetMark();
+ *(pRedline->GetMark()) = *aPaM.GetMark();
+ }
+
+ // set content node (if necessary)
+ if (nullptr != pRedlineInfo->pContentIndex)
+ {
+ SwNodeOffset nPoint = aPaM.GetPoint()->GetNodeIndex();
+ if( nPoint < pRedlineInfo->pContentIndex->GetIndex() ||
+ nPoint > pRedlineInfo->pContentIndex->GetNode().EndOfSectionIndex() )
+ pRedline->SetContentIdx(*pRedlineInfo->pContentIndex);
+ else
+ SAL_WARN("sw", "Recursive change tracking");
+ }
+
+ // set redline mode (without doing the associated book-keeping)
+ pDoc->getIDocumentRedlineAccess().SetRedlineFlags_intern(RedlineFlags::On);
+ pDoc->getIDocumentRedlineAccess().AppendRedline(pRedline, false);
+
+ // restore the correct order of the delete redlines at the same position
+ for (auto i = aSwapRedlines.rbegin(); i != aSwapRedlines.rend(); ++i)
+ pDoc->getIDocumentRedlineAccess().AppendRedline(const_cast<SwRangeRedline*>(*i), false);
+
+ pDoc->getIDocumentRedlineAccess().SetRedlineFlags_intern(RedlineFlags::NONE);
+ }
+}
+
+SwRedlineData* XMLRedlineImportHelper::ConvertRedline(
+ RedlineInfo* pRedlineInfo,
+ SwDoc* pDoc)
+{
+ // convert info:
+ // 1) Author String -> Author ID (default to zero)
+ std::size_t nAuthorId = (nullptr == pDoc) ? 0 :
+ pDoc->getIDocumentRedlineAccess().InsertRedlineAuthor( pRedlineInfo->sAuthor );
+
+ // 2) util::DateTime -> DateTime
+ DateTime aDT( DateTime::EMPTY );
+ aDT.SetYear( pRedlineInfo->aDateTime.Year );
+ aDT.SetMonth( pRedlineInfo->aDateTime.Month );
+ aDT.SetDay( pRedlineInfo->aDateTime.Day );
+ aDT.SetHour( pRedlineInfo->aDateTime.Hours );
+ aDT.SetMin( pRedlineInfo->aDateTime.Minutes );
+ aDT.SetSec( pRedlineInfo->aDateTime.Seconds );
+ aDT.SetNanoSec( pRedlineInfo->aDateTime.NanoSeconds );
+
+ sal_uInt32 nMovedID = pRedlineInfo->sMovedID.toInt32();
+
+ // 3) recursively convert next redline
+ // ( check presence and sanity of hierarchical redline info )
+ SwRedlineData* pNext = nullptr;
+ if ( (nullptr != pRedlineInfo->pNextRedline) &&
+ (RedlineType::Delete == pRedlineInfo->eType) &&
+ (RedlineType::Insert == pRedlineInfo->pNextRedline->eType) )
+ {
+ pNext = ConvertRedline(pRedlineInfo->pNextRedline, pDoc);
+ }
+
+ // create redline data
+ SwRedlineData* pData = new SwRedlineData(pRedlineInfo->eType,
+ nAuthorId, aDT, nMovedID,
+ pRedlineInfo->sComment,
+ pNext); // next data (if available)
+
+ return pData;
+}
+
+void XMLRedlineImportHelper::SetShowChanges( bool bShow )
+{
+ m_bShowChanges = bShow;
+}
+
+void XMLRedlineImportHelper::SetRecordChanges( bool bRecord )
+{
+ m_bRecordChanges = bRecord;
+}
+
+void XMLRedlineImportHelper::SetProtectionKey(
+ const Sequence<sal_Int8> & rKey )
+{
+ m_aProtectionKey = rKey;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/XMLRedlineImportHelper.hxx b/sw/source/filter/xml/XMLRedlineImportHelper.hxx
new file mode 100644
index 0000000000..8a15f53dfb
--- /dev/null
+++ b/sw/source/filter/xml/XMLRedlineImportHelper.hxx
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SW_SOURCE_FILTER_XML_XMLREDLINEIMPORTHELPER_HXX
+#define INCLUDED_SW_SOURCE_FILTER_XML_XMLREDLINEIMPORTHELPER_HXX
+
+#include <rtl/ustring.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/uno/Sequence.h>
+#include <com/sun/star/util/DateTime.hpp>
+#include <redline.hxx>
+
+#include <map>
+
+class SvXMLImport;
+class RedlineInfo;
+class SwRedlineData;
+class SwDoc;
+class SwXMLImport;
+namespace com::sun::star {
+ namespace text { class XTextCursor; }
+ namespace text { class XTextRange; }
+ namespace frame { class XModel; }
+}
+
+typedef std::map< OUString, RedlineInfo* > RedlineMapType;
+
+class XMLRedlineImportHelper final
+{
+ SwXMLImport & m_rImport;
+
+ const OUString m_sInsertion;
+ const OUString m_sDeletion;
+ const OUString m_sFormatChange;
+
+ RedlineMapType m_aRedlineMap;
+
+ // if true, no redlines should be inserted into document
+ // (This typically happen when a document is loaded in 'insert'-mode.)
+ bool m_bIgnoreRedlines;
+
+ // save information for saving and reconstruction of the redline mode
+ css::uno::Reference<css::beans::XPropertySet> m_xModelPropertySet;
+ css::uno::Reference<css::beans::XPropertySet> m_xImportInfoPropertySet;
+ bool m_bShowChanges;
+ bool m_bRecordChanges;
+ css::uno::Sequence<sal_Int8> m_aProtectionKey;
+
+public:
+
+ XMLRedlineImportHelper(
+ SwXMLImport & rImport,
+ bool bIgnoreRedlines, // ignore redlines mode
+ // property sets of model + import info for saving + restoring the
+ // redline mode
+ const css::uno::Reference<css::beans::XPropertySet> & rModel,
+ const css::uno::Reference<css::beans::XPropertySet> & rImportInfoSet );
+ ~XMLRedlineImportHelper();
+
+ // create a redline object
+ // (The redline will be inserted into the document after both start
+ // and end cursor has been set.)
+ void Add(
+ std::u16string_view rType, // redline type (insert, del,... )
+ const OUString& rId, // use to identify this redline
+ const OUString& rAuthor, // name of the author
+ const OUString& rComment, // redline comment
+ const css::util::DateTime& rDateTime, // date+time
+ const OUString& rMovedID, // redline move id
+ bool bMergeLastParagraph); // merge last paragraph?
+
+ // create a text section for the redline, and return an
+ // XText/XTextCursor that may be used to write into it.
+ css::uno::Reference<css::text::XTextCursor> CreateRedlineTextSection(
+ css::uno::Reference<css::text::XTextCursor> const & xOldCursor, // needed to get the document
+ const OUString& rId); // ID used to RedlineAdd() call
+
+ // Set start or end position for a redline in the text body.
+ // Accepts XTextRange objects.
+ void SetCursor(
+ const OUString& rId, // ID used in RedlineAdd() call
+ bool bStart, // start or end Range
+ css::uno::Reference<css::text::XTextRange> const & rRange, // the actual XTextRange
+ // text range is (from an XML view) outside of a paragraph
+ // (i.e. before a table)
+ bool bIsOutsideOfParagraph);
+
+ /**
+ * Adjust the start (end) position for a redline that begins in a
+ * start node. It takes the cursor positions _inside_ the redlined
+ * element (e.g. section or table).
+ */
+ void AdjustStartNodeCursor(
+ const OUString& rId); // ID used in RedlineAdd() call
+
+ // set redline mode: show changes
+ void SetShowChanges( bool bShowChanges );
+
+ // set redline mode: record changes
+ void SetRecordChanges( bool bRecordChanges );
+
+ // set redline protection key
+ void SetProtectionKey(const css::uno::Sequence<sal_Int8> & rKey );
+
+private:
+
+ static inline bool IsReady(const RedlineInfo* pRedline);
+
+ void InsertIntoDocument(RedlineInfo* pRedline);
+
+ SwRedlineData* ConvertRedline(
+ RedlineInfo* pRedline, // RedlineInfo to be converted
+ SwDoc* pDoc); // document needed for Author-ID conversion
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/swxml.cxx b/sw/source/filter/xml/swxml.cxx
new file mode 100644
index 0000000000..16ae089113
--- /dev/null
+++ b/sw/source/filter/xml/swxml.cxx
@@ -0,0 +1,1017 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <comphelper/processfactory.hxx>
+#include <com/sun/star/xml/sax/InputSource.hpp>
+#include <com/sun/star/xml/sax/Parser.hpp>
+#include <com/sun/star/xml/sax/SAXParseException.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/document/NamedPropertyValues.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/packages/zip/ZipIOException.hpp>
+#include <com/sun/star/packages/WrongPasswordException.hpp>
+#include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <o3tl/any.hxx>
+#include <vcl/errinf.hxx>
+#include <sfx2/docfile.hxx>
+#include <svtools/sfxecode.hxx>
+#include <svl/stritem.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <svx/xmlgrhlp.hxx>
+#include <svx/xmleohlp.hxx>
+#include <comphelper/fileformat.h>
+#include <comphelper/genericpropertyset.hxx>
+#include <comphelper/propertysetinfo.hxx>
+#include <sal/log.hxx>
+#include <sfx2/frame.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <swerror.h>
+#include <fltini.hxx>
+#include <drawdoc.hxx>
+#include <doc.hxx>
+#include <docfunc.hxx>
+#include <IDocumentSettingAccess.hxx>
+#include <IDocumentDrawModelAccess.hxx>
+#include <IDocumentMarkAccess.hxx>
+#include <IDocumentRedlineAccess.hxx>
+#include <DocumentRedlineManager.hxx>
+#include <docary.hxx>
+#include <docsh.hxx>
+#include <unotextrange.hxx>
+#include <SwXMLSectionList.hxx>
+
+#include <SwStyleNameMapper.hxx>
+#include <poolfmt.hxx>
+#include <numrule.hxx>
+#include <paratr.hxx>
+#include <fmtrowsplt.hxx>
+
+#include <svx/svdpage.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdograf.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <istyleaccess.hxx>
+
+#include <sfx2/DocumentMetadataAccess.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::lang;
+
+static void lcl_EnsureValidPam( SwPaM& rPam )
+{
+ if( rPam.GetPointContentNode() != nullptr )
+ {
+ // set proper point content
+ if( rPam.GetPointContentNode() != rPam.GetPoint()->GetContentNode() )
+ {
+ rPam.GetPoint()->nContent.Assign( rPam.GetPointContentNode(), 0 );
+ }
+ // else: point was already valid
+
+ // if mark is invalid, we delete it
+ if( ( rPam.GetMarkContentNode() == nullptr ) ||
+ ( rPam.GetMarkContentNode() != rPam.GetMark()->GetContentNode() ) )
+ {
+ rPam.DeleteMark();
+ }
+ }
+ else
+ {
+ // point is not valid, so move it into the first content
+ rPam.DeleteMark();
+ rPam.GetPoint()->Assign(
+ *rPam.GetDoc().GetNodes().GetEndOfContent().StartOfSectionNode() );
+ rPam.GetPoint()->Adjust(SwNodeOffset(+1));
+ rPam.Move( fnMoveForward, GoInContent ); // go into content
+ }
+}
+
+XMLReader::XMLReader()
+{
+}
+
+SwReaderType XMLReader::GetReaderType()
+{
+ return SwReaderType::Storage;
+}
+
+namespace
+{
+
+/// read a component (file + filter version)
+ErrCodeMsg ReadThroughComponent(
+ uno::Reference<io::XInputStream> const & xInputStream,
+ uno::Reference<XComponent> const & xModelComponent,
+ const OUString& rStreamName,
+ uno::Reference<uno::XComponentContext> const & rxContext,
+ const char* pFilterName,
+ const Sequence<Any>& rFilterArguments,
+ const OUString& rName,
+ bool bMustBeSuccessful,
+ bool bEncrypted )
+{
+ OSL_ENSURE(xInputStream.is(), "input stream missing");
+ OSL_ENSURE(xModelComponent.is(), "document missing");
+ OSL_ENSURE(rxContext.is(), "factory missing");
+ OSL_ENSURE(nullptr != pFilterName,"I need a service name for the component!");
+
+ // prepare ParserInputSource
+ xml::sax::InputSource aParserInput;
+ aParserInput.sSystemId = rName;
+ aParserInput.aInputStream = xInputStream;
+
+ // get filter
+ const OUString aFilterName(OUString::createFromAscii(pFilterName));
+ uno::Reference< XInterface > xFilter =
+ rxContext->getServiceManager()->createInstanceWithArgumentsAndContext(aFilterName, rFilterArguments, rxContext);
+ SAL_WARN_IF(!xFilter.is(), "sw.filter", "Can't instantiate filter component: " << aFilterName);
+ if( !xFilter.is() )
+ return ERR_SWG_READ_ERROR;
+ // the underlying SvXMLImport implements XFastParser, XImporter, XFastDocumentHandler
+ uno::Reference< xml::sax::XFastParser > xFastParser(xFilter, UNO_QUERY);
+ uno::Reference< xml::sax::XDocumentHandler > xDocumentHandler;
+ if (!xFastParser)
+ xDocumentHandler.set(xFilter, UNO_QUERY);
+ if (!xDocumentHandler && !xFastParser)
+ {
+ SAL_WARN("sd", "service does not implement XFastParser or XDocumentHandler");
+ assert(false);
+ return ERR_SWG_READ_ERROR;
+ }
+
+ // connect model and filter
+ uno::Reference < XImporter > xImporter( xFilter, UNO_QUERY );
+ xImporter->setTargetDocument( xModelComponent );
+
+ // finally, parse the stream
+ try
+ {
+ if (xFastParser)
+ xFastParser->parseStream( aParserInput );
+ else
+ {
+ uno::Reference< xml::sax::XParser > xParser = xml::sax::Parser::create(rxContext);
+ // connect parser and filter
+ xParser->setDocumentHandler( xDocumentHandler );
+ xParser->parseStream( aParserInput );
+ }
+ }
+ catch( xml::sax::SAXParseException& r)
+ {
+ css::uno::Any ex( cppu::getCaughtException() );
+ // sax parser sends wrapped exceptions,
+ // try to find the original one
+ xml::sax::SAXException aSaxEx = *static_cast<xml::sax::SAXException*>(&r);
+ bool bTryChild = true;
+
+ while( bTryChild )
+ {
+ xml::sax::SAXException aTmp;
+ if ( aSaxEx.WrappedException >>= aTmp )
+ aSaxEx = aTmp;
+ else
+ bTryChild = false;
+ }
+
+ packages::zip::ZipIOException aBrokenPackage;
+ if ( aSaxEx.WrappedException >>= aBrokenPackage )
+ return ERRCODE_IO_BROKENPACKAGE;
+
+ if( bEncrypted )
+ return ERRCODE_SFX_WRONGPASSWORD;
+
+ SAL_WARN( "sw", "SAX parse exception caught while importing: " << exceptionToString(ex) );
+
+ const OUString sErr( OUString::number( r.LineNumber )
+ + ","
+ + OUString::number( r.ColumnNumber ) );
+
+ if( !rStreamName.isEmpty() )
+ {
+ return ErrCodeMsg(
+ (bMustBeSuccessful ? ERR_FORMAT_FILE_ROWCOL
+ : WARN_FORMAT_FILE_ROWCOL),
+ rStreamName, sErr,
+ DialogMask::ButtonsOk | DialogMask::MessageError );
+ }
+ else
+ {
+ OSL_ENSURE( bMustBeSuccessful, "Warnings are not supported" );
+ return ErrCodeMsg( ERR_FORMAT_ROWCOL, sErr,
+ DialogMask::ButtonsOk | DialogMask::MessageError );
+ }
+ }
+ catch(const xml::sax::SAXException& r)
+ {
+ css::uno::Any ex( cppu::getCaughtException() );
+ packages::zip::ZipIOException aBrokenPackage;
+ if ( r.WrappedException >>= aBrokenPackage )
+ return ERRCODE_IO_BROKENPACKAGE;
+
+ if( bEncrypted )
+ return ERRCODE_SFX_WRONGPASSWORD;
+
+ SAL_WARN( "sw", "uno exception caught while importing: " << exceptionToString(ex) );
+ return ERR_SWG_READ_ERROR;
+ }
+ catch(const packages::zip::ZipIOException&)
+ {
+ TOOLS_WARN_EXCEPTION( "sw", "uno exception caught while importing" );
+ return ERRCODE_IO_BROKENPACKAGE;
+ }
+ catch(const io::IOException&)
+ {
+ TOOLS_WARN_EXCEPTION( "sw", "uno exception caught while importing" );
+ return ERR_SWG_READ_ERROR;
+ }
+ catch(const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sw", "uno exception caught while importing" );
+ return ERR_SWG_READ_ERROR;
+ }
+
+ // success!
+ return ERRCODE_NONE;
+}
+
+// read a component (storage version)
+ErrCodeMsg ReadThroughComponent(
+ uno::Reference<embed::XStorage> const & xStorage,
+ uno::Reference<XComponent> const & xModelComponent,
+ const char* pStreamName,
+ uno::Reference<uno::XComponentContext> const & rxContext,
+ const char* pFilterName,
+ const Sequence<Any>& rFilterArguments,
+ const OUString& rName,
+ bool bMustBeSuccessful)
+{
+ OSL_ENSURE(xStorage.is(), "Need storage!");
+ OSL_ENSURE(nullptr != pStreamName, "Please, please, give me a name!");
+
+ // open stream (and set parser input)
+ OUString sStreamName = OUString::createFromAscii(pStreamName);
+ bool bContainsStream = false;
+ try
+ {
+ bContainsStream = xStorage->isStreamElement(sStreamName);
+ }
+ catch( container::NoSuchElementException& )
+ {
+ }
+
+ if (!bContainsStream )
+ {
+ // stream name not found! return immediately with OK signal
+ return ERRCODE_NONE;
+ }
+
+ // set Base URL
+ uno::Reference< beans::XPropertySet > xInfoSet;
+ if( rFilterArguments.hasElements() )
+ rFilterArguments.getConstArray()[0] >>= xInfoSet;
+ OSL_ENSURE( xInfoSet.is(), "missing property set" );
+ if( xInfoSet.is() )
+ {
+ xInfoSet->setPropertyValue( "StreamName", Any( sStreamName ) );
+ }
+
+ try
+ {
+ // get input stream
+ uno::Reference <io::XStream> xStream = xStorage->openStreamElement( sStreamName, embed::ElementModes::READ );
+ uno::Reference <beans::XPropertySet > xProps( xStream, uno::UNO_QUERY );
+
+ Any aAny = xProps->getPropertyValue("Encrypted");
+
+ std::optional<const bool> b = o3tl::tryAccess<bool>(aAny);
+ bool bEncrypted = b.has_value() && *b;
+
+ uno::Reference <io::XInputStream> xInputStream = xStream->getInputStream();
+
+ // read from the stream
+ return ReadThroughComponent(
+ xInputStream, xModelComponent, sStreamName, rxContext,
+ pFilterName, rFilterArguments,
+ rName, bMustBeSuccessful, bEncrypted );
+ }
+ catch ( packages::WrongPasswordException& )
+ {
+ return ERRCODE_SFX_WRONGPASSWORD;
+ }
+ catch( packages::zip::ZipIOException& )
+ {
+ return ERRCODE_IO_BROKENPACKAGE;
+ }
+ catch ( uno::Exception& )
+ {
+ OSL_FAIL( "Error on import" );
+ // TODO/LATER: error handling
+ }
+
+ return ERR_SWG_READ_ERROR;
+}
+
+}
+
+// #i44177#
+static void lcl_AdjustOutlineStylesForOOo(SwDoc& _rDoc)
+{
+ // array containing the names of the default outline styles ('Heading 1',
+ // 'Heading 2', ..., 'Heading 10')
+ OUString aDefOutlStyleNames[ MAXLEVEL ];
+ {
+ OUString sStyleName;
+ for ( sal_uInt8 i = 0; i < MAXLEVEL; ++i )
+ {
+ sStyleName =
+ SwStyleNameMapper::GetProgName( RES_POOLCOLL_HEADLINE1 + i,
+ sStyleName );
+ aDefOutlStyleNames[i] = sStyleName;
+ }
+ }
+
+ // array indicating, which outline level already has a style assigned.
+ bool aOutlineLevelAssigned[ MAXLEVEL ];
+ // array of the default outline styles, which are created for the document.
+ SwTextFormatColl* aCreatedDefaultOutlineStyles[ MAXLEVEL ];
+
+ {
+ for ( sal_uInt8 i = 0; i < MAXLEVEL; ++i )
+ {
+ aOutlineLevelAssigned[ i ] = false;
+ aCreatedDefaultOutlineStyles[ i ] = nullptr;
+ }
+ }
+
+ // determine, which outline level has already a style assigned and
+ // which of the default outline styles is created.
+ const SwTextFormatColls& rColls = *(_rDoc.GetTextFormatColls());
+ for ( size_t n = 1; n < rColls.size(); ++n )
+ {
+ SwTextFormatColl* pColl = rColls[ n ];
+ if ( pColl->IsAssignedToListLevelOfOutlineStyle() )
+ {
+ aOutlineLevelAssigned[ pColl->GetAssignedOutlineStyleLevel() ] = true;
+ }
+
+ for ( sal_uInt8 i = 0; i < MAXLEVEL; ++i )
+ {
+ if ( aCreatedDefaultOutlineStyles[ i ] == nullptr &&
+ pColl->GetName() == aDefOutlStyleNames[i] )
+ {
+ aCreatedDefaultOutlineStyles[ i ] = pColl;
+ break;
+ }
+ }
+ }
+
+ // assign already created default outline style to outline level, which
+ // doesn't have a style assigned to it.
+ const SwNumRule* pOutlineRule = _rDoc.GetOutlineNumRule();
+ for ( sal_uInt8 i = 0; i < MAXLEVEL; ++i )
+ {
+ // #i73361#
+ // Do not change assignment of already created default outline style
+ // to a certain outline level.
+ if ( !aOutlineLevelAssigned[ i ] &&
+ aCreatedDefaultOutlineStyles[ i ] != nullptr &&
+ ! aCreatedDefaultOutlineStyles[ i ]->IsAssignedToListLevelOfOutlineStyle() )
+ {
+ // apply outline level at created default outline style
+ aCreatedDefaultOutlineStyles[ i ]->AssignToListLevelOfOutlineStyle(i);
+
+ // apply outline numbering rule, if none is set.
+ const SwNumRuleItem& rItem =
+ aCreatedDefaultOutlineStyles[ i ]->GetFormatAttr( RES_PARATR_NUMRULE, false );
+ if ( rItem.GetValue().isEmpty() )
+ {
+ SwNumRuleItem aItem( pOutlineRule->GetName() );
+ aCreatedDefaultOutlineStyles[ i ]->SetFormatAttr( aItem );
+ }
+ }
+ }
+}
+
+static void lcl_ConvertSdrOle2ObjsToSdrGrafObjs(SwDoc& _rDoc)
+{
+ if ( !(_rDoc.getIDocumentDrawModelAccess().GetDrawModel() &&
+ _rDoc.getIDocumentDrawModelAccess().GetDrawModel()->GetPage( 0 )) )
+ return;
+
+ const SdrPage& rSdrPage( *(_rDoc.getIDocumentDrawModelAccess().GetDrawModel()->GetPage( 0 )) );
+
+ // iterate recursive with group objects over all shapes on the draw page
+ SdrObjListIter aIter( &rSdrPage );
+ while( aIter.IsMore() )
+ {
+ SdrOle2Obj* pOle2Obj = dynamic_cast< SdrOle2Obj* >( aIter.Next() );
+ if( pOle2Obj )
+ {
+ // found an ole2 shape
+ SdrObjList* pObjList = pOle2Obj->getParentSdrObjListFromSdrObject();
+
+ // get its graphic
+ Graphic aGraphic;
+ pOle2Obj->Connect();
+ const Graphic* pGraphic = pOle2Obj->GetGraphic();
+ if( pGraphic )
+ aGraphic = *pGraphic;
+ pOle2Obj->Disconnect();
+
+ // create new graphic shape with the ole graphic and shape size
+ rtl::Reference<SdrGrafObj> pGraphicObj = new SdrGrafObj(
+ pOle2Obj->getSdrModelFromSdrObject(),
+ aGraphic,
+ pOle2Obj->GetCurrentBoundRect());
+
+ // apply layer of ole2 shape at graphic shape
+ pGraphicObj->SetLayer( pOle2Obj->GetLayer() );
+
+ // replace ole2 shape with the new graphic object and delete the ol2 shape
+ pObjList->ReplaceObject( pGraphicObj.get(), pOle2Obj->GetOrdNum() );
+ }
+ }
+}
+
+ErrCodeMsg XMLReader::Read( SwDoc &rDoc, const OUString& rBaseURL, SwPaM &rPaM, const OUString & rName )
+{
+ // needed for relative URLs, but in clipboard copy/paste there may be none
+ // and also there is the SwXMLTextBlocks special case
+ SAL_INFO_IF(rBaseURL.isEmpty(), "sw.filter", "sw::XMLReader: no base URL");
+
+ // Get service factory
+ uno::Reference< uno::XComponentContext > xContext =
+ comphelper::getProcessComponentContext();
+
+ uno::Reference<document::XGraphicStorageHandler> xGraphicStorageHandler;
+ rtl::Reference<SvXMLGraphicHelper> xGraphicHelper;
+ uno::Reference< document::XEmbeddedObjectResolver > xObjectResolver;
+ rtl::Reference<SvXMLEmbeddedObjectHelper> xObjectHelper;
+
+ // get the input stream (storage or stream)
+ uno::Reference<embed::XStorage> xStorage;
+ if( m_pMedium )
+ xStorage = m_pMedium->GetStorage();
+ else
+ xStorage = m_xStorage;
+
+ if( !xStorage.is() )
+ return ERR_SWG_READ_ERROR;
+
+ xGraphicHelper = SvXMLGraphicHelper::Create( xStorage,
+ SvXMLGraphicHelperMode::Read );
+ xGraphicStorageHandler = xGraphicHelper.get();
+ SfxObjectShell *pPersist = rDoc.GetPersist();
+ if( pPersist )
+ {
+ xObjectHelper = SvXMLEmbeddedObjectHelper::Create(
+ xStorage, *pPersist,
+ SvXMLEmbeddedObjectHelperMode::Read );
+ xObjectResolver = xObjectHelper.get();
+ }
+
+ // Get the docshell, the model, and finally the model's component
+ SwDocShell *pDocSh = rDoc.GetDocShell();
+ OSL_ENSURE( pDocSh, "XMLReader::Read: got no doc shell" );
+ if( !pDocSh )
+ return ERR_SWG_READ_ERROR;
+ uno::Reference< lang::XComponent > xModelComp = pDocSh->GetModel();
+ OSL_ENSURE( xModelComp.is(),
+ "XMLReader::Read: got no model" );
+ if( !xModelComp.is() )
+ return ERR_SWG_READ_ERROR;
+
+ // create and prepare the XPropertySet that gets passed through
+ // the components, and the XStatusIndicator that shows progress to
+ // the user.
+
+ // create XPropertySet with three properties for status indicator
+ static comphelper::PropertyMapEntry const aInfoMap[] =
+ {
+ { OUString("ProgressRange"), 0,
+ ::cppu::UnoType<sal_Int32>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0},
+ { OUString("ProgressMax"), 0,
+ ::cppu::UnoType<sal_Int32>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0},
+ { OUString("ProgressCurrent"), 0,
+ ::cppu::UnoType<sal_Int32>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0},
+ { OUString("NumberStyles"), 0,
+ cppu::UnoType<container::XNameContainer>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0},
+ { OUString("RecordChanges"), 0,
+ cppu::UnoType<bool>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("ShowChanges"), 0,
+ cppu::UnoType<bool>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("RedlineProtectionKey"), 0,
+ cppu::UnoType<Sequence<sal_Int8>>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("PrivateData"), 0,
+ cppu::UnoType<XInterface>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("BaseURI"), 0,
+ ::cppu::UnoType<OUString>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("StreamRelPath"), 0,
+ ::cppu::UnoType<OUString>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("StreamName"), 0,
+ ::cppu::UnoType<OUString>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0 },
+ // properties for insert modes
+ { OUString("StyleInsertModeFamilies"), 0,
+ cppu::UnoType<Sequence<OUString>>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("StyleInsertModeOverwrite"), 0,
+ cppu::UnoType<bool>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("TextInsertModeRange"), 0,
+ cppu::UnoType<text::XTextRange>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0},
+ { OUString("AutoTextMode"), 0,
+ cppu::UnoType<bool>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("OrganizerMode"), 0,
+ cppu::UnoType<bool>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0 },
+
+ // #i28749# - Add property, which indicates, if the
+ // shape position attributes are given in horizontal left-to-right layout.
+ // This is the case for the OpenOffice.org file format.
+ { OUString("ShapePositionInHoriL2R"), 0,
+ cppu::UnoType<bool>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0 },
+
+ { OUString("BuildId"), 0,
+ ::cppu::UnoType<OUString>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0 },
+
+ // Add property, which indicates, if a text document in OpenOffice.org
+ // file format is read.
+ // Note: Text documents read via the binary filter are also finally
+ // read using the OpenOffice.org file format. Thus, e.g. for text
+ // documents in StarOffice 5.2 binary file format this property
+ // will be true.
+ { OUString("TextDocInOOoFileFormat"), 0,
+ cppu::UnoType<bool>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("SourceStorage"), 0, cppu::UnoType<embed::XStorage>::get(),
+ css::beans::PropertyAttribute::MAYBEVOID, 0 },
+ };
+ uno::Reference< beans::XPropertySet > xInfoSet(
+ comphelper::GenericPropertySet_CreateInstance(
+ new comphelper::PropertySetInfo( aInfoMap ) ) );
+
+ // get BuildId from parent container if available
+ uno::Reference< container::XChild > xChild( xModelComp, uno::UNO_QUERY );
+ if( xChild.is() )
+ {
+ uno::Reference< beans::XPropertySet > xParentSet( xChild->getParent(), uno::UNO_QUERY );
+ if( xParentSet.is() )
+ {
+ uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xParentSet->getPropertySetInfo() );
+ static constexpr OUString sPropName(u"BuildId"_ustr );
+ if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(sPropName) )
+ {
+ xInfoSet->setPropertyValue( sPropName, xParentSet->getPropertyValue(sPropName) );
+ }
+ }
+ }
+
+ // try to get an XStatusIndicator from the Medium
+ uno::Reference<task::XStatusIndicator> xStatusIndicator;
+
+ if (pDocSh->GetMedium())
+ {
+ const SfxUnoAnyItem* pItem =
+ pDocSh->GetMedium()->GetItemSet().GetItem(SID_PROGRESS_STATUSBAR_CONTROL);
+ if (pItem)
+ {
+ pItem->GetValue() >>= xStatusIndicator;
+ }
+ }
+
+ // set progress range and start status indicator
+ sal_Int32 nProgressRange(1000000);
+ if (xStatusIndicator.is())
+ {
+ xStatusIndicator->start(SvxResId(RID_SVXSTR_DOC_LOAD), nProgressRange);
+ }
+ uno::Any aProgRange;
+ aProgRange <<= nProgressRange;
+ xInfoSet->setPropertyValue("ProgressRange", aProgRange);
+
+ Reference< container::XNameAccess > xLateInitSettings( document::NamedPropertyValues::create(xContext), UNO_QUERY_THROW );
+ beans::NamedValue aLateInitSettings( "LateInitSettings", Any( xLateInitSettings ) );
+
+ xInfoSet->setPropertyValue( "SourceStorage", Any( xStorage ) );
+
+ // prepare filter arguments, WARNING: the order is important!
+ Sequence<Any> aFilterArgs{ Any(xInfoSet),
+ Any(xStatusIndicator),
+ Any(xGraphicStorageHandler),
+ Any(xObjectResolver),
+ Any(aLateInitSettings) };
+
+ Sequence<Any> aEmptyArgs{ Any(xInfoSet),
+ Any(xStatusIndicator) };
+
+ // prepare for special modes
+ if( m_aOption.IsFormatsOnly() )
+ {
+ sal_Int32 nCount =
+ (m_aOption.IsFrameFormats() ? 1 : 0) +
+ (m_aOption.IsPageDescs() ? 1 : 0) +
+ (m_aOption.IsTextFormats() ? 2 : 0) +
+ (m_aOption.IsNumRules() ? 1 : 0);
+
+ Sequence< OUString> aFamiliesSeq( nCount );
+ OUString *pSeq = aFamiliesSeq.getArray();
+ if( m_aOption.IsFrameFormats() )
+ // SfxStyleFamily::Frame;
+ *pSeq++ = "FrameStyles";
+ if( m_aOption.IsPageDescs() )
+ // SfxStyleFamily::Page;
+ *pSeq++ = "PageStyles";
+ if( m_aOption.IsTextFormats() )
+ {
+ // (SfxStyleFamily::Char|SfxStyleFamily::Para);
+ *pSeq++ = "CharacterStyles";
+ *pSeq++ = "ParagraphStyles";
+ }
+ if( m_aOption.IsNumRules() )
+ // SfxStyleFamily::Pseudo;
+ *pSeq++ = "NumberingStyles";
+
+ xInfoSet->setPropertyValue( "StyleInsertModeFamilies",
+ Any(aFamiliesSeq) );
+
+ xInfoSet->setPropertyValue( "StyleInsertModeOverwrite", Any(!m_aOption.IsMerge()) );
+ }
+ else if( m_bInsertMode )
+ {
+ const rtl::Reference<SwXTextRange> xInsertTextRange =
+ SwXTextRange::CreateXTextRange(rDoc, *rPaM.GetPoint(), nullptr);
+ xInfoSet->setPropertyValue( "TextInsertModeRange",
+ Any(uno::Reference<text::XTextRange>(xInsertTextRange)) );
+ }
+ else
+ {
+ rPaM.GetBound().nContent.Assign(nullptr, 0);
+ rPaM.GetBound(false).nContent.Assign(nullptr, 0);
+ }
+
+ if( IsBlockMode() )
+ {
+ xInfoSet->setPropertyValue( "AutoTextMode", Any(true) );
+ }
+ if( IsOrganizerMode() )
+ {
+ xInfoSet->setPropertyValue( "OrganizerMode", Any(true) );
+ }
+
+ // Set base URI
+ // there is ambiguity which medium should be used here
+ // for now the own medium has a preference
+ SfxMedium* pMedDescrMedium = m_pMedium ? m_pMedium : pDocSh->GetMedium();
+ OSL_ENSURE( pMedDescrMedium, "There is no medium to get MediaDescriptor from!" );
+
+ xInfoSet->setPropertyValue( "BaseURI", Any( rBaseURL ) );
+
+ // TODO/LATER: separate links from usual embedded objects
+ OUString StreamPath;
+ if( SfxObjectCreateMode::EMBEDDED == rDoc.GetDocShell()->GetCreateMode() )
+ {
+ if (pMedDescrMedium)
+ {
+ const SfxStringItem* pDocHierarchItem =
+ pMedDescrMedium->GetItemSet().GetItem(SID_DOC_HIERARCHICALNAME);
+ if ( pDocHierarchItem )
+ StreamPath = pDocHierarchItem->GetValue();
+ }
+ else
+ {
+ StreamPath = "dummyObjectName";
+ }
+
+ if( !StreamPath.isEmpty() )
+ {
+ xInfoSet->setPropertyValue( "StreamRelPath", Any( StreamPath ) );
+ }
+ }
+
+ rtl::Reference<SwDoc> aHoldRef(&rDoc); // prevent deletion
+ ErrCodeMsg nRet = ERRCODE_NONE;
+
+ // save redline mode into import info property set
+ static constexpr OUString sShowChanges(u"ShowChanges"_ustr);
+ static constexpr OUString sRecordChanges(u"RecordChanges"_ustr);
+ static constexpr OUString sRedlineProtectionKey(u"RedlineProtectionKey"_ustr);
+ xInfoSet->setPropertyValue( sShowChanges,
+ Any(IDocumentRedlineAccess::IsShowChanges(rDoc.getIDocumentRedlineAccess().GetRedlineFlags())) );
+ xInfoSet->setPropertyValue( sRecordChanges,
+ Any(IDocumentRedlineAccess::IsRedlineOn(rDoc.getIDocumentRedlineAccess().GetRedlineFlags())) );
+ xInfoSet->setPropertyValue( sRedlineProtectionKey,
+ Any(rDoc.getIDocumentRedlineAccess().GetRedlinePassword()) );
+
+ // force redline mode to "none"
+ rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( RedlineFlags::NONE );
+
+ const bool bOASIS = ( SotStorage::GetVersion( xStorage ) > SOFFICE_FILEFORMAT_60 );
+ // #i28749# - set property <ShapePositionInHoriL2R>
+ {
+ const bool bShapePositionInHoriL2R = !bOASIS;
+ xInfoSet->setPropertyValue(
+ "ShapePositionInHoriL2R",
+ Any( bShapePositionInHoriL2R ) );
+ }
+ {
+ const bool bTextDocInOOoFileFormat = !bOASIS;
+ xInfoSet->setPropertyValue(
+ "TextDocInOOoFileFormat",
+ Any( bTextDocInOOoFileFormat ) );
+ }
+
+ ErrCode nWarnRDF = ERRCODE_NONE;
+ if ( !(IsOrganizerMode() || IsBlockMode() || m_aOption.IsFormatsOnly() ||
+ m_bInsertMode) )
+ {
+ // RDF metadata - must be read before styles/content
+ // N.B.: embedded documents have their own manifest.rdf!
+ try
+ {
+ const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(xModelComp,
+ uno::UNO_QUERY_THROW);
+ const uno::Reference<frame::XModel> xModel(xModelComp,
+ uno::UNO_QUERY_THROW);
+ const uno::Reference<rdf::XURI> xBaseURI( ::sfx2::createBaseURI(
+ xContext, xModel, rBaseURL, StreamPath) );
+ const uno::Reference<task::XInteractionHandler> xHandler(
+ pDocSh->GetMedium()->GetInteractionHandler() );
+ xDMA->loadMetadataFromStorage(xStorage, xBaseURI, xHandler);
+ }
+ catch (const lang::WrappedTargetException & e)
+ {
+ ucb::InteractiveAugmentedIOException iaioe;
+ if (e.TargetException >>= iaioe)
+ {
+ // import error that was not ignored by InteractionHandler!
+ nWarnRDF = ERR_SWG_READ_ERROR;
+ }
+ else
+ {
+ nWarnRDF = WARN_SWG_FEATURES_LOST; // uhh... something wrong?
+ }
+ }
+ catch (uno::Exception &)
+ {
+ nWarnRDF = WARN_SWG_FEATURES_LOST; // uhh... something went wrong?
+ }
+ }
+
+ // read storage streams
+
+ // #i103539#: always read meta.xml for generator
+ ErrCodeMsg const nWarn = ReadThroughComponent(
+ xStorage, xModelComp, "meta.xml", xContext,
+ (bOASIS ? "com.sun.star.comp.Writer.XMLOasisMetaImporter"
+ : "com.sun.star.comp.Writer.XMLMetaImporter"),
+ aEmptyArgs, rName, false );
+
+ ErrCodeMsg nWarn2 = ERRCODE_NONE;
+ if( !(IsOrganizerMode() || IsBlockMode() || m_aOption.IsFormatsOnly() ||
+ m_bInsertMode) )
+ {
+ nWarn2 = ReadThroughComponent(
+ xStorage, xModelComp, "settings.xml", xContext,
+ (bOASIS ? "com.sun.star.comp.Writer.XMLOasisSettingsImporter"
+ : "com.sun.star.comp.Writer.XMLSettingsImporter"),
+ aFilterArgs, rName, false );
+ }
+
+ nRet = ReadThroughComponent(
+ xStorage, xModelComp, "styles.xml", xContext,
+ (bOASIS ? "com.sun.star.comp.Writer.XMLOasisStylesImporter"
+ : "com.sun.star.comp.Writer.XMLStylesImporter"),
+ aFilterArgs, rName, true );
+
+ if( !nRet && !(IsOrganizerMode() || m_aOption.IsFormatsOnly()) )
+ nRet = ReadThroughComponent(
+ xStorage, xModelComp, "content.xml", xContext,
+ (bOASIS ? "com.sun.star.comp.Writer.XMLOasisContentImporter"
+ : "com.sun.star.comp.Writer.XMLContentImporter"),
+ aFilterArgs, rName, true );
+
+ if( !IsOrganizerMode() && !IsBlockMode() && !m_bInsertMode &&
+ !m_aOption.IsFormatsOnly() &&
+ // sw_redlinehide: disable layout cache for now
+ *o3tl::doAccess<bool>(xInfoSet->getPropertyValue(sShowChanges)) &&
+ // sw_fieldmarkhide: also disable if there is a fieldmark
+ rDoc.getIDocumentMarkAccess()->getFieldmarksBegin()
+ == rDoc.getIDocumentMarkAccess()->getFieldmarksEnd())
+ {
+ try
+ {
+ uno::Reference < io::XStream > xStm = xStorage->openStreamElement( "layout-cache", embed::ElementModes::READ );
+ std::unique_ptr<SvStream> pStrm2 = utl::UcbStreamHelper::CreateStream( xStm );
+ if( !pStrm2->GetError() )
+ rDoc.ReadLayoutCache( *pStrm2 );
+ }
+ catch (const uno::Exception&)
+ {
+ }
+ }
+
+ // Notify math objects
+ if( m_bInsertMode )
+ rDoc.PrtOLENotify( false );
+ else if ( rDoc.IsOLEPrtNotifyPending() )
+ rDoc.PrtOLENotify( true );
+
+ nRet = nRet ? nRet : (nWarn ? nWarn : (nWarn2 ? nWarn2 : nWarnRDF ) );
+
+ ::svx::DropUnusedNamedItems(xModelComp);
+
+ m_aOption.ResetAllFormatsOnly();
+
+ // redline password
+ Any aAny = xInfoSet->getPropertyValue( sRedlineProtectionKey );
+ Sequence<sal_Int8> aKey;
+ aAny >>= aKey;
+ rDoc.getIDocumentRedlineAccess().SetRedlinePassword( aKey );
+
+ // restore redline mode from import info property set
+ RedlineFlags nRedlineFlags = RedlineFlags::ShowInsert;
+ aAny = xInfoSet->getPropertyValue( sShowChanges );
+ if ( *o3tl::doAccess<bool>(aAny) )
+ nRedlineFlags |= RedlineFlags::ShowDelete;
+ aAny = xInfoSet->getPropertyValue( sRecordChanges );
+ if ( *o3tl::doAccess<bool>(aAny) || aKey.hasElements() )
+ nRedlineFlags |= RedlineFlags::On;
+
+ // ... restore redline mode
+ // (First set bogus mode to make sure the mode in getIDocumentRedlineAccess().SetRedlineFlags()
+ // is different from its previous mode.)
+ rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( ~nRedlineFlags );
+ // must set flags to show delete so that CompressRedlines works
+ rDoc.getIDocumentRedlineAccess().SetRedlineFlags(nRedlineFlags|RedlineFlags::ShowDelete);
+ // tdf#83260 ensure that the first call of CompressRedlines after loading
+ // the document is a no-op by calling it now
+ rDoc.getIDocumentRedlineAccess().CompressRedlines();
+ // can't set it on the layout or view shell because it doesn't exist yet
+ rDoc.GetDocumentRedlineManager().SetHideRedlines(!(nRedlineFlags & RedlineFlags::ShowDelete));
+
+ lcl_EnsureValidPam( rPaM ); // move Pam into valid content
+
+ if( xGraphicHelper )
+ xGraphicHelper->dispose();
+ xGraphicHelper.clear();
+ xGraphicStorageHandler = nullptr;
+ if( xObjectHelper )
+ xObjectHelper->dispose();
+ xObjectHelper.clear();
+ xObjectResolver = nullptr;
+ aHoldRef.clear();
+
+ if ( !bOASIS )
+ {
+ // #i44177# - assure that for documents in OpenOffice.org
+ // file format the relation between outline numbering rule and styles is
+ // filled-up accordingly.
+ // Note: The OpenOffice.org file format, which has no content that applies
+ // a certain style, which is related to the outline numbering rule,
+ // has lost the information, that this certain style is related to
+ // the outline numbering rule.
+ // #i70748# - only for templates
+ if ( m_pMedium && m_pMedium->GetFilter() &&
+ m_pMedium->GetFilter()->IsOwnTemplateFormat() )
+ {
+ lcl_AdjustOutlineStylesForOOo( rDoc );
+ }
+ // Fix #i58251#: Unfortunately is the static default different to SO7 behaviour,
+ // so we have to set a dynamic default after importing SO7
+ rDoc.SetDefault(SwFormatRowSplit(false));
+ }
+
+ rDoc.PropagateOutlineRule();
+
+ // #i62875#
+ if ( rDoc.getIDocumentSettingAccess().get(DocumentSettingId::DO_NOT_CAPTURE_DRAW_OBJS_ON_PAGE) && !docfunc::ExistsDrawObjs( rDoc ) )
+ {
+ rDoc.getIDocumentSettingAccess().set(DocumentSettingId::DO_NOT_CAPTURE_DRAW_OBJS_ON_PAGE, false);
+ }
+
+ // Convert all instances of <SdrOle2Obj> into <SdrGrafObj>, because the
+ // Writer doesn't support such objects.
+ lcl_ConvertSdrOle2ObjsToSdrGrafObjs( rDoc );
+
+ // set BuildId on XModel for later OLE object loading
+ if( xInfoSet.is() )
+ {
+ uno::Reference< beans::XPropertySet > xModelSet( xModelComp, uno::UNO_QUERY );
+ if( xModelSet.is() )
+ {
+ uno::Reference< beans::XPropertySetInfo > xModelSetInfo( xModelSet->getPropertySetInfo() );
+ static constexpr OUString sName(u"BuildId"_ustr );
+ if( xModelSetInfo.is() && xModelSetInfo->hasPropertyByName(sName) )
+ {
+ xModelSet->setPropertyValue( sName, xInfoSet->getPropertyValue(sName) );
+ }
+ }
+ }
+
+ // tdf#115815 restore annotation ranges stored in temporary bookmarks
+ rDoc.getIDocumentMarkAccess()->restoreAnnotationMarks();
+
+ if (xStatusIndicator.is())
+ {
+ xStatusIndicator->end();
+ }
+
+ rDoc.GetIStyleAccess().clearCaches(); // Clear Automatic-Style-Caches(shared_pointer!)
+ return nRet;
+}
+
+ // read the sections of the document, which is equal to the medium.
+ // returns the count of it
+size_t XMLReader::GetSectionList( SfxMedium& rMedium,
+ std::vector<OUString>& rStrings) const
+{
+ uno::Reference< uno::XComponentContext > xContext =
+ comphelper::getProcessComponentContext();
+ uno::Reference < embed::XStorage > xStg2;
+ if( ( xStg2 = rMedium.GetStorage() ).is() )
+ {
+ try
+ {
+ xml::sax::InputSource aParserInput;
+ static constexpr OUString sDocName( u"content.xml"_ustr );
+ aParserInput.sSystemId = sDocName;
+
+ uno::Reference < io::XStream > xStm = xStg2->openStreamElement( sDocName, embed::ElementModes::READ );
+ aParserInput.aInputStream = xStm->getInputStream();
+
+ // get filter
+ rtl::Reference< SwXMLSectionList > xImport = new SwXMLSectionList( xContext, rStrings );
+
+ // parse
+ xImport->parseStream( aParserInput );
+ }
+ catch( xml::sax::SAXParseException& )
+ {
+ TOOLS_WARN_EXCEPTION("sw", "");
+ // re throw ?
+ }
+ catch( xml::sax::SAXException& )
+ {
+ TOOLS_WARN_EXCEPTION("sw", "");
+ // re throw ?
+ }
+ catch( io::IOException& )
+ {
+ TOOLS_WARN_EXCEPTION("sw", "");
+ // re throw ?
+ }
+ catch( packages::WrongPasswordException& )
+ {
+ // re throw ?
+ }
+ }
+ return rStrings.size();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/wrtxml.cxx b/sw/source/filter/xml/wrtxml.cxx
new file mode 100644
index 0000000000..bfb1366566
--- /dev/null
+++ b/sw/source/filter/xml/wrtxml.cxx
@@ -0,0 +1,586 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <com/sun/star/xml/sax/Writer.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/document/XExporter.hpp>
+#include <com/sun/star/document/XFilter.hpp>
+#include <com/sun/star/frame/XModule.hpp>
+
+#include <officecfg/Office/Common.hxx>
+#include <comphelper/fileformat.h>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/genericpropertyset.hxx>
+#include <comphelper/propertysetinfo.hxx>
+#include <vcl/errinf.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <svx/xmlgrhlp.hxx>
+#include <svx/xmleohlp.hxx>
+#include <svl/stritem.hxx>
+#include <sfx2/frame.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <pam.hxx>
+#include <doc.hxx>
+#include <docfunc.hxx>
+#include <IDocumentRedlineAccess.hxx>
+#include <IDocumentMarkAccess.hxx>
+#include <IDocumentStatistics.hxx>
+#include <IDocumentLayoutAccess.hxx>
+#include <rootfrm.hxx>
+#include <docstat.hxx>
+#include <docsh.hxx>
+
+#include <xmloff/shapeexport.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <swerror.h>
+#include "wrtxml.hxx"
+#include "zorder.hxx"
+#include <strings.hrc>
+
+#include <comphelper/documentconstants.hxx>
+#include <com/sun/star/rdf/XDocumentMetadataAccess.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+
+SwXMLWriter::SwXMLWriter( const OUString& rBaseURL )
+{
+ SetBaseURL( rBaseURL );
+}
+
+SwXMLWriter::~SwXMLWriter()
+{
+}
+
+ErrCodeMsg SwXMLWriter::Write_(const SfxItemSet* pMediumItemSet)
+{
+ uno::Reference<task::XStatusIndicator> xStatusIndicator;
+ OUString aDocHierarchicalName;
+ bool bNoEmbDS(false);
+
+ if (pMediumItemSet)
+ {
+ const SfxUnoAnyItem* pStatusBarItem =
+ pMediumItemSet->GetItem(SID_PROGRESS_STATUSBAR_CONTROL);
+ if (pStatusBarItem)
+ pStatusBarItem->GetValue() >>= xStatusIndicator;
+ const SfxStringItem* pDocHierarchItem =
+ pMediumItemSet->GetItem(SID_DOC_HIERARCHICALNAME);
+ if (pDocHierarchItem)
+ aDocHierarchicalName = pDocHierarchItem->GetValue();
+ const SfxBoolItem* pNoEmbDS = pMediumItemSet->GetItem(SID_NO_EMBEDDED_DS);
+ if (pNoEmbDS)
+ bNoEmbDS = pNoEmbDS->GetValue();
+ }
+
+ // Get service factory
+ uno::Reference< uno::XComponentContext > xContext =
+ comphelper::getProcessComponentContext();
+
+ // Get data sink ...
+ uno::Reference<document::XGraphicStorageHandler> xGraphicStorageHandler;
+ rtl::Reference<SvXMLGraphicHelper> xGraphicHelper ;
+ uno::Reference< document::XEmbeddedObjectResolver > xObjectResolver;
+ rtl::Reference<SvXMLEmbeddedObjectHelper> xObjectHelper;
+
+ OSL_ENSURE( m_xStg.is(), "Where is my storage?" );
+ xGraphicHelper = SvXMLGraphicHelper::Create( m_xStg,
+ SvXMLGraphicHelperMode::Write );
+ xGraphicStorageHandler = xGraphicHelper.get();
+
+ SfxObjectShell *pPersist = m_pDoc->GetPersist();
+ if( pPersist )
+ {
+ xObjectHelper = SvXMLEmbeddedObjectHelper::Create(
+ m_xStg, *pPersist,
+ SvXMLEmbeddedObjectHelperMode::Write );
+ xObjectResolver = xObjectHelper.get();
+ }
+
+ // create and prepare the XPropertySet that gets passed through
+ // the components, and the XStatusIndicator that shows progress to
+ // the user.
+
+ // create XPropertySet with three properties for status indicator
+ static comphelper::PropertyMapEntry const aInfoMap[] =
+ {
+ { OUString("ProgressRange"), 0,
+ ::cppu::UnoType<sal_Int32>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0},
+ { OUString("ProgressMax"), 0,
+ ::cppu::UnoType<sal_Int32>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0},
+ { OUString("ProgressCurrent"), 0,
+ ::cppu::UnoType<sal_Int32>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0},
+ { OUString("WrittenNumberStyles"), 0,
+ cppu::UnoType<uno::Sequence<sal_Int32>>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0},
+ { OUString("UsePrettyPrinting"), 0,
+ cppu::UnoType<bool>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0},
+ { OUString("ShowChanges"), 0,
+ cppu::UnoType<bool>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("RedlineProtectionKey"), 0,
+ cppu::UnoType<Sequence<sal_Int8>>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("BaseURI"), 0,
+ ::cppu::UnoType<OUString>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("StreamRelPath"), 0,
+ ::cppu::UnoType<OUString>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("StreamName"), 0,
+ ::cppu::UnoType<OUString>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("AutoTextMode"), 0,
+ cppu::UnoType<bool>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("StyleNames"), 0,
+ cppu::UnoType<Sequence<OUString>>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("StyleFamilies"), 0,
+ cppu::UnoType<Sequence<sal_Int32>>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0 },
+ // #i69627#
+ { OUString("OutlineStyleAsNormalListStyle"), 0,
+ cppu::UnoType<bool>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("TargetStorage"),0, cppu::UnoType<embed::XStorage>::get(),
+ css::beans::PropertyAttribute::MAYBEVOID, 0 },
+ // tdf#144532
+ { OUString("NoEmbDataSet"), 0,
+ cppu::UnoType<bool>::get(),
+ beans::PropertyAttribute::MAYBEVOID, 0 },
+ };
+ uno::Reference< beans::XPropertySet > xInfoSet(
+ comphelper::GenericPropertySet_CreateInstance(
+ new comphelper::PropertySetInfo( aInfoMap ) ) );
+
+ xInfoSet->setPropertyValue( "TargetStorage", Any( m_xStg ) );
+
+ xInfoSet->setPropertyValue("NoEmbDataSet", Any(bNoEmbDS));
+
+ if (m_bShowProgress)
+ {
+ // set progress range and start status indicator
+ sal_Int32 nProgressRange(1000000);
+ if (xStatusIndicator.is())
+ {
+ xStatusIndicator->start(SwResId( STR_STATSTR_SWGWRITE),
+ nProgressRange);
+ }
+ xInfoSet->setPropertyValue("ProgressRange", Any(nProgressRange));
+
+ xInfoSet->setPropertyValue("ProgressMax", Any(static_cast < sal_Int32 >( -1 )));
+ }
+
+ xInfoSet->setPropertyValue( "UsePrettyPrinting", Any(officecfg::Office::Common::Save::Document::PrettyPrinting::get()) );
+
+ uno::Reference<lang::XComponent> const xModelComp(m_pDoc->GetDocShell()->GetModel());
+ uno::Reference<drawing::XDrawPageSupplier> const xDPS(xModelComp, uno::UNO_QUERY);
+ assert(xDPS.is());
+ xmloff::FixZOrder(xDPS->getDrawPage(), sw::GetZOrderLayer(m_pDoc->getIDocumentDrawModelAccess()));
+
+ // save show redline mode ...
+ RedlineFlags const nOrigRedlineFlags = m_pDoc->getIDocumentRedlineAccess().GetRedlineFlags();
+ RedlineFlags nRedlineFlags(nOrigRedlineFlags);
+ bool isShowChanges;
+ // TODO: ideally this would be stored per-view...
+ SwRootFrame const*const pLayout(m_pDoc->getIDocumentLayoutAccess().GetCurrentLayout());
+ isShowChanges = pLayout == nullptr || !pLayout->IsHideRedlines();
+ xInfoSet->setPropertyValue("ShowChanges", Any(isShowChanges));
+ // ... and hide redlines for export
+ nRedlineFlags &= ~RedlineFlags::ShowMask;
+ nRedlineFlags |= RedlineFlags::ShowInsert;
+ m_pDoc->getIDocumentRedlineAccess().SetRedlineFlags( nRedlineFlags );
+
+ // Set base URI
+ xInfoSet->setPropertyValue( "BaseURI", Any( GetBaseURL() ) );
+
+ if( SfxObjectCreateMode::EMBEDDED == m_pDoc->GetDocShell()->GetCreateMode() )
+ {
+ const OUString aName( !aDocHierarchicalName.isEmpty()
+ ? aDocHierarchicalName
+ : OUString( "dummyObjectName" ) );
+
+ xInfoSet->setPropertyValue( "StreamRelPath", Any( aName ) );
+ }
+
+ if( m_bBlock )
+ {
+ xInfoSet->setPropertyValue( "AutoTextMode", Any(true) );
+ }
+
+ // #i69627#
+ const bool bOASIS = ( SotStorage::GetVersion( m_xStg ) > SOFFICE_FILEFORMAT_60 );
+ if ( bOASIS &&
+ docfunc::HasOutlineStyleToBeWrittenAsNormalListStyle( *m_pDoc ) )
+ {
+ xInfoSet->setPropertyValue( "OutlineStyleAsNormalListStyle", Any( true ) );
+ }
+
+ // filter arguments
+ // - graphics + object resolver for styles + content
+ // - status indicator
+ // - info property set
+ // - else empty
+ sal_Int32 nArgs = 1;
+ if( xStatusIndicator.is() )
+ nArgs++;
+
+ Sequence < Any > aEmptyArgs( nArgs );
+ Any *pArgs = aEmptyArgs.getArray();
+ *pArgs++ <<= xInfoSet;
+ if( xStatusIndicator.is() )
+ *pArgs++ <<= xStatusIndicator;
+
+ if( xGraphicStorageHandler.is() )
+ nArgs++;
+ if( xObjectResolver.is() )
+ nArgs++;
+
+ Sequence < Any > aFilterArgs( nArgs );
+ pArgs = aFilterArgs.getArray();
+ *pArgs++ <<= xInfoSet;
+ if( xGraphicStorageHandler.is() )
+ *pArgs++ <<= xGraphicStorageHandler;
+ if( xObjectResolver.is() )
+ *pArgs++ <<= xObjectResolver;
+ if( xStatusIndicator.is() )
+ *pArgs++ <<= xStatusIndicator;
+
+ PutNumFormatFontsInAttrPool();
+ PutEditEngFontsInAttrPool();
+
+ // properties
+ Sequence < PropertyValue > aProps( m_pOrigFileName ? 1 : 0 );
+ if( m_pOrigFileName )
+ {
+ PropertyValue *pProps = aProps.getArray();
+ pProps->Name = "FileName";
+ pProps->Value <<= *m_pOrigFileName;
+ }
+
+ // export sub streams for package, else full stream into a file
+ bool bWarn = false;
+
+ // RDF metadata: export if ODF >= 1.2
+ // N.B.: embedded documents have their own manifest.rdf!
+ if ( bOASIS )
+ {
+ const uno::Reference<beans::XPropertySet> xPropSet(m_xStg,
+ uno::UNO_QUERY_THROW);
+ try
+ {
+ OUString Version;
+ // ODF >= 1.2
+ if ((xPropSet->getPropertyValue("Version") >>= Version)
+ && Version != ODFVER_010_TEXT
+ && Version != ODFVER_011_TEXT)
+ {
+ const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(
+ xModelComp, uno::UNO_QUERY_THROW);
+ xDMA->storeMetadataToStorage(m_xStg);
+ }
+ }
+ catch (beans::UnknownPropertyException &)
+ { /* ignore */ }
+ catch (uno::Exception &)
+ {
+ bWarn = true;
+ }
+ }
+
+ bool bStoreMeta = ( SfxObjectCreateMode::EMBEDDED != m_pDoc->GetDocShell()->GetCreateMode() );
+ if ( !bStoreMeta )
+ {
+ try
+ {
+ Reference< frame::XModule > xModule( xModelComp, UNO_QUERY );
+ if ( xModule.is() )
+ {
+ const OUString aModuleID = xModule->getIdentifier();
+ bStoreMeta = !aModuleID.isEmpty() &&
+ ( aModuleID == "com.sun.star.sdb.FormDesign" ||
+ aModuleID == "com.sun.star.sdb.TextReportDesign" );
+ }
+ }
+ catch( uno::Exception& )
+ {}
+ }
+
+ OUString sWarnFile;
+ if( !m_bOrganizerMode && !m_bBlock && bStoreMeta )
+ {
+ if( !WriteThroughComponent(
+ xModelComp, "meta.xml", xContext,
+ (bOASIS ? "com.sun.star.comp.Writer.XMLOasisMetaExporter"
+ : "com.sun.star.comp.Writer.XMLMetaExporter"),
+ aEmptyArgs, aProps ) )
+ {
+ bWarn = true;
+ sWarnFile = "meta.xml";
+ }
+ }
+
+ if( !m_bBlock )
+ {
+ if( !WriteThroughComponent(
+ xModelComp, "settings.xml", xContext,
+ (bOASIS ? "com.sun.star.comp.Writer.XMLOasisSettingsExporter"
+ : "com.sun.star.comp.Writer.XMLSettingsExporter"),
+ aEmptyArgs, aProps ) )
+ {
+ if( !bWarn )
+ {
+ bWarn = true;
+ sWarnFile = "settings.xml";
+ }
+ }
+ }
+
+ bool bErr = false;
+
+ OUString sErrFile;
+ if( !WriteThroughComponent(
+ xModelComp, "styles.xml", xContext,
+ (bOASIS ? "com.sun.star.comp.Writer.XMLOasisStylesExporter"
+ : "com.sun.star.comp.Writer.XMLStylesExporter"),
+ aFilterArgs, aProps ) )
+ {
+ bErr = true;
+ sErrFile = "styles.xml";
+ }
+
+ if( !m_bOrganizerMode && !bErr )
+ {
+ if( !WriteThroughComponent(
+ xModelComp, "content.xml", xContext,
+ (bOASIS ? "com.sun.star.comp.Writer.XMLOasisContentExporter"
+ : "com.sun.star.comp.Writer.XMLContentExporter"),
+ aFilterArgs, aProps ) )
+ {
+ bErr = true;
+ sErrFile = "content.xml";
+ }
+ }
+
+ if( m_pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() && m_pDoc->getIDocumentStatistics().GetDocStat().nPage > 1 &&
+ !(m_bOrganizerMode || m_bBlock || bErr ||
+ // sw_redlinehide: disable layout cache for now
+ m_pDoc->getIDocumentLayoutAccess().GetCurrentLayout()->HasMergedParas()))
+ {
+ try
+ {
+ uno::Reference < io::XStream > xStm = m_xStg->openStreamElement( "layout-cache", embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
+ std::unique_ptr<SvStream> pStream = utl::UcbStreamHelper::CreateStream( xStm );
+ if( !pStream->GetError() )
+ {
+ uno::Reference < beans::XPropertySet > xSet( xStm, UNO_QUERY );
+ uno::Any aAny2;
+ aAny2 <<= OUString("application/binary");
+ xSet->setPropertyValue("MediaType", aAny2 );
+ m_pDoc->WriteLayoutCache( *pStream );
+ }
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ }
+
+ if( xGraphicHelper )
+ xGraphicHelper->dispose();
+ xGraphicHelper.clear();
+ xGraphicStorageHandler = nullptr;
+
+ if( xObjectHelper )
+ xObjectHelper->dispose();
+ xObjectHelper.clear();
+ xObjectResolver = nullptr;
+
+ // restore redline mode
+ nRedlineFlags = m_pDoc->getIDocumentRedlineAccess().GetRedlineFlags();
+ nRedlineFlags &= ~RedlineFlags::ShowMask;
+ nRedlineFlags |= RedlineFlags::ShowInsert;
+ nRedlineFlags |= nOrigRedlineFlags & RedlineFlags::ShowMask;
+ m_pDoc->getIDocumentRedlineAccess().SetRedlineFlags( nRedlineFlags );
+
+ // tdf#115815 restore annotation ranges collapsed by hide redlines
+ m_pDoc->getIDocumentMarkAccess()->restoreAnnotationMarks();
+
+ if (xStatusIndicator.is())
+ {
+ xStatusIndicator->end();
+ }
+
+ if( bErr )
+ {
+ if( !sErrFile.isEmpty() )
+ return ErrCodeMsg( ERR_WRITE_ERROR_FILE, sErrFile,
+ DialogMask::ButtonsOk | DialogMask::MessageError );
+ return ERR_SWG_WRITE_ERROR;
+ }
+ else if( bWarn )
+ {
+ if( !sWarnFile.isEmpty() )
+ return ErrCodeMsg( WARN_WRITE_ERROR_FILE, sWarnFile,
+ DialogMask::ButtonsOk | DialogMask::MessageError );
+ return WARN_SWG_FEATURES_LOST;
+ }
+
+ return ERRCODE_NONE;
+}
+
+ErrCodeMsg SwXMLWriter::WriteStorage()
+{
+ return Write_(nullptr);
+}
+
+ErrCodeMsg SwXMLWriter::WriteMedium( SfxMedium& aTargetMedium )
+{
+ return Write_(&aTargetMedium.GetItemSet());
+}
+
+ErrCodeMsg SwXMLWriter::Write( SwPaM& rPaM, SfxMedium& rMed,
+ const OUString* pFileName )
+{
+ return IsStgWriter()
+ ? static_cast<StgWriter *>(this)->Write( rPaM, rMed.GetOutputStorage(), pFileName, &rMed )
+ : static_cast<Writer *>(this)->Write( rPaM, *rMed.GetOutStream(), pFileName );
+}
+
+bool SwXMLWriter::WriteThroughComponent(
+ const uno::Reference<XComponent> & xComponent,
+ const char* pStreamName,
+ const uno::Reference<uno::XComponentContext> & rxContext,
+ const char* pServiceName,
+ const Sequence<Any> & rArguments,
+ const Sequence<beans::PropertyValue> & rMediaDesc )
+{
+ OSL_ENSURE( m_xStg.is(), "Need storage!" );
+ OSL_ENSURE( nullptr != pStreamName, "Need stream name!" );
+ OSL_ENSURE( nullptr != pServiceName, "Need service name!" );
+
+ SAL_INFO( "sw.filter", "SwXMLWriter::WriteThroughComponent : stream " << pStreamName );
+ // open stream
+ bool bRet = false;
+ try
+ {
+ const OUString sStreamName = OUString::createFromAscii( pStreamName );
+ uno::Reference<io::XStream> xStream =
+ m_xStg->openStreamElement( sStreamName,
+ embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
+
+ uno::Reference <beans::XPropertySet > xSet( xStream, uno::UNO_QUERY );
+ if( !xSet.is() )
+ return false;
+
+ xSet->setPropertyValue("MediaType", Any(OUString("text/xml")) );
+
+ // even plain stream should be encrypted in encrypted documents
+ xSet->setPropertyValue( "UseCommonStoragePasswordEncryption", Any(true) );
+
+ // set buffer and create outputstream
+ uno::Reference< io::XOutputStream > xOutputStream = xStream->getOutputStream();
+
+ // set Base URL
+ uno::Reference< beans::XPropertySet > xInfoSet;
+ if( rArguments.hasElements() )
+ rArguments.getConstArray()[0] >>= xInfoSet;
+ OSL_ENSURE( xInfoSet.is(), "missing property set" );
+ if( xInfoSet.is() )
+ {
+ xInfoSet->setPropertyValue( "StreamName", Any( sStreamName ) );
+ }
+
+ // write the stuff
+ bRet = WriteThroughComponent(
+ xOutputStream, xComponent, rxContext,
+ pServiceName, rArguments, rMediaDesc );
+ }
+ catch ( uno::Exception& )
+ {
+ }
+
+ return bRet;
+
+}
+
+bool SwXMLWriter::WriteThroughComponent(
+ const uno::Reference<io::XOutputStream> & xOutputStream,
+ const uno::Reference<XComponent> & xComponent,
+ const uno::Reference<XComponentContext> & rxContext,
+ const char* pServiceName,
+ const Sequence<Any> & rArguments,
+ const Sequence<PropertyValue> & rMediaDesc )
+{
+ OSL_ENSURE( xOutputStream.is(), "I really need an output stream!" );
+ OSL_ENSURE( xComponent.is(), "Need component!" );
+ OSL_ENSURE( nullptr != pServiceName, "Need component name!" );
+
+ // get component
+ uno::Reference< xml::sax::XWriter > xSaxWriter = xml::sax::Writer::create(rxContext);
+ SAL_INFO( "sw.filter", "SAX-Writer created" );
+ // connect XML writer to output stream
+ xSaxWriter->setOutputStream( xOutputStream );
+
+ // prepare arguments (prepend doc handler to given arguments)
+ Sequence<Any> aArgs( 1 + rArguments.getLength() );
+ auto pArgs = aArgs.getArray();
+ *pArgs <<= xSaxWriter;
+ std::copy(rArguments.begin(), rArguments.end(), std::next(pArgs));
+
+ // get filter component
+ uno::Reference< document::XExporter > xExporter(
+ rxContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+ OUString::createFromAscii(pServiceName), aArgs, rxContext), UNO_QUERY);
+ OSL_ENSURE( xExporter.is(),
+ "can't instantiate export filter component" );
+ if( !xExporter.is() )
+ return false;
+ SAL_INFO( "sw.filter", pServiceName << " instantiated." );
+ // connect model and filter
+ xExporter->setSourceDocument( xComponent );
+
+ // filter!
+ SAL_INFO( "sw.filter", "call filter()" );
+ uno::Reference<XFilter> xFilter( xExporter, UNO_QUERY );
+ return xFilter->filter( rMediaDesc );
+}
+
+void GetXMLWriter(
+ [[maybe_unused]] std::u16string_view /*rName*/, const OUString& rBaseURL, WriterRef& xRet )
+{
+ xRet = new SwXMLWriter( rBaseURL );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/wrtxml.hxx b/sw/source/filter/xml/wrtxml.hxx
new file mode 100644
index 0000000000..abbdd7aa7b
--- /dev/null
+++ b/sw/source/filter/xml/wrtxml.hxx
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SW_SOURCE_FILTER_XML_WRTXML_HXX
+#define INCLUDED_SW_SOURCE_FILTER_XML_WRTXML_HXX
+
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <shellio.hxx>
+
+class SwPaM;
+class SfxMedium;
+
+namespace com::sun::star {
+ namespace uno { template<class A> class Reference; }
+ namespace uno { template<class A> class Sequence; }
+ namespace uno { class Any; }
+ namespace lang { class XComponent; }
+ namespace lang { class XMultiServiceFactory; }
+ namespace beans { struct PropertyValue; }
+}
+
+class SwXMLWriter : public StgWriter
+{
+ ErrCodeMsg Write_(const SfxItemSet* pMediumItemSet);
+
+ using StgWriter::Write;
+
+protected:
+ virtual ErrCodeMsg WriteStorage() override;
+ virtual ErrCodeMsg WriteMedium( SfxMedium& aTargetMedium ) override;
+
+public:
+
+ SwXMLWriter( const OUString& rBaseURL );
+ virtual ~SwXMLWriter() override;
+
+ virtual ErrCodeMsg Write( SwPaM&, SfxMedium&, const OUString* ) override;
+
+private:
+
+ // helper methods to write XML streams
+
+ // write a single XML stream into the package
+ bool WriteThroughComponent(
+ // the component we export
+ const css::uno::Reference<css::lang::XComponent> & xComponent,
+ const char* pStreamName, // the stream name
+ // service factory for pServiceName
+ const css::uno::Reference<css::uno::XComponentContext> & rFactory,
+ const char* pServiceName, // service name of the component
+ // the argument (XInitialization)
+ const css::uno::Sequence<css::uno::Any> & rArguments,
+ // output descriptor
+ const css::uno::Sequence<css::beans::PropertyValue> & rMediaDesc );
+
+ // write a single output stream
+ // (to be called either directly or by WriteThroughComponent(...))
+ static bool WriteThroughComponent(
+ const css::uno::Reference<css::io::XOutputStream> & xOutputStream,
+ const css::uno::Reference<css::lang::XComponent> & xComponent,
+ const css::uno::Reference<css::uno::XComponentContext> & rFactory,
+ const char* pServiceName,
+ const css::uno::Sequence<css::uno::Any> & rArguments,
+ const css::uno::Sequence<css::beans::PropertyValue> & rMediaDesc );
+};
+
+#endif // INCLUDED_SW_SOURCE_FILTER_XML_WRTXML_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlbrsh.cxx b/sw/source/filter/xml/xmlbrsh.cxx
new file mode 100644
index 0000000000..b31dc0cfa4
--- /dev/null
+++ b/sw/source/filter/xml/xmlbrsh.cxx
@@ -0,0 +1,194 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <editeng/memberids.h>
+#include <vcl/graph.hxx>
+
+#include <sal/log.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/xmlimp.hxx>
+#include <xmloff/XMLBase64ImportContext.hxx>
+#include <editeng/brushitem.hxx>
+#include <xmloff/xmluconv.hxx>
+
+#include "xmlbrshi.hxx"
+#include "xmlbrshe.hxx"
+#include "xmlexp.hxx"
+#include "xmlimpit.hxx"
+#include "xmlexpit.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::xmloff::token;
+
+void SwXMLBrushItemImportContext::ProcessAttrs(
+ const uno::Reference< xml::sax::XFastAttributeList >& xAttrList,
+ const SvXMLUnitConverter& rUnitConv )
+{
+ for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) )
+ {
+ const OUString sValue = aIter.toString();
+
+ switch( aIter.getToken() )
+ {
+ case XML_ELEMENT(XLINK, XML_HREF):
+ m_xGraphic = GetImport().loadGraphicByURL(sValue);
+ break;
+ case XML_ELEMENT(XLINK, XML_TYPE):
+ case XML_ELEMENT(XLINK, XML_ACTUATE):
+ case XML_ELEMENT(XLINK, XML_SHOW):
+ break;
+ case XML_ELEMENT(STYLE, XML_POSITION):
+ SvXMLImportItemMapper::PutXMLValue(
+ *m_pItem, sValue, MID_GRAPHIC_POSITION, rUnitConv );
+ break;
+ case XML_ELEMENT(STYLE, XML_REPEAT):
+ SvXMLImportItemMapper::PutXMLValue(
+ *m_pItem, sValue, MID_GRAPHIC_REPEAT, rUnitConv );
+ break;
+ case XML_ELEMENT(STYLE, XML_FILTER_NAME):
+ SvXMLImportItemMapper::PutXMLValue(
+ *m_pItem, sValue, MID_GRAPHIC_FILTER, rUnitConv );
+ break;
+ default:
+ XMLOFF_WARN_UNKNOWN("sw", aIter);
+ }
+ }
+
+}
+
+css::uno::Reference< css::xml::sax::XFastContextHandler > SwXMLBrushItemImportContext::createFastChildContext(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/ )
+{
+ if ((nElement & TOKEN_MASK) == xmloff::token::XML_BINARY_DATA)
+ {
+ if (!m_xBase64Stream.is())
+ {
+ m_xBase64Stream = GetImport().GetStreamForGraphicObjectURLFromBase64();
+ if (m_xBase64Stream.is())
+ return new XMLBase64ImportContext(GetImport(), m_xBase64Stream);
+ }
+ }
+ XMLOFF_WARN_UNKNOWN_ELEMENT("sw", nElement);
+ return nullptr;
+}
+
+void SwXMLBrushItemImportContext::endFastElement(sal_Int32 )
+{
+ if (m_xBase64Stream.is())
+ {
+ m_xGraphic = GetImport().loadGraphicFromBase64(m_xBase64Stream);
+ m_xBase64Stream = nullptr;
+ }
+
+ if (m_xGraphic.is())
+ {
+ Graphic aGraphic(m_xGraphic);
+ SvxGraphicPosition eOldGraphicPos = m_pItem->GetGraphicPos();
+ m_pItem->SetGraphic(aGraphic);
+ if (GPOS_NONE == eOldGraphicPos && GPOS_NONE != m_pItem->GetGraphicPos())
+ m_pItem->SetGraphicPos(GPOS_TILED);
+ }
+
+ if (!(m_pItem->GetGraphic()))
+ m_pItem->SetGraphicPos(GPOS_NONE);
+ else if (GPOS_NONE == m_pItem->GetGraphicPos())
+ m_pItem->SetGraphicPos(GPOS_TILED);
+}
+
+SwXMLBrushItemImportContext::SwXMLBrushItemImportContext(
+ SvXMLImport& rImport, sal_Int32 /*nElement*/,
+ const uno::Reference< xml::sax::XFastAttributeList >& xAttrList,
+ const SvXMLUnitConverter& rUnitConv,
+ const SvxBrushItem& rItem ) :
+ SvXMLImportContext( rImport ),
+ m_pItem( new SvxBrushItem( rItem ) )
+{
+ // delete any graphic that is existing
+ m_pItem->SetGraphicPos( GPOS_NONE );
+
+ ProcessAttrs( xAttrList, rUnitConv );
+}
+
+SwXMLBrushItemImportContext::SwXMLBrushItemImportContext(
+ SvXMLImport& rImport, sal_Int32 /*nElement*/,
+ const uno::Reference< xml::sax::XFastAttributeList > & xAttrList,
+ const SvXMLUnitConverter& rUnitConv,
+ sal_uInt16 nWhich ) :
+ SvXMLImportContext( rImport ),
+ m_pItem( new SvxBrushItem( nWhich ) )
+{
+ ProcessAttrs( xAttrList, rUnitConv );
+}
+
+SwXMLBrushItemImportContext::~SwXMLBrushItemImportContext()
+{
+}
+
+SwXMLBrushItemExport::SwXMLBrushItemExport( SwXMLExport& rExp ) :
+ m_rExport( rExp )
+{
+}
+
+void SwXMLBrushItemExport::exportXML( const SvxBrushItem& rItem )
+{
+ GetExport().CheckAttrList();
+
+ uno::Reference<graphic::XGraphic> xGraphic;
+
+ const Graphic* pGraphic = rItem.GetGraphic();
+
+ if (pGraphic)
+ xGraphic = pGraphic->GetXGraphic();
+
+ if (xGraphic.is())
+ {
+ OUString sMimeType;
+ OUString sValue = GetExport().AddEmbeddedXGraphic(xGraphic, sMimeType);
+ if (!sValue.isEmpty())
+ {
+ GetExport().AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sValue );
+ GetExport().AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
+ GetExport().AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
+ }
+
+ const SvXMLUnitConverter& rUnitConv = GetExport().GetTwipUnitConverter();
+ if (SvXMLExportItemMapper::QueryXMLValue(rItem, sValue, MID_GRAPHIC_POSITION, rUnitConv))
+ GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_POSITION, sValue );
+
+ if (SvXMLExportItemMapper::QueryXMLValue(rItem, sValue, MID_GRAPHIC_REPEAT, rUnitConv))
+ GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_REPEAT, sValue );
+
+ if (SvXMLExportItemMapper::QueryXMLValue(rItem, sValue, MID_GRAPHIC_FILTER, rUnitConv))
+ GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_FILTER_NAME, sValue );
+ }
+
+ {
+ SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_STYLE, XML_BACKGROUND_IMAGE,
+ true, true );
+ if (xGraphic.is())
+ {
+ // optional office:binary-data
+ GetExport().AddEmbeddedXGraphicAsBase64(xGraphic);
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlbrshe.hxx b/sw/source/filter/xml/xmlbrshe.hxx
new file mode 100644
index 0000000000..0253a6f068
--- /dev/null
+++ b/sw/source/filter/xml/xmlbrshe.hxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SW_SOURCE_FILTER_XML_XMLBRSHE_HXX
+#define INCLUDED_SW_SOURCE_FILTER_XML_XMLBRSHE_HXX
+
+class SvxBrushItem;
+class SwXMLExport;
+
+class SwXMLBrushItemExport
+{
+ SwXMLExport& m_rExport;
+
+ SwXMLExport& GetExport() { return m_rExport; }
+
+public:
+ explicit SwXMLBrushItemExport(SwXMLExport& rExport);
+
+ // core API
+ void exportXML(const SvxBrushItem& rItem);
+};
+
+#endif // INCLUDED_SW_SOURCE_FILTER_XML_XMLBRSHE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlbrshi.hxx b/sw/source/filter/xml/xmlbrshi.hxx
new file mode 100644
index 0000000000..0e5cb43c84
--- /dev/null
+++ b/sw/source/filter/xml/xmlbrshi.hxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SW_SOURCE_FILTER_XML_XMLBRSHI_HXX
+#define INCLUDED_SW_SOURCE_FILTER_XML_XMLBRSHI_HXX
+
+#include <memory>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+
+#include <xmloff/xmlictxt.hxx>
+
+class SvXMLImport;
+class SvXMLUnitConverter;
+class SvxBrushItem;
+
+namespace com::sun::star {
+ namespace io { class XOutputStream; }
+}
+
+class SwXMLBrushItemImportContext : public SvXMLImportContext
+{
+private:
+ css::uno::Reference<css::io::XOutputStream> m_xBase64Stream;
+ css::uno::Reference<css::graphic::XGraphic> m_xGraphic;
+
+ std::unique_ptr<SvxBrushItem> m_pItem;
+
+ void ProcessAttrs(
+ const css::uno::Reference<css::xml::sax::XFastAttributeList > & xAttrList,
+ const SvXMLUnitConverter& rUnitConv );
+
+public:
+
+ SwXMLBrushItemImportContext(
+ SvXMLImport& rImport,
+ sal_Int32 nElement,
+ const css::uno::Reference<css::xml::sax::XFastAttributeList > & xAttrList,
+ const SvXMLUnitConverter& rUnitConv,
+ const SvxBrushItem& rItem );
+
+ SwXMLBrushItemImportContext(
+ SvXMLImport& rImport,
+ sal_Int32 nElement,
+ const css::uno::Reference<css::xml::sax::XFastAttributeList > & xAttrList,
+ const SvXMLUnitConverter& rUnitConv,
+ sal_uInt16 nWhich );
+
+ virtual ~SwXMLBrushItemImportContext() override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+
+ virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
+
+ const SvxBrushItem& GetItem() const { return *m_pItem; }
+};
+
+#endif // _XMLBRSHI_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlexp.cxx b/sw/source/filter/xml/xmlexp.cxx
new file mode 100644
index 0000000000..434eb8c073
--- /dev/null
+++ b/sw/source/filter/xml/xmlexp.cxx
@@ -0,0 +1,623 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/xforms/XFormsSupplier.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+#include <comphelper/indexedpropertyvalues.hxx>
+#include <osl/diagnose.h>
+#include <o3tl/any.hxx>
+#include <sax/tools/converter.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/xmleohlp.hxx>
+#include <svx/xmlgrhlp.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/svddef.hxx>
+#include <tools/UnitConversion.hxx>
+#include <xmloff/namespacemap.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <editeng/xmlcnitm.hxx>
+#include <xmloff/ProgressBarHelper.hxx>
+#include <xmloff/xmluconv.hxx>
+#include <xmloff/xformsexport.hxx>
+#include <drawdoc.hxx>
+#include <doc.hxx>
+#include <swmodule.hxx>
+#include <docsh.hxx>
+#include <viewsh.hxx>
+#include <rootfrm.hxx>
+#include <docstat.hxx>
+#include <swerror.h>
+#include <unotext.hxx>
+#include "xmltexte.hxx"
+#include "xmlexp.hxx"
+#include "xmlexpit.hxx"
+#include "zorder.hxx"
+#include <comphelper/processfactory.hxx>
+#include <docary.hxx>
+#include <frameformats.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <vcl/svapp.hxx>
+#include <IDocumentSettingAccess.hxx>
+#include <IDocumentDrawModelAccess.hxx>
+#include <IDocumentRedlineAccess.hxx>
+#include <IDocumentStatistics.hxx>
+#include <IDocumentLayoutAccess.hxx>
+
+
+#include <pausethreadstarting.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::xml::sax;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::i18n;
+using namespace ::com::sun::star::xforms;
+using namespace ::xmloff::token;
+
+SwXMLExport::SwXMLExport(
+ const uno::Reference< uno::XComponentContext >& rContext,
+ OUString const & implementationName, SvXMLExportFlags nExportFlags)
+: SvXMLExport( rContext, implementationName, util::MeasureUnit::INCH, XML_TEXT,
+ nExportFlags ),
+ m_bBlock( false ),
+ m_bShowProgress( true ),
+ m_bSavedShowChanges( false ),
+ m_pDoc( nullptr )
+{
+ InitItemExport();
+}
+
+ErrCode SwXMLExport::exportDoc( enum XMLTokenEnum eClass )
+{
+ if( !GetModel().is() )
+ return ERR_SWG_WRITE_ERROR;
+
+ SwPauseThreadStarting aPauseThreadStarting; // #i73788#
+
+ // from here, we use core interfaces -> lock Solar-Mutex
+ SolarMutexGuard aGuard;
+
+ {
+ Reference<XPropertySet> rInfoSet = getExportInfo();
+ if( rInfoSet.is() )
+ {
+ static constexpr OUString sAutoTextMode(u"AutoTextMode"_ustr);
+ if( rInfoSet->getPropertySetInfo()->hasPropertyByName(
+ sAutoTextMode ) )
+ {
+ Any aAny = rInfoSet->getPropertyValue(sAutoTextMode);
+ if( auto b = o3tl::tryAccess<bool>(aAny) )
+ {
+ if( *b )
+ m_bBlock = true;
+ }
+ }
+ }
+ }
+
+ SwDoc *pDoc = getDoc();
+ if (!pDoc)
+ return ERR_SWG_WRITE_ERROR;
+
+ if( getExportFlags() & (SvXMLExportFlags::FONTDECLS|SvXMLExportFlags::STYLES|
+ SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::CONTENT))
+ {
+ if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
+ {
+ GetNamespaceMap_().Add(
+ GetXMLToken(XML_NP_OFFICE_EXT),
+ GetXMLToken(XML_N_OFFICE_EXT),
+ XML_NAMESPACE_OFFICE_EXT);
+ }
+
+ GetTextParagraphExport()->SetBlockMode( m_bBlock );
+
+ const SfxItemPool& rPool = pDoc->GetAttrPool();
+ sal_uInt16 aWhichIds[5] = { RES_UNKNOWNATR_CONTAINER,
+ RES_TXTATR_UNKNOWN_CONTAINER,
+ SDRATTR_XMLATTRIBUTES,
+ EE_PARA_XMLATTRIBS,
+ EE_CHAR_XMLATTRIBS };
+
+ const int nWhichIds = rPool.GetSecondaryPool() ? 5 : 2;
+ for( int j=0; j < nWhichIds; ++j )
+ {
+ const sal_uInt16 nWhichId = aWhichIds[j];
+ for (const SfxPoolItem* pItem : rPool.GetItemSurrogates(nWhichId))
+ {
+ auto pUnknown = dynamic_cast<const SvXMLAttrContainerItem*>( pItem );
+ OSL_ENSURE( pUnknown, "illegal attribute container item" );
+ if( pUnknown && (pUnknown->GetAttrCount() > 0) )
+ {
+ sal_uInt16 nIdx = pUnknown->GetFirstNamespaceIndex();
+ while( USHRT_MAX != nIdx )
+ {
+ GetNamespaceMap_().Add( pUnknown->GetPrefix( nIdx ),
+ pUnknown->GetNamespace( nIdx ) );
+ nIdx = pUnknown->GetNextNamespaceIndex( nIdx );
+ }
+ }
+ }
+ }
+ }
+
+ sal_uInt16 const eUnit = SvXMLUnitConverter::GetMeasureUnit(
+ SW_MOD()->GetMetric(pDoc->getIDocumentSettingAccess().get(DocumentSettingId::HTML_MODE)));
+ if (GetMM100UnitConverter().GetXMLMeasureUnit() != eUnit )
+ {
+ GetMM100UnitConverter().SetXMLMeasureUnit( eUnit );
+ m_pTwipUnitConverter->SetXMLMeasureUnit( eUnit );
+ }
+
+ if( getExportFlags() & SvXMLExportFlags::META)
+ {
+ // Update doc stat, so that correct values are exported and
+ // the progress works correctly.
+ pDoc->getIDocumentStatistics().UpdateDocStat( false, true );
+ }
+ if( m_bShowProgress )
+ {
+ ProgressBarHelper *pProgress = GetProgressBarHelper();
+ if( -1 == pProgress->GetReference() )
+ {
+ // progress isn't initialized:
+ // We assume that the whole doc is exported, and the following
+ // durations:
+ // - meta information: 2
+ // - settings: 4 (TODO: not now!)
+ // - styles (except page styles): 2
+ // - page styles: 2 (TODO: not now!) + 2 for each paragraph
+ // - paragraph: 2 (1 for automatic styles and one for content)
+
+ // count each item once, and then multiply by two to reach the
+ // figures given above
+ // The styles in pDoc also count the default style that never
+ // gets exported -> subtract one.
+ sal_Int32 nRef = 1; // meta.xml
+ nRef += pDoc->GetCharFormats()->size() - 1;
+ nRef += pDoc->GetFrameFormats()->size() - 1;
+ nRef += pDoc->GetTextFormatColls()->size() - 1;
+ nRef *= 2; // for the above styles, xmloff will increment by 2!
+ // #i93174#: count all paragraphs for the progress bar
+ nRef += pDoc->getIDocumentStatistics().GetUpdatedDocStat( false, true ).nAllPara; // 1: only content, no autostyle
+ pProgress->SetReference( nRef );
+ pProgress->SetValue( 0 );
+ }
+ }
+
+ if( getExportFlags() & (SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::CONTENT))
+ {
+ //We depend on the correctness of OrdNums.
+ SwDrawModel* pModel = pDoc->getIDocumentDrawModelAccess().GetDrawModel();
+ if( pModel )
+ pModel->GetPage( 0 )->RecalcObjOrdNums();
+ }
+
+ // adjust document class (eClass)
+ if (pDoc->getIDocumentSettingAccess().get(DocumentSettingId::GLOBAL_DOCUMENT))
+ {
+ eClass = XML_TEXT_GLOBAL;
+
+ // additionally, we take care of the save-linked-sections-thingy
+ mbSaveLinkedSections = pDoc->getIDocumentSettingAccess().get(DocumentSettingId::GLOBAL_DOCUMENT_SAVE_LINKS);
+ }
+ // MIB: 03/26/04: The Label information is saved in the settings, so
+ // we don't need it here.
+ // else: keep default pClass that we received
+
+ rtl::Reference<SvXMLGraphicHelper> xGraphicStorageHandler;
+ if (!GetGraphicStorageHandler().is())
+ {
+ xGraphicStorageHandler = SvXMLGraphicHelper::Create(SvXMLGraphicHelperMode::Write, GetImageFilterName());
+ SetGraphicStorageHandler(xGraphicStorageHandler);
+ }
+
+ rtl::Reference<SvXMLEmbeddedObjectHelper> xEmbeddedResolver;
+ if( !GetEmbeddedResolver().is() )
+ {
+ SfxObjectShell *pPersist = pDoc->GetPersist();
+ if( pPersist )
+ {
+ xEmbeddedResolver = SvXMLEmbeddedObjectHelper::Create(
+ *pPersist,
+ SvXMLEmbeddedObjectHelperMode::Write );
+ SetEmbeddedResolver( xEmbeddedResolver );
+ }
+ }
+
+ // set redline mode if we export STYLES or CONTENT, unless redline
+ // mode is taken care of outside (through info XPropertySet)
+ bool bSaveRedline =
+ bool( getExportFlags() & (SvXMLExportFlags::CONTENT|SvXMLExportFlags::STYLES) );
+ if( bSaveRedline )
+ {
+ // if the info property set has a ShowChanges property,
+ // then change tracking is taken care of on the outside,
+ // so we don't have to!
+ Reference<XPropertySet> rInfoSet = getExportInfo();
+ if( rInfoSet.is() )
+ {
+ bSaveRedline = ! rInfoSet->getPropertySetInfo()->hasPropertyByName(
+ "ShowChanges" );
+ }
+ }
+ RedlineFlags nRedlineFlags = RedlineFlags::NONE;
+ SwRootFrame const*const pLayout(m_pDoc->getIDocumentLayoutAccess().GetCurrentLayout());
+ m_bSavedShowChanges = pLayout == nullptr || !pLayout->IsHideRedlines();
+ if( bSaveRedline )
+ {
+ // tdf#133487 call this once in flat-ODF case
+ uno::Reference<drawing::XDrawPageSupplier> const xDPS(GetModel(), uno::UNO_QUERY);
+ assert(xDPS.is());
+ xmloff::FixZOrder(xDPS->getDrawPage(), sw::GetZOrderLayer(m_pDoc->getIDocumentDrawModelAccess()));
+
+ // now save and switch redline mode
+ nRedlineFlags = pDoc->getIDocumentRedlineAccess().GetRedlineFlags();
+ pDoc->getIDocumentRedlineAccess().SetRedlineFlags(
+ ( nRedlineFlags & RedlineFlags::ShowMask ) | RedlineFlags::ShowInsert );
+ }
+
+ ErrCode nRet = SvXMLExport::exportDoc( eClass );
+
+ // now we can restore the redline mode (if we changed it previously)
+ if( bSaveRedline )
+ {
+ pDoc->getIDocumentRedlineAccess().SetRedlineFlags( nRedlineFlags );
+ }
+
+ if (xGraphicStorageHandler)
+ xGraphicStorageHandler->dispose();
+ xGraphicStorageHandler.clear();
+ if( xEmbeddedResolver )
+ xEmbeddedResolver->dispose();
+ xEmbeddedResolver.clear();
+
+ OSL_ENSURE( !m_pTableLines, "there are table columns infos left" );
+
+ return nRet;
+}
+
+XMLTextParagraphExport* SwXMLExport::CreateTextParagraphExport()
+{
+ return new SwXMLTextParagraphExport(*this, *GetAutoStylePool());
+}
+
+XMLShapeExport* SwXMLExport::CreateShapeExport()
+{
+ XMLShapeExport* pShapeExport = new XMLShapeExport( *this, XMLTextParagraphExport::CreateShapeExtPropMapper( *this ) );
+ Reference < XDrawPageSupplier > xDPS( GetModel(), UNO_QUERY );
+ if( xDPS.is() )
+ {
+ Reference < XShapes > xShapes = xDPS->getDrawPage();
+ pShapeExport->seekShapes( xShapes );
+ }
+
+ return pShapeExport;
+}
+
+SwXMLExport::~SwXMLExport()
+{
+ DeleteTableLines();
+ FinitItemExport();
+}
+
+void SwXMLExport::ExportFontDecls_()
+{
+ GetFontAutoStylePool(); // make sure the pool is created
+ SvXMLExport::ExportFontDecls_();
+}
+
+void SwXMLExport::GetViewSettings(Sequence<PropertyValue>& aProps)
+{
+ aProps.realloc(7);
+ // Currently exporting 9 properties
+ PropertyValue *pValue = aProps.getArray();
+
+ rtl::Reference< comphelper::IndexedPropertyValuesContainer > xBox = new comphelper::IndexedPropertyValuesContainer();
+ pValue[0].Name = "Views";
+ pValue[0].Value <<= uno::Reference< container::XIndexContainer >(xBox);
+
+ SwDoc *pDoc = getDoc();
+ const tools::Rectangle rRect =
+ pDoc->GetDocShell()->GetVisArea( ASPECT_CONTENT );
+ bool bTwip = pDoc->GetDocShell()->GetMapUnit ( ) == MapUnit::MapTwip;
+
+ OSL_ENSURE( bTwip, "Map unit for visible area is not in TWIPS!" );
+
+ pValue[1].Name = "ViewAreaTop";
+ pValue[1].Value <<= bTwip ? convertTwipToMm100 ( rRect.Top() ) : rRect.Top();
+
+ pValue[2].Name = "ViewAreaLeft";
+ pValue[2].Value <<= bTwip ? convertTwipToMm100 ( rRect.Left() ) : rRect.Left();
+
+ pValue[3].Name = "ViewAreaWidth";
+ pValue[3].Value <<= bTwip ? convertTwipToMm100 ( rRect.GetWidth() ) : rRect.GetWidth();
+
+ pValue[4].Name = "ViewAreaHeight";
+ pValue[4].Value <<= bTwip ? convertTwipToMm100 ( rRect.GetHeight() ) : rRect.GetHeight();
+
+ // "show redline mode" cannot simply be read from the document
+ // since it gets changed during execution. If it's in the info
+ // XPropertySet, we take it from there.
+ bool bShowRedlineChanges = m_bSavedShowChanges;
+ Reference<XPropertySet> xInfoSet( getExportInfo() );
+ if ( xInfoSet.is() )
+ {
+ static constexpr OUString sShowChanges( u"ShowChanges"_ustr );
+ if( xInfoSet->getPropertySetInfo()->hasPropertyByName( sShowChanges ) )
+ {
+ bShowRedlineChanges = *o3tl::doAccess<bool>(xInfoSet->
+ getPropertyValue( sShowChanges ));
+ }
+ }
+
+ pValue[5].Name = "ShowRedlineChanges";
+ pValue[5].Value <<= bShowRedlineChanges;
+
+ pValue[6].Name = "InBrowseMode";
+ pValue[6].Value <<= pDoc->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE);
+}
+
+void SwXMLExport::GetConfigurationSettings( Sequence < PropertyValue >& rProps)
+{
+ Reference< XMultiServiceFactory > xFac( GetModel(), UNO_QUERY );
+ if (!xFac.is())
+ return;
+
+ Reference< XPropertySet > xProps( xFac->createInstance("com.sun.star.document.Settings"), UNO_QUERY );
+ if (!xProps.is())
+ return;
+
+ static const std::initializer_list<std::u16string_view> vOmitFalseValues = {
+ u"DoNotBreakWrappedTables",
+ u"AllowTextAfterFloatingTableBreak",
+ };
+ SvXMLUnitConverter::convertPropertySet( rProps, xProps, &vOmitFalseValues );
+
+ // tdf#144532 if NoEmbDataSet was set, to indicate not to write an embedded
+ // database for the case of a temporary mail merge preview document, then
+ // also filter out the "EmbeddedDatabaseName" property from the document
+ // settings so that when the temp mailmerge preview document is closed it
+ // doesn't unregister the database of the same name which was registered by
+ // the document this is a copy of
+ Reference<XPropertySet> rInfoSet = getExportInfo();
+
+ if (!rInfoSet.is() || !rInfoSet->getPropertySetInfo()->hasPropertyByName(u"NoEmbDataSet"_ustr))
+ return;
+
+ Any aAny = rInfoSet->getPropertyValue(u"NoEmbDataSet"_ustr);
+ bool bNoEmbDataSet = *o3tl::doAccess<bool>(aAny);
+ if (!bNoEmbDataSet)
+ return;
+
+ Sequence<PropertyValue> aFilteredProps(rProps.getLength());
+ auto aFilteredPropsRange = asNonConstRange(aFilteredProps);
+ sal_Int32 nFilteredPropLen = 0;
+ for (sal_Int32 i = 0; i < rProps.getLength(); ++i)
+ {
+ if (rProps[i].Name == "EmbeddedDatabaseName")
+ continue;
+ aFilteredPropsRange[nFilteredPropLen] = rProps[i];
+ ++nFilteredPropLen;
+ }
+ aFilteredProps.realloc(nFilteredPropLen);
+ std::swap(rProps, aFilteredProps);
+}
+
+sal_Int32 SwXMLExport::GetDocumentSpecificSettings( std::vector< SettingsGroup >& _out_rSettings )
+{
+ // the only doc-specific settings group we know so far are the XForms settings
+ uno::Sequence<beans::PropertyValue> aXFormsSettings;
+ Reference< XFormsSupplier > xXFormsSupp( GetModel(), UNO_QUERY );
+ Reference< XNameAccess > xXForms;
+ if ( xXFormsSupp.is() )
+ xXForms = xXFormsSupp->getXForms().get();
+ if ( xXForms.is() )
+ {
+ getXFormsSettings( xXForms, aXFormsSettings );
+ _out_rSettings.emplace_back( XML_XFORM_MODEL_SETTINGS, aXFormsSettings );
+ }
+
+ return aXFormsSettings.getLength() + SvXMLExport::GetDocumentSpecificSettings( _out_rSettings );
+}
+
+void SwXMLExport::SetBodyAttributes()
+{
+ // export use of soft page breaks
+ SwDoc *pDoc = getDoc();
+ if( pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() &&
+ pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->GetPageCount() > 1 )
+ {
+ OUStringBuffer sBuffer;
+ ::sax::Converter::convertBool(sBuffer, true);
+ AddAttribute(XML_NAMESPACE_TEXT, XML_USE_SOFT_PAGE_BREAKS,
+ sBuffer.makeStringAndClear());
+ }
+}
+
+void SwXMLExport::ExportContent_()
+{
+ // export forms
+ Reference<XDrawPageSupplier> xDrawPageSupplier(GetModel(), UNO_QUERY);
+ if (xDrawPageSupplier.is())
+ {
+ // export only if we actually have elements
+ Reference<XDrawPage> xPage = xDrawPageSupplier->getDrawPage();
+ if (xPage.is())
+ {
+ // prevent export of form controls which are embedded in mute sections
+ GetTextParagraphExport()->PreventExportOfControlsInMuteSections(
+ xPage, GetFormExport() );
+
+ // #i36597#
+ if ( xmloff::OFormLayerXMLExport::pageContainsForms( xPage ) || GetFormExport()->documentContainsXForms() )
+ {
+ ::xmloff::OOfficeFormsExport aOfficeForms(*this);
+
+ GetFormExport()->exportXForms();
+
+ GetFormExport()->seekPage(xPage);
+ GetFormExport()->exportForms(xPage);
+ }
+ }
+ }
+
+ Reference<XPropertySet> xPropSet(GetModel(), UNO_QUERY);
+ if (xPropSet.is())
+ {
+ Any aAny = xPropSet->getPropertyValue( "TwoDigitYear" );
+ aAny <<= sal_Int16(1930);
+
+ sal_Int16 nYear = 0;
+ aAny >>= nYear;
+ if (nYear != 1930 )
+ {
+ AddAttribute(XML_NAMESPACE_TABLE, XML_NULL_YEAR, OUString::number(nYear));
+ SvXMLElementExport aCalcSettings(*this, XML_NAMESPACE_TABLE, XML_CALCULATION_SETTINGS, true, true);
+ }
+ }
+
+ GetTextParagraphExport()->exportTrackedChanges( false );
+ GetTextParagraphExport()->exportTextDeclarations();
+ Reference < XTextDocument > xTextDoc( GetModel(), UNO_QUERY );
+ Reference < XText > xText = xTextDoc->getText();
+
+ GetTextParagraphExport()->exportFramesBoundToPage( m_bShowProgress );
+ GetTextParagraphExport()->exportText( xText, m_bShowProgress );
+}
+
+SwDoc* SwXMLExport::getDoc()
+{
+ if( m_pDoc != nullptr )
+ return m_pDoc;
+ Reference < XTextDocument > xTextDoc( GetModel(), UNO_QUERY );
+ if (!xTextDoc)
+ {
+ SAL_WARN("sw.filter", "Problem of mismatching filter for export.");
+ return nullptr;
+ }
+
+ Reference < XText > xText = xTextDoc->getText();
+ SwXText* pText = dynamic_cast<SwXText*>(xText.get());
+ assert( pText != nullptr );
+ m_pDoc = pText->GetDoc();
+ assert( m_pDoc != nullptr );
+ return m_pDoc;
+}
+
+const SwDoc* SwXMLExport::getDoc() const
+{
+ return const_cast< SwXMLExport* >( this )->getDoc();
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Writer_XMLExporter_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SwXMLExport(context, "com.sun.star.comp.Writer.XMLExporter",
+ SvXMLExportFlags::ALL));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Writer_XMLStylesExporter_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SwXMLExport(context, "com.sun.star.comp.Writer.XMLStylesExporter",
+ SvXMLExportFlags::STYLES | SvXMLExportFlags::MASTERSTYLES | SvXMLExportFlags::AUTOSTYLES |
+ SvXMLExportFlags::FONTDECLS));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Writer_XMLContentExporter_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SwXMLExport(context, "com.sun.star.comp.Writer.XMLContentExporter",
+ SvXMLExportFlags::SCRIPTS | SvXMLExportFlags::CONTENT | SvXMLExportFlags::AUTOSTYLES |
+ SvXMLExportFlags::FONTDECLS));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Writer_XMLMetaExporter_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SwXMLExport(context, "com.sun.star.comp.Writer.XMLMetaExporter",
+ SvXMLExportFlags::META));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Writer_XMLSettingsExporter_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SwXMLExport(context, "com.sun.star.comp.Writer.XMLSettingsExporter",
+ SvXMLExportFlags::SETTINGS));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Writer_XMLOasisExporter_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SwXMLExport(context, "com.sun.star.comp.Writer.XMLOasisExporter",
+ SvXMLExportFlags::ALL | SvXMLExportFlags::OASIS));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Writer_XMLOasisStylesExporter_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SwXMLExport(context, "com.sun.star.comp.Writer.XMLOasisStylesExporter",
+ SvXMLExportFlags::STYLES | SvXMLExportFlags::MASTERSTYLES | SvXMLExportFlags::AUTOSTYLES |
+ SvXMLExportFlags::FONTDECLS | SvXMLExportFlags::OASIS));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Writer_XMLOasisContentExporter_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SwXMLExport(context, "com.sun.star.comp.Writer.XMLOasisContentExporter",
+ SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::CONTENT | SvXMLExportFlags::SCRIPTS |
+ SvXMLExportFlags::FONTDECLS | SvXMLExportFlags::OASIS));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Writer_XMLOasisMetaExporter_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SwXMLExport(context, "com.sun.star.comp.Writer.XMLOasisMetaExporter",
+ SvXMLExportFlags::META | SvXMLExportFlags::OASIS));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Writer_XMLOasisSettingsExporter_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SwXMLExport(context, "com.sun.star.comp.Writer.XMLOasisSettingsExporter",
+ SvXMLExportFlags::SETTINGS | SvXMLExportFlags::OASIS));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlexp.hxx b/sw/source/filter/xml/xmlexp.hxx
new file mode 100644
index 0000000000..6e095396db
--- /dev/null
+++ b/sw/source/filter/xml/xmlexp.hxx
@@ -0,0 +1,146 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SW_SOURCE_FILTER_XML_XMLEXP_HXX
+#define INCLUDED_SW_SOURCE_FILTER_XML_XMLEXP_HXX
+
+#include <xmloff/xmlexp.hxx>
+#include "xmlitmap.hxx"
+#include <xmloff/xmltoken.hxx>
+
+#include <optional>
+#include <string_view>
+#include <vector>
+
+class SwDoc;
+class SwFormat;
+class SwFrameFormat;
+class SvXMLUnitConverter;
+class SvXMLExportItemMapper;
+class SvXMLAutoStylePoolP;
+class SwTableLine;
+class SwTableLines;
+class SwTableBox;
+class SwXMLTableColumn_Impl;
+class SwXMLTableLines_Impl;
+class SwXMLTableColumnsSortByWidth_Impl;
+class SwXMLTableFrameFormatsSort_Impl;
+class SwXMLTableInfo_Impl;
+class SwTableNode;
+class XMLPropertySetMapper;
+class SwXMLTableLines_Impl;
+
+typedef std::vector< SwXMLTableLines_Impl* > SwXMLTableLinesCache_Impl;
+
+class SwXMLExport : public SvXMLExport
+{
+ std::unique_ptr<SvXMLUnitConverter> m_pTwipUnitConverter;
+ std::unique_ptr<SvXMLExportItemMapper> m_pTableItemMapper;
+ std::unique_ptr<SwXMLTableLinesCache_Impl> m_pTableLines;
+
+ SvXMLItemMapEntriesRef m_xTableItemMap;
+ SvXMLItemMapEntriesRef m_xTableRowItemMap;
+ SvXMLItemMapEntriesRef m_xTableCellItemMap;
+
+ bool m_bBlock : 1; // export text block?
+ bool m_bShowProgress : 1;
+ bool m_bSavedShowChanges : 1;
+
+ SwDoc* m_pDoc; // cached for getDoc()
+
+ void InitItemExport();
+ void FinitItemExport();
+ void ExportTableLinesAutoStyles( const SwTableLines& rLines,
+ sal_uInt32 nAbsWidth,
+ sal_uInt32 nBaseWidth,
+ std::u16string_view rNamePrefix,
+ SwXMLTableColumnsSortByWidth_Impl& rExpCols,
+ SwXMLTableFrameFormatsSort_Impl& rExpRows,
+ SwXMLTableFrameFormatsSort_Impl& rExpCells,
+ SwXMLTableInfo_Impl& rTableInfo,
+ bool bTop=false );
+
+ void ExportFormat(const SwFormat& rFormat, enum ::xmloff::token::XMLTokenEnum eClass,
+ ::std::optional<OUString> const oStyleName);
+ void ExportTableFormat( const SwFrameFormat& rFormat, sal_uInt32 nAbsWidth );
+
+ void ExportTableColumnStyle( const SwXMLTableColumn_Impl& rCol );
+ void ExportTableBox( const SwTableBox& rBox, sal_uInt32 nColSpan, sal_uInt32 nRowSpan,
+ SwXMLTableInfo_Impl& rTableInfo );
+ void ExportTableLine( const SwTableLine& rLine,
+ const SwXMLTableLines_Impl& rLines,
+ SwXMLTableInfo_Impl& rTableInfo );
+ void ExportTableLines( const SwTableLines& rLines,
+ SwXMLTableInfo_Impl& rTableInfo,
+ sal_uInt32 nHeaderRows = 0 );
+
+ void exportTheme();
+
+ virtual void ExportMeta_() override;
+ virtual void ExportFontDecls_() override;
+ virtual void ExportStyles_( bool bUsed ) override;
+ virtual void ExportAutoStyles_() override;
+ virtual void ExportMasterStyles_() override;
+ virtual void SetBodyAttributes() override;
+ virtual void ExportContent_() override;
+ virtual void GetViewSettings(css::uno::Sequence<css::beans::PropertyValue>& aProps) override;
+ virtual void GetConfigurationSettings(css::uno::Sequence<css::beans::PropertyValue>& aProps) override;
+ virtual sal_Int32 GetDocumentSpecificSettings( std::vector< SettingsGroup >& _out_rSettings ) override;
+
+private:
+ void DeleteTableLines();
+protected:
+
+ virtual XMLTextParagraphExport* CreateTextParagraphExport() override;
+ virtual SvXMLAutoStylePoolP* CreateAutoStylePool() override;
+ virtual XMLPageExport* CreatePageExport() override;
+ virtual XMLShapeExport* CreateShapeExport() override;
+ virtual XMLFontAutoStylePool* CreateFontAutoStylePool() override;
+
+public:
+ SwXMLExport(
+ const css::uno::Reference< css::uno::XComponentContext >& rContext,
+ OUString const & implementationName, SvXMLExportFlags nExportFlags);
+
+ virtual ~SwXMLExport() override;
+
+ void collectAutoStyles() override;
+
+ virtual ErrCode exportDoc( enum ::xmloff::token::XMLTokenEnum eClass = ::xmloff::token::XML_TOKEN_INVALID ) override;
+
+ inline const SvXMLUnitConverter& GetTwipUnitConverter() const;
+
+ void ExportTableAutoStyles( const SwTableNode& rTableNd );
+ void ExportTable( const SwTableNode& rTableNd );
+
+ bool IsShowProgress() const { return m_bShowProgress; }
+ void SetShowProgress( bool b ) { m_bShowProgress = b; }
+
+ const SwDoc* getDoc() const;
+ SwDoc* getDoc();
+};
+
+inline const SvXMLUnitConverter& SwXMLExport::GetTwipUnitConverter() const
+{
+ return *m_pTwipUnitConverter;
+}
+
+#endif // INCLUDED_SW_SOURCE_FILTER_XML_XMLEXP_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlexpit.cxx b/sw/source/filter/xml/xmlexpit.cxx
new file mode 100644
index 0000000000..a39d12228c
--- /dev/null
+++ b/sw/source/filter/xml/xmlexpit.cxx
@@ -0,0 +1,1137 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlexpit.hxx"
+
+#include <osl/diagnose.h>
+#include <rtl/ustrbuf.hxx>
+#include <sax/tools/converter.hxx>
+#include <svl/poolitem.hxx>
+#include <svl/itemset.hxx>
+#include <utility>
+#include <xmloff/xmluconv.hxx>
+#include <xmloff/namespacemap.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/prhdlfac.hxx>
+#include <xmloff/xmltypes.hxx>
+#include <editeng/xmlcnitm.hxx>
+#include <xmloff/xmlexp.hxx>
+#include <xmloff/xmlprhdl.hxx>
+#include <editeng/memberids.h>
+#include <hintids.hxx>
+#include <unomid.h>
+#include <svx/unomid.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/shaditem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/formatbreakitem.hxx>
+#include <editeng/keepitem.hxx>
+#include <editeng/brushitem.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <editeng/prntitem.hxx>
+#include <fmtpdsc.hxx>
+#include <fmtornt.hxx>
+#include <fmtfsize.hxx>
+
+#include "xmlithlp.hxx"
+
+#include <fmtrowsplt.hxx>
+
+using ::editeng::SvxBorderLine;
+using namespace ::com::sun::star;
+using namespace ::xmloff::token;
+using uno::Any;
+
+// fills the given attribute list with the items in the given set
+void SvXMLExportItemMapper::exportXML( const SvXMLExport& rExport,
+ comphelper::AttributeList& rAttrList,
+ const SfxItemSet& rSet,
+ const SvXMLUnitConverter& rUnitConverter,
+ const SvXMLNamespaceMap& rNamespaceMap,
+ std::vector<sal_uInt16> *pIndexArray ) const
+{
+ const sal_uInt16 nCount = mrMapEntries->getCount();
+ sal_uInt16 nIndex = 0;
+
+ while( nIndex < nCount )
+ {
+ SvXMLItemMapEntry const & rEntry = mrMapEntries->getByIndex( nIndex );
+
+ // we have a valid map entry here, so lets use it...
+ if( 0 == (rEntry.nMemberId & MID_SW_FLAG_NO_ITEM_EXPORT) )
+ {
+ const SfxPoolItem* pItem = GetItem( rSet, rEntry.nWhichId );
+ // do we have an item?
+ if(pItem)
+ {
+ if( 0 != (rEntry.nMemberId & MID_SW_FLAG_ELEMENT_ITEM_EXPORT) )
+ {
+ // element items do not add any properties,
+ // we export it later
+ if( pIndexArray )
+ pIndexArray->push_back( nIndex );
+
+ }
+ else
+ {
+ exportXML( rExport, rAttrList, *pItem, rEntry, rUnitConverter,
+ rNamespaceMap, &rSet );
+ }
+ }
+ }
+ else
+ {
+ OSL_FAIL( "no item not handled in xml export" );
+ }
+ nIndex++;
+ }
+}
+
+void SvXMLExportItemMapper::exportXML(const SvXMLExport&,
+ comphelper::AttributeList& rAttrList,
+ const SfxPoolItem& rItem,
+ const SvXMLItemMapEntry& rEntry,
+ const SvXMLUnitConverter& rUnitConverter,
+ const SvXMLNamespaceMap& rNamespaceMap,
+ const SfxItemSet *pSet ) const
+{
+ if( 0 != (rEntry.nMemberId & MID_SW_FLAG_SPECIAL_ITEM_EXPORT) )
+ {
+ if( dynamic_cast<const SwFormatRowSplit*>( &rItem) != nullptr )
+ {
+ OUString aValue;
+ bool bAddAttribute = true;
+ if( rEntry.nNameSpace == XML_NAMESPACE_STYLE )
+ {
+ bAddAttribute = false;
+ }
+ else
+ {
+ OUStringBuffer aOut;
+ const SfxBoolItem* pSplit = dynamic_cast<const SfxBoolItem*>( &rItem );
+ assert(pSplit && "Wrong Which-ID");
+ const sal_uInt16 eEnum = (pSplit && pSplit->GetValue()) ? 1 : 0;
+ SvXMLUnitConverter::convertEnum( aOut, eEnum, aXML_KeepTogetherType );
+ aValue = aOut.makeStringAndClear();
+ }
+ if( bAddAttribute )
+ {
+ const OUString sName( rNamespaceMap.GetQNameByKey( rEntry.nNameSpace,
+ GetXMLToken(rEntry.eLocalName) ) );
+ rAttrList.AddAttribute( sName, aValue );
+ }
+ }
+
+ if (const SvXMLAttrContainerItem *pUnknown = dynamic_cast<const SvXMLAttrContainerItem*>(&rItem))
+ {
+ std::unique_ptr<SvXMLNamespaceMap> pNewNamespaceMap;
+ const SvXMLNamespaceMap *pNamespaceMap = &rNamespaceMap;
+
+ const sal_uInt16 nCount = pUnknown->GetAttrCount();
+ for( sal_uInt16 i=0; i < nCount; i++ )
+ {
+ const OUString sPrefix( pUnknown->GetAttrPrefix( i ) );
+ if( !sPrefix.isEmpty() )
+ {
+ const OUString sNamespace( pUnknown->GetAttrNamespace( i ) );
+
+ // if the prefix isn't defined yet or has another meaning,
+ // we have to redefine it now.
+ const sal_uInt16 nIdx = pNamespaceMap->GetIndexByPrefix( sPrefix );
+ if( USHRT_MAX == nIdx ||
+ pNamespaceMap->GetNameByIndex( nIdx ) != sNamespace )
+ {
+ if( !pNewNamespaceMap )
+ {
+ pNewNamespaceMap.reset(
+ new SvXMLNamespaceMap( rNamespaceMap ));
+ pNamespaceMap = pNewNamespaceMap.get();
+ }
+ pNewNamespaceMap->Add( sPrefix, sNamespace );
+
+ rAttrList.AddAttribute( GetXMLToken(XML_XMLNS) + ":" + sPrefix,
+ sNamespace );
+ }
+
+ rAttrList.AddAttribute( sPrefix + ":" + pUnknown->GetAttrLName(i),
+ pUnknown->GetAttrValue(i) );
+ }
+ else
+ {
+ rAttrList.AddAttribute( pUnknown->GetAttrLName(i),
+ pUnknown->GetAttrValue(i) );
+ }
+ }
+ }
+ else
+ {
+ handleSpecialItem( rAttrList, rEntry, rItem, rUnitConverter,
+ rNamespaceMap, pSet );
+ }
+ }
+ else if( 0 == (rEntry.nMemberId & MID_SW_FLAG_ELEMENT_ITEM_EXPORT) )
+ {
+ bool bDone = false;
+ switch (rItem.Which())
+ {
+ case RES_FRAMEDIR:
+ {
+ // Write bt-lr and tb-rl90 to the extension namespace, handle other values
+ // below.
+ auto pDirection = static_cast<const SvxFrameDirectionItem*>(&rItem);
+ if (rEntry.nNameSpace == XML_NAMESPACE_LO_EXT
+ && pDirection->GetValue() == SvxFrameDirection::Vertical_LR_BT)
+ {
+ const OUString sName(rNamespaceMap.GetQNameByKey(
+ XML_NAMESPACE_LO_EXT, GetXMLToken(XML_WRITING_MODE)));
+ rAttrList.AddAttribute(sName, GetXMLToken(XML_BT_LR));
+ }
+ if (rEntry.nNameSpace == XML_NAMESPACE_LO_EXT
+ || pDirection->GetValue() == SvxFrameDirection::Vertical_LR_BT)
+ bDone = true;
+
+ if (rEntry.nNameSpace == XML_NAMESPACE_LO_EXT
+ && pDirection->GetValue() == SvxFrameDirection::Vertical_RL_TB90)
+ {
+ const OUString sName(rNamespaceMap.GetQNameByKey(
+ XML_NAMESPACE_LO_EXT, GetXMLToken(XML_WRITING_MODE)));
+ rAttrList.AddAttribute(sName, GetXMLToken(XML_TB_RL90));
+ }
+ if (rEntry.nNameSpace == XML_NAMESPACE_LO_EXT
+ || pDirection->GetValue() == SvxFrameDirection::Vertical_RL_TB90)
+ bDone = true;
+ break;
+ }
+ }
+
+ if (!bDone)
+ {
+ OUString aValue;
+ if( QueryXMLValue(rItem, aValue,
+ static_cast< sal_uInt16 >(
+ rEntry.nMemberId & MID_SW_FLAG_MASK ),
+ rUnitConverter ) )
+ {
+ const OUString sName(
+ rNamespaceMap.GetQNameByKey( rEntry.nNameSpace,
+ GetXMLToken(rEntry.eLocalName)));
+ rAttrList.AddAttribute( sName, aValue );
+ }
+ }
+ }
+}
+
+void SvXMLExportItemMapper::exportElementItems(
+ SvXMLExport& rExport,
+ const SfxItemSet &rSet,
+ const std::vector<sal_uInt16> &rIndexArray ) const
+{
+ const size_t nCount = rIndexArray.size();
+
+ bool bItemsExported = false;
+ for( size_t nIndex = 0; nIndex < nCount; ++nIndex )
+ {
+ const sal_uInt16 nElement = rIndexArray[ nIndex ];
+ SvXMLItemMapEntry const & rEntry = mrMapEntries->getByIndex( nElement );
+ OSL_ENSURE( 0 != (rEntry.nMemberId & MID_SW_FLAG_ELEMENT_ITEM_EXPORT),
+ "wrong mid flag!" );
+
+ const SfxPoolItem* pItem = GetItem( rSet, rEntry.nWhichId );
+ // do we have an item?
+ if(pItem)
+ {
+ rExport.IgnorableWhitespace();
+ handleElementItem( rEntry, *pItem );
+ bItemsExported = true;
+ }
+ }
+
+ if( bItemsExported )
+ rExport.IgnorableWhitespace();
+}
+
+/** returns the item with the given WhichId from the given ItemSet if it's
+ set
+*/
+const SfxPoolItem* SvXMLExportItemMapper::GetItem( const SfxItemSet& rSet,
+ sal_uInt16 nWhichId)
+{
+ // first get item from itemset
+ const SfxPoolItem* pItem;
+ SfxItemState eState = rSet.GetItemState( nWhichId, false, &pItem );
+
+ if( SfxItemState::SET == eState )
+ {
+ return pItem;
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+
+SvXMLExportItemMapper::SvXMLExportItemMapper( SvXMLItemMapEntriesRef rMapEntries )
+ : mrMapEntries(std::move(rMapEntries))
+{
+}
+
+SvXMLExportItemMapper::~SvXMLExportItemMapper()
+{
+}
+
+void SvXMLExportItemMapper::exportXML( SvXMLExport& rExport,
+ const SfxItemSet& rSet,
+ const SvXMLUnitConverter& rUnitConverter,
+ XMLTokenEnum ePropToken ) const
+{
+ std::vector<sal_uInt16> aIndexArray;
+
+ exportXML( rExport, rExport.GetAttrList(), rSet, rUnitConverter,
+ rExport.GetNamespaceMap(), &aIndexArray );
+
+ if( rExport.GetAttrList().getLength() > 0 || !aIndexArray.empty() )
+ {
+ rExport.IgnorableWhitespace();
+
+ SvXMLElementExport aElem( rExport, XML_NAMESPACE_STYLE, ePropToken,
+ false, false );
+ exportElementItems( rExport, rSet, aIndexArray );
+ }
+}
+
+/** this method is called for every item that has the
+ MID_SW_FLAG_SPECIAL_ITEM_EXPORT flag set */
+void SvXMLExportItemMapper::handleSpecialItem( comphelper::AttributeList& /*rAttrList*/,
+ const SvXMLItemMapEntry& /*rEntry*/,
+ const SfxPoolItem& /*rItem*/,
+ const SvXMLUnitConverter& /*rUnitConverter*/,
+ const SvXMLNamespaceMap& /*rNamespaceMap*/,
+ const SfxItemSet* /*pSet*/ /* = NULL */ ) const
+{
+ OSL_FAIL( "special item not handled in xml export" );
+}
+
+/** this method is called for every item that has the
+ MID_SW_FLAG_ELEMENT_EXPORT flag set */
+void SvXMLExportItemMapper::handleElementItem(
+ const SvXMLItemMapEntry& /*rEntry*/,
+ const SfxPoolItem& /*rItem*/ ) const
+{
+ OSL_FAIL( "element item not handled in xml export" );
+}
+
+static bool lcl_isOdfDoubleLine( const SvxBorderLine* pLine )
+{
+ bool bIsOdfDouble = false;
+ switch (pLine->GetBorderLineStyle())
+ {
+ case SvxBorderLineStyle::DOUBLE:
+ case SvxBorderLineStyle::THINTHICK_SMALLGAP:
+ case SvxBorderLineStyle::THINTHICK_MEDIUMGAP:
+ case SvxBorderLineStyle::THINTHICK_LARGEGAP:
+ case SvxBorderLineStyle::THICKTHIN_SMALLGAP:
+ case SvxBorderLineStyle::THICKTHIN_MEDIUMGAP:
+ case SvxBorderLineStyle::THICKTHIN_LARGEGAP:
+ bIsOdfDouble = true;
+ break;
+ default:
+ break;
+ }
+ return bIsOdfDouble;
+}
+
+bool SvXMLExportItemMapper::QueryXMLValue(
+ const SfxPoolItem& rItem,
+ OUString& rValue,
+ sal_uInt16 nMemberId,
+ const SvXMLUnitConverter& rUnitConverter )
+{
+ bool bOk = false;
+ OUStringBuffer aOut;
+
+ switch ( rItem.Which() )
+ {
+ case RES_MARGIN_FIRSTLINE:
+ case RES_MARGIN_TEXTLEFT:
+ case RES_MARGIN_RIGHT:
+ assert(false); // is only called for frame formats?
+ break;
+
+ case RES_LR_SPACE:
+ {
+ const SvxLRSpaceItem& rLRSpace = dynamic_cast<const SvxLRSpaceItem&>(rItem);
+
+ bOk = true;
+ switch( nMemberId )
+ {
+ case MID_L_MARGIN:
+ if (rLRSpace.GetPropLeft() != 100)
+ {
+ ::sax::Converter::convertPercent(
+ aOut, rLRSpace.GetPropLeft() );
+ }
+ else
+ {
+ rUnitConverter.convertMeasureToXML(
+ aOut, rLRSpace.GetLeft() );
+ }
+ break;
+
+ case MID_R_MARGIN:
+ if (rLRSpace.GetPropRight() != 100)
+ {
+ ::sax::Converter::convertPercent(
+ aOut, rLRSpace.GetPropRight() );
+ }
+ else
+ {
+ rUnitConverter.convertMeasureToXML(
+ aOut, rLRSpace.GetRight() );
+ }
+ break;
+
+ case MID_FIRST_AUTO:
+ if (rLRSpace.IsAutoFirst())
+ {
+ ::sax::Converter::convertBool(
+ aOut, rLRSpace.IsAutoFirst() );
+ }
+ else
+ bOk = false;
+ break;
+
+ case MID_FIRST_LINE_INDENT:
+ if (!rLRSpace.IsAutoFirst())
+ {
+ if (rLRSpace.GetPropTextFirstLineOffset() != 100)
+ {
+ ::sax::Converter::convertPercent(
+ aOut, rLRSpace.GetPropTextFirstLineOffset() );
+ }
+ else
+ {
+ rUnitConverter.convertMeasureToXML(
+ aOut, rLRSpace.GetTextFirstLineOffset() );
+ }
+ }
+ else
+ bOk = false;
+ break;
+
+ default:
+ OSL_FAIL( "unknown member id!");
+ bOk = false;
+ break;
+ }
+ }
+ break;
+
+ case RES_UL_SPACE:
+ {
+ const SvxULSpaceItem& rULSpace = dynamic_cast<const SvxULSpaceItem&>(rItem);
+
+ switch( nMemberId )
+ {
+ case MID_UP_MARGIN:
+ if (rULSpace.GetPropUpper() != 100)
+ {
+ ::sax::Converter::convertPercent(
+ aOut, rULSpace.GetPropUpper() );
+ }
+ else
+ {
+ rUnitConverter.convertMeasureToXML(
+ aOut, rULSpace.GetUpper() );
+ }
+ break;
+
+ case MID_LO_MARGIN:
+ if (rULSpace.GetPropLower() != 100)
+ {
+ ::sax::Converter::convertPercent(
+ aOut, rULSpace.GetPropLower() );
+ }
+ else
+ {
+ rUnitConverter.convertMeasureToXML(
+ aOut, rULSpace.GetLower() );
+ }
+ break;
+
+ default:
+ OSL_FAIL("unknown MemberId");
+ };
+
+ bOk = true;
+ }
+ break;
+
+ case RES_SHADOW:
+ {
+ const SvxShadowItem* pShadow = dynamic_cast<const SvxShadowItem*>( &rItem );
+ assert(pShadow && "Wrong Which-ID");
+ if (pShadow)
+ {
+ sal_Int32 nX = 1, nY = 1;
+ switch( pShadow->GetLocation() )
+ {
+ case SvxShadowLocation::TopLeft:
+ nX = -1;
+ nY = -1;
+ break;
+ case SvxShadowLocation::TopRight:
+ nY = -1;
+ break;
+ case SvxShadowLocation::BottomLeft:
+ nX = -1;
+ break;
+ case SvxShadowLocation::BottomRight:
+ break;
+ case SvxShadowLocation::NONE:
+ default:
+ rValue = GetXMLToken(XML_NONE);
+ return true;
+ }
+
+ nX *= pShadow->GetWidth();
+ nY *= pShadow->GetWidth();
+
+ ::sax::Converter::convertColor(aOut, pShadow->GetColor());
+ aOut.append( ' ' );
+ rUnitConverter.convertMeasureToXML( aOut, nX );
+ aOut.append( ' ' );
+ rUnitConverter.convertMeasureToXML( aOut, nY );
+
+ bOk = true;
+ }
+ }
+ break;
+
+ case RES_BOX:
+ {
+ const SvxBoxItem* pBox = dynamic_cast<const SvxBoxItem*>( &rItem );
+ assert(pBox && "Wrong Which-ID");
+ if (pBox)
+ {
+ /**
+ xml -> MemberId
+
+ border-padding ALL_BORDER_PADDING
+ border-padding-before LEFT_BORDER_PADDING
+ border-padding-after RIGHT_BORDER_PADDING
+ border-padding-start TOP_BORDER_PADDING
+ border-padding-end BOTTOM_BORDER_PADDING
+
+ border ALL_BORDER
+ border-before LEFT_BORDER
+ border-after RIGHT_BORDER
+ border-start TOP_BORDER
+ border-end BOTTOM_BORDER
+
+ border-line-width ALL_BORDER_LINE_WIDTH
+ border-line-width-before LEFT_BORDER_LINE_WIDTH
+ border-line-width-after RIGHT_BORDER_LINE_WIDTH
+ border-line-width-start TOP_BORDER_LINE_WIDTH
+ border-line-width-end BOTTOM_BORDER_LINE_WIDTH
+ */
+
+ const SvxBorderLine* pLeft = pBox->GetLeft();
+ const SvxBorderLine* pRight = pBox->GetRight();
+ const SvxBorderLine* pTop = pBox->GetTop();
+ const SvxBorderLine* pBottom = pBox->GetBottom();
+ const sal_uInt16 nTopDist = pBox->GetDistance( SvxBoxItemLine::TOP );
+ const sal_uInt16 nBottomDist = pBox->GetDistance( SvxBoxItemLine::BOTTOM );
+ const sal_uInt16 nLeftDist = pBox->GetDistance( SvxBoxItemLine::LEFT );
+ const sal_uInt16 nRightDist = pBox->GetDistance( SvxBoxItemLine::RIGHT );
+
+ // check if we need to export it
+ switch( nMemberId )
+ {
+ case ALL_BORDER_PADDING:
+ case LEFT_BORDER_PADDING:
+ case RIGHT_BORDER_PADDING:
+ case TOP_BORDER_PADDING:
+ case BOTTOM_BORDER_PADDING:
+ {
+ bool bEqual = nLeftDist == nRightDist &&
+ nLeftDist == nTopDist &&
+ nLeftDist == nBottomDist;
+ // don't export individual paddings if all paddings are equal and
+ // don't export all padding if some paddings are not equal
+ if( (bEqual && ALL_BORDER_PADDING != nMemberId) ||
+ (!bEqual && ALL_BORDER_PADDING == nMemberId) )
+ return false;
+ }
+ break;
+ case ALL_BORDER:
+ case LEFT_BORDER:
+ case RIGHT_BORDER:
+ case TOP_BORDER:
+ case BOTTOM_BORDER:
+ {
+ bool bEqual = ( nullptr == pTop && nullptr == pBottom &&
+ nullptr == pLeft && nullptr == pRight ) ||
+ ( pTop && pBottom && pLeft && pRight &&
+ *pTop == *pBottom && *pTop == *pLeft &&
+ *pTop == *pRight );
+
+ // don't export individual borders if all are the same and
+ // don't export all borders if some are not equal
+ if( (bEqual && ALL_BORDER != nMemberId) ||
+ (!bEqual && ALL_BORDER == nMemberId) )
+ return false;
+ }
+ break;
+ case ALL_BORDER_LINE_WIDTH:
+ case LEFT_BORDER_LINE_WIDTH:
+ case RIGHT_BORDER_LINE_WIDTH:
+ case TOP_BORDER_LINE_WIDTH:
+ case BOTTOM_BORDER_LINE_WIDTH:
+ {
+ // if no line is set, there is nothing to export
+ if( !pTop && !pBottom && !pLeft && !pRight )
+ return false;
+
+ bool bEqual = nullptr != pTop &&
+ nullptr != pBottom &&
+ nullptr != pLeft &&
+ nullptr != pRight;
+
+ if( bEqual )
+ {
+ const sal_uInt16 nDistance = pTop->GetDistance();
+ const sal_uInt16 nInWidth = pTop->GetInWidth();
+ const sal_uInt16 nOutWidth = pTop->GetOutWidth();
+ const tools::Long nWidth = pTop->GetWidth();
+
+ bEqual = nDistance == pLeft->GetDistance() &&
+ nInWidth == pLeft->GetInWidth() &&
+ nOutWidth == pLeft->GetOutWidth() &&
+ nWidth == pLeft->GetWidth() &&
+ nDistance == pRight->GetDistance() &&
+ nInWidth == pRight->GetInWidth() &&
+ nOutWidth == pRight->GetOutWidth() &&
+ nWidth == pRight->GetWidth() &&
+ nDistance == pBottom->GetDistance() &&
+ nInWidth == pBottom->GetInWidth() &&
+ nOutWidth == pBottom->GetOutWidth() &&
+ nWidth == pBottom->GetWidth();
+ }
+
+ switch( nMemberId )
+ {
+ case ALL_BORDER_LINE_WIDTH:
+ if( !bEqual || pTop->GetDistance() == 0 ||
+ !lcl_isOdfDoubleLine( pTop ) )
+ return false;
+ break;
+ case LEFT_BORDER_LINE_WIDTH:
+ if( bEqual || nullptr == pLeft ||
+ 0 == pLeft->GetDistance() ||
+ !lcl_isOdfDoubleLine( pLeft ) )
+ return false;
+ break;
+ case RIGHT_BORDER_LINE_WIDTH:
+ if( bEqual || nullptr == pRight ||
+ 0 == pRight->GetDistance() ||
+ !lcl_isOdfDoubleLine( pRight ) )
+ return false;
+ break;
+ case TOP_BORDER_LINE_WIDTH:
+ if( bEqual || nullptr == pTop ||
+ 0 == pTop->GetDistance() ||
+ !lcl_isOdfDoubleLine( pTop ) )
+ return false;
+ break;
+ case BOTTOM_BORDER_LINE_WIDTH:
+ if( bEqual || nullptr == pBottom ||
+ 0 == pBottom->GetDistance() ||
+ !lcl_isOdfDoubleLine( pBottom ) )
+ return false;
+ break;
+ }
+ }
+ break;
+ }
+
+ // now export it export
+ switch( nMemberId )
+ {
+ // padding
+ case ALL_BORDER_PADDING:
+ case LEFT_BORDER_PADDING:
+ rUnitConverter.convertMeasureToXML( aOut, nLeftDist );
+ break;
+ case RIGHT_BORDER_PADDING:
+ rUnitConverter.convertMeasureToXML( aOut, nRightDist );
+ break;
+ case TOP_BORDER_PADDING:
+ rUnitConverter.convertMeasureToXML( aOut, nTopDist );
+ break;
+ case BOTTOM_BORDER_PADDING:
+ rUnitConverter.convertMeasureToXML( aOut, nBottomDist );
+ break;
+
+ // border
+ case ALL_BORDER:
+ case LEFT_BORDER:
+ case RIGHT_BORDER:
+ case TOP_BORDER:
+ case BOTTOM_BORDER:
+ {
+ const SvxBorderLine* pLine;
+ switch( nMemberId )
+ {
+ case ALL_BORDER:
+ case LEFT_BORDER:
+ pLine = pLeft;
+ break;
+ case RIGHT_BORDER:
+ pLine = pRight;
+ break;
+ case TOP_BORDER:
+ pLine = pTop;
+ break;
+ case BOTTOM_BORDER:
+ pLine = pBottom;
+ break;
+ default:
+ pLine = nullptr;
+ break;
+ }
+
+ if( nullptr != pLine )
+ {
+ sal_Int32 nWidth = pLine->GetWidth();
+
+ enum XMLTokenEnum eStyle = XML_SOLID;
+ bool bNoBorder = false;
+ switch (pLine->GetBorderLineStyle())
+ {
+ case SvxBorderLineStyle::SOLID:
+ eStyle = XML_SOLID;
+ break;
+ case SvxBorderLineStyle::DOTTED:
+ eStyle = XML_DOTTED;
+ break;
+ case SvxBorderLineStyle::DASHED:
+ eStyle = XML_DASHED;
+ break;
+ case SvxBorderLineStyle::FINE_DASHED:
+ eStyle = XML_FINE_DASHED;
+ break;
+ case SvxBorderLineStyle::DASH_DOT:
+ eStyle = XML_DASH_DOT;
+ break;
+ case SvxBorderLineStyle::DASH_DOT_DOT:
+ eStyle = XML_DASH_DOT_DOT;
+ break;
+ case SvxBorderLineStyle::DOUBLE_THIN:
+ eStyle = XML_DOUBLE_THIN;
+ break;
+ case SvxBorderLineStyle::DOUBLE:
+ case SvxBorderLineStyle::THINTHICK_SMALLGAP:
+ case SvxBorderLineStyle::THINTHICK_MEDIUMGAP:
+ case SvxBorderLineStyle::THINTHICK_LARGEGAP:
+ case SvxBorderLineStyle::THICKTHIN_SMALLGAP:
+ case SvxBorderLineStyle::THICKTHIN_MEDIUMGAP:
+ case SvxBorderLineStyle::THICKTHIN_LARGEGAP:
+ eStyle = XML_DOUBLE;
+ break;
+ case SvxBorderLineStyle::EMBOSSED:
+ eStyle = XML_RIDGE;
+ break;
+ case SvxBorderLineStyle::ENGRAVED:
+ eStyle = XML_GROOVE;
+ break;
+ case SvxBorderLineStyle::INSET:
+ eStyle = XML_INSET;
+ break;
+ case SvxBorderLineStyle::OUTSET:
+ eStyle = XML_OUTSET;
+ break;
+ default:
+ bNoBorder = true;
+ }
+
+ if ( !bNoBorder )
+ {
+ ::sax::Converter::convertMeasure(aOut, nWidth,
+ util::MeasureUnit::TWIP,
+ util::MeasureUnit::POINT);
+ aOut.append( " "
+ + GetXMLToken( eStyle )
+ + " " );
+ ::sax::Converter::convertColor(aOut,
+ pLine->GetColor());
+ }
+ }
+ else
+ {
+ aOut.append( GetXMLToken(XML_NONE) );
+ }
+ }
+ break;
+
+ // width
+ case ALL_BORDER_LINE_WIDTH:
+ case LEFT_BORDER_LINE_WIDTH:
+ case RIGHT_BORDER_LINE_WIDTH:
+ case TOP_BORDER_LINE_WIDTH:
+ case BOTTOM_BORDER_LINE_WIDTH:
+ const SvxBorderLine* pLine;
+ switch( nMemberId )
+ {
+ case ALL_BORDER_LINE_WIDTH:
+ case LEFT_BORDER_LINE_WIDTH:
+ pLine = pLeft;
+ break;
+ case RIGHT_BORDER_LINE_WIDTH:
+ pLine = pRight;
+ break;
+ case TOP_BORDER_LINE_WIDTH:
+ pLine = pTop;
+ break;
+ case BOTTOM_BORDER_LINE_WIDTH:
+ pLine = pBottom;
+ break;
+ default:
+ return false;
+ }
+ rUnitConverter.convertMeasureToXML( aOut, pLine->GetInWidth() );
+ aOut.append( ' ' );
+ rUnitConverter.convertMeasureToXML( aOut, pLine->GetDistance() );
+ aOut.append( ' ' );
+ rUnitConverter.convertMeasureToXML( aOut, pLine->GetOutWidth() );
+ break;
+ }
+ bOk = true;
+ }
+ }
+ break;
+
+ case RES_BREAK:
+ {
+ const SvxFormatBreakItem& rFormatBreak = dynamic_cast<const SvxFormatBreakItem&>(rItem);
+
+ sal_uInt16 eEnum = 0;
+
+ switch( nMemberId )
+ {
+ case MID_BREAK_BEFORE:
+ switch (rFormatBreak.GetBreak())
+ {
+ case SvxBreak::ColumnBefore:
+ eEnum = 1;
+ break;
+ case SvxBreak::PageBefore:
+ eEnum = 2;
+ break;
+ case SvxBreak::NONE:
+ eEnum = 0;
+ break;
+ default:
+ return false;
+ }
+ break;
+ case MID_BREAK_AFTER:
+ switch (rFormatBreak.GetBreak())
+ {
+ case SvxBreak::ColumnAfter:
+ eEnum = 1;
+ break;
+ case SvxBreak::PageAfter:
+ eEnum = 2;
+ break;
+ case SvxBreak::NONE:
+ eEnum = 0;
+ break;
+ default:
+ return false;
+ }
+ break;
+ }
+
+ bOk = SvXMLUnitConverter::convertEnum( aOut, eEnum, psXML_BreakType );
+ }
+ break;
+
+ case RES_KEEP:
+ {
+ const SvxFormatKeepItem* pFormatKeep = dynamic_cast<const SvxFormatKeepItem*>( &rItem );
+ assert(pFormatKeep && "Wrong Which-ID");
+ if (pFormatKeep)
+ {
+ aOut.append( pFormatKeep->GetValue()
+ ? GetXMLToken( XML_ALWAYS )
+ : GetXMLToken( XML_AUTO ) );
+ bOk = true;
+ }
+ }
+ break;
+
+ case RES_PRINT:
+ {
+ const SvxPrintItem* pHasTextChangesOnly = dynamic_cast<const SvxPrintItem*>( &rItem );
+ if (pHasTextChangesOnly && !pHasTextChangesOnly->GetValue())
+ {
+ aOut.append( "false" );
+ bOk = true;
+ }
+ }
+ break;
+
+ case RES_BACKGROUND:
+ {
+ const SvxBrushItem& rBrush = dynamic_cast<const SvxBrushItem&>(rItem);
+
+ // note: the graphic is only exported if nMemberId equals
+ // MID_GRAPHIC...
+ // If not, only the color or transparency is exported
+
+ switch( nMemberId )
+ {
+ case MID_BACK_COLOR:
+ if ( rBrush.GetColor().IsTransparent() )
+ aOut.append( GetXMLToken(XML_TRANSPARENT) );
+ else
+ {
+ ::sax::Converter::convertColor(aOut,
+ rBrush.GetColor());
+ }
+ bOk = true;
+ break;
+
+ case MID_GRAPHIC_POSITION:
+ switch (rBrush.GetGraphicPos())
+ {
+ case GPOS_LT:
+ case GPOS_MT:
+ case GPOS_RT:
+ aOut.append( GetXMLToken(XML_TOP) );
+ bOk = true;
+ break;
+ case GPOS_LM:
+ case GPOS_MM:
+ case GPOS_RM:
+ aOut.append( GetXMLToken(XML_CENTER) );
+ bOk = true;
+ break;
+ case GPOS_LB:
+ case GPOS_MB:
+ case GPOS_RB:
+ aOut.append( GetXMLToken(XML_BOTTOM) );
+ bOk = true;
+ break;
+ default:
+ ;
+ }
+
+ if( bOk )
+ {
+ aOut.append( ' ' );
+
+ switch (rBrush.GetGraphicPos())
+ {
+ case GPOS_LT:
+ case GPOS_LB:
+ case GPOS_LM:
+ aOut.append( GetXMLToken(XML_LEFT) );
+ break;
+ case GPOS_MT:
+ case GPOS_MM:
+ case GPOS_MB:
+ aOut.append( GetXMLToken(XML_CENTER) );
+ break;
+ case GPOS_RM:
+ case GPOS_RT:
+ case GPOS_RB:
+ aOut.append( GetXMLToken(XML_RIGHT) );
+ break;
+ default:
+ ;
+ }
+ }
+ break;
+
+ case MID_GRAPHIC_REPEAT:
+ {
+ SvxGraphicPosition eGraphicPos = rBrush.GetGraphicPos();
+ if( GPOS_AREA == eGraphicPos )
+ {
+ aOut.append( GetXMLToken(XML_STRETCH) );
+ bOk = true;
+ }
+ else if( GPOS_NONE != eGraphicPos && GPOS_TILED != eGraphicPos )
+ {
+ aOut.append( GetXMLToken(XML_BACKGROUND_NO_REPEAT) );
+ bOk = true;
+ }
+ }
+ break;
+
+ case MID_GRAPHIC_FILTER:
+ if (rBrush.GetGraphicPos() != GPOS_NONE &&
+ !rBrush.GetGraphicFilter().isEmpty())
+ {
+ aOut.append(rBrush.GetGraphicFilter());
+ bOk = true;
+ }
+ break;
+ }
+ }
+ break;
+
+ case RES_PAGEDESC:
+ {
+ const SwFormatPageDesc& rPageDesc = dynamic_cast<const SwFormatPageDesc&>(rItem);
+
+ if( MID_PAGEDESC_PAGENUMOFFSET==nMemberId )
+ {
+ ::std::optional<sal_uInt16> oNumOffset = rPageDesc.GetNumOffset();
+ if (oNumOffset && *oNumOffset > 0)
+ {
+ // #i114163# positiveInteger only!
+ sal_Int32 const number(*oNumOffset);
+ aOut.append(number);
+ }
+ else
+ {
+ aOut.append(GetXMLToken(XML_AUTO));
+ }
+ bOk = true;
+ }
+ }
+ break;
+
+ case RES_LAYOUT_SPLIT:
+ case RES_ROW_SPLIT:
+ {
+ const SfxBoolItem* pSplit = dynamic_cast<const SfxBoolItem*>( &rItem );
+ assert(pSplit && "Wrong Which-ID");
+ if (pSplit)
+ {
+ ::sax::Converter::convertBool( aOut, pSplit->GetValue() );
+ bOk = true;
+ }
+ }
+ break;
+
+ case RES_HORI_ORIENT:
+ {
+ const SwFormatHoriOrient* pHoriOrient = dynamic_cast<const SwFormatHoriOrient*>( &rItem );
+ assert(pHoriOrient && "Wrong Which-ID");
+ if (pHoriOrient)
+ {
+ SvXMLUnitConverter::convertEnum( aOut, pHoriOrient->GetHoriOrient(),
+ aXMLTableAlignMap );
+ bOk = true;
+ }
+ }
+ break;
+
+ case RES_VERT_ORIENT:
+ {
+ const SwFormatVertOrient* pVertOrient = dynamic_cast<const SwFormatVertOrient*>( &rItem );
+ assert(pVertOrient && "Wrong Which-ID");
+
+ SvXMLUnitConverter::convertEnum( aOut, pVertOrient->GetVertOrient(),
+ aXMLTableVAlignMap );
+ bOk = true;
+ }
+ break;
+
+ case RES_FRM_SIZE:
+ {
+ const SwFormatFrameSize& rFrameSize = dynamic_cast<const SwFormatFrameSize&>(rItem);
+
+ bool bOutHeight = false;
+ switch( nMemberId )
+ {
+ case MID_FRMSIZE_REL_WIDTH:
+ if (rFrameSize.GetWidthPercent())
+ {
+ ::sax::Converter::convertPercent(
+ aOut, rFrameSize.GetWidthPercent() );
+ bOk = true;
+ }
+ break;
+ case MID_FRMSIZE_MIN_HEIGHT:
+ if( SwFrameSize::Minimum == rFrameSize.GetHeightSizeType() )
+ bOutHeight = true;
+ break;
+ case MID_FRMSIZE_FIX_HEIGHT:
+ if( SwFrameSize::Fixed == rFrameSize.GetHeightSizeType() )
+ bOutHeight = true;
+ break;
+ }
+
+ if( bOutHeight )
+ {
+ rUnitConverter.convertMeasureToXML(aOut, rFrameSize.GetHeight());
+ bOk = true;
+ }
+ }
+ break;
+
+ case RES_FRAMEDIR:
+ {
+ Any aAny;
+ bOk = rItem.QueryValue( aAny );
+ if( bOk )
+ {
+ std::unique_ptr<XMLPropertyHandler> pWritingModeHandler =
+ XMLPropertyHandlerFactory::CreatePropertyHandler(
+ XML_TYPE_TEXT_WRITING_MODE_WITH_DEFAULT );
+ OUString sValue;
+ bOk = pWritingModeHandler->exportXML( sValue, aAny,
+ rUnitConverter );
+ if( bOk )
+ aOut.append( sValue );
+ }
+ }
+ break;
+
+ case RES_COLLAPSING_BORDERS:
+ {
+ const SfxBoolItem* pBorders = dynamic_cast<const SfxBoolItem*>( &rItem );
+ assert(pBorders && "Wrong RES-ID");
+ if (pBorders)
+ {
+ aOut.append( pBorders->GetValue()
+ ? GetXMLToken( XML_COLLAPSING )
+ : GetXMLToken( XML_SEPARATING ) );
+ bOk = true;
+ }
+ }
+ break;
+
+ default:
+ OSL_FAIL("GetXMLValue not implemented for this item.");
+ break;
+ }
+
+ if ( bOk )
+ rValue = aOut.makeStringAndClear();
+
+ return bOk;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlexpit.hxx b/sw/source/filter/xml/xmlexpit.hxx
new file mode 100644
index 0000000000..b0e10fb0ab
--- /dev/null
+++ b/sw/source/filter/xml/xmlexpit.hxx
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SW_SOURCE_FILTER_XML_XMLEXPIT_HXX
+#define INCLUDED_SW_SOURCE_FILTER_XML_XMLEXPIT_HXX
+
+#include <xmloff/xmlexppr.hxx>
+#include "xmlitmap.hxx"
+#include <vector>
+
+class SvXMLUnitConverter;
+class SfxPoolItem;
+class SfxItemSet;
+namespace comphelper { class AttributeList; }
+class SvXMLNamespaceMap;
+class SvXMLExport;
+
+class SvXMLExportItemMapper
+{
+ SvXMLItemMapEntriesRef mrMapEntries;
+
+protected:
+ /** fills the given attribute list with the items in the given set */
+ void exportXML( const SvXMLExport& rExport,
+ comphelper::AttributeList& rAttrList,
+ const SfxItemSet& rSet,
+ const SvXMLUnitConverter& rUnitConverter,
+ const SvXMLNamespaceMap& rNamespaceMap,
+ std::vector<sal_uInt16> *pIndexArray ) const;
+
+ void exportXML( const SvXMLExport& rExport,
+ comphelper::AttributeList& rAttrList,
+ const SfxPoolItem& rItem,
+ const SvXMLItemMapEntry &rEntry,
+ const SvXMLUnitConverter& rUnitConverter,
+ const SvXMLNamespaceMap& rNamespaceMap,
+ const SfxItemSet *pSet ) const;
+
+ void exportElementItems( SvXMLExport& rExport,
+ const SfxItemSet &rSet,
+ const std::vector<sal_uInt16> &rIndexArray ) const;
+
+ static const SfxPoolItem* GetItem( const SfxItemSet &rSet,
+ sal_uInt16 nWhichId );
+
+public:
+ explicit SvXMLExportItemMapper( SvXMLItemMapEntriesRef rMapEntries );
+ virtual ~SvXMLExportItemMapper();
+
+ void exportXML( SvXMLExport& rExport,
+ const SfxItemSet& rSet,
+ const SvXMLUnitConverter& rUnitConverter,
+ ::xmloff::token::XMLTokenEnum ePropToken ) const;
+
+ /** this method is called for every item that has the
+ MID_SW_FLAG_SPECIAL_ITEM_EXPORT flag set */
+ virtual void handleSpecialItem( comphelper::AttributeList& rAttrList,
+ const SvXMLItemMapEntry& rEntry,
+ const SfxPoolItem& rItem,
+ const SvXMLUnitConverter& rUnitConverter,
+ const SvXMLNamespaceMap& rNamespaceMap,
+ const SfxItemSet *pSet ) const;
+
+ /** this method is called for every item that has the
+ MID_SW_FLAG_ELEMENT_EXPORT flag set */
+ virtual void handleElementItem( const SvXMLItemMapEntry& rEntry,
+ const SfxPoolItem& rItem ) const;
+
+ inline void setMapEntries( SvXMLItemMapEntriesRef rMapEntries );
+
+ static bool QueryXMLValue( const SfxPoolItem& rItem,
+ OUString& rValue, sal_uInt16 nMemberId,
+ const SvXMLUnitConverter& rUnitConverter );
+};
+
+inline void
+SvXMLExportItemMapper::setMapEntries( SvXMLItemMapEntriesRef rMapEntries )
+{
+ mrMapEntries = rMapEntries;
+}
+
+#endif // INCLUDED_SW_SOURCE_FILTER_XML_XMLEXPIT_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlfmt.cxx b/sw/source/filter/xml/xmlfmt.cxx
new file mode 100644
index 0000000000..9bd4d2a5f4
--- /dev/null
+++ b/sw/source/filter/xml/xmlfmt.cxx
@@ -0,0 +1,1079 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <comphelper/diagnose_ex.hxx>
+#include <fmtcol.hxx>
+#include <hints.hxx>
+#include <doc.hxx>
+#include <docary.hxx>
+#include <IDocumentStylePoolAccess.hxx>
+#include <unoprnms.hxx>
+#include <fmtpdsc.hxx>
+#include <pagedesc.hxx>
+#include <xmloff/maptype.hxx>
+#include <xmloff/xmlnumfi.hxx>
+#include <xmloff/xmlprmap.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/xmlstyle.hxx>
+#include <xmloff/txtstyli.hxx>
+#include <xmloff/txtimp.hxx>
+#include <xmloff/families.hxx>
+#include <xmloff/XMLTextMasterStylesContext.hxx>
+#include <xmloff/XMLTextShapeStyleContext.hxx>
+#include <xmloff/XMLGraphicsDefaultStyle.hxx>
+#include <xmloff/XMLDrawingPageStyleContext.hxx>
+#include <xmloff/XMLTextMasterPageContext.hxx>
+#include <xmloff/table/XMLTableImport.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include "xmlimp.hxx"
+#include <cellatr.hxx>
+#include <SwStyleNameMapper.hxx>
+#include <ccoll.hxx>
+
+#include <memory>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::xmloff::token;
+
+namespace {
+
+class SwXMLConditionParser_Impl
+{
+ OUString m_sInput;
+
+ Master_CollCondition m_nCondition;
+ sal_uInt32 m_nSubCondition;
+
+ sal_Int32 m_nPos;
+ sal_Int32 m_nLength;
+
+ inline bool SkipWS();
+ inline bool MatchChar( sal_Unicode c );
+ inline bool MatchName( OUString& rName );
+ inline bool MatchNumber( sal_uInt32& rNumber );
+
+public:
+
+ explicit SwXMLConditionParser_Impl( const OUString& rInp );
+
+ bool IsValid() const { return Master_CollCondition::NONE != m_nCondition; }
+
+ Master_CollCondition GetCondition() const { return m_nCondition; }
+ sal_uInt32 GetSubCondition() const { return m_nSubCondition; }
+};
+
+}
+
+inline bool SwXMLConditionParser_Impl::SkipWS()
+{
+ while( m_nPos < m_nLength && ' ' == m_sInput[m_nPos] )
+ m_nPos++;
+ return true;
+}
+
+inline bool SwXMLConditionParser_Impl::MatchChar( sal_Unicode c )
+{
+ bool bRet = false;
+ if( m_nPos < m_nLength && c == m_sInput[m_nPos] )
+ {
+ m_nPos++;
+ bRet = true;
+ }
+ return bRet;
+}
+
+inline bool SwXMLConditionParser_Impl::MatchName( OUString& rName )
+{
+ OUStringBuffer sBuffer( m_nLength );
+ while( m_nPos < m_nLength &&
+ ( ('a' <= m_sInput[m_nPos] && m_sInput[m_nPos] <= 'z') ||
+ '-' == m_sInput[m_nPos] ) )
+ {
+ sBuffer.append( m_sInput[m_nPos] );
+ m_nPos++;
+ }
+ rName = sBuffer.makeStringAndClear();
+ return !rName.isEmpty();
+}
+
+inline bool SwXMLConditionParser_Impl::MatchNumber( sal_uInt32& rNumber )
+{
+ OUStringBuffer sBuffer( m_nLength );
+ while( m_nPos < m_nLength && '0' <= m_sInput[m_nPos] && m_sInput[m_nPos] <= '9' )
+ {
+ sBuffer.append( m_sInput[m_nPos] );
+ m_nPos++;
+ }
+
+ OUString sNum( sBuffer.makeStringAndClear() );
+ if( !sNum.isEmpty() )
+ rNumber = sNum.toInt32();
+ return !sNum.isEmpty();
+}
+
+SwXMLConditionParser_Impl::SwXMLConditionParser_Impl( const OUString& rInp ) :
+ m_sInput( rInp ),
+ m_nCondition( Master_CollCondition::NONE ),
+ m_nSubCondition( 0 ),
+ m_nPos( 0 ),
+ m_nLength( rInp.getLength() )
+{
+ OUString sFunc;
+ bool bHasSub = false;
+ sal_uInt32 nSub = 0;
+ bool bOK = SkipWS() && MatchName( sFunc ) && SkipWS() &&
+ MatchChar( '(' ) && SkipWS() && MatchChar( ')' ) && SkipWS();
+ if( bOK && MatchChar( '=' ) )
+ {
+ bOK = SkipWS() && MatchNumber( nSub ) && SkipWS();
+ bHasSub = true;
+ }
+
+ bOK &= m_nPos == m_nLength;
+
+ if( !bOK )
+ return;
+
+ if( IsXMLToken( sFunc, XML_ENDNOTE ) && !bHasSub )
+ m_nCondition = Master_CollCondition::PARA_IN_ENDNOTE;
+ else if( IsXMLToken( sFunc, XML_FOOTER ) && !bHasSub )
+ m_nCondition = Master_CollCondition::PARA_IN_FOOTER;
+ else if( IsXMLToken( sFunc, XML_FOOTNOTE ) && !bHasSub )
+ m_nCondition = Master_CollCondition::PARA_IN_FOOTNOTE;
+ else if( IsXMLToken( sFunc, XML_HEADER ) && !bHasSub )
+ m_nCondition = Master_CollCondition::PARA_IN_HEADER;
+ else if( IsXMLToken( sFunc, XML_LIST_LEVEL) &&
+ nSub >=1 && nSub <= MAXLEVEL )
+ {
+ m_nCondition = Master_CollCondition::PARA_IN_LIST;
+ m_nSubCondition = nSub-1;
+ }
+ else if( IsXMLToken( sFunc, XML_OUTLINE_LEVEL) &&
+ nSub >=1 && nSub <= MAXLEVEL )
+ {
+ m_nCondition = Master_CollCondition::PARA_IN_OUTLINE;
+ m_nSubCondition = nSub-1;
+ }
+ else if( IsXMLToken( sFunc, XML_SECTION ) && !bHasSub )
+ {
+ m_nCondition = Master_CollCondition::PARA_IN_SECTION;
+ }
+ else if( IsXMLToken( sFunc, XML_TABLE ) && !bHasSub )
+ {
+ m_nCondition = Master_CollCondition::PARA_IN_TABLEBODY;
+ }
+ else if( IsXMLToken( sFunc, XML_TABLE_HEADER ) && !bHasSub )
+ {
+ m_nCondition = Master_CollCondition::PARA_IN_TABLEHEAD;
+ }
+ else if( IsXMLToken( sFunc, XML_TEXT_BOX ) && !bHasSub )
+ {
+ m_nCondition = Master_CollCondition::PARA_IN_FRAME;
+ }
+}
+
+namespace {
+
+class SwXMLConditionContext_Impl : public SvXMLImportContext
+{
+ Master_CollCondition m_nCondition;
+ sal_uInt32 m_nSubCondition;
+
+ OUString m_sApplyStyle;
+
+public:
+
+ SwXMLConditionContext_Impl(
+ SvXMLImport& rImport, sal_Int32 nElement,
+ const uno::Reference< xml::sax::XFastAttributeList > & xAttrList );
+
+ bool IsValid() const { return Master_CollCondition::NONE != m_nCondition; }
+
+ Master_CollCondition getCondition() const { return m_nCondition; }
+ sal_uInt32 getSubCondition() const { return m_nSubCondition; }
+ OUString const &getApplyStyle() const { return m_sApplyStyle; }
+};
+
+}
+
+SwXMLConditionContext_Impl::SwXMLConditionContext_Impl(
+ SvXMLImport& rImport, sal_Int32 /*nElement*/,
+ const uno::Reference< xml::sax::XFastAttributeList > & xAttrList ) :
+ SvXMLImportContext( rImport ),
+ m_nCondition( Master_CollCondition::NONE ),
+ m_nSubCondition( 0 )
+{
+ for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ))
+ {
+ OUString sValue = aIter.toString();
+ switch (aIter.getToken())
+ {
+ case XML_ELEMENT(STYLE, XML_CONDITION):
+ {
+ SwXMLConditionParser_Impl aCondParser( sValue );
+ if( aCondParser.IsValid() )
+ {
+ m_nCondition = aCondParser.GetCondition();
+ m_nSubCondition = aCondParser.GetSubCondition();
+ }
+ break;
+ }
+ case XML_ELEMENT(STYLE, XML_APPLY_STYLE_NAME):
+ m_sApplyStyle = sValue;
+ break;
+ default:
+ XMLOFF_WARN_UNKNOWN("sw", aIter);
+ }
+ }
+}
+
+typedef std::vector<rtl::Reference<SwXMLConditionContext_Impl>> SwXMLConditions_Impl;
+
+namespace {
+
+class SwXMLTextStyleContext_Impl : public XMLTextStyleContext
+{
+ std::unique_ptr<SwXMLConditions_Impl> m_pConditions;
+
+protected:
+
+ virtual uno::Reference < style::XStyle > Create() override;
+ virtual void Finish( bool bOverwrite ) override;
+
+public:
+
+
+ SwXMLTextStyleContext_Impl( SwXMLImport& rImport,
+ XmlStyleFamily nFamily,
+ SvXMLStylesContext& rStyles );
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+};
+
+}
+
+uno::Reference < style::XStyle > SwXMLTextStyleContext_Impl::Create()
+{
+ uno::Reference < style::XStyle > xNewStyle;
+ if( m_pConditions && XmlStyleFamily::TEXT_PARAGRAPH == GetFamily() )
+ {
+ uno::Reference< lang::XMultiServiceFactory > xFactory( GetImport().GetModel(),
+ uno::UNO_QUERY );
+ if( xFactory.is() )
+ {
+ uno::Reference < uno::XInterface > xIfc =
+ xFactory->createInstance( "com.sun.star.style.ConditionalParagraphStyle" );
+ if( xIfc.is() )
+ xNewStyle.set( xIfc, uno::UNO_QUERY );
+ }
+ }
+ else
+ {
+ xNewStyle = XMLTextStyleContext::Create();
+ }
+
+ return xNewStyle;
+}
+
+void
+SwXMLTextStyleContext_Impl::Finish( bool bOverwrite )
+{
+ if( m_pConditions && XmlStyleFamily::TEXT_PARAGRAPH == GetFamily() && GetStyle().is() )
+ {
+ CommandStruct const*const pCommands = SwCondCollItem::GetCmds();
+
+ Reference< XPropertySet > xPropSet( GetStyle(), UNO_QUERY );
+
+ uno::Sequence< beans::NamedValue > aSeq( m_pConditions->size() );
+ auto aSeqRange = asNonConstRange(aSeq);
+
+ for (std::vector<rtl::Reference<SwXMLConditionContext_Impl>>::size_type i = 0;
+ i < m_pConditions->size(); ++i)
+ {
+ assert((*m_pConditions)[i]->IsValid()); // checked before inserting
+ Master_CollCondition nCond = (*m_pConditions)[i]->getCondition();
+ sal_uInt32 nSubCond = (*m_pConditions)[i]->getSubCondition();
+
+ for (size_t j = 0; j < COND_COMMAND_COUNT; ++j)
+ {
+ if (pCommands[j].nCnd == nCond &&
+ pCommands[j].nSubCond == nSubCond)
+ {
+ aSeqRange[i].Name = GetCommandContextByIndex( j );
+ aSeqRange[i].Value <<= GetImport().GetStyleDisplayName(
+ GetFamily(), (*m_pConditions)[i]->getApplyStyle() );
+ break;
+ }
+ }
+ }
+
+ try
+ {
+ xPropSet->setPropertyValue(UNO_NAME_PARA_STYLE_CONDITIONS, uno::Any(aSeq));
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_WARN_EXCEPTION("sw.xml", "exception when setting ParaStyleConditions");
+ }
+ }
+ XMLTextStyleContext::Finish( bOverwrite );
+}
+
+SwXMLTextStyleContext_Impl::SwXMLTextStyleContext_Impl( SwXMLImport& rImport,
+ XmlStyleFamily nFamily,
+ SvXMLStylesContext& rStyles ) :
+ XMLTextStyleContext( rImport, rStyles, nFamily )
+{
+}
+
+css::uno::Reference< css::xml::sax::XFastContextHandler > SwXMLTextStyleContext_Impl::createFastChildContext(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
+{
+ if( nElement == XML_ELEMENT(STYLE, XML_MAP) )
+ {
+ rtl::Reference<SwXMLConditionContext_Impl> xCond{
+ new SwXMLConditionContext_Impl( GetImport(), nElement, xAttrList )};
+ if( xCond->IsValid() )
+ {
+ if( !m_pConditions )
+ m_pConditions = std::make_unique<SwXMLConditions_Impl>();
+ m_pConditions->push_back( xCond );
+ }
+ return xCond;
+ }
+
+ return XMLTextStyleContext::createFastChildContext( nElement, xAttrList );
+}
+
+namespace {
+
+class SwXMLCellStyleContext : public XMLPropStyleContext
+{
+ OUString m_sDataStyleName;
+ void AddDataFormat();
+public:
+ using XMLPropStyleContext::XMLPropStyleContext;
+ virtual void FillPropertySet(const css::uno::Reference<css::beans::XPropertySet>& rPropSet) override;
+ virtual void SetAttribute(sal_Int32 nElement, const OUString& rValue) override;
+};
+
+class SwXMLItemSetStyleContext_Impl : public SvXMLStyleContext
+{
+ OUString m_sMasterPageName;
+ std::optional<SfxItemSet> m_oItemSet;
+ SwXMLTextStyleContext_Impl *m_pTextStyle;
+ SvXMLStylesContext &m_rStyles;
+
+ OUString m_sDataStyleName;
+
+ bool m_bHasMasterPageName : 1;
+ bool m_bPageDescConnected : 1;
+ bool m_bDataStyleIsResolved;
+
+ SvXMLImportContext *CreateItemSetContext(
+ sal_Int32 nElement,
+ const uno::Reference< xml::sax::XFastAttributeList > & xAttrList);
+
+protected:
+
+ virtual void SetAttribute( sal_Int32 nElement,
+ const OUString& rValue ) override;
+
+ SwXMLImport& GetSwImport() { return static_cast<SwXMLImport&>(GetImport()); }
+
+public:
+
+
+ SwXMLItemSetStyleContext_Impl(
+ SwXMLImport& rImport,
+ SvXMLStylesContext& rStylesC,
+ XmlStyleFamily nFamily);
+
+ virtual void CreateAndInsert( bool bOverwrite ) override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+
+ // The item set may be empty!
+ SfxItemSet *GetItemSet() { return m_oItemSet ? &*m_oItemSet : nullptr; }
+
+ bool HasMasterPageName() const { return m_bHasMasterPageName; }
+
+ bool IsPageDescConnected() const { return m_bPageDescConnected; }
+ void ConnectPageDesc();
+
+ bool ResolveDataStyleName();
+};
+
+}
+
+void SwXMLCellStyleContext::AddDataFormat()
+{
+ if (m_sDataStyleName.isEmpty() || IsDefaultStyle())
+ return;
+
+ const SvXMLNumFormatContext* pStyle = static_cast<const SvXMLNumFormatContext*>(
+ GetStyles()->FindStyleChildContext(XmlStyleFamily::DATA_STYLE, m_sDataStyleName, true));
+
+ if (!pStyle)
+ {
+ SAL_WARN("sw.xml", "not possible to get data style " << m_sDataStyleName);
+ return;
+ }
+
+ sal_Int32 nNumberFormat = const_cast<SvXMLNumFormatContext*>(pStyle)->GetKey();
+ if (nNumberFormat < 0)
+ return;
+
+ rtl::Reference<SvXMLImportPropertyMapper> xPropertyMapper(GetStyles()->GetImportPropertyMapper(GetFamily()));
+ if (!xPropertyMapper.is())
+ {
+ SAL_WARN("sw.xml", "there is no import prop mapper");
+ return;
+ }
+
+ const rtl::Reference<XMLPropertySetMapper>& xPropertySetMapper(xPropertyMapper->getPropertySetMapper());
+ sal_Int32 nIndex = xPropertySetMapper->GetEntryIndex(XML_NAMESPACE_STYLE, GetXMLToken(XML_DATA_STYLE_NAME), 0);
+ if (nIndex < 0)
+ {
+ SAL_WARN("sw.xml", "could not find id for " << GetXMLToken(XML_DATA_STYLE_NAME));
+ return;
+ }
+
+ auto aIter = std::find_if(GetProperties().begin(), GetProperties().end(),
+ [&nIndex](const XMLPropertyState& rProp) {
+ return rProp.mnIndex == nIndex;
+ });
+
+ if (aIter != GetProperties().end())
+ aIter->maValue <<= nNumberFormat;
+ else
+ GetProperties().push_back(XMLPropertyState(nIndex, Any(nNumberFormat)));
+}
+
+void SwXMLCellStyleContext::FillPropertySet(const css::uno::Reference<css::beans::XPropertySet>& rPropSet)
+{
+ AddDataFormat();
+ XMLPropStyleContext::FillPropertySet(rPropSet);
+}
+
+void SwXMLCellStyleContext::SetAttribute(sal_Int32 nElement, const OUString& rValue)
+{
+ if ((nElement & TOKEN_MASK) == XML_DATA_STYLE_NAME)
+ m_sDataStyleName = rValue;
+ else
+ XMLPropStyleContext::SetAttribute(nElement, rValue);
+}
+
+void SwXMLItemSetStyleContext_Impl::SetAttribute( sal_Int32 nElement,
+ const OUString& rValue )
+{
+ switch(nElement)
+ {
+ case XML_ELEMENT(STYLE, XML_MASTER_PAGE_NAME):
+ {
+ m_sMasterPageName = rValue;
+ m_bHasMasterPageName = true;
+ break;
+ }
+ case XML_ELEMENT(STYLE, XML_DATA_STYLE_NAME):
+ {
+ // if we have a valid data style name
+ if (!rValue.isEmpty())
+ {
+ m_sDataStyleName = rValue;
+ m_bDataStyleIsResolved = false; // needs to be resolved
+ }
+ break;
+ }
+ default:
+ SvXMLStyleContext::SetAttribute( nElement, rValue );
+ }
+}
+
+SvXMLImportContext *SwXMLItemSetStyleContext_Impl::CreateItemSetContext(
+ sal_Int32 nElement,
+ const uno::Reference< xml::sax::XFastAttributeList > & xAttrList )
+{
+ OSL_ENSURE( !m_oItemSet,
+ "SwXMLItemSetStyleContext_Impl::CreateItemSetContext: item set exists" );
+
+ SvXMLImportContext *pContext = nullptr;
+
+ SwDoc* pDoc = GetSwImport().getDoc();
+
+ SfxItemPool& rItemPool = pDoc->GetAttrPool();
+ switch( GetFamily() )
+ {
+ case XmlStyleFamily::TABLE_TABLE:
+ m_oItemSet.emplace( rItemPool, aTableSetRange );
+ break;
+ case XmlStyleFamily::TABLE_COLUMN:
+ m_oItemSet.emplace( rItemPool, svl::Items<RES_FRM_SIZE, RES_FRM_SIZE> );
+ break;
+ case XmlStyleFamily::TABLE_ROW:
+ m_oItemSet.emplace( rItemPool, aTableLineSetRange );
+ break;
+ case XmlStyleFamily::TABLE_CELL:
+ m_oItemSet.emplace( rItemPool, aTableBoxSetRange );
+ break;
+ default:
+ OSL_ENSURE( false,
+ "SwXMLItemSetStyleContext_Impl::CreateItemSetContext: unknown family" );
+ break;
+ }
+ if( m_oItemSet )
+ pContext = GetSwImport().CreateTableItemImportContext(
+ nElement, xAttrList, GetFamily(),
+ *m_oItemSet );
+ if( !pContext )
+ {
+ m_oItemSet.reset();
+ }
+
+ return pContext;
+}
+
+
+SwXMLItemSetStyleContext_Impl::SwXMLItemSetStyleContext_Impl( SwXMLImport& rImport,
+ SvXMLStylesContext& rStylesC,
+ XmlStyleFamily nFamily ) :
+ SvXMLStyleContext( rImport, nFamily ),
+ m_pTextStyle( nullptr ),
+ m_rStyles( rStylesC ),
+ m_bHasMasterPageName( false ),
+ m_bPageDescConnected( false ),
+ m_bDataStyleIsResolved( true )
+{
+}
+
+void SwXMLItemSetStyleContext_Impl::CreateAndInsert( bool bOverwrite )
+{
+ if( m_pTextStyle )
+ m_pTextStyle->CreateAndInsert( bOverwrite );
+}
+
+css::uno::Reference< css::xml::sax::XFastContextHandler > SwXMLItemSetStyleContext_Impl::createFastChildContext(
+ sal_Int32 nElement,
+ const uno::Reference< xml::sax::XFastAttributeList > & xAttrList )
+{
+ switch (nElement)
+ {
+ case XML_ELEMENT(STYLE, XML_TABLE_PROPERTIES):
+ case XML_ELEMENT(STYLE, XML_TABLE_COLUMN_PROPERTIES):
+ case XML_ELEMENT(STYLE, XML_TABLE_ROW_PROPERTIES):
+ case XML_ELEMENT(STYLE, XML_TABLE_CELL_PROPERTIES):
+ return CreateItemSetContext( nElement, xAttrList );
+ case XML_ELEMENT(STYLE, XML_TEXT_PROPERTIES):
+ case XML_ELEMENT(STYLE, XML_PARAGRAPH_PROPERTIES):
+ {
+ if( !m_pTextStyle )
+ {
+ m_pTextStyle = new SwXMLTextStyleContext_Impl( GetSwImport(), XmlStyleFamily::TEXT_PARAGRAPH, m_rStyles );
+ rtl::Reference<sax_fastparser::FastAttributeList> xTmpAttrList = new sax_fastparser::FastAttributeList(nullptr);
+ xTmpAttrList->add(XML_ELEMENT(STYLE, XML_NAME), GetName().toUtf8() );
+ m_pTextStyle->startFastElement( nElement, xTmpAttrList );
+ m_rStyles.AddStyle( *m_pTextStyle );
+ }
+ return m_pTextStyle->createFastChildContext( nElement, xAttrList );
+ }
+ default:
+ XMLOFF_WARN_UNKNOWN_ELEMENT("sw", nElement);
+ }
+
+ return nullptr;
+}
+
+void SwXMLItemSetStyleContext_Impl::ConnectPageDesc()
+{
+ if( m_bPageDescConnected || !HasMasterPageName() )
+ return;
+ m_bPageDescConnected = true;
+
+ SwDoc *pDoc = GetSwImport().getDoc();
+
+ // #i40788# - first determine the display name of the page style,
+ // then map this name to the corresponding user interface name.
+ OUString sName = GetImport().GetStyleDisplayName( XmlStyleFamily::MASTER_PAGE,
+ m_sMasterPageName );
+ SwStyleNameMapper::FillUIName( sName,
+ sName,
+ SwGetPoolIdFromName::PageDesc);
+ SwPageDesc *pPageDesc = pDoc->FindPageDesc(sName);
+ if( !pPageDesc )
+ {
+ // If the page style is a pool style, then we maybe have to create it
+ // first if it hasn't been used by now.
+ const sal_uInt16 nPoolId = SwStyleNameMapper::GetPoolIdFromUIName( sName, SwGetPoolIdFromName::PageDesc );
+ if( USHRT_MAX != nPoolId )
+ pPageDesc = pDoc->getIDocumentStylePoolAccess().GetPageDescFromPool( nPoolId, false );
+ }
+
+ if( !pPageDesc )
+ return;
+
+ if( !m_oItemSet )
+ {
+ SfxItemPool& rItemPool = pDoc->GetAttrPool();
+ m_oItemSet.emplace( rItemPool, aTableSetRange );
+ }
+
+ std::unique_ptr<SwFormatPageDesc> pFormatPageDesc;
+ if( const SwFormatPageDesc* pItem = m_oItemSet->GetItemIfSet( RES_PAGEDESC, false ) )
+ {
+ if( pItem->GetPageDesc() != pPageDesc )
+ pFormatPageDesc.reset(new SwFormatPageDesc( *pItem ));
+ }
+ else
+ pFormatPageDesc.reset(new SwFormatPageDesc());
+
+ if( pFormatPageDesc )
+ {
+ pFormatPageDesc->RegisterToPageDesc( *pPageDesc );
+ m_oItemSet->Put( std::move(pFormatPageDesc) );
+ }
+}
+
+bool SwXMLItemSetStyleContext_Impl::ResolveDataStyleName()
+{
+ // resolve, if not already done
+ if (! m_bDataStyleIsResolved)
+ {
+ // get the format key
+ sal_Int32 nFormat =
+ GetImport().GetTextImport()->GetDataStyleKey(m_sDataStyleName);
+
+ // if the key is valid, insert Item into ItemSet
+ if( -1 != nFormat )
+ {
+ if( !m_oItemSet )
+ {
+ SwDoc *pDoc = GetSwImport().getDoc();
+
+ SfxItemPool& rItemPool = pDoc->GetAttrPool();
+ m_oItemSet.emplace( rItemPool, aTableBoxSetRange );
+ }
+ SwTableBoxNumFormat aNumFormatItem(nFormat);
+ m_oItemSet->Put(aNumFormatItem);
+ }
+
+ // now resolved
+ m_bDataStyleIsResolved = true;
+ return true;
+ }
+ else
+ {
+ // was already resolved; nothing to do
+ return false;
+ }
+}
+
+namespace {
+
+class SwXMLStylesContext_Impl : public SvXMLStylesContext
+{
+ SwXMLImport& GetSwImport() { return static_cast<SwXMLImport&>(GetImport()); }
+ const SwXMLImport& GetSwImport() const
+ { return static_cast<const SwXMLImport&>(GetImport()); }
+
+protected:
+
+ using SvXMLStylesContext::CreateStyleChildContext;
+ virtual SvXMLStyleContext *CreateStyleChildContext( sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList ) override;
+
+ using SvXMLStylesContext::CreateStyleStyleChildContext;
+ virtual SvXMLStyleContext *CreateStyleStyleChildContext( XmlStyleFamily nFamily,
+ sal_Int32 nElement,
+ const uno::Reference< xml::sax::XFastAttributeList > & xAttrList ) override;
+ using SvXMLStylesContext::CreateDefaultStyleStyleChildContext;
+ virtual SvXMLStyleContext *CreateDefaultStyleStyleChildContext(
+ XmlStyleFamily nFamily, sal_Int32 nElement,
+ const uno::Reference< xml::sax::XFastAttributeList > & xAttrList ) override;
+ // HACK
+ virtual rtl::Reference < SvXMLImportPropertyMapper > GetImportPropertyMapper(
+ XmlStyleFamily nFamily ) const override;
+
+ virtual uno::Reference < container::XNameContainer >
+ GetStylesContainer( XmlStyleFamily nFamily ) const override;
+ virtual OUString GetServiceName( XmlStyleFamily nFamily ) const override;
+ // HACK
+
+public:
+
+ SwXMLStylesContext_Impl(
+ SwXMLImport& rImport,
+ bool bAuto );
+
+ virtual bool InsertStyleFamily( XmlStyleFamily nFamily ) const override;
+
+ virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
+};
+
+}
+
+SvXMLStyleContext *SwXMLStylesContext_Impl::CreateStyleChildContext(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList )
+{
+ SvXMLStyleContext* pContext = nullptr;
+
+ if(nElement == XML_ELEMENT(TABLE, XML_TABLE_TEMPLATE))
+ {
+ rtl::Reference<XMLTableImport> xTableImport = GetImport().GetShapeImport()->GetShapeTableImport();
+ pContext = xTableImport->CreateTableTemplateContext(nElement, xAttrList);
+ }
+ if (!pContext)
+ pContext = SvXMLStylesContext::CreateStyleChildContext(nElement, xAttrList);
+
+ return pContext;
+}
+
+SvXMLStyleContext *SwXMLStylesContext_Impl::CreateStyleStyleChildContext(
+ XmlStyleFamily nFamily, sal_Int32 nElement,
+ const uno::Reference< xml::sax::XFastAttributeList > & xAttrList )
+{
+ SvXMLStyleContext *pStyle = nullptr;
+
+ switch( nFamily )
+ {
+ case XmlStyleFamily::TEXT_PARAGRAPH:
+ pStyle = new SwXMLTextStyleContext_Impl( GetSwImport(), nFamily, *this );
+ break;
+ case XmlStyleFamily::TABLE_TABLE:
+ case XmlStyleFamily::TABLE_COLUMN:
+ case XmlStyleFamily::TABLE_ROW:
+ case XmlStyleFamily::TABLE_CELL:
+ // Distinguish real and automatic styles.
+ if (IsAutomaticStyle())
+ pStyle = new SwXMLItemSetStyleContext_Impl(GetSwImport(), *this, nFamily);
+ else if (nFamily == XmlStyleFamily::TABLE_CELL) // Real cell styles are used for table-template import.
+ pStyle = new SwXMLCellStyleContext(GetSwImport(), *this, nFamily);
+ else
+ SAL_WARN("sw.xml", "Context does not exists for non automatic table, column or row style.");
+ break;
+ case XmlStyleFamily::SD_GRAPHICS_ID:
+ // As long as there are no element items, we can use the text
+ // style class.
+ pStyle = new XMLTextShapeStyleContext( GetImport(), *this, nFamily );
+ break;
+ case XmlStyleFamily::SD_DRAWINGPAGE_ID:
+ pStyle = new XMLDrawingPageStyleContext(GetImport(),
+ *this, g_MasterPageContextIDs, g_MasterPageFamilies);
+ break;
+ default:
+ pStyle = SvXMLStylesContext::CreateStyleStyleChildContext( nFamily,
+ nElement,
+ xAttrList );
+ break;
+ }
+
+ return pStyle;
+}
+
+SvXMLStyleContext *SwXMLStylesContext_Impl::CreateDefaultStyleStyleChildContext(
+ XmlStyleFamily nFamily, sal_Int32 nElement,
+ const uno::Reference< xml::sax::XFastAttributeList > & xAttrList )
+{
+ SvXMLStyleContext *pStyle = nullptr;
+
+ switch( nFamily )
+ {
+ case XmlStyleFamily::TEXT_PARAGRAPH:
+ case XmlStyleFamily::TABLE_TABLE:
+ case XmlStyleFamily::TABLE_ROW:
+ pStyle = new XMLTextStyleContext( GetImport(),
+ *this, nFamily,
+ true );
+ break;
+ case XmlStyleFamily::SD_GRAPHICS_ID:
+ // There are no writer specific defaults for graphic styles!
+ pStyle = new XMLGraphicsDefaultStyle( GetImport(), *this );
+ break;
+ default:
+ pStyle = SvXMLStylesContext::CreateDefaultStyleStyleChildContext( nFamily,
+ nElement,
+ xAttrList );
+ break;
+ }
+
+ return pStyle;
+}
+
+SwXMLStylesContext_Impl::SwXMLStylesContext_Impl(
+ SwXMLImport& rImport,
+ bool bAuto ) :
+ SvXMLStylesContext( rImport, bAuto )
+{
+}
+
+bool SwXMLStylesContext_Impl::InsertStyleFamily( XmlStyleFamily nFamily ) const
+{
+ const SwXMLImport& rSwImport = GetSwImport();
+ const SfxStyleFamily nStyleFamilyMask = rSwImport.GetStyleFamilyMask();
+
+ bool bIns = true;
+ switch( nFamily )
+ {
+ case XmlStyleFamily::TEXT_PARAGRAPH:
+ bIns = bool(nStyleFamilyMask & SfxStyleFamily::Para);
+ break;
+ case XmlStyleFamily::TEXT_TEXT:
+ bIns = bool(nStyleFamilyMask & SfxStyleFamily::Char);
+ break;
+ case XmlStyleFamily::SD_GRAPHICS_ID:
+ bIns = bool(nStyleFamilyMask & SfxStyleFamily::Frame);
+ break;
+ case XmlStyleFamily::TEXT_LIST:
+ bIns = bool(nStyleFamilyMask & SfxStyleFamily::Pseudo);
+ break;
+ case XmlStyleFamily::TEXT_OUTLINE:
+ case XmlStyleFamily::TEXT_FOOTNOTECONFIG:
+ case XmlStyleFamily::TEXT_ENDNOTECONFIG:
+ case XmlStyleFamily::TEXT_LINENUMBERINGCONFIG:
+ case XmlStyleFamily::TEXT_BIBLIOGRAPHYCONFIG:
+ bIns = !(rSwImport.IsInsertMode() || rSwImport.IsStylesOnlyMode() ||
+ rSwImport.IsBlockMode());
+ break;
+ default:
+ bIns = SvXMLStylesContext::InsertStyleFamily( nFamily );
+ break;
+ }
+
+ return bIns;
+}
+
+rtl::Reference < SvXMLImportPropertyMapper > SwXMLStylesContext_Impl::GetImportPropertyMapper(
+ XmlStyleFamily nFamily ) const
+{
+ rtl::Reference < SvXMLImportPropertyMapper > xMapper;
+ if( nFamily == XmlStyleFamily::TABLE_TABLE )
+ xMapper = XMLTextImportHelper::CreateTableDefaultExtPropMapper(
+ const_cast<SwXMLStylesContext_Impl*>( this )->GetImport() );
+ else if( nFamily == XmlStyleFamily::TABLE_ROW )
+ xMapper = XMLTextImportHelper::CreateTableRowDefaultExtPropMapper(
+ const_cast<SwXMLStylesContext_Impl*>( this )->GetImport() );
+ else if( nFamily == XmlStyleFamily::TABLE_CELL )
+ xMapper = XMLTextImportHelper::CreateTableCellExtPropMapper(
+ const_cast<SwXMLStylesContext_Impl*>( this )->GetImport() );
+ else if (nFamily == XmlStyleFamily::SD_DRAWINGPAGE_ID)
+ {
+ xMapper = XMLTextImportHelper::CreateDrawingPageExtPropMapper(
+ const_cast<SwXMLStylesContext_Impl*>(this)->GetImport());
+ }
+ else
+ xMapper = SvXMLStylesContext::GetImportPropertyMapper( nFamily );
+ return xMapper;
+}
+
+uno::Reference < container::XNameContainer > SwXMLStylesContext_Impl::GetStylesContainer(
+ XmlStyleFamily nFamily ) const
+{
+ uno::Reference < container::XNameContainer > xStyles;
+ if( XmlStyleFamily::SD_GRAPHICS_ID == nFamily )
+ xStyles = const_cast<SvXMLImport *>(&GetImport())->GetTextImport()->GetFrameStyles();
+ else if( XmlStyleFamily::TABLE_CELL == nFamily )
+ xStyles = const_cast<SvXMLImport *>(&GetImport())->GetTextImport()->GetCellStyles();
+
+ if (!xStyles.is())
+ xStyles = SvXMLStylesContext::GetStylesContainer( nFamily );
+
+ return xStyles;
+}
+
+OUString SwXMLStylesContext_Impl::GetServiceName( XmlStyleFamily nFamily ) const
+{
+ if( XmlStyleFamily::SD_GRAPHICS_ID == nFamily )
+ return "com.sun.star.style.FrameStyle";
+ else if( XmlStyleFamily::TABLE_CELL == nFamily )
+ return "com.sun.star.style.CellStyle";
+
+ return SvXMLStylesContext::GetServiceName( nFamily );
+}
+
+void SwXMLStylesContext_Impl::endFastElement(sal_Int32 )
+{
+ GetSwImport().InsertStyles( IsAutomaticStyle() );
+ if (!IsAutomaticStyle())
+ GetImport().GetShapeImport()->GetShapeTableImport()->finishStyles();
+}
+
+namespace {
+
+class SwXMLMasterStylesContext_Impl : public XMLTextMasterStylesContext
+{
+protected:
+ virtual bool InsertStyleFamily( XmlStyleFamily nFamily ) const override;
+
+ SwXMLImport& GetSwImport() { return static_cast<SwXMLImport&>(GetImport()); }
+ const SwXMLImport& GetSwImport() const
+ { return static_cast<const SwXMLImport&>(GetImport()); }
+
+public:
+
+
+ SwXMLMasterStylesContext_Impl( SwXMLImport& rImport );
+
+ virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
+};
+
+}
+
+SwXMLMasterStylesContext_Impl::SwXMLMasterStylesContext_Impl(
+ SwXMLImport& rImport ) :
+ XMLTextMasterStylesContext( rImport )
+{
+}
+
+bool SwXMLMasterStylesContext_Impl::InsertStyleFamily( XmlStyleFamily nFamily ) const
+{
+ bool bIns;
+
+ const SwXMLImport& rSwImport = GetSwImport();
+ const SfxStyleFamily nStyleFamilyMask = rSwImport.GetStyleFamilyMask();
+ if( XmlStyleFamily::MASTER_PAGE == nFamily )
+ bIns = bool(nStyleFamilyMask & SfxStyleFamily::Page);
+ else
+ bIns = XMLTextMasterStylesContext::InsertStyleFamily( nFamily );
+
+ return bIns;
+}
+
+void SwXMLMasterStylesContext_Impl::endFastElement(sal_Int32 )
+{
+ FinishStyles( !GetSwImport().IsInsertMode() );
+ GetSwImport().FinishStyles();
+}
+
+SvXMLImportContext *SwXMLImport::CreateStylesContext(
+ bool bAuto )
+{
+ SvXMLStylesContext *pContext = new SwXMLStylesContext_Impl( *this, bAuto );
+ if( bAuto )
+ SetAutoStyles( pContext );
+ else
+ SetStyles( pContext );
+
+ return pContext;
+}
+
+SvXMLImportContext *SwXMLImport::CreateMasterStylesContext()
+{
+ SvXMLStylesContext *pContext =
+ new SwXMLMasterStylesContext_Impl( *this );
+ SetMasterStyles( pContext );
+
+ return pContext;
+}
+
+void SwXMLImport::InsertStyles( bool bAuto )
+{
+ if( bAuto && GetAutoStyles() )
+ GetAutoStyles()->CopyAutoStylesToDoc();
+ if( !bAuto && GetStyles() )
+ GetStyles()->CopyStylesToDoc( !IsInsertMode(), false );
+}
+
+void SwXMLImport::FinishStyles()
+{
+ if( GetStyles() )
+ GetStyles()->FinishStyles( !IsInsertMode() );
+}
+
+void SwXMLImport::UpdateTextCollConditions( SwDoc *pDoc )
+{
+ if( !pDoc )
+ pDoc = getDoc();
+
+ const SwTextFormatColls& rColls = *pDoc->GetTextFormatColls();
+ const size_t nCount = rColls.size();
+ for( size_t i=0; i < nCount; ++i )
+ {
+ SwTextFormatColl *pColl = rColls[i];
+ if( pColl && RES_CONDTXTFMTCOLL == pColl->Which() )
+ {
+ const SwFormatCollConditions& rConditions =
+ static_cast<const SwConditionTextFormatColl *>(pColl)->GetCondColls();
+ bool bSendModify = false;
+ for( size_t j=0; j < rConditions.size() && !bSendModify; ++j )
+ {
+ const SwCollCondition& rCond = *rConditions[j];
+ switch( rCond.GetCondition() )
+ {
+ case Master_CollCondition::PARA_IN_TABLEHEAD:
+ case Master_CollCondition::PARA_IN_TABLEBODY:
+ case Master_CollCondition::PARA_IN_FOOTER:
+ case Master_CollCondition::PARA_IN_HEADER:
+ bSendModify = true;
+ break;
+ default: break;
+ }
+ }
+ if(bSendModify)
+ pColl->GetNotifier().Broadcast(sw::CondCollCondChg(*pColl));
+ }
+ }
+}
+
+bool SwXMLImport::FindAutomaticStyle(
+ XmlStyleFamily nFamily,
+ const OUString& rName,
+ const SfxItemSet **ppItemSet ) const
+{
+ SwXMLItemSetStyleContext_Impl *pStyle = nullptr;
+ if( GetAutoStyles() )
+ {
+ pStyle = const_cast<SwXMLItemSetStyleContext_Impl*>(dynamic_cast< const SwXMLItemSetStyleContext_Impl* >(
+ GetAutoStyles()->
+ FindStyleChildContext( nFamily, rName,
+ true ) ) );
+ if( pStyle )
+ {
+ if( ppItemSet )
+ {
+ if( XmlStyleFamily::TABLE_TABLE == pStyle->GetFamily() &&
+ pStyle->HasMasterPageName() &&
+ !pStyle->IsPageDescConnected() )
+ pStyle->ConnectPageDesc();
+ (*ppItemSet) = pStyle->GetItemSet();
+
+ // resolve data style name late
+ if( XmlStyleFamily::TABLE_CELL == pStyle->GetFamily() &&
+ pStyle->ResolveDataStyleName() )
+ {
+ (*ppItemSet) = pStyle->GetItemSet();
+ }
+
+ }
+ }
+ }
+
+ return pStyle != nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlfmte.cxx b/sw/source/filter/xml/xmlfmte.cxx
new file mode 100644
index 0000000000..8e20f46e42
--- /dev/null
+++ b/sw/source/filter/xml/xmlfmte.cxx
@@ -0,0 +1,389 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <xmloff/xmlnamespace.hxx>
+#include "xmlexpit.hxx"
+#include <xmloff/namespacemap.hxx>
+#include <xmloff/XMLTextListAutoStylePool.hxx>
+#include <xmloff/XMLTextMasterPageExport.hxx>
+#include <xmloff/table/XMLTableExport.hxx>
+
+#include <xmloff/txtprmap.hxx>
+#include <xmloff/xmlaustp.hxx>
+#include <xmloff/families.hxx>
+#include <xmloff/maptype.hxx>
+#include <format.hxx>
+#include <fmtpdsc.hxx>
+#include <pagedesc.hxx>
+#include <cellatr.hxx>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/util/Color.hpp>
+#include "xmlexp.hxx"
+#include <SwStyleNameMapper.hxx>
+#include <osl/diagnose.h>
+#include <comphelper/sequenceashashmap.hxx>
+
+#include <svx/unoapi.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdmodel.hxx>
+#include <docmodel/theme/ThemeColorType.hxx>
+#include <docmodel/theme/Theme.hxx>
+
+
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::lang;
+using namespace ::xmloff::token;
+
+void SwXMLExport::ExportFormat(const SwFormat& rFormat, enum XMLTokenEnum eFamily,
+ ::std::optional<OUString> const oStyleName)
+{
+ // <style:style ...>
+ CheckAttrList();
+
+ // style:family="..."
+ OSL_ENSURE( RES_FRMFMT==rFormat.Which(), "frame format expected" );
+ if( RES_FRMFMT != rFormat.Which() )
+ return;
+ OSL_ENSURE( eFamily != XML_TOKEN_INVALID, "family must be specified" );
+ // style:name="..."
+ assert(oStyleName || (eFamily != XML_TABLE_ROW && eFamily != XML_TABLE_CELL));
+ bool bEncoded = false;
+ OUString const name(oStyleName ? *oStyleName : rFormat.GetName());
+ AddAttribute(XML_NAMESPACE_STYLE, XML_NAME, EncodeStyleName(name, &bEncoded));
+ if( bEncoded )
+ {
+ AddAttribute(XML_NAMESPACE_STYLE, XML_DISPLAY_NAME, name);
+ }
+
+ if( eFamily != XML_TOKEN_INVALID )
+ AddAttribute( XML_NAMESPACE_STYLE, XML_FAMILY, eFamily );
+
+#if OSL_DEBUG_LEVEL > 0
+ // style:parent-style-name="..." (if it's not the default only)
+ const SwFormat* pParent = rFormat.DerivedFrom();
+ // Only adopt parent name, if it's not the default
+ OSL_ENSURE( !pParent || pParent->IsDefault(), "unexpected parent" );
+
+ OSL_ENSURE( USHRT_MAX == rFormat.GetPoolFormatId(), "pool ids aren't supported" );
+ OSL_ENSURE( USHRT_MAX == rFormat.GetPoolHelpId(), "help ids aren't supported" );
+ OSL_ENSURE( USHRT_MAX == rFormat.GetPoolHelpId() ||
+ UCHAR_MAX == rFormat.GetPoolHlpFileId(), "help file ids aren't supported" );
+#endif
+
+ // style:master-page-name
+ if( RES_FRMFMT == rFormat.Which() && XML_TABLE == eFamily )
+ {
+ if( const SwFormatPageDesc* pItem = rFormat.GetAttrSet().GetItemIfSet( RES_PAGEDESC,
+ false ) )
+ {
+ OUString sName;
+ const SwPageDesc *pPageDesc = pItem->GetPageDesc();
+ if( pPageDesc )
+ SwStyleNameMapper::FillProgName(
+ pPageDesc->GetName(),
+ sName,
+ SwGetPoolIdFromName::PageDesc);
+ AddAttribute( XML_NAMESPACE_STYLE, XML_MASTER_PAGE_NAME,
+ EncodeStyleName( sName ) );
+ }
+ }
+
+ if( XML_TABLE_CELL == eFamily )
+ {
+ OSL_ENSURE(RES_FRMFMT == rFormat.Which(), "only frame format");
+
+ if( const SwTableBoxNumFormat *pItem =
+ rFormat.GetAttrSet().GetItemIfSet( RES_BOXATR_FORMAT, false ) )
+ {
+ sal_Int32 nFormat = static_cast<sal_Int32>(pItem->GetValue());
+
+ if ( (nFormat != -1) && (nFormat != static_cast<sal_Int32>(getSwDefaultTextFormat())) )
+ {
+ // if we have a format, register and then export
+ // (Careful: here we assume that data styles will be
+ // written after cell styles)
+ addDataStyle(nFormat);
+ OUString sDataStyleName = getDataStyleName(nFormat);
+ if( !sDataStyleName.isEmpty() )
+ AddAttribute( XML_NAMESPACE_STYLE, XML_DATA_STYLE_NAME,
+ sDataStyleName );
+ }
+ }
+ }
+
+ {
+ SvXMLElementExport aElem( *this, XML_NAMESPACE_STYLE, XML_STYLE,
+ true, true );
+
+ SvXMLItemMapEntriesRef xItemMap;
+ XMLTokenEnum ePropToken = XML_TABLE_PROPERTIES;
+ if( XML_TABLE == eFamily )
+ {
+ xItemMap = m_xTableItemMap;
+ }
+ else if( XML_TABLE_ROW == eFamily )
+ {
+ xItemMap = m_xTableRowItemMap;
+ ePropToken = XML_TABLE_ROW_PROPERTIES;
+ }
+ else if( XML_TABLE_CELL == eFamily )
+ {
+ xItemMap = m_xTableCellItemMap;
+ ePropToken = XML_TABLE_CELL_PROPERTIES;
+ }
+
+ if( xItemMap.is() )
+ {
+ m_pTableItemMapper->setMapEntries( xItemMap );
+ m_pTableItemMapper->exportXML( *this,
+ rFormat.GetAttrSet(),
+ GetTwipUnitConverter(),
+ ePropToken );
+ }
+ }
+}
+
+void SwXMLExport::ExportStyles_( bool bUsed )
+{
+ SvXMLExport::ExportStyles_( bUsed );
+
+ // drawing defaults
+ GetShapeExport()->ExportGraphicDefaults();
+
+ GetTextParagraphExport()->exportTextStyles( bUsed
+ ,IsShowProgress()
+ );
+ collectDataStyles(true);
+ exportDataStyles();
+ GetShapeExport()->GetShapeTableExport()->exportTableStyles();
+ //page defaults
+ GetPageExport()->exportDefaultStyle();
+
+ // Theme
+ exportTheme();
+}
+
+void SwXMLExport::exportTheme()
+{
+ if ((getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0)
+ return;
+
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(GetModel(), UNO_QUERY);
+ if (!xDrawPageSupplier.is())
+ return;
+
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ if (!xDrawPage.is())
+ return;
+
+ SdrPage* pPage = GetSdrPageFromXDrawPage(xDrawPage);
+ SAL_WARN_IF(!pPage, "oox", "Can't get SdrPage from XDrawPage");
+
+ if (!pPage)
+ return;
+
+ auto const& pTheme = pPage->getSdrModelFromSdrPage().getTheme();
+ if (!pTheme)
+ return;
+
+ ExportThemeElement(pTheme);
+}
+
+void SwXMLExport::collectAutoStyles()
+{
+ SvXMLExport::collectAutoStyles();
+
+ if (mbAutoStylesCollected)
+ return;
+
+ // The order in which styles are collected *MUST* be the same as
+ // the order in which they are exported. Otherwise, caching will
+ // fail.
+ if( getExportFlags() & (SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::CONTENT) )
+ {
+ if( !(getExportFlags() & SvXMLExportFlags::CONTENT) )
+ {
+ // only master pages are exported => styles for frames bound
+ // to frames (but none for frames bound to pages) need to be
+ // collected.
+ // TODO: exclude PageBoundFrames on export
+ }
+ }
+
+ // exported in _ExportMasterStyles
+ if( getExportFlags() & SvXMLExportFlags::MASTERSTYLES )
+ GetPageExport()->collectAutoStyles( false );
+
+
+ // exported in ExportContent_
+ if( getExportFlags() & SvXMLExportFlags::CONTENT )
+ {
+ // collect form autostyle
+ // (do this before collectTextAutoStyles, 'cause the shapes need the results of the work
+ // done by examineForms)
+ Reference<XDrawPageSupplier> xDrawPageSupplier( GetModel(), UNO_QUERY );
+ if (xDrawPageSupplier.is() && GetFormExport().is())
+ {
+ Reference<XDrawPage> xPage = xDrawPageSupplier->getDrawPage();
+ if (xPage.is())
+ GetFormExport()->examineForms(xPage);
+ }
+
+ GetTextParagraphExport()->collectTextAutoStylesOptimized( m_bShowProgress );
+ }
+
+ mbAutoStylesCollected = true;
+}
+
+void SwXMLExport::ExportAutoStyles_()
+{
+ collectAutoStyles();
+
+ // if we don't export styles (i.e. in content stream only, but not
+ // in single-stream case), then we can save ourselves a bit of
+ // work and memory by not collecting field masters
+ if( !(getExportFlags() & SvXMLExportFlags::STYLES) )
+ GetTextParagraphExport()->exportUsedDeclarations();
+
+ // exported in ExportContent_
+ if( getExportFlags() & SvXMLExportFlags::CONTENT )
+ {
+ GetTextParagraphExport()->exportTrackedChanges( true );
+ }
+
+ GetTextParagraphExport()->exportTextAutoStyles();
+ GetShapeExport()->exportAutoStyles();
+ if( getExportFlags() & SvXMLExportFlags::MASTERSTYLES )
+ GetPageExport()->exportAutoStyles();
+
+ // we rely on data styles being written after cell styles in the
+ // ExportFormat() method; so be careful when changing order.
+ exportAutoDataStyles();
+
+ SvXMLExportFlags nContentAutostyles = SvXMLExportFlags::CONTENT | SvXMLExportFlags::AUTOSTYLES;
+ if ( ( getExportFlags() & nContentAutostyles ) == nContentAutostyles )
+ GetFormExport()->exportAutoStyles();
+}
+
+XMLPageExport* SwXMLExport::CreatePageExport()
+{
+ return new XMLTextMasterPageExport( *this );
+}
+
+void SwXMLExport::ExportMasterStyles_()
+{
+ // export master styles
+ GetPageExport()->exportMasterStyles( false );
+}
+
+namespace {
+
+class SwXMLAutoStylePoolP : public SvXMLAutoStylePoolP
+{
+ SvXMLExport& m_rExport;
+ const OUString m_sListStyleName;
+ const OUString m_sMasterPageName;
+
+protected:
+
+ virtual void exportStyleAttributes(
+ comphelper::AttributeList& rAttrList,
+ XmlStyleFamily nFamily,
+ const std::vector< XMLPropertyState >& rProperties,
+ const SvXMLExportPropertyMapper& rPropExp
+ , const SvXMLUnitConverter& rUnitConverter,
+ const SvXMLNamespaceMap& rNamespaceMap
+ ) const override;
+public:
+
+ explicit SwXMLAutoStylePoolP( SvXMLExport& rExport );
+};
+
+}
+
+void SwXMLAutoStylePoolP::exportStyleAttributes(
+ comphelper::AttributeList& rAttrList,
+ XmlStyleFamily nFamily,
+ const std::vector< XMLPropertyState >& rProperties,
+ const SvXMLExportPropertyMapper& rPropExp
+ , const SvXMLUnitConverter& rUnitConverter,
+ const SvXMLNamespaceMap& rNamespaceMap
+ ) const
+{
+ SvXMLAutoStylePoolP::exportStyleAttributes( rAttrList, nFamily, rProperties, rPropExp, rUnitConverter, rNamespaceMap);
+
+ if( XmlStyleFamily::TEXT_PARAGRAPH != nFamily )
+ return;
+
+ for( const auto& rProperty : rProperties )
+ {
+ if (rProperty.mnIndex != -1) // #i26762#
+ {
+ switch( rPropExp.getPropertySetMapper()->
+ GetEntryContextId( rProperty.mnIndex ) )
+ {
+ case CTF_NUMBERINGSTYLENAME:
+ {
+ OUString sStyleName;
+ rProperty.maValue >>= sStyleName;
+ // #i70748# - export also empty list styles
+ if( !sStyleName.isEmpty() )
+ {
+ OUString sTmp = m_rExport.GetTextParagraphExport()->GetListAutoStylePool().Find( sStyleName );
+ if( !sTmp.isEmpty() )
+ sStyleName = sTmp;
+ }
+ GetExport().AddAttribute( XML_NAMESPACE_STYLE,
+ m_sListStyleName,
+ GetExport().EncodeStyleName( sStyleName ) );
+ }
+ break;
+ case CTF_PAGEDESCNAME:
+ {
+ OUString sStyleName;
+ rProperty.maValue >>= sStyleName;
+ GetExport().AddAttribute( XML_NAMESPACE_STYLE,
+ m_sMasterPageName,
+ GetExport().EncodeStyleName( sStyleName ) );
+ }
+ break;
+ }
+ }
+ }
+}
+
+SwXMLAutoStylePoolP::SwXMLAutoStylePoolP(SvXMLExport& rExp ) :
+ SvXMLAutoStylePoolP( rExp ),
+ m_rExport( rExp ),
+ m_sListStyleName( GetXMLToken( XML_LIST_STYLE_NAME ) ),
+ m_sMasterPageName( GetXMLToken( XML_MASTER_PAGE_NAME ) )
+{
+}
+
+SvXMLAutoStylePoolP* SwXMLExport::CreateAutoStylePool()
+{
+ return new SwXMLAutoStylePoolP( *this );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlfonte.cxx b/sw/source/filter/xml/xmlfonte.cxx
new file mode 100644
index 0000000000..c6a9c89cb6
--- /dev/null
+++ b/sw/source/filter/xml/xmlfonte.cxx
@@ -0,0 +1,143 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <hintids.hxx>
+#include <xmloff/XMLFontAutoStylePool.hxx>
+#include <editeng/fontitem.hxx>
+#include <doc.hxx>
+#include "xmlexp.hxx"
+#include "xmlimp.hxx"
+#include <IDocumentSettingAccess.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::text;
+
+namespace {
+
+class SwXMLFontAutoStylePool_Impl: public XMLFontAutoStylePool
+{
+public:
+ SwXMLFontAutoStylePool_Impl(SwXMLExport& rExport, bool bFontEmbedding);
+};
+
+}
+
+namespace
+{
+sal_Int32 CompareTo(sal_Int32 nA, sal_Int32 nB)
+{
+ if (nA < nB)
+ {
+ return -1;
+ }
+
+ if (nA > nB)
+ {
+ return 1;
+ }
+
+ return 0;
+}
+}
+
+SwXMLFontAutoStylePool_Impl::SwXMLFontAutoStylePool_Impl(SwXMLExport& _rExport, bool bFontEmbedding)
+ : XMLFontAutoStylePool(_rExport, bFontEmbedding)
+{
+ sal_uInt16 const aWhichIds[3] = { RES_CHRATR_FONT, RES_CHRATR_CJK_FONT,
+ RES_CHRATR_CTL_FONT };
+
+ const SfxItemPool& rPool = _rExport.getDoc()->GetAttrPool();
+ std::vector<const SvxFontItem *> aFonts;
+ for(sal_uInt16 nWhichId : aWhichIds)
+ {
+ const SvxFontItem& rFont =
+ static_cast<const SvxFontItem&>(rPool.GetDefaultItem( nWhichId ));
+ aFonts.push_back(&rFont);
+ for (const SfxPoolItem* pItem : rPool.GetItemSurrogates(nWhichId))
+ {
+ auto pFont = static_cast<const SvxFontItem *>(pItem);
+ aFonts.push_back(pFont);
+ }
+ }
+
+ std::sort(aFonts.begin(), aFonts.end(),
+ [](const SvxFontItem* pA, const SvxFontItem* pB) -> bool
+ {
+ sal_Int32 nRet = pA->GetFamilyName().compareTo(pB->GetFamilyName());
+ if (nRet != 0)
+ {
+ return nRet < 0;
+ }
+
+ nRet = pA->GetStyleName().compareTo(pB->GetStyleName());
+ if (nRet != 0)
+ {
+ return nRet < 0;
+ }
+
+ nRet = CompareTo(pA->GetFamily(), pB->GetFamily());
+ if (nRet != 0)
+ {
+ return nRet < 0;
+ }
+
+ nRet = CompareTo(pA->GetPitch(), pB->GetPitch());
+ if (nRet != 0)
+ {
+ return nRet < 0;
+ }
+
+ return pA->GetCharSet() < pB->GetCharSet();
+ });
+ for (const auto& pFont : aFonts)
+ {
+ Add(pFont->GetFamilyName(), pFont->GetStyleName(), pFont->GetFamily(), pFont->GetPitch(),
+ pFont->GetCharSet());
+ }
+
+ auto const & pDocument = _rExport.getDoc();
+
+ m_bEmbedUsedOnly = pDocument->getIDocumentSettingAccess().get(DocumentSettingId::EMBED_USED_FONTS);
+ m_bEmbedLatinScript = pDocument->getIDocumentSettingAccess().get(DocumentSettingId::EMBED_LATIN_SCRIPT_FONTS);
+ m_bEmbedAsianScript = pDocument->getIDocumentSettingAccess().get(DocumentSettingId::EMBED_ASIAN_SCRIPT_FONTS);
+ m_bEmbedComplexScript = pDocument->getIDocumentSettingAccess().get(DocumentSettingId::EMBED_COMPLEX_SCRIPT_FONTS);
+
+}
+
+XMLFontAutoStylePool* SwXMLExport::CreateFontAutoStylePool()
+{
+ bool blockFontEmbedding = false;
+ // We write font info to both content.xml and styles.xml, but they are both
+ // written by different SwXMLExport instance, and would therefore write each
+ // font file twice without complicated checking for duplicates, so handle
+ // the embedding only in one of them.
+ if( !( getExportFlags() & SvXMLExportFlags::CONTENT) )
+ blockFontEmbedding = true;
+ if( !getDoc()->getIDocumentSettingAccess().get( DocumentSettingId::EMBED_FONTS ))
+ blockFontEmbedding = true;
+ return new SwXMLFontAutoStylePool_Impl( *this, !blockFontEmbedding );
+}
+
+void SwXMLImport::NotifyContainsEmbeddedFont()
+{
+ getDoc()->getIDocumentSettingAccess().set( DocumentSettingId::EMBED_FONTS, true );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlimp.cxx b/sw/source/filter/xml/xmlimp.cxx
new file mode 100644
index 0000000000..81ddfbbb5f
--- /dev/null
+++ b/sw/source/filter/xml/xmlimp.cxx
@@ -0,0 +1,1924 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <cassert>
+
+#include <com/sun/star/document/PrinterIndependentLayout.hpp>
+#include <com/sun/star/document/XExporter.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+
+#include <o3tl/any.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/xmlictxt.hxx>
+#include <xmloff/txtimp.hxx>
+#include <xmloff/XMLTextShapeImportHelper.hxx>
+#include <xmloff/XMLFontStylesContext.hxx>
+#include <xmloff/ProgressBarHelper.hxx>
+#include <doc.hxx>
+#include <drawdoc.hxx>
+#include <IDocumentSettingAccess.hxx>
+#include <IDocumentDeviceAccess.hxx>
+#include <IDocumentListsAccess.hxx>
+#include <IDocumentStylePoolAccess.hxx>
+#include <IDocumentDrawModelAccess.hxx>
+#include <TextCursorHelper.hxx>
+#include <unotext.hxx>
+#include <unotextrange.hxx>
+#include <poolfmt.hxx>
+#include <ndtxt.hxx>
+#include <editsh.hxx>
+#include <strings.hrc>
+#include <svl/stritem.hxx>
+#include "xmlimp.hxx"
+#include "xmlimpit.hxx"
+#include "xmltexti.hxx"
+#include <list.hxx>
+#include <swdll.hxx>
+#include <xmloff/DocumentSettingsContext.hxx>
+#include <docsh.hxx>
+#include <svx/xmlgrhlp.hxx>
+#include <svx/xmleohlp.hxx>
+#include <sfx2/printer.hxx>
+#include <sfx2/sfxmodelfactory.hxx>
+#include <xmloff/xmluconv.hxx>
+#include <unotools/fcm.hxx>
+#include <unotools/mediadescriptor.hxx>
+#include <unotools/streamwrap.hxx>
+#include <unotools/tempfile.hxx>
+#include <tools/UnitConversion.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+#include <vcl/svapp.hxx>
+#include <unotxdoc.hxx>
+#include <numrule.hxx>
+
+#include <xmloff/xmlmetai.hxx>
+#include <xmloff/xformsimport.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <officecfg/Office/Common.hxx>
+
+#include <unordered_set>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::i18n;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::xforms;
+using namespace ::xmloff::token;
+
+namespace {
+
+class SwXMLBodyContext_Impl : public SvXMLImportContext
+{
+ SwXMLImport& GetSwImport() { return static_cast<SwXMLImport&>(GetImport()); }
+
+public:
+
+ SwXMLBodyContext_Impl( SwXMLImport& rImport );
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+};
+
+}
+
+SwXMLBodyContext_Impl::SwXMLBodyContext_Impl( SwXMLImport& rImport ) :
+ SvXMLImportContext( rImport )
+{
+ // tdf#107211: if at this point we don't have a defined char style "Default"
+ // or "Default Style", add a mapping for it as it is not written
+ // into the file since it's not really a style but "no style"
+ // (hence referencing it actually makes no sense except for hyperlinks
+ // which default to something other than "Default")
+ OUString const sDefault(SwResId(STR_POOLCHR_STANDARD));
+ uno::Reference<container::XNameContainer> const& xStyles(
+ rImport.GetTextImport()->GetTextStyles());
+ if (!xStyles->hasByName("Default"))
+ { // this old name was used before LO 4.0
+ rImport.AddStyleDisplayName(XmlStyleFamily::TEXT_TEXT, "Default", sDefault);
+ }
+ if (!xStyles->hasByName("Default_20_Style"))
+ { // this new name contains a space which is converted to _20_ on export
+ rImport.AddStyleDisplayName(XmlStyleFamily::TEXT_TEXT, "Default_20_Style", sDefault);
+ }
+ bool isEncoded(false);
+ OUString const defaultEncoded(
+ rImport.GetMM100UnitConverter().encodeStyleName(sDefault, &isEncoded));
+ if (isEncoded && defaultEncoded != "Default_20_Style"
+ && !xStyles->hasByName(defaultEncoded))
+ { // new name may contain a space which is converted to _20_ on export
+ rImport.AddStyleDisplayName(XmlStyleFamily::TEXT_TEXT, defaultEncoded, sDefault);
+ }
+}
+
+css::uno::Reference< css::xml::sax::XFastContextHandler > SwXMLBodyContext_Impl::createFastChildContext(
+ sal_Int32 /*nElement*/,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/ )
+{
+ return GetSwImport().CreateBodyContentContext();
+}
+
+namespace {
+
+// #i69629#
+// enhance class <SwXMLDocContext_Impl> in order to be able to create subclasses
+// NB: virtually inherit so we can multiply inherit properly
+// in SwXMLOfficeDocContext_Impl
+class SwXMLDocContext_Impl : public virtual SvXMLImportContext
+{
+ sal_Int32 mnElement;
+
+protected: // #i69629#
+ SwXMLImport& GetSwImport() { return static_cast<SwXMLImport&>(GetImport()); }
+
+public:
+ SwXMLDocContext_Impl( SwXMLImport& rImport, sal_Int32 nElement );
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override;
+};
+
+}
+
+SwXMLDocContext_Impl::SwXMLDocContext_Impl( SwXMLImport& rImport, sal_Int32 nElement ) :
+ SvXMLImportContext( rImport ), mnElement(nElement)
+{
+}
+
+uno::Reference< xml::sax::XFastContextHandler > SAL_CALL SwXMLDocContext_Impl::createFastChildContext(
+ sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& /*xAttrList*/ )
+{
+ switch (nElement)
+ {
+ case XML_ELEMENT(OFFICE, XML_SCRIPTS):
+ return GetSwImport().CreateScriptContext();
+ case XML_ELEMENT(OFFICE, XML_SETTINGS):
+ return new XMLDocumentSettingsContext( GetImport() );
+ case XML_ELEMENT(OFFICE, XML_STYLES):
+ GetSwImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ return GetSwImport().CreateStylesContext( false );
+ case XML_ELEMENT(OFFICE, XML_AUTOMATIC_STYLES):
+ // don't use the autostyles from the styles-document for the progress
+ if ( mnElement != 0 && (mnElement & TOKEN_MASK) != XML_DOCUMENT_STYLES )
+ GetSwImport().GetProgressBarHelper()->Increment
+ ( PROGRESS_BAR_STEP );
+ return GetSwImport().CreateStylesContext( true );
+ case XML_ELEMENT(OFFICE, XML_MASTER_STYLES):
+ return GetSwImport().CreateMasterStylesContext();
+ case XML_ELEMENT(OFFICE, XML_FONT_FACE_DECLS):
+ return GetSwImport().CreateFontDeclsContext();
+ case XML_ELEMENT(OFFICE, XML_META):
+ OSL_FAIL(" XML_ELEMENT(OFFICE, XML_META): should not have come here, maybe document is invalid?");
+ break;
+ case XML_ELEMENT(OFFICE, XML_BODY):
+ GetSwImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ return new SwXMLBodyContext_Impl( GetSwImport() );
+ case XML_ELEMENT(XFORMS, XML_MODEL):
+ return createXFormsModelContext(GetImport());
+ default:
+ XMLOFF_WARN_UNKNOWN_ELEMENT("sw", nElement);
+ }
+ return nullptr;
+}
+
+namespace {
+
+// #i69629# - new subclass <SwXMLOfficeDocContext_Impl> of class <SwXMLDocContext_Impl>
+class SwXMLOfficeDocContext_Impl :
+ public SwXMLDocContext_Impl, public SvXMLMetaDocumentContext
+{
+public:
+
+ SwXMLOfficeDocContext_Impl( SwXMLImport& rImport, sal_Int32 nElement,
+ const Reference< document::XDocumentProperties >& xDocProps);
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs ) override;
+};
+
+}
+
+SwXMLOfficeDocContext_Impl::SwXMLOfficeDocContext_Impl(
+ SwXMLImport& rImport,
+ sal_Int32 nElement,
+ const Reference< document::XDocumentProperties >& xDocProps) :
+ SvXMLImportContext( rImport ),
+ SwXMLDocContext_Impl( rImport, nElement ),
+ SvXMLMetaDocumentContext( rImport, xDocProps )
+{
+}
+
+uno::Reference< xml::sax::XFastContextHandler > SAL_CALL SwXMLOfficeDocContext_Impl::createFastChildContext(
+ sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList )
+{
+ // assign paragraph styles to list levels of outline style after all styles
+ // are imported and finished. This is the case, when <office:body> starts
+ // in flat OpenDocument file format.
+ {
+ if( nElement == XML_ELEMENT( OFFICE, XML_BODY ) )
+ {
+ GetImport().GetTextImport()->SetOutlineStyles( true );
+ }
+ }
+
+ // behave like meta base class iff we encounter office:meta
+ if ( nElement == XML_ELEMENT( OFFICE, XML_META ) ) {
+ return SvXMLMetaDocumentContext::createFastChildContext(
+ nElement, xAttrList );
+ } else {
+ return SwXMLDocContext_Impl::createFastChildContext(
+ nElement, xAttrList );
+ }
+}
+
+namespace {
+
+// #i69629# - new subclass <SwXMLDocStylesContext_Impl> of class <SwXMLDocContext_Impl>
+class SwXMLDocStylesContext_Impl : public SwXMLDocContext_Impl
+{
+public:
+
+ SwXMLDocStylesContext_Impl( SwXMLImport& rImport, sal_Int32 nElement );
+
+ virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
+};
+
+}
+
+SwXMLDocStylesContext_Impl::SwXMLDocStylesContext_Impl( SwXMLImport& rImport, sal_Int32 nElement ) :
+ SvXMLImportContext( rImport ),
+ SwXMLDocContext_Impl( rImport, nElement )
+{
+}
+
+void SwXMLDocStylesContext_Impl::endFastElement(sal_Int32 )
+{
+ // assign paragraph styles to list levels of outline style after all styles
+ // are imported and finished.
+ SwXMLImport& rSwImport = dynamic_cast<SwXMLImport&>( GetImport());
+ GetImport().GetTextImport()->SetOutlineStyles(
+ bool(rSwImport.GetStyleFamilyMask() & SfxStyleFamily::Para));
+}
+
+SvXMLImportContext *SwXMLImport::CreateFastContext( sal_Int32 nElement,
+ const uno::Reference< xml::sax::XFastAttributeList >& /*xAttrList*/ )
+{
+ SvXMLImportContext *pContext = nullptr;
+
+ switch (nElement)
+ {
+ case XML_ELEMENT( OFFICE, XML_DOCUMENT_META ):
+ pContext = CreateMetaContext(nElement);
+ break;
+ case XML_ELEMENT( OFFICE, XML_DOCUMENT ):
+ {
+ uno::Reference<document::XDocumentProperties> const xDocProps(
+ GetDocumentProperties());
+ // flat OpenDocument file format
+ pContext = new SwXMLOfficeDocContext_Impl( *this, nElement, xDocProps );
+ }
+ break;
+ // #i69629# - own subclasses for <office:document> and <office:document-styles>
+ case XML_ELEMENT(OFFICE, XML_DOCUMENT_SETTINGS):
+ case XML_ELEMENT(OFFICE, XML_DOCUMENT_CONTENT):
+ pContext = new SwXMLDocContext_Impl( *this, nElement );
+ break;
+ case XML_ELEMENT(OFFICE, XML_DOCUMENT_STYLES):
+ pContext = new SwXMLDocStylesContext_Impl( *this, nElement );
+ break;
+ }
+ return pContext;
+}
+
+SwXMLImport::SwXMLImport(
+ const uno::Reference< uno::XComponentContext >& rContext,
+ OUString const & implementationName, SvXMLImportFlags nImportFlags)
+: SvXMLImport( rContext, implementationName, nImportFlags ),
+ m_nStyleFamilyMask( SfxStyleFamily::All ),
+ m_bLoadDoc( true ),
+ m_bInsert( false ),
+ m_bBlock( false ),
+ m_bOrganizerMode( false ),
+ m_bInititedXForms( false ),
+ m_pDoc( nullptr ),
+ m_sDefTableName(SwResId(STR_TABLE_DEFNAME))
+{
+ InitItemImport();
+}
+
+SwXMLImport::~SwXMLImport() noexcept
+{
+ if (HasShapeImport())
+ {
+ SAL_WARN("sw", "endDocument skipped, dropping shapes now to avoid dangling SvTextShapeImportHelper pointing to this");
+ ClearShapeImport();
+ }
+ FinitItemImport();
+ // Call cleanup() here because the destruction of some stuff like XMLRedlineImportHelper will cast
+ // to cast their mrImport to SwXMLImport and that is illegal after this destructor is done.
+ cleanup();
+}
+
+void SwXMLImport::setTextInsertMode(
+ const Reference< XTextRange > & rInsertPos )
+{
+ m_bInsert = true;
+
+ Reference < XText > xText = rInsertPos->getText();
+ Reference < XTextCursor > xTextCursor =
+ xText->createTextCursorByRange( rInsertPos );
+ GetTextImport()->SetCursor( xTextCursor );
+}
+
+void SwXMLImport::setStyleInsertMode( SfxStyleFamily nFamilies,
+ bool bOverwrite )
+{
+ m_bInsert = !bOverwrite;
+ m_nStyleFamilyMask = nFamilies;
+ m_bLoadDoc = false;
+}
+
+static OTextCursorHelper *lcl_xml_GetSwXTextCursor( const Reference < XTextCursor >& rTextCursor )
+{
+ OTextCursorHelper* pTextCursor = dynamic_cast<OTextCursorHelper*>(rTextCursor.get());
+ OSL_ENSURE( pTextCursor, "SwXTextCursor missing" );
+ return pTextCursor;
+}
+
+void SwXMLImport::startDocument()
+{
+ // delegate to parent
+ SvXMLImport::startDocument();
+
+ OSL_ENSURE( GetModel().is(), "model is missing" );
+ if( !GetModel().is() )
+ return;
+
+ // this method will modify the document directly -> lock SolarMutex
+ SolarMutexGuard aGuard;
+
+ Reference< XPropertySet > xImportInfo( getImportInfo() );
+ Reference< XPropertySetInfo > xPropertySetInfo;
+ if( xImportInfo.is() )
+ xPropertySetInfo = xImportInfo->getPropertySetInfo();
+ if( xPropertySetInfo.is() )
+ {
+ Any aAny;
+ // insert style mode?
+ OUString sStyleInsertModeFamilies("StyleInsertModeFamilies");
+ if( xPropertySetInfo->hasPropertyByName(sStyleInsertModeFamilies) )
+ {
+ aAny = xImportInfo->getPropertyValue(sStyleInsertModeFamilies);
+ Sequence< OUString> aFamiliesSeq;
+ if( aAny >>= aFamiliesSeq )
+ {
+ SfxStyleFamily nFamilyMask = SfxStyleFamily::None;
+ for( const OUString& rFamily : std::as_const(aFamiliesSeq) )
+ {
+ if( rFamily=="FrameStyles" )
+ nFamilyMask |= SfxStyleFamily::Frame;
+ else if( rFamily=="PageStyles" )
+ nFamilyMask |= SfxStyleFamily::Page;
+ else if( rFamily=="CharacterStyles" )
+ nFamilyMask |= SfxStyleFamily::Char;
+ else if( rFamily=="ParagraphStyles" )
+ nFamilyMask |= SfxStyleFamily::Para;
+ else if( rFamily=="NumberingStyles" )
+ nFamilyMask |= SfxStyleFamily::Pseudo;
+ }
+
+ bool bOverwrite = false;
+ static constexpr OUString sStyleInsertModeOverwrite(u"StyleInsertModeOverwrite"_ustr);
+ if( xPropertySetInfo->hasPropertyByName(sStyleInsertModeOverwrite) )
+ {
+ aAny = xImportInfo->getPropertyValue(sStyleInsertModeOverwrite);
+ if( auto b = o3tl::tryAccess<bool>(aAny) )
+ {
+ if( *b )
+ bOverwrite = true;
+ }
+ }
+
+ setStyleInsertMode( nFamilyMask, bOverwrite );
+ }
+ }
+
+ // text insert mode?
+ static constexpr OUString sTextInsertModeRange(u"TextInsertModeRange"_ustr);
+ if( xPropertySetInfo->hasPropertyByName(sTextInsertModeRange) )
+ {
+ aAny = xImportInfo->getPropertyValue(sTextInsertModeRange);
+ Reference<XTextRange> xInsertTextRange;
+ if( aAny >>= xInsertTextRange )
+ setTextInsertMode( xInsertTextRange );
+ }
+
+ // auto text mode
+ static constexpr OUString sAutoTextMode(u"AutoTextMode"_ustr);
+ if( xPropertySetInfo->hasPropertyByName(sAutoTextMode) )
+ {
+ aAny = xImportInfo->getPropertyValue(sAutoTextMode);
+ if( auto b = o3tl::tryAccess<bool>(aAny) )
+ {
+ if( *b )
+ m_bBlock = true;
+ }
+ }
+
+ // organizer mode
+ static constexpr OUString sOrganizerMode(u"OrganizerMode"_ustr);
+ if( xPropertySetInfo->hasPropertyByName(sOrganizerMode) )
+ {
+ aAny = xImportInfo->getPropertyValue(sOrganizerMode);
+ if( auto b = o3tl::tryAccess<bool>(aAny) )
+ {
+ if( *b )
+ m_bOrganizerMode = true;
+ }
+ }
+
+ // default document properties
+ static constexpr OUString sDefSettings(u"DefaultDocumentSettings"_ustr);
+ if (xPropertySetInfo->hasPropertyByName(sDefSettings))
+ {
+ aAny = xImportInfo->getPropertyValue(sDefSettings);
+ Sequence<PropertyValue> aProps;
+ if (aAny >>= aProps)
+ {
+ Reference<lang::XMultiServiceFactory> xFac(GetModel(), UNO_QUERY);
+ Reference<XPropertySet> xProps(
+ xFac->createInstance("com.sun.star.document.Settings"), UNO_QUERY);
+ Reference<XPropertySetInfo> xInfo(xProps->getPropertySetInfo());
+
+ if (xProps.is() && xInfo.is())
+ {
+ for (const auto& rProp : std::as_const(aProps))
+ {
+ if (xInfo->hasPropertyByName(rProp.Name))
+ {
+ xProps->setPropertyValue(rProp.Name, rProp.Value);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // There only is a text cursor by now if we are in insert mode. In any
+ // other case we have to create one at the start of the document.
+ // We also might change into the insert mode later, so we have to make
+ // sure to first set the insert mode and then create the text import
+ // helper. Otherwise it won't have the insert flag set!
+ OTextCursorHelper *pTextCursor = nullptr;
+ Reference < XTextCursor > xTextCursor;
+ if( HasTextImport() )
+ xTextCursor = GetTextImport()->GetCursor();
+ if( !xTextCursor.is() )
+ {
+ Reference < XTextDocument > xTextDoc( GetModel(), UNO_QUERY );
+ Reference < XText > xText = xTextDoc->getText();
+ xTextCursor = xText->createTextCursor();
+ SwCursorShell *pCursorSh = nullptr;
+ SwDoc *pDoc = nullptr;
+ if( SvXMLImportFlags::ALL == getImportFlags() )
+ {
+ pTextCursor = lcl_xml_GetSwXTextCursor( xTextCursor );
+ OSL_ENSURE( pTextCursor, "SwXTextCursor missing" );
+ if( !pTextCursor )
+ return;
+
+ pDoc = pTextCursor->GetDoc();
+ OSL_ENSURE( pDoc, "SwDoc missing" );
+ if( !pDoc )
+ return;
+
+ // Is there an edit shell. If yes, then we are currently inserting
+ // a document. We then have to insert at the current edit shell's
+ // cursor position. That not quite clean code, but there is no other
+ // way currently.
+ pCursorSh = pDoc->GetEditShell();
+ }
+ if( pCursorSh )
+ {
+ const rtl::Reference<SwXTextRange> xInsertTextRange(
+ SwXTextRange::CreateXTextRange(
+ *pDoc, *pCursorSh->GetCursor()->GetPoint(), nullptr ) );
+ setTextInsertMode( xInsertTextRange );
+ xTextCursor = GetTextImport()->GetCursor();
+ pTextCursor = nullptr;
+ }
+ else
+ GetTextImport()->SetCursor( xTextCursor );
+ }
+
+ if( !(getImportFlags() & (SvXMLImportFlags::CONTENT|SvXMLImportFlags::MASTERSTYLES)) )
+ return;
+
+ if( !pTextCursor )
+ pTextCursor = lcl_xml_GetSwXTextCursor( xTextCursor );
+ OSL_ENSURE( pTextCursor, "SwXTextCursor missing" );
+ if( !pTextCursor )
+ return;
+
+ SwDoc *pDoc = pTextCursor->GetDoc();
+ OSL_ENSURE( pDoc, "SwDoc missing" );
+ if( !pDoc )
+ return;
+
+ if (SvXMLImportFlags::ALL == getImportFlags())
+ {
+ // for flat ODF - this is done in SwReader::Read() for package ODF
+ pDoc->SetInReading(true);
+ pDoc->SetInXMLImport(true);
+ }
+
+ if( (getImportFlags() & SvXMLImportFlags::CONTENT) && !IsStylesOnlyMode() )
+ {
+ m_oSttNdIdx.emplace( pDoc->GetNodes() );
+ if( IsInsertMode() )
+ {
+ SwPaM *pPaM = pTextCursor->GetPaM();
+ const SwPosition* pPos = pPaM->GetPoint();
+
+ // Split once and remember the node that has been split.
+ pDoc->getIDocumentContentOperations().SplitNode( *pPos, false );
+ *m_oSttNdIdx = pPos->GetNodeIndex()-1;
+
+ // Split again.
+ pDoc->getIDocumentContentOperations().SplitNode( *pPos, false );
+
+ // Insert all content into the new node
+ pPaM->Move( fnMoveBackward );
+ pDoc->SetTextFormatColl
+ ( *pPaM, pDoc->getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD, false ) );
+ }
+ }
+
+ // We need a draw model to be able to set the z order
+ pDoc->getIDocumentDrawModelAccess().GetOrCreateDrawModel(); // #i52858# - method name changed
+
+ // SJ: #i49801# locking the model to disable repaints
+ SwDrawModel* pDrawModel = pDoc->getIDocumentDrawModelAccess().GetDrawModel();
+ if ( pDrawModel )
+ pDrawModel->setLock(true);
+
+ if (!GetGraphicStorageHandler().is())
+ {
+ m_xGraphicStorageHandler = SvXMLGraphicHelper::Create(SvXMLGraphicHelperMode::Read);
+ SetGraphicStorageHandler(m_xGraphicStorageHandler);
+ }
+
+ if( !GetEmbeddedResolver().is() )
+ {
+ SfxObjectShell *pPersist = pDoc->GetPersist();
+ if( pPersist )
+ {
+ m_xEmbeddedResolver = SvXMLEmbeddedObjectHelper::Create(
+ *pPersist,
+ SvXMLEmbeddedObjectHelperMode::Read );
+ SetEmbeddedResolver( m_xEmbeddedResolver );
+ }
+ }
+}
+
+void SwXMLImport::endDocument()
+{
+ OSL_ENSURE( GetModel().is(), "model missing; maybe startDocument wasn't called?" );
+ if( !GetModel().is() )
+ return;
+
+ // this method will modify the document directly -> lock SolarMutex
+ SolarMutexGuard aGuard;
+
+ if (m_xGraphicStorageHandler)
+ m_xGraphicStorageHandler->dispose();
+ m_xGraphicStorageHandler.clear();
+
+ if( m_xEmbeddedResolver )
+ m_xEmbeddedResolver->dispose();
+ m_xEmbeddedResolver.clear();
+ // Clear the shape import to sort the shapes (and not in the
+ // destructor that might be called after the import has finished
+ // for Java filters.
+ if( HasShapeImport() )
+ ClearShapeImport();
+
+ SwDoc *pDoc = nullptr;
+ if( (getImportFlags() & SvXMLImportFlags::CONTENT) && !IsStylesOnlyMode() )
+ {
+ Reference<XInterface> xCursorTunnel( GetTextImport()->GetCursor(),
+ UNO_QUERY);
+ assert(xCursorTunnel.is() && "missing XUnoTunnel for Cursor");
+ OTextCursorHelper* pTextCursor = dynamic_cast<OTextCursorHelper*>(xCursorTunnel.get());
+ assert(pTextCursor && "SwXTextCursor missing");
+ SwPaM *pPaM = pTextCursor->GetPaM();
+ if( IsInsertMode() && m_oSttNdIdx->GetIndex() )
+ {
+ // If we are in insert mode, join the split node that is in front
+ // of the new content with the first new node. Or in other words:
+ // Revert the first split node.
+ SwTextNode* pTextNode = m_oSttNdIdx->GetNode().GetTextNode();
+ SwNodeIndex aNxtIdx( *m_oSttNdIdx );
+ if( pTextNode && pTextNode->CanJoinNext( &aNxtIdx ) &&
+ m_oSttNdIdx->GetIndex() + 1 == aNxtIdx.GetIndex() )
+ {
+ // If the PaM points to the first new node, move the PaM to the
+ // end of the previous node.
+ if( pPaM->GetPoint()->GetNode() == aNxtIdx.GetNode() )
+ {
+ pPaM->GetPoint()->Assign( *pTextNode,
+ pTextNode->GetText().getLength());
+ }
+
+#if OSL_DEBUG_LEVEL > 0
+ // !!! This should be impossible !!!!
+ OSL_ENSURE( m_oSttNdIdx->GetIndex()+1 !=
+ pPaM->GetBound().GetNodeIndex(),
+ "PaM.Bound1 point to new node " );
+ OSL_ENSURE( m_oSttNdIdx->GetIndex()+1 !=
+ pPaM->GetBound( false ).GetNodeIndex(),
+ "PaM.Bound2 points to new node" );
+
+ if( m_oSttNdIdx->GetIndex()+1 ==
+ pPaM->GetBound().GetNodeIndex() )
+ {
+ const sal_Int32 nCntPos =
+ pPaM->GetBound().GetContentIndex();
+ pPaM->GetBound().SetContent(
+ pTextNode->GetText().getLength() + nCntPos );
+ }
+ if( m_oSttNdIdx->GetIndex()+1 ==
+ pPaM->GetBound( false ).GetNodeIndex() )
+ {
+ const sal_Int32 nCntPos =
+ pPaM->GetBound( false ).GetContentIndex();
+ pPaM->GetBound( false ).SetContent(
+ pTextNode->GetText().getLength() + nCntPos );
+ }
+#endif
+ // If the first new node isn't empty, convert the node's text
+ // attributes into hints. Otherwise, set the new node's
+ // paragraph style at the previous (empty) node.
+ SwTextNode* pDelNd = aNxtIdx.GetNode().GetTextNode();
+ if (!pTextNode->GetText().isEmpty())
+ pDelNd->FormatToTextAttr( pTextNode );
+ else
+ {
+ pTextNode->ResetAttr(RES_CHRATR_BEGIN, RES_CHRATR_END);
+ pTextNode->ChgFormatColl( pDelNd->GetTextColl() );
+ if (!pDelNd->GetNoCondAttr(RES_PARATR_LIST_ID, /*bInParents=*/false))
+ {
+ // MergeListsAtDocumentInsertPosition() will deal with lists below, copy
+ // paragraph direct formatting otherwise.
+ pDelNd->CopyCollFormat(*pTextNode);
+ }
+ }
+ pTextNode->JoinNext();
+ }
+ }
+
+ SwPosition* pPos = pPaM->GetPoint();
+ OSL_ENSURE( !pPos->GetContentIndex(), "last paragraph isn't empty" );
+ if( !pPos->GetContentIndex() )
+ {
+ SwTextNode* pCurrNd;
+ SwNodeOffset nNodeIdx = pPos->GetNodeIndex();
+ pDoc = &pPaM->GetDoc();
+
+ OSL_ENSURE( pPos->GetNode().IsContentNode(),
+ "insert position is not a content node" );
+ if( !IsInsertMode() )
+ {
+ // If we're not in insert mode, the last node is deleted.
+ const SwNode *pPrev = pDoc->GetNodes()[nNodeIdx -1];
+ if( pPrev->IsContentNode() ||
+ ( pPrev->IsEndNode() &&
+ pPrev->StartOfSectionNode()->IsSectionNode() ) )
+ {
+ SwContentNode* pCNd = pPaM->GetPointContentNode();
+ if( pCNd && pCNd->StartOfSectionIndex()+2 <
+ pCNd->EndOfSectionIndex() )
+ {
+ SwNode& rDelNode = pPaM->GetPoint()->GetNode();
+ // move so we don't have a dangling SwContentIndex to the deleted node
+ pPaM->GetPoint()->Adjust(SwNodeOffset(+1));
+ if (pPaM->HasMark())
+ pPaM->GetMark()->Adjust(SwNodeOffset(+1));
+ pDoc->GetNodes().Delete( rDelNode );
+ }
+ }
+ }
+ else if( nullptr != (pCurrNd = pDoc->GetNodes()[nNodeIdx]->GetTextNode()) )
+ {
+ // Id we're in insert mode, the empty node is joined with
+ // the next and the previous one.
+ if( pCurrNd->CanJoinNext( pPos ))
+ {
+ SwTextNode* pNextNd = pPos->GetNode().GetTextNode();
+ bool endNodeFound = pDoc->GetNodes()[nNodeIdx-1]->IsEndNode();
+ SwNode *pLastPar = pDoc->GetNodes()[nNodeIdx -2];
+ if ( !pLastPar->IsTextNode() ) {
+ pLastPar = pDoc->GetNodes()[nNodeIdx -1];
+ }
+ if ( !endNodeFound && pLastPar->IsTextNode() )
+ {
+ pNextNd->ChgFormatColl(pLastPar->GetTextNode()->GetTextColl());
+ }
+
+ pPaM->SetMark(); pPaM->DeleteMark();
+ pNextNd->JoinPrev();
+
+ // Remove line break that has been inserted by the import,
+ // but only if one has been inserted and
+ // no endNode found to avoid removing section
+ if( pNextNd->CanJoinPrev(/* &pPos->nNode*/ ) && !endNodeFound &&
+ *m_oSttNdIdx != pPos->GetNode() )
+ {
+ pNextNd->JoinPrev();
+ }
+ }
+ else if (pCurrNd->GetText().isEmpty())
+ {
+ pPaM->SetMark(); pPaM->DeleteMark();
+ SwNode& rDelNode = pPos->GetNode();
+ // move so we don't have a dangling SwContentIndex to the deleted node
+ pPaM->GetPoint()->Adjust(SwNodeOffset(+1));
+ pDoc->GetNodes().Delete( rDelNode );
+ pPaM->Move( fnMoveBackward );
+ }
+ }
+
+ // tdf#113877
+ // when we insert one document with list inside into another one with list at the insert position,
+ // the resulting numbering in these lists is not consequent.
+ //
+ // Main document:
+ // 1. One
+ // 2. Two
+ // 3. Three
+ // 4. <-- insert position
+ //
+ // Inserted document:
+ // 1. One
+ // 2. Two
+ // 3. Three
+ // 4.
+ //
+ // Expected result
+ // 1. One
+ // 2. Two
+ // 3. Three
+ // 4. One
+ // 5. Two
+ // 6. Three
+ // 7.
+ //
+ MergeListsAtDocumentInsertPosition(pDoc);
+ }
+ }
+
+ /* Was called too early. Moved from SwXMLBodyContext_Impl::EndElement */
+
+ GetTextImport()->RedlineAdjustStartNodeCursor();
+
+ if( (getImportFlags() & SvXMLImportFlags::CONTENT) ||
+ ((getImportFlags() & SvXMLImportFlags::MASTERSTYLES) && IsStylesOnlyMode()) )
+ {
+ // pDoc might be 0. In this case UpdateTextCollCondition is looking
+ // for it itself.
+ UpdateTextCollConditions( pDoc );
+ }
+
+ GetTextImport()->ResetCursor();
+
+ m_oSttNdIdx.reset();
+
+ // tdf#150753: pDoc may be null e.g. when the package lacks content.xml;
+ // we should not forget to tidy up here, including unlocking draw model
+ if (!pDoc)
+ pDoc = getDoc();
+ assert(pDoc);
+ // SJ: #i49801# -> now permitting repaints
+ if (getImportFlags() == SvXMLImportFlags::ALL)
+ {
+ // Notify math objects. If we are in the package filter this will
+ // be done by the filter object itself
+ if (IsInsertMode())
+ pDoc->PrtOLENotify(false);
+ else if (pDoc->IsOLEPrtNotifyPending())
+ pDoc->PrtOLENotify(true);
+
+ assert(pDoc->IsInReading());
+ assert(pDoc->IsInXMLImport());
+ pDoc->SetInReading(false);
+ pDoc->SetInXMLImport(false);
+ }
+
+ SwDrawModel* pDrawModel = pDoc->getIDocumentDrawModelAccess().GetDrawModel();
+ if (pDrawModel)
+ pDrawModel->setLock(false);
+
+ // #i90243#
+ if ( m_bInititedXForms )
+ {
+ Reference< xforms::XFormsSupplier > xFormsSupp( GetModel(), UNO_QUERY );
+ Reference< XNameAccess > xXForms;
+ if ( xFormsSupp.is() )
+ xXForms = xFormsSupp->getXForms().get();
+
+ if ( xXForms.is() )
+ {
+ try
+ {
+ Sequence< beans::PropertyValue > aXFormsSettings;
+
+ const OUString& sXFormsSettingsName( GetXMLToken( XML_XFORM_MODEL_SETTINGS ) );
+ if ( m_xLateInitSettings.is() && m_xLateInitSettings->hasByName( sXFormsSettingsName ) )
+ {
+ OSL_VERIFY( m_xLateInitSettings->getByName( sXFormsSettingsName ) >>= aXFormsSettings );
+ applyXFormsSettings( xXForms, aXFormsSettings );
+ }
+ }
+ catch( const Exception& )
+ {
+ }
+ }
+ }
+
+ for (SwNodeOffset i(0); i < pDoc->GetNodes().Count(); ++i)
+ {
+ if (SwTableNode *const pTableNode = pDoc->GetNodes()[i]->GetTableNode())
+ {
+ if (!pTableNode->GetTable().IsNewModel()
+ && pTableNode->GetTable().CanConvertSubtables())
+ {
+ pTableNode->GetTable().ConvertSubtables();
+ }
+ }
+ // don't skip to the end; nested tables could have subtables too...
+ }
+
+ // delegate to parent: takes care of error handling
+ SvXMLImport::endDocument();
+ ClearTextImport();
+}
+
+// tdf#113877
+// when we insert one document with list inside into another one with list at the insert position,
+// the resulting numbering in these lists is not consequent.
+//
+// CASE-1: Main document:
+// 1. One
+// 2. Two
+// 3. Three
+// 4. <-- insert position
+//
+// Inserted document:
+// 1. One
+// 2. Two
+// 3. Three
+// 4.
+//
+// Expected result
+// 1. One
+// 2. Two
+// 3. Three
+// 4. One
+// 5. Two
+// 6. Three
+// 7.
+//
+// CASE-2: Main document:
+// 1. One
+// 2. Two
+// 3. Three
+// 4. <-- insert position
+//
+// Inserted document:
+// A) One
+// B) Two
+// C) Three
+// D)
+//
+// Expected result
+// 1. One
+// 2. Two
+// 3. Three
+// 4. One
+// A) Two
+// B) Three
+// 5.
+//
+void SwXMLImport::MergeListsAtDocumentInsertPosition(SwDoc *pDoc)
+{
+ // 1. check environment
+ if (! pDoc)
+ return;
+
+ if (! IsInsertMode() || ! m_oSttNdIdx->GetIndex())
+ return;
+
+ SwNodeOffset index(1);
+
+ // the last node of the main document where we have inserted a document
+ SwNode* const node1 = pDoc->GetNodes()[m_oSttNdIdx->GetIndex() + 0];
+
+ // the first node of the inserted document
+ SwNode* node2 = pDoc->GetNodes()[m_oSttNdIdx->GetIndex() + index];
+
+ if (! (node1 && node2
+ && (node1->GetNodeType() == node2->GetNodeType())
+ && (node1->IsTextNode() == node2->IsTextNode())
+ ))
+ {
+ // not a text node at insert position
+ return;
+ }
+
+ // 2. get the first node of the inserted document,
+ // which will be used to detect if inside inserted document a new list was started after the first list
+ const SfxPoolItem* pListId2Initial = nullptr;
+ {
+ SwContentNode* contentNode1 = static_cast<SwContentNode *>(node1);
+ SwContentNode* contentNode2 = static_cast<SwContentNode *>(node2);
+
+ // check if both lists have the same list properties
+ const SfxPoolItem* pListId1 = contentNode1->GetNoCondAttr( RES_PARATR_LIST_ID, false );
+ const SfxPoolItem* pListId2 = contentNode2->GetNoCondAttr( RES_PARATR_LIST_ID, false );
+
+ if (! pListId1)
+ return;
+ if (! pListId2)
+ return;
+
+ auto pStringListId1 = dynamic_cast<const SfxStringItem*>(pListId1);
+ assert(pStringListId1);
+ const OUString& sListId1 = pStringListId1->GetValue();
+ auto pStringListId2 = dynamic_cast<const SfxStringItem*>(pListId2);
+ assert(pStringListId2);
+ const OUString& sListId2 = pStringListId2->GetValue();
+
+ const SwList* pList1 = pDoc->getIDocumentListsAccess().getListByName( sListId1 );
+ const SwList* pList2 = pDoc->getIDocumentListsAccess().getListByName( sListId2 );
+
+ if (! pList1)
+ return;
+ if (! pList2)
+ return;
+
+ const OUString& sDefaultListStyleName1 = pList1->GetDefaultListStyleName();
+ const OUString& sDefaultListStyleName2 = pList2->GetDefaultListStyleName();
+
+ if (sDefaultListStyleName1 != sDefaultListStyleName2)
+ {
+ const SwNumRule* pNumRule1 = pDoc->FindNumRulePtr( sDefaultListStyleName1 );
+ const SwNumRule* pNumRule2 = pDoc->FindNumRulePtr( sDefaultListStyleName2 );
+
+ if (pNumRule1 && pNumRule2)
+ {
+ // check style of the each list level
+ for( sal_uInt8 n = 0; n < MAXLEVEL; ++n )
+ {
+ if( pNumRule1->Get( n ) != pNumRule2->Get( n ) )
+ {
+ return;
+ }
+ }
+
+ // our list should be merged
+ pListId2Initial = pListId2;
+ }
+ }
+ else
+ {
+ // our list should be merged
+ pListId2Initial = pListId2;
+ }
+ }
+
+ if (! pListId2Initial)
+ {
+ // two lists have different styles => they should not be merged
+ return;
+ }
+
+ // 3. merge two lists
+ while (
+ node1 && node2
+ && (node1->GetNodeType() == node2->GetNodeType())
+ && (node1->IsTextNode() == node2->IsTextNode())
+ )
+ {
+ SwContentNode* contentNode1 = static_cast<SwContentNode *>( node1 );
+ SwContentNode* contentNode2 = static_cast<SwContentNode *>( node2 );
+
+ const SfxPoolItem* pListId1 = contentNode1->GetNoCondAttr( RES_PARATR_LIST_ID, false );
+ const SfxPoolItem* pListId2 = contentNode2->GetNoCondAttr( RES_PARATR_LIST_ID, false );
+
+ if (! pListId1)
+ return;
+ if (! pListId2)
+ return;
+
+ if (*pListId2Initial != *pListId2)
+ {
+ // no more list items of the first list inside inserted document
+ return;
+ }
+
+ // set list style to this list element
+ contentNode2->SetAttr(*pListId1);
+
+ // get next item
+ index++;
+ if (index >= pDoc->GetNodes().Count())
+ {
+ // no more items
+ return;
+ }
+
+ node2 = pDoc->GetNodes()[m_oSttNdIdx->GetIndex() + index];
+ }
+}
+
+namespace {
+
+// Locally derive XMLTextShapeImportHelper, so we can take care of the
+// form import This is Writer, but not text specific, so it should go
+// here!
+class SvTextShapeImportHelper : public XMLTextShapeImportHelper
+{
+ // hold own reference form import helper, because the SvxImport
+ // stored in the superclass, from whom we originally got the
+ // reference, is already destroyed when we want to use it in the
+ // destructor
+ rtl::Reference< ::xmloff::OFormLayerXMLImport > rFormImport;
+
+ // hold reference to the one page (if it exists) for calling startPage()
+ // and endPage. If !xPage.is(), then this document doesn't have a
+ // XDrawPage.
+ Reference<drawing::XDrawPage> xPage;
+
+public:
+ explicit SvTextShapeImportHelper(SvXMLImport& rImp);
+ virtual ~SvTextShapeImportHelper() override;
+};
+
+}
+
+SvTextShapeImportHelper::SvTextShapeImportHelper(SvXMLImport& rImp) :
+ XMLTextShapeImportHelper(rImp)
+{
+ Reference<drawing::XDrawPageSupplier> xSupplier(rImp.GetModel(),UNO_QUERY);
+ if (xSupplier.is())
+ {
+ if (rImp.GetFormImport().is())
+ {
+ rImp.GetFormImport()->startPage(xSupplier->getDrawPage());
+ rFormImport = rImp.GetFormImport();
+ }
+
+ xPage = xSupplier->getDrawPage();
+ XMLShapeImportHelper::startPage( xPage );
+ }
+}
+
+SvTextShapeImportHelper::~SvTextShapeImportHelper()
+{
+ rFormImport->endPage();
+
+ if (xPage.is())
+ {
+ XMLShapeImportHelper::endPage(xPage);
+ }
+}
+
+XMLTextImportHelper* SwXMLImport::CreateTextImport()
+{
+ return new SwXMLTextImportHelper( GetModel(), *this, getImportInfo(),
+ IsInsertMode(),
+ IsStylesOnlyMode(),
+ IsBlockMode(), m_bOrganizerMode );
+}
+
+XMLShapeImportHelper* SwXMLImport::CreateShapeImport()
+{
+ return new SvTextShapeImportHelper( *this );
+}
+
+SvXMLImportContext *SwXMLImport::CreateFontDeclsContext()
+{
+ XMLFontStylesContext *pFSContext =
+ new XMLFontStylesContext( *this, osl_getThreadTextEncoding() );
+ SetFontDecls( pFSContext );
+ return pFSContext;
+}
+
+void SwXMLImport::SetViewSettings(const Sequence < PropertyValue > & aViewProps)
+{
+ if (IsInsertMode() || IsStylesOnlyMode() || IsBlockMode() || m_bOrganizerMode || !GetModel().is() )
+ return;
+
+ // this method will modify the document directly -> lock SolarMutex
+ SolarMutexGuard aGuard;
+
+ SwDoc *pDoc = getDoc();
+ tools::Rectangle aRect;
+ if( pDoc->GetDocShell() )
+ aRect = pDoc->GetDocShell()->GetVisArea( ASPECT_CONTENT );
+ //TODO/LATER: why that cast?!
+ //aRect = ((SfxInPlaceObject *)pDoc->GetDocShell())->GetVisArea();
+
+ sal_Int64 nTmp = 0;
+ bool bShowRedlineChanges = false, bBrowseMode = false;
+ bool bChangeShowRedline = false, bChangeBrowseMode = false;
+
+ //TODO/LATER: why that cast?!
+ bool bTwip = pDoc->GetDocShell()->GetMapUnit ( ) == MapUnit::MapTwip;
+ //sal_Bool bTwip = pDoc->GetDocShell()->SfxInPlaceObject::GetMapUnit ( ) == MapUnit::MapTwip;
+
+ for (const PropertyValue& rValue : aViewProps)
+ {
+ if ( rValue.Name == "ViewAreaTop" )
+ {
+ rValue.Value >>= nTmp;
+ aRect.SetPosY(bTwip ? sanitiseMm100ToTwip(nTmp) : nTmp);
+ }
+ else if ( rValue.Name == "ViewAreaLeft" )
+ {
+ rValue.Value >>= nTmp;
+ aRect.SetPosX(bTwip ? sanitiseMm100ToTwip(nTmp) : nTmp);
+ }
+ else if ( rValue.Name == "ViewAreaWidth" )
+ {
+ rValue.Value >>= nTmp;
+ Size aSize( aRect.GetSize() );
+ aSize.setWidth(bTwip ? sanitiseMm100ToTwip(nTmp) : nTmp);
+ aRect.SetSize( aSize );
+ }
+ else if ( rValue.Name == "ViewAreaHeight" )
+ {
+ rValue.Value >>= nTmp;
+ Size aSize( aRect.GetSize() );
+ aSize.setHeight(bTwip ? sanitiseMm100ToTwip(nTmp) : nTmp);
+ aRect.SetSize( aSize );
+ }
+ else if ( rValue.Name == "ShowRedlineChanges" )
+ {
+ bShowRedlineChanges = *o3tl::doAccess<bool>(rValue.Value);
+ bChangeShowRedline = true;
+ }
+// Headers and footers are not displayed in BrowseView anymore
+ else if ( rValue.Name == "InBrowseMode" )
+ {
+ bBrowseMode = *o3tl::doAccess<bool>(rValue.Value);
+ bChangeBrowseMode = true;
+ }
+ }
+ if( pDoc->GetDocShell() )
+ pDoc->GetDocShell()->SetVisArea ( aRect );
+
+ if (bChangeBrowseMode)
+ pDoc->getIDocumentSettingAccess().set(DocumentSettingId::BROWSE_MODE, bBrowseMode );
+
+ if (bChangeShowRedline)
+ GetTextImport()->SetShowChanges( bShowRedlineChanges );
+}
+
+// Note: this will be called only if there are OOo elements in settings.xml.
+// So if a setting is missing there we can assume that it was written
+// by an OOo/LO version that is older than the introduction of the setting!
+void SwXMLImport::SetConfigurationSettings(const Sequence < PropertyValue > & aConfigProps)
+{
+ // this method will modify the document directly -> lock SolarMutex
+ SolarMutexGuard aGuard;
+
+ Reference< lang::XMultiServiceFactory > xFac( GetModel(), UNO_QUERY );
+ if( !xFac.is() )
+ return;
+
+ Reference< XPropertySet > xProps( xFac->createInstance("com.sun.star.document.Settings"), UNO_QUERY );
+ if( !xProps.is() )
+ return;
+
+ Reference< XPropertySetInfo > xInfo( xProps->getPropertySetInfo() );
+ if( !xInfo.is() )
+ return;
+
+ std::unordered_set< OUString > aExcludeAlways;
+ aExcludeAlways.insert("LinkUpdateMode");
+ // this should contain things that are actually user-settable, via Tools->Options
+ std::unordered_set< OUString > aExcludeWhenNotLoadingUserSettings {
+ "ForbiddenCharacters",
+ "IsKernAsianPunctuation",
+ "CharacterCompressionType",
+ "FieldAutoUpdate",
+ "ChartAutoUpdate",
+ "AddParaTableSpacing",
+ "AddParaTableSpacingAtStart",
+ "PrintAnnotationMode",
+ "PrintBlackFonts",
+ "PrintControls",
+ "PrintDrawings",
+ "PrintGraphics",
+ "PrintHiddenText",
+ "PrintLeftPages",
+ "PrintPageBackground",
+ "PrintProspect",
+ "PrintReversed",
+ "PrintRightPages",
+ "PrintFaxName",
+ "PrintPaperFromSetup",
+ "PrintTables",
+ "PrintTextPlaceholder",
+ "PrintSingleJobs",
+ "UpdateFromTemplate",
+ "PrinterIndependentLayout",
+ "PrintEmptyPages",
+ "ConsiderTextWrapOnObjPos",
+ "DoNotJustifyLinesWithManualBreak",
+ "ProtectForm",
+ "MsWordCompTrailingBlanks",
+ "SubtractFlysAnchoredAtFlys",
+ "EmptyDbFieldHidesPara",
+ "UseVariableWidthNBSP",
+ };
+
+ bool bAreUserSettingsFromDocument = officecfg::Office::Common::Load::UserDefinedSettings::get();
+
+ // for some properties we don't want to use the application
+ // default if they're missing. So we watch for them in the loop
+ // below, and set them if not found
+ bool bPrinterIndependentLayout = false;
+ bool bUseOldNumbering = false;
+ bool bAddExternalLeading = false;
+ bool bAddParaSpacingToTableCells = false;
+ bool bAddParaLineSpacingToTableCells = false;
+ bool bUseFormerLineSpacing = false;
+ bool bUseFormerObjectPositioning = false;
+ bool bUseFormerTextWrapping = false;
+ bool bConsiderWrapOnObjPos = false;
+ bool bIgnoreFirstLineIndentInNumbering = false;
+ bool bDoNotJustifyLinesWithManualBreak = false;
+ bool bDoNotResetParaAttrsForNumFont = false;
+ bool bDoNotCaptureDrawObjsOnPage( false );
+ bool bClipAsCharacterAnchoredWriterFlyFrames( false );
+ bool bUnixForceZeroExtLeading = false;
+ bool bSmallCapsPercentage66 = false;
+ bool bTabOverflow = false;
+ bool bTabOverMarginValue = false;
+ bool bPropLineSpacingShrinksFirstLine = false;
+ bool bSubtractFlysAnchoredAtFlys = false;
+ bool bEmptyDbFieldHidesPara = false;
+ bool bCollapseEmptyCellPara = false;
+ bool bAutoFirstLineIndentDisregardLineSpace = false;
+ bool bHyphenateURLs = false;
+ bool bDoNotBreakWrappedTables = false;
+ bool bAllowTextAfterFloatingTableBreak = false;
+ bool bDropCapPunctuation = false;
+
+ const PropertyValue* currentDatabaseDataSource = nullptr;
+ const PropertyValue* currentDatabaseCommand = nullptr;
+ const PropertyValue* currentDatabaseCommandType = nullptr;
+ const PropertyValue* embeddedDatabaseName = nullptr;
+
+ for( const PropertyValue& rValue : aConfigProps )
+ {
+ bool bSet = aExcludeAlways.find(rValue.Name) == aExcludeAlways.end();
+ if( bSet && !bAreUserSettingsFromDocument
+ && (aExcludeWhenNotLoadingUserSettings.find(rValue.Name)
+ != aExcludeWhenNotLoadingUserSettings.end()) )
+ {
+ bSet = false;
+ }
+
+ if( bSet )
+ {
+ try
+ {
+ if( xInfo->hasPropertyByName( rValue.Name ) )
+ {
+ if( rValue.Name == "RedlineProtectionKey" )
+ {
+ Sequence<sal_Int8> aKey;
+ rValue.Value >>= aKey;
+ GetTextImport()->SetChangesProtectionKey( aKey );
+ }
+ else
+ {
+ // HACK: Setting these out of order does not work.
+ if( rValue.Name == "CurrentDatabaseDataSource" )
+ currentDatabaseDataSource = &rValue;
+ else if( rValue.Name == "CurrentDatabaseCommand" )
+ currentDatabaseCommand = &rValue;
+ else if( rValue.Name == "CurrentDatabaseCommandType" )
+ currentDatabaseCommandType = &rValue;
+ else if (rValue.Name == "EmbeddedDatabaseName")
+ embeddedDatabaseName = &rValue;
+ else
+ xProps->setPropertyValue( rValue.Name, rValue.Value );
+ }
+ }
+
+ // did we find any of the non-default cases?
+ if ( rValue.Name == "PrinterIndependentLayout" )
+ bPrinterIndependentLayout = true;
+ else if ( rValue.Name == "AddExternalLeading" )
+ bAddExternalLeading = true;
+ else if ( rValue.Name == "AddParaSpacingToTableCells" )
+ bAddParaSpacingToTableCells = true;
+ else if ( rValue.Name == "AddParaLineSpacingToTableCells" )
+ bAddParaLineSpacingToTableCells = true;
+ else if ( rValue.Name == "UseFormerLineSpacing" )
+ bUseFormerLineSpacing = true;
+ else if ( rValue.Name == "UseFormerObjectPositioning" )
+ bUseFormerObjectPositioning = true;
+ else if ( rValue.Name == "UseFormerTextWrapping" )
+ bUseFormerTextWrapping = true;
+ else if ( rValue.Name == "UseOldNumbering" )
+ bUseOldNumbering = true;
+ else if ( rValue.Name == "ConsiderTextWrapOnObjPos" )
+ bConsiderWrapOnObjPos = true;
+ else if ( rValue.Name == "IgnoreFirstLineIndentInNumbering" )
+ bIgnoreFirstLineIndentInNumbering = true;
+ else if ( rValue.Name == "DoNotJustifyLinesWithManualBreak" )
+ bDoNotJustifyLinesWithManualBreak = true;
+ else if ( rValue.Name == "DoNotResetParaAttrsForNumFont" )
+ bDoNotResetParaAttrsForNumFont = true;
+ else if ( rValue.Name == "DoNotCaptureDrawObjsOnPage" )
+ bDoNotCaptureDrawObjsOnPage = true;
+ else if ( rValue.Name == "ClipAsCharacterAnchoredWriterFlyFrames" )
+ bClipAsCharacterAnchoredWriterFlyFrames = true;
+ else if ( rValue.Name == "UnxForceZeroExtLeading" )
+ bUnixForceZeroExtLeading = true;
+ else if ( rValue.Name == "SmallCapsPercentage66" )
+ bSmallCapsPercentage66 = true;
+ else if ( rValue.Name == "TabOverflow" )
+ bTabOverflow = true;
+ else if ( rValue.Name == "TabOverMargin" )
+ {
+ rValue.Value >>= bTabOverMarginValue;
+ }
+ else if ( rValue.Name == "PropLineSpacingShrinksFirstLine" )
+ bPropLineSpacingShrinksFirstLine = true;
+ else if (rValue.Name == "SubtractFlysAnchoredAtFlys")
+ bSubtractFlysAnchoredAtFlys = true;
+ else if (rValue.Name == "EmptyDbFieldHidesPara")
+ bEmptyDbFieldHidesPara = true;
+ else if (rValue.Name == "CollapseEmptyCellPara")
+ bCollapseEmptyCellPara = true;
+ else if (rValue.Name == "AutoFirstLineIndentDisregardLineSpace")
+ bAutoFirstLineIndentDisregardLineSpace = true;
+ else if (rValue.Name == "HyphenateURLs")
+ {
+ bHyphenateURLs = true;
+ }
+ else if (rValue.Name == "DoNotBreakWrappedTables")
+ {
+ rValue.Value >>= bDoNotBreakWrappedTables;
+ }
+ else if (rValue.Name == "AllowTextAfterFloatingTableBreak")
+ {
+ rValue.Value >>= bAllowTextAfterFloatingTableBreak;
+ }
+ else if ( rValue.Name == "DropCapPunctuation" )
+ bDropCapPunctuation = true;
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sw", "SwXMLImport::SetConfigurationSettings" );
+ }
+ }
+ }
+
+ try
+ {
+ if( currentDatabaseDataSource != nullptr )
+ xProps->setPropertyValue( currentDatabaseDataSource->Name, currentDatabaseDataSource->Value );
+ if( currentDatabaseCommand != nullptr )
+ xProps->setPropertyValue( currentDatabaseCommand->Name, currentDatabaseCommand->Value );
+ if( currentDatabaseCommandType != nullptr )
+ xProps->setPropertyValue( currentDatabaseCommandType->Name, currentDatabaseCommandType->Value );
+ if (embeddedDatabaseName)
+ xProps->setPropertyValue(embeddedDatabaseName->Name, embeddedDatabaseName->Value);
+ } catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sw", "SwXMLImport::SetConfigurationSettings" );
+ }
+
+ // finally, treat the non-default cases
+ // introduce boolean, that indicates a document, written by version prior SO8.
+ // If user settings are not loaded, we can't know if this is an old document. Better to assume no?
+ const bool bDocumentPriorSO8 = !bConsiderWrapOnObjPos && bAreUserSettingsFromDocument;
+
+ // Use old behaviour if this setting didn't exist, but only if this setting is being read from the document.
+ // (Obviously the setting doesn't exist if we are explicitly ignoring it, so then stick with program/user defaults)
+ if(!bPrinterIndependentLayout && bAreUserSettingsFromDocument)
+ {
+ xProps->setPropertyValue( "PrinterIndependentLayout", Any(sal_Int16(document::PrinterIndependentLayout::DISABLED)) );
+ }
+
+ if( ! bAddExternalLeading )
+ {
+ xProps->setPropertyValue( "AddExternalLeading", Any( false ) );
+ }
+
+ if( ! bUseFormerLineSpacing )
+ {
+ xProps->setPropertyValue( "UseFormerLineSpacing", Any( true ) );
+ }
+
+ if( !bUseFormerObjectPositioning )
+ {
+ xProps->setPropertyValue( "UseFormerObjectPositioning", Any( true ) );
+ }
+
+ if( !bUseOldNumbering )
+ {
+ xProps->setPropertyValue( "UseOldNumbering", Any(true) );
+ }
+
+ if( !bAddParaSpacingToTableCells )
+ {
+ xProps->setPropertyValue( "AddParaSpacingToTableCells",
+ Any( false ) );
+ }
+ if (!bAddParaLineSpacingToTableCells)
+ {
+ xProps->setPropertyValue("AddParaLineSpacingToTableCells", Any(false));
+ }
+
+ if( !bUseFormerTextWrapping )
+ {
+ xProps->setPropertyValue( "UseFormerTextWrapping", Any( true ) );
+ }
+
+ if (!bConsiderWrapOnObjPos && bAreUserSettingsFromDocument)
+ {
+ xProps->setPropertyValue( "ConsiderTextWrapOnObjPos", Any( false ) );
+ }
+
+ // #i47448#
+ // For SO7pp4, part of the 'new numbering' stuff has been backported from
+ // SO8. Unfortunately, only part of it and by using the same compatibility option
+ // like in SO8. Therefore documents generated with SO7pp4, containing
+ // numbered paragraphs with first line indent differ between SO7pp4 and
+ // SO8. In order to fix this for SO8pp1, I introduce a new compatibility
+ // flag 'bIgnoreFirstLineIndentInNumbering'. This flag has to be set for all
+ // documents < SO8, but not for SO8. So if the property is not present, the
+ // flag will be set to 'true'. SO8 documents surely have the
+ // 'ConsiderWrapOnObjPos' property set (no matter if 'true' or 'false'),
+ // therefore the correct condition to set this flag is this:
+ if( !bIgnoreFirstLineIndentInNumbering && bDocumentPriorSO8 )
+ {
+ xProps->setPropertyValue( "IgnoreFirstLineIndentInNumbering",
+ Any( true ) );
+ }
+
+ // This flag has to be set for all documents < SO8
+ if ( !bDoNotJustifyLinesWithManualBreak && bDocumentPriorSO8 )
+ {
+ xProps->setPropertyValue( "DoNotJustifyLinesWithManualBreak",
+ Any( true ) );
+ }
+
+ // This flag has to be set for all documents < SO8
+ if ( !bDoNotResetParaAttrsForNumFont && bDocumentPriorSO8 )
+ {
+ xProps->setPropertyValue( "DoNotResetParaAttrsForNumFont",
+ Any( true ) );
+ }
+
+ // This flag has to be set for all documents < SO8
+ if ( !bDoNotCaptureDrawObjsOnPage && bDocumentPriorSO8 )
+ {
+ xProps->setPropertyValue( "DoNotCaptureDrawObjsOnPage",
+ Any( true ) );
+ }
+
+ // This flag has to be set for all documents < SO8
+ if ( !bClipAsCharacterAnchoredWriterFlyFrames && bDocumentPriorSO8 )
+ {
+ xProps->setPropertyValue( "ClipAsCharacterAnchoredWriterFlyFrames",
+ Any( true ) );
+ }
+
+ if ( !bUnixForceZeroExtLeading )
+ {
+ xProps->setPropertyValue( "UnxForceZeroExtLeading", Any( true ) );
+ }
+
+ // Old LO versions had 66 as the value for small caps percentage, later changed to 80.
+ // In order to keep backwards compatibility, SmallCapsPercentage66 option is written to .odt
+ // files, and the default for new documents is 'false'. Files without this option
+ // are considered to be old files, so set the compatibility option too.
+ if ( !bSmallCapsPercentage66 )
+ {
+ xProps->setPropertyValue( "SmallCapsPercentage66", Any( true ) );
+ }
+
+ if ( !bTabOverflow )
+ {
+ xProps->setPropertyValue( "TabOverflow", Any( false ) );
+ }
+
+ if (bTabOverMarginValue)
+ // Let TabOverMargin imply the new default for
+ // PrinterIndependentLayout, knowing the first is set by Word import
+ // filters and Word defaults to our new default as well.
+ xProps->setPropertyValue(
+ "PrinterIndependentLayout",
+ uno::Any(document::PrinterIndependentLayout::HIGH_RESOLUTION));
+
+ if (!bPropLineSpacingShrinksFirstLine)
+ xProps->setPropertyValue("PropLineSpacingShrinksFirstLine", Any(false));
+
+ if (!bSubtractFlysAnchoredAtFlys && bAreUserSettingsFromDocument)
+ xProps->setPropertyValue("SubtractFlysAnchoredAtFlys", Any(true));
+
+ if (!bEmptyDbFieldHidesPara && bAreUserSettingsFromDocument)
+ xProps->setPropertyValue("EmptyDbFieldHidesPara", Any(false));
+
+ if (!bCollapseEmptyCellPara)
+ xProps->setPropertyValue("CollapseEmptyCellPara", Any(false));
+
+ if (!bAutoFirstLineIndentDisregardLineSpace)
+ xProps->setPropertyValue("AutoFirstLineIndentDisregardLineSpace", Any(false));
+
+ if (!bHyphenateURLs)
+ {
+ xProps->setPropertyValue("HyphenateURLs", Any(true));
+ }
+
+ if (bDoNotBreakWrappedTables)
+ {
+ xProps->setPropertyValue("DoNotBreakWrappedTables", Any(true));
+ }
+
+ if (bAllowTextAfterFloatingTableBreak)
+ {
+ xProps->setPropertyValue("AllowTextAfterFloatingTableBreak", Any(true));
+ }
+
+ // LO 7.4 and previous versions had different drop cap punctuation: very long dashes.
+ // In order to keep backwards compatibility, DropCapPunctuation option is written to .odt
+ // files, and the default for new documents is 'true'. Files without this option
+ // are considered to be old files, so set the compatibility option too.
+ if ( !bDropCapPunctuation )
+ {
+ xProps->setPropertyValue( "DropCapPunctuation", Any( false ) );
+ }
+
+ SwDoc *pDoc = getDoc();
+ SfxPrinter *pPrinter = pDoc->getIDocumentDeviceAccess().getPrinter( false );
+ if( pPrinter )
+ {
+ // If the printer is known, then the OLE objects will
+ // already have correct sizes, and we don't have to call
+ // PrtOLENotify again. Otherwise we have to call it.
+ // The flag might be set from setting the printer, so it
+ // it is required to clear it.
+ pDoc->SetOLEPrtNotifyPending( !pPrinter->IsKnown() );
+ }
+}
+
+void SwXMLImport::SetDocumentSpecificSettings(
+ const OUString& _rSettingsGroupName,
+ const Sequence< PropertyValue>& _rSettings )
+{
+ // the only doc-specific settings group we know so far are the XForms settings
+ if ( !IsXMLToken( _rSettingsGroupName, XML_XFORM_MODEL_SETTINGS ) )
+ return;
+
+ // preserve the settings for a later iteration - we are currently reading the settings.xml,
+ // the content.xml will be read later, by another instance of SwXMLImport
+ OSL_ENSURE( m_xLateInitSettings.is(), "SwXMLImport::SetDocumentSpecificSettings: no storage for those settings!" );
+ if ( !m_xLateInitSettings.is() )
+ return;
+
+ try
+ {
+ if ( m_xLateInitSettings->hasByName( _rSettingsGroupName ) )
+ {
+ m_xLateInitSettings->replaceByName( _rSettingsGroupName, Any( _rSettings ) );
+ OSL_FAIL( "SwXMLImport::SetDocumentSpecificSettings: already have settings for this model!" );
+ }
+ else
+ m_xLateInitSettings->insertByName( _rSettingsGroupName, Any( _rSettings ) );
+ }
+ catch( const Exception& )
+ {
+ }
+}
+
+void SwXMLImport::initialize(
+ const Sequence<Any>& aArguments )
+{
+ // delegate to super class
+ SvXMLImport::initialize(aArguments);
+
+ // we are only looking for a NamedValue "LateInitSettings"
+ for(const auto& rArgument : aArguments)
+ {
+ beans::NamedValue aNamedValue;
+ if ( rArgument >>= aNamedValue )
+ {
+ if (aNamedValue.Name == "LateInitSettings")
+ {
+ OSL_VERIFY( aNamedValue.Value >>= m_xLateInitSettings );
+ }
+ }
+ }
+}
+
+void SwXMLImport::initXForms()
+{
+ // obtain SwDoc
+ auto pXTextDocument = comphelper::getFromUnoTunnel<SwXTextDocument>(GetModel());
+ if( pXTextDocument == nullptr )
+ return;
+
+ SwDoc *pDoc = pXTextDocument->GetDocShell()->GetDoc();
+
+ // init XForms (if not already done)
+ // (no default model, since we'll load the models)
+ if( ! pDoc->isXForms() )
+ pDoc->initXForms( false );
+
+ m_bInititedXForms = true;
+}
+
+SwDoc* SwXMLImport::getDoc()
+{
+ if( m_pDoc != nullptr )
+ return m_pDoc;
+ Reference < XTextDocument > xTextDoc( GetModel(), UNO_QUERY );
+ Reference < XText > xText = xTextDoc->getText();
+ SwXText* pText = dynamic_cast<SwXText*>(xText.get());
+ assert( pText != nullptr );
+ m_pDoc = pText->GetDoc();
+ assert( m_pDoc != nullptr );
+ return m_pDoc;
+}
+
+const SwDoc* SwXMLImport::getDoc() const
+{
+ return const_cast< SwXMLImport* >( this )->getDoc();
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Writer_XMLOasisImporter_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SwXMLImport(context, "com.sun.star.comp.Writer.XMLOasisImporter",
+ SvXMLImportFlags::ALL));
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Writer_XMLOasisStylesImporter_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SwXMLImport(context, "com.sun.star.comp.Writer.XMLOasisStylesImporter",
+ SvXMLImportFlags::STYLES | SvXMLImportFlags::MASTERSTYLES | SvXMLImportFlags::AUTOSTYLES |
+ SvXMLImportFlags::FONTDECLS));
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Writer_XMLOasisContentImporter_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SwXMLImport(context, "com.sun.star.comp.Writer.XMLOasisContentImporter",
+ SvXMLImportFlags::CONTENT | SvXMLImportFlags::SCRIPTS | SvXMLImportFlags::AUTOSTYLES |
+ SvXMLImportFlags::FONTDECLS));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Writer_XMLOasisMetaImporter_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SwXMLImport(context, "com.sun.star.comp.Writer.XMLOasisMetaImporter",
+ SvXMLImportFlags::META));
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Writer_XMLOasisSettingsImporter_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SwXMLImport(context, "com.sun.star.comp.Writer.XMLOasisSettingsImporter",
+ SvXMLImportFlags::SETTINGS));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportFODT(SvStream &rStream)
+{
+ SwGlobals::ensure();
+
+ SfxObjectShellLock xDocSh(new SwDocShell(SfxObjectCreateMode::INTERNAL));
+ xDocSh->DoInitNew();
+ uno::Reference<frame::XModel> xModel(xDocSh->GetModel());
+
+ uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(comphelper::getProcessServiceFactory());
+ uno::Reference<io::XInputStream> xStream(new utl::OSeekableInputStreamWrapper(rStream));
+ uno::Reference<uno::XInterface> xInterface(xMultiServiceFactory->createInstance("com.sun.star.comp.Writer.XmlFilterAdaptor"), uno::UNO_SET_THROW);
+
+ css::uno::Sequence<OUString> aUserData
+ {
+ "com.sun.star.comp.filter.OdfFlatXml",
+ "",
+ "com.sun.star.comp.Writer.XMLOasisImporter",
+ "com.sun.star.comp.Writer.XMLOasisExporter",
+ "",
+ "",
+ "true"
+ };
+ uno::Sequence<beans::PropertyValue> aAdaptorArgs(comphelper::InitPropertySequence(
+ {
+ { "UserData", uno::Any(aUserData) },
+ }));
+ css::uno::Sequence<uno::Any> aOuterArgs{ uno::Any(aAdaptorArgs) };
+
+ uno::Reference<lang::XInitialization> xInit(xInterface, uno::UNO_QUERY_THROW);
+ xInit->initialize(aOuterArgs);
+
+ uno::Reference<document::XImporter> xImporter(xInterface, uno::UNO_QUERY_THROW);
+ uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence(
+ {
+ { "InputStream", uno::Any(xStream) },
+ { "URL", uno::Any(OUString("private:stream")) },
+ }));
+ xImporter->setTargetDocument(xModel);
+
+ uno::Reference<document::XFilter> xFilter(xInterface, uno::UNO_QUERY_THROW);
+ //SetLoading hack because the document properties will be re-initted
+ //by the xml filter and during the init, while it's considered uninitialized,
+ //setting a property will inform the document it's modified, which attempts
+ //to update the properties, which throws cause the properties are uninitialized
+ xDocSh->SetLoading(SfxLoadedFlags::NONE);
+ bool ret = xFilter->filter(aArgs);
+ xDocSh->SetLoading(SfxLoadedFlags::ALL);
+
+ xDocSh->DoClose();
+
+ return ret;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT bool TestPDFExportFODT(SvStream &rStream)
+{
+ // do the same sort of check as FilterDetect::detect
+ OString const str(read_uInt8s_ToOString(rStream, 4000));
+ rStream.Seek(STREAM_SEEK_TO_BEGIN);
+ OUString resultString(str.getStr(), str.getLength(), RTL_TEXTENCODING_ASCII_US,
+ RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_DEFAULT|RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT|RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT);
+ if (!resultString.startsWith("<?xml") || resultString.indexOf("office:mimetype=\"application/vnd.oasis.opendocument.text\"") == -1)
+ return false;
+
+ Reference<css::frame::XDesktop2> xDesktop = css::frame::Desktop::create(comphelper::getProcessComponentContext());
+ Reference<css::frame::XFrame> xTargetFrame = xDesktop->findFrame("_blank", 0);
+
+ Reference<uno::XComponentContext> xContext(comphelper::getProcessComponentContext());
+ Reference<css::frame::XModel2> xModel(xContext->getServiceManager()->createInstanceWithContext(
+ "com.sun.star.text.TextDocument", xContext), UNO_QUERY_THROW);
+
+ Reference<css::frame::XLoadable> xModelLoad(xModel, UNO_QUERY_THROW);
+ xModelLoad->initNew();
+
+ uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(comphelper::getProcessServiceFactory());
+ uno::Reference<io::XInputStream> xStream(new utl::OSeekableInputStreamWrapper(rStream));
+ uno::Reference<uno::XInterface> xInterface(xMultiServiceFactory->createInstance("com.sun.star.comp.Writer.XmlFilterAdaptor"), uno::UNO_SET_THROW);
+
+ css::uno::Sequence<OUString> aUserData
+ {
+ "com.sun.star.comp.filter.OdfFlatXml",
+ "",
+ "com.sun.star.comp.Writer.XMLOasisImporter",
+ "com.sun.star.comp.Writer.XMLOasisExporter",
+ "",
+ "",
+ "true"
+ };
+ uno::Sequence<beans::PropertyValue> aAdaptorArgs(comphelper::InitPropertySequence(
+ {
+ { "UserData", uno::Any(aUserData) },
+ }));
+ css::uno::Sequence<uno::Any> aOuterArgs{ uno::Any(aAdaptorArgs) };
+
+ uno::Reference<lang::XInitialization> xInit(xInterface, uno::UNO_QUERY_THROW);
+ xInit->initialize(aOuterArgs);
+
+ uno::Reference<document::XImporter> xImporter(xInterface, uno::UNO_QUERY_THROW);
+ uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence(
+ {
+ { "InputStream", uno::Any(xStream) },
+ { "URL", uno::Any(OUString("private:stream")) },
+ }));
+ xImporter->setTargetDocument(xModel);
+
+ uno::Reference<document::XFilter> xFODTFilter(xInterface, uno::UNO_QUERY_THROW);
+ bool ret = xFODTFilter->filter(aArgs);
+
+ if (ret)
+ {
+ css::uno::Reference<css::frame::XController2> xController(xModel->createDefaultViewController(xTargetFrame), UNO_SET_THROW);
+ utl::ConnectFrameControllerModel(xTargetFrame, xController, xModel);
+
+ utl::TempFileFast aTempFile;
+
+ uno::Reference<document::XFilter> xPDFFilter(
+ xMultiServiceFactory->createInstance("com.sun.star.document.PDFFilter"), uno::UNO_QUERY);
+ uno::Reference<document::XExporter> xExporter(xPDFFilter, uno::UNO_QUERY);
+ xExporter->setSourceDocument(xModel);
+
+ uno::Reference<io::XOutputStream> xOutputStream(new utl::OStreamWrapper(*aTempFile.GetStream(StreamMode::READWRITE)));
+
+ // ofz#60533 fuzzer learned to use fo:font-size="842pt" which generate timeouts trying
+ // to export thousands of pages from minimal input size
+ uno::Sequence<beans::PropertyValue> aFilterData(comphelper::InitPropertySequence({
+ { "PageRange", uno::Any(OUString("1-100")) }
+ }));
+ uno::Sequence<beans::PropertyValue> aDescriptor(comphelper::InitPropertySequence({
+ { "FilterName", uno::Any(OUString("writer_pdf_Export")) },
+ { "OutputStream", uno::Any(xOutputStream) },
+ { "FilterData", uno::Any(aFilterData) }
+ }));
+ xPDFFilter->filter(aDescriptor);
+ }
+
+ css::uno::Reference<css::util::XCloseable> xClose(xModel, css::uno::UNO_QUERY);
+ xClose->close(false);
+
+ return ret;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportDOCX(SvStream &rStream)
+{
+ SwGlobals::ensure();
+
+ SfxObjectShellLock xDocSh(new SwDocShell(SfxObjectCreateMode::INTERNAL));
+ xDocSh->DoInitNew();
+ uno::Reference<frame::XModel> xModel(xDocSh->GetModel());
+
+ uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(comphelper::getProcessServiceFactory());
+ uno::Reference<io::XInputStream> xStream(new utl::OSeekableInputStreamWrapper(rStream));
+
+ uno::Reference<document::XFilter> xFilter(xMultiServiceFactory->createInstance("com.sun.star.comp.Writer.WriterFilter"), uno::UNO_QUERY_THROW);
+
+ uno::Reference<document::XImporter> xImporter(xFilter, uno::UNO_QUERY_THROW);
+ uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence(
+ {
+ { "InputStream", uno::Any(xStream) },
+ { "InputMode", uno::Any(true) },
+ }));
+ xImporter->setTargetDocument(xModel);
+
+ //SetLoading hack because the document properties will be re-initted
+ //by the xml filter and during the init, while it's considered uninitialized,
+ //setting a property will inform the document it's modified, which attempts
+ //to update the properties, which throws cause the properties are uninitialized
+ xDocSh->SetLoading(SfxLoadedFlags::NONE);
+ bool ret = false;
+ try
+ {
+ ret = xFilter->filter(aArgs);
+ }
+ catch (...)
+ {
+ }
+ xDocSh->SetLoading(SfxLoadedFlags::ALL);
+
+ xDocSh->DoClose();
+
+ return ret;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlimp.hxx b/sw/source/filter/xml/xmlimp.hxx
new file mode 100644
index 0000000000..4c528155f2
--- /dev/null
+++ b/sw/source/filter/xml/xmlimp.hxx
@@ -0,0 +1,187 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SW_SOURCE_FILTER_XML_XMLIMP_HXX
+#define INCLUDED_SW_SOURCE_FILTER_XML_XMLIMP_HXX
+
+#include <sal/config.h>
+
+#include <memory>
+#include <optional>
+
+#include <com/sun/star/document/XDocumentProperties.hpp>
+
+#include <xmloff/xmlictxt.hxx>
+#include <xmloff/xmlimp.hxx>
+
+#include "xmlitmap.hxx"
+#include <o3tl/typed_flags_set.hxx>
+#include <ndindex.hxx>
+
+class SwDoc;
+class SvXMLUnitConverter;
+class SvXMLTokenMap;
+class SvXMLImportItemMapper;
+class SfxItemSet;
+class XMLTextImportHelper;
+class SvXMLGraphicHelper;
+class SvXMLEmbeddedObjectHelper;
+enum class SfxStyleFamily;
+
+// define, how many steps ( = paragraphs ) the progress bar should advance
+// for styles, autostyles and settings + meta
+#define PROGRESS_BAR_STEP 20
+
+// we only need this scoped enum to be flags here, in sw
+namespace o3tl
+{
+ template<> struct typed_flags<SfxStyleFamily> : is_typed_flags<SfxStyleFamily, 0xffff> {};
+}
+
+class SwXMLImport: public SvXMLImport
+{
+ std::optional<SwNodeIndex> m_oSttNdIdx;
+
+ std::unique_ptr<SvXMLUnitConverter> m_pTwipUnitConv;
+ std::unique_ptr<SvXMLImportItemMapper> m_pTableItemMapper;// paragraph item import
+
+ rtl::Reference<SvXMLGraphicHelper> m_xGraphicStorageHandler;
+
+ rtl::Reference<SvXMLEmbeddedObjectHelper> m_xEmbeddedResolver;
+
+ SvXMLItemMapEntriesRef m_xTableItemMap;
+ SvXMLItemMapEntriesRef m_xTableColItemMap;
+ SvXMLItemMapEntriesRef m_xTableRowItemMap;
+ SvXMLItemMapEntriesRef m_xTableCellItemMap;
+ css::uno::Reference< css::container::XNameContainer >
+ m_xLateInitSettings;
+
+ SfxStyleFamily m_nStyleFamilyMask;// Mask of styles to load
+ bool m_bLoadDoc : 1; // Load doc or styles only
+ bool m_bInsert : 1; // Insert mode. If styles are
+ // loaded only false means that
+ // existing styles will be
+ // overwritten.
+ bool m_bBlock : 1; // Load text block
+ bool m_bOrganizerMode : 1;
+ bool m_bInititedXForms : 1;
+
+ SwDoc* m_pDoc; // cached for getDoc()
+
+ // Optimization for new table name lookup
+ OUString m_sDefTableName; // See STR_TABLE_DEFNAME
+ std::map<OUString, sal_uInt32> m_aTableNameMap; // Last used indices for duplicating table names
+
+ void InitItemImport();
+ void FinitItemImport();
+ void UpdateTextCollConditions( SwDoc *pDoc );
+
+ void setTextInsertMode(
+ const css::uno::Reference< css::text::XTextRange > & rInsertPos );
+ void setStyleInsertMode( SfxStyleFamily nFamilies,
+ bool bOverwrite );
+
+protected:
+
+ virtual SvXMLImportContext *CreateFastContext( sal_Int32 nElement,
+ const ::css::uno::Reference< ::css::xml::sax::XFastAttributeList >& xAttrList ) override;
+
+ virtual XMLTextImportHelper* CreateTextImport() override;
+
+ virtual XMLShapeImportHelper* CreateShapeImport() override;
+
+public:
+ SwXMLImport(
+ const css::uno::Reference< css::uno::XComponentContext >& rContext,
+ OUString const & implementationName, SvXMLImportFlags nImportFlags);
+
+ virtual ~SwXMLImport() noexcept override;
+
+ // css::xml::sax::XDocumentHandler
+ virtual void SAL_CALL startDocument() override;
+ virtual void SAL_CALL endDocument() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ void InsertStyles( bool bAuto );
+ void FinishStyles();
+
+ // namespace office
+
+ // NB: in contrast to other CreateFooContexts, this particular one handles
+ // the root element (i.e. office:document-meta)
+ SvXMLImportContext *CreateMetaContext( const sal_Int32 nElement );
+ SvXMLImportContext *CreateScriptContext();
+ SvXMLImportContext *CreateStylesContext( bool bAuto );
+ SvXMLImportContext *CreateMasterStylesContext();
+ SvXMLImportContext *CreateFontDeclsContext();
+ SvXMLImportContext *CreateBodyContentContext();
+ SfxStyleFamily GetStyleFamilyMask() const { return m_nStyleFamilyMask; }
+ bool IsInsertMode() const { return m_bInsert; }
+ bool IsStylesOnlyMode() const { return !m_bLoadDoc; }
+ bool IsBlockMode() const { return m_bBlock; }
+
+ inline const SvXMLImportItemMapper& GetTableItemMapper() const;
+ inline SvXMLImportItemMapper& GetTableItemMapper();
+ SvXMLImportContext *CreateTableItemImportContext( sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList,
+ XmlStyleFamily nSubFamily, SfxItemSet& rItemSet );
+
+ bool FindAutomaticStyle( XmlStyleFamily nFamily,
+ const OUString& rName,
+ const SfxItemSet **ppItemSet ) const;
+ void MergeListsAtDocumentInsertPosition(SwDoc *pDoc);
+
+ virtual void SetStatistics(
+ const css::uno::Sequence< css::beans::NamedValue> & i_rStats) override;
+ virtual void SetViewSettings(const css::uno::Sequence<css::beans::PropertyValue>& aViewProps) override;
+ virtual void SetConfigurationSettings(const css::uno::Sequence<css::beans::PropertyValue>& aConfigProps) override;
+ virtual void SetDocumentSpecificSettings(const OUString& _rSettingsGroupName,
+ const css::uno::Sequence<css::beans::PropertyValue>& _rSettings) override;
+
+ // initialize XForms
+ virtual void initXForms() override;
+
+ // get the document properties, but only if they actually need importing
+ css::uno::Reference<css::document::XDocumentProperties>
+ GetDocumentProperties() const;
+
+ virtual void NotifyContainsEmbeddedFont() override;
+
+ const SwDoc* getDoc() const;
+ SwDoc* getDoc();
+
+ const OUString& GetDefTableName() { return m_sDefTableName; }
+ std::map<OUString, sal_uInt32>& GetTableNameMap() { return m_aTableNameMap; }
+};
+
+inline const SvXMLImportItemMapper& SwXMLImport::GetTableItemMapper() const
+{
+ return *m_pTableItemMapper;
+}
+
+inline SvXMLImportItemMapper& SwXMLImport::GetTableItemMapper()
+{
+ return *m_pTableItemMapper;
+}
+
+#endif // _XMLIMP_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlimpit.cxx b/sw/source/filter/xml/xmlimpit.cxx
new file mode 100644
index 0000000000..eaabf789e2
--- /dev/null
+++ b/sw/source/filter/xml/xmlimpit.cxx
@@ -0,0 +1,1056 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlimpit.hxx"
+
+#include <sal/log.hxx>
+#include <sax/tools/converter.hxx>
+#include <utility>
+#include <xmloff/xmluconv.hxx>
+#include <svl/itempool.hxx>
+#include <svl/poolitem.hxx>
+#include <svl/itemset.hxx>
+#include <xmloff/namespacemap.hxx>
+#include <editeng/xmlcnitm.hxx>
+#include <editeng/memberids.h>
+#include <osl/diagnose.h>
+
+#include <hintids.hxx>
+#include <unomid.h>
+#include <svx/unomid.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/shaditem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/formatbreakitem.hxx>
+#include <editeng/keepitem.hxx>
+#include <editeng/brushitem.hxx>
+#include <editeng/frmdir.hxx>
+#include <fmtpdsc.hxx>
+#include <fmtornt.hxx>
+#include <fmtfsize.hxx>
+
+#include <xmloff/prhdlfac.hxx>
+#include <xmloff/xmltypes.hxx>
+#include <xmloff/xmlprhdl.hxx>
+#include <xmloff/xmlimp.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include "xmlithlp.hxx"
+#include <com/sun/star/uno/Any.hxx>
+
+using ::editeng::SvxBorderLine;
+using namespace ::com::sun::star;
+using namespace ::xmloff::token;
+using uno::Any;
+
+constexpr sal_uInt16 nUnknownWhich = RES_UNKNOWNATR_CONTAINER;
+
+SvXMLImportItemMapper::SvXMLImportItemMapper(
+ SvXMLItemMapEntriesRef aMapEntries ) :
+ mrMapEntries(std::move( aMapEntries ))
+{
+}
+
+SvXMLImportItemMapper::~SvXMLImportItemMapper()
+{
+}
+
+void
+SvXMLImportItemMapper::setMapEntries( SvXMLItemMapEntriesRef rMapEntries )
+{
+ mrMapEntries = std::move(rMapEntries);
+}
+
+// fills the given itemset with the attributes in the given list
+void SvXMLImportItemMapper::importXML( SfxItemSet& rSet,
+ uno::Reference< xml::sax::XFastAttributeList > const & xAttrList,
+ const SvXMLUnitConverter& rUnitConverter,
+ const SvXMLNamespaceMap& rNamespaceMap )
+{
+ std::unique_ptr<SvXMLAttrContainerItem> pUnknownItem;
+ for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ))
+ {
+ if( IsTokenInNamespace(aIter.getToken(), XML_NAMESPACE_XMLNS) )
+ continue;
+
+ sal_Int32 nToken = aIter.getToken();
+ const OUString sValue = aIter.toString();
+
+ // find a map entry for this attribute
+ sal_Int32 nLookupToken = nToken;
+ // compatibility namespaces need to be transformed into current namespace before looking up
+ if (IsTokenInNamespace(nLookupToken, XML_NAMESPACE_FO_COMPAT))
+ nLookupToken = XML_ELEMENT(FO, (nLookupToken & TOKEN_MASK));
+ SvXMLItemMapEntry const * pEntry = mrMapEntries->getByName( nLookupToken );
+
+ if( pEntry )
+ {
+ // we have a valid map entry here, so lets use it...
+ if( 0 == (pEntry->nMemberId & (MID_SW_FLAG_NO_ITEM_IMPORT|
+ MID_SW_FLAG_ELEMENT_ITEM_IMPORT)) )
+ {
+ // first get item from itemset
+ const SfxPoolItem* pItem = nullptr;
+ SfxItemState eState = rSet.GetItemState( pEntry->nWhichId, true,
+ &pItem );
+
+ // if it's not set, try the pool
+ if (SfxItemState::SET != eState && SfxItemPool::IsWhich(pEntry->nWhichId))
+ pItem = &rSet.GetPool()->GetDefaultItem(pEntry->nWhichId);
+
+ // do we have an item?
+ if(eState >= SfxItemState::DEFAULT && pItem)
+ {
+ std::unique_ptr<SfxPoolItem> pNewItem(pItem->Clone());
+ bool bPut = false;
+
+ if( 0 == (pEntry->nMemberId&MID_SW_FLAG_SPECIAL_ITEM_IMPORT) )
+ {
+ bPut = PutXMLValue( *pNewItem, sValue,
+ o3tl::narrowing<sal_uInt16>( pEntry->nMemberId & MID_SW_FLAG_MASK ),
+ rUnitConverter );
+
+ }
+ else
+ {
+ bPut = handleSpecialItem( *pEntry, *pNewItem, rSet,
+ sValue, rUnitConverter );
+ }
+
+ if( bPut )
+ rSet.Put( std::move(pNewItem) );
+ }
+ else
+ {
+ OSL_FAIL( "Could not get a needed item for xml import!" );
+ }
+ }
+ else if( 0 != (pEntry->nMemberId & MID_SW_FLAG_NO_ITEM_IMPORT) )
+ {
+ handleNoItem( *pEntry, rSet, sValue, rUnitConverter,
+ rNamespaceMap );
+ }
+ }
+ else
+ {
+ if( !pUnknownItem )
+ {
+ const SfxPoolItem* pItem = nullptr;
+ if( SfxItemState::SET == rSet.GetItemState( nUnknownWhich, true,
+ &pItem ) )
+ {
+ pUnknownItem.reset( static_cast<SvXMLAttrContainerItem*>( pItem->Clone() ) );
+ }
+ else
+ {
+ pUnknownItem.reset( new SvXMLAttrContainerItem( nUnknownWhich ) );
+ }
+ }
+ if( pUnknownItem )
+ {
+ if( IsTokenInNamespace(nToken, XML_NAMESPACE_NONE) )
+ pUnknownItem->AddAttr( SvXMLImport::getNameFromToken( nToken ), sValue );
+ else
+ {
+ const OUString& rAttrNamespacePrefix = SvXMLImport::getNamespacePrefixFromToken(nToken, &rNamespaceMap);
+ OUString sAttrName = SvXMLImport::getNameFromToken( nToken );
+ if ( !rAttrNamespacePrefix.isEmpty() )
+ sAttrName = rAttrNamespacePrefix + SvXMLImport::aNamespaceSeparator + sAttrName;
+ OUString aLocalName, aPrefix, aNamespace;
+ rNamespaceMap.GetKeyByAttrName( sAttrName, &aPrefix, &aLocalName,
+ &aNamespace );
+ if ( !rAttrNamespacePrefix.isEmpty() )
+ pUnknownItem->AddAttr( rAttrNamespacePrefix, aNamespace, aLocalName,
+ sValue );
+ else
+ pUnknownItem->AddAttr( aLocalName, sValue );
+ }
+ }
+ }
+ }
+
+ importXMLUnknownAttributes(rSet, xAttrList, rUnitConverter, pUnknownItem);
+
+ if( pUnknownItem )
+ {
+ rSet.Put( *pUnknownItem );
+ }
+
+ finished(rSet, rUnitConverter);
+}
+
+void SvXMLImportItemMapper::importXMLUnknownAttributes( SfxItemSet& rSet,
+ uno::Reference< xml::sax::XFastAttributeList > const & xAttrList,
+ const SvXMLUnitConverter& rUnitConverter,
+ std::unique_ptr<SvXMLAttrContainerItem>& pUnknownItem)
+{
+ const css::uno::Sequence< css::xml::Attribute > unknownAttributes = xAttrList->getUnknownAttributes();
+ for (const auto & rAttribute : unknownAttributes)
+ {
+ if( !pUnknownItem )
+ {
+ const SfxPoolItem* pItem = nullptr;
+ if( SfxItemState::SET == rSet.GetItemState( nUnknownWhich, true,
+ &pItem ) )
+ {
+ pUnknownItem.reset( static_cast<SvXMLAttrContainerItem*>( pItem->Clone() ) );
+ }
+ else
+ {
+ pUnknownItem.reset( new SvXMLAttrContainerItem( nUnknownWhich ) );
+ }
+ }
+ if( pUnknownItem )
+ {
+ if( rAttribute.NamespaceURL.isEmpty() )
+ pUnknownItem->AddAttr( rAttribute.Name, rAttribute.Value );
+ else
+ {
+ OUString sPrefix;
+ OUString sName = rAttribute.Name;
+ int i = sName.indexOf(':');
+ if (i != -1)
+ {
+ sPrefix = sName.copy(0, i-1);
+ sName = sName.copy(i+1);
+ }
+ // the sax parser doesn't reject these, strangely
+ if (sName.indexOf(':') == -1)
+ pUnknownItem->AddAttr( sPrefix, rAttribute.NamespaceURL, sName,
+ rAttribute.Value );
+ else
+ SAL_WARN("sw", "ignoring dodgy attribute: " + rAttribute.Name);
+ }
+ }
+ }
+
+ if( pUnknownItem )
+ {
+ rSet.Put( *pUnknownItem );
+ }
+
+ finished(rSet, rUnitConverter);
+}
+
+/** this method is called for every item that has the
+ MID_SW_FLAG_SPECIAL_ITEM_IMPORT flag set */
+bool
+SvXMLImportItemMapper::handleSpecialItem( const SvXMLItemMapEntry& /*rEntry*/,
+ SfxPoolItem& /*rItem*/,
+ SfxItemSet& /*rSet*/,
+ const OUString& /*rValue*/,
+ const SvXMLUnitConverter& /*rUnitConverter*/ )
+{
+ OSL_FAIL( "unsupported special item in xml import" );
+ return false;
+}
+
+/** this method is called for every item that has the
+ MID_SW_FLAG_NO_ITEM_IMPORT flag set */
+bool SvXMLImportItemMapper::handleNoItem( const SvXMLItemMapEntry& /*rEntry*/,
+ SfxItemSet& /*rSet*/,
+ const OUString& /*rValue*/,
+ const SvXMLUnitConverter& /*rUnitConverter*/,
+ const SvXMLNamespaceMap& /*rNamespaceMap*/ )
+{
+ OSL_FAIL( "unsupported no item in xml import" );
+ return false;
+}
+
+void
+SvXMLImportItemMapper::finished(SfxItemSet &, SvXMLUnitConverter const&) const
+{
+ // nothing to do here
+}
+
+namespace {
+
+struct BoxHolder
+{
+ std::unique_ptr<SvxBorderLine> pTop;
+ std::unique_ptr<SvxBorderLine> pBottom;
+ std::unique_ptr<SvxBorderLine> pLeft;
+ std::unique_ptr<SvxBorderLine> pRight;
+
+ BoxHolder(BoxHolder const&) = delete;
+ BoxHolder& operator=(BoxHolder const&) = delete;
+
+ explicit BoxHolder(SvxBoxItem const & rBox)
+ {
+ if (rBox.GetTop())
+ pTop.reset(new SvxBorderLine( *rBox.GetTop() ));
+ if (rBox.GetBottom())
+ pBottom.reset(new SvxBorderLine( *rBox.GetBottom() ));
+ if (rBox.GetLeft())
+ pLeft.reset(new SvxBorderLine( *rBox.GetLeft() ));
+ if (rBox.GetRight())
+ pRight.reset(new SvxBorderLine( *rBox.GetRight() ));
+ }
+};
+
+}
+
+// put an XML-string value into an item
+bool SvXMLImportItemMapper::PutXMLValue(
+ SfxPoolItem& rItem,
+ const OUString& rValue,
+ sal_uInt16 nMemberId,
+ const SvXMLUnitConverter& rUnitConverter )
+{
+ bool bOk = false;
+
+ switch (rItem.Which())
+ {
+ case RES_MARGIN_FIRSTLINE:
+ case RES_MARGIN_TEXTLEFT:
+ case RES_MARGIN_RIGHT:
+ assert(false); // is only called for frame formats?
+ break;
+
+ case RES_LR_SPACE:
+ {
+ SvxLRSpaceItem& rLRSpace = dynamic_cast<SvxLRSpaceItem&>(rItem);
+
+ switch( nMemberId )
+ {
+ case MID_L_MARGIN:
+ case MID_R_MARGIN:
+ {
+ sal_Int32 nProp = 100;
+ sal_Int32 nAbs = 0;
+
+ if( rValue.indexOf( '%' ) != -1 )
+ bOk = ::sax::Converter::convertPercent(nProp, rValue);
+ else
+ bOk = rUnitConverter.convertMeasureToCore(nAbs, rValue);
+
+ if( bOk )
+ {
+ switch( nMemberId )
+ {
+ case MID_L_MARGIN:
+ rLRSpace.SetTextLeft( nAbs, o3tl::narrowing<sal_uInt16>(nProp) );
+ break;
+ case MID_R_MARGIN:
+ rLRSpace.SetRight( nAbs, o3tl::narrowing<sal_uInt16>(nProp) );
+ break;
+ }
+ }
+ }
+ break;
+
+ case MID_FIRST_LINE_INDENT:
+ {
+ assert(false); // it looks like this can't be called? (frame formats only, aTableItemMap)
+ sal_Int32 nProp = 100;
+ sal_Int32 nAbs = 0;
+
+ if( rValue.indexOf( '%' ) != -1 )
+ bOk = ::sax::Converter::convertPercent(nProp, rValue);
+ else
+ bOk = rUnitConverter.convertMeasureToCore(nAbs, rValue,
+ -0x7fff, 0x7fff );
+
+ rLRSpace.SetTextFirstLineOffset( static_cast<short>(nAbs), o3tl::narrowing<sal_uInt16>(nProp) );
+ }
+ break;
+
+ case MID_FIRST_AUTO:
+ {
+ assert(false); // it looks like this can't be called? (frame formats only, aTableItemMap)
+ bool bAutoFirst(false);
+ bOk = ::sax::Converter::convertBool( bAutoFirst, rValue );
+ if( bOk )
+ rLRSpace.SetAutoFirst( bAutoFirst );
+ }
+ break;
+
+ default:
+ OSL_FAIL( "unknown member id!");
+ }
+ }
+ break;
+
+ case RES_UL_SPACE:
+ {
+ SvxULSpaceItem& rULSpace = dynamic_cast<SvxULSpaceItem&>(rItem);
+
+ sal_Int32 nProp = 100;
+ sal_Int32 nAbs = 0;
+
+ if( rValue.indexOf( '%' ) != -1 )
+ bOk = ::sax::Converter::convertPercent( nProp, rValue );
+ else
+ bOk = rUnitConverter.convertMeasureToCore( nAbs, rValue );
+
+ switch( nMemberId )
+ {
+ case MID_UP_MARGIN:
+ rULSpace.SetUpper( o3tl::narrowing<sal_uInt16>(nAbs), o3tl::narrowing<sal_uInt16>(nProp) );
+ break;
+ case MID_LO_MARGIN:
+ rULSpace.SetLower( o3tl::narrowing<sal_uInt16>(nAbs), o3tl::narrowing<sal_uInt16>(nProp) );
+ break;
+ default:
+ OSL_FAIL("unknown MemberId");
+ }
+ }
+ break;
+
+ case RES_SHADOW:
+ {
+ SvxShadowItem& rShadow = dynamic_cast<SvxShadowItem&>(rItem);
+
+ bool bColorFound = false;
+ bool bOffsetFound = false;
+
+ SvXMLTokenEnumerator aTokenEnum( rValue );
+
+ Color aColor( 128,128, 128 );
+ rShadow.SetLocation( SvxShadowLocation::BottomRight );
+
+ std::u16string_view aToken;
+ while( aTokenEnum.getNextToken( aToken ) )
+ {
+ if( IsXMLToken( aToken, XML_NONE ) )
+ {
+ rShadow.SetLocation( SvxShadowLocation::NONE );
+ bOk = true;
+ }
+ else if( !bColorFound && aToken.substr(0,1) == u"#" )
+ {
+ bOk = ::sax::Converter::convertColor( aColor, aToken );
+ if( !bOk )
+ return false;
+
+ bColorFound = true;
+ }
+ else if( !bOffsetFound )
+ {
+ sal_Int32 nX = 0, nY = 0;
+
+ bOk = rUnitConverter.convertMeasureToCore( nX, aToken );
+ if( bOk && aTokenEnum.getNextToken( aToken ) )
+ bOk = rUnitConverter.convertMeasureToCore( nY, aToken );
+
+ if( bOk )
+ {
+ if( nX < 0 )
+ {
+ if( nY < 0 )
+ {
+ rShadow.SetLocation( SvxShadowLocation::TopLeft );
+ }
+ else
+ {
+ rShadow.SetLocation( SvxShadowLocation::BottomLeft );
+ }
+ }
+ else
+ {
+ if( nY < 0 )
+ {
+ rShadow.SetLocation( SvxShadowLocation::TopRight );
+ }
+ else
+ {
+ rShadow.SetLocation( SvxShadowLocation::BottomRight );
+ }
+ }
+
+ if( nX < 0 ) nX *= -1;
+ if( nY < 0 ) nY *= -1;
+
+ rShadow.SetWidth( static_cast< sal_uInt16 >( (nX + nY) >> 1 ) );
+ }
+ }
+ }
+
+ if( bOk && ( bColorFound || bOffsetFound ) )
+ {
+ rShadow.SetColor(aColor);
+ }
+ else
+ bOk = false;
+ }
+ break;
+
+ case RES_BOX:
+ {
+ SvxBoxItem& rBox = dynamic_cast<SvxBoxItem&>(rItem);
+
+ // copy SvxBorderLines
+ BoxHolder aBoxes(rBox);
+
+ sal_Int32 nTemp;
+
+ switch( nMemberId )
+ {
+ case ALL_BORDER_PADDING:
+ case LEFT_BORDER_PADDING:
+ case RIGHT_BORDER_PADDING:
+ case TOP_BORDER_PADDING:
+ case BOTTOM_BORDER_PADDING:
+ if (!rUnitConverter.convertMeasureToCore( nTemp, rValue,
+ 0, 0xffff ))
+ {
+ return false;
+ }
+
+ if( nMemberId == LEFT_BORDER_PADDING ||
+ nMemberId == ALL_BORDER_PADDING )
+ rBox.SetDistance( o3tl::narrowing<sal_uInt16>(nTemp), SvxBoxItemLine::LEFT );
+ if( nMemberId == RIGHT_BORDER_PADDING ||
+ nMemberId == ALL_BORDER_PADDING )
+ rBox.SetDistance( o3tl::narrowing<sal_uInt16>(nTemp), SvxBoxItemLine::RIGHT );
+ if( nMemberId == TOP_BORDER_PADDING ||
+ nMemberId == ALL_BORDER_PADDING )
+ rBox.SetDistance( o3tl::narrowing<sal_uInt16>(nTemp), SvxBoxItemLine::TOP );
+ if( nMemberId == BOTTOM_BORDER_PADDING ||
+ nMemberId == ALL_BORDER_PADDING )
+ rBox.SetDistance( o3tl::narrowing<sal_uInt16>(nTemp), SvxBoxItemLine::BOTTOM);
+ break;
+
+ case ALL_BORDER:
+ case LEFT_BORDER:
+ case RIGHT_BORDER:
+ case TOP_BORDER:
+ case BOTTOM_BORDER:
+ {
+ bool bHasStyle = false;
+ bool bHasWidth = false;
+ bool bHasColor = false;
+
+ sal_uInt16 nStyle = USHRT_MAX;
+ sal_uInt16 nWidth = 0;
+ sal_uInt16 nNamedWidth = USHRT_MAX;
+
+ Color aColor( COL_BLACK );
+
+ if( !sw_frmitems_parseXMLBorder( rValue, rUnitConverter,
+ bHasStyle, nStyle,
+ bHasWidth, nWidth, nNamedWidth,
+ bHasColor, aColor ) )
+ return false;
+
+ if( TOP_BORDER == nMemberId || ALL_BORDER == nMemberId )
+ sw_frmitems_setXMLBorder( aBoxes.pTop,
+ bHasStyle, nStyle,
+ bHasWidth, nWidth, nNamedWidth,
+ bHasColor, aColor );
+
+ if( BOTTOM_BORDER == nMemberId || ALL_BORDER == nMemberId )
+ sw_frmitems_setXMLBorder( aBoxes.pBottom,
+ bHasStyle, nStyle,
+ bHasWidth, nWidth, nNamedWidth,
+ bHasColor, aColor );
+
+ if( LEFT_BORDER == nMemberId || ALL_BORDER == nMemberId )
+ sw_frmitems_setXMLBorder( aBoxes.pLeft,
+ bHasStyle, nStyle,
+ bHasWidth, nWidth, nNamedWidth,
+ bHasColor, aColor );
+
+ if( RIGHT_BORDER == nMemberId || ALL_BORDER == nMemberId )
+ sw_frmitems_setXMLBorder( aBoxes.pRight,
+ bHasStyle, nStyle,
+ bHasWidth, nWidth, nNamedWidth,
+ bHasColor, aColor );
+ }
+ break;
+ case ALL_BORDER_LINE_WIDTH:
+ case LEFT_BORDER_LINE_WIDTH:
+ case RIGHT_BORDER_LINE_WIDTH:
+ case TOP_BORDER_LINE_WIDTH:
+ case BOTTOM_BORDER_LINE_WIDTH:
+ {
+ SvXMLTokenEnumerator aTokenEnum( rValue );
+
+ sal_Int32 nInWidth, nDistance, nOutWidth;
+
+ std::u16string_view aToken;
+ if( !aTokenEnum.getNextToken( aToken ) )
+ return false;
+
+ if (!rUnitConverter.convertMeasureToCore(nInWidth, aToken))
+ return false;
+
+ if( !aTokenEnum.getNextToken( aToken ) )
+ return false;
+
+ if (!rUnitConverter.convertMeasureToCore(nDistance, aToken))
+ return false;
+
+ if( !aTokenEnum.getNextToken( aToken ) )
+ return false;
+
+ if (!rUnitConverter.convertMeasureToCore(nOutWidth, aToken))
+ return false;
+
+ // #i61946: accept line style even it's not part of our "normal" set of line styles
+ sal_uInt16 nWidth = 0;
+
+ if( TOP_BORDER_LINE_WIDTH == nMemberId ||
+ ALL_BORDER_LINE_WIDTH == nMemberId )
+ sw_frmitems_setXMLBorder( aBoxes.pTop, nWidth,
+ static_cast< sal_uInt16 >( nOutWidth ),
+ static_cast< sal_uInt16 >( nInWidth ),
+ static_cast< sal_uInt16 >( nDistance ) );
+
+ if( BOTTOM_BORDER_LINE_WIDTH == nMemberId ||
+ ALL_BORDER_LINE_WIDTH == nMemberId )
+ sw_frmitems_setXMLBorder( aBoxes.pBottom, nWidth,
+ static_cast< sal_uInt16 >( nOutWidth ),
+ static_cast< sal_uInt16 >( nInWidth ),
+ static_cast< sal_uInt16 >( nDistance ) );
+
+ if( LEFT_BORDER_LINE_WIDTH == nMemberId ||
+ ALL_BORDER_LINE_WIDTH == nMemberId )
+ sw_frmitems_setXMLBorder( aBoxes.pLeft, nWidth,
+ static_cast< sal_uInt16 >( nOutWidth ),
+ static_cast< sal_uInt16 >( nInWidth ),
+ static_cast< sal_uInt16 >( nDistance ) );
+
+ if( RIGHT_BORDER_LINE_WIDTH == nMemberId ||
+ ALL_BORDER_LINE_WIDTH == nMemberId )
+ sw_frmitems_setXMLBorder( aBoxes.pRight, nWidth,
+ static_cast< sal_uInt16 >( nOutWidth ),
+ static_cast< sal_uInt16 >( nInWidth ),
+ static_cast< sal_uInt16 >( nDistance ) );
+ }
+ break;
+ }
+
+ rBox.SetLine( aBoxes.pTop.get(), SvxBoxItemLine::TOP );
+ rBox.SetLine( aBoxes.pBottom.get(), SvxBoxItemLine::BOTTOM );
+ rBox.SetLine( aBoxes.pLeft.get(), SvxBoxItemLine::LEFT );
+ rBox.SetLine( aBoxes.pRight.get(), SvxBoxItemLine::RIGHT );
+
+ bOk = true;
+ }
+ break;
+
+ case RES_BREAK:
+ {
+ SvxFormatBreakItem& rFormatBreak = dynamic_cast<SvxFormatBreakItem&>(rItem);
+ sal_uInt16 eEnum{};
+
+ if( !SvXMLUnitConverter::convertEnum( eEnum, rValue, psXML_BreakType ) )
+ return false;
+
+ if( eEnum == 0 )
+ {
+ rFormatBreak.SetValue( SvxBreak::NONE );
+ bOk = true;
+ }
+ else
+ {
+ switch( nMemberId )
+ {
+ case MID_BREAK_BEFORE:
+ rFormatBreak.SetValue( eEnum == 1 ?
+ SvxBreak::ColumnBefore :
+ SvxBreak::PageBefore );
+ break;
+ case MID_BREAK_AFTER:
+ rFormatBreak.SetValue( eEnum == 1 ?
+ SvxBreak::ColumnAfter :
+ SvxBreak::PageAfter );
+ break;
+ }
+ bOk = true;
+ }
+ }
+ break;
+
+ case RES_KEEP:
+ {
+ SvxFormatKeepItem& rFormatKeep = dynamic_cast<SvxFormatKeepItem&>(rItem);
+
+ if( IsXMLToken( rValue, XML_ALWAYS ) ||
+ IsXMLToken( rValue, XML_TRUE ) )
+ {
+ rFormatKeep.SetValue( true );
+ bOk = true;
+ }
+ else if( IsXMLToken( rValue, XML_AUTO ) ||
+ IsXMLToken( rValue, XML_FALSE ) )
+ {
+ rFormatKeep.SetValue( false );
+ bOk = true;
+ }
+ }
+ break;
+
+ case RES_BACKGROUND:
+ {
+ SvxBrushItem& rBrush = dynamic_cast<SvxBrushItem&>(rItem);
+
+ Color aTempColor;
+ switch( nMemberId )
+ {
+ case MID_BACK_COLOR:
+ if( IsXMLToken( rValue, XML_TRANSPARENT ) )
+ {
+ rBrush.GetColor().SetAlpha(0);
+ bOk = true;
+ }
+ else if (::sax::Converter::convertColor(aTempColor, rValue))
+ {
+ aTempColor.SetAlpha(255);
+ rBrush.SetColor( aTempColor );
+ bOk = true;
+ }
+ break;
+
+ case MID_GRAPHIC_REPEAT:
+ {
+ SvxGraphicPosition eGraphicPos = rBrush.GetGraphicPos();
+ SvxGraphicPosition nPos = GPOS_NONE;
+ if( SvXMLUnitConverter::convertEnum( nPos, rValue,
+ psXML_BrushRepeat ) )
+ {
+ if( GPOS_MM != nPos || GPOS_NONE == eGraphicPos ||
+ GPOS_AREA == eGraphicPos || GPOS_TILED == eGraphicPos )
+ rBrush.SetGraphicPos( nPos );
+ bOk = true;
+ }
+ }
+ break;
+
+ case MID_GRAPHIC_POSITION:
+ {
+ SvxGraphicPosition ePos = GPOS_NONE, eTmp;
+ SvxGraphicPosition nTmp;
+ SvXMLTokenEnumerator aTokenEnum( rValue );
+ std::u16string_view aToken;
+ bool bHori = false, bVert = false;
+ bOk = true;
+ while( bOk && aTokenEnum.getNextToken( aToken ) )
+ {
+ if( bHori && bVert )
+ {
+ bOk = false;
+ }
+ else if( std::u16string_view::npos != aToken.find( '%' ) )
+ {
+ sal_Int32 nPrc = 50;
+ if (::sax::Converter::convertPercent(nPrc, aToken))
+ {
+ if( !bHori )
+ {
+ ePos = nPrc < 25 ? GPOS_LT :
+ (nPrc < 75 ? GPOS_MM : GPOS_RB);
+ bHori = true;
+ }
+ else
+ {
+ eTmp = nPrc < 25 ? GPOS_LT:
+ (nPrc < 75 ? GPOS_LM : GPOS_LB);
+ sw_frmitems_MergeXMLVertPos( ePos, eTmp );
+ bVert = true;
+ }
+ }
+ else
+ {
+ // wrong percentage
+ bOk = false;
+ }
+ }
+ else if( IsXMLToken( aToken, XML_CENTER ) )
+ {
+ if( bHori )
+ sw_frmitems_MergeXMLVertPos( ePos, GPOS_MM );
+ else if ( bVert )
+ sw_frmitems_MergeXMLHoriPos( ePos, GPOS_MM );
+ else
+ ePos = GPOS_MM;
+ }
+ else if( SvXMLUnitConverter::convertEnum( nTmp, aToken,
+ psXML_BrushHoriPos ) )
+ {
+ if( bVert )
+ sw_frmitems_MergeXMLHoriPos(
+ ePos, nTmp );
+ else if( !bHori )
+ ePos = nTmp;
+ else
+ bOk = false;
+ bHori = true;
+ }
+ else if( SvXMLUnitConverter::convertEnum( nTmp, aToken,
+ psXML_BrushVertPos ) )
+ {
+ if( bHori )
+ sw_frmitems_MergeXMLVertPos(
+ ePos, nTmp );
+ else if( !bVert )
+ ePos = nTmp;
+ else
+ bOk = false;
+ bVert = true;
+ }
+ else
+ {
+ bOk = false;
+ }
+ }
+
+ if( GPOS_NONE == ePos ) bOk = false;
+ if( bOk )
+ rBrush.SetGraphicPos( ePos );
+ }
+ break;
+
+ case MID_GRAPHIC_FILTER:
+ rBrush.SetGraphicFilter( rValue );
+ bOk = true;
+ break;
+ }
+ }
+ break;
+
+ case RES_PAGEDESC:
+ {
+ SwFormatPageDesc& rPageDesc = dynamic_cast<SwFormatPageDesc&>(rItem);
+
+ if( MID_PAGEDESC_PAGENUMOFFSET==nMemberId )
+ {
+ sal_Int32 nVal;
+ bOk = ::sax::Converter::convertNumber(
+ nVal, rValue, 0, USHRT_MAX);
+ // i#114163 tdf#77111: OOo < 3.3 had a bug where it wrote
+ // "auto" as "0" for tables - now that we support a real offset
+ // 0, this fake "0" MUST NOT be imported as offset 0!
+ if( bOk && nVal > 0 )
+ rPageDesc.SetNumOffset( o3tl::narrowing<sal_uInt16>(nVal) );
+ }
+ }
+ break;
+
+ case RES_LAYOUT_SPLIT:
+ case RES_ROW_SPLIT:
+ {
+ SfxBoolItem& rSplit = dynamic_cast<SfxBoolItem&>(rItem);
+
+ if( IsXMLToken( rValue, XML_AUTO ) ||
+ IsXMLToken( rValue, XML_TRUE ) )
+ {
+ rSplit.SetValue( true );
+ bOk = true;
+ }
+ else if( IsXMLToken( rValue, XML_ALWAYS ) ||
+ IsXMLToken( rValue, XML_FALSE ) )
+ {
+ rSplit.SetValue( false );
+ bOk = true;
+ }
+ }
+ break;
+
+ case RES_PRINT:
+ {
+ SfxBoolItem& rHasTextChangesOnly = dynamic_cast<SfxBoolItem&>(rItem);
+
+ if( IsXMLToken( rValue, XML_TRUE ) )
+ {
+ rHasTextChangesOnly.SetValue( true );
+ bOk = true;
+ }
+ else if( IsXMLToken( rValue, XML_FALSE ) )
+ {
+ rHasTextChangesOnly.SetValue( false );
+ bOk = true;
+ }
+ }
+ break;
+
+ case RES_HORI_ORIENT:
+ {
+ SwFormatHoriOrient& rHoriOrient = dynamic_cast<SwFormatHoriOrient&>(rItem);
+
+ sal_Int16 nValue;
+ bOk = SvXMLUnitConverter::convertEnum( nValue, rValue,
+ aXMLTableAlignMap );
+ if( bOk )
+ rHoriOrient.SetHoriOrient( nValue );
+ }
+ break;
+
+ case RES_VERT_ORIENT:
+ {
+ SwFormatVertOrient& rVertOrient = dynamic_cast<SwFormatVertOrient&>(rItem);
+
+ sal_Int16 nValue;
+ bOk = SvXMLUnitConverter::convertEnum( nValue, rValue,
+ aXMLTableVAlignMap );
+ if( bOk )
+ rVertOrient.SetVertOrient( nValue );
+ //#i8855# text::VertOrientation::NONE is stored as empty string and should be applied here
+ else if(rValue.isEmpty())
+ {
+ rVertOrient.SetVertOrient( text::VertOrientation::NONE );
+ bOk = true;
+ }
+ }
+ break;
+
+ case RES_FRM_SIZE:
+ {
+ SwFormatFrameSize& rFrameSize = dynamic_cast<SwFormatFrameSize&>(rItem);
+
+ bool bSetHeight = false;
+ bool bSetWidth = false;
+ bool bSetSizeType = false;
+ SwFrameSize eSizeType = SwFrameSize::Variable;
+ sal_Int32 nMin = MINLAY;
+
+ switch( nMemberId )
+ {
+ case MID_FRMSIZE_REL_WIDTH:
+ {
+ sal_Int32 nValue;
+ bOk = ::sax::Converter::convertPercent( nValue, rValue );
+ if( bOk )
+ {
+ if( nValue < 1 )
+ nValue = 1;
+ else if( nValue > 100 )
+ nValue = 100;
+
+ rFrameSize.SetWidthPercent( static_cast<sal_Int8>(nValue) );
+ }
+ }
+ break;
+ case MID_FRMSIZE_WIDTH:
+ bSetWidth = true;
+ break;
+ case MID_FRMSIZE_MIN_HEIGHT:
+ eSizeType = SwFrameSize::Minimum;
+ bSetHeight = true;
+ nMin = 1;
+ bSetSizeType = true;
+ break;
+ case MID_FRMSIZE_FIX_HEIGHT:
+ eSizeType = SwFrameSize::Fixed;
+ bSetHeight = true;
+ nMin = 1;
+ bSetSizeType = true;
+ break;
+ case MID_FRMSIZE_COL_WIDTH:
+ eSizeType = SwFrameSize::Fixed;
+ bSetWidth = true;
+ bSetSizeType = true;
+ break;
+ case MID_FRMSIZE_REL_COL_WIDTH:
+ {
+ sal_Int32 nPos = rValue.indexOf( '*' );
+ if( -1 != nPos )
+ {
+ sal_Int32 nValue = rValue.toInt32();
+ if( nValue < MINLAY )
+ nValue = MINLAY;
+ else if( nValue > SAL_MAX_UINT16 )
+ nValue = SAL_MAX_UINT16;
+
+ rFrameSize.SetWidth( o3tl::narrowing<sal_uInt16>(nValue) );
+ rFrameSize.SetHeightSizeType( SwFrameSize::Variable );
+ bOk = true;
+ }
+ }
+ break;
+ }
+
+ if( bSetHeight || bSetWidth )
+ {
+ sal_Int32 nValue;
+ bOk = rUnitConverter.convertMeasureToCore(nValue, rValue, nMin,
+ USHRT_MAX );
+ if( bOk )
+ {
+ if( bSetWidth )
+ rFrameSize.SetWidth( o3tl::narrowing<sal_uInt16>(nValue) );
+ if( bSetHeight )
+ rFrameSize.SetHeight( o3tl::narrowing<sal_uInt16>(nValue) );
+ if( bSetSizeType )
+ rFrameSize.SetHeightSizeType( eSizeType );
+ }
+ }
+ }
+ break;
+
+ case RES_FRAMEDIR:
+ {
+ if (IsXMLToken(rValue, XML_BT_LR))
+ {
+ // Read bt-lr from the extension namespace, handle other values
+ // below.
+ Any aAny;
+ aAny <<= static_cast<sal_uInt16>(SvxFrameDirection::Vertical_LR_BT);
+ bOk = rItem.PutValue(aAny, 0);
+ }
+ else if (IsXMLToken(rValue, XML_TB_RL90))
+ {
+ // Read tb-rl90 from the extension namespace.
+ Any aAny;
+ aAny <<= static_cast<sal_uInt16>(SvxFrameDirection::Vertical_RL_TB90);
+ bOk = rItem.PutValue(aAny, 0);
+ }
+ else
+ {
+ std::unique_ptr<XMLPropertyHandler> pWritingModeHandler =
+ XMLPropertyHandlerFactory::CreatePropertyHandler(
+ XML_TYPE_TEXT_WRITING_MODE_WITH_DEFAULT );
+ Any aAny;
+ bOk = pWritingModeHandler->importXML( rValue, aAny,
+ rUnitConverter );
+ if( bOk )
+ bOk = rItem.PutValue( aAny, 0 );
+ }
+ }
+ break;
+
+ case RES_COLLAPSING_BORDERS:
+ {
+ SfxBoolItem& rBorders = dynamic_cast<SfxBoolItem&>(rItem);
+
+ if( IsXMLToken( rValue, XML_COLLAPSING ) )
+ {
+ rBorders.SetValue(true);
+ bOk = true;
+ }
+ else if( IsXMLToken( rValue, XML_SEPARATING ) )
+ {
+ rBorders.SetValue(false);
+ bOk = true;
+ }
+ else
+ bOk = false;
+ }
+ break;
+
+ default:
+ OSL_FAIL("Item not implemented!");
+ break;
+ }
+
+ return bOk;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlimpit.hxx b/sw/source/filter/xml/xmlimpit.hxx
new file mode 100644
index 0000000000..8227546a62
--- /dev/null
+++ b/sw/source/filter/xml/xmlimpit.hxx
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SW_SOURCE_FILTER_XML_XMLIMPIT_HXX
+#define INCLUDED_SW_SOURCE_FILTER_XML_XMLIMPIT_HXX
+
+#include <com/sun/star/xml/sax/XFastAttributeList.hpp>
+#include "xmlitmap.hxx"
+
+class SvXMLUnitConverter;
+class SfxPoolItem;
+class SfxItemSet;
+class SvXMLNamespaceMap;
+struct SvXMLItemMapEntry;
+class SvXMLAttrContainerItem;
+
+class SvXMLImportItemMapper
+{
+ SvXMLItemMapEntriesRef mrMapEntries;
+
+public:
+ explicit SvXMLImportItemMapper( SvXMLItemMapEntriesRef aMapEntries );
+ virtual ~SvXMLImportItemMapper();
+
+ /** fills the given itemset with the attributes in the given list */
+ void importXML( SfxItemSet& rSet,
+ css::uno::Reference< css::xml::sax::XFastAttributeList > const & xAttrList,
+ const SvXMLUnitConverter& rUnitConverter,
+ const SvXMLNamespaceMap& rNamespaceMap );
+
+ /** this method is called for every item that has the
+ MID_SW_FLAG_SPECIAL_ITEM_IMPORT flag set */
+ virtual bool handleSpecialItem( const SvXMLItemMapEntry& rEntry,
+ SfxPoolItem& rItem,
+ SfxItemSet& rSet,
+ const OUString& rValue,
+ const SvXMLUnitConverter& rUnitConverter );
+
+ /** this method is called for every item that has the
+ MID_SW_FLAG_NO_ITEM_IMPORT flag set */
+ virtual bool handleNoItem( const SvXMLItemMapEntry& rEntry,
+ SfxItemSet& rSet,
+ const OUString& rValue,
+ const SvXMLUnitConverter& rUnitConverter,
+ const SvXMLNamespaceMap& rNamespaceMap );
+
+ /** This method is called when all attributes have benn processed. It
+ * may be used to remove items that are incomplete */
+ virtual void finished(SfxItemSet & rSet,
+ SvXMLUnitConverter const& rUnitConverter) const;
+
+ virtual void setMapEntries( SvXMLItemMapEntriesRef rMapEntries );
+ inline const SvXMLItemMapEntriesRef& getMapEntries() const;
+
+ /** This method is called for every item that should be set based
+ upon an XML attribute value. */
+ static bool PutXMLValue(
+ SfxPoolItem& rItem,
+ const OUString& rValue,
+ sal_uInt16 nMemberId,
+ const SvXMLUnitConverter& rUnitConverter );
+private:
+ void importXMLUnknownAttributes( SfxItemSet& rSet,
+ css::uno::Reference< css::xml::sax::XFastAttributeList > const & xAttrList,
+ const SvXMLUnitConverter& rUnitConverter,
+ std::unique_ptr<SvXMLAttrContainerItem>& pUnknownItem );
+
+};
+
+inline const SvXMLItemMapEntriesRef&
+SvXMLImportItemMapper::getMapEntries() const
+{
+ return mrMapEntries;
+}
+
+#endif // INCLUDED_SW_SOURCE_FILTER_XML_XMLIMPIT_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlitem.cxx b/sw/source/filter/xml/xmlitem.cxx
new file mode 100644
index 0000000000..ff98d2ff69
--- /dev/null
+++ b/sw/source/filter/xml/xmlitem.cxx
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <editeng/brushitem.hxx>
+#include <sal/log.hxx>
+#include <xmloff/xmlimp.hxx>
+#include "xmlimpit.hxx"
+#include "xmlitem.hxx"
+#include "xmlbrshi.hxx"
+#include <hintids.hxx>
+
+using namespace ::com::sun::star;
+
+SwXMLItemSetContext::SwXMLItemSetContext( SvXMLImport& rImp, sal_Int32 /*nElement*/,
+ const uno::Reference< xml::sax::XFastAttributeList >& xAttrList,
+ SfxItemSet& rISet,
+ SvXMLImportItemMapper& rIMap,
+ const SvXMLUnitConverter& rUnitConverter ):
+ SvXMLImportContext( rImp ),
+ m_rItemSet( rISet ),
+ m_rIMapper( rIMap ),
+ m_rUnitConv( rUnitConverter )
+{
+ rIMap.importXML( m_rItemSet, xAttrList, m_rUnitConv,
+ GetImport().GetNamespaceMap() );
+}
+
+SwXMLItemSetContext::~SwXMLItemSetContext()
+{
+ if( m_xBackground.is() )
+ {
+ const SvxBrushItem& rItem = m_xBackground->GetItem();
+ m_rItemSet.Put( rItem );
+ }
+}
+
+css::uno::Reference< css::xml::sax::XFastContextHandler > SwXMLItemSetContext::createFastChildContext(
+ sal_Int32 nElement,
+ const uno::Reference< xml::sax::XFastAttributeList >& xAttrList )
+{
+ SvXMLItemMapEntriesRef xMapEntries = m_rIMapper.getMapEntries();
+ SvXMLItemMapEntry const * pEntry = xMapEntries->getByName( nElement );
+
+ if( pEntry && 0 != (pEntry->nMemberId & MID_SW_FLAG_ELEMENT_ITEM_IMPORT) )
+ {
+ return createFastChildContext( nElement, xAttrList, *pEntry );
+ }
+ else
+ XMLOFF_WARN_UNKNOWN_ELEMENT("sw", nElement);
+ return nullptr;
+}
+
+/** This method is called from this instance implementation of
+ CreateChildContext if the element matches an entry in the
+ SvXMLImportItemMapper with the mid flag MID_SW_FLAG_ELEMENT
+*/
+SvXMLImportContextRef SwXMLItemSetContext::createFastChildContext( sal_Int32 nElement,
+ const uno::Reference< xml::sax::XFastAttributeList >& xAttrList,
+ const SvXMLItemMapEntry& rEntry )
+{
+ rtl::Reference<SwXMLBrushItemImportContext> xContext;
+
+ switch( rEntry.nWhichId )
+ {
+ case RES_BACKGROUND:
+ {
+ if( const SvxBrushItem* pItem = m_rItemSet.GetItemIfSet( RES_BACKGROUND,
+ false ) )
+ {
+ xContext = new SwXMLBrushItemImportContext(
+ GetImport(), nElement, xAttrList,
+ m_rUnitConv, *pItem );
+ }
+ else
+ {
+ xContext = new SwXMLBrushItemImportContext(
+ GetImport(), nElement, xAttrList,
+ m_rUnitConv, RES_BACKGROUND );
+ }
+ m_xBackground = xContext;
+ }
+ break;
+ }
+
+ return xContext;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlitem.hxx b/sw/source/filter/xml/xmlitem.hxx
new file mode 100644
index 0000000000..cd6f9c8db6
--- /dev/null
+++ b/sw/source/filter/xml/xmlitem.hxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SW_SOURCE_FILTER_XML_XMLITEM_HXX
+#define INCLUDED_SW_SOURCE_FILTER_XML_XMLITEM_HXX
+
+#include <com/sun/star/xml/sax/XFastAttributeList.hpp>
+#include <svl/itemset.hxx>
+#include <xmloff/xmlictxt.hxx>
+
+class SfxItemSet;
+class SvXMLImportItemMapper;
+class SvXMLUnitConverter;
+struct SvXMLItemMapEntry;
+class SwXMLBrushItemImportContext;
+
+class SwXMLItemSetContext final : public SvXMLImportContext
+{
+ SfxItemSet &m_rItemSet;
+ const SvXMLImportItemMapper &m_rIMapper;
+ const SvXMLUnitConverter &m_rUnitConv;
+ rtl::Reference<SwXMLBrushItemImportContext> m_xBackground;
+
+public:
+
+ SwXMLItemSetContext( SvXMLImport& rImport, sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList,
+ SfxItemSet& rItemSet,
+ SvXMLImportItemMapper& rIMap,
+ const SvXMLUnitConverter& rUnitConv );
+
+ virtual ~SwXMLItemSetContext() override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+
+private:
+ // This method is called from this instance implementation of
+ // createFastChildContext if the element matches an entry in the
+ // SvXMLImportItemMapper with the mid flag MID_SW_FLAG_ELEMENT_ITEM_IMPORT
+ SvXMLImportContextRef createFastChildContext( sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList,
+ const SvXMLItemMapEntry& rEntry );
+};
+
+#endif // INCLUDED_SW_SOURCE_FILTER_XML_XMLITEM_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmliteme.cxx b/sw/source/filter/xml/xmliteme.cxx
new file mode 100644
index 0000000000..3d19a9d6dc
--- /dev/null
+++ b/sw/source/filter/xml/xmliteme.cxx
@@ -0,0 +1,246 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/util/MeasureUnit.hpp>
+
+#include <hintids.hxx>
+#include <rtl/ustring.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <utility>
+#include <xmloff/xmluconv.hxx>
+#include "xmlexpit.hxx"
+#include <xmloff/namespacemap.hxx>
+#include "xmlbrshe.hxx"
+#include <editeng/brushitem.hxx>
+#include <fmtornt.hxx>
+#include <unomid.h>
+#include <frmfmt.hxx>
+#include "xmlexp.hxx"
+#include <editeng/memberids.h>
+#include <editeng/prntitem.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::xmloff::token;
+
+namespace {
+
+class SwXMLTableItemMapper_Impl: public SvXMLExportItemMapper
+{
+ SwXMLBrushItemExport m_aBrushItemExport;
+
+protected:
+
+ sal_uInt32 m_nAbsWidth;
+
+ static void AddAttribute( sal_uInt16 nPrefix, enum XMLTokenEnum eLName,
+ const OUString& rValue,
+ const SvXMLNamespaceMap& rNamespaceMap,
+ comphelper::AttributeList& rAttrList );
+
+public:
+
+ SwXMLTableItemMapper_Impl(
+ SvXMLItemMapEntriesRef rMapEntries,
+ SwXMLExport& rExp );
+
+ virtual void handleSpecialItem( comphelper::AttributeList& rAttrList,
+ const SvXMLItemMapEntry& rEntry,
+ const SfxPoolItem& rItem,
+ const SvXMLUnitConverter& rUnitConverter,
+ const SvXMLNamespaceMap& rNamespaceMap,
+ const SfxItemSet *pSet ) const override;
+
+ virtual void handleElementItem(
+ const SvXMLItemMapEntry& rEntry,
+ const SfxPoolItem& rItem ) const override;
+
+ inline void SetAbsWidth( sal_uInt32 nAbs );
+};
+
+}
+
+SwXMLTableItemMapper_Impl::SwXMLTableItemMapper_Impl(
+ SvXMLItemMapEntriesRef rMapEntries,
+ SwXMLExport& rExp ) :
+ SvXMLExportItemMapper( std::move(rMapEntries) ),
+ m_aBrushItemExport( rExp ),
+ m_nAbsWidth( USHRT_MAX )
+{
+}
+
+void SwXMLTableItemMapper_Impl::AddAttribute( sal_uInt16 nPrefix,
+ enum XMLTokenEnum eLName,
+ const OUString& rValue,
+ const SvXMLNamespaceMap& rNamespaceMap,
+ comphelper::AttributeList& rAttrList )
+{
+ OUString sName( rNamespaceMap.GetQNameByKey( nPrefix,
+ GetXMLToken(eLName) ) );
+ rAttrList.AddAttribute( sName, rValue );
+}
+
+void SwXMLTableItemMapper_Impl::handleSpecialItem(
+ comphelper::AttributeList& rAttrList,
+ const SvXMLItemMapEntry& rEntry,
+ const SfxPoolItem& rItem,
+ const SvXMLUnitConverter& rUnitConverter,
+ const SvXMLNamespaceMap& rNamespaceMap,
+ const SfxItemSet *pSet ) const
+{
+ switch( rEntry.nWhichId )
+ {
+
+ case RES_PRINT:
+ {
+ const SvxPrintItem *pItem;
+ if( pSet &&
+ (pItem = pSet->GetItemIfSet( RES_PRINT )) )
+ {
+ bool bHasTextChangesOnly = pItem->GetValue();
+ if ( !bHasTextChangesOnly )
+ {
+ OUString sValue;
+ sal_uInt16 nMemberId =
+ static_cast<sal_uInt16>( rEntry.nMemberId & MID_SW_FLAG_MASK );
+
+ if( SvXMLExportItemMapper::QueryXMLValue(
+ rItem, sValue, nMemberId, rUnitConverter ) )
+ {
+ AddAttribute( rEntry.nNameSpace, rEntry.eLocalName,
+ sValue, rNamespaceMap, rAttrList );
+ }
+ }
+ }
+ }
+ break;
+
+ case RES_LR_SPACE:
+ {
+ const SwFormatHoriOrient *pItem;
+ if( pSet &&
+ (pItem = pSet->GetItemIfSet( RES_HORI_ORIENT )) )
+ {
+ sal_Int16 eHoriOrient = pItem->GetHoriOrient();
+ bool bExport = false;
+ sal_uInt16 nMemberId =
+ o3tl::narrowing<sal_uInt16>( rEntry.nMemberId & MID_SW_FLAG_MASK );
+ switch( nMemberId )
+ {
+ case MID_L_MARGIN:
+ bExport = text::HoriOrientation::NONE == eHoriOrient ||
+ text::HoriOrientation::LEFT_AND_WIDTH == eHoriOrient;
+ break;
+ case MID_R_MARGIN:
+ bExport = text::HoriOrientation::NONE == eHoriOrient;
+ break;
+ }
+ OUString sValue;
+ if( bExport && SvXMLExportItemMapper::QueryXMLValue(
+ rItem, sValue, nMemberId, rUnitConverter ) )
+ {
+ AddAttribute( rEntry.nNameSpace, rEntry.eLocalName, sValue,
+ rNamespaceMap, rAttrList );
+ }
+ }
+ }
+ break;
+
+ case RES_FRM_SIZE:
+ {
+ sal_uInt16 nMemberId =
+ o3tl::narrowing<sal_uInt16>( rEntry.nMemberId & MID_SW_FLAG_MASK );
+ switch( nMemberId )
+ {
+ case MID_FRMSIZE_WIDTH:
+ if( m_nAbsWidth )
+ {
+ OUStringBuffer sBuffer;
+ rUnitConverter.convertMeasureToXML( sBuffer, m_nAbsWidth );
+ AddAttribute( rEntry.nNameSpace, rEntry.eLocalName,
+ sBuffer.makeStringAndClear(),
+ rNamespaceMap, rAttrList );
+ }
+ break;
+ case MID_FRMSIZE_REL_WIDTH:
+ {
+ OUString sValue;
+ if( SvXMLExportItemMapper::QueryXMLValue(
+ rItem, sValue, nMemberId, rUnitConverter ) )
+ {
+ AddAttribute( rEntry.nNameSpace, rEntry.eLocalName,
+ sValue, rNamespaceMap, rAttrList );
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+}
+
+/** this method is called for every item that has the
+ MID_SW_FLAG_ELEMENT_EXPORT flag set */
+void SwXMLTableItemMapper_Impl::handleElementItem(
+ const SvXMLItemMapEntry& rEntry,
+ const SfxPoolItem& rItem ) const
+{
+ switch( rEntry.nWhichId )
+ {
+ case RES_BACKGROUND:
+ {
+ const_cast<SwXMLTableItemMapper_Impl *>(this)->m_aBrushItemExport.exportXML(
+ static_cast<const SvxBrushItem&>(rItem) );
+ }
+ break;
+ }
+}
+
+inline void SwXMLTableItemMapper_Impl::SetAbsWidth( sal_uInt32 nAbs )
+{
+ m_nAbsWidth = nAbs;
+}
+
+void SwXMLExport::InitItemExport()
+{
+ m_pTwipUnitConverter.reset(new SvXMLUnitConverter(getComponentContext(),
+ util::MeasureUnit::TWIP, GetMM100UnitConverter().GetXMLMeasureUnit(),
+ getSaneDefaultVersion()));
+
+ m_xTableItemMap = new SvXMLItemMapEntries( aXMLTableItemMap );
+ m_xTableRowItemMap = new SvXMLItemMapEntries( aXMLTableRowItemMap );
+ m_xTableCellItemMap = new SvXMLItemMapEntries( aXMLTableCellItemMap );
+
+ m_pTableItemMapper.reset(new SwXMLTableItemMapper_Impl( m_xTableItemMap, *this ));
+}
+
+void SwXMLExport::FinitItemExport()
+{
+ m_pTableItemMapper.reset();
+ m_pTwipUnitConverter.reset();
+}
+
+void SwXMLExport::ExportTableFormat( const SwFrameFormat& rFormat, sal_uInt32 nAbsWidth )
+{
+ static_cast<SwXMLTableItemMapper_Impl *>(m_pTableItemMapper.get())
+ ->SetAbsWidth( nAbsWidth );
+ ExportFormat(rFormat, XML_TABLE, {});
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlitemi.cxx b/sw/source/filter/xml/xmlitemi.cxx
new file mode 100644
index 0000000000..9281604c4f
--- /dev/null
+++ b/sw/source/filter/xml/xmlitemi.cxx
@@ -0,0 +1,278 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <rtl/ustring.hxx>
+#include <osl/diagnose.h>
+
+#include <com/sun/star/util/MeasureUnit.hpp>
+
+#include <xmloff/xmluconv.hxx>
+#include <xmloff/families.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/xmltoken.hxx>
+
+#include <editeng/memberids.h>
+#include <svl/itemset.hxx>
+#include <svl/itempool.hxx>
+
+#include <hintids.hxx>
+#include <unomid.h>
+#include "xmlimp.hxx"
+#include "xmlitmap.hxx"
+#include "xmlimpit.hxx"
+#include "xmlitem.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace {
+
+class SwXMLImportTableItemMapper_Impl: public SvXMLImportItemMapper
+{
+
+public:
+
+ explicit SwXMLImportTableItemMapper_Impl(const SvXMLItemMapEntriesRef& rMapEntries);
+
+ virtual bool handleSpecialItem( const SvXMLItemMapEntry& rEntry,
+ SfxPoolItem& rItem,
+ SfxItemSet& rSet,
+ const OUString& rValue,
+ const SvXMLUnitConverter& rUnitConverter ) override;
+
+ virtual bool
+ handleNoItem(SvXMLItemMapEntry const& rEntry,
+ SfxItemSet & rSet,
+ OUString const& rValue,
+ SvXMLUnitConverter const& rUnitConverter,
+ SvXMLNamespaceMap const& rNamespaceMap) override;
+
+ virtual void finished(SfxItemSet & rSet,
+ SvXMLUnitConverter const& rUnitConverter) const override;
+
+ virtual void setMapEntries( SvXMLItemMapEntriesRef rMapEntries ) override;
+
+private:
+ void Reset();
+
+ OUString m_FoMarginValue;
+ enum { LEFT = 0, RIGHT = 1, TOP = 2, BOTTOM = 3 };
+ bool m_bHaveMargin[4];
+};
+
+}
+
+SwXMLImportTableItemMapper_Impl::SwXMLImportTableItemMapper_Impl(
+ const SvXMLItemMapEntriesRef& rMapEntries ) :
+ SvXMLImportItemMapper( rMapEntries )
+{
+ Reset();
+}
+
+void SwXMLImportTableItemMapper_Impl::Reset()
+{
+ m_FoMarginValue.clear();
+ for (int i = 0; i < 3; ++i)
+ {
+ m_bHaveMargin[i] = false;
+ }
+}
+
+void SwXMLImportTableItemMapper_Impl::setMapEntries(
+ SvXMLItemMapEntriesRef rMapEntries )
+{
+ Reset();
+ SvXMLImportItemMapper::setMapEntries(rMapEntries);
+}
+
+bool SwXMLImportTableItemMapper_Impl::handleSpecialItem(
+ const SvXMLItemMapEntry& rEntry,
+ SfxPoolItem& rItem,
+ SfxItemSet& rItemSet,
+ const OUString& rValue,
+ const SvXMLUnitConverter& rUnitConv )
+{
+ bool bRet = false;
+ sal_uInt16 nMemberId = static_cast< sal_Int16 >(rEntry.nMemberId & MID_SW_FLAG_MASK);
+ switch( rItem.Which() )
+ {
+ case RES_LR_SPACE:
+ switch (nMemberId)
+ {
+ case MID_L_MARGIN:
+ m_bHaveMargin[LEFT] = true;
+ break;
+ case MID_R_MARGIN:
+ m_bHaveMargin[RIGHT] = true;
+ break;
+ }
+ bRet = SvXMLImportItemMapper::PutXMLValue(
+ rItem, rValue, nMemberId, rUnitConv);
+ break;
+ case RES_UL_SPACE:
+ switch (nMemberId)
+ {
+ case MID_UP_MARGIN:
+ m_bHaveMargin[TOP] = true;
+ break;
+ case MID_LO_MARGIN:
+ m_bHaveMargin[BOTTOM] = true;
+ break;
+ }
+ bRet = SvXMLImportItemMapper::PutXMLValue(
+ rItem, rValue, nMemberId, rUnitConv);
+ break;
+ case RES_FRM_SIZE:
+ switch( nMemberId )
+ {
+ case MID_FRMSIZE_COL_WIDTH:
+ // If the item is existing already, a relative value has been set
+ // already that must be preserved.
+ if( SfxItemState::SET != rItemSet.GetItemState( RES_FRM_SIZE,
+ false ) )
+ bRet = SvXMLImportItemMapper::PutXMLValue(
+ rItem, rValue, nMemberId, rUnitConv );
+ break;
+ }
+ }
+
+ return bRet;
+}
+
+bool SwXMLImportTableItemMapper_Impl::handleNoItem(
+ SvXMLItemMapEntry const& rEntry,
+ SfxItemSet & rSet,
+ OUString const& rValue,
+ SvXMLUnitConverter const& rUnitConverter,
+ SvXMLNamespaceMap const& rNamespaceMap)
+{
+ if ((XML_NAMESPACE_FO == rEntry.nNameSpace) &&
+ (xmloff::token::XML_MARGIN == rEntry.eLocalName))
+ {
+ m_FoMarginValue = rValue;
+ return true;
+ }
+ else
+ {
+ return SvXMLImportItemMapper::handleNoItem(
+ rEntry, rSet, rValue, rUnitConverter, rNamespaceMap);
+ }
+}
+
+void SwXMLImportTableItemMapper_Impl::finished(
+ SfxItemSet & rSet, SvXMLUnitConverter const& rUnitConverter) const
+{
+ if (m_FoMarginValue.isEmpty())
+ return;
+
+ sal_uInt16 const Ids[4][2] = {
+ { RES_LR_SPACE, MID_L_MARGIN },
+ { RES_LR_SPACE, MID_R_MARGIN },
+ { RES_UL_SPACE, MID_UP_MARGIN },
+ { RES_UL_SPACE, MID_LO_MARGIN },
+ };
+ for (int i = 0; i < 4; ++i)
+ {
+ if (m_bHaveMargin[i])
+ {
+ continue; // already read fo:margin-top etc.
+ }
+ // first get item from itemset
+ SfxPoolItem const* pItem = nullptr;
+ SfxItemState eState =
+ rSet.GetItemState(Ids[i][0], true, &pItem);
+
+ // if not set, try the pool
+ if ((SfxItemState::SET != eState) && SfxItemPool::IsWhich(Ids[i][0]))
+ {
+ pItem = &rSet.GetPool()->GetDefaultItem(Ids[i][0]);
+ }
+
+ // do we have an item?
+ if (eState >= SfxItemState::DEFAULT && pItem)
+ {
+ std::unique_ptr<SfxPoolItem> pNewItem(pItem->Clone());
+ bool const bPut = PutXMLValue(
+ *pNewItem, m_FoMarginValue, Ids[i][1], rUnitConverter);
+ if (bPut)
+ {
+ rSet.Put(std::move(pNewItem));
+ }
+ }
+ else
+ {
+ OSL_ENSURE(false, "could not get item");
+ }
+ }
+}
+
+void SwXMLImport::InitItemImport()
+{
+ m_pTwipUnitConv.reset( new SvXMLUnitConverter( GetComponentContext(),
+ util::MeasureUnit::TWIP, util::MeasureUnit::TWIP,
+ SvtSaveOptions::ODFSVER_LATEST_EXTENDED) );
+
+ m_xTableItemMap = new SvXMLItemMapEntries( aXMLTableItemMap );
+ m_xTableColItemMap = new SvXMLItemMapEntries( aXMLTableColItemMap );
+ m_xTableRowItemMap = new SvXMLItemMapEntries( aXMLTableRowItemMap );
+ m_xTableCellItemMap = new SvXMLItemMapEntries( aXMLTableCellItemMap );
+
+ m_pTableItemMapper.reset( new SwXMLImportTableItemMapper_Impl( m_xTableItemMap ) );
+}
+
+void SwXMLImport::FinitItemImport()
+{
+ m_pTableItemMapper.reset();
+ m_pTwipUnitConv.reset();
+}
+
+SvXMLImportContext *SwXMLImport::CreateTableItemImportContext(
+ sal_Int32 nElement,
+ const Reference< xml::sax::XFastAttributeList > & xAttrList,
+ XmlStyleFamily nFamily,
+ SfxItemSet& rItemSet )
+{
+ SvXMLItemMapEntriesRef xItemMap;
+
+ switch( nFamily )
+ {
+ case XmlStyleFamily::TABLE_TABLE:
+ xItemMap = m_xTableItemMap;
+ break;
+ case XmlStyleFamily::TABLE_COLUMN:
+ xItemMap = m_xTableColItemMap;
+ break;
+ case XmlStyleFamily::TABLE_ROW:
+ xItemMap = m_xTableRowItemMap;
+ break;
+ case XmlStyleFamily::TABLE_CELL:
+ xItemMap = m_xTableCellItemMap;
+ break;
+ default: break;
+ }
+
+ m_pTableItemMapper->setMapEntries( xItemMap );
+
+ return new SwXMLItemSetContext( *this, nElement,
+ xAttrList, rItemSet,
+ GetTableItemMapper(),
+ *m_pTwipUnitConv );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlitemm.cxx b/sw/source/filter/xml/xmlitemm.cxx
new file mode 100644
index 0000000000..0d25da02c1
--- /dev/null
+++ b/sw/source/filter/xml/xmlitemm.cxx
@@ -0,0 +1,286 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <editeng/memberids.h>
+#include <hintids.hxx>
+#include <svx/unomid.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include "xmlitmap.hxx"
+#include <xmloff/xmltoken.hxx>
+#include <o3tl/safeint.hxx>
+
+#include <unomid.h>
+
+using namespace ::xmloff::token;
+
+#define MAP_ENTRY( p, l, w, m ) \
+ { XML_NAMESPACE_##p, XML_##l, o3tl::narrowing<sal_uInt16>(w), m }
+#define M_E_SI( p, l, w, m ) \
+ { XML_NAMESPACE_##p, XML_##l, o3tl::narrowing<sal_uInt16>(w), MID_SW_FLAG_SPECIAL_ITEM_IMPORT|m }
+#define M_E_SE( p, l, w, m ) \
+ { XML_NAMESPACE_##p, XML_##l, o3tl::narrowing<sal_uInt16>(w), MID_SW_FLAG_SPECIAL_ITEM_EXPORT|m }
+#define M_E_SIE( p, l, w, m ) \
+ { XML_NAMESPACE_##p, XML_##l, o3tl::narrowing<sal_uInt16>(w), MID_SW_FLAG_SPECIAL_ITEM_EXPORT|MID_SW_FLAG_SPECIAL_ITEM_IMPORT|m }
+
+const SvXMLItemMapEntry aTableItemMap[] =
+{
+ // RES_FILL_ORDER
+ // not required
+ // RES_FRM_SIZE
+ M_E_SE( STYLE, WIDTH, RES_FRM_SIZE, MID_FRMSIZE_WIDTH ),
+ M_E_SE( STYLE, REL_WIDTH, RES_FRM_SIZE, MID_FRMSIZE_REL_WIDTH ),
+ // RES_PAPER_BIN
+ // not required
+ M_E_SE( FO, MARGIN, 0xFFFF/*invalid*/, MID_SW_FLAG_NO_ITEM_IMPORT),
+ M_E_SIE( FO, MARGIN_LEFT, RES_LR_SPACE, MID_L_MARGIN ),
+ M_E_SIE( FO, MARGIN_RIGHT, RES_LR_SPACE, MID_R_MARGIN ),
+ // RES_UL_SPACE
+ M_E_SI( FO, MARGIN_TOP, RES_UL_SPACE, MID_UP_MARGIN ),
+ M_E_SI( FO, MARGIN_BOTTOM, RES_UL_SPACE, MID_LO_MARGIN ),
+ // RES_PAGEDESC
+ MAP_ENTRY( STYLE, PAGE_NUMBER, RES_PAGEDESC, MID_PAGEDESC_PAGENUMOFFSET),
+ // RES_BREAK
+ MAP_ENTRY( FO, BREAK_BEFORE, RES_BREAK, MID_BREAK_BEFORE ),
+ MAP_ENTRY( FO, BREAK_AFTER, RES_BREAK, MID_BREAK_AFTER ),
+ // RES_CNTNT
+ // not required
+ // RES_HEADER
+ // not required
+ // RES_FOOTER
+ // not required
+ // RES_PRINT
+ // not required
+ // RES_OPAQUE
+ // not required
+ // RES_PROTECT
+ // not required
+ // RES_SURROUND
+ // not required
+ // RES_VERT_ORIENT
+ // not required
+ // RES_HORI_ORIENT
+ MAP_ENTRY( TABLE, ALIGN, RES_HORI_ORIENT, 0 ),
+ // RES_ANCHOR
+ // not required
+ // RES_BACKGROUND
+ MAP_ENTRY( FO, BACKGROUND_COLOR, RES_BACKGROUND, MID_BACK_COLOR ),
+ MAP_ENTRY( STYLE, BACKGROUND_IMAGE, RES_BACKGROUND, MID_SW_FLAG_ELEMENT_ITEM ),
+ // RES_BOX
+ // not required
+ // RES_SHADOW
+ MAP_ENTRY( STYLE, SHADOW, RES_SHADOW, 0 ),
+ // RES_FRMMACRO
+ // not required
+ // RES_COL
+ // not required
+ // RES_KEEP
+ MAP_ENTRY( FO, KEEP_WITH_NEXT, RES_KEEP, 0 ),
+ // RES_URL
+ // not required
+ // RES_EDIT_IN_READONLY
+ // not required
+ // RES_LAYOUT_SPLIT
+ MAP_ENTRY( STYLE, MAY_BREAK_BETWEEN_ROWS, RES_LAYOUT_SPLIT, 0 ),
+ // RES_CHAIN
+ // not required
+ // RES_LINENUMBER
+ // not required
+ // RES_FTN_AT_TXTEND
+ // not required
+ // RES_END_AT_TXTEND
+ // not required
+ // RES_UNKNOWNATR_CONTAINER
+ M_E_SE( TEXT, XMLNS, RES_UNKNOWNATR_CONTAINER, 0 ),
+
+ // RES_FRAMEDIR
+ MAP_ENTRY( STYLE, WRITING_MODE, RES_FRAMEDIR, 0 ),
+
+ // RES_COLLAPSING_BORDERS
+ MAP_ENTRY( TABLE, BORDER_MODEL, RES_COLLAPSING_BORDERS, 0 )
+};
+const std::span<SvXMLItemMapEntry const> aXMLTableItemMap(aTableItemMap);
+
+const SvXMLItemMapEntry aTableColItemMap[] =
+{
+ M_E_SI( STYLE, COLUMN_WIDTH, RES_FRM_SIZE, MID_FRMSIZE_COL_WIDTH ),
+ MAP_ENTRY( STYLE, REL_COLUMN_WIDTH, RES_FRM_SIZE, MID_FRMSIZE_REL_COL_WIDTH ),
+};
+const std::span<SvXMLItemMapEntry const> aXMLTableColItemMap(aTableColItemMap);
+
+const SvXMLItemMapEntry aTableRowItemMap[] =
+{
+ // RES_FILL_ORDER
+ // not required
+ // RES_FRM_SIZE
+ MAP_ENTRY( STYLE, ROW_HEIGHT, RES_FRM_SIZE, MID_FRMSIZE_FIX_HEIGHT ),
+ MAP_ENTRY( STYLE, MIN_ROW_HEIGHT, RES_FRM_SIZE, MID_FRMSIZE_MIN_HEIGHT ),
+ // RES_PAPER_BIN
+ // not required
+ // RES_LR_SPACE
+ // not required
+ // RES_UL_SPACE
+ // not required
+ // RES_PAGEDESC
+ // not required
+ // RES_BREAK
+ // not required
+ // RES_CNTNT
+ // not required
+ // RES_HEADER
+ // not required
+ // RES_FOOTER
+ // not required
+ // RES_PRINT
+ // M_E_SE( STYLE, TEXT_CHANGES_ONLY, RES_PRINT, 0 ),
+ M_E_SE( LO_EXT, TEXT_CHANGES_ONLY, RES_PRINT, 0 ),
+ // RES_OPAQUE
+ // not required
+ // RES_PROTECT
+ // not required
+ // RES_SURROUND
+ // not required
+ // RES_VERT_ORIENT
+ // not required
+ // RES_HORI_ORIENT
+ // not required
+ // RES_ANCHOR
+ // not required
+ // RES_BACKGROUND
+ MAP_ENTRY( FO, BACKGROUND_COLOR, RES_BACKGROUND, MID_BACK_COLOR ),
+ MAP_ENTRY( STYLE, BACKGROUND_IMAGE, RES_BACKGROUND, MID_SW_FLAG_ELEMENT_ITEM ),
+ // RES_BOX
+ // not required
+ // RES_ANCHOR
+ // not required
+ // RES_SHADOW
+ // not required
+ // RES_FRMMACRO
+ // not required
+ // RES_COL
+ // not required
+ // RES_KEEP
+ // not required
+ // RES_URL
+ // not required
+ // RES_EDIT_IN_READONLY
+ // not required
+ // RES_LAYOUT_SPLIT
+ M_E_SE( STYLE, KEEP_TOGETHER, RES_ROW_SPLIT, 0 ),
+ M_E_SE( FO, KEEP_TOGETHER, RES_ROW_SPLIT, 0 ),
+ // RES_CHAIN
+ // not required
+ // RES_LINENUMBER
+ // not required
+ // RES_FTN_AT_TXTEND
+ // not required
+ // RES_END_AT_TXTEND
+ // not required
+ // RES_UNKNOWNATR_CONTAINER
+ M_E_SE( TEXT, XMLNS, RES_UNKNOWNATR_CONTAINER, 0 )
+};
+const std::span<SvXMLItemMapEntry const> aXMLTableRowItemMap(aTableRowItemMap);
+
+const SvXMLItemMapEntry aTableCellItemMap[] =
+{
+ // RES_FILL_ORDER
+ // not required
+ // RES_FRM_SIZE
+ // not required
+ // RES_PAPER_BIN
+ // not required
+ // RES_LR_SPACE
+ // not required
+ // RES_UL_SPACE
+ // not required
+ // RES_PAGEDESC
+ // not required
+ // RES_BREAK
+ // not required
+ // RES_CNTNT
+ // not required
+ // RES_HEADER
+ // not required
+ // RES_FOOTER
+ // not required
+ // RES_PRINT
+ // M_E_SE( STYLE, TEXT_CHANGES_ONLY, RES_PRINT, 0 ),
+ M_E_SE( LO_EXT, TEXT_CHANGES_ONLY, RES_PRINT, 0 ),
+ // RES_OPAQUE
+ // not required
+ // RES_PROTECT
+ // not required
+ // RES_SURROUND
+ // not required
+ // RES_VERT_ORIENT
+ MAP_ENTRY( STYLE, VERTICAL_ALIGN, RES_VERT_ORIENT, 0 ),
+ // RES_HORI_ORIENT
+ // not required
+ // RES_ANCHOR
+ // not required
+ // RES_BACKGROUND
+ MAP_ENTRY( FO, BACKGROUND_COLOR, RES_BACKGROUND, MID_BACK_COLOR ),
+ MAP_ENTRY( STYLE, BACKGROUND_IMAGE, RES_BACKGROUND, MID_SW_FLAG_ELEMENT_ITEM ),
+ // RES_BOX
+ MAP_ENTRY( STYLE, BORDER_LINE_WIDTH, RES_BOX, ALL_BORDER_LINE_WIDTH ),
+ MAP_ENTRY( STYLE, BORDER_LINE_WIDTH_LEFT, RES_BOX, LEFT_BORDER_LINE_WIDTH ),
+ MAP_ENTRY( STYLE, BORDER_LINE_WIDTH_RIGHT, RES_BOX, RIGHT_BORDER_LINE_WIDTH ),
+ MAP_ENTRY( STYLE, BORDER_LINE_WIDTH_TOP, RES_BOX, TOP_BORDER_LINE_WIDTH ),
+ MAP_ENTRY( STYLE, BORDER_LINE_WIDTH_BOTTOM, RES_BOX, BOTTOM_BORDER_LINE_WIDTH ),
+ MAP_ENTRY( FO, PADDING, RES_BOX, ALL_BORDER_PADDING ),
+ MAP_ENTRY( FO, PADDING_LEFT, RES_BOX, LEFT_BORDER_PADDING ),
+ MAP_ENTRY( FO, PADDING_RIGHT, RES_BOX, RIGHT_BORDER_PADDING ),
+ MAP_ENTRY( FO, PADDING_TOP, RES_BOX, TOP_BORDER_PADDING ),
+ MAP_ENTRY( FO, PADDING_BOTTOM, RES_BOX, BOTTOM_BORDER_PADDING ),
+ MAP_ENTRY( FO, BORDER, RES_BOX, ALL_BORDER ),
+ MAP_ENTRY( FO, BORDER_LEFT, RES_BOX, LEFT_BORDER ),
+ MAP_ENTRY( FO, BORDER_RIGHT, RES_BOX, RIGHT_BORDER ),
+ MAP_ENTRY( FO, BORDER_TOP, RES_BOX, TOP_BORDER ),
+ MAP_ENTRY( FO, BORDER_BOTTOM, RES_BOX, BOTTOM_BORDER ),
+ // RES_SHADOW
+ // not required
+ // RES_FRMMACRO
+ // not required
+ // RES_COL
+ // not required
+ // RES_KEEP
+ // not required
+ // RES_URL
+ // not required
+ // RES_EDIT_IN_READONLY
+ // not required
+ // RES_LAYOUT_SPLIT
+ // not required
+ // RES_CHAIN
+ // not required
+ // RES_LINENUMBER
+ // not required
+ // RES_FTN_AT_TXTEND
+ // not required
+ // RES_END_AT_TXTEND
+ // not required
+ // RES_UNKNOWNATR_CONTAINER
+ M_E_SE( TEXT, XMLNS, RES_UNKNOWNATR_CONTAINER, 0 ),
+
+ // RES_FRAMEDIR
+ MAP_ENTRY( STYLE, WRITING_MODE, RES_FRAMEDIR, 0 ),
+ MAP_ENTRY( LO_EXT, WRITING_MODE, RES_FRAMEDIR, 0 ),
+};
+const std::span<SvXMLItemMapEntry const> aXMLTableCellItemMap(aTableCellItemMap);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlithlp.cxx b/sw/source/filter/xml/xmlithlp.cxx
new file mode 100644
index 0000000000..d629765d78
--- /dev/null
+++ b/sw/source/filter/xml/xmlithlp.cxx
@@ -0,0 +1,333 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <limits.h>
+
+#include "xmlithlp.hxx"
+#include <sax/tools/converter.hxx>
+#include <editeng/borderline.hxx>
+#include <editeng/brushitem.hxx>
+
+#include <xmloff/xmluconv.hxx>
+#include <osl/diagnose.h>
+#include <o3tl/safeint.hxx>
+
+#include <com/sun/star/table/BorderLineStyle.hpp>
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+
+using ::editeng::SvxBorderLine;
+using namespace ::xmloff::token;
+using namespace ::com::sun::star;
+
+#define SVX_XML_BORDER_WIDTH_THIN 0
+#define SVX_XML_BORDER_WIDTH_MIDDLE 1
+#define SVX_XML_BORDER_WIDTH_THICK 2
+
+const struct SvXMLEnumMapEntry<sal_uInt16> psXML_BorderStyles[] =
+{
+ { XML_NONE, table::BorderLineStyle::NONE },
+ { XML_HIDDEN, table::BorderLineStyle::NONE },
+ { XML_SOLID, table::BorderLineStyle::SOLID },
+ { XML_DOUBLE, table::BorderLineStyle::DOUBLE },
+ { XML_DOUBLE_THIN, table::BorderLineStyle::DOUBLE_THIN },
+ { XML_DOTTED, table::BorderLineStyle::DOTTED },
+ { XML_DASHED, table::BorderLineStyle::DASHED },
+ { XML_FINE_DASHED, table::BorderLineStyle::FINE_DASHED },
+ { XML_DASH_DOT, table::BorderLineStyle::DASH_DOT },
+ { XML_DASH_DOT_DOT, table::BorderLineStyle::DASH_DOT_DOT },
+ { XML_GROOVE, table::BorderLineStyle::ENGRAVED },
+ { XML_RIDGE, table::BorderLineStyle::EMBOSSED },
+ { XML_INSET, table::BorderLineStyle::INSET },
+ { XML_OUTSET, table::BorderLineStyle::OUTSET },
+ { XML_TOKEN_INVALID, 0 }
+};
+
+const struct SvXMLEnumMapEntry<sal_uInt16> psXML_NamedBorderWidths[] =
+{
+ { XML_THIN, SVX_XML_BORDER_WIDTH_THIN },
+ { XML_MIDDLE, SVX_XML_BORDER_WIDTH_MIDDLE },
+ { XML_THICK, SVX_XML_BORDER_WIDTH_THICK },
+ { XML_TOKEN_INVALID, 0 }
+};
+// mapping tables to map external xml input to internal box line widths
+
+const sal_uInt16 aBorderWidths[] = {
+ SvxBorderLineWidth::Hairline,
+ SvxBorderLineWidth::VeryThin,
+ SvxBorderLineWidth::Thin
+};
+
+bool sw_frmitems_parseXMLBorder( std::u16string_view rValue,
+ const SvXMLUnitConverter& rUnitConverter,
+ bool& rHasStyle, sal_uInt16& rStyle,
+ bool& rHasWidth, sal_uInt16& rWidth,
+ sal_uInt16& rNamedWidth,
+ bool& rHasColor, Color& rColor )
+{
+ std::u16string_view aToken;
+ SvXMLTokenEnumerator aTokens( rValue );
+
+ rHasStyle = false;
+ rHasWidth = false;
+ rHasColor = false;
+
+ rStyle = USHRT_MAX;
+ rWidth = 0;
+ rNamedWidth = USHRT_MAX;
+
+ sal_Int32 nTemp;
+ while( aTokens.getNextToken( aToken ) && !aToken.empty() )
+ {
+ if( !rHasWidth &&
+ SvXMLUnitConverter::convertEnum( rNamedWidth, aToken,
+ psXML_NamedBorderWidths ) )
+ {
+ rHasWidth = true;
+ }
+ else if( !rHasStyle &&
+ SvXMLUnitConverter::convertEnum( rStyle, aToken,
+ psXML_BorderStyles ) )
+ {
+ rHasStyle = true;
+ }
+ else if (!rHasColor && ::sax::Converter::convertColor(rColor, aToken))
+ {
+ rHasColor = true;
+ }
+ else if( !rHasWidth &&
+ rUnitConverter.convertMeasureToCore(nTemp, aToken, 0, USHRT_MAX))
+ {
+ rWidth = o3tl::narrowing<sal_uInt16>(nTemp);
+ rHasWidth = true;
+ }
+ else
+ {
+ // misformed
+ return false;
+ }
+ }
+
+ return rHasStyle || rHasWidth || rHasColor;
+}
+
+static void sw_frmitems_setXMLBorderStyle( SvxBorderLine& rLine, sal_uInt16 nStyle )
+{
+ SvxBorderLineStyle eStyle = SvxBorderLineStyle::NONE;
+ if ( nStyle != table::BorderLineStyle::NONE )
+ eStyle = SvxBorderLineStyle( nStyle );
+ rLine.SetBorderLineStyle(eStyle);
+}
+
+bool sw_frmitems_setXMLBorder( std::unique_ptr<SvxBorderLine>& rpLine,
+ bool bHasStyle, sal_uInt16 nStyle,
+ bool bHasWidth, sal_uInt16 nWidth,
+ sal_uInt16 nNamedWidth,
+ bool bHasColor, const Color& rColor )
+{
+ // first of all, delete an empty line
+ if( (bHasStyle && table::BorderLineStyle::NONE == nStyle) ||
+ (bHasWidth && USHRT_MAX == nNamedWidth && 0 == nWidth) )
+ {
+ bool bRet = nullptr != rpLine;
+ rpLine.reset();
+ return bRet;
+ }
+
+ // if there is no line and no style and no with, there will never be a line
+ if( !rpLine && !(bHasStyle && bHasWidth) )
+ return false;
+
+ // We now do know that there will be a line
+ if( !rpLine )
+ rpLine.reset(new SvxBorderLine);
+
+ if( ( bHasWidth &&
+ (USHRT_MAX != nNamedWidth || (nWidth != rpLine->GetWidth() ) ) ) ||
+ ( bHasStyle &&
+ ((table::BorderLineStyle::SOLID == nStyle && rpLine->GetDistance()) ||
+ (table::BorderLineStyle::DOUBLE == nStyle && !rpLine->GetDistance())) ) )
+ {
+ bool bDouble = (bHasWidth && table::BorderLineStyle::DOUBLE == nStyle ) ||
+ rpLine->GetDistance();
+
+ // fdo#38542: for double borders, do not override the width
+ // set via style:border-line-width{,-left,-right,-top,-bottom}
+ if (!bDouble || !rpLine->GetWidth())
+ {
+ // The width has to be changed
+ if (bHasWidth && USHRT_MAX != nNamedWidth)
+ {
+ if (bDouble)
+ {
+ rpLine->SetBorderLineStyle( SvxBorderLineStyle::DOUBLE );
+ }
+ rpLine->SetWidth( aBorderWidths[nNamedWidth] );
+ }
+ else
+ {
+ if (!bHasWidth)
+ nWidth = rpLine->GetScaledWidth();
+
+ rpLine->SetWidth( nWidth );
+ }
+ }
+ sw_frmitems_setXMLBorderStyle( *rpLine, nStyle );
+ }
+
+ // set color
+ if( bHasColor )
+ rpLine->SetColor( rColor );
+
+ return true;
+}
+
+void sw_frmitems_setXMLBorder( std::unique_ptr<SvxBorderLine>& rpLine,
+ sal_uInt16 nWidth, sal_uInt16 nOutWidth,
+ sal_uInt16 nInWidth, sal_uInt16 nDistance )
+{
+ if( !rpLine )
+ rpLine.reset(new SvxBorderLine);
+
+ if( nWidth > 0 )
+ rpLine->SetWidth( nWidth );
+ else
+ rpLine->GuessLinesWidths(SvxBorderLineStyle::DOUBLE,
+ nOutWidth, nInWidth, nDistance);
+}
+
+const struct SvXMLEnumMapEntry<SvxGraphicPosition> psXML_BrushRepeat[] =
+{
+ { XML_REPEAT, GPOS_TILED },
+ { XML_BACKGROUND_NO_REPEAT, GPOS_MM },
+ { XML_STRETCH, GPOS_AREA },
+ { XML_TOKEN_INVALID, SvxGraphicPosition(0) }
+};
+
+const struct SvXMLEnumMapEntry<SvxGraphicPosition> psXML_BrushHoriPos[] =
+{
+ { XML_LEFT, GPOS_LM },
+ { XML_RIGHT, GPOS_RM },
+ { XML_TOKEN_INVALID, SvxGraphicPosition(0) }
+};
+
+const struct SvXMLEnumMapEntry<SvxGraphicPosition> psXML_BrushVertPos[] =
+{
+ { XML_TOP, GPOS_MT },
+ { XML_BOTTOM, GPOS_MB },
+ { XML_TOKEN_INVALID, SvxGraphicPosition(0) }
+};
+
+void sw_frmitems_MergeXMLHoriPos( SvxGraphicPosition& ePos,
+ SvxGraphicPosition eHori )
+{
+ OSL_ENSURE( GPOS_LM==eHori || GPOS_MM==eHori || GPOS_RM==eHori,
+ "sw_frmitems_MergeXMLHoriPos: vertical pos must be middle" );
+
+ switch( ePos )
+ {
+ case GPOS_LT:
+ case GPOS_MT:
+ case GPOS_RT:
+ ePos = GPOS_LM==eHori ? GPOS_LT : (GPOS_MM==eHori ? GPOS_MT : GPOS_RT);
+ break;
+
+ case GPOS_LM:
+ case GPOS_MM:
+ case GPOS_RM:
+ ePos = eHori;
+ break;
+
+ case GPOS_LB:
+ case GPOS_MB:
+ case GPOS_RB:
+ ePos = GPOS_LM==eHori ? GPOS_LB : (GPOS_MM==eHori ? GPOS_MB : GPOS_RB);
+ break;
+ default:
+ ;
+ }
+}
+
+void sw_frmitems_MergeXMLVertPos( SvxGraphicPosition& ePos,
+ SvxGraphicPosition eVert )
+{
+ OSL_ENSURE( GPOS_MT==eVert || GPOS_MM==eVert || GPOS_MB==eVert,
+ "sw_frmitems_MergeXMLVertPos: horizontal pos must be middle" );
+
+ switch( ePos )
+ {
+ case GPOS_LT:
+ case GPOS_LM:
+ case GPOS_LB:
+ ePos = GPOS_MT==eVert ? GPOS_LT : (GPOS_MM==eVert ? GPOS_LM : GPOS_LB);
+ break;
+
+ case GPOS_MT:
+ case GPOS_MM:
+ case GPOS_MB:
+ ePos = eVert;
+ break;
+
+ case GPOS_RT:
+ case GPOS_RM:
+ case GPOS_RB:
+ ePos = GPOS_MT==eVert ? GPOS_RT : (GPOS_MM==eVert ? GPOS_RM : GPOS_RB);
+ break;
+ default:
+ ;
+ }
+}
+
+const struct SvXMLEnumMapEntry<sal_uInt16> psXML_BreakType[] =
+{
+ { XML_AUTO, 0 },
+ { XML_COLUMN, 1 },
+ { XML_PAGE, 2 },
+ { XML_EVEN_PAGE, 2 },
+ { XML_ODD_PAGE, 2 },
+ { XML_TOKEN_INVALID, 0}
+};
+
+const struct SvXMLEnumMapEntry<sal_Int16> aXMLTableAlignMap[] =
+{
+ { XML_LEFT, text::HoriOrientation::LEFT },
+ { XML_LEFT, text::HoriOrientation::LEFT_AND_WIDTH },
+ { XML_CENTER, text::HoriOrientation::CENTER },
+ { XML_RIGHT, text::HoriOrientation::RIGHT },
+ { XML_MARGINS, text::HoriOrientation::FULL },
+ { XML_MARGINS, text::HoriOrientation::NONE },
+ { XML_TOKEN_INVALID, 0 }
+};
+
+const struct SvXMLEnumMapEntry<sal_Int16> aXMLTableVAlignMap[] =
+{
+ { XML_TOP, text::VertOrientation::TOP },
+ { XML_MIDDLE, text::VertOrientation::CENTER },
+ { XML_BOTTOM, text::VertOrientation::BOTTOM },
+ { XML_TOKEN_INVALID, 0 }
+};
+
+const struct SvXMLEnumMapEntry<sal_uInt16> aXML_KeepTogetherType[] =
+{
+ { XML_ALWAYS, 0 },
+ { XML_AUTO, 1 },
+ { XML_TOKEN_INVALID, 0}
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlithlp.hxx b/sw/source/filter/xml/xmlithlp.hxx
new file mode 100644
index 0000000000..99d3acd21d
--- /dev/null
+++ b/sw/source/filter/xml/xmlithlp.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SW_SOURCE_FILTER_XML_XMLITHLP_HXX
+#define INCLUDED_SW_SOURCE_FILTER_XML_XMLITHLP_HXX
+
+#include <sal/types.h>
+#include <xmloff/xmlement.hxx>
+#include <editeng/brushitem.hxx>
+
+namespace editeng { class SvxBorderLine; }
+
+template<typename EnumT> struct SvXMLEnumMapEntry;
+class SvXMLUnitConverter;
+class Color;
+
+/** Define various helper variables and functions for xmlimpit.cxx and
+ * xmlexpit.cxx. */
+bool sw_frmitems_parseXMLBorder( std::u16string_view rValue,
+ const SvXMLUnitConverter& rUnitConverter,
+ bool& rHasStyle, sal_uInt16& rStyle,
+ bool& rHasWidth, sal_uInt16& rWidth,
+ sal_uInt16& rNamedWidth,
+ bool& rHasColor, Color& rColor );
+
+bool sw_frmitems_setXMLBorder( std::unique_ptr<editeng::SvxBorderLine>& rpLine,
+ bool bHasStyle, sal_uInt16 nStyle,
+ bool bHasWidth, sal_uInt16 nWidth,
+ sal_uInt16 nNamedWidth,
+ bool bHasColor, const Color& rColor );
+
+void sw_frmitems_setXMLBorder( std::unique_ptr<editeng::SvxBorderLine>& rpLine,
+ sal_uInt16 nWidth, sal_uInt16 nOutWidth,
+ sal_uInt16 nInWidth, sal_uInt16 nDistance );
+
+void sw_frmitems_MergeXMLHoriPos( SvxGraphicPosition& ePos,
+ SvxGraphicPosition eHori );
+
+void sw_frmitems_MergeXMLVertPos( SvxGraphicPosition& ePos,
+ SvxGraphicPosition eVert );
+
+extern const struct SvXMLEnumMapEntry<sal_uInt16> psXML_BorderStyles[];
+extern const struct SvXMLEnumMapEntry<sal_uInt16> psXML_NamedBorderWidths[];
+extern const struct SvXMLEnumMapEntry<SvxGraphicPosition> psXML_BrushRepeat[];
+extern const struct SvXMLEnumMapEntry<SvxGraphicPosition> psXML_BrushHoriPos[];
+extern const struct SvXMLEnumMapEntry<SvxGraphicPosition> psXML_BrushVertPos[];
+extern const struct SvXMLEnumMapEntry<sal_uInt16> psXML_BreakType[];
+extern const struct SvXMLEnumMapEntry<sal_Int16> aXMLTableAlignMap[];
+extern const struct SvXMLEnumMapEntry<sal_Int16> aXMLTableVAlignMap[];
+extern const struct SvXMLEnumMapEntry<sal_uInt16> aXML_KeepTogetherType[];
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlitmap.hxx b/sw/source/filter/xml/xmlitmap.hxx
new file mode 100644
index 0000000000..5c7f731cc1
--- /dev/null
+++ b/sw/source/filter/xml/xmlitmap.hxx
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SW_SOURCE_FILTER_XML_XMLITMAP_HXX
+#define INCLUDED_SW_SOURCE_FILTER_XML_XMLITMAP_HXX
+
+#include <sal/types.h>
+#include <tools/ref.hxx>
+#include <xmloff/xmltoken.hxx>
+#include <memory>
+#include <span>
+
+#define MID_SW_FLAG_MASK 0x0000ffff
+
+// this flags are used in the item mapper for import and export
+#define MID_SW_FLAG_SPECIAL_ITEM_IMPORT 0x80000000
+#define MID_SW_FLAG_NO_ITEM_IMPORT 0x40000000
+#define MID_SW_FLAG_SPECIAL_ITEM_EXPORT 0x20000000
+#define MID_SW_FLAG_NO_ITEM_EXPORT 0x10000000
+#define MID_SW_FLAG_ELEMENT_ITEM_IMPORT 0x08000000
+#define MID_SW_FLAG_ELEMENT_ITEM_EXPORT 0x04000000
+#define MID_SW_FLAG_ELEMENT_ITEM 0x0c000000 // both import and export
+
+struct SvXMLItemMapEntry
+{
+ sal_uInt16 nNameSpace; // declares the Namespace in which this item
+ // exists
+ sal_uInt16 nWhichId; // the WhichId to identify the item
+ // in the pool
+ enum ::xmloff::token::XMLTokenEnum const eLocalName;
+ // the local name for the item inside
+ // the Namespace (as an XMLTokenEnum)
+ sal_uInt32 nMemberId; // the memberid specifies which part
+ // of the item should be imported or
+ // exported with this Namespace
+ // and localName
+ SvXMLItemMapEntry(
+ sal_uInt16 nameSpace,
+ enum ::xmloff::token::XMLTokenEnum localName,
+ sal_uInt16 whichId,
+ sal_uInt32 memberId)
+ : nNameSpace(nameSpace), nWhichId(whichId), eLocalName(localName), nMemberId(memberId) {}
+};
+
+/** this class manages an array of SvXMLItemMapEntry. It is
+ used for optimizing the static array on startup of import
+ or export */
+class SvXMLItemMapEntries final : public SvRefBase
+{
+ std::span<SvXMLItemMapEntry const> mpEntries;
+
+public:
+ explicit SvXMLItemMapEntries(std::span<SvXMLItemMapEntry const> pEntries) : mpEntries(pEntries) {}
+ virtual ~SvXMLItemMapEntries() override;
+
+ SvXMLItemMapEntry const * getByName( sal_Int32 nElement ) const;
+ SvXMLItemMapEntry const & getByIndex( sal_uInt16 nIndex ) const { return mpEntries[nIndex]; }
+
+ sal_uInt16 getCount() const { return mpEntries.size(); }
+};
+
+typedef tools::SvRef<SvXMLItemMapEntries> SvXMLItemMapEntriesRef;
+
+extern const std::span<SvXMLItemMapEntry const> aXMLTableItemMap;
+extern const std::span<SvXMLItemMapEntry const> aXMLTableColItemMap;
+extern const std::span<SvXMLItemMapEntry const> aXMLTableRowItemMap;
+extern const std::span<SvXMLItemMapEntry const> aXMLTableCellItemMap;
+
+#endif // INCLUDED_SW_SOURCE_FILTER_XML_XMLITMAP_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlitmpr.cxx b/sw/source/filter/xml/xmlitmpr.cxx
new file mode 100644
index 0000000000..e7cf7ec90d
--- /dev/null
+++ b/sw/source/filter/xml/xmlitmpr.cxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlitmap.hxx"
+#include <xmloff/xmlimp.hxx>
+
+SvXMLItemMapEntries::~SvXMLItemMapEntries()
+{
+}
+
+SvXMLItemMapEntry const * SvXMLItemMapEntries::getByName( sal_Int32 nElement ) const
+{
+ for (const SvXMLItemMapEntry& rEntry : mpEntries)
+ {
+ if( IsTokenInNamespace(nElement, rEntry.nNameSpace) &&
+ (nElement & TOKEN_MASK) == rEntry.eLocalName )
+ return &rEntry;
+ }
+
+ return nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlmeta.cxx b/sw/source/filter/xml/xmlmeta.cxx
new file mode 100644
index 0000000000..925fea5d9a
--- /dev/null
+++ b/sw/source/filter/xml/xmlmeta.cxx
@@ -0,0 +1,175 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <osl/diagnose.h>
+#include <xmloff/xmlmetai.hxx>
+#include <xmloff/ProgressBarHelper.hxx>
+#include <xmloff/xmltkmap.hxx>
+#include <o3tl/safeint.hxx>
+#include <xmloff/xmluconv.hxx>
+#include <docstat.hxx>
+#include <doc.hxx>
+#include <IDocumentStatistics.hxx>
+#include "xmlimp.hxx"
+#include "xmlexp.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::text;
+using namespace ::xmloff::token;
+
+uno::Reference<document::XDocumentProperties>
+SwXMLImport::GetDocumentProperties() const
+{
+ if (m_bOrganizerMode || IsStylesOnlyMode() ||
+ IsBlockMode() || IsInsertMode())
+ {
+ return nullptr;
+ }
+ uno::Reference<document::XDocumentPropertiesSupplier> const xDPS(
+ GetModel(), UNO_QUERY_THROW);
+ return xDPS->getDocumentProperties();
+}
+
+SvXMLImportContext *SwXMLImport::CreateMetaContext(
+ const sal_Int32 /*nElement*/ )
+{
+ SvXMLImportContext *pContext = nullptr;
+
+ if (getImportFlags() & SvXMLImportFlags::META)
+ {
+ uno::Reference<document::XDocumentProperties> const xDocProps(
+ GetDocumentProperties());
+ pContext = new SvXMLMetaDocumentContext(*this, xDocProps);
+ }
+
+ return pContext;
+}
+
+namespace {
+
+enum SvXMLTokenMapAttrs
+{
+ XML_TOK_META_STAT_TABLE = 1,
+ XML_TOK_META_STAT_IMAGE = 2,
+ XML_TOK_META_STAT_OLE = 4,
+ XML_TOK_META_STAT_PAGE = 8,
+ XML_TOK_META_STAT_PARA = 16,
+ XML_TOK_META_STAT_WORD = 32,
+ XML_TOK_META_STAT_CHAR = 64,
+ XML_TOK_META_STAT_NON_WHITE_SPACE_CHAR = 128,
+ XML_TOK_META_STAT_END=XML_TOK_UNKNOWN
+};
+
+struct statistic {
+ SvXMLTokenMapAttrs token;
+ const char* name;
+ sal_uInt16 SwDocStat::* target16;
+ sal_uLong SwDocStat::* target32; /* or 64, on LP64 platforms */
+};
+
+}
+
+const struct statistic s_stats [] = {
+ { XML_TOK_META_STAT_TABLE, "TableCount", &SwDocStat::nTable, nullptr },
+ { XML_TOK_META_STAT_IMAGE, "ImageCount", &SwDocStat::nGrf, nullptr },
+ { XML_TOK_META_STAT_OLE, "ObjectCount", &SwDocStat::nOLE, nullptr },
+ { XML_TOK_META_STAT_PAGE, "PageCount", nullptr, &SwDocStat::nPage },
+ { XML_TOK_META_STAT_PARA, "ParagraphCount", nullptr, &SwDocStat::nPara },
+ { XML_TOK_META_STAT_WORD, "WordCount", nullptr, &SwDocStat::nWord },
+ { XML_TOK_META_STAT_CHAR, "CharacterCount", nullptr, &SwDocStat::nChar },
+ { XML_TOK_META_STAT_NON_WHITE_SPACE_CHAR, "NonWhitespaceCharacterCount", nullptr, &SwDocStat::nCharExcludingSpaces },
+ { XML_TOK_META_STAT_END, nullptr, nullptr, nullptr }
+};
+
+void SwXMLImport::SetStatistics(
+ const Sequence< beans::NamedValue > & i_rStats)
+{
+ if( IsStylesOnlyMode() || IsInsertMode() )
+ return;
+
+ SvXMLImport::SetStatistics(i_rStats);
+
+ SwDoc *pDoc = getDoc();
+ SwDocStat aDocStat( pDoc->getIDocumentStatistics().GetDocStat() );
+
+ sal_uInt32 nTokens = 0;
+
+ for (const auto& rStat : i_rStats) {
+ for (struct statistic const* pStat = s_stats; pStat->name != nullptr;
+ ++pStat) {
+ if (rStat.Name.equalsAscii(pStat->name)) {
+ sal_Int32 val = 0;
+ if (rStat.Value >>= val) {
+ if (pStat->target16 != nullptr) {
+ aDocStat.*(pStat->target16)
+ = o3tl::narrowing<sal_uInt16> (val);
+ } else {
+ aDocStat.*(pStat->target32)
+ = static_cast<sal_uInt32> (val);
+ }
+ nTokens |= pStat->token;
+ } else {
+ OSL_FAIL("SwXMLImport::SetStatistics: invalid entry");
+ }
+ }
+ }
+ }
+
+ if( nTokens )
+ pDoc->getIDocumentStatistics().SetDocStat( aDocStat );
+
+ // set progress bar reference to #paragraphs. If not available,
+ // use #pages*10, or guesstimate 250 paragraphs. Additionally
+ // guesstimate PROGRESS_BAR_STEPS each for meta+settings, styles,
+ // and autostyles.
+ bool bSetFallback = true;
+ sal_Int32 nProgressReference = sal_Int32(); // silence C4701
+ const sal_Int32 nProgressReferenceWriggleRoom = 3 * PROGRESS_BAR_STEP;
+ if (nTokens & XML_TOK_META_STAT_PARA)
+ {
+ nProgressReference = static_cast<sal_Int32>(aDocStat.nPara);
+ bSetFallback = false;
+ }
+ else if (nTokens & XML_TOK_META_STAT_PAGE)
+ bSetFallback = o3tl::checked_multiply<sal_Int32>(aDocStat.nPage, 10, nProgressReference);
+ if (!bSetFallback)
+ bSetFallback = o3tl::checked_add(nProgressReference, nProgressReferenceWriggleRoom, nProgressReference);
+ if (bSetFallback)
+ nProgressReference = 250 + nProgressReferenceWriggleRoom;
+ ProgressBarHelper* pProgress = GetProgressBarHelper();
+ pProgress->SetReference(nProgressReference);
+ pProgress->SetValue( 0 );
+}
+
+void SwXMLExport::ExportMeta_()
+{
+ SvXMLExport::ExportMeta_();
+
+ if( !m_bBlock && IsShowProgress() )
+ {
+ ProgressBarHelper *pProgress = GetProgressBarHelper();
+ pProgress->SetValue( pProgress->GetValue() + 2 );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlscript.cxx b/sw/source/filter/xml/xmlscript.cxx
new file mode 100644
index 0000000000..07a94e8a5a
--- /dev/null
+++ b/sw/source/filter/xml/xmlscript.cxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <xmloff/xmlscripti.hxx>
+#include "xmlimp.hxx"
+
+using namespace ::com::sun::star;
+
+SvXMLImportContext* SwXMLImport::CreateScriptContext()
+{
+ SvXMLImportContext* pContext = nullptr;
+
+ if (!(IsStylesOnlyMode() || IsInsertMode()))
+ {
+ pContext = new XMLScriptContext(*this, GetModel());
+ }
+
+ return pContext;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmltble.cxx b/sw/source/filter/xml/xmltble.cxx
new file mode 100644
index 0000000000..1341bbbe37
--- /dev/null
+++ b/sw/source/filter/xml/xmltble.cxx
@@ -0,0 +1,1266 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <com/sun/star/text/XTextTable.hpp>
+#include <com/sun/star/text/XTextSection.hpp>
+
+#include <hintids.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/xmluconv.hxx>
+#include <xmloff/numehelp.hxx>
+#include <editeng/brushitem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/prntitem.hxx>
+#include <editeng/xmlcnitm.hxx>
+#include <fmtrowsplt.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <swtable.hxx>
+#include <doc.hxx>
+#include <frmfmt.hxx>
+#include <wrtswtbl.hxx>
+#include <fmtfsize.hxx>
+#include <fmtornt.hxx>
+#include <cellatr.hxx>
+#include <ddefld.hxx>
+#include <swddetbl.hxx>
+#include <xmloff/namespacemap.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <unotbl.hxx>
+#include "xmltexte.hxx"
+#include "xmlexp.hxx"
+#include <o3tl/any.hxx>
+#include <o3tl/sorted_vector.hxx>
+#include <textboxhelper.hxx>
+#include <SwStyleNameMapper.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::xmloff::token;
+using table::XCell;
+using std::vector;
+using std::advance;
+
+
+class SwXMLTableColumn_Impl : public SwWriteTableCol
+{
+ OUString m_sStyleName;
+ sal_uInt32 m_nRelWidth;
+
+public:
+
+ explicit SwXMLTableColumn_Impl(sal_uInt32 nPosition)
+ : SwWriteTableCol(nPosition)
+ , m_nRelWidth(0)
+ {};
+
+ void SetStyleName( const OUString& rName ) { m_sStyleName = rName; }
+ const OUString& GetStyleName() const { return m_sStyleName; }
+
+ void SetRelWidth( sal_uInt32 nSet ) { m_nRelWidth = nSet; }
+ sal_uInt32 GetRelWidth() const { return m_nRelWidth; }
+};
+
+namespace {
+
+struct SwXMLTableColumnCmpWidth_Impl
+{
+ bool operator()( SwXMLTableColumn_Impl* const& lhs, SwXMLTableColumn_Impl* const& rhs ) const
+ {
+ sal_Int32 n = static_cast<sal_Int32>(lhs->GetWidthOpt()) - static_cast<sal_Int32>(rhs->GetWidthOpt());
+ if( !n )
+ n = static_cast<sal_Int32>(lhs->GetRelWidth()) - static_cast<sal_Int32>(rhs->GetRelWidth());
+ return n < 0;
+ }
+};
+
+class SwXMLTableColumns_Impl : public o3tl::sorted_vector<std::unique_ptr<SwXMLTableColumn_Impl>, o3tl::less_uniqueptr_to<SwXMLTableColumn_Impl> > {
+};
+
+}
+
+class SwXMLTableColumnsSortByWidth_Impl : public o3tl::sorted_vector<SwXMLTableColumn_Impl*, SwXMLTableColumnCmpWidth_Impl> {};
+
+class SwXMLTableLines_Impl
+{
+ SwXMLTableColumns_Impl m_aCols;
+ const SwTableLines *m_pLines;
+ sal_uInt32 m_nWidth;
+
+public:
+
+ explicit SwXMLTableLines_Impl( const SwTableLines& rLines );
+
+ sal_uInt32 GetWidth() const { return m_nWidth; }
+ const SwTableLines *GetLines() const { return m_pLines; }
+
+ const SwXMLTableColumns_Impl& GetColumns() const { return m_aCols; }
+};
+
+SwXMLTableLines_Impl::SwXMLTableLines_Impl( const SwTableLines& rLines ) :
+ m_pLines( &rLines ),
+ m_nWidth( 0 )
+{
+#if OSL_DEBUG_LEVEL > 0
+ sal_uInt32 nEndCPos = 0U;
+#endif
+ const size_t nLines = rLines.size();
+ for( size_t nLine=0U; nLine<nLines; ++nLine )
+ {
+ const SwTableLine *pLine = rLines[nLine];
+ const SwTableBoxes& rBoxes = pLine->GetTabBoxes();
+ const size_t nBoxes = rBoxes.size();
+
+ sal_uInt32 nCPos = 0U;
+ for( size_t nBox=0U; nBox<nBoxes; ++nBox )
+ {
+ const SwTableBox *pBox = rBoxes[nBox];
+
+ if( nBox < nBoxes-1U || m_nWidth==0 )
+ {
+ nCPos = nCPos + SwWriteTable::GetBoxWidth( pBox );
+ std::unique_ptr<SwXMLTableColumn_Impl> pCol(
+ new SwXMLTableColumn_Impl( nCPos ));
+
+ m_aCols.insert( std::move(pCol) );
+
+ if( nBox==nBoxes-1U )
+ {
+ OSL_ENSURE( nLine==0U && m_nWidth==0,
+ "parent width will be lost" );
+ m_nWidth = nCPos;
+ }
+ }
+ else
+ {
+#if OSL_DEBUG_LEVEL > 0
+ sal_uInt32 nCheckPos =
+ nCPos + SwWriteTable::GetBoxWidth( pBox );
+ if( !nEndCPos )
+ {
+ nEndCPos = nCheckPos;
+ }
+#endif
+ nCPos = m_nWidth;
+#if OSL_DEBUG_LEVEL > 0
+ SwXMLTableColumn_Impl aCol( m_nWidth );
+ OSL_ENSURE( m_aCols.find(&aCol) != m_aCols.end(), "couldn't find last column" );
+ OSL_ENSURE( SwXMLTableColumn_Impl(nCheckPos) ==
+ SwXMLTableColumn_Impl(nCPos),
+ "rows have different total widths" );
+#endif
+ }
+ }
+ }
+}
+
+typedef vector< SwFrameFormat* > SwXMLFrameFormats_Impl;
+
+class SwXMLTableFrameFormatsSort_Impl
+{
+private:
+ SwXMLFrameFormats_Impl m_aFormatList;
+ SwXMLTextParagraphExport::FormatMap & m_rFormatMap;
+
+public:
+ SwXMLTableFrameFormatsSort_Impl(SwXMLTextParagraphExport::FormatMap & rFormatMap)
+ : m_rFormatMap(rFormatMap)
+ {}
+ ::std::optional<OUString> AddRow(SwFrameFormat& rFrameFormat, std::u16string_view rNamePrefix, sal_uInt32 nLine );
+ ::std::optional<OUString> AddCell(SwFrameFormat& rFrameFormat, std::u16string_view rNamePrefix,
+ sal_uInt32 nCol, sal_uInt32 nRow, bool bTop );
+};
+
+::std::optional<OUString> SwXMLTableFrameFormatsSort_Impl::AddRow(SwFrameFormat& rFrameFormat,
+ std::u16string_view rNamePrefix,
+ sal_uInt32 nLine )
+{
+ const SfxItemSet& rItemSet = rFrameFormat.GetAttrSet();
+
+ const SwFormatFrameSize *pFrameSize = rItemSet.GetItemIfSet( RES_FRM_SIZE, false );
+ const SwFormatRowSplit* pRowSplit = rItemSet.GetItemIfSet( RES_ROW_SPLIT, false );
+ const SvxBrushItem *pBrush = rItemSet.GetItemIfSet( RES_BACKGROUND, false );
+ const SvxPrintItem *pHasTextChangesOnly = rItemSet.GetItemIfSet( RES_PRINT, false);
+
+ // empty styles have not to be exported
+ if( !pFrameSize && !pBrush && !pRowSplit && !pHasTextChangesOnly )
+ {
+ m_rFormatMap.try_emplace(&rFrameFormat); // empty just to enable assert
+ return {};
+ }
+
+ // order is: -/brush, size/-, size/brush
+ SwXMLFrameFormats_Impl::iterator i;
+ for( i = m_aFormatList.begin(); i < m_aFormatList.end(); ++i )
+ {
+ const SwFormatFrameSize *pTestFrameSize = nullptr;
+ const SwFormatRowSplit* pTestRowSplit = nullptr;
+ const SvxBrushItem *pTestBrush = nullptr;
+ const SvxPrintItem *pTestHasTextChangesOnly = nullptr;
+ const SwFrameFormat *pTestFormat = *i;
+ const SfxItemSet& rTestSet = pTestFormat->GetAttrSet();
+ if( const SwFormatFrameSize* pItem = rTestSet.GetItemIfSet( RES_FRM_SIZE, false ) )
+ {
+ if( !pFrameSize )
+ break;
+
+ pTestFrameSize = pItem;
+ }
+ else
+ {
+ if( pFrameSize )
+ continue;
+ }
+
+ if( const SvxBrushItem* pItem = rTestSet.GetItemIfSet( RES_BACKGROUND, false) )
+ {
+ if( !pBrush )
+ break;
+
+ pTestBrush = pItem;
+ }
+ else
+ {
+ if( pBrush )
+ continue;
+ }
+
+ if( const SwFormatRowSplit* pItem = rTestSet.GetItemIfSet( RES_ROW_SPLIT, false ) )
+ {
+ if( !pRowSplit )
+ break;
+
+ pTestRowSplit = pItem;
+ }
+ else
+ {
+ if( pRowSplit )
+ continue;
+ }
+
+ if( const SvxPrintItem* pItem = rTestSet.GetItemIfSet( RES_PRINT, false ) )
+ {
+ if( !pHasTextChangesOnly )
+ break;
+
+ pTestHasTextChangesOnly = pItem;
+ }
+ else
+ {
+ if( pHasTextChangesOnly )
+ continue;
+ }
+
+ if( pFrameSize &&
+ ( pFrameSize->GetHeightSizeType() != pTestFrameSize->GetHeightSizeType() ||
+ pFrameSize->GetHeight() != pTestFrameSize->GetHeight() ) )
+ continue;
+
+ if( pBrush && (*pBrush != *pTestBrush) )
+ continue;
+
+ if( pRowSplit && (!pRowSplit->GetValue() != !pTestRowSplit->GetValue()) )
+ continue;
+
+ if( pHasTextChangesOnly && (!pHasTextChangesOnly->GetValue() != !pTestHasTextChangesOnly->GetValue()) )
+ continue;
+
+ // found!
+ auto const oName(m_rFormatMap.find(pTestFormat)->second);
+ assert(oName);
+ m_rFormatMap.try_emplace(&rFrameFormat, oName);
+ return {};
+ }
+
+ {
+ OUString const name(OUString::Concat(rNamePrefix) + "." + OUString::number(nLine+1));
+ m_rFormatMap.try_emplace(&rFrameFormat, name);
+ if ( i != m_aFormatList.end() ) ++i;
+ m_aFormatList.insert( i, &rFrameFormat );
+ return ::std::optional<OUString>(name);
+ }
+}
+
+static OUString lcl_xmltble_appendBoxPrefix(std::u16string_view rNamePrefix,
+ sal_uInt32 nCol, sal_uInt32 nRow, bool bTop )
+{
+ if( bTop )
+ {
+ OUString sTmp;
+ sw_GetTableBoxColStr( o3tl::narrowing<sal_uInt16>(nCol), sTmp );
+ return OUString::Concat(rNamePrefix) + "." + sTmp + OUString::number(nRow + 1);
+ }
+ return OUString::Concat(rNamePrefix)
+ + "." + OUString::number(nCol + 1)
+ + "." + OUString::number(nRow + 1);
+}
+
+::std::optional<OUString> SwXMLTableFrameFormatsSort_Impl::AddCell(SwFrameFormat& rFrameFormat,
+ std::u16string_view rNamePrefix,
+ sal_uInt32 nCol, sal_uInt32 nRow, bool bTop )
+{
+ const SfxItemSet& rItemSet = rFrameFormat.GetAttrSet();
+ const SwFormatVertOrient *pVertOrient = rItemSet.GetItemIfSet( RES_VERT_ORIENT, false );
+ const SvxBrushItem *pBrush = rItemSet.GetItemIfSet( RES_BACKGROUND, false );
+ const SvxBoxItem *pBox = rItemSet.GetItemIfSet( RES_BOX, false );
+ const SwTableBoxNumFormat *pNumFormat = rItemSet.GetItemIfSet( RES_BOXATR_FORMAT,
+ false );
+ const SvxFrameDirectionItem *pFrameDir = rItemSet.GetItemIfSet( RES_FRAMEDIR,
+ false );
+ const SvXMLAttrContainerItem *pAttCnt = rItemSet.GetItemIfSet( RES_UNKNOWNATR_CONTAINER,
+ false );
+ const SvxPrintItem *pHasTextChangesOnly = rItemSet.GetItemIfSet( RES_PRINT, false);
+
+ // empty styles have not to be exported
+ if( !pVertOrient && !pBrush && !pBox && !pNumFormat && !pFrameDir && !pAttCnt &&
+ !pHasTextChangesOnly )
+ {
+ m_rFormatMap.try_emplace(&rFrameFormat); // empty just to enable assert
+ return {};
+ }
+
+ // order is: -/-/-/num,
+ // -/-/box/-, -/-/box/num,
+ // -/brush/-/-, -/brush/-/num, -/brush/box/-, -/brush/box/num,
+ // vert/-/-/-, vert/-/-/num, vert/-/box/-, ver/-/box/num,
+ // vert/brush/-/-, vert/brush/-/num, vert/brush/box/-,
+ // vert/brush/box/num
+ SwXMLFrameFormats_Impl::iterator i;
+ for( i = m_aFormatList.begin(); i < m_aFormatList.end(); ++i )
+ {
+ const SwFormatVertOrient *pTestVertOrient = nullptr;
+ const SvxBrushItem *pTestBrush = nullptr;
+ const SvxBoxItem *pTestBox = nullptr;
+ const SwTableBoxNumFormat *pTestNumFormat = nullptr;
+ const SvxFrameDirectionItem *pTestFrameDir = nullptr;
+ const SvXMLAttrContainerItem *pTestAttCnt = nullptr;
+ const SvxPrintItem *pTestHasTextChangesOnly = rItemSet.GetItemIfSet( RES_PRINT, false);
+ const SwFrameFormat* pTestFormat = *i;
+ const SfxItemSet& rTestSet = pTestFormat->GetAttrSet();
+ if( const SwFormatVertOrient* pItem = rTestSet.GetItemIfSet( RES_VERT_ORIENT, false ) )
+ {
+ if( !pVertOrient )
+ break;
+
+ pTestVertOrient = pItem;
+ }
+ else
+ {
+ if( pVertOrient )
+ continue;
+ }
+
+ if( const SvxBrushItem* pItem = rTestSet.GetItemIfSet( RES_BACKGROUND, false ) )
+ {
+ if( !pBrush )
+ break;
+
+ pTestBrush = pItem;
+ }
+ else
+ {
+ if( pBrush )
+ continue;
+ }
+
+ if( const SvxBoxItem* pItem = rTestSet.GetItemIfSet( RES_BOX, false ) )
+ {
+ if( !pBox )
+ break;
+
+ pTestBox = pItem;
+ }
+ else
+ {
+ if( pBox )
+ continue;
+ }
+
+ if ( const SwTableBoxNumFormat* pItem = rTestSet.GetItemIfSet( RES_BOXATR_FORMAT,
+ false ) )
+ {
+ if( !pNumFormat )
+ break;
+
+ pTestNumFormat = pItem;
+ }
+ else
+ {
+ if( pNumFormat )
+ continue;
+
+ }
+
+ if ( const SvxFrameDirectionItem* pItem = rTestSet.GetItemIfSet( RES_FRAMEDIR,
+ false ) )
+ {
+ if( !pFrameDir )
+ break;
+
+ pTestFrameDir = pItem;
+ }
+ else
+ {
+ if( pFrameDir )
+ continue;
+
+ }
+
+ if ( const SvXMLAttrContainerItem* pItem = rTestSet.GetItemIfSet( RES_UNKNOWNATR_CONTAINER,
+ false ) )
+ {
+ if( !pAttCnt )
+ break;
+
+ pTestAttCnt = pItem;
+ }
+ else
+ {
+ if ( pAttCnt )
+ continue;
+
+ }
+
+ if( const SvxPrintItem* pItem = rTestSet.GetItemIfSet( RES_PRINT, false ) )
+ {
+ if( !pHasTextChangesOnly )
+ break;
+
+ pTestHasTextChangesOnly = pItem;
+ }
+ else
+ {
+ if( pHasTextChangesOnly )
+ continue;
+ }
+
+ if( pVertOrient &&
+ pVertOrient->GetVertOrient() != pTestVertOrient->GetVertOrient() )
+ continue;
+
+ if( pBrush && ( *pBrush != *pTestBrush ) )
+ continue;
+
+ if( pBox && ( *pBox != *pTestBox ) )
+ continue;
+
+ if( pNumFormat && pNumFormat->GetValue() != pTestNumFormat->GetValue() )
+ continue;
+
+ if( pFrameDir && pFrameDir->GetValue() != pTestFrameDir->GetValue() )
+ continue;
+
+ if( pAttCnt && ( *pAttCnt != *pTestAttCnt ) )
+ continue;
+
+ if( pHasTextChangesOnly && (!pHasTextChangesOnly->GetValue() != !pTestHasTextChangesOnly->GetValue()) )
+ continue;
+
+ // found!
+ auto const oName(m_rFormatMap.find(pTestFormat)->second);
+ assert(oName);
+ m_rFormatMap.try_emplace(&rFrameFormat, oName);
+ return {};
+ }
+
+ {
+ OUString const name(lcl_xmltble_appendBoxPrefix(rNamePrefix, nCol, nRow, bTop));
+ m_rFormatMap.try_emplace(&rFrameFormat, name);
+ if ( i != m_aFormatList.end() ) ++i;
+ m_aFormatList.insert( i, &rFrameFormat );
+ return ::std::optional<OUString>(name);
+ }
+}
+
+class SwXMLTableInfo_Impl
+{
+ const SwTable *m_pTable;
+ Reference<XTextSection> m_xBaseSection;
+ bool m_bBaseSectionValid;
+ sal_uInt32 m_nPrefix;
+ SwXMLTextParagraphExport::FormatMap const& m_rLineFormats;
+ SwXMLTextParagraphExport::FormatMap const& m_rBoxFormats;
+
+public:
+
+ inline SwXMLTableInfo_Impl( const SwTable *pTable, sal_uInt16 nPrefix,
+ SwXMLTextParagraphExport::FormatMap const& rLineFormats,
+ SwXMLTextParagraphExport::FormatMap const& rBoxFormats)
+ : m_pTable(pTable)
+ , m_bBaseSectionValid(false)
+ , m_nPrefix(nPrefix)
+ , m_rLineFormats(rLineFormats)
+ , m_rBoxFormats(rBoxFormats)
+ {
+ }
+
+ const SwTable *GetTable() const { return m_pTable; }
+ const SwFrameFormat *GetTableFormat() const { return m_pTable->GetFrameFormat(); }
+
+ bool IsBaseSectionValid() const { return m_bBaseSectionValid; }
+ const Reference<XTextSection>& GetBaseSection() const { return m_xBaseSection; }
+ inline void SetBaseSection( const Reference < XTextSection >& rBase );
+ /// The namespace (table or loext) that should be used for the elements.
+ sal_uInt16 GetPrefix() const { return m_nPrefix; }
+ SwXMLTextParagraphExport::FormatMap const& GetLineFormats() const { return m_rLineFormats; }
+ SwXMLTextParagraphExport::FormatMap const& GetBoxFormats() const { return m_rBoxFormats; }
+};
+
+inline void SwXMLTableInfo_Impl::SetBaseSection(
+ const Reference < XTextSection >& rBaseSection )
+{
+ m_xBaseSection = rBaseSection;
+ m_bBaseSectionValid = true;
+}
+
+void SwXMLExport::ExportTableColumnStyle( const SwXMLTableColumn_Impl& rCol )
+{
+ // <style:style ...>
+ CheckAttrList();
+
+ // style:name="..."
+ bool bEncoded = false;
+ AddAttribute( XML_NAMESPACE_STYLE, XML_NAME,
+ EncodeStyleName( rCol.GetStyleName(), &bEncoded ) );
+ if( bEncoded )
+ AddAttribute( XML_NAMESPACE_STYLE, XML_DISPLAY_NAME, rCol.GetStyleName() );
+
+ // style:family="table-column"
+ AddAttribute( XML_NAMESPACE_STYLE, XML_FAMILY, XML_TABLE_COLUMN );
+
+ {
+ SvXMLElementExport aElem( *this, XML_NAMESPACE_STYLE, XML_STYLE, true,
+ true );
+ if( rCol.GetWidthOpt() )
+ {
+ OUStringBuffer sValue;
+ GetTwipUnitConverter().convertMeasureToXML( sValue,
+ rCol.GetWidthOpt() );
+ AddAttribute( XML_NAMESPACE_STYLE, XML_COLUMN_WIDTH,
+ sValue.makeStringAndClear() );
+ }
+ if( rCol.GetRelWidth() )
+ {
+ OUString sValue = OUString::number(static_cast<sal_Int32>(rCol.GetRelWidth()) ) + "*";
+ AddAttribute( XML_NAMESPACE_STYLE, XML_REL_COLUMN_WIDTH,
+ sValue );
+ }
+
+ {
+ SvXMLElementExport aElemExport( *this, XML_NAMESPACE_STYLE,
+ XML_TABLE_COLUMN_PROPERTIES,
+ true, true );
+ }
+ }
+}
+
+void SwXMLExport::ExportTableLinesAutoStyles( const SwTableLines& rLines,
+ sal_uInt32 nAbsWidth, sal_uInt32 nBaseWidth,
+ std::u16string_view rNamePrefix,
+ SwXMLTableColumnsSortByWidth_Impl& rExpCols,
+ SwXMLTableFrameFormatsSort_Impl& rExpRows,
+ SwXMLTableFrameFormatsSort_Impl& rExpCells,
+ SwXMLTableInfo_Impl& rTableInfo,
+ bool bTop )
+{
+ // pass 1: calculate columns
+ SwXMLTableLines_Impl *pLines = new SwXMLTableLines_Impl( rLines );
+ if( !m_pTableLines )
+ m_pTableLines.reset(new SwXMLTableLinesCache_Impl);
+
+ m_pTableLines->push_back( pLines );
+
+ // pass 2: export column styles
+ {
+ const SwXMLTableColumns_Impl& rCols = pLines->GetColumns();
+ sal_uInt32 nCPos = 0U;
+ const size_t nColumns = rCols.size();
+ for( size_t nColumn=0U; nColumn<nColumns; ++nColumn )
+ {
+ SwXMLTableColumn_Impl *pColumn = rCols[nColumn].get();
+
+ sal_uInt32 nOldCPos = nCPos;
+ nCPos = pColumn->GetPos();
+
+ sal_uInt32 nWidth = nCPos - nOldCPos;
+
+ // If a base width is given, the table has either an automatic
+ // or margin alignment, or a percentage width. In either case,
+ // relative widths should be exported.
+ if( nBaseWidth )
+ {
+ pColumn->SetRelWidth( nWidth );
+ }
+
+ // If an absolute width is given, the table either has a fixed
+ // width, or the current width is known from the layout. In the
+ // later case, a base width is set in addition and must be used
+ // to "absolutize" the relative column width.
+ if( nAbsWidth )
+ {
+ sal_uInt32 nColAbsWidth = nWidth;
+ if( nBaseWidth )
+ {
+ nColAbsWidth *= nAbsWidth;
+ nColAbsWidth += (nBaseWidth/2UL);
+ nColAbsWidth /= nBaseWidth;
+ }
+ pColumn->SetWidthOpt( nColAbsWidth, false );
+ }
+
+ SwXMLTableColumnsSortByWidth_Impl::const_iterator it = rExpCols.find( pColumn );
+ if( it != rExpCols.end() )
+ {
+ pColumn->SetStyleName( (*it)->GetStyleName() );
+ }
+ else
+ {
+ if( bTop )
+ {
+ OUString sTmp;
+ sw_GetTableBoxColStr( nColumn, sTmp );
+ pColumn->SetStyleName( OUString::Concat(rNamePrefix) + "." + sTmp );
+ }
+ else
+ {
+ pColumn->SetStyleName(
+ OUString::Concat(rNamePrefix) + "." + OUString::number(nColumn + 1U) );
+ }
+ ExportTableColumnStyle( *pColumn );
+ rExpCols.insert( pColumn );
+ }
+ }
+ }
+
+ // pass 3: export line/rows
+ const size_t nLines = rLines.size();
+ for( size_t nLine=0U; nLine<nLines; ++nLine )
+ {
+ SwTableLine *pLine = rLines[nLine];
+
+ SwFrameFormat *pFrameFormat = pLine->GetFrameFormat();
+ if (auto oNew = rExpRows.AddRow(*pFrameFormat, rNamePrefix, nLine))
+ {
+ ExportFormat(*pFrameFormat, XML_TABLE_ROW, std::move(oNew));
+ }
+
+ const SwTableBoxes& rBoxes = pLine->GetTabBoxes();
+ const size_t nBoxes = rBoxes.size();
+
+ sal_uInt32 nCPos = 0U;
+ size_t nCol = 0U;
+ for( size_t nBox=0U; nBox<nBoxes; nBox++ )
+ {
+ SwTableBox *pBox = rBoxes[nBox];
+
+ if( nBox < nBoxes-1U )
+ nCPos = nCPos + SwWriteTable::GetBoxWidth( pBox );
+ else
+ nCPos = pLines->GetWidth();
+
+ // and their index
+ const size_t nOldCol = nCol;
+ SwXMLTableColumn_Impl aCol( nCPos );
+ SwXMLTableColumns_Impl::const_iterator it = pLines->GetColumns().find( &aCol );
+ OSL_ENSURE( it != pLines->GetColumns().end(), "couldn't find column" );
+ nCol = it - pLines->GetColumns().begin();
+
+ const SwStartNode *pBoxSttNd = pBox->GetSttNd();
+ if( pBoxSttNd )
+ {
+ SwFrameFormat *pFrameFormat2 = pBox->GetFrameFormat();
+ if (auto oNew = rExpCells.AddCell(*pFrameFormat2, rNamePrefix, nOldCol, nLine,
+ bTop) )
+ {
+ ExportFormat(*pFrameFormat2, XML_TABLE_CELL, std::move(oNew));
+ }
+
+ rtl::Reference < SwXCell > xCell = SwXCell::CreateXCell(
+ const_cast<SwFrameFormat *>(rTableInfo.GetTableFormat()),
+ pBox,
+ const_cast<SwTable *>(rTableInfo.GetTable()) );
+ if (xCell.is())
+ {
+ if( !rTableInfo.IsBaseSectionValid() )
+ {
+ Any aAny = xCell->getPropertyValue("TextSection");
+ Reference < XTextSection > xTextSection;
+ aAny >>= xTextSection;
+ rTableInfo.SetBaseSection( xTextSection );
+ }
+
+ const bool bExportContent = bool(getExportFlags() & SvXMLExportFlags::CONTENT );
+ if ( !bExportContent )
+ {
+ // AUTOSTYLES - not needed anymore if we are currently exporting content.xml
+ GetTextParagraphExport()->collectTextAutoStyles(
+ xCell, rTableInfo.GetBaseSection(), IsShowProgress() );
+ }
+ }
+ else {
+ OSL_FAIL("here should be a XCell");
+ }
+ }
+ else
+ {
+ ExportTableLinesAutoStyles( pBox->GetTabLines(),
+ nAbsWidth, nBaseWidth,
+ lcl_xmltble_appendBoxPrefix( rNamePrefix,
+ nOldCol, nLine, bTop ),
+ rExpCols, rExpRows, rExpCells,
+ rTableInfo );
+ }
+
+ nCol++;
+ }
+ }
+}
+
+void SwXMLExport::ExportTableAutoStyles(const SwTableNode& rTableNd)
+{
+ auto & rFormats(static_cast<SwXMLTextParagraphExport *>(GetTextParagraphExport().get())->GetTableFormats());
+ auto const it(rFormats.find(&rTableNd));
+ assert(it != rFormats.end());
+ SwXMLTextParagraphExport::FormatMap & rRowFormats(it->second.first);
+ SwXMLTextParagraphExport::FormatMap & rBoxFormats(it->second.second);
+ const SwTable& rTable = rTableNd.GetTable();
+ const SwFrameFormat *pTableFormat = rTable.GetFrameFormat();
+
+ if( !pTableFormat )
+ return;
+
+ sal_Int16 eTabHoriOri = pTableFormat->GetHoriOrient().GetHoriOrient();
+ const SwFormatFrameSize& rFrameSize = pTableFormat->GetFrameSize();
+
+ sal_uInt32 nAbsWidth = rFrameSize.GetSize().Width();
+ sal_uInt32 nBaseWidth = 0;
+ sal_Int8 nPercentWidth = rFrameSize.GetWidthPercent();
+
+ bool bFixAbsWidth = nPercentWidth != 0 || /*text::*/HoriOrientation::NONE == eTabHoriOri
+ || /*text::*/HoriOrientation::FULL == eTabHoriOri;
+ if( bFixAbsWidth )
+ {
+ nBaseWidth = nAbsWidth;
+ nAbsWidth = pTableFormat->FindLayoutRect(true).Width();
+ if( !nAbsWidth )
+ {
+ // TODO?
+ }
+ }
+ ExportTableFormat( *pTableFormat, nAbsWidth );
+
+ SwXMLTableColumnsSortByWidth_Impl aExpCols;
+ SwXMLTableFrameFormatsSort_Impl aExpRows(rRowFormats);
+ SwXMLTableFrameFormatsSort_Impl aExpCells(rBoxFormats);
+ SwXMLTableInfo_Impl aTableInfo(&rTable, XML_NAMESPACE_TABLE, rRowFormats, rBoxFormats);
+ ExportTableLinesAutoStyles( rTable.GetTabLines(), nAbsWidth, nBaseWidth,
+ pTableFormat->GetName(), aExpCols, aExpRows, aExpCells,
+ aTableInfo, true);
+
+}
+
+void SwXMLExport::ExportTableBox( const SwTableBox& rBox,
+ sal_uInt32 nColSpan,
+ sal_uInt32 nRowSpan,
+ SwXMLTableInfo_Impl& rTableInfo )
+{
+ const SwStartNode *pBoxSttNd = rBox.GetSttNd();
+ if( pBoxSttNd )
+ {
+ const SwFrameFormat *pFrameFormat = rBox.GetFrameFormat();
+ if( pFrameFormat )
+ {
+ auto const it(rTableInfo.GetBoxFormats().find(pFrameFormat));
+ assert(it != rTableInfo.GetBoxFormats().end());
+ if (it->second)
+ {
+ assert(!it->second->isEmpty());
+ AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, EncodeStyleName(*it->second));
+ }
+ }
+ }
+
+ if( nRowSpan != 1 )
+ {
+ AddAttribute( XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_SPANNED,
+ OUString::number(nRowSpan) );
+ }
+
+ if( nColSpan != 1 )
+ {
+ AddAttribute( XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_SPANNED,
+ OUString::number(nColSpan) );
+ }
+
+ {
+ if( pBoxSttNd )
+ {
+ // start node -> normal cell
+ // get cell range for table
+ rtl::Reference<SwXCell> xCell = SwXCell::CreateXCell( const_cast<SwFrameFormat *>(rTableInfo.GetTableFormat()),
+ const_cast<SwTableBox *>(&rBox),
+ const_cast<SwTable *>(rTableInfo.GetTable()) );
+
+ if (xCell.is())
+ {
+ // get formula (and protection)
+ const OUString sCellFormula = xCell->getFormula();
+
+ // if this cell has a formula, export it
+ // (with value and number format)
+ if (!sCellFormula.isEmpty())
+ {
+ const OUString sQValue =
+ GetNamespaceMap().GetQNameByKey(
+ XML_NAMESPACE_OOOW, sCellFormula, false );
+ // formula
+ AddAttribute(XML_NAMESPACE_TABLE, XML_FORMULA, sQValue );
+ }
+
+ // value and format (if NumberFormat != -1)
+ sal_Int32 nNumberFormat = 0;
+ Any aAny = xCell->getPropertyValue("NumberFormat");
+ aAny >>= nNumberFormat;
+
+ if (static_cast<sal_Int32>(getSwDefaultTextFormat()) == nNumberFormat)
+ {
+ // text format
+ AddAttribute( XML_NAMESPACE_OFFICE,
+ XML_VALUE_TYPE, XML_STRING );
+ }
+ else if ( (-1 != nNumberFormat) && !xCell->getString().isEmpty() )
+ {
+ // number format key:
+ // (export values only if cell contains text;)
+ XMLNumberFormatAttributesExportHelper::
+ SetNumberFormatAttributes(
+ *this, nNumberFormat, xCell->getValue() );
+ }
+ // else: invalid key; ignore
+
+ // cell protection
+ aAny = xCell->getPropertyValue("IsProtected");
+ if (*o3tl::doAccess<bool>(aAny))
+ {
+ AddAttribute( XML_NAMESPACE_TABLE, XML_PROTECTED,
+ XML_TRUE );
+ }
+
+ if( !rTableInfo.IsBaseSectionValid() )
+ {
+ aAny = xCell->getPropertyValue("TextSection");
+ Reference < XTextSection > xTextSection;
+ aAny >>= xTextSection;
+ rTableInfo.SetBaseSection( xTextSection );
+ }
+
+ // export cell element
+ SvXMLElementExport aElem( *this, rTableInfo.GetPrefix(),
+ XML_TABLE_CELL, true, true );
+
+ // export cell content
+ GetTextParagraphExport()->exportText( xCell,
+ rTableInfo.GetBaseSection(),
+ IsShowProgress() );
+ }
+ else
+ {
+ OSL_FAIL("here should be a XCell");
+ ClearAttrList();
+ }
+ }
+ else
+ {
+ // no start node -> merged cells: export subtable in cell
+ SvXMLElementExport aElem( *this, XML_NAMESPACE_TABLE,
+ XML_TABLE_CELL, true, true );
+ {
+ AddAttribute( XML_NAMESPACE_TABLE, XML_IS_SUB_TABLE,
+ GetXMLToken( XML_TRUE ) );
+
+ SvXMLElementExport aElemExport( *this, XML_NAMESPACE_TABLE,
+ XML_TABLE, true, true );
+ ExportTableLines( rBox.GetTabLines(), rTableInfo );
+ }
+ }
+ }
+}
+
+void SwXMLExport::ExportTableLine( const SwTableLine& rLine,
+ const SwXMLTableLines_Impl& rLines,
+ SwXMLTableInfo_Impl& rTableInfo )
+{
+ if( rLine.hasSoftPageBreak() )
+ {
+ SvXMLElementExport aElem( *this, XML_NAMESPACE_TEXT,
+ XML_SOFT_PAGE_BREAK, true, true );
+ }
+ const SwFrameFormat *pFrameFormat = rLine.GetFrameFormat();
+ if( pFrameFormat )
+ {
+ auto const it(rTableInfo.GetLineFormats().find(pFrameFormat));
+ assert(it != rTableInfo.GetLineFormats().end());
+ if (it->second)
+ {
+ assert(!it->second->isEmpty());
+ AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, EncodeStyleName(*it->second));
+ }
+ }
+
+ {
+ SvXMLElementExport aElem( *this, rTableInfo.GetPrefix(), XML_TABLE_ROW, true, true );
+ const SwTableBoxes& rBoxes = rLine.GetTabBoxes();
+ const size_t nBoxes = rBoxes.size();
+
+ sal_uInt32 nCPos = 0U;
+ size_t nCol = 0U;
+ for( size_t nBox=0U; nBox<nBoxes; ++nBox )
+ {
+ const SwTableBox *pBox = rBoxes[nBox];
+
+ // NEW TABLES
+ const sal_Int32 nRowSpan = pBox->getRowSpan();
+ if( nRowSpan < 1 )
+ {
+ // Export style of covered cell, it includes border information.
+ const SwFrameFormat* pFormat = pBox->GetFrameFormat();
+ if (pFormat)
+ {
+ auto const it(rTableInfo.GetBoxFormats().find(pFormat));
+ assert(it != rTableInfo.GetBoxFormats().end());
+ if (it->second)
+ {
+ assert(!it->second->isEmpty());
+ AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, EncodeStyleName(*it->second));
+ }
+ }
+
+ SvXMLElementExport aElem2( *this, rTableInfo.GetPrefix(),
+ XML_COVERED_TABLE_CELL, true,
+ false );
+ }
+
+ if( nBox < nBoxes-1U )
+ nCPos = nCPos + SwWriteTable::GetBoxWidth( pBox );
+ else
+ nCPos = rLines.GetWidth();
+
+ // and their index
+ const size_t nOldCol = nCol;
+ SwXMLTableColumn_Impl aCol( nCPos );
+ SwXMLTableColumns_Impl::const_iterator it = rLines.GetColumns().find( &aCol );
+ OSL_ENSURE( it != rLines.GetColumns().end(), "couldn't find column" );
+ nCol = it - rLines.GetColumns().begin();
+
+ // #i95726# - Some fault tolerance, if table is somehow corrupted.
+ if ( nCol < nOldCol )
+ {
+ OSL_FAIL( "table and/or table information seems to be corrupted." );
+ // NOTE: nOldCol is not necessarily a valid index into
+ // GetColumns(), but that doesn't matter here
+ nCol = nOldCol;
+ }
+
+ const sal_uInt32 nColSpan = nCol - nOldCol + 1U;
+
+ if ( nRowSpan >= 1 )
+ ExportTableBox( *pBox, nColSpan, static_cast< sal_uInt32 >(nRowSpan), rTableInfo );
+
+ for( size_t i=nOldCol; i<nCol; ++i )
+ {
+ SvXMLElementExport aElemExport( *this, rTableInfo.GetPrefix(),
+ XML_COVERED_TABLE_CELL, true,
+ false );
+ }
+
+ nCol++;
+ }
+ }
+}
+
+void SwXMLExport::ExportTableLines( const SwTableLines& rLines,
+ SwXMLTableInfo_Impl& rTableInfo,
+ sal_uInt32 nHeaderRows )
+{
+ OSL_ENSURE( m_pTableLines && !m_pTableLines->empty(),
+ "SwXMLExport::ExportTableLines: table columns infos missing" );
+ if( !m_pTableLines || m_pTableLines->empty() )
+ return;
+
+ SwXMLTableLines_Impl* pLines = nullptr;
+ size_t nInfoPos;
+ for( nInfoPos=0; nInfoPos < m_pTableLines->size(); nInfoPos++ )
+ {
+ if( m_pTableLines->at( nInfoPos )->GetLines() == &rLines )
+ {
+ pLines = m_pTableLines->at( nInfoPos );
+ break;
+ }
+ }
+ OSL_ENSURE( pLines,
+ "SwXMLExport::ExportTableLines: table columns info missing" );
+ OSL_ENSURE( 0==nInfoPos,
+ "SwXMLExport::ExportTableLines: table columns infos are unsorted" );
+ if( !pLines )
+ return;
+
+ SwXMLTableLinesCache_Impl::iterator it = m_pTableLines->begin();
+ advance( it, nInfoPos );
+ m_pTableLines->erase( it );
+
+ if( m_pTableLines->empty() )
+ m_pTableLines.reset();
+
+ // pass 2: export columns
+ const SwXMLTableColumns_Impl& rCols = pLines->GetColumns();
+ size_t nColumn = 0U;
+ const size_t nColumns = rCols.size();
+ sal_Int32 nColRep = 1;
+ SwXMLTableColumn_Impl *pColumn = (nColumns > 0) ? rCols.front().get() : nullptr;
+ while( pColumn )
+ {
+ nColumn++;
+ SwXMLTableColumn_Impl *pNextColumn =
+ (nColumn < nColumns) ? rCols[nColumn].get() : nullptr;
+ if( pNextColumn &&
+ pNextColumn->GetStyleName() == pColumn->GetStyleName() )
+ {
+ nColRep++;
+ }
+ else
+ {
+ AddAttribute( XML_NAMESPACE_TABLE, XML_STYLE_NAME,
+ EncodeStyleName(pColumn->GetStyleName()) );
+
+ if( nColRep > 1 )
+ {
+ AddAttribute( XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED,
+ OUString::number(nColRep) );
+ }
+
+ {
+ SvXMLElementExport aElem( *this, rTableInfo.GetPrefix(), XML_TABLE_COLUMN, true, true );
+ }
+
+ nColRep = 1;
+ }
+ pColumn = pNextColumn;
+ }
+
+ // pass 3: export line/rows
+ const size_t nLines = rLines.size();
+ // export header rows, if present
+ if( nHeaderRows > 0 )
+ {
+ SvXMLElementExport aElem( *this, XML_NAMESPACE_TABLE,
+ XML_TABLE_HEADER_ROWS, true, true );
+
+ OSL_ENSURE( nHeaderRows <= nLines, "more headers then lines?" );
+ for( size_t nLine = 0U; nLine < nHeaderRows; ++nLine )
+ ExportTableLine( *(rLines[nLine]), *pLines, rTableInfo );
+ }
+ // export remaining rows
+ for( size_t nLine = nHeaderRows; nLine < nLines; ++nLine )
+ {
+ ExportTableLine( *(rLines[nLine]), *pLines, rTableInfo );
+ }
+
+ delete pLines;
+}
+
+void SwXMLExport::ExportTable( const SwTableNode& rTableNd )
+{
+ ::std::optional<sal_uInt16> oPrefix = XML_NAMESPACE_TABLE;
+ if (const SwFrameFormat* pFlyFormat = rTableNd.GetFlyFormat())
+ {
+ if (SwTextBoxHelper::isTextBox(pFlyFormat, RES_FLYFRMFMT))
+ {
+ // TODO ODF 1.4 OFFICE-3761
+ if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
+ {
+ oPrefix = XML_NAMESPACE_LO_EXT;
+ }
+ else
+ {
+ oPrefix.reset(); // no export to OASIS namespace yet
+ }
+ }
+ }
+
+ if (!oPrefix)
+ return;
+
+ const SwTable& rTable = rTableNd.GetTable();
+ const SwFrameFormat *pTableFormat = rTable.GetFrameFormat();
+ if (pTableFormat && !pTableFormat->GetName().isEmpty())
+ {
+ AddAttribute(XML_NAMESPACE_TABLE, XML_NAME, pTableFormat->GetName());
+ AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME,
+ EncodeStyleName(pTableFormat->GetName()));
+ }
+
+ // table:template-name=
+ if (!rTable.GetTableStyleName().isEmpty())
+ {
+ OUString sStyleName;
+ SwStyleNameMapper::FillProgName(rTable.GetTableStyleName(), sStyleName, SwGetPoolIdFromName::TabStyle);
+ AddAttribute(XML_NAMESPACE_TABLE, XML_TEMPLATE_NAME, sStyleName);
+ }
+
+ SvXMLElementExport aElem(*this, *oPrefix, XML_TABLE, true, true);
+
+ // export DDE source (if this is a DDE table)
+ if ( auto pSwDdeTable = dynamic_cast<const SwDDETable*>( &rTable) )
+ {
+ // get DDE Field Type (contains the DDE connection)
+ const SwDDEFieldType* pDDEFieldType = pSwDdeTable->GetDDEFieldType();
+
+ // connection name
+ AddAttribute( XML_NAMESPACE_OFFICE, XML_NAME,
+ pDDEFieldType->GetName() );
+
+ // DDE command
+ const OUString& sCmd = pDDEFieldType->GetCmd();
+ sal_Int32 nIdx{ 0 };
+ AddAttribute( XML_NAMESPACE_OFFICE, XML_DDE_APPLICATION,
+ sCmd.getToken(0, sfx2::cTokenSeparator, nIdx) );
+ AddAttribute( XML_NAMESPACE_OFFICE, XML_DDE_ITEM,
+ sCmd.getToken(0, sfx2::cTokenSeparator, nIdx) );
+ AddAttribute( XML_NAMESPACE_OFFICE, XML_DDE_TOPIC,
+ sCmd.getToken(0, sfx2::cTokenSeparator, nIdx) );
+
+ // auto update
+ if (pDDEFieldType->GetType() == SfxLinkUpdateMode::ALWAYS)
+ {
+ AddAttribute( XML_NAMESPACE_OFFICE,
+ XML_AUTOMATIC_UPDATE, XML_TRUE );
+ }
+
+ // DDE source element (always empty)
+ SvXMLElementExport aSource(*this, XML_NAMESPACE_OFFICE,
+ XML_DDE_SOURCE, true, false);
+ }
+
+ auto const& rFormats(static_cast<SwXMLTextParagraphExport const*>(GetTextParagraphExport().get())->GetTableFormats());
+ auto const it(rFormats.find(&rTableNd));
+ assert(it != rFormats.end());
+ SwXMLTableInfo_Impl aTableInfo(&rTable, *oPrefix, it->second.first, it->second.second);
+ ExportTableLines( rTable.GetTabLines(), aTableInfo, rTable.GetRowsToRepeat() );
+}
+
+void SwXMLTextParagraphExport::exportTableAutoStyles() {
+ // note: maTableNodes is used here only to keep the iteration order as before
+ for (const auto* pTableNode : maTableNodes)
+ {
+ static_cast<SwXMLExport&>(GetExport()).ExportTableAutoStyles(*pTableNode);
+ }
+}
+
+void SwXMLTextParagraphExport::CollectTableLinesAutoStyles(const SwTableLines& rLines,
+ SwFrameFormat& rFormat, bool _bProgress)
+{
+ // Follow SwXMLExport::ExportTableLines/ExportTableLine/ExportTableBox
+ for (const SwTableLine* pLine : rLines)
+ {
+ for (SwTableBox* pBox : pLine->GetTabBoxes())
+ {
+ if (pBox->getRowSpan() <= 0)
+ continue;
+ if (pBox->GetSttNd())
+ {
+ if (rtl::Reference<SwXCell> xCell = SwXCell::CreateXCell(&rFormat, pBox))
+ exportText(xCell, true /*bAutoStyles*/, _bProgress, true /*bExportParagraph*/);
+ }
+ else
+ {
+ // no start node -> merged cells: export subtable in cell
+ CollectTableLinesAutoStyles(pBox->GetTabLines(), rFormat, _bProgress);
+ }
+ }
+ }
+}
+
+void SwXMLTextParagraphExport::exportTable(
+ const Reference < XTextContent > & rTextContent,
+ bool bAutoStyles, bool _bProgress )
+{
+ bool bOldShowProgress = static_cast<SwXMLExport&>(GetExport()).IsShowProgress();
+ static_cast<SwXMLExport&>(GetExport()).SetShowProgress( _bProgress );
+
+ Reference < XTextTable > xTextTable( rTextContent, UNO_QUERY );
+ OSL_ENSURE( xTextTable.is(), "text table missing" );
+ if( xTextTable.is() )
+ {
+ SwXTextTable* pXTable = dynamic_cast<SwXTextTable*>(rTextContent.get());
+ if( pXTable )
+ {
+ SwFrameFormat *const pFormat = pXTable->GetFrameFormat();
+ OSL_ENSURE( pFormat, "table format missing" );
+ const SwTable *pTable = SwTable::FindTable( pFormat );
+ OSL_ENSURE( pTable, "table missing" );
+ const SwTableNode *pTableNd = pTable->GetTableNode();
+ OSL_ENSURE( pTableNd, "table node missing" );
+ if( bAutoStyles )
+ {
+ // AUTOSTYLES: Optimization: Do not export table autostyle if
+ // we are currently exporting the content.xml stuff and
+ // the table is located in header/footer:
+ // During the flat XML export (used e.g. by .sdw-export)
+ // ALL flags are set at the same time.
+ const bool bExportStyles = bool( GetExport().getExportFlags() & SvXMLExportFlags::STYLES );
+ if (!isAutoStylesCollected()
+ && (bExportStyles || !pFormat->GetDoc()->IsInHeaderFooter(*pTableNd)))
+ {
+ maTableNodes.push_back(pTableNd);
+ m_TableFormats.try_emplace(pTableNd);
+ // Collect all tables inside cells of this table, too
+ CollectTableLinesAutoStyles(pTable->GetTabLines(), *pFormat, _bProgress);
+ }
+ }
+ else
+ {
+ static_cast<SwXMLExport&>(GetExport()).ExportTable( *pTableNd );
+ }
+ }
+ }
+
+ static_cast<SwXMLExport&>(GetExport()).SetShowProgress( bOldShowProgress );
+}
+
+void SwXMLExport::DeleteTableLines()
+{
+ if ( m_pTableLines )
+ {
+ for (SwXMLTableLines_Impl* p : *m_pTableLines)
+ delete p;
+ m_pTableLines->clear();
+ m_pTableLines.reset();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmltbli.cxx b/sw/source/filter/xml/xmltbli.cxx
new file mode 100644
index 0000000000..b2d312cad2
--- /dev/null
+++ b/sw/source/filter/xml/xmltbli.cxx
@@ -0,0 +1,2757 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <hintids.hxx>
+
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/text/XTextTable.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+#include <comphelper/servicehelper.hxx>
+#include <o3tl/numeric.hxx>
+#include <o3tl/safeint.hxx>
+#include <sal/log.hxx>
+#include <svl/itemset.hxx>
+#include <svl/numformat.hxx>
+#include <svl/zformat.hxx>
+#include <sax/tools/converter.hxx>
+#include <unotools/configmgr.hxx>
+#include <utility>
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/namespacemap.hxx>
+
+#include <xmloff/families.hxx>
+#include <xmloff/xmluconv.hxx>
+#include <xmloff/i18nmap.hxx>
+#include <editeng/protitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <poolfmt.hxx>
+#include <fmtfsize.hxx>
+#include <fmtornt.hxx>
+#include <fmtfordr.hxx>
+#include <doc.hxx>
+#include <IDocumentFieldsAccess.hxx>
+#include <IDocumentLayoutAccess.hxx>
+#include <IDocumentStylePoolAccess.hxx>
+#include <swtable.hxx>
+#include <swtblfmt.hxx>
+#include <pam.hxx>
+#include <unoprnms.hxx>
+#include <unotbl.hxx>
+#include <unotextrange.hxx>
+#include <cellatr.hxx>
+#include <swddetbl.hxx>
+#include <ddefld.hxx>
+#include <sfx2/linkmgr.hxx>
+#include "xmlimp.hxx"
+#include "xmltbli.hxx"
+#include <vcl/svapp.hxx>
+#include <ndtxt.hxx>
+#include <unotextcursor.hxx>
+#include <SwStyleNameMapper.hxx>
+#include <IDocumentSettingAccess.hxx>
+
+#include <algorithm>
+#include <vector>
+#include <memory>
+
+#include <limits.h>
+
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::xml::sax;
+using namespace ::xmloff::token;
+
+class SwXMLTableCell_Impl
+{
+ OUString m_aStyleName;
+
+ OUString m_StringValue;
+
+ OUString m_sFormula; // cell formula; valid if length > 0
+ double m_dValue; // formula value
+
+ rtl::Reference<SwXMLTableContext> m_xSubTable;
+
+ const SwStartNode *m_pStartNode;
+ sal_uInt32 m_nRowSpan;
+ sal_uInt32 m_nColSpan;
+
+ bool m_bProtected : 1;
+ bool m_bHasValue; // determines whether dValue attribute is valid
+ bool mbCovered;
+ bool m_bHasStringValue;
+
+public:
+
+ SwXMLTableCell_Impl( sal_uInt32 nRSpan=1, sal_uInt32 nCSpan=1 ) :
+ m_dValue( 0.0 ),
+ m_pStartNode( nullptr ),
+ m_nRowSpan( nRSpan ),
+ m_nColSpan( nCSpan ),
+ m_bProtected( false ),
+ m_bHasValue( false ),
+ mbCovered( false )
+ , m_bHasStringValue(false)
+ {}
+
+ inline void Set( const OUString& rStyleName,
+ sal_uInt32 nRSpan, sal_uInt32 nCSpan,
+ const SwStartNode *pStNd, SwXMLTableContext *pTable,
+ bool bProtect,
+ const OUString* pFormula,
+ bool bHasValue,
+ bool bCovered,
+ double dVal,
+ OUString const*const pStringValue);
+
+ bool IsUsed() const { return m_pStartNode!=nullptr ||
+ m_xSubTable.is() || m_bProtected;}
+
+ sal_uInt32 GetRowSpan() const { return m_nRowSpan; }
+ void SetRowSpan( sal_uInt32 nSet ) { m_nRowSpan = nSet; }
+ sal_uInt32 GetColSpan() const { return m_nColSpan; }
+ void SetStyleName(const OUString& rStyleName) { m_aStyleName = rStyleName; }
+ const OUString& GetStyleName() const { return m_aStyleName; }
+ const OUString& GetFormula() const { return m_sFormula; }
+ double GetValue() const { return m_dValue; }
+ bool HasValue() const { return m_bHasValue; }
+ bool IsProtected() const { return m_bProtected; }
+ bool IsCovered() const { return mbCovered; }
+ bool HasStringValue() const { return m_bHasStringValue; }
+ OUString const* GetStringValue() const {
+ return m_bHasStringValue ? &m_StringValue : nullptr;
+ }
+
+ const SwStartNode *GetStartNode() const { return m_pStartNode; }
+ inline void SetStartNode( const SwStartNode *pSttNd );
+
+ inline SwXMLTableContext *GetSubTable() const;
+
+ inline void Dispose();
+};
+
+inline void SwXMLTableCell_Impl::Set( const OUString& rStyleName,
+ sal_uInt32 nRSpan, sal_uInt32 nCSpan,
+ const SwStartNode *pStNd,
+ SwXMLTableContext *pTable,
+ bool bProtect,
+ const OUString* pFormula,
+ bool bHasVal,
+ bool bCov,
+ double dVal,
+ OUString const*const pStringValue )
+{
+ m_aStyleName = rStyleName;
+ m_nRowSpan = nRSpan;
+ m_nColSpan = nCSpan;
+ m_pStartNode = pStNd;
+ m_xSubTable = pTable;
+ m_dValue = dVal;
+ m_bHasValue = bHasVal;
+ mbCovered = bCov;
+ if (pStringValue)
+ {
+ m_StringValue = *pStringValue;
+ }
+ m_bHasStringValue = (pStringValue != nullptr);
+ m_bProtected = bProtect;
+
+ // set formula, if valid
+ if (pFormula != nullptr)
+ {
+ m_sFormula = *pFormula;
+ }
+}
+
+inline void SwXMLTableCell_Impl::SetStartNode( const SwStartNode *pSttNd )
+{
+ m_pStartNode = pSttNd;
+ m_xSubTable = nullptr;
+}
+
+inline SwXMLTableContext *SwXMLTableCell_Impl::GetSubTable() const
+{
+ return m_xSubTable.get();
+}
+
+inline void SwXMLTableCell_Impl::Dispose()
+{
+ if( m_xSubTable.is() )
+ m_xSubTable = nullptr;
+}
+
+class SwXMLTableRow_Impl
+{
+ OUString m_aStyleName;
+ OUString m_aDefaultCellStyleName;
+ std::vector<std::unique_ptr<SwXMLTableCell_Impl>> m_Cells;
+ bool m_bSplitable;
+
+public:
+
+ SwXMLTableRow_Impl( OUString aStyleName, sal_uInt32 nCells,
+ const OUString *pDfltCellStyleName = nullptr );
+
+ inline SwXMLTableCell_Impl *GetCell( sal_uInt32 nCol );
+
+ inline void Set( const OUString& rStyleName,
+ const OUString& rDfltCellStyleName );
+
+ void Expand( sal_uInt32 nCells, bool bOneCell );
+
+ void SetSplitable( bool bSet ) { m_bSplitable = bSet; }
+ bool IsSplitable() const { return m_bSplitable; }
+
+ const OUString& GetStyleName() const { return m_aStyleName; }
+ const OUString& GetDefaultCellStyleName() const { return m_aDefaultCellStyleName; }
+
+ void Dispose();
+};
+
+SwXMLTableRow_Impl::SwXMLTableRow_Impl( OUString aStyleName,
+ sal_uInt32 nCells,
+ const OUString *pDfltCellStyleName ) :
+ m_aStyleName(std::move( aStyleName )),
+ m_bSplitable( false )
+{
+ if( pDfltCellStyleName )
+ m_aDefaultCellStyleName = *pDfltCellStyleName;
+ OSL_ENSURE( nCells <= USHRT_MAX,
+ "SwXMLTableRow_Impl::SwXMLTableRow_Impl: too many cells" );
+ if( nCells > USHRT_MAX )
+ nCells = USHRT_MAX;
+
+ for( sal_uInt32 i=0U; i<nCells; ++i )
+ {
+ m_Cells.push_back(std::make_unique<SwXMLTableCell_Impl>());
+ }
+}
+
+inline SwXMLTableCell_Impl *SwXMLTableRow_Impl::GetCell( sal_uInt32 nCol )
+{
+ OSL_ENSURE( nCol < USHRT_MAX,
+ "SwXMLTableRow_Impl::GetCell: column number is too big" );
+ // #i95726# - some fault tolerance
+ OSL_ENSURE( nCol < m_Cells.size(),
+ "SwXMLTableRow_Impl::GetCell: column number is out of bound" );
+ return nCol < m_Cells.size() ? m_Cells[nCol].get() : nullptr;
+}
+
+void SwXMLTableRow_Impl::Expand( sal_uInt32 nCells, bool bOneCell )
+{
+ OSL_ENSURE( nCells <= USHRT_MAX,
+ "SwXMLTableRow_Impl::Expand: too many cells" );
+ if( nCells > USHRT_MAX )
+ nCells = USHRT_MAX;
+
+ sal_uInt32 nColSpan = nCells - m_Cells.size();
+ for (size_t i = m_Cells.size(); i < nCells; ++i)
+ {
+ m_Cells.push_back(std::make_unique<SwXMLTableCell_Impl>(
+ 1UL, bOneCell ? nColSpan : 1UL));
+ nColSpan--;
+ }
+
+ OSL_ENSURE( nCells <= m_Cells.size(),
+ "SwXMLTableRow_Impl::Expand: wrong number of cells" );
+}
+
+inline void SwXMLTableRow_Impl::Set( const OUString& rStyleName,
+ const OUString& rDfltCellStyleName )
+{
+ m_aStyleName = rStyleName;
+ m_aDefaultCellStyleName = rDfltCellStyleName;
+}
+
+void SwXMLTableRow_Impl::Dispose()
+{
+ for (auto & pCell : m_Cells)
+ {
+ pCell->Dispose();
+ }
+}
+
+namespace {
+
+class SwXMLTableCellContext_Impl : public SvXMLImportContext
+{
+ OUString m_aStyleName;
+ OUString m_sFormula;
+ OUString m_sSaveParaDefault;
+ OUString m_StringValue;
+
+ rtl::Reference<SwXMLTableContext> m_xMyTable;
+
+ double m_fValue;
+ bool m_bHasValue;
+ bool m_bHasStringValue;
+ bool m_bValueTypeIsString;
+ bool m_bProtect;
+
+ sal_uInt32 m_nRowSpan;
+ sal_uInt32 m_nColSpan;
+ sal_uInt32 m_nColRepeat;
+
+ bool m_bHasTextContent : 1;
+ bool m_bHasTableContent : 1;
+
+ SwXMLTableContext *GetTable() { return m_xMyTable.get(); }
+
+ bool HasContent() const { return m_bHasTextContent || m_bHasTableContent; }
+ inline void InsertContent_();
+ inline void InsertContent();
+ inline void InsertContent( SwXMLTableContext *pTable );
+
+public:
+
+ SwXMLTableCellContext_Impl(
+ SwXMLImport& rImport, sal_Int32 nElement,
+ const Reference< xml::sax::XFastAttributeList > & xAttrList,
+ SwXMLTableContext *pTable );
+
+ virtual css::uno::Reference<css::xml::sax::XFastContextHandler> SAL_CALL createFastChildContext(
+ sal_Int32 nElement,
+ const Reference< xml::sax::XFastAttributeList > & xAttrList ) override;
+ virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
+
+ SwXMLImport& GetSwImport() { return static_cast<SwXMLImport&>(GetImport()); }
+};
+
+/// Handles <table:covered-table-cell>.
+class SwXMLCoveredTableCellContext : public SvXMLImportContext
+{
+public:
+ SwXMLCoveredTableCellContext(SwXMLImport& rImport,
+ const Reference<xml::sax::XFastAttributeList>& xAttrList,
+ SwXMLTableContext& rTable);
+};
+
+SwXMLCoveredTableCellContext::SwXMLCoveredTableCellContext(
+ SwXMLImport& rImport, const Reference<xml::sax::XFastAttributeList>& xAttrList,
+ SwXMLTableContext& rTable)
+ : SvXMLImportContext(rImport)
+{
+ OUString aStyleName;
+ for (auto& rIter : sax_fastparser::castToFastAttributeList(xAttrList))
+ {
+ switch (rIter.getToken())
+ {
+ case XML_ELEMENT(TABLE, XML_STYLE_NAME):
+ aStyleName = rIter.toString();
+ break;
+ }
+ }
+
+ if (!aStyleName.isEmpty())
+ {
+ rTable.InsertCoveredCell(aStyleName);
+ }
+}
+}
+
+SwXMLTableCellContext_Impl::SwXMLTableCellContext_Impl(
+ SwXMLImport& rImport, sal_Int32 /*nElement*/,
+ const Reference< xml::sax::XFastAttributeList > & xAttrList,
+ SwXMLTableContext *pTable ) :
+ SvXMLImportContext( rImport ),
+ m_xMyTable( pTable ),
+ m_fValue( 0.0 ),
+ m_bHasValue( false ),
+ m_bHasStringValue(false),
+ m_bValueTypeIsString(false),
+ m_bProtect( false ),
+ m_nRowSpan( 1 ),
+ m_nColSpan( 1 ),
+ m_nColRepeat( 1 ),
+ m_bHasTextContent( false ),
+ m_bHasTableContent( false )
+{
+ m_sSaveParaDefault = GetImport().GetTextImport()->GetCellParaStyleDefault();
+ for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
+ {
+ switch( aIter.getToken() )
+ {
+ case XML_ELEMENT(TABLE, XML_STYLE_NAME):
+ m_aStyleName = aIter.toString();
+ GetImport().GetTextImport()->SetCellParaStyleDefault(m_aStyleName);
+ break;
+ case XML_ELEMENT(TABLE, XML_NUMBER_COLUMNS_SPANNED):
+ m_nColSpan = static_cast<sal_uInt32>(std::max<sal_Int32>(1, aIter.toInt32()));
+ if (m_nColSpan > 256)
+ {
+ SAL_INFO("sw.xml", "ignoring huge table:number-columns-spanned " << m_nColSpan);
+ m_nColSpan = 1;
+ }
+ break;
+ case XML_ELEMENT(TABLE, XML_NUMBER_ROWS_SPANNED):
+ m_nRowSpan = static_cast<sal_uInt32>(std::max<sal_Int32>(1, aIter.toInt32()));
+ if (m_nRowSpan > 8192 || (m_nRowSpan > 256 && utl::ConfigManager::IsFuzzing()))
+ {
+ SAL_INFO("sw.xml", "ignoring huge table:number-rows-spanned " << m_nRowSpan);
+ m_nRowSpan = 1;
+ }
+ break;
+ case XML_ELEMENT(TABLE, XML_NUMBER_COLUMNS_REPEATED):
+ m_nColRepeat = static_cast<sal_uInt32>(std::max<sal_Int32>(1, aIter.toInt32()));
+ if (m_nColRepeat > 256)
+ {
+ SAL_INFO("sw.xml", "ignoring huge table:number-columns-repeated " << m_nColRepeat);
+ m_nColRepeat = 1;
+ }
+ break;
+ case XML_ELEMENT(TABLE, XML_FORMULA):
+ {
+ OUString sTmp;
+ const sal_uInt16 nPrefix2 = GetImport().GetNamespaceMap().
+ GetKeyByAttrValueQName(aIter.toString(), &sTmp);
+ m_sFormula = XML_NAMESPACE_OOOW == nPrefix2 ? sTmp : aIter.toString();
+ }
+ break;
+ case XML_ELEMENT(OFFICE, XML_VALUE):
+ {
+ // Writer wrongly uses DBL_MAX to flag error but fails to
+ // check for it after import, so check that here, tdf#139126.
+ double fTmp;
+ if (::sax::Converter::convertDouble(fTmp, aIter.toView()) && fTmp < DBL_MAX)
+ {
+ m_fValue = fTmp;
+ m_bHasValue = true;
+ }
+ }
+ break;
+ case XML_ELEMENT(OFFICE, XML_TIME_VALUE):
+ {
+ double fTmp;
+ if (::sax::Converter::convertDuration(fTmp, aIter.toView()))
+ {
+ m_fValue = fTmp;
+ m_bHasValue = true;
+ }
+ }
+ break;
+ case XML_ELEMENT(OFFICE, XML_DATE_VALUE):
+ {
+ double fTmp;
+ if (GetImport().GetMM100UnitConverter().convertDateTime(fTmp,
+ aIter.toView()))
+ {
+ m_fValue = fTmp;
+ m_bHasValue = true;
+ }
+ }
+ break;
+ case XML_ELEMENT(OFFICE, XML_BOOLEAN_VALUE):
+ {
+ bool bTmp(false);
+ if (::sax::Converter::convertBool(bTmp, aIter.toView()))
+ {
+ m_fValue = (bTmp ? 1.0 : 0.0);
+ m_bHasValue = true;
+ }
+ }
+ break;
+ case XML_ELEMENT(TABLE, XML_PROTECT): // for backwards compatibility with SRC629 (and before)
+ case XML_ELEMENT(TABLE, XML_PROTECTED):
+ {
+ bool bTmp(false);
+ if (::sax::Converter::convertBool(bTmp, aIter.toView()))
+ {
+ m_bProtect = bTmp;
+ }
+ }
+ break;
+ case XML_ELEMENT(OFFICE, XML_STRING_VALUE):
+ {
+ m_StringValue = aIter.toString();
+ m_bHasStringValue = true;
+ }
+ break;
+ case XML_ELEMENT(OFFICE, XML_VALUE_TYPE):
+ {
+ if ("string" == aIter.toView())
+ {
+ m_bValueTypeIsString = true;
+ }
+ // ignore other types - it would be correct to require
+ // matching value-type and $type-value attributes,
+ // but we've been reading those without checking forever.
+ }
+ break;
+ default:
+ SAL_WARN("sw", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << "=" << aIter.toString());
+ }
+ }
+}
+
+inline void SwXMLTableCellContext_Impl::InsertContent_()
+{
+ SwStartNode const*const pStartNode( GetTable()->InsertTableSection(nullptr,
+ (m_bHasStringValue && m_bValueTypeIsString &&
+ !m_aStyleName.isEmpty()) ? & m_aStyleName : nullptr) );
+ GetTable()->InsertCell( m_aStyleName, m_nRowSpan, m_nColSpan,
+ pStartNode,
+ nullptr, m_bProtect, &m_sFormula, m_bHasValue, m_fValue,
+ (m_bHasStringValue && m_bValueTypeIsString) ? &m_StringValue : nullptr);
+}
+
+inline void SwXMLTableCellContext_Impl::InsertContent()
+{
+ OSL_ENSURE( !HasContent(), "content already there" );
+ m_bHasTextContent = true;
+ InsertContent_();
+}
+
+inline void SwXMLTableCellContext_Impl::InsertContent(
+ SwXMLTableContext *pTable )
+{
+ GetTable()->InsertCell( m_aStyleName, m_nRowSpan, m_nColSpan, nullptr, pTable, m_bProtect );
+ m_bHasTableContent = true;
+}
+
+css::uno::Reference<css::xml::sax::XFastContextHandler> SwXMLTableCellContext_Impl::createFastChildContext(
+ sal_Int32 nElement,
+ const Reference< xml::sax::XFastAttributeList > & xAttrList )
+{
+ SvXMLImportContext *pContext = nullptr;
+
+ bool bSubTable = false;
+ if( nElement == XML_ELEMENT(TABLE, XML_TABLE) )
+ {
+ for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
+ {
+ if( aIter.getToken() == XML_ELEMENT(TABLE, XML_IS_SUB_TABLE) )
+ {
+ if ( IsXMLToken( aIter, XML_TRUE ) )
+ bSubTable = true;
+ }
+ else
+ XMLOFF_WARN_UNKNOWN("sw", aIter);
+ //FIXME: RDFa
+ }
+ }
+
+ if( bSubTable )
+ {
+ if( !HasContent() )
+ {
+ SwXMLTableContext *pTableContext =
+ new SwXMLTableContext( GetSwImport(), GetTable() );
+ pContext = pTableContext;
+ if( GetTable()->IsValid() )
+ InsertContent( pTableContext );
+
+ GetTable()->SetHasSubTables( true );
+ }
+ }
+ else
+ {
+ if( GetTable()->IsValid() && !HasContent() )
+ InsertContent();
+ // fdo#60842: "office:string-value" overrides text content -> no import
+ if (!(m_bValueTypeIsString && m_bHasStringValue))
+ {
+ pContext = GetImport().GetTextImport()->CreateTextChildContext(
+ GetImport(), nElement, xAttrList,
+ XMLTextType::Cell );
+ }
+ }
+
+ return pContext;
+}
+
+void SwXMLTableCellContext_Impl::endFastElement(sal_Int32 )
+{
+ if( GetTable()->IsValid() )
+ {
+ if( m_bHasTextContent )
+ {
+ GetImport().GetTextImport()->DeleteParagraph();
+ if( m_nColRepeat > 1 && m_nColSpan == 1 )
+ {
+ // The original text is invalid after deleting the last
+ // paragraph
+ Reference < XTextCursor > xSrcTextCursor =
+ GetImport().GetTextImport()->GetText()->createTextCursor();
+ xSrcTextCursor->gotoEnd( true );
+
+ // Until we have an API for copying we have to use the core.
+ OTextCursorHelper *pSrcTextCursor = dynamic_cast<OTextCursorHelper*>(xSrcTextCursor.get());
+ assert(pSrcTextCursor && "SwXTextCursor missing");
+ SwDoc *pDoc = pSrcTextCursor->GetDoc();
+ const SwPaM *pSrcPaM = pSrcTextCursor->GetPaM();
+
+ while( m_nColRepeat > 1 && GetTable()->IsInsertCellPossible() )
+ {
+ InsertContent_();
+
+ OTextCursorHelper *pDstTextCursor = dynamic_cast<OTextCursorHelper*>(GetImport().GetTextImport()->GetCursor().get());
+ assert(pDstTextCursor && "SwXTextCursor missing");
+ SwPaM aSrcPaM(*pSrcPaM->GetMark(), *pSrcPaM->GetPoint());
+ SwPosition aDstPos( *pDstTextCursor->GetPaM()->GetPoint() );
+ pDoc->getIDocumentContentOperations().CopyRange(aSrcPaM, aDstPos, SwCopyFlags::CheckPosInFly);
+
+ m_nColRepeat--;
+ }
+ }
+ }
+ else if( !m_bHasTableContent )
+ {
+ InsertContent();
+ if( m_nColRepeat > 1 && m_nColSpan == 1 )
+ {
+ while( m_nColRepeat > 1 && GetTable()->IsInsertCellPossible() )
+ {
+ InsertContent_();
+ m_nColRepeat--;
+ }
+ }
+ }
+ }
+ GetImport().GetTextImport()->SetCellParaStyleDefault(m_sSaveParaDefault);
+}
+
+namespace {
+
+class SwXMLTableColContext_Impl : public SvXMLImportContext
+{
+ rtl::Reference<SwXMLTableContext> m_xMyTable;
+
+ SwXMLTableContext *GetTable() { return m_xMyTable.get(); }
+
+public:
+
+ SwXMLTableColContext_Impl(
+ SwXMLImport& rImport,
+ const Reference< xml::sax::XFastAttributeList > & xAttrList,
+ SwXMLTableContext *pTable );
+
+ SwXMLImport& GetSwImport() { return static_cast<SwXMLImport&>(GetImport()); }
+};
+
+}
+
+SwXMLTableColContext_Impl::SwXMLTableColContext_Impl(
+ SwXMLImport& rImport,
+ const Reference< xml::sax::XFastAttributeList > & xAttrList,
+ SwXMLTableContext *pTable ) :
+ SvXMLImportContext( rImport ),
+ m_xMyTable( pTable )
+{
+ sal_uInt32 nColRep = 1;
+ OUString aStyleName, aDfltCellStyleName;
+
+ for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) )
+ {
+ switch (aIter.getToken())
+ {
+ case XML_ELEMENT(TABLE, XML_STYLE_NAME):
+ aStyleName = aIter.toString();
+ break;
+ case XML_ELEMENT(TABLE, XML_NUMBER_COLUMNS_REPEATED):
+ {
+ nColRep = static_cast<sal_uInt32>(std::max<sal_Int32>(1, aIter.toInt32()));
+ if (nColRep > 256)
+ {
+ SAL_INFO("sw.xml", "ignoring huge table:number-columns-repeated " << nColRep);
+ nColRep = 1;
+ }
+ break;
+ }
+ case XML_ELEMENT(TABLE, XML_DEFAULT_CELL_STYLE_NAME):
+ aDfltCellStyleName = aIter.toString();
+ break;
+ case XML_ELEMENT(XML, XML_ID):
+ {
+ //FIXME where to put this??? columns do not actually exist in writer...
+ break;
+ }
+ default:
+ XMLOFF_WARN_UNKNOWN("sw", aIter);
+ }
+ }
+
+ sal_Int32 nWidth = MINLAY;
+ bool bRelWidth = true;
+ if( !aStyleName.isEmpty() )
+ {
+ const SwFormatFrameSize *pSize;
+ const SfxItemSet *pAutoItemSet = nullptr;
+ if( GetSwImport().FindAutomaticStyle(
+ XmlStyleFamily::TABLE_COLUMN,
+ aStyleName, &pAutoItemSet ) &&
+ pAutoItemSet &&
+ (pSize = pAutoItemSet->GetItemIfSet( RES_FRM_SIZE, false )) )
+ {
+ nWidth = pSize->GetWidth();
+ bRelWidth = SwFrameSize::Variable == pSize->GetHeightSizeType();
+ }
+ }
+
+ if( nWidth )
+ {
+ while( nColRep-- && GetTable()->IsInsertColPossible() )
+ GetTable()->InsertColumn( nWidth, bRelWidth, &aDfltCellStyleName );
+ }
+}
+
+namespace {
+
+class SwXMLTableColsContext_Impl : public SvXMLImportContext
+{
+ rtl::Reference<SwXMLTableContext> m_xMyTable;
+
+ SwXMLTableContext *GetTable() { return m_xMyTable.get(); }
+
+public:
+
+ SwXMLTableColsContext_Impl(
+ SwXMLImport& rImport,
+ SwXMLTableContext *pTable );
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList ) override;
+
+ SwXMLImport& GetSwImport() { return static_cast<SwXMLImport&>(GetImport()); }
+};
+
+}
+
+SwXMLTableColsContext_Impl::SwXMLTableColsContext_Impl(
+ SwXMLImport& rImport,
+ SwXMLTableContext *pTable ) :
+ SvXMLImportContext( rImport ),
+ m_xMyTable( pTable )
+{
+}
+
+css::uno::Reference< css::xml::sax::XFastContextHandler > SwXMLTableColsContext_Impl::createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList )
+{
+ SvXMLImportContext *pContext = nullptr;
+
+ if( nElement == XML_ELEMENT(TABLE, XML_TABLE_COLUMN) &&
+ GetTable()->IsInsertColPossible() )
+ pContext = new SwXMLTableColContext_Impl( GetSwImport(), xAttrList, GetTable() );
+ else
+ XMLOFF_WARN_UNKNOWN_ELEMENT("sw", nElement);
+
+ return pContext;
+}
+
+namespace {
+
+class SwXMLTableRowContext_Impl : public SvXMLImportContext
+{
+ rtl::Reference<SwXMLTableContext> m_xMyTable;
+
+ sal_uInt32 m_nRowRepeat;
+
+ SwXMLTableContext *GetTable() { return m_xMyTable.get(); }
+
+public:
+
+ SwXMLTableRowContext_Impl(
+ SwXMLImport& rImport, sal_Int32 nElement,
+ const Reference< xml::sax::XFastAttributeList > & xAttrList,
+ SwXMLTableContext *pTable, bool bInHead=false );
+
+ virtual css::uno::Reference<css::xml::sax::XFastContextHandler> SAL_CALL createFastChildContext( sal_Int32 nElement,
+ const Reference< xml::sax::XFastAttributeList > & xAttrList ) override;
+
+ virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
+
+ SwXMLImport& GetSwImport() { return static_cast<SwXMLImport&>(GetImport()); }
+};
+
+}
+
+SwXMLTableRowContext_Impl::SwXMLTableRowContext_Impl( SwXMLImport& rImport,
+ sal_Int32 /*nElement*/,
+ const Reference< xml::sax::XFastAttributeList > & xAttrList,
+ SwXMLTableContext *pTable,
+ bool bInHead ) :
+ SvXMLImportContext( rImport ),
+ m_xMyTable( pTable ),
+ m_nRowRepeat( 1 )
+{
+ OUString aStyleName, aDfltCellStyleName;
+
+ for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
+ {
+ switch(aIter.getToken())
+ {
+ case XML_ELEMENT(TABLE, XML_STYLE_NAME):
+ aStyleName = aIter.toString();
+ break;
+ case XML_ELEMENT(STYLE, XML_NUMBER_ROWS_REPEATED):
+ {
+ m_nRowRepeat = static_cast<sal_uInt32>(std::max<sal_Int32>(1, aIter.toInt32()));
+ if (m_nRowRepeat > 8192 || (m_nRowRepeat > 256 && utl::ConfigManager::IsFuzzing()))
+ {
+ SAL_INFO("sw.xml", "ignoring huge table:number-rows-repeated " << m_nRowRepeat);
+ m_nRowRepeat = 1;
+ }
+ break;
+ }
+ case XML_ELEMENT(STYLE, XML_DEFAULT_CELL_STYLE_NAME):
+ aDfltCellStyleName = aIter.toString();
+ break;
+ case XML_ELEMENT(XML, XML_ID):
+ break;
+ default:
+ XMLOFF_WARN_UNKNOWN("sw", aIter);
+ }
+ }
+ if( GetTable()->IsValid() )
+ GetTable()->InsertRow( aStyleName, aDfltCellStyleName, bInHead );
+}
+
+void SwXMLTableRowContext_Impl::endFastElement(sal_Int32 )
+{
+ if( GetTable()->IsValid() )
+ {
+ GetTable()->FinishRow();
+
+ if( m_nRowRepeat > 1 )
+ GetTable()->InsertRepRows( m_nRowRepeat );
+ }
+}
+
+css::uno::Reference<css::xml::sax::XFastContextHandler> SwXMLTableRowContext_Impl::createFastChildContext(
+ sal_Int32 nElement,
+ const Reference< xml::sax::XFastAttributeList > & xAttrList )
+{
+ SvXMLImportContext *pContext = nullptr;
+
+ if( nElement == XML_ELEMENT(TABLE, XML_TABLE_CELL) ||
+ nElement == XML_ELEMENT(LO_EXT, XML_TABLE_CELL) )
+ {
+ if( !GetTable()->IsValid() || GetTable()->IsInsertCellPossible() )
+ pContext = new SwXMLTableCellContext_Impl( GetSwImport(), nElement,
+ xAttrList,
+ GetTable() );
+ }
+ else if( nElement == XML_ELEMENT(TABLE, XML_COVERED_TABLE_CELL) ||
+ nElement == XML_ELEMENT(LO_EXT, XML_COVERED_TABLE_CELL) )
+ {
+ if (GetTable()->IsValid() && GetTable()->IsInsertCoveredCellPossible())
+ {
+ pContext = new SwXMLCoveredTableCellContext(GetSwImport(), xAttrList, *GetTable());
+ }
+ else
+ {
+ pContext = new SvXMLImportContext(GetImport());
+ }
+ }
+ else
+ SAL_WARN("sw", "unknown element " << SvXMLImport::getPrefixAndNameFromToken(nElement));
+
+ return pContext;
+}
+
+namespace {
+
+class SwXMLTableRowsContext_Impl : public SvXMLImportContext
+{
+ rtl::Reference<SwXMLTableContext> m_xMyTable;
+
+ bool m_bHeader;
+
+ SwXMLTableContext *GetTable() { return m_xMyTable.get(); }
+
+public:
+
+ SwXMLTableRowsContext_Impl( SwXMLImport& rImport,
+ SwXMLTableContext *pTable,
+ bool bHead );
+
+ virtual css::uno::Reference<css::xml::sax::XFastContextHandler> SAL_CALL createFastChildContext(
+ sal_Int32 nElement,
+ const Reference< xml::sax::XFastAttributeList > & xAttrList ) override;
+
+ SwXMLImport& GetSwImport() { return static_cast<SwXMLImport&>(GetImport()); }
+};
+
+}
+
+SwXMLTableRowsContext_Impl::SwXMLTableRowsContext_Impl( SwXMLImport& rImport,
+ SwXMLTableContext *pTable,
+ bool bHead ) :
+ SvXMLImportContext( rImport ),
+ m_xMyTable( pTable ),
+ m_bHeader( bHead )
+{
+}
+
+css::uno::Reference<css::xml::sax::XFastContextHandler> SwXMLTableRowsContext_Impl::createFastChildContext(
+ sal_Int32 nElement,
+ const Reference< xml::sax::XFastAttributeList > & xAttrList )
+{
+ if( nElement== XML_ELEMENT(TABLE, XML_TABLE_ROW ) &&
+ GetTable()->IsInsertRowPossible() )
+ return new SwXMLTableRowContext_Impl( GetSwImport(), nElement,
+ xAttrList,
+ GetTable(),
+ m_bHeader );
+ SAL_WARN("sw", "unknown element " << SvXMLImport::getPrefixAndNameFromToken(nElement));
+ return nullptr;
+}
+
+class SwXMLDDETableContext_Impl : public SvXMLImportContext
+{
+ OUString m_sConnectionName;
+ OUString m_sDDEApplication;
+ OUString m_sDDEItem;
+ OUString m_sDDETopic;
+ bool m_bIsAutomaticUpdate;
+
+public:
+
+
+ SwXMLDDETableContext_Impl(SwXMLImport& rImport);
+
+ virtual void SAL_CALL startFastElement(
+ sal_Int32 nElement,
+ const Reference<xml::sax::XFastAttributeList> & xAttrList) override;
+
+ OUString& GetConnectionName() { return m_sConnectionName; }
+ OUString& GetDDEApplication() { return m_sDDEApplication; }
+ OUString& GetDDEItem() { return m_sDDEItem; }
+ OUString& GetDDETopic() { return m_sDDETopic; }
+ bool GetIsAutomaticUpdate() const { return m_bIsAutomaticUpdate; }
+};
+
+
+SwXMLDDETableContext_Impl::SwXMLDDETableContext_Impl(SwXMLImport& rImport) :
+ SvXMLImportContext(rImport),
+ m_bIsAutomaticUpdate(false)
+{
+}
+
+void SwXMLDDETableContext_Impl::startFastElement(
+ sal_Int32 /*nElement*/,
+ const Reference<xml::sax::XFastAttributeList> & xAttrList)
+{
+ for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) )
+ {
+ switch (aIter.getToken())
+ {
+ case XML_ELEMENT(OFFICE, XML_DDE_APPLICATION):
+ m_sDDEApplication = aIter.toString();
+ break;
+ case XML_ELEMENT(OFFICE, XML_DDE_TOPIC):
+ m_sDDETopic = aIter.toString();
+ break;
+ case XML_ELEMENT(OFFICE, XML_DDE_ITEM):
+ m_sDDEItem = aIter.toString();
+ break;
+ case XML_ELEMENT(OFFICE, XML_NAME):
+ m_sConnectionName = aIter.toString();
+ break;
+ case XML_ELEMENT(OFFICE, XML_AUTOMATIC_UPDATE):
+ {
+ bool bTmp(false);
+ if (::sax::Converter::convertBool(bTmp, aIter.toView()))
+ {
+ m_bIsAutomaticUpdate = bTmp;
+ }
+ break;
+ }
+ default:
+ XMLOFF_WARN_UNKNOWN("sw", aIter);
+ }
+ // else: unknown attribute namespace
+ }
+}
+
+// generate a new name for DDE field type (called by lcl_GetDDEFieldType below)
+static OUString lcl_GenerateFieldTypeName(const OUString& sPrefix, SwTableNode* pTableNode)
+{
+ const OUString sPrefixStr(sPrefix.isEmpty() ? OUString("_") : sPrefix);
+
+ // increase count until we find a name that is not yet taken
+ OUString sName;
+ sal_Int32 nCount = 0;
+ do
+ {
+ // this is crazy, but just in case all names are taken: exit gracefully
+ if (nCount == SAL_MAX_INT32)
+ return sName;
+
+ ++nCount;
+ sName = sPrefixStr + OUString::number(nCount);
+ }
+ while (nullptr != pTableNode->GetDoc().getIDocumentFieldsAccess().GetFieldType(SwFieldIds::Dde, sName, false));
+
+ return sName;
+}
+
+// set table properties
+static SwDDEFieldType* lcl_GetDDEFieldType(SwXMLDDETableContext_Impl* pContext,
+ SwTableNode* pTableNode)
+{
+ // make command string
+ const OUString sCommand(pContext->GetDDEApplication()
+ + OUStringChar(sfx2::cTokenSeparator)
+ + pContext->GetDDEItem()
+ + OUStringChar(sfx2::cTokenSeparator)
+ + pContext->GetDDETopic());
+
+ const SfxLinkUpdateMode nType = pContext->GetIsAutomaticUpdate()
+ ? SfxLinkUpdateMode::ALWAYS
+ : SfxLinkUpdateMode::ONCALL;
+
+ OUString sName(pContext->GetConnectionName());
+
+ // field type to be returned
+ SwDDEFieldType* pType = nullptr;
+
+ // valid name?
+ if (sName.isEmpty())
+ {
+ sName = lcl_GenerateFieldTypeName(pContext->GetDDEApplication(),
+ pTableNode);
+ }
+ else
+ {
+ // check for existing DDE field type with the same name
+ SwDDEFieldType* pOldType = static_cast<SwDDEFieldType*>(pTableNode->GetDoc().getIDocumentFieldsAccess().GetFieldType(SwFieldIds::Dde, sName, false));
+ if (nullptr != pOldType)
+ {
+ // same values -> return old type
+ if ( (pOldType->GetCmd() == sCommand) &&
+ (pOldType->GetType() == nType) )
+ {
+ // same name, same values -> return old type!
+ pType = pOldType;
+ }
+ else
+ {
+ // same name, different values -> think of new name
+ sName = lcl_GenerateFieldTypeName(pContext->GetDDEApplication(),
+ pTableNode);
+ }
+ }
+ // no old type -> create new one
+ }
+
+ // create new field type (unless we already have one)
+ if (nullptr == pType)
+ {
+ // create new field type and return
+ SwDDEFieldType aDDEFieldType(sName, sCommand, nType);
+ pType = static_cast<SwDDEFieldType*>(pTableNode->
+ GetDoc().getIDocumentFieldsAccess().InsertFieldType(aDDEFieldType));
+ }
+
+ OSL_ENSURE(nullptr != pType, "We really want a SwDDEFieldType here!");
+ return pType;
+}
+
+class TableBoxIndex
+{
+public:
+ OUString msName;
+ sal_Int32 mnWidth;
+ bool mbProtected;
+
+ TableBoxIndex( OUString aName, sal_Int32 nWidth,
+ bool bProtected ) :
+ msName(std::move( aName )),
+ mnWidth( nWidth ),
+ mbProtected( bProtected )
+ { }
+
+ bool operator== ( const TableBoxIndex& rArg ) const
+ {
+ return (rArg.mnWidth == mnWidth) &&
+ (rArg.mbProtected == mbProtected) &&
+ (rArg.msName == msName);
+ }
+};
+
+class TableBoxIndexHasher
+{
+public:
+ size_t operator() (const TableBoxIndex& rArg) const
+ {
+ return rArg.msName.hashCode() + rArg.mnWidth + (rArg.mbProtected ? 1 : 0);
+ }
+};
+
+const SwXMLTableCell_Impl *SwXMLTableContext::GetCell( sal_uInt32 nRow,
+ sal_uInt32 nCol ) const
+{
+ return (*m_pRows)[nRow]->GetCell( nCol );
+}
+
+SwXMLTableCell_Impl *SwXMLTableContext::GetCell( sal_uInt32 nRow,
+ sal_uInt32 nCol )
+{
+ return (*m_pRows)[nRow]->GetCell( nCol );
+}
+
+
+SwXMLTableContext::SwXMLTableContext( SwXMLImport& rImport,
+ const Reference< xml::sax::XFastAttributeList > & xAttrList ) :
+ XMLTextTableContext( rImport ),
+ m_pRows( new SwXMLTableRows_Impl ),
+ m_pTableNode( nullptr ),
+ m_pBox1( nullptr ),
+ m_bOwnsBox1( false ),
+ m_pSttNd1( nullptr ),
+ m_pBoxFormat( nullptr ),
+ m_pLineFormat( nullptr ),
+ m_bFirstSection( true ),
+ m_bRelWidth( true ),
+ m_bHasSubTables( false ),
+ m_nHeaderRows( 0 ),
+ m_nCurRow( 0 ),
+ m_nCurCol( 0 ),
+ m_nNonMergedCurCol( 0 ),
+ m_nWidth( 0 )
+{
+ OUString aName;
+ OUString sXmlId;
+
+ // this method will modify the document directly -> lock SolarMutex
+ SolarMutexGuard aGuard;
+
+ for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
+ {
+ const OUString sValue = aIter.toString();
+ switch(aIter.getToken())
+ {
+ case XML_ELEMENT(TABLE, XML_STYLE_NAME):
+ m_aStyleName = sValue;
+ break;
+ case XML_ELEMENT(TABLE, XML_NAME):
+ aName = sValue;
+ break;
+ case XML_ELEMENT(TABLE, XML_DEFAULT_CELL_STYLE_NAME):
+ m_aDfltCellStyleName = sValue;
+ break;
+ case XML_ELEMENT(TABLE, XML_TEMPLATE_NAME):
+ m_aTemplateName = sValue;
+ break;
+ case XML_ELEMENT(XML, XML_ID):
+ sXmlId = sValue;
+ break;
+ default:
+ XMLOFF_WARN_UNKNOWN("sw", aIter);
+ }
+ }
+
+ SwDoc *pDoc = GetSwImport().getDoc();
+
+ OUString sTableName;
+ if( !aName.isEmpty() )
+ {
+ const SwTableFormat *pTableFormat = pDoc->FindTableFormatByName( aName );
+ if( !pTableFormat )
+ sTableName = aName;
+ }
+ if( sTableName.isEmpty() )
+ {
+ // Optimization: use import's own map to create unique names, because
+ // SwDoc::GetUniqueTableName scans all the already present tables,
+ // builds a bitset using rather complex rules, and that has quadratic
+ // complexity. Try once, then fallback to SwDoc::GetUniqueTableName
+ auto& tableNameMap = rImport.GetTableNameMap();
+ sal_Int32 nextIx = ++tableNameMap[aName];
+ OUString test = aName.isEmpty()
+ ? OUString(rImport.GetDefTableName() + OUString::number(nextIx))
+ : OUString(aName + "_" + OUString::number(nextIx));
+ if (const SwTableFormat* pExisting = pDoc->FindTableFormatByName(test); !pExisting)
+ sTableName = test;
+ else
+ sTableName = pDoc->GetUniqueTableName();
+ GetImport().GetTextImport()
+ ->GetRenameMap().Add( XML_TEXT_RENAME_TYPE_TABLE, aName, sTableName );
+ }
+
+ Reference< XTextTable > xTable;
+ SwXTextTable *pXTable = nullptr;
+ Reference<XMultiServiceFactory> xFactory( GetImport().GetModel(),
+ UNO_QUERY );
+ OSL_ENSURE( xFactory.is(), "factory missing" );
+ if( xFactory.is() )
+ {
+ Reference<XInterface> xIfc = xFactory->createInstance( "com.sun.star.text.TextTable" );
+ OSL_ENSURE( xIfc.is(), "Couldn't create a table" );
+
+ if( xIfc.is() )
+ xTable.set( xIfc, UNO_QUERY );
+ }
+
+ if( xTable.is() )
+ {
+ xTable->initialize( 1, 1 );
+ if (auto xPropSet = xTable.query<css::beans::XPropertySet>())
+ xPropSet->setPropertyValue(UNO_NAME_TABLE_NAME, css::uno::Any(sTableName));
+
+ try
+ {
+ m_xTextContent = xTable;
+ GetImport().GetTextImport()->InsertTextContent( m_xTextContent );
+ }
+ catch( IllegalArgumentException& )
+ {
+ xTable = nullptr;
+ }
+ }
+
+ if( xTable.is() )
+ {
+ //FIXME
+ // xml:id for RDF metadata
+ GetImport().SetXmlId(xTable, sXmlId);
+
+ pXTable = dynamic_cast<SwXTextTable*>(xTable.get());
+
+ Reference < XCellRange > xCellRange( xTable, UNO_QUERY );
+ Reference < XCell > xCell = xCellRange->getCellByPosition( 0, 0 );
+ Reference < XText> xText( xCell, UNO_QUERY );
+ m_xOldCursor = GetImport().GetTextImport()->GetCursor();
+ GetImport().GetTextImport()->SetCursor( xText->createTextCursor() );
+
+ // take care of open redlines for tables
+ GetImport().GetTextImport()->RedlineAdjustStartNodeCursor();
+ }
+ if( !pXTable )
+ return;
+
+ SwFrameFormat *const pTableFrameFormat = pXTable->GetFrameFormat();
+ OSL_ENSURE( pTableFrameFormat, "table format missing" );
+ SwTable *pTable = SwTable::FindTable( pTableFrameFormat );
+ OSL_ENSURE( pTable, "table missing" );
+ m_pTableNode = pTable->GetTableNode();
+ OSL_ENSURE( m_pTableNode, "table node missing" );
+
+ SwTableLine *pLine1 = m_pTableNode->GetTable().GetTabLines()[0U];
+ m_pBox1 = pLine1->GetTabBoxes()[0U];
+ m_pSttNd1 = m_pBox1->GetSttNd();
+}
+
+SwXMLTableContext::SwXMLTableContext( SwXMLImport& rImport,
+ SwXMLTableContext *pTable ) :
+ XMLTextTableContext( rImport ),
+ m_pRows( new SwXMLTableRows_Impl ),
+ m_pTableNode( pTable->m_pTableNode ),
+ m_pBox1( nullptr ),
+ m_bOwnsBox1( false ),
+ m_pSttNd1( nullptr ),
+ m_pBoxFormat( nullptr ),
+ m_pLineFormat( nullptr ),
+ m_xParentTable( pTable ),
+ m_bFirstSection( false ),
+ m_bRelWidth( true ),
+ m_bHasSubTables( false ),
+ m_nHeaderRows( 0 ),
+ m_nCurRow( 0 ),
+ m_nCurCol( 0 ),
+ m_nNonMergedCurCol( 0 ),
+ m_nWidth( 0 )
+{
+}
+
+SwXMLTableContext::~SwXMLTableContext()
+{
+ if (m_bOwnsBox1)
+ delete m_pBox1;
+ m_xColumnDefaultCellStyleNames.reset();
+ m_pSharedBoxFormats.reset();
+ m_pRows.reset();
+
+ // close redlines on table end nodes
+ GetImport().GetTextImport()->RedlineAdjustStartNodeCursor();
+}
+
+css::uno::Reference<css::xml::sax::XFastContextHandler> SwXMLTableContext::createFastChildContext(
+ sal_Int32 nElement,
+ const Reference< xml::sax::XFastAttributeList > & xAttrList )
+{
+ bool bHeader = false;
+ switch (nElement)
+ {
+ case XML_ELEMENT(TABLE, XML_TABLE_ROW):
+ case XML_ELEMENT(LO_EXT, XML_TABLE_ROW):
+ if( IsInsertRowPossible() )
+ return new SwXMLTableRowContext_Impl( GetSwImport(), nElement, xAttrList, this );
+ break;
+ case XML_ELEMENT(TABLE, XML_TABLE_HEADER_ROWS):
+ bHeader = true;
+ [[fallthrough]];
+ case XML_ELEMENT(TABLE, XML_TABLE_ROWS):
+ return new SwXMLTableRowsContext_Impl( GetSwImport(), this, bHeader );
+ case XML_ELEMENT(TABLE, XML_TABLE_HEADER_COLUMNS):
+ case XML_ELEMENT(TABLE, XML_TABLE_COLUMNS):
+ // There are slight differences between <table:table-columns> and
+ // <table:table-columns-groups>. However, none of these are
+ // supported in Writer (they are Calc-only features), so we
+ // support column groups by simply using the <table:table-columns>
+ // token for column groups, too.
+ case XML_ELEMENT(TABLE, XML_TABLE_COLUMN_GROUP):
+ if( IsValid() )
+ return new SwXMLTableColsContext_Impl( GetSwImport(), this );
+ break;
+ case XML_ELEMENT(TABLE, XML_TABLE_COLUMN):
+ case XML_ELEMENT(LO_EXT, XML_TABLE_COLUMN):
+ if( IsValid() && IsInsertColPossible() )
+ return new SwXMLTableColContext_Impl( GetSwImport(), xAttrList,
+ this );
+ break;
+ case XML_ELEMENT(OFFICE, XML_DDE_SOURCE):
+ // save context for later processing (discard old context, if approp.)
+ if( IsValid() )
+ {
+ m_xDDESource.set(new SwXMLDDETableContext_Impl( GetSwImport() ));
+ return m_xDDESource;
+ }
+ break;
+ }
+ return nullptr;
+}
+
+void SwXMLTableContext::InsertColumn( sal_Int32 nWidth2, bool bRelWidth2,
+ const OUString *pDfltCellStyleName )
+{
+ OSL_ENSURE( m_nCurCol < USHRT_MAX,
+ "SwXMLTableContext::InsertColumn: no space left" );
+ if( m_nCurCol >= USHRT_MAX )
+ return;
+
+ if( nWidth2 < MINLAY )
+ nWidth2 = MINLAY;
+ else if( nWidth2 > MAX_WIDTH )
+ nWidth2 = MAX_WIDTH;
+ m_aColumnWidths.emplace_back(nWidth2, bRelWidth2 );
+ if( !((pDfltCellStyleName && !pDfltCellStyleName->isEmpty()) ||
+ m_xColumnDefaultCellStyleNames) )
+ return;
+
+ if( !m_xColumnDefaultCellStyleNames )
+ {
+ m_xColumnDefaultCellStyleNames.emplace();
+ sal_uLong nCount = m_aColumnWidths.size() - 1;
+ while( nCount-- )
+ m_xColumnDefaultCellStyleNames->push_back(OUString());
+ }
+
+ if(pDfltCellStyleName)
+ m_xColumnDefaultCellStyleNames->push_back(*pDfltCellStyleName);
+ else
+ m_xColumnDefaultCellStyleNames->push_back(OUString());
+}
+
+sal_Int32 SwXMLTableContext::GetColumnWidth( sal_uInt32 nCol,
+ sal_uInt32 nColSpan ) const
+{
+ sal_uInt32 nLast = nCol+nColSpan;
+ if( nLast > m_aColumnWidths.size() )
+ nLast = m_aColumnWidths.size();
+
+ sal_Int32 nWidth2 = 0;
+ for( sal_uInt32 i=nCol; i < nLast; ++i )
+ nWidth2 += m_aColumnWidths[i].width;
+
+ return nWidth2;
+}
+
+OUString SwXMLTableContext::GetColumnDefaultCellStyleName( sal_uInt32 nCol ) const
+{
+ if( m_xColumnDefaultCellStyleNames && nCol < m_xColumnDefaultCellStyleNames->size())
+ return (*m_xColumnDefaultCellStyleNames)[static_cast<size_t>(nCol)];
+
+ return OUString();
+}
+
+void SwXMLTableContext::InsertCell( const OUString& rStyleName,
+ sal_uInt32 nRowSpan, sal_uInt32 nColSpan,
+ const SwStartNode *pStartNode,
+ SwXMLTableContext *pTable,
+ bool bProtect,
+ const OUString* pFormula,
+ bool bHasValue,
+ double fValue,
+ OUString const*const pStringValue )
+{
+ OSL_ENSURE( m_nCurCol < GetColumnCount(),
+ "SwXMLTableContext::InsertCell: row is full" );
+ OSL_ENSURE( m_nCurRow < USHRT_MAX,
+ "SwXMLTableContext::InsertCell: table is full" );
+ if( m_nCurCol >= USHRT_MAX || m_nCurRow > USHRT_MAX )
+ return;
+
+ OSL_ENSURE( nRowSpan >=1, "SwXMLTableContext::InsertCell: row span is 0" );
+ if( 0 == nRowSpan )
+ nRowSpan = 1;
+ OSL_ENSURE( nColSpan >=1, "SwXMLTableContext::InsertCell: col span is 0" );
+ if( 0 == nColSpan )
+ nColSpan = 1;
+
+ // Until it is possible to add columns here, fix the column span.
+ sal_uInt32 nColsReq = m_nCurCol + nColSpan;
+ if( nColsReq > GetColumnCount() )
+ {
+ nColSpan = GetColumnCount() - m_nCurCol;
+ nColsReq = GetColumnCount();
+ }
+
+ // Check whether there are cells from a previous line already that reach
+ // into the current row.
+ if( m_nCurRow > 0 && nColSpan > 1 )
+ {
+ SwXMLTableRow_Impl *pCurRow = (*m_pRows)[m_nCurRow].get();
+ sal_uInt32 nLastCol = GetColumnCount() < nColsReq ? GetColumnCount()
+ : nColsReq;
+ for( sal_uInt32 i=m_nCurCol+1; i<nLastCol; ++i )
+ {
+ if( pCurRow->GetCell(i)->IsUsed() )
+ {
+ // If this cell is used, the column span is truncated
+ nColSpan = i - m_nCurCol;
+ nColsReq = i;
+ break;
+ }
+ }
+ }
+
+ sal_uInt32 nRowsReq = m_nCurRow + nRowSpan;
+ if( nRowsReq > USHRT_MAX )
+ {
+ nRowSpan = USHRT_MAX - m_nCurRow;
+ nRowsReq = USHRT_MAX;
+ }
+
+ // Add columns (if # required columns greater than # columns):
+ // This should never happen, since we require column definitions!
+ if ( nColsReq > GetColumnCount() )
+ {
+ for( sal_uInt32 i=GetColumnCount(); i<nColsReq; ++i )
+ {
+ m_aColumnWidths.emplace_back(MINLAY, true );
+ }
+ // adjust columns in *all* rows, if columns must be inserted
+ for (size_t i = 0; i < m_pRows->size(); ++i)
+ (*m_pRows)[i]->Expand( nColsReq, i<m_nCurRow );
+ }
+
+ // Add rows
+ if (m_pRows->size() < nRowsReq)
+ {
+ for (size_t i = m_pRows->size(); i < nRowsReq; ++i)
+ m_pRows->push_back(std::make_unique<SwXMLTableRow_Impl>(
+ "", GetColumnCount()));
+ }
+
+ OUString sStyleName( rStyleName );
+ if( sStyleName.isEmpty() )
+ {
+ sStyleName = (*m_pRows)[m_nCurRow]->GetDefaultCellStyleName();
+ if( sStyleName.isEmpty() && m_xColumnDefaultCellStyleNames )
+ {
+ sStyleName = GetColumnDefaultCellStyleName( m_nCurCol );
+ if( sStyleName.isEmpty() )
+ sStyleName = m_aDfltCellStyleName;
+ }
+ }
+
+ // Fill the cells
+ for( sal_uInt32 i=nColSpan; i>0; --i )
+ {
+ for( sal_uInt32 j=nRowSpan; j>0; --j )
+ {
+ const bool bCovered = i != nColSpan || j != nRowSpan;
+ SwXMLTableCell_Impl *pCell = GetCell( nRowsReq-j, nColsReq-i );
+ if (!pCell)
+ throw css::lang::IndexOutOfBoundsException();
+ pCell->Set( sStyleName, j, i, pStartNode,
+ pTable, bProtect, pFormula, bHasValue, bCovered, fValue,
+ pStringValue );
+ }
+ }
+
+ // Set current col to the next (free) column
+ m_nCurCol = nColsReq;
+ m_nNonMergedCurCol = nColsReq;
+ while( m_nCurCol<GetColumnCount() && GetCell(m_nCurRow,m_nCurCol)->IsUsed() )
+ m_nCurCol++;
+}
+
+void SwXMLTableContext::InsertCoveredCell(const OUString& rStyleName)
+{
+ const IDocumentSettingAccess& rIDSA = GetSwImport().getDoc()->getIDocumentSettingAccess();
+ bool bWordTableCell = rIDSA.get(DocumentSettingId::TABLE_ROW_KEEP);
+ if (!bWordTableCell)
+ {
+ // Compatibility flag not active, ignore formatting of covered cells.
+ return;
+ }
+
+ SwXMLTableCell_Impl* pCell = GetCell(m_nCurRow, m_nNonMergedCurCol);
+ ++m_nNonMergedCurCol;
+ if (!pCell)
+ {
+ return;
+ }
+
+ pCell->SetStyleName(rStyleName);
+}
+
+void SwXMLTableContext::InsertRow( const OUString& rStyleName,
+ const OUString& rDfltCellStyleName,
+ bool bInHead )
+{
+ OSL_ENSURE( m_nCurRow < USHRT_MAX,
+ "SwXMLTableContext::InsertRow: no space left" );
+ if( m_nCurRow >= USHRT_MAX )
+ return;
+
+ // Make sure there is at least one column.
+ if( 0==m_nCurRow && 0 == GetColumnCount() )
+ InsertColumn( USHRT_MAX, true );
+
+ if (m_nCurRow < m_pRows->size())
+ {
+ // The current row has already been inserted because of a row span
+ // of a previous row.
+ (*m_pRows)[m_nCurRow]->Set(
+ rStyleName, rDfltCellStyleName );
+ }
+ else
+ {
+ // add a new row
+ m_pRows->push_back(std::make_unique<SwXMLTableRow_Impl>(
+ rStyleName, GetColumnCount(),
+ &rDfltCellStyleName));
+ }
+
+ // We start at the first column ...
+ m_nCurCol=0;
+ m_nNonMergedCurCol = 0;
+
+ // ... but this cell may be occupied already.
+ while( m_nCurCol<GetColumnCount() && GetCell(m_nCurRow,m_nCurCol)->IsUsed() )
+ m_nCurCol++;
+
+ if( bInHead && m_nHeaderRows == m_nCurRow )
+ m_nHeaderRows++;
+}
+
+void SwXMLTableContext::InsertRepRows( sal_uInt32 nCount )
+{
+ const SwXMLTableRow_Impl *pSrcRow = (*m_pRows)[m_nCurRow-1].get();
+ while( nCount > 1 && IsInsertRowPossible() )
+ {
+ InsertRow( pSrcRow->GetStyleName(), pSrcRow->GetDefaultCellStyleName(),
+ false );
+ while( m_nCurCol < GetColumnCount() )
+ {
+ if( !GetCell(m_nCurRow,m_nCurCol)->IsUsed() )
+ {
+ const SwXMLTableCell_Impl *pSrcCell =
+ GetCell( m_nCurRow-1, m_nCurCol );
+ InsertCell( pSrcCell->GetStyleName(), 1U,
+ pSrcCell->GetColSpan(),
+ InsertTableSection(),
+ nullptr, pSrcCell->IsProtected(),
+ &pSrcCell->GetFormula(),
+ pSrcCell->HasValue(), pSrcCell->GetValue(),
+ pSrcCell->GetStringValue() );
+ }
+ }
+ FinishRow();
+ nCount--;
+ }
+}
+
+void SwXMLTableContext::FinishRow()
+{
+ // Insert an empty cell at the end of the line if the row is not complete
+ if( m_nCurCol < GetColumnCount() )
+ {
+ InsertCell( "", 1U, GetColumnCount() - m_nCurCol,
+ InsertTableSection() );
+ }
+
+ // Move to the next row.
+ m_nCurRow++;
+}
+
+const SwStartNode *SwXMLTableContext::GetPrevStartNode( sal_uInt32 nRow,
+ sal_uInt32 nCol ) const
+{
+ const SwXMLTableCell_Impl *pPrevCell = nullptr;
+ if( GetColumnCount() == nCol )
+ {
+ // The last cell is the right one here.
+ pPrevCell = GetCell( m_pRows->size() - 1U, GetColumnCount() - 1 );
+ }
+ else if( nCol > 0 )
+ {
+ // The previous cell in this row.
+ pPrevCell = GetCell( nRow, nCol-1 );
+ }
+ else if( nRow > 0 )
+ {
+ // The last cell from the previous row.
+ pPrevCell = GetCell( nRow-1, GetColumnCount()-1 );
+ }
+
+ const SwStartNode *pSttNd = nullptr;
+ if( pPrevCell )
+ {
+ if( pPrevCell->GetStartNode() )
+ pSttNd = pPrevCell->GetStartNode();
+ // #i95726# - Some fault tolerance
+// else
+ else if ( pPrevCell->GetSubTable() )
+ pSttNd = pPrevCell->GetSubTable()->GetLastStartNode();
+
+ OSL_ENSURE( pSttNd != nullptr,
+ "table corrupt" );
+ }
+
+ return pSttNd;
+}
+
+void SwXMLTableContext::FixRowSpan( sal_uInt32 nRow, sal_uInt32 nCol,
+ sal_uInt32 nColSpan )
+{
+ sal_uInt32 nLastCol = nCol + nColSpan;
+ for( sal_uInt32 i = nCol; i < nLastCol; i++ )
+ {
+ sal_uInt32 j = nRow;
+ sal_uInt32 nRowSpan = 1;
+ SwXMLTableCell_Impl *pCell = GetCell( j, i );
+ while( pCell && pCell->GetRowSpan() > 1 )
+ {
+ pCell->SetRowSpan( nRowSpan++ );
+ pCell = j > 0 ? GetCell( --j, i ) : nullptr;
+ }
+ }
+}
+
+void SwXMLTableContext::ReplaceWithEmptyCell( sal_uInt32 nRow, sal_uInt32 nCol, bool bRows )
+{
+ const SwStartNode *pPrevSttNd = GetPrevStartNode( nRow, nCol );
+ const SwStartNode *pSttNd = InsertTableSection( pPrevSttNd );
+
+ const SwXMLTableCell_Impl *pCell = GetCell( nRow, nCol );
+ sal_uInt32 nLastRow = bRows ? nRow + pCell->GetRowSpan() : nRow + 1;
+ sal_uInt32 nLastCol = nCol + pCell->GetColSpan();
+
+ for( sal_uInt32 i=nRow; i<nLastRow; i++ )
+ {
+ SwXMLTableRow_Impl *pRow = (*m_pRows)[i].get();
+ for( sal_uInt32 j=nCol; j<nLastCol; j++ )
+ pRow->GetCell( j )->SetStartNode( pSttNd );
+ }
+
+}
+
+SwTableBox *SwXMLTableContext::NewTableBox( const SwStartNode *pStNd,
+ SwTableLine *pUpper )
+{
+ // The topmost table is the only table that maintains the two members
+ // pBox1 and bFirstSection.
+ if( m_xParentTable.is() )
+ return m_xParentTable->NewTableBox( pStNd, pUpper );
+
+ SwTableBox *pBox;
+
+ if( m_pBox1 &&
+ m_pBox1->GetSttNd() == pStNd )
+ {
+ // if the StartNode is equal to the StartNode of the initially
+ // created box, we use this box
+ pBox = m_pBox1;
+ pBox->SetUpper( pUpper );
+ m_pBox1 = nullptr;
+ m_bOwnsBox1 = false;
+ }
+ else
+ pBox = new SwTableBox( m_pBoxFormat, *pStNd, pUpper );
+
+ return pBox;
+}
+
+SwTableBoxFormat* SwXMLTableContext::GetSharedBoxFormat(
+ SwTableBox* pBox,
+ const OUString& rStyleName,
+ sal_Int32 nColumnWidth,
+ bool bProtected,
+ bool bMayShare,
+ bool& bNew,
+ bool* pModifyLocked )
+{
+ if ( m_pSharedBoxFormats == nullptr )
+ m_pSharedBoxFormats.reset(new map_BoxFormat);
+
+ SwTableBoxFormat* pBoxFormat2;
+
+ TableBoxIndex aKey( rStyleName, nColumnWidth, bProtected );
+ map_BoxFormat::iterator aIter = m_pSharedBoxFormats->find( aKey );
+ if ( aIter == m_pSharedBoxFormats->end() )
+ {
+ // unknown format so far -> construct a new one
+
+ // get the old format, and reset all attributes
+ // (but preserve FillOrder)
+ pBoxFormat2 = static_cast<SwTableBoxFormat*>(pBox->ClaimFrameFormat());
+ SwFormatFillOrder aFillOrder( pBoxFormat2->GetFillOrder() );
+ pBoxFormat2->ResetAllFormatAttr(); // #i73790# - method renamed
+ pBoxFormat2->SetFormatAttr( aFillOrder );
+ bNew = true; // it's a new format now
+
+ // share this format, if allowed
+ if ( bMayShare )
+ (*m_pSharedBoxFormats)[ aKey ] = pBoxFormat2;
+ }
+ else
+ {
+ // set the shared format
+ pBoxFormat2 = aIter->second;
+ pBox->ChgFrameFormat( pBoxFormat2, /*bNeedToReregister*/false );
+ bNew = false; // copied from an existing format
+
+ // claim it, if we are not allowed to share
+ if ( !bMayShare )
+ pBoxFormat2 = static_cast<SwTableBoxFormat*>(pBox->ClaimFrameFormat());
+ }
+
+ // lock format (if so desired)
+ if ( pModifyLocked != nullptr )
+ {
+ (*pModifyLocked) = pBoxFormat2->IsModifyLocked();
+ pBoxFormat2->LockModify();
+ }
+
+ return pBoxFormat2;
+}
+
+SwTableBox *SwXMLTableContext::MakeTableBox( SwTableLine *pUpper,
+ sal_uInt32 nTopRow,
+ sal_uInt32 nLeftCol,
+ sal_uInt32 nBottomRow,
+ sal_uInt32 nRightCol )
+{
+ //FIXME: here would be a great place to handle XmlId for cell
+ SwTableBox *pBox = new SwTableBox( m_pBoxFormat, 0, pUpper );
+
+ sal_uInt32 nColSpan = nRightCol - nLeftCol;
+ sal_Int32 nColWidth = GetColumnWidth( nLeftCol, nColSpan );
+
+ // TODO: Share formats!
+ SwFrameFormat *pFrameFormat = pBox->ClaimFrameFormat();
+ SwFormatFillOrder aFillOrder( pFrameFormat->GetFillOrder() );
+ pFrameFormat->ResetAllFormatAttr(); // #i73790# - method renamed
+ pFrameFormat->SetFormatAttr( aFillOrder );
+
+ pFrameFormat->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable, nColWidth ) );
+
+ SwTableLines& rLines = pBox->GetTabLines();
+ bool bSplitted = false;
+
+ while( !bSplitted )
+ {
+ sal_uInt32 nStartRow = nTopRow;
+ sal_uInt32 i;
+
+ for( i = nTopRow; i < nBottomRow; i++ )
+ {
+ // Could the table be split behind the current row?
+ bool bSplit = true;
+ SwXMLTableRow_Impl *pRow = (*m_pRows)[i].get();
+ for( sal_uInt32 j=nLeftCol; j<nRightCol; j++ )
+ {
+ bSplit = ( 1 == pRow->GetCell(j)->GetRowSpan() );
+ if( !bSplit )
+ break;
+ }
+ if( bSplit && (nStartRow>nTopRow || i+1<nBottomRow) )
+ {
+ SwTableLine *pLine =
+ MakeTableLine( pBox, nStartRow, nLeftCol, i+1,
+ nRightCol );
+
+ rLines.push_back( pLine );
+
+ nStartRow = i+1;
+ bSplitted = true;
+ }
+ }
+ if( !bSplitted )
+ {
+ // No splitting was possible. That for, we have to force it.
+ // Ruthless!
+
+ nStartRow = nTopRow;
+ while( nStartRow < nBottomRow )
+ {
+ sal_uInt32 nMaxRowSpan = 0;
+ SwXMLTableRow_Impl *pStartRow = (*m_pRows)[nStartRow].get();
+ const SwXMLTableCell_Impl *pCell;
+ for( i=nLeftCol; i<nRightCol; i++ )
+ {
+ pCell = pStartRow->GetCell(i);
+ if( pCell->GetRowSpan() > nMaxRowSpan )
+ nMaxRowSpan = pCell->GetRowSpan();
+ }
+
+ nStartRow += nMaxRowSpan;
+ if( nStartRow<nBottomRow )
+ {
+ SwXMLTableRow_Impl *pPrevRow = (*m_pRows)[nStartRow - 1U].get();
+ i = nLeftCol;
+ while( i < nRightCol )
+ {
+ if( pPrevRow->GetCell(i)->GetRowSpan() > 1 )
+ {
+ const SwXMLTableCell_Impl *pCell2 =
+ GetCell( nStartRow, i );
+ const sal_uInt32 nColSpan2 = pCell2->GetColSpan();
+ FixRowSpan( nStartRow-1, i, nColSpan2 );
+ ReplaceWithEmptyCell( nStartRow, i, true );
+ i += nColSpan2;
+ }
+ else
+ {
+ i++;
+ }
+ }
+ }
+ }
+ // and now start over again...
+ }
+ }
+
+ return pBox;
+}
+
+SwTableBox *SwXMLTableContext::MakeTableBox(
+ SwTableLine *pUpper, const SwXMLTableCell_Impl *pCell,
+ sal_uInt32 nLeftCol, sal_uInt32 nRightCol )
+{
+ //FIXME: here would be a great place to handle XmlId for cell
+ SwTableBox *pBox;
+ sal_uInt32 nColSpan = nRightCol - nLeftCol;
+ sal_Int32 nColWidth = GetColumnWidth( nLeftCol, nColSpan );
+
+ if( pCell->GetStartNode() )
+ {
+ pBox = NewTableBox( pCell->GetStartNode(), pUpper );
+ }
+ else
+ {
+ // and it is a table: therefore we build a new box and
+ // put the rows of the table into the rows of the box
+ pBox = new SwTableBox( m_pBoxFormat, 0, pUpper );
+ pCell->GetSubTable()->MakeTable( pBox, nColWidth );
+ }
+
+ // Share formats!
+ const OUString sStyleName = pCell->GetStyleName();
+ bool bModifyLocked;
+ bool bNew;
+ SwTableBoxFormat *pBoxFormat2 = GetSharedBoxFormat(
+ pBox, sStyleName, nColWidth, pCell->IsProtected(),
+ pCell->GetStartNode() && pCell->GetFormula().isEmpty() &&
+ ! pCell->HasValue(),
+ bNew, &bModifyLocked );
+
+ // if a new format was created, then we need to set the style
+ if ( bNew )
+ {
+ // set style
+ const SfxItemSet *pAutoItemSet = nullptr;
+ if( pCell->GetStartNode() && !sStyleName.isEmpty() &&
+ GetSwImport().FindAutomaticStyle(
+ XmlStyleFamily::TABLE_CELL, sStyleName, &pAutoItemSet ) )
+ {
+ if( pAutoItemSet )
+ pBoxFormat2->SetFormatAttr( *pAutoItemSet );
+ }
+ }
+
+ if( pCell->GetStartNode() )
+ {
+ if (pCell->HasStringValue())
+ {
+ SwNodeIndex const aNodeIndex(*(pCell->GetStartNode()), 1);
+ SwTextNode *const pTextNode(aNodeIndex.GetNode().GetTextNode());
+ SAL_WARN_IF(!pTextNode, "sw", "Should have a text node in cell?");
+ if (pTextNode)
+ {
+ SAL_WARN_IF(!pTextNode->GetText().isEmpty(), "sw",
+ "why text here?");
+ pTextNode->InsertText(*pCell->GetStringValue(),
+ SwContentIndex(pTextNode, 0));
+ }
+ }
+
+ // try to rescue broken documents with a certain pattern
+ // if: 1) the cell has a default number format (number 0)
+ // 2) the call has no formula
+ // 3) the value is 0.0
+ // 4) the text doesn't look anything like 0.0
+ // [read: length > 10, or length smaller 10 and no 0 in it]
+ // then make it a text cell!
+ bool bSuppressNumericContent = false;
+ if( pCell->HasValue() && (pCell->GetValue() == 0.0) &&
+ pCell->GetFormula().isEmpty() &&
+ !sStyleName.isEmpty() )
+ {
+ // default num format?
+ if( const SwTableBoxNumFormat* pNumFormat = pBoxFormat2->GetItemIfSet( RES_BOXATR_FORMAT, false ) )
+ {
+ if (pNumFormat && (pNumFormat->GetValue() % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
+ {
+ // only one text node?
+ SwNodeIndex aNodeIndex( *(pCell->GetStartNode()), 1 );
+ if( ( aNodeIndex.GetNode().EndOfSectionIndex() -
+ aNodeIndex.GetNode().StartOfSectionIndex() ) == SwNodeOffset(2) )
+ {
+ SwTextNode* pTextNode= aNodeIndex.GetNode().GetTextNode();
+ if( pTextNode != nullptr )
+ {
+ // check text: does it look like some form of 0.0?
+ const OUString& rText = pTextNode->GetText();
+ if( ( rText.getLength() > 10 ) ||
+ ( rText.indexOf( '0' ) == -1 ) )
+ {
+ bSuppressNumericContent = true;
+ }
+ }
+ }
+ else
+ bSuppressNumericContent = true; // several nodes
+ }
+ }
+ }
+
+ if( bSuppressNumericContent )
+ {
+ // suppress numeric content? Then reset number format!
+ pBoxFormat2->ResetFormatAttr( RES_BOXATR_FORMULA );
+ pBoxFormat2->ResetFormatAttr( RES_BOXATR_FORMAT );
+ pBoxFormat2->ResetFormatAttr( RES_BOXATR_VALUE );
+ }
+ else
+ {
+ // the normal case: set formula and value (if available)
+
+ const OUString& rFormula = pCell->GetFormula();
+ if (!rFormula.isEmpty())
+ {
+ // formula cell: insert formula if valid
+ SwTableBoxFormula aFormulaItem( rFormula );
+ pBoxFormat2->SetFormatAttr( aFormulaItem );
+ }
+ else if (!pCell->HasValue() && pCell->HasStringValue())
+ {
+ // Check for another inconsistency:
+ // No value but a non-textual format, i.e. a number format
+ // Solution: the number format will be removed,
+ // the cell gets the default text format.
+ if( const SwTableBoxNumFormat* pNumFormat = m_pBoxFormat->GetItemIfSet( RES_BOXATR_FORMAT, false ) )
+ {
+ const SwDoc* pDoc = m_pBoxFormat->GetDoc();
+ const SvNumberFormatter* pNumberFormatter = pDoc ?
+ pDoc->GetNumberFormatter() : nullptr;
+ if( pNumFormat != nullptr && pNumberFormatter &&
+ !pNumberFormatter->GetEntry( pNumFormat->GetValue() )->IsTextFormat() )
+ m_pBoxFormat->ResetFormatAttr( RES_BOXATR_FORMAT );
+ }
+ }
+ // always insert value, even if default
+ if( pCell->HasValue() )
+ {
+ SwTableBoxValue aValueItem( pCell->GetValue() );
+ pBoxFormat2->SetFormatAttr( aValueItem );
+ }
+ }
+
+ // update cell content depend on the default language
+ pBox->ActualiseValueBox();
+ }
+
+ // table cell protection
+ if( pCell->IsProtected() )
+ {
+ SvxProtectItem aProtectItem( RES_PROTECT );
+ aProtectItem.SetContentProtect( true );
+ pBoxFormat2->SetFormatAttr( aProtectItem );
+ }
+
+ // restore old modify-lock state
+ if (! bModifyLocked)
+ pBoxFormat2->UnlockModify();
+
+ pBoxFormat2->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable, nColWidth ) );
+
+ return pBox;
+}
+
+SwTableLine *SwXMLTableContext::MakeTableLine( SwTableBox *pUpper,
+ sal_uInt32 nTopRow,
+ sal_uInt32 nLeftCol,
+ sal_uInt32 nBottomRow,
+ sal_uInt32 nRightCol )
+{
+ //FIXME: here would be a great place to handle XmlId for row
+ SwTableLine *pLine;
+ if( !pUpper && 0UL==nTopRow )
+ {
+ pLine = m_pTableNode->GetTable().GetTabLines()[0U];
+ }
+ else
+ {
+ pLine = new SwTableLine( m_pLineFormat, 0, pUpper );
+ }
+
+ // TODO: Share formats!
+ SwFrameFormat *pFrameFormat = pLine->ClaimFrameFormat();
+ SwFormatFillOrder aFillOrder( pFrameFormat->GetFillOrder() );
+ pFrameFormat->ResetAllFormatAttr(); // #i73790# - method renamed
+ pFrameFormat->SetFormatAttr( aFillOrder );
+
+ const SfxItemSet *pAutoItemSet = nullptr;
+ const OUString& rStyleName = (*m_pRows)[nTopRow]->GetStyleName();
+ if( 1 == (nBottomRow - nTopRow) &&
+ !rStyleName.isEmpty() &&
+ GetSwImport().FindAutomaticStyle(
+ XmlStyleFamily::TABLE_ROW, rStyleName, &pAutoItemSet ) )
+ {
+ if( pAutoItemSet )
+ pFrameFormat->SetFormatAttr( *pAutoItemSet );
+ }
+
+ SwTableBoxes& rBoxes = pLine->GetTabBoxes();
+
+ sal_uInt32 nStartCol = nLeftCol;
+ while( nStartCol < nRightCol )
+ {
+ for( sal_uInt32 nRow=nTopRow; nRow<nBottomRow; nRow++ )
+ (*m_pRows)[nRow]->SetSplitable( true );
+
+ sal_uInt32 nCol = nStartCol;
+ sal_uInt32 nSplitCol = nRightCol;
+ bool bSplitted = false;
+ while( !bSplitted )
+ {
+ OSL_ENSURE( nCol < nRightCol, "Ran too far" );
+
+ // Can be split after current HTML table column?
+ // If yes, can the created region still be split to
+ // rows if the next column is added to it?
+ bool bSplit = true;
+ bool bHoriSplitMayContinue = false;
+ bool bHoriSplitPossible = false;
+
+ if ( m_bHasSubTables )
+ {
+ // Convert row spans if the table has subtables:
+ for( sal_uInt32 nRow=nTopRow; nRow<nBottomRow; nRow++ )
+ {
+ SwXMLTableCell_Impl *pCell = GetCell(nRow,nCol);
+ // Could the table fragment be split horizontally behind
+ // the current line?
+ bool bHoriSplit = (*m_pRows)[nRow]->IsSplitable() &&
+ nRow+1 < nBottomRow &&
+ 1 == pCell->GetRowSpan();
+ (*m_pRows)[nRow]->SetSplitable( bHoriSplit );
+
+ // Could the table fragment be split vertically behind the
+ // current column (uptp the current line?
+ bSplit &= ( 1 == pCell->GetColSpan() );
+ if( bSplit )
+ {
+ bHoriSplitPossible |= bHoriSplit;
+
+ // Could the current table fragment be split
+ // horizontally behind the next column, too?
+ bHoriSplit &= (nCol+1 < nRightCol &&
+ 1 == GetCell(nRow,nCol+1)->GetRowSpan());
+ bHoriSplitMayContinue |= bHoriSplit;
+ }
+ }
+ }
+ else
+ {
+ // No subtables: we use the new table model.
+ SwXMLTableCell_Impl *pCell = GetCell(nTopRow,nCol);
+
+ // #i95726# - some fault tolerance
+ if ( pCell == nullptr )
+ {
+ OSL_FAIL( "table seems to be corrupt." );
+ break;
+ }
+
+ // Could the table fragment be split vertically behind the
+ // current column (uptp the current line?
+ bSplit = 1 == pCell->GetColSpan();
+ }
+
+#if OSL_DEBUG_LEVEL > 0
+ if( nCol == nRightCol-1 )
+ {
+ OSL_ENSURE( bSplit, "Split-Flag wrong" );
+ if ( m_bHasSubTables )
+ {
+ OSL_ENSURE( !bHoriSplitMayContinue,
+ "HoriSplitMayContinue-Flag wrong" );
+ SwXMLTableCell_Impl *pTmpCell = GetCell( nTopRow, nStartCol );
+ OSL_ENSURE( pTmpCell->GetRowSpan() != (nBottomRow-nTopRow) ||
+ !bHoriSplitPossible, "HoriSplitPossible-Flag wrong" );
+ }
+ }
+#endif
+
+ OSL_ENSURE( !m_bHasSubTables || !bHoriSplitMayContinue || bHoriSplitPossible,
+ "bHoriSplitMayContinue, but not bHoriSplitPossible" );
+
+ if( bSplit )
+ {
+ SwTableBox* pBox = nullptr;
+ SwXMLTableCell_Impl *pCell = GetCell( nTopRow, nStartCol );
+ // #i95726# - some fault tolerance
+ if( ( !m_bHasSubTables || ( pCell->GetRowSpan() == (nBottomRow-nTopRow) ) ) &&
+ pCell->GetColSpan() == (nCol+1-nStartCol) &&
+ ( pCell->GetStartNode() || pCell->GetSubTable() ) )
+ {
+ // insert new empty cell for covered cells:
+ sal_Int32 nBoxRowSpan = 1;
+ if ( !m_bHasSubTables )
+ {
+ nBoxRowSpan = pCell->GetRowSpan();
+ if ( pCell->IsCovered() )
+ {
+ nBoxRowSpan = -1 * nBoxRowSpan;
+ ReplaceWithEmptyCell( nTopRow, nStartCol, false );
+ }
+ }
+
+ // The remaining box neither contains lines nor rows (i.e.
+ // is a content box
+ nSplitCol = nCol + 1;
+
+ pBox = MakeTableBox( pLine, pCell, nStartCol, nSplitCol );
+
+ if ( 1 != nBoxRowSpan )
+ pBox->setRowSpan( nBoxRowSpan );
+
+ bSplitted = true;
+ }
+ else if( m_bHasSubTables && bHoriSplitPossible && bHoriSplitMayContinue )
+ {
+ // The table fragment could be split behind the current
+ // column, and the remaining fragment could be divided
+ // into lines. Anyway, it could be that this applies to
+ // the next column, too. That for, we check the next
+ // column but remember the current one as a good place to
+ // split.
+ nSplitCol = nCol + 1;
+ }
+ else if ( m_bHasSubTables )
+ {
+ // If the table resulting table fragment could be divided
+ // into lines if splitting behind the current column, but
+ // this doesn't apply for thr next column, we split begind
+ // the current column. This applies for the last column,
+ // too.
+ // If the resulting box cannot be split into rows,
+ // the split at the last split position we remembered.
+ if( bHoriSplitPossible || nSplitCol > nCol+1 )
+ {
+ OSL_ENSURE( !bHoriSplitMayContinue,
+ "bHoriSplitMayContinue==true" );
+ OSL_ENSURE( bHoriSplitPossible || nSplitCol == nRightCol,
+ "bHoriSplitPossible flag should be set" );
+
+ nSplitCol = nCol + 1;
+ }
+
+ pBox = MakeTableBox( pLine, nTopRow, nStartCol,
+ nBottomRow, nSplitCol );
+ bSplitted = true;
+ }
+
+ OSL_ENSURE( m_bHasSubTables || pBox, "Colspan trouble" );
+
+ if( pBox )
+ rBoxes.push_back( pBox );
+ }
+ nCol++;
+ }
+ nStartCol = nSplitCol;
+ }
+
+ return pLine;
+}
+
+void SwXMLTableContext::MakeTable_( SwTableBox *pBox )
+{
+ // fix column widths
+ sal_uInt32 nCols = GetColumnCount();
+
+ // If there are empty rows (because of some row span of previous rows)
+ // the have to be deleted. The previous rows have to be truncated.
+
+ if (m_pRows->size() > m_nCurRow)
+ {
+ SwXMLTableRow_Impl *pPrevRow = (*m_pRows)[m_nCurRow - 1U].get();
+ const SwXMLTableCell_Impl *pCell;
+ for( size_t i = 0; i < m_aColumnWidths.size(); ++i )
+ {
+ pCell = pPrevRow->GetCell(i);
+ if( pCell->GetRowSpan() > 1 )
+ {
+ FixRowSpan( m_nCurRow-1, i, 1UL );
+ }
+ }
+ for (size_t i = m_pRows->size() - 1; i >= m_nCurRow; --i)
+ m_pRows->pop_back();
+ }
+
+ if (m_pRows->empty())
+ {
+ InsertCell( "", 1U, nCols, InsertTableSection() );
+ }
+
+ // TODO: Do we have to keep both values, the relative and the absolute
+ // width?
+ sal_Int32 nAbsWidth = 0;
+ sal_Int32 nMinAbsColWidth = 0;
+ sal_Int32 nRelWidth = 0;
+ sal_Int32 nMinRelColWidth = 0;
+ sal_uInt32 nRelCols = 0;
+ for( const auto& rCol : m_aColumnWidths)
+ {
+ if( rCol.isRelative )
+ {
+ nRelWidth += rCol.width;
+ if( 0 == nMinRelColWidth || rCol.width < nMinRelColWidth )
+ nMinRelColWidth = rCol.width;
+ nRelCols++;
+ }
+ else
+ {
+ nAbsWidth += rCol.width;
+ if( 0 == nMinAbsColWidth || rCol.width < nMinAbsColWidth )
+ nMinAbsColWidth = rCol.width;
+ }
+ }
+ sal_uInt32 nAbsCols = nCols - nRelCols;
+
+ if( m_bRelWidth )
+ {
+ // If there a columns that have an absolute width, we have to
+ // calculate a relative one for them.
+ if( nAbsCols > 0 )
+ {
+ // All column that have absolute widths get relative widths;
+ // these widths relate to each over like the original absolute
+ // widths. The smallest column gets a width that has the same
+ // value as the smallest column that has a relative width
+ // already.
+ if( 0 == nMinRelColWidth )
+ nMinRelColWidth = nMinAbsColWidth;
+
+ for( auto& rCol : m_aColumnWidths)
+ {
+ if( !rCol.isRelative )
+ {
+ if (nMinAbsColWidth == 0)
+ throw o3tl::divide_by_zero();
+ sal_Int32 nVal;
+ if (o3tl::checked_multiply<sal_Int32>(rCol.width, nMinRelColWidth, nVal))
+ throw std::overflow_error("overflow in multiply");
+ sal_Int32 nRelCol = nVal / nMinAbsColWidth;
+ rCol.width = nRelCol;
+ rCol.isRelative = true;
+ nRelWidth += nRelCol;
+ nAbsCols--;
+ if (nAbsCols <= 0)
+ break;
+ }
+ }
+ }
+
+ if( !m_nWidth )
+ {
+ // This happens only for percentage values for the table itself.
+ // In this case, the columns get the correct width even if
+ // the sum of the relative widths is smaller than the available
+ // width in TWIP. Therefore, we can use the relative width.
+ m_nWidth = std::min(nRelWidth, MAX_WIDTH);
+ }
+ if( nRelWidth != m_nWidth && nRelWidth && nCols )
+ {
+ double n = static_cast<double>(m_nWidth) / static_cast<double>(nRelWidth);
+ nRelWidth = 0;
+ for( auto colIter = m_aColumnWidths.begin(); colIter != (m_aColumnWidths.end() - 1); ++colIter)
+ {
+ sal_Int32 nW = static_cast<sal_Int32>( colIter->width * n);
+ colIter->width = o3tl::narrowing<sal_uInt16>(nW);
+ nRelWidth += nW;
+ }
+ m_aColumnWidths.back().width = (m_nWidth-nRelWidth);
+ }
+ }
+ else
+ {
+ // If there are columns that have relative widths, we have to
+ // calculate an absolute widths for them.
+ if( nRelCols > 0 )
+ {
+ // The absolute space that is available for all columns with a
+ // relative width.
+ sal_Int32 nAbsForRelWidth =
+ m_nWidth > nAbsWidth ? m_nWidth - nAbsWidth : sal_Int32(0L);
+
+ // The relative width that has to be distributed in addition to
+ // equally widthed columns.
+ sal_Int32 nExtraRel = nRelWidth - (nRelCols * nMinRelColWidth);
+
+ // The absolute space that may be distributed in addition to
+ // minimum widthed columns.
+ sal_Int32 nMinAbs = nRelCols * MINLAY;
+ sal_Int32 nExtraAbs =
+ nAbsForRelWidth > nMinAbs ? nAbsForRelWidth - nMinAbs : sal_Int32(0L);
+
+ bool bMin = false; // Do all columns get the minimum width?
+ bool bMinExtra = false; // Do all columns get the minimum width plus
+ // some extra space?
+
+ if( nAbsForRelWidth <= nMinAbs )
+ {
+ // If there is not enough space left for all columns to
+ // get the minimum width, they get the minimum width, anyway.
+ nAbsForRelWidth = nMinAbs;
+ bMin = true;
+ }
+ else if( nAbsForRelWidth <= (nRelWidth * MINLAY) /
+ nMinRelColWidth )
+ {
+ // If there is enough space for all columns to get the
+ // minimum width, but not to get a width that takes the
+ // relative width into account, each column gets the minimum
+ // width plus some extra space that is based on the additional
+ // space that is available.
+ bMinExtra = true;
+ }
+ // Otherwise, if there is enough space for every column, every
+ // column gets this space.
+
+ for( auto& rCol : m_aColumnWidths )
+ {
+ if( rCol.isRelative )
+ {
+ sal_Int32 nAbsCol;
+ if( 1 == nRelCols )
+ {
+ // The last column that has a relative width gets
+ // all absolute space that is left.
+ nAbsCol = nAbsForRelWidth;
+ }
+ else
+ {
+ if( bMin )
+ {
+ nAbsCol = MINLAY;
+ }
+ else if( bMinExtra )
+ {
+ sal_Int32 nExtraRelCol = rCol.width - nMinRelColWidth;
+ nAbsCol = MINLAY + (nExtraRelCol * nExtraAbs) /
+ nExtraRel;
+ }
+ else
+ {
+ nAbsCol = ( rCol.width * nAbsForRelWidth) / nRelWidth;
+ }
+ }
+ rCol.width = nAbsCol;
+ rCol.isRelative = false;
+ nAbsForRelWidth -= nAbsCol;
+ nAbsWidth += nAbsCol;
+ nRelCols--;
+ if (nRelCols <= 0)
+ break;
+ }
+ }
+ }
+
+ if( nCols && nAbsWidth )
+ {
+ if( nAbsWidth < m_nWidth )
+ {
+ // If the table's width is larger than the sum of the absolute
+ // column widths, every column get some extra width.
+ sal_Int32 nExtraAbs = m_nWidth - nAbsWidth;
+ sal_Int32 nAbsLastCol = m_aColumnWidths.back().width + nExtraAbs;
+ for( auto colIter = m_aColumnWidths.begin(); colIter != (m_aColumnWidths.end() - 1); ++colIter )
+ {
+ sal_Int32 nAbsCol = colIter->width;
+ sal_Int32 nExtraAbsCol = (nAbsCol * nExtraAbs) /
+ nAbsWidth;
+ nAbsCol += nExtraAbsCol;
+ colIter->width = nAbsCol;
+ nAbsLastCol -= nExtraAbsCol;
+ }
+ m_aColumnWidths.back().width = nAbsLastCol;
+ }
+ else if( nAbsWidth > m_nWidth )
+ {
+ // If the table's width is smaller than the sum of the absolute
+ // column widths, every column needs to shrink.
+ // Every column gets the minimum width plus some extra width.
+ sal_Int32 nExtraAbs = m_nWidth - (nCols * MINLAY);
+ sal_Int32 nAbsLastCol = MINLAY + nExtraAbs;
+ for( auto colIter = m_aColumnWidths.begin(); colIter != (m_aColumnWidths.end() - 1); ++colIter )
+ {
+ sal_Int32 nAbsCol = colIter->width;
+ sal_Int32 nExtraAbsCol = (nAbsCol * nExtraAbs) /
+ nAbsWidth;
+ nAbsCol = MINLAY + nExtraAbsCol;
+ colIter->width = nAbsCol;
+ nAbsLastCol -= nExtraAbsCol;
+ }
+ m_aColumnWidths.back().width = nAbsLastCol;
+ }
+ }
+ }
+
+ SwTableLines& rLines =
+ pBox ? pBox->GetTabLines()
+ : m_pTableNode->GetTable().GetTabLines();
+
+ sal_uInt32 nStartRow = 0;
+ sal_uInt32 nRows = m_pRows->size();
+ for(sal_uInt32 i=0; i<nRows; ++i )
+ {
+ // Could we split the table behind the current line?
+ bool bSplit = true;
+ if ( m_bHasSubTables )
+ {
+ SwXMLTableRow_Impl *pRow = (*m_pRows)[i].get();
+ for( sal_uInt32 j=0; j<nCols; j++ )
+ {
+ bSplit = ( 1 == pRow->GetCell(j)->GetRowSpan() );
+ if( !bSplit )
+ break;
+ }
+ }
+
+ if( bSplit )
+ {
+ SwTableLine *pLine =
+ MakeTableLine( pBox, nStartRow, 0UL, i+1, nCols );
+ if( pBox || nStartRow>0 )
+ rLines.push_back( pLine );
+ nStartRow = i+1;
+ }
+ }
+}
+
+void SwXMLTableContext::MakeTable()
+{
+ // this method will modify the document directly -> lock SolarMutex
+ // This will call all other MakeTable*(..) methods, so
+ // those don't need to be locked separately.
+ SolarMutexGuard aGuard;
+
+ // #i97274# handle invalid tables
+ if (!m_pRows || m_pRows->empty() || !GetColumnCount())
+ {
+ OSL_FAIL("invalid table: no cells; deleting...");
+ m_pTableNode->GetDoc().getIDocumentContentOperations().DeleteSection( m_pTableNode );
+ m_pTableNode = nullptr;
+ m_pBox1 = nullptr;
+ m_bOwnsBox1 = false;
+ m_pSttNd1 = nullptr;
+ return;
+ }
+
+ SwXMLImport& rSwImport = GetSwImport();
+
+ SwFrameFormat *pFrameFormat = m_pTableNode->GetTable().GetFrameFormat();
+
+ sal_Int16 eHoriOrient = text::HoriOrientation::FULL;
+ bool bSetHoriOrient = false;
+
+ sal_uInt8 nPercentWidth = 0U;
+
+ OUString sStyleName;
+ SwStyleNameMapper::FillUIName( m_aTemplateName, sStyleName, SwGetPoolIdFromName::TabStyle );
+ m_pTableNode->GetTable().SetTableStyleName( sStyleName );
+ m_pTableNode->GetTable().SetRowsToRepeat( m_nHeaderRows );
+ m_pTableNode->GetTable().SetTableModel( !m_bHasSubTables );
+
+ const SfxItemSet *pAutoItemSet = nullptr;
+ if( !m_aStyleName.isEmpty() &&
+ rSwImport.FindAutomaticStyle(
+ XmlStyleFamily::TABLE_TABLE, m_aStyleName, &pAutoItemSet ) &&
+ pAutoItemSet )
+ {
+ const SvxLRSpaceItem *pLRSpace =
+ pAutoItemSet->GetItemIfSet( RES_LR_SPACE, false );
+
+ if( const SwFormatHoriOrient* pItem = pAutoItemSet->GetItemIfSet( RES_HORI_ORIENT, false ) )
+ {
+ eHoriOrient = pItem->GetHoriOrient();
+ switch( eHoriOrient )
+ {
+ case text::HoriOrientation::FULL:
+ if( pLRSpace )
+ {
+ eHoriOrient = text::HoriOrientation::NONE;
+ bSetHoriOrient = true;
+ }
+ break;
+ case text::HoriOrientation::LEFT:
+ if( pLRSpace )
+ {
+ eHoriOrient = text::HoriOrientation::LEFT_AND_WIDTH;
+ bSetHoriOrient = true;
+ }
+ break;
+ default:
+ ;
+ }
+ }
+ else
+ {
+ bSetHoriOrient = true;
+ }
+
+ const SwFormatFrameSize *pSize =
+ pAutoItemSet->GetItemIfSet( RES_FRM_SIZE, false );
+
+ switch( eHoriOrient )
+ {
+ case text::HoriOrientation::FULL:
+ case text::HoriOrientation::NONE:
+ // For text::HoriOrientation::NONE we would prefer to use the sum
+ // of the relative column widths as reference width.
+ // Unfortunately this works only if this sum interpreted as
+ // twip value is larger than the space that is available.
+ // We don't know that space, so we have to use MAX_WIDTH, too.
+ // Even if a size is specified, it will be ignored!
+ m_nWidth = MAX_WIDTH;
+ break;
+ default:
+ if( pSize )
+ {
+ if( pSize->GetWidthPercent() )
+ {
+ // The width will be set in MakeTable_
+ nPercentWidth = pSize->GetWidthPercent();
+ }
+ else
+ {
+ m_nWidth = pSize->GetWidth();
+ sal_Int32 const min = static_cast<sal_Int32>(
+ std::min<sal_uInt32>(GetColumnCount() * MINLAY, MAX_WIDTH));
+ if( m_nWidth < min )
+ {
+ m_nWidth = min;
+ }
+ else if( m_nWidth > MAX_WIDTH )
+ {
+ m_nWidth = MAX_WIDTH;
+ }
+ m_bRelWidth = false;
+ }
+ }
+ else
+ {
+ eHoriOrient = text::HoriOrientation::LEFT_AND_WIDTH == eHoriOrient
+ ? text::HoriOrientation::NONE : text::HoriOrientation::FULL;
+ bSetHoriOrient = true;
+ m_nWidth = MAX_WIDTH;
+ }
+ break;
+ }
+
+ pFrameFormat->SetFormatAttr( *pAutoItemSet );
+ }
+ else
+ {
+ bSetHoriOrient = true;
+ m_nWidth = MAX_WIDTH;
+ }
+
+ SwTableLine *pLine1 = m_pTableNode->GetTable().GetTabLines()[0U];
+ assert(m_pBox1 == pLine1->GetTabBoxes()[0] && !m_bOwnsBox1 && "Why is box 1 change?");
+ m_pBox1->m_pStartNode = m_pSttNd1;
+ pLine1->GetTabBoxes().erase( pLine1->GetTabBoxes().begin() );
+ m_bOwnsBox1 = true;
+
+ m_pLineFormat = static_cast<SwTableLineFormat*>(pLine1->GetFrameFormat());
+ m_pBoxFormat = static_cast<SwTableBoxFormat*>(m_pBox1->GetFrameFormat());
+
+ MakeTable_();
+
+ if( bSetHoriOrient )
+ pFrameFormat->SetFormatAttr( SwFormatHoriOrient( 0, eHoriOrient ) );
+
+ // This must be after the call to MakeTable_, because nWidth might be
+ // changed there.
+ pFrameFormat->LockModify();
+ SwFormatFrameSize aSize( SwFrameSize::Variable, m_nWidth );
+ aSize.SetWidthPercent( nPercentWidth );
+ pFrameFormat->SetFormatAttr( aSize );
+ pFrameFormat->UnlockModify();
+
+ for (std::unique_ptr<SwXMLTableRow_Impl> & rRow : *m_pRows)
+ rRow->Dispose();
+
+ // now that table is complete, change into DDE table (if appropriate)
+ if (m_xDDESource.is())
+ {
+ // change existing table into DDE table:
+ // 1) Get DDE field type (get data from dde-source context),
+ SwDDEFieldType* pFieldType = lcl_GetDDEFieldType( m_xDDESource.get(),
+ m_pTableNode );
+
+ // 2) release the DDE source context,
+ m_xDDESource.clear();
+
+ // 3) create new DDE table, and
+ std::unique_ptr<SwDDETable> pDDETable( new SwDDETable( m_pTableNode->GetTable(),
+ pFieldType, false ) );
+
+ // 4) set new (DDE)table at node.
+ m_pTableNode->SetNewTable(std::move(pDDETable), false);
+ }
+
+ // ??? this is always false: root frame is only created in SwViewShell::Init
+ if( m_pTableNode->GetDoc().getIDocumentLayoutAccess().GetCurrentViewShell() )
+ {
+ m_pTableNode->DelFrames();
+ m_pTableNode->MakeOwnFrames();
+ }
+}
+
+void SwXMLTableContext::MakeTable( SwTableBox *pBox, sal_Int32 nW )
+{
+ //FIXME: here would be a great place to handle XmlId for subtable
+ m_pLineFormat = GetParentTable()->m_pLineFormat;
+ m_pBoxFormat = GetParentTable()->m_pBoxFormat;
+ m_nWidth = nW;
+ m_bRelWidth = GetParentTable()->m_bRelWidth;
+
+ MakeTable_( pBox );
+
+ for (std::unique_ptr<SwXMLTableRow_Impl> & rpRow : *m_pRows)
+ {
+ // i#113600, to break the cyclic reference to SwXMLTableContext object
+ rpRow->Dispose();
+ }
+}
+
+const SwStartNode *SwXMLTableContext::InsertTableSection(
+ const SwStartNode *const pPrevSttNd,
+ OUString const*const pStringValueStyleName)
+{
+ // The topmost table is the only table that maintains the two members
+ // pBox1 and bFirstSection.
+ if( m_xParentTable.is() )
+ return m_xParentTable->InsertTableSection(pPrevSttNd, pStringValueStyleName);
+
+ const SwStartNode *pStNd;
+
+ if( m_bFirstSection )
+ {
+ Reference<XInterface> xCursorTunnel( GetImport().GetTextImport()->GetCursor(),
+ UNO_QUERY);
+ OSL_ENSURE( xCursorTunnel.is(), "missing XUnoTunnel for Cursor" );
+ OTextCursorHelper *pTextCursor = dynamic_cast<OTextCursorHelper*>(xCursorTunnel.get());
+ assert(pTextCursor && "SwXTextCursor missing");
+
+ // The Cursor already is in the first section
+ pStNd = pTextCursor->GetPaM()->GetPointNode().FindTableBoxStartNode();
+ m_bFirstSection = false;
+ GetImport().GetTextImport()->SetStyleAndAttrs( GetImport(),
+ GetImport().GetTextImport()->GetCursor(), "Standard", true );
+ }
+ else
+ {
+ SwDoc* pDoc = GetSwImport().getDoc();
+ const SwEndNode *pEndNd = pPrevSttNd ? pPrevSttNd->EndOfSectionNode()
+ : m_pTableNode->EndOfSectionNode();
+ // #i78921# - make code robust
+ OSL_ENSURE( pDoc, "<SwXMLTableContext::InsertTableSection(..)> - no <pDoc> at <SwXTextCursor> instance - <SwXTextCurosr> doesn't seem to be registered at a <SwUnoCursor> instance." );
+ if ( !pDoc )
+ {
+ pDoc = &const_cast<SwDoc&>(pEndNd->GetDoc());
+ }
+ SwNodeOffset nOffset(pPrevSttNd ? 1 : 0);
+ SwNodeIndex aIdx( *pEndNd, nOffset );
+ SwTextFormatColl *pColl =
+ pDoc->getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_STANDARD, false );
+ pStNd = pDoc->GetNodes().MakeTextSection( aIdx.GetNode(), SwTableBoxStartNode,
+ pColl );
+ // Consider the case that a table is defined without a row.
+ if( !pPrevSttNd && m_pBox1 != nullptr )
+ {
+ m_pBox1->m_pStartNode = pStNd;
+ SwContentNode *pCNd = pDoc->GetNodes()[ pStNd->GetIndex() + 1 ]
+ ->GetContentNode();
+ SwFrameFormat *const pTableFormat = m_pTableNode->GetTable().GetFrameFormat();
+ rtl::Reference<SwXCell> xParent = SwXCell::CreateXCell( pTableFormat, m_pBox1 );
+ DBG_TESTSOLARMUTEX();
+ SwPaM aPam(*pCNd, *pCNd);
+ rtl::Reference<SwXTextCursor> xTextCursor =
+ new SwXTextCursor(*pDoc, xParent, CursorType::TableText,
+ *aPam.GetPoint(), aPam.GetMark());
+ GetImport().GetTextImport()->SetCursor( static_cast<XWordCursor*>(xTextCursor.get()) );
+ }
+ }
+
+ if (pStringValueStyleName)
+ { // fdo#62147: apply style to paragraph on string-value cell
+ GetImport().GetTextImport()->SetStyleAndAttrs( GetImport(),
+ GetImport().GetTextImport()->GetCursor(), *pStringValueStyleName,
+ true, false, -1, false); // parameters same as sCellParaStyleName
+ }
+
+ return pStNd;
+}
+
+void SwXMLTableContext::endFastElement(sal_Int32 )
+{
+ if( IsValid() && !m_xParentTable.is() )
+ {
+ MakeTable();
+ GetImport().GetTextImport()->SetCursor( m_xOldCursor );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmltbli.hxx b/sw/source/filter/xml/xmltbli.hxx
new file mode 100644
index 0000000000..400fc8ba0c
--- /dev/null
+++ b/sw/source/filter/xml/xmltbli.hxx
@@ -0,0 +1,214 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SW_SOURCE_FILTER_XML_XMLTBLI_HXX
+#define INCLUDED_SW_SOURCE_FILTER_XML_XMLTBLI_HXX
+
+#include <xmloff/XMLTextTableContext.hxx>
+
+#include "xmlimp.hxx"
+
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+class SwXMLImport;
+class SwTableNode;
+class SwTableBox;
+class SwTableLine;
+class SwStartNode;
+class SwTableBoxFormat;
+class SwTableLineFormat;
+class SwXMLTableCell_Impl;
+class SwXMLTableRow_Impl;
+typedef std::vector<std::unique_ptr<SwXMLTableRow_Impl>> SwXMLTableRows_Impl;
+class SwXMLDDETableContext_Impl;
+class TableBoxIndexHasher;
+class TableBoxIndex;
+
+namespace com::sun::star {
+ namespace text { class XTextContent; }
+ namespace text { class XTextCursor; }
+}
+
+class SwXMLTableContext : public XMLTextTableContext
+{
+ OUString m_aStyleName;
+ OUString m_aDfltCellStyleName;
+ OUString m_aTemplateName;
+
+ //! Holds basic information about a column's width.
+ struct ColumnWidthInfo {
+ sal_uInt16 width; //!< Column width (absolute or relative).
+ bool isRelative; //!< True for a relative width, false for absolute.
+ ColumnWidthInfo(sal_uInt16 wdth, bool isRel) : width(wdth), isRelative(isRel) {};
+ };
+ std::vector<ColumnWidthInfo> m_aColumnWidths;
+ std::optional<std::vector<OUString>> m_xColumnDefaultCellStyleNames;
+
+ css::uno::Reference< css::text::XTextCursor > m_xOldCursor;
+ css::uno::Reference< css::text::XTextContent > m_xTextContent;
+
+ std::unique_ptr<SwXMLTableRows_Impl> m_pRows;
+
+ SwTableNode *m_pTableNode;
+ SwTableBox *m_pBox1;
+ bool m_bOwnsBox1;
+ const SwStartNode *m_pSttNd1;
+
+ SwTableBoxFormat *m_pBoxFormat;
+ SwTableLineFormat *m_pLineFormat;
+
+ // hash map of shared format, indexed by the (XML) style name,
+ // the column width, and protection flag
+ typedef std::unordered_map<TableBoxIndex,SwTableBoxFormat*,
+ TableBoxIndexHasher> map_BoxFormat;
+ std::unique_ptr<map_BoxFormat> m_pSharedBoxFormats;
+
+ rtl::Reference<SwXMLTableContext> m_xParentTable; // if table is a sub table
+
+ rtl::Reference<SwXMLDDETableContext_Impl> m_xDDESource;
+
+ bool m_bFirstSection : 1;
+ bool m_bRelWidth : 1;
+ bool m_bHasSubTables : 1;
+
+ sal_uInt16 m_nHeaderRows;
+ sal_uInt32 m_nCurRow;
+ sal_uInt32 m_nCurCol;
+ /// Same as m_nCurCol, but not incremented multiple times for table cells with row span.
+ sal_uInt32 m_nNonMergedCurCol;
+ sal_Int32 m_nWidth;
+
+ // The maximum table width (i.e., maximum value for m_nWidth); must be >= MINLAY and must also
+ // fit into ColumnWidthInfo::width (of type sal_uInt16), see e.g. the emplacement of
+ // MINLAY<=nWidth2<=MAX_WIDTH into m_aColumnWidths in SwXMLTableContext::InsertColumn:
+ static constexpr sal_Int32 MAX_WIDTH = SAL_MAX_UINT16;
+
+ SwTableBox *NewTableBox( const SwStartNode *pStNd,
+ SwTableLine *pUpper );
+ SwTableBox *MakeTableBox( SwTableLine *pUpper,
+ const SwXMLTableCell_Impl *pStartNode,
+ sal_uInt32 nLeftCol, sal_uInt32 nRightCol );
+ SwTableBox *MakeTableBox( SwTableLine *pUpper,
+ sal_uInt32 nTopRow, sal_uInt32 nLeftCol,
+ sal_uInt32 nBottomRow, sal_uInt32 nRightCol );
+ SwTableLine *MakeTableLine( SwTableBox *pUpper,
+ sal_uInt32 nTopRow, sal_uInt32 nLeftCol,
+ sal_uInt32 nBottomRow, sal_uInt32 nRightCol );
+
+ void MakeTable_( SwTableBox *pBox=nullptr );
+ void MakeTable( SwTableBox *pBox, sal_Int32 nWidth );
+ void MakeTable();
+
+ inline SwXMLTableContext *GetParentTable() const;
+
+ const SwStartNode *GetPrevStartNode( sal_uInt32 nRow,
+ sal_uInt32 nCol ) const;
+ inline const SwStartNode *GetLastStartNode() const;
+ void FixRowSpan( sal_uInt32 nRow, sal_uInt32 nCol, sal_uInt32 nColSpan );
+ void ReplaceWithEmptyCell( sal_uInt32 nRow, sal_uInt32 nCol, bool bRows );
+
+ /** sets the appropriate SwTableBoxFormat at pBox. */
+ SwTableBoxFormat* GetSharedBoxFormat(
+ SwTableBox* pBox, /// the table box
+ const OUString& rStyleName, /// XML style name
+ sal_Int32 nColumnWidth, /// width of column
+ bool bProtected, /// is cell protected?
+ bool bMayShare, /// may the format be shared (no value, formula...)
+ bool& bNew, /// true, if the format it not from the cache
+ bool* pModifyLocked ); /// if set, call pBox->LockModify() and return old lock status
+
+public:
+
+
+ SwXMLTableContext( SwXMLImport& rImport,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList );
+ SwXMLTableContext( SwXMLImport& rImport,
+ SwXMLTableContext *pTable );
+
+ virtual ~SwXMLTableContext() override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 Element,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList ) override;
+
+ SwXMLImport& GetSwImport() { return static_cast<SwXMLImport&>(GetImport()); }
+
+ void InsertColumn( sal_Int32 nWidth, bool bRelWidth,
+ const OUString *pDfltCellStyleName = nullptr );
+ sal_Int32 GetColumnWidth( sal_uInt32 nCol, sal_uInt32 nColSpan ) const;
+ OUString GetColumnDefaultCellStyleName( sal_uInt32 nCol ) const;
+ inline sal_uInt32 GetColumnCount() const;
+
+ bool IsInsertCellPossible() const { return m_nCurCol < GetColumnCount(); }
+
+ /// Determines if it's OK to insert a covered cell, given the total column count.
+ bool IsInsertCoveredCellPossible() const { return m_nNonMergedCurCol < GetColumnCount(); }
+
+ bool IsInsertColPossible() const { return m_nCurCol < USHRT_MAX; }
+ bool IsInsertRowPossible() const { return m_nCurRow < USHRT_MAX; }
+ bool IsValid() const { return m_pTableNode != nullptr; }
+
+ void InsertCell( const OUString& rStyleName,
+ sal_uInt32 nRowSpan, sal_uInt32 nColSpan,
+ const SwStartNode *pStNd,
+ SwXMLTableContext *pTable=nullptr,
+ bool bIsProtected = false,
+ const OUString *pFormula=nullptr,
+ bool bHasValue = false,
+ double fValue = 0.0,
+ OUString const*const pStringValue = nullptr);
+
+ /// Sets formatting of an already created covered cell.
+ void InsertCoveredCell(const OUString& rStyleName);
+
+ void InsertRow( const OUString& rStyleName,
+ const OUString& rDfltCellStyleName,
+ bool bInHead );
+ void FinishRow();
+ void InsertRepRows( sal_uInt32 nCount );
+ const SwXMLTableCell_Impl *GetCell( sal_uInt32 nRow, sal_uInt32 nCol ) const;
+ SwXMLTableCell_Impl *GetCell( sal_uInt32 nRow, sal_uInt32 nCol );
+ const SwStartNode *InsertTableSection(const SwStartNode *pPrevSttNd = nullptr,
+ OUString const* pStringValueStyleName = nullptr);
+
+ virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
+
+ void SetHasSubTables( bool bNew ) { m_bHasSubTables = bNew; }
+};
+
+inline SwXMLTableContext *SwXMLTableContext::GetParentTable() const
+{
+ return m_xParentTable.get();
+}
+
+inline sal_uInt32 SwXMLTableContext::GetColumnCount() const
+{
+ return m_aColumnWidths.size();
+}
+
+inline const SwStartNode *SwXMLTableContext::GetLastStartNode() const
+{
+ return GetPrevStartNode( 0UL, GetColumnCount() );
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmltext.cxx b/sw/source/filter/xml/xmltext.cxx
new file mode 100644
index 0000000000..115dc1a523
--- /dev/null
+++ b/sw/source/filter/xml/xmltext.cxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlimp.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::text;
+
+namespace {
+
+class SwXMLBodyContentContext_Impl : public SvXMLImportContext
+{
+ SwXMLImport& GetSwImport() { return static_cast<SwXMLImport&>(GetImport()); }
+
+public:
+
+ SwXMLBodyContentContext_Impl( SwXMLImport& rImport );
+
+ css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override;
+
+ // The body element's text:global attribute can be ignored, because
+ // we must have the correct object shell already.
+ virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
+};
+
+}
+
+SwXMLBodyContentContext_Impl::SwXMLBodyContentContext_Impl( SwXMLImport& rImport ) :
+ SvXMLImportContext( rImport )
+{
+}
+
+css::uno::Reference< css::xml::sax::XFastContextHandler > SwXMLBodyContentContext_Impl::createFastChildContext(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
+{
+ return GetSwImport().GetTextImport()->CreateTextChildContext(
+ GetImport(), nElement, xAttrList,
+ XMLTextType::Body );
+}
+
+void SwXMLBodyContentContext_Impl::endFastElement(sal_Int32 )
+{
+ /* Code moved to SwXMLOmport::endDocument */
+ GetImport().GetTextImport()->SetOutlineStyles( false );
+}
+
+SvXMLImportContext *SwXMLImport::CreateBodyContentContext()
+{
+ SvXMLImportContext *pContext = nullptr;
+
+ if( !IsStylesOnlyMode() )
+ pContext = new SwXMLBodyContentContext_Impl( *this );
+
+ return pContext;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmltexte.cxx b/sw/source/filter/xml/xmltexte.cxx
new file mode 100644
index 0000000000..9c68a12f70
--- /dev/null
+++ b/sw/source/filter/xml/xmltexte.cxx
@@ -0,0 +1,549 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <comphelper/classids.hxx>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/embed/XLinkageSupport.hpp>
+#include <com/sun/star/document/XEmbeddedObjectSupplier.hpp>
+#include <xmloff/families.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/txtprmap.hxx>
+#include <xmloff/maptype.hxx>
+#include <xmloff/xmlexppr.hxx>
+
+#include <ndole.hxx>
+#include <fmtcntnt.hxx>
+#include <unoframe.hxx>
+#include "xmlexp.hxx"
+#include "xmltexte.hxx"
+#include <SwAppletImpl.hxx>
+#include <ndindex.hxx>
+
+#include <osl/diagnose.h>
+#include <sot/exchange.hxx>
+#include <svl/urihelper.hxx>
+#include <sfx2/frmdescr.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::style;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::io;
+using namespace ::xmloff::token;
+
+namespace {
+
+enum SvEmbeddedObjectTypes
+{
+ SV_EMBEDDED_OWN,
+ SV_EMBEDDED_OUTPLACE,
+ SV_EMBEDDED_APPLET,
+ SV_EMBEDDED_PLUGIN,
+ SV_EMBEDDED_FRAME
+};
+
+}
+
+SwNoTextNode *SwXMLTextParagraphExport::GetNoTextNode(
+ const Reference < XPropertySet >& rPropSet )
+{
+ SwXFrame* pFrame = dynamic_cast<SwXFrame*>(rPropSet.get());
+ assert(pFrame && "SwXFrame missing");
+ SwFrameFormat *pFrameFormat = pFrame->GetFrameFormat();
+ const SwFormatContent& rContent = pFrameFormat->GetContent();
+ const SwNodeIndex *pNdIdx = rContent.GetContentIdx();
+ return pNdIdx->GetNodes()[pNdIdx->GetIndex() + 1]->GetNoTextNode();
+}
+
+constexpr OUString gsEmbeddedObjectProtocol( u"vnd.sun.star.EmbeddedObject:"_ustr );
+
+SwXMLTextParagraphExport::SwXMLTextParagraphExport(
+ SwXMLExport& rExp,
+ SvXMLAutoStylePoolP& _rAutoStylePool ) :
+ XMLTextParagraphExport( rExp, _rAutoStylePool ),
+ m_aAppletClassId( SO3_APPLET_CLASSID ),
+ m_aPluginClassId( SO3_PLUGIN_CLASSID ),
+ m_aIFrameClassId( SO3_IFRAME_CLASSID )
+{
+}
+
+SwXMLTextParagraphExport::~SwXMLTextParagraphExport()
+{
+}
+
+static void lcl_addURL ( SvXMLExport &rExport, const OUString &rURL,
+ bool bToRel = true )
+{
+ const OUString sRelURL = ( bToRel && !rURL.isEmpty() )
+ ? URIHelper::simpleNormalizedMakeRelative(rExport.GetOrigFileName(), rURL)
+ : rURL;
+
+ if (!sRelURL.isEmpty())
+ {
+ rExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, sRelURL );
+ rExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
+ rExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
+ rExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
+ }
+}
+
+static void lcl_addAspect(
+ const svt::EmbeddedObjectRef& rObj,
+ std::vector<XMLPropertyState>& rStates,
+ const rtl::Reference < XMLPropertySetMapper >& rMapper )
+{
+ sal_Int64 nAspect = rObj.GetViewAspect();
+ if ( nAspect )
+ rStates.emplace_back( rMapper->FindEntryIndex( CTF_OLE_DRAW_ASPECT ), uno::Any( nAspect ) );
+}
+
+static void lcl_addOutplaceProperties(
+ const svt::EmbeddedObjectRef& rObj,
+ std::vector<XMLPropertyState>& rStates,
+ const rtl::Reference < XMLPropertySetMapper >& rMapper )
+{
+ MapMode aMode( MapUnit::Map100thMM ); // the API expects this map mode for the embedded objects
+ Size aSize = rObj.GetSize( &aMode ); // get the size in the requested map mode
+
+ if( !(aSize.Width() && aSize.Height()) )
+ return;
+
+ rStates.emplace_back( rMapper->FindEntryIndex( CTF_OLE_VIS_AREA_LEFT ), Any(sal_Int32(0)) );
+ rStates.emplace_back( rMapper->FindEntryIndex( CTF_OLE_VIS_AREA_TOP ), Any(sal_Int32(0)) );
+ rStates.emplace_back( rMapper->FindEntryIndex( CTF_OLE_VIS_AREA_WIDTH ), Any(static_cast<sal_Int32>(aSize.Width())) );
+ rStates.emplace_back( rMapper->FindEntryIndex( CTF_OLE_VIS_AREA_HEIGHT ), Any(static_cast<sal_Int32>(aSize.Height())) );
+}
+
+static void lcl_addFrameProperties(
+ const uno::Reference < embed::XEmbeddedObject >& xObj,
+ std::vector<XMLPropertyState>& rStates,
+ const rtl::Reference < XMLPropertySetMapper >& rMapper )
+{
+ if ( !::svt::EmbeddedObjectRef::TryRunningState( xObj ) )
+ return;
+
+ uno::Reference < beans::XPropertySet > xSet( xObj->getComponent(), uno::UNO_QUERY );
+ if ( !xSet.is() )
+ return;
+
+ bool bIsAutoScroll = false, bIsScrollingMode = false;
+ Any aAny = xSet->getPropertyValue("FrameIsAutoScroll");
+ aAny >>= bIsAutoScroll;
+ if ( !bIsAutoScroll )
+ {
+ aAny = xSet->getPropertyValue("FrameIsScrollingMode");
+ aAny >>= bIsScrollingMode;
+ }
+
+ bool bIsBorderSet = false, bIsAutoBorder = false;
+ aAny = xSet->getPropertyValue("FrameIsAutoBorder");
+ aAny >>= bIsAutoBorder;
+ if ( !bIsAutoBorder )
+ {
+ aAny = xSet->getPropertyValue("FrameIsBorder");
+ aAny >>= bIsBorderSet;
+ }
+
+ sal_Int32 nWidth, nHeight;
+ aAny = xSet->getPropertyValue("FrameMarginWidth");
+ aAny >>= nWidth;
+ aAny = xSet->getPropertyValue("FrameMarginHeight");
+ aAny >>= nHeight;
+
+ if( !bIsAutoScroll )
+ rStates.emplace_back( rMapper->FindEntryIndex( CTF_FRAME_DISPLAY_SCROLLBAR ), Any(bIsScrollingMode) );
+ if( !bIsAutoBorder )
+ rStates.emplace_back( rMapper->FindEntryIndex( CTF_FRAME_DISPLAY_BORDER ), Any(bIsBorderSet) );
+ if( SIZE_NOT_SET != nWidth )
+ rStates.emplace_back( rMapper->FindEntryIndex( CTF_FRAME_MARGIN_HORI ), Any(nWidth) );
+ if( SIZE_NOT_SET != nHeight )
+ rStates.emplace_back( rMapper->FindEntryIndex( CTF_FRAME_MARGIN_VERT ), Any(nHeight) );
+}
+
+void SwXMLTextParagraphExport::_collectTextEmbeddedAutoStyles(
+ const Reference < XPropertySet > & rPropSet )
+{
+ SwOLENode *pOLENd = GetNoTextNode( rPropSet )->GetOLENode();
+ svt::EmbeddedObjectRef& rObjRef = pOLENd->GetOLEObj().GetObject();
+ if( !rObjRef.is() )
+ return;
+
+ std::vector<XMLPropertyState> aStates;
+ aStates.reserve(8);
+ SvGlobalName aClassId( rObjRef->getClassID() );
+
+ if( m_aIFrameClassId == aClassId )
+ {
+ lcl_addFrameProperties( rObjRef.GetObject(), aStates,
+ GetAutoFramePropMapper()->getPropertySetMapper() );
+ }
+ else if ( !SotExchange::IsInternal( aClassId ) )
+ {
+ lcl_addOutplaceProperties( rObjRef, aStates,
+ GetAutoFramePropMapper()->getPropertySetMapper() );
+ }
+
+ lcl_addAspect( rObjRef, aStates,
+ GetAutoFramePropMapper()->getPropertySetMapper() );
+
+ Add( XmlStyleFamily::TEXT_FRAME, rPropSet, aStates );
+}
+
+void SwXMLTextParagraphExport::_exportTextEmbedded(
+ const Reference < XPropertySet > & rPropSet,
+ const Reference < XPropertySetInfo > & rPropSetInfo )
+{
+ SwOLENode *pOLENd = GetNoTextNode( rPropSet )->GetOLENode();
+ SwOLEObj& rOLEObj = pOLENd->GetOLEObj();
+ svt::EmbeddedObjectRef& rObjRef = rOLEObj.GetObject();
+ if( !rObjRef.is() )
+ return;
+
+ SvGlobalName aClassId( rObjRef->getClassID() );
+
+ SvEmbeddedObjectTypes nType = SV_EMBEDDED_OWN;
+ if( m_aPluginClassId == aClassId )
+ {
+ nType = SV_EMBEDDED_PLUGIN;
+ }
+ else if( m_aAppletClassId == aClassId )
+ {
+ nType = SV_EMBEDDED_APPLET;
+ }
+ else if( m_aIFrameClassId == aClassId )
+ {
+ nType = SV_EMBEDDED_FRAME;
+ }
+ else if ( !SotExchange::IsInternal( aClassId ) )
+ {
+ nType = SV_EMBEDDED_OUTPLACE;
+ }
+
+ enum XMLTokenEnum eElementName = XML__UNKNOWN_;
+ SvXMLExport &rXMLExport = GetExport();
+
+ // First the stuff common to each of Applet/Plugin/Floating Frame
+ OUString sStyle;
+ Any aAny;
+ if( rPropSetInfo->hasPropertyByName( gsFrameStyleName ) )
+ {
+ aAny = rPropSet->getPropertyValue( gsFrameStyleName );
+ aAny >>= sStyle;
+ }
+
+ std::vector<XMLPropertyState> aStates;
+ aStates.reserve(8);
+ switch( nType )
+ {
+ case SV_EMBEDDED_FRAME:
+ lcl_addFrameProperties( rObjRef.GetObject(), aStates,
+ GetAutoFramePropMapper()->getPropertySetMapper() );
+ break;
+ case SV_EMBEDDED_OUTPLACE:
+ lcl_addOutplaceProperties( rObjRef, aStates,
+ GetAutoFramePropMapper()->getPropertySetMapper() );
+ break;
+ default:
+ ;
+ }
+
+ lcl_addAspect( rObjRef, aStates,
+ GetAutoFramePropMapper()->getPropertySetMapper() );
+
+ const OUString sAutoStyle = Find( XmlStyleFamily::TEXT_FRAME,
+ rPropSet, sStyle, aStates );
+ aStates.clear();
+
+ if( !sAutoStyle.isEmpty() )
+ rXMLExport.AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE_NAME, sAutoStyle );
+ addTextFrameAttributes( rPropSet, false );
+
+ SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_DRAW,
+ XML_FRAME, false, true );
+
+ switch (nType)
+ {
+ case SV_EMBEDDED_OUTPLACE:
+ case SV_EMBEDDED_OWN:
+ if( !(rXMLExport.getExportFlags() & SvXMLExportFlags::EMBEDDED) )
+ {
+ OUString sURL;
+
+ bool bIsOwnLink = false;
+ if( SV_EMBEDDED_OWN == nType )
+ {
+ try
+ {
+ uno::Reference< embed::XLinkageSupport > xLinkage( rObjRef.GetObject(), uno::UNO_QUERY );
+ bIsOwnLink = xLinkage.is() && xLinkage->isLink();
+ if ( bIsOwnLink )
+ sURL = xLinkage->getLinkURL();
+ }
+ catch(const uno::Exception&)
+ {
+ // TODO/LATER: error handling
+ OSL_FAIL( "Link detection or retrieving of the URL of OOo link is failed!" );
+ }
+ }
+
+ if ( !bIsOwnLink )
+ {
+ sURL = gsEmbeddedObjectProtocol + rOLEObj.GetCurrentPersistName();
+ }
+
+ sURL = GetExport().AddEmbeddedObject( sURL );
+ lcl_addURL( rXMLExport, sURL, false );
+ }
+ if( SV_EMBEDDED_OWN == nType && !pOLENd->GetChartTableName().isEmpty() )
+ {
+ OUString sRange( pOLENd->GetChartTableName() );
+ OUStringBuffer aBuffer( sRange.getLength() + 2 );
+ for( sal_Int32 i=0; i < sRange.getLength(); i++ )
+ {
+ sal_Unicode c = sRange[i];
+ switch( c )
+ {
+ case ' ':
+ case '.':
+ case '\'':
+ case '\\':
+ if( aBuffer.isEmpty() )
+ {
+ aBuffer.append( OUString::Concat("\'") + sRange.subView(0, i) );
+ }
+ if( '\'' == c || '\\' == c )
+ aBuffer.append( '\\' );
+ [[fallthrough]];
+ default:
+ if( !aBuffer.isEmpty() )
+ aBuffer.append( c );
+ }
+ }
+ if( !aBuffer.isEmpty() )
+ {
+ aBuffer.append( '\'' );
+ sRange = aBuffer.makeStringAndClear();
+ }
+
+ rXMLExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NOTIFY_ON_UPDATE_OF_RANGES,
+ sRange );
+ }
+ eElementName = SV_EMBEDDED_OUTPLACE==nType ? XML_OBJECT_OLE
+ : XML_OBJECT;
+ break;
+ case SV_EMBEDDED_APPLET:
+ {
+ // It's an applet!
+ if( svt::EmbeddedObjectRef::TryRunningState( rObjRef.GetObject() ) )
+ {
+ uno::Reference < beans::XPropertySet > xSet( rObjRef->getComponent(), uno::UNO_QUERY );
+ OUString aStr;
+ Any aAny2 = xSet->getPropertyValue("AppletCodeBase");
+ aAny2 >>= aStr;
+ if (!aStr.isEmpty() )
+ lcl_addURL(rXMLExport, aStr);
+
+ aAny2 = xSet->getPropertyValue("AppletName");
+ aAny2 >>= aStr;
+ if (!aStr.isEmpty())
+ rXMLExport.AddAttribute( XML_NAMESPACE_DRAW, XML_APPLET_NAME, aStr );
+
+ aAny2 = xSet->getPropertyValue("AppletCode");
+ aAny2 >>= aStr;
+ rXMLExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CODE, aStr );
+
+ bool bScript = false;
+ aAny2 = xSet->getPropertyValue("AppletIsScript");
+ aAny2 >>= bScript;
+ rXMLExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MAY_SCRIPT, bScript ? XML_TRUE : XML_FALSE );
+
+ uno::Sequence < beans::PropertyValue > aProps;
+ aAny2 = xSet->getPropertyValue("AppletCommands");
+ aAny2 >>= aProps;
+
+ sal_Int32 i = aProps.getLength();
+ while ( i > 0 )
+ {
+ const beans::PropertyValue& aProp = aProps[--i];
+ const SwHtmlOptType nType2 = SwApplet_Impl::GetOptionType( aProp.Name, true );
+ if ( nType2 == SwHtmlOptType::TAG)
+ {
+ OUString aStr2;
+ aProp.Value >>= aStr2;
+ rXMLExport.AddAttribute( XML_NAMESPACE_DRAW, aProp.Name, aStr2);
+ }
+ }
+
+ eElementName = XML_APPLET;
+ }
+ }
+ break;
+ case SV_EMBEDDED_PLUGIN:
+ {
+ // It's a plugin!
+ if ( svt::EmbeddedObjectRef::TryRunningState( rObjRef.GetObject() ) )
+ {
+ uno::Reference < beans::XPropertySet > xSet( rObjRef->getComponent(), uno::UNO_QUERY );
+ OUString aStr;
+ Any aAny2 = xSet->getPropertyValue("PluginURL");
+ aAny2 >>= aStr;
+ lcl_addURL( rXMLExport, aStr );
+
+ aAny2 = xSet->getPropertyValue("PluginMimeType");
+ aAny2 >>= aStr;
+ if (!aStr.isEmpty())
+ rXMLExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIME_TYPE, aStr );
+ eElementName = XML_PLUGIN;
+ }
+ }
+ break;
+ case SV_EMBEDDED_FRAME:
+ {
+ // It's a floating frame!
+ if ( svt::EmbeddedObjectRef::TryRunningState( rObjRef.GetObject() ) )
+ {
+ uno::Reference < beans::XPropertySet > xSet( rObjRef->getComponent(), uno::UNO_QUERY );
+ OUString aStr;
+ Any aAny2 = xSet->getPropertyValue("FrameURL");
+ aAny2 >>= aStr;
+
+ lcl_addURL( rXMLExport, aStr );
+
+ aAny2 = xSet->getPropertyValue("FrameName");
+ aAny2 >>= aStr;
+
+ if (!aStr.isEmpty())
+ rXMLExport.AddAttribute( XML_NAMESPACE_DRAW, XML_FRAME_NAME, aStr );
+ eElementName = XML_FLOATING_FRAME;
+ }
+ }
+ break;
+ default:
+ OSL_ENSURE( false, "unknown object type! Base class should have been called!" );
+ }
+
+ {
+ SvXMLElementExport aElementExport( rXMLExport, XML_NAMESPACE_DRAW, eElementName,
+ false, true );
+ switch( nType )
+ {
+ case SV_EMBEDDED_OWN:
+ if( rXMLExport.getExportFlags() & SvXMLExportFlags::EMBEDDED )
+ {
+ Reference < XEmbeddedObjectSupplier > xEOS( rPropSet, UNO_QUERY );
+ OSL_ENSURE( xEOS.is(), "no embedded object supplier for own object" );
+ Reference < XComponent > xComp = xEOS->getEmbeddedObject();
+ rXMLExport.ExportEmbeddedOwnObject( xComp );
+ }
+ break;
+ case SV_EMBEDDED_OUTPLACE:
+ if( rXMLExport.getExportFlags() & SvXMLExportFlags::EMBEDDED )
+ {
+ OUString sURL( gsEmbeddedObjectProtocol + rOLEObj.GetCurrentPersistName() );
+
+ if ( !( rXMLExport.getExportFlags() & SvXMLExportFlags::OASIS ) )
+ sURL += "?oasis=false";
+
+ rXMLExport.AddEmbeddedObjectAsBase64( sURL );
+ }
+ break;
+ case SV_EMBEDDED_APPLET:
+ {
+ if ( svt::EmbeddedObjectRef::TryRunningState( rObjRef.GetObject() ) )
+ {
+ uno::Reference < beans::XPropertySet > xSet( rObjRef->getComponent(), uno::UNO_QUERY );
+ uno::Sequence < beans::PropertyValue > aProps;
+ aAny = xSet->getPropertyValue("AppletCommands");
+ aAny >>= aProps;
+
+ sal_Int32 i = aProps.getLength();
+ while ( i > 0 )
+ {
+ const beans::PropertyValue& aProp = aProps[--i];
+ const SwHtmlOptType nType2 = SwApplet_Impl::GetOptionType( aProp.Name, true );
+ if (SwHtmlOptType::PARAM == nType2 || SwHtmlOptType::SIZE == nType2 )
+ {
+ OUString aStr;
+ aProp.Value >>= aStr;
+ rXMLExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aProp.Name );
+ rXMLExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aStr );
+ SvXMLElementExport aElementExport2( rXMLExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
+ }
+ }
+ }
+ }
+ break;
+ case SV_EMBEDDED_PLUGIN:
+ {
+ if ( svt::EmbeddedObjectRef::TryRunningState( rObjRef.GetObject() ) )
+ {
+ uno::Reference < beans::XPropertySet > xSet( rObjRef->getComponent(), uno::UNO_QUERY );
+ uno::Sequence < beans::PropertyValue > aProps;
+ aAny = xSet->getPropertyValue("PluginCommands");
+ aAny >>= aProps;
+
+ sal_Int32 i = aProps.getLength();
+ while ( i > 0 )
+ {
+ const beans::PropertyValue& aProp = aProps[--i];
+ const SwHtmlOptType nType2 = SwApplet_Impl::GetOptionType( aProp.Name, false );
+ if ( nType2 == SwHtmlOptType::TAG)
+ {
+ OUString aStr;
+ aProp.Value >>= aStr;
+ rXMLExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aProp.Name );
+ rXMLExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aStr );
+ SvXMLElementExport aElementExport2( rXMLExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
+ }
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if( SV_EMBEDDED_OUTPLACE==nType || SV_EMBEDDED_OWN==nType )
+ {
+ OUString sURL = XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE + rOLEObj.GetCurrentPersistName();
+ if( !(rXMLExport.getExportFlags() & SvXMLExportFlags::EMBEDDED) )
+ {
+ sURL = GetExport().AddEmbeddedObject( sURL );
+ lcl_addURL( rXMLExport, sURL, false );
+ }
+
+ SvXMLElementExport aElementExport( GetExport(), XML_NAMESPACE_DRAW,
+ XML_IMAGE, false, true );
+
+ if( rXMLExport.getExportFlags() & SvXMLExportFlags::EMBEDDED )
+ GetExport().AddEmbeddedObjectAsBase64( sURL );
+ }
+
+ // Lastly the stuff common to each of Applet/Plugin/Floating Frame
+ exportEvents( rPropSet );
+ exportTitleAndDescription( rPropSet, rPropSetInfo ); // #i73249#
+ exportContour( rPropSet, rPropSetInfo );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmltexte.hxx b/sw/source/filter/xml/xmltexte.hxx
new file mode 100644
index 0000000000..09ce6c46f4
--- /dev/null
+++ b/sw/source/filter/xml/xmltexte.hxx
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SW_SOURCE_FILTER_XML_XMLTEXTE_HXX
+#define INCLUDED_SW_SOURCE_FILTER_XML_XMLTEXTE_HXX
+
+#include <xmloff/txtparae.hxx>
+#include <tools/globname.hxx>
+
+#include <optional>
+#include <unordered_map>
+
+#define XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE "vnd.sun.star.GraphicObject:"
+
+class SwXMLExport;
+class SvXMLAutoStylePoolP;
+class SwNoTextNode;
+class SwTableNode;
+class SwTableLines;
+namespace com::sun::star::style { class XStyle; }
+
+class SwXMLTextParagraphExport : public XMLTextParagraphExport
+{
+ const SvGlobalName m_aAppletClassId;
+ const SvGlobalName m_aPluginClassId;
+ const SvGlobalName m_aIFrameClassId;
+
+ // Collected autostyles for use in exportTextAutoStyles
+ std::vector<const SwTableNode*> maTableNodes;
+public:
+ typedef ::std::unordered_map<SwFrameFormat const*, ::std::optional<OUString>> FormatMap;
+private:
+ ::std::unordered_map<SwTableNode const*, ::std::pair<FormatMap, FormatMap>> m_TableFormats;
+
+ static SwNoTextNode *GetNoTextNode(
+ const css::uno::Reference < css::beans::XPropertySet >& rPropSet );
+
+ void CollectTableLinesAutoStyles(const SwTableLines& rLines, SwFrameFormat& rFormat,
+ bool bProgress);
+
+protected:
+ virtual void _collectTextEmbeddedAutoStyles(
+ const css::uno::Reference< css::beans::XPropertySet > & rPropSet ) override;
+ virtual void _exportTextEmbedded(
+ const css::uno::Reference< css::beans::XPropertySet > & rPropSet,
+ const css::uno::Reference< css::beans::XPropertySetInfo > & rPropSetInfo ) override;
+
+ virtual void exportTable(
+ const css::uno::Reference< css::text::XTextContent > & rTextContent,
+ bool bAutoStyles, bool bProgress ) override;
+
+ virtual void exportTableAutoStyles() override;
+
+public:
+ SwXMLTextParagraphExport(
+ SwXMLExport& rExp,
+ SvXMLAutoStylePoolP& rAutoStylePool );
+ virtual ~SwXMLTextParagraphExport() override;
+
+ ::std::unordered_map<SwTableNode const*, ::std::pair<FormatMap, FormatMap>> const&
+ GetTableFormats() const { return m_TableFormats; }
+ ::std::unordered_map<SwTableNode const*, ::std::pair<FormatMap, FormatMap>> &
+ GetTableFormats() { return m_TableFormats; }
+};
+
+#endif // INCLUDED_SW_SOURCE_FILTER_XML_XMLTEXTE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmltexti.cxx b/sw/source/filter/xml/xmltexti.cxx
new file mode 100644
index 0000000000..508cb428dc
--- /dev/null
+++ b/sw/source/filter/xml/xmltexti.cxx
@@ -0,0 +1,997 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <com/sun/star/embed/EmbeddedObjectCreator.hpp>
+#include <com/sun/star/embed/OOoEmbeddedObjectFactory.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <o3tl/any.hxx>
+#include <osl/diagnose.h>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <comphelper/classids.hxx>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <xmloff/prstylei.hxx>
+#include <xmloff/maptype.hxx>
+#include <xmloff/xmlprmap.hxx>
+#include <xmloff/txtprmap.hxx>
+#include <xmloff/i18nmap.hxx>
+#include <xmloff/xmlimppr.hxx>
+#include <TextCursorHelper.hxx>
+#include <unoframe.hxx>
+#include <doc.hxx>
+#include <IDocumentDrawModelAccess.hxx>
+#include <IDocumentContentOperations.hxx>
+#include <fmtfsize.hxx>
+#include <fmtanchr.hxx>
+#include <fmtcntnt.hxx>
+#include "xmlimp.hxx"
+#include "xmltbli.hxx"
+#include "xmltexti.hxx"
+#include "XMLRedlineImportHelper.hxx"
+#include <xmloff/XMLFilterServiceNames.h>
+#include <SwAppletImpl.hxx>
+#include <ndole.hxx>
+#include <docsh.hxx>
+#include <sfx2/docfile.hxx>
+#include <vcl/svapp.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <svtools/embedhlp.hxx>
+#include <svl/urihelper.hxx>
+#include <sfx2/frmdescr.hxx>
+#include <tools/globname.hxx>
+
+#include <algorithm>
+#include <utility>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::beans;
+using namespace xml::sax;
+
+const std::pair<OUString, SvGUID> aServiceMap[] = {
+ { XML_IMPORT_FILTER_WRITER, { SO3_SW_CLASSID } },
+ { XML_IMPORT_FILTER_CALC, { SO3_SC_CLASSID } },
+ { XML_IMPORT_FILTER_DRAW, { SO3_SDRAW_CLASSID } },
+ { XML_IMPORT_FILTER_IMPRESS, { SO3_SIMPRESS_CLASSID } },
+ { XML_IMPORT_FILTER_CHART, { SO3_SCH_CLASSID } },
+ { XML_IMPORT_FILTER_MATH, { SO3_SM_CLASSID } },
+};
+static void lcl_putHeightAndWidth ( SfxItemSet &rItemSet,
+ sal_Int32 nHeight, sal_Int32 nWidth,
+ Size *pTwipSize = nullptr )
+{
+ if( nWidth > 0 && nHeight > 0 )
+ {
+ nWidth = o3tl::toTwips(nWidth, o3tl::Length::mm100);
+ if( nWidth < MINFLY )
+ nWidth = MINFLY;
+ nHeight = o3tl::toTwips(nHeight, o3tl::Length::mm100);
+ if( nHeight < MINFLY )
+ nHeight = MINFLY;
+ rItemSet.Put( SwFormatFrameSize( SwFrameSize::Fixed, nWidth, nHeight ) );
+ }
+
+ SwFormatAnchor aAnchor( RndStdIds::FLY_AT_CHAR );
+ rItemSet.Put( aAnchor );
+
+ if( pTwipSize )
+ {
+ pTwipSize->setWidth( nWidth );
+ pTwipSize->setHeight( nHeight);
+ }
+}
+
+static void lcl_setObjectVisualArea( const uno::Reference< embed::XEmbeddedObject >& xObj,
+ sal_Int64 nAspect,
+ const Size& aVisSize,
+ const MapUnit& aUnit )
+{
+ if( !(xObj.is() && nAspect != embed::Aspects::MSOLE_ICON) )
+ return;
+
+ // convert the visual area to the objects units
+ MapUnit aObjUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) );
+ Size aObjVisSize = OutputDevice::LogicToLogic(aVisSize, MapMode(aUnit), MapMode(aObjUnit));
+ awt::Size aSz;
+ aSz.Width = aObjVisSize.Width();
+ aSz.Height = aObjVisSize.Height();
+
+ try
+ {
+ xObj->setVisualAreaSize( nAspect, aSz );
+ }
+ catch( uno::Exception& )
+ {
+ OSL_FAIL( "Couldn't set visual area of the object!" );
+ }
+}
+
+SwXMLTextImportHelper::SwXMLTextImportHelper(
+ const uno::Reference < XModel>& rModel,
+ SwXMLImport& rImport,
+ const uno::Reference<XPropertySet> & rInfoSet,
+ bool bInsertM, bool bStylesOnlyM,
+ bool bBlockM, bool bOrganizerM ) :
+ XMLTextImportHelper( rModel, rImport, bInsertM, bStylesOnlyM, true/*bProgress*/,
+ bBlockM, bOrganizerM ),
+ m_pRedlineHelper( nullptr )
+{
+ uno::Reference<XPropertySet> xDocPropSet( rModel, UNO_QUERY );
+ m_pRedlineHelper = new XMLRedlineImportHelper(rImport,
+ bInsertM || bBlockM, xDocPropSet, rInfoSet );
+}
+
+SwXMLTextImportHelper::~SwXMLTextImportHelper()
+{
+ // the redline helper destructor sets properties on the document
+ // and may throw an exception while doing so... catch this
+ try
+ {
+ delete m_pRedlineHelper;
+ }
+ catch ( const RuntimeException& )
+ {
+ // ignore
+ }
+}
+
+SvXMLImportContext *SwXMLTextImportHelper::CreateTableChildContext(
+ SvXMLImport& rImport,
+ sal_Int32 /*nElement*/,
+ const uno::Reference< XFastAttributeList > & xAttrList )
+{
+ return new SwXMLTableContext( static_cast<SwXMLImport&>(rImport), xAttrList );
+}
+
+bool SwXMLTextImportHelper::IsInHeaderFooter() const
+{
+ OTextCursorHelper* pTextCursor = dynamic_cast<OTextCursorHelper*>(const_cast<SwXMLTextImportHelper *>(this)->GetCursor().get());
+ SAL_WARN_IF(!pTextCursor, "sw.uno", "SwXTextCursor missing");
+ SwDoc *pDoc = pTextCursor ? pTextCursor->GetDoc() : nullptr;
+
+ return pDoc && pDoc->IsInHeaderFooter( pTextCursor->GetPaM()->GetPoint()->GetNode() );
+}
+
+static SwOLENode *lcl_GetOLENode( const SwFrameFormat *pFrameFormat )
+{
+ SwOLENode *pOLENd = nullptr;
+ if( pFrameFormat )
+ {
+ const SwFormatContent& rContent = pFrameFormat->GetContent();
+ const SwNodeIndex *pNdIdx = rContent.GetContentIdx();
+ pOLENd = pNdIdx->GetNodes()[pNdIdx->GetIndex() + 1]->GetOLENode();
+ }
+ OSL_ENSURE( pOLENd, "Where is the OLE node" );
+ return pOLENd;
+}
+
+uno::Reference< XPropertySet > SwXMLTextImportHelper::createAndInsertOLEObject(
+ SvXMLImport& rImport,
+ const OUString& rHRef,
+ const OUString& rStyleName,
+ const OUString& rTableName,
+ sal_Int32 nWidth, sal_Int32 nHeight )
+{
+ // this method will modify the document directly -> lock SolarMutex
+ SolarMutexGuard aGuard;
+
+ uno::Reference < XPropertySet > xPropSet;
+
+ sal_Int32 nPos = rHRef.indexOf( ':' );
+ if( -1 == nPos )
+ return xPropSet;
+
+ OUString aObjName( rHRef.copy( nPos+1) );
+
+ if( aObjName.isEmpty() )
+ return xPropSet;
+
+ OTextCursorHelper* pTextCursor = dynamic_cast<OTextCursorHelper*>(GetCursor().get());
+ SAL_WARN_IF(!pTextCursor, "sw.uno", "SwXTextCursor missing");
+ SwDoc *pDoc = static_cast<SwXMLImport&>(rImport).getDoc();
+
+ SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END> aItemSet( pDoc->GetAttrPool() );
+ Size aTwipSize( 0, 0 );
+ tools::Rectangle aVisArea( 0, 0, nWidth, nHeight );
+ lcl_putHeightAndWidth( aItemSet, nHeight, nWidth,
+ &aTwipSize );
+
+ SwFrameFormat *pFrameFormat = nullptr;
+ SwOLENode *pOLENd = nullptr;
+ if( rHRef.startsWith("vnd.sun.star.ServiceName:") )
+ {
+ bool bInsert = false;
+ SvGlobalName aClassName;
+ for (const auto& [sFilterService, rCLASSID] : aServiceMap)
+ {
+ if (aObjName == sFilterService)
+ {
+ aClassName = SvGlobalName(rCLASSID);
+ bInsert = true;
+ break;
+ }
+ }
+
+ if( bInsert )
+ {
+ uno::Reference < embed::XStorage > xStorage = comphelper::OStorageHelper::GetTemporaryStorage();
+ try
+ {
+ // create object with desired ClassId
+ uno::Sequence < sal_Int8 > aClass( aClassName.GetByteSequence() );
+ uno::Reference < embed::XEmbeddedObjectCreator > xFactory = embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
+ uno::Sequence<beans::PropertyValue> aObjArgs( comphelper::InitPropertySequence({
+ { "DefaultParentBaseURL", Any(GetXMLImport().GetBaseURL()) }
+ }));
+ uno::Reference < embed::XEmbeddedObject > xObj( xFactory->createInstanceInitNew(
+ aClass, OUString(), xStorage, "DummyName", aObjArgs), uno::UNO_QUERY );
+ if ( xObj.is() )
+ {
+ //TODO/LATER: is it enough to only set the VisAreaSize?
+ lcl_setObjectVisualArea( xObj, embed::Aspects::MSOLE_CONTENT, aTwipSize, MapUnit::MapTwip );
+ }
+
+ if( pTextCursor )
+ {
+ pFrameFormat = pDoc->getIDocumentContentOperations().InsertEmbObject(
+ *pTextCursor->GetPaM(),
+ ::svt::EmbeddedObjectRef(xObj, embed::Aspects::MSOLE_CONTENT),
+ &aItemSet);
+ pOLENd = lcl_GetOLENode( pFrameFormat );
+ }
+
+ if( pOLENd )
+ aObjName = pOLENd->GetOLEObj().GetCurrentPersistName();
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ }
+ }
+ else
+ {
+ // check whether an object with this name already exists in the document
+ OUString aName;
+ SwIterator<SwContentNode,SwFormatColl> aIter( *pDoc->GetDfltGrfFormatColl() );
+ for( SwContentNode* pNd = aIter.First(); pNd; pNd = aIter.Next() )
+ {
+ SwOLENode* pExistingOLENd = pNd->GetOLENode();
+ if( pExistingOLENd )
+ {
+ OUString aExistingName = pExistingOLENd->GetOLEObj().GetCurrentPersistName();
+ if ( aExistingName == aObjName )
+ {
+ OSL_FAIL( "The document contains duplicate object references, means it is partially broken, please let developers know how this document was generated!" );
+
+ OUString aTmpName = pDoc->GetPersist()->GetEmbeddedObjectContainer().CreateUniqueObjectName();
+ try
+ {
+ pDoc->GetPersist()->GetStorage()->copyElementTo( aObjName,
+ pDoc->GetPersist()->GetStorage(),
+ aTmpName );
+ aName = aTmpName;
+ }
+ catch ( uno::Exception& )
+ {
+ OSL_FAIL( "Couldn't create a copy of the object!" );
+ }
+
+ break;
+ }
+ }
+ }
+
+ if ( aName.isEmpty() )
+ aName = aObjName;
+
+ // the correct aspect will be set later
+ // TODO/LATER: Actually it should be set here
+ if( pTextCursor )
+ {
+ pFrameFormat = pDoc->getIDocumentContentOperations().InsertOLE( *pTextCursor->GetPaM(), aName, embed::Aspects::MSOLE_CONTENT, &aItemSet, nullptr );
+ pOLENd = lcl_GetOLENode( pFrameFormat );
+ }
+ aObjName = aName;
+ }
+
+ if( !pFrameFormat )
+ return xPropSet;
+
+ if( IsInsertMode() )
+ {
+ if( !pOLENd )
+ pOLENd = lcl_GetOLENode( pFrameFormat );
+ if( pOLENd )
+ pOLENd->SetOLESizeInvalid( true );
+ }
+
+ xPropSet = SwXTextEmbeddedObject::CreateXTextEmbeddedObject(
+ *pDoc, pFrameFormat);
+ if( pDoc->getIDocumentDrawModelAccess().GetDrawModel() )
+ {
+ // req for z-order
+ SwXFrame::GetOrCreateSdrObject(*static_cast<SwFlyFrameFormat*>(pFrameFormat));
+ }
+ if( !rTableName.isEmpty() )
+ {
+ const SwFormatContent& rContent = pFrameFormat->GetContent();
+ const SwNodeIndex *pNdIdx = rContent.GetContentIdx();
+ SwOLENode *pOLENode = pNdIdx->GetNodes()[pNdIdx->GetIndex() + 1]->GetOLENode();
+ OSL_ENSURE( pOLENode, "Where is the OLE node" );
+
+ OUStringBuffer aBuffer( rTableName.getLength() );
+ bool bQuoted = false;
+ bool bEscape = false;
+ bool bError = false;
+ for( sal_Int32 i=0; i < rTableName.getLength(); i++ )
+ {
+ bool bEndOfNameFound = false;
+ sal_Unicode c = rTableName[i];
+ switch( c )
+ {
+ case '\'':
+ if( bEscape )
+ {
+ aBuffer.append( c );
+ bEscape = false;
+ }
+ else if( bQuoted )
+ {
+ bEndOfNameFound = true;
+ }
+ else if( 0 == i )
+ {
+ bQuoted = true;
+ }
+ else
+ {
+ bError = true;
+ }
+ break;
+ case '\\':
+ if( bEscape )
+ {
+ aBuffer.append( c );
+ bEscape = false;
+ }
+ else
+ {
+ bEscape = true;
+ }
+ break;
+ case ' ':
+ case '.':
+ if( !bQuoted )
+ {
+ bEndOfNameFound = true;
+ }
+ else
+ {
+ aBuffer.append( c );
+ bEscape = false;
+ }
+ break;
+ default:
+ {
+ aBuffer.append( c );
+ bEscape = false;
+ }
+ break;
+ }
+ if( bError || bEndOfNameFound )
+ break;
+ }
+ if( !bError )
+ {
+ OUString sTableName( aBuffer.makeStringAndClear() );
+ pOLENode->SetChartTableName( GetRenameMap().Get( XML_TEXT_RENAME_TYPE_TABLE, sTableName ) );
+ }
+ }
+
+ sal_Int64 nDrawAspect = 0;
+ const XMLPropStyleContext *pStyle = nullptr;
+ bool bHasSizeProps = false;
+ if( !rStyleName.isEmpty() )
+ {
+ pStyle = FindAutoFrameStyle( rStyleName );
+ if( pStyle )
+ {
+ rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap =
+ pStyle->GetStyles()
+ ->GetImportPropertyMapper(pStyle->GetFamily());
+ OSL_ENSURE( xImpPrMap.is(), "Where is the import prop mapper?" );
+ if( xImpPrMap.is() )
+ {
+ rtl::Reference<XMLPropertySetMapper> rPropMapper =
+ xImpPrMap->getPropertySetMapper();
+
+ sal_Int32 nCount = pStyle->GetProperties().size();
+ for( sal_Int32 i=0; i < nCount; i++ )
+ {
+ const XMLPropertyState& rProp = pStyle->GetProperties()[i];
+ sal_Int32 nIdx = rProp.mnIndex;
+ if( -1 == nIdx )
+ continue;
+
+ switch( rPropMapper->GetEntryContextId(nIdx) )
+ {
+ case CTF_OLE_VIS_AREA_LEFT:
+ {
+ sal_Int32 nVal = 0;
+ rProp.maValue >>= nVal;
+ aVisArea.SetPosX( nVal );
+ }
+ break;
+ case CTF_OLE_VIS_AREA_TOP:
+ {
+ sal_Int32 nVal = 0;
+ rProp.maValue >>= nVal;
+ aVisArea.SetPosY( nVal );
+ }
+ break;
+ case CTF_OLE_VIS_AREA_WIDTH:
+ {
+ sal_Int32 nVal = 0;
+ rProp.maValue >>= nVal;
+ aVisArea.setWidth( nVal );
+ bHasSizeProps = true;
+ }
+ break;
+ case CTF_OLE_VIS_AREA_HEIGHT:
+ {
+ sal_Int32 nVal = 0;
+ rProp.maValue >>= nVal;
+ aVisArea.setHeight( nVal );
+ bHasSizeProps = true;
+ }
+ break;
+ case CTF_OLE_DRAW_ASPECT:
+ {
+ rProp.maValue >>= nDrawAspect;
+
+ if ( !nDrawAspect )
+ nDrawAspect = embed::Aspects::MSOLE_CONTENT;
+
+ if ( pOLENd )
+ pOLENd->GetOLEObj().GetObject().SetViewAspect( nDrawAspect );
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if ( bHasSizeProps )
+ {
+ uno::Reference < embed::XEmbeddedObject > xObj =
+ pDoc->GetPersist()->GetEmbeddedObjectContainer().GetEmbeddedObject( aObjName );
+ if( xObj.is() )
+ lcl_setObjectVisualArea( xObj, ( nDrawAspect ? nDrawAspect : embed::Aspects::MSOLE_CONTENT ),
+ aVisArea.GetSize(), MapUnit::Map100thMM );
+ }
+
+ return xPropSet;
+}
+
+uno::Reference< XPropertySet > SwXMLTextImportHelper::createAndInsertOOoLink(
+ SvXMLImport& rImport,
+ const OUString& rHRef,
+ const OUString& /*rStyleName*/,
+ const OUString& /*rTableName*/,
+ sal_Int32 nWidth, sal_Int32 nHeight )
+{
+ // this method will modify the document directly -> lock SolarMutex
+ SolarMutexGuard aGuard;
+
+ uno::Reference < XPropertySet > xPropSet;
+
+ OTextCursorHelper* pTextCursor = dynamic_cast<OTextCursorHelper*>(GetCursor().get());
+ assert( pTextCursor && "SwXTextCursor missing" );
+ SwDoc *pDoc = static_cast<SwXMLImport&>(rImport).getDoc();
+
+ SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END> aItemSet( pDoc->GetAttrPool() );
+ Size aTwipSize( 0, 0 );
+ lcl_putHeightAndWidth( aItemSet, nHeight, nWidth,
+ &aTwipSize );
+
+ // We'll need a (valid) URL. If we don't have do not insert the link and return early.
+ // Copy URL into URL object on the way.
+ INetURLObject aURLObj;
+ bool bValidURL = !rHRef.isEmpty() &&
+ aURLObj.SetURL( URIHelper::SmartRel2Abs(
+ INetURLObject( GetXMLImport().GetBaseURL() ), rHRef ) );
+ if( !bValidURL )
+ return xPropSet;
+
+ uno::Reference < embed::XStorage > xStorage = comphelper::OStorageHelper::GetTemporaryStorage();
+ try
+ {
+ // create object with desired ClassId
+ uno::Reference < embed::XEmbeddedObjectCreator > xFactory =
+ embed::OOoEmbeddedObjectFactory::create(::comphelper::getProcessComponentContext());
+
+ uno::Sequence< beans::PropertyValue > aMediaDescriptor{ comphelper::makePropertyValue(
+ "URL", aURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE )) };
+
+ if (SfxMedium* pMedium = pDoc->GetDocShell() ? pDoc->GetDocShell()->GetMedium() : nullptr)
+ {
+ uno::Reference< task::XInteractionHandler > xInteraction = pMedium->GetInteractionHandler();
+ if ( xInteraction.is() )
+ {
+ aMediaDescriptor.realloc( 2 );
+ auto pMediaDescriptor = aMediaDescriptor.getArray();
+ pMediaDescriptor[1].Name = "InteractionHandler";
+ pMediaDescriptor[1].Value <<= xInteraction;
+ }
+
+ const auto nLen = aMediaDescriptor.getLength() + 1;
+ aMediaDescriptor.realloc(nLen);
+ auto pMediaDescriptor = aMediaDescriptor.getArray();
+ pMediaDescriptor[nLen - 1].Name = "Referer";
+ pMediaDescriptor[nLen - 1].Value <<= pMedium->GetName();
+ }
+
+ uno::Reference < embed::XEmbeddedObject > xObj(
+ xFactory->createInstanceLink(
+ xStorage, "DummyName", aMediaDescriptor, uno::Sequence< beans::PropertyValue >() ),
+ uno::UNO_QUERY_THROW );
+
+ {
+ SwFrameFormat *const pFrameFormat =
+ pDoc->getIDocumentContentOperations().InsertEmbObject(
+ *pTextCursor->GetPaM(),
+ ::svt::EmbeddedObjectRef(xObj, embed::Aspects::MSOLE_CONTENT),
+ &aItemSet );
+
+ // TODO/LATER: in future may need a way to set replacement image url to the link ( may be even to the object ), needs oasis cws???
+
+ xPropSet = SwXTextEmbeddedObject::CreateXTextEmbeddedObject(
+ *pDoc, pFrameFormat);
+ if( pDoc->getIDocumentDrawModelAccess().GetDrawModel() )
+ {
+ SwXFrame::GetOrCreateSdrObject(*
+ static_cast<SwFlyFrameFormat*>(pFrameFormat)); // req for z-order
+ }
+ }
+ }
+ catch ( uno::Exception& )
+ {
+ }
+
+ // TODO/LATER: should the rStyleName and rTableName be handled as for usual embedded object?
+
+ return xPropSet;
+}
+
+uno::Reference< XPropertySet > SwXMLTextImportHelper::createAndInsertApplet(
+ const OUString &rName,
+ const OUString &rCode,
+ bool bMayScript,
+ const OUString& rHRef,
+ sal_Int32 nWidth, sal_Int32 nHeight )
+{
+ // this method will modify the document directly -> lock SolarMutex
+ SolarMutexGuard aGuard;
+
+ uno::Reference < XPropertySet > xPropSet;
+ OTextCursorHelper* pTextCursor = dynamic_cast<OTextCursorHelper*>(GetCursor().get());
+ assert( pTextCursor && "SwXTextCursor missing" );
+ SwDoc *pDoc = pTextCursor->GetDoc();
+
+ SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END> aItemSet( pDoc->GetAttrPool() );
+ lcl_putHeightAndWidth( aItemSet, nHeight, nWidth);
+
+ SwApplet_Impl aAppletImpl ( std::move(aItemSet) );
+
+ OUString sCodeBase;
+ if( !rHRef.isEmpty() )
+ sCodeBase = GetXMLImport().GetAbsoluteReference( rHRef );
+
+ aAppletImpl.CreateApplet ( rCode, rName, bMayScript, sCodeBase, GetXMLImport().GetDocumentBase() );
+
+ // set the size of the applet
+ lcl_setObjectVisualArea( aAppletImpl.GetApplet(),
+ embed::Aspects::MSOLE_CONTENT,
+ Size( nWidth, nHeight ),
+ MapUnit::Map100thMM );
+
+ SwFrameFormat *const pFrameFormat =
+ pDoc->getIDocumentContentOperations().InsertEmbObject( *pTextCursor->GetPaM(),
+ ::svt::EmbeddedObjectRef(aAppletImpl.GetApplet(), embed::Aspects::MSOLE_CONTENT),
+ &aAppletImpl.GetItemSet());
+ xPropSet = SwXTextEmbeddedObject::CreateXTextEmbeddedObject(
+ *pDoc, pFrameFormat);
+ if( pDoc->getIDocumentDrawModelAccess().GetDrawModel() )
+ {
+ // req for z-order
+ SwXFrame::GetOrCreateSdrObject(*static_cast<SwFlyFrameFormat*>(pFrameFormat));
+ }
+
+ return xPropSet;
+}
+
+uno::Reference< XPropertySet > SwXMLTextImportHelper::createAndInsertPlugin(
+ const OUString &rMimeType,
+ const OUString& rHRef,
+ sal_Int32 nWidth, sal_Int32 nHeight )
+{
+ uno::Reference < XPropertySet > xPropSet;
+ OTextCursorHelper* pTextCursor = dynamic_cast<OTextCursorHelper*>(GetCursor().get());
+ assert( pTextCursor && "SwXTextCursor missing" );
+ SwDoc *pDoc = pTextCursor->GetDoc();
+
+ SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END> aItemSet( pDoc->GetAttrPool() );
+ lcl_putHeightAndWidth( aItemSet, nHeight, nWidth);
+
+ // We'll need a (valid) URL, or we need a MIME type. If we don't have
+ // either, do not insert plugin and return early. Copy URL into URL object
+ // on the way.
+ INetURLObject aURLObj;
+
+ bool bValidURL = !rHRef.isEmpty() &&
+ aURLObj.SetURL( URIHelper::SmartRel2Abs( INetURLObject( GetXMLImport().GetBaseURL() ), rHRef ) );
+ bool bValidMimeType = !rMimeType.isEmpty();
+ if( !bValidURL && !bValidMimeType )
+ return xPropSet;
+
+ uno::Reference < embed::XStorage > xStorage = comphelper::OStorageHelper::GetTemporaryStorage();
+ try
+ {
+ // create object with desired ClassId
+ uno::Sequence < sal_Int8 > aClass( SvGlobalName( SO3_PLUGIN_CLASSID ).GetByteSequence() );
+ uno::Reference < embed::XEmbeddedObjectCreator > xFactory = embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
+ uno::Reference < embed::XEmbeddedObject > xObj( xFactory->createInstanceInitNew(
+ aClass, OUString(), xStorage, "DummyName",
+ uno::Sequence < beans::PropertyValue >() ), uno::UNO_QUERY );
+
+ // set size to the object
+ lcl_setObjectVisualArea( xObj,
+ embed::Aspects::MSOLE_CONTENT,
+ Size( nWidth, nHeight ),
+ MapUnit::Map100thMM );
+
+ if ( svt::EmbeddedObjectRef::TryRunningState( xObj ) )
+ {
+ uno::Reference < beans::XPropertySet > xSet( xObj->getComponent(), uno::UNO_QUERY );
+ if ( xSet.is() )
+ {
+ if( bValidURL )
+ xSet->setPropertyValue("PluginURL",
+ Any( aURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) );
+ if( bValidMimeType )
+ xSet->setPropertyValue("PluginMimeType",
+ Any( rMimeType ) );
+ }
+
+ SwFrameFormat *const pFrameFormat =
+ pDoc->getIDocumentContentOperations().InsertEmbObject(
+ *pTextCursor->GetPaM(),
+ ::svt::EmbeddedObjectRef(xObj, embed::Aspects::MSOLE_CONTENT),
+ &aItemSet);
+ xPropSet = SwXTextEmbeddedObject::CreateXTextEmbeddedObject(
+ *pDoc, pFrameFormat);
+ if( pDoc->getIDocumentDrawModelAccess().GetDrawModel() )
+ {
+ SwXFrame::GetOrCreateSdrObject(*
+ static_cast<SwFlyFrameFormat*>(pFrameFormat)); // req for z-order
+ }
+ }
+ }
+ catch ( uno::Exception& )
+ {
+ }
+
+ return xPropSet;
+}
+uno::Reference< XPropertySet > SwXMLTextImportHelper::createAndInsertFloatingFrame(
+ const OUString& rName,
+ const OUString& rHRef,
+ const OUString& rStyleName,
+ sal_Int32 nWidth, sal_Int32 nHeight )
+{
+ // this method will modify the document directly -> lock SolarMutex
+ SolarMutexGuard aGuard;
+
+ uno::Reference < XPropertySet > xPropSet;
+ OTextCursorHelper* pTextCursor = dynamic_cast<OTextCursorHelper*>(GetCursor().get());
+ assert( pTextCursor && "SwXTextCursor missing" );
+ SwDoc *pDoc = pTextCursor->GetDoc();
+
+ SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END> aItemSet( pDoc->GetAttrPool() );
+ lcl_putHeightAndWidth( aItemSet, nHeight, nWidth);
+
+ ScrollingMode eScrollMode = ScrollingMode::Auto;
+ bool bHasBorder = false;
+ bool bIsBorderSet = false;
+ Size aMargin( SIZE_NOT_SET, SIZE_NOT_SET );
+ const XMLPropStyleContext *pStyle = nullptr;
+ if( !rStyleName.isEmpty() )
+ {
+ pStyle = FindAutoFrameStyle( rStyleName );
+ if( pStyle )
+ {
+ rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap =
+ pStyle->GetStyles()
+ ->GetImportPropertyMapper(pStyle->GetFamily());
+ OSL_ENSURE( xImpPrMap.is(), "Where is the import prop mapper?" );
+ if( xImpPrMap.is() )
+ {
+ rtl::Reference<XMLPropertySetMapper> rPropMapper =
+ xImpPrMap->getPropertySetMapper();
+
+ sal_Int32 nCount = pStyle->GetProperties().size();
+ for( sal_Int32 i=0; i < nCount; i++ )
+ {
+ const XMLPropertyState& rProp = pStyle->GetProperties()[i];
+ sal_Int32 nIdx = rProp.mnIndex;
+ if( -1 == nIdx )
+ continue;
+
+ switch( rPropMapper->GetEntryContextId(nIdx) )
+ {
+ case CTF_FRAME_DISPLAY_SCROLLBAR:
+ {
+ bool bYes = *o3tl::doAccess<bool>(rProp.maValue);
+ eScrollMode = bYes ? ScrollingMode::Yes : ScrollingMode::No;
+ }
+ break;
+ case CTF_FRAME_DISPLAY_BORDER:
+ {
+ bHasBorder = *o3tl::doAccess<bool>(rProp.maValue);
+ bIsBorderSet = true;
+ }
+ break;
+ case CTF_FRAME_MARGIN_HORI:
+ {
+ sal_Int32 nVal = SIZE_NOT_SET;
+ rProp.maValue >>= nVal;
+ aMargin.setWidth( nVal );
+ }
+ break;
+ case CTF_FRAME_MARGIN_VERT:
+ {
+ sal_Int32 nVal = SIZE_NOT_SET;
+ rProp.maValue >>= nVal;
+ aMargin.setHeight( nVal );
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ uno::Reference < embed::XStorage > xStorage = comphelper::OStorageHelper::GetTemporaryStorage();
+ try
+ {
+ // create object with desired ClassId
+ uno::Sequence < sal_Int8 > aClass( SvGlobalName( SO3_IFRAME_CLASSID ).GetByteSequence() );
+ uno::Reference < embed::XEmbeddedObjectCreator > xFactory = embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() );
+ uno::Reference < embed::XEmbeddedObject > xObj( xFactory->createInstanceInitNew(
+ aClass, OUString(), xStorage, "DummyName",
+ uno::Sequence < beans::PropertyValue >() ), uno::UNO_QUERY );
+
+ // set size to the object
+ lcl_setObjectVisualArea( xObj,
+ embed::Aspects::MSOLE_CONTENT,
+ Size( nWidth, nHeight ),
+ MapUnit::Map100thMM );
+
+ if ( svt::EmbeddedObjectRef::TryRunningState( xObj ) )
+ {
+ uno::Reference < beans::XPropertySet > xSet( xObj->getComponent(), uno::UNO_QUERY );
+ if ( xSet.is() )
+ {
+ OUString sHRef = URIHelper::SmartRel2Abs(
+ INetURLObject( GetXMLImport().GetBaseURL() ), rHRef );
+
+ if (INetURLObject(sHRef).IsExoticProtocol())
+ GetXMLImport().NotifyMacroEventRead();
+
+ xSet->setPropertyValue("FrameURL",
+ Any( sHRef ) );
+
+ xSet->setPropertyValue("FrameName",
+ Any( rName ) );
+
+ if ( eScrollMode == ScrollingMode::Auto )
+ xSet->setPropertyValue("FrameIsAutoScroll",
+ Any( true ) );
+ else
+ xSet->setPropertyValue("FrameIsScrollingMode",
+ Any( eScrollMode == ScrollingMode::Yes ) );
+
+ if ( bIsBorderSet )
+ xSet->setPropertyValue("FrameIsBorder",
+ Any( bHasBorder ) );
+ else
+ xSet->setPropertyValue("FrameIsAutoBorder",
+ Any( true ) );
+
+ xSet->setPropertyValue("FrameMarginWidth",
+ Any( sal_Int32( aMargin.Width() ) ) );
+
+ xSet->setPropertyValue("FrameMarginHeight",
+ Any( sal_Int32( aMargin.Height() ) ) );
+ }
+
+ SwFrameFormat *const pFrameFormat =
+ pDoc->getIDocumentContentOperations().InsertEmbObject(
+ *pTextCursor->GetPaM(),
+ ::svt::EmbeddedObjectRef(xObj, embed::Aspects::MSOLE_CONTENT),
+ &aItemSet);
+ xPropSet = SwXTextEmbeddedObject::CreateXTextEmbeddedObject(
+ *pDoc, pFrameFormat);
+ if( pDoc->getIDocumentDrawModelAccess().GetDrawModel() )
+ {
+ // req for z-order
+ SwXFrame::GetOrCreateSdrObject(*
+ static_cast<SwFlyFrameFormat*>(pFrameFormat));
+ }
+ }
+ }
+ catch ( uno::Exception& )
+ {
+ }
+
+ return xPropSet;
+}
+
+void SwXMLTextImportHelper::endAppletOrPlugin(
+ const uno::Reference < XPropertySet > &rPropSet,
+ std::map < const OUString, OUString > &rParamMap)
+{
+ // this method will modify the document directly -> lock SolarMutex
+ SolarMutexGuard aGuard;
+
+ SwXFrame* pFrame = dynamic_cast<SwXFrame*>(rPropSet.get());
+ assert(pFrame && "SwXFrame missing");
+ SwFrameFormat *pFrameFormat = pFrame->GetFrameFormat();
+ const SwFormatContent& rContent = pFrameFormat->GetContent();
+ const SwNodeIndex *pNdIdx = rContent.GetContentIdx();
+ SwOLENode *pOLENd = pNdIdx->GetNodes()[pNdIdx->GetIndex() + 1]->GetNoTextNode()->GetOLENode();
+ SwOLEObj& rOLEObj = pOLENd->GetOLEObj();
+
+ uno::Reference < embed::XEmbeddedObject > xEmbObj( rOLEObj.GetOleRef() );
+ if ( !svt::EmbeddedObjectRef::TryRunningState( xEmbObj ) )
+ return;
+
+ uno::Reference < beans::XPropertySet > xSet( xEmbObj->getComponent(), uno::UNO_QUERY );
+ if ( !xSet.is() )
+ return;
+
+ const sal_Int32 nCount = rParamMap.size();
+ uno::Sequence< beans::PropertyValue > aCommandSequence( nCount );
+
+ std::transform(rParamMap.begin(), rParamMap.end(), aCommandSequence.getArray(),
+ [](const auto& rParam)
+ {
+ return beans::PropertyValue(/* Name */ rParam.first,
+ /* Handle */ -1,
+ /* Value */ uno::Any(rParam.second),
+ /* State */ beans::PropertyState_DIRECT_VALUE);
+ });
+
+ // unfortunately the names of the properties are depending on the object
+ OUString aParaName("AppletCommands");
+ try
+ {
+ xSet->setPropertyValue( aParaName, Any( aCommandSequence ) );
+ }
+ catch ( uno::Exception& )
+ {
+ aParaName = "PluginCommands";
+ try
+ {
+ xSet->setPropertyValue( aParaName, Any( aCommandSequence ) );
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ }
+}
+
+// redlining helper methods
+// (override to provide the real implementation)
+void SwXMLTextImportHelper::RedlineAdd(
+ const OUString& rType,
+ const OUString& rId,
+ const OUString& rAuthor,
+ const OUString& rComment,
+ const util::DateTime& rDateTime,
+ const OUString& rMovedID,
+ bool bMergeLastPara)
+{
+ // create redline helper on demand
+ OSL_ENSURE(nullptr != m_pRedlineHelper, "helper should have been created in constructor");
+ if (nullptr != m_pRedlineHelper)
+ m_pRedlineHelper->Add(rType, rId, rAuthor, rComment, rDateTime, rMovedID,
+ bMergeLastPara);
+}
+
+uno::Reference<XTextCursor> SwXMLTextImportHelper::RedlineCreateText(
+ uno::Reference<XTextCursor> & rOldCursor,
+ const OUString& rId)
+{
+ uno::Reference<XTextCursor> xRet;
+
+ if (nullptr != m_pRedlineHelper)
+ {
+ xRet = m_pRedlineHelper->CreateRedlineTextSection(rOldCursor, rId);
+ }
+
+ return xRet;
+}
+
+void SwXMLTextImportHelper::RedlineSetCursor(
+ const OUString& rId,
+ bool bStart,
+ bool bIsOutsideOfParagraph)
+{
+ if (nullptr != m_pRedlineHelper) {
+ uno::Reference<XTextRange> xTextRange( GetCursor()->getStart() );
+ m_pRedlineHelper->SetCursor(rId, bStart, xTextRange,
+ bIsOutsideOfParagraph);
+ }
+ // else: ignore redline (wasn't added before, else we'd have a helper)
+}
+
+void SwXMLTextImportHelper::RedlineAdjustStartNodeCursor()
+{
+ OUString rId = GetOpenRedlineId();
+ if ((nullptr != m_pRedlineHelper) && !rId.isEmpty())
+ {
+ m_pRedlineHelper->AdjustStartNodeCursor(rId);
+ ResetOpenRedlineId();
+ }
+ // else: ignore redline (wasn't added before, or no open redline ID
+}
+
+void SwXMLTextImportHelper::SetShowChanges( bool bShowChanges )
+{
+ if ( nullptr != m_pRedlineHelper )
+ m_pRedlineHelper->SetShowChanges( bShowChanges );
+}
+
+void SwXMLTextImportHelper::SetRecordChanges( bool bRecordChanges )
+{
+ if ( nullptr != m_pRedlineHelper )
+ m_pRedlineHelper->SetRecordChanges( bRecordChanges );
+}
+
+void SwXMLTextImportHelper::SetChangesProtectionKey(
+ const Sequence<sal_Int8> & rKey )
+{
+ if ( nullptr != m_pRedlineHelper )
+ m_pRedlineHelper->SetProtectionKey( rKey );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmltexti.hxx b/sw/source/filter/xml/xmltexti.hxx
new file mode 100644
index 0000000000..886ce4c7ac
--- /dev/null
+++ b/sw/source/filter/xml/xmltexti.hxx
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SW_SOURCE_FILTER_XML_XMLTEXTI_HXX
+#define INCLUDED_SW_SOURCE_FILTER_XML_XMLTEXTI_HXX
+
+#include <xmloff/txtimp.hxx>
+
+class XMLRedlineImportHelper;
+class SvXMLImport;
+
+class SwXMLTextImportHelper : public XMLTextImportHelper
+{
+ XMLRedlineImportHelper *m_pRedlineHelper;
+
+protected:
+ virtual SvXMLImportContext *CreateTableChildContext(
+ SvXMLImport& rImport,
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList ) override;
+
+public:
+ SwXMLTextImportHelper(
+ const css::uno::Reference<css::frame::XModel>& rModel,
+ SwXMLImport& rImport,
+ const css::uno::Reference<css::beans::XPropertySet>& rInfoSet,
+ bool bInsertM, bool bStylesOnlyM,
+ bool bBlockM, bool bOrganizerM );
+ virtual ~SwXMLTextImportHelper() override;
+
+ virtual css::uno::Reference<css::beans::XPropertySet>
+ createAndInsertOLEObject( SvXMLImport& rImport,
+ const OUString& rHRef,
+ const OUString& rStyleName,
+ const OUString& rTableName,
+ sal_Int32 nWidth, sal_Int32 nHeight ) override;
+ virtual css::uno::Reference<css::beans::XPropertySet>
+ createAndInsertOOoLink( SvXMLImport& rImport,
+ const OUString& rHRef,
+ const OUString& rStyleName,
+ const OUString& rTableName,
+ sal_Int32 nWidth, sal_Int32 nHeight ) override;
+ virtual css::uno::Reference<css::beans::XPropertySet>
+ createAndInsertApplet(
+ const OUString &rName,
+ const OUString &rCode,
+ bool bMayScript,
+ const OUString& rHRef,
+ sal_Int32 nWidth, sal_Int32 nHeight ) override;
+
+ virtual css::uno::Reference<css::beans::XPropertySet>
+ createAndInsertPlugin(
+ const OUString &rMimeType,
+ const OUString& rHRef,
+ sal_Int32 nWidth, sal_Int32 nHeight ) override;
+
+ virtual css::uno::Reference<css::beans::XPropertySet>
+ createAndInsertFloatingFrame(
+ const OUString &rName,
+ const OUString &rHRef,
+ const OUString &rStyleName,
+ sal_Int32 nWidth, sal_Int32 nHeight ) override;
+
+ virtual void endAppletOrPlugin(
+ const css::uno::Reference < css::beans::XPropertySet > &rPropSet,
+ std::map < const OUString, OUString > &rParamMap) override;
+
+ virtual bool IsInHeaderFooter() const override;
+
+ // redlining helper methods
+ // (here is the real implementation)
+ virtual void RedlineAdd(
+ const OUString& rType, /// redline type (insert, del,... )
+ const OUString& rId, /// use to identify this redline
+ const OUString& rAuthor, /// name of the author
+ const OUString& rComment, /// redline comment
+ const css::util::DateTime& rDateTime, /// date+time
+ const OUString& rMovedID, /// redline move id, to find moveFrom/MoveTo parts
+ bool bMergeLastPara) override; /// merge last paragraph
+ virtual css::uno::Reference<css::text::XTextCursor> RedlineCreateText(
+ css::uno::Reference<css::text::XTextCursor> & rOldCursor, /// needed to get the document
+ const OUString& rId) override; /// ID used to RedlineAdd() call
+ virtual void RedlineSetCursor(
+ const OUString& rId, /// ID used to RedlineAdd() call
+ bool bStart, /// start or end Cursor
+ bool bIsOutsideOfParagraph) override;
+ virtual void RedlineAdjustStartNodeCursor() override;
+ virtual void SetShowChanges( bool bShowChanges ) override;
+ virtual void SetRecordChanges( bool bRecordChanges ) override;
+ virtual void SetChangesProtectionKey(
+ const css::uno::Sequence<sal_Int8> & rKey ) override;
+};
+
+#endif // INCLUDED_SW_SOURCE_FILTER_XML_XMLTEXTI_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/zorder.hxx b/sw/source/filter/xml/zorder.hxx
new file mode 100644
index 0000000000..11cf17ef9c
--- /dev/null
+++ b/sw/source/filter/xml/zorder.hxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <IDocumentDrawModelAccess.hxx>
+
+#include <o3tl/any.hxx>
+#include <o3tl/unreachable.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+
+namespace sw
+{
+struct GetZOrderLayer
+{
+ GetZOrderLayer(IDocumentDrawModelAccess const& rIDDMA)
+ : m_nHeavenId(rIDDMA.GetHeavenId().get())
+ , m_nHellId(rIDDMA.GetHellId().get())
+ , m_nControlsId(rIDDMA.GetControlsId().get())
+ , m_nInvisibleHeavenId(rIDDMA.GetInvisibleHeavenId().get())
+ , m_nInvisibleHellId(rIDDMA.GetInvisibleHellId().get())
+ , m_nInvisibleControlsId(rIDDMA.GetInvisibleControlsId().get())
+ {
+ }
+
+ auto operator()(css::uno::Reference<css::beans::XPropertySet> const& xShape) -> unsigned int
+ {
+ sal_Int16 nLayerID(0);
+ if (xShape->getPropertySetInfo()->hasPropertyByName("LayerID"))
+ {
+ xShape->getPropertyValue("LayerID") >>= nLayerID;
+ if (nLayerID == m_nHellId || nLayerID == m_nInvisibleHellId)
+ {
+ return 0;
+ }
+ else if (nLayerID == m_nHeavenId || nLayerID == m_nInvisibleHeavenId)
+ {
+ return 1;
+ }
+ else if (nLayerID == m_nControlsId || nLayerID == m_nInvisibleControlsId)
+ {
+ return 2;
+ }
+ O3TL_UNREACHABLE;
+ }
+ else // SwXFrame only has "Opaque"
+ {
+ if (*o3tl::doAccess<bool>(xShape->getPropertyValue("Opaque")))
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ }
+
+private:
+ sal_Int16 m_nHeavenId;
+ sal_Int16 m_nHellId;
+ sal_Int16 m_nControlsId;
+ sal_Int16 m_nInvisibleHeavenId;
+ sal_Int16 m_nInvisibleHellId;
+ sal_Int16 m_nInvisibleControlsId;
+};
+
+} // namespace sw
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */