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