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>
21 #include <sal/log.hxx>
23 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
24 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
25 #include <com/sun/star/accessibility/AccessibleRole.hpp>
26 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
27 #include <com/sun/star/awt/FontWeight.hpp>
28 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
29 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
30 #include <com/sun/star/i18n/Boundary.hpp>
31 #include <cppuhelper/exc_hlp.hxx>
32 #include <extended/textwindowaccessibility.hxx>
33 #include <comphelper/accessibleeventnotifier.hxx>
34 #include <unotools/accessiblerelationsethelper.hxx>
35 #include <unotools/accessiblestatesethelper.hxx>
36 #include <vcl/svapp.hxx>
37 #include <vcl/txtattr.hxx>
38 #include <vcl/window.hxx>
39 #include <tools/diagnose_ex.h>
40 #include <toolkit/helper/convert.hxx>
41 #include <comphelper/sequence.hxx>
48 namespace accessibility
50 void SfxListenerGuard::startListening(::SfxBroadcaster
& rNotifier
)
52 assert(m_pNotifier
== nullptr && "called more than once");
53 m_pNotifier
= &rNotifier
;
54 m_rListener
.StartListening(*m_pNotifier
, DuplicateHandling::Prevent
);
57 void SfxListenerGuard::endListening()
59 if (m_pNotifier
!= nullptr)
61 m_rListener
.EndListening(*m_pNotifier
);
62 m_pNotifier
= nullptr;
66 void WindowListenerGuard::startListening(vcl::Window
& rNotifier
)
68 assert(m_pNotifier
== nullptr && "called more than once");
69 m_pNotifier
= &rNotifier
;
70 m_pNotifier
->AddEventListener(m_aListener
);
73 void WindowListenerGuard::endListening()
77 m_pNotifier
->RemoveEventListener(m_aListener
);
78 m_pNotifier
= nullptr;
82 Paragraph::Paragraph(::rtl::Reference
< Document
> const & rDocument
,
83 Paragraphs::size_type nNumber
):
84 ParagraphBase(m_aMutex
),
85 m_xDocument(rDocument
),
89 m_aParagraphText
= m_xDocument
->retrieveParagraphText(this);
93 Paragraph::numberChanged(bool bIncremented
)
101 void Paragraph::textChanged()
103 OUString aParagraphText
= implGetText();
104 css::uno::Any aOldValue
, aNewValue
;
105 if ( implInitTextChangedEvent( m_aParagraphText
, aParagraphText
, aOldValue
, aNewValue
) )
107 m_aParagraphText
= aParagraphText
;
108 notifyEvent(css::accessibility::AccessibleEventId::
110 aOldValue
, aNewValue
);
114 void Paragraph::notifyEvent(::sal_Int16 nEventId
,
115 css::uno::Any
const & rOldValue
,
116 css::uno::Any
const & rNewValue
)
119 comphelper::AccessibleEventNotifier::addEvent( m_nClientId
, css::accessibility::AccessibleEventObject(
120 static_cast< ::cppu::OWeakObject
* >(this),
121 nEventId
, rNewValue
, rOldValue
) );
125 css::uno::Reference
< css::accessibility::XAccessibleContext
> SAL_CALL
126 Paragraph::getAccessibleContext()
133 ::sal_Int32 SAL_CALL
Paragraph::getAccessibleChildCount()
140 css::uno::Reference
< css::accessibility::XAccessible
> SAL_CALL
141 Paragraph::getAccessibleChild(::sal_Int32
)
144 throw css::lang::IndexOutOfBoundsException(
145 "textwindowaccessibility.cxx:"
146 " Paragraph::getAccessibleChild",
147 static_cast< css::uno::XWeak
* >(this));
151 css::uno::Reference
< css::accessibility::XAccessible
> SAL_CALL
152 Paragraph::getAccessibleParent()
155 return m_xDocument
->getAccessible();
159 ::sal_Int32 SAL_CALL
Paragraph::getAccessibleIndexInParent()
162 return m_xDocument
->retrieveParagraphIndex(this);
166 ::sal_Int16 SAL_CALL
Paragraph::getAccessibleRole()
169 return css::accessibility::AccessibleRole::PARAGRAPH
;
173 OUString SAL_CALL
Paragraph::getAccessibleDescription()
180 OUString SAL_CALL
Paragraph::getAccessibleName()
187 css::uno::Reference
< css::accessibility::XAccessibleRelationSet
>
188 SAL_CALL
Paragraph::getAccessibleRelationSet()
191 return m_xDocument
->retrieveParagraphRelationSet( this );
195 css::uno::Reference
< css::accessibility::XAccessibleStateSet
>
196 SAL_CALL
Paragraph::getAccessibleStateSet()
200 // FIXME Notification of changes (STATE_CHANGED) missing when
201 // m_rView.IsReadOnly() changes:
202 return new ::utl::AccessibleStateSetHelper(
203 m_xDocument
->retrieveParagraphState(this));
207 css::lang::Locale SAL_CALL
Paragraph::getLocale()
210 return m_xDocument
->retrieveLocale();
214 sal_Bool SAL_CALL
Paragraph::containsPoint(css::awt::Point
const & rPoint
)
217 css::awt::Rectangle
aRect(m_xDocument
->retrieveParagraphBounds(this,
219 return rPoint
.X
>= 0 && rPoint
.X
< aRect
.Width
220 && rPoint
.Y
>= 0 && rPoint
.Y
< aRect
.Height
;
224 css::uno::Reference
< css::accessibility::XAccessible
> SAL_CALL
225 Paragraph::getAccessibleAtPoint(css::awt::Point
const &)
232 css::awt::Rectangle SAL_CALL
Paragraph::getBounds()
235 return m_xDocument
->retrieveParagraphBounds(this, false);
239 css::awt::Point SAL_CALL
Paragraph::getLocation()
242 css::awt::Rectangle
aRect(m_xDocument
->retrieveParagraphBounds(this,
244 return css::awt::Point(aRect
.X
, aRect
.Y
);
248 css::awt::Point SAL_CALL
Paragraph::getLocationOnScreen()
251 css::awt::Rectangle
aRect(m_xDocument
->retrieveParagraphBounds(this,
253 return css::awt::Point(aRect
.X
, aRect
.Y
);
257 css::awt::Size SAL_CALL
Paragraph::getSize()
260 css::awt::Rectangle
aRect(m_xDocument
->retrieveParagraphBounds(this,
262 return css::awt::Size(aRect
.Width
, aRect
.Height
);
266 void SAL_CALL
Paragraph::grabFocus()
269 VclPtr
<vcl::Window
> pWindow
= m_xDocument
->GetWindow();
272 pWindow
->GrabFocus();
276 m_xDocument
->changeParagraphSelection(this, 0, 0);
278 catch (const css::lang::IndexOutOfBoundsException
&)
280 TOOLS_INFO_EXCEPTION("accessibility", "Paragraph::grabFocus: caught unexpected");
285 sal_Int32 SAL_CALL
Paragraph::getForeground()
291 sal_Int32 SAL_CALL
Paragraph::getBackground()
297 ::sal_Int32 SAL_CALL
Paragraph::getCaretPosition()
300 return m_xDocument
->retrieveParagraphCaretPosition(this);
304 sal_Bool SAL_CALL
Paragraph::setCaretPosition(::sal_Int32 nIndex
)
307 m_xDocument
->changeParagraphSelection(this, nIndex
, nIndex
);
312 ::sal_Unicode SAL_CALL
Paragraph::getCharacter(::sal_Int32 nIndex
)
315 return OCommonAccessibleText::implGetCharacter(implGetText(), nIndex
);
319 css::uno::Sequence
< css::beans::PropertyValue
> SAL_CALL
320 Paragraph::getCharacterAttributes(::sal_Int32 nIndex
, const css::uno::Sequence
< OUString
>& aRequestedAttributes
)
323 return m_xDocument
->retrieveCharacterAttributes( this, nIndex
, aRequestedAttributes
);
327 css::awt::Rectangle SAL_CALL
328 Paragraph::getCharacterBounds(::sal_Int32 nIndex
)
331 css::awt::Rectangle
aBounds(m_xDocument
->retrieveCharacterBounds(this, nIndex
));
332 css::awt::Rectangle
aParaBounds(m_xDocument
->retrieveParagraphBounds(this, false));
333 aBounds
.X
-= aParaBounds
.X
;
334 aBounds
.Y
-= aParaBounds
.Y
;
339 ::sal_Int32 SAL_CALL
Paragraph::getCharacterCount()
342 return implGetText().getLength();
347 Paragraph::getIndexAtPoint(css::awt::Point
const & rPoint
)
350 css::awt::Point
aPoint(rPoint
);
351 css::awt::Rectangle
aParaBounds(m_xDocument
->retrieveParagraphBounds(this, false));
352 aPoint
.X
+= aParaBounds
.X
;
353 aPoint
.Y
+= aParaBounds
.Y
;
354 return m_xDocument
->retrieveCharacterIndex(this, aPoint
);
358 OUString SAL_CALL
Paragraph::getSelectedText()
362 return OCommonAccessibleText::getSelectedText();
366 ::sal_Int32 SAL_CALL
Paragraph::getSelectionStart()
369 return OCommonAccessibleText::getSelectionStart();
373 ::sal_Int32 SAL_CALL
Paragraph::getSelectionEnd()
376 return OCommonAccessibleText::getSelectionEnd();
380 sal_Bool SAL_CALL
Paragraph::setSelection(::sal_Int32 nStartIndex
,
381 ::sal_Int32 nEndIndex
)
384 m_xDocument
->changeParagraphSelection(this, nStartIndex
, nEndIndex
);
389 OUString SAL_CALL
Paragraph::getText()
392 return implGetText();
396 OUString SAL_CALL
Paragraph::getTextRange(::sal_Int32 nStartIndex
,
397 ::sal_Int32 nEndIndex
)
400 return OCommonAccessibleText::implGetTextRange(implGetText(), nStartIndex
, nEndIndex
);
404 css::accessibility::TextSegment SAL_CALL
Paragraph::getTextAtIndex( sal_Int32 nIndex
, sal_Int16 aTextType
)
407 return OCommonAccessibleText::getTextAtIndex(nIndex
, aTextType
);
411 css::accessibility::TextSegment SAL_CALL
Paragraph::getTextBeforeIndex( sal_Int32 nIndex
, sal_Int16 aTextType
)
414 return OCommonAccessibleText::getTextBeforeIndex(nIndex
, aTextType
);
418 css::accessibility::TextSegment SAL_CALL
Paragraph::getTextBehindIndex( sal_Int32 nIndex
, sal_Int16 aTextType
)
421 return OCommonAccessibleText::getTextBehindIndex(nIndex
, aTextType
);
425 sal_Bool SAL_CALL
Paragraph::copyText(::sal_Int32 nStartIndex
,
426 ::sal_Int32 nEndIndex
)
429 m_xDocument
->copyParagraphText(this, nStartIndex
, nEndIndex
);
434 sal_Bool SAL_CALL
Paragraph::scrollSubstringTo( sal_Int32
, sal_Int32
, css::accessibility::AccessibleScrollType
)
440 sal_Bool SAL_CALL
Paragraph::cutText(::sal_Int32 nStartIndex
,
441 ::sal_Int32 nEndIndex
)
444 m_xDocument
->changeParagraphText(this, nStartIndex
, nEndIndex
, true, false,
450 sal_Bool SAL_CALL
Paragraph::pasteText(::sal_Int32 nIndex
)
453 m_xDocument
->changeParagraphText(this, nIndex
, nIndex
, false, true,
459 sal_Bool SAL_CALL
Paragraph::deleteText(::sal_Int32 nStartIndex
,
460 ::sal_Int32 nEndIndex
)
463 m_xDocument
->changeParagraphText(this, nStartIndex
, nEndIndex
, false, false,
469 sal_Bool SAL_CALL
Paragraph::insertText(OUString
const & rText
,
473 m_xDocument
->changeParagraphText(this, nIndex
, nIndex
, false, false, rText
);
479 Paragraph::replaceText(::sal_Int32 nStartIndex
, ::sal_Int32 nEndIndex
,
480 OUString
const & rReplacement
)
483 m_xDocument
->changeParagraphText(this, nStartIndex
, nEndIndex
, false, false,
489 sal_Bool SAL_CALL
Paragraph::setAttributes(
490 ::sal_Int32 nStartIndex
, ::sal_Int32 nEndIndex
,
491 css::uno::Sequence
< css::beans::PropertyValue
> const & rAttributeSet
)
494 m_xDocument
->changeParagraphAttributes(this, nStartIndex
, nEndIndex
,
500 sal_Bool SAL_CALL
Paragraph::setText(OUString
const & rText
)
503 m_xDocument
->changeParagraphText(this, rText
);
508 css::uno::Sequence
< css::beans::PropertyValue
> SAL_CALL
509 Paragraph::getDefaultAttributes(const css::uno::Sequence
< OUString
>&)
512 return {}; // default attributes are not supported by text engine
516 css::uno::Sequence
< css::beans::PropertyValue
> SAL_CALL
517 Paragraph::getRunAttributes(::sal_Int32 Index
, const css::uno::Sequence
< OUString
>& RequestedAttributes
)
520 return m_xDocument
->retrieveRunAttributes( this, Index
, RequestedAttributes
);
524 ::sal_Int32 SAL_CALL
Paragraph::getLineNumberAtIndex( ::sal_Int32 nIndex
)
528 ::sal_Int32 nLineNo
= -1;
529 m_xDocument
->retrieveParagraphLineBoundary( this, nIndex
, &nLineNo
);
535 css::accessibility::TextSegment SAL_CALL
Paragraph::getTextAtLineNumber( ::sal_Int32 nLineNo
)
539 css::i18n::Boundary aBoundary
=
540 m_xDocument
->retrieveParagraphBoundaryOfLine( this, nLineNo
);
542 return css::accessibility::TextSegment( getTextRange(aBoundary
.startPos
, aBoundary
.endPos
),
543 aBoundary
.startPos
, aBoundary
.endPos
);
547 css::accessibility::TextSegment SAL_CALL
Paragraph::getTextAtLineWithCaret( )
551 sal_Int32 nLineNo
= getNumberOfLineWithCaret();
554 return ( nLineNo
>= 0 ) ?
555 getTextAtLineNumber( nLineNo
) :
556 css::accessibility::TextSegment();
557 } catch (const css::lang::IndexOutOfBoundsException
&) {
558 css::uno::Any anyEx
= cppu::getCaughtException();
559 throw css::lang::WrappedTargetRuntimeException(
560 "textwindowaccessibility.cxx:"
561 " Paragraph::getTextAtLineWithCaret",
562 static_cast< css::uno::XWeak
* >( this ), anyEx
);
567 ::sal_Int32 SAL_CALL
Paragraph::getNumberOfLineWithCaret( )
570 return m_xDocument
->retrieveParagraphLineWithCursor(this);
575 void SAL_CALL
Paragraph::addAccessibleEventListener(
577 css::accessibility::XAccessibleEventListener
> const & rListener
)
582 ::osl::ClearableMutexGuard
aGuard(rBHelper
.rMutex
);
583 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
586 rListener
->disposing(css::lang::EventObject(
587 static_cast< ::cppu::OWeakObject
* >(this)));
592 m_nClientId
= comphelper::AccessibleEventNotifier::registerClient( );
593 comphelper::AccessibleEventNotifier::addEventListener( m_nClientId
, rListener
);
598 void SAL_CALL
Paragraph::removeAccessibleEventListener(
600 css::accessibility::XAccessibleEventListener
> const & rListener
)
602 comphelper::AccessibleEventNotifier::TClientId nId
= 0;
604 osl::MutexGuard
aGuard(rBHelper
.rMutex
);
605 if (rListener
.is() && m_nClientId
!= 0
606 && comphelper::AccessibleEventNotifier::removeEventListener( m_nClientId
, rListener
) == 0)
614 // no listeners anymore
615 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
616 // and at least to us not firing any events anymore, in case somebody calls
617 // NotifyAccessibleEvent, again
618 comphelper::AccessibleEventNotifier::revokeClient(nId
);
623 void SAL_CALL
Paragraph::disposing()
625 comphelper::AccessibleEventNotifier::TClientId nId
= 0;
627 osl::MutexGuard
aGuard(rBHelper
.rMutex
);
632 comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing(nId
, *this);
636 OUString
Paragraph::implGetText()
638 return m_xDocument
->retrieveParagraphText(this);
642 css::lang::Locale
Paragraph::implGetLocale()
644 return m_xDocument
->retrieveLocale();
648 void Paragraph::implGetSelection(::sal_Int32
& rStartIndex
,
649 ::sal_Int32
& rEndIndex
)
651 m_xDocument
->retrieveParagraphSelection(this, &rStartIndex
, &rEndIndex
);
655 void Paragraph::implGetParagraphBoundary( const OUString
& rText
,
656 css::i18n::Boundary
& rBoundary
,
659 ::sal_Int32 nLength
= rText
.getLength();
661 if ( implIsValidIndex( nIndex
, nLength
) )
663 rBoundary
.startPos
= 0;
664 rBoundary
.endPos
= nLength
;
668 rBoundary
.startPos
= nIndex
;
669 rBoundary
.endPos
= nIndex
;
674 void Paragraph::implGetLineBoundary( const OUString
& rText
,
675 css::i18n::Boundary
& rBoundary
,
678 ::sal_Int32 nLength
= rText
.getLength();
680 if ( implIsValidIndex( nIndex
, nLength
) || nIndex
== nLength
)
682 css::i18n::Boundary aBoundary
=
683 m_xDocument
->retrieveParagraphLineBoundary( this, nIndex
, nullptr );
684 rBoundary
.startPos
= aBoundary
.startPos
;
685 rBoundary
.endPos
= aBoundary
.endPos
;
689 rBoundary
.startPos
= nIndex
;
690 rBoundary
.endPos
= nIndex
;
695 void Paragraph::checkDisposed()
697 ::osl::MutexGuard
aGuard(rBHelper
.rMutex
);
698 if (!(rBHelper
.bDisposed
|| rBHelper
.bInDispose
))
700 throw css::lang::DisposedException(
701 OUString(), static_cast< css::uno::XWeak
* >(this));
704 Document::Document(::VCLXWindow
* pVclXWindow
, ::TextEngine
& rEngine
,
706 VCLXAccessibleComponent(pVclXWindow
),
707 m_xAccessible(pVclXWindow
),
710 m_aEngineListener(*this),
711 m_aViewListener(LINK(this, Document
, WindowEventHandler
)),
714 m_nVisibleBeginOffset(0),
715 m_nSelectionFirstPara(-1),
716 m_nSelectionFirstPos(-1),
717 m_nSelectionLastPara(-1),
718 m_nSelectionLastPos(-1),
719 m_bSelectionChangedNotification(false)
722 css::lang::Locale
Document::retrieveLocale()
724 SolarMutexGuard aGuard
;
725 return m_rEngine
.GetLocale();
728 ::sal_Int32
Document::retrieveParagraphIndex(Paragraph
const * pParagraph
)
730 ::osl::MutexGuard
aInternalGuard(GetMutex());
732 // If a client holds on to a Paragraph that is no longer visible, it can
733 // happen that this Paragraph lies outside the range from m_aVisibleBegin
734 // to m_aVisibleEnd. In that case, return -1 instead of a valid index:
735 Paragraphs::iterator
aPara(m_xParagraphs
->begin()
736 + pParagraph
->getNumber());
737 return aPara
< m_aVisibleBegin
|| aPara
>= m_aVisibleEnd
738 ? -1 : static_cast< ::sal_Int32
>(aPara
- m_aVisibleBegin
);
739 // XXX numeric overflow
742 ::sal_Int64
Document::retrieveParagraphState(Paragraph
const * pParagraph
)
744 ::osl::MutexGuard
aInternalGuard(GetMutex());
746 // If a client holds on to a Paragraph that is no longer visible, it can
747 // happen that this Paragraph lies outside the range from m_aVisibleBegin
748 // to m_aVisibleEnd. In that case, it is neither VISIBLE nor SHOWING:
750 = (static_cast< ::sal_Int64
>(1)
751 << css::accessibility::AccessibleStateType::ENABLED
)
752 | (static_cast< ::sal_Int64
>(1)
753 << css::accessibility::AccessibleStateType::SENSITIVE
)
754 | (static_cast< ::sal_Int64
>(1)
755 << css::accessibility::AccessibleStateType::FOCUSABLE
)
756 | (static_cast< ::sal_Int64
>(1)
757 << css::accessibility::AccessibleStateType::MULTI_LINE
);
758 if (!m_rView
.IsReadOnly())
759 nState
|= (static_cast< ::sal_Int64
>(1)
760 << css::accessibility::AccessibleStateType::EDITABLE
);
761 Paragraphs::iterator
aPara(m_xParagraphs
->begin()
762 + pParagraph
->getNumber());
763 if (aPara
>= m_aVisibleBegin
&& aPara
< m_aVisibleEnd
)
766 |= (static_cast< ::sal_Int64
>(1)
767 << css::accessibility::AccessibleStateType::VISIBLE
)
768 | (static_cast< ::sal_Int64
>(1)
769 << css::accessibility::AccessibleStateType::SHOWING
);
770 if (aPara
== m_aFocused
)
771 nState
|= (static_cast< ::sal_Int64
>(1)
772 << css::accessibility::AccessibleStateType::FOCUSED
);
778 Document::retrieveParagraphBounds(Paragraph
const * pParagraph
,
781 SolarMutexGuard aGuard
;
782 ::osl::MutexGuard
aInternalGuard(GetMutex());
784 // If a client holds on to a Paragraph that is no longer visible (as it
785 // scrolled out the top of the view), it can happen that this Paragraph
786 // lies before m_aVisibleBegin. In that case, calculate the vertical
787 // position of the Paragraph starting at paragraph 0, otherwise optimize
788 // and start at m_aVisibleBegin:
789 Paragraphs::iterator
aPara(m_xParagraphs
->begin()
790 + pParagraph
->getNumber());
791 auto lAddHeight
= [](const sal_Int32
& rSum
, const ParagraphInfo
& rParagraph
) {
792 return rSum
+ rParagraph
.getHeight(); };
794 if (aPara
< m_aVisibleBegin
)
795 nPos
= std::accumulate(m_xParagraphs
->begin(), aPara
, sal_Int32(0), lAddHeight
);
797 nPos
= std::accumulate(m_aVisibleBegin
, aPara
, m_nViewOffset
- m_nVisibleBeginOffset
, lAddHeight
);
801 aOrig
= m_rView
.GetWindow()->OutputToAbsoluteScreenPixel(aOrig
);
803 return css::awt::Rectangle(
804 static_cast< ::sal_Int32
>(aOrig
.X()),
805 static_cast< ::sal_Int32
>(aOrig
.Y()) + nPos
- m_nViewOffset
,
806 m_rView
.GetWindow()->GetOutputSizePixel().Width(), aPara
->getHeight());
807 // XXX numeric overflow (3x)
811 Document::retrieveParagraphText(Paragraph
const * pParagraph
)
813 SolarMutexGuard aGuard
;
814 ::osl::MutexGuard
aInternalGuard(GetMutex());
815 return m_rEngine
.GetText(static_cast< ::sal_uInt32
>(pParagraph
->getNumber()));
816 // numeric overflow cannot happen here
819 void Document::retrieveParagraphSelection(Paragraph
const * pParagraph
,
820 ::sal_Int32
* pBegin
,
823 SolarMutexGuard aGuard
;
824 ::osl::MutexGuard
aInternalGuard(GetMutex());
825 ::TextSelection
const & rSelection
= m_rView
.GetSelection();
826 Paragraphs::size_type nNumber
= pParagraph
->getNumber();
827 TextPaM
aStartPaM( rSelection
.GetStart() );
828 TextPaM
aEndPaM( rSelection
.GetEnd() );
829 TextPaM
aMinPaM( std::min( aStartPaM
, aEndPaM
) );
830 TextPaM
aMaxPaM( std::max( aStartPaM
, aEndPaM
) );
832 if ( nNumber
>= aMinPaM
.GetPara() && nNumber
<= aMaxPaM
.GetPara() )
834 *pBegin
= nNumber
> aMinPaM
.GetPara() ? 0 : aMinPaM
.GetIndex();
835 // XXX numeric overflow
836 *pEnd
= nNumber
< aMaxPaM
.GetPara()
837 ? m_rEngine
.GetText(static_cast< ::sal_uInt32
>(nNumber
)).getLength()
838 : aMaxPaM
.GetIndex();
839 // XXX numeric overflow (3x)
841 if ( aStartPaM
> aEndPaM
)
842 std::swap( *pBegin
, *pEnd
);
851 ::sal_Int32
Document::retrieveParagraphCaretPosition(Paragraph
const * pParagraph
)
853 SolarMutexGuard aGuard
;
854 ::osl::MutexGuard
aInternalGuard(GetMutex());
855 ::TextSelection
const & rSelection
= m_rView
.GetSelection();
856 Paragraphs::size_type nNumber
= pParagraph
->getNumber();
857 TextPaM
aEndPaM( rSelection
.GetEnd() );
859 return aEndPaM
.GetPara() == nNumber
? aEndPaM
.GetIndex() : -1;
863 Document::retrieveCharacterBounds(Paragraph
const * pParagraph
,
866 SolarMutexGuard aGuard
;
867 ::osl::MutexGuard
aInternalGuard(GetMutex());
868 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>(pParagraph
->getNumber());
869 sal_Int32 nLength
= m_rEngine
.GetText(nNumber
).getLength();
870 // XXX numeric overflow
871 if (nIndex
< 0 || nIndex
> nLength
)
872 throw css::lang::IndexOutOfBoundsException(
873 "textwindowaccessibility.cxx:"
874 " Document::retrieveCharacterAttributes",
875 static_cast< css::uno::XWeak
* >(this));
876 css::awt::Rectangle
aBounds( 0, 0, 0, 0 );
877 if ( nIndex
== nLength
)
879 aBounds
= AWTRectangle(
880 m_rEngine
.PaMtoEditCursor(::TextPaM(nNumber
, nIndex
)));
884 ::tools::Rectangle
aLeft(
885 m_rEngine
.PaMtoEditCursor(::TextPaM(nNumber
, nIndex
)));
886 // XXX numeric overflow
887 ::tools::Rectangle
aRight(
888 m_rEngine
.PaMtoEditCursor(::TextPaM(nNumber
, nIndex
+ 1)));
889 // XXX numeric overflow (2x)
890 // FIXME If the vertical extends of the two cursors do not match, assume
891 // nIndex is the last character on the line; the bounding box will then
892 // extend to m_rEngine.GetMaxTextWidth():
893 ::sal_Int32 nWidth
= (aLeft
.Top() == aRight
.Top()
894 && aLeft
.Bottom() == aRight
.Bottom())
895 ? static_cast< ::sal_Int32
>(aRight
.Left() - aLeft
.Left())
896 : static_cast< ::sal_Int32
>(m_rEngine
.GetMaxTextWidth()
898 // XXX numeric overflow (4x)
899 aBounds
= css::awt::Rectangle(static_cast< ::sal_Int32
>(aLeft
.Left()),
900 static_cast< ::sal_Int32
>(aLeft
.Top() - m_nViewOffset
),
902 static_cast< ::sal_Int32
>(aLeft
.Bottom()
904 // XXX numeric overflow (4x)
909 ::sal_Int32
Document::retrieveCharacterIndex(Paragraph
const * pParagraph
,
910 css::awt::Point
const & rPoint
)
912 SolarMutexGuard aGuard
;
913 ::osl::MutexGuard
aInternalGuard(GetMutex());
914 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>(pParagraph
->getNumber());
915 // XXX numeric overflow
916 ::TextPaM
aPaM(m_rEngine
.GetPaM(::Point(static_cast< tools::Long
>(rPoint
.X
),
917 static_cast< tools::Long
>(rPoint
.Y
))));
918 // XXX numeric overflow (2x)
919 return aPaM
.GetPara() == nNumber
? aPaM
.GetIndex() : -1;
920 // XXX numeric overflow
923 css::uno::Sequence
< css::beans::PropertyValue
>
924 Document::retrieveCharacterAttributes(
925 Paragraph
const * pParagraph
, ::sal_Int32 nIndex
,
926 const css::uno::Sequence
< OUString
>& aRequestedAttributes
)
928 SolarMutexGuard aGuard
;
930 vcl::Font aFont
= m_rEngine
.GetFont();
931 const sal_Int32 AttributeCount
= 9;
932 std::vector
< css::beans::PropertyValue
> aAttribs
;
933 aAttribs
.reserve(AttributeCount
);
935 css::beans::PropertyValue aAttrib
;
937 aAttrib
.State
= css::beans::PropertyState_DIRECT_VALUE
;
939 //character background color
940 aAttrib
.Name
= "CharBackColor";
941 aAttrib
.Value
= mapFontColor( aFont
.GetFillColor() );
942 aAttribs
.push_back(aAttrib
);
945 aAttrib
.Name
= "CharColor";
946 //aAttrib.Value = mapFontColor( aFont.GetColor() );
947 aAttrib
.Value
= mapFontColor( m_rEngine
.GetTextColor() );
948 aAttribs
.push_back(aAttrib
);
950 //character font name
951 aAttrib
.Name
= "CharFontName";
952 aAttrib
.Value
<<= aFont
.GetFamilyName();
953 aAttribs
.push_back(aAttrib
);
956 aAttrib
.Name
= "CharHeight";
957 aAttrib
.Value
<<= static_cast<sal_Int16
>(aFont
.GetFontHeight());
958 aAttribs
.push_back(aAttrib
);
961 aAttrib
.Name
= "CharPosture";
962 aAttrib
.Value
<<= static_cast<sal_Int16
>(aFont
.GetItalic());
963 aAttribs
.push_back(aAttrib
);
967 aAttrib.Name = "CharRelief";
968 aAttrib.Value = css::uno::Any( (sal_Int16)aFont.GetRelief() );
969 aAttribs.push_back(aAttrib);
972 //character strikeout
973 aAttrib
.Name
= "CharStrikeout";
974 aAttrib
.Value
<<= static_cast<sal_Int16
>(aFont
.GetStrikeout());
975 aAttribs
.push_back(aAttrib
);
977 //character underline
978 aAttrib
.Name
= "CharUnderline";
979 aAttrib
.Value
<<= static_cast<sal_Int16
>(aFont
.GetUnderline());
980 aAttribs
.push_back(aAttrib
);
983 aAttrib
.Name
= "CharWeight";
984 aAttrib
.Value
<<= static_cast<float>(aFont
.GetWeight());
985 aAttribs
.push_back(aAttrib
);
987 //character alignment
988 aAttrib
.Name
= "ParaAdjust";
989 aAttrib
.Value
<<= static_cast<sal_Int16
>(m_rEngine
.GetTextAlign());
990 aAttribs
.push_back(aAttrib
);
992 ::osl::MutexGuard
aInternalGuard(GetMutex());
993 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>(pParagraph
->getNumber());
994 // XXX numeric overflow
995 // nIndex can be equal to getLength();
996 if (nIndex
< 0 || nIndex
> m_rEngine
.GetText(nNumber
).getLength())
997 throw css::lang::IndexOutOfBoundsException(
998 "textwindowaccessibility.cxx:"
999 " Document::retrieveCharacterAttributes",
1000 static_cast< css::uno::XWeak
* >(this));
1003 // retrieve run attributes
1004 tPropValMap aCharAttrSeq
;
1005 retrieveRunAttributesImpl( pParagraph
, nIndex
, aRequestedAttributes
, aCharAttrSeq
);
1007 for (const css::beans::PropertyValue
& rAttrib
: aAttribs
)
1009 aCharAttrSeq
[ rAttrib
.Name
] = rAttrib
;
1012 const css::uno::Sequence
< css::beans::PropertyValue
> aRes
= comphelper::mapValuesToSequence( aCharAttrSeq
);
1014 // sort the attributes
1015 auto nLength
= static_cast<size_t>(aRes
.getLength());
1016 std::unique_ptr
<sal_Int32
[]> pIndices( new sal_Int32
[nLength
] );
1017 std::iota(&pIndices
[0], &pIndices
[nLength
], 0);
1018 std::sort(&pIndices
[0], &pIndices
[nLength
],
1019 [&aRes
](sal_Int32 a
, sal_Int32 b
) { return aRes
[a
].Name
< aRes
[b
].Name
; });
1021 // create sorted sequences according to index array
1022 std::vector
<css::beans::PropertyValue
> aNewValues
;
1023 aNewValues
.reserve(nLength
);
1024 std::transform(&pIndices
[0], &pIndices
[nLength
], std::back_inserter(aNewValues
),
1025 [&aRes
](const sal_Int32 nIdx
) { return aRes
[nIdx
]; });
1027 return comphelper::containerToSequence(aNewValues
);
1030 void Document::retrieveRunAttributesImpl(
1031 Paragraph
const * pParagraph
, ::sal_Int32 Index
,
1032 const css::uno::Sequence
< OUString
>& RequestedAttributes
,
1033 tPropValMap
& rRunAttrSeq
)
1035 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>( pParagraph
->getNumber() );
1036 ::TextPaM
aPaM( nNumber
, Index
);
1037 // XXX numeric overflow
1038 ::TextAttribFontColor
const * pColor
1039 = static_cast< ::TextAttribFontColor
const * >(
1040 m_rEngine
.FindAttrib( aPaM
, TEXTATTR_FONTCOLOR
) );
1041 ::TextAttribFontWeight
const * pWeight
1042 = static_cast< ::TextAttribFontWeight
const * >(
1043 m_rEngine
.FindAttrib( aPaM
, TEXTATTR_FONTWEIGHT
) );
1044 tPropValMap aRunAttrSeq
;
1047 css::beans::PropertyValue aPropVal
;
1048 aPropVal
.Name
= "CharColor";
1049 aPropVal
.Handle
= -1;
1050 aPropVal
.Value
= mapFontColor( pColor
->GetColor() );
1051 aPropVal
.State
= css::beans::PropertyState_DIRECT_VALUE
;
1052 aRunAttrSeq
[ aPropVal
.Name
] = aPropVal
;
1056 css::beans::PropertyValue aPropVal
;
1057 aPropVal
.Name
= "CharWeight";
1058 aPropVal
.Handle
= -1;
1059 aPropVal
.Value
= mapFontWeight( pWeight
->getFontWeight() );
1060 aPropVal
.State
= css::beans::PropertyState_DIRECT_VALUE
;
1061 aRunAttrSeq
[ aPropVal
.Name
] = aPropVal
;
1063 if ( !RequestedAttributes
.hasElements() )
1065 rRunAttrSeq
= aRunAttrSeq
;
1069 for ( const OUString
& rReqAttr
: RequestedAttributes
)
1071 tPropValMap::iterator aIter
= aRunAttrSeq
.find( rReqAttr
);
1072 if ( aIter
!= aRunAttrSeq
.end() )
1074 rRunAttrSeq
[ (*aIter
).first
] = (*aIter
).second
;
1080 css::uno::Sequence
< css::beans::PropertyValue
>
1081 Document::retrieveRunAttributes(
1082 Paragraph
const * pParagraph
, ::sal_Int32 Index
,
1083 const css::uno::Sequence
< OUString
>& RequestedAttributes
)
1085 SolarMutexGuard aGuard
;
1086 ::osl::MutexGuard
aInternalGuard( GetMutex() );
1087 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>( pParagraph
->getNumber() );
1088 // XXX numeric overflow
1089 if ( Index
< 0 || Index
>= m_rEngine
.GetText(nNumber
).getLength() )
1090 throw css::lang::IndexOutOfBoundsException(
1091 "textwindowaccessibility.cxx:"
1092 " Document::retrieveRunAttributes",
1093 static_cast< css::uno::XWeak
* >( this ) );
1095 tPropValMap aRunAttrSeq
;
1096 retrieveRunAttributesImpl( pParagraph
, Index
, RequestedAttributes
, aRunAttrSeq
);
1097 return comphelper::mapValuesToSequence( aRunAttrSeq
);
1100 void Document::changeParagraphText(Paragraph
const * pParagraph
,
1101 OUString
const & rText
)
1103 SolarMutexGuard aGuard
;
1105 ::osl::MutexGuard
aInternalGuard(GetMutex());
1106 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>(pParagraph
->getNumber());
1107 // XXX numeric overflow
1108 changeParagraphText(nNumber
, 0, m_rEngine
.GetTextLen(nNumber
), false,
1113 void Document::changeParagraphText(Paragraph
const * pParagraph
,
1114 ::sal_Int32 nBegin
, ::sal_Int32 nEnd
,
1115 bool bCut
, bool bPaste
,
1116 OUString
const & rText
)
1118 SolarMutexGuard aGuard
;
1120 ::osl::MutexGuard
aInternalGuard(GetMutex());
1121 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>(pParagraph
->getNumber());
1122 // XXX numeric overflow
1123 if (nBegin
< 0 || nBegin
> nEnd
1124 || nEnd
> m_rEngine
.GetText(nNumber
).getLength())
1125 throw css::lang::IndexOutOfBoundsException(
1126 "textwindowaccessibility.cxx:"
1127 " Document::changeParagraphText",
1128 static_cast< css::uno::XWeak
* >(this));
1129 changeParagraphText(nNumber
, static_cast< ::sal_uInt16
>(nBegin
),
1130 static_cast< ::sal_uInt16
>(nEnd
), bCut
, bPaste
, rText
);
1131 // XXX numeric overflow (2x)
1135 void Document::copyParagraphText(Paragraph
const * pParagraph
,
1136 ::sal_Int32 nBegin
, ::sal_Int32 nEnd
)
1138 SolarMutexGuard aGuard
;
1140 ::osl::MutexGuard
aInternalGuard(GetMutex());
1141 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>(pParagraph
->getNumber());
1142 // XXX numeric overflow
1143 if (nBegin
< 0 || nBegin
> nEnd
1144 || nEnd
> m_rEngine
.GetText(nNumber
).getLength())
1145 throw css::lang::IndexOutOfBoundsException(
1146 "textwindowaccessibility.cxx:"
1147 " Document::copyParagraphText",
1148 static_cast< css::uno::XWeak
* >(this));
1149 m_rView
.SetSelection(
1150 ::TextSelection(::TextPaM(nNumber
, nBegin
),
1151 ::TextPaM(nNumber
, nEnd
)));
1152 // XXX numeric overflow (2x)
1157 void Document::changeParagraphAttributes(
1158 Paragraph
const * pParagraph
, ::sal_Int32 nBegin
, ::sal_Int32 nEnd
,
1159 css::uno::Sequence
< css::beans::PropertyValue
> const & rAttributeSet
)
1161 SolarMutexGuard aGuard
;
1163 ::osl::MutexGuard
aInternalGuard(GetMutex());
1164 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>(pParagraph
->getNumber());
1165 // XXX numeric overflow
1166 if (nBegin
< 0 || nBegin
> nEnd
1167 || nEnd
> m_rEngine
.GetText(nNumber
).getLength())
1168 throw css::lang::IndexOutOfBoundsException(
1169 "textwindowaccessibility.cxx:"
1170 " Document::changeParagraphAttributes",
1171 static_cast< css::uno::XWeak
* >(this));
1173 // FIXME The new attributes are added to any attributes already set,
1174 // they do not replace the old attributes as required by
1175 // XAccessibleEditableText.setAttributes:
1176 for (const auto& rAttr
: rAttributeSet
)
1177 if ( rAttr
.Name
== "CharColor" )
1178 m_rEngine
.SetAttrib(::TextAttribFontColor(
1179 mapFontColor(rAttr
.Value
)),
1180 nNumber
, nBegin
, nEnd
);
1181 // XXX numeric overflow (2x)
1182 else if ( rAttr
.Name
== "CharWeight" )
1183 m_rEngine
.SetAttrib(::TextAttribFontWeight(
1184 mapFontWeight(rAttr
.Value
)),
1185 nNumber
, nBegin
, nEnd
);
1186 // XXX numeric overflow (2x)
1190 void Document::changeParagraphSelection(Paragraph
const * pParagraph
,
1191 ::sal_Int32 nBegin
, ::sal_Int32 nEnd
)
1193 SolarMutexGuard aGuard
;
1195 ::osl::MutexGuard
aInternalGuard(GetMutex());
1196 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>(pParagraph
->getNumber());
1197 // XXX numeric overflow
1198 if (nBegin
< 0 || nBegin
> nEnd
1199 || nEnd
> m_rEngine
.GetText(nNumber
).getLength())
1200 throw css::lang::IndexOutOfBoundsException(
1201 "textwindowaccessibility.cxx:"
1202 " Document::changeParagraphSelection",
1203 static_cast< css::uno::XWeak
* >(this));
1204 m_rView
.SetSelection(
1205 ::TextSelection(::TextPaM(nNumber
, nBegin
),
1206 ::TextPaM(nNumber
, nEnd
)));
1207 // XXX numeric overflow (2x)
1212 Document::retrieveParagraphLineBoundary( Paragraph
const * pParagraph
,
1213 ::sal_Int32 nIndex
, ::sal_Int32
*pLineNo
)
1215 css::i18n::Boundary aBoundary
;
1216 aBoundary
.startPos
= nIndex
;
1217 aBoundary
.endPos
= nIndex
;
1219 SolarMutexGuard aGuard
;
1221 ::osl::MutexGuard
aInternalGuard( GetMutex() );
1222 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>( pParagraph
->getNumber() );
1223 if ( nIndex
< 0 || nIndex
> m_rEngine
.GetText( nNumber
).getLength() )
1224 throw css::lang::IndexOutOfBoundsException(
1225 "textwindowaccessibility.cxx:"
1226 " Document::retrieveParagraphLineBoundary",
1227 static_cast< css::uno::XWeak
* >( this ) );
1228 ::sal_Int32 nLineStart
= 0;
1229 ::sal_Int32 nLineEnd
= 0;
1230 ::sal_uInt16 nLineCount
= m_rEngine
.GetLineCount( nNumber
);
1231 for ( ::sal_uInt16 nLine
= 0; nLine
< nLineCount
; ++nLine
)
1233 nLineStart
= nLineEnd
;
1234 nLineEnd
+= m_rEngine
.GetLineLen( nNumber
, nLine
);
1235 if ( nIndex
>= nLineStart
&& ( ( nLine
== nLineCount
- 1 ) ? nIndex
<= nLineEnd
: nIndex
< nLineEnd
) )
1237 aBoundary
.startPos
= nLineStart
;
1238 aBoundary
.endPos
= nLineEnd
;
1250 Document::retrieveParagraphBoundaryOfLine( Paragraph
const * pParagraph
,
1251 ::sal_Int32 nLineNo
)
1253 css::i18n::Boundary aBoundary
;
1254 aBoundary
.startPos
= 0;
1255 aBoundary
.endPos
= 0;
1257 SolarMutexGuard aGuard
;
1259 ::osl::MutexGuard
aInternalGuard( GetMutex() );
1260 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>( pParagraph
->getNumber() );
1261 if ( nLineNo
>= m_rEngine
.GetLineCount( nNumber
) )
1262 throw css::lang::IndexOutOfBoundsException(
1263 "textwindowaccessibility.cxx:"
1264 " Document::retrieveParagraphBoundaryOfLine",
1265 static_cast< css::uno::XWeak
* >( this ) );
1266 ::sal_Int32 nLineStart
= 0;
1267 ::sal_Int32 nLineEnd
= 0;
1268 for ( ::sal_Int32 nLine
= 0; nLine
<= nLineNo
; ++nLine
)
1270 nLineStart
= nLineEnd
;
1271 nLineEnd
+= m_rEngine
.GetLineLen( nNumber
, nLine
);
1274 aBoundary
.startPos
= nLineStart
;
1275 aBoundary
.endPos
= nLineEnd
;
1281 sal_Int32
Document::retrieveParagraphLineWithCursor( Paragraph
const * pParagraph
)
1283 SolarMutexGuard aGuard
;
1284 ::osl::MutexGuard
aInternalGuard(GetMutex());
1285 ::TextSelection
const & rSelection
= m_rView
.GetSelection();
1286 Paragraphs::size_type nNumber
= pParagraph
->getNumber();
1287 TextPaM
aEndPaM( rSelection
.GetEnd() );
1289 return aEndPaM
.GetPara() == nNumber
1290 ? m_rView
.GetLineNumberOfCursorInSelection() : -1;
1294 css::uno::Reference
< css::accessibility::XAccessibleRelationSet
>
1295 Document::retrieveParagraphRelationSet( Paragraph
const * pParagraph
)
1297 ::osl::MutexGuard
aInternalGuard( GetMutex() );
1299 rtl::Reference
<::utl::AccessibleRelationSetHelper
> pRelationSetHelper
= new ::utl::AccessibleRelationSetHelper();
1301 Paragraphs::iterator
aPara( m_xParagraphs
->begin() + pParagraph
->getNumber() );
1303 if ( aPara
> m_aVisibleBegin
&& aPara
< m_aVisibleEnd
)
1305 css::uno::Sequence
< css::uno::Reference
< css::uno::XInterface
> > aSequence
{ getAccessibleChild( aPara
- 1 ) };
1306 css::accessibility::AccessibleRelation
aRelation( css::accessibility::AccessibleRelationType::CONTENT_FLOWS_FROM
, aSequence
);
1307 pRelationSetHelper
->AddRelation( aRelation
);
1310 if ( aPara
>= m_aVisibleBegin
&& aPara
< m_aVisibleEnd
-1 )
1312 css::uno::Sequence
< css::uno::Reference
< css::uno::XInterface
> > aSequence
{ getAccessibleChild( aPara
+ 1 ) };
1313 css::accessibility::AccessibleRelation
aRelation( css::accessibility::AccessibleRelationType::CONTENT_FLOWS_TO
, aSequence
);
1314 pRelationSetHelper
->AddRelation( aRelation
);
1317 return pRelationSetHelper
;
1321 ::sal_Int32 SAL_CALL
Document::getAccessibleChildCount()
1323 ::comphelper::OExternalLockGuard
aGuard(this);
1325 return m_aVisibleEnd
- m_aVisibleBegin
;
1329 css::uno::Reference
< css::accessibility::XAccessible
> SAL_CALL
1330 Document::getAccessibleChild(::sal_Int32 i
)
1332 ::comphelper::OExternalLockGuard
aGuard(this);
1334 if (i
< 0 || i
>= m_aVisibleEnd
- m_aVisibleBegin
)
1335 throw css::lang::IndexOutOfBoundsException(
1336 "textwindowaccessibility.cxx:"
1337 " Document::getAccessibleChild",
1338 static_cast< css::uno::XWeak
* >(this));
1339 return getAccessibleChild(m_aVisibleBegin
1340 + static_cast< Paragraphs::size_type
>(i
));
1344 ::sal_Int16 SAL_CALL
Document::getAccessibleRole()
1346 return css::accessibility::AccessibleRole::TEXT_FRAME
;
1350 css::uno::Reference
< css::accessibility::XAccessible
> SAL_CALL
1351 Document::getAccessibleAtPoint(css::awt::Point
const & rPoint
)
1353 ::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(m_aVisibleBegin
); aIt
!= m_aVisibleEnd
;
1364 nPos
+= aIt
->getHeight(); // XXX numeric overflow
1366 return getAccessibleChild(aIt
);
1371 void Document::FillAccessibleStateSet( utl::AccessibleStateSetHelper
& rStateSet
)
1373 VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet
);
1374 if (!m_rView
.IsReadOnly())
1375 rStateSet
.AddState( css::accessibility::AccessibleStateType::EDITABLE
);
1378 void Document::FillAccessibleRelationSet( utl::AccessibleRelationSetHelper
& rRelationSet
)
1380 if( getAccessibleParent()->getAccessibleContext()->getAccessibleRole() == css::accessibility::AccessibleRole::SCROLL_PANE
)
1382 css::uno::Sequence
< css::uno::Reference
< css::uno::XInterface
> > aSequence
{ getAccessibleParent() };
1383 rRelationSet
.AddRelation( css::accessibility::AccessibleRelation( css::accessibility::AccessibleRelationType::MEMBER_OF
, aSequence
) );
1387 VCLXAccessibleComponent::FillAccessibleRelationSet(rRelationSet
);
1391 void SAL_CALL
Document::disposing()
1393 m_aEngineListener
.endListening();
1394 m_aViewListener
.endListening();
1395 if (m_xParagraphs
!= nullptr)
1396 disposeParagraphs();
1397 VCLXAccessibleComponent::disposing();
1401 void Document::Notify(::SfxBroadcaster
&, ::SfxHint
const & rHint
)
1403 const TextHint
* pTextHint
= dynamic_cast<const TextHint
*>(&rHint
);
1407 ::TextHint
const & rTextHint
= *pTextHint
;
1408 switch (rTextHint
.GetId())
1410 case SfxHintId::TextParaInserted
:
1411 case SfxHintId::TextParaRemoved
:
1412 // SfxHintId::TextParaInserted and SfxHintId::TextParaRemoved are sent at
1413 // "unsafe" times (when the text engine has not yet re-formatted its
1414 // content), so that for example calling ::TextEngine::GetTextHeight
1415 // from within the code that handles SfxHintId::TextParaInserted causes
1416 // trouble within the text engine. Therefore, these hints are just
1417 // buffered until a following ::TextEngine::FormatDoc causes a
1418 // SfxHintId::TextFormatted to come in:
1419 case SfxHintId::TextFormatPara
:
1420 // ::TextEngine::FormatDoc sends a sequence of
1421 // SfxHintId::TextFormatParas, followed by an optional
1422 // SfxHintId::TextHeightChanged, followed in all cases by one
1423 // SfxHintId::TextFormatted. Only the SfxHintId::TextFormatParas contain
1424 // the numbers of the affected paragraphs, but they are sent
1425 // before the changes are applied. Therefore, SfxHintId::TextFormatParas
1426 // are just buffered until another hint comes in:
1428 ::osl::MutexGuard
aInternalGuard(GetMutex());
1432 m_aParagraphNotifications
.push(rTextHint
);
1435 case SfxHintId::TextFormatted
:
1436 case SfxHintId::TextHeightChanged
:
1437 case SfxHintId::TextModified
:
1439 ::osl::MutexGuard
aInternalGuard(GetMutex());
1442 handleParagraphNotifications();
1445 case SfxHintId::TextViewScrolled
:
1447 ::osl::MutexGuard
aInternalGuard(GetMutex());
1450 handleParagraphNotifications();
1452 ::sal_Int32 nOffset
= static_cast< ::sal_Int32
>(
1453 m_rView
.GetStartDocPos().Y());
1454 // XXX numeric overflow
1455 if (nOffset
!= m_nViewOffset
)
1457 m_nViewOffset
= nOffset
;
1459 Paragraphs::iterator
aOldVisibleBegin(
1461 Paragraphs::iterator
aOldVisibleEnd(m_aVisibleEnd
);
1463 determineVisibleRange();
1465 notifyVisibleRangeChanges(aOldVisibleBegin
,
1467 m_xParagraphs
->end());
1471 case SfxHintId::TextViewSelectionChanged
:
1472 case SfxHintId::TextViewCaretChanged
:
1474 ::osl::MutexGuard
aInternalGuard(GetMutex());
1478 if (m_aParagraphNotifications
.empty())
1480 handleSelectionChangeNotification();
1484 // SfxHintId::TextViewSelectionChanged is sometimes sent at
1485 // "unsafe" times (when the text engine has not yet re-
1486 // formatted its content), so that for example calling
1487 // ::TextEngine::GetTextHeight from within the code that
1488 // handles a previous SfxHintId::TextParaInserted causes
1489 // trouble within the text engine. Therefore, these
1490 // hints are just buffered (along with
1491 // SfxHintId::TextParaInserted/REMOVED/FORMATPARA) until a
1492 // following ::TextEngine::FormatDoc causes a
1493 // SfxHintId::TextFormatted to come in:
1494 m_bSelectionChangedNotification
= true;
1502 IMPL_LINK(Document
, WindowEventHandler
, ::VclWindowEvent
&, rEvent
, void)
1504 switch (rEvent
.GetId())
1506 case VclEventId::WindowResize
:
1508 ::osl::MutexGuard
aInternalGuard(GetMutex());
1512 ::sal_Int32 nHeight
= static_cast< ::sal_Int32
>(
1513 m_rView
.GetWindow()->GetOutputSizePixel().Height());
1514 // XXX numeric overflow
1515 if (nHeight
!= m_nViewHeight
)
1517 m_nViewHeight
= nHeight
;
1519 Paragraphs::iterator
aOldVisibleBegin(m_aVisibleBegin
);
1520 Paragraphs::iterator
aOldVisibleEnd(m_aVisibleEnd
);
1522 determineVisibleRange();
1524 notifyVisibleRangeChanges(aOldVisibleBegin
, aOldVisibleEnd
,
1525 m_xParagraphs
->end());
1529 case VclEventId::WindowGetFocus
:
1531 ::osl::MutexGuard
aInternalGuard(GetMutex());
1534 //to enable the PARAGRAPH to get focus for multiline edit
1535 ::sal_Int32 count
= getAccessibleChildCount();
1536 bool bEmpty
= m_aFocused
== m_aVisibleEnd
&& count
== 1;
1537 if ((m_aFocused
>= m_aVisibleBegin
&& m_aFocused
< m_aVisibleEnd
) || bEmpty
)
1539 Paragraphs::iterator aTemp
= bEmpty
? m_aVisibleBegin
: m_aFocused
;
1540 ::rtl::Reference
< Paragraph
> xParagraph(getParagraph(aTemp
));
1541 if (xParagraph
.is())
1543 xParagraph
->notifyEvent(
1544 css::accessibility::AccessibleEventId::
1548 css::accessibility::AccessibleStateType::
1554 case VclEventId::WindowLoseFocus
:
1556 ::osl::MutexGuard
aInternalGuard(GetMutex());
1559 //to enable the PARAGRAPH to get focus for multiline edit
1560 ::sal_Int32 count
= getAccessibleChildCount();
1561 bool bEmpty
= m_aFocused
== m_aVisibleEnd
&& count
== 1;
1562 if ((m_aFocused
>= m_aVisibleBegin
&& m_aFocused
< m_aVisibleEnd
) || bEmpty
)
1564 Paragraphs::iterator aTemp
= bEmpty
? m_aVisibleBegin
: m_aFocused
;
1565 ::rtl::Reference
< Paragraph
> xParagraph(getParagraph(aTemp
));
1566 if (xParagraph
.is())
1567 xParagraph
->notifyEvent(
1568 css::accessibility::AccessibleEventId::
1571 css::accessibility::AccessibleStateType::
1581 void Document::init()
1583 if (m_xParagraphs
!= nullptr)
1586 const ::sal_uInt32 nCount
= m_rEngine
.GetParagraphCount();
1587 m_xParagraphs
.reset(new Paragraphs
);
1588 m_xParagraphs
->reserve(static_cast< Paragraphs::size_type
>(nCount
));
1589 // numeric overflow is harmless here
1590 for (::sal_uInt32 i
= 0; i
< nCount
; ++i
)
1591 m_xParagraphs
->push_back(ParagraphInfo(static_cast< ::sal_Int32
>(
1592 m_rEngine
.GetTextHeight(i
))));
1593 // XXX numeric overflow
1594 m_nViewOffset
= static_cast< ::sal_Int32
>(
1595 m_rView
.GetStartDocPos().Y()); // XXX numeric overflow
1596 m_nViewHeight
= static_cast< ::sal_Int32
>(
1597 m_rView
.GetWindow()->GetOutputSizePixel().Height());
1598 // XXX numeric overflow
1599 determineVisibleRange();
1600 m_nSelectionFirstPara
= -1;
1601 m_nSelectionFirstPos
= -1;
1602 m_nSelectionLastPara
= -1;
1603 m_nSelectionLastPos
= -1;
1604 m_aFocused
= m_xParagraphs
->end();
1605 m_bSelectionChangedNotification
= false;
1606 m_aEngineListener
.startListening(m_rEngine
);
1607 m_aViewListener
.startListening(*m_rView
.GetWindow());
1610 ::rtl::Reference
< Paragraph
>
1611 Document::getParagraph(Paragraphs::iterator
const & rIt
)
1613 return static_cast< Paragraph
* >(
1614 css::uno::Reference
< css::accessibility::XAccessible
>(
1615 rIt
->getParagraph()).get());
1618 css::uno::Reference
< css::accessibility::XAccessible
>
1619 Document::getAccessibleChild(Paragraphs::iterator
const & rIt
)
1621 css::uno::Reference
< css::accessibility::XAccessible
> xParagraph(
1622 rIt
->getParagraph());
1623 if (!xParagraph
.is())
1625 xParagraph
= new Paragraph(this, rIt
- m_xParagraphs
->begin());
1626 rIt
->setParagraph(xParagraph
);
1631 void Document::determineVisibleRange()
1633 Paragraphs::iterator
const aEnd
= m_xParagraphs
->end();
1635 m_aVisibleBegin
= aEnd
;
1636 m_aVisibleEnd
= aEnd
;
1637 m_nVisibleBeginOffset
= 0;
1639 ::sal_Int32 nPos
= 0;
1640 for (Paragraphs::iterator aIt
= m_xParagraphs
->begin(); m_aVisibleEnd
== aEnd
&& aIt
!= aEnd
; ++aIt
)
1642 ::sal_Int32
const nOldPos
= nPos
;
1643 nPos
+= aIt
->getHeight(); // XXX numeric overflow
1644 if (m_aVisibleBegin
== aEnd
)
1646 if (nPos
>= m_nViewOffset
)
1648 m_aVisibleBegin
= aIt
;
1649 m_nVisibleBeginOffset
= m_nViewOffset
- nOldPos
;
1654 if (nPos
>= m_nViewOffset
+ m_nViewHeight
) // XXX numeric overflow
1656 m_aVisibleEnd
= aIt
;
1662 !((m_aVisibleBegin
== m_xParagraphs
->end() && m_aVisibleEnd
== m_xParagraphs
->end() && m_nVisibleBeginOffset
== 0)
1663 || (m_aVisibleBegin
< m_aVisibleEnd
&& m_nVisibleBeginOffset
>= 0)),
1665 "invalid visible range");
1668 void Document::notifyVisibleRangeChanges(
1669 Paragraphs::iterator
const & rOldVisibleBegin
,
1670 Paragraphs::iterator
const & rOldVisibleEnd
,
1671 Paragraphs::iterator
const & rInserted
)
1673 // XXX Replace this code that determines which paragraphs have changed from
1674 // invisible to visible or vice versa with a better algorithm.
1675 for (Paragraphs::iterator
aIt(rOldVisibleBegin
); aIt
!= rOldVisibleEnd
;
1678 if (aIt
!= rInserted
1679 && (aIt
< m_aVisibleBegin
|| aIt
>= m_aVisibleEnd
))
1680 NotifyAccessibleEvent(
1681 css::accessibility::AccessibleEventId::
1683 css::uno::Any(getAccessibleChild(aIt
)),
1686 for (Paragraphs::iterator
aIt(m_aVisibleBegin
); aIt
!= m_aVisibleEnd
;
1689 if (aIt
== rInserted
1690 || aIt
< rOldVisibleBegin
|| aIt
>= rOldVisibleEnd
)
1691 NotifyAccessibleEvent(
1692 css::accessibility::AccessibleEventId::
1695 css::uno::Any(getAccessibleChild(aIt
)));
1700 Document::changeParagraphText(::sal_uInt32 nNumber
, ::sal_uInt16 nBegin
, ::sal_uInt16 nEnd
,
1701 bool bCut
, bool bPaste
,
1702 OUString
const & rText
)
1704 m_rView
.SetSelection(::TextSelection(::TextPaM(nNumber
, nBegin
),
1705 ::TextPaM(nNumber
, nEnd
)));
1708 else if (nBegin
!= nEnd
)
1709 m_rView
.DeleteSelected();
1712 else if (!rText
.isEmpty())
1713 m_rView
.InsertText(rText
);
1716 void Document::handleParagraphNotifications()
1718 while (!m_aParagraphNotifications
.empty())
1720 ::TextHint
aHint(m_aParagraphNotifications
.front());
1721 m_aParagraphNotifications
.pop();
1722 switch (aHint
.GetId())
1724 case SfxHintId::TextParaInserted
:
1726 ::sal_uInt32 n
= static_cast< ::sal_uInt32
>( aHint
.GetValue() );
1727 assert(n
<= m_xParagraphs
->size() && "bad SfxHintId::TextParaInserted event");
1729 // Save the values of old iterators (the iterators themselves
1730 // will get invalidated), and adjust the old values so that they
1731 // reflect the insertion of the new paragraph:
1732 Paragraphs::size_type nOldVisibleBegin
1733 = m_aVisibleBegin
- m_xParagraphs
->begin();
1734 Paragraphs::size_type nOldVisibleEnd
1735 = m_aVisibleEnd
- m_xParagraphs
->begin();
1736 Paragraphs::size_type nOldFocused
1737 = m_aFocused
- m_xParagraphs
->begin();
1738 if (n
<= nOldVisibleBegin
)
1739 ++nOldVisibleBegin
; // XXX numeric overflow
1740 if (n
<= nOldVisibleEnd
)
1741 ++nOldVisibleEnd
; // XXX numeric overflow
1742 if (n
<= nOldFocused
)
1743 ++nOldFocused
; // XXX numeric overflow
1744 if (sal::static_int_cast
<sal_Int32
>(n
) <= m_nSelectionFirstPara
)
1745 ++m_nSelectionFirstPara
; // XXX numeric overflow
1746 if (sal::static_int_cast
<sal_Int32
>(n
) <= m_nSelectionLastPara
)
1747 ++m_nSelectionLastPara
; // XXX numeric overflow
1749 Paragraphs::iterator
aIns(
1750 m_xParagraphs
->insert(
1751 m_xParagraphs
->begin() + n
,
1752 ParagraphInfo(static_cast< ::sal_Int32
>(
1753 m_rEngine
.GetTextHeight(n
)))));
1754 // XXX numeric overflow (2x)
1756 determineVisibleRange();
1757 m_aFocused
= m_xParagraphs
->begin() + nOldFocused
;
1759 for (Paragraphs::iterator
aIt(aIns
);;)
1762 if (aIt
== m_xParagraphs
->end())
1764 ::rtl::Reference
< Paragraph
> xParagraph(
1766 if (xParagraph
.is())
1767 xParagraph
->numberChanged(true);
1770 notifyVisibleRangeChanges(
1771 m_xParagraphs
->begin() + nOldVisibleBegin
,
1772 m_xParagraphs
->begin() + nOldVisibleEnd
, aIns
);
1775 case SfxHintId::TextParaRemoved
:
1777 ::sal_uInt32 n
= static_cast< ::sal_uInt32
>( aHint
.GetValue() );
1778 if (n
== TEXT_PARA_ALL
)
1780 for (Paragraphs::iterator
aIt(m_aVisibleBegin
);
1781 aIt
!= m_aVisibleEnd
; ++aIt
)
1783 NotifyAccessibleEvent(
1784 css::accessibility::AccessibleEventId::
1786 css::uno::Any(getAccessibleChild(aIt
)),
1789 disposeParagraphs();
1790 m_xParagraphs
->clear();
1791 determineVisibleRange();
1792 m_nSelectionFirstPara
= -1;
1793 m_nSelectionFirstPos
= -1;
1794 m_nSelectionLastPara
= -1;
1795 m_nSelectionLastPos
= -1;
1796 m_aFocused
= m_xParagraphs
->end();
1800 assert(n
< m_xParagraphs
->size() && "Bad SfxHintId::TextParaRemoved event");
1802 Paragraphs::iterator
aIt(m_xParagraphs
->begin() + n
);
1803 // numeric overflow cannot occur
1805 // Save the values of old iterators (the iterators
1806 // themselves will get invalidated), and adjust the old
1807 // values so that they reflect the removal of the paragraph:
1808 Paragraphs::size_type nOldVisibleBegin
1809 = m_aVisibleBegin
- m_xParagraphs
->begin();
1810 Paragraphs::size_type nOldVisibleEnd
1811 = m_aVisibleEnd
- m_xParagraphs
->begin();
1813 = nOldVisibleBegin
<= n
&& n
< nOldVisibleEnd
;
1814 Paragraphs::size_type nOldFocused
1815 = m_aFocused
- m_xParagraphs
->begin();
1816 bool bWasFocused
= aIt
== m_aFocused
;
1817 if (n
< nOldVisibleBegin
)
1819 if (n
< nOldVisibleEnd
)
1821 if (n
< nOldFocused
)
1823 if (sal::static_int_cast
<sal_Int32
>(n
) < m_nSelectionFirstPara
)
1824 --m_nSelectionFirstPara
;
1825 else if (sal::static_int_cast
<sal_Int32
>(n
) == m_nSelectionFirstPara
)
1827 if (m_nSelectionFirstPara
== m_nSelectionLastPara
)
1829 m_nSelectionFirstPara
= -1;
1830 m_nSelectionFirstPos
= -1;
1831 m_nSelectionLastPara
= -1;
1832 m_nSelectionLastPos
= -1;
1836 ++m_nSelectionFirstPara
;
1837 m_nSelectionFirstPos
= 0;
1840 if (sal::static_int_cast
<sal_Int32
>(n
) < m_nSelectionLastPara
)
1841 --m_nSelectionLastPara
;
1842 else if (sal::static_int_cast
<sal_Int32
>(n
) == m_nSelectionLastPara
)
1844 assert(m_nSelectionFirstPara
< m_nSelectionLastPara
&& "logic error");
1845 --m_nSelectionLastPara
;
1846 m_nSelectionLastPos
= 0x7FFFFFFF;
1849 css::uno::Reference
< css::accessibility::XAccessible
>
1852 xStrong
= getAccessibleChild(aIt
);
1853 css::uno::WeakReference
<
1854 css::accessibility::XAccessible
> xWeak(
1855 aIt
->getParagraph());
1856 aIt
= m_xParagraphs
->erase(aIt
);
1858 determineVisibleRange();
1859 m_aFocused
= bWasFocused
? m_xParagraphs
->end()
1860 : m_xParagraphs
->begin() + nOldFocused
;
1862 for (; aIt
!= m_xParagraphs
->end(); ++aIt
)
1864 ::rtl::Reference
< Paragraph
> xParagraph(
1866 if (xParagraph
.is())
1867 xParagraph
->numberChanged(false);
1871 NotifyAccessibleEvent(
1872 css::accessibility::AccessibleEventId::
1874 css::uno::Any(xStrong
),
1877 css::uno::Reference
< css::lang::XComponent
> xComponent(
1878 xWeak
.get(), css::uno::UNO_QUERY
);
1879 if (xComponent
.is())
1880 xComponent
->dispose();
1882 notifyVisibleRangeChanges(
1883 m_xParagraphs
->begin() + nOldVisibleBegin
,
1884 m_xParagraphs
->begin() + nOldVisibleEnd
,
1885 m_xParagraphs
->end());
1889 case SfxHintId::TextFormatPara
:
1891 ::sal_uInt32 n
= static_cast< ::sal_uInt32
>( aHint
.GetValue() );
1892 assert(n
< m_xParagraphs
->size() && "Bad SfxHintId::TextFormatPara event");
1894 (*m_xParagraphs
)[static_cast< Paragraphs::size_type
>(n
)].
1895 changeHeight(static_cast< ::sal_Int32
>(
1896 m_rEngine
.GetTextHeight(n
)));
1897 // XXX numeric overflow
1898 Paragraphs::iterator
aOldVisibleBegin(m_aVisibleBegin
);
1899 Paragraphs::iterator
aOldVisibleEnd(m_aVisibleEnd
);
1900 determineVisibleRange();
1901 notifyVisibleRangeChanges(aOldVisibleBegin
, aOldVisibleEnd
,
1902 m_xParagraphs
->end());
1904 if (n
< m_xParagraphs
->size())
1906 Paragraphs::iterator
aIt(m_xParagraphs
->begin() + n
);
1907 ::rtl::Reference
< Paragraph
> xParagraph(getParagraph(aIt
));
1908 if (xParagraph
.is())
1909 xParagraph
->textChanged();
1914 SAL_WARN("accessibility", "bad buffered hint");
1918 if (m_bSelectionChangedNotification
)
1920 m_bSelectionChangedNotification
= false;
1921 handleSelectionChangeNotification();
1928 enum class SelChangeType
1930 None
, // no change, or invalid
1931 CaretMove
, // neither old nor new have selection, and they are different
1932 NoSelToSel
, // old has no selection but new has selection
1933 SelToNoSel
, // old has selection but new has no selection
1934 // both old and new have selections
1935 NoParaChange
, // only end index changed inside end para
1936 EndParaNoMoreBehind
, // end para was behind start, but now is same or ahead
1937 AddedFollowingPara
, // selection extended to following paragraph(s)
1938 ExcludedPreviousPara
, // selection shrunk excluding previous paragraph(s)
1939 ExcludedFollowingPara
, // selection shrunk excluding following paragraph(s)
1940 AddedPreviousPara
, // selection extended to previous paragraph(s)
1941 EndParaBecameBehind
// end para was ahead of start, but now is behind
1944 SelChangeType
getSelChangeType(const TextPaM
& Os
, const TextPaM
& Oe
,
1945 const TextPaM
& Ns
, const TextPaM
& Ne
)
1947 if (Os
== Oe
) // no old selection
1949 if (Ns
== Ne
) // no new selection: only caret moves
1950 return Os
!= Ns
? SelChangeType::CaretMove
: SelChangeType::None
;
1951 else // old has no selection but new has selection
1952 return SelChangeType::NoSelToSel
;
1954 else if (Ns
== Ne
) // old has selection; no new selection
1956 return SelChangeType::SelToNoSel
;
1958 else if (Os
== Ns
) // both old and new have selections, and their starts are same
1960 const sal_Int32 Osp
= Os
.GetPara(), Oep
= Oe
.GetPara();
1961 const sal_Int32 Nsp
= Ns
.GetPara(), Nep
= Ne
.GetPara();
1962 if (Oep
== Nep
) // end of selection stays in the same paragraph
1964 //Send text_selection_change event on Nep
1965 return Oe
.GetIndex() != Ne
.GetIndex() ? SelChangeType::NoParaChange
1966 : SelChangeType::None
;
1968 else if (Oep
< Nep
) // end of selection moved to a following paragraph
1970 //all the following examples like 1,2->1,3 means that old start select para is 1, old end select para is 2,
1971 // then press shift up, the new start select para is 1, new end select para is 3;
1972 //for example, 1, 2 -> 1, 3; 4,1 -> 4, 7; 4,1 -> 4, 2; 4,4->4,5
1973 if (Nep
>= Nsp
) // new end para not behind start
1975 // 1, 2 -> 1, 3; 4, 1 -> 4, 7; 4,4->4,5;
1976 if (Oep
< Osp
) // old end was behind start
1978 // 4,1 -> 4,7; 4,1 -> 4,4
1979 return SelChangeType::EndParaNoMoreBehind
;
1981 else // old end para wasn't behind start
1983 // 1, 2 -> 1, 3; 4,4->4,5;
1984 return SelChangeType::AddedFollowingPara
;
1987 else // new end para is still behind start
1990 return SelChangeType::ExcludedPreviousPara
;
1993 else // Oep > Nep => end of selection moved to a previous paragraph
1995 // 3,2 -> 3,1; 4,7 -> 4,1; 4, 7 -> 4,6; 4,4 -> 4,3
1996 if (Nep
>= Nsp
) // new end para is still not behind of start
1999 return SelChangeType::ExcludedFollowingPara
;
2001 else // new end para is behind start
2003 // 3,2 -> 3,1, 4,7 -> 4,1; 4,4->4,3
2004 if (Oep
<= Osp
) // it was not ahead already
2006 // 3,2 -> 3,1; 4,4->4,3
2007 return SelChangeType::AddedPreviousPara
;
2009 else // it was ahead previously
2012 return SelChangeType::EndParaBecameBehind
;
2017 return SelChangeType::None
;
2022 void Document::sendEvent(::sal_Int32 start
, ::sal_Int32 end
, ::sal_Int16 nEventId
)
2024 size_t nAvailDistance
= std::distance(m_xParagraphs
->begin(), m_aVisibleEnd
);
2026 Paragraphs::iterator
aEnd(m_xParagraphs
->begin());
2027 size_t nEndDistance
= std::min
<size_t>(end
+ 1, nAvailDistance
);
2028 std::advance(aEnd
, nEndDistance
);
2030 Paragraphs::iterator
aIt(m_xParagraphs
->begin());
2031 size_t nStartDistance
= std::min
<size_t>(start
, nAvailDistance
);
2032 std::advance(aIt
, nStartDistance
);
2036 ::rtl::Reference
< Paragraph
> xParagraph(getParagraph(aIt
));
2037 if (xParagraph
.is())
2038 xParagraph
->notifyEvent(
2040 css::uno::Any(), css::uno::Any());
2045 void Document::handleSelectionChangeNotification()
2047 ::TextSelection
const & rSelection
= m_rView
.GetSelection();
2048 assert(rSelection
.GetStart().GetPara() < m_xParagraphs
->size() &&
2049 rSelection
.GetEnd().GetPara() < m_xParagraphs
->size() &&
2050 "bad SfxHintId::TextViewSelectionChanged event");
2051 ::sal_Int32 nNewFirstPara
2052 = static_cast< ::sal_Int32
>(rSelection
.GetStart().GetPara());
2053 ::sal_Int32 nNewFirstPos
= rSelection
.GetStart().GetIndex();
2054 // XXX numeric overflow
2055 ::sal_Int32 nNewLastPara
2056 = static_cast< ::sal_Int32
>(rSelection
.GetEnd().GetPara());
2057 ::sal_Int32 nNewLastPos
= rSelection
.GetEnd().GetIndex();
2058 // XXX numeric overflow
2061 Paragraphs::iterator
aIt(m_xParagraphs
->begin() + nNewLastPara
);
2062 if (m_aFocused
!= m_xParagraphs
->end() && m_aFocused
!= aIt
2063 && m_aFocused
>= m_aVisibleBegin
&& m_aFocused
< m_aVisibleEnd
)
2065 ::rtl::Reference
< Paragraph
> xParagraph(getParagraph(m_aFocused
));
2066 if (xParagraph
.is())
2067 xParagraph
->notifyEvent(
2068 css::accessibility::AccessibleEventId::
2071 css::accessibility::AccessibleStateType::FOCUSED
),
2075 // Gain focus and update cursor position:
2076 if (aIt
>= m_aVisibleBegin
&& aIt
< m_aVisibleEnd
2077 && (aIt
!= m_aFocused
2078 || nNewLastPara
!= m_nSelectionLastPara
2079 || nNewLastPos
!= m_nSelectionLastPos
))
2081 ::rtl::Reference
< Paragraph
> xParagraph(getParagraph(aIt
));
2082 if (xParagraph
.is())
2084 //disable the first event when user types in empty field.
2085 ::sal_Int32 count
= getAccessibleChildCount();
2086 bool bEmpty
= count
> 1;
2087 //if (aIt != m_aFocused)
2088 if (aIt
!= m_aFocused
&& bEmpty
)
2089 xParagraph
->notifyEvent(
2090 css::accessibility::AccessibleEventId::
2094 css::accessibility::AccessibleStateType::FOCUSED
));
2095 if (nNewLastPara
!= m_nSelectionLastPara
2096 || nNewLastPos
!= m_nSelectionLastPos
)
2097 xParagraph
->notifyEvent(
2098 css::accessibility::AccessibleEventId::
2100 css::uno::makeAny
< ::sal_Int32
>(
2101 nNewLastPara
== m_nSelectionLastPara
2102 ? m_nSelectionLastPos
: 0),
2103 css::uno::Any(nNewLastPos
));
2108 if (m_nSelectionFirstPara
!= -1)
2112 SelChangeType ret
= getSelChangeType(TextPaM(m_nSelectionFirstPara
, m_nSelectionFirstPos
),
2113 TextPaM(m_nSelectionLastPara
, m_nSelectionLastPos
),
2114 rSelection
.GetStart(), rSelection
.GetEnd());
2117 case SelChangeType::None
:
2120 case SelChangeType::CaretMove
:
2121 //only caret moved, already handled in above
2123 case SelChangeType::NoSelToSel
:
2124 //old has no selection but new has selection
2125 nMin
= std::min(nNewFirstPara
, nNewLastPara
);
2126 nMax
= std::max(nNewFirstPara
, nNewLastPara
);
2127 sendEvent(nMin
, nMax
, css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2128 sendEvent(nMin
, nMax
,
2129 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2131 case SelChangeType::SelToNoSel
:
2132 //old has selection but new has no selection.
2133 nMin
= std::min(m_nSelectionFirstPara
, m_nSelectionLastPara
);
2134 nMax
= std::max(m_nSelectionFirstPara
, m_nSelectionLastPara
);
2135 sendEvent(nMin
, nMax
, css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2136 sendEvent(nMin
, nMax
,
2137 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2139 case SelChangeType::NoParaChange
:
2140 //Send text_selection_change event on Nep
2141 sendEvent(nNewLastPara
, nNewLastPara
,
2142 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2144 case SelChangeType::EndParaNoMoreBehind
:
2145 // 4, 1 -> 4, 7; 4,1 -> 4,4
2146 sendEvent(m_nSelectionLastPara
, m_nSelectionFirstPara
- 1,
2147 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2148 sendEvent(nNewFirstPara
+ 1, nNewLastPara
,
2149 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2151 sendEvent(m_nSelectionLastPara
, nNewLastPara
,
2152 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2154 case SelChangeType::AddedFollowingPara
:
2155 // 1, 2 -> 1, 4; 4,4->4,5;
2156 sendEvent(m_nSelectionLastPara
+ 1, nNewLastPara
,
2157 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2159 sendEvent(m_nSelectionLastPara
, nNewLastPara
,
2160 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2162 case SelChangeType::ExcludedPreviousPara
:
2164 sendEvent(m_nSelectionLastPara
+ 1, nNewLastPara
,
2165 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2167 sendEvent(m_nSelectionLastPara
, nNewLastPara
,
2168 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2170 case SelChangeType::ExcludedFollowingPara
:
2172 sendEvent(nNewLastPara
+ 1, m_nSelectionLastPara
,
2173 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2175 sendEvent(nNewLastPara
, m_nSelectionLastPara
,
2176 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2178 case SelChangeType::AddedPreviousPara
:
2179 // 3,2 -> 3,1; 4,4->4,3
2180 sendEvent(nNewLastPara
, m_nSelectionLastPara
- 1,
2181 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2183 sendEvent(nNewLastPara
, m_nSelectionLastPara
,
2184 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2186 case SelChangeType::EndParaBecameBehind
:
2188 sendEvent(m_nSelectionFirstPara
+ 1, m_nSelectionLastPara
,
2189 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2190 sendEvent(nNewLastPara
, nNewFirstPara
- 1,
2191 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2193 sendEvent(nNewLastPara
, m_nSelectionLastPara
,
2194 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2199 m_nSelectionFirstPara
= nNewFirstPara
;
2200 m_nSelectionFirstPos
= nNewFirstPos
;
2201 m_nSelectionLastPara
= nNewLastPara
;
2202 m_nSelectionLastPos
= nNewLastPos
;
2205 void Document::disposeParagraphs()
2207 for (auto const& paragraph
: *m_xParagraphs
)
2209 css::uno::Reference
< css::lang::XComponent
> xComponent(
2210 paragraph
.getParagraph().get(), css::uno::UNO_QUERY
);
2211 if (xComponent
.is())
2212 xComponent
->dispose();
2217 css::uno::Any
Document::mapFontColor(::Color
const & rColor
)
2219 return css::uno::makeAny(rColor
.GetRGBColor());
2220 // FIXME keep transparency?
2224 ::Color
Document::mapFontColor(css::uno::Any
const & rColor
)
2232 css::uno::Any
Document::mapFontWeight(::FontWeight nWeight
)
2234 // Map from ::FontWeight to css::awt::FontWeight, depends on order of
2235 // elements in ::FontWeight (vcl/vclenum.hxx):
2236 static float const aWeight
[]
2237 = { css::awt::FontWeight::DONTKNOW
, // WEIGHT_DONTKNOW
2238 css::awt::FontWeight::THIN
, // WEIGHT_THIN
2239 css::awt::FontWeight::ULTRALIGHT
, // WEIGHT_ULTRALIGHT
2240 css::awt::FontWeight::LIGHT
, // WEIGHT_LIGHT
2241 css::awt::FontWeight::SEMILIGHT
, // WEIGHT_SEMILIGHT
2242 css::awt::FontWeight::NORMAL
, // WEIGHT_NORMAL
2243 css::awt::FontWeight::NORMAL
, // WEIGHT_MEDIUM
2244 css::awt::FontWeight::SEMIBOLD
, // WEIGHT_SEMIBOLD
2245 css::awt::FontWeight::BOLD
, // WEIGHT_BOLD
2246 css::awt::FontWeight::ULTRABOLD
, // WEIGHT_ULTRABOLD
2247 css::awt::FontWeight::BLACK
}; // WEIGHT_BLACK
2248 return css::uno::Any(aWeight
[nWeight
]);
2252 ::FontWeight
Document::mapFontWeight(css::uno::Any
const & rWeight
)
2254 float nWeight
= css::awt::FontWeight::NORMAL
;
2255 rWeight
>>= nWeight
;
2256 return nWeight
<= css::awt::FontWeight::DONTKNOW
? WEIGHT_DONTKNOW
2257 : nWeight
<= css::awt::FontWeight::THIN
? WEIGHT_THIN
2258 : nWeight
<= css::awt::FontWeight::ULTRALIGHT
? WEIGHT_ULTRALIGHT
2259 : nWeight
<= css::awt::FontWeight::LIGHT
? WEIGHT_LIGHT
2260 : nWeight
<= css::awt::FontWeight::SEMILIGHT
? WEIGHT_SEMILIGHT
2261 : nWeight
<= css::awt::FontWeight::NORMAL
? WEIGHT_NORMAL
2262 : nWeight
<= css::awt::FontWeight::SEMIBOLD
? WEIGHT_SEMIBOLD
2263 : nWeight
<= css::awt::FontWeight::BOLD
? WEIGHT_BOLD
2264 : nWeight
<= css::awt::FontWeight::ULTRABOLD
? WEIGHT_ULTRABOLD
2270 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */