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 // Sym2_6109, 1051 //aAttribs[i].Value = mapFontColor( aFont.GetColor() ); 1052 aAttribs[i].Value = mapFontColor( m_rEngine.GetTextColor() ); 1053 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; 1054 i++; 1055 } 1056 //character font name 1057 { 1058 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharFontName")); 1059 aAttribs[i].Handle = -1; 1060 aAttribs[i].Value = ::css::uno::makeAny( (::rtl::OUString)aFont.GetName() ); 1061 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; 1062 i++; 1063 } 1064 //character height 1065 { 1066 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharHeight")); 1067 aAttribs[i].Handle = -1; 1068 aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetHeight() ); 1069 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; 1070 i++; 1071 } 1072 //character posture 1073 { 1074 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharPosture")); 1075 aAttribs[i].Handle = -1; 1076 aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetItalic() ); 1077 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; 1078 i++; 1079 } 1080 //character relief 1081 /*{ 1082 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharRelief")); 1083 aAttribs[i].Handle = -1; 1084 aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetRelief() ); 1085 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; 1086 i++; 1087 }*/ 1088 //character strikeout 1089 { 1090 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharStrikeout")); 1091 aAttribs[i].Handle = -1; 1092 aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetStrikeout() ); 1093 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; 1094 i++; 1095 } 1096 //character underline 1097 { 1098 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharUnderline")); 1099 aAttribs[i].Handle = -1; 1100 aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetUnderline() ); 1101 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; 1102 i++; 1103 } 1104 //character weight 1105 { 1106 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharWeight")); 1107 aAttribs[i].Handle = -1; 1108 aAttribs[i].Value = ::css::uno::makeAny( (float)aFont.GetWeight() ); 1109 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; 1110 i++; 1111 } 1112 //character alignment 1113 { 1114 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ParaAdjust")); 1115 aAttribs[i].Handle = -1; 1116 aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)m_rEngine.GetTextAlign() ); 1117 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; 1118 i++; 1119 } 1120 ::osl::MutexGuard aInternalGuard(GetMutex()); 1121 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber()); 1122 // XXX numeric overflow 1123 // nIndex can be equal to Len(); 1124 //if (nIndex < 0 || nIndex >= m_rEngine.GetText(nNumber).Len()) 1125 if (nIndex < 0 || nIndex > m_rEngine.GetText(nNumber).Len()) 1126 throw ::css::lang::IndexOutOfBoundsException( 1127 ::rtl::OUString( 1128 RTL_CONSTASCII_USTRINGPARAM( 1129 "textwindowaccessibility.cxx:" 1130 " Document::retrieveCharacterAttributes")), 1131 static_cast< ::css::uno::XWeak * >(this)); 1132 1133 // retrieve default attributes 1134 tPropValMap aCharAttrSeq; 1135 retrieveDefaultAttributesImpl( pParagraph, aRequestedAttributes, aCharAttrSeq ); 1136 1137 // retrieve run attributes 1138 tPropValMap aRunAttrSeq; 1139 retrieveRunAttributesImpl( pParagraph, nIndex, aRequestedAttributes, aRunAttrSeq ); 1140 1141 // merge default and run attributes 1142 for ( tPropValMap::const_iterator aRunIter = aRunAttrSeq.begin(); 1143 aRunIter != aRunAttrSeq.end(); 1144 ++aRunIter ) 1145 { 1146 aCharAttrSeq[ aRunIter->first ] = aRunIter->second; 1147 } 1148 1149 ::css::beans::PropertyValue* pValues = aAttribs.getArray(); 1150 for (i = 0; i < AttributeCount; i++,pValues++) 1151 { 1152 aCharAttrSeq[ pValues->Name ] = *pValues; 1153 } 1154 1155 ::css::uno::Sequence< ::css::beans::PropertyValue > aRes = convertHashMapToSequence( aCharAttrSeq ); 1156 1157 // Sym2_6109, sort the attributes 1158 sal_Int32 nLength = aRes.getLength(); 1159 const ::css::beans::PropertyValue* pPairs = aRes.getConstArray(); 1160 sal_Int32* pIndices = new sal_Int32[nLength]; 1161 for( i = 0; i < nLength; i++ ) 1162 pIndices[i] = i; 1163 std::sort( &pIndices[0], &pIndices[nLength], IndexCompare(pPairs) ); 1164 // create sorted sequences accoring to index array 1165 ::css::uno::Sequence< ::css::beans::PropertyValue > aNewValues( nLength ); 1166 ::css::beans::PropertyValue* pNewValues = aNewValues.getArray(); 1167 for( i = 0; i < nLength; i++ ) 1168 { 1169 pNewValues[i] = pPairs[pIndices[i]]; 1170 } 1171 delete[] pIndices; 1172 1173 return aNewValues; 1174 } 1175 1176 void Document::retrieveDefaultAttributesImpl( 1177 ParagraphImpl const * pParagraph, 1178 const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes, 1179 tPropValMap& rDefAttrSeq) 1180 { 1181 // default attributes are not supported by text engine 1182 (void) pParagraph; 1183 (void) RequestedAttributes; 1184 (void) rDefAttrSeq; 1185 } 1186 1187 ::css::uno::Sequence< ::css::beans::PropertyValue > 1188 Document::retrieveDefaultAttributes( 1189 ParagraphImpl const * pParagraph, 1190 const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes) 1191 { 1192 ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() ); 1193 ::osl::MutexGuard aInternalGuard( GetMutex() ); 1194 1195 tPropValMap aDefAttrSeq; 1196 retrieveDefaultAttributesImpl( pParagraph, RequestedAttributes, aDefAttrSeq ); 1197 return convertHashMapToSequence( aDefAttrSeq ); 1198 } 1199 1200 // static 1201 ::css::uno::Sequence< ::css::beans::PropertyValue > 1202 Document::convertHashMapToSequence(tPropValMap& rAttrSeq) 1203 { 1204 ::css::uno::Sequence< ::css::beans::PropertyValue > aValues( rAttrSeq.size() ); 1205 ::css::beans::PropertyValue* pValues = aValues.getArray(); 1206 ::sal_Int32 i = 0; 1207 for ( tPropValMap::const_iterator aIter = rAttrSeq.begin(); 1208 aIter != rAttrSeq.end(); 1209 ++aIter ) 1210 { 1211 pValues[i] = aIter->second; 1212 ++i; 1213 } 1214 return aValues; 1215 } 1216 1217 void Document::retrieveRunAttributesImpl( 1218 ParagraphImpl const * pParagraph, ::sal_Int32 Index, 1219 const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes, 1220 tPropValMap& rRunAttrSeq) 1221 { 1222 ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() ); 1223 ::TextPaM aPaM( nNumber, static_cast< ::sal_uInt16 >( Index ) ); 1224 // XXX numeric overflow 1225 // FIXME TEXTATTR_HYPERLINK ignored: 1226 ::TextAttribFontColor const * pColor 1227 = static_cast< ::TextAttribFontColor const * >( 1228 m_rEngine.FindAttrib( aPaM, TEXTATTR_FONTCOLOR ) ); 1229 ::TextAttribFontWeight const * pWeight 1230 = static_cast< ::TextAttribFontWeight const * >( 1231 m_rEngine.FindAttrib( aPaM, TEXTATTR_FONTWEIGHT ) ); 1232 tPropValMap aRunAttrSeq; 1233 if ( pColor ) 1234 { 1235 ::css::beans::PropertyValue aPropVal; 1236 aPropVal.Name = 1237 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CharColor" ) ); 1238 aPropVal.Handle = -1; 1239 aPropVal.Value = mapFontColor( pColor->GetColor() ); 1240 aPropVal.State = ::css::beans::PropertyState_DIRECT_VALUE; 1241 aRunAttrSeq[ aPropVal.Name ] = aPropVal; 1242 } 1243 if ( pWeight ) 1244 { 1245 ::css::beans::PropertyValue aPropVal; 1246 aPropVal.Name = 1247 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CharWeight" ) ); 1248 aPropVal.Handle = -1; 1249 aPropVal.Value = mapFontWeight( pWeight->getFontWeight() ); 1250 aPropVal.State = ::css::beans::PropertyState_DIRECT_VALUE; 1251 aRunAttrSeq[ aPropVal.Name ] = aPropVal; 1252 } 1253 if ( RequestedAttributes.getLength() == 0 ) 1254 { 1255 rRunAttrSeq = aRunAttrSeq; 1256 } 1257 else 1258 { 1259 const ::rtl::OUString* pReqAttrs = RequestedAttributes.getConstArray(); 1260 const ::sal_Int32 nLength = RequestedAttributes.getLength(); 1261 for ( ::sal_Int32 i = 0; i < nLength; ++i ) 1262 { 1263 tPropValMap::iterator aIter = aRunAttrSeq.find( pReqAttrs[i] ); 1264 if ( aIter != aRunAttrSeq.end() ) 1265 { 1266 rRunAttrSeq[ (*aIter).first ] = (*aIter).second; 1267 } 1268 } 1269 } 1270 } 1271 1272 ::css::uno::Sequence< ::css::beans::PropertyValue > 1273 Document::retrieveRunAttributes( 1274 ParagraphImpl const * pParagraph, ::sal_Int32 Index, 1275 const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes) 1276 { 1277 ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() ); 1278 ::osl::MutexGuard aInternalGuard( GetMutex() ); 1279 ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() ); 1280 // XXX numeric overflow 1281 if ( Index < 0 || Index >= m_rEngine.GetText(nNumber).Len() ) 1282 throw ::css::lang::IndexOutOfBoundsException( 1283 ::rtl::OUString( 1284 RTL_CONSTASCII_USTRINGPARAM( 1285 "textwindowaccessibility.cxx:" 1286 " Document::retrieveRunAttributes") ), 1287 static_cast< ::css::uno::XWeak * >( this ) ); 1288 1289 tPropValMap aRunAttrSeq; 1290 retrieveRunAttributesImpl( pParagraph, Index, RequestedAttributes, aRunAttrSeq ); 1291 return convertHashMapToSequence( aRunAttrSeq ); 1292 } 1293 1294 void Document::changeParagraphText(ParagraphImpl * pParagraph, 1295 ::rtl::OUString const & rText) 1296 { 1297 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); 1298 { 1299 ::osl::MutexGuard aInternalGuard(GetMutex()); 1300 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber()); 1301 // XXX numeric overflow 1302 changeParagraphText(nNumber, 0, m_rEngine.GetTextLen(nNumber), false, 1303 false, rText); 1304 } 1305 } 1306 1307 void Document::changeParagraphText(ParagraphImpl * pParagraph, 1308 ::sal_Int32 nBegin, ::sal_Int32 nEnd, 1309 bool bCut, bool bPaste, 1310 ::rtl::OUString const & rText) 1311 { 1312 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); 1313 { 1314 ::osl::MutexGuard aInternalGuard(GetMutex()); 1315 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber()); 1316 // XXX numeric overflow 1317 if (nBegin < 0 || nBegin > nEnd 1318 || nEnd > m_rEngine.GetText(nNumber).Len()) 1319 throw ::css::lang::IndexOutOfBoundsException( 1320 ::rtl::OUString( 1321 RTL_CONSTASCII_USTRINGPARAM( 1322 "textwindowaccessibility.cxx:" 1323 " Document::changeParagraphText")), 1324 static_cast< ::css::uno::XWeak * >(this)); 1325 changeParagraphText(nNumber, static_cast< ::sal_uInt16 >(nBegin), 1326 static_cast< ::sal_uInt16 >(nEnd), bCut, bPaste, rText); 1327 // XXX numeric overflow (2x) 1328 } 1329 } 1330 1331 void Document::copyParagraphText(ParagraphImpl const * pParagraph, 1332 ::sal_Int32 nBegin, ::sal_Int32 nEnd) 1333 { 1334 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); 1335 { 1336 ::osl::MutexGuard aInternalGuard(GetMutex()); 1337 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber()); 1338 // XXX numeric overflow 1339 if (nBegin < 0 || nBegin > nEnd 1340 || nEnd > m_rEngine.GetText(nNumber).Len()) 1341 throw ::css::lang::IndexOutOfBoundsException( 1342 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 1343 "textwindowaccessibility.cxx:" 1344 " Document::copyParagraphText")), 1345 static_cast< ::css::uno::XWeak * >(this)); 1346 m_rView.SetSelection( 1347 ::TextSelection(::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nBegin)), 1348 ::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nEnd)))); 1349 // XXX numeric overflow (2x) 1350 m_rView.Copy(); 1351 } 1352 } 1353 1354 void Document::changeParagraphAttributes( 1355 ParagraphImpl * pParagraph, ::sal_Int32 nBegin, ::sal_Int32 nEnd, 1356 ::css::uno::Sequence< ::css::beans::PropertyValue > const & rAttributeSet) 1357 { 1358 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); 1359 { 1360 ::osl::MutexGuard aInternalGuard(GetMutex()); 1361 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber()); 1362 // XXX numeric overflow 1363 if (nBegin < 0 || nBegin > nEnd 1364 || nEnd > m_rEngine.GetText(nNumber).Len()) 1365 throw ::css::lang::IndexOutOfBoundsException( 1366 ::rtl::OUString( 1367 RTL_CONSTASCII_USTRINGPARAM( 1368 "textwindowaccessibility.cxx:" 1369 " Document::changeParagraphAttributes")), 1370 static_cast< ::css::uno::XWeak * >(this)); 1371 1372 // FIXME The new attributes are added to any attributes already set, 1373 // they do not replace the old attributes as required by 1374 // XAccessibleEditableText.setAttributes: 1375 for (::sal_Int32 i = 0; i < rAttributeSet.getLength(); ++i) 1376 if (rAttributeSet[i].Name.equalsAsciiL( 1377 RTL_CONSTASCII_STRINGPARAM("CharColor"))) 1378 m_rEngine.SetAttrib(::TextAttribFontColor( 1379 mapFontColor(rAttributeSet[i].Value)), 1380 nNumber, static_cast< ::sal_uInt16 >(nBegin), 1381 static_cast< ::sal_uInt16 >(nEnd)); 1382 // XXX numeric overflow (2x) 1383 else if (rAttributeSet[i].Name.equalsAsciiL( 1384 RTL_CONSTASCII_STRINGPARAM("CharWeight"))) 1385 m_rEngine.SetAttrib(::TextAttribFontWeight( 1386 mapFontWeight(rAttributeSet[i].Value)), 1387 nNumber, static_cast< ::sal_uInt16 >(nBegin), 1388 static_cast< ::sal_uInt16 >(nEnd)); 1389 // XXX numeric overflow (2x) 1390 } 1391 } 1392 1393 void Document::changeParagraphSelection(ParagraphImpl * pParagraph, 1394 ::sal_Int32 nBegin, ::sal_Int32 nEnd) 1395 { 1396 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); 1397 { 1398 ::osl::MutexGuard aInternalGuard(GetMutex()); 1399 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber()); 1400 // XXX numeric overflow 1401 if (nBegin < 0 || nBegin > nEnd 1402 || nEnd > m_rEngine.GetText(nNumber).Len()) 1403 throw ::css::lang::IndexOutOfBoundsException( 1404 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 1405 "textwindowaccessibility.cxx:" 1406 " Document::changeParagraphSelection")), 1407 static_cast< ::css::uno::XWeak * >(this)); 1408 m_rView.SetSelection( 1409 ::TextSelection(::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nBegin)), 1410 ::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nEnd)))); 1411 // XXX numeric overflow (2x) 1412 } 1413 } 1414 1415 ::css::i18n::Boundary 1416 Document::retrieveParagraphLineBoundary( ParagraphImpl const * pParagraph, 1417 ::sal_Int32 nIndex, ::sal_Int32 *pLineNo ) 1418 { 1419 ::css::i18n::Boundary aBoundary; 1420 aBoundary.startPos = nIndex; 1421 aBoundary.endPos = nIndex; 1422 1423 ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() ); 1424 { 1425 ::osl::MutexGuard aInternalGuard( GetMutex() ); 1426 ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() ); 1427 if ( nIndex < 0 || nIndex > m_rEngine.GetText( nNumber ).Len() ) 1428 throw ::css::lang::IndexOutOfBoundsException( 1429 ::rtl::OUString( 1430 RTL_CONSTASCII_USTRINGPARAM( 1431 "textwindowaccessibility.cxx:" 1432 " Document::retrieveParagraphLineBoundary" ) ), 1433 static_cast< ::css::uno::XWeak * >( this ) ); 1434 ::sal_Int32 nLineStart = 0; 1435 ::sal_Int32 nLineEnd = 0; 1436 ::sal_uInt16 nLineCount = m_rEngine.GetLineCount( nNumber ); 1437 for ( ::sal_uInt16 nLine = 0; nLine < nLineCount; ++nLine ) 1438 { 1439 ::sal_Int32 nLineLength = static_cast< ::sal_Int32 >( 1440 m_rEngine.GetLineLen( nNumber, nLine ) ); 1441 nLineStart = nLineEnd; 1442 nLineEnd += nLineLength; 1443 if ( nIndex >= nLineStart && ( ( nLine == nLineCount - 1 ) ? nIndex <= nLineEnd : nIndex < nLineEnd ) ) 1444 { 1445 aBoundary.startPos = nLineStart; 1446 aBoundary.endPos = nLineEnd; 1447 if( pLineNo ) 1448 pLineNo[0] = nLine; 1449 break; 1450 } 1451 } 1452 } 1453 1454 return aBoundary; 1455 } 1456 1457 ::css::i18n::Boundary 1458 Document::retrieveParagraphBoundaryOfLine( ParagraphImpl const * pParagraph, 1459 ::sal_Int32 nLineNo ) 1460 { 1461 ::css::i18n::Boundary aBoundary; 1462 aBoundary.startPos = 0; 1463 aBoundary.endPos = 0; 1464 1465 ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() ); 1466 { 1467 ::osl::MutexGuard aInternalGuard( GetMutex() ); 1468 ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() ); 1469 if ( nLineNo >= m_rEngine.GetLineCount( nNumber ) ) 1470 throw ::css::lang::IndexOutOfBoundsException( 1471 ::rtl::OUString( 1472 RTL_CONSTASCII_USTRINGPARAM( 1473 "textwindowaccessibility.cxx:" 1474 " Document::retrieveParagraphBoundaryOfLine" ) ), 1475 static_cast< ::css::uno::XWeak * >( this ) ); 1476 ::sal_Int32 nLineStart = 0; 1477 ::sal_Int32 nLineEnd = 0; 1478 for ( ::sal_uInt16 nLine = 0; nLine <= nLineNo; ++nLine ) 1479 { 1480 ::sal_Int32 nLineLength = static_cast< ::sal_Int32 >( 1481 m_rEngine.GetLineLen( nNumber, nLine ) ); 1482 nLineStart = nLineEnd; 1483 nLineEnd += nLineLength; 1484 } 1485 1486 aBoundary.startPos = nLineStart; 1487 aBoundary.endPos = nLineEnd; 1488 } 1489 1490 return aBoundary; 1491 } 1492 1493 sal_Int32 Document::retrieveParagraphLineWithCursor( ParagraphImpl const * pParagraph ) 1494 { 1495 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); 1496 ::osl::MutexGuard aInternalGuard(GetMutex()); 1497 ::TextSelection const & rSelection = m_rView.GetSelection(); 1498 Paragraphs::size_type nNumber = pParagraph->getNumber(); 1499 TextPaM aEndPaM( rSelection.GetEnd() ); 1500 1501 return aEndPaM.GetPara() == nNumber 1502 ? m_rView.GetLineNumberOfCursorInSelection() : -1; 1503 } 1504 1505 1506 ::css::uno::Reference< ::css::accessibility::XAccessibleRelationSet > 1507 Document::retrieveParagraphRelationSet( ParagraphImpl const * pParagraph ) 1508 { 1509 ::osl::MutexGuard aInternalGuard( GetMutex() ); 1510 1511 ::utl::AccessibleRelationSetHelper* pRelationSetHelper = new ::utl::AccessibleRelationSetHelper(); 1512 ::css::uno::Reference< ::css::accessibility::XAccessibleRelationSet > xSet = pRelationSetHelper; 1513 1514 Paragraphs::iterator aPara( m_xParagraphs->begin() + pParagraph->getNumber() ); 1515 1516 if ( aPara > m_aVisibleBegin && aPara < m_aVisibleEnd ) 1517 { 1518 ::css::uno::Sequence< ::css::uno::Reference< ::css::uno::XInterface > > aSequence(1); 1519 aSequence[0] = getAccessibleChild( aPara - 1 ); 1520 ::css::accessibility::AccessibleRelation aRelation( ::css::accessibility::AccessibleRelationType::CONTENT_FLOWS_FROM, aSequence ); 1521 pRelationSetHelper->AddRelation( aRelation ); 1522 } 1523 1524 if ( aPara >= m_aVisibleBegin && aPara < m_aVisibleEnd -1 ) 1525 { 1526 ::css::uno::Sequence< ::css::uno::Reference< ::css::uno::XInterface > > aSequence(1); 1527 aSequence[0] = getAccessibleChild( aPara + 1 ); 1528 ::css::accessibility::AccessibleRelation aRelation( ::css::accessibility::AccessibleRelationType::CONTENT_FLOWS_TO, aSequence ); 1529 pRelationSetHelper->AddRelation( aRelation ); 1530 } 1531 1532 return xSet; 1533 } 1534 1535 void Document::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent ) 1536 { 1537 switch ( rVclWindowEvent.GetId() ) 1538 { 1539 case VCLEVENT_WINDOW_GETFOCUS: 1540 case VCLEVENT_WINDOW_LOSEFOCUS: 1541 { 1542 // #107179# if our parent is a compound control (e.g. MultiLineEdit), 1543 // suppress the window focus events here 1544 // IAccessible2 implementation 2009 1545 //if ( !m_bCompoundControlChild ) 1546 VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent ); 1547 } 1548 break; 1549 default: 1550 VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent ); 1551 } 1552 } 1553 1554 // virtual 1555 ::sal_Int32 SAL_CALL Document::getAccessibleChildCount() 1556 throw (::css::uno::RuntimeException) 1557 { 1558 ::comphelper::OExternalLockGuard aGuard(this); 1559 init(); 1560 return m_aVisibleEnd - m_aVisibleBegin; 1561 } 1562 1563 // virtual 1564 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL 1565 Document::getAccessibleChild(::sal_Int32 i) 1566 throw (::css::lang::IndexOutOfBoundsException, 1567 ::css::uno::RuntimeException) 1568 { 1569 ::comphelper::OExternalLockGuard aGuard(this); 1570 init(); 1571 if (i < 0 || i >= m_aVisibleEnd - m_aVisibleBegin) 1572 throw ::css::lang::IndexOutOfBoundsException( 1573 ::rtl::OUString( 1574 RTL_CONSTASCII_USTRINGPARAM( 1575 "textwindowaccessibility.cxx:" 1576 " Document::getAccessibleChild")), 1577 static_cast< ::css::uno::XWeak * >(this)); 1578 return getAccessibleChild(m_aVisibleBegin 1579 + static_cast< Paragraphs::size_type >(i)); 1580 } 1581 1582 // virtual 1583 ::sal_Int16 SAL_CALL Document::getAccessibleRole() 1584 throw (::css::uno::RuntimeException) 1585 { 1586 return ::css::accessibility::AccessibleRole::TEXT_FRAME; 1587 } 1588 1589 // virtual 1590 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL 1591 Document::getAccessibleAtPoint(::css::awt::Point const & rPoint) 1592 throw (::css::uno::RuntimeException) 1593 { 1594 ::comphelper::OExternalLockGuard aGuard(this); 1595 init(); 1596 if (rPoint.X >= 0 1597 && rPoint.X < m_rView.GetWindow()->GetOutputSizePixel().Width() 1598 && rPoint.Y >= 0 && rPoint.Y < m_nViewHeight) 1599 { 1600 ::sal_Int32 nOffset = m_nViewOffset + rPoint.Y; // XXX numeric overflow 1601 ::sal_Int32 nPos = m_nViewOffset - m_nVisibleBeginOffset; 1602 for (Paragraphs::iterator aIt(m_aVisibleBegin); aIt != m_aVisibleEnd; 1603 ++aIt) 1604 { 1605 nPos += aIt->getHeight(); // XXX numeric overflow 1606 if (nOffset < nPos) 1607 return getAccessibleChild(aIt); 1608 } 1609 } 1610 return 0; 1611 } 1612 void Document::FillAccessibleStateSet( utl::AccessibleStateSetHelper& rStateSet ) 1613 { 1614 VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet ); 1615 if (!m_rView.IsReadOnly()) 1616 rStateSet.AddState( ::css::accessibility::AccessibleStateType::EDITABLE ); 1617 } 1618 1619 void Document::FillAccessibleRelationSet( utl::AccessibleRelationSetHelper& rRelationSet ) 1620 { 1621 if( getAccessibleParent()->getAccessibleContext()->getAccessibleRole() == ::css::accessibility::AccessibleRole::SCROLL_PANE ) 1622 { 1623 ::css::uno::Sequence< ::css::uno::Reference< ::css::uno::XInterface > > aSequence(1); 1624 aSequence[0] = getAccessibleParent(); 1625 rRelationSet.AddRelation( ::css::accessibility::AccessibleRelation( ::css::accessibility::AccessibleRelationType::MEMBER_OF, aSequence ) ); 1626 } 1627 else 1628 { 1629 VCLXAccessibleComponent::FillAccessibleRelationSet(rRelationSet); 1630 } 1631 } 1632 // virtual 1633 void SAL_CALL Document::disposing() 1634 { 1635 m_aEngineListener.endListening(); 1636 m_aViewListener.endListening(); 1637 if (m_xParagraphs.get() != 0) 1638 disposeParagraphs(); 1639 VCLXAccessibleComponent::disposing(); 1640 } 1641 1642 // virtual 1643 void Document::Notify(::SfxBroadcaster &, ::SfxHint const & rHint) 1644 { 1645 if (rHint.ISA(::TextHint)) 1646 { 1647 ::TextHint const & rTextHint 1648 = static_cast< ::TextHint const & >(rHint); 1649 switch (rTextHint.GetId()) 1650 { 1651 case TEXT_HINT_PARAINSERTED: 1652 case TEXT_HINT_PARAREMOVED: 1653 // TEXT_HINT_PARAINSERTED and TEXT_HINT_PARAREMOVED are sent at 1654 // "unsafe" times (when the text engine has not yet re-formatted its 1655 // content), so that for example calling ::TextEngine::GetTextHeight 1656 // from within the code that handles TEXT_HINT_PARAINSERTED causes 1657 // trouble within the text engine. Therefore, these hints are just 1658 // buffered until a following ::TextEngine::FormatDoc causes a 1659 // TEXT_HINT_TEXTFORMATTED to come in: 1660 case TEXT_HINT_FORMATPARA: 1661 // ::TextEngine::FormatDoc sends a sequence of 1662 // TEXT_HINT_FORMATPARAs, followed by an optional 1663 // TEXT_HINT_TEXTHEIGHTCHANGED, followed in all cases by one 1664 // TEXT_HINT_TEXTFORMATTED. Only the TEXT_HINT_FORMATPARAs contain 1665 // the the numbers of the affected paragraphs, but they are sent 1666 // before the changes are applied. Therefore, TEXT_HINT_FORMATPARAs 1667 // are just buffered until another hint comes in: 1668 { 1669 ::osl::MutexGuard aInternalGuard(GetMutex()); 1670 if (!isAlive()) 1671 break; 1672 1673 m_aParagraphNotifications.push(rTextHint); 1674 break; 1675 } 1676 case TEXT_HINT_TEXTFORMATTED: 1677 case TEXT_HINT_TEXTHEIGHTCHANGED: 1678 case TEXT_HINT_MODIFIED: 1679 { 1680 ::osl::MutexGuard aInternalGuard(GetMutex()); 1681 if (!isAlive()) 1682 break; 1683 handleParagraphNotifications(); 1684 break; 1685 } 1686 case TEXT_HINT_VIEWSCROLLED: 1687 { 1688 ::osl::MutexGuard aInternalGuard(GetMutex()); 1689 if (!isAlive()) 1690 break; 1691 handleParagraphNotifications(); 1692 1693 ::sal_Int32 nOffset = static_cast< ::sal_Int32 >( 1694 m_rView.GetStartDocPos().Y()); 1695 // XXX numeric overflow 1696 if (nOffset != m_nViewOffset) 1697 { 1698 m_nViewOffset = nOffset; 1699 1700 Paragraphs::iterator aOldVisibleBegin( 1701 m_aVisibleBegin); 1702 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd); 1703 1704 determineVisibleRange(); 1705 1706 notifyVisibleRangeChanges(aOldVisibleBegin, 1707 aOldVisibleEnd, 1708 m_xParagraphs->end()); 1709 } 1710 break; 1711 } 1712 case TEXT_HINT_VIEWSELECTIONCHANGED: 1713 { 1714 ::osl::MutexGuard aInternalGuard(GetMutex()); 1715 if (!isAlive()) 1716 break; 1717 1718 if (m_aParagraphNotifications.empty()) 1719 { 1720 handleSelectionChangeNotification(); 1721 } 1722 else 1723 { 1724 // TEXT_HINT_VIEWSELECTIONCHANGED is sometimes sent at 1725 // "unsafe" times (when the text engine has not yet re- 1726 // formatted its content), so that for example calling 1727 // ::TextEngine::GetTextHeight from within the code that 1728 // handles a previous TEXT_HINT_PARAINSERTED causes 1729 // trouble within the text engine. Therefore, these 1730 // hints are just buffered (along with 1731 // TEXT_HINT_PARAINSERTED/REMOVED/FORMATPARA) until a 1732 // following ::TextEngine::FormatDoc causes a 1733 // TEXT_HINT_TEXTFORMATTED to come in: 1734 m_bSelectionChangedNotification = true; 1735 } 1736 break; 1737 } 1738 } 1739 } 1740 } 1741 1742 IMPL_LINK(Document, WindowEventHandler, ::VclSimpleEvent *, pEvent) 1743 { 1744 switch (pEvent->GetId()) 1745 { 1746 case VCLEVENT_WINDOW_RESIZE: 1747 { 1748 ::osl::MutexGuard aInternalGuard(GetMutex()); 1749 if (!isAlive()) 1750 break; 1751 1752 ::sal_Int32 nHeight = static_cast< ::sal_Int32 >( 1753 m_rView.GetWindow()->GetOutputSizePixel().Height()); 1754 // XXX numeric overflow 1755 if (nHeight != m_nViewHeight) 1756 { 1757 m_nViewHeight = nHeight; 1758 1759 Paragraphs::iterator aOldVisibleBegin(m_aVisibleBegin); 1760 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd); 1761 1762 determineVisibleRange(); 1763 1764 notifyVisibleRangeChanges(aOldVisibleBegin, aOldVisibleEnd, 1765 m_xParagraphs->end()); 1766 } 1767 break; 1768 } 1769 case VCLEVENT_WINDOW_GETFOCUS: 1770 { 1771 ::osl::MutexGuard aInternalGuard(GetMutex()); 1772 if (!isAlive()) 1773 break; 1774 //to enable the PARAGRAPH to get focus for multiline edit 1775 ::sal_Int32 count = getAccessibleChildCount(); 1776 ::sal_Bool bEmpty = m_aFocused == m_aVisibleEnd && count == 1; 1777 if ((m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd) || bEmpty) 1778 { 1779 Paragraphs::iterator m_aTemp = bEmpty ? m_aVisibleBegin : m_aFocused; 1780 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(m_aTemp)); 1781 if (xParagraph.is()) 1782 { 1783 xParagraph->notifyEvent( 1784 ::css::accessibility::AccessibleEventId:: 1785 STATE_CHANGED, 1786 ::css::uno::Any(), 1787 ::css::uno::makeAny( 1788 ::css::accessibility::AccessibleStateType:: 1789 FOCUSED)); 1790 } 1791 } 1792 /* 1793 ::rtl::Reference< ParagraphImpl > xParagraph( 1794 getParagraph(m_aFocused)); 1795 if (xParagraph.is()) 1796 xParagraph->notifyEvent( 1797 ::css::accessibility::AccessibleEventId:: 1798 STATE_CHANGED, 1799 ::css::uno::Any(), 1800 ::css::uno::makeAny( 1801 ::css::accessibility::AccessibleStateType:: 1802 FOCUSED)); 1803 */ 1804 break; 1805 } 1806 case VCLEVENT_WINDOW_LOSEFOCUS: 1807 { 1808 ::osl::MutexGuard aInternalGuard(GetMutex()); 1809 if (!isAlive()) 1810 break; 1811 //to enable the PARAGRAPH to get focus for multiline edit 1812 ::sal_Int32 count = getAccessibleChildCount(); 1813 ::sal_Bool bEmpty = m_aFocused == m_aVisibleEnd && count == 1; 1814 if ((m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd) || bEmpty) 1815 { 1816 Paragraphs::iterator m_aTemp = bEmpty ? m_aVisibleBegin : m_aFocused; 1817 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(m_aTemp)); 1818 if (xParagraph.is()) 1819 xParagraph->notifyEvent( 1820 ::css::accessibility::AccessibleEventId:: 1821 STATE_CHANGED, 1822 ::css::uno::makeAny( 1823 ::css::accessibility::AccessibleStateType:: 1824 FOCUSED), 1825 ::css::uno::Any()); 1826 } 1827 1828 /* 1829 if (m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd) 1830 { 1831 ::rtl::Reference< ParagraphImpl > xParagraph( 1832 getParagraph(m_aFocused)); 1833 if (xParagraph.is()) 1834 xParagraph->notifyEvent( 1835 ::css::accessibility::AccessibleEventId:: 1836 STATE_CHANGED, 1837 ::css::uno::makeAny( 1838 ::css::accessibility::AccessibleStateType:: 1839 FOCUSED), 1840 ::css::uno::Any()); 1841 } 1842 */ 1843 break; 1844 } 1845 } 1846 return 0; 1847 } 1848 1849 void Document::init() 1850 { 1851 if (m_xParagraphs.get() == 0) 1852 { 1853 ::sal_uLong nCount = m_rEngine.GetParagraphCount(); 1854 ::std::auto_ptr< Paragraphs > p(new Paragraphs); 1855 p->reserve(static_cast< Paragraphs::size_type >(nCount)); 1856 // numeric overflow is harmless here 1857 for (::sal_uLong i = 0; i < nCount; ++i) 1858 p->push_back(ParagraphInfo(static_cast< ::sal_Int32 >( 1859 m_rEngine.GetTextHeight(i)))); 1860 // XXX numeric overflow 1861 m_nViewOffset = static_cast< ::sal_Int32 >( 1862 m_rView.GetStartDocPos().Y()); // XXX numeric overflow 1863 m_nViewHeight = static_cast< ::sal_Int32 >( 1864 m_rView.GetWindow()->GetOutputSizePixel().Height()); 1865 // XXX numeric overflow 1866 m_xParagraphs = p; 1867 determineVisibleRange(); 1868 m_nSelectionFirstPara = -1; 1869 m_nSelectionFirstPos = -1; 1870 m_nSelectionLastPara = -1; 1871 m_nSelectionLastPos = -1; 1872 m_aFocused = m_xParagraphs->end(); 1873 m_bSelectionChangedNotification = false; 1874 m_aEngineListener.startListening(m_rEngine); 1875 m_aViewListener.startListening(*m_rView.GetWindow()); 1876 } 1877 } 1878 1879 ::rtl::Reference< ParagraphImpl > 1880 Document::getParagraph(Paragraphs::iterator const & rIt) 1881 { 1882 return static_cast< ParagraphImpl * >( 1883 ::css::uno::Reference< ::css::accessibility::XAccessible >( 1884 rIt->getParagraph()).get()); 1885 } 1886 1887 ::css::uno::Reference< ::css::accessibility::XAccessible > 1888 Document::getAccessibleChild(Paragraphs::iterator const & rIt) 1889 { 1890 ::css::uno::Reference< ::css::accessibility::XAccessible > xParagraph( 1891 rIt->getParagraph()); 1892 if (!xParagraph.is()) 1893 { 1894 xParagraph = new Paragraph(this, rIt - m_xParagraphs->begin()); 1895 rIt->setParagraph(xParagraph); 1896 } 1897 return xParagraph; 1898 } 1899 1900 void Document::determineVisibleRange() 1901 { 1902 m_aVisibleBegin = m_xParagraphs->end(); 1903 m_aVisibleEnd = m_aVisibleBegin; 1904 ::sal_Int32 nPos = 0; 1905 for (Paragraphs::iterator aIt = m_xParagraphs->begin();;) 1906 { 1907 if (aIt == m_xParagraphs->end()) 1908 { 1909 m_nVisibleBeginOffset = 0; 1910 break; 1911 } 1912 ::sal_Int32 nOldPos = nPos; 1913 nPos += aIt->getHeight(); // XXX numeric overflow 1914 if (m_aVisibleBegin == m_xParagraphs->end() && nPos >= m_nViewOffset) 1915 { 1916 m_aVisibleBegin = aIt; 1917 m_nVisibleBeginOffset = m_nViewOffset - nOldPos; 1918 } 1919 ++aIt; 1920 if (m_aVisibleBegin != m_xParagraphs->end() 1921 && (aIt == m_xParagraphs->end() 1922 || nPos >= m_nViewOffset + m_nViewHeight)) 1923 // XXX numeric overflow 1924 { 1925 m_aVisibleEnd = aIt; 1926 break; 1927 } 1928 } 1929 } 1930 1931 void Document::notifyVisibleRangeChanges( 1932 Paragraphs::iterator const & rOldVisibleBegin, 1933 Paragraphs::iterator const & rOldVisibleEnd, 1934 Paragraphs::iterator const & rInserted) 1935 { 1936 // XXX Replace this code that determines which paragraphs have changed from 1937 // invisible to visible or vice versa with a better algorithm. 1938 {for (Paragraphs::iterator aIt(rOldVisibleBegin); aIt != rOldVisibleEnd; 1939 ++aIt) 1940 if (aIt != rInserted 1941 && (aIt < m_aVisibleBegin || aIt >= m_aVisibleEnd)) 1942 NotifyAccessibleEvent( 1943 ::css::accessibility::AccessibleEventId:: 1944 CHILD, 1945 ::css::uno::makeAny(getAccessibleChild(aIt)), 1946 ::css::uno::Any()); 1947 } 1948 {for (Paragraphs::iterator aIt(m_aVisibleBegin); aIt != m_aVisibleEnd; 1949 ++aIt) 1950 if (aIt == rInserted 1951 || aIt < rOldVisibleBegin || aIt >= rOldVisibleEnd) 1952 NotifyAccessibleEvent( 1953 ::css::accessibility::AccessibleEventId:: 1954 CHILD, 1955 ::css::uno::Any(), 1956 ::css::uno::makeAny(getAccessibleChild(aIt))); 1957 } 1958 } 1959 1960 void 1961 Document::changeParagraphText(::sal_uLong nNumber, ::sal_uInt16 nBegin, ::sal_uInt16 nEnd, 1962 bool bCut, bool bPaste, 1963 ::rtl::OUString const & rText) 1964 { 1965 m_rView.SetSelection(::TextSelection(::TextPaM(nNumber, nBegin), 1966 ::TextPaM(nNumber, nEnd))); 1967 if (bCut) 1968 m_rView.Cut(); 1969 else if (nBegin != nEnd) 1970 m_rView.DeleteSelected(); 1971 if (bPaste) 1972 m_rView.Paste(); 1973 else if (rText.getLength() != 0) 1974 m_rView.InsertText(rText); 1975 } 1976 1977 void Document::handleParagraphNotifications() 1978 { 1979 while (!m_aParagraphNotifications.empty()) 1980 { 1981 ::TextHint aHint(m_aParagraphNotifications.front()); 1982 m_aParagraphNotifications.pop(); 1983 switch (aHint.GetId()) 1984 { 1985 case TEXT_HINT_PARAINSERTED: 1986 { 1987 ::sal_uLong n = aHint.GetValue(); 1988 OSL_ENSURE(n <= m_xParagraphs->size(), 1989 "bad TEXT_HINT_PARAINSERTED event"); 1990 1991 // Save the values of old iterators (the iterators themselves 1992 // will get invalidated), and adjust the old values so that they 1993 // reflect the insertion of the new paragraph: 1994 Paragraphs::size_type nOldVisibleBegin 1995 = m_aVisibleBegin - m_xParagraphs->begin(); 1996 Paragraphs::size_type nOldVisibleEnd 1997 = m_aVisibleEnd - m_xParagraphs->begin(); 1998 Paragraphs::size_type nOldFocused 1999 = m_aFocused - m_xParagraphs->begin(); 2000 if (n <= nOldVisibleBegin) 2001 ++nOldVisibleBegin; // XXX numeric overflow 2002 if (n <= nOldVisibleEnd) 2003 ++nOldVisibleEnd; // XXX numeric overflow 2004 if (n <= nOldFocused) 2005 ++nOldFocused; // XXX numeric overflow 2006 if (sal::static_int_cast<sal_Int32>(n) <= m_nSelectionFirstPara) 2007 ++m_nSelectionFirstPara; // XXX numeric overflow 2008 if (sal::static_int_cast<sal_Int32>(n) <= m_nSelectionLastPara) 2009 ++m_nSelectionLastPara; // XXX numeric overflow 2010 2011 Paragraphs::iterator aIns( 2012 m_xParagraphs->insert( 2013 m_xParagraphs->begin() + n, 2014 ParagraphInfo(static_cast< ::sal_Int32 >( 2015 m_rEngine.GetTextHeight(n))))); 2016 // XXX numeric overflow (2x) 2017 2018 determineVisibleRange(); 2019 m_aFocused = m_xParagraphs->begin() + nOldFocused; 2020 2021 for (Paragraphs::iterator aIt(aIns);;) 2022 { 2023 ++aIt; 2024 if (aIt == m_xParagraphs->end()) 2025 break; 2026 ::rtl::Reference< ParagraphImpl > xParagraph( 2027 getParagraph(aIt)); 2028 if (xParagraph.is()) 2029 xParagraph->numberChanged(true); 2030 } 2031 2032 notifyVisibleRangeChanges( 2033 m_xParagraphs->begin() + nOldVisibleBegin, 2034 m_xParagraphs->begin() + nOldVisibleEnd, aIns); 2035 break; 2036 } 2037 case TEXT_HINT_PARAREMOVED: 2038 { 2039 ::sal_uLong n = aHint.GetValue(); 2040 if (n == TEXT_PARA_ALL) 2041 { 2042 {for (Paragraphs::iterator aIt(m_aVisibleBegin); 2043 aIt != m_aVisibleEnd; ++aIt) 2044 NotifyAccessibleEvent( 2045 ::css::accessibility::AccessibleEventId:: 2046 CHILD, 2047 ::css::uno::makeAny(getAccessibleChild(aIt)), 2048 ::css::uno::Any()); 2049 } 2050 disposeParagraphs(); 2051 m_xParagraphs->clear(); 2052 determineVisibleRange(); 2053 m_nSelectionFirstPara = -1; 2054 m_nSelectionFirstPos = -1; 2055 m_nSelectionLastPara = -1; 2056 m_nSelectionLastPos = -1; 2057 m_aFocused = m_xParagraphs->end(); 2058 } 2059 else 2060 { 2061 OSL_ENSURE(n < m_xParagraphs->size(), 2062 "Bad TEXT_HINT_PARAREMOVED event"); 2063 2064 Paragraphs::iterator aIt(m_xParagraphs->begin() + n); 2065 // numeric overflow cannot occur 2066 2067 // Save the values of old iterators (the iterators 2068 // themselves will get invalidated), and adjust the old 2069 // values so that they reflect the removal of the paragraph: 2070 Paragraphs::size_type nOldVisibleBegin 2071 = m_aVisibleBegin - m_xParagraphs->begin(); 2072 Paragraphs::size_type nOldVisibleEnd 2073 = m_aVisibleEnd - m_xParagraphs->begin(); 2074 bool bWasVisible 2075 = nOldVisibleBegin <= n && n < nOldVisibleEnd; 2076 Paragraphs::size_type nOldFocused 2077 = m_aFocused - m_xParagraphs->begin(); 2078 bool bWasFocused = aIt == m_aFocused; 2079 if (n < nOldVisibleBegin) 2080 --nOldVisibleBegin; 2081 if (n < nOldVisibleEnd) 2082 --nOldVisibleEnd; 2083 if (n < nOldFocused) 2084 --nOldFocused; 2085 if (sal::static_int_cast<sal_Int32>(n) < m_nSelectionFirstPara) 2086 --m_nSelectionFirstPara; 2087 else if (sal::static_int_cast<sal_Int32>(n) == m_nSelectionFirstPara) 2088 { 2089 if (m_nSelectionFirstPara == m_nSelectionLastPara) 2090 { 2091 m_nSelectionFirstPara = -1; 2092 m_nSelectionFirstPos = -1; 2093 m_nSelectionLastPara = -1; 2094 m_nSelectionLastPos = -1; 2095 } 2096 else 2097 { 2098 ++m_nSelectionFirstPara; 2099 m_nSelectionFirstPos = 0; 2100 } 2101 } 2102 if (sal::static_int_cast<sal_Int32>(n) < m_nSelectionLastPara) 2103 --m_nSelectionLastPara; 2104 else if (sal::static_int_cast<sal_Int32>(n) == m_nSelectionLastPara) 2105 { 2106 OSL_ENSURE(m_nSelectionFirstPara < m_nSelectionLastPara, 2107 "logic error"); 2108 --m_nSelectionLastPara; 2109 m_nSelectionLastPos = 0x7FFFFFFF; 2110 } 2111 2112 ::css::uno::Reference< ::css::accessibility::XAccessible > 2113 xStrong; 2114 if (bWasVisible) 2115 xStrong = getAccessibleChild(aIt); 2116 ::css::uno::WeakReference< 2117 ::css::accessibility::XAccessible > xWeak( 2118 aIt->getParagraph()); 2119 aIt = m_xParagraphs->erase(aIt); 2120 2121 determineVisibleRange(); 2122 m_aFocused = bWasFocused ? m_xParagraphs->end() 2123 : m_xParagraphs->begin() + nOldFocused; 2124 2125 for (; aIt != m_xParagraphs->end(); ++aIt) 2126 { 2127 ::rtl::Reference< ParagraphImpl > xParagraph( 2128 getParagraph(aIt)); 2129 if (xParagraph.is()) 2130 xParagraph->numberChanged(false); 2131 } 2132 2133 if (bWasVisible) 2134 NotifyAccessibleEvent( 2135 ::css::accessibility::AccessibleEventId:: 2136 CHILD, 2137 ::css::uno::makeAny(getAccessibleChild(aIt)), 2138 ::css::uno::Any()); 2139 2140 ::css::uno::Reference< ::css::lang::XComponent > xComponent( 2141 xWeak.get(), ::css::uno::UNO_QUERY); 2142 if (xComponent.is()) 2143 xComponent->dispose(); 2144 2145 notifyVisibleRangeChanges( 2146 m_xParagraphs->begin() + nOldVisibleBegin, 2147 m_xParagraphs->begin() + nOldVisibleEnd, 2148 m_xParagraphs->end()); 2149 } 2150 break; 2151 } 2152 case TEXT_HINT_FORMATPARA: 2153 { 2154 ::sal_uLong n = aHint.GetValue(); 2155 OSL_ENSURE(n < m_xParagraphs->size(), 2156 "Bad TEXT_HINT_FORMATPARA event"); 2157 2158 (*m_xParagraphs)[static_cast< Paragraphs::size_type >(n)]. 2159 changeHeight(static_cast< ::sal_Int32 >( 2160 m_rEngine.GetTextHeight(n))); 2161 // XXX numeric overflow 2162 Paragraphs::iterator aOldVisibleBegin(m_aVisibleBegin); 2163 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd); 2164 determineVisibleRange(); 2165 notifyVisibleRangeChanges(aOldVisibleBegin, aOldVisibleEnd, 2166 m_xParagraphs->end()); 2167 2168 if (n < m_xParagraphs->size()) 2169 { 2170 Paragraphs::iterator aIt(m_xParagraphs->begin() + n); 2171 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt)); 2172 if (xParagraph.is()) 2173 xParagraph->textChanged(); 2174 } 2175 break; 2176 } 2177 default: 2178 OSL_ENSURE(false, "bad buffered hint"); 2179 break; 2180 } 2181 } 2182 if (m_bSelectionChangedNotification) 2183 { 2184 m_bSelectionChangedNotification = false; 2185 handleSelectionChangeNotification(); 2186 } 2187 } 2188 2189 ::sal_Int32 Document::getSelectionType(::sal_Int32 nNewFirstPara, ::sal_Int32 nNewFirstPos, ::sal_Int32 nNewLastPara, ::sal_Int32 nNewLastPos) 2190 { 2191 if (m_nSelectionFirstPara == -1) 2192 return -1; 2193 ::sal_Int32 Osp = m_nSelectionFirstPara, Osl = m_nSelectionFirstPos, Oep = m_nSelectionLastPara, Oel = m_nSelectionLastPos; 2194 ::sal_Int32 Nsp = nNewFirstPara, Nsl = nNewFirstPos, Nep = nNewLastPara, Nel = nNewLastPos; 2195 TextPaM Ns(Nsp, sal_uInt16(Nsl)); 2196 TextPaM Ne(Nep, sal_uInt16(Nel)); 2197 TextPaM Os(Osp, sal_uInt16(Osl)); 2198 TextPaM Oe(Oep, sal_uInt16(Oel)); 2199 2200 if (Os == Oe && Ns == Ne) 2201 { 2202 //only caret moves. 2203 return 1; 2204 } 2205 else if (Os == Oe && Ns != Ne) 2206 { 2207 //old has no selection but new has selection 2208 return 2; 2209 } 2210 else if (Os != Oe && Ns == Ne) 2211 { 2212 //old has selection but new has no selection. 2213 return 3; 2214 } 2215 else if (Os != Oe && Ns != Ne && Osp == Nsp && Osl == Nsl) 2216 { 2217 //both old and new have selections. 2218 if (Oep == Nep ) 2219 { 2220 //Send text_selection_change event on Nep 2221 2222 return 4; 2223 } 2224 else if (Oep < Nep) 2225 { 2226 //all the following examples like 1,2->1,3 means that old start select para is 1, old end select para is 2, 2227 // then press shift up, the new start select para is 1, new end select para is 3; 2228 //for example, 1, 2 -> 1, 3; 4,1 -> 4, 7; 4,1 -> 4, 2; 4,4->4,5 2229 if (Nep >= Nsp) 2230 { 2231 // 1, 2 -> 1, 3; 4, 1 -> 4, 7; 4,4->4,5; 2232 if (Oep < Osp) 2233 { 2234 // 4,1 -> 4,7; 2235 return 5; 2236 } 2237 else if (Oep >= Osp) 2238 { 2239 // 1, 2 -> 1, 3; 4,4->4,5; 2240 return 6; 2241 } 2242 } 2243 else 2244 { 2245 // 4,1 -> 4,2, 2246 if (Oep < Osp) 2247 { 2248 // 4,1 -> 4,2, 2249 return 7; 2250 } 2251 else if (Oep >= Osp) 2252 { 2253 // no such condition. Oep > Osp = Nsp > Nep 2254 } 2255 } 2256 } 2257 else if (Oep > Nep) 2258 { 2259 // 3,2 -> 3,1; 4,7 -> 4,1; 4, 7 -> 4,6; 4,4 -> 4,3 2260 if (Nep >= Nsp) 2261 { 2262 // 4,7 -> 4,6 2263 if (Oep <= Osp) 2264 { 2265 //no such condition, Oep<Osp=Nsp <= Nep 2266 } 2267 else if (Oep > Osp) 2268 { 2269 // 4,7 ->4,6 2270 return 8; 2271 } 2272 } 2273 else 2274 { 2275 // 3,2 -> 3,1, 4,7 -> 4,1; 4,4->4,3 2276 if (Oep <= Osp) 2277 { 2278 // 3,2 -> 3,1; 4,4->4,3 2279 return 9; 2280 } 2281 else if (Oep > Osp) 2282 { 2283 // 4,7 -> 4,1 2284 return 10; 2285 } 2286 } 2287 } 2288 } 2289 return -1; 2290 } 2291 2292 2293 void Document::sendEvent(::sal_Int32 start, ::sal_Int32 end, ::sal_Int16 nEventId) 2294 { 2295 Paragraphs::iterator aEnd = ::std::min(m_xParagraphs->begin() + end + 1, m_aVisibleEnd); 2296 for (Paragraphs::iterator aIt = ::std::max(m_xParagraphs->begin() + start, m_aVisibleBegin); 2297 aIt < aEnd; ++aIt) 2298 { 2299 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt)); 2300 if (xParagraph.is()) 2301 xParagraph->notifyEvent( 2302 nEventId, 2303 ::css::uno::Any(), ::css::uno::Any()); 2304 } 2305 } 2306 2307 void Document::handleSelectionChangeNotification() 2308 { 2309 ::TextSelection const & rSelection = m_rView.GetSelection(); 2310 OSL_ENSURE(rSelection.GetStart().GetPara() < m_xParagraphs->size() 2311 && rSelection.GetEnd().GetPara() < m_xParagraphs->size(), 2312 "bad TEXT_HINT_VIEWSELECTIONCHANGED event"); 2313 ::sal_Int32 nNewFirstPara 2314 = static_cast< ::sal_Int32 >(rSelection.GetStart().GetPara()); 2315 ::sal_Int32 nNewFirstPos 2316 = static_cast< ::sal_Int32 >(rSelection.GetStart().GetIndex()); 2317 // XXX numeric overflow 2318 ::sal_Int32 nNewLastPara 2319 = static_cast< ::sal_Int32 >(rSelection.GetEnd().GetPara()); 2320 ::sal_Int32 nNewLastPos 2321 = static_cast< ::sal_Int32 >(rSelection.GetEnd().GetIndex()); 2322 // XXX numeric overflow 2323 2324 // Lose focus: 2325 Paragraphs::iterator aIt(m_xParagraphs->begin() + nNewLastPara); 2326 if (m_aFocused != m_xParagraphs->end() && m_aFocused != aIt 2327 && m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd) 2328 { 2329 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(m_aFocused)); 2330 if (xParagraph.is()) 2331 xParagraph->notifyEvent( 2332 ::css::accessibility::AccessibleEventId:: 2333 STATE_CHANGED, 2334 ::css::uno::makeAny( 2335 ::css::accessibility::AccessibleStateType::FOCUSED), 2336 ::css::uno::Any()); 2337 } 2338 2339 // Gain focus and update cursor position: 2340 if (aIt >= m_aVisibleBegin && aIt < m_aVisibleEnd 2341 && (aIt != m_aFocused 2342 || nNewLastPara != m_nSelectionLastPara 2343 || nNewLastPos != m_nSelectionLastPos)) 2344 { 2345 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt)); 2346 if (xParagraph.is()) 2347 { 2348 //disable the first event when user types in empty field. 2349 ::sal_Int32 count = getAccessibleChildCount(); 2350 ::sal_Bool bEmpty = count > 1; 2351 //if (aIt != m_aFocused) 2352 if (aIt != m_aFocused && bEmpty) 2353 xParagraph->notifyEvent( 2354 ::css::accessibility::AccessibleEventId:: 2355 STATE_CHANGED, 2356 ::css::uno::Any(), 2357 ::css::uno::makeAny( 2358 ::css::accessibility::AccessibleStateType::FOCUSED)); 2359 if (nNewLastPara != m_nSelectionLastPara 2360 || nNewLastPos != m_nSelectionLastPos) 2361 xParagraph->notifyEvent( 2362 ::css::accessibility::AccessibleEventId:: 2363 CARET_CHANGED, 2364 ::css::uno::makeAny< ::sal_Int32 >( 2365 nNewLastPara == m_nSelectionLastPara 2366 ? m_nSelectionLastPos : 0), 2367 ::css::uno::makeAny(nNewLastPos)); 2368 } 2369 } 2370 m_aFocused = aIt; 2371 2372 ::sal_Int32 nMin; 2373 ::sal_Int32 nMax; 2374 ::sal_Int32 ret = getSelectionType(nNewFirstPara, nNewFirstPos, nNewLastPara, nNewLastPos); 2375 switch (ret) 2376 { 2377 case -1: 2378 { 2379 //no event 2380 } 2381 break; 2382 case 1: 2383 { 2384 //only caret moved, already handled in above 2385 } 2386 break; 2387 case 2: 2388 { 2389 //old has no selection but new has selection 2390 nMin = ::std::min(nNewFirstPara, nNewLastPara); 2391 nMax = ::std::max(nNewFirstPara, nNewLastPara); 2392 sendEvent(nMin, nMax, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2393 sendEvent(nMin, nMax, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2394 } 2395 break; 2396 case 3: 2397 { 2398 //old has selection but new has no selection. 2399 nMin = ::std::min(m_nSelectionFirstPara, m_nSelectionLastPara); 2400 nMax = ::std::max(m_nSelectionFirstPara, m_nSelectionLastPara); 2401 sendEvent(nMin, nMax, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2402 sendEvent(nMin, nMax, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2403 } 2404 break; 2405 case 4: 2406 { 2407 //Send text_selection_change event on Nep 2408 sendEvent(nNewLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2409 } 2410 break; 2411 case 5: 2412 { 2413 // 4, 1 -> 4, 7 2414 sendEvent(m_nSelectionLastPara, m_nSelectionFirstPara-1, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2415 sendEvent(nNewFirstPara+1, nNewLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2416 2417 sendEvent(m_nSelectionLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2418 } 2419 break; 2420 case 6: 2421 { 2422 // 1, 2 -> 1, 4; 4,4->4,5; 2423 sendEvent(m_nSelectionLastPara+1, nNewLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2424 2425 sendEvent(m_nSelectionLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2426 } 2427 break; 2428 case 7: 2429 { 2430 // 4,1 -> 4,3, 2431 sendEvent(m_nSelectionLastPara +1, nNewLastPara , ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2432 2433 sendEvent(m_nSelectionLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2434 } 2435 break; 2436 case 8: 2437 { 2438 // 4,7 ->4,5; 2439 sendEvent(nNewLastPara + 1, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2440 2441 sendEvent(nNewLastPara, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2442 } 2443 break; 2444 case 9: 2445 { 2446 // 3,2 -> 3,1; 4,4->4,3 2447 sendEvent(nNewLastPara, m_nSelectionLastPara - 1, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2448 2449 sendEvent(nNewLastPara, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2450 } 2451 break; 2452 case 10: 2453 { 2454 // 4,7 -> 4,1 2455 sendEvent(m_nSelectionFirstPara + 1, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2456 sendEvent(nNewLastPara, nNewFirstPara - 1, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); 2457 2458 sendEvent(nNewLastPara, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); 2459 } 2460 break; 2461 default: 2462 break; 2463 } 2464 2465 /* 2466 // Update both old and new selection. (Regardless of how the two selections 2467 // look like, there will always be two ranges to the left and right of the 2468 // overlap---the overlap and/or the range to the right of it possibly being 2469 // empty. Only for these two ranges notifications have to be sent.) 2470 2471 TextPaM aOldTextStart( static_cast< sal_uLong >( m_nSelectionFirstPara ), static_cast< sal_uInt16 >( m_nSelectionFirstPos ) ); 2472 TextPaM aOldTextEnd( static_cast< sal_uLong >( m_nSelectionLastPara ), static_cast< sal_uInt16 >( m_nSelectionLastPos ) ); 2473 TextPaM aNewTextStart( static_cast< sal_uLong >( nNewFirstPara ), static_cast< sal_uInt16 >( nNewFirstPos ) ); 2474 TextPaM aNewTextEnd( static_cast< sal_uLong >( nNewLastPara ), static_cast< sal_uInt16 >( nNewLastPos ) ); 2475 2476 // justify selections 2477 justifySelection( aOldTextStart, aOldTextEnd ); 2478 justifySelection( aNewTextStart, aNewTextEnd ); 2479 2480 sal_Int32 nFirst1; 2481 sal_Int32 nLast1; 2482 sal_Int32 nFirst2; 2483 sal_Int32 nLast2; 2484 2485 if ( m_nSelectionFirstPara == -1 ) 2486 { 2487 // old selection not initialized yet => notify events only for new selection (if not empty) 2488 nFirst1 = aNewTextStart.GetPara(); 2489 nLast1 = aNewTextEnd.GetPara() + ( aNewTextStart != aNewTextEnd ? 1 : 0 ); 2490 nFirst2 = 0; 2491 nLast2 = 0; 2492 } 2493 else if ( aOldTextStart == aOldTextEnd && aNewTextStart == aNewTextEnd ) 2494 { 2495 // old an new selection empty => no events 2496 nFirst1 = 0; 2497 nLast1 = 0; 2498 nFirst2 = 0; 2499 nLast2 = 0; 2500 } 2501 else if ( aOldTextStart != aOldTextEnd && aNewTextStart == aNewTextEnd ) 2502 { 2503 // old selection not empty + new selection empty => notify events only for old selection 2504 nFirst1 = aOldTextStart.GetPara(); 2505 nLast1 = aOldTextEnd.GetPara() + 1; 2506 nFirst2 = 0; 2507 nLast2 = 0; 2508 } 2509 else if ( aOldTextStart == aOldTextEnd && aNewTextStart != aNewTextEnd ) 2510 { 2511 // old selection empty + new selection not empty => notify events only for new selection 2512 nFirst1 = aNewTextStart.GetPara(); 2513 nLast1 = aNewTextEnd.GetPara() + 1; 2514 nFirst2 = 0; 2515 nLast2 = 0; 2516 } 2517 else 2518 { 2519 // old and new selection not empty => notify events for the two ranges left and right of the overlap 2520 ::std::vector< TextPaM > aTextPaMs(4); 2521 aTextPaMs[0] = aOldTextStart; 2522 aTextPaMs[1] = aOldTextEnd; 2523 aTextPaMs[2] = aNewTextStart; 2524 aTextPaMs[3] = aNewTextEnd; 2525 ::std::sort( aTextPaMs.begin(), aTextPaMs.end() ); 2526 2527 nFirst1 = aTextPaMs[0].GetPara(); 2528 nLast1 = aTextPaMs[1].GetPara() + ( aTextPaMs[0] != aTextPaMs[1] ? 1 : 0 ); 2529 2530 nFirst2 = aTextPaMs[2].GetPara(); 2531 nLast2 = aTextPaMs[3].GetPara() + ( aTextPaMs[2] != aTextPaMs[3] ? 1 : 0 ); 2532 2533 // adjust overlapping ranges 2534 if ( nLast1 > nFirst2 ) 2535 nLast1 = nFirst2; 2536 } 2537 2538 // notify selection changes 2539 notifySelectionChange( nFirst1, nLast1 ); 2540 notifySelectionChange( nFirst2, nLast2 ); 2541 */ 2542 m_nSelectionFirstPara = nNewFirstPara; 2543 m_nSelectionFirstPos = nNewFirstPos; 2544 m_nSelectionLastPara = nNewLastPara; 2545 m_nSelectionLastPos = nNewLastPos; 2546 } 2547 2548 void Document::notifySelectionChange( sal_Int32 nFirst, sal_Int32 nLast ) 2549 { 2550 if ( nFirst < nLast ) 2551 { 2552 Paragraphs::iterator aEnd( ::std::min( m_xParagraphs->begin() + nLast, m_aVisibleEnd ) ); 2553 for ( Paragraphs::iterator aIt = ::std::max( m_xParagraphs->begin() + nFirst, m_aVisibleBegin ); aIt < aEnd; ++aIt ) 2554 { 2555 ::rtl::Reference< ParagraphImpl > xParagraph( getParagraph( aIt ) ); 2556 if ( xParagraph.is() ) 2557 { 2558 xParagraph->notifyEvent( 2559 ::css::accessibility::AccessibleEventId::SELECTION_CHANGED, 2560 ::css::uno::Any(), ::css::uno::Any() ); 2561 xParagraph->notifyEvent( 2562 ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED, 2563 ::css::uno::Any(), ::css::uno::Any() ); 2564 } 2565 } 2566 } 2567 } 2568 2569 void Document::justifySelection( TextPaM& rTextStart, TextPaM& rTextEnd ) 2570 { 2571 if ( rTextStart > rTextEnd ) 2572 { 2573 TextPaM aTextPaM( rTextStart ); 2574 rTextStart = rTextEnd; 2575 rTextEnd = aTextPaM; 2576 } 2577 } 2578 2579 void Document::disposeParagraphs() 2580 { 2581 for (Paragraphs::iterator aIt(m_xParagraphs->begin()); 2582 aIt != m_xParagraphs->end(); ++aIt) 2583 { 2584 ::css::uno::Reference< ::css::lang::XComponent > xComponent( 2585 aIt->getParagraph().get(), ::css::uno::UNO_QUERY); 2586 if (xComponent.is()) 2587 xComponent->dispose(); 2588 } 2589 } 2590 2591 // static 2592 ::css::uno::Any Document::mapFontColor(::Color const & rColor) 2593 { 2594 return ::css::uno::makeAny( 2595 static_cast< ::sal_Int32 >(COLORDATA_RGB(rColor.GetColor()))); 2596 // FIXME keep transparency? 2597 } 2598 2599 // static 2600 ::Color Document::mapFontColor(::css::uno::Any const & rColor) 2601 { 2602 ::sal_Int32 nColor = 0; 2603 rColor >>= nColor; 2604 return ::Color(static_cast< ::ColorData >(nColor)); 2605 } 2606 2607 // static 2608 ::css::uno::Any Document::mapFontWeight(::FontWeight nWeight) 2609 { 2610 // Map from ::FontWeight to ::css:awt::FontWeight, depends on order of 2611 // elements in ::FontWeight (vcl/vclenum.hxx): 2612 static float const aWeight[] 2613 = { ::css::awt::FontWeight::DONTKNOW, // WEIGHT_DONTKNOW 2614 ::css::awt::FontWeight::THIN, // WEIGHT_THIN 2615 ::css::awt::FontWeight::ULTRALIGHT, // WEIGHT_ULTRALIGHT 2616 ::css::awt::FontWeight::LIGHT, // WEIGHT_LIGHT 2617 ::css::awt::FontWeight::SEMILIGHT, // WEIGHT_SEMILIGHT 2618 ::css::awt::FontWeight::NORMAL, // WEIGHT_NORMAL 2619 ::css::awt::FontWeight::NORMAL, // WEIGHT_MEDIUM 2620 ::css::awt::FontWeight::SEMIBOLD, // WEIGHT_SEMIBOLD 2621 ::css::awt::FontWeight::BOLD, // WEIGHT_BOLD 2622 ::css::awt::FontWeight::ULTRABOLD, // WEIGHT_ULTRABOLD 2623 ::css::awt::FontWeight::BLACK }; // WEIGHT_BLACK 2624 return ::css::uno::makeAny(aWeight[nWeight]); 2625 } 2626 2627 // static 2628 ::FontWeight Document::mapFontWeight(::css::uno::Any const & rWeight) 2629 { 2630 float nWeight = ::css::awt::FontWeight::NORMAL; 2631 rWeight >>= nWeight; 2632 return nWeight <= ::css::awt::FontWeight::DONTKNOW ? WEIGHT_DONTKNOW 2633 : nWeight <= ::css::awt::FontWeight::THIN ? WEIGHT_THIN 2634 : nWeight <= ::css::awt::FontWeight::ULTRALIGHT ? WEIGHT_ULTRALIGHT 2635 : nWeight <= ::css::awt::FontWeight::LIGHT ? WEIGHT_LIGHT 2636 : nWeight <= ::css::awt::FontWeight::SEMILIGHT ? WEIGHT_SEMILIGHT 2637 : nWeight <= ::css::awt::FontWeight::NORMAL ? WEIGHT_NORMAL 2638 : nWeight <= ::css::awt::FontWeight::SEMIBOLD ? WEIGHT_SEMIBOLD 2639 : nWeight <= ::css::awt::FontWeight::BOLD ? WEIGHT_BOLD 2640 : nWeight <= ::css::awt::FontWeight::ULTRABOLD ? WEIGHT_ULTRABOLD 2641 : WEIGHT_BLACK; 2642 } 2643 2644 } 2645 2646