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 <unotools/accessiblestatesethelper.hxx>
33 #include <com/sun/star/accessibility/AccessibleRole.hpp>
34 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
35 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
36 #include <com/sun/star/sheet/XSpreadsheet.hpp>
37 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
38 #include <svx/AccessibleTextHelper.hxx>
39 #include <editeng/editview.hxx>
40 #include <editeng/editeng.hxx>
41 #include <svx/svdmodel.hxx>
42 #include <vcl/svapp.hxx>
43 #include <vcl/window.hxx>
44 #include <sfx2/objsh.hxx>
45 #include <cppuhelper/queryinterface.hxx>
47 #include <unonames.hxx>
48 #include <document.hxx>
49 #include <AccessibleDocument.hxx>
50 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
51 #include <unotools/accessiblerelationsethelper.hxx>
52 #include <com/sun/star/accessibility/XAccessibleText.hpp>
54 using ::com::sun::star::lang::IndexOutOfBoundsException
;
55 using namespace ::com::sun::star
;
56 using namespace ::com::sun::star::accessibility
;
58 //===== internal ============================================================
60 ScAccessibleEditObject::ScAccessibleEditObject(
61 const uno::Reference
<XAccessible
>& rxParent
,
62 EditView
* pEditView
, vcl::Window
* pWin
, const OUString
& rName
,
63 const OUString
& rDescription
, EditObjectType eObjectType
)
64 : ScAccessibleContextBase(rxParent
, AccessibleRole::TEXT_FRAME
)
65 , mpEditView(pEditView
)
68 , meObjectType(eObjectType
)
72 InitAcc(rxParent
, pEditView
, pWin
, nullptr, rName
, rDescription
);
75 ScAccessibleEditObject::ScAccessibleEditObject(EditObjectType eObjectType
)
76 : ScAccessibleContextBase(nullptr, AccessibleRole::TEXT_FRAME
)
80 , meObjectType(eObjectType
)
86 void ScAccessibleEditObject::InitAcc(
87 const uno::Reference
<XAccessible
>& rxParent
,
88 EditView
* pEditView
, vcl::Window
* pWin
,
89 ScTextWnd
* pTxtWnd
, const OUString
& rName
,
90 const OUString
& rDescription
)
93 mpEditView
= pEditView
;
99 SetDescription(rDescription
);
100 if( meObjectType
== CellInEditMode
)
102 const ScAccessibleDocument
*pAccDoc
= static_cast<ScAccessibleDocument
*>(rxParent
.get());
105 m_pScDoc
= pAccDoc
->GetDocument();
106 m_curCellAddress
=pAccDoc
->GetCurCellAddress();
111 ScAccessibleEditObject::~ScAccessibleEditObject()
113 if (!ScAccessibleContextBase::IsDefunc() && !rBHelper
.bInDispose
)
115 // increment refcount to prevent double call off dtor
116 osl_atomic_increment( &m_refCount
);
117 // call dispose to inform object which have a weak reference to this object
122 void SAL_CALL
ScAccessibleEditObject::disposing()
124 SolarMutexGuard aGuard
;
125 mpTextHelper
.reset();
127 ScAccessibleContextBase::disposing();
130 void ScAccessibleEditObject::LostFocus()
134 mpTextHelper
->SetFocus(false);
138 void ScAccessibleEditObject::GotFocus()
143 mpTextHelper
->SetFocus();
146 //===== XInterface ==========================================================
148 css::uno::Any SAL_CALL
149 ScAccessibleEditObject::queryInterface (const css::uno::Type
& rType
)
151 css::uno::Any aReturn
= ScAccessibleContextBase::queryInterface (rType
);
152 if ( ! aReturn
.hasValue())
153 aReturn
= ::cppu::queryInterface (rType
,
154 static_cast< css::accessibility::XAccessibleSelection
* >(this)
159 ScAccessibleEditObject::acquire()
162 ScAccessibleContextBase::acquire ();
165 ScAccessibleEditObject::release()
168 ScAccessibleContextBase::release ();
170 //===== XAccessibleComponent ============================================
172 uno::Reference
< XAccessible
> SAL_CALL
ScAccessibleEditObject::getAccessibleAtPoint(
173 const awt::Point
& rPoint
)
175 uno::Reference
<XAccessible
> xRet
;
176 if (containsPoint(rPoint
))
178 SolarMutexGuard aGuard
;
183 xRet
= mpTextHelper
->GetAt(rPoint
);
189 tools::Rectangle
ScAccessibleEditObject::GetBoundingBoxOnScreen() const
191 tools::Rectangle aScreenBounds
;
195 if ( meObjectType
== CellInEditMode
)
197 if ( mpEditView
&& mpEditView
->GetEditEngine() )
199 MapMode
aMapMode( mpEditView
->GetEditEngine()->GetRefMapMode() );
200 aScreenBounds
= mpWindow
->LogicToPixel( mpEditView
->GetOutputArea(), aMapMode
);
201 Point aCellLoc
= aScreenBounds
.TopLeft();
202 tools::Rectangle aWindowRect
= mpWindow
->GetWindowExtentsRelative( nullptr );
203 Point aWindowLoc
= aWindowRect
.TopLeft();
204 Point
aPos( aCellLoc
.getX() + aWindowLoc
.getX(), aCellLoc
.getY() + aWindowLoc
.getY() );
205 aScreenBounds
.SetPos( aPos
);
210 aScreenBounds
= mpWindow
->GetWindowExtentsRelative( nullptr );
214 return aScreenBounds
;
217 tools::Rectangle
ScAccessibleEditObject::GetBoundingBox() const
219 tools::Rectangle
aBounds( GetBoundingBoxOnScreen() );
223 uno::Reference
< XAccessible
> xThis( mpWindow
->GetAccessible() );
226 uno::Reference
< XAccessibleContext
> xContext( xThis
->getAccessibleContext() );
229 uno::Reference
< XAccessible
> xParent( xContext
->getAccessibleParent() );
232 uno::Reference
< XAccessibleComponent
> xParentComponent( xParent
->getAccessibleContext(), uno::UNO_QUERY
);
233 if ( xParentComponent
.is() )
235 Point aScreenLoc
= aBounds
.TopLeft();
236 awt::Point aParentScreenLoc
= xParentComponent
->getLocationOnScreen();
237 Point
aPos( aScreenLoc
.getX() - aParentScreenLoc
.X
, aScreenLoc
.getY() - aParentScreenLoc
.Y
);
238 aBounds
.SetPos( aPos
);
248 //===== XAccessibleContext ==============================================
251 ScAccessibleEditObject::getAccessibleChildCount()
253 SolarMutexGuard aGuard
;
256 return mpTextHelper
->GetChildCount();
259 uno::Reference
< XAccessible
> SAL_CALL
260 ScAccessibleEditObject::getAccessibleChild(sal_Int32 nIndex
)
262 SolarMutexGuard aGuard
;
265 return mpTextHelper
->GetChild(nIndex
);
268 uno::Reference
<XAccessibleStateSet
> SAL_CALL
269 ScAccessibleEditObject::getAccessibleStateSet()
271 SolarMutexGuard aGuard
;
272 uno::Reference
<XAccessibleStateSet
> xParentStates
;
273 if (getAccessibleParent().is())
275 uno::Reference
<XAccessibleContext
> xParentContext
= getAccessibleParent()->getAccessibleContext();
276 xParentStates
= xParentContext
->getAccessibleStateSet();
278 utl::AccessibleStateSetHelper
* pStateSet
= new utl::AccessibleStateSetHelper();
279 if (IsDefunc(xParentStates
))
280 pStateSet
->AddState(AccessibleStateType::DEFUNC
);
283 // all states are const, because this object exists only in one state
284 pStateSet
->AddState(AccessibleStateType::EDITABLE
);
285 pStateSet
->AddState(AccessibleStateType::ENABLED
);
286 pStateSet
->AddState(AccessibleStateType::SENSITIVE
);
287 pStateSet
->AddState(AccessibleStateType::MULTI_LINE
);
288 pStateSet
->AddState(AccessibleStateType::MULTI_SELECTABLE
);
289 pStateSet
->AddState(AccessibleStateType::SHOWING
);
290 pStateSet
->AddState(AccessibleStateType::VISIBLE
);
296 ScAccessibleEditObject::createAccessibleDescription()
298 // OSL_FAIL("Should never be called, because is set in the constructor.")
303 ScAccessibleEditObject::createAccessibleName()
305 OSL_FAIL("Should never be called, because is set in the constructor.");
309 ///===== XAccessibleEventBroadcaster =====================================
312 ScAccessibleEditObject::addAccessibleEventListener(const uno::Reference
<XAccessibleEventListener
>& xListener
)
316 mpTextHelper
->AddEventListener(xListener
);
318 ScAccessibleContextBase::addAccessibleEventListener(xListener
);
322 ScAccessibleEditObject::removeAccessibleEventListener(const uno::Reference
<XAccessibleEventListener
>& xListener
)
326 mpTextHelper
->RemoveEventListener(xListener
);
328 ScAccessibleContextBase::removeAccessibleEventListener(xListener
);
331 //===== XServiceInfo ====================================================
333 OUString SAL_CALL
ScAccessibleEditObject::getImplementationName()
335 return "ScAccessibleEditObject";
338 //===== XTypeProvider =======================================================
340 uno::Sequence
<sal_Int8
> SAL_CALL
341 ScAccessibleEditObject::getImplementationId()
343 return css::uno::Sequence
<sal_Int8
>();
346 //==== internal =========================================================
348 bool ScAccessibleEditObject::IsDefunc(
349 const uno::Reference
<XAccessibleStateSet
>& rxParentStates
)
351 return ScAccessibleContextBase::IsDefunc() || !getAccessibleParent().is() ||
352 (rxParentStates
.is() && rxParentStates
->contains(AccessibleStateType::DEFUNC
));
355 OutputDevice
* ScAccessibleEditObject::GetOutputDeviceForView()
360 void ScAccessibleEditObject::CreateTextHelper()
365 ::std::unique_ptr
< ScAccessibleTextData
> pAccessibleTextData
;
366 if (meObjectType
== CellInEditMode
|| meObjectType
== EditControl
)
368 pAccessibleTextData
.reset
369 (new ScAccessibleEditObjectTextData(mpEditView
, GetOutputDeviceForView()));
373 pAccessibleTextData
.reset
374 (new ScAccessibleEditLineTextData(nullptr, GetOutputDeviceForView(), mpTextWnd
));
377 std::unique_ptr
<ScAccessibilityEditSource
> pEditSrc
=
378 std::make_unique
<ScAccessibilityEditSource
>(std::move(pAccessibleTextData
));
380 mpTextHelper
= std::make_unique
<::accessibility::AccessibleTextHelper
>(std::move(pEditSrc
));
381 mpTextHelper
->SetEventSource(this);
383 const ScInputHandler
* pInputHdl
= SC_MOD()->GetInputHdl();
384 if ( pInputHdl
&& pInputHdl
->IsEditMode() )
386 mpTextHelper
->SetFocus();
390 mpTextHelper
->SetFocus(mbHasFocus
);
393 // #i54814# activate cell in edit mode
394 if( meObjectType
== CellInEditMode
)
396 // do not activate cell object, if top edit line is active
397 if( pInputHdl
&& !pInputHdl
->IsTopMode() )
399 SdrHint
aHint( SdrHintKind::BeginEdit
);
400 mpTextHelper
->GetEditSource().GetBroadcaster().Broadcast( aHint
);
405 sal_Int32 SAL_CALL
ScAccessibleEditObject::getForeground( )
407 return GetFgBgColor(SC_UNONAME_CCOLOR
);
410 sal_Int32 SAL_CALL
ScAccessibleEditObject::getBackground( )
412 return GetFgBgColor(SC_UNONAME_CELLBACK
);
415 sal_Int32
ScAccessibleEditObject::GetFgBgColor( const OUString
&strPropColor
)
417 SolarMutexGuard aGuard
;
421 SfxObjectShell
* pObjSh
= m_pScDoc
->GetDocumentShell();
424 uno::Reference
<sheet::XSpreadsheetDocument
> xSpreadDoc( pObjSh
->GetModel(), uno::UNO_QUERY
);
425 if ( xSpreadDoc
.is() )
427 uno::Reference
<sheet::XSpreadsheets
> xSheets
= xSpreadDoc
->getSheets();
428 uno::Reference
<container::XIndexAccess
> xIndex( xSheets
, uno::UNO_QUERY
);
431 uno::Any aTable
= xIndex
->getByIndex(m_curCellAddress
.Tab());
432 uno::Reference
<sheet::XSpreadsheet
> xTable
;
435 uno::Reference
<table::XCell
> xCell
= xTable
->getCellByPosition(m_curCellAddress
.Col(), m_curCellAddress
.Row());
438 uno::Reference
<beans::XPropertySet
> xCellProps(xCell
, uno::UNO_QUERY
);
441 uno::Any aAny
= xCellProps
->getPropertyValue(strPropColor
);
452 //===== XAccessibleSelection ============================================
454 void SAL_CALL
ScAccessibleEditObject::selectAccessibleChild( sal_Int32
)
458 sal_Bool SAL_CALL
ScAccessibleEditObject::isAccessibleChildSelected( sal_Int32 nChildIndex
)
460 uno::Reference
<XAccessible
> xAcc
= getAccessibleChild( nChildIndex
);
461 uno::Reference
<XAccessibleContext
> xContext
;
463 xContext
= xAcc
->getAccessibleContext();
466 if( xContext
->getAccessibleRole() == AccessibleRole::PARAGRAPH
)
468 uno::Reference
< css::accessibility::XAccessibleText
>
469 xText(xAcc
, uno::UNO_QUERY
);
472 if( xText
->getSelectionStart() >= 0 ) return true;
479 void SAL_CALL
ScAccessibleEditObject::clearAccessibleSelection( )
483 void SAL_CALL
ScAccessibleEditObject::selectAllAccessibleChildren( )
487 sal_Int32 SAL_CALL
ScAccessibleEditObject::getSelectedAccessibleChildCount()
489 sal_Int32 nCount
= 0;
490 sal_Int32 TotalCount
= getAccessibleChildCount();
491 for( sal_Int32 i
= 0; i
< TotalCount
; i
++ )
492 if( isAccessibleChildSelected(i
) ) nCount
++;
496 uno::Reference
<XAccessible
> SAL_CALL
ScAccessibleEditObject::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex
)
498 if ( nSelectedChildIndex
> getSelectedAccessibleChildCount() )
499 throw IndexOutOfBoundsException();
501 for( i1
= 0, i2
= 0; i1
< getAccessibleChildCount(); i1
++ )
502 if( isAccessibleChildSelected(i1
) )
504 if( i2
== nSelectedChildIndex
)
505 return getAccessibleChild( i1
);
508 return uno::Reference
<XAccessible
>();
511 void SAL_CALL
ScAccessibleEditObject::deselectAccessibleChild(
516 uno::Reference
< XAccessibleRelationSet
> ScAccessibleEditObject::getAccessibleRelationSet( )
518 SolarMutexGuard aGuard
;
519 vcl::Window
* pWindow
= mpWindow
;
520 utl::AccessibleRelationSetHelper
* rRelationSet
= new utl::AccessibleRelationSetHelper
;
521 uno::Reference
< XAccessibleRelationSet
> rSet
= rRelationSet
;
524 vcl::Window
*pLabeledBy
= pWindow
->GetAccessibleRelationLabeledBy();
525 if ( pLabeledBy
&& pLabeledBy
!= pWindow
)
527 uno::Sequence
< uno::Reference
< uno::XInterface
> > aSequence
{ pLabeledBy
->GetAccessible() };
528 rRelationSet
->AddRelation( AccessibleRelation( AccessibleRelationType::LABELED_BY
, aSequence
) );
530 vcl::Window
* pMemberOf
= pWindow
->GetAccessibleRelationMemberOf();
531 if ( pMemberOf
&& pMemberOf
!= pWindow
)
533 uno::Sequence
< uno::Reference
< uno::XInterface
> > aSequence
{ pMemberOf
->GetAccessible() };
534 rRelationSet
->AddRelation( AccessibleRelation( AccessibleRelationType::MEMBER_OF
, aSequence
) );
538 return uno::Reference
< XAccessibleRelationSet
>();
541 tools::Rectangle
ScAccessibleEditControlObject::GetBoundingBoxOnScreen() const
543 tools::Rectangle aScreenBounds
;
545 if (m_pController
&& m_pController
->GetDrawingArea())
547 aScreenBounds
= tools::Rectangle(m_pController
->GetDrawingArea()->get_accessible_location(),
548 m_pController
->GetOutputSizePixel());
551 return aScreenBounds
;
554 tools::Rectangle
ScAccessibleEditControlObject::GetBoundingBox() const
556 tools::Rectangle
aBounds( GetBoundingBoxOnScreen() );
558 uno::Reference
< XAccessibleContext
> xContext(const_cast<ScAccessibleEditControlObject
*>(this)->getAccessibleContext());
561 uno::Reference
< XAccessible
> xParent( xContext
->getAccessibleParent() );
564 uno::Reference
< XAccessibleComponent
> xParentComponent( xParent
->getAccessibleContext(), uno::UNO_QUERY
);
565 if ( xParentComponent
.is() )
567 Point aScreenLoc
= aBounds
.TopLeft();
568 awt::Point aParentScreenLoc
= xParentComponent
->getLocationOnScreen();
569 Point
aPos( aScreenLoc
.getX() - aParentScreenLoc
.X
, aScreenLoc
.getY() - aParentScreenLoc
.Y
);
570 aBounds
.SetPos( aPos
);
578 void SAL_CALL
ScAccessibleEditControlObject::disposing()
580 ScAccessibleEditObject::disposing();
581 m_pController
= nullptr;
584 uno::Reference
< XAccessibleRelationSet
> ScAccessibleEditControlObject::getAccessibleRelationSet()
586 SolarMutexGuard aGuard
;
587 if (!m_pController
|| !m_pController
->GetDrawingArea())
588 return uno::Reference
< XAccessibleRelationSet
>();
589 return m_pController
->GetDrawingArea()->get_accessible_relation_set();
592 OutputDevice
* ScAccessibleEditControlObject::GetOutputDeviceForView()
594 if (!m_pController
|| !m_pController
->GetDrawingArea())
596 return &m_pController
->GetDrawingArea()->get_ref_device();
599 ScAccessibleEditLineObject::ScAccessibleEditLineObject(ScTextWnd
* pTextWnd
)
600 : ScAccessibleEditControlObject(pTextWnd
, ScAccessibleEditObject::EditLine
)
602 // tdf#141769 set this early so its always available, even before the on-demand
603 // editview is created
604 mpTextWnd
= pTextWnd
;
607 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */