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 accoring 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 switch ( rVclWindowEvent.GetId() ) 1537 { 1538 case VCLEVENT_WINDOW_GETFOCUS: 1539 case VCLEVENT_WINDOW_LOSEFOCUS: 1540 { 1541 // #107179# if our parent is a compound control (e.g. MultiLineEdit), 1542 // suppress the window focus events here 1543 //if ( !m_bCompoundControlChild ) 1544 VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent ); 1545 } 1546 break; 1547 default: 1548 VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent ); 1549 } 1550 } 1551 1552 // virtual 1553 ::sal_Int32 SAL_CALL Document::getAccessibleChildCount() 1554 throw (::css::uno::RuntimeException) 1555 { 1556 ::comphelper::OExternalLockGuard aGuard(this); 1557 init(); 1558 return m_aVisibleEnd - m_aVisibleBegin; 1559 } 1560 1561 // virtual 1562 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL 1563 Document::getAccessibleChild(::sal_Int32 i) 1564 throw (::css::lang::IndexOutOfBoundsException, 1565 ::css::uno::RuntimeException) 1566 { 1567 ::comphelper::OExternalLockGuard aGuard(this); 1568 init(); 1569 if (i < 0 || i >= m_aVisibleEnd - m_aVisibleBegin) 1570 throw ::css::lang::IndexOutOfBoundsException( 1571 ::rtl::OUString( 1572 RTL_CONSTASCII_USTRINGPARAM( 1573 "textwindowaccessibility.cxx:" 1574 " Document::getAccessibleChild")), 1575 static_cast< ::css::uno::XWeak * >(this)); 1576 return getAccessibleChild(m_aVisibleBegin 1577 + static_cast< Paragraphs::size_type >(i)); 1578 } 1579 1580 // virtual 1581 ::sal_Int16 SAL_CALL Document::getAccessibleRole() 1582 throw (::css::uno::RuntimeException) 1583 { 1584 return ::css::accessibility::AccessibleRole::TEXT_FRAME; 1585 } 1586 1587 // virtual 1588 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL 1589 Document::getAccessibleAtPoint(::css::awt::Point const & rPoint) 1590 throw (::css::uno::RuntimeException) 1591 { 1592 ::comphelper::OExternalLockGuard aGuard(this); 1593 init(); 1594 if (rPoint.X >= 0 1595 && rPoint.X < m_rView.GetWindow()->GetOutputSizePixel().Width() 1596 && rPoint.Y >= 0 && rPoint.Y < m_nViewHeight) 1597 { 1598 ::sal_Int32 nOffset = m_nViewOffset + rPoint.Y; // XXX numeric overflow 1599 ::sal_Int32 nPos = m_nViewOffset - m_nVisibleBeginOffset; 1600 for (Paragraphs::iterator aIt(m_aVisibleBegin); aIt != m_aVisibleEnd; 1601 ++aIt) 1602 { 1603 nPos += aIt->getHeight(); // XXX numeric overflow 1604 if (nOffset < nPos) 1605 return getAccessibleChild(aIt); 1606 } 1607 } 1608 return 0; 1609 } 1610 void Document::FillAccessibleStateSet( utl::AccessibleStateSetHelper& rStateSet ) 1611 { 1612 VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet ); 1613 if (!m_rView.IsReadOnly()) 1614 rStateSet.AddState( ::css::accessibility::AccessibleStateType::EDITABLE ); 1615 } 1616 1617 void Document::FillAccessibleRelationSet( utl::AccessibleRelationSetHelper& rRelationSet ) 1618 { 1619 if( getAccessibleParent()->getAccessibleContext()->getAccessibleRole() == ::css::accessibility::AccessibleRole::SCROLL_PANE ) 1620 { 1621 ::css::uno::Sequence< ::css::uno::Reference< ::css::uno::XInterface > > aSequence(1); 1622 aSequence[0] = getAccessibleParent(); 1623 rRelationSet.AddRelation( ::css::accessibility::AccessibleRelation( ::css::accessibility::AccessibleRelationType::MEMBER_OF, aSequence ) ); 1624 } 1625 else 1626 { 1627 VCLXAccessibleComponent::FillAccessibleRelationSet(rRelationSet); 1628 } 1629 } 1630 // virtual 1631 void SAL_CALL Document::disposing() 1632 { 1633 m_aEngineListener.endListening(); 1634 m_aViewListener.endListening(); 1635 if (m_xParagraphs.get() != 0) 1636 disposeParagraphs(); 1637 VCLXAccessibleComponent::disposing(); 1638 } 1639 1640 // virtual 1641 void Document::Notify(::SfxBroadcaster &, ::SfxHint const & rHint) 1642 { 1643 if (rHint.ISA(::TextHint)) 1644 { 1645 ::TextHint const & rTextHint 1646 = static_cast< ::TextHint const & >(rHint); 1647 switch (rTextHint.GetId()) 1648 { 1649 case TEXT_HINT_PARAINSERTED: 1650 case TEXT_HINT_PARAREMOVED: 1651 // TEXT_HINT_PARAINSERTED and TEXT_HINT_PARAREMOVED are sent at 1652 // "unsafe" times (when the text engine has not yet re-formatted its 1653 // content), so that for example calling ::TextEngine::GetTextHeight 1654 // from within the code that handles TEXT_HINT_PARAINSERTED causes 1655 // trouble within the text engine. Therefore, these hints are just 1656 // buffered until a following ::TextEngine::FormatDoc causes a 1657 // TEXT_HINT_TEXTFORMATTED to come in: 1658 case TEXT_HINT_FORMATPARA: 1659 // ::TextEngine::FormatDoc sends a sequence of 1660 // TEXT_HINT_FORMATPARAs, followed by an optional 1661 // TEXT_HINT_TEXTHEIGHTCHANGED, followed in all cases by one 1662 // TEXT_HINT_TEXTFORMATTED. Only the TEXT_HINT_FORMATPARAs contain 1663 // the the numbers of the affected paragraphs, but they are sent 1664 // before the changes are applied. Therefore, TEXT_HINT_FORMATPARAs 1665 // are just buffered until another hint comes in: 1666 { 1667 ::osl::MutexGuard aInternalGuard(GetMutex()); 1668 if (!isAlive()) 1669 break; 1670 1671 m_aParagraphNotifications.push(rTextHint); 1672 break; 1673 } 1674 case TEXT_HINT_TEXTFORMATTED: 1675 case TEXT_HINT_TEXTHEIGHTCHANGED: 1676 case TEXT_HINT_MODIFIED: 1677 { 1678 ::osl::MutexGuard aInternalGuard(GetMutex()); 1679 if (!isAlive()) 1680 break; 1681 handleParagraphNotifications(); 1682 break; 1683 } 1684 case TEXT_HINT_VIEWSCROLLED: 1685 { 1686 ::osl::MutexGuard aInternalGuard(GetMutex()); 1687 if (!isAlive()) 1688 break; 1689 handleParagraphNotifications(); 1690 1691 ::sal_Int32 nOffset = static_cast< ::sal_Int32 >( 1692 m_rView.GetStartDocPos().Y()); 1693 // XXX numeric overflow 1694 if (nOffset != m_nViewOffset) 1695 { 1696 m_nViewOffset = nOffset; 1697 1698 Paragraphs::iterator aOldVisibleBegin( 1699 m_aVisibleBegin); 1700 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd); 1701 1702 determineVisibleRange(); 1703 1704 notifyVisibleRangeChanges(aOldVisibleBegin, 1705 aOldVisibleEnd, 1706 m_xParagraphs->end()); 1707 } 1708 break; 1709 } 1710 case TEXT_HINT_VIEWSELECTIONCHANGED: 1711 { 1712 ::osl::MutexGuard aInternalGuard(GetMutex()); 1713 if (!isAlive()) 1714 break; 1715 1716 if (m_aParagraphNotifications.empty()) 1717 { 1718 handleSelectionChangeNotification(); 1719 } 1720 else 1721 { 1722 // TEXT_HINT_VIEWSELECTIONCHANGED is sometimes sent at 1723 // "unsafe" times (when the text engine has not yet re- 1724 // formatted its content), so that for example calling 1725 // ::TextEngine::GetTextHeight from within the code that 1726 // handles a previous TEXT_HINT_PARAINSERTED causes 1727 // trouble within the text engine. Therefore, these 1728 // hints are just buffered (along with 1729 // TEXT_HINT_PARAINSERTED/REMOVED/FORMATPARA) until a 1730 // following ::TextEngine::FormatDoc causes a 1731 // TEXT_HINT_TEXTFORMATTED to come in: 1732 m_bSelectionChangedNotification = true; 1733 } 1734 break; 1735 } 1736 } 1737 } 1738 } 1739 1740 IMPL_LINK(Document, WindowEventHandler, ::VclSimpleEvent *, pEvent) 1741 { 1742 switch (pEvent->GetId()) 1743 { 1744 case VCLEVENT_WINDOW_RESIZE: 1745 { 1746 ::osl::MutexGuard aInternalGuard(GetMutex()); 1747 if (!isAlive()) 1748 break; 1749 1750 ::sal_Int32 nHeight = static_cast< ::sal_Int32 >( 1751 m_rView.GetWindow()->GetOutputSizePixel().Height()); 1752 // XXX numeric overflow 1753 if (nHeight != m_nViewHeight) 1754 { 1755 m_nViewHeight = nHeight; 1756 1757 Paragraphs::iterator aOldVisibleBegin(m_aVisibleBegin); 1758 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd); 1759 1760 determineVisibleRange(); 1761 1762 notifyVisibleRangeChanges(aOldVisibleBegin, aOldVisibleEnd, 1763 m_xParagraphs->end()); 1764 } 1765 break; 1766 } 1767 case VCLEVENT_WINDOW_GETFOCUS: 1768 { 1769 ::osl::MutexGuard aInternalGuard(GetMutex()); 1770 if (!isAlive()) 1771 break; 1772 //to enable the PARAGRAPH to get focus for multiline edit 1773 ::sal_Int32 count = getAccessibleChildCount(); 1774 ::sal_Bool bEmpty = m_aFocused == m_aVisibleEnd && count == 1; 1775 if ((m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd) || bEmpty) 1776 { 1777 Paragraphs::iterator m_aTemp = bEmpty ? m_aVisibleBegin : m_aFocused; 1778 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(m_aTemp)); 1779 if (xParagraph.is()) 1780 { 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 } 1790 /* 1791 ::rtl::Reference< ParagraphImpl > xParagraph( 1792 getParagraph(m_aFocused)); 1793 if (xParagraph.is()) 1794 xParagraph->notifyEvent( 1795 ::css::accessibility::AccessibleEventId:: 1796 STATE_CHANGED, 1797 ::css::uno::Any(), 1798 ::css::uno::makeAny( 1799 ::css::accessibility::AccessibleStateType:: 1800 FOCUSED)); 1801 */ 1802 break; 1803 } 1804 case VCLEVENT_WINDOW_LOSEFOCUS: 1805 { 1806 ::osl::MutexGuard aInternalGuard(GetMutex()); 1807 if (!isAlive()) 1808 break; 1809 //to enable the PARAGRAPH to get focus for multiline edit 1810 ::sal_Int32 count = getAccessibleChildCount(); 1811 ::sal_Bool bEmpty = m_aFocused == m_aVisibleEnd && count == 1; 1812 if ((m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd) || bEmpty) 1813 { 1814 Paragraphs::iterator m_aTemp = bEmpty ? m_aVisibleBegin : m_aFocused; 1815 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(m_aTemp)); 1816 if (xParagraph.is()) 1817 xParagraph->notifyEvent( 1818 ::css::accessibility::AccessibleEventId:: 1819 STATE_CHANGED, 1820 ::css::uno::makeAny( 1821 ::css::accessibility::AccessibleStateType:: 1822 FOCUSED), 1823 ::css::uno::Any()); 1824 } 1825 1826 /* 1827 if (m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd) 1828 { 1829 ::rtl::Reference< ParagraphImpl > xParagraph( 1830 getParagraph(m_aFocused)); 1831 if (xParagraph.is()) 1832 xParagraph->notifyEvent( 1833 ::css::accessibility::AccessibleEventId:: 1834 STATE_CHANGED, 1835 ::css::uno::makeAny( 1836 ::css::accessibility::AccessibleStateType:: 1837 FOCUSED), 1838 ::css::uno::Any()); 1839 } 1840 */ 1841 break; 1842 } 1843 } 1844 return 0; 1845 } 1846 1847 void Document::init() 1848 { 1849 if (m_xParagraphs.get() == 0) 1850 { 1851 ::sal_uLong nCount = m_rEngine.GetParagraphCount(); 1852 ::std::auto_ptr< Paragraphs > p(new Paragraphs); 1853 p->reserve(static_cast< Paragraphs::size_type >(nCount)); 1854 // numeric overflow is harmless here 1855 for (::sal_uLong i = 0; i < nCount; ++i) 1856 p->push_back(ParagraphInfo(static_cast< ::sal_Int32 >( 1857 m_rEngine.GetTextHeight(i)))); 1858 // XXX numeric overflow 1859 m_nViewOffset = static_cast< ::sal_Int32 >( 1860 m_rView.GetStartDocPos().Y()); // XXX numeric overflow 1861 m_nViewHeight = static_cast< ::sal_Int32 >( 1862 m_rView.GetWindow()->GetOutputSizePixel().Height()); 1863 // XXX numeric overflow 1864 m_xParagraphs = p; 1865 determineVisibleRange(); 1866 m_nSelectionFirstPara = -1; 1867 m_nSelectionFirstPos = -1; 1868 m_nSelectionLastPara = -1; 1869 m_nSelectionLastPos = -1; 1870 m_aFocused = m_xParagraphs->end(); 1871 m_bSelectionChangedNotification = false; 1872 m_aEngineListener.startListening(m_rEngine); 1873 m_aViewListener.startListening(*m_rView.GetWindow()); 1874 } 1875 } 1876 1877 ::rtl::Reference< ParagraphImpl > 1878 Document::getParagraph(Paragraphs::iterator const & rIt) 1879 { 1880 return static_cast< ParagraphImpl * >( 1881 ::css::uno::Reference< ::css::accessibility::XAccessible >( 1882 rIt->getParagraph()).get()); 1883 } 1884 1885 ::css::uno::Reference< ::css::accessibility::XAccessible > 1886 Document::getAccessibleChild(Paragraphs::iterator const & rIt) 1887 { 1888 ::css::uno::Reference< ::css::accessibility::XAccessible > xParagraph( 1889 rIt->getParagraph()); 1890 if (!xParagraph.is()) 1891 { 1892 xParagraph = new Paragraph(this, rIt - m_xParagraphs->begin()); 1893 rIt->setParagraph(xParagraph); 1894 } 1895 return xParagraph; 1896 } 1897 1898 void Document::determineVisibleRange() 1899 { 1900 m_aVisibleBegin = m_xParagraphs->end(); 1901 m_aVisibleEnd = m_aVisibleBegin; 1902 ::sal_Int32 nPos = 0; 1903 for (Paragraphs::iterator aIt = m_xParagraphs->begin();;) 1904 { 1905 if (aIt == m_xParagraphs->end()) 1906 { 1907 m_nVisibleBeginOffset = 0; 1908 break; 1909 } 1910 ::sal_Int32 nOldPos = nPos; 1911 nPos += aIt->getHeight(); // XXX numeric overflow 1912 if (m_aVisibleBegin == m_xParagraphs->end() && nPos >= m_nViewOffset) 1913 { 1914 m_aVisibleBegin = aIt; 1915 m_nVisibleBeginOffset = m_nViewOffset - nOldPos; 1916 } 1917 ++aIt; 1918 if (m_aVisibleBegin != m_xParagraphs->end() 1919 && (aIt == m_xParagraphs->end() 1920 || nPos >= m_nViewOffset + m_nViewHeight)) 1921 // XXX numeric overflow 1922 { 1923 m_aVisibleEnd = aIt; 1924 break; 1925 } 1926 } 1927 } 1928 1929 void Document::notifyVisibleRangeChanges( 1930 Paragraphs::iterator const & rOldVisibleBegin, 1931 Paragraphs::iterator const & rOldVisibleEnd, 1932 Paragraphs::iterator const & rInserted) 1933 { 1934 // XXX Replace this code that determines which paragraphs have changed from 1935 // invisible to visible or vice versa with a better algorithm. 1936 {for (Paragraphs::iterator aIt(rOldVisibleBegin); aIt != rOldVisibleEnd; 1937 ++aIt) 1938 if (aIt != rInserted 1939 && (aIt < m_aVisibleBegin || aIt >= m_aVisibleEnd)) 1940 NotifyAccessibleEvent( 1941 ::css::accessibility::AccessibleEventId:: 1942 CHILD, 1943 ::css::uno::makeAny(getAccessibleChild(aIt)), 1944 ::css::uno::Any()); 1945 } 1946 {for (Paragraphs::iterator aIt(m_aVisibleBegin); aIt != m_aVisibleEnd; 1947 ++aIt) 1948 if (aIt == rInserted 1949 || aIt < rOldVisibleBegin || aIt >= rOldVisibleEnd) 1950 NotifyAccessibleEvent( 1951 ::css::accessibility::AccessibleEventId:: 1952 CHILD, 1953 ::css::uno::Any(), 1954 ::css::uno::makeAny(getAccessibleChild(aIt))); 1955 } 1956 } 1957 1958 void 1959 Document::changeParagraphText(::sal_uLong nNumber, ::sal_uInt16 nBegin, ::sal_uInt16 nEnd, 1960 bool bCut, bool bPaste, 1961 ::rtl::OUString const & rText) 1962 { 1963 m_rView.SetSelection(::TextSelection(::TextPaM(nNumber, nBegin), 1964 ::TextPaM(nNumber, nEnd))); 1965 if (bCut) 1966 m_rView.Cut(); 1967 else if (nBegin != nEnd) 1968 m_rView.DeleteSelected(); 1969 if (bPaste) 1970 m_rView.Paste(); 1971 else if (rText.getLength() != 0) 1972 m_rView.InsertText(rText); 1973 } 1974 1975 void Document::handleParagraphNotifications() 1976 { 1977 while (!m_aParagraphNotifications.empty()) 1978 { 1979 ::TextHint aHint(m_aParagraphNotifications.front()); 1980 m_aParagraphNotifications.pop(); 1981 switch (aHint.GetId()) 1982 { 1983 case TEXT_HINT_PARAINSERTED: 1984 { 1985 ::sal_uLong n = aHint.GetValue(); 1986 OSL_ENSURE(n <= m_xParagraphs->size(), 1987 "bad TEXT_HINT_PARAINSERTED event"); 1988 1989 // Save the values of old iterators (the iterators themselves 1990 // will get invalidated), and adjust the old values so that they 1991 // reflect the insertion of the new paragraph: 1992 Paragraphs::size_type nOldVisibleBegin 1993 = m_aVisibleBegin - m_xParagraphs->begin(); 1994 Paragraphs::size_type nOldVisibleEnd 1995 = m_aVisibleEnd - m_xParagraphs->begin(); 1996 Paragraphs::size_type nOldFocused 1997 = m_aFocused - m_xParagraphs->begin(); 1998 if (n <= nOldVisibleBegin) 1999 ++nOldVisibleBegin; // XXX numeric overflow 2000 if (n <= nOldVisibleEnd) 2001 ++nOldVisibleEnd; // XXX numeric overflow 2002 if (n <= nOldFocused) 2003 ++nOldFocused; // XXX numeric overflow 2004 if (sal::static_int_cast<sal_Int32>(n) <= m_nSelectionFirstPara) 2005 ++m_nSelectionFirstPara; // XXX numeric overflow 2006 if (sal::static_int_cast<sal_Int32>(n) <= m_nSelectionLastPara) 2007 ++m_nSelectionLastPara; // XXX numeric overflow 2008 2009 Paragraphs::iterator aIns( 2010 m_xParagraphs->insert( 2011 m_xParagraphs->begin() + n, 2012 ParagraphInfo(static_cast< ::sal_Int32 >( 2013 m_rEngine.GetTextHeight(n))))); 2014 // XXX numeric overflow (2x) 2015 2016 determineVisibleRange(); 2017 m_aFocused = m_xParagraphs->begin() + nOldFocused; 2018 2019 for (Paragraphs::iterator aIt(aIns);;) 2020 { 2021 ++aIt; 2022 if (aIt == m_xParagraphs->end()) 2023 break; 2024 ::rtl::Reference< ParagraphImpl > xParagraph( 2025 getParagraph(aIt)); 2026 if (xParagraph.is()) 2027 xParagraph->numberChanged(true); 2028 } 2029 2030 notifyVisibleRangeChanges( 2031 m_xParagraphs->begin() + nOldVisibleBegin, 2032 m_xParagraphs->begin() + nOldVisibleEnd, aIns); 2033 break; 2034 } 2035 case TEXT_HINT_PARAREMOVED: 2036 { 2037 ::sal_uLong n = aHint.GetValue(); 2038 if (n == TEXT_PARA_ALL) 2039 { 2040 {for (Paragraphs::iterator aIt(m_aVisibleBegin); 2041 aIt != m_aVisibleEnd; ++aIt) 2042 NotifyAccessibleEvent( 2043 ::css::accessibility::AccessibleEventId:: 2044 CHILD, 2045 ::css::uno::makeAny(getAccessibleChild(aIt)), 2046 ::css::uno::Any()); 2047 } 2048 disposeParagraphs(); 2049 m_xParagraphs->clear(); 2050 determineVisibleRange(); 2051 m_nSelectionFirstPara = -1; 2052 m_nSelectionFirstPos = -1; 2053 m_nSelectionLastPara = -1; 2054 m_nSelectionLastPos = -1; 2055 m_aFocused = m_xParagraphs->end(); 2056 } 2057 else 2058 { 2059 OSL_ENSURE(n < m_xParagraphs->size(), 2060 "Bad TEXT_HINT_PARAREMOVED event"); 2061 2062 Paragraphs::iterator aIt(m_xParagraphs->begin() + n); 2063 // numeric overflow cannot occur 2064 2065 // Save the values of old iterators (the iterators 2066 // themselves will get invalidated), and adjust the old 2067 // values so that they reflect the removal of the paragraph: 2068 Paragraphs::size_type nOldVisibleBegin 2069 = m_aVisibleBegin - m_xParagraphs->begin(); 2070 Paragraphs::size_type nOldVisibleEnd 2071 = m_aVisibleEnd - m_xParagraphs->begin(); 2072 bool bWasVisible 2073 = nOldVisibleBegin <= n && n < nOldVisibleEnd; 2074 Paragraphs::size_type nOldFocused 2075 = m_aFocused - m_xParagraphs->begin(); 2076 bool bWasFocused = aIt == m_aFocused; 2077 if (n < nOldVisibleBegin) 2078 --nOldVisibleBegin; 2079 if (n < nOldVisibleEnd) 2080 --nOldVisibleEnd; 2081 if (n < nOldFocused) 2082 --nOldFocused; 2083 if (sal::static_int_cast<sal_Int32>(n) < m_nSelectionFirstPara) 2084 --m_nSelectionFirstPara; 2085 else if (sal::static_int_cast<sal_Int32>(n) == m_nSelectionFirstPara) 2086 { 2087 if (m_nSelectionFirstPara == m_nSelectionLastPara) 2088 { 2089 m_nSelectionFirstPara = -1; 2090 m_nSelectionFirstPos = -1; 2091 m_nSelectionLastPara = -1; 2092 m_nSelectionLastPos = -1; 2093 } 2094 else 2095 { 2096 ++m_nSelectionFirstPara; 2097 m_nSelectionFirstPos = 0; 2098 } 2099 } 2100 if (sal::static_int_cast<sal_Int32>(n) < m_nSelectionLastPara) 2101 --m_nSelectionLastPara; 2102 else if (sal::static_int_cast<sal_Int32>(n) == m_nSelectionLastPara) 2103 { 2104 OSL_ENSURE(m_nSelectionFirstPara < m_nSelectionLastPara, 2105 "logic error"); 2106 --m_nSelectionLastPara; 2107 m_nSelectionLastPos = 0x7FFFFFFF; 2108 } 2109 2110 ::css::uno::Reference< ::css::accessibility::XAccessible > 2111 xStrong; 2112 if (bWasVisible) 2113 xStrong = getAccessibleChild(aIt); 2114 ::css::uno::WeakReference< 2115 ::css::accessibility::XAccessible > xWeak( 2116 aIt->getParagraph()); 2117 aIt = m_xParagraphs->erase(aIt); 2118 2119 determineVisibleRange(); 2120 m_aFocused = bWasFocused ? m_xParagraphs->end() 2121 : m_xParagraphs->begin() + nOldFocused; 2122 2123 for (; aIt != m_xParagraphs->end(); ++aIt) 2124 { 2125 ::rtl::Reference< ParagraphImpl > xParagraph( 2126 getParagraph(aIt)); 2127 if (xParagraph.is()) 2128 xParagraph->numberChanged(false); 2129 } 2130 2131 if (bWasVisible) 2132 NotifyAccessibleEvent( 2133 ::css::accessibility::AccessibleEventId:: 2134 CHILD, 2135 ::css::uno::makeAny(getAccessibleChild(aIt)), 2136 ::css::uno::Any()); 2137 2138 ::css::uno::Reference< ::css::lang::XComponent > xComponent( 2139 xWeak.get(), ::css::uno::UNO_QUERY); 2140 if (xComponent.is()) 2141 xComponent->dispose(); 2142 2143 notifyVisibleRangeChanges( 2144 m_xParagraphs->begin() + nOldVisibleBegin, 2145 m_xParagraphs->begin() + nOldVisibleEnd, 2146 m_xParagraphs->end()); 2147 } 2148 break; 2149 } 2150 case TEXT_HINT_FORMATPARA: 2151 { 2152 ::sal_uLong n = aHint.GetValue(); 2153 OSL_ENSURE(n < m_xParagraphs->size(), 2154 "Bad TEXT_HINT_FORMATPARA event"); 2155 2156 (*m_xParagraphs)[static_cast< Paragraphs::size_type >(n)]. 2157 changeHeight(static_cast< ::sal_Int32 >( 2158 m_rEngine.GetTextHeight(n))); 2159 // XXX numeric overflow 2160 Paragraphs::iterator aOldVisibleBegin(m_aVisibleBegin); 2161 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd); 2162 determineVisibleRange(); 2163 notifyVisibleRangeChanges(aOldVisibleBegin, aOldVisibleEnd, 2164 m_xParagraphs->end()); 2165 2166 if (n < m_xParagraphs->size()) 2167 { 2168 Paragraphs::iterator aIt(m_xParagraphs->begin() + n); 2169 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt)); 2170 if (xParagraph.is()) 2171 xParagraph->textChanged(); 2172 } 2173 break; 2174 } 2175 default: 2176 OSL_ENSURE(false, "bad buffered hint"); 2177 break; 2178 } 2179 } 2180 if (m_bSelectionChangedNotification) 2181 { 2182 m_bSelectionChangedNotification = false; 2183 handleSelectionChangeNotification(); 2184 } 2185 } 2186 2187 ::sal_Int32 Document::getSelectionType(::sal_Int32 nNewFirstPara, ::sal_Int32 nNewFirstPos, ::sal_Int32 nNewLastPara, ::sal_Int32 nNewLastPos) 2188 { 2189 if (m_nSelectionFirstPara == -1) 2190 return -1; 2191 ::sal_Int32 Osp = m_nSelectionFirstPara, Osl = m_nSelectionFirstPos, Oep = m_nSelectionLastPara, Oel = m_nSelectionLastPos; 2192 ::sal_Int32 Nsp = nNewFirstPara, Nsl = nNewFirstPos, Nep = nNewLastPara, Nel = nNewLastPos; 2193 TextPaM Ns(Nsp, sal_uInt16(Nsl)); 2194 TextPaM Ne(Nep, sal_uInt16(Nel)); 2195 TextPaM Os(Osp, sal_uInt16(Osl)); 2196 TextPaM Oe(Oep, sal_uInt16(Oel)); 2197 2198 if (Os == Oe && Ns == Ne) 2199 { 2200 //only caret moves. 2201 return 1; 2202 } 2203 else if (Os == Oe && Ns != Ne) 2204 { 2205 //old has no selection but new has selection 2206 return 2; 2207 } 2208 else if (Os != Oe && Ns == Ne) 2209 { 2210 //old has selection but new has no selection. 2211 return 3; 2212 } 2213 else if (Os != Oe && Ns != Ne && Osp == Nsp && Osl == Nsl) 2214 { 2215 //both old and new have selections. 2216 if (Oep == Nep ) 2217 { 2218 //Send text_selection_change event on Nep 2219 2220 return 4; 2221 } 2222 else if (Oep < Nep) 2223 { 2224 //all the following examples like 1,2->1,3 means that old start select para is 1, old end select para is 2, 2225 // then press shift up, the new start select para is 1, new end select para is 3; 2226 //for example, 1, 2 -> 1, 3; 4,1 -> 4, 7; 4,1 -> 4, 2; 4,4->4,5 2227 if (Nep >= Nsp) 2228 { 2229 // 1, 2 -> 1, 3; 4, 1 -> 4, 7; 4,4->4,5; 2230 if (Oep < Osp) 2231 { 2232 // 4,1 -> 4,7; 2233 return 5; 2234 } 2235 else if (Oep >= Osp) 2236 { 2237 // 1, 2 -> 1, 3; 4,4->4,5; 2238 return 6; 2239 } 2240 } 2241 else 2242 { 2243 // 4,1 -> 4,2, 2244 if (Oep < Osp) 2245 { 2246 // 4,1 -> 4,2, 2247 return 7; 2248 } 2249 else if (Oep >= Osp) 2250 { 2251 // no such condition. Oep > Osp = Nsp > Nep 2252 } 2253 } 2254 } 2255 else if (Oep > Nep) 2256 { 2257 // 3,2 -> 3,1; 4,7 -> 4,1; 4, 7 -> 4,6; 4,4 -> 4,3 2258 if (Nep >= Nsp) 2259 { 2260 // 4,7 -> 4,6 2261 if (Oep <= Osp) 2262 { 2263 //no such condition, Oep<Osp=Nsp <= Nep 2264 } 2265 else if (Oep > Osp) 2266 { 2267 // 4,7 ->4,6 2268 return 8; 2269 } 2270 } 2271 else 2272 { 2273 // 3,2 -> 3,1, 4,7 -> 4,1; 4,4->4,3 2274 if (Oep <= Osp) 2275 { 2276 // 3,2 -> 3,1; 4,4->4,3 2277 return 9; 2278 } 2279 else if (Oep > Osp) 2280 { 2281 // 4,7 -> 4,1 2282 return 10; 2283 } 2284 } 2285 } 2286 } 2287 return -1; 2288 } 2289 2290 2291 void Document::sendEvent(::sal_Int32 start, ::sal_Int32 end, ::sal_Int16 nEventId) 2292 { 2293 Paragraphs::iterator aEnd = ::std::min(m_xParagraphs->begin() + end + 1, m_aVisibleEnd); 2294 for (Paragraphs::iterator aIt = ::std::max(m_xParagraphs->begin() + start, m_aVisibleBegin); 2295 aIt < aEnd; ++aIt) 2296 { 2297 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt)); 2298 if (xParagraph.is()) 2299 xParagraph->notifyEvent( 2300 nEventId, 2301 ::css::uno::Any(), ::css::uno::Any()); 2302 } 2303 } 2304 2305 void Document::handleSelectionChangeNotification() 2306 { 2307 ::TextSelection const & rSelection = m_rView.GetSelection(); 2308 OSL_ENSURE(rSelection.GetStart().GetPara() < m_xParagraphs->size() 2309 && rSelection.GetEnd().GetPara() < m_xParagraphs->size(), 2310 "bad TEXT_HINT_VIEWSELECTIONCHANGED event"); 2311 ::sal_Int32 nNewFirstPara 2312 = static_cast< ::sal_Int32 >(rSelection.GetStart().GetPara()); 2313 ::sal_Int32 nNewFirstPos 2314 = static_cast< ::sal_Int32 >(rSelection.GetStart().GetIndex()); 2315 // XXX numeric overflow 2316 ::sal_Int32 nNewLastPara 2317 = static_cast< ::sal_Int32 >(rSelection.GetEnd().GetPara()); 2318 ::sal_Int32 nNewLastPos 2319 = static_cast< ::sal_Int32 >(rSelection.GetEnd().GetIndex()); 2320 // XXX numeric overflow 2321 2322 // Lose focus: 2323 Paragraphs::iterator aIt(m_xParagraphs->begin() + nNewLastPara); 2324 if (m_aFocused != m_xParagraphs->end() && m_aFocused != aIt 2325 && m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd) 2326 { 2327 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(m_aFocused)); 2328 if (xParagraph.is()) 2329 xParagraph->notifyEvent( 2330 ::css::accessibility::AccessibleEventId:: 2331 STATE_CHANGED, 2332 ::css::uno::makeAny( 2333 ::css::accessibility::AccessibleStateType::FOCUSED), 2334 ::css::uno::Any()); 2335 } 2336 2337 // Gain focus and update cursor position: 2338 if (aIt >= m_aVisibleBegin && aIt < m_aVisibleEnd 2339 && (aIt != m_aFocused 2340 || nNewLastPara != m_nSelectionLastPara 2341 || nNewLastPos != m_nSelectionLastPos)) 2342 { 2343 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt)); 2344 if (xParagraph.is()) 2345 { 2346 //disable the first event when user types in empty field. 2347 ::sal_Int32 count = getAccessibleChildCount(); 2348 ::sal_Bool bEmpty = count > 1; 2349 //if (aIt != m_aFocused) 2350 if (aIt != m_aFocused && bEmpty) 2351 xParagraph->notifyEvent( 2352 ::css::accessibility::AccessibleEventId:: 2353 STATE_CHANGED, 2354 ::css::uno::Any(), 2355 ::css::uno::makeAny( 2356 ::css::accessibility::AccessibleStateType::FOCUSED)); 2357 if (nNewLastPara != m_nSelectionLastPara 2358 || nNewLastPos != m_nSelectionLastPos) 2359 xParagraph->notifyEvent( 2360 ::css::accessibility::AccessibleEventId:: 2361 CARET_CHANGED, 2362 ::css::uno::makeAny< ::sal_Int32 >( 2363 nNewLastPara == m_nSelectionLastPara 2364 ? m_nSelectionLastPos : 0), 2365 ::css::uno::makeAny(nNewLastPos)); 2366 } 2367 } 2368 m_aFocused = aIt; 2369 2370 ::sal_Int32 nMin; 2371 ::sal_Int32 nMax; 2372 ::sal_Int32 ret = getSelectionType(nNewFirstPara, nNewFirstPos, nNewLastPara, nNewLastPos); 2373 switch (ret) 2374 { 2375 case -1: 2376 { 2377 //no event 2378 } 2379 break; 2380 case 1: 2381 { 2382 //only caret moved, already handled in above 2383 } 2384 break; 2385 case 2: 2386 { 2387 //old has no selection but new has selection 2388 nMin = ::std::min(nNewFirstPara, nNewLastPara); 2389 nMax = ::std::max(nNewFirstPara, nNewLastPara); 2390 sendEvent(nMin, nMax, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2391 sendEvent(nMin, nMax, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2392 } 2393 break; 2394 case 3: 2395 { 2396 //old has selection but new has no selection. 2397 nMin = ::std::min(m_nSelectionFirstPara, m_nSelectionLastPara); 2398 nMax = ::std::max(m_nSelectionFirstPara, m_nSelectionLastPara); 2399 sendEvent(nMin, nMax, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2400 sendEvent(nMin, nMax, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2401 } 2402 break; 2403 case 4: 2404 { 2405 //Send text_selection_change event on Nep 2406 sendEvent(nNewLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2407 } 2408 break; 2409 case 5: 2410 { 2411 // 4, 1 -> 4, 7 2412 sendEvent(m_nSelectionLastPara, m_nSelectionFirstPara-1, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2413 sendEvent(nNewFirstPara+1, nNewLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2414 2415 sendEvent(m_nSelectionLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2416 } 2417 break; 2418 case 6: 2419 { 2420 // 1, 2 -> 1, 4; 4,4->4,5; 2421 sendEvent(m_nSelectionLastPara+1, nNewLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2422 2423 sendEvent(m_nSelectionLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2424 } 2425 break; 2426 case 7: 2427 { 2428 // 4,1 -> 4,3, 2429 sendEvent(m_nSelectionLastPara +1, nNewLastPara , ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2430 2431 sendEvent(m_nSelectionLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2432 } 2433 break; 2434 case 8: 2435 { 2436 // 4,7 ->4,5; 2437 sendEvent(nNewLastPara + 1, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2438 2439 sendEvent(nNewLastPara, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2440 } 2441 break; 2442 case 9: 2443 { 2444 // 3,2 -> 3,1; 4,4->4,3 2445 sendEvent(nNewLastPara, m_nSelectionLastPara - 1, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2446 2447 sendEvent(nNewLastPara, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2448 } 2449 break; 2450 case 10: 2451 { 2452 // 4,7 -> 4,1 2453 sendEvent(m_nSelectionFirstPara + 1, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2454 sendEvent(nNewLastPara, nNewFirstPara - 1, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2455 2456 sendEvent(nNewLastPara, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2457 } 2458 break; 2459 default: 2460 break; 2461 } 2462 2463 /* 2464 // Update both old and new selection. (Regardless of how the two selections 2465 // look like, there will always be two ranges to the left and right of the 2466 // overlap---the overlap and/or the range to the right of it possibly being 2467 // empty. Only for these two ranges notifications have to be sent.) 2468 2469 TextPaM aOldTextStart( static_cast< sal_uLong >( m_nSelectionFirstPara ), static_cast< sal_uInt16 >( m_nSelectionFirstPos ) ); 2470 TextPaM aOldTextEnd( static_cast< sal_uLong >( m_nSelectionLastPara ), static_cast< sal_uInt16 >( m_nSelectionLastPos ) ); 2471 TextPaM aNewTextStart( static_cast< sal_uLong >( nNewFirstPara ), static_cast< sal_uInt16 >( nNewFirstPos ) ); 2472 TextPaM aNewTextEnd( static_cast< sal_uLong >( nNewLastPara ), static_cast< sal_uInt16 >( nNewLastPos ) ); 2473 2474 // justify selections 2475 justifySelection( aOldTextStart, aOldTextEnd ); 2476 justifySelection( aNewTextStart, aNewTextEnd ); 2477 2478 sal_Int32 nFirst1; 2479 sal_Int32 nLast1; 2480 sal_Int32 nFirst2; 2481 sal_Int32 nLast2; 2482 2483 if ( m_nSelectionFirstPara == -1 ) 2484 { 2485 // old selection not initialized yet => notify events only for new selection (if not empty) 2486 nFirst1 = aNewTextStart.GetPara(); 2487 nLast1 = aNewTextEnd.GetPara() + ( aNewTextStart != aNewTextEnd ? 1 : 0 ); 2488 nFirst2 = 0; 2489 nLast2 = 0; 2490 } 2491 else if ( aOldTextStart == aOldTextEnd && aNewTextStart == aNewTextEnd ) 2492 { 2493 // old an new selection empty => no events 2494 nFirst1 = 0; 2495 nLast1 = 0; 2496 nFirst2 = 0; 2497 nLast2 = 0; 2498 } 2499 else if ( aOldTextStart != aOldTextEnd && aNewTextStart == aNewTextEnd ) 2500 { 2501 // old selection not empty + new selection empty => notify events only for old selection 2502 nFirst1 = aOldTextStart.GetPara(); 2503 nLast1 = aOldTextEnd.GetPara() + 1; 2504 nFirst2 = 0; 2505 nLast2 = 0; 2506 } 2507 else if ( aOldTextStart == aOldTextEnd && aNewTextStart != aNewTextEnd ) 2508 { 2509 // old selection empty + new selection not empty => notify events only for new selection 2510 nFirst1 = aNewTextStart.GetPara(); 2511 nLast1 = aNewTextEnd.GetPara() + 1; 2512 nFirst2 = 0; 2513 nLast2 = 0; 2514 } 2515 else 2516 { 2517 // old and new selection not empty => notify events for the two ranges left and right of the overlap 2518 ::std::vector< TextPaM > aTextPaMs(4); 2519 aTextPaMs[0] = aOldTextStart; 2520 aTextPaMs[1] = aOldTextEnd; 2521 aTextPaMs[2] = aNewTextStart; 2522 aTextPaMs[3] = aNewTextEnd; 2523 ::std::sort( aTextPaMs.begin(), aTextPaMs.end() ); 2524 2525 nFirst1 = aTextPaMs[0].GetPara(); 2526 nLast1 = aTextPaMs[1].GetPara() + ( aTextPaMs[0] != aTextPaMs[1] ? 1 : 0 ); 2527 2528 nFirst2 = aTextPaMs[2].GetPara(); 2529 nLast2 = aTextPaMs[3].GetPara() + ( aTextPaMs[2] != aTextPaMs[3] ? 1 : 0 ); 2530 2531 // adjust overlapping ranges 2532 if ( nLast1 > nFirst2 ) 2533 nLast1 = nFirst2; 2534 } 2535 2536 // notify selection changes 2537 notifySelectionChange( nFirst1, nLast1 ); 2538 notifySelectionChange( nFirst2, nLast2 ); 2539 */ 2540 m_nSelectionFirstPara = nNewFirstPara; 2541 m_nSelectionFirstPos = nNewFirstPos; 2542 m_nSelectionLastPara = nNewLastPara; 2543 m_nSelectionLastPos = nNewLastPos; 2544 } 2545 2546 void Document::notifySelectionChange( sal_Int32 nFirst, sal_Int32 nLast ) 2547 { 2548 if ( nFirst < nLast ) 2549 { 2550 Paragraphs::iterator aEnd( ::std::min( m_xParagraphs->begin() + nLast, m_aVisibleEnd ) ); 2551 for ( Paragraphs::iterator aIt = ::std::max( m_xParagraphs->begin() + nFirst, m_aVisibleBegin ); aIt < aEnd; ++aIt ) 2552 { 2553 ::rtl::Reference< ParagraphImpl > xParagraph( getParagraph( aIt ) ); 2554 if ( xParagraph.is() ) 2555 { 2556 xParagraph->notifyEvent( 2557 ::css::accessibility::AccessibleEventId::SELECTION_CHANGED, 2558 ::css::uno::Any(), ::css::uno::Any() ); 2559 xParagraph->notifyEvent( 2560 ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED, 2561 ::css::uno::Any(), ::css::uno::Any() ); 2562 } 2563 } 2564 } 2565 } 2566 2567 void Document::justifySelection( TextPaM& rTextStart, TextPaM& rTextEnd ) 2568 { 2569 if ( rTextStart > rTextEnd ) 2570 { 2571 TextPaM aTextPaM( rTextStart ); 2572 rTextStart = rTextEnd; 2573 rTextEnd = aTextPaM; 2574 } 2575 } 2576 2577 void Document::disposeParagraphs() 2578 { 2579 for (Paragraphs::iterator aIt(m_xParagraphs->begin()); 2580 aIt != m_xParagraphs->end(); ++aIt) 2581 { 2582 ::css::uno::Reference< ::css::lang::XComponent > xComponent( 2583 aIt->getParagraph().get(), ::css::uno::UNO_QUERY); 2584 if (xComponent.is()) 2585 xComponent->dispose(); 2586 } 2587 } 2588 2589 // static 2590 ::css::uno::Any Document::mapFontColor(::Color const & rColor) 2591 { 2592 return ::css::uno::makeAny( 2593 static_cast< ::sal_Int32 >(COLORDATA_RGB(rColor.GetColor()))); 2594 // FIXME keep transparency? 2595 } 2596 2597 // static 2598 ::Color Document::mapFontColor(::css::uno::Any const & rColor) 2599 { 2600 ::sal_Int32 nColor = 0; 2601 rColor >>= nColor; 2602 return ::Color(static_cast< ::ColorData >(nColor)); 2603 } 2604 2605 // static 2606 ::css::uno::Any Document::mapFontWeight(::FontWeight nWeight) 2607 { 2608 // Map from ::FontWeight to ::css:awt::FontWeight, depends on order of 2609 // elements in ::FontWeight (vcl/vclenum.hxx): 2610 static float const aWeight[] 2611 = { ::css::awt::FontWeight::DONTKNOW, // WEIGHT_DONTKNOW 2612 ::css::awt::FontWeight::THIN, // WEIGHT_THIN 2613 ::css::awt::FontWeight::ULTRALIGHT, // WEIGHT_ULTRALIGHT 2614 ::css::awt::FontWeight::LIGHT, // WEIGHT_LIGHT 2615 ::css::awt::FontWeight::SEMILIGHT, // WEIGHT_SEMILIGHT 2616 ::css::awt::FontWeight::NORMAL, // WEIGHT_NORMAL 2617 ::css::awt::FontWeight::NORMAL, // WEIGHT_MEDIUM 2618 ::css::awt::FontWeight::SEMIBOLD, // WEIGHT_SEMIBOLD 2619 ::css::awt::FontWeight::BOLD, // WEIGHT_BOLD 2620 ::css::awt::FontWeight::ULTRABOLD, // WEIGHT_ULTRABOLD 2621 ::css::awt::FontWeight::BLACK }; // WEIGHT_BLACK 2622 return ::css::uno::makeAny(aWeight[nWeight]); 2623 } 2624 2625 // static 2626 ::FontWeight Document::mapFontWeight(::css::uno::Any const & rWeight) 2627 { 2628 float nWeight = ::css::awt::FontWeight::NORMAL; 2629 rWeight >>= nWeight; 2630 return nWeight <= ::css::awt::FontWeight::DONTKNOW ? WEIGHT_DONTKNOW 2631 : nWeight <= ::css::awt::FontWeight::THIN ? WEIGHT_THIN 2632 : nWeight <= ::css::awt::FontWeight::ULTRALIGHT ? WEIGHT_ULTRALIGHT 2633 : nWeight <= ::css::awt::FontWeight::LIGHT ? WEIGHT_LIGHT 2634 : nWeight <= ::css::awt::FontWeight::SEMILIGHT ? WEIGHT_SEMILIGHT 2635 : nWeight <= ::css::awt::FontWeight::NORMAL ? WEIGHT_NORMAL 2636 : nWeight <= ::css::awt::FontWeight::SEMIBOLD ? WEIGHT_SEMIBOLD 2637 : nWeight <= ::css::awt::FontWeight::BOLD ? WEIGHT_BOLD 2638 : nWeight <= ::css::awt::FontWeight::ULTRABOLD ? WEIGHT_ULTRABOLD 2639 : WEIGHT_BLACK; 2640 } 2641 2642 } 2643 2644