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