summaryrefslogtreecommitdiff
path: root/xmloff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2022-02-24 16:43:19 +0100
committerMiklos Vajna <vmiklos@collabora.com>2022-02-25 09:09:01 +0100
commitd5a67b97b47bcb57467cf0ddc5855c0b29a82122 (patch)
tree8f13f91f0363dd7d832087dc5da0015536827d0b /xmloff
parenta45f880cc11a7287a1c8ff3c4ffebaa20e41653b (diff)
ODT import: fix MSO-style <text:list text:continue-numbering="true">
The ODF spec says that text:continue-numbering="true" should only continue the numbering in case the styles of the previous and the current list match. In contrast, Word continues the numbering even in case there is e.g. numbering, then bullets, then numbering again, in case the list styles of the two numberings are the same. Work this around at import time when the generator confirms that the document is coming from Word. At least Office 2019 and the latest renderer at office.com is affected. (I've mailed dochelp@microsoft, no answer yet.) (cherry picked from commit 1127c63470096f62394f133c61cee2e6fb7fd0c7) Change-Id: Ib63e14322e5501a6220f798abd9365d7913dab4c
Diffstat (limited to 'xmloff')
-rw-r--r--xmloff/inc/txtlists.hxx5
-rw-r--r--xmloff/qa/unit/data/continue-numbering-word.odtbin0 -> 6151 bytes
-rw-r--r--xmloff/qa/unit/text.cxx25
-rw-r--r--xmloff/source/core/xmlimp.cxx22
-rw-r--r--xmloff/source/text/XMLTextListBlockContext.cxx8
-rw-r--r--xmloff/source/text/txtlists.cxx23
6 files changed, 83 insertions, 0 deletions
diff --git a/xmloff/inc/txtlists.hxx b/xmloff/inc/txtlists.hxx
index 30529a141fb9..dda522c441f9 100644
--- a/xmloff/inc/txtlists.hxx
+++ b/xmloff/inc/txtlists.hxx
@@ -121,6 +121,9 @@ class XMLTextListsHelper
bool* o_pRestartNumbering = nullptr,
bool* io_pSetDefaults = nullptr);
+ /// Looks up the last list id of a given list style, by name.
+ OUString GetLastIdOfStyleName(const OUString& sListStyleName) const;
+
private:
/** list context: list, list-item, numbered-paragraph
@@ -152,6 +155,8 @@ class XMLTextListsHelper
typedef ::std::map< OUString, OUString > tMapForContinuingLists;
std::unique_ptr<tMapForContinuingLists> mpContinuingLists;
+ std::unique_ptr<std::map<OUString, OUString>> mpStyleNameLastListIds;
+
// stack type for opened list elements and its list style:
// vector with pair( <ListId>, <ListStyleName> ) as value
typedef ::std::vector< ::std::pair< OUString, OUString > >
diff --git a/xmloff/qa/unit/data/continue-numbering-word.odt b/xmloff/qa/unit/data/continue-numbering-word.odt
new file mode 100644
index 000000000000..278a1fa65684
--- /dev/null
+++ b/xmloff/qa/unit/data/continue-numbering-word.odt
Binary files differ
diff --git a/xmloff/qa/unit/text.cxx b/xmloff/qa/unit/text.cxx
index 9ac9ac93dbc4..1d239e2e0c09 100644
--- a/xmloff/qa/unit/text.cxx
+++ b/xmloff/qa/unit/text.cxx
@@ -220,6 +220,31 @@ CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testParaStyleListLevel)
"list-level", "2");
}
+CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testContinueNumberingWord)
+{
+ // Given a document, which is produced by Word and contains text:continue-numbering="true":
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "continue-numbering-word.odt";
+
+ // When loading that document:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure that the numbering from the 1st para is continued on the 3rd para:
+ uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<text::XText> xText = xTextDocument->getText();
+ uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xTextDocument->getText(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
+ xParaEnum->nextElement();
+ xParaEnum->nextElement();
+ uno::Reference<beans::XPropertySet> xPara(xParaEnum->nextElement(), uno::UNO_QUERY);
+ auto aActual = xPara->getPropertyValue("ListLabelString").get<OUString>();
+ // Without the accompanying fix in place, this failed with:
+ // - Expected: 2.
+ // - Actual : 1.
+ // i.e. the numbering was not continued, like in Word.
+ CPPUNIT_ASSERT_EQUAL(OUString("2."), aActual);
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/core/xmlimp.cxx b/xmloff/source/core/xmlimp.cxx
index 5b4d006211ba..f0501699fa38 100644
--- a/xmloff/source/core/xmlimp.cxx
+++ b/xmloff/source/core/xmlimp.cxx
@@ -56,6 +56,7 @@
#include <com/sun/star/xml/sax/FastParser.hpp>
#include <com/sun/star/xml/sax/SAXException.hpp>
#include <com/sun/star/packages/zip/ZipIOException.hpp>
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
#include <comphelper/fileformat.h>
#include <comphelper/namecontainer.hxx>
#include <comphelper/servicehelper.hxx>
@@ -289,6 +290,8 @@ public:
bool mbIsOOoXML;
+ std::optional<bool> mbIsMSO;
+
// Boolean, indicating that position attributes
// of shapes are given in horizontal left-to-right layout. This is the case
// for the OpenOffice.org file format. (#i28749#)
@@ -1851,6 +1854,25 @@ bool SvXMLImport::IsOOoXML() const
return mpImpl->mbIsOOoXML;
}
+bool SvXMLImport::IsMSO() const
+{
+ if (!mpImpl->mbIsMSO.has_value())
+ {
+ uno::Reference<document::XDocumentPropertiesSupplier> xSupplier(GetModel(), uno::UNO_QUERY);
+ if (xSupplier.is())
+ {
+ uno::Reference<document::XDocumentProperties> xProps
+ = xSupplier->getDocumentProperties();
+ if (xProps.is())
+ {
+ mpImpl->mbIsMSO = xProps->getGenerator().startsWith("MicrosoftOffice");
+ }
+ }
+ }
+
+ return mpImpl->mbIsMSO.has_value() ? *mpImpl->mbIsMSO : false;
+}
+
// xml:id for RDF metadata
void SvXMLImport::SetXmlId(uno::Reference<uno::XInterface> const & i_xIfc,
OUString const & i_rXmlId)
diff --git a/xmloff/source/text/XMLTextListBlockContext.cxx b/xmloff/source/text/XMLTextListBlockContext.cxx
index 03c9fe0e537e..7c688f4c5e6c 100644
--- a/xmloff/source/text/XMLTextListBlockContext.cxx
+++ b/xmloff/source/text/XMLTextListBlockContext.cxx
@@ -181,6 +181,14 @@ XMLTextListBlockContext::XMLTextListBlockContext(
}
}
+ bool bContinueNumbering = bIsContinueNumberingAttributePresent && !mbRestartNumbering;
+ if (msContinueListId.isEmpty() && bContinueNumbering && GetImport().IsMSO())
+ {
+ // No "continue list" id, but continue numbering was requested. Connect to the last list of
+ // the same list style in the Word case, even if there was a different list in the meantime.
+ msContinueListId = rTextListsHelper.GetLastIdOfStyleName(msListStyleName);
+ }
+
if ( !msContinueListId.isEmpty() )
{
if ( !rTextListsHelper.IsListProcessed( msContinueListId ) )
diff --git a/xmloff/source/text/txtlists.cxx b/xmloff/source/text/txtlists.cxx
index ec66f9d7d72c..9b3b46f175e7 100644
--- a/xmloff/source/text/txtlists.cxx
+++ b/xmloff/source/text/txtlists.cxx
@@ -124,6 +124,13 @@ void XMLTextListsHelper::KeepListAsProcessed( const OUString& sListId,
msLastProcessedListId = sListId;
msListStyleOfLastProcessedList = sListStyleName;
+ // Remember what is the last list id of this list style.
+ if (!mpStyleNameLastListIds)
+ {
+ mpStyleNameLastListIds = std::make_unique<std::map<OUString, OUString>>();
+ }
+ (*mpStyleNameLastListIds)[sListStyleName] = sListId;
+
// Inconsistent behavior regarding lists (#i92811#)
if ( sListStyleDefaultListId.isEmpty())
return;
@@ -473,4 +480,20 @@ XMLTextListsHelper::MakeNumRule(
return xNumRules;
}
+OUString XMLTextListsHelper::GetLastIdOfStyleName(const OUString& sListStyleName) const
+{
+ if (!mpStyleNameLastListIds)
+ {
+ return {};
+ }
+
+ auto it = mpStyleNameLastListIds->find(sListStyleName);
+ if (it == mpStyleNameLastListIds->end())
+ {
+ return {};
+ }
+
+ return it->second;
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */