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.)

Change-Id: Ib63e14322e5501a6220f798abd9365d7913dab4c
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/130503
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins
This commit is contained in:
Miklos Vajna
2022-02-24 17:37:59 +01:00
parent 3469f6976c
commit 1127c63470
7 changed files with 85 additions and 0 deletions
+2
View File
@@ -464,6 +464,8 @@ public:
OUString GetODFVersion() const;
bool IsOOoXML() const; // legacy non-ODF format?
/// Determines if the document was generated by Microsoft Office.
bool IsMSO() const;
/**
* Record an error condition that occurred during import. The
+5
View File
@@ -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 > >
Binary file not shown.
+25
View File
@@ -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: */
+22
View File
@@ -58,6 +58,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>
@@ -291,6 +292,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#)
@@ -1864,6 +1867,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)
@@ -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 ) )
+23
View File
@@ -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: */