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_sc.hxx"
26
27
28 #include "AccessibleContextBase.hxx"
29 #include "unoguard.hxx"
30 #include <com/sun/star/accessibility/AccessibleRole.hpp>
31 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
32 #ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLESTATETYPE_HPP_
33 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
34 #endif
35 #include <com/sun/star/beans/PropertyChangeEvent.hpp>
36 #include <rtl/uuid.h>
37 #include <tools/debug.hxx>
38 #include <tools/gen.hxx>
39 #ifndef _UTL_ACCESSIBLESTATESETHELPER_HXX
40 #include <unotools/accessiblestatesethelper.hxx>
41 #endif
42 #include <toolkit/helper/convert.hxx>
43 #include <svl/smplhint.hxx>
44 #include <comphelper/sequence.hxx>
45 #include <unotools/accessiblerelationsethelper.hxx>
46 #include <vcl/unohelp.hxx>
47 #include <tools/color.hxx>
48 #include <comphelper/accessibleeventnotifier.hxx>
49
50 using namespace ::rtl;
51 using namespace ::com::sun::star;
52 using namespace ::com::sun::star::accessibility;
53
54 //===== internal ============================================================
55
DBG_NAME(ScAccessibleContextBase)56 DBG_NAME(ScAccessibleContextBase)
57
58 ScAccessibleContextBase::ScAccessibleContextBase(
59 const uno::Reference<XAccessible>& rxParent,
60 const sal_Int16 aRole)
61 :
62 ScAccessibleContextBaseWeakImpl(m_aMutex),
63 mxParent(rxParent),
64 mnClientId(0),
65 maRole(aRole)
66 {
67 DBG_CTOR(ScAccessibleContextBase, NULL);
68 }
69
70
~ScAccessibleContextBase(void)71 ScAccessibleContextBase::~ScAccessibleContextBase(void)
72 {
73 DBG_DTOR(ScAccessibleContextBase, NULL);
74
75 if (!IsDefunc() && !rBHelper.bInDispose)
76 {
77 // increment refcount to prevent double call off dtor
78 osl_incrementInterlockedCount( &m_refCount );
79 // call dispose to inform object which have a weak reference to this object
80 dispose();
81 }
82 }
83
Init()84 void ScAccessibleContextBase::Init()
85 {
86 // hold reference to make sure that the destructor is not called
87 uno::Reference< XAccessibleContext > xOwnContext(this);
88
89 if (mxParent.is())
90 {
91 uno::Reference< XAccessibleEventBroadcaster > xBroadcaster (mxParent->getAccessibleContext(), uno::UNO_QUERY);
92 if (xBroadcaster.is())
93 xBroadcaster->addEventListener(this);
94 }
95 msName = createAccessibleName();
96 msDescription = createAccessibleDescription();
97 }
98
disposing()99 void SAL_CALL ScAccessibleContextBase::disposing()
100 {
101 ScUnoGuard aGuard;
102 // CommitDefunc(); not necessary and should not be send, because it cost a lot of time
103
104 // hold reference to make sure that the destructor is not called
105 uno::Reference< XAccessibleContext > xOwnContext(this);
106
107 if ( mnClientId )
108 {
109 sal_Int32 nTemClientId(mnClientId);
110 mnClientId = 0;
111 comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( nTemClientId, *this );
112 }
113
114 if (mxParent.is())
115 {
116 uno::Reference< XAccessibleEventBroadcaster > xBroadcaster (mxParent->getAccessibleContext(), uno::UNO_QUERY);
117 if (xBroadcaster.is())
118 xBroadcaster->removeEventListener(this);
119 mxParent = NULL;
120 }
121
122 ScAccessibleContextBaseWeakImpl::disposing();
123 }
124
125 //===== XInterface =====================================================
126
queryInterface(uno::Type const & rType)127 uno::Any SAL_CALL ScAccessibleContextBase::queryInterface( uno::Type const & rType )
128 throw (uno::RuntimeException)
129 {
130 uno::Any aAny (ScAccessibleContextBaseWeakImpl::queryInterface(rType));
131 return aAny.hasValue() ? aAny : ScAccessibleContextBaseImplEvent::queryInterface(rType);
132 }
133
acquire()134 void SAL_CALL ScAccessibleContextBase::acquire()
135 throw ()
136 {
137 ScAccessibleContextBaseWeakImpl::acquire();
138 }
139
release()140 void SAL_CALL ScAccessibleContextBase::release()
141 throw ()
142 {
143 ScAccessibleContextBaseWeakImpl::release();
144 }
145
146 //===== SfxListener =====================================================
147
Notify(SfxBroadcaster &,const SfxHint & rHint)148 void ScAccessibleContextBase::Notify( SfxBroadcaster&, const SfxHint& rHint )
149 {
150 if (rHint.ISA( SfxSimpleHint ) )
151 {
152 const SfxSimpleHint& rRef = (const SfxSimpleHint&)rHint;
153 if (rRef.GetId() == SFX_HINT_DYING)
154 {
155 // it seems the Broadcaster is dying, since the view is dying
156 dispose();
157 }
158 }
159 }
160
161 //===== XAccessible =========================================================
162
163 uno::Reference< XAccessibleContext> SAL_CALL
getAccessibleContext(void)164 ScAccessibleContextBase::getAccessibleContext(void)
165 throw (uno::RuntimeException)
166 {
167 return this;
168 }
169
170 //===== XAccessibleComponent ================================================
171
containsPoint(const awt::Point & rPoint)172 sal_Bool SAL_CALL ScAccessibleContextBase::containsPoint(const awt::Point& rPoint )
173 throw (uno::RuntimeException)
174 {
175 ScUnoGuard aGuard;
176 IsObjectValid();
177 return Rectangle (Point(), GetBoundingBox().GetSize()).IsInside(VCLPoint(rPoint));
178 }
179
getAccessibleAtPoint(const awt::Point &)180 uno::Reference< XAccessible > SAL_CALL ScAccessibleContextBase::getAccessibleAtPoint(
181 const awt::Point& /* rPoint */ )
182 throw (uno::RuntimeException)
183 {
184 DBG_ERROR("not implemented");
185 return uno::Reference<XAccessible>();
186 }
187
getBounds()188 awt::Rectangle SAL_CALL ScAccessibleContextBase::getBounds( )
189 throw (uno::RuntimeException)
190 {
191 ScUnoGuard aGuard;
192 IsObjectValid();
193 return AWTRectangle(GetBoundingBox());
194 }
195
getLocation()196 awt::Point SAL_CALL ScAccessibleContextBase::getLocation( )
197 throw (uno::RuntimeException)
198 {
199 ScUnoGuard aGuard;
200 IsObjectValid();
201 return AWTPoint(GetBoundingBox().TopLeft());
202 }
203
getLocationOnScreen()204 awt::Point SAL_CALL ScAccessibleContextBase::getLocationOnScreen( )
205 throw (uno::RuntimeException)
206 {
207 ScUnoGuard aGuard;
208 IsObjectValid();
209 return AWTPoint(GetBoundingBoxOnScreen().TopLeft());
210 }
211
getSize()212 awt::Size SAL_CALL ScAccessibleContextBase::getSize( )
213 throw (uno::RuntimeException)
214 {
215 ScUnoGuard aGuard;
216 IsObjectValid();
217 return AWTSize(GetBoundingBox().GetSize());
218 }
219
isShowing()220 sal_Bool SAL_CALL ScAccessibleContextBase::isShowing( )
221 throw (uno::RuntimeException)
222 {
223 ScUnoGuard aGuard;
224 IsObjectValid();
225 sal_Bool bShowing(sal_False);
226 if (mxParent.is())
227 {
228 uno::Reference<XAccessibleComponent> xParentComponent (mxParent->getAccessibleContext(), uno::UNO_QUERY);
229 if (xParentComponent.is())
230 {
231 Rectangle aParentBounds(VCLRectangle(xParentComponent->getBounds()));
232 Rectangle aBounds(VCLRectangle(getBounds()));
233 bShowing = aBounds.IsOver(aParentBounds);
234 }
235 }
236 return bShowing;
237 }
238
isVisible()239 sal_Bool SAL_CALL ScAccessibleContextBase::isVisible( )
240 throw (uno::RuntimeException)
241 {
242 return sal_True;
243 }
244
grabFocus()245 void SAL_CALL ScAccessibleContextBase::grabFocus( )
246 throw (uno::RuntimeException)
247 {
248 DBG_ERROR("not implemented");
249 }
250
getForeground()251 sal_Int32 SAL_CALL ScAccessibleContextBase::getForeground( )
252 throw (uno::RuntimeException)
253 {
254 return COL_BLACK;
255 }
256
getBackground()257 sal_Int32 SAL_CALL ScAccessibleContextBase::getBackground( )
258 throw (uno::RuntimeException)
259 {
260 return COL_WHITE;
261 }
262
263 //===== XAccessibleContext ==================================================
264
265 sal_Int32 SAL_CALL
getAccessibleChildCount(void)266 ScAccessibleContextBase::getAccessibleChildCount(void)
267 throw (uno::RuntimeException)
268 {
269 DBG_ERROR("should be implemented in the abrevated class");
270 return 0;
271 }
272
273 uno::Reference<XAccessible> SAL_CALL
getAccessibleChild(sal_Int32)274 ScAccessibleContextBase::getAccessibleChild(sal_Int32 /* nIndex */)
275 throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
276 {
277 DBG_ERROR("should be implemented in the abrevated class");
278 return uno::Reference<XAccessible>();
279 }
280
281 uno::Reference<XAccessible> SAL_CALL
getAccessibleParent(void)282 ScAccessibleContextBase::getAccessibleParent(void)
283 throw (uno::RuntimeException)
284 {
285 return mxParent;
286 }
287
288 sal_Int32 SAL_CALL
getAccessibleIndexInParent(void)289 ScAccessibleContextBase::getAccessibleIndexInParent(void)
290 throw (uno::RuntimeException)
291 {
292 ScUnoGuard aGuard;
293 IsObjectValid();
294 // Use a simple but slow solution for now. Optimize later.
295 // Return -1 to indicate that this object's parent does not know about the
296 // object.
297 sal_Int32 nIndex(-1);
298
299 // Iterate over all the parent's children and search for this object.
300 if (mxParent.is())
301 {
302 uno::Reference<XAccessibleContext> xParentContext (
303 mxParent->getAccessibleContext());
304 if (xParentContext.is())
305 {
306 sal_Int32 nChildCount = xParentContext->getAccessibleChildCount();
307 for (sal_Int32 i=0; i<nChildCount; ++i)
308 {
309 uno::Reference<XAccessible> xChild (xParentContext->getAccessibleChild (i));
310 if (xChild.is())
311 {
312 if (xChild.get() == this)
313 nIndex = i;
314 }
315 }
316 }
317 }
318
319 return nIndex;
320 }
321
322 sal_Int16 SAL_CALL
getAccessibleRole(void)323 ScAccessibleContextBase::getAccessibleRole(void)
324 throw (uno::RuntimeException)
325 {
326 return maRole;
327 }
328
329 ::rtl::OUString SAL_CALL
getAccessibleDescription(void)330 ScAccessibleContextBase::getAccessibleDescription(void)
331 throw (uno::RuntimeException)
332 {
333 ScUnoGuard aGuard;
334 IsObjectValid();
335 if (!msDescription.getLength())
336 {
337 OUString sDescription(createAccessibleDescription());
338 // DBG_ASSERT(sDescription.getLength(), "We should give always a descripition.");
339
340 if (msDescription != sDescription)
341 {
342 AccessibleEventObject aEvent;
343 aEvent.EventId = AccessibleEventId::DESCRIPTION_CHANGED;
344 aEvent.Source = uno::Reference< XAccessibleContext >(this);
345 aEvent.OldValue <<= msDescription;
346 aEvent.NewValue <<= sDescription;
347
348 msDescription = sDescription;
349
350 CommitChange(aEvent);
351 }
352 }
353 return msDescription;
354 }
355
356 OUString SAL_CALL
getAccessibleName(void)357 ScAccessibleContextBase::getAccessibleName(void)
358 throw (uno::RuntimeException)
359 {
360 ScUnoGuard aGuard;
361 IsObjectValid();
362 if (!msName.getLength())
363 {
364 OUString sName(createAccessibleName());
365 DBG_ASSERT(sName.getLength(), "We should give always a name.");
366
367 if (msName != sName)
368 {
369 AccessibleEventObject aEvent;
370 aEvent.EventId = AccessibleEventId::NAME_CHANGED;
371 aEvent.Source = uno::Reference< XAccessibleContext >(this);
372 aEvent.OldValue <<= msName;
373 aEvent.NewValue <<= sName;
374
375 msName = sName;
376
377 CommitChange(aEvent);
378 }
379 }
380 return msName;
381 }
382
383 uno::Reference<XAccessibleRelationSet> SAL_CALL
getAccessibleRelationSet(void)384 ScAccessibleContextBase::getAccessibleRelationSet(void)
385 throw (uno::RuntimeException)
386 {
387 return new utl::AccessibleRelationSetHelper();
388 }
389
390 uno::Reference<XAccessibleStateSet> SAL_CALL
getAccessibleStateSet(void)391 ScAccessibleContextBase::getAccessibleStateSet(void)
392 throw (uno::RuntimeException)
393 {
394 return uno::Reference<XAccessibleStateSet>();
395 }
396
397 lang::Locale SAL_CALL
getLocale(void)398 ScAccessibleContextBase::getLocale(void)
399 throw (IllegalAccessibleComponentStateException,
400 uno::RuntimeException)
401 {
402 ScUnoGuard aGuard;
403 IsObjectValid();
404 if (mxParent.is())
405 {
406 uno::Reference<XAccessibleContext> xParentContext (
407 mxParent->getAccessibleContext());
408 if (xParentContext.is())
409 return xParentContext->getLocale ();
410 }
411
412 // No locale and no parent. Therefore throw exception to indicate this
413 // cluelessness.
414 throw IllegalAccessibleComponentStateException ();
415 }
416
417 //===== XAccessibleEventBroadcaster =====================================
418
419 void SAL_CALL
addEventListener(const uno::Reference<XAccessibleEventListener> & xListener)420 ScAccessibleContextBase::addEventListener(
421 const uno::Reference<XAccessibleEventListener>& xListener)
422 throw (uno::RuntimeException)
423 {
424 if (xListener.is())
425 {
426 ScUnoGuard aGuard;
427 IsObjectValid();
428 if (!IsDefunc())
429 {
430 if (!mnClientId)
431 mnClientId = comphelper::AccessibleEventNotifier::registerClient( );
432 comphelper::AccessibleEventNotifier::addEventListener( mnClientId, xListener );
433 }
434 }
435 }
436
437 void SAL_CALL
removeEventListener(const uno::Reference<XAccessibleEventListener> & xListener)438 ScAccessibleContextBase::removeEventListener(
439 const uno::Reference<XAccessibleEventListener>& xListener)
440 throw (uno::RuntimeException)
441 {
442 if (xListener.is())
443 {
444 ScUnoGuard aGuard;
445 if (!IsDefunc() && mnClientId)
446 {
447 sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( mnClientId, xListener );
448 if ( !nListenerCount )
449 {
450 // no listeners anymore
451 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
452 // and at least to us not firing any events anymore, in case somebody calls
453 // NotifyAccessibleEvent, again
454 comphelper::AccessibleEventNotifier::revokeClient( mnClientId );
455 mnClientId = 0;
456 }
457 }
458 }
459 }
460
461 //===== XAccessibleEventListener ========================================
462
disposing(const lang::EventObject & rSource)463 void SAL_CALL ScAccessibleContextBase::disposing(
464 const lang::EventObject& rSource )
465 throw (uno::RuntimeException)
466 {
467 ScUnoGuard aGuard;
468 if (rSource.Source == mxParent)
469 dispose();
470 }
471
notifyEvent(const AccessibleEventObject &)472 void SAL_CALL ScAccessibleContextBase::notifyEvent(
473 const AccessibleEventObject& /* aEvent */ )
474 throw (uno::RuntimeException)
475 {
476 }
477
478 //===== XServiceInfo ========================================================
479
480 ::rtl::OUString SAL_CALL
getImplementationName(void)481 ScAccessibleContextBase::getImplementationName(void)
482 throw (uno::RuntimeException)
483 {
484 return OUString(RTL_CONSTASCII_USTRINGPARAM ("ScAccessibleContextBase"));
485 }
486
487 sal_Bool SAL_CALL
supportsService(const OUString & sServiceName)488 ScAccessibleContextBase::supportsService(const OUString& sServiceName)
489 throw (uno::RuntimeException)
490 {
491 // Iterate over all supported service names and return true if on of them
492 // matches the given name.
493 uno::Sequence< ::rtl::OUString> aSupportedServices (
494 getSupportedServiceNames ());
495 sal_Int32 nLength(aSupportedServices.getLength());
496 const OUString* pServiceNames = aSupportedServices.getConstArray();
497 for (int i=0; i<nLength; ++i, ++pServiceNames)
498 if (sServiceName == *pServiceNames)
499 return sal_True;
500 return sal_False;
501 }
502
503 uno::Sequence< ::rtl::OUString> SAL_CALL
getSupportedServiceNames(void)504 ScAccessibleContextBase::getSupportedServiceNames(void)
505 throw (uno::RuntimeException)
506 {
507 uno::Sequence<OUString> aServiceNames(2);
508 OUString* pServiceNames = aServiceNames.getArray();
509 if (pServiceNames)
510 {
511 pServiceNames[0] = OUString(RTL_CONSTASCII_USTRINGPARAM ("com.sun.star.accessibility.Accessible"));
512 pServiceNames[1] = OUString(RTL_CONSTASCII_USTRINGPARAM ("com.sun.star.accessibility.AccessibleContext"));
513 }
514
515 return aServiceNames;
516 }
517
518 //===== XTypeProvider =======================================================
519
getTypes()520 uno::Sequence< uno::Type > SAL_CALL ScAccessibleContextBase::getTypes()
521 throw (uno::RuntimeException)
522 {
523 return comphelper::concatSequences(ScAccessibleContextBaseWeakImpl::getTypes(), ScAccessibleContextBaseImplEvent::getTypes());
524 }
525
526 uno::Sequence<sal_Int8> SAL_CALL
getImplementationId(void)527 ScAccessibleContextBase::getImplementationId(void)
528 throw (uno::RuntimeException)
529 {
530 ScUnoGuard aGuard;
531 IsObjectValid();
532 static uno::Sequence<sal_Int8> aId;
533 if (aId.getLength() == 0)
534 {
535 aId.realloc (16);
536 rtl_createUuid (reinterpret_cast<sal_uInt8 *>(aId.getArray()), 0, sal_True);
537 }
538 return aId;
539 }
540
541 //===== internal ============================================================
542
543 ::rtl::OUString SAL_CALL
createAccessibleDescription(void)544 ScAccessibleContextBase::createAccessibleDescription(void)
545 throw (uno::RuntimeException)
546 {
547 DBG_ERROR("should be implemented in the abrevated class");
548 return rtl::OUString();
549 }
550
551 ::rtl::OUString SAL_CALL
createAccessibleName(void)552 ScAccessibleContextBase::createAccessibleName(void)
553 throw (uno::RuntimeException)
554 {
555 DBG_ERROR("should be implemented in the abrevated class");
556 return rtl::OUString();
557 }
558
CommitChange(const AccessibleEventObject & rEvent) const559 void ScAccessibleContextBase::CommitChange(const AccessibleEventObject& rEvent) const
560 {
561 if (mnClientId)
562 comphelper::AccessibleEventNotifier::addEvent( mnClientId, rEvent );
563 }
564
ChangeName()565 void ScAccessibleContextBase::ChangeName()
566 {
567 AccessibleEventObject aEvent;
568 aEvent.EventId = AccessibleEventId::NAME_CHANGED;
569 aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this));
570 aEvent.OldValue <<= msName;
571
572 msName = rtl::OUString(); // reset the name so it will be hold again
573 getAccessibleName(); // create the new name
574
575 aEvent.NewValue <<= msName;
576
577 CommitChange(aEvent);
578 }
579
CommitFocusGained() const580 void ScAccessibleContextBase::CommitFocusGained() const
581 {
582 AccessibleEventObject aEvent;
583 aEvent.EventId = AccessibleEventId::STATE_CHANGED;
584 aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this));
585 aEvent.NewValue <<= AccessibleStateType::FOCUSED;
586
587 CommitChange(aEvent);
588
589 ::vcl::unohelper::NotifyAccessibleStateEventGlobally(aEvent);
590 }
591
CommitFocusLost() const592 void ScAccessibleContextBase::CommitFocusLost() const
593 {
594 AccessibleEventObject aEvent;
595 aEvent.EventId = AccessibleEventId::STATE_CHANGED;
596 aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this));
597 aEvent.OldValue <<= AccessibleStateType::FOCUSED;
598
599 CommitChange(aEvent);
600
601 vcl::unohelper::NotifyAccessibleStateEventGlobally(aEvent);
602 }
603
GetBoundingBoxOnScreen(void) const604 Rectangle ScAccessibleContextBase::GetBoundingBoxOnScreen(void) const
605 throw (uno::RuntimeException)
606 {
607 DBG_ERROR("not implemented");
608 return Rectangle();
609 }
610
GetBoundingBox(void) const611 Rectangle ScAccessibleContextBase::GetBoundingBox(void) const
612 throw (uno::RuntimeException)
613 {
614 DBG_ERROR("not implemented");
615 return Rectangle();
616 }
617
IsObjectValid() const618 void ScAccessibleContextBase::IsObjectValid() const
619 throw (lang::DisposedException)
620 {
621 if (rBHelper.bDisposed || rBHelper.bInDispose)
622 throw lang::DisposedException();
623 }
624
625