Update ooo320-m1
[ooovba.git] / accessibility / source / extended / textwindowaccessibility.cxx
blob78abef10d3f0fc53f6663a6682f42f771987fc2a
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: textwindowaccessibility.cxx,v $
10 * $Revision: 1.7 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_accessibility.hxx"
34 #ifndef _TOOLKIT_AWT_VCLXACCESSIBLECOMPONENT_HXX_
35 #include <accessibility/extended/textwindowaccessibility.hxx>
36 #endif
37 #include "comphelper/accessibleeventnotifier.hxx"
38 #include "unotools/accessiblerelationsethelper.hxx"
39 #include <unotools/accessiblestatesethelper.hxx>
40 #include <vcl/window.hxx>
41 #include <toolkit/helper/convert.hxx>
43 #include <algorithm>
44 #include <vector>
45 #include <hash_map>
47 namespace css = ::com::sun::star;
49 namespace accessibility
52 // Both ::osl::Mutex and ParagraphBase implement acquire and release, and thus
53 // ::rtl::Reference< Paragraph > does not work. So ParagraphImpl was factored
54 // out and ::rtl::Reference< ParagraphImpl > is used instead.
55 class Paragraph: private ::osl::Mutex, public ParagraphImpl
57 public:
58 inline Paragraph(::rtl::Reference< Document > const & rDocument,
59 Paragraphs::size_type nNumber):
60 ParagraphImpl(rDocument, nNumber, *this) {}
63 void SfxListenerGuard::startListening(::SfxBroadcaster & rNotifier)
65 OSL_ENSURE(m_pNotifier == 0, "called more than once");
66 m_pNotifier = &rNotifier;
67 m_rListener.StartListening(*m_pNotifier, true);
70 void SfxListenerGuard::endListening()
72 if (m_pNotifier != 0)
74 m_rListener.EndListening(*m_pNotifier);
75 m_pNotifier = 0;
79 void WindowListenerGuard::startListening(::Window & rNotifier)
81 OSL_ENSURE(m_pNotifier == 0, "called more than once");
82 m_pNotifier = &rNotifier;
83 m_pNotifier->AddEventListener(m_aListener);
86 void WindowListenerGuard::endListening()
88 if (m_pNotifier != 0)
90 m_pNotifier->RemoveEventListener(m_aListener);
91 m_pNotifier = 0;
95 ParagraphImpl::ParagraphImpl(::rtl::Reference< Document > const & rDocument,
96 Paragraphs::size_type nNumber,
97 ::osl::Mutex & rMutex):
98 ParagraphBase(rMutex),
99 m_xDocument(rDocument),
100 m_nNumber(nNumber),
101 m_nClientId(0)
103 m_aParagraphText = m_xDocument->retrieveParagraphText(this);
106 void
107 ParagraphImpl::numberChanged(bool bIncremented)
109 if (bIncremented)
110 ++m_nNumber;
111 else
112 --m_nNumber;
115 void ParagraphImpl::textChanged()
117 ::rtl::OUString aParagraphText = implGetText();
118 ::css::uno::Any aOldValue, aNewValue;
119 if ( implInitTextChangedEvent( m_aParagraphText, aParagraphText, aOldValue, aNewValue ) )
121 m_aParagraphText = aParagraphText;
122 notifyEvent(::css::accessibility::AccessibleEventId::
123 TEXT_CHANGED,
124 aOldValue, aNewValue);
128 void ParagraphImpl::notifyEvent(::sal_Int16 nEventId,
129 ::css::uno::Any const & rOldValue,
130 ::css::uno::Any const & rNewValue)
132 if (m_nClientId)
133 comphelper::AccessibleEventNotifier::addEvent( m_nClientId, ::css::accessibility::AccessibleEventObject(
134 static_cast< ::cppu::OWeakObject * >(this),
135 nEventId, rNewValue, rOldValue) );
138 // virtual
139 ::css::uno::Reference< ::css::accessibility::XAccessibleContext > SAL_CALL
140 ParagraphImpl::getAccessibleContext() throw (::css::uno::RuntimeException)
142 checkDisposed();
143 return this;
146 // virtual
147 ::sal_Int32 SAL_CALL ParagraphImpl::getAccessibleChildCount()
148 throw (::css::uno::RuntimeException)
150 checkDisposed();
151 return 0;
154 // virtual
155 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL
156 ParagraphImpl::getAccessibleChild(::sal_Int32)
157 throw (::css::lang::IndexOutOfBoundsException,
158 ::css::uno::RuntimeException)
160 checkDisposed();
161 throw ::css::lang::IndexOutOfBoundsException(
162 ::rtl::OUString(
163 RTL_CONSTASCII_USTRINGPARAM(
164 "textwindowaccessibility.cxx:"
165 " ParagraphImpl::getAccessibleChild")),
166 static_cast< ::css::uno::XWeak * >(this));
169 // virtual
170 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL
171 ParagraphImpl::getAccessibleParent()
172 throw (::css::uno::RuntimeException)
174 checkDisposed();
175 return m_xDocument->getAccessible();
178 // virtual
179 ::sal_Int32 SAL_CALL ParagraphImpl::getAccessibleIndexInParent()
180 throw (::css::uno::RuntimeException)
182 checkDisposed();
183 return m_xDocument->retrieveParagraphIndex(this);
186 // virtual
187 ::sal_Int16 SAL_CALL ParagraphImpl::getAccessibleRole()
188 throw (::css::uno::RuntimeException)
190 checkDisposed();
191 return ::css::accessibility::AccessibleRole::PARAGRAPH;
194 // virtual
195 ::rtl::OUString SAL_CALL ParagraphImpl::getAccessibleDescription()
196 throw (::css::uno::RuntimeException)
198 checkDisposed();
199 return ::rtl::OUString();
202 // virtual
203 ::rtl::OUString SAL_CALL ParagraphImpl::getAccessibleName()
204 throw (::css::uno::RuntimeException)
206 checkDisposed();
207 return ::rtl::OUString();
210 // virtual
211 ::css::uno::Reference< ::css::accessibility::XAccessibleRelationSet >
212 SAL_CALL ParagraphImpl::getAccessibleRelationSet()
213 throw (::css::uno::RuntimeException)
215 checkDisposed();
216 return m_xDocument->retrieveParagraphRelationSet( this );
219 // virtual
220 ::css::uno::Reference< ::css::accessibility::XAccessibleStateSet >
221 SAL_CALL ParagraphImpl::getAccessibleStateSet()
222 throw (::css::uno::RuntimeException)
224 checkDisposed();
226 // FIXME Notification of changes (STATE_CHANGED) missing when
227 // m_rView.IsReadOnly() changes:
228 return new ::utl::AccessibleStateSetHelper(
229 m_xDocument->retrieveParagraphState(this));
232 // virtual
233 ::css::lang::Locale SAL_CALL ParagraphImpl::getLocale()
234 throw (::css::accessibility::IllegalAccessibleComponentStateException,
235 ::css::uno::RuntimeException)
237 checkDisposed();
238 return m_xDocument->retrieveLocale();
241 // virtual
242 ::sal_Bool SAL_CALL ParagraphImpl::containsPoint(::css::awt::Point const & rPoint)
243 throw (::css::uno::RuntimeException)
245 checkDisposed();
246 ::css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this,
247 false));
248 return rPoint.X >= 0 && rPoint.X < aRect.Width
249 && rPoint.Y >= 0 && rPoint.Y < aRect.Height;
252 // virtual
253 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL
254 ParagraphImpl::getAccessibleAtPoint(::css::awt::Point const &)
255 throw (::css::uno::RuntimeException)
257 checkDisposed();
258 return 0;
261 // virtual
262 ::css::awt::Rectangle SAL_CALL ParagraphImpl::getBounds()
263 throw (::css::uno::RuntimeException)
265 checkDisposed();
266 return m_xDocument->retrieveParagraphBounds(this, false);
269 // virtual
270 ::css::awt::Point SAL_CALL ParagraphImpl::getLocation()
271 throw (::css::uno::RuntimeException)
273 checkDisposed();
274 ::css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this,
275 false));
276 return ::css::awt::Point(aRect.X, aRect.Y);
279 // virtual
280 ::css::awt::Point SAL_CALL ParagraphImpl::getLocationOnScreen()
281 throw (::css::uno::RuntimeException)
283 checkDisposed();
284 ::css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this,
285 true));
286 return ::css::awt::Point(aRect.X, aRect.Y);
289 // virtual
290 ::css::awt::Size SAL_CALL ParagraphImpl::getSize()
291 throw (::css::uno::RuntimeException)
293 checkDisposed();
294 ::css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this,
295 false));
296 return ::css::awt::Size(aRect.Width, aRect.Height);
299 // virtual
300 void SAL_CALL ParagraphImpl::grabFocus() throw (::css::uno::RuntimeException)
302 checkDisposed();
303 Window* pWindow = m_xDocument->GetWindow();
304 if ( pWindow )
306 pWindow->GrabFocus();
310 m_xDocument->changeParagraphSelection(this, 0, 0);
312 catch (::css::lang::IndexOutOfBoundsException & rEx)
314 OSL_TRACE(
315 "textwindowaccessibility.cxx: ParagraphImpl::grabFocus:"
316 " caught unexpected %s\n",
317 ::rtl::OUStringToOString(rEx.Message, RTL_TEXTENCODING_UTF8).
318 getStr());
322 // virtual
323 ::css::uno::Any SAL_CALL ParagraphImpl::getAccessibleKeyBinding()
324 throw (::css::uno::RuntimeException)
326 checkDisposed();
327 return ::css::uno::Any();
330 // virtual
331 ::css::util::Color SAL_CALL ParagraphImpl::getForeground()
332 throw (::css::uno::RuntimeException)
334 return 0; // TODO
337 // virtual
338 ::css::util::Color SAL_CALL ParagraphImpl::getBackground()
339 throw (::css::uno::RuntimeException)
341 return 0; // TODO
344 // virtual
345 ::sal_Int32 SAL_CALL ParagraphImpl::getCaretPosition()
346 throw (::css::uno::RuntimeException)
348 checkDisposed();
349 return m_xDocument->retrieveParagraphCaretPosition(this);
352 // virtual
353 ::sal_Bool SAL_CALL ParagraphImpl::setCaretPosition(::sal_Int32 nIndex)
354 throw (::css::lang::IndexOutOfBoundsException,
355 ::css::uno::RuntimeException)
357 checkDisposed();
358 m_xDocument->changeParagraphSelection(this, nIndex, nIndex);
359 return true;
362 // virtual
363 ::sal_Unicode SAL_CALL ParagraphImpl::getCharacter(::sal_Int32 nIndex)
364 throw (::css::lang::IndexOutOfBoundsException,
365 ::css::uno::RuntimeException)
367 checkDisposed();
368 return OCommonAccessibleText::getCharacter(nIndex);
371 // virtual
372 ::css::uno::Sequence< ::css::beans::PropertyValue > SAL_CALL
373 ParagraphImpl::getCharacterAttributes(::sal_Int32 nIndex, const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aRequestedAttributes)
374 throw (::css::lang::IndexOutOfBoundsException,
375 ::css::uno::RuntimeException)
377 checkDisposed();
378 return m_xDocument->retrieveCharacterAttributes( this, nIndex, aRequestedAttributes );
381 // virtual
382 ::css::awt::Rectangle SAL_CALL
383 ParagraphImpl::getCharacterBounds(::sal_Int32 nIndex)
384 throw (::css::lang::IndexOutOfBoundsException,
385 ::css::uno::RuntimeException)
387 checkDisposed();
388 ::css::awt::Rectangle aBounds(m_xDocument->retrieveCharacterBounds(this, nIndex));
389 ::css::awt::Rectangle aParaBounds(m_xDocument->retrieveParagraphBounds(this, false));
390 aBounds.X -= aParaBounds.X;
391 aBounds.Y -= aParaBounds.Y;
392 return aBounds;
395 // virtual
396 ::sal_Int32 SAL_CALL ParagraphImpl::getCharacterCount()
397 throw (::css::uno::RuntimeException)
399 checkDisposed();
400 return OCommonAccessibleText::getCharacterCount();
403 // virtual
404 ::sal_Int32 SAL_CALL
405 ParagraphImpl::getIndexAtPoint(::css::awt::Point const & rPoint)
406 throw (::css::uno::RuntimeException)
408 checkDisposed();
409 ::css::awt::Point aPoint(rPoint);
410 ::css::awt::Rectangle aParaBounds(m_xDocument->retrieveParagraphBounds(this, false));
411 aPoint.X += aParaBounds.X;
412 aPoint.Y += aParaBounds.Y;
413 return m_xDocument->retrieveCharacterIndex(this, aPoint);
416 // virtual
417 ::rtl::OUString SAL_CALL ParagraphImpl::getSelectedText()
418 throw (::css::uno::RuntimeException)
420 checkDisposed();
422 return OCommonAccessibleText::getSelectedText();
425 // virtual
426 ::sal_Int32 SAL_CALL ParagraphImpl::getSelectionStart()
427 throw (::css::uno::RuntimeException)
429 checkDisposed();
430 return OCommonAccessibleText::getSelectionStart();
433 // virtual
434 ::sal_Int32 SAL_CALL ParagraphImpl::getSelectionEnd()
435 throw (::css::uno::RuntimeException)
437 checkDisposed();
438 return OCommonAccessibleText::getSelectionEnd();
441 // virtual
442 ::sal_Bool SAL_CALL ParagraphImpl::setSelection(::sal_Int32 nStartIndex,
443 ::sal_Int32 nEndIndex)
444 throw (::css::lang::IndexOutOfBoundsException,
445 ::css::uno::RuntimeException)
447 checkDisposed();
448 m_xDocument->changeParagraphSelection(this, nStartIndex, nEndIndex);
449 return true;
452 // virtual
453 ::rtl::OUString SAL_CALL ParagraphImpl::getText()
454 throw (::css::uno::RuntimeException)
456 checkDisposed();
457 return OCommonAccessibleText::getText();
460 // virtual
461 ::rtl::OUString SAL_CALL ParagraphImpl::getTextRange(::sal_Int32 nStartIndex,
462 ::sal_Int32 nEndIndex)
463 throw (::css::lang::IndexOutOfBoundsException,
464 ::css::uno::RuntimeException)
466 checkDisposed();
467 return OCommonAccessibleText::getTextRange(nStartIndex, nEndIndex);
470 // virtual
471 ::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)
473 checkDisposed();
474 return OCommonAccessibleText::getTextAtIndex(nIndex, aTextType);
477 // virtual
478 ::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)
480 checkDisposed();
481 return OCommonAccessibleText::getTextBeforeIndex(nIndex, aTextType);
484 // virtual
485 ::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)
487 checkDisposed();
488 return OCommonAccessibleText::getTextBehindIndex(nIndex, aTextType);
491 // virtual
492 ::sal_Bool SAL_CALL ParagraphImpl::copyText(::sal_Int32 nStartIndex,
493 ::sal_Int32 nEndIndex)
494 throw (::css::lang::IndexOutOfBoundsException,
495 ::css::uno::RuntimeException)
497 checkDisposed();
498 m_xDocument->copyParagraphText(this, nStartIndex, nEndIndex);
499 return true;
502 // virtual
503 ::sal_Bool SAL_CALL ParagraphImpl::cutText(::sal_Int32 nStartIndex,
504 ::sal_Int32 nEndIndex)
505 throw (::css::lang::IndexOutOfBoundsException,
506 ::css::uno::RuntimeException)
508 checkDisposed();
509 m_xDocument->changeParagraphText(this, nStartIndex, nEndIndex, true, false,
510 ::rtl::OUString());
511 return true;
514 // virtual
515 ::sal_Bool SAL_CALL ParagraphImpl::pasteText(::sal_Int32 nIndex)
516 throw (::css::lang::IndexOutOfBoundsException,
517 ::css::uno::RuntimeException)
519 checkDisposed();
520 m_xDocument->changeParagraphText(this, nIndex, nIndex, false, true,
521 ::rtl::OUString());
522 return true;
525 // virtual
526 ::sal_Bool SAL_CALL ParagraphImpl::deleteText(::sal_Int32 nStartIndex,
527 ::sal_Int32 nEndIndex)
528 throw (::css::lang::IndexOutOfBoundsException,
529 ::css::uno::RuntimeException)
531 checkDisposed();
532 m_xDocument->changeParagraphText(this, nStartIndex, nEndIndex, false, false,
533 ::rtl::OUString());
534 return true;
537 // virtual
538 ::sal_Bool SAL_CALL ParagraphImpl::insertText(::rtl::OUString const & rText,
539 ::sal_Int32 nIndex)
540 throw (::css::lang::IndexOutOfBoundsException,
541 ::css::uno::RuntimeException)
543 checkDisposed();
544 m_xDocument->changeParagraphText(this, nIndex, nIndex, false, false, rText);
545 return true;
548 // virtual
549 ::sal_Bool SAL_CALL
550 ParagraphImpl::replaceText(::sal_Int32 nStartIndex, ::sal_Int32 nEndIndex,
551 ::rtl::OUString const & rReplacement)
552 throw (::css::lang::IndexOutOfBoundsException,
553 ::css::uno::RuntimeException)
555 checkDisposed();
556 m_xDocument->changeParagraphText(this, nStartIndex, nEndIndex, false, false,
557 rReplacement);
558 return true;
561 // virtual
562 ::sal_Bool SAL_CALL ParagraphImpl::setAttributes(
563 ::sal_Int32 nStartIndex, ::sal_Int32 nEndIndex,
564 ::css::uno::Sequence< ::css::beans::PropertyValue > const & rAttributeSet)
565 throw (::css::lang::IndexOutOfBoundsException,
566 ::css::uno::RuntimeException)
568 checkDisposed();
569 m_xDocument->changeParagraphAttributes(this, nStartIndex, nEndIndex,
570 rAttributeSet);
571 return true;
574 // virtual
575 ::sal_Bool SAL_CALL ParagraphImpl::setText(::rtl::OUString const & rText)
576 throw (::css::uno::RuntimeException)
578 checkDisposed();
579 m_xDocument->changeParagraphText(this, rText);
580 return true;
583 // virtual
584 ::css::uno::Sequence< ::css::beans::PropertyValue > SAL_CALL
585 ParagraphImpl::getDefaultAttributes(const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes)
586 throw (::css::uno::RuntimeException)
588 checkDisposed();
589 return m_xDocument->retrieveDefaultAttributes( this, RequestedAttributes );
592 // virtual
593 ::css::uno::Sequence< ::css::beans::PropertyValue > SAL_CALL
594 ParagraphImpl::getRunAttributes(::sal_Int32 Index, const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes)
595 throw (::css::lang::IndexOutOfBoundsException,
596 ::css::uno::RuntimeException)
598 checkDisposed();
599 return m_xDocument->retrieveRunAttributes( this, Index, RequestedAttributes );
602 // virtual
603 ::sal_Int32 SAL_CALL ParagraphImpl::getLineNumberAtIndex( ::sal_Int32 nIndex )
604 throw (::css::lang::IndexOutOfBoundsException,
605 ::css::uno::RuntimeException)
607 checkDisposed();
609 ::sal_Int32 nLineNo = -1;
610 ::css::i18n::Boundary aBoundary =
611 m_xDocument->retrieveParagraphLineBoundary( this, nIndex, &nLineNo );
613 return nLineNo;
616 // virtual
617 ::css::accessibility::TextSegment SAL_CALL ParagraphImpl::getTextAtLineNumber( ::sal_Int32 nLineNo )
618 throw (::css::lang::IndexOutOfBoundsException,
619 ::css::uno::RuntimeException)
621 checkDisposed();
623 ::css::i18n::Boundary aBoundary =
624 m_xDocument->retrieveParagraphBoundaryOfLine( this, nLineNo );
626 return ::css::accessibility::TextSegment( getTextRange(aBoundary.startPos, aBoundary.endPos),
627 aBoundary.startPos, aBoundary.endPos);
630 // virtual
631 ::css::accessibility::TextSegment SAL_CALL ParagraphImpl::getTextAtLineWithCaret( )
632 throw (::css::uno::RuntimeException)
634 checkDisposed();
636 sal_Int32 nLineNo = getNumberOfLineWithCaret();
638 try {
639 return ( nLineNo >= 0 ) ?
640 getTextAtLineNumber( nLineNo ) :
641 ::css::accessibility::TextSegment();
642 } catch (const ::css::lang::IndexOutOfBoundsException&) {
643 throw ::css::uno::RuntimeException(
644 ::rtl::OUString(
645 RTL_CONSTASCII_USTRINGPARAM(
646 "textwindowaccessibility.cxx:"
647 " ParagraphImpl::getTextAtLineWithCaret") ),
648 static_cast< ::css::uno::XWeak * >( this ) );
652 // virtual
653 ::sal_Int32 SAL_CALL ParagraphImpl::getNumberOfLineWithCaret( )
654 throw (::css::uno::RuntimeException)
656 checkDisposed();
657 return m_xDocument->retrieveParagraphLineWithCursor(this);
661 // virtual
662 void SAL_CALL ParagraphImpl::addEventListener(
663 ::css::uno::Reference<
664 ::css::accessibility::XAccessibleEventListener > const & rListener)
665 throw (::css::uno::RuntimeException)
667 if (rListener.is())
669 ::osl::ClearableMutexGuard aGuard(rBHelper.rMutex);
670 if (rBHelper.bDisposed || rBHelper.bInDispose)
672 aGuard.clear();
673 rListener->disposing(::css::lang::EventObject(
674 static_cast< ::cppu::OWeakObject * >(this)));
676 else
678 if (!m_nClientId)
679 m_nClientId = comphelper::AccessibleEventNotifier::registerClient( );
680 comphelper::AccessibleEventNotifier::addEventListener( m_nClientId, rListener );
685 // virtual
686 void SAL_CALL ParagraphImpl::removeEventListener(
687 ::css::uno::Reference<
688 ::css::accessibility::XAccessibleEventListener > const & rListener)
689 throw (::css::uno::RuntimeException)
691 comphelper::AccessibleEventNotifier::TClientId nId = 0;
693 ::osl::ClearableMutexGuard aGuard(rBHelper.rMutex);
694 if (rListener.is() && m_nClientId != 0
695 && comphelper::AccessibleEventNotifier::removeEventListener( m_nClientId, rListener ) == 0)
697 nId = m_nClientId;
698 m_nClientId = 0;
701 if (nId != 0)
703 // no listeners anymore
704 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
705 // and at least to us not firing any events anymore, in case somebody calls
706 // NotifyAccessibleEvent, again
707 comphelper::AccessibleEventNotifier::revokeClient(nId);
711 // virtual
712 void SAL_CALL ParagraphImpl::disposing()
714 comphelper::AccessibleEventNotifier::TClientId nId = 0;
716 ::osl::ClearableMutexGuard aGuard(rBHelper.rMutex);
717 nId = m_nClientId;
718 m_nClientId = 0;
720 if (nId != 0)
721 comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing(nId, *this);
724 // virtual
725 ::rtl::OUString ParagraphImpl::implGetText()
727 return m_xDocument->retrieveParagraphText(this);
730 // virtual
731 ::css::lang::Locale ParagraphImpl::implGetLocale()
733 return m_xDocument->retrieveLocale();
736 // virtual
737 void ParagraphImpl::implGetSelection(::sal_Int32 & rStartIndex,
738 ::sal_Int32 & rEndIndex)
740 m_xDocument->retrieveParagraphSelection(this, &rStartIndex, &rEndIndex);
743 // virtual
744 void ParagraphImpl::implGetParagraphBoundary( ::css::i18n::Boundary& rBoundary,
745 ::sal_Int32 nIndex )
747 ::rtl::OUString sText( implGetText() );
748 ::sal_Int32 nLength = sText.getLength();
750 if ( implIsValidIndex( nIndex, nLength ) )
752 rBoundary.startPos = 0;
753 rBoundary.endPos = nLength;
755 else
757 rBoundary.startPos = nIndex;
758 rBoundary.endPos = nIndex;
762 // virtual
763 void ParagraphImpl::implGetLineBoundary( ::css::i18n::Boundary& rBoundary,
764 ::sal_Int32 nIndex )
766 ::rtl::OUString sText( implGetText() );
767 ::sal_Int32 nLength = sText.getLength();
769 if ( implIsValidIndex( nIndex, nLength ) || nIndex == nLength )
771 ::css::i18n::Boundary aBoundary =
772 m_xDocument->retrieveParagraphLineBoundary( this, nIndex );
773 rBoundary.startPos = aBoundary.startPos;
774 rBoundary.endPos = aBoundary.endPos;
776 else
778 rBoundary.startPos = nIndex;
779 rBoundary.endPos = nIndex;
784 void ParagraphImpl::checkDisposed()
786 ::osl::MutexGuard aGuard(rBHelper.rMutex);
787 if (!(rBHelper.bDisposed || rBHelper.bInDispose))
788 return;
789 throw ::css::lang::DisposedException(
790 ::rtl::OUString(), static_cast< ::css::uno::XWeak * >(this));
793 Document::Document(::VCLXWindow * pVclXWindow, ::TextEngine & rEngine,
794 ::TextView & rView, bool bCompoundControlChild):
795 VCLXAccessibleComponent(pVclXWindow),
796 m_xAccessible(pVclXWindow),
797 m_rEngine(rEngine),
798 m_rView(rView),
799 m_aEngineListener(*this),
800 m_aViewListener(LINK(this, Document, WindowEventHandler)),
801 m_bCompoundControlChild(bCompoundControlChild)
804 ::css::lang::Locale Document::retrieveLocale()
806 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
807 return m_rEngine.GetLocale();
810 ::sal_Int32 Document::retrieveParagraphIndex(ParagraphImpl const * pParagraph)
812 ::osl::MutexGuard aInternalGuard(GetMutex());
814 // If a client holds on to a Paragraph that is no longer visible, it can
815 // happen that this Paragraph lies outside the range from m_aVisibleBegin
816 // to m_aVisibleEnd. In that case, return -1 instead of a valid index:
817 Paragraphs::iterator aPara(m_xParagraphs->begin()
818 + pParagraph->getNumber());
819 return aPara < m_aVisibleBegin || aPara >= m_aVisibleEnd
820 ? -1 : static_cast< ::sal_Int32 >(aPara - m_aVisibleBegin);
821 // XXX numeric overflow
824 ::sal_Int64 Document::retrieveParagraphState(ParagraphImpl const * pParagraph)
826 ::osl::MutexGuard aInternalGuard(GetMutex());
828 // If a client holds on to a Paragraph that is no longer visible, it can
829 // happen that this Paragraph lies outside the range from m_aVisibleBegin
830 // to m_aVisibleEnd. In that case, it is neither VISIBLE nor SHOWING:
831 ::sal_Int64 nState
832 = (static_cast< ::sal_Int64 >(1)
833 << ::css::accessibility::AccessibleStateType::ENABLED)
834 | (static_cast< ::sal_Int64 >(1)
835 << ::css::accessibility::AccessibleStateType::SENSITIVE)
836 | (static_cast< ::sal_Int64 >(1)
837 << ::css::accessibility::AccessibleStateType::FOCUSABLE)
838 | (static_cast< ::sal_Int64 >(1)
839 << ::css::accessibility::AccessibleStateType::MULTI_LINE);
840 if (!m_rView.IsReadOnly())
841 nState |= (static_cast< ::sal_Int64 >(1)
842 << ::css::accessibility::AccessibleStateType::EDITABLE);
843 Paragraphs::iterator aPara(m_xParagraphs->begin()
844 + pParagraph->getNumber());
845 if (aPara >= m_aVisibleBegin && aPara < m_aVisibleEnd)
847 nState
848 |= (static_cast< ::sal_Int64 >(1)
849 << ::css::accessibility::AccessibleStateType::VISIBLE)
850 | (static_cast< ::sal_Int64 >(1)
851 << ::css::accessibility::AccessibleStateType::SHOWING);
852 if (aPara == m_aFocused)
853 nState |= (static_cast< ::sal_Int64 >(1)
854 << ::css::accessibility::AccessibleStateType::FOCUSED);
856 return nState;
859 ::css::awt::Rectangle
860 Document::retrieveParagraphBounds(ParagraphImpl const * pParagraph,
861 bool bAbsolute)
863 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
864 ::osl::MutexGuard aInternalGuard(GetMutex());
866 // If a client holds on to a Paragraph that is no longer visible (as it
867 // scrolled out the top of the view), it can happen that this Paragraph
868 // lies before m_aVisibleBegin. In that case, calculate the vertical
869 // position of the Paragraph starting at paragraph 0, otherwise optimize
870 // and start at m_aVisibleBegin:
871 Paragraphs::iterator aPara(m_xParagraphs->begin()
872 + pParagraph->getNumber());
873 ::sal_Int32 nPos;
874 Paragraphs::iterator aIt;
875 if (aPara < m_aVisibleBegin)
877 nPos = 0;
878 aIt = m_xParagraphs->begin();
880 else
882 nPos = m_nViewOffset - m_nVisibleBeginOffset;
883 aIt = m_aVisibleBegin;
885 for (; aIt != aPara; ++aIt)
886 nPos += aIt->getHeight();
888 Point aOrig(0, 0);
889 if (bAbsolute)
890 aOrig = m_rView.GetWindow()->OutputToAbsoluteScreenPixel(aOrig);
892 return ::css::awt::Rectangle(
893 static_cast< ::sal_Int32 >(aOrig.X()),
894 static_cast< ::sal_Int32 >(aOrig.Y()) + nPos - m_nViewOffset,
895 m_rView.GetWindow()->GetOutputSizePixel().Width(), aPara->getHeight());
896 // XXX numeric overflow (3x)
899 ::rtl::OUString
900 Document::retrieveParagraphText(ParagraphImpl const * pParagraph)
902 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
903 ::osl::MutexGuard aInternalGuard(GetMutex());
904 return m_rEngine.GetText(static_cast< ::ULONG >(pParagraph->getNumber()));
905 // numeric overflow cannot happen here
908 void Document::retrieveParagraphSelection(ParagraphImpl const * pParagraph,
909 ::sal_Int32 * pBegin,
910 ::sal_Int32 * pEnd)
912 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
913 ::osl::MutexGuard aInternalGuard(GetMutex());
914 ::TextSelection const & rSelection = m_rView.GetSelection();
915 Paragraphs::size_type nNumber = pParagraph->getNumber();
916 TextPaM aStartPaM( rSelection.GetStart() );
917 TextPaM aEndPaM( rSelection.GetEnd() );
918 TextPaM aMinPaM( ::std::min( aStartPaM, aEndPaM ) );
919 TextPaM aMaxPaM( ::std::max( aStartPaM, aEndPaM ) );
921 if ( nNumber >= aMinPaM.GetPara() && nNumber <= aMaxPaM.GetPara() )
923 *pBegin = nNumber > aMinPaM.GetPara()
924 ? 0
925 : static_cast< ::sal_Int32 >( aMinPaM.GetIndex() );
926 // XXX numeric overflow
927 *pEnd = nNumber < aMaxPaM.GetPara()
928 ? static_cast< ::sal_Int32 >( m_rEngine.GetText(static_cast< ::ULONG >(nNumber)).Len() )
929 : static_cast< ::sal_Int32 >( aMaxPaM.GetIndex() );
930 // XXX numeric overflow (3x)
932 if ( aStartPaM > aEndPaM )
933 ::std::swap( *pBegin, *pEnd );
935 else
937 *pBegin = 0;
938 *pEnd = 0;
942 ::sal_Int32 Document::retrieveParagraphCaretPosition(ParagraphImpl const * pParagraph)
944 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
945 ::osl::MutexGuard aInternalGuard(GetMutex());
946 ::TextSelection const & rSelection = m_rView.GetSelection();
947 Paragraphs::size_type nNumber = pParagraph->getNumber();
948 TextPaM aEndPaM( rSelection.GetEnd() );
950 return aEndPaM.GetPara() == nNumber
951 ? static_cast< ::sal_Int32 >(aEndPaM.GetIndex()) : -1;
954 ::css::awt::Rectangle
955 Document::retrieveCharacterBounds(ParagraphImpl const * pParagraph,
956 ::sal_Int32 nIndex)
958 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
959 ::osl::MutexGuard aInternalGuard(GetMutex());
960 ::ULONG nNumber = static_cast< ::ULONG >(pParagraph->getNumber());
961 sal_Int32 nLength = m_rEngine.GetText(nNumber).Len();
962 // XXX numeric overflow
963 if (nIndex < 0 || nIndex > nLength)
964 throw ::css::lang::IndexOutOfBoundsException(
965 ::rtl::OUString(
966 RTL_CONSTASCII_USTRINGPARAM(
967 "textwindowaccessibility.cxx:"
968 " Document::retrieveCharacterAttributes")),
969 static_cast< ::css::uno::XWeak * >(this));
970 ::css::awt::Rectangle aBounds( 0, 0, 0, 0 );
971 if ( nIndex == nLength )
973 aBounds = AWTRectangle(
974 m_rEngine.PaMtoEditCursor(::TextPaM(nNumber,
975 static_cast< ::USHORT >(nIndex))));
977 else
979 ::Rectangle aLeft(
980 m_rEngine.PaMtoEditCursor(::TextPaM(nNumber,
981 static_cast< ::USHORT >(nIndex))));
982 // XXX numeric overflow
983 ::Rectangle aRight(
984 m_rEngine.PaMtoEditCursor(::TextPaM(nNumber,
985 static_cast< ::USHORT >(nIndex)
986 + 1)));
987 // XXX numeric overflow (2x)
988 // FIXME If the vertical extends of the two cursors do not match, assume
989 // nIndex is the last character on the line; the bounding box will then
990 // extend to m_rEnginge.GetMaxTextWidth():
991 ::sal_Int32 nWidth = (aLeft.Top() == aRight.Top()
992 && aLeft.Bottom() == aRight.Bottom())
993 ? static_cast< ::sal_Int32 >(aRight.Left() - aLeft.Left())
994 : static_cast< ::sal_Int32 >(m_rEngine.GetMaxTextWidth()
995 - aLeft.Left());
996 // XXX numeric overflow (4x)
997 aBounds = ::css::awt::Rectangle(static_cast< ::sal_Int32 >(aLeft.Left()),
998 static_cast< ::sal_Int32 >(aLeft.Top() - m_nViewOffset),
999 nWidth,
1000 static_cast< ::sal_Int32 >(aLeft.Bottom()
1001 - aLeft.Top()));
1002 // XXX numeric overflow (4x)
1004 return aBounds;
1007 ::sal_Int32 Document::retrieveCharacterIndex(ParagraphImpl const * pParagraph,
1008 ::css::awt::Point const & rPoint)
1010 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1011 ::osl::MutexGuard aInternalGuard(GetMutex());
1012 ::ULONG nNumber = static_cast< ::ULONG >(pParagraph->getNumber());
1013 // XXX numeric overflow
1014 ::TextPaM aPaM(m_rEngine.GetPaM(::Point(static_cast< long >(rPoint.X),
1015 static_cast< long >(rPoint.Y))));
1016 // XXX numeric overflow (2x)
1017 return aPaM.GetPara() == nNumber
1018 ? static_cast< ::sal_Int32 >(aPaM.GetIndex()) : -1;
1019 // XXX numeric overflow
1022 ::css::uno::Sequence< ::css::beans::PropertyValue >
1023 Document::retrieveCharacterAttributes(
1024 ParagraphImpl const * pParagraph, ::sal_Int32 nIndex,
1025 const ::css::uno::Sequence< ::rtl::OUString >& aRequestedAttributes)
1027 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1028 ::osl::MutexGuard aInternalGuard(GetMutex());
1029 ::ULONG nNumber = static_cast< ::ULONG >(pParagraph->getNumber());
1030 // XXX numeric overflow
1031 if (nIndex < 0 || nIndex >= m_rEngine.GetText(nNumber).Len())
1032 throw ::css::lang::IndexOutOfBoundsException(
1033 ::rtl::OUString(
1034 RTL_CONSTASCII_USTRINGPARAM(
1035 "textwindowaccessibility.cxx:"
1036 " Document::retrieveCharacterAttributes")),
1037 static_cast< ::css::uno::XWeak * >(this));
1039 // retrieve default attributes
1040 tPropValMap aCharAttrSeq;
1041 retrieveDefaultAttributesImpl( pParagraph, aRequestedAttributes, aCharAttrSeq );
1043 // retrieve run attributes
1044 tPropValMap aRunAttrSeq;
1045 retrieveRunAttributesImpl( pParagraph, nIndex, aRequestedAttributes, aRunAttrSeq );
1047 // merge default and run attributes
1048 for ( tPropValMap::const_iterator aRunIter = aRunAttrSeq.begin();
1049 aRunIter != aRunAttrSeq.end();
1050 ++aRunIter )
1052 aCharAttrSeq[ aRunIter->first ] = aRunIter->second;
1055 return convertHashMapToSequence( aCharAttrSeq );
1058 void Document::retrieveDefaultAttributesImpl(
1059 ParagraphImpl const * pParagraph,
1060 const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes,
1061 tPropValMap& rDefAttrSeq)
1063 // default attributes are not supported by text engine
1064 (void) pParagraph;
1065 (void) RequestedAttributes;
1066 (void) rDefAttrSeq;
1069 ::css::uno::Sequence< ::css::beans::PropertyValue >
1070 Document::retrieveDefaultAttributes(
1071 ParagraphImpl const * pParagraph,
1072 const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes)
1074 ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() );
1075 ::osl::MutexGuard aInternalGuard( GetMutex() );
1077 tPropValMap aDefAttrSeq;
1078 retrieveDefaultAttributesImpl( pParagraph, RequestedAttributes, aDefAttrSeq );
1079 return convertHashMapToSequence( aDefAttrSeq );
1082 // static
1083 ::css::uno::Sequence< ::css::beans::PropertyValue >
1084 Document::convertHashMapToSequence(tPropValMap& rAttrSeq)
1086 ::css::uno::Sequence< ::css::beans::PropertyValue > aValues( rAttrSeq.size() );
1087 ::css::beans::PropertyValue* pValues = aValues.getArray();
1088 ::sal_Int32 i = 0;
1089 for ( tPropValMap::const_iterator aIter = rAttrSeq.begin();
1090 aIter != rAttrSeq.end();
1091 ++aIter )
1093 pValues[i] = aIter->second;
1094 ++i;
1096 return aValues;
1099 void Document::retrieveRunAttributesImpl(
1100 ParagraphImpl const * pParagraph, ::sal_Int32 Index,
1101 const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes,
1102 tPropValMap& rRunAttrSeq)
1104 ::ULONG nNumber = static_cast< ::ULONG >( pParagraph->getNumber() );
1105 ::TextPaM aPaM( nNumber, static_cast< ::USHORT >( Index ) );
1106 // XXX numeric overflow
1107 // FIXME TEXTATTR_HYPERLINK ignored:
1108 ::TextAttribFontColor const * pColor
1109 = static_cast< ::TextAttribFontColor const * >(
1110 m_rEngine.FindAttrib( aPaM, TEXTATTR_FONTCOLOR ) );
1111 ::TextAttribFontWeight const * pWeight
1112 = static_cast< ::TextAttribFontWeight const * >(
1113 m_rEngine.FindAttrib( aPaM, TEXTATTR_FONTWEIGHT ) );
1114 tPropValMap aRunAttrSeq;
1115 if ( pColor )
1117 ::css::beans::PropertyValue aPropVal;
1118 aPropVal.Name =
1119 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CharColor" ) );
1120 aPropVal.Handle = -1;
1121 aPropVal.Value = mapFontColor( pColor->GetColor() );
1122 aPropVal.State = ::css::beans::PropertyState_DIRECT_VALUE;
1123 aRunAttrSeq[ aPropVal.Name ] = aPropVal;
1125 if ( pWeight )
1127 ::css::beans::PropertyValue aPropVal;
1128 aPropVal.Name =
1129 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CharWeight" ) );
1130 aPropVal.Handle = -1;
1131 aPropVal.Value = mapFontWeight( pWeight->getFontWeight() );
1132 aPropVal.State = ::css::beans::PropertyState_DIRECT_VALUE;
1133 aRunAttrSeq[ aPropVal.Name ] = aPropVal;
1135 if ( RequestedAttributes.getLength() == 0 )
1137 rRunAttrSeq = aRunAttrSeq;
1139 else
1141 const ::rtl::OUString* pReqAttrs = RequestedAttributes.getConstArray();
1142 const ::sal_Int32 nLength = RequestedAttributes.getLength();
1143 for ( ::sal_Int32 i = 0; i < nLength; ++i )
1145 tPropValMap::iterator aIter = aRunAttrSeq.find( pReqAttrs[i] );
1146 if ( aIter != aRunAttrSeq.end() )
1148 rRunAttrSeq[ (*aIter).first ] = (*aIter).second;
1154 ::css::uno::Sequence< ::css::beans::PropertyValue >
1155 Document::retrieveRunAttributes(
1156 ParagraphImpl const * pParagraph, ::sal_Int32 Index,
1157 const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes)
1159 ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() );
1160 ::osl::MutexGuard aInternalGuard( GetMutex() );
1161 ::ULONG nNumber = static_cast< ::ULONG >( pParagraph->getNumber() );
1162 // XXX numeric overflow
1163 if ( Index < 0 || Index >= m_rEngine.GetText(nNumber).Len() )
1164 throw ::css::lang::IndexOutOfBoundsException(
1165 ::rtl::OUString(
1166 RTL_CONSTASCII_USTRINGPARAM(
1167 "textwindowaccessibility.cxx:"
1168 " Document::retrieveRunAttributes") ),
1169 static_cast< ::css::uno::XWeak * >( this ) );
1171 tPropValMap aRunAttrSeq;
1172 retrieveRunAttributesImpl( pParagraph, Index, RequestedAttributes, aRunAttrSeq );
1173 return convertHashMapToSequence( aRunAttrSeq );
1176 void Document::changeParagraphText(ParagraphImpl * pParagraph,
1177 ::rtl::OUString const & rText)
1179 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1181 ::osl::MutexGuard aInternalGuard(GetMutex());
1182 ::ULONG nNumber = static_cast< ::ULONG >(pParagraph->getNumber());
1183 // XXX numeric overflow
1184 changeParagraphText(nNumber, 0, m_rEngine.GetTextLen(nNumber), false,
1185 false, rText);
1189 void Document::changeParagraphText(ParagraphImpl * pParagraph,
1190 ::sal_Int32 nBegin, ::sal_Int32 nEnd,
1191 bool bCut, bool bPaste,
1192 ::rtl::OUString const & rText)
1194 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1196 ::osl::MutexGuard aInternalGuard(GetMutex());
1197 ::ULONG nNumber = static_cast< ::ULONG >(pParagraph->getNumber());
1198 // XXX numeric overflow
1199 if (nBegin < 0 || nBegin > nEnd
1200 || nEnd > m_rEngine.GetText(nNumber).Len())
1201 throw ::css::lang::IndexOutOfBoundsException(
1202 ::rtl::OUString(
1203 RTL_CONSTASCII_USTRINGPARAM(
1204 "textwindowaccessibility.cxx:"
1205 " Document::changeParagraphText")),
1206 static_cast< ::css::uno::XWeak * >(this));
1207 changeParagraphText(nNumber, static_cast< ::USHORT >(nBegin),
1208 static_cast< ::USHORT >(nEnd), bCut, bPaste, rText);
1209 // XXX numeric overflow (2x)
1213 void Document::copyParagraphText(ParagraphImpl const * pParagraph,
1214 ::sal_Int32 nBegin, ::sal_Int32 nEnd)
1216 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1218 ::osl::MutexGuard aInternalGuard(GetMutex());
1219 ::ULONG nNumber = static_cast< ::ULONG >(pParagraph->getNumber());
1220 // XXX numeric overflow
1221 if (nBegin < 0 || nBegin > nEnd
1222 || nEnd > m_rEngine.GetText(nNumber).Len())
1223 throw ::css::lang::IndexOutOfBoundsException(
1224 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1225 "textwindowaccessibility.cxx:"
1226 " Document::copyParagraphText")),
1227 static_cast< ::css::uno::XWeak * >(this));
1228 m_rView.SetSelection(
1229 ::TextSelection(::TextPaM(nNumber, static_cast< ::USHORT >(nBegin)),
1230 ::TextPaM(nNumber, static_cast< ::USHORT >(nEnd))));
1231 // XXX numeric overflow (2x)
1232 m_rView.Copy();
1236 void Document::changeParagraphAttributes(
1237 ParagraphImpl * pParagraph, ::sal_Int32 nBegin, ::sal_Int32 nEnd,
1238 ::css::uno::Sequence< ::css::beans::PropertyValue > const & rAttributeSet)
1240 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1242 ::osl::MutexGuard aInternalGuard(GetMutex());
1243 ::ULONG nNumber = static_cast< ::ULONG >(pParagraph->getNumber());
1244 // XXX numeric overflow
1245 if (nBegin < 0 || nBegin > nEnd
1246 || nEnd > m_rEngine.GetText(nNumber).Len())
1247 throw ::css::lang::IndexOutOfBoundsException(
1248 ::rtl::OUString(
1249 RTL_CONSTASCII_USTRINGPARAM(
1250 "textwindowaccessibility.cxx:"
1251 " Document::changeParagraphAttributes")),
1252 static_cast< ::css::uno::XWeak * >(this));
1254 // FIXME The new attributes are added to any attributes already set,
1255 // they do not replace the old attributes as required by
1256 // XAccessibleEditableText.setAttributes:
1257 for (::sal_Int32 i = 0; i < rAttributeSet.getLength(); ++i)
1258 if (rAttributeSet[i].Name.equalsAsciiL(
1259 RTL_CONSTASCII_STRINGPARAM("CharColor")))
1260 m_rEngine.SetAttrib(::TextAttribFontColor(
1261 mapFontColor(rAttributeSet[i].Value)),
1262 nNumber, static_cast< ::USHORT >(nBegin),
1263 static_cast< ::USHORT >(nEnd));
1264 // XXX numeric overflow (2x)
1265 else if (rAttributeSet[i].Name.equalsAsciiL(
1266 RTL_CONSTASCII_STRINGPARAM("CharWeight")))
1267 m_rEngine.SetAttrib(::TextAttribFontWeight(
1268 mapFontWeight(rAttributeSet[i].Value)),
1269 nNumber, static_cast< ::USHORT >(nBegin),
1270 static_cast< ::USHORT >(nEnd));
1271 // XXX numeric overflow (2x)
1275 void Document::changeParagraphSelection(ParagraphImpl * pParagraph,
1276 ::sal_Int32 nBegin, ::sal_Int32 nEnd)
1278 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1280 ::osl::MutexGuard aInternalGuard(GetMutex());
1281 ::ULONG nNumber = static_cast< ::ULONG >(pParagraph->getNumber());
1282 // XXX numeric overflow
1283 if (nBegin < 0 || nBegin > nEnd
1284 || nEnd > m_rEngine.GetText(nNumber).Len())
1285 throw ::css::lang::IndexOutOfBoundsException(
1286 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1287 "textwindowaccessibility.cxx:"
1288 " Document::changeParagraphSelection")),
1289 static_cast< ::css::uno::XWeak * >(this));
1290 m_rView.SetSelection(
1291 ::TextSelection(::TextPaM(nNumber, static_cast< ::USHORT >(nBegin)),
1292 ::TextPaM(nNumber, static_cast< ::USHORT >(nEnd))));
1293 // XXX numeric overflow (2x)
1297 ::css::i18n::Boundary
1298 Document::retrieveParagraphLineBoundary( ParagraphImpl const * pParagraph,
1299 ::sal_Int32 nIndex, ::sal_Int32 *pLineNo )
1301 ::css::i18n::Boundary aBoundary;
1302 aBoundary.startPos = nIndex;
1303 aBoundary.endPos = nIndex;
1305 ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() );
1307 ::osl::MutexGuard aInternalGuard( GetMutex() );
1308 ::ULONG nNumber = static_cast< ::ULONG >( pParagraph->getNumber() );
1309 if ( nIndex < 0 || nIndex > m_rEngine.GetText( nNumber ).Len() )
1310 throw ::css::lang::IndexOutOfBoundsException(
1311 ::rtl::OUString(
1312 RTL_CONSTASCII_USTRINGPARAM(
1313 "textwindowaccessibility.cxx:"
1314 " Document::retrieveParagraphLineBoundary" ) ),
1315 static_cast< ::css::uno::XWeak * >( this ) );
1316 ::sal_Int32 nLineStart = 0;
1317 ::sal_Int32 nLineEnd = 0;
1318 ::USHORT nLineCount = m_rEngine.GetLineCount( nNumber );
1319 for ( ::USHORT nLine = 0; nLine < nLineCount; ++nLine )
1321 ::sal_Int32 nLineLength = static_cast< ::sal_Int32 >(
1322 m_rEngine.GetLineLen( nNumber, nLine ) );
1323 nLineStart = nLineEnd;
1324 nLineEnd += nLineLength;
1325 if ( nIndex >= nLineStart && ( ( nLine == nLineCount - 1 ) ? nIndex <= nLineEnd : nIndex < nLineEnd ) )
1327 aBoundary.startPos = nLineStart;
1328 aBoundary.endPos = nLineEnd;
1329 if( pLineNo )
1330 pLineNo[0] = nLine;
1331 break;
1336 return aBoundary;
1339 ::css::i18n::Boundary
1340 Document::retrieveParagraphBoundaryOfLine( ParagraphImpl const * pParagraph,
1341 ::sal_Int32 nLineNo )
1343 ::css::i18n::Boundary aBoundary;
1344 aBoundary.startPos = 0;
1345 aBoundary.endPos = 0;
1347 ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() );
1349 ::osl::MutexGuard aInternalGuard( GetMutex() );
1350 ::ULONG nNumber = static_cast< ::ULONG >( pParagraph->getNumber() );
1351 if ( nLineNo >= m_rEngine.GetLineCount( nNumber ) )
1352 throw ::css::lang::IndexOutOfBoundsException(
1353 ::rtl::OUString(
1354 RTL_CONSTASCII_USTRINGPARAM(
1355 "textwindowaccessibility.cxx:"
1356 " Document::retrieveParagraphBoundaryOfLine" ) ),
1357 static_cast< ::css::uno::XWeak * >( this ) );
1358 ::sal_Int32 nLineStart = 0;
1359 ::sal_Int32 nLineEnd = 0;
1360 for ( ::USHORT nLine = 0; nLine <= nLineNo; ++nLine )
1362 ::sal_Int32 nLineLength = static_cast< ::sal_Int32 >(
1363 m_rEngine.GetLineLen( nNumber, nLine ) );
1364 nLineStart = nLineEnd;
1365 nLineEnd += nLineLength;
1368 aBoundary.startPos = nLineStart;
1369 aBoundary.endPos = nLineEnd;
1372 return aBoundary;
1375 sal_Int32 Document::retrieveParagraphLineWithCursor( ParagraphImpl const * pParagraph )
1377 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1378 ::osl::MutexGuard aInternalGuard(GetMutex());
1379 ::TextSelection const & rSelection = m_rView.GetSelection();
1380 Paragraphs::size_type nNumber = pParagraph->getNumber();
1381 TextPaM aEndPaM( rSelection.GetEnd() );
1383 return aEndPaM.GetPara() == nNumber
1384 ? m_rView.GetLineNumberOfCursorInSelection() : -1;
1388 ::css::uno::Reference< ::css::accessibility::XAccessibleRelationSet >
1389 Document::retrieveParagraphRelationSet( ParagraphImpl const * pParagraph )
1391 ::osl::MutexGuard aInternalGuard( GetMutex() );
1393 ::utl::AccessibleRelationSetHelper* pRelationSetHelper = new ::utl::AccessibleRelationSetHelper();
1394 ::css::uno::Reference< ::css::accessibility::XAccessibleRelationSet > xSet = pRelationSetHelper;
1396 Paragraphs::iterator aPara( m_xParagraphs->begin() + pParagraph->getNumber() );
1398 if ( aPara > m_aVisibleBegin && aPara < m_aVisibleEnd )
1400 ::css::uno::Sequence< ::css::uno::Reference< ::css::uno::XInterface > > aSequence(1);
1401 aSequence[0] = getAccessibleChild( aPara - 1 );
1402 ::css::accessibility::AccessibleRelation aRelation( ::css::accessibility::AccessibleRelationType::CONTENT_FLOWS_FROM, aSequence );
1403 pRelationSetHelper->AddRelation( aRelation );
1406 if ( aPara >= m_aVisibleBegin && aPara < m_aVisibleEnd -1 )
1408 ::css::uno::Sequence< ::css::uno::Reference< ::css::uno::XInterface > > aSequence(1);
1409 aSequence[0] = getAccessibleChild( aPara + 1 );
1410 ::css::accessibility::AccessibleRelation aRelation( ::css::accessibility::AccessibleRelationType::CONTENT_FLOWS_TO, aSequence );
1411 pRelationSetHelper->AddRelation( aRelation );
1414 return xSet;
1417 void Document::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
1419 switch ( rVclWindowEvent.GetId() )
1421 case VCLEVENT_WINDOW_GETFOCUS:
1422 case VCLEVENT_WINDOW_LOSEFOCUS:
1424 // #107179# if our parent is a compound control (e.g. MultiLineEdit),
1425 // suppress the window focus events here
1426 if ( !m_bCompoundControlChild )
1427 VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent );
1429 break;
1430 default:
1431 VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent );
1435 // virtual
1436 ::sal_Int32 SAL_CALL Document::getAccessibleChildCount()
1437 throw (::css::uno::RuntimeException)
1439 ::comphelper::OExternalLockGuard aGuard(this);
1440 init();
1441 return m_aVisibleEnd - m_aVisibleBegin;
1444 // virtual
1445 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL
1446 Document::getAccessibleChild(::sal_Int32 i)
1447 throw (::css::lang::IndexOutOfBoundsException,
1448 ::css::uno::RuntimeException)
1450 ::comphelper::OExternalLockGuard aGuard(this);
1451 init();
1452 if (i < 0 || i >= m_aVisibleEnd - m_aVisibleBegin)
1453 throw ::css::lang::IndexOutOfBoundsException(
1454 ::rtl::OUString(
1455 RTL_CONSTASCII_USTRINGPARAM(
1456 "textwindowaccessibility.cxx:"
1457 " Document::getAccessibleChild")),
1458 static_cast< ::css::uno::XWeak * >(this));
1459 return getAccessibleChild(m_aVisibleBegin
1460 + static_cast< Paragraphs::size_type >(i));
1463 // virtual
1464 ::sal_Int16 SAL_CALL Document::getAccessibleRole()
1465 throw (::css::uno::RuntimeException)
1467 return ::css::accessibility::AccessibleRole::TEXT_FRAME;
1470 // virtual
1471 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL
1472 Document::getAccessibleAtPoint(::css::awt::Point const & rPoint)
1473 throw (::css::uno::RuntimeException)
1475 ::comphelper::OExternalLockGuard aGuard(this);
1476 init();
1477 if (rPoint.X >= 0
1478 && rPoint.X < m_rView.GetWindow()->GetOutputSizePixel().Width()
1479 && rPoint.Y >= 0 && rPoint.Y < m_nViewHeight)
1481 ::sal_Int32 nOffset = m_nViewOffset + rPoint.Y; // XXX numeric overflow
1482 ::sal_Int32 nPos = m_nViewOffset - m_nVisibleBeginOffset;
1483 for (Paragraphs::iterator aIt(m_aVisibleBegin); aIt != m_aVisibleEnd;
1484 ++aIt)
1486 nPos += aIt->getHeight(); // XXX numeric overflow
1487 if (nOffset < nPos)
1488 return getAccessibleChild(aIt);
1491 return 0;
1494 // virtual
1495 void SAL_CALL Document::disposing()
1497 m_aEngineListener.endListening();
1498 m_aViewListener.endListening();
1499 if (m_xParagraphs.get() != 0)
1500 disposeParagraphs();
1501 VCLXAccessibleComponent::disposing();
1504 // virtual
1505 void Document::Notify(::SfxBroadcaster &, ::SfxHint const & rHint)
1507 if (rHint.ISA(::TextHint))
1509 ::TextHint const & rTextHint
1510 = static_cast< ::TextHint const & >(rHint);
1511 switch (rTextHint.GetId())
1513 case TEXT_HINT_PARAINSERTED:
1514 case TEXT_HINT_PARAREMOVED:
1515 // TEXT_HINT_PARAINSERTED and TEXT_HINT_PARAREMOVED are sent at
1516 // "unsafe" times (when the text engine has not yet re-formatted its
1517 // content), so that for example calling ::TextEngine::GetTextHeight
1518 // from within the code that handles TEXT_HINT_PARAINSERTED causes
1519 // trouble within the text engine. Therefore, these hints are just
1520 // buffered until a following ::TextEngine::FormatDoc causes a
1521 // TEXT_HINT_TEXTFORMATTED to come in:
1522 case TEXT_HINT_FORMATPARA:
1523 // ::TextEngine::FormatDoc sends a sequence of
1524 // TEXT_HINT_FORMATPARAs, followed by an optional
1525 // TEXT_HINT_TEXTHEIGHTCHANGED, followed in all cases by one
1526 // TEXT_HINT_TEXTFORMATTED. Only the TEXT_HINT_FORMATPARAs contain
1527 // the the numbers of the affected paragraphs, but they are sent
1528 // before the changes are applied. Therefore, TEXT_HINT_FORMATPARAs
1529 // are just buffered until another hint comes in:
1531 ::osl::MutexGuard aInternalGuard(GetMutex());
1532 if (!isAlive())
1533 break;
1535 m_aParagraphNotifications.push(rTextHint);
1536 break;
1538 case TEXT_HINT_TEXTFORMATTED:
1539 case TEXT_HINT_TEXTHEIGHTCHANGED:
1540 case TEXT_HINT_MODIFIED:
1542 ::osl::MutexGuard aInternalGuard(GetMutex());
1543 if (!isAlive())
1544 break;
1545 handleParagraphNotifications();
1546 break;
1548 case TEXT_HINT_VIEWSCROLLED:
1550 ::osl::MutexGuard aInternalGuard(GetMutex());
1551 if (!isAlive())
1552 break;
1553 handleParagraphNotifications();
1555 ::sal_Int32 nOffset = static_cast< ::sal_Int32 >(
1556 m_rView.GetStartDocPos().Y());
1557 // XXX numeric overflow
1558 if (nOffset != m_nViewOffset)
1560 m_nViewOffset = nOffset;
1562 Paragraphs::iterator aOldVisibleBegin(
1563 m_aVisibleBegin);
1564 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd);
1566 determineVisibleRange();
1568 notifyVisibleRangeChanges(aOldVisibleBegin,
1569 aOldVisibleEnd,
1570 m_xParagraphs->end());
1572 break;
1574 case TEXT_HINT_VIEWSELECTIONCHANGED:
1576 ::osl::MutexGuard aInternalGuard(GetMutex());
1577 if (!isAlive())
1578 break;
1580 if (m_aParagraphNotifications.empty())
1582 handleSelectionChangeNotification();
1584 else
1586 // TEXT_HINT_VIEWSELECTIONCHANGED is sometimes sent at
1587 // "unsafe" times (when the text engine has not yet re-
1588 // formatted its content), so that for example calling
1589 // ::TextEngine::GetTextHeight from within the code that
1590 // handles a previous TEXT_HINT_PARAINSERTED causes
1591 // trouble within the text engine. Therefore, these
1592 // hints are just buffered (along with
1593 // TEXT_HINT_PARAINSERTED/REMOVED/FORMATPARA) until a
1594 // following ::TextEngine::FormatDoc causes a
1595 // TEXT_HINT_TEXTFORMATTED to come in:
1596 m_bSelectionChangedNotification = true;
1598 break;
1604 IMPL_LINK(Document, WindowEventHandler, ::VclSimpleEvent *, pEvent)
1606 switch (pEvent->GetId())
1608 case VCLEVENT_WINDOW_RESIZE:
1610 ::osl::MutexGuard aInternalGuard(GetMutex());
1611 if (!isAlive())
1612 break;
1614 ::sal_Int32 nHeight = static_cast< ::sal_Int32 >(
1615 m_rView.GetWindow()->GetOutputSizePixel().Height());
1616 // XXX numeric overflow
1617 if (nHeight != m_nViewHeight)
1619 m_nViewHeight = nHeight;
1621 Paragraphs::iterator aOldVisibleBegin(m_aVisibleBegin);
1622 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd);
1624 determineVisibleRange();
1626 notifyVisibleRangeChanges(aOldVisibleBegin, aOldVisibleEnd,
1627 m_xParagraphs->end());
1629 break;
1631 case VCLEVENT_WINDOW_GETFOCUS:
1633 ::osl::MutexGuard aInternalGuard(GetMutex());
1634 if (!isAlive())
1635 break;
1637 if (m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd)
1639 ::rtl::Reference< ParagraphImpl > xParagraph(
1640 getParagraph(m_aFocused));
1641 if (xParagraph.is())
1642 xParagraph->notifyEvent(
1643 ::css::accessibility::AccessibleEventId::
1644 STATE_CHANGED,
1645 ::css::uno::Any(),
1646 ::css::uno::makeAny(
1647 ::css::accessibility::AccessibleStateType::
1648 FOCUSED));
1650 break;
1652 case VCLEVENT_WINDOW_LOSEFOCUS:
1654 ::osl::MutexGuard aInternalGuard(GetMutex());
1655 if (!isAlive())
1656 break;
1658 if (m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd)
1660 ::rtl::Reference< ParagraphImpl > xParagraph(
1661 getParagraph(m_aFocused));
1662 if (xParagraph.is())
1663 xParagraph->notifyEvent(
1664 ::css::accessibility::AccessibleEventId::
1665 STATE_CHANGED,
1666 ::css::uno::makeAny(
1667 ::css::accessibility::AccessibleStateType::
1668 FOCUSED),
1669 ::css::uno::Any());
1671 break;
1674 return 0;
1677 void Document::init()
1679 if (m_xParagraphs.get() == 0)
1681 ::ULONG nCount = m_rEngine.GetParagraphCount();
1682 ::std::auto_ptr< Paragraphs > p(new Paragraphs);
1683 p->reserve(static_cast< Paragraphs::size_type >(nCount));
1684 // numeric overflow is harmless here
1685 for (::ULONG i = 0; i < nCount; ++i)
1686 p->push_back(ParagraphInfo(static_cast< ::sal_Int32 >(
1687 m_rEngine.GetTextHeight(i))));
1688 // XXX numeric overflow
1689 m_nViewOffset = static_cast< ::sal_Int32 >(
1690 m_rView.GetStartDocPos().Y()); // XXX numeric overflow
1691 m_nViewHeight = static_cast< ::sal_Int32 >(
1692 m_rView.GetWindow()->GetOutputSizePixel().Height());
1693 // XXX numeric overflow
1694 m_xParagraphs = p;
1695 determineVisibleRange();
1696 m_nSelectionFirstPara = -1;
1697 m_nSelectionFirstPos = -1;
1698 m_nSelectionLastPara = -1;
1699 m_nSelectionLastPos = -1;
1700 m_aFocused = m_xParagraphs->end();
1701 m_bSelectionChangedNotification = false;
1702 m_aEngineListener.startListening(m_rEngine);
1703 m_aViewListener.startListening(*m_rView.GetWindow());
1707 ::rtl::Reference< ParagraphImpl >
1708 Document::getParagraph(Paragraphs::iterator const & rIt)
1710 return static_cast< ParagraphImpl * >(
1711 ::css::uno::Reference< ::css::accessibility::XAccessible >(
1712 rIt->getParagraph()).get());
1715 ::css::uno::Reference< ::css::accessibility::XAccessible >
1716 Document::getAccessibleChild(Paragraphs::iterator const & rIt)
1718 ::css::uno::Reference< ::css::accessibility::XAccessible > xParagraph(
1719 rIt->getParagraph());
1720 if (!xParagraph.is())
1722 xParagraph = new Paragraph(this, rIt - m_xParagraphs->begin());
1723 rIt->setParagraph(xParagraph);
1725 return xParagraph;
1728 void Document::determineVisibleRange()
1730 m_aVisibleBegin = m_xParagraphs->end();
1731 m_aVisibleEnd = m_aVisibleBegin;
1732 ::sal_Int32 nPos = 0;
1733 for (Paragraphs::iterator aIt = m_xParagraphs->begin();;)
1735 if (aIt == m_xParagraphs->end())
1737 m_nVisibleBeginOffset = 0;
1738 break;
1740 ::sal_Int32 nOldPos = nPos;
1741 nPos += aIt->getHeight(); // XXX numeric overflow
1742 if (m_aVisibleBegin == m_xParagraphs->end() && nPos >= m_nViewOffset)
1744 m_aVisibleBegin = aIt;
1745 m_nVisibleBeginOffset = m_nViewOffset - nOldPos;
1747 ++aIt;
1748 if (m_aVisibleBegin != m_xParagraphs->end()
1749 && (aIt == m_xParagraphs->end()
1750 || nPos >= m_nViewOffset + m_nViewHeight))
1751 // XXX numeric overflow
1753 m_aVisibleEnd = aIt;
1754 break;
1759 void Document::notifyVisibleRangeChanges(
1760 Paragraphs::iterator const & rOldVisibleBegin,
1761 Paragraphs::iterator const & rOldVisibleEnd,
1762 Paragraphs::iterator const & rInserted)
1764 // XXX Replace this code that determines which paragraphs have changed from
1765 // invisible to visible or vice versa with a better algorithm.
1766 {for (Paragraphs::iterator aIt(rOldVisibleBegin); aIt != rOldVisibleEnd;
1767 ++aIt)
1768 if (aIt != rInserted
1769 && (aIt < m_aVisibleBegin || aIt >= m_aVisibleEnd))
1770 NotifyAccessibleEvent(
1771 ::css::accessibility::AccessibleEventId::
1772 CHILD,
1773 ::css::uno::makeAny(getAccessibleChild(aIt)),
1774 ::css::uno::Any());
1776 {for (Paragraphs::iterator aIt(m_aVisibleBegin); aIt != m_aVisibleEnd;
1777 ++aIt)
1778 if (aIt == rInserted
1779 || aIt < rOldVisibleBegin || aIt >= rOldVisibleEnd)
1780 NotifyAccessibleEvent(
1781 ::css::accessibility::AccessibleEventId::
1782 CHILD,
1783 ::css::uno::Any(),
1784 ::css::uno::makeAny(getAccessibleChild(aIt)));
1788 void
1789 Document::changeParagraphText(::ULONG nNumber, ::USHORT nBegin, ::USHORT nEnd,
1790 bool bCut, bool bPaste,
1791 ::rtl::OUString const & rText)
1793 m_rView.SetSelection(::TextSelection(::TextPaM(nNumber, nBegin),
1794 ::TextPaM(nNumber, nEnd)));
1795 if (bCut)
1796 m_rView.Cut();
1797 else if (nBegin != nEnd)
1798 m_rView.DeleteSelected();
1799 if (bPaste)
1800 m_rView.Paste();
1801 else if (rText.getLength() != 0)
1802 m_rView.InsertText(rText);
1805 void Document::handleParagraphNotifications()
1807 while (!m_aParagraphNotifications.empty())
1809 ::TextHint aHint(m_aParagraphNotifications.front());
1810 m_aParagraphNotifications.pop();
1811 switch (aHint.GetId())
1813 case TEXT_HINT_PARAINSERTED:
1815 ::ULONG n = aHint.GetValue();
1816 OSL_ENSURE(n <= m_xParagraphs->size(),
1817 "bad TEXT_HINT_PARAINSERTED event");
1819 // Save the values of old iterators (the iterators themselves
1820 // will get invalidated), and adjust the old values so that they
1821 // reflect the insertion of the new paragraph:
1822 Paragraphs::size_type nOldVisibleBegin
1823 = m_aVisibleBegin - m_xParagraphs->begin();
1824 Paragraphs::size_type nOldVisibleEnd
1825 = m_aVisibleEnd - m_xParagraphs->begin();
1826 Paragraphs::size_type nOldFocused
1827 = m_aFocused - m_xParagraphs->begin();
1828 if (n <= nOldVisibleBegin)
1829 ++nOldVisibleBegin; // XXX numeric overflow
1830 if (n <= nOldVisibleEnd)
1831 ++nOldVisibleEnd; // XXX numeric overflow
1832 if (n <= nOldFocused)
1833 ++nOldFocused; // XXX numeric overflow
1834 if (sal::static_int_cast<sal_Int32>(n) <= m_nSelectionFirstPara)
1835 ++m_nSelectionFirstPara; // XXX numeric overflow
1836 if (sal::static_int_cast<sal_Int32>(n) <= m_nSelectionLastPara)
1837 ++m_nSelectionLastPara; // XXX numeric overflow
1839 Paragraphs::iterator aIns(
1840 m_xParagraphs->insert(
1841 m_xParagraphs->begin() + n,
1842 ParagraphInfo(static_cast< ::sal_Int32 >(
1843 m_rEngine.GetTextHeight(n)))));
1844 // XXX numeric overflow (2x)
1846 determineVisibleRange();
1847 m_aFocused = m_xParagraphs->begin() + nOldFocused;
1849 for (Paragraphs::iterator aIt(aIns);;)
1851 ++aIt;
1852 if (aIt == m_xParagraphs->end())
1853 break;
1854 ::rtl::Reference< ParagraphImpl > xParagraph(
1855 getParagraph(aIt));
1856 if (xParagraph.is())
1857 xParagraph->numberChanged(true);
1860 notifyVisibleRangeChanges(
1861 m_xParagraphs->begin() + nOldVisibleBegin,
1862 m_xParagraphs->begin() + nOldVisibleEnd, aIns);
1863 break;
1865 case TEXT_HINT_PARAREMOVED:
1867 ::ULONG n = aHint.GetValue();
1868 if (n == TEXT_PARA_ALL)
1870 {for (Paragraphs::iterator aIt(m_aVisibleBegin);
1871 aIt != m_aVisibleEnd; ++aIt)
1872 NotifyAccessibleEvent(
1873 ::css::accessibility::AccessibleEventId::
1874 CHILD,
1875 ::css::uno::makeAny(getAccessibleChild(aIt)),
1876 ::css::uno::Any());
1878 disposeParagraphs();
1879 m_xParagraphs->clear();
1880 determineVisibleRange();
1881 m_nSelectionFirstPara = -1;
1882 m_nSelectionFirstPos = -1;
1883 m_nSelectionLastPara = -1;
1884 m_nSelectionLastPos = -1;
1885 m_aFocused = m_xParagraphs->end();
1887 else
1889 OSL_ENSURE(n < m_xParagraphs->size(),
1890 "Bad TEXT_HINT_PARAREMOVED event");
1892 Paragraphs::iterator aIt(m_xParagraphs->begin() + n);
1893 // numeric overflow cannot occur
1895 // Save the values of old iterators (the iterators
1896 // themselves will get invalidated), and adjust the old
1897 // values so that they reflect the removal of the paragraph:
1898 Paragraphs::size_type nOldVisibleBegin
1899 = m_aVisibleBegin - m_xParagraphs->begin();
1900 Paragraphs::size_type nOldVisibleEnd
1901 = m_aVisibleEnd - m_xParagraphs->begin();
1902 bool bWasVisible
1903 = nOldVisibleBegin <= n && n < nOldVisibleEnd;
1904 Paragraphs::size_type nOldFocused
1905 = m_aFocused - m_xParagraphs->begin();
1906 bool bWasFocused = aIt == m_aFocused;
1907 if (n < nOldVisibleBegin)
1908 --nOldVisibleBegin;
1909 if (n < nOldVisibleEnd)
1910 --nOldVisibleEnd;
1911 if (n < nOldFocused)
1912 --nOldFocused;
1913 if (sal::static_int_cast<sal_Int32>(n) < m_nSelectionFirstPara)
1914 --m_nSelectionFirstPara;
1915 else if (sal::static_int_cast<sal_Int32>(n) == m_nSelectionFirstPara)
1917 if (m_nSelectionFirstPara == m_nSelectionLastPara)
1919 m_nSelectionFirstPara = -1;
1920 m_nSelectionFirstPos = -1;
1921 m_nSelectionLastPara = -1;
1922 m_nSelectionLastPos = -1;
1924 else
1926 ++m_nSelectionFirstPara;
1927 m_nSelectionFirstPos = 0;
1930 if (sal::static_int_cast<sal_Int32>(n) < m_nSelectionLastPara)
1931 --m_nSelectionLastPara;
1932 else if (sal::static_int_cast<sal_Int32>(n) == m_nSelectionLastPara)
1934 OSL_ENSURE(m_nSelectionFirstPara < m_nSelectionLastPara,
1935 "logic error");
1936 --m_nSelectionLastPara;
1937 m_nSelectionLastPos = 0x7FFFFFFF;
1940 ::css::uno::Reference< ::css::accessibility::XAccessible >
1941 xStrong;
1942 if (bWasVisible)
1943 xStrong = getAccessibleChild(aIt);
1944 ::css::uno::WeakReference<
1945 ::css::accessibility::XAccessible > xWeak(
1946 aIt->getParagraph());
1947 aIt = m_xParagraphs->erase(aIt);
1949 determineVisibleRange();
1950 m_aFocused = bWasFocused ? m_xParagraphs->end()
1951 : m_xParagraphs->begin() + nOldFocused;
1953 for (; aIt != m_xParagraphs->end(); ++aIt)
1955 ::rtl::Reference< ParagraphImpl > xParagraph(
1956 getParagraph(aIt));
1957 if (xParagraph.is())
1958 xParagraph->numberChanged(false);
1961 if (bWasVisible)
1962 NotifyAccessibleEvent(
1963 ::css::accessibility::AccessibleEventId::
1964 CHILD,
1965 ::css::uno::makeAny(getAccessibleChild(aIt)),
1966 ::css::uno::Any());
1968 ::css::uno::Reference< ::css::lang::XComponent > xComponent(
1969 xWeak.get(), ::css::uno::UNO_QUERY);
1970 if (xComponent.is())
1971 xComponent->dispose();
1973 notifyVisibleRangeChanges(
1974 m_xParagraphs->begin() + nOldVisibleBegin,
1975 m_xParagraphs->begin() + nOldVisibleEnd,
1976 m_xParagraphs->end());
1978 break;
1980 case TEXT_HINT_FORMATPARA:
1982 ::ULONG n = aHint.GetValue();
1983 OSL_ENSURE(n < m_xParagraphs->size(),
1984 "Bad TEXT_HINT_FORMATPARA event");
1986 (*m_xParagraphs)[static_cast< Paragraphs::size_type >(n)].
1987 changeHeight(static_cast< ::sal_Int32 >(
1988 m_rEngine.GetTextHeight(n)));
1989 // XXX numeric overflow
1990 Paragraphs::iterator aOldVisibleBegin(m_aVisibleBegin);
1991 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd);
1992 determineVisibleRange();
1993 notifyVisibleRangeChanges(aOldVisibleBegin, aOldVisibleEnd,
1994 m_xParagraphs->end());
1995 Paragraphs::iterator aIt(m_xParagraphs->begin() + n);
1996 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt));
1997 if (xParagraph.is())
1998 xParagraph->textChanged();
1999 break;
2001 default:
2002 OSL_ENSURE(false, "bad buffered hint");
2003 break;
2006 if (m_bSelectionChangedNotification)
2008 m_bSelectionChangedNotification = false;
2009 handleSelectionChangeNotification();
2013 void Document::handleSelectionChangeNotification()
2015 ::TextSelection const & rSelection = m_rView.GetSelection();
2016 OSL_ENSURE(rSelection.GetStart().GetPara() < m_xParagraphs->size()
2017 && rSelection.GetEnd().GetPara() < m_xParagraphs->size(),
2018 "bad TEXT_HINT_VIEWSELECTIONCHANGED event");
2019 ::sal_Int32 nNewFirstPara
2020 = static_cast< ::sal_Int32 >(rSelection.GetStart().GetPara());
2021 ::sal_Int32 nNewFirstPos
2022 = static_cast< ::sal_Int32 >(rSelection.GetStart().GetIndex());
2023 // XXX numeric overflow
2024 ::sal_Int32 nNewLastPara
2025 = static_cast< ::sal_Int32 >(rSelection.GetEnd().GetPara());
2026 ::sal_Int32 nNewLastPos
2027 = static_cast< ::sal_Int32 >(rSelection.GetEnd().GetIndex());
2028 // XXX numeric overflow
2030 // Lose focus:
2031 Paragraphs::iterator aIt(m_xParagraphs->begin() + nNewLastPara);
2032 if (m_aFocused != m_xParagraphs->end() && m_aFocused != aIt
2033 && m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd)
2035 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(m_aFocused));
2036 if (xParagraph.is())
2037 xParagraph->notifyEvent(
2038 ::css::accessibility::AccessibleEventId::
2039 STATE_CHANGED,
2040 ::css::uno::makeAny(
2041 ::css::accessibility::AccessibleStateType::FOCUSED),
2042 ::css::uno::Any());
2045 // Gain focus and update cursor position:
2046 if (aIt >= m_aVisibleBegin && aIt < m_aVisibleEnd
2047 && (aIt != m_aFocused
2048 || nNewLastPara != m_nSelectionLastPara
2049 || nNewLastPos != m_nSelectionLastPos))
2051 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt));
2052 if (xParagraph.is())
2054 if (aIt != m_aFocused)
2055 xParagraph->notifyEvent(
2056 ::css::accessibility::AccessibleEventId::
2057 STATE_CHANGED,
2058 ::css::uno::Any(),
2059 ::css::uno::makeAny(
2060 ::css::accessibility::AccessibleStateType::FOCUSED));
2061 if (nNewLastPara != m_nSelectionLastPara
2062 || nNewLastPos != m_nSelectionLastPos)
2063 xParagraph->notifyEvent(
2064 ::css::accessibility::AccessibleEventId::
2065 CARET_CHANGED,
2066 ::css::uno::makeAny< ::sal_Int32 >(
2067 nNewLastPara == m_nSelectionLastPara
2068 ? m_nSelectionLastPos : 0),
2069 ::css::uno::makeAny(nNewLastPos));
2072 m_aFocused = aIt;
2074 // Update both old and new selection. (Regardless of how the two selections
2075 // look like, there will always be two ranges to the left and right of the
2076 // overlap---the overlap and/or the range to the right of it possibly being
2077 // empty. Only for these two ranges notifications have to be sent.)
2079 TextPaM aOldTextStart( static_cast< ULONG >( m_nSelectionFirstPara ), static_cast< USHORT >( m_nSelectionFirstPos ) );
2080 TextPaM aOldTextEnd( static_cast< ULONG >( m_nSelectionLastPara ), static_cast< USHORT >( m_nSelectionLastPos ) );
2081 TextPaM aNewTextStart( static_cast< ULONG >( nNewFirstPara ), static_cast< USHORT >( nNewFirstPos ) );
2082 TextPaM aNewTextEnd( static_cast< ULONG >( nNewLastPara ), static_cast< USHORT >( nNewLastPos ) );
2084 // justify selections
2085 justifySelection( aOldTextStart, aOldTextEnd );
2086 justifySelection( aNewTextStart, aNewTextEnd );
2088 sal_Int32 nFirst1;
2089 sal_Int32 nLast1;
2090 sal_Int32 nFirst2;
2091 sal_Int32 nLast2;
2093 if ( m_nSelectionFirstPara == -1 )
2095 // old selection not initialized yet => notify events only for new selection (if not empty)
2096 nFirst1 = aNewTextStart.GetPara();
2097 nLast1 = aNewTextEnd.GetPara() + ( aNewTextStart != aNewTextEnd ? 1 : 0 );
2098 nFirst2 = 0;
2099 nLast2 = 0;
2101 else if ( aOldTextStart == aOldTextEnd && aNewTextStart == aNewTextEnd )
2103 // old an new selection empty => no events
2104 nFirst1 = 0;
2105 nLast1 = 0;
2106 nFirst2 = 0;
2107 nLast2 = 0;
2109 else if ( aOldTextStart != aOldTextEnd && aNewTextStart == aNewTextEnd )
2111 // old selection not empty + new selection empty => notify events only for old selection
2112 nFirst1 = aOldTextStart.GetPara();
2113 nLast1 = aOldTextEnd.GetPara() + 1;
2114 nFirst2 = 0;
2115 nLast2 = 0;
2117 else if ( aOldTextStart == aOldTextEnd && aNewTextStart != aNewTextEnd )
2119 // old selection empty + new selection not empty => notify events only for new selection
2120 nFirst1 = aNewTextStart.GetPara();
2121 nLast1 = aNewTextEnd.GetPara() + 1;
2122 nFirst2 = 0;
2123 nLast2 = 0;
2125 else
2127 // old and new selection not empty => notify events for the two ranges left and right of the overlap
2128 ::std::vector< TextPaM > aTextPaMs(4);
2129 aTextPaMs[0] = aOldTextStart;
2130 aTextPaMs[1] = aOldTextEnd;
2131 aTextPaMs[2] = aNewTextStart;
2132 aTextPaMs[3] = aNewTextEnd;
2133 ::std::sort( aTextPaMs.begin(), aTextPaMs.end() );
2135 nFirst1 = aTextPaMs[0].GetPara();
2136 nLast1 = aTextPaMs[1].GetPara() + ( aTextPaMs[0] != aTextPaMs[1] ? 1 : 0 );
2138 nFirst2 = aTextPaMs[2].GetPara();
2139 nLast2 = aTextPaMs[3].GetPara() + ( aTextPaMs[2] != aTextPaMs[3] ? 1 : 0 );
2141 // adjust overlapping ranges
2142 if ( nLast1 > nFirst2 )
2143 nLast1 = nFirst2;
2146 // notify selection changes
2147 notifySelectionChange( nFirst1, nLast1 );
2148 notifySelectionChange( nFirst2, nLast2 );
2150 m_nSelectionFirstPara = nNewFirstPara;
2151 m_nSelectionFirstPos = nNewFirstPos;
2152 m_nSelectionLastPara = nNewLastPara;
2153 m_nSelectionLastPos = nNewLastPos;
2156 void Document::notifySelectionChange( sal_Int32 nFirst, sal_Int32 nLast )
2158 if ( nFirst < nLast )
2160 Paragraphs::iterator aEnd( ::std::min( m_xParagraphs->begin() + nLast, m_aVisibleEnd ) );
2161 for ( Paragraphs::iterator aIt = ::std::max( m_xParagraphs->begin() + nFirst, m_aVisibleBegin ); aIt < aEnd; ++aIt )
2163 ::rtl::Reference< ParagraphImpl > xParagraph( getParagraph( aIt ) );
2164 if ( xParagraph.is() )
2166 xParagraph->notifyEvent(
2167 ::css::accessibility::AccessibleEventId::SELECTION_CHANGED,
2168 ::css::uno::Any(), ::css::uno::Any() );
2169 xParagraph->notifyEvent(
2170 ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED,
2171 ::css::uno::Any(), ::css::uno::Any() );
2177 void Document::justifySelection( TextPaM& rTextStart, TextPaM& rTextEnd )
2179 if ( rTextStart > rTextEnd )
2181 TextPaM aTextPaM( rTextStart );
2182 rTextStart = rTextEnd;
2183 rTextEnd = aTextPaM;
2187 void Document::disposeParagraphs()
2189 for (Paragraphs::iterator aIt(m_xParagraphs->begin());
2190 aIt != m_xParagraphs->end(); ++aIt)
2192 ::css::uno::Reference< ::css::lang::XComponent > xComponent(
2193 aIt->getParagraph().get(), ::css::uno::UNO_QUERY);
2194 if (xComponent.is())
2195 xComponent->dispose();
2199 // static
2200 ::css::uno::Any Document::mapFontColor(::Color const & rColor)
2202 return ::css::uno::makeAny(
2203 static_cast< ::sal_Int32 >(COLORDATA_RGB(rColor.GetColor())));
2204 // FIXME keep transparency?
2207 // static
2208 ::Color Document::mapFontColor(::css::uno::Any const & rColor)
2210 ::sal_Int32 nColor = 0;
2211 rColor >>= nColor;
2212 return ::Color(static_cast< ::ColorData >(nColor));
2215 // static
2216 ::css::uno::Any Document::mapFontWeight(::FontWeight nWeight)
2218 // Map from ::FontWeight to ::css:awt::FontWeight, depends on order of
2219 // elements in ::FontWeight (vcl/vclenum.hxx):
2220 static float const aWeight[]
2221 = { ::css::awt::FontWeight::DONTKNOW, // WEIGHT_DONTKNOW
2222 ::css::awt::FontWeight::THIN, // WEIGHT_THIN
2223 ::css::awt::FontWeight::ULTRALIGHT, // WEIGHT_ULTRALIGHT
2224 ::css::awt::FontWeight::LIGHT, // WEIGHT_LIGHT
2225 ::css::awt::FontWeight::SEMILIGHT, // WEIGHT_SEMILIGHT
2226 ::css::awt::FontWeight::NORMAL, // WEIGHT_NORMAL
2227 ::css::awt::FontWeight::NORMAL, // WEIGHT_MEDIUM
2228 ::css::awt::FontWeight::SEMIBOLD, // WEIGHT_SEMIBOLD
2229 ::css::awt::FontWeight::BOLD, // WEIGHT_BOLD
2230 ::css::awt::FontWeight::ULTRABOLD, // WEIGHT_ULTRABOLD
2231 ::css::awt::FontWeight::BLACK }; // WEIGHT_BLACK
2232 return ::css::uno::makeAny(aWeight[nWeight]);
2235 // static
2236 ::FontWeight Document::mapFontWeight(::css::uno::Any const & rWeight)
2238 float nWeight = ::css::awt::FontWeight::NORMAL;
2239 rWeight >>= nWeight;
2240 return nWeight <= ::css::awt::FontWeight::DONTKNOW ? WEIGHT_DONTKNOW
2241 : nWeight <= ::css::awt::FontWeight::THIN ? WEIGHT_THIN
2242 : nWeight <= ::css::awt::FontWeight::ULTRALIGHT ? WEIGHT_ULTRALIGHT
2243 : nWeight <= ::css::awt::FontWeight::LIGHT ? WEIGHT_LIGHT
2244 : nWeight <= ::css::awt::FontWeight::SEMILIGHT ? WEIGHT_SEMILIGHT
2245 : nWeight <= ::css::awt::FontWeight::NORMAL ? WEIGHT_NORMAL
2246 : nWeight <= ::css::awt::FontWeight::SEMIBOLD ? WEIGHT_SEMIBOLD
2247 : nWeight <= ::css::awt::FontWeight::BOLD ? WEIGHT_BOLD
2248 : nWeight <= ::css::awt::FontWeight::ULTRABOLD ? WEIGHT_ULTRABOLD
2249 : WEIGHT_BLACK;