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 {
129 uno::Any aAny (ScAccessibleContextBaseWeakImpl::queryInterface(rType));
130 return aAny.hasValue() ? aAny : ScAccessibleContextBaseImplEvent::queryInterface(rType);
131 }
132
acquire()133 void SAL_CALL ScAccessibleContextBase::acquire()
134 throw ()
135 {
136 ScAccessibleContextBaseWeakImpl::acquire();
137 }
138
release()139 void SAL_CALL ScAccessibleContextBase::release()
140 throw ()
141 {
142 ScAccessibleContextBaseWeakImpl::release();
143 }
144
145 //===== SfxListener =====================================================
146
Notify(SfxBroadcaster &,const SfxHint & rHint)147 void ScAccessibleContextBase::Notify( SfxBroadcaster&, const SfxHint& rHint )
148 {
149 if (rHint.ISA( SfxSimpleHint ) )
150 {
151 const SfxSimpleHint& rRef = (const SfxSimpleHint&)rHint;
152 if (rRef.GetId() == SFX_HINT_DYING)
153 {
154 // it seems the Broadcaster is dying, since the view is dying
155 dispose();
156 }
157 }
158 }
159
160 //===== XAccessible =========================================================
161
162 uno::Reference< XAccessibleContext> SAL_CALL
getAccessibleContext(void)163 ScAccessibleContextBase::getAccessibleContext(void)
164 {
165 return this;
166 }
167
168 //===== XAccessibleComponent ================================================
169
containsPoint(const awt::Point & rPoint)170 sal_Bool SAL_CALL ScAccessibleContextBase::containsPoint(const awt::Point& rPoint )
171 {
172 ScUnoGuard aGuard;
173 IsObjectValid();
174 return Rectangle (Point(), GetBoundingBox().GetSize()).IsInside(VCLPoint(rPoint));
175 }
176
getAccessibleAtPoint(const awt::Point &)177 uno::Reference< XAccessible > SAL_CALL ScAccessibleContextBase::getAccessibleAtPoint(
178 const awt::Point& /* rPoint */ )
179 {
180 DBG_ERROR("not implemented");
181 return uno::Reference<XAccessible>();
182 }
183
getBounds()184 awt::Rectangle SAL_CALL ScAccessibleContextBase::getBounds( )
185 {
186 ScUnoGuard aGuard;
187 IsObjectValid();
188 return AWTRectangle(GetBoundingBox());
189 }
190
getLocation()191 awt::Point SAL_CALL ScAccessibleContextBase::getLocation( )
192 {
193 ScUnoGuard aGuard;
194 IsObjectValid();
195 return AWTPoint(GetBoundingBox().TopLeft());
196 }
197
getLocationOnScreen()198 awt::Point SAL_CALL ScAccessibleContextBase::getLocationOnScreen( )
199 {
200 ScUnoGuard aGuard;
201 IsObjectValid();
202 return AWTPoint(GetBoundingBoxOnScreen().TopLeft());
203 }
204
getSize()205 awt::Size SAL_CALL ScAccessibleContextBase::getSize( )
206 {
207 ScUnoGuard aGuard;
208 IsObjectValid();
209 return AWTSize(GetBoundingBox().GetSize());
210 }
211
isShowing()212 sal_Bool SAL_CALL ScAccessibleContextBase::isShowing( )
213 {
214 ScUnoGuard aGuard;
215 IsObjectValid();
216 sal_Bool bShowing(sal_False);
217 if (mxParent.is())
218 {
219 uno::Reference<XAccessibleComponent> xParentComponent (mxParent->getAccessibleContext(), uno::UNO_QUERY);
220 if (xParentComponent.is())
221 {
222 Rectangle aParentBounds(VCLRectangle(xParentComponent->getBounds()));
223 Rectangle aBounds(VCLRectangle(getBounds()));
224 bShowing = aBounds.IsOver(aParentBounds);
225 }
226 }
227 return bShowing;
228 }
229
isVisible()230 sal_Bool SAL_CALL ScAccessibleContextBase::isVisible( )
231 {
232 return sal_True;
233 }
234
grabFocus()235 void SAL_CALL ScAccessibleContextBase::grabFocus( )
236 {
237 DBG_ERROR("not implemented");
238 }
239
getForeground()240 sal_Int32 SAL_CALL ScAccessibleContextBase::getForeground( )
241 {
242 return COL_BLACK;
243 }
244
getBackground()245 sal_Int32 SAL_CALL ScAccessibleContextBase::getBackground( )
246 {
247 return COL_WHITE;
248 }
249
250 //===== XAccessibleContext ==================================================
251
252 sal_Int32 SAL_CALL
getAccessibleChildCount(void)253 ScAccessibleContextBase::getAccessibleChildCount(void)
254 {
255 DBG_ERROR("should be implemented in the abrevated class");
256 return 0;
257 }
258
259 uno::Reference<XAccessible> SAL_CALL
getAccessibleChild(sal_Int32)260 ScAccessibleContextBase::getAccessibleChild(sal_Int32 /* nIndex */)
261 {
262 DBG_ERROR("should be implemented in the abrevated class");
263 return uno::Reference<XAccessible>();
264 }
265
266 uno::Reference<XAccessible> SAL_CALL
getAccessibleParent(void)267 ScAccessibleContextBase::getAccessibleParent(void)
268 {
269 return mxParent;
270 }
271
272 sal_Int32 SAL_CALL
getAccessibleIndexInParent(void)273 ScAccessibleContextBase::getAccessibleIndexInParent(void)
274 {
275 ScUnoGuard aGuard;
276 IsObjectValid();
277 // Use a simple but slow solution for now. Optimize later.
278 // Return -1 to indicate that this object's parent does not know about the
279 // object.
280 sal_Int32 nIndex(-1);
281
282 // Iterate over all the parent's children and search for this object.
283 if (mxParent.is())
284 {
285 uno::Reference<XAccessibleContext> xParentContext (
286 mxParent->getAccessibleContext());
287 if (xParentContext.is())
288 {
289 sal_Int32 nChildCount = xParentContext->getAccessibleChildCount();
290 for (sal_Int32 i=0; i<nChildCount; ++i)
291 {
292 uno::Reference<XAccessible> xChild (xParentContext->getAccessibleChild (i));
293 if (xChild.is())
294 {
295 if (xChild.get() == this)
296 nIndex = i;
297 }
298 }
299 }
300 }
301
302 return nIndex;
303 }
304
305 sal_Int16 SAL_CALL
getAccessibleRole(void)306 ScAccessibleContextBase::getAccessibleRole(void)
307 {
308 return maRole;
309 }
310
311 ::rtl::OUString SAL_CALL
getAccessibleDescription(void)312 ScAccessibleContextBase::getAccessibleDescription(void)
313 {
314 ScUnoGuard aGuard;
315 IsObjectValid();
316 if (!msDescription.getLength())
317 {
318 OUString sDescription(createAccessibleDescription());
319 // DBG_ASSERT(sDescription.getLength(), "We should give always a description.");
320
321 if (msDescription != sDescription)
322 {
323 AccessibleEventObject aEvent;
324 aEvent.EventId = AccessibleEventId::DESCRIPTION_CHANGED;
325 aEvent.Source = uno::Reference< XAccessibleContext >(this);
326 aEvent.OldValue <<= msDescription;
327 aEvent.NewValue <<= sDescription;
328
329 msDescription = sDescription;
330
331 CommitChange(aEvent);
332 }
333 }
334 return msDescription;
335 }
336
337 OUString SAL_CALL
getAccessibleName(void)338 ScAccessibleContextBase::getAccessibleName(void)
339 {
340 ScUnoGuard aGuard;
341 IsObjectValid();
342 if (!msName.getLength())
343 {
344 OUString sName(createAccessibleName());
345 DBG_ASSERT(sName.getLength(), "We should give always a name.");
346
347 if (msName != sName)
348 {
349 AccessibleEventObject aEvent;
350 aEvent.EventId = AccessibleEventId::NAME_CHANGED;
351 aEvent.Source = uno::Reference< XAccessibleContext >(this);
352 aEvent.OldValue <<= msName;
353 aEvent.NewValue <<= sName;
354
355 msName = sName;
356
357 CommitChange(aEvent);
358 }
359 }
360 return msName;
361 }
362
363 uno::Reference<XAccessibleRelationSet> SAL_CALL
getAccessibleRelationSet(void)364 ScAccessibleContextBase::getAccessibleRelationSet(void)
365 {
366 return new utl::AccessibleRelationSetHelper();
367 }
368
369 uno::Reference<XAccessibleStateSet> SAL_CALL
getAccessibleStateSet(void)370 ScAccessibleContextBase::getAccessibleStateSet(void)
371 {
372 return uno::Reference<XAccessibleStateSet>();
373 }
374
375 lang::Locale SAL_CALL
getLocale(void)376 ScAccessibleContextBase::getLocale(void)
377 {
378 ScUnoGuard aGuard;
379 IsObjectValid();
380 if (mxParent.is())
381 {
382 uno::Reference<XAccessibleContext> xParentContext (
383 mxParent->getAccessibleContext());
384 if (xParentContext.is())
385 return xParentContext->getLocale ();
386 }
387
388 // No locale and no parent. Therefore throw exception to indicate this
389 // cluelessness.
390 throw IllegalAccessibleComponentStateException ();
391 }
392
393 //===== XAccessibleEventBroadcaster =====================================
394
395 void SAL_CALL
addEventListener(const uno::Reference<XAccessibleEventListener> & xListener)396 ScAccessibleContextBase::addEventListener(
397 const uno::Reference<XAccessibleEventListener>& xListener)
398 {
399 if (xListener.is())
400 {
401 ScUnoGuard aGuard;
402 IsObjectValid();
403 if (!IsDefunc())
404 {
405 if (!mnClientId)
406 mnClientId = comphelper::AccessibleEventNotifier::registerClient( );
407 comphelper::AccessibleEventNotifier::addEventListener( mnClientId, xListener );
408 }
409 }
410 }
411
412 void SAL_CALL
removeEventListener(const uno::Reference<XAccessibleEventListener> & xListener)413 ScAccessibleContextBase::removeEventListener(
414 const uno::Reference<XAccessibleEventListener>& xListener)
415 {
416 if (xListener.is())
417 {
418 ScUnoGuard aGuard;
419 if (!IsDefunc() && mnClientId)
420 {
421 sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( mnClientId, xListener );
422 if ( !nListenerCount )
423 {
424 // no listeners anymore
425 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
426 // and at least to us not firing any events anymore, in case somebody calls
427 // NotifyAccessibleEvent, again
428 comphelper::AccessibleEventNotifier::revokeClient( mnClientId );
429 mnClientId = 0;
430 }
431 }
432 }
433 }
434
435 //===== XAccessibleEventListener ========================================
436
disposing(const lang::EventObject & rSource)437 void SAL_CALL ScAccessibleContextBase::disposing(
438 const lang::EventObject& rSource )
439 {
440 ScUnoGuard aGuard;
441 if (rSource.Source == mxParent)
442 dispose();
443 }
444
notifyEvent(const AccessibleEventObject &)445 void SAL_CALL ScAccessibleContextBase::notifyEvent(
446 const AccessibleEventObject& /* aEvent */ )
447 {
448 }
449
450 //===== XServiceInfo ========================================================
451
452 ::rtl::OUString SAL_CALL
getImplementationName(void)453 ScAccessibleContextBase::getImplementationName(void)
454 {
455 return OUString(RTL_CONSTASCII_USTRINGPARAM ("ScAccessibleContextBase"));
456 }
457
458 sal_Bool SAL_CALL
supportsService(const OUString & sServiceName)459 ScAccessibleContextBase::supportsService(const OUString& sServiceName)
460 {
461 // Iterate over all supported service names and return true if on of them
462 // matches the given name.
463 uno::Sequence< ::rtl::OUString> aSupportedServices (
464 getSupportedServiceNames ());
465 sal_Int32 nLength(aSupportedServices.getLength());
466 const OUString* pServiceNames = aSupportedServices.getConstArray();
467 for (int i=0; i<nLength; ++i, ++pServiceNames)
468 if (sServiceName == *pServiceNames)
469 return sal_True;
470 return sal_False;
471 }
472
473 uno::Sequence< ::rtl::OUString> SAL_CALL
getSupportedServiceNames(void)474 ScAccessibleContextBase::getSupportedServiceNames(void)
475 {
476 uno::Sequence<OUString> aServiceNames(2);
477 OUString* pServiceNames = aServiceNames.getArray();
478 if (pServiceNames)
479 {
480 pServiceNames[0] = OUString(RTL_CONSTASCII_USTRINGPARAM ("com.sun.star.accessibility.Accessible"));
481 pServiceNames[1] = OUString(RTL_CONSTASCII_USTRINGPARAM ("com.sun.star.accessibility.AccessibleContext"));
482 }
483
484 return aServiceNames;
485 }
486
487 //===== XTypeProvider =======================================================
488
getTypes()489 uno::Sequence< uno::Type > SAL_CALL ScAccessibleContextBase::getTypes()
490 {
491 return comphelper::concatSequences(ScAccessibleContextBaseWeakImpl::getTypes(), ScAccessibleContextBaseImplEvent::getTypes());
492 }
493
494 uno::Sequence<sal_Int8> SAL_CALL
getImplementationId(void)495 ScAccessibleContextBase::getImplementationId(void)
496 {
497 ScUnoGuard aGuard;
498 IsObjectValid();
499 static uno::Sequence<sal_Int8> aId;
500 if (aId.getLength() == 0)
501 {
502 aId.realloc (16);
503 rtl_createUuid (reinterpret_cast<sal_uInt8 *>(aId.getArray()), 0, sal_True);
504 }
505 return aId;
506 }
507
508 //===== internal ============================================================
509
510 ::rtl::OUString SAL_CALL
createAccessibleDescription(void)511 ScAccessibleContextBase::createAccessibleDescription(void)
512 {
513 DBG_ERROR("should be implemented in the abrevated class");
514 return rtl::OUString();
515 }
516
517 ::rtl::OUString SAL_CALL
createAccessibleName(void)518 ScAccessibleContextBase::createAccessibleName(void)
519 {
520 DBG_ERROR("should be implemented in the abrevated class");
521 return rtl::OUString();
522 }
523
CommitChange(const AccessibleEventObject & rEvent) const524 void ScAccessibleContextBase::CommitChange(const AccessibleEventObject& rEvent) const
525 {
526 if (mnClientId)
527 comphelper::AccessibleEventNotifier::addEvent( mnClientId, rEvent );
528 }
529
ChangeName()530 void ScAccessibleContextBase::ChangeName()
531 {
532 AccessibleEventObject aEvent;
533 aEvent.EventId = AccessibleEventId::NAME_CHANGED;
534 aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this));
535 aEvent.OldValue <<= msName;
536
537 msName = rtl::OUString(); // reset the name so it will be hold again
538 getAccessibleName(); // create the new name
539
540 aEvent.NewValue <<= msName;
541
542 CommitChange(aEvent);
543 }
544
CommitFocusGained() const545 void ScAccessibleContextBase::CommitFocusGained() const
546 {
547 AccessibleEventObject aEvent;
548 aEvent.EventId = AccessibleEventId::STATE_CHANGED;
549 aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this));
550 aEvent.NewValue <<= AccessibleStateType::FOCUSED;
551
552 CommitChange(aEvent);
553
554 ::vcl::unohelper::NotifyAccessibleStateEventGlobally(aEvent);
555 }
556
CommitFocusLost() const557 void ScAccessibleContextBase::CommitFocusLost() const
558 {
559 AccessibleEventObject aEvent;
560 aEvent.EventId = AccessibleEventId::STATE_CHANGED;
561 aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this));
562 aEvent.OldValue <<= AccessibleStateType::FOCUSED;
563
564 CommitChange(aEvent);
565
566 vcl::unohelper::NotifyAccessibleStateEventGlobally(aEvent);
567 }
568
GetBoundingBoxOnScreen(void) const569 Rectangle ScAccessibleContextBase::GetBoundingBoxOnScreen(void) const
570 {
571 DBG_ERROR("not implemented");
572 return Rectangle();
573 }
574
GetBoundingBox(void) const575 Rectangle ScAccessibleContextBase::GetBoundingBox(void) const
576 {
577 DBG_ERROR("not implemented");
578 return Rectangle();
579 }
580
IsObjectValid() const581 void ScAccessibleContextBase::IsObjectValid() const
582 {
583 if (rBHelper.bDisposed || rBHelper.bInDispose)
584 throw lang::DisposedException();
585 }
586