summaryrefslogtreecommitdiff
path: root/writerfilter
diff options
context:
space:
mode:
Diffstat (limited to 'writerfilter')
-rw-r--r--writerfilter/inc/dmapper/resourcemodel.hxx7
-rw-r--r--writerfilter/source/dmapper/DomainMapper.cxx157
-rw-r--r--writerfilter/source/dmapper/DomainMapper.hxx2
-rw-r--r--writerfilter/source/dmapper/DomainMapperTableManager.cxx4
-rw-r--r--writerfilter/source/dmapper/DomainMapper_Impl.cxx13
-rw-r--r--writerfilter/source/dmapper/DomainMapper_Impl.hxx9
-rw-r--r--writerfilter/source/dmapper/LoggedResources.hxx2
-rw-r--r--writerfilter/source/dmapper/SdtHelper.cxx183
-rw-r--r--writerfilter/source/dmapper/SdtHelper.hxx59
-rw-r--r--writerfilter/source/ooxml/OOXMLDocumentImpl.cxx1
-rw-r--r--writerfilter/source/ooxml/model.xml34
11 files changed, 406 insertions, 65 deletions
diff --git a/writerfilter/inc/dmapper/resourcemodel.hxx b/writerfilter/inc/dmapper/resourcemodel.hxx
index 44e659235845..177c3cee9d6b 100644
--- a/writerfilter/inc/dmapper/resourcemodel.hxx
+++ b/writerfilter/inc/dmapper/resourcemodel.hxx
@@ -180,6 +180,11 @@ const sal_uInt8 cFieldStart = 0x13;
const sal_uInt8 cFieldSep = 0x14;
const sal_uInt8 cFieldEnd = 0x15;
+namespace ooxml
+{
+class OOXMLDocument;
+}
+
/**
Handler for a stream.
*/
@@ -205,6 +210,8 @@ public:
/// The current section is the last one in this body text.
virtual void markLastSectionGroup( ) { };
+ virtual void setDocumentReference(writerfilter::ooxml::OOXMLDocument* pDocument) = 0;
+
/**
Receives start mark for group with the same paragraph properties.
*/
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx
index c6d718790763..40b03086d596 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -183,6 +183,11 @@ DomainMapper::DomainMapper( const uno::Reference< uno::XComponentContext >& xCon
catch( const uno::Exception& ) {}
}
+void DomainMapper::setDocumentReference(writerfilter::ooxml::OOXMLDocument* pDocument)
+{
+ m_pImpl->setDocumentReference(pDocument);
+}
+
DomainMapper::~DomainMapper()
{
try
@@ -1019,6 +1024,11 @@ void DomainMapper::lcl_attribute(Id nName, Value & val)
}
break;
case NS_ooxml::LN_CT_SdtBlock_sdtContent:
+ if (m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::unknown)
+ {
+ // Still not determined content type? and it is even not unsupported? Then it is plain text field
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::plainText);
+ }
m_pImpl->SetSdt(true);
break;
case NS_ooxml::LN_CT_SdtBlock_sdtEndContent:
@@ -1031,10 +1041,20 @@ void DomainMapper::lcl_attribute(Id nName, Value & val)
else
m_pImpl->setSdtEndDeferred(true);
- if (m_pImpl->m_pSdtHelper->isInsideDropDownControl())
- m_pImpl->m_pSdtHelper->createDropDownControl();
- else if (m_pImpl->m_pSdtHelper->validateDateFormat())
- m_pImpl->m_pSdtHelper->createDateContentControl();
+ switch (m_pImpl->m_pSdtHelper->getControlType())
+ {
+ case SdtControlType::dropDown:
+ m_pImpl->m_pSdtHelper->createDropDownControl();
+ break;
+ case SdtControlType::plainText:
+ m_pImpl->m_pSdtHelper->createPlainTextControl();
+ break;
+ case SdtControlType::datePicker:
+ m_pImpl->m_pSdtHelper->createDateContentControl();
+ break;
+ case SdtControlType::unknown:
+ default:;
+ }
break;
case NS_ooxml::LN_CT_SdtListItem_displayText:
// TODO handle when this is != value
@@ -1098,14 +1118,26 @@ void DomainMapper::lcl_attribute(Id nName, Value & val)
}
break;
case NS_ooxml::LN_CT_DataBinding_prefixMappings:
+ m_pImpl->m_pSdtHelper->setDataBindingPrefixMapping(sStringValue);
m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_DataBinding_prefixMappings", sStringValue);
break;
case NS_ooxml::LN_CT_DataBinding_xpath:
+ m_pImpl->m_pSdtHelper->setDataBindingXPath(sStringValue);
m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_DataBinding_xpath", sStringValue);
break;
case NS_ooxml::LN_CT_DataBinding_storeItemID:
+ m_pImpl->m_pSdtHelper->setDataBindingStoreItemID(sStringValue);
m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_DataBinding_storeItemID", sStringValue);
break;
+ case NS_ooxml::LN_CT_SdtPlaceholder_docPart_val:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_SdtPlaceholder_docPart_val", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_SdtColor_val:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_SdtColor_val", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_SdtText_multiLine:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_SdtText_multiLine", sStringValue);
+ break;
case NS_ooxml::LN_CT_PTab_leader:
case NS_ooxml::LN_CT_PTab_relativeTo:
case NS_ooxml::LN_CT_PTab_alignment:
@@ -2542,7 +2574,7 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext )
case NS_ooxml::LN_CT_SdtPr_dropDownList:
case NS_ooxml::LN_CT_SdtPr_comboBox:
{
- m_pImpl->m_pSdtHelper->setInsideDropDownControl(true);
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::dropDown);
writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
if (pProperties.get() != nullptr)
pProperties->resolve(*this);
@@ -2555,8 +2587,17 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext )
pProperties->resolve(*this);
}
break;
+ case NS_ooxml::LN_CT_SdtPr_placeholder:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ break;
case NS_ooxml::LN_CT_SdtPr_date:
{
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::datePicker);
resolveSprmProps(*this, rSprm);
m_pImpl->m_pSdtHelper->setDateFieldStartRange(GetCurrentTextRange()->getEnd());
}
@@ -2579,6 +2620,17 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext )
m_pImpl->m_pSdtHelper->getLocale().append(sStringValue);
}
break;
+ case NS_ooxml::LN_CT_SdtPr_text:
+ {
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::plainText);
+ enableInteropGrabBag("ooxml:CT_SdtPr_text");
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(*this);
+ m_pImpl->m_pSdtHelper->appendToInteropGrabBag(getInteropGrabBag());
+ m_pImpl->disableInteropGrabBag();
+ }
+ break;
case NS_ooxml::LN_CT_SdtPr_dataBinding:
case NS_ooxml::LN_CT_SdtPr_equation:
case NS_ooxml::LN_CT_SdtPr_checkbox:
@@ -2587,9 +2639,10 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext )
case NS_ooxml::LN_CT_SdtPr_picture:
case NS_ooxml::LN_CT_SdtPr_citation:
case NS_ooxml::LN_CT_SdtPr_group:
- case NS_ooxml::LN_CT_SdtPr_text:
case NS_ooxml::LN_CT_SdtPr_id:
case NS_ooxml::LN_CT_SdtPr_alias:
+ case NS_ooxml::LN_CT_SdtPlaceholder_docPart:
+ case NS_ooxml::LN_CT_SdtPr_color:
{
// this is an unsupported SDT property, create a grab bag for it
OUString sName;
@@ -2603,11 +2656,21 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext )
case NS_ooxml::LN_CT_SdtPr_picture: sName = "ooxml:CT_SdtPr_picture"; break;
case NS_ooxml::LN_CT_SdtPr_citation: sName = "ooxml:CT_SdtPr_citation"; break;
case NS_ooxml::LN_CT_SdtPr_group: sName = "ooxml:CT_SdtPr_group"; break;
- case NS_ooxml::LN_CT_SdtPr_text: sName = "ooxml:CT_SdtPr_text"; break;
case NS_ooxml::LN_CT_SdtPr_id: sName = "ooxml:CT_SdtPr_id"; break;
case NS_ooxml::LN_CT_SdtPr_alias: sName = "ooxml:CT_SdtPr_alias"; break;
+ case NS_ooxml::LN_CT_SdtPlaceholder_docPart: sName = "ooxml:CT_SdtPlaceholder_docPart"; break;
+ case NS_ooxml::LN_CT_SdtPr_color: sName = "ooxml:CT_SdtPr_color"; break;
default: assert(false);
};
+ if (
+ nSprmId == NS_ooxml::LN_CT_SdtPr_checkbox ||
+ nSprmId == NS_ooxml::LN_CT_SdtPr_docPartObj ||
+ nSprmId == NS_ooxml::LN_CT_SdtPr_docPartList ||
+ nSprmId == NS_ooxml::LN_CT_SdtPr_picture ||
+ nSprmId == NS_ooxml::LN_CT_SdtPr_citation)
+ {
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::unsupported);
+ }
enableInteropGrabBag(sName);
// process subitems
@@ -3385,7 +3448,7 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, size_t len)
}
bool bNewLine = len == 1 && (sText[0] == 0x0d || sText[0] == 0x07);
- if (m_pImpl->m_pSdtHelper->isInsideDropDownControl())
+ if (m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::dropDown)
{
if (bNewLine)
// Dropdown control has single-line texts, so in case of newline, create the control.
@@ -3396,43 +3459,54 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, size_t len)
return;
}
}
+ else if (m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::datePicker)
+ {
+ if (IsInHeaderFooter() && m_pImpl->IsDiscardHeaderFooter())
+ {
+ m_pImpl->m_pSdtHelper->getDateFormat().truncate();
+ m_pImpl->m_pSdtHelper->getLocale().truncate();
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::unknown);
+ return;
+ }
+ }
+ else if (m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::plainText)
+ {
+ m_pImpl->m_pSdtHelper->getSdtTexts().append(sText);
+ if (bNewLine)
+ {
+ m_pImpl->m_pSdtHelper->createPlainTextControl();
+ finishParagraph();
+ }
+ return;
+ }
else if (!m_pImpl->m_pSdtHelper->isInteropGrabBagEmpty())
{
- // Ignore grabbag when we have a date field, it can conflict during export
- if(m_pImpl->m_pSdtHelper->validateDateFormat())
+ // there are unsupported SDT properties in the document
+ // save them in the paragraph interop grab bag
+ if (m_pImpl->IsDiscardHeaderFooter())
{
+ // Unless we're supposed to ignore this header/footer.
m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear();
+ return;
}
- else
+ if((m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_checkbox") ||
+ m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_text") ||
+ m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_dataBinding") ||
+ m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_citation") ||
+ (m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_id") &&
+ m_pImpl->m_pSdtHelper->getInteropGrabBagSize() == 1)) && !m_pImpl->m_pSdtHelper->isOutsideAParagraph())
{
+ PropertyMapPtr pContext = m_pImpl->GetTopContextOfType(CONTEXT_CHARACTER);
- // there are unsupported SDT properties in the document
- // save them in the paragraph interop grab bag
- if (m_pImpl->IsDiscardHeaderFooter())
- {
- // Unless we're supposed to ignore this header/footer.
- m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear();
- return;
- }
- if((m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_checkbox") ||
- m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_text") ||
- m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_dataBinding") ||
- m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_citation") ||
- (m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_id") &&
- m_pImpl->m_pSdtHelper->getInteropGrabBagSize() == 1)) && !m_pImpl->m_pSdtHelper->isOutsideAParagraph())
- {
- PropertyMapPtr pContext = m_pImpl->GetTopContextOfType(CONTEXT_CHARACTER);
+ if (m_pImpl->IsOpenField())
+ // We have a field, insert the SDT properties to the field's grab-bag, so they won't be lost.
+ pContext = m_pImpl->GetTopFieldContext()->getProperties();
- if (m_pImpl->IsOpenField())
- // We have a field, insert the SDT properties to the field's grab-bag, so they won't be lost.
- pContext = m_pImpl->GetTopFieldContext()->getProperties();
-
- pContext->Insert(PROP_SDTPR, uno::makeAny(m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear()), true, CHAR_GRAB_BAG);
- }
- else
- m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH)->Insert(PROP_SDTPR,
- uno::makeAny(m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear()), true, PARA_GRAB_BAG);
+ pContext->Insert(PROP_SDTPR, uno::makeAny(m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear()), true, CHAR_GRAB_BAG);
}
+ else
+ m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH)->Insert(PROP_SDTPR,
+ uno::makeAny(m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear()), true, PARA_GRAB_BAG);
}
else if (len == 1 && sText[0] == 0x03)
{
@@ -3458,15 +3532,6 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, size_t len)
return;
}
}
- else if (m_pImpl->m_pSdtHelper->validateDateFormat())
- {
- if(IsInHeaderFooter() && m_pImpl->IsDiscardHeaderFooter())
- {
- m_pImpl->m_pSdtHelper->getDateFormat().truncate();
- m_pImpl->m_pSdtHelper->getLocale().truncate();
- return;
- }
- }
if (!m_pImpl->hasTableManager())
return;
@@ -4016,7 +4081,7 @@ void DomainMapper::HandleRedline( Sprm& rSprm )
void DomainMapper::finishParagraph(const bool bRemove)
{
- if (m_pImpl->m_pSdtHelper->validateDateFormat())
+ if (m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::datePicker)
m_pImpl->m_pSdtHelper->createDateContentControl();
m_pImpl->finishParagraph(m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH), bRemove);
}
diff --git a/writerfilter/source/dmapper/DomainMapper.hxx b/writerfilter/source/dmapper/DomainMapper.hxx
index b2c2ba63d9a0..e606e8369cd1 100644
--- a/writerfilter/source/dmapper/DomainMapper.hxx
+++ b/writerfilter/source/dmapper/DomainMapper.hxx
@@ -81,6 +81,8 @@ public:
utl::MediaDescriptor const & rMediaDesc);
virtual ~DomainMapper() override;
+ virtual void setDocumentReference(writerfilter::ooxml::OOXMLDocument* pDocument) override;
+
// Stream
virtual void markLastParagraphInSection() override;
virtual void markLastSectionGroup() override;
diff --git a/writerfilter/source/dmapper/DomainMapperTableManager.cxx b/writerfilter/source/dmapper/DomainMapperTableManager.cxx
index 618ca603efe6..b5040c230b62 100644
--- a/writerfilter/source/dmapper/DomainMapperTableManager.cxx
+++ b/writerfilter/source/dmapper/DomainMapperTableManager.cxx
@@ -392,6 +392,8 @@ bool DomainMapperTableManager::sprm(Sprm & rSprm)
DomainMapperTableManager::IntVectorPtr const & DomainMapperTableManager::getCurrentGrid( )
{
+ if (m_aTableGrid.empty())
+ throw std::out_of_range("no current grid");
return m_aTableGrid.back( );
}
@@ -552,6 +554,8 @@ void DomainMapperTableManager::endOfRowAction()
// Compare the table position with the previous ones. We may need to split
// into two tables if those are different. We surely don't want to do anything
// if we don't have any row yet.
+ if (m_aTmpPosition.empty())
+ throw std::out_of_range("row without a position");
TablePositionHandlerPtr pTmpPosition = m_aTmpPosition.back();
TablePropertyMapPtr pTablePropMap = m_aTmpTableProperties.back( );
TablePositionHandlerPtr pCurrentPosition = m_aTablePositions.back();
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 82c13df4f7ef..8803603227df 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -270,6 +270,7 @@ DomainMapper_Impl::DomainMapper_Impl(
utl::MediaDescriptor const & rMediaDesc) :
m_eDocumentType( eDocumentType ),
m_rDMapper( rDMapper ),
+ m_pOOXMLDocument(nullptr),
m_xTextDocument( xModel, uno::UNO_QUERY ),
m_xTextFactory( xModel, uno::UNO_QUERY ),
m_xComponentContext( xContext ),
@@ -354,6 +355,11 @@ DomainMapper_Impl::DomainMapper_Impl(
appendTableManager( );
GetBodyText();
+ if (!m_bIsNewDoc && !m_xBodyText)
+ {
+ throw uno::Exception("failed to find body text of the insert position", nullptr);
+ }
+
uno::Reference< text::XTextAppend > xBodyTextAppend( m_xBodyText, uno::UNO_QUERY );
m_aTextAppendStack.push(TextAppendContext(xBodyTextAppend,
m_bIsNewDoc ? uno::Reference<text::XTextCursor>() : m_xBodyText->createTextCursorByRange(m_xInsertTextRange)));
@@ -366,7 +372,7 @@ DomainMapper_Impl::DomainMapper_Impl(
getTableManager( ).startLevel();
m_bUsingEnhancedFields = !utl::ConfigManager::IsFuzzing() && officecfg::Office::Common::Filter::Microsoft::Import::ImportWWFieldsAsEnhancedFields::get(m_xComponentContext);
- m_pSdtHelper = new SdtHelper(*this);
+ m_pSdtHelper = new SdtHelper(*this, m_xComponentContext);
m_aRedlines.push(std::vector<RedlineParamsPtr>());
@@ -390,6 +396,11 @@ DomainMapper_Impl::~DomainMapper_Impl()
}
}
+writerfilter::ooxml::OOXMLDocument* DomainMapper_Impl::getDocumentReference() const
+{
+ return m_pOOXMLDocument;
+}
+
uno::Reference< container::XNameContainer > const & DomainMapper_Impl::GetPageStyles()
{
if(!m_xPageStyles1.is())
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
index 668461bc978a..43c2a2b85b8d 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
@@ -75,6 +75,11 @@ namespace com{ namespace sun{ namespace star{
}}}
namespace writerfilter {
+
+namespace ooxml {
+ class OOXMLDocument;
+}
+
namespace dmapper {
class SdtHelper;
@@ -436,6 +441,7 @@ public:
private:
SourceDocumentType const m_eDocumentType;
DomainMapper& m_rDMapper;
+ writerfilter::ooxml::OOXMLDocument* m_pOOXMLDocument;
OUString m_aBaseUrl;
css::uno::Reference<css::text::XTextDocument> m_xTextDocument;
css::uno::Reference<css::beans::XPropertySet> m_xDocumentSettings;
@@ -602,6 +608,9 @@ public:
utl::MediaDescriptor const & rMediaDesc);
~DomainMapper_Impl();
+ void setDocumentReference(writerfilter::ooxml::OOXMLDocument* pDocument) { if (!m_pOOXMLDocument) m_pOOXMLDocument = pDocument; };
+ writerfilter::ooxml::OOXMLDocument* getDocumentReference() const;
+
SectionPropertyMap* GetLastSectionContext( )
{
return dynamic_cast< SectionPropertyMap* >( m_pLastSectionContext.get( ) );
diff --git a/writerfilter/source/dmapper/LoggedResources.hxx b/writerfilter/source/dmapper/LoggedResources.hxx
index 3177224d4664..d89376bd679f 100644
--- a/writerfilter/source/dmapper/LoggedResources.hxx
+++ b/writerfilter/source/dmapper/LoggedResources.hxx
@@ -72,6 +72,8 @@ public:
void startGlossaryEntry() override;
void endGlossaryEntry() override;
+ virtual void setDocumentReference(writerfilter::ooxml::OOXMLDocument* /*pDocument*/) override{};
+
protected:
virtual void lcl_startSectionGroup() = 0;
virtual void lcl_endSectionGroup() = 0;
diff --git a/writerfilter/source/dmapper/SdtHelper.cxx b/writerfilter/source/dmapper/SdtHelper.cxx
index 154e7660d842..8a2356051a21 100644
--- a/writerfilter/source/dmapper/SdtHelper.cxx
+++ b/writerfilter/source/dmapper/SdtHelper.cxx
@@ -12,20 +12,33 @@
#include <com/sun/star/drawing/XControlShape.hpp>
#include <com/sun/star/text/VertOrientation.hpp>
#include <editeng/unoprnms.hxx>
+#include <sal/log.hxx>
#include <vcl/svapp.hxx>
#include <vcl/outdev.hxx>
+#include <comphelper/string.hxx>
#include <comphelper/sequence.hxx>
#include <xmloff/odffields.hxx>
#include <com/sun/star/text/XTextField.hpp>
#include "DomainMapper_Impl.hxx"
#include "StyleSheetTable.hxx"
#include <officecfg/Office/Writer.hxx>
+#include <com/sun/star/util/XRefreshable.hpp>
+#include <com/sun/star/text/XTextFieldsSupplier.hpp>
+#include <com/sun/star/document/XOOXMLDocumentPropertiesImporter.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <ooxml/OOXMLDocument.hxx>
+#include <com/sun/star/xml/xpath/XPathAPI.hpp>
+#include <com/sun/star/xml/dom/DocumentBuilder.hpp>
+#include <com/sun/star/xml/dom/XNode.hpp>
namespace writerfilter
{
namespace dmapper
+
{
using namespace ::com::sun::star;
+using namespace ::css::xml::xpath;
+using namespace ::comphelper;
/// w:sdt's w:dropDownList doesn't have width, so guess the size based on the longest string.
static awt::Size lcl_getOptimalWidth(const StyleSheetTablePtr& pStyleSheet,
@@ -68,19 +81,139 @@ static awt::Size lcl_getOptimalWidth(const StyleSheetTablePtr& pStyleSheet,
return { nWidth + nBorder + nHeight, nHeight + nBorder };
}
-SdtHelper::SdtHelper(DomainMapper_Impl& rDM_Impl)
+SdtHelper::SdtHelper(DomainMapper_Impl& rDM_Impl,
+ css::uno::Reference<css::uno::XComponentContext> const& xContext)
: m_rDM_Impl(rDM_Impl)
- , m_bInsideDropDownControl(false)
+ , m_xComponentContext(xContext)
+ , m_aControlType(SdtControlType::unknown)
, m_bHasElements(false)
, m_bOutsideAParagraph(false)
+ , m_bPropertiesXMLsLoaded(false)
{
}
SdtHelper::~SdtHelper() = default;
+void SdtHelper::loadPropertiesXMLs()
+{
+ // Initialize properties xml storage (m_xPropertiesXMLs)
+ uno::Reference<uno::XInterface> xTemp
+ = m_xComponentContext->getServiceManager()->createInstanceWithContext(
+ "com.sun.star.document.OOXMLDocumentPropertiesImporter", m_xComponentContext);
+ uno::Reference<document::XOOXMLDocumentPropertiesImporter> xImporter(xTemp, uno::UNO_QUERY);
+ if (!xImporter.is())
+ return;
+
+ uno::Reference<xml::dom::XDocumentBuilder> xDomBuilder(
+ xml::dom::DocumentBuilder::create(m_xComponentContext));
+ if (!xDomBuilder.is())
+ return;
+
+ std::vector<uno::Reference<xml::dom::XDocument>> aPropDocs;
+
+ // Load core properties
+ try
+ {
+ auto xCorePropsStream = xImporter->getCorePropertiesStream(m_rDM_Impl.m_xDocumentStorage);
+ aPropDocs.push_back(xDomBuilder->parse(xCorePropsStream));
+ }
+ catch (const uno::Exception&)
+ {
+ SAL_WARN("writerfilter",
+ "SdtHelper::loadPropertiesXMLs: failed loading core properties XML");
+ }
+
+ // Load extended properties
+ try
+ {
+ auto xExtPropsStream
+ = xImporter->getExtendedPropertiesStream(m_rDM_Impl.m_xDocumentStorage);
+ aPropDocs.push_back(xDomBuilder->parse(xExtPropsStream));
+ }
+ catch (const uno::Exception&)
+ {
+ SAL_WARN("writerfilter",
+ "SdtHelper::loadPropertiesXMLs: failed loading extended properties XML");
+ }
+
+ // TODO: some other property items?
+
+ // Add custom XMLs
+ uno::Sequence<uno::Reference<xml::dom::XDocument>> aCustomXmls
+ = m_rDM_Impl.getDocumentReference()->getCustomXmlDomList();
+ for (const auto& xDoc : aCustomXmls)
+ {
+ aPropDocs.push_back(xDoc);
+ }
+
+ m_xPropertiesXMLs = comphelper::containerToSequence(aPropDocs);
+ m_bPropertiesXMLsLoaded = true;
+}
+
+static void lcl_registerNamespaces(const OUString& sNamespaceString,
+ const uno::Reference<XXPathAPI>& xXPathAPI)
+{
+ // Split namespaces and register it in XPathAPI
+ auto aNamespaces = string::split(sNamespaceString, ' ');
+ for (const auto& sNamespace : aNamespaces)
+ {
+ // Here we have just one namespace in format "xmlns:ns0='http://someurl'"
+ auto aNamespace = string::split(sNamespace, '=');
+ if (aNamespace.size() < 2)
+ {
+ SAL_WARN("writerfilter",
+ "SdtHelper::getValueFromDataBinding: invalid namespace: " << sNamespace);
+ continue;
+ }
+
+ auto aNamespaceId = string::split(aNamespace[0], ':');
+ if (aNamespaceId.size() < 2)
+ {
+ SAL_WARN("writerfilter",
+ "SdtHelper::getValueFromDataBinding: invalid namespace: " << aNamespace[0]);
+ continue;
+ }
+
+ OUString sNamespaceURL = aNamespace[1];
+ sNamespaceURL = string::strip(sNamespaceURL, ' ');
+ sNamespaceURL = string::strip(sNamespaceURL, '\'');
+
+ xXPathAPI->registerNS(aNamespaceId[1], sNamespaceURL);
+ }
+}
+
+std::optional<OUString> SdtHelper::getValueFromDataBinding()
+{
+ // No xpath - nothing to do
+ if (m_sDataBindingXPath.isEmpty())
+ return {};
+
+ // Load properties XMLs
+ if (!m_bPropertiesXMLsLoaded)
+ loadPropertiesXMLs();
+
+ uno::Reference<XXPathAPI> xXpathAPI = XPathAPI::create(m_xComponentContext);
+
+ lcl_registerNamespaces(m_sDataBindingPrefixMapping, xXpathAPI);
+
+ // Iterate all properties xml documents and try to fetch data
+ for (const auto& xDocument : m_xPropertiesXMLs)
+ {
+ uno::Reference<XXPathObject> xResult = xXpathAPI->eval(xDocument, m_sDataBindingXPath);
+
+ if (xResult.is() && xResult->getNodeList() && xResult->getNodeList()->getLength())
+ {
+ return xResult->getString();
+ }
+ }
+
+ // No data
+ return {};
+}
+
void SdtHelper::createDropDownControl()
{
- assert(m_bInsideDropDownControl);
+ assert(getControlType() == SdtControlType::dropDown);
const bool bDropDown
= officecfg::Office::Writer::Filter::Import::DOCX::ImportComboBoxAsDropDown::get();
@@ -135,12 +268,39 @@ void SdtHelper::createDropDownControl()
// clean up
m_aDropDownItems.clear();
- m_bInsideDropDownControl = false;
+ setControlType(SdtControlType::unknown);
}
-bool SdtHelper::validateDateFormat()
+void SdtHelper::createPlainTextControl()
{
- return !m_sDateFormat.toString().isEmpty() && !m_sLocale.toString().isEmpty();
+ assert(getControlType() == SdtControlType::plainText);
+
+ OUString aDefaultText = m_aSdtTexts.makeStringAndClear();
+
+ // create field
+ uno::Reference<css::text::XTextField> xControlModel(
+ m_rDM_Impl.GetTextFactory()->createInstance("com.sun.star.text.TextField.Input"),
+ uno::UNO_QUERY);
+
+ // set properties
+ uno::Reference<beans::XPropertySet> xPropertySet(xControlModel, uno::UNO_QUERY);
+
+ std::optional<OUString> oData = getValueFromDataBinding();
+ if (oData.has_value())
+ aDefaultText = *oData;
+
+ xPropertySet->setPropertyValue("Content", uno::makeAny(aDefaultText));
+
+ // add it into document
+ m_rDM_Impl.appendTextContent(xControlModel, uno::Sequence<beans::PropertyValue>());
+
+ // Store all unused sdt parameters from grabbag
+ xPropertySet->setPropertyValue(UNO_NAME_MISC_OBJ_INTEROPGRABBAG,
+ uno::makeAny(getInteropGrabBagAndClear()));
+
+ // clean up
+ m_aDropDownItems.clear();
+ setControlType(SdtControlType::unknown);
}
void SdtHelper::createDateContentControl()
@@ -194,6 +354,11 @@ void SdtHelper::createDateContentControl()
uno::makeAny(m_sLocale.makeStringAndClear()));
}
OUString sFullDate = m_sDate.makeStringAndClear();
+
+ std::optional<OUString> oData = getValueFromDataBinding();
+ if (oData.has_value())
+ sFullDate = *oData;
+
if (!sFullDate.isEmpty())
{
sal_Int32 nTimeSep = sFullDate.indexOf("T");
@@ -201,8 +366,14 @@ void SdtHelper::createDateContentControl()
sFullDate = sFullDate.copy(0, nTimeSep);
xNameCont->insertByName(ODF_FORMDATE_CURRENTDATE, uno::makeAny(sFullDate));
}
+
+ // Store all unused sdt parameters from grabbag
+ xNameCont->insertByName(UNO_NAME_MISC_OBJ_INTEROPGRABBAG,
+ uno::makeAny(getInteropGrabBagAndClear()));
}
}
+
+ setControlType(SdtControlType::unknown);
}
void SdtHelper::createControlShape(awt::Size aSize,
diff --git a/writerfilter/source/dmapper/SdtHelper.hxx b/writerfilter/source/dmapper/SdtHelper.hxx
index 3cce8e3658af..e206cdc33cbe 100644
--- a/writerfilter/source/dmapper/SdtHelper.hxx
+++ b/writerfilter/source/dmapper/SdtHelper.hxx
@@ -11,9 +11,12 @@
#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_SDTHELPER_HXX
#include <vector>
+#include <optional>
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/xml/dom/XDocument.hpp>
#include <rtl/ustrbuf.hxx>
#include <tools/ref.hxx>
@@ -24,6 +27,10 @@ namespace sun
{
namespace star
{
+namespace uno
+{
+class XComponentContext;
+}
namespace awt
{
struct Size;
@@ -39,6 +46,15 @@ namespace dmapper
{
class DomainMapper_Impl;
+enum class SdtControlType
+{
+ datePicker,
+ dropDown,
+ plainText,
+ unsupported, // Sdt block is defined, but we still do not support such type of field
+ unknown
+};
+
/**
* Helper to create form controls from w:sdt tokens.
*
@@ -48,17 +64,26 @@ class DomainMapper_Impl;
class SdtHelper final : public virtual SvRefBase
{
DomainMapper_Impl& m_rDM_Impl;
+ css::uno::Reference<css::uno::XComponentContext> m_xComponentContext;
/// Items of the drop-down control.
std::vector<OUString> m_aDropDownItems;
- /// Indicator of a drop-down control
- bool m_bInsideDropDownControl;
+ /// Type of sdt control
+ SdtControlType m_aControlType;
/// Pieces of the default text -- currently used only by the dropdown control.
OUStringBuffer m_aSdtTexts;
/// Date ISO string contained in the w:date element, used by the date control.
OUStringBuffer m_sDate;
/// Date format string as it comes from the ooxml document.
OUStringBuffer m_sDateFormat;
+
+ /// <w:dataBinding w:prefixMappings="">
+ OUString m_sDataBindingPrefixMapping;
+ /// <w:dataBinding w:xpath="">
+ OUString m_sDataBindingXPath;
+ /// <w:dataBinding w:storeItemID="">
+ OUString m_sDataBindingStoreItemID;
+
/// Start range of the date field
css::uno::Reference<css::text::XTextRange> m_xDateFieldStartRange;
/// Locale string as it comes from the ooxml document.
@@ -70,13 +95,25 @@ class SdtHelper final : public virtual SvRefBase
/// The last stored SDT element is outside paragraphs.
bool m_bOutsideAParagraph;
+ /// Storage for all properties documents as xml::dom::XDocument for later querying xpath for data
+ css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument>> m_xPropertiesXMLs;
+
+ /// Check if m_xPropertiesXMLs is initialized and loaded (need extra flag to distinguish
+ /// empty sequence from not yet initialized)
+ bool m_bPropertiesXMLsLoaded;
+
/// Create and append the drawing::XControlShape, containing the various models.
void createControlShape(css::awt::Size aSize,
css::uno::Reference<css::awt::XControlModel> const& xControlModel,
const css::uno::Sequence<css::beans::PropertyValue>& rGrabBag);
+ std::optional<OUString> getValueFromDataBinding();
+
+ void loadPropertiesXMLs();
+
public:
- explicit SdtHelper(DomainMapper_Impl& rDM_Impl);
+ explicit SdtHelper(DomainMapper_Impl& rDM_Impl,
+ css::uno::Reference<css::uno::XComponentContext> const& xContext);
~SdtHelper() override;
std::vector<OUString>& getDropDownItems() { return m_aDropDownItems; }
@@ -86,14 +123,18 @@ public:
OUStringBuffer& getDateFormat() { return m_sDateFormat; }
+ void setDataBindingPrefixMapping(const OUString& sValue)
+ {
+ m_sDataBindingPrefixMapping = sValue;
+ }
+ void setDataBindingXPath(const OUString& sValue) { m_sDataBindingXPath = sValue; }
+ void setDataBindingStoreItemID(const OUString& sValue) { m_sDataBindingStoreItemID = sValue; }
+
void setDateFieldStartRange(const css::uno::Reference<css::text::XTextRange>& xStartRange)
{
m_xDateFieldStartRange = xStartRange;
}
- /// Decides if we have enough information to create a date control.
- bool validateDateFormat();
-
OUStringBuffer& getLocale() { return m_sLocale; }
/// If createControlShape() was ever called.
bool hasElements() const { return m_bHasElements; }
@@ -105,14 +146,16 @@ public:
bool isOutsideAParagraph() const { return m_bOutsideAParagraph; }
- bool isInsideDropDownControl() const { return m_bInsideDropDownControl; }
- void setInsideDropDownControl(bool bInside) { m_bInsideDropDownControl = bInside; }
+ SdtControlType getControlType() { return m_aControlType; }
+ void setControlType(SdtControlType aType) { m_aControlType = aType; }
/// Create drop-down control from w:sdt's w:dropDownList.
void createDropDownControl();
/// Create date control from w:sdt's w:date.
void createDateContentControl();
+ void createPlainTextControl();
+
void appendToInteropGrabBag(const css::beans::PropertyValue& rValue);
css::uno::Sequence<css::beans::PropertyValue> getInteropGrabBagAndClear();
bool isInteropGrabBagEmpty() const;
diff --git a/writerfilter/source/ooxml/OOXMLDocumentImpl.cxx b/writerfilter/source/ooxml/OOXMLDocumentImpl.cxx
index 2df01a68f27c..e8449752c77b 100644
--- a/writerfilter/source/ooxml/OOXMLDocumentImpl.cxx
+++ b/writerfilter/source/ooxml/OOXMLDocumentImpl.cxx
@@ -478,6 +478,7 @@ void OOXMLDocumentImpl::resolve(Stream & rStream)
{
uno::Reference<uno::XComponentContext> xContext(mpStream->getContext());
+ rStream.setDocumentReference(this);
OOXMLFastDocumentHandler * pDocHandler =
new OOXMLFastDocumentHandler(xContext, &rStream, this, mnXNoteId);
pDocHandler->setIsSubstream( mbIsSubstream );
diff --git a/writerfilter/source/ooxml/model.xml b/writerfilter/source/ooxml/model.xml
index 969eca1d84e3..f5b0e597a737 100644
--- a/writerfilter/source/ooxml/model.xml
+++ b/writerfilter/source/ooxml/model.xml
@@ -13903,9 +13903,14 @@
<data type="string"/>
</attribute>
</define>
- <define name="CT_Placeholder">
+ <define name="CT_SdtPlaceholderDocPart">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SdtPlaceholder">
<element name="docPart">
- <ref name="CT_String"/>
+ <ref name="CT_SdtPlaceholderDocPart"/>
</element>
</define>
<define name="CT_SdtText">
@@ -13924,6 +13929,11 @@
<data type="string"/>
</attribute>
</define>
+ <define name="CT_SdtColor">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
<define name="CT_SdtPr">
<choice>
<element name="rPr">
@@ -13936,7 +13946,7 @@
<ref name="CT_Lock"/>
</element>
<element name="placeholder">
- <ref name="CT_Placeholder"/>
+ <ref name="CT_SdtPlaceholder"/>
</element>
<element name="showingPlcHdr">
<ref name="CT_OnOff"/>
@@ -13981,7 +13991,7 @@
<ref name="CT_Empty"/>
</element>
<element name="text">
- <ref name="CT_OnOff"/>
+ <ref name="CT_SdtText"/>
</element>
<element name="citation">
<ref name="CT_OnOff"/>
@@ -13992,6 +14002,9 @@
<element name="bibliography">
<ref name="CT_Empty"/>
</element>
+ <element name="w15:color">
+ <ref name="CT_SdtColor"/>
+ </element>
</choice>
</define>
<define name="CT_SdtEndPr">
@@ -18222,11 +18235,20 @@
<attribute name="val" tokenid="ooxml:CT_CalendarType_val" action="setValue"/>
<action name="start" action="setDefaultStringValue"/>
</resource>
+ <resource name="CT_SdtText" resource="Properties">
+ <attribute name="multiLine" tokenid="ooxml:CT_SdtText_multiLine"/>
+ </resource>
+ <resource name="CT_SdtPlaceholder" resource="Properties">
+ <attribute name="docPart" tokenid="ooxml:CT_SdtPlaceholder_docPart"/>
+ </resource>
<resource name="CT_DataBinding" resource="Properties">
<attribute name="prefixMappings" tokenid="ooxml:CT_DataBinding_prefixMappings"/>
<attribute name="xpath" tokenid="ooxml:CT_DataBinding_xpath"/>
<attribute name="storeItemID" tokenid="ooxml:CT_DataBinding_storeItemID"/>
</resource>
+ <resource name="CT_SdtColor" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_SdtColor_val"/>
+ </resource>
<resource name="CT_SdtPr" resource="Properties">
<element name="rPr" tokenid="ooxml:CT_SdtPr_rPr"/>
<element name="alias" tokenid="ooxml:CT_SdtPr_alias"/>
@@ -18250,6 +18272,7 @@
<element name="citation" tokenid="ooxml:CT_SdtPr_citation"/>
<element name="group" tokenid="ooxml:CT_SdtPr_group"/>
<element name="bibliography" tokenid="ooxml:CT_SdtPr_bibliography"/>
+ <element name="w15:color" tokenid="ooxml:CT_SdtPr_color"/>
</resource>
<resource name="CT_SdtEndPr" resource="Properties">
<element name="rPr" tokenid="ooxml:CT_SdtEndPr_rPr"/>
@@ -18314,6 +18337,9 @@
<attribute name="displayText" tokenid="ooxml:CT_SdtListItem_displayText"/>
<attribute name="value" tokenid="ooxml:CT_SdtListItem_value"/>
</resource>
+ <resource name="CT_SdtPlaceholderDocPart" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_SdtPlaceholder_docPart_val"/>
+ </resource>
<resource name="CT_Attr" resource="Properties">
<attribute name="uri" tokenid="ooxml:CT_Attr_uri"/>
<attribute name="name" tokenid="ooxml:CT_Attr_name"/>