cui/uiconfig/ui/lineendstabpage.ui | 28 +--- include/xmloff/xmltoken.hxx | 2 schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng | 22 +++ solenv/sanitizers/ui/cui.suppr | 1 xmloff/qa/unit/data/content-control-checkbox.fodt | 8 + xmloff/qa/unit/text.cxx | 84 ++++++++++++ xmloff/source/core/xmltoken.cxx | 2 xmloff/source/text/txtparae.cxx | 32 ++++ xmloff/source/text/xmlcontentcontrolcontext.cxx | 43 ++++++ xmloff/source/text/xmlcontentcontrolcontext.hxx | 5 xmloff/source/token/tokens.txt | 2 11 files changed, 210 insertions(+), 19 deletions(-)
New commits: commit c2fab664a887b16cb78570851ceffcacd26815f7 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Wed Apr 27 08:53:13 2022 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Wed Apr 27 10:16:19 2022 +0200 sw content controls, checkbox: add ODT filter Map the 4 new UNO properties to XML attributes: - Checkbox <-> loext:checkbox="..." - Checked <-> loext:checked="..." - CheckedState <-> loext:checked-state="..." - UncheckedState <-> loext:unchecked-state="..." Change-Id: Ia4623004ee39c77f5f242c2d720bc188e4dd9433 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133467 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx index cdfb259f59ce..4db16a783e2d 100644 --- a/include/xmloff/xmltoken.hxx +++ b/include/xmloff/xmltoken.hxx @@ -3489,6 +3489,8 @@ namespace xmloff::token { XML_CONTENT_CONTROL, XML_SHOWING_PLACE_HOLDER, + XML_CHECKED_STATE, + XML_UNCHECKED_STATE, XML_TOKEN_END }; diff --git a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng index 68ac5c155d6a..511f31629eb4 100644 --- a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng +++ b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng @@ -2812,6 +2812,28 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1. <rng:ref name="boolean"/> </rng:attribute> </rng:optional> + <rng:optional> + <!-- default value: false --> + <rng:attribute name="loext:checkbox"> + <rng:ref name="boolean"/> + </rng:attribute> + </rng:optional> + <rng:optional> + <!-- default value: false --> + <rng:attribute name="loext:checked"> + <rng:ref name="boolean"/> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="loext:checked-state"> + <rng:ref name="string"/> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="loext:unchecked-state"> + <rng:ref name="string"/> + </rng:attribute> + </rng:optional> <rng:zeroOrMore> <rng:ref name="paragraph-content-or-hyperlink"/> </rng:zeroOrMore> diff --git a/xmloff/qa/unit/data/content-control-checkbox.fodt b/xmloff/qa/unit/data/content-control-checkbox.fodt new file mode 100644 index 000000000000..59c333ab9d57 --- /dev/null +++ b/xmloff/qa/unit/data/content-control-checkbox.fodt @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<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:checkbox="true" loext:checked="true" loext:checked-state="☒" loext:unchecked-state="☐">☒</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 5efe9cd91a2d..cd9afdf08654 100644 --- a/xmloff/qa/unit/text.cxx +++ b/xmloff/qa/unit/text.cxx @@ -453,6 +453,90 @@ CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testContentControlImport) CPPUNIT_ASSERT_EQUAL(OUString("test"), xContent->getString()); } +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testCheckboxContentControlExport) +{ + // Given a document with a checkbox content control around a text portion: + getComponent() = loadFromDesktop("private:factory/swriter"); + uno::Reference<lang::XMultiServiceFactory> xMSF(getComponent(), uno::UNO_QUERY); + uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY); + uno::Reference<text::XText> xText = xTextDocument->getText(); + uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor(); + xText->insertString(xCursor, OUString(u"☐"), /*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("Checkbox", uno::makeAny(true)); + xContentControlProps->setPropertyValue("Checked", uno::makeAny(true)); + xContentControlProps->setPropertyValue("CheckedState", uno::makeAny(OUString(u"☒"))); + xContentControlProps->setPropertyValue("UncheckedState", uno::makeAny(OUString(u"☐"))); + xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); + + // When exporting to ODT: + uno::Reference<frame::XStorable> xStorable(getComponent(), uno::UNO_QUERY); + uno::Sequence<beans::PropertyValue> aStoreProps = comphelper::InitPropertySequence({ + { "FilterName", uno::makeAny(OUString("writer8")) }, + }); + utl::TempFile aTempFile; + aTempFile.EnableKillingFile(); + xStorable->storeToURL(aTempFile.GetURL(), aStoreProps); + validate(aTempFile.GetFileName(), test::ODF); + + // Then make sure the expected markup is used: + std::unique_ptr<SvStream> pStream = parseExportStream(aTempFile, "content.xml"); + xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get()); + assertXPath(pXmlDoc, "//loext:content-control", "checkbox", "true"); + assertXPath(pXmlDoc, "//loext:content-control", "checked", "true"); + assertXPath(pXmlDoc, "//loext:content-control", "checked-state", u"☒"); + assertXPath(pXmlDoc, "//loext:content-control", "unchecked-state", u"☐"); +} + +CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testCheckboxContentControlImport) +{ + // Given an ODF document with a checkbox content control: + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "content-control-checkbox.fodt"; + + // When loading that document: + getComponent() = loadFromDesktop(aURL); + + // Then make sure that the content control is not lost on import: + uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY); + uno::Reference<container::XEnumerationAccess> xParagraphsAccess(xTextDocument->getText(), + uno::UNO_QUERY); + uno::Reference<container::XEnumeration> xParagraphs = xParagraphsAccess->createEnumeration(); + uno::Reference<container::XEnumerationAccess> xParagraph(xParagraphs->nextElement(), + uno::UNO_QUERY); + uno::Reference<container::XEnumeration> xPortions = xParagraph->createEnumeration(); + uno::Reference<beans::XPropertySet> xTextPortion(xPortions->nextElement(), uno::UNO_QUERY); + OUString aPortionType; + xTextPortion->getPropertyValue("TextPortionType") >>= aPortionType; + CPPUNIT_ASSERT_EQUAL(OUString("ContentControl"), aPortionType); + uno::Reference<text::XTextContent> xContentControl; + xTextPortion->getPropertyValue("ContentControl") >>= xContentControl; + uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY); + bool bCheckbox{}; + xContentControlProps->getPropertyValue("Checkbox") >>= bCheckbox; + // Without the accompanying fix in place, this failed, as the checkbox-related attributes were + // ignored on import. + CPPUNIT_ASSERT(bCheckbox); + bool bChecked{}; + xContentControlProps->getPropertyValue("Checked") >>= bChecked; + CPPUNIT_ASSERT(bChecked); + OUString aCheckedState; + xContentControlProps->getPropertyValue("CheckedState") >>= aCheckedState; + CPPUNIT_ASSERT_EQUAL(OUString(u"☒"), aCheckedState); + OUString aUncheckedState; + xContentControlProps->getPropertyValue("UncheckedState") >>= aUncheckedState; + CPPUNIT_ASSERT_EQUAL(OUString(u"☐"), aUncheckedState); + uno::Reference<text::XTextRange> xContentControlRange(xContentControl, uno::UNO_QUERY); + uno::Reference<text::XText> xText = xContentControlRange->getText(); + uno::Reference<container::XEnumerationAccess> xContentEnumAccess(xText, uno::UNO_QUERY); + uno::Reference<container::XEnumeration> xContentEnum = xContentEnumAccess->createEnumeration(); + uno::Reference<text::XTextRange> xContent(xContentEnum->nextElement(), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString(u"☒"), xContent->getString()); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx index 2839bd0d1832..b84451538ebd 100644 --- a/xmloff/source/core/xmltoken.cxx +++ b/xmloff/source/core/xmltoken.cxx @@ -3492,6 +3492,8 @@ namespace xmloff::token { TOKEN("content-control", XML_CONTENT_CONTROL ), TOKEN("showing-place-holder", XML_SHOWING_PLACE_HOLDER ), + TOKEN("checked-state", XML_CHECKED_STATE), + TOKEN("unchecked-state", XML_UNCHECKED_STATE), #if OSL_DEBUG_LEVEL > 0 diff --git a/xmloff/source/text/txtparae.cxx b/xmloff/source/text/txtparae.cxx index 5b8c07b70919..9b82dad50ee9 100644 --- a/xmloff/source/text/txtparae.cxx +++ b/xmloff/source/text/txtparae.cxx @@ -3900,6 +3900,38 @@ void XMLTextParagraphExport::ExportContentControl( GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_SHOWING_PLACE_HOLDER, aBuffer.makeStringAndClear()); } + + bool bCheckbox = false; + xPropertySet->getPropertyValue("Checkbox") >>= bCheckbox; + if (bCheckbox) + { + OUStringBuffer aBuffer; + sax::Converter::convertBool(aBuffer, bCheckbox); + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_CHECKBOX, aBuffer.makeStringAndClear()); + } + + bool bChecked = false; + xPropertySet->getPropertyValue("Checked") >>= bChecked; + if (bChecked) + { + OUStringBuffer aBuffer; + sax::Converter::convertBool(aBuffer, bChecked); + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_CHECKED, aBuffer.makeStringAndClear()); + } + + OUString aCheckedState; + xPropertySet->getPropertyValue("CheckedState") >>= aCheckedState; + if (!aCheckedState.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_CHECKED_STATE, aCheckedState); + } + + OUString aUncheckedState; + xPropertySet->getPropertyValue("UncheckedState") >>= aUncheckedState; + if (!aUncheckedState.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_UNCHECKED_STATE, aUncheckedState); + } } 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 fb7869b6e8a8..61fa609e0185 100644 --- a/xmloff/source/text/xmlcontentcontrolcontext.cxx +++ b/xmloff/source/text/xmlcontentcontrolcontext.cxx @@ -58,6 +58,32 @@ void XMLContentControlContext::startFastElement( } break; } + case XML_ELEMENT(LO_EXT, XML_CHECKBOX): + { + if (sax::Converter::convertBool(bTmp, rIter.toView())) + { + m_bCheckbox = bTmp; + } + break; + } + case XML_ELEMENT(LO_EXT, XML_CHECKED): + { + if (sax::Converter::convertBool(bTmp, rIter.toView())) + { + m_bChecked = bTmp; + } + break; + } + case XML_ELEMENT(LO_EXT, XML_CHECKED_STATE): + { + m_aCheckedState = rIter.toString(); + break; + } + case XML_ELEMENT(LO_EXT, XML_UNCHECKED_STATE): + { + m_aUncheckedState = rIter.toString(); + break; + } default: XMLOFF_WARN_UNKNOWN("xmloff", rIter); } @@ -99,6 +125,23 @@ void XMLContentControlContext::endFastElement(sal_Int32) { xPropertySet->setPropertyValue("ShowingPlaceHolder", uno::makeAny(m_bShowingPlaceHolder)); } + + if (m_bCheckbox) + { + xPropertySet->setPropertyValue("Checkbox", uno::makeAny(m_bCheckbox)); + } + if (m_bChecked) + { + xPropertySet->setPropertyValue("Checked", uno::makeAny(m_bChecked)); + } + if (!m_aCheckedState.isEmpty()) + { + xPropertySet->setPropertyValue("CheckedState", uno::makeAny(m_aCheckedState)); + } + if (!m_aUncheckedState.isEmpty()) + { + xPropertySet->setPropertyValue("UncheckedState", uno::makeAny(m_aUncheckedState)); + } } css::uno::Reference<css::xml::sax::XFastContextHandler> diff --git a/xmloff/source/text/xmlcontentcontrolcontext.hxx b/xmloff/source/text/xmlcontentcontrolcontext.hxx index 2658fa76972b..3d3e44d76445 100644 --- a/xmloff/source/text/xmlcontentcontrolcontext.hxx +++ b/xmloff/source/text/xmlcontentcontrolcontext.hxx @@ -35,6 +35,11 @@ class XMLContentControlContext : public SvXMLImportContext bool m_bShowingPlaceHolder = false; + bool m_bCheckbox = false; + bool m_bChecked = false; + OUString m_aCheckedState; + OUString m_aUncheckedState; + public: XMLContentControlContext(SvXMLImport& rImport, sal_Int32 nElement, XMLHints_Impl& rHints, bool& rIgnoreLeadingSpace); diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt index 1a8d60b4ec1b..accdd853e9e1 100644 --- a/xmloff/source/token/tokens.txt +++ b/xmloff/source/token/tokens.txt @@ -3235,4 +3235,6 @@ color-lum-mod color-lum-off content-control showing-place-holder +checked-state +unchecked-state TOKEN_END_DUMMY commit 7fbfefaedec93d7b49d1f53e23aed3cbbb55b315 Author: Seth Chaiklin <sdc.bla...@youmail.dk> AuthorDate: Fri Apr 15 03:11:45 2022 +0100 Commit: Seth Chaiklin <sdc.bla...@youmail.dk> CommitDate: Wed Apr 27 10:16:08 2022 +0200 tdf#126658 UI improvements to Arrow Styles tab in Line dialog * label "Organize Arrow Styles -> "Manage Arrow Styles" * label "Title" -> "Style _name" * button label "_Modify" -> "_Rename" + Add a tooltip for "Rename" - Remove label "Add..." (which was inadequate) + Add tooltip and extended tooltip for "Add" button Change-Id: I0226b32158c3bb9ae2600f8bfce3739f2ddbe5c4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133036 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caol...@redhat.com> diff --git a/cui/uiconfig/ui/lineendstabpage.ui b/cui/uiconfig/ui/lineendstabpage.ui index 2f63fcc1bec6..292159657ac0 100644 --- a/cui/uiconfig/ui/lineendstabpage.ui +++ b/cui/uiconfig/ui/lineendstabpage.ui @@ -63,7 +63,7 @@ <object class="GtkLabel" id="FT_TITLE"> <property name="visible">True</property> <property name="can-focus">False</property> - <property name="label" translatable="yes" context="lineendstabpage|FT_TITLE">_Title:</property> + <property name="label" translatable="yes" context="lineendstabpage|FT_TITLE">Style _name:</property> <property name="use-underline">True</property> <property name="mnemonic-widget">EDT_NAME</property> <property name="xalign">0</property> @@ -124,21 +124,6 @@ <property name="top-attach">1</property> </packing> </child> - <child> - <object class="GtkLabel" id="FI_TIP"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="valign">end</property> - <property name="vexpand">True</property> - <property name="label" translatable="yes" context="lineendstabpage|FI_TIP">Add a selected object to create new arrow styles.</property> - <property name="xalign">0</property> - </object> - <packing> - <property name="left-attach">0</property> - <property name="top-attach">2</property> - <property name="width">2</property> - </packing> - </child> </object> <packing> <property name="expand">False</property> @@ -160,7 +145,13 @@ <property name="visible">True</property> <property name="can-focus">True</property> <property name="receives-default">True</property> + <property name="tooltip-text" translatable="yes" context="lineendstabpage|BTN_ADD|tooltip_text">Adds selected shape as Arrow Style.</property> <property name="use-underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="BTN_ADD-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="lineendstabpage|extended_tip|BTN_ADD">To add a new Arrow Style, first select the shape in the document to be added, then open this dialog and press Add. If the selected shape is not permitted as an Arrow Style, then the Add button is not active.</property> + </object> + </child> </object> <packing> <property name="expand">False</property> @@ -170,10 +161,11 @@ </child> <child> <object class="GtkButton" id="BTN_MODIFY"> - <property name="label" translatable="yes" context="lineendstabpage|BTN_MODIFY">_Modify</property> + <property name="label" translatable="yes" context="lineendstabpage|BTN_MODIFY">_Rename</property> <property name="visible">True</property> <property name="can-focus">True</property> <property name="receives-default">True</property> + <property name="tooltip-text" translatable="yes" context="lineendstabpage|BTN_MODIFY|tooltip_text">Applies changes to the Style name.</property> <property name="use-underline">True</property> </object> <packing> @@ -307,7 +299,7 @@ <object class="GtkLabel" id="label1"> <property name="visible">True</property> <property name="can-focus">False</property> - <property name="label" translatable="yes" context="lineendstabpage|label1">Organize Arrow Styles</property> + <property name="label" translatable="yes" context="lineendstabpage|label1">Manage Arrow Styles</property> <property name="xalign">0</property> <attributes> <attribute name="weight" value="bold"/> diff --git a/solenv/sanitizers/ui/cui.suppr b/solenv/sanitizers/ui/cui.suppr index 7086f62b9ab5..b7e0c00c469d 100644 --- a/solenv/sanitizers/ui/cui.suppr +++ b/solenv/sanitizers/ui/cui.suppr @@ -80,7 +80,6 @@ cui/uiconfig/ui/insertoleobject.ui://GtkEntry[@id='urled'] no-labelled-by cui/uiconfig/ui/javastartparametersdialog.ui://GtkLabel[@id='label6'] orphan-label cui/uiconfig/ui/lineendstabpage.ui://GtkLabel[@id='FT_LINE_END_STYLE'] orphan-label cui/uiconfig/ui/lineendstabpage.ui://GtkComboBox[@id='LB_LINEENDS'] no-labelled-by -cui/uiconfig/ui/lineendstabpage.ui://GtkLabel[@id='FI_TIP'] orphan-label cui/uiconfig/ui/linestyletabpage.ui://GtkSpinButton[@id='NUM_FLD_2'] no-labelled-by cui/uiconfig/ui/linestyletabpage.ui://GtkSpinButton[@id='MTR_FLD_LENGTH_2'] no-labelled-by cui/uiconfig/ui/macroselectordialog.ui://GtkLabel[@id='helpmacro'] orphan-label