bump product version to 5.0.4.1
[LibreOffice.git] / svx / source / table / accessiblecell.cxx
blobb41e5002f8e3c828a2671eff49a37fd00925e219
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
22 #include <memory>
23 #include <utility>
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 )
53 , mpText( NULL )
54 , mxCell( rCell )
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);
91 if( bOwnParaObject)
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
105 // changes.
106 bool bIsFocused = mpText->HaveFocus ();
107 mpText->SetFocus (true);
108 bStateHasChanged = (bIsFocused != mpText->HaveFocus ());
110 else
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 ());
130 else
131 bStateHasChanged = AccessibleContextBase::ResetState (aState);
133 return bStateHasChanged;
138 bool AccessibleCell::operator== (const AccessibleCell& rAccessibleCell)
140 return this == &rAccessibleCell;
144 // XInterface
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;
175 ThrowIfDisposed ();
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;
187 ThrowIfDisposed ();
189 // todo: does GetChild throw IndexOutOfBoundsException?
190 return mpText->GetChild (nIndex);
195 /** Return a copy of the state set.
196 Possible states are:
197 ENABLED
198 SHOWING
199 VISIBLE
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 ();
212 else
214 ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
216 if(pStateSet)
218 // Merge current FOCUSED state from edit engine.
219 if (mpText != NULL)
221 if (mpText->HaveFocus())
222 pStateSet->AddState (AccessibleStateType::FOCUSED);
223 else
224 pStateSet->RemoveState (AccessibleStateType::FOCUSED);
226 // Set the invisible state for merged cell
227 if (mxCell.is() && mxCell->isMerged())
228 pStateSet->RemoveState(AccessibleStateType::VISIBLE);
229 else
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();
235 if( xTempAcc.is() )
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();
243 if( rState.is() ) {
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);
253 break;
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));
265 return xStateSet;
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
280 found.
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));
294 if (xChild.is())
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) )
304 return xChild;
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);
321 ThrowIfDisposed ();
322 ::com::sun::star::awt::Rectangle aBoundingBox;
323 if( mxCell.is() )
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());
351 else
353 OSL_TRACE ("parent does not support component");
354 aBoundingBox = awt::Rectangle (aPixelPosition.getX(), aPixelPosition.getY(),aPixelSize.getWidth(), aPixelSize.getHeight());
358 return aBoundingBox;
363 ::com::sun::star::awt::Point SAL_CALL AccessibleCell::getLocation() throw (RuntimeException, std::exception)
365 ThrowIfDisposed ();
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)
374 ThrowIfDisposed ();
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;
387 else
389 OSL_TRACE ("getLocation: parent does not support XAccessibleComponent");
392 return aLocation;
397 awt::Size SAL_CALL AccessibleCell::getSize() throw (RuntimeException, std::exception)
399 ThrowIfDisposed ();
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)
429 ThrowIfDisposed ();
430 sal_Int32 nColor (0x0ffffffL);
432 // todo
433 return nColor;
438 sal_Int32 SAL_CALL AccessibleCell::getBackground() throw (RuntimeException, std::exception)
440 ThrowIfDisposed ();
441 sal_Int32 nColor (0L);
443 // todo
444 return nColor;
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)
453 //todo
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);
485 else
487 AccessibleContextBase::addAccessibleEventListener (rxListener);
488 if (mpText != NULL)
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);
499 if (mpText != NULL)
500 mpText->RemoveEventListener (rxListener);
504 // XServiceInfo
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)
516 ThrowIfDisposed ();
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
540 if( mpText )
541 mpText->UpdateChildren();
545 // protected
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);
559 if (mpText != NULL)
561 mpText->Dispose();
562 delete mpText;
563 mpText = NULL;
566 // Cleanup. Remove references to objects to allow them to be
567 // destroyed.
568 mxCell.clear();
569 maShapeTreeInfo = AccessibleShapeTreeInfo();
571 // Call base classes.
572 AccessibleContextBase::dispose ();
575 sal_Int32 SAL_CALL AccessibleCell::getAccessibleIndexInParent() throw (RuntimeException, std::exception)
577 ThrowIfDisposed ();
578 return mnIndexInParent;
582 OUString AccessibleCell::getCellName( sal_Int32 nCol, sal_Int32 nRow )
584 OUStringBuffer aBuf;
586 if (nCol < 26*26)
588 if (nCol < 26)
589 aBuf.append( static_cast<sal_Unicode>( 'A' +
590 static_cast<sal_uInt16>(nCol)));
591 else
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)));
599 else
601 OUStringBuffer aStr;
602 while (nCol >= 26)
604 sal_Int32 nC = nCol % 26;
605 aStr.append(static_cast<sal_Unicode>( 'A' +
606 static_cast<sal_uInt16>(nC)));
607 nCol = nCol - 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)
620 ThrowIfDisposed ();
621 SolarMutexGuard aSolarGuard;
623 if( pAccTable )
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()
641 if (mpText)
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)
651 ThrowIfDisposed ();
652 SolarMutexGuard aSolarGuard;
654 if( mxCell.is() )
655 return mxCell->getName();
657 return AccessibleCellBase::getAccessibleName();
661 } // end of namespace accessibility
663 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */