writerfilter: use content controls for text in block SDTs

Text inside block SDTs was shown as Text Fields wich ignored properties such as
alias and formatting. Now those texts are imported as content controls like in
the case of run SDTs.

Added the ability for content controls to remember and export the "multiline"
property of block SDT text.

Some existing tests have been changed due to some different export results.

Change-Id: Ice1eb4ca6dd53c99d5abb239371f8ac896c3b6e4
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/156867
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins
This commit is contained in:
Jaume Pujantell
2023-09-13 08:58:21 +02:00
parent af9c3ed6f7
commit 5082d50d24
16 changed files with 221 additions and 55 deletions

View File

@@ -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;
};

View File

@@ -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<size_t> 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;
};

View File

@@ -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";

View File

@@ -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.
// Plain text Block SDT is imported as content control
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<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<container::XEnumerationAccess> xFieldsAccess(xTextFieldsSupplier->getTextFields());
uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
CPPUNIT_ASSERT(xFields->hasMoreElements());
uno::Reference<text::XTextField> 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 <w:text/>
assertXPath(pXmlDoc, "/w:document/w:body/w:p[3]/w:sdt/w:sdtPr/w:text");
// Ensure that we have no <w:text/> (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")

View File

@@ -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<css::uno::Reference<css::text::XTextRange>>(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 :

View File

@@ -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")

View File

@@ -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")

View File

@@ -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())
{

View File

@@ -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<SwXText> xParentText, std::unique_ptr<const TextRangeList_t> pPortions)
@@ -475,6 +476,7 @@ void SwXContentControl::AttachImpl(const uno::Reference<text::XTextRange>& 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();

View File

@@ -1053,6 +1053,7 @@ o3tl::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetContentCo
{ UNO_NAME_ID, 0, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0 },
{ UNO_NAME_TAB_INDEX, 0, cppu::UnoType<sal_uInt32>::get(), PROPERTY_NONE, 0 },
{ UNO_NAME_LOCK, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 },
{ UNO_NAME_MULTILINE, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 },
{ UNO_NAME_DATE_STRING, 0, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0 },
};

View File

@@ -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);
}

View File

@@ -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<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xTextDocument->getText(),
uno::UNO_QUERY);
uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
uno::Reference<container::XEnumerationAccess> xPara(xParaEnum->nextElement(), uno::UNO_QUERY);
uno::Reference<container::XEnumeration> xPortionEnum = xPara->createEnumeration();
uno::Reference<beans::XPropertySet> 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<text::XTextContent> xContentControl;
xPortion->getPropertyValue("ContentControl") >>= xContentControl;
uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
OUString aAlias;
xContentControlProps->getPropertyValue("Alias") >>= aAlias;
CPPUNIT_ASSERT_EQUAL(OUString("myalias"), aAlias);
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View File

@@ -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,14 +4131,14 @@ 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;
}
}
else if (!m_pImpl->m_pSdtHelper->isInteropGrabBagEmpty())
{
// there are unsupported SDT properties in the document
@@ -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);
}
}

View File

@@ -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<css::text::XTextField> xControlModel(
m_rDM_Impl.GetTextFactory()->createInstance("com.sun.star.text.TextField.Input"),
uno::UNO_QUERY);
uno::Reference<text::XTextCursor> xCrsr;
uno::Reference<text::XText> xText;
if (m_rDM_Impl.HasTopText())
{
uno::Reference<text::XTextAppend> 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<beans::XPropertySet> 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<OUString> oData = getValueFromDataBinding();
if (oData.has_value())
aDefaultText = *oData;
xCrsr->setString(*oData);
xPropertySet->setPropertyValue("Content", uno::Any(aDefaultText));
uno::Reference<text::XTextContent> xContentControl(
m_rDM_Impl.GetTextFactory()->createInstance("com.sun.star.text.ContentControl"),
uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> 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<beans::PropertyValue> 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<text::XTextCursor> 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();

View File

@@ -83,12 +83,14 @@ class SdtHelper final : public virtual SvRefBase
/// <w:dataBinding w:storeItemID="">
OUString m_sDataBindingStoreItemID;
/// Start range of the date field
css::uno::Reference<css::text::XTextRange> m_xDateFieldStartRange;
/// Start range of the date or plain text field
css::uno::Reference<css::text::XTextRange> 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<css::beans::PropertyValue> 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<css::text::XTextRange>& xStartRange)
void setFieldStartRange(const css::uno::Reference<css::text::XTextRange>& 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;