diff --git a/include/xmloff/xmlimp.hxx b/include/xmloff/xmlimp.hxx index 44a97ddb9c3f..11cd7c570737 100644 --- a/include/xmloff/xmlimp.hxx +++ b/include/xmloff/xmlimp.hxx @@ -553,6 +553,8 @@ public: static const sal_uInt16 LO_63x = 63 | LO_flag; static const sal_uInt16 LO_7x = 70 | LO_flag; static const sal_uInt16 LO_76 = 76 | LO_flag; + static const sal_uInt16 LO_242 = 80 | LO_flag; + static const sal_uInt16 LO_248 = 81 | LO_flag; static const sal_uInt16 LO_New = 100 | LO_flag; static const sal_uInt16 ProductVersionUnknown = SAL_MAX_UINT16; diff --git a/sw/CppunitTest_sw_ooxmlexport26.mk b/sw/CppunitTest_sw_ooxmlexport26.mk index 8b57467c2f61..2bb987dd2ce4 100644 --- a/sw/CppunitTest_sw_ooxmlexport26.mk +++ b/sw/CppunitTest_sw_ooxmlexport26.mk @@ -11,6 +11,9 @@ $(eval $(call sw_ooxmlexport_test,26)) +# this test requires "de" translations and if missing tests will be skipped +$(call gb_CppunitTest_get_target,sw_ooxmlexport26) : $(call gb_AllLangMoTarget_get_target,sw) + $(call gb_CppunitTest_get_target,sw_ooxmlexport26) : export LO_TEST_LOCALE=de # vim: set noet sw=4 ts=4: diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx index 3c26a31db62e..0c9a77bd3cac 100644 --- a/sw/inc/doc.hxx +++ b/sw/inc/doc.hxx @@ -319,6 +319,7 @@ private: bool mbInWriting : 1; //< TRUE: Document is in the process of being written. bool mbInMailMerge : 1; //< TRUE: Document is in the process of being written by mail merge. bool mbInXMLImport : 1; //< TRUE: During xml import, attribute portion building is not necessary. + bool mbInXMLImport242 : 1 = false; //< TRUE: During xml import, apply workaround for style-ref field bool mbInWriterfilterImport : 1; //< TRUE: writerfilter import (DOCX,RTF) bool mbUpdateTOX : 1; //< TRUE: After loading document, update TOX. bool mbInLoadAsynchron : 1; //< TRUE: Document is in the process of being loaded asynchronously. @@ -989,6 +990,8 @@ public: bool IsInXMLImport() const { return mbInXMLImport; } void SetInXMLImport( bool bNew ) { mbInXMLImport = bNew; } + bool IsInXMLImport242() const { return mbInXMLImport242; } + void SetInXMLImport242(bool const bNew) { mbInXMLImport242 = bNew; } bool IsInWriterfilterImport() const { return mbInWriterfilterImport; } void SetInWriterfilterImport(bool const b) { mbInWriterfilterImport = b; } diff --git a/sw/qa/extras/ooxmlexport/data/tdf166850_24.2.7.2.fodt b/sw/qa/extras/ooxmlexport/data/tdf166850_24.2.7.2.fodt new file mode 100644 index 000000000000..a2308801c2db --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/tdf166850_24.2.7.2.fodt @@ -0,0 +1,164 @@ + + + 2025-06-10T15:12:43.320595150LibreOffice/24.2.7.2$Linux_X86_64 LibreOffice_project/ee3885777aa7032db5a9b65deec9457448a91162 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Second heading + + + + + + + + + + + + + First heading + Second heading + Second heading + + + diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx index 95a755c3bb29..1e7e8ce727dc 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx @@ -739,16 +739,6 @@ DECLARE_OOXMLEXPORT_TEST(testTdf153082_comma, "custom-styles-TOC-comma.docx") CPPUNIT_ASSERT(tocContent.indexOf("Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.") != -1); } -DECLARE_OOXMLEXPORT_TEST(testTdf160402, "StyleRef-DE.docx") -{ - xmlDocUniquePtr pLayout = parseLayoutDump(); - assertXPath(pLayout, "/root/page[1]/header/txt[1]/SwParaPortion/SwLineLayout/SwFieldPortion", "expand", u"Heading 1"); - assertXPath(pLayout, "/root/page[2]/header/txt[1]/SwParaPortion/SwLineLayout/SwFieldPortion", "expand", u"Nunc viverra imperdiet enim. Fusce est. Vivamus a tellus."); - assertXPath(pLayout, "/root/page[3]/header/txt[1]/SwParaPortion/SwLineLayout/SwFieldPortion", "expand", u"Cras faucibus condimentum odio. Sed ac ligula. Aliquam at eros."); - assertXPath(pLayout, "/root/page[4]/header/txt[1]/SwParaPortion/SwLineLayout/SwFieldPortion", "expand", u"Nunc viverra imperdiet enim. Fusce est. Vivamus a tellus."); - assertXPath(pLayout, "/root/page[5]/header/txt[1]/SwParaPortion/SwLineLayout/SwFieldPortion", "expand", u"Aenean nec lorem. In porttitor. Donec laoreet nonummy augue."); -} - DECLARE_OOXMLEXPORT_TEST(testTdf142407, "tdf142407.docx") { uno::Reference xPageStyles = getStyles(u"PageStyles"_ustr); diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport26.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport26.cxx index 2346da8dc504..f40100534939 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport26.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport26.cxx @@ -9,6 +9,10 @@ #include +#include +#include +#include + #include #include @@ -23,6 +27,21 @@ public: } }; +DECLARE_OOXMLEXPORT_TEST(testTdf160402, "StyleRef-DE.docx") +{ + xmlDocUniquePtr pLayout = parseLayoutDump(); + assertXPath(pLayout, "/root/page[1]/header/txt[1]/SwParaPortion/SwLineLayout/SwFieldPortion", + "expand", u"Heading 1"); + assertXPath(pLayout, "/root/page[2]/header/txt[1]/SwParaPortion/SwLineLayout/SwFieldPortion", + "expand", u"Nunc viverra imperdiet enim. Fusce est. Vivamus a tellus."); + assertXPath(pLayout, "/root/page[3]/header/txt[1]/SwParaPortion/SwLineLayout/SwFieldPortion", + "expand", u"Cras faucibus condimentum odio. Sed ac ligula. Aliquam at eros."); + assertXPath(pLayout, "/root/page[4]/header/txt[1]/SwParaPortion/SwLineLayout/SwFieldPortion", + "expand", u"Nunc viverra imperdiet enim. Fusce est. Vivamus a tellus."); + assertXPath(pLayout, "/root/page[5]/header/txt[1]/SwParaPortion/SwLineLayout/SwFieldPortion", + "expand", u"Aenean nec lorem. In porttitor. Donec laoreet nonummy augue."); +} + //test requires German user interface otherwise it will not detect the issue CPPUNIT_TEST_FIXTURE(Test, testTdf166850) { @@ -35,6 +54,35 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf166850) "expand", u"Heading 1"); } +CPPUNIT_TEST_FIXTURE(Test, testTdf166850_ODT) +{ + // test ODT import from version 24.2 where this worked + // but only in the same locale that was used to import from DOCX, not in + // a different one + OUString instdir; + osl_getEnvironment(u"INSTDIR"_ustr.pData, &instdir.pData); + OUString url; + CPPUNIT_ASSERT_EQUAL(::osl::FileBase::E_None, + ::osl::FileBase::getFileURLFromSystemPath(instdir, url)); + url += "/" LIBO_SHARE_RESOURCE_FOLDER "/de/LC_MESSAGES/sw.mo"; + ::osl::DirectoryItem item; + if (::osl::DirectoryItem::get(url, item) == ::osl::FileBase::E_NOENT) + { + return; + } + createSwDoc("tdf166850_24.2.7.2.fodt"); + SwDoc* pDoc = getSwDoc(); + SwViewShell* pViewShell = pDoc->getIDocumentLayoutAccess().GetCurrentViewShell(); + pViewShell->UpdateFields(); + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/SwParaPortion/SwLineLayout/SwFieldPortion", + "expand", u"First heading"); + assertXPath(pXmlDoc, "/root/page[2]/header/txt[1]/SwParaPortion/SwLineLayout/SwFieldPortion", + "expand", u"Second heading"); + assertXPath(pXmlDoc, "/root/page[2]/body/txt[2]/SwParaPortion/SwLineLayout/SwFieldPortion", + "expand", u"Second heading"); +} + } // end of anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/core/fields/reffld.cxx b/sw/source/core/fields/reffld.cxx index 20dccd31999e..c7392d889f52 100644 --- a/sw/source/core/fields/reffld.cxx +++ b/sw/source/core/fields/reffld.cxx @@ -962,6 +962,17 @@ bool SwGetRefField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const break; } } + else if (REF_STYLE == m_nSubType) + { + ProgName name; + SwStyleNameMapper::FillProgName(UIName{sTmp}, name, SwGetPoolIdFromName::TxtColl); + if (name == sTmp) + { + SwStyleNameMapper::FillProgName(UIName{sTmp}, name, SwGetPoolIdFromName::ChrFmt); + } + sTmp = name.toString(); + + } rAny <<= sTmp; } break; @@ -1025,7 +1036,13 @@ bool SwGetRefField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId ) case ReferenceFieldSource::BOOKMARK : m_nSubType = REF_BOOKMARK ; break; case ReferenceFieldSource::FOOTNOTE : m_nSubType = REF_FOOTNOTE ; break; case ReferenceFieldSource::ENDNOTE : m_nSubType = REF_ENDNOTE ; break; - case ReferenceFieldSource::STYLE : m_nSubType = REF_STYLE ; break; + case ReferenceFieldSource::STYLE : + if (REF_STYLE != m_nSubType) + { + m_nSubType = REF_STYLE; + ConvertProgrammaticToUIName(); + } + break; } } break; @@ -1070,6 +1087,29 @@ bool SwGetRefField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId ) void SwGetRefField::ConvertProgrammaticToUIName() { + if (GetTyp() && REF_STYLE == m_nSubType) + { + // this is super ugly, but there isn't a sensible way to check in xmloff + SwDoc & rDoc{static_cast(GetTyp())->GetDoc()}; + if (rDoc.IsInXMLImport242()) + { + SAL_INFO("sw.xml", "Potentially accepting erroneously produced UIName for style-ref field"); + return; + } + ProgName const par1{GetPar1()}; + UIName name; + SwStyleNameMapper::FillUIName(par1, name, SwGetPoolIdFromName::TxtColl); + if (name.toString() == par1.toString()) + { + SwStyleNameMapper::FillUIName(par1, name, SwGetPoolIdFromName::ChrFmt); + } + if (name.toString() != par1.toString()) + { + SetPar1(name.toString()); + } + return; + } + if(!(GetTyp() && REF_SEQUENCEFLD == m_nSubType)) return; diff --git a/sw/source/core/unocore/unofield.cxx b/sw/source/core/unocore/unofield.cxx index 9fc8a02c6d96..746d21b1509f 100644 --- a/sw/source/core/unocore/unofield.cxx +++ b/sw/source/core/unocore/unofield.cxx @@ -1513,6 +1513,9 @@ void SAL_CALL SwXTextField::attach( case SwServiceType::FieldTypeGetReference: { SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::GetRef); + // tdf#159549 tdf#166850: if nUSHORT2 is ReferenceFieldSource::STYLE, + // sPar1 needs to be converted from ProgName to UIName - this + // is done when setting the FIELD_PROP_USHORT2 below xField.reset(new SwGetRefField(static_cast(pFieldType), SwMarkName(m_pImpl->m_pProps->sPar1), m_pImpl->m_pProps->sPar4, diff --git a/sw/source/filter/basflt/shellio.cxx b/sw/source/filter/basflt/shellio.cxx index 38440d48eea3..c3d66e8269c8 100644 --- a/sw/source/filter/basflt/shellio.cxx +++ b/sw/source/filter/basflt/shellio.cxx @@ -346,6 +346,7 @@ ErrCodeMsg SwReader::Read( const Reader& rOptions ) mxDoc->SetInReading( false ); mxDoc->SetInXMLImport( false ); + mxDoc->SetInXMLImport242(false); mxDoc->SetInWriterfilterImport(false); if (!mbSkipInvalidateNumRules) diff --git a/sw/source/filter/xml/xmlfmt.cxx b/sw/source/filter/xml/xmlfmt.cxx index d5b06c6ac502..f4944a282209 100644 --- a/sw/source/filter/xml/xmlfmt.cxx +++ b/sw/source/filter/xml/xmlfmt.cxx @@ -995,6 +995,14 @@ void SwXMLMasterStylesContext_Impl::endFastElement(sal_Int32 ) SvXMLImportContext *SwXMLImport::CreateStylesContext( bool bAuto ) { + // tdf#166850 this only worked in 24.2.4..24.2.7 and broke in 24.8.0 + // anyway but must *not* be applied to fixed 25.2.x or later + if (isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, SvXMLImport::LO_248) + && !isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, SvXMLImport::LO_242)) + { + getDoc()->SetInXMLImport242(true); + } + SvXMLStylesContext *pContext = new SwXMLStylesContext_Impl( *this, bAuto ); if( bAuto ) SetAutoStyles( pContext ); diff --git a/sw/source/filter/xml/xmlimp.cxx b/sw/source/filter/xml/xmlimp.cxx index d879abe2f03b..7e6820e3cf66 100644 --- a/sw/source/filter/xml/xmlimp.cxx +++ b/sw/source/filter/xml/xmlimp.cxx @@ -668,6 +668,7 @@ void SwXMLImport::endDocument() assert(pDoc->IsInXMLImport()); pDoc->SetInReading(false); pDoc->SetInXMLImport(false); + pDoc->SetInXMLImport242(false); } SwDrawModel* pDrawModel = pDoc->getIDocumentDrawModelAccess().GetDrawModel(); diff --git a/sw/source/writerfilter/dmapper/StyleSheetTable.cxx b/sw/source/writerfilter/dmapper/StyleSheetTable.cxx index 6e3259aacc8f..099ae839e7ef 100644 --- a/sw/source/writerfilter/dmapper/StyleSheetTable.cxx +++ b/sw/source/writerfilter/dmapper/StyleSheetTable.cxx @@ -1103,22 +1103,19 @@ OUString StyleSheetTable::CloneTOCStyle(FontTablePtr const& rFontTable, StyleShe // the old converted name is what is applied to paragraphs m_pImpl->m_ClonedTOCStylesMap.emplace(pStyle->m_sConvertedStyleName, pClone->m_sConvertedStyleName); std::vector const styles{ pClone }; - std::vector aRetStyleNames = ApplyStyleSheetsImpl(rFontTable, styles); - pClone->m_sConvertedStyleName = aRetStyleNames[0]; + ApplyStyleSheetsImpl(rFontTable, styles); return pClone->m_sConvertedStyleName; } void StyleSheetTable::ApplyStyleSheets( const FontTablePtr& rFontTable ) { - ApplyStyleSheetsImpl(rFontTable, m_pImpl->m_aStyleSheetEntries); + return ApplyStyleSheetsImpl(rFontTable, m_pImpl->m_aStyleSheetEntries); } -std::vector StyleSheetTable::ApplyStyleSheetsImpl(const FontTablePtr& rFontTable, std::vector const& rEntries) +void StyleSheetTable::ApplyStyleSheetsImpl(const FontTablePtr& rFontTable, std::vector const& rEntries) { - std::vector aStyleUINames(rEntries.size()); - std::vector::iterator aStyleUINamesIt = aStyleUINames.begin(); if (!m_pImpl->m_xTextDocument) - return aStyleUINames; + return; try { rtl::Reference< SwXStyleFamilies > xStyleFamilies = m_pImpl->m_xTextDocument->getSwStyleFamilies(); @@ -1134,7 +1131,6 @@ std::vector StyleSheetTable::ApplyStyleSheetsImpl(const FontTablePtr& std::vector aTableStylesVec; for (auto& pEntry : rEntries) { - *aStyleUINamesIt = pEntry->m_sStyleName; if( pEntry->m_nStyleTypeCode == STYLE_TYPE_UNKNOWN && !pEntry->m_sStyleName.isEmpty() ) pEntry->m_nStyleTypeCode = STYLE_TYPE_PARA; // unspecified style types are considered paragraph styles @@ -1418,7 +1414,7 @@ std::vector StyleSheetTable::ApplyStyleSheetsImpl(const FontTablePtr& aMissingParent.emplace_back( sParentStyle, xStyle ); xStyles->insertStyleByName( sConvertedStyleName, static_cast(xStyle.get()) ); - *aStyleUINamesIt = static_cast(xStyle.get())->GetStyleUIName().toString(); + if (!m_pImpl->m_bIsNewDoc && bParaStyle) { // Remember the inserted style, which may or may not be referred during @@ -1447,7 +1443,6 @@ std::vector StyleSheetTable::ApplyStyleSheetsImpl(const FontTablePtr& pEntry->m_pProperties->InsertProps( m_pImpl->m_pDefaultCharProps, /*bOverwrite=*/false ); pEntry->m_pProperties->InsertProps( m_pImpl->m_pDefaultParaProps, /*bOverwrite=*/false ); } - ++aStyleUINamesIt; } // Update the styles that were created before their parents or next-styles @@ -1497,7 +1492,6 @@ std::vector StyleSheetTable::ApplyStyleSheetsImpl(const FontTablePtr& { DBG_UNHANDLED_EXCEPTION("writerfilter", "Styles could not be imported completely"); } - return aStyleUINames; } diff --git a/sw/source/writerfilter/dmapper/StyleSheetTable.hxx b/sw/source/writerfilter/dmapper/StyleSheetTable.hxx index 3715e1ef6ef7..eaf84387b512 100644 --- a/sw/source/writerfilter/dmapper/StyleSheetTable.hxx +++ b/sw/source/writerfilter/dmapper/StyleSheetTable.hxx @@ -128,7 +128,7 @@ private: void applyDefaults(bool bParaProperties); - std::vector ApplyStyleSheetsImpl(const FontTablePtr& rFontTable, std::vector const& rEntries); + void ApplyStyleSheetsImpl(const FontTablePtr& rFontTable, std::vector const& rEntries); }; diff --git a/xmloff/qa/unit/uxmloff.cxx b/xmloff/qa/unit/uxmloff.cxx index 7fb1004bf612..cf888baa93fd 100644 --- a/xmloff/qa/unit/uxmloff.cxx +++ b/xmloff/qa/unit/uxmloff.cxx @@ -199,7 +199,9 @@ void Test::testMetaGenerator() { "LibreOffice_powered_by_CIBDev/6.4.0.0.0$Linux_X86_64 LibreOffice_project/e29e100174c133d27e953934311d68602c4515b7", ";6.4.0.0.0", SvXMLImport::LO_63x }, { "LibreOfficeDev/7.0.6.0.0$Linux_X86_64 LibreOffice_project/dfc40e2292c6e19e285c10ed8c8044d9454107d0", ";7.0.6.0.0", SvXMLImport::LO_7x }, { "CIB_OfficeDev/6.4.0.19$Linux_X86_64 LibreOffice_project/2e04f804b5f82770435f250873f07b3384d95504", ";6.4.0.19", SvXMLImport::LO_63x }, - { "LibreOfficeDev/24.2.0.0.alpha0$Linux_X86_64 LibreOffice_project/b81e7b6f3c71fb3ade1cb665444ac730dac0a9a9", ";24.2.0.0.", SvXMLImport::LO_New }, + { "LibreOfficeDev/24.2.0.0.alpha0$Linux_X86_64 LibreOffice_project/b81e7b6f3c71fb3ade1cb665444ac730dac0a9a9", ";24.2.0.0.", SvXMLImport::LO_242 }, + { "LibreOfficeDev/24.8.6.2$Linux_X86_64 LibreOffice_project/dc6216c3d2b4ec3bcdba950f1e6ee1d013adb2d6", ";24.8.6.2", SvXMLImport::LO_248 }, + { "LibreOfficeDev/25.8.0.0.alpha0$Linux_X86_64 LibreOffice_project/308705574842e0c36f7385f73fc47da9a4542367", ";25.8.0.0.", SvXMLImport::LO_New } }; for (auto const[pGenerator, pBuildId, nResult] : tests) diff --git a/xmloff/source/core/xmlimp.cxx b/xmloff/source/core/xmlimp.cxx index a487b992a142..134259fdb0f5 100644 --- a/xmloff/source/core/xmlimp.cxx +++ b/xmloff/source/core/xmlimp.cxx @@ -234,8 +234,16 @@ public: { OUString const nMajor(loVersion.subView(0, firstDot)); auto const year(nMajor.toInt32()); - //auto const month(loVersion.copy(firstDot+1).toInt32()); - if (0 < year) + auto const month(o3tl::toInt32(loVersion.subView(firstDot+1))); + if (24 == year && month == 2) + { + mnGeneratorVersion = SvXMLImport::LO_242; + } + else if (24 == year && month == 8) + { + mnGeneratorVersion = SvXMLImport::LO_248; + } + else if (0 < year) { mnGeneratorVersion = SvXMLImport::LO_New; }