1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_accessibility.hxx" 26 27 #ifndef _TOOLKIT_AWT_VCLXACCESSIBLECOMPONENT_HXX_ 28 #include <accessibility/extended/textwindowaccessibility.hxx> 29 #endif 30 #include "comphelper/accessibleeventnotifier.hxx" 31 #include "unotools/accessiblerelationsethelper.hxx" 32 #include <unotools/accessiblestatesethelper.hxx> 33 #include <vcl/window.hxx> 34 #include <toolkit/helper/convert.hxx> 35 36 #include <algorithm> 37 #include <vector> 38 #include <hash_map> 39 40 namespace css = ::com::sun::star; 41 42 namespace accessibility 43 { 44 ::sal_Int32 getSelectionType(::sal_Int32 nNewFirstPara, ::sal_Int32 nNewFirstPos, ::sal_Int32 nNewLastPara, ::sal_Int32 nNewLastPos); 45 void sendEvent(::sal_Int32 start, ::sal_Int32 end, ::sal_Int16 nEventId); 46 47 // Both ::osl::Mutex and ParagraphBase implement acquire and release, and thus 48 // ::rtl::Reference< Paragraph > does not work. So ParagraphImpl was factored 49 // out and ::rtl::Reference< ParagraphImpl > is used instead. 50 class Paragraph: private ::osl::Mutex, public ParagraphImpl 51 { 52 public: 53 inline Paragraph(::rtl::Reference< Document > const & rDocument, 54 Paragraphs::size_type nNumber): 55 ParagraphImpl(rDocument, nNumber, *this) {} 56 }; 57 58 void SfxListenerGuard::startListening(::SfxBroadcaster & rNotifier) 59 { 60 OSL_ENSURE(m_pNotifier == 0, "called more than once"); 61 m_pNotifier = &rNotifier; 62 m_rListener.StartListening(*m_pNotifier, true); 63 } 64 65 void SfxListenerGuard::endListening() 66 { 67 if (m_pNotifier != 0) 68 { 69 m_rListener.EndListening(*m_pNotifier); 70 m_pNotifier = 0; 71 } 72 } 73 74 void WindowListenerGuard::startListening(::Window & rNotifier) 75 { 76 OSL_ENSURE(m_pNotifier == 0, "called more than once"); 77 m_pNotifier = &rNotifier; 78 m_pNotifier->AddEventListener(m_aListener); 79 } 80 81 void WindowListenerGuard::endListening() 82 { 83 if (m_pNotifier != 0) 84 { 85 m_pNotifier->RemoveEventListener(m_aListener); 86 m_pNotifier = 0; 87 } 88 } 89 90 ParagraphImpl::ParagraphImpl(::rtl::Reference< Document > const & rDocument, 91 Paragraphs::size_type nNumber, 92 ::osl::Mutex & rMutex): 93 ParagraphBase(rMutex), 94 m_xDocument(rDocument), 95 m_nNumber(nNumber), 96 m_nClientId(0) 97 { 98 m_aParagraphText = m_xDocument->retrieveParagraphText(this); 99 } 100 101 void 102 ParagraphImpl::numberChanged(bool bIncremented) 103 { 104 if (bIncremented) 105 ++m_nNumber; 106 else 107 --m_nNumber; 108 } 109 110 void ParagraphImpl::textChanged() 111 { 112 ::rtl::OUString aParagraphText = implGetText(); 113 ::css::uno::Any aOldValue, aNewValue; 114 if ( implInitTextChangedEvent( m_aParagraphText, aParagraphText, aOldValue, aNewValue ) ) 115 { 116 m_aParagraphText = aParagraphText; 117 notifyEvent(::css::accessibility::AccessibleEventId:: 118 TEXT_CHANGED, 119 aOldValue, aNewValue); 120 } 121 } 122 123 void ParagraphImpl::notifyEvent(::sal_Int16 nEventId, 124 ::css::uno::Any const & rOldValue, 125 ::css::uno::Any const & rNewValue) 126 { 127 if (m_nClientId) 128 comphelper::AccessibleEventNotifier::addEvent( m_nClientId, ::css::accessibility::AccessibleEventObject( 129 static_cast< ::cppu::OWeakObject * >(this), 130 nEventId, rNewValue, rOldValue) ); 131 } 132 133 // virtual 134 ::css::uno::Reference< ::css::accessibility::XAccessibleContext > SAL_CALL 135 ParagraphImpl::getAccessibleContext() 136 { 137 checkDisposed(); 138 return this; 139 } 140 141 // virtual 142 ::sal_Int32 SAL_CALL ParagraphImpl::getAccessibleChildCount() 143 { 144 checkDisposed(); 145 return 0; 146 } 147 148 // virtual 149 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL 150 ParagraphImpl::getAccessibleChild(::sal_Int32) 151 { 152 checkDisposed(); 153 throw ::css::lang::IndexOutOfBoundsException( 154 ::rtl::OUString( 155 RTL_CONSTASCII_USTRINGPARAM( 156 "textwindowaccessibility.cxx:" 157 " ParagraphImpl::getAccessibleChild")), 158 static_cast< ::css::uno::XWeak * >(this)); 159 } 160 161 // virtual 162 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL 163 ParagraphImpl::getAccessibleParent() 164 { 165 checkDisposed(); 166 return m_xDocument->getAccessible(); 167 } 168 169 // virtual 170 ::sal_Int32 SAL_CALL ParagraphImpl::getAccessibleIndexInParent() 171 { 172 checkDisposed(); 173 return m_xDocument->retrieveParagraphIndex(this); 174 } 175 176 // virtual 177 ::sal_Int16 SAL_CALL ParagraphImpl::getAccessibleRole() 178 { 179 checkDisposed(); 180 return ::css::accessibility::AccessibleRole::PARAGRAPH; 181 } 182 183 // virtual 184 ::rtl::OUString SAL_CALL ParagraphImpl::getAccessibleDescription() 185 { 186 checkDisposed(); 187 return ::rtl::OUString(); 188 } 189 190 // virtual 191 ::rtl::OUString SAL_CALL ParagraphImpl::getAccessibleName() 192 { 193 checkDisposed(); 194 return ::rtl::OUString(); 195 } 196 197 // virtual 198 ::css::uno::Reference< ::css::accessibility::XAccessibleRelationSet > 199 SAL_CALL ParagraphImpl::getAccessibleRelationSet() 200 { 201 checkDisposed(); 202 return m_xDocument->retrieveParagraphRelationSet( this ); 203 } 204 205 // virtual 206 ::css::uno::Reference< ::css::accessibility::XAccessibleStateSet > 207 SAL_CALL ParagraphImpl::getAccessibleStateSet() 208 { 209 checkDisposed(); 210 211 // FIXME Notification of changes (STATE_CHANGED) missing when 212 // m_rView.IsReadOnly() changes: 213 return new ::utl::AccessibleStateSetHelper( 214 m_xDocument->retrieveParagraphState(this)); 215 } 216 217 // virtual 218 ::css::lang::Locale SAL_CALL ParagraphImpl::getLocale() 219 { 220 checkDisposed(); 221 return m_xDocument->retrieveLocale(); 222 } 223 224 // virtual 225 ::sal_Bool SAL_CALL ParagraphImpl::containsPoint(::css::awt::Point const & rPoint) 226 { 227 checkDisposed(); 228 ::css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this, 229 false)); 230 return rPoint.X >= 0 && rPoint.X < aRect.Width 231 && rPoint.Y >= 0 && rPoint.Y < aRect.Height; 232 } 233 234 // virtual 235 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL 236 ParagraphImpl::getAccessibleAtPoint(::css::awt::Point const &) 237 { 238 checkDisposed(); 239 return 0; 240 } 241 242 // virtual 243 ::css::awt::Rectangle SAL_CALL ParagraphImpl::getBounds() 244 { 245 checkDisposed(); 246 return m_xDocument->retrieveParagraphBounds(this, false); 247 } 248 249 // virtual 250 ::css::awt::Point SAL_CALL ParagraphImpl::getLocation() 251 { 252 checkDisposed(); 253 ::css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this, 254 false)); 255 return ::css::awt::Point(aRect.X, aRect.Y); 256 } 257 258 // virtual 259 ::css::awt::Point SAL_CALL ParagraphImpl::getLocationOnScreen() 260 { 261 checkDisposed(); 262 ::css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this, 263 true)); 264 return ::css::awt::Point(aRect.X, aRect.Y); 265 } 266 267 // virtual 268 ::css::awt::Size SAL_CALL ParagraphImpl::getSize() 269 { 270 checkDisposed(); 271 ::css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this, 272 false)); 273 return ::css::awt::Size(aRect.Width, aRect.Height); 274 } 275 276 // virtual 277 void SAL_CALL ParagraphImpl::grabFocus() 278 { 279 checkDisposed(); 280 Window* pWindow = m_xDocument->GetWindow(); 281 if ( pWindow ) 282 { 283 pWindow->GrabFocus(); 284 } 285 try 286 { 287 m_xDocument->changeParagraphSelection(this, 0, 0); 288 } 289 catch (::css::lang::IndexOutOfBoundsException & rEx) 290 { 291 OSL_TRACE( 292 "textwindowaccessibility.cxx: ParagraphImpl::grabFocus:" 293 " caught unexpected %s\n", 294 ::rtl::OUStringToOString(rEx.Message, RTL_TEXTENCODING_UTF8). 295 getStr()); 296 } 297 } 298 299 // virtual 300 ::css::uno::Any SAL_CALL ParagraphImpl::getAccessibleKeyBinding() 301 { 302 checkDisposed(); 303 return ::css::uno::Any(); 304 } 305 306 // virtual 307 ::css::util::Color SAL_CALL ParagraphImpl::getForeground() 308 { 309 return 0; // TODO 310 } 311 312 // virtual 313 ::css::util::Color SAL_CALL ParagraphImpl::getBackground() 314 { 315 return 0; // TODO 316 } 317 318 // virtual 319 ::sal_Int32 SAL_CALL ParagraphImpl::getCaretPosition() 320 { 321 checkDisposed(); 322 return m_xDocument->retrieveParagraphCaretPosition(this); 323 } 324 325 // virtual 326 ::sal_Bool SAL_CALL ParagraphImpl::setCaretPosition(::sal_Int32 nIndex) 327 { 328 checkDisposed(); 329 m_xDocument->changeParagraphSelection(this, nIndex, nIndex); 330 return true; 331 } 332 333 // virtual 334 ::sal_Unicode SAL_CALL ParagraphImpl::getCharacter(::sal_Int32 nIndex) 335 { 336 checkDisposed(); 337 return OCommonAccessibleText::getCharacter(nIndex); 338 } 339 340 // virtual 341 ::css::uno::Sequence< ::css::beans::PropertyValue > SAL_CALL 342 ParagraphImpl::getCharacterAttributes(::sal_Int32 nIndex, const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aRequestedAttributes) 343 { 344 checkDisposed(); 345 return m_xDocument->retrieveCharacterAttributes( this, nIndex, aRequestedAttributes ); 346 } 347 348 // virtual 349 ::css::awt::Rectangle SAL_CALL 350 ParagraphImpl::getCharacterBounds(::sal_Int32 nIndex) 351 { 352 checkDisposed(); 353 ::css::awt::Rectangle aBounds(m_xDocument->retrieveCharacterBounds(this, nIndex)); 354 ::css::awt::Rectangle aParaBounds(m_xDocument->retrieveParagraphBounds(this, false)); 355 aBounds.X -= aParaBounds.X; 356 aBounds.Y -= aParaBounds.Y; 357 return aBounds; 358 } 359 360 // virtual 361 ::sal_Int32 SAL_CALL ParagraphImpl::getCharacterCount() 362 { 363 checkDisposed(); 364 return OCommonAccessibleText::getCharacterCount(); 365 } 366 367 // virtual 368 ::sal_Int32 SAL_CALL 369 ParagraphImpl::getIndexAtPoint(::css::awt::Point const & rPoint) 370 { 371 checkDisposed(); 372 ::css::awt::Point aPoint(rPoint); 373 ::css::awt::Rectangle aParaBounds(m_xDocument->retrieveParagraphBounds(this, false)); 374 aPoint.X += aParaBounds.X; 375 aPoint.Y += aParaBounds.Y; 376 return m_xDocument->retrieveCharacterIndex(this, aPoint); 377 } 378 379 // virtual 380 ::rtl::OUString SAL_CALL ParagraphImpl::getSelectedText() 381 { 382 checkDisposed(); 383 384 return OCommonAccessibleText::getSelectedText(); 385 } 386 387 // virtual 388 ::sal_Int32 SAL_CALL ParagraphImpl::getSelectionStart() 389 { 390 checkDisposed(); 391 return OCommonAccessibleText::getSelectionStart(); 392 } 393 394 // virtual 395 ::sal_Int32 SAL_CALL ParagraphImpl::getSelectionEnd() 396 { 397 checkDisposed(); 398 return OCommonAccessibleText::getSelectionEnd(); 399 } 400 401 // virtual 402 ::sal_Bool SAL_CALL ParagraphImpl::setSelection(::sal_Int32 nStartIndex, 403 ::sal_Int32 nEndIndex) 404 { 405 checkDisposed(); 406 m_xDocument->changeParagraphSelection(this, nStartIndex, nEndIndex); 407 return true; 408 } 409 410 // virtual 411 ::rtl::OUString SAL_CALL ParagraphImpl::getText() 412 { 413 checkDisposed(); 414 return OCommonAccessibleText::getText(); 415 } 416 417 // virtual 418 ::rtl::OUString SAL_CALL ParagraphImpl::getTextRange(::sal_Int32 nStartIndex, 419 ::sal_Int32 nEndIndex) 420 { 421 checkDisposed(); 422 return OCommonAccessibleText::getTextRange(nStartIndex, nEndIndex); 423 } 424 425 // virtual 426 ::com::sun::star::accessibility::TextSegment SAL_CALL ParagraphImpl::getTextAtIndex( sal_Int32 nIndex, sal_Int16 aTextType ) 427 { 428 checkDisposed(); 429 return OCommonAccessibleText::getTextAtIndex(nIndex, aTextType); 430 } 431 432 // virtual 433 ::com::sun::star::accessibility::TextSegment SAL_CALL ParagraphImpl::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 aTextType ) 434 { 435 checkDisposed(); 436 return OCommonAccessibleText::getTextBeforeIndex(nIndex, aTextType); 437 } 438 439 // virtual 440 ::com::sun::star::accessibility::TextSegment SAL_CALL ParagraphImpl::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 aTextType ) 441 { 442 checkDisposed(); 443 return OCommonAccessibleText::getTextBehindIndex(nIndex, aTextType); 444 } 445 446 // virtual 447 ::sal_Bool SAL_CALL ParagraphImpl::copyText(::sal_Int32 nStartIndex, 448 ::sal_Int32 nEndIndex) 449 { 450 checkDisposed(); 451 m_xDocument->copyParagraphText(this, nStartIndex, nEndIndex); 452 return true; 453 } 454 455 // virtual 456 ::sal_Bool SAL_CALL ParagraphImpl::cutText(::sal_Int32 nStartIndex, 457 ::sal_Int32 nEndIndex) 458 { 459 checkDisposed(); 460 m_xDocument->changeParagraphText(this, nStartIndex, nEndIndex, true, false, 461 ::rtl::OUString()); 462 return true; 463 } 464 465 // virtual 466 ::sal_Bool SAL_CALL ParagraphImpl::pasteText(::sal_Int32 nIndex) 467 { 468 checkDisposed(); 469 m_xDocument->changeParagraphText(this, nIndex, nIndex, false, true, 470 ::rtl::OUString()); 471 return true; 472 } 473 474 // virtual 475 ::sal_Bool SAL_CALL ParagraphImpl::deleteText(::sal_Int32 nStartIndex, 476 ::sal_Int32 nEndIndex) 477 { 478 checkDisposed(); 479 m_xDocument->changeParagraphText(this, nStartIndex, nEndIndex, false, false, 480 ::rtl::OUString()); 481 return true; 482 } 483 484 // virtual 485 ::sal_Bool SAL_CALL ParagraphImpl::insertText(::rtl::OUString const & rText, 486 ::sal_Int32 nIndex) 487 { 488 checkDisposed(); 489 m_xDocument->changeParagraphText(this, nIndex, nIndex, false, false, rText); 490 return true; 491 } 492 493 // virtual 494 ::sal_Bool SAL_CALL 495 ParagraphImpl::replaceText(::sal_Int32 nStartIndex, ::sal_Int32 nEndIndex, 496 ::rtl::OUString const & rReplacement) 497 { 498 checkDisposed(); 499 m_xDocument->changeParagraphText(this, nStartIndex, nEndIndex, false, false, 500 rReplacement); 501 return true; 502 } 503 504 // virtual 505 ::sal_Bool SAL_CALL ParagraphImpl::setAttributes( 506 ::sal_Int32 nStartIndex, ::sal_Int32 nEndIndex, 507 ::css::uno::Sequence< ::css::beans::PropertyValue > const & rAttributeSet) 508 { 509 checkDisposed(); 510 m_xDocument->changeParagraphAttributes(this, nStartIndex, nEndIndex, 511 rAttributeSet); 512 return true; 513 } 514 515 // virtual 516 ::sal_Bool SAL_CALL ParagraphImpl::setText(::rtl::OUString const & rText) 517 { 518 checkDisposed(); 519 m_xDocument->changeParagraphText(this, rText); 520 return true; 521 } 522 523 // virtual 524 ::css::uno::Sequence< ::css::beans::PropertyValue > SAL_CALL 525 ParagraphImpl::getDefaultAttributes(const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes) 526 { 527 checkDisposed(); 528 return m_xDocument->retrieveDefaultAttributes( this, RequestedAttributes ); 529 } 530 531 // virtual 532 ::css::uno::Sequence< ::css::beans::PropertyValue > SAL_CALL 533 ParagraphImpl::getRunAttributes(::sal_Int32 Index, const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes) 534 { 535 checkDisposed(); 536 return m_xDocument->retrieveRunAttributes( this, Index, RequestedAttributes ); 537 } 538 539 // virtual 540 ::sal_Int32 SAL_CALL ParagraphImpl::getLineNumberAtIndex( ::sal_Int32 nIndex ) 541 { 542 checkDisposed(); 543 544 ::sal_Int32 nLineNo = -1; 545 ::css::i18n::Boundary aBoundary = 546 m_xDocument->retrieveParagraphLineBoundary( this, nIndex, &nLineNo ); 547 548 return nLineNo; 549 } 550 551 // virtual 552 ::css::accessibility::TextSegment SAL_CALL ParagraphImpl::getTextAtLineNumber( ::sal_Int32 nLineNo ) 553 { 554 checkDisposed(); 555 556 ::css::i18n::Boundary aBoundary = 557 m_xDocument->retrieveParagraphBoundaryOfLine( this, nLineNo ); 558 559 return ::css::accessibility::TextSegment( getTextRange(aBoundary.startPos, aBoundary.endPos), 560 aBoundary.startPos, aBoundary.endPos); 561 } 562 563 // virtual 564 ::css::accessibility::TextSegment SAL_CALL ParagraphImpl::getTextAtLineWithCaret( ) 565 { 566 checkDisposed(); 567 568 sal_Int32 nLineNo = getNumberOfLineWithCaret(); 569 570 try { 571 return ( nLineNo >= 0 ) ? 572 getTextAtLineNumber( nLineNo ) : 573 ::css::accessibility::TextSegment(); 574 } catch (const ::css::lang::IndexOutOfBoundsException&) { 575 throw ::css::uno::RuntimeException( 576 ::rtl::OUString( 577 RTL_CONSTASCII_USTRINGPARAM( 578 "textwindowaccessibility.cxx:" 579 " ParagraphImpl::getTextAtLineWithCaret") ), 580 static_cast< ::css::uno::XWeak * >( this ) ); 581 } 582 } 583 584 // virtual 585 ::sal_Int32 SAL_CALL ParagraphImpl::getNumberOfLineWithCaret( ) 586 { 587 checkDisposed(); 588 return m_xDocument->retrieveParagraphLineWithCursor(this); 589 } 590 591 592 // virtual 593 void SAL_CALL ParagraphImpl::addEventListener( 594 ::css::uno::Reference< 595 ::css::accessibility::XAccessibleEventListener > const & rListener) 596 { 597 if (rListener.is()) 598 { 599 ::osl::ClearableMutexGuard aGuard(rBHelper.rMutex); 600 if (rBHelper.bDisposed || rBHelper.bInDispose) 601 { 602 aGuard.clear(); 603 rListener->disposing(::css::lang::EventObject( 604 static_cast< ::cppu::OWeakObject * >(this))); 605 } 606 else 607 { 608 if (!m_nClientId) 609 m_nClientId = comphelper::AccessibleEventNotifier::registerClient( ); 610 comphelper::AccessibleEventNotifier::addEventListener( m_nClientId, rListener ); 611 } 612 } 613 } 614 615 // virtual 616 void SAL_CALL ParagraphImpl::removeEventListener( 617 ::css::uno::Reference< 618 ::css::accessibility::XAccessibleEventListener > const & rListener) 619 { 620 comphelper::AccessibleEventNotifier::TClientId nId = 0; 621 { 622 ::osl::ClearableMutexGuard aGuard(rBHelper.rMutex); 623 if (rListener.is() && m_nClientId != 0 624 && comphelper::AccessibleEventNotifier::removeEventListener( m_nClientId, rListener ) == 0) 625 { 626 nId = m_nClientId; 627 m_nClientId = 0; 628 } 629 } 630 if (nId != 0) 631 { 632 // no listeners anymore 633 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client), 634 // and at least to us not firing any events anymore, in case somebody calls 635 // NotifyAccessibleEvent, again 636 comphelper::AccessibleEventNotifier::revokeClient(nId); 637 } 638 } 639 640 // virtual 641 void SAL_CALL ParagraphImpl::disposing() 642 { 643 comphelper::AccessibleEventNotifier::TClientId nId = 0; 644 { 645 ::osl::ClearableMutexGuard aGuard(rBHelper.rMutex); 646 nId = m_nClientId; 647 m_nClientId = 0; 648 } 649 if (nId != 0) 650 comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing(nId, *this); 651 } 652 653 // virtual 654 ::rtl::OUString ParagraphImpl::implGetText() 655 { 656 return m_xDocument->retrieveParagraphText(this); 657 } 658 659 // virtual 660 ::css::lang::Locale ParagraphImpl::implGetLocale() 661 { 662 return m_xDocument->retrieveLocale(); 663 } 664 665 // virtual 666 void ParagraphImpl::implGetSelection(::sal_Int32 & rStartIndex, 667 ::sal_Int32 & rEndIndex) 668 { 669 m_xDocument->retrieveParagraphSelection(this, &rStartIndex, &rEndIndex); 670 } 671 672 // virtual 673 void ParagraphImpl::implGetParagraphBoundary( ::css::i18n::Boundary& rBoundary, 674 ::sal_Int32 nIndex ) 675 { 676 ::rtl::OUString sText( implGetText() ); 677 ::sal_Int32 nLength = sText.getLength(); 678 679 if ( implIsValidIndex( nIndex, nLength ) ) 680 { 681 rBoundary.startPos = 0; 682 rBoundary.endPos = nLength; 683 } 684 else 685 { 686 rBoundary.startPos = nIndex; 687 rBoundary.endPos = nIndex; 688 } 689 } 690 691 // virtual 692 void ParagraphImpl::implGetLineBoundary( ::css::i18n::Boundary& rBoundary, 693 ::sal_Int32 nIndex ) 694 { 695 ::rtl::OUString sText( implGetText() ); 696 ::sal_Int32 nLength = sText.getLength(); 697 698 if ( implIsValidIndex( nIndex, nLength ) || nIndex == nLength ) 699 { 700 ::css::i18n::Boundary aBoundary = 701 m_xDocument->retrieveParagraphLineBoundary( this, nIndex ); 702 rBoundary.startPos = aBoundary.startPos; 703 rBoundary.endPos = aBoundary.endPos; 704 } 705 else 706 { 707 rBoundary.startPos = nIndex; 708 rBoundary.endPos = nIndex; 709 } 710 } 711 712 713 void ParagraphImpl::checkDisposed() 714 { 715 ::osl::MutexGuard aGuard(rBHelper.rMutex); 716 if (!(rBHelper.bDisposed || rBHelper.bInDispose)) 717 return; 718 throw ::css::lang::DisposedException( 719 ::rtl::OUString(), static_cast< ::css::uno::XWeak * >(this)); 720 } 721 722 Document::Document(::VCLXWindow * pVclXWindow, ::TextEngine & rEngine, 723 ::TextView & rView, bool bCompoundControlChild): 724 VCLXAccessibleComponent(pVclXWindow), 725 m_xAccessible(pVclXWindow), 726 m_rEngine(rEngine), 727 m_rView(rView), 728 m_aEngineListener(*this), 729 m_aViewListener(LINK(this, Document, WindowEventHandler)), 730 m_bCompoundControlChild(bCompoundControlChild) 731 {} 732 733 ::css::lang::Locale Document::retrieveLocale() 734 { 735 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); 736 return m_rEngine.GetLocale(); 737 } 738 739 ::sal_Int32 Document::retrieveParagraphIndex(ParagraphImpl const * pParagraph) 740 { 741 ::osl::MutexGuard aInternalGuard(GetMutex()); 742 743 // If a client holds on to a Paragraph that is no longer visible, it can 744 // happen that this Paragraph lies outside the range from m_aVisibleBegin 745 // to m_aVisibleEnd. In that case, return -1 instead of a valid index: 746 Paragraphs::iterator aPara(m_xParagraphs->begin() 747 + pParagraph->getNumber()); 748 return aPara < m_aVisibleBegin || aPara >= m_aVisibleEnd 749 ? -1 : static_cast< ::sal_Int32 >(aPara - m_aVisibleBegin); 750 // XXX numeric overflow 751 } 752 753 ::sal_Int64 Document::retrieveParagraphState(ParagraphImpl const * pParagraph) 754 { 755 ::osl::MutexGuard aInternalGuard(GetMutex()); 756 757 // If a client holds on to a Paragraph that is no longer visible, it can 758 // happen that this Paragraph lies outside the range from m_aVisibleBegin 759 // to m_aVisibleEnd. In that case, it is neither VISIBLE nor SHOWING: 760 ::sal_Int64 nState 761 = (static_cast< ::sal_Int64 >(1) 762 << ::css::accessibility::AccessibleStateType::ENABLED) 763 | (static_cast< ::sal_Int64 >(1) 764 << ::css::accessibility::AccessibleStateType::SENSITIVE) 765 | (static_cast< ::sal_Int64 >(1) 766 << ::css::accessibility::AccessibleStateType::FOCUSABLE) 767 | (static_cast< ::sal_Int64 >(1) 768 << ::css::accessibility::AccessibleStateType::MULTI_LINE); 769 if (!m_rView.IsReadOnly()) 770 nState |= (static_cast< ::sal_Int64 >(1) 771 << ::css::accessibility::AccessibleStateType::EDITABLE); 772 Paragraphs::iterator aPara(m_xParagraphs->begin() 773 + pParagraph->getNumber()); 774 if (aPara >= m_aVisibleBegin && aPara < m_aVisibleEnd) 775 { 776 nState 777 |= (static_cast< ::sal_Int64 >(1) 778 << ::css::accessibility::AccessibleStateType::VISIBLE) 779 | (static_cast< ::sal_Int64 >(1) 780 << ::css::accessibility::AccessibleStateType::SHOWING); 781 if (aPara == m_aFocused) 782 nState |= (static_cast< ::sal_Int64 >(1) 783 << ::css::accessibility::AccessibleStateType::FOCUSED); 784 } 785 return nState; 786 }; 787 788 ::css::awt::Rectangle 789 Document::retrieveParagraphBounds(ParagraphImpl const * pParagraph, 790 bool bAbsolute) 791 { 792 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); 793 ::osl::MutexGuard aInternalGuard(GetMutex()); 794 795 // If a client holds on to a Paragraph that is no longer visible (as it 796 // scrolled out the top of the view), it can happen that this Paragraph 797 // lies before m_aVisibleBegin. In that case, calculate the vertical 798 // position of the Paragraph starting at paragraph 0, otherwise optimize 799 // and start at m_aVisibleBegin: 800 Paragraphs::iterator aPara(m_xParagraphs->begin() 801 + pParagraph->getNumber()); 802 ::sal_Int32 nPos; 803 Paragraphs::iterator aIt; 804 if (aPara < m_aVisibleBegin) 805 { 806 nPos = 0; 807 aIt = m_xParagraphs->begin(); 808 } 809 else 810 { 811 nPos = m_nViewOffset - m_nVisibleBeginOffset; 812 aIt = m_aVisibleBegin; 813 } 814 for (; aIt != aPara; ++aIt) 815 nPos += aIt->getHeight(); 816 817 Point aOrig(0, 0); 818 if (bAbsolute) 819 aOrig = m_rView.GetWindow()->OutputToAbsoluteScreenPixel(aOrig); 820 821 return ::css::awt::Rectangle( 822 static_cast< ::sal_Int32 >(aOrig.X()), 823 static_cast< ::sal_Int32 >(aOrig.Y()) + nPos - m_nViewOffset, 824 m_rView.GetWindow()->GetOutputSizePixel().Width(), aPara->getHeight()); 825 // XXX numeric overflow (3x) 826 } 827 828 ::rtl::OUString 829 Document::retrieveParagraphText(ParagraphImpl const * pParagraph) 830 { 831 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); 832 ::osl::MutexGuard aInternalGuard(GetMutex()); 833 return m_rEngine.GetText(static_cast< ::sal_uLong >(pParagraph->getNumber())); 834 // numeric overflow cannot happen here 835 } 836 837 void Document::retrieveParagraphSelection(ParagraphImpl const * pParagraph, 838 ::sal_Int32 * pBegin, 839 ::sal_Int32 * pEnd) 840 { 841 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); 842 ::osl::MutexGuard aInternalGuard(GetMutex()); 843 ::TextSelection const & rSelection = m_rView.GetSelection(); 844 Paragraphs::size_type nNumber = pParagraph->getNumber(); 845 TextPaM aStartPaM( rSelection.GetStart() ); 846 TextPaM aEndPaM( rSelection.GetEnd() ); 847 TextPaM aMinPaM( ::std::min( aStartPaM, aEndPaM ) ); 848 TextPaM aMaxPaM( ::std::max( aStartPaM, aEndPaM ) ); 849 850 if ( nNumber >= aMinPaM.GetPara() && nNumber <= aMaxPaM.GetPara() ) 851 { 852 *pBegin = nNumber > aMinPaM.GetPara() 853 ? 0 854 : static_cast< ::sal_Int32 >( aMinPaM.GetIndex() ); 855 // XXX numeric overflow 856 *pEnd = nNumber < aMaxPaM.GetPara() 857 ? static_cast< ::sal_Int32 >( m_rEngine.GetText(static_cast< ::sal_uLong >(nNumber)).Len() ) 858 : static_cast< ::sal_Int32 >( aMaxPaM.GetIndex() ); 859 // XXX numeric overflow (3x) 860 861 if ( aStartPaM > aEndPaM ) 862 ::std::swap( *pBegin, *pEnd ); 863 } 864 else 865 { 866 *pBegin = 0; 867 *pEnd = 0; 868 } 869 } 870 871 ::sal_Int32 Document::retrieveParagraphCaretPosition(ParagraphImpl const * pParagraph) 872 { 873 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); 874 ::osl::MutexGuard aInternalGuard(GetMutex()); 875 ::TextSelection const & rSelection = m_rView.GetSelection(); 876 Paragraphs::size_type nNumber = pParagraph->getNumber(); 877 TextPaM aEndPaM( rSelection.GetEnd() ); 878 879 return aEndPaM.GetPara() == nNumber 880 ? static_cast< ::sal_Int32 >(aEndPaM.GetIndex()) : -1; 881 } 882 883 ::css::awt::Rectangle 884 Document::retrieveCharacterBounds(ParagraphImpl const * pParagraph, 885 ::sal_Int32 nIndex) 886 { 887 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); 888 ::osl::MutexGuard aInternalGuard(GetMutex()); 889 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber()); 890 sal_Int32 nLength = m_rEngine.GetText(nNumber).Len(); 891 // XXX numeric overflow 892 if (nIndex < 0 || nIndex > nLength) 893 throw ::css::lang::IndexOutOfBoundsException( 894 ::rtl::OUString( 895 RTL_CONSTASCII_USTRINGPARAM( 896 "textwindowaccessibility.cxx:" 897 " Document::retrieveCharacterAttributes")), 898 static_cast< ::css::uno::XWeak * >(this)); 899 ::css::awt::Rectangle aBounds( 0, 0, 0, 0 ); 900 if ( nIndex == nLength ) 901 { 902 aBounds = AWTRectangle( 903 m_rEngine.PaMtoEditCursor(::TextPaM(nNumber, 904 static_cast< ::sal_uInt16 >(nIndex)))); 905 } 906 else 907 { 908 ::Rectangle aLeft( 909 m_rEngine.PaMtoEditCursor(::TextPaM(nNumber, 910 static_cast< ::sal_uInt16 >(nIndex)))); 911 // XXX numeric overflow 912 ::Rectangle aRight( 913 m_rEngine.PaMtoEditCursor(::TextPaM(nNumber, 914 static_cast< ::sal_uInt16 >(nIndex) 915 + 1))); 916 // XXX numeric overflow (2x) 917 // FIXME If the vertical extends of the two cursors do not match, assume 918 // nIndex is the last character on the line; the bounding box will then 919 // extend to m_rEnginge.GetMaxTextWidth(): 920 ::sal_Int32 nWidth = (aLeft.Top() == aRight.Top() 921 && aLeft.Bottom() == aRight.Bottom()) 922 ? static_cast< ::sal_Int32 >(aRight.Left() - aLeft.Left()) 923 : static_cast< ::sal_Int32 >(m_rEngine.GetMaxTextWidth() 924 - aLeft.Left()); 925 // XXX numeric overflow (4x) 926 aBounds = ::css::awt::Rectangle(static_cast< ::sal_Int32 >(aLeft.Left()), 927 static_cast< ::sal_Int32 >(aLeft.Top() - m_nViewOffset), 928 nWidth, 929 static_cast< ::sal_Int32 >(aLeft.Bottom() 930 - aLeft.Top())); 931 // XXX numeric overflow (4x) 932 } 933 return aBounds; 934 } 935 936 ::sal_Int32 Document::retrieveCharacterIndex(ParagraphImpl const * pParagraph, 937 ::css::awt::Point const & rPoint) 938 { 939 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); 940 ::osl::MutexGuard aInternalGuard(GetMutex()); 941 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber()); 942 // XXX numeric overflow 943 ::TextPaM aPaM(m_rEngine.GetPaM(::Point(static_cast< long >(rPoint.X), 944 static_cast< long >(rPoint.Y)))); 945 // XXX numeric overflow (2x) 946 return aPaM.GetPara() == nNumber 947 ? static_cast< ::sal_Int32 >(aPaM.GetIndex()) : -1; 948 // XXX numeric overflow 949 } 950 951 struct IndexCompare 952 { 953 const ::css::beans::PropertyValue* pValues; 954 IndexCompare( const ::css::beans::PropertyValue* pVals ) : pValues(pVals) {} 955 bool operator() ( const sal_Int32& a, const sal_Int32& b ) const 956 { 957 return (pValues[a].Name < pValues[b].Name) ? true : false; 958 } 959 }; 960 961 ::css::uno::Sequence< ::css::beans::PropertyValue > 962 Document::retrieveCharacterAttributes( 963 ParagraphImpl const * pParagraph, ::sal_Int32 nIndex, 964 const ::css::uno::Sequence< ::rtl::OUString >& aRequestedAttributes) 965 { 966 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); 967 968 Font aFont = m_rEngine.GetFont(); 969 const sal_Int32 AttributeCount = 9; 970 sal_Int32 i = 0; 971 ::css::uno::Sequence< ::css::beans::PropertyValue > aAttribs( AttributeCount ); 972 //character background color 973 { 974 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharBackColor")); 975 aAttribs[i].Handle = -1; 976 aAttribs[i].Value = mapFontColor( aFont.GetFillColor() ); 977 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; 978 i++; 979 } 980 //character color 981 { 982 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharColor")); 983 aAttribs[i].Handle = -1; 984 //aAttribs[i].Value = mapFontColor( aFont.GetColor() ); 985 aAttribs[i].Value = mapFontColor( m_rEngine.GetTextColor() ); 986 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; 987 i++; 988 } 989 //character font name 990 { 991 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharFontName")); 992 aAttribs[i].Handle = -1; 993 aAttribs[i].Value = ::css::uno::makeAny( (::rtl::OUString)aFont.GetName() ); 994 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; 995 i++; 996 } 997 //character height 998 { 999 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharHeight")); 1000 aAttribs[i].Handle = -1; 1001 aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetHeight() ); 1002 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; 1003 i++; 1004 } 1005 //character posture 1006 { 1007 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharPosture")); 1008 aAttribs[i].Handle = -1; 1009 aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetItalic() ); 1010 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; 1011 i++; 1012 } 1013 //character relief 1014 /*{ 1015 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharRelief")); 1016 aAttribs[i].Handle = -1; 1017 aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetRelief() ); 1018 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; 1019 i++; 1020 }*/ 1021 //character strikeout 1022 { 1023 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharStrikeout")); 1024 aAttribs[i].Handle = -1; 1025 aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetStrikeout() ); 1026 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; 1027 i++; 1028 } 1029 //character underline 1030 { 1031 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharUnderline")); 1032 aAttribs[i].Handle = -1; 1033 aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetUnderline() ); 1034 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; 1035 i++; 1036 } 1037 //character weight 1038 { 1039 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharWeight")); 1040 aAttribs[i].Handle = -1; 1041 aAttribs[i].Value = ::css::uno::makeAny( (float)aFont.GetWeight() ); 1042 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; 1043 i++; 1044 } 1045 //character alignment 1046 { 1047 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ParaAdjust")); 1048 aAttribs[i].Handle = -1; 1049 aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)m_rEngine.GetTextAlign() ); 1050 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; 1051 i++; 1052 } 1053 ::osl::MutexGuard aInternalGuard(GetMutex()); 1054 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber()); 1055 // XXX numeric overflow 1056 // nIndex can be equal to Len(); 1057 //if (nIndex < 0 || nIndex >= m_rEngine.GetText(nNumber).Len()) 1058 if (nIndex < 0 || nIndex > m_rEngine.GetText(nNumber).Len()) 1059 throw ::css::lang::IndexOutOfBoundsException( 1060 ::rtl::OUString( 1061 RTL_CONSTASCII_USTRINGPARAM( 1062 "textwindowaccessibility.cxx:" 1063 " Document::retrieveCharacterAttributes")), 1064 static_cast< ::css::uno::XWeak * >(this)); 1065 1066 // retrieve default attributes 1067 tPropValMap aCharAttrSeq; 1068 retrieveDefaultAttributesImpl( pParagraph, aRequestedAttributes, aCharAttrSeq ); 1069 1070 // retrieve run attributes 1071 tPropValMap aRunAttrSeq; 1072 retrieveRunAttributesImpl( pParagraph, nIndex, aRequestedAttributes, aRunAttrSeq ); 1073 1074 // merge default and run attributes 1075 for ( tPropValMap::const_iterator aRunIter = aRunAttrSeq.begin(); 1076 aRunIter != aRunAttrSeq.end(); 1077 ++aRunIter ) 1078 { 1079 aCharAttrSeq[ aRunIter->first ] = aRunIter->second; 1080 } 1081 1082 ::css::beans::PropertyValue* pValues = aAttribs.getArray(); 1083 for (i = 0; i < AttributeCount; i++,pValues++) 1084 { 1085 aCharAttrSeq[ pValues->Name ] = *pValues; 1086 } 1087 1088 ::css::uno::Sequence< ::css::beans::PropertyValue > aRes = convertHashMapToSequence( aCharAttrSeq ); 1089 1090 // sort the attributes 1091 sal_Int32 nLength = aRes.getLength(); 1092 const ::css::beans::PropertyValue* pPairs = aRes.getConstArray(); 1093 sal_Int32* pIndices = new sal_Int32[nLength]; 1094 for( i = 0; i < nLength; i++ ) 1095 pIndices[i] = i; 1096 std::sort( &pIndices[0], &pIndices[nLength], IndexCompare(pPairs) ); 1097 // create sorted sequences according to index array 1098 ::css::uno::Sequence< ::css::beans::PropertyValue > aNewValues( nLength ); 1099 ::css::beans::PropertyValue* pNewValues = aNewValues.getArray(); 1100 for( i = 0; i < nLength; i++ ) 1101 { 1102 pNewValues[i] = pPairs[pIndices[i]]; 1103 } 1104 delete[] pIndices; 1105 1106 return aNewValues; 1107 } 1108 1109 void Document::retrieveDefaultAttributesImpl( 1110 ParagraphImpl const * pParagraph, 1111 const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes, 1112 tPropValMap& rDefAttrSeq) 1113 { 1114 // default attributes are not supported by text engine 1115 (void) pParagraph; 1116 (void) RequestedAttributes; 1117 (void) rDefAttrSeq; 1118 } 1119 1120 ::css::uno::Sequence< ::css::beans::PropertyValue > 1121 Document::retrieveDefaultAttributes( 1122 ParagraphImpl const * pParagraph, 1123 const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes) 1124 { 1125 ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() ); 1126 ::osl::MutexGuard aInternalGuard( GetMutex() ); 1127 1128 tPropValMap aDefAttrSeq; 1129 retrieveDefaultAttributesImpl( pParagraph, RequestedAttributes, aDefAttrSeq ); 1130 return convertHashMapToSequence( aDefAttrSeq ); 1131 } 1132 1133 // static 1134 ::css::uno::Sequence< ::css::beans::PropertyValue > 1135 Document::convertHashMapToSequence(tPropValMap& rAttrSeq) 1136 { 1137 ::css::uno::Sequence< ::css::beans::PropertyValue > aValues( rAttrSeq.size() ); 1138 ::css::beans::PropertyValue* pValues = aValues.getArray(); 1139 ::sal_Int32 i = 0; 1140 for ( tPropValMap::const_iterator aIter = rAttrSeq.begin(); 1141 aIter != rAttrSeq.end(); 1142 ++aIter ) 1143 { 1144 pValues[i] = aIter->second; 1145 ++i; 1146 } 1147 return aValues; 1148 } 1149 1150 void Document::retrieveRunAttributesImpl( 1151 ParagraphImpl const * pParagraph, ::sal_Int32 Index, 1152 const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes, 1153 tPropValMap& rRunAttrSeq) 1154 { 1155 ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() ); 1156 ::TextPaM aPaM( nNumber, static_cast< ::sal_uInt16 >( Index ) ); 1157 // XXX numeric overflow 1158 // FIXME TEXTATTR_HYPERLINK ignored: 1159 ::TextAttribFontColor const * pColor 1160 = static_cast< ::TextAttribFontColor const * >( 1161 m_rEngine.FindAttrib( aPaM, TEXTATTR_FONTCOLOR ) ); 1162 ::TextAttribFontWeight const * pWeight 1163 = static_cast< ::TextAttribFontWeight const * >( 1164 m_rEngine.FindAttrib( aPaM, TEXTATTR_FONTWEIGHT ) ); 1165 tPropValMap aRunAttrSeq; 1166 if ( pColor ) 1167 { 1168 ::css::beans::PropertyValue aPropVal; 1169 aPropVal.Name = 1170 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CharColor" ) ); 1171 aPropVal.Handle = -1; 1172 aPropVal.Value = mapFontColor( pColor->GetColor() ); 1173 aPropVal.State = ::css::beans::PropertyState_DIRECT_VALUE; 1174 aRunAttrSeq[ aPropVal.Name ] = aPropVal; 1175 } 1176 if ( pWeight ) 1177 { 1178 ::css::beans::PropertyValue aPropVal; 1179 aPropVal.Name = 1180 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CharWeight" ) ); 1181 aPropVal.Handle = -1; 1182 aPropVal.Value = mapFontWeight( pWeight->getFontWeight() ); 1183 aPropVal.State = ::css::beans::PropertyState_DIRECT_VALUE; 1184 aRunAttrSeq[ aPropVal.Name ] = aPropVal; 1185 } 1186 if ( RequestedAttributes.getLength() == 0 ) 1187 { 1188 rRunAttrSeq = aRunAttrSeq; 1189 } 1190 else 1191 { 1192 const ::rtl::OUString* pReqAttrs = RequestedAttributes.getConstArray(); 1193 const ::sal_Int32 nLength = RequestedAttributes.getLength(); 1194 for ( ::sal_Int32 i = 0; i < nLength; ++i ) 1195 { 1196 tPropValMap::iterator aIter = aRunAttrSeq.find( pReqAttrs[i] ); 1197 if ( aIter != aRunAttrSeq.end() ) 1198 { 1199 rRunAttrSeq[ (*aIter).first ] = (*aIter).second; 1200 } 1201 } 1202 } 1203 } 1204 1205 ::css::uno::Sequence< ::css::beans::PropertyValue > 1206 Document::retrieveRunAttributes( 1207 ParagraphImpl const * pParagraph, ::sal_Int32 Index, 1208 const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes) 1209 { 1210 ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() ); 1211 ::osl::MutexGuard aInternalGuard( GetMutex() ); 1212 ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() ); 1213 // XXX numeric overflow 1214 if ( Index < 0 || Index >= m_rEngine.GetText(nNumber).Len() ) 1215 throw ::css::lang::IndexOutOfBoundsException( 1216 ::rtl::OUString( 1217 RTL_CONSTASCII_USTRINGPARAM( 1218 "textwindowaccessibility.cxx:" 1219 " Document::retrieveRunAttributes") ), 1220 static_cast< ::css::uno::XWeak * >( this ) ); 1221 1222 tPropValMap aRunAttrSeq; 1223 retrieveRunAttributesImpl( pParagraph, Index, RequestedAttributes, aRunAttrSeq ); 1224 return convertHashMapToSequence( aRunAttrSeq ); 1225 } 1226 1227 void Document::changeParagraphText(ParagraphImpl * pParagraph, 1228 ::rtl::OUString const & rText) 1229 { 1230 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); 1231 { 1232 ::osl::MutexGuard aInternalGuard(GetMutex()); 1233 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber()); 1234 // XXX numeric overflow 1235 changeParagraphText(nNumber, 0, m_rEngine.GetTextLen(nNumber), false, 1236 false, rText); 1237 } 1238 } 1239 1240 void Document::changeParagraphText(ParagraphImpl * pParagraph, 1241 ::sal_Int32 nBegin, ::sal_Int32 nEnd, 1242 bool bCut, bool bPaste, 1243 ::rtl::OUString const & rText) 1244 { 1245 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); 1246 { 1247 ::osl::MutexGuard aInternalGuard(GetMutex()); 1248 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber()); 1249 // XXX numeric overflow 1250 if (nBegin < 0 || nBegin > nEnd 1251 || nEnd > m_rEngine.GetText(nNumber).Len()) 1252 throw ::css::lang::IndexOutOfBoundsException( 1253 ::rtl::OUString( 1254 RTL_CONSTASCII_USTRINGPARAM( 1255 "textwindowaccessibility.cxx:" 1256 " Document::changeParagraphText")), 1257 static_cast< ::css::uno::XWeak * >(this)); 1258 changeParagraphText(nNumber, static_cast< ::sal_uInt16 >(nBegin), 1259 static_cast< ::sal_uInt16 >(nEnd), bCut, bPaste, rText); 1260 // XXX numeric overflow (2x) 1261 } 1262 } 1263 1264 void Document::copyParagraphText(ParagraphImpl const * pParagraph, 1265 ::sal_Int32 nBegin, ::sal_Int32 nEnd) 1266 { 1267 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); 1268 { 1269 ::osl::MutexGuard aInternalGuard(GetMutex()); 1270 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber()); 1271 // XXX numeric overflow 1272 if (nBegin < 0 || nBegin > nEnd 1273 || nEnd > m_rEngine.GetText(nNumber).Len()) 1274 throw ::css::lang::IndexOutOfBoundsException( 1275 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 1276 "textwindowaccessibility.cxx:" 1277 " Document::copyParagraphText")), 1278 static_cast< ::css::uno::XWeak * >(this)); 1279 m_rView.SetSelection( 1280 ::TextSelection(::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nBegin)), 1281 ::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nEnd)))); 1282 // XXX numeric overflow (2x) 1283 m_rView.Copy(); 1284 } 1285 } 1286 1287 void Document::changeParagraphAttributes( 1288 ParagraphImpl * pParagraph, ::sal_Int32 nBegin, ::sal_Int32 nEnd, 1289 ::css::uno::Sequence< ::css::beans::PropertyValue > const & rAttributeSet) 1290 { 1291 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); 1292 { 1293 ::osl::MutexGuard aInternalGuard(GetMutex()); 1294 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber()); 1295 // XXX numeric overflow 1296 if (nBegin < 0 || nBegin > nEnd 1297 || nEnd > m_rEngine.GetText(nNumber).Len()) 1298 throw ::css::lang::IndexOutOfBoundsException( 1299 ::rtl::OUString( 1300 RTL_CONSTASCII_USTRINGPARAM( 1301 "textwindowaccessibility.cxx:" 1302 " Document::changeParagraphAttributes")), 1303 static_cast< ::css::uno::XWeak * >(this)); 1304 1305 // FIXME The new attributes are added to any attributes already set, 1306 // they do not replace the old attributes as required by 1307 // XAccessibleEditableText.setAttributes: 1308 for (::sal_Int32 i = 0; i < rAttributeSet.getLength(); ++i) 1309 if (rAttributeSet[i].Name.equalsAsciiL( 1310 RTL_CONSTASCII_STRINGPARAM("CharColor"))) 1311 m_rEngine.SetAttrib(::TextAttribFontColor( 1312 mapFontColor(rAttributeSet[i].Value)), 1313 nNumber, static_cast< ::sal_uInt16 >(nBegin), 1314 static_cast< ::sal_uInt16 >(nEnd)); 1315 // XXX numeric overflow (2x) 1316 else if (rAttributeSet[i].Name.equalsAsciiL( 1317 RTL_CONSTASCII_STRINGPARAM("CharWeight"))) 1318 m_rEngine.SetAttrib(::TextAttribFontWeight( 1319 mapFontWeight(rAttributeSet[i].Value)), 1320 nNumber, static_cast< ::sal_uInt16 >(nBegin), 1321 static_cast< ::sal_uInt16 >(nEnd)); 1322 // XXX numeric overflow (2x) 1323 } 1324 } 1325 1326 void Document::changeParagraphSelection(ParagraphImpl * pParagraph, 1327 ::sal_Int32 nBegin, ::sal_Int32 nEnd) 1328 { 1329 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); 1330 { 1331 ::osl::MutexGuard aInternalGuard(GetMutex()); 1332 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber()); 1333 // XXX numeric overflow 1334 if (nBegin < 0 || nBegin > nEnd 1335 || nEnd > m_rEngine.GetText(nNumber).Len()) 1336 throw ::css::lang::IndexOutOfBoundsException( 1337 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 1338 "textwindowaccessibility.cxx:" 1339 " Document::changeParagraphSelection")), 1340 static_cast< ::css::uno::XWeak * >(this)); 1341 m_rView.SetSelection( 1342 ::TextSelection(::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nBegin)), 1343 ::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nEnd)))); 1344 // XXX numeric overflow (2x) 1345 } 1346 } 1347 1348 ::css::i18n::Boundary 1349 Document::retrieveParagraphLineBoundary( ParagraphImpl const * pParagraph, 1350 ::sal_Int32 nIndex, ::sal_Int32 *pLineNo ) 1351 { 1352 ::css::i18n::Boundary aBoundary; 1353 aBoundary.startPos = nIndex; 1354 aBoundary.endPos = nIndex; 1355 1356 ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() ); 1357 { 1358 ::osl::MutexGuard aInternalGuard( GetMutex() ); 1359 ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() ); 1360 if ( nIndex < 0 || nIndex > m_rEngine.GetText( nNumber ).Len() ) 1361 throw ::css::lang::IndexOutOfBoundsException( 1362 ::rtl::OUString( 1363 RTL_CONSTASCII_USTRINGPARAM( 1364 "textwindowaccessibility.cxx:" 1365 " Document::retrieveParagraphLineBoundary" ) ), 1366 static_cast< ::css::uno::XWeak * >( this ) ); 1367 ::sal_Int32 nLineStart = 0; 1368 ::sal_Int32 nLineEnd = 0; 1369 ::sal_uInt16 nLineCount = m_rEngine.GetLineCount( nNumber ); 1370 for ( ::sal_uInt16 nLine = 0; nLine < nLineCount; ++nLine ) 1371 { 1372 ::sal_Int32 nLineLength = static_cast< ::sal_Int32 >( 1373 m_rEngine.GetLineLen( nNumber, nLine ) ); 1374 nLineStart = nLineEnd; 1375 nLineEnd += nLineLength; 1376 if ( nIndex >= nLineStart && ( ( nLine == nLineCount - 1 ) ? nIndex <= nLineEnd : nIndex < nLineEnd ) ) 1377 { 1378 aBoundary.startPos = nLineStart; 1379 aBoundary.endPos = nLineEnd; 1380 if( pLineNo ) 1381 pLineNo[0] = nLine; 1382 break; 1383 } 1384 } 1385 } 1386 1387 return aBoundary; 1388 } 1389 1390 ::css::i18n::Boundary 1391 Document::retrieveParagraphBoundaryOfLine( ParagraphImpl const * pParagraph, 1392 ::sal_Int32 nLineNo ) 1393 { 1394 ::css::i18n::Boundary aBoundary; 1395 aBoundary.startPos = 0; 1396 aBoundary.endPos = 0; 1397 1398 ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() ); 1399 { 1400 ::osl::MutexGuard aInternalGuard( GetMutex() ); 1401 ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() ); 1402 if ( nLineNo >= m_rEngine.GetLineCount( nNumber ) ) 1403 throw ::css::lang::IndexOutOfBoundsException( 1404 ::rtl::OUString( 1405 RTL_CONSTASCII_USTRINGPARAM( 1406 "textwindowaccessibility.cxx:" 1407 " Document::retrieveParagraphBoundaryOfLine" ) ), 1408 static_cast< ::css::uno::XWeak * >( this ) ); 1409 ::sal_Int32 nLineStart = 0; 1410 ::sal_Int32 nLineEnd = 0; 1411 for ( ::sal_uInt16 nLine = 0; nLine <= nLineNo; ++nLine ) 1412 { 1413 ::sal_Int32 nLineLength = static_cast< ::sal_Int32 >( 1414 m_rEngine.GetLineLen( nNumber, nLine ) ); 1415 nLineStart = nLineEnd; 1416 nLineEnd += nLineLength; 1417 } 1418 1419 aBoundary.startPos = nLineStart; 1420 aBoundary.endPos = nLineEnd; 1421 } 1422 1423 return aBoundary; 1424 } 1425 1426 sal_Int32 Document::retrieveParagraphLineWithCursor( ParagraphImpl const * pParagraph ) 1427 { 1428 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); 1429 ::osl::MutexGuard aInternalGuard(GetMutex()); 1430 ::TextSelection const & rSelection = m_rView.GetSelection(); 1431 Paragraphs::size_type nNumber = pParagraph->getNumber(); 1432 TextPaM aEndPaM( rSelection.GetEnd() ); 1433 1434 return aEndPaM.GetPara() == nNumber 1435 ? m_rView.GetLineNumberOfCursorInSelection() : -1; 1436 } 1437 1438 1439 ::css::uno::Reference< ::css::accessibility::XAccessibleRelationSet > 1440 Document::retrieveParagraphRelationSet( ParagraphImpl const * pParagraph ) 1441 { 1442 ::osl::MutexGuard aInternalGuard( GetMutex() ); 1443 1444 ::utl::AccessibleRelationSetHelper* pRelationSetHelper = new ::utl::AccessibleRelationSetHelper(); 1445 ::css::uno::Reference< ::css::accessibility::XAccessibleRelationSet > xSet = pRelationSetHelper; 1446 1447 Paragraphs::iterator aPara( m_xParagraphs->begin() + pParagraph->getNumber() ); 1448 1449 if ( aPara > m_aVisibleBegin && aPara < m_aVisibleEnd ) 1450 { 1451 ::css::uno::Sequence< ::css::uno::Reference< ::css::uno::XInterface > > aSequence(1); 1452 aSequence[0] = getAccessibleChild( aPara - 1 ); 1453 ::css::accessibility::AccessibleRelation aRelation( ::css::accessibility::AccessibleRelationType::CONTENT_FLOWS_FROM, aSequence ); 1454 pRelationSetHelper->AddRelation( aRelation ); 1455 } 1456 1457 if ( aPara >= m_aVisibleBegin && aPara < m_aVisibleEnd -1 ) 1458 { 1459 ::css::uno::Sequence< ::css::uno::Reference< ::css::uno::XInterface > > aSequence(1); 1460 aSequence[0] = getAccessibleChild( aPara + 1 ); 1461 ::css::accessibility::AccessibleRelation aRelation( ::css::accessibility::AccessibleRelationType::CONTENT_FLOWS_TO, aSequence ); 1462 pRelationSetHelper->AddRelation( aRelation ); 1463 } 1464 1465 return xSet; 1466 } 1467 1468 void Document::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent ) 1469 { 1470 VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent ); 1471 } 1472 1473 // virtual 1474 ::sal_Int32 SAL_CALL Document::getAccessibleChildCount() 1475 { 1476 ::comphelper::OExternalLockGuard aGuard(this); 1477 init(); 1478 return m_aVisibleEnd - m_aVisibleBegin; 1479 } 1480 1481 // virtual 1482 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL 1483 Document::getAccessibleChild(::sal_Int32 i) 1484 { 1485 ::comphelper::OExternalLockGuard aGuard(this); 1486 init(); 1487 if (i < 0 || i >= m_aVisibleEnd - m_aVisibleBegin) 1488 throw ::css::lang::IndexOutOfBoundsException( 1489 ::rtl::OUString( 1490 RTL_CONSTASCII_USTRINGPARAM( 1491 "textwindowaccessibility.cxx:" 1492 " Document::getAccessibleChild")), 1493 static_cast< ::css::uno::XWeak * >(this)); 1494 return getAccessibleChild(m_aVisibleBegin 1495 + static_cast< Paragraphs::size_type >(i)); 1496 } 1497 1498 // virtual 1499 ::sal_Int16 SAL_CALL Document::getAccessibleRole() 1500 { 1501 return ::css::accessibility::AccessibleRole::TEXT_FRAME; 1502 } 1503 1504 // virtual 1505 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL 1506 Document::getAccessibleAtPoint(::css::awt::Point const & rPoint) 1507 { 1508 ::comphelper::OExternalLockGuard aGuard(this); 1509 init(); 1510 if (rPoint.X >= 0 1511 && rPoint.X < m_rView.GetWindow()->GetOutputSizePixel().Width() 1512 && rPoint.Y >= 0 && rPoint.Y < m_nViewHeight) 1513 { 1514 ::sal_Int32 nOffset = m_nViewOffset + rPoint.Y; // XXX numeric overflow 1515 ::sal_Int32 nPos = m_nViewOffset - m_nVisibleBeginOffset; 1516 for (Paragraphs::iterator aIt(m_aVisibleBegin); aIt != m_aVisibleEnd; 1517 ++aIt) 1518 { 1519 nPos += aIt->getHeight(); // XXX numeric overflow 1520 if (nOffset < nPos) 1521 return getAccessibleChild(aIt); 1522 } 1523 } 1524 return 0; 1525 } 1526 void Document::FillAccessibleStateSet( utl::AccessibleStateSetHelper& rStateSet ) 1527 { 1528 VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet ); 1529 if (!m_rView.IsReadOnly()) 1530 rStateSet.AddState( ::css::accessibility::AccessibleStateType::EDITABLE ); 1531 } 1532 1533 void Document::FillAccessibleRelationSet( utl::AccessibleRelationSetHelper& rRelationSet ) 1534 { 1535 if( getAccessibleParent()->getAccessibleContext()->getAccessibleRole() == ::css::accessibility::AccessibleRole::SCROLL_PANE ) 1536 { 1537 ::css::uno::Sequence< ::css::uno::Reference< ::css::uno::XInterface > > aSequence(1); 1538 aSequence[0] = getAccessibleParent(); 1539 rRelationSet.AddRelation( ::css::accessibility::AccessibleRelation( ::css::accessibility::AccessibleRelationType::MEMBER_OF, aSequence ) ); 1540 } 1541 else 1542 { 1543 VCLXAccessibleComponent::FillAccessibleRelationSet(rRelationSet); 1544 } 1545 } 1546 // virtual 1547 void SAL_CALL Document::disposing() 1548 { 1549 m_aEngineListener.endListening(); 1550 m_aViewListener.endListening(); 1551 if (m_xParagraphs.get() != 0) 1552 disposeParagraphs(); 1553 VCLXAccessibleComponent::disposing(); 1554 } 1555 1556 // virtual 1557 void Document::Notify(::SfxBroadcaster &, ::SfxHint const & rHint) 1558 { 1559 if (rHint.ISA(::TextHint)) 1560 { 1561 ::TextHint const & rTextHint 1562 = static_cast< ::TextHint const & >(rHint); 1563 switch (rTextHint.GetId()) 1564 { 1565 case TEXT_HINT_PARAINSERTED: 1566 case TEXT_HINT_PARAREMOVED: 1567 // TEXT_HINT_PARAINSERTED and TEXT_HINT_PARAREMOVED are sent at 1568 // "unsafe" times (when the text engine has not yet re-formatted its 1569 // content), so that for example calling ::TextEngine::GetTextHeight 1570 // from within the code that handles TEXT_HINT_PARAINSERTED causes 1571 // trouble within the text engine. Therefore, these hints are just 1572 // buffered until a following ::TextEngine::FormatDoc causes a 1573 // TEXT_HINT_TEXTFORMATTED to come in: 1574 case TEXT_HINT_FORMATPARA: 1575 // ::TextEngine::FormatDoc sends a sequence of 1576 // TEXT_HINT_FORMATPARAs, followed by an optional 1577 // TEXT_HINT_TEXTHEIGHTCHANGED, followed in all cases by one 1578 // TEXT_HINT_TEXTFORMATTED. Only the TEXT_HINT_FORMATPARAs contain 1579 // the numbers of the affected paragraphs, but they are sent 1580 // before the changes are applied. Therefore, TEXT_HINT_FORMATPARAs 1581 // are just buffered until another hint comes in: 1582 { 1583 ::osl::MutexGuard aInternalGuard(GetMutex()); 1584 if (!isAlive()) 1585 break; 1586 1587 m_aParagraphNotifications.push(rTextHint); 1588 break; 1589 } 1590 case TEXT_HINT_TEXTFORMATTED: 1591 case TEXT_HINT_TEXTHEIGHTCHANGED: 1592 case TEXT_HINT_MODIFIED: 1593 { 1594 ::osl::MutexGuard aInternalGuard(GetMutex()); 1595 if (!isAlive()) 1596 break; 1597 handleParagraphNotifications(); 1598 break; 1599 } 1600 case TEXT_HINT_VIEWSCROLLED: 1601 { 1602 ::osl::MutexGuard aInternalGuard(GetMutex()); 1603 if (!isAlive()) 1604 break; 1605 handleParagraphNotifications(); 1606 1607 ::sal_Int32 nOffset = static_cast< ::sal_Int32 >( 1608 m_rView.GetStartDocPos().Y()); 1609 // XXX numeric overflow 1610 if (nOffset != m_nViewOffset) 1611 { 1612 m_nViewOffset = nOffset; 1613 1614 Paragraphs::iterator aOldVisibleBegin( 1615 m_aVisibleBegin); 1616 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd); 1617 1618 determineVisibleRange(); 1619 1620 notifyVisibleRangeChanges(aOldVisibleBegin, 1621 aOldVisibleEnd, 1622 m_xParagraphs->end()); 1623 } 1624 break; 1625 } 1626 case TEXT_HINT_VIEWSELECTIONCHANGED: 1627 { 1628 ::osl::MutexGuard aInternalGuard(GetMutex()); 1629 if (!isAlive()) 1630 break; 1631 1632 if (m_aParagraphNotifications.empty()) 1633 { 1634 handleSelectionChangeNotification(); 1635 } 1636 else 1637 { 1638 // TEXT_HINT_VIEWSELECTIONCHANGED is sometimes sent at 1639 // "unsafe" times (when the text engine has not yet re- 1640 // formatted its content), so that for example calling 1641 // ::TextEngine::GetTextHeight from within the code that 1642 // handles a previous TEXT_HINT_PARAINSERTED causes 1643 // trouble within the text engine. Therefore, these 1644 // hints are just buffered (along with 1645 // TEXT_HINT_PARAINSERTED/REMOVED/FORMATPARA) until a 1646 // following ::TextEngine::FormatDoc causes a 1647 // TEXT_HINT_TEXTFORMATTED to come in: 1648 m_bSelectionChangedNotification = true; 1649 } 1650 break; 1651 } 1652 } 1653 } 1654 } 1655 1656 IMPL_LINK(Document, WindowEventHandler, ::VclSimpleEvent *, pEvent) 1657 { 1658 switch (pEvent->GetId()) 1659 { 1660 case VCLEVENT_WINDOW_RESIZE: 1661 { 1662 ::osl::MutexGuard aInternalGuard(GetMutex()); 1663 if (!isAlive()) 1664 break; 1665 1666 ::sal_Int32 nHeight = static_cast< ::sal_Int32 >( 1667 m_rView.GetWindow()->GetOutputSizePixel().Height()); 1668 // XXX numeric overflow 1669 if (nHeight != m_nViewHeight) 1670 { 1671 m_nViewHeight = nHeight; 1672 1673 Paragraphs::iterator aOldVisibleBegin(m_aVisibleBegin); 1674 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd); 1675 1676 determineVisibleRange(); 1677 1678 notifyVisibleRangeChanges(aOldVisibleBegin, aOldVisibleEnd, 1679 m_xParagraphs->end()); 1680 } 1681 break; 1682 } 1683 case VCLEVENT_WINDOW_GETFOCUS: 1684 { 1685 ::osl::MutexGuard aInternalGuard(GetMutex()); 1686 if (!isAlive()) 1687 break; 1688 //to enable the PARAGRAPH to get focus for multiline edit 1689 ::sal_Int32 count = getAccessibleChildCount(); 1690 ::sal_Bool bEmpty = m_aFocused == m_aVisibleEnd && count == 1; 1691 if ((m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd) || bEmpty) 1692 { 1693 Paragraphs::iterator m_aTemp = bEmpty ? m_aVisibleBegin : m_aFocused; 1694 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(m_aTemp)); 1695 if (xParagraph.is()) 1696 { 1697 xParagraph->notifyEvent( 1698 ::css::accessibility::AccessibleEventId:: 1699 STATE_CHANGED, 1700 ::css::uno::Any(), 1701 ::css::uno::makeAny( 1702 ::css::accessibility::AccessibleStateType:: 1703 FOCUSED)); 1704 } 1705 } 1706 /* 1707 ::rtl::Reference< ParagraphImpl > xParagraph( 1708 getParagraph(m_aFocused)); 1709 if (xParagraph.is()) 1710 xParagraph->notifyEvent( 1711 ::css::accessibility::AccessibleEventId:: 1712 STATE_CHANGED, 1713 ::css::uno::Any(), 1714 ::css::uno::makeAny( 1715 ::css::accessibility::AccessibleStateType:: 1716 FOCUSED)); 1717 */ 1718 break; 1719 } 1720 case VCLEVENT_WINDOW_LOSEFOCUS: 1721 { 1722 ::osl::MutexGuard aInternalGuard(GetMutex()); 1723 if (!isAlive()) 1724 break; 1725 //to enable the PARAGRAPH to get focus for multiline edit 1726 ::sal_Int32 count = getAccessibleChildCount(); 1727 ::sal_Bool bEmpty = m_aFocused == m_aVisibleEnd && count == 1; 1728 if ((m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd) || bEmpty) 1729 { 1730 Paragraphs::iterator m_aTemp = bEmpty ? m_aVisibleBegin : m_aFocused; 1731 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(m_aTemp)); 1732 if (xParagraph.is()) 1733 xParagraph->notifyEvent( 1734 ::css::accessibility::AccessibleEventId:: 1735 STATE_CHANGED, 1736 ::css::uno::makeAny( 1737 ::css::accessibility::AccessibleStateType:: 1738 FOCUSED), 1739 ::css::uno::Any()); 1740 } 1741 1742 /* 1743 if (m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd) 1744 { 1745 ::rtl::Reference< ParagraphImpl > xParagraph( 1746 getParagraph(m_aFocused)); 1747 if (xParagraph.is()) 1748 xParagraph->notifyEvent( 1749 ::css::accessibility::AccessibleEventId:: 1750 STATE_CHANGED, 1751 ::css::uno::makeAny( 1752 ::css::accessibility::AccessibleStateType:: 1753 FOCUSED), 1754 ::css::uno::Any()); 1755 } 1756 */ 1757 break; 1758 } 1759 } 1760 return 0; 1761 } 1762 1763 void Document::init() 1764 { 1765 if (m_xParagraphs.get() == 0) 1766 { 1767 ::sal_uLong nCount = m_rEngine.GetParagraphCount(); 1768 ::std::auto_ptr< Paragraphs > p(new Paragraphs); 1769 p->reserve(static_cast< Paragraphs::size_type >(nCount)); 1770 // numeric overflow is harmless here 1771 for (::sal_uLong i = 0; i < nCount; ++i) 1772 p->push_back(ParagraphInfo(static_cast< ::sal_Int32 >( 1773 m_rEngine.GetTextHeight(i)))); 1774 // XXX numeric overflow 1775 m_nViewOffset = static_cast< ::sal_Int32 >( 1776 m_rView.GetStartDocPos().Y()); // XXX numeric overflow 1777 m_nViewHeight = static_cast< ::sal_Int32 >( 1778 m_rView.GetWindow()->GetOutputSizePixel().Height()); 1779 // XXX numeric overflow 1780 m_xParagraphs = p; 1781 determineVisibleRange(); 1782 m_nSelectionFirstPara = -1; 1783 m_nSelectionFirstPos = -1; 1784 m_nSelectionLastPara = -1; 1785 m_nSelectionLastPos = -1; 1786 m_aFocused = m_xParagraphs->end(); 1787 m_bSelectionChangedNotification = false; 1788 m_aEngineListener.startListening(m_rEngine); 1789 m_aViewListener.startListening(*m_rView.GetWindow()); 1790 } 1791 } 1792 1793 ::rtl::Reference< ParagraphImpl > 1794 Document::getParagraph(Paragraphs::iterator const & rIt) 1795 { 1796 return static_cast< ParagraphImpl * >( 1797 ::css::uno::Reference< ::css::accessibility::XAccessible >( 1798 rIt->getParagraph()).get()); 1799 } 1800 1801 ::css::uno::Reference< ::css::accessibility::XAccessible > 1802 Document::getAccessibleChild(Paragraphs::iterator const & rIt) 1803 { 1804 ::css::uno::Reference< ::css::accessibility::XAccessible > xParagraph( 1805 rIt->getParagraph()); 1806 if (!xParagraph.is()) 1807 { 1808 xParagraph = new Paragraph(this, rIt - m_xParagraphs->begin()); 1809 rIt->setParagraph(xParagraph); 1810 } 1811 return xParagraph; 1812 } 1813 1814 void Document::determineVisibleRange() 1815 { 1816 m_aVisibleBegin = m_xParagraphs->end(); 1817 m_aVisibleEnd = m_aVisibleBegin; 1818 ::sal_Int32 nPos = 0; 1819 for (Paragraphs::iterator aIt = m_xParagraphs->begin();;) 1820 { 1821 if (aIt == m_xParagraphs->end()) 1822 { 1823 m_nVisibleBeginOffset = 0; 1824 break; 1825 } 1826 ::sal_Int32 nOldPos = nPos; 1827 nPos += aIt->getHeight(); // XXX numeric overflow 1828 if (m_aVisibleBegin == m_xParagraphs->end() && nPos >= m_nViewOffset) 1829 { 1830 m_aVisibleBegin = aIt; 1831 m_nVisibleBeginOffset = m_nViewOffset - nOldPos; 1832 } 1833 ++aIt; 1834 if (m_aVisibleBegin != m_xParagraphs->end() 1835 && (aIt == m_xParagraphs->end() 1836 || nPos >= m_nViewOffset + m_nViewHeight)) 1837 // XXX numeric overflow 1838 { 1839 m_aVisibleEnd = aIt; 1840 break; 1841 } 1842 } 1843 } 1844 1845 void Document::notifyVisibleRangeChanges( 1846 Paragraphs::iterator const & rOldVisibleBegin, 1847 Paragraphs::iterator const & rOldVisibleEnd, 1848 Paragraphs::iterator const & rInserted) 1849 { 1850 // XXX Replace this code that determines which paragraphs have changed from 1851 // invisible to visible or vice versa with a better algorithm. 1852 {for (Paragraphs::iterator aIt(rOldVisibleBegin); aIt != rOldVisibleEnd; 1853 ++aIt) 1854 if (aIt != rInserted 1855 && (aIt < m_aVisibleBegin || aIt >= m_aVisibleEnd)) 1856 NotifyAccessibleEvent( 1857 ::css::accessibility::AccessibleEventId:: 1858 CHILD, 1859 ::css::uno::makeAny(getAccessibleChild(aIt)), 1860 ::css::uno::Any()); 1861 } 1862 {for (Paragraphs::iterator aIt(m_aVisibleBegin); aIt != m_aVisibleEnd; 1863 ++aIt) 1864 if (aIt == rInserted 1865 || aIt < rOldVisibleBegin || aIt >= rOldVisibleEnd) 1866 NotifyAccessibleEvent( 1867 ::css::accessibility::AccessibleEventId:: 1868 CHILD, 1869 ::css::uno::Any(), 1870 ::css::uno::makeAny(getAccessibleChild(aIt))); 1871 } 1872 } 1873 1874 void 1875 Document::changeParagraphText(::sal_uLong nNumber, ::sal_uInt16 nBegin, ::sal_uInt16 nEnd, 1876 bool bCut, bool bPaste, 1877 ::rtl::OUString const & rText) 1878 { 1879 m_rView.SetSelection(::TextSelection(::TextPaM(nNumber, nBegin), 1880 ::TextPaM(nNumber, nEnd))); 1881 if (bCut) 1882 m_rView.Cut(); 1883 else if (nBegin != nEnd) 1884 m_rView.DeleteSelected(); 1885 if (bPaste) 1886 m_rView.Paste(); 1887 else if ( !rText.isEmpty() ) 1888 m_rView.InsertText(rText); 1889 } 1890 1891 void Document::handleParagraphNotifications() 1892 { 1893 while (!m_aParagraphNotifications.empty()) 1894 { 1895 ::TextHint aHint(m_aParagraphNotifications.front()); 1896 m_aParagraphNotifications.pop(); 1897 switch (aHint.GetId()) 1898 { 1899 case TEXT_HINT_PARAINSERTED: 1900 { 1901 ::sal_uLong n = aHint.GetValue(); 1902 OSL_ENSURE(n <= m_xParagraphs->size(), 1903 "bad TEXT_HINT_PARAINSERTED event"); 1904 1905 // Save the values of old iterators (the iterators themselves 1906 // will get invalidated), and adjust the old values so that they 1907 // reflect the insertion of the new paragraph: 1908 Paragraphs::size_type nOldVisibleBegin 1909 = m_aVisibleBegin - m_xParagraphs->begin(); 1910 Paragraphs::size_type nOldVisibleEnd 1911 = m_aVisibleEnd - m_xParagraphs->begin(); 1912 Paragraphs::size_type nOldFocused 1913 = m_aFocused - m_xParagraphs->begin(); 1914 if (n <= nOldVisibleBegin) 1915 ++nOldVisibleBegin; // XXX numeric overflow 1916 if (n <= nOldVisibleEnd) 1917 ++nOldVisibleEnd; // XXX numeric overflow 1918 if (n <= nOldFocused) 1919 ++nOldFocused; // XXX numeric overflow 1920 if (sal::static_int_cast<sal_Int32>(n) <= m_nSelectionFirstPara) 1921 ++m_nSelectionFirstPara; // XXX numeric overflow 1922 if (sal::static_int_cast<sal_Int32>(n) <= m_nSelectionLastPara) 1923 ++m_nSelectionLastPara; // XXX numeric overflow 1924 1925 Paragraphs::iterator aIns( 1926 m_xParagraphs->insert( 1927 m_xParagraphs->begin() + n, 1928 ParagraphInfo(static_cast< ::sal_Int32 >( 1929 m_rEngine.GetTextHeight(n))))); 1930 // XXX numeric overflow (2x) 1931 1932 determineVisibleRange(); 1933 m_aFocused = m_xParagraphs->begin() + nOldFocused; 1934 1935 for (Paragraphs::iterator aIt(aIns);;) 1936 { 1937 ++aIt; 1938 if (aIt == m_xParagraphs->end()) 1939 break; 1940 ::rtl::Reference< ParagraphImpl > xParagraph( 1941 getParagraph(aIt)); 1942 if (xParagraph.is()) 1943 xParagraph->numberChanged(true); 1944 } 1945 1946 notifyVisibleRangeChanges( 1947 m_xParagraphs->begin() + nOldVisibleBegin, 1948 m_xParagraphs->begin() + nOldVisibleEnd, aIns); 1949 break; 1950 } 1951 case TEXT_HINT_PARAREMOVED: 1952 { 1953 ::sal_uLong n = aHint.GetValue(); 1954 if (n == TEXT_PARA_ALL) 1955 { 1956 {for (Paragraphs::iterator aIt(m_aVisibleBegin); 1957 aIt != m_aVisibleEnd; ++aIt) 1958 NotifyAccessibleEvent( 1959 ::css::accessibility::AccessibleEventId:: 1960 CHILD, 1961 ::css::uno::makeAny(getAccessibleChild(aIt)), 1962 ::css::uno::Any()); 1963 } 1964 disposeParagraphs(); 1965 m_xParagraphs->clear(); 1966 determineVisibleRange(); 1967 m_nSelectionFirstPara = -1; 1968 m_nSelectionFirstPos = -1; 1969 m_nSelectionLastPara = -1; 1970 m_nSelectionLastPos = -1; 1971 m_aFocused = m_xParagraphs->end(); 1972 } 1973 else 1974 { 1975 OSL_ENSURE(n < m_xParagraphs->size(), 1976 "Bad TEXT_HINT_PARAREMOVED event"); 1977 1978 Paragraphs::iterator aIt(m_xParagraphs->begin() + n); 1979 // numeric overflow cannot occur 1980 1981 // Save the values of old iterators (the iterators 1982 // themselves will get invalidated), and adjust the old 1983 // values so that they reflect the removal of the paragraph: 1984 Paragraphs::size_type nOldVisibleBegin 1985 = m_aVisibleBegin - m_xParagraphs->begin(); 1986 Paragraphs::size_type nOldVisibleEnd 1987 = m_aVisibleEnd - m_xParagraphs->begin(); 1988 bool bWasVisible 1989 = nOldVisibleBegin <= n && n < nOldVisibleEnd; 1990 Paragraphs::size_type nOldFocused 1991 = m_aFocused - m_xParagraphs->begin(); 1992 bool bWasFocused = aIt == m_aFocused; 1993 if (n < nOldVisibleBegin) 1994 --nOldVisibleBegin; 1995 if (n < nOldVisibleEnd) 1996 --nOldVisibleEnd; 1997 if (n < nOldFocused) 1998 --nOldFocused; 1999 if (sal::static_int_cast<sal_Int32>(n) < m_nSelectionFirstPara) 2000 --m_nSelectionFirstPara; 2001 else if (sal::static_int_cast<sal_Int32>(n) == m_nSelectionFirstPara) 2002 { 2003 if (m_nSelectionFirstPara == m_nSelectionLastPara) 2004 { 2005 m_nSelectionFirstPara = -1; 2006 m_nSelectionFirstPos = -1; 2007 m_nSelectionLastPara = -1; 2008 m_nSelectionLastPos = -1; 2009 } 2010 else 2011 { 2012 ++m_nSelectionFirstPara; 2013 m_nSelectionFirstPos = 0; 2014 } 2015 } 2016 if (sal::static_int_cast<sal_Int32>(n) < m_nSelectionLastPara) 2017 --m_nSelectionLastPara; 2018 else if (sal::static_int_cast<sal_Int32>(n) == m_nSelectionLastPara) 2019 { 2020 OSL_ENSURE(m_nSelectionFirstPara < m_nSelectionLastPara, 2021 "logic error"); 2022 --m_nSelectionLastPara; 2023 m_nSelectionLastPos = 0x7FFFFFFF; 2024 } 2025 2026 ::css::uno::Reference< ::css::accessibility::XAccessible > 2027 xStrong; 2028 if (bWasVisible) 2029 xStrong = getAccessibleChild(aIt); 2030 ::css::uno::WeakReference< 2031 ::css::accessibility::XAccessible > xWeak( 2032 aIt->getParagraph()); 2033 aIt = m_xParagraphs->erase(aIt); 2034 2035 determineVisibleRange(); 2036 m_aFocused = bWasFocused ? m_xParagraphs->end() 2037 : m_xParagraphs->begin() + nOldFocused; 2038 2039 for (; aIt != m_xParagraphs->end(); ++aIt) 2040 { 2041 ::rtl::Reference< ParagraphImpl > xParagraph( 2042 getParagraph(aIt)); 2043 if (xParagraph.is()) 2044 xParagraph->numberChanged(false); 2045 } 2046 2047 if (bWasVisible) 2048 NotifyAccessibleEvent( 2049 ::css::accessibility::AccessibleEventId:: 2050 CHILD, 2051 ::css::uno::makeAny(getAccessibleChild(aIt)), 2052 ::css::uno::Any()); 2053 2054 ::css::uno::Reference< ::css::lang::XComponent > xComponent( 2055 xWeak.get(), ::css::uno::UNO_QUERY); 2056 if (xComponent.is()) 2057 xComponent->dispose(); 2058 2059 notifyVisibleRangeChanges( 2060 m_xParagraphs->begin() + nOldVisibleBegin, 2061 m_xParagraphs->begin() + nOldVisibleEnd, 2062 m_xParagraphs->end()); 2063 } 2064 break; 2065 } 2066 case TEXT_HINT_FORMATPARA: 2067 { 2068 ::sal_uLong n = aHint.GetValue(); 2069 OSL_ENSURE(n < m_xParagraphs->size(), 2070 "Bad TEXT_HINT_FORMATPARA event"); 2071 2072 (*m_xParagraphs)[static_cast< Paragraphs::size_type >(n)]. 2073 changeHeight(static_cast< ::sal_Int32 >( 2074 m_rEngine.GetTextHeight(n))); 2075 // XXX numeric overflow 2076 Paragraphs::iterator aOldVisibleBegin(m_aVisibleBegin); 2077 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd); 2078 determineVisibleRange(); 2079 notifyVisibleRangeChanges(aOldVisibleBegin, aOldVisibleEnd, 2080 m_xParagraphs->end()); 2081 2082 if (n < m_xParagraphs->size()) 2083 { 2084 Paragraphs::iterator aIt(m_xParagraphs->begin() + n); 2085 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt)); 2086 if (xParagraph.is()) 2087 xParagraph->textChanged(); 2088 } 2089 break; 2090 } 2091 default: 2092 OSL_ENSURE(false, "bad buffered hint"); 2093 break; 2094 } 2095 } 2096 if (m_bSelectionChangedNotification) 2097 { 2098 m_bSelectionChangedNotification = false; 2099 handleSelectionChangeNotification(); 2100 } 2101 } 2102 2103 ::sal_Int32 Document::getSelectionType(::sal_Int32 nNewFirstPara, ::sal_Int32 nNewFirstPos, ::sal_Int32 nNewLastPara, ::sal_Int32 nNewLastPos) 2104 { 2105 if (m_nSelectionFirstPara == -1) 2106 return -1; 2107 ::sal_Int32 Osp = m_nSelectionFirstPara, Osl = m_nSelectionFirstPos, Oep = m_nSelectionLastPara, Oel = m_nSelectionLastPos; 2108 ::sal_Int32 Nsp = nNewFirstPara, Nsl = nNewFirstPos, Nep = nNewLastPara, Nel = nNewLastPos; 2109 TextPaM Ns(Nsp, sal_uInt16(Nsl)); 2110 TextPaM Ne(Nep, sal_uInt16(Nel)); 2111 TextPaM Os(Osp, sal_uInt16(Osl)); 2112 TextPaM Oe(Oep, sal_uInt16(Oel)); 2113 2114 if (Os == Oe && Ns == Ne) 2115 { 2116 //only caret moves. 2117 return 1; 2118 } 2119 else if (Os == Oe && Ns != Ne) 2120 { 2121 //old has no selection but new has selection 2122 return 2; 2123 } 2124 else if (Os != Oe && Ns == Ne) 2125 { 2126 //old has selection but new has no selection. 2127 return 3; 2128 } 2129 else if (Os != Oe && Ns != Ne && Osp == Nsp && Osl == Nsl) 2130 { 2131 //both old and new have selections. 2132 if (Oep == Nep ) 2133 { 2134 //Send text_selection_change event on Nep 2135 2136 return 4; 2137 } 2138 else if (Oep < Nep) 2139 { 2140 //all the following examples like 1,2->1,3 means that old start select para is 1, old end select para is 2, 2141 // then press shift up, the new start select para is 1, new end select para is 3; 2142 //for example, 1, 2 -> 1, 3; 4,1 -> 4, 7; 4,1 -> 4, 2; 4,4->4,5 2143 if (Nep >= Nsp) 2144 { 2145 // 1, 2 -> 1, 3; 4, 1 -> 4, 7; 4,4->4,5; 2146 if (Oep < Osp) 2147 { 2148 // 4,1 -> 4,7; 2149 return 5; 2150 } 2151 else if (Oep >= Osp) 2152 { 2153 // 1, 2 -> 1, 3; 4,4->4,5; 2154 return 6; 2155 } 2156 } 2157 else 2158 { 2159 // 4,1 -> 4,2, 2160 if (Oep < Osp) 2161 { 2162 // 4,1 -> 4,2, 2163 return 7; 2164 } 2165 else if (Oep >= Osp) 2166 { 2167 // no such condition. Oep > Osp = Nsp > Nep 2168 } 2169 } 2170 } 2171 else if (Oep > Nep) 2172 { 2173 // 3,2 -> 3,1; 4,7 -> 4,1; 4, 7 -> 4,6; 4,4 -> 4,3 2174 if (Nep >= Nsp) 2175 { 2176 // 4,7 -> 4,6 2177 if (Oep <= Osp) 2178 { 2179 //no such condition, Oep<Osp=Nsp <= Nep 2180 } 2181 else if (Oep > Osp) 2182 { 2183 // 4,7 ->4,6 2184 return 8; 2185 } 2186 } 2187 else 2188 { 2189 // 3,2 -> 3,1, 4,7 -> 4,1; 4,4->4,3 2190 if (Oep <= Osp) 2191 { 2192 // 3,2 -> 3,1; 4,4->4,3 2193 return 9; 2194 } 2195 else if (Oep > Osp) 2196 { 2197 // 4,7 -> 4,1 2198 return 10; 2199 } 2200 } 2201 } 2202 } 2203 return -1; 2204 } 2205 2206 2207 void Document::sendEvent(::sal_Int32 start, ::sal_Int32 end, ::sal_Int16 nEventId) 2208 { 2209 Paragraphs::iterator aEnd = ::std::min(m_xParagraphs->begin() + end + 1, m_aVisibleEnd); 2210 for (Paragraphs::iterator aIt = ::std::max(m_xParagraphs->begin() + start, m_aVisibleBegin); 2211 aIt < aEnd; ++aIt) 2212 { 2213 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt)); 2214 if (xParagraph.is()) 2215 xParagraph->notifyEvent( 2216 nEventId, 2217 ::css::uno::Any(), ::css::uno::Any()); 2218 } 2219 } 2220 2221 void Document::handleSelectionChangeNotification() 2222 { 2223 ::TextSelection const & rSelection = m_rView.GetSelection(); 2224 OSL_ENSURE(rSelection.GetStart().GetPara() < m_xParagraphs->size() 2225 && rSelection.GetEnd().GetPara() < m_xParagraphs->size(), 2226 "bad TEXT_HINT_VIEWSELECTIONCHANGED event"); 2227 ::sal_Int32 nNewFirstPara 2228 = static_cast< ::sal_Int32 >(rSelection.GetStart().GetPara()); 2229 ::sal_Int32 nNewFirstPos 2230 = static_cast< ::sal_Int32 >(rSelection.GetStart().GetIndex()); 2231 // XXX numeric overflow 2232 ::sal_Int32 nNewLastPara 2233 = static_cast< ::sal_Int32 >(rSelection.GetEnd().GetPara()); 2234 ::sal_Int32 nNewLastPos 2235 = static_cast< ::sal_Int32 >(rSelection.GetEnd().GetIndex()); 2236 // XXX numeric overflow 2237 2238 // Lose focus: 2239 Paragraphs::iterator aIt(m_xParagraphs->begin() + nNewLastPara); 2240 if (m_aFocused != m_xParagraphs->end() && m_aFocused != aIt 2241 && m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd) 2242 { 2243 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(m_aFocused)); 2244 if (xParagraph.is()) 2245 xParagraph->notifyEvent( 2246 ::css::accessibility::AccessibleEventId:: 2247 STATE_CHANGED, 2248 ::css::uno::makeAny( 2249 ::css::accessibility::AccessibleStateType::FOCUSED), 2250 ::css::uno::Any()); 2251 } 2252 2253 // Gain focus and update cursor position: 2254 if (aIt >= m_aVisibleBegin && aIt < m_aVisibleEnd 2255 && (aIt != m_aFocused 2256 || nNewLastPara != m_nSelectionLastPara 2257 || nNewLastPos != m_nSelectionLastPos)) 2258 { 2259 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt)); 2260 if (xParagraph.is()) 2261 { 2262 //disable the first event when user types in empty field. 2263 ::sal_Int32 count = getAccessibleChildCount(); 2264 ::sal_Bool bEmpty = count > 1; 2265 //if (aIt != m_aFocused) 2266 if (aIt != m_aFocused && bEmpty) 2267 xParagraph->notifyEvent( 2268 ::css::accessibility::AccessibleEventId:: 2269 STATE_CHANGED, 2270 ::css::uno::Any(), 2271 ::css::uno::makeAny( 2272 ::css::accessibility::AccessibleStateType::FOCUSED)); 2273 if (nNewLastPara != m_nSelectionLastPara 2274 || nNewLastPos != m_nSelectionLastPos) 2275 xParagraph->notifyEvent( 2276 ::css::accessibility::AccessibleEventId:: 2277 CARET_CHANGED, 2278 ::css::uno::makeAny< ::sal_Int32 >( 2279 nNewLastPara == m_nSelectionLastPara 2280 ? m_nSelectionLastPos : 0), 2281 ::css::uno::makeAny(nNewLastPos)); 2282 } 2283 } 2284 m_aFocused = aIt; 2285 2286 ::sal_Int32 nMin; 2287 ::sal_Int32 nMax; 2288 ::sal_Int32 ret = getSelectionType(nNewFirstPara, nNewFirstPos, nNewLastPara, nNewLastPos); 2289 switch (ret) 2290 { 2291 case -1: 2292 { 2293 //no event 2294 } 2295 break; 2296 case 1: 2297 { 2298 //only caret moved, already handled in above 2299 } 2300 break; 2301 case 2: 2302 { 2303 //old has no selection but new has selection 2304 nMin = ::std::min(nNewFirstPara, nNewLastPara); 2305 nMax = ::std::max(nNewFirstPara, nNewLastPara); 2306 sendEvent(nMin, nMax, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2307 sendEvent(nMin, nMax, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2308 } 2309 break; 2310 case 3: 2311 { 2312 //old has selection but new has no selection. 2313 nMin = ::std::min(m_nSelectionFirstPara, m_nSelectionLastPara); 2314 nMax = ::std::max(m_nSelectionFirstPara, m_nSelectionLastPara); 2315 sendEvent(nMin, nMax, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2316 sendEvent(nMin, nMax, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2317 } 2318 break; 2319 case 4: 2320 { 2321 //Send text_selection_change event on Nep 2322 sendEvent(nNewLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2323 } 2324 break; 2325 case 5: 2326 { 2327 // 4, 1 -> 4, 7 2328 sendEvent(m_nSelectionLastPara, m_nSelectionFirstPara-1, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2329 sendEvent(nNewFirstPara+1, nNewLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2330 2331 sendEvent(m_nSelectionLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2332 } 2333 break; 2334 case 6: 2335 { 2336 // 1, 2 -> 1, 4; 4,4->4,5; 2337 sendEvent(m_nSelectionLastPara+1, nNewLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2338 2339 sendEvent(m_nSelectionLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2340 } 2341 break; 2342 case 7: 2343 { 2344 // 4,1 -> 4,3, 2345 sendEvent(m_nSelectionLastPara +1, nNewLastPara , ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2346 2347 sendEvent(m_nSelectionLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2348 } 2349 break; 2350 case 8: 2351 { 2352 // 4,7 ->4,5; 2353 sendEvent(nNewLastPara + 1, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2354 2355 sendEvent(nNewLastPara, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2356 } 2357 break; 2358 case 9: 2359 { 2360 // 3,2 -> 3,1; 4,4->4,3 2361 sendEvent(nNewLastPara, m_nSelectionLastPara - 1, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2362 2363 sendEvent(nNewLastPara, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2364 } 2365 break; 2366 case 10: 2367 { 2368 // 4,7 -> 4,1 2369 sendEvent(m_nSelectionFirstPara + 1, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2370 sendEvent(nNewLastPara, nNewFirstPara - 1, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2371 2372 sendEvent(nNewLastPara, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2373 } 2374 break; 2375 default: 2376 break; 2377 } 2378 2379 /* 2380 // Update both old and new selection. (Regardless of how the two selections 2381 // look like, there will always be two ranges to the left and right of the 2382 // overlap---the overlap and/or the range to the right of it possibly being 2383 // empty. Only for these two ranges notifications have to be sent.) 2384 2385 TextPaM aOldTextStart( static_cast< sal_uLong >( m_nSelectionFirstPara ), static_cast< sal_uInt16 >( m_nSelectionFirstPos ) ); 2386 TextPaM aOldTextEnd( static_cast< sal_uLong >( m_nSelectionLastPara ), static_cast< sal_uInt16 >( m_nSelectionLastPos ) ); 2387 TextPaM aNewTextStart( static_cast< sal_uLong >( nNewFirstPara ), static_cast< sal_uInt16 >( nNewFirstPos ) ); 2388 TextPaM aNewTextEnd( static_cast< sal_uLong >( nNewLastPara ), static_cast< sal_uInt16 >( nNewLastPos ) ); 2389 2390 // justify selections 2391 justifySelection( aOldTextStart, aOldTextEnd ); 2392 justifySelection( aNewTextStart, aNewTextEnd ); 2393 2394 sal_Int32 nFirst1; 2395 sal_Int32 nLast1; 2396 sal_Int32 nFirst2; 2397 sal_Int32 nLast2; 2398 2399 if ( m_nSelectionFirstPara == -1 ) 2400 { 2401 // old selection not initialized yet => notify events only for new selection (if not empty) 2402 nFirst1 = aNewTextStart.GetPara(); 2403 nLast1 = aNewTextEnd.GetPara() + ( aNewTextStart != aNewTextEnd ? 1 : 0 ); 2404 nFirst2 = 0; 2405 nLast2 = 0; 2406 } 2407 else if ( aOldTextStart == aOldTextEnd && aNewTextStart == aNewTextEnd ) 2408 { 2409 // old an new selection empty => no events 2410 nFirst1 = 0; 2411 nLast1 = 0; 2412 nFirst2 = 0; 2413 nLast2 = 0; 2414 } 2415 else if ( aOldTextStart != aOldTextEnd && aNewTextStart == aNewTextEnd ) 2416 { 2417 // old selection not empty + new selection empty => notify events only for old selection 2418 nFirst1 = aOldTextStart.GetPara(); 2419 nLast1 = aOldTextEnd.GetPara() + 1; 2420 nFirst2 = 0; 2421 nLast2 = 0; 2422 } 2423 else if ( aOldTextStart == aOldTextEnd && aNewTextStart != aNewTextEnd ) 2424 { 2425 // old selection empty + new selection not empty => notify events only for new selection 2426 nFirst1 = aNewTextStart.GetPara(); 2427 nLast1 = aNewTextEnd.GetPara() + 1; 2428 nFirst2 = 0; 2429 nLast2 = 0; 2430 } 2431 else 2432 { 2433 // old and new selection not empty => notify events for the two ranges left and right of the overlap 2434 ::std::vector< TextPaM > aTextPaMs(4); 2435 aTextPaMs[0] = aOldTextStart; 2436 aTextPaMs[1] = aOldTextEnd; 2437 aTextPaMs[2] = aNewTextStart; 2438 aTextPaMs[3] = aNewTextEnd; 2439 ::std::sort( aTextPaMs.begin(), aTextPaMs.end() ); 2440 2441 nFirst1 = aTextPaMs[0].GetPara(); 2442 nLast1 = aTextPaMs[1].GetPara() + ( aTextPaMs[0] != aTextPaMs[1] ? 1 : 0 ); 2443 2444 nFirst2 = aTextPaMs[2].GetPara(); 2445 nLast2 = aTextPaMs[3].GetPara() + ( aTextPaMs[2] != aTextPaMs[3] ? 1 : 0 ); 2446 2447 // adjust overlapping ranges 2448 if ( nLast1 > nFirst2 ) 2449 nLast1 = nFirst2; 2450 } 2451 2452 // notify selection changes 2453 notifySelectionChange( nFirst1, nLast1 ); 2454 notifySelectionChange( nFirst2, nLast2 ); 2455 */ 2456 m_nSelectionFirstPara = nNewFirstPara; 2457 m_nSelectionFirstPos = nNewFirstPos; 2458 m_nSelectionLastPara = nNewLastPara; 2459 m_nSelectionLastPos = nNewLastPos; 2460 } 2461 2462 void Document::notifySelectionChange( sal_Int32 nFirst, sal_Int32 nLast ) 2463 { 2464 if ( nFirst < nLast ) 2465 { 2466 Paragraphs::iterator aEnd( ::std::min( m_xParagraphs->begin() + nLast, m_aVisibleEnd ) ); 2467 for ( Paragraphs::iterator aIt = ::std::max( m_xParagraphs->begin() + nFirst, m_aVisibleBegin ); aIt < aEnd; ++aIt ) 2468 { 2469 ::rtl::Reference< ParagraphImpl > xParagraph( getParagraph( aIt ) ); 2470 if ( xParagraph.is() ) 2471 { 2472 xParagraph->notifyEvent( 2473 ::css::accessibility::AccessibleEventId::SELECTION_CHANGED, 2474 ::css::uno::Any(), ::css::uno::Any() ); 2475 xParagraph->notifyEvent( 2476 ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED, 2477 ::css::uno::Any(), ::css::uno::Any() ); 2478 } 2479 } 2480 } 2481 } 2482 2483 void Document::justifySelection( TextPaM& rTextStart, TextPaM& rTextEnd ) 2484 { 2485 if ( rTextStart > rTextEnd ) 2486 { 2487 TextPaM aTextPaM( rTextStart ); 2488 rTextStart = rTextEnd; 2489 rTextEnd = aTextPaM; 2490 } 2491 } 2492 2493 void Document::disposeParagraphs() 2494 { 2495 for (Paragraphs::iterator aIt(m_xParagraphs->begin()); 2496 aIt != m_xParagraphs->end(); ++aIt) 2497 { 2498 ::css::uno::Reference< ::css::lang::XComponent > xComponent( 2499 aIt->getParagraph().get(), ::css::uno::UNO_QUERY); 2500 if (xComponent.is()) 2501 xComponent->dispose(); 2502 } 2503 } 2504 2505 // static 2506 ::css::uno::Any Document::mapFontColor(::Color const & rColor) 2507 { 2508 return ::css::uno::makeAny( 2509 static_cast< ::sal_Int32 >(COLORDATA_RGB(rColor.GetColor()))); 2510 // FIXME keep transparency? 2511 } 2512 2513 // static 2514 ::Color Document::mapFontColor(::css::uno::Any const & rColor) 2515 { 2516 ::sal_Int32 nColor = 0; 2517 rColor >>= nColor; 2518 return ::Color(static_cast< ::ColorData >(nColor)); 2519 } 2520 2521 // static 2522 ::css::uno::Any Document::mapFontWeight(::FontWeight nWeight) 2523 { 2524 // Map from ::FontWeight to ::css:awt::FontWeight, depends on order of 2525 // elements in ::FontWeight (vcl/vclenum.hxx): 2526 static float const aWeight[] 2527 = { ::css::awt::FontWeight::DONTKNOW, // WEIGHT_DONTKNOW 2528 ::css::awt::FontWeight::THIN, // WEIGHT_THIN 2529 ::css::awt::FontWeight::ULTRALIGHT, // WEIGHT_ULTRALIGHT 2530 ::css::awt::FontWeight::LIGHT, // WEIGHT_LIGHT 2531 ::css::awt::FontWeight::SEMILIGHT, // WEIGHT_SEMILIGHT 2532 ::css::awt::FontWeight::NORMAL, // WEIGHT_NORMAL 2533 ::css::awt::FontWeight::NORMAL, // WEIGHT_MEDIUM 2534 ::css::awt::FontWeight::SEMIBOLD, // WEIGHT_SEMIBOLD 2535 ::css::awt::FontWeight::BOLD, // WEIGHT_BOLD 2536 ::css::awt::FontWeight::ULTRABOLD, // WEIGHT_ULTRABOLD 2537 ::css::awt::FontWeight::BLACK }; // WEIGHT_BLACK 2538 return ::css::uno::makeAny(aWeight[nWeight]); 2539 } 2540 2541 // static 2542 ::FontWeight Document::mapFontWeight(::css::uno::Any const & rWeight) 2543 { 2544 float nWeight = ::css::awt::FontWeight::NORMAL; 2545 rWeight >>= nWeight; 2546 return nWeight <= ::css::awt::FontWeight::DONTKNOW ? WEIGHT_DONTKNOW 2547 : nWeight <= ::css::awt::FontWeight::THIN ? WEIGHT_THIN 2548 : nWeight <= ::css::awt::FontWeight::ULTRALIGHT ? WEIGHT_ULTRALIGHT 2549 : nWeight <= ::css::awt::FontWeight::LIGHT ? WEIGHT_LIGHT 2550 : nWeight <= ::css::awt::FontWeight::SEMILIGHT ? WEIGHT_SEMILIGHT 2551 : nWeight <= ::css::awt::FontWeight::NORMAL ? WEIGHT_NORMAL 2552 : nWeight <= ::css::awt::FontWeight::SEMIBOLD ? WEIGHT_SEMIBOLD 2553 : nWeight <= ::css::awt::FontWeight::BOLD ? WEIGHT_BOLD 2554 : nWeight <= ::css::awt::FontWeight::ULTRABOLD ? WEIGHT_ULTRABOLD 2555 : WEIGHT_BLACK; 2556 } 2557 2558 } 2559