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/accessiblecontexthelper.hxx>
34 #include <comphelper/accessibleeventnotifier.hxx>
35 #include <unotools/accessiblerelationsethelper.hxx>
37 #include <vcl/svapp.hxx>
38 #include <vcl/txtattr.hxx>
39 #include <vcl/window.hxx>
40 #include <comphelper/diagnose_ex.hxx>
41 #include <toolkit/helper/convert.hxx>
42 #include <comphelper/sequence.hxx>
49 namespace accessibility
51 void SfxListenerGuard::startListening(::SfxBroadcaster
& rNotifier
)
53 assert(m_pNotifier
== nullptr && "called more than once");
54 m_pNotifier
= &rNotifier
;
55 m_rListener
.StartListening(*m_pNotifier
, DuplicateHandling::Prevent
);
58 void SfxListenerGuard::endListening()
60 if (m_pNotifier
!= nullptr)
62 m_rListener
.EndListening(*m_pNotifier
);
63 m_pNotifier
= nullptr;
67 void WindowListenerGuard::startListening(vcl::Window
& rNotifier
)
69 assert(m_pNotifier
== nullptr && "called more than once");
70 m_pNotifier
= &rNotifier
;
71 m_pNotifier
->AddEventListener(m_aListener
);
74 void WindowListenerGuard::endListening()
78 m_pNotifier
->RemoveEventListener(m_aListener
);
79 m_pNotifier
= nullptr;
83 Paragraph::Paragraph(::rtl::Reference
< Document
> xDocument
,
84 Paragraphs::size_type nNumber
):
85 ParagraphBase(m_aMutex
),
86 m_xDocument(std::move(xDocument
)),
90 m_aParagraphText
= m_xDocument
->retrieveParagraphText(this);
94 Paragraph::numberChanged(bool bIncremented
)
102 void Paragraph::textChanged()
104 OUString aParagraphText
= implGetText();
105 css::uno::Any aOldValue
, aNewValue
;
106 if ( implInitTextChangedEvent( m_aParagraphText
, aParagraphText
, aOldValue
, aNewValue
) )
108 m_aParagraphText
= aParagraphText
;
109 notifyEvent(css::accessibility::AccessibleEventId::
111 aOldValue
, aNewValue
);
115 void Paragraph::notifyEvent(::sal_Int16 nEventId
,
116 css::uno::Any
const & rOldValue
,
117 css::uno::Any
const & rNewValue
)
120 comphelper::AccessibleEventNotifier::addEvent( m_nClientId
, css::accessibility::AccessibleEventObject(
122 nEventId
, rNewValue
, rOldValue
, -1) );
126 css::uno::Reference
< css::accessibility::XAccessibleContext
> SAL_CALL
127 Paragraph::getAccessibleContext()
134 sal_Int64 SAL_CALL
Paragraph::getAccessibleChildCount()
141 css::uno::Reference
< css::accessibility::XAccessible
> SAL_CALL
142 Paragraph::getAccessibleChild(sal_Int64
)
145 throw css::lang::IndexOutOfBoundsException(
146 "textwindowaccessibility.cxx:"
147 " Paragraph::getAccessibleChild",
152 css::uno::Reference
< css::accessibility::XAccessible
> SAL_CALL
153 Paragraph::getAccessibleParent()
156 return m_xDocument
->getAccessible();
160 sal_Int64 SAL_CALL
Paragraph::getAccessibleIndexInParent()
163 return m_xDocument
->retrieveParagraphIndex(this);
167 ::sal_Int16 SAL_CALL
Paragraph::getAccessibleRole()
170 return css::accessibility::AccessibleRole::PARAGRAPH
;
174 OUString SAL_CALL
Paragraph::getAccessibleDescription()
181 OUString SAL_CALL
Paragraph::getAccessibleName()
188 css::uno::Reference
< css::accessibility::XAccessibleRelationSet
>
189 SAL_CALL
Paragraph::getAccessibleRelationSet()
192 return m_xDocument
->retrieveParagraphRelationSet( this );
196 sal_Int64 SAL_CALL
Paragraph::getAccessibleStateSet()
200 // FIXME Notification of changes (STATE_CHANGED) missing when
201 // m_rView.IsReadOnly() changes:
202 return m_xDocument
->retrieveParagraphState(this);
206 css::lang::Locale SAL_CALL
Paragraph::getLocale()
209 return m_xDocument
->retrieveLocale();
213 sal_Bool SAL_CALL
Paragraph::containsPoint(css::awt::Point
const & rPoint
)
216 css::awt::Rectangle
aRect(m_xDocument
->retrieveParagraphBounds(this,
218 return rPoint
.X
>= 0 && rPoint
.X
< aRect
.Width
219 && rPoint
.Y
>= 0 && rPoint
.Y
< aRect
.Height
;
223 css::uno::Reference
< css::accessibility::XAccessible
> SAL_CALL
224 Paragraph::getAccessibleAtPoint(css::awt::Point
const &)
231 css::awt::Rectangle SAL_CALL
Paragraph::getBounds()
234 return m_xDocument
->retrieveParagraphBounds(this, false);
238 css::awt::Point SAL_CALL
Paragraph::getLocation()
241 css::awt::Rectangle
aRect(m_xDocument
->retrieveParagraphBounds(this,
243 return css::awt::Point(aRect
.X
, aRect
.Y
);
247 css::awt::Point SAL_CALL
Paragraph::getLocationOnScreen()
250 css::awt::Rectangle
aRect(m_xDocument
->retrieveParagraphBounds(this,
252 return css::awt::Point(aRect
.X
, aRect
.Y
);
256 css::awt::Size SAL_CALL
Paragraph::getSize()
259 css::awt::Rectangle
aRect(m_xDocument
->retrieveParagraphBounds(this,
261 return css::awt::Size(aRect
.Width
, aRect
.Height
);
265 void SAL_CALL
Paragraph::grabFocus()
268 VclPtr
<vcl::Window
> pWindow
= m_xDocument
->GetWindow();
271 pWindow
->GrabFocus();
275 m_xDocument
->changeParagraphSelection(this, 0, 0);
277 catch (const css::lang::IndexOutOfBoundsException
&)
279 TOOLS_INFO_EXCEPTION("accessibility", "Paragraph::grabFocus: caught unexpected");
284 sal_Int32 SAL_CALL
Paragraph::getForeground()
290 sal_Int32 SAL_CALL
Paragraph::getBackground()
296 ::sal_Int32 SAL_CALL
Paragraph::getCaretPosition()
299 return m_xDocument
->retrieveParagraphCaretPosition(this);
303 sal_Bool SAL_CALL
Paragraph::setCaretPosition(::sal_Int32 nIndex
)
306 m_xDocument
->changeParagraphSelection(this, nIndex
, nIndex
);
311 ::sal_Unicode SAL_CALL
Paragraph::getCharacter(::sal_Int32 nIndex
)
314 return OCommonAccessibleText::implGetCharacter(implGetText(), nIndex
);
318 css::uno::Sequence
< css::beans::PropertyValue
> SAL_CALL
319 Paragraph::getCharacterAttributes(::sal_Int32 nIndex
, const css::uno::Sequence
< OUString
>& aRequestedAttributes
)
322 return m_xDocument
->retrieveCharacterAttributes( this, nIndex
, aRequestedAttributes
);
326 css::awt::Rectangle SAL_CALL
327 Paragraph::getCharacterBounds(::sal_Int32 nIndex
)
330 css::awt::Rectangle
aBounds(m_xDocument
->retrieveCharacterBounds(this, nIndex
));
331 css::awt::Rectangle
aParaBounds(m_xDocument
->retrieveParagraphBounds(this, false));
332 aBounds
.X
-= aParaBounds
.X
;
333 aBounds
.Y
-= aParaBounds
.Y
;
338 ::sal_Int32 SAL_CALL
Paragraph::getCharacterCount()
341 return implGetText().getLength();
346 Paragraph::getIndexAtPoint(css::awt::Point
const & rPoint
)
349 css::awt::Point
aPoint(rPoint
);
350 css::awt::Rectangle
aParaBounds(m_xDocument
->retrieveParagraphBounds(this, false));
351 aPoint
.X
+= aParaBounds
.X
;
352 aPoint
.Y
+= aParaBounds
.Y
;
353 return m_xDocument
->retrieveCharacterIndex(this, aPoint
);
357 OUString SAL_CALL
Paragraph::getSelectedText()
361 return OCommonAccessibleText::getSelectedText();
365 ::sal_Int32 SAL_CALL
Paragraph::getSelectionStart()
368 return OCommonAccessibleText::getSelectionStart();
372 ::sal_Int32 SAL_CALL
Paragraph::getSelectionEnd()
375 return OCommonAccessibleText::getSelectionEnd();
379 sal_Bool SAL_CALL
Paragraph::setSelection(::sal_Int32 nStartIndex
,
380 ::sal_Int32 nEndIndex
)
383 m_xDocument
->changeParagraphSelection(this, nStartIndex
, nEndIndex
);
388 OUString SAL_CALL
Paragraph::getText()
391 return implGetText();
395 OUString SAL_CALL
Paragraph::getTextRange(::sal_Int32 nStartIndex
,
396 ::sal_Int32 nEndIndex
)
399 return OCommonAccessibleText::implGetTextRange(implGetText(), nStartIndex
, nEndIndex
);
403 css::accessibility::TextSegment SAL_CALL
Paragraph::getTextAtIndex( sal_Int32 nIndex
, sal_Int16 aTextType
)
406 return OCommonAccessibleText::getTextAtIndex(nIndex
, aTextType
);
410 css::accessibility::TextSegment SAL_CALL
Paragraph::getTextBeforeIndex( sal_Int32 nIndex
, sal_Int16 aTextType
)
413 return OCommonAccessibleText::getTextBeforeIndex(nIndex
, aTextType
);
417 css::accessibility::TextSegment SAL_CALL
Paragraph::getTextBehindIndex( sal_Int32 nIndex
, sal_Int16 aTextType
)
420 return OCommonAccessibleText::getTextBehindIndex(nIndex
, aTextType
);
424 sal_Bool SAL_CALL
Paragraph::copyText(::sal_Int32 nStartIndex
,
425 ::sal_Int32 nEndIndex
)
428 m_xDocument
->copyParagraphText(this, nStartIndex
, nEndIndex
);
433 sal_Bool SAL_CALL
Paragraph::scrollSubstringTo( sal_Int32
, sal_Int32
, css::accessibility::AccessibleScrollType
)
439 sal_Bool SAL_CALL
Paragraph::cutText(::sal_Int32 nStartIndex
,
440 ::sal_Int32 nEndIndex
)
443 m_xDocument
->changeParagraphText(this, nStartIndex
, nEndIndex
, true, false,
449 sal_Bool SAL_CALL
Paragraph::pasteText(::sal_Int32 nIndex
)
452 m_xDocument
->changeParagraphText(this, nIndex
, nIndex
, false, true,
458 sal_Bool SAL_CALL
Paragraph::deleteText(::sal_Int32 nStartIndex
,
459 ::sal_Int32 nEndIndex
)
462 m_xDocument
->changeParagraphText(this, nStartIndex
, nEndIndex
, false, false,
468 sal_Bool SAL_CALL
Paragraph::insertText(OUString
const & rText
,
472 m_xDocument
->changeParagraphText(this, nIndex
, nIndex
, false, false, rText
);
478 Paragraph::replaceText(::sal_Int32 nStartIndex
, ::sal_Int32 nEndIndex
,
479 OUString
const & rReplacement
)
482 m_xDocument
->changeParagraphText(this, nStartIndex
, nEndIndex
, false, false,
488 sal_Bool SAL_CALL
Paragraph::setAttributes(
489 ::sal_Int32 nStartIndex
, ::sal_Int32 nEndIndex
,
490 css::uno::Sequence
< css::beans::PropertyValue
> const & rAttributeSet
)
493 m_xDocument
->changeParagraphAttributes(this, nStartIndex
, nEndIndex
,
499 sal_Bool SAL_CALL
Paragraph::setText(OUString
const & rText
)
502 m_xDocument
->changeParagraphText(this, rText
);
507 css::uno::Sequence
< css::beans::PropertyValue
> SAL_CALL
508 Paragraph::getDefaultAttributes(const css::uno::Sequence
< OUString
>&)
511 return {}; // default attributes are not supported by text engine
515 css::uno::Sequence
< css::beans::PropertyValue
> SAL_CALL
516 Paragraph::getRunAttributes(::sal_Int32 Index
, const css::uno::Sequence
< OUString
>& RequestedAttributes
)
519 return m_xDocument
->retrieveRunAttributes( this, Index
, RequestedAttributes
);
523 ::sal_Int32 SAL_CALL
Paragraph::getLineNumberAtIndex( ::sal_Int32 nIndex
)
527 ::sal_Int32 nLineNo
= -1;
528 m_xDocument
->retrieveParagraphLineBoundary( this, nIndex
, &nLineNo
);
534 css::accessibility::TextSegment SAL_CALL
Paragraph::getTextAtLineNumber( ::sal_Int32 nLineNo
)
538 css::i18n::Boundary aBoundary
=
539 m_xDocument
->retrieveParagraphBoundaryOfLine( this, nLineNo
);
541 return css::accessibility::TextSegment( getTextRange(aBoundary
.startPos
, aBoundary
.endPos
),
542 aBoundary
.startPos
, aBoundary
.endPos
);
546 css::accessibility::TextSegment SAL_CALL
Paragraph::getTextAtLineWithCaret( )
550 sal_Int32 nLineNo
= getNumberOfLineWithCaret();
553 return ( nLineNo
>= 0 ) ?
554 getTextAtLineNumber( nLineNo
) :
555 css::accessibility::TextSegment();
556 } catch (const css::lang::IndexOutOfBoundsException
&) {
557 css::uno::Any anyEx
= cppu::getCaughtException();
558 throw css::lang::WrappedTargetRuntimeException(
559 "textwindowaccessibility.cxx:"
560 " Paragraph::getTextAtLineWithCaret",
566 ::sal_Int32 SAL_CALL
Paragraph::getNumberOfLineWithCaret( )
569 return m_xDocument
->retrieveParagraphLineWithCursor(this);
574 void SAL_CALL
Paragraph::addAccessibleEventListener(
576 css::accessibility::XAccessibleEventListener
> const & rListener
)
581 ::osl::ClearableMutexGuard
aGuard(rBHelper
.rMutex
);
582 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
585 rListener
->disposing(css::lang::EventObject(
591 m_nClientId
= comphelper::AccessibleEventNotifier::registerClient( );
592 comphelper::AccessibleEventNotifier::addEventListener( m_nClientId
, rListener
);
597 void SAL_CALL
Paragraph::removeAccessibleEventListener(
599 css::accessibility::XAccessibleEventListener
> const & rListener
)
601 comphelper::AccessibleEventNotifier::TClientId nId
= 0;
603 osl::MutexGuard
aGuard(rBHelper
.rMutex
);
604 if (rListener
.is() && m_nClientId
!= 0
605 && comphelper::AccessibleEventNotifier::removeEventListener( m_nClientId
, rListener
) == 0)
613 // no listeners anymore
614 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
615 // and at least to us not firing any events anymore, in case somebody calls
616 // NotifyAccessibleEvent, again
617 comphelper::AccessibleEventNotifier::revokeClient(nId
);
622 void SAL_CALL
Paragraph::disposing()
624 comphelper::AccessibleEventNotifier::TClientId nId
= 0;
626 osl::MutexGuard
aGuard(rBHelper
.rMutex
);
631 comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing(nId
, *this);
635 OUString
Paragraph::implGetText()
637 return m_xDocument
->retrieveParagraphText(this);
641 css::lang::Locale
Paragraph::implGetLocale()
643 return m_xDocument
->retrieveLocale();
647 void Paragraph::implGetSelection(::sal_Int32
& rStartIndex
,
648 ::sal_Int32
& rEndIndex
)
650 m_xDocument
->retrieveParagraphSelection(this, &rStartIndex
, &rEndIndex
);
654 void Paragraph::implGetParagraphBoundary( const OUString
& rText
,
655 css::i18n::Boundary
& rBoundary
,
658 ::sal_Int32 nLength
= rText
.getLength();
660 if ( implIsValidIndex( nIndex
, nLength
) )
662 rBoundary
.startPos
= 0;
663 rBoundary
.endPos
= nLength
;
667 rBoundary
.startPos
= nIndex
;
668 rBoundary
.endPos
= nIndex
;
673 void Paragraph::implGetLineBoundary( const OUString
& rText
,
674 css::i18n::Boundary
& rBoundary
,
677 ::sal_Int32 nLength
= rText
.getLength();
679 if ( implIsValidIndex( nIndex
, nLength
) || nIndex
== nLength
)
681 css::i18n::Boundary aBoundary
=
682 m_xDocument
->retrieveParagraphLineBoundary( this, nIndex
, nullptr );
683 rBoundary
.startPos
= aBoundary
.startPos
;
684 rBoundary
.endPos
= aBoundary
.endPos
;
688 rBoundary
.startPos
= nIndex
;
689 rBoundary
.endPos
= nIndex
;
694 void Paragraph::checkDisposed()
696 ::osl::MutexGuard
aGuard(rBHelper
.rMutex
);
697 if (!(rBHelper
.bDisposed
|| rBHelper
.bInDispose
))
699 throw css::lang::DisposedException(
700 OUString(), getXWeak());
703 Document::Document(::VCLXWindow
* pVclXWindow
, ::TextEngine
& rEngine
,
705 VCLXAccessibleComponent(pVclXWindow
),
706 m_xAccessible(pVclXWindow
),
709 m_aEngineListener(*this),
710 m_aViewListener(LINK(this, Document
, WindowEventHandler
)),
713 m_nVisibleBeginOffset(0),
714 m_nSelectionFirstPara(-1),
715 m_nSelectionFirstPos(-1),
716 m_nSelectionLastPara(-1),
717 m_nSelectionLastPos(-1),
718 m_bSelectionChangedNotification(false)
721 css::lang::Locale
Document::retrieveLocale()
723 SolarMutexGuard aGuard
;
724 return m_rEngine
.GetLocale();
727 ::sal_Int32
Document::retrieveParagraphIndex(Paragraph
const * pParagraph
)
729 ::osl::MutexGuard
aInternalGuard(GetMutex());
731 // If a client holds on to a Paragraph that is no longer visible, it can
732 // happen that this Paragraph lies outside the range from m_aVisibleBegin
733 // to m_aVisibleEnd. In that case, return -1 instead of a valid index:
734 Paragraphs::iterator
aPara(m_xParagraphs
->begin()
735 + pParagraph
->getNumber());
736 return aPara
< m_aVisibleBegin
|| aPara
>= m_aVisibleEnd
737 ? -1 : static_cast< ::sal_Int32
>(aPara
- m_aVisibleBegin
);
738 // XXX numeric overflow
741 ::sal_Int64
Document::retrieveParagraphState(Paragraph
const * pParagraph
)
743 ::osl::MutexGuard
aInternalGuard(GetMutex());
745 // If a client holds on to a Paragraph that is no longer visible, it can
746 // happen that this Paragraph lies outside the range from m_aVisibleBegin
747 // to m_aVisibleEnd. In that case, it is neither VISIBLE nor SHOWING:
749 = css::accessibility::AccessibleStateType::ENABLED
750 | css::accessibility::AccessibleStateType::SENSITIVE
751 | css::accessibility::AccessibleStateType::FOCUSABLE
752 | css::accessibility::AccessibleStateType::MULTI_LINE
;
753 if (!m_rView
.IsReadOnly())
754 nState
|= css::accessibility::AccessibleStateType::EDITABLE
;
755 Paragraphs::iterator
aPara(m_xParagraphs
->begin()
756 + pParagraph
->getNumber());
757 if (aPara
>= m_aVisibleBegin
&& aPara
< m_aVisibleEnd
)
760 |= css::accessibility::AccessibleStateType::VISIBLE
761 | css::accessibility::AccessibleStateType::SHOWING
;
762 if (aPara
== m_aFocused
)
763 nState
|= css::accessibility::AccessibleStateType::FOCUSED
;
769 Document::retrieveParagraphBounds(Paragraph
const * pParagraph
,
772 SolarMutexGuard aGuard
;
773 ::osl::MutexGuard
aInternalGuard(GetMutex());
775 // If a client holds on to a Paragraph that is no longer visible (as it
776 // scrolled out the top of the view), it can happen that this Paragraph
777 // lies before m_aVisibleBegin. In that case, calculate the vertical
778 // position of the Paragraph starting at paragraph 0, otherwise optimize
779 // and start at m_aVisibleBegin:
780 Paragraphs::iterator
aPara(m_xParagraphs
->begin()
781 + pParagraph
->getNumber());
782 auto lAddHeight
= [](const sal_Int32
& rSum
, const ParagraphInfo
& rParagraph
) {
783 return rSum
+ rParagraph
.getHeight(); };
785 if (aPara
< m_aVisibleBegin
)
786 nPos
= std::accumulate(m_xParagraphs
->begin(), aPara
, sal_Int32(0), lAddHeight
);
788 nPos
= std::accumulate(m_aVisibleBegin
, aPara
, m_nViewOffset
- m_nVisibleBeginOffset
, lAddHeight
);
792 aOrig
= m_rView
.GetWindow()->OutputToAbsoluteScreenPixel(aOrig
);
794 return css::awt::Rectangle(
795 static_cast< ::sal_Int32
>(aOrig
.X()),
796 static_cast< ::sal_Int32
>(aOrig
.Y()) + nPos
- m_nViewOffset
,
797 m_rView
.GetWindow()->GetOutputSizePixel().Width(), aPara
->getHeight());
798 // XXX numeric overflow (3x)
802 Document::retrieveParagraphText(Paragraph
const * pParagraph
)
804 SolarMutexGuard aGuard
;
805 ::osl::MutexGuard
aInternalGuard(GetMutex());
806 return m_rEngine
.GetText(static_cast< ::sal_uInt32
>(pParagraph
->getNumber()));
807 // numeric overflow cannot happen here
810 void Document::retrieveParagraphSelection(Paragraph
const * pParagraph
,
811 ::sal_Int32
* pBegin
,
814 SolarMutexGuard aGuard
;
815 ::osl::MutexGuard
aInternalGuard(GetMutex());
816 ::TextSelection
const & rSelection
= m_rView
.GetSelection();
817 Paragraphs::size_type nNumber
= pParagraph
->getNumber();
818 TextPaM
aStartPaM( rSelection
.GetStart() );
819 TextPaM
aEndPaM( rSelection
.GetEnd() );
820 TextPaM
aMinPaM( std::min( aStartPaM
, aEndPaM
) );
821 TextPaM
aMaxPaM( std::max( aStartPaM
, aEndPaM
) );
823 if ( nNumber
>= aMinPaM
.GetPara() && nNumber
<= aMaxPaM
.GetPara() )
825 *pBegin
= nNumber
> aMinPaM
.GetPara() ? 0 : aMinPaM
.GetIndex();
826 // XXX numeric overflow
827 *pEnd
= nNumber
< aMaxPaM
.GetPara()
828 ? m_rEngine
.GetText(static_cast< ::sal_uInt32
>(nNumber
)).getLength()
829 : aMaxPaM
.GetIndex();
830 // XXX numeric overflow (3x)
832 if ( aStartPaM
> aEndPaM
)
833 std::swap( *pBegin
, *pEnd
);
842 ::sal_Int32
Document::retrieveParagraphCaretPosition(Paragraph
const * pParagraph
)
844 SolarMutexGuard aGuard
;
845 ::osl::MutexGuard
aInternalGuard(GetMutex());
846 ::TextSelection
const & rSelection
= m_rView
.GetSelection();
847 Paragraphs::size_type nNumber
= pParagraph
->getNumber();
848 TextPaM
aEndPaM( rSelection
.GetEnd() );
850 return aEndPaM
.GetPara() == nNumber
? aEndPaM
.GetIndex() : -1;
854 Document::retrieveCharacterBounds(Paragraph
const * pParagraph
,
857 SolarMutexGuard aGuard
;
858 ::osl::MutexGuard
aInternalGuard(GetMutex());
859 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>(pParagraph
->getNumber());
860 sal_Int32 nLength
= m_rEngine
.GetText(nNumber
).getLength();
861 // XXX numeric overflow
862 if (nIndex
< 0 || nIndex
> nLength
)
863 throw css::lang::IndexOutOfBoundsException(
864 "textwindowaccessibility.cxx:"
865 " Document::retrieveCharacterAttributes",
867 css::awt::Rectangle
aBounds( 0, 0, 0, 0 );
868 if ( nIndex
== nLength
)
870 aBounds
= AWTRectangle(
871 m_rEngine
.PaMtoEditCursor(::TextPaM(nNumber
, nIndex
)));
875 ::tools::Rectangle
aLeft(
876 m_rEngine
.PaMtoEditCursor(::TextPaM(nNumber
, nIndex
)));
877 // XXX numeric overflow
878 ::tools::Rectangle
aRight(
879 m_rEngine
.PaMtoEditCursor(::TextPaM(nNumber
, nIndex
+ 1)));
880 // XXX numeric overflow (2x)
881 // FIXME If the vertical extends of the two cursors do not match, assume
882 // nIndex is the last character on the line; the bounding box will then
883 // extend to m_rEngine.GetMaxTextWidth():
884 ::sal_Int32 nWidth
= (aLeft
.Top() == aRight
.Top()
885 && aLeft
.Bottom() == aRight
.Bottom())
886 ? static_cast< ::sal_Int32
>(aRight
.Left() - aLeft
.Left())
887 : static_cast< ::sal_Int32
>(m_rEngine
.GetMaxTextWidth()
889 // XXX numeric overflow (4x)
890 aBounds
= css::awt::Rectangle(static_cast< ::sal_Int32
>(aLeft
.Left()),
891 static_cast< ::sal_Int32
>(aLeft
.Top() - m_nViewOffset
),
893 static_cast< ::sal_Int32
>(aLeft
.Bottom()
895 // XXX numeric overflow (4x)
900 ::sal_Int32
Document::retrieveCharacterIndex(Paragraph
const * pParagraph
,
901 css::awt::Point
const & rPoint
)
903 SolarMutexGuard aGuard
;
904 ::osl::MutexGuard
aInternalGuard(GetMutex());
905 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>(pParagraph
->getNumber());
906 // XXX numeric overflow
907 ::TextPaM
aPaM(m_rEngine
.GetPaM(::Point(static_cast< tools::Long
>(rPoint
.X
),
908 static_cast< tools::Long
>(rPoint
.Y
))));
909 // XXX numeric overflow (2x)
910 return aPaM
.GetPara() == nNumber
? aPaM
.GetIndex() : -1;
911 // XXX numeric overflow
914 css::uno::Sequence
< css::beans::PropertyValue
>
915 Document::retrieveCharacterAttributes(
916 Paragraph
const * pParagraph
, ::sal_Int32 nIndex
,
917 const css::uno::Sequence
< OUString
>& aRequestedAttributes
)
919 SolarMutexGuard aGuard
;
921 vcl::Font aFont
= m_rEngine
.GetFont();
922 const sal_Int32 AttributeCount
= 9;
923 std::vector
< css::beans::PropertyValue
> aAttribs
;
924 aAttribs
.reserve(AttributeCount
);
926 css::beans::PropertyValue aAttrib
;
928 aAttrib
.State
= css::beans::PropertyState_DIRECT_VALUE
;
930 //character background color
931 aAttrib
.Name
= "CharBackColor";
932 aAttrib
.Value
= mapFontColor( aFont
.GetFillColor() );
933 aAttribs
.push_back(aAttrib
);
936 aAttrib
.Name
= "CharColor";
937 //aAttrib.Value = mapFontColor( aFont.GetColor() );
938 aAttrib
.Value
= mapFontColor( m_rEngine
.GetTextColor() );
939 aAttribs
.push_back(aAttrib
);
941 //character font name
942 aAttrib
.Name
= "CharFontName";
943 aAttrib
.Value
<<= aFont
.GetFamilyName();
944 aAttribs
.push_back(aAttrib
);
947 aAttrib
.Name
= "CharHeight";
948 aAttrib
.Value
<<= static_cast<sal_Int16
>(aFont
.GetFontHeight());
949 aAttribs
.push_back(aAttrib
);
952 aAttrib
.Name
= "CharPosture";
953 aAttrib
.Value
<<= static_cast<sal_Int16
>(aFont
.GetItalic());
954 aAttribs
.push_back(aAttrib
);
958 aAttrib.Name = "CharRelief";
959 aAttrib.Value = css::uno::Any( (sal_Int16)aFont.GetRelief() );
960 aAttribs.push_back(aAttrib);
963 //character strikeout
964 aAttrib
.Name
= "CharStrikeout";
965 aAttrib
.Value
<<= static_cast<sal_Int16
>(aFont
.GetStrikeout());
966 aAttribs
.push_back(aAttrib
);
968 //character underline
969 aAttrib
.Name
= "CharUnderline";
970 aAttrib
.Value
<<= static_cast<sal_Int16
>(aFont
.GetUnderline());
971 aAttribs
.push_back(aAttrib
);
974 aAttrib
.Name
= "CharWeight";
975 aAttrib
.Value
<<= static_cast<float>(aFont
.GetWeight());
976 aAttribs
.push_back(aAttrib
);
978 //character alignment
979 aAttrib
.Name
= "ParaAdjust";
980 aAttrib
.Value
<<= static_cast<sal_Int16
>(m_rEngine
.GetTextAlign());
981 aAttribs
.push_back(aAttrib
);
983 ::osl::MutexGuard
aInternalGuard(GetMutex());
984 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>(pParagraph
->getNumber());
985 // XXX numeric overflow
986 // nIndex can be equal to getLength();
987 if (nIndex
< 0 || nIndex
> m_rEngine
.GetText(nNumber
).getLength())
988 throw css::lang::IndexOutOfBoundsException(
989 "textwindowaccessibility.cxx:"
990 " Document::retrieveCharacterAttributes",
994 // retrieve run attributes
995 tPropValMap aCharAttrSeq
;
996 retrieveRunAttributesImpl( pParagraph
, nIndex
, aRequestedAttributes
, aCharAttrSeq
);
998 for (const css::beans::PropertyValue
& rAttrib
: aAttribs
)
1000 aCharAttrSeq
[ rAttrib
.Name
] = rAttrib
;
1003 const css::uno::Sequence
< css::beans::PropertyValue
> aRes
= comphelper::mapValuesToSequence( aCharAttrSeq
);
1005 // sort the attributes
1006 auto nLength
= static_cast<size_t>(aRes
.getLength());
1007 std::unique_ptr
<sal_Int32
[]> pIndices( new sal_Int32
[nLength
] );
1008 std::iota(&pIndices
[0], &pIndices
[nLength
], 0);
1009 std::sort(&pIndices
[0], &pIndices
[nLength
],
1010 [&aRes
](sal_Int32 a
, sal_Int32 b
) { return aRes
[a
].Name
< aRes
[b
].Name
; });
1012 // create sorted sequences according to index array
1013 std::vector
<css::beans::PropertyValue
> aNewValues
;
1014 aNewValues
.reserve(nLength
);
1015 std::transform(&pIndices
[0], &pIndices
[nLength
], std::back_inserter(aNewValues
),
1016 [&aRes
](const sal_Int32 nIdx
) { return aRes
[nIdx
]; });
1018 return comphelper::containerToSequence(aNewValues
);
1021 void Document::retrieveRunAttributesImpl(
1022 Paragraph
const * pParagraph
, ::sal_Int32 Index
,
1023 const css::uno::Sequence
< OUString
>& RequestedAttributes
,
1024 tPropValMap
& rRunAttrSeq
)
1026 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>( pParagraph
->getNumber() );
1027 ::TextPaM
aPaM( nNumber
, Index
);
1028 // XXX numeric overflow
1029 ::TextAttribFontColor
const * pColor
1030 = static_cast< ::TextAttribFontColor
const * >(
1031 m_rEngine
.FindAttrib( aPaM
, TEXTATTR_FONTCOLOR
) );
1032 ::TextAttribFontWeight
const * pWeight
1033 = static_cast< ::TextAttribFontWeight
const * >(
1034 m_rEngine
.FindAttrib( aPaM
, TEXTATTR_FONTWEIGHT
) );
1035 tPropValMap aRunAttrSeq
;
1038 css::beans::PropertyValue aPropVal
;
1039 aPropVal
.Name
= "CharColor";
1040 aPropVal
.Handle
= -1;
1041 aPropVal
.Value
= mapFontColor( pColor
->GetColor() );
1042 aPropVal
.State
= css::beans::PropertyState_DIRECT_VALUE
;
1043 aRunAttrSeq
[ aPropVal
.Name
] = aPropVal
;
1047 css::beans::PropertyValue aPropVal
;
1048 aPropVal
.Name
= "CharWeight";
1049 aPropVal
.Handle
= -1;
1050 aPropVal
.Value
= mapFontWeight( pWeight
->getFontWeight() );
1051 aPropVal
.State
= css::beans::PropertyState_DIRECT_VALUE
;
1052 aRunAttrSeq
[ aPropVal
.Name
] = aPropVal
;
1054 if ( !RequestedAttributes
.hasElements() )
1056 rRunAttrSeq
= aRunAttrSeq
;
1060 for ( const OUString
& rReqAttr
: RequestedAttributes
)
1062 tPropValMap::iterator aIter
= aRunAttrSeq
.find( rReqAttr
);
1063 if ( aIter
!= aRunAttrSeq
.end() )
1065 rRunAttrSeq
[ (*aIter
).first
] = (*aIter
).second
;
1071 css::uno::Sequence
< css::beans::PropertyValue
>
1072 Document::retrieveRunAttributes(
1073 Paragraph
const * pParagraph
, ::sal_Int32 Index
,
1074 const css::uno::Sequence
< OUString
>& RequestedAttributes
)
1076 SolarMutexGuard aGuard
;
1077 ::osl::MutexGuard
aInternalGuard( GetMutex() );
1078 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>( pParagraph
->getNumber() );
1079 // XXX numeric overflow
1080 if ( Index
< 0 || Index
>= m_rEngine
.GetText(nNumber
).getLength() )
1081 throw css::lang::IndexOutOfBoundsException(
1082 "textwindowaccessibility.cxx:"
1083 " Document::retrieveRunAttributes",
1086 tPropValMap aRunAttrSeq
;
1087 retrieveRunAttributesImpl( pParagraph
, Index
, RequestedAttributes
, aRunAttrSeq
);
1088 return comphelper::mapValuesToSequence( aRunAttrSeq
);
1091 void Document::changeParagraphText(Paragraph
const * pParagraph
,
1092 OUString
const & rText
)
1094 SolarMutexGuard aGuard
;
1096 ::osl::MutexGuard
aInternalGuard(GetMutex());
1097 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>(pParagraph
->getNumber());
1098 // XXX numeric overflow
1099 changeParagraphText(nNumber
, 0, m_rEngine
.GetTextLen(nNumber
), false,
1104 void Document::changeParagraphText(Paragraph
const * pParagraph
,
1105 ::sal_Int32 nBegin
, ::sal_Int32 nEnd
,
1106 bool bCut
, bool bPaste
,
1107 OUString
const & rText
)
1109 SolarMutexGuard aGuard
;
1111 ::osl::MutexGuard
aInternalGuard(GetMutex());
1112 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>(pParagraph
->getNumber());
1113 // XXX numeric overflow
1114 if (nBegin
< 0 || nBegin
> nEnd
1115 || nEnd
> m_rEngine
.GetText(nNumber
).getLength())
1116 throw css::lang::IndexOutOfBoundsException(
1117 "textwindowaccessibility.cxx:"
1118 " Document::changeParagraphText",
1120 changeParagraphText(nNumber
, static_cast< ::sal_uInt16
>(nBegin
),
1121 static_cast< ::sal_uInt16
>(nEnd
), bCut
, bPaste
, rText
);
1122 // XXX numeric overflow (2x)
1126 void Document::copyParagraphText(Paragraph
const * pParagraph
,
1127 ::sal_Int32 nBegin
, ::sal_Int32 nEnd
)
1129 SolarMutexGuard aGuard
;
1131 ::osl::MutexGuard
aInternalGuard(GetMutex());
1132 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>(pParagraph
->getNumber());
1133 // XXX numeric overflow
1134 if (nBegin
< 0 || nBegin
> nEnd
1135 || nEnd
> m_rEngine
.GetText(nNumber
).getLength())
1136 throw css::lang::IndexOutOfBoundsException(
1137 "textwindowaccessibility.cxx:"
1138 " Document::copyParagraphText",
1140 m_rView
.SetSelection(
1141 ::TextSelection(::TextPaM(nNumber
, nBegin
),
1142 ::TextPaM(nNumber
, nEnd
)));
1143 // XXX numeric overflow (2x)
1148 void Document::changeParagraphAttributes(
1149 Paragraph
const * pParagraph
, ::sal_Int32 nBegin
, ::sal_Int32 nEnd
,
1150 css::uno::Sequence
< css::beans::PropertyValue
> const & rAttributeSet
)
1152 SolarMutexGuard aGuard
;
1154 ::osl::MutexGuard
aInternalGuard(GetMutex());
1155 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>(pParagraph
->getNumber());
1156 // XXX numeric overflow
1157 if (nBegin
< 0 || nBegin
> nEnd
1158 || nEnd
> m_rEngine
.GetText(nNumber
).getLength())
1159 throw css::lang::IndexOutOfBoundsException(
1160 "textwindowaccessibility.cxx:"
1161 " Document::changeParagraphAttributes",
1164 // FIXME The new attributes are added to any attributes already set,
1165 // they do not replace the old attributes as required by
1166 // XAccessibleEditableText.setAttributes:
1167 for (const auto& rAttr
: rAttributeSet
)
1168 if ( rAttr
.Name
== "CharColor" )
1169 m_rEngine
.SetAttrib(::TextAttribFontColor(
1170 mapFontColor(rAttr
.Value
)),
1171 nNumber
, nBegin
, nEnd
);
1172 // XXX numeric overflow (2x)
1173 else if ( rAttr
.Name
== "CharWeight" )
1174 m_rEngine
.SetAttrib(::TextAttribFontWeight(
1175 mapFontWeight(rAttr
.Value
)),
1176 nNumber
, nBegin
, nEnd
);
1177 // XXX numeric overflow (2x)
1181 void Document::changeParagraphSelection(Paragraph
const * pParagraph
,
1182 ::sal_Int32 nBegin
, ::sal_Int32 nEnd
)
1184 SolarMutexGuard aGuard
;
1186 ::osl::MutexGuard
aInternalGuard(GetMutex());
1187 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>(pParagraph
->getNumber());
1188 // XXX numeric overflow
1189 if (nBegin
< 0 || nBegin
> nEnd
1190 || nEnd
> m_rEngine
.GetText(nNumber
).getLength())
1191 throw css::lang::IndexOutOfBoundsException(
1192 "textwindowaccessibility.cxx:"
1193 " Document::changeParagraphSelection",
1195 m_rView
.SetSelection(
1196 ::TextSelection(::TextPaM(nNumber
, nBegin
),
1197 ::TextPaM(nNumber
, nEnd
)));
1198 // XXX numeric overflow (2x)
1203 Document::retrieveParagraphLineBoundary( Paragraph
const * pParagraph
,
1204 ::sal_Int32 nIndex
, ::sal_Int32
*pLineNo
)
1206 css::i18n::Boundary aBoundary
;
1207 aBoundary
.startPos
= nIndex
;
1208 aBoundary
.endPos
= nIndex
;
1210 SolarMutexGuard aGuard
;
1212 ::osl::MutexGuard
aInternalGuard( GetMutex() );
1213 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>( pParagraph
->getNumber() );
1214 if ( nIndex
< 0 || nIndex
> m_rEngine
.GetText( nNumber
).getLength() )
1215 throw css::lang::IndexOutOfBoundsException(
1216 "textwindowaccessibility.cxx:"
1217 " Document::retrieveParagraphLineBoundary",
1219 ::sal_Int32 nLineStart
= 0;
1220 ::sal_Int32 nLineEnd
= 0;
1221 ::sal_uInt16 nLineCount
= m_rEngine
.GetLineCount( nNumber
);
1222 for ( ::sal_uInt16 nLine
= 0; nLine
< nLineCount
; ++nLine
)
1224 nLineStart
= nLineEnd
;
1225 nLineEnd
+= m_rEngine
.GetLineLen( nNumber
, nLine
);
1226 if ( nIndex
>= nLineStart
&& ( ( nLine
== nLineCount
- 1 ) ? nIndex
<= nLineEnd
: nIndex
< nLineEnd
) )
1228 aBoundary
.startPos
= nLineStart
;
1229 aBoundary
.endPos
= nLineEnd
;
1241 Document::retrieveParagraphBoundaryOfLine( Paragraph
const * pParagraph
,
1242 ::sal_Int32 nLineNo
)
1244 css::i18n::Boundary aBoundary
;
1245 aBoundary
.startPos
= 0;
1246 aBoundary
.endPos
= 0;
1248 SolarMutexGuard aGuard
;
1250 ::osl::MutexGuard
aInternalGuard( GetMutex() );
1251 ::sal_uInt32 nNumber
= static_cast< ::sal_uInt32
>( pParagraph
->getNumber() );
1252 if ( nLineNo
>= m_rEngine
.GetLineCount( nNumber
) )
1253 throw css::lang::IndexOutOfBoundsException(
1254 "textwindowaccessibility.cxx:"
1255 " Document::retrieveParagraphBoundaryOfLine",
1257 ::sal_Int32 nLineStart
= 0;
1258 ::sal_Int32 nLineEnd
= 0;
1259 for ( ::sal_Int32 nLine
= 0; nLine
<= nLineNo
; ++nLine
)
1261 nLineStart
= nLineEnd
;
1262 nLineEnd
+= m_rEngine
.GetLineLen( nNumber
, nLine
);
1265 aBoundary
.startPos
= nLineStart
;
1266 aBoundary
.endPos
= nLineEnd
;
1272 sal_Int32
Document::retrieveParagraphLineWithCursor( Paragraph
const * pParagraph
)
1274 SolarMutexGuard aGuard
;
1275 ::osl::MutexGuard
aInternalGuard(GetMutex());
1276 ::TextSelection
const & rSelection
= m_rView
.GetSelection();
1277 Paragraphs::size_type nNumber
= pParagraph
->getNumber();
1278 TextPaM
aEndPaM( rSelection
.GetEnd() );
1280 return aEndPaM
.GetPara() == nNumber
1281 ? m_rView
.GetLineNumberOfCursorInSelection() : -1;
1285 css::uno::Reference
< css::accessibility::XAccessibleRelationSet
>
1286 Document::retrieveParagraphRelationSet( Paragraph
const * pParagraph
)
1288 ::osl::MutexGuard
aInternalGuard( GetMutex() );
1290 rtl::Reference
<::utl::AccessibleRelationSetHelper
> pRelationSetHelper
= new ::utl::AccessibleRelationSetHelper();
1292 Paragraphs::iterator
aPara( m_xParagraphs
->begin() + pParagraph
->getNumber() );
1294 if ( aPara
> m_aVisibleBegin
&& aPara
< m_aVisibleEnd
)
1296 css::uno::Sequence
< css::uno::Reference
< css::uno::XInterface
> > aSequence
{ getAccessibleChild( aPara
- 1 ) };
1297 css::accessibility::AccessibleRelation
aRelation( css::accessibility::AccessibleRelationType::CONTENT_FLOWS_FROM
, aSequence
);
1298 pRelationSetHelper
->AddRelation( aRelation
);
1301 if ( aPara
>= m_aVisibleBegin
&& aPara
< m_aVisibleEnd
-1 )
1303 css::uno::Sequence
< css::uno::Reference
< css::uno::XInterface
> > aSequence
{ getAccessibleChild( aPara
+ 1 ) };
1304 css::accessibility::AccessibleRelation
aRelation( css::accessibility::AccessibleRelationType::CONTENT_FLOWS_TO
, aSequence
);
1305 pRelationSetHelper
->AddRelation( aRelation
);
1308 return pRelationSetHelper
;
1312 sal_Int64 SAL_CALL
Document::getAccessibleChildCount()
1314 ::comphelper::OExternalLockGuard
aGuard(this);
1316 return m_aVisibleEnd
- m_aVisibleBegin
;
1320 css::uno::Reference
< css::accessibility::XAccessible
> SAL_CALL
1321 Document::getAccessibleChild(sal_Int64 i
)
1323 ::comphelper::OExternalLockGuard
aGuard(this);
1325 if (i
< 0 || i
>= m_aVisibleEnd
- m_aVisibleBegin
)
1326 throw css::lang::IndexOutOfBoundsException(
1327 "textwindowaccessibility.cxx:"
1328 " Document::getAccessibleChild",
1330 return getAccessibleChild(m_aVisibleBegin
1331 + static_cast< Paragraphs::size_type
>(i
));
1335 ::sal_Int16 SAL_CALL
Document::getAccessibleRole()
1337 return css::accessibility::AccessibleRole::TEXT_FRAME
;
1341 css::uno::Reference
< css::accessibility::XAccessible
> SAL_CALL
1342 Document::getAccessibleAtPoint(css::awt::Point
const & rPoint
)
1344 ::comphelper::OExternalLockGuard
aGuard(this);
1347 && rPoint
.X
< m_rView
.GetWindow()->GetOutputSizePixel().Width()
1348 && rPoint
.Y
>= 0 && rPoint
.Y
< m_nViewHeight
)
1350 ::sal_Int32 nOffset
= m_nViewOffset
+ rPoint
.Y
; // XXX numeric overflow
1351 ::sal_Int32 nPos
= m_nViewOffset
- m_nVisibleBeginOffset
;
1352 for (Paragraphs::iterator
aIt(m_aVisibleBegin
); aIt
!= m_aVisibleEnd
;
1355 nPos
+= aIt
->getHeight(); // XXX numeric overflow
1357 return getAccessibleChild(aIt
);
1362 void Document::FillAccessibleStateSet( sal_Int64
& rStateSet
)
1364 VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet
);
1365 if (!m_rView
.IsReadOnly())
1366 rStateSet
|= css::accessibility::AccessibleStateType::EDITABLE
;
1369 void Document::FillAccessibleRelationSet( utl::AccessibleRelationSetHelper
& rRelationSet
)
1371 if( getAccessibleParent()->getAccessibleContext()->getAccessibleRole() == css::accessibility::AccessibleRole::SCROLL_PANE
)
1373 css::uno::Sequence
< css::uno::Reference
< css::uno::XInterface
> > aSequence
{ getAccessibleParent() };
1374 rRelationSet
.AddRelation( css::accessibility::AccessibleRelation( css::accessibility::AccessibleRelationType::MEMBER_OF
, aSequence
) );
1378 VCLXAccessibleComponent::FillAccessibleRelationSet(rRelationSet
);
1382 void SAL_CALL
Document::disposing()
1384 m_aEngineListener
.endListening();
1385 m_aViewListener
.endListening();
1386 if (m_xParagraphs
!= nullptr)
1387 disposeParagraphs();
1388 VCLXAccessibleComponent::disposing();
1392 void Document::Notify(::SfxBroadcaster
&, ::SfxHint
const & rHint
)
1394 const TextHint
* pTextHint
= dynamic_cast<const TextHint
*>(&rHint
);
1398 ::TextHint
const & rTextHint
= *pTextHint
;
1399 switch (rTextHint
.GetId())
1401 case SfxHintId::TextParaInserted
:
1402 case SfxHintId::TextParaRemoved
:
1403 // SfxHintId::TextParaInserted and SfxHintId::TextParaRemoved are sent at
1404 // "unsafe" times (when the text engine has not yet re-formatted its
1405 // content), so that for example calling ::TextEngine::GetTextHeight
1406 // from within the code that handles SfxHintId::TextParaInserted causes
1407 // trouble within the text engine. Therefore, these hints are just
1408 // buffered until a following ::TextEngine::FormatDoc causes a
1409 // SfxHintId::TextFormatted to come in:
1410 case SfxHintId::TextFormatPara
:
1411 // ::TextEngine::FormatDoc sends a sequence of
1412 // SfxHintId::TextFormatParas, followed by an optional
1413 // SfxHintId::TextHeightChanged, followed in all cases by one
1414 // SfxHintId::TextFormatted. Only the SfxHintId::TextFormatParas contain
1415 // the numbers of the affected paragraphs, but they are sent
1416 // before the changes are applied. Therefore, SfxHintId::TextFormatParas
1417 // are just buffered until another hint comes in:
1419 ::osl::MutexGuard
aInternalGuard(GetMutex());
1423 m_aParagraphNotifications
.push(rTextHint
);
1426 case SfxHintId::TextFormatted
:
1427 case SfxHintId::TextHeightChanged
:
1428 case SfxHintId::TextModified
:
1430 ::osl::MutexGuard
aInternalGuard(GetMutex());
1433 handleParagraphNotifications();
1436 case SfxHintId::TextViewScrolled
:
1438 ::osl::MutexGuard
aInternalGuard(GetMutex());
1441 handleParagraphNotifications();
1443 ::sal_Int32 nOffset
= static_cast< ::sal_Int32
>(
1444 m_rView
.GetStartDocPos().Y());
1445 // XXX numeric overflow
1446 if (nOffset
!= m_nViewOffset
)
1448 m_nViewOffset
= nOffset
;
1450 Paragraphs::iterator
aOldVisibleBegin(
1452 Paragraphs::iterator
aOldVisibleEnd(m_aVisibleEnd
);
1454 determineVisibleRange();
1456 notifyVisibleRangeChanges(aOldVisibleBegin
,
1458 m_xParagraphs
->end());
1462 case SfxHintId::TextViewSelectionChanged
:
1463 case SfxHintId::TextViewCaretChanged
:
1465 ::osl::MutexGuard
aInternalGuard(GetMutex());
1469 if (m_aParagraphNotifications
.empty())
1471 handleSelectionChangeNotification();
1475 // SfxHintId::TextViewSelectionChanged is sometimes sent at
1476 // "unsafe" times (when the text engine has not yet re-
1477 // formatted its content), so that for example calling
1478 // ::TextEngine::GetTextHeight from within the code that
1479 // handles a previous SfxHintId::TextParaInserted causes
1480 // trouble within the text engine. Therefore, these
1481 // hints are just buffered (along with
1482 // SfxHintId::TextParaInserted/REMOVED/FORMATPARA) until a
1483 // following ::TextEngine::FormatDoc causes a
1484 // SfxHintId::TextFormatted to come in:
1485 m_bSelectionChangedNotification
= true;
1493 IMPL_LINK(Document
, WindowEventHandler
, ::VclWindowEvent
&, rEvent
, void)
1495 switch (rEvent
.GetId())
1497 case VclEventId::WindowResize
:
1499 ::osl::MutexGuard
aInternalGuard(GetMutex());
1503 ::sal_Int32 nHeight
= static_cast< ::sal_Int32
>(
1504 m_rView
.GetWindow()->GetOutputSizePixel().Height());
1505 // XXX numeric overflow
1506 if (nHeight
!= m_nViewHeight
)
1508 m_nViewHeight
= nHeight
;
1510 Paragraphs::iterator
aOldVisibleBegin(m_aVisibleBegin
);
1511 Paragraphs::iterator
aOldVisibleEnd(m_aVisibleEnd
);
1513 determineVisibleRange();
1515 notifyVisibleRangeChanges(aOldVisibleBegin
, aOldVisibleEnd
,
1516 m_xParagraphs
->end());
1520 case VclEventId::WindowGetFocus
:
1522 ::osl::MutexGuard
aInternalGuard(GetMutex());
1525 //to enable the PARAGRAPH to get focus for multiline edit
1526 sal_Int64 count
= getAccessibleChildCount();
1527 bool bEmpty
= m_aFocused
== m_aVisibleEnd
&& count
== 1;
1528 if ((m_aFocused
>= m_aVisibleBegin
&& m_aFocused
< m_aVisibleEnd
) || bEmpty
)
1530 Paragraphs::iterator aTemp
= bEmpty
? m_aVisibleBegin
: m_aFocused
;
1531 ::rtl::Reference
< Paragraph
> xParagraph(getParagraph(aTemp
));
1532 if (xParagraph
.is())
1534 xParagraph
->notifyEvent(
1535 css::accessibility::AccessibleEventId::
1539 css::accessibility::AccessibleStateType::
1545 case VclEventId::WindowLoseFocus
:
1547 ::osl::MutexGuard
aInternalGuard(GetMutex());
1550 //to enable the PARAGRAPH to get focus for multiline edit
1551 sal_Int64 count
= getAccessibleChildCount();
1552 bool bEmpty
= m_aFocused
== m_aVisibleEnd
&& count
== 1;
1553 if ((m_aFocused
>= m_aVisibleBegin
&& m_aFocused
< m_aVisibleEnd
) || bEmpty
)
1555 Paragraphs::iterator aTemp
= bEmpty
? m_aVisibleBegin
: m_aFocused
;
1556 ::rtl::Reference
< Paragraph
> xParagraph(getParagraph(aTemp
));
1557 if (xParagraph
.is())
1558 xParagraph
->notifyEvent(
1559 css::accessibility::AccessibleEventId::
1562 css::accessibility::AccessibleStateType::
1572 void Document::init()
1574 if (m_xParagraphs
!= nullptr)
1577 const ::sal_uInt32 nCount
= m_rEngine
.GetParagraphCount();
1578 m_xParagraphs
.reset(new Paragraphs
);
1579 m_xParagraphs
->reserve(static_cast< Paragraphs::size_type
>(nCount
));
1580 // numeric overflow is harmless here
1581 for (::sal_uInt32 i
= 0; i
< nCount
; ++i
)
1582 m_xParagraphs
->push_back(ParagraphInfo(static_cast< ::sal_Int32
>(
1583 m_rEngine
.GetTextHeight(i
))));
1584 // XXX numeric overflow
1585 m_nViewOffset
= static_cast< ::sal_Int32
>(
1586 m_rView
.GetStartDocPos().Y()); // XXX numeric overflow
1587 m_nViewHeight
= static_cast< ::sal_Int32
>(
1588 m_rView
.GetWindow()->GetOutputSizePixel().Height());
1589 // XXX numeric overflow
1590 determineVisibleRange();
1591 m_nSelectionFirstPara
= -1;
1592 m_nSelectionFirstPos
= -1;
1593 m_nSelectionLastPara
= -1;
1594 m_nSelectionLastPos
= -1;
1595 m_aFocused
= m_xParagraphs
->end();
1596 m_bSelectionChangedNotification
= false;
1597 m_aEngineListener
.startListening(m_rEngine
);
1598 m_aViewListener
.startListening(*m_rView
.GetWindow());
1601 ::rtl::Reference
< Paragraph
>
1602 Document::getParagraph(Paragraphs::iterator
const & rIt
)
1604 return static_cast< Paragraph
* >(
1605 css::uno::Reference
< css::accessibility::XAccessible
>(
1606 rIt
->getParagraph()).get());
1609 css::uno::Reference
< css::accessibility::XAccessible
>
1610 Document::getAccessibleChild(Paragraphs::iterator
const & rIt
)
1612 css::uno::Reference
< css::accessibility::XAccessible
> xParagraph(
1613 rIt
->getParagraph());
1614 if (!xParagraph
.is())
1616 xParagraph
= new Paragraph(this, rIt
- m_xParagraphs
->begin());
1617 rIt
->setParagraph(xParagraph
);
1622 void Document::determineVisibleRange()
1624 Paragraphs::iterator
const aEnd
= m_xParagraphs
->end();
1626 m_aVisibleBegin
= aEnd
;
1627 m_aVisibleEnd
= aEnd
;
1628 m_nVisibleBeginOffset
= 0;
1630 ::sal_Int32 nPos
= 0;
1631 for (Paragraphs::iterator aIt
= m_xParagraphs
->begin(); m_aVisibleEnd
== aEnd
&& aIt
!= aEnd
; ++aIt
)
1633 ::sal_Int32
const nOldPos
= nPos
;
1634 nPos
+= aIt
->getHeight(); // XXX numeric overflow
1635 if (m_aVisibleBegin
== aEnd
)
1637 if (nPos
>= m_nViewOffset
)
1639 m_aVisibleBegin
= aIt
;
1640 m_nVisibleBeginOffset
= m_nViewOffset
- nOldPos
;
1645 if (nPos
>= m_nViewOffset
+ m_nViewHeight
) // XXX numeric overflow
1647 m_aVisibleEnd
= aIt
;
1653 !((m_aVisibleBegin
== m_xParagraphs
->end() && m_aVisibleEnd
== m_xParagraphs
->end() && m_nVisibleBeginOffset
== 0)
1654 || (m_aVisibleBegin
< m_aVisibleEnd
&& m_nVisibleBeginOffset
>= 0)),
1656 "invalid visible range");
1659 void Document::notifyVisibleRangeChanges(
1660 Paragraphs::iterator
const & rOldVisibleBegin
,
1661 Paragraphs::iterator
const & rOldVisibleEnd
,
1662 Paragraphs::iterator
const & rInserted
)
1664 // XXX Replace this code that determines which paragraphs have changed from
1665 // invisible to visible or vice versa with a better algorithm.
1666 for (Paragraphs::iterator
aIt(rOldVisibleBegin
); aIt
!= rOldVisibleEnd
;
1669 if (aIt
!= rInserted
1670 && (aIt
< m_aVisibleBegin
|| aIt
>= m_aVisibleEnd
))
1671 NotifyAccessibleEvent(
1672 css::accessibility::AccessibleEventId::
1674 css::uno::Any(getAccessibleChild(aIt
)),
1677 for (Paragraphs::iterator
aIt(m_aVisibleBegin
); aIt
!= m_aVisibleEnd
;
1680 if (aIt
== rInserted
1681 || aIt
< rOldVisibleBegin
|| aIt
>= rOldVisibleEnd
)
1682 NotifyAccessibleEvent(
1683 css::accessibility::AccessibleEventId::
1686 css::uno::Any(getAccessibleChild(aIt
)));
1691 Document::changeParagraphText(::sal_uInt32 nNumber
, ::sal_uInt16 nBegin
, ::sal_uInt16 nEnd
,
1692 bool bCut
, bool bPaste
,
1693 OUString
const & rText
)
1695 m_rView
.SetSelection(::TextSelection(::TextPaM(nNumber
, nBegin
),
1696 ::TextPaM(nNumber
, nEnd
)));
1699 else if (nBegin
!= nEnd
)
1700 m_rView
.DeleteSelected();
1703 else if (!rText
.isEmpty())
1704 m_rView
.InsertText(rText
);
1707 void Document::handleParagraphNotifications()
1709 while (!m_aParagraphNotifications
.empty())
1711 ::TextHint
aHint(m_aParagraphNotifications
.front());
1712 m_aParagraphNotifications
.pop();
1713 switch (aHint
.GetId())
1715 case SfxHintId::TextParaInserted
:
1717 ::sal_uInt32 n
= static_cast< ::sal_uInt32
>( aHint
.GetValue() );
1718 assert(n
<= m_xParagraphs
->size() && "bad SfxHintId::TextParaInserted event");
1720 // Save the values of old iterators (the iterators themselves
1721 // will get invalidated), and adjust the old values so that they
1722 // reflect the insertion of the new paragraph:
1723 Paragraphs::size_type nOldVisibleBegin
1724 = m_aVisibleBegin
- m_xParagraphs
->begin();
1725 Paragraphs::size_type nOldVisibleEnd
1726 = m_aVisibleEnd
- m_xParagraphs
->begin();
1727 Paragraphs::size_type nOldFocused
1728 = m_aFocused
- m_xParagraphs
->begin();
1729 if (n
<= nOldVisibleBegin
)
1730 ++nOldVisibleBegin
; // XXX numeric overflow
1731 if (n
<= nOldVisibleEnd
)
1732 ++nOldVisibleEnd
; // XXX numeric overflow
1733 if (n
<= nOldFocused
)
1734 ++nOldFocused
; // XXX numeric overflow
1735 if (sal::static_int_cast
<sal_Int32
>(n
) <= m_nSelectionFirstPara
)
1736 ++m_nSelectionFirstPara
; // XXX numeric overflow
1737 if (sal::static_int_cast
<sal_Int32
>(n
) <= m_nSelectionLastPara
)
1738 ++m_nSelectionLastPara
; // XXX numeric overflow
1740 Paragraphs::iterator
aIns(
1741 m_xParagraphs
->insert(
1742 m_xParagraphs
->begin() + n
,
1743 ParagraphInfo(static_cast< ::sal_Int32
>(
1744 m_rEngine
.GetTextHeight(n
)))));
1745 // XXX numeric overflow (2x)
1747 determineVisibleRange();
1748 m_aFocused
= m_xParagraphs
->begin() + nOldFocused
;
1750 for (Paragraphs::iterator
aIt(aIns
);;)
1753 if (aIt
== m_xParagraphs
->end())
1755 ::rtl::Reference
< Paragraph
> xParagraph(
1757 if (xParagraph
.is())
1758 xParagraph
->numberChanged(true);
1761 notifyVisibleRangeChanges(
1762 m_xParagraphs
->begin() + nOldVisibleBegin
,
1763 m_xParagraphs
->begin() + nOldVisibleEnd
, aIns
);
1766 case SfxHintId::TextParaRemoved
:
1768 ::sal_uInt32 n
= static_cast< ::sal_uInt32
>( aHint
.GetValue() );
1769 if (n
== TEXT_PARA_ALL
)
1771 for (Paragraphs::iterator
aIt(m_aVisibleBegin
);
1772 aIt
!= m_aVisibleEnd
; ++aIt
)
1774 NotifyAccessibleEvent(
1775 css::accessibility::AccessibleEventId::
1777 css::uno::Any(getAccessibleChild(aIt
)),
1780 disposeParagraphs();
1781 m_xParagraphs
->clear();
1782 determineVisibleRange();
1783 m_nSelectionFirstPara
= -1;
1784 m_nSelectionFirstPos
= -1;
1785 m_nSelectionLastPara
= -1;
1786 m_nSelectionLastPos
= -1;
1787 m_aFocused
= m_xParagraphs
->end();
1791 assert(n
< m_xParagraphs
->size() && "Bad SfxHintId::TextParaRemoved event");
1793 Paragraphs::iterator
aIt(m_xParagraphs
->begin() + n
);
1794 // numeric overflow cannot occur
1796 // Save the values of old iterators (the iterators
1797 // themselves will get invalidated), and adjust the old
1798 // values so that they reflect the removal of the paragraph:
1799 Paragraphs::size_type nOldVisibleBegin
1800 = m_aVisibleBegin
- m_xParagraphs
->begin();
1801 Paragraphs::size_type nOldVisibleEnd
1802 = m_aVisibleEnd
- m_xParagraphs
->begin();
1804 = nOldVisibleBegin
<= n
&& n
< nOldVisibleEnd
;
1805 Paragraphs::size_type nOldFocused
1806 = m_aFocused
- m_xParagraphs
->begin();
1807 bool bWasFocused
= aIt
== m_aFocused
;
1808 if (n
< nOldVisibleBegin
)
1810 if (n
< nOldVisibleEnd
)
1812 if (n
< nOldFocused
)
1814 if (sal::static_int_cast
<sal_Int32
>(n
) < m_nSelectionFirstPara
)
1815 --m_nSelectionFirstPara
;
1816 else if (sal::static_int_cast
<sal_Int32
>(n
) == m_nSelectionFirstPara
)
1818 if (m_nSelectionFirstPara
== m_nSelectionLastPara
)
1820 m_nSelectionFirstPara
= -1;
1821 m_nSelectionFirstPos
= -1;
1822 m_nSelectionLastPara
= -1;
1823 m_nSelectionLastPos
= -1;
1827 ++m_nSelectionFirstPara
;
1828 m_nSelectionFirstPos
= 0;
1831 if (sal::static_int_cast
<sal_Int32
>(n
) < m_nSelectionLastPara
)
1832 --m_nSelectionLastPara
;
1833 else if (sal::static_int_cast
<sal_Int32
>(n
) == m_nSelectionLastPara
)
1835 assert(m_nSelectionFirstPara
< m_nSelectionLastPara
&& "logic error");
1836 --m_nSelectionLastPara
;
1837 m_nSelectionLastPos
= 0x7FFFFFFF;
1840 css::uno::Reference
< css::accessibility::XAccessible
>
1843 xStrong
= getAccessibleChild(aIt
);
1844 css::uno::WeakReference
<
1845 css::accessibility::XAccessible
> xWeak(
1846 aIt
->getParagraph());
1847 aIt
= m_xParagraphs
->erase(aIt
);
1849 determineVisibleRange();
1850 m_aFocused
= bWasFocused
? m_xParagraphs
->end()
1851 : m_xParagraphs
->begin() + nOldFocused
;
1853 for (; aIt
!= m_xParagraphs
->end(); ++aIt
)
1855 ::rtl::Reference
< Paragraph
> xParagraph(
1857 if (xParagraph
.is())
1858 xParagraph
->numberChanged(false);
1862 NotifyAccessibleEvent(
1863 css::accessibility::AccessibleEventId::
1865 css::uno::Any(xStrong
),
1868 css::uno::Reference
< css::lang::XComponent
> xComponent(
1869 xWeak
.get(), css::uno::UNO_QUERY
);
1870 if (xComponent
.is())
1871 xComponent
->dispose();
1873 notifyVisibleRangeChanges(
1874 m_xParagraphs
->begin() + nOldVisibleBegin
,
1875 m_xParagraphs
->begin() + nOldVisibleEnd
,
1876 m_xParagraphs
->end());
1880 case SfxHintId::TextFormatPara
:
1882 ::sal_uInt32 n
= static_cast< ::sal_uInt32
>( aHint
.GetValue() );
1883 assert(n
< m_xParagraphs
->size() && "Bad SfxHintId::TextFormatPara event");
1885 (*m_xParagraphs
)[static_cast< Paragraphs::size_type
>(n
)].
1886 changeHeight(static_cast< ::sal_Int32
>(
1887 m_rEngine
.GetTextHeight(n
)));
1888 // XXX numeric overflow
1889 Paragraphs::iterator
aOldVisibleBegin(m_aVisibleBegin
);
1890 Paragraphs::iterator
aOldVisibleEnd(m_aVisibleEnd
);
1891 determineVisibleRange();
1892 notifyVisibleRangeChanges(aOldVisibleBegin
, aOldVisibleEnd
,
1893 m_xParagraphs
->end());
1895 if (n
< m_xParagraphs
->size())
1897 Paragraphs::iterator
aIt(m_xParagraphs
->begin() + n
);
1898 ::rtl::Reference
< Paragraph
> xParagraph(getParagraph(aIt
));
1899 if (xParagraph
.is())
1900 xParagraph
->textChanged();
1905 SAL_WARN("accessibility", "bad buffered hint");
1909 if (m_bSelectionChangedNotification
)
1911 m_bSelectionChangedNotification
= false;
1912 handleSelectionChangeNotification();
1919 enum class SelChangeType
1921 None
, // no change, or invalid
1922 CaretMove
, // neither old nor new have selection, and they are different
1923 NoSelToSel
, // old has no selection but new has selection
1924 SelToNoSel
, // old has selection but new has no selection
1925 // both old and new have selections
1926 NoParaChange
, // only end index changed inside end para
1927 EndParaNoMoreBehind
, // end para was behind start, but now is same or ahead
1928 AddedFollowingPara
, // selection extended to following paragraph(s)
1929 ExcludedPreviousPara
, // selection shrunk excluding previous paragraph(s)
1930 ExcludedFollowingPara
, // selection shrunk excluding following paragraph(s)
1931 AddedPreviousPara
, // selection extended to previous paragraph(s)
1932 EndParaBecameBehind
// end para was ahead of start, but now is behind
1935 SelChangeType
getSelChangeType(const TextPaM
& Os
, const TextPaM
& Oe
,
1936 const TextPaM
& Ns
, const TextPaM
& Ne
)
1938 if (Os
== Oe
) // no old selection
1940 if (Ns
== Ne
) // no new selection: only caret moves
1941 return Os
!= Ns
? SelChangeType::CaretMove
: SelChangeType::None
;
1942 else // old has no selection but new has selection
1943 return SelChangeType::NoSelToSel
;
1945 else if (Ns
== Ne
) // old has selection; no new selection
1947 return SelChangeType::SelToNoSel
;
1949 else if (Os
== Ns
) // both old and new have selections, and their starts are same
1951 const sal_Int32 Osp
= Os
.GetPara(), Oep
= Oe
.GetPara();
1952 const sal_Int32 Nsp
= Ns
.GetPara(), Nep
= Ne
.GetPara();
1953 if (Oep
== Nep
) // end of selection stays in the same paragraph
1955 //Send text_selection_change event on Nep
1956 return Oe
.GetIndex() != Ne
.GetIndex() ? SelChangeType::NoParaChange
1957 : SelChangeType::None
;
1959 else if (Oep
< Nep
) // end of selection moved to a following paragraph
1961 //all the following examples like 1,2->1,3 means that old start select para is 1, old end select para is 2,
1962 // then press shift up, the new start select para is 1, new end select para is 3;
1963 //for example, 1, 2 -> 1, 3; 4,1 -> 4, 7; 4,1 -> 4, 2; 4,4->4,5
1964 if (Nep
>= Nsp
) // new end para not behind start
1966 // 1, 2 -> 1, 3; 4, 1 -> 4, 7; 4,4->4,5;
1967 if (Oep
< Osp
) // old end was behind start
1969 // 4,1 -> 4,7; 4,1 -> 4,4
1970 return SelChangeType::EndParaNoMoreBehind
;
1972 else // old end para wasn't behind start
1974 // 1, 2 -> 1, 3; 4,4->4,5;
1975 return SelChangeType::AddedFollowingPara
;
1978 else // new end para is still behind start
1981 return SelChangeType::ExcludedPreviousPara
;
1984 else // Oep > Nep => end of selection moved to a previous paragraph
1986 // 3,2 -> 3,1; 4,7 -> 4,1; 4, 7 -> 4,6; 4,4 -> 4,3
1987 if (Nep
>= Nsp
) // new end para is still not behind of start
1990 return SelChangeType::ExcludedFollowingPara
;
1992 else // new end para is behind start
1994 // 3,2 -> 3,1, 4,7 -> 4,1; 4,4->4,3
1995 if (Oep
<= Osp
) // it was not ahead already
1997 // 3,2 -> 3,1; 4,4->4,3
1998 return SelChangeType::AddedPreviousPara
;
2000 else // it was ahead previously
2003 return SelChangeType::EndParaBecameBehind
;
2008 return SelChangeType::None
;
2013 void Document::sendEvent(::sal_Int32 start
, ::sal_Int32 end
, ::sal_Int16 nEventId
)
2015 size_t nAvailDistance
= std::distance(m_xParagraphs
->begin(), m_aVisibleEnd
);
2017 Paragraphs::iterator
aEnd(m_xParagraphs
->begin());
2018 size_t nEndDistance
= std::min
<size_t>(end
+ 1, nAvailDistance
);
2019 std::advance(aEnd
, nEndDistance
);
2021 Paragraphs::iterator
aIt(m_xParagraphs
->begin());
2022 size_t nStartDistance
= std::min
<size_t>(start
, nAvailDistance
);
2023 std::advance(aIt
, nStartDistance
);
2027 ::rtl::Reference
< Paragraph
> xParagraph(getParagraph(aIt
));
2028 if (xParagraph
.is())
2029 xParagraph
->notifyEvent(
2031 css::uno::Any(), css::uno::Any());
2036 void Document::handleSelectionChangeNotification()
2038 ::TextSelection
const & rSelection
= m_rView
.GetSelection();
2039 assert(rSelection
.GetStart().GetPara() < m_xParagraphs
->size() &&
2040 rSelection
.GetEnd().GetPara() < m_xParagraphs
->size() &&
2041 "bad SfxHintId::TextViewSelectionChanged event");
2042 ::sal_Int32 nNewFirstPara
2043 = static_cast< ::sal_Int32
>(rSelection
.GetStart().GetPara());
2044 ::sal_Int32 nNewFirstPos
= rSelection
.GetStart().GetIndex();
2045 // XXX numeric overflow
2046 ::sal_Int32 nNewLastPara
2047 = static_cast< ::sal_Int32
>(rSelection
.GetEnd().GetPara());
2048 ::sal_Int32 nNewLastPos
= rSelection
.GetEnd().GetIndex();
2049 // XXX numeric overflow
2052 Paragraphs::iterator
aIt(m_xParagraphs
->begin() + nNewLastPara
);
2053 if (m_aFocused
!= m_xParagraphs
->end() && m_aFocused
!= aIt
2054 && m_aFocused
>= m_aVisibleBegin
&& m_aFocused
< m_aVisibleEnd
)
2056 ::rtl::Reference
< Paragraph
> xParagraph(getParagraph(m_aFocused
));
2057 if (xParagraph
.is())
2058 xParagraph
->notifyEvent(
2059 css::accessibility::AccessibleEventId::
2062 css::accessibility::AccessibleStateType::FOCUSED
),
2066 // Gain focus and update cursor position:
2067 if (aIt
>= m_aVisibleBegin
&& aIt
< m_aVisibleEnd
2068 && (aIt
!= m_aFocused
2069 || nNewLastPara
!= m_nSelectionLastPara
2070 || nNewLastPos
!= m_nSelectionLastPos
))
2072 ::rtl::Reference
< Paragraph
> xParagraph(getParagraph(aIt
));
2073 if (xParagraph
.is())
2075 //disable the first event when user types in empty field.
2076 sal_Int64 count
= getAccessibleChildCount();
2077 bool bEmpty
= count
> 1;
2078 //if (aIt != m_aFocused)
2079 if (aIt
!= m_aFocused
&& bEmpty
)
2080 xParagraph
->notifyEvent(
2081 css::accessibility::AccessibleEventId::
2085 css::accessibility::AccessibleStateType::FOCUSED
));
2086 if (nNewLastPara
!= m_nSelectionLastPara
2087 || nNewLastPos
!= m_nSelectionLastPos
)
2088 xParagraph
->notifyEvent(
2089 css::accessibility::AccessibleEventId::
2091 css::uno::Any( ::sal_Int32 (
2092 nNewLastPara
== m_nSelectionLastPara
2093 ? m_nSelectionLastPos
: 0)),
2094 css::uno::Any(nNewLastPos
));
2099 if (m_nSelectionFirstPara
!= -1)
2103 SelChangeType ret
= getSelChangeType(TextPaM(m_nSelectionFirstPara
, m_nSelectionFirstPos
),
2104 TextPaM(m_nSelectionLastPara
, m_nSelectionLastPos
),
2105 rSelection
.GetStart(), rSelection
.GetEnd());
2108 case SelChangeType::None
:
2111 case SelChangeType::CaretMove
:
2112 //only caret moved, already handled in above
2114 case SelChangeType::NoSelToSel
:
2115 //old has no selection but new has selection
2116 nMin
= std::min(nNewFirstPara
, nNewLastPara
);
2117 nMax
= std::max(nNewFirstPara
, nNewLastPara
);
2118 sendEvent(nMin
, nMax
, css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2119 sendEvent(nMin
, nMax
,
2120 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2122 case SelChangeType::SelToNoSel
:
2123 //old has selection but new has no selection.
2124 nMin
= std::min(m_nSelectionFirstPara
, m_nSelectionLastPara
);
2125 nMax
= std::max(m_nSelectionFirstPara
, m_nSelectionLastPara
);
2126 sendEvent(nMin
, nMax
, css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2127 sendEvent(nMin
, nMax
,
2128 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2130 case SelChangeType::NoParaChange
:
2131 //Send text_selection_change event on Nep
2132 sendEvent(nNewLastPara
, nNewLastPara
,
2133 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2135 case SelChangeType::EndParaNoMoreBehind
:
2136 // 4, 1 -> 4, 7; 4,1 -> 4,4
2137 sendEvent(m_nSelectionLastPara
, m_nSelectionFirstPara
- 1,
2138 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2139 sendEvent(nNewFirstPara
+ 1, nNewLastPara
,
2140 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2142 sendEvent(m_nSelectionLastPara
, nNewLastPara
,
2143 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2145 case SelChangeType::AddedFollowingPara
:
2146 // 1, 2 -> 1, 4; 4,4->4,5;
2147 sendEvent(m_nSelectionLastPara
+ 1, nNewLastPara
,
2148 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2150 sendEvent(m_nSelectionLastPara
, nNewLastPara
,
2151 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2153 case SelChangeType::ExcludedPreviousPara
:
2155 sendEvent(m_nSelectionLastPara
+ 1, nNewLastPara
,
2156 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2158 sendEvent(m_nSelectionLastPara
, nNewLastPara
,
2159 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2161 case SelChangeType::ExcludedFollowingPara
:
2163 sendEvent(nNewLastPara
+ 1, m_nSelectionLastPara
,
2164 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2166 sendEvent(nNewLastPara
, m_nSelectionLastPara
,
2167 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2169 case SelChangeType::AddedPreviousPara
:
2170 // 3,2 -> 3,1; 4,4->4,3
2171 sendEvent(nNewLastPara
, m_nSelectionLastPara
- 1,
2172 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2174 sendEvent(nNewLastPara
, m_nSelectionLastPara
,
2175 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2177 case SelChangeType::EndParaBecameBehind
:
2179 sendEvent(m_nSelectionFirstPara
+ 1, m_nSelectionLastPara
,
2180 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2181 sendEvent(nNewLastPara
, nNewFirstPara
- 1,
2182 css::accessibility::AccessibleEventId::SELECTION_CHANGED
);
2184 sendEvent(nNewLastPara
, m_nSelectionLastPara
,
2185 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED
);
2190 m_nSelectionFirstPara
= nNewFirstPara
;
2191 m_nSelectionFirstPos
= nNewFirstPos
;
2192 m_nSelectionLastPara
= nNewLastPara
;
2193 m_nSelectionLastPos
= nNewLastPos
;
2196 void Document::disposeParagraphs()
2198 for (auto const& paragraph
: *m_xParagraphs
)
2200 css::uno::Reference
< css::lang::XComponent
> xComponent(
2201 paragraph
.getParagraph().get(), css::uno::UNO_QUERY
);
2202 if (xComponent
.is())
2203 xComponent
->dispose();
2208 css::uno::Any
Document::mapFontColor(::Color
const & rColor
)
2210 return css::uno::Any(rColor
.GetRGBColor());
2211 // FIXME keep transparency?
2215 ::Color
Document::mapFontColor(css::uno::Any
const & rColor
)
2223 css::uno::Any
Document::mapFontWeight(::FontWeight nWeight
)
2225 // Map from ::FontWeight to css::awt::FontWeight, depends on order of
2226 // elements in ::FontWeight (vcl/vclenum.hxx):
2227 static float const aWeight
[]
2228 = { css::awt::FontWeight::DONTKNOW
, // WEIGHT_DONTKNOW
2229 css::awt::FontWeight::THIN
, // WEIGHT_THIN
2230 css::awt::FontWeight::ULTRALIGHT
, // WEIGHT_ULTRALIGHT
2231 css::awt::FontWeight::LIGHT
, // WEIGHT_LIGHT
2232 css::awt::FontWeight::SEMILIGHT
, // WEIGHT_SEMILIGHT
2233 css::awt::FontWeight::NORMAL
, // WEIGHT_NORMAL
2234 css::awt::FontWeight::NORMAL
, // WEIGHT_MEDIUM
2235 css::awt::FontWeight::SEMIBOLD
, // WEIGHT_SEMIBOLD
2236 css::awt::FontWeight::BOLD
, // WEIGHT_BOLD
2237 css::awt::FontWeight::ULTRABOLD
, // WEIGHT_ULTRABOLD
2238 css::awt::FontWeight::BLACK
}; // WEIGHT_BLACK
2239 return css::uno::Any(aWeight
[nWeight
]);
2243 ::FontWeight
Document::mapFontWeight(css::uno::Any
const & rWeight
)
2245 float nWeight
= css::awt::FontWeight::NORMAL
;
2246 rWeight
>>= nWeight
;
2247 return nWeight
<= css::awt::FontWeight::DONTKNOW
? WEIGHT_DONTKNOW
2248 : nWeight
<= css::awt::FontWeight::THIN
? WEIGHT_THIN
2249 : nWeight
<= css::awt::FontWeight::ULTRALIGHT
? WEIGHT_ULTRALIGHT
2250 : nWeight
<= css::awt::FontWeight::LIGHT
? WEIGHT_LIGHT
2251 : nWeight
<= css::awt::FontWeight::SEMILIGHT
? WEIGHT_SEMILIGHT
2252 : nWeight
<= css::awt::FontWeight::NORMAL
? WEIGHT_NORMAL
2253 : nWeight
<= css::awt::FontWeight::SEMIBOLD
? WEIGHT_SEMIBOLD
2254 : nWeight
<= css::awt::FontWeight::BOLD
? WEIGHT_BOLD
2255 : nWeight
<= css::awt::FontWeight::ULTRABOLD
? WEIGHT_ULTRABOLD
2261 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */