sw: DOCX: recognize TOC title during import
Change-Id: Ifa4fb59858d61580f76e3d104aa4caa6b5902d1b
Reviewed-on: https://gerrit.libreoffice.org/64735
Tested-by: Jenkins
Reviewed-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx
index 3878c42..4d1cf10c 100644
--- a/sw/inc/doc.hxx
+++ b/sw/inc/doc.hxx
@@ -917,6 +917,11 @@ public:
const SfxItemSet* pSet = nullptr,
bool bExpand = false,
SwRootFrame const* pLayout = nullptr);
SwTOXBaseSection* InsertTableOf( const SwPaM& aPam,
const SwTOXBase& rTOX,
const SfxItemSet* pSet = nullptr,
bool bExpand = false,
SwRootFrame const* pLayout = nullptr );
void InsertTableOf( sal_uLong nSttNd, sal_uLong nEndNd,
const SwTOXBase& rTOX,
const SfxItemSet* pSet );
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
index b36fe83..90c7566 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
@@ -24,6 +24,7 @@
#include <com/sun/star/graphic/XGraphic.hpp>
#include <com/sun/star/text/RubyAdjust.hpp>
#include <com/sun/star/text/RubyPosition.hpp>
#include <com/sun/star/text/XDocumentIndex.hpp>
#include <sfx2/docfile.hxx>
@@ -144,6 +145,19 @@ DECLARE_OOXMLEXPORT_TEST(testTdf121561_tocTitle, "tdf121456_tabsOffset.odt")
assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:docPartObj/w:docPartUnique", 1);
}
DECLARE_OOXMLEXPORT_TEST(testTdf121561_tocTitleDocx, "tdf121456_tabsOffset.odt")
{
xmlDocPtr pXmlDoc = parseExport();
if (!pXmlDoc)
return;
uno::Reference<text::XDocumentIndexesSupplier> xIndexSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<container::XIndexAccess> xIndexes(xIndexSupplier->getDocumentIndexes( ), uno::UNO_QUERY);
uno::Reference<text::XDocumentIndex> xTOCIndex(xIndexes->getByIndex(0), uno::UNO_QUERY);
CPPUNIT_ASSERT_EQUAL(OUString("Inhaltsverzeichnis"), getProperty<OUString>(xTOCIndex, "Title"));
}
DECLARE_OOXMLEXPORT_TEST(testTdf106174_rtlParaAlign, "tdf106174_rtlParaAlign.docx")
{
CPPUNIT_ASSERT_EQUAL(sal_Int16(style::ParagraphAdjust_CENTER), getProperty<sal_Int16>(getParagraph(1), "ParaAdjust"));
diff --git a/sw/source/core/doc/doctxm.cxx b/sw/source/core/doc/doctxm.cxx
index 4e7ab45..923cd9b 100644
--- a/sw/source/core/doc/doctxm.cxx
+++ b/sw/source/core/doc/doctxm.cxx
@@ -347,15 +347,24 @@ const SwTOXMark& SwDoc::GotoTOXMark( const SwTOXMark& rCurTOXMark,
}
SwTOXBaseSection* SwDoc::InsertTableOf( const SwPosition& rPos,
const SwTOXBase& rTOX,
const SfxItemSet* pSet,
bool bExpand,
const SwTOXBase& rTOX,
const SfxItemSet* pSet,
bool bExpand,
SwRootFrame const*const pLayout)
{
SwPaM aPam( rPos );
return InsertTableOf( aPam, rTOX, pSet, bExpand, pLayout );
}
SwTOXBaseSection* SwDoc::InsertTableOf( const SwPaM& aPam,
const SwTOXBase& rTOX,
const SfxItemSet* pSet,
bool bExpand,
SwRootFrame const*const pLayout )
{
GetIDocumentUndoRedo().StartUndo( SwUndoId::INSTOX, nullptr );
OUString sSectNm = GetUniqueTOXBaseName( *rTOX.GetTOXType(), rTOX.GetTOXName() );
SwPaM aPam( rPos );
SwSectionData aSectionData( TOX_CONTENT_SECTION, sSectNm );
SwTOXBaseSection *const pNewSection = dynamic_cast<SwTOXBaseSection *>(
InsertSwSection( aPam, aSectionData, & rTOX, pSet, false ));
diff --git a/sw/source/core/unocore/unoidx.cxx b/sw/source/core/unocore/unoidx.cxx
index 7e40304..c7f3397 100644
--- a/sw/source/core/unocore/unoidx.cxx
+++ b/sw/source/core/unocore/unoidx.cxx
@@ -1340,10 +1340,6 @@ SwXDocumentIndex::attach(const uno::Reference< text::XTextRange > & xTextRange)
}
UnoActionContext aAction(pDoc);
if (aPam.HasMark())
{
pDoc->getIDocumentContentOperations().DeleteAndJoin(aPam);
}
SwTOXBase & rTOXBase = m_pImpl->m_pProps->GetTOXBase();
SwTOXType const*const pTOXType = rTOXBase.GetTOXType();
@@ -1354,7 +1350,7 @@ SwXDocumentIndex::attach(const uno::Reference< text::XTextRange > & xTextRange)
}
//TODO: apply Section attributes (columns and background)
SwTOXBaseSection *const pTOX =
pDoc->InsertTableOf( *aPam.GetPoint(), rTOXBase, nullptr, false,
pDoc->InsertTableOf( aPam, rTOXBase, nullptr, false,
m_pImpl->m_pDoc->getIDocumentLayoutAccess().GetCurrentLayout());
pDoc->SetTOXBaseName(*pTOX, m_pImpl->m_pProps->GetTOXBase().GetTOXName());
diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx
index 097195c..79717e2 100644
--- a/sw/source/filter/ww8/docxexport.cxx
+++ b/sw/source/filter/ww8/docxexport.cxx
@@ -1442,6 +1442,11 @@ void DocxExport::WriteMainText()
// setup the namespaces
m_pDocumentFS->startElementNS( XML_w, XML_document, MainXmlNamespaces());
if ( getenv("SW_DEBUG_DOM") )
{
m_pDoc->dumpAsXml();
}
// reset the incrementing linked-textboxes chain ID before re-saving.
m_nLinkedTextboxesChainId=0;
m_aLinkedTextboxesHelper.clear();
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 6e2fc62..a0d79ac 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -514,6 +514,15 @@ void DomainMapper_Impl::SetParaSectpr(bool bParaSectpr)
void DomainMapper_Impl::SetSdt(bool bSdt)
{
m_bSdt = bSdt;
if (m_bSdt)
{
m_xStdEntryStart = GetTopTextAppend()->getEnd();
}
else
{
m_xStdEntryStart = uno::Reference< text::XTextRange >();
}
}
@@ -3680,6 +3689,42 @@ static uno::Sequence< beans::PropertyValues > lcl_createTOXLevelHyperlinks( bool
return aNewLevel;
}
/// Returns title of the TOC placed in paragraph(s) before TOC field inside STD-frame
OUString DomainMapper_Impl::extractTocTitle()
{
if (!m_xStdEntryStart.is())
return OUString();
uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
if(!xTextAppend.is())
return OUString();
// try-catch was added in the same way as inside appendTextSectionAfter()
try
{
uno::Reference< text::XParagraphCursor > xCursor( xTextAppend->createTextCursorByRange( m_xStdEntryStart ), uno::UNO_QUERY_THROW);
if (!xCursor.is())
return OUString();
//the cursor has been moved to the end of the paragraph because of the appendTextPortion() calls
xCursor->gotoStartOfParagraph( false );
if (m_aTextAppendStack.top().xInsertPosition.is())
xCursor->gotoRange( m_aTextAppendStack.top().xInsertPosition, true );
else
xCursor->gotoEnd( true );
//the paragraph after this new section is already inserted
xCursor->goLeft(1, true);
return xCursor->getString();
}
catch(const uno::Exception&)
{
}
return OUString();
}
void DomainMapper_Impl::handleToc
(const FieldContextPtr& pContext,
const OUString & sTOCServiceName)
@@ -3799,16 +3844,57 @@ void DomainMapper_Impl::handleToc
if( !bFromOutline && !bFromEntries && sTemplate.isEmpty() )
bFromOutline = true;
const OUString aTocTitle = extractTocTitle();
if (m_xTextFactory.is())
xTOC.set(
m_xTextFactory->createInstance
( bTableOfFigures ?
"com.sun.star.text.IllustrationsIndex"
: sTOCServiceName),
uno::UNO_QUERY_THROW);
if (m_xTextFactory.is() && ! m_aTextAppendStack.empty())
{
if (aTocTitle.isEmpty() || bTableOfFigures)
{
xTOC.set(
m_xTextFactory->createInstance
( bTableOfFigures ?
"com.sun.star.text.IllustrationsIndex"
: sTOCServiceName),
uno::UNO_QUERY_THROW);
OUString const sMarker("Y");
//insert index
uno::Reference< text::XTextContent > xToInsert( xTOC, uno::UNO_QUERY );
uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
if (xTextAppend.is())
{
uno::Reference< text::XTextCursor > xCrsr = xTextAppend->getText()->createTextCursor();
uno::Reference< text::XText > xText = xTextAppend->getText();
if(xCrsr.is() && xText.is())
{
xCrsr->gotoEnd(false);
xText->insertString(xCrsr, sMarker, false);
xText->insertTextContent(uno::Reference< text::XTextRange >( xCrsr, uno::UNO_QUERY_THROW ), xToInsert, false);
xTOCMarkerCursor = xCrsr;
}
}
}
else
{
// create TOC section
css::uno::Reference<css::text::XTextRange> xTextRangeEndOfTocHeader = GetTopTextAppend()->getEnd();
xTOC = createSectionForRange(m_xStdEntryStart, xTextRangeEndOfTocHeader, sTOCServiceName, false);
// init [xTOCMarkerCursor]
uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
uno::Reference< text::XText > xText = xTextAppend->getText();
uno::Reference< text::XTextCursor > xCrsr = xText->createTextCursor();
xTOCMarkerCursor = xCrsr;
// create header of the TOC with the TOC title inside
const OUString aObjectType("com.sun.star.text.IndexHeaderSection");
uno::Reference<beans::XPropertySet> xIfc = createSectionForRange(m_xStdEntryStart, xTextRangeEndOfTocHeader, aObjectType, true);
}
}
if (xTOC.is())
xTOC->setPropertyValue(getPropertyName( PROP_TITLE ), uno::makeAny(OUString()));
xTOC->setPropertyValue(getPropertyName( PROP_TITLE ), uno::makeAny(aTocTitle));
if (!aBookmarkName.isEmpty())
xTOC->setPropertyValue(getPropertyName(PROP_TOC_BOOKMARK), uno::makeAny(aBookmarkName));
if( !bTableOfFigures && xTOC.is() )
@@ -3898,27 +3984,45 @@ void DomainMapper_Impl::handleToc
}
pContext->SetTOC( xTOC );
m_bParaHadField = false;
}
uno::Reference<beans::XPropertySet> DomainMapper_Impl::createSectionForRange(
uno::Reference< css::text::XTextRange > xStart,
uno::Reference< css::text::XTextRange > xEnd,
const OUString & sObjectType,
bool stepLeft)
{
if (!xStart.is())
return uno::Reference<beans::XPropertySet>();
if (!xEnd.is())
return uno::Reference<beans::XPropertySet>();
uno::Reference< beans::XPropertySet > xRet;
if (m_aTextAppendStack.empty())
return;
OUString const sMarker("Y");
//insert index
uno::Reference< text::XTextContent > xToInsert( xTOC, uno::UNO_QUERY );
return xRet;
uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
if (xTextAppend.is())
if(xTextAppend.is())
{
uno::Reference< text::XTextCursor > xCrsr = xTextAppend->getText()->createTextCursor();
uno::Reference< text::XText > xText = xTextAppend->getText();
if(xCrsr.is() && xText.is())
try
{
xCrsr->gotoEnd(false);
xText->insertString(xCrsr, sMarker, false);
xText->insertTextContent(uno::Reference< text::XTextRange >( xCrsr, uno::UNO_QUERY_THROW ), xToInsert, false);
xTOCMarkerCursor = xCrsr;
uno::Reference< text::XParagraphCursor > xCursor(
xTextAppend->createTextCursorByRange( xStart ), uno::UNO_QUERY_THROW);
//the cursor has been moved to the end of the paragraph because of the appendTextPortion() calls
xCursor->gotoStartOfParagraph( false );
xCursor->gotoRange( xEnd, true );
//the paragraph after this new section is already inserted
if (stepLeft)
xCursor->goLeft(1, true);
uno::Reference< text::XTextContent > xSection( m_xTextFactory->createInstance(sObjectType), uno::UNO_QUERY_THROW );
xSection->attach( uno::Reference< text::XTextRange >( xCursor, uno::UNO_QUERY_THROW) );
xRet.set(xSection, uno::UNO_QUERY );
}
catch(const uno::Exception&)
{
}
}
return xRet;
}
void DomainMapper_Impl::handleBibliography
@@ -5005,10 +5109,13 @@ void DomainMapper_Impl::PopFieldContext()
}
else
{
xTOCMarkerCursor->goLeft(1,true);
xTOCMarkerCursor->setString(OUString());
xTOCMarkerCursor->goLeft(1,true);
xTOCMarkerCursor->setString(OUString());
if (!m_xStdEntryStart.is())
{
xTOCMarkerCursor->goLeft(1,true);
xTOCMarkerCursor->setString(OUString());
xTOCMarkerCursor->goLeft(1,true);
xTOCMarkerCursor->setString(OUString());
}
}
}
if (m_bStartedTOC || m_bStartIndex || m_bStartBibliography)
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
index c20912d..6006d24 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
@@ -542,6 +542,7 @@ private:
SmartTagHandler m_aSmartTagHandler;
css::uno::Reference<css::text::XTextRange> m_xGlossaryEntryStart;
css::uno::Reference<css::text::XTextRange> m_xStdEntryStart;
public:
css::uno::Reference<css::text::XTextRange> m_xInsertTextRange;
@@ -795,6 +796,10 @@ public:
/// The end of field is reached (cFieldEnd appeared) - the command might still be open.
void PopFieldContext();
/// Returns title of the TOC placed in paragraph(s) before TOC field inside STD-frame
OUString extractTocTitle();
css::uno::Reference<css::beans::XPropertySet> createSectionForRange(css::uno::Reference< css::text::XTextRange > xStart, css::uno::Reference< css::text::XTextRange > xEnd, const OUString & sObjectType, bool stepLeft);
void SetBookmarkName( const OUString& rBookmarkName );
void StartOrEndBookmark( const OUString& rId );