Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / svx / source / table / accessiblecell.cxx
blob39f520fed02813c05eed67ca43c5afcc27537b79
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>
25 #include "accessiblecell.hxx"
26 #include <cell.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>
33 #include <vcl/svapp.hxx>
35 #include <unotools/accessiblestatesethelper.hxx>
36 #include <comphelper/string.hxx>
37 #include <comphelper/sequence.hxx>
38 #include <svx/IAccessibleViewForwarder.hxx>
39 #include <svx/unoshtxt.hxx>
40 #include <svx/svdotext.hxx>
41 #include <tools/debug.hxx>
43 using namespace sdr::table;
44 using namespace ::com::sun::star;
45 using namespace ::com::sun::star::uno;
46 using namespace ::com::sun::star::accessibility;
47 using namespace ::com::sun::star::lang;
48 using namespace ::com::sun::star::container;
50 namespace accessibility {
52 AccessibleCell::AccessibleCell( const css::uno::Reference< css::accessibility::XAccessible>& rxParent, const sdr::table::CellRef& rCell, sal_Int32 nIndex, const AccessibleShapeTreeInfo& rShapeTreeInfo )
53 : AccessibleCellBase( rxParent, AccessibleRole::TABLE_CELL )
54 , maShapeTreeInfo( rShapeTreeInfo )
55 , mnIndexInParent( nIndex )
56 , mxCell( rCell )
58 //Init the pAccTable var
59 pAccTable = dynamic_cast <AccessibleTableShape *> (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()))
74 return;
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);
89 bool AccessibleCell::SetState (sal_Int16 aState)
91 bool bStateHasChanged = false;
93 if (aState == AccessibleStateType::FOCUSED && mpText != nullptr)
95 // Offer FOCUSED state to edit engine and detect whether the state
96 // changes.
97 bool bIsFocused = mpText->HaveFocus ();
98 mpText->SetFocus();
99 bStateHasChanged = (bIsFocused != mpText->HaveFocus ());
101 else
102 bStateHasChanged = AccessibleContextBase::SetState (aState);
104 return bStateHasChanged;
108 bool AccessibleCell::ResetState (sal_Int16 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 ());
120 else
121 bStateHasChanged = AccessibleContextBase::ResetState (aState);
123 return bStateHasChanged;
127 // XInterface
130 Any SAL_CALL AccessibleCell::queryInterface( const Type& aType )
132 return AccessibleCellBase::queryInterface( aType );
136 void SAL_CALL AccessibleCell::acquire( ) throw ()
138 AccessibleCellBase::acquire();
142 void SAL_CALL AccessibleCell::release( ) throw ()
144 AccessibleCellBase::release();
148 // XAccessibleContext
151 /** The children of this cell come from the paragraphs of text.
153 sal_Int32 SAL_CALL AccessibleCell::getAccessibleChildCount()
155 SolarMutexGuard aSolarGuard;
156 ThrowIfDisposed ();
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_Int32 nIndex)
166 SolarMutexGuard aSolarGuard;
167 ThrowIfDisposed ();
169 // todo: does GetChild throw IndexOutOfBoundsException?
170 return mpText->GetChild (nIndex);
174 /** Return a copy of the state set.
175 Possible states are:
176 ENABLED
177 SHOWING
178 VISIBLE
180 Reference<XAccessibleStateSet> SAL_CALL AccessibleCell::getAccessibleStateSet()
182 SolarMutexGuard aSolarGuard;
183 ::osl::MutexGuard aGuard (maMutex);
184 Reference<XAccessibleStateSet> xStateSet;
186 if (rBHelper.bDisposed || mpText == nullptr)
188 // Return a minimal state set that only contains the DEFUNC state.
189 xStateSet = AccessibleContextBase::getAccessibleStateSet ();
191 else
193 ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
195 if(pStateSet)
197 // Merge current FOCUSED state from edit engine.
198 if (mpText != nullptr)
200 if (mpText->HaveFocus())
201 pStateSet->AddState (AccessibleStateType::FOCUSED);
202 else
203 pStateSet->RemoveState (AccessibleStateType::FOCUSED);
205 // Set the invisible state for merged cell
206 if (mxCell.is() && mxCell->isMerged())
207 pStateSet->RemoveState(AccessibleStateType::VISIBLE);
208 else
209 pStateSet->AddState(AccessibleStateType::VISIBLE);
212 //Just when the parent table is not read-only,set states EDITABLE,RESIZABLE,MOVEABLE
213 css::uno::Reference<XAccessible> xTempAcc = getAccessibleParent();
214 if( xTempAcc.is() )
216 css::uno::Reference<XAccessibleContext>
217 xTempAccContext = xTempAcc->getAccessibleContext();
218 if( xTempAccContext.is() )
220 css::uno::Reference<XAccessibleStateSet> rState =
221 xTempAccContext->getAccessibleStateSet();
222 if( rState.is() )
224 css::uno::Sequence<short> aStates = rState->getStates();
225 if (std::find(aStates.begin(), aStates.end(), AccessibleStateType::EDITABLE) != aStates.end())
227 pStateSet->AddState (AccessibleStateType::EDITABLE);
228 pStateSet->AddState (AccessibleStateType::RESIZABLE);
229 pStateSet->AddState (AccessibleStateType::MOVEABLE);
234 // Create a copy of the state set that may be modified by the
235 // caller without affecting the current state set.
236 xStateSet.set(new ::utl::AccessibleStateSetHelper (*pStateSet));
240 return xStateSet;
244 // XAccessibleComponent
247 sal_Bool SAL_CALL AccessibleCell::containsPoint( const css::awt::Point& aPoint)
249 return AccessibleComponentBase::containsPoint( aPoint );
252 /** The implementation below is at the moment straightforward. It iterates
253 over all children (and thereby instances all children which have not
254 been already instantiated) until a child covering the specified point is
255 found.
256 This leaves room for improvement. For instance, first iterate only over
257 the already instantiated children and only if no match is found
258 instantiate the remaining ones.
260 Reference<XAccessible > SAL_CALL AccessibleCell::getAccessibleAtPoint ( const css::awt::Point& aPoint)
262 SolarMutexGuard aSolarGuard;
263 ::osl::MutexGuard aGuard (maMutex);
265 sal_Int32 nChildCount = getAccessibleChildCount ();
266 for (sal_Int32 i=0; i<nChildCount; ++i)
268 Reference<XAccessible> xChild (getAccessibleChild (i));
269 if (xChild.is())
271 Reference<XAccessibleComponent> xChildComponent (xChild->getAccessibleContext(), uno::UNO_QUERY);
272 if (xChildComponent.is())
274 awt::Rectangle aBBox (xChildComponent->getBounds());
275 if ( (aPoint.X >= aBBox.X)
276 && (aPoint.Y >= aBBox.Y)
277 && (aPoint.X < aBBox.X+aBBox.Width)
278 && (aPoint.Y < aBBox.Y+aBBox.Height) )
279 return xChild;
284 // Have not found a child under the given point. Returning empty
285 // reference to indicate this.
286 return uno::Reference<XAccessible>();
290 css::awt::Rectangle SAL_CALL AccessibleCell::getBounds()
292 SolarMutexGuard aSolarGuard;
293 ::osl::MutexGuard aGuard (maMutex);
295 ThrowIfDisposed ();
296 css::awt::Rectangle aBoundingBox;
297 if( mxCell.is() )
299 // Get the cell's bounding box in internal coordinates (in 100th of mm)
300 const ::tools::Rectangle aCellRect( mxCell->getCellRect() );
302 // Transform coordinates from internal to pixel.
303 if (maShapeTreeInfo.GetViewForwarder() == nullptr)
304 throw uno::RuntimeException ("AccessibleCell has no valid view forwarder",static_cast<uno::XWeak*>(this));
306 ::Size aPixelSize( maShapeTreeInfo.GetViewForwarder()->LogicToPixel(::Size(aCellRect.GetWidth(), aCellRect.GetHeight())) );
307 ::Point aPixelPosition( maShapeTreeInfo.GetViewForwarder()->LogicToPixel( aCellRect.TopLeft() ));
309 // Clip the shape's bounding box with the bounding box of its parent.
310 Reference<XAccessibleComponent> xParentComponent ( getAccessibleParent(), uno::UNO_QUERY);
311 if (xParentComponent.is())
313 // Make the coordinates relative to the parent.
314 awt::Point aParentLocation (xParentComponent->getLocationOnScreen());
315 int x = aPixelPosition.getX() - aParentLocation.X;
316 int y = aPixelPosition.getY() - aParentLocation.Y;
318 // Clip with parent (with coordinates relative to itself).
319 ::tools::Rectangle aBBox ( x, y, x + aPixelSize.getWidth(), y + aPixelSize.getHeight());
320 awt::Size aParentSize (xParentComponent->getSize());
321 ::tools::Rectangle aParentBBox (0,0, aParentSize.Width, aParentSize.Height);
322 aBBox = aBBox.GetIntersection (aParentBBox);
323 aBoundingBox = awt::Rectangle ( aBBox.getX(), aBBox.getY(), aBBox.getWidth(), aBBox.getHeight());
325 else
327 SAL_INFO("svx", "parent does not support component");
328 aBoundingBox = awt::Rectangle (aPixelPosition.getX(), aPixelPosition.getY(),aPixelSize.getWidth(), aPixelSize.getHeight());
332 return aBoundingBox;
336 css::awt::Point SAL_CALL AccessibleCell::getLocation()
338 ThrowIfDisposed ();
339 css::awt::Rectangle aBoundingBox(getBounds());
340 return css::awt::Point(aBoundingBox.X, aBoundingBox.Y);
344 css::awt::Point SAL_CALL AccessibleCell::getLocationOnScreen()
346 ThrowIfDisposed ();
348 // Get relative position...
349 css::awt::Point aLocation(getLocation ());
351 // ... and add absolute position of the parent.
352 Reference<XAccessibleComponent> xParentComponent( getAccessibleParent(), uno::UNO_QUERY);
353 if(xParentComponent.is())
355 css::awt::Point aParentLocation(xParentComponent->getLocationOnScreen());
356 aLocation.X += aParentLocation.X;
357 aLocation.Y += aParentLocation.Y;
359 else
361 SAL_WARN("svx", "parent does not support XAccessibleComponent");
364 return aLocation;
368 awt::Size SAL_CALL AccessibleCell::getSize()
370 ThrowIfDisposed ();
371 awt::Rectangle aBoundingBox (getBounds());
372 return awt::Size (aBoundingBox.Width, aBoundingBox.Height);
376 void SAL_CALL AccessibleCell::grabFocus()
378 AccessibleComponentBase::grabFocus();
382 sal_Int32 SAL_CALL AccessibleCell::getForeground()
384 ThrowIfDisposed ();
386 // todo
387 return sal_Int32(0x0ffffffL);
391 sal_Int32 SAL_CALL AccessibleCell::getBackground()
393 ThrowIfDisposed ();
395 // todo
396 return 0;
400 // XAccessibleExtendedComponent
403 css::uno::Reference< css::awt::XFont > SAL_CALL AccessibleCell::getFont()
405 //todo
406 return AccessibleComponentBase::getFont();
410 OUString SAL_CALL AccessibleCell::getTitledBorderText()
412 return AccessibleComponentBase::getTitledBorderText();
416 OUString SAL_CALL AccessibleCell::getToolTipText()
418 return AccessibleComponentBase::getToolTipText();
422 // XAccessibleEventBroadcaster
425 void SAL_CALL AccessibleCell::addAccessibleEventListener( const Reference<XAccessibleEventListener >& rxListener)
427 SolarMutexGuard aSolarGuard;
428 ::osl::MutexGuard aGuard (maMutex);
429 if (rBHelper.bDisposed || rBHelper.bInDispose)
431 Reference<XInterface> xSource( static_cast<XComponent *>(this) );
432 lang::EventObject aEventObj(xSource);
433 rxListener->disposing(aEventObj);
435 else
437 AccessibleContextBase::addAccessibleEventListener (rxListener);
438 if (mpText != nullptr)
439 mpText->AddEventListener (rxListener);
444 void SAL_CALL AccessibleCell::removeAccessibleEventListener( const Reference<XAccessibleEventListener >& rxListener)
446 SolarMutexGuard aSolarGuard;
447 AccessibleContextBase::removeAccessibleEventListener(rxListener);
448 if (mpText != nullptr)
449 mpText->RemoveEventListener (rxListener);
453 // XServiceInfo
456 OUString SAL_CALL AccessibleCell::getImplementationName()
458 return "AccessibleCell";
462 Sequence<OUString> SAL_CALL AccessibleCell::getSupportedServiceNames()
464 ThrowIfDisposed ();
465 const css::uno::Sequence<OUString> vals { "com.sun.star.drawing.AccessibleCell" };
466 return comphelper::concatSequences(AccessibleContextBase::getSupportedServiceNames(), vals);
470 // IAccessibleViewForwarderListener
473 void AccessibleCell::ViewForwarderChanged()
475 // Inform all listeners that the graphical representation (i.e. size
476 // and/or position) of the shape has changed.
477 CommitChange(AccessibleEventId::VISIBLE_DATA_CHANGED, Any(), Any());
479 // update our children that our screen position might have changed
480 if( mpText )
481 mpText->UpdateChildren();
485 // protected
488 void AccessibleCell::disposing()
490 SolarMutexGuard aSolarGuard;
491 ::osl::MutexGuard aGuard (maMutex);
493 // Make sure to send an event that this object loses the focus in the
494 // case that it has the focus.
495 ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
496 if (pStateSet != nullptr)
497 pStateSet->RemoveState(AccessibleStateType::FOCUSED);
499 if (mpText != nullptr)
501 mpText->Dispose();
502 mpText.reset();
505 // Cleanup. Remove references to objects to allow them to be
506 // destroyed.
507 mxCell.clear();
508 maShapeTreeInfo.dispose();
510 // Call base classes.
511 AccessibleContextBase::dispose ();
514 sal_Int32 SAL_CALL AccessibleCell::getAccessibleIndexInParent()
516 ThrowIfDisposed ();
517 return mnIndexInParent;
521 OUString AccessibleCell::getCellName( sal_Int32 nCol, sal_Int32 nRow )
523 OUStringBuffer aBuf;
525 if (nCol < 26*26)
527 if (nCol < 26)
528 aBuf.append( static_cast<sal_Unicode>( 'A' +
529 static_cast<sal_uInt16>(nCol)));
530 else
532 aBuf.append( static_cast<sal_Unicode>( 'A' +
533 (static_cast<sal_uInt16>(nCol) / 26) - 1));
534 aBuf.append( static_cast<sal_Unicode>( 'A' +
535 (static_cast<sal_uInt16>(nCol) % 26)));
538 else
540 OUStringBuffer aStr;
541 while (nCol >= 26)
543 sal_Int32 nC = nCol % 26;
544 aStr.append(static_cast<sal_Unicode>( 'A' +
545 static_cast<sal_uInt16>(nC)));
546 nCol = nCol - nC;
547 nCol = nCol / 26 - 1;
549 aStr.append(static_cast<sal_Unicode>( 'A' +
550 static_cast<sal_uInt16>(nCol)));
551 aBuf.append(comphelper::string::reverseString(aStr.makeStringAndClear()));
553 aBuf.append( OUString::number(nRow+1) );
554 return aBuf.makeStringAndClear();
557 OUString SAL_CALL AccessibleCell::getAccessibleName()
559 ThrowIfDisposed ();
560 SolarMutexGuard aSolarGuard;
562 if( pAccTable )
566 sal_Int32 nRow = 0, nCol = 0;
567 pAccTable->getColumnAndRow(mnIndexInParent, nCol, nRow);
568 return getCellName( nCol, nRow );
570 catch(const Exception&)
575 return AccessibleCellBase::getAccessibleName();
578 void AccessibleCell::UpdateChildren()
580 if (mpText)
581 mpText->UpdateChildren();
584 /* MT: Above getAccessibleName was introduced with IA2 CWS, while below was introduce in 3.3 meanwhile. Check which one is correct
585 +If this is correct, we also don't need sdr::table::CellRef getCellRef(), UpdateChildren(), getCellName( sal_Int32 nCol, sal_Int32 nRow ) above
588 OUString SAL_CALL AccessibleCell::getAccessibleName() throw (css::uno::RuntimeException)
590 ThrowIfDisposed ();
591 SolarMutexGuard aSolarGuard;
593 if( mxCell.is() )
594 return mxCell->getName();
596 return AccessibleCellBase::getAccessibleName();
600 } // end of namespace accessibility
602 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */