diff options
-rw-r--r-- | include/xmloff/txtimp.hxx | 4 | ||||
-rw-r--r-- | include/xmloff/xmltoken.hxx | 1 | ||||
-rw-r--r-- | schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng | 6 | ||||
-rw-r--r-- | sw/qa/extras/globalfilter/data/fieldmark_QUOTE_nest.fodt | 133 | ||||
-rw-r--r-- | sw/qa/extras/globalfilter/globalfilter.cxx | 13 | ||||
-rw-r--r-- | sw/source/core/inc/unobookmark.hxx | 4 | ||||
-rw-r--r-- | sw/source/core/unocore/unobkm.cxx | 19 | ||||
-rw-r--r-- | xmloff/source/core/xmltoken.cxx | 1 | ||||
-rw-r--r-- | xmloff/source/text/XMLTextMarkImportContext.cxx | 46 | ||||
-rw-r--r-- | xmloff/source/text/XMLTextMarkImportContext.hxx | 3 | ||||
-rw-r--r-- | xmloff/source/text/txtimp.cxx | 36 | ||||
-rw-r--r-- | xmloff/source/text/txtparae.cxx | 14 | ||||
-rw-r--r-- | xmloff/source/text/txtparai.cxx | 1 | ||||
-rw-r--r-- | xmloff/source/token/tokens.txt | 1 |
14 files changed, 260 insertions, 22 deletions
diff --git a/include/xmloff/txtimp.hxx b/include/xmloff/txtimp.hxx index 9259747bd94d..0124bc8eb2c2 100644 --- a/include/xmloff/txtimp.hxx +++ b/include/xmloff/txtimp.hxx @@ -289,7 +289,9 @@ public: css::uno::Reference<css::text::XFormField> popFieldCtx(); void addFieldParam( const OUString& name, const OUString& value ); void setCurrentFieldParamsTo(css::uno::Reference< css::text::XFormField> const &xFormField); - OUString getCurrentFieldType(); + ::std::pair<OUString, OUString> getCurrentFieldType() const; + css::uno::Reference<css::text::XTextRange> getCurrentFieldStart() const; + bool hasCurrentFieldSeparator() const; bool hasCurrentFieldCtx() const; diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx index 58b6329ec71a..77f9c605b707 100644 --- a/include/xmloff/xmltoken.hxx +++ b/include/xmloff/xmltoken.hxx @@ -3308,6 +3308,7 @@ namespace xmloff::token { // enhanced fields XML_FIELDMARK, XML_FIELDMARK_START, + XML_FIELDMARK_SEPARATOR, XML_FIELDMARK_END, XML_IMAGE_SCALE, diff --git a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng index fcf6bfaab353..c92b5c6330bf 100644 --- a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng +++ b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng @@ -2808,6 +2808,12 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1. </rng:define> <rng:define name="paragraph-content" combine="choice" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0"> + <rng:element name="field:fieldmark-separator"> + <rng:empty/> + </rng:element> + </rng:define> + <rng:define name="paragraph-content" combine="choice" + xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0"> <rng:element name="field:fieldmark-end"> <rng:empty/> </rng:element> diff --git a/sw/qa/extras/globalfilter/data/fieldmark_QUOTE_nest.fodt b/sw/qa/extras/globalfilter/data/fieldmark_QUOTE_nest.fodt new file mode 100644 index 000000000000..86b17a15bbce --- /dev/null +++ b/sw/qa/extras/globalfilter/data/fieldmark_QUOTE_nest.fodt @@ -0,0 +1,133 @@ +<?xml version='1.0' encoding='UTF-8'?> +<office:document xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta: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:meta><meta:initial-creator>Michael Stahl</meta:initial-creator><dc:creator>Michael Stahl</dc:creator><meta:editing-cycles>2</meta:editing-cycles><meta:creation-date>2019-01-24T14:48:00</meta:creation-date><dc:date>2019-01-24T14:48:00</dc:date><meta:editing-duration>P0D</meta:editing-duration><meta:generator>LibreOfficeDev/7.5.0.0.alpha0$Linux_X86_64 LibreOffice_project/be346d6cdc87b18dc861279187915de42722e970</meta:generator><meta:document-statistic meta:table-count="0" meta:image-count="0" meta:object-count="0" meta:page-count="1" meta:paragraph-count="13" meta:word-count="6" meta:character-count="24" meta:non-whitespace-character-count="18"/><meta:user-defined meta:name="AppVersion">15.0000</meta:user-defined><meta:template xlink:type="simple" xlink:actuate="onRequest" xlink:title="Normal.dotm" xlink:href=""/></office:meta> + <office:font-face-decls> + <style:font-face style:name="Calibri" svg:font-family="Calibri" style:font-family-generic="roman" style:font-pitch="variable"/> + <style:font-face style:name="Calibri1" svg:font-family="Calibri" style:font-family-generic="system" style:font-pitch="variable"/> + <style:font-face style:name="Times New Roman" svg:font-family="'Times New Roman'" style:font-family-generic="system" style:font-pitch="variable"/> + </office:font-face-decls> + <office:styles> + <style:default-style style:family="graphic"> + <style:graphic-properties svg:stroke-color="#3465a4" draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.3cm" draw:shadow-offset-y="0.3cm" draw:start-line-spacing-horizontal="0.283cm" draw:start-line-spacing-vertical="0.283cm" draw:end-line-spacing-horizontal="0.283cm" draw:end-line-spacing-vertical="0.283cm" style:flow-with-text="false"/> + <style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" style:writing-mode="lr-tb" style:font-independent-line-spacing="false"> + <style:tab-stops/> + </style:paragraph-properties> + <style:text-properties style:use-window-font-color="true" loext:opacity="0%" loext:color-lum-mod="100%" loext:color-lum-off="0%" style:font-name="Calibri" fo:font-size="10pt" fo:language="de" fo:country="DE" style:letter-kerning="false" style:font-name-asian="Calibri1" style:font-size-asian="10pt" style:language-asian="de" style:country-asian="DE" style:font-name-complex="Times New Roman" style:font-size-complex="10pt" style:language-complex="ar" style:country-complex="SA"/> + </style:default-style> + <style:default-style style:family="paragraph"> + <style:paragraph-properties fo:hyphenation-ladder-count="no-limit" style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="1.249cm" style:writing-mode="page"/> + <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Calibri" fo:font-size="10pt" fo:language="de" fo:country="DE" style:letter-kerning="false" style:font-name-asian="Calibri1" style:font-size-asian="10pt" style:language-asian="de" style:country-asian="DE" style:font-name-complex="Times New Roman" style:font-size-complex="10pt" style:language-complex="ar" style:country-complex="SA" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" loext:hyphenation-word-char-count="5" loext:hyphenation-zone="no-limit"/> + </style:default-style> + <style:default-style style:family="table"> + <style:table-properties table:border-model="collapsing"/> + </style:default-style> + <style:default-style style:family="table-row"> + <style:table-row-properties fo:keep-together="auto"/> + </style:default-style> + <style:style style:name="Standard" style:family="paragraph" style:class="text"> + <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0.282cm" style:contextual-spacing="false" fo:line-height="108%" fo:text-align="start" style:justify-single-word="false" fo:orphans="2" fo:widows="2" style:writing-mode="lr-tb"/> + <style:text-properties fo:font-size="11pt" style:font-size-asian="11pt" style:language-asian="en" style:country-asian="US" style:font-size-complex="11pt"/> + </style:style> + <text:outline-style style:name="Outline"> + <text:outline-level-style text:level="1" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="2" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="3" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="4" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="5" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="6" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="7" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="8" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="9" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="10" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + </text:outline-style> + <text:notes-configuration text:note-class="footnote" style:num-format="1" text:start-value="0" text:footnotes-position="page" text:start-numbering-at="document"/> + <text:notes-configuration text:note-class="endnote" style:num-format="i" text:start-value="0"/> + <text:linenumbering-configuration text:number-lines="false" text:offset="0.499cm" style:num-format="1" text:number-position="left" text:increment="5"/> + <style:default-page-layout> + <style:page-layout-properties style:layout-grid-standard-mode="true"/> + </style:default-page-layout> + </office:styles> + <office:automatic-styles> + <style:style style:name="T1" style:family="text"> + <style:text-properties fo:language="en" fo:country="IE"/> + </style:style> + <style:page-layout style:name="pm1"> + <style:page-layout-properties fo:page-width="21.001cm" fo:page-height="29.7cm" style:num-format="1" style:print-orientation="portrait" fo:margin-top="2.499cm" fo:margin-bottom="2cm" fo:margin-left="2.499cm" fo:margin-right="2.499cm" style:writing-mode="lr-tb" style:layout-grid-color="#c0c0c0" style:layout-grid-lines="39" style:layout-grid-base-height="0.635cm" style:layout-grid-ruby-height="0cm" style:layout-grid-mode="none" style:layout-grid-ruby-below="false" style:layout-grid-print="false" style:layout-grid-display="false" style:layout-grid-base-width="0.388cm" style:layout-grid-snap-to="true" style:footnote-max-height="0cm" loext:margin-gutter="0cm"> + <style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/> + </style:page-layout-properties> + <style:header-style/> + <style:footer-style/> + </style:page-layout> + <style:style style:name="dp1" style:family="drawing-page"> + <style:drawing-page-properties draw:background-size="full"/> + </style:style> + </office:automatic-styles> + <office:master-styles> + <style:master-page style:name="Standard" style:page-layout-name="pm1" draw:style-name="dp1"/> + </office:master-styles> + <office:body> + <office:text> + <text:sequence-decls> + <text:sequence-decl text:display-outline-level="0" text:name="Illustration"/> + <text:sequence-decl text:display-outline-level="0" text:name="Table"/> + <text:sequence-decl text:display-outline-level="0" text:name="Text"/> + <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/> + <text:sequence-decl text:display-outline-level="0" text:name="Figure"/> + </text:sequence-decls> + <text:p text:style-name="Standard"><field:fieldmark-start text:name="Bookmark1" field:type="vnd.oasis.opendocument.field.UNHANDLED"><field:param field:name="vnd.oasis.opendocument.field.code" field:value=""/></field:fieldmark-start><text:s/>QUOTE <text:s/>"foo </text:p> + <text:p text:style-name="Standard"><text:s/><field:fieldmark-start text:name="Bookmark" field:type="vnd.oasis.opendocument.field.UNHANDLED"><field:param field:name="vnd.oasis.opendocument.field.code" field:value=""/></field:fieldmark-start><text:s/>QUOTE <text:s/>"foo </text:p> + <text:p text:style-name="Standard"><text:s/>bar </text:p> + <text:p text:style-name="Standard">baz" <field:fieldmark-separator/>foo </text:p> + <text:p text:style-name="Standard"><text:s/>bar </text:p> + <text:p text:style-name="Standard">baz<field:fieldmark-end/></text:p> + <text:p text:style-name="Standard">bar </text:p> + <text:p text:style-name="Standard"><text:span text:style-name="T1">baz" </text:span><field:fieldmark-separator/><text:span text:style-name="T1">foo </text:span></text:p> + <text:p text:style-name="Standard"><text:span text:style-name="T1"><text:s/>foo </text:span></text:p> + <text:p text:style-name="Standard"><text:span text:style-name="T1"><text:s/>bar </text:span></text:p> + <text:p text:style-name="Standard"><text:span text:style-name="T1">baz</text:span></text:p> + <text:p text:style-name="Standard"><text:span text:style-name="T1">bar </text:span></text:p> + <text:p text:style-name="Standard"><text:span text:style-name="T1">baz</text:span><field:fieldmark-end/></text:p> + <text:p text:style-name="Standard"/> + </office:text> + </office:body> +</office:document>
\ No newline at end of file diff --git a/sw/qa/extras/globalfilter/globalfilter.cxx b/sw/qa/extras/globalfilter/globalfilter.cxx index ebe5abb81804..fefc1fbda8ee 100644 --- a/sw/qa/extras/globalfilter/globalfilter.cxx +++ b/sw/qa/extras/globalfilter/globalfilter.cxx @@ -1041,6 +1041,7 @@ void Test::testNestedFieldmark() pBatch->commit(); std::pair<OUString, OUString> const aFilterNames[] = { + {"writer8", "fieldmark_QUOTE_nest.fodt"}, {"Office Open XML Text", "fieldmark_QUOTE_nest.docx"}, {"Rich Text Format", "fieldmark_QUOTE_nest.rtf"}, }; @@ -1465,12 +1466,20 @@ void Test::testTextFormField() // In the first paragraph we have an empty text form field with the placeholder spaces const uno::Reference< text::XTextRange > xPara = getParagraph(1); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("TextFieldStart"), getProperty<OUString>(getRun(xPara, 1), "TextPortionType")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("TextFieldSeparator"), getProperty<OUString>(getRun(xPara, 2), "TextPortionType")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("Text"), getProperty<OUString>(getRun(xPara, 3), "TextPortionType")); sal_Unicode vEnSpaces[5] = {8194, 8194, 8194, 8194, 8194}; - CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString(vEnSpaces, 5), xPara->getString()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString(vEnSpaces, 5), getRun(xPara, 3)->getString()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("TextFieldEnd"), getProperty<OUString>(getRun(xPara, 4), "TextPortionType")); // In the second paragraph we have a set text const uno::Reference< text::XTextRange > xPara2 = getParagraph(2); - CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("xxxxx"), xPara2->getString()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("TextFieldStart"), getProperty<OUString>(getRun(xPara2, 1), "TextPortionType")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("TextFieldSeparator"), getProperty<OUString>(getRun(xPara2, 2), "TextPortionType")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("Text"), getProperty<OUString>(getRun(xPara2, 3), "TextPortionType")); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("xxxxx"), getRun(xPara2, 3)->getString()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("TextFieldEnd"), getProperty<OUString>(getRun(xPara2, 4), "TextPortionType")); } } diff --git a/sw/source/core/inc/unobookmark.hxx b/sw/source/core/inc/unobookmark.hxx index 57b2d1d9a5b2..09ccb69e6da4 100644 --- a/sw/source/core/inc/unobookmark.hxx +++ b/sw/source/core/inc/unobookmark.hxx @@ -61,7 +61,8 @@ protected: /// @throws css::uno::RuntimeException void attachToRangeEx( const css::uno::Reference< css::text::XTextRange > & xTextRange, - IDocumentMarkAccess::MarkType eType); + IDocumentMarkAccess::MarkType eType, + bool isFieldmarkSeparatorAtStart = false); /// @throws css::lang::IllegalArgumentException /// @throws css::uno::RuntimeException virtual void attachToRange( @@ -190,6 +191,7 @@ class SwXFieldmark final { ::sw::mark::ICheckboxFieldmark* getCheckboxFieldmark(); bool const m_bReplacementObject; + bool m_isFieldmarkSeparatorAtStart = false; css::uno::Reference<css::text::XTextRange> GetCommand(::sw::mark::IFieldmark const& rMark); diff --git a/sw/source/core/unocore/unobkm.cxx b/sw/source/core/unocore/unobkm.cxx index a98956749713..456325d5f575 100644 --- a/sw/source/core/unocore/unobkm.cxx +++ b/sw/source/core/unocore/unobkm.cxx @@ -206,7 +206,8 @@ sal_Int64 SAL_CALL SwXBookmark::getSomething( const uno::Sequence< sal_Int8 >& r void SwXBookmark::attachToRangeEx( const uno::Reference< text::XTextRange > & xTextRange, - IDocumentMarkAccess::MarkType eType) + IDocumentMarkAccess::MarkType eType, + bool const isFieldmarkSeparatorAtStart) { if (m_pImpl->m_pRegisteredBookmark) { @@ -247,7 +248,10 @@ void SwXBookmark::attachToRangeEx( } m_pImpl->registerInMark(*this, m_pImpl->m_pDoc->getIDocumentMarkAccess()->makeMark( - aPam, m_pImpl->m_sMarkName, eType, ::sw::mark::InsertMode::New)); + aPam, m_pImpl->m_sMarkName, eType, ::sw::mark::InsertMode::New, + // note: aPam will be moved fwd by inserting start char, so sep + // will be directly following start + isFieldmarkSeparatorAtStart ? aPam.Start() : nullptr)); // #i81002# // Check, if bookmark has been created. // E.g., the creation of a cross-reference bookmark is suppress, @@ -622,7 +626,8 @@ void SwXFieldmark::attachToRange( const uno::Reference < text::XTextRange >& xTe { attachToRangeEx( xTextRange, - ( m_bReplacementObject ? IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK : IDocumentMarkAccess::MarkType::TEXT_FIELDMARK ) ); + (m_bReplacementObject ? IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK : IDocumentMarkAccess::MarkType::TEXT_FIELDMARK), + m_isFieldmarkSeparatorAtStart); } OUString SwXFieldmark::getFieldType() @@ -743,6 +748,14 @@ SwXFieldmark::setPropertyValue(const OUString& PropertyName, pCheckboxFm->SetChecked( bChecked ); } + else if (PropertyName == "PrivateSeparatorAtStart") + { + bool isFieldmarkSeparatorAtStart{}; + if (rValue >>= isFieldmarkSeparatorAtStart) + { + m_isFieldmarkSeparatorAtStart = isFieldmarkSeparatorAtStart; + } + } // this doesn't support any SwXBookmark property } diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx index a996c4e9fb54..1606dbc68ab3 100644 --- a/xmloff/source/core/xmltoken.cxx +++ b/xmloff/source/core/xmltoken.cxx @@ -3318,6 +3318,7 @@ namespace xmloff::token { // enhanced fields TOKEN( "fieldmark", XML_FIELDMARK ), TOKEN( "fieldmark-start", XML_FIELDMARK_START ), + TOKEN( "fieldmark-separator", XML_FIELDMARK_SEPARATOR ), TOKEN( "fieldmark-end", XML_FIELDMARK_END ), TOKEN( "image-scale", XML_IMAGE_SCALE ), diff --git a/xmloff/source/text/XMLTextMarkImportContext.cxx b/xmloff/source/text/XMLTextMarkImportContext.cxx index 8e823d6c1757..4e42899e709c 100644 --- a/xmloff/source/text/XMLTextMarkImportContext.cxx +++ b/xmloff/source/text/XMLTextMarkImportContext.cxx @@ -35,6 +35,7 @@ #include <com/sun/star/xml/sax/XAttributeList.hpp> #include <com/sun/star/text/ControlCharacter.hpp> #include <com/sun/star/text/XTextContent.hpp> +#include <com/sun/star/text/XTextRangeCompare.hpp> #include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/lang/XMultiServiceFactory.hpp> #include <com/sun/star/container/XNamed.hpp> @@ -105,7 +106,7 @@ namespace { enum lcl_MarkType { TypeReference, TypeReferenceStart, TypeReferenceEnd, TypeBookmark, TypeBookmarkStart, TypeBookmarkEnd, - TypeFieldmark, TypeFieldmarkStart, TypeFieldmarkEnd + TypeFieldmark, TypeFieldmarkStart, TypeFieldmarkSeparator, TypeFieldmarkEnd }; } @@ -120,6 +121,7 @@ SvXMLEnumMapEntry<lcl_MarkType> const lcl_aMarkTypeMap[] = { XML_BOOKMARK_END, TypeBookmarkEnd }, { XML_FIELDMARK, TypeFieldmark }, { XML_FIELDMARK_START, TypeFieldmarkStart }, + { XML_FIELDMARK_SEPARATOR, TypeFieldmarkSeparator }, { XML_FIELDMARK_END, TypeFieldmarkEnd }, { XML_TOKEN_INVALID, lcl_MarkType(0) }, }; @@ -173,12 +175,12 @@ void XMLTextMarkImportContext::startFastElement( sal_Int32 nElement, } static auto InsertFieldmark(SvXMLImport & rImport, - XMLTextImportHelper & rHelper, OUString const& rName) -> void + XMLTextImportHelper & rHelper, bool const isFieldmarkSeparatorMissing) -> void { assert(rHelper.hasCurrentFieldCtx()); // was set up in StartElement() // fdo#86795 check if it's actually a checkbox first - OUString const type(rHelper.getCurrentFieldType()); + auto const [ name, type ] = rHelper.getCurrentFieldType(); OUString const fieldmarkTypeName = lcl_getFieldmarkName(type); if (fieldmarkTypeName == ODF_FORMCHECKBOX || fieldmarkTypeName == ODF_FORMDROPDOWN) @@ -187,9 +189,20 @@ static auto InsertFieldmark(SvXMLImport & rImport, return; } + uno::Reference<text::XTextRange> const xStartRange(rHelper.getCurrentFieldStart()); + uno::Reference<text::XTextCursor> const xCursor( + rHelper.GetText()->createTextCursorByRange(xStartRange)); + uno::Reference<text::XTextRangeCompare> const xCompare(rHelper.GetText(), uno::UNO_QUERY); + if (xCompare->compareRegionStarts(xStartRange, rHelper.GetCursorAsRange()) < 0) + { + SAL_WARN("xmloff.text", "invalid field mark positions"); + assert(false); + } + xCursor->gotoRange(rHelper.GetCursorAsRange(), true); + Reference<XTextContent> const xContent = XMLTextMarkImportContext::CreateAndInsertMark( - rImport, "com.sun.star.text.Fieldmark", - rName, rHelper.GetCursorAsRange()); + rImport, "com.sun.star.text.Fieldmark", name, xCursor, + OUString(), isFieldmarkSeparatorMissing); if (!xContent.is()) return; @@ -256,7 +269,7 @@ void XMLTextMarkImportContext::endFastElement(sal_Int32 nElement) if (!SvXMLUnitConverter::convertEnum(nTmp, SvXMLImport::getNameFromToken(nElement), lcl_aMarkTypeMap)) return; - if (m_sBookmarkName.isEmpty() && TypeFieldmarkEnd != nTmp) + if (m_sBookmarkName.isEmpty() && TypeFieldmarkEnd != nTmp && TypeFieldmarkSeparator != nTmp) return; switch (nTmp) @@ -412,13 +425,21 @@ void XMLTextMarkImportContext::endFastElement(sal_Int32 nElement) // else: no start found -> ignore! break; } - case TypeFieldmarkStart: // no separator, so insert at start + case TypeFieldmarkStart: + { + break; + } + case TypeFieldmarkSeparator: { - InsertFieldmark(GetImport(), m_rHelper, m_sBookmarkName); + InsertFieldmark(GetImport(), m_rHelper, false); break; } case TypeFieldmarkEnd: { + if (!m_rHelper.hasCurrentFieldSeparator()) + { // backward compat for old files without separator + InsertFieldmark(GetImport(), m_rHelper, true); + } PopFieldmark(m_rHelper); break; } @@ -446,7 +467,8 @@ Reference<XTextContent> XMLTextMarkImportContext::CreateAndInsertMark( const OUString& sServiceName, const OUString& sMarkName, const Reference<XTextRange> & rRange, - const OUString& i_rXmlId) + const OUString& i_rXmlId, + bool const isFieldmarkSeparatorMissing) { // create mark const Reference<XMultiServiceFactory> xFactory(rImport.GetModel(), @@ -478,6 +500,12 @@ Reference<XTextContent> XMLTextMarkImportContext::CreateAndInsertMark( } } + if (isFieldmarkSeparatorMissing) + { + uno::Reference<beans::XPropertySet> const xProps(xIfc, uno::UNO_QUERY_THROW); + xProps->setPropertyValue("PrivateSeparatorAtStart", uno::Any(true)); + } + // cast to XTextContent and attach to document const Reference<XTextContent> xTextContent(xIfc, UNO_QUERY); if (xTextContent.is()) diff --git a/xmloff/source/text/XMLTextMarkImportContext.hxx b/xmloff/source/text/XMLTextMarkImportContext.hxx index 407cddbadf7f..da05f524083e 100644 --- a/xmloff/source/text/XMLTextMarkImportContext.hxx +++ b/xmloff/source/text/XMLTextMarkImportContext.hxx @@ -96,7 +96,8 @@ public: const OUString& sServiceName, const OUString& sMarkName, const css::uno::Reference<css::text::XTextRange> & rRange, - const OUString& i_rXmlId = OUString()); + const OUString& i_rXmlId = OUString(), + bool const isFieldmarkSeparatorMissing = false); bool FindName( const css::uno::Reference<css::xml::sax::XFastAttributeList> & xAttrList); diff --git a/xmloff/source/text/txtimp.cxx b/xmloff/source/text/txtimp.cxx index 079e8df8d82d..f26ce21e66ab 100644 --- a/xmloff/source/text/txtimp.cxx +++ b/xmloff/source/text/txtimp.cxx @@ -166,7 +166,7 @@ struct XMLTextImportHelper::Impl typedef ::std::pair< OUString, OUString> field_name_type_t; typedef ::std::pair< OUString, OUString > field_param_t; typedef ::std::vector< field_param_t > field_params_t; - typedef ::std::tuple<field_name_type_t, field_params_t, uno::Reference<text::XFormField>> field_stack_item_t; + typedef ::std::tuple<field_name_type_t, field_params_t, uno::Reference<text::XFormField>, uno::Reference<text::XTextRange>> field_stack_item_t; typedef ::std::stack< field_stack_item_t > field_stack_t; field_stack_t m_FieldStack; @@ -2105,7 +2105,7 @@ bool XMLTextImportHelper::FindAndRemoveBookmarkStartRange( void XMLTextImportHelper::pushFieldCtx( const OUString& name, const OUString& type ) { m_xImpl->m_FieldStack.push(Impl::field_stack_item_t( - Impl::field_name_type_t(name, type), Impl::field_params_t(), uno::Reference<text::XFormField>{})); + Impl::field_name_type_t(name, type), Impl::field_params_t(), uno::Reference<text::XFormField>{}, GetCursor()->getStart())); } uno::Reference<text::XFormField> @@ -2133,16 +2133,42 @@ void XMLTextImportHelper::addFieldParam( const OUString& name, const OUString& v } } -OUString XMLTextImportHelper::getCurrentFieldType() +::std::pair<OUString, OUString> XMLTextImportHelper::getCurrentFieldType() const { assert(!m_xImpl->m_FieldStack.empty()); if (!m_xImpl->m_FieldStack.empty()) { - return std::get<0>(m_xImpl->m_FieldStack.top()).second; + return std::get<0>(m_xImpl->m_FieldStack.top()); } else { - return OUString(); + return {}; + } +} + +uno::Reference<text::XTextRange> XMLTextImportHelper::getCurrentFieldStart() const +{ + assert(!m_xImpl->m_FieldStack.empty()); + if (!m_xImpl->m_FieldStack.empty()) + { + return std::get<3>(m_xImpl->m_FieldStack.top()); + } + else + { + return {}; + } +} + +bool XMLTextImportHelper::hasCurrentFieldSeparator() const +{ + assert(!m_xImpl->m_FieldStack.empty()); + if (!m_xImpl->m_FieldStack.empty()) + { + return std::get<2>(m_xImpl->m_FieldStack.top()).is(); + } + else + { + return {}; } } diff --git a/xmloff/source/text/txtparae.cxx b/xmloff/source/text/txtparae.cxx index 5d9bd3768d01..63232f8b2822 100644 --- a/xmloff/source/text/txtparae.cxx +++ b/xmloff/source/text/txtparae.cxx @@ -181,6 +181,7 @@ constexpr OUStringLiteral gsVisitedCharStyleName(u"VisitedCharStyleName"); constexpr OUStringLiteral gsWidth(u"Width"); constexpr OUStringLiteral gsWidthType( u"WidthType" ); constexpr OUStringLiteral gsTextFieldStart( u"TextFieldStart" ); +constexpr OUStringLiteral gsTextFieldSep(u"TextFieldSeparator"); constexpr OUStringLiteral gsTextFieldEnd( u"TextFieldEnd" ); constexpr OUStringLiteral gsTextFieldStartEnd( u"TextFieldStartEnd" ); @@ -2284,6 +2285,19 @@ void XMLTextParagraphExport::exportTextRangeEnumeration( } } } + else if (sType == gsTextFieldSep) + { + Reference<text::XFormField> const xFormField(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY); + if (!bAutoStyles) + { + if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + SvXMLElementExport aElem( GetExport(), !bAutoStyles, + XML_NAMESPACE_FIELD, XML_FIELDMARK_SEPARATOR, + false, false ); + } + } + } else if (sType == gsTextFieldEnd) { if (!bAutoStyles) diff --git a/xmloff/source/text/txtparai.cxx b/xmloff/source/text/txtparai.cxx index 3641d7e1af20..5a37d1e46894 100644 --- a/xmloff/source/text/txtparai.cxx +++ b/xmloff/source/text/txtparai.cxx @@ -1433,6 +1433,7 @@ css::uno::Reference< css::xml::sax::XFastContextHandler > XMLImpSpanContext_Impl case XML_ELEMENT(FIELD, XML_FIELDMARK): case XML_ELEMENT(FIELD, XML_FIELDMARK_START): + case XML_ELEMENT(FIELD, XML_FIELDMARK_SEPARATOR): case XML_ELEMENT(FIELD, XML_FIELDMARK_END): pContext = new XMLTextMarkImportContext(rImport, *rImport.GetTextImport(), rHints.GetCrossRefHeadingBookmark()); diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt index 849802878614..568122e0f582 100644 --- a/xmloff/source/token/tokens.txt +++ b/xmloff/source/token/tokens.txt @@ -3093,6 +3093,7 @@ use-zero ignore fieldmark fieldmark-start +fieldmark-separator fieldmark-end image-scale isotropic |