Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / core / docnode / node.cxx
blob4304b875c4d763a6e17fc2b7d066a2276bb41fb4
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 <hintids.hxx>
22 #include <editeng/protitem.hxx>
23 #include <osl/diagnose.h>
24 #include <tools/gen.hxx>
25 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
26 #include <com/sun/star/i18n/XBreakIterator.hpp>
27 #include <fmtcntnt.hxx>
28 #include <fmtanchr.hxx>
29 #include <frmfmt.hxx>
30 #include <txtftn.hxx>
31 #include <ftnfrm.hxx>
32 #include <doc.hxx>
33 #include <node.hxx>
34 #include <ndindex.hxx>
35 #include <numrule.hxx>
36 #include <swtable.hxx>
37 #include <ndtxt.hxx>
38 #include <pam.hxx>
39 #include <section.hxx>
40 #include <cntfrm.hxx>
41 #include <flyfrm.hxx>
42 #include <txtfrm.hxx>
43 #include <tabfrm.hxx>
44 #include <viewsh.hxx>
45 #include <paratr.hxx>
46 #include <ftnidx.hxx>
47 #include <fmtftn.hxx>
48 #include <fmthdft.hxx>
49 #include <frmatr.hxx>
50 #include <fmtautofmt.hxx>
51 #include <frmtool.hxx>
52 #include <pagefrm.hxx>
53 #include <node2lay.hxx>
54 #include <pagedesc.hxx>
55 #include <fmtpdsc.hxx>
56 #include <breakit.hxx>
57 #include <SwStyleNameMapper.hxx>
58 #include <scriptinfo.hxx>
59 #include <rootfrm.hxx>
60 #include <istyleaccess.hxx>
61 #include <IDocumentListItems.hxx>
62 #include <DocumentSettingManager.hxx>
63 #include <IDocumentLinksAdministration.hxx>
64 #include <IDocumentRedlineAccess.hxx>
65 #include <IDocumentLayoutAccess.hxx>
66 #include <calbck.hxx>
67 #include <ndole.hxx>
68 #include <memory>
69 #include <swcrsr.hxx>
70 #include <hints.hxx>
71 #include <frameformats.hxx>
72 #include <OnlineAccessibilityCheck.hxx>
73 #ifdef DBG_UTIL
74 #include <sal/backtrace.hxx>
75 #endif
77 using namespace ::com::sun::star::i18n;
79 namespace sw
82 void AccessibilityCheckStatus::reset()
84 pCollection.reset();
90 * Some local helper functions for the attribute set handle of a content node.
91 * Since the attribute set of a content node may not be modified directly,
92 * we always have to create a new SwAttrSet, do the modifications, and get
93 * a new handle from the style access
96 namespace AttrSetHandleHelper
99 static void GetNewAutoStyle( std::shared_ptr<const SfxItemSet>& rpAttrSet,
100 const SwContentNode& rNode,
101 SwAttrSet const & rNewAttrSet )
103 const SwAttrSet* pAttrSet = static_cast<const SwAttrSet*>(rpAttrSet.get());
104 if( rNode.GetModifyAtAttr() )
105 const_cast<SwAttrSet*>(pAttrSet)->SetModifyAtAttr( nullptr );
106 IStyleAccess& rSA = pAttrSet->GetPool()->GetDoc()->GetIStyleAccess();
107 rpAttrSet = rSA.getAutomaticStyle( rNewAttrSet, rNode.IsTextNode() ?
108 IStyleAccess::AUTO_STYLE_PARA :
109 IStyleAccess::AUTO_STYLE_NOTXT );
110 const bool bSetModifyAtAttr = const_cast<SwAttrSet*>(static_cast<const SwAttrSet*>(rpAttrSet.get()))->SetModifyAtAttr( &rNode );
111 rNode.SetModifyAtAttr( bSetModifyAtAttr );
114 static void SetParent( std::shared_ptr<const SfxItemSet>& rpAttrSet,
115 const SwContentNode& rNode,
116 const SwFormat* pParentFormat,
117 const SwFormat* pConditionalFormat )
119 const SwAttrSet* pAttrSet = static_cast<const SwAttrSet*>(rpAttrSet.get());
120 OSL_ENSURE( pAttrSet, "no SwAttrSet" );
121 OSL_ENSURE( pParentFormat || !pConditionalFormat, "ConditionalFormat without ParentFormat?" );
123 const SwAttrSet* pParentSet = pParentFormat ? &pParentFormat->GetAttrSet() : nullptr;
125 if ( pParentSet == pAttrSet->GetParent() )
126 return;
128 SwAttrSet aNewSet( *pAttrSet );
129 aNewSet.SetParent( pParentSet );
130 aNewSet.ClearItem( RES_FRMATR_STYLE_NAME );
131 aNewSet.ClearItem( RES_FRMATR_CONDITIONAL_STYLE_NAME );
133 if ( pParentFormat )
135 OUString sVal;
136 SwStyleNameMapper::FillProgName( pParentFormat->GetName(), sVal, SwGetPoolIdFromName::TxtColl );
137 const SfxStringItem aAnyFormatColl( RES_FRMATR_STYLE_NAME, sVal );
138 aNewSet.Put( aAnyFormatColl );
140 if ( pConditionalFormat != pParentFormat )
141 SwStyleNameMapper::FillProgName( pConditionalFormat->GetName(), sVal, SwGetPoolIdFromName::TxtColl );
143 const SfxStringItem aFormatColl( RES_FRMATR_CONDITIONAL_STYLE_NAME, sVal );
144 aNewSet.Put( aFormatColl );
147 GetNewAutoStyle( rpAttrSet, rNode, aNewSet );
150 static const SfxPoolItem* Put( std::shared_ptr<const SfxItemSet>& rpAttrSet,
151 const SwContentNode& rNode,
152 const SfxPoolItem& rAttr )
154 SwAttrSet aNewSet( static_cast<const SwAttrSet&>(*rpAttrSet) );
155 const SfxPoolItem* pRet = aNewSet.Put( rAttr );
156 if ( pRet )
157 GetNewAutoStyle( rpAttrSet, rNode, aNewSet );
158 return pRet;
161 static bool Put( std::shared_ptr<const SfxItemSet>& rpAttrSet, const SwContentNode& rNode,
162 const SfxItemSet& rSet )
164 SwAttrSet aNewSet( static_cast<const SwAttrSet&>(*rpAttrSet) );
166 // #i76273# Robust
167 std::optional<SfxItemSetFixed<RES_FRMATR_STYLE_NAME, RES_FRMATR_CONDITIONAL_STYLE_NAME>> pStyleNames;
168 if ( SfxItemState::SET == rSet.GetItemState( RES_FRMATR_STYLE_NAME, false ) )
170 pStyleNames.emplace( *aNewSet.GetPool() );
171 pStyleNames->Put( aNewSet );
174 const bool bRet = aNewSet.Put( rSet );
176 // #i76273# Robust
177 if ( pStyleNames )
179 aNewSet.Put( *pStyleNames );
182 if ( bRet )
183 GetNewAutoStyle( rpAttrSet, rNode, aNewSet );
185 return bRet;
188 static bool Put_BC( std::shared_ptr<const SfxItemSet>& rpAttrSet,
189 const SwContentNode& rNode, const SfxPoolItem& rAttr,
190 SwAttrSet* pOld, SwAttrSet* pNew )
192 SwAttrSet aNewSet( static_cast<const SwAttrSet&>(*rpAttrSet) );
194 // for a correct broadcast, we need to do a SetModifyAtAttr with the items
195 // from aNewSet. The 'regular' SetModifyAtAttr is done in GetNewAutoStyle
196 if( rNode.GetModifyAtAttr() )
197 aNewSet.SetModifyAtAttr( &rNode );
199 const bool bRet = aNewSet.Put_BC( rAttr, pOld, pNew );
201 if ( bRet )
202 GetNewAutoStyle( rpAttrSet, rNode, aNewSet );
204 return bRet;
207 static bool Put_BC( std::shared_ptr<const SfxItemSet>& rpAttrSet,
208 const SwContentNode& rNode, const SfxItemSet& rSet,
209 SwAttrSet* pOld, SwAttrSet* pNew )
211 SwAttrSet aNewSet( static_cast<const SwAttrSet&>(*rpAttrSet) );
213 // #i76273# Robust
214 std::optional<SfxItemSetFixed<RES_FRMATR_STYLE_NAME, RES_FRMATR_CONDITIONAL_STYLE_NAME>> pStyleNames;
215 if ( SfxItemState::SET == rSet.GetItemState( RES_FRMATR_STYLE_NAME, false ) )
217 pStyleNames.emplace( *aNewSet.GetPool() );
218 pStyleNames->Put( aNewSet );
221 // for a correct broadcast, we need to do a SetModifyAtAttr with the items
222 // from aNewSet. The 'regular' SetModifyAtAttr is done in GetNewAutoStyle
223 if( rNode.GetModifyAtAttr() )
224 aNewSet.SetModifyAtAttr( &rNode );
226 const bool bRet = aNewSet.Put_BC( rSet, pOld, pNew );
228 // #i76273# Robust
229 if ( pStyleNames )
231 aNewSet.Put( *pStyleNames );
234 if ( bRet )
235 GetNewAutoStyle( rpAttrSet, rNode, aNewSet );
237 return bRet;
240 static sal_uInt16 ClearItem_BC( std::shared_ptr<const SfxItemSet>& rpAttrSet,
241 const SwContentNode& rNode, sal_uInt16 nWhich,
242 SwAttrSet* pOld, SwAttrSet* pNew )
244 SwAttrSet aNewSet( static_cast<const SwAttrSet&>(*rpAttrSet) );
245 if( rNode.GetModifyAtAttr() )
246 aNewSet.SetModifyAtAttr( &rNode );
247 const sal_uInt16 nRet = aNewSet.ClearItem_BC( nWhich, pOld, pNew );
248 if ( nRet )
249 GetNewAutoStyle( rpAttrSet, rNode, aNewSet );
250 return nRet;
253 static sal_uInt16 ClearItem_BC( std::shared_ptr<const SfxItemSet>& rpAttrSet,
254 const SwContentNode& rNode,
255 sal_uInt16 nWhich1, sal_uInt16 nWhich2,
256 SwAttrSet* pOld, SwAttrSet* pNew )
258 SwAttrSet aNewSet( static_cast<const SwAttrSet&>(*rpAttrSet) );
259 if( rNode.GetModifyAtAttr() )
260 aNewSet.SetModifyAtAttr( &rNode );
261 const sal_uInt16 nRet = aNewSet.ClearItem_BC( nWhich1, nWhich2, pOld, pNew );
262 if ( nRet )
263 GetNewAutoStyle( rpAttrSet, rNode, aNewSet );
264 return nRet;
269 /** Returns the section level at the position given by aIndex.
271 * We use the following logic:
272 * S = Start, E = End, C = ContentNode
273 * Level 0 = E
274 * 1 = S E
275 * 2 = SC
277 * All EndNodes of the BaseSection have level 0
278 * All StartNodes of the BaseSection have level 1
280 sal_uInt16 SwNode::GetSectionLevel() const
282 // EndNode of a BaseSection? They are always 0!
283 if( IsEndNode() && SwNodeOffset(0) == m_pStartOfSection->StartOfSectionIndex() )
284 return 0;
286 sal_uInt16 nLevel;
287 const SwNode* pNode = IsStartNode() ? this : m_pStartOfSection;
288 for( nLevel = 1; SwNodeOffset(0) != pNode->StartOfSectionIndex(); ++nLevel )
289 pNode = pNode->m_pStartOfSection;
290 return IsEndNode() ? nLevel-1 : nLevel;
293 #ifdef DBG_UTIL
294 tools::Long SwNode::s_nSerial = 0;
295 #endif
297 /// only used by SwContentNodeTmp in SwTextNode::Update
298 SwNode::SwNode()
299 : m_nNodeType( SwNodeType::Start )
300 , m_nAFormatNumLvl( 0 )
301 , m_bIgnoreDontExpand( false)
302 , m_eMerge(Merge::None)
303 #ifdef DBG_UTIL
304 , m_nSerial( s_nSerial++)
305 #endif
306 , m_pStartOfSection( nullptr )
309 SwNode::SwNode( const SwNode& rWhere, const SwNodeType nNdType )
310 : m_nNodeType( nNdType )
311 , m_nAFormatNumLvl( 0 )
312 , m_bIgnoreDontExpand( false)
313 , m_eMerge(Merge::None)
314 #ifdef DBG_UTIL
315 , m_nSerial( s_nSerial++)
316 #endif
317 , m_pStartOfSection( nullptr )
319 SwNodeOffset nWhereOffset = rWhere.GetIndex();
320 if( !nWhereOffset )
321 return;
323 SwNodes& rNodes = const_cast<SwNodes&> (rWhere.GetNodes());
324 SwNode* pNd = rNodes[ nWhereOffset -1 ];
325 rNodes.InsertNode( this, nWhereOffset );
326 m_pStartOfSection = pNd->GetStartNode();
327 if( nullptr == m_pStartOfSection )
329 m_pStartOfSection = pNd->m_pStartOfSection;
330 if( pNd->GetEndNode() ) // Skip EndNode ? Section
332 pNd = m_pStartOfSection;
333 m_pStartOfSection = pNd->m_pStartOfSection;
338 /** Inserts a node into the rNodes array at the rWhere position
340 * @param rNodes the variable array in that the node will be inserted
341 * @param nPos position within the array where the node will be inserted
342 * @param nNdType the type of node to insert
344 SwNode::SwNode( SwNodes& rNodes, SwNodeOffset nPos, const SwNodeType nNdType )
345 : m_nNodeType( nNdType )
346 , m_nAFormatNumLvl( 0 )
347 , m_bIgnoreDontExpand( false)
348 , m_eMerge(Merge::None)
349 #ifdef DBG_UTIL
350 , m_nSerial( s_nSerial++)
351 #endif
352 , m_pStartOfSection( nullptr )
354 if( !nPos )
355 return;
357 SwNode* pNd = rNodes[ nPos - 1 ];
358 rNodes.InsertNode( this, nPos );
359 m_pStartOfSection = pNd->GetStartNode();
360 if( nullptr == m_pStartOfSection )
362 m_pStartOfSection = pNd->m_pStartOfSection;
363 if( pNd->GetEndNode() ) // Skip EndNode ? Section!
365 pNd = m_pStartOfSection;
366 m_pStartOfSection = pNd->m_pStartOfSection;
371 SwNode::~SwNode()
373 assert(m_aAnchoredFlys.empty() || GetDoc().IsInDtor()); // must all be deleted
374 InvalidateInSwCache(RES_OBJECTDYING);
375 assert(!IsInCache());
378 /// Find the TableNode in which it is located.
379 /// If we're not in a table: return 0
380 SwTableNode* SwNode::FindTableNode()
382 if( IsTableNode() )
383 return GetTableNode();
384 SwStartNode* pTmp = m_pStartOfSection;
385 while( !pTmp->IsTableNode() && pTmp->GetIndex() )
386 pTmp = pTmp->m_pStartOfSection;
387 return pTmp->GetTableNode();
390 /// Is the node located in the visible area of the Shell?
391 bool SwNode::IsInVisibleArea( SwViewShell const * pSh ) const
393 bool bRet = false;
394 const SwContentNode* pNd;
396 if( SwNodeType::Start & m_nNodeType )
398 SwNodeIndex aIdx( *this );
399 pNd = GetNodes().GoNext( &aIdx );
401 else if( SwNodeType::End & m_nNodeType )
403 SwNodeIndex aIdx( *EndOfSectionNode() );
404 pNd = SwNodes::GoPrevious( &aIdx );
406 else
407 pNd = GetContentNode();
409 if( !pSh )
410 // Get the Shell from the Doc
411 pSh = GetDoc().getIDocumentLayoutAccess().GetCurrentViewShell();
413 if( pSh )
415 const SwFrame* pFrame;
416 if (pNd && nullptr != (pFrame = pNd->getLayoutFrame(pSh->GetLayout(), nullptr, nullptr)))
419 if ( pFrame->IsInTab() )
420 pFrame = pFrame->FindTabFrame();
422 if( !pFrame->isFrameAreaDefinitionValid() )
426 pFrame = pFrame->FindPrev();
428 while ( pFrame && !pFrame->isFrameAreaDefinitionValid() );
431 if( !pFrame || pSh->VisArea().Overlaps( pFrame->getFrameArea() ) )
432 bRet = true;
436 return bRet;
439 bool SwNode::IsInProtectSect() const
441 const SwNode* pNd = SwNodeType::Section == m_nNodeType ? m_pStartOfSection : this;
442 const SwSectionNode* pSectNd = pNd->FindSectionNode();
443 return pSectNd && pSectNd->GetSection().IsProtectFlag();
446 /// Does the node contain anything protected?
447 /// I.e.: Area/Frame/Table rows/... including the Anchor for
448 /// Frames/Footnotes/...
449 bool SwNode::IsProtect() const
451 const SwNode* pNd = SwNodeType::Section == m_nNodeType ? m_pStartOfSection : this;
452 const SwStartNode* pSttNd = pNd->FindSectionNode();
453 if( pSttNd && static_cast<const SwSectionNode*>(pSttNd)->GetSection().IsProtectFlag() )
454 return true;
456 pSttNd = FindTableBoxStartNode();
457 if( nullptr != pSttNd )
459 SwContentFrame* pCFrame;
460 if( IsContentNode() && nullptr != (pCFrame = static_cast<const SwContentNode*>(this)->getLayoutFrame( GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() ) ))
461 return pCFrame->IsProtected();
463 const SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().
464 GetTableBox( pSttNd->GetIndex() );
465 //Robust #149568
466 if( pBox && pBox->GetFrameFormat()->GetProtect().IsContentProtected() )
467 return true;
470 SwFrameFormat* pFlyFormat = GetFlyFormat();
471 if( pFlyFormat )
473 if (pFlyFormat->GetProtect().IsContentProtected())
474 return true;
475 const SwFormatAnchor& rAnchor = pFlyFormat->GetAnchor();
476 const SwNode* pAnchorNode = rAnchor.GetAnchorNode();
477 if (!pAnchorNode)
478 return false;
479 return pAnchorNode != this && pAnchorNode->IsProtect();
482 pSttNd = FindFootnoteStartNode();
483 if( nullptr != pSttNd )
485 const SwTextFootnote* pTFootnote = GetDoc().GetFootnoteIdxs().SeekEntry(
486 *pSttNd );
487 if( pTFootnote )
488 return pTFootnote->GetTextNode().IsProtect();
491 return false;
494 /// Find the PageDesc that is used to format this node. If the Layout is available,
495 /// we search through that. Else we can only do it the hard way by searching onwards through the nodes.
496 const SwPageDesc* SwNode::FindPageDesc( SwNodeOffset* pPgDescNdIdx ) const
498 if ( !GetNodes().IsDocNodes() )
500 return nullptr;
503 const SwPageDesc* pPgDesc = nullptr;
505 const SwContentNode* pNode;
506 if( SwNodeType::Start & m_nNodeType )
508 SwNodeIndex aIdx( *this );
509 pNode = GetNodes().GoNext( &aIdx );
511 else if( SwNodeType::End & m_nNodeType )
513 SwNodeIndex aIdx( *EndOfSectionNode() );
514 pNode = SwNodes::GoPrevious( &aIdx );
516 else
518 pNode = GetContentNode();
519 if( pNode )
520 pPgDesc = pNode->GetAttr( RES_PAGEDESC ).GetPageDesc();
523 // Are we going through the layout?
524 if( !pPgDesc )
526 const SwFrame* pFrame;
527 const SwPageFrame* pPage;
528 if (pNode && nullptr != (pFrame = pNode->getLayoutFrame(pNode->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, nullptr)) &&
529 nullptr != ( pPage = pFrame->FindPageFrame() ) )
531 pPgDesc = pPage->GetPageDesc();
532 if ( pPgDescNdIdx )
534 *pPgDescNdIdx = pNode->GetIndex();
539 if( !pPgDesc )
541 // Thus via the nodes array
542 const SwDoc& rDoc = GetDoc();
543 const SwNode* pNd = this;
544 const SwStartNode* pSttNd;
545 if( pNd->GetIndex() < GetNodes().GetEndOfExtras().GetIndex() &&
546 nullptr != ( pSttNd = pNd->FindFlyStartNode() ) )
548 // Find the right Anchor first
549 const SwFrameFormat* pFormat = nullptr;
550 const sw::SpzFrameFormats& rFormats = *rDoc.GetSpzFrameFormats();
552 for(sw::SpzFrameFormat* pSpz: rFormats)
554 const SwFormatContent& rContent = pSpz->GetContent();
555 if( rContent.GetContentIdx() &&
556 &rContent.GetContentIdx()->GetNode() == static_cast<SwNode const *>(pSttNd) )
558 pFormat = pSpz;
559 break;
563 if( pFormat )
565 const SwFormatAnchor* pAnchor = &pFormat->GetAnchor();
566 if ((RndStdIds::FLY_AT_PAGE != pAnchor->GetAnchorId()) &&
567 pAnchor->GetAnchorNode() )
569 pNd = pAnchor->GetAnchorNode();
570 const SwNode* pFlyNd = pNd->FindFlyStartNode();
571 while( pFlyNd )
573 // Get up through the Anchor
574 size_t n;
575 for( n = 0; n < rFormats.size(); ++n )
577 const SwFrameFormat* pFrameFormat = rFormats[ n ];
578 const SwNodeIndex* pIdx = pFrameFormat->GetContent().
579 GetContentIdx();
580 if( pIdx && pFlyNd == &pIdx->GetNode() )
582 if( pFormat == pFrameFormat )
584 pNd = pFlyNd;
585 pFlyNd = nullptr;
586 break;
588 pAnchor = &pFrameFormat->GetAnchor();
589 if ((RndStdIds::FLY_AT_PAGE == pAnchor->GetAnchorId()) ||
590 !pAnchor->GetAnchorNode() )
592 pFlyNd = nullptr;
593 break;
596 pFlyNd = pAnchor->GetAnchorNode()->FindFlyStartNode();
597 break;
600 if( n >= rFormats.size() )
602 OSL_ENSURE( false, "FlySection, but no Format found" );
603 return nullptr;
608 // pNd should now contain the correct Anchor or it's still this
611 if( pNd->GetIndex() < GetNodes().GetEndOfExtras().GetIndex() )
613 if( pNd->GetIndex() > GetNodes().GetEndOfAutotext().GetIndex() )
615 pPgDesc = &rDoc.GetPageDesc( 0 );
616 pNd = nullptr;
618 else
620 // Find the Body text node
621 if( nullptr != ( pSttNd = pNd->FindHeaderStartNode() ) ||
622 nullptr != ( pSttNd = pNd->FindFooterStartNode() ))
624 // Then find this StartNode in the PageDescs
625 sal_uInt16 nId;
626 UseOnPage eAskUse;
627 if( SwHeaderStartNode == pSttNd->GetStartNodeType())
629 nId = RES_HEADER;
630 eAskUse = UseOnPage::HeaderShare;
632 else
634 nId = RES_FOOTER;
635 eAskUse = UseOnPage::FooterShare;
638 for( size_t n = rDoc.GetPageDescCnt(); n && !pPgDesc; )
640 const SwPageDesc& rPgDsc = rDoc.GetPageDesc( --n );
641 const SwFrameFormat* pFormat = &rPgDsc.GetMaster();
642 int nStt = 0, nLast = 1;
643 if( !( eAskUse & rPgDsc.ReadUseOn() )) ++nLast;
645 for( ; nStt < nLast; ++nStt, pFormat = &rPgDsc.GetLeft() )
647 const SwFrameFormat * pHdFtFormat = nId == RES_HEADER
648 ? static_cast<SwFormatHeader const &>(
649 pFormat->GetFormatAttr(nId)).GetHeaderFormat()
650 : static_cast<SwFormatFooter const &>(
651 pFormat->GetFormatAttr(nId)).GetFooterFormat();
652 if( pHdFtFormat )
654 const SwFormatContent& rContent = pHdFtFormat->GetContent();
655 if( rContent.GetContentIdx() &&
656 &rContent.GetContentIdx()->GetNode() ==
657 static_cast<SwNode const *>(pSttNd) )
659 pPgDesc = &rPgDsc;
660 break;
666 if( !pPgDesc )
667 pPgDesc = &rDoc.GetPageDesc( 0 );
668 pNd = nullptr;
670 else if( nullptr != ( pSttNd = pNd->FindFootnoteStartNode() ))
672 // the Anchor can only be in the Body text
673 const SwTextFootnote* pTextFootnote;
674 const SwFootnoteIdxs& rFootnoteArr = rDoc.GetFootnoteIdxs();
675 for( size_t n = 0; n < rFootnoteArr.size(); ++n )
676 if( nullptr != ( pTextFootnote = rFootnoteArr[ n ])->GetStartNode() &&
677 static_cast<SwNode const *>(pSttNd) ==
678 &pTextFootnote->GetStartNode()->GetNode() )
680 pNd = &pTextFootnote->GetTextNode();
681 break;
684 else
686 // Can only be a page-bound Fly (or something newer).
687 // we can only return the standard here
688 OSL_ENSURE( pNd->FindFlyStartNode(),
689 "Where is this Node?" );
691 pPgDesc = &rDoc.GetPageDesc( 0 );
692 pNd = nullptr;
697 if( pNd )
699 SwFindNearestNode aInfo( *pNd );
700 // Over all Nodes of all PageDescs
701 for (const SfxPoolItem* pItem : rDoc.GetAttrPool().GetItemSurrogates(RES_PAGEDESC))
703 auto pPageDescItem = dynamic_cast<const SwFormatPageDesc*>(pItem);
704 if( pPageDescItem && pPageDescItem->GetDefinedIn() )
706 const sw::BroadcastingModify* pMod = pPageDescItem->GetDefinedIn();
707 if( auto pContentNode = dynamic_cast<const SwContentNode*>( pMod) )
708 aInfo.CheckNode( *pContentNode );
709 else if( auto pFormat = dynamic_cast<const SwFormat*>( pMod) )
710 pFormat->GetInfo( aInfo );
714 pNd = aInfo.GetFoundNode();
715 if( nullptr != pNd )
717 if( pNd->IsContentNode() )
718 pPgDesc = pNd->GetContentNode()->GetAttr( RES_PAGEDESC ).GetPageDesc();
719 else if( pNd->IsTableNode() )
720 pPgDesc = pNd->GetTableNode()->GetTable().
721 GetFrameFormat()->GetPageDesc().GetPageDesc();
722 else if( pNd->IsSectionNode() )
723 pPgDesc = pNd->GetSectionNode()->GetSection().
724 GetFormat()->GetPageDesc().GetPageDesc();
725 if ( pPgDescNdIdx )
727 *pPgDescNdIdx = pNd->GetIndex();
730 if( !pPgDesc )
731 pPgDesc = &rDoc.GetPageDesc( 0 );
734 return pPgDesc;
737 /// If the node is located in a Fly, we return it formatted accordingly
738 SwFrameFormat* SwNode::GetFlyFormat() const
740 SwFrameFormat* pRet = nullptr;
741 const SwNode* pSttNd = FindFlyStartNode();
742 if( pSttNd )
744 if( IsContentNode() )
746 SwContentFrame* pFrame = SwIterator<SwContentFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>(*static_cast<const SwContentNode*>(this)).First();
747 if( pFrame && pFrame->FindFlyFrame())
748 pRet = pFrame->FindFlyFrame()->GetFormat();
750 if( !pRet )
752 // The hard way through the Doc is our last way out
753 const sw::SpzFrameFormats& rSpzs = *GetDoc().GetSpzFrameFormats();
754 for(sw::SpzFrameFormat* pSpz: rSpzs)
756 // Only Writer fly frames can contain Writer nodes.
757 if (pSpz->Which() != RES_FLYFRMFMT)
758 continue;
759 const SwFormatContent& rContent = pSpz->GetContent();
760 if( rContent.GetContentIdx() &&
761 &rContent.GetContentIdx()->GetNode() == pSttNd )
763 pRet = pSpz;
764 break;
769 return pRet;
772 SwTableBox* SwNode::GetTableBox() const
774 SwTableBox* pBox = nullptr;
775 const SwNode* pSttNd = FindTableBoxStartNode();
776 if( pSttNd )
777 pBox = const_cast<SwTableBox*>(pSttNd->FindTableNode()->GetTable().GetTableBox(
778 pSttNd->GetIndex() ));
779 return pBox;
782 SwStartNode* SwNode::FindSttNodeByType( SwStartNodeType eTyp )
784 SwStartNode* pTmp = IsStartNode() ? static_cast<SwStartNode*>(this) : m_pStartOfSection;
786 while( eTyp != pTmp->GetStartNodeType() && pTmp->GetIndex() )
787 pTmp = pTmp->m_pStartOfSection;
788 return eTyp == pTmp->GetStartNodeType() ? pTmp : nullptr;
791 const SwTextNode* SwNode::FindOutlineNodeOfLevel(sal_uInt8 const nLvl,
792 SwRootFrame const*const pLayout) const
794 const SwTextNode* pRet = nullptr;
795 const SwOutlineNodes& rONds = GetNodes().GetOutLineNds();
796 if( MAXLEVEL > nLvl && !rONds.empty() )
798 SwOutlineNodes::size_type nPos;
799 SwNode* pNd = const_cast<SwNode*>(this);
800 bool bCheckFirst = false;
801 if( !rONds.Seek_Entry( pNd, &nPos ))
803 if (nPos == 0)
804 bCheckFirst = true;
806 else
808 ++nPos;
811 if( bCheckFirst )
813 // The first OutlineNode comes after the one asking.
814 // Test if both are on the same page.
815 // If not it's invalid.
816 for (nPos = 0; nPos < rONds.size(); ++nPos)
818 pRet = rONds[nPos]->GetTextNode();
819 if (!pLayout || sw::IsParaPropsNode(*pLayout, *pRet))
821 break;
824 if (nPos == rONds.size())
826 return nullptr;
829 const SwContentNode* pCNd = GetContentNode();
831 Point aPt( 0, 0 );
832 std::pair<Point, bool> const tmp(aPt, false);
833 const SwFrame* pFrame = pRet->getLayoutFrame(pRet->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, &tmp),
834 * pMyFrame = pCNd ? pCNd->getLayoutFrame(pCNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, &tmp) : nullptr;
835 const SwPageFrame* pPgFrame = pFrame ? pFrame->FindPageFrame() : nullptr;
836 if( pPgFrame && pMyFrame &&
837 pPgFrame->getFrameArea().Top() > pMyFrame->getFrameArea().Top() )
839 // The one asking precedes the Page, thus its invalid
840 pRet = nullptr;
843 else
845 for ( ; 0 < nPos; --nPos)
847 SwTextNode const*const pNode = rONds[nPos - 1]->GetTextNode();
848 if ((nPos == 1 /*as before*/ || pNode->GetAttrOutlineLevel() - 1 <= nLvl)
849 && (!pLayout || sw::IsParaPropsNode(*pLayout, *pNode)))
851 pRet = pNode;
852 break;
857 return pRet;
860 static bool IsValidNextPrevNd( const SwNode& rNd )
862 return SwNodeType::Table == rNd.GetNodeType() ||
863 ( SwNodeType::ContentMask & rNd.GetNodeType() ) ||
864 ( SwNodeType::End == rNd.GetNodeType() && rNd.StartOfSectionNode() &&
865 SwNodeType::Table == rNd.StartOfSectionNode()->GetNodeType() );
868 sal_uInt8 SwNode::HasPrevNextLayNode() const
870 // assumption: <this> node is a node inside the document nodes array section.
872 sal_uInt8 nRet = 0;
873 if( IsValidNextPrevNd( *this ))
875 SwNodeIndex aIdx( *this, -1 );
876 // #i77805# - skip section start and end nodes
877 while ( aIdx.GetNode().IsSectionNode() ||
878 ( aIdx.GetNode().IsEndNode() &&
879 aIdx.GetNode().StartOfSectionNode()->IsSectionNode() ) )
881 --aIdx;
883 if( IsValidNextPrevNd( aIdx.GetNode() ))
884 nRet |= ND_HAS_PREV_LAYNODE;
885 // #i77805# - skip section start and end nodes
886 aIdx.Assign(*this, +1);
887 while ( aIdx.GetNode().IsSectionNode() ||
888 ( aIdx.GetNode().IsEndNode() &&
889 aIdx.GetNode().StartOfSectionNode()->IsSectionNode() ) )
891 ++aIdx;
893 if( IsValidNextPrevNd( aIdx.GetNode() ))
894 nRet |= ND_HAS_NEXT_LAYNODE;
896 return nRet;
899 void SwNode::dumpAsXml(xmlTextWriterPtr pWriter) const
901 const char* pName = "???";
902 switch (GetNodeType())
904 case SwNodeType::End:
905 pName = "end";
906 break;
907 case SwNodeType::Start:
908 case SwNodeType::Text:
909 case SwNodeType::Ole:
910 abort(); // overridden
911 case SwNodeType::Table:
912 pName = "table";
913 break;
914 case SwNodeType::Grf:
915 pName = "grf";
916 break;
917 default: break;
919 (void)xmlTextWriterStartElement(pWriter, BAD_CAST(pName));
921 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
922 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("type"), BAD_CAST(OString::number(static_cast<sal_uInt8>(GetNodeType())).getStr()));
923 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("index"), BAD_CAST(OString::number(sal_Int32(GetIndex())).getStr()));
925 switch (GetNodeType())
927 case SwNodeType::Grf:
929 auto pNoTextNode = static_cast<const SwNoTextNode*>(this);
930 const tools::PolyPolygon* pContour = pNoTextNode->HasContour();
931 if (pContour)
933 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("pContour"));
934 for (sal_uInt16 i = 0; i < pContour->Count(); ++i)
936 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("polygon"));
937 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("index"),
938 BAD_CAST(OString::number(i).getStr()));
939 const tools::Polygon& rPolygon = pContour->GetObject(i);
940 for (sal_uInt16 j = 0; j < rPolygon.GetSize(); ++j)
942 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("point"));
943 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("index"),
944 BAD_CAST(OString::number(j).getStr()));
945 const Point& rPoint = rPolygon.GetPoint(j);
946 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("x"),
947 BAD_CAST(OString::number(rPoint.X()).getStr()));
948 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("y"),
949 BAD_CAST(OString::number(rPoint.Y()).getStr()));
950 (void)xmlTextWriterEndElement(pWriter);
952 (void)xmlTextWriterEndElement(pWriter);
954 (void)xmlTextWriterEndElement(pWriter);
957 break;
958 default:
959 break;
962 (void)xmlTextWriterEndElement(pWriter);
963 if (GetNodeType() == SwNodeType::End)
964 (void)xmlTextWriterEndElement(pWriter); // end start node
967 SwStartNode::SwStartNode( const SwNode& rWhere, const SwNodeType nNdType,
968 SwStartNodeType eSttNd )
969 : SwNode( rWhere, nNdType ), m_eStartNodeType( eSttNd )
971 if( !rWhere.GetIndex() )
973 SwNodes& rNodes = const_cast<SwNodes&> (rWhere.GetNodes());
974 rNodes.InsertNode( this, rWhere.GetIndex() );
975 m_pStartOfSection = this;
977 // Just do this temporarily until the EndNode is inserted
978 m_pEndOfSection = reinterpret_cast<SwEndNode*>(this);
981 SwStartNode::SwStartNode( SwNodes& rNodes, SwNodeOffset nPos )
982 : SwNode( rNodes, nPos, SwNodeType::Start ), m_eStartNodeType( SwNormalStartNode )
984 if( !nPos )
986 rNodes.InsertNode( this, nPos );
987 m_pStartOfSection = this;
989 // Just do this temporarily until the EndNode is inserted
990 m_pEndOfSection = reinterpret_cast<SwEndNode*>(this);
993 void SwStartNode::CheckSectionCondColl() const
995 SwNodeIndex aIdx( *this );
996 SwNodeOffset nEndIdx = EndOfSectionIndex();
997 const SwNodes& rNds = GetNodes();
998 SwContentNode* pCNd;
999 while( nullptr != ( pCNd = rNds.GoNext( &aIdx )) && pCNd->GetIndex() < nEndIdx )
1000 pCNd->ChkCondColl();
1003 void SwStartNode::dumpAsXml(xmlTextWriterPtr pWriter) const
1005 const char* pName = "???";
1006 switch (GetNodeType())
1008 case SwNodeType::Table:
1009 pName = "table";
1010 break;
1011 default:
1012 switch(GetStartNodeType())
1014 case SwNormalStartNode:
1015 pName = "start";
1016 break;
1017 case SwTableBoxStartNode:
1018 pName = "tablebox";
1019 break;
1020 case SwFlyStartNode:
1021 pName = "fly";
1022 break;
1023 case SwFootnoteStartNode:
1024 pName = "footnote";
1025 break;
1026 case SwHeaderStartNode:
1027 pName = "header";
1028 break;
1029 case SwFooterStartNode:
1030 pName = "footer";
1031 break;
1033 break;
1036 (void)xmlTextWriterStartElement(pWriter, BAD_CAST(pName));
1037 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
1038 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("type"), BAD_CAST(OString::number(static_cast<sal_uInt8>(GetNodeType())).getStr()));
1039 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("index"), BAD_CAST(OString::number(sal_Int32(GetIndex())).getStr()));
1041 if (GetStartNodeType() == SwTableBoxStartNode)
1043 if (SwTableBox* pBox = GetTableBox())
1044 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("rowspan"), BAD_CAST(OString::number(pBox->getRowSpan()).getStr()));
1045 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("attrset"));
1046 if (SwTableBox* pBox = GetTableBox())
1047 pBox->GetFrameFormat()->GetAttrSet().dumpAsXml(pWriter);
1048 (void)xmlTextWriterEndElement(pWriter);
1051 // (void)xmlTextWriterEndElement(pWriter); - it is a start node, so don't end, will make xml better nested
1055 /** Insert a node into the array
1057 * The StartOfSection pointer is set to the given node.
1059 * The EndOfSection pointer of the corresponding start node is set to this node.
1061 * @param rWhere position where the node should be inserted
1062 * @param rSttNd the start note of the section
1065 SwEndNode::SwEndNode( const SwNode& rWhere, SwStartNode& rSttNd )
1066 : SwNode( rWhere, SwNodeType::End )
1068 m_pStartOfSection = &rSttNd;
1069 m_pStartOfSection->m_pEndOfSection = this;
1072 SwEndNode::SwEndNode( SwNodes& rNds, SwNodeOffset nPos, SwStartNode& rSttNd )
1073 : SwNode( rNds, nPos, SwNodeType::End )
1075 m_pStartOfSection = &rSttNd;
1076 m_pStartOfSection->m_pEndOfSection = this;
1079 /// only used by SwContentNodeTmp in SwTextNode::Update
1080 SwContentNode::SwContentNode()
1081 : SwNode()
1082 , m_aCondCollListener( *this )
1083 , m_pCondColl( nullptr )
1084 , mbSetModifyAtAttr( false )
1087 SwContentNode::SwContentNode( const SwNode& rWhere, const SwNodeType nNdType,
1088 SwFormatColl *pColl )
1089 : SwNode( rWhere, nNdType )
1090 , m_aCondCollListener( *this )
1091 , m_pCondColl( nullptr )
1092 , mbSetModifyAtAttr( false )
1094 if(pColl)
1095 pColl->Add(this);
1098 SwContentNode::~SwContentNode()
1100 // The base class SwClient of SwFrame excludes itself from the dependency list!
1101 // Thus, we need to delete all Frames in the dependency list.
1102 if (!IsTextNode()) // see ~SwTextNode
1104 DelFrames(nullptr);
1107 m_aCondCollListener.EndListeningAll();
1108 m_pCondColl = nullptr;
1110 if ( mpAttrSet && mbSetModifyAtAttr )
1111 const_cast<SwAttrSet*>(static_cast<const SwAttrSet*>(mpAttrSet.get()))->SetModifyAtAttr( nullptr );
1112 InvalidateInSwCache(RES_OBJECTDYING);
1114 void SwContentNode::UpdateAttr(const SwUpdateAttr& rUpdate)
1116 if (GetNodes().IsDocNodes()
1117 && IsTextNode()
1118 && RES_ATTRSET_CHG == rUpdate.getWhichAttr())
1119 static_cast<SwTextNode*>(this)->SetCalcHiddenCharFlags();
1120 CallSwClientNotify(sw::LegacyModifyHint(&rUpdate, &rUpdate));
1123 void SwContentNode::SwClientNotify( const SwModify&, const SfxHint& rHint)
1125 if (rHint.GetId() == SfxHintId::SwLegacyModify)
1127 auto pLegacyHint = static_cast<const sw::LegacyModifyHint*>(&rHint);
1128 const sal_uInt16 nWhich = pLegacyHint->GetWhich();
1129 InvalidateInSwCache(nWhich);
1131 bool bSetParent = false;
1132 bool bCalcHidden = false;
1133 SwFormatColl* pFormatColl = nullptr;
1134 switch(nWhich)
1136 case RES_OBJECTDYING:
1138 SwFormat* pFormat = pLegacyHint->m_pNew
1139 ? static_cast<SwFormat*>(static_cast<const SwPtrMsgPoolItem*>(pLegacyHint->m_pNew)->pObject)
1140 : nullptr;
1141 // Do not mangle pointers if it is the upper-most format!
1142 if(pFormat && GetRegisteredIn() == pFormat)
1144 // As ~SwFormat calls CheckRegistrationFormat before
1145 // ~SwModify, which sends the RES_OBJECTDYING, we should never
1146 // reach this point.
1147 assert(false);
1150 break;
1152 case RES_FMT_CHG:
1153 // If the Format parent was switched, register the Attrset at the new one
1154 // Skip own Modify!
1155 if(GetpSwAttrSet()
1156 && pLegacyHint->m_pNew
1157 && static_cast<const SwFormatChg*>(pLegacyHint->m_pNew)->pChangedFormat == GetRegisteredIn())
1159 pFormatColl = GetFormatColl();
1160 bSetParent = true;
1162 break;
1164 case RES_ATTRSET_CHG:
1165 if (GetNodes().IsDocNodes()
1166 && IsTextNode()
1167 && pLegacyHint->m_pOld
1168 && SfxItemState::SET == pLegacyHint->m_pOld->StaticWhichCast(RES_ATTRSET_CHG).GetChgSet()->GetItemState(RES_CHRATR_HIDDEN, false))
1169 bCalcHidden = true;
1170 break;
1172 case RES_UPDATE_ATTR:
1173 // RES_UPDATE_ATTR _should_ always contain a SwUpdateAttr hint in old and new.
1174 // However, faking one with just a basic SfxPoolItem setting a WhichId has been observed.
1175 // This makes the crude "WhichId" type divert from the true type, which is bad.
1176 // Thus we are asserting here, but falling back to an proper
1177 // hint instead. so that we at least will not spread such poison further.
1178 #ifdef DBG_UTIL
1179 if(pLegacyHint->m_pNew != pLegacyHint->m_pOld)
1181 auto pBT = sal::backtrace_get(20);
1182 SAL_WARN("sw.core", "UpdateAttr not matching! " << sal::backtrace_to_string(pBT.get()));
1184 #endif
1185 assert(pLegacyHint->m_pNew == pLegacyHint->m_pOld);
1186 assert(dynamic_cast<const SwUpdateAttr*>(pLegacyHint->m_pNew));
1187 const SwUpdateAttr aFallbackHint(0,0,0);
1188 const SwUpdateAttr& rUpdateAttr = pLegacyHint->m_pNew ? *static_cast<const SwUpdateAttr*>(pLegacyHint->m_pNew) : aFallbackHint;
1189 UpdateAttr(rUpdateAttr);
1190 return;
1192 if(bSetParent && GetpSwAttrSet())
1193 AttrSetHandleHelper::SetParent(mpAttrSet, *this, pFormatColl, pFormatColl);
1194 if(bCalcHidden)
1195 static_cast<SwTextNode*>(this)->SetCalcHiddenCharFlags();
1196 CallSwClientNotify(rHint);
1198 else if (auto pModifyChangedHint = dynamic_cast<const sw::ModifyChangedHint*>(&rHint))
1200 m_pCondColl = const_cast<SwFormatColl*>(static_cast<const SwFormatColl*>(pModifyChangedHint->m_pNew));
1202 else if(auto pCondCollCondChgHint = dynamic_cast<const sw::CondCollCondChg*>(&rHint))
1204 ChkCondColl(&pCondCollCondChgHint->m_rColl);
1208 bool SwContentNode::InvalidateNumRule()
1210 SwNumRule* pRule = nullptr;
1211 const SfxPoolItem* pItem;
1212 if( GetNodes().IsDocNodes() &&
1213 nullptr != ( pItem = GetNoCondAttr( RES_PARATR_NUMRULE, true )) &&
1214 !static_cast<const SwNumRuleItem*>(pItem)->GetValue().isEmpty() &&
1215 nullptr != (pRule = GetDoc().FindNumRulePtr(
1216 static_cast<const SwNumRuleItem*>(pItem)->GetValue() ) ) )
1218 pRule->SetInvalidRule( true );
1220 return nullptr != pRule;
1223 SwContentFrame *SwContentNode::getLayoutFrame( const SwRootFrame* _pRoot,
1224 const SwPosition *const pPos,
1225 std::pair<Point, bool> const*const pViewPosAndCalcFrame) const
1227 return static_cast<SwContentFrame*>( ::GetFrameOfModify( _pRoot, *this, FRM_CNTNT,
1228 pPos, pViewPosAndCalcFrame));
1231 SwRect SwContentNode::FindLayoutRect( const bool bPrtArea, const Point* pPoint ) const
1233 SwRect aRet;
1234 std::pair<Point, bool> tmp;
1235 if (pPoint)
1237 tmp.first = *pPoint;
1238 tmp.second = false;
1240 SwContentFrame* pFrame = static_cast<SwContentFrame*>( ::GetFrameOfModify( nullptr, *this,
1241 FRM_CNTNT, nullptr, pPoint ? &tmp : nullptr) );
1242 if( pFrame )
1243 aRet = bPrtArea ? pFrame->getFramePrintArea() : pFrame->getFrameArea();
1244 return aRet;
1247 SwRect SwContentNode::FindPageFrameRect() const
1249 SwRect aRet;
1250 SwFrame* pFrame = ::GetFrameOfModify( nullptr, *this, FRM_CNTNT );
1251 if( pFrame && nullptr != ( pFrame = pFrame->FindPageFrame() ))
1252 aRet = pFrame->getFrameArea();
1253 return aRet;
1256 sal_Int32 SwContentNode::Len() const { return 0; }
1258 SwFormatColl *SwContentNode::ChgFormatColl( SwFormatColl *pNewColl )
1260 OSL_ENSURE( pNewColl, "Collectionpointer is 0." );
1261 SwFormatColl *pOldColl = GetFormatColl();
1263 if( pNewColl != pOldColl )
1265 pNewColl->Add( this );
1267 // Set the Parent of out AutoAttributes to the new Collection
1268 if( GetpSwAttrSet() )
1269 AttrSetHandleHelper::SetParent( mpAttrSet, *this, pNewColl, pNewColl );
1271 SetCondFormatColl( nullptr );
1273 if( !IsModifyLocked() )
1275 assert(dynamic_cast<SwTextFormatColl*>(pNewColl));
1276 ChkCondColl(static_cast<SwTextFormatColl*>(pNewColl));
1277 SwFormatChg aTmp1( pOldColl );
1278 SwFormatChg aTmp2( pNewColl );
1279 CallSwClientNotify( sw::LegacyModifyHint(&aTmp1, &aTmp2) );
1282 InvalidateInSwCache(RES_ATTRSET_CHG);
1283 return pOldColl;
1286 bool SwContentNode::GoNext(SwPosition* pPos, SwCursorSkipMode nMode ) const
1288 if (!GoNext(&pPos->nContent, nMode))
1289 return false;
1290 if (pPos->nContent.GetContentNode() != &pPos->GetNode())
1291 pPos->nNode.Assign(*pPos->nContent.GetContentNode());
1292 return true;
1295 bool SwContentNode::GoNext(SwContentIndex * pIdx, SwCursorSkipMode nMode ) const
1297 bool bRet = true;
1298 if( pIdx->GetIndex() < Len() )
1300 if( !IsTextNode() )
1301 ++(*pIdx);
1302 else
1304 const SwTextNode& rTNd = *GetTextNode();
1305 sal_Int32 nPos = pIdx->GetIndex();
1306 assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is());
1307 sal_Int32 nDone = 0;
1308 sal_uInt16 nItrMode = ( SwCursorSkipMode::Cells & nMode ) ?
1309 CharacterIteratorMode::SKIPCELL :
1310 CharacterIteratorMode::SKIPCONTROLCHARACTER;
1311 nPos = g_pBreakIt->GetBreakIter()->nextCharacters( rTNd.GetText(), nPos,
1312 g_pBreakIt->GetLocale( rTNd.GetLang( nPos ) ),
1313 nItrMode, 1, nDone );
1315 // Check if nPos is inside hidden text range:
1316 if ( SwCursorSkipMode::Hidden & nMode )
1318 sal_Int32 nHiddenStart;
1319 sal_Int32 nHiddenEnd;
1320 SwScriptInfo::GetBoundsOfHiddenRange( rTNd, nPos, nHiddenStart, nHiddenEnd );
1321 if ( nHiddenStart != COMPLETE_STRING && nHiddenStart != nPos )
1322 nPos = nHiddenEnd;
1325 if( 1 == nDone )
1326 *pIdx = nPos;
1327 else
1328 bRet = false;
1331 else
1332 bRet = false;
1333 return bRet;
1336 bool SwContentNode::GoPrevious(SwContentIndex * pIdx, SwCursorSkipMode nMode ) const
1338 bool bRet = true;
1339 if( pIdx->GetIndex() > 0 )
1341 if( !IsTextNode() )
1342 --(*pIdx);
1343 else
1345 const SwTextNode& rTNd = *GetTextNode();
1346 sal_Int32 nPos = pIdx->GetIndex();
1347 assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is());
1348 sal_Int32 nDone = 0;
1349 sal_uInt16 nItrMode = ( SwCursorSkipMode::Cells & nMode ) ?
1350 CharacterIteratorMode::SKIPCELL :
1351 CharacterIteratorMode::SKIPCONTROLCHARACTER;
1352 nPos = g_pBreakIt->GetBreakIter()->previousCharacters( rTNd.GetText(), nPos,
1353 g_pBreakIt->GetLocale( rTNd.GetLang( nPos ) ),
1354 nItrMode, 1, nDone );
1356 // Check if nPos is inside hidden text range:
1357 if ( SwCursorSkipMode::Hidden & nMode )
1359 sal_Int32 nHiddenStart;
1360 sal_Int32 nHiddenEnd;
1361 SwScriptInfo::GetBoundsOfHiddenRange( rTNd, nPos, nHiddenStart, nHiddenEnd );
1362 if ( nHiddenStart != COMPLETE_STRING )
1363 nPos = nHiddenStart;
1366 if( 1 == nDone )
1367 *pIdx = nPos;
1368 else
1369 bRet = false;
1372 else
1373 bRet = false;
1374 return bRet;
1378 * Creates all Views for the Doc for this Node.
1379 * The created ContentFrames are attached to the corresponding Layout.
1381 void SwContentNode::MakeFramesForAdjacentContentNode(SwContentNode& rNode)
1383 OSL_ENSURE( &rNode != this,
1384 "No ContentNode or CopyNode and new Node identical." );
1386 if( !HasWriterListeners() || &rNode == this ) // Do we actually have Frames?
1387 return;
1389 SwFrame *pFrame;
1390 SwLayoutFrame *pUpper;
1391 // Create Frames for Nodes which come after the Table?
1392 OSL_ENSURE( FindTableNode() == rNode.FindTableNode(), "Table confusion" );
1394 SwNode2Layout aNode2Layout( *this, rNode.GetIndex() );
1396 while( nullptr != (pUpper = aNode2Layout.UpperFrame( pFrame, rNode )) )
1398 if (pUpper->getRootFrame()->HasMergedParas()
1399 && !rNode.IsCreateFrameWhenHidingRedlines())
1401 continue;
1403 SwFrame *pNew = rNode.MakeFrame( pUpper );
1404 pNew->Paste( pUpper, pFrame );
1405 // #i27138#
1406 // notify accessibility paragraphs objects about changed
1407 // CONTENT_FLOWS_FROM/_TO relation.
1408 // Relation CONTENT_FLOWS_FROM for next paragraph will change
1409 // and relation CONTENT_FLOWS_TO for previous paragraph will change.
1410 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
1411 if ( pNew->IsTextFrame() )
1413 SwViewShell* pViewShell( pNew->getRootFrame()->GetCurrShell() );
1414 if ( pViewShell && pViewShell->GetLayout() &&
1415 pViewShell->GetLayout()->IsAnyShellAccessible() )
1417 auto pNext = pNew->FindNextCnt( true );
1418 auto pPrev = pNew->FindPrevCnt();
1419 pViewShell->InvalidateAccessibleParaFlowRelation(
1420 pNext ? pNext->DynCastTextFrame() : nullptr,
1421 pPrev ? pPrev->DynCastTextFrame() : nullptr );
1424 #endif
1429 * Deletes all Views from the Doc for this Node.
1430 * The ContentFrames are removed from the corresponding Layout.
1432 void SwContentNode::DelFrames(SwRootFrame const*const pLayout)
1434 if( !HasWriterListeners() )
1435 return;
1437 SwIterator<SwContentFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aIter(*this);
1438 for( SwContentFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
1440 if (pLayout && pLayout != pFrame->getRootFrame())
1442 continue; // skip it
1444 if (pFrame->IsTextFrame())
1446 if (sw::MergedPara * pMerged =
1447 static_cast<SwTextFrame *>(pFrame)->GetMergedPara())
1449 if (this != pMerged->pFirstNode)
1451 // SwNodes::RemoveNode iterates *backwards* - so
1452 // ensure there are no more extents pointing to this
1453 // node as SwFrame::InvalidatePage() will access them.
1454 // Note: cannot send via SwClientNotify from dtor
1455 // because that would access deleted wrong-lists
1456 sw::UpdateMergedParaForDelete(*pMerged, true,
1457 *static_cast<SwTextNode*>(this), 0, Len());
1458 if (this == pMerged->pParaPropsNode)
1460 // otherwise pointer should have been updated to a different node
1461 assert(this == pMerged->pLastNode);
1462 assert(pMerged->extents.empty());
1463 for (SwNodeOffset i = pMerged->pLastNode->GetIndex() - 1;;
1464 --i)
1466 assert(pMerged->pFirstNode->GetIndex() <= i);
1467 SwNode *const pNode(GetNodes()[i]);
1468 if (pNode->IsTextNode()
1469 && pNode->GetRedlineMergeFlag() != Merge::Hidden)
1471 pMerged->pParaPropsNode = pNode->GetTextNode();
1472 break;
1474 else if (pMerged->pFirstNode->GetIndex() == i)
1475 { // this can only happen when called from CheckParaRedlineMerge()
1476 // and the pMerged will be deleted anyway
1477 pMerged->pParaPropsNode = pMerged->pFirstNode;
1478 break;
1481 assert(pMerged->listener.IsListeningTo(pMerged->pParaPropsNode));
1483 assert(GetIndex() <= pMerged->pLastNode->GetIndex());
1484 if (this == pMerged->pLastNode)
1486 // tdf#130680 find the previous node that is a
1487 // listener of pMerged; see CheckParaRedlineMerge()
1488 for (SwNodeOffset i = GetIndex() - 1;
1489 this == pMerged->pLastNode; --i)
1491 SwNode *const pNode = GetNodes()[i];
1492 if (pNode->IsTextNode())
1494 pMerged->pLastNode = pNode->GetTextNode();
1496 else if (SwEndNode const*const pEnd = pNode->GetEndNode())
1498 SwStartNode const*const pStart(pEnd->StartOfSectionNode());
1499 i = pStart->GetIndex(); // skip table or section
1502 assert(pMerged->pFirstNode->GetIndex() <= pMerged->pLastNode->GetIndex());
1503 assert(pMerged->listener.IsListeningTo(pMerged->pLastNode));
1505 // avoid re-parenting mess (ModifyChangedHint)
1506 pMerged->listener.EndListening(this);
1507 continue; // don't delete
1510 // #i27138#
1511 // notify accessibility paragraphs objects about changed
1512 // CONTENT_FLOWS_FROM/_TO relation.
1513 // Relation CONTENT_FLOWS_FROM for current next paragraph will change
1514 // and relation CONTENT_FLOWS_TO for current previous paragraph will change.
1515 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
1516 SwViewShell* pViewShell( pFrame->getRootFrame()->GetCurrShell() );
1517 if ( pViewShell && pViewShell->GetLayout() &&
1518 pViewShell->GetLayout()->IsAnyShellAccessible() )
1520 auto pNext = pFrame->FindNextCnt( true );
1521 auto pPrev = pFrame->FindPrevCnt();
1522 pViewShell->InvalidateAccessibleParaFlowRelation(
1523 pNext ? pNext->DynCastTextFrame() : nullptr,
1524 pPrev ? pPrev->DynCastTextFrame() : nullptr );
1526 #endif
1529 if( pFrame->IsFollow() )
1531 SwContentFrame* pMaster = pFrame->FindMaster();
1532 pMaster->SetFollow( pFrame->GetFollow() );
1534 pFrame->SetFollow( nullptr );//So it doesn't get funny ideas.
1535 //Otherwise it could be possible that a follow
1536 //gets destroyed before its master. Following
1537 //the now invalid pointer will then lead to an
1538 //illegal memory access. The chain can be
1539 //crushed here because we'll destroy all of it
1540 //anyway.
1542 if( pFrame->GetUpper() && pFrame->IsInFootnote() && !pFrame->GetIndNext() &&
1543 !pFrame->GetIndPrev() )
1545 SwFootnoteFrame *pFootnote = pFrame->FindFootnoteFrame();
1546 OSL_ENSURE( pFootnote, "You promised a FootnoteFrame?" );
1547 SwContentFrame* pCFrame;
1548 if( !pFootnote->GetFollow() && !pFootnote->GetMaster() &&
1549 nullptr != ( pCFrame = pFootnote->GetRefFromAttr()) && pCFrame->IsFollow() )
1551 OSL_ENSURE( pCFrame->IsTextFrame(), "NoTextFrame has Footnote?" );
1552 pCFrame->FindMaster()->Prepare( PrepareHint::FootnoteInvalidationGone );
1555 pFrame->Cut();
1556 SwFrame::DestroyFrame(pFrame);
1560 SwContentNode *SwContentNode::JoinNext()
1562 return this;
1566 /// Get info from Modify
1567 bool SwContentNode::GetInfo( SfxPoolItem& rInfo ) const
1569 switch( rInfo.Which() )
1571 case RES_FINDNEARESTNODE:
1572 if( GetAttr( RES_PAGEDESC ).GetPageDesc() )
1573 static_cast<SwFindNearestNode&>(rInfo).CheckNode( *this );
1574 return true;
1575 case RES_AUTOFMT_DOCNODE:
1576 if( &GetNodes() == static_cast<SwAutoFormatGetDocNode&>(rInfo).pNodes )
1578 return false;
1580 break;
1582 return sw::BroadcastingModify::GetInfo( rInfo );
1585 /// @param rAttr the attribute to set
1586 bool SwContentNode::SetAttr(const SfxPoolItem& rAttr )
1588 if( !GetpSwAttrSet() ) // Have the Nodes created by the corresponding AttrSets
1589 NewAttrSet( GetDoc().GetAttrPool() );
1591 OSL_ENSURE( GetpSwAttrSet(), "Why did't we create an AttrSet?");
1593 InvalidateInSwCache(RES_ATTRSET_CHG);
1595 bool bRet = false;
1596 // If Modify is locked, we do not send any Modifys
1597 if( IsModifyLocked() ||
1598 ( !HasWriterListeners() && RES_PARATR_NUMRULE != rAttr.Which() ))
1600 bRet = nullptr != AttrSetHandleHelper::Put( mpAttrSet, *this, rAttr );
1602 else
1604 SwAttrSet aOld( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ),
1605 aNew( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() );
1606 bRet = AttrSetHandleHelper::Put_BC( mpAttrSet, *this, rAttr, &aOld, &aNew );
1607 if( bRet )
1608 sw::ClientNotifyAttrChg(*this, *GetpSwAttrSet(), aOld, aNew);
1610 return bRet;
1613 bool SwContentNode::SetAttr( const SfxItemSet& rSet )
1615 InvalidateInSwCache(RES_ATTRSET_CHG);
1617 if( const SwFormatAutoFormat* pFnd = rSet.GetItemIfSet( RES_AUTO_STYLE, false ) )
1619 OSL_ENSURE( rSet.Count() == 1, "SetAutoStyle mixed with other attributes?!" );
1621 // If there already is an attribute set (usually containing a numbering
1622 // item), we have to merge the attribute of the new set into the old set:
1623 bool bSetParent = true;
1624 if ( GetpSwAttrSet() )
1626 bSetParent = false;
1627 AttrSetHandleHelper::Put( mpAttrSet, *this, *pFnd->GetStyleHandle() );
1629 else
1631 mpAttrSet = pFnd->GetStyleHandle();
1634 if ( bSetParent )
1636 // If the content node has a conditional style, we have to set the
1637 // string item containing the correct conditional style name (the
1638 // style name property has already been set during the import!)
1639 // In case we do not have a conditional style, we make use of the
1640 // fact that nobody else uses the attribute set behind the handle.
1641 // FME 2007-07-10 #i78124# If autostyle does not have a parent,
1642 // the string is empty.
1643 const SfxStringItem* pNameItem = nullptr;
1644 if ( nullptr != GetCondFormatColl() ||
1645 !(pNameItem = mpAttrSet->GetItemIfSet( RES_FRMATR_STYLE_NAME, false )) ||
1646 pNameItem->GetValue().isEmpty() )
1647 AttrSetHandleHelper::SetParent( mpAttrSet, *this, &GetAnyFormatColl(), GetFormatColl() );
1648 else
1649 const_cast<SfxItemSet*>(mpAttrSet.get())->SetParent( &GetFormatColl()->GetAttrSet() );
1652 return true;
1655 if( !GetpSwAttrSet() ) // Have the AttrsSets created by the corresponding Nodes
1656 NewAttrSet( GetDoc().GetAttrPool() );
1658 bool bRet = false;
1659 // If Modify is locked, do not send any Modifys
1660 if ( IsModifyLocked() ||
1661 ( !HasWriterListeners() &&
1662 SfxItemState::SET != rSet.GetItemState( RES_PARATR_NUMRULE, false ) ) )
1664 // Some special treatment for Attributes
1665 bRet = AttrSetHandleHelper::Put( mpAttrSet, *this, rSet );
1667 else
1669 SwAttrSet aOld( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ),
1670 aNew( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() );
1671 bRet = AttrSetHandleHelper::Put_BC( mpAttrSet, *this, rSet, &aOld, &aNew );
1672 if( bRet )
1673 sw::ClientNotifyAttrChg(*this, *GetpSwAttrSet(), aOld, aNew);
1675 return bRet;
1678 // With nWhich it takes the Hint from the Delta array
1679 bool SwContentNode::ResetAttr( sal_uInt16 nWhich1, sal_uInt16 nWhich2 )
1681 if( !GetpSwAttrSet() )
1682 return false;
1684 InvalidateInSwCache(RES_ATTRSET_CHG);
1686 // If Modify is locked, do not send out any Modifys
1687 if( IsModifyLocked() )
1689 sal_uInt16 nDel = 0;
1690 if ( !nWhich2 || nWhich2 < nWhich1 )
1692 nDel = ClearItemsFromAttrSet( { nWhich1 } );
1694 else
1695 nDel = AttrSetHandleHelper::ClearItem_BC( mpAttrSet, *this, nWhich1, nWhich2, nullptr, nullptr );
1697 if( !GetpSwAttrSet()->Count() ) // Empty? Delete
1698 mpAttrSet.reset();
1699 return 0 != nDel;
1702 // No valid area defined?
1703 if( !nWhich2 || nWhich2 < nWhich1 )
1704 nWhich2 = nWhich1; // Then set only this Item to 1st Id
1706 SwAttrSet aOld( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ),
1707 aNew( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() );
1708 bool bRet = 0 != AttrSetHandleHelper::ClearItem_BC( mpAttrSet, *this, nWhich1, nWhich2, &aOld, &aNew );
1710 if( bRet )
1712 sw::ClientNotifyAttrChg(*this, *GetpSwAttrSet(), aOld, aNew);
1714 if( !GetpSwAttrSet()->Count() ) // Empty?, delete it
1715 mpAttrSet.reset();
1717 return bRet;
1720 bool SwContentNode::ResetAttr( const std::vector<sal_uInt16>& rWhichArr )
1722 if( !GetpSwAttrSet() )
1723 return false;
1725 InvalidateInSwCache(RES_ATTRSET_CHG);
1726 // If Modify is locked, do not send out any Modifys
1727 sal_uInt16 nDel = 0;
1728 if( IsModifyLocked() )
1730 nDel = ClearItemsFromAttrSet( rWhichArr );
1732 else
1734 SwAttrSet aOld( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ),
1735 aNew( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() );
1737 for ( const auto& rWhich : rWhichArr )
1738 if( AttrSetHandleHelper::ClearItem_BC( mpAttrSet, *this, rWhich, &aOld, &aNew ))
1739 ++nDel;
1741 if( nDel )
1742 sw::ClientNotifyAttrChg(*this, *GetpSwAttrSet(), aOld, aNew);
1744 if( !GetpSwAttrSet()->Count() ) // Empty?, delete it
1745 mpAttrSet.reset();
1746 return 0 != nDel ;
1749 sal_uInt16 SwContentNode::ResetAllAttr()
1751 if( !GetpSwAttrSet() )
1752 return 0;
1753 InvalidateInSwCache(RES_ATTRSET_CHG);
1755 // If Modify is locked, do not send out any Modifys
1756 if( IsModifyLocked() )
1758 sal_uInt16 nDel = ClearItemsFromAttrSet( { 0 } );
1759 if( !GetpSwAttrSet()->Count() ) // Empty? Delete
1760 mpAttrSet.reset();
1761 return nDel;
1764 SwAttrSet aOld( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ),
1765 aNew( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() );
1766 bool bRet = 0 != AttrSetHandleHelper::ClearItem_BC( mpAttrSet, *this, 0, &aOld, &aNew );
1768 if( bRet )
1770 sw::ClientNotifyAttrChg(*this, *GetpSwAttrSet(), aOld, aNew);
1771 if( !GetpSwAttrSet()->Count() ) // Empty? Delete
1772 mpAttrSet.reset();
1774 return aNew.Count();
1777 bool SwContentNode::GetAttr( SfxItemSet& rSet ) const
1779 if( rSet.Count() )
1780 rSet.ClearItem();
1782 const SwAttrSet& rAttrSet = GetSwAttrSet();
1783 return rSet.Set( rAttrSet );
1786 sal_uInt16 SwContentNode::ClearItemsFromAttrSet( const std::vector<sal_uInt16>& rWhichIds )
1788 sal_uInt16 nRet = 0;
1789 if ( rWhichIds.empty() )
1790 return nRet;
1792 OSL_ENSURE( GetpSwAttrSet(), "no item set" );
1793 SwAttrSet aNewAttrSet( *GetpSwAttrSet() );
1794 for ( const auto& rWhichId : rWhichIds )
1796 nRet = nRet + aNewAttrSet.ClearItem( rWhichId );
1798 if ( nRet )
1799 AttrSetHandleHelper::GetNewAutoStyle( mpAttrSet, *this, aNewAttrSet );
1801 return nRet;
1804 const SfxPoolItem* SwContentNode::GetNoCondAttr( sal_uInt16 nWhich,
1805 bool bInParents ) const
1807 const SfxPoolItem* pFnd = nullptr;
1808 if( m_pCondColl && m_pCondColl->GetRegisteredIn() )
1810 if( !GetpSwAttrSet() || ( SfxItemState::SET != GetpSwAttrSet()->GetItemState(
1811 nWhich, false, &pFnd ) && bInParents ))
1813 (void)static_cast<const SwFormat*>(GetRegisteredIn())->GetItemState( nWhich, bInParents, &pFnd );
1816 // undo change of issue #i51029#
1817 // Note: <GetSwAttrSet()> returns <mpAttrSet>, if set, otherwise it returns
1818 // the attribute set of the paragraph style, which is valid for the
1819 // content node - see file <node.hxx>
1820 else
1822 GetSwAttrSet().GetItemState( nWhich, bInParents, &pFnd );
1824 return pFnd;
1827 static bool lcl_CheckMaxLength(SwNode const& rPrev, SwNode const& rNext)
1829 if (rPrev.GetNodeType() != rNext.GetNodeType())
1831 return false;
1833 if (!rPrev.IsTextNode())
1835 return true;
1838 // Check if a node can contain the other (order is not significant)
1839 return rPrev.GetTextNode()->GetSpaceLeft() > rNext.GetTextNode()->Len();
1842 /// Can we join two Nodes?
1843 /// We can return the 2nd position in pIdx.
1844 bool SwContentNode::CanJoinNext( SwNodeIndex* pIdx ) const
1846 const SwNodes& rNds = GetNodes();
1847 SwNodeIndex aIdx( *this, 1 );
1849 const SwNode* pNd = this;
1850 while( aIdx < rNds.Count()-1 &&
1851 (( pNd = &aIdx.GetNode())->IsSectionNode() ||
1852 ( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsSectionNode() )))
1853 ++aIdx;
1855 if (rNds.Count()-1 == aIdx.GetIndex())
1856 return false;
1857 if (!lcl_CheckMaxLength(*this, *pNd))
1859 return false;
1861 if( pIdx )
1862 *pIdx = aIdx;
1863 return true;
1866 /// Can we join two Nodes?
1867 /// We can return the 2nd position in pIdx.
1868 bool SwContentNode::CanJoinNext( SwPosition* pIdx ) const
1870 const SwNodes& rNds = GetNodes();
1871 SwNodeIndex aIdx( *this, 1 );
1873 const SwNode* pNd = this;
1874 while( aIdx < rNds.Count()-1 &&
1875 (( pNd = &aIdx.GetNode())->IsSectionNode() ||
1876 ( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsSectionNode() )))
1877 ++aIdx;
1879 if (rNds.Count()-1 == aIdx.GetIndex())
1880 return false;
1881 if (!lcl_CheckMaxLength(*this, *pNd))
1883 return false;
1885 if( pIdx )
1886 pIdx->Assign(aIdx);
1887 return true;
1890 /// Can we join two Nodes?
1891 /// We can return the 2nd position in pIdx.
1892 bool SwContentNode::CanJoinPrev( SwNodeIndex* pIdx ) const
1894 SwNodeIndex aIdx( *this, -1 );
1896 const SwNode* pNd = this;
1897 while( aIdx.GetIndex() &&
1898 (( pNd = &aIdx.GetNode())->IsSectionNode() ||
1899 ( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsSectionNode() )))
1900 --aIdx;
1902 if (SwNodeOffset(0) == aIdx.GetIndex())
1903 return false;
1904 if (!lcl_CheckMaxLength(*pNd, *this))
1906 return false;
1908 if( pIdx )
1909 *pIdx = aIdx;
1910 return true;
1913 void SwContentNode::SetCondFormatColl(SwFormatColl* pColl)
1915 if( !((!pColl && m_pCondColl) || ( pColl && !m_pCondColl ) ||
1916 ( pColl && pColl != m_pCondColl->GetRegisteredIn() )) )
1917 return;
1919 SwFormatColl* pOldColl = GetCondFormatColl();
1920 m_aCondCollListener.EndListeningAll();
1921 if(pColl)
1922 m_aCondCollListener.StartListening(pColl);
1923 m_pCondColl = pColl;
1924 if(GetpSwAttrSet())
1925 AttrSetHandleHelper::SetParent(mpAttrSet, *this, &GetAnyFormatColl(), GetFormatColl());
1927 if(!IsModifyLocked())
1929 SwFormatChg aTmp1(pOldColl ? pOldColl : GetFormatColl());
1930 SwFormatChg aTmp2(pColl ? pColl : GetFormatColl());
1931 CallSwClientNotify(sw::LegacyModifyHint(&aTmp1, &aTmp2));
1933 InvalidateInSwCache(RES_ATTRSET_CHG);
1936 bool SwContentNode::IsAnyCondition( SwCollCondition& rTmp ) const
1938 const SwNodes& rNds = GetNodes();
1940 Master_CollCondition nCond = Master_CollCondition::NONE;
1941 const SwStartNode* pSttNd = StartOfSectionNode();
1942 while( pSttNd )
1944 switch( pSttNd->GetNodeType() )
1946 case SwNodeType::Table: nCond = Master_CollCondition::PARA_IN_TABLEBODY; break;
1947 case SwNodeType::Section: nCond = Master_CollCondition::PARA_IN_SECTION; break;
1949 default:
1950 switch( pSttNd->GetStartNodeType() )
1952 case SwTableBoxStartNode:
1954 nCond = Master_CollCondition::PARA_IN_TABLEBODY;
1955 const SwTableNode* pTableNd = pSttNd->FindTableNode();
1956 const SwTableBox* pBox;
1957 if( pTableNd && nullptr != ( pBox = pTableNd->GetTable().
1958 GetTableBox(pSttNd->GetIndex()) ) &&
1959 pBox->IsInHeadline( &pTableNd->GetTable() ) )
1960 nCond = Master_CollCondition::PARA_IN_TABLEHEAD;
1962 break;
1963 case SwFlyStartNode: nCond = Master_CollCondition::PARA_IN_FRAME; break;
1964 case SwFootnoteStartNode:
1966 nCond = Master_CollCondition::PARA_IN_FOOTNOTE;
1967 const SwFootnoteIdxs& rFootnoteArr = rNds.GetDoc().GetFootnoteIdxs();
1968 const SwTextFootnote* pTextFootnote;
1969 const SwNode* pSrchNd = pSttNd;
1971 for( size_t n = 0; n < rFootnoteArr.size(); ++n )
1972 if( nullptr != ( pTextFootnote = rFootnoteArr[ n ])->GetStartNode() &&
1973 pSrchNd == &pTextFootnote->GetStartNode()->GetNode() )
1975 if( pTextFootnote->GetFootnote().IsEndNote() )
1976 nCond = Master_CollCondition::PARA_IN_ENDNOTE;
1977 break;
1980 break;
1981 case SwHeaderStartNode: nCond = Master_CollCondition::PARA_IN_HEADER; break;
1982 case SwFooterStartNode: nCond = Master_CollCondition::PARA_IN_FOOTER; break;
1983 case SwNormalStartNode: break;
1987 if( nCond != Master_CollCondition::NONE )
1989 rTmp.SetCondition( nCond, 0 );
1990 return true;
1992 pSttNd = pSttNd->GetIndex()
1993 ? pSttNd->StartOfSectionNode()
1994 : nullptr;
1999 SwOutlineNodes::size_type nPos;
2000 const SwOutlineNodes& rOutlNds = rNds.GetOutLineNds();
2001 if( !rOutlNds.empty() )
2003 if( !rOutlNds.Seek_Entry( const_cast<SwContentNode*>(this), &nPos ) && nPos )
2004 --nPos;
2005 if( nPos < rOutlNds.size() &&
2006 rOutlNds[ nPos ]->GetIndex() < GetIndex() )
2008 SwTextNode* pOutlNd = rOutlNds[ nPos ]->GetTextNode();
2010 if( pOutlNd->IsOutline())
2012 rTmp.SetCondition( Master_CollCondition::PARA_IN_OUTLINE, pOutlNd->GetAttrOutlineLevel() - 1 );
2013 return true;
2019 return false;
2022 void SwContentNode::ChkCondColl(const SwTextFormatColl* pColl)
2024 if(pColl != GetRegisteredIn())
2026 SAL_INFO("sw.core", "Not our cond collection, skipping check of Cond Colls.");
2027 return;
2029 if(&GetNodes() != &GetDoc().GetNodes())
2031 SAL_WARN("sw.core", "Nodes amiss, skipping check of Cond Colls.");
2032 return;
2034 // Check, just to be sure
2035 if( RES_CONDTXTFMTCOLL != GetFormatColl()->Which() )
2036 return;
2038 SwCollCondition aTmp( nullptr, Master_CollCondition::NONE, 0 );
2039 const SwCollCondition* pCColl;
2041 bool bDone = false;
2043 if( IsAnyCondition( aTmp ))
2045 pCColl = static_cast<SwConditionTextFormatColl*>(GetFormatColl())
2046 ->HasCondition( aTmp );
2048 if (pCColl)
2050 SetCondFormatColl( pCColl->GetTextFormatColl() );
2051 bDone = true;
2055 if (bDone)
2056 return;
2058 if( IsTextNode() && static_cast<SwTextNode*>(this)->GetNumRule())
2060 // Is at which Level in a list?
2061 aTmp.SetCondition( Master_CollCondition::PARA_IN_LIST,
2062 static_cast<SwTextNode*>(this)->GetActualListLevel() );
2063 pCColl = static_cast<SwConditionTextFormatColl*>(GetFormatColl())->
2064 HasCondition( aTmp );
2066 else
2067 pCColl = nullptr;
2069 if( pCColl )
2070 SetCondFormatColl( pCColl->GetTextFormatColl() );
2071 else if( m_pCondColl )
2072 SetCondFormatColl( nullptr );
2075 // #i42921#
2076 SvxFrameDirection SwContentNode::GetTextDirection( const SwPosition& rPos,
2077 const Point* pPt ) const
2079 SvxFrameDirection nRet = SvxFrameDirection::Unknown;
2081 Point aPt;
2082 if( pPt )
2083 aPt = *pPt;
2085 // #i72024# - No format of the frame, because this can cause recursive layout actions
2086 std::pair<Point, bool> const tmp(aPt, false);
2087 SwFrame* pFrame = getLayoutFrame(GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), &rPos, &tmp);
2089 if ( pFrame )
2091 if ( pFrame->IsVertical() )
2093 if (pFrame->IsVertLRBT())
2094 nRet = SvxFrameDirection::Vertical_LR_BT;
2095 else if (pFrame->IsRightToLeft())
2096 nRet = SvxFrameDirection::Vertical_LR_TB;
2097 else
2098 nRet = SvxFrameDirection::Vertical_RL_TB;
2100 else
2102 if ( pFrame->IsRightToLeft() )
2103 nRet = SvxFrameDirection::Horizontal_RL_TB;
2104 else
2105 nRet = SvxFrameDirection::Horizontal_LR_TB;
2109 return nRet;
2112 std::unique_ptr<SwOLENodes> SwContentNode::CreateOLENodesArray( const SwFormatColl& rColl, bool bOnlyWithInvalidSize )
2114 std::unique_ptr<SwOLENodes> pNodes;
2115 SwIterator<SwContentNode,SwFormatColl> aIter( rColl );
2116 for( SwContentNode* pNd = aIter.First(); pNd; pNd = aIter.Next() )
2118 SwOLENode *pONd = pNd->GetOLENode();
2119 if ( pONd && (!bOnlyWithInvalidSize || pONd->IsOLESizeInvalid()) )
2121 if ( !pNodes )
2122 pNodes.reset(new SwOLENodes);
2123 pNodes->push_back( pONd );
2127 return pNodes;
2130 drawinglayer::attribute::SdrAllFillAttributesHelperPtr SwContentNode::getSdrAllFillAttributesHelper() const
2132 return drawinglayer::attribute::SdrAllFillAttributesHelperPtr();
2136 * Document Interface Access
2138 const IDocumentSettingAccess* SwNode::getIDocumentSettingAccess() const { return &GetDoc().GetDocumentSettingManager(); }
2139 const IDocumentDeviceAccess& SwNode::getIDocumentDeviceAccess() const { return GetDoc().getIDocumentDeviceAccess(); }
2140 const IDocumentRedlineAccess& SwNode::getIDocumentRedlineAccess() const { return GetDoc().getIDocumentRedlineAccess(); }
2141 const IDocumentStylePoolAccess& SwNode::getIDocumentStylePoolAccess() const { return GetDoc().getIDocumentStylePoolAccess(); }
2142 const IDocumentDrawModelAccess& SwNode::getIDocumentDrawModelAccess() const { return GetDoc().getIDocumentDrawModelAccess(); }
2143 const IDocumentLayoutAccess& SwNode::getIDocumentLayoutAccess() const { return GetDoc().getIDocumentLayoutAccess(); }
2144 IDocumentLayoutAccess& SwNode::getIDocumentLayoutAccess() { return GetDoc().getIDocumentLayoutAccess(); }
2145 const IDocumentLinksAdministration& SwNode::getIDocumentLinksAdministration() const { return GetDoc().getIDocumentLinksAdministration(); }
2146 IDocumentLinksAdministration& SwNode::getIDocumentLinksAdministration() { return GetDoc().getIDocumentLinksAdministration(); }
2147 const IDocumentFieldsAccess& SwNode::getIDocumentFieldsAccess() const { return GetDoc().getIDocumentFieldsAccess(); }
2148 IDocumentFieldsAccess& SwNode::getIDocumentFieldsAccess() { return GetDoc().getIDocumentFieldsAccess(); }
2149 IDocumentContentOperations& SwNode::getIDocumentContentOperations() { return GetDoc().getIDocumentContentOperations(); }
2150 IDocumentListItems& SwNode::getIDocumentListItems() { return GetDoc().getIDocumentListItems(); } // #i83479#
2152 const IDocumentMarkAccess* SwNode::getIDocumentMarkAccess() const { return GetDoc().getIDocumentMarkAccess(); }
2153 IStyleAccess& SwNode::getIDocumentStyleAccess() { return GetDoc().GetIStyleAccess(); }
2155 bool SwNode::IsInRedlines() const
2157 const SwDoc& rDoc = GetDoc();
2159 return rDoc.getIDocumentRedlineAccess().IsInRedlines(*this);
2162 void SwNode::AddAnchoredFly(SwFrameFormat *const pFlyFormat)
2164 assert(pFlyFormat);
2165 assert(pFlyFormat->GetAnchor(false).GetAnchorNode() == this);
2166 // check node type, cf. SwFormatAnchor::SetAnchor()
2167 assert(IsTextNode() || IsStartNode() || IsTableNode());
2168 m_aAnchoredFlys.push_back(pFlyFormat);
2171 void SwNode::RemoveAnchoredFly(SwFrameFormat *const pFlyFormat)
2173 assert(pFlyFormat);
2174 // cannot assert this in Remove because it is called when new anchor is already set
2175 // assert(&pFlyFormat->GetAnchor(false).GetContentAnchor()->GetNode() == this);
2176 assert(IsTextNode() || IsStartNode() || IsTableNode());
2177 auto it(std::find(m_aAnchoredFlys.begin(), m_aAnchoredFlys.end(), pFlyFormat));
2178 assert(it != m_aAnchoredFlys.end());
2179 m_aAnchoredFlys.erase(it);
2182 void SwNode::resetAndQueueAccessibilityCheck(bool bIssueObjectNameChanged)
2184 GetDoc().getOnlineAccessibilityCheck()->resetAndQueue(this, bIssueObjectNameChanged);
2188 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */