summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2022-06-01 08:30:03 +0200
committerMiklos Vajna <vmiklos@collabora.com>2022-06-01 09:09:40 +0200
commit9cb1a07dc2760a30d7f321aa7fa4ce2a460dfa6c (patch)
tree9d2d703bc1d8dfbb8f5cdc61f3c4607daeae4d56
parent64f8a70298695d1952c3a399e897755ab861add5 (diff)
sw content controls, date: add LOK API
- send a LOK_CALLBACK_CONTENT_CONTROL with date=true when entering a date content control - extend lok::Document::sendContentControlEvent() to be able to set the date of a date content control (after the client's date picker is closed) - update gtktiledviewer to work with these Change-Id: I0abf21eb1d4ba233050f0aa2607b68740c048262 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135214 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins
-rw-r--r--include/LibreOfficeKit/LibreOfficeKit.hxx6
-rw-r--r--include/LibreOfficeKit/LibreOfficeKitEnums.h7
-rw-r--r--libreofficekit/qa/gtktiledviewer/gtv-lokdocview-signal-handlers.cxx3
-rw-r--r--libreofficekit/qa/gtktiledviewer/gtv-main-toolbar.cxx4
-rw-r--r--libreofficekit/qa/gtktiledviewer/gtv-main-toolbar.hxx1
-rw-r--r--libreofficekit/qa/gtktiledviewer/gtv-signal-handlers.cxx27
-rw-r--r--libreofficekit/qa/gtktiledviewer/gtv-signal-handlers.hxx1
-rw-r--r--libreofficekit/qa/gtktiledviewer/gtv.ui45
-rw-r--r--sw/qa/extras/tiledrendering/tiledrendering.cxx57
-rw-r--r--sw/source/core/crsr/viscrs.cxx5
-rw-r--r--sw/source/uibase/uno/unotxdoc.cxx61
11 files changed, 217 insertions, 0 deletions
diff --git a/include/LibreOfficeKit/LibreOfficeKit.hxx b/include/LibreOfficeKit/LibreOfficeKit.hxx
index 993654c88345..6dbfbf964b29 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.hxx
+++ b/include/LibreOfficeKit/LibreOfficeKit.hxx
@@ -851,6 +851,12 @@ public:
* "type": "picture",
* "changed": "file:///path/to/test.png"
* }
+ *
+ * To select a date of the current date content control:
+ * {
+ * "type": "date",
+ * "selected": "2022-05-29T00:00:00Z"
+ * }
*/
void sendContentControlEvent(const char* pArguments)
{
diff --git a/include/LibreOfficeKit/LibreOfficeKitEnums.h b/include/LibreOfficeKit/LibreOfficeKitEnums.h
index 63ddec957be0..f1b2328510b3 100644
--- a/include/LibreOfficeKit/LibreOfficeKitEnums.h
+++ b/include/LibreOfficeKit/LibreOfficeKitEnums.h
@@ -822,6 +822,13 @@ typedef enum
* {
* "action": "change-picture"
* }
+ *
+ * Entered a date content control:
+ * {
+ * "action": "show",
+ * "rectangles": "...",
+ * "date": "true"
+ * }
*/
LOK_CALLBACK_CONTENT_CONTROL = 55,
diff --git a/libreofficekit/qa/gtktiledviewer/gtv-lokdocview-signal-handlers.cxx b/libreofficekit/qa/gtktiledviewer/gtv-lokdocview-signal-handlers.cxx
index 4e702364a6a9..8d1b3eb67e10 100644
--- a/libreofficekit/qa/gtktiledviewer/gtv-lokdocview-signal-handlers.cxx
+++ b/libreofficekit/qa/gtktiledviewer/gtv-lokdocview-signal-handlers.cxx
@@ -229,6 +229,9 @@ void LOKDocViewSigHandlers::contentControl(LOKDocView* pDocView, gchar* pJson, g
}
}
+ boost::optional<boost::property_tree::ptree&> oDate = aTree.get_child_optional("date");
+ gtk_widget_set_sensitive(GTK_WIDGET(toolbar->m_pContentControlDateSelector), bool(oDate));
+
gtv_application_window_set_part_broadcast(window, true);
}
diff --git a/libreofficekit/qa/gtktiledviewer/gtv-main-toolbar.cxx b/libreofficekit/qa/gtktiledviewer/gtv-main-toolbar.cxx
index afe6162f76fc..84c5335b32c2 100644
--- a/libreofficekit/qa/gtktiledviewer/gtv-main-toolbar.cxx
+++ b/libreofficekit/qa/gtktiledviewer/gtv-main-toolbar.cxx
@@ -118,6 +118,8 @@ gtv_main_toolbar_init(GtvMainToolbar* toolbar)
toolbar->m_pFormulabar = GTK_WIDGET(gtk_builder_get_object(builder.get(), "formulabar_entry"));
toolbar->m_pContentControlSelector
= GTK_WIDGET(gtk_builder_get_object(builder.get(), "combo_contentcontrolselector"));
+ toolbar->m_pContentControlDateSelector
+ = GTK_WIDGET(gtk_builder_get_object(builder.get(), "menu_contentcontroldateselector"));
// TODO: compile with -rdynamic and get rid of it
gtk_builder_add_callback_symbol(builder.get(), "btn_clicked", G_CALLBACK(btn_clicked));
@@ -132,6 +134,8 @@ gtv_main_toolbar_init(GtvMainToolbar* toolbar)
gtk_builder_add_callback_symbol(builder.get(), "changePart", G_CALLBACK(changePart));
gtk_builder_add_callback_symbol(builder.get(), "changeContentControl",
G_CALLBACK(changeContentControl));
+ gtk_builder_add_callback_symbol(builder.get(), "changeDateContentControl",
+ G_CALLBACK(changeDateContentControl));
gtk_builder_add_callback_symbol(builder.get(), "changeZoom", G_CALLBACK(changeZoom));
gtk_builder_add_callback_symbol(builder.get(), "toggleFindbar", G_CALLBACK(toggleFindbar));
gtk_builder_add_callback_symbol(builder.get(), "documentRedline", G_CALLBACK(documentRedline));
diff --git a/libreofficekit/qa/gtktiledviewer/gtv-main-toolbar.hxx b/libreofficekit/qa/gtktiledviewer/gtv-main-toolbar.hxx
index e385e6e855d1..91827ef92695 100644
--- a/libreofficekit/qa/gtktiledviewer/gtv-main-toolbar.hxx
+++ b/libreofficekit/qa/gtktiledviewer/gtv-main-toolbar.hxx
@@ -30,6 +30,7 @@ struct GtvMainToolbar
GtkWidget* m_pAddressbar;
GtkWidget* m_pFormulabar;
GtkWidget* m_pContentControlSelector;
+ GtkWidget* m_pContentControlDateSelector;
};
struct GtvMainToolbarClass
diff --git a/libreofficekit/qa/gtktiledviewer/gtv-signal-handlers.cxx b/libreofficekit/qa/gtktiledviewer/gtv-signal-handlers.cxx
index 0afce9b671db..bb0e7edd390d 100644
--- a/libreofficekit/qa/gtktiledviewer/gtv-signal-handlers.cxx
+++ b/libreofficekit/qa/gtktiledviewer/gtv-signal-handlers.cxx
@@ -334,6 +334,33 @@ void changeContentControl(GtkWidget* pSelector, gpointer /*pItem*/)
}
}
+void changeDateContentControl(GtkWidget* pSelector, gpointer /*pItem*/)
+{
+ GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pSelector));
+ if (gtv_application_window_get_part_broadcast(window) && window->lokdocview)
+ {
+ GtkPopover* pPopover = GTK_POPOVER(gtk_widget_get_parent(gtk_widget_get_parent(pSelector)));
+ guint nYear, nMonth, nDay;
+ gtk_calendar_get_date(GTK_CALENDAR(pSelector), &nYear, &nMonth, &nDay);
+ gtk_popover_popdown(pPopover);
+
+ std::stringstream aDate;
+ aDate << std::setfill('0') << std::setw(4) << nYear;
+ aDate << "-";
+ aDate << std::setfill('0') << std::setw(2) << (nMonth + 1);
+ aDate << "-";
+ aDate << std::setfill('0') << std::setw(2) << nDay;
+ aDate << "T00:00:00Z";
+ boost::property_tree::ptree aValues;
+ aValues.put("type", "date");
+ aValues.put("selected", aDate.str());
+ std::stringstream aStream;
+ boost::property_tree::write_json(aStream, aValues);
+ std::string aJson = aStream.str();
+ lok_doc_view_send_content_control_event(LOK_DOC_VIEW(window->lokdocview), aJson.c_str());
+ }
+}
+
void changeZoom( GtkWidget* pButton, gpointer /* pItem */ )
{
static const float fZooms[] = { 0.25, 0.5, 0.75, 1.0, 1.5, 2.0, 3.0, 5.0 };
diff --git a/libreofficekit/qa/gtktiledviewer/gtv-signal-handlers.hxx b/libreofficekit/qa/gtktiledviewer/gtv-signal-handlers.hxx
index c5cf89c281fc..c06017d87414 100644
--- a/libreofficekit/qa/gtktiledviewer/gtv-signal-handlers.hxx
+++ b/libreofficekit/qa/gtktiledviewer/gtv-signal-handlers.hxx
@@ -69,6 +69,7 @@ gboolean signalFormulabar(GtkWidget* /*pWidget*/, GdkEventKey* /*pEvent*/, gpoin
void changeContentControl(GtkWidget* pSelector, gpointer /*pItem*/);
+void changeDateContentControl(GtkWidget* pSelector, gpointer /*pItem*/);
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/libreofficekit/qa/gtktiledviewer/gtv.ui b/libreofficekit/qa/gtktiledviewer/gtv.ui
index 26e15a0a9e3d..79cb9a9ec409 100644
--- a/libreofficekit/qa/gtktiledviewer/gtv.ui
+++ b/libreofficekit/qa/gtktiledviewer/gtv.ui
@@ -446,6 +446,27 @@
</packing>
</child>
<child>
+ <object class="GtkToolItem" id="contentcontroldateselectortoolitem">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuButton" id="menu_contentcontroldateselector">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="tooltip_text">Content control date</property>
+ <property name="popover">calendar</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkToggleToolButton" id="btn_editmode">
<property name="visible">True</property>
<property name="label" translatable="yes">Turn on/off edit mode</property>
@@ -779,4 +800,28 @@
</packing>
</child>
</object>
+ <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>
+ <signal name="day-selected-double-click" handler="changeDateContentControl" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
</interface>
diff --git a/sw/qa/extras/tiledrendering/tiledrendering.cxx b/sw/qa/extras/tiledrendering/tiledrendering.cxx
index 2a8c05fe19e6..a9205c07841a 100644
--- a/sw/qa/extras/tiledrendering/tiledrendering.cxx
+++ b/sw/qa/extras/tiledrendering/tiledrendering.cxx
@@ -172,6 +172,7 @@ public:
void testContentControl();
void testDropDownContentControl();
void testPictureContentControl();
+ void testDateContentControl();
CPPUNIT_TEST_SUITE(SwTiledRenderingTest);
CPPUNIT_TEST(testRegisterCallback);
@@ -262,6 +263,7 @@ public:
CPPUNIT_TEST(testContentControl);
CPPUNIT_TEST(testDropDownContentControl);
CPPUNIT_TEST(testPictureContentControl);
+ CPPUNIT_TEST(testDateContentControl);
CPPUNIT_TEST_SUITE_END();
private:
@@ -3784,6 +3786,61 @@ void SwTiledRenderingTest::testPictureContentControl()
}
+void SwTiledRenderingTest::testDateContentControl()
+{
+ // Given a document with a date content control:
+ SwXTextDocument* pXTextDocument = createDoc();
+ SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
+ 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, "choose a date", /*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);
+ pWrtShell->SttEndDoc(/*bStt=*/true);
+ m_aContentControl.clear();
+
+ // When entering that content control:
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, /*nCount=*/1, /*bBasicCall=*/false);
+
+ // Then make sure that the callback is emitted:
+ CPPUNIT_ASSERT(!m_aContentControl.isEmpty());
+ {
+ std::stringstream aStream(m_aContentControl.getStr());
+ boost::property_tree::ptree aTree;
+ boost::property_tree::read_json(aStream, aTree);
+ OString sAction = aTree.get_child("action").get_value<std::string>().c_str();
+ CPPUNIT_ASSERT_EQUAL(OString("show"), sAction);
+ OString sRectangles = aTree.get_child("rectangles").get_value<std::string>().c_str();
+ CPPUNIT_ASSERT(!sRectangles.isEmpty());
+ boost::optional<boost::property_tree::ptree&> oDate = aTree.get_child_optional("date");
+ CPPUNIT_ASSERT(oDate);
+ }
+
+ // And when selecting a date:
+ std::map<OUString, OUString> aArguments;
+ aArguments.emplace("type", "date");
+ aArguments.emplace("selected", "2022-05-30T00:00:00Z");
+ pXTextDocument->executeContentControlEvent(aArguments);
+
+ // Then make sure that the document is updated accordingly:
+ SwTextNode* pTextNode = pWrtShell->GetCursor()->GetNode().GetTextNode();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 2022-05-30
+ // - Actual : choose a date
+ // i.e. the document text was not updated.
+ CPPUNIT_ASSERT_EQUAL(OUString("2022-05-30"), pTextNode->GetExpandText(pWrtShell->GetLayout()));
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(SwTiledRenderingTest);
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/core/crsr/viscrs.cxx b/sw/source/core/crsr/viscrs.cxx
index 9863e1a75324..ba3d49893233 100644
--- a/sw/source/core/crsr/viscrs.cxx
+++ b/sw/source/core/crsr/viscrs.cxx
@@ -708,6 +708,11 @@ void SwSelPaintRects::HighlightContentControl()
}
}
+ if (pContentControl && pContentControl->GetDate())
+ {
+ aJson.put("date", "true");
+ }
+
std::unique_ptr<char, o3tl::free_delete> pJson(aJson.extractData());
GetShell()->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_CONTENT_CONTROL, pJson.get());
}
diff --git a/sw/source/uibase/uno/unotxdoc.cxx b/sw/source/uibase/uno/unotxdoc.cxx
index 57998981f02e..b3f6e2e7487f 100644
--- a/sw/source/uibase/uno/unotxdoc.cxx
+++ b/sw/source/uibase/uno/unotxdoc.cxx
@@ -3359,6 +3359,11 @@ SwXTextDocument::getSearchResultRectangles(const char* pPayload)
return std::vector<basegfx::B2DRange>();
}
+namespace
+{
+inline constexpr OUStringLiteral SELECTED_DATE_FORMAT = u"YYYY-MM-DD";
+}
+
void SwXTextDocument::executeContentControlEvent(const StringMap& rArguments)
{
auto it = rArguments.find("type");
@@ -3421,6 +3426,62 @@ void SwXTextDocument::executeContentControlEvent(const StringMap& rArguments)
pView->GetViewFrame()->GetDispatcher()->ExecuteList(SID_INSERT_GRAPHIC,
SfxCallMode::SYNCHRON, { &aItem });
}
+ else if (it->second == "date")
+ {
+ SwWrtShell* pWrtShell = m_pDocShell->GetWrtShell();
+ const SwPosition* pStart = pWrtShell->GetCursor()->Start();
+ SwTextNode* pTextNode = pStart->nNode.GetNode().GetTextNode();
+ if (!pTextNode)
+ {
+ return;
+ }
+
+ SwTextAttr* pAttr = pTextNode->GetTextAttrAt(pStart->nContent.GetIndex(),
+ RES_TXTATR_CONTENTCONTROL, SwTextNode::PARENT);
+ if (!pAttr)
+ {
+ return;
+ }
+
+ auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
+ const SwFormatContentControl& rFormatContentControl
+ = pTextContentControl->GetContentControl();
+ std::shared_ptr<SwContentControl> pContentControl
+ = rFormatContentControl.GetContentControl();
+ if (!pContentControl->GetDate())
+ {
+ return;
+ }
+
+ it = rArguments.find("selected");
+ if (it == rArguments.end())
+ {
+ return;
+ }
+
+ OUString aSelectedDate = it->second.replaceAll("T00:00:00Z", "");
+ SwDoc& rDoc = pTextNode->GetDoc();
+ SvNumberFormatter* pNumberFormatter = rDoc.GetNumberFormatter();
+ sal_uInt32 nFormat
+ = pNumberFormatter->GetEntryKey(SELECTED_DATE_FORMAT, LANGUAGE_ENGLISH_US);
+ if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
+ {
+ sal_Int32 nCheckPos = 0;
+ SvNumFormatType nType;
+ OUString sFormat = SELECTED_DATE_FORMAT;
+ pNumberFormatter->PutEntry(sFormat, nCheckPos, nType, nFormat, LANGUAGE_ENGLISH_US);
+ }
+
+ if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
+ {
+ return;
+ }
+
+ double dCurrentDate = 0;
+ pNumberFormatter->IsNumberFormat(aSelectedDate, nFormat, dCurrentDate);
+ pContentControl->SetSelectedDate(dCurrentDate);
+ pWrtShell->GotoContentControl(rFormatContentControl);
+ }
}
int SwXTextDocument::getPart()