diff options
Diffstat (limited to 'writerfilter')
-rw-r--r-- | writerfilter/inc/dmapper/resourcemodel.hxx | 7 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper.cxx | 157 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper.hxx | 2 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapperTableManager.cxx | 4 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper_Impl.cxx | 13 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper_Impl.hxx | 9 | ||||
-rw-r--r-- | writerfilter/source/dmapper/LoggedResources.hxx | 2 | ||||
-rw-r--r-- | writerfilter/source/dmapper/SdtHelper.cxx | 183 | ||||
-rw-r--r-- | writerfilter/source/dmapper/SdtHelper.hxx | 59 | ||||
-rw-r--r-- | writerfilter/source/ooxml/OOXMLDocumentImpl.cxx | 1 | ||||
-rw-r--r-- | writerfilter/source/ooxml/model.xml | 34 |
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"/> |