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     return AccessibleRole::LIST_ITEM; // #i73747# role SHAPE seems more appropriate, but is not read
655 }
656 
657 Reference< XAccessibleRelationSet > SAL_CALL AccessibleBase::getAccessibleRelationSet()
658     throw (RuntimeException)
659 {
660     Reference< XAccessibleRelationSet > aResult;
661     return aResult;
662 }
663 
664 Reference< XAccessibleStateSet > SAL_CALL AccessibleBase::getAccessibleStateSet()
665     throw (RuntimeException)
666 {
667     if( ! m_bStateSetInitialized )
668     {
669         Reference< view::XSelectionSupplier > xSelSupp( GetInfo().m_xSelectionSupplier );
670         if ( xSelSupp.is() )
671         {
672             ObjectIdentifier aOID( xSelSupp->getSelection() );
673             if ( aOID.isValid() && GetId() == aOID )
674             {
675                 AddState( AccessibleStateType::SELECTED );
676                 AddState( AccessibleStateType::FOCUSED );
677             }
678         }
679         m_bStateSetInitialized = true;
680     }
681 
682     return m_aStateSet;
683 }
684 
685 
686 lang::Locale SAL_CALL AccessibleBase::getLocale()
687     throw (IllegalAccessibleComponentStateException, RuntimeException)
688 {
689     CheckDisposeState();
690 
691     return Application::GetSettings().GetLocale();
692 }
693 
694 // ________ AccessibleBase::XAccessibleComponent ________
695 sal_Bool SAL_CALL AccessibleBase::containsPoint( const awt::Point& aPoint )
696     throw (RuntimeException)
697 {
698     awt::Rectangle aRect( getBounds() );
699 
700     // contains() works with relative coordinates
701     aRect.X = 0;
702     aRect.Y = 0;
703 
704     return ( aPoint.X >= aRect.X &&
705              aPoint.Y >= aRect.Y &&
706              aPoint.X < (aRect.X + aRect.Width) &&
707              aPoint.Y < (aRect.Y + aRect.Height) );
708 }
709 
710 Reference< XAccessible > SAL_CALL AccessibleBase::getAccessibleAtPoint( const awt::Point& aPoint )
711     throw (RuntimeException)
712 {
713     CheckDisposeState();
714     Reference< XAccessible > aResult;
715     awt::Rectangle aRect( getBounds());
716 
717     // children are positioned relative to this object, so translate bound rect
718     aRect.X = 0;
719     aRect.Y = 0;
720 
721     // children must be inside the own bound rect
722     if( ( aRect.X <= aPoint.X && aPoint.X <= (aRect.X + aRect.Width) ) &&
723         ( aRect.Y <= aPoint.Y && aPoint.Y <= (aRect.Y + aRect.Height)))
724     {
725         // /--
726         ClearableMutexGuard aGuard( GetMutex() );
727         ChildListVectorType aLocalChildList( m_aChildList );
728         aGuard.clear();
729         // \--
730 
731         Reference< XAccessibleComponent > aComp;
732         for( ChildListVectorType::const_iterator aIter = aLocalChildList.begin();
733              aIter != aLocalChildList.end(); ++aIter )
734         {
735             aComp.set( *aIter, UNO_QUERY );
736             if( aComp.is())
737             {
738                 aRect = aComp->getBounds();
739                 if( ( aRect.X <= aPoint.X && aPoint.X <= (aRect.X + aRect.Width) ) &&
740                     ( aRect.Y <= aPoint.Y && aPoint.Y <= (aRect.Y + aRect.Height)))
741                 {
742                     aResult = (*aIter);
743                     break;
744                 }
745             }
746         }
747     }
748 
749     return aResult;
750 }
751 
752 awt::Rectangle SAL_CALL AccessibleBase::getBounds()
753     throw (RuntimeException)
754 {
755     ExplicitValueProvider *pExplicitValueProvider(
756         ExplicitValueProvider::getExplicitValueProvider( m_aAccInfo.m_xView ));
757     if( pExplicitValueProvider )
758     {
759         Window* pWindow( VCLUnoHelper::GetWindow( m_aAccInfo.m_xWindow ));
760         awt::Rectangle aLogicRect( pExplicitValueProvider->getRectangleOfObject( m_aAccInfo.m_aOID.getObjectCID() ));
761         if( pWindow )
762         {
763             Rectangle aRect( aLogicRect.X, aLogicRect.Y,
764                              aLogicRect.X + aLogicRect.Width,
765                              aLogicRect.Y + aLogicRect.Height );
766             // /-- solar
767             ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
768             aRect = pWindow->LogicToPixel( aRect );
769 
770             // aLogicRect ist relative to the page, but we need a value relative
771             // to the parent object
772             awt::Point aParentLocOnScreen;
773             uno::Reference< XAccessibleComponent > xParent( getAccessibleParent(), uno::UNO_QUERY );
774             if( xParent.is() )
775                 aParentLocOnScreen = xParent->getLocationOnScreen();
776 
777             // aOffset = aParentLocOnScreen - GetUpperLeftOnScreen()
778             awt::Point aULOnScreen = GetUpperLeftOnScreen();
779             awt::Point aOffset( aParentLocOnScreen.X - aULOnScreen.X,
780                                 aParentLocOnScreen.Y - aULOnScreen.Y );
781 
782             return awt::Rectangle( aRect.getX() - aOffset.X, aRect.getY() - aOffset.Y,
783                                    aRect.getWidth(), aRect.getHeight());
784             // \-- solar
785         }
786 	}
787 
788     return awt::Rectangle();
789 }
790 
791 awt::Point SAL_CALL AccessibleBase::getLocation()
792     throw (RuntimeException)
793 {
794     CheckDisposeState();
795     awt::Rectangle aBBox( getBounds() );
796     return awt::Point( aBBox.X, aBBox.Y );
797 }
798 
799 awt::Point SAL_CALL AccessibleBase::getLocationOnScreen()
800     throw (RuntimeException)
801 {
802     CheckDisposeState();
803 
804     if( m_aAccInfo.m_pParent != NULL )
805     {
806         AccessibleBase * pParent = m_aAccInfo.m_pParent;
807         awt::Point aLocThisRel( getLocation());
808         awt::Point aUpperLeft;
809 
810         if( pParent != NULL )
811             aUpperLeft = pParent->getLocationOnScreen();
812 
813         return  awt::Point( aUpperLeft.X + aLocThisRel.X,
814                             aUpperLeft.Y + aLocThisRel.Y );
815     }
816     else
817         return getLocation();
818 }
819 
820 awt::Size SAL_CALL AccessibleBase::getSize()
821     throw (RuntimeException)
822 {
823     CheckDisposeState();
824     awt::Rectangle aBBox( getBounds() );
825     return awt::Size( aBBox.Width, aBBox.Height );
826 }
827 
828 void SAL_CALL AccessibleBase::grabFocus()
829     throw (RuntimeException)
830 {
831     CheckDisposeState();
832 
833     Reference< view::XSelectionSupplier > xSelSupp( GetInfo().m_xSelectionSupplier );
834     if ( xSelSupp.is() )
835     {
836         xSelSupp->select( GetId().getAny() );
837     }
838 }
839 
840 sal_Int32 SAL_CALL AccessibleBase::getForeground()
841     throw (RuntimeException)
842 {
843     return getColor( ACC_BASE_FOREGROUND );
844 }
845 
846 sal_Int32 SAL_CALL AccessibleBase::getBackground()
847     throw (RuntimeException)
848 {
849     return getColor( ACC_BASE_BACKGROUND );
850 }
851 
852 sal_Int32 AccessibleBase::getColor( eColorType eColType )
853 {
854     sal_Int32 nResult = static_cast< sal_Int32 >( Color( COL_TRANSPARENT ).GetColor());
855     if( m_bAlwaysTransparent )
856         return nResult;
857 
858     ObjectIdentifier aOID( m_aAccInfo.m_aOID );
859     ObjectType eType( aOID.getObjectType() );
860     Reference< beans::XPropertySet > xObjProp;
861     OUString aObjectCID = aOID.getObjectCID();
862     if( eType == OBJECTTYPE_LEGEND_ENTRY )
863     {
864         // for colors get the data series/point properties
865         OUString aParentParticle( ObjectIdentifier::getFullParentParticle( aObjectCID ));
866         aObjectCID = ObjectIdentifier::createClassifiedIdentifierForParticle( aParentParticle );
867     }
868 
869     xObjProp.set(
870         ObjectIdentifier::getObjectPropertySet(
871             aObjectCID, Reference< chart2::XChartDocument >( m_aAccInfo.m_xChartDocument )), uno::UNO_QUERY );
872     if( xObjProp.is())
873     {
874         try
875         {
876             OUString aPropName;
877             OUString aStylePropName;
878 
879             switch( eType )
880             {
881                 case OBJECTTYPE_LEGEND_ENTRY:
882                 case OBJECTTYPE_DATA_SERIES:
883                 case OBJECTTYPE_DATA_POINT:
884                     if( eColType == ACC_BASE_FOREGROUND )
885                     {
886                         aPropName = C2U("BorderColor");
887                         aStylePropName = C2U("BorderTransparency");
888                     }
889                     else
890                     {
891                         aPropName = C2U("Color");
892                         aStylePropName = C2U("Transparency");
893                     }
894                     break;
895                 default:
896                     if( eColType == ACC_BASE_FOREGROUND )
897                     {
898                         aPropName = C2U("LineColor");
899                         aStylePropName = C2U("LineTransparence");
900                     }
901                     else
902                     {
903                         aPropName = C2U("FillColor");
904                         aStylePropName = C2U("FillTransparence");
905                     }
906                     break;
907             }
908 
909             bool bTransparent = m_bAlwaysTransparent;
910             Reference< beans::XPropertySetInfo > xInfo( xObjProp->getPropertySetInfo(), uno::UNO_QUERY );
911             if( xInfo.is() &&
912                 xInfo->hasPropertyByName( aStylePropName ))
913             {
914                 if( eColType == ACC_BASE_FOREGROUND )
915                 {
916                     drawing::LineStyle aLStyle;
917                     if( xObjProp->getPropertyValue( aStylePropName ) >>= aLStyle )
918                         bTransparent = (aLStyle == drawing::LineStyle_NONE);
919                 }
920                 else
921                 {
922                     drawing::FillStyle aFStyle;
923                     if( xObjProp->getPropertyValue( aStylePropName ) >>= aFStyle )
924                         bTransparent = (aFStyle == drawing::FillStyle_NONE);
925                 }
926             }
927 
928             if( !bTransparent &&
929                 xInfo.is() &&
930                 xInfo->hasPropertyByName( aPropName ))
931             {
932                 xObjProp->getPropertyValue( aPropName ) >>= nResult;
933             }
934         }
935         catch( const uno::Exception & ex )
936         {
937             ASSERT_EXCEPTION( ex );
938         }
939     }
940 
941     return nResult;
942 }
943 
944 // ________ AccessibleBase::XServiceInfo ________
945 OUString SAL_CALL AccessibleBase::getImplementationName()
946     throw (RuntimeException)
947 {
948     return OUString( RTL_CONSTASCII_USTRINGPARAM( "AccessibleBase" ));
949 }
950 
951 sal_Bool SAL_CALL AccessibleBase::supportsService( const OUString& ServiceName )
952     throw (RuntimeException)
953 {
954     return comphelper::ServiceInfoHelper::supportsService( ServiceName, getSupportedServiceNames() );
955 }
956 
957 uno::Sequence< OUString > SAL_CALL AccessibleBase::getSupportedServiceNames()
958     throw (RuntimeException)
959 {
960     uno::Sequence< ::rtl::OUString > aSeq( 2 );
961     ::rtl::OUString* pStr = aSeq.getArray();
962     pStr[ 0 ] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.accessibility.Accessible" ));
963     pStr[ 1 ] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.accessibility.AccessibleContext" ));
964 
965     return aSeq;
966 }
967 
968 // ________ AccessibleBase::XEventListener ________
969 void SAL_CALL AccessibleBase::disposing( const lang::EventObject& /*Source*/ )
970     throw (RuntimeException)
971 {
972 }
973 
974 // ________ XAccessibleEventBroadcasters ________
975 void SAL_CALL AccessibleBase::addEventListener( const Reference< XAccessibleEventListener >& xListener )
976     throw (RuntimeException)
977 {
978     MutexGuard aGuard( GetMutex() );
979 
980     if ( xListener.is() )
981     {
982         if ( !m_nEventNotifierId )
983             m_nEventNotifierId = ::comphelper::AccessibleEventNotifier::registerClient();
984 
985         ::comphelper::AccessibleEventNotifier::addEventListener( m_nEventNotifierId, xListener );
986     }
987 }
988 
989 void SAL_CALL AccessibleBase::removeEventListener( const Reference< XAccessibleEventListener >& xListener )
990     throw (RuntimeException)
991 {
992     MutexGuard aGuard( GetMutex() );
993 
994     if ( xListener.is() )
995     {
996         sal_Int32 nListenerCount = ::comphelper::AccessibleEventNotifier::removeEventListener( m_nEventNotifierId, xListener );
997         if ( !nListenerCount )
998         {
999             // no listeners anymore
1000             ::comphelper::AccessibleEventNotifier::revokeClient( m_nEventNotifierId );
1001             m_nEventNotifierId = 0;
1002         }
1003     }
1004 }
1005 
1006 } // namespace chart
1007