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