android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / docnode / ndsect.cxx
blobcf96e1d5094b88628e098d910bed425a84033668
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <config_wasm_strip.h>
21 #include <libxml/xmlwriter.h>
22 #include <hintids.hxx>
23 #include <osl/diagnose.h>
24 #include <sfx2/linkmgr.hxx>
25 #include <svl/itemiter.hxx>
26 #include <sal/log.hxx>
27 #include <fmtcntnt.hxx>
28 #include <txtftn.hxx>
29 #include <doc.hxx>
30 #include <IDocumentUndoRedo.hxx>
31 #include <IDocumentLinksAdministration.hxx>
32 #include <IDocumentLayoutAccess.hxx>
33 #include <IDocumentFieldsAccess.hxx>
34 #include <IDocumentRedlineAccess.hxx>
35 #include <IDocumentState.hxx>
36 #include <rootfrm.hxx>
37 #include <pam.hxx>
38 #include <ndtxt.hxx>
39 #include <section.hxx>
40 #include <UndoSection.hxx>
41 #include <UndoDelete.hxx>
42 #include <swundo.hxx>
43 #include <calc.hxx>
44 #include <swtable.hxx>
45 #include <swserv.hxx>
46 #include <frmfmt.hxx>
47 #include <frmtool.hxx>
48 #include <ftnidx.hxx>
49 #include <docary.hxx>
50 #include <redline.hxx>
51 #include <sectfrm.hxx>
52 #include <cntfrm.hxx>
53 #include <node2lay.hxx>
54 #include <doctxm.hxx>
55 #include <fmtftntx.hxx>
56 #include <strings.hrc>
57 #include <viewsh.hxx>
58 #include <memory>
59 #include "ndsect.hxx"
60 #include <tools/datetimeutils.hxx>
61 #include <o3tl/string_view.hxx>
63 // #i21457# - new implementation of local method <lcl_IsInSameTableBox(..)>.
64 // Method now determines the previous/next on its own. Thus, it can be controlled,
65 // for which previous/next is checked, if it's visible.
66 static bool lcl_IsInSameTableBox( SwNodes const & _rNds,
67 const SwNode& _rNd,
68 const bool _bPrev )
70 const SwTableNode* pTableNd = _rNd.FindTableNode();
71 if ( !pTableNd )
73 return true;
76 // determine index to be checked. Its assumed that a previous/next exist.
77 SwNodeIndex aChkIdx( _rNd );
79 // determine index of previous/next - skip hidden ones, which are
80 // inside the table.
81 // If found one is before/after table, this one isn't in the same
82 // table box as <_rNd>.
83 for(;;)
85 if ( _bPrev
86 ? !SwNodes::GoPrevSection( &aChkIdx, false, false )
87 : !_rNds.GoNextSection( &aChkIdx, false, false ) )
89 OSL_FAIL( "<lcl_IsInSameTableBox(..)> - no previous/next!" );
90 return false;
93 if ( aChkIdx < pTableNd->GetIndex() ||
94 aChkIdx > pTableNd->EndOfSectionNode()->GetIndex() )
96 return false;
99 // check, if found one isn't inside a hidden section, which
100 // is also inside the table.
101 SwSectionNode* pSectNd = aChkIdx.GetNode().FindSectionNode();
102 if ( !pSectNd ||
103 pSectNd->GetIndex() < pTableNd->GetIndex() ||
104 !pSectNd->GetSection().IsHiddenFlag() )
106 break;
110 // Find the Box's StartNode
111 const SwTableSortBoxes& rSortBoxes = pTableNd->GetTable().GetTabSortBoxes();
112 SwNodeOffset nIdx = _rNd.GetIndex();
113 for (size_t n = 0; n < rSortBoxes.size(); ++n)
115 const SwStartNode* pNd = rSortBoxes[ n ]->GetSttNd();
116 if ( pNd->GetIndex() < nIdx && nIdx < pNd->EndOfSectionIndex() )
118 // The other index needs to be within the same Section
119 nIdx = aChkIdx.GetIndex();
120 return pNd->GetIndex() < nIdx && nIdx < pNd->EndOfSectionIndex();
124 return true;
127 static void lcl_CheckEmptyLayFrame( SwNodes const & rNds, SwSectionData& rSectionData,
128 const SwNode& rStt, const SwNode& rEnd )
130 SwNodeIndex aIdx( rStt );
131 if( !SwNodes::GoPrevSection( &aIdx, true, false ) ||
132 !CheckNodesRange( rStt, aIdx.GetNode(), true ) ||
133 // #i21457#
134 !lcl_IsInSameTableBox( rNds, rStt, true ))
136 aIdx = rEnd;
137 if( !rNds.GoNextSection( &aIdx, true, false ) ||
138 !CheckNodesRange( rEnd, aIdx.GetNode(), true ) ||
139 // #i21457#
140 !lcl_IsInSameTableBox( rNds, rEnd, false ))
142 rSectionData.SetHidden( false );
147 SwSection *
148 SwDoc::InsertSwSection(SwPaM const& rRange, SwSectionData & rNewData,
149 std::tuple<SwTOXBase const*, sw::RedlineMode, sw::FieldmarkMode, sw::ParagraphBreakMode> const*const pTOXBaseAndMode,
150 SfxItemSet const*const pAttr, bool const bUpdate)
152 const SwNode* pPrvNd = nullptr;
153 sal_uInt16 nRegionRet = 0;
154 if( rRange.HasMark() )
156 nRegionRet = IsInsRegionAvailable( rRange, &pPrvNd );
157 if( 0 == nRegionRet )
159 // demoted to info because this is called from SwXTextSection::attach,
160 // so it could be invalid input
161 SAL_INFO("sw.core" , "InsertSwSection: rRange overlaps other sections");
162 return nullptr;
166 // See if the whole Document should be hidden, which we currently are not able to do.
167 if (rNewData.IsHidden() && rRange.HasMark())
169 auto [pStt, pEnd] = rRange.StartEnd(); // SwPosition*
170 if( !pStt->GetContentIndex() &&
171 pEnd->GetNode().GetContentNode()->Len() ==
172 pEnd->GetContentIndex() )
174 ::lcl_CheckEmptyLayFrame( GetNodes(),
175 rNewData,
176 pStt->GetNode(),
177 pEnd->GetNode() );
181 SwUndoInsSection* pUndoInsSect = nullptr;
182 bool const bUndo(GetIDocumentUndoRedo().DoesUndo());
183 if (bUndo)
185 pUndoInsSect = new SwUndoInsSection(rRange, rNewData, pAttr, pTOXBaseAndMode);
186 GetIDocumentUndoRedo().AppendUndo( std::unique_ptr<SwUndo>(pUndoInsSect) );
187 GetIDocumentUndoRedo().DoUndo(false);
190 SwSectionFormat* const pFormat = MakeSectionFormat();
191 pFormat->SetFormatName(rNewData.GetSectionName());
192 if ( pAttr )
194 pFormat->SetFormatAttr( *pAttr );
197 SwTOXBase const*const pTOXBase(pTOXBaseAndMode ? std::get<0>(*pTOXBaseAndMode) : nullptr);
198 SwSectionNode* pNewSectNode = nullptr;
200 RedlineFlags eOld = getIDocumentRedlineAccess().GetRedlineFlags();
201 getIDocumentRedlineAccess().SetRedlineFlags_intern( (eOld & ~RedlineFlags::ShowMask) | RedlineFlags::Ignore );
203 if( rRange.HasMark() )
205 auto [pSttPos, pEndPos] = const_cast<SwPaM&>(rRange).StartEnd(); // SwPosition*
206 if( pPrvNd && 3 == nRegionRet )
208 OSL_ENSURE( pPrvNd, "The SectionNode is missing" );
209 SwNodeIndex aStt( pSttPos->GetNode() ), aEnd( pEndPos->GetNode(), +1 );
210 while( pPrvNd != aStt.GetNode().StartOfSectionNode() )
211 --aStt;
212 while( pPrvNd != aEnd.GetNode().StartOfSectionNode() )
213 ++aEnd;
215 --aEnd; // End is inclusive in the InsertSection
216 pNewSectNode = GetNodes().InsertTextSection(
217 aStt.GetNode(), *pFormat, rNewData, pTOXBase, & aEnd.GetNode());
219 else
221 if( pUndoInsSect )
223 if( !( pPrvNd && 1 == nRegionRet ) &&
224 pSttPos->GetContentIndex() )
226 SwTextNode* const pTNd =
227 pSttPos->GetNode().GetTextNode();
228 if (pTNd)
230 pUndoInsSect->SaveSplitNode( pTNd, true );
234 if ( !( pPrvNd && 2 == nRegionRet ) )
236 SwTextNode *const pTNd =
237 pEndPos->GetNode().GetTextNode();
238 if (pTNd && (pTNd->GetText().getLength()
239 != pEndPos->GetContentIndex()))
241 pUndoInsSect->SaveSplitNode( pTNd, false );
246 if( pPrvNd && 1 == nRegionRet )
248 pSttPos->Assign( *pPrvNd );
250 else if( pSttPos->GetContentIndex() )
252 getIDocumentContentOperations().SplitNode( *pSttPos, false );
255 if( pPrvNd && 2 == nRegionRet )
257 pEndPos->Assign( *pPrvNd );
259 else
261 const SwContentNode* pCNd = pEndPos->GetNode().GetContentNode();
262 if( pCNd && pCNd->Len() != pEndPos->GetContentIndex() )
264 sal_Int32 nContent = pSttPos->GetContentIndex();
265 getIDocumentContentOperations().SplitNode( *pEndPos, false );
267 SwTextNode* pTNd;
268 if( pEndPos->GetNodeIndex() == pSttPos->GetNodeIndex() )
270 pSttPos->Adjust(SwNodeOffset(-1));
271 pEndPos->Adjust(SwNodeOffset(-1));
272 pTNd = pSttPos->GetNode().GetTextNode();
273 pSttPos->SetContent( nContent );
275 else
277 // Set to the end of the previous
278 pEndPos->Adjust(SwNodeOffset(-1));
279 pTNd = pEndPos->GetNode().GetTextNode();
281 nContent = pTNd ? pTNd->GetText().getLength() : 0;
282 pEndPos->SetContent( nContent );
285 pNewSectNode = GetNodes().InsertTextSection(
286 pSttPos->GetNode(), *pFormat, rNewData, pTOXBase, &pEndPos->GetNode());
289 else
291 const SwPosition* pPos = rRange.GetPoint();
292 const SwContentNode* pCNd = pPos->GetNode().GetContentNode();
293 if( !pPos->GetContentIndex() )
295 pNewSectNode = GetNodes().InsertTextSection(
296 pPos->GetNode(), *pFormat, rNewData, pTOXBase, nullptr);
298 else if( pPos->GetContentIndex() == pCNd->Len() )
300 pNewSectNode = GetNodes().InsertTextSection(
301 pPos->GetNode(), *pFormat, rNewData, pTOXBase, nullptr, false);
303 else
305 if( pUndoInsSect && pCNd->IsTextNode() )
307 pUndoInsSect->SaveSplitNode( const_cast<SwTextNode*>(static_cast<const SwTextNode*>(pCNd)), true );
309 getIDocumentContentOperations().SplitNode( *pPos, false );
310 pNewSectNode = GetNodes().InsertTextSection(
311 pPos->GetNode(), *pFormat, rNewData, pTOXBase, nullptr);
315 pNewSectNode->CheckSectionCondColl();
317 getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld );
319 // To-Do - add 'SwExtraRedlineTable' also ?
320 if( getIDocumentRedlineAccess().IsRedlineOn() || (!getIDocumentRedlineAccess().IsIgnoreRedline() && !getIDocumentRedlineAccess().GetRedlineTable().empty() ))
322 SwPaM aPam( *pNewSectNode->EndOfSectionNode(), *pNewSectNode, SwNodeOffset(1) );
323 if( getIDocumentRedlineAccess().IsRedlineOn() )
325 getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Insert, aPam ), true);
327 else
329 getIDocumentRedlineAccess().SplitRedline( aPam );
333 // Is a Condition set?
334 if (rNewData.IsHidden() && !rNewData.GetCondition().isEmpty())
336 // The calculate up to that position
337 SwCalc aCalc( *this );
338 if( ! IsInReading() )
340 getIDocumentFieldsAccess().FieldsToCalc(aCalc, pNewSectNode->GetIndex(), SAL_MAX_INT32);
342 SwSection& rNewSect = pNewSectNode->GetSection();
343 rNewSect.SetCondHidden( aCalc.Calculate( rNewSect.GetCondition() ).GetBool() );
346 bool bUpdateFootnote = false;
347 if( !GetFootnoteIdxs().empty() && pAttr )
349 sal_uInt16 nVal = pAttr->Get( RES_FTN_AT_TXTEND ).GetValue();
350 if( ( FTNEND_ATTXTEND_OWNNUMSEQ == nVal ||
351 FTNEND_ATTXTEND_OWNNUMANDFMT == nVal ) ||
352 ( FTNEND_ATTXTEND_OWNNUMSEQ == ( nVal = pAttr->Get( RES_END_AT_TXTEND ).GetValue() ) ||
353 FTNEND_ATTXTEND_OWNNUMANDFMT == nVal ))
355 bUpdateFootnote = true;
359 if( pUndoInsSect )
361 pUndoInsSect->SetSectNdPos( pNewSectNode->GetIndex() );
362 pUndoInsSect->SetUpdateFootnoteFlag( bUpdateFootnote );
363 GetIDocumentUndoRedo().DoUndo(bUndo);
366 if (rNewData.IsLinkType())
368 pNewSectNode->GetSection().CreateLink( bUpdate ? LinkCreateType::Update : LinkCreateType::Connect );
371 if( bUpdateFootnote )
373 GetFootnoteIdxs().UpdateFootnote( *pNewSectNode );
376 getIDocumentState().SetModified();
377 return &pNewSectNode->GetSection();
380 sal_uInt16 SwDoc::IsInsRegionAvailable( const SwPaM& rRange,
381 const SwNode** ppSttNd )
383 sal_uInt16 nRet = 1;
384 if( rRange.HasMark() )
386 // See if we have a valid Section
387 auto [pStt, pEnd] = rRange.StartEnd(); // SwPosition*
389 const SwContentNode* pCNd = pEnd->GetNode().GetContentNode();
390 const SwNode* pNd = &pStt->GetNode();
391 const SwSectionNode* pSectNd = pNd->FindSectionNode();
392 const SwSectionNode* pEndSectNd = pCNd ? pCNd->FindSectionNode() : nullptr;
393 if( pSectNd && pEndSectNd && pSectNd != pEndSectNd )
395 // Try to create an enclosing Section, but only if Start is
396 // located at the Section's beginning and End at it's end
397 nRet = 0;
398 if( !pStt->GetContentIndex()
399 && pSectNd->GetIndex() == pStt->GetNodeIndex() - 1
400 && pEnd->GetContentIndex() == pCNd->Len() )
402 SwNodeIndex aIdx( pStt->GetNode(), -1 );
403 SwNodeOffset nCmp = pEnd->GetNodeIndex();
404 const SwStartNode* pPrvNd;
405 const SwEndNode* pNxtNd;
406 while( nullptr != ( pPrvNd = (pNd = &aIdx.GetNode())->GetSectionNode() ) &&
407 ( aIdx.GetIndex() >= nCmp ||
408 nCmp >= pPrvNd->EndOfSectionIndex() ) )
410 --aIdx;
412 if( !pPrvNd )
413 pPrvNd = pNd->IsStartNode() ? static_cast<const SwStartNode*>(pNd)
414 : pNd->StartOfSectionNode();
416 aIdx = pEnd->GetNodeIndex() + 1;
417 nCmp = pStt->GetNodeIndex();
418 while( nullptr != ( pNxtNd = (pNd = &aIdx.GetNode())->GetEndNode() ) &&
419 pNxtNd->StartOfSectionNode()->IsSectionNode() &&
420 ( pNxtNd->StartOfSectionIndex() >= nCmp ||
421 nCmp >= aIdx.GetIndex() ) )
423 ++aIdx;
425 if( !pNxtNd )
426 pNxtNd = pNd->EndOfSectionNode();
428 if( pPrvNd && pNxtNd && pPrvNd == pNxtNd->StartOfSectionNode() )
430 nRet = 3;
432 if( ppSttNd )
433 *ppSttNd = pPrvNd;
437 else if( !pSectNd && pEndSectNd )
439 // Try to create an enclosing Section, but only if the End
440 // is at the Section's end.
441 nRet = 0;
442 if( pEnd->GetContentIndex() == pCNd->Len() )
444 SwNodeIndex aIdx( pEnd->GetNode(), 1 );
445 if( aIdx.GetNode().IsEndNode() &&
446 nullptr != aIdx.GetNode().FindSectionNode() )
448 do {
449 ++aIdx;
450 } while( aIdx.GetNode().IsEndNode() &&
451 nullptr != aIdx.GetNode().FindSectionNode() );
453 nRet = 2;
454 if( ppSttNd )
456 --aIdx;
457 *ppSttNd = &aIdx.GetNode();
463 else if( pSectNd && !pEndSectNd )
465 // Try to create an enclosing Section, but only if Start
466 // is at the Section's start.
467 nRet = 0;
468 if( !pStt->GetContentIndex() )
470 SwNodeIndex aIdx( pStt->GetNode(), -1 );
471 if( aIdx.GetNode().IsSectionNode() )
473 do {
474 --aIdx;
475 } while( aIdx.GetNode().IsSectionNode() );
476 if( !aIdx.GetNode().IsSectionNode() )
478 nRet = 1;
479 if( ppSttNd )
481 ++aIdx;
482 *ppSttNd = &aIdx.GetNode();
489 return nRet;
492 SwSection* SwDoc::GetCurrSection( const SwPosition& rPos )
494 const SwSectionNode* pSectNd = rPos.GetNode().FindSectionNode();
495 if( pSectNd )
496 return const_cast<SwSection*>(&pSectNd->GetSection());
497 return nullptr;
500 SwSectionFormat* SwDoc::MakeSectionFormat()
502 SwSectionFormat* pNew = new SwSectionFormat( mpDfltFrameFormat.get(), this );
503 mpSectionFormatTable->push_back( pNew );
504 return pNew;
507 void SwDoc::DelSectionFormat( SwSectionFormat *pFormat, bool bDelNodes )
509 SwSectionFormats::iterator itFormatPos = std::find( mpSectionFormatTable->begin(), mpSectionFormatTable->end(), pFormat );
511 GetIDocumentUndoRedo().StartUndo(SwUndoId::DELSECTION, nullptr);
513 if( mpSectionFormatTable->end() != itFormatPos )
515 const SwNodeIndex* pIdx = pFormat->GetContent( false ).GetContentIdx();
516 const SfxPoolItem* pFootnoteEndAtTextEnd = pFormat->GetItemIfSet(
517 RES_FTN_AT_TXTEND);
518 if( !pFootnoteEndAtTextEnd )
519 pFootnoteEndAtTextEnd = pFormat->GetItemIfSet(RES_END_AT_TXTEND);
521 const SwSectionNode* pSectNd;
523 if( GetIDocumentUndoRedo().DoesUndo() )
525 if( bDelNodes && pIdx && &GetNodes() == &pIdx->GetNodes() &&
526 nullptr != (pSectNd = pIdx->GetNode().GetSectionNode() ))
528 SwNodeIndex aUpdIdx( *pIdx );
529 SwPaM aPaM( *pSectNd->EndOfSectionNode(), *pSectNd );
530 GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoDelete>(aPaM, SwDeleteFlags::Default));
531 if( pFootnoteEndAtTextEnd )
532 GetFootnoteIdxs().UpdateFootnote( aUpdIdx.GetNode() );
533 getIDocumentState().SetModified();
534 //#126178# start/end undo have to be pairs!
535 GetIDocumentUndoRedo().EndUndo(SwUndoId::DELSECTION, nullptr);
536 return ;
538 GetIDocumentUndoRedo().AppendUndo( MakeUndoDelSection( *pFormat ) );
540 else if( bDelNodes && pIdx && &GetNodes() == &pIdx->GetNodes() &&
541 nullptr != (pSectNd = pIdx->GetNode().GetSectionNode() ))
543 SwNodeIndex aUpdIdx( *pIdx );
544 getIDocumentContentOperations().DeleteSection( const_cast<SwNode*>(static_cast<SwNode const *>(pSectNd)) );
545 if( pFootnoteEndAtTextEnd )
546 GetFootnoteIdxs().UpdateFootnote( aUpdIdx.GetNode() );
547 getIDocumentState().SetModified();
548 //#126178# start/end undo have to be pairs!
549 GetIDocumentUndoRedo().EndUndo(SwUndoId::DELSECTION, nullptr);
550 return ;
553 pFormat->RemoveAllUnos();
555 // A ClearRedo could result in a recursive call of this function and delete some section
556 // formats, thus the position inside the SectionFormatTable could have changed
557 itFormatPos = std::find( mpSectionFormatTable->begin(), mpSectionFormatTable->end(), pFormat );
559 // WARNING: First remove from the array and then delete,
560 // as the Section DTOR tries to delete it's format itself.
561 mpSectionFormatTable->erase( itFormatPos );
563 SwNodeOffset nCnt(0), nSttNd(0);
564 if( pIdx && &GetNodes() == &pIdx->GetNodes() &&
565 nullptr != (pSectNd = pIdx->GetNode().GetSectionNode() ))
567 nSttNd = pSectNd->GetIndex();
568 nCnt = pSectNd->EndOfSectionIndex() - nSttNd - 1;
571 delete pFormat;
573 if( nSttNd && pFootnoteEndAtTextEnd )
575 SwNodeIndex aUpdIdx( GetNodes(), nSttNd );
576 GetFootnoteIdxs().UpdateFootnote( aUpdIdx.GetNode() );
579 SwContentNode* pCNd;
580 for( ; nCnt--; ++nSttNd )
581 if( nullptr != (pCNd = GetNodes()[ nSttNd ]->GetContentNode() ) &&
582 RES_CONDTXTFMTCOLL == pCNd->GetFormatColl()->Which() )
583 pCNd->ChkCondColl();
586 GetIDocumentUndoRedo().EndUndo(SwUndoId::DELSECTION, nullptr);
588 if (GetIDocumentUndoRedo().DoesUndo())
589 { // TODO is this ever needed?
590 getIDocumentState().SetModified();
594 void SwDoc::UpdateSection( size_t const nPos, SwSectionData & rNewData,
595 SfxItemSet const*const pAttr, bool const bPreventLinkUpdate )
597 SwSectionFormat* pFormat = (*mpSectionFormatTable)[ nPos ];
598 SwSection* pSection = pFormat->GetSection();
600 /// remember hidden condition flag of SwSection before changes
601 bool bOldCondHidden = pSection->IsCondHidden();
603 if (pSection->DataEquals(rNewData))
605 // Check Attributes
606 bool bOnlyAttrChg = false;
607 if( pAttr && pAttr->Count() )
609 SfxItemIter aIter( *pAttr );
610 const SfxPoolItem* pItem = aIter.GetCurItem();
613 if (pFormat->GetFormatAttr(pItem->Which()) != *pItem)
615 bOnlyAttrChg = true;
616 break;
619 pItem = aIter.NextItem();
620 } while (pItem);
623 if( bOnlyAttrChg )
625 if (GetIDocumentUndoRedo().DoesUndo())
627 GetIDocumentUndoRedo().AppendUndo(
628 MakeUndoUpdateSection( *pFormat, true ) );
630 // #i32968# Inserting columns in the section causes MakeFrameFormat
631 // to put two objects of type SwUndoFrameFormat on the undo stack.
632 // We don't want them.
633 ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
634 pFormat->SetFormatAttr( *pAttr );
635 getIDocumentState().SetModified();
637 return;
640 // Test if the whole Content Section (Document/TableBox/Fly) should be hidden,
641 // which we're currently not able to do.
642 const SwNodeIndex* pIdx = nullptr;
644 if (rNewData.IsHidden())
646 pIdx = pFormat->GetContent().GetContentIdx();
647 if (pIdx)
649 const SwSectionNode* pSectNd =
650 pIdx->GetNode().GetSectionNode();
651 if (pSectNd)
653 ::lcl_CheckEmptyLayFrame( GetNodes(), rNewData,
654 *pSectNd, *pSectNd->EndOfSectionNode() );
660 if (GetIDocumentUndoRedo().DoesUndo())
662 GetIDocumentUndoRedo().AppendUndo(MakeUndoUpdateSection(*pFormat, false));
664 // #i32968# Inserting columns in the section causes MakeFrameFormat to put two
665 // objects of type SwUndoFrameFormat on the undo stack. We don't want them.
666 ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
668 // The LinkFileName could only consist of separators
669 OUString sCompareString = OUStringChar(sfx2::cTokenSeparator) + OUStringChar(sfx2::cTokenSeparator);
670 const bool bUpdate =
671 (!pSection->IsLinkType() && rNewData.IsLinkType())
672 || (!rNewData.GetLinkFileName().isEmpty()
673 && (rNewData.GetLinkFileName() != sCompareString)
674 && (rNewData.GetLinkFileName() != pSection->GetLinkFileName()));
676 OUString sSectName( rNewData.GetSectionName() );
677 if (sSectName != pSection->GetSectionName())
678 sSectName = GetUniqueSectionName( &sSectName );
679 else
680 sSectName.clear();
682 /// In SwSection::operator=(..) class member m_bCondHiddenFlag is always set to true.
683 /// IMHO this have to be changed, but I can't estimate the consequences:
684 /// Either it is set to true using corresponding method <SwSection.SetCondHidden(..)>,
685 /// or it is set to the value of SwSection which is assigned to it.
686 /// Discussion with AMA results that the adjustment to the assignment operator
687 /// could be very risky.
688 pSection->SetSectionData(rNewData);
690 if( pAttr )
691 pSection->GetFormat()->SetFormatAttr( *pAttr );
693 if( !sSectName.isEmpty() )
695 pSection->SetSectionName( sSectName );
698 // Is a Condition set
699 if( pSection->IsHidden() && !pSection->GetCondition().isEmpty() )
701 // Then calculate up to that position
702 SwCalc aCalc( *this );
703 if( !pIdx )
704 pIdx = pFormat->GetContent().GetContentIdx();
705 getIDocumentFieldsAccess().FieldsToCalc(aCalc, pIdx->GetIndex(), SAL_MAX_INT32);
707 /// Because on using SwSection::operator=() to set up <pSection>
708 /// with <rNewData> and the above given note, the hidden condition flag
709 /// has to be set to false, if hidden condition flag of <pFormat->GetSection()>
710 /// (SwSection before the changes) is false (already saved in <bOldCondHidden>)
711 /// and new calculated condition is true.
712 /// This is necessary, because otherwise the <SetCondHidden> would have
713 /// no effect.
714 bool bCalculatedCondHidden =
715 aCalc.Calculate( pSection->GetCondition() ).GetBool();
716 if ( bCalculatedCondHidden && !bOldCondHidden )
718 pSection->SetCondHidden( false );
720 pSection->SetCondHidden( bCalculatedCondHidden );
723 if( bUpdate )
724 pSection->CreateLink( bPreventLinkUpdate ? LinkCreateType::Connect : LinkCreateType::Update );
725 else if( !pSection->IsLinkType() && pSection->IsConnected() )
727 pSection->Disconnect();
728 getIDocumentLinksAdministration().GetLinkManager().Remove( &pSection->GetBaseLink() );
731 getIDocumentState().SetModified();
734 void sw_DeleteFootnote( SwSectionNode *pNd, SwNodeOffset nStt, SwNodeOffset nEnd )
736 SwFootnoteIdxs& rFootnoteArr = pNd->GetDoc().GetFootnoteIdxs();
737 if( rFootnoteArr.empty() )
738 return;
740 size_t nPos = 0;
741 rFootnoteArr.SeekEntry( *pNd, &nPos );
742 SwTextFootnote* pSrch;
744 // Delete all succeeding Footnotes
745 while( nPos < rFootnoteArr.size() &&
746 SwTextFootnote_GetIndex( (pSrch = rFootnoteArr[ nPos ]) ) <= nEnd )
748 // If the Nodes are not deleted, they need to deregister at the Pages
749 // (delete Frames) or else they will remain there (Undo does not delete them!)
750 pSrch->DelFrames(nullptr);
751 ++nPos;
754 while( nPos-- &&
755 SwTextFootnote_GetIndex( (pSrch = rFootnoteArr[ nPos ]) ) >= nStt )
757 // If the Nodes are not deleted, they need to deregister at the Pages
758 // (delete Frames) or else they will remain there (Undo does not delete them!)
759 pSrch->DelFrames(nullptr);
763 static bool lcl_IsTOXSection(SwSectionData const& rSectionData)
765 return (SectionType::ToxContent == rSectionData.GetType())
766 || (SectionType::ToxHeader == rSectionData.GetType());
769 SwSectionNode* SwNodes::InsertTextSection(SwNode& rNd,
770 SwSectionFormat& rSectionFormat,
771 SwSectionData const& rSectionData,
772 SwTOXBase const*const pTOXBase,
773 SwNode const*const pEndNd,
774 bool const bInsAtStart, bool const bCreateFrames)
776 SwNodeIndex aInsPos( rNd );
777 if( !pEndNd ) // No Area, thus create a new Section before/after it
779 // #i26762#
780 OSL_ENSURE(!pEndNd || rNd.GetIndex() <= pEndNd->GetIndex(),
781 "Section start and end in wrong order!");
783 if( bInsAtStart )
785 if (!lcl_IsTOXSection(rSectionData))
787 do {
788 --aInsPos;
789 } while( aInsPos.GetNode().IsSectionNode() );
790 ++aInsPos;
793 else
795 ++aInsPos;
796 if (!lcl_IsTOXSection(rSectionData))
798 SwNode* pNd;
799 while( aInsPos.GetIndex() < Count() - 1 &&
800 ( pNd = &aInsPos.GetNode())->IsEndNode() &&
801 pNd->StartOfSectionNode()->IsSectionNode())
803 ++aInsPos;
809 SwSectionNode *const pSectNd =
810 new SwSectionNode(aInsPos.GetNode(), rSectionFormat, pTOXBase);
812 if (lcl_IsTOXSection(rSectionData))
814 // We're inserting a ToX. Make sure that if a redline ends right before the ToX start, then
815 // that end now doesn't cross a section start node.
816 SwRedlineTable& rRedlines = GetDoc().getIDocumentRedlineAccess().GetRedlineTable();
817 for (SwRedlineTable::size_type nIndex = 0; nIndex < rRedlines.size(); ++nIndex)
819 SwRangeRedline* pRedline = rRedlines[nIndex];
820 if ( RedlineType::Delete != pRedline->GetType() ||
821 !pRedline->HasMark() || pRedline->GetMark()->GetNode() != aInsPos.GetNode() )
823 continue;
826 // The redline ends at the new section content start, so it originally ended before the
827 // section start: move it back.
828 SwPaM aRedlineEnd(*pRedline->GetMark());
829 aRedlineEnd.Move(fnMoveBackward);
830 *pRedline->GetMark() = *aRedlineEnd.GetPoint();
831 break;
835 if( pEndNd )
837 // Special case for the Reader/Writer
838 if( *pEndNd != GetEndOfContent() )
839 aInsPos = pEndNd->GetIndex()+1;
840 // #i58710: We created a RTF document with a section break inside a table cell
841 // We are not able to handle a section start inside a table and the section end outside.
842 const SwNode* pLastNode = pSectNd->StartOfSectionNode()->EndOfSectionNode();
843 if( aInsPos > pLastNode->GetIndex() )
844 aInsPos = pLastNode->GetIndex();
845 // Another way round: if the section starts outside a table but the end is inside...
846 // aInsPos is at the moment the Position where my EndNode will be inserted
847 const SwStartNode* pStartNode = aInsPos.GetNode().StartOfSectionNode();
848 // This StartNode should be in front of me, but if not, I want to survive
849 SwNodeOffset nMyIndex = pSectNd->GetIndex();
850 if( pStartNode->GetIndex() > nMyIndex ) // Suspicious!
852 const SwNode* pTemp;
855 pTemp = pStartNode; // pTemp is a suspicious one
856 pStartNode = pStartNode->StartOfSectionNode();
858 while( pStartNode->GetIndex() > nMyIndex );
859 pTemp = pTemp->EndOfSectionNode();
860 // If it starts behind me but ends behind my end...
861 if( pTemp->GetIndex() >= aInsPos.GetIndex() )
862 aInsPos = pTemp->GetIndex()+1; // ...I have to correct my end position
865 else
867 SwTextNode* pCpyTNd = rNd.GetTextNode();
868 if( pCpyTNd )
870 SwTextNode* pTNd = new SwTextNode( aInsPos.GetNode(), pCpyTNd->GetTextColl() );
871 if( pCpyTNd->HasSwAttrSet() )
873 // Move PageDesc/Break to the first Node of the section
874 const SfxItemSet& rSet = *pCpyTNd->GetpSwAttrSet();
875 if( SfxItemState::SET == rSet.GetItemState( RES_BREAK ) ||
876 SfxItemState::SET == rSet.GetItemState( RES_PAGEDESC ))
878 SfxItemSet aSet( rSet );
879 if( bInsAtStart )
880 pCpyTNd->ResetAttr( RES_PAGEDESC, RES_BREAK );
881 else
883 aSet.ClearItem( RES_PAGEDESC );
884 aSet.ClearItem( RES_BREAK );
886 pTNd->SetAttr( aSet );
888 else
889 pTNd->SetAttr( rSet );
891 // Do not forget to create the Frame!
892 pCpyTNd->MakeFramesForAdjacentContentNode(*pTNd);
894 else
895 new SwTextNode( aInsPos.GetNode(), GetDoc().GetDfltTextFormatColl() );
897 new SwEndNode( aInsPos.GetNode(), *pSectNd );
899 pSectNd->GetSection().SetSectionData(rSectionData);
900 SwSectionFormat* pSectFormat = pSectNd->GetSection().GetFormat();
902 // We could optimize this, by not removing already contained Frames and recreating them,
903 // but by simply rewiring them
904 bool bInsFrame = bCreateFrames && !pSectNd->GetSection().IsHiddenFlag() &&
905 GetDoc().getIDocumentLayoutAccess().GetCurrentViewShell();
906 std::optional<SwNode2LayoutSaveUpperFrames> oNode2Layout;
907 if( bInsFrame )
909 if( !pSectNd->GetNodes().FindPrvNxtFrameNode( *pSectNd, pSectNd->EndOfSectionNode() ) )
910 // Collect all Uppers
911 oNode2Layout.emplace(*pSectNd);
914 // Set the right StartNode for all in this Area
915 SwNodeOffset nEnd = pSectNd->EndOfSectionIndex();
916 SwNodeOffset nStart = pSectNd->GetIndex()+1;
917 SwNodeOffset nSkipIdx = NODE_OFFSET_MAX;
918 for( SwNodeOffset n = nStart; n < nEnd; ++n )
920 SwNode* pNd = (*this)[n];
922 // Attach all Sections in the NodeSection underneath the new one
923 if( NODE_OFFSET_MAX == nSkipIdx )
924 pNd->m_pStartOfSection = pSectNd;
925 else if( n >= nSkipIdx )
926 nSkipIdx = NODE_OFFSET_MAX;
928 if( pNd->IsStartNode() )
930 // Make up the Format's nesting
931 if( pNd->IsSectionNode() )
933 static_cast<SwSectionNode*>(pNd)->GetSection().GetFormat()->
934 SetDerivedFrom( pSectFormat );
935 static_cast<SwSectionNode*>(pNd)->DelFrames();
936 n = pNd->EndOfSectionIndex();
938 else
940 if( pNd->IsTableNode() )
941 static_cast<SwTableNode*>(pNd)->DelFrames();
943 if( NODE_OFFSET_MAX == nSkipIdx )
944 nSkipIdx = pNd->EndOfSectionIndex();
947 else if( pNd->IsContentNode() )
948 static_cast<SwContentNode*>(pNd)->DelFrames(nullptr);
951 sw_DeleteFootnote( pSectNd, nStart, nEnd );
953 if( bInsFrame )
955 if( oNode2Layout )
957 SwNodeOffset nIdx = pSectNd->GetIndex();
958 oNode2Layout->RestoreUpperFrames( pSectNd->GetNodes(), nIdx, nIdx + 1 );
959 oNode2Layout.reset();
961 else
962 pSectNd->MakeOwnFrames(&aInsPos);
965 return pSectNd;
968 SwSectionNode* SwNode::FindSectionNode()
970 if( IsSectionNode() )
971 return GetSectionNode();
972 SwStartNode* pTmp = m_pStartOfSection;
973 while( !pTmp->IsSectionNode() && pTmp->GetIndex() )
974 pTmp = pTmp->m_pStartOfSection;
975 return pTmp->GetSectionNode();
978 // SwSectionNode
980 // ugly hack to make m_pSection const
981 static SwSectionFormat &
982 lcl_initParent(SwSectionNode & rThis, SwSectionFormat & rFormat)
984 SwSectionNode *const pParent =
985 rThis.StartOfSectionNode()->FindSectionNode();
986 if( pParent )
988 // Register the Format at the right Parent
989 rFormat.SetDerivedFrom( pParent->GetSection().GetFormat() );
991 return rFormat;
994 SwSectionNode::SwSectionNode(const SwNode& rWhere,
995 SwSectionFormat & rFormat, SwTOXBase const*const pTOXBase)
996 : SwStartNode( rWhere, SwNodeType::Section )
997 , m_pSection( pTOXBase
998 ? new SwTOXBaseSection(*pTOXBase, lcl_initParent(*this, rFormat))
999 : new SwSection( SectionType::Content, rFormat.GetName(),
1000 lcl_initParent(*this, rFormat) ) )
1002 // Set the connection from Format to Node
1003 // Suppress Modify; no one's interested anyway
1004 rFormat.LockModify();
1005 rFormat.SetFormatAttr( SwFormatContent( this ) );
1006 rFormat.UnlockModify();
1009 SwSectionNode::~SwSectionNode()
1011 // mba: test if iteration works as clients will be removed in callback
1012 // use hint which allows to specify, if the content shall be saved or not
1013 m_pSection->GetFormat()->CallSwClientNotify( SwSectionFrameMoveAndDeleteHint( true ) );
1014 SwSectionFormat* pFormat = m_pSection->GetFormat();
1015 if( pFormat )
1017 // Remove the Attribute, because the Section deletes it's Format
1018 // and it will neutralize the Section, if the Content Attribute is set
1019 pFormat->LockModify();
1020 pFormat->ResetFormatAttr( RES_CNTNT );
1021 pFormat->UnlockModify();
1025 SwFrame *SwSectionNode::MakeFrame( SwFrame *pSib )
1027 m_pSection->m_Data.SetHiddenFlag(false);
1028 return new SwSectionFrame( *m_pSection, pSib );
1031 // Creates all Document Views for the preceding Node.
1032 // The created ContentFrames are attached to the corresponding Layout
1033 void SwSectionNode::MakeFramesForAdjacentContentNode(const SwNodeIndex & rIdx)
1035 // Take my successive or preceding ContentFrame
1036 SwNodes& rNds = GetNodes();
1037 if( !(rNds.IsDocNodes() && rNds.GetDoc().getIDocumentLayoutAccess().GetCurrentViewShell()) )
1038 return;
1040 if (GetSection().IsHiddenFlag() || IsContentHidden())
1042 SwNodeIndex aIdx( *EndOfSectionNode() );
1043 SwContentNode* pCNd = rNds.GoNextSection( &aIdx, true, false );
1044 if( !pCNd )
1046 aIdx = *this;
1047 pCNd = SwNodes::GoPrevSection(&aIdx, true, false);
1048 if (!pCNd)
1049 return;
1051 pCNd = aIdx.GetNode().GetContentNode();
1052 pCNd->MakeFramesForAdjacentContentNode(static_cast<SwContentNode&>(rIdx.GetNode()));
1054 else
1056 SwNode2Layout aNode2Layout( *this, rIdx.GetIndex() );
1057 SwFrame *pFrame;
1058 while( nullptr != (pFrame = aNode2Layout.NextFrame()) )
1060 OSL_ENSURE( pFrame->IsSctFrame(), "Depend of Section not a Section." );
1061 if (pFrame->getRootFrame()->HasMergedParas()
1062 && !rIdx.GetNode().IsCreateFrameWhenHidingRedlines())
1064 continue;
1066 SwFrame *pNew = rIdx.GetNode().GetContentNode()->MakeFrame( pFrame );
1068 SwSectionNode* pS = rIdx.GetNode().FindSectionNode();
1070 // Assure that node is not inside a table, which is inside the
1071 // found section.
1072 if ( pS )
1074 SwTableNode* pTableNode = rIdx.GetNode().FindTableNode();
1075 if ( pTableNode &&
1076 pTableNode->GetIndex() > pS->GetIndex() )
1078 pS = nullptr;
1082 // if the node is in a section, the sectionframe now
1083 // has to be created...
1084 // boolean to control <Init()> of a new section frame.
1085 bool bInitNewSect = false;
1086 if( pS )
1088 SwSectionFrame *pSct = new SwSectionFrame( pS->GetSection(), pFrame );
1089 // prepare <Init()> of new section frame.
1090 bInitNewSect = true;
1091 SwLayoutFrame* pUp = pSct;
1092 while( pUp->Lower() ) // for columned sections
1094 OSL_ENSURE( pUp->Lower()->IsLayoutFrame(),"Who's in there?" );
1095 pUp = static_cast<SwLayoutFrame*>(pUp->Lower());
1097 pNew->Paste( pUp );
1098 // #i27138#
1099 // notify accessibility paragraphs objects about changed
1100 // CONTENT_FLOWS_FROM/_TO relation.
1101 // Relation CONTENT_FLOWS_FROM for next paragraph will change
1102 // and relation CONTENT_FLOWS_TO for previous paragraph will change.
1103 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
1104 if ( pNew->IsTextFrame() )
1106 SwViewShell* pViewShell( pNew->getRootFrame()->GetCurrShell() );
1107 if ( pViewShell && pViewShell->GetLayout() &&
1108 pViewShell->GetLayout()->IsAnyShellAccessible() )
1110 auto pNext = pNew->FindNextCnt( true );
1111 auto pPrev = pNew->FindPrevCnt();
1112 pViewShell->InvalidateAccessibleParaFlowRelation(
1113 pNext ? pNext->DynCastTextFrame() : nullptr,
1114 pPrev ? pPrev->DynCastTextFrame() : nullptr );
1117 #endif
1118 pNew = pSct;
1121 // If a Node got Frames attached before or after
1122 if ( rIdx < GetIndex() )
1123 // the new one precedes me
1124 pNew->Paste( pFrame->GetUpper(), pFrame );
1125 else
1126 // the new one succeeds me
1127 pNew->Paste( pFrame->GetUpper(), pFrame->GetNext() );
1128 // #i27138#
1129 // notify accessibility paragraphs objects about changed
1130 // CONTENT_FLOWS_FROM/_TO relation.
1131 // Relation CONTENT_FLOWS_FROM for next paragraph will change
1132 // and relation CONTENT_FLOWS_TO for previous paragraph will change.
1133 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
1134 if ( pNew->IsTextFrame() )
1136 SwViewShell* pViewShell( pNew->getRootFrame()->GetCurrShell() );
1137 if ( pViewShell && pViewShell->GetLayout() &&
1138 pViewShell->GetLayout()->IsAnyShellAccessible() )
1140 auto pNext = pNew->FindNextCnt( true );
1141 auto pPrev = pNew->FindPrevCnt();
1142 pViewShell->InvalidateAccessibleParaFlowRelation(
1143 pNext ? pNext->DynCastTextFrame() : nullptr,
1144 pPrev ? pPrev->DynCastTextFrame() : nullptr );
1147 #endif
1148 if ( bInitNewSect )
1149 static_cast<SwSectionFrame*>(pNew)->Init();
1154 // Create a new SectionFrame for every occurrence in the Layout and insert before
1155 // the corresponding ContentFrame
1156 void SwSectionNode::MakeOwnFrames(SwNodeIndex* pIdxBehind, SwNodeIndex* pEndIdx)
1158 OSL_ENSURE( pIdxBehind, "no Index" );
1159 SwNodes& rNds = GetNodes();
1160 SwDoc& rDoc = rNds.GetDoc();
1162 *pIdxBehind = *this;
1164 m_pSection->m_Data.SetHiddenFlag(true);
1166 if( rNds.IsDocNodes() )
1168 if( pEndIdx )
1169 ::MakeFrames( &rDoc, pIdxBehind->GetNode(), pEndIdx->GetNode() );
1170 else
1171 ::MakeFrames( &rDoc, pIdxBehind->GetNode(), SwNodeIndex( *EndOfSectionNode(), 1 ).GetNode() );
1175 void SwSectionNode::DelFrames(SwRootFrame const*const /*FIXME TODO*/, bool const bForce)
1177 SwNodeOffset nStt = GetIndex()+1, nEnd = EndOfSectionIndex();
1178 if( nStt >= nEnd )
1180 return ;
1183 SwNodes& rNds = GetNodes();
1184 m_pSection->GetFormat()->DelFrames();
1186 // Update our Flag
1187 m_pSection->m_Data.SetHiddenFlag(true);
1189 // If the Area is within a Fly or TableBox, we can only hide it if
1190 // there is more Content which has Frames.
1191 // Or else the Fly/TableBox Frame does not have a Lower!
1192 if (bForce)
1193 return;
1195 SwNodeIndex aIdx( *this );
1196 if( !SwNodes::GoPrevSection( &aIdx, true, false ) ||
1197 !CheckNodesRange( *this, aIdx.GetNode(), true ) ||
1198 // #i21457#
1199 !lcl_IsInSameTableBox( rNds, *this, true ))
1201 aIdx = *EndOfSectionNode();
1202 if( !rNds.GoNextSection( &aIdx, true, false ) ||
1203 !CheckNodesRange( *EndOfSectionNode(), aIdx.GetNode(), true ) ||
1204 // #i21457#
1205 !lcl_IsInSameTableBox( rNds, *EndOfSectionNode(), false ))
1207 m_pSection->m_Data.SetHiddenFlag(false);
1212 SwSectionNode* SwSectionNode::MakeCopy( SwDoc& rDoc, const SwNodeIndex& rIdx ) const
1214 // In which array am I: Nodes, UndoNodes?
1215 const SwNodes& rNds = GetNodes();
1217 // Copy the SectionFrameFormat
1218 SwSectionFormat* pSectFormat = rDoc.MakeSectionFormat();
1219 pSectFormat->CopyAttrs( *GetSection().GetFormat() );
1221 std::unique_ptr<SwTOXBase> pTOXBase;
1222 if (SectionType::ToxContent == GetSection().GetType())
1224 assert( dynamic_cast< const SwTOXBaseSection* >( &GetSection() ) && "no TOXBaseSection!" );
1225 SwTOXBaseSection const& rTBS(
1226 dynamic_cast<SwTOXBaseSection const&>(GetSection()));
1227 pTOXBase.reset( new SwTOXBase(rTBS, &rDoc) );
1230 SwSectionNode *const pSectNd =
1231 new SwSectionNode(rIdx.GetNode(), *pSectFormat, pTOXBase.get());
1232 SwEndNode* pEndNd = new SwEndNode( rIdx.GetNode(), *pSectNd );
1233 SwNodeIndex aInsPos( *pEndNd );
1235 // Take over values
1236 SwSection *const pNewSect = pSectNd->m_pSection.get();
1238 if (SectionType::ToxContent != GetSection().GetType())
1240 // Keep the Name for Move
1241 if( &rNds.GetDoc() == &rDoc && rDoc.IsCopyIsMove() )
1243 pNewSect->SetSectionName( GetSection().GetSectionName() );
1245 else
1247 const OUString sSectionName(GetSection().GetSectionName());
1248 pNewSect->SetSectionName(rDoc.GetUniqueSectionName( &sSectionName ));
1252 pNewSect->SetType( GetSection().GetType() );
1253 pNewSect->SetCondition( GetSection().GetCondition() );
1254 pNewSect->SetCondHidden( GetSection().IsCondHidden() );
1255 pNewSect->SetLinkFileName( GetSection().GetLinkFileName() );
1256 if( !pNewSect->IsHiddenFlag() && GetSection().IsHidden() )
1257 pNewSect->SetHidden();
1258 if( !pNewSect->IsProtectFlag() && GetSection().IsProtect() )
1259 pNewSect->SetProtect();
1260 // edit in readonly sections
1261 if( !pNewSect->IsEditInReadonlyFlag() && GetSection().IsEditInReadonly() )
1262 pNewSect->SetEditInReadonly();
1264 SwNodeRange aRg( *this, SwNodeOffset(+1), *EndOfSectionNode() ); // Where am I?
1265 rNds.Copy_( aRg, aInsPos.GetNode(), false );
1267 // Delete all Frames from the copied Area. They are created when creating
1268 // the SectionFrames.
1269 pSectNd->DelFrames();
1271 // Copy the Links/Server
1272 if( pNewSect->IsLinkType() ) // Add the Link
1273 pNewSect->CreateLink( rDoc.getIDocumentLayoutAccess().GetCurrentViewShell() ? LinkCreateType::Connect : LinkCreateType::NONE );
1275 // If we copy from the Undo as Server, enter it again
1276 if (m_pSection->IsServer()
1277 && rDoc.GetIDocumentUndoRedo().IsUndoNodes(rNds))
1279 pNewSect->SetRefObject( m_pSection->GetObject() );
1280 rDoc.getIDocumentLinksAdministration().GetLinkManager().InsertServer( pNewSect->GetObject() );
1283 // METADATA: copy xml:id; must be done after insertion of node
1284 pSectFormat->RegisterAsCopyOf(*GetSection().GetFormat());
1286 return pSectNd;
1289 bool SwSectionNode::IsContentHidden() const
1291 OSL_ENSURE( !m_pSection->IsHidden(),
1292 "That's simple: Hidden Section => Hidden Content" );
1293 SwNodeIndex aTmp( *this, 1 );
1294 SwNodeOffset nEnd = EndOfSectionIndex();
1295 while( aTmp < nEnd )
1297 if( aTmp.GetNode().IsSectionNode() )
1299 const SwSection& rSect = static_cast<SwSectionNode&>(aTmp.GetNode()).GetSection();
1300 if( rSect.IsHiddenFlag() )
1301 // Skip this Section
1302 aTmp = *aTmp.GetNode().EndOfSectionNode();
1304 else
1306 if( aTmp.GetNode().IsContentNode() || aTmp.GetNode().IsTableNode() )
1307 return false; // We found non-hidden content
1308 OSL_ENSURE( aTmp.GetNode().IsEndNode(), "EndNode expected" );
1310 ++aTmp;
1312 return true; // Hide everything
1315 void SwSectionNode::dumpAsXml(xmlTextWriterPtr pWriter) const
1317 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("section"));
1318 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
1319 (void)xmlTextWriterWriteAttribute(
1320 pWriter, BAD_CAST("type"),
1321 BAD_CAST(OString::number(static_cast<sal_uInt8>(GetNodeType())).getStr()));
1322 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("index"),
1323 BAD_CAST(OString::number(sal_Int32(GetIndex())).getStr()));
1325 if (m_pSection)
1327 m_pSection->dumpAsXml(pWriter);
1330 // (void)xmlTextWriterEndElement(pWriter); - it is a start node, so don't end, will make xml better nested
1333 void SwSectionNode::NodesArrChgd()
1335 SwSectionFormat *const pFormat = m_pSection->GetFormat();
1336 if( !pFormat )
1337 return;
1339 SwNodes& rNds = GetNodes();
1340 SwDoc* pDoc = pFormat->GetDoc();
1342 if( !rNds.IsDocNodes() )
1344 pFormat->RemoveAllUnos();
1347 pFormat->LockModify();
1348 pFormat->SetFormatAttr( SwFormatContent( this ));
1349 pFormat->UnlockModify();
1351 SwSectionNode* pSectNd = StartOfSectionNode()->FindSectionNode();
1352 // set the correct parent from the new section
1353 pFormat->SetDerivedFrom( pSectNd ? pSectNd->GetSection().GetFormat()
1354 : pDoc->GetDfltFrameFormat() );
1356 // Set the right StartNode for all in this Area
1357 SwNodeOffset nStart = GetIndex()+1, nEnd = EndOfSectionIndex();
1358 for( SwNodeOffset n = nStart; n < nEnd; ++n )
1360 // Make up the Format's nesting
1361 pSectNd = rNds[ n ]->GetSectionNode();
1362 if( nullptr != pSectNd )
1364 pSectNd->GetSection().GetFormat()->SetDerivedFrom( pFormat );
1365 n = pSectNd->EndOfSectionIndex();
1369 // Moving Nodes to the UndoNodes array?
1370 if( rNds.IsDocNodes() )
1372 OSL_ENSURE( pDoc == &GetDoc(),
1373 "Moving to different Documents?" );
1374 if( m_pSection->IsLinkType() ) // Remove the Link
1375 m_pSection->CreateLink( pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() ? LinkCreateType::Connect : LinkCreateType::NONE );
1377 if (m_pSection->IsServer())
1378 pDoc->getIDocumentLinksAdministration().GetLinkManager().InsertServer( m_pSection->GetObject() );
1380 else
1382 if (SectionType::Content != m_pSection->GetType()
1383 && m_pSection->IsConnected())
1385 pDoc->getIDocumentLinksAdministration().GetLinkManager().Remove( &m_pSection->GetBaseLink() );
1387 if (m_pSection->IsServer())
1388 pDoc->getIDocumentLinksAdministration().GetLinkManager().RemoveServer( m_pSection->GetObject() );
1393 OUString SwDoc::GetUniqueSectionName( const OUString* pChkStr ) const
1395 if( IsInMailMerge())
1397 OUString newName = "MailMergeSection"
1398 + OStringToOUString( DateTimeToOString( DateTime( DateTime::SYSTEM )), RTL_TEXTENCODING_ASCII_US )
1399 + OUString::number( mpSectionFormatTable->size() + 1 );
1400 if( pChkStr )
1401 newName += *pChkStr;
1402 return newName;
1405 const OUString aName(SwResId(STR_REGION_DEFNAME));
1407 SwSectionFormats::size_type nNum = 0;
1408 const SwSectionFormats::size_type nFlagSize = ( mpSectionFormatTable->size() / 8 ) + 2;
1409 std::unique_ptr<sal_uInt8[]> pSetFlags(new sal_uInt8[ nFlagSize ]);
1410 memset( pSetFlags.get(), 0, nFlagSize );
1412 for( auto pFormat : *mpSectionFormatTable )
1414 const SwSectionNode *const pSectNd = pFormat->GetSectionNode();
1415 if( pSectNd != nullptr )
1417 const OUString& rNm = pSectNd->GetSection().GetSectionName();
1418 if (rNm.startsWith( aName ))
1420 // Calculate the Number and reset the Flag
1421 nNum = o3tl::toInt32(rNm.subView( aName.getLength() ));
1422 if( nNum-- && nNum < mpSectionFormatTable->size() )
1423 pSetFlags[ nNum / 8 ] |= (0x01 << ( nNum & 0x07 ));
1425 if( pChkStr && *pChkStr==rNm )
1426 pChkStr = nullptr;
1430 if( !pChkStr )
1432 // Flagged all Numbers accordingly, so get the right Number
1433 nNum = mpSectionFormatTable->size();
1434 for( SwSectionFormats::size_type n = 0; n < nFlagSize; ++n )
1436 auto nTmp = pSetFlags[ n ];
1437 if( nTmp != 0xFF )
1439 // Calculate the Number
1440 nNum = n * 8;
1441 while( nTmp & 1 )
1443 ++nNum;
1444 nTmp >>= 1;
1446 break;
1450 pSetFlags.reset();
1451 if( pChkStr )
1452 return *pChkStr;
1453 return aName + OUString::number( ++nNum );
1456 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */