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 (maMutex);
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  ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
195 
196  if(pStateSet)
197  {
198  // Merge current FOCUSED state from edit engine.
199  if (mpText != nullptr)
200  {
201  if (mpText->HaveFocus())
202  pStateSet->AddState (AccessibleStateType::FOCUSED);
203  else
204  pStateSet->RemoveState (AccessibleStateType::FOCUSED);
205  }
206  // Set the invisible state for merged cell
207  if (mxCell.is() && mxCell->isMerged())
208  pStateSet->RemoveState(AccessibleStateType::VISIBLE);
209  else
210  pStateSet->AddState(AccessibleStateType::VISIBLE);
211 
212 
213  //Just when the parent table is not read-only,set states EDITABLE,RESIZABLE,MOVEABLE
214  css::uno::Reference<XAccessible> xTempAcc = getAccessibleParent();
215  if( xTempAcc.is() )
216  {
217  css::uno::Reference<XAccessibleContext>
218  xTempAccContext = xTempAcc->getAccessibleContext();
219  if( xTempAccContext.is() )
220  {
221  css::uno::Reference<XAccessibleStateSet> rState =
222  xTempAccContext->getAccessibleStateSet();
223  if( rState.is() )
224  {
225  const css::uno::Sequence<short> aStates = rState->getStates();
226  if (std::find(aStates.begin(), aStates.end(), AccessibleStateType::EDITABLE) != aStates.end())
227  {
228  pStateSet->AddState (AccessibleStateType::EDITABLE);
229  pStateSet->AddState (AccessibleStateType::RESIZABLE);
230  pStateSet->AddState (AccessibleStateType::MOVEABLE);
231  }
232  }
233  }
234  }
235  // Create a copy of the state set that may be modified by the
236  // caller without affecting the current state set.
237  xStateSet.set(new ::utl::AccessibleStateSetHelper (*pStateSet));
238  }
239  }
240 
241  return xStateSet;
242 }
243 
244 
245 // XAccessibleComponent
246 
247 
248 sal_Bool SAL_CALL AccessibleCell::containsPoint( const css::awt::Point& aPoint)
249 {
251 }
252 
261 Reference<XAccessible > SAL_CALL AccessibleCell::getAccessibleAtPoint ( const css::awt::Point& aPoint)
262 {
263  SolarMutexGuard aSolarGuard;
264  ::osl::MutexGuard aGuard (maMutex);
265 
266  sal_Int32 nChildCount = getAccessibleChildCount ();
267  for (sal_Int32 i=0; i<nChildCount; ++i)
268  {
269  Reference<XAccessible> xChild (getAccessibleChild (i));
270  if (xChild.is())
271  {
272  Reference<XAccessibleComponent> xChildComponent (xChild->getAccessibleContext(), uno::UNO_QUERY);
273  if (xChildComponent.is())
274  {
275  awt::Rectangle aBBox (xChildComponent->getBounds());
276  if ( (aPoint.X >= aBBox.X)
277  && (aPoint.Y >= aBBox.Y)
278  && (aPoint.X < aBBox.X+aBBox.Width)
279  && (aPoint.Y < aBBox.Y+aBBox.Height) )
280  return xChild;
281  }
282  }
283  }
284 
285  // Have not found a child under the given point. Returning empty
286  // reference to indicate this.
287  return uno::Reference<XAccessible>();
288 }
289 
290 
291 css::awt::Rectangle SAL_CALL AccessibleCell::getBounds()
292 {
293  SolarMutexGuard aSolarGuard;
294  ::osl::MutexGuard aGuard (maMutex);
295 
296  ThrowIfDisposed ();
297  css::awt::Rectangle aBoundingBox;
298  if( mxCell.is() )
299  {
300  // Get the cell's bounding box in internal coordinates (in 100th of mm)
301  const ::tools::Rectangle aCellRect( mxCell->getCellRect() );
302 
303  // Transform coordinates from internal to pixel.
304  if (maShapeTreeInfo.GetViewForwarder() == nullptr)
305  throw uno::RuntimeException ("AccessibleCell has no valid view forwarder",static_cast<uno::XWeak*>(this));
306 
307  ::Size aPixelSize( maShapeTreeInfo.GetViewForwarder()->LogicToPixel(::Size(aCellRect.GetWidth(), aCellRect.GetHeight())) );
308  ::Point aPixelPosition( maShapeTreeInfo.GetViewForwarder()->LogicToPixel( aCellRect.TopLeft() ));
309 
310  // Clip the shape's bounding box with the bounding box of its parent.
311  Reference<XAccessibleComponent> xParentComponent ( getAccessibleParent(), uno::UNO_QUERY);
312  if (xParentComponent.is())
313  {
314  // Make the coordinates relative to the parent.
315  awt::Point aParentLocation (xParentComponent->getLocationOnScreen());
316  int x = aPixelPosition.getX() - aParentLocation.X;
317  int y = aPixelPosition.getY() - aParentLocation.Y;
318 
319  // Clip with parent (with coordinates relative to itself).
320  ::tools::Rectangle aBBox ( x, y, x + aPixelSize.getWidth(), y + aPixelSize.getHeight());
321  awt::Size aParentSize (xParentComponent->getSize());
322  ::tools::Rectangle aParentBBox (0,0, aParentSize.Width, aParentSize.Height);
323  aBBox = aBBox.GetIntersection (aParentBBox);
324  aBoundingBox = awt::Rectangle ( aBBox.Left(), aBBox.Top(), aBBox.getWidth(), aBBox.getHeight());
325  }
326  else
327  {
328  SAL_INFO("svx", "parent does not support component");
329  aBoundingBox = awt::Rectangle (aPixelPosition.getX(), aPixelPosition.getY(),aPixelSize.getWidth(), aPixelSize.getHeight());
330  }
331  }
332 
333  return aBoundingBox;
334 }
335 
336 
337 css::awt::Point SAL_CALL AccessibleCell::getLocation()
338 {
339  ThrowIfDisposed ();
340  css::awt::Rectangle aBoundingBox(getBounds());
341  return css::awt::Point(aBoundingBox.X, aBoundingBox.Y);
342 }
343 
344 
345 css::awt::Point SAL_CALL AccessibleCell::getLocationOnScreen()
346 {
347  ThrowIfDisposed ();
348 
349  // Get relative position...
350  css::awt::Point aLocation(getLocation ());
351 
352  // ... and add absolute position of the parent.
353  Reference<XAccessibleComponent> xParentComponent( getAccessibleParent(), uno::UNO_QUERY);
354  if(xParentComponent.is())
355  {
356  css::awt::Point aParentLocation(xParentComponent->getLocationOnScreen());
357  aLocation.X += aParentLocation.X;
358  aLocation.Y += aParentLocation.Y;
359  }
360  else
361  {
362  SAL_WARN("svx", "parent does not support XAccessibleComponent");
363  }
364 
365  return aLocation;
366 }
367 
368 
369 awt::Size SAL_CALL AccessibleCell::getSize()
370 {
371  ThrowIfDisposed ();
372  awt::Rectangle aBoundingBox (getBounds());
373  return awt::Size (aBoundingBox.Width, aBoundingBox.Height);
374 }
375 
376 
378 {
380 }
381 
382 
383 sal_Int32 SAL_CALL AccessibleCell::getForeground()
384 {
385  ThrowIfDisposed ();
386 
387  // todo
388  return sal_Int32(0x0ffffffL);
389 }
390 
391 
392 sal_Int32 SAL_CALL AccessibleCell::getBackground()
393 {
394  ThrowIfDisposed ();
395 
396  // todo
397  return 0;
398 }
399 
400 
401 // XAccessibleExtendedComponent
402 
403 
404 css::uno::Reference< css::awt::XFont > SAL_CALL AccessibleCell::getFont()
405 {
406 //todo
408 }
409 
410 
412 {
414 }
415 
416 
418 {
420 }
421 
422 
423 // XAccessibleEventBroadcaster
424 
425 
426 void SAL_CALL AccessibleCell::addAccessibleEventListener( const Reference<XAccessibleEventListener >& rxListener)
427 {
428  SolarMutexGuard aSolarGuard;
429  ::osl::MutexGuard aGuard (maMutex);
430  if (rBHelper.bDisposed || rBHelper.bInDispose)
431  {
432  Reference<XInterface> xSource( static_cast<XComponent *>(this) );
433  lang::EventObject aEventObj(xSource);
434  rxListener->disposing(aEventObj);
435  }
436  else
437  {
439  if (mpText != nullptr)
440  mpText->AddEventListener (rxListener);
441  }
442 }
443 
444 
445 void SAL_CALL AccessibleCell::removeAccessibleEventListener( const Reference<XAccessibleEventListener >& rxListener)
446 {
447  SolarMutexGuard aSolarGuard;
449  if (mpText != nullptr)
450  mpText->RemoveEventListener (rxListener);
451 }
452 
453 
454 // XServiceInfo
455 
456 
458 {
459  return "AccessibleCell";
460 }
461 
462 
464 {
465  ThrowIfDisposed ();
466  const css::uno::Sequence<OUString> vals { "com.sun.star.drawing.AccessibleCell" };
468 }
469 
470 
471 // IAccessibleViewForwarderListener
472 
473 
475 {
476  // Inform all listeners that the graphical representation (i.e. size
477  // and/or position) of the shape has changed.
478  CommitChange(AccessibleEventId::VISIBLE_DATA_CHANGED, Any(), Any());
479 
480  // update our children that our screen position might have changed
481  if( mpText )
482  mpText->UpdateChildren();
483 }
484 
485 
486 // protected
487 
488 
490 {
491  SolarMutexGuard aSolarGuard;
492  ::osl::MutexGuard aGuard (maMutex);
493 
494  // Make sure to send an event that this object loses the focus in the
495  // case that it has the focus.
496  ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
497  if (pStateSet != nullptr)
498  pStateSet->RemoveState(AccessibleStateType::FOCUSED);
499 
500  if (mpText != nullptr)
501  {
502  mpText->Dispose();
503  mpText.reset();
504  }
505 
506  // Cleanup. Remove references to objects to allow them to be
507  // destroyed.
508  mxCell.clear();
510 
511  // Call base classes.
512  AccessibleContextBase::dispose ();
513 }
514 
516 {
517  ThrowIfDisposed ();
518  return mnIndexInParent;
519 }
520 
521 
522 OUString AccessibleCell::getCellName( sal_Int32 nCol, sal_Int32 nRow )
523 {
524  OUStringBuffer aBuf;
525 
526  if (nCol < 26*26)
527  {
528  if (nCol < 26)
529  aBuf.append( static_cast<sal_Unicode>( 'A' +
530  static_cast<sal_uInt16>(nCol)));
531  else
532  {
533  aBuf.append( static_cast<sal_Unicode>( 'A' +
534  (static_cast<sal_uInt16>(nCol) / 26) - 1));
535  aBuf.append( static_cast<sal_Unicode>( 'A' +
536  (static_cast<sal_uInt16>(nCol) % 26)));
537  }
538  }
539  else
540  {
541  OUStringBuffer aStr;
542  while (nCol >= 26)
543  {
544  sal_Int32 nC = nCol % 26;
545  aStr.append(static_cast<sal_Unicode>( 'A' +
546  static_cast<sal_uInt16>(nC)));
547  nCol = nCol - nC;
548  nCol = nCol / 26 - 1;
549  }
550  aStr.append(static_cast<sal_Unicode>( 'A' +
551  static_cast<sal_uInt16>(nCol)));
552  aBuf.append(comphelper::string::reverseString(aStr.makeStringAndClear()));
553  }
554  aBuf.append(nRow+1);
555  return aBuf.makeStringAndClear();
556 }
557 
559 {
560  ThrowIfDisposed ();
561  SolarMutexGuard aSolarGuard;
562 
563  if( pAccTable )
564  {
565  try
566  {
567  sal_Int32 nRow = 0, nCol = 0;
569  return getCellName( nCol, nRow );
570  }
571  catch(const Exception&)
572  {
573  }
574  }
575 
576  return AccessibleCellBase::getAccessibleName();
577 }
578 
580 {
581  if (mpText)
582  mpText->UpdateChildren();
583 }
584 
585 /* MT: Above getAccessibleName was introduced with IA2 CWS, while below was introduce in 3.3 meanwhile. Check which one is correct
586 +If this is correct, we also don't need sdr::table::CellRef getCellRef(), UpdateChildren(), getCellName( sal_Int32 nCol, sal_Int32 nRow ) above
587 +
588 
589 OUString SAL_CALL AccessibleCell::getAccessibleName() throw (css::uno::RuntimeException)
590 {
591  ThrowIfDisposed ();
592  SolarMutexGuard aSolarGuard;
593 
594  if( mxCell.is() )
595  return mxCell->getName();
596 
597  return AccessibleCellBase::getAccessibleName();
598 }
599 */
600 
601 } // end of namespace accessibility
602 
603 /* 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
std::mutex maMutex
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
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
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)