1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <hintids.hxx>
22 #include <editeng/formatbreakitem.hxx>
23 #include <comphelper/classids.hxx>
24 #include <o3tl/string_view.hxx>
27 #include <txttxmrk.hxx>
28 #include <fmtpdsc.hxx>
30 #include <pagedesc.hxx>
32 #include <IDocumentUndoRedo.hxx>
33 #include <DocumentSettingManager.hxx>
34 #include <IDocumentRedlineAccess.hxx>
35 #include <IDocumentFieldsAccess.hxx>
36 #include <IDocumentState.hxx>
37 #include <IDocumentLayoutAccess.hxx>
38 #include <IDocumentStylePoolAccess.hxx>
39 #include <pagefrm.hxx>
41 #include <swtable.hxx>
45 #include <poolfmt.hxx>
47 #include <rootfrm.hxx>
48 #include <UndoAttribute.hxx>
49 #include <UndoSection.hxx>
53 #include <charfmt.hxx>
54 #include <fchrfmt.hxx>
60 #include <node2lay.hxx>
61 #include <SwStyleNameMapper.hxx>
62 #include <breakit.hxx>
64 #include <ToxTextGenerator.hxx>
65 #include <ToxTabStopTokenHandler.hxx>
66 #include <frameformats.hxx>
67 #include <tools/datetimeutils.hxx>
68 #include <tools/globname.hxx>
69 #include <com/sun/star/embed/XEmbeddedObject.hpp>
70 #include <o3tl/safeint.hxx>
71 #include <osl/diagnose.h>
75 using namespace ::com::sun::star
;
77 template<typename T
, typename
... Args
> static
78 typename
std::enable_if
<!std::is_array
<T
>::value
, std::unique_ptr
<T
>>::type
79 MakeSwTOXSortTabBase(SwRootFrame
const*const pLayout
, Args
&& ... args
)
81 std::unique_ptr
<T
> pRet(new T(std::forward
<Args
>(args
)...));
82 pRet
->InitText(pLayout
); // ensure it's expanded with the layout
86 void SwDoc::GetTOIKeys(SwTOIKeyType eTyp
, std::vector
<OUString
>& rArr
,
87 SwRootFrame
const& rLayout
) const
91 // Look up all Primary and Secondary via the Pool
92 for (const SfxPoolItem
* pPoolItem
: GetAttrPool().GetItemSurrogates(RES_TXTATR_TOXMARK
))
94 const SwTOXMark
* pItem
= dynamic_cast<const SwTOXMark
*>(pPoolItem
);
97 const SwTOXType
* pTOXType
= pItem
->GetTOXType();
98 if ( !pTOXType
|| pTOXType
->GetType()!=TOX_INDEX
)
100 const SwTextTOXMark
* pMark
= pItem
->GetTextTOXMark();
101 if ( pMark
&& pMark
->GetpTextNd() &&
102 pMark
->GetpTextNd()->GetNodes().IsDocNodes() &&
103 (!rLayout
.IsHideRedlines()
104 || !sw::IsMarkHintHidden(rLayout
, *pMark
->GetpTextNd(), *pMark
)))
106 const OUString sStr
= TOI_PRIMARY
== eTyp
107 ? pItem
->GetPrimaryKey()
108 : pItem
->GetSecondaryKey();
110 if( !sStr
.isEmpty() )
111 rArr
.push_back( sStr
);
116 /// Get current table of contents Mark.
117 sal_uInt16
SwDoc::GetCurTOXMark( const SwPosition
& rPos
,
120 // search on Position rPos for all SwTOXMarks
121 SwTextNode
*const pTextNd
= rPos
.GetNode().GetTextNode();
122 if( !pTextNd
|| !pTextNd
->GetpSwpHints() )
125 const SwpHints
& rHts
= *pTextNd
->GetpSwpHints();
127 const sal_Int32
*pEndIdx
;
129 const sal_Int32 nCurrentPos
= rPos
.GetContentIndex();
131 for( size_t n
= 0; n
< rHts
.Count(); ++n
)
133 const SwTextAttr
* pHt
= rHts
.Get(n
);
134 if( RES_TXTATR_TOXMARK
!= pHt
->Which() )
136 if( ( nSttIdx
= pHt
->GetStart() ) < nCurrentPos
)
138 // also check the end
139 pEndIdx
= pHt
->End();
140 if( nullptr == pEndIdx
|| *pEndIdx
<= nCurrentPos
)
141 continue; // keep searching
143 else if( nSttIdx
> nCurrentPos
)
144 // If Hint's Start is greater than rPos, break, because
145 // the attributes are sorted by Start!
148 SwTOXMark
* pTMark
= const_cast<SwTOXMark
*>(&pHt
->GetTOXMark());
149 rArr
.push_back( pTMark
);
154 /// Delete table of contents Mark
155 void SwDoc::DeleteTOXMark( const SwTOXMark
* pTOXMark
)
157 const SwTextTOXMark
* pTextTOXMark
= pTOXMark
->GetTextTOXMark();
158 assert(pTextTOXMark
);
160 SwTextNode
& rTextNd
= const_cast<SwTextNode
&>(pTextTOXMark
->GetTextNode());
161 assert(rTextNd
.GetpSwpHints());
163 if (pTextTOXMark
->HasDummyChar())
165 // tdf#106377 don't use SwUndoResetAttr, it uses NOTXTATRCHR
166 SwPaM
tmp(rTextNd
, pTextTOXMark
->GetStart(),
167 rTextNd
, pTextTOXMark
->GetStart()+1);
168 assert(rTextNd
.GetText()[pTextTOXMark
->GetStart()] == CH_TXTATR_INWORD
);
169 getIDocumentContentOperations().DeleteRange(tmp
);
173 std::unique_ptr
<SwRegHistory
> aRHst
;
174 if (GetIDocumentUndoRedo().DoesUndo())
176 // save attributes for Undo
177 SwUndoResetAttr
* pUndo
= new SwUndoResetAttr(
178 SwPosition( rTextNd
, pTextTOXMark
->GetStart() ),
179 RES_TXTATR_TOXMARK
);
180 GetIDocumentUndoRedo().AppendUndo( std::unique_ptr
<SwUndo
>(pUndo
) );
182 aRHst
.reset(new SwRegHistory(rTextNd
, &pUndo
->GetHistory()));
183 rTextNd
.GetpSwpHints()->Register(aRHst
.get());
186 rTextNd
.DeleteAttribute( const_cast<SwTextTOXMark
*>(pTextTOXMark
) );
188 if (GetIDocumentUndoRedo().DoesUndo())
190 if( rTextNd
.GetpSwpHints() )
191 rTextNd
.GetpSwpHints()->DeRegister();
195 getIDocumentState().SetModified();
200 /// Travel between table of content Marks
201 class CompareNodeContent
203 SwNodeOffset m_nNode
;
204 sal_Int32 m_nContent
;
206 CompareNodeContent( SwNodeOffset nNd
, sal_Int32 nCnt
)
207 : m_nNode( nNd
), m_nContent( nCnt
) {}
209 bool operator==( const CompareNodeContent
& rCmp
) const
210 { return m_nNode
== rCmp
.m_nNode
&& m_nContent
== rCmp
.m_nContent
; }
211 bool operator!=( const CompareNodeContent
& rCmp
) const
212 { return m_nNode
!= rCmp
.m_nNode
|| m_nContent
!= rCmp
.m_nContent
; }
213 bool operator< ( const CompareNodeContent
& rCmp
) const
214 { return m_nNode
< rCmp
.m_nNode
||
215 ( m_nNode
== rCmp
.m_nNode
&& m_nContent
< rCmp
.m_nContent
); }
216 bool operator<=( const CompareNodeContent
& rCmp
) const
217 { return m_nNode
< rCmp
.m_nNode
||
218 ( m_nNode
== rCmp
.m_nNode
&& m_nContent
<= rCmp
.m_nContent
); }
219 bool operator> ( const CompareNodeContent
& rCmp
) const
220 { return m_nNode
> rCmp
.m_nNode
||
221 ( m_nNode
== rCmp
.m_nNode
&& m_nContent
> rCmp
.m_nContent
); }
222 bool operator>=( const CompareNodeContent
& rCmp
) const
223 { return m_nNode
> rCmp
.m_nNode
||
224 ( m_nNode
== rCmp
.m_nNode
&& m_nContent
>= rCmp
.m_nContent
); }
229 const SwTOXMark
& SwDoc::GotoTOXMark( const SwTOXMark
& rCurTOXMark
,
230 SwTOXSearch eDir
, bool bInReadOnly
)
232 const SwTextTOXMark
* pMark
= rCurTOXMark
.GetTextTOXMark();
234 CompareNodeContent
aAbsIdx(pMark
? pMark
->GetpTextNd()->GetIndex() : SwNodeOffset(0), pMark
? pMark
->GetStart() : 0);
235 CompareNodeContent
aPrevPos( SwNodeOffset(0), 0 );
236 CompareNodeContent
aNextPos( NODE_OFFSET_MAX
, SAL_MAX_INT32
);
237 CompareNodeContent
aMax( SwNodeOffset(0), 0 );
238 CompareNodeContent
aMin( NODE_OFFSET_MAX
, SAL_MAX_INT32
);
240 const SwTOXMark
* pNew
= nullptr;
241 const SwTOXMark
* pMax
= &rCurTOXMark
;
242 const SwTOXMark
* pMin
= &rCurTOXMark
;
244 const SwTOXType
* pType
= rCurTOXMark
.GetTOXType();
246 pType
->CollectTextMarks(aMarks
);
248 for(SwTOXMark
* pTOXMark
: aMarks
)
250 if ( pTOXMark
== &rCurTOXMark
)
253 pMark
= pTOXMark
->GetTextTOXMark();
257 SwTextNode
const*const pTOXSrc
= pMark
->GetpTextNd();
262 std::pair
<Point
, bool> const tmp(aPt
, false);
263 const SwContentFrame
* pCFrame
= pTOXSrc
->getLayoutFrame(
264 getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, &tmp
);
268 if ( bInReadOnly
|| !pCFrame
->IsProtected() )
270 CompareNodeContent
aAbsNew( pTOXSrc
->GetIndex(), pMark
->GetStart() );
273 // The following (a bit more complicated) statements make it
274 // possible to also travel across Entries on the same (!)
275 // position. If someone has time, please feel free to optimize.
277 if (pTOXMark
->GetText(nullptr) != rCurTOXMark
.GetText(nullptr))
281 if ( (aAbsNew
< aAbsIdx
&& aAbsNew
> aPrevPos
) ||
282 (aAbsIdx
== aAbsNew
&&
283 (reinterpret_cast<sal_uLong
>(&rCurTOXMark
) > reinterpret_cast<sal_uLong
>(pTOXMark
) &&
284 (!pNew
|| aPrevPos
< aAbsIdx
|| reinterpret_cast<sal_uLong
>(pNew
) < reinterpret_cast<sal_uLong
>(pTOXMark
) ) )) ||
285 (aPrevPos
== aAbsNew
&& aAbsIdx
!= aAbsNew
&&
286 reinterpret_cast<sal_uLong
>(pTOXMark
) > reinterpret_cast<sal_uLong
>(pNew
)) )
290 if ( aAbsNew
>= aMax
)
299 if (pTOXMark
->GetText(nullptr) != rCurTOXMark
.GetText(nullptr))
303 if ( (aAbsNew
> aAbsIdx
&& aAbsNew
< aNextPos
) ||
304 (aAbsIdx
== aAbsNew
&&
305 (reinterpret_cast<sal_uLong
>(&rCurTOXMark
) < reinterpret_cast<sal_uLong
>(pTOXMark
) &&
306 (!pNew
|| aNextPos
> aAbsIdx
|| reinterpret_cast<sal_uLong
>(pNew
) > reinterpret_cast<sal_uLong
>(pTOXMark
)) )) ||
307 (aNextPos
== aAbsNew
&& aAbsIdx
!= aAbsNew
&&
308 reinterpret_cast<sal_uLong
>(pTOXMark
) < reinterpret_cast<sal_uLong
>(pNew
)) )
312 if ( aAbsNew
<= aMin
)
323 // We couldn't find a successor
324 // Use minimum or maximum
344 SwTOXBaseSection
* SwDoc::InsertTableOf( const SwPosition
& rPos
,
345 const SwTOXBase
& rTOX
,
346 const SfxItemSet
* pSet
,
348 SwRootFrame
const*const pLayout
)
351 return InsertTableOf( aPam
, rTOX
, pSet
, bExpand
, pLayout
);
354 SwTOXBaseSection
* SwDoc::InsertTableOf( const SwPaM
& aPam
,
355 const SwTOXBase
& rTOX
,
356 const SfxItemSet
* pSet
,
358 SwRootFrame
const*const pLayout
)
360 assert(!bExpand
|| pLayout
!= nullptr);
361 GetIDocumentUndoRedo().StartUndo( SwUndoId::INSTOX
, nullptr );
363 OUString sSectNm
= GetUniqueTOXBaseName( *rTOX
.GetTOXType(), rTOX
.GetTOXName() );
364 SwSectionData
aSectionData( SectionType::ToxContent
, sSectNm
);
366 std::tuple
<SwTOXBase
const*, sw::RedlineMode
, sw::FieldmarkMode
, sw::ParagraphBreakMode
> const tmp(
368 pLayout
&& pLayout
->IsHideRedlines()
369 ? sw::RedlineMode::Hidden
370 : sw::RedlineMode::Shown
,
371 pLayout
? pLayout
->GetFieldmarkMode() : sw::FieldmarkMode::ShowBoth
,
372 pLayout
? pLayout
->GetParagraphBreakMode() : sw::ParagraphBreakMode::Shown
);
373 SwTOXBaseSection
*const pNewSection
= dynamic_cast<SwTOXBaseSection
*>(
374 InsertSwSection(aPam
, aSectionData
, & tmp
, pSet
, false));
377 SwSectionNode
*const pSectNd
= pNewSection
->GetFormat()->GetSectionNode();
378 pNewSection
->SetTOXName(sSectNm
); // rTOX may have had no name...
382 // add value for 2nd parameter = true to
383 // indicate, that a creation of a new table of content has to be performed.
384 // Value of 1st parameter = default value.
385 pNewSection
->Update( nullptr, pLayout
, true );
387 else if( rTOX
.GetTitle().getLength()==1 && IsInReading() )
388 // insert title of TOX
390 // then insert the headline section
391 SwNodeIndex
aIdx( *pSectNd
, +1 );
393 SwTextNode
* pHeadNd
= GetNodes().MakeTextNode( aIdx
.GetNode(),
394 getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_STANDARD
) );
396 SwSectionData
headerData( SectionType::ToxHeader
, pNewSection
->GetTOXName()+"_Head" );
399 SwSectionFormat
* pSectFormat
= MakeSectionFormat();
400 GetNodes().InsertTextSection(
401 *pHeadNd
, *pSectFormat
, headerData
, nullptr, &aIdx
.GetNode(), true, false);
405 GetIDocumentUndoRedo().EndUndo( SwUndoId::INSTOX
, nullptr );
410 void SwDoc::InsertTableOf( SwNodeOffset nSttNd
, SwNodeOffset nEndNd
,
411 const SwTOXBase
& rTOX
,
412 const SfxItemSet
* pSet
)
414 // check for recursive TOX
415 SwNode
* pNd
= GetNodes()[ nSttNd
];
416 SwSectionNode
* pSectNd
= pNd
->FindSectionNode();
419 SectionType eT
= pSectNd
->GetSection().GetType();
420 if( SectionType::ToxHeader
== eT
|| SectionType::ToxContent
== eT
)
422 pSectNd
= pSectNd
->StartOfSectionNode()->FindSectionNode();
425 const OUString sSectNm
= GetUniqueTOXBaseName(*rTOX
.GetTOXType(), rTOX
.GetTOXName());
427 SwSectionData
aSectionData( SectionType::ToxContent
, sSectNm
);
429 SwNodeIndex
aStt( GetNodes(), nSttNd
), aEnd( GetNodes(), nEndNd
);
430 SwSectionFormat
* pFormat
= MakeSectionFormat();
432 pFormat
->SetFormatAttr(*pSet
);
434 SwSectionNode
*const pNewSectionNode
=
435 GetNodes().InsertTextSection(aStt
.GetNode(), *pFormat
, aSectionData
, &rTOX
, &aEnd
.GetNode());
436 if (!pNewSectionNode
)
438 DelSectionFormat( pFormat
);
442 SwTOXBaseSection
*const pNewSection(
443 dynamic_cast<SwTOXBaseSection
*>(& pNewSectionNode
->GetSection()));
445 pNewSection
->SetTOXName(sSectNm
); // rTOX may have had no name...
448 /// Get current table of contents
449 SwTOXBase
* SwDoc::GetCurTOX( const SwPosition
& rPos
)
451 SwNode
& rNd
= rPos
.GetNode();
452 SwSectionNode
* pSectNd
= rNd
.FindSectionNode();
455 SectionType eT
= pSectNd
->GetSection().GetType();
456 if( SectionType::ToxContent
== eT
)
458 assert( dynamic_cast< const SwTOXBaseSection
*>( &pSectNd
->GetSection()) &&
459 "no TOXBaseSection!" );
460 SwTOXBaseSection
& rTOXSect
= static_cast<SwTOXBaseSection
&>(
461 pSectNd
->GetSection());
464 pSectNd
= pSectNd
->StartOfSectionNode()->FindSectionNode();
469 const SwAttrSet
& SwDoc::GetTOXBaseAttrSet(const SwTOXBase
& rTOXBase
)
471 assert( dynamic_cast<const SwTOXBaseSection
*>( &rTOXBase
) && "no TOXBaseSection!" );
472 const SwTOXBaseSection
& rTOXSect
= static_cast<const SwTOXBaseSection
&>(rTOXBase
);
473 SwSectionFormat
const * pFormat
= rTOXSect
.GetFormat();
474 OSL_ENSURE( pFormat
, "invalid TOXBaseSection!" );
475 return pFormat
->GetAttrSet();
478 const SwTOXBase
* SwDoc::GetDefaultTOXBase( TOXTypes eTyp
, bool bCreate
)
480 std::unique_ptr
<SwTOXBase
>* prBase
= nullptr;
483 case TOX_CONTENT
: prBase
= &mpDefTOXBases
->pContBase
; break;
484 case TOX_INDEX
: prBase
= &mpDefTOXBases
->pIdxBase
; break;
485 case TOX_USER
: prBase
= &mpDefTOXBases
->pUserBase
; break;
486 case TOX_TABLES
: prBase
= &mpDefTOXBases
->pTableBase
; break;
487 case TOX_OBJECTS
: prBase
= &mpDefTOXBases
->pObjBase
; break;
488 case TOX_ILLUSTRATIONS
: prBase
= &mpDefTOXBases
->pIllBase
; break;
489 case TOX_AUTHORITIES
: prBase
= &mpDefTOXBases
->pAuthBase
; break;
490 case TOX_BIBLIOGRAPHY
: prBase
= &mpDefTOXBases
->pBiblioBase
; break;
491 case TOX_CITATION
: /** TODO */break;
495 if(!(*prBase
) && bCreate
)
498 const SwTOXType
* pType
= GetTOXType(eTyp
, 0);
499 prBase
->reset(new SwTOXBase(pType
, aForm
, SwTOXElement::NONE
, pType
->GetTypeName()));
501 return prBase
->get();
504 void SwDoc::SetDefaultTOXBase(const SwTOXBase
& rBase
)
506 std::unique_ptr
<SwTOXBase
>* prBase
= nullptr;
507 switch(rBase
.GetType())
509 case TOX_CONTENT
: prBase
= &mpDefTOXBases
->pContBase
; break;
510 case TOX_INDEX
: prBase
= &mpDefTOXBases
->pIdxBase
; break;
511 case TOX_USER
: prBase
= &mpDefTOXBases
->pUserBase
; break;
512 case TOX_TABLES
: prBase
= &mpDefTOXBases
->pTableBase
; break;
513 case TOX_OBJECTS
: prBase
= &mpDefTOXBases
->pObjBase
; break;
514 case TOX_ILLUSTRATIONS
: prBase
= &mpDefTOXBases
->pIllBase
; break;
515 case TOX_AUTHORITIES
: prBase
= &mpDefTOXBases
->pAuthBase
; break;
516 case TOX_BIBLIOGRAPHY
: prBase
= &mpDefTOXBases
->pBiblioBase
; break;
517 case TOX_CITATION
: /** TODO */break;
521 prBase
->reset(new SwTOXBase(rBase
));
524 /// Delete table of contents
525 bool SwDoc::DeleteTOX( const SwTOXBase
& rTOXBase
, bool bDelNodes
)
527 // We only delete the TOX, not the Nodes
529 assert( dynamic_cast<const SwTOXBaseSection
*>( &rTOXBase
) && "no TOXBaseSection!" );
531 const SwTOXBaseSection
& rTOXSect
= static_cast<const SwTOXBaseSection
&>(rTOXBase
);
532 SwSectionFormat
const * pFormat
= rTOXSect
.GetFormat();
533 /* Save the start node of the TOX' section. */
534 SwSectionNode
const * pMyNode
= pFormat
? pFormat
->GetSectionNode() : nullptr;
537 GetIDocumentUndoRedo().StartUndo( SwUndoId::CLEARTOXRANGE
, nullptr );
539 /* Save start node of section's surrounding. */
540 SwNode
const * pStartNd
= pMyNode
->StartOfSectionNode();
542 /* Look for the point where to move the cursors in the area to
543 delete to. This is done by first searching forward from the
544 end of the TOX' section. If no content node is found behind
545 the TOX one is searched before it. If this is not
546 successful, too, insert new text node behind the end of
547 the TOX' section. The cursors from the TOX' section will be
548 moved to the content node found or the new text node. */
550 /* Set PaM to end of TOX' section and search following content node.
551 aSearchPam will contain the point where to move the cursors
553 SwPaM
aSearchPam(*pMyNode
->EndOfSectionNode());
554 SwPosition
aEndPos(*pStartNd
->EndOfSectionNode());
555 if (! aSearchPam
.Move() /* no content node found */
556 || *aSearchPam
.GetPoint() >= aEndPos
/* content node found
557 outside surrounding */
560 /* Set PaM to beginning of TOX' section and search previous
562 SwPaM
aTmpPam(*pMyNode
);
563 aSearchPam
= aTmpPam
;
564 SwPosition
aStartPos(*pStartNd
);
566 if ( ! aSearchPam
.Move(fnMoveBackward
) /* no content node found */
567 || *aSearchPam
.GetPoint() <= aStartPos
/* content node
572 /* There is no content node in the surrounding of
573 TOX'. Append text node behind TOX' section. */
575 SwPosition
aInsPos(*pMyNode
->EndOfSectionNode());
576 getIDocumentContentOperations().AppendTextNode(aInsPos
);
578 SwPaM
aTmpPam1(aInsPos
);
579 aSearchPam
= aTmpPam1
;
583 /* PaM containing the TOX. */
584 SwPaM
aPam(*pMyNode
->EndOfSectionNode(), *pMyNode
);
586 /* Move cursors contained in TOX to the above calculated point. */
587 PaMCorrAbs(aPam
, *aSearchPam
.GetPoint());
591 SwSections
aArr( 0 );
592 pFormat
->GetChildSections( aArr
, SectionSort::Not
, false );
593 for( const auto pSect
: aArr
)
595 if( SectionType::ToxHeader
== pSect
->GetType() )
597 DelSectionFormat( pSect
->GetFormat(), bDelNodes
);
602 DelSectionFormat( const_cast<SwSectionFormat
*>(pFormat
), bDelNodes
);
604 GetIDocumentUndoRedo().EndUndo( SwUndoId::CLEARTOXRANGE
, nullptr );
611 /// Manage table of content types
612 sal_uInt16
SwDoc::GetTOXTypeCount(TOXTypes eTyp
) const
615 for( auto const & pTOXType
: *mpTOXTypes
)
616 if( eTyp
== pTOXType
->GetType() )
621 const SwTOXType
* SwDoc::GetTOXType( TOXTypes eTyp
, sal_uInt16 nId
) const
624 for( auto const & pTOXType
: *mpTOXTypes
)
625 if( eTyp
== pTOXType
->GetType() && nCnt
++ == nId
)
626 return pTOXType
.get();
630 const SwTOXType
* SwDoc::InsertTOXType( const SwTOXType
& rTyp
)
632 SwTOXType
* pNew
= new SwTOXType(rTyp
);
633 mpTOXTypes
->emplace_back( pNew
);
637 OUString
SwDoc::GetUniqueTOXBaseName( const SwTOXType
& rType
,
638 const OUString
& sChkStr
) const
642 OUString newName
= "MailMergeTOX"
643 + OStringToOUString( DateTimeToOString( DateTime( DateTime::SYSTEM
)), RTL_TEXTENCODING_ASCII_US
)
644 + OUString::number( mpSectionFormatTable
->size() + 1 );
645 if( !sChkStr
.isEmpty())
650 bool bUseChkStr
= !sChkStr
.isEmpty();
651 const OUString
& aName( rType
.GetTypeName() );
652 const sal_Int32 nNmLen
= aName
.getLength();
654 SwSectionFormats::size_type nNum
= 0;
655 const SwSectionFormats::size_type nFlagSize
= ( mpSectionFormatTable
->size() / 8 ) +2;
656 std::unique_ptr
<sal_uInt8
[]> pSetFlags(new sal_uInt8
[ nFlagSize
]);
657 memset( pSetFlags
.get(), 0, nFlagSize
);
659 for( auto pSectionFormat
: *mpSectionFormatTable
)
661 const SwSectionNode
*pSectNd
= pSectionFormat
->GetSectionNode();
665 const SwSection
& rSect
= pSectNd
->GetSection();
666 if (rSect
.GetType()==SectionType::ToxContent
)
668 const OUString
& rNm
= rSect
.GetSectionName();
669 if ( rNm
.startsWith(aName
) )
671 // Calculate number and set the Flag
672 nNum
= o3tl::toInt32(rNm
.subView( nNmLen
));
673 if( nNum
-- && nNum
< mpSectionFormatTable
->size() )
674 pSetFlags
[ nNum
/ 8 ] |= (0x01 << ( nNum
& 0x07 ));
676 if ( bUseChkStr
&& sChkStr
==rNm
)
683 // All Numbers have been flagged accordingly, so get the right Number
684 nNum
= mpSectionFormatTable
->size();
685 for( SwSectionFormats::size_type n
= 0; n
< nFlagSize
; ++n
)
687 sal_uInt8 nTmp
= pSetFlags
[ n
];
703 return aName
+ OUString::number( ++nNum
);
706 bool SwDoc::SetTOXBaseName(const SwTOXBase
& rTOXBase
, const OUString
& rName
)
708 assert( dynamic_cast<const SwTOXBaseSection
*>( &rTOXBase
) && "no TOXBaseSection!" );
709 SwTOXBaseSection
* pTOX
= const_cast<SwTOXBaseSection
*>(static_cast<const SwTOXBaseSection
*>(&rTOXBase
));
711 if (GetUniqueTOXBaseName(*rTOXBase
.GetTOXType(), rName
) == rName
)
713 pTOX
->SetTOXName(rName
);
714 pTOX
->SetSectionName(rName
);
715 getIDocumentState().SetModified();
721 static const SwTextNode
* lcl_FindChapterNode( const SwNode
& rNd
,
722 SwRootFrame
const*const pLayout
, sal_uInt8
const nLvl
= 0 )
724 const SwNode
* pNd
= &rNd
;
725 if( pNd
->GetNodes().GetEndOfExtras().GetIndex() > pNd
->GetIndex() )
727 // then find the "Anchor" (Body) position
729 SwNode2Layout
aNode2Layout( *pNd
, pNd
->GetIndex() );
730 const SwFrame
* pFrame
= aNode2Layout
.GetFrame( &aPt
);
734 SwPosition
aPos( *pNd
);
735 pNd
= GetBodyTextNode( pNd
->GetDoc(), aPos
, *pFrame
);
736 OSL_ENSURE( pNd
, "Where's the paragraph?" );
737 // tdf#151462 - search for outline node containing the current node
738 return pNd
? pNd
->FindOutlineNodeOfLevel(pNd
->GetSectionLevel() - 1, pLayout
) : nullptr;
741 return pNd
->FindOutlineNodeOfLevel(nLvl
, pLayout
);
744 static bool IsHeadingContained(const SwTextNode
* pChptrNd
, const SwNode
& rNd
)
746 const SwNode
* pNd
= &rNd
;
747 const SwOutlineNodes
& rONds
= pNd
->GetNodes().GetOutLineNds();
748 bool bIsHeadingContained
= false;
751 bool bCheckFirst
= false;
752 SwOutlineNodes::size_type nPos
;
754 if (!rONds
.Seek_Entry(const_cast<SwNode
*>(pNd
), &nPos
))
764 const SwContentNode
* pCNd
= pNd
->GetContentNode();
767 std::pair
<Point
, bool> const tmp(aPt
, false);
769 const SwFrame
* pChptrFrame
= pChptrNd
? pChptrNd
->getLayoutFrame(
770 pChptrNd
->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, &tmp
) : nullptr;
771 const SwPageFrame
* pChptrPgFrame
= pChptrFrame
? pChptrFrame
->FindPageFrame() : nullptr;
772 const SwFrame
* pNdFrame
773 = pCNd
? pCNd
->getLayoutFrame(
774 pCNd
->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, &tmp
)
777 // Check if the one asking doesn't precede the page of the specified chapter note
779 = pNdFrame
&& pChptrPgFrame
780 && pChptrPgFrame
->getFrameArea().Top() <= pNdFrame
->getFrameArea().Top();
781 // Check if the one asking doesn't succeed the specified chapter note
782 if (bIsHeadingContained
)
784 const SwNode
* aChptrNd
= pChptrNd
;
785 if (!rONds
.Seek_Entry(const_cast<SwNode
*>(aChptrNd
), &nPos
) && nPos
)
787 // Search for the next outline node with a larger level than the specified chapter node
788 while (nPos
< rONds
.size() - 1
789 && pChptrNd
->GetAttrOutlineLevel()
790 < rONds
[nPos
+ 1]->GetTextNode()->GetAttrOutlineLevel())
792 // If there exists such an outline node, check if the one asking doesn't succeed
793 // the specified chapter node
794 if (nPos
< rONds
.size() - 1) {
796 const auto aONdsTxtNd
= rONds
[nPos
]->GetTextNode();
797 pChptrFrame
= aONdsTxtNd
->getLayoutFrame(
798 aONdsTxtNd
->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr,
800 pChptrPgFrame
= pChptrFrame
? pChptrFrame
->FindPageFrame() : nullptr;
802 = pNdFrame
&& pChptrPgFrame
803 && pChptrPgFrame
->getFrameArea().Top() >= pNdFrame
->getFrameArea().Top();
809 // Search for the next outline node which lies not within the current chapter node
811 && pChptrNd
->GetAttrOutlineLevel()
812 < rONds
[nPos
]->GetTextNode()->GetAttrOutlineLevel())
814 bIsHeadingContained
= pChptrNd
== rONds
[nPos
]->GetTextNode();
819 // If there are no outline nodes, consider the heading contained,
820 // otherwise the _XDocumentIndex._update() test fails
821 bIsHeadingContained
= true;
823 return bIsHeadingContained
;
826 // Table of contents class
827 SwTOXBaseSection::SwTOXBaseSection(SwTOXBase
const& rBase
, SwSectionFormat
& rFormat
)
829 , SwSection( SectionType::ToxContent
, OUString(), rFormat
)
831 SetProtect( rBase
.IsProtected() );
832 SetSectionName( GetTOXName() );
835 SwTOXBaseSection::~SwTOXBaseSection()
839 bool SwTOXBaseSection::SetPosAtStartEnd( SwPosition
& rPos
) const
842 const SwSectionNode
* pSectNd
= GetFormat()->GetSectionNode();
845 rPos
.Assign(*pSectNd
);
846 pSectNd
->GetDoc().GetNodes().GoNext( &rPos
);
852 /// Collect table of contents content
853 void SwTOXBaseSection::Update(const SfxItemSet
* pAttr
,
854 SwRootFrame
const*const pLayout
,
859 SwSectionNode
const*const pSectNd(GetFormat()->GetSectionNode());
860 if (nullptr == pSectNd
||
861 !pSectNd
->GetNodes().IsDocNodes() ||
863 (pLayout
->HasMergedParas() && pSectNd
->GetRedlineMergeFlag() == SwNode::Merge::Hidden
))
868 if ( !mbKeepExpression
)
870 maMSTOCExpression
.clear();
873 SwDoc
& rDoc
= const_cast<SwDoc
&>(pSectNd
->GetDoc());
875 if (pAttr
&& GetFormat())
876 rDoc
.ChgFormat(*GetFormat(), *pAttr
);
878 // determine default page description, which will be used by the content nodes,
879 // if no appropriate one is found.
880 const SwPageDesc
* pDefaultPageDesc
;
883 pSectNd
->GetSection().GetFormat()->GetPageDesc().GetPageDesc();
884 if ( !_bNewTOX
&& !pDefaultPageDesc
)
886 // determine page description of table-of-content
887 SwNodeOffset nPgDescNdIdx
= pSectNd
->GetIndex() + 1;
888 SwNodeOffset
* pPgDescNdIdx
= &nPgDescNdIdx
;
889 pDefaultPageDesc
= pSectNd
->FindPageDesc( pPgDescNdIdx
);
890 if ( nPgDescNdIdx
< pSectNd
->GetIndex() )
892 pDefaultPageDesc
= nullptr;
895 // consider end node of content section in the node array.
896 if ( !pDefaultPageDesc
&&
897 ( pSectNd
->EndOfSectionNode()->GetIndex() <
898 (pSectNd
->GetNodes().GetEndOfContent().GetIndex() - 1) )
901 // determine page description of content after table-of-content
902 SwNodeIndex
aIdx( *(pSectNd
->EndOfSectionNode()) );
903 const SwContentNode
* pNdAfterTOX
= pSectNd
->GetNodes().GoNext( &aIdx
);
904 const SwAttrSet
& aNdAttrSet
= pNdAfterTOX
->GetSwAttrSet();
905 const SvxBreak eBreak
= aNdAttrSet
.GetBreak().GetBreak();
906 if ( eBreak
!= SvxBreak::PageBefore
&& eBreak
!= SvxBreak::PageBoth
)
908 pDefaultPageDesc
= pNdAfterTOX
->FindPageDesc();
911 // consider start node of content section in the node array.
912 if ( !pDefaultPageDesc
&&
913 ( pSectNd
->GetIndex() >
914 (pSectNd
->GetNodes().GetEndOfContent().StartOfSectionIndex() + 1) )
917 // determine page description of content before table-of-content
918 SwNodeIndex
aIdx( *pSectNd
);
919 SwContentNode
* pTmp
= SwNodes::GoPrevious( &aIdx
);
920 assert(pTmp
); // make coverity happy
921 pDefaultPageDesc
= pTmp
->FindPageDesc();
924 if ( !pDefaultPageDesc
)
926 // determine default page description
927 pDefaultPageDesc
= &rDoc
.GetPageDesc( 0 );
931 rDoc
.getIDocumentState().SetModified();
933 // get current Language
934 SwTOXInternational
aIntl( GetLanguage(),
935 TOX_INDEX
== GetTOXType()->GetType() ?
936 GetOptions() : SwTOIOptions::NONE
,
937 GetSortAlgorithm() );
941 // find the first layout node for this TOX, if it only find the content
942 // in his own chapter
943 const SwSectionNode
* pChapterSectNd
= IsFromChapter() ? pSectNd
->FindSectionNode() : nullptr;
944 const SwTextNode
* pOwnChapterNode
= pChapterSectNd
945 ? ::lcl_FindChapterNode( *pSectNd
, pLayout
, pChapterSectNd
->GetSectionLevel() + 1 )
948 SwNode2LayoutSaveUpperFrames
aN2L(*pSectNd
);
949 const_cast<SwSectionNode
*>(pSectNd
)->DelFrames();
951 // This would be a good time to update the Numbering
952 rDoc
.UpdateNumRule();
954 if( GetCreateType() & SwTOXElement::Mark
)
955 UpdateMarks( aIntl
, pOwnChapterNode
, pLayout
);
957 if( GetCreateType() & SwTOXElement::OutlineLevel
)
958 UpdateOutline( pOwnChapterNode
, pLayout
);
960 if( GetCreateType() & SwTOXElement::Template
)
961 UpdateTemplate( pOwnChapterNode
, pLayout
);
963 if( GetCreateType() & SwTOXElement::Ole
||
964 TOX_OBJECTS
== SwTOXBase::GetType())
965 UpdateContent( SwTOXElement::Ole
, pOwnChapterNode
, pLayout
);
967 if( GetCreateType() & SwTOXElement::Table
||
968 (TOX_TABLES
== SwTOXBase::GetType() && IsFromObjectNames()) )
969 UpdateTable( pOwnChapterNode
, pLayout
);
971 if( GetCreateType() & SwTOXElement::Graphic
||
972 (TOX_ILLUSTRATIONS
== SwTOXBase::GetType() && IsFromObjectNames()))
973 UpdateContent( SwTOXElement::Graphic
, pOwnChapterNode
, pLayout
);
975 if( !GetSequenceName().isEmpty() && !IsFromObjectNames() &&
976 (TOX_TABLES
== SwTOXBase::GetType() ||
977 TOX_ILLUSTRATIONS
== SwTOXBase::GetType() ) )
978 UpdateSequence( pOwnChapterNode
, pLayout
);
980 if( GetCreateType() & SwTOXElement::Frame
)
981 UpdateContent( SwTOXElement::Frame
, pOwnChapterNode
, pLayout
);
983 if(TOX_AUTHORITIES
== SwTOXBase::GetType())
984 UpdateAuthorities( aIntl
, pLayout
);
986 // Insert AlphaDelimiters if needed (just for keywords)
987 if( TOX_INDEX
== SwTOXBase::GetType() &&
988 ( GetOptions() & SwTOIOptions::AlphaDelimiter
) )
989 InsertAlphaDelimiter( aIntl
);
991 // remove old content an insert one empty textnode (to hold the layout!)
992 SwTextNode
* pFirstEmptyNd
;
994 SwUndoUpdateIndex
* pUndo(nullptr);
996 rDoc
.getIDocumentRedlineAccess().DeleteRedline( *pSectNd
, true, RedlineType::Any
);
998 SwNodeIndex
aSttIdx( *pSectNd
, +1 );
999 SwNodeIndex
aEndIdx( *pSectNd
->EndOfSectionNode() );
1000 pFirstEmptyNd
= rDoc
.GetNodes().MakeTextNode( aEndIdx
.GetNode(),
1001 rDoc
.getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TEXT
) );
1004 // Task 70995 - save and restore PageDesc and Break Attributes
1005 SwNodeIndex
aNxtIdx( aSttIdx
);
1006 const SwContentNode
* pCNd
= aNxtIdx
.GetNode().GetContentNode();
1008 pCNd
= rDoc
.GetNodes().GoNext( &aNxtIdx
);
1009 assert(pCNd
!= pFirstEmptyNd
);
1010 assert(pCNd
->GetIndex() < pFirstEmptyNd
->GetIndex());
1011 if( pCNd
->HasSwAttrSet() )
1013 SfxItemSet
aBrkSet( rDoc
.GetAttrPool(), aBreakSetRange
);
1014 aBrkSet
.Put( *pCNd
->GetpSwAttrSet() );
1015 if( aBrkSet
.Count() )
1016 pFirstEmptyNd
->SetAttr( aBrkSet
);
1020 if (rDoc
.GetIDocumentUndoRedo().DoesUndo())
1022 // note: this will first append a SwUndoDelSection from the ctor...
1023 pUndo
= new SwUndoUpdateIndex(*this);
1024 // tdf#123313 insert Undo *after* all CrossRefBookmark Undos have
1025 // been inserted by the Update*() functions
1026 rDoc
.GetIDocumentUndoRedo().AppendUndo(std::unique_ptr
<SwUndoUpdateIndex
>(pUndo
));
1031 SwPosition
aPos( aEndIdx
, pFirstEmptyNd
, 0 );
1032 SwDoc::CorrAbs( aSttIdx
, aEndIdx
, aPos
, true );
1034 // delete flys in whole range including start node which requires
1035 // giving the node before start node as Mark parameter, hence -1.
1036 // (flys must be deleted because the anchor nodes are removed)
1037 DelFlyInRange( SwNodeIndex(aSttIdx
, -1).GetNode(), aEndIdx
.GetNode() );
1039 rDoc
.GetNodes().Delete( aSttIdx
, aEndIdx
.GetIndex() - aSttIdx
.GetIndex() );
1043 // insert title of TOX
1044 if ( !GetTitle().isEmpty() )
1046 // then insert the headline section
1047 SwNodeIndex
aIdx( *pSectNd
, +1 );
1049 SwTextNode
* pHeadNd
= rDoc
.GetNodes().MakeTextNode( aIdx
.GetNode(),
1050 GetTextFormatColl( FORM_TITLE
) );
1051 pHeadNd
->InsertText( GetTitle(), SwContentIndex( pHeadNd
) );
1053 SwSectionData
headerData( SectionType::ToxHeader
, GetTOXName()+"_Head" );
1056 SwSectionFormat
* pSectFormat
= rDoc
.MakeSectionFormat();
1057 rDoc
.GetNodes().InsertTextSection(
1058 *pHeadNd
, *pSectFormat
, headerData
, nullptr, &aIdx
.GetNode(), true, false);
1062 pUndo
->TitleSectionInserted(*pSectFormat
);
1066 // Sort the List of all TOC Marks and TOC Sections
1067 std::vector
<SwTextFormatColl
*> aCollArr( GetTOXForm().GetFormMax(), nullptr );
1068 std::unordered_map
<OUString
, int> markURLs
;
1069 SwNodeIndex
aInsPos( *pFirstEmptyNd
, 1 );
1070 for( size_t nCnt
= 0; nCnt
< m_aSortArr
.size(); ++nCnt
)
1072 ::SetProgressState( 0, rDoc
.GetDocShell() );
1074 // Put the Text into the TOC
1075 sal_uInt16 nLvl
= m_aSortArr
[ nCnt
]->GetLevel();
1076 SwTextFormatColl
* pColl
= aCollArr
[ nLvl
];
1079 pColl
= GetTextFormatColl( nLvl
);
1080 aCollArr
[ nLvl
] = pColl
;
1083 // Generate: Set dynamic TabStops
1084 SwTextNode
* pTOXNd
= rDoc
.GetNodes().MakeTextNode( aInsPos
.GetNode() , pColl
);
1085 m_aSortArr
[ nCnt
]->pTOXNd
= pTOXNd
;
1087 // Generate: Evaluate Form and insert the place holder for the
1088 // page number. If it is a TOX_INDEX and the SwForm IsCommaSeparated()
1089 // then a range of entries must be generated into one paragraph
1091 if(TOX_INDEX
== SwTOXBase::GetType() &&
1092 GetTOXForm().IsCommaSeparated() &&
1093 m_aSortArr
[nCnt
]->GetType() == TOX_SORT_INDEX
)
1095 const SwTOXMark
& rMark
= m_aSortArr
[nCnt
]->pTextMark
->GetTOXMark();
1096 const OUString
& sPrimKey
= rMark
.GetPrimaryKey();
1097 const OUString
& sSecKey
= rMark
.GetSecondaryKey();
1098 const SwTOXMark
* pNextMark
= nullptr;
1099 while(m_aSortArr
.size() > (nCnt
+ nRange
) &&
1100 m_aSortArr
[nCnt
+ nRange
]->GetType() == TOX_SORT_INDEX
)
1102 pNextMark
= &(m_aSortArr
[nCnt
+ nRange
]->pTextMark
->GetTOXMark());
1104 pNextMark
->GetPrimaryKey() != sPrimKey
||
1105 pNextMark
->GetSecondaryKey() != sSecKey
)
1110 // pass node index of table-of-content section and default page description
1111 // to method <GenerateText(..)>.
1112 ::SetProgressState( 0, rDoc
.GetDocShell() );
1114 std::shared_ptr
<sw::ToxTabStopTokenHandler
> tabStopTokenHandler
=
1115 std::make_shared
<sw::DefaultToxTabStopTokenHandler
>(
1116 pSectNd
->GetIndex(), *pDefaultPageDesc
, GetTOXForm().IsRelTabPos(),
1117 rDoc
.GetDocumentSettingManager().get(DocumentSettingId::TABS_RELATIVE_TO_INDENT
) ?
1118 sw::DefaultToxTabStopTokenHandler::TABSTOPS_RELATIVE_TO_INDENT
:
1119 sw::DefaultToxTabStopTokenHandler::TABSTOPS_RELATIVE_TO_PAGE
);
1120 sw::ToxTextGenerator
ttgn(GetTOXForm(), tabStopTokenHandler
);
1121 ttgn
.GenerateText(GetFormat()->GetDoc(), markURLs
, m_aSortArr
, nCnt
, nRange
, pLayout
);
1125 // delete the first dummy node and remove all Cursor into the previous node
1126 aInsPos
= *pFirstEmptyNd
;
1128 SwPaM
aCorPam( *pFirstEmptyNd
);
1129 if( !aCorPam
.Move( fnMoveForward
) )
1130 aCorPam
.Move( fnMoveBackward
);
1131 SwNodeIndex
aEndIdx( aInsPos
, 1 );
1132 SwDoc::CorrAbs( aInsPos
, aEndIdx
, *aCorPam
.GetPoint(), true );
1134 // Task 70995 - save and restore PageDesc and Break Attributes
1135 if( pFirstEmptyNd
->HasSwAttrSet() )
1137 if( !GetTitle().isEmpty() )
1140 aEndIdx
= *pFirstEmptyNd
;
1141 SwContentNode
* pCNd
= rDoc
.GetNodes().GoNext( &aEndIdx
);
1142 if( pCNd
) // Robust against defect documents, e.g. i60336
1143 pCNd
->SetAttr( *pFirstEmptyNd
->GetpSwAttrSet() );
1147 // now create the new Frames
1148 SwNodeOffset nIdx
= pSectNd
->GetIndex();
1149 // don't delete if index is empty
1150 if(nIdx
+ SwNodeOffset(2) < pSectNd
->EndOfSectionIndex())
1151 rDoc
.GetNodes().Delete( aInsPos
);
1153 aN2L
.RestoreUpperFrames( rDoc
.GetNodes(), nIdx
, nIdx
+ 1 );
1154 o3tl::sorted_vector
<SwRootFrame
*> aAllLayouts
= rDoc
.GetAllLayouts();
1155 for ( const auto& rpLayout
: aAllLayouts
)
1157 SwFrame::CheckPageDescs( static_cast<SwPageFrame
*>(rpLayout
->Lower()) );
1160 SetProtect( SwTOXBase::IsProtected() );
1163 void SwTOXBaseSection::InsertAlphaDelimiter( const SwTOXInternational
& rIntl
)
1165 SwDoc
* pDoc
= GetFormat()->GetDoc();
1168 while( i
< m_aSortArr
.size() )
1170 ::SetProgressState( 0, pDoc
->GetDocShell() );
1172 sal_uInt16 nLevel
= m_aSortArr
[i
]->GetLevel();
1174 // Skip AlphaDelimiter
1175 if( nLevel
== FORM_ALPHA_DELIMITER
)
1178 const OUString sDeli
= rIntl
.GetIndexKey( m_aSortArr
[i
]->GetText(),
1179 m_aSortArr
[i
]->GetLocale() );
1181 // Do we already have a Delimiter?
1182 if( !sDeli
.isEmpty() && sLastDeli
!= sDeli
)
1184 // We skip all that are less than a small Blank (these are special characters)
1185 if( ' ' <= sDeli
[0] )
1187 std::unique_ptr
<SwTOXCustom
> pCst(
1188 MakeSwTOXSortTabBase
<SwTOXCustom
>(nullptr,
1189 TextAndReading(sDeli
, OUString()),
1190 FORM_ALPHA_DELIMITER
,
1191 rIntl
, m_aSortArr
[i
]->GetLocale() ));
1192 m_aSortArr
.insert( m_aSortArr
.begin() + i
, std::move(pCst
));
1198 // Skip until we get to the same or a lower Level
1201 } while (i
< m_aSortArr
.size() && m_aSortArr
[i
]->GetLevel() > nLevel
);
1205 /// Evaluate Template
1206 SwTextFormatColl
* SwTOXBaseSection::GetTextFormatColl( sal_uInt16 nLevel
)
1208 SwDoc
* pDoc
= GetFormat()->GetDoc();
1209 const OUString
& rName
= GetTOXForm().GetTemplate( nLevel
);
1210 SwTextFormatColl
* pColl
= !rName
.isEmpty() ? pDoc
->FindTextFormatCollByName(rName
) :nullptr;
1213 sal_uInt16 nPoolFormat
= 0;
1214 const TOXTypes eMyType
= SwTOXBase::GetType();
1217 case TOX_INDEX
: nPoolFormat
= RES_POOLCOLL_TOX_IDXH
; break;
1220 nPoolFormat
= RES_POOLCOLL_TOX_USERH
;
1222 nPoolFormat
= RES_POOLCOLL_TOX_USER6
- 6;
1224 case TOX_ILLUSTRATIONS
: nPoolFormat
= RES_POOLCOLL_TOX_ILLUSH
; break;
1225 case TOX_OBJECTS
: nPoolFormat
= RES_POOLCOLL_TOX_OBJECTH
; break;
1226 case TOX_TABLES
: nPoolFormat
= RES_POOLCOLL_TOX_TABLESH
; break;
1227 case TOX_AUTHORITIES
:
1228 case TOX_BIBLIOGRAPHY
:
1229 nPoolFormat
= RES_POOLCOLL_TOX_AUTHORITIESH
; break;
1230 case TOX_CITATION
: /** TODO */break;
1232 // There's a jump in the ContentArea!
1234 nPoolFormat
= RES_POOLCOLL_TOX_CNTNTH
;
1236 nPoolFormat
= RES_POOLCOLL_TOX_CNTNT6
- 6;
1240 if(eMyType
== TOX_AUTHORITIES
&& nLevel
)
1241 nPoolFormat
= nPoolFormat
+ 1;
1242 else if(eMyType
== TOX_INDEX
&& nLevel
)
1244 // pool: Level 1,2,3, Delimiter
1245 // SwForm: Delimiter, Level 1,2,3
1246 nPoolFormat
+= 1 == nLevel
? nLevel
+ 3 : nLevel
- 1;
1249 nPoolFormat
= nPoolFormat
+ nLevel
;
1250 pColl
= pDoc
->getIDocumentStylePoolAccess().GetTextCollFromPool( nPoolFormat
);
1255 void SwTOXBaseSection::SwClientNotify(const SwModify
& rModify
, const SfxHint
& rHint
)
1257 if (auto pFindHint
= dynamic_cast<const sw::FindContentFrameHint
*>(&rHint
))
1259 if(pFindHint
->m_rpContentFrame
)
1261 auto pSectFormat
= GetFormat();
1264 const SwSectionNode
* pSectNd
= pSectFormat
->GetSectionNode();
1267 SwNodeIndex
aIdx(*pSectNd
, 1);
1268 SwContentNode
* pCNd
= aIdx
.GetNode().GetContentNode();
1270 pCNd
= pFindHint
->m_rDoc
.GetNodes().GoNext(&aIdx
);
1273 if(pCNd
->EndOfSectionIndex() >= pSectNd
->EndOfSectionIndex())
1275 pFindHint
->m_rpContentFrame
= pCNd
->getLayoutFrame(&pFindHint
->m_rLayout
);
1277 SwTOXBase::SwClientNotify(rModify
, rHint
);
1280 /// Create from Marks
1281 void SwTOXBaseSection::UpdateMarks(const SwTOXInternational
& rIntl
,
1282 const SwTextNode
* pOwnChapterNode
,
1283 SwRootFrame
const*const pLayout
)
1285 const auto pType
= static_cast<SwTOXType
*>(SwTOXBase::GetRegisteredIn());
1286 auto pShell
= GetFormat()->GetDoc()->GetDocShell();
1287 const TOXTypes eTOXTyp
= GetTOXType()->GetType();
1288 std::vector
<std::reference_wrapper
<SwTextTOXMark
>> vMarks
;
1289 pType
->CollectTextTOXMarksForLayout(vMarks
, pLayout
);
1290 for(auto& rMark
: vMarks
)
1292 ::SetProgressState(0, pShell
);
1293 auto& rNode
= rMark
.get().GetTextNode();
1294 if(IsFromChapter() && !IsHeadingContained(pOwnChapterNode
, rNode
))
1296 auto rTOXMark
= rMark
.get().GetTOXMark();
1297 if(TOX_INDEX
== eTOXTyp
)
1301 lang::Locale aLocale
= g_pBreakIt
->GetLocale(rNode
.GetLang(rMark
.get().GetStart()));
1302 InsertSorted(MakeSwTOXSortTabBase
<SwTOXIndex
>(pLayout
, rNode
, &rMark
.get(), GetOptions(), FORM_ENTRY
, rIntl
, aLocale
));
1303 if(GetOptions() & SwTOIOptions::KeyAsEntry
&& !rTOXMark
.GetPrimaryKey().isEmpty())
1305 InsertSorted(MakeSwTOXSortTabBase
<SwTOXIndex
>(pLayout
, rNode
, &rMark
.get(), GetOptions(), FORM_PRIMARY_KEY
, rIntl
, aLocale
));
1306 if (!rTOXMark
.GetSecondaryKey().isEmpty())
1308 InsertSorted(MakeSwTOXSortTabBase
<SwTOXIndex
>(pLayout
, rNode
, &rMark
.get(), GetOptions(), FORM_SECONDARY_KEY
, rIntl
, aLocale
));
1312 else if(TOX_USER
== eTOXTyp
|| rTOXMark
.GetLevel() <= GetLevel())
1313 { // table of content mark, also used for user marks
1314 InsertSorted(MakeSwTOXSortTabBase
<SwTOXContent
>(pLayout
, rNode
, &rMark
.get(), rIntl
));
1319 /// Generate table of contents from outline
1320 void SwTOXBaseSection::UpdateOutline( const SwTextNode
* pOwnChapterNode
,
1321 SwRootFrame
const*const pLayout
)
1323 SwDoc
* pDoc
= GetFormat()->GetDoc();
1324 SwNodes
& rNds
= pDoc
->GetNodes();
1326 const SwOutlineNodes
& rOutlNds
= rNds
.GetOutLineNds();
1327 for( auto pOutlineNode
: rOutlNds
)
1329 ::SetProgressState( 0, pDoc
->GetDocShell() );
1330 SwTextNode
* pTextNd
= pOutlineNode
->GetTextNode();
1331 if( pTextNd
&& pTextNd
->Len() && pTextNd
->HasWriterListeners() &&
1332 o3tl::make_unsigned( pTextNd
->GetAttrOutlineLevel()) <= GetLevel() &&
1333 pTextNd
->getLayoutFrame(pLayout
) &&
1334 !pTextNd
->IsHiddenByParaField() &&
1335 !pTextNd
->HasHiddenCharAttribute( true ) &&
1336 (!pLayout
|| !pLayout
->HasMergedParas()
1337 || static_cast<SwTextFrame
*>(pTextNd
->getLayoutFrame(pLayout
))->GetTextNodeForParaProps() == pTextNd
) &&
1338 ( !IsFromChapter() || IsHeadingContained(pOwnChapterNode
, *pTextNd
) ))
1340 InsertSorted(MakeSwTOXSortTabBase
<SwTOXPara
>(pLayout
, *pTextNd
, SwTOXElement::OutlineLevel
));
1345 /// Generate table of contents from template areas
1346 void SwTOXBaseSection::UpdateTemplate(const SwTextNode
* pOwnChapterNode
,
1347 SwRootFrame
const*const pLayout
)
1349 SwDoc
* pDoc
= GetFormat()->GetDoc();
1350 for(sal_uInt16 i
= 0; i
< MAXLEVEL
; i
++)
1352 const OUString sTmpStyleNames
= GetStyleNames(i
);
1353 if (sTmpStyleNames
.isEmpty())
1356 sal_Int32 nIndex
= 0;
1359 SwTextFormatColl
* pColl
= pDoc
->FindTextFormatCollByName(
1360 sTmpStyleNames
.getToken( 0, TOX_STYLE_DELIMITER
, nIndex
));
1361 //TODO: no outline Collections in content indexes if OutlineLevels are already included
1363 ( TOX_CONTENT
== SwTOXBase::GetType() &&
1364 GetCreateType() & SwTOXElement::OutlineLevel
&&
1365 pColl
->IsAssignedToListLevelOfOutlineStyle()) )
1368 SwIterator
<SwTextNode
,SwFormatColl
> aIter( *pColl
);
1369 for( SwTextNode
* pTextNd
= aIter
.First(); pTextNd
; pTextNd
= aIter
.Next() )
1371 ::SetProgressState( 0, pDoc
->GetDocShell() );
1373 if (pTextNd
->GetText().getLength() &&
1374 pTextNd
->getLayoutFrame(pLayout
) &&
1375 pTextNd
->GetNodes().IsDocNodes() &&
1376 // tdf#40142 - consider level settings of the various text nodes
1377 o3tl::make_unsigned(pTextNd
->GetAttrOutlineLevel()) <= GetLevel() &&
1378 (!pLayout
|| !pLayout
->HasMergedParas()
1379 || static_cast<SwTextFrame
*>(pTextNd
->getLayoutFrame(pLayout
))->GetTextNodeForParaProps() == pTextNd
) &&
1380 (!IsFromChapter() || IsHeadingContained(pOwnChapterNode
, *pTextNd
)))
1382 InsertSorted(MakeSwTOXSortTabBase
<SwTOXPara
>(pLayout
, *pTextNd
, SwTOXElement::Template
, i
+ 1));
1389 /// Generate content from sequence fields
1390 void SwTOXBaseSection::UpdateSequence(const SwTextNode
* pOwnChapterNode
,
1391 SwRootFrame
const*const pLayout
)
1393 SwDoc
* pDoc
= GetFormat()->GetDoc();
1394 SwFieldType
* pSeqField
= pDoc
->getIDocumentFieldsAccess().GetFieldType(SwFieldIds::SetExp
, GetSequenceName(), false);
1398 std::vector
<SwFormatField
*> vFields
;
1399 pSeqField
->GatherFields(vFields
);
1400 for(auto pFormatField
: vFields
)
1402 const SwTextField
* pTextField
= pFormatField
->GetTextField();
1403 SwTextNode
& rTextNode
= pTextField
->GetTextNode();
1404 ::SetProgressState( 0, pDoc
->GetDocShell() );
1406 if (rTextNode
.GetText().getLength() &&
1407 rTextNode
.getLayoutFrame(pLayout
) &&
1408 ( !IsFromChapter() || IsHeadingContained(pOwnChapterNode
, rTextNode
))
1409 && (!pLayout
|| !pLayout
->IsHideRedlines()
1410 || !sw::IsFieldDeletedInModel(pDoc
->getIDocumentRedlineAccess(), *pTextField
)))
1412 const SwSetExpField
& rSeqField
= dynamic_cast<const SwSetExpField
&>(*(pFormatField
->GetField()));
1413 const OUString sName
= GetSequenceName()
1414 + OUStringChar(cSequenceMarkSeparator
)
1415 + OUString::number( rSeqField
.GetSeqNumber() );
1416 std::unique_ptr
<SwTOXPara
> pNew(new SwTOXPara( rTextNode
, SwTOXElement::Sequence
, 1, sName
));
1417 // set indexes if the number or the reference text are to be displayed
1418 if( GetCaptionDisplay() == CAPTION_TEXT
)
1420 pNew
->SetStartIndex(
1421 SwGetExpField::GetReferenceTextPos( *pFormatField
, *pDoc
));
1423 else if(GetCaptionDisplay() == CAPTION_NUMBER
)
1425 pNew
->SetEndIndex(pTextField
->GetStart() + 1);
1427 pNew
->InitText(pLayout
);
1428 InsertSorted(std::move(pNew
));
1433 void SwTOXBaseSection::UpdateAuthorities(const SwTOXInternational
& rIntl
,
1434 SwRootFrame
const*const pLayout
)
1436 SwDoc
* pDoc
= GetFormat()->GetDoc();
1437 SwFieldType
* pAuthField
= pDoc
->getIDocumentFieldsAccess().GetFieldType(SwFieldIds::TableOfAuthorities
, OUString(), false);
1441 std::vector
<SwFormatField
*> vFields
;
1442 pAuthField
->GatherFields(vFields
);
1443 for(auto pFormatField
: vFields
)
1445 const auto pTextField
= pFormatField
->GetTextField();
1446 const SwTextNode
& rTextNode
= pFormatField
->GetTextField()->GetTextNode();
1447 ::SetProgressState( 0, pDoc
->GetDocShell() );
1449 if (rTextNode
.GetText().getLength() &&
1450 rTextNode
.getLayoutFrame(pLayout
) &&
1451 (!pLayout
|| !pLayout
->IsHideRedlines()
1452 || !sw::IsFieldDeletedInModel(pDoc
->getIDocumentRedlineAccess(), *pTextField
)))
1454 //#106485# the body node has to be used!
1455 SwContentFrame
*const pFrame
= rTextNode
.getLayoutFrame(pLayout
);
1456 SwPosition
aFieldPos(rTextNode
);
1457 const SwTextNode
* pTextNode
= nullptr;
1458 if(pFrame
&& !pFrame
->IsInDocBody())
1459 pTextNode
= GetBodyTextNode( *pDoc
, aFieldPos
, *pFrame
);
1461 pTextNode
= &rTextNode
;
1463 InsertSorted(MakeSwTOXSortTabBase
<SwTOXAuthority
>(pLayout
, *pTextNode
, *pFormatField
, rIntl
));
1468 static SwTOOElements
lcl_IsSOObject( const SvGlobalName
& rFactoryNm
)
1470 static const struct SoObjType
{
1471 SwTOOElements nFlag
;
1476 sal_uInt8 b8
, b9
, b10
, b11
, b12
, b13
, b14
, b15
;
1479 { SwTOOElements::Math
,
1480 { {SO3_SM_CLASSID_60
},{SO3_SM_CLASSID_50
},
1481 {SO3_SM_CLASSID_40
},{SO3_SM_CLASSID_30
} } },
1482 { SwTOOElements::Chart
,
1483 { {SO3_SCH_CLASSID_60
},{SO3_SCH_CLASSID_50
},
1484 {SO3_SCH_CLASSID_40
},{SO3_SCH_CLASSID_30
} } },
1485 { SwTOOElements::Calc
,
1486 { {SO3_SC_CLASSID_60
},{SO3_SC_CLASSID_50
},
1487 {SO3_SC_CLASSID_40
},{SO3_SC_CLASSID_30
} } },
1488 { SwTOOElements::DrawImpress
,
1489 { {SO3_SIMPRESS_CLASSID_60
},{SO3_SIMPRESS_CLASSID_50
},
1490 {SO3_SIMPRESS_CLASSID_40
},{SO3_SIMPRESS_CLASSID_30
} } },
1491 { SwTOOElements::DrawImpress
,
1492 { {SO3_SDRAW_CLASSID_60
},{SO3_SDRAW_CLASSID_50
} } }
1495 for( SoObjType
const & rArr
: aArr
)
1496 for (auto & rId
: rArr
.aGlNmIds
)
1500 SvGlobalName
aGlbNm( rId
.n1
, rId
.n2
, rId
.n3
,
1501 rId
.b8
, rId
.b9
, rId
.b10
, rId
.b11
,
1502 rId
.b12
, rId
.b13
, rId
.b14
, rId
.b15
);
1503 if( rFactoryNm
== aGlbNm
)
1509 return SwTOOElements::NONE
;
1512 void SwTOXBaseSection::UpdateContent( SwTOXElement eMyType
,
1513 const SwTextNode
* pOwnChapterNode
,
1514 SwRootFrame
const*const pLayout
)
1516 SwDoc
* pDoc
= GetFormat()->GetDoc();
1517 SwNodes
& rNds
= pDoc
->GetNodes();
1518 // on the 1st Node of the 1st Section
1519 SwNodeOffset nIdx
= rNds
.GetEndOfAutotext().StartOfSectionIndex() + SwNodeOffset(2),
1520 nEndIdx
= rNds
.GetEndOfAutotext().GetIndex();
1522 while( nIdx
< nEndIdx
)
1524 ::SetProgressState( 0, pDoc
->GetDocShell() );
1526 SwNode
* pNd
= rNds
[ nIdx
];
1527 SwContentNode
* pCNd
= nullptr;
1530 case SwTOXElement::Frame
:
1531 if( !pNd
->IsNoTextNode() )
1533 pCNd
= pNd
->GetContentNode();
1536 SwNodeIndex
aTmp( *pNd
);
1537 pCNd
= rNds
.GoNext( &aTmp
);
1541 case SwTOXElement::Graphic
:
1542 if( pNd
->IsGrfNode() )
1543 pCNd
= static_cast<SwContentNode
*>(pNd
);
1545 case SwTOXElement::Ole
:
1546 if( pNd
->IsOLENode() )
1548 bool bInclude
= true;
1549 if(TOX_OBJECTS
== SwTOXBase::GetType())
1551 SwOLENode
* pOLENode
= pNd
->GetOLENode();
1552 SwTOOElements nMyOLEOptions
= GetOLEOptions();
1553 SwOLEObj
& rOLEObj
= pOLENode
->GetOLEObj();
1555 if( rOLEObj
.IsOleRef() ) // Not yet loaded
1557 SvGlobalName
aTmpName( rOLEObj
.GetOleRef()->getClassID() );
1558 SwTOOElements nObj
= ::lcl_IsSOObject( aTmpName
);
1559 bInclude
= ( (nMyOLEOptions
& SwTOOElements::Other
) && SwTOOElements::NONE
== nObj
)
1560 || (nMyOLEOptions
& nObj
);
1564 OSL_FAIL("OLE Object no loaded?");
1570 pCNd
= static_cast<SwContentNode
*>(pNd
);
1578 // find node in body text
1579 int nSetLevel
= USHRT_MAX
;
1581 //#111105# tables of tables|illustrations|objects don't support hierarchies
1582 if( IsLevelFromChapter() &&
1583 TOX_TABLES
!= SwTOXBase::GetType() &&
1584 TOX_ILLUSTRATIONS
!= SwTOXBase::GetType() &&
1585 TOX_OBJECTS
!= SwTOXBase::GetType() )
1587 const SwTextNode
* pOutlNd
= ::lcl_FindChapterNode( *pCNd
,
1588 pLayout
, MAXLEVEL
- 1);
1591 if( pOutlNd
->GetTextColl()->IsAssignedToListLevelOfOutlineStyle())
1593 nSetLevel
= pOutlNd
->GetTextColl()->GetAttrOutlineLevel();
1598 if (pCNd
->getLayoutFrame(pLayout
)
1599 && (!pLayout
|| !pLayout
->HasMergedParas()
1600 || pCNd
->GetRedlineMergeFlag() != SwNode::Merge::Hidden
)
1601 && ( !IsFromChapter() || IsHeadingContained(pOwnChapterNode
, *pCNd
)))
1603 std::unique_ptr
<SwTOXPara
> pNew( MakeSwTOXSortTabBase
<SwTOXPara
>(
1604 pLayout
, *pCNd
, eMyType
,
1605 ( USHRT_MAX
!= nSetLevel
)
1606 ? o3tl::narrowing
<sal_uInt16
>(nSetLevel
)
1607 : FORM_ALPHA_DELIMITER
) );
1608 InsertSorted( std::move(pNew
) );
1612 nIdx
= pNd
->StartOfSectionNode()->EndOfSectionIndex() + SwNodeOffset(2); // 2 == End/Start Node
1616 /// Collect table entries
1617 void SwTOXBaseSection::UpdateTable(const SwTextNode
* pOwnChapterNode
,
1618 SwRootFrame
const*const pLayout
)
1620 SwDoc
* pDoc
= GetFormat()->GetDoc();
1621 SwNodes
& rNds
= pDoc
->GetNodes();
1623 for(SwTableFormat
* pFrameFormat
: *pDoc
->GetTableFrameFormats())
1625 ::SetProgressState( 0, pDoc
->GetDocShell() );
1627 SwTable
* pTmpTable
= SwTable::FindTable( pFrameFormat
);
1629 if( pTmpTable
&& nullptr != (pFBox
= pTmpTable
->GetTabSortBoxes()[0] ) &&
1630 pFBox
->GetSttNd() && pFBox
->GetSttNd()->GetNodes().IsDocNodes() )
1632 const SwTableNode
* pTableNd
= pFBox
->GetSttNd()->FindTableNode();
1633 SwNodeIndex
aContentIdx( *pTableNd
, 1 );
1635 SwContentNode
* pCNd
;
1636 while( nullptr != ( pCNd
= rNds
.GoNext( &aContentIdx
) ) &&
1637 aContentIdx
.GetIndex() < pTableNd
->EndOfSectionIndex() )
1639 if (pCNd
->getLayoutFrame(pLayout
)
1640 && (!pLayout
|| !pLayout
->HasMergedParas()
1641 || pCNd
->GetRedlineMergeFlag() != SwNode::Merge::Hidden
)
1642 && (!IsFromChapter() || IsHeadingContained(pOwnChapterNode
, *pCNd
)))
1644 std::unique_ptr
<SwTOXTable
> pNew(new SwTOXTable( *pCNd
));
1645 if( IsLevelFromChapter() && TOX_TABLES
!= SwTOXBase::GetType())
1647 const SwTextNode
* pOutlNd
=
1648 ::lcl_FindChapterNode(*pCNd
, pLayout
, MAXLEVEL
- 1);
1651 if( pOutlNd
->GetTextColl()->IsAssignedToListLevelOfOutlineStyle())
1653 const int nTmp
= pOutlNd
->GetTextColl()->GetAttrOutlineLevel();
1654 pNew
->SetLevel(o3tl::narrowing
<sal_uInt16
>(nTmp
));
1658 pNew
->InitText(pLayout
);
1659 InsertSorted(std::move(pNew
));
1667 /// Calculate PageNumber and insert after formatting
1668 void SwTOXBaseSection::UpdatePageNum()
1670 if( m_aSortArr
.empty() )
1673 // Insert the current PageNumber into the TOC
1674 SwPageFrame
* pCurrentPage
= nullptr;
1675 sal_uInt16 nPage
= 0;
1676 SwDoc
* pDoc
= GetFormat()->GetDoc();
1678 SwTOXInternational
aIntl( GetLanguage(),
1679 TOX_INDEX
== GetTOXType()->GetType() ?
1680 GetOptions() : SwTOIOptions::NONE
,
1681 GetSortAlgorithm() );
1683 for( size_t nCnt
= 0; nCnt
< m_aSortArr
.size(); ++nCnt
)
1685 // Loop over all SourceNodes
1687 // process run in lines
1689 if(GetTOXForm().IsCommaSeparated() &&
1690 m_aSortArr
[nCnt
]->GetType() == TOX_SORT_INDEX
)
1692 const SwTOXMark
& rMark
= m_aSortArr
[nCnt
]->pTextMark
->GetTOXMark();
1693 const OUString
& sPrimKey
= rMark
.GetPrimaryKey();
1694 const OUString
& sSecKey
= rMark
.GetSecondaryKey();
1695 const SwTOXMark
* pNextMark
= nullptr;
1696 while(m_aSortArr
.size() > (nCnt
+ nRange
)&&
1697 m_aSortArr
[nCnt
+ nRange
]->GetType() == TOX_SORT_INDEX
&&
1698 nullptr != (pNextMark
= &(m_aSortArr
[nCnt
+ nRange
]->pTextMark
->GetTOXMark())) &&
1699 pNextMark
->GetPrimaryKey() == sPrimKey
&&
1700 pNextMark
->GetSecondaryKey() == sSecKey
)
1706 for(size_t nRunInEntry
= nCnt
; nRunInEntry
< nCnt
+ nRange
; ++nRunInEntry
)
1708 std::vector
<sal_uInt16
> aNums
; // the PageNumber
1709 std::vector
<SwPageDesc
*> aDescs
; // The PageDescriptors matching the PageNumbers
1710 std::vector
<sal_uInt16
> aMainNums
; // contains page numbers of main entries
1711 SwTOXSortTabBase
* pSortBase
= m_aSortArr
[nRunInEntry
].get();
1712 size_t nSize
= pSortBase
->aTOXSources
.size();
1713 for (size_t j
= 0; j
< nSize
; ++j
)
1715 ::SetProgressState( 0, pDoc
->GetDocShell() );
1717 SwTOXSource
& rTOXSource
= pSortBase
->aTOXSources
[j
];
1718 if( rTOXSource
.pNd
)
1720 SwContentFrame
* pFrame
= rTOXSource
.pNd
->getLayoutFrame( pDoc
->getIDocumentLayoutAccess().GetCurrentLayout() );
1721 OSL_ENSURE( pFrame
|| pDoc
->IsUpdateTOX(), "TOX, no Frame found");
1724 if( pFrame
->IsTextFrame() && static_cast<SwTextFrame
*>(pFrame
)->HasFollow() )
1726 // find the right one
1728 TextFrameIndex
const nPos(static_cast<SwTextFrame
*>(pFrame
)
1729 ->MapModelToView(static_cast<SwTextNode
const*>(rTOXSource
.pNd
),
1733 pNext
= static_cast<SwTextFrame
*>(pFrame
->GetFollow());
1734 if (!pNext
|| nPos
< pNext
->GetOffset())
1740 SwPageFrame
* pTmpPage
= pFrame
->FindPageFrame();
1741 if( pTmpPage
!= pCurrentPage
)
1743 nPage
= pTmpPage
->GetVirtPageNum();
1744 pCurrentPage
= pTmpPage
;
1748 std::vector
<sal_uInt16
>::size_type i
;
1749 for( i
= 0; i
< aNums
.size() && aNums
[i
] < nPage
; ++i
)
1752 if( i
>= aNums
.size() || aNums
[ i
] != nPage
)
1754 aNums
.insert(aNums
.begin() + i
, nPage
);
1755 aDescs
.insert(aDescs
.begin() + i
, pCurrentPage
->GetPageDesc() );
1757 // is it a main entry?
1758 if(TOX_SORT_INDEX
== pSortBase
->GetType() &&
1759 rTOXSource
.bMainEntry
)
1761 aMainNums
.push_back(nPage
);
1765 // Insert the PageNumber into the TOC TextNode
1766 const SwTOXSortTabBase
* pBase
= m_aSortArr
[ nCnt
].get();
1769 const SwTextNode
* pTextNd
= pBase
->pTOXNd
->GetTextNode();
1770 OSL_ENSURE( pTextNd
, "no TextNode, wrong TOC" );
1772 UpdatePageNum_( const_cast<SwTextNode
*>(pTextNd
), aNums
, aDescs
, &aMainNums
,
1777 // Delete the mapping array after setting the right PageNumber
1781 /// Replace the PageNumber place holders. Search for the page no. in the array
1782 /// of main entry page numbers.
1783 static bool lcl_HasMainEntry( const std::vector
<sal_uInt16
>* pMainEntryNums
, sal_uInt16 nToFind
)
1785 if (!pMainEntryNums
)
1788 for( auto nMainEntry
: *pMainEntryNums
)
1789 if (nToFind
== nMainEntry
)
1794 void SwTOXBaseSection::UpdatePageNum_( SwTextNode
* pNd
,
1795 const std::vector
<sal_uInt16
>& rNums
,
1796 const std::vector
<SwPageDesc
*>& rDescs
,
1797 const std::vector
<sal_uInt16
>* pMainEntryNums
,
1798 const SwTOXInternational
& rIntl
)
1800 // collect starts end ends of main entry character style
1801 std::optional
< std::vector
<sal_uInt16
> > xCharStyleIdx
;
1803 xCharStyleIdx
.emplace();
1806 = OUStringChar(C_NUM_REPL
) + SwTOXMark::S_PAGE_DELI
+ OUStringChar(C_NUM_REPL
);
1807 sal_Int32 nStartPos
= pNd
->GetText().indexOf(sSrchStr
);
1808 sSrchStr
= OUStringChar(C_NUM_REPL
) + OUStringChar(C_END_PAGE_NUM
);
1809 sal_Int32 nEndPos
= pNd
->GetText().indexOf(sSrchStr
);
1811 if (-1 == nEndPos
|| rNums
.empty())
1814 if (-1 == nStartPos
|| nStartPos
> nEndPos
)
1815 nStartPos
= nEndPos
;
1817 sal_uInt16 nOld
= rNums
[0],
1820 OUString
aNumStr( rDescs
[0]->GetNumType().GetNumStr( nBeg
) );
1821 if( xCharStyleIdx
&& lcl_HasMainEntry( pMainEntryNums
, nBeg
))
1823 xCharStyleIdx
->push_back( 0 );
1826 // Delete place holder
1827 SwContentIndex
aPos(pNd
, nStartPos
);
1828 SwCharFormat
* pPageNoCharFormat
= nullptr;
1829 SwpHints
* pHints
= pNd
->GetpSwpHints();
1831 for(size_t nHintIdx
= 0; nHintIdx
< pHints
->Count(); ++nHintIdx
)
1833 const SwTextAttr
* pAttr
= pHints
->Get(nHintIdx
);
1834 const sal_Int32 nTmpEnd
= pAttr
->End() ? *pAttr
->End() : 0;
1835 if( nStartPos
>= pAttr
->GetStart() &&
1836 (nStartPos
+ 2) <= nTmpEnd
&&
1837 pAttr
->Which() == RES_TXTATR_CHARFMT
)
1839 pPageNoCharFormat
= pAttr
->GetCharFormat().GetCharFormat();
1843 pNd
->EraseText(aPos
, nEndPos
- nStartPos
+ 2);
1845 std::vector
<sal_uInt16
>::size_type i
;
1846 for( i
= 1; i
< rNums
.size(); ++i
)
1848 SvxNumberType
aType( rDescs
[i
]->GetNumType() );
1849 if( TOX_INDEX
== SwTOXBase::GetType() )
1850 { // Summarize for the following
1851 // Add up all following
1852 // break up if main entry starts or ends and
1853 // insert a char style index
1854 bool bMainEntryChanges
= lcl_HasMainEntry(pMainEntryNums
, nOld
)
1855 != lcl_HasMainEntry(pMainEntryNums
, rNums
[i
]);
1857 if(nOld
== rNums
[i
]-1 && !bMainEntryChanges
&&
1858 (GetOptions() & (SwTOIOptions::FF
|SwTOIOptions::Dash
)))
1862 // Flush for the following old values
1863 if(GetOptions() & SwTOIOptions::FF
)
1866 aNumStr
+= rIntl
.GetFollowingText( nCount
> 1 );
1868 else if (nCount
) //#58127# If nCount == 0, then the only PageNumber is already in aNumStr!
1871 aNumStr
+= SwTOXMark::S_PAGE_DELI
;
1875 aNumStr
+= aType
.GetNumStr( nBeg
+ nCount
);
1878 // Create new String
1880 aNumStr
+= SwTOXMark::S_PAGE_DELI
;
1881 //the change of the character style must apply after sPageDeli is appended
1882 if (xCharStyleIdx
&& bMainEntryChanges
)
1884 xCharStyleIdx
->push_back(aNumStr
.getLength());
1886 aNumStr
+= aType
.GetNumStr( nBeg
);
1892 { // Insert all Numbers
1893 aNumStr
+= aType
.GetNumStr( rNums
[i
] );
1894 if (i
+1 != rNums
.size())
1895 aNumStr
+= SwTOXMark::S_PAGE_DELI
;
1898 // Flush when ending and the following old values
1899 if( TOX_INDEX
== SwTOXBase::GetType() )
1901 if(GetOptions() & SwTOIOptions::FF
)
1904 aNumStr
+= rIntl
.GetFollowingText( nCount
> 1 );
1910 else if(nCount
== 1)
1911 aNumStr
+= SwTOXMark::S_PAGE_DELI
;
1912 //#58127# If nCount == 0, then the only PageNumber is already in aNumStr!
1914 aNumStr
+= rDescs
[i
-1]->GetNumType().GetNumStr( nBeg
+nCount
);
1917 pNd
->InsertText( aNumStr
, aPos
, SwInsertFlags::EMPTYEXPAND
| SwInsertFlags::FORCEHINTEXPAND
);
1918 if(pPageNoCharFormat
)
1920 SwFormatCharFormat
aCharFormat( pPageNoCharFormat
);
1921 pNd
->InsertItem(aCharFormat
, nStartPos
, nStartPos
+ aNumStr
.getLength(), SetAttrMode::DONTEXPAND
);
1924 // The main entries should get their character style
1925 if (!xCharStyleIdx
|| xCharStyleIdx
->empty() || GetMainEntryCharStyle().isEmpty())
1928 // eventually the last index must me appended
1929 if (xCharStyleIdx
->size()&0x01)
1930 xCharStyleIdx
->push_back(aNumStr
.getLength());
1933 SwDoc
& rDoc
= pNd
->GetDoc();
1934 sal_uInt16 nPoolId
= SwStyleNameMapper::GetPoolIdFromUIName( GetMainEntryCharStyle(), SwGetPoolIdFromName::ChrFmt
);
1935 SwCharFormat
* pCharFormat
= nullptr;
1936 if(USHRT_MAX
!= nPoolId
)
1937 pCharFormat
= rDoc
.getIDocumentStylePoolAccess().GetCharFormatFromPool(nPoolId
);
1939 pCharFormat
= rDoc
.FindCharFormatByName( GetMainEntryCharStyle() );
1941 pCharFormat
= rDoc
.MakeCharFormat(GetMainEntryCharStyle(), nullptr);
1943 // find the page numbers in aNumStr and set the character style
1944 sal_Int32 nOffset
= pNd
->GetText().getLength() - aNumStr
.getLength();
1945 SwFormatCharFormat
aCharFormat(pCharFormat
);
1946 for (size_t j
= 0; j
< xCharStyleIdx
->size(); j
+= 2)
1948 sal_Int32 nStartIdx
= (*xCharStyleIdx
)[j
] + nOffset
;
1949 sal_Int32 nEndIdx
= (*xCharStyleIdx
)[j
+ 1] + nOffset
;
1950 pNd
->InsertItem(aCharFormat
, nStartIdx
, nEndIdx
, SetAttrMode::DONTEXPAND
);
1954 void SwTOXBaseSection::InsertSorted(std::unique_ptr
<SwTOXSortTabBase
> pNew
)
1956 Range
aRange(0, m_aSortArr
.size());
1957 if( TOX_INDEX
== SwTOXBase::GetType() && pNew
->pTextMark
)
1959 const SwTOXMark
& rMark
= pNew
->pTextMark
->GetTOXMark();
1961 // Calculate the range where to insert
1962 if( !(GetOptions() & SwTOIOptions::KeyAsEntry
) &&
1963 !rMark
.GetPrimaryKey().isEmpty() )
1965 aRange
= GetKeyRange( rMark
.GetPrimaryKey(),
1966 rMark
.GetPrimaryKeyReading(),
1967 *pNew
, FORM_PRIMARY_KEY
, aRange
);
1969 if( !rMark
.GetSecondaryKey().isEmpty() )
1970 aRange
= GetKeyRange( rMark
.GetSecondaryKey(),
1971 rMark
.GetSecondaryKeyReading(),
1972 *pNew
, FORM_SECONDARY_KEY
, aRange
);
1975 // Search for identical entries and remove the trailing one
1976 if(TOX_AUTHORITIES
== SwTOXBase::GetType())
1978 for(short i
= static_cast<short>(aRange
.Min()); i
< static_cast<short>(aRange
.Max()); ++i
)
1980 SwTOXSortTabBase
* pOld
= m_aSortArr
[i
].get();
1981 if (pOld
->equivalent(*pNew
))
1983 if (pOld
->sort_lt(*pNew
))
1989 // remove the old content
1990 m_aSortArr
.erase( m_aSortArr
.begin() + i
);
1998 // find position and insert
2001 for( i
= aRange
.Min(); i
< aRange
.Max(); ++i
)
2002 { // Only check for same level
2003 SwTOXSortTabBase
* pOld
= m_aSortArr
[i
].get();
2004 if (pOld
->equivalent(*pNew
))
2006 if(TOX_AUTHORITIES
!= SwTOXBase::GetType())
2008 // Own entry for double entries or keywords
2009 if( pOld
->GetType() == TOX_SORT_CUSTOM
&&
2010 SwTOXSortTabBase::GetOptions() & SwTOIOptions::KeyAsEntry
)
2013 if(!(SwTOXSortTabBase::GetOptions() & SwTOIOptions::SameEntry
))
2015 m_aSortArr
.insert(m_aSortArr
.begin() + i
, std::move(pNew
));
2018 // If the own entry is already present, add it to the references list
2019 pOld
->aTOXSources
.push_back(pNew
->aTOXSources
[0]);
2023 #if OSL_DEBUG_LEVEL > 0
2025 OSL_FAIL("Bibliography entries cannot be found here");
2028 if (pNew
->sort_lt(*pOld
))
2032 while( TOX_INDEX
== SwTOXBase::GetType() && i
< aRange
.Max() &&
2033 m_aSortArr
[i
]->GetLevel() > pNew
->GetLevel() )
2036 // Insert at position i
2037 m_aSortArr
.insert(m_aSortArr
.begin()+i
, std::move(pNew
));
2040 /// Find Key Range and insert if possible
2041 Range
SwTOXBaseSection::GetKeyRange(const OUString
& rStr
, const OUString
& rStrReading
,
2042 const SwTOXSortTabBase
& rNew
,
2043 sal_uInt16 nLevel
, const Range
& rRange
)
2045 const SwTOXInternational
& rIntl
= *rNew
.pTOXIntl
;
2046 TextAndReading
aToCompare(rStr
, rStrReading
);
2048 if( SwTOIOptions::InitialCaps
& GetOptions() )
2050 aToCompare
.sText
= rIntl
.ToUpper( aToCompare
.sText
, 0 )
2051 + aToCompare
.sText
.subView(1);
2054 OSL_ENSURE(rRange
.Min() >= 0 && rRange
.Max() >= 0, "Min Max < 0");
2056 const tools::Long nMin
= rRange
.Min();
2057 const tools::Long nMax
= rRange
.Max();
2061 for( i
= nMin
; i
< nMax
; ++i
)
2063 SwTOXSortTabBase
* pBase
= m_aSortArr
[i
].get();
2065 if( rIntl
.IsEqual( pBase
->GetText(), pBase
->GetLocale(),
2066 aToCompare
, rNew
.GetLocale() ) &&
2067 pBase
->GetLevel() == nLevel
)
2071 { // If not already present, create and insert
2072 std::unique_ptr
<SwTOXCustom
> pKey(MakeSwTOXSortTabBase
<SwTOXCustom
>(
2073 nullptr, aToCompare
, nLevel
, rIntl
, rNew
.GetLocale() ));
2074 for(i
= nMin
; i
< nMax
; ++i
)
2076 if (nLevel
== m_aSortArr
[i
]->GetLevel() && pKey
->sort_lt(*m_aSortArr
[i
]))
2079 m_aSortArr
.insert(m_aSortArr
.begin() + i
, std::move(pKey
));
2081 const tools::Long nStart
= i
+1;
2082 const tools::Long nEnd
= m_aSortArr
.size();
2084 // Find end of range
2085 for(i
= nStart
; i
< nEnd
; ++i
)
2087 if(m_aSortArr
[i
]->GetLevel() <= nLevel
)
2089 return Range(nStart
, i
);
2092 return Range(nStart
, nEnd
);
2095 bool SwTOXBase::IsTOXBaseInReadonly() const
2097 const SwTOXBaseSection
*pSect
= dynamic_cast<const SwTOXBaseSection
*>(this);
2098 if (!pSect
|| !pSect
->GetFormat())
2101 const SwSectionNode
* pSectNode
= pSect
->GetFormat()->GetSectionNode();
2105 const SwDocShell
* pDocSh
= pSectNode
->GetDoc().GetDocShell();
2109 if (pDocSh
->IsReadOnly())
2112 pSectNode
= pSectNode
->StartOfSectionNode()->FindSectionNode();
2116 return pSectNode
->GetSection().IsProtectFlag();
2119 const SfxItemSet
* SwTOXBase::GetAttrSet() const
2121 const SwTOXBaseSection
*pSect
= dynamic_cast<const SwTOXBaseSection
*>(this);
2122 if(pSect
&& pSect
->GetFormat())
2123 return &pSect
->GetFormat()->GetAttrSet();
2127 void SwTOXBase::SetAttrSet( const SfxItemSet
& rSet
)
2129 SwTOXBaseSection
*pSect
= dynamic_cast<SwTOXBaseSection
*>(this);
2130 if( pSect
&& pSect
->GetFormat() )
2131 pSect
->GetFormat()->SetFormatAttr( rSet
);
2134 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */