LibreOffice Module svx (master)  1
accessiblecell.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <sal/config.h>
21 #include <sal/log.hxx>
22 
23 #include <memory>
24 
25 #include "accessiblecell.hxx"
26 #include <cell.hxx>
27 
28 #include <com/sun/star/accessibility/AccessibleRole.hpp>
29 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
30 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
31 
32 #include <editeng/unoedsrc.hxx>
33 #include <vcl/svapp.hxx>
34 #include <vcl/window.hxx>
35 
37 #include <comphelper/string.hxx>
38 #include <comphelper/sequence.hxx>
40 #include <svx/unoshtxt.hxx>
41 #include <svx/svdotext.hxx>
42 #include <tools/debug.hxx>
43 
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;
50 
51 namespace accessibility {
52 
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 )
58 {
59  //Init the pAccTable var
60  pAccTable = dynamic_cast <AccessibleTableShape *> (rxParent.get());
61 }
62 
63 
65 {
66  DBG_ASSERT( mpText == nullptr, "svx::AccessibleCell::~AccessibleCell(), not disposed!?" );
67 }
68 
69 
71 {
73  const vcl::Window* pWindow = maShapeTreeInfo.GetWindow ();
74  if( !((pView != nullptr) && (pWindow != nullptr) && mxCell.is()))
75  return;
76 
77  // create AccessibleTextHelper to handle this shape's text
78  if( mxCell->CanCreateEditOutlinerParaObject() || mxCell->GetOutlinerParaObject() != nullptr )
79  {
80  // non-empty text -> use full-fledged edit source right away
81 
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);
86  }
87 }
88 
89 
90 bool AccessibleCell::SetState (sal_Int16 aState)
91 {
92  bool bStateHasChanged = false;
93 
94  if (aState == AccessibleStateType::FOCUSED && mpText != nullptr)
95  {
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 ());
101  }
102  else
103  bStateHasChanged = AccessibleContextBase::SetState (aState);
104 
105  return bStateHasChanged;
106 }
107 
108 
109 bool AccessibleCell::ResetState (sal_Int16 aState)
110 {
111  bool bStateHasChanged = false;
112 
113  if (aState == AccessibleStateType::FOCUSED && mpText != nullptr)
114  {
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 ());
120  }
121  else
122  bStateHasChanged = AccessibleContextBase::ResetState (aState);
123 
124  return bStateHasChanged;
125 }
126 
127 
128 // XInterface
129 
130 
131 Any SAL_CALL AccessibleCell::queryInterface( const Type& aType )
132 {
133  return AccessibleCellBase::queryInterface( aType );
134 }
135 
136 
137 void SAL_CALL AccessibleCell::acquire( ) noexcept
138 {
139  AccessibleCellBase::acquire();
140 }
141 
142 
143 void SAL_CALL AccessibleCell::release( ) noexcept
144 {
145  AccessibleCellBase::release();
146 }
147 
148 
149 // XAccessibleContext
150 
151 
155 {
156  SolarMutexGuard aSolarGuard;
157  ThrowIfDisposed ();
158  return mpText != nullptr ? mpText->GetChildCount () : 0;
159 }
160 
161 
165 Reference<XAccessible> SAL_CALL AccessibleCell::getAccessibleChild (sal_Int32 nIndex)
166 {
167  SolarMutexGuard aSolarGuard;
168  ThrowIfDisposed ();
169 
170  // todo: does GetChild throw IndexOutOfBoundsException?
171  return mpText->GetChild (nIndex);
172 }
173 
174 
181 Reference<XAccessibleStateSet> SAL_CALL AccessibleCell::getAccessibleStateSet()
182 {
183  SolarMutexGuard aSolarGuard;
184  ::osl::MutexGuard aGuard (m_aMutex);
185  Reference<XAccessibleStateSet> xStateSet;
186 
187  if (rBHelper.bDisposed || mpText == nullptr)
188  {
189  // Return a minimal state set that only contains the DEFUNC state.
191  }
192  else
193  {
194  if(mxStateSet)
195  {
196  // Merge current FOCUSED state from edit engine.
197  if (mpText != nullptr)
198  {
199  if (mpText->HaveFocus())
200  mxStateSet->AddState (AccessibleStateType::FOCUSED);
201  else
202  mxStateSet->RemoveState (AccessibleStateType::FOCUSED);
203  }
204  // Set the invisible state for merged cell
205  if (mxCell.is() && mxCell->isMerged())
206  mxStateSet->RemoveState(AccessibleStateType::VISIBLE);
207  else
208  mxStateSet->AddState(AccessibleStateType::VISIBLE);
209 
210 
211  //Just when the parent table is not read-only,set states EDITABLE,RESIZABLE,MOVEABLE
212  css::uno::Reference<XAccessible> xTempAcc = getAccessibleParent();
213  if( xTempAcc.is() )
214  {
215  css::uno::Reference<XAccessibleContext>
216  xTempAccContext = xTempAcc->getAccessibleContext();
217  if( xTempAccContext.is() )
218  {
219  css::uno::Reference<XAccessibleStateSet> rState =
220  xTempAccContext->getAccessibleStateSet();
221  if( rState.is() )
222  {
223  const css::uno::Sequence<short> aStates = rState->getStates();
224  if (std::find(aStates.begin(), aStates.end(), AccessibleStateType::EDITABLE) != aStates.end())
225  {
226  mxStateSet->AddState (AccessibleStateType::EDITABLE);
227  mxStateSet->AddState (AccessibleStateType::RESIZABLE);
228  mxStateSet->AddState (AccessibleStateType::MOVEABLE);
229  }
230  }
231  }
232  }
233  // Create a copy of the state set that may be modified by the
234  // caller without affecting the current state set.
235  xStateSet.set(new ::utl::AccessibleStateSetHelper (*mxStateSet));
236  }
237  }
238 
239  return xStateSet;
240 }
241 
242 
243 // XAccessibleComponent
244 
245 
246 sal_Bool SAL_CALL AccessibleCell::containsPoint( const css::awt::Point& aPoint)
247 {
249 }
250 
259 Reference<XAccessible > SAL_CALL AccessibleCell::getAccessibleAtPoint ( const css::awt::Point& aPoint)
260 {
261  SolarMutexGuard aSolarGuard;
262  ::osl::MutexGuard aGuard (m_aMutex);
263 
264  sal_Int32 nChildCount = getAccessibleChildCount ();
265  for (sal_Int32 i=0; i<nChildCount; ++i)
266  {
267  Reference<XAccessible> xChild (getAccessibleChild (i));
268  if (xChild.is())
269  {
270  Reference<XAccessibleComponent> xChildComponent (xChild->getAccessibleContext(), uno::UNO_QUERY);
271  if (xChildComponent.is())
272  {
273  awt::Rectangle aBBox (xChildComponent->getBounds());
274  if ( (aPoint.X >= aBBox.X)
275  && (aPoint.Y >= aBBox.Y)
276  && (aPoint.X < aBBox.X+aBBox.Width)
277  && (aPoint.Y < aBBox.Y+aBBox.Height) )
278  return xChild;
279  }
280  }
281  }
282 
283  // Have not found a child under the given point. Returning empty
284  // reference to indicate this.
285  return uno::Reference<XAccessible>();
286 }
287 
288 
289 css::awt::Rectangle SAL_CALL AccessibleCell::getBounds()
290 {
291  SolarMutexGuard aSolarGuard;
292  ::osl::MutexGuard aGuard (m_aMutex);
293 
294  ThrowIfDisposed ();
295  css::awt::Rectangle aBoundingBox;
296  if( mxCell.is() )
297  {
298  // Get the cell's bounding box in internal coordinates (in 100th of mm)
299  const ::tools::Rectangle aCellRect( mxCell->getCellRect() );
300 
301  // Transform coordinates from internal to pixel.
302  if (maShapeTreeInfo.GetViewForwarder() == nullptr)
303  throw uno::RuntimeException ("AccessibleCell has no valid view forwarder",static_cast<uno::XWeak*>(this));
304 
305  ::Size aPixelSize( maShapeTreeInfo.GetViewForwarder()->LogicToPixel(::Size(aCellRect.GetWidth(), aCellRect.GetHeight())) );
306  ::Point aPixelPosition( maShapeTreeInfo.GetViewForwarder()->LogicToPixel( aCellRect.TopLeft() ));
307 
308  // Clip the shape's bounding box with the bounding box of its parent.
309  Reference<XAccessibleComponent> xParentComponent ( getAccessibleParent(), uno::UNO_QUERY);
310  if (xParentComponent.is())
311  {
312  // Make the coordinates relative to the parent.
313  awt::Point aParentLocation (xParentComponent->getLocationOnScreen());
314  int x = aPixelPosition.getX() - aParentLocation.X;
315  int y = aPixelPosition.getY() - aParentLocation.Y;
316 
317  // Clip with parent (with coordinates relative to itself).
318  ::tools::Rectangle aBBox ( x, y, x + aPixelSize.getWidth(), y + aPixelSize.getHeight());
319  awt::Size aParentSize (xParentComponent->getSize());
320  ::tools::Rectangle aParentBBox (0,0, aParentSize.Width, aParentSize.Height);
321  aBBox = aBBox.GetIntersection (aParentBBox);
322  aBoundingBox = awt::Rectangle ( aBBox.Left(), aBBox.Top(), aBBox.getWidth(), aBBox.getHeight());
323  }
324  else
325  {
326  SAL_INFO("svx", "parent does not support component");
327  aBoundingBox = awt::Rectangle (aPixelPosition.getX(), aPixelPosition.getY(),aPixelSize.getWidth(), aPixelSize.getHeight());
328  }
329  }
330 
331  return aBoundingBox;
332 }
333 
334 
335 css::awt::Point SAL_CALL AccessibleCell::getLocation()
336 {
337  ThrowIfDisposed ();
338  css::awt::Rectangle aBoundingBox(getBounds());
339  return css::awt::Point(aBoundingBox.X, aBoundingBox.Y);
340 }
341 
342 
343 css::awt::Point SAL_CALL AccessibleCell::getLocationOnScreen()
344 {
345  ThrowIfDisposed ();
346 
347  // Get relative position...
348  css::awt::Point aLocation(getLocation ());
349 
350  // ... and add absolute position of the parent.
351  Reference<XAccessibleComponent> xParentComponent( getAccessibleParent(), uno::UNO_QUERY);
352  if(xParentComponent.is())
353  {
354  css::awt::Point aParentLocation(xParentComponent->getLocationOnScreen());
355  aLocation.X += aParentLocation.X;
356  aLocation.Y += aParentLocation.Y;
357  }
358  else
359  {
360  SAL_WARN("svx", "parent does not support XAccessibleComponent");
361  }
362 
363  return aLocation;
364 }
365 
366 
367 awt::Size SAL_CALL AccessibleCell::getSize()
368 {
369  ThrowIfDisposed ();
370  awt::Rectangle aBoundingBox (getBounds());
371  return awt::Size (aBoundingBox.Width, aBoundingBox.Height);
372 }
373 
374 
376 {
378 }
379 
380 
381 sal_Int32 SAL_CALL AccessibleCell::getForeground()
382 {
383  ThrowIfDisposed ();
384 
385  // todo
386  return sal_Int32(0x0ffffffL);
387 }
388 
389 
390 sal_Int32 SAL_CALL AccessibleCell::getBackground()
391 {
392  ThrowIfDisposed ();
393 
394  // todo
395  return 0;
396 }
397 
398 
399 // XAccessibleExtendedComponent
400 
401 
402 css::uno::Reference< css::awt::XFont > SAL_CALL AccessibleCell::getFont()
403 {
404 //todo
406 }
407 
408 
410 {
412 }
413 
414 
416 {
418 }
419 
420 
421 // XAccessibleEventBroadcaster
422 
423 
424 void SAL_CALL AccessibleCell::addAccessibleEventListener( const Reference<XAccessibleEventListener >& rxListener)
425 {
426  SolarMutexGuard aSolarGuard;
427  ::osl::MutexGuard aGuard (m_aMutex);
428  if (rBHelper.bDisposed || rBHelper.bInDispose)
429  {
430  Reference<XInterface> xSource( static_cast<XComponent *>(this) );
431  lang::EventObject aEventObj(xSource);
432  rxListener->disposing(aEventObj);
433  }
434  else
435  {
437  if (mpText != nullptr)
438  mpText->AddEventListener (rxListener);
439  }
440 }
441 
442 
443 void SAL_CALL AccessibleCell::removeAccessibleEventListener( const Reference<XAccessibleEventListener >& rxListener)
444 {
445  SolarMutexGuard aSolarGuard;
447  if (mpText != nullptr)
448  mpText->RemoveEventListener (rxListener);
449 }
450 
451 
452 // XServiceInfo
453 
454 
456 {
457  return "AccessibleCell";
458 }
459 
460 
462 {
463  ThrowIfDisposed ();
464  const css::uno::Sequence<OUString> vals { "com.sun.star.drawing.AccessibleCell" };
466 }
467 
468 
469 // IAccessibleViewForwarderListener
470 
471 
473 {
474  // Inform all listeners that the graphical representation (i.e. size
475  // and/or position) of the shape has changed.
476  CommitChange(AccessibleEventId::VISIBLE_DATA_CHANGED, Any(), Any());
477 
478  // update our children that our screen position might have changed
479  if( mpText )
480  mpText->UpdateChildren();
481 }
482 
483 
484 // protected
485 
486 
488 {
489  SolarMutexGuard aSolarGuard;
490  ::osl::MutexGuard aGuard (m_aMutex);
491 
492  // Make sure to send an event that this object loses the focus in the
493  // case that it has the focus.
494  if (mxStateSet != nullptr)
495  mxStateSet->RemoveState(AccessibleStateType::FOCUSED);
496 
497  if (mpText != nullptr)
498  {
499  mpText->Dispose();
500  mpText.reset();
501  }
502 
503  // Cleanup. Remove references to objects to allow them to be
504  // destroyed.
505  mxCell.clear();
507 
508  // Call base classes.
509  AccessibleContextBase::dispose ();
510 }
511 
513 {
514  ThrowIfDisposed ();
515  return mnIndexInParent;
516 }
517 
518 
519 OUString AccessibleCell::getCellName( sal_Int32 nCol, sal_Int32 nRow )
520 {
521  OUStringBuffer aBuf;
522 
523  if (nCol < 26*26)
524  {
525  if (nCol < 26)
526  aBuf.append( static_cast<sal_Unicode>( 'A' +
527  static_cast<sal_uInt16>(nCol)));
528  else
529  {
530  aBuf.append( static_cast<sal_Unicode>( 'A' +
531  (static_cast<sal_uInt16>(nCol) / 26) - 1));
532  aBuf.append( static_cast<sal_Unicode>( 'A' +
533  (static_cast<sal_uInt16>(nCol) % 26)));
534  }
535  }
536  else
537  {
538  OUStringBuffer aStr;
539  while (nCol >= 26)
540  {
541  sal_Int32 nC = nCol % 26;
542  aStr.append(static_cast<sal_Unicode>( 'A' +
543  static_cast<sal_uInt16>(nC)));
544  nCol = nCol - nC;
545  nCol = nCol / 26 - 1;
546  }
547  aStr.append(static_cast<sal_Unicode>( 'A' +
548  static_cast<sal_uInt16>(nCol)));
549  aBuf.append(comphelper::string::reverseString(aStr.makeStringAndClear()));
550  }
551  aBuf.append(nRow+1);
552  return aBuf.makeStringAndClear();
553 }
554 
556 {
557  ThrowIfDisposed ();
558  SolarMutexGuard aSolarGuard;
559 
560  if( pAccTable )
561  {
562  try
563  {
564  sal_Int32 nRow = 0, nCol = 0;
566  return getCellName( nCol, nRow );
567  }
568  catch(const Exception&)
569  {
570  }
571  }
572 
573  return AccessibleCellBase::getAccessibleName();
574 }
575 
577 {
578  if (mpText)
579  mpText->UpdateChildren();
580 }
581 
582 /* MT: Above getAccessibleName was introduced with IA2 CWS, while below was introduce in 3.3 meanwhile. Check which one is correct
583 +If this is correct, we also don't need sdr::table::CellRef getCellRef(), UpdateChildren(), getCellName( sal_Int32 nCol, sal_Int32 nRow ) above
584 +
585 
586 OUString SAL_CALL AccessibleCell::getAccessibleName() throw (css::uno::RuntimeException)
587 {
588  ThrowIfDisposed ();
589  SolarMutexGuard aSolarGuard;
590 
591  if( mxCell.is() )
592  return mxCell->getName();
593 
594  return AccessibleCellBase::getAccessibleName();
595 }
596 */
597 
598 } // end of namespace accessibility
599 
600 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual void SAL_CALL removeAccessibleEventListener(const css::uno::Reference< css::accessibility::XAccessibleEventListener > &xListener) override
virtual void SAL_CALL acquire() noexcept override
Type
virtual css::awt::Point SAL_CALL getLocationOnScreen() override
std::unique_ptr< AccessibleTextHelper > mpText
The accessible text engine. May be NULL if it can not be created.
virtual void ViewForwarderChanged() override
This method is called to indicate a change of the specified view forwarder, specifically, a change in visible area.
AccessibleTableShape * pAccTable
virtual sal_Bool SAL_CALL containsPoint(const css::awt::Point &aPoint) override
virtual void SAL_CALL addAccessibleEventListener(const css::uno::Reference< css::accessibility::XAccessibleEventListener > &xListener) override
Helper class for objects containing EditEngine/Outliner text.
vcl::Window * GetWindow() const
Return the current Window.
virtual css::uno::Reference< css::awt::XFont > SAL_CALL getFont() override
SdrView * GetSdrView() const
Return the current SdrView.
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
aBuf
virtual sal_Bool SAL_CALL containsPoint(const css::awt::Point &aPoint) override
virtual css::uno::Reference< css::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet() override
virtual OUString SAL_CALL getTitledBorderText() override
virtual sal_Int32 SAL_CALL getBackground() override
float x
virtual void SAL_CALL addAccessibleEventListener(const css::uno::Reference< css::accessibility::XAccessibleEventListener > &rxListener) override
virtual bool ResetState(sal_Int16 aState) override
virtual OUString SAL_CALL getAccessibleName() override
virtual bool SetState(sal_Int16 aState) override
virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type &aType) override
std::mutex m_aMutex
virtual void SAL_CALL disposing() override
This method is called from the component helper base class while disposing.
float y
virtual void SAL_CALL removeAccessibleEventListener(const css::uno::Reference< css::accessibility::XAccessibleEventListener > &rxListener) override
#define DBG_ASSERT(sCon, aError)
int i
virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint(const css::awt::Point &aPoint) override
The implementation below is at the moment straightforward.
unsigned char sal_Bool
virtual css::awt::Rectangle SAL_CALL getBounds() override
virtual OUString SAL_CALL getToolTipText() override
virtual sal_Int32 SAL_CALL getAccessibleChildCount() override
The children of this cell come from the paragraphs of text.
AccessibleShapeTreeInfo maShapeTreeInfo
Bundle of information passed to all shapes in a document tree.
css::uno::Sequence< T > concatSequences(const css::uno::Sequence< T > &rS1, const Ss &...rSn)
virtual Point LogicToPixel(const Point &rPoint) const =0
Transform the specified point from internal coordinates in 100th of mm to an absolute screen position...
virtual void SAL_CALL grabFocus() override
void getColumnAndRow(sal_Int32 nChildIndex, sal_Int32 &rnColumn, sal_Int32 &rnRow)
sal_Int32 mnIndexInParent
the index in parent.
virtual css::uno::Reference< css::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet() override
Return a copy of the state set.
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
virtual sal_Int32 SAL_CALL getAccessibleIndexInParent() override
virtual void SAL_CALL release() noexcept override
#define SAL_INFO(area, stream)
::OutputDevice const * GetOutDev() const
virtual ~AccessibleCell() override
const IAccessibleViewForwarder * GetViewForwarder() const
Return the current view forwarder.
virtual void SAL_CALL grabFocus() override
virtual sal_Int32 SAL_CALL getForeground() override
virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild(sal_Int32 nIndex) override
Forward the request to the shape.
virtual css::uno::Reference< css::awt::XFont > SAL_CALL getFont() override
virtual css::awt::Size SAL_CALL getSize() override
virtual bool SetState(sal_Int16 aState)
#define SAL_WARN(area, stream)
::cppu::ImplInheritanceHelper< AccessibleContextBase, css::accessibility::XAccessibleExtendedComponent > AccessibleCellBase
virtual bool ResetState(sal_Int16 aState)
static OUString getCellName(sal_Int32 nCol, sal_Int32 nRow)
OUString reverseString(std::u16string_view rStr)
virtual OUString SAL_CALL getToolTipText() override
virtual OUString SAL_CALL getTitledBorderText() override
aStr
This class bundles all information that is passed down the tree of accessible shapes so that each sha...
virtual css::awt::Point SAL_CALL getLocation() override
virtual OUString SAL_CALL getImplementationName() override