summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2022-04-27 08:53:13 +0200
committerMiklos Vajna <vmiklos@collabora.com>2022-04-27 10:16:19 +0200
commitc2fab664a887b16cb78570851ceffcacd26815f7 (patch)
tree8625ed3500df507e48b40f289eb077055a4d987e
parent7fbfefaedec93d7b49d1f53e23aed3cbbb55b315 (diff)
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 <vmiklos@collabora.com> Tested-by: Jenkins
-rw-r--r--include/xmloff/xmltoken.hxx2
-rw-r--r--schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng22
-rw-r--r--xmloff/qa/unit/data/content-control-checkbox.fodt8
-rw-r--r--xmloff/qa/unit/text.cxx84
-rw-r--r--xmloff/source/core/xmltoken.cxx2
-rw-r--r--xmloff/source/text/txtparae.cxx32
-rw-r--r--xmloff/source/text/xmlcontentcontrolcontext.cxx43
-rw-r--r--xmloff/source/text/xmlcontentcontrolcontext.hxx5
-rw-r--r--xmloff/source/token/tokens.txt2
9 files changed, 200 insertions, 0 deletions
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