diff --git a/offapi/com/sun/star/text/ContentControl.idl b/offapi/com/sun/star/text/ContentControl.idl index 34beff3cb127..6f6aa80ca54d 100644 --- a/offapi/com/sun/star/text/ContentControl.idl +++ b/offapi/com/sun/star/text/ContentControl.idl @@ -147,6 +147,12 @@ service ContentControl @since LibreOffice 7.6 */ [optional, property] string Lock; + + /** Indicates if the control accepts soft breaks. + + @since LibreOffice 24.2 + */ + [optional, property] string MultiLine; }; diff --git a/sw/inc/formatcontentcontrol.hxx b/sw/inc/formatcontentcontrol.hxx index 190d0bd540fe..cffe326d0703 100644 --- a/sw/inc/formatcontentcontrol.hxx +++ b/sw/inc/formatcontentcontrol.hxx @@ -173,7 +173,7 @@ class SW_DLLPUBLIC SwContentControl final : public sw::BroadcastingModify /// The appearance: just remembered. OUString m_aAppearance; - /// The alias: just remembered. + /// The alias. OUString m_aAlias; /// The tag: just remembered. @@ -188,6 +188,9 @@ class SW_DLLPUBLIC SwContentControl final : public sw::BroadcastingModify /// The control and content locks: mostly just remembered. OUString m_aLock; + /// The multiline property: just remembered. + OUString m_aMultiLine; + /// Stores a list item index, in case the doc model is not yet updated. // i.e. temporarily store the selected item until the text is inserted by GotoContentControl. std::optional m_oSelectedListItem; @@ -389,6 +392,10 @@ public: // At the implementation level, define whether the user can directly modify the contents. bool GetReadWrite() const { return m_bReadWrite; } + void SetMultiLine(const OUString& rMultiline) { m_aMultiLine = rMultiline; } + + const OUString& GetMultiLine() const { return m_aMultiLine; } + SwContentControlType GetType() const; }; diff --git a/sw/inc/unoprnms.hxx b/sw/inc/unoprnms.hxx index 6553153b459d..630028f0e7a6 100644 --- a/sw/inc/unoprnms.hxx +++ b/sw/inc/unoprnms.hxx @@ -941,6 +941,7 @@ inline constexpr OUStringLiteral UNO_NAME_TAG = u"Tag"; inline constexpr OUStringLiteral UNO_NAME_ID = u"Id"; inline constexpr OUStringLiteral UNO_NAME_TAB_INDEX = u"TabIndex"; inline constexpr OUStringLiteral UNO_NAME_LOCK = u"Lock"; +inline constexpr OUStringLiteral UNO_NAME_MULTILINE = u"MultiLine"; inline constexpr OUStringLiteral UNO_NAME_DATE_STRING = u"DateString"; inline constexpr OUStringLiteral UNO_NAME_PARA_ID = u"ParaId"; inline constexpr OUStringLiteral UNO_NAME_PARA_ID_PARENT = u"ParaIdParent"; diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx index 90c3c750c53c..6d3d0452740a 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx @@ -683,28 +683,12 @@ DECLARE_OOXMLEXPORT_TEST(testTdf123642_BookmarkAtDocEnd, "tdf123642.docx") DECLARE_OOXMLEXPORT_TEST(testTdf148361, "tdf148361.docx") { - if (isExported()) - { - // Block SDT is turned into run SDT on export, so the next import will have this as content - // control, not as a field. - OUString aActual = getParagraph(1)->getString(); - // This was "itadmin". - CPPUNIT_ASSERT_EQUAL(OUString("itadmin"), aActual); - } - else - { - // Refresh fields and ensure cross-reference to numbered para is okay - uno::Reference xTextFieldsSupplier(mxComponent, uno::UNO_QUERY); - uno::Reference xFieldsAccess(xTextFieldsSupplier->getTextFields()); + // Plain text Block SDT is imported as content control + OUString aActual = getParagraph(1)->getString(); + // This was "itadmin". + CPPUNIT_ASSERT_EQUAL(OUString("itadmin"), aActual); - uno::Reference xFields(xFieldsAccess->createEnumeration()); - CPPUNIT_ASSERT(xFields->hasMoreElements()); - - uno::Reference xTextField1(xFields->nextElement(), uno::UNO_QUERY); - CPPUNIT_ASSERT_EQUAL(OUString("itadmin"), xTextField1->getPresentation(false)); - } - - OUString aActual = getParagraph(2)->getString(); + aActual = getParagraph(2)->getString(); // This was "itadmin". CPPUNIT_ASSERT_EQUAL(OUString("[Type text]"), aActual); } @@ -936,9 +920,7 @@ DECLARE_OOXMLEXPORT_TEST(testTdf81507, "tdf81507.docx") // Ensure that we have assertXPath(pXmlDoc, "/w:document/w:body/w:p[3]/w:sdt/w:sdtPr/w:text"); - - // Ensure that we have no (not quite correct case, but to ensure import/export are okay) - assertXPath(pXmlDoc, "/w:document/w:body/w:p[4]/w:sdt/w:sdtPr/w:text", 0); + assertXPath(pXmlDoc, "/w:document/w:body/w:p[4]/w:sdt/w:sdtPr/w:text"); } DECLARE_OOXMLEXPORT_TEST(testTdf139948, "tdf139948.docx") diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport19.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport19.cxx index 275891d4f58b..fbd3bdb4aaaf 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport19.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport19.cxx @@ -1108,7 +1108,10 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf157136) { // 1st paragraph - block content control auto xRun = getRun(getParagraph(1), 1); - CPPUNIT_ASSERT_EQUAL(OUString("Click or tap here to enter text.\r"), xRun->getString()); + auto xContentControl + = getProperty>(xRun, "ContentControl"); + CPPUNIT_ASSERT_EQUAL(OUString("Click or tap here to enter text."), + xContentControl->getString()); // Without the fix in place, this would fail with // - Expected: Placeholder Text // - Actual : diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport3.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport3.cxx index ae1aa909d5fe..24b2ee333e49 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport3.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport3.cxx @@ -1003,7 +1003,8 @@ CPPUNIT_TEST_FIXTURE(Test, testGlossaryWithEmail) // preserve the ShowingPlaceholder setting on both block SDTs. pXmlDoc = parseExport("word/document.xml"); - assertXPath(pXmlDoc,"/w:document/w:body/w:p/w:sdt/w:sdtPr/w:showingPlcHdr", 2); + assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtPr/w:showingPlcHdr", 1); + assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:hyperlink/w:sdt/w:sdtPr/w:showingPlcHdr", 1); } DECLARE_OOXMLEXPORT_TEST(testFdo71785, "fdo71785.docx") diff --git a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx index c0578ad31a16..a7ffaa2ae7f5 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx @@ -636,7 +636,7 @@ CPPUNIT_TEST_FIXTURE(Test, testSdtCompanyMultipara) // Here is just a simple text node, so there should be either one or zero paragraph // (in this case sdt element is inside paragraph) assertXPath(pXmlDoc, "//w:sdtContent/w:p", 0); - assertXPath(pXmlDoc, "//w:sdtContent/w:r", 1); + assertXPath(pXmlDoc, "//w:sdtContent/w:r", 2); } DECLARE_OOXMLEXPORT_TEST(testFixedDateFields, "fixed-date-field.docx") diff --git a/sw/source/core/txtnode/attrcontentcontrol.cxx b/sw/source/core/txtnode/attrcontentcontrol.cxx index bc62606f2d97..2dd007f480b3 100644 --- a/sw/source/core/txtnode/attrcontentcontrol.cxx +++ b/sw/source/core/txtnode/attrcontentcontrol.cxx @@ -220,6 +220,7 @@ SwContentControl::SwContentControl(SwFormatContentControl* pFormat) SetId(pOther->m_nId); SetTabIndex(pOther->m_nTabIndex); SetLock(pOther->m_aLock); + SetMultiLine(pOther->m_aMultiLine); } SwContentControl::~SwContentControl() {} @@ -605,6 +606,8 @@ void SwContentControl::dumpAsXml(xmlTextWriterPtr pWriter) const BAD_CAST(OString::number(m_nTabIndex).getStr())); (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("lock"), BAD_CAST(m_aLock.toUtf8().getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("multiline"), + BAD_CAST(m_aMultiLine.toUtf8().getStr())); if (!m_aListItems.empty()) { diff --git a/sw/source/core/unocore/unocontentcontrol.cxx b/sw/source/core/unocore/unocontentcontrol.cxx index 541fc46699b3..8492e0fc94f7 100644 --- a/sw/source/core/unocore/unocontentcontrol.cxx +++ b/sw/source/core/unocore/unocontentcontrol.cxx @@ -176,6 +176,7 @@ public: sal_Int32 m_nId; sal_uInt32 m_nTabIndex; OUString m_aLock; + OUString m_aMultiLine; Impl(SwXContentControl& rThis, SwDoc& rDoc, SwContentControl* pContentControl, css::uno::Reference xParentText, std::unique_ptr pPortions) @@ -475,6 +476,7 @@ void SwXContentControl::AttachImpl(const uno::Reference& xText pContentControl->SetId(m_pImpl->m_nId); pContentControl->SetTabIndex(m_pImpl->m_nTabIndex); pContentControl->SetLock(m_pImpl->m_aLock); + pContentControl->SetMultiLine(m_pImpl->m_aMultiLine); SwFormatContentControl aContentControl(pContentControl, nWhich); bool bSuccess @@ -1010,6 +1012,21 @@ void SAL_CALL SwXContentControl::setPropertyValue(const OUString& rPropertyName, } } } + else if (rPropertyName == UNO_NAME_MULTILINE) + { + OUString aValue; + if (rValue >>= aValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_aMultiLine = aValue; + } + else + { + m_pImpl->m_pContentControl->SetMultiLine(aValue); + } + } + } else { throw beans::UnknownPropertyException(); @@ -1305,6 +1322,17 @@ uno::Any SAL_CALL SwXContentControl::getPropertyValue(const OUString& rPropertyN aRet <<= m_pImpl->m_pContentControl->GetLock(); } } + else if (rPropertyName == UNO_NAME_MULTILINE) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_aMultiLine; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetMultiLine(); + } + } else { throw beans::UnknownPropertyException(); diff --git a/sw/source/core/unocore/unomap1.cxx b/sw/source/core/unocore/unomap1.cxx index aae854fc24e0..ba165289c177 100644 --- a/sw/source/core/unocore/unomap1.cxx +++ b/sw/source/core/unocore/unomap1.cxx @@ -1053,6 +1053,7 @@ o3tl::span SwUnoPropertyMapProvider::GetContentCo { UNO_NAME_ID, 0, cppu::UnoType::get(), PROPERTY_NONE, 0 }, { UNO_NAME_TAB_INDEX, 0, cppu::UnoType::get(), PROPERTY_NONE, 0 }, { UNO_NAME_LOCK, 0, cppu::UnoType::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_MULTILINE, 0, cppu::UnoType::get(), PROPERTY_NONE, 0 }, { UNO_NAME_DATE_STRING, 0, cppu::UnoType::get(), PropertyAttribute::READONLY, 0 }, }; diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index 9c67855acbdd..4a4d440abc44 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -2739,7 +2739,11 @@ void DocxAttributeOutput::WriteContentControlStart() m_pSerializer->endElementNS(XML_w, XML_date); } - if (m_pContentControl->GetPlainText()) + if (!m_pContentControl->GetMultiLine().isEmpty()) + { + m_pSerializer->singleElementNS(XML_w, XML_text, FSNS(XML_w, XML_multiLine), m_pContentControl->GetMultiLine()); + } + else if (m_pContentControl->GetPlainText()) { m_pSerializer->singleElementNS(XML_w, XML_text); } diff --git a/writerfilter/qa/cppunittests/dmapper/DomainMapper.cxx b/writerfilter/qa/cppunittests/dmapper/DomainMapper.cxx index 97f856044d6c..7cafcd19f280 100644 --- a/writerfilter/qa/cppunittests/dmapper/DomainMapper.cxx +++ b/writerfilter/qa/cppunittests/dmapper/DomainMapper.cxx @@ -119,6 +119,36 @@ CPPUNIT_TEST_FIXTURE(Test, testFloattableThenTable) // Make sure the anchor text is the body text, not some cell. CPPUNIT_ASSERT_EQUAL(xBodyText, xAnchor->getText()); } + +CPPUNIT_TEST_FIXTURE(Test, testSdtBlockText) +{ + // Given a document with a block SDT that only contains text: + loadFromURL(u"sdt-block-text.docx"); + + // Then make sure that the text inside the SDT is imported as a content control: + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xParaEnumAccess(xTextDocument->getText(), + uno::UNO_QUERY); + uno::Reference xParaEnum = xParaEnumAccess->createEnumeration(); + uno::Reference xPara(xParaEnum->nextElement(), uno::UNO_QUERY); + uno::Reference xPortionEnum = xPara->createEnumeration(); + uno::Reference xPortion(xPortionEnum->nextElement(), uno::UNO_QUERY); + OUString aTextPortionType; + xPortion->getPropertyValue("TextPortionType") >>= aTextPortionType; + // Without the accompanying fix in place, this test would have failed with: + // - Expected: ContentControl + // - Actual : TextField + // i.e. the SDT was imported as a text field, not as a content control. + CPPUNIT_ASSERT_EQUAL(OUString("ContentControl"), aTextPortionType); + + // Make sure the properties are imported + uno::Reference xContentControl; + xPortion->getPropertyValue("ContentControl") >>= xContentControl; + uno::Reference xContentControlProps(xContentControl, uno::UNO_QUERY); + OUString aAlias; + xContentControlProps->getPropertyValue("Alias") >>= aAlias; + CPPUNIT_ASSERT_EQUAL(OUString("myalias"), aAlias); +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerfilter/qa/cppunittests/dmapper/data/sdt-block-text.docx b/writerfilter/qa/cppunittests/dmapper/data/sdt-block-text.docx new file mode 100644 index 000000000000..2dfbc4a3284a Binary files /dev/null and b/writerfilter/qa/cppunittests/dmapper/data/sdt-block-text.docx differ diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx index 726730ad3076..f015b79520bf 100644 --- a/writerfilter/source/dmapper/DomainMapper.cxx +++ b/writerfilter/source/dmapper/DomainMapper.cxx @@ -1132,7 +1132,7 @@ void DomainMapper::lcl_attribute(Id nName, Value & val) } if (nName == NS_ooxml::LN_CT_SdtRun_sdtContent) { - if (m_pImpl->GetSdtStarts().empty() && !m_pImpl->m_pSdtHelper->getSdtTexts().isEmpty()) + if (m_pImpl->GetSdtStarts().empty() && m_pImpl->m_pSdtHelper->hasUnusedText()) { // A non-inline SDT is already started, first convert that to a field and only // then map the inline SDT to a content control. @@ -1191,6 +1191,9 @@ void DomainMapper::lcl_attribute(Id nName, Value & val) m_pImpl->PushSdt(); break; } + if (m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::plainText + && GetCurrentTextRange().is()) + m_pImpl->m_pSdtHelper->setFieldStartRange(GetCurrentTextRange()->getEnd()); m_pImpl->SetSdt(true); } break; @@ -2977,7 +2980,7 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext ) { m_pImpl->m_pSdtHelper->setControlType(SdtControlType::datePicker); resolveSprmProps(*this, rSprm); - m_pImpl->m_pSdtHelper->setDateFieldStartRange(GetCurrentTextRange()->getEnd()); + m_pImpl->m_pSdtHelper->setFieldStartRange(GetCurrentTextRange()->getEnd()); } break; case NS_ooxml::LN_CT_SdtDate_dateFormat: @@ -4128,13 +4131,13 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, size_t len) } else if (m_pImpl->m_pSdtHelper->GetSdtType() != NS_ooxml::LN_CT_SdtRun_sdtContent && m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::plainText) { - m_pImpl->m_pSdtHelper->getSdtTexts().append(sText); if (bNewLine) { m_pImpl->m_pSdtHelper->createPlainTextControl(); finishParagraph(); + m_pImpl->m_pSdtHelper->setFieldStartRange(GetCurrentTextRange()->getEnd()); + return; } - return; } else if (!m_pImpl->m_pSdtHelper->isInteropGrabBagEmpty()) { @@ -4387,6 +4390,10 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, size_t len) m_pImpl->clearDeferredBreaks(); } + bool bSdtBlockUnusedText + = m_pImpl->m_pSdtHelper->GetSdtType() != NS_ooxml::LN_CT_SdtRun_sdtContent + && m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::plainText + && m_pImpl->m_pSdtHelper->hasUnusedText(); if (pContext && pContext->GetFootnote().is()) { pContext->GetFootnote()->setLabel( sText ); @@ -4396,18 +4403,33 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, size_t len) } else if (m_pImpl->IsOpenFieldCommand() && !m_pImpl->IsForceGenericFields()) { + if (bSdtBlockUnusedText) + m_pImpl->m_pSdtHelper->createPlainTextControl(); m_pImpl->AppendFieldCommand(sText); + if (bSdtBlockUnusedText) + m_pImpl->m_pSdtHelper->setFieldStartRange(GetCurrentTextRange()->getEnd()); } else if( m_pImpl->IsOpenField() && m_pImpl->IsFieldResultAsString()) + { + if (bSdtBlockUnusedText) + m_pImpl->m_pSdtHelper->createPlainTextControl(); /*depending on the success of the field insert operation this result will be set at the field or directly inserted into the text*/ m_pImpl->AppendFieldResult(sText); + if (bSdtBlockUnusedText) + m_pImpl->m_pSdtHelper->setFieldStartRange(GetCurrentTextRange()->getEnd()); + } else { if (pContext == nullptr) pContext = new PropertyMap(); m_pImpl->appendTextPortion( sText, pContext ); + + if (m_pImpl->m_pSdtHelper->GetSdtType() == NS_ooxml::LN_CT_SdtBlock_sdtContent + && m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::plainText + && !sText.isEmpty()) + m_pImpl->m_pSdtHelper->setHasUnusedText(true); } } diff --git a/writerfilter/source/dmapper/SdtHelper.cxx b/writerfilter/source/dmapper/SdtHelper.cxx index 041802147605..c7f99878e12d 100644 --- a/writerfilter/source/dmapper/SdtHelper.cxx +++ b/writerfilter/source/dmapper/SdtHelper.cxx @@ -83,6 +83,7 @@ SdtHelper::SdtHelper(DomainMapper_Impl& rDM_Impl, : m_rDM_Impl(rDM_Impl) , m_xComponentContext(std::move(xContext)) , m_aControlType(SdtControlType::unknown) + , m_bHasUnusedText(false) , m_bHasElements(false) , m_bOutsideAParagraph(false) , m_bPropertiesXMLsLoaded(false) @@ -334,31 +335,102 @@ void SdtHelper::createPlainTextControl() { assert(getControlType() == SdtControlType::plainText); - OUString aDefaultText = m_aSdtTexts.makeStringAndClear(); + if (!m_xFieldStartRange.is()) + return; - // create field - uno::Reference xControlModel( - m_rDM_Impl.GetTextFactory()->createInstance("com.sun.star.text.TextField.Input"), - uno::UNO_QUERY); + uno::Reference xCrsr; + uno::Reference xText; + if (m_rDM_Impl.HasTopText()) + { + uno::Reference xTextAppend = m_rDM_Impl.GetTopTextAppend(); + if (xTextAppend.is()) + { + xText = m_rDM_Impl.GetTopTextAppend()->getEnd()->getText(); + xCrsr = xText->createTextCursorByRange(m_xFieldStartRange); + } + } + if (!xCrsr.is()) + return; - // set properties - uno::Reference xPropertySet(xControlModel, uno::UNO_QUERY); + try + { + bool bIsInTable = (m_rDM_Impl.hasTableManager() && m_rDM_Impl.getTableManager().isInTable()) + != (m_rDM_Impl.m_nTableDepth > 0) + && m_rDM_Impl.GetIsDummyParaAddedForTableInSection(); + if (bIsInTable) + xCrsr->goRight(1, false); + xCrsr->gotoEnd(true); + } + catch (uno::Exception&) + { + TOOLS_WARN_EXCEPTION("writerfilter.dmapper", + "Cannot get the right text range for date field"); + return; + } std::optional oData = getValueFromDataBinding(); if (oData.has_value()) - aDefaultText = *oData; + xCrsr->setString(*oData); - xPropertySet->setPropertyValue("Content", uno::Any(aDefaultText)); + uno::Reference xContentControl( + m_rDM_Impl.GetTextFactory()->createInstance("com.sun.star.text.ContentControl"), + uno::UNO_QUERY); + uno::Reference xContentControlProps(xContentControl, uno::UNO_QUERY); - PropertyMap aMap; - aMap.InsertProps(m_rDM_Impl.GetTopContext()); + for (const beans::PropertyValue& prop : getInteropGrabBagAndClear()) + { + OUString sPropertyName; + if (prop.Name == "ooxml:CT_SdtPr_showingPlcHdr") + sPropertyName = "ShowingPlaceHolder"; + else if (prop.Name == "ooxml:CT_SdtPr_alias") + sPropertyName = "Alias"; + else if (prop.Name == "ooxml:CT_SdtPr_tag") + sPropertyName = "Tag"; + else if (prop.Name == "ooxml:CT_SdtPr_id") + sPropertyName = "Id"; + else if (prop.Name == "ooxml:CT_SdtPr_tabIndex") + sPropertyName = "TabIndex"; + else if (prop.Name == "ooxml:CT_SdtPr_lock") + sPropertyName = "Lock"; + else if (prop.Name == "ooxml:CT_SdtPlaceholder_docPart" + || prop.Name == "ooxml:CT_SdtPr_dataBinding" || prop.Name == "ooxml:CT_SdtPr_color" + || prop.Name == "ooxml:CT_SdtPr_appearance" || prop.Name == "ooxml:CT_SdtPr_text") + { + uno::Sequence aInternalGrabBag; + prop.Value >>= aInternalGrabBag; + for (const beans::PropertyValue& internalProp : aInternalGrabBag) + { + if (internalProp.Name == "ooxml:CT_SdtPlaceholder_docPart_val") + sPropertyName = "PlaceholderDocPart"; + else if (internalProp.Name == "ooxml:CT_DataBinding_prefixMappings") + sPropertyName = "DataBindingPrefixMappings"; + else if (internalProp.Name == "ooxml:CT_DataBinding_xpath") + sPropertyName = "DataBindingXpath"; + else if (internalProp.Name == "ooxml:CT_DataBinding_storeItemID") + sPropertyName = "DataBindingStoreItemID"; + else if (internalProp.Name == "ooxml:CT_SdtAppearance_val") + sPropertyName = "Appearance"; + else if (internalProp.Name == "ooxml:CT_SdtColor_val") + sPropertyName = "Color"; + else if (internalProp.Name == "ooxml:CT_SdtText_multiLine") + sPropertyName = "MultiLine"; + if (!sPropertyName.isEmpty()) + { + xContentControlProps->setPropertyValue(sPropertyName, internalProp.Value); + } + sPropertyName.clear(); + } + } - // add it into document - m_rDM_Impl.appendTextContent(xControlModel, aMap.GetPropertyValues()); + if (!sPropertyName.isEmpty()) + { + xContentControlProps->setPropertyValue(sPropertyName, prop.Value); + } + } - // Store all unused sdt parameters from grabbag - xPropertySet->setPropertyValue(UNO_NAME_MISC_OBJ_INTEROPGRABBAG, - uno::Any(getInteropGrabBagAndClear())); + xContentControlProps->setPropertyValue("PlainText", uno::Any(true)); + + xText->insertTextContent(xCrsr, xContentControl, /*bAbsorb=*/true); // clean up clear(); @@ -366,7 +438,7 @@ void SdtHelper::createPlainTextControl() void SdtHelper::createDateContentControl() { - if (!m_xDateFieldStartRange.is()) + if (!m_xFieldStartRange.is()) return; uno::Reference xCrsr; @@ -383,7 +455,7 @@ void SdtHelper::createDateContentControl() try { - xCrsr->gotoRange(m_xDateFieldStartRange, false); + xCrsr->gotoRange(m_xFieldStartRange, false); // tdf#138093: Date selector reset, if placed inside table // Modified to XOR relationship and adding dummy paragraph conditions bool bIsInTable = (m_rDM_Impl.hasTableManager() && m_rDM_Impl.getTableManager().isInTable()) @@ -520,6 +592,7 @@ void SdtHelper::clear() m_sDataBindingXPath.clear(); m_sDataBindingStoreItemID.clear(); m_aGrabBag.clear(); + m_bHasUnusedText = false; m_bShowingPlcHdr = false; m_bChecked = false; m_aCheckedState.clear(); diff --git a/writerfilter/source/dmapper/SdtHelper.hxx b/writerfilter/source/dmapper/SdtHelper.hxx index 6803db16ef06..5db799bd1fd2 100644 --- a/writerfilter/source/dmapper/SdtHelper.hxx +++ b/writerfilter/source/dmapper/SdtHelper.hxx @@ -83,12 +83,14 @@ class SdtHelper final : public virtual SvRefBase /// OUString m_sDataBindingStoreItemID; - /// Start range of the date field - css::uno::Reference m_xDateFieldStartRange; + /// Start range of the date or plain text field + css::uno::Reference m_xFieldStartRange; /// Locale string as it comes from the ooxml document. OUStringBuffer m_sLocale; /// Grab bag to store unsupported SDTs, aiming to save them back on export. std::vector m_aGrabBag; + /// Has inserted texts for plain text control + bool m_bHasUnusedText; bool m_bHasElements; /// The last stored SDT element is outside paragraphs. @@ -169,9 +171,9 @@ public: void setDataBindingStoreItemID(const OUString& sValue) { m_sDataBindingStoreItemID = sValue; } const OUString& GetDataBindingStoreItemID() const { return m_sDataBindingStoreItemID; } - void setDateFieldStartRange(const css::uno::Reference& xStartRange) + void setFieldStartRange(const css::uno::Reference& xStartRange) { - m_xDateFieldStartRange = xStartRange; + m_xFieldStartRange = xStartRange; } OUStringBuffer& getLocale() { return m_sLocale; } @@ -204,6 +206,9 @@ public: bool containedInInteropGrabBag(const OUString& rValueName); sal_Int32 getInteropGrabBagSize() const; + void setHasUnusedText(bool bHasUnusedText) { m_bHasUnusedText = bHasUnusedText; } + bool hasUnusedText() const { return m_bHasUnusedText; } + void SetShowingPlcHdr(); bool GetShowingPlcHdr() const;