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