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/lang/IndexOutOfBoundsException.hpp>
24 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
25 #include <com/sun/star/i18n/Boundary.hpp>
26 #include <cppuhelper/exc_hlp.hxx>
27 #include <extended/textwindowaccessibility.hxx>
28 #include <comphelper/accessibleeventnotifier.hxx>
29 #include <unotools/accessiblerelationsethelper.hxx>
30 #include <unotools/accessiblestatesethelper.hxx>
31 #include <vcl/window.hxx>
32 #include <toolkit/helper/convert.hxx>
33 #include <comphelper/sequence.hxx>
39 namespace accessibility
41 void SfxListenerGuard::startListening(::SfxBroadcaster
& rNotifier
)
43 assert(m_pNotifier
== nullptr && "called more than once");
44 m_pNotifier
= &rNotifier
;
45 m_rListener
.StartListening(*m_pNotifier
, DuplicateHandling::Prevent
);
48 void SfxListenerGuard::endListening()
50 if (m_pNotifier
!= nullptr)
52 m_rListener
.EndListening(*m_pNotifier
);
53 m_pNotifier
= nullptr;
57 void WindowListenerGuard::startListening(vcl::Window
& rNotifier
)
59 assert(m_pNotifier
== nullptr && "called more than once");
60 m_pNotifier
= &rNotifier
;
61 m_pNotifier
->AddEventListener(m_aListener
);
64 void WindowListenerGuard::endListening()
68 m_pNotifier
->RemoveEventListener(m_aListener
);
69 m_pNotifier
= nullptr;
73 Paragraph::Paragraph(::rtl::Reference
< Document
> const & rDocument
,
74 Paragraphs::size_type nNumber
):
75 ParagraphBase(m_aMutex
),
76 m_xDocument(rDocument
),
80 m_aParagraphText
= m_xDocument
->retrieveParagraphText(this);
84 Paragraph::numberChanged(bool bIncremented
)
92 void Paragraph::textChanged()
94 OUString aParagraphText
= implGetText();
95 css::uno::Any aOldValue
, aNewValue
;
96 if ( implInitTextChangedEvent( m_aParagraphText
, aParagraphText
, aOldValue
, aNewValue
) )
98 m_aParagraphText
= aParagraphText
;
99 notifyEvent(css::accessibility::AccessibleEventId::
101 aOldValue
, aNewValue
);
105 void Paragraph::notifyEvent(::sal_Int16 nEventId
,
106 css::uno::Any
const & rOldValue
,
107 css::uno::Any
const & rNewValue
)
110 comphelper::AccessibleEventNotifier::addEvent( m_nClientId
, css::accessibility::AccessibleEventObject(
111 static_cast< ::cppu::OWeakObject
* >(this),
112 nEventId
, rNewValue
, rOldValue
) );
116 css::uno::Reference
< css::accessibility::XAccessibleContext
> SAL_CALL
117 Paragraph::getAccessibleContext()
124 ::sal_Int32 SAL_CALL
Paragraph::getAccessibleChildCount()
131 css::uno::Reference
< css::accessibility::XAccessible
> SAL_CALL
132 Paragraph::getAccessibleChild(::sal_Int32
)
135 throw css::lang::IndexOutOfBoundsException(
136 "textwindowaccessibility.cxx:"
137 " Paragraph::getAccessibleChild",
138 static_cast< css::uno::XWeak
* >(this));
142 css::uno::Reference
< css::accessibility::XAccessible
> SAL_CALL
143 Paragraph::getAccessibleParent()
146 return m_xDocument
->getAccessible();
150 ::sal_Int32 SAL_CALL
Paragraph::getAccessibleIndexInParent()
153 return m_xDocument
->retrieveParagraphIndex(this);
157 ::sal_Int16 SAL_CALL
Paragraph::getAccessibleRole()
160 return css::accessibility::AccessibleRole::PARAGRAPH
;
164 OUString SAL_CALL
Paragraph::getAccessibleDescription()
171 OUString SAL_CALL
Paragraph::getAccessibleName()
178 css::uno::Reference
< css::accessibility::XAccessibleRelationSet
>
179 SAL_CALL
Paragraph::getAccessibleRelationSet()
182 return m_xDocument
->retrieveParagraphRelationSet( this );
186 css::uno::Reference
< css::accessibility::XAccessibleStateSet
>
187 SAL_CALL
Paragraph::getAccessibleStateSet()
191 // FIXME Notification of changes (STATE_CHANGED) missing when
192 // m_rView.IsReadOnly() changes:
193 return new ::utl::AccessibleStateSetHelper(
194 m_xDocument
->retrieveParagraphState(this));
198 css::lang::Locale SAL_CALL
Paragraph::getLocale()
201 return m_xDocument
->retrieveLocale();
205 sal_Bool SAL_CALL
Paragraph::containsPoint(css::awt::Point
const & rPoint
)
208 css::awt::Rectangle
aRect(m_xDocument
->retrieveParagraphBounds(this,
210 return rPoint
.X
>= 0 && rPoint
.X
< aRect
.Width
211 && rPoint
.Y
>= 0 && rPoint
.Y
< aRect
.Height
;
215 css::uno::Reference
< css::accessibility::XAccessible
> SAL_CALL
216 Paragraph::getAccessibleAtPoint(css::awt::Point
const &)
223 css::awt::Rectangle SAL_CALL
Paragraph::getBounds()
226 return m_xDocument
->retrieveParagraphBounds(this, false);
230 css::awt::Point SAL_CALL
Paragraph::getLocation()
233 css::awt::Rectangle
aRect(m_xDocument
->retrieveParagraphBounds(this,
235 return css::awt::Point(aRect
.X
, aRect
.Y
);
239 css::awt::Point SAL_CALL
Paragraph::getLocationOnScreen()
242 css::awt::Rectangle
aRect(m_xDocument
->retrieveParagraphBounds(this,
244 return css::awt::Point(aRect
.X
, aRect
.Y
);
248 css::awt::Size SAL_CALL
Paragraph::getSize()
251 css::awt::Rectangle
aRect(m_xDocument
->retrieveParagraphBounds(this,
253 return css::awt::Size(aRect
.Width
, aRect
.Height
);
257 void SAL_CALL
Paragraph::grabFocus()
260 VclPtr
<vcl::Window
> pWindow
= m_xDocument
->GetWindow();
263 pWindow
->GrabFocus();
267 m_xDocument
->changeParagraphSelection(this, 0, 0);
269 catch (const css::lang::IndexOutOfBoundsException
& rEx
)
271 SAL_INFO("accessibility",
272 "textwindowaccessibility.cxx: Paragraph::grabFocus: caught unexpected "
278 css::util::Color SAL_CALL
Paragraph::getForeground()
284 css::util::Color SAL_CALL
Paragraph::getBackground()
290 ::sal_Int32 SAL_CALL
Paragraph::getCaretPosition()
293 return m_xDocument
->retrieveParagraphCaretPosition(this);
297 sal_Bool SAL_CALL
Paragraph::setCaretPosition(::sal_Int32 nIndex
)
300 m_xDocument
->changeParagraphSelection(this, nIndex
, nIndex
);
305 ::sal_Unicode SAL_CALL
Paragraph::getCharacter(::sal_Int32 nIndex
)
308 return OCommonAccessibleText::implGetCharacter(implGetText(), nIndex
);
312 css::uno::Sequence
< css::beans::PropertyValue
> SAL_CALL
313 Paragraph::getCharacterAttributes(::sal_Int32 nIndex
, const css::uno::Sequence
< OUString
>& aRequestedAttributes
)
316 return m_xDocument
->retrieveCharacterAttributes( this, nIndex
, aRequestedAttributes
);
320 css::awt::Rectangle SAL_CALL
321 Paragraph::getCharacterBounds(::sal_Int32 nIndex
)
324 css::awt::Rectangle
aBounds(m_xDocument
->retrieveCharacterBounds(this, nIndex
));
325 css::awt::Rectangle
aParaBounds(m_xDocument
->retrieveParagraphBounds(this, false));
326 aBounds
.X
-= aParaBounds
.X
;
327 aBounds
.Y
-= aParaBounds
.Y
;
332 ::sal_Int32 SAL_CALL
Paragraph::getCharacterCount()
335 return implGetText().getLength();
340 Paragraph::getIndexAtPoint(css::awt::Point
const & rPoint
)
343 css::awt::Point
aPoint(rPoint
);
344 css::awt::Rectangle
aParaBounds(m_xDocument
->retrieveParagraphBounds(this, false));
345 aPoint
.X
+= aParaBounds
.X
;
346 aPoint
.Y
+= aParaBounds
.Y
;
347 return m_xDocument
->retrieveCharacterIndex(this, aPoint
);
351 OUString SAL_CALL
Paragraph::getSelectedText()
355 return OCommonAccessibleText::getSelectedText();
359 ::sal_Int32 SAL_CALL
Paragraph::getSelectionStart()
362 return OCommonAccessibleText::getSelectionStart();
366 ::sal_Int32 SAL_CALL
Paragraph::getSelectionEnd()
369 return OCommonAccessibleText::getSelectionEnd();
373 sal_Bool SAL_CALL
Paragraph::setSelection(::sal_Int32 nStartIndex
,
374 ::sal_Int32 nEndIndex
)
377 m_xDocument
->changeParagraphSelection(this, nStartIndex
, nEndIndex
);
382 OUString SAL_CALL
Paragraph::getText()
385 return implGetText();
389 OUString SAL_CALL
Paragraph::getTextRange(::sal_Int32 nStartIndex
,
390 ::sal_Int32 nEndIndex
)
393 return OCommonAccessibleText::implGetTextRange(implGetText(), nStartIndex
, nEndIndex
);
397 css::accessibility::TextSegment SAL_CALL
Paragraph::getTextAtIndex( sal_Int32 nIndex
, sal_Int16 aTextType
)
400 return OCommonAccessibleText::getTextAtIndex(nIndex
, aTextType
);
404 css::accessibility::TextSegment SAL_CALL
Paragraph::getTextBeforeIndex( sal_Int32 nIndex
, sal_Int16 aTextType
)
407 return OCommonAccessibleText::getTextBeforeIndex(nIndex
, aTextType
);
411 css::accessibility::TextSegment SAL_CALL
Paragraph::getTextBehindIndex( sal_Int32 nIndex
, sal_Int16 aTextType
)
414 return OCommonAccessibleText::getTextBehindIndex(nIndex
, aTextType
);
418 sal_Bool SAL_CALL
Paragraph::copyText(::sal_Int32 nStartIndex
,
419 ::sal_Int32 nEndIndex
)
422 m_xDocument
->copyParagraphText(this, nStartIndex
, nEndIndex
);
427 sal_Bool SAL_CALL
Paragraph::cutText(::sal_Int32 nStartIndex
,
428 ::sal_Int32 nEndIndex
)
431 m_xDocument
->changeParagraphText(this, nStartIndex
, nEndIndex
, true, false,
437 sal_Bool SAL_CALL
Paragraph::pasteText(::sal_Int32 nIndex
)
440 m_xDocument
->changeParagraphText(this, nIndex
, nIndex
, false, true,
446 sal_Bool SAL_CALL
Paragraph::deleteText(::sal_Int32 nStartIndex
,
447 ::sal_Int32 nEndIndex
)
450 m_xDocument
->changeParagraphText(this, nStartIndex
, nEndIndex
, false, false,
456 sal_Bool SAL_CALL
Paragraph::insertText(OUString
const & rText
,
460 m_xDocument
->changeParagraphText(this, nIndex
, nIndex
, false, false, rText
);
466 Paragraph::replaceText(::sal_Int32 nStartIndex
, ::sal_Int32 nEndIndex
,
467 OUString
const & rReplacement
)
470 m_xDocument
->changeParagraphText(this, nStartIndex
, nEndIndex
, false, false,
476 sal_Bool SAL_CALL
Paragraph::setAttributes(
477 ::sal_Int32 nStartIndex
, ::sal_Int32 nEndIndex
,
478 css::uno::Sequence
< css::beans::PropertyValue
> const & rAttributeSet
)
481 m_xDocument
->changeParagraphAttributes(this, nStartIndex
, nEndIndex
,
487 sal_Bool SAL_CALL
Paragraph::setText(OUString
const & rText
)
490 m_xDocument
->changeParagraphText(this, rText
);
495 css::uno::Sequence
< css::beans::PropertyValue
> SAL_CALL
496 Paragraph::getDefaultAttributes(const css::uno::Sequence
< OUString
>&)
499 return {}; // default attributes are not supported by text engine
503 css::uno::Sequence
< css::beans::PropertyValue
> SAL_CALL
504 Paragraph::getRunAttributes(::sal_Int32 Index
, const css::uno::Sequence
< OUString
>& RequestedAttributes
)
507 return m_xDocument
->retrieveRunAttributes( this, Index
, RequestedAttributes
);
511 ::sal_Int32 SAL_CALL
Paragraph::getLineNumberAtIndex( ::sal_Int32 nIndex
)
515 ::sal_Int32 nLineNo
= -1;
516 m_xDocument
->retrieveParagraphLineBoundary( this, nIndex
, &nLineNo
);
522 css::accessibility::TextSegment SAL_CALL
Paragraph::getTextAtLineNumber( ::sal_Int32 nLineNo
)
526 css::i18n::Boundary aBoundary
=
527 m_xDocument
->retrieveParagraphBoundaryOfLine( this, nLineNo
);
529 return css::accessibility::TextSegment( getTextRange(aBoundary
.startPos
, aBoundary
.endPos
),
530 aBoundary
.startPos
, aBoundary
.endPos
);
534 css::accessibility::TextSegment SAL_CALL
Paragraph::getTextAtLineWithCaret( )
538 sal_Int32 nLineNo
= getNumberOfLineWithCaret();
541 return ( nLineNo
>= 0 ) ?
542 getTextAtLineNumber( nLineNo
) :
543 css::accessibility::TextSegment();
544 } catch (const css::lang::IndexOutOfBoundsException
&) {
545 css::uno::Any anyEx
= cppu::getCaughtException();
546 throw css::lang::WrappedTargetRuntimeException(
547 "textwindowaccessibility.cxx:"
548 " Paragraph::getTextAtLineWithCaret",
549 static_cast< css::uno::XWeak
* >( this ), anyEx
);
554 ::sal_Int32 SAL_CALL
Paragraph::getNumberOfLineWithCaret( )
557 return m_xDocument
->retrieveParagraphLineWithCursor(this);
562 void SAL_CALL
Paragraph::addAccessibleEventListener(
564 css::accessibility::XAccessibleEventListener
> const & rListener
)
568 ::osl::ClearableMutexGuard
aGuard(rBHelper
.rMutex
);
569 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
572 rListener
->disposing(css::lang::EventObject(
573 static_cast< ::cppu::OWeakObject
* >(this)));
578 m_nClientId
= comphelper::AccessibleEventNotifier::registerClient( );
579 comphelper::AccessibleEventNotifier::addEventListener( m_nClientId
, rListener
);
585 void SAL_CALL
Paragraph::removeAccessibleEventListener(
587 css::accessibility::XAccessibleEventListener
> const & rListener
)
589 comphelper::AccessibleEventNotifier::TClientId nId
= 0;
591 ::osl::ClearableMutexGuard
aGuard(rBHelper
.rMutex
);
592 if (rListener
.is() && m_nClientId
!= 0
593 && comphelper::AccessibleEventNotifier::removeEventListener( m_nClientId
, rListener
) == 0)
601 // no listeners anymore
602 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
603 // and at least to us not firing any events anymore, in case somebody calls
604 // NotifyAccessibleEvent, again
605 comphelper::AccessibleEventNotifier::revokeClient(nId
);
610 void SAL_CALL
Paragraph::disposing()
612 comphelper::AccessibleEventNotifier::TClientId nId
= 0;
614 ::osl::ClearableMutexGuard
aGuard(rBHelper
.rMutex
);
619 comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing(nId
, *this);
623 OUString
Paragraph::implGetText()
625 return m_xDocument
->retrieveParagraphText(this);
629 css::lang::Locale
Paragraph::implGetLocale()
631 return m_xDocument
->retrieveLocale();
635 void Paragraph::implGetSelection(::sal_Int32
& rStartIndex
,
636 ::sal_Int32
& rEndIndex
)
638 m_xDocument
->retrieveParagraphSelection(this, &rStartIndex
, &rEndIndex
);
642 void Paragraph::implGetParagraphBoundary( const OUString
& rText
,
643 css::i18n::Boundary
& rBoundary
,
646 ::sal_Int32 nLength
= rText
.getLength();
648 if ( implIsValidIndex( nIndex
, nLength
) )
650 rBoundary
.startPos
= 0;
651 rBoundary
.endPos
= nLength
;
655 rBoundary
.startPos
= nIndex
;
656 rBoundary
.endPos
= nIndex
;
661 void Paragraph::implGetLineBoundary( const OUString
& rText
,
662 css::i18n::Boundary
& rBoundary
,
665 ::sal_Int32 nLength
= rText
.getLength();
667 if ( implIsValidIndex( nIndex
, nLength
) || nIndex
== nLength
)
669 css::i18n::Boundary aBoundary
=
670 m_xDocument
->retrieveParagraphLineBoundary( this, nIndex
, nullptr );
671 rBoundary
.startPos
= aBoundary
.startPos
;
672 rBoundary
.endPos
= aBoundary
.endPos
;
676 rBoundary
.startPos
= nIndex
;
677 rBoundary
.endPos
= nIndex
;
682 void Paragraph::checkDisposed()
684 ::osl::MutexGuard
aGuard(rBHelper
.rMutex
);
685 if (!(rBHelper
.bDisposed
|| rBHelper
.bInDispose
))
687 throw css::lang::DisposedException(
688 OUString(), static_cast< css::uno::XWeak
* >(this));
691 Document::Document(::VCLXWindow
* pVclXWindow
, ::TextEngine
& rEngine
,
693 VCLXAccessibleComponent(pVclXWindow
),
694 m_xAccessible(pVclXWindow
),
697 m_aEngineListener(*this),
698 m_aViewListener(LINK(this, Document
, WindowEventHandler
)),
701 m_nVisibleBeginOffset(0),
702 m_nSelectionFirstPara(-1),
703 m_nSelectionFirstPos(-1),
704 m_nSelectionLastPara(-1),
705 m_nSelectionLastPos(-1),
706 m_bSelectionChangedNotification(false)
709 css::lang::Locale
Document::retrieveLocale()
711 SolarMutexGuard aGuard
;
712 return m_rEngine
.GetLocale();
715 ::sal_Int32
Document::retrieveParagraphIndex(Paragraph
const * pParagraph
)
717 ::osl::MutexGuard
aInternalGuard(GetMutex());
719 // If a client holds on to a Paragraph that is no longer visible, it can
720 // happen that this Paragraph lies outside the range from m_aVisibleBegin
721 // to m_aVisibleEnd. In that case, return -1 instead of a valid index:
722 Paragraphs::iterator
aPara(m_xParagraphs
->begin()
723 + pParagraph
->getNumber());
724 return aPara
< m_aVisibleBegin
|| aPara
>= m_aVisibleEnd
725 ? -1 : static_cast< ::sal_Int32
>(aPara
- m_aVisibleBegin
);
726 // XXX numeric overflow
729 ::sal_Int64
Document::retrieveParagraphState(Paragraph
const * pParagraph
)
731 ::osl::MutexGuard
aInternalGuard(GetMutex());
733 // If a client holds on to a Paragraph that is no longer visible, it can
734 // happen that this Paragraph lies outside the range from m_aVisibleBegin
735 // to m_aVisibleEnd. In that case, it is neither VISIBLE nor SHOWING:
737 = (static_cast< ::sal_Int64
>(1)
738 << css::accessibility::AccessibleStateType::ENABLED
)
739 | (static_cast< ::sal_Int64
>(1)
740 << css::accessibility::AccessibleStateType::SENSITIVE
)
741 | (static_cast< ::sal_Int64
>(1)
742 << css::accessibility::AccessibleStateType::FOCUSABLE
)
743 | (static_cast< ::sal_Int64
>(1)
744 << css::accessibility::AccessibleStateType::MULTI_LINE
);
745 if (!m_rView
.IsReadOnly())
746 nState
|= (static_cast< ::sal_Int64
>(1)
747 << css::accessibility::AccessibleStateType::EDITABLE
);
748 Paragraphs::iterator
aPara(m_xParagraphs
->begin()
749 + pParagraph
->getNumber());
750 if (aPara
>= m_aVisibleBegin
&& aPara
< m_aVisibleEnd
)
753 |= (static_cast< ::sal_Int64
>(1)
754 << css::accessibility::AccessibleStateType::VISIBLE
)
755 | (static_cast< ::sal_Int64
>(1)
756 << css::accessibility::AccessibleStateType::SHOWING
);
757 if (aPara
== m_aFocused
)
758 nState
|= (static_cast< ::sal_Int64
>(1)
759 << css::accessibility::AccessibleStateType::FOCUSED
);
765 Document::retrieveParagraphBounds(Paragraph
const * pParagraph
,
768 SolarMutexGuard aGuard
;
769 ::osl::MutexGuard
aInternalGuard(GetMutex());
771 // If a client holds on to a Paragraph that is no longer visible (as it
772 // scrolled out the top of the view), it can happen that this Paragraph
773 // lies before m_aVisibleBegin. In that case, calculate the vertical
774 // position of the Paragraph starting at paragraph 0, otherwise optimize
775 // and start at m_aVisibleBegin:
776 Paragraphs::iterator
aPara(m_xParagraphs
->begin()
777 + pParagraph
->getNumber());
779 Paragraphs::iterator aIt
;
780 if (aPara
< m_aVisibleBegin
)
783 aIt
= m_xParagraphs
->begin();
787 nPos
= m_nViewOffset
- m_nVisibleBeginOffset
;
788 aIt
= m_aVisibleBegin
;
790 for (; aIt
!= aPara
; ++aIt
)
791 nPos
+= aIt
->getHeight();
795 aOrig
= m_rView
.GetWindow()->OutputToAbsoluteScreenPixel(aOrig
);
797 return css::awt::Rectangle(
798 static_cast< ::sal_Int32
>(aOrig
.X()),
799 static_cast< ::sal_Int32
>(aOrig
.Y()) + nPos
- m_nViewOffset
,
800 m_rView
.GetWindow()->GetOutputSizePixel().Width(), aPara
->getHeight());
801 // XXX numeric overflow (3x)
805 Document::retrieveParagraphText(Paragraph
const * pParagraph
)
807 SolarMutexGuard aGuard
;
808 ::osl::MutexGuard
aInternalGuard(GetMutex());
809 return m_rEngine
.GetText(static_cast< ::sal_uInt32
>(pParagraph
->getNumber()));
810 // numeric overflow cannot happen here
813 void Document::retrieveParagraphSelection(Paragraph
const * pParagraph
,
814 ::sal_Int32
* pBegin
,
817 SolarMutexGuard aGuard
;
818 ::osl::MutexGuard
aInternalGuard(GetMutex());
819 ::TextSelection
const & rSelection
= m_rView
.GetSelection();
820 Paragraphs::size_type nNumber
= pParagraph
->getNumber();
821 TextPaM
aStartPaM( rSelection
.GetStart() );
822 TextPaM
aEndPaM( rSelection
.GetEnd() );
823 TextPaM
aMinPaM( std::min( aStartPaM
, aEndPaM
) );
824 TextPaM
aMaxPaM( std::max( aStartPaM
, aEndPaM
) );
826 if ( nNumber
>= aMinPaM
.GetPara() && nNumber
<= aMaxPaM
.GetPara() )
828 *pBegin
= nNumber
> aMinPaM
.GetPara() ? 0 : aMinPaM
.GetIndex();
829 // XXX numeric overflow
830 *pEnd
= nNumber
< aMaxPaM
.GetPara()
831 ? m_rEngine
.GetText(static_cast< ::sal_uLong
>(nNumber
)).getLength()
832 : aMaxPaM
.GetIndex();
833 // XXX numeric overflow (3x)
835 if ( aStartPaM
> aEndPaM
)
836 std::swap( *pBegin
, *pEnd
);
845 ::sal_Int32
Document::retrieveParagraphCaretPosition(Paragraph
const * pParagraph
)
847 SolarMutexGuard aGuard
;
848 ::osl::MutexGuard
aInternalGuard(GetMutex());
849 ::TextSelection
const & rSelection
= m_rView
.GetSelection();
850 Paragraphs::size_type nNumber
= pParagraph
->getNumber();
851 TextPaM
aEndPaM( rSelection
.GetEnd() );
853 return aEndPaM
.GetPara() == nNumber
? aEndPaM
.GetIndex() : -1;
857 Document::retrieveCharacterBounds(Paragraph
const * pParagraph
,
860 SolarMutexGuard aGuard
;
861 ::osl::MutexGuard
aInternalGuard(GetMutex());
862 ::sal_uLong nNumber
= static_cast< ::sal_uLong
>(pParagraph
->getNumber());
863 sal_Int32 nLength
= m_rEngine
.GetText(nNumber
).getLength();
864 // XXX numeric overflow
865 if (nIndex
< 0 || nIndex
> nLength
)
866 throw css::lang::IndexOutOfBoundsException(
867 "textwindowaccessibility.cxx:"
868 " Document::retrieveCharacterAttributes",
869 static_cast< css::uno::XWeak
* >(this));
870 css::awt::Rectangle
aBounds( 0, 0, 0, 0 );
871 if ( nIndex
== nLength
)
873 aBounds
= AWTRectangle(
874 m_rEngine
.PaMtoEditCursor(::TextPaM(nNumber
, nIndex
)));
878 ::tools::Rectangle
aLeft(
879 m_rEngine
.PaMtoEditCursor(::TextPaM(nNumber
, nIndex
)));
880 // XXX numeric overflow
881 ::tools::Rectangle
aRight(
882 m_rEngine
.PaMtoEditCursor(::TextPaM(nNumber
, nIndex
+ 1)));
883 // XXX numeric overflow (2x)
884 // FIXME If the vertical extends of the two cursors do not match, assume
885 // nIndex is the last character on the line; the bounding box will then
886 // extend to m_rEnginge.GetMaxTextWidth():
887 ::sal_Int32 nWidth
= (aLeft
.Top() == aRight
.Top()
888 && aLeft
.Bottom() == aRight
.Bottom())
889 ? static_cast< ::sal_Int32
>(aRight
.Left() - aLeft
.Left())
890 : static_cast< ::sal_Int32
>(m_rEngine
.GetMaxTextWidth()
892 // XXX numeric overflow (4x)
893 aBounds
= css::awt::Rectangle(static_cast< ::sal_Int32
>(aLeft
.Left()),
894 static_cast< ::sal_Int32
>(aLeft
.Top() - m_nViewOffset
),
896 static_cast< ::sal_Int32
>(aLeft
.Bottom()
898 // XXX numeric overflow (4x)
903 ::sal_Int32
Document::retrieveCharacterIndex(Paragraph
const * pParagraph
,
904 css::awt::Point
const & rPoint
)
906 SolarMutexGuard aGuard
;
907 ::osl::MutexGuard
aInternalGuard(GetMutex());
908 ::sal_uLong nNumber
= static_cast< ::sal_uLong
>(pParagraph
->getNumber());
909 // XXX numeric overflow
910 ::TextPaM
aPaM(m_rEngine
.GetPaM(::Point(static_cast< long >(rPoint
.X
),
911 static_cast< long >(rPoint
.Y
))));
912 // XXX numeric overflow (2x)
913 return aPaM
.GetPara() == nNumber
? aPaM
.GetIndex() : -1;
914 // XXX numeric overflow
919 const css::beans::PropertyValue
* pValues
;
920 explicit IndexCompare(const css::beans::PropertyValue
* pVals
)
924 bool operator() ( sal_Int32 a
, sal_Int32 b
) const
926 return pValues
[a
].Name
< pValues
[b
].Name
;
930 css::uno::Sequence
< css::beans::PropertyValue
>
931 Document::retrieveCharacterAttributes(
932 Paragraph
const * pParagraph
, ::sal_Int32 nIndex
,
933 const css::uno::Sequence
< OUString
>& aRequestedAttributes
)
935 SolarMutexGuard aGuard
;
937 vcl::Font aFont
= m_rEngine
.GetFont();
938 const sal_Int32 AttributeCount
= 9;
940 css::uno::Sequence
< css::beans::PropertyValue
> aAttribs( AttributeCount
);
942 //character background color
943 aAttribs
[i
].Name
= "CharBackColor";
944 aAttribs
[i
].Handle
= -1;
945 aAttribs
[i
].Value
= mapFontColor( aFont
.GetFillColor() );
946 aAttribs
[i
].State
= css::beans::PropertyState_DIRECT_VALUE
;
950 aAttribs
[i
].Name
= "CharColor";
951 aAttribs
[i
].Handle
= -1;
952 //aAttribs[i].Value = mapFontColor( aFont.GetColor() );
953 aAttribs
[i
].Value
= mapFontColor( m_rEngine
.GetTextColor() );
954 aAttribs
[i
].State
= css::beans::PropertyState_DIRECT_VALUE
;
957 //character font name
958 aAttribs
[i
].Name
= "CharFontName";
959 aAttribs
[i
].Handle
= -1;
960 aAttribs
[i
].Value
<<= aFont
.GetFamilyName();
961 aAttribs
[i
].State
= css::beans::PropertyState_DIRECT_VALUE
;
965 aAttribs
[i
].Name
= "CharHeight";
966 aAttribs
[i
].Handle
= -1;
967 aAttribs
[i
].Value
<<= static_cast<sal_Int16
>(aFont
.GetFontHeight());
968 aAttribs
[i
].State
= css::beans::PropertyState_DIRECT_VALUE
;
972 aAttribs
[i
].Name
= "CharPosture";
973 aAttribs
[i
].Handle
= -1;
974 aAttribs
[i
].Value
<<= static_cast<sal_Int16
>(aFont
.GetItalic());
975 aAttribs
[i
].State
= css::beans::PropertyState_DIRECT_VALUE
;
980 aAttribs[i].Name = "CharRelief";
981 aAttribs[i].Handle = -1;
982 aAttribs[i].Value = css::uno::Any( (sal_Int16)aFont.GetRelief() );
983 aAttribs[i].State = css::beans::PropertyState_DIRECT_VALUE;
987 //character strikeout
988 aAttribs
[i
].Name
= "CharStrikeout";
989 aAttribs
[i
].Handle
= -1;
990 aAttribs
[i
].Value
<<= static_cast<sal_Int16
>(aFont
.GetStrikeout());
991 aAttribs
[i
].State
= css::beans::PropertyState_DIRECT_VALUE
;
994 //character underline
995 aAttribs
[i
].Name
= "CharUnderline";
996 aAttribs
[i
].Handle
= -1;
997 aAttribs
[i
].Value
<<= static_cast<sal_Int16
>(aFont
.GetUnderline());
998 aAttribs
[i
].State
= css::beans::PropertyState_DIRECT_VALUE
;
1002 aAttribs
[i
].Name
= "CharWeight";
1003 aAttribs
[i
].Handle
= -1;
1004 aAttribs
[i
].Value
<<= static_cast<float>(aFont
.GetWeight());
1005 aAttribs
[i
].State
= css::beans::PropertyState_DIRECT_VALUE
;
1008 //character alignment
1009 aAttribs
[i
].Name
= "ParaAdjust";
1010 aAttribs
[i
].Handle
= -1;
1011 aAttribs
[i
].Value
<<= static_cast<sal_Int16
>(m_rEngine
.GetTextAlign());
1012 aAttribs
[i
].State
= css::beans::PropertyState_DIRECT_VALUE
;
1015 ::osl::MutexGuard
aInternalGuard(GetMutex());
1016 ::sal_uLong nNumber
= static_cast< ::sal_uLong
>(pParagraph
->getNumber());
1017 // XXX numeric overflow
1018 // nIndex can be equal to getLength();
1019 if (nIndex
< 0 || nIndex
> m_rEngine
.GetText(nNumber
).getLength())
1020 throw css::lang::IndexOutOfBoundsException(
1021 "textwindowaccessibility.cxx:"
1022 " Document::retrieveCharacterAttributes",
1023 static_cast< css::uno::XWeak
* >(this));
1026 // retrieve run attributes
1027 tPropValMap aCharAttrSeq
;
1028 retrieveRunAttributesImpl( pParagraph
, nIndex
, aRequestedAttributes
, aCharAttrSeq
);
1030 css::beans::PropertyValue
* pValues
= aAttribs
.getArray();
1031 for (i
= 0; i
< AttributeCount
; i
++,pValues
++)
1033 aCharAttrSeq
[ pValues
->Name
] = *pValues
;
1036 css::uno::Sequence
< css::beans::PropertyValue
> aRes
= comphelper::mapValuesToSequence( aCharAttrSeq
);
1038 // sort the attributes
1039 sal_Int32 nLength
= aRes
.getLength();
1040 const css::beans::PropertyValue
* pPairs
= aRes
.getConstArray();
1041 std::unique_ptr
<sal_Int32
[]> pIndices( new sal_Int32
[nLength
] );
1042 for( i
= 0; i
< nLength
; i
++ )
1044 std::sort( &pIndices
[0], &pIndices
[nLength
], IndexCompare(pPairs
) );
1045 // create sorted sequences according to index array
1046 css::uno::Sequence
< css::beans::PropertyValue
> aNewValues( nLength
);
1047 css::beans::PropertyValue
* pNewValues
= aNewValues
.getArray();
1048 for( i
= 0; i
< nLength
; i
++ )
1050 pNewValues
[i
] = pPairs
[pIndices
[i
]];
1056 void Document::retrieveRunAttributesImpl(
1057 Paragraph
const * pParagraph
, ::sal_Int32 Index
,
1058 const css::uno::Sequence
< OUString
>& RequestedAttributes
,
1059 tPropValMap
& rRunAttrSeq
)
1061 ::sal_uLong nNumber
= static_cast< ::sal_uLong
>( pParagraph
->getNumber() );
1062 ::TextPaM
aPaM( nNumber
, Index
);
1063 // XXX numeric overflow
1064 ::TextAttribFontColor
const * pColor
1065 = static_cast< ::TextAttribFontColor
const * >(
1066 m_rEngine
.FindAttrib( aPaM
, TEXTATTR_FONTCOLOR
) );
1067 ::TextAttribFontWeight
const * pWeight
1068 = static_cast< ::TextAttribFontWeight
const * >(
1069 m_rEngine
.FindAttrib( aPaM
, TEXTATTR_FONTWEIGHT
) );
1070 tPropValMap aRunAttrSeq
;
1073 css::beans::PropertyValue aPropVal
;
1074 aPropVal
.Name
= "CharColor";
1075 aPropVal
.Handle
= -1;
1076 aPropVal
.Value
= mapFontColor( pColor
->GetColor() );
1077 aPropVal
.State
= css::beans::PropertyState_DIRECT_VALUE
;
1078 aRunAttrSeq
[ aPropVal
.Name
] = aPropVal
;
1082 css::beans::PropertyValue aPropVal
;
1083 aPropVal
.Name
= "CharWeight";
1084 aPropVal
.Handle
= -1;
1085 aPropVal
.Value
= mapFontWeight( pWeight
->getFontWeight() );
1086 aPropVal
.State
= css::beans::PropertyState_DIRECT_VALUE
;
1087 aRunAttrSeq
[ aPropVal
.Name
] = aPropVal
;
1089 if ( RequestedAttributes
.getLength() == 0 )
1091 rRunAttrSeq
= aRunAttrSeq
;
1095 const OUString
* pReqAttrs
= RequestedAttributes
.getConstArray();
1096 const ::sal_Int32 nLength
= RequestedAttributes
.getLength();
1097 for ( ::sal_Int32 i
= 0; i
< nLength
; ++i
)
1099 tPropValMap::iterator aIter
= aRunAttrSeq
.find( pReqAttrs
[i
] );
1100 if ( aIter
!= aRunAttrSeq
.end() )
1102 rRunAttrSeq
[ (*aIter
).first
] = (*aIter
).second
;
1108 css::uno::Sequence
< css::beans::PropertyValue
>
1109 Document::retrieveRunAttributes(
1110 Paragraph
const * pParagraph
, ::sal_Int32 Index
,
1111 const css::uno::Sequence
< OUString
>& RequestedAttributes
)
1113 SolarMutexGuard aGuard
;
1114 ::osl::MutexGuard
aInternalGuard( GetMutex() );
1115 ::sal_uLong nNumber
= static_cast< ::sal_uLong
>( pParagraph
->getNumber() );
1116 // XXX numeric overflow
1117 if ( Index
< 0 || Index
>= m_rEngine
.GetText(nNumber
).getLength() )
1118 throw css::lang::IndexOutOfBoundsException(
1119 "textwindowaccessibility.cxx:"
1120 " Document::retrieveRunAttributes",
1121 static_cast< css::uno::XWeak
* >( this ) );
1123 tPropValMap aRunAttrSeq
;
1124 retrieveRunAttributesImpl( pParagraph
, Index
, RequestedAttributes
, aRunAttrSeq
);
1125 return comphelper::mapValuesToSequence( aRunAttrSeq
);
1128 void Document::changeParagraphText(Paragraph
const * pParagraph
,
1129 OUString
const & rText
)
1131 SolarMutexGuard aGuard
;
1133 ::osl::MutexGuard
aInternalGuard(GetMutex());
1134 ::sal_uLong nNumber
= static_cast< ::sal_uLong
>(pParagraph
->getNumber());
1135 // XXX numeric overflow
1136 changeParagraphText(nNumber
, 0, m_rEngine
.GetTextLen(nNumber
), false,
1141 void Document::changeParagraphText(Paragraph
const * pParagraph
,
1142 ::sal_Int32 nBegin
, ::sal_Int32 nEnd
,
1143 bool bCut
, bool bPaste
,
1144 OUString
const & rText
)
1146 SolarMutexGuard aGuard
;
1148 ::osl::MutexGuard
aInternalGuard(GetMutex());
1149 ::sal_uLong nNumber
= static_cast< ::sal_uLong
>(pParagraph
->getNumber());
1150 // XXX numeric overflow
1151 if (nBegin
< 0 || nBegin
> nEnd
1152 || nEnd
> m_rEngine
.GetText(nNumber
).getLength())
1153 throw css::lang::IndexOutOfBoundsException(
1154 "textwindowaccessibility.cxx:"
1155 " Document::changeParagraphText",
1156 static_cast< css::uno::XWeak
* >(this));
1157 changeParagraphText(nNumber
, static_cast< ::sal_uInt16
>(nBegin
),
1158 static_cast< ::sal_uInt16
>(nEnd
), bCut
, bPaste
, rText
);
1159 // XXX numeric overflow (2x)
1163 void Document::copyParagraphText(Paragraph
const * pParagraph
,
1164 ::sal_Int32 nBegin
, ::sal_Int32 nEnd
)
1166 SolarMutexGuard aGuard
;
1168 ::osl::MutexGuard
aInternalGuard(GetMutex());
1169 ::sal_uLong nNumber
= static_cast< ::sal_uLong
>(pParagraph
->getNumber());
1170 // XXX numeric overflow
1171 if (nBegin
< 0 || nBegin
> nEnd
1172 || nEnd
> m_rEngine
.GetText(nNumber
).getLength())
1173 throw css::lang::IndexOutOfBoundsException(
1174 "textwindowaccessibility.cxx:"
1175 " Document::copyParagraphText",
1176 static_cast< css::uno::XWeak
* >(this));
1177 m_rView
.SetSelection(
1178 ::TextSelection(::TextPaM(nNumber
, nBegin
),
1179 ::TextPaM(nNumber
, nEnd
)));
1180 // XXX numeric overflow (2x)
1185 void Document::changeParagraphAttributes(
1186 Paragraph
const * pParagraph
, ::sal_Int32 nBegin
, ::sal_Int32 nEnd
,
1187 css::uno::Sequence
< css::beans::PropertyValue
> const & rAttributeSet
)
1189 SolarMutexGuard aGuard
;
1191 ::osl::MutexGuard
aInternalGuard(GetMutex());
1192 ::sal_uLong nNumber
= static_cast< ::sal_uLong
>(pParagraph
->getNumber());
1193 // XXX numeric overflow
1194 if (nBegin
< 0 || nBegin
> nEnd
1195 || nEnd
> m_rEngine
.GetText(nNumber
).getLength())
1196 throw css::lang::IndexOutOfBoundsException(
1197 "textwindowaccessibility.cxx:"
1198 " Document::changeParagraphAttributes",
1199 static_cast< css::uno::XWeak
* >(this));
1201 // FIXME The new attributes are added to any attributes already set,
1202 // they do not replace the old attributes as required by
1203 // XAccessibleEditableText.setAttributes:
1204 for (::sal_Int32 i
= 0; i
< rAttributeSet
.getLength(); ++i
)
1205 if ( rAttributeSet
[i
].Name
== "CharColor" )
1206 m_rEngine
.SetAttrib(::TextAttribFontColor(
1207 mapFontColor(rAttributeSet
[i
].Value
)),
1208 nNumber
, nBegin
, nEnd
);
1209 // XXX numeric overflow (2x)
1210 else if ( rAttributeSet
[i
].Name
== "CharWeight" )
1211 m_rEngine
.SetAttrib(::TextAttribFontWeight(
1212 mapFontWeight(rAttributeSet
[i
].Value
)),
1213 nNumber
, nBegin
, nEnd
);
1214 // XXX numeric overflow (2x)
1218 void Document::changeParagraphSelection(Paragraph
const * pParagraph
,
1219 ::sal_Int32 nBegin
, ::sal_Int32 nEnd
)
1221 SolarMutexGuard aGuard
;
1223 ::osl::MutexGuard
aInternalGuard(GetMutex());
1224 ::sal_uLong nNumber
= static_cast< ::sal_uLong
>(pParagraph
->getNumber());
1225 // XXX numeric overflow
1226 if (nBegin
< 0 || nBegin
> nEnd
1227 || nEnd
> m_rEngine
.GetText(nNumber
).getLength())
1228 throw css::lang::IndexOutOfBoundsException(
1229 "textwindowaccessibility.cxx:"
1230 " Document::changeParagraphSelection",
1231 static_cast< css::uno::XWeak
* >(this));
1232 m_rView
.SetSelection(
1233 ::TextSelection(::TextPaM(nNumber
, nBegin
),
1234 ::TextPaM(nNumber
, nEnd
)));
1235 // XXX numeric overflow (2x)
1240 Document::retrieveParagraphLineBoundary( Paragraph
const * pParagraph
,
1241 ::sal_Int32 nIndex
, ::sal_Int32
*pLineNo
)
1243 css::i18n::Boundary aBoundary
;
1244 aBoundary
.startPos
= nIndex
;
1245 aBoundary
.endPos
= nIndex
;
1247 SolarMutexGuard aGuard
;
1249 ::osl::MutexGuard
aInternalGuard( GetMutex() );
1250 ::sal_uLong nNumber
= static_cast< ::sal_uLong
>( pParagraph
->getNumber() );
1251 if ( nIndex
< 0 || nIndex
> m_rEngine
.GetText( nNumber
).getLength() )
1252 throw css::lang::IndexOutOfBoundsException(
1253 "textwindowaccessibility.cxx:"
1254 " Document::retrieveParagraphLineBoundary",
1255 static_cast< css::uno::XWeak
* >( this ) );
1256 ::sal_Int32 nLineStart
= 0;
1257 ::sal_Int32 nLineEnd
= 0;
1258 ::sal_uInt16 nLineCount
= m_rEngine
.GetLineCount( nNumber
);
1259 for ( ::sal_uInt16 nLine
= 0; nLine
< nLineCount
; ++nLine
)
1261 nLineStart
= nLineEnd
;
1262 nLineEnd
+= m_rEngine
.GetLineLen( nNumber
, nLine
);
1263 if ( nIndex
>= nLineStart
&& ( ( nLine
== nLineCount
- 1 ) ? nIndex
<= nLineEnd
: nIndex
< nLineEnd
) )
1265 aBoundary
.startPos
= nLineStart
;
1266 aBoundary
.endPos
= nLineEnd
;
1278 Document::retrieveParagraphBoundaryOfLine( Paragraph
const * pParagraph
,
1279 ::sal_Int32 nLineNo
)
1281 css::i18n::Boundary aBoundary
;
1282 aBoundary
.startPos
= 0;
1283 aBoundary
.endPos
= 0;
1285 SolarMutexGuard aGuard
;
1287 ::osl::MutexGuard
aInternalGuard( GetMutex() );
1288 ::sal_uLong nNumber
= static_cast< ::sal_uLong
>( pParagraph
->getNumber() );
1289 if ( nLineNo
>= m_rEngine
.GetLineCount( nNumber
) )
1290 throw css::lang::IndexOutOfBoundsException(
1291 "textwindowaccessibility.cxx:"
1292 " Document::retrieveParagraphBoundaryOfLine",
1293 static_cast< css::uno::XWeak
* >( this ) );
1294 ::sal_Int32 nLineStart
= 0;
1295 ::sal_Int32 nLineEnd
= 0;
1296 for ( ::sal_Int32 nLine
= 0; nLine
<= nLineNo
; ++nLine
)
1298 nLineStart
= nLineEnd
;
1299 nLineEnd
+= m_rEngine
.GetLineLen( nNumber
, nLine
);
1302 aBoundary
.startPos
= nLineStart
;
1303 aBoundary
.endPos
= nLineEnd
;
1309 sal_Int32
Document::retrieveParagraphLineWithCursor( Paragraph
const * pParagraph
)
1311 SolarMutexGuard aGuard
;
1312 ::osl::MutexGuard
aInternalGuard(GetMutex());
1313 ::TextSelection
const & rSelection
= m_rView
.GetSelection();
1314 Paragraphs::size_type nNumber
= pParagraph
->getNumber();
1315 TextPaM
aEndPaM( rSelection
.GetEnd() );
1317 return aEndPaM
.GetPara() == nNumber
1318 ? m_rView
.GetLineNumberOfCursorInSelection() : -1;
1322 css::uno::Reference
< css::accessibility::XAccessibleRelationSet
>
1323 Document::retrieveParagraphRelationSet( Paragraph
const * pParagraph
)
1325 ::osl::MutexGuard
aInternalGuard( GetMutex() );
1327 ::utl::AccessibleRelationSetHelper
* pRelationSetHelper
= new ::utl::AccessibleRelationSetHelper();
1328 css::uno::Reference
< css::accessibility::XAccessibleRelationSet
> xSet
= pRelationSetHelper
;
1330 Paragraphs::iterator
aPara( m_xParagraphs
->begin() + pParagraph
->getNumber() );
1332 if ( aPara
> m_aVisibleBegin
&& aPara
< m_aVisibleEnd
)
1334 css::uno::Sequence
< css::uno::Reference
< css::uno::XInterface
> > aSequence
{ getAccessibleChild( aPara
- 1 ) };
1335 css::accessibility::AccessibleRelation
aRelation( css::accessibility::AccessibleRelationType::CONTENT_FLOWS_FROM
, aSequence
);
1336 pRelationSetHelper
->AddRelation( aRelation
);
1339 if ( aPara
>= m_aVisibleBegin
&& aPara
< m_aVisibleEnd
-1 )
1341 css::uno::Sequence
< css::uno::Reference
< css::uno::XInterface
> > aSequence
{ getAccessibleChild( aPara
+ 1 ) };
1342 css::accessibility::AccessibleRelation
aRelation( css::accessibility::AccessibleRelationType::CONTENT_FLOWS_TO
, aSequence
);
1343 pRelationSetHelper
->AddRelation( aRelation
);
1350 ::sal_Int32 SAL_CALL
Document::getAccessibleChildCount()
1352 ::comphelper::OExternalLockGuard
aGuard(this);
1354 return m_aVisibleEnd
- m_aVisibleBegin
;
1358 css::uno::Reference
< css::accessibility::XAccessible
> SAL_CALL
1359 Document::getAccessibleChild(::sal_Int32 i
)
1361 ::comphelper::OExternalLockGuard
aGuard(this);
1363 if (i
< 0 || i
>= m_aVisibleEnd
- m_aVisibleBegin
)
1364 throw css::lang::IndexOutOfBoundsException(
1365 "textwindowaccessibility.cxx:"
1366 " Document::getAccessibleChild",
1367 static_cast< css::uno::XWeak
* >(this));
1368 return getAccessibleChild(m_aVisibleBegin
1369 + static_cast< Paragraphs::size_type
>(i
));
1373 ::sal_Int16 SAL_CALL
Document::getAccessibleRole()
1375 return css::accessibility::AccessibleRole::TEXT_FRAME
;
1379 css::uno::Reference
< css::accessibility::XAccessible
> SAL_CALL
1380 Document::getAccessibleAtPoint(css::awt::Point
const & rPoint
)
1382 ::comphelper::OExternalLockGuard
aGuard(this);
1385 && rPoint
.X
< m_rView
.GetWindow()->GetOutputSizePixel().Width()
1386 && rPoint
.Y
>= 0 && rPoint
.Y
< m_nViewHeight
)
1388 ::sal_Int32 nOffset
= m_nViewOffset
+ rPoint
.Y
; // XXX numeric overflow
1389 ::sal_Int32 nPos
= m_nViewOffset
- m_nVisibleBeginOffset
;
1390 for (Paragraphs::iterator
aIt(m_aVisibleBegin
); aIt
!= m_aVisibleEnd
;
1393 nPos
+= aIt
->getHeight(); // XXX numeric overflow
1395 return getAccessibleChild(aIt
);
1400 void Document::FillAccessibleStateSet( utl::AccessibleStateSetHelper
& rStateSet
)
1402 VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet
);
1403 if (!m_rView
.IsReadOnly())
1404 rStateSet
.AddState( css::accessibility::AccessibleStateType::EDITABLE
);
1407 void Document::FillAccessibleRelationSet( utl::AccessibleRelationSetHelper
& rRelationSet
)
1409 if( getAccessibleParent()->getAccessibleContext()->getAccessibleRole() == css::accessibility::AccessibleRole::SCROLL_PANE
)
1411 css::uno::Sequence
< css::uno::Reference
< css::uno::XInterface
> > aSequence
{ getAccessibleParent() };
1412 rRelationSet
.AddRelation( css::accessibility::AccessibleRelation( css::accessibility::AccessibleRelationType::MEMBER_OF
, aSequence
) );
1416 VCLXAccessibleComponent::FillAccessibleRelationSet(rRelationSet
);
1420 void SAL_CALL
Document::disposing()
1422 m_aEngineListener
.endListening();
1423 m_aViewListener
.endListening();
1424 if (m_xParagraphs
!= nullptr)
1425 disposeParagraphs();
1426 VCLXAccessibleComponent::disposing();
1430 void Document::Notify(::SfxBroadcaster
&, ::SfxHint
const & rHint
)
1432 const TextHint
* pTextHint
= dynamic_cast<const TextHint
*>(&rHint
);
1435 ::TextHint
const & rTextHint
= *pTextHint
;
1436 switch (rTextHint
.GetId())
1438 case SfxHintId::TextParaInserted
:
1439 case SfxHintId::TextParaRemoved
:
1440 // SfxHintId::TextParaInserted and SfxHintId::TextParaRemoved are sent at
1441 // "unsafe" times (when the text engine has not yet re-formatted its
1442 // content), so that for example calling ::TextEngine::GetTextHeight
1443 // from within the code that handles SfxHintId::TextParaInserted causes
1444 // trouble within the text engine. Therefore, these hints are just
1445 // buffered until a following ::TextEngine::FormatDoc causes a
1446 // SfxHintId::TextFormatted to come in:
1447 case SfxHintId::TextFormatPara
:
1448 // ::TextEngine::FormatDoc sends a sequence of
1449 // SfxHintId::TextFormatParas, followed by an optional
1450 // SfxHintId::TextHeightChanged, followed in all cases by one
1451 // SfxHintId::TextFormatted. Only the SfxHintId::TextFormatParas contain
1452 // the numbers of the affected paragraphs, but they are sent
1453 // before the changes are applied. Therefore, SfxHintId::TextFormatParas
1454 // are just buffered until another hint comes in:
1456 ::osl::MutexGuard
aInternalGuard(GetMutex());
1460 m_aParagraphNotifications
.push(rTextHint
);
1463 case SfxHintId::TextFormatted
:
1464 case SfxHintId::TextHeightChanged
:
1465 case SfxHintId::TextModified
:
1467 ::osl::MutexGuard
aInternalGuard(GetMutex());
1470 handleParagraphNotifications();
1473 case SfxHintId::TextViewScrolled
:
1475 ::osl::MutexGuard
aInternalGuard(GetMutex());
1478 handleParagraphNotifications();
1480 ::sal_Int32 nOffset
= static_cast< ::sal_Int32
>(
1481 m_rView
.GetStartDocPos().Y());
1482 // XXX numeric overflow
1483 if (nOffset
!= m_nViewOffset
)
1485 m_nViewOffset
= nOffset
;
1487 Paragraphs::iterator
aOldVisibleBegin(
1489 Paragraphs::iterator
aOldVisibleEnd(m_aVisibleEnd
);
1491 determineVisibleRange();
1493 notifyVisibleRangeChanges(aOldVisibleBegin
,
1495 m_xParagraphs
->end());
1499 case SfxHintId::TextViewSelectionChanged
:
1500 case SfxHintId::TextViewCaretChanged
:
1502 ::osl::MutexGuard
aInternalGuard(GetMutex());
1506 if (m_aParagraphNotifications
.empty())
1508 handleSelectionChangeNotification();
1512 // SfxHintId::TextViewSelectionChanged is sometimes sent at
1513 // "unsafe" times (when the text engine has not yet re-
1514 // formatted its content), so that for example calling
1515 // ::TextEngine::GetTextHeight from within the code that
1516 // handles a previous SfxHintId::TextParaInserted causes
1517 // trouble within the text engine. Therefore, these
1518 // hints are just buffered (along with
1519 // SfxHintId::TextParaInserted/REMOVED/FORMATPARA) until a
1520 // following ::TextEngine::FormatDoc causes a
1521 // SfxHintId::TextFormatted to come in:
1522 m_bSelectionChangedNotification
= true;
1531 IMPL_LINK(Document
, WindowEventHandler
, ::VclWindowEvent
&, rEvent
, void)
1533 switch (rEvent
.GetId())
1535 case VclEventId::WindowResize
:
1537 ::osl::MutexGuard
aInternalGuard(GetMutex());
1541 ::sal_Int32 nHeight
= static_cast< ::sal_Int32
>(
1542 m_rView
.GetWindow()->GetOutputSizePixel().Height());
1543 // XXX numeric overflow
1544 if (nHeight
!= m_nViewHeight
)
1546 m_nViewHeight
= nHeight
;
1548 Paragraphs::iterator
aOldVisibleBegin(m_aVisibleBegin
);
1549 Paragraphs::iterator
aOldVisibleEnd(m_aVisibleEnd
);
1551 determineVisibleRange();
1553 notifyVisibleRangeChanges(aOldVisibleBegin
, aOldVisibleEnd
,
1554 m_xParagraphs
->end());
1558 case VclEventId::WindowGetFocus
:
1560 ::osl::MutexGuard
aInternalGuard(GetMutex());
1563 //to enable the PARAGRAPH to get focus for multiline edit
1564 ::sal_Int32 count
= getAccessibleChildCount();
1565 bool bEmpty
= m_aFocused
== m_aVisibleEnd
&& count
== 1;
1566 if ((m_aFocused
>= m_aVisibleBegin
&& m_aFocused
< m_aVisibleEnd
) || bEmpty
)
1568 Paragraphs::iterator aTemp
= bEmpty
? m_aVisibleBegin
: m_aFocused
;
1569 ::rtl::Reference
< Paragraph
> xParagraph(getParagraph(aTemp
));
1570 if (xParagraph
.is())
1572 xParagraph
->notifyEvent(
1573 css::accessibility::AccessibleEventId::
1577 css::accessibility::AccessibleStateType::
1583 case VclEventId::WindowLoseFocus
:
1585 ::osl::MutexGuard
aInternalGuard(GetMutex());
1588 //to enable the PARAGRAPH to get focus for multiline edit
1589 ::sal_Int32 count
= getAccessibleChildCount();
1590 bool bEmpty
= m_aFocused
== m_aVisibleEnd
&& count
== 1;
1591 if ((m_aFocused
>= m_aVisibleBegin
&& m_aFocused
< m_aVisibleEnd
) || bEmpty
)
1593 Paragraphs::iterator aTemp
= bEmpty
? m_aVisibleBegin
: m_aFocused
;
1594 ::rtl::Reference
< Paragraph
> xParagraph(getParagraph(aTemp
));
1595 if (xParagraph
.is())
1596 xParagraph
->notifyEvent(
1597 css::accessibility::AccessibleEventId::
1600 css::accessibility::AccessibleStateType::
1610 void Document::init()
1612 if (m_xParagraphs
== nullptr)
1614 const sal_uInt32 nCount
= m_rEngine
.GetParagraphCount();
1615 m_xParagraphs
.reset(new Paragraphs
);
1616 m_xParagraphs
->reserve(static_cast< Paragraphs::size_type
>(nCount
));
1617 // numeric overflow is harmless here
1618 for (sal_uInt32 i
= 0; i
< nCount
; ++i
)
1619 m_xParagraphs
->push_back(ParagraphInfo(static_cast< ::sal_Int32
>(
1620 m_rEngine
.GetTextHeight(i
))));
1621 // XXX numeric overflow
1622 m_nViewOffset
= static_cast< ::sal_Int32
>(
1623 m_rView
.GetStartDocPos().Y()); // XXX numeric overflow
1624 m_nViewHeight
= static_cast< ::sal_Int32
>(
1625 m_rView
.GetWindow()->GetOutputSizePixel().Height());
1626 // XXX numeric overflow
1627 determineVisibleRange();
1628 m_nSelectionFirstPara
= -1;
1629 m_nSelectionFirstPos
= -1;
1630 m_nSelectionLastPara
= -1;
1631 m_nSelectionLastPos
= -1;
1632 m_aFocused
= m_xParagraphs
->end();
1633 m_bSelectionChangedNotification
= false;
1634 m_aEngineListener
.startListening(m_rEngine
);
1635 m_aViewListener
.startListening(*m_rView
.GetWindow());
1639 ::rtl::Reference
< Paragraph
>
1640 Document::getParagraph(Paragraphs::iterator
const & rIt
)
1642 return static_cast< Paragraph
* >(
1643 css::uno::Reference
< css::accessibility::XAccessible
>(
1644 rIt
->getParagraph()).get());
1647 css::uno::Reference
< css::accessibility::XAccessible
>
1648 Document::getAccessibleChild(Paragraphs::iterator
const & rIt
)
1650 css::uno::Reference
< css::accessibility::XAccessible
> xParagraph(
1651 rIt
->getParagraph());
1652 if (!xParagraph
.is())
1654 xParagraph
= new Paragraph(this, rIt
- m_xParagraphs
->begin());
1655 rIt
->setParagraph(xParagraph
);
1660 void Document::determineVisibleRange()
1662 Paragraphs::iterator
const aEnd
= m_xParagraphs
->end();
1664 m_aVisibleBegin
= aEnd
;
1665 m_aVisibleEnd
= aEnd
;
1666 m_nVisibleBeginOffset
= 0;
1668 ::sal_Int32 nPos
= 0;
1669 for (Paragraphs::iterator aIt
= m_xParagraphs
->begin(); m_aVisibleEnd
== aEnd
&& aIt
!= aEnd
; ++aIt
)
1671 ::sal_Int32
const nOldPos
= nPos
;
1672 nPos
+= aIt
->getHeight(); // XXX numeric overflow
1673 if (m_aVisibleBegin
== aEnd
)
1675 if (nPos
>= m_nViewOffset
)
1677 m_aVisibleBegin
= aIt
;
1678 m_nVisibleBeginOffset
= m_nViewOffset
- nOldPos
;
1683 if (nPos
>= m_nViewOffset
+ m_nViewHeight
) // XXX numeric overflow
1685 m_aVisibleEnd
= aIt
;
1691 !((m_aVisibleBegin
== m_xParagraphs
->end() && m_aVisibleEnd
== m_xParagraphs
->end() && m_nVisibleBeginOffset
== 0)
1692 || (m_aVisibleBegin
< m_aVisibleEnd
&& m_nVisibleBeginOffset
>= 0)),
1694 "invalid visible range");
1697 void Document::notifyVisibleRangeChanges(
1698 Paragraphs::iterator
const & rOldVisibleBegin
,
1699 Paragraphs::iterator
const & rOldVisibleEnd
,
1700 Paragraphs::iterator
const & rInserted
)
1702 // XXX Replace this code that determines which paragraphs have changed from
1703 // invisible to visible or vice versa with a better algorithm.
1704 for (Paragraphs::iterator
aIt(rOldVisibleBegin
); aIt
!= rOldVisibleEnd
;
1707 if (aIt
!= rInserted
1708 && (aIt
< m_aVisibleBegin
|| aIt
>= m_aVisibleEnd
))
1709 NotifyAccessibleEvent(
1710 css::accessibility::AccessibleEventId::
1712 css::uno::Any(getAccessibleChild(aIt
)),
1715 for (Paragraphs::iterator
aIt(m_aVisibleBegin
); aIt
!= m_aVisibleEnd
;
1718 if (aIt
== rInserted
1719 || aIt
< rOldVisibleBegin
|| aIt
>= rOldVisibleEnd
)
1720 NotifyAccessibleEvent(
1721 css::accessibility::AccessibleEventId::
1724 css::uno::Any(getAccessibleChild(aIt
)));
1729 Document::changeParagraphText(::sal_uLong nNumber
, ::sal_uInt16 nBegin
, ::sal_uInt16 nEnd
,
1730 bool bCut
, bool bPaste
,
1731 OUString
const & rText
)
1733 m_rView
.SetSelection(::TextSelection(::TextPaM(nNumber
, nBegin
),
1734 ::TextPaM(nNumber
, nEnd
)));
1737 else if (nBegin
!= nEnd
)
1738 m_rView
.DeleteSelected();
1741 else if (!rText
.isEmpty())
1742 m_rView
.InsertText(rText
);
1745 void Document::handleParagraphNotifications()
1747 while (!m_aParagraphNotifications
.empty())
1749 ::TextHint
aHint(m_aParagraphNotifications
.front());
1750 m_aParagraphNotifications
.pop();
1751 switch (aHint
.GetId())
1753 case SfxHintId::TextParaInserted
:
1755 ::sal_uLong n
= aHint
.GetValue();
1756 assert(n
<= m_xParagraphs
->size() && "bad SfxHintId::TextParaInserted event");
1758 // Save the values of old iterators (the iterators themselves
1759 // will get invalidated), and adjust the old values so that they
1760 // reflect the insertion of the new paragraph:
1761 Paragraphs::size_type nOldVisibleBegin
1762 = m_aVisibleBegin
- m_xParagraphs
->begin();
1763 Paragraphs::size_type nOldVisibleEnd
1764 = m_aVisibleEnd
- m_xParagraphs
->begin();
1765 Paragraphs::size_type nOldFocused
1766 = m_aFocused
- m_xParagraphs
->begin();
1767 if (n
<= nOldVisibleBegin
)
1768 ++nOldVisibleBegin
; // XXX numeric overflow
1769 if (n
<= nOldVisibleEnd
)
1770 ++nOldVisibleEnd
; // XXX numeric overflow
1771 if (n
<= nOldFocused
)
1772 ++nOldFocused
; // XXX numeric overflow
1773 if (sal::static_int_cast
<sal_Int32
>(n
) <= m_nSelectionFirstPara
)
1774 ++m_nSelectionFirstPara
; // XXX numeric overflow
1775 if (sal::static_int_cast
<sal_Int32
>(n
) <= m_nSelectionLastPara
)
1776 ++m_nSelectionLastPara
; // XXX numeric overflow
1778 Paragraphs::iterator
aIns(
1779 m_xParagraphs
->insert(
1780 m_xParagraphs
->begin() + n
,
1781 ParagraphInfo(static_cast< ::sal_Int32
>(
1782 m_rEngine
.GetTextHeight(n
)))));
1783 // XXX numeric overflow (2x)
1785 determineVisibleRange();
1786 m_aFocused
= m_xParagraphs
->begin() + nOldFocused
;
1788 for (Paragraphs::iterator
aIt(aIns
);;)
1791 if (aIt
== m_xParagraphs
->end())
1793 ::rtl::Reference
< Paragraph
> xParagraph(
1795 if (xParagraph
.is())
1796 xParagraph
->numberChanged(true);
1799 notifyVisibleRangeChanges(
1800 m_xParagraphs
->begin() + nOldVisibleBegin
,
1801 m_xParagraphs
->begin() + nOldVisibleEnd
, aIns
);
1804 case SfxHintId::TextParaRemoved
:
1806 ::sal_uLong n
= aHint
.GetValue();
1807 if (n
== TEXT_PARA_ALL
)
1809 for (Paragraphs::iterator
aIt(m_aVisibleBegin
);
1810 aIt
!= m_aVisibleEnd
; ++aIt
)
1812 NotifyAccessibleEvent(
1813 css::accessibility::AccessibleEventId::
1815 css::uno::Any(getAccessibleChild(aIt
)),
1818 disposeParagraphs();
1819 m_xParagraphs
->clear();
1820 determineVisibleRange();
1821 m_nSelectionFirstPara
= -1;
1822 m_nSelectionFirstPos
= -1;
1823 m_nSelectionLastPara
= -1;
1824 m_nSelectionLastPos
= -1;
1825 m_aFocused
= m_xParagraphs
->end();
1829 assert(n
< m_xParagraphs
->size() && "Bad SfxHintId::TextParaRemoved event");
1831 Paragraphs::iterator
aIt(m_xParagraphs
->begin() + n
);
1832 // numeric overflow cannot occur
1834 // Save the values of old iterators (the iterators
1835 // themselves will get invalidated), and adjust the old
1836 // values so that they reflect the removal of the paragraph:
1837 Paragraphs::size_type nOldVisibleBegin
1838 = m_aVisibleBegin
- m_xParagraphs
->begin();
1839 Paragraphs::size_type nOldVisibleEnd
1840 = m_aVisibleEnd
- m_xParagraphs
->begin();
1842 = nOldVisibleBegin
<= n
&& n
< nOldVisibleEnd
;
1843 Paragraphs::size_type nOldFocused
1844 = m_aFocused
- m_xParagraphs
->begin();
1845 bool bWasFocused
= aIt
== m_aFocused
;
1846 if (n
< nOldVisibleBegin
)
1848 if (n
< nOldVisibleEnd
)
1850 if (n
< nOldFocused
)
1852 if (sal::static_int_cast
<sal_Int32
>(n
) < m_nSelectionFirstPara
)
1853 --m_nSelectionFirstPara
;
1854 else if (sal::static_int_cast
<sal_Int32
>(n
) == m_nSelectionFirstPara
)
1856 if (m_nSelectionFirstPara
== m_nSelectionLastPara
)
1858 m_nSelectionFirstPara
= -1;
1859 m_nSelectionFirstPos
= -1;
1860 m_nSelectionLastPara
= -1;
1861 m_nSelectionLastPos
= -1;
1865 ++m_nSelectionFirstPara
;
1866 m_nSelectionFirstPos
= 0;
1869 if (sal::static_int_cast
<sal_Int32
>(n
) < m_nSelectionLastPara
)
1870 --m_nSelectionLastPara
;
1871 else if (sal::static_int_cast
<sal_Int32
>(n
) == m_nSelectionLastPara
)
1873 assert(m_nSelectionFirstPara
< m_nSelectionLastPara
&& "logic error");
1874 --m_nSelectionLastPara
;
1875 m_nSelectionLastPos
= 0x7FFFFFFF;
1878 css::uno::Reference
< css::accessibility::XAccessible
>
1881 xStrong
= getAccessibleChild(aIt
);
1882 css::uno::WeakReference
<
1883 css::accessibility::XAccessible
> xWeak(
1884 aIt
->getParagraph());
1885 aIt
= m_xParagraphs
->erase(aIt
);
1887 determineVisibleRange();
1888 m_aFocused
= bWasFocused
? m_xParagraphs
->end()
1889 : m_xParagraphs
->begin() + nOldFocused
;
1891 for (; aIt
!= m_xParagraphs
->end(); ++aIt
)
1893 ::rtl::Reference
< Paragraph
> xParagraph(
1895 if (xParagraph
.is())
1896 xParagraph
->numberChanged(false);
1900 NotifyAccessibleEvent(
1901 css::accessibility::AccessibleEventId::
1903 css::uno::Any(xStrong
),
1906 css::uno::Reference
< css::lang::XComponent
> xComponent(
1907 xWeak
.get(), css::uno::UNO_QUERY
);
1908 if (xComponent
.is())
1909 xComponent
->dispose();
1911 notifyVisibleRangeChanges(
1912 m_xParagraphs
->begin() + nOldVisibleBegin
,
1913 m_xParagraphs
->begin() + nOldVisibleEnd
,
1914 m_xParagraphs
->end());
1918 case SfxHintId::TextFormatPara
:
1920 ::sal_uLong n
= aHint
.GetValue();
1921 assert(n
< m_xParagraphs
->size() && "Bad SfxHintId::TextFormatPara event");
1923 (*m_xParagraphs
)[static_cast< Paragraphs::size_type
>(n
)].
1924 changeHeight(static_cast< ::sal_Int32
>(
1925 m_rEngine
.GetTextHeight(n
)));
1926 // XXX numeric overflow
1927 Paragraphs::iterator
aOldVisibleBegin(m_aVisibleBegin
);
1928 Paragraphs::iterator
aOldVisibleEnd(m_aVisibleEnd
);
1929 determineVisibleRange();
1930 notifyVisibleRangeChanges(aOldVisibleBegin
, aOldVisibleEnd
,
1931 m_xParagraphs
->end());
1933 if (n
< m_xParagraphs
->size())
1935 Paragraphs::iterator
aIt(m_xParagraphs
->begin() + n
);
1936 ::rtl::Reference
< Paragraph
> xParagraph(getParagraph(aIt
));
1937 if (xParagraph
.is())
1938 xParagraph
->textChanged();
1943 SAL_WARN("accessibility", "bad buffered hint");
1947 if (m_bSelectionChangedNotification
)
1949 m_bSelectionChangedNotification
= false;
1950 handleSelectionChangeNotification();
1957 enum class SelChangeType
1959 None
, // no change, or invalid
1960 CaretMove
, // neither old nor new have selection, and they are different
1961 NoSelToSel
, // old has no selection but new has selection
1962 SelToNoSel
, // old has selection but new has no selection
1963 // both old and new have selections
1964 NoParaChange
, // only end index changed inside end para
1965 EndParaNoMoreBehind
, // end para was behind start, but now is same or ahead
1966 AddedFollowingPara
, // selection extended to following paragraph(s)
1967 ExcludedPreviousPara
, // selection shrunk excluding previous paragraph(s)
1968 ExcludedFollowingPara
, // selection shrunk excluding following paragraph(s)
1969 AddedPreviousPara
, // selection extended to previous paragraph(s)
1970 EndParaBecameBehind
// end para was ahead of start, but now is behind
1973 SelChangeType
getSelChangeType(const TextPaM
& Os
, const TextPaM
& Oe
,
1974 const TextPaM
& Ns
, const TextPaM
& Ne
)
1976 if (Os
== Oe
) // no old selection
1978 if (Ns
== Ne
) // no new selection: only caret moves
1979 return Os
!= Ns
? SelChangeType::CaretMove
: SelChangeType::None
;
1980 else // old has no selection but new has selection
1981 return SelChangeType::NoSelToSel
;
1983 else if (Ns
== Ne
) // old has selection; no new selection
1985 return SelChangeType::SelToNoSel
;
1987 else if (Os
== Ns
) // both old and new have selections, and their starts are same
1989 const sal_Int32 Osp
= Os
.GetPara(), Oep
= Oe
.GetPara();
1990 const sal_Int32 Nsp
= Ns
.GetPara(), Nep
= Ne
.GetPara();
1991 if (Oep
== Nep
) // end of selection stays in the same paragraph
1993 //Send text_selection_change event on Nep
1994 return Oe
.GetIndex() != Ne
.GetIndex() ? SelChangeType::NoParaChange
1995 : SelChangeType::None
;
1997 else if (Oep
< Nep
) // end of selection moved to a following paragraph
1999 //all the following examples like 1,2->1,3 means that old start select para is 1, old end select para is 2,
2000 // then press shift up, the new start select para is 1, new end select para is 3;
2001 //for example, 1, 2 -> 1, 3; 4,1 -> 4, 7; 4,1 -> 4, 2; 4,4->4,5
2002 if (Nep
>= Nsp
) // new end para not behind start
2004 // 1, 2 -> 1, 3; 4, 1 -> 4, 7; 4,4->4,5;
2005 if (Oep
< Osp
) // old end was behind start
2007 // 4,1 -> 4,7; 4,1 -> 4,4
2008 return SelChangeType::EndParaNoMoreBehind
;
2010 else // old end para wasn't behind start
2012 // 1, 2 -> 1, 3; 4,4->4,5;
2013 return SelChangeType::AddedFollowingPara
;
2016 else // new end para is still behind start
2019 return SelChangeType::ExcludedPreviousPara
;
2022 else // Oep > Nep => end of selection moved to a previous paragraph
2024 // 3,2 -> 3,1; 4,7 -> 4,1; 4, 7 -> 4,6; 4,4 -> 4,3
2025 if (Nep
>= Nsp
) // new end para is still not behind of start
2028 return SelChangeType::ExcludedFollowingPara
;
2030 else // new end para is behind start
2032 // 3,2 -> 3,1, 4,7 -> 4,1; 4,4->4,3
2033 if (Oep
<= Osp
) // it was not ahead already
2035 // 3,2 -> 3,1; 4,4->4,3
2036 return SelChangeType::AddedPreviousPara
;
2038 else // it was ahead previously
2041 return SelChangeType::EndParaBecameBehind
;
2046 return SelChangeType::None
;
2051 void Document::sendEvent(::sal_Int32 start
, ::sal_Int32 end
, ::sal_Int16 nEventId
)
2053 size_t nAvailDistance
= std::distance(m_xParagraphs
->begin(), m_aVisibleEnd
);
2055 Paragraphs::iterator
aEnd(m_xParagraphs
->begin());
2056 size_t nEndDistance
= std::min
<size_t>(end
+ 1, nAvailDistance
);
2057 std::advance(aEnd
, nEndDistance
);
2059 Paragraphs::iterator
aIt(m_xParagraphs
->begin());
2060 size_t nStartDistance
= std::min
<size_t>(start
, nAvailDistance
);
2061 std::advance(aIt
, nStartDistance
);
2065 ::rtl::Reference
< Paragraph
> xParagraph(getParagraph(aIt
));
2066 if (xParagraph
.is())
2067 xParagraph
->notifyEvent(
2069 css::uno::Any(), css::uno::Any());
2074 void Document::handleSelectionChangeNotification()
2076 ::TextSelection
const & rSelection
= m_rView
.GetSelection();
2077 assert(rSelection
.GetStart().GetPara() < m_xParagraphs
->size() &&
2078 rSelection
.GetEnd().GetPara() < m_xParagraphs
->size() &&
2079 "bad SfxHintId::TextViewSelectionChanged event");
2080 ::sal_Int32 nNewFirstPara
2081 = static_cast< ::sal_Int32
>(rSelection
.GetStart().GetPara());
2082 ::sal_Int32 nNewFirstPos
= rSelection
.GetStart().GetIndex();
2083 // XXX numeric overflow
2084 ::sal_Int32 nNewLastPara
2085 = static_cast< ::sal_Int32
>(rSelection
.GetEnd().GetPara());
2086 ::sal_Int32 nNewLastPos
= rSelection
.GetEnd().GetIndex();
2087 // XXX numeric overflow
2090 Paragraphs::iterator
aIt(m_xParagraphs
->begin() + nNewLastPara
);
2091 if (m_aFocused
!= m_xParagraphs
->end() && m_aFocused
!= aIt
2092 && m_aFocused
>= m_aVisibleBegin
&& m_aFocused
< m_aVisibleEnd
)
2094 ::rtl::Reference
< Paragraph
> xParagraph(getParagraph(m_aFocused
));
2095 if (xParagraph
.is())
2096 xParagraph
->notifyEvent(
2097 css::accessibility::AccessibleEventId::
2100 css::accessibility::AccessibleStateType::FOCUSED
),
2104 // Gain focus and update cursor position:
2105 if (aIt
>= m_aVisibleBegin
&& aIt
< m_aVisibleEnd
2106 && (aIt
!= m_aFocused
2107 || nNewLastPara
!= m_nSelectionLastPara
2108 || nNewLastPos
!= m_nSelectionLastPos
))
2110 ::rtl::Reference
< Paragraph
> xParagraph(getParagraph(aIt
));
2111 if (xParagraph
.is())
2113 //disable the first event when user types in empty field.
2114 ::sal_Int32 count
= getAccessibleChildCount();
2115 bool bEmpty
= count
> 1;
2116 //if (aIt != m_aFocused)
2117 if (aIt
!= m_aFocused
&& bEmpty
)
2118 xParagraph
->notifyEvent(
2119 css::accessibility::AccessibleEventId::
2123 css::accessibility::AccessibleStateType::FOCUSED
));
2124 if (nNewLastPara
!= m_nSelectionLastPara
2125 || nNewLastPos
!= m_nSelectionLastPos
)
2126 xParagraph
->notifyEvent(
2127 css::accessibility::AccessibleEventId::
2129 css::uno::makeAny
< ::sal_Int32
>(
2130 nNewLastPara
== m_nSelectionLastPara
2131 ? m_nSelectionLastPos
: 0),
2132 css::uno::Any(nNewLastPos
));
2137 if (m_nSelectionFirstPara
!= -1)
2141 SelChangeType ret
= getSelChangeType(TextPaM(m_nSelectionFirstPara
, m_nSelectionFirstPos
),
2142 TextPaM(m_nSelectionLastPara
, m_nSelectionLastPos
),
2143 rSelection
.GetStart(), rSelection
.GetEnd());
2146 case SelChangeType::None
:
2149 case SelChangeType::CaretMove
:
2150 //only caret moved, already handled in above
2152 case SelChangeType::NoSelToSel
:
2153 //old has no selection but new has selection
2154 nMin
= std::min(nNewFirstPara
, nNewLastPara
);
2155 nMax
= std::max(nNewFirstPara
, nNewLastPara
);
2156 sendEvent(nMin
, nMax
, css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2157 sendEvent(nMin
, nMax
,
2158 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2160 case SelChangeType::SelToNoSel
:
2161 //old has selection but new has no selection.
2162 nMin
= std::min(m_nSelectionFirstPara
, m_nSelectionLastPara
);
2163 nMax
= std::max(m_nSelectionFirstPara
, m_nSelectionLastPara
);
2164 sendEvent(nMin
, nMax
, css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2165 sendEvent(nMin
, nMax
,
2166 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2168 case SelChangeType::NoParaChange
:
2169 //Send text_selection_change event on Nep
2170 sendEvent(nNewLastPara
, nNewLastPara
,
2171 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2173 case SelChangeType::EndParaNoMoreBehind
:
2174 // 4, 1 -> 4, 7; 4,1 -> 4,4
2175 sendEvent(m_nSelectionLastPara
, m_nSelectionFirstPara
- 1,
2176 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2177 sendEvent(nNewFirstPara
+ 1, nNewLastPara
,
2178 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2180 sendEvent(m_nSelectionLastPara
, nNewLastPara
,
2181 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2183 case SelChangeType::AddedFollowingPara
:
2184 // 1, 2 -> 1, 4; 4,4->4,5;
2185 sendEvent(m_nSelectionLastPara
+ 1, nNewLastPara
,
2186 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2188 sendEvent(m_nSelectionLastPara
, nNewLastPara
,
2189 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2191 case SelChangeType::ExcludedPreviousPara
:
2193 sendEvent(m_nSelectionLastPara
+ 1, nNewLastPara
,
2194 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2196 sendEvent(m_nSelectionLastPara
, nNewLastPara
,
2197 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2199 case SelChangeType::ExcludedFollowingPara
:
2201 sendEvent(nNewLastPara
+ 1, m_nSelectionLastPara
,
2202 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2204 sendEvent(nNewLastPara
, m_nSelectionLastPara
,
2205 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2207 case SelChangeType::AddedPreviousPara
:
2208 // 3,2 -> 3,1; 4,4->4,3
2209 sendEvent(nNewLastPara
, m_nSelectionLastPara
- 1,
2210 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2212 sendEvent(nNewLastPara
, m_nSelectionLastPara
,
2213 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2215 case SelChangeType::EndParaBecameBehind
:
2217 sendEvent(m_nSelectionFirstPara
+ 1, m_nSelectionLastPara
,
2218 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2219 sendEvent(nNewLastPara
, nNewFirstPara
- 1,
2220 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2222 sendEvent(nNewLastPara
, m_nSelectionLastPara
,
2223 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2228 m_nSelectionFirstPara
= nNewFirstPara
;
2229 m_nSelectionFirstPos
= nNewFirstPos
;
2230 m_nSelectionLastPara
= nNewLastPara
;
2231 m_nSelectionLastPos
= nNewLastPos
;
2234 void Document::disposeParagraphs()
2236 for (auto const& paragraph
: *m_xParagraphs
)
2238 css::uno::Reference
< css::lang::XComponent
> xComponent(
2239 paragraph
.getParagraph().get(), css::uno::UNO_QUERY
);
2240 if (xComponent
.is())
2241 xComponent
->dispose();
2246 css::uno::Any
Document::mapFontColor(::Color
const & rColor
)
2248 return css::uno::makeAny(rColor
.GetRGBColor());
2249 // FIXME keep transparency?
2253 ::Color
Document::mapFontColor(css::uno::Any
const & rColor
)
2261 css::uno::Any
Document::mapFontWeight(::FontWeight nWeight
)
2263 // Map from ::FontWeight to css::awt::FontWeight, depends on order of
2264 // elements in ::FontWeight (vcl/vclenum.hxx):
2265 static float const aWeight
[]
2266 = { css::awt::FontWeight::DONTKNOW
, // WEIGHT_DONTKNOW
2267 css::awt::FontWeight::THIN
, // WEIGHT_THIN
2268 css::awt::FontWeight::ULTRALIGHT
, // WEIGHT_ULTRALIGHT
2269 css::awt::FontWeight::LIGHT
, // WEIGHT_LIGHT
2270 css::awt::FontWeight::SEMILIGHT
, // WEIGHT_SEMILIGHT
2271 css::awt::FontWeight::NORMAL
, // WEIGHT_NORMAL
2272 css::awt::FontWeight::NORMAL
, // WEIGHT_MEDIUM
2273 css::awt::FontWeight::SEMIBOLD
, // WEIGHT_SEMIBOLD
2274 css::awt::FontWeight::BOLD
, // WEIGHT_BOLD
2275 css::awt::FontWeight::ULTRABOLD
, // WEIGHT_ULTRABOLD
2276 css::awt::FontWeight::BLACK
}; // WEIGHT_BLACK
2277 return css::uno::Any(aWeight
[nWeight
]);
2281 ::FontWeight
Document::mapFontWeight(css::uno::Any
const & rWeight
)
2283 float nWeight
= css::awt::FontWeight::NORMAL
;
2284 rWeight
>>= nWeight
;
2285 return nWeight
<= css::awt::FontWeight::DONTKNOW
? WEIGHT_DONTKNOW
2286 : nWeight
<= css::awt::FontWeight::THIN
? WEIGHT_THIN
2287 : nWeight
<= css::awt::FontWeight::ULTRALIGHT
? WEIGHT_ULTRALIGHT
2288 : nWeight
<= css::awt::FontWeight::LIGHT
? WEIGHT_LIGHT
2289 : nWeight
<= css::awt::FontWeight::SEMILIGHT
? WEIGHT_SEMILIGHT
2290 : nWeight
<= css::awt::FontWeight::NORMAL
? WEIGHT_NORMAL
2291 : nWeight
<= css::awt::FontWeight::SEMIBOLD
? WEIGHT_SEMIBOLD
2292 : nWeight
<= css::awt::FontWeight::BOLD
? WEIGHT_BOLD
2293 : nWeight
<= css::awt::FontWeight::ULTRABOLD
? WEIGHT_ULTRABOLD
2299 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */