1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
25 #include <AccessibleEditObject.hxx>
26 #include <AccessibleText.hxx>
27 #include <editsrc.hxx>
29 #include <inputhdl.hxx>
30 #include <inputwin.hxx>
32 #include <com/sun/star/accessibility/AccessibleRole.hpp>
33 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
34 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
35 #include <com/sun/star/sheet/XSpreadsheet.hpp>
36 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
37 #include <svx/AccessibleTextHelper.hxx>
38 #include <editeng/editview.hxx>
39 #include <editeng/editeng.hxx>
40 #include <svx/svdmodel.hxx>
41 #include <vcl/svapp.hxx>
42 #include <vcl/window.hxx>
43 #include <sfx2/objsh.hxx>
44 #include <cppuhelper/queryinterface.hxx>
46 #include <unonames.hxx>
47 #include <document.hxx>
48 #include <AccessibleDocument.hxx>
49 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
50 #include <unotools/accessiblerelationsethelper.hxx>
51 #include <com/sun/star/accessibility/XAccessibleText.hpp>
53 using ::com::sun::star::lang::IndexOutOfBoundsException
;
54 using namespace ::com::sun::star
;
55 using namespace ::com::sun::star::accessibility
;
57 //===== internal ============================================================
59 ScAccessibleEditObject::ScAccessibleEditObject(
60 const uno::Reference
<XAccessible
>& rxParent
,
61 EditView
* pEditView
, vcl::Window
* pWin
, const OUString
& rName
,
62 const OUString
& rDescription
, EditObjectType eObjectType
)
63 : ScAccessibleContextBase(rxParent
, AccessibleRole::TEXT_FRAME
)
64 , mpEditView(pEditView
)
67 , meObjectType(eObjectType
)
71 InitAcc(rxParent
, pEditView
, rName
, rDescription
);
74 ScAccessibleEditObject::ScAccessibleEditObject(EditObjectType eObjectType
)
75 : ScAccessibleContextBase(nullptr, AccessibleRole::TEXT_FRAME
)
79 , meObjectType(eObjectType
)
85 void ScAccessibleEditObject::InitAcc(
86 const uno::Reference
<XAccessible
>& rxParent
,
88 const OUString
& rName
,
89 const OUString
& rDescription
)
92 mpEditView
= pEditView
;
96 SetDescription(rDescription
);
97 if( meObjectType
== CellInEditMode
)
99 const ScAccessibleDocument
*pAccDoc
= static_cast<ScAccessibleDocument
*>(rxParent
.get());
102 m_pScDoc
= pAccDoc
->GetDocument();
103 m_curCellAddress
=pAccDoc
->GetCurCellAddress();
108 ScAccessibleEditObject::~ScAccessibleEditObject()
110 if (!ScAccessibleContextBase::IsDefunc() && !rBHelper
.bInDispose
)
112 // increment refcount to prevent double call off dtor
113 osl_atomic_increment( &m_refCount
);
114 // call dispose to inform object which have a weak reference to this object
119 void SAL_CALL
ScAccessibleEditObject::disposing()
121 SolarMutexGuard aGuard
;
122 mpTextHelper
.reset();
124 ScAccessibleContextBase::disposing();
127 void ScAccessibleEditObject::LostFocus()
131 mpTextHelper
->SetFocus(false);
135 void ScAccessibleEditObject::GotFocus()
140 mpTextHelper
->SetFocus();
143 //===== XInterface ==========================================================
145 css::uno::Any SAL_CALL
146 ScAccessibleEditObject::queryInterface (const css::uno::Type
& rType
)
148 css::uno::Any aReturn
= ScAccessibleContextBase::queryInterface (rType
);
149 if ( ! aReturn
.hasValue())
150 aReturn
= ::cppu::queryInterface (rType
,
151 static_cast< css::accessibility::XAccessibleSelection
* >(this)
156 ScAccessibleEditObject::acquire()
159 ScAccessibleContextBase::acquire ();
162 ScAccessibleEditObject::release()
165 ScAccessibleContextBase::release ();
167 //===== XAccessibleComponent ============================================
169 uno::Reference
< XAccessible
> SAL_CALL
ScAccessibleEditObject::getAccessibleAtPoint(
170 const awt::Point
& rPoint
)
172 uno::Reference
<XAccessible
> xRet
;
173 if (containsPoint(rPoint
))
175 SolarMutexGuard aGuard
;
180 xRet
= mpTextHelper
->GetAt(rPoint
);
186 AbsoluteScreenPixelRectangle
ScAccessibleEditObject::GetBoundingBoxOnScreen() const
188 AbsoluteScreenPixelRectangle aScreenBounds
;
192 if ( meObjectType
== CellInEditMode
)
196 MapMode
aMapMode(mpEditView
->getEditEngine().GetRefMapMode());
197 tools::Rectangle aScreenBoundsLog
= mpWindow
->LogicToPixel( mpEditView
->GetOutputArea(), aMapMode
);
198 Point aCellLoc
= aScreenBoundsLog
.TopLeft();
199 AbsoluteScreenPixelRectangle aWindowRect
= mpWindow
->GetWindowExtentsAbsolute();
200 AbsoluteScreenPixelPoint aWindowLoc
= aWindowRect
.TopLeft();
201 AbsoluteScreenPixelPoint
aPos( aCellLoc
.getX() + aWindowLoc
.getX(), aCellLoc
.getY() + aWindowLoc
.getY() );
202 aScreenBounds
= AbsoluteScreenPixelRectangle( aPos
, aScreenBoundsLog
.GetSize() );
207 aScreenBounds
= mpWindow
->GetWindowExtentsAbsolute();
211 return aScreenBounds
;
214 tools::Rectangle
ScAccessibleEditObject::GetBoundingBox() const
216 tools::Rectangle
aBounds( GetBoundingBoxOnScreen() );
220 uno::Reference
< XAccessible
> xThis( mpWindow
->GetAccessible() );
223 uno::Reference
< XAccessibleContext
> xContext( xThis
->getAccessibleContext() );
226 uno::Reference
< XAccessible
> xParent( xContext
->getAccessibleParent() );
229 uno::Reference
< XAccessibleComponent
> xParentComponent( xParent
->getAccessibleContext(), uno::UNO_QUERY
);
230 if ( xParentComponent
.is() )
232 Point aScreenLoc
= aBounds
.TopLeft();
233 awt::Point aParentScreenLoc
= xParentComponent
->getLocationOnScreen();
234 Point
aPos( aScreenLoc
.getX() - aParentScreenLoc
.X
, aScreenLoc
.getY() - aParentScreenLoc
.Y
);
235 aBounds
.SetPos( aPos
);
245 //===== XAccessibleContext ==============================================
248 ScAccessibleEditObject::getAccessibleChildCount()
250 SolarMutexGuard aGuard
;
253 return mpTextHelper
->GetChildCount();
256 uno::Reference
< XAccessible
> SAL_CALL
257 ScAccessibleEditObject::getAccessibleChild(sal_Int64 nIndex
)
259 SolarMutexGuard aGuard
;
262 return mpTextHelper
->GetChild(nIndex
);
265 sal_Int64 SAL_CALL
ScAccessibleEditObject::getAccessibleStateSet()
267 SolarMutexGuard aGuard
;
268 sal_Int64 nParentStates
= 0;
269 if (getAccessibleParent().is())
271 uno::Reference
<XAccessibleContext
> xParentContext
= getAccessibleParent()->getAccessibleContext();
272 nParentStates
= xParentContext
->getAccessibleStateSet();
274 sal_Int64 nStateSet
= 0;
275 if (IsDefunc(nParentStates
))
276 nStateSet
|= AccessibleStateType::DEFUNC
;
279 // all states are const, because this object exists only in one state
280 nStateSet
|= AccessibleStateType::EDITABLE
;
281 nStateSet
|= AccessibleStateType::ENABLED
;
282 nStateSet
|= AccessibleStateType::SENSITIVE
;
283 nStateSet
|= AccessibleStateType::MULTI_LINE
;
284 nStateSet
|= AccessibleStateType::MULTI_SELECTABLE
;
285 nStateSet
|= AccessibleStateType::SHOWING
;
286 nStateSet
|= AccessibleStateType::VISIBLE
;
292 ScAccessibleEditObject::createAccessibleDescription()
294 // OSL_FAIL("Should never be called, because is set in the constructor.")
299 ScAccessibleEditObject::createAccessibleName()
301 OSL_FAIL("Should never be called, because is set in the constructor.");
305 ///===== XAccessibleEventBroadcaster =====================================
308 ScAccessibleEditObject::addAccessibleEventListener(const uno::Reference
<XAccessibleEventListener
>& xListener
)
312 mpTextHelper
->AddEventListener(xListener
);
314 ScAccessibleContextBase::addAccessibleEventListener(xListener
);
318 ScAccessibleEditObject::removeAccessibleEventListener(const uno::Reference
<XAccessibleEventListener
>& xListener
)
322 mpTextHelper
->RemoveEventListener(xListener
);
324 ScAccessibleContextBase::removeAccessibleEventListener(xListener
);
327 //===== XServiceInfo ====================================================
329 OUString SAL_CALL
ScAccessibleEditObject::getImplementationName()
331 return u
"ScAccessibleEditObject"_ustr
;
334 //===== XTypeProvider =======================================================
336 uno::Sequence
<sal_Int8
> SAL_CALL
337 ScAccessibleEditObject::getImplementationId()
339 return css::uno::Sequence
<sal_Int8
>();
342 //==== internal =========================================================
344 bool ScAccessibleEditObject::IsDefunc(sal_Int64 nParentStates
)
346 return ScAccessibleContextBase::IsDefunc() || !getAccessibleParent().is() ||
347 (nParentStates
& AccessibleStateType::DEFUNC
);
350 OutputDevice
* ScAccessibleEditObject::GetOutputDeviceForView()
352 return mpWindow
->GetOutDev();
355 void ScAccessibleEditObject::CreateTextHelper()
360 ::std::unique_ptr
< ScAccessibleTextData
> pAccessibleTextData
;
361 if (meObjectType
== CellInEditMode
|| meObjectType
== EditControl
)
363 pAccessibleTextData
.reset
364 (new ScAccessibleEditObjectTextData(mpEditView
, GetOutputDeviceForView()));
368 pAccessibleTextData
.reset
369 (new ScAccessibleEditLineTextData(nullptr, GetOutputDeviceForView(), mpTextWnd
));
372 std::unique_ptr
<ScAccessibilityEditSource
> pEditSrc
=
373 std::make_unique
<ScAccessibilityEditSource
>(std::move(pAccessibleTextData
));
375 mpTextHelper
= std::make_unique
<::accessibility::AccessibleTextHelper
>(std::move(pEditSrc
));
376 mpTextHelper
->SetEventSource(this);
378 const ScInputHandler
* pInputHdl
= ScModule::get()->GetInputHdl();
379 if ( pInputHdl
&& pInputHdl
->IsEditMode() )
381 mpTextHelper
->SetFocus();
385 mpTextHelper
->SetFocus(mbHasFocus
);
388 // #i54814# activate cell in edit mode
389 if( meObjectType
== CellInEditMode
)
391 // do not activate cell object, if top edit line is active
392 if( pInputHdl
&& !pInputHdl
->IsTopMode() )
394 SdrHint
aHint( SdrHintKind::BeginEdit
);
395 mpTextHelper
->GetEditSource().GetBroadcaster().Broadcast( aHint
);
400 sal_Int32 SAL_CALL
ScAccessibleEditObject::getForeground( )
402 return GetFgBgColor(SC_UNONAME_CCOLOR
);
405 sal_Int32 SAL_CALL
ScAccessibleEditObject::getBackground( )
407 return GetFgBgColor(SC_UNONAME_CELLBACK
);
410 sal_Int32
ScAccessibleEditObject::GetFgBgColor( const OUString
&strPropColor
)
412 SolarMutexGuard aGuard
;
416 ScDocShell
* pObjSh
= m_pScDoc
->GetDocumentShell();
419 ScModelObj
* pSpreadDoc
= pObjSh
->GetModel();
422 uno::Reference
<sheet::XSpreadsheets
> xSheets
= pSpreadDoc
->getSheets();
423 uno::Reference
<container::XIndexAccess
> xIndex( xSheets
, uno::UNO_QUERY
);
426 uno::Any aTable
= xIndex
->getByIndex(m_curCellAddress
.Tab());
427 uno::Reference
<sheet::XSpreadsheet
> xTable
;
430 uno::Reference
<table::XCell
> xCell
= xTable
->getCellByPosition(m_curCellAddress
.Col(), m_curCellAddress
.Row());
433 uno::Reference
<beans::XPropertySet
> xCellProps(xCell
, uno::UNO_QUERY
);
436 uno::Any aAny
= xCellProps
->getPropertyValue(strPropColor
);
447 //===== XAccessibleSelection ============================================
449 void SAL_CALL
ScAccessibleEditObject::selectAccessibleChild( sal_Int64
)
453 sal_Bool SAL_CALL
ScAccessibleEditObject::isAccessibleChildSelected( sal_Int64 nChildIndex
)
455 uno::Reference
<XAccessible
> xAcc
= getAccessibleChild( nChildIndex
);
456 uno::Reference
<XAccessibleContext
> xContext
;
458 xContext
= xAcc
->getAccessibleContext();
461 if( xContext
->getAccessibleRole() == AccessibleRole::PARAGRAPH
)
463 uno::Reference
< css::accessibility::XAccessibleText
>
464 xText(xAcc
, uno::UNO_QUERY
);
467 if( xText
->getSelectionStart() >= 0 ) return true;
474 void SAL_CALL
ScAccessibleEditObject::clearAccessibleSelection( )
478 void SAL_CALL
ScAccessibleEditObject::selectAllAccessibleChildren( )
482 sal_Int64 SAL_CALL
ScAccessibleEditObject::getSelectedAccessibleChildCount()
484 sal_Int64 nCount
= 0;
485 sal_Int64 TotalCount
= getAccessibleChildCount();
486 for( sal_Int64 i
= 0; i
< TotalCount
; i
++ )
487 if( isAccessibleChildSelected(i
) ) nCount
++;
491 uno::Reference
<XAccessible
> SAL_CALL
ScAccessibleEditObject::getSelectedAccessibleChild( sal_Int64 nSelectedChildIndex
)
493 if ( nSelectedChildIndex
< 0 || nSelectedChildIndex
> getSelectedAccessibleChildCount() )
494 throw IndexOutOfBoundsException();
496 for (sal_Int64 i1
= 0, i2
= 0; i1
< getAccessibleChildCount(); i1
++ )
497 if( isAccessibleChildSelected(i1
) )
499 if( i2
== nSelectedChildIndex
)
500 return getAccessibleChild( i1
);
503 return uno::Reference
<XAccessible
>();
506 void SAL_CALL
ScAccessibleEditObject::deselectAccessibleChild(sal_Int64
)
510 uno::Reference
< XAccessibleRelationSet
> ScAccessibleEditObject::getAccessibleRelationSet( )
512 SolarMutexGuard aGuard
;
513 vcl::Window
* pWindow
= mpWindow
;
514 rtl::Reference
<utl::AccessibleRelationSetHelper
> rRelationSet
= new utl::AccessibleRelationSetHelper
;
517 vcl::Window
*pLabeledBy
= pWindow
->GetAccessibleRelationLabeledBy();
518 if ( pLabeledBy
&& pLabeledBy
!= pWindow
)
520 uno::Sequence
<uno::Reference
<css::accessibility::XAccessible
>> aSequence
{ pLabeledBy
->GetAccessible() };
521 rRelationSet
->AddRelation( AccessibleRelation( AccessibleRelationType_LABELED_BY
, aSequence
) );
523 vcl::Window
* pMemberOf
= pWindow
->GetAccessibleRelationMemberOf();
524 if ( pMemberOf
&& pMemberOf
!= pWindow
)
526 uno::Sequence
< uno::Reference
<css::accessibility::XAccessible
> > aSequence
{ pMemberOf
->GetAccessible() };
527 rRelationSet
->AddRelation( AccessibleRelation( AccessibleRelationType_MEMBER_OF
, aSequence
) );
531 return uno::Reference
< XAccessibleRelationSet
>();
534 AbsoluteScreenPixelRectangle
ScAccessibleEditControlObject::GetBoundingBoxOnScreen() const
536 AbsoluteScreenPixelRectangle aScreenBounds
;
538 if (m_pController
&& m_pController
->GetDrawingArea())
540 aScreenBounds
= AbsoluteScreenPixelRectangle(m_pController
->GetDrawingArea()->get_accessible_location_on_screen(),
541 m_pController
->GetOutputSizePixel());
544 return aScreenBounds
;
547 tools::Rectangle
ScAccessibleEditControlObject::GetBoundingBox() const
549 tools::Rectangle
aBounds( GetBoundingBoxOnScreen() );
551 uno::Reference
< XAccessibleContext
> xContext(const_cast<ScAccessibleEditControlObject
*>(this)->getAccessibleContext());
554 uno::Reference
< XAccessible
> xParent( xContext
->getAccessibleParent() );
557 uno::Reference
< XAccessibleComponent
> xParentComponent( xParent
->getAccessibleContext(), uno::UNO_QUERY
);
558 if ( xParentComponent
.is() )
560 Point aScreenLoc
= aBounds
.TopLeft();
561 awt::Point aParentScreenLoc
= xParentComponent
->getLocationOnScreen();
562 Point
aPos( aScreenLoc
.getX() - aParentScreenLoc
.X
, aScreenLoc
.getY() - aParentScreenLoc
.Y
);
563 aBounds
.SetPos( aPos
);
571 void SAL_CALL
ScAccessibleEditControlObject::disposing()
573 ScAccessibleEditObject::disposing();
574 m_pController
= nullptr;
577 uno::Reference
< XAccessibleRelationSet
> ScAccessibleEditControlObject::getAccessibleRelationSet()
579 SolarMutexGuard aGuard
;
580 if (!m_pController
|| !m_pController
->GetDrawingArea())
581 return uno::Reference
< XAccessibleRelationSet
>();
582 return m_pController
->GetDrawingArea()->get_accessible_relation_set();
585 OutputDevice
* ScAccessibleEditControlObject::GetOutputDeviceForView()
587 if (!m_pController
|| !m_pController
->GetDrawingArea())
589 return &m_pController
->GetDrawingArea()->get_ref_device();
592 ScAccessibleEditLineObject::ScAccessibleEditLineObject(ScTextWnd
* pTextWnd
)
593 : ScAccessibleEditControlObject(pTextWnd
, ScAccessibleEditObject::EditLine
)
595 // tdf#141769 set this early so its always available, even before the on-demand
596 // editview is created
597 mpTextWnd
= pTextWnd
;
600 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */