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 #include <svx/AccessibleShape.hxx>
31 #include "svx/DescriptionGenerator.hxx"
32 #include <svx/AccessibleShapeInfo.hxx>
33 #include <com/sun/star/view/XSelectionSupplier.hpp>
34 #include <rtl/uuid.h>
35 #ifndef _COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLE_ROLE_HPP_
36 #include <com/sun/star/accessibility/AccessibleRole.hpp>
37 #endif
38 #ifndef _COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLE_STATE_TYPE_HPP_
39 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
40 #endif
41 #include <com/sun/star/beans/XPropertySet.hpp>
42 #include <com/sun/star/container/XChild.hpp>
43 #include <com/sun/star/drawing/XShapes.hpp>
44 #include <com/sun/star/drawing/XShapeDescriptor.hpp>
45 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
46 #include <com/sun/star/drawing/FillStyle.hpp>
47 #include <com/sun/star/text/XText.hpp>
48 #include <editeng/outlobj.hxx>
49 #include <rtl/ref.hxx>
50 #include <editeng/unoedsrc.hxx>
51 #include <svx/unoshtxt.hxx>
52 #include <svx/svdobj.hxx>
53 #include <svx/svdmodel.hxx>
54 #include "svx/unoapi.hxx"
55 #include <com/sun/star/uno/Exception.hpp>
56 #include <svx/ShapeTypeHandler.hxx>
57 #include <svx/SvxShapeTypes.hxx>
58 
59 #ifndef _SVX_ACCESSIBILITY_HRC
60 #include "accessibility.hrc"
61 #endif
62 #include "svx/svdstr.hrc"
63 #include <svx/dialmgr.hxx>
64 #include <vcl/svapp.hxx>
65 #include <unotools/accessiblestatesethelper.hxx>
66 #include <svx/svdview.hxx>
67 #include "AccessibleEmptyEditSource.hxx"
68 
69 using namespace ::com::sun::star;
70 using namespace	::com::sun::star::accessibility;
71 using ::com::sun::star::uno::Reference;
72 using ::rtl::OUString;
73 
74 namespace accessibility {
75 
76 namespace {
77 
78 OUString GetOptionalProperty (
79     const Reference<beans::XPropertySet>& rxSet,
80     const OUString& rsPropertyName)
81 {
82     OUString sValue;
83 
84     if (rxSet.is())
85     {
86         const Reference<beans::XPropertySetInfo> xInfo (rxSet->getPropertySetInfo());
87         if ( ! xInfo.is() || xInfo->hasPropertyByName(rsPropertyName))
88         {
89             try
90             {
91                 rxSet->getPropertyValue(rsPropertyName) >>= sValue;
92             }
93             catch (beans::UnknownPropertyException&)
94             {
95                 // This exception should only be thrown when the property
96                 // does not exits (of course) and the XPropertySetInfo is
97                 // not available.
98             }
99         }
100     }
101     return sValue;
102 }
103 
104 } // end of anonymous namespace
105 
106 
107 
108 
109 //=====  internal  ============================================================
110 
111 AccessibleShape::AccessibleShape (
112     const AccessibleShapeInfo& rShapeInfo,
113     const AccessibleShapeTreeInfo& rShapeTreeInfo)
114     : AccessibleContextBase (rShapeInfo.mxParent,AccessibleRole::LIST_ITEM),
115       mpChildrenManager(NULL),
116       mxShape (rShapeInfo.mxShape),
117       maShapeTreeInfo (rShapeTreeInfo),
118       mnIndex (rShapeInfo.mnIndex),
119 	  m_nIndexInParent(-1),
120       mpText (NULL),
121       mpParent (rShapeInfo.mpChildrenManager)
122 {
123 	m_pShape = GetSdrObjectFromXShape(mxShape);
124     UpdateNameAndDescription();
125 }
126 
127 
128 
129 
130 AccessibleShape::~AccessibleShape (void)
131 {
132     if (mpChildrenManager != NULL)
133         delete mpChildrenManager;
134     if (mpText != NULL)
135         delete mpText;
136     OSL_TRACE ("~AccessibleShape");
137 
138     // Unregistering from the various broadcasters should be unnecessary
139     // since this destructor would not have been called if one of the
140     // broadcasters would still hold a strong reference to this object.
141 }
142 
143 
144 
145 
146 void AccessibleShape::Init (void)
147 {
148     // Update the OPAQUE and SELECTED shape.
149     UpdateStates ();
150 
151     // Create a children manager when this shape has children of its own.
152     Reference<drawing::XShapes> xShapes (mxShape, uno::UNO_QUERY);
153     if (xShapes.is() && xShapes->getCount() > 0)
154         mpChildrenManager = new ChildrenManager (
155             this, xShapes, maShapeTreeInfo, *this);
156     if (mpChildrenManager != NULL)
157         mpChildrenManager->Update();
158 
159     // Register at model as document::XEventListener.
160     if (maShapeTreeInfo.GetModelBroadcaster().is())
161         maShapeTreeInfo.GetModelBroadcaster()->addEventListener (
162             static_cast<document::XEventListener*>(this));
163 
164     // Beware! Here we leave the paths of the UNO API and descend into the
165     // depths of the core.  Necessary for makeing the edit engine
166     // accessible.
167     Reference<text::XText> xText (mxShape, uno::UNO_QUERY);
168     if (xText.is())
169     {
170         SdrView* pView = maShapeTreeInfo.GetSdrView ();
171         const Window* pWindow = maShapeTreeInfo.GetWindow ();
172         if (pView != NULL && pWindow != NULL && mxShape.is())
173         {
174             // #107948# Determine whether shape text is empty
175             SdrObject* pSdrObject = GetSdrObjectFromXShape(mxShape);
176 			if( pSdrObject )
177 			{
178                 SdrTextObj* pTextObj = PTR_CAST( SdrTextObj, pSdrObject );
179                 OutlinerParaObject* pOutlinerParaObject = NULL;
180 
181                 if( pTextObj )
182                     pOutlinerParaObject = pTextObj->GetEditOutlinerParaObject(); // Get the OutlinerParaObject if text edit is active
183 
184                 bool bOwnParaObj = pOutlinerParaObject != NULL;
185 
186                 if( !pOutlinerParaObject && pSdrObject )
187                     pOutlinerParaObject = pSdrObject->GetOutlinerParaObject();
188 
189                 // create AccessibleTextHelper to handle this shape's text
190                 if( !pOutlinerParaObject )
191                 {
192                     // empty text -> use proxy edit source to delay creation of EditEngine
193                     ::std::auto_ptr<SvxEditSource> pEditSource( new AccessibleEmptyEditSource ( *pSdrObject, *pView, *pWindow) );
194                     mpText = new AccessibleTextHelper( pEditSource );
195                 }
196                 else
197                 {
198                     // non-empty text -> use full-fledged edit source right away
199                     ::std::auto_ptr<SvxEditSource> pEditSource( new SvxTextEditSource ( *pSdrObject, 0, *pView, *pWindow) );
200                     mpText = new AccessibleTextHelper( pEditSource );
201                 }
202 
203                 if( bOwnParaObj )
204                     delete pOutlinerParaObject;
205 
206                 mpText->SetEventSource(this);
207             }
208         }
209     }
210 }
211 
212 
213 
214 
215 void AccessibleShape::UpdateStates (void)
216 {
217     ::utl::AccessibleStateSetHelper* pStateSet =
218         static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
219     if (pStateSet == NULL)
220         return;
221 
222     // Set the opaque state for certain shape types when their fill style is
223     // solid.
224     bool bShapeIsOpaque = false;
225     switch (ShapeTypeHandler::Instance().GetTypeId (mxShape))
226     {
227         case DRAWING_PAGE:
228         case DRAWING_RECTANGLE:
229         case DRAWING_TEXT:
230         {
231             uno::Reference<beans::XPropertySet> xSet (mxShape, uno::UNO_QUERY);
232             if (xSet.is())
233             {
234                 try
235                 {
236 					drawing::FillStyle aFillStyle;
237 					bShapeIsOpaque =  ( xSet->getPropertyValue (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("FillStyle"))) >>= aFillStyle)
238 										&& aFillStyle == drawing::FillStyle_SOLID;
239                 }
240                 catch (::com::sun::star::beans::UnknownPropertyException&)
241                 {
242                     // Ignore.
243                 }
244             }
245         }
246     }
247     if (bShapeIsOpaque)
248         pStateSet->AddState (AccessibleStateType::OPAQUE);
249     else
250         pStateSet->RemoveState (AccessibleStateType::OPAQUE);
251 
252     // Set the selected state.
253     bool bShapeIsSelected = false;
254 	// XXX fix_me this has to be done with an extra interface later on
255 	if ( m_pShape && maShapeTreeInfo.GetSdrView() )
256 	{
257 		bShapeIsSelected = maShapeTreeInfo.GetSdrView()->IsObjMarked(m_pShape) == sal_True;
258 	}
259 
260     if (bShapeIsSelected)
261         pStateSet->AddState (AccessibleStateType::SELECTED);
262     else
263         pStateSet->RemoveState (AccessibleStateType::SELECTED);
264 }
265 
266 
267 
268 
269 bool AccessibleShape::operator== (const AccessibleShape& rShape)
270 {
271     return this==&rShape;
272 }
273 
274 
275 
276 
277 sal_Bool AccessibleShape::SetState (sal_Int16 aState)
278 {
279     sal_Bool bStateHasChanged = sal_False;
280 
281     if (aState == AccessibleStateType::FOCUSED && mpText != NULL)
282     {
283         // Offer FOCUSED state to edit engine and detect whether the state
284         // changes.
285         sal_Bool bIsFocused = mpText->HaveFocus ();
286         mpText->SetFocus (sal_True);
287         bStateHasChanged = (bIsFocused != mpText->HaveFocus ());
288     }
289     else
290         bStateHasChanged = AccessibleContextBase::SetState (aState);
291 
292     return bStateHasChanged;
293 }
294 
295 
296 
297 
298 sal_Bool AccessibleShape::ResetState (sal_Int16 aState)
299 {
300     sal_Bool bStateHasChanged = sal_False;
301 
302     if (aState == AccessibleStateType::FOCUSED && mpText != NULL)
303     {
304         // Try to remove FOCUSED state from the edit engine and detect
305         // whether the state changes.
306         sal_Bool bIsFocused = mpText->HaveFocus ();
307         mpText->SetFocus (sal_False);
308         bStateHasChanged = (bIsFocused != mpText->HaveFocus ());
309     }
310     else
311         bStateHasChanged = AccessibleContextBase::ResetState (aState);
312 
313     return bStateHasChanged;
314 }
315 
316 
317 
318 
319 sal_Bool AccessibleShape::GetState (sal_Int16 aState)
320 {
321     if (aState == AccessibleStateType::FOCUSED && mpText != NULL)
322     {
323         // Just delegate the call to the edit engine.  The state is not
324         // merged into the state set.
325         return mpText->HaveFocus();
326     }
327     else
328         return AccessibleContextBase::GetState (aState);
329 }
330 
331 
332 
333 
334 //=====  XAccessibleContext  ==================================================
335 
336 /** The children of this shape come from two sources: The children from
337     group or scene shapes and the paragraphs of text.
338 */
339 sal_Int32 SAL_CALL
340    	AccessibleShape::getAccessibleChildCount ()
341     throw (::com::sun::star::uno::RuntimeException)
342 {
343     ThrowIfDisposed ();
344     sal_Int32 nChildCount = 0;
345 
346     // Add the number of shapes that are children of this shape.
347     if (mpChildrenManager != NULL)
348         nChildCount += mpChildrenManager->GetChildCount ();
349     // Add the number text paragraphs.
350     if (mpText != NULL)
351         nChildCount += mpText->GetChildCount ();
352 
353     return nChildCount;
354 }
355 
356 
357 
358 
359 /** Forward the request to the shape.  Return the requested shape or throw
360     an exception for a wrong index.
361 */
362 uno::Reference<XAccessible> SAL_CALL
363     AccessibleShape::getAccessibleChild (sal_Int32 nIndex)
364     throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException)
365 {
366     ThrowIfDisposed ();
367 
368     uno::Reference<XAccessible> xChild;
369 
370     // Depending on the index decide whether to delegate this call to the
371     // children manager or the edit engine.
372     if ((mpChildrenManager != NULL)
373         && (nIndex < mpChildrenManager->GetChildCount()))
374     {
375         xChild = mpChildrenManager->GetChild (nIndex);
376     }
377     else if (mpText != NULL)
378     {
379         sal_Int32 nI = nIndex;
380         if (mpChildrenManager != NULL)
381             nI -= mpChildrenManager->GetChildCount();
382         xChild = mpText->GetChild (nI);
383     }
384     else
385         throw lang::IndexOutOfBoundsException (
386             ::rtl::OUString::createFromAscii ("shape has no child with index ")
387             + rtl::OUString::valueOf(nIndex),
388             static_cast<uno::XWeak*>(this));
389 
390     return xChild;
391 }
392 
393 
394 
395 
396 /**	Return a copy of the state set.
397     Possible states are:
398 		ENABLED
399 		SHOWING
400 		VISIBLE
401 */
402 uno::Reference<XAccessibleStateSet> SAL_CALL
403     AccessibleShape::getAccessibleStateSet (void)
404     throw (::com::sun::star::uno::RuntimeException)
405 {
406     ::osl::MutexGuard aGuard (maMutex);
407     Reference<XAccessibleStateSet> xStateSet;
408 
409 	if (rBHelper.bDisposed || mpText == NULL)
410         // Return a minimal state set that only contains the DEFUNC state.
411         xStateSet = AccessibleContextBase::getAccessibleStateSet ();
412     else
413     {
414         ::utl::AccessibleStateSetHelper* pStateSet =
415               static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
416 
417         if (pStateSet != NULL)
418         {
419             // Merge current FOCUSED state from edit engine.
420             if (mpText != NULL)
421             {
422                 if (mpText->HaveFocus())
423                     pStateSet->AddState (AccessibleStateType::FOCUSED);
424                 else
425                     pStateSet->RemoveState (AccessibleStateType::FOCUSED);
426             }
427 
428             // Create a copy of the state set that may be modified by the
429             // caller without affecting the current state set.
430             xStateSet = Reference<XAccessibleStateSet>(
431                 new ::utl::AccessibleStateSetHelper (*pStateSet));
432         }
433     }
434 
435     return xStateSet;
436 }
437 
438 
439 
440 
441 //=====  XAccessibleComponent  ================================================
442 
443 /** The implementation below is at the moment straightforward.  It iterates
444     over all children (and thereby instances all children which have not
445     been already instatiated) until a child covering the specifed point is
446     found.
447     This leaves room for improvement.  For instance, first iterate only over
448     the already instantiated children and only if no match is found
449     instantiate the remaining ones.
450 */
451 uno::Reference<XAccessible > SAL_CALL
452     AccessibleShape::getAccessibleAtPoint (
453         const awt::Point& aPoint)
454     throw (uno::RuntimeException)
455 {
456     ::osl::MutexGuard aGuard (maMutex);
457 
458     sal_Int32 nChildCount = getAccessibleChildCount ();
459     for (sal_Int32 i=0; i<nChildCount; ++i)
460     {
461         Reference<XAccessible> xChild (getAccessibleChild (i));
462         if (xChild.is())
463         {
464             Reference<XAccessibleComponent> xChildComponent (
465                 xChild->getAccessibleContext(), uno::UNO_QUERY);
466             if (xChildComponent.is())
467             {
468                 awt::Rectangle aBBox (xChildComponent->getBounds());
469                 if ( (aPoint.X >= aBBox.X)
470                     && (aPoint.Y >= aBBox.Y)
471                     && (aPoint.X < aBBox.X+aBBox.Width)
472                     && (aPoint.Y < aBBox.Y+aBBox.Height) )
473                     return xChild;
474             }
475         }
476     }
477 
478     // Have not found a child under the given point.  Returning empty
479     // reference to indicate this.
480     return uno::Reference<XAccessible>();
481 }
482 
483 
484 
485 
486 awt::Rectangle SAL_CALL AccessibleShape::getBounds (void)
487     throw (::com::sun::star::uno::RuntimeException)
488 {
489     ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
490     ::osl::MutexGuard aGuard (maMutex);
491 
492     ThrowIfDisposed ();
493 	awt::Rectangle aBoundingBox;
494 	if ( mxShape.is() )
495 	{
496 
497 		static const OUString sBoundRectName (
498 			RTL_CONSTASCII_USTRINGPARAM("BoundRect"));
499 		static const OUString sAnchorPositionName (
500 			RTL_CONSTASCII_USTRINGPARAM("AnchorPosition"));
501 
502 		// Get the shape's bounding box in internal coordinates (in 100th of
503 		// mm).  Use the property BoundRect.  Only if that is not supported ask
504 		// the shape for its position and size directly.
505 		Reference<beans::XPropertySet> xSet (mxShape, uno::UNO_QUERY);
506 		Reference<beans::XPropertySetInfo> xSetInfo;
507 		bool bFoundBoundRect = false;
508 		if (xSet.is())
509 		{
510 			xSetInfo = xSet->getPropertySetInfo ();
511 			if (xSetInfo.is())
512 			{
513 				if (xSetInfo->hasPropertyByName (sBoundRectName))
514 				{
515 					try
516 					{
517 						uno::Any aValue = xSet->getPropertyValue (sBoundRectName);
518 						aValue >>= aBoundingBox;
519 						bFoundBoundRect = true;
520 					}
521 					catch (beans::UnknownPropertyException e)
522 					{
523 						// Handled below (bFoundBoundRect stays false).
524 					}
525 				}
526 				else
527 					OSL_TRACE (" no property BoundRect");
528 			}
529 		}
530 
531 		// Fallback when there is no BoundRect Property.
532 		if ( ! bFoundBoundRect )
533 		{
534 			awt::Point aPosition (mxShape->getPosition());
535 			awt::Size aSize (mxShape->getSize());
536 			aBoundingBox = awt::Rectangle (
537 				aPosition.X, aPosition.Y,
538 				aSize.Width, aSize.Height);
539 
540 			// While BoundRects have absolute positions, the position returned
541 			// by XPosition::getPosition is relative.  Get the anchor position
542 			// (usually not (0,0) for Writer shapes).
543 			if (xSetInfo.is())
544 			{
545 				if (xSetInfo->hasPropertyByName (sAnchorPositionName))
546 				{
547 					uno::Any aPos = xSet->getPropertyValue (sAnchorPositionName);
548 					awt::Point aAnchorPosition;
549 					aPos >>= aAnchorPosition;
550 					aBoundingBox.X += aAnchorPosition.X;
551 					aBoundingBox.Y += aAnchorPosition.Y;
552 				}
553 			}
554 		}
555 
556 		// Transform coordinates from internal to pixel.
557 		if (maShapeTreeInfo.GetViewForwarder() == NULL)
558 			throw uno::RuntimeException (::rtl::OUString (
559 				RTL_CONSTASCII_USTRINGPARAM(
560 					"AccessibleShape has no valid view forwarder")),
561 				static_cast<uno::XWeak*>(this));
562 		::Size aPixelSize = maShapeTreeInfo.GetViewForwarder()->LogicToPixel (
563 			::Size (aBoundingBox.Width, aBoundingBox.Height));
564 		::Point aPixelPosition = maShapeTreeInfo.GetViewForwarder()->LogicToPixel (
565 			::Point (aBoundingBox.X, aBoundingBox.Y));
566 
567 		// Clip the shape's bounding box with the bounding box of its parent.
568 		Reference<XAccessibleComponent> xParentComponent (
569 			getAccessibleParent(), uno::UNO_QUERY);
570 		if (xParentComponent.is())
571 		{
572 			// Make the coordinates relative to the parent.
573 			awt::Point aParentLocation (xParentComponent->getLocationOnScreen());
574 			int x = aPixelPosition.getX() - aParentLocation.X;
575 			int y = aPixelPosition.getY() - aParentLocation.Y;
576 
577 			/*        //  The following block is a workarround for bug #99889# (property
578 			//  BoundRect returnes coordinates relative to document window
579 			//  instead of absolute coordinates for shapes in Writer).  Has to
580 			//  be removed as soon as bug is fixed.
581 
582 			// Use a non-null anchor position as flag that the shape is in a
583 			// Writer document.
584 			if (xSetInfo.is())
585 				if (xSetInfo->hasPropertyByName (sAnchorPositionName))
586 				{
587 					uno::Any aPos = xSet->getPropertyValue (sAnchorPositionName);
588 					awt::Point aAnchorPosition;
589 					aPos >>= aAnchorPosition;
590 					if (aAnchorPosition.X > 0)
591 					{
592 						x = aPixelPosition.getX();
593 						y = aPixelPosition.getY();
594 					}
595 				}
596 			//  End of workarround.
597 			*/
598 			// Clip with parent (with coordinates relative to itself).
599 			::Rectangle aBBox (
600 				x, y, x + aPixelSize.getWidth(), y + aPixelSize.getHeight());
601 			awt::Size aParentSize (xParentComponent->getSize());
602 			::Rectangle aParentBBox (0,0, aParentSize.Width, aParentSize.Height);
603 			aBBox = aBBox.GetIntersection (aParentBBox);
604 			aBoundingBox = awt::Rectangle (
605 				aBBox.getX(),
606 				aBBox.getY(),
607 				aBBox.getWidth(),
608 				aBBox.getHeight());
609 		}
610 		else
611 		{
612 			OSL_TRACE ("parent does not support component");
613 			aBoundingBox = awt::Rectangle (
614 				aPixelPosition.getX(), aPixelPosition.getY(),
615 				aPixelSize.getWidth(), aPixelSize.getHeight());
616 		}
617 	}
618 
619     return aBoundingBox;
620 }
621 
622 
623 
624 
625 awt::Point SAL_CALL AccessibleShape::getLocation (void)
626     throw (::com::sun::star::uno::RuntimeException)
627 {
628     ThrowIfDisposed ();
629     awt::Rectangle aBoundingBox (getBounds());
630     return awt::Point (aBoundingBox.X, aBoundingBox.Y);
631 }
632 
633 
634 
635 
636 awt::Point SAL_CALL AccessibleShape::getLocationOnScreen (void)
637     throw (::com::sun::star::uno::RuntimeException)
638 {
639     ThrowIfDisposed ();
640 
641     // Get relative position...
642     awt::Point aLocation (getLocation ());
643 
644     // ... and add absolute position of the parent.
645     uno::Reference<XAccessibleComponent> xParentComponent (
646         getAccessibleParent(), uno::UNO_QUERY);
647     if (xParentComponent.is())
648     {
649         awt::Point aParentLocation (xParentComponent->getLocationOnScreen());
650         aLocation.X += aParentLocation.X;
651         aLocation.Y += aParentLocation.Y;
652     }
653     else
654         OSL_TRACE ("getLocation: parent does not support XAccessibleComponent");
655     return aLocation;
656 }
657 
658 
659 
660 
661 awt::Size SAL_CALL AccessibleShape::getSize (void)
662     throw (uno::RuntimeException)
663 {
664     ThrowIfDisposed ();
665     awt::Rectangle aBoundingBox (getBounds());
666     return awt::Size (aBoundingBox.Width, aBoundingBox.Height);
667 }
668 
669 
670 
671 
672 sal_Int32 SAL_CALL AccessibleShape::getForeground (void)
673     throw (::com::sun::star::uno::RuntimeException)
674 {
675     ThrowIfDisposed ();
676     sal_Int32 nColor (0x0ffffffL);
677 
678     try
679     {
680         uno::Reference<beans::XPropertySet> aSet (mxShape, uno::UNO_QUERY);
681         if (aSet.is())
682         {
683             uno::Any aColor;
684             aColor = aSet->getPropertyValue (OUString::createFromAscii ("LineColor"));
685             aColor >>= nColor;
686         }
687     }
688     catch (::com::sun::star::beans::UnknownPropertyException)
689     {
690         // Ignore exception and return default color.
691     }
692     return nColor;
693 }
694 
695 
696 
697 
698 sal_Int32 SAL_CALL AccessibleShape::getBackground (void)
699     throw (::com::sun::star::uno::RuntimeException)
700 {
701     ThrowIfDisposed ();
702     sal_Int32 nColor (0L);
703 
704     try
705     {
706         uno::Reference<beans::XPropertySet> aSet (mxShape, uno::UNO_QUERY);
707         if (aSet.is())
708         {
709             uno::Any aColor;
710             aColor = aSet->getPropertyValue (OUString::createFromAscii ("FillColor"));
711             aColor >>= nColor;
712         }
713     }
714     catch (::com::sun::star::beans::UnknownPropertyException)
715     {
716         // Ignore exception and return default color.
717     }
718     return nColor;
719 }
720 
721 
722 
723 
724 //=====  XAccessibleEventBroadcaster  =========================================
725 
726 void SAL_CALL AccessibleShape::addEventListener (
727     const Reference<XAccessibleEventListener >& rxListener)
728     throw (uno::RuntimeException)
729 {
730 	if (rBHelper.bDisposed || rBHelper.bInDispose)
731 	{
732         uno::Reference<uno::XInterface> xThis (
733             (lang::XComponent *)this, uno::UNO_QUERY);
734 		rxListener->disposing (lang::EventObject (xThis));
735 	}
736     else
737     {
738         AccessibleContextBase::addEventListener (rxListener);
739         if (mpText != NULL)
740             mpText->AddEventListener (rxListener);
741     }
742 }
743 
744 
745 
746 
747 void SAL_CALL AccessibleShape::removeEventListener (
748     const Reference<XAccessibleEventListener >& rxListener)
749     throw (uno::RuntimeException)
750 {
751     AccessibleContextBase::removeEventListener (rxListener);
752     if (mpText != NULL)
753         mpText->RemoveEventListener (rxListener);
754 }
755 
756 
757 
758 
759 //=====  XInterface  ==========================================================
760 
761 com::sun::star::uno::Any SAL_CALL
762     AccessibleShape::queryInterface (const com::sun::star::uno::Type & rType)
763     throw (::com::sun::star::uno::RuntimeException)
764 {
765     ::com::sun::star::uno::Any aReturn = AccessibleContextBase::queryInterface (rType);
766     if ( ! aReturn.hasValue())
767         aReturn = ::cppu::queryInterface (rType,
768             static_cast<XAccessibleComponent*>(this),
769             static_cast<XAccessibleExtendedComponent*>(this),
770             static_cast<lang::XEventListener*>(this),
771             static_cast<document::XEventListener*>(this),
772             static_cast<lang::XUnoTunnel*>(this)
773             );
774     return aReturn;
775 }
776 
777 
778 
779 
780 void SAL_CALL
781     AccessibleShape::acquire (void)
782     throw ()
783 {
784     AccessibleContextBase::acquire ();
785 }
786 
787 
788 
789 
790 void SAL_CALL
791     AccessibleShape::release (void)
792     throw ()
793 {
794     AccessibleContextBase::release ();
795 }
796 
797 
798 
799 
800 //=====  XServiceInfo  ========================================================
801 
802 ::rtl::OUString SAL_CALL
803     AccessibleShape::getImplementationName (void)
804     throw (::com::sun::star::uno::RuntimeException)
805 {
806 	return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleShape"));
807 }
808 
809 
810 
811 
812 uno::Sequence<OUString> SAL_CALL
813     AccessibleShape::getSupportedServiceNames (void)
814     throw (::com::sun::star::uno::RuntimeException)
815 {
816     ThrowIfDisposed ();
817     // Get list of supported service names from base class...
818     uno::Sequence<OUString> aServiceNames =
819         AccessibleContextBase::getSupportedServiceNames();
820     sal_Int32 nCount (aServiceNames.getLength());
821 
822     // ...and add additional names.
823     aServiceNames.realloc (nCount + 1);
824     static const OUString sAdditionalServiceName (RTL_CONSTASCII_USTRINGPARAM(
825         "com.sun.star.drawing.AccessibleShape"));
826     aServiceNames[nCount] = sAdditionalServiceName;
827 
828     return aServiceNames;
829 }
830 
831 
832 
833 
834 
835 //=====  XTypeProvider  ===================================================
836 
837 uno::Sequence<uno::Type> SAL_CALL
838     AccessibleShape::getTypes (void)
839     throw (uno::RuntimeException)
840 {
841     ThrowIfDisposed ();
842     // Get list of types from the context base implementation, ...
843 	uno::Sequence<uno::Type> aTypeList (AccessibleContextBase::getTypes());
844     // ... get list of types from component base implementation, ...
845 	uno::Sequence<uno::Type> aComponentTypeList (AccessibleComponentBase::getTypes());
846     // ... define local types, ...
847     const uno::Type aLangEventListenerType =
848     	::getCppuType((const uno::Reference<lang::XEventListener>*)0);
849     const uno::Type aDocumentEventListenerType =
850     	::getCppuType((const uno::Reference<document::XEventListener>*)0);
851     const uno::Type aUnoTunnelType =
852     	::getCppuType((const uno::Reference<lang::XUnoTunnel>*)0);
853     //    const uno::Type aStateSetType =
854     //    	::getCppuType((const uno::Reference<XAccessibleStateSet>*)0);
855 
856     // ... and merge them all into one list.
857     sal_Int32   nTypeCount (aTypeList.getLength()),
858         nComponentTypeCount (aComponentTypeList.getLength());
859     int         i;
860 
861     aTypeList.realloc (nTypeCount + nComponentTypeCount + 3);
862 
863     for (i=0; i<nComponentTypeCount; i++)
864         aTypeList[nTypeCount + i] = aComponentTypeList[i];
865 
866     aTypeList[nTypeCount + i++ ] = aLangEventListenerType;
867     aTypeList[nTypeCount + i++ ] = aDocumentEventListenerType;
868     aTypeList[nTypeCount + i ] = aUnoTunnelType;
869 
870 	return aTypeList;
871 }
872 
873 
874 
875 
876 //=====  lang::XEventListener  ================================================
877 
878 /** Disposing calls are accepted only from the model: Just reset the
879     reference to the model in the shape tree info.  Otherwise this object
880     remains functional.
881 */
882 void SAL_CALL
883     AccessibleShape::disposing (const lang::EventObject& aEvent)
884     throw (uno::RuntimeException)
885 {
886     ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
887     ::osl::MutexGuard aGuard (maMutex);
888 
889     try
890     {
891         if (aEvent.Source ==  maShapeTreeInfo.GetModelBroadcaster())
892         {
893             // Remove reference to model broadcaster to allow it to pass
894             // away.
895             maShapeTreeInfo.SetModelBroadcaster(NULL);
896         }
897 
898     }
899     catch (uno::RuntimeException e)
900     {
901         OSL_TRACE ("caught exception while disposing");
902     }
903 }
904 
905 
906 
907 
908 //=====  document::XEventListener  ============================================
909 
910 void SAL_CALL
911     AccessibleShape::notifyEvent (const document::EventObject& rEventObject)
912     throw (uno::RuntimeException)
913 {
914 	static const OUString sShapeModified (
915 		RTL_CONSTASCII_USTRINGPARAM("ShapeModified"));
916 
917     // First check if the event is for us.
918     uno::Reference<drawing::XShape> xShape (
919         rEventObject.Source, uno::UNO_QUERY);
920     if ( xShape.get() == mxShape.get() )
921     {
922         if (rEventObject.EventName.equals (sShapeModified))
923         {
924             // Some property of a shape has been modified.  Send an event
925             // that indicates a change of the visible data to all listeners.
926             CommitChange (
927                 AccessibleEventId::VISIBLE_DATA_CHANGED,
928                 uno::Any(),
929                 uno::Any());
930 
931             // Name and Description may have changed.  Update the local
932             // values accordingly.
933             UpdateNameAndDescription();
934         }
935     }
936 }
937 
938 
939 
940 
941 //=====  lang::XUnoTunnel  ================================================
942 
943 const uno::Sequence< sal_Int8 >&
944     AccessibleShape::getUnoTunnelImplementationId()
945     throw()
946 {
947 	static uno::Sequence< sal_Int8 >* pSeq = 0;
948 
949     if( !pSeq )
950 	{
951 		::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
952 
953         if( !pSeq )
954 		{
955 			static uno::Sequence< sal_Int8 > aSeq( 16 );
956 			rtl_createUuid( (sal_uInt8*) aSeq.getArray(), 0, sal_True );
957 			pSeq = &aSeq;
958 		}
959 	}
960 
961     return( *pSeq );
962 }
963 
964 //------------------------------------------------------------------------------
965 AccessibleShape*
966     AccessibleShape::getImplementation( const uno::Reference< uno::XInterface >& rxIFace )
967     throw()
968 {
969     uno::Reference< lang::XUnoTunnel >  xTunnel( rxIFace, uno::UNO_QUERY );
970 	AccessibleShape*                    pReturn = NULL;
971 
972     if( xTunnel.is() )
973 		pReturn = reinterpret_cast< AccessibleShape* >( xTunnel->getSomething( getUnoTunnelImplementationId() ) );
974 
975 	return( pReturn );
976 }
977 
978 //------------------------------------------------------------------------------
979 sal_Int64 SAL_CALL
980     AccessibleShape::getSomething( const uno::Sequence< sal_Int8 >& rIdentifier )
981     throw(uno::RuntimeException)
982 {
983 	sal_Int64 nReturn( 0 );
984 
985 	if(	( rIdentifier.getLength() == 16 ) && ( 0 == rtl_compareMemory( getUnoTunnelImplementationId().getConstArray(), rIdentifier.getConstArray(), 16 ) ) )
986 		nReturn = reinterpret_cast< sal_Int64 >( this );
987 
988 	return( nReturn );
989 }
990 
991 //=====  IAccessibleViewForwarderListener  ====================================
992 
993 void AccessibleShape::ViewForwarderChanged (ChangeType aChangeType,
994         const IAccessibleViewForwarder* pViewForwarder)
995 {
996     // Inform all listeners that the graphical representation (i.e. size
997     // and/or position) of the shape has changed.
998     CommitChange (AccessibleEventId::VISIBLE_DATA_CHANGED,
999         uno::Any(),
1000         uno::Any());
1001 
1002     // Tell children manager of the modified view forwarder.
1003     if (mpChildrenManager != NULL)
1004         mpChildrenManager->ViewForwarderChanged (aChangeType, pViewForwarder);
1005 
1006     // update our children that our screen position might have changed
1007     if( mpText )
1008         mpText->UpdateChildren();
1009 }
1010 
1011 
1012 
1013 
1014 //=====  protected internal  ==================================================
1015 ///	Set this object's name if is different to the current name.
1016 ::rtl::OUString
1017     AccessibleShape::CreateAccessibleBaseName (void)
1018     throw (::com::sun::star::uno::RuntimeException)
1019 {
1020 	return ShapeTypeHandler::CreateAccessibleBaseName( mxShape );
1021 }
1022 
1023 
1024 ::rtl::OUString
1025     AccessibleShape::CreateAccessibleName (void)
1026     throw (::com::sun::star::uno::RuntimeException)
1027 {
1028     OUString sName (CreateAccessibleBaseName());
1029 
1030     // Append the shape's index to the name to disambiguate between shapes
1031     // of the same type.  If such an index where not given to the
1032     // constructor then use the z-order instead.  If even that does not exist
1033     // we throw an exception.
1034     long nIndex = mnIndex;
1035     if (nIndex == -1)
1036     {
1037         try
1038         {
1039             uno::Reference<beans::XPropertySet> xSet (mxShape, uno::UNO_QUERY);
1040             if (xSet.is())
1041             {
1042                 uno::Any aZOrder (xSet->getPropertyValue (::rtl::OUString::createFromAscii ("ZOrder")));
1043                 aZOrder >>= nIndex;
1044 
1045                 // Add one to be not zero based.
1046                 nIndex += 1;
1047             }
1048         }
1049         catch (beans::UnknownPropertyException)
1050         {
1051             // We throw our own exception that is a bit more informative.
1052             throw uno::RuntimeException (::rtl::OUString (
1053                 RTL_CONSTASCII_USTRINGPARAM("AccessibleShape has invalid index and no ZOrder property")),
1054                 static_cast<uno::XWeak*>(this));
1055         }
1056 
1057     }
1058 
1059     // Put a space between name and index because of Gnopernicus othewise
1060     // spells the name.
1061     sName += OUString (RTL_CONSTASCII_USTRINGPARAM(" ")) + OUString::valueOf (nIndex);
1062 
1063     return sName;
1064 }
1065 
1066 
1067 
1068 
1069 ::rtl::OUString
1070     AccessibleShape::CreateAccessibleDescription (void)
1071     throw (::com::sun::star::uno::RuntimeException)
1072 {
1073     DescriptionGenerator aDG (mxShape);
1074     aDG.Initialize (CreateAccessibleBaseName());
1075     switch (ShapeTypeHandler::Instance().GetTypeId (mxShape))
1076     {
1077         case DRAWING_3D_CUBE:
1078         case DRAWING_3D_EXTRUDE:
1079         case DRAWING_3D_LATHE:
1080         case DRAWING_3D_SPHERE:
1081             aDG.Add3DProperties ();
1082             break;
1083 
1084         case DRAWING_3D_SCENE:
1085         case DRAWING_GROUP:
1086         case DRAWING_PAGE:
1087             // No further information is appended.
1088             break;
1089 
1090         case DRAWING_CAPTION:
1091         case DRAWING_CLOSED_BEZIER:
1092         case DRAWING_CLOSED_FREEHAND:
1093         case DRAWING_ELLIPSE:
1094         case DRAWING_POLY_POLYGON:
1095         case DRAWING_POLY_POLYGON_PATH:
1096         case DRAWING_RECTANGLE:
1097             aDG.AddLineProperties ();
1098             aDG.AddFillProperties ();
1099             break;
1100 
1101         case DRAWING_CONNECTOR:
1102         case DRAWING_LINE:
1103         case DRAWING_MEASURE:
1104         case DRAWING_OPEN_BEZIER:
1105         case DRAWING_OPEN_FREEHAND:
1106         case DRAWING_POLY_LINE:
1107         case DRAWING_POLY_LINE_PATH:
1108             aDG.AddLineProperties ();
1109             break;
1110 
1111         case DRAWING_CONTROL:
1112             aDG.AddProperty (OUString::createFromAscii ("ControlBackground"),
1113                 DescriptionGenerator::COLOR,
1114                 OUString());
1115             aDG.AddProperty (OUString::createFromAscii ("ControlBorder"),
1116                 DescriptionGenerator::INTEGER,
1117                 OUString());
1118             break;
1119 
1120         case DRAWING_TEXT:
1121             aDG.AddTextProperties ();
1122             break;
1123 
1124         default:
1125             aDG.Initialize (::rtl::OUString (
1126                                 RTL_CONSTASCII_USTRINGPARAM("Unknown accessible shape")));
1127             uno::Reference<drawing::XShapeDescriptor> xDescriptor (mxShape, uno::UNO_QUERY);
1128             if (xDescriptor.is())
1129             {
1130                 aDG.AppendString (::rtl::OUString (RTL_CONSTASCII_USTRINGPARAM("service name=")));
1131                 aDG.AppendString (xDescriptor->getShapeType());
1132             }
1133     }
1134 
1135     return aDG();
1136 }
1137 
1138 
1139 
1140 
1141 uno::Reference< drawing::XShape > AccessibleShape::GetXShape()
1142 {
1143     return( mxShape );
1144 }
1145 
1146 
1147 
1148 // protected
1149 void AccessibleShape::disposing (void)
1150 {
1151     ::vos::OGuard aSolarGuard (::Application::GetSolarMutex());
1152     ::osl::MutexGuard aGuard (maMutex);
1153 
1154     // Make sure to send an event that this object looses the focus in the
1155     // case that it has the focus.
1156     ::utl::AccessibleStateSetHelper* pStateSet =
1157           static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
1158     if (pStateSet != NULL)
1159         pStateSet->RemoveState (AccessibleStateType::FOCUSED);
1160 
1161     // Unregister from broadcasters.
1162     Reference<lang::XComponent> xComponent (mxShape, uno::UNO_QUERY);
1163     if (xComponent.is())
1164         xComponent->removeEventListener (this);
1165 
1166     // Unregister from model.
1167     if (maShapeTreeInfo.GetModelBroadcaster().is())
1168         maShapeTreeInfo.GetModelBroadcaster()->removeEventListener (
1169             static_cast<document::XEventListener*>(this));
1170 
1171     // Release the child containers.
1172     if (mpChildrenManager != NULL)
1173     {
1174         delete mpChildrenManager;
1175         mpChildrenManager = NULL;
1176     }
1177     if (mpText != NULL)
1178     {
1179         mpText->Dispose();
1180         delete mpText;
1181         mpText = NULL;
1182     }
1183 
1184     // Cleanup.  Remove references to objects to allow them to be
1185     // destroyed.
1186     mxShape = NULL;
1187     maShapeTreeInfo = AccessibleShapeTreeInfo();
1188 
1189     // Call base classes.
1190     AccessibleContextBase::dispose ();
1191 }
1192 
1193 sal_Int32 SAL_CALL
1194    	AccessibleShape::getAccessibleIndexInParent (void)
1195     throw (::com::sun::star::uno::RuntimeException)
1196 {
1197     ThrowIfDisposed ();
1198 	//	Use a simple but slow solution for now.  Optimize later.
1199 
1200 	sal_Int32 nIndex = m_nIndexInParent;
1201 	if ( -1 == nIndex )
1202 		nIndex = AccessibleContextBase::getAccessibleIndexInParent();
1203     return nIndex;
1204 }
1205 
1206 
1207 
1208 
1209 void AccessibleShape::UpdateNameAndDescription (void)
1210 {
1211     // Ignore missing title, name, or description.  There are fallbacks for
1212     // them.
1213     try
1214     {
1215         Reference<beans::XPropertySet> xSet (mxShape, uno::UNO_QUERY_THROW);
1216         OUString sString;
1217 
1218         // Get the accessible name.
1219         sString = GetOptionalProperty(xSet, OUString(RTL_CONSTASCII_USTRINGPARAM("Title")));
1220         if (sString.getLength() > 0)
1221         {
1222             SetAccessibleName(sString, AccessibleContextBase::FromShape);
1223         }
1224         else
1225         {
1226             sString = GetOptionalProperty(xSet, OUString(RTL_CONSTASCII_USTRINGPARAM("Name")));
1227             if (sString.getLength() > 0)
1228                 SetAccessibleName(sString, AccessibleContextBase::FromShape);
1229         }
1230 
1231         // Get the accessible description.
1232         sString = GetOptionalProperty(xSet, OUString(RTL_CONSTASCII_USTRINGPARAM("Description")));
1233         if (sString.getLength() > 0)
1234             SetAccessibleDescription(sString, AccessibleContextBase::FromShape);
1235     }
1236     catch (uno::RuntimeException&)
1237     {
1238     }
1239 }
1240 
1241 
1242 
1243 
1244 } // end of namespace accessibility
1245