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