1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
21 #include <sal/log.hxx>
25 #include "accessiblecell.hxx"
28 #include <com/sun/star/accessibility/AccessibleRole.hpp>
29 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
30 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
32 #include <editeng/unoedsrc.hxx>
34 #include <vcl/svapp.hxx>
35 #include <vcl/window.hxx>
37 #include <comphelper/string.hxx>
38 #include <comphelper/sequence.hxx>
39 #include <svx/IAccessibleViewForwarder.hxx>
40 #include <svx/unoshtxt.hxx>
41 #include <svx/svdotext.hxx>
42 #include <tools/debug.hxx>
44 using namespace sdr::table
;
45 using namespace ::com::sun::star
;
46 using namespace ::com::sun::star::uno
;
47 using namespace ::com::sun::star::accessibility
;
48 using namespace ::com::sun::star::lang
;
50 namespace accessibility
{
52 AccessibleCell::AccessibleCell( const rtl::Reference
< AccessibleTableShape
>& rxParent
, sdr::table::CellRef xCell
, sal_Int32 nIndex
, const AccessibleShapeTreeInfo
& rShapeTreeInfo
)
53 : AccessibleCellBase( rxParent
, AccessibleRole::TABLE_CELL
)
54 , maShapeTreeInfo( rShapeTreeInfo
)
55 , mnIndexInParent( nIndex
)
56 , mxCell(std::move( xCell
))
58 //Init the pAccTable var
59 pAccTable
= rxParent
.get();
63 AccessibleCell::~AccessibleCell()
65 DBG_ASSERT( mpText
== nullptr, "svx::AccessibleCell::~AccessibleCell(), not disposed!?" );
69 void AccessibleCell::Init()
71 SdrView
* pView
= maShapeTreeInfo
.GetSdrView();
72 const vcl::Window
* pWindow
= maShapeTreeInfo
.GetWindow ();
73 if( !((pView
!= nullptr) && (pWindow
!= nullptr) && mxCell
.is()))
76 // create AccessibleTextHelper to handle this shape's text
77 if( mxCell
->CanCreateEditOutlinerParaObject() || mxCell
->GetOutlinerParaObject() != nullptr )
79 // non-empty text -> use full-fledged edit source right away
81 mpText
.reset( new AccessibleTextHelper( std::make_unique
<SvxTextEditSource
>(mxCell
->GetObject(), mxCell
.get(), *pView
, *pWindow
->GetOutDev()) ) );
82 if( mxCell
.is() && mxCell
->IsActiveCell() )
84 mpText
->SetEventSource(this);
89 bool AccessibleCell::SetState (sal_Int64 aState
)
91 bool bStateHasChanged
= false;
93 if (aState
== AccessibleStateType::FOCUSED
&& mpText
!= nullptr)
95 // Offer FOCUSED state to edit engine and detect whether the state
97 bool bIsFocused
= mpText
->HaveFocus ();
99 bStateHasChanged
= (bIsFocused
!= mpText
->HaveFocus ());
102 bStateHasChanged
= AccessibleContextBase::SetState (aState
);
104 return bStateHasChanged
;
108 bool AccessibleCell::ResetState (sal_Int64 aState
)
110 bool bStateHasChanged
= false;
112 if (aState
== AccessibleStateType::FOCUSED
&& mpText
!= nullptr)
114 // Try to remove FOCUSED state from the edit engine and detect
115 // whether the state changes.
116 bool bIsFocused
= mpText
->HaveFocus ();
117 mpText
->SetFocus (false);
118 bStateHasChanged
= (bIsFocused
!= mpText
->HaveFocus ());
121 bStateHasChanged
= AccessibleContextBase::ResetState (aState
);
123 return bStateHasChanged
;
130 Any SAL_CALL
AccessibleCell::queryInterface( const Type
& aType
)
132 return AccessibleCellBase::queryInterface( aType
);
136 void SAL_CALL
AccessibleCell::acquire( ) noexcept
138 AccessibleCellBase::acquire();
142 void SAL_CALL
AccessibleCell::release( ) noexcept
144 AccessibleCellBase::release();
148 // XAccessibleContext
151 /** The children of this cell come from the paragraphs of text.
153 sal_Int64 SAL_CALL
AccessibleCell::getAccessibleChildCount()
155 SolarMutexGuard aSolarGuard
;
157 return mpText
!= nullptr ? mpText
->GetChildCount () : 0;
161 /** Forward the request to the shape. Return the requested shape or throw
162 an exception for a wrong index.
164 Reference
<XAccessible
> SAL_CALL
AccessibleCell::getAccessibleChild (sal_Int64 nIndex
)
166 SolarMutexGuard aSolarGuard
;
169 return mpText
->GetChild (nIndex
);
173 /** Return a copy of the state set.
179 sal_Int64 SAL_CALL
AccessibleCell::getAccessibleStateSet()
181 SolarMutexGuard aSolarGuard
;
182 ::osl::MutexGuard
aGuard (m_aMutex
);
183 sal_Int64 nStateSet
= 0;
185 if (rBHelper
.bDisposed
|| mpText
== nullptr)
187 // Return a minimal state set that only contains the DEFUNC state.
188 nStateSet
= AccessibleContextBase::getAccessibleStateSet ();
192 // Merge current FOCUSED state from edit engine.
193 if (mpText
!= nullptr)
195 if (mpText
->HaveFocus())
196 mnStateSet
|= AccessibleStateType::FOCUSED
;
198 mnStateSet
&= ~AccessibleStateType::FOCUSED
;
200 // Set the invisible state for merged cell
201 if (mxCell
.is() && mxCell
->isMerged())
202 mnStateSet
&= ~AccessibleStateType::VISIBLE
;
204 mnStateSet
|= AccessibleStateType::VISIBLE
;
207 //Just when the parent table is not read-only,set states EDITABLE,RESIZABLE,MOVEABLE
208 css::uno::Reference
<XAccessible
> xTempAcc
= getAccessibleParent();
211 css::uno::Reference
<XAccessibleContext
>
212 xTempAccContext
= xTempAcc
->getAccessibleContext();
213 if( xTempAccContext
.is() )
215 if (xTempAccContext
->getAccessibleStateSet() & AccessibleStateType::EDITABLE
)
217 mnStateSet
|= AccessibleStateType::EDITABLE
;
218 mnStateSet
|= AccessibleStateType::RESIZABLE
;
219 mnStateSet
|= AccessibleStateType::MOVEABLE
;
223 nStateSet
= mnStateSet
;
230 // XAccessibleComponent
233 sal_Bool SAL_CALL
AccessibleCell::containsPoint( const css::awt::Point
& aPoint
)
235 return AccessibleComponentBase::containsPoint( aPoint
);
238 /** The implementation below is at the moment straightforward. It iterates
239 over all children (and thereby instances all children which have not
240 been already instantiated) until a child covering the specified point is
242 This leaves room for improvement. For instance, first iterate only over
243 the already instantiated children and only if no match is found
244 instantiate the remaining ones.
246 Reference
<XAccessible
> SAL_CALL
AccessibleCell::getAccessibleAtPoint ( const css::awt::Point
& aPoint
)
248 SolarMutexGuard aSolarGuard
;
249 ::osl::MutexGuard
aGuard (m_aMutex
);
251 sal_Int64 nChildCount
= getAccessibleChildCount ();
252 for (sal_Int64 i
= 0; i
< nChildCount
; ++i
)
254 Reference
<XAccessible
> xChild (getAccessibleChild (i
));
257 Reference
<XAccessibleComponent
> xChildComponent (xChild
->getAccessibleContext(), uno::UNO_QUERY
);
258 if (xChildComponent
.is())
260 awt::Rectangle
aBBox (xChildComponent
->getBounds());
261 if ( (aPoint
.X
>= aBBox
.X
)
262 && (aPoint
.Y
>= aBBox
.Y
)
263 && (aPoint
.X
< aBBox
.X
+aBBox
.Width
)
264 && (aPoint
.Y
< aBBox
.Y
+aBBox
.Height
) )
270 // Have not found a child under the given point. Returning empty
271 // reference to indicate this.
272 return uno::Reference
<XAccessible
>();
276 css::awt::Rectangle SAL_CALL
AccessibleCell::getBounds()
278 SolarMutexGuard aSolarGuard
;
279 ::osl::MutexGuard
aGuard (m_aMutex
);
282 css::awt::Rectangle aBoundingBox
;
285 // Get the cell's bounding box in internal coordinates (in 100th of mm)
286 const ::tools::Rectangle
aCellRect( mxCell
->getCellRect() );
288 // Transform coordinates from internal to pixel.
289 if (maShapeTreeInfo
.GetViewForwarder() == nullptr)
290 throw uno::RuntimeException (u
"AccessibleCell has no valid view forwarder"_ustr
, getXWeak());
292 ::Size
aPixelSize( maShapeTreeInfo
.GetViewForwarder()->LogicToPixel(::Size(aCellRect
.GetWidth(), aCellRect
.GetHeight())) );
293 ::Point
aPixelPosition( maShapeTreeInfo
.GetViewForwarder()->LogicToPixel( aCellRect
.TopLeft() ));
295 // Clip the shape's bounding box with the bounding box of its parent.
296 Reference
<XAccessibleComponent
> xParentComponent ( getAccessibleParent(), uno::UNO_QUERY
);
297 if (xParentComponent
.is())
299 // Make the coordinates relative to the parent.
300 awt::Point
aParentLocation (xParentComponent
->getLocationOnScreen());
301 int x
= aPixelPosition
.getX() - aParentLocation
.X
;
302 int y
= aPixelPosition
.getY() - aParentLocation
.Y
;
304 // Clip with parent (with coordinates relative to itself).
305 ::tools::Rectangle
aBBox ( x
, y
, x
+ aPixelSize
.getWidth(), y
+ aPixelSize
.getHeight());
306 awt::Size
aParentSize (xParentComponent
->getSize());
307 ::tools::Rectangle
aParentBBox (0,0, aParentSize
.Width
, aParentSize
.Height
);
308 aBBox
= aBBox
.GetIntersection (aParentBBox
);
309 aBoundingBox
= awt::Rectangle ( aBBox
.Left(), aBBox
.Top(), aBBox
.getOpenWidth(), aBBox
.getOpenHeight());
313 SAL_INFO("svx", "parent does not support component");
314 aBoundingBox
= awt::Rectangle (aPixelPosition
.getX(), aPixelPosition
.getY(),aPixelSize
.getWidth(), aPixelSize
.getHeight());
322 css::awt::Point SAL_CALL
AccessibleCell::getLocation()
325 css::awt::Rectangle
aBoundingBox(getBounds());
326 return css::awt::Point(aBoundingBox
.X
, aBoundingBox
.Y
);
330 css::awt::Point SAL_CALL
AccessibleCell::getLocationOnScreen()
334 // Get relative position...
335 css::awt::Point
aLocation(getLocation ());
337 // ... and add absolute position of the parent.
338 Reference
<XAccessibleComponent
> xParentComponent( getAccessibleParent(), uno::UNO_QUERY
);
339 if(xParentComponent
.is())
341 css::awt::Point
aParentLocation(xParentComponent
->getLocationOnScreen());
342 aLocation
.X
+= aParentLocation
.X
;
343 aLocation
.Y
+= aParentLocation
.Y
;
347 SAL_WARN("svx", "parent does not support XAccessibleComponent");
354 awt::Size SAL_CALL
AccessibleCell::getSize()
357 awt::Rectangle
aBoundingBox (getBounds());
358 return awt::Size (aBoundingBox
.Width
, aBoundingBox
.Height
);
362 void SAL_CALL
AccessibleCell::grabFocus()
364 AccessibleComponentBase::grabFocus();
368 sal_Int32 SAL_CALL
AccessibleCell::getForeground()
373 return sal_Int32(0x0ffffffL
);
377 sal_Int32 SAL_CALL
AccessibleCell::getBackground()
386 // XAccessibleExtendedComponent
388 OUString SAL_CALL
AccessibleCell::getTitledBorderText()
390 return AccessibleComponentBase::getTitledBorderText();
394 OUString SAL_CALL
AccessibleCell::getToolTipText()
396 return AccessibleComponentBase::getToolTipText();
400 // XAccessibleEventBroadcaster
403 void SAL_CALL
AccessibleCell::addAccessibleEventListener( const Reference
<XAccessibleEventListener
>& rxListener
)
405 SolarMutexGuard aSolarGuard
;
406 ::osl::MutexGuard
aGuard (m_aMutex
);
407 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
409 Reference
<XInterface
> xSource( static_cast<XComponent
*>(this) );
410 lang::EventObject
aEventObj(xSource
);
411 rxListener
->disposing(aEventObj
);
415 AccessibleContextBase::addAccessibleEventListener (rxListener
);
416 if (mpText
!= nullptr)
417 mpText
->AddEventListener (rxListener
);
422 void SAL_CALL
AccessibleCell::removeAccessibleEventListener( const Reference
<XAccessibleEventListener
>& rxListener
)
424 SolarMutexGuard aSolarGuard
;
425 AccessibleContextBase::removeAccessibleEventListener(rxListener
);
426 if (mpText
!= nullptr)
427 mpText
->RemoveEventListener (rxListener
);
434 OUString SAL_CALL
AccessibleCell::getImplementationName()
436 return u
"AccessibleCell"_ustr
;
440 Sequence
<OUString
> SAL_CALL
AccessibleCell::getSupportedServiceNames()
443 const css::uno::Sequence
<OUString
> vals
{ u
"com.sun.star.drawing.AccessibleCell"_ustr
};
444 return comphelper::concatSequences(AccessibleContextBase::getSupportedServiceNames(), vals
);
448 // IAccessibleViewForwarderListener
451 void AccessibleCell::ViewForwarderChanged()
453 // Inform all listeners that the graphical representation (i.e. size
454 // and/or position) of the shape has changed.
455 CommitChange(AccessibleEventId::VISIBLE_DATA_CHANGED
, Any(), Any(), -1);
457 // update our children that our screen position might have changed
459 mpText
->UpdateChildren();
466 void AccessibleCell::disposing()
468 SolarMutexGuard aSolarGuard
;
469 ::osl::MutexGuard
aGuard (m_aMutex
);
471 // Make sure to send an event that this object loses the focus in the
472 // case that it has the focus.
473 mnStateSet
&= ~AccessibleStateType::FOCUSED
;
475 if (mpText
!= nullptr)
481 // Cleanup. Remove references to objects to allow them to be
484 maShapeTreeInfo
.dispose();
486 // Call base classes.
487 AccessibleContextBase::dispose ();
490 sal_Int64 SAL_CALL
AccessibleCell::getAccessibleIndexInParent()
493 return mnIndexInParent
;
497 OUString
AccessibleCell::getCellName( sal_Int32 nCol
, sal_Int32 nRow
)
504 aBuf
.append( static_cast<sal_Unicode
>( 'A' +
505 static_cast<sal_uInt16
>(nCol
)));
509 OUStringChar(static_cast<sal_Unicode
>( 'A' +
510 (static_cast<sal_uInt16
>(nCol
) / 26) - 1))
511 + OUStringChar( static_cast<sal_Unicode
>( 'A' +
512 (static_cast<sal_uInt16
>(nCol
) % 26))) );
520 sal_Int32 nC
= nCol
% 26;
521 aStr
.append(static_cast<sal_Unicode
>( 'A' +
522 static_cast<sal_uInt16
>(nC
)));
524 nCol
= nCol
/ 26 - 1;
526 aStr
.append(static_cast<sal_Unicode
>( 'A' +
527 static_cast<sal_uInt16
>(nCol
)));
528 aBuf
.append(comphelper::string::reverseString(aStr
));
531 return aBuf
.makeStringAndClear();
534 OUString SAL_CALL
AccessibleCell::getAccessibleName()
537 SolarMutexGuard aSolarGuard
;
543 sal_Int32 nRow
= 0, nCol
= 0;
544 pAccTable
->getColumnAndRow(mnIndexInParent
, nCol
, nRow
);
545 return getCellName( nCol
, nRow
);
547 catch(const Exception
&)
552 return AccessibleCellBase::getAccessibleName();
555 void AccessibleCell::UpdateChildren()
558 mpText
->UpdateChildren();
561 /* MT: Above getAccessibleName was introduced with IA2 CWS, while below was introduce in 3.3 meanwhile. Check which one is correct
562 +If this is correct, we also don't need sdr::table::CellRef getCellRef(), UpdateChildren(), getCellName( sal_Int32 nCol, sal_Int32 nRow ) above
565 OUString SAL_CALL AccessibleCell::getAccessibleName() throw (css::uno::RuntimeException)
568 SolarMutexGuard aSolarGuard;
571 return mxCell->getName();
573 return AccessibleCellBase::getAccessibleName();
577 } // end of namespace accessibility
579 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */