summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2022-05-25 09:58:28 +0200
committerMiklos Vajna <vmiklos@collabora.com>2022-05-25 11:52:02 +0200
commitce5d609da9d20b3c91f6f8eb4ee88451cbd55a9d (patch)
tree2aba1fb0c225d7b89d67e244e56d68220b041135
parentd77db907465547f8704fd32b2c90165b54873dba (diff)
sw content controls, date: show a date picker on click
- add a new SwContentControl::GetDateString() that knows how to produce a formatted date, taking the language and the date format into account - add a new SwDateContentControlButton that knows how to open popup a calendar on click and that puts the selected date into SwContentControl::m_oSelectedDate - extend SwWrtShell::GotoContentControl() to consume that selected date & update the document text accordingly - in case SwSelPaintRects::HighlightContentControl() notices a date content control, create an instance of this newly introduced SwDateContentControlButton Change-Id: Ia2cb0fa3aefbf543b8dc2e96bcebb41408eb12c3 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/134926 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins
-rw-r--r--sw/Library_sw.mk1
-rw-r--r--sw/UIConfig_swriter.mk1
-rw-r--r--sw/inc/formatcontentcontrol.hxx10
-rw-r--r--sw/qa/core/unocore/unocore.cxx7
-rw-r--r--sw/qa/uibase/wrtsh/wrtsh.cxx37
-rw-r--r--sw/source/core/crsr/crstrvl.cxx2
-rw-r--r--sw/source/core/crsr/datecontentcontrolbutton.cxx59
-rw-r--r--sw/source/core/crsr/viscrs.cxx21
-rw-r--r--sw/source/core/inc/datecontentcontrolbutton.hxx41
-rw-r--r--sw/source/core/txtnode/attrcontentcontrol.cxx35
-rw-r--r--sw/source/uibase/wrtsh/wrtsh3.cxx21
-rw-r--r--sw/uiconfig/swriter/ui/contentcontrolcalendar.ui28
12 files changed, 256 insertions, 7 deletions
diff --git a/sw/Library_sw.mk b/sw/Library_sw.mk
index eec16fd5612c..22694869fb54 100644
--- a/sw/Library_sw.mk
+++ b/sw/Library_sw.mk
@@ -164,6 +164,7 @@ $(eval $(call gb_Library_add_exception_objects,sw,\
sw/source/core/crsr/crstrvl1 \
sw/source/core/crsr/DateFormFieldButton \
sw/source/core/crsr/DropDownFormFieldButton \
+ sw/source/core/crsr/datecontentcontrolbutton \
sw/source/core/crsr/dropdowncontentcontrolbutton \
sw/source/core/crsr/findattr \
sw/source/core/crsr/findcoll \
diff --git a/sw/UIConfig_swriter.mk b/sw/UIConfig_swriter.mk
index 012d86008b39..5dafec57ee88 100644
--- a/sw/UIConfig_swriter.mk
+++ b/sw/UIConfig_swriter.mk
@@ -121,6 +121,7 @@ $(eval $(call gb_UIConfig_add_uifiles,modules/swriter,\
sw/uiconfig/swriter/ui/combobox \
sw/uiconfig/swriter/ui/comboboxfragment \
sw/uiconfig/swriter/ui/conditionpage \
+ sw/uiconfig/swriter/ui/contentcontrolcalendar \
sw/uiconfig/swriter/ui/contentcontroldlg \
sw/uiconfig/swriter/ui/contentcontroldropdown \
sw/uiconfig/swriter/ui/contentcontrollistitemdlg \
diff --git a/sw/inc/formatcontentcontrol.hxx b/sw/inc/formatcontentcontrol.hxx
index 6e3da73412ba..5137037df62a 100644
--- a/sw/inc/formatcontentcontrol.hxx
+++ b/sw/inc/formatcontentcontrol.hxx
@@ -137,6 +137,9 @@ class SW_DLLPUBLIC SwContentControl : public sw::BroadcastingModify
/// Stores a list item index, in case the doc model is not yet updated.
std::optional<size_t> m_oSelectedListItem;
+ /// Stores a date timestamp, in case the doc model is not yet updated.
+ std::optional<double> m_oSelectedDate;
+
public:
SwTextContentControl* GetTextAttr() const;
@@ -212,6 +215,9 @@ public:
OUString GetDateLanguage() const { return m_aDateLanguage; }
+ /// Formats m_oSelectedDate, taking m_aDateFormat and m_aDateLanguage into account.
+ OUString GetDateString() const;
+
void SetSelectedListItem(std::optional<size_t> oSelectedListItem)
{
m_oSelectedListItem = oSelectedListItem;
@@ -219,6 +225,10 @@ public:
std::optional<size_t> GetSelectedListItem() const { return m_oSelectedListItem; }
+ void SetSelectedDate(std::optional<double> oSelectedDate) { m_oSelectedDate = oSelectedDate; }
+
+ std::optional<double> GetSelectedDate() const { return m_oSelectedDate; }
+
virtual void dumpAsXml(xmlTextWriterPtr pWriter) const;
};
diff --git a/sw/qa/core/unocore/unocore.cxx b/sw/qa/core/unocore/unocore.cxx
index 16959a06f377..a998810e6029 100644
--- a/sw/qa/core/unocore/unocore.cxx
+++ b/sw/qa/core/unocore/unocore.cxx
@@ -590,12 +590,7 @@ CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlDate)
uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
uno::Reference<text::XText> xText = xTextDocument->getText();
uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
- uno::Reference<beans::XPropertySet> xTextGraphic(
- xMSF->createInstance("com.sun.star.text.TextGraphicObject"), uno::UNO_QUERY);
- xTextGraphic->setPropertyValue("AnchorType",
- uno::Any(text::TextContentAnchorType_AS_CHARACTER));
- uno::Reference<text::XTextContent> xTextContent(xTextGraphic, uno::UNO_QUERY);
- xText->insertTextContent(xCursor, xTextContent, false);
+ xText->insertString(xCursor, "test", /*bAbsorb=*/false);
xCursor->gotoStart(/*bExpand=*/false);
xCursor->gotoEnd(/*bExpand=*/true);
uno::Reference<text::XTextContent> xContentControl(
diff --git a/sw/qa/uibase/wrtsh/wrtsh.cxx b/sw/qa/uibase/wrtsh/wrtsh.cxx
index 65a41086dce4..06bb8a45edc1 100644
--- a/sw/qa/uibase/wrtsh/wrtsh.cxx
+++ b/sw/qa/uibase/wrtsh/wrtsh.cxx
@@ -307,6 +307,43 @@ CPPUNIT_TEST_FIXTURE(Test, testInsertPictureContentControl)
CPPUNIT_ASSERT(pContentControl->GetPicture());
CPPUNIT_ASSERT(pTextNode->GetTextAttrForCharAt(1, RES_TXTATR_FLYCNT));
}
+
+CPPUNIT_TEST_FIXTURE(Test, testSelectDateContentControl)
+{
+ // Given a document with a date content control:
+ SwDoc* pDoc = createSwDoc();
+ uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XText> xText = xTextDocument->getText();
+ uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
+ xText->insertString(xCursor, "test", /*bAbsorb=*/false);
+ xCursor->gotoStart(/*bExpand=*/false);
+ xCursor->gotoEnd(/*bExpand=*/true);
+ uno::Reference<text::XTextContent> xContentControl(
+ xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
+ xContentControlProps->setPropertyValue("Date", uno::Any(true));
+ xContentControlProps->setPropertyValue("DateFormat", uno::Any(OUString("YYYY-MM-DD")));
+ xContentControlProps->setPropertyValue("DateLanguage", uno::Any(OUString("en-US")));
+ xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
+
+ // When clicking on that content control:
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ SwTextNode* pTextNode = pWrtShell->GetCursor()->GetNode().GetTextNode();
+ SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_CONTENTCONTROL);
+ auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
+ auto& rFormatContentControl
+ = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
+ rFormatContentControl.GetContentControl()->SetSelectedDate(44705);
+ pWrtShell->GotoContentControl(rFormatContentControl);
+
+ // Then make sure that the document text is updated:
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 2022-05-24
+ // - Actual : test
+ // i.e. the content control was not updated.
+ CPPUNIT_ASSERT_EQUAL(OUString("2022-05-24"), pTextNode->GetExpandText(pWrtShell->GetLayout()));
+}
}
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/core/crsr/crstrvl.cxx b/sw/source/core/crsr/crstrvl.cxx
index e36cf1671007..ee12399323ac 100644
--- a/sw/source/core/crsr/crstrvl.cxx
+++ b/sw/source/core/crsr/crstrvl.cxx
@@ -858,7 +858,7 @@ bool SwCursorShell::GotoFormatContentControl(const SwFormatContentControl& rCont
bool bRet = false;
std::shared_ptr<SwContentControl> pContentControl = rContentControl.GetContentControl();
if (!pContentControl->GetShowingPlaceHolder() && !pContentControl->GetCheckbox()
- && !pContentControl->GetSelectedListItem())
+ && !pContentControl->GetSelectedListItem() && !pContentControl->GetSelectedDate())
{
return bRet;
}
diff --git a/sw/source/core/crsr/datecontentcontrolbutton.cxx b/sw/source/core/crsr/datecontentcontrolbutton.cxx
new file mode 100644
index 000000000000..c52f546e9c6f
--- /dev/null
+++ b/sw/source/core/crsr/datecontentcontrolbutton.cxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <datecontentcontrolbutton.hxx>
+
+#include <svl/numformat.hxx>
+#include <tools/date.hxx>
+#include <vcl/svapp.hxx>
+
+#include <edtwin.hxx>
+#include <formatcontentcontrol.hxx>
+#include <view.hxx>
+#include <wrtsh.hxx>
+
+IMPL_LINK(SwDateContentControlButton, SelectHandler, weld::Calendar&, rCalendar, void)
+{
+ const Date& rNullDate = m_pNumberFormatter->GetNullDate();
+ double fDate = rCalendar.get_date() - rNullDate;
+ m_xPopup->popdown();
+ m_pContentControl->SetSelectedDate(fDate);
+ SwView& rView = static_cast<SwEditWin*>(GetParent())->GetView();
+ SwWrtShell& rWrtShell = rView.GetWrtShell();
+ rWrtShell.GotoContentControl(*m_pContentControl->GetFormatContentControl());
+}
+
+SwDateContentControlButton::SwDateContentControlButton(
+ SwEditWin* pEditWin, const std::shared_ptr<SwContentControl>& pContentControl,
+ SvNumberFormatter* pNumberFormatter)
+ : SwContentControlButton(pEditWin, pContentControl)
+ , m_pNumberFormatter(pNumberFormatter)
+{
+}
+
+SwDateContentControlButton::~SwDateContentControlButton() { disposeOnce(); }
+
+void SwDateContentControlButton::LaunchPopup()
+{
+ m_xPopupBuilder = Application::CreateBuilder(GetFrameWeld(),
+ "modules/swriter/ui/contentcontrolcalendar.ui");
+ m_xPopup = m_xPopupBuilder->weld_popover("Calendar");
+ m_xCalendar = m_xPopupBuilder->weld_calendar("date");
+ m_xCalendar->connect_activated(LINK(this, SwDateContentControlButton, SelectHandler));
+ SwContentControlButton::LaunchPopup();
+ m_xCalendar->grab_focus();
+}
+
+void SwDateContentControlButton::DestroyPopup()
+{
+ m_xCalendar.reset();
+ SwContentControlButton::DestroyPopup();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/crsr/viscrs.cxx b/sw/source/core/crsr/viscrs.cxx
index 6991ee8a7a95..9863e1a75324 100644
--- a/sw/source/core/crsr/viscrs.cxx
+++ b/sw/source/core/crsr/viscrs.cxx
@@ -63,6 +63,7 @@
#include <wrtsh.hxx>
#include <textcontentcontrol.hxx>
#include <dropdowncontentcontrolbutton.hxx>
+#include <datecontentcontrolbutton.hxx>
// Here static members are defined. They will get changed on alteration of the
// MapMode. This is done so that on ShowCursor the same size does not have to be
@@ -753,6 +754,26 @@ void SwSelPaintRects::HighlightContentControl()
m_pContentControlButton->Show();
}
}
+ if (pContentControl && pContentControl->GetDate())
+ {
+ auto pWrtShell = dynamic_cast<const SwWrtShell*>(GetShell());
+ if (pWrtShell)
+ {
+ auto& rEditWin = const_cast<SwEditWin&>(pWrtShell->GetView().GetEditWin());
+ if (m_pContentControlButton
+ && m_pContentControlButton->GetContentControl() != pContentControl)
+ {
+ m_pContentControlButton.disposeAndClear();
+ }
+ if (!m_pContentControlButton)
+ {
+ m_pContentControlButton = VclPtr<SwDateContentControlButton>::Create(
+ &rEditWin, pContentControl, pWrtShell->GetDoc()->GetNumberFormatter());
+ }
+ m_pContentControlButton->CalcPosAndSize(aLastPortionPaintArea);
+ m_pContentControlButton->Show();
+ }
+ }
}
else
{
diff --git a/sw/source/core/inc/datecontentcontrolbutton.hxx b/sw/source/core/inc/datecontentcontrolbutton.hxx
new file mode 100644
index 000000000000..48b08f2db981
--- /dev/null
+++ b/sw/source/core/inc/datecontentcontrolbutton.hxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "contentcontrolbutton.hxx"
+
+class SwEditWin;
+class SvNumberFormatter;
+class SwContentControl;
+
+/**
+ * This button is shown when the cursor is on a date content control. The user can select a date
+ * from a date picker.
+ */
+class SwDateContentControlButton final : public SwContentControlButton
+{
+private:
+ SvNumberFormatter* m_pNumberFormatter;
+
+ std::unique_ptr<weld::Calendar> m_xCalendar;
+
+ DECL_LINK(SelectHandler, weld::Calendar&, void);
+
+public:
+ SwDateContentControlButton(SwEditWin* pEditWin,
+ const std::shared_ptr<SwContentControl>& pContentControl,
+ SvNumberFormatter* pNumberFormatter);
+ ~SwDateContentControlButton() override;
+
+ void LaunchPopup() override;
+ void DestroyPopup() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/attrcontentcontrol.cxx b/sw/source/core/txtnode/attrcontentcontrol.cxx
index 7eb39907ce0c..06dc388ee1ef 100644
--- a/sw/source/core/txtnode/attrcontentcontrol.cxx
+++ b/sw/source/core/txtnode/attrcontentcontrol.cxx
@@ -24,9 +24,11 @@
#include <sal/log.hxx>
#include <comphelper/propertyvalue.hxx>
#include <comphelper/sequenceashashmap.hxx>
+#include <svl/numformat.hxx>
#include <ndtxt.hxx>
#include <textcontentcontrol.hxx>
+#include <doc.hxx>
using namespace com::sun::star;
@@ -207,6 +209,39 @@ void SwContentControl::SwClientNotify(const SwModify&, const SfxHint& rHint)
}
}
+OUString SwContentControl::GetDateString() const
+{
+ SwDoc& rDoc = m_pTextNode->GetDoc();
+ SvNumberFormatter* pNumberFormatter = rDoc.GetNumberFormatter();
+ sal_uInt32 nFormat = pNumberFormatter->GetEntryKey(
+ m_aDateFormat, LanguageTag(m_aDateLanguage).getLanguageType());
+
+ if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
+ {
+ // Try to find a format based on just the language.
+ sal_Int32 nCheckPos = 0;
+ SvNumFormatType nType;
+ OUString aFormat = m_aDateFormat;
+ pNumberFormatter->PutEntry(aFormat, nCheckPos, nType, nFormat,
+ LanguageTag(m_aDateLanguage).getLanguageType());
+ }
+
+ const Color* pColor = nullptr;
+ OUString aFormatted;
+ if (!m_oSelectedDate)
+ {
+ return OUString();
+ }
+
+ if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
+ {
+ return OUString();
+ }
+
+ pNumberFormatter->GetOutputString(*m_oSelectedDate, nFormat, aFormatted, &pColor, false);
+ return aFormatted;
+}
+
void SwContentControl::dumpAsXml(xmlTextWriterPtr pWriter) const
{
(void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwContentControl"));
diff --git a/sw/source/uibase/wrtsh/wrtsh3.cxx b/sw/source/uibase/wrtsh/wrtsh3.cxx
index fcb123662bcf..f01946e45d17 100644
--- a/sw/source/uibase/wrtsh/wrtsh3.cxx
+++ b/sw/source/uibase/wrtsh/wrtsh3.cxx
@@ -178,6 +178,27 @@ bool SwWrtShell::GotoContentControl(const SwFormatContentControl& rContentContro
LockView(/*bViewLocked=*/false);
ShowCursor();
}
+ else if (bRet && pContentControl && pContentControl->GetSelectedDate())
+ {
+ // Date: GotoFormatContentControl() selected the old content.
+ LockView(/*bViewLocked=*/true);
+ OUString aOldState = GetCursorDescr();
+ OUString aNewState = pContentControl->GetDateString();
+ SwRewriter aRewriter;
+ aRewriter.AddRule(UndoArg1, aOldState);
+ aRewriter.AddRule(UndoArg2, SwResId(STR_YIELDS));
+ aRewriter.AddRule(UndoArg3, SwResId(STR_START_QUOTE) + aNewState + SwResId(STR_END_QUOTE));
+ GetIDocumentUndoRedo().StartUndo(SwUndoId::REPLACE, &aRewriter);
+
+ // Update the content.
+ DelLeft();
+ pContentControl->SetSelectedDate(std::nullopt);
+ Insert(aNewState);
+
+ GetIDocumentUndoRedo().EndUndo(SwUndoId::REPLACE, &aRewriter);
+ LockView(/*bViewLocked=*/false);
+ ShowCursor();
+ }
if (bRet && IsSelFrameMode())
{
diff --git a/sw/uiconfig/swriter/ui/contentcontrolcalendar.ui b/sw/uiconfig/swriter/ui/contentcontrolcalendar.ui
new file mode 100644
index 000000000000..e5355f723621
--- /dev/null
+++ b/sw/uiconfig/swriter/ui/contentcontrolcalendar.ui
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="sw">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkPopover" id="Calendar">
+ <property name="can-focus">False</property>
+ <property name="position">bottom</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCalendar" id="date">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>