svx: prefix members of SvxClipboardFormatItem
[LibreOffice.git] / sw / source / core / docnode / ndsect.cxx
blob72c4f40c7f213b921adbabf0445c481094295e5d
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(const SwNode& _rNd, const bool _bPrev)
68 const SwTableNode* pTableNd = _rNd.FindTableNode();
69 if ( !pTableNd )
71 return true;
74 // determine index to be checked. Its assumed that a previous/next exist.
75 SwNodeIndex aChkIdx( _rNd );
77 // determine index of previous/next - skip hidden ones, which are
78 // inside the table.
79 // If found one is before/after table, this one isn't in the same
80 // table box as <_rNd>.
81 for(;;)
83 if ( _bPrev
84 ? !SwNodes::GoPrevSection( &aChkIdx, false, false )
85 : !SwNodes::GoNextSection( &aChkIdx, false, false ) )
87 OSL_FAIL( "<lcl_IsInSameTableBox(..)> - no previous/next!" );
88 return false;
91 if ( aChkIdx < pTableNd->GetIndex() ||
92 aChkIdx > pTableNd->EndOfSectionNode()->GetIndex() )
94 return false;
97 // check, if found one isn't inside a hidden section, which
98 // is also inside the table.
99 SwSectionNode* pSectNd = aChkIdx.GetNode().FindSectionNode();
100 if ( !pSectNd ||
101 pSectNd->GetIndex() < pTableNd->GetIndex() ||
102 !pSectNd->GetSection().IsHiddenFlag() )
104 break;
108 // Find the Box's StartNode
109 const SwTableSortBoxes& rSortBoxes = pTableNd->GetTable().GetTabSortBoxes();
110 SwNodeOffset nIdx = _rNd.GetIndex();
111 for (size_t n = 0; n < rSortBoxes.size(); ++n)
113 const SwStartNode* pNd = rSortBoxes[ n ]->GetSttNd();
114 if ( pNd->GetIndex() < nIdx && nIdx < pNd->EndOfSectionIndex() )
116 // The other index needs to be within the same Section
117 nIdx = aChkIdx.GetIndex();
118 return pNd->GetIndex() < nIdx && nIdx < pNd->EndOfSectionIndex();
122 return true;
125 static void lcl_CheckEmptyLayFrame( SwSectionData& rSectionData,
126 const SwNode& rStt, const SwNode& rEnd )
128 SwNodeIndex aIdx( rStt );
129 if( !SwNodes::GoPrevSection( &aIdx, true, false ) ||
130 !CheckNodesRange( rStt, aIdx.GetNode(), true ) ||
131 // #i21457#
132 !lcl_IsInSameTableBox( rStt, true ))
134 aIdx = rEnd;
135 if( !SwNodes::GoNextSection( &aIdx, true, false ) ||
136 !CheckNodesRange( rEnd, aIdx.GetNode(), true ) ||
137 // #i21457#
138 !lcl_IsInSameTableBox( rEnd, false ))
140 rSectionData.SetHidden( false );
145 SwSection *
146 SwDoc::InsertSwSection(SwPaM const& rRange, SwSectionData & rNewData,
147 std::tuple<SwTOXBase const*, sw::RedlineMode, sw::FieldmarkMode, sw::ParagraphBreakMode> const*const pTOXBaseAndMode,
148 SfxItemSet const*const pAttr, bool const bUpdate)
150 const SwNode* pPrvNd = nullptr;
151 sal_uInt16 nRegionRet = 0;
152 if( rRange.HasMark() )
154 nRegionRet = IsInsRegionAvailable( rRange, &pPrvNd );
155 if( 0 == nRegionRet )
157 // demoted to info because this is called from SwXTextSection::attach,
158 // so it could be invalid input
159 SAL_INFO("sw.core" , "InsertSwSection: rRange overlaps other sections");
160 return nullptr;
164 // See if the whole Document should be hidden, which we currently are not able to do.
165 if (rNewData.IsHidden() && rRange.HasMark())
167 auto [pStart, pEnd] = rRange.StartEnd(); // SwPosition*
168 if( !pStart->GetContentIndex() &&
169 pEnd->GetNode().GetContentNode()->Len() ==
170 pEnd->GetContentIndex() )
172 ::lcl_CheckEmptyLayFrame(
173 rNewData,
174 pStart->GetNode(),
175 pEnd->GetNode() );
179 SwUndoInsSection* pUndoInsSect = nullptr;
180 bool const bUndo(GetIDocumentUndoRedo().DoesUndo());
181 if (bUndo)
183 pUndoInsSect = new SwUndoInsSection(rRange, rNewData, pAttr, pTOXBaseAndMode);
184 GetIDocumentUndoRedo().AppendUndo( std::unique_ptr<SwUndo>(pUndoInsSect) );
185 GetIDocumentUndoRedo().DoUndo(false);
188 SwSectionFormat* const pFormat = MakeSectionFormat();
189 pFormat->SetFormatName(rNewData.GetSectionName());
190 if ( pAttr )
192 pFormat->SetFormatAttr( *pAttr );
195 SwTOXBase const*const pTOXBase(pTOXBaseAndMode ? std::get<0>(*pTOXBaseAndMode) : nullptr);
196 SwSectionNode* pNewSectNode = nullptr;
198 RedlineFlags eOld = getIDocumentRedlineAccess().GetRedlineFlags();
199 getIDocumentRedlineAccess().SetRedlineFlags_intern( (eOld & ~RedlineFlags::ShowMask) | RedlineFlags::Ignore );
201 if( rRange.HasMark() )
203 auto [pSttPos, pEndPos] = const_cast<SwPaM&>(rRange).StartEnd(); // SwPosition*
204 if( pPrvNd && 3 == nRegionRet )
206 OSL_ENSURE( pPrvNd, "The SectionNode is missing" );
207 SwNodeIndex aStt( pSttPos->GetNode() ), aEnd( pEndPos->GetNode(), +1 );
208 while( pPrvNd != aStt.GetNode().StartOfSectionNode() )
209 --aStt;
210 while( pPrvNd != aEnd.GetNode().StartOfSectionNode() )
211 ++aEnd;
213 --aEnd; // End is inclusive in the InsertSection
214 pNewSectNode = GetNodes().InsertTextSection(
215 aStt.GetNode(), *pFormat, rNewData, pTOXBase, & aEnd.GetNode());
217 else
219 if( pUndoInsSect )
221 if( !( pPrvNd && 1 == nRegionRet ) &&
222 pSttPos->GetContentIndex() )
224 SwTextNode* const pTNd =
225 pSttPos->GetNode().GetTextNode();
226 if (pTNd)
228 pUndoInsSect->SaveSplitNode( pTNd, true );
232 if ( !( pPrvNd && 2 == nRegionRet ) )
234 SwTextNode *const pTNd =
235 pEndPos->GetNode().GetTextNode();
236 if (pTNd && (pTNd->GetText().getLength()
237 != pEndPos->GetContentIndex()))
239 pUndoInsSect->SaveSplitNode( pTNd, false );
244 if( pPrvNd && 1 == nRegionRet )
246 pSttPos->Assign( *pPrvNd );
248 else if( pSttPos->GetContentIndex() )
250 getIDocumentContentOperations().SplitNode( *pSttPos, false );
253 if( pPrvNd && 2 == nRegionRet )
255 pEndPos->Assign( *pPrvNd );
257 else
259 const SwContentNode* pCNd = pEndPos->GetNode().GetContentNode();
260 if( pCNd && pCNd->Len() != pEndPos->GetContentIndex() )
262 sal_Int32 nContent = pSttPos->GetContentIndex();
263 getIDocumentContentOperations().SplitNode( *pEndPos, false );
265 SwTextNode* pTNd;
266 if( pEndPos->GetNodeIndex() == pSttPos->GetNodeIndex() )
268 pSttPos->Adjust(SwNodeOffset(-1));
269 pEndPos->Adjust(SwNodeOffset(-1));
270 pTNd = pSttPos->GetNode().GetTextNode();
271 pSttPos->SetContent( nContent );
273 else
275 // Set to the end of the previous
276 pEndPos->Adjust(SwNodeOffset(-1));
277 pTNd = pEndPos->GetNode().GetTextNode();
279 nContent = pTNd ? pTNd->GetText().getLength() : 0;
280 pEndPos->SetContent( nContent );
283 pNewSectNode = GetNodes().InsertTextSection(
284 pSttPos->GetNode(), *pFormat, rNewData, pTOXBase, &pEndPos->GetNode());
287 else
289 const SwPosition* pPos = rRange.GetPoint();
290 const SwContentNode* pCNd = pPos->GetNode().GetContentNode();
291 if( !pPos->GetContentIndex() )
293 pNewSectNode = GetNodes().InsertTextSection(
294 pPos->GetNode(), *pFormat, rNewData, pTOXBase, nullptr);
296 else if( pPos->GetContentIndex() == pCNd->Len() )
298 pNewSectNode = GetNodes().InsertTextSection(
299 pPos->GetNode(), *pFormat, rNewData, pTOXBase, nullptr, false);
301 else
303 if (pUndoInsSect)
304 if (const SwTextNode* pTextNode = pCNd->GetTextNode())
305 pUndoInsSect->SaveSplitNode(pTextNode, true);
306 getIDocumentContentOperations().SplitNode( *pPos, false );
307 pNewSectNode = GetNodes().InsertTextSection(
308 pPos->GetNode(), *pFormat, rNewData, pTOXBase, nullptr);
312 pNewSectNode->CheckSectionCondColl();
314 getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld );
316 // To-Do - add 'SwExtraRedlineTable' also ?
317 if( getIDocumentRedlineAccess().IsRedlineOn() || (!getIDocumentRedlineAccess().IsIgnoreRedline() && !getIDocumentRedlineAccess().GetRedlineTable().empty() ))
319 SwPaM aPam( *pNewSectNode->EndOfSectionNode(), *pNewSectNode, SwNodeOffset(1) );
320 if( getIDocumentRedlineAccess().IsRedlineOn() )
322 getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Insert, aPam ), true);
324 else
326 getIDocumentRedlineAccess().SplitRedline( aPam );
330 // Is a Condition set?
331 if (rNewData.IsHidden() && !rNewData.GetCondition().isEmpty())
333 // The calculate up to that position
334 SwCalc aCalc( *this );
335 if( ! IsInReading() )
337 getIDocumentFieldsAccess().FieldsToCalc(aCalc, pNewSectNode->GetIndex(), SAL_MAX_INT32);
339 SwSection& rNewSect = pNewSectNode->GetSection();
340 rNewSect.SetCondHidden( aCalc.Calculate( rNewSect.GetCondition() ).GetBool() );
343 bool bUpdateFootnote = false;
344 if( !GetFootnoteIdxs().empty() && pAttr )
346 sal_uInt16 nVal = pAttr->Get( RES_FTN_AT_TXTEND ).GetValue();
347 if( ( FTNEND_ATTXTEND_OWNNUMSEQ == nVal ||
348 FTNEND_ATTXTEND_OWNNUMANDFMT == nVal ) ||
349 ( FTNEND_ATTXTEND_OWNNUMSEQ == ( nVal = pAttr->Get( RES_END_AT_TXTEND ).GetValue() ) ||
350 FTNEND_ATTXTEND_OWNNUMANDFMT == nVal ))
352 bUpdateFootnote = true;
356 if( pUndoInsSect )
358 pUndoInsSect->SetSectNdPos( pNewSectNode->GetIndex() );
359 pUndoInsSect->SetUpdateFootnoteFlag( bUpdateFootnote );
360 GetIDocumentUndoRedo().DoUndo(bUndo);
363 if (rNewData.IsLinkType())
365 pNewSectNode->GetSection().CreateLink( bUpdate ? LinkCreateType::Update : LinkCreateType::Connect );
368 if( bUpdateFootnote )
370 GetFootnoteIdxs().UpdateFootnote( *pNewSectNode );
373 getIDocumentState().SetModified();
374 return &pNewSectNode->GetSection();
377 sal_uInt16 SwDoc::IsInsRegionAvailable( const SwPaM& rRange,
378 const SwNode** ppSttNd )
380 sal_uInt16 nRet = 1;
381 if( rRange.HasMark() )
383 // See if we have a valid Section
384 auto [pStart, pEnd] = rRange.StartEnd(); // SwPosition*
386 const SwContentNode* pCNd = pEnd->GetNode().GetContentNode();
387 const SwNode* pNd = &pStart->GetNode();
388 const SwSectionNode* pSectNd = pNd->FindSectionNode();
389 const SwSectionNode* pEndSectNd = pCNd ? pCNd->FindSectionNode() : nullptr;
390 if( pSectNd && pEndSectNd && pSectNd != pEndSectNd )
392 // Try to create an enclosing Section, but only if Start is
393 // located at the Section's beginning and End at it's end
394 nRet = 0;
395 if( !pStart->GetContentIndex()
396 && pSectNd->GetIndex() == pStart->GetNodeIndex() - 1
397 && pEnd->GetContentIndex() == pCNd->Len() )
399 SwNodeIndex aIdx( pStart->GetNode(), -1 );
400 SwNodeOffset nCmp = pEnd->GetNodeIndex();
401 const SwStartNode* pPrvNd;
402 const SwEndNode* pNxtNd;
403 while( nullptr != ( pPrvNd = (pNd = &aIdx.GetNode())->GetSectionNode() ) &&
404 ( aIdx.GetIndex() >= nCmp ||
405 nCmp >= pPrvNd->EndOfSectionIndex() ) )
407 --aIdx;
409 if( !pPrvNd )
410 pPrvNd = pNd->IsStartNode() ? static_cast<const SwStartNode*>(pNd)
411 : pNd->StartOfSectionNode();
413 aIdx = pEnd->GetNodeIndex() + 1;
414 nCmp = pStart->GetNodeIndex();
415 while( nullptr != ( pNxtNd = (pNd = &aIdx.GetNode())->GetEndNode() ) &&
416 pNxtNd->StartOfSectionNode()->IsSectionNode() &&
417 ( pNxtNd->StartOfSectionIndex() >= nCmp ||
418 nCmp >= aIdx.GetIndex() ) )
420 ++aIdx;
422 if( !pNxtNd )
423 pNxtNd = pNd->EndOfSectionNode();
425 if( pPrvNd && pNxtNd && pPrvNd == pNxtNd->StartOfSectionNode() )
427 nRet = 3;
429 if( ppSttNd )
430 *ppSttNd = pPrvNd;
434 else if( !pSectNd && pEndSectNd )
436 // Try to create an enclosing Section, but only if the End
437 // is at the Section's end.
438 nRet = 0;
439 if( pEnd->GetContentIndex() == pCNd->Len() )
441 SwNodeIndex aIdx( pEnd->GetNode(), 1 );
442 if( aIdx.GetNode().IsEndNode() &&
443 nullptr != aIdx.GetNode().FindSectionNode() )
445 do {
446 ++aIdx;
447 } while( aIdx.GetNode().IsEndNode() &&
448 nullptr != aIdx.GetNode().FindSectionNode() );
450 nRet = 2;
451 if( ppSttNd )
453 --aIdx;
454 *ppSttNd = &aIdx.GetNode();
460 else if( pSectNd && !pEndSectNd )
462 // Try to create an enclosing Section, but only if Start
463 // is at the Section's start.
464 nRet = 0;
465 if( !pStart->GetContentIndex() )
467 SwNodeIndex aIdx( pStart->GetNode(), -1 );
468 if( aIdx.GetNode().IsSectionNode() )
470 do {
471 --aIdx;
472 } while( aIdx.GetNode().IsSectionNode() );
473 if( !aIdx.GetNode().IsSectionNode() )
475 nRet = 1;
476 if( ppSttNd )
478 ++aIdx;
479 *ppSttNd = &aIdx.GetNode();
486 return nRet;
489 SwSection* SwDoc::GetCurrSection( const SwPosition& rPos )
491 SwSectionNode* pSectNd = rPos.GetNode().FindSectionNode();
492 if( pSectNd )
493 return &pSectNd->GetSection();
494 return nullptr;
497 SwSectionFormat* SwDoc::MakeSectionFormat()
499 SwSectionFormat* pNew = new SwSectionFormat( mpDfltFrameFormat.get(), this );
500 mpSectionFormatTable->push_back( pNew );
501 return pNew;
504 void SwDoc::DelSectionFormat( SwSectionFormat *pFormat, bool bDelNodes )
506 SwSectionFormats::iterator itFormatPos = std::find( mpSectionFormatTable->begin(), mpSectionFormatTable->end(), pFormat );
508 GetIDocumentUndoRedo().StartUndo(SwUndoId::DELSECTION, nullptr);
510 if( mpSectionFormatTable->end() != itFormatPos )
512 const SwNodeIndex* pIdx = pFormat->GetContent( false ).GetContentIdx();
513 const SfxPoolItem* pFootnoteEndAtTextEnd = pFormat->GetItemIfSet(
514 RES_FTN_AT_TXTEND);
515 if( !pFootnoteEndAtTextEnd )
516 pFootnoteEndAtTextEnd = pFormat->GetItemIfSet(RES_END_AT_TXTEND);
518 SwSectionNode* pSectNd;
520 if( GetIDocumentUndoRedo().DoesUndo() )
522 if( bDelNodes && pIdx && &GetNodes() == &pIdx->GetNodes() &&
523 nullptr != (pSectNd = pIdx->GetNode().GetSectionNode() ))
525 SwNodeIndex aUpdIdx( *pIdx );
526 SwPaM aPaM( *pSectNd->EndOfSectionNode(), *pSectNd );
527 GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoDelete>(aPaM, SwDeleteFlags::Default));
528 if( pFootnoteEndAtTextEnd )
529 GetFootnoteIdxs().UpdateFootnote( aUpdIdx.GetNode() );
530 getIDocumentState().SetModified();
531 //#126178# start/end undo have to be pairs!
532 GetIDocumentUndoRedo().EndUndo(SwUndoId::DELSECTION, nullptr);
533 return ;
535 GetIDocumentUndoRedo().AppendUndo( MakeUndoDelSection( *pFormat ) );
537 else if( bDelNodes && pIdx && &GetNodes() == &pIdx->GetNodes() &&
538 nullptr != (pSectNd = pIdx->GetNode().GetSectionNode() ))
540 SwNodeIndex aUpdIdx( *pIdx );
541 getIDocumentContentOperations().DeleteSection(pSectNd);
542 if( pFootnoteEndAtTextEnd )
543 GetFootnoteIdxs().UpdateFootnote( aUpdIdx.GetNode() );
544 getIDocumentState().SetModified();
545 //#126178# start/end undo have to be pairs!
546 GetIDocumentUndoRedo().EndUndo(SwUndoId::DELSECTION, nullptr);
547 return ;
550 pFormat->RemoveAllUnos();
552 // A ClearRedo could result in a recursive call of this function and delete some section
553 // formats, thus the position inside the SectionFormatTable could have changed
554 itFormatPos = std::find( mpSectionFormatTable->begin(), mpSectionFormatTable->end(), pFormat );
556 // WARNING: First remove from the array and then delete,
557 // as the Section DTOR tries to delete it's format itself.
558 mpSectionFormatTable->erase( itFormatPos );
560 SwNodeOffset nCnt(0), nSttNd(0);
561 if( pIdx && &GetNodes() == &pIdx->GetNodes() &&
562 nullptr != (pSectNd = pIdx->GetNode().GetSectionNode() ))
564 nSttNd = pSectNd->GetIndex();
565 nCnt = pSectNd->EndOfSectionIndex() - nSttNd - 1;
568 delete pFormat;
570 if( nSttNd && pFootnoteEndAtTextEnd )
572 SwNodeIndex aUpdIdx( GetNodes(), nSttNd );
573 GetFootnoteIdxs().UpdateFootnote( aUpdIdx.GetNode() );
576 SwContentNode* pCNd;
577 for( ; nCnt--; ++nSttNd )
578 if( nullptr != (pCNd = GetNodes()[ nSttNd ]->GetContentNode() ) &&
579 RES_CONDTXTFMTCOLL == pCNd->GetFormatColl()->Which() )
580 pCNd->ChkCondColl();
583 GetIDocumentUndoRedo().EndUndo(SwUndoId::DELSECTION, nullptr);
585 if (GetIDocumentUndoRedo().DoesUndo())
586 { // TODO is this ever needed?
587 getIDocumentState().SetModified();
591 void SwDoc::UpdateSection( size_t const nPos, SwSectionData & rNewData,
592 SfxItemSet const*const pAttr, bool const bPreventLinkUpdate )
594 SwSectionFormat* pFormat = (*mpSectionFormatTable)[ nPos ];
595 SwSection* pSection = pFormat->GetSection();
597 /// remember hidden condition flag of SwSection before changes
598 bool bOldCondHidden = pSection->IsCondHidden();
600 if (pSection->DataEquals(rNewData))
602 // Check Attributes
603 bool bOnlyAttrChg = false;
604 if( pAttr && pAttr->Count() )
606 SfxItemIter aIter( *pAttr );
607 const SfxPoolItem* pItem = aIter.GetCurItem();
610 if (pFormat->GetFormatAttr(pItem->Which()) != *pItem)
612 bOnlyAttrChg = true;
613 break;
616 pItem = aIter.NextItem();
617 } while (pItem);
620 if( bOnlyAttrChg )
622 if (GetIDocumentUndoRedo().DoesUndo())
624 GetIDocumentUndoRedo().AppendUndo(
625 MakeUndoUpdateSection( *pFormat, true ) );
627 // #i32968# Inserting columns in the section causes MakeFrameFormat
628 // to put two objects of type SwUndoFrameFormat on the undo stack.
629 // We don't want them.
630 ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
631 pFormat->SetFormatAttr( *pAttr );
632 getIDocumentState().SetModified();
634 return;
637 // Test if the whole Content Section (Document/TableBox/Fly) should be hidden,
638 // which we're currently not able to do.
639 const SwNodeIndex* pIdx = nullptr;
641 if (rNewData.IsHidden())
643 pIdx = pFormat->GetContent().GetContentIdx();
644 if (pIdx)
646 const SwSectionNode* pSectNd =
647 pIdx->GetNode().GetSectionNode();
648 if (pSectNd)
650 ::lcl_CheckEmptyLayFrame( rNewData,
651 *pSectNd, *pSectNd->EndOfSectionNode() );
657 if (GetIDocumentUndoRedo().DoesUndo())
659 GetIDocumentUndoRedo().AppendUndo(MakeUndoUpdateSection(*pFormat, false));
661 // #i32968# Inserting columns in the section causes MakeFrameFormat to put two
662 // objects of type SwUndoFrameFormat on the undo stack. We don't want them.
663 ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
665 // The LinkFileName could only consist of separators
666 OUString sCompareString = OUStringChar(sfx2::cTokenSeparator) + OUStringChar(sfx2::cTokenSeparator);
667 const bool bUpdate =
668 (!pSection->IsLinkType() && rNewData.IsLinkType())
669 || (!rNewData.GetLinkFileName().isEmpty()
670 && (rNewData.GetLinkFileName() != sCompareString)
671 && (rNewData.GetLinkFileName() != pSection->GetLinkFileName()));
673 OUString sSectName( rNewData.GetSectionName() );
674 if (sSectName != pSection->GetSectionName())
675 sSectName = GetUniqueSectionName( &sSectName );
676 else
677 sSectName.clear();
679 /// In SwSection::operator=(..) class member m_bCondHiddenFlag is always set to true.
680 /// IMHO this have to be changed, but I can't estimate the consequences:
681 /// Either it is set to true using corresponding method <SwSection.SetCondHidden(..)>,
682 /// or it is set to the value of SwSection which is assigned to it.
683 /// Discussion with AMA results that the adjustment to the assignment operator
684 /// could be very risky.
685 pSection->SetSectionData(rNewData);
687 if( pAttr )
688 pSection->GetFormat()->SetFormatAttr( *pAttr );
690 if( !sSectName.isEmpty() )
692 pSection->SetSectionName( sSectName );
695 // Is a Condition set
696 if( pSection->IsHidden() && !pSection->GetCondition().isEmpty() )
698 // Then calculate up to that position
699 SwCalc aCalc( *this );
700 if( !pIdx )
701 pIdx = pFormat->GetContent().GetContentIdx();
702 getIDocumentFieldsAccess().FieldsToCalc(aCalc, pIdx->GetIndex(), SAL_MAX_INT32);
704 /// Because on using SwSection::operator=() to set up <pSection>
705 /// with <rNewData> and the above given note, the hidden condition flag
706 /// has to be set to false, if hidden condition flag of <pFormat->GetSection()>
707 /// (SwSection before the changes) is false (already saved in <bOldCondHidden>)
708 /// and new calculated condition is true.
709 /// This is necessary, because otherwise the <SetCondHidden> would have
710 /// no effect.
711 bool bCalculatedCondHidden =
712 aCalc.Calculate( pSection->GetCondition() ).GetBool();
713 if ( bCalculatedCondHidden && !bOldCondHidden )
715 pSection->SetCondHidden( false );
717 pSection->SetCondHidden( bCalculatedCondHidden );
720 if( bUpdate )
721 pSection->CreateLink( bPreventLinkUpdate ? LinkCreateType::Connect : LinkCreateType::Update );
722 else if( !pSection->IsLinkType() && pSection->IsConnected() )
724 pSection->Disconnect();
725 getIDocumentLinksAdministration().GetLinkManager().Remove( &pSection->GetBaseLink() );
728 getIDocumentState().SetModified();
731 void sw_DeleteFootnote( SwSectionNode *pNd, SwNodeOffset nStt, SwNodeOffset nEnd )
733 SwFootnoteIdxs& rFootnoteArr = pNd->GetDoc().GetFootnoteIdxs();
734 if( rFootnoteArr.empty() )
735 return;
737 size_t nPos = 0;
738 rFootnoteArr.SeekEntry( *pNd, &nPos );
740 // Delete all succeeding Footnotes
741 while (nPos < rFootnoteArr.size())
743 SwTextFootnote* pSrch = rFootnoteArr[nPos];
744 if (SwTextFootnote_GetIndex(pSrch) > nEnd)
745 break;
746 // If the Nodes are not deleted, they need to deregister at the Pages
747 // (delete Frames) or else they will remain there (Undo does not delete them!)
748 pSrch->DelFrames(nullptr);
749 ++nPos;
752 while (nPos > 0)
754 nPos--;
755 SwTextFootnote* pSrch = rFootnoteArr[nPos];
756 if (SwTextFootnote_GetIndex(pSrch) < nStt)
757 break;
758 // If the Nodes are not deleted, they need to deregister at the Pages
759 // (delete Frames) or else they will remain there (Undo does not delete them!)
760 pSrch->DelFrames(nullptr);
764 static bool lcl_IsTOXSection(SwSectionData const& rSectionData)
766 return (SectionType::ToxContent == rSectionData.GetType())
767 || (SectionType::ToxHeader == rSectionData.GetType());
770 SwSectionNode* SwNodes::InsertTextSection(SwNode& rNd,
771 SwSectionFormat& rSectionFormat,
772 SwSectionData const& rSectionData,
773 SwTOXBase const*const pTOXBase,
774 SwNode const*const pEndNd,
775 bool const bInsAtStart, bool const bCreateFrames)
777 SwNodeIndex aInsPos( rNd );
778 if( !pEndNd ) // No Area, thus create a new Section before/after it
780 // #i26762#
781 OSL_ENSURE(!pEndNd || rNd.GetIndex() <= pEndNd->GetIndex(),
782 "Section start and end in wrong order!");
784 if( bInsAtStart )
786 if (!lcl_IsTOXSection(rSectionData))
788 do {
789 --aInsPos;
790 } while( aInsPos.GetNode().IsSectionNode() );
791 ++aInsPos;
794 else
796 ++aInsPos;
797 if (!lcl_IsTOXSection(rSectionData))
799 SwNode* pNd;
800 while( aInsPos.GetIndex() < Count() - 1 &&
801 ( pNd = &aInsPos.GetNode())->IsEndNode() &&
802 pNd->StartOfSectionNode()->IsSectionNode())
804 ++aInsPos;
810 SwSectionNode *const pSectNd =
811 new SwSectionNode(aInsPos.GetNode(), rSectionFormat, pTOXBase);
813 if (lcl_IsTOXSection(rSectionData))
815 // We're inserting a ToX. Make sure that if a redline ends right before the ToX start, then
816 // that end now doesn't cross a section start node.
817 SwRedlineTable& rRedlines = GetDoc().getIDocumentRedlineAccess().GetRedlineTable();
818 for (SwRedlineTable::size_type nIndex = 0; nIndex < rRedlines.size(); ++nIndex)
820 SwRangeRedline* pRedline = rRedlines[nIndex];
821 if ( RedlineType::Delete != pRedline->GetType() ||
822 !pRedline->HasMark() || pRedline->GetMark()->GetNode() != aInsPos.GetNode() )
824 continue;
827 // The redline ends at the new section content start, so it originally ended before the
828 // section start: move it back.
829 SwPaM aRedlineEnd(*pRedline->GetMark());
830 aRedlineEnd.Move(fnMoveBackward);
831 *pRedline->GetMark() = *aRedlineEnd.GetPoint();
832 break;
836 if( pEndNd )
838 // Special case for the Reader/Writer
839 if( *pEndNd != GetEndOfContent() )
840 aInsPos = pEndNd->GetIndex()+1;
841 // #i58710: We created a RTF document with a section break inside a table cell
842 // We are not able to handle a section start inside a table and the section end outside.
843 const SwNode* pLastNode = pSectNd->StartOfSectionNode()->EndOfSectionNode();
844 if( aInsPos > pLastNode->GetIndex() )
845 aInsPos = pLastNode->GetIndex();
846 // Another way round: if the section starts outside a table but the end is inside...
847 // aInsPos is at the moment the Position where my EndNode will be inserted
848 const SwStartNode* pStartNode = aInsPos.GetNode().StartOfSectionNode();
849 // This StartNode should be in front of me, but if not, I want to survive
850 SwNodeOffset nMyIndex = pSectNd->GetIndex();
851 if( pStartNode->GetIndex() > nMyIndex ) // Suspicious!
853 const SwNode* pTemp;
856 pTemp = pStartNode; // pTemp is a suspicious one
857 pStartNode = pStartNode->StartOfSectionNode();
859 while( pStartNode->GetIndex() > nMyIndex );
860 pTemp = pTemp->EndOfSectionNode();
861 // If it starts behind me but ends behind my end...
862 if( pTemp->GetIndex() >= aInsPos.GetIndex() )
863 aInsPos = pTemp->GetIndex()+1; // ...I have to correct my end position
866 else
868 SwTextNode* pCpyTNd = rNd.GetTextNode();
869 if( pCpyTNd )
871 SwTextNode* pTNd = new SwTextNode( aInsPos.GetNode(), pCpyTNd->GetTextColl() );
872 if( pCpyTNd->HasSwAttrSet() )
874 // Move PageDesc/Break to the first Node of the section
875 const SfxItemSet& rSet = *pCpyTNd->GetpSwAttrSet();
876 if( SfxItemState::SET == rSet.GetItemState( RES_BREAK ) ||
877 SfxItemState::SET == rSet.GetItemState( RES_PAGEDESC ))
879 SfxItemSet aSet( rSet );
880 if( bInsAtStart )
881 pCpyTNd->ResetAttr( RES_PAGEDESC, RES_BREAK );
882 else
884 aSet.ClearItem( RES_PAGEDESC );
885 aSet.ClearItem( RES_BREAK );
887 pTNd->SetAttr( aSet );
889 else
890 pTNd->SetAttr( rSet );
892 // Do not forget to create the Frame!
893 pCpyTNd->MakeFramesForAdjacentContentNode(*pTNd);
895 else
896 new SwTextNode( aInsPos.GetNode(), GetDoc().GetDfltTextFormatColl() );
898 new SwEndNode( aInsPos.GetNode(), *pSectNd );
900 pSectNd->GetSection().SetSectionData(rSectionData);
901 SwSectionFormat* pSectFormat = pSectNd->GetSection().GetFormat();
903 // We could optimize this, by not removing already contained Frames and recreating them,
904 // but by simply rewiring them
905 bool bInsFrame = bCreateFrames && !pSectNd->GetSection().IsHiddenFlag() &&
906 GetDoc().getIDocumentLayoutAccess().GetCurrentViewShell();
907 std::optional<SwNode2LayoutSaveUpperFrames> oNode2Layout;
908 if( bInsFrame )
910 if( !pSectNd->GetNodes().FindPrvNxtFrameNode( *pSectNd, pSectNd->EndOfSectionNode() ) )
911 // Collect all Uppers
912 oNode2Layout.emplace(*pSectNd);
915 // Set the right StartNode for all in this Area
916 SwNodeOffset nEnd = pSectNd->EndOfSectionIndex();
917 SwNodeOffset nStart = pSectNd->GetIndex()+1;
918 SwNodeOffset nSkipIdx = NODE_OFFSET_MAX;
919 for( SwNodeOffset n = nStart; n < nEnd; ++n )
921 SwNode* pNd = (*this)[n];
923 // Attach all Sections in the NodeSection underneath the new one
924 if( NODE_OFFSET_MAX == nSkipIdx )
925 pNd->m_pStartOfSection = pSectNd;
926 else if( n >= nSkipIdx )
927 nSkipIdx = NODE_OFFSET_MAX;
929 if( pNd->IsStartNode() )
931 // Make up the Format's nesting
932 if( pNd->IsSectionNode() )
934 static_cast<SwSectionNode*>(pNd)->GetSection().GetFormat()->
935 SetDerivedFrom( pSectFormat );
936 static_cast<SwSectionNode*>(pNd)->DelFrames();
937 n = pNd->EndOfSectionIndex();
939 else
941 if( pNd->IsTableNode() )
942 static_cast<SwTableNode*>(pNd)->DelFrames();
944 if( NODE_OFFSET_MAX == nSkipIdx )
945 nSkipIdx = pNd->EndOfSectionIndex();
948 else if( pNd->IsContentNode() )
949 static_cast<SwContentNode*>(pNd)->DelFrames(nullptr);
952 sw_DeleteFootnote( pSectNd, nStart, nEnd );
954 if( bInsFrame )
956 if( oNode2Layout )
958 SwNodeOffset nIdx = pSectNd->GetIndex();
959 oNode2Layout->RestoreUpperFrames( pSectNd->GetNodes(), nIdx, nIdx + 1 );
960 oNode2Layout.reset();
962 else
963 pSectNd->MakeOwnFrames(&aInsPos);
966 return pSectNd;
969 SwSectionNode* SwNode::FindSectionNode()
971 for (SwNode* tmp = this;; tmp = tmp->StartOfSectionNode())
972 if (SwSectionNode* sectNode = tmp->GetSectionNode(); sectNode || !tmp->GetIndex())
973 return sectNode;
976 // SwSectionNode
978 // ugly hack to make m_pSection const
979 static SwSectionFormat &
980 lcl_initParent(SwSectionNode & rThis, SwSectionFormat & rFormat)
982 SwSectionNode *const pParent =
983 rThis.StartOfSectionNode()->FindSectionNode();
984 if( pParent )
986 // Register the Format at the right Parent
987 rFormat.SetDerivedFrom( pParent->GetSection().GetFormat() );
989 return rFormat;
992 SwSectionNode::SwSectionNode(const SwNode& rWhere,
993 SwSectionFormat & rFormat, SwTOXBase const*const pTOXBase)
994 : SwStartNode( rWhere, SwNodeType::Section )
995 , m_pSection( pTOXBase
996 ? new SwTOXBaseSection(*pTOXBase, lcl_initParent(*this, rFormat))
997 : new SwSection( SectionType::Content, rFormat.GetName(),
998 lcl_initParent(*this, rFormat) ) )
1000 // Set the connection from Format to Node
1001 // Suppress Modify; no one's interested anyway
1002 rFormat.LockModify();
1003 rFormat.SetFormatAttr( SwFormatContent( this ) );
1004 rFormat.UnlockModify();
1007 SwSectionNode::~SwSectionNode()
1009 // mba: test if iteration works as clients will be removed in callback
1010 // use hint which allows to specify, if the content shall be saved or not
1011 m_pSection->GetFormat()->CallSwClientNotify( SwSectionFrameMoveAndDeleteHint( true ) );
1012 SwSectionFormat* pFormat = m_pSection->GetFormat();
1013 if( pFormat )
1015 // Remove the Attribute, because the Section deletes it's Format
1016 // and it will neutralize the Section, if the Content Attribute is set
1017 pFormat->LockModify();
1018 pFormat->ResetFormatAttr( RES_CNTNT );
1019 pFormat->UnlockModify();
1023 SwFrame* SwSectionNode::MakeFrame(SwFrame* pSib, bool bHidden)
1025 m_pSection->m_Data.SetHiddenFlag(bHidden);
1026 return new SwSectionFrame( *m_pSection, pSib );
1029 // Creates all Document Views for the preceding Node.
1030 // The created ContentFrames are attached to the corresponding Layout
1031 void SwSectionNode::MakeFramesForAdjacentContentNode(const SwNodeIndex & rIdx)
1033 // Take my successive or preceding ContentFrame
1034 SwNodes& rNds = GetNodes();
1035 if( !(rNds.IsDocNodes() && rNds.GetDoc().getIDocumentLayoutAccess().GetCurrentViewShell()) )
1036 return;
1038 if (GetSection().IsHiddenFlag() || IsContentHidden())
1040 SwNodeIndex aIdx( *EndOfSectionNode() );
1041 SwContentNode* pCNd = SwNodes::GoNextSection(&aIdx, true, false);
1042 if( !pCNd )
1044 aIdx = *this;
1045 pCNd = SwNodes::GoPrevSection(&aIdx, true, false);
1046 if (!pCNd)
1047 return;
1049 pCNd = aIdx.GetNode().GetContentNode();
1050 pCNd->MakeFramesForAdjacentContentNode(static_cast<SwContentNode&>(rIdx.GetNode()));
1052 else
1054 SwNode2Layout aNode2Layout( *this, rIdx.GetIndex() );
1055 SwFrame *pFrame;
1056 while( nullptr != (pFrame = aNode2Layout.NextFrame()) )
1058 OSL_ENSURE( pFrame->IsSctFrame(), "Depend of Section not a Section." );
1059 if (pFrame->getRootFrame()->HasMergedParas()
1060 && !rIdx.GetNode().IsCreateFrameWhenHidingRedlines())
1062 continue;
1064 SwFrame *pNew = rIdx.GetNode().GetContentNode()->MakeFrame( pFrame );
1066 SwSectionNode* pS = rIdx.GetNode().FindSectionNode();
1068 // Assure that node is not inside a table, which is inside the
1069 // found section.
1070 if ( pS )
1072 SwTableNode* pTableNode = rIdx.GetNode().FindTableNode();
1073 if ( pTableNode &&
1074 pTableNode->GetIndex() > pS->GetIndex() )
1076 pS = nullptr;
1080 // if the node is in a section, the sectionframe now
1081 // has to be created...
1082 // boolean to control <Init()> of a new section frame.
1083 bool bInitNewSect = false;
1084 if( pS )
1086 SwSectionFrame *pSct = new SwSectionFrame( pS->GetSection(), pFrame );
1087 // prepare <Init()> of new section frame.
1088 bInitNewSect = true;
1089 SwLayoutFrame* pUp = pSct;
1090 while( pUp->Lower() ) // for columned sections
1092 OSL_ENSURE( pUp->Lower()->IsLayoutFrame(),"Who's in there?" );
1093 pUp = static_cast<SwLayoutFrame*>(pUp->Lower());
1095 pNew->Paste( pUp );
1096 // #i27138#
1097 // notify accessibility paragraphs objects about changed
1098 // CONTENT_FLOWS_FROM/_TO relation.
1099 // Relation CONTENT_FLOWS_FROM for next paragraph will change
1100 // and relation CONTENT_FLOWS_TO for previous paragraph will change.
1101 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
1102 if ( pNew->IsTextFrame() )
1104 SwViewShell* pViewShell( pNew->getRootFrame()->GetCurrShell() );
1105 if ( pViewShell && pViewShell->GetLayout() &&
1106 pViewShell->GetLayout()->IsAnyShellAccessible() )
1108 auto pNext = pNew->FindNextCnt( true );
1109 auto pPrev = pNew->FindPrevCnt();
1110 pViewShell->InvalidateAccessibleParaFlowRelation(
1111 pNext ? pNext->DynCastTextFrame() : nullptr,
1112 pPrev ? pPrev->DynCastTextFrame() : nullptr );
1115 #endif
1116 pNew = pSct;
1119 // If a Node got Frames attached before or after
1120 if ( rIdx < GetIndex() )
1121 // the new one precedes me
1122 pNew->Paste( pFrame->GetUpper(), pFrame );
1123 else
1124 // the new one succeeds me
1125 pNew->Paste( pFrame->GetUpper(), pFrame->GetNext() );
1126 // #i27138#
1127 // notify accessibility paragraphs objects about changed
1128 // CONTENT_FLOWS_FROM/_TO relation.
1129 // Relation CONTENT_FLOWS_FROM for next paragraph will change
1130 // and relation CONTENT_FLOWS_TO for previous paragraph will change.
1131 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
1132 if ( pNew->IsTextFrame() )
1134 SwViewShell* pViewShell( pNew->getRootFrame()->GetCurrShell() );
1135 if ( pViewShell && pViewShell->GetLayout() &&
1136 pViewShell->GetLayout()->IsAnyShellAccessible() )
1138 auto pNext = pNew->FindNextCnt( true );
1139 auto pPrev = pNew->FindPrevCnt();
1140 pViewShell->InvalidateAccessibleParaFlowRelation(
1141 pNext ? pNext->DynCastTextFrame() : nullptr,
1142 pPrev ? pPrev->DynCastTextFrame() : nullptr );
1145 #endif
1146 if ( bInitNewSect )
1147 static_cast<SwSectionFrame*>(pNew)->Init();
1152 // Create a new SectionFrame for every occurrence in the Layout and insert before
1153 // the corresponding ContentFrame
1154 void SwSectionNode::MakeOwnFrames(SwNodeIndex* pIdxBehind, SwNodeIndex* pEndIdx)
1156 assert(pIdxBehind && "no Index");
1157 SwNodes& rNds = GetNodes();
1158 SwDoc& rDoc = rNds.GetDoc();
1160 *pIdxBehind = *this;
1162 m_pSection->m_Data.SetHiddenFlag(true);
1164 if( rNds.IsDocNodes() )
1166 if( pEndIdx )
1167 ::MakeFrames( &rDoc, pIdxBehind->GetNode(), pEndIdx->GetNode() );
1168 else
1169 ::MakeFrames( &rDoc, pIdxBehind->GetNode(), SwNodeIndex( *EndOfSectionNode(), 1 ).GetNode() );
1173 void SwSectionNode::DelFrames(SwRootFrame const*const /*FIXME TODO*/, bool const bForce)
1175 SwNodeOffset nStt = GetIndex()+1, nEnd = EndOfSectionIndex();
1176 if( nStt >= nEnd )
1178 return ;
1181 m_pSection->GetFormat()->DelFrames();
1183 // Update our Flag
1184 m_pSection->m_Data.SetHiddenFlag(true);
1186 // If the Area is within a Fly or TableBox, we can only hide it if
1187 // there is more Content which has Frames.
1188 // Or else the Fly/TableBox Frame does not have a Lower!
1189 if (bForce)
1190 return;
1192 SwNodeIndex aIdx( *this );
1193 if( !SwNodes::GoPrevSection( &aIdx, true, false ) ||
1194 !CheckNodesRange( *this, aIdx.GetNode(), true ) ||
1195 // #i21457#
1196 !lcl_IsInSameTableBox( *this, true ))
1198 aIdx = *EndOfSectionNode();
1199 if( !SwNodes::GoNextSection( &aIdx, true, false ) ||
1200 !CheckNodesRange( *EndOfSectionNode(), aIdx.GetNode(), true ) ||
1201 // #i21457#
1202 !lcl_IsInSameTableBox( *EndOfSectionNode(), false ))
1204 m_pSection->m_Data.SetHiddenFlag(false);
1209 SwSectionNode* SwSectionNode::MakeCopy( SwDoc& rDoc, const SwNodeIndex& rIdx ) const
1211 // In which array am I: Nodes, UndoNodes?
1212 const SwNodes& rNds = GetNodes();
1214 // Copy the SectionFrameFormat
1215 SwSectionFormat* pSectFormat = rDoc.MakeSectionFormat();
1216 pSectFormat->CopyAttrs( *GetSection().GetFormat() );
1218 std::unique_ptr<SwTOXBase> pTOXBase;
1219 if (SectionType::ToxContent == GetSection().GetType())
1221 assert( dynamic_cast< const SwTOXBaseSection* >( &GetSection() ) && "no TOXBaseSection!" );
1222 SwTOXBaseSection const& rTBS(
1223 dynamic_cast<SwTOXBaseSection const&>(GetSection()));
1224 pTOXBase.reset( new SwTOXBase(rTBS, &rDoc) );
1227 SwSectionNode *const pSectNd =
1228 new SwSectionNode(rIdx.GetNode(), *pSectFormat, pTOXBase.get());
1229 SwEndNode* pEndNd = new SwEndNode( rIdx.GetNode(), *pSectNd );
1230 SwNodeIndex aInsPos( *pEndNd );
1232 // Take over values
1233 SwSection *const pNewSect = pSectNd->m_pSection.get();
1235 if (SectionType::ToxContent != GetSection().GetType())
1237 // Keep the Name for Move
1238 if( &rNds.GetDoc() == &rDoc && rDoc.IsCopyIsMove() )
1240 pNewSect->SetSectionName( GetSection().GetSectionName() );
1242 else
1244 const OUString sSectionName(GetSection().GetSectionName());
1245 pNewSect->SetSectionName(rDoc.GetUniqueSectionName( &sSectionName ));
1249 pNewSect->SetType( GetSection().GetType() );
1250 pNewSect->SetCondition( GetSection().GetCondition() );
1251 pNewSect->SetCondHidden( GetSection().IsCondHidden() );
1252 pNewSect->SetLinkFileName( GetSection().GetLinkFileName() );
1253 if( !pNewSect->IsHiddenFlag() && GetSection().IsHidden() )
1254 pNewSect->SetHidden();
1255 if( !pNewSect->IsProtectFlag() && GetSection().IsProtect() )
1256 pNewSect->SetProtect();
1257 // edit in readonly sections
1258 if( !pNewSect->IsEditInReadonlyFlag() && GetSection().IsEditInReadonly() )
1259 pNewSect->SetEditInReadonly();
1261 SwNodeRange aRg( *this, SwNodeOffset(+1), *EndOfSectionNode() ); // Where am I?
1262 rNds.Copy_( aRg, aInsPos.GetNode(), false );
1264 // Delete all Frames from the copied Area. They are created when creating
1265 // the SectionFrames.
1266 pSectNd->DelFrames();
1268 // Copy the Links/Server
1269 if( pNewSect->IsLinkType() ) // Add the Link
1270 pNewSect->CreateLink( rDoc.getIDocumentLayoutAccess().GetCurrentViewShell() ? LinkCreateType::Connect : LinkCreateType::NONE );
1272 // If we copy from the Undo as Server, enter it again
1273 if (m_pSection->IsServer()
1274 && rDoc.GetIDocumentUndoRedo().IsUndoNodes(rNds))
1276 pNewSect->SetRefObject( m_pSection->GetObject() );
1277 rDoc.getIDocumentLinksAdministration().GetLinkManager().InsertServer( pNewSect->GetObject() );
1280 // METADATA: copy xml:id; must be done after insertion of node
1281 pSectFormat->RegisterAsCopyOf(*GetSection().GetFormat());
1283 return pSectNd;
1286 bool SwSectionNode::IsContentHidden() const
1288 OSL_ENSURE( !m_pSection->IsHidden(),
1289 "That's simple: Hidden Section => Hidden Content" );
1290 SwNodeIndex aTmp( *this, 1 );
1291 SwNodeOffset nEnd = EndOfSectionIndex();
1292 while( aTmp < nEnd )
1294 if( aTmp.GetNode().IsSectionNode() )
1296 const SwSection& rSect = static_cast<SwSectionNode&>(aTmp.GetNode()).GetSection();
1297 if( rSect.IsHiddenFlag() )
1298 // Skip this Section
1299 aTmp = *aTmp.GetNode().EndOfSectionNode();
1301 else
1303 if( aTmp.GetNode().IsContentNode() || aTmp.GetNode().IsTableNode() )
1304 return false; // We found non-hidden content
1305 OSL_ENSURE( aTmp.GetNode().IsEndNode(), "EndNode expected" );
1307 ++aTmp;
1309 return true; // Hide everything
1312 void SwSectionNode::dumpAsXml(xmlTextWriterPtr pWriter) const
1314 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("section"));
1315 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
1316 (void)xmlTextWriterWriteAttribute(
1317 pWriter, BAD_CAST("type"),
1318 BAD_CAST(OString::number(static_cast<sal_uInt8>(GetNodeType())).getStr()));
1319 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("index"),
1320 BAD_CAST(OString::number(sal_Int32(GetIndex())).getStr()));
1322 if (m_pSection)
1324 m_pSection->dumpAsXml(pWriter);
1327 // (void)xmlTextWriterEndElement(pWriter); - it is a start node, so don't end, will make xml better nested
1330 void SwSectionNode::NodesArrChgd()
1332 SwSectionFormat *const pFormat = m_pSection->GetFormat();
1333 if( !pFormat )
1334 return;
1336 SwNodes& rNds = GetNodes();
1337 SwDoc* pDoc = pFormat->GetDoc();
1339 if( !rNds.IsDocNodes() )
1341 pFormat->RemoveAllUnos();
1344 pFormat->LockModify();
1345 pFormat->SetFormatAttr( SwFormatContent( this ));
1346 pFormat->UnlockModify();
1348 SwSectionNode* pSectNd = StartOfSectionNode()->FindSectionNode();
1349 // set the correct parent from the new section
1350 pFormat->SetDerivedFrom( pSectNd ? pSectNd->GetSection().GetFormat()
1351 : pDoc->GetDfltFrameFormat() );
1353 // Set the right StartNode for all in this Area
1354 SwNodeOffset nStart = GetIndex()+1, nEnd = EndOfSectionIndex();
1355 for( SwNodeOffset n = nStart; n < nEnd; ++n )
1357 // Make up the Format's nesting
1358 pSectNd = rNds[ n ]->GetSectionNode();
1359 if( nullptr != pSectNd )
1361 pSectNd->GetSection().GetFormat()->SetDerivedFrom( pFormat );
1362 n = pSectNd->EndOfSectionIndex();
1366 // Moving Nodes to the UndoNodes array?
1367 if( rNds.IsDocNodes() )
1369 OSL_ENSURE( pDoc == &GetDoc(),
1370 "Moving to different Documents?" );
1371 if( m_pSection->IsLinkType() ) // Remove the Link
1372 m_pSection->CreateLink( pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() ? LinkCreateType::Connect : LinkCreateType::NONE );
1374 if (m_pSection->IsServer())
1375 pDoc->getIDocumentLinksAdministration().GetLinkManager().InsertServer( m_pSection->GetObject() );
1377 else
1379 if (SectionType::Content != m_pSection->GetType()
1380 && m_pSection->IsConnected())
1382 pDoc->getIDocumentLinksAdministration().GetLinkManager().Remove( &m_pSection->GetBaseLink() );
1384 if (m_pSection->IsServer())
1385 pDoc->getIDocumentLinksAdministration().GetLinkManager().RemoveServer( m_pSection->GetObject() );
1390 OUString SwDoc::GetUniqueSectionName( const OUString* pChkStr ) const
1392 if( IsInMailMerge())
1394 OUString newName = "MailMergeSection"
1395 + DateTimeToOUString( DateTime( DateTime::SYSTEM ) )
1396 + OUString::number( mpSectionFormatTable->size() + 1 );
1397 if( pChkStr )
1398 newName += *pChkStr;
1399 return newName;
1402 const OUString aName(SwResId(STR_REGION_DEFNAME));
1404 SwSectionFormats::size_type nNum = 0;
1405 const SwSectionFormats::size_type nFlagSize = ( mpSectionFormatTable->size() / 8 ) + 2;
1406 std::unique_ptr<sal_uInt8[]> pSetFlags(new sal_uInt8[ nFlagSize ]);
1407 memset( pSetFlags.get(), 0, nFlagSize );
1409 for( auto pFormat : *mpSectionFormatTable )
1411 const SwSectionNode *const pSectNd = pFormat->GetSectionNode();
1412 if( pSectNd != nullptr )
1414 const OUString& rNm = pSectNd->GetSection().GetSectionName();
1415 if (rNm.startsWith( aName ))
1417 // Calculate the Number and reset the Flag
1418 nNum = o3tl::toInt32(rNm.subView( aName.getLength() ));
1419 if (nNum)
1421 --nNum;
1422 if (nNum < mpSectionFormatTable->size())
1424 pSetFlags[ nNum / 8 ] |= (0x01 << ( nNum & 0x07 ));
1428 if( pChkStr && *pChkStr==rNm )
1429 pChkStr = nullptr;
1433 if( !pChkStr )
1435 // Flagged all Numbers accordingly, so get the right Number
1436 nNum = mpSectionFormatTable->size();
1437 for( SwSectionFormats::size_type n = 0; n < nFlagSize; ++n )
1439 auto nTmp = pSetFlags[ n ];
1440 if( nTmp != 0xFF )
1442 // Calculate the Number
1443 nNum = n * 8;
1444 while( nTmp & 1 )
1446 ++nNum;
1447 nTmp >>= 1;
1449 break;
1453 pSetFlags.reset();
1454 if( pChkStr )
1455 return *pChkStr;
1456 return aName + OUString::number( ++nNum );
1459 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */