Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / starmath / source / accessibility.cxx
blob988931c5a540a99e238fd96d24974df248d44813
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <memory>
24 #include <com/sun/star/accessibility/AccessibleRole.hpp>
25 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
26 #include <com/sun/star/accessibility/AccessibleTextType.hpp>
27 #include <com/sun/star/accessibility/XAccessibleEventListener.hpp>
28 #include <com/sun/star/accessibility/AccessibleEventObject.hpp>
29 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
30 #include <unotools/accessiblerelationsethelper.hxx>
32 #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
33 #include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
34 #include <com/sun/star/i18n/WordType.hpp>
35 #include <unotools/accessiblestatesethelper.hxx>
36 #include <comphelper/accessibleeventnotifier.hxx>
37 #include <cppuhelper/supportsservice.hxx>
38 #include <osl/diagnose.h>
39 #include <svx/AccessibleTextHelper.hxx>
40 #include <vcl/svapp.hxx>
41 #include <vcl/window.hxx>
42 #include <vcl/unohelp2.hxx>
43 #include <vcl/settings.hxx>
45 #include <tools/gen.hxx>
46 #include <svl/itemset.hxx>
48 #include <editeng/editobj.hxx>
49 #include <editeng/editdata.hxx>
50 #include <editeng/editview.hxx>
51 #include <editeng/eeitem.hxx>
52 #include <editeng/outliner.hxx>
53 #include <editeng/unoedhlp.hxx>
56 #include "accessibility.hxx"
57 #include <document.hxx>
58 #include <view.hxx>
59 #include <o3tl/make_unique.hxx>
60 #include <strings.hrc>
62 using namespace com::sun::star;
63 using namespace com::sun::star::lang;
64 using namespace com::sun::star::uno;
65 using namespace com::sun::star::accessibility;
68 static awt::Rectangle lcl_GetBounds( vcl::Window const *pWin )
70 // !! see VCLXAccessibleComponent::implGetBounds()
72 //! the coordinates returned are relative to the parent window !
73 //! Thus the top-left point may be different from (0, 0) !
75 awt::Rectangle aBounds;
76 if (pWin)
78 tools::Rectangle aRect = pWin->GetWindowExtentsRelative( nullptr );
79 aBounds.X = aRect.Left();
80 aBounds.Y = aRect.Top();
81 aBounds.Width = aRect.GetWidth();
82 aBounds.Height = aRect.GetHeight();
83 vcl::Window* pParent = pWin->GetAccessibleParentWindow();
84 if (pParent)
86 tools::Rectangle aParentRect = pParent->GetWindowExtentsRelative( nullptr );
87 awt::Point aParentScreenLoc( aParentRect.Left(), aParentRect.Top() );
88 aBounds.X -= aParentScreenLoc.X;
89 aBounds.Y -= aParentScreenLoc.Y;
92 return aBounds;
95 static awt::Point lcl_GetLocationOnScreen( vcl::Window const *pWin )
97 // !! see VCLXAccessibleComponent::getLocationOnScreen()
99 awt::Point aPos;
100 if (pWin)
102 tools::Rectangle aRect = pWin->GetWindowExtentsRelative( nullptr );
103 aPos.X = aRect.Left();
104 aPos.Y = aRect.Top();
106 return aPos;
110 SmGraphicAccessible::SmGraphicAccessible( SmGraphicWindow *pGraphicWin ) :
111 aAccName (SmResId(RID_DOCUMENTSTR)),
112 nClientId (0),
113 pWin (pGraphicWin)
115 OSL_ENSURE( pWin, "SmGraphicAccessible: window missing" );
118 SmGraphicAccessible::~SmGraphicAccessible()
123 SmDocShell * SmGraphicAccessible::GetDoc_Impl()
125 SmViewShell *pView = pWin ? pWin->GetView() : nullptr;
126 return pView ? pView->GetDoc() : nullptr;
129 OUString SmGraphicAccessible::GetAccessibleText_Impl()
131 OUString aTxt;
132 SmDocShell *pDoc = GetDoc_Impl();
133 if (pDoc)
134 aTxt = pDoc->GetAccessibleText();
135 return aTxt;
138 void SmGraphicAccessible::ClearWin()
140 pWin = nullptr; // implicitly results in AccessibleStateType::DEFUNC set
142 if ( nClientId )
144 comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( nClientId, *this );
145 nClientId = 0;
149 void SmGraphicAccessible::LaunchEvent(
150 const sal_Int16 nAccessibleEventId,
151 const uno::Any &rOldVal,
152 const uno::Any &rNewVal)
154 AccessibleEventObject aEvt;
155 aEvt.Source = static_cast<XAccessible *>(this);
156 aEvt.EventId = nAccessibleEventId;
157 aEvt.OldValue = rOldVal;
158 aEvt.NewValue = rNewVal ;
160 // pass event on to event-listener's
161 if (nClientId)
162 comphelper::AccessibleEventNotifier::addEvent( nClientId, aEvt );
165 uno::Reference< XAccessibleContext > SAL_CALL SmGraphicAccessible::getAccessibleContext()
167 return this;
170 sal_Bool SAL_CALL SmGraphicAccessible::containsPoint( const awt::Point& aPoint )
172 //! the arguments coordinates are relative to the current window !
173 //! Thus the top-left point is (0, 0)
175 SolarMutexGuard aGuard;
176 if (!pWin)
177 throw RuntimeException();
179 Size aSz( pWin->GetSizePixel() );
180 return aPoint.X >= 0 && aPoint.Y >= 0 &&
181 aPoint.X < aSz.Width() && aPoint.Y < aSz.Height();
184 uno::Reference< XAccessible > SAL_CALL SmGraphicAccessible::getAccessibleAtPoint(
185 const awt::Point& aPoint )
187 SolarMutexGuard aGuard;
188 XAccessible *pRes = nullptr;
189 if (containsPoint( aPoint ))
190 pRes = this;
191 return pRes;
194 awt::Rectangle SAL_CALL SmGraphicAccessible::getBounds()
196 SolarMutexGuard aGuard;
197 if (!pWin)
198 throw RuntimeException();
199 OSL_ENSURE(pWin->GetParent()->GetAccessible() == getAccessibleParent(),
200 "mismatch of window parent and accessible parent" );
201 return lcl_GetBounds( pWin );
204 awt::Point SAL_CALL SmGraphicAccessible::getLocation()
206 SolarMutexGuard aGuard;
207 if (!pWin)
208 throw RuntimeException();
209 OSL_ENSURE(pWin->GetParent()->GetAccessible() == getAccessibleParent(),
210 "mismatch of window parent and accessible parent" );
211 awt::Rectangle aRect( lcl_GetBounds( pWin ) );
212 return awt::Point( aRect.X, aRect.Y );
215 awt::Point SAL_CALL SmGraphicAccessible::getLocationOnScreen()
217 SolarMutexGuard aGuard;
218 if (!pWin)
219 throw RuntimeException();
220 OSL_ENSURE(pWin->GetParent()->GetAccessible() == getAccessibleParent(),
221 "mismatch of window parent and accessible parent" );
222 return lcl_GetLocationOnScreen( pWin );
225 awt::Size SAL_CALL SmGraphicAccessible::getSize()
227 SolarMutexGuard aGuard;
228 if (!pWin)
229 throw RuntimeException();
230 OSL_ENSURE(pWin->GetParent()->GetAccessible() == getAccessibleParent(),
231 "mismatch of window parent and accessible parent" );
233 Size aSz( pWin->GetSizePixel() );
234 #if OSL_DEBUG_LEVEL > 0
235 awt::Rectangle aRect( lcl_GetBounds( pWin ) );
236 Size aSz2( aRect.Width, aRect.Height );
237 assert(aSz == aSz2 && "mismatch in width" );
238 #endif
239 return awt::Size( aSz.Width(), aSz.Height() );
242 void SAL_CALL SmGraphicAccessible::grabFocus()
244 SolarMutexGuard aGuard;
245 if (!pWin)
246 throw RuntimeException();
248 pWin->GrabFocus();
251 sal_Int32 SAL_CALL SmGraphicAccessible::getForeground()
253 SolarMutexGuard aGuard;
255 if (!pWin)
256 throw RuntimeException();
257 return static_cast<sal_Int32>(pWin->GetTextColor());
260 sal_Int32 SAL_CALL SmGraphicAccessible::getBackground()
262 SolarMutexGuard aGuard;
264 if (!pWin)
265 throw RuntimeException();
266 Wallpaper aWall( pWin->GetDisplayBackground() );
267 Color nCol;
268 if (aWall.IsBitmap() || aWall.IsGradient())
269 nCol = pWin->GetSettings().GetStyleSettings().GetWindowColor();
270 else
271 nCol = aWall.GetColor();
272 return static_cast<sal_Int32>(nCol);
275 sal_Int32 SAL_CALL SmGraphicAccessible::getAccessibleChildCount()
277 return 0;
280 Reference< XAccessible > SAL_CALL SmGraphicAccessible::getAccessibleChild(
281 sal_Int32 /*i*/ )
283 throw IndexOutOfBoundsException(); // there is no child...
286 Reference< XAccessible > SAL_CALL SmGraphicAccessible::getAccessibleParent()
288 SolarMutexGuard aGuard;
289 if (!pWin)
290 throw RuntimeException();
292 vcl::Window *pAccParent = pWin->GetAccessibleParentWindow();
293 OSL_ENSURE( pAccParent, "accessible parent missing" );
294 return pAccParent ? pAccParent->GetAccessible() : Reference< XAccessible >();
297 sal_Int32 SAL_CALL SmGraphicAccessible::getAccessibleIndexInParent()
299 SolarMutexGuard aGuard;
300 sal_Int32 nIdx = -1;
301 vcl::Window *pAccParent = pWin ? pWin->GetAccessibleParentWindow() : nullptr;
302 if (pAccParent)
304 sal_uInt16 nCnt = pAccParent->GetAccessibleChildWindowCount();
305 for (sal_uInt16 i = 0; i < nCnt && nIdx == -1; ++i)
306 if (pAccParent->GetAccessibleChildWindow( i ) == pWin)
307 nIdx = i;
309 return nIdx;
312 sal_Int16 SAL_CALL SmGraphicAccessible::getAccessibleRole()
314 return AccessibleRole::DOCUMENT;
317 OUString SAL_CALL SmGraphicAccessible::getAccessibleDescription()
319 SolarMutexGuard aGuard;
320 SmDocShell *pDoc = GetDoc_Impl();
321 return pDoc ? pDoc->GetText() : OUString();
324 OUString SAL_CALL SmGraphicAccessible::getAccessibleName()
326 SolarMutexGuard aGuard;
327 return aAccName;
330 Reference< XAccessibleRelationSet > SAL_CALL SmGraphicAccessible::getAccessibleRelationSet()
332 SolarMutexGuard aGuard;
333 Reference< XAccessibleRelationSet > xRelSet = new utl::AccessibleRelationSetHelper();
334 return xRelSet; // empty relation set
337 Reference< XAccessibleStateSet > SAL_CALL SmGraphicAccessible::getAccessibleStateSet()
339 SolarMutexGuard aGuard;
340 ::utl::AccessibleStateSetHelper *pStateSet =
341 new ::utl::AccessibleStateSetHelper;
343 Reference<XAccessibleStateSet> xStateSet( pStateSet );
345 if (!pWin)
346 pStateSet->AddState( AccessibleStateType::DEFUNC );
347 else
349 pStateSet->AddState( AccessibleStateType::ENABLED );
350 pStateSet->AddState( AccessibleStateType::FOCUSABLE );
351 if (pWin->HasFocus())
352 pStateSet->AddState( AccessibleStateType::FOCUSED );
353 if (pWin->IsActive())
354 pStateSet->AddState( AccessibleStateType::ACTIVE );
355 if (pWin->IsVisible())
356 pStateSet->AddState( AccessibleStateType::SHOWING );
357 if (pWin->IsReallyVisible())
358 pStateSet->AddState( AccessibleStateType::VISIBLE );
359 if (COL_TRANSPARENT != pWin->GetBackground().GetColor())
360 pStateSet->AddState( AccessibleStateType::OPAQUE );
363 return xStateSet;
366 Locale SAL_CALL SmGraphicAccessible::getLocale()
368 SolarMutexGuard aGuard;
369 // should be the document language...
370 // We use the language of the localized symbol names here.
371 return Application::GetSettings().GetUILanguageTag().getLocale();
375 void SAL_CALL SmGraphicAccessible::addAccessibleEventListener(
376 const Reference< XAccessibleEventListener >& xListener )
378 if (xListener.is())
380 SolarMutexGuard aGuard;
381 if (pWin)
383 if (!nClientId)
384 nClientId = comphelper::AccessibleEventNotifier::registerClient( );
385 comphelper::AccessibleEventNotifier::addEventListener( nClientId, xListener );
390 void SAL_CALL SmGraphicAccessible::removeAccessibleEventListener(
391 const Reference< XAccessibleEventListener >& xListener )
393 if (xListener.is() && nClientId)
395 SolarMutexGuard aGuard;
396 sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( nClientId, xListener );
397 if ( !nListenerCount )
399 // no listeners anymore
400 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
401 // and at least to us not firing any events anymore, in case somebody calls
402 // NotifyAccessibleEvent, again
403 comphelper::AccessibleEventNotifier::revokeClient( nClientId );
404 nClientId = 0;
409 sal_Int32 SAL_CALL SmGraphicAccessible::getCaretPosition()
411 return 0;
414 sal_Bool SAL_CALL SmGraphicAccessible::setCaretPosition( sal_Int32 nIndex )
416 SolarMutexGuard aGuard;
417 OUString aTxt( GetAccessibleText_Impl() );
418 if (nIndex >= aTxt.getLength())
419 throw IndexOutOfBoundsException();
420 return false;
423 sal_Unicode SAL_CALL SmGraphicAccessible::getCharacter( sal_Int32 nIndex )
425 SolarMutexGuard aGuard;
426 OUString aTxt( GetAccessibleText_Impl() );
427 if (nIndex >= aTxt.getLength())
428 throw IndexOutOfBoundsException();
429 return aTxt[nIndex];
432 Sequence< beans::PropertyValue > SAL_CALL SmGraphicAccessible::getCharacterAttributes(
433 sal_Int32 nIndex,
434 const uno::Sequence< OUString > & /*rRequestedAttributes*/ )
436 SolarMutexGuard aGuard;
437 sal_Int32 nLen = GetAccessibleText_Impl().getLength();
438 if (!(0 <= nIndex && nIndex < nLen))
439 throw IndexOutOfBoundsException();
440 return Sequence< beans::PropertyValue >();
443 awt::Rectangle SAL_CALL SmGraphicAccessible::getCharacterBounds( sal_Int32 nIndex )
445 SolarMutexGuard aGuard;
447 awt::Rectangle aRes;
449 if (!pWin)
450 throw RuntimeException();
452 // get accessible text
453 SmViewShell *pView = pWin->GetView();
454 SmDocShell *pDoc = pView ? pView->GetDoc() : nullptr;
455 if (!pDoc)
456 throw RuntimeException();
457 OUString aTxt( GetAccessibleText_Impl() );
458 if (!(0 <= nIndex && nIndex <= aTxt.getLength())) // aTxt.getLength() is valid
459 throw IndexOutOfBoundsException();
461 // find a reasonable rectangle for position aTxt.getLength().
462 bool bWasBehindText = (nIndex == aTxt.getLength());
463 if (bWasBehindText && nIndex)
464 --nIndex;
466 const SmNode *pTree = pDoc->GetFormulaTree();
467 const SmNode *pNode = pTree->FindNodeWithAccessibleIndex( nIndex );
468 //! pNode may be 0 if the index belongs to a char that was inserted
469 //! only for the accessible text!
470 if (pNode)
472 sal_Int32 nAccIndex = pNode->GetAccessibleIndex();
473 OSL_ENSURE( nAccIndex >= 0, "invalid accessible index" );
474 OSL_ENSURE( nIndex >= nAccIndex, "index out of range" );
476 OUStringBuffer aBuf;
477 pNode->GetAccessibleText(aBuf);
478 OUString aNodeText = aBuf.makeStringAndClear();
479 sal_Int32 nNodeIndex = nIndex - nAccIndex;
480 if (0 <= nNodeIndex && nNodeIndex < aNodeText.getLength())
482 // get appropriate rectangle
483 Point aOffset(pNode->GetTopLeft() - pTree->GetTopLeft());
484 Point aTLPos (pWin->GetFormulaDrawPos() + aOffset);
485 Size aSize (pNode->GetSize());
487 long* pXAry = new long[ aNodeText.getLength() ];
488 pWin->SetFont( pNode->GetFont() );
489 pWin->GetTextArray( aNodeText, pXAry, 0, aNodeText.getLength() );
490 aTLPos.AdjustX(nNodeIndex > 0 ? pXAry[nNodeIndex - 1] : 0 );
491 aSize.setWidth( nNodeIndex > 0 ? pXAry[nNodeIndex] - pXAry[nNodeIndex - 1] : pXAry[nNodeIndex] );
492 delete[] pXAry;
494 aTLPos = pWin->LogicToPixel( aTLPos );
495 aSize = pWin->LogicToPixel( aSize );
496 aRes.X = aTLPos.X();
497 aRes.Y = aTLPos.Y();
498 aRes.Width = aSize.Width();
499 aRes.Height = aSize.Height();
503 // take rectangle from last character and move it to the right
504 if (bWasBehindText)
505 aRes.X += aRes.Width;
507 return aRes;
510 sal_Int32 SAL_CALL SmGraphicAccessible::getCharacterCount()
512 SolarMutexGuard aGuard;
513 return GetAccessibleText_Impl().getLength();
516 sal_Int32 SAL_CALL SmGraphicAccessible::getIndexAtPoint( const awt::Point& aPoint )
518 SolarMutexGuard aGuard;
520 sal_Int32 nRes = -1;
521 if (pWin)
523 const SmNode *pTree = pWin->GetView()->GetDoc()->GetFormulaTree();
524 // can be NULL! e.g. if one clicks within the window already during loading of the
525 // document (before the parser even started)
526 if (!pTree)
527 return nRes;
529 // get position relative to formula draw position
530 Point aPos( aPoint.X, aPoint.Y );
531 aPos = pWin->PixelToLogic( aPos );
532 aPos -= pWin->GetFormulaDrawPos();
534 // if it was inside the formula then get the appropriate node
535 const SmNode *pNode = nullptr;
536 if (pTree->OrientedDist(aPos) <= 0)
537 pNode = pTree->FindRectClosestTo(aPos);
539 if (pNode)
541 // get appropriate rectangle
542 Point aOffset( pNode->GetTopLeft() - pTree->GetTopLeft() );
543 Point aTLPos ( aOffset );
544 Size aSize( pNode->GetSize() );
546 tools::Rectangle aRect( aTLPos, aSize );
547 if (aRect.IsInside( aPos ))
549 OSL_ENSURE( pNode->IsVisible(), "node is not a leaf" );
550 OUStringBuffer aBuf;
551 pNode->GetAccessibleText(aBuf);
552 OUString aTxt = aBuf.makeStringAndClear();
553 OSL_ENSURE( !aTxt.isEmpty(), "no accessible text available" );
555 long nNodeX = pNode->GetLeft();
557 long* pXAry = new long[ aTxt.getLength() ];
558 pWin->SetFont( pNode->GetFont() );
559 pWin->GetTextArray( aTxt, pXAry, 0, aTxt.getLength() );
560 for (sal_Int32 i = 0; i < aTxt.getLength() && nRes == -1; ++i)
562 if (pXAry[i] + nNodeX > aPos.X())
563 nRes = i;
565 delete[] pXAry;
566 OSL_ENSURE( nRes >= 0 && nRes < aTxt.getLength(), "index out of range" );
567 OSL_ENSURE( pNode->GetAccessibleIndex() >= 0,
568 "invalid accessible index" );
570 nRes = pNode->GetAccessibleIndex() + nRes;
574 return nRes;
577 OUString SAL_CALL SmGraphicAccessible::getSelectedText()
579 return OUString();
582 sal_Int32 SAL_CALL SmGraphicAccessible::getSelectionStart()
584 return -1;
587 sal_Int32 SAL_CALL SmGraphicAccessible::getSelectionEnd()
589 return -1;
592 sal_Bool SAL_CALL SmGraphicAccessible::setSelection(
593 sal_Int32 nStartIndex,
594 sal_Int32 nEndIndex )
596 SolarMutexGuard aGuard;
597 sal_Int32 nLen = GetAccessibleText_Impl().getLength();
598 if (!(0 <= nStartIndex && nStartIndex < nLen) ||
599 !(0 <= nEndIndex && nEndIndex < nLen))
600 throw IndexOutOfBoundsException();
601 return false;
604 OUString SAL_CALL SmGraphicAccessible::getText()
606 SolarMutexGuard aGuard;
607 return GetAccessibleText_Impl();
610 OUString SAL_CALL SmGraphicAccessible::getTextRange(
611 sal_Int32 nStartIndex,
612 sal_Int32 nEndIndex )
614 //!! nEndIndex may be the string length per definition of the interface !!
615 //!! text should be copied exclusive that end index though. And arguments
616 //!! may be switched.
618 SolarMutexGuard aGuard;
619 OUString aTxt( GetAccessibleText_Impl() );
620 sal_Int32 nStart = std::min(nStartIndex, nEndIndex);
621 sal_Int32 nEnd = std::max(nStartIndex, nEndIndex);
622 if ((nStart > aTxt.getLength()) ||
623 (nEnd > aTxt.getLength()))
624 throw IndexOutOfBoundsException();
625 return aTxt.copy( nStart, nEnd - nStart );
628 css::accessibility::TextSegment SAL_CALL SmGraphicAccessible::getTextAtIndex( sal_Int32 nIndex, sal_Int16 aTextType )
630 SolarMutexGuard aGuard;
631 OUString aTxt( GetAccessibleText_Impl() );
632 //!! nIndex is allowed to be the string length
633 if (nIndex > aTxt.getLength())
634 throw IndexOutOfBoundsException();
636 css::accessibility::TextSegment aResult;
637 aResult.SegmentStart = -1;
638 aResult.SegmentEnd = -1;
639 if ( (AccessibleTextType::CHARACTER == aTextType) && (nIndex < aTxt.getLength()) )
641 aResult.SegmentText = aTxt.copy(nIndex, 1);
642 aResult.SegmentStart = nIndex;
643 aResult.SegmentEnd = nIndex+1;
645 return aResult;
648 css::accessibility::TextSegment SAL_CALL SmGraphicAccessible::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 aTextType )
650 SolarMutexGuard aGuard;
651 OUString aTxt( GetAccessibleText_Impl() );
652 //!! nIndex is allowed to be the string length
653 if (nIndex > aTxt.getLength())
654 throw IndexOutOfBoundsException();
656 css::accessibility::TextSegment aResult;
657 aResult.SegmentStart = -1;
658 aResult.SegmentEnd = -1;
660 if ( (AccessibleTextType::CHARACTER == aTextType) && nIndex )
662 aResult.SegmentText = aTxt.copy(nIndex-1, 1);
663 aResult.SegmentStart = nIndex-1;
664 aResult.SegmentEnd = nIndex;
666 return aResult;
669 css::accessibility::TextSegment SAL_CALL SmGraphicAccessible::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 aTextType )
671 SolarMutexGuard aGuard;
672 OUString aTxt( GetAccessibleText_Impl() );
673 //!! nIndex is allowed to be the string length
674 if (nIndex > aTxt.getLength())
675 throw IndexOutOfBoundsException();
677 css::accessibility::TextSegment aResult;
678 aResult.SegmentStart = -1;
679 aResult.SegmentEnd = -1;
681 nIndex++; // text *behind*
682 if ( (AccessibleTextType::CHARACTER == aTextType) && (nIndex < aTxt.getLength()) )
684 aResult.SegmentText = aTxt.copy(nIndex, 1);
685 aResult.SegmentStart = nIndex;
686 aResult.SegmentEnd = nIndex+1;
688 return aResult;
691 sal_Bool SAL_CALL SmGraphicAccessible::copyText(
692 sal_Int32 nStartIndex,
693 sal_Int32 nEndIndex )
695 SolarMutexGuard aGuard;
696 bool bReturn = false;
698 if (!pWin)
699 throw RuntimeException();
701 Reference< datatransfer::clipboard::XClipboard > xClipboard = pWin->GetClipboard();
702 if ( xClipboard.is() )
704 OUString sText( getTextRange(nStartIndex, nEndIndex) );
706 vcl::unohelper::TextDataObject* pDataObj = new vcl::unohelper::TextDataObject( sText );
707 SolarMutexReleaser aReleaser;
708 xClipboard->setContents( pDataObj, nullptr );
710 Reference< datatransfer::clipboard::XFlushableClipboard > xFlushableClipboard( xClipboard, uno::UNO_QUERY );
711 if( xFlushableClipboard.is() )
712 xFlushableClipboard->flushClipboard();
714 bReturn = true;
718 return bReturn;
721 OUString SAL_CALL SmGraphicAccessible::getImplementationName()
723 return OUString("SmGraphicAccessible");
726 sal_Bool SAL_CALL SmGraphicAccessible::supportsService(
727 const OUString& rServiceName )
729 return cppu::supportsService(this, rServiceName);
732 Sequence< OUString > SAL_CALL SmGraphicAccessible::getSupportedServiceNames()
734 return Sequence< OUString >{
735 "css::accessibility::Accessible",
736 "css::accessibility::AccessibleComponent",
737 "css::accessibility::AccessibleContext",
738 "css::accessibility::AccessibleText"
743 SmEditSource::SmEditSource( SmEditAccessible &rAcc ) :
744 aViewFwd (rAcc),
745 aTextFwd (rAcc, *this),
746 aEditViewFwd(rAcc),
747 rEditAcc (rAcc)
751 SmEditSource::SmEditSource( const SmEditSource &rSrc ) :
752 SvxEditSource(),
753 aViewFwd (rSrc.rEditAcc),
754 aTextFwd (rSrc.rEditAcc, *this),
755 aEditViewFwd(rSrc.rEditAcc),
756 rEditAcc (rSrc.rEditAcc)
760 SmEditSource::~SmEditSource()
764 std::unique_ptr<SvxEditSource> SmEditSource::Clone() const
766 return std::unique_ptr<SvxEditSource>(new SmEditSource( *this ));
769 SvxTextForwarder* SmEditSource::GetTextForwarder()
771 return &aTextFwd;
774 SvxViewForwarder* SmEditSource::GetViewForwarder()
776 return &aViewFwd;
779 SvxEditViewForwarder* SmEditSource::GetEditViewForwarder( bool /*bCreate*/ )
781 return &aEditViewFwd;
784 void SmEditSource::UpdateData()
786 // would possibly only by needed if the XText interface is implemented
787 // and its text needs to be updated.
790 SfxBroadcaster & SmEditSource::GetBroadcaster() const
792 return const_cast<SmEditSource*>(this)->aBroadCaster;
795 SmViewForwarder::SmViewForwarder( SmEditAccessible &rAcc ) :
796 rEditAcc(rAcc)
800 SmViewForwarder::~SmViewForwarder()
804 bool SmViewForwarder::IsValid() const
806 return rEditAcc.GetEditView() != nullptr;
809 tools::Rectangle SmViewForwarder::GetVisArea() const
811 EditView *pEditView = rEditAcc.GetEditView();
812 OutputDevice* pOutDev = pEditView ? pEditView->GetWindow() : nullptr;
814 if( pOutDev && pEditView)
816 tools::Rectangle aVisArea = pEditView->GetVisArea();
818 // figure out map mode from edit engine
819 EditEngine* pEditEngine = pEditView->GetEditEngine();
821 if( pEditEngine )
823 MapMode aMapMode(pOutDev->GetMapMode());
824 aVisArea = OutputDevice::LogicToLogic( aVisArea,
825 pEditEngine->GetRefMapMode(),
826 MapMode(aMapMode.GetMapUnit()));
827 aMapMode.SetOrigin(Point());
828 return pOutDev->LogicToPixel( aVisArea, aMapMode );
832 return tools::Rectangle();
835 Point SmViewForwarder::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const
837 EditView *pEditView = rEditAcc.GetEditView();
838 OutputDevice* pOutDev = pEditView ? pEditView->GetWindow() : nullptr;
840 if( pOutDev )
842 MapMode aMapMode(pOutDev->GetMapMode());
843 Point aPoint( OutputDevice::LogicToLogic( rPoint, rMapMode,
844 MapMode(aMapMode.GetMapUnit())) );
845 aMapMode.SetOrigin(Point());
846 return pOutDev->LogicToPixel( aPoint, aMapMode );
849 return Point();
852 Point SmViewForwarder::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const
854 EditView *pEditView = rEditAcc.GetEditView();
855 OutputDevice* pOutDev = pEditView ? pEditView->GetWindow() : nullptr;
857 if( pOutDev )
859 MapMode aMapMode(pOutDev->GetMapMode());
860 aMapMode.SetOrigin(Point());
861 Point aPoint( pOutDev->PixelToLogic( rPoint, aMapMode ) );
862 return OutputDevice::LogicToLogic( aPoint,
863 MapMode(aMapMode.GetMapUnit()),
864 rMapMode );
867 return Point();
871 SmTextForwarder::SmTextForwarder( SmEditAccessible& rAcc, SmEditSource & rSource) :
872 rEditAcc ( rAcc ),
873 rEditSource (rSource)
875 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
876 if (pEditEngine)
877 pEditEngine->SetNotifyHdl( LINK(this, SmTextForwarder, NotifyHdl) );
880 SmTextForwarder::~SmTextForwarder()
882 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
883 if (pEditEngine)
884 pEditEngine->SetNotifyHdl( Link<EENotify&,void>() );
887 IMPL_LINK(SmTextForwarder, NotifyHdl, EENotify&, rNotify, void)
889 ::std::unique_ptr< SfxHint > aHint = SvxEditSourceHelper::EENotification2Hint( &rNotify );
890 if (aHint.get())
891 rEditSource.GetBroadcaster().Broadcast( *aHint.get() );
894 sal_Int32 SmTextForwarder::GetParagraphCount() const
896 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
897 return pEditEngine ? pEditEngine->GetParagraphCount() : 0;
900 sal_Int32 SmTextForwarder::GetTextLen( sal_Int32 nParagraph ) const
902 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
903 return pEditEngine ? pEditEngine->GetTextLen( nParagraph ) : 0;
906 OUString SmTextForwarder::GetText( const ESelection& rSel ) const
908 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
909 OUString aRet;
910 if (pEditEngine)
911 aRet = pEditEngine->GetText( rSel );
912 return convertLineEnd(aRet, GetSystemLineEnd());
915 SfxItemSet SmTextForwarder::GetAttribs( const ESelection& rSel, EditEngineAttribs nOnlyHardAttrib ) const
917 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
918 assert(pEditEngine && "EditEngine missing");
919 if( rSel.nStartPara == rSel.nEndPara )
921 GetAttribsFlags nFlags = GetAttribsFlags::NONE;
922 switch( nOnlyHardAttrib )
924 case EditEngineAttribs::All:
925 nFlags = GetAttribsFlags::ALL;
926 break;
927 case EditEngineAttribs::OnlyHard:
928 nFlags = GetAttribsFlags::CHARATTRIBS;
929 break;
930 default:
931 SAL_WARN("starmath", "unknown flags for SmTextForwarder::GetAttribs");
934 return pEditEngine->GetAttribs( rSel.nStartPara, rSel.nStartPos, rSel.nEndPos, nFlags );
936 else
938 return pEditEngine->GetAttribs( rSel, nOnlyHardAttrib );
942 SfxItemSet SmTextForwarder::GetParaAttribs( sal_Int32 nPara ) const
944 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
945 assert(pEditEngine && "EditEngine missing");
947 SfxItemSet aSet( pEditEngine->GetParaAttribs( nPara ) );
949 sal_uInt16 nWhich = EE_PARA_START;
950 while( nWhich <= EE_PARA_END )
952 if( aSet.GetItemState( nWhich ) != SfxItemState::SET )
954 if( pEditEngine->HasParaAttrib( nPara, nWhich ) )
955 aSet.Put( pEditEngine->GetParaAttrib( nPara, nWhich ) );
957 nWhich++;
960 return aSet;
963 void SmTextForwarder::SetParaAttribs( sal_Int32 nPara, const SfxItemSet& rSet )
965 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
966 if (pEditEngine)
967 pEditEngine->SetParaAttribs( nPara, rSet );
970 SfxItemPool* SmTextForwarder::GetPool() const
972 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
973 return pEditEngine ? pEditEngine->GetEmptyItemSet().GetPool() : nullptr;
976 void SmTextForwarder::RemoveAttribs( const ESelection& rSelection )
978 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
979 if (pEditEngine)
980 pEditEngine->RemoveAttribs( rSelection, false/*bRemoveParaAttribs*/, 0 );
983 void SmTextForwarder::GetPortions( sal_Int32 nPara, std::vector<sal_Int32>& rList ) const
985 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
986 if (pEditEngine)
987 pEditEngine->GetPortions( nPara, rList );
990 void SmTextForwarder::QuickInsertText( const OUString& rText, const ESelection& rSel )
992 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
993 if (pEditEngine)
994 pEditEngine->QuickInsertText( rText, rSel );
997 void SmTextForwarder::QuickInsertLineBreak( const ESelection& rSel )
999 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1000 if (pEditEngine)
1001 pEditEngine->QuickInsertLineBreak( rSel );
1004 void SmTextForwarder::QuickInsertField( const SvxFieldItem& rFld, const ESelection& rSel )
1006 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1007 if (pEditEngine)
1008 pEditEngine->QuickInsertField( rFld, rSel );
1011 void SmTextForwarder::QuickSetAttribs( const SfxItemSet& rSet, const ESelection& rSel )
1013 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1014 if (pEditEngine)
1015 pEditEngine->QuickSetAttribs( rSet, rSel );
1018 bool SmTextForwarder::IsValid() const
1020 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1021 // cannot reliably query EditEngine state
1022 // while in the middle of an update
1023 return pEditEngine && pEditEngine->GetUpdateMode();
1026 OUString SmTextForwarder::CalcFieldValue( const SvxFieldItem& rField, sal_Int32 nPara, sal_Int32 nPos, boost::optional<Color>& rpTxtColor, boost::optional<Color>& rpFldColor )
1028 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1029 return pEditEngine ? pEditEngine->CalcFieldValue(rField, nPara, nPos, rpTxtColor, rpFldColor) : OUString();
1032 void SmTextForwarder::FieldClicked(const SvxFieldItem&, sal_Int32, sal_Int32)
1036 static SfxItemState GetSvxEditEngineItemState( EditEngine const & rEditEngine, const ESelection& rSel, sal_uInt16 nWhich )
1038 std::vector<EECharAttrib> aAttribs;
1040 const SfxPoolItem* pLastItem = nullptr;
1042 SfxItemState eState = SfxItemState::DEFAULT;
1044 // check all paragraphs inside the selection
1045 for( sal_Int32 nPara = rSel.nStartPara; nPara <= rSel.nEndPara; nPara++ )
1047 SfxItemState eParaState = SfxItemState::DEFAULT;
1049 // calculate start and endpos for this paragraph
1050 sal_Int32 nPos = 0;
1051 if( rSel.nStartPara == nPara )
1052 nPos = rSel.nStartPos;
1054 sal_Int32 nEndPos = rSel.nEndPos;
1055 if( rSel.nEndPara != nPara )
1056 nEndPos = rEditEngine.GetTextLen( nPara );
1059 // get list of char attribs
1060 rEditEngine.GetCharAttribs( nPara, aAttribs );
1062 bool bEmpty = true; // we found no item inside the selection of this paragraph
1063 bool bGaps = false; // we found items but theire gaps between them
1064 sal_Int32 nLastEnd = nPos;
1066 const SfxPoolItem* pParaItem = nullptr;
1068 for(std::vector<EECharAttrib>::const_iterator i = aAttribs.begin(); i < aAttribs.end(); ++i)
1070 OSL_ENSURE( i->pAttr, "GetCharAttribs gives corrupt data" );
1072 const bool bEmptyPortion = (i->nStart == i->nEnd);
1073 if( (!bEmptyPortion && (i->nStart >= nEndPos)) || (bEmptyPortion && (i->nStart > nEndPos)) )
1074 break; // break if we are already behind our selection
1076 if( (!bEmptyPortion && (i->nEnd <= nPos)) || (bEmptyPortion && (i->nEnd < nPos)) )
1077 continue; // or if the attribute ends before our selection
1079 if( i->pAttr->Which() != nWhich )
1080 continue; // skip if is not the searched item
1082 // if we already found an item
1083 if( pParaItem )
1085 // ... and its different to this one than the state is don't care
1086 if( *pParaItem != *(i->pAttr) )
1087 return SfxItemState::DONTCARE;
1089 else
1091 pParaItem = i->pAttr;
1094 if( bEmpty )
1095 bEmpty = false;
1097 if( !bGaps && i->nStart > nLastEnd )
1098 bGaps = true;
1100 nLastEnd = i->nEnd;
1103 if( !bEmpty && !bGaps && nLastEnd < ( nEndPos - 1 ) )
1104 bGaps = true;
1105 if( bEmpty )
1106 eParaState = SfxItemState::DEFAULT;
1107 else if( bGaps )
1108 eParaState = SfxItemState::DONTCARE;
1109 else
1110 eParaState = SfxItemState::SET;
1112 // if we already found an item check if we found the same
1113 if( pLastItem )
1115 if( (pParaItem == nullptr) || (*pLastItem != *pParaItem) )
1116 return SfxItemState::DONTCARE;
1118 else
1120 pLastItem = pParaItem;
1121 eState = eParaState;
1125 return eState;
1128 SfxItemState SmTextForwarder::GetItemState( const ESelection& rSel, sal_uInt16 nWhich ) const
1130 SfxItemState nState = SfxItemState::DISABLED;
1131 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1132 if (pEditEngine)
1133 nState = GetSvxEditEngineItemState( *pEditEngine, rSel, nWhich );
1134 return nState;
1137 SfxItemState SmTextForwarder::GetItemState( sal_Int32 nPara, sal_uInt16 nWhich ) const
1139 SfxItemState nState = SfxItemState::DISABLED;
1140 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1141 if (pEditEngine)
1143 const SfxItemSet& rSet = pEditEngine->GetParaAttribs( nPara );
1144 nState = rSet.GetItemState( nWhich );
1146 return nState;
1149 LanguageType SmTextForwarder::GetLanguage( sal_Int32 nPara, sal_Int32 nIndex ) const
1151 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1152 return pEditEngine ? pEditEngine->GetLanguage(nPara, nIndex) : LANGUAGE_NONE;
1155 sal_Int32 SmTextForwarder::GetFieldCount( sal_Int32 nPara ) const
1157 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1158 return pEditEngine ? pEditEngine->GetFieldCount(nPara) : 0;
1161 EFieldInfo SmTextForwarder::GetFieldInfo( sal_Int32 nPara, sal_uInt16 nField ) const
1163 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1164 return pEditEngine ? pEditEngine->GetFieldInfo( nPara, nField ) : EFieldInfo();
1167 EBulletInfo SmTextForwarder::GetBulletInfo( sal_Int32 /*nPara*/ ) const
1169 return EBulletInfo();
1172 tools::Rectangle SmTextForwarder::GetCharBounds( sal_Int32 nPara, sal_Int32 nIndex ) const
1174 tools::Rectangle aRect(0,0,0,0);
1175 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1177 if (pEditEngine)
1179 // Handle virtual position one-past-the end of the string
1180 if( nIndex >= pEditEngine->GetTextLen(nPara) )
1182 if( nIndex )
1183 aRect = pEditEngine->GetCharacterBounds( EPosition(nPara, nIndex-1) );
1185 aRect.Move( aRect.Right() - aRect.Left(), 0 );
1186 aRect.SetSize( Size(1, pEditEngine->GetTextHeight()) );
1188 else
1190 aRect = pEditEngine->GetCharacterBounds( EPosition(nPara, nIndex) );
1193 return aRect;
1196 tools::Rectangle SmTextForwarder::GetParaBounds( sal_Int32 nPara ) const
1198 tools::Rectangle aRect(0,0,0,0);
1199 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1201 if (pEditEngine)
1203 const Point aPnt = pEditEngine->GetDocPosTopLeft( nPara );
1204 const sal_uLong nWidth = pEditEngine->CalcTextWidth();
1205 const sal_uLong nHeight = pEditEngine->GetTextHeight( nPara );
1206 aRect = tools::Rectangle( aPnt.X(), aPnt.Y(), aPnt.X() + nWidth, aPnt.Y() + nHeight );
1209 return aRect;
1212 MapMode SmTextForwarder::GetMapMode() const
1214 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1215 return pEditEngine ? pEditEngine->GetRefMapMode() : MapMode( MapUnit::Map100thMM );
1218 OutputDevice* SmTextForwarder::GetRefDevice() const
1220 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1221 return pEditEngine ? pEditEngine->GetRefDevice() : nullptr;
1224 bool SmTextForwarder::GetIndexAtPoint( const Point& rPos, sal_Int32& nPara, sal_Int32& nIndex ) const
1226 bool bRes = false;
1227 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1228 if (pEditEngine)
1230 EPosition aDocPos = pEditEngine->FindDocPosition( rPos );
1231 nPara = aDocPos.nPara;
1232 nIndex = aDocPos.nIndex;
1233 bRes = true;
1235 return bRes;
1238 bool SmTextForwarder::GetWordIndices( sal_Int32 nPara, sal_Int32 nIndex, sal_Int32& nStart, sal_Int32& nEnd ) const
1240 bool bRes = false;
1241 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1242 if (pEditEngine)
1244 ESelection aRes = pEditEngine->GetWord( ESelection(nPara, nIndex, nPara, nIndex), css::i18n::WordType::DICTIONARY_WORD );
1246 if( aRes.nStartPara == nPara &&
1247 aRes.nStartPara == aRes.nEndPara )
1249 nStart = aRes.nStartPos;
1250 nEnd = aRes.nEndPos;
1252 bRes = true;
1256 return bRes;
1259 bool SmTextForwarder::GetAttributeRun( sal_Int32& nStartIndex, sal_Int32& nEndIndex, sal_Int32 nPara, sal_Int32 nIndex, bool bInCell ) const
1261 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1262 return pEditEngine &&
1263 SvxEditSourceHelper::GetAttributeRun( nStartIndex, nEndIndex, *pEditEngine, nPara, nIndex, bInCell );
1266 sal_Int32 SmTextForwarder::GetLineCount( sal_Int32 nPara ) const
1268 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1269 return pEditEngine ? pEditEngine->GetLineCount(nPara) : 0;
1272 sal_Int32 SmTextForwarder::GetLineLen( sal_Int32 nPara, sal_Int32 nLine ) const
1274 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1275 return pEditEngine ? pEditEngine->GetLineLen(nPara, nLine) : 0;
1278 void SmTextForwarder::GetLineBoundaries( /*out*/sal_Int32 &rStart, /*out*/sal_Int32 &rEnd, sal_Int32 nPara, sal_Int32 nLine ) const
1280 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1281 if (pEditEngine)
1282 pEditEngine->GetLineBoundaries(rStart, rEnd, nPara, nLine);
1283 else
1284 rStart = rEnd = 0;
1287 sal_Int32 SmTextForwarder::GetLineNumberAtIndex( sal_Int32 nPara, sal_Int32 nIndex ) const
1289 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1290 return pEditEngine ? pEditEngine->GetLineNumberAtIndex(nPara, nIndex) : 0;
1293 bool SmTextForwarder::QuickFormatDoc( bool /*bFull*/ )
1295 bool bRes = false;
1296 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1297 if (pEditEngine)
1299 pEditEngine->QuickFormatDoc();
1300 bRes = true;
1302 return bRes;
1305 sal_Int16 SmTextForwarder::GetDepth( sal_Int32 /*nPara*/ ) const
1307 // math has no outliner...
1308 return -1;
1311 bool SmTextForwarder::SetDepth( sal_Int32 /*nPara*/, sal_Int16 nNewDepth )
1313 // math has no outliner...
1314 return -1 == nNewDepth; // is it the value from 'GetDepth' ?
1317 bool SmTextForwarder::Delete( const ESelection& rSelection )
1319 bool bRes = false;
1320 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1321 if (pEditEngine)
1323 pEditEngine->QuickDelete( rSelection );
1324 pEditEngine->QuickFormatDoc();
1325 bRes = true;
1327 return bRes;
1330 bool SmTextForwarder::InsertText( const OUString& rStr, const ESelection& rSelection )
1332 bool bRes = false;
1333 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1334 if (pEditEngine)
1336 pEditEngine->QuickInsertText( rStr, rSelection );
1337 pEditEngine->QuickFormatDoc();
1338 bRes = true;
1340 return bRes;
1343 const SfxItemSet* SmTextForwarder::GetEmptyItemSetPtr()
1345 const SfxItemSet *pItemSet = nullptr;
1346 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1347 if (pEditEngine)
1349 pItemSet = &pEditEngine->GetEmptyItemSet();
1351 return pItemSet;
1354 void SmTextForwarder::AppendParagraph()
1356 // append an empty paragraph
1357 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1358 if (pEditEngine)
1360 sal_Int32 nParaCount = pEditEngine->GetParagraphCount();
1361 pEditEngine->InsertParagraph( nParaCount, OUString() );
1365 sal_Int32 SmTextForwarder::AppendTextPortion( sal_Int32 nPara, const OUString &rText, const SfxItemSet &rSet )
1367 sal_uInt16 nRes = 0;
1368 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1369 if (pEditEngine && nPara < pEditEngine->GetParagraphCount())
1371 // append text
1372 ESelection aSel( nPara, pEditEngine->GetTextLen( nPara ) );
1373 pEditEngine->QuickInsertText( rText, aSel );
1375 // set attributes for new appended text
1376 nRes = aSel.nEndPos = pEditEngine->GetTextLen( nPara );
1377 pEditEngine->QuickSetAttribs( rSet, aSel );
1379 return nRes;
1382 void SmTextForwarder::CopyText(const SvxTextForwarder& rSource)
1385 const SmTextForwarder* pSourceForwarder = dynamic_cast< const SmTextForwarder* >( &rSource );
1386 if( !pSourceForwarder )
1387 return;
1388 EditEngine* pSourceEditEngine = pSourceForwarder->rEditAcc.GetEditEngine();
1389 EditEngine *pEditEngine = rEditAcc.GetEditEngine();
1390 if (pEditEngine && pSourceEditEngine )
1392 std::unique_ptr<EditTextObject> pNewTextObject = pSourceEditEngine->CreateTextObject();
1393 pEditEngine->SetText( *pNewTextObject );
1398 SmEditViewForwarder::SmEditViewForwarder( SmEditAccessible& rAcc ) :
1399 rEditAcc( rAcc )
1403 SmEditViewForwarder::~SmEditViewForwarder()
1407 bool SmEditViewForwarder::IsValid() const
1409 return rEditAcc.GetEditView() != nullptr;
1412 tools::Rectangle SmEditViewForwarder::GetVisArea() const
1414 tools::Rectangle aRect(0,0,0,0);
1416 EditView *pEditView = rEditAcc.GetEditView();
1417 OutputDevice* pOutDev = pEditView ? pEditView->GetWindow() : nullptr;
1419 if( pOutDev && pEditView)
1421 tools::Rectangle aVisArea = pEditView->GetVisArea();
1423 // figure out map mode from edit engine
1424 EditEngine* pEditEngine = pEditView->GetEditEngine();
1426 if( pEditEngine )
1428 MapMode aMapMode(pOutDev->GetMapMode());
1429 aVisArea = OutputDevice::LogicToLogic( aVisArea,
1430 pEditEngine->GetRefMapMode(),
1431 MapMode(aMapMode.GetMapUnit()));
1432 aMapMode.SetOrigin(Point());
1433 aRect = pOutDev->LogicToPixel( aVisArea, aMapMode );
1437 return aRect;
1440 Point SmEditViewForwarder::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const
1442 EditView *pEditView = rEditAcc.GetEditView();
1443 OutputDevice* pOutDev = pEditView ? pEditView->GetWindow() : nullptr;
1445 if( pOutDev )
1447 MapMode aMapMode(pOutDev->GetMapMode());
1448 Point aPoint( OutputDevice::LogicToLogic( rPoint, rMapMode,
1449 MapMode(aMapMode.GetMapUnit())));
1450 aMapMode.SetOrigin(Point());
1451 return pOutDev->LogicToPixel( aPoint, aMapMode );
1454 return Point();
1457 Point SmEditViewForwarder::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const
1459 EditView *pEditView = rEditAcc.GetEditView();
1460 OutputDevice* pOutDev = pEditView ? pEditView->GetWindow() : nullptr;
1462 if( pOutDev )
1464 MapMode aMapMode(pOutDev->GetMapMode());
1465 aMapMode.SetOrigin(Point());
1466 Point aPoint( pOutDev->PixelToLogic( rPoint, aMapMode ) );
1467 return OutputDevice::LogicToLogic( aPoint,
1468 MapMode(aMapMode.GetMapUnit()),
1469 rMapMode );
1472 return Point();
1475 bool SmEditViewForwarder::GetSelection( ESelection& rSelection ) const
1477 bool bRes = false;
1478 EditView *pEditView = rEditAcc.GetEditView();
1479 if (pEditView)
1481 rSelection = pEditView->GetSelection();
1482 bRes = true;
1484 return bRes;
1487 bool SmEditViewForwarder::SetSelection( const ESelection& rSelection )
1489 bool bRes = false;
1490 EditView *pEditView = rEditAcc.GetEditView();
1491 if (pEditView)
1493 pEditView->SetSelection( rSelection );
1494 bRes = true;
1496 return bRes;
1499 bool SmEditViewForwarder::Copy()
1501 bool bRes = false;
1502 EditView *pEditView = rEditAcc.GetEditView();
1503 if (pEditView)
1505 pEditView->Copy();
1506 bRes = true;
1508 return bRes;
1511 bool SmEditViewForwarder::Cut()
1513 bool bRes = false;
1514 EditView *pEditView = rEditAcc.GetEditView();
1515 if (pEditView)
1517 pEditView->Cut();
1518 bRes = true;
1520 return bRes;
1523 bool SmEditViewForwarder::Paste()
1525 bool bRes = false;
1526 EditView *pEditView = rEditAcc.GetEditView();
1527 if (pEditView)
1529 pEditView->Paste();
1530 bRes = true;
1532 return bRes;
1536 SmEditAccessible::SmEditAccessible( SmEditWindow *pEditWin ) :
1537 aAccName (SmResId(STR_CMDBOXWINDOW)),
1538 pTextHelper (),
1539 pWin (pEditWin)
1541 OSL_ENSURE( pWin, "SmEditAccessible: window missing" );
1544 SmEditAccessible::~SmEditAccessible()
1548 ::accessibility::AccessibleTextHelper *SmEditAccessible::GetTextHelper()
1550 return pTextHelper.get();
1553 void SmEditAccessible::Init()
1555 OSL_ENSURE( pWin, "SmEditAccessible: window missing" );
1556 if (pWin)
1558 EditEngine *pEditEngine = pWin->GetEditEngine();
1559 EditView *pEditView = pWin->GetEditView();
1560 if (pEditEngine && pEditView)
1562 assert(!pTextHelper);
1563 pTextHelper.reset(new ::accessibility::AccessibleTextHelper( o3tl::make_unique<SmEditSource>( *this ) ));
1564 pTextHelper->SetEventSource( this );
1569 void SmEditAccessible::ClearWin()
1571 // remove handler before current object gets destroyed
1572 // (avoid handler being called for already dead object)
1573 EditEngine *pEditEngine = GetEditEngine();
1574 if (pEditEngine)
1575 pEditEngine->SetNotifyHdl( Link<EENotify&,void>() );
1577 pWin = nullptr; // implicitly results in AccessibleStateType::DEFUNC set
1579 //! make TextHelper implicitly release C++ references to some core objects
1580 pTextHelper->SetEditSource( ::std::unique_ptr<SvxEditSource>() );
1581 //! make TextHelper release references
1582 //! (e.g. the one set by the 'SetEventSource' call)
1583 pTextHelper->Dispose();
1584 pTextHelper.reset();
1587 // XAccessible
1588 uno::Reference< XAccessibleContext > SAL_CALL SmEditAccessible::getAccessibleContext( )
1590 return this;
1593 // XAccessibleComponent
1594 sal_Bool SAL_CALL SmEditAccessible::containsPoint( const awt::Point& aPoint )
1596 //! the arguments coordinates are relative to the current window !
1597 //! Thus the top left-point is (0, 0)
1599 SolarMutexGuard aGuard;
1600 if (!pWin)
1601 throw RuntimeException();
1603 Size aSz( pWin->GetSizePixel() );
1604 return aPoint.X >= 0 && aPoint.Y >= 0 &&
1605 aPoint.X < aSz.Width() && aPoint.Y < aSz.Height();
1608 uno::Reference< XAccessible > SAL_CALL SmEditAccessible::getAccessibleAtPoint( const awt::Point& aPoint )
1610 SolarMutexGuard aGuard;
1611 if (!pTextHelper)
1612 throw RuntimeException();
1613 return pTextHelper->GetAt( aPoint );
1616 awt::Rectangle SAL_CALL SmEditAccessible::getBounds( )
1618 SolarMutexGuard aGuard;
1619 if (!pWin)
1620 throw RuntimeException();
1621 OSL_ENSURE(pWin->GetParent()->GetAccessible() == getAccessibleParent(),
1622 "mismatch of window parent and accessible parent" );
1623 return lcl_GetBounds( pWin );
1626 awt::Point SAL_CALL SmEditAccessible::getLocation( )
1628 SolarMutexGuard aGuard;
1629 if (!pWin)
1630 throw RuntimeException();
1631 OSL_ENSURE(pWin->GetParent()->GetAccessible() == getAccessibleParent(),
1632 "mismatch of window parent and accessible parent" );
1633 awt::Rectangle aRect( lcl_GetBounds( pWin ) );
1634 return awt::Point( aRect.X, aRect.Y );
1637 awt::Point SAL_CALL SmEditAccessible::getLocationOnScreen( )
1639 SolarMutexGuard aGuard;
1640 if (!pWin)
1641 throw RuntimeException();
1642 OSL_ENSURE(pWin->GetParent()->GetAccessible() == getAccessibleParent(),
1643 "mismatch of window parent and accessible parent" );
1644 return lcl_GetLocationOnScreen( pWin );
1647 awt::Size SAL_CALL SmEditAccessible::getSize( )
1649 SolarMutexGuard aGuard;
1650 if (!pWin)
1651 throw RuntimeException();
1652 OSL_ENSURE(pWin->GetParent()->GetAccessible() == getAccessibleParent(),
1653 "mismatch of window parent and accessible parent" );
1655 Size aSz( pWin->GetSizePixel() );
1656 #if OSL_DEBUG_LEVEL > 0
1657 awt::Rectangle aRect( lcl_GetBounds( pWin ) );
1658 Size aSz2( aRect.Width, aRect.Height );
1659 assert(aSz == aSz2 && "mismatch in width");
1660 #endif
1661 return awt::Size( aSz.Width(), aSz.Height() );
1664 void SAL_CALL SmEditAccessible::grabFocus( )
1666 SolarMutexGuard aGuard;
1667 if (!pWin)
1668 throw RuntimeException();
1670 pWin->GrabFocus();
1673 sal_Int32 SAL_CALL SmEditAccessible::getForeground()
1675 SolarMutexGuard aGuard;
1677 if (!pWin)
1678 throw RuntimeException();
1679 return static_cast<sal_Int32>(pWin->GetTextColor());
1682 sal_Int32 SAL_CALL SmEditAccessible::getBackground()
1684 SolarMutexGuard aGuard;
1686 if (!pWin)
1687 throw RuntimeException();
1688 Wallpaper aWall( pWin->GetDisplayBackground() );
1689 Color nCol;
1690 if (aWall.IsBitmap() || aWall.IsGradient())
1691 nCol = pWin->GetSettings().GetStyleSettings().GetWindowColor();
1692 else
1693 nCol = aWall.GetColor();
1694 return static_cast<sal_Int32>(nCol);
1697 // XAccessibleContext
1698 sal_Int32 SAL_CALL SmEditAccessible::getAccessibleChildCount( )
1700 SolarMutexGuard aGuard;
1701 if (!pTextHelper)
1702 throw RuntimeException();
1703 return pTextHelper->GetChildCount();
1706 uno::Reference< XAccessible > SAL_CALL SmEditAccessible::getAccessibleChild( sal_Int32 i )
1708 SolarMutexGuard aGuard;
1709 if (!pTextHelper)
1710 throw RuntimeException();
1711 return pTextHelper->GetChild( i );
1714 uno::Reference< XAccessible > SAL_CALL SmEditAccessible::getAccessibleParent( )
1716 SolarMutexGuard aGuard;
1717 if (!pWin)
1718 throw RuntimeException();
1720 vcl::Window *pAccParent = pWin->GetAccessibleParentWindow();
1721 OSL_ENSURE( pAccParent, "accessible parent missing" );
1722 return pAccParent ? pAccParent->GetAccessible() : Reference< XAccessible >();
1725 sal_Int32 SAL_CALL SmEditAccessible::getAccessibleIndexInParent( )
1727 SolarMutexGuard aGuard;
1728 sal_Int32 nIdx = -1;
1729 vcl::Window *pAccParent = pWin ? pWin->GetAccessibleParentWindow() : nullptr;
1730 if (pAccParent)
1732 sal_uInt16 nCnt = pAccParent->GetAccessibleChildWindowCount();
1733 for (sal_uInt16 i = 0; i < nCnt && nIdx == -1; ++i)
1734 if (pAccParent->GetAccessibleChildWindow( i ) == pWin)
1735 nIdx = i;
1737 return nIdx;
1740 sal_Int16 SAL_CALL SmEditAccessible::getAccessibleRole( )
1742 return AccessibleRole::PANEL /*TEXT ?*/;
1745 OUString SAL_CALL SmEditAccessible::getAccessibleDescription( )
1747 return OUString(); // empty as agreed with product-management
1750 OUString SAL_CALL SmEditAccessible::getAccessibleName( )
1752 SolarMutexGuard aGuard;
1753 // same name as displayed by the window when not docked
1754 return aAccName;
1757 uno::Reference< XAccessibleRelationSet > SAL_CALL SmEditAccessible::getAccessibleRelationSet( )
1759 Reference< XAccessibleRelationSet > xRelSet = new utl::AccessibleRelationSetHelper();
1760 return xRelSet; // empty relation set
1763 uno::Reference< XAccessibleStateSet > SAL_CALL SmEditAccessible::getAccessibleStateSet( )
1765 SolarMutexGuard aGuard;
1766 ::utl::AccessibleStateSetHelper *pStateSet =
1767 new ::utl::AccessibleStateSetHelper;
1769 Reference<XAccessibleStateSet> xStateSet( pStateSet );
1771 if (!pWin || !pTextHelper)
1772 pStateSet->AddState( AccessibleStateType::DEFUNC );
1773 else
1775 pStateSet->AddState( AccessibleStateType::MULTI_LINE );
1776 pStateSet->AddState( AccessibleStateType::ENABLED );
1777 pStateSet->AddState( AccessibleStateType::FOCUSABLE );
1778 if (pWin->HasFocus())
1779 pStateSet->AddState( AccessibleStateType::FOCUSED );
1780 if (pWin->IsActive())
1781 pStateSet->AddState( AccessibleStateType::ACTIVE );
1782 if (pWin->IsVisible())
1783 pStateSet->AddState( AccessibleStateType::SHOWING );
1784 if (pWin->IsReallyVisible())
1785 pStateSet->AddState( AccessibleStateType::VISIBLE );
1786 if (COL_TRANSPARENT != pWin->GetBackground().GetColor())
1787 pStateSet->AddState( AccessibleStateType::OPAQUE );
1790 return xStateSet;
1793 Locale SAL_CALL SmEditAccessible::getLocale( )
1795 SolarMutexGuard aGuard;
1796 // should be the document language...
1797 // We use the language of the localized symbol names here.
1798 return Application::GetSettings().GetUILanguageTag().getLocale();
1802 // XAccessibleEventBroadcaster
1803 void SAL_CALL SmEditAccessible::addAccessibleEventListener( const uno::Reference< XAccessibleEventListener >& xListener )
1805 if (pTextHelper) // not disposing (about to destroy view shell)
1806 pTextHelper->AddEventListener( xListener );
1809 void SAL_CALL SmEditAccessible::removeAccessibleEventListener( const uno::Reference< XAccessibleEventListener >& xListener )
1811 if (pTextHelper) // not disposing (about to destroy view shell)
1812 pTextHelper->RemoveEventListener( xListener );
1815 OUString SAL_CALL SmEditAccessible::getImplementationName()
1817 return OUString("SmEditAccessible");
1820 sal_Bool SAL_CALL SmEditAccessible::supportsService(
1821 const OUString& rServiceName )
1823 return cppu::supportsService(this, rServiceName);
1826 Sequence< OUString > SAL_CALL SmEditAccessible::getSupportedServiceNames()
1828 return Sequence< OUString >{
1829 "css::accessibility::Accessible",
1830 "css::accessibility::AccessibleComponent",
1831 "css::accessibility::AccessibleContext"
1836 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */