diff options
author | Tamás Zolnai <tamas.zolnai@collabora.com> | 2019-07-10 18:22:31 +0200 |
---|---|---|
committer | Tamás Zolnai <tamas.zolnai@collabora.com> | 2019-07-17 11:40:00 +0200 |
commit | 047220d82b3eefa5fdeec186752b70205a16369b (patch) | |
tree | b4b8fcfca643326bc64b91d8cef31dc5e502297d /writerfilter | |
parent | 38229d47b2aec0f49da56ce937a203a8b4ca1fb3 (diff) |
MSForms: Rework text-based date form field's representation
* Better to represent it similar to text form field with two
marking characters selecting a text range
* So the text between the two marks can be anything (not only
a well formatted date) and also have any character formatting.
* With this we handle the case when the user needs a placeholder
text in the date field or when the user needs time values (hour,
minute, sec) next to the date.
Reviewed-on: https://gerrit.libreoffice.org/75459
Tested-by: Jenkins
Reviewed-by: Tamás Zolnai <tamas.zolnai@collabora.com>
(cherry picked from commit 68e1be4ccbb90ee9a788962219a88312c4ffbea2)
Change-Id: Id60a50a2028058f8a6a080e265c0730d88b98543
Diffstat (limited to 'writerfilter')
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper.cxx | 81 | ||||
-rw-r--r-- | writerfilter/source/dmapper/SdtHelper.cxx | 41 | ||||
-rw-r--r-- | writerfilter/source/dmapper/SdtHelper.hxx | 12 |
3 files changed, 83 insertions, 51 deletions
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx index b542d43bc2c0..95bd864fc63a 100644 --- a/writerfilter/source/dmapper/DomainMapper.cxx +++ b/writerfilter/source/dmapper/DomainMapper.cxx @@ -2408,6 +2408,7 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext ) case NS_ooxml::LN_CT_SdtPr_date: { resolveSprmProps(*this, rSprm); + m_pImpl->m_pSdtHelper->setDateFieldStartRange(GetCurrentTextRange()->getEnd()); } break; case NS_ooxml::LN_CT_SdtDate_dateFormat: @@ -3009,10 +3010,6 @@ void DomainMapper::lcl_startCharacterGroup() // call setSdtEndDeferred(false) here, that will happen only in lcl_utext(). m_pImpl->GetTopContext()->Insert(PROP_SDT_END_BEFORE, uno::makeAny(true), true, CHAR_GRAB_BAG); } - - // Remember formatting of the date control as it only supports plain strings natively. - if (!m_pImpl->m_pSdtHelper->getDateFormat().isEmpty()) - enableInteropGrabBag("CharFormat"); } void DomainMapper::lcl_endCharacterGroup() @@ -3181,48 +3178,43 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, size_t len) return; } } - else if (m_pImpl->m_pSdtHelper->validateDateFormat()) - { - // Date field will be imported, so we don't need the corresponding date text in most of the cases - // however when fullDate is not specified, but we have a date string we need to import it as - // simple text (this is the case when user sets date field manually in MSO). - if((!m_pImpl->m_pSdtHelper->getDate().toString().isEmpty() || sText.isEmpty()) && - (!IsInHeaderFooter() || !m_pImpl->IsDiscardHeaderFooter())) // discard date control with header / footer - { - return; - } - // Remove date field attributes to avoid to import an actual date field - m_pImpl->m_pSdtHelper->getDateFormat().truncate(); - m_pImpl->m_pSdtHelper->getLocale().truncate(); - } else if (!m_pImpl->m_pSdtHelper->isInteropGrabBagEmpty()) { - // there are unsupported SDT properties in the document - // save them in the paragraph interop grab bag - if (m_pImpl->IsDiscardHeaderFooter()) + // Ignore grabbag when we have a date field, it can conflict during export + if(m_pImpl->m_pSdtHelper->validateDateFormat()) { - // 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()) + else { - 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(); + // 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); - pContext->Insert(PROP_SDTPR, uno::makeAny(m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear()), true, CHAR_GRAB_BAG); + 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); } - 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) { @@ -3248,6 +3240,21 @@ 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() && m_pImpl->getTableManager().isInTable()) || + m_pImpl->m_nTableDepth > 0) + { + // Inside a table we need to import date field earlier + m_pImpl->m_pSdtHelper->createDateContentControl(true); + } + } if (!m_pImpl->hasTableManager()) return; diff --git a/writerfilter/source/dmapper/SdtHelper.cxx b/writerfilter/source/dmapper/SdtHelper.cxx index 6dd39b71b03c..0a109c53d000 100644 --- a/writerfilter/source/dmapper/SdtHelper.cxx +++ b/writerfilter/source/dmapper/SdtHelper.cxx @@ -98,24 +98,40 @@ bool SdtHelper::validateDateFormat() return !m_sDateFormat.toString().isEmpty() && !m_sLocale.toString().isEmpty(); } -void SdtHelper::createDateContentControl() +void SdtHelper::createDateContentControl(bool bInsideTable) { + if(!m_xDateFieldStartRange.is()) + return; + uno::Reference<text::XTextCursor> xCrsr; if(m_rDM_Impl.HasTopText()) { uno::Reference<text::XTextAppend> xTextAppend = m_rDM_Impl.GetTopTextAppend(); if (xTextAppend.is()) - xCrsr = xTextAppend->createTextCursorByRange(xTextAppend->getEnd()); + { + xCrsr = xTextAppend->createTextCursorByRange(xTextAppend); + } } if (xCrsr.is()) { + try + { + xCrsr->gotoRange(m_xDateFieldStartRange, false); + if(bInsideTable) + xCrsr->goRight(1, false); + xCrsr->gotoEnd(true); + } + catch (uno::Exception&) { + OSL_ENSURE(false, "Cannot get the right text range for date field"); + return; + } + uno::Reference< uno::XInterface > xFieldInterface; - xFieldInterface = m_rDM_Impl.GetTextFactory()->createInstance("com.sun.star.text.FormFieldmark"); + xFieldInterface = m_rDM_Impl.GetTextFactory()->createInstance("com.sun.star.text.Fieldmark"); uno::Reference< text::XFormField > xFormField( xFieldInterface, uno::UNO_QUERY ); uno::Reference< text::XTextContent > xToInsert(xFormField, uno::UNO_QUERY); if ( xFormField.is() && xToInsert.is() ) { - xCrsr->gotoEnd(true); xToInsert->attach( uno::Reference< text::XTextRange >( xCrsr, uno::UNO_QUERY_THROW )); xFormField->setFieldType(ODF_FORMDATE); uno::Reference<container::XNameContainer> xNameCont = xFormField->getParameters(); @@ -126,15 +142,14 @@ void SdtHelper::createDateContentControl() sDateFormat = sDateFormat.replaceAll("'", "\""); xNameCont->insertByName(ODF_FORMDATE_DATEFORMAT, uno::makeAny(sDateFormat)); xNameCont->insertByName(ODF_FORMDATE_DATEFORMAT_LANGUAGE, uno::makeAny(m_sLocale.makeStringAndClear())); - OUString sDate = m_sDate.makeStringAndClear(); - if(!sDate.isEmpty()) - { - // Remove time part of the full date - sal_Int32 nTimeSep = sDate.indexOf("T"); - if(nTimeSep != -1) - sDate = sDate.copy(0, nTimeSep); - xNameCont->insertByName(ODF_FORMDATE_CURRENTDATE, uno::makeAny(sDate)); - } + } + OUString sFullDate = m_sDate.makeStringAndClear(); + if(!sFullDate.isEmpty()) + { + sal_Int32 nTimeSep = sFullDate.indexOf("T"); + if(nTimeSep != -1) + sFullDate = sFullDate.copy(0, nTimeSep); + xNameCont->insertByName(ODF_FORMDATE_CURRENTDATE, uno::makeAny(sFullDate)); } } } diff --git a/writerfilter/source/dmapper/SdtHelper.hxx b/writerfilter/source/dmapper/SdtHelper.hxx index 01abd4117adb..5efb397edd8a 100644 --- a/writerfilter/source/dmapper/SdtHelper.hxx +++ b/writerfilter/source/dmapper/SdtHelper.hxx @@ -13,6 +13,7 @@ #include <vector> #include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/text/XTextRange.hpp> #include <rtl/ustrbuf.hxx> #include <tools/ref.hxx> @@ -56,6 +57,8 @@ class SdtHelper final : public virtual SvRefBase OUStringBuffer m_sDate; /// Date format string as it comes from the ooxml document. OUStringBuffer m_sDateFormat; + /// Start range of the date field + css::uno::Reference<css::text::XTextRange> m_xDateFieldStartRange; /// 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. @@ -79,15 +82,22 @@ public: { return m_aSdtTexts; } + OUStringBuffer& getDate() { return m_sDate; } + OUStringBuffer& getDateFormat() { return m_sDateFormat; } + 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(); @@ -114,7 +124,7 @@ public: /// Create drop-down control from w:sdt's w:dropDownList. void createDropDownControl(); /// Create date control from w:sdt's w:date. - void createDateContentControl(); + void createDateContentControl(bool bInsideTable = false); void appendToInteropGrabBag(const css::beans::PropertyValue& rValue); css::uno::Sequence<css::beans::PropertyValue> getInteropGrabBagAndClear(); |