LibreOffice Module accessibility (master) 1
textwindowaccessibility.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <sal/config.h>
21#include <sal/log.hxx>
22
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>
36#include <utility>
37#include <vcl/svapp.hxx>
38#include <vcl/txtattr.hxx>
39#include <vcl/window.hxx>
43
44#include <algorithm>
45#include <memory>
46#include <numeric>
47#include <vector>
48
49namespace accessibility
50{
52{
53 assert(m_pNotifier == nullptr && "called more than once");
54 m_pNotifier = &rNotifier;
55 m_rListener.StartListening(*m_pNotifier, DuplicateHandling::Prevent);
56}
57
59{
60 if (m_pNotifier != nullptr)
61 {
63 m_pNotifier = nullptr;
64 }
65}
66
68{
69 assert(m_pNotifier == nullptr && "called more than once");
70 m_pNotifier = &rNotifier;
71 m_pNotifier->AddEventListener(m_aListener);
72}
73
75{
76 if (m_pNotifier)
77 {
78 m_pNotifier->RemoveEventListener(m_aListener);
79 m_pNotifier = nullptr;
80 }
81}
82
84 Paragraphs::size_type nNumber):
86 m_xDocument(std::move(xDocument)),
87 m_nNumber(nNumber),
88 m_nClientId(0)
89{
90 m_aParagraphText = m_xDocument->retrieveParagraphText(this);
91}
92
93void
94Paragraph::numberChanged(bool bIncremented)
95{
96 if (bIncremented)
97 ++m_nNumber;
98 else
99 --m_nNumber;
100}
101
103{
104 OUString aParagraphText = implGetText();
105 css::uno::Any aOldValue, aNewValue;
106 if ( implInitTextChangedEvent( m_aParagraphText, aParagraphText, aOldValue, aNewValue ) )
107 {
108 m_aParagraphText = aParagraphText;
109 notifyEvent(css::accessibility::AccessibleEventId::
110 TEXT_CHANGED,
111 aOldValue, aNewValue);
112 }
113}
114
115void Paragraph::notifyEvent(::sal_Int16 nEventId,
116 css::uno::Any const & rOldValue,
117 css::uno::Any const & rNewValue)
118{
119 if (m_nClientId)
120 comphelper::AccessibleEventNotifier::addEvent( m_nClientId, css::accessibility::AccessibleEventObject(
121 getXWeak(),
122 nEventId, rNewValue, rOldValue, -1) );
123}
124
125// virtual
126css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL
128{
130 return this;
131}
132
133// virtual
135{
137 return 0;
138}
139
140// virtual
141css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
143{
145 throw css::lang::IndexOutOfBoundsException(
146 "textwindowaccessibility.cxx:"
147 " Paragraph::getAccessibleChild",
148 getXWeak());
149}
150
151// virtual
152css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
154{
156 return m_xDocument->getAccessible();
157}
158
159// virtual
161{
163 return m_xDocument->retrieveParagraphIndex(this);
164}
165
166// virtual
167::sal_Int16 SAL_CALL Paragraph::getAccessibleRole()
168{
170 return css::accessibility::AccessibleRole::PARAGRAPH;
171}
172
173// virtual
175{
177 return OUString();
178}
179
180// virtual
182{
184 return OUString();
185}
186
187// virtual
188css::uno::Reference< css::accessibility::XAccessibleRelationSet >
190{
192 return m_xDocument->retrieveParagraphRelationSet( this );
193}
194
195// virtual
197{
199
200 // FIXME Notification of changes (STATE_CHANGED) missing when
201 // m_rView.IsReadOnly() changes:
202 return m_xDocument->retrieveParagraphState(this);
203}
204
205// virtual
206css::lang::Locale SAL_CALL Paragraph::getLocale()
207{
209 return m_xDocument->retrieveLocale();
210}
211
212// virtual
213sal_Bool SAL_CALL Paragraph::containsPoint(css::awt::Point const & rPoint)
214{
216 css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this,
217 false));
218 return rPoint.X >= 0 && rPoint.X < aRect.Width
219 && rPoint.Y >= 0 && rPoint.Y < aRect.Height;
220}
221
222// virtual
223css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
224Paragraph::getAccessibleAtPoint(css::awt::Point const &)
225{
227 return nullptr;
228}
229
230// virtual
231css::awt::Rectangle SAL_CALL Paragraph::getBounds()
232{
234 return m_xDocument->retrieveParagraphBounds(this, false);
235}
236
237// virtual
238css::awt::Point SAL_CALL Paragraph::getLocation()
239{
241 css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this,
242 false));
243 return css::awt::Point(aRect.X, aRect.Y);
244}
245
246// virtual
247css::awt::Point SAL_CALL Paragraph::getLocationOnScreen()
248{
250 css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this,
251 true));
252 return css::awt::Point(aRect.X, aRect.Y);
253}
254
255// virtual
256css::awt::Size SAL_CALL Paragraph::getSize()
257{
259 css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this,
260 false));
261 return css::awt::Size(aRect.Width, aRect.Height);
262}
263
264// virtual
265void SAL_CALL Paragraph::grabFocus()
266{
268 VclPtr<vcl::Window> pWindow = m_xDocument->GetWindow();
269 if ( pWindow )
270 {
271 pWindow->GrabFocus();
272 }
273 try
274 {
275 m_xDocument->changeParagraphSelection(this, 0, 0);
276 }
277 catch (const css::lang::IndexOutOfBoundsException &)
278 {
279 TOOLS_INFO_EXCEPTION("accessibility", "Paragraph::grabFocus: caught unexpected");
280 }
281}
282
283// virtual
284sal_Int32 SAL_CALL Paragraph::getForeground()
285{
286 return 0; // TODO
287}
288
289// virtual
290sal_Int32 SAL_CALL Paragraph::getBackground()
291{
292 return 0; // TODO
293}
294
295// virtual
296::sal_Int32 SAL_CALL Paragraph::getCaretPosition()
297{
299 return m_xDocument->retrieveParagraphCaretPosition(this);
300}
301
302// virtual
303sal_Bool SAL_CALL Paragraph::setCaretPosition(::sal_Int32 nIndex)
304{
306 m_xDocument->changeParagraphSelection(this, nIndex, nIndex);
307 return true;
308}
309
310// virtual
311::sal_Unicode SAL_CALL Paragraph::getCharacter(::sal_Int32 nIndex)
312{
315}
316
317// virtual
318css::uno::Sequence< css::beans::PropertyValue > SAL_CALL
319Paragraph::getCharacterAttributes(::sal_Int32 nIndex, const css::uno::Sequence< OUString >& aRequestedAttributes)
320{
322 return m_xDocument->retrieveCharacterAttributes( this, nIndex, aRequestedAttributes );
323}
324
325// virtual
326css::awt::Rectangle SAL_CALL
328{
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;
334 return aBounds;
335}
336
337// virtual
338::sal_Int32 SAL_CALL Paragraph::getCharacterCount()
339{
341 return implGetText().getLength();
342}
343
344// virtual
345::sal_Int32 SAL_CALL
346Paragraph::getIndexAtPoint(css::awt::Point const & rPoint)
347{
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);
354}
355
356// virtual
357OUString SAL_CALL Paragraph::getSelectedText()
358{
360
362}
363
364// virtual
365::sal_Int32 SAL_CALL Paragraph::getSelectionStart()
366{
369}
370
371// virtual
372::sal_Int32 SAL_CALL Paragraph::getSelectionEnd()
373{
376}
377
378// virtual
379sal_Bool SAL_CALL Paragraph::setSelection(::sal_Int32 nStartIndex,
380 ::sal_Int32 nEndIndex)
381{
383 m_xDocument->changeParagraphSelection(this, nStartIndex, nEndIndex);
384 return true;
385}
386
387// virtual
388OUString SAL_CALL Paragraph::getText()
389{
391 return implGetText();
392}
393
394// virtual
395OUString SAL_CALL Paragraph::getTextRange(::sal_Int32 nStartIndex,
396 ::sal_Int32 nEndIndex)
397{
399 return OCommonAccessibleText::implGetTextRange(implGetText(), nStartIndex, nEndIndex);
400}
401
402// virtual
403css::accessibility::TextSegment SAL_CALL Paragraph::getTextAtIndex( sal_Int32 nIndex, sal_Int16 aTextType )
404{
407}
408
409// virtual
410css::accessibility::TextSegment SAL_CALL Paragraph::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 aTextType )
411{
414}
415
416// virtual
417css::accessibility::TextSegment SAL_CALL Paragraph::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 aTextType )
418{
421}
422
423// virtual
424sal_Bool SAL_CALL Paragraph::copyText(::sal_Int32 nStartIndex,
425 ::sal_Int32 nEndIndex)
426{
428 m_xDocument->copyParagraphText(this, nStartIndex, nEndIndex);
429 return true;
430}
431
432// virtual
433sal_Bool SAL_CALL Paragraph::scrollSubstringTo( sal_Int32, sal_Int32, css::accessibility::AccessibleScrollType )
434{
435 return false;
436}
437
438// virtual
439sal_Bool SAL_CALL Paragraph::cutText(::sal_Int32 nStartIndex,
440 ::sal_Int32 nEndIndex)
441{
443 m_xDocument->changeParagraphText(this, nStartIndex, nEndIndex, true, false,
444 OUString());
445 return true;
446}
447
448// virtual
449sal_Bool SAL_CALL Paragraph::pasteText(::sal_Int32 nIndex)
450{
452 m_xDocument->changeParagraphText(this, nIndex, nIndex, false, true,
453 OUString());
454 return true;
455}
456
457// virtual
458sal_Bool SAL_CALL Paragraph::deleteText(::sal_Int32 nStartIndex,
459 ::sal_Int32 nEndIndex)
460{
462 m_xDocument->changeParagraphText(this, nStartIndex, nEndIndex, false, false,
463 OUString());
464 return true;
465}
466
467// virtual
468sal_Bool SAL_CALL Paragraph::insertText(OUString const & rText,
469 ::sal_Int32 nIndex)
470{
472 m_xDocument->changeParagraphText(this, nIndex, nIndex, false, false, rText);
473 return true;
474}
475
476// virtual
477sal_Bool SAL_CALL
478Paragraph::replaceText(::sal_Int32 nStartIndex, ::sal_Int32 nEndIndex,
479 OUString const & rReplacement)
480{
482 m_xDocument->changeParagraphText(this, nStartIndex, nEndIndex, false, false,
483 rReplacement);
484 return true;
485}
486
487// virtual
489 ::sal_Int32 nStartIndex, ::sal_Int32 nEndIndex,
490 css::uno::Sequence< css::beans::PropertyValue > const & rAttributeSet)
491{
493 m_xDocument->changeParagraphAttributes(this, nStartIndex, nEndIndex,
494 rAttributeSet);
495 return true;
496}
497
498// virtual
499sal_Bool SAL_CALL Paragraph::setText(OUString const & rText)
500{
502 m_xDocument->changeParagraphText(this, rText);
503 return true;
504}
505
506// virtual
507css::uno::Sequence< css::beans::PropertyValue > SAL_CALL
508Paragraph::getDefaultAttributes(const css::uno::Sequence< OUString >&)
509{
511 return {}; // default attributes are not supported by text engine
512}
513
514// virtual
515css::uno::Sequence< css::beans::PropertyValue > SAL_CALL
516Paragraph::getRunAttributes(::sal_Int32 Index, const css::uno::Sequence< OUString >& RequestedAttributes)
517{
519 return m_xDocument->retrieveRunAttributes( this, Index, RequestedAttributes );
520}
521
522// virtual
523::sal_Int32 SAL_CALL Paragraph::getLineNumberAtIndex( ::sal_Int32 nIndex )
524{
526
527 ::sal_Int32 nLineNo = -1;
528 m_xDocument->retrieveParagraphLineBoundary( this, nIndex, &nLineNo );
529
530 return nLineNo;
531}
532
533// virtual
534css::accessibility::TextSegment SAL_CALL Paragraph::getTextAtLineNumber( ::sal_Int32 nLineNo )
535{
537
538 css::i18n::Boundary aBoundary =
539 m_xDocument->retrieveParagraphBoundaryOfLine( this, nLineNo );
540
541 return css::accessibility::TextSegment( getTextRange(aBoundary.startPos, aBoundary.endPos),
542 aBoundary.startPos, aBoundary.endPos);
543}
544
545// virtual
546css::accessibility::TextSegment SAL_CALL Paragraph::getTextAtLineWithCaret( )
547{
549
550 sal_Int32 nLineNo = getNumberOfLineWithCaret();
551
552 try {
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",
561 getXWeak(), anyEx );
562 }
563}
564
565// virtual
567{
569 return m_xDocument->retrieveParagraphLineWithCursor(this);
570}
571
572
573// virtual
575 css::uno::Reference<
576 css::accessibility::XAccessibleEventListener > const & rListener)
577{
578 if (!rListener.is())
579 return;
580
581 ::osl::ClearableMutexGuard aGuard(rBHelper.rMutex);
582 if (rBHelper.bDisposed || rBHelper.bInDispose)
583 {
584 aGuard.clear();
585 rListener->disposing(css::lang::EventObject(
586 getXWeak()));
587 }
588 else
589 {
590 if (!m_nClientId)
593 }
594}
595
596// virtual
598 css::uno::Reference<
599 css::accessibility::XAccessibleEventListener > const & rListener)
600{
602 {
603 osl::MutexGuard aGuard(rBHelper.rMutex);
604 if (rListener.is() && m_nClientId != 0
606 {
608 m_nClientId = 0;
609 }
610 }
611 if (nId != 0)
612 {
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
618 }
619}
620
621// virtual
622void SAL_CALL Paragraph::disposing()
623{
625 {
626 osl::MutexGuard aGuard(rBHelper.rMutex);
628 m_nClientId = 0;
629 }
630 if (nId != 0)
632}
633
634// virtual
636{
637 return m_xDocument->retrieveParagraphText(this);
638}
639
640// virtual
641css::lang::Locale Paragraph::implGetLocale()
642{
643 return m_xDocument->retrieveLocale();
644}
645
646// virtual
647void Paragraph::implGetSelection(::sal_Int32 & rStartIndex,
648 ::sal_Int32 & rEndIndex)
649{
650 m_xDocument->retrieveParagraphSelection(this, &rStartIndex, &rEndIndex);
651}
652
653// virtual
654void Paragraph::implGetParagraphBoundary( const OUString& rText,
655 css::i18n::Boundary& rBoundary,
656 ::sal_Int32 nIndex )
657{
658 ::sal_Int32 nLength = rText.getLength();
659
661 {
662 rBoundary.startPos = 0;
663 rBoundary.endPos = nLength;
664 }
665 else
666 {
667 rBoundary.startPos = nIndex;
668 rBoundary.endPos = nIndex;
669 }
670}
671
672// virtual
673void Paragraph::implGetLineBoundary( const OUString& rText,
674 css::i18n::Boundary& rBoundary,
675 ::sal_Int32 nIndex )
676{
677 ::sal_Int32 nLength = rText.getLength();
678
680 {
681 css::i18n::Boundary aBoundary =
682 m_xDocument->retrieveParagraphLineBoundary( this, nIndex, nullptr );
683 rBoundary.startPos = aBoundary.startPos;
684 rBoundary.endPos = aBoundary.endPos;
685 }
686 else
687 {
688 rBoundary.startPos = nIndex;
689 rBoundary.endPos = nIndex;
690 }
691}
692
693
695{
696 ::osl::MutexGuard aGuard(rBHelper.rMutex);
697 if (!(rBHelper.bDisposed || rBHelper.bInDispose))
698 return;
699 throw css::lang::DisposedException(
700 OUString(), getXWeak());
701}
702
704 ::TextView & rView):
705 VCLXAccessibleComponent(pVclXWindow),
706 m_xAccessible(pVclXWindow),
707 m_rEngine(rEngine),
708 m_rView(rView),
709 m_aEngineListener(*this),
710 m_aViewListener(LINK(this, Document, WindowEventHandler)),
711 m_nViewOffset(0),
712 m_nViewHeight(0),
713 m_nVisibleBeginOffset(0),
714 m_nSelectionFirstPara(-1),
715 m_nSelectionFirstPos(-1),
716 m_nSelectionLastPara(-1),
717 m_nSelectionLastPos(-1),
718 m_bSelectionChangedNotification(false)
719{}
720
721css::lang::Locale Document::retrieveLocale()
722{
723 SolarMutexGuard aGuard;
724 return m_rEngine.GetLocale();
725}
726
727::sal_Int32 Document::retrieveParagraphIndex(Paragraph const * pParagraph)
728{
729 ::osl::MutexGuard aInternalGuard(GetMutex());
730
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
739}
740
741::sal_Int64 Document::retrieveParagraphState(Paragraph const * pParagraph)
742{
743 ::osl::MutexGuard aInternalGuard(GetMutex());
744
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:
748 ::sal_Int64 nState
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)
758 {
759 nState
760 |= css::accessibility::AccessibleStateType::VISIBLE
761 | css::accessibility::AccessibleStateType::SHOWING;
762 if (aPara == m_aFocused)
763 nState |= css::accessibility::AccessibleStateType::FOCUSED;
764 }
765 return nState;
766};
767
768css::awt::Rectangle
770 bool bAbsolute)
771{
772 SolarMutexGuard aGuard;
773 ::osl::MutexGuard aInternalGuard(GetMutex());
774
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(); };
784 ::sal_Int32 nPos;
785 if (aPara < m_aVisibleBegin)
786 nPos = std::accumulate(m_xParagraphs->begin(), aPara, sal_Int32(0), lAddHeight);
787 else
788 nPos = std::accumulate(m_aVisibleBegin, aPara, m_nViewOffset - m_nVisibleBeginOffset, lAddHeight);
789
790 Point aOrig(0, 0);
791 if (bAbsolute)
793
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)
799}
800
801OUString
803{
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
808}
809
811 ::sal_Int32 * pBegin,
812 ::sal_Int32 * pEnd)
813{
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 ) );
822
823 if ( nNumber >= aMinPaM.GetPara() && nNumber <= aMaxPaM.GetPara() )
824 {
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)
831
832 if ( aStartPaM > aEndPaM )
833 std::swap( *pBegin, *pEnd );
834 }
835 else
836 {
837 *pBegin = 0;
838 *pEnd = 0;
839 }
840}
841
843{
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() );
849
850 return aEndPaM.GetPara() == nNumber ? aEndPaM.GetIndex() : -1;
851}
852
853css::awt::Rectangle
855 ::sal_Int32 nIndex)
856{
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",
866 getXWeak());
867 css::awt::Rectangle aBounds( 0, 0, 0, 0 );
868 if ( nIndex == nLength )
869 {
870 aBounds = AWTRectangle(
872 }
873 else
874 {
875 ::tools::Rectangle aLeft(
877 // XXX numeric overflow
878 ::tools::Rectangle aRight(
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()
888 - aLeft.Left());
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),
892 nWidth,
893 static_cast< ::sal_Int32 >(aLeft.Bottom()
894 - aLeft.Top()));
895 // XXX numeric overflow (4x)
896 }
897 return aBounds;
898}
899
900::sal_Int32 Document::retrieveCharacterIndex(Paragraph const * pParagraph,
901 css::awt::Point const & rPoint)
902{
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
912}
913
914css::uno::Sequence< css::beans::PropertyValue >
916 Paragraph const * pParagraph, ::sal_Int32 nIndex,
917 const css::uno::Sequence< OUString >& aRequestedAttributes)
918{
919 SolarMutexGuard aGuard;
920
921 vcl::Font aFont = m_rEngine.GetFont();
922 const sal_Int32 AttributeCount = 9;
923 std::vector< css::beans::PropertyValue > aAttribs;
924 aAttribs.reserve(AttributeCount);
925
926 css::beans::PropertyValue aAttrib;
927 aAttrib.Handle = -1;
928 aAttrib.State = css::beans::PropertyState_DIRECT_VALUE;
929
930 //character background color
931 aAttrib.Name = "CharBackColor";
932 aAttrib.Value = mapFontColor( aFont.GetFillColor() );
933 aAttribs.push_back(aAttrib);
934
935 //character color
936 aAttrib.Name = "CharColor";
937 //aAttrib.Value = mapFontColor( aFont.GetColor() );
938 aAttrib.Value = mapFontColor( m_rEngine.GetTextColor() );
939 aAttribs.push_back(aAttrib);
940
941 //character font name
942 aAttrib.Name = "CharFontName";
943 aAttrib.Value <<= aFont.GetFamilyName();
944 aAttribs.push_back(aAttrib);
945
946 //character height
947 aAttrib.Name = "CharHeight";
948 aAttrib.Value <<= static_cast<sal_Int16>(aFont.GetFontHeight());
949 aAttribs.push_back(aAttrib);
950
951 //character posture
952 aAttrib.Name = "CharPosture";
953 aAttrib.Value <<= static_cast<sal_Int16>(aFont.GetItalic());
954 aAttribs.push_back(aAttrib);
955
956 //character relief
957 /*
958 aAttrib.Name = "CharRelief";
959 aAttrib.Value = css::uno::Any( (sal_Int16)aFont.GetRelief() );
960 aAttribs.push_back(aAttrib);
961 */
962
963 //character strikeout
964 aAttrib.Name = "CharStrikeout";
965 aAttrib.Value <<= static_cast<sal_Int16>(aFont.GetStrikeout());
966 aAttribs.push_back(aAttrib);
967
968 //character underline
969 aAttrib.Name = "CharUnderline";
970 aAttrib.Value <<= static_cast<sal_Int16>(aFont.GetUnderline());
971 aAttribs.push_back(aAttrib);
972
973 //character weight
974 aAttrib.Name = "CharWeight";
975 aAttrib.Value <<= static_cast<float>(aFont.GetWeight());
976 aAttribs.push_back(aAttrib);
977
978 //character alignment
979 aAttrib.Name = "ParaAdjust";
980 aAttrib.Value <<= static_cast<sal_Int16>(m_rEngine.GetTextAlign());
981 aAttribs.push_back(aAttrib);
982
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",
991 getXWeak());
992
993
994 // retrieve run attributes
995 tPropValMap aCharAttrSeq;
996 retrieveRunAttributesImpl( pParagraph, nIndex, aRequestedAttributes, aCharAttrSeq );
997
998 for (const css::beans::PropertyValue& rAttrib : aAttribs)
999 {
1000 aCharAttrSeq[ rAttrib.Name ] = rAttrib;
1001 }
1002
1003 const css::uno::Sequence< css::beans::PropertyValue > aRes = comphelper::mapValuesToSequence( aCharAttrSeq );
1004
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; });
1011
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]; });
1017
1018 return comphelper::containerToSequence(aNewValues);
1019}
1020
1022 Paragraph const * pParagraph, ::sal_Int32 Index,
1023 const css::uno::Sequence< OUString >& RequestedAttributes,
1024 tPropValMap& rRunAttrSeq)
1025{
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 * >(
1032 ::TextAttribFontWeight const * pWeight
1033 = static_cast< ::TextAttribFontWeight const * >(
1035 tPropValMap aRunAttrSeq;
1036 if ( pColor )
1037 {
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;
1044 }
1045 if ( pWeight )
1046 {
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;
1053 }
1054 if ( !RequestedAttributes.hasElements() )
1055 {
1056 rRunAttrSeq = aRunAttrSeq;
1057 }
1058 else
1059 {
1060 for ( const OUString& rReqAttr : RequestedAttributes )
1061 {
1062 tPropValMap::iterator aIter = aRunAttrSeq.find( rReqAttr );
1063 if ( aIter != aRunAttrSeq.end() )
1064 {
1065 rRunAttrSeq[ (*aIter).first ] = (*aIter).second;
1066 }
1067 }
1068 }
1069}
1070
1071css::uno::Sequence< css::beans::PropertyValue >
1073 Paragraph const * pParagraph, ::sal_Int32 Index,
1074 const css::uno::Sequence< OUString >& RequestedAttributes)
1075{
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",
1084 getXWeak() );
1085
1086 tPropValMap aRunAttrSeq;
1087 retrieveRunAttributesImpl( pParagraph, Index, RequestedAttributes, aRunAttrSeq );
1088 return comphelper::mapValuesToSequence( aRunAttrSeq );
1089}
1090
1092 OUString const & rText)
1093{
1094 SolarMutexGuard aGuard;
1095 {
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,
1100 false, rText);
1101 }
1102}
1103
1105 ::sal_Int32 nBegin, ::sal_Int32 nEnd,
1106 bool bCut, bool bPaste,
1107 OUString const & rText)
1108{
1109 SolarMutexGuard aGuard;
1110 {
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",
1119 getXWeak());
1120 changeParagraphText(nNumber, static_cast< ::sal_uInt16 >(nBegin),
1121 static_cast< ::sal_uInt16 >(nEnd), bCut, bPaste, rText);
1122 // XXX numeric overflow (2x)
1123 }
1124}
1125
1127 ::sal_Int32 nBegin, ::sal_Int32 nEnd)
1128{
1129 SolarMutexGuard aGuard;
1130 {
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",
1139 getXWeak());
1141 ::TextSelection(::TextPaM(nNumber, nBegin),
1142 ::TextPaM(nNumber, nEnd)));
1143 // XXX numeric overflow (2x)
1144 m_rView.Copy();
1145 }
1146}
1147
1149 Paragraph const * pParagraph, ::sal_Int32 nBegin, ::sal_Int32 nEnd,
1150 css::uno::Sequence< css::beans::PropertyValue > const & rAttributeSet)
1151{
1152 SolarMutexGuard aGuard;
1153 {
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",
1162 getXWeak());
1163
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" )
1170 mapFontColor(rAttr.Value)),
1171 nNumber, nBegin, nEnd);
1172 // XXX numeric overflow (2x)
1173 else if ( rAttr.Name == "CharWeight" )
1175 mapFontWeight(rAttr.Value)),
1176 nNumber, nBegin, nEnd);
1177 // XXX numeric overflow (2x)
1178 }
1179}
1180
1182 ::sal_Int32 nBegin, ::sal_Int32 nEnd)
1183{
1184 SolarMutexGuard aGuard;
1185 {
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",
1194 getXWeak());
1196 ::TextSelection(::TextPaM(nNumber, nBegin),
1197 ::TextPaM(nNumber, nEnd)));
1198 // XXX numeric overflow (2x)
1199 }
1200}
1201
1202css::i18n::Boundary
1204 ::sal_Int32 nIndex, ::sal_Int32 *pLineNo )
1205{
1206 css::i18n::Boundary aBoundary;
1207 aBoundary.startPos = nIndex;
1208 aBoundary.endPos = nIndex;
1209
1210 SolarMutexGuard aGuard;
1211 {
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",
1218 getXWeak() );
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 )
1223 {
1224 nLineStart = nLineEnd;
1225 nLineEnd += m_rEngine.GetLineLen( nNumber, nLine );
1226 if ( nIndex >= nLineStart && ( ( nLine == nLineCount - 1 ) ? nIndex <= nLineEnd : nIndex < nLineEnd ) )
1227 {
1228 aBoundary.startPos = nLineStart;
1229 aBoundary.endPos = nLineEnd;
1230 if( pLineNo )
1231 pLineNo[0] = nLine;
1232 break;
1233 }
1234 }
1235 }
1236
1237 return aBoundary;
1238}
1239
1240css::i18n::Boundary
1242 ::sal_Int32 nLineNo )
1243{
1244 css::i18n::Boundary aBoundary;
1245 aBoundary.startPos = 0;
1246 aBoundary.endPos = 0;
1247
1248 SolarMutexGuard aGuard;
1249 {
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",
1256 getXWeak() );
1257 ::sal_Int32 nLineStart = 0;
1258 ::sal_Int32 nLineEnd = 0;
1259 for ( ::sal_Int32 nLine = 0; nLine <= nLineNo; ++nLine )
1260 {
1261 nLineStart = nLineEnd;
1262 nLineEnd += m_rEngine.GetLineLen( nNumber, nLine );
1263 }
1264
1265 aBoundary.startPos = nLineStart;
1266 aBoundary.endPos = nLineEnd;
1267 }
1268
1269 return aBoundary;
1270}
1271
1273{
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() );
1279
1280 return aEndPaM.GetPara() == nNumber
1282}
1283
1284
1285css::uno::Reference< css::accessibility::XAccessibleRelationSet >
1287{
1288 ::osl::MutexGuard aInternalGuard( GetMutex() );
1289
1290 rtl::Reference<::utl::AccessibleRelationSetHelper> pRelationSetHelper = new ::utl::AccessibleRelationSetHelper();
1291
1292 Paragraphs::iterator aPara( m_xParagraphs->begin() + pParagraph->getNumber() );
1293
1294 if ( aPara > m_aVisibleBegin && aPara < m_aVisibleEnd )
1295 {
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 );
1299 }
1300
1301 if ( aPara >= m_aVisibleBegin && aPara < m_aVisibleEnd -1 )
1302 {
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 );
1306 }
1307
1308 return pRelationSetHelper;
1309}
1310
1311// virtual
1313{
1315 init();
1317}
1318
1319// virtual
1320css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
1322{
1324 init();
1325 if (i < 0 || i >= m_aVisibleEnd - m_aVisibleBegin)
1326 throw css::lang::IndexOutOfBoundsException(
1327 "textwindowaccessibility.cxx:"
1328 " Document::getAccessibleChild",
1329 getXWeak());
1331 + static_cast< Paragraphs::size_type >(i));
1332}
1333
1334// virtual
1335::sal_Int16 SAL_CALL Document::getAccessibleRole()
1336{
1337 return css::accessibility::AccessibleRole::TEXT_FRAME;
1338}
1339
1340// virtual
1341css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
1342Document::getAccessibleAtPoint(css::awt::Point const & rPoint)
1343{
1345 init();
1346 if (rPoint.X >= 0
1347 && rPoint.X < m_rView.GetWindow()->GetOutputSizePixel().Width()
1348 && rPoint.Y >= 0 && rPoint.Y < m_nViewHeight)
1349 {
1350 ::sal_Int32 nOffset = m_nViewOffset + rPoint.Y; // XXX numeric overflow
1352 for (Paragraphs::iterator aIt(m_aVisibleBegin); aIt != m_aVisibleEnd;
1353 ++aIt)
1354 {
1355 nPos += aIt->getHeight(); // XXX numeric overflow
1356 if (nOffset < nPos)
1357 return getAccessibleChild(aIt);
1358 }
1359 }
1360 return nullptr;
1361}
1362void Document::FillAccessibleStateSet( sal_Int64& rStateSet )
1363{
1364 VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet );
1365 if (!m_rView.IsReadOnly())
1366 rStateSet |= css::accessibility::AccessibleStateType::EDITABLE;
1367}
1368
1370{
1371 if( getAccessibleParent()->getAccessibleContext()->getAccessibleRole() == css::accessibility::AccessibleRole::SCROLL_PANE )
1372 {
1373 css::uno::Sequence< css::uno::Reference< css::uno::XInterface > > aSequence { getAccessibleParent() };
1374 rRelationSet.AddRelation( css::accessibility::AccessibleRelation( css::accessibility::AccessibleRelationType::MEMBER_OF, aSequence ) );
1375 }
1376 else
1377 {
1378 VCLXAccessibleComponent::FillAccessibleRelationSet(rRelationSet);
1379 }
1380}
1381// virtual
1382void SAL_CALL Document::disposing()
1383{
1386 if (m_xParagraphs != nullptr)
1388 VCLXAccessibleComponent::disposing();
1389}
1390
1391// virtual
1393{
1394 const TextHint* pTextHint = dynamic_cast<const TextHint*>(&rHint);
1395 if (!pTextHint)
1396 return;
1397
1398 ::TextHint const & rTextHint = *pTextHint;
1399 switch (rTextHint.GetId())
1400 {
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:
1418 {
1419 ::osl::MutexGuard aInternalGuard(GetMutex());
1420 if (!isAlive())
1421 break;
1422
1423 m_aParagraphNotifications.push(rTextHint);
1424 break;
1425 }
1426 case SfxHintId::TextFormatted:
1427 case SfxHintId::TextHeightChanged:
1428 case SfxHintId::TextModified:
1429 {
1430 ::osl::MutexGuard aInternalGuard(GetMutex());
1431 if (!isAlive())
1432 break;
1434 break;
1435 }
1436 case SfxHintId::TextViewScrolled:
1437 {
1438 ::osl::MutexGuard aInternalGuard(GetMutex());
1439 if (!isAlive())
1440 break;
1442
1443 ::sal_Int32 nOffset = static_cast< ::sal_Int32 >(
1445 // XXX numeric overflow
1446 if (nOffset != m_nViewOffset)
1447 {
1448 m_nViewOffset = nOffset;
1449
1450 Paragraphs::iterator aOldVisibleBegin(
1452 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd);
1453
1455
1456 notifyVisibleRangeChanges(aOldVisibleBegin,
1457 aOldVisibleEnd,
1458 m_xParagraphs->end());
1459 }
1460 break;
1461 }
1462 case SfxHintId::TextViewSelectionChanged:
1463 case SfxHintId::TextViewCaretChanged:
1464 {
1465 ::osl::MutexGuard aInternalGuard(GetMutex());
1466 if (!isAlive())
1467 break;
1468
1469 if (m_aParagraphNotifications.empty())
1470 {
1472 }
1473 else
1474 {
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:
1486 }
1487 break;
1488 }
1489 default: break;
1490 }
1491}
1492
1493IMPL_LINK(Document, WindowEventHandler, ::VclWindowEvent&, rEvent, void)
1494{
1495 switch (rEvent.GetId())
1496 {
1497 case VclEventId::WindowResize:
1498 {
1499 ::osl::MutexGuard aInternalGuard(GetMutex());
1500 if (!isAlive())
1501 break;
1502
1503 ::sal_Int32 nHeight = static_cast< ::sal_Int32 >(
1504 m_rView.GetWindow()->GetOutputSizePixel().Height());
1505 // XXX numeric overflow
1506 if (nHeight != m_nViewHeight)
1507 {
1508 m_nViewHeight = nHeight;
1509
1510 Paragraphs::iterator aOldVisibleBegin(m_aVisibleBegin);
1511 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd);
1512
1513 determineVisibleRange();
1514
1515 notifyVisibleRangeChanges(aOldVisibleBegin, aOldVisibleEnd,
1516 m_xParagraphs->end());
1517 }
1518 break;
1519 }
1520 case VclEventId::WindowGetFocus:
1521 {
1522 ::osl::MutexGuard aInternalGuard(GetMutex());
1523 if (!isAlive())
1524 break;
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)
1529 {
1530 Paragraphs::iterator aTemp = bEmpty ? m_aVisibleBegin : m_aFocused;
1531 ::rtl::Reference< Paragraph > xParagraph(getParagraph(aTemp));
1532 if (xParagraph.is())
1533 {
1534 xParagraph->notifyEvent(
1535 css::accessibility::AccessibleEventId::
1536 STATE_CHANGED,
1537 css::uno::Any(),
1538 css::uno::Any(
1539 css::accessibility::AccessibleStateType::
1540 FOCUSED));
1541 }
1542 }
1543 break;
1544 }
1545 case VclEventId::WindowLoseFocus:
1546 {
1547 ::osl::MutexGuard aInternalGuard(GetMutex());
1548 if (!isAlive())
1549 break;
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)
1554 {
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::
1560 STATE_CHANGED,
1561 css::uno::Any(
1562 css::accessibility::AccessibleStateType::
1563 FOCUSED),
1564 css::uno::Any());
1565 }
1566 break;
1567 }
1568 default: break;
1569 }
1570}
1571
1573{
1574 if (m_xParagraphs != nullptr)
1575 return;
1576
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 >(
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 >(
1589 // XXX numeric overflow
1595 m_aFocused = m_xParagraphs->end();
1599}
1600
1602Document::getParagraph(Paragraphs::iterator const & rIt)
1603{
1604 return static_cast< Paragraph * >(
1605 css::uno::Reference< css::accessibility::XAccessible >(
1606 rIt->getParagraph()).get());
1607}
1608
1609css::uno::Reference< css::accessibility::XAccessible >
1610Document::getAccessibleChild(Paragraphs::iterator const & rIt)
1611{
1612 css::uno::Reference< css::accessibility::XAccessible > xParagraph(
1613 rIt->getParagraph());
1614 if (!xParagraph.is())
1615 {
1616 xParagraph = new Paragraph(this, rIt - m_xParagraphs->begin());
1617 rIt->setParagraph(xParagraph);
1618 }
1619 return xParagraph;
1620}
1621
1623{
1624 Paragraphs::iterator const aEnd = m_xParagraphs->end();
1625
1626 m_aVisibleBegin = aEnd;
1627 m_aVisibleEnd = aEnd;
1629
1630 ::sal_Int32 nPos = 0;
1631 for (Paragraphs::iterator aIt = m_xParagraphs->begin(); m_aVisibleEnd == aEnd && aIt != aEnd; ++aIt)
1632 {
1633 ::sal_Int32 const nOldPos = nPos;
1634 nPos += aIt->getHeight(); // XXX numeric overflow
1635 if (m_aVisibleBegin == aEnd)
1636 {
1637 if (nPos >= m_nViewOffset)
1638 {
1639 m_aVisibleBegin = aIt;
1641 }
1642 }
1643 else
1644 {
1645 if (nPos >= m_nViewOffset + m_nViewHeight) // XXX numeric overflow
1646 {
1647 m_aVisibleEnd = aIt;
1648 }
1649 }
1650 }
1651
1654 || (m_aVisibleBegin < m_aVisibleEnd && m_nVisibleBeginOffset >= 0)),
1655 "accessibility",
1656 "invalid visible range");
1657}
1658
1660 Paragraphs::iterator const & rOldVisibleBegin,
1661 Paragraphs::iterator const & rOldVisibleEnd,
1662 Paragraphs::iterator const & rInserted)
1663{
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;
1667 ++aIt)
1668 {
1669 if (aIt != rInserted
1670 && (aIt < m_aVisibleBegin || aIt >= m_aVisibleEnd))
1671 NotifyAccessibleEvent(
1672 css::accessibility::AccessibleEventId::
1673 CHILD,
1674 css::uno::Any(getAccessibleChild(aIt)),
1675 css::uno::Any());
1676 }
1677 for (Paragraphs::iterator aIt(m_aVisibleBegin); aIt != m_aVisibleEnd;
1678 ++aIt)
1679 {
1680 if (aIt == rInserted
1681 || aIt < rOldVisibleBegin || aIt >= rOldVisibleEnd)
1682 NotifyAccessibleEvent(
1683 css::accessibility::AccessibleEventId::
1684 CHILD,
1685 css::uno::Any(),
1686 css::uno::Any(getAccessibleChild(aIt)));
1687 }
1688}
1689
1690void
1691Document::changeParagraphText(::sal_uInt32 nNumber, ::sal_uInt16 nBegin, ::sal_uInt16 nEnd,
1692 bool bCut, bool bPaste,
1693 OUString const & rText)
1694{
1696 ::TextPaM(nNumber, nEnd)));
1697 if (bCut)
1698 m_rView.Cut();
1699 else if (nBegin != nEnd)
1701 if (bPaste)
1702 m_rView.Paste();
1703 else if (!rText.isEmpty())
1704 m_rView.InsertText(rText);
1705}
1706
1708{
1709 while (!m_aParagraphNotifications.empty())
1710 {
1713 switch (aHint.GetId())
1714 {
1715 case SfxHintId::TextParaInserted:
1716 {
1717 ::sal_uInt32 n = static_cast< ::sal_uInt32 >( aHint.GetValue() );
1718 assert(n <= m_xParagraphs->size() && "bad SfxHintId::TextParaInserted event");
1719
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
1739
1740 Paragraphs::iterator aIns(
1741 m_xParagraphs->insert(
1742 m_xParagraphs->begin() + n,
1743 ParagraphInfo(static_cast< ::sal_Int32 >(
1745 // XXX numeric overflow (2x)
1746
1748 m_aFocused = m_xParagraphs->begin() + nOldFocused;
1749
1750 for (Paragraphs::iterator aIt(aIns);;)
1751 {
1752 ++aIt;
1753 if (aIt == m_xParagraphs->end())
1754 break;
1756 getParagraph(aIt));
1757 if (xParagraph.is())
1758 xParagraph->numberChanged(true);
1759 }
1760
1762 m_xParagraphs->begin() + nOldVisibleBegin,
1763 m_xParagraphs->begin() + nOldVisibleEnd, aIns);
1764 break;
1765 }
1766 case SfxHintId::TextParaRemoved:
1767 {
1768 ::sal_uInt32 n = static_cast< ::sal_uInt32 >( aHint.GetValue() );
1769 if (n == TEXT_PARA_ALL)
1770 {
1771 for (Paragraphs::iterator aIt(m_aVisibleBegin);
1772 aIt != m_aVisibleEnd; ++aIt)
1773 {
1774 NotifyAccessibleEvent(
1775 css::accessibility::AccessibleEventId::
1776 CHILD,
1777 css::uno::Any(getAccessibleChild(aIt)),
1778 css::uno::Any());
1779 }
1781 m_xParagraphs->clear();
1787 m_aFocused = m_xParagraphs->end();
1788 }
1789 else
1790 {
1791 assert(n < m_xParagraphs->size() && "Bad SfxHintId::TextParaRemoved event");
1792
1793 Paragraphs::iterator aIt(m_xParagraphs->begin() + n);
1794 // numeric overflow cannot occur
1795
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();
1803 bool bWasVisible
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)
1809 --nOldVisibleBegin;
1810 if (n < nOldVisibleEnd)
1811 --nOldVisibleEnd;
1812 if (n < nOldFocused)
1813 --nOldFocused;
1814 if (sal::static_int_cast<sal_Int32>(n) < m_nSelectionFirstPara)
1816 else if (sal::static_int_cast<sal_Int32>(n) == m_nSelectionFirstPara)
1817 {
1819 {
1824 }
1825 else
1826 {
1829 }
1830 }
1831 if (sal::static_int_cast<sal_Int32>(n) < m_nSelectionLastPara)
1833 else if (sal::static_int_cast<sal_Int32>(n) == m_nSelectionLastPara)
1834 {
1835 assert(m_nSelectionFirstPara < m_nSelectionLastPara && "logic error");
1837 m_nSelectionLastPos = 0x7FFFFFFF;
1838 }
1839
1840 css::uno::Reference< css::accessibility::XAccessible >
1841 xStrong;
1842 if (bWasVisible)
1843 xStrong = getAccessibleChild(aIt);
1844 css::uno::WeakReference<
1845 css::accessibility::XAccessible > xWeak(
1846 aIt->getParagraph());
1847 aIt = m_xParagraphs->erase(aIt);
1848
1850 m_aFocused = bWasFocused ? m_xParagraphs->end()
1851 : m_xParagraphs->begin() + nOldFocused;
1852
1853 for (; aIt != m_xParagraphs->end(); ++aIt)
1854 {
1856 getParagraph(aIt));
1857 if (xParagraph.is())
1858 xParagraph->numberChanged(false);
1859 }
1860
1861 if (bWasVisible)
1862 NotifyAccessibleEvent(
1863 css::accessibility::AccessibleEventId::
1864 CHILD,
1865 css::uno::Any(xStrong),
1866 css::uno::Any());
1867
1868 css::uno::Reference< css::lang::XComponent > xComponent(
1869 xWeak.get(), css::uno::UNO_QUERY);
1870 if (xComponent.is())
1871 xComponent->dispose();
1872
1874 m_xParagraphs->begin() + nOldVisibleBegin,
1875 m_xParagraphs->begin() + nOldVisibleEnd,
1876 m_xParagraphs->end());
1877 }
1878 break;
1879 }
1880 case SfxHintId::TextFormatPara:
1881 {
1882 ::sal_uInt32 n = static_cast< ::sal_uInt32 >( aHint.GetValue() );
1883 assert(n < m_xParagraphs->size() && "Bad SfxHintId::TextFormatPara event");
1884
1885 (*m_xParagraphs)[static_cast< Paragraphs::size_type >(n)].
1886 changeHeight(static_cast< ::sal_Int32 >(
1888 // XXX numeric overflow
1889 Paragraphs::iterator aOldVisibleBegin(m_aVisibleBegin);
1890 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd);
1892 notifyVisibleRangeChanges(aOldVisibleBegin, aOldVisibleEnd,
1893 m_xParagraphs->end());
1894
1895 if (n < m_xParagraphs->size())
1896 {
1897 Paragraphs::iterator aIt(m_xParagraphs->begin() + n);
1899 if (xParagraph.is())
1900 xParagraph->textChanged();
1901 }
1902 break;
1903 }
1904 default:
1905 SAL_WARN("accessibility", "bad buffered hint");
1906 break;
1907 }
1908 }
1910 {
1913 }
1914}
1915
1916namespace
1917{
1918
1919enum class SelChangeType
1920{
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
1933};
1934
1935SelChangeType getSelChangeType(const TextPaM& Os, const TextPaM& Oe,
1936 const TextPaM& Ns, const TextPaM& Ne)
1937{
1938 if (Os == Oe) // no old selection
1939 {
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;
1944 }
1945 else if (Ns == Ne) // old has selection; no new selection
1946 {
1947 return SelChangeType::SelToNoSel;
1948 }
1949 else if (Os == Ns) // both old and new have selections, and their starts are same
1950 {
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
1954 {
1955 //Send text_selection_change event on Nep
1956 return Oe.GetIndex() != Ne.GetIndex() ? SelChangeType::NoParaChange
1957 : SelChangeType::None;
1958 }
1959 else if (Oep < Nep) // end of selection moved to a following paragraph
1960 {
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
1965 {
1966 // 1, 2 -> 1, 3; 4, 1 -> 4, 7; 4,4->4,5;
1967 if (Oep < Osp) // old end was behind start
1968 {
1969 // 4,1 -> 4,7; 4,1 -> 4,4
1970 return SelChangeType::EndParaNoMoreBehind;
1971 }
1972 else // old end para wasn't behind start
1973 {
1974 // 1, 2 -> 1, 3; 4,4->4,5;
1975 return SelChangeType::AddedFollowingPara;
1976 }
1977 }
1978 else // new end para is still behind start
1979 {
1980 // 4,1 -> 4,2,
1981 return SelChangeType::ExcludedPreviousPara;
1982 }
1983 }
1984 else // Oep > Nep => end of selection moved to a previous paragraph
1985 {
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
1988 {
1989 // 4,7 ->4,6
1990 return SelChangeType::ExcludedFollowingPara;
1991 }
1992 else // new end para is behind start
1993 {
1994 // 3,2 -> 3,1, 4,7 -> 4,1; 4,4->4,3
1995 if (Oep <= Osp) // it was not ahead already
1996 {
1997 // 3,2 -> 3,1; 4,4->4,3
1998 return SelChangeType::AddedPreviousPara;
1999 }
2000 else // it was ahead previously
2001 {
2002 // 4,7 -> 4,1
2003 return SelChangeType::EndParaBecameBehind;
2004 }
2005 }
2006 }
2007 }
2008 return SelChangeType::None;
2009}
2010
2011} // namespace
2012
2013void Document::sendEvent(::sal_Int32 start, ::sal_Int32 end, ::sal_Int16 nEventId)
2014{
2015 size_t nAvailDistance = std::distance(m_xParagraphs->begin(), m_aVisibleEnd);
2016
2017 Paragraphs::iterator aEnd(m_xParagraphs->begin());
2018 size_t nEndDistance = std::min<size_t>(end + 1, nAvailDistance);
2019 std::advance(aEnd, nEndDistance);
2020
2021 Paragraphs::iterator aIt(m_xParagraphs->begin());
2022 size_t nStartDistance = std::min<size_t>(start, nAvailDistance);
2023 std::advance(aIt, nStartDistance);
2024
2025 while (aIt < aEnd)
2026 {
2028 if (xParagraph.is())
2029 xParagraph->notifyEvent(
2030 nEventId,
2031 css::uno::Any(), css::uno::Any());
2032 ++aIt;
2033 }
2034}
2035
2037{
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
2050
2051 // Lose focus:
2052 Paragraphs::iterator aIt(m_xParagraphs->begin() + nNewLastPara);
2053 if (m_aFocused != m_xParagraphs->end() && m_aFocused != aIt
2055 {
2057 if (xParagraph.is())
2058 xParagraph->notifyEvent(
2059 css::accessibility::AccessibleEventId::
2060 STATE_CHANGED,
2061 css::uno::Any(
2062 css::accessibility::AccessibleStateType::FOCUSED),
2063 css::uno::Any());
2064 }
2065
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))
2071 {
2073 if (xParagraph.is())
2074 {
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::
2082 STATE_CHANGED,
2083 css::uno::Any(),
2084 css::uno::Any(
2085 css::accessibility::AccessibleStateType::FOCUSED));
2086 if (nNewLastPara != m_nSelectionLastPara
2087 || nNewLastPos != m_nSelectionLastPos)
2088 xParagraph->notifyEvent(
2089 css::accessibility::AccessibleEventId::
2090 CARET_CHANGED,
2091 css::uno::Any( ::sal_Int32 (
2092 nNewLastPara == m_nSelectionLastPara
2093 ? m_nSelectionLastPos : 0)),
2094 css::uno::Any(nNewLastPos));
2095 }
2096 }
2097 m_aFocused = aIt;
2098
2099 if (m_nSelectionFirstPara != -1)
2100 {
2101 sal_Int32 nMin;
2102 sal_Int32 nMax;
2103 SelChangeType ret = getSelChangeType(TextPaM(m_nSelectionFirstPara, m_nSelectionFirstPos),
2105 rSelection.GetStart(), rSelection.GetEnd());
2106 switch (ret)
2107 {
2108 case SelChangeType::None:
2109 //no event
2110 break;
2111 case SelChangeType::CaretMove:
2112 //only caret moved, already handled in above
2113 break;
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);
2121 break;
2122 case SelChangeType::SelToNoSel:
2123 //old has selection but new has no selection.
2126 sendEvent(nMin, nMax, css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2127 sendEvent(nMin, nMax,
2128 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2129 break;
2130 case SelChangeType::NoParaChange:
2131 //Send text_selection_change event on Nep
2132 sendEvent(nNewLastPara, nNewLastPara,
2133 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2134 break;
2135 case SelChangeType::EndParaNoMoreBehind:
2136 // 4, 1 -> 4, 7; 4,1 -> 4,4
2138 css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2139 sendEvent(nNewFirstPara + 1, nNewLastPara,
2140 css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2141
2142 sendEvent(m_nSelectionLastPara, nNewLastPara,
2143 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2144 break;
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);
2149
2150 sendEvent(m_nSelectionLastPara, nNewLastPara,
2151 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2152 break;
2153 case SelChangeType::ExcludedPreviousPara:
2154 // 4,1 -> 4,3,
2155 sendEvent(m_nSelectionLastPara + 1, nNewLastPara,
2156 css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2157
2158 sendEvent(m_nSelectionLastPara, nNewLastPara,
2159 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2160 break;
2161 case SelChangeType::ExcludedFollowingPara:
2162 // 4,7 ->4,5;
2163 sendEvent(nNewLastPara + 1, m_nSelectionLastPara,
2164 css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2165
2166 sendEvent(nNewLastPara, m_nSelectionLastPara,
2167 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2168 break;
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);
2173
2174 sendEvent(nNewLastPara, m_nSelectionLastPara,
2175 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2176 break;
2177 case SelChangeType::EndParaBecameBehind:
2178 // 4,7 -> 4,1
2180 css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2181 sendEvent(nNewLastPara, nNewFirstPara - 1,
2182 css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2183
2184 sendEvent(nNewLastPara, m_nSelectionLastPara,
2185 css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2186 break;
2187 }
2188 }
2189
2190 m_nSelectionFirstPara = nNewFirstPara;
2191 m_nSelectionFirstPos = nNewFirstPos;
2192 m_nSelectionLastPara = nNewLastPara;
2193 m_nSelectionLastPos = nNewLastPos;
2194}
2195
2197{
2198 for (auto const& paragraph : *m_xParagraphs)
2199 {
2200 css::uno::Reference< css::lang::XComponent > xComponent(
2201 paragraph.getParagraph().get(), css::uno::UNO_QUERY);
2202 if (xComponent.is())
2203 xComponent->dispose();
2204 }
2205}
2206
2207// static
2208css::uno::Any Document::mapFontColor(::Color const & rColor)
2209{
2210 return css::uno::Any(rColor.GetRGBColor());
2211 // FIXME keep transparency?
2212}
2213
2214// static
2215::Color Document::mapFontColor(css::uno::Any const & rColor)
2216{
2217 ::Color nColor;
2218 rColor >>= nColor;
2219 return nColor;
2220}
2221
2222// static
2224{
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]);
2240}
2241
2242// static
2243::FontWeight Document::mapFontWeight(css::uno::Any const & rWeight)
2244{
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
2256 : WEIGHT_BLACK;
2257}
2258
2259}
2260
2261/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
struct _ADOIndex Index
Color GetRGBColor() const
constexpr tools::Long Y() const
constexpr tools::Long X() const
void StartListening(SfxBroadcaster &rBroadcaster, DuplicateHandling eDuplicateHanding=DuplicateHandling::Unexpected)
void EndListening(SfxBroadcaster &rBroadcaster, bool bRemoveAllDuplicates=false)
constexpr tools::Long Height() const
constexpr tools::Long Width() const
const Color & GetColor() const
FontWeight getFontWeight() const
sal_Int32 GetTextLen() const
TextPaM GetPaM(const Point &rDocPos)
tools::Rectangle PaMtoEditCursor(const TextPaM &rPaM, bool bSpecial=false)
tools::Long GetTextHeight() const
sal_uInt16 GetLineCount(sal_uInt32 nParagraph) const
sal_Int32 GetLineLen(sal_uInt32 nParagraph, sal_uInt16 nLine) const
tools::Long GetMaxTextWidth() const
OUString GetText(LineEnd aSeparator=LINEEND_LF) const
sal_uInt32 GetParagraphCount() const
void SetAttrib(const TextAttrib &rAttr, sal_uInt32 nPara, sal_Int32 nStart, sal_Int32 nEnd)
TxtAlign GetTextAlign() const
const TextAttrib * FindAttrib(const TextPaM &rPaM, sal_uInt16 nWhich) const
css::lang::Locale const & GetLocale()
const Color & GetTextColor() const
const vcl::Font & GetFont() const
sal_Int32 GetValue() const
sal_uInt32 GetPara() const
sal_Int32 GetIndex() const
const TextPaM & GetStart() const
const TextPaM & GetEnd() const
void SetSelection(const TextSelection &rNewSel)
vcl::Window * GetWindow() const
bool IsReadOnly() const
sal_Int32 GetLineNumberOfCursorInSelection() const
void Paste()
void Cut()
void Copy()
void DeleteSelected()
const TextSelection & GetSelection() const
void InsertText(const OUString &rNew)
const Point & GetStartDocPos() const
virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild(sal_Int64 i) override
css::uno::Sequence< css::beans::PropertyValue > retrieveCharacterAttributes(Paragraph const *pParagraph, ::sal_Int32 nIndex, const css::uno::Sequence< OUString > &aRequestedAttributes)
void notifyVisibleRangeChanges(Paragraphs::iterator const &rOldVisibleBegin, Paragraphs::iterator const &rOldVisibleEnd, Paragraphs::iterator const &rInserted)
void copyParagraphText(Paragraph const *pParagraph, ::sal_Int32 nBegin, ::sal_Int32 nEnd)
virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint(css::awt::Point const &rPoint) override
css::awt::Rectangle retrieveParagraphBounds(Paragraph const *pParagraph, bool bAbsolute)
virtual void Notify(::SfxBroadcaster &rBC, ::SfxHint const &rHint) override
void retrieveParagraphSelection(Paragraph const *pParagraph, ::sal_Int32 *pBegin, ::sal_Int32 *pEnd)
void retrieveRunAttributesImpl(Paragraph const *pParagraph, ::sal_Int32 Index, const css::uno::Sequence< OUString > &RequestedAttributes, tPropValMap &rRunAttrSeq)
static css::uno::Any mapFontColor(::Color const &rColor)
::sal_Int32 retrieveCharacterIndex(Paragraph const *pParagraph, css::awt::Point const &rPoint)
Paragraphs::iterator m_aVisibleBegin
virtual sal_Int64 SAL_CALL getAccessibleChildCount() override
virtual ::sal_Int16 SAL_CALL getAccessibleRole() override
::sal_Int64 retrieveParagraphState(Paragraph const *pParagraph)
void changeParagraphText(Paragraph const *pParagraph, OUString const &rText)
::sal_Int32 retrieveParagraphIndex(Paragraph const *pParagraph)
css::i18n::Boundary retrieveParagraphLineBoundary(Paragraph const *pParagraph, ::sal_Int32 nIndex, ::sal_Int32 *pLineNo)
virtual void SAL_CALL disposing() override
void changeParagraphSelection(Paragraph const *pParagraph, ::sal_Int32 nBegin, ::sal_Int32 nEnd)
virtual void FillAccessibleRelationSet(utl::AccessibleRelationSetHelper &rRelationSet) override
sal_Int32 retrieveParagraphLineWithCursor(Paragraph const *pParagraph)
void changeParagraphAttributes(Paragraph const *pParagraph, ::sal_Int32 nBegin, ::sal_Int32 nEnd, css::uno::Sequence< css::beans::PropertyValue > const &rAttributeSet)
static css::uno::Any mapFontWeight(::FontWeight nWeight)
void sendEvent(::sal_Int32 start, ::sal_Int32 end, ::sal_Int16 nEventId)
Paragraphs::iterator m_aVisibleEnd
css::uno::Sequence< css::beans::PropertyValue > retrieveRunAttributes(Paragraph const *pParagraph, ::sal_Int32 Index, const css::uno::Sequence< OUString > &RequestedAttributes)
virtual void FillAccessibleStateSet(sal_Int64 &rStateSet) override
css::awt::Rectangle retrieveCharacterBounds(Paragraph const *pParagraph, ::sal_Int32 nIndex)
::sal_Int32 retrieveParagraphCaretPosition(Paragraph const *pParagraph)
Document(::VCLXWindow *pVclXWindow, ::TextEngine &rEngine, ::TextView &rView)
static ::rtl::Reference< Paragraph > getParagraph(Paragraphs::iterator const &rIt)
std::unique_ptr< Paragraphs > m_xParagraphs
css::i18n::Boundary retrieveParagraphBoundaryOfLine(Paragraph const *pParagraph, ::sal_Int32 nIndex)
css::uno::Reference< css::accessibility::XAccessibleRelationSet > retrieveParagraphRelationSet(Paragraph const *pParagraph)
OUString retrieveParagraphText(Paragraph const *pParagraph)
std::queue< ::TextHint > m_aParagraphNotifications
virtual sal_Bool SAL_CALL deleteText(::sal_Int32 nStartIndex, ::sal_Int32 nEndIndex) override
virtual sal_Bool SAL_CALL scrollSubstringTo(sal_Int32 nStartIndex, sal_Int32 nEndIndex, css::accessibility::AccessibleScrollType aScrollType) override
virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent() override
virtual sal_Bool SAL_CALL copyText(::sal_Int32 nStartIndex, ::sal_Int32 nEndIndex) override
virtual css::lang::Locale implGetLocale() override
virtual css::accessibility::TextSegment SAL_CALL getTextBehindIndex(sal_Int32 nIndex, sal_Int16 aTextType) override
virtual ::sal_Int32 SAL_CALL getSelectionEnd() override
virtual ::sal_Unicode SAL_CALL getCharacter(::sal_Int32 nIndex) override
void numberChanged(bool bIncremented)
virtual OUString implGetText() override
virtual css::awt::Rectangle SAL_CALL getBounds() override
virtual sal_Bool SAL_CALL setCaretPosition(::sal_Int32 nIndex) override
virtual ::sal_Int32 SAL_CALL getNumberOfLineWithCaret() override
virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext() override
virtual ::sal_Int32 SAL_CALL getCaretPosition() override
virtual void SAL_CALL addAccessibleEventListener(css::uno::Reference< css::accessibility::XAccessibleEventListener > const &rListener) override
virtual css::lang::Locale SAL_CALL getLocale() override
virtual void implGetLineBoundary(const OUString &rText, css::i18n::Boundary &rBoundary, ::sal_Int32 nIndex) override
Paragraphs::size_type getNumber() const
virtual void SAL_CALL grabFocus() override
virtual css::accessibility::TextSegment SAL_CALL getTextAtIndex(sal_Int32 nIndex, sal_Int16 aTextType) override
virtual sal_Bool SAL_CALL setText(OUString const &rText) override
sal_uInt32 m_nClientId
client id in the AccessibleEventNotifier queue
virtual sal_Bool SAL_CALL replaceText(::sal_Int32 nStartIndex, ::sal_Int32 nEndIndex, OUString const &rReplacement) override
virtual ::sal_Int32 SAL_CALL getIndexAtPoint(css::awt::Point const &rPoint) override
virtual void implGetParagraphBoundary(const OUString &rText, css::i18n::Boundary &rBoundary, ::sal_Int32 nIndex) override
virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet() override
virtual sal_Bool SAL_CALL containsPoint(css::awt::Point const &rPoint) override
virtual sal_Int64 SAL_CALL getAccessibleChildCount() override
virtual sal_Int64 SAL_CALL getAccessibleIndexInParent() override
virtual css::awt::Size SAL_CALL getSize() override
virtual css::accessibility::TextSegment SAL_CALL getTextBeforeIndex(sal_Int32 nIndex, sal_Int16 aTextType) override
virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild(sal_Int64 i) override
virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL getCharacterAttributes(::sal_Int32 nIndex, const css::uno::Sequence< OUString > &aRequestedAttributes) override
virtual sal_Bool SAL_CALL setAttributes(::sal_Int32 nStartIndex, ::sal_Int32 nEndIndex, css::uno::Sequence< css::beans::PropertyValue > const &rAttributeSet) override
virtual void implGetSelection(::sal_Int32 &rStartIndex, ::sal_Int32 &rEndIndex) override
virtual css::awt::Rectangle SAL_CALL getCharacterBounds(::sal_Int32 nIndex) override
virtual ::sal_Int32 SAL_CALL getLineNumberAtIndex(::sal_Int32 nIndex) override
virtual ::sal_Int32 SAL_CALL getCharacterCount() override
virtual sal_Bool SAL_CALL cutText(::sal_Int32 nStartIndex, ::sal_Int32 nEndIndex) override
virtual css::awt::Point SAL_CALL getLocation() override
virtual css::awt::Point SAL_CALL getLocationOnScreen() override
virtual OUString SAL_CALL getText() override
virtual sal_Bool SAL_CALL insertText(OUString const &rText, ::sal_Int32 nIndex) override
virtual sal_Int32 SAL_CALL getBackground() override
virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL getDefaultAttributes(const css::uno::Sequence< OUString > &RequestedAttributes) override
virtual sal_Bool SAL_CALL pasteText(::sal_Int32 nIndex) override
virtual ::sal_Int32 SAL_CALL getSelectionStart() override
virtual sal_Int32 SAL_CALL getForeground() override
virtual sal_Int64 SAL_CALL getAccessibleStateSet() override
virtual OUString SAL_CALL getAccessibleName() override
virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint(css::awt::Point const &rPoint) override
virtual void SAL_CALL removeAccessibleEventListener(css::uno::Reference< css::accessibility::XAccessibleEventListener > const &rListener) override
::rtl::Reference< Document > m_xDocument
virtual OUString SAL_CALL getTextRange(::sal_Int32 nStartIndex, ::sal_Int32 nEndIndex) override
virtual ::sal_Int16 SAL_CALL getAccessibleRole() override
virtual css::accessibility::TextSegment SAL_CALL getTextAtLineWithCaret() override
virtual OUString SAL_CALL getSelectedText() override
virtual sal_Bool SAL_CALL setSelection(::sal_Int32 nStartIndex, ::sal_Int32 nEndIndex) override
virtual OUString SAL_CALL getAccessibleDescription() override
virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL getRunAttributes(::sal_Int32 Index, const css::uno::Sequence< OUString > &RequestedAttributes) override
virtual css::accessibility::TextSegment SAL_CALL getTextAtLineNumber(::sal_Int32 nLineNo) override
void notifyEvent(::sal_Int16 nEventId, css::uno::Any const &rOldValue, css::uno::Any const &rNewValue)
Paragraph(::rtl::Reference< Document > xDocument, Paragraphs::size_type nNumber)
virtual void SAL_CALL disposing() override
void startListening(::SfxBroadcaster &rNotifier)
void startListening(vcl::Window &rNotifier)
::Link< VclWindowEvent &, void > m_aListener
static sal_Int32 addEventListener(const TClientId _nClient, const css::uno::Reference< css::accessibility::XAccessibleEventListener > &_rxListener)
static void addEvent(const TClientId _nClient, const css::accessibility::AccessibleEventObject &_rEvent)
static sal_Int32 removeEventListener(const TClientId _nClient, const css::uno::Reference< css::accessibility::XAccessibleEventListener > &_rxListener)
static void revokeClient(const TClientId _nClient)
static void revokeClientNotifyDisposing(const TClientId _nClient, const css::uno::Reference< css::uno::XInterface > &_rxEventSource)
css::accessibility::TextSegment getTextBeforeIndex(sal_Int32 nIndex, sal_Int16 aTextType)
css::accessibility::TextSegment getTextAtIndex(sal_Int32 nIndex, sal_Int16 aTextType)
static bool implIsValidIndex(sal_Int32 nIndex, sal_Int32 nLength)
static bool implInitTextChangedEvent(std::u16string_view rOldString, std::u16string_view rNewString, css::uno::Any &rDeleted, css::uno::Any &rInserted)
static sal_Unicode implGetCharacter(std::u16string_view rText, sal_Int32 nIndex)
css::accessibility::TextSegment getTextBehindIndex(sal_Int32 nIndex, sal_Int16 aTextType)
static OUString implGetTextRange(std::u16string_view rText, sal_Int32 nStartIndex, sal_Int32 nEndIndex)
constexpr tools::Long Top() const
constexpr tools::Long Left() const
constexpr tools::Long Bottom() const
void AddRelation(const css::accessibility::AccessibleRelation &rRelation)
tools::Long GetFontHeight() const
FontStrikeout GetStrikeout() const
FontItalic GetItalic()
const OUString & GetFamilyName() const
FontWeight GetWeight()
FontLineStyle GetUnderline() const
const Color & GetFillColor() const
Size GetOutputSizePixel() const
Point OutputToAbsoluteScreenPixel(const Point &rPos) const
css::awt::Rectangle AWTRectangle(const ::tools::Rectangle &rVCLRect)
int nCount
Reference< XOfficeDatabaseDocument > m_xDocument
#define TOOLS_INFO_EXCEPTION(area, stream)
sal_Int32 nState
WEIGHT_ULTRALIGHT
WEIGHT_ULTRABOLD
WEIGHT_THIN
WEIGHT_BOLD
WEIGHT_NORMAL
WEIGHT_LIGHT
WEIGHT_DONTKNOW
WEIGHT_SEMIBOLD
WEIGHT_SEMILIGHT
WEIGHT_BLACK
std::mutex m_aMutex
sal_Int32 nIndex
sal_Int64 n
uno_Any a
sal_uInt16 nPos
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
@ paragraph
std::vector< ParagraphInfo > Paragraphs
std::unordered_map< OUString, css::beans::PropertyValue > tPropValMap
IMPL_LINK(AccessibleDocumentViewBase, WindowChildEventListener, VclWindowEvent &, rEvent, void)
size
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
css::uno::Sequence< typename M::mapped_type > mapValuesToSequence(M const &map)
Any SAL_CALL getCaughtException()
int i
None
end
FontWeight
long Long
bool isAlive()
sal_Int16 nId
#define TEXT_PARA_ALL
#define TEXTATTR_FONTWEIGHT
#define TEXTATTR_FONTCOLOR
unsigned char sal_Bool
sal_uInt16 sal_Unicode
sal_Int32 nLength