diff options
author | Miklos Vajna <vmiklos@collabora.com> | 2022-05-27 11:38:42 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.com> | 2022-05-31 14:40:45 +0200 |
commit | d0ebc93087975ce361b618512548bc05b5b95c8b (patch) | |
tree | 4e0b22ca7cd62610e519f2bf4650b4f08d5af431 | |
parent | c04e1a32a1610c735ef2de6e8fde107abb1b66ae (diff) |
sw content controls, date: add current date handling
While working on the DOCX import for dates, it turns out there is a need
to store the selected date in machine-readable format as well. This is
useful, because once the timestamp is formatted, the user is allowed to
hand-edit the result, so otherwise the selected date would be lost.
This commit adds:
- doc model & UNO API
- click handler (store the selected date, default to the current date in
the date picker if possible)
- ODT filter
- DOCX export
And tests for all these.
(cherry picked from commit 79baafccf3d390810f516b2cf9cb3ad2b4e9e63b)
Change-Id: I00f4e87ebfe0e8a19486367c32d472ccd2ff16a8
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135150
Tested-by: Miklos Vajna <vmiklos@collabora.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
-rw-r--r-- | schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng | 5 | ||||
-rw-r--r-- | sw/inc/formatcontentcontrol.hxx | 13 | ||||
-rw-r--r-- | sw/inc/unoprnms.hxx | 1 | ||||
-rw-r--r-- | sw/qa/core/unocore/unocore.cxx | 3 | ||||
-rw-r--r-- | sw/qa/uibase/wrtsh/wrtsh.cxx | 2 | ||||
-rw-r--r-- | sw/source/core/crsr/datecontentcontrolbutton.cxx | 12 | ||||
-rw-r--r-- | sw/source/core/txtnode/attrcontentcontrol.cxx | 63 | ||||
-rw-r--r-- | sw/source/core/unocore/unocontentcontrol.cxx | 28 | ||||
-rw-r--r-- | sw/source/core/unocore/unomap1.cxx | 2 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.cxx | 10 | ||||
-rw-r--r-- | sw/source/uibase/wrtsh/wrtsh3.cxx | 5 | ||||
-rw-r--r-- | xmloff/qa/unit/data/content-control-date.fodt | 2 | ||||
-rw-r--r-- | xmloff/qa/unit/text.cxx | 6 | ||||
-rw-r--r-- | xmloff/source/text/txtparae.cxx | 6 | ||||
-rw-r--r-- | xmloff/source/text/xmlcontentcontrolcontext.cxx | 9 | ||||
-rw-r--r-- | xmloff/source/text/xmlcontentcontrolcontext.hxx | 1 |
16 files changed, 163 insertions, 5 deletions
diff --git a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng index 514a30c30307..55bedf37b1bb 100644 --- a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng +++ b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng @@ -2816,6 +2816,11 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1. <rng:ref name="language"/> </rng:attribute> </rng:optional> + <rng:optional> + <rng:attribute name="loext:current-date"> + <rng:ref name="string"/> + </rng:attribute> + </rng:optional> <rng:zeroOrMore> <rng:element name="loext:list-item"> <rng:attribute name="loext:display-text"> diff --git a/sw/inc/formatcontentcontrol.hxx b/sw/inc/formatcontentcontrol.hxx index 1dba4bce03a6..90452dfaeb2b 100644 --- a/sw/inc/formatcontentcontrol.hxx +++ b/sw/inc/formatcontentcontrol.hxx @@ -135,6 +135,9 @@ class SW_DLLPUBLIC SwContentControl : public sw::BroadcastingModify /// If m_bDate is true, the date's BCP 47 language tag. OUString m_aDateLanguage; + /// Date in YYYY-MM-DDT00:00:00Z format. + OUString m_aCurrentDate; + /// Stores a list item index, in case the doc model is not yet updated. std::optional<size_t> m_oSelectedListItem; @@ -216,6 +219,16 @@ public: OUString GetDateLanguage() const { return m_aDateLanguage; } + void SetCurrentDate(const OUString& rCurrentDate) { m_aCurrentDate = rCurrentDate; } + + OUString GetCurrentDate() const { return m_aCurrentDate; } + + /// Formats fCurrentDate and sets it. + void SetCurrentDateValue(double fCurrentDate); + + /// Parses m_aCurrentDate and returns it. + double GetCurrentDateValue() const; + /// Formats m_oSelectedDate, taking m_aDateFormat and m_aDateLanguage into account. OUString GetDateString() const; diff --git a/sw/inc/unoprnms.hxx b/sw/inc/unoprnms.hxx index 4ac4aa7d0dca..72aaf746cb1e 100644 --- a/sw/inc/unoprnms.hxx +++ b/sw/inc/unoprnms.hxx @@ -879,6 +879,7 @@ #define UNO_NAME_PICTURE "Picture" #define UNO_NAME_DATE_FORMAT "DateFormat" #define UNO_NAME_DATE_LANGUAGE "DateLanguage" +#define UNO_NAME_CURRENT_DATE "CurrentDate" #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/qa/core/unocore/unocore.cxx b/sw/qa/core/unocore/unocore.cxx index edc11b03b9fb..b5ad497e5dac 100644 --- a/sw/qa/core/unocore/unocore.cxx +++ b/sw/qa/core/unocore/unocore.cxx @@ -549,6 +549,8 @@ CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlDate) xContentControlProps->setPropertyValue("Date", uno::Any(true)); xContentControlProps->setPropertyValue("DateFormat", uno::Any(OUString("M/d/yyyy"))); xContentControlProps->setPropertyValue("DateLanguage", uno::Any(OUString("en-US"))); + xContentControlProps->setPropertyValue("CurrentDate", + uno::Any(OUString("2022-05-25T00:00:00Z"))); xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); // Then make sure that the specified properties are set: @@ -562,6 +564,7 @@ CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlDate) CPPUNIT_ASSERT(pContentControl->GetDate()); CPPUNIT_ASSERT_EQUAL(OUString("M/d/yyyy"), pContentControl->GetDateFormat()); CPPUNIT_ASSERT_EQUAL(OUString("en-US"), pContentControl->GetDateLanguage()); + CPPUNIT_ASSERT_EQUAL(OUString("2022-05-25T00:00:00Z"), pContentControl->GetCurrentDate()); } CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/qa/uibase/wrtsh/wrtsh.cxx b/sw/qa/uibase/wrtsh/wrtsh.cxx index 6eb9e51a3f60..6f3478e7f99b 100644 --- a/sw/qa/uibase/wrtsh/wrtsh.cxx +++ b/sw/qa/uibase/wrtsh/wrtsh.cxx @@ -343,6 +343,8 @@ CPPUNIT_TEST_FIXTURE(Test, testSelectDateContentControl) // - Actual : test // i.e. the content control was not updated. CPPUNIT_ASSERT_EQUAL(OUString("2022-05-24"), pTextNode->GetExpandText(pWrtShell->GetLayout())); + CPPUNIT_ASSERT_EQUAL(OUString("2022-05-24T00:00:00Z"), + rFormatContentControl.GetContentControl()->GetCurrentDate()); } } diff --git a/sw/source/core/crsr/datecontentcontrolbutton.cxx b/sw/source/core/crsr/datecontentcontrolbutton.cxx index c52f546e9c6f..9de971b6f9f6 100644 --- a/sw/source/core/crsr/datecontentcontrolbutton.cxx +++ b/sw/source/core/crsr/datecontentcontrolbutton.cxx @@ -45,6 +45,18 @@ void SwDateContentControlButton::LaunchPopup() "modules/swriter/ui/contentcontrolcalendar.ui"); m_xPopup = m_xPopupBuilder->weld_popover("Calendar"); m_xCalendar = m_xPopupBuilder->weld_calendar("date"); + + // Read the doc model. + if (m_pContentControl) + { + const Date& rNullDate = m_pNumberFormatter->GetNullDate(); + double fCurrentDate = m_pContentControl->GetCurrentDateValue(); + if (fCurrentDate != 0) + { + m_xCalendar->set_date(rNullDate + sal_Int32(fCurrentDate)); + } + } + m_xCalendar->connect_activated(LINK(this, SwDateContentControlButton, SelectHandler)); SwContentControlButton::LaunchPopup(); m_xCalendar->grab_focus(); diff --git a/sw/source/core/txtnode/attrcontentcontrol.cxx b/sw/source/core/txtnode/attrcontentcontrol.cxx index 06dc388ee1ef..529a3ea9e331 100644 --- a/sw/source/core/txtnode/attrcontentcontrol.cxx +++ b/sw/source/core/txtnode/attrcontentcontrol.cxx @@ -32,6 +32,11 @@ using namespace com::sun::star; +namespace +{ +inline constexpr OUStringLiteral CURRENT_DATE_FORMAT = u"YYYY-MM-DD"; +} + SwFormatContentControl* SwFormatContentControl::CreatePoolDefault(sal_uInt16 nWhich) { return new SwFormatContentControl(nWhich); @@ -218,7 +223,7 @@ OUString SwContentControl::GetDateString() const if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND) { - // Try to find a format based on just the language. + // If not found, then create it. sal_Int32 nCheckPos = 0; SvNumFormatType nType; OUString aFormat = m_aDateFormat; @@ -242,6 +247,60 @@ OUString SwContentControl::GetDateString() const return aFormatted; } +void SwContentControl::SetCurrentDateValue(double fCurrentDate) +{ + SwDoc& rDoc = m_pTextNode->GetDoc(); + SvNumberFormatter* pNumberFormatter = rDoc.GetNumberFormatter(); + OUString aFormatted; + sal_uInt32 nFormat = pNumberFormatter->GetEntryKey(CURRENT_DATE_FORMAT, LANGUAGE_ENGLISH_US); + if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND) + { + // If not found, then create it. + sal_Int32 nCheckPos = 0; + SvNumFormatType nType; + OUString sFormat = CURRENT_DATE_FORMAT; + pNumberFormatter->PutEntry(sFormat, nCheckPos, nType, nFormat, LANGUAGE_ENGLISH_US); + } + + if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND) + { + return; + } + + const Color* pColor = nullptr; + pNumberFormatter->GetOutputString(fCurrentDate, nFormat, aFormatted, &pColor, false); + m_aCurrentDate = aFormatted + "T00:00:00Z"; +} + +double SwContentControl::GetCurrentDateValue() const +{ + if (m_aCurrentDate.isEmpty()) + { + return 0; + } + + SwDoc& rDoc = m_pTextNode->GetDoc(); + SvNumberFormatter* pNumberFormatter = rDoc.GetNumberFormatter(); + sal_uInt32 nFormat = pNumberFormatter->GetEntryKey(CURRENT_DATE_FORMAT, LANGUAGE_ENGLISH_US); + if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND) + { + sal_Int32 nCheckPos = 0; + SvNumFormatType nType; + OUString sFormat = CURRENT_DATE_FORMAT; + pNumberFormatter->PutEntry(sFormat, nCheckPos, nType, nFormat, LANGUAGE_ENGLISH_US); + } + + if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND) + { + return 0; + } + + double dCurrentDate = 0; + OUString aCurrentDate = m_aCurrentDate.replaceAll("T00:00:00Z", ""); + pNumberFormatter->IsNumberFormat(aCurrentDate, nFormat, dCurrentDate); + return dCurrentDate; +} + void SwContentControl::dumpAsXml(xmlTextWriterPtr pWriter) const { (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwContentControl")); @@ -265,6 +324,8 @@ void SwContentControl::dumpAsXml(xmlTextWriterPtr pWriter) const BAD_CAST(m_aDateFormat.toUtf8().getStr())); (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("date-language"), BAD_CAST(m_aDateLanguage.toUtf8().getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("current-date"), + BAD_CAST(m_aCurrentDate.toUtf8().getStr())); if (!m_aListItems.empty()) { diff --git a/sw/source/core/unocore/unocontentcontrol.cxx b/sw/source/core/unocore/unocontentcontrol.cxx index ef6959866b4c..393ab8d7dfb9 100644 --- a/sw/source/core/unocore/unocontentcontrol.cxx +++ b/sw/source/core/unocore/unocontentcontrol.cxx @@ -165,6 +165,7 @@ public: bool m_bDate; OUString m_aDateFormat; OUString m_aDateLanguage; + OUString m_aCurrentDate; Impl(SwXContentControl& rThis, SwDoc& rDoc, SwContentControl* pContentControl, const uno::Reference<text::XText>& xParentText, @@ -527,6 +528,7 @@ void SwXContentControl::AttachImpl(const uno::Reference<text::XTextRange>& xText pContentControl->SetDate(m_pImpl->m_bDate); pContentControl->SetDateFormat(m_pImpl->m_aDateFormat); pContentControl->SetDateLanguage(m_pImpl->m_aDateLanguage); + pContentControl->SetCurrentDate(m_pImpl->m_aCurrentDate); SwFormatContentControl aContentControl(pContentControl, nWhich); bool bSuccess @@ -826,6 +828,21 @@ void SAL_CALL SwXContentControl::setPropertyValue(const OUString& rPropertyName, } } } + else if (rPropertyName == UNO_NAME_CURRENT_DATE) + { + OUString aValue; + if (rValue >>= aValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_aCurrentDate = aValue; + } + else + { + m_pImpl->m_pContentControl->SetCurrentDate(aValue); + } + } + } else { throw beans::UnknownPropertyException(); @@ -949,6 +966,17 @@ uno::Any SAL_CALL SwXContentControl::getPropertyValue(const OUString& rPropertyN aRet <<= m_pImpl->m_pContentControl->GetDateLanguage(); } } + else if (rPropertyName == UNO_NAME_CURRENT_DATE) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_aCurrentDate; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetCurrentDate(); + } + } else { throw beans::UnknownPropertyException(); diff --git a/sw/source/core/unocore/unomap1.cxx b/sw/source/core/unocore/unomap1.cxx index 70e6fc0e5fc7..3eccea466868 100644 --- a/sw/source/core/unocore/unomap1.cxx +++ b/sw/source/core/unocore/unomap1.cxx @@ -1035,7 +1035,7 @@ const SfxItemPropertyMapEntry* SwUnoPropertyMapProvider::GetContentControlProper { u"" UNO_NAME_PICTURE, 0, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, { u"" UNO_NAME_DATE, 0, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, { u"" UNO_NAME_DATE_FORMAT, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, - { u"" UNO_NAME_DATE_LANGUAGE, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { u"" UNO_NAME_CURRENT_DATE, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, { u"", 0, css::uno::Type(), 0, 0 } }; diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index f253e77658d7..95dff36042e2 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -2382,7 +2382,15 @@ void DocxAttributeOutput::WriteContentControlStart() if (m_pContentControl->GetDate()) { - m_pSerializer->startElementNS(XML_w, XML_date); + OUString aCurrentDate = m_pContentControl->GetCurrentDate(); + if (aCurrentDate.isEmpty()) + { + m_pSerializer->startElementNS(XML_w, XML_date); + } + else + { + m_pSerializer->startElementNS(XML_w, XML_date, FSNS(XML_w, XML_fullDate), aCurrentDate); + } OUString aDateFormat = m_pContentControl->GetDateFormat(); if (!aDateFormat.isEmpty()) { diff --git a/sw/source/uibase/wrtsh/wrtsh3.cxx b/sw/source/uibase/wrtsh/wrtsh3.cxx index f01946e45d17..e4b594770282 100644 --- a/sw/source/uibase/wrtsh/wrtsh3.cxx +++ b/sw/source/uibase/wrtsh/wrtsh3.cxx @@ -190,9 +190,12 @@ bool SwWrtShell::GotoContentControl(const SwFormatContentControl& rContentContro aRewriter.AddRule(UndoArg3, SwResId(STR_START_QUOTE) + aNewState + SwResId(STR_END_QUOTE)); GetIDocumentUndoRedo().StartUndo(SwUndoId::REPLACE, &aRewriter); + // Write the doc model. + pContentControl->SetCurrentDateValue(*pContentControl->GetSelectedDate()); + pContentControl->SetSelectedDate(std::nullopt); + // Update the content. DelLeft(); - pContentControl->SetSelectedDate(std::nullopt); Insert(aNewState); GetIDocumentUndoRedo().EndUndo(SwUndoId::REPLACE, &aRewriter); diff --git a/xmloff/qa/unit/data/content-control-date.fodt b/xmloff/qa/unit/data/content-control-date.fodt index dd3749a02e99..c49e51339c3b 100644 --- a/xmloff/qa/unit/data/content-control-date.fodt +++ b/xmloff/qa/unit/data/content-control-date.fodt @@ -2,7 +2,7 @@ <office:document xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> <office:body> <office:text> - <text:p><loext:content-control loext:date="true" loext:date-format="YYYY-MM-DD" loext:date-rfc-language-tag="en-US">choose a date</loext:content-control></text:p> + <text:p><loext:content-control loext:date="true" loext:date-format="YYYY-MM-DD" loext:date-rfc-language-tag="en-US" loext:current-date="2022-05-25T00:00:00Z">choose a date</loext:content-control></text:p> </office:text> </office:body> </office:document> diff --git a/xmloff/qa/unit/text.cxx b/xmloff/qa/unit/text.cxx index 4f32c23025de..9ac816298b60 100644 --- a/xmloff/qa/unit/text.cxx +++ b/xmloff/qa/unit/text.cxx @@ -665,6 +665,8 @@ CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testDateContentControlExport) xContentControlProps->setPropertyValue("Date", uno::Any(true)); xContentControlProps->setPropertyValue("DateFormat", uno::Any(OUString("YYYY-MM-DD"))); xContentControlProps->setPropertyValue("DateLanguage", uno::Any(OUString("en-US"))); + xContentControlProps->setPropertyValue("CurrentDate", + uno::Any(OUString("2022-05-25T00:00:00Z"))); xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); // When exporting to ODT: @@ -685,6 +687,7 @@ CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testDateContentControlExport) assertXPath(pXmlDoc, "//loext:content-control", "date", "true"); assertXPath(pXmlDoc, "//loext:content-control", "date-format", "YYYY-MM-DD"); assertXPath(pXmlDoc, "//loext:content-control", "date-rfc-language-tag", "en-US"); + assertXPath(pXmlDoc, "//loext:content-control", "current-date", "2022-05-25T00:00:00Z"); } CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testDateContentControlImport) @@ -721,6 +724,9 @@ CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testDateContentControlImport) OUString aDateLanguage; xContentControlProps->getPropertyValue("DateLanguage") >>= aDateLanguage; CPPUNIT_ASSERT_EQUAL(OUString("en-US"), aDateLanguage); + OUString aCurrentDate; + xContentControlProps->getPropertyValue("CurrentDate") >>= aCurrentDate; + CPPUNIT_ASSERT_EQUAL(OUString("2022-05-25T00:00:00Z"), aCurrentDate); } CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/xmloff/source/text/txtparae.cxx b/xmloff/source/text/txtparae.cxx index e2ec85cb8105..4105772445b2 100644 --- a/xmloff/source/text/txtparae.cxx +++ b/xmloff/source/text/txtparae.cxx @@ -3940,6 +3940,12 @@ void XMLTextParagraphExport::ExportContentControl( { GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_DATE_RFC_LANGUAGE_TAG, aDateLanguage); } + OUString aCurrentDate; + xPropertySet->getPropertyValue("CurrentDate") >>= aCurrentDate; + if (!aCurrentDate.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_CURRENT_DATE, aCurrentDate); + } } SvXMLElementExport aElem(GetExport(), bExport, XML_NAMESPACE_LO_EXT, XML_CONTENT_CONTROL, false, diff --git a/xmloff/source/text/xmlcontentcontrolcontext.cxx b/xmloff/source/text/xmlcontentcontrolcontext.cxx index 24b81e04a67c..22af458e43bc 100644 --- a/xmloff/source/text/xmlcontentcontrolcontext.cxx +++ b/xmloff/source/text/xmlcontentcontrolcontext.cxx @@ -112,6 +112,11 @@ void XMLContentControlContext::startFastElement( m_aDateLanguage = rIter.toString(); break; } + case XML_ELEMENT(LO_EXT, XML_CURRENT_DATE): + { + m_aCurrentDate = rIter.toString(); + break; + } default: XMLOFF_WARN_UNKNOWN("xmloff", rIter); } @@ -193,6 +198,10 @@ void XMLContentControlContext::endFastElement(sal_Int32) { xPropertySet->setPropertyValue("DateLanguage", uno::Any(m_aDateLanguage)); } + if (!m_aCurrentDate.isEmpty()) + { + xPropertySet->setPropertyValue("CurrentDate", uno::Any(m_aCurrentDate)); + } } css::uno::Reference<css::xml::sax::XFastContextHandler> diff --git a/xmloff/source/text/xmlcontentcontrolcontext.hxx b/xmloff/source/text/xmlcontentcontrolcontext.hxx index 623ef97e8df3..2c3ecfb9cafb 100644 --- a/xmloff/source/text/xmlcontentcontrolcontext.hxx +++ b/xmloff/source/text/xmlcontentcontrolcontext.hxx @@ -47,6 +47,7 @@ class XMLContentControlContext : public SvXMLImportContext bool m_bDate = false; OUString m_aDateFormat; OUString m_aDateLanguage; + OUString m_aCurrentDate; public: XMLContentControlContext(SvXMLImport& rImport, sal_Int32 nElement, XMLHints_Impl& rHints, |