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