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