Bump version to 6.4-15
[LibreOffice.git] / svx / source / table / accessiblecell.cxx
blob77c91a0db481f729c6db6e571c8c66eb0a4a0422
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>
21 #include <sal/log.hxx>
23 #include <memory>
24 #include <utility>
26 #include "accessiblecell.hxx"
28 #include <svx/DescriptionGenerator.hxx>
30 #include <com/sun/star/accessibility/AccessibleRole.hpp>
31 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
32 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
34 #include <vcl/svapp.hxx>
36 #include <unotools/accessiblestatesethelper.hxx>
37 #include <comphelper/string.hxx>
38 #include <editeng/outlobj.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, const sdr::table::CellRef& rCell, sal_Int32 nIndex, const AccessibleShapeTreeInfo& rShapeTreeInfo )
54 : AccessibleCellBase( rxParent, AccessibleRole::TABLE_CELL )
55 , maShapeTreeInfo( rShapeTreeInfo )
56 , mnIndexInParent( nIndex )
57 , mxCell( rCell )
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())
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) ) );
82 if( mxCell.is() && mxCell->IsActiveCell() )
83 mpText->SetFocus();
84 mpText->SetEventSource(this);
90 bool AccessibleCell::SetState (sal_Int16 aState)
92 bool bStateHasChanged = false;
94 if (aState == AccessibleStateType::FOCUSED && mpText != nullptr)
96 // Offer FOCUSED state to edit engine and detect whether the state
97 // changes.
98 bool bIsFocused = mpText->HaveFocus ();
99 mpText->SetFocus();
100 bStateHasChanged = (bIsFocused != mpText->HaveFocus ());
102 else
103 bStateHasChanged = AccessibleContextBase::SetState (aState);
105 return bStateHasChanged;
109 bool AccessibleCell::ResetState (sal_Int16 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 ());
121 else
122 bStateHasChanged = AccessibleContextBase::ResetState (aState);
124 return bStateHasChanged;
128 // XInterface
131 Any SAL_CALL AccessibleCell::queryInterface( const Type& aType )
133 return AccessibleCellBase::queryInterface( aType );
137 void SAL_CALL AccessibleCell::acquire( ) throw ()
139 AccessibleCellBase::acquire();
143 void SAL_CALL AccessibleCell::release( ) throw ()
145 AccessibleCellBase::release();
149 // XAccessibleContext
152 /** The children of this cell come from the paragraphs of text.
154 sal_Int32 SAL_CALL AccessibleCell::getAccessibleChildCount()
156 SolarMutexGuard aSolarGuard;
157 ThrowIfDisposed ();
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_Int32 nIndex)
167 SolarMutexGuard aSolarGuard;
168 ThrowIfDisposed ();
170 // todo: does GetChild throw IndexOutOfBoundsException?
171 return mpText->GetChild (nIndex);
175 /** Return a copy of the state set.
176 Possible states are:
177 ENABLED
178 SHOWING
179 VISIBLE
181 Reference<XAccessibleStateSet> SAL_CALL AccessibleCell::getAccessibleStateSet()
183 SolarMutexGuard aSolarGuard;
184 ::osl::MutexGuard aGuard (maMutex);
185 Reference<XAccessibleStateSet> xStateSet;
187 if (rBHelper.bDisposed || mpText == nullptr)
189 // Return a minimal state set that only contains the DEFUNC state.
190 xStateSet = AccessibleContextBase::getAccessibleStateSet ();
192 else
194 ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
196 if(pStateSet)
198 // Merge current FOCUSED state from edit engine.
199 if (mpText != nullptr)
201 if (mpText->HaveFocus())
202 pStateSet->AddState (AccessibleStateType::FOCUSED);
203 else
204 pStateSet->RemoveState (AccessibleStateType::FOCUSED);
206 // Set the invisible state for merged cell
207 if (mxCell.is() && mxCell->isMerged())
208 pStateSet->RemoveState(AccessibleStateType::VISIBLE);
209 else
210 pStateSet->AddState(AccessibleStateType::VISIBLE);
213 //Just when the parent table is not read-only,set states EDITABLE,RESIZABLE,MOVEABLE
214 css::uno::Reference<XAccessible> xTempAcc = getAccessibleParent();
215 if( xTempAcc.is() )
217 css::uno::Reference<XAccessibleContext>
218 xTempAccContext = xTempAcc->getAccessibleContext();
219 if( xTempAccContext.is() )
221 css::uno::Reference<XAccessibleStateSet> rState =
222 xTempAccContext->getAccessibleStateSet();
223 if( rState.is() )
225 css::uno::Sequence<short> aStates = rState->getStates();
226 if (std::find(aStates.begin(), aStates.end(), AccessibleStateType::EDITABLE) != aStates.end())
228 pStateSet->AddState (AccessibleStateType::EDITABLE);
229 pStateSet->AddState (AccessibleStateType::RESIZABLE);
230 pStateSet->AddState (AccessibleStateType::MOVEABLE);
235 // Create a copy of the state set that may be modified by the
236 // caller without affecting the current state set.
237 xStateSet.set(new ::utl::AccessibleStateSetHelper (*pStateSet));
241 return xStateSet;
245 // XAccessibleComponent
248 sal_Bool SAL_CALL AccessibleCell::containsPoint( const css::awt::Point& aPoint)
250 return AccessibleComponentBase::containsPoint( aPoint );
253 /** The implementation below is at the moment straightforward. It iterates
254 over all children (and thereby instances all children which have not
255 been already instantiated) until a child covering the specified point is
256 found.
257 This leaves room for improvement. For instance, first iterate only over
258 the already instantiated children and only if no match is found
259 instantiate the remaining ones.
261 Reference<XAccessible > SAL_CALL AccessibleCell::getAccessibleAtPoint ( const css::awt::Point& aPoint)
263 SolarMutexGuard aSolarGuard;
264 ::osl::MutexGuard aGuard (maMutex);
266 sal_Int32 nChildCount = getAccessibleChildCount ();
267 for (sal_Int32 i=0; i<nChildCount; ++i)
269 Reference<XAccessible> xChild (getAccessibleChild (i));
270 if (xChild.is())
272 Reference<XAccessibleComponent> xChildComponent (xChild->getAccessibleContext(), uno::UNO_QUERY);
273 if (xChildComponent.is())
275 awt::Rectangle aBBox (xChildComponent->getBounds());
276 if ( (aPoint.X >= aBBox.X)
277 && (aPoint.Y >= aBBox.Y)
278 && (aPoint.X < aBBox.X+aBBox.Width)
279 && (aPoint.Y < aBBox.Y+aBBox.Height) )
280 return xChild;
285 // Have not found a child under the given point. Returning empty
286 // reference to indicate this.
287 return uno::Reference<XAccessible>();
291 css::awt::Rectangle SAL_CALL AccessibleCell::getBounds()
293 SolarMutexGuard aSolarGuard;
294 ::osl::MutexGuard aGuard (maMutex);
296 ThrowIfDisposed ();
297 css::awt::Rectangle aBoundingBox;
298 if( mxCell.is() )
300 // Get the cell's bounding box in internal coordinates (in 100th of mm)
301 const ::tools::Rectangle aCellRect( mxCell->getCellRect() );
303 // Transform coordinates from internal to pixel.
304 if (maShapeTreeInfo.GetViewForwarder() == nullptr)
305 throw uno::RuntimeException ("AccessibleCell has no valid view forwarder",static_cast<uno::XWeak*>(this));
307 ::Size aPixelSize( maShapeTreeInfo.GetViewForwarder()->LogicToPixel(::Size(aCellRect.GetWidth(), aCellRect.GetHeight())) );
308 ::Point aPixelPosition( maShapeTreeInfo.GetViewForwarder()->LogicToPixel( aCellRect.TopLeft() ));
310 // Clip the shape's bounding box with the bounding box of its parent.
311 Reference<XAccessibleComponent> xParentComponent ( getAccessibleParent(), uno::UNO_QUERY);
312 if (xParentComponent.is())
314 // Make the coordinates relative to the parent.
315 awt::Point aParentLocation (xParentComponent->getLocationOnScreen());
316 int x = aPixelPosition.getX() - aParentLocation.X;
317 int y = aPixelPosition.getY() - aParentLocation.Y;
319 // Clip with parent (with coordinates relative to itself).
320 ::tools::Rectangle aBBox ( x, y, x + aPixelSize.getWidth(), y + aPixelSize.getHeight());
321 awt::Size aParentSize (xParentComponent->getSize());
322 ::tools::Rectangle aParentBBox (0,0, aParentSize.Width, aParentSize.Height);
323 aBBox = aBBox.GetIntersection (aParentBBox);
324 aBoundingBox = awt::Rectangle ( aBBox.getX(), aBBox.getY(), aBBox.getWidth(), aBBox.getHeight());
326 else
328 SAL_INFO("svx", "parent does not support component");
329 aBoundingBox = awt::Rectangle (aPixelPosition.getX(), aPixelPosition.getY(),aPixelSize.getWidth(), aPixelSize.getHeight());
333 return aBoundingBox;
337 css::awt::Point SAL_CALL AccessibleCell::getLocation()
339 ThrowIfDisposed ();
340 css::awt::Rectangle aBoundingBox(getBounds());
341 return css::awt::Point(aBoundingBox.X, aBoundingBox.Y);
345 css::awt::Point SAL_CALL AccessibleCell::getLocationOnScreen()
347 ThrowIfDisposed ();
349 // Get relative position...
350 css::awt::Point aLocation(getLocation ());
352 // ... and add absolute position of the parent.
353 Reference<XAccessibleComponent> xParentComponent( getAccessibleParent(), uno::UNO_QUERY);
354 if(xParentComponent.is())
356 css::awt::Point aParentLocation(xParentComponent->getLocationOnScreen());
357 aLocation.X += aParentLocation.X;
358 aLocation.Y += aParentLocation.Y;
360 else
362 SAL_WARN("svx", "parent does not support XAccessibleComponent");
365 return aLocation;
369 awt::Size SAL_CALL AccessibleCell::getSize()
371 ThrowIfDisposed ();
372 awt::Rectangle aBoundingBox (getBounds());
373 return awt::Size (aBoundingBox.Width, aBoundingBox.Height);
377 void SAL_CALL AccessibleCell::grabFocus()
379 AccessibleComponentBase::grabFocus();
383 sal_Int32 SAL_CALL AccessibleCell::getForeground()
385 ThrowIfDisposed ();
387 // todo
388 return sal_Int32(0x0ffffffL);
392 sal_Int32 SAL_CALL AccessibleCell::getBackground()
394 ThrowIfDisposed ();
396 // todo
397 return 0;
401 // XAccessibleExtendedComponent
404 css::uno::Reference< css::awt::XFont > SAL_CALL AccessibleCell::getFont()
406 //todo
407 return AccessibleComponentBase::getFont();
411 OUString SAL_CALL AccessibleCell::getTitledBorderText()
413 return AccessibleComponentBase::getTitledBorderText();
417 OUString SAL_CALL AccessibleCell::getToolTipText()
419 return AccessibleComponentBase::getToolTipText();
423 // XAccessibleEventBroadcaster
426 void SAL_CALL AccessibleCell::addAccessibleEventListener( const Reference<XAccessibleEventListener >& rxListener)
428 SolarMutexGuard aSolarGuard;
429 ::osl::MutexGuard aGuard (maMutex);
430 if (rBHelper.bDisposed || rBHelper.bInDispose)
432 Reference<XInterface> xSource( static_cast<XComponent *>(this) );
433 lang::EventObject aEventObj(xSource);
434 rxListener->disposing(aEventObj);
436 else
438 AccessibleContextBase::addAccessibleEventListener (rxListener);
439 if (mpText != nullptr)
440 mpText->AddEventListener (rxListener);
445 void SAL_CALL AccessibleCell::removeAccessibleEventListener( const Reference<XAccessibleEventListener >& rxListener)
447 SolarMutexGuard aSolarGuard;
448 AccessibleContextBase::removeAccessibleEventListener(rxListener);
449 if (mpText != nullptr)
450 mpText->RemoveEventListener (rxListener);
454 // XServiceInfo
457 OUString SAL_CALL AccessibleCell::getImplementationName()
459 return "AccessibleCell";
463 Sequence<OUString> SAL_CALL AccessibleCell::getSupportedServiceNames()
465 ThrowIfDisposed ();
467 // Get list of supported service names from base class...
468 uno::Sequence<OUString> aServiceNames = AccessibleContextBase::getSupportedServiceNames();
469 sal_Int32 nCount (aServiceNames.getLength());
471 // ...and add additional names.
472 aServiceNames.realloc (nCount + 1);
473 aServiceNames[nCount] = "com.sun.star.drawing.AccessibleCell";
475 return aServiceNames;
479 // IAccessibleViewForwarderListener
482 void AccessibleCell::ViewForwarderChanged()
484 // Inform all listeners that the graphical representation (i.e. size
485 // and/or position) of the shape has changed.
486 CommitChange(AccessibleEventId::VISIBLE_DATA_CHANGED, Any(), Any());
488 // update our children that our screen position might have changed
489 if( mpText )
490 mpText->UpdateChildren();
494 // protected
497 void AccessibleCell::disposing()
499 SolarMutexGuard aSolarGuard;
500 ::osl::MutexGuard aGuard (maMutex);
502 // Make sure to send an event that this object loses the focus in the
503 // case that it has the focus.
504 ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
505 if (pStateSet != nullptr)
506 pStateSet->RemoveState(AccessibleStateType::FOCUSED);
508 if (mpText != nullptr)
510 mpText->Dispose();
511 mpText.reset();
514 // Cleanup. Remove references to objects to allow them to be
515 // destroyed.
516 mxCell.clear();
517 maShapeTreeInfo.dispose();
519 // Call base classes.
520 AccessibleContextBase::dispose ();
523 sal_Int32 SAL_CALL AccessibleCell::getAccessibleIndexInParent()
525 ThrowIfDisposed ();
526 return mnIndexInParent;
530 OUString AccessibleCell::getCellName( sal_Int32 nCol, sal_Int32 nRow )
532 OUStringBuffer aBuf;
534 if (nCol < 26*26)
536 if (nCol < 26)
537 aBuf.append( static_cast<sal_Unicode>( 'A' +
538 static_cast<sal_uInt16>(nCol)));
539 else
541 aBuf.append( static_cast<sal_Unicode>( 'A' +
542 (static_cast<sal_uInt16>(nCol) / 26) - 1));
543 aBuf.append( static_cast<sal_Unicode>( 'A' +
544 (static_cast<sal_uInt16>(nCol) % 26)));
547 else
549 OUStringBuffer aStr;
550 while (nCol >= 26)
552 sal_Int32 nC = nCol % 26;
553 aStr.append(static_cast<sal_Unicode>( 'A' +
554 static_cast<sal_uInt16>(nC)));
555 nCol = nCol - nC;
556 nCol = nCol / 26 - 1;
558 aStr.append(static_cast<sal_Unicode>( 'A' +
559 static_cast<sal_uInt16>(nCol)));
560 aBuf.append(comphelper::string::reverseString(aStr.makeStringAndClear()));
562 aBuf.append( OUString::number(nRow+1) );
563 return aBuf.makeStringAndClear();
566 OUString SAL_CALL AccessibleCell::getAccessibleName()
568 ThrowIfDisposed ();
569 SolarMutexGuard aSolarGuard;
571 if( pAccTable )
575 sal_Int32 nRow = 0, nCol = 0;
576 pAccTable->getColumnAndRow(mnIndexInParent, nCol, nRow);
577 return getCellName( nCol, nRow );
579 catch(const Exception&)
584 return AccessibleCellBase::getAccessibleName();
587 void AccessibleCell::UpdateChildren()
589 if (mpText)
590 mpText->UpdateChildren();
593 /* MT: Above getAccessibleName was introduced with IA2 CWS, while below was introduce in 3.3 meanwhile. Check which one is correct
594 +If this is correct, we also don't need sdr::table::CellRef getCellRef(), UpdateChildren(), getCellName( sal_Int32 nCol, sal_Int32 nRow ) above
597 OUString SAL_CALL AccessibleCell::getAccessibleName() throw (css::uno::RuntimeException)
599 ThrowIfDisposed ();
600 SolarMutexGuard aSolarGuard;
602 if( mxCell.is() )
603 return mxCell->getName();
605 return AccessibleCellBase::getAccessibleName();
609 } // end of namespace accessibility
611 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */