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 
36 #include <comphelper/string.hxx>
37 #include <comphelper/sequence.hxx>
39 #include <svx/unoshtxt.hxx>
40 #include <svx/svdotext.hxx>
41 #include <tools/debug.hxx>
42 
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;
49 
50 namespace accessibility {
51 
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 )
57 {
58  //Init the pAccTable var
59  pAccTable = dynamic_cast <AccessibleTableShape *> (rxParent.get());
60 }
61 
62 
64 {
65  DBG_ASSERT( mpText == nullptr, "svx::AccessibleCell::~AccessibleCell(), not disposed!?" );
66 }
67 
68 
70 {
72  const vcl::Window* pWindow = maShapeTreeInfo.GetWindow ();
73  if( !((pView != nullptr) && (pWindow != nullptr) && mxCell.is()))
74  return;
75 
76  // create AccessibleTextHelper to handle this shape's text
77  if( mxCell->CanCreateEditOutlinerParaObject() || mxCell->GetOutlinerParaObject() != nullptr )
78  {
79  // non-empty text -> use full-fledged edit source right away
80 
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);
85  }
86 }
87 
88 
89 bool AccessibleCell::SetState (sal_Int16 aState)
90 {
91  bool bStateHasChanged = false;
92 
93  if (aState == AccessibleStateType::FOCUSED && mpText != nullptr)
94  {
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 ());
100  }
101  else
102  bStateHasChanged = AccessibleContextBase::SetState (aState);
103 
104  return bStateHasChanged;
105 }
106 
107 
108 bool AccessibleCell::ResetState (sal_Int16 aState)
109 {
110  bool bStateHasChanged = false;
111 
112  if (aState == AccessibleStateType::FOCUSED && mpText != nullptr)
113  {
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 ());
119  }
120  else
121  bStateHasChanged = AccessibleContextBase::ResetState (aState);
122 
123  return bStateHasChanged;
124 }
125 
126 
127 // XInterface
128 
129 
130 Any SAL_CALL AccessibleCell::queryInterface( const Type& aType )
131 {
132  return AccessibleCellBase::queryInterface( aType );
133 }
134 
135 
136 void SAL_CALL AccessibleCell::acquire( ) throw ()
137 {
138  AccessibleCellBase::acquire();
139 }
140 
141 
142 void SAL_CALL AccessibleCell::release( ) throw ()
143 {
144  AccessibleCellBase::release();
145 }
146 
147 
148 // XAccessibleContext
149 
150 
154 {
155  SolarMutexGuard aSolarGuard;
156  ThrowIfDisposed ();
157  return mpText != nullptr ? mpText->GetChildCount () : 0;
158 }
159 
160 
164 Reference<XAccessible> SAL_CALL AccessibleCell::getAccessibleChild (sal_Int32 nIndex)
165 {
166  SolarMutexGuard aSolarGuard;
167  ThrowIfDisposed ();
168 
169  // todo: does GetChild throw IndexOutOfBoundsException?
170  return mpText->GetChild (nIndex);
171 }
172 
173 
180 Reference<XAccessibleStateSet> SAL_CALL AccessibleCell::getAccessibleStateSet()
181 {
182  SolarMutexGuard aSolarGuard;
183  ::osl::MutexGuard aGuard (maMutex);
184  Reference<XAccessibleStateSet> xStateSet;
185 
186  if (rBHelper.bDisposed || mpText == nullptr)
187  {
188  // Return a minimal state set that only contains the DEFUNC state.
190  }
191  else
192  {
193  ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
194 
195  if(pStateSet)
196  {
197  // Merge current FOCUSED state from edit engine.
198  if (mpText != nullptr)
199  {
200  if (mpText->HaveFocus())
201  pStateSet->AddState (AccessibleStateType::FOCUSED);
202  else
203  pStateSet->RemoveState (AccessibleStateType::FOCUSED);
204  }
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);
210 
211 
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() )
215  {
216  css::uno::Reference<XAccessibleContext>
217  xTempAccContext = xTempAcc->getAccessibleContext();
218  if( xTempAccContext.is() )
219  {
220  css::uno::Reference<XAccessibleStateSet> rState =
221  xTempAccContext->getAccessibleStateSet();
222  if( rState.is() )
223  {
224  css::uno::Sequence<short> aStates = rState->getStates();
225  if (std::find(aStates.begin(), aStates.end(), AccessibleStateType::EDITABLE) != aStates.end())
226  {
227  pStateSet->AddState (AccessibleStateType::EDITABLE);
228  pStateSet->AddState (AccessibleStateType::RESIZABLE);
229  pStateSet->AddState (AccessibleStateType::MOVEABLE);
230  }
231  }
232  }
233  }
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));
237  }
238  }
239 
240  return xStateSet;
241 }
242 
243 
244 // XAccessibleComponent
245 
246 
247 sal_Bool SAL_CALL AccessibleCell::containsPoint( const css::awt::Point& aPoint)
248 {
250 }
251 
260 Reference<XAccessible > SAL_CALL AccessibleCell::getAccessibleAtPoint ( const css::awt::Point& aPoint)
261 {
262  SolarMutexGuard aSolarGuard;
263  ::osl::MutexGuard aGuard (maMutex);
264 
265  sal_Int32 nChildCount = getAccessibleChildCount ();
266  for (sal_Int32 i=0; i<nChildCount; ++i)
267  {
268  Reference<XAccessible> xChild (getAccessibleChild (i));
269  if (xChild.is())
270  {
271  Reference<XAccessibleComponent> xChildComponent (xChild->getAccessibleContext(), uno::UNO_QUERY);
272  if (xChildComponent.is())
273  {
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;
280  }
281  }
282  }
283 
284  // Have not found a child under the given point. Returning empty
285  // reference to indicate this.
286  return uno::Reference<XAccessible>();
287 }
288 
289 
290 css::awt::Rectangle SAL_CALL AccessibleCell::getBounds()
291 {
292  SolarMutexGuard aSolarGuard;
293  ::osl::MutexGuard aGuard (maMutex);
294 
295  ThrowIfDisposed ();
296  css::awt::Rectangle aBoundingBox;
297  if( mxCell.is() )
298  {
299  // Get the cell's bounding box in internal coordinates (in 100th of mm)
300  const ::tools::Rectangle aCellRect( mxCell->getCellRect() );
301 
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));
305 
306  ::Size aPixelSize( maShapeTreeInfo.GetViewForwarder()->LogicToPixel(::Size(aCellRect.GetWidth(), aCellRect.GetHeight())) );
307  ::Point aPixelPosition( maShapeTreeInfo.GetViewForwarder()->LogicToPixel( aCellRect.TopLeft() ));
308 
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())
312  {
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;
317 
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());
324  }
325  else
326  {
327  SAL_INFO("svx", "parent does not support component");
328  aBoundingBox = awt::Rectangle (aPixelPosition.getX(), aPixelPosition.getY(),aPixelSize.getWidth(), aPixelSize.getHeight());
329  }
330  }
331 
332  return aBoundingBox;
333 }
334 
335 
336 css::awt::Point SAL_CALL AccessibleCell::getLocation()
337 {
338  ThrowIfDisposed ();
339  css::awt::Rectangle aBoundingBox(getBounds());
340  return css::awt::Point(aBoundingBox.X, aBoundingBox.Y);
341 }
342 
343 
344 css::awt::Point SAL_CALL AccessibleCell::getLocationOnScreen()
345 {
346  ThrowIfDisposed ();
347 
348  // Get relative position...
349  css::awt::Point aLocation(getLocation ());
350 
351  // ... and add absolute position of the parent.
352  Reference<XAccessibleComponent> xParentComponent( getAccessibleParent(), uno::UNO_QUERY);
353  if(xParentComponent.is())
354  {
355  css::awt::Point aParentLocation(xParentComponent->getLocationOnScreen());
356  aLocation.X += aParentLocation.X;
357  aLocation.Y += aParentLocation.Y;
358  }
359  else
360  {
361  SAL_WARN("svx", "parent does not support XAccessibleComponent");
362  }
363 
364  return aLocation;
365 }
366 
367 
368 awt::Size SAL_CALL AccessibleCell::getSize()
369 {
370  ThrowIfDisposed ();
371  awt::Rectangle aBoundingBox (getBounds());
372  return awt::Size (aBoundingBox.Width, aBoundingBox.Height);
373 }
374 
375 
377 {
379 }
380 
381 
382 sal_Int32 SAL_CALL AccessibleCell::getForeground()
383 {
384  ThrowIfDisposed ();
385 
386  // todo
387  return sal_Int32(0x0ffffffL);
388 }
389 
390 
391 sal_Int32 SAL_CALL AccessibleCell::getBackground()
392 {
393  ThrowIfDisposed ();
394 
395  // todo
396  return 0;
397 }
398 
399 
400 // XAccessibleExtendedComponent
401 
402 
403 css::uno::Reference< css::awt::XFont > SAL_CALL AccessibleCell::getFont()
404 {
405 //todo
407 }
408 
409 
411 {
413 }
414 
415 
417 {
419 }
420 
421 
422 // XAccessibleEventBroadcaster
423 
424 
425 void SAL_CALL AccessibleCell::addAccessibleEventListener( const Reference<XAccessibleEventListener >& rxListener)
426 {
427  SolarMutexGuard aSolarGuard;
428  ::osl::MutexGuard aGuard (maMutex);
429  if (rBHelper.bDisposed || rBHelper.bInDispose)
430  {
431  Reference<XInterface> xSource( static_cast<XComponent *>(this) );
432  lang::EventObject aEventObj(xSource);
433  rxListener->disposing(aEventObj);
434  }
435  else
436  {
438  if (mpText != nullptr)
439  mpText->AddEventListener (rxListener);
440  }
441 }
442 
443 
444 void SAL_CALL AccessibleCell::removeAccessibleEventListener( const Reference<XAccessibleEventListener >& rxListener)
445 {
446  SolarMutexGuard aSolarGuard;
448  if (mpText != nullptr)
449  mpText->RemoveEventListener (rxListener);
450 }
451 
452 
453 // XServiceInfo
454 
455 
457 {
458  return "AccessibleCell";
459 }
460 
461 
463 {
464  ThrowIfDisposed ();
465  const css::uno::Sequence<OUString> vals { "com.sun.star.drawing.AccessibleCell" };
467 }
468 
469 
470 // IAccessibleViewForwarderListener
471 
472 
474 {
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());
478 
479  // update our children that our screen position might have changed
480  if( mpText )
481  mpText->UpdateChildren();
482 }
483 
484 
485 // protected
486 
487 
489 {
490  SolarMutexGuard aSolarGuard;
491  ::osl::MutexGuard aGuard (maMutex);
492 
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);
498 
499  if (mpText != nullptr)
500  {
501  mpText->Dispose();
502  mpText.reset();
503  }
504 
505  // Cleanup. Remove references to objects to allow them to be
506  // destroyed.
507  mxCell.clear();
509 
510  // Call base classes.
511  AccessibleContextBase::dispose ();
512 }
513 
515 {
516  ThrowIfDisposed ();
517  return mnIndexInParent;
518 }
519 
520 
521 OUString AccessibleCell::getCellName( sal_Int32 nCol, sal_Int32 nRow )
522 {
523  OUStringBuffer aBuf;
524 
525  if (nCol < 26*26)
526  {
527  if (nCol < 26)
528  aBuf.append( static_cast<sal_Unicode>( 'A' +
529  static_cast<sal_uInt16>(nCol)));
530  else
531  {
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)));
536  }
537  }
538  else
539  {
540  OUStringBuffer aStr;
541  while (nCol >= 26)
542  {
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;
548  }
549  aStr.append(static_cast<sal_Unicode>( 'A' +
550  static_cast<sal_uInt16>(nCol)));
551  aBuf.append(comphelper::string::reverseString(aStr.makeStringAndClear()));
552  }
553  aBuf.append( OUString::number(nRow+1) );
554  return aBuf.makeStringAndClear();
555 }
556 
558 {
559  ThrowIfDisposed ();
560  SolarMutexGuard aSolarGuard;
561 
562  if( pAccTable )
563  {
564  try
565  {
566  sal_Int32 nRow = 0, nCol = 0;
568  return getCellName( nCol, nRow );
569  }
570  catch(const Exception&)
571  {
572  }
573  }
574 
575  return AccessibleCellBase::getAccessibleName();
576 }
577 
579 {
580  if (mpText)
581  mpText->UpdateChildren();
582 }
583 
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
586 +
587 
588 OUString SAL_CALL AccessibleCell::getAccessibleName() throw (css::uno::RuntimeException)
589 {
590  ThrowIfDisposed ();
591  SolarMutexGuard aSolarGuard;
592 
593  if( mxCell.is() )
594  return mxCell->getName();
595 
596  return AccessibleCellBase::getAccessibleName();
597 }
598 */
599 
600 } // end of namespace accessibility
601 
602 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual void SAL_CALL removeAccessibleEventListener(const css::uno::Reference< css::accessibility::XAccessibleEventListener > &xListener) 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 void SAL_CALL release() 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 void SAL_CALL acquire() 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
virtual void SAL_CALL disposing() override
This method is called from the component helper base class while disposing.
::osl::Mutex maMutex
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
#define SAL_INFO(area, stream)
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)
virtual OUString SAL_CALL getToolTipText() override
OUString reverseString(const OUString &rStr)
void AddState(sal_Int16 aState)
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
void RemoveState(sal_Int16 aState)