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