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 <sal/config.h> 21 22 #include <utility> 23 24 #include <comphelper/servicehelper.hxx> 25 #include <cppuhelper/supportsservice.hxx> 26 #include <editeng/brushitem.hxx> 27 #include <editeng/flstitem.hxx> 28 #include <editeng/unolingu.hxx> 29 #include <rtl/ustrbuf.hxx> 30 #include <svl/listener.hxx> 31 #include <sfx2/docfile.hxx> 32 #include <sfx2/docfilt.hxx> 33 #include <sfx2/fcontnr.hxx> 34 #include <sfx2/linkmgr.hxx> 35 #include <svtools/ctrltool.hxx> 36 #include <vcl/svapp.hxx> 37 38 #include <swtypes.hxx> 39 #include <hintids.hxx> 40 #include <cmdid.h> 41 #include <hints.hxx> 42 #include <IMark.hxx> 43 #include <bookmrk.hxx> 44 #include <frmfmt.hxx> 45 #include <doc.hxx> 46 #include <IDocumentUndoRedo.hxx> 47 #include <IDocumentLayoutAccess.hxx> 48 #include <IDocumentMarkAccess.hxx> 49 #include <textboxhelper.hxx> 50 #include <ndtxt.hxx> 51 #include <ndnotxt.hxx> 52 #include <unocrsr.hxx> 53 #include <swundo.hxx> 54 #include <rootfrm.hxx> 55 #include <flyfrm.hxx> 56 #include <ftnidx.hxx> 57 #include <docary.hxx> 58 #include <paratr.hxx> 59 #include <pam.hxx> 60 #include <shellio.hxx> 61 #include <swerror.h> 62 #include <swtblfmt.hxx> 63 #include <docsh.hxx> 64 #include <docstyle.hxx> 65 #include <charfmt.hxx> 66 #include <txtfld.hxx> 67 #include <fmtfld.hxx> 68 #include <fmtpdsc.hxx> 69 #include <pagedesc.hxx> 70 #include <poolfmt.hxx> 71 #include <edimp.hxx> 72 #include <fchrfmt.hxx> 73 #include <cntfrm.hxx> 74 #include <pagefrm.hxx> 75 #include <doctxm.hxx> 76 #include <fmtrfmrk.hxx> 77 #include <txtrfmrk.hxx> 78 #include <unoparaframeenum.hxx> 79 #include <unofootnote.hxx> 80 #include <unotextbodyhf.hxx> 81 #include <unotextrange.hxx> 82 #include <unoparagraph.hxx> 83 #include <unomap.hxx> 84 #include <unoport.hxx> 85 #include <unocrsrhelper.hxx> 86 #include <unosett.hxx> 87 #include <unoprnms.hxx> 88 #include <unotbl.hxx> 89 #include <unodraw.hxx> 90 #include <unocoll.hxx> 91 #include <unostyle.hxx> 92 #include <fmtanchr.hxx> 93 #include <flypos.hxx> 94 #include <txtftn.hxx> 95 #include <fmtftn.hxx> 96 #include <fmtcntnt.hxx> 97 #include <com/sun/star/text/WrapTextMode.hpp> 98 #include <com/sun/star/text/TextContentAnchorType.hpp> 99 #include <com/sun/star/style/PageStyleLayout.hpp> 100 #include <com/sun/star/text/XTextDocument.hpp> 101 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp> 102 #include <com/sun/star/drawing/XDrawPageSupplier.hpp> 103 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp> 104 #include <unoframe.hxx> 105 #include <fmthdft.hxx> 106 #include <fmtflcnt.hxx> 107 #include <fmtclds.hxx> 108 #include <dcontact.hxx> 109 #include <dflyobj.hxx> 110 #include <vector> 111 #include <sortedobjs.hxx> 112 #include <sortopt.hxx> 113 #include <algorithm> 114 #include <iterator> 115 116 using namespace ::com::sun::star; 117 118 namespace sw { 119 120 uno::Sequence< OUString > 121 GetSupportedServiceNamesImpl( 122 size_t const nServices, char const*const pServices[]) 123 { 124 uno::Sequence< OUString > ret(nServices); 125 for (size_t i = 0; i < nServices; ++i) 126 { 127 ret[i] = OUString::createFromAscii(pServices[i]); 128 } 129 return ret; 130 } 131 132 } // namespace sw 133 134 namespace sw { 135 136 void DeepCopyPaM(SwPaM const & rSource, SwPaM & rTarget) 137 { 138 rTarget = rSource; 139 140 if (rSource.GetNext() != &rSource) 141 { 142 SwPaM *pPam = const_cast<SwPaM*>(rSource.GetNext()); 143 do 144 { 145 // create new PaM 146 SwPaM *const pNew = new SwPaM(*pPam, nullptr); 147 // insert into ring 148 pNew->MoveTo(&rTarget); 149 pPam = pPam->GetNext(); 150 } 151 while (pPam != &rSource); 152 } 153 } 154 155 } // namespace sw 156 157 struct FrameClientSortListLess 158 { 159 bool operator() (FrameClientSortListEntry const& r1, 160 FrameClientSortListEntry const& r2) const 161 { 162 return (r1.nIndex < r2.nIndex) 163 || ((r1.nIndex == r2.nIndex) && (r1.nOrder < r2.nOrder)); 164 } 165 }; 166 167 namespace 168 { 169 void lcl_CollectFrameAtNodeWithLayout(const SwContentFrame* pCFrame, 170 FrameClientSortList_t& rFrames, 171 const RndStdIds nAnchorType) 172 { 173 auto pObjs = pCFrame->GetDrawObjs(); 174 if(!pObjs) 175 return; 176 for(const auto pAnchoredObj : *pObjs) 177 { 178 SwFrameFormat& rFormat = pAnchoredObj->GetFrameFormat(); 179 // Filter out textboxes, which are not interesting at a UNO level. 180 if(SwTextBoxHelper::isTextBox(&rFormat, RES_FLYFRMFMT)) 181 continue; 182 if(rFormat.GetAnchor().GetAnchorId() == nAnchorType) 183 { 184 const auto nIdx = 185 rFormat.GetAnchor().GetContentAnchor()->nContent.GetIndex(); 186 const auto nOrder = rFormat.GetAnchor().GetOrder(); 187 FrameClientSortListEntry entry(nIdx, nOrder, new sw::FrameClient(&rFormat)); 188 rFrames.push_back(entry); 189 } 190 } 191 } 192 } 193 194 195 void CollectFrameAtNode( const SwNodeIndex& rIdx, 196 FrameClientSortList_t& rFrames, 197 const bool bAtCharAnchoredObjs ) 198 { 199 // _bAtCharAnchoredObjs: 200 // <true>: at-character anchored objects are collected 201 // <false>: at-paragraph anchored objects are collected 202 203 // search all borders, images, and OLEs that are connected to the paragraph 204 SwDoc* pDoc = rIdx.GetNode().GetDoc(); 205 206 const auto nChkType = bAtCharAnchoredObjs ? RndStdIds::FLY_AT_CHAR : RndStdIds::FLY_AT_PARA; 207 const SwContentFrame* pCFrame; 208 const SwContentNode* pCNd; 209 if( pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() && 210 nullptr != (pCNd = rIdx.GetNode().GetContentNode()) && 211 nullptr != (pCFrame = pCNd->getLayoutFrame( pDoc->getIDocumentLayoutAccess().GetCurrentLayout())) ) 212 { 213 lcl_CollectFrameAtNodeWithLayout(pCFrame, rFrames, nChkType); 214 } 215 else 216 { 217 const SwFrameFormats& rFormats = *pDoc->GetSpzFrameFormats(); 218 const size_t nSize = rFormats.size(); 219 for ( size_t i = 0; i < nSize; i++) 220 { 221 const SwFrameFormat* pFormat = rFormats[ i ]; 222 const SwFormatAnchor& rAnchor = pFormat->GetAnchor(); 223 const SwPosition* pAnchorPos; 224 if( rAnchor.GetAnchorId() == nChkType && 225 nullptr != (pAnchorPos = rAnchor.GetContentAnchor()) && 226 pAnchorPos->nNode == rIdx ) 227 { 228 229 // OD 2004-05-07 #i28701# - determine insert position for 230 // sorted <rFrameArr> 231 const sal_Int32 nIndex = pAnchorPos->nContent.GetIndex(); 232 sal_uInt32 nOrder = rAnchor.GetOrder(); 233 234 FrameClientSortListEntry entry(nIndex, nOrder, new sw::FrameClient(const_cast<SwFrameFormat*>(pFormat))); 235 rFrames.push_back(entry); 236 } 237 } 238 std::sort(rFrames.begin(), rFrames.end(), FrameClientSortListLess()); 239 } 240 } 241 242 UnoActionContext::UnoActionContext(SwDoc *const pDoc) 243 : m_pDoc(pDoc) 244 { 245 SwRootFrame *const pRootFrame = m_pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); 246 if (pRootFrame) 247 { 248 pRootFrame->StartAllAction(); 249 } 250 } 251 252 UnoActionContext::~UnoActionContext() COVERITY_NOEXCEPT_FALSE 253 { 254 // Doc may already have been removed here 255 if (m_pDoc) 256 { 257 SwRootFrame *const pRootFrame = m_pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); 258 if (pRootFrame) 259 { 260 pRootFrame->EndAllAction(); 261 } 262 } 263 } 264 265 static void lcl_RemoveImpl(SwDoc *const pDoc) 266 { 267 assert(pDoc); 268 SwRootFrame *const pRootFrame = pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); 269 if (pRootFrame) 270 { 271 pRootFrame->UnoRemoveAllActions(); 272 } 273 } 274 275 UnoActionRemoveContext::UnoActionRemoveContext(SwDoc *const pDoc) 276 : m_pDoc(pDoc) 277 { 278 lcl_RemoveImpl(m_pDoc); 279 } 280 281 static SwDoc * lcl_IsNewStyleTable(SwUnoTableCursor const& rCursor) 282 { 283 SwTableNode *const pTableNode = rCursor.GetNode().FindTableNode(); 284 return (pTableNode && !pTableNode->GetTable().IsNewModel()) 285 ? rCursor.GetDoc() 286 : nullptr; 287 } 288 289 UnoActionRemoveContext::UnoActionRemoveContext(SwUnoTableCursor const& rCursor) 290 : m_pDoc(lcl_IsNewStyleTable(rCursor)) 291 { 292 // this insanity is only necessary for old-style tables 293 // because SwRootFrame::MakeTableCursors() creates the table cursor for these 294 if (m_pDoc) 295 { 296 lcl_RemoveImpl(m_pDoc); 297 } 298 } 299 300 UnoActionRemoveContext::~UnoActionRemoveContext() COVERITY_NOEXCEPT_FALSE 301 { 302 if (m_pDoc) 303 { 304 SwRootFrame *const pRootFrame = m_pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); 305 if (pRootFrame) 306 { 307 pRootFrame->UnoRestoreAllActions(); 308 } 309 } 310 } 311 312 void ClientModify(SwClient* pClient, const SfxPoolItem *pOld, const SfxPoolItem *pNew) 313 { 314 switch( pOld ? pOld->Which() : 0 ) 315 { 316 case RES_REMOVE_UNO_OBJECT: 317 case RES_OBJECTDYING: 318 if( static_cast<void*>(pClient->GetRegisteredIn()) == static_cast<const SwPtrMsgPoolItem *>(pOld)->pObject ) 319 pClient->EndListeningAll(); 320 break; 321 322 case RES_FMT_CHG: 323 // Is the move to the new one finished and will the old one be deleted? 324 if( static_cast<const SwFormatChg*>(pNew)->pChangedFormat == pClient->GetRegisteredIn() && 325 static_cast<const SwFormatChg*>(pOld)->pChangedFormat->IsFormatInDTOR() ) 326 pClient->EndListeningAll(); 327 break; 328 } 329 } 330 331 void SwUnoCursorHelper::SetCursorAttr(SwPaM & rPam, 332 const SfxItemSet& rSet, 333 const SetAttrMode nAttrMode, const bool bTableMode) 334 { 335 const SetAttrMode nFlags = nAttrMode | SetAttrMode::APICALL; 336 SwDoc* pDoc = rPam.GetDoc(); 337 //StartEndAction 338 UnoActionContext aAction(pDoc); 339 if (rPam.GetNext() != &rPam) // Ring of Cursors 340 { 341 pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSATTR, nullptr); 342 343 for(SwPaM& rCurrent : rPam.GetRingContainer()) 344 { 345 if (rCurrent.HasMark() && 346 ( bTableMode || 347 (*rCurrent.GetPoint() != *rCurrent.GetMark()) )) 348 { 349 pDoc->getIDocumentContentOperations().InsertItemSet(rCurrent, rSet, nFlags); 350 } 351 } 352 353 pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSATTR, nullptr); 354 } 355 else 356 { 357 pDoc->getIDocumentContentOperations().InsertItemSet( rPam, rSet, nFlags ); 358 } 359 360 if( rSet.GetItemState( RES_PARATR_OUTLINELEVEL, false ) >= SfxItemState::DEFAULT ) 361 { 362 SwTextNode * pTmpNode = rPam.GetNode().GetTextNode(); 363 if ( pTmpNode ) 364 { 365 rPam.GetDoc()->GetNodes().UpdateOutlineNode( *pTmpNode ); 366 } 367 } 368 } 369 370 // #i63870# 371 // split third parameter <bCurrentAttrOnly> into new parameters <bOnlyTextAttr> 372 // and <bGetFromChrFormat> to get better control about resulting <SfxItemSet> 373 void SwUnoCursorHelper::GetCursorAttr(SwPaM & rPam, 374 SfxItemSet & rSet, const bool bOnlyTextAttr, const bool bGetFromChrFormat) 375 { 376 static const sal_uLong nMaxLookup = 1000; 377 SfxItemSet aSet( *rSet.GetPool(), rSet.GetRanges() ); 378 SfxItemSet *pSet = &rSet; 379 for(SwPaM& rCurrent : rPam.GetRingContainer()) 380 { 381 SwPosition const & rStart( *rCurrent.Start() ); 382 SwPosition const & rEnd( *rCurrent.End() ); 383 const sal_uLong nSttNd = rStart.nNode.GetIndex(); 384 const sal_uLong nEndNd = rEnd .nNode.GetIndex(); 385 386 if (nEndNd - nSttNd >= nMaxLookup) 387 { 388 rSet.ClearItem(); 389 rSet.InvalidateAllItems(); 390 return;// uno::Any(); 391 } 392 393 // the first node inserts the values into the get set 394 // all other nodes merge their values into the get set 395 for (sal_uLong n = nSttNd; n <= nEndNd; ++n) 396 { 397 SwNode *const pNd = rPam.GetDoc()->GetNodes()[ n ]; 398 switch (pNd->GetNodeType()) 399 { 400 case SwNodeType::Text: 401 { 402 const sal_Int32 nStart = (n == nSttNd) 403 ? rStart.nContent.GetIndex() : 0; 404 const sal_Int32 nEnd = (n == nEndNd) 405 ? rEnd.nContent.GetIndex() 406 : pNd->GetTextNode()->GetText().getLength(); 407 pNd->GetTextNode()->GetParaAttr(*pSet, nStart, nEnd, bOnlyTextAttr, bGetFromChrFormat); 408 } 409 break; 410 411 case SwNodeType::Grf: 412 case SwNodeType::Ole: 413 static_cast<SwContentNode*>(pNd)->GetAttr( *pSet ); 414 break; 415 416 default: 417 continue; // skip this node 418 } 419 420 if (pSet != &rSet) 421 { 422 rSet.MergeValues( aSet ); 423 } 424 else 425 { 426 pSet = &aSet; 427 } 428 429 if (aSet.Count()) 430 { 431 aSet.ClearItem(); 432 } 433 } 434 } 435 } 436 437 struct SwXParagraphEnumerationImpl final : public SwXParagraphEnumeration 438 { 439 uno::Reference< text::XText > const m_xParentText; 440 const CursorType m_eCursorType; 441 /// Start node of the cell _or_ table the enumeration belongs to. 442 /// Used to restrict the movement of the UNO cursor to the cell and its 443 /// embedded tables. 444 SwStartNode const*const m_pOwnStartNode; 445 SwTable const*const m_pOwnTable; 446 const sal_uLong m_nEndIndex; 447 sal_Int32 m_nFirstParaStart; 448 sal_Int32 m_nLastParaEnd; 449 bool m_bFirstParagraph; 450 uno::Reference< text::XTextContent > m_xNextPara; 451 sw::UnoCursorPointer m_pCursor; 452 453 SwXParagraphEnumerationImpl( 454 uno::Reference< text::XText > const& xParent, 455 const std::shared_ptr<SwUnoCursor>& pCursor, 456 const CursorType eType, 457 SwStartNode const*const pStartNode, SwTable const*const pTable) 458 : m_xParentText( xParent ) 459 , m_eCursorType( eType ) 460 // remember table and start node for later travelling 461 // (used in export of tables in tables) 462 , m_pOwnStartNode( pStartNode ) 463 // for import of tables in tables we have to remember the actual 464 // table and start node of the current position in the enumeration. 465 , m_pOwnTable( pTable ) 466 , m_nEndIndex( pCursor->End()->nNode.GetIndex() ) 467 , m_nFirstParaStart( -1 ) 468 , m_nLastParaEnd( -1 ) 469 , m_bFirstParagraph( true ) 470 , m_pCursor(pCursor) 471 { 472 OSL_ENSURE(m_xParentText.is(), "SwXParagraphEnumeration: no parent?"); 473 OSL_ENSURE( !((CursorType::SelectionInTable == eType) || 474 (CursorType::TableText == eType)) 475 || (m_pOwnTable && m_pOwnStartNode), 476 "SwXParagraphEnumeration: table type but no start node or table?"); 477 478 if ((CursorType::Selection == m_eCursorType) || 479 (CursorType::SelectionInTable == m_eCursorType)) 480 { 481 SwUnoCursor & rCursor = GetCursor(); 482 rCursor.Normalize(); 483 m_nFirstParaStart = rCursor.GetPoint()->nContent.GetIndex(); 484 m_nLastParaEnd = rCursor.GetMark()->nContent.GetIndex(); 485 rCursor.DeleteMark(); 486 } 487 } 488 489 virtual ~SwXParagraphEnumerationImpl() override 490 { m_pCursor.reset(nullptr); } 491 virtual void SAL_CALL release() throw () override 492 { 493 SolarMutexGuard g; 494 OWeakObject::release(); 495 } 496 497 // XServiceInfo 498 virtual OUString SAL_CALL getImplementationName() override 499 { return OUString("SwXParagraphEnumeration"); } 500 virtual sal_Bool SAL_CALL supportsService( const OUString& rServiceName) override 501 { return cppu::supportsService(this, rServiceName); }; 502 virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override 503 { return {"com.sun.star.text.ParagraphEnumeration"}; }; 504 505 // XEnumeration 506 virtual sal_Bool SAL_CALL hasMoreElements() override; 507 virtual css::uno::Any SAL_CALL nextElement() override; 508 509 SwUnoCursor& GetCursor() 510 { return *m_pCursor; } 511 /// @throws container::NoSuchElementException 512 /// @throws lang::WrappedTargetException 513 /// @throws uno::RuntimeException 514 uno::Reference< text::XTextContent > NextElement_Impl(); 515 516 /** 517 * Determines if the last element in the enumeration should be ignored or 518 * not. 519 */ 520 bool IgnoreLastElement(SwUnoCursor& rCursor, bool bMovedFromTable); 521 }; 522 523 SwXParagraphEnumeration* SwXParagraphEnumeration::Create( 524 uno::Reference< text::XText > const& xParent, 525 const std::shared_ptr<SwUnoCursor>& pCursor, 526 const CursorType eType, 527 SwStartNode const*const pStartNode, 528 SwTable const*const pTable) 529 { 530 return new SwXParagraphEnumerationImpl(xParent, pCursor, eType, pStartNode, pTable); 531 } 532 533 sal_Bool SAL_CALL 534 SwXParagraphEnumerationImpl::hasMoreElements() 535 { 536 SolarMutexGuard aGuard; 537 return m_bFirstParagraph || m_xNextPara.is(); 538 } 539 540 //!! compare to SwShellTableCursor::FillRects() in viscrs.cxx 541 static SwTableNode * 542 lcl_FindTopLevelTable( 543 SwTableNode *const pTableNode, SwTable const*const pOwnTable) 544 { 545 // find top-most table in current context (section) level 546 547 SwTableNode * pLast = pTableNode; 548 for (SwTableNode* pTmp = pLast; 549 pTmp != nullptr && &pTmp->GetTable() != pOwnTable; /* we must not go up higher than the own table! */ 550 pTmp = pTmp->StartOfSectionNode()->FindTableNode() ) 551 { 552 pLast = pTmp; 553 } 554 return pLast; 555 } 556 557 static bool 558 lcl_CursorIsInSection( 559 SwUnoCursor const*const pUnoCursor, SwStartNode const*const pOwnStartNode) 560 { 561 // returns true if the cursor is in the section (or in a sub section!) 562 // represented by pOwnStartNode 563 564 bool bRes = true; 565 if (pUnoCursor && pOwnStartNode) 566 { 567 const SwEndNode * pOwnEndNode = pOwnStartNode->EndOfSectionNode(); 568 bRes = pOwnStartNode->GetIndex() <= pUnoCursor->Start()->nNode.GetIndex() && 569 pUnoCursor->End()->nNode.GetIndex() <= pOwnEndNode->GetIndex(); 570 } 571 return bRes; 572 } 573 574 bool SwXParagraphEnumerationImpl::IgnoreLastElement(SwUnoCursor& rCursor, bool bMovedFromTable) 575 { 576 // Ignore the last element of a selection enumeration if this is a stub 577 // paragraph (directly after table, selection ends at paragaph start). 578 579 if (rCursor.Start()->nNode.GetIndex() != m_nEndIndex) 580 return false; 581 582 if (m_eCursorType != CursorType::Selection) 583 return false; 584 585 if (!bMovedFromTable) 586 return false; 587 588 return m_nLastParaEnd == 0; 589 } 590 591 uno::Reference< text::XTextContent > 592 SwXParagraphEnumerationImpl::NextElement_Impl() 593 { 594 SwUnoCursor& rUnoCursor = GetCursor(); 595 596 // check for exceeding selections 597 if (!m_bFirstParagraph && 598 ((CursorType::Selection == m_eCursorType) || 599 (CursorType::SelectionInTable == m_eCursorType))) 600 { 601 SwPosition* pStart = rUnoCursor.Start(); 602 auto aNewCursor(rUnoCursor.GetDoc()->CreateUnoCursor(*pStart)); 603 // one may also go into tables here 604 if (CursorType::SelectionInTable != m_eCursorType) 605 { 606 aNewCursor->SetRemainInSection( false ); 607 } 608 609 // os 2005-01-14: This part is only necessary to detect movements out 610 // of a selection; if there is no selection we don't have to care 611 SwTableNode *const pTableNode = aNewCursor->GetNode().FindTableNode(); 612 bool bMovedFromTable = false; 613 if (CursorType::SelectionInTable != m_eCursorType && pTableNode) 614 { 615 aNewCursor->GetPoint()->nNode = pTableNode->EndOfSectionIndex(); 616 aNewCursor->Move(fnMoveForward, GoInNode); 617 bMovedFromTable = true; 618 } 619 else 620 { 621 aNewCursor->MovePara(GoNextPara, fnParaStart); 622 } 623 if (m_nEndIndex < aNewCursor->Start()->nNode.GetIndex()) 624 { 625 return nullptr; 626 } 627 628 if (IgnoreLastElement(*aNewCursor, bMovedFromTable)) 629 { 630 return nullptr; 631 } 632 } 633 634 bool bInTable = false; 635 if (!m_bFirstParagraph) 636 { 637 rUnoCursor.SetRemainInSection( false ); 638 // what to do if already in a table? 639 SwTableNode * pTableNode = rUnoCursor.GetNode().FindTableNode(); 640 pTableNode = lcl_FindTopLevelTable( pTableNode, m_pOwnTable ); 641 if (pTableNode && (&pTableNode->GetTable() != m_pOwnTable)) 642 { 643 // this is a foreign table: go to end 644 rUnoCursor.GetPoint()->nNode = pTableNode->EndOfSectionIndex(); 645 if (!rUnoCursor.Move(fnMoveForward, GoInNode)) 646 { 647 return nullptr; 648 } 649 bInTable = true; 650 } 651 } 652 653 uno::Reference< text::XTextContent > xRef; 654 // the cursor must remain in the current section or a subsection 655 // before AND after the movement... 656 if (lcl_CursorIsInSection( &rUnoCursor, m_pOwnStartNode ) && 657 (m_bFirstParagraph || bInTable || 658 (rUnoCursor.MovePara(GoNextPara, fnParaStart) && 659 lcl_CursorIsInSection( &rUnoCursor, m_pOwnStartNode )))) 660 { 661 if (m_eCursorType == CursorType::Selection || m_eCursorType == CursorType::SelectionInTable) 662 { 663 // This is a selection, check if the cursor would go past the end 664 // of the selection. 665 if (rUnoCursor.Start()->nNode.GetIndex() > m_nEndIndex) 666 return nullptr; 667 } 668 669 SwPosition* pStart = rUnoCursor.Start(); 670 const sal_Int32 nFirstContent = 671 m_bFirstParagraph ? m_nFirstParaStart : -1; 672 const sal_Int32 nLastContent = 673 (m_nEndIndex == pStart->nNode.GetIndex()) ? m_nLastParaEnd : -1; 674 675 // position in a table, or in a simple paragraph? 676 SwTableNode * pTableNode = rUnoCursor.GetNode().FindTableNode(); 677 pTableNode = lcl_FindTopLevelTable( pTableNode, m_pOwnTable ); 678 if (/*CursorType::TableText != eCursorType && CursorType::SelectionInTable != eCursorType && */ 679 pTableNode && (&pTableNode->GetTable() != m_pOwnTable)) 680 { 681 // this is a foreign table 682 SwFrameFormat* pTableFormat = 683 static_cast<SwFrameFormat*>(pTableNode->GetTable().GetFrameFormat()); 684 xRef = SwXTextTable::CreateXTextTable(pTableFormat); 685 } 686 else 687 { 688 text::XText *const pText = m_xParentText.get(); 689 xRef = SwXParagraph::CreateXParagraph(*rUnoCursor.GetDoc(), 690 pStart->nNode.GetNode().GetTextNode(), 691 static_cast<SwXText*>(pText), nFirstContent, nLastContent); 692 } 693 } 694 695 return xRef; 696 } 697 698 uno::Any SAL_CALL SwXParagraphEnumerationImpl::nextElement() 699 { 700 SolarMutexGuard aGuard; 701 if (m_bFirstParagraph) 702 { 703 m_xNextPara = NextElement_Impl(); 704 m_bFirstParagraph = false; 705 } 706 const uno::Reference< text::XTextContent > xRef = m_xNextPara; 707 if (!xRef.is()) 708 { 709 throw container::NoSuchElementException(); 710 } 711 m_xNextPara = NextElement_Impl(); 712 713 uno::Any aRet; 714 aRet <<= xRef; 715 return aRet; 716 } 717 718 class SwXTextRange::Impl 719 : public SvtListener 720 { 721 public: 722 const SfxItemPropertySet& m_rPropSet; 723 const enum RangePosition m_eRangePosition; 724 SwDoc& m_rDoc; 725 uno::Reference<text::XText> m_xParentText; 726 const SwFrameFormat* m_pTableFormat; 727 const ::sw::mark::IMark* m_pMark; 728 729 Impl(SwDoc& rDoc, const enum RangePosition eRange, 730 SwFrameFormat* const pTableFormat, 731 const uno::Reference<text::XText>& xParent = nullptr) 732 : m_rPropSet(*aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_CURSOR)) 733 , m_eRangePosition(eRange) 734 , m_rDoc(rDoc) 735 , m_xParentText(xParent) 736 , m_pTableFormat(pTableFormat) 737 , m_pMark(nullptr) 738 { 739 m_pTableFormat && StartListening(pTableFormat->GetNotifier()); 740 } 741 742 virtual ~Impl() override 743 { 744 // Impl owns the bookmark; delete it here: SolarMutex is locked 745 Invalidate(); 746 } 747 748 void Invalidate() 749 { 750 if (m_pMark) 751 { 752 m_rDoc.getIDocumentMarkAccess()->deleteMark(m_pMark); 753 m_pMark = nullptr; 754 } 755 m_pTableFormat = nullptr; 756 EndListeningAll(); 757 } 758 759 const ::sw::mark::IMark* GetBookmark() const { return m_pMark; } 760 void SetMark(::sw::mark::IMark& rMark) 761 { 762 EndListeningAll(); 763 m_pTableFormat = nullptr; 764 m_pMark = &rMark; 765 StartListening(rMark.GetNotifier()); 766 } 767 768 protected: 769 virtual void Notify(const SfxHint&) override; 770 }; 771 772 void SwXTextRange::Impl::Notify(const SfxHint& rHint) 773 { 774 if(rHint.GetId() == SfxHintId::Dying) 775 { 776 EndListeningAll(); 777 m_pTableFormat = nullptr; 778 m_pMark = nullptr; 779 } 780 } 781 782 SwXTextRange::SwXTextRange(SwPaM const & rPam, 783 const uno::Reference< text::XText > & xParent, 784 const enum RangePosition eRange) 785 : m_pImpl( new SwXTextRange::Impl(*rPam.GetDoc(), eRange, nullptr, xParent) ) 786 { 787 SetPositions(rPam); 788 } 789 790 SwXTextRange::SwXTextRange(SwFrameFormat& rTableFormat) 791 : m_pImpl( 792 new SwXTextRange::Impl(*rTableFormat.GetDoc(), RANGE_IS_TABLE, &rTableFormat) ) 793 { 794 SwTable *const pTable = SwTable::FindTable( &rTableFormat ); 795 SwTableNode *const pTableNode = pTable->GetTableNode(); 796 SwPosition aPosition( *pTableNode ); 797 SwPaM aPam( aPosition ); 798 799 SetPositions( aPam ); 800 } 801 802 SwXTextRange::~SwXTextRange() 803 { 804 } 805 806 const SwDoc& SwXTextRange::GetDoc() const 807 { 808 return m_pImpl->m_rDoc; 809 } 810 811 SwDoc& SwXTextRange::GetDoc() 812 { 813 return m_pImpl->m_rDoc; 814 } 815 816 void SwXTextRange::Invalidate() 817 { 818 m_pImpl->Invalidate(); 819 } 820 821 void SwXTextRange::SetPositions(const SwPaM& rPam) 822 { 823 m_pImpl->Invalidate(); 824 IDocumentMarkAccess* const pMA = m_pImpl->m_rDoc.getIDocumentMarkAccess(); 825 auto pMark = pMA->makeMark(rPam, OUString(), IDocumentMarkAccess::MarkType::UNO_BOOKMARK, sw::mark::InsertMode::New); 826 m_pImpl->SetMark(*pMark); 827 } 828 829 void SwXTextRange::DeleteAndInsert( 830 const OUString& rText, const bool bForceExpandHints) 831 { 832 if (RANGE_IS_TABLE == m_pImpl->m_eRangePosition) 833 { 834 // setString on table not allowed 835 throw uno::RuntimeException(); 836 } 837 838 const SwPosition aPos(GetDoc().GetNodes().GetEndOfContent()); 839 SwCursor aCursor(aPos, nullptr); 840 if (GetPositions(aCursor)) 841 { 842 UnoActionContext aAction(& m_pImpl->m_rDoc); 843 m_pImpl->m_rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT, nullptr); 844 if (aCursor.HasMark()) 845 { 846 m_pImpl->m_rDoc.getIDocumentContentOperations().DeleteAndJoin(aCursor); 847 } 848 849 if (!rText.isEmpty()) 850 { 851 SwUnoCursorHelper::DocInsertStringSplitCR( 852 m_pImpl->m_rDoc, aCursor, rText, bForceExpandHints); 853 854 SwUnoCursorHelper::SelectPam(aCursor, true); 855 aCursor.Left(rText.getLength()); 856 } 857 SetPositions(aCursor); 858 m_pImpl->m_rDoc.GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT, nullptr); 859 } 860 } 861 862 namespace 863 { 864 class theSwXTextRangeUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theSwXTextRangeUnoTunnelId > {}; 865 } 866 867 const uno::Sequence< sal_Int8 > & SwXTextRange::getUnoTunnelId() 868 { 869 return theSwXTextRangeUnoTunnelId::get().getSeq(); 870 } 871 872 // XUnoTunnel 873 sal_Int64 SAL_CALL 874 SwXTextRange::getSomething(const uno::Sequence< sal_Int8 >& rId) 875 { 876 return ::sw::UnoTunnelImpl<SwXTextRange>(rId, this); 877 } 878 879 OUString SAL_CALL 880 SwXTextRange::getImplementationName() 881 { 882 return OUString("SwXTextRange"); 883 } 884 885 static char const*const g_ServicesTextRange[] = 886 { 887 "com.sun.star.text.TextRange", 888 "com.sun.star.style.CharacterProperties", 889 "com.sun.star.style.CharacterPropertiesAsian", 890 "com.sun.star.style.CharacterPropertiesComplex", 891 "com.sun.star.style.ParagraphProperties", 892 "com.sun.star.style.ParagraphPropertiesAsian", 893 "com.sun.star.style.ParagraphPropertiesComplex", 894 }; 895 896 static const size_t g_nServicesTextRange(SAL_N_ELEMENTS(g_ServicesTextRange)); 897 898 sal_Bool SAL_CALL SwXTextRange::supportsService(const OUString& rServiceName) 899 { 900 return cppu::supportsService(this, rServiceName); 901 } 902 903 uno::Sequence< OUString > SAL_CALL 904 SwXTextRange::getSupportedServiceNames() 905 { 906 return ::sw::GetSupportedServiceNamesImpl( 907 g_nServicesTextRange, g_ServicesTextRange); 908 } 909 910 uno::Reference< text::XText > SAL_CALL 911 SwXTextRange::getText() 912 { 913 SolarMutexGuard aGuard; 914 915 if (!m_pImpl->m_xParentText.is()) 916 { 917 if (m_pImpl->m_eRangePosition == RANGE_IS_TABLE && 918 m_pImpl->m_pTableFormat) 919 { 920 SwTable const*const pTable = SwTable::FindTable( m_pImpl->m_pTableFormat ); 921 SwTableNode const*const pTableNode = pTable->GetTableNode(); 922 const SwPosition aPosition( *pTableNode ); 923 m_pImpl->m_xParentText = 924 ::sw::CreateParentXText(m_pImpl->m_rDoc, aPosition); 925 } 926 } 927 OSL_ENSURE(m_pImpl->m_xParentText.is(), "SwXTextRange::getText: no text"); 928 return m_pImpl->m_xParentText; 929 } 930 931 uno::Reference< text::XTextRange > SAL_CALL 932 SwXTextRange::getStart() 933 { 934 SolarMutexGuard aGuard; 935 936 uno::Reference< text::XTextRange > xRet; 937 ::sw::mark::IMark const * const pBkmk = m_pImpl->GetBookmark(); 938 if (!m_pImpl->m_xParentText.is()) 939 { 940 getText(); 941 } 942 if(pBkmk) 943 { 944 SwPaM aPam(pBkmk->GetMarkStart()); 945 xRet = new SwXTextRange(aPam, m_pImpl->m_xParentText); 946 } 947 else if (RANGE_IS_TABLE == m_pImpl->m_eRangePosition) 948 { 949 // start and end are this, if it's a table 950 xRet = this; 951 } 952 else 953 { 954 throw uno::RuntimeException(); 955 } 956 return xRet; 957 } 958 959 uno::Reference< text::XTextRange > SAL_CALL 960 SwXTextRange::getEnd() 961 { 962 SolarMutexGuard aGuard; 963 964 uno::Reference< text::XTextRange > xRet; 965 ::sw::mark::IMark const * const pBkmk = m_pImpl->GetBookmark(); 966 if (!m_pImpl->m_xParentText.is()) 967 { 968 getText(); 969 } 970 if(pBkmk) 971 { 972 SwPaM aPam(pBkmk->GetMarkEnd()); 973 xRet = new SwXTextRange(aPam, m_pImpl->m_xParentText); 974 } 975 else if (RANGE_IS_TABLE == m_pImpl->m_eRangePosition) 976 { 977 // start and end are this, if it's a table 978 xRet = this; 979 } 980 else 981 { 982 throw uno::RuntimeException(); 983 } 984 return xRet; 985 } 986 987 OUString SAL_CALL SwXTextRange::getString() 988 { 989 SolarMutexGuard aGuard; 990 991 OUString sRet; 992 // for tables there is no bookmark, thus also no text 993 // one could export the table as ASCII here maybe? 994 SwPaM aPaM(GetDoc().GetNodes()); 995 if (GetPositions(aPaM) && aPaM.HasMark()) 996 { 997 SwUnoCursorHelper::GetTextFromPam(aPaM, sRet); 998 } 999 return sRet; 1000 } 1001 1002 void SAL_CALL SwXTextRange::setString(const OUString& rString) 1003 { 1004 SolarMutexGuard aGuard; 1005 1006 DeleteAndInsert(rString, false); 1007 } 1008 1009 bool SwXTextRange::GetPositions(SwPaM& rToFill) const 1010 { 1011 ::sw::mark::IMark const * const pBkmk = m_pImpl->GetBookmark(); 1012 if(pBkmk) 1013 { 1014 *rToFill.GetPoint() = pBkmk->GetMarkPos(); 1015 if(pBkmk->IsExpanded()) 1016 { 1017 rToFill.SetMark(); 1018 *rToFill.GetMark() = pBkmk->GetOtherMarkPos(); 1019 } 1020 else 1021 { 1022 rToFill.DeleteMark(); 1023 } 1024 return true; 1025 } 1026 return false; 1027 } 1028 1029 namespace sw { 1030 1031 bool XTextRangeToSwPaM( SwUnoInternalPaM & rToFill, 1032 const uno::Reference< text::XTextRange > & xTextRange) 1033 { 1034 bool bRet = false; 1035 1036 uno::Reference<lang::XUnoTunnel> xRangeTunnel( xTextRange, uno::UNO_QUERY); 1037 SwXTextRange* pRange = nullptr; 1038 OTextCursorHelper* pCursor = nullptr; 1039 SwXTextPortion* pPortion = nullptr; 1040 SwXText* pText = nullptr; 1041 SwXParagraph* pPara = nullptr; 1042 if(xRangeTunnel.is()) 1043 { 1044 pRange = ::sw::UnoTunnelGetImplementation<SwXTextRange>(xRangeTunnel); 1045 pCursor = 1046 ::sw::UnoTunnelGetImplementation<OTextCursorHelper>(xRangeTunnel); 1047 pPortion= 1048 ::sw::UnoTunnelGetImplementation<SwXTextPortion>(xRangeTunnel); 1049 pText = ::sw::UnoTunnelGetImplementation<SwXText>(xRangeTunnel); 1050 pPara = ::sw::UnoTunnelGetImplementation<SwXParagraph>(xRangeTunnel); 1051 } 1052 1053 // if it's a text then create a temporary cursor there and re-use 1054 // the pCursor variable 1055 // #i108489#: Reference in outside scope to keep cursor alive 1056 uno::Reference< text::XTextCursor > xTextCursor; 1057 if (pText) 1058 { 1059 xTextCursor.set( pText->CreateCursor() ); 1060 xTextCursor->gotoEnd(true); 1061 const uno::Reference<lang::XUnoTunnel> xCursorTunnel( 1062 xTextCursor, uno::UNO_QUERY); 1063 pCursor = 1064 ::sw::UnoTunnelGetImplementation<OTextCursorHelper>(xCursorTunnel); 1065 } 1066 if(pRange && &pRange->GetDoc() == rToFill.GetDoc()) 1067 { 1068 bRet = pRange->GetPositions(rToFill); 1069 } 1070 else 1071 { 1072 if (pPara) 1073 { 1074 bRet = pPara->SelectPaM(rToFill); 1075 } 1076 else 1077 { 1078 SwDoc* const pDoc = pCursor ? pCursor->GetDoc() 1079 : (pPortion ? pPortion->GetCursor().GetDoc() : nullptr); 1080 const SwPaM* const pUnoCursor = pCursor ? pCursor->GetPaM() 1081 : (pPortion ? &pPortion->GetCursor() : nullptr); 1082 if (pUnoCursor && pDoc == rToFill.GetDoc()) 1083 { 1084 OSL_ENSURE(!pUnoCursor->IsMultiSelection(), 1085 "what to do about rings?"); 1086 bRet = true; 1087 *rToFill.GetPoint() = *pUnoCursor->GetPoint(); 1088 if (pUnoCursor->HasMark()) 1089 { 1090 rToFill.SetMark(); 1091 *rToFill.GetMark() = *pUnoCursor->GetMark(); 1092 } 1093 else 1094 rToFill.DeleteMark(); 1095 } 1096 } 1097 } 1098 return bRet; 1099 } 1100 1101 static bool 1102 lcl_IsStartNodeInFormat(const bool bHeader, SwStartNode const *const pSttNode, 1103 SwFrameFormat const*const pFrameFormat, SwFrameFormat*& rpFormat) 1104 { 1105 bool bRet = false; 1106 const SfxItemSet& rSet = pFrameFormat->GetAttrSet(); 1107 const SfxPoolItem* pItem; 1108 if (SfxItemState::SET == rSet.GetItemState( 1109 bHeader ? sal_uInt16(RES_HEADER) : sal_uInt16(RES_FOOTER), 1110 true, &pItem)) 1111 { 1112 SfxPoolItem *const pItemNonConst(const_cast<SfxPoolItem *>(pItem)); 1113 SwFrameFormat *const pHeadFootFormat = bHeader ? 1114 static_cast<SwFormatHeader*>(pItemNonConst)->GetHeaderFormat() : 1115 static_cast<SwFormatFooter*>(pItemNonConst)->GetFooterFormat(); 1116 if (pHeadFootFormat) 1117 { 1118 const SwFormatContent& rFlyContent = pHeadFootFormat->GetContent(); 1119 const SwNode& rNode = rFlyContent.GetContentIdx()->GetNode(); 1120 SwStartNode const*const pCurSttNode = rNode.FindSttNodeByType( 1121 bHeader ? SwHeaderStartNode : SwFooterStartNode); 1122 if (pCurSttNode && (pCurSttNode == pSttNode)) 1123 { 1124 rpFormat = pHeadFootFormat; 1125 bRet = true; 1126 } 1127 } 1128 } 1129 return bRet; 1130 } 1131 1132 } // namespace sw 1133 1134 uno::Reference< text::XTextRange > 1135 SwXTextRange::CreateXTextRange( 1136 SwDoc & rDoc, const SwPosition& rPos, const SwPosition *const pMark) 1137 { 1138 const uno::Reference<text::XText> xParentText( 1139 ::sw::CreateParentXText(rDoc, rPos)); 1140 const auto pNewCursor(rDoc.CreateUnoCursor(rPos)); 1141 if(pMark) 1142 { 1143 pNewCursor->SetMark(); 1144 *pNewCursor->GetMark() = *pMark; 1145 } 1146 const bool isCell( dynamic_cast<SwXCell*>(xParentText.get()) ); 1147 const uno::Reference< text::XTextRange > xRet( 1148 new SwXTextRange(*pNewCursor, xParentText, 1149 isCell ? RANGE_IN_CELL : RANGE_IN_TEXT) ); 1150 return xRet; 1151 } 1152 1153 namespace sw { 1154 1155 uno::Reference< text::XText > 1156 CreateParentXText(SwDoc & rDoc, const SwPosition& rPos) 1157 { 1158 uno::Reference< text::XText > xParentText; 1159 SwStartNode* pSttNode = rPos.nNode.GetNode().StartOfSectionNode(); 1160 while(pSttNode && pSttNode->IsSectionNode()) 1161 { 1162 pSttNode = pSttNode->StartOfSectionNode(); 1163 } 1164 SwStartNodeType eType = pSttNode ? pSttNode->GetStartNodeType() : SwNormalStartNode; 1165 switch(eType) 1166 { 1167 case SwTableBoxStartNode: 1168 { 1169 SwTableNode const*const pTableNode = pSttNode->FindTableNode(); 1170 SwFrameFormat *const pTableFormat = 1171 static_cast<SwFrameFormat*>(pTableNode->GetTable().GetFrameFormat()); 1172 SwTableBox *const pBox = pSttNode->GetTableBox(); 1173 1174 xParentText = pBox 1175 ? SwXCell::CreateXCell( pTableFormat, pBox ) 1176 : new SwXCell( pTableFormat, *pSttNode ); 1177 } 1178 break; 1179 case SwFlyStartNode: 1180 { 1181 SwFrameFormat *const pFormat = pSttNode->GetFlyFormat(); 1182 if (nullptr != pFormat) 1183 { 1184 xParentText.set(SwXTextFrame::CreateXTextFrame(rDoc, pFormat), 1185 uno::UNO_QUERY); 1186 } 1187 } 1188 break; 1189 case SwHeaderStartNode: 1190 case SwFooterStartNode: 1191 { 1192 const bool bHeader = (SwHeaderStartNode == eType); 1193 const size_t nPDescCount = rDoc.GetPageDescCnt(); 1194 for(size_t i = 0; i < nPDescCount; i++) 1195 { 1196 const SwPageDesc& rDesc = rDoc.GetPageDesc( i ); 1197 const SwFrameFormat* pFrameFormatMaster = &rDesc.GetMaster(); 1198 const SwFrameFormat* pFrameFormatLeft = &rDesc.GetLeft(); 1199 1200 SwFrameFormat* pHeadFootFormat = nullptr; 1201 if (!lcl_IsStartNodeInFormat(bHeader, pSttNode, pFrameFormatMaster, 1202 pHeadFootFormat)) 1203 { 1204 lcl_IsStartNodeInFormat(bHeader, pSttNode, pFrameFormatLeft, 1205 pHeadFootFormat); 1206 } 1207 1208 if (pHeadFootFormat) 1209 { 1210 xParentText = SwXHeadFootText::CreateXHeadFootText( 1211 *pHeadFootFormat, bHeader); 1212 } 1213 } 1214 } 1215 break; 1216 case SwFootnoteStartNode: 1217 { 1218 const size_t nFootnoteCnt = rDoc.GetFootnoteIdxs().size(); 1219 for (size_t n = 0; n < nFootnoteCnt; ++n ) 1220 { 1221 const SwTextFootnote* pTextFootnote = rDoc.GetFootnoteIdxs()[ n ]; 1222 const SwFormatFootnote& rFootnote = pTextFootnote->GetFootnote(); 1223 pTextFootnote = rFootnote.GetTextFootnote(); 1224 1225 if (pSttNode == pTextFootnote->GetStartNode()->GetNode(). 1226 FindSttNodeByType(SwFootnoteStartNode)) 1227 { 1228 xParentText.set(SwXFootnote::CreateXFootnote(rDoc, 1229 &const_cast<SwFormatFootnote&>(rFootnote)), uno::UNO_QUERY); 1230 break; 1231 } 1232 } 1233 } 1234 break; 1235 default: 1236 { 1237 // then it is the body text 1238 const uno::Reference<frame::XModel> xModel = 1239 rDoc.GetDocShell()->GetBaseModel(); 1240 const uno::Reference< text::XTextDocument > xDoc( 1241 xModel, uno::UNO_QUERY); 1242 xParentText = xDoc->getText(); 1243 } 1244 } 1245 OSL_ENSURE(xParentText.is(), "no parent text?"); 1246 return xParentText; 1247 } 1248 1249 } // namespace sw 1250 1251 uno::Reference< container::XEnumeration > SAL_CALL 1252 SwXTextRange::createContentEnumeration(const OUString& rServiceName) 1253 { 1254 SolarMutexGuard g; 1255 1256 if ( rServiceName != "com.sun.star.text.TextContent" ) 1257 { 1258 throw uno::RuntimeException(); 1259 } 1260 1261 if (!m_pImpl->GetBookmark()) 1262 { 1263 throw uno::RuntimeException(); 1264 } 1265 const SwPosition aPos(GetDoc().GetNodes().GetEndOfContent()); 1266 const auto pNewCursor(m_pImpl->m_rDoc.CreateUnoCursor(aPos)); 1267 if (!GetPositions(*pNewCursor)) 1268 { 1269 throw uno::RuntimeException(); 1270 } 1271 1272 return SwXParaFrameEnumeration::Create(*pNewCursor, PARAFRAME_PORTION_TEXTRANGE); 1273 } 1274 1275 uno::Reference< container::XEnumeration > SAL_CALL 1276 SwXTextRange::createEnumeration() 1277 { 1278 SolarMutexGuard g; 1279 1280 if (!m_pImpl->GetBookmark()) 1281 { 1282 throw uno::RuntimeException(); 1283 } 1284 const SwPosition aPos(GetDoc().GetNodes().GetEndOfContent()); 1285 auto pNewCursor(m_pImpl->m_rDoc.CreateUnoCursor(aPos)); 1286 if (!GetPositions(*pNewCursor)) 1287 { 1288 throw uno::RuntimeException(); 1289 } 1290 if (!m_pImpl->m_xParentText.is()) 1291 { 1292 getText(); 1293 } 1294 1295 const CursorType eSetType = (RANGE_IN_CELL == m_pImpl->m_eRangePosition) 1296 ? CursorType::SelectionInTable : CursorType::Selection; 1297 return SwXParagraphEnumeration::Create(m_pImpl->m_xParentText, pNewCursor, eSetType); 1298 } 1299 1300 uno::Type SAL_CALL SwXTextRange::getElementType() 1301 { 1302 return cppu::UnoType<text::XTextRange>::get(); 1303 } 1304 1305 sal_Bool SAL_CALL SwXTextRange::hasElements() 1306 { 1307 return true; 1308 } 1309 1310 uno::Sequence< OUString > SAL_CALL 1311 SwXTextRange::getAvailableServiceNames() 1312 { 1313 uno::Sequence<OUString> aRet { "com.sun.star.text.TextContent" }; 1314 return aRet; 1315 } 1316 1317 uno::Reference< beans::XPropertySetInfo > SAL_CALL 1318 SwXTextRange::getPropertySetInfo() 1319 { 1320 SolarMutexGuard aGuard; 1321 1322 static uno::Reference< beans::XPropertySetInfo > xRef = 1323 m_pImpl->m_rPropSet.getPropertySetInfo(); 1324 return xRef; 1325 } 1326 1327 void SAL_CALL 1328 SwXTextRange::setPropertyValue( 1329 const OUString& rPropertyName, const uno::Any& rValue) 1330 { 1331 SolarMutexGuard aGuard; 1332 1333 if (!m_pImpl->GetBookmark()) 1334 { 1335 throw uno::RuntimeException(); 1336 } 1337 SwPaM aPaM(GetDoc().GetNodes()); 1338 GetPositions(aPaM); 1339 SwUnoCursorHelper::SetPropertyValue(aPaM, m_pImpl->m_rPropSet, 1340 rPropertyName, rValue); 1341 } 1342 1343 uno::Any SAL_CALL 1344 SwXTextRange::getPropertyValue(const OUString& rPropertyName) 1345 { 1346 SolarMutexGuard aGuard; 1347 1348 if (!m_pImpl->GetBookmark()) 1349 { 1350 throw uno::RuntimeException(); 1351 } 1352 SwPaM aPaM(GetDoc().GetNodes()); 1353 GetPositions(aPaM); 1354 return SwUnoCursorHelper::GetPropertyValue(aPaM, m_pImpl->m_rPropSet, 1355 rPropertyName); 1356 } 1357 1358 void SAL_CALL 1359 SwXTextRange::addPropertyChangeListener( 1360 const OUString& /*rPropertyName*/, 1361 const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) 1362 { 1363 OSL_FAIL("SwXTextRange::addPropertyChangeListener(): not implemented"); 1364 } 1365 1366 void SAL_CALL 1367 SwXTextRange::removePropertyChangeListener( 1368 const OUString& /*rPropertyName*/, 1369 const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) 1370 { 1371 OSL_FAIL("SwXTextRange::removePropertyChangeListener(): not implemented"); 1372 } 1373 1374 void SAL_CALL 1375 SwXTextRange::addVetoableChangeListener( 1376 const OUString& /*rPropertyName*/, 1377 const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) 1378 { 1379 OSL_FAIL("SwXTextRange::addVetoableChangeListener(): not implemented"); 1380 } 1381 1382 void SAL_CALL 1383 SwXTextRange::removeVetoableChangeListener( 1384 const OUString& /*rPropertyName*/, 1385 const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) 1386 { 1387 OSL_FAIL("SwXTextRange::removeVetoableChangeListener(): not implemented"); 1388 } 1389 1390 beans::PropertyState SAL_CALL 1391 SwXTextRange::getPropertyState(const OUString& rPropertyName) 1392 { 1393 SolarMutexGuard aGuard; 1394 1395 if (!m_pImpl->GetBookmark()) 1396 { 1397 throw uno::RuntimeException(); 1398 } 1399 SwPaM aPaM(GetDoc().GetNodes()); 1400 GetPositions(aPaM); 1401 return SwUnoCursorHelper::GetPropertyState(aPaM, m_pImpl->m_rPropSet, 1402 rPropertyName); 1403 } 1404 1405 uno::Sequence< beans::PropertyState > SAL_CALL 1406 SwXTextRange::getPropertyStates(const uno::Sequence< OUString >& rPropertyName) 1407 { 1408 SolarMutexGuard g; 1409 1410 if (!m_pImpl->GetBookmark()) 1411 { 1412 throw uno::RuntimeException(); 1413 } 1414 SwPaM aPaM(GetDoc().GetNodes()); 1415 GetPositions(aPaM); 1416 return SwUnoCursorHelper::GetPropertyStates(aPaM, m_pImpl->m_rPropSet, 1417 rPropertyName); 1418 } 1419 1420 void SAL_CALL SwXTextRange::setPropertyToDefault(const OUString& rPropertyName) 1421 { 1422 SolarMutexGuard aGuard; 1423 1424 if (!m_pImpl->GetBookmark()) 1425 { 1426 throw uno::RuntimeException(); 1427 } 1428 SwPaM aPaM(GetDoc().GetNodes()); 1429 GetPositions(aPaM); 1430 SwUnoCursorHelper::SetPropertyToDefault(aPaM, m_pImpl->m_rPropSet, 1431 rPropertyName); 1432 } 1433 1434 uno::Any SAL_CALL 1435 SwXTextRange::getPropertyDefault(const OUString& rPropertyName) 1436 { 1437 SolarMutexGuard aGuard; 1438 1439 if (!m_pImpl->GetBookmark()) 1440 { 1441 throw uno::RuntimeException(); 1442 } 1443 SwPaM aPaM(GetDoc().GetNodes()); 1444 GetPositions(aPaM); 1445 return SwUnoCursorHelper::GetPropertyDefault(aPaM, m_pImpl->m_rPropSet, 1446 rPropertyName); 1447 } 1448 1449 void SAL_CALL 1450 SwXTextRange::makeRedline( 1451 const OUString& rRedlineType, 1452 const uno::Sequence< beans::PropertyValue >& rRedlineProperties ) 1453 { 1454 SolarMutexGuard aGuard; 1455 1456 if (!m_pImpl->GetBookmark()) 1457 { 1458 throw uno::RuntimeException(); 1459 } 1460 SwPaM aPaM(GetDoc().GetNodes()); 1461 SwXTextRange::GetPositions(aPaM); 1462 SwUnoCursorHelper::makeRedline( aPaM, rRedlineType, rRedlineProperties ); 1463 } 1464 1465 struct SwXTextRangesImpl final : public SwXTextRanges 1466 { 1467 1468 // XUnoTunnel 1469 virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& rIdentifier) override; 1470 1471 // XServiceInfo 1472 virtual OUString SAL_CALL getImplementationName() override 1473 { return OUString("SwXTextRanges"); }; 1474 virtual sal_Bool SAL_CALL supportsService( const OUString& rServiceName) override 1475 { return cppu::supportsService(this, rServiceName); }; 1476 virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override 1477 { return { "com.sun.star.text.TextRanges" }; }; 1478 1479 // XElementAccess 1480 virtual css::uno::Type SAL_CALL getElementType() override 1481 { return cppu::UnoType<text::XTextRange>::get(); }; 1482 virtual sal_Bool SAL_CALL hasElements() override 1483 { return getCount() > 0; }; 1484 // XIndexAccess 1485 virtual sal_Int32 SAL_CALL getCount() override; 1486 virtual css::uno::Any SAL_CALL getByIndex(sal_Int32 nIndex) override; 1487 1488 explicit SwXTextRangesImpl(SwPaM *const pPaM) 1489 { 1490 if (pPaM) 1491 { 1492 m_pUnoCursor.reset(pPaM->GetDoc()->CreateUnoCursor(*pPaM->GetPoint())); 1493 ::sw::DeepCopyPaM(*pPaM, *GetCursor()); 1494 } 1495 MakeRanges(); 1496 } 1497 virtual void SAL_CALL release() throw () override 1498 { 1499 SolarMutexGuard g; 1500 OWeakObject::release(); 1501 } 1502 virtual SwUnoCursor* GetCursor() override 1503 { return &(*m_pUnoCursor); }; 1504 void MakeRanges(); 1505 std::vector< uno::Reference< text::XTextRange > > m_Ranges; 1506 sw::UnoCursorPointer m_pUnoCursor; 1507 }; 1508 1509 void SwXTextRangesImpl::MakeRanges() 1510 { 1511 if (GetCursor()) 1512 { 1513 for(SwPaM& rTmpCursor : GetCursor()->GetRingContainer()) 1514 { 1515 const uno::Reference< text::XTextRange > xRange( 1516 SwXTextRange::CreateXTextRange( 1517 *rTmpCursor.GetDoc(), 1518 *rTmpCursor.GetPoint(), rTmpCursor.GetMark())); 1519 if (xRange.is()) 1520 { 1521 m_Ranges.push_back(xRange); 1522 } 1523 } 1524 } 1525 } 1526 1527 SwXTextRanges* SwXTextRanges::Create(SwPaM *const pPaM) 1528 { return new SwXTextRangesImpl(pPaM); } 1529 1530 namespace 1531 { 1532 class theSwXTextRangesUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theSwXTextRangesUnoTunnelId > {}; 1533 } 1534 1535 const uno::Sequence< sal_Int8 > & SwXTextRanges::getUnoTunnelId() 1536 { return theSwXTextRangesUnoTunnelId::get().getSeq(); } 1537 1538 sal_Int64 SAL_CALL 1539 SwXTextRangesImpl::getSomething(const uno::Sequence< sal_Int8 >& rId) 1540 { 1541 return ::sw::UnoTunnelImpl<SwXTextRanges>(rId, this); 1542 } 1543 1544 /* 1545 * Text positions 1546 * Up to the first access to a text position, only a SwCursor is stored. 1547 * Afterwards, an array with uno::Reference<XTextPosition> will be created. 1548 */ 1549 1550 sal_Int32 SAL_CALL SwXTextRangesImpl::getCount() 1551 { 1552 SolarMutexGuard aGuard; 1553 return static_cast<sal_Int32>(m_Ranges.size()); 1554 } 1555 1556 uno::Any SAL_CALL SwXTextRangesImpl::getByIndex(sal_Int32 nIndex) 1557 { 1558 SolarMutexGuard aGuard; 1559 if ((nIndex < 0) || (static_cast<size_t>(nIndex) >= m_Ranges.size())) 1560 throw lang::IndexOutOfBoundsException(); 1561 uno::Any ret; 1562 ret <<= m_Ranges.at(nIndex); 1563 return ret; 1564 } 1565 1566 void SwUnoCursorHelper::SetString(SwCursor & rCursor, const OUString& rString) 1567 { 1568 // Start/EndAction 1569 SwDoc *const pDoc = rCursor.GetDoc(); 1570 UnoActionContext aAction(pDoc); 1571 pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT, nullptr); 1572 if (rCursor.HasMark()) 1573 { 1574 pDoc->getIDocumentContentOperations().DeleteAndJoin(rCursor); 1575 } 1576 if (!rString.isEmpty()) 1577 { 1578 const bool bSuccess( SwUnoCursorHelper::DocInsertStringSplitCR( 1579 *pDoc, rCursor, rString, false ) ); 1580 OSL_ENSURE( bSuccess, "DocInsertStringSplitCR" ); 1581 SwUnoCursorHelper::SelectPam(rCursor, true); 1582 rCursor.Left(rString.getLength()); 1583 } 1584 pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT, nullptr); 1585 } 1586 1587 struct SwXParaFrameEnumerationImpl final : public SwXParaFrameEnumeration 1588 { 1589 // XServiceInfo 1590 virtual OUString SAL_CALL getImplementationName() override 1591 { return OUString("SwXParaFrameEnumeration"); }; 1592 virtual sal_Bool SAL_CALL supportsService(const OUString& rServiceName) override 1593 { return cppu::supportsService(this, rServiceName); }; 1594 virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override 1595 { return {"com.sun.star.util.ContentEnumeration"}; }; 1596 1597 // XEnumeration 1598 virtual sal_Bool SAL_CALL hasMoreElements() override; 1599 virtual css::uno::Any SAL_CALL nextElement() override; 1600 1601 SwXParaFrameEnumerationImpl(const SwPaM& rPaM, const enum ParaFrameMode eParaFrameMode, SwFrameFormat* const pFormat); 1602 virtual void SAL_CALL release() throw () override 1603 { 1604 SolarMutexGuard g; 1605 OWeakObject::release(); 1606 } 1607 SwUnoCursor& GetCursor() 1608 { return *m_pUnoCursor; } 1609 void PurgeFrameClients() 1610 { 1611 if(!m_pUnoCursor) 1612 { 1613 m_vFrames.clear(); 1614 m_xNextObject = nullptr; 1615 } 1616 else 1617 { 1618 // removing orphaned Clients 1619 const auto iter = std::remove_if(m_vFrames.begin(), m_vFrames.end(), 1620 [] (std::shared_ptr<sw::FrameClient>& rEntry) -> bool { return !rEntry->GetRegisteredIn(); }); 1621 m_vFrames.erase(iter, m_vFrames.end()); 1622 } 1623 } 1624 void FillFrame(); 1625 bool CreateNextObject(); 1626 uno::Reference< text::XTextContent > m_xNextObject; 1627 FrameClientList_t m_vFrames; 1628 ::sw::UnoCursorPointer m_pUnoCursor; 1629 }; 1630 1631 1632 SwXParaFrameEnumeration* SwXParaFrameEnumeration::Create(const SwPaM& rPaM, const enum ParaFrameMode eParaFrameMode, SwFrameFormat* const pFormat) 1633 { return new SwXParaFrameEnumerationImpl(rPaM, eParaFrameMode, pFormat); } 1634 1635 SwXParaFrameEnumerationImpl::SwXParaFrameEnumerationImpl( 1636 const SwPaM& rPaM, const enum ParaFrameMode eParaFrameMode, 1637 SwFrameFormat* const pFormat) 1638 : m_pUnoCursor(rPaM.GetDoc()->CreateUnoCursor(*rPaM.GetPoint())) 1639 { 1640 if (rPaM.HasMark()) 1641 { 1642 GetCursor().SetMark(); 1643 *GetCursor().GetMark() = *rPaM.GetMark(); 1644 } 1645 if (PARAFRAME_PORTION_PARAGRAPH == eParaFrameMode) 1646 { 1647 FrameClientSortList_t vFrames; 1648 ::CollectFrameAtNode(rPaM.GetPoint()->nNode, vFrames, false); 1649 std::transform(vFrames.begin(), vFrames.end(), 1650 std::back_inserter(m_vFrames), 1651 [] (const FrameClientSortListEntry& rEntry) { return rEntry.pFrameClient; }); 1652 } 1653 else if (pFormat) 1654 { 1655 m_vFrames.push_back(std::make_shared<sw::FrameClient>(pFormat)); 1656 } 1657 else if ((PARAFRAME_PORTION_CHAR == eParaFrameMode) || 1658 (PARAFRAME_PORTION_TEXTRANGE == eParaFrameMode)) 1659 { 1660 if (PARAFRAME_PORTION_TEXTRANGE == eParaFrameMode) 1661 { 1662 //get all frames that are bound at paragraph or at character 1663 for(const auto& pFlyFrame : rPaM.GetDoc()->GetAllFlyFormats(&GetCursor(), false, true)) 1664 { 1665 const auto pFrameFormat = const_cast<SwFrameFormat*>(&pFlyFrame->GetFormat()); 1666 m_vFrames.push_back(std::make_shared<sw::FrameClient>(pFrameFormat)); 1667 } 1668 } 1669 FillFrame(); 1670 } 1671 } 1672 1673 // Search for a FLYCNT text attribute at the cursor point and fill the frame 1674 // into the array 1675 void SwXParaFrameEnumerationImpl::FillFrame() 1676 { 1677 if(!m_pUnoCursor->GetNode().IsTextNode()) 1678 return; 1679 // search for objects at the cursor - anchored at/as char 1680 const auto pTextAttr = m_pUnoCursor->GetNode().GetTextNode()->GetTextAttrForCharAt( 1681 m_pUnoCursor->GetPoint()->nContent.GetIndex(), RES_TXTATR_FLYCNT); 1682 if(!pTextAttr) 1683 return; 1684 const SwFormatFlyCnt& rFlyCnt = pTextAttr->GetFlyCnt(); 1685 SwFrameFormat* const pFrameFormat = rFlyCnt.GetFrameFormat(); 1686 m_vFrames.push_back(std::make_shared<sw::FrameClient>(pFrameFormat)); 1687 } 1688 1689 bool SwXParaFrameEnumerationImpl::CreateNextObject() 1690 { 1691 if (m_vFrames.empty()) 1692 return false; 1693 1694 SwFrameFormat* const pFormat = static_cast<SwFrameFormat*>( 1695 m_vFrames.front()->GetRegisteredIn()); 1696 m_vFrames.pop_front(); 1697 // the format should be valid here, otherwise the client 1698 // would have been removed by PurgeFrameClients 1699 // check for a shape first 1700 if(pFormat->Which() == RES_DRAWFRMFMT) 1701 { 1702 SdrObject* pObject(nullptr); 1703 pFormat->CallSwClientNotify(sw::FindSdrObjectHint(pObject)); 1704 if(pObject) 1705 m_xNextObject.set(pObject->getUnoShape(), uno::UNO_QUERY); 1706 } 1707 else 1708 { 1709 const SwNodeIndex* pIdx = pFormat->GetContent().GetContentIdx(); 1710 OSL_ENSURE(pIdx, "where is the index?"); 1711 SwNode const*const pNd = 1712 m_pUnoCursor->GetDoc()->GetNodes()[ pIdx->GetIndex() + 1 ]; 1713 1714 if (!pNd->IsNoTextNode()) 1715 { 1716 m_xNextObject.set(SwXTextFrame::CreateXTextFrame( 1717 *pFormat->GetDoc(), pFormat)); 1718 } 1719 else if (pNd->IsGrfNode()) 1720 { 1721 m_xNextObject.set(SwXTextGraphicObject::CreateXTextGraphicObject( 1722 *pFormat->GetDoc(), pFormat)); 1723 } 1724 else 1725 { 1726 assert(pNd->IsOLENode()); 1727 m_xNextObject.set(SwXTextEmbeddedObject::CreateXTextEmbeddedObject( 1728 *pFormat->GetDoc(), pFormat)); 1729 } 1730 } 1731 return m_xNextObject.is(); 1732 } 1733 1734 sal_Bool SAL_CALL 1735 SwXParaFrameEnumerationImpl::hasMoreElements() 1736 { 1737 SolarMutexGuard aGuard; 1738 PurgeFrameClients(); 1739 return m_xNextObject.is() || CreateNextObject(); 1740 } 1741 1742 uno::Any SAL_CALL SwXParaFrameEnumerationImpl::nextElement() 1743 { 1744 SolarMutexGuard aGuard; 1745 PurgeFrameClients(); 1746 if (!m_xNextObject.is() && !m_vFrames.empty()) 1747 CreateNextObject(); 1748 if (!m_xNextObject.is()) 1749 throw container::NoSuchElementException(); 1750 uno::Any aRet; 1751 aRet <<= m_xNextObject; 1752 m_xNextObject = nullptr; 1753 return aRet; 1754 } 1755 1756 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 1757
