diff options
author | Mike Kaganski <mike.kaganski@collabora.com> | 2023-05-10 20:39:12 +0300 |
---|---|---|
committer | Mike Kaganski <mike.kaganski@collabora.com> | 2023-05-11 18:06:02 +0200 |
commit | 1a88efa8e02a6d765dab13c7110443bb9e6acecf (patch) | |
tree | fcefc280189d41ff6b6277017232085bfe334743 /sw | |
parent | abd630e81bc150d05e4129cc22752ecf461777c7 (diff) |
tdf#155238: Reimplement how ListAutoFormat is stored to ODF
This reimplements commits 6249858a8972aef077e0249bd93cfe8f01bce4d6
(sw: ODT import/export of DOCX's paragraph marker formatting,
2022-12-19) and 209dce614c43f63f63f5b42a746665c0ec1cbfe3 (sw: fix
ODT import of paragraph marker formatting, 2022-12-20).
Instead of using an empty trailing span for the ListAutoFormat data,
introduce a new loext:marker-style-name attribute for text:p element,
referencing a text autostyle.
The problems with the previous implementation were that (1) it was
impossible (or very difficult) to disambiguate several empty trailing
spans, in case it was needed; and (2) this was incompatible change,
with other ODF implementations treating the trailing span normally.
I couldn't manage to incorporate the attribute to paragraph autostyle,
because of problems referencing different autostyles one from another,
so put it directly to the paragraph attributes.
Change-Id: I33473147f1f774c24cbbc57bf0c4f3a1d83ce5bc
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151645
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Diffstat (limited to 'sw')
-rw-r--r-- | sw/qa/extras/odfexport/data/ParagraphMarkerMarkup.fodt | 22 | ||||
-rw-r--r-- | sw/qa/extras/odfexport/odfexport2.cxx | 10 | ||||
-rw-r--r-- | sw/qa/extras/odfimport/data/emptyParagraphLoosesFontHeight.fodt | 21 | ||||
-rw-r--r-- | sw/qa/extras/odfimport/odfimport.cxx | 21 | ||||
-rw-r--r-- | sw/qa/extras/ooxmlexport/ooxmlexport2.cxx | 3 | ||||
-rw-r--r-- | sw/source/core/unocore/unoobj.cxx | 71 | ||||
-rw-r--r-- | sw/source/core/unocore/unoparagraph.cxx | 15 | ||||
-rw-r--r-- | sw/source/core/unocore/unoportenum.cxx | 5 |
8 files changed, 101 insertions, 67 deletions
diff --git a/sw/qa/extras/odfexport/data/ParagraphMarkerMarkup.fodt b/sw/qa/extras/odfexport/data/ParagraphMarkerMarkup.fodt new file mode 100644 index 000000000000..c3a21261da26 --- /dev/null +++ b/sw/qa/extras/odfexport/data/ParagraphMarkerMarkup.fodt @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible: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:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:styles> + <style:style style:name="Standard" style:family="paragraph" style:class="text"> + <style:text-properties fo:font-size="11pt"/> + </style:style> + </office:styles> + <office:automatic-styles> + <style:style style:name="T1" style:family="text"> + <style:text-properties fo:font-size="8pt"/> + </style:style> + <style:style style:name="T2" style:family="text"> + <style:text-properties fo:font-size="9pt" fo:color="#ff0000"/> + </style:style> + </office:automatic-styles> + <office:body> + <office:text> + <text:p text:style-name="Standard" loext:marker-style-name="T2"><text:span text:style-name="T1">text</text:span></text:p> + </office:text> + </office:body> +</office:document>
\ No newline at end of file diff --git a/sw/qa/extras/odfexport/odfexport2.cxx b/sw/qa/extras/odfexport/odfexport2.cxx index 269525a8756b..7c3d7fb9b841 100644 --- a/sw/qa/extras/odfexport/odfexport2.cxx +++ b/sw/qa/extras/odfexport/odfexport2.cxx @@ -1061,6 +1061,16 @@ DECLARE_ODFEXPORT_TEST(testTdf78510, "WordTest_edit.odt") #endif } +CPPUNIT_TEST_FIXTURE(Test, testParagraphMarkerMarkupRoundtrip) +{ + loadAndReload("ParagraphMarkerMarkup.fodt"); + // Test that the markup stays at save-and-reload + xmlDocUniquePtr pXmlDoc = parseExport("content.xml"); + assertXPath(pXmlDoc, "/office:document-content/office:body/office:text/text:p", "marker-style-name", "T2"); + assertXPath(pXmlDoc, "/office:document-content/office:automatic-styles/style:style[@style:name='T2']/style:text-properties", "font-size", "9pt"); + assertXPath(pXmlDoc, "/office:document-content/office:automatic-styles/style:style[@style:name='T2']/style:text-properties", "color", "#ff0000"); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/qa/extras/odfimport/data/emptyParagraphLoosesFontHeight.fodt b/sw/qa/extras/odfimport/data/emptyParagraphLoosesFontHeight.fodt new file mode 100644 index 000000000000..7843d7e00f5f --- /dev/null +++ b/sw/qa/extras/odfimport/data/emptyParagraphLoosesFontHeight.fodt @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:styles> + <style:style style:name="Standard" style:family="paragraph" style:class="text"> + <style:text-properties fo:font-size="11pt"/> + </style:style> + </office:styles> + <office:automatic-styles> + <style:style style:name="T1" style:family="text"> + <style:text-properties fo:font-size="8pt"/> + </style:style> + </office:automatic-styles> + <office:body> + <office:text> + <text:p text:style-name="Standard"><text:span text:style-name="T1">value1</text:span><text:span text:style-name="T1"/></text:p> + <text:p text:style-name="Standard"><text:span text:style-name="T1"></text:span><text:span text:style-name="T1"/></text:p> + <text:p text:style-name="Standard"><text:span text:style-name="T1">value2</text:span><text:span text:style-name="T1"/></text:p> + </office:text> + </office:body> +</office:document>
\ No newline at end of file diff --git a/sw/qa/extras/odfimport/odfimport.cxx b/sw/qa/extras/odfimport/odfimport.cxx index 7225be2d4b8e..29df94d9afd6 100644 --- a/sw/qa/extras/odfimport/odfimport.cxx +++ b/sw/qa/extras/odfimport/odfimport.cxx @@ -1513,5 +1513,26 @@ CPPUNIT_TEST_FIXTURE(Test, testWindowsFileZone) #endif } +CPPUNIT_TEST_FIXTURE(Test, testEmptyTrailingSpans) +{ + createSwDoc("emptyParagraphLoosesFontHeight.fodt"); + + CPPUNIT_ASSERT_EQUAL(3, getParagraphs()); + + auto xPara2 = getParagraph(2); + CPPUNIT_ASSERT_EQUAL(float(11), getProperty<float>(xPara2, "CharHeight")); + auto xRun = getRun(xPara2, 1); + CPPUNIT_ASSERT_EQUAL(float(8), getProperty<float>(xRun, "CharHeight")); + // Both empty spans merge -> no more runs + CPPUNIT_ASSERT_THROW(getRun(xPara2, 2), css::container::NoSuchElementException); + + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + + auto height1 = getXPath(pXmlDoc, "/root/page/body/txt[1]/infos/bounds", "height").toInt32(); + auto height2 = getXPath(pXmlDoc, "/root/page/body/txt[2]/infos/bounds", "height").toInt32(); + CPPUNIT_ASSERT_EQUAL(height1, height2); + CPPUNIT_ASSERT_DOUBLES_EQUAL(184, height2, 1); // allow a bit of room for rounding just in case +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx index 8a816ae9f9dd..9248670760ac 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx @@ -861,8 +861,7 @@ DECLARE_OOXMLEXPORT_TEST(testFdo64238_b, "fdo64238_b.docx") xRunEnum->nextElement(); numOfRuns++; } - // "This is the ", "ODD", " [", "LEFT", "] header" and the colored paragraph marker - CPPUNIT_ASSERT_EQUAL(sal_Int32(6), numOfRuns); + CPPUNIT_ASSERT_EQUAL(sal_Int32(5), numOfRuns); } DECLARE_OOXMLEXPORT_TEST(testFdo56679, "fdo56679.docx") diff --git a/sw/source/core/unocore/unoobj.cxx b/sw/source/core/unocore/unoobj.cxx index 7ef11b9462ab..2e65cf97bfcd 100644 --- a/sw/source/core/unocore/unoobj.cxx +++ b/sw/source/core/unocore/unoobj.cxx @@ -230,57 +230,6 @@ lcl_setAutoStyle(IStyleAccess & rStyleAccess, const uno::Any & rValue, rSet.Put(aFormat); }; -/// Tries to map rValue to RES_PARATR_LIST_AUTOFMT on the current paragraph, returns true on -/// success. -static bool lcl_setListAutoStyle(SwPaM& rPam, const uno::Any& rValue, SfxItemSet& rItemSet) -{ - // See if this is an empty range at the end of a paragraph. - if (rPam.Start()->GetNodeIndex() != rPam.End()->GetNodeIndex()) - { - return false; - } - - if (rPam.Start()->GetContentIndex() != rPam.End()->GetContentIndex()) - { - return false; - } - - SwTextNode* pTextNode = rPam.GetPointNode().GetTextNode(); - if (!pTextNode) - { - return false; - } - - if (rPam.Start()->GetContentIndex() != pTextNode->Len()) - { - return false; - } - - // Look up the style content based on the name. - OUString sStyle; - if (!(rValue >>= sStyle)) - { - return false; - } - - IStyleAccess& rStyleAccess = rPam.GetDoc().GetIStyleAccess(); - std::shared_ptr<SfxItemSet> pStyle - = rStyleAccess.getByName(sStyle, IStyleAccess::AUTO_STYLE_CHAR); - if (!pStyle) - { - return false; - } - - // Set the style on the text node. - SwFormatAutoFormat aItem(RES_PARATR_LIST_AUTOFMT); - aItem.SetStyleHandle(pStyle); - pTextNode->SetAttr(aItem); - // Clear the style from the hints array. Without clearing, it would contain some style which - // happened to be there previously. - rItemSet.ClearItem(RES_TXTATR_AUTOFMT); - return true; -} - void SwUnoCursorHelper::SetTextFormatColl(const uno::Any & rAny, SwPaM & rPaM) { @@ -499,11 +448,6 @@ SwUnoCursorHelper::SetCursorPropertyValue( lcl_setCharStyle(rPam.GetDoc(), rValue, rItemSet); break; case RES_TXTATR_AUTOFMT: - if (lcl_setListAutoStyle(rPam, rValue, rItemSet)) - { - break; - } - lcl_setAutoStyle(rPam.GetDoc().GetIStyleAccess(), rValue, rItemSet, false); break; @@ -567,8 +511,8 @@ SwUnoCursorHelper::SetCursorPropertyValue( } else if (FN_UNO_PARA_NUM_AUTO_FORMAT == rEntry.nWID) { - uno::Sequence<beans::NamedValue> props; - if (rValue >>= props) + std::shared_ptr<SfxItemSet> pAutoStyle; + if (uno::Sequence<beans::NamedValue> props; rValue >>= props) { // TODO create own map for this, it contains UNO_NAME_DISPLAY_NAME? or make property readable so ODF export can map it to a automatic style? SfxItemPropertySet const& rPropSet(*aSwMapProvider.GetPropertySet(PROPERTY_MAP_CHAR_AUTO_STYLE)); @@ -603,8 +547,15 @@ SwUnoCursorHelper::SetCursorPropertyValue( IStyleAccess& rStyleAccess = rPam.GetDoc().GetIStyleAccess(); // Add it to the autostyle pool, needed by the ODT export. - const std::shared_ptr<SfxItemSet> pAutoStyle - = rStyleAccess.getAutomaticStyle(items, IStyleAccess::AUTO_STYLE_CHAR); + pAutoStyle = rStyleAccess.getAutomaticStyle(items, IStyleAccess::AUTO_STYLE_CHAR); + } + else if (OUString styleName; rValue >>= styleName) + { + IStyleAccess& rStyleAccess = rPam.GetDoc().GetIStyleAccess(); + pAutoStyle = rStyleAccess.getByName(styleName, IStyleAccess::AUTO_STYLE_CHAR); + } + if (pAutoStyle) + { SwFormatAutoFormat item(RES_PARATR_LIST_AUTOFMT); // note: paragraph auto styles have ParaStyleName property for the parent style; character auto styles currently do not because there's a separate hint, but for this it would be a good way to add it in order to export it as style:parent-style-name, see XMLTextParagraphExport::Add() item.SetStyleHandle(pAutoStyle); diff --git a/sw/source/core/unocore/unoparagraph.cxx b/sw/source/core/unocore/unoparagraph.cxx index 55c71ca730a4..1d0fae809f41 100644 --- a/sw/source/core/unocore/unoparagraph.cxx +++ b/sw/source/core/unocore/unoparagraph.cxx @@ -26,6 +26,7 @@ #include <comphelper/diagnose_ex.hxx> #include <cmdid.h> +#include <fmtautofmt.hxx> #include <unomid.h> #include <unoparaframeenum.hxx> #include <unotext.hxx> @@ -527,6 +528,20 @@ uno::Sequence< uno::Any > SwXParagraph::Impl::GetPropertyValues_Impl( const SwAttrSet& rAttrSet( rTextNode.GetSwAttrSet() ); for (sal_Int32 nProp = 0; nProp < rPropertyNames.getLength(); nProp++) { + if (pPropertyNames[nProp] == "ParaMarkerAutoStyleSpan") + { + // A hack to tunnel the fake text span to ODF export + // see XMLTextParagraphExport::exportParagraph + if (rTextNode.GetAttr(RES_PARATR_LIST_AUTOFMT).GetStyleHandle()) + { + SwUnoCursor aEndCursor(*aPam.GetMark()); + css::uno::Reference<css::beans::XPropertySet> xFakeSpan( + new SwXTextPortion(&aEndCursor, {}, PORTION_LIST_AUTOFMT)); + pValues[nProp] <<= xFakeSpan; + } + continue; + } + SfxItemPropertyMapEntry const*const pEntry = rMap.getByName( pPropertyNames[nProp] ); if (!pEntry) diff --git a/sw/source/core/unocore/unoportenum.cxx b/sw/source/core/unocore/unoportenum.cxx index db567f3cbf05..fd6cc626336b 100644 --- a/sw/source/core/unocore/unoportenum.cxx +++ b/sw/source/core/unocore/unoportenum.cxx @@ -1504,11 +1504,6 @@ static void lcl_CreatePortions( // text portion because there may be a hyperlink attribute xRef = new SwXTextPortion(pUnoCursor, i_xParentText, PORTION_TEXT); } - else if (bAtEnd && !xRef.is() && pTextNode->GetSwAttrSet().HasItem(RES_PARATR_LIST_AUTOFMT)) - { - // We have explicit paragraph marker formatting, export it. - xRef = new SwXTextPortion(pUnoCursor, i_xParentText, PORTION_LIST_AUTOFMT); - } else if (bAtEnd && !xRef.is() && pHints) { // See if there is an empty autofmt at the paragraph end. If so, export it, since that |