tdf#161417 RTF export: handle endnotes at section ends
Similar to commit 566c7017a84e3d573de85a6d986b81d3f59de0fa (tdf#160984
sw continuous endnotes: DOCX: export of <w:endnotePr> pos == sectEnd,
2024-05-29), but this is RTF, not DOCX.
Additional complexity is that it's not enough to just write \aendnotes
(sect end) or \aenddoc (doc end) to export the position, also \fet and
\endnhere needs writing, otherwise Word ignores this.
Last bit is to ignore section formats which are not nullptr but are -1,
ignore these in RtfAttributeOutput::SectionBreak(), similar to how
DocxAttributeOutput::SectionBreak() does the same already.
Change-Id: I2327c979d5af402eb15523d97149f6409fcf4adf
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/168468
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins
diff --git a/sw/qa/extras/rtfexport/rtfexport8.cxx b/sw/qa/extras/rtfexport/rtfexport8.cxx
index 33219ed..347b39c 100644
--- a/sw/qa/extras/rtfexport/rtfexport8.cxx
+++ b/sw/qa/extras/rtfexport/rtfexport8.cxx
@@ -39,6 +39,7 @@
#include <frmmgr.hxx>
#include <formatflysplit.hxx>
#include <fmtwrapinfluenceonobjpos.hxx>
#include <fmtftntx.hxx>
using namespace css;
@@ -173,6 +174,36 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf158586_lostFrame)
verify();
}
CPPUNIT_TEST_FIXTURE(Test, testEndnotesAtSectEndRTF)
{
// Given a document, endnotes at collected at section end:
createSwDoc();
{
SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
pWrtShell->SplitNode();
pWrtShell->Up(/*bSelect=*/false);
pWrtShell->Insert("x");
pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/true, 1, /*bBasicCall=*/false);
SwSectionData aSection(SectionType::Content, pWrtShell->GetUniqueSectionName());
pWrtShell->StartAction();
SfxItemSetFixed<RES_FTN_AT_TXTEND, RES_FRAMEDIR> aSet(pWrtShell->GetAttrPool());
aSet.Put(SwFormatEndAtTextEnd(FTNEND_ATTXTEND));
pWrtShell->InsertSection(aSection, &aSet);
pWrtShell->EndAction();
pWrtShell->InsertFootnote(OUString(), /*bEndNote=*/true);
}
// When saving to DOC:
saveAndReload(mpFilter);
// Then make sure the endnote position is section end:
SwDoc* pDoc = getSwDoc();
SwSectionFormats& rSections = pDoc->GetSections();
SwSectionFormat* pFormat = rSections[0];
// Without the accompanying fix in place, this test would have failed, endnotes were at doc end.
CPPUNIT_ASSERT(pFormat->GetEndAtTextEnd().IsAtEnd());
}
CPPUNIT_TEST_FIXTURE(Test, testTdf158983)
{
auto verify = [this]() {
diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx b/sw/source/filter/ww8/rtfattributeoutput.cxx
index 2c9f92a..8721e2f 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.cxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.cxx
@@ -97,6 +97,7 @@
#include "rtfexport.hxx"
#include <IDocumentDeviceAccess.hxx>
#include <sfx2/printer.hxx>
#include <fmtftntx.hxx>
using namespace ::com::sun::star;
using namespace sw::util;
@@ -1367,6 +1368,23 @@ void RtfAttributeOutput::SectionBreak(sal_uInt8 nC, bool /*bBreakAfter*/,
m_rExport.SectionProperties(*pSectionInfo);
break;
}
// Endnotes included in the section:
if (!pSectionInfo)
{
return;
}
const SwSectionFormat* pSectionFormat = pSectionInfo->pSectionFormat;
if (!pSectionFormat || pSectionFormat == reinterpret_cast<SwSectionFormat*>(sal_IntPtr(-1)))
{
// MSWordExportBase::WriteText() can set the section format to -1, ignore.
return;
}
if (!pSectionFormat->GetEndAtTextEnd().IsAtEnd())
{
return;
}
m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_ENDNHERE);
}
void RtfAttributeOutput::StartSection()
diff --git a/sw/source/filter/ww8/rtfexport.cxx b/sw/source/filter/ww8/rtfexport.cxx
index 8acd964..88a3086 100644
--- a/sw/source/filter/ww8/rtfexport.cxx
+++ b/sw/source/filter/ww8/rtfexport.cxx
@@ -70,6 +70,9 @@
#include <frmatr.hxx>
#include <swtable.hxx>
#include <IMark.hxx>
#include <fmtftntx.hxx>
#include <ftnidx.hxx>
#include <txtftn.hxx>
using namespace ::com::sun::star;
@@ -798,7 +801,8 @@ ErrCode RtfExport::ExportDocument_Impl()
// enable it on a per-section basis. OTOH don't always enable it as it
// breaks moving of drawings - so write it only in case there is really a
// protected section in the document.
for (auto const& pSectionFormat : m_rDoc.GetSections())
SwSectionFormats& rSections = m_rDoc.GetSections();
for (auto const& pSectionFormat : rSections)
{
if (!pSectionFormat->IsInUndo() && pSectionFormat->GetProtect().IsContentProtected())
{
@@ -968,8 +972,55 @@ ErrCode RtfExport::ExportDocument_Impl()
const SwEndNoteInfo& rEndNoteInfo = m_rDoc.GetEndNoteInfo();
if (!rSections.empty())
{
SwSectionFormat* pFormat = rSections[0];
bool bEndnAtEnd = pFormat->GetEndAtTextEnd().IsAtEnd();
if (bEndnAtEnd)
{
// Endnotes at end of section.
Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_AENDNOTES);
}
else
{
// Endnotes at end of document.
Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_AENDDOC);
}
}
// Types of notes that are present in the document:
Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_FET);
SwFootnoteIdxs& rFootnotes = m_rDoc.GetFootnoteIdxs();
bool bHasFootnote = false;
bool bHasEndnote = false;
for (const auto& pFootnote : rFootnotes)
{
if (pFootnote->GetFootnote().IsEndNote())
{
bHasEndnote = true;
}
else
{
bHasFootnote = true;
}
if (bHasFootnote && bHasEndnote)
{
break;
}
}
if (bHasFootnote && bHasEndnote)
{
// Both footnotes and endnotes.
Strm().WriteOString("2");
}
else if (bHasEndnote)
{
// Endnotes only.
Strm().WriteOString("1");
}
Strm()
.WriteOString(OOO_STRING_SVTOOLS_RTF_AENDDOC)
.WriteOString(OOO_STRING_SVTOOLS_RTF_AFTNRSTCONT)
.WriteOString(OOO_STRING_SVTOOLS_RTF_AFTNSTART);
Strm().WriteNumberAsString(rEndNoteInfo.m_nFootnoteOffset + 1);