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 <stdlib.h> 21 22 #include <memory> 23 #include <iostream> 24 #include <set> 25 #include <utility> 26 27 #include <com/sun/star/drawing/XDrawPageSupplier.hpp> 28 #include <com/sun/star/text/ControlCharacter.hpp> 29 #include <com/sun/star/text/TableColumnSeparator.hpp> 30 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp> 31 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> 32 33 #include <svl/listener.hxx> 34 #include <vcl/svapp.hxx> 35 #include <comphelper/profilezone.hxx> 36 #include <comphelper/sequence.hxx> 37 #include <comphelper/servicehelper.hxx> 38 #include <cppuhelper/exc_hlp.hxx> 39 #include <cppuhelper/supportsservice.hxx> 40 #include <sal/log.hxx> 41 42 #include <cmdid.h> 43 #include <unotextbodyhf.hxx> 44 #include <unotext.hxx> 45 #include <unotextrange.hxx> 46 #include <unotextcursor.hxx> 47 #include <unosection.hxx> 48 #include <unobookmark.hxx> 49 #include <unorefmark.hxx> 50 #include <unoport.hxx> 51 #include <unotbl.hxx> 52 #include <unoidx.hxx> 53 #include <unocoll.hxx> 54 #include <unoframe.hxx> 55 #include <unofield.hxx> 56 #include <unometa.hxx> 57 #include <unodraw.hxx> 58 #include <unoredline.hxx> 59 #include <unomap.hxx> 60 #include <unoprnms.hxx> 61 #include <unoparagraph.hxx> 62 #include <unocrsrhelper.hxx> 63 #include <docsh.hxx> 64 #include <docary.hxx> 65 #include <doc.hxx> 66 #include <IDocumentUndoRedo.hxx> 67 #include <redline.hxx> 68 #include <swundo.hxx> 69 #include <section.hxx> 70 #include <IMark.hxx> 71 #include <fmtanchr.hxx> 72 #include <fmtcntnt.hxx> 73 #include <ndtxt.hxx> 74 75 using namespace ::com::sun::star; 76 77 const sal_Char cInvalidObject[] = "this object is invalid"; 78 79 class SwXText::Impl 80 { 81 82 public: 83 SwXText & m_rThis; 84 SfxItemPropertySet const& m_rPropSet; 85 const CursorType m_eType; 86 SwDoc * m_pDoc; 87 bool m_bIsValid; 88 89 Impl( SwXText & rThis, 90 SwDoc *const pDoc, const CursorType eType) 91 : m_rThis(rThis) 92 , m_rPropSet(*aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT)) 93 , m_eType(eType) 94 , m_pDoc(pDoc) 95 , m_bIsValid(nullptr != pDoc) 96 { 97 } 98 99 /// @throws lang::IllegalArgumentException 100 /// @throws uno::RuntimeException 101 uno::Reference< text::XTextRange > 102 finishOrAppendParagraph( 103 const uno::Sequence< beans::PropertyValue >& 104 rCharacterAndParagraphProperties, 105 const uno::Reference< text::XTextRange >& xInsertPosition); 106 107 /// @throws lang::IllegalArgumentException 108 /// @throws uno::RuntimeException 109 sal_Int16 ComparePositions( 110 const uno::Reference<text::XTextRange>& xPos1, 111 const uno::Reference<text::XTextRange>& xPos2); 112 113 /// @throws lang::IllegalArgumentException 114 /// @throws uno::RuntimeException 115 bool CheckForOwnMember(const SwPaM & rPaM); 116 117 void ConvertCell( 118 const uno::Sequence< uno::Reference< text::XTextRange > > & rCell, 119 std::vector<SwNodeRange> & rRowNodes, 120 SwNodeRange *const pLastCell); 121 122 }; 123 124 SwXText::SwXText(SwDoc *const pDoc, const CursorType eType) 125 : m_pImpl( new SwXText::Impl(*this, pDoc, eType) ) 126 { 127 } 128 129 SwXText::~SwXText() 130 { 131 } 132 133 const SwDoc * SwXText::GetDoc() const 134 { 135 return m_pImpl->m_pDoc; 136 } 137 SwDoc * SwXText::GetDoc() 138 { 139 return m_pImpl->m_pDoc; 140 } 141 142 bool SwXText::IsValid() const 143 { 144 return m_pImpl->m_bIsValid; 145 } 146 147 void SwXText::Invalidate() 148 { 149 m_pImpl->m_bIsValid = false; 150 } 151 152 void SwXText::SetDoc(SwDoc *const pDoc) 153 { 154 OSL_ENSURE(!m_pImpl->m_pDoc || !pDoc, 155 "SwXText::SetDoc: already have a doc?"); 156 m_pImpl->m_pDoc = pDoc; 157 m_pImpl->m_bIsValid = (nullptr != pDoc); 158 } 159 160 void 161 SwXText::PrepareForAttach(uno::Reference< text::XTextRange > &, const SwPaM &) 162 { 163 } 164 165 bool SwXText::CheckForOwnMemberMeta(const SwPaM &, const bool) 166 { 167 OSL_ENSURE(CursorType::Meta != m_pImpl->m_eType, "should not be called!"); 168 return false; 169 } 170 171 const SwStartNode *SwXText::GetStartNode() const 172 { 173 return GetDoc()->GetNodes().GetEndOfContent().StartOfSectionNode(); 174 } 175 176 uno::Reference< text::XTextCursor > 177 SwXText::CreateCursor() 178 { 179 uno::Reference< text::XTextCursor > xRet; 180 if(IsValid()) 181 { 182 SwNode& rNode = GetDoc()->GetNodes().GetEndOfContent(); 183 SwPosition aPos(rNode); 184 xRet = static_cast<text::XWordCursor*>( 185 new SwXTextCursor(*GetDoc(), this, m_pImpl->m_eType, aPos)); 186 xRet->gotoStart(false); 187 } 188 return xRet; 189 } 190 191 uno::Any SAL_CALL 192 SwXText::queryInterface(const uno::Type& rType) 193 { 194 uno::Any aRet; 195 if (rType == cppu::UnoType<text::XText>::get()) 196 { 197 aRet <<= uno::Reference< text::XText >(this); 198 } 199 else if (rType == cppu::UnoType<text::XSimpleText>::get()) 200 { 201 aRet <<= uno::Reference< text::XSimpleText >(this); 202 } 203 else if (rType == cppu::UnoType<text::XTextRange>::get()) 204 { 205 aRet <<= uno::Reference< text::XTextRange>(this); 206 } 207 else if (rType == cppu::UnoType<text::XTextRangeCompare>::get()) 208 { 209 aRet <<= uno::Reference< text::XTextRangeCompare >(this); 210 } 211 else if (rType == cppu::UnoType<lang::XTypeProvider>::get()) 212 { 213 aRet <<= uno::Reference< lang::XTypeProvider >(this); 214 } 215 else if (rType == cppu::UnoType<text::XRelativeTextContentInsert>::get()) 216 { 217 aRet <<= uno::Reference< text::XRelativeTextContentInsert >(this); 218 } 219 else if (rType == cppu::UnoType<text::XRelativeTextContentRemove>::get()) 220 { 221 aRet <<= uno::Reference< text::XRelativeTextContentRemove >(this); 222 } 223 else if (rType == cppu::UnoType<beans::XPropertySet>::get()) 224 { 225 aRet <<= uno::Reference< beans::XPropertySet >(this); 226 } 227 else if (rType == cppu::UnoType<lang::XUnoTunnel>::get()) 228 { 229 aRet <<= uno::Reference< lang::XUnoTunnel >(this); 230 } 231 else if (rType == cppu::UnoType<text::XTextAppendAndConvert>::get()) 232 { 233 aRet <<= uno::Reference< text::XTextAppendAndConvert >(this); 234 } 235 else if (rType == cppu::UnoType<text::XTextAppend>::get()) 236 { 237 aRet <<= uno::Reference< text::XTextAppend >(this); 238 } 239 else if (rType == cppu::UnoType<text::XTextPortionAppend>::get()) 240 { 241 aRet <<= uno::Reference< text::XTextPortionAppend >(this); 242 } 243 else if (rType == cppu::UnoType<text::XParagraphAppend>::get()) 244 { 245 aRet <<= uno::Reference< text::XParagraphAppend >(this); 246 } 247 else if (rType == cppu::UnoType<text::XTextConvert>::get() ) 248 { 249 aRet <<= uno::Reference< text::XTextConvert >(this); 250 } 251 else if (rType == cppu::UnoType<text::XTextContentAppend>::get()) 252 { 253 aRet <<= uno::Reference< text::XTextContentAppend >(this); 254 } 255 else if(rType == cppu::UnoType<text::XTextCopy>::get()) 256 { 257 aRet <<= uno::Reference< text::XTextCopy >( this ); 258 } 259 return aRet; 260 } 261 262 uno::Sequence< uno::Type > SAL_CALL 263 SwXText::getTypes() 264 { 265 static const uno::Sequence< uno::Type > aTypes { 266 cppu::UnoType<text::XText>::get(), 267 cppu::UnoType<text::XTextRangeCompare>::get(), 268 cppu::UnoType<text::XRelativeTextContentInsert>::get(), 269 cppu::UnoType<text::XRelativeTextContentRemove>::get(), 270 cppu::UnoType<lang::XUnoTunnel>::get(), 271 cppu::UnoType<beans::XPropertySet>::get(), 272 cppu::UnoType<text::XTextPortionAppend>::get(), 273 cppu::UnoType<text::XParagraphAppend>::get(), 274 cppu::UnoType<text::XTextContentAppend>::get(), 275 cppu::UnoType<text::XTextConvert>::get(), 276 cppu::UnoType<text::XTextAppend>::get(), 277 cppu::UnoType<text::XTextAppendAndConvert>::get() 278 }; 279 return aTypes; 280 } 281 282 // belongs the range in the text ? insert it then. 283 void SAL_CALL 284 SwXText::insertString(const uno::Reference< text::XTextRange >& xTextRange, 285 const OUString& rString, sal_Bool bAbsorb) 286 { 287 SolarMutexGuard aGuard; 288 comphelper::ProfileZone aZone("SwXText::insertString"); 289 290 if (!xTextRange.is()) 291 { 292 throw uno::RuntimeException(); 293 } 294 if (!GetDoc()) 295 { 296 throw uno::RuntimeException(); 297 } 298 const uno::Reference<lang::XUnoTunnel> xRangeTunnel(xTextRange, 299 uno::UNO_QUERY); 300 SwXTextRange *const pRange = 301 ::sw::UnoTunnelGetImplementation<SwXTextRange>(xRangeTunnel); 302 OTextCursorHelper *const pCursor = 303 ::sw::UnoTunnelGetImplementation<OTextCursorHelper>(xRangeTunnel); 304 if ((!pRange || &pRange ->GetDoc() != GetDoc()) && 305 (!pCursor || pCursor->GetDoc() != GetDoc())) 306 { 307 throw uno::RuntimeException(); 308 } 309 310 const SwStartNode *const pOwnStartNode = GetStartNode(); 311 SwPaM aPam(GetDoc()->GetNodes()); 312 const SwPaM * pPam(nullptr); 313 if (pCursor) 314 { 315 pPam = pCursor->GetPaM(); 316 } 317 else // pRange 318 { 319 if (pRange->GetPositions(aPam)) 320 { 321 pPam = &aPam; 322 } 323 } 324 if (!pPam) 325 { 326 throw uno::RuntimeException(); 327 } 328 329 const SwStartNode* pTmp(pPam->GetNode().StartOfSectionNode()); 330 while (pTmp && pTmp->IsSectionNode()) 331 { 332 pTmp = pTmp->StartOfSectionNode(); 333 } 334 if (!pOwnStartNode || (pOwnStartNode != pTmp)) 335 { 336 throw uno::RuntimeException(); 337 } 338 339 bool bForceExpandHints( false ); 340 if (CursorType::Meta == m_pImpl->m_eType) 341 { 342 try 343 { 344 bForceExpandHints = CheckForOwnMemberMeta(*pPam, bAbsorb); 345 } 346 catch (const lang::IllegalArgumentException& iae) 347 { 348 // stupid method not allowed to throw iae 349 css::uno::Any anyEx = cppu::getCaughtException(); 350 throw lang::WrappedTargetRuntimeException( iae.Message, 351 uno::Reference< uno::XInterface >(), anyEx ); 352 } 353 } 354 if (bAbsorb) 355 { 356 //!! scan for CR characters and inserting the paragraph breaks 357 //!! has to be done in the called function. 358 //!! Implemented in SwXTextRange::DeleteAndInsert 359 if (pCursor) 360 { 361 SwXTextCursor * const pTextCursor( 362 dynamic_cast<SwXTextCursor*>(pCursor) ); 363 if (pTextCursor) 364 { 365 pTextCursor->DeleteAndInsert(rString, bForceExpandHints); 366 } 367 else 368 { 369 xTextRange->setString(rString); 370 } 371 } 372 else 373 { 374 pRange->DeleteAndInsert(rString, bForceExpandHints); 375 } 376 } 377 else 378 { 379 // create a PaM positioned before the parameter PaM, 380 // so the text is inserted before 381 UnoActionContext aContext(GetDoc()); 382 SwPaM aInsertPam(*pPam->Start()); 383 ::sw::GroupUndoGuard const undoGuard(GetDoc()->GetIDocumentUndoRedo()); 384 SwUnoCursorHelper::DocInsertStringSplitCR( 385 *GetDoc(), aInsertPam, rString, bForceExpandHints ); 386 } 387 } 388 389 void SAL_CALL 390 SwXText::insertControlCharacter( 391 const uno::Reference< text::XTextRange > & xTextRange, 392 sal_Int16 nControlCharacter, sal_Bool bAbsorb) 393 { 394 SolarMutexGuard aGuard; 395 396 if (!xTextRange.is()) 397 { 398 throw lang::IllegalArgumentException(); 399 } 400 if (!GetDoc()) 401 { 402 throw uno::RuntimeException(); 403 } 404 405 SwUnoInternalPaM aPam(*GetDoc()); 406 if (!::sw::XTextRangeToSwPaM(aPam, xTextRange)) 407 { 408 throw uno::RuntimeException(); 409 } 410 const bool bForceExpandHints(CheckForOwnMemberMeta(aPam, bAbsorb)); 411 412 const SwInsertFlags nInsertFlags = 413 bForceExpandHints 414 ? ( SwInsertFlags::FORCEHINTEXPAND | SwInsertFlags::EMPTYEXPAND) 415 : SwInsertFlags::EMPTYEXPAND; 416 417 if (bAbsorb && aPam.HasMark()) 418 { 419 m_pImpl->m_pDoc->getIDocumentContentOperations().DeleteAndJoin(aPam); 420 aPam.DeleteMark(); 421 } 422 423 sal_Unicode cIns = 0; 424 switch (nControlCharacter) 425 { 426 case text::ControlCharacter::PARAGRAPH_BREAK : 427 // a table cell now becomes an ordinary text cell! 428 m_pImpl->m_pDoc->ClearBoxNumAttrs(aPam.GetPoint()->nNode); 429 m_pImpl->m_pDoc->getIDocumentContentOperations().SplitNode(*aPam.GetPoint(), false); 430 break; 431 case text::ControlCharacter::APPEND_PARAGRAPH: 432 { 433 m_pImpl->m_pDoc->ClearBoxNumAttrs(aPam.GetPoint()->nNode); 434 m_pImpl->m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPam.GetPoint()); 435 436 const uno::Reference<lang::XUnoTunnel> xRangeTunnel( 437 xTextRange, uno::UNO_QUERY); 438 SwXTextRange *const pRange = 439 ::sw::UnoTunnelGetImplementation<SwXTextRange>(xRangeTunnel); 440 OTextCursorHelper *const pCursor = 441 ::sw::UnoTunnelGetImplementation<OTextCursorHelper>( 442 xRangeTunnel); 443 if (pRange) 444 { 445 pRange->SetPositions(aPam); 446 } 447 else if (pCursor) 448 { 449 SwPaM *const pCursorPam = pCursor->GetPaM(); 450 *pCursorPam->GetPoint() = *aPam.GetPoint(); 451 pCursorPam->DeleteMark(); 452 } 453 } 454 break; 455 case text::ControlCharacter::LINE_BREAK: cIns = 10; break; 456 case text::ControlCharacter::SOFT_HYPHEN: cIns = CHAR_SOFTHYPHEN; break; 457 case text::ControlCharacter::HARD_HYPHEN: cIns = CHAR_HARDHYPHEN; break; 458 case text::ControlCharacter::HARD_SPACE: cIns = CHAR_HARDBLANK; break; 459 } 460 if (cIns) 461 { 462 m_pImpl->m_pDoc->getIDocumentContentOperations().InsertString( 463 aPam, OUString(cIns), nInsertFlags); 464 } 465 466 if (bAbsorb) 467 { 468 const uno::Reference<lang::XUnoTunnel> xRangeTunnel( 469 xTextRange, uno::UNO_QUERY); 470 SwXTextRange *const pRange = 471 ::sw::UnoTunnelGetImplementation<SwXTextRange>(xRangeTunnel); 472 OTextCursorHelper *const pCursor = 473 ::sw::UnoTunnelGetImplementation<OTextCursorHelper>(xRangeTunnel); 474 475 SwCursor aCursor(*aPam.GetPoint(), nullptr); 476 SwUnoCursorHelper::SelectPam(aCursor, true); 477 aCursor.Left(1); 478 // here, the PaM needs to be moved: 479 if (pRange) 480 { 481 pRange->SetPositions(aCursor); 482 } 483 else 484 { 485 SwPaM *const pUnoCursor = pCursor->GetPaM(); 486 *pUnoCursor->GetPoint() = *aCursor.GetPoint(); 487 if (aCursor.HasMark()) 488 { 489 pUnoCursor->SetMark(); 490 *pUnoCursor->GetMark() = *aCursor.GetMark(); 491 } 492 else 493 { 494 pUnoCursor->DeleteMark(); 495 } 496 } 497 } 498 } 499 500 void SAL_CALL 501 SwXText::insertTextContent( 502 const uno::Reference< text::XTextRange > & xRange, 503 const uno::Reference< text::XTextContent > & xContent, 504 sal_Bool bAbsorb) 505 { 506 SolarMutexGuard aGuard; 507 comphelper::ProfileZone aZone("SwXText::insertTextContent"); 508 509 if (!xRange.is()) 510 { 511 lang::IllegalArgumentException aIllegal; 512 aIllegal.Message = "first parameter invalid;"; 513 throw aIllegal; 514 } 515 if (!xContent.is()) 516 { 517 lang::IllegalArgumentException aIllegal; 518 aIllegal.Message = "second parameter invalid"; 519 throw aIllegal; 520 } 521 if(!GetDoc()) 522 { 523 uno::RuntimeException aRuntime; 524 aRuntime.Message = cInvalidObject; 525 throw aRuntime; 526 } 527 528 SwUnoInternalPaM aPam(*GetDoc()); 529 if (!::sw::XTextRangeToSwPaM(aPam, xRange)) 530 { 531 lang::IllegalArgumentException aIllegal; 532 aIllegal.Message = "first parameter invalid"; 533 throw aIllegal; 534 } 535 // Any direct formatting ending at the insert position (xRange) should not 536 // be expanded to cover the inserted content (xContent) 537 GetDoc()->DontExpandFormat( *aPam.Start() ); 538 539 // first test if the range is at the right position, then call 540 // xContent->attach 541 const SwStartNode* pOwnStartNode = GetStartNode(); 542 SwStartNodeType eSearchNodeType = SwNormalStartNode; 543 switch (m_pImpl->m_eType) 544 { 545 case CursorType::Frame: eSearchNodeType = SwFlyStartNode; break; 546 case CursorType::TableText: eSearchNodeType = SwTableBoxStartNode; break; 547 case CursorType::Footnote: eSearchNodeType = SwFootnoteStartNode; break; 548 case CursorType::Header: eSearchNodeType = SwHeaderStartNode; break; 549 case CursorType::Footer: eSearchNodeType = SwFooterStartNode; break; 550 //case CURSOR_INVALID: 551 //case CursorType::Body: 552 default: 553 break; 554 } 555 556 const SwStartNode* pTmp = 557 aPam.GetNode().FindSttNodeByType(eSearchNodeType); 558 559 // ignore SectionNodes 560 while (pTmp && pTmp->IsSectionNode()) 561 { 562 pTmp = pTmp->StartOfSectionNode(); 563 } 564 // if the document starts with a section 565 while (pOwnStartNode && pOwnStartNode->IsSectionNode()) 566 { 567 pOwnStartNode = pOwnStartNode->StartOfSectionNode(); 568 } 569 // this checks if (this) and xRange are in the same text::XText interface 570 if (pOwnStartNode != pTmp) 571 { 572 uno::RuntimeException aRunException; 573 aRunException.Message = "text interface and cursor not related"; 574 throw aRunException; 575 } 576 577 const bool bForceExpandHints(CheckForOwnMemberMeta(aPam, bAbsorb)); 578 579 // special treatment for Contents that do not replace the range, but 580 // instead are "overlaid" 581 const uno::Reference<lang::XUnoTunnel> xContentTunnel(xContent, 582 uno::UNO_QUERY); 583 if (!xContentTunnel.is()) 584 { 585 lang::IllegalArgumentException aArgException; 586 aArgException.Message = "text content does not support lang::XUnoTunnel"; 587 throw aArgException; 588 } 589 SwXDocumentIndexMark *const pDocumentIndexMark = 590 ::sw::UnoTunnelGetImplementation<SwXDocumentIndexMark>(xContentTunnel); 591 SwXTextSection *const pSection = 592 ::sw::UnoTunnelGetImplementation<SwXTextSection>(xContentTunnel); 593 SwXBookmark *const pBookmark = 594 ::sw::UnoTunnelGetImplementation<SwXBookmark>(xContentTunnel); 595 SwXReferenceMark *const pReferenceMark = 596 ::sw::UnoTunnelGetImplementation<SwXReferenceMark>(xContentTunnel); 597 SwXMeta *const pMeta = 598 ::sw::UnoTunnelGetImplementation<SwXMeta>(xContentTunnel); 599 SwXTextField* pTextField = 600 ::sw::UnoTunnelGetImplementation<SwXTextField>(xContentTunnel); 601 if (pTextField && pTextField->GetServiceId() != SwServiceType::FieldTypeAnnotation) 602 pTextField = nullptr; 603 604 const bool bAttribute = pBookmark || pDocumentIndexMark 605 || pSection || pReferenceMark || pMeta || pTextField; 606 607 if (bAbsorb && !bAttribute) 608 { 609 xRange->setString(OUString()); 610 } 611 uno::Reference< text::XTextRange > xTempRange = 612 (bAttribute && bAbsorb) ? xRange : xRange->getStart(); 613 if (bForceExpandHints) 614 { 615 // if necessary, replace xTempRange with a new SwXTextCursor 616 PrepareForAttach(xTempRange, aPam); 617 } 618 xContent->attach(xTempRange); 619 } 620 621 void SAL_CALL 622 SwXText::insertTextContentBefore( 623 const uno::Reference< text::XTextContent>& xNewContent, 624 const uno::Reference< text::XTextContent>& xSuccessor) 625 { 626 SolarMutexGuard aGuard; 627 628 if(!GetDoc()) 629 { 630 uno::RuntimeException aRuntime; 631 aRuntime.Message = cInvalidObject; 632 throw aRuntime; 633 } 634 635 const uno::Reference<lang::XUnoTunnel> xParaTunnel(xNewContent, 636 uno::UNO_QUERY); 637 SwXParagraph *const pPara = 638 ::sw::UnoTunnelGetImplementation<SwXParagraph>(xParaTunnel); 639 if (!pPara || !pPara->IsDescriptor() || !xSuccessor.is()) 640 { 641 throw lang::IllegalArgumentException(); 642 } 643 644 bool bRet = false; 645 const uno::Reference<lang::XUnoTunnel> xSuccTunnel(xSuccessor, 646 uno::UNO_QUERY); 647 SwXTextSection *const pXSection = 648 ::sw::UnoTunnelGetImplementation<SwXTextSection>(xSuccTunnel); 649 SwXTextTable *const pXTable = 650 ::sw::UnoTunnelGetImplementation<SwXTextTable>(xSuccTunnel); 651 SwFrameFormat *const pTableFormat = pXTable ? pXTable->GetFrameFormat() : nullptr; 652 SwTextNode * pTextNode = nullptr; 653 if(pTableFormat && pTableFormat->GetDoc() == GetDoc()) 654 { 655 SwTable *const pTable = SwTable::FindTable( pTableFormat ); 656 SwTableNode *const pTableNode = pTable->GetTableNode(); 657 658 const SwNodeIndex aTableIdx( *pTableNode, -1 ); 659 SwPosition aBefore(aTableIdx); 660 bRet = GetDoc()->getIDocumentContentOperations().AppendTextNode( aBefore ); 661 pTextNode = aBefore.nNode.GetNode().GetTextNode(); 662 } 663 else if (pXSection && pXSection->GetFormat() && 664 pXSection->GetFormat()->GetDoc() == GetDoc()) 665 { 666 SwSectionFormat *const pSectFormat = pXSection->GetFormat(); 667 SwSectionNode *const pSectNode = pSectFormat->GetSectionNode(); 668 669 const SwNodeIndex aSectIdx( *pSectNode, -1 ); 670 SwPosition aBefore(aSectIdx); 671 bRet = GetDoc()->getIDocumentContentOperations().AppendTextNode( aBefore ); 672 pTextNode = aBefore.nNode.GetNode().GetTextNode(); 673 } 674 if (!bRet || !pTextNode) 675 { 676 throw lang::IllegalArgumentException(); 677 } 678 pPara->attachToText(*this, *pTextNode); 679 } 680 681 void SAL_CALL 682 SwXText::insertTextContentAfter( 683 const uno::Reference< text::XTextContent>& xNewContent, 684 const uno::Reference< text::XTextContent>& xPredecessor) 685 { 686 SolarMutexGuard aGuard; 687 688 if(!GetDoc()) 689 { 690 throw uno::RuntimeException(); 691 } 692 693 const uno::Reference<lang::XUnoTunnel> xParaTunnel(xNewContent, 694 uno::UNO_QUERY); 695 SwXParagraph *const pPara = 696 ::sw::UnoTunnelGetImplementation<SwXParagraph>(xParaTunnel); 697 if(!pPara || !pPara->IsDescriptor() || !xPredecessor.is()) 698 { 699 throw lang::IllegalArgumentException(); 700 } 701 702 const uno::Reference<lang::XUnoTunnel> xPredTunnel(xPredecessor, 703 uno::UNO_QUERY); 704 SwXTextSection *const pXSection = 705 ::sw::UnoTunnelGetImplementation<SwXTextSection>(xPredTunnel); 706 SwXTextTable *const pXTable = 707 ::sw::UnoTunnelGetImplementation<SwXTextTable>(xPredTunnel); 708 SwFrameFormat *const pTableFormat = pXTable ? pXTable->GetFrameFormat() : nullptr; 709 bool bRet = false; 710 SwTextNode * pTextNode = nullptr; 711 if(pTableFormat && pTableFormat->GetDoc() == GetDoc()) 712 { 713 SwTable *const pTable = SwTable::FindTable( pTableFormat ); 714 SwTableNode *const pTableNode = pTable->GetTableNode(); 715 716 SwEndNode *const pTableEnd = pTableNode->EndOfSectionNode(); 717 SwPosition aTableEnd(*pTableEnd); 718 bRet = GetDoc()->getIDocumentContentOperations().AppendTextNode( aTableEnd ); 719 pTextNode = aTableEnd.nNode.GetNode().GetTextNode(); 720 } 721 else if (pXSection && pXSection->GetFormat() && 722 pXSection->GetFormat()->GetDoc() == GetDoc()) 723 { 724 SwSectionFormat *const pSectFormat = pXSection->GetFormat(); 725 SwSectionNode *const pSectNode = pSectFormat->GetSectionNode(); 726 SwEndNode *const pEnd = pSectNode->EndOfSectionNode(); 727 SwPosition aEnd(*pEnd); 728 bRet = GetDoc()->getIDocumentContentOperations().AppendTextNode( aEnd ); 729 pTextNode = aEnd.nNode.GetNode().GetTextNode(); 730 } 731 if (!bRet || !pTextNode) 732 { 733 throw lang::IllegalArgumentException(); 734 } 735 pPara->attachToText(*this, *pTextNode); 736 } 737 738 void SAL_CALL 739 SwXText::removeTextContentBefore( 740 const uno::Reference< text::XTextContent>& xSuccessor) 741 { 742 SolarMutexGuard aGuard; 743 744 if(!GetDoc()) 745 { 746 uno::RuntimeException aRuntime; 747 aRuntime.Message = cInvalidObject; 748 throw aRuntime; 749 } 750 751 bool bRet = false; 752 const uno::Reference<lang::XUnoTunnel> xSuccTunnel(xSuccessor, 753 uno::UNO_QUERY); 754 SwXTextSection *const pXSection = 755 ::sw::UnoTunnelGetImplementation<SwXTextSection>(xSuccTunnel); 756 SwXTextTable *const pXTable = 757 ::sw::UnoTunnelGetImplementation<SwXTextTable>(xSuccTunnel); 758 SwFrameFormat *const pTableFormat = pXTable ? pXTable->GetFrameFormat() : nullptr; 759 if(pTableFormat && pTableFormat->GetDoc() == GetDoc()) 760 { 761 SwTable *const pTable = SwTable::FindTable( pTableFormat ); 762 SwTableNode *const pTableNode = pTable->GetTableNode(); 763 764 const SwNodeIndex aTableIdx( *pTableNode, -1 ); 765 if(aTableIdx.GetNode().IsTextNode()) 766 { 767 SwPaM aBefore(aTableIdx); 768 bRet = GetDoc()->getIDocumentContentOperations().DelFullPara( aBefore ); 769 } 770 } 771 else if (pXSection && pXSection->GetFormat() && 772 pXSection->GetFormat()->GetDoc() == GetDoc()) 773 { 774 SwSectionFormat *const pSectFormat = pXSection->GetFormat(); 775 SwSectionNode *const pSectNode = pSectFormat->GetSectionNode(); 776 777 const SwNodeIndex aSectIdx( *pSectNode, -1 ); 778 if(aSectIdx.GetNode().IsTextNode()) 779 { 780 SwPaM aBefore(aSectIdx); 781 bRet = GetDoc()->getIDocumentContentOperations().DelFullPara( aBefore ); 782 } 783 } 784 if(!bRet) 785 { 786 throw lang::IllegalArgumentException(); 787 } 788 } 789 790 void SAL_CALL 791 SwXText::removeTextContentAfter( 792 const uno::Reference< text::XTextContent>& xPredecessor) 793 { 794 SolarMutexGuard aGuard; 795 796 if(!GetDoc()) 797 { 798 uno::RuntimeException aRuntime; 799 aRuntime.Message = cInvalidObject; 800 throw aRuntime; 801 } 802 803 bool bRet = false; 804 const uno::Reference<lang::XUnoTunnel> xPredTunnel(xPredecessor, 805 uno::UNO_QUERY); 806 SwXTextSection *const pXSection = 807 ::sw::UnoTunnelGetImplementation<SwXTextSection>(xPredTunnel); 808 SwXTextTable *const pXTable = 809 ::sw::UnoTunnelGetImplementation<SwXTextTable>(xPredTunnel); 810 SwFrameFormat *const pTableFormat = pXTable ? pXTable->GetFrameFormat() : nullptr; 811 if(pTableFormat && pTableFormat->GetDoc() == GetDoc()) 812 { 813 SwTable *const pTable = SwTable::FindTable( pTableFormat ); 814 SwTableNode *const pTableNode = pTable->GetTableNode(); 815 SwEndNode *const pTableEnd = pTableNode->EndOfSectionNode(); 816 817 const SwNodeIndex aTableIdx( *pTableEnd, 1 ); 818 if(aTableIdx.GetNode().IsTextNode()) 819 { 820 SwPaM aPaM(aTableIdx); 821 bRet = GetDoc()->getIDocumentContentOperations().DelFullPara( aPaM ); 822 } 823 } 824 else if (pXSection && pXSection->GetFormat() && 825 pXSection->GetFormat()->GetDoc() == GetDoc()) 826 { 827 SwSectionFormat *const pSectFormat = pXSection->GetFormat(); 828 SwSectionNode *const pSectNode = pSectFormat->GetSectionNode(); 829 SwEndNode *const pEnd = pSectNode->EndOfSectionNode(); 830 const SwNodeIndex aSectIdx( *pEnd, 1 ); 831 if(aSectIdx.GetNode().IsTextNode()) 832 { 833 SwPaM aAfter(aSectIdx); 834 bRet = GetDoc()->getIDocumentContentOperations().DelFullPara( aAfter ); 835 } 836 } 837 if(!bRet) 838 { 839 throw lang::IllegalArgumentException(); 840 } 841 } 842 843 void SAL_CALL 844 SwXText::removeTextContent( 845 const uno::Reference< text::XTextContent > & xContent) 846 { 847 // forward: need no solar mutex here 848 if(!xContent.is()) 849 { 850 uno::RuntimeException aRuntime; 851 aRuntime.Message = "first parameter invalid"; 852 throw aRuntime; 853 } 854 xContent->dispose(); 855 } 856 857 uno::Reference< text::XText > SAL_CALL 858 SwXText::getText() 859 { 860 SolarMutexGuard aGuard; 861 comphelper::ProfileZone aZone("SwXText::getText"); 862 863 const uno::Reference< text::XText > xRet(this); 864 return xRet; 865 } 866 867 uno::Reference< text::XTextRange > SAL_CALL 868 SwXText::getStart() 869 { 870 SolarMutexGuard aGuard; 871 872 const uno::Reference< text::XTextCursor > xRef = CreateCursor(); 873 if(!xRef.is()) 874 { 875 uno::RuntimeException aRuntime; 876 aRuntime.Message = cInvalidObject; 877 throw aRuntime; 878 } 879 xRef->gotoStart(false); 880 const uno::Reference< text::XTextRange > xRet(xRef, uno::UNO_QUERY); 881 return xRet; 882 } 883 884 uno::Reference< text::XTextRange > SAL_CALL 885 SwXText::getEnd() 886 { 887 SolarMutexGuard aGuard; 888 889 const uno::Reference< text::XTextCursor > xRef = CreateCursor(); 890 if(!xRef.is()) 891 { 892 uno::RuntimeException aRuntime; 893 aRuntime.Message = cInvalidObject; 894 throw aRuntime; 895 } 896 xRef->gotoEnd(false); 897 const uno::Reference< text::XTextRange > xRet(xRef, uno::UNO_QUERY); 898 return xRet; 899 } 900 901 OUString SAL_CALL SwXText::getString() 902 { 903 SolarMutexGuard aGuard; 904 905 const uno::Reference< text::XTextCursor > xRet = CreateCursor(); 906 if(!xRet.is()) 907 { 908 SAL_WARN("sw.uno", "cursor was not created in getString() call. Returning empty string."); 909 return OUString(); 910 } 911 xRet->gotoEnd(true); 912 return xRet->getString(); 913 } 914 915 void SAL_CALL 916 SwXText::setString(const OUString& rString) 917 { 918 SolarMutexGuard aGuard; 919 920 if (!GetDoc()) 921 { 922 uno::RuntimeException aRuntime; 923 aRuntime.Message = cInvalidObject; 924 throw aRuntime; 925 } 926 927 const SwStartNode* pStartNode = GetStartNode(); 928 if (!pStartNode) 929 { 930 throw uno::RuntimeException(); 931 } 932 933 GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::START, nullptr); 934 //insert an empty paragraph at the start and at the end to ensure that 935 //all tables and sections can be removed by the selecting text::XTextCursor 936 if (CursorType::Meta != m_pImpl->m_eType) 937 { 938 SwPosition aStartPos(*pStartNode); 939 const SwEndNode* pEnd = pStartNode->EndOfSectionNode(); 940 SwNodeIndex aEndIdx(*pEnd); 941 --aEndIdx; 942 //the inserting of nodes should only be done if really necessary 943 //to prevent #97924# (removes paragraph attributes when setting the text 944 //e.g. of a table cell 945 bool bInsertNodes = false; 946 SwNodeIndex aStartIdx(*pStartNode); 947 do 948 { 949 ++aStartIdx; 950 SwNode& rCurrentNode = aStartIdx.GetNode(); 951 if(rCurrentNode.GetNodeType() == SwNodeType::Section 952 ||rCurrentNode.GetNodeType() == SwNodeType::Table) 953 { 954 bInsertNodes = true; 955 break; 956 } 957 } 958 while(aStartIdx < aEndIdx); 959 if(bInsertNodes) 960 { 961 GetDoc()->getIDocumentContentOperations().AppendTextNode( aStartPos ); 962 SwPosition aEndPos(aEndIdx.GetNode()); 963 SwPaM aPam(aEndPos); 964 GetDoc()->getIDocumentContentOperations().AppendTextNode( *aPam.Start() ); 965 } 966 } 967 968 const uno::Reference< text::XTextCursor > xRet = CreateCursor(); 969 if(!xRet.is()) 970 { 971 GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::END, nullptr); 972 uno::RuntimeException aRuntime; 973 aRuntime.Message = cInvalidObject; 974 throw aRuntime; 975 } 976 xRet->gotoEnd(true); 977 xRet->setString(rString); 978 GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::END, nullptr); 979 } 980 981 //FIXME why is CheckForOwnMember duplicated in some insert methods? 982 // Description: Checks if pRange/pCursor are member of the same text interface. 983 // Only one of the pointers has to be set! 984 bool SwXText::Impl::CheckForOwnMember( 985 const SwPaM & rPaM) 986 { 987 const uno::Reference<text::XTextCursor> xOwnCursor(m_rThis.CreateCursor()); 988 989 const uno::Reference<lang::XUnoTunnel> xTunnel(xOwnCursor, uno::UNO_QUERY); 990 OTextCursorHelper *const pOwnCursor = 991 ::sw::UnoTunnelGetImplementation<OTextCursorHelper>(xTunnel); 992 OSL_ENSURE(pOwnCursor, "OTextCursorHelper::getUnoTunnelId() ??? "); 993 const SwStartNode* pOwnStartNode = 994 pOwnCursor->GetPaM()->GetNode().StartOfSectionNode(); 995 SwStartNodeType eSearchNodeType = SwNormalStartNode; 996 switch (m_eType) 997 { 998 case CursorType::Frame: eSearchNodeType = SwFlyStartNode; break; 999 case CursorType::TableText: eSearchNodeType = SwTableBoxStartNode; break; 1000 case CursorType::Footnote: eSearchNodeType = SwFootnoteStartNode; break; 1001 case CursorType::Header: eSearchNodeType = SwHeaderStartNode; break; 1002 case CursorType::Footer: eSearchNodeType = SwFooterStartNode; break; 1003 //case CURSOR_INVALID: 1004 //case CursorType::Body: 1005 default: 1006 ; 1007 } 1008 1009 const SwNode& rSrcNode = rPaM.GetNode(); 1010 const SwStartNode* pTmp = rSrcNode.FindSttNodeByType(eSearchNodeType); 1011 1012 // skip SectionNodes 1013 while(pTmp && pTmp->IsSectionNode()) 1014 { 1015 pTmp = pTmp->StartOfSectionNode(); 1016 } 1017 1018 //if the document starts with a section 1019 while(pOwnStartNode->IsSectionNode()) 1020 { 1021 pOwnStartNode = pOwnStartNode->StartOfSectionNode(); 1022 } 1023 1024 //this checks if (this) and xRange are in the same text::XText interface 1025 return (pOwnStartNode == pTmp); 1026 } 1027 1028 sal_Int16 1029 SwXText::Impl::ComparePositions( 1030 const uno::Reference<text::XTextRange>& xPos1, 1031 const uno::Reference<text::XTextRange>& xPos2) 1032 { 1033 SwUnoInternalPaM aPam1(*m_pDoc); 1034 SwUnoInternalPaM aPam2(*m_pDoc); 1035 1036 if (!::sw::XTextRangeToSwPaM(aPam1, xPos1) || 1037 !::sw::XTextRangeToSwPaM(aPam2, xPos2)) 1038 { 1039 throw lang::IllegalArgumentException(); 1040 } 1041 if (!CheckForOwnMember(aPam1) || !CheckForOwnMember(aPam2)) 1042 { 1043 throw lang::IllegalArgumentException(); 1044 } 1045 1046 sal_Int16 nCompare = 0; 1047 SwPosition const*const pStart1 = aPam1.Start(); 1048 SwPosition const*const pStart2 = aPam2.Start(); 1049 if (*pStart1 < *pStart2) 1050 { 1051 nCompare = 1; 1052 } 1053 else if (*pStart1 > *pStart2) 1054 { 1055 nCompare = -1; 1056 } 1057 else 1058 { 1059 OSL_ENSURE(*pStart1 == *pStart2, 1060 "SwPositions should be equal here"); 1061 nCompare = 0; 1062 } 1063 1064 return nCompare; 1065 } 1066 1067 sal_Int16 SAL_CALL 1068 SwXText::compareRegionStarts( 1069 const uno::Reference<text::XTextRange>& xRange1, 1070 const uno::Reference<text::XTextRange>& xRange2) 1071 { 1072 SolarMutexGuard aGuard; 1073 1074 if (!xRange1.is() || !xRange2.is()) 1075 { 1076 throw lang::IllegalArgumentException(); 1077 } 1078 const uno::Reference<text::XTextRange> xStart1 = xRange1->getStart(); 1079 const uno::Reference<text::XTextRange> xStart2 = xRange2->getStart(); 1080 1081 return m_pImpl->ComparePositions(xStart1, xStart2); 1082 } 1083 1084 sal_Int16 SAL_CALL 1085 SwXText::compareRegionEnds( 1086 const uno::Reference<text::XTextRange>& xRange1, 1087 const uno::Reference<text::XTextRange>& xRange2) 1088 { 1089 SolarMutexGuard aGuard; 1090 1091 if (!xRange1.is() || !xRange2.is()) 1092 { 1093 throw lang::IllegalArgumentException(); 1094 } 1095 uno::Reference<text::XTextRange> xEnd1 = xRange1->getEnd(); 1096 uno::Reference<text::XTextRange> xEnd2 = xRange2->getEnd(); 1097 1098 return m_pImpl->ComparePositions(xEnd1, xEnd2); 1099 } 1100 1101 uno::Reference< beans::XPropertySetInfo > SAL_CALL 1102 SwXText::getPropertySetInfo() 1103 { 1104 SolarMutexGuard g; 1105 1106 static uno::Reference< beans::XPropertySetInfo > xInfo = 1107 m_pImpl->m_rPropSet.getPropertySetInfo(); 1108 return xInfo; 1109 } 1110 1111 void SAL_CALL 1112 SwXText::setPropertyValue(const OUString& /*aPropertyName*/, 1113 const uno::Any& /*aValue*/) 1114 { 1115 throw lang::IllegalArgumentException(); 1116 } 1117 1118 uno::Any SAL_CALL 1119 SwXText::getPropertyValue( 1120 const OUString& rPropertyName) 1121 { 1122 SolarMutexGuard aGuard; 1123 1124 if(!IsValid()) 1125 { 1126 throw uno::RuntimeException(); 1127 } 1128 1129 SfxItemPropertySimpleEntry const*const pEntry = 1130 m_pImpl->m_rPropSet.getPropertyMap().getByName(rPropertyName); 1131 if (!pEntry) 1132 { 1133 beans::UnknownPropertyException aExcept; 1134 aExcept.Message = "Unknown property: " + rPropertyName; 1135 throw aExcept; 1136 } 1137 1138 uno::Any aRet; 1139 switch (pEntry->nWID) 1140 { 1141 // no code necessary - the redline is always located at the end node 1142 // case FN_UNO_REDLINE_NODE_START: 1143 // break; 1144 case FN_UNO_REDLINE_NODE_END: 1145 { 1146 const SwRedlineTable& rRedTable = GetDoc()->getIDocumentRedlineAccess().GetRedlineTable(); 1147 const size_t nRedTableCount = rRedTable.size(); 1148 if (nRedTableCount > 0) 1149 { 1150 SwStartNode const*const pStartNode = GetStartNode(); 1151 const sal_uLong nOwnIndex = pStartNode->EndOfSectionIndex(); 1152 for (size_t nRed = 0; nRed < nRedTableCount; ++nRed) 1153 { 1154 SwRangeRedline const*const pRedline = rRedTable[nRed]; 1155 SwPosition const*const pRedStart = pRedline->Start(); 1156 const SwNodeIndex nRedNode = pRedStart->nNode; 1157 if (nOwnIndex == nRedNode.GetIndex()) 1158 { 1159 aRet <<= SwXRedlinePortion::CreateRedlineProperties( 1160 *pRedline, true); 1161 break; 1162 } 1163 } 1164 } 1165 } 1166 break; 1167 } 1168 return aRet; 1169 } 1170 1171 void SAL_CALL 1172 SwXText::addPropertyChangeListener( 1173 const OUString& /*rPropertyName*/, 1174 const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) 1175 { 1176 OSL_FAIL("SwXText::addPropertyChangeListener(): not implemented"); 1177 } 1178 1179 void SAL_CALL 1180 SwXText::removePropertyChangeListener( 1181 const OUString& /*rPropertyName*/, 1182 const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) 1183 { 1184 OSL_FAIL("SwXText::removePropertyChangeListener(): not implemented"); 1185 } 1186 1187 void SAL_CALL 1188 SwXText::addVetoableChangeListener( 1189 const OUString& /*rPropertyName*/, 1190 const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) 1191 { 1192 OSL_FAIL("SwXText::addVetoableChangeListener(): not implemented"); 1193 } 1194 1195 void SAL_CALL 1196 SwXText::removeVetoableChangeListener( 1197 const OUString& /*rPropertyName*/, 1198 const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) 1199 { 1200 OSL_FAIL("SwXText::removeVetoableChangeListener(): not implemented"); 1201 } 1202 1203 namespace 1204 { 1205 class theSwXTextUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theSwXTextUnoTunnelId > {}; 1206 } 1207 1208 const uno::Sequence< sal_Int8 > & SwXText::getUnoTunnelId() 1209 { 1210 return theSwXTextUnoTunnelId::get().getSeq(); 1211 } 1212 1213 sal_Int64 SAL_CALL 1214 SwXText::getSomething(const uno::Sequence< sal_Int8 >& rId) 1215 { 1216 return ::sw::UnoTunnelImpl<SwXText>(rId, this); 1217 } 1218 1219 uno::Reference< text::XTextRange > SAL_CALL 1220 SwXText::finishParagraph( 1221 const uno::Sequence< beans::PropertyValue > & rProperties) 1222 { 1223 SolarMutexGuard g; 1224 1225 return m_pImpl->finishOrAppendParagraph(rProperties, uno::Reference< text::XTextRange >()); 1226 } 1227 1228 uno::Reference< text::XTextRange > SAL_CALL 1229 SwXText::finishParagraphInsert( 1230 const uno::Sequence< beans::PropertyValue > & rProperties, 1231 const uno::Reference< text::XTextRange >& xInsertPosition) 1232 { 1233 SolarMutexGuard g; 1234 1235 return m_pImpl->finishOrAppendParagraph(rProperties, xInsertPosition); 1236 } 1237 1238 uno::Reference< text::XTextRange > 1239 SwXText::Impl::finishOrAppendParagraph( 1240 const uno::Sequence< beans::PropertyValue > & rProperties, 1241 const uno::Reference< text::XTextRange >& xInsertPosition) 1242 { 1243 if (!m_bIsValid) 1244 { 1245 throw uno::RuntimeException(); 1246 } 1247 1248 const SwStartNode* pStartNode = m_rThis.GetStartNode(); 1249 if(!pStartNode) 1250 { 1251 throw uno::RuntimeException(); 1252 } 1253 1254 uno::Reference< text::XTextRange > xRet; 1255 bool bIllegalException = false; 1256 bool bRuntimeException = false; 1257 OUString sMessage; 1258 m_pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::START , nullptr); 1259 // find end node, go backward - don't skip tables because the new 1260 // paragraph has to be the last node 1261 //aPam.Move( fnMoveBackward, GoInNode ); 1262 SwPosition aInsertPosition( 1263 SwNodeIndex( *pStartNode->EndOfSectionNode(), -1 ) ); 1264 SwPaM aPam(aInsertPosition); 1265 // If we got a position reference, then the insert point is not the end of 1266 // the document. 1267 if (xInsertPosition.is()) 1268 { 1269 SwUnoInternalPaM aStartPam(*m_rThis.GetDoc()); 1270 ::sw::XTextRangeToSwPaM(aStartPam, xInsertPosition); 1271 aPam = aStartPam; 1272 aPam.SetMark(); 1273 } 1274 m_pDoc->getIDocumentContentOperations().AppendTextNode( *aPam.GetPoint() ); 1275 // remove attributes from the previous paragraph 1276 m_pDoc->ResetAttrs(aPam); 1277 // in case of finishParagraph the PaM needs to be moved to the 1278 // previous paragraph 1279 aPam.Move( fnMoveBackward, GoInNode ); 1280 1281 try 1282 { 1283 SfxItemPropertySet const*const pParaPropSet = 1284 aSwMapProvider.GetPropertySet(PROPERTY_MAP_PARAGRAPH); 1285 1286 SwUnoCursorHelper::SetPropertyValues(aPam, *pParaPropSet, rProperties); 1287 } 1288 catch (const lang::IllegalArgumentException& rIllegal) 1289 { 1290 sMessage = rIllegal.Message; 1291 bIllegalException = true; 1292 } 1293 catch (const uno::RuntimeException& rRuntime) 1294 { 1295 sMessage = rRuntime.Message; 1296 bRuntimeException = true; 1297 } 1298 catch (const uno::Exception& rEx) 1299 { 1300 sMessage = rEx.Message; 1301 bRuntimeException = true; 1302 } 1303 1304 m_pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::END, nullptr); 1305 if (bIllegalException || bRuntimeException) 1306 { 1307 m_pDoc->GetIDocumentUndoRedo().Undo(); 1308 if (bIllegalException) 1309 { 1310 lang::IllegalArgumentException aEx; 1311 aEx.Message = sMessage; 1312 throw aEx; 1313 } 1314 else 1315 { 1316 uno::RuntimeException aEx; 1317 aEx.Message = sMessage; 1318 throw aEx; 1319 } 1320 } 1321 SwTextNode *const pTextNode( aPam.Start()->nNode.GetNode().GetTextNode() ); 1322 OSL_ENSURE(pTextNode, "no SwTextNode?"); 1323 if (pTextNode) 1324 { 1325 xRet.set(SwXParagraph::CreateXParagraph(*m_pDoc, pTextNode, &m_rThis), 1326 uno::UNO_QUERY); 1327 } 1328 1329 return xRet; 1330 } 1331 1332 uno::Reference< text::XTextRange > SAL_CALL 1333 SwXText::insertTextPortion( 1334 const OUString& rText, 1335 const uno::Sequence< beans::PropertyValue > & 1336 rCharacterAndParagraphProperties, 1337 const uno::Reference<text::XTextRange>& xInsertPosition) 1338 { 1339 SolarMutexGuard aGuard; 1340 1341 if(!IsValid()) 1342 { 1343 throw uno::RuntimeException(); 1344 } 1345 uno::Reference< text::XTextRange > xRet; 1346 const uno::Reference< text::XTextCursor > xTextCursor = CreateCursor(); 1347 xTextCursor->gotoRange(xInsertPosition, false); 1348 1349 const uno::Reference< lang::XUnoTunnel > xRangeTunnel( 1350 xTextCursor, uno::UNO_QUERY_THROW ); 1351 SwXTextCursor *const pTextCursor = 1352 ::sw::UnoTunnelGetImplementation<SwXTextCursor>(xRangeTunnel); 1353 1354 bool bIllegalException = false; 1355 bool bRuntimeException = false; 1356 OUString sMessage; 1357 m_pImpl->m_pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT, nullptr); 1358 1359 auto& rCursor(pTextCursor->GetCursor()); 1360 m_pImpl->m_pDoc->DontExpandFormat( *rCursor.Start() ); 1361 1362 if (!rText.isEmpty()) 1363 { 1364 SwNodeIndex const nodeIndex(rCursor.GetPoint()->nNode, -1); 1365 const sal_Int32 nContentPos = rCursor.GetPoint()->nContent.GetIndex(); 1366 SwUnoCursorHelper::DocInsertStringSplitCR( 1367 *m_pImpl->m_pDoc, rCursor, rText, false); 1368 SwUnoCursorHelper::SelectPam(rCursor, true); 1369 rCursor.GetPoint()->nNode.Assign(nodeIndex.GetNode(), +1); 1370 rCursor.GetPoint()->nContent = nContentPos; 1371 } 1372 1373 try 1374 { 1375 SfxItemPropertySet const*const pCursorPropSet = 1376 aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_CURSOR); 1377 SwUnoCursorHelper::SetPropertyValues(rCursor, *pCursorPropSet, 1378 rCharacterAndParagraphProperties, 1379 SetAttrMode::NOFORMATATTR); 1380 } 1381 catch (const lang::IllegalArgumentException& rIllegal) 1382 { 1383 sMessage = rIllegal.Message; 1384 bIllegalException = true; 1385 } 1386 catch (const uno::RuntimeException& rRuntime) 1387 { 1388 sMessage = rRuntime.Message; 1389 bRuntimeException = true; 1390 } 1391 m_pImpl->m_pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT, nullptr); 1392 if (bIllegalException || bRuntimeException) 1393 { 1394 m_pImpl->m_pDoc->GetIDocumentUndoRedo().Undo(); 1395 if (bIllegalException) 1396 { 1397 lang::IllegalArgumentException aEx; 1398 aEx.Message = sMessage; 1399 throw aEx; 1400 } 1401 else 1402 { 1403 uno::RuntimeException aEx; 1404 aEx.Message = sMessage; 1405 throw aEx; 1406 } 1407 } 1408 xRet = new SwXTextRange(rCursor, this); 1409 return xRet; 1410 } 1411 1412 // Append text portions at the end of the last paragraph of the text interface. 1413 // Support of import filters. 1414 uno::Reference< text::XTextRange > SAL_CALL 1415 SwXText::appendTextPortion( 1416 const OUString& rText, 1417 const uno::Sequence< beans::PropertyValue > & 1418 rCharacterAndParagraphProperties) 1419 { 1420 // Right now this doesn't need a guard, as it's just calling the insert 1421 // version, that has it already. 1422 uno::Reference<text::XTextRange> xInsertPosition = getEnd(); 1423 return insertTextPortion(rText, rCharacterAndParagraphProperties, xInsertPosition); 1424 } 1425 1426 // enable inserting/appending text contents like graphic objects, shapes and so on to 1427 // support import filters 1428 uno::Reference< text::XTextRange > SAL_CALL 1429 SwXText::insertTextContentWithProperties( 1430 const uno::Reference< text::XTextContent >& xTextContent, 1431 const uno::Sequence< beans::PropertyValue >& 1432 rCharacterAndParagraphProperties, 1433 const uno::Reference< text::XTextRange >& xInsertPosition) 1434 { 1435 SolarMutexGuard aGuard; 1436 1437 if (!IsValid()) 1438 { 1439 throw uno::RuntimeException(); 1440 } 1441 1442 m_pImpl->m_pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT, nullptr); 1443 1444 // now attach the text content here 1445 insertTextContent( xInsertPosition, xTextContent, false ); 1446 // now apply the properties to the anchor 1447 if (rCharacterAndParagraphProperties.hasElements()) 1448 { 1449 try 1450 { 1451 const sal_Int32 nLen(rCharacterAndParagraphProperties.getLength()); 1452 const uno::Reference< beans::XPropertySet > xAnchor( 1453 xTextContent->getAnchor(), uno::UNO_QUERY); 1454 if (xAnchor.is()) 1455 { 1456 for (sal_Int32 nElement = 0; nElement < nLen; ++nElement) 1457 { 1458 xAnchor->setPropertyValue( 1459 rCharacterAndParagraphProperties[nElement].Name, 1460 rCharacterAndParagraphProperties[nElement].Value); 1461 } 1462 } 1463 } 1464 catch (const uno::Exception& e) 1465 { 1466 css::uno::Any anyEx = cppu::getCaughtException(); 1467 m_pImpl->m_pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT, nullptr); 1468 throw lang::WrappedTargetRuntimeException( e.Message, 1469 uno::Reference< uno::XInterface >(), anyEx ); 1470 } 1471 } 1472 m_pImpl->m_pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT, nullptr); 1473 return xInsertPosition; 1474 } 1475 1476 uno::Reference< text::XTextRange > SAL_CALL 1477 SwXText::appendTextContent( 1478 const uno::Reference< text::XTextContent >& xTextContent, 1479 const uno::Sequence< beans::PropertyValue >& 1480 rCharacterAndParagraphProperties) 1481 { 1482 // Right now this doesn't need a guard, as it's just calling the insert 1483 // version, that has it already. 1484 uno::Reference<text::XTextRange> xInsertPosition = getEnd(); 1485 return insertTextContentWithProperties(xTextContent, rCharacterAndParagraphProperties, xInsertPosition); 1486 } 1487 1488 // determine wether SwFrameFormat is a graphic node 1489 static bool isGraphicNode(const SwFrameFormat* pFrameFormat) 1490 { 1491 // safety 1492 if( !pFrameFormat->GetContent().GetContentIdx() ) 1493 { 1494 return false; 1495 } 1496 auto index = *pFrameFormat->GetContent().GetContentIdx(); 1497 // consider the next node -> there is the graphic stored 1498 index++; 1499 return index.GetNode().IsGrfNode(); 1500 } 1501 1502 // move previously appended paragraphs into a text frames 1503 // to support import filters 1504 uno::Reference< text::XTextContent > SAL_CALL 1505 SwXText::convertToTextFrame( 1506 const uno::Reference< text::XTextRange >& xStart, 1507 const uno::Reference< text::XTextRange >& xEnd, 1508 const uno::Sequence< beans::PropertyValue >& rFrameProperties) 1509 { 1510 SolarMutexGuard aGuard; 1511 1512 if(!IsValid()) 1513 { 1514 throw uno::RuntimeException(); 1515 } 1516 uno::Reference< text::XTextContent > xRet; 1517 SwUnoInternalPaM aStartPam(*GetDoc()); 1518 std::unique_ptr< SwUnoInternalPaM > pEndPam(new SwUnoInternalPaM(*GetDoc())); 1519 if (!::sw::XTextRangeToSwPaM(aStartPam, xStart) || 1520 !::sw::XTextRangeToSwPaM(*pEndPam, xEnd)) 1521 { 1522 throw lang::IllegalArgumentException(); 1523 } 1524 1525 const uno::Reference<lang::XUnoTunnel> xStartRangeTunnel(xStart, 1526 uno::UNO_QUERY); 1527 SwXTextRange *const pStartRange = 1528 ::sw::UnoTunnelGetImplementation<SwXTextRange>(xStartRangeTunnel); 1529 const uno::Reference<lang::XUnoTunnel> xEndRangeTunnel(xEnd, 1530 uno::UNO_QUERY); 1531 SwXTextRange *const pEndRange = 1532 ::sw::UnoTunnelGetImplementation<SwXTextRange>(xEndRangeTunnel); 1533 // bookmarks have to be removed before the referenced text node 1534 // is deleted in DelFullPara 1535 if (pStartRange) 1536 { 1537 pStartRange->Invalidate(); 1538 } 1539 if (pEndRange) 1540 { 1541 pEndRange->Invalidate(); 1542 } 1543 1544 m_pImpl->m_pDoc->GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr ); 1545 bool bIllegalException = false; 1546 bool bRuntimeException = false; 1547 OUString sMessage; 1548 SwStartNode* pStartStartNode = aStartPam.GetNode().StartOfSectionNode(); 1549 while (pStartStartNode && pStartStartNode->IsSectionNode()) 1550 { 1551 pStartStartNode = pStartStartNode->StartOfSectionNode(); 1552 } 1553 SwStartNode* pEndStartNode = pEndPam->GetNode().StartOfSectionNode(); 1554 while (pEndStartNode && pEndStartNode->IsSectionNode()) 1555 { 1556 pEndStartNode = pEndStartNode->StartOfSectionNode(); 1557 } 1558 bool bParaAfterInserted = false; 1559 bool bParaBeforeInserted = false; 1560 if ( 1561 pStartStartNode && pEndStartNode && 1562 (pStartStartNode != pEndStartNode || pStartStartNode != GetStartNode()) 1563 ) 1564 { 1565 // todo: if the start/end is in a table then insert a paragraph 1566 // before/after, move the start/end nodes, then convert and 1567 // remove the additional paragraphs in the end 1568 SwTableNode * pStartTableNode(nullptr); 1569 if (pStartStartNode->GetStartNodeType() == SwTableBoxStartNode) 1570 { 1571 pStartTableNode = pStartStartNode->FindTableNode(); 1572 // Is it the same table start node than the end? 1573 SwTableNode *const pEndStartTableNode(pEndStartNode->FindTableNode()); 1574 while (pEndStartTableNode && pStartTableNode && 1575 pEndStartTableNode->GetIndex() < pStartTableNode->GetIndex()) 1576 { 1577 SwStartNode* pStartStartTableNode = pStartTableNode->StartOfSectionNode(); 1578 pStartTableNode = pStartStartTableNode->FindTableNode(); 1579 } 1580 } 1581 if (pStartTableNode) 1582 { 1583 const SwNodeIndex aTableIdx( *pStartTableNode, -1 ); 1584 SwPosition aBefore(aTableIdx); 1585 bParaBeforeInserted = GetDoc()->getIDocumentContentOperations().AppendTextNode( aBefore ); 1586 aStartPam.DeleteMark(); 1587 *aStartPam.GetPoint() = aBefore; 1588 pStartStartNode = aStartPam.GetNode().StartOfSectionNode(); 1589 } 1590 if (pEndStartNode->GetStartNodeType() == SwTableBoxStartNode) 1591 { 1592 SwTableNode *const pEndTableNode = pEndStartNode->FindTableNode(); 1593 SwEndNode *const pTableEnd = pEndTableNode->EndOfSectionNode(); 1594 SwPosition aTableEnd(*pTableEnd); 1595 bParaAfterInserted = GetDoc()->getIDocumentContentOperations().AppendTextNode( aTableEnd ); 1596 pEndPam->DeleteMark(); 1597 *pEndPam->GetPoint() = aTableEnd; 1598 pEndStartNode = pEndPam->GetNode().StartOfSectionNode(); 1599 } 1600 // now we should have the positions in the same hierarchy 1601 if ((pStartStartNode != pEndStartNode) || 1602 (pStartStartNode != GetStartNode())) 1603 { 1604 // if not - remove the additional paragraphs and throw 1605 if (bParaBeforeInserted) 1606 { 1607 SwCursor aDelete(*aStartPam.GetPoint(), nullptr); 1608 *aStartPam.GetPoint() = // park it because node is deleted 1609 SwPosition(GetDoc()->GetNodes().GetEndOfContent()); 1610 aDelete.MovePara(GoCurrPara, fnParaStart); 1611 aDelete.SetMark(); 1612 aDelete.MovePara(GoCurrPara, fnParaEnd); 1613 GetDoc()->getIDocumentContentOperations().DelFullPara(aDelete); 1614 } 1615 if (bParaAfterInserted) 1616 { 1617 SwCursor aDelete(*pEndPam->GetPoint(), nullptr); 1618 *pEndPam->GetPoint() = // park it because node is deleted 1619 SwPosition(GetDoc()->GetNodes().GetEndOfContent()); 1620 aDelete.MovePara(GoCurrPara, fnParaStart); 1621 aDelete.SetMark(); 1622 aDelete.MovePara(GoCurrPara, fnParaEnd); 1623 GetDoc()->getIDocumentContentOperations().DelFullPara(aDelete); 1624 } 1625 throw lang::IllegalArgumentException(); 1626 } 1627 } 1628 1629 // make a selection from aStartPam to a EndPam 1630 // If there is no content in the frame the shape is in 1631 // it gets deleted in the DelFullPara call below, 1632 // In this case insert a tmp text node ( we delete it later ) 1633 if ( aStartPam.Start()->nNode == pEndPam->Start()->nNode 1634 && aStartPam.End()->nNode == pEndPam->End()->nNode ) 1635 { 1636 SwPosition aEnd(*aStartPam.End()); 1637 bParaAfterInserted = GetDoc()->getIDocumentContentOperations().AppendTextNode( aEnd ); 1638 pEndPam->DeleteMark(); 1639 *pEndPam->GetPoint() = aEnd; 1640 } 1641 aStartPam.SetMark(); 1642 *aStartPam.End() = *pEndPam->End(); 1643 pEndPam.reset(); 1644 1645 // see if there are frames already anchored to this node 1646 // we have to work with the SdrObjects, as unique name is not guaranteed in their frame format 1647 // tdf#115094: do nothing if we have a graphic node 1648 std::set<const SdrObject*> aAnchoredObjectsByPtr; 1649 std::set<OUString> aAnchoredObjectsByName; 1650 for (size_t i = 0; i < m_pImpl->m_pDoc->GetSpzFrameFormats()->size(); ++i) 1651 { 1652 const SwFrameFormat* pFrameFormat = (*m_pImpl->m_pDoc->GetSpzFrameFormats())[i]; 1653 const SwFormatAnchor& rAnchor = pFrameFormat->GetAnchor(); 1654 if ( !isGraphicNode(pFrameFormat) && 1655 (RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId() || RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId()) && 1656 aStartPam.Start()->nNode.GetIndex() <= rAnchor.GetContentAnchor()->nNode.GetIndex() && 1657 aStartPam.End()->nNode.GetIndex() >= rAnchor.GetContentAnchor()->nNode.GetIndex()) 1658 { 1659 if (pFrameFormat->GetName().isEmpty()) 1660 { 1661 aAnchoredObjectsByPtr.insert(pFrameFormat->FindSdrObject()); 1662 } 1663 else 1664 { 1665 aAnchoredObjectsByName.insert(pFrameFormat->GetName()); 1666 } 1667 } 1668 } 1669 1670 const uno::Reference<text::XTextFrame> xNewFrame( 1671 SwXTextFrame::CreateXTextFrame(*m_pImpl->m_pDoc, nullptr)); 1672 SwXTextFrame& rNewFrame = dynamic_cast<SwXTextFrame&>(*xNewFrame); 1673 rNewFrame.SetSelection( aStartPam ); 1674 try 1675 { 1676 const beans::PropertyValue* pValues = rFrameProperties.getConstArray(); 1677 for (sal_Int32 nProp = 0; nProp < rFrameProperties.getLength(); ++nProp) 1678 { 1679 rNewFrame.SwXFrame::setPropertyValue( 1680 pValues[nProp].Name, pValues[nProp].Value); 1681 } 1682 1683 { // has to be in a block to remove the SwIndexes before 1684 // DelFullPara is called 1685 const uno::Reference< text::XTextRange> xInsertTextRange = 1686 new SwXTextRange(aStartPam, this); 1687 aStartPam.DeleteMark(); // mark position node may be deleted! 1688 rNewFrame.attach( xInsertTextRange ); 1689 rNewFrame.setName(m_pImpl->m_pDoc->GetUniqueFrameName()); 1690 } 1691 1692 SwTextNode *const pTextNode(aStartPam.GetNode().GetTextNode()); 1693 assert(pTextNode); 1694 if (!pTextNode || !pTextNode->Len()) // don't remove if it contains text! 1695 { 1696 { // has to be in a block to remove the SwIndexes before 1697 // DelFullPara is called 1698 SwPaM aMovePam( aStartPam.GetNode() ); 1699 if (aMovePam.Move( fnMoveForward, GoInContent )) 1700 { 1701 // move the anchor to the next paragraph 1702 SwFormatAnchor aNewAnchor(rNewFrame.GetFrameFormat()->GetAnchor()); 1703 aNewAnchor.SetAnchor( aMovePam.Start() ); 1704 m_pImpl->m_pDoc->SetAttr( 1705 aNewAnchor, *rNewFrame.GetFrameFormat() ); 1706 1707 // also move frames anchored to us 1708 for (size_t i = 0; i < m_pImpl->m_pDoc->GetSpzFrameFormats()->size(); ++i) 1709 { 1710 SwFrameFormat* pFrameFormat = (*m_pImpl->m_pDoc->GetSpzFrameFormats())[i]; 1711 if ((!pFrameFormat->GetName().isEmpty() && aAnchoredObjectsByName.find(pFrameFormat->GetName()) != aAnchoredObjectsByName.end() ) || 1712 ( pFrameFormat->GetName().isEmpty() && aAnchoredObjectsByPtr.find(pFrameFormat->FindSdrObject()) != aAnchoredObjectsByPtr.end()) ) 1713 { 1714 // copy the anchor to the next paragraph 1715 SwFormatAnchor aAnchor(pFrameFormat->GetAnchor()); 1716 aAnchor.SetAnchor(aMovePam.Start()); 1717 m_pImpl->m_pDoc->SetAttr(aAnchor, *pFrameFormat); 1718 } 1719 } 1720 } 1721 } 1722 m_pImpl->m_pDoc->getIDocumentContentOperations().DelFullPara(aStartPam); 1723 } 1724 } 1725 catch (const lang::IllegalArgumentException& rIllegal) 1726 { 1727 sMessage = rIllegal.Message; 1728 bIllegalException = true; 1729 } 1730 catch (const uno::RuntimeException& rRuntime) 1731 { 1732 sMessage = rRuntime.Message; 1733 bRuntimeException = true; 1734 } 1735 xRet = xNewFrame; 1736 if (bParaBeforeInserted || bParaAfterInserted) 1737 { 1738 const uno::Reference<text::XTextCursor> xFrameTextCursor = 1739 rNewFrame.createTextCursor(); 1740 const uno::Reference<XUnoTunnel> xTunnel(xFrameTextCursor, 1741 uno::UNO_QUERY); 1742 SwXTextCursor *const pFrameCursor = 1743 ::sw::UnoTunnelGetImplementation<SwXTextCursor>(xTunnel); 1744 if (bParaBeforeInserted) 1745 { 1746 // todo: remove paragraph before frame 1747 m_pImpl->m_pDoc->getIDocumentContentOperations().DelFullPara(*pFrameCursor->GetPaM()); 1748 } 1749 if (bParaAfterInserted) 1750 { 1751 xFrameTextCursor->gotoEnd(false); 1752 if (!bParaBeforeInserted) 1753 m_pImpl->m_pDoc->getIDocumentContentOperations().DelFullPara(*pFrameCursor->GetPaM()); 1754 else 1755 { 1756 // In case the frame has a table only, the cursor points to the end of the first cell of the table. 1757 SwPaM aPaM(*pFrameCursor->GetPaM()->GetNode().FindSttNodeByType(SwFlyStartNode)->EndOfSectionNode()); 1758 // Now we have the end of the frame -- the node before that will be the paragraph we want to remove. 1759 --aPaM.GetPoint()->nNode; 1760 m_pImpl->m_pDoc->getIDocumentContentOperations().DelFullPara(aPaM); 1761 } 1762 } 1763 } 1764 1765 m_pImpl->m_pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::END, nullptr); 1766 if (bIllegalException || bRuntimeException) 1767 { 1768 m_pImpl->m_pDoc->GetIDocumentUndoRedo().Undo(); 1769 if (bIllegalException) 1770 { 1771 lang::IllegalArgumentException aEx; 1772 aEx.Message = sMessage; 1773 throw aEx; 1774 } 1775 else 1776 { 1777 uno::RuntimeException aEx; 1778 aEx.Message = sMessage; 1779 throw aEx; 1780 } 1781 } 1782 return xRet; 1783 } 1784 1785 // Move previously imported paragraphs into a new text table. 1786 struct VerticallyMergedCell 1787 { 1788 std::vector<uno::Reference< beans::XPropertySet > > aCells; 1789 sal_Int32 const nLeftPosition; 1790 bool bOpen; 1791 1792 VerticallyMergedCell(uno::Reference< beans::XPropertySet > const& rxCell, 1793 const sal_Int32 nLeft) 1794 : nLeftPosition( nLeft ) 1795 , bOpen( true ) 1796 { 1797 aCells.push_back( rxCell ); 1798 } 1799 }; 1800 1801 #define COL_POS_FUZZY 2 1802 1803 static bool lcl_SimilarPosition( const sal_Int32 nPos1, const sal_Int32 nPos2 ) 1804 { 1805 return abs( nPos1 - nPos2 ) < COL_POS_FUZZY; 1806 } 1807 1808 void SwXText::Impl::ConvertCell( 1809 const uno::Sequence< uno::Reference< text::XTextRange > > & rCell, 1810 std::vector<SwNodeRange> & rRowNodes, 1811 SwNodeRange *const pLastCell) 1812 { 1813 if (rCell.getLength() != 2) 1814 { 1815 throw lang::IllegalArgumentException( 1816 "rCell needs to contain 2 elements", 1817 uno::Reference< text::XTextCopy >( &m_rThis ), sal_Int16( 2 ) ); 1818 } 1819 const uno::Reference<text::XTextRange> xStartRange = rCell[0]; 1820 const uno::Reference<text::XTextRange> xEndRange = rCell[1]; 1821 SwUnoInternalPaM aStartCellPam(*m_pDoc); 1822 SwUnoInternalPaM aEndCellPam(*m_pDoc); 1823 1824 // !!! TODO - PaMs in tables and sections do not work here - 1825 // the same applies to PaMs in frames !!! 1826 1827 if (!::sw::XTextRangeToSwPaM(aStartCellPam, xStartRange) || 1828 !::sw::XTextRangeToSwPaM(aEndCellPam, xEndRange)) 1829 { 1830 throw lang::IllegalArgumentException( 1831 "Start or End range cannot be resolved to a SwPaM", 1832 uno::Reference< text::XTextCopy >( &m_rThis ), sal_Int16( 2 ) ); 1833 } 1834 1835 SwNodeRange aTmpRange(aStartCellPam.Start()->nNode, 1836 aEndCellPam.End()->nNode); 1837 std::unique_ptr<SwNodeRange> pCorrectedRange = 1838 m_pDoc->GetNodes().ExpandRangeForTableBox(aTmpRange); 1839 1840 if (pCorrectedRange) 1841 { 1842 SwPaM aNewStartPaM(pCorrectedRange->aStart, 0); 1843 aStartCellPam = aNewStartPaM; 1844 1845 sal_Int32 nEndLen = 0; 1846 SwTextNode * pTextNode = pCorrectedRange->aEnd.GetNode().GetTextNode(); 1847 if (pTextNode != nullptr) 1848 nEndLen = pTextNode->Len(); 1849 1850 SwPaM aNewEndPaM(pCorrectedRange->aEnd, nEndLen); 1851 aEndCellPam = aNewEndPaM; 1852 1853 pCorrectedRange.reset(); 1854 } 1855 1856 /** check the nodes between start and end 1857 it is allowed to have pairs of StartNode/EndNodes 1858 */ 1859 if (aStartCellPam.Start()->nNode < aEndCellPam.End()->nNode) 1860 { 1861 // increment on each StartNode and decrement on each EndNode 1862 // we must reach zero at the end and must not go below zero 1863 long nOpenNodeBlock = 0; 1864 SwNodeIndex aCellIndex = aStartCellPam.Start()->nNode; 1865 while (aCellIndex < aEndCellPam.End()->nNode.GetIndex()) 1866 { 1867 if (aCellIndex.GetNode().IsStartNode()) 1868 { 1869 ++nOpenNodeBlock; 1870 } 1871 else if (aCellIndex.GetNode().IsEndNode()) 1872 { 1873 --nOpenNodeBlock; 1874 } 1875 if (nOpenNodeBlock < 0) 1876 { 1877 throw lang::IllegalArgumentException(); 1878 } 1879 ++aCellIndex; 1880 } 1881 if (nOpenNodeBlock != 0) 1882 { 1883 throw lang::IllegalArgumentException(); 1884 } 1885 } 1886 1887 /** The vector<vector> NodeRanges has to contain consecutive nodes. 1888 In rTableRanges the ranges don't need to be full paragraphs but 1889 they have to follow each other. To process the ranges they 1890 have to be aligned on paragraph borders by inserting paragraph 1891 breaks. Non-consecutive ranges must initiate an exception. 1892 */ 1893 if (!pLastCell) // first cell? 1894 { 1895 // align the beginning - if necessary 1896 if (aStartCellPam.Start()->nContent.GetIndex()) 1897 { 1898 m_pDoc->getIDocumentContentOperations().SplitNode(*aStartCellPam.Start(), false); 1899 } 1900 } 1901 else 1902 { 1903 // check the predecessor 1904 const sal_uLong nStartCellNodeIndex = 1905 aStartCellPam.Start()->nNode.GetIndex(); 1906 const sal_uLong nLastNodeEndIndex = pLastCell->aEnd.GetIndex(); 1907 if (nLastNodeEndIndex == nStartCellNodeIndex) 1908 { 1909 // same node as predecessor then equal nContent? 1910 if (0 != aStartCellPam.Start()->nContent.GetIndex()) 1911 { 1912 throw lang::IllegalArgumentException(); 1913 } 1914 1915 m_pDoc->getIDocumentContentOperations().SplitNode(*aStartCellPam.Start(), false); 1916 sal_uLong const nNewIndex(aStartCellPam.Start()->nNode.GetIndex()); 1917 if (nNewIndex != nStartCellNodeIndex) 1918 { 1919 // aStartCellPam now points to the 2nd node 1920 // the last cell may *also* point to 2nd node now - fix it! 1921 assert(nNewIndex == nStartCellNodeIndex + 1); 1922 if (pLastCell->aEnd.GetIndex() == nNewIndex) 1923 { 1924 --pLastCell->aEnd; 1925 if (pLastCell->aStart.GetIndex() == nNewIndex) 1926 { 1927 --pLastCell->aStart; 1928 } 1929 } 1930 } 1931 } 1932 else if (nStartCellNodeIndex == (nLastNodeEndIndex + 1)) 1933 { 1934 // next paragraph - now the content index of the new should be 0 1935 // and of the old one should be equal to the text length 1936 // but if it isn't we don't care - the cell is being inserted on 1937 // the node border anyway 1938 } 1939 else 1940 { 1941 throw lang::IllegalArgumentException(); 1942 } 1943 } 1944 // now check if there's a need to insert another paragraph break 1945 if (aEndCellPam.End()->nContent.GetIndex() < 1946 aEndCellPam.End()->nNode.GetNode().GetTextNode()->Len()) 1947 { 1948 m_pDoc->getIDocumentContentOperations().SplitNode(*aEndCellPam.End(), false); 1949 // take care that the new start/endcell is moved to the right position 1950 // aStartCellPam has to point to the start of the new (previous) node 1951 // aEndCellPam has to point to the end of the new (previous) node 1952 aStartCellPam.DeleteMark(); 1953 aStartCellPam.Move(fnMoveBackward, GoInNode); 1954 aStartCellPam.GetPoint()->nContent = 0; 1955 aEndCellPam.DeleteMark(); 1956 aEndCellPam.Move(fnMoveBackward, GoInNode); 1957 aEndCellPam.GetPoint()->nContent = 1958 aEndCellPam.GetNode().GetTextNode()->Len(); 1959 } 1960 1961 assert(aStartCellPam.Start()->nContent.GetIndex() == 0); 1962 assert(aEndCellPam.End()->nContent.GetIndex() == aEndCellPam.End()->nNode.GetNode().GetTextNode()->Len()); 1963 SwNodeRange aCellRange(aStartCellPam.Start()->nNode, 1964 aEndCellPam.End()->nNode); 1965 rRowNodes.push_back(aCellRange); // note: invalidates pLastCell! 1966 } 1967 1968 typedef uno::Sequence< text::TableColumnSeparator > TableColumnSeparators; 1969 1970 static void 1971 lcl_ApplyRowProperties( 1972 uno::Sequence<beans::PropertyValue> const& rRowProperties, 1973 uno::Any const& rRow, 1974 TableColumnSeparators & rRowSeparators) 1975 { 1976 uno::Reference< beans::XPropertySet > xRow; 1977 rRow >>= xRow; 1978 const beans::PropertyValue* pProperties = rRowProperties.getConstArray(); 1979 for (sal_Int32 nProperty = 0; nProperty < rRowProperties.getLength(); 1980 ++nProperty) 1981 { 1982 if ( pProperties[ nProperty ].Name == "TableColumnSeparators" ) 1983 { 1984 // add the separators to access the cell's positions 1985 // for vertical merging later 1986 TableColumnSeparators aSeparators; 1987 pProperties[ nProperty ].Value >>= aSeparators; 1988 rRowSeparators = aSeparators; 1989 } 1990 xRow->setPropertyValue( 1991 pProperties[ nProperty ].Name, pProperties[ nProperty ].Value); 1992 } 1993 } 1994 1995 static sal_Int32 lcl_GetLeftPos(sal_Int32 nCell, TableColumnSeparators const& rRowSeparators) 1996 { 1997 if(!nCell) 1998 return 0; 1999 if (rRowSeparators.getLength() < nCell) 2000 return -1; 2001 return rRowSeparators[nCell - 1].Position; 2002 } 2003 2004 static void 2005 lcl_ApplyCellProperties( 2006 const sal_Int32 nLeftPos, 2007 const uno::Sequence< beans::PropertyValue >& rCellProperties, 2008 const uno::Reference< uno::XInterface >& xCell, 2009 std::vector<VerticallyMergedCell> & rMergedCells) 2010 { 2011 const sal_Int32 nCellProperties = rCellProperties.getLength(); 2012 const uno::Reference< beans::XPropertySet > xCellPS(xCell, uno::UNO_QUERY); 2013 for (sal_Int32 nProperty = 0; nProperty < nCellProperties; ++nProperty) 2014 { 2015 const OUString & rName = rCellProperties[nProperty].Name; 2016 const uno::Any & rValue = rCellProperties[nProperty].Value; 2017 if ( rName == "VerticalMerge" ) 2018 { 2019 // determine left border position 2020 // add the cell to a queue of merged cells 2021 bool bMerge = false; 2022 rValue >>= bMerge; 2023 if (bMerge) 2024 { 2025 // 'close' all the cell with the same left position 2026 // if separate vertical merges in the same column exist 2027 for(auto& aMergedCell : rMergedCells) 2028 { 2029 if(lcl_SimilarPosition(aMergedCell.nLeftPosition, nLeftPos)) 2030 { 2031 aMergedCell.bOpen = false; 2032 } 2033 } 2034 // add the new group of merged cells 2035 rMergedCells.emplace_back(xCellPS, nLeftPos); 2036 } 2037 else 2038 { 2039 bool bFound = false; 2040 SAL_WARN_IF(rMergedCells.empty(), "sw.uno", "the first merged cell is missing"); 2041 for(auto& aMergedCell : rMergedCells) 2042 { 2043 if (aMergedCell.bOpen && lcl_SimilarPosition(aMergedCell.nLeftPosition, nLeftPos)) 2044 { 2045 aMergedCell.aCells.push_back( xCellPS ); 2046 bFound = true; 2047 } 2048 } 2049 SAL_WARN_IF(!bFound, "sw.uno", "couldn't find first vertically merged cell" ); 2050 } 2051 } 2052 else 2053 { 2054 try 2055 { 2056 xCellPS->setPropertyValue(rName, rValue); 2057 } 2058 catch (const uno::Exception& e) 2059 { 2060 SAL_WARN( "sw.uno", "Exception when getting PropertyState: " 2061 + rName + ". Message: " + e.Message ); 2062 } 2063 } 2064 } 2065 } 2066 2067 static void 2068 lcl_MergeCells(std::vector<VerticallyMergedCell> & rMergedCells) 2069 { 2070 for(auto& aMergedCell : rMergedCells) 2071 { 2072 // the first of the cells gets the number of cells set as RowSpan 2073 // the others get the inverted number of remaining merged cells 2074 // (3,-2,-1) 2075 sal_Int32 nCellCount = static_cast<sal_Int32>(aMergedCell.aCells.size()); 2076 if(nCellCount<2) 2077 { 2078 SAL_WARN("sw.uno", "incomplete vertical cell merge"); 2079 continue; 2080 } 2081 aMergedCell.aCells.front()->setPropertyValue(UNO_NAME_ROW_SPAN, uno::makeAny(nCellCount--)); 2082 nCellCount*=-1; 2083 for(auto pxPSet = aMergedCell.aCells.begin()+1; nCellCount<0; ++pxPSet, ++nCellCount) 2084 (*pxPSet)->setPropertyValue(UNO_NAME_ROW_SPAN, uno::makeAny(nCellCount)); 2085 } 2086 } 2087 2088 uno::Reference< text::XTextTable > SAL_CALL 2089 SwXText::convertToTable( 2090 const uno::Sequence< uno::Sequence< uno::Sequence< 2091 uno::Reference< text::XTextRange > > > >& rTableRanges, 2092 const uno::Sequence< uno::Sequence< uno::Sequence< 2093 beans::PropertyValue > > >& rCellProperties, 2094 const uno::Sequence< uno::Sequence< beans::PropertyValue > >& 2095 rRowProperties, 2096 const uno::Sequence< beans::PropertyValue >& rTableProperties) 2097 { 2098 SolarMutexGuard aGuard; 2099 2100 if(!IsValid()) 2101 { 2102 throw uno::RuntimeException(); 2103 } 2104 2105 IDocumentRedlineAccess & rIDRA(m_pImpl->m_pDoc->getIDocumentRedlineAccess()); 2106 if (!IDocumentRedlineAccess::IsShowChanges(rIDRA.GetRedlineFlags())) 2107 { 2108 throw uno::RuntimeException( 2109 "cannot convertToTable if tracked changes are hidden!"); 2110 } 2111 2112 //at first collect the text ranges as SwPaMs 2113 const uno::Sequence< uno::Sequence< uno::Reference< text::XTextRange > > >* 2114 pTableRanges = rTableRanges.getConstArray(); 2115 std::vector< std::vector<SwNodeRange> > aTableNodes; 2116 for (sal_Int32 nRow = 0; nRow < rTableRanges.getLength(); ++nRow) 2117 { 2118 std::vector<SwNodeRange> aRowNodes; 2119 const uno::Sequence< uno::Reference< text::XTextRange > >* pRow = 2120 pTableRanges[nRow].getConstArray(); 2121 const sal_Int32 nCells(pTableRanges[nRow].getLength()); 2122 2123 if (0 == nCells) // this would lead to no pLastCell below 2124 { // and make it impossible to detect node gaps 2125 throw lang::IllegalArgumentException(); 2126 } 2127 2128 for (sal_Int32 nCell = 0; nCell < nCells; ++nCell) 2129 { 2130 SwNodeRange *const pLastCell( 2131 (nCell == 0) 2132 ? ((nRow == 0) 2133 ? nullptr 2134 : &*aTableNodes.rbegin()->rbegin()) 2135 : &*aRowNodes.rbegin()); 2136 m_pImpl->ConvertCell(pRow[nCell], aRowNodes, pLastCell); 2137 } 2138 assert(!aRowNodes.empty()); 2139 aTableNodes.push_back(aRowNodes); 2140 } 2141 2142 std::vector< TableColumnSeparators > 2143 aRowSeparators(rRowProperties.getLength()); 2144 std::vector<VerticallyMergedCell> aMergedCells; 2145 2146 SwTable const*const pTable = m_pImpl->m_pDoc->TextToTable( aTableNodes ); 2147 2148 if (!pTable) 2149 return uno::Reference< text::XTextTable >(); 2150 2151 uno::Reference<text::XTextTable> const xRet = 2152 SwXTextTable::CreateXTextTable(pTable->GetFrameFormat()); 2153 uno::Reference<beans::XPropertySet> const xPrSet(xRet, uno::UNO_QUERY); 2154 // set properties to the table 2155 // catch lang::WrappedTargetException and lang::IndexOutOfBoundsException 2156 try 2157 { 2158 //apply table properties 2159 for(const auto& rTableProperty : rTableProperties) 2160 { 2161 try 2162 { 2163 xPrSet->setPropertyValue(rTableProperty.Name, rTableProperty.Value); 2164 } 2165 catch (const uno::Exception& e) 2166 { 2167 SAL_WARN( "sw.uno", "Exception when setting property: " 2168 + rTableProperty.Name + ". Message: " + e.Message ); 2169 } 2170 } 2171 2172 //apply row properties 2173 const auto xRows = xRet->getRows(); 2174 const sal_Int32 nLast = std::min(xRows->getCount(), rRowProperties.getLength()); 2175 SAL_WARN_IF(nLast != rRowProperties.getLength(), "sw.uno", "not enough rows for properties"); 2176 for(sal_Int32 nCnt = 0; nCnt < nLast; ++nCnt) 2177 lcl_ApplyRowProperties(rRowProperties[nCnt], xRows->getByIndex(nCnt), aRowSeparators[nCnt]); 2178 2179 uno::Reference<table::XCellRange> const xCR(xRet, uno::UNO_QUERY_THROW); 2180 //apply cell properties 2181 sal_Int32 nRow = 0; 2182 for(const auto& rCellPropertiesForRow : rCellProperties) 2183 { 2184 sal_Int32 nCell = 0; 2185 for(const auto& rCellProps : rCellPropertiesForRow) 2186 { 2187 lcl_ApplyCellProperties(lcl_GetLeftPos(nCell, aRowSeparators[nRow]), 2188 rCellProps, 2189 xCR->getCellByPosition(nCell, nRow), 2190 aMergedCells); 2191 ++nCell; 2192 } 2193 ++nRow; 2194 } 2195 2196 // now that the cell properties are set the vertical merge values 2197 // have to be applied 2198 lcl_MergeCells(aMergedCells); 2199 } 2200 catch (const lang::WrappedTargetException&) 2201 { 2202 } 2203 catch (const lang::IndexOutOfBoundsException&) 2204 { 2205 } 2206 2207 assert(SwTable::FindTable(pTable->GetFrameFormat()) == pTable); 2208 assert(pTable->GetFrameFormat() == 2209 dynamic_cast<SwXTextTable&>(*xRet).GetFrameFormat()); 2210 return xRet; 2211 } 2212 2213 void SAL_CALL 2214 SwXText::copyText( 2215 const uno::Reference< text::XTextCopy >& xSource ) 2216 { 2217 SolarMutexGuard aGuard; 2218 2219 uno::Reference< text::XText > const xText(xSource, uno::UNO_QUERY_THROW); 2220 uno::Reference< text::XTextCursor > const xCursor = 2221 xText->createTextCursor(); 2222 xCursor->gotoEnd( true ); 2223 2224 uno::Reference< lang::XUnoTunnel > const xCursorTunnel(xCursor, 2225 uno::UNO_QUERY_THROW); 2226 2227 OTextCursorHelper *const pCursor = 2228 ::sw::UnoTunnelGetImplementation<OTextCursorHelper>(xCursorTunnel); 2229 if (!pCursor) 2230 { 2231 throw uno::RuntimeException(); 2232 } 2233 2234 SwNodeIndex rNdIndex( *GetStartNode( ), 1 ); 2235 SwPosition rPos( rNdIndex ); 2236 m_pImpl->m_pDoc->getIDocumentContentOperations().CopyRange( *pCursor->GetPaM(), rPos, /*bCopyAll=*/false, /*bCheckPos=*/true ); 2237 } 2238 2239 SwXBodyText::SwXBodyText(SwDoc *const pDoc) 2240 : SwXText(pDoc, CursorType::Body) 2241 { 2242 } 2243 2244 SwXBodyText::~SwXBodyText() 2245 { 2246 } 2247 2248 OUString SAL_CALL 2249 SwXBodyText::getImplementationName() 2250 { 2251 return OUString("SwXBodyText"); 2252 } 2253 2254 static char const*const g_ServicesBodyText[] = 2255 { 2256 "com.sun.star.text.Text", 2257 }; 2258 2259 static const size_t g_nServicesBodyText(SAL_N_ELEMENTS(g_ServicesBodyText)); 2260 2261 sal_Bool SAL_CALL SwXBodyText::supportsService(const OUString& rServiceName) 2262 { 2263 return cppu::supportsService(this, rServiceName); 2264 } 2265 2266 uno::Sequence< OUString > SAL_CALL 2267 SwXBodyText::getSupportedServiceNames() 2268 { 2269 return ::sw::GetSupportedServiceNamesImpl( 2270 g_nServicesBodyText, g_ServicesBodyText); 2271 } 2272 2273 uno::Any SAL_CALL 2274 SwXBodyText::queryAggregation(const uno::Type& rType) 2275 { 2276 uno::Any aRet; 2277 if (rType == cppu::UnoType<container::XEnumerationAccess>::get()) 2278 { 2279 aRet <<= uno::Reference< container::XEnumerationAccess >(this); 2280 } 2281 else if (rType == cppu::UnoType<container::XElementAccess>::get()) 2282 { 2283 aRet <<= uno::Reference< container::XElementAccess >(this); 2284 } 2285 else if (rType == cppu::UnoType<lang::XServiceInfo>::get()) 2286 { 2287 aRet <<= uno::Reference< lang::XServiceInfo >(this); 2288 } 2289 else 2290 { 2291 aRet = SwXText::queryInterface( rType ); 2292 } 2293 if(aRet.getValueType() == cppu::UnoType<void>::get()) 2294 { 2295 aRet = OWeakAggObject::queryAggregation( rType ); 2296 } 2297 return aRet; 2298 } 2299 2300 uno::Sequence< uno::Type > SAL_CALL 2301 SwXBodyText::getTypes() 2302 { 2303 const uno::Sequence< uno::Type > aTypes = SwXBodyText_Base::getTypes(); 2304 const uno::Sequence< uno::Type > aTextTypes = SwXText::getTypes(); 2305 return ::comphelper::concatSequences(aTypes, aTextTypes); 2306 } 2307 2308 uno::Sequence< sal_Int8 > SAL_CALL 2309 SwXBodyText::getImplementationId() 2310 { 2311 return css::uno::Sequence<sal_Int8>(); 2312 } 2313 2314 uno::Any SAL_CALL 2315 SwXBodyText::queryInterface(const uno::Type& rType) 2316 { 2317 const uno::Any ret = SwXText::queryInterface(rType); 2318 return (ret.getValueType() == cppu::UnoType<void>::get()) 2319 ? SwXBodyText_Base::queryInterface(rType) 2320 : ret; 2321 } 2322 2323 SwXTextCursor * SwXBodyText::CreateTextCursor(const bool bIgnoreTables) 2324 { 2325 if(!IsValid()) 2326 { 2327 return nullptr; 2328 } 2329 2330 // the cursor has to skip tables contained in this text 2331 SwPaM aPam(GetDoc()->GetNodes().GetEndOfContent()); 2332 aPam.Move( fnMoveBackward, GoInDoc ); 2333 if (!bIgnoreTables) 2334 { 2335 SwTableNode * pTableNode = aPam.GetNode().FindTableNode(); 2336 SwContentNode * pCont = nullptr; 2337 while (pTableNode) 2338 { 2339 aPam.GetPoint()->nNode = *pTableNode->EndOfSectionNode(); 2340 pCont = GetDoc()->GetNodes().GoNext(&aPam.GetPoint()->nNode); 2341 pTableNode = pCont->FindTableNode(); 2342 } 2343 if (pCont) 2344 { 2345 aPam.GetPoint()->nContent.Assign(pCont, 0); 2346 } 2347 } 2348 return new SwXTextCursor(*GetDoc(), this, CursorType::Body, *aPam.GetPoint()); 2349 } 2350 2351 uno::Reference< text::XTextCursor > SAL_CALL 2352 SwXBodyText::createTextCursor() 2353 { 2354 SolarMutexGuard aGuard; 2355 2356 const uno::Reference< text::XTextCursor > xRef( 2357 static_cast<text::XWordCursor*>(CreateTextCursor()) ); 2358 if (!xRef.is()) 2359 { 2360 uno::RuntimeException aRuntime; 2361 aRuntime.Message = cInvalidObject; 2362 throw aRuntime; 2363 } 2364 return xRef; 2365 } 2366 2367 uno::Reference< text::XTextCursor > SAL_CALL 2368 SwXBodyText::createTextCursorByRange( 2369 const uno::Reference< text::XTextRange > & xTextPosition) 2370 { 2371 SolarMutexGuard aGuard; 2372 2373 if(!IsValid()) 2374 { 2375 uno::RuntimeException aRuntime; 2376 aRuntime.Message = cInvalidObject; 2377 throw aRuntime; 2378 } 2379 2380 uno::Reference< text::XTextCursor > aRef; 2381 SwUnoInternalPaM aPam(*GetDoc()); 2382 if (::sw::XTextRangeToSwPaM(aPam, xTextPosition)) 2383 { 2384 if ( !aPam.GetNode().GetTextNode() ) 2385 throw uno::RuntimeException("Invalid text range" ); 2386 2387 SwNode& rNode = GetDoc()->GetNodes().GetEndOfContent(); 2388 2389 SwStartNode* p1 = aPam.GetNode().StartOfSectionNode(); 2390 //document starts with a section? 2391 while(p1->IsSectionNode()) 2392 { 2393 p1 = p1->StartOfSectionNode(); 2394 } 2395 SwStartNode *const p2 = rNode.StartOfSectionNode(); 2396 2397 if(p1 == p2) 2398 { 2399 aRef = static_cast<text::XWordCursor*>( 2400 new SwXTextCursor(*GetDoc(), this, CursorType::Body, 2401 *aPam.GetPoint(), aPam.GetMark())); 2402 } 2403 } 2404 if(!aRef.is()) 2405 { 2406 throw uno::RuntimeException( "End of content node doesn't have the proper start node", 2407 uno::Reference< uno::XInterface >( *this ) ); 2408 } 2409 return aRef; 2410 } 2411 2412 uno::Reference< container::XEnumeration > SAL_CALL 2413 SwXBodyText::createEnumeration() 2414 { 2415 SolarMutexGuard aGuard; 2416 2417 if (!IsValid()) 2418 { 2419 uno::RuntimeException aRuntime; 2420 aRuntime.Message = cInvalidObject; 2421 throw aRuntime; 2422 } 2423 2424 SwNode& rNode = GetDoc()->GetNodes().GetEndOfContent(); 2425 SwPosition aPos(rNode); 2426 auto pUnoCursor(GetDoc()->CreateUnoCursor(aPos)); 2427 pUnoCursor->Move(fnMoveBackward, GoInDoc); 2428 return SwXParagraphEnumeration::Create(this, pUnoCursor, CursorType::Body); 2429 } 2430 2431 uno::Type SAL_CALL 2432 SwXBodyText::getElementType() 2433 { 2434 return cppu::UnoType<text::XTextRange>::get(); 2435 } 2436 2437 sal_Bool SAL_CALL 2438 SwXBodyText::hasElements() 2439 { 2440 SolarMutexGuard aGuard; 2441 2442 if (!IsValid()) 2443 { 2444 uno::RuntimeException aRuntime; 2445 aRuntime.Message = cInvalidObject; 2446 throw aRuntime; 2447 } 2448 2449 return true; 2450 } 2451 2452 class SwXHeadFootText::Impl 2453 : public SvtListener 2454 { 2455 public: 2456 SwFrameFormat* m_pHeadFootFormat; 2457 bool const m_bIsHeader; 2458 2459 Impl(SwFrameFormat& rHeadFootFormat, const bool bIsHeader) 2460 : m_pHeadFootFormat(&rHeadFootFormat) 2461 , m_bIsHeader(bIsHeader) 2462 { 2463 StartListening(m_pHeadFootFormat->GetNotifier()); 2464 } 2465 2466 SwFrameFormat* GetHeadFootFormat() const { 2467 return m_pHeadFootFormat; 2468 } 2469 2470 SwFrameFormat& GetHeadFootFormatOrThrow() { 2471 if (!m_pHeadFootFormat) { 2472 throw uno::RuntimeException("SwXHeadFootText: disposed or invalid", nullptr); 2473 } 2474 return *m_pHeadFootFormat; 2475 } 2476 protected: 2477 virtual void Notify(const SfxHint& rHint) override 2478 { 2479 if(rHint.GetId() == SfxHintId::Dying) 2480 m_pHeadFootFormat = nullptr; 2481 } 2482 }; 2483 2484 uno::Reference<text::XText> SwXHeadFootText::CreateXHeadFootText( 2485 SwFrameFormat& rHeadFootFormat, 2486 const bool bIsHeader) 2487 { 2488 // re-use existing SwXHeadFootText 2489 // #i105557#: do not iterate over the registered clients: race condition 2490 uno::Reference<text::XText> xText(rHeadFootFormat.GetXObject(), uno::UNO_QUERY); 2491 if(!xText.is()) 2492 { 2493 const auto pXHFT(new SwXHeadFootText(rHeadFootFormat, bIsHeader)); 2494 xText.set(pXHFT); 2495 rHeadFootFormat.SetXObject(xText); 2496 } 2497 return xText; 2498 } 2499 2500 SwXHeadFootText::SwXHeadFootText(SwFrameFormat& rHeadFootFormat, const bool bIsHeader) 2501 : SwXText( 2502 rHeadFootFormat.GetDoc(), 2503 bIsHeader ? CursorType::Header : CursorType::Footer) 2504 , m_pImpl(new SwXHeadFootText::Impl(rHeadFootFormat, bIsHeader)) 2505 { 2506 } 2507 2508 SwXHeadFootText::~SwXHeadFootText() 2509 { } 2510 2511 OUString SAL_CALL 2512 SwXHeadFootText::getImplementationName() 2513 { 2514 return {"SwXHeadFootText"}; 2515 } 2516 2517 sal_Bool SAL_CALL SwXHeadFootText::supportsService(const OUString& rServiceName) 2518 { 2519 return cppu::supportsService(this, rServiceName); 2520 } 2521 2522 uno::Sequence<OUString> SAL_CALL 2523 SwXHeadFootText::getSupportedServiceNames() 2524 { 2525 return {"com.sun.star.text.Text"}; 2526 } 2527 2528 const SwStartNode* SwXHeadFootText::GetStartNode() const 2529 { 2530 const SwStartNode* pSttNd = nullptr; 2531 SwFrameFormat* const pHeadFootFormat = m_pImpl->GetHeadFootFormat(); 2532 if(pHeadFootFormat) 2533 { 2534 const SwFormatContent& rFlyContent = pHeadFootFormat->GetContent(); 2535 if(rFlyContent.GetContentIdx()) 2536 { 2537 pSttNd = rFlyContent.GetContentIdx()->GetNode().GetStartNode(); 2538 } 2539 } 2540 return pSttNd; 2541 } 2542 2543 uno::Reference<text::XTextCursor> SwXHeadFootText::CreateCursor() 2544 { 2545 return createTextCursor(); 2546 } 2547 2548 uno::Sequence<uno::Type> SAL_CALL SwXHeadFootText::getTypes() 2549 { 2550 return ::comphelper::concatSequences( 2551 SwXHeadFootText_Base::getTypes(), 2552 SwXText::getTypes()); 2553 } 2554 2555 uno::Sequence<sal_Int8> SAL_CALL SwXHeadFootText::getImplementationId() 2556 { 2557 return css::uno::Sequence<sal_Int8>(); 2558 } 2559 2560 uno::Any SAL_CALL SwXHeadFootText::queryInterface(const uno::Type& rType) 2561 { 2562 const uno::Any ret = SwXHeadFootText_Base::queryInterface(rType); 2563 return (ret.getValueType() == cppu::UnoType<void>::get()) 2564 ? SwXText::queryInterface(rType) 2565 : ret; 2566 } 2567 2568 uno::Reference<text::XTextCursor> SAL_CALL 2569 SwXHeadFootText::createTextCursor() 2570 { 2571 SolarMutexGuard aGuard; 2572 2573 SwFrameFormat & rHeadFootFormat( m_pImpl->GetHeadFootFormatOrThrow() ); 2574 2575 const SwFormatContent& rFlyContent = rHeadFootFormat.GetContent(); 2576 const SwNode& rNode = rFlyContent.GetContentIdx()->GetNode(); 2577 SwPosition aPos(rNode); 2578 SwXTextCursor *const pXCursor = new SwXTextCursor(*GetDoc(), this, 2579 (m_pImpl->m_bIsHeader) ? CursorType::Header : CursorType::Footer, aPos); 2580 auto& rUnoCursor(pXCursor->GetCursor()); 2581 rUnoCursor.Move(fnMoveForward, GoInNode); 2582 2583 // save current start node to be able to check if there is content 2584 // after the table - otherwise the cursor would be in the body text! 2585 SwStartNode const*const pOwnStartNode = rNode.FindSttNodeByType( 2586 (m_pImpl->m_bIsHeader) ? SwHeaderStartNode : SwFooterStartNode); 2587 // is there a table here? 2588 SwTableNode* pTableNode = rUnoCursor.GetNode().FindTableNode(); 2589 SwContentNode* pCont = nullptr; 2590 while (pTableNode) 2591 { 2592 rUnoCursor.GetPoint()->nNode = *pTableNode->EndOfSectionNode(); 2593 pCont = GetDoc()->GetNodes().GoNext(&rUnoCursor.GetPoint()->nNode); 2594 pTableNode = pCont->FindTableNode(); 2595 } 2596 if (pCont) 2597 { 2598 rUnoCursor.GetPoint()->nContent.Assign(pCont, 0); 2599 } 2600 SwStartNode const*const pNewStartNode = rUnoCursor.GetNode().FindSttNodeByType( 2601 (m_pImpl->m_bIsHeader) ? SwHeaderStartNode : SwFooterStartNode); 2602 if (!pNewStartNode || (pNewStartNode != pOwnStartNode)) 2603 { 2604 uno::RuntimeException aExcept; 2605 aExcept.Message = "no text available"; 2606 throw aExcept; 2607 } 2608 return static_cast<text::XWordCursor*>(pXCursor); 2609 } 2610 2611 uno::Reference<text::XTextCursor> SAL_CALL SwXHeadFootText::createTextCursorByRange( 2612 const uno::Reference<text::XTextRange>& xTextPosition) 2613 { 2614 SolarMutexGuard aGuard; 2615 SwFrameFormat& rHeadFootFormat( m_pImpl->GetHeadFootFormatOrThrow() ); 2616 2617 SwUnoInternalPaM aPam(*GetDoc()); 2618 if (!sw::XTextRangeToSwPaM(aPam, xTextPosition)) 2619 { 2620 uno::RuntimeException aRuntime; 2621 aRuntime.Message = cInvalidObject; 2622 throw aRuntime; 2623 } 2624 2625 SwNode& rNode = rHeadFootFormat.GetContent().GetContentIdx()->GetNode(); 2626 SwPosition aPos(rNode); 2627 SwPaM aHFPam(aPos); 2628 aHFPam.Move(fnMoveForward, GoInNode); 2629 SwStartNode* const pOwnStartNode = aHFPam.GetNode().FindSttNodeByType( 2630 (m_pImpl->m_bIsHeader) ? SwHeaderStartNode : SwFooterStartNode); 2631 SwStartNode* const p1 = aPam.GetNode().FindSttNodeByType( 2632 (m_pImpl->m_bIsHeader) ? SwHeaderStartNode : SwFooterStartNode); 2633 if (p1 == pOwnStartNode) 2634 { 2635 return static_cast<text::XWordCursor*>( 2636 new SwXTextCursor( 2637 *GetDoc(), 2638 this, 2639 (m_pImpl->m_bIsHeader) ? CursorType::Header : CursorType::Footer, 2640 *aPam.GetPoint(), aPam.GetMark())); 2641 } 2642 return nullptr; 2643 } 2644 2645 uno::Reference<container::XEnumeration> SAL_CALL SwXHeadFootText::createEnumeration() 2646 { 2647 SolarMutexGuard aGuard; 2648 SwFrameFormat& rHeadFootFormat(m_pImpl->GetHeadFootFormatOrThrow()); 2649 2650 const SwFormatContent& rFlyContent = rHeadFootFormat.GetContent(); 2651 const SwNode& rNode = rFlyContent.GetContentIdx()->GetNode(); 2652 SwPosition aPos(rNode); 2653 auto pUnoCursor(GetDoc()->CreateUnoCursor(aPos)); 2654 pUnoCursor->Move(fnMoveForward, GoInNode); 2655 return SwXParagraphEnumeration::Create( 2656 this, 2657 pUnoCursor, 2658 (m_pImpl->m_bIsHeader) 2659 ? CursorType::Header 2660 : CursorType::Footer); 2661 } 2662 2663 uno::Type SAL_CALL SwXHeadFootText::getElementType() 2664 { return cppu::UnoType<text::XTextRange>::get(); } 2665 2666 sal_Bool SAL_CALL SwXHeadFootText::hasElements() 2667 { return true; } 2668 2669 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 2670
