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
;
49 using namespace ::com::sun::star::container
;
51 namespace accessibility
{
53 AccessibleCell::AccessibleCell( const css::uno::Reference
< css::accessibility::XAccessible
>& rxParent
, sdr::table::CellRef xCell
, sal_Int32 nIndex
, const AccessibleShapeTreeInfo
& rShapeTreeInfo
)
54 : AccessibleCellBase( rxParent
, AccessibleRole::TABLE_CELL
)
55 , maShapeTreeInfo( rShapeTreeInfo
)
56 , mnIndexInParent( nIndex
)
57 , mxCell(std::move( xCell
))
59 //Init the pAccTable var
60 pAccTable
= dynamic_cast <AccessibleTableShape
*> (rxParent
.get());
64 AccessibleCell::~AccessibleCell()
66 DBG_ASSERT( mpText
== nullptr, "svx::AccessibleCell::~AccessibleCell(), not disposed!?" );
70 void AccessibleCell::Init()
72 SdrView
* pView
= maShapeTreeInfo
.GetSdrView();
73 const vcl::Window
* pWindow
= maShapeTreeInfo
.GetWindow ();
74 if( !((pView
!= nullptr) && (pWindow
!= nullptr) && mxCell
.is()))
77 // create AccessibleTextHelper to handle this shape's text
78 if( mxCell
->CanCreateEditOutlinerParaObject() || mxCell
->GetOutlinerParaObject() != nullptr )
80 // non-empty text -> use full-fledged edit source right away
82 mpText
.reset( new AccessibleTextHelper( std::make_unique
<SvxTextEditSource
>(mxCell
->GetObject(), mxCell
.get(), *pView
, *pWindow
->GetOutDev()) ) );
83 if( mxCell
.is() && mxCell
->IsActiveCell() )
85 mpText
->SetEventSource(this);
90 bool AccessibleCell::SetState (sal_Int64 aState
)
92 bool bStateHasChanged
= false;
94 if (aState
== AccessibleStateType::FOCUSED
&& mpText
!= nullptr)
96 // Offer FOCUSED state to edit engine and detect whether the state
98 bool bIsFocused
= mpText
->HaveFocus ();
100 bStateHasChanged
= (bIsFocused
!= mpText
->HaveFocus ());
103 bStateHasChanged
= AccessibleContextBase::SetState (aState
);
105 return bStateHasChanged
;
109 bool AccessibleCell::ResetState (sal_Int64 aState
)
111 bool bStateHasChanged
= false;
113 if (aState
== AccessibleStateType::FOCUSED
&& mpText
!= nullptr)
115 // Try to remove FOCUSED state from the edit engine and detect
116 // whether the state changes.
117 bool bIsFocused
= mpText
->HaveFocus ();
118 mpText
->SetFocus (false);
119 bStateHasChanged
= (bIsFocused
!= mpText
->HaveFocus ());
122 bStateHasChanged
= AccessibleContextBase::ResetState (aState
);
124 return bStateHasChanged
;
131 Any SAL_CALL
AccessibleCell::queryInterface( const Type
& aType
)
133 return AccessibleCellBase::queryInterface( aType
);
137 void SAL_CALL
AccessibleCell::acquire( ) noexcept
139 AccessibleCellBase::acquire();
143 void SAL_CALL
AccessibleCell::release( ) noexcept
145 AccessibleCellBase::release();
149 // XAccessibleContext
152 /** The children of this cell come from the paragraphs of text.
154 sal_Int64 SAL_CALL
AccessibleCell::getAccessibleChildCount()
156 SolarMutexGuard aSolarGuard
;
158 return mpText
!= nullptr ? mpText
->GetChildCount () : 0;
162 /** Forward the request to the shape. Return the requested shape or throw
163 an exception for a wrong index.
165 Reference
<XAccessible
> SAL_CALL
AccessibleCell::getAccessibleChild (sal_Int64 nIndex
)
167 SolarMutexGuard aSolarGuard
;
170 return mpText
->GetChild (nIndex
);
174 /** Return a copy of the state set.
180 sal_Int64 SAL_CALL
AccessibleCell::getAccessibleStateSet()
182 SolarMutexGuard aSolarGuard
;
183 ::osl::MutexGuard
aGuard (m_aMutex
);
184 sal_Int64 nStateSet
= 0;
186 if (rBHelper
.bDisposed
|| mpText
== nullptr)
188 // Return a minimal state set that only contains the DEFUNC state.
189 nStateSet
= AccessibleContextBase::getAccessibleStateSet ();
193 // Merge current FOCUSED state from edit engine.
194 if (mpText
!= nullptr)
196 if (mpText
->HaveFocus())
197 mnStateSet
|= AccessibleStateType::FOCUSED
;
199 mnStateSet
&= ~AccessibleStateType::FOCUSED
;
201 // Set the invisible state for merged cell
202 if (mxCell
.is() && mxCell
->isMerged())
203 mnStateSet
&= ~AccessibleStateType::VISIBLE
;
205 mnStateSet
|= AccessibleStateType::VISIBLE
;
208 //Just when the parent table is not read-only,set states EDITABLE,RESIZABLE,MOVEABLE
209 css::uno::Reference
<XAccessible
> xTempAcc
= getAccessibleParent();
212 css::uno::Reference
<XAccessibleContext
>
213 xTempAccContext
= xTempAcc
->getAccessibleContext();
214 if( xTempAccContext
.is() )
216 if (xTempAccContext
->getAccessibleStateSet() & AccessibleStateType::EDITABLE
)
218 mnStateSet
|= AccessibleStateType::EDITABLE
;
219 mnStateSet
|= AccessibleStateType::RESIZABLE
;
220 mnStateSet
|= AccessibleStateType::MOVEABLE
;
224 nStateSet
= mnStateSet
;
231 // XAccessibleComponent
234 sal_Bool SAL_CALL
AccessibleCell::containsPoint( const css::awt::Point
& aPoint
)
236 return AccessibleComponentBase::containsPoint( aPoint
);
239 /** The implementation below is at the moment straightforward. It iterates
240 over all children (and thereby instances all children which have not
241 been already instantiated) until a child covering the specified point is
243 This leaves room for improvement. For instance, first iterate only over
244 the already instantiated children and only if no match is found
245 instantiate the remaining ones.
247 Reference
<XAccessible
> SAL_CALL
AccessibleCell::getAccessibleAtPoint ( const css::awt::Point
& aPoint
)
249 SolarMutexGuard aSolarGuard
;
250 ::osl::MutexGuard
aGuard (m_aMutex
);
252 sal_Int64 nChildCount
= getAccessibleChildCount ();
253 for (sal_Int64 i
= 0; i
< nChildCount
; ++i
)
255 Reference
<XAccessible
> xChild (getAccessibleChild (i
));
258 Reference
<XAccessibleComponent
> xChildComponent (xChild
->getAccessibleContext(), uno::UNO_QUERY
);
259 if (xChildComponent
.is())
261 awt::Rectangle
aBBox (xChildComponent
->getBounds());
262 if ( (aPoint
.X
>= aBBox
.X
)
263 && (aPoint
.Y
>= aBBox
.Y
)
264 && (aPoint
.X
< aBBox
.X
+aBBox
.Width
)
265 && (aPoint
.Y
< aBBox
.Y
+aBBox
.Height
) )
271 // Have not found a child under the given point. Returning empty
272 // reference to indicate this.
273 return uno::Reference
<XAccessible
>();
277 css::awt::Rectangle SAL_CALL
AccessibleCell::getBounds()
279 SolarMutexGuard aSolarGuard
;
280 ::osl::MutexGuard
aGuard (m_aMutex
);
283 css::awt::Rectangle aBoundingBox
;
286 // Get the cell's bounding box in internal coordinates (in 100th of mm)
287 const ::tools::Rectangle
aCellRect( mxCell
->getCellRect() );
289 // Transform coordinates from internal to pixel.
290 if (maShapeTreeInfo
.GetViewForwarder() == nullptr)
291 throw uno::RuntimeException ("AccessibleCell has no valid view forwarder",static_cast<uno::XWeak
*>(this));
293 ::Size
aPixelSize( maShapeTreeInfo
.GetViewForwarder()->LogicToPixel(::Size(aCellRect
.GetWidth(), aCellRect
.GetHeight())) );
294 ::Point
aPixelPosition( maShapeTreeInfo
.GetViewForwarder()->LogicToPixel( aCellRect
.TopLeft() ));
296 // Clip the shape's bounding box with the bounding box of its parent.
297 Reference
<XAccessibleComponent
> xParentComponent ( getAccessibleParent(), uno::UNO_QUERY
);
298 if (xParentComponent
.is())
300 // Make the coordinates relative to the parent.
301 awt::Point
aParentLocation (xParentComponent
->getLocationOnScreen());
302 int x
= aPixelPosition
.getX() - aParentLocation
.X
;
303 int y
= aPixelPosition
.getY() - aParentLocation
.Y
;
305 // Clip with parent (with coordinates relative to itself).
306 ::tools::Rectangle
aBBox ( x
, y
, x
+ aPixelSize
.getWidth(), y
+ aPixelSize
.getHeight());
307 awt::Size
aParentSize (xParentComponent
->getSize());
308 ::tools::Rectangle
aParentBBox (0,0, aParentSize
.Width
, aParentSize
.Height
);
309 aBBox
= aBBox
.GetIntersection (aParentBBox
);
310 aBoundingBox
= awt::Rectangle ( aBBox
.Left(), aBBox
.Top(), aBBox
.getOpenWidth(), aBBox
.getOpenHeight());
314 SAL_INFO("svx", "parent does not support component");
315 aBoundingBox
= awt::Rectangle (aPixelPosition
.getX(), aPixelPosition
.getY(),aPixelSize
.getWidth(), aPixelSize
.getHeight());
323 css::awt::Point SAL_CALL
AccessibleCell::getLocation()
326 css::awt::Rectangle
aBoundingBox(getBounds());
327 return css::awt::Point(aBoundingBox
.X
, aBoundingBox
.Y
);
331 css::awt::Point SAL_CALL
AccessibleCell::getLocationOnScreen()
335 // Get relative position...
336 css::awt::Point
aLocation(getLocation ());
338 // ... and add absolute position of the parent.
339 Reference
<XAccessibleComponent
> xParentComponent( getAccessibleParent(), uno::UNO_QUERY
);
340 if(xParentComponent
.is())
342 css::awt::Point
aParentLocation(xParentComponent
->getLocationOnScreen());
343 aLocation
.X
+= aParentLocation
.X
;
344 aLocation
.Y
+= aParentLocation
.Y
;
348 SAL_WARN("svx", "parent does not support XAccessibleComponent");
355 awt::Size SAL_CALL
AccessibleCell::getSize()
358 awt::Rectangle
aBoundingBox (getBounds());
359 return awt::Size (aBoundingBox
.Width
, aBoundingBox
.Height
);
363 void SAL_CALL
AccessibleCell::grabFocus()
365 AccessibleComponentBase::grabFocus();
369 sal_Int32 SAL_CALL
AccessibleCell::getForeground()
374 return sal_Int32(0x0ffffffL
);
378 sal_Int32 SAL_CALL
AccessibleCell::getBackground()
387 // XAccessibleExtendedComponent
390 css::uno::Reference
< css::awt::XFont
> SAL_CALL
AccessibleCell::getFont()
393 return AccessibleComponentBase::getFont();
397 OUString SAL_CALL
AccessibleCell::getTitledBorderText()
399 return AccessibleComponentBase::getTitledBorderText();
403 OUString SAL_CALL
AccessibleCell::getToolTipText()
405 return AccessibleComponentBase::getToolTipText();
409 // XAccessibleEventBroadcaster
412 void SAL_CALL
AccessibleCell::addAccessibleEventListener( const Reference
<XAccessibleEventListener
>& rxListener
)
414 SolarMutexGuard aSolarGuard
;
415 ::osl::MutexGuard
aGuard (m_aMutex
);
416 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
418 Reference
<XInterface
> xSource( static_cast<XComponent
*>(this) );
419 lang::EventObject
aEventObj(xSource
);
420 rxListener
->disposing(aEventObj
);
424 AccessibleContextBase::addAccessibleEventListener (rxListener
);
425 if (mpText
!= nullptr)
426 mpText
->AddEventListener (rxListener
);
431 void SAL_CALL
AccessibleCell::removeAccessibleEventListener( const Reference
<XAccessibleEventListener
>& rxListener
)
433 SolarMutexGuard aSolarGuard
;
434 AccessibleContextBase::removeAccessibleEventListener(rxListener
);
435 if (mpText
!= nullptr)
436 mpText
->RemoveEventListener (rxListener
);
443 OUString SAL_CALL
AccessibleCell::getImplementationName()
445 return "AccessibleCell";
449 Sequence
<OUString
> SAL_CALL
AccessibleCell::getSupportedServiceNames()
452 const css::uno::Sequence
<OUString
> vals
{ "com.sun.star.drawing.AccessibleCell" };
453 return comphelper::concatSequences(AccessibleContextBase::getSupportedServiceNames(), vals
);
457 // IAccessibleViewForwarderListener
460 void AccessibleCell::ViewForwarderChanged()
462 // Inform all listeners that the graphical representation (i.e. size
463 // and/or position) of the shape has changed.
464 CommitChange(AccessibleEventId::VISIBLE_DATA_CHANGED
, Any(), Any(), -1);
466 // update our children that our screen position might have changed
468 mpText
->UpdateChildren();
475 void AccessibleCell::disposing()
477 SolarMutexGuard aSolarGuard
;
478 ::osl::MutexGuard
aGuard (m_aMutex
);
480 // Make sure to send an event that this object loses the focus in the
481 // case that it has the focus.
482 mnStateSet
&= ~AccessibleStateType::FOCUSED
;
484 if (mpText
!= nullptr)
490 // Cleanup. Remove references to objects to allow them to be
493 maShapeTreeInfo
.dispose();
495 // Call base classes.
496 AccessibleContextBase::dispose ();
499 sal_Int64 SAL_CALL
AccessibleCell::getAccessibleIndexInParent()
502 return mnIndexInParent
;
506 OUString
AccessibleCell::getCellName( sal_Int32 nCol
, sal_Int32 nRow
)
513 aBuf
.append( static_cast<sal_Unicode
>( 'A' +
514 static_cast<sal_uInt16
>(nCol
)));
518 OUStringChar(static_cast<sal_Unicode
>( 'A' +
519 (static_cast<sal_uInt16
>(nCol
) / 26) - 1))
520 + OUStringChar( static_cast<sal_Unicode
>( 'A' +
521 (static_cast<sal_uInt16
>(nCol
) % 26))) );
529 sal_Int32 nC
= nCol
% 26;
530 aStr
.append(static_cast<sal_Unicode
>( 'A' +
531 static_cast<sal_uInt16
>(nC
)));
533 nCol
= nCol
/ 26 - 1;
535 aStr
.append(static_cast<sal_Unicode
>( 'A' +
536 static_cast<sal_uInt16
>(nCol
)));
537 aBuf
.append(comphelper::string::reverseString(aStr
));
540 return aBuf
.makeStringAndClear();
543 OUString SAL_CALL
AccessibleCell::getAccessibleName()
546 SolarMutexGuard aSolarGuard
;
552 sal_Int32 nRow
= 0, nCol
= 0;
553 pAccTable
->getColumnAndRow(mnIndexInParent
, nCol
, nRow
);
554 return getCellName( nCol
, nRow
);
556 catch(const Exception
&)
561 return AccessibleCellBase::getAccessibleName();
564 void AccessibleCell::UpdateChildren()
567 mpText
->UpdateChildren();
570 /* MT: Above getAccessibleName was introduced with IA2 CWS, while below was introduce in 3.3 meanwhile. Check which one is correct
571 +If this is correct, we also don't need sdr::table::CellRef getCellRef(), UpdateChildren(), getCellName( sal_Int32 nCol, sal_Int32 nRow ) above
574 OUString SAL_CALL AccessibleCell::getAccessibleName() throw (css::uno::RuntimeException)
577 SolarMutexGuard aSolarGuard;
580 return mxCell->getName();
582 return AccessibleCellBase::getAccessibleName();
586 } // end of namespace accessibility
588 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */