1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <accessibility/textwindowaccessibility.hxx>
24 #include <sal/log.hxx>
26 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
27 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
28 #include <com/sun/star/accessibility/AccessibleRole.hpp>
29 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
30 #include <com/sun/star/awt/FontWeight.hpp>
31 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
32 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
33 #include <com/sun/star/i18n/Boundary.hpp>
34 #include <cppuhelper/exc_hlp.hxx>
35 #include <comphelper/accessiblecontexthelper.hxx>
36 #include <comphelper/accessibleeventnotifier.hxx>
37 #include <o3tl/safeint.hxx>
38 #include <unotools/accessiblerelationsethelper.hxx>
40 #include <vcl/svapp.hxx>
41 #include <vcl/txtattr.hxx>
42 #include <vcl/unohelp.hxx>
43 #include <vcl/window.hxx>
44 #include <comphelper/diagnose_ex.hxx>
45 #include <comphelper/sequence.hxx>
51 namespace accessibility
53 void SfxListenerGuard::startListening(::SfxBroadcaster
& rNotifier
)
55 assert(m_pNotifier
== nullptr && "called more than once");
56 m_pNotifier
= &rNotifier
;
57 m_rListener
.StartListening(*m_pNotifier
, DuplicateHandling::Prevent
);
60 void SfxListenerGuard::endListening()
62 if (m_pNotifier
!= nullptr)
64 m_rListener
.EndListening(*m_pNotifier
);
65 m_pNotifier
= nullptr;
69 void WindowListenerGuard::startListening(vcl::Window
& rNotifier
)
71 assert(m_pNotifier
== nullptr && "called more than once");
72 m_pNotifier
= &rNotifier
;
73 m_pNotifier
->AddEventListener(m_aListener
);
76 void WindowListenerGuard::endListening()
80 m_pNotifier
->RemoveEventListener(m_aListener
);
81 m_pNotifier
= nullptr;
85 Paragraph::Paragraph(::rtl::Reference
< Document
> xDocument
,
86 Paragraphs::size_type nNumber
):
87 ParagraphBase(m_aMutex
),
88 m_xDocument(std::move(xDocument
)),
92 m_aParagraphText
= m_xDocument
->retrieveParagraphText(this);
96 Paragraph::numberChanged(bool bIncremented
)
104 void Paragraph::textChanged()
106 OUString aParagraphText
= implGetText();
107 css::uno::Any aOldValue
, aNewValue
;
108 if ( implInitTextChangedEvent( m_aParagraphText
, aParagraphText
, aOldValue
, aNewValue
) )
110 m_aParagraphText
= aParagraphText
;
111 notifyEvent(css::accessibility::AccessibleEventId::
113 aOldValue
, aNewValue
);
117 void Paragraph::notifyEvent(::sal_Int16 nEventId
,
118 css::uno::Any
const & rOldValue
,
119 css::uno::Any
const & rNewValue
)
122 comphelper::AccessibleEventNotifier::addEvent( m_nClientId
, css::accessibility::AccessibleEventObject(
124 nEventId
, rNewValue
, rOldValue
, -1) );
128 css::uno::Reference
< css::accessibility::XAccessibleContext
> SAL_CALL
129 Paragraph::getAccessibleContext()
136 sal_Int64 SAL_CALL
Paragraph::getAccessibleChildCount()
143 css::uno::Reference
< css::accessibility::XAccessible
> SAL_CALL
144 Paragraph::getAccessibleChild(sal_Int64
)
147 throw css::lang::IndexOutOfBoundsException(
148 u
"textwindowaccessibility.cxx:"
149 " Paragraph::getAccessibleChild"_ustr
,
154 css::uno::Reference
< css::accessibility::XAccessible
> SAL_CALL
155 Paragraph::getAccessibleParent()
158 return m_xDocument
->getAccessible();
162 sal_Int64 SAL_CALL
Paragraph::getAccessibleIndexInParent()
165 return m_xDocument
->retrieveParagraphIndex(this);
169 ::sal_Int16 SAL_CALL
Paragraph::getAccessibleRole()
172 return css::accessibility::AccessibleRole::PARAGRAPH
;
176 OUString SAL_CALL
Paragraph::getAccessibleDescription()
183 OUString SAL_CALL
Paragraph::getAccessibleName()
190 css::uno::Reference
< css::accessibility::XAccessibleRelationSet
>
191 SAL_CALL
Paragraph::getAccessibleRelationSet()
194 return m_xDocument
->retrieveParagraphRelationSet( this );
198 sal_Int64 SAL_CALL
Paragraph::getAccessibleStateSet()
202 // FIXME Notification of changes (STATE_CHANGED) missing when
203 // m_rView.IsReadOnly() changes:
204 return m_xDocument
->retrieveParagraphState(this);
208 css::lang::Locale SAL_CALL
Paragraph::getLocale()
211 return m_xDocument
->retrieveLocale();
215 sal_Bool SAL_CALL
Paragraph::containsPoint(css::awt::Point
const & rPoint
)
218 css::awt::Rectangle
aRect(m_xDocument
->retrieveParagraphBounds(this,
220 return rPoint
.X
>= 0 && rPoint
.X
< aRect
.Width
221 && rPoint
.Y
>= 0 && rPoint
.Y
< aRect
.Height
;
225 css::uno::Reference
< css::accessibility::XAccessible
> SAL_CALL
226 Paragraph::getAccessibleAtPoint(css::awt::Point
const &)
233 css::awt::Rectangle SAL_CALL
Paragraph::getBounds()
236 return m_xDocument
->retrieveParagraphBounds(this, false);
240 css::awt::Point SAL_CALL
Paragraph::getLocation()
243 css::awt::Rectangle
aRect(m_xDocument
->retrieveParagraphBounds(this,
245 return css::awt::Point(aRect
.X
, aRect
.Y
);
249 css::awt::Point SAL_CALL
Paragraph::getLocationOnScreen()
252 css::awt::Rectangle
aRect(m_xDocument
->retrieveParagraphBounds(this,
254 return css::awt::Point(aRect
.X
, aRect
.Y
);
258 css::awt::Size SAL_CALL
Paragraph::getSize()
261 css::awt::Rectangle
aRect(m_xDocument
->retrieveParagraphBounds(this,
263 return css::awt::Size(aRect
.Width
, aRect
.Height
);
267 void SAL_CALL
Paragraph::grabFocus()
270 VclPtr
<vcl::Window
> pWindow
= m_xDocument
->GetWindow();
273 pWindow
->GrabFocus();
277 m_xDocument
->changeParagraphSelection(this, 0, 0);
279 catch (const css::lang::IndexOutOfBoundsException
&)
281 TOOLS_INFO_EXCEPTION("accessibility", "Paragraph::grabFocus: caught unexpected");
286 sal_Int32 SAL_CALL
Paragraph::getForeground()
292 sal_Int32 SAL_CALL
Paragraph::getBackground()
298 ::sal_Int32 SAL_CALL
Paragraph::getCaretPosition()
301 return m_xDocument
->retrieveParagraphCaretPosition(this);
305 sal_Bool SAL_CALL
Paragraph::setCaretPosition(::sal_Int32 nIndex
)
308 m_xDocument
->changeParagraphSelection(this, nIndex
, nIndex
);
313 ::sal_Unicode SAL_CALL
Paragraph::getCharacter(::sal_Int32 nIndex
)
316 return OCommonAccessibleText::implGetCharacter(implGetText(), nIndex
);
320 css::uno::Sequence
< css::beans::PropertyValue
> SAL_CALL
321 Paragraph::getCharacterAttributes(::sal_Int32 nIndex
, const css::uno::Sequence
< OUString
>& aRequestedAttributes
)
324 return m_xDocument
->retrieveCharacterAttributes( this, nIndex
, aRequestedAttributes
);
328 css::awt::Rectangle SAL_CALL
329 Paragraph::getCharacterBounds(::sal_Int32 nIndex
)
332 css::awt::Rectangle
aBounds(m_xDocument
->retrieveCharacterBounds(this, nIndex
));
333 css::awt::Rectangle
aParaBounds(m_xDocument
->retrieveParagraphBounds(this, false));
334 aBounds
.X
-= aParaBounds
.X
;
335 aBounds
.Y
-= aParaBounds
.Y
;
340 ::sal_Int32 SAL_CALL
Paragraph::getCharacterCount()
343 return implGetText().getLength();
348 Paragraph::getIndexAtPoint(css::awt::Point
const & rPoint
)
351 css::awt::Point
aPoint(rPoint
);
352 css::awt::Rectangle
aParaBounds(m_xDocument
->retrieveParagraphBounds(this, false));
353 aPoint
.X
+= aParaBounds
.X
;
354 aPoint
.Y
+= aParaBounds
.Y
;
355 return m_xDocument
->retrieveCharacterIndex(this, aPoint
);
359 OUString SAL_CALL
Paragraph::getSelectedText()
363 return OCommonAccessibleText::getSelectedText();
367 ::sal_Int32 SAL_CALL
Paragraph::getSelectionStart()
370 return OCommonAccessibleText::getSelectionStart();
374 ::sal_Int32 SAL_CALL
Paragraph::getSelectionEnd()
377 return OCommonAccessibleText::getSelectionEnd();
381 sal_Bool SAL_CALL
Paragraph::setSelection(::sal_Int32 nStartIndex
,
382 ::sal_Int32 nEndIndex
)
385 m_xDocument
->changeParagraphSelection(this, nStartIndex
, nEndIndex
);
390 OUString SAL_CALL
Paragraph::getText()
393 return implGetText();
397 OUString SAL_CALL
Paragraph::getTextRange(::sal_Int32 nStartIndex
,
398 ::sal_Int32 nEndIndex
)
401 return OCommonAccessibleText::implGetTextRange(implGetText(), nStartIndex
, nEndIndex
);
405 css::accessibility::TextSegment SAL_CALL
Paragraph::getTextAtIndex( sal_Int32 nIndex
, sal_Int16 aTextType
)
408 return OCommonAccessibleText::getTextAtIndex(nIndex
, aTextType
);
412 css::accessibility::TextSegment SAL_CALL
Paragraph::getTextBeforeIndex( sal_Int32 nIndex
, sal_Int16 aTextType
)
415 return OCommonAccessibleText::getTextBeforeIndex(nIndex
, aTextType
);
419 css::accessibility::TextSegment SAL_CALL
Paragraph::getTextBehindIndex( sal_Int32 nIndex
, sal_Int16 aTextType
)
422 return OCommonAccessibleText::getTextBehindIndex(nIndex
, aTextType
);
426 sal_Bool SAL_CALL
Paragraph::copyText(::sal_Int32 nStartIndex
,
427 ::sal_Int32 nEndIndex
)
430 m_xDocument
->copyParagraphText(this, nStartIndex
, nEndIndex
);
435 sal_Bool SAL_CALL
Paragraph::scrollSubstringTo( sal_Int32
, sal_Int32
, css::accessibility::AccessibleScrollType
)
441 sal_Bool SAL_CALL
Paragraph::cutText(::sal_Int32 nStartIndex
,
442 ::sal_Int32 nEndIndex
)
445 m_xDocument
->changeParagraphText(this, nStartIndex
, nEndIndex
, true, false,
451 sal_Bool SAL_CALL
Paragraph::pasteText(::sal_Int32 nIndex
)
454 m_xDocument
->changeParagraphText(this, nIndex
, nIndex
, false, true,
460 sal_Bool SAL_CALL
Paragraph::deleteText(::sal_Int32 nStartIndex
,
461 ::sal_Int32 nEndIndex
)
464 m_xDocument
->changeParagraphText(this, nStartIndex
, nEndIndex
, false, false,
470 sal_Bool SAL_CALL
Paragraph::insertText(OUString
const & rText
,
474 m_xDocument
->changeParagraphText(this, nIndex
, nIndex
, false, false, rText
);
480 Paragraph::replaceText(::sal_Int32 nStartIndex
, ::sal_Int32 nEndIndex
,
481 OUString
const & rReplacement
)
484 m_xDocument
->changeParagraphText(this, nStartIndex
, nEndIndex
, false, false,
490 sal_Bool SAL_CALL
Paragraph::setAttributes(
491 ::sal_Int32 nStartIndex
, ::sal_Int32 nEndIndex
,
492 css::uno::Sequence
< css::beans::PropertyValue
> const & rAttributeSet
)
495 m_xDocument
->changeParagraphAttributes(this, nStartIndex
, nEndIndex
,
501 sal_Bool SAL_CALL
Paragraph::setText(OUString
const & rText
)
504 m_xDocument
->changeParagraphText(this, rText
);
509 css::uno::Sequence
< css::beans::PropertyValue
> SAL_CALL
510 Paragraph::getDefaultAttributes(const css::uno::Sequence
< OUString
>&)
513 return {}; // default attributes are not supported by text engine
517 css::uno::Sequence
< css::beans::PropertyValue
> SAL_CALL
518 Paragraph::getRunAttributes(::sal_Int32 Index
, const css::uno::Sequence
< OUString
>& RequestedAttributes
)
521 return m_xDocument
->retrieveRunAttributes( this, Index
, RequestedAttributes
);
525 ::sal_Int32 SAL_CALL
Paragraph::getLineNumberAtIndex( ::sal_Int32 nIndex
)
529 ::sal_Int32 nLineNo
= -1;
530 m_xDocument
->retrieveParagraphLineBoundary( this, nIndex
, &nLineNo
);
536 css::accessibility::TextSegment SAL_CALL
Paragraph::getTextAtLineNumber( ::sal_Int32 nLineNo
)
540 css::i18n::Boundary aBoundary
=
541 m_xDocument
->retrieveParagraphBoundaryOfLine( this, nLineNo
);
543 return css::accessibility::TextSegment( getTextRange(aBoundary
.startPos
, aBoundary
.endPos
),
544 aBoundary
.startPos
, aBoundary
.endPos
);
548 css::accessibility::TextSegment SAL_CALL
Paragraph::getTextAtLineWithCaret( )
552 sal_Int32 nLineNo
= getNumberOfLineWithCaret();
555 return ( nLineNo
>= 0 ) ?
556 getTextAtLineNumber( nLineNo
) :
557 css::accessibility::TextSegment();
558 } catch (const css::lang::IndexOutOfBoundsException
&) {
559 css::uno::Any anyEx
= cppu::getCaughtException();
560 throw css::lang::WrappedTargetRuntimeException(
561 u
"textwindowaccessibility.cxx:"
562 " Paragraph::getTextAtLineWithCaret"_ustr
,
568 ::sal_Int32 SAL_CALL
Paragraph::getNumberOfLineWithCaret( )
571 return m_xDocument
->retrieveParagraphLineWithCursor(this);
576 void SAL_CALL
Paragraph::addAccessibleEventListener(
578 css::accessibility::XAccessibleEventListener
> const & rListener
)
583 ::osl::ClearableMutexGuard
aGuard(rBHelper
.rMutex
);
584 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
587 rListener
->disposing(css::lang::EventObject(
593 m_nClientId
= comphelper::AccessibleEventNotifier::registerClient( );
594 comphelper::AccessibleEventNotifier::addEventListener( m_nClientId
, rListener
);
599 void SAL_CALL
Paragraph::removeAccessibleEventListener(
601 css::accessibility::XAccessibleEventListener
> const & rListener
)
603 comphelper::AccessibleEventNotifier::TClientId nId
= 0;
605 osl::MutexGuard
aGuard(rBHelper
.rMutex
);
606 if (rListener
.is() && m_nClientId
!= 0
607 && comphelper::AccessibleEventNotifier::removeEventListener( m_nClientId
, rListener
) == 0)
615 // no listeners anymore
616 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
617 // and at least to us not firing any events anymore, in case somebody calls
618 // NotifyAccessibleEvent, again
619 comphelper::AccessibleEventNotifier::revokeClient(nId
);
624 void SAL_CALL
Paragraph::disposing()
626 comphelper::AccessibleEventNotifier::TClientId nId
= 0;
628 osl::MutexGuard
aGuard(rBHelper
.rMutex
);
633 comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing(nId
, *this);
637 OUString
Paragraph::implGetText()
639 return m_xDocument
->retrieveParagraphText(this);
643 css::lang::Locale
Paragraph::implGetLocale()
645 return m_xDocument
->retrieveLocale();
649 void Paragraph::implGetSelection(::sal_Int32
& rStartIndex
,
650 ::sal_Int32
& rEndIndex
)
652 m_xDocument
->retrieveParagraphSelection(this, &rStartIndex
, &rEndIndex
);
656 void Paragraph::implGetParagraphBoundary( const OUString
& rText
,
657 css::i18n::Boundary
& rBoundary
,
660 ::sal_Int32 nLength
= rText
.getLength();
662 if ( implIsValidIndex( nIndex
, nLength
) )
664 rBoundary
.startPos
= 0;
665 rBoundary
.endPos
= nLength
;
669 rBoundary
.startPos
= nIndex
;
670 rBoundary
.endPos
= nIndex
;
675 void Paragraph::implGetLineBoundary( const OUString
& rText
,
676 css::i18n::Boundary
& rBoundary
,
679 ::sal_Int32 nLength
= rText
.getLength();
681 if ( implIsValidIndex( nIndex
, nLength
) || nIndex
== nLength
)
683 css::i18n::Boundary aBoundary
=
684 m_xDocument
->retrieveParagraphLineBoundary( this, nIndex
, nullptr );
685 rBoundary
.startPos
= aBoundary
.startPos
;
686 rBoundary
.endPos
= aBoundary
.endPos
;
690 rBoundary
.startPos
= nIndex
;
691 rBoundary
.endPos
= nIndex
;
696 void Paragraph::checkDisposed()
698 ::osl::MutexGuard
aGuard(rBHelper
.rMutex
);
699 if (!(rBHelper
.bDisposed
|| rBHelper
.bInDispose
))
701 throw css::lang::DisposedException(
702 OUString(), getXWeak());
705 Document::Document(vcl::Window
* pWindow
, ::TextEngine
& rEngine
,
707 : VCLXAccessibleComponent(pWindow
),
710 m_aEngineListener(*this),
711 m_aViewListener(LINK(this, Document
, WindowEventHandler
)),
712 m_nVisibleBeginOffset(0),
713 m_nSelectionFirstPara(-1),
714 m_nSelectionFirstPos(-1),
715 m_nSelectionLastPara(-1),
716 m_nSelectionLastPos(-1),
717 m_bSelectionChangedNotification(false)
719 const sal_uInt32 nCount
= m_rEngine
.GetParagraphCount();
720 m_aParagraphs
.reserve(nCount
);
721 for (sal_uInt32 i
= 0; i
< nCount
; ++i
)
722 m_aParagraphs
.emplace_back(m_rEngine
.GetTextHeight(i
));
723 m_nViewOffset
= static_cast<::sal_Int32
>(m_rView
.GetStartDocPos().Y()); // XXX numeric overflow
724 m_nViewHeight
= static_cast<::sal_Int32
>(m_rView
.GetWindow()->GetOutputSizePixel().Height());
725 // XXX numeric overflow
726 determineVisibleRange();
727 m_nFocused
= m_aParagraphs
.size();
728 m_aEngineListener
.startListening(m_rEngine
);
729 m_aViewListener
.startListening(*m_rView
.GetWindow());
732 css::uno::Reference
<css::accessibility::XAccessible
> Document::getAccessible() const
734 if (vcl::Window
* pWindow
= GetWindow())
735 return pWindow
->GetAccessible();
739 css::lang::Locale
Document::retrieveLocale()
741 SolarMutexGuard aGuard
;
742 return m_rEngine
.GetLocale();
745 ::sal_Int32
Document::retrieveParagraphIndex(Paragraph
const * pParagraph
)
747 ::osl::MutexGuard
aInternalGuard(GetMutex());
749 // If a client holds on to a Paragraph that is no longer visible, it can
750 // happen that this Paragraph lies outside the range from m_aVisibleBegin
751 // to m_aVisibleEnd. In that case, return -1 instead of a valid index:
752 auto nPara(pParagraph
->getNumber());
753 return nPara
< m_nVisibleBegin
|| nPara
>= m_nVisibleEnd
754 ? -1 : static_cast< ::sal_Int32
>(nPara
- m_nVisibleBegin
);
755 // XXX numeric overflow
758 ::sal_Int64
Document::retrieveParagraphState(Paragraph
const * pParagraph
)
760 ::osl::MutexGuard
aInternalGuard(GetMutex());
762 // If a client holds on to a Paragraph that is no longer visible, it can
763 // happen that this Paragraph lies outside the range from m_aVisibleBegin
764 // to m_aVisibleEnd. In that case, it is neither VISIBLE nor SHOWING:
766 = css::accessibility::AccessibleStateType::ENABLED
767 | css::accessibility::AccessibleStateType::SENSITIVE
768 | css::accessibility::AccessibleStateType::FOCUSABLE
769 | css::accessibility::AccessibleStateType::MULTI_LINE
;
770 if (!m_rView
.IsReadOnly())
771 nState
|= css::accessibility::AccessibleStateType::EDITABLE
;
772 auto nPara(pParagraph
->getNumber());
773 if (nPara
>= m_nVisibleBegin
&& nPara
< m_nVisibleEnd
)
776 |= css::accessibility::AccessibleStateType::VISIBLE
777 | css::accessibility::AccessibleStateType::SHOWING
;
778 if (nPara
== m_nFocused
)
779 nState
|= css::accessibility::AccessibleStateType::FOCUSED
;
785 Document::retrieveParagraphBounds(Paragraph
const * pParagraph
,
788 SolarMutexGuard aGuard
;
789 ::osl::MutexGuard
aInternalGuard(GetMutex());
791 // If a client holds on to a Paragraph that is no longer visible (as it
792 // scrolled out the top of the view), it can happen that this Paragraph
793 // lies before m_aVisibleBegin. In that case, calculate the vertical
794 // position of the Paragraph starting at paragraph 0, otherwise optimize
795 // and start at m_aVisibleBegin:
796 auto nPara(pParagraph
->getNumber());
797 auto lAddHeight
= [](const sal_Int32
& rSum
, const ParagraphInfo
& rParagraph
) {
798 return rSum
+ rParagraph
.getHeight(); };
800 if (nPara
< m_nVisibleBegin
)
801 nPos
= std::accumulate(m_aParagraphs
.begin(), getIter(nPara
), sal_Int32(0), lAddHeight
);
803 nPos
= std::accumulate(visibleBegin(), getIter(nPara
), m_nViewOffset
- m_nVisibleBeginOffset
, lAddHeight
);
807 aOrig
= Point(m_rView
.GetWindow()->OutputToAbsoluteScreenPixel(aOrig
));
809 return css::awt::Rectangle(
810 static_cast< ::sal_Int32
>(aOrig
.X()),
811 static_cast< ::sal_Int32
>(aOrig
.Y()) + nPos
- m_nViewOffset
,
812 m_rView
.GetWindow()->GetOutputSizePixel().Width(), getIter(nPara
)->getHeight());
813 // XXX numeric overflow (3x)
817 Document::retrieveParagraphText(Paragraph
const * pParagraph
)
819 SolarMutexGuard aGuard
;
820 ::osl::MutexGuard
aInternalGuard(GetMutex());
821 return m_rEngine
.GetText(static_cast< ::sal_uInt32
>(pParagraph
->getNumber()));
822 // numeric overflow cannot happen here
825 void Document::retrieveParagraphSelection(Paragraph
const * pParagraph
,
826 ::sal_Int32
* pBegin
,
829 SolarMutexGuard aGuard
;
830 ::osl::MutexGuard
aInternalGuard(GetMutex());
831 ::TextSelection
const & rSelection
= m_rView
.GetSelection();
832 Paragraphs::size_type nNumber
= pParagraph
->getNumber();
833 TextPaM
aStartPaM( rSelection
.GetStart() );
834 TextPaM
aEndPaM( rSelection
.GetEnd() );
835 TextPaM
aMinPaM( std::min( aStartPaM
, aEndPaM
) );
836 TextPaM
aMaxPaM( std::max( aStartPaM
, aEndPaM
) );
838 if ( nNumber
>= aMinPaM
.GetPara() && nNumber
<= aMaxPaM
.GetPara() )
840 *pBegin
= nNumber
> aMinPaM
.GetPara() ? 0 : aMinPaM
.GetIndex();
841 // XXX numeric overflow
842 *pEnd
= nNumber
< aMaxPaM
.GetPara()
843 ? m_rEngine
.GetText(static_cast< ::sal_uInt32
>(nNumber
)).getLength()
844 : aMaxPaM
.GetIndex();
845 // XXX numeric overflow (3x)
847 if ( aStartPaM
> aEndPaM
)
848 std::swap( *pBegin
, *pEnd
);
857 ::sal_Int32
Document::retrieveParagraphCaretPosition(Paragraph
const * pParagraph
)
859 SolarMutexGuard aGuard
;
860 ::osl::MutexGuard
aInternalGuard(GetMutex());
861 ::TextSelection
const & rSelection
= m_rView
.GetSelection();
862 Paragraphs::size_type nNumber
= pParagraph
->getNumber();
863 TextPaM
aEndPaM( rSelection
.GetEnd() );
865 return aEndPaM
.GetPara() == nNumber
? aEndPaM
.GetIndex() : -1;
869 Document::retrieveCharacterBounds(Paragraph
const * pParagraph
,
872 SolarMutexGuard aGuard
;
873 ::osl::MutexGuard
aInternalGuard(GetMutex());
874 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>(pParagraph
->getNumber());
875 sal_Int32 nLength
= m_rEngine
.GetText(nNumber
).getLength();
876 // XXX numeric overflow
877 if (nIndex
< 0 || nIndex
> nLength
)
878 throw css::lang::IndexOutOfBoundsException(
879 u
"textwindowaccessibility.cxx:"
880 " Document::retrieveCharacterAttributes"_ustr
,
882 css::awt::Rectangle
aBounds( 0, 0, 0, 0 );
883 if ( nIndex
== nLength
)
886 = vcl::unohelper::ConvertToAWTRect(m_rEngine
.PaMtoEditCursor(::TextPaM(nNumber
, nIndex
)));
890 ::tools::Rectangle
aLeft(
891 m_rEngine
.PaMtoEditCursor(::TextPaM(nNumber
, nIndex
)));
892 // XXX numeric overflow
893 ::tools::Rectangle
aRight(
894 m_rEngine
.PaMtoEditCursor(::TextPaM(nNumber
, nIndex
+ 1)));
895 // XXX numeric overflow (2x)
896 // FIXME If the vertical extends of the two cursors do not match, assume
897 // nIndex is the last character on the line; the bounding box will then
898 // extend to m_rEngine.GetMaxTextWidth():
899 ::sal_Int32 nWidth
= (aLeft
.Top() == aRight
.Top()
900 && aLeft
.Bottom() == aRight
.Bottom())
901 ? static_cast< ::sal_Int32
>(aRight
.Left() - aLeft
.Left())
902 : static_cast< ::sal_Int32
>(m_rEngine
.GetMaxTextWidth()
904 // XXX numeric overflow (4x)
905 aBounds
= css::awt::Rectangle(static_cast< ::sal_Int32
>(aLeft
.Left()),
906 static_cast< ::sal_Int32
>(aLeft
.Top() - m_nViewOffset
),
908 static_cast< ::sal_Int32
>(aLeft
.Bottom()
910 // XXX numeric overflow (4x)
915 ::sal_Int32
Document::retrieveCharacterIndex(Paragraph
const * pParagraph
,
916 css::awt::Point
const & rPoint
)
918 SolarMutexGuard aGuard
;
919 ::osl::MutexGuard
aInternalGuard(GetMutex());
920 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>(pParagraph
->getNumber());
921 // XXX numeric overflow
922 ::TextPaM
aPaM(m_rEngine
.GetPaM(::Point(static_cast< tools::Long
>(rPoint
.X
),
923 static_cast< tools::Long
>(rPoint
.Y
))));
924 // XXX numeric overflow (2x)
925 return aPaM
.GetPara() == nNumber
? aPaM
.GetIndex() : -1;
926 // XXX numeric overflow
929 css::uno::Sequence
< css::beans::PropertyValue
>
930 Document::retrieveCharacterAttributes(
931 Paragraph
const * pParagraph
, ::sal_Int32 nIndex
,
932 const css::uno::Sequence
< OUString
>& aRequestedAttributes
)
934 SolarMutexGuard aGuard
;
936 vcl::Font aFont
= m_rEngine
.GetFont();
937 const sal_Int32 AttributeCount
= 9;
938 std::vector
< css::beans::PropertyValue
> aAttribs
;
939 aAttribs
.reserve(AttributeCount
);
941 css::beans::PropertyValue aAttrib
;
943 aAttrib
.State
= css::beans::PropertyState_DIRECT_VALUE
;
945 //character background color
946 aAttrib
.Name
= "CharBackColor";
947 aAttrib
.Value
= mapFontColor( aFont
.GetFillColor() );
948 aAttribs
.push_back(aAttrib
);
951 aAttrib
.Name
= "CharColor";
952 //aAttrib.Value = mapFontColor( aFont.GetColor() );
953 aAttrib
.Value
= mapFontColor( m_rEngine
.GetTextColor() );
954 aAttribs
.push_back(aAttrib
);
956 //character font name
957 aAttrib
.Name
= "CharFontName";
958 aAttrib
.Value
<<= aFont
.GetFamilyName();
959 aAttribs
.push_back(aAttrib
);
962 aAttrib
.Name
= "CharHeight";
963 aAttrib
.Value
<<= static_cast<sal_Int16
>(aFont
.GetFontHeight());
964 aAttribs
.push_back(aAttrib
);
967 aAttrib
.Name
= "CharPosture";
968 aAttrib
.Value
<<= vcl::unohelper::ConvertFontSlant(aFont
.GetItalic());
969 aAttribs
.push_back(aAttrib
);
973 aAttrib.Name = "CharRelief";
974 aAttrib.Value = css::uno::Any( (sal_Int16)aFont.GetRelief() );
975 aAttribs.push_back(aAttrib);
978 //character strikeout
979 aAttrib
.Name
= "CharStrikeout";
980 aAttrib
.Value
<<= static_cast<sal_Int16
>(aFont
.GetStrikeout());
981 aAttribs
.push_back(aAttrib
);
983 //character underline
984 aAttrib
.Name
= "CharUnderline";
985 aAttrib
.Value
<<= static_cast<sal_Int16
>(aFont
.GetUnderline());
986 aAttribs
.push_back(aAttrib
);
989 aAttrib
.Name
= "CharWeight";
990 aAttrib
.Value
<<= static_cast<float>(aFont
.GetWeight());
991 aAttribs
.push_back(aAttrib
);
993 //character alignment
994 aAttrib
.Name
= "ParaAdjust";
995 aAttrib
.Value
<<= static_cast<sal_Int16
>(m_rEngine
.GetTextAlign());
996 aAttribs
.push_back(aAttrib
);
998 ::osl::MutexGuard
aInternalGuard(GetMutex());
999 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>(pParagraph
->getNumber());
1000 // XXX numeric overflow
1001 // nIndex can be equal to getLength();
1002 if (nIndex
< 0 || nIndex
> m_rEngine
.GetText(nNumber
).getLength())
1003 throw css::lang::IndexOutOfBoundsException(
1004 u
"textwindowaccessibility.cxx:"
1005 " Document::retrieveCharacterAttributes"_ustr
,
1009 // retrieve run attributes
1010 tPropValMap aCharAttrSeq
;
1011 retrieveRunAttributesImpl( pParagraph
, nIndex
, aRequestedAttributes
, aCharAttrSeq
);
1013 for (const css::beans::PropertyValue
& rAttrib
: aAttribs
)
1015 aCharAttrSeq
[ rAttrib
.Name
] = rAttrib
;
1018 const css::uno::Sequence
< css::beans::PropertyValue
> aRes
= comphelper::mapValuesToSequence( aCharAttrSeq
);
1020 // sort the attributes
1021 auto nLength
= static_cast<size_t>(aRes
.getLength());
1022 std::vector
<sal_Int32
> pIndices(nLength
);
1023 std::iota(pIndices
.begin(), pIndices
.end(), 0);
1024 std::sort(pIndices
.begin(), pIndices
.end(),
1025 [&aRes
](sal_Int32 a
, sal_Int32 b
) { return aRes
[a
].Name
< aRes
[b
].Name
; });
1027 // create sorted sequences according to index array
1028 std::vector
<css::beans::PropertyValue
> aNewValues
;
1029 aNewValues
.reserve(nLength
);
1030 std::transform(pIndices
.begin(), pIndices
.end(), std::back_inserter(aNewValues
),
1031 [&aRes
](const sal_Int32 nIdx
) -> const css::beans::PropertyValue
& { return aRes
[nIdx
]; });
1033 return comphelper::containerToSequence(aNewValues
);
1036 void Document::retrieveRunAttributesImpl(
1037 Paragraph
const * pParagraph
, ::sal_Int32 Index
,
1038 const css::uno::Sequence
< OUString
>& RequestedAttributes
,
1039 tPropValMap
& rRunAttrSeq
)
1041 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>( pParagraph
->getNumber() );
1042 ::TextPaM
aPaM( nNumber
, Index
);
1043 // XXX numeric overflow
1044 ::TextAttribFontColor
const * pColor
1045 = static_cast< ::TextAttribFontColor
const * >(
1046 m_rEngine
.FindAttrib( aPaM
, TEXTATTR_FONTCOLOR
) );
1047 ::TextAttribFontWeight
const * pWeight
1048 = static_cast< ::TextAttribFontWeight
const * >(
1049 m_rEngine
.FindAttrib( aPaM
, TEXTATTR_FONTWEIGHT
) );
1050 tPropValMap aRunAttrSeq
;
1053 css::beans::PropertyValue aPropVal
{
1055 mapFontColor(pColor
->GetColor()),
1056 css::beans::PropertyState_DIRECT_VALUE
};
1057 aRunAttrSeq
[ aPropVal
.Name
] = aPropVal
;
1061 css::beans::PropertyValue aPropVal
{
1063 mapFontWeight(pWeight
->getFontWeight()),
1064 css::beans::PropertyState_DIRECT_VALUE
};
1065 aRunAttrSeq
[ aPropVal
.Name
] = aPropVal
;
1067 if ( !RequestedAttributes
.hasElements() )
1069 rRunAttrSeq
= std::move(aRunAttrSeq
);
1073 for ( const OUString
& rReqAttr
: RequestedAttributes
)
1075 tPropValMap::iterator aIter
= aRunAttrSeq
.find( rReqAttr
);
1076 if ( aIter
!= aRunAttrSeq
.end() )
1078 rRunAttrSeq
[ (*aIter
).first
] = (*aIter
).second
;
1084 css::uno::Sequence
< css::beans::PropertyValue
>
1085 Document::retrieveRunAttributes(
1086 Paragraph
const * pParagraph
, ::sal_Int32 Index
,
1087 const css::uno::Sequence
< OUString
>& RequestedAttributes
)
1089 SolarMutexGuard aGuard
;
1090 ::osl::MutexGuard
aInternalGuard( GetMutex() );
1091 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>( pParagraph
->getNumber() );
1092 // XXX numeric overflow
1093 if ( Index
< 0 || Index
>= m_rEngine
.GetText(nNumber
).getLength() )
1094 throw css::lang::IndexOutOfBoundsException(
1095 u
"textwindowaccessibility.cxx:"
1096 " Document::retrieveRunAttributes"_ustr
,
1099 tPropValMap aRunAttrSeq
;
1100 retrieveRunAttributesImpl( pParagraph
, Index
, RequestedAttributes
, aRunAttrSeq
);
1101 return comphelper::mapValuesToSequence( aRunAttrSeq
);
1104 void Document::changeParagraphText(Paragraph
const * pParagraph
,
1105 OUString
const & rText
)
1107 SolarMutexGuard aGuard
;
1109 ::osl::MutexGuard
aInternalGuard(GetMutex());
1110 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>(pParagraph
->getNumber());
1111 // XXX numeric overflow
1112 changeParagraphText(nNumber
, 0, m_rEngine
.GetTextLen(nNumber
), false,
1117 void Document::changeParagraphText(Paragraph
const * pParagraph
,
1118 ::sal_Int32 nBegin
, ::sal_Int32 nEnd
,
1119 bool bCut
, bool bPaste
,
1120 OUString
const & rText
)
1122 SolarMutexGuard aGuard
;
1124 ::osl::MutexGuard
aInternalGuard(GetMutex());
1125 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>(pParagraph
->getNumber());
1126 // XXX numeric overflow
1127 if (nBegin
< 0 || nBegin
> nEnd
1128 || nEnd
> m_rEngine
.GetText(nNumber
).getLength())
1129 throw css::lang::IndexOutOfBoundsException(
1130 u
"textwindowaccessibility.cxx:"
1131 " Document::changeParagraphText"_ustr
,
1133 changeParagraphText(nNumber
, static_cast< ::sal_uInt16
>(nBegin
),
1134 static_cast< ::sal_uInt16
>(nEnd
), bCut
, bPaste
, rText
);
1135 // XXX numeric overflow (2x)
1139 void Document::copyParagraphText(Paragraph
const * pParagraph
,
1140 ::sal_Int32 nBegin
, ::sal_Int32 nEnd
)
1142 SolarMutexGuard aGuard
;
1144 ::osl::MutexGuard
aInternalGuard(GetMutex());
1145 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>(pParagraph
->getNumber());
1146 // XXX numeric overflow
1147 if (nBegin
< 0 || nBegin
> nEnd
1148 || nEnd
> m_rEngine
.GetText(nNumber
).getLength())
1149 throw css::lang::IndexOutOfBoundsException(
1150 u
"textwindowaccessibility.cxx:"
1151 " Document::copyParagraphText"_ustr
,
1153 m_rView
.SetSelection(
1154 ::TextSelection(::TextPaM(nNumber
, nBegin
),
1155 ::TextPaM(nNumber
, nEnd
)));
1156 // XXX numeric overflow (2x)
1161 void Document::changeParagraphAttributes(
1162 Paragraph
const * pParagraph
, ::sal_Int32 nBegin
, ::sal_Int32 nEnd
,
1163 css::uno::Sequence
< css::beans::PropertyValue
> const & rAttributeSet
)
1165 SolarMutexGuard aGuard
;
1167 ::osl::MutexGuard
aInternalGuard(GetMutex());
1168 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>(pParagraph
->getNumber());
1169 // XXX numeric overflow
1170 if (nBegin
< 0 || nBegin
> nEnd
1171 || nEnd
> m_rEngine
.GetText(nNumber
).getLength())
1172 throw css::lang::IndexOutOfBoundsException(
1173 u
"textwindowaccessibility.cxx:"
1174 " Document::changeParagraphAttributes"_ustr
,
1177 // FIXME The new attributes are added to any attributes already set,
1178 // they do not replace the old attributes as required by
1179 // XAccessibleEditableText.setAttributes:
1180 for (const auto& rAttr
: rAttributeSet
)
1181 if ( rAttr
.Name
== "CharColor" )
1182 m_rEngine
.SetAttrib(::TextAttribFontColor(
1183 mapFontColor(rAttr
.Value
)),
1184 nNumber
, nBegin
, nEnd
);
1185 // XXX numeric overflow (2x)
1186 else if ( rAttr
.Name
== "CharWeight" )
1187 m_rEngine
.SetAttrib(::TextAttribFontWeight(
1188 mapFontWeight(rAttr
.Value
)),
1189 nNumber
, nBegin
, nEnd
);
1190 // XXX numeric overflow (2x)
1194 void Document::changeParagraphSelection(Paragraph
const * pParagraph
,
1195 ::sal_Int32 nBegin
, ::sal_Int32 nEnd
)
1197 SolarMutexGuard aGuard
;
1199 ::osl::MutexGuard
aInternalGuard(GetMutex());
1200 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>(pParagraph
->getNumber());
1201 // XXX numeric overflow
1202 if (nBegin
< 0 || nBegin
> nEnd
1203 || nEnd
> m_rEngine
.GetText(nNumber
).getLength())
1204 throw css::lang::IndexOutOfBoundsException(
1205 u
"textwindowaccessibility.cxx:"
1206 " Document::changeParagraphSelection"_ustr
,
1208 m_rView
.SetSelection(
1209 ::TextSelection(::TextPaM(nNumber
, nBegin
),
1210 ::TextPaM(nNumber
, nEnd
)));
1211 // XXX numeric overflow (2x)
1216 Document::retrieveParagraphLineBoundary( Paragraph
const * pParagraph
,
1217 ::sal_Int32 nIndex
, ::sal_Int32
*pLineNo
)
1219 css::i18n::Boundary aBoundary
;
1220 aBoundary
.startPos
= nIndex
;
1221 aBoundary
.endPos
= nIndex
;
1223 SolarMutexGuard aGuard
;
1225 ::osl::MutexGuard
aInternalGuard( GetMutex() );
1226 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>( pParagraph
->getNumber() );
1227 if ( nIndex
< 0 || nIndex
> m_rEngine
.GetText( nNumber
).getLength() )
1228 throw css::lang::IndexOutOfBoundsException(
1229 u
"textwindowaccessibility.cxx:"
1230 " Document::retrieveParagraphLineBoundary"_ustr
,
1232 ::sal_Int32 nLineStart
= 0;
1233 ::sal_Int32 nLineEnd
= 0;
1234 ::sal_uInt16 nLineCount
= m_rEngine
.GetLineCount( nNumber
);
1235 for ( ::sal_uInt16 nLine
= 0; nLine
< nLineCount
; ++nLine
)
1237 nLineStart
= nLineEnd
;
1238 nLineEnd
+= m_rEngine
.GetLineLen( nNumber
, nLine
);
1239 if ( nIndex
>= nLineStart
&& ( ( nLine
== nLineCount
- 1 ) ? nIndex
<= nLineEnd
: nIndex
< nLineEnd
) )
1241 aBoundary
.startPos
= nLineStart
;
1242 aBoundary
.endPos
= nLineEnd
;
1254 Document::retrieveParagraphBoundaryOfLine( Paragraph
const * pParagraph
,
1255 ::sal_Int32 nLineNo
)
1257 css::i18n::Boundary aBoundary
;
1258 aBoundary
.startPos
= 0;
1259 aBoundary
.endPos
= 0;
1261 SolarMutexGuard aGuard
;
1263 ::osl::MutexGuard
aInternalGuard( GetMutex() );
1264 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>( pParagraph
->getNumber() );
1265 if ( nLineNo
>= m_rEngine
.GetLineCount( nNumber
) )
1266 throw css::lang::IndexOutOfBoundsException(
1267 u
"textwindowaccessibility.cxx:"
1268 " Document::retrieveParagraphBoundaryOfLine"_ustr
,
1270 ::sal_Int32 nLineStart
= 0;
1271 ::sal_Int32 nLineEnd
= 0;
1272 for ( ::sal_Int32 nLine
= 0; nLine
<= nLineNo
; ++nLine
)
1274 nLineStart
= nLineEnd
;
1275 nLineEnd
+= m_rEngine
.GetLineLen( nNumber
, nLine
);
1278 aBoundary
.startPos
= nLineStart
;
1279 aBoundary
.endPos
= nLineEnd
;
1285 sal_Int32
Document::retrieveParagraphLineWithCursor( Paragraph
const * pParagraph
)
1287 SolarMutexGuard aGuard
;
1288 ::osl::MutexGuard
aInternalGuard(GetMutex());
1289 ::TextSelection
const & rSelection
= m_rView
.GetSelection();
1290 Paragraphs::size_type nNumber
= pParagraph
->getNumber();
1291 TextPaM
aEndPaM( rSelection
.GetEnd() );
1293 return aEndPaM
.GetPara() == nNumber
1294 ? m_rView
.GetLineNumberOfCursorInSelection() : -1;
1298 css::uno::Reference
< css::accessibility::XAccessibleRelationSet
>
1299 Document::retrieveParagraphRelationSet( Paragraph
const * pParagraph
)
1301 ::osl::MutexGuard
aInternalGuard( GetMutex() );
1303 rtl::Reference
<::utl::AccessibleRelationSetHelper
> pRelationSetHelper
= new ::utl::AccessibleRelationSetHelper();
1305 auto nPara(pParagraph
->getNumber());
1307 if (nPara
> m_nVisibleBegin
&& nPara
< m_nVisibleEnd
)
1309 css::uno::Sequence
<css::uno::Reference
<css::accessibility::XAccessible
>> aSequence
{ getAccessibleChild(getIter(nPara
- 1)) };
1310 css::accessibility::AccessibleRelation
aRelation(css::accessibility::AccessibleRelationType_CONTENT_FLOWS_FROM
, aSequence
);
1311 pRelationSetHelper
->AddRelation( aRelation
);
1314 if (nPara
>= m_nVisibleBegin
&& m_nVisibleEnd
> 1 && nPara
< m_nVisibleEnd
- 1)
1316 css::uno::Sequence
<css::uno::Reference
<css::accessibility::XAccessible
>> aSequence
{ getAccessibleChild(getIter(nPara
+ 1)) };
1317 css::accessibility::AccessibleRelation
aRelation( css::accessibility::AccessibleRelationType_CONTENT_FLOWS_TO
, aSequence
);
1318 pRelationSetHelper
->AddRelation( aRelation
);
1321 return pRelationSetHelper
;
1325 sal_Int64 SAL_CALL
Document::getAccessibleChildCount()
1327 ::comphelper::OExternalLockGuard
aGuard(this);
1328 return m_nVisibleEnd
- m_nVisibleBegin
;
1332 css::uno::Reference
< css::accessibility::XAccessible
> SAL_CALL
1333 Document::getAccessibleChild(sal_Int64 i
)
1335 ::comphelper::OExternalLockGuard
aGuard(this);
1336 if (i
< 0 || o3tl::make_unsigned(i
) >= m_nVisibleEnd
- m_nVisibleBegin
)
1337 throw css::lang::IndexOutOfBoundsException(
1338 u
"textwindowaccessibility.cxx:"
1339 " Document::getAccessibleChild"_ustr
,
1341 return getAccessibleChild(getIter(m_nVisibleBegin
+ i
));
1345 ::sal_Int16 SAL_CALL
Document::getAccessibleRole()
1347 return css::accessibility::AccessibleRole::TEXT_FRAME
;
1351 css::uno::Reference
< css::accessibility::XAccessible
> SAL_CALL
1352 Document::getAccessibleAtPoint(css::awt::Point
const & rPoint
)
1354 ::comphelper::OExternalLockGuard
aGuard(this);
1356 && rPoint
.X
< m_rView
.GetWindow()->GetOutputSizePixel().Width()
1357 && rPoint
.Y
>= 0 && rPoint
.Y
< m_nViewHeight
)
1359 ::sal_Int32 nOffset
= m_nViewOffset
+ rPoint
.Y
; // XXX numeric overflow
1360 ::sal_Int32 nPos
= m_nViewOffset
- m_nVisibleBeginOffset
;
1361 for (Paragraphs::iterator
aIt(visibleBegin()), aEnd(visibleEnd()); aIt
!= aEnd
; ++aIt
)
1363 nPos
+= aIt
->getHeight(); // XXX numeric overflow
1365 return getAccessibleChild(aIt
);
1370 void Document::FillAccessibleStateSet( sal_Int64
& rStateSet
)
1372 VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet
);
1373 if (!m_rView
.IsReadOnly())
1374 rStateSet
|= css::accessibility::AccessibleStateType::EDITABLE
;
1377 void Document::FillAccessibleRelationSet( utl::AccessibleRelationSetHelper
& rRelationSet
)
1379 if( getAccessibleParent()->getAccessibleContext()->getAccessibleRole() == css::accessibility::AccessibleRole::SCROLL_PANE
)
1381 css::uno::Sequence
<css::uno::Reference
<css::accessibility::XAccessible
>> aSequence
{ getAccessibleParent() };
1382 rRelationSet
.AddRelation( css::accessibility::AccessibleRelation( css::accessibility::AccessibleRelationType_MEMBER_OF
, aSequence
) );
1386 VCLXAccessibleComponent::FillAccessibleRelationSet(rRelationSet
);
1390 void SAL_CALL
Document::disposing()
1392 m_aEngineListener
.endListening();
1393 m_aViewListener
.endListening();
1394 disposeParagraphs();
1395 VCLXAccessibleComponent::disposing();
1399 void Document::Notify(::SfxBroadcaster
&, ::SfxHint
const & rHint
)
1401 switch (rHint
.GetId())
1403 case SfxHintId::TextParaInserted
:
1404 case SfxHintId::TextParaRemoved
:
1405 // SfxHintId::TextParaInserted and SfxHintId::TextParaRemoved are sent at
1406 // "unsafe" times (when the text engine has not yet re-formatted its
1407 // content), so that for example calling ::TextEngine::GetTextHeight
1408 // from within the code that handles SfxHintId::TextParaInserted causes
1409 // trouble within the text engine. Therefore, these hints are just
1410 // buffered until a following ::TextEngine::FormatDoc causes a
1411 // SfxHintId::TextFormatted to come in:
1412 case SfxHintId::TextFormatPara
:
1413 // ::TextEngine::FormatDoc sends a sequence of
1414 // SfxHintId::TextFormatParas, followed by an optional
1415 // SfxHintId::TextHeightChanged, followed in all cases by one
1416 // SfxHintId::TextFormatted. Only the SfxHintId::TextFormatParas contain
1417 // the numbers of the affected paragraphs, but they are sent
1418 // before the changes are applied. Therefore, SfxHintId::TextFormatParas
1419 // are just buffered until another hint comes in:
1421 ::osl::MutexGuard
aInternalGuard(GetMutex());
1425 const TextHint
& rTextHint
= static_cast<const TextHint
&>(rHint
);
1426 m_aParagraphNotifications
.push(rTextHint
);
1429 case SfxHintId::TextFormatted
:
1430 case SfxHintId::TextHeightChanged
:
1431 case SfxHintId::TextModified
:
1433 ::osl::MutexGuard
aInternalGuard(GetMutex());
1436 handleParagraphNotifications();
1439 case SfxHintId::TextViewScrolled
:
1441 ::osl::MutexGuard
aInternalGuard(GetMutex());
1444 handleParagraphNotifications();
1446 ::sal_Int32 nOffset
= static_cast< ::sal_Int32
>(
1447 m_rView
.GetStartDocPos().Y());
1448 // XXX numeric overflow
1449 if (nOffset
!= m_nViewOffset
)
1451 m_nViewOffset
= nOffset
;
1453 Paragraphs::iterator
aOldVisibleBegin(visibleBegin());
1454 Paragraphs::iterator
aOldVisibleEnd(visibleEnd());
1456 determineVisibleRange();
1458 notifyVisibleRangeChanges(aOldVisibleBegin
,
1460 m_aParagraphs
.end());
1464 case SfxHintId::TextViewSelectionChanged
:
1465 case SfxHintId::TextViewCaretChanged
:
1467 ::osl::MutexGuard
aInternalGuard(GetMutex());
1471 if (m_aParagraphNotifications
.empty())
1473 handleSelectionChangeNotification();
1477 // SfxHintId::TextViewSelectionChanged is sometimes sent at
1478 // "unsafe" times (when the text engine has not yet re-
1479 // formatted its content), so that for example calling
1480 // ::TextEngine::GetTextHeight from within the code that
1481 // handles a previous SfxHintId::TextParaInserted causes
1482 // trouble within the text engine. Therefore, these
1483 // hints are just buffered (along with
1484 // SfxHintId::TextParaInserted/REMOVED/FORMATPARA) until a
1485 // following ::TextEngine::FormatDoc causes a
1486 // SfxHintId::TextFormatted to come in:
1487 m_bSelectionChangedNotification
= true;
1495 IMPL_LINK(Document
, WindowEventHandler
, ::VclWindowEvent
&, rEvent
, void)
1497 switch (rEvent
.GetId())
1499 case VclEventId::WindowResize
:
1501 ::osl::MutexGuard
aInternalGuard(GetMutex());
1505 ::sal_Int32 nHeight
= static_cast< ::sal_Int32
>(
1506 m_rView
.GetWindow()->GetOutputSizePixel().Height());
1507 // XXX numeric overflow
1508 if (nHeight
!= m_nViewHeight
)
1510 m_nViewHeight
= nHeight
;
1512 Paragraphs::iterator
aOldVisibleBegin(visibleBegin());
1513 Paragraphs::iterator
aOldVisibleEnd(visibleEnd());
1515 determineVisibleRange();
1517 notifyVisibleRangeChanges(aOldVisibleBegin
, aOldVisibleEnd
,
1518 m_aParagraphs
.end());
1522 case VclEventId::WindowGetFocus
:
1524 ::osl::MutexGuard
aInternalGuard(GetMutex());
1527 //to enable the PARAGRAPH to get focus for multiline edit
1528 sal_Int64 count
= getAccessibleChildCount();
1529 bool bEmpty
= m_nFocused
== m_nVisibleEnd
&& count
== 1;
1530 if (bEmpty
|| (m_nFocused
>= m_nVisibleBegin
&& m_nFocused
< m_nVisibleEnd
))
1532 Paragraphs::iterator aTemp
= bEmpty
? visibleBegin() : focused();
1533 ::rtl::Reference
< Paragraph
> xParagraph(getParagraph(aTemp
));
1534 if (xParagraph
.is())
1536 xParagraph
->notifyEvent(
1537 css::accessibility::AccessibleEventId::
1541 css::accessibility::AccessibleStateType::
1547 case VclEventId::WindowLoseFocus
:
1549 ::osl::MutexGuard
aInternalGuard(GetMutex());
1552 //to enable the PARAGRAPH to get focus for multiline edit
1553 sal_Int64 count
= getAccessibleChildCount();
1554 bool bEmpty
= m_nFocused
== m_nVisibleEnd
&& count
== 1;
1555 if (bEmpty
|| (m_nFocused
>= m_nVisibleBegin
&& m_nFocused
< m_nVisibleEnd
))
1557 Paragraphs::iterator aTemp
= bEmpty
? visibleBegin() : focused();
1558 ::rtl::Reference
< Paragraph
> xParagraph(getParagraph(aTemp
));
1559 if (xParagraph
.is())
1560 xParagraph
->notifyEvent(
1561 css::accessibility::AccessibleEventId::
1564 css::accessibility::AccessibleStateType::
1574 ::rtl::Reference
< Paragraph
>
1575 Document::getParagraph(Paragraphs::iterator
const & rIt
)
1577 return rIt
->getParagraph().get();
1580 css::uno::Reference
< css::accessibility::XAccessible
>
1581 Document::getAccessibleChild(Paragraphs::iterator
const & rIt
)
1583 rtl::Reference
< Paragraph
> xParagraph(rIt
->getParagraph());
1584 if (!xParagraph
.is())
1586 xParagraph
= new Paragraph(this, rIt
- m_aParagraphs
.begin());
1587 rIt
->setParagraph(xParagraph
);
1592 void Document::determineVisibleRange()
1594 auto const nEnd
= m_aParagraphs
.size();
1596 m_nVisibleBegin
= nEnd
;
1597 m_nVisibleEnd
= nEnd
;
1598 m_nVisibleBeginOffset
= 0;
1600 ::sal_Int32 nPos
= 0;
1601 for (Paragraphs::size_type i
= 0; m_nVisibleEnd
== nEnd
&& i
!= nEnd
; ++i
)
1603 ::sal_Int32
const nOldPos
= nPos
;
1604 nPos
+= m_aParagraphs
[i
].getHeight(); // XXX numeric overflow
1605 if (m_nVisibleBegin
== nEnd
)
1607 if (nPos
>= m_nViewOffset
)
1609 m_nVisibleBegin
= i
;
1610 m_nVisibleBeginOffset
= m_nViewOffset
- nOldPos
;
1615 if (nPos
>= m_nViewOffset
+ m_nViewHeight
) // XXX numeric overflow
1623 !((m_nVisibleBegin
== m_aParagraphs
.size() && m_nVisibleEnd
== m_aParagraphs
.size() && m_nVisibleBeginOffset
== 0)
1624 || (m_nVisibleBegin
< m_nVisibleEnd
&& m_nVisibleBeginOffset
>= 0)),
1626 "invalid visible range");
1629 void Document::notifyVisibleRangeChanges(
1630 Paragraphs::iterator
const & rOldVisibleBegin
,
1631 Paragraphs::iterator
const & rOldVisibleEnd
,
1632 Paragraphs::iterator
const & rInserted
)
1634 // XXX Replace this code that determines which paragraphs have changed from
1635 // invisible to visible or vice versa with a better algorithm.
1636 auto aVisibleBegin
= visibleBegin(), aVisibleEnd
= visibleEnd();
1637 for (Paragraphs::iterator
aIt(rOldVisibleBegin
); aIt
!= rOldVisibleEnd
;
1640 if (aIt
!= rInserted
&& (aIt
< aVisibleBegin
|| aIt
>= aVisibleEnd
))
1641 NotifyAccessibleEvent(
1642 css::accessibility::AccessibleEventId::
1644 css::uno::Any(getAccessibleChild(aIt
)),
1647 for (Paragraphs::iterator
aIt(aVisibleBegin
); aIt
!= aVisibleEnd
; ++aIt
)
1649 if (aIt
== rInserted
1650 || aIt
< rOldVisibleBegin
|| aIt
>= rOldVisibleEnd
)
1651 NotifyAccessibleEvent(
1652 css::accessibility::AccessibleEventId::
1655 css::uno::Any(getAccessibleChild(aIt
)));
1660 Document::changeParagraphText(::sal_uInt32 nNumber
, ::sal_uInt16 nBegin
, ::sal_uInt16 nEnd
,
1661 bool bCut
, bool bPaste
,
1662 OUString
const & rText
)
1664 m_rView
.SetSelection(::TextSelection(::TextPaM(nNumber
, nBegin
),
1665 ::TextPaM(nNumber
, nEnd
)));
1668 else if (nBegin
!= nEnd
)
1669 m_rView
.DeleteSelected();
1672 else if (!rText
.isEmpty())
1673 m_rView
.InsertText(rText
);
1676 void Document::handleParagraphNotifications()
1678 // Recursion is possible, e.g. when SfxHintId::TextParaInserted is being handled,
1679 // and TextEngine::GetTextHeight is called for the paragraph being inserted; that
1680 // tries to handle the following SfxHintId::TextFormatPara notification at the
1681 // moment when the respective element hasn't yet been inserted into m_aParagraphs,
1682 // which could crash. Therefore, re-entry is not allowed. The handling is done in
1683 // a loop anyway, so it will process all of them in due order.
1684 // See also comments in Document::Notify.
1685 if (m_bInParagraphNotificationsHandler
)
1687 m_bInParagraphNotificationsHandler
= true;
1688 while (!m_aParagraphNotifications
.empty())
1690 ::TextHint
aHint(m_aParagraphNotifications
.front());
1691 m_aParagraphNotifications
.pop();
1692 switch (aHint
.GetId())
1694 case SfxHintId::TextParaInserted
:
1696 ::sal_uInt32 n
= static_cast< ::sal_uInt32
>( aHint
.GetValue() );
1697 assert(n
<= m_aParagraphs
.size() && "bad SfxHintId::TextParaInserted event");
1699 // Save the values of old offsets, and adjust the old values so that they
1700 // reflect the insertion of the new paragraph:
1701 Paragraphs::size_type nOldVisibleBegin
= m_nVisibleBegin
;
1702 Paragraphs::size_type nOldVisibleEnd
= m_nVisibleEnd
;
1703 Paragraphs::size_type nOldFocused
= m_nFocused
;
1704 if (n
<= nOldVisibleBegin
)
1705 ++nOldVisibleBegin
; // XXX numeric overflow
1706 if (n
<= nOldVisibleEnd
)
1707 ++nOldVisibleEnd
; // XXX numeric overflow
1708 if (n
<= nOldFocused
)
1709 ++nOldFocused
; // XXX numeric overflow
1710 if (sal::static_int_cast
<sal_Int32
>(n
) <= m_nSelectionFirstPara
)
1711 ++m_nSelectionFirstPara
; // XXX numeric overflow
1712 if (sal::static_int_cast
<sal_Int32
>(n
) <= m_nSelectionLastPara
)
1713 ++m_nSelectionLastPara
; // XXX numeric overflow
1715 Paragraphs::iterator
aIns(
1716 m_aParagraphs
.insert(
1718 ParagraphInfo(static_cast< ::sal_Int32
>(
1719 m_rEngine
.GetTextHeight(n
)))));
1720 // XXX numeric overflow (2x)
1722 determineVisibleRange();
1723 m_nFocused
= nOldFocused
;
1725 for (Paragraphs::iterator
aIt(aIns
);;)
1728 if (aIt
== m_aParagraphs
.end())
1730 ::rtl::Reference
< Paragraph
> xParagraph(
1732 if (xParagraph
.is())
1733 xParagraph
->numberChanged(true);
1736 notifyVisibleRangeChanges(getIter(nOldVisibleBegin
), getIter(nOldVisibleEnd
), aIns
);
1739 case SfxHintId::TextParaRemoved
:
1741 ::sal_uInt32 n
= static_cast< ::sal_uInt32
>( aHint
.GetValue() );
1742 if (n
== TEXT_PARA_ALL
)
1744 for (Paragraphs::iterator
aIt(visibleBegin()), aEnd(visibleEnd());
1747 NotifyAccessibleEvent(
1748 css::accessibility::AccessibleEventId::
1750 css::uno::Any(getAccessibleChild(aIt
)),
1753 disposeParagraphs();
1754 m_aParagraphs
.clear();
1755 determineVisibleRange();
1756 m_nSelectionFirstPara
= -1;
1757 m_nSelectionFirstPos
= -1;
1758 m_nSelectionLastPara
= -1;
1759 m_nSelectionLastPos
= -1;
1760 m_nFocused
= m_aParagraphs
.size();
1764 assert(n
< m_aParagraphs
.size() && "Bad SfxHintId::TextParaRemoved event");
1766 Paragraphs::iterator
aIt(getIter(n
));
1768 // Save the values of old offsets, and adjust the old
1769 // values so that they reflect the removal of the paragraph:
1770 Paragraphs::size_type nOldVisibleBegin
= m_nVisibleBegin
;
1771 Paragraphs::size_type nOldVisibleEnd
= m_nVisibleEnd
;
1773 = nOldVisibleBegin
<= n
&& n
< nOldVisibleEnd
;
1774 Paragraphs::size_type nOldFocused
= m_nFocused
;
1775 bool bWasFocused
= n
== m_nFocused
;
1776 if (n
< nOldVisibleBegin
)
1778 if (n
< nOldVisibleEnd
)
1780 if (n
< nOldFocused
)
1782 if (sal::static_int_cast
<sal_Int32
>(n
) < m_nSelectionFirstPara
)
1783 --m_nSelectionFirstPara
;
1784 else if (sal::static_int_cast
<sal_Int32
>(n
) == m_nSelectionFirstPara
)
1786 if (m_nSelectionFirstPara
== m_nSelectionLastPara
)
1788 m_nSelectionFirstPara
= -1;
1789 m_nSelectionFirstPos
= -1;
1790 m_nSelectionLastPara
= -1;
1791 m_nSelectionLastPos
= -1;
1795 ++m_nSelectionFirstPara
;
1796 m_nSelectionFirstPos
= 0;
1799 if (sal::static_int_cast
<sal_Int32
>(n
) < m_nSelectionLastPara
)
1800 --m_nSelectionLastPara
;
1801 else if (sal::static_int_cast
<sal_Int32
>(n
) == m_nSelectionLastPara
)
1803 assert(m_nSelectionFirstPara
< m_nSelectionLastPara
&& "logic error");
1804 --m_nSelectionLastPara
;
1805 m_nSelectionLastPos
= 0x7FFFFFFF;
1808 css::uno::Reference
< css::accessibility::XAccessible
>
1811 xStrong
= getAccessibleChild(aIt
);
1812 unotools::WeakReference
<Paragraph
> xWeak(
1813 aIt
->getParagraph());
1814 aIt
= m_aParagraphs
.erase(aIt
);
1816 determineVisibleRange();
1817 m_nFocused
= bWasFocused
? m_aParagraphs
.size() : nOldFocused
;
1819 for (; aIt
!= m_aParagraphs
.end(); ++aIt
)
1821 ::rtl::Reference
< Paragraph
> xParagraph(
1823 if (xParagraph
.is())
1824 xParagraph
->numberChanged(false);
1828 NotifyAccessibleEvent(
1829 css::accessibility::AccessibleEventId::
1831 css::uno::Any(xStrong
),
1834 rtl::Reference
< Paragraph
> xComponent( xWeak
.get() );
1835 if (xComponent
.is())
1836 xComponent
->dispose();
1838 notifyVisibleRangeChanges(
1839 getIter(nOldVisibleBegin
),
1840 getIter(nOldVisibleEnd
),
1841 m_aParagraphs
.end());
1845 case SfxHintId::TextFormatPara
:
1847 ::sal_uInt32 n
= static_cast< ::sal_uInt32
>( aHint
.GetValue() );
1848 assert(n
< m_aParagraphs
.size() && "Bad SfxHintId::TextFormatPara event");
1850 m_aParagraphs
[static_cast< Paragraphs::size_type
>(n
)].
1851 changeHeight(static_cast< ::sal_Int32
>(
1852 m_rEngine
.GetTextHeight(n
)));
1853 // XXX numeric overflow
1854 Paragraphs::iterator
aOldVisibleBegin(visibleBegin());
1855 Paragraphs::iterator
aOldVisibleEnd(visibleEnd());
1856 determineVisibleRange();
1857 notifyVisibleRangeChanges(aOldVisibleBegin
, aOldVisibleEnd
,
1858 m_aParagraphs
.end());
1860 if (n
< m_aParagraphs
.size())
1862 Paragraphs::iterator
aIt(m_aParagraphs
.begin() + n
);
1863 ::rtl::Reference
< Paragraph
> xParagraph(getParagraph(aIt
));
1864 if (xParagraph
.is())
1865 xParagraph
->textChanged();
1870 SAL_WARN("accessibility", "bad buffered hint");
1874 m_bInParagraphNotificationsHandler
= false;
1875 if (m_bSelectionChangedNotification
)
1877 m_bSelectionChangedNotification
= false;
1878 handleSelectionChangeNotification();
1885 enum class SelChangeType
1887 None
, // no change, or invalid
1888 CaretMove
, // neither old nor new have selection, and they are different
1889 NoSelToSel
, // old has no selection but new has selection
1890 SelToNoSel
, // old has selection but new has no selection
1891 // both old and new have selections
1892 NoParaChange
, // only end index changed inside end para
1893 EndParaNoMoreBehind
, // end para was behind start, but now is same or ahead
1894 AddedFollowingPara
, // selection extended to following paragraph(s)
1895 ExcludedPreviousPara
, // selection shrunk excluding previous paragraph(s)
1896 ExcludedFollowingPara
, // selection shrunk excluding following paragraph(s)
1897 AddedPreviousPara
, // selection extended to previous paragraph(s)
1898 EndParaBecameBehind
// end para was ahead of start, but now is behind
1901 SelChangeType
getSelChangeType(const TextPaM
& Os
, const TextPaM
& Oe
,
1902 const TextPaM
& Ns
, const TextPaM
& Ne
)
1904 if (Os
== Oe
) // no old selection
1906 if (Ns
== Ne
) // no new selection: only caret moves
1907 return Os
!= Ns
? SelChangeType::CaretMove
: SelChangeType::None
;
1908 else // old has no selection but new has selection
1909 return SelChangeType::NoSelToSel
;
1911 else if (Ns
== Ne
) // old has selection; no new selection
1913 return SelChangeType::SelToNoSel
;
1915 else if (Os
== Ns
) // both old and new have selections, and their starts are same
1917 const sal_Int32 Osp
= Os
.GetPara(), Oep
= Oe
.GetPara();
1918 const sal_Int32 Nsp
= Ns
.GetPara(), Nep
= Ne
.GetPara();
1919 if (Oep
== Nep
) // end of selection stays in the same paragraph
1921 //Send text_selection_change event on Nep
1922 return Oe
.GetIndex() != Ne
.GetIndex() ? SelChangeType::NoParaChange
1923 : SelChangeType::None
;
1925 else if (Oep
< Nep
) // end of selection moved to a following paragraph
1927 //all the following examples like 1,2->1,3 means that old start select para is 1, old end select para is 2,
1928 // then press shift up, the new start select para is 1, new end select para is 3;
1929 //for example, 1, 2 -> 1, 3; 4,1 -> 4, 7; 4,1 -> 4, 2; 4,4->4,5
1930 if (Nep
>= Nsp
) // new end para not behind start
1932 // 1, 2 -> 1, 3; 4, 1 -> 4, 7; 4,4->4,5;
1933 if (Oep
< Osp
) // old end was behind start
1935 // 4,1 -> 4,7; 4,1 -> 4,4
1936 return SelChangeType::EndParaNoMoreBehind
;
1938 else // old end para wasn't behind start
1940 // 1, 2 -> 1, 3; 4,4->4,5;
1941 return SelChangeType::AddedFollowingPara
;
1944 else // new end para is still behind start
1947 return SelChangeType::ExcludedPreviousPara
;
1950 else // Oep > Nep => end of selection moved to a previous paragraph
1952 // 3,2 -> 3,1; 4,7 -> 4,1; 4, 7 -> 4,6; 4,4 -> 4,3
1953 if (Nep
>= Nsp
) // new end para is still not behind of start
1956 return SelChangeType::ExcludedFollowingPara
;
1958 else // new end para is behind start
1960 // 3,2 -> 3,1, 4,7 -> 4,1; 4,4->4,3
1961 if (Oep
<= Osp
) // it was not ahead already
1963 // 3,2 -> 3,1; 4,4->4,3
1964 return SelChangeType::AddedPreviousPara
;
1966 else // it was ahead previously
1969 return SelChangeType::EndParaBecameBehind
;
1974 return SelChangeType::None
;
1979 void Document::sendEvent(::sal_Int32 start
, ::sal_Int32 end
, ::sal_Int16 nEventId
)
1981 size_t nAvailDistance
= std::distance(m_aParagraphs
.begin(), visibleEnd());
1983 Paragraphs::iterator
aEnd(m_aParagraphs
.begin());
1984 size_t nEndDistance
= std::min
<size_t>(end
+ 1, nAvailDistance
);
1985 std::advance(aEnd
, nEndDistance
);
1987 Paragraphs::iterator
aIt(m_aParagraphs
.begin());
1988 size_t nStartDistance
= std::min
<size_t>(start
, nAvailDistance
);
1989 std::advance(aIt
, nStartDistance
);
1993 ::rtl::Reference
< Paragraph
> xParagraph(getParagraph(aIt
));
1994 if (xParagraph
.is())
1995 xParagraph
->notifyEvent(
1997 css::uno::Any(), css::uno::Any());
2002 void Document::handleSelectionChangeNotification()
2004 ::TextSelection
const & rSelection
= m_rView
.GetSelection();
2005 assert(rSelection
.GetStart().GetPara() < m_aParagraphs
.size() &&
2006 rSelection
.GetEnd().GetPara() < m_aParagraphs
.size() &&
2007 "bad SfxHintId::TextViewSelectionChanged event");
2008 ::sal_Int32 nNewFirstPara
2009 = static_cast< ::sal_Int32
>(rSelection
.GetStart().GetPara());
2010 ::sal_Int32 nNewFirstPos
= rSelection
.GetStart().GetIndex();
2011 // XXX numeric overflow
2012 ::sal_Int32 nNewLastPara
2013 = static_cast< ::sal_Int32
>(rSelection
.GetEnd().GetPara());
2014 ::sal_Int32 nNewLastPos
= rSelection
.GetEnd().GetIndex();
2015 // XXX numeric overflow
2018 Paragraphs::iterator
aIt(getIter(nNewLastPara
));
2019 if (m_nFocused
< m_aParagraphs
.size() && focused() != aIt
2020 && m_nFocused
>= m_nVisibleBegin
&& m_nFocused
< m_nVisibleEnd
)
2022 ::rtl::Reference
< Paragraph
> xParagraph(getParagraph(focused()));
2023 if (xParagraph
.is())
2024 xParagraph
->notifyEvent(
2025 css::accessibility::AccessibleEventId::
2028 css::accessibility::AccessibleStateType::FOCUSED
),
2032 // Gain focus and update cursor position:
2033 if (aIt
>= visibleBegin() && aIt
< visibleEnd()
2034 && (aIt
!= focused()
2035 || nNewLastPara
!= m_nSelectionLastPara
2036 || nNewLastPos
!= m_nSelectionLastPos
))
2038 ::rtl::Reference
< Paragraph
> xParagraph(getParagraph(aIt
));
2039 if (xParagraph
.is())
2041 //disable the first event when user types in empty field.
2042 sal_Int64 count
= getAccessibleChildCount();
2043 bool bEmpty
= count
> 1;
2044 if (aIt
!= focused() && bEmpty
)
2045 xParagraph
->notifyEvent(
2046 css::accessibility::AccessibleEventId::
2050 css::accessibility::AccessibleStateType::FOCUSED
));
2051 if (nNewLastPara
!= m_nSelectionLastPara
2052 || nNewLastPos
!= m_nSelectionLastPos
)
2053 xParagraph
->notifyEvent(
2054 css::accessibility::AccessibleEventId::
2056 css::uno::Any( ::sal_Int32 (
2057 nNewLastPara
== m_nSelectionLastPara
2058 ? m_nSelectionLastPos
: 0)),
2059 css::uno::Any(nNewLastPos
));
2062 m_nFocused
= std::distance(m_aParagraphs
.begin(), aIt
);
2064 if (m_nSelectionFirstPara
!= -1)
2068 SelChangeType ret
= getSelChangeType(TextPaM(m_nSelectionFirstPara
, m_nSelectionFirstPos
),
2069 TextPaM(m_nSelectionLastPara
, m_nSelectionLastPos
),
2070 rSelection
.GetStart(), rSelection
.GetEnd());
2073 case SelChangeType::None
:
2076 case SelChangeType::CaretMove
:
2077 //only caret moved, already handled in above
2079 case SelChangeType::NoSelToSel
:
2080 //old has no selection but new has selection
2081 nMin
= std::min(nNewFirstPara
, nNewLastPara
);
2082 nMax
= std::max(nNewFirstPara
, nNewLastPara
);
2083 sendEvent(nMin
, nMax
, css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2084 sendEvent(nMin
, nMax
,
2085 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2087 case SelChangeType::SelToNoSel
:
2088 //old has selection but new has no selection.
2089 nMin
= std::min(m_nSelectionFirstPara
, m_nSelectionLastPara
);
2090 nMax
= std::max(m_nSelectionFirstPara
, m_nSelectionLastPara
);
2091 sendEvent(nMin
, nMax
, css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2092 sendEvent(nMin
, nMax
,
2093 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2095 case SelChangeType::NoParaChange
:
2096 //Send text_selection_change event on Nep
2097 sendEvent(nNewLastPara
, nNewLastPara
,
2098 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2100 case SelChangeType::EndParaNoMoreBehind
:
2101 // 4, 1 -> 4, 7; 4,1 -> 4,4
2102 sendEvent(m_nSelectionLastPara
, m_nSelectionFirstPara
- 1,
2103 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2104 sendEvent(nNewFirstPara
+ 1, nNewLastPara
,
2105 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2107 sendEvent(m_nSelectionLastPara
, nNewLastPara
,
2108 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2110 case SelChangeType::AddedFollowingPara
:
2111 // 1, 2 -> 1, 4; 4,4->4,5;
2112 sendEvent(m_nSelectionLastPara
+ 1, nNewLastPara
,
2113 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2115 sendEvent(m_nSelectionLastPara
, nNewLastPara
,
2116 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2118 case SelChangeType::ExcludedPreviousPara
:
2120 sendEvent(m_nSelectionLastPara
+ 1, nNewLastPara
,
2121 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2123 sendEvent(m_nSelectionLastPara
, nNewLastPara
,
2124 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2126 case SelChangeType::ExcludedFollowingPara
:
2128 sendEvent(nNewLastPara
+ 1, m_nSelectionLastPara
,
2129 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2131 sendEvent(nNewLastPara
, m_nSelectionLastPara
,
2132 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2134 case SelChangeType::AddedPreviousPara
:
2135 // 3,2 -> 3,1; 4,4->4,3
2136 sendEvent(nNewLastPara
, m_nSelectionLastPara
- 1,
2137 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2139 sendEvent(nNewLastPara
, m_nSelectionLastPara
,
2140 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2142 case SelChangeType::EndParaBecameBehind
:
2144 sendEvent(m_nSelectionFirstPara
+ 1, m_nSelectionLastPara
,
2145 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2146 sendEvent(nNewLastPara
, nNewFirstPara
- 1,
2147 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2149 sendEvent(nNewLastPara
, m_nSelectionLastPara
,
2150 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2155 m_nSelectionFirstPara
= nNewFirstPara
;
2156 m_nSelectionFirstPos
= nNewFirstPos
;
2157 m_nSelectionLastPara
= nNewLastPara
;
2158 m_nSelectionLastPos
= nNewLastPos
;
2161 void Document::disposeParagraphs()
2163 for (auto const& paragraph
: m_aParagraphs
)
2165 rtl::Reference
< Paragraph
> xComponent(
2166 paragraph
.getParagraph().get() );
2167 if (xComponent
.is())
2168 xComponent
->dispose();
2173 css::uno::Any
Document::mapFontColor(::Color
const & rColor
)
2175 return css::uno::Any(rColor
.GetRGBColor());
2176 // FIXME keep transparency?
2180 ::Color
Document::mapFontColor(css::uno::Any
const & rColor
)
2188 css::uno::Any
Document::mapFontWeight(::FontWeight nWeight
)
2190 // Map from ::FontWeight to css::awt::FontWeight, depends on order of
2191 // elements in ::FontWeight (vcl/vclenum.hxx):
2192 static float const aWeight
[]
2193 = { css::awt::FontWeight::DONTKNOW
, // WEIGHT_DONTKNOW
2194 css::awt::FontWeight::THIN
, // WEIGHT_THIN
2195 css::awt::FontWeight::ULTRALIGHT
, // WEIGHT_ULTRALIGHT
2196 css::awt::FontWeight::LIGHT
, // WEIGHT_LIGHT
2197 css::awt::FontWeight::SEMILIGHT
, // WEIGHT_SEMILIGHT
2198 css::awt::FontWeight::NORMAL
, // WEIGHT_NORMAL
2199 css::awt::FontWeight::NORMAL
, // WEIGHT_MEDIUM
2200 css::awt::FontWeight::SEMIBOLD
, // WEIGHT_SEMIBOLD
2201 css::awt::FontWeight::BOLD
, // WEIGHT_BOLD
2202 css::awt::FontWeight::ULTRABOLD
, // WEIGHT_ULTRABOLD
2203 css::awt::FontWeight::BLACK
}; // WEIGHT_BLACK
2204 return css::uno::Any(aWeight
[nWeight
]);
2208 ::FontWeight
Document::mapFontWeight(css::uno::Any
const & rWeight
)
2210 float nWeight
= css::awt::FontWeight::NORMAL
;
2211 rWeight
>>= nWeight
;
2212 return nWeight
<= css::awt::FontWeight::DONTKNOW
? WEIGHT_DONTKNOW
2213 : nWeight
<= css::awt::FontWeight::THIN
? WEIGHT_THIN
2214 : nWeight
<= css::awt::FontWeight::ULTRALIGHT
? WEIGHT_ULTRALIGHT
2215 : nWeight
<= css::awt::FontWeight::LIGHT
? WEIGHT_LIGHT
2216 : nWeight
<= css::awt::FontWeight::SEMILIGHT
? WEIGHT_SEMILIGHT
2217 : nWeight
<= css::awt::FontWeight::NORMAL
? WEIGHT_NORMAL
2218 : nWeight
<= css::awt::FontWeight::SEMIBOLD
? WEIGHT_SEMIBOLD
2219 : nWeight
<= css::awt::FontWeight::BOLD
? WEIGHT_BOLD
2220 : nWeight
<= css::awt::FontWeight::ULTRABOLD
? WEIGHT_ULTRABOLD
2226 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */