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 <accessiblecell.hxx>
27 #include "svx/DescriptionGenerator.hxx"
29 #include <com/sun/star/accessibility/AccessibleRole.hpp>
30 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
32 #include <vcl/svapp.hxx>
34 #include <unotools/accessiblestatesethelper.hxx>
35 #include <comphelper/string.hxx>
36 #include <editeng/outlobj.hxx>
37 #include <svx/unoshtxt.hxx>
38 #include <svx/svdotext.hxx>
40 using namespace sdr::table
;
41 using namespace ::com::sun::star
;
42 using namespace ::com::sun::star::uno
;
43 using namespace ::com::sun::star::accessibility
;
44 using namespace ::com::sun::star::lang
;
45 using namespace ::com::sun::star::container
;
47 namespace accessibility
{
49 AccessibleCell::AccessibleCell( const ::com::sun::star::uno::Reference
< ::com::sun::star::accessibility::XAccessible
>& rxParent
, const sdr::table::CellRef
& rCell
, sal_Int32 nIndex
, const AccessibleShapeTreeInfo
& rShapeTreeInfo
)
50 : AccessibleCellBase( rxParent
, AccessibleRole::TABLE_CELL
)
51 , maShapeTreeInfo( rShapeTreeInfo
)
52 , mnIndexInParent( nIndex
)
56 //Init the pAccTable var
57 pAccTable
= dynamic_cast <AccessibleTableShape
*> (rxParent
.get());
62 AccessibleCell::~AccessibleCell()
64 DBG_ASSERT( mpText
== 0, "svx::AccessibleCell::~AccessibleCell(), not disposed!?" );
69 void AccessibleCell::Init()
71 SdrView
* pView
= maShapeTreeInfo
.GetSdrView();
72 const vcl::Window
* pWindow
= maShapeTreeInfo
.GetWindow ();
73 if( (pView
!= NULL
) && (pWindow
!= NULL
) && mxCell
.is())
75 OutlinerParaObject
* pOutlinerParaObject
= mxCell
->GetEditOutlinerParaObject(); // Get the OutlinerParaObject if text edit is active
77 bool bOwnParaObject
= pOutlinerParaObject
!= 0;
79 if( !pOutlinerParaObject
)
80 pOutlinerParaObject
= mxCell
->GetOutlinerParaObject();
82 // create AccessibleTextHelper to handle this shape's text
83 if( pOutlinerParaObject
)
85 // non-empty text -> use full-fledged edit source right away
86 ::std::unique_ptr
<SvxEditSource
> pEditSource( new SvxTextEditSource( mxCell
->GetObject(), mxCell
.get(), *pView
, *pWindow
) );
87 mpText
= new AccessibleTextHelper( std::move(pEditSource
) );
88 mpText
->SetEventSource(this);
92 delete pOutlinerParaObject
;
98 bool AccessibleCell::SetState (sal_Int16 aState
)
100 bool bStateHasChanged
= false;
102 if (aState
== AccessibleStateType::FOCUSED
&& mpText
!= NULL
)
104 // Offer FOCUSED state to edit engine and detect whether the state
106 bool bIsFocused
= mpText
->HaveFocus ();
107 mpText
->SetFocus (true);
108 bStateHasChanged
= (bIsFocused
!= mpText
->HaveFocus ());
111 bStateHasChanged
= AccessibleContextBase::SetState (aState
);
113 return bStateHasChanged
;
118 bool AccessibleCell::ResetState (sal_Int16 aState
)
120 bool bStateHasChanged
= false;
122 if (aState
== AccessibleStateType::FOCUSED
&& mpText
!= NULL
)
124 // Try to remove FOCUSED state from the edit engine and detect
125 // whether the state changes.
126 bool bIsFocused
= mpText
->HaveFocus ();
127 mpText
->SetFocus (false);
128 bStateHasChanged
= (bIsFocused
!= mpText
->HaveFocus ());
131 bStateHasChanged
= AccessibleContextBase::ResetState (aState
);
133 return bStateHasChanged
;
138 bool AccessibleCell::operator== (const AccessibleCell
& rAccessibleCell
)
140 return this == &rAccessibleCell
;
147 Any SAL_CALL
AccessibleCell::queryInterface( const Type
& aType
) throw (RuntimeException
, std::exception
)
149 return AccessibleCellBase::queryInterface( aType
);
154 void SAL_CALL
AccessibleCell::acquire( ) throw ()
156 AccessibleCellBase::acquire();
161 void SAL_CALL
AccessibleCell::release( ) throw ()
163 AccessibleCellBase::release();
167 // XAccessibleContext
170 /** The children of this cell come from the paragraphs of text.
172 sal_Int32 SAL_CALL
AccessibleCell::getAccessibleChildCount() throw (::com::sun::star::uno::RuntimeException
, std::exception
)
174 SolarMutexGuard aSolarGuard
;
176 return mpText
!= NULL
? mpText
->GetChildCount () : 0;
181 /** Forward the request to the shape. Return the requested shape or throw
182 an exception for a wrong index.
184 Reference
<XAccessible
> SAL_CALL
AccessibleCell::getAccessibleChild (sal_Int32 nIndex
) throw (IndexOutOfBoundsException
, RuntimeException
, std::exception
)
186 SolarMutexGuard aSolarGuard
;
189 // todo: does GetChild throw IndexOutOfBoundsException?
190 return mpText
->GetChild (nIndex
);
195 /** Return a copy of the state set.
201 Reference
<XAccessibleStateSet
> SAL_CALL
AccessibleCell::getAccessibleStateSet() throw (RuntimeException
, std::exception
)
203 SolarMutexGuard aSolarGuard
;
204 ::osl::MutexGuard
aGuard (maMutex
);
205 Reference
<XAccessibleStateSet
> xStateSet
;
207 if (rBHelper
.bDisposed
|| mpText
== NULL
)
209 // Return a minimal state set that only contains the DEFUNC state.
210 xStateSet
= AccessibleContextBase::getAccessibleStateSet ();
214 ::utl::AccessibleStateSetHelper
* pStateSet
= static_cast< ::utl::AccessibleStateSetHelper
*>(mxStateSet
.get());
218 // Merge current FOCUSED state from edit engine.
221 if (mpText
->HaveFocus())
222 pStateSet
->AddState (AccessibleStateType::FOCUSED
);
224 pStateSet
->RemoveState (AccessibleStateType::FOCUSED
);
226 // Set the invisible state for merged cell
227 if (mxCell
.is() && mxCell
->isMerged())
228 pStateSet
->RemoveState(AccessibleStateType::VISIBLE
);
230 pStateSet
->AddState(AccessibleStateType::VISIBLE
);
233 //Just when the parent table is not read-only,set states EDITABLE,RESIZABLE,MOVEABLE
234 ::com::sun::star::uno::Reference
<XAccessible
> xTempAcc
= getAccessibleParent();
237 ::com::sun::star::uno::Reference
<XAccessibleContext
>
238 xTempAccContext
= xTempAcc
->getAccessibleContext();
239 if( xTempAccContext
.is() )
241 ::com::sun::star::uno::Reference
<XAccessibleStateSet
> rState
=
242 xTempAccContext
->getAccessibleStateSet();
244 com::sun::star::uno::Sequence
<short> pStates
= rState
->getStates();
245 int count
= pStates
.getLength();
246 for( int iIndex
= 0;iIndex
< count
;iIndex
++ )
248 if( pStates
[iIndex
] == AccessibleStateType::EDITABLE
)
250 pStateSet
->AddState (AccessibleStateType::EDITABLE
);
251 pStateSet
->AddState (AccessibleStateType::RESIZABLE
);
252 pStateSet
->AddState (AccessibleStateType::MOVEABLE
);
259 // Create a copy of the state set that may be modified by the
260 // caller without affecting the current state set.
261 xStateSet
= Reference
<XAccessibleStateSet
>(new ::utl::AccessibleStateSetHelper (*pStateSet
));
269 // XAccessibleComponent
272 sal_Bool SAL_CALL
AccessibleCell::containsPoint( const ::com::sun::star::awt::Point
& aPoint
) throw (::com::sun::star::uno::RuntimeException
, std::exception
)
274 return AccessibleComponentBase::containsPoint( aPoint
);
277 /** The implementation below is at the moment straightforward. It iterates
278 over all children (and thereby instances all children which have not
279 been already instatiated) until a child covering the specifed point is
281 This leaves room for improvement. For instance, first iterate only over
282 the already instantiated children and only if no match is found
283 instantiate the remaining ones.
285 Reference
<XAccessible
> SAL_CALL
AccessibleCell::getAccessibleAtPoint ( const ::com::sun::star::awt::Point
& aPoint
) throw(RuntimeException
, std::exception
)
287 SolarMutexGuard aSolarGuard
;
288 ::osl::MutexGuard
aGuard (maMutex
);
290 sal_Int32 nChildCount
= getAccessibleChildCount ();
291 for (sal_Int32 i
=0; i
<nChildCount
; ++i
)
293 Reference
<XAccessible
> xChild (getAccessibleChild (i
));
296 Reference
<XAccessibleComponent
> xChildComponent (xChild
->getAccessibleContext(), uno::UNO_QUERY
);
297 if (xChildComponent
.is())
299 awt::Rectangle
aBBox (xChildComponent
->getBounds());
300 if ( (aPoint
.X
>= aBBox
.X
)
301 && (aPoint
.Y
>= aBBox
.Y
)
302 && (aPoint
.X
< aBBox
.X
+aBBox
.Width
)
303 && (aPoint
.Y
< aBBox
.Y
+aBBox
.Height
) )
309 // Have not found a child under the given point. Returning empty
310 // reference to indicate this.
311 return uno::Reference
<XAccessible
>();
316 ::com::sun::star::awt::Rectangle SAL_CALL
AccessibleCell::getBounds() throw(RuntimeException
, std::exception
)
318 SolarMutexGuard aSolarGuard
;
319 ::osl::MutexGuard
aGuard (maMutex
);
322 ::com::sun::star::awt::Rectangle aBoundingBox
;
325 // Get the cell's bounding box in internal coordinates (in 100th of mm)
326 const ::Rectangle
aCellRect( mxCell
->getCellRect() );
328 // Transform coordinates from internal to pixel.
329 if (maShapeTreeInfo
.GetViewForwarder() == NULL
)
330 throw uno::RuntimeException ("AccessibleCell has no valid view forwarder",static_cast<uno::XWeak
*>(this));
332 ::Size
aPixelSize( maShapeTreeInfo
.GetViewForwarder()->LogicToPixel(::Size(aCellRect
.GetWidth(), aCellRect
.GetHeight())) );
333 ::Point
aPixelPosition( maShapeTreeInfo
.GetViewForwarder()->LogicToPixel( aCellRect
.TopLeft() ));
335 // Clip the shape's bounding box with the bounding box of its parent.
336 Reference
<XAccessibleComponent
> xParentComponent ( getAccessibleParent(), uno::UNO_QUERY
);
337 if (xParentComponent
.is())
339 // Make the coordinates relative to the parent.
340 awt::Point
aParentLocation (xParentComponent
->getLocationOnScreen());
341 int x
= aPixelPosition
.getX() - aParentLocation
.X
;
342 int y
= aPixelPosition
.getY() - aParentLocation
.Y
;
344 // Clip with parent (with coordinates relative to itself).
345 ::Rectangle
aBBox ( x
, y
, x
+ aPixelSize
.getWidth(), y
+ aPixelSize
.getHeight());
346 awt::Size
aParentSize (xParentComponent
->getSize());
347 ::Rectangle
aParentBBox (0,0, aParentSize
.Width
, aParentSize
.Height
);
348 aBBox
= aBBox
.GetIntersection (aParentBBox
);
349 aBoundingBox
= awt::Rectangle ( aBBox
.getX(), aBBox
.getY(), aBBox
.getWidth(), aBBox
.getHeight());
353 OSL_TRACE ("parent does not support component");
354 aBoundingBox
= awt::Rectangle (aPixelPosition
.getX(), aPixelPosition
.getY(),aPixelSize
.getWidth(), aPixelSize
.getHeight());
363 ::com::sun::star::awt::Point SAL_CALL
AccessibleCell::getLocation() throw (RuntimeException
, std::exception
)
366 ::com::sun::star::awt::Rectangle
aBoundingBox(getBounds());
367 return ::com::sun::star::awt::Point(aBoundingBox
.X
, aBoundingBox
.Y
);
372 ::com::sun::star::awt::Point SAL_CALL
AccessibleCell::getLocationOnScreen() throw(RuntimeException
, std::exception
)
376 // Get relative position...
377 ::com::sun::star::awt::Point
aLocation(getLocation ());
379 // ... and add absolute position of the parent.
380 Reference
<XAccessibleComponent
> xParentComponent( getAccessibleParent(), uno::UNO_QUERY
);
381 if(xParentComponent
.is())
383 ::com::sun::star::awt::Point
aParentLocation(xParentComponent
->getLocationOnScreen());
384 aLocation
.X
+= aParentLocation
.X
;
385 aLocation
.Y
+= aParentLocation
.Y
;
389 OSL_TRACE ("getLocation: parent does not support XAccessibleComponent");
397 awt::Size SAL_CALL
AccessibleCell::getSize() throw (RuntimeException
, std::exception
)
400 awt::Rectangle
aBoundingBox (getBounds());
401 return awt::Size (aBoundingBox
.Width
, aBoundingBox
.Height
);
406 void SAL_CALL
AccessibleCell::addFocusListener ( const ::com::sun::star::uno::Reference
< ::com::sun::star::awt::XFocusListener
>& xListener
) throw (::com::sun::star::uno::RuntimeException
)
408 AccessibleComponentBase::addFocusListener( xListener
);
413 void SAL_CALL
AccessibleCell::removeFocusListener (const ::com::sun::star::uno::Reference
< ::com::sun::star::awt::XFocusListener
>& xListener
) throw (::com::sun::star::uno::RuntimeException
)
415 AccessibleComponentBase::removeFocusListener( xListener
);
420 void SAL_CALL
AccessibleCell::grabFocus() throw (::com::sun::star::uno::RuntimeException
, std::exception
)
422 AccessibleComponentBase::grabFocus();
427 sal_Int32 SAL_CALL
AccessibleCell::getForeground() throw (RuntimeException
, std::exception
)
430 sal_Int32
nColor (0x0ffffffL
);
438 sal_Int32 SAL_CALL
AccessibleCell::getBackground() throw (RuntimeException
, std::exception
)
441 sal_Int32
nColor (0L);
448 // XAccessibleExtendedComponent
451 ::com::sun::star::uno::Reference
< ::com::sun::star::awt::XFont
> SAL_CALL
AccessibleCell::getFont() throw (::com::sun::star::uno::RuntimeException
, std::exception
)
454 return AccessibleComponentBase::getFont();
459 OUString SAL_CALL
AccessibleCell::getTitledBorderText() throw (::com::sun::star::uno::RuntimeException
, std::exception
)
461 return AccessibleComponentBase::getTitledBorderText();
466 OUString SAL_CALL
AccessibleCell::getToolTipText() throw (::com::sun::star::uno::RuntimeException
, std::exception
)
468 return AccessibleComponentBase::getToolTipText();
472 // XAccessibleEventBroadcaster
475 void SAL_CALL
AccessibleCell::addAccessibleEventListener( const Reference
<XAccessibleEventListener
>& rxListener
) throw (RuntimeException
, std::exception
)
477 SolarMutexGuard aSolarGuard
;
478 ::osl::MutexGuard
aGuard (maMutex
);
479 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
481 Reference
<XInterface
> xSource( static_cast<XComponent
*>(this) );
482 lang::EventObject
aEventObj(xSource
);
483 rxListener
->disposing(aEventObj
);
487 AccessibleContextBase::addAccessibleEventListener (rxListener
);
489 mpText
->AddEventListener (rxListener
);
495 void SAL_CALL
AccessibleCell::removeAccessibleEventListener( const Reference
<XAccessibleEventListener
>& rxListener
) throw (RuntimeException
, std::exception
)
497 SolarMutexGuard aSolarGuard
;
498 AccessibleContextBase::removeAccessibleEventListener(rxListener
);
500 mpText
->RemoveEventListener (rxListener
);
507 OUString SAL_CALL
AccessibleCell::getImplementationName() throw (RuntimeException
, std::exception
)
509 return OUString("AccessibleCell");
514 Sequence
<OUString
> SAL_CALL
AccessibleCell::getSupportedServiceNames() throw (RuntimeException
, std::exception
)
518 // Get list of supported service names from base class...
519 uno::Sequence
<OUString
> aServiceNames
= AccessibleContextBase::getSupportedServiceNames();
520 sal_Int32
nCount (aServiceNames
.getLength());
522 // ...and add additional names.
523 aServiceNames
.realloc (nCount
+ 1);
524 aServiceNames
[nCount
] = "com.sun.star.drawing.AccessibleCell";
526 return aServiceNames
;
530 // IAccessibleViewForwarderListener
533 void AccessibleCell::ViewForwarderChanged (ChangeType
/*aChangeType*/, const IAccessibleViewForwarder
* /*pViewForwarder*/)
535 // Inform all listeners that the graphical representation (i.e. size
536 // and/or position) of the shape has changed.
537 CommitChange(AccessibleEventId::VISIBLE_DATA_CHANGED
, Any(), Any());
539 // update our children that our screen position might have changed
541 mpText
->UpdateChildren();
548 void AccessibleCell::disposing()
550 SolarMutexGuard aSolarGuard
;
551 ::osl::MutexGuard
aGuard (maMutex
);
553 // Make sure to send an event that this object loses the focus in the
554 // case that it has the focus.
555 ::utl::AccessibleStateSetHelper
* pStateSet
= static_cast< ::utl::AccessibleStateSetHelper
*>(mxStateSet
.get());
556 if (pStateSet
!= NULL
)
557 pStateSet
->RemoveState(AccessibleStateType::FOCUSED
);
566 // Cleanup. Remove references to objects to allow them to be
569 maShapeTreeInfo
= AccessibleShapeTreeInfo();
571 // Call base classes.
572 AccessibleContextBase::dispose ();
575 sal_Int32 SAL_CALL
AccessibleCell::getAccessibleIndexInParent() throw (RuntimeException
, std::exception
)
578 return mnIndexInParent
;
582 OUString
AccessibleCell::getCellName( sal_Int32 nCol
, sal_Int32 nRow
)
589 aBuf
.append( static_cast<sal_Unicode
>( 'A' +
590 static_cast<sal_uInt16
>(nCol
)));
593 aBuf
.append( static_cast<sal_Unicode
>( 'A' +
594 (static_cast<sal_uInt16
>(nCol
) / 26) - 1));
595 aBuf
.append( static_cast<sal_Unicode
>( 'A' +
596 (static_cast<sal_uInt16
>(nCol
) % 26)));
604 sal_Int32 nC
= nCol
% 26;
605 aStr
.append(static_cast<sal_Unicode
>( 'A' +
606 static_cast<sal_uInt16
>(nC
)));
608 nCol
= nCol
/ 26 - 1;
610 aStr
.append(static_cast<sal_Unicode
>( 'A' +
611 static_cast<sal_uInt16
>(nCol
)));
612 aBuf
.append(comphelper::string::reverseString(aStr
.makeStringAndClear()));
614 aBuf
.append( OUString::number(nRow
+1) );
615 return aBuf
.makeStringAndClear();
618 OUString SAL_CALL
AccessibleCell::getAccessibleName() throw (::com::sun::star::uno::RuntimeException
, std::exception
)
621 SolarMutexGuard aSolarGuard
;
627 sal_Int32 nRow
= 0, nCol
= 0;
628 pAccTable
->getColumnAndRow(mnIndexInParent
, nCol
, nRow
);
629 return getCellName( nCol
, nRow
);
631 catch(const Exception
&)
636 return AccessibleCellBase::getAccessibleName();
639 void AccessibleCell::UpdateChildren()
642 mpText
->UpdateChildren();
645 /* MT: Above getAccessibleName was introduced with IA2 CWS, while below was introduce in 3.3 meanwhile. Check which one is correct
646 +If this is correct, we also don't need sdr::table::CellRef getCellRef(), UpdateChildren(), getCellName( sal_Int32 nCol, sal_Int32 nRow ) above
649 OUString SAL_CALL AccessibleCell::getAccessibleName() throw (::com::sun::star::uno::RuntimeException)
652 SolarMutexGuard aSolarGuard;
655 return mxCell->getName();
657 return AccessibleCellBase::getAccessibleName();
661 } // end of namespace accessibility
663 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */