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