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>
38 #include <svx/unoshtxt.hxx>
39 #include <svx/svdotext.hxx>
40 #include <tools/debug.hxx>
41 
42 using namespace sdr::table;
43 using namespace ::com::sun::star;
44 using namespace ::com::sun::star::uno;
45 using namespace ::com::sun::star::accessibility;
46 using namespace ::com::sun::star::lang;
47 using namespace ::com::sun::star::container;
48 
49 namespace accessibility {
50 
51 AccessibleCell::AccessibleCell( const css::uno::Reference< css::accessibility::XAccessible>& rxParent, const sdr::table::CellRef& rCell, sal_Int32 nIndex, const AccessibleShapeTreeInfo& rShapeTreeInfo )
52 : AccessibleCellBase( rxParent, AccessibleRole::TABLE_CELL )
53 , maShapeTreeInfo( rShapeTreeInfo )
54 , mnIndexInParent( nIndex )
55 , mxCell( rCell )
56 {
57  //Init the pAccTable var
58  pAccTable = dynamic_cast <AccessibleTableShape *> (rxParent.get());
59 }
60 
61 
63 {
64  DBG_ASSERT( mpText == nullptr, "svx::AccessibleCell::~AccessibleCell(), not disposed!?" );
65 }
66 
67 
69 {
71  const vcl::Window* pWindow = maShapeTreeInfo.GetWindow ();
72  if( (pView != nullptr) && (pWindow != nullptr) && mxCell.is())
73  {
74  // create AccessibleTextHelper to handle this shape's text
75  if( mxCell->CanCreateEditOutlinerParaObject() || mxCell->GetOutlinerParaObject() != nullptr )
76  {
77  // non-empty text -> use full-fledged edit source right away
78 
79  mpText.reset( new AccessibleTextHelper( std::make_unique<SvxTextEditSource>(mxCell->GetObject(), mxCell.get(), *pView, *pWindow) ) );
80  if( mxCell.is() && mxCell->IsActiveCell() )
81  mpText->SetFocus();
82  mpText->SetEventSource(this);
83  }
84  }
85 }
86 
87 
88 bool AccessibleCell::SetState (sal_Int16 aState)
89 {
90  bool bStateHasChanged = false;
91 
92  if (aState == AccessibleStateType::FOCUSED && mpText != nullptr)
93  {
94  // Offer FOCUSED state to edit engine and detect whether the state
95  // changes.
96  bool bIsFocused = mpText->HaveFocus ();
97  mpText->SetFocus();
98  bStateHasChanged = (bIsFocused != mpText->HaveFocus ());
99  }
100  else
101  bStateHasChanged = AccessibleContextBase::SetState (aState);
102 
103  return bStateHasChanged;
104 }
105 
106 
107 bool AccessibleCell::ResetState (sal_Int16 aState)
108 {
109  bool bStateHasChanged = false;
110 
111  if (aState == AccessibleStateType::FOCUSED && mpText != nullptr)
112  {
113  // Try to remove FOCUSED state from the edit engine and detect
114  // whether the state changes.
115  bool bIsFocused = mpText->HaveFocus ();
116  mpText->SetFocus (false);
117  bStateHasChanged = (bIsFocused != mpText->HaveFocus ());
118  }
119  else
120  bStateHasChanged = AccessibleContextBase::ResetState (aState);
121 
122  return bStateHasChanged;
123 }
124 
125 
126 // XInterface
127 
128 
129 Any SAL_CALL AccessibleCell::queryInterface( const Type& aType )
130 {
131  return AccessibleCellBase::queryInterface( aType );
132 }
133 
134 
135 void SAL_CALL AccessibleCell::acquire( ) throw ()
136 {
137  AccessibleCellBase::acquire();
138 }
139 
140 
141 void SAL_CALL AccessibleCell::release( ) throw ()
142 {
143  AccessibleCellBase::release();
144 }
145 
146 
147 // XAccessibleContext
148 
149 
153 {
154  SolarMutexGuard aSolarGuard;
155  ThrowIfDisposed ();
156  return mpText != nullptr ? mpText->GetChildCount () : 0;
157 }
158 
159 
163 Reference<XAccessible> SAL_CALL AccessibleCell::getAccessibleChild (sal_Int32 nIndex)
164 {
165  SolarMutexGuard aSolarGuard;
166  ThrowIfDisposed ();
167 
168  // todo: does GetChild throw IndexOutOfBoundsException?
169  return mpText->GetChild (nIndex);
170 }
171 
172 
179 Reference<XAccessibleStateSet> SAL_CALL AccessibleCell::getAccessibleStateSet()
180 {
181  SolarMutexGuard aSolarGuard;
182  ::osl::MutexGuard aGuard (maMutex);
183  Reference<XAccessibleStateSet> xStateSet;
184 
185  if (rBHelper.bDisposed || mpText == nullptr)
186  {
187  // Return a minimal state set that only contains the DEFUNC state.
189  }
190  else
191  {
192  ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
193 
194  if(pStateSet)
195  {
196  // Merge current FOCUSED state from edit engine.
197  if (mpText != nullptr)
198  {
199  if (mpText->HaveFocus())
200  pStateSet->AddState (AccessibleStateType::FOCUSED);
201  else
202  pStateSet->RemoveState (AccessibleStateType::FOCUSED);
203  }
204  // Set the invisible state for merged cell
205  if (mxCell.is() && mxCell->isMerged())
206  pStateSet->RemoveState(AccessibleStateType::VISIBLE);
207  else
208  pStateSet->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  css::uno::Sequence<short> aStates = rState->getStates();
224  if (std::find(aStates.begin(), aStates.end(), AccessibleStateType::EDITABLE) != aStates.end())
225  {
226  pStateSet->AddState (AccessibleStateType::EDITABLE);
227  pStateSet->AddState (AccessibleStateType::RESIZABLE);
228  pStateSet->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 (*pStateSet));
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 (maMutex);
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 (maMutex);
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.getX(), aBBox.getY(), 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 (maMutex);
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 
465  // Get list of supported service names from base class...
467  sal_Int32 nCount (aServiceNames.getLength());
468 
469  // ...and add additional names.
470  aServiceNames.realloc (nCount + 1);
471  aServiceNames[nCount] = "com.sun.star.drawing.AccessibleCell";
472 
473  return aServiceNames;
474 }
475 
476 
477 // IAccessibleViewForwarderListener
478 
479 
481 {
482  // Inform all listeners that the graphical representation (i.e. size
483  // and/or position) of the shape has changed.
484  CommitChange(AccessibleEventId::VISIBLE_DATA_CHANGED, Any(), Any());
485 
486  // update our children that our screen position might have changed
487  if( mpText )
488  mpText->UpdateChildren();
489 }
490 
491 
492 // protected
493 
494 
496 {
497  SolarMutexGuard aSolarGuard;
498  ::osl::MutexGuard aGuard (maMutex);
499 
500  // Make sure to send an event that this object loses the focus in the
501  // case that it has the focus.
502  ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
503  if (pStateSet != nullptr)
504  pStateSet->RemoveState(AccessibleStateType::FOCUSED);
505 
506  if (mpText != nullptr)
507  {
508  mpText->Dispose();
509  mpText.reset();
510  }
511 
512  // Cleanup. Remove references to objects to allow them to be
513  // destroyed.
514  mxCell.clear();
516 
517  // Call base classes.
518  AccessibleContextBase::dispose ();
519 }
520 
522 {
523  ThrowIfDisposed ();
524  return mnIndexInParent;
525 }
526 
527 
528 OUString AccessibleCell::getCellName( sal_Int32 nCol, sal_Int32 nRow )
529 {
530  OUStringBuffer aBuf;
531 
532  if (nCol < 26*26)
533  {
534  if (nCol < 26)
535  aBuf.append( static_cast<sal_Unicode>( 'A' +
536  static_cast<sal_uInt16>(nCol)));
537  else
538  {
539  aBuf.append( static_cast<sal_Unicode>( 'A' +
540  (static_cast<sal_uInt16>(nCol) / 26) - 1));
541  aBuf.append( static_cast<sal_Unicode>( 'A' +
542  (static_cast<sal_uInt16>(nCol) % 26)));
543  }
544  }
545  else
546  {
547  OUStringBuffer aStr;
548  while (nCol >= 26)
549  {
550  sal_Int32 nC = nCol % 26;
551  aStr.append(static_cast<sal_Unicode>( 'A' +
552  static_cast<sal_uInt16>(nC)));
553  nCol = nCol - nC;
554  nCol = nCol / 26 - 1;
555  }
556  aStr.append(static_cast<sal_Unicode>( 'A' +
557  static_cast<sal_uInt16>(nCol)));
558  aBuf.append(comphelper::string::reverseString(aStr.makeStringAndClear()));
559  }
560  aBuf.append( OUString::number(nRow+1) );
561  return aBuf.makeStringAndClear();
562 }
563 
565 {
566  ThrowIfDisposed ();
567  SolarMutexGuard aSolarGuard;
568 
569  if( pAccTable )
570  {
571  try
572  {
573  sal_Int32 nRow = 0, nCol = 0;
575  return getCellName( nCol, nRow );
576  }
577  catch(const Exception&)
578  {
579  }
580  }
581 
582  return AccessibleCellBase::getAccessibleName();
583 }
584 
586 {
587  if (mpText)
588  mpText->UpdateChildren();
589 }
590 
591 /* MT: Above getAccessibleName was introduced with IA2 CWS, while below was introduce in 3.3 meanwhile. Check which one is correct
592 +If this is correct, we also don't need sdr::table::CellRef getCellRef(), UpdateChildren(), getCellName( sal_Int32 nCol, sal_Int32 nRow ) above
593 +
594 
595 OUString SAL_CALL AccessibleCell::getAccessibleName() throw (css::uno::RuntimeException)
596 {
597  ThrowIfDisposed ();
598  SolarMutexGuard aSolarGuard;
599 
600  if( mxCell.is() )
601  return mxCell->getName();
602 
603  return AccessibleCellBase::getAccessibleName();
604 }
605 */
606 
607 } // end of namespace accessibility
608 
609 /* 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
osl::Mutex maMutex
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
Sequence< OUString > aServiceNames
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
int nCount
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.
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.
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)