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