Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / svx / source / table / accessiblecell.cxx
blob1bb1ca78482a4cd952bde2ed7b067239541df1ec
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 <utility>
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()))
75 return;
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() )
84 mpText->SetFocus();
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
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_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 ());
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( ) 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;
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_Int64 nIndex)
167 SolarMutexGuard aSolarGuard;
168 ThrowIfDisposed ();
170 return mpText->GetChild (nIndex);
174 /** Return a copy of the state set.
175 Possible states are:
176 ENABLED
177 SHOWING
178 VISIBLE
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 ();
191 else
193 // Merge current FOCUSED state from edit engine.
194 if (mpText != nullptr)
196 if (mpText->HaveFocus())
197 mnStateSet |= AccessibleStateType::FOCUSED;
198 else
199 mnStateSet &= ~AccessibleStateType::FOCUSED;
201 // Set the invisible state for merged cell
202 if (mxCell.is() && mxCell->isMerged())
203 mnStateSet &= ~AccessibleStateType::VISIBLE;
204 else
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();
210 if( xTempAcc.is() )
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;
227 return nStateSet;
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
242 found.
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));
256 if (xChild.is())
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) )
266 return xChild;
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);
282 ThrowIfDisposed ();
283 css::awt::Rectangle aBoundingBox;
284 if( mxCell.is() )
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());
312 else
314 SAL_INFO("svx", "parent does not support component");
315 aBoundingBox = awt::Rectangle (aPixelPosition.getX(), aPixelPosition.getY(),aPixelSize.getWidth(), aPixelSize.getHeight());
319 return aBoundingBox;
323 css::awt::Point SAL_CALL AccessibleCell::getLocation()
325 ThrowIfDisposed ();
326 css::awt::Rectangle aBoundingBox(getBounds());
327 return css::awt::Point(aBoundingBox.X, aBoundingBox.Y);
331 css::awt::Point SAL_CALL AccessibleCell::getLocationOnScreen()
333 ThrowIfDisposed ();
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;
346 else
348 SAL_WARN("svx", "parent does not support XAccessibleComponent");
351 return aLocation;
355 awt::Size SAL_CALL AccessibleCell::getSize()
357 ThrowIfDisposed ();
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()
371 ThrowIfDisposed ();
373 // todo
374 return sal_Int32(0x0ffffffL);
378 sal_Int32 SAL_CALL AccessibleCell::getBackground()
380 ThrowIfDisposed ();
382 // todo
383 return 0;
387 // XAccessibleExtendedComponent
390 css::uno::Reference< css::awt::XFont > SAL_CALL AccessibleCell::getFont()
392 //todo
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);
422 else
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);
440 // XServiceInfo
443 OUString SAL_CALL AccessibleCell::getImplementationName()
445 return "AccessibleCell";
449 Sequence<OUString> SAL_CALL AccessibleCell::getSupportedServiceNames()
451 ThrowIfDisposed ();
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
467 if( mpText )
468 mpText->UpdateChildren();
472 // protected
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)
486 mpText->Dispose();
487 mpText.reset();
490 // Cleanup. Remove references to objects to allow them to be
491 // destroyed.
492 mxCell.clear();
493 maShapeTreeInfo.dispose();
495 // Call base classes.
496 AccessibleContextBase::dispose ();
499 sal_Int64 SAL_CALL AccessibleCell::getAccessibleIndexInParent()
501 ThrowIfDisposed ();
502 return mnIndexInParent;
506 OUString AccessibleCell::getCellName( sal_Int32 nCol, sal_Int32 nRow )
508 OUStringBuffer aBuf;
510 if (nCol < 26*26)
512 if (nCol < 26)
513 aBuf.append( static_cast<sal_Unicode>( 'A' +
514 static_cast<sal_uInt16>(nCol)));
515 else
517 aBuf.append(
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))) );
524 else
526 OUStringBuffer aStr;
527 while (nCol >= 26)
529 sal_Int32 nC = nCol % 26;
530 aStr.append(static_cast<sal_Unicode>( 'A' +
531 static_cast<sal_uInt16>(nC)));
532 nCol = nCol - 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));
539 aBuf.append(nRow+1);
540 return aBuf.makeStringAndClear();
543 OUString SAL_CALL AccessibleCell::getAccessibleName()
545 ThrowIfDisposed ();
546 SolarMutexGuard aSolarGuard;
548 if( pAccTable )
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()
566 if (mpText)
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)
576 ThrowIfDisposed ();
577 SolarMutexGuard aSolarGuard;
579 if( mxCell.is() )
580 return mxCell->getName();
582 return AccessibleCellBase::getAccessibleName();
586 } // end of namespace accessibility
588 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */