1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 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/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 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 . 18 */ 19 20 #include <hintids.hxx> 21 #include <editeng/protitem.hxx> 22 #include <osl/diagnose.h> 23 #include <tools/gen.hxx> 24 #include <com/sun/star/i18n/CharacterIteratorMode.hpp> 25 #include <com/sun/star/i18n/XBreakIterator.hpp> 26 #include <fmtcntnt.hxx> 27 #include <fmtanchr.hxx> 28 #include <frmfmt.hxx> 29 #include <txtftn.hxx> 30 #include <ftnfrm.hxx> 31 #include <doc.hxx> 32 #include <node.hxx> 33 #include <ndindex.hxx> 34 #include <numrule.hxx> 35 #include <swtable.hxx> 36 #include <ndtxt.hxx> 37 #include <pam.hxx> 38 #include <swcache.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 #ifdef DBG_UTIL 73 #include <sal/backtrace.hxx> 74 #endif 75 76 using namespace ::com::sun::star::i18n; 77 78 79 /* 80 * Some local helper functions for the attribute set handle of a content node. 81 * Since the attribute set of a content node may not be modified directly, 82 * we always have to create a new SwAttrSet, do the modifications, and get 83 * a new handle from the style access 84 */ 85 86 namespace AttrSetHandleHelper 87 { 88 89 static void GetNewAutoStyle( std::shared_ptr<const SfxItemSet>& rpAttrSet, 90 const SwContentNode& rNode, 91 SwAttrSet const & rNewAttrSet ) 92 { 93 const SwAttrSet* pAttrSet = static_cast<const SwAttrSet*>(rpAttrSet.get()); 94 if( rNode.GetModifyAtAttr() ) 95 const_cast<SwAttrSet*>(pAttrSet)->SetModifyAtAttr( nullptr ); 96 IStyleAccess& rSA = pAttrSet->GetPool()->GetDoc()->GetIStyleAccess(); 97 rpAttrSet = rSA.getAutomaticStyle( rNewAttrSet, rNode.IsTextNode() ? 98 IStyleAccess::AUTO_STYLE_PARA : 99 IStyleAccess::AUTO_STYLE_NOTXT ); 100 const bool bSetModifyAtAttr = const_cast<SwAttrSet*>(static_cast<const SwAttrSet*>(rpAttrSet.get()))->SetModifyAtAttr( &rNode ); 101 rNode.SetModifyAtAttr( bSetModifyAtAttr ); 102 } 103 104 static void SetParent( std::shared_ptr<const SfxItemSet>& rpAttrSet, 105 const SwContentNode& rNode, 106 const SwFormat* pParentFormat, 107 const SwFormat* pConditionalFormat ) 108 { 109 const SwAttrSet* pAttrSet = static_cast<const SwAttrSet*>(rpAttrSet.get()); 110 OSL_ENSURE( pAttrSet, "no SwAttrSet" ); 111 OSL_ENSURE( pParentFormat || !pConditionalFormat, "ConditionalFormat without ParentFormat?" ); 112 113 const SwAttrSet* pParentSet = pParentFormat ? &pParentFormat->GetAttrSet() : nullptr; 114 115 if ( pParentSet == pAttrSet->GetParent() ) 116 return; 117 118 SwAttrSet aNewSet( *pAttrSet ); 119 aNewSet.SetParent( pParentSet ); 120 aNewSet.ClearItem( RES_FRMATR_STYLE_NAME ); 121 aNewSet.ClearItem( RES_FRMATR_CONDITIONAL_STYLE_NAME ); 122 123 if ( pParentFormat ) 124 { 125 OUString sVal; 126 SwStyleNameMapper::FillProgName( pParentFormat->GetName(), sVal, SwGetPoolIdFromName::TxtColl ); 127 const SfxStringItem aAnyFormatColl( RES_FRMATR_STYLE_NAME, sVal ); 128 aNewSet.Put( aAnyFormatColl ); 129 130 if ( pConditionalFormat != pParentFormat ) 131 SwStyleNameMapper::FillProgName( pConditionalFormat->GetName(), sVal, SwGetPoolIdFromName::TxtColl ); 132 133 const SfxStringItem aFormatColl( RES_FRMATR_CONDITIONAL_STYLE_NAME, sVal ); 134 aNewSet.Put( aFormatColl ); 135 } 136 137 GetNewAutoStyle( rpAttrSet, rNode, aNewSet ); 138 } 139 140 static const SfxPoolItem* Put( std::shared_ptr<const SfxItemSet>& rpAttrSet, 141 const SwContentNode& rNode, 142 const SfxPoolItem& rAttr ) 143 { 144 SwAttrSet aNewSet( static_cast<const SwAttrSet&>(*rpAttrSet) ); 145 const SfxPoolItem* pRet = aNewSet.Put( rAttr ); 146 if ( pRet ) 147 GetNewAutoStyle( rpAttrSet, rNode, aNewSet ); 148 return pRet; 149 } 150 151 static bool Put( std::shared_ptr<const SfxItemSet>& rpAttrSet, const SwContentNode& rNode, 152 const SfxItemSet& rSet ) 153 { 154 SwAttrSet aNewSet( static_cast<const SwAttrSet&>(*rpAttrSet) ); 155 156 // #i76273# Robust 157 std::optional<SfxItemSetFixed<RES_FRMATR_STYLE_NAME, RES_FRMATR_CONDITIONAL_STYLE_NAME>> pStyleNames; 158 if ( SfxItemState::SET == rSet.GetItemState( RES_FRMATR_STYLE_NAME, false ) ) 159 { 160 pStyleNames.emplace( *aNewSet.GetPool() ); 161 pStyleNames->Put( aNewSet ); 162 } 163 164 const bool bRet = aNewSet.Put( rSet ); 165 166 // #i76273# Robust 167 if ( pStyleNames ) 168 { 169 aNewSet.Put( *pStyleNames ); 170 } 171 172 if ( bRet ) 173 GetNewAutoStyle( rpAttrSet, rNode, aNewSet ); 174 175 return bRet; 176 } 177 178 static bool Put_BC( std::shared_ptr<const SfxItemSet>& rpAttrSet, 179 const SwContentNode& rNode, const SfxPoolItem& rAttr, 180 SwAttrSet* pOld, SwAttrSet* pNew ) 181 { 182 SwAttrSet aNewSet( static_cast<const SwAttrSet&>(*rpAttrSet) ); 183 184 // for a correct broadcast, we need to do a SetModifyAtAttr with the items 185 // from aNewSet. The 'regular' SetModifyAtAttr is done in GetNewAutoStyle 186 if( rNode.GetModifyAtAttr() ) 187 aNewSet.SetModifyAtAttr( &rNode ); 188 189 const bool bRet = aNewSet.Put_BC( rAttr, pOld, pNew ); 190 191 if ( bRet ) 192 GetNewAutoStyle( rpAttrSet, rNode, aNewSet ); 193 194 return bRet; 195 } 196 197 static bool Put_BC( std::shared_ptr<const SfxItemSet>& rpAttrSet, 198 const SwContentNode& rNode, const SfxItemSet& rSet, 199 SwAttrSet* pOld, SwAttrSet* pNew ) 200 { 201 SwAttrSet aNewSet( static_cast<const SwAttrSet&>(*rpAttrSet) ); 202 203 // #i76273# Robust 204 std::optional<SfxItemSetFixed<RES_FRMATR_STYLE_NAME, RES_FRMATR_CONDITIONAL_STYLE_NAME>> pStyleNames; 205 if ( SfxItemState::SET == rSet.GetItemState( RES_FRMATR_STYLE_NAME, false ) ) 206 { 207 pStyleNames.emplace( *aNewSet.GetPool() ); 208 pStyleNames->Put( aNewSet ); 209 } 210 211 // for a correct broadcast, we need to do a SetModifyAtAttr with the items 212 // from aNewSet. The 'regular' SetModifyAtAttr is done in GetNewAutoStyle 213 if( rNode.GetModifyAtAttr() ) 214 aNewSet.SetModifyAtAttr( &rNode ); 215 216 const bool bRet = aNewSet.Put_BC( rSet, pOld, pNew ); 217 218 // #i76273# Robust 219 if ( pStyleNames ) 220 { 221 aNewSet.Put( *pStyleNames ); 222 } 223 224 if ( bRet ) 225 GetNewAutoStyle( rpAttrSet, rNode, aNewSet ); 226 227 return bRet; 228 } 229 230 static sal_uInt16 ClearItem_BC( std::shared_ptr<const SfxItemSet>& rpAttrSet, 231 const SwContentNode& rNode, sal_uInt16 nWhich, 232 SwAttrSet* pOld, SwAttrSet* pNew ) 233 { 234 SwAttrSet aNewSet( static_cast<const SwAttrSet&>(*rpAttrSet) ); 235 if( rNode.GetModifyAtAttr() ) 236 aNewSet.SetModifyAtAttr( &rNode ); 237 const sal_uInt16 nRet = aNewSet.ClearItem_BC( nWhich, pOld, pNew ); 238 if ( nRet ) 239 GetNewAutoStyle( rpAttrSet, rNode, aNewSet ); 240 return nRet; 241 } 242 243 static sal_uInt16 ClearItem_BC( std::shared_ptr<const SfxItemSet>& rpAttrSet, 244 const SwContentNode& rNode, 245 sal_uInt16 nWhich1, sal_uInt16 nWhich2, 246 SwAttrSet* pOld, SwAttrSet* pNew ) 247 { 248 SwAttrSet aNewSet( static_cast<const SwAttrSet&>(*rpAttrSet) ); 249 if( rNode.GetModifyAtAttr() ) 250 aNewSet.SetModifyAtAttr( &rNode ); 251 const sal_uInt16 nRet = aNewSet.ClearItem_BC( nWhich1, nWhich2, pOld, pNew ); 252 if ( nRet ) 253 GetNewAutoStyle( rpAttrSet, rNode, aNewSet ); 254 return nRet; 255 } 256 257 } 258 259 /** Returns the section level at the position given by aIndex. 260 * 261 * We use the following logic: 262 * S = Start, E = End, C = ContentNode 263 * Level 0 = E 264 * 1 = S E 265 * 2 = SC 266 * 267 * All EndNodes of the BaseSection have level 0 268 * All StartNodes of the BaseSection have level 1 269 */ 270 sal_uInt16 SwNode::GetSectionLevel() const 271 { 272 // EndNode of a BaseSection? They are always 0! 273 if( IsEndNode() && SwNodeOffset(0) == m_pStartOfSection->StartOfSectionIndex() ) 274 return 0; 275 276 sal_uInt16 nLevel; 277 const SwNode* pNode = IsStartNode() ? this : m_pStartOfSection; 278 for( nLevel = 1; SwNodeOffset(0) != pNode->StartOfSectionIndex(); ++nLevel ) 279 pNode = pNode->m_pStartOfSection; 280 return IsEndNode() ? nLevel-1 : nLevel; 281 } 282 283 #ifdef DBG_UTIL 284 tools::Long SwNode::s_nSerial = 0; 285 #endif 286 287 SwNode::SwNode( const SwNodeIndex &rWhere, const SwNodeType nNdType ) 288 : m_nNodeType( nNdType ) 289 , m_nAFormatNumLvl( 0 ) 290 , m_bIgnoreDontExpand( false) 291 , m_eMerge(Merge::None) 292 #ifdef DBG_UTIL 293 , m_nSerial( s_nSerial++) 294 #endif 295 , m_pStartOfSection( nullptr ) 296 { 297 if( !rWhere.GetIndex() ) 298 return; 299 300 SwNodes& rNodes = const_cast<SwNodes&> (rWhere.GetNodes()); 301 SwNode* pNd = rNodes[ rWhere.GetIndex() -1 ]; 302 rNodes.InsertNode( this, rWhere ); 303 m_pStartOfSection = pNd->GetStartNode(); 304 if( nullptr == m_pStartOfSection ) 305 { 306 m_pStartOfSection = pNd->m_pStartOfSection; 307 if( pNd->GetEndNode() ) // Skip EndNode ? Section 308 { 309 pNd = m_pStartOfSection; 310 m_pStartOfSection = pNd->m_pStartOfSection; 311 } 312 } 313 } 314 315 /** Inserts a node into the rNodes array at the rWhere position 316 * 317 * @param rNodes the variable array in that the node will be inserted 318 * @param nPos position within the array where the node will be inserted 319 * @param nNdType the type of node to insert 320 */ 321 SwNode::SwNode( SwNodes& rNodes, SwNodeOffset nPos, const SwNodeType nNdType ) 322 : m_nNodeType( nNdType ) 323 , m_nAFormatNumLvl( 0 ) 324 , m_bIgnoreDontExpand( false) 325 , m_eMerge(Merge::None) 326 #ifdef DBG_UTIL 327 , m_nSerial( s_nSerial++) 328 #endif 329 , m_pStartOfSection( nullptr ) 330 { 331 if( !nPos ) 332 return; 333 334 SwNode* pNd = rNodes[ nPos - 1 ]; 335 rNodes.InsertNode( this, nPos ); 336 m_pStartOfSection = pNd->GetStartNode(); 337 if( nullptr == m_pStartOfSection ) 338 { 339 m_pStartOfSection = pNd->m_pStartOfSection; 340 if( pNd->GetEndNode() ) // Skip EndNode ? Section! 341 { 342 pNd = m_pStartOfSection; 343 m_pStartOfSection = pNd->m_pStartOfSection; 344 } 345 } 346 } 347 348 SwNode::~SwNode() 349 { 350 assert(m_aAnchoredFlys.empty() || GetDoc().IsInDtor()); // must all be deleted 351 InvalidateInSwCache(RES_OBJECTDYING); 352 assert(!IsInCache()); 353 } 354 355 /// Find the TableNode in which it is located. 356 /// If we're not in a table: return 0 357 SwTableNode* SwNode::FindTableNode() 358 { 359 if( IsTableNode() ) 360 return GetTableNode(); 361 SwStartNode* pTmp = m_pStartOfSection; 362 while( !pTmp->IsTableNode() && pTmp->GetIndex() ) 363 pTmp = pTmp->m_pStartOfSection; 364 return pTmp->GetTableNode(); 365 } 366 367 /// Is the node located in the visible area of the Shell? 368 bool SwNode::IsInVisibleArea( SwViewShell const * pSh ) const 369 { 370 bool bRet = false; 371 const SwContentNode* pNd; 372 373 if( SwNodeType::Start & m_nNodeType ) 374 { 375 SwNodeIndex aIdx( *this ); 376 pNd = GetNodes().GoNext( &aIdx ); 377 } 378 else if( SwNodeType::End & m_nNodeType ) 379 { 380 SwNodeIndex aIdx( *EndOfSectionNode() ); 381 pNd = SwNodes::GoPrevious( &aIdx ); 382 } 383 else 384 pNd = GetContentNode(); 385 386 if( !pSh ) 387 // Get the Shell from the Doc 388 pSh = GetDoc().getIDocumentLayoutAccess().GetCurrentViewShell(); 389 390 if( pSh ) 391 { 392 const SwFrame* pFrame; 393 if (pNd && nullptr != (pFrame = pNd->getLayoutFrame(pSh->GetLayout(), nullptr, nullptr))) 394 { 395 396 if ( pFrame->IsInTab() ) 397 pFrame = pFrame->FindTabFrame(); 398 399 if( !pFrame->isFrameAreaDefinitionValid() ) 400 { 401 do 402 { 403 pFrame = pFrame->FindPrev(); 404 } 405 while ( pFrame && !pFrame->isFrameAreaDefinitionValid() ); 406 } 407 408 if( !pFrame || pSh->VisArea().Overlaps( pFrame->getFrameArea() ) ) 409 bRet = true; 410 } 411 } 412 413 return bRet; 414 } 415 416 bool SwNode::IsInProtectSect() const 417 { 418 const SwNode* pNd = SwNodeType::Section == m_nNodeType ? m_pStartOfSection : this; 419 const SwSectionNode* pSectNd = pNd->FindSectionNode(); 420 return pSectNd && pSectNd->GetSection().IsProtectFlag(); 421 } 422 423 /// Does the node contain anything protected? 424 /// I.e.: Area/Frame/Table rows/... including the Anchor for 425 /// Frames/Footnotes/... 426 bool SwNode::IsProtect() const 427 { 428 const SwNode* pNd = SwNodeType::Section == m_nNodeType ? m_pStartOfSection : this; 429 const SwStartNode* pSttNd = pNd->FindSectionNode(); 430 if( pSttNd && static_cast<const SwSectionNode*>(pSttNd)->GetSection().IsProtectFlag() ) 431 return true; 432 433 pSttNd = FindTableBoxStartNode(); 434 if( nullptr != pSttNd ) 435 { 436 SwContentFrame* pCFrame; 437 if( IsContentNode() && nullptr != (pCFrame = static_cast<const SwContentNode*>(this)->getLayoutFrame( GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() ) )) 438 return pCFrame->IsProtected(); 439 440 const SwTableBox* pBox = pSttNd->FindTableNode()->GetTable(). 441 GetTableBox( pSttNd->GetIndex() ); 442 //Robust #149568 443 if( pBox && pBox->GetFrameFormat()->GetProtect().IsContentProtected() ) 444 return true; 445 } 446 447 SwFrameFormat* pFlyFormat = GetFlyFormat(); 448 if( pFlyFormat ) 449 { 450 if (pFlyFormat->GetProtect().IsContentProtected()) 451 return true; 452 const SwFormatAnchor& rAnchor = pFlyFormat->GetAnchor(); 453 const SwPosition* pAnchorPos = rAnchor.GetContentAnchor(); 454 if (!pAnchorPos) 455 return false; 456 const SwNode& rAnchorNd = pAnchorPos->nNode.GetNode(); 457 return &rAnchorNd != this && rAnchorNd.IsProtect(); 458 } 459 460 pSttNd = FindFootnoteStartNode(); 461 if( nullptr != pSttNd ) 462 { 463 const SwTextFootnote* pTFootnote = GetDoc().GetFootnoteIdxs().SeekEntry( 464 SwNodeIndex( *pSttNd ) ); 465 if( pTFootnote ) 466 return pTFootnote->GetTextNode().IsProtect(); 467 } 468 469 return false; 470 } 471 472 /// Find the PageDesc that is used to format this node. If the Layout is available, 473 /// we search through that. Else we can only do it the hard way by searching onwards through the nodes. 474 const SwPageDesc* SwNode::FindPageDesc( SwNodeOffset* pPgDescNdIdx ) const 475 { 476 if ( !GetNodes().IsDocNodes() ) 477 { 478 return nullptr; 479 } 480 481 const SwPageDesc* pPgDesc = nullptr; 482 483 const SwContentNode* pNode; 484 if( SwNodeType::Start & m_nNodeType ) 485 { 486 SwNodeIndex aIdx( *this ); 487 pNode = GetNodes().GoNext( &aIdx ); 488 } 489 else if( SwNodeType::End & m_nNodeType ) 490 { 491 SwNodeIndex aIdx( *EndOfSectionNode() ); 492 pNode = SwNodes::GoPrevious( &aIdx ); 493 } 494 else 495 { 496 pNode = GetContentNode(); 497 if( pNode ) 498 pPgDesc = static_cast<const SwFormatPageDesc&>(pNode->GetAttr( RES_PAGEDESC )).GetPageDesc(); 499 } 500 501 // Are we going through the layout? 502 if( !pPgDesc ) 503 { 504 const SwFrame* pFrame; 505 const SwPageFrame* pPage; 506 if (pNode && nullptr != (pFrame = pNode->getLayoutFrame(pNode->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, nullptr)) && 507 nullptr != ( pPage = pFrame->FindPageFrame() ) ) 508 { 509 pPgDesc = pPage->GetPageDesc(); 510 if ( pPgDescNdIdx ) 511 { 512 *pPgDescNdIdx = pNode->GetIndex(); 513 } 514 } 515 } 516 517 if( !pPgDesc ) 518 { 519 // Thus via the nodes array 520 const SwDoc& rDoc = GetDoc(); 521 const SwNode* pNd = this; 522 const SwStartNode* pSttNd; 523 if( pNd->GetIndex() < GetNodes().GetEndOfExtras().GetIndex() && 524 nullptr != ( pSttNd = pNd->FindFlyStartNode() ) ) 525 { 526 // Find the right Anchor first 527 const SwFrameFormat* pFormat = nullptr; 528 const SwFrameFormats& rFormats = *rDoc.GetSpzFrameFormats(); 529 530 for( size_t n = 0; n < rFormats.size(); ++n ) 531 { 532 const SwFrameFormat* pFrameFormat = rFormats[ n ]; 533 const SwFormatContent& rContent = pFrameFormat->GetContent(); 534 if( rContent.GetContentIdx() && 535 &rContent.GetContentIdx()->GetNode() == static_cast<SwNode const *>(pSttNd) ) 536 { 537 pFormat = pFrameFormat; 538 break; 539 } 540 } 541 542 if( pFormat ) 543 { 544 const SwFormatAnchor* pAnchor = &pFormat->GetAnchor(); 545 if ((RndStdIds::FLY_AT_PAGE != pAnchor->GetAnchorId()) && 546 pAnchor->GetContentAnchor() ) 547 { 548 pNd = &pAnchor->GetContentAnchor()->nNode.GetNode(); 549 const SwNode* pFlyNd = pNd->FindFlyStartNode(); 550 while( pFlyNd ) 551 { 552 // Get up through the Anchor 553 size_t n; 554 for( n = 0; n < rFormats.size(); ++n ) 555 { 556 const SwFrameFormat* pFrameFormat = rFormats[ n ]; 557 const SwNodeIndex* pIdx = pFrameFormat->GetContent(). 558 GetContentIdx(); 559 if( pIdx && pFlyNd == &pIdx->GetNode() ) 560 { 561 if( pFormat == pFrameFormat ) 562 { 563 pNd = pFlyNd; 564 pFlyNd = nullptr; 565 break; 566 } 567 pAnchor = &pFrameFormat->GetAnchor(); 568 if ((RndStdIds::FLY_AT_PAGE == pAnchor->GetAnchorId()) || 569 !pAnchor->GetContentAnchor() ) 570 { 571 pFlyNd = nullptr; 572 break; 573 } 574 575 pFlyNd = pAnchor->GetContentAnchor()->nNode. 576 GetNode().FindFlyStartNode(); 577 break; 578 } 579 } 580 if( n >= rFormats.size() ) 581 { 582 OSL_ENSURE( false, "FlySection, but no Format found" ); 583 return nullptr; 584 } 585 } 586 } 587 } 588 // pNd should now contain the correct Anchor or it's still this 589 } 590 591 if( pNd->GetIndex() < GetNodes().GetEndOfExtras().GetIndex() ) 592 { 593 if( pNd->GetIndex() > GetNodes().GetEndOfAutotext().GetIndex() ) 594 { 595 pPgDesc = &rDoc.GetPageDesc( 0 ); 596 pNd = nullptr; 597 } 598 else 599 { 600 // Find the Body text node 601 if( nullptr != ( pSttNd = pNd->FindHeaderStartNode() ) || 602 nullptr != ( pSttNd = pNd->FindFooterStartNode() )) 603 { 604 // Then find this StartNode in the PageDescs 605 sal_uInt16 nId; 606 UseOnPage eAskUse; 607 if( SwHeaderStartNode == pSttNd->GetStartNodeType()) 608 { 609 nId = RES_HEADER; 610 eAskUse = UseOnPage::HeaderShare; 611 } 612 else 613 { 614 nId = RES_FOOTER; 615 eAskUse = UseOnPage::FooterShare; 616 } 617 618 for( size_t n = rDoc.GetPageDescCnt(); n && !pPgDesc; ) 619 { 620 const SwPageDesc& rPgDsc = rDoc.GetPageDesc( --n ); 621 const SwFrameFormat* pFormat = &rPgDsc.GetMaster(); 622 int nStt = 0, nLast = 1; 623 if( !( eAskUse & rPgDsc.ReadUseOn() )) ++nLast; 624 625 for( ; nStt < nLast; ++nStt, pFormat = &rPgDsc.GetLeft() ) 626 { 627 const SwFrameFormat * pHdFtFormat = nId == RES_HEADER 628 ? static_cast<SwFormatHeader const &>( 629 pFormat->GetFormatAttr(nId)).GetHeaderFormat() 630 : static_cast<SwFormatFooter const &>( 631 pFormat->GetFormatAttr(nId)).GetFooterFormat(); 632 if( pHdFtFormat ) 633 { 634 const SwFormatContent& rContent = pHdFtFormat->GetContent(); 635 if( rContent.GetContentIdx() && 636 &rContent.GetContentIdx()->GetNode() == 637 static_cast<SwNode const *>(pSttNd) ) 638 { 639 pPgDesc = &rPgDsc; 640 break; 641 } 642 } 643 } 644 } 645 646 if( !pPgDesc ) 647 pPgDesc = &rDoc.GetPageDesc( 0 ); 648 pNd = nullptr; 649 } 650 else if( nullptr != ( pSttNd = pNd->FindFootnoteStartNode() )) 651 { 652 // the Anchor can only be in the Body text 653 const SwTextFootnote* pTextFootnote; 654 const SwFootnoteIdxs& rFootnoteArr = rDoc.GetFootnoteIdxs(); 655 for( size_t n = 0; n < rFootnoteArr.size(); ++n ) 656 if( nullptr != ( pTextFootnote = rFootnoteArr[ n ])->GetStartNode() && 657 static_cast<SwNode const *>(pSttNd) == 658 &pTextFootnote->GetStartNode()->GetNode() ) 659 { 660 pNd = &pTextFootnote->GetTextNode(); 661 break; 662 } 663 } 664 else 665 { 666 // Can only be a page-bound Fly (or something newer). 667 // we can only return the standard here 668 OSL_ENSURE( pNd->FindFlyStartNode(), 669 "Where is this Node?" ); 670 671 pPgDesc = &rDoc.GetPageDesc( 0 ); 672 pNd = nullptr; 673 } 674 } 675 } 676 677 if( pNd ) 678 { 679 SwFindNearestNode aInfo( *pNd ); 680 // Over all Nodes of all PageDescs 681 for (const SfxPoolItem* pItem : rDoc.GetAttrPool().GetItemSurrogates(RES_PAGEDESC)) 682 { 683 auto pPageDescItem = dynamic_cast<const SwFormatPageDesc*>(pItem); 684 if( pPageDescItem && pPageDescItem->GetDefinedIn() ) 685 { 686 const sw::BroadcastingModify* pMod = pPageDescItem->GetDefinedIn(); 687 if( auto pContentNode = dynamic_cast<const SwContentNode*>( pMod) ) 688 aInfo.CheckNode( *pContentNode ); 689 else if( auto pFormat = dynamic_cast<const SwFormat*>( pMod) ) 690 pFormat->GetInfo( aInfo ); 691 } 692 } 693 694 pNd = aInfo.GetFoundNode(); 695 if( nullptr != pNd ) 696 { 697 if( pNd->IsContentNode() ) 698 pPgDesc = static_cast<const SwFormatPageDesc&>(pNd->GetContentNode()-> 699 GetAttr( RES_PAGEDESC )).GetPageDesc(); 700 else if( pNd->IsTableNode() ) 701 pPgDesc = pNd->GetTableNode()->GetTable(). 702 GetFrameFormat()->GetPageDesc().GetPageDesc(); 703 else if( pNd->IsSectionNode() ) 704 pPgDesc = pNd->GetSectionNode()->GetSection(). 705 GetFormat()->GetPageDesc().GetPageDesc(); 706 if ( pPgDescNdIdx ) 707 { 708 *pPgDescNdIdx = pNd->GetIndex(); 709 } 710 } 711 if( !pPgDesc ) 712 pPgDesc = &rDoc.GetPageDesc( 0 ); 713 } 714 } 715 return pPgDesc; 716 } 717 718 /// If the node is located in a Fly, we return it formatted accordingly 719 SwFrameFormat* SwNode::GetFlyFormat() const 720 { 721 SwFrameFormat* pRet = nullptr; 722 const SwNode* pSttNd = FindFlyStartNode(); 723 if( pSttNd ) 724 { 725 if( IsContentNode() ) 726 { 727 SwContentFrame* pFrame = SwIterator<SwContentFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>(*static_cast<const SwContentNode*>(this)).First(); 728 if( pFrame ) 729 pRet = pFrame->FindFlyFrame()->GetFormat(); 730 } 731 if( !pRet ) 732 { 733 // The hard way through the Doc is our last way out 734 const SwFrameFormats& rFrameFormatTable = *GetDoc().GetSpzFrameFormats(); 735 for( size_t n = 0; n < rFrameFormatTable.size(); ++n ) 736 { 737 SwFrameFormat* pFormat = rFrameFormatTable[n]; 738 // Only Writer fly frames can contain Writer nodes. 739 if (pFormat->Which() != RES_FLYFRMFMT) 740 continue; 741 const SwFormatContent& rContent = pFormat->GetContent(); 742 if( rContent.GetContentIdx() && 743 &rContent.GetContentIdx()->GetNode() == pSttNd ) 744 { 745 pRet = pFormat; 746 break; 747 } 748 } 749 } 750 } 751 return pRet; 752 } 753 754 SwTableBox* SwNode::GetTableBox() const 755 { 756 SwTableBox* pBox = nullptr; 757 const SwNode* pSttNd = FindTableBoxStartNode(); 758 if( pSttNd ) 759 pBox = const_cast<SwTableBox*>(pSttNd->FindTableNode()->GetTable().GetTableBox( 760 pSttNd->GetIndex() )); 761 return pBox; 762 } 763 764 SwStartNode* SwNode::FindSttNodeByType( SwStartNodeType eTyp ) 765 { 766 SwStartNode* pTmp = IsStartNode() ? static_cast<SwStartNode*>(this) : m_pStartOfSection; 767 768 while( eTyp != pTmp->GetStartNodeType() && pTmp->GetIndex() ) 769 pTmp = pTmp->m_pStartOfSection; 770 return eTyp == pTmp->GetStartNodeType() ? pTmp : nullptr; 771 } 772 773 const SwTextNode* SwNode::FindOutlineNodeOfLevel(sal_uInt8 const nLvl, 774 SwRootFrame const*const pLayout) const 775 { 776 const SwTextNode* pRet = nullptr; 777 const SwOutlineNodes& rONds = GetNodes().GetOutLineNds(); 778 if( MAXLEVEL > nLvl && !rONds.empty() ) 779 { 780 SwOutlineNodes::size_type nPos; 781 SwNode* pNd = const_cast<SwNode*>(this); 782 bool bCheckFirst = false; 783 if( !rONds.Seek_Entry( pNd, &nPos )) 784 { 785 if (nPos == 0) 786 bCheckFirst = true; 787 } 788 else 789 { 790 ++nPos; 791 } 792 793 if( bCheckFirst ) 794 { 795 // The first OutlineNode comes after the one asking. 796 // Test if both are on the same page. 797 // If not it's invalid. 798 for (nPos = 0; nPos < rONds.size(); ++nPos) 799 { 800 pRet = rONds[nPos]->GetTextNode(); 801 if (!pLayout || sw::IsParaPropsNode(*pLayout, *pRet)) 802 { 803 break; 804 } 805 } 806 if (nPos == rONds.size()) 807 { 808 return nullptr; 809 } 810 811 const SwContentNode* pCNd = GetContentNode(); 812 813 Point aPt( 0, 0 ); 814 std::pair<Point, bool> const tmp(aPt, false); 815 const SwFrame* pFrame = pRet->getLayoutFrame(pRet->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, &tmp), 816 * pMyFrame = pCNd ? pCNd->getLayoutFrame(pCNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, &tmp) : nullptr; 817 const SwPageFrame* pPgFrame = pFrame ? pFrame->FindPageFrame() : nullptr; 818 if( pPgFrame && pMyFrame && 819 pPgFrame->getFrameArea().Top() > pMyFrame->getFrameArea().Top() ) 820 { 821 // The one asking precedes the Page, thus its invalid 822 pRet = nullptr; 823 } 824 } 825 else 826 { 827 for ( ; 0 < nPos; --nPos) 828 { 829 SwTextNode const*const pNode = rONds[nPos - 1]->GetTextNode(); 830 if ((nPos == 1 /*as before*/ || pNode->GetAttrOutlineLevel() - 1 <= nLvl) 831 && (!pLayout || sw::IsParaPropsNode(*pLayout, *pNode))) 832 { 833 pRet = pNode; 834 break; 835 } 836 } 837 } 838 } 839 return pRet; 840 } 841 842 static bool IsValidNextPrevNd( const SwNode& rNd ) 843 { 844 return SwNodeType::Table == rNd.GetNodeType() || 845 ( SwNodeType::ContentMask & rNd.GetNodeType() ) || 846 ( SwNodeType::End == rNd.GetNodeType() && rNd.StartOfSectionNode() && 847 SwNodeType::Table == rNd.StartOfSectionNode()->GetNodeType() ); 848 } 849 850 sal_uInt8 SwNode::HasPrevNextLayNode() const 851 { 852 // assumption: <this> node is a node inside the document nodes array section. 853 854 sal_uInt8 nRet = 0; 855 if( IsValidNextPrevNd( *this )) 856 { 857 SwNodeIndex aIdx( *this, -1 ); 858 // #i77805# - skip section start and end nodes 859 while ( aIdx.GetNode().IsSectionNode() || 860 ( aIdx.GetNode().IsEndNode() && 861 aIdx.GetNode().StartOfSectionNode()->IsSectionNode() ) ) 862 { 863 --aIdx; 864 } 865 if( IsValidNextPrevNd( aIdx.GetNode() )) 866 nRet |= ND_HAS_PREV_LAYNODE; 867 // #i77805# - skip section start and end nodes 868 aIdx.Assign(*this, +1); 869 while ( aIdx.GetNode().IsSectionNode() || 870 ( aIdx.GetNode().IsEndNode() && 871 aIdx.GetNode().StartOfSectionNode()->IsSectionNode() ) ) 872 { 873 ++aIdx; 874 } 875 if( IsValidNextPrevNd( aIdx.GetNode() )) 876 nRet |= ND_HAS_NEXT_LAYNODE; 877 } 878 return nRet; 879 } 880 881 void SwNode::dumpAsXml(xmlTextWriterPtr pWriter) const 882 { 883 const char* pName = "???"; 884 switch (GetNodeType()) 885 { 886 case SwNodeType::End: 887 pName = "end"; 888 break; 889 case SwNodeType::Start: 890 case SwNodeType::Text: 891 case SwNodeType::Ole: 892 abort(); // overridden 893 case SwNodeType::Table: 894 pName = "table"; 895 break; 896 case SwNodeType::Grf: 897 pName = "grf"; 898 break; 899 default: break; 900 } 901 (void)xmlTextWriterStartElement(pWriter, BAD_CAST(pName)); 902 903 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this); 904 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("type"), BAD_CAST(OString::number(static_cast<sal_uInt8>(GetNodeType())).getStr())); 905 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("index"), BAD_CAST(OString::number(sal_Int32(GetIndex())).getStr())); 906 907 switch (GetNodeType()) 908 { 909 case SwNodeType::Grf: 910 { 911 auto pNoTextNode = static_cast<const SwNoTextNode*>(this); 912 const tools::PolyPolygon* pContour = pNoTextNode->HasContour(); 913 if (pContour) 914 { 915 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("pContour")); 916 for (sal_uInt16 i = 0; i < pContour->Count(); ++i) 917 { 918 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("polygon")); 919 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("index"), 920 BAD_CAST(OString::number(i).getStr())); 921 const tools::Polygon& rPolygon = pContour->GetObject(i); 922 for (sal_uInt16 j = 0; j < rPolygon.GetSize(); ++j) 923 { 924 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("point")); 925 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("index"), 926 BAD_CAST(OString::number(j).getStr())); 927 const Point& rPoint = rPolygon.GetPoint(j); 928 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("x"), 929 BAD_CAST(OString::number(rPoint.X()).getStr())); 930 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("y"), 931 BAD_CAST(OString::number(rPoint.Y()).getStr())); 932 (void)xmlTextWriterEndElement(pWriter); 933 } 934 (void)xmlTextWriterEndElement(pWriter); 935 } 936 (void)xmlTextWriterEndElement(pWriter); 937 } 938 } 939 break; 940 default: 941 break; 942 } 943 944 (void)xmlTextWriterEndElement(pWriter); 945 if (GetNodeType() == SwNodeType::End) 946 (void)xmlTextWriterEndElement(pWriter); // end start node 947 } 948 949 SwStartNode::SwStartNode( const SwNodeIndex &rWhere, const SwNodeType nNdType, 950 SwStartNodeType eSttNd ) 951 : SwNode( rWhere, nNdType ), m_eStartNodeType( eSttNd ) 952 { 953 if( !rWhere.GetIndex() ) 954 { 955 SwNodes& rNodes = const_cast<SwNodes&> (rWhere.GetNodes()); 956 rNodes.InsertNode( this, rWhere ); 957 m_pStartOfSection = this; 958 } 959 // Just do this temporarily until the EndNode is inserted 960 m_pEndOfSection = reinterpret_cast<SwEndNode*>(this); 961 } 962 963 SwStartNode::SwStartNode( SwNodes& rNodes, SwNodeOffset nPos ) 964 : SwNode( rNodes, nPos, SwNodeType::Start ), m_eStartNodeType( SwNormalStartNode ) 965 { 966 if( !nPos ) 967 { 968 rNodes.InsertNode( this, nPos ); 969 m_pStartOfSection = this; 970 } 971 // Just do this temporarily until the EndNode is inserted 972 m_pEndOfSection = reinterpret_cast<SwEndNode*>(this); 973 } 974 975 void SwStartNode::CheckSectionCondColl() const 976 { 977 //FEATURE::CONDCOLL 978 SwNodeIndex aIdx( *this ); 979 SwNodeOffset nEndIdx = EndOfSectionIndex(); 980 const SwNodes& rNds = GetNodes(); 981 SwContentNode* pCNd; 982 while( nullptr != ( pCNd = rNds.GoNext( &aIdx )) && pCNd->GetIndex() < nEndIdx ) 983 pCNd->ChkCondColl(); 984 //FEATURE::CONDCOLL 985 } 986 987 void SwStartNode::dumpAsXml(xmlTextWriterPtr pWriter) const 988 { 989 const char* pName = "???"; 990 switch (GetNodeType()) 991 { 992 case SwNodeType::Table: 993 pName = "table"; 994 break; 995 default: 996 switch(GetStartNodeType()) 997 { 998 case SwNormalStartNode: 999 pName = "start"; 1000 break; 1001 case SwTableBoxStartNode: 1002 pName = "tablebox"; 1003 break; 1004 case SwFlyStartNode: 1005 pName = "fly"; 1006 break; 1007 case SwFootnoteStartNode: 1008 pName = "footnote"; 1009 break; 1010 case SwHeaderStartNode: 1011 pName = "header"; 1012 break; 1013 case SwFooterStartNode: 1014 pName = "footer"; 1015 break; 1016 } 1017 break; 1018 } 1019 1020 (void)xmlTextWriterStartElement(pWriter, BAD_CAST(pName)); 1021 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this); 1022 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("type"), BAD_CAST(OString::number(static_cast<sal_uInt8>(GetNodeType())).getStr())); 1023 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("index"), BAD_CAST(OString::number(sal_Int32(GetIndex())).getStr())); 1024 1025 if (IsTableNode()) 1026 { 1027 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("attrset")); 1028 GetTableNode()->GetTable().GetFrameFormat()->GetAttrSet().dumpAsXml(pWriter); 1029 (void)xmlTextWriterEndElement(pWriter); 1030 } 1031 else if (GetStartNodeType() == SwTableBoxStartNode) 1032 { 1033 if (SwTableBox* pBox = GetTableBox()) 1034 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("rowspan"), BAD_CAST(OString::number(pBox->getRowSpan()).getStr())); 1035 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("attrset")); 1036 if (SwTableBox* pBox = GetTableBox()) 1037 pBox->GetFrameFormat()->GetAttrSet().dumpAsXml(pWriter); 1038 (void)xmlTextWriterEndElement(pWriter); 1039 } 1040 1041 // (void)xmlTextWriterEndElement(pWriter); - it is a start node, so don't end, will make xml better nested 1042 } 1043 1044 1045 /** Insert a node into the array 1046 * 1047 * The StartOfSection pointer is set to the given node. 1048 * 1049 * The EndOfSection pointer of the corresponding start node is set to this node. 1050 * 1051 * @param rWhere position where the node shoul be inserted 1052 * @param rSttNd the start note of the section 1053 */ 1054 1055 SwEndNode::SwEndNode( const SwNodeIndex &rWhere, SwStartNode& rSttNd ) 1056 : SwNode( rWhere, SwNodeType::End ) 1057 { 1058 m_pStartOfSection = &rSttNd; 1059 m_pStartOfSection->m_pEndOfSection = this; 1060 } 1061 1062 SwEndNode::SwEndNode( SwNodes& rNds, SwNodeOffset nPos, SwStartNode& rSttNd ) 1063 : SwNode( rNds, nPos, SwNodeType::End ) 1064 { 1065 m_pStartOfSection = &rSttNd; 1066 m_pStartOfSection->m_pEndOfSection = this; 1067 } 1068 1069 SwContentNode::SwContentNode( const SwNodeIndex &rWhere, const SwNodeType nNdType, 1070 SwFormatColl *pColl ) 1071 : SwNode( rWhere, nNdType ) 1072 , m_aCondCollListener( *this ) 1073 , m_pCondColl( nullptr ) 1074 , mbSetModifyAtAttr( false ) 1075 { 1076 if(pColl) 1077 pColl->Add(this); 1078 } 1079 1080 SwContentNode::~SwContentNode() 1081 { 1082 // The base class SwClient of SwFrame excludes itself from the dependency list! 1083 // Thus, we need to delete all Frames in the dependency list. 1084 if (!IsTextNode()) // see ~SwTextNode 1085 { 1086 DelFrames(nullptr); 1087 } 1088 1089 m_aCondCollListener.EndListeningAll(); 1090 m_pCondColl = nullptr; 1091 1092 if ( mpAttrSet && mbSetModifyAtAttr ) 1093 const_cast<SwAttrSet*>(static_cast<const SwAttrSet*>(mpAttrSet.get()))->SetModifyAtAttr( nullptr ); 1094 InvalidateInSwCache(RES_OBJECTDYING); 1095 } 1096 void SwContentNode::UpdateAttr(const SwUpdateAttr& rUpdate) 1097 { 1098 if (GetNodes().IsDocNodes() 1099 && IsTextNode() 1100 && RES_ATTRSET_CHG == rUpdate.getWhichAttr()) 1101 static_cast<SwTextNode*>(this)->SetCalcHiddenCharFlags(); 1102 CallSwClientNotify(sw::LegacyModifyHint(&rUpdate, &rUpdate)); 1103 } 1104 1105 void SwContentNode::SwClientNotify( const SwModify&, const SfxHint& rHint) 1106 { 1107 if (rHint.GetId() == SfxHintId::SwLegacyModify) 1108 { 1109 auto pLegacyHint = static_cast<const sw::LegacyModifyHint*>(&rHint); 1110 const sal_uInt16 nWhich = pLegacyHint->GetWhich(); 1111 InvalidateInSwCache(nWhich); 1112 1113 bool bSetParent = false; 1114 bool bCalcHidden = false; 1115 SwFormatColl* pFormatColl = nullptr; 1116 switch(nWhich) 1117 { 1118 case RES_OBJECTDYING: 1119 { 1120 SwFormat* pFormat = pLegacyHint->m_pNew 1121 ? static_cast<SwFormat*>(static_cast<const SwPtrMsgPoolItem*>(pLegacyHint->m_pNew)->pObject) 1122 : nullptr; 1123 // Do not mangle pointers if it is the upper-most format! 1124 if(pFormat && GetRegisteredIn() == pFormat) 1125 { 1126 if(pFormat->GetRegisteredIn()) 1127 { 1128 // If Parent, register anew in the new Parent 1129 pFormat->GetRegisteredIn()->Add(this); 1130 pFormatColl = GetFormatColl(); 1131 } 1132 else 1133 EndListeningAll(); 1134 bSetParent = true; 1135 } 1136 } 1137 break; 1138 1139 case RES_FMT_CHG: 1140 // If the Format parent was switched, register the Attrset at the new one 1141 // Skip own Modify! 1142 if(GetpSwAttrSet() 1143 && pLegacyHint->m_pNew 1144 && static_cast<const SwFormatChg*>(pLegacyHint->m_pNew)->pChangedFormat == GetRegisteredIn()) 1145 { 1146 pFormatColl = GetFormatColl(); 1147 bSetParent = true; 1148 } 1149 break; 1150 1151 case RES_ATTRSET_CHG: 1152 if (GetNodes().IsDocNodes() 1153 && IsTextNode() 1154 && pLegacyHint->m_pOld 1155 && SfxItemState::SET == pLegacyHint->m_pOld->StaticWhichCast(RES_ATTRSET_CHG).GetChgSet()->GetItemState(RES_CHRATR_HIDDEN, false)) 1156 bCalcHidden = true; 1157 break; 1158 1159 case RES_UPDATE_ATTR: 1160 // RES_UPDATE_ATTR _should_ always contain a SwUpdateAttr hint in old and new. 1161 // However, faking one with just a basic SfxPoolItem setting a WhichId has been observed. 1162 // This makes the crude "WhichId" type divert from the true type, which is bad. 1163 // Thus we are asserting here, but falling back to an proper 1164 // hint instead. so that we at least will not spread such poison further. 1165 #ifdef DBG_UTIL 1166 if(pLegacyHint->m_pNew != pLegacyHint->m_pOld) 1167 { 1168 auto pBT = sal::backtrace_get(20); 1169 SAL_WARN("sw.core", "UpdateAttr not matching! " << sal::backtrace_to_string(pBT.get())); 1170 } 1171 #endif 1172 assert(pLegacyHint->m_pNew == pLegacyHint->m_pOld); 1173 assert(dynamic_cast<const SwUpdateAttr*>(pLegacyHint->m_pNew)); 1174 const SwUpdateAttr aFallbackHint(0,0,0); 1175 const SwUpdateAttr& rUpdateAttr = pLegacyHint->m_pNew ? *static_cast<const SwUpdateAttr*>(pLegacyHint->m_pNew) : aFallbackHint; 1176 UpdateAttr(rUpdateAttr); 1177 return; 1178 } 1179 if(bSetParent && GetpSwAttrSet()) 1180 AttrSetHandleHelper::SetParent(mpAttrSet, *this, pFormatColl, pFormatColl); 1181 if(bCalcHidden) 1182 static_cast<SwTextNode*>(this)->SetCalcHiddenCharFlags(); 1183 CallSwClientNotify(rHint); 1184 } 1185 else if (auto pModifyChangedHint = dynamic_cast<const sw::ModifyChangedHint*>(&rHint)) 1186 { 1187 m_pCondColl = const_cast<SwFormatColl*>(static_cast<const SwFormatColl*>(pModifyChangedHint->m_pNew)); 1188 } 1189 else if(auto pCondCollCondChgHint = dynamic_cast<const sw::CondCollCondChg*>(&rHint)) 1190 { 1191 ChkCondColl(&pCondCollCondChgHint->m_rColl); 1192 } 1193 } 1194 1195 bool SwContentNode::InvalidateNumRule() 1196 { 1197 SwNumRule* pRule = nullptr; 1198 const SfxPoolItem* pItem; 1199 if( GetNodes().IsDocNodes() && 1200 nullptr != ( pItem = GetNoCondAttr( RES_PARATR_NUMRULE, true )) && 1201 !static_cast<const SwNumRuleItem*>(pItem)->GetValue().isEmpty() && 1202 nullptr != (pRule = GetDoc().FindNumRulePtr( 1203 static_cast<const SwNumRuleItem*>(pItem)->GetValue() ) ) ) 1204 { 1205 pRule->SetInvalidRule( true ); 1206 } 1207 return nullptr != pRule; 1208 } 1209 1210 SwContentFrame *SwContentNode::getLayoutFrame( const SwRootFrame* _pRoot, 1211 const SwPosition *const pPos, 1212 std::pair<Point, bool> const*const pViewPosAndCalcFrame) const 1213 { 1214 return static_cast<SwContentFrame*>( ::GetFrameOfModify( _pRoot, *this, FRM_CNTNT, 1215 pPos, pViewPosAndCalcFrame)); 1216 } 1217 1218 SwRect SwContentNode::FindLayoutRect( const bool bPrtArea, const Point* pPoint ) const 1219 { 1220 SwRect aRet; 1221 std::pair<Point, bool> tmp; 1222 if (pPoint) 1223 { 1224 tmp.first = *pPoint; 1225 tmp.second = false; 1226 } 1227 SwContentFrame* pFrame = static_cast<SwContentFrame*>( ::GetFrameOfModify( nullptr, *this, 1228 FRM_CNTNT, nullptr, pPoint ? &tmp : nullptr) ); 1229 if( pFrame ) 1230 aRet = bPrtArea ? pFrame->getFramePrintArea() : pFrame->getFrameArea(); 1231 return aRet; 1232 } 1233 1234 SwRect SwContentNode::FindPageFrameRect() const 1235 { 1236 SwRect aRet; 1237 SwFrame* pFrame = ::GetFrameOfModify( nullptr, *this, FRM_CNTNT ); 1238 if( pFrame && nullptr != ( pFrame = pFrame->FindPageFrame() )) 1239 aRet = pFrame->getFrameArea(); 1240 return aRet; 1241 } 1242 1243 sal_Int32 SwContentNode::Len() const { return 0; } 1244 1245 SwFormatColl *SwContentNode::ChgFormatColl( SwFormatColl *pNewColl ) 1246 { 1247 OSL_ENSURE( pNewColl, "Collectionpointer is 0." ); 1248 SwFormatColl *pOldColl = GetFormatColl(); 1249 1250 if( pNewColl != pOldColl ) 1251 { 1252 pNewColl->Add( this ); 1253 1254 // Set the Parent of out AutoAttributes to the new Collection 1255 if( GetpSwAttrSet() ) 1256 AttrSetHandleHelper::SetParent( mpAttrSet, *this, pNewColl, pNewColl ); 1257 1258 SetCondFormatColl( nullptr ); 1259 1260 if( !IsModifyLocked() ) 1261 { 1262 assert(dynamic_cast<SwTextFormatColl*>(pNewColl)); 1263 ChkCondColl(static_cast<SwTextFormatColl*>(pNewColl)); 1264 SwFormatChg aTmp1( pOldColl ); 1265 SwFormatChg aTmp2( pNewColl ); 1266 SwClientNotify( *this, sw::LegacyModifyHint(&aTmp1, &aTmp2) ); 1267 } 1268 } 1269 InvalidateInSwCache(RES_ATTRSET_CHG); 1270 return pOldColl; 1271 } 1272 1273 bool SwContentNode::GoNext(SwIndex * pIdx, sal_uInt16 nMode ) const 1274 { 1275 bool bRet = true; 1276 if( pIdx->GetIndex() < Len() ) 1277 { 1278 if( !IsTextNode() ) 1279 ++(*pIdx); 1280 else 1281 { 1282 const SwTextNode& rTNd = *GetTextNode(); 1283 sal_Int32 nPos = pIdx->GetIndex(); 1284 assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is()); 1285 sal_Int32 nDone = 0; 1286 sal_uInt16 nItrMode = ( CRSR_SKIP_CELLS & nMode ) ? 1287 CharacterIteratorMode::SKIPCELL : 1288 CharacterIteratorMode::SKIPCONTROLCHARACTER; 1289 nPos = g_pBreakIt->GetBreakIter()->nextCharacters( rTNd.GetText(), nPos, 1290 g_pBreakIt->GetLocale( rTNd.GetLang( nPos ) ), 1291 nItrMode, 1, nDone ); 1292 1293 // Check if nPos is inside hidden text range: 1294 if ( CRSR_SKIP_HIDDEN & nMode ) 1295 { 1296 sal_Int32 nHiddenStart; 1297 sal_Int32 nHiddenEnd; 1298 SwScriptInfo::GetBoundsOfHiddenRange( rTNd, nPos, nHiddenStart, nHiddenEnd ); 1299 if ( nHiddenStart != COMPLETE_STRING && nHiddenStart != nPos ) 1300 nPos = nHiddenEnd; 1301 } 1302 1303 if( 1 == nDone ) 1304 *pIdx = nPos; 1305 else 1306 bRet = false; 1307 } 1308 } 1309 else 1310 bRet = false; 1311 return bRet; 1312 } 1313 1314 bool SwContentNode::GoPrevious(SwIndex * pIdx, sal_uInt16 nMode ) const 1315 { 1316 bool bRet = true; 1317 if( pIdx->GetIndex() > 0 ) 1318 { 1319 if( !IsTextNode() ) 1320 --(*pIdx); 1321 else 1322 { 1323 const SwTextNode& rTNd = *GetTextNode(); 1324 sal_Int32 nPos = pIdx->GetIndex(); 1325 assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is()); 1326 sal_Int32 nDone = 0; 1327 sal_uInt16 nItrMode = ( CRSR_SKIP_CELLS & nMode ) ? 1328 CharacterIteratorMode::SKIPCELL : 1329 CharacterIteratorMode::SKIPCONTROLCHARACTER; 1330 nPos = g_pBreakIt->GetBreakIter()->previousCharacters( rTNd.GetText(), nPos, 1331 g_pBreakIt->GetLocale( rTNd.GetLang( nPos ) ), 1332 nItrMode, 1, nDone ); 1333 1334 // Check if nPos is inside hidden text range: 1335 if ( CRSR_SKIP_HIDDEN & nMode ) 1336 { 1337 sal_Int32 nHiddenStart; 1338 sal_Int32 nHiddenEnd; 1339 SwScriptInfo::GetBoundsOfHiddenRange( rTNd, nPos, nHiddenStart, nHiddenEnd ); 1340 if ( nHiddenStart != COMPLETE_STRING ) 1341 nPos = nHiddenStart; 1342 } 1343 1344 if( 1 == nDone ) 1345 *pIdx = nPos; 1346 else 1347 bRet = false; 1348 } 1349 } 1350 else 1351 bRet = false; 1352 return bRet; 1353 } 1354 1355 /** 1356 * Creates all Views for the Doc for this Node. 1357 * The created ContentFrames are attached to the corresponding Layout. 1358 */ 1359 void SwContentNode::MakeFramesForAdjacentContentNode(SwContentNode& rNode) 1360 { 1361 OSL_ENSURE( &rNode != this, 1362 "No ContentNode or CopyNode and new Node identical." ); 1363 1364 if( !HasWriterListeners() || &rNode == this ) // Do we actually have Frames? 1365 return; 1366 1367 SwFrame *pFrame; 1368 SwLayoutFrame *pUpper; 1369 // Create Frames for Nodes which come after the Table? 1370 OSL_ENSURE( FindTableNode() == rNode.FindTableNode(), "Table confusion" ); 1371 1372 SwNode2Layout aNode2Layout( *this, rNode.GetIndex() ); 1373 1374 while( nullptr != (pUpper = aNode2Layout.UpperFrame( pFrame, rNode )) ) 1375 { 1376 if (pUpper->getRootFrame()->HasMergedParas() 1377 && !rNode.IsCreateFrameWhenHidingRedlines()) 1378 { 1379 continue; 1380 } 1381 SwFrame *pNew = rNode.MakeFrame( pUpper ); 1382 pNew->Paste( pUpper, pFrame ); 1383 // #i27138# 1384 // notify accessibility paragraphs objects about changed 1385 // CONTENT_FLOWS_FROM/_TO relation. 1386 // Relation CONTENT_FLOWS_FROM for next paragraph will change 1387 // and relation CONTENT_FLOWS_TO for previous paragraph will change. 1388 if ( pNew->IsTextFrame() ) 1389 { 1390 SwViewShell* pViewShell( pNew->getRootFrame()->GetCurrShell() ); 1391 if ( pViewShell && pViewShell->GetLayout() && 1392 pViewShell->GetLayout()->IsAnyShellAccessible() ) 1393 { 1394 auto pNext = pNew->FindNextCnt( true ); 1395 auto pPrev = pNew->FindPrevCnt(); 1396 pViewShell->InvalidateAccessibleParaFlowRelation( 1397 pNext ? pNext->DynCastTextFrame() : nullptr, 1398 pPrev ? pPrev->DynCastTextFrame() : nullptr ); 1399 } 1400 } 1401 } 1402 } 1403 1404 /** 1405 * Deletes all Views from the Doc for this Node. 1406 * The ContentFrames are removed from the corresponding Layout. 1407 */ 1408 void SwContentNode::DelFrames(SwRootFrame const*const pLayout) 1409 { 1410 if( !HasWriterListeners() ) 1411 return; 1412 1413 SwIterator<SwContentFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aIter(*this); 1414 for( SwContentFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next() ) 1415 { 1416 if (pLayout && pLayout != pFrame->getRootFrame()) 1417 { 1418 continue; // skip it 1419 } 1420 if (pFrame->IsTextFrame()) 1421 { 1422 if (sw::MergedPara * pMerged = 1423 static_cast<SwTextFrame *>(pFrame)->GetMergedPara()) 1424 { 1425 if (this != pMerged->pFirstNode) 1426 { 1427 // SwNodes::RemoveNode iterates *backwards* - so 1428 // ensure there are no more extents pointing to this 1429 // node as SwFrame::InvalidatePage() will access them. 1430 // Note: cannot send via SwClientNotify from dtor 1431 // because that would access deleted wrong-lists 1432 sw::UpdateMergedParaForDelete(*pMerged, true, 1433 *static_cast<SwTextNode*>(this), 0, Len()); 1434 if (this == pMerged->pParaPropsNode) 1435 { 1436 // otherwise pointer should have been updated to a different node 1437 assert(this == pMerged->pLastNode); 1438 assert(pMerged->extents.empty()); 1439 for (SwNodeOffset i = pMerged->pLastNode->GetIndex() - 1;; 1440 --i) 1441 { 1442 assert(pMerged->pFirstNode->GetIndex() <= i); 1443 SwNode *const pNode(GetNodes()[i]); 1444 if (pNode->IsTextNode() 1445 && pNode->GetRedlineMergeFlag() != Merge::Hidden) 1446 { 1447 pMerged->pParaPropsNode = pNode->GetTextNode(); 1448 break; 1449 } 1450 } 1451 assert(pMerged->listener.IsListeningTo(pMerged->pParaPropsNode)); 1452 } 1453 assert(GetIndex() <= pMerged->pLastNode->GetIndex()); 1454 if (this == pMerged->pLastNode) 1455 { 1456 // tdf#130680 find the previous node that is a 1457 // listener of pMerged; see CheckParaRedlineMerge() 1458 for (SwNodeOffset i = GetIndex() - 1; 1459 this == pMerged->pLastNode; --i) 1460 { 1461 SwNode *const pNode = GetNodes()[i]; 1462 if (pNode->IsTextNode()) 1463 { 1464 pMerged->pLastNode = pNode->GetTextNode(); 1465 } 1466 else if (SwEndNode const*const pEnd = pNode->GetEndNode()) 1467 { 1468 SwStartNode const*const pStart(pEnd->StartOfSectionNode()); 1469 i = pStart->GetIndex(); // skip table or section 1470 } 1471 } 1472 assert(pMerged->pFirstNode->GetIndex() <= pMerged->pLastNode->GetIndex()); 1473 assert(pMerged->listener.IsListeningTo(pMerged->pLastNode)); 1474 } 1475 // avoid re-parenting mess (ModifyChangedHint) 1476 pMerged->listener.EndListening(this); 1477 continue; // don't delete 1478 } 1479 } 1480 // #i27138# 1481 // notify accessibility paragraphs objects about changed 1482 // CONTENT_FLOWS_FROM/_TO relation. 1483 // Relation CONTENT_FLOWS_FROM for current next paragraph will change 1484 // and relation CONTENT_FLOWS_TO for current previous paragraph will change. 1485 SwViewShell* pViewShell( pFrame->getRootFrame()->GetCurrShell() ); 1486 if ( pViewShell && pViewShell->GetLayout() && 1487 pViewShell->GetLayout()->IsAnyShellAccessible() ) 1488 { 1489 auto pNext = pFrame->FindNextCnt( true ); 1490 auto pPrev = pFrame->FindPrevCnt(); 1491 pViewShell->InvalidateAccessibleParaFlowRelation( 1492 pNext ? pNext->DynCastTextFrame() : nullptr, 1493 pPrev ? pPrev->DynCastTextFrame() : nullptr ); 1494 } 1495 } 1496 1497 if( pFrame->IsFollow() ) 1498 { 1499 SwContentFrame* pMaster = pFrame->FindMaster(); 1500 pMaster->SetFollow( pFrame->GetFollow() ); 1501 } 1502 pFrame->SetFollow( nullptr );//So it doesn't get funny ideas. 1503 //Otherwise it could be possible that a follow 1504 //gets destroyed before its master. Following 1505 //the now invalid pointer will then lead to an 1506 //illegal memory access. The chain can be 1507 //crushed here because we'll destroy all of it 1508 //anyway. 1509 1510 if( pFrame->GetUpper() && pFrame->IsInFootnote() && !pFrame->GetIndNext() && 1511 !pFrame->GetIndPrev() ) 1512 { 1513 SwFootnoteFrame *pFootnote = pFrame->FindFootnoteFrame(); 1514 OSL_ENSURE( pFootnote, "You promised a FootnoteFrame?" ); 1515 SwContentFrame* pCFrame; 1516 if( !pFootnote->GetFollow() && !pFootnote->GetMaster() && 1517 nullptr != ( pCFrame = pFootnote->GetRefFromAttr()) && pCFrame->IsFollow() ) 1518 { 1519 OSL_ENSURE( pCFrame->IsTextFrame(), "NoTextFrame has Footnote?" ); 1520 pCFrame->FindMaster()->Prepare( PrepareHint::FootnoteInvalidationGone ); 1521 } 1522 } 1523 pFrame->Cut(); 1524 SwFrame::DestroyFrame(pFrame); 1525 } 1526 } 1527 1528 SwContentNode *SwContentNode::JoinNext() 1529 { 1530 return this; 1531 } 1532 1533 /// Get info from Modify 1534 bool SwContentNode::GetInfo( SfxPoolItem& rInfo ) const 1535 { 1536 switch( rInfo.Which() ) 1537 { 1538 case RES_AUTOFMT_DOCNODE: 1539 if( &GetNodes() == static_cast<SwAutoFormatGetDocNode&>(rInfo).pNodes ) 1540 { 1541 return false; 1542 } 1543 break; 1544 1545 case RES_FINDNEARESTNODE: 1546 if( static_cast<const SwFormatPageDesc&>(GetAttr( RES_PAGEDESC )).GetPageDesc() ) 1547 static_cast<SwFindNearestNode&>(rInfo).CheckNode( *this ); 1548 return true; 1549 1550 case RES_CONTENT_VISIBLE: 1551 { 1552 static_cast<SwPtrMsgPoolItem&>(rInfo).pObject = 1553 SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>(*this).First(); 1554 } 1555 return false; 1556 } 1557 1558 return sw::BroadcastingModify::GetInfo( rInfo ); 1559 } 1560 1561 /// @param rAttr the attribute to set 1562 bool SwContentNode::SetAttr(const SfxPoolItem& rAttr ) 1563 { 1564 if( !GetpSwAttrSet() ) // Have the Nodes created by the corresponding AttrSets 1565 NewAttrSet( GetDoc().GetAttrPool() ); 1566 1567 OSL_ENSURE( GetpSwAttrSet(), "Why did't we create an AttrSet?"); 1568 1569 InvalidateInSwCache(RES_ATTRSET_CHG); 1570 1571 bool bRet = false; 1572 // If Modify is locked, we do not send any Modifys 1573 if( IsModifyLocked() || 1574 ( !HasWriterListeners() && RES_PARATR_NUMRULE != rAttr.Which() )) 1575 { 1576 bRet = nullptr != AttrSetHandleHelper::Put( mpAttrSet, *this, rAttr ); 1577 } 1578 else 1579 { 1580 SwAttrSet aOld( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ), 1581 aNew( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ); 1582 bRet = AttrSetHandleHelper::Put_BC( mpAttrSet, *this, rAttr, &aOld, &aNew ); 1583 if( bRet ) 1584 sw::ClientNotifyAttrChg(*this, *GetpSwAttrSet(), aOld, aNew); 1585 } 1586 return bRet; 1587 } 1588 1589 bool SwContentNode::SetAttr( const SfxItemSet& rSet ) 1590 { 1591 InvalidateInSwCache(RES_ATTRSET_CHG); 1592 1593 const SfxPoolItem* pFnd = nullptr; 1594 if( SfxItemState::SET == rSet.GetItemState( RES_AUTO_STYLE, false, &pFnd ) ) 1595 { 1596 OSL_ENSURE( rSet.Count() == 1, "SetAutoStyle mixed with other attributes?!" ); 1597 const SwFormatAutoFormat* pTmp = static_cast<const SwFormatAutoFormat*>(pFnd); 1598 1599 // If there already is an attribute set (usually containing a numbering 1600 // item), we have to merge the attribute of the new set into the old set: 1601 bool bSetParent = true; 1602 if ( GetpSwAttrSet() ) 1603 { 1604 bSetParent = false; 1605 AttrSetHandleHelper::Put( mpAttrSet, *this, *pTmp->GetStyleHandle() ); 1606 } 1607 else 1608 { 1609 mpAttrSet = pTmp->GetStyleHandle(); 1610 } 1611 1612 if ( bSetParent ) 1613 { 1614 // If the content node has a conditional style, we have to set the 1615 // string item containing the correct conditional style name (the 1616 // style name property has already been set during the import!) 1617 // In case we do not have a conditional style, we make use of the 1618 // fact that nobody else uses the attribute set behind the handle. 1619 // FME 2007-07-10 #i78124# If autostyle does not have a parent, 1620 // the string is empty. 1621 const SfxPoolItem* pNameItem = nullptr; 1622 if ( nullptr != GetCondFormatColl() || 1623 SfxItemState::SET != mpAttrSet->GetItemState( RES_FRMATR_STYLE_NAME, false, &pNameItem ) || 1624 static_cast<const SfxStringItem*>(pNameItem)->GetValue().isEmpty() ) 1625 AttrSetHandleHelper::SetParent( mpAttrSet, *this, &GetAnyFormatColl(), GetFormatColl() ); 1626 else 1627 const_cast<SfxItemSet*>(mpAttrSet.get())->SetParent( &GetFormatColl()->GetAttrSet() ); 1628 } 1629 1630 return true; 1631 } 1632 1633 if( !GetpSwAttrSet() ) // Have the AttrsSets created by the corresponding Nodes 1634 NewAttrSet( GetDoc().GetAttrPool() ); 1635 1636 bool bRet = false; 1637 // If Modify is locked, do not send any Modifys 1638 if ( IsModifyLocked() || 1639 ( !HasWriterListeners() && 1640 SfxItemState::SET != rSet.GetItemState( RES_PARATR_NUMRULE, false ) ) ) 1641 { 1642 // Some special treatment for Attributes 1643 bRet = AttrSetHandleHelper::Put( mpAttrSet, *this, rSet ); 1644 } 1645 else 1646 { 1647 SwAttrSet aOld( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ), 1648 aNew( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ); 1649 bRet = AttrSetHandleHelper::Put_BC( mpAttrSet, *this, rSet, &aOld, &aNew ); 1650 if( bRet ) 1651 sw::ClientNotifyAttrChg(*this, *GetpSwAttrSet(), aOld, aNew); 1652 } 1653 return bRet; 1654 } 1655 1656 // With nWhich it takes the Hint from the Delta array 1657 bool SwContentNode::ResetAttr( sal_uInt16 nWhich1, sal_uInt16 nWhich2 ) 1658 { 1659 if( !GetpSwAttrSet() ) 1660 return false; 1661 1662 InvalidateInSwCache(RES_ATTRSET_CHG); 1663 1664 // If Modify is locked, do not send out any Modifys 1665 if( IsModifyLocked() ) 1666 { 1667 sal_uInt16 nDel = 0; 1668 if ( !nWhich2 || nWhich2 < nWhich1 ) 1669 { 1670 nDel = ClearItemsFromAttrSet( { nWhich1 } ); 1671 } 1672 else 1673 nDel = AttrSetHandleHelper::ClearItem_BC( mpAttrSet, *this, nWhich1, nWhich2, nullptr, nullptr ); 1674 1675 if( !GetpSwAttrSet()->Count() ) // Empty? Delete 1676 mpAttrSet.reset(); 1677 return 0 != nDel; 1678 } 1679 1680 // No valid area defined? 1681 if( !nWhich2 || nWhich2 < nWhich1 ) 1682 nWhich2 = nWhich1; // Then set only this Item to 1st Id 1683 1684 SwAttrSet aOld( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ), 1685 aNew( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ); 1686 bool bRet = 0 != AttrSetHandleHelper::ClearItem_BC( mpAttrSet, *this, nWhich1, nWhich2, &aOld, &aNew ); 1687 1688 if( bRet ) 1689 { 1690 sw::ClientNotifyAttrChg(*this, *GetpSwAttrSet(), aOld, aNew); 1691 1692 if( !GetpSwAttrSet()->Count() ) // Empty?, delete it 1693 mpAttrSet.reset(); 1694 } 1695 return bRet; 1696 } 1697 1698 bool SwContentNode::ResetAttr( const std::vector<sal_uInt16>& rWhichArr ) 1699 { 1700 if( !GetpSwAttrSet() ) 1701 return false; 1702 1703 InvalidateInSwCache(RES_ATTRSET_CHG); 1704 // If Modify is locked, do not send out any Modifys 1705 sal_uInt16 nDel = 0; 1706 if( IsModifyLocked() ) 1707 { 1708 nDel = ClearItemsFromAttrSet( rWhichArr ); 1709 } 1710 else 1711 { 1712 SwAttrSet aOld( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ), 1713 aNew( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ); 1714 1715 for ( const auto& rWhich : rWhichArr ) 1716 if( AttrSetHandleHelper::ClearItem_BC( mpAttrSet, *this, rWhich, &aOld, &aNew )) 1717 ++nDel; 1718 1719 if( nDel ) 1720 sw::ClientNotifyAttrChg(*this, *GetpSwAttrSet(), aOld, aNew); 1721 } 1722 if( !GetpSwAttrSet()->Count() ) // Empty?, delete it 1723 mpAttrSet.reset(); 1724 return 0 != nDel ; 1725 } 1726 1727 sal_uInt16 SwContentNode::ResetAllAttr() 1728 { 1729 if( !GetpSwAttrSet() ) 1730 return 0; 1731 InvalidateInSwCache(RES_ATTRSET_CHG); 1732 1733 // If Modify is locked, do not send out any Modifys 1734 if( IsModifyLocked() ) 1735 { 1736 sal_uInt16 nDel = ClearItemsFromAttrSet( { 0 } ); 1737 if( !GetpSwAttrSet()->Count() ) // Empty? Delete 1738 mpAttrSet.reset(); 1739 return nDel; 1740 } 1741 1742 SwAttrSet aOld( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ), 1743 aNew( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ); 1744 bool bRet = 0 != AttrSetHandleHelper::ClearItem_BC( mpAttrSet, *this, 0, &aOld, &aNew ); 1745 1746 if( bRet ) 1747 { 1748 sw::ClientNotifyAttrChg(*this, *GetpSwAttrSet(), aOld, aNew); 1749 if( !GetpSwAttrSet()->Count() ) // Empty? Delete 1750 mpAttrSet.reset(); 1751 } 1752 return aNew.Count(); 1753 } 1754 1755 bool SwContentNode::GetAttr( SfxItemSet& rSet ) const 1756 { 1757 if( rSet.Count() ) 1758 rSet.ClearItem(); 1759 1760 const SwAttrSet& rAttrSet = GetSwAttrSet(); 1761 return rSet.Set( rAttrSet ); 1762 } 1763 1764 sal_uInt16 SwContentNode::ClearItemsFromAttrSet( const std::vector<sal_uInt16>& rWhichIds ) 1765 { 1766 sal_uInt16 nRet = 0; 1767 if ( rWhichIds.empty() ) 1768 return nRet; 1769 1770 OSL_ENSURE( GetpSwAttrSet(), "no item set" ); 1771 SwAttrSet aNewAttrSet( *GetpSwAttrSet() ); 1772 for ( const auto& rWhichId : rWhichIds ) 1773 { 1774 nRet = nRet + aNewAttrSet.ClearItem( rWhichId ); 1775 } 1776 if ( nRet ) 1777 AttrSetHandleHelper::GetNewAutoStyle( mpAttrSet, *this, aNewAttrSet ); 1778 1779 return nRet; 1780 } 1781 1782 const SfxPoolItem* SwContentNode::GetNoCondAttr( sal_uInt16 nWhich, 1783 bool bInParents ) const 1784 { 1785 const SfxPoolItem* pFnd = nullptr; 1786 if( m_pCondColl && m_pCondColl->GetRegisteredIn() ) 1787 { 1788 if( !GetpSwAttrSet() || ( SfxItemState::SET != GetpSwAttrSet()->GetItemState( 1789 nWhich, false, &pFnd ) && bInParents )) 1790 { 1791 (void)static_cast<const SwFormat*>(GetRegisteredIn())->GetItemState( nWhich, bInParents, &pFnd ); 1792 } 1793 } 1794 // undo change of issue #i51029# 1795 // Note: <GetSwAttrSet()> returns <mpAttrSet>, if set, otherwise it returns 1796 // the attribute set of the paragraph style, which is valid for the 1797 // content node - see file <node.hxx> 1798 else 1799 { 1800 GetSwAttrSet().GetItemState( nWhich, bInParents, &pFnd ); 1801 } 1802 return pFnd; 1803 } 1804 1805 static bool lcl_CheckMaxLength(SwNode const& rPrev, SwNode const& rNext) 1806 { 1807 if (rPrev.GetNodeType() != rNext.GetNodeType()) 1808 { 1809 return false; 1810 } 1811 if (!rPrev.IsTextNode()) 1812 { 1813 return true; 1814 } 1815 1816 // Check if a node can contain the other (order is not significant) 1817 return rPrev.GetTextNode()->GetSpaceLeft() > rNext.GetTextNode()->Len(); 1818 } 1819 1820 /// Can we join two Nodes? 1821 /// We can return the 2nd position in pIdx. 1822 bool SwContentNode::CanJoinNext( SwNodeIndex* pIdx ) const 1823 { 1824 const SwNodes& rNds = GetNodes(); 1825 SwNodeIndex aIdx( *this, 1 ); 1826 1827 const SwNode* pNd = this; 1828 while( aIdx < rNds.Count()-1 && 1829 (( pNd = &aIdx.GetNode())->IsSectionNode() || 1830 ( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsSectionNode() ))) 1831 ++aIdx; 1832 1833 if (rNds.Count()-1 == aIdx.GetIndex()) 1834 return false; 1835 if (!lcl_CheckMaxLength(*this, *pNd)) 1836 { 1837 return false; 1838 } 1839 if( pIdx ) 1840 *pIdx = aIdx; 1841 return true; 1842 } 1843 1844 /// Can we join two Nodes? 1845 /// We can return the 2nd position in pIdx. 1846 bool SwContentNode::CanJoinPrev( SwNodeIndex* pIdx ) const 1847 { 1848 SwNodeIndex aIdx( *this, -1 ); 1849 1850 const SwNode* pNd = this; 1851 while( aIdx.GetIndex() && 1852 (( pNd = &aIdx.GetNode())->IsSectionNode() || 1853 ( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsSectionNode() ))) 1854 --aIdx; 1855 1856 if (SwNodeOffset(0) == aIdx.GetIndex()) 1857 return false; 1858 if (!lcl_CheckMaxLength(*pNd, *this)) 1859 { 1860 return false; 1861 } 1862 if( pIdx ) 1863 *pIdx = aIdx; 1864 return true; 1865 } 1866 1867 void SwContentNode::SetCondFormatColl(SwFormatColl* pColl) 1868 { 1869 if( !((!pColl && m_pCondColl) || ( pColl && !m_pCondColl ) || 1870 ( pColl && pColl != m_pCondColl->GetRegisteredIn() )) ) 1871 return; 1872 1873 SwFormatColl* pOldColl = GetCondFormatColl(); 1874 m_aCondCollListener.EndListeningAll(); 1875 if(pColl) 1876 m_aCondCollListener.StartListening(pColl); 1877 m_pCondColl = pColl; 1878 if(GetpSwAttrSet()) 1879 AttrSetHandleHelper::SetParent(mpAttrSet, *this, &GetAnyFormatColl(), GetFormatColl()); 1880 1881 if(!IsModifyLocked()) 1882 { 1883 SwFormatChg aTmp1(pOldColl ? pOldColl : GetFormatColl()); 1884 SwFormatChg aTmp2(pColl ? pColl : GetFormatColl()); 1885 CallSwClientNotify(sw::LegacyModifyHint(&aTmp1, &aTmp2)); 1886 } 1887 InvalidateInSwCache(RES_ATTRSET_CHG); 1888 } 1889 1890 bool SwContentNode::IsAnyCondition( SwCollCondition& rTmp ) const 1891 { 1892 const SwNodes& rNds = GetNodes(); 1893 { 1894 Master_CollCondition nCond = Master_CollCondition::NONE; 1895 const SwStartNode* pSttNd = StartOfSectionNode(); 1896 while( pSttNd ) 1897 { 1898 switch( pSttNd->GetNodeType() ) 1899 { 1900 case SwNodeType::Table: nCond = Master_CollCondition::PARA_IN_TABLEBODY; break; 1901 case SwNodeType::Section: nCond = Master_CollCondition::PARA_IN_SECTION; break; 1902 1903 default: 1904 switch( pSttNd->GetStartNodeType() ) 1905 { 1906 case SwTableBoxStartNode: 1907 { 1908 nCond = Master_CollCondition::PARA_IN_TABLEBODY; 1909 const SwTableNode* pTableNd = pSttNd->FindTableNode(); 1910 const SwTableBox* pBox; 1911 if( pTableNd && nullptr != ( pBox = pTableNd->GetTable(). 1912 GetTableBox(pSttNd->GetIndex()) ) && 1913 pBox->IsInHeadline( &pTableNd->GetTable() ) ) 1914 nCond = Master_CollCondition::PARA_IN_TABLEHEAD; 1915 } 1916 break; 1917 case SwFlyStartNode: nCond = Master_CollCondition::PARA_IN_FRAME; break; 1918 case SwFootnoteStartNode: 1919 { 1920 nCond = Master_CollCondition::PARA_IN_FOOTNOTE; 1921 const SwFootnoteIdxs& rFootnoteArr = rNds.GetDoc().GetFootnoteIdxs(); 1922 const SwTextFootnote* pTextFootnote; 1923 const SwNode* pSrchNd = pSttNd; 1924 1925 for( size_t n = 0; n < rFootnoteArr.size(); ++n ) 1926 if( nullptr != ( pTextFootnote = rFootnoteArr[ n ])->GetStartNode() && 1927 pSrchNd == &pTextFootnote->GetStartNode()->GetNode() ) 1928 { 1929 if( pTextFootnote->GetFootnote().IsEndNote() ) 1930 nCond = Master_CollCondition::PARA_IN_ENDNOTE; 1931 break; 1932 } 1933 } 1934 break; 1935 case SwHeaderStartNode: nCond = Master_CollCondition::PARA_IN_HEADER; break; 1936 case SwFooterStartNode: nCond = Master_CollCondition::PARA_IN_FOOTER; break; 1937 case SwNormalStartNode: break; 1938 } 1939 } 1940 1941 if( nCond != Master_CollCondition::NONE ) 1942 { 1943 rTmp.SetCondition( nCond, 0 ); 1944 return true; 1945 } 1946 pSttNd = pSttNd->GetIndex() 1947 ? pSttNd->StartOfSectionNode() 1948 : nullptr; 1949 } 1950 } 1951 1952 { 1953 SwOutlineNodes::size_type nPos; 1954 const SwOutlineNodes& rOutlNds = rNds.GetOutLineNds(); 1955 if( !rOutlNds.empty() ) 1956 { 1957 if( !rOutlNds.Seek_Entry( const_cast<SwContentNode*>(this), &nPos ) && nPos ) 1958 --nPos; 1959 if( nPos < rOutlNds.size() && 1960 rOutlNds[ nPos ]->GetIndex() < GetIndex() ) 1961 { 1962 SwTextNode* pOutlNd = rOutlNds[ nPos ]->GetTextNode(); 1963 1964 if( pOutlNd->IsOutline()) 1965 { 1966 rTmp.SetCondition( Master_CollCondition::PARA_IN_OUTLINE, pOutlNd->GetAttrOutlineLevel() - 1 ); 1967 return true; 1968 } 1969 } 1970 } 1971 } 1972 1973 return false; 1974 } 1975 1976 void SwContentNode::ChkCondColl(const SwTextFormatColl* pColl) 1977 { 1978 if(pColl != GetRegisteredIn()) 1979 { 1980 SAL_WARN("sw.core", "Wrong cond collection, skipping check of Cond Colls."); 1981 return; 1982 } 1983 if(&GetNodes() != &GetDoc().GetNodes()) 1984 { 1985 SAL_WARN("sw.core", "Nodes amiss, skipping check of Cond Colls."); 1986 return; 1987 } 1988 // Check, just to be sure 1989 if( RES_CONDTXTFMTCOLL != GetFormatColl()->Which() ) 1990 return; 1991 1992 SwCollCondition aTmp( nullptr, Master_CollCondition::NONE, 0 ); 1993 const SwCollCondition* pCColl; 1994 1995 bool bDone = false; 1996 1997 if( IsAnyCondition( aTmp )) 1998 { 1999 pCColl = static_cast<SwConditionTextFormatColl*>(GetFormatColl()) 2000 ->HasCondition( aTmp ); 2001 2002 if (pCColl) 2003 { 2004 SetCondFormatColl( pCColl->GetTextFormatColl() ); 2005 bDone = true; 2006 } 2007 } 2008 2009 if (bDone) 2010 return; 2011 2012 if( IsTextNode() && static_cast<SwTextNode*>(this)->GetNumRule()) 2013 { 2014 // Is at which Level in a list? 2015 aTmp.SetCondition( Master_CollCondition::PARA_IN_LIST, 2016 static_cast<SwTextNode*>(this)->GetActualListLevel() ); 2017 pCColl = static_cast<SwConditionTextFormatColl*>(GetFormatColl())-> 2018 HasCondition( aTmp ); 2019 } 2020 else 2021 pCColl = nullptr; 2022 2023 if( pCColl ) 2024 SetCondFormatColl( pCColl->GetTextFormatColl() ); 2025 else if( m_pCondColl ) 2026 SetCondFormatColl( nullptr ); 2027 } 2028 2029 // #i42921# 2030 SvxFrameDirection SwContentNode::GetTextDirection( const SwPosition& rPos, 2031 const Point* pPt ) const 2032 { 2033 SvxFrameDirection nRet = SvxFrameDirection::Unknown; 2034 2035 Point aPt; 2036 if( pPt ) 2037 aPt = *pPt; 2038 2039 // #i72024# - No format of the frame, because this can cause recursive layout actions 2040 std::pair<Point, bool> const tmp(aPt, false); 2041 SwFrame* pFrame = getLayoutFrame(GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), &rPos, &tmp); 2042 2043 if ( pFrame ) 2044 { 2045 if ( pFrame->IsVertical() ) 2046 { 2047 if (pFrame->IsVertLRBT()) 2048 nRet = SvxFrameDirection::Vertical_LR_BT; 2049 else if (pFrame->IsRightToLeft()) 2050 nRet = SvxFrameDirection::Vertical_LR_TB; 2051 else 2052 nRet = SvxFrameDirection::Vertical_RL_TB; 2053 } 2054 else 2055 { 2056 if ( pFrame->IsRightToLeft() ) 2057 nRet = SvxFrameDirection::Horizontal_RL_TB; 2058 else 2059 nRet = SvxFrameDirection::Horizontal_LR_TB; 2060 } 2061 } 2062 2063 return nRet; 2064 } 2065 2066 std::unique_ptr<SwOLENodes> SwContentNode::CreateOLENodesArray( const SwFormatColl& rColl, bool bOnlyWithInvalidSize ) 2067 { 2068 std::unique_ptr<SwOLENodes> pNodes; 2069 SwIterator<SwContentNode,SwFormatColl> aIter( rColl ); 2070 for( SwContentNode* pNd = aIter.First(); pNd; pNd = aIter.Next() ) 2071 { 2072 SwOLENode *pONd = pNd->GetOLENode(); 2073 if ( pONd && (!bOnlyWithInvalidSize || pONd->IsOLESizeInvalid()) ) 2074 { 2075 if ( !pNodes ) 2076 pNodes.reset(new SwOLENodes); 2077 pNodes->push_back( pONd ); 2078 } 2079 } 2080 2081 return pNodes; 2082 } 2083 2084 drawinglayer::attribute::SdrAllFillAttributesHelperPtr SwContentNode::getSdrAllFillAttributesHelper() const 2085 { 2086 return drawinglayer::attribute::SdrAllFillAttributesHelperPtr(); 2087 } 2088 2089 /* 2090 * Document Interface Access 2091 */ 2092 const IDocumentSettingAccess* SwNode::getIDocumentSettingAccess() const { return &GetDoc().GetDocumentSettingManager(); } 2093 const IDocumentDeviceAccess& SwNode::getIDocumentDeviceAccess() const { return GetDoc().getIDocumentDeviceAccess(); } 2094 const IDocumentRedlineAccess& SwNode::getIDocumentRedlineAccess() const { return GetDoc().getIDocumentRedlineAccess(); } 2095 const IDocumentStylePoolAccess& SwNode::getIDocumentStylePoolAccess() const { return GetDoc().getIDocumentStylePoolAccess(); } 2096 const IDocumentDrawModelAccess& SwNode::getIDocumentDrawModelAccess() const { return GetDoc().getIDocumentDrawModelAccess(); } 2097 const IDocumentLayoutAccess& SwNode::getIDocumentLayoutAccess() const { return GetDoc().getIDocumentLayoutAccess(); } 2098 IDocumentLayoutAccess& SwNode::getIDocumentLayoutAccess() { return GetDoc().getIDocumentLayoutAccess(); } 2099 const IDocumentLinksAdministration& SwNode::getIDocumentLinksAdministration() const { return GetDoc().getIDocumentLinksAdministration(); } 2100 IDocumentLinksAdministration& SwNode::getIDocumentLinksAdministration() { return GetDoc().getIDocumentLinksAdministration(); } 2101 const IDocumentFieldsAccess& SwNode::getIDocumentFieldsAccess() const { return GetDoc().getIDocumentFieldsAccess(); } 2102 IDocumentFieldsAccess& SwNode::getIDocumentFieldsAccess() { return GetDoc().getIDocumentFieldsAccess(); } 2103 IDocumentContentOperations& SwNode::getIDocumentContentOperations() { return GetDoc().getIDocumentContentOperations(); } 2104 IDocumentListItems& SwNode::getIDocumentListItems() { return GetDoc().getIDocumentListItems(); } // #i83479# 2105 2106 const IDocumentMarkAccess* SwNode::getIDocumentMarkAccess() const { return GetDoc().getIDocumentMarkAccess(); } 2107 IStyleAccess& SwNode::getIDocumentStyleAccess() { return GetDoc().GetIStyleAccess(); } 2108 2109 bool SwNode::IsInRedlines() const 2110 { 2111 const SwDoc& rDoc = GetDoc(); 2112 2113 return rDoc.getIDocumentRedlineAccess().IsInRedlines(*this); 2114 } 2115 2116 void SwNode::AddAnchoredFly(SwFrameFormat *const pFlyFormat) 2117 { 2118 assert(pFlyFormat); 2119 assert(&pFlyFormat->GetAnchor(false).GetContentAnchor()->nNode.GetNode() == this); 2120 // check node type, cf. SwFormatAnchor::SetAnchor() 2121 assert(IsTextNode() || IsStartNode() || IsTableNode()); 2122 m_aAnchoredFlys.push_back(pFlyFormat); 2123 } 2124 2125 void SwNode::RemoveAnchoredFly(SwFrameFormat *const pFlyFormat) 2126 { 2127 assert(pFlyFormat); 2128 // cannot assert this in Remove because it is called when new anchor is already set 2129 // assert(&pFlyFormat->GetAnchor(false).GetContentAnchor()->nNode.GetNode() == this); 2130 assert(IsTextNode() || IsStartNode() || IsTableNode()); 2131 auto it(std::find(m_aAnchoredFlys.begin(), m_aAnchoredFlys.end(), pFlyFormat)); 2132 assert(it != m_aAnchoredFlys.end()); 2133 m_aAnchoredFlys.erase(it); 2134 } 2135 2136 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 2137
