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_chart2.hxx"
30 
31 #include "AccessibleBase.hxx"
32 #include "AccessibleChartShape.hxx"
33 #include "ObjectHierarchy.hxx"
34 #include "ObjectIdentifier.hxx"
35 #include "chartview/ExplicitValueProvider.hxx"
36 #include "macros.hxx"
37 
38 #include <com/sun/star/awt/XDevice.hpp>
39 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
40 #include <com/sun/star/accessibility/AccessibleEventObject.hpp>
41 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
42 #include <com/sun/star/accessibility/AccessibleRole.hpp>
43 #include <comphelper/serviceinfohelper.hxx>
44 #include <com/sun/star/drawing/LineStyle.hpp>
45 #include <com/sun/star/drawing/FillStyle.hpp>
46 #include <rtl/ustrbuf.hxx>
47 // for SolarMutex
48 #include <vcl/svapp.hxx>
49 #include <rtl/uuid.h>
50 #include <cppuhelper/queryinterface.hxx>
51 #include <svl/itemset.hxx>
52 #include <editeng/unofdesc.hxx>
53 #include <editeng/outliner.hxx>
54 #include <svx/svdoutl.hxx>
55 #include <svx/svdetc.hxx>
56 #include <svx/unoshape.hxx>
57 #include <svx/unoprov.hxx>
58 #include <vcl/unohelp.hxx>
59 #include <toolkit/helper/vclunohelper.hxx>
60 #include <vcl/window.hxx>
61 
62 #include <algorithm>
63 
64 #include "ChartElementFactory.hxx"
65 
66 using namespace ::com::sun::star;
67 using namespace ::com::sun::star::accessibility;
68 
69 using ::com::sun::star::uno::UNO_QUERY;
70 using ::rtl::OUString;
71 using ::rtl::OUStringBuffer;
72 using ::com::sun::star::uno::Reference;
73 using ::osl::MutexGuard;
74 using ::osl::ClearableMutexGuard;
75 using ::osl::ResettableMutexGuard;
76 using ::com::sun::star::uno::RuntimeException;
77 using ::com::sun::star::uno::Any;
78 
79 namespace chart
80 {
81 
82 /** @param bMayHaveChildren is false per default
83  */
84 AccessibleBase::AccessibleBase(
85     const AccessibleElementInfo & rAccInfo,
86     bool bMayHaveChildren,
87     bool bAlwaysTransparent /* default: false */ ) :
88         impl::AccessibleBase_Base( m_aMutex ),
89         m_bIsDisposed( false ),
90         m_bMayHaveChildren( bMayHaveChildren ),
91         m_bChildrenInitialized( false ),
92         m_nEventNotifierId(0),
93         m_pStateSetHelper( new ::utl::AccessibleStateSetHelper() ),
94         m_aStateSet( m_pStateSetHelper ),
95         m_aAccInfo( rAccInfo ),
96         m_bAlwaysTransparent( bAlwaysTransparent ),
97         m_bStateSetInitialized( false )
98 {
99     // initialize some states
100     OSL_ASSERT( m_pStateSetHelper );
101     m_pStateSetHelper->AddState( AccessibleStateType::ENABLED );
102     m_pStateSetHelper->AddState( AccessibleStateType::SHOWING );
103     m_pStateSetHelper->AddState( AccessibleStateType::VISIBLE );
104     m_pStateSetHelper->AddState( AccessibleStateType::SELECTABLE );
105     m_pStateSetHelper->AddState( AccessibleStateType::FOCUSABLE );
106 }
107 
108 AccessibleBase::~AccessibleBase()
109 {
110     OSL_ASSERT( m_bIsDisposed );
111 }
112 
113 // ________ public ________
114 
115 bool AccessibleBase::CheckDisposeState( bool bThrowException /* default: true */ ) const
116     throw (lang::DisposedException)
117 {
118     if( bThrowException &&
119         m_bIsDisposed )
120     {
121         throw lang::DisposedException(
122             C2U("component has state DEFUNC" ),
123             static_cast< uno::XWeak * >( const_cast< AccessibleBase * >( this )));
124     }
125     return m_bIsDisposed;
126 }
127 
128 bool AccessibleBase::NotifyEvent( EventType eEventType, const AccessibleUniqueId & rId )
129 {
130     if( GetId() == rId )
131     {
132         // event is addressed to this object
133 
134         ::com::sun::star::uno::Any aEmpty;
135         ::com::sun::star::uno::Any aSelected;
136         aSelected <<= AccessibleStateType::SELECTED;
137         switch( eEventType )
138         {
139             case OBJECT_CHANGE:
140                 {
141                     BroadcastAccEvent( AccessibleEventId::VISIBLE_DATA_CHANGED, aEmpty, aEmpty );
142 #if OSL_DEBUG_LEVEL > 1
143                     OSL_TRACE(
144                         ::rtl::OUStringToOString(
145                             OUString( RTL_CONSTASCII_USTRINGPARAM(
146                                           "Visible data event sent by: " )) +
147                             getAccessibleName(),
148                             RTL_TEXTENCODING_ASCII_US ).getStr() );
149 #endif
150                 }
151                 break;
152 
153             case GOT_SELECTION:
154                 {
155                     AddState( AccessibleStateType::SELECTED );
156                     BroadcastAccEvent( AccessibleEventId::STATE_CHANGED, aSelected, aEmpty );
157 
158                     AddState( AccessibleStateType::FOCUSED );
159                     aSelected <<= AccessibleStateType::FOCUSED;
160                     BroadcastAccEvent( AccessibleEventId::STATE_CHANGED, aSelected, aEmpty, true );
161 #if OSL_DEBUG_LEVEL > 1
162                     OSL_TRACE(
163                         ::rtl::OUStringToOString(
164                             OUString( RTL_CONSTASCII_USTRINGPARAM(
165                                           "Selection acquired by: " )) +
166                             getAccessibleName(),
167                             RTL_TEXTENCODING_ASCII_US ).getStr() );
168 #endif
169                 }
170                 break;
171 
172             case LOST_SELECTION:
173                 {
174                     RemoveState( AccessibleStateType::SELECTED );
175                     BroadcastAccEvent( AccessibleEventId::STATE_CHANGED, aEmpty, aSelected );
176 
177                     AddState( AccessibleStateType::FOCUSED );
178                     aSelected <<= AccessibleStateType::FOCUSED;
179                     BroadcastAccEvent( AccessibleEventId::STATE_CHANGED, aEmpty, aSelected, true );
180 #if OSL_DEBUG_LEVEL > 1
181                     OSL_TRACE(
182                         ::rtl::OUStringToOString(
183                             OUString( RTL_CONSTASCII_USTRINGPARAM(
184                                           "Selection lost by: " )) +
185                             getAccessibleName(),
186                             RTL_TEXTENCODING_ASCII_US ).getStr() );
187 #endif
188                 }
189                 break;
190 
191             case PROPERTY_CHANGE:
192                 {
193                     //not implemented --> rebuild all
194                 }
195                 break;
196         }
197         return true;
198     }
199     else if( m_bMayHaveChildren )
200     {
201         bool bStop = false;
202         // /--
203         ClearableMutexGuard aGuard( GetMutex() );
204         // make local copy for notification
205         ChildListVectorType aLocalChildList( m_aChildList );
206         aGuard.clear();
207         // \--
208 
209         ChildListVectorType::iterator aEndIter = aLocalChildList.end();
210         for( ChildListVectorType::iterator aIter = aLocalChildList.begin() ;
211              ( aIter != aEndIter ) && ( ! bStop ) ;
212              ++aIter )
213         {
214             // Note: at this place we must be sure to have an AccessibleBase
215             // object in the UNO reference to XAccessible !
216             bStop = (*static_cast< AccessibleBase * >
217                      ( (*aIter).get() )).NotifyEvent( eEventType, rId );
218         }
219         return bStop;
220     }
221 
222     return false;
223 }
224 
225 void AccessibleBase::AddState( sal_Int16 aState )
226     throw (RuntimeException)
227 {
228     CheckDisposeState();
229     OSL_ASSERT( m_pStateSetHelper );
230     m_pStateSetHelper->AddState( aState );
231 }
232 
233 void AccessibleBase::RemoveState( sal_Int16 aState )
234     throw (RuntimeException)
235 {
236     CheckDisposeState();
237     OSL_ASSERT( m_pStateSetHelper );
238     m_pStateSetHelper->RemoveState( aState );
239 }
240 
241 // ________ protected ________
242 
243 bool AccessibleBase::UpdateChildren()
244 {
245     bool bMustUpdateChildren = false;
246     {
247         // /--
248         MutexGuard aGuard( GetMutex() );
249         if( ! m_bMayHaveChildren ||
250             m_bIsDisposed )
251             return false;
252 
253         bMustUpdateChildren = ( m_bMayHaveChildren &&
254                                 ! m_bChildrenInitialized );
255         // \--
256     }
257 
258     // update unguarded
259     if( bMustUpdateChildren )
260         m_bChildrenInitialized = ImplUpdateChildren();
261 
262     return m_bChildrenInitialized;
263 }
264 
265 bool AccessibleBase::ImplUpdateChildren()
266 {
267     bool bResult = false;
268 
269     if( m_aAccInfo.m_spObjectHierarchy )
270     {
271         ObjectHierarchy::tChildContainer aModelChildren(
272             m_aAccInfo.m_spObjectHierarchy->getChildren( GetId() ));
273         ::std::vector< ChildOIDMap::key_type > aAccChildren;
274         aAccChildren.reserve( aModelChildren.size());
275         ::std::transform( m_aChildOIDMap.begin(), m_aChildOIDMap.end(),
276                           ::std::back_inserter( aAccChildren ),
277                           ::std::select1st< ChildOIDMap::value_type >());
278 
279         ::std::sort( aModelChildren.begin(), aModelChildren.end());
280 
281         ::std::vector< ObjectHierarchy::tOID > aChildrenToRemove, aChildrenToAdd;
282         ::std::set_difference( aModelChildren.begin(), aModelChildren.end(),
283                                aAccChildren.begin(), aAccChildren.end(),
284                                ::std::back_inserter( aChildrenToAdd ));
285         ::std::set_difference( aAccChildren.begin(), aAccChildren.end(),
286                                aModelChildren.begin(), aModelChildren.end(),
287                                ::std::back_inserter( aChildrenToRemove ));
288 
289         ::std::vector< ObjectHierarchy::tOID >::const_iterator aIt( aChildrenToRemove.begin());
290         for( ; aIt != aChildrenToRemove.end(); ++aIt )
291         {
292             RemoveChildByOId( *aIt );
293         }
294 
295         AccessibleElementInfo aAccInfo( GetInfo());
296         aAccInfo.m_pParent = this;
297 
298         for( aIt = aChildrenToAdd.begin(); aIt != aChildrenToAdd.end(); ++aIt )
299         {
300             aAccInfo.m_aOID = *aIt;
301             if ( aIt->isAutoGeneratedObject() )
302             {
303                 AddChild( ChartElementFactory::CreateChartElement( aAccInfo ) );
304             }
305             else if ( aIt->isAdditionalShape() )
306             {
307                 AddChild( new AccessibleChartShape( aAccInfo, true, false ) );
308             }
309         }
310         bResult = true;
311     }
312 
313     return bResult;
314 }
315 
316 void AccessibleBase::AddChild( AccessibleBase * pChild  )
317 {
318     OSL_ENSURE( pChild != NULL, "Invalid Child" );
319     if( pChild )
320     {
321         // /--
322         ClearableMutexGuard aGuard( GetMutex() );
323 
324         Reference< XAccessible > xChild( pChild );
325         m_aChildList.push_back( xChild );
326 
327         m_aChildOIDMap[ pChild->GetId() ] = xChild;
328 
329         // inform listeners of new child
330         if( m_bChildrenInitialized )
331         {
332             Any aEmpty, aNew;
333             aNew <<= xChild;
334 
335             aGuard.clear();
336             // \-- (1st)
337             BroadcastAccEvent( AccessibleEventId::CHILD, aNew, aEmpty );
338         }
339         // \-- (2nd)
340     }
341 }
342 
343 /** in this method we imply that the Reference< XAccessible > elements in the
344     vector are AccessibleBase objects !
345  */
346 void AccessibleBase::RemoveChildByOId( const ObjectIdentifier& rOId )
347 {
348     // /--
349     ClearableMutexGuard aGuard( GetMutex() );
350 
351     ChildOIDMap::iterator aIt( m_aChildOIDMap.find( rOId ));
352     if( aIt != m_aChildOIDMap.end())
353     {
354         Reference< XAccessible > xChild( aIt->second );
355 
356         // remove from map
357         m_aChildOIDMap.erase( aIt );
358 
359         // search child in vector
360         ChildListVectorType::iterator aVecIter =
361             ::std::find( m_aChildList.begin(), m_aChildList.end(), xChild );
362 
363         OSL_ENSURE( aVecIter != m_aChildList.end(),
364                     "Inconsistent ChildMap" );
365 
366         // remove child from vector
367         m_aChildList.erase( aVecIter );
368         bool bInitialized = m_bChildrenInitialized;
369 
370         // call listeners unguarded
371         aGuard.clear();
372         // \-- (1st)
373 
374         // inform listeners of removed child
375         if( bInitialized )
376         {
377             Any aEmpty, aOld;
378             aOld <<= xChild;
379 
380             BroadcastAccEvent( AccessibleEventId::CHILD, aEmpty, aOld );
381         }
382 
383         // dispose the child
384         Reference< lang::XComponent > xComp( xChild, UNO_QUERY );
385         if( xComp.is())
386             xComp->dispose();
387     }
388 }
389 
390 awt::Point AccessibleBase::GetUpperLeftOnScreen() const
391 {
392     awt::Point aResult;
393     if( m_aAccInfo.m_pParent )
394     {
395         // /--
396         ClearableMutexGuard aGuard( GetMutex() );
397         AccessibleBase * pParent = m_aAccInfo.m_pParent;
398         aGuard.clear();
399         // \--
400 
401         if( pParent )
402         {
403             aResult = pParent->GetUpperLeftOnScreen();
404         }
405         else
406             OSL_ENSURE( false, "Default position used is probably incorrect." );
407     }
408 
409     return aResult;
410 }
411 
412 void AccessibleBase::BroadcastAccEvent(
413     sal_Int16 nId,
414     const Any & rNew,
415     const Any & rOld,
416     bool bSendGlobally ) const
417 {
418     // /--
419     ClearableMutexGuard aGuard( GetMutex() );
420 
421     if ( !m_nEventNotifierId && !bSendGlobally )
422         return;
423         // if we don't have a client id for the notifier, then we don't have listeners, then
424         // we don't need to notify anything
425         //except SendGlobally for focus handling?
426 
427     // the const cast is needed, because UNO parameters are never const
428     const AccessibleEventObject aEvent(
429         const_cast< uno::XWeak * >( static_cast< const uno::XWeak * >( this )),
430         nId, rNew, rOld );
431 
432     if ( m_nEventNotifierId ) // let the notifier handle this event
433         ::comphelper::AccessibleEventNotifier::addEvent( m_nEventNotifierId, aEvent );
434 
435     aGuard.clear();
436     // \--
437 
438     // send event to global message queue
439     if( bSendGlobally )
440     {
441         ::vcl::unohelper::NotifyAccessibleStateEventGlobally( aEvent );
442     }
443 }
444 
445 void AccessibleBase::KillAllChildren()
446 {
447     // /--
448     ClearableMutexGuard aGuard( GetMutex() );
449 
450     // make local copy for notification
451     ChildListVectorType aLocalChildList( m_aChildList );
452 
453     // remove all children
454     m_aChildList.clear();
455     m_aChildOIDMap.clear();
456 
457     aGuard.clear();
458     // \--
459 
460     // call dispose for all children
461     // and notify listeners
462     Reference< lang::XComponent > xComp;
463     Any aEmpty, aOld;
464     ChildListVectorType::const_iterator aEndIter = aLocalChildList.end();
465     for( ChildListVectorType::const_iterator aIter = aLocalChildList.begin();
466          aIter != aEndIter; ++aIter )
467     {
468         aOld <<= (*aIter);
469         BroadcastAccEvent( AccessibleEventId::CHILD, aEmpty, aOld );
470 
471         xComp.set( *aIter, UNO_QUERY );
472         if( xComp.is())
473             xComp->dispose();
474     }
475     m_bChildrenInitialized = false;
476 }
477 
478 AccessibleElementInfo AccessibleBase::GetInfo() const
479 {
480     return m_aAccInfo;
481 }
482 
483 void AccessibleBase::SetInfo( const AccessibleElementInfo & rNewInfo )
484 {
485     m_aAccInfo = rNewInfo;
486     if( m_bMayHaveChildren )
487     {
488         KillAllChildren();
489     }
490     BroadcastAccEvent( AccessibleEventId::INVALIDATE_ALL_CHILDREN, uno::Any(), uno::Any(),
491                        true /* global notification */ );
492 }
493 
494 AccessibleUniqueId AccessibleBase::GetId() const
495 {
496     return m_aAccInfo.m_aOID;
497 }
498 
499 // ____________________________________
500 // ____________________________________
501 //
502 //             Interfaces
503 // ____________________________________
504 // ____________________________________
505 
506 // ________ (XComponent::dispose) ________
507 void SAL_CALL AccessibleBase::disposing()
508 {
509     // /--
510     ClearableMutexGuard aGuard( GetMutex() );
511     OSL_ENSURE( ! m_bIsDisposed, "dispose() called twice" );
512 
513     // notify disposing to all AccessibleEvent listeners asynchron
514     if ( m_nEventNotifierId )
515     {
516         ::comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( m_nEventNotifierId, *this );
517         m_nEventNotifierId = 0;
518     }
519 
520     // reset pointers
521     m_aAccInfo.m_pParent = NULL;
522 
523     // invalidate implementation for helper, but keep UNO reference to still
524     // allow a tool to query the DEFUNC state.
525     // Note: The object will be deleted when the last reference is released
526     m_pStateSetHelper = NULL;
527 
528     // attach new empty state set helper to member reference
529     ::utl::AccessibleStateSetHelper * pHelper = new ::utl::AccessibleStateSetHelper();
530     pHelper->AddState( AccessibleStateType::DEFUNC );
531     // release old helper and attach new one
532     m_aStateSet.set( pHelper );
533 
534     m_bIsDisposed = true;
535 
536     // call listeners unguarded
537     aGuard.clear();
538     // \--
539 
540     if( m_bMayHaveChildren )
541     {
542         KillAllChildren();
543     }
544     else
545         OSL_ENSURE( m_aChildList.empty(), "Child list should be empty" );
546 }
547 
548 // ________ XAccessible ________
549 Reference< XAccessibleContext > SAL_CALL AccessibleBase::getAccessibleContext()
550     throw (RuntimeException)
551 {
552     return this;
553 }
554 
555 // ________ AccessibleBase::XAccessibleContext ________
556 sal_Int32 SAL_CALL AccessibleBase::getAccessibleChildCount()
557     throw (RuntimeException)
558 {
559     // /--
560     ClearableMutexGuard aGuard( GetMutex() );
561     if( ! m_bMayHaveChildren ||
562         m_bIsDisposed )
563         return 0;
564 
565     bool bMustUpdateChildren = ( m_bMayHaveChildren &&
566                                  ! m_bChildrenInitialized );
567 
568     aGuard.clear();
569     // \--
570 
571     // update unguarded
572     if( bMustUpdateChildren )
573         UpdateChildren();
574 
575     return ImplGetAccessibleChildCount();
576 }
577 
578 sal_Int32 AccessibleBase::ImplGetAccessibleChildCount() const
579     throw (RuntimeException)
580 {
581     return m_aChildList.size();
582 }
583 
584 Reference< XAccessible > SAL_CALL AccessibleBase::getAccessibleChild( sal_Int32 i )
585     throw (lang::IndexOutOfBoundsException, RuntimeException)
586 {
587     CheckDisposeState();
588     Reference< XAccessible > xResult;
589 
590     // /--
591     ResettableMutexGuard aGuard( GetMutex() );
592     bool bMustUpdateChildren = ( m_bMayHaveChildren &&
593                                  ! m_bChildrenInitialized );
594 
595     aGuard.clear();
596     // \--
597 
598     if( bMustUpdateChildren )
599         UpdateChildren();
600 
601     xResult.set( ImplGetAccessibleChildById( i ));
602 
603     return xResult;
604     // \--
605 }
606 
607 Reference< XAccessible > AccessibleBase::ImplGetAccessibleChildById( sal_Int32 i ) const
608     throw (lang::IndexOutOfBoundsException, RuntimeException)
609 {
610     Reference< XAccessible > xResult;
611     // /--
612     MutexGuard aGuard( GetMutex());
613     if( ! m_bMayHaveChildren ||
614         i < 0 ||
615         static_cast< ChildListVectorType::size_type >( i ) >= m_aChildList.size() )
616     {
617         OUStringBuffer aBuf;
618         aBuf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "Index " ));
619         aBuf.append( i );
620         aBuf.appendAscii( RTL_CONSTASCII_STRINGPARAM( " is invalid for range [ 0, " ));
621         aBuf.append( static_cast< sal_Int32 >( m_aChildList.size() - 1 ) );
622         aBuf.appendAscii( RTL_CONSTASCII_STRINGPARAM( " ]" ) );
623         lang::IndexOutOfBoundsException aEx( aBuf.makeStringAndClear(),
624                                              const_cast< ::cppu::OWeakObject * >(
625                                                  static_cast< const ::cppu::OWeakObject * >( this )));
626         throw aEx;
627     }
628     else
629         xResult.set( m_aChildList[ i ] );
630 
631     return xResult;
632 }
633 
634 Reference< XAccessible > SAL_CALL AccessibleBase::getAccessibleParent()
635     throw (RuntimeException)
636 {
637     CheckDisposeState();
638     Reference< XAccessible > aResult;
639     if( m_aAccInfo.m_pParent )
640         aResult.set( m_aAccInfo.m_pParent );
641 
642     return aResult;
643 }
644 
645 sal_Int32 SAL_CALL AccessibleBase::getAccessibleIndexInParent()
646     throw (RuntimeException)
647 {
648     CheckDisposeState();
649 
650     if( m_aAccInfo.m_spObjectHierarchy )
651         return m_aAccInfo.m_spObjectHierarchy->getIndexInParent( GetId() );
652     return -1;
653 }
654 
655 sal_Int16 SAL_CALL AccessibleBase::getAccessibleRole()
656     throw (RuntimeException)
657 {
658     return AccessibleRole::LIST_ITEM; // #i73747# role SHAPE seems more appropriate, but is not read
659 }
660 
661 Reference< XAccessibleRelationSet > SAL_CALL AccessibleBase::getAccessibleRelationSet()
662     throw (RuntimeException)
663 {
664     Reference< XAccessibleRelationSet > aResult;
665     return aResult;
666 }
667 
668 Reference< XAccessibleStateSet > SAL_CALL AccessibleBase::getAccessibleStateSet()
669     throw (RuntimeException)
670 {
671     if( ! m_bStateSetInitialized )
672     {
673         Reference< view::XSelectionSupplier > xSelSupp( GetInfo().m_xSelectionSupplier );
674         if ( xSelSupp.is() )
675         {
676             ObjectIdentifier aOID( xSelSupp->getSelection() );
677             if ( aOID.isValid() && GetId() == aOID )
678             {
679                 AddState( AccessibleStateType::SELECTED );
680                 AddState( AccessibleStateType::FOCUSED );
681             }
682         }
683         m_bStateSetInitialized = true;
684     }
685 
686     return m_aStateSet;
687 }
688 
689 
690 lang::Locale SAL_CALL AccessibleBase::getLocale()
691     throw (IllegalAccessibleComponentStateException, RuntimeException)
692 {
693     CheckDisposeState();
694 
695     return Application::GetSettings().GetLocale();
696 }
697 
698 // ________ AccessibleBase::XAccessibleComponent ________
699 sal_Bool SAL_CALL AccessibleBase::containsPoint( const awt::Point& aPoint )
700     throw (RuntimeException)
701 {
702     awt::Rectangle aRect( getBounds() );
703 
704     // contains() works with relative coordinates
705     aRect.X = 0;
706     aRect.Y = 0;
707 
708     return ( aPoint.X >= aRect.X &&
709              aPoint.Y >= aRect.Y &&
710              aPoint.X < (aRect.X + aRect.Width) &&
711              aPoint.Y < (aRect.Y + aRect.Height) );
712 }
713 
714 Reference< XAccessible > SAL_CALL AccessibleBase::getAccessibleAtPoint( const awt::Point& aPoint )
715     throw (RuntimeException)
716 {
717     CheckDisposeState();
718     Reference< XAccessible > aResult;
719     awt::Rectangle aRect( getBounds());
720 
721     // children are positioned relative to this object, so translate bound rect
722     aRect.X = 0;
723     aRect.Y = 0;
724 
725     // children must be inside the own bound rect
726     if( ( aRect.X <= aPoint.X && aPoint.X <= (aRect.X + aRect.Width) ) &&
727         ( aRect.Y <= aPoint.Y && aPoint.Y <= (aRect.Y + aRect.Height)))
728     {
729         // /--
730         ClearableMutexGuard aGuard( GetMutex() );
731         ChildListVectorType aLocalChildList( m_aChildList );
732         aGuard.clear();
733         // \--
734 
735         Reference< XAccessibleComponent > aComp;
736         for( ChildListVectorType::const_iterator aIter = aLocalChildList.begin();
737              aIter != aLocalChildList.end(); ++aIter )
738         {
739             aComp.set( *aIter, UNO_QUERY );
740             if( aComp.is())
741             {
742                 aRect = aComp->getBounds();
743                 if( ( aRect.X <= aPoint.X && aPoint.X <= (aRect.X + aRect.Width) ) &&
744                     ( aRect.Y <= aPoint.Y && aPoint.Y <= (aRect.Y + aRect.Height)))
745                 {
746                     aResult = (*aIter);
747                     break;
748                 }
749             }
750         }
751     }
752 
753     return aResult;
754 }
755 
756 awt::Rectangle SAL_CALL AccessibleBase::getBounds()
757     throw (RuntimeException)
758 {
759     ExplicitValueProvider *pExplicitValueProvider(
760         ExplicitValueProvider::getExplicitValueProvider( m_aAccInfo.m_xView ));
761     if( pExplicitValueProvider )
762     {
763         Window* pWindow( VCLUnoHelper::GetWindow( m_aAccInfo.m_xWindow ));
764         awt::Rectangle aLogicRect( pExplicitValueProvider->getRectangleOfObject( m_aAccInfo.m_aOID.getObjectCID() ));
765         if( pWindow )
766         {
767             Rectangle aRect( aLogicRect.X, aLogicRect.Y,
768                              aLogicRect.X + aLogicRect.Width,
769                              aLogicRect.Y + aLogicRect.Height );
770             // /-- solar
771             ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
772             aRect = pWindow->LogicToPixel( aRect );
773 
774             // aLogicRect ist relative to the page, but we need a value relative
775             // to the parent object
776             awt::Point aParentLocOnScreen;
777             uno::Reference< XAccessibleComponent > xParent( getAccessibleParent(), uno::UNO_QUERY );
778             if( xParent.is() )
779                 aParentLocOnScreen = xParent->getLocationOnScreen();
780 
781             // aOffset = aParentLocOnScreen - GetUpperLeftOnScreen()
782             awt::Point aULOnScreen = GetUpperLeftOnScreen();
783             awt::Point aOffset( aParentLocOnScreen.X - aULOnScreen.X,
784                                 aParentLocOnScreen.Y - aULOnScreen.Y );
785 
786             return awt::Rectangle( aRect.getX() - aOffset.X, aRect.getY() - aOffset.Y,
787                                    aRect.getWidth(), aRect.getHeight());
788             // \-- solar
789         }
790 	}
791 
792     return awt::Rectangle();
793 }
794 
795 awt::Point SAL_CALL AccessibleBase::getLocation()
796     throw (RuntimeException)
797 {
798     CheckDisposeState();
799     awt::Rectangle aBBox( getBounds() );
800     return awt::Point( aBBox.X, aBBox.Y );
801 }
802 
803 awt::Point SAL_CALL AccessibleBase::getLocationOnScreen()
804     throw (RuntimeException)
805 {
806     CheckDisposeState();
807 
808     if( m_aAccInfo.m_pParent != NULL )
809     {
810         AccessibleBase * pParent = m_aAccInfo.m_pParent;
811         awt::Point aLocThisRel( getLocation());
812         awt::Point aUpperLeft;
813 
814         if( pParent != NULL )
815             aUpperLeft = pParent->getLocationOnScreen();
816 
817         return  awt::Point( aUpperLeft.X + aLocThisRel.X,
818                             aUpperLeft.Y + aLocThisRel.Y );
819     }
820     else
821         return getLocation();
822 }
823 
824 awt::Size SAL_CALL AccessibleBase::getSize()
825     throw (RuntimeException)
826 {
827     CheckDisposeState();
828     awt::Rectangle aBBox( getBounds() );
829     return awt::Size( aBBox.Width, aBBox.Height );
830 }
831 
832 void SAL_CALL AccessibleBase::grabFocus()
833     throw (RuntimeException)
834 {
835     CheckDisposeState();
836 
837     Reference< view::XSelectionSupplier > xSelSupp( GetInfo().m_xSelectionSupplier );
838     if ( xSelSupp.is() )
839     {
840         xSelSupp->select( GetId().getAny() );
841     }
842 }
843 
844 sal_Int32 SAL_CALL AccessibleBase::getForeground()
845     throw (RuntimeException)
846 {
847     return getColor( ACC_BASE_FOREGROUND );
848 }
849 
850 sal_Int32 SAL_CALL AccessibleBase::getBackground()
851     throw (RuntimeException)
852 {
853     return getColor( ACC_BASE_BACKGROUND );
854 }
855 
856 sal_Int32 AccessibleBase::getColor( eColorType eColType )
857 {
858     sal_Int32 nResult = static_cast< sal_Int32 >( Color( COL_TRANSPARENT ).GetColor());
859     if( m_bAlwaysTransparent )
860         return nResult;
861 
862     ObjectIdentifier aOID( m_aAccInfo.m_aOID );
863     ObjectType eType( aOID.getObjectType() );
864     Reference< beans::XPropertySet > xObjProp;
865     OUString aObjectCID = aOID.getObjectCID();
866     if( eType == OBJECTTYPE_LEGEND_ENTRY )
867     {
868         // for colors get the data series/point properties
869         OUString aParentParticle( ObjectIdentifier::getFullParentParticle( aObjectCID ));
870         aObjectCID = ObjectIdentifier::createClassifiedIdentifierForParticle( aParentParticle );
871     }
872 
873     xObjProp.set(
874         ObjectIdentifier::getObjectPropertySet(
875             aObjectCID, Reference< chart2::XChartDocument >( m_aAccInfo.m_xChartDocument )), uno::UNO_QUERY );
876     if( xObjProp.is())
877     {
878         try
879         {
880             OUString aPropName;
881             OUString aStylePropName;
882 
883             switch( eType )
884             {
885                 case OBJECTTYPE_LEGEND_ENTRY:
886                 case OBJECTTYPE_DATA_SERIES:
887                 case OBJECTTYPE_DATA_POINT:
888                     if( eColType == ACC_BASE_FOREGROUND )
889                     {
890                         aPropName = C2U("BorderColor");
891                         aStylePropName = C2U("BorderTransparency");
892                     }
893                     else
894                     {
895                         aPropName = C2U("Color");
896                         aStylePropName = C2U("Transparency");
897                     }
898                     break;
899                 default:
900                     if( eColType == ACC_BASE_FOREGROUND )
901                     {
902                         aPropName = C2U("LineColor");
903                         aStylePropName = C2U("LineTransparence");
904                     }
905                     else
906                     {
907                         aPropName = C2U("FillColor");
908                         aStylePropName = C2U("FillTransparence");
909                     }
910                     break;
911             }
912 
913             bool bTransparent = m_bAlwaysTransparent;
914             Reference< beans::XPropertySetInfo > xInfo( xObjProp->getPropertySetInfo(), uno::UNO_QUERY );
915             if( xInfo.is() &&
916                 xInfo->hasPropertyByName( aStylePropName ))
917             {
918                 if( eColType == ACC_BASE_FOREGROUND )
919                 {
920                     drawing::LineStyle aLStyle;
921                     if( xObjProp->getPropertyValue( aStylePropName ) >>= aLStyle )
922                         bTransparent = (aLStyle == drawing::LineStyle_NONE);
923                 }
924                 else
925                 {
926                     drawing::FillStyle aFStyle;
927                     if( xObjProp->getPropertyValue( aStylePropName ) >>= aFStyle )
928                         bTransparent = (aFStyle == drawing::FillStyle_NONE);
929                 }
930             }
931 
932             if( !bTransparent &&
933                 xInfo.is() &&
934                 xInfo->hasPropertyByName( aPropName ))
935             {
936                 xObjProp->getPropertyValue( aPropName ) >>= nResult;
937             }
938         }
939         catch( const uno::Exception & ex )
940         {
941             ASSERT_EXCEPTION( ex );
942         }
943     }
944 
945     return nResult;
946 }
947 
948 // ________ AccessibleBase::XServiceInfo ________
949 OUString SAL_CALL AccessibleBase::getImplementationName()
950     throw (RuntimeException)
951 {
952     return OUString( RTL_CONSTASCII_USTRINGPARAM( "AccessibleBase" ));
953 }
954 
955 sal_Bool SAL_CALL AccessibleBase::supportsService( const OUString& ServiceName )
956     throw (RuntimeException)
957 {
958     return comphelper::ServiceInfoHelper::supportsService( ServiceName, getSupportedServiceNames() );
959 }
960 
961 uno::Sequence< OUString > SAL_CALL AccessibleBase::getSupportedServiceNames()
962     throw (RuntimeException)
963 {
964     uno::Sequence< ::rtl::OUString > aSeq( 2 );
965     ::rtl::OUString* pStr = aSeq.getArray();
966     pStr[ 0 ] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.accessibility.Accessible" ));
967     pStr[ 1 ] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.accessibility.AccessibleContext" ));
968 
969     return aSeq;
970 }
971 
972 // ________ AccessibleBase::XEventListener ________
973 void SAL_CALL AccessibleBase::disposing( const lang::EventObject& /*Source*/ )
974     throw (RuntimeException)
975 {
976 }
977 
978 // ________ XAccessibleEventBroadcasters ________
979 void SAL_CALL AccessibleBase::addEventListener( const Reference< XAccessibleEventListener >& xListener )
980     throw (RuntimeException)
981 {
982     MutexGuard aGuard( GetMutex() );
983 
984     if ( xListener.is() )
985     {
986         if ( !m_nEventNotifierId )
987             m_nEventNotifierId = ::comphelper::AccessibleEventNotifier::registerClient();
988 
989         ::comphelper::AccessibleEventNotifier::addEventListener( m_nEventNotifierId, xListener );
990     }
991 }
992 
993 void SAL_CALL AccessibleBase::removeEventListener( const Reference< XAccessibleEventListener >& xListener )
994     throw (RuntimeException)
995 {
996     MutexGuard aGuard( GetMutex() );
997 
998     if ( xListener.is() )
999     {
1000         sal_Int32 nListenerCount = ::comphelper::AccessibleEventNotifier::removeEventListener( m_nEventNotifierId, xListener );
1001         if ( !nListenerCount )
1002         {
1003             // no listeners anymore
1004             ::comphelper::AccessibleEventNotifier::revokeClient( m_nEventNotifierId );
1005             m_nEventNotifierId = 0;
1006         }
1007     }
1008 }
1009 
1010 } // namespace chart
1011