xref: /trunk/main/svx/source/table/accessiblecell.cxx (revision f6e50924)
1  /**************************************************************
2   *
3   * Licensed to the Apache Software Foundation (ASF) under one
4   * or more contributor license agreements.  See the NOTICE file
5   * distributed with this work for additional information
6   * regarding copyright ownership.  The ASF licenses this file
7   * to you under the Apache License, Version 2.0 (the
8   * "License"); you may not use this file except in compliance
9   * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   *
20   *************************************************************/
21  
22  
23  
24  // MARKER(update_precomp.py): autogen include statement, do not remove
25  #include "precompiled_svx.hxx"
26  
27  #include <accessiblecell.hxx>
28  
29  #include "svx/DescriptionGenerator.hxx"
30  
31  #include <com/sun/star/accessibility/AccessibleRole.hpp>
32  #include <com/sun/star/accessibility/AccessibleStateType.hpp>
33  
34  #include <vcl/svapp.hxx>
35  
36  #include <unotools/accessiblestatesethelper.hxx>
37  
38  #include <editeng/outlobj.hxx>
39  #include <svx/unoshtxt.hxx>
40  #include <svx/svdotext.hxx>
41  
42  using ::rtl::OUString;
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  // --------------------------------------------------------------------
53  // AccessibleCell
54  // --------------------------------------------------------------------
55  
56  AccessibleCell::AccessibleCell( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible>& rxParent, const sdr::table::CellRef& rCell, sal_Int32 nIndex, const AccessibleShapeTreeInfo& rShapeTreeInfo )
57  : AccessibleCellBase( rxParent, AccessibleRole::TABLE_CELL )
58  , maShapeTreeInfo( rShapeTreeInfo )
59  , mnIndexInParent( nIndex )
60  , mpText( NULL )
61  , mxCell( rCell )
62  {
63  }
64  
65  // --------------------------------------------------------------------
66  
67  AccessibleCell::~AccessibleCell (void)
68  {
69  	DBG_ASSERT( mpText == 0, "svx::AccessibleCell::~AccessibleCell(), not disposed!?" );
70  }
71  
72  // --------------------------------------------------------------------
73  
74  void AccessibleCell::Init (void)
75  {
76  	SdrView* pView = maShapeTreeInfo.GetSdrView();
77  	const Window* pWindow = maShapeTreeInfo.GetWindow ();
78  	if( (pView != NULL) && (pWindow != NULL) && mxCell.is())
79  	{
80          OutlinerParaObject* pOutlinerParaObject = mxCell->GetEditOutlinerParaObject(); // Get the OutlinerParaObject if text edit is active
81  
82          bool bOwnParaObject = pOutlinerParaObject != 0;
83  
84  		if( !pOutlinerParaObject )
85  			pOutlinerParaObject = mxCell->GetOutlinerParaObject();
86  
87  		// create AccessibleTextHelper to handle this shape's text
88          if( pOutlinerParaObject )
89          {
90              // non-empty text -> use full-fledged edit source right away
91              ::std::auto_ptr<SvxEditSource> pEditSource( new SvxTextEditSource( mxCell->GetObject(), mxCell.get(), *pView, *pWindow) );
92              mpText = new AccessibleTextHelper( pEditSource );
93  			mpText->SetEventSource(this);
94          }
95  
96          if( bOwnParaObject)
97              delete pOutlinerParaObject;
98      }
99  }
100  
101  // --------------------------------------------------------------------
102  
103  sal_Bool AccessibleCell::SetState (sal_Int16 aState)
104  {
105      sal_Bool bStateHasChanged = sal_False;
106  
107      if (aState == AccessibleStateType::FOCUSED && mpText != NULL)
108      {
109          // Offer FOCUSED state to edit engine and detect whether the state
110          // changes.
111          sal_Bool bIsFocused = mpText->HaveFocus ();
112          mpText->SetFocus (sal_True);
113          bStateHasChanged = (bIsFocused != mpText->HaveFocus ());
114      }
115      else
116          bStateHasChanged = AccessibleContextBase::SetState (aState);
117  
118      return bStateHasChanged;
119  }
120  
121  // --------------------------------------------------------------------
122  
123  sal_Bool AccessibleCell::ResetState (sal_Int16 aState)
124  {
125      sal_Bool bStateHasChanged = sal_False;
126  
127      if (aState == AccessibleStateType::FOCUSED && mpText != NULL)
128      {
129          // Try to remove FOCUSED state from the edit engine and detect
130          // whether the state changes.
131          sal_Bool bIsFocused = mpText->HaveFocus ();
132          mpText->SetFocus (sal_False);
133          bStateHasChanged = (bIsFocused != mpText->HaveFocus ());
134      }
135      else
136          bStateHasChanged = AccessibleContextBase::ResetState (aState);
137  
138      return bStateHasChanged;
139  }
140  
141  // --------------------------------------------------------------------
142  
143  sal_Bool AccessibleCell::GetState (sal_Int16 aState)
144  {
145      if (aState == AccessibleStateType::FOCUSED && mpText != NULL)
146      {
147          // Just delegate the call to the edit engine.  The state is not
148          // merged into the state set.
149          return mpText->HaveFocus();
150      }
151      else
152          return AccessibleContextBase::GetState (aState);
153  }
154  
155  //-----------------------------------------------------------------------------
156  
157  bool AccessibleCell::operator== (const AccessibleCell& rAccessibleCell)
158  {
159  	return this == &rAccessibleCell;
160  }
161  
162  //-----------------------------------------------------------------------------
163  // XInterface
164  //-----------------------------------------------------------------------------
165  
166  Any SAL_CALL AccessibleCell::queryInterface( const Type& aType ) throw (RuntimeException)
167  {
168  	return AccessibleCellBase::queryInterface( aType );
169  }
170  
171  //-----------------------------------------------------------------------------
172  
173  void SAL_CALL AccessibleCell::acquire(  ) throw ()
174  {
175  	AccessibleCellBase::acquire();
176  }
177  
178  //-----------------------------------------------------------------------------
179  
180  void SAL_CALL AccessibleCell::release(  ) throw ()
181  {
182  	AccessibleCellBase::release();
183  }
184  
185  // --------------------------------------------------------------------
186  // XAccessibleContext
187  // --------------------------------------------------------------------
188  
189  /** The children of this cell come from the paragraphs of text.
190  */
191  sal_Int32 SAL_CALL AccessibleCell::getAccessibleChildCount() throw (::com::sun::star::uno::RuntimeException)
192  {
193      ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
194      ThrowIfDisposed ();
195  	return mpText != NULL ? mpText->GetChildCount () : 0;
196  }
197  
198  // --------------------------------------------------------------------
199  
200  /** Forward the request to the shape.  Return the requested shape or throw
201      an exception for a wrong index.
202  */
203  Reference<XAccessible> SAL_CALL AccessibleCell::getAccessibleChild (sal_Int32 nIndex) throw (IndexOutOfBoundsException, RuntimeException)
204  {
205      ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
206      ThrowIfDisposed ();
207  
208  	// todo: does GetChild throw IndexOutOfBoundsException?
209  	return mpText->GetChild (nIndex);
210  }
211  
212  // --------------------------------------------------------------------
213  
214  /**	Return a copy of the state set.
215      Possible states are:
216  		ENABLED
217  		SHOWING
218  		VISIBLE
219  */
220  Reference<XAccessibleStateSet> SAL_CALL AccessibleCell::getAccessibleStateSet (void) throw (RuntimeException)
221  {
222      ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
223      ::osl::MutexGuard aGuard (maMutex);
224      Reference<XAccessibleStateSet> xStateSet;
225  
226  	if (rBHelper.bDisposed || mpText == NULL)
227  	{
228          // Return a minimal state set that only contains the DEFUNC state.
229          xStateSet = AccessibleContextBase::getAccessibleStateSet ();
230  	}
231      else
232      {
233          ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
234  
235          if(pStateSet)
236          {
237              // Merge current FOCUSED state from edit engine.
238              if (mpText != NULL)
239  			{
240  				if (mpText->HaveFocus())
241                      pStateSet->AddState (AccessibleStateType::FOCUSED);
242                  else
243                      pStateSet->RemoveState (AccessibleStateType::FOCUSED);
244  			}
245  
246              // Create a copy of the state set that may be modified by the
247              // caller without affecting the current state set.
248              xStateSet = Reference<XAccessibleStateSet>(new ::utl::AccessibleStateSetHelper (*pStateSet));
249          }
250      }
251  
252      return xStateSet;
253  }
254  
255  // --------------------------------------------------------------------
256  // XAccessibleComponent
257  // --------------------------------------------------------------------
258  
259  sal_Bool SAL_CALL AccessibleCell::containsPoint( const ::com::sun::star::awt::Point& aPoint) throw (::com::sun::star::uno::RuntimeException)
260  {
261  	return AccessibleComponentBase::containsPoint( aPoint );
262  }
263  
264  /** The implementation below is at the moment straightforward.  It iterates
265      over all children (and thereby instances all children which have not
266      been already instatiated) until a child covering the specifed point is
267      found.
268      This leaves room for improvement.  For instance, first iterate only over
269      the already instantiated children and only if no match is found
270      instantiate the remaining ones.
271  */
272  Reference<XAccessible > SAL_CALL  AccessibleCell::getAccessibleAtPoint ( const ::com::sun::star::awt::Point& aPoint) throw(RuntimeException)
273  {
274      ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
275      ::osl::MutexGuard aGuard (maMutex);
276  
277      sal_Int32 nChildCount = getAccessibleChildCount ();
278      for (sal_Int32 i=0; i<nChildCount; ++i)
279      {
280          Reference<XAccessible> xChild (getAccessibleChild (i));
281          if (xChild.is())
282          {
283              Reference<XAccessibleComponent> xChildComponent (xChild->getAccessibleContext(), uno::UNO_QUERY);
284              if (xChildComponent.is())
285              {
286                  awt::Rectangle aBBox (xChildComponent->getBounds());
287                  if ( (aPoint.X >= aBBox.X)
288                      && (aPoint.Y >= aBBox.Y)
289                      && (aPoint.X < aBBox.X+aBBox.Width)
290                      && (aPoint.Y < aBBox.Y+aBBox.Height) )
291                      return xChild;
292              }
293          }
294      }
295  
296      // Have not found a child under the given point.  Returning empty
297      // reference to indicate this.
298      return uno::Reference<XAccessible>();
299  }
300  
301  // --------------------------------------------------------------------
302  
303  ::com::sun::star::awt::Rectangle SAL_CALL AccessibleCell::getBounds(void) throw(RuntimeException)
304  {
305      ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
306      ::osl::MutexGuard aGuard (maMutex);
307  
308      ThrowIfDisposed ();
309  	::com::sun::star::awt::Rectangle aBoundingBox;
310  	if( mxCell.is() )
311  	{
312  		// Get the cell's bounding box in internal coordinates (in 100th of mm)
313  		const ::Rectangle aCellRect( mxCell->getCellRect() );
314  
315  		// Transform coordinates from internal to pixel.
316  		if (maShapeTreeInfo.GetViewForwarder() == NULL)
317  			throw uno::RuntimeException (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleCell has no valid view forwarder")),static_cast<uno::XWeak*>(this));
318  
319  		::Size aPixelSize( maShapeTreeInfo.GetViewForwarder()->LogicToPixel(::Size(aCellRect.GetWidth(), aCellRect.GetHeight())) );
320  		::Point aPixelPosition( maShapeTreeInfo.GetViewForwarder()->LogicToPixel( aCellRect.TopLeft() ));
321  
322  		// Clip the shape's bounding box with the bounding box of its parent.
323  		Reference<XAccessibleComponent> xParentComponent ( getAccessibleParent(), uno::UNO_QUERY);
324  		if (xParentComponent.is())
325  		{
326  			// Make the coordinates relative to the parent.
327  			awt::Point aParentLocation (xParentComponent->getLocationOnScreen());
328  			int x = aPixelPosition.getX() - aParentLocation.X;
329  			int y = aPixelPosition.getY() - aParentLocation.Y;
330  
331  			// Clip with parent (with coordinates relative to itself).
332  			::Rectangle aBBox ( x, y, x + aPixelSize.getWidth(), y + aPixelSize.getHeight());
333  			awt::Size aParentSize (xParentComponent->getSize());
334  			::Rectangle aParentBBox (0,0, aParentSize.Width, aParentSize.Height);
335  			aBBox = aBBox.GetIntersection (aParentBBox);
336  			aBoundingBox = awt::Rectangle (	aBBox.getX(), aBBox.getY(), aBBox.getWidth(), aBBox.getHeight());
337  		}
338  		else
339  		{
340  			OSL_TRACE ("parent does not support component");
341  			aBoundingBox = awt::Rectangle (aPixelPosition.getX(), aPixelPosition.getY(),aPixelSize.getWidth(), aPixelSize.getHeight());
342  		}
343  	}
344  
345      return aBoundingBox;
346  }
347  
348  // --------------------------------------------------------------------
349  
350  ::com::sun::star::awt::Point SAL_CALL AccessibleCell::getLocation(void) throw (RuntimeException)
351  {
352      ThrowIfDisposed ();
353  	::com::sun::star::awt::Rectangle aBoundingBox(getBounds());
354      return ::com::sun::star::awt::Point(aBoundingBox.X, aBoundingBox.Y);
355  }
356  
357  // --------------------------------------------------------------------
358  
359  ::com::sun::star::awt::Point SAL_CALL AccessibleCell::getLocationOnScreen(void) throw(RuntimeException)
360  {
361      ThrowIfDisposed ();
362  
363      // Get relative position...
364      ::com::sun::star::awt::Point aLocation(getLocation ());
365  
366      // ... and add absolute position of the parent.
367      Reference<XAccessibleComponent> xParentComponent( getAccessibleParent(), uno::UNO_QUERY);
368      if(xParentComponent.is())
369      {
370          ::com::sun::star::awt::Point aParentLocation(xParentComponent->getLocationOnScreen());
371          aLocation.X += aParentLocation.X;
372          aLocation.Y += aParentLocation.Y;
373      }
374      else
375  	{
376          OSL_TRACE ("getLocation: parent does not support XAccessibleComponent");
377  	}
378  
379  	return aLocation;
380  }
381  
382  // --------------------------------------------------------------------
383  
384  awt::Size SAL_CALL AccessibleCell::getSize (void) throw (RuntimeException)
385  {
386      ThrowIfDisposed ();
387      awt::Rectangle aBoundingBox (getBounds());
388      return awt::Size (aBoundingBox.Width, aBoundingBox.Height);
389  }
390  
391  // --------------------------------------------------------------------
392  
393  void SAL_CALL AccessibleCell::addFocusListener ( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XFocusListener >& xListener) throw (::com::sun::star::uno::RuntimeException)
394  {
395  	AccessibleComponentBase::addFocusListener( xListener );
396  }
397  
398  // --------------------------------------------------------------------
399  
400  void SAL_CALL AccessibleCell::removeFocusListener (const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XFocusListener >& xListener ) throw (::com::sun::star::uno::RuntimeException)
401  {
402  	AccessibleComponentBase::removeFocusListener( xListener );
403  }
404  
405  // --------------------------------------------------------------------
406  
407  void SAL_CALL AccessibleCell::grabFocus (void) throw (::com::sun::star::uno::RuntimeException)
408  {
409  	AccessibleComponentBase::grabFocus();
410  }
411  
412  // --------------------------------------------------------------------
413  
414  sal_Int32 SAL_CALL AccessibleCell::getForeground(void) throw (RuntimeException)
415  {
416      ThrowIfDisposed ();
417      sal_Int32 nColor (0x0ffffffL);
418  
419  	// todo
420      return nColor;
421  }
422  
423  // --------------------------------------------------------------------
424  
425  sal_Int32 SAL_CALL AccessibleCell::getBackground (void) throw (RuntimeException)
426  {
427      ThrowIfDisposed ();
428      sal_Int32 nColor (0L);
429  
430  	// todo
431      return nColor;
432  }
433  
434  // --------------------------------------------------------------------
435  // XAccessibleExtendedComponent
436  // --------------------------------------------------------------------
437  
438  ::com::sun::star::uno::Reference< ::com::sun::star::awt::XFont > SAL_CALL AccessibleCell::getFont (void) throw (::com::sun::star::uno::RuntimeException)
439  {
440  //todo
441  	return AccessibleComponentBase::getFont();
442  }
443  
444  // --------------------------------------------------------------------
445  
446  ::rtl::OUString SAL_CALL AccessibleCell::getTitledBorderText (void) throw (::com::sun::star::uno::RuntimeException)
447  {
448  	return AccessibleComponentBase::getTitledBorderText();
449  }
450  
451  // --------------------------------------------------------------------
452  
453  ::rtl::OUString SAL_CALL AccessibleCell::getToolTipText (void) throw (::com::sun::star::uno::RuntimeException)
454  {
455  	return AccessibleComponentBase::getToolTipText();
456  }
457  
458  // --------------------------------------------------------------------
459  // XAccessibleEventBroadcaster
460  // --------------------------------------------------------------------
461  
462  void SAL_CALL AccessibleCell::addEventListener( const Reference<XAccessibleEventListener >& rxListener)  throw (RuntimeException)
463  {
464      ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
465      ::osl::MutexGuard aGuard (maMutex);
466  	if (rBHelper.bDisposed || rBHelper.bInDispose)
467  	{
468  		Reference<XInterface> xSource( static_cast<XComponent *>(this) );
469  		lang::EventObject aEventObj(xSource);
470  		rxListener->disposing(aEventObj);
471  	}
472      else
473      {
474          AccessibleContextBase::addEventListener (rxListener);
475          if (mpText != NULL)
476              mpText->AddEventListener (rxListener);
477      }
478  }
479  
480  // --------------------------------------------------------------------
481  
482  void SAL_CALL AccessibleCell::removeEventListener( const Reference<XAccessibleEventListener >& rxListener) throw (RuntimeException)
483  {
484      ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
485      AccessibleContextBase::removeEventListener(rxListener);
486      if (mpText != NULL)
487          mpText->RemoveEventListener (rxListener);
488  }
489  
490  // --------------------------------------------------------------------
491  // XServiceInfo
492  // --------------------------------------------------------------------
493  
494  OUString SAL_CALL AccessibleCell::getImplementationName(void) throw (RuntimeException)
495  {
496  	return OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleCell"));
497  }
498  
499  // --------------------------------------------------------------------
500  
501  Sequence<OUString> SAL_CALL AccessibleCell::getSupportedServiceNames(void) throw (RuntimeException)
502  {
503      ThrowIfDisposed ();
504  
505  	// Get list of supported service names from base class...
506      uno::Sequence<OUString> aServiceNames = AccessibleContextBase::getSupportedServiceNames();
507      sal_Int32 nCount (aServiceNames.getLength());
508  
509      // ...and add additional names.
510      aServiceNames.realloc (nCount + 1);
511      static const OUString sAdditionalServiceName (RTL_CONSTASCII_USTRINGPARAM("com.sun.star.drawing.AccessibleCell"));
512      aServiceNames[nCount] = sAdditionalServiceName;
513  
514      return aServiceNames;
515  }
516  
517  // --------------------------------------------------------------------
518  // IAccessibleViewForwarderListener
519  // --------------------------------------------------------------------
520  
521  void AccessibleCell::ViewForwarderChanged (ChangeType /*aChangeType*/, const IAccessibleViewForwarder* /*pViewForwarder*/)
522  {
523      // Inform all listeners that the graphical representation (i.e. size
524      // and/or position) of the shape has changed.
525      CommitChange(AccessibleEventId::VISIBLE_DATA_CHANGED, Any(), Any());
526  
527      // update our children that our screen position might have changed
528      if( mpText )
529          mpText->UpdateChildren();
530  }
531  
532  // --------------------------------------------------------------------
533  // protected
534  // --------------------------------------------------------------------
535  
536  void AccessibleCell::disposing (void)
537  {
538      ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
539      ::osl::MutexGuard aGuard (maMutex);
540  
541      // Make sure to send an event that this object looses the focus in the
542      // case that it has the focus.
543      ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
544      if (pStateSet != NULL)
545          pStateSet->RemoveState(AccessibleStateType::FOCUSED);
546  
547      if (mpText != NULL)
548      {
549          mpText->Dispose();
550          delete mpText;
551          mpText = NULL;
552      }
553  
554      // Cleanup.  Remove references to objects to allow them to be
555      // destroyed.
556      mxCell.clear();
557      maShapeTreeInfo = AccessibleShapeTreeInfo();
558  
559      // Call base classes.
560      AccessibleContextBase::dispose ();
561  }
562  
563  sal_Int32 SAL_CALL AccessibleCell::getAccessibleIndexInParent (void) throw (RuntimeException)
564  {
565      ThrowIfDisposed ();
566      return mnIndexInParent;
567  }
568  
569  ::rtl::OUString SAL_CALL AccessibleCell::getAccessibleName (void) throw (::com::sun::star::uno::RuntimeException)
570  {
571      ThrowIfDisposed ();
572      ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
573  
574      if( mxCell.is() )
575          return mxCell->getName();
576  
577      return AccessibleCellBase::getAccessibleName();
578  }
579  
580  } // end of namespace accessibility
581