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 152 : 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 152 : maRole(aRole)
49 : {
50 152 : }
51 :
52 272 : ScAccessibleContextBase::~ScAccessibleContextBase(void)
53 : {
54 136 : 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 136 : }
62 :
63 100 : void ScAccessibleContextBase::Init()
64 : {
65 : // hold reference to make sure that the destructor is not called
66 100 : uno::Reference< XAccessibleContext > xOwnContext(this);
67 :
68 100 : if (mxParent.is())
69 : {
70 100 : uno::Reference< XAccessibleEventBroadcaster > xBroadcaster (mxParent->getAccessibleContext(), uno::UNO_QUERY);
71 100 : if (xBroadcaster.is())
72 100 : xBroadcaster->addAccessibleEventListener(this);
73 : }
74 100 : msName = createAccessibleName();
75 100 : msDescription = createAccessibleDescription();
76 100 : }
77 :
78 152 : void SAL_CALL ScAccessibleContextBase::disposing()
79 : {
80 152 : 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 304 : uno::Reference< XAccessibleContext > xOwnContext(this);
85 :
86 152 : if ( mnClientId )
87 : {
88 34 : sal_Int32 nTemClientId(mnClientId);
89 34 : mnClientId = 0;
90 34 : comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( nTemClientId, *this );
91 : }
92 :
93 152 : if (mxParent.is())
94 : {
95 152 : uno::Reference< XAccessibleEventBroadcaster > xBroadcaster (mxParent->getAccessibleContext(), uno::UNO_QUERY);
96 152 : if (xBroadcaster.is())
97 152 : xBroadcaster->removeAccessibleEventListener(this);
98 152 : mxParent = NULL;
99 : }
100 :
101 304 : ScAccessibleContextBaseWeakImpl::disposing();
102 152 : }
103 :
104 : //===== XInterface =====================================================
105 :
106 1040 : uno::Any SAL_CALL ScAccessibleContextBase::queryInterface( uno::Type const & rType )
107 : throw (uno::RuntimeException, std::exception)
108 : {
109 1040 : uno::Any aAny (ScAccessibleContextBaseWeakImpl::queryInterface(rType));
110 1040 : return aAny.hasValue() ? aAny : ScAccessibleContextBaseImplEvent::queryInterface(rType);
111 : }
112 :
113 8538 : void SAL_CALL ScAccessibleContextBase::acquire()
114 : throw ()
115 : {
116 8538 : ScAccessibleContextBaseWeakImpl::acquire();
117 8538 : }
118 :
119 8522 : void SAL_CALL ScAccessibleContextBase::release()
120 : throw ()
121 : {
122 8522 : ScAccessibleContextBaseWeakImpl::release();
123 8522 : }
124 :
125 : //===== SfxListener =====================================================
126 :
127 436 : void ScAccessibleContextBase::Notify( SfxBroadcaster&, const SfxHint& rHint )
128 : {
129 436 : const SfxSimpleHint* pSimpleHint = dynamic_cast<const SfxSimpleHint*>(&rHint);
130 436 : if (pSimpleHint)
131 : {
132 300 : if (pSimpleHint->GetId() == SFX_HINT_DYING)
133 : {
134 : // it seems the Broadcaster is dying, since the view is dying
135 42 : dispose();
136 : }
137 : }
138 436 : }
139 :
140 : //===== XAccessible =========================================================
141 :
142 : uno::Reference< XAccessibleContext> SAL_CALL
143 1380 : ScAccessibleContextBase::getAccessibleContext(void)
144 : throw (uno::RuntimeException, std::exception)
145 : {
146 1380 : return this;
147 : }
148 :
149 : //===== XAccessibleComponent ================================================
150 :
151 1980 : sal_Bool SAL_CALL ScAccessibleContextBase::containsPoint(const awt::Point& rPoint )
152 : throw (uno::RuntimeException, std::exception)
153 : {
154 1980 : SolarMutexGuard aGuard;
155 1980 : IsObjectValid();
156 1980 : 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 946 : awt::Rectangle SAL_CALL ScAccessibleContextBase::getBounds( )
168 : throw (uno::RuntimeException, std::exception)
169 : {
170 946 : SolarMutexGuard aGuard;
171 946 : IsObjectValid();
172 946 : return AWTRectangle(GetBoundingBox());
173 : }
174 :
175 8 : awt::Point SAL_CALL ScAccessibleContextBase::getLocation( )
176 : throw (uno::RuntimeException, std::exception)
177 : {
178 8 : SolarMutexGuard aGuard;
179 8 : IsObjectValid();
180 8 : return AWTPoint(GetBoundingBox().TopLeft());
181 : }
182 :
183 16 : awt::Point SAL_CALL ScAccessibleContextBase::getLocationOnScreen( )
184 : throw (uno::RuntimeException, std::exception)
185 : {
186 16 : SolarMutexGuard aGuard;
187 16 : IsObjectValid();
188 16 : return AWTPoint(GetBoundingBoxOnScreen().TopLeft());
189 : }
190 :
191 8 : awt::Size SAL_CALL ScAccessibleContextBase::getSize( )
192 : throw (uno::RuntimeException, std::exception)
193 : {
194 8 : SolarMutexGuard aGuard;
195 8 : IsObjectValid();
196 8 : return AWTSize(GetBoundingBox().GetSize());
197 : }
198 :
199 436 : bool SAL_CALL ScAccessibleContextBase::isShowing( )
200 : throw (uno::RuntimeException)
201 : {
202 436 : SolarMutexGuard aGuard;
203 436 : IsObjectValid();
204 436 : bool bShowing(false);
205 436 : if (mxParent.is())
206 : {
207 436 : uno::Reference<XAccessibleComponent> xParentComponent (mxParent->getAccessibleContext(), uno::UNO_QUERY);
208 436 : if (xParentComponent.is())
209 : {
210 436 : Rectangle aParentBounds(VCLRectangle(xParentComponent->getBounds()));
211 436 : Rectangle aBounds(VCLRectangle(getBounds()));
212 436 : bShowing = aBounds.IsOver(aParentBounds);
213 436 : }
214 : }
215 436 : return bShowing;
216 : }
217 :
218 394 : bool SAL_CALL ScAccessibleContextBase::isVisible()
219 : throw (uno::RuntimeException, std::exception)
220 : {
221 394 : 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 6 : sal_Int32 SAL_CALL ScAccessibleContextBase::getForeground( )
231 : throw (uno::RuntimeException, std::exception)
232 : {
233 6 : return COL_BLACK;
234 : }
235 :
236 6 : sal_Int32 SAL_CALL ScAccessibleContextBase::getBackground( )
237 : throw (uno::RuntimeException, std::exception)
238 : {
239 6 : 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 1690 : ScAccessibleContextBase::getAccessibleParent(void)
262 : throw (uno::RuntimeException, std::exception)
263 : {
264 1690 : return mxParent;
265 : }
266 :
267 : sal_Int32 SAL_CALL
268 6 : ScAccessibleContextBase::getAccessibleIndexInParent(void)
269 : throw (uno::RuntimeException, std::exception)
270 : {
271 6 : SolarMutexGuard aGuard;
272 6 : 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 6 : sal_Int32 nIndex(-1);
277 :
278 : // Iterate over all the parent's children and search for this object.
279 6 : if (mxParent.is())
280 : {
281 : uno::Reference<XAccessibleContext> xParentContext (
282 6 : mxParent->getAccessibleContext());
283 6 : if (xParentContext.is())
284 : {
285 6 : sal_Int32 nChildCount = xParentContext->getAccessibleChildCount();
286 24 : for (sal_Int32 i=0; i<nChildCount; ++i)
287 : {
288 18 : uno::Reference<XAccessible> xChild (xParentContext->getAccessibleChild (i));
289 18 : if (xChild.is())
290 : {
291 18 : if (xChild.get() == this)
292 18 : nIndex = i;
293 : }
294 18 : }
295 6 : }
296 : }
297 :
298 6 : return nIndex;
299 : }
300 :
301 : sal_Int16 SAL_CALL
302 304 : ScAccessibleContextBase::getAccessibleRole(void)
303 : throw (uno::RuntimeException, std::exception)
304 : {
305 304 : return maRole;
306 : }
307 :
308 : OUString SAL_CALL
309 158 : ScAccessibleContextBase::getAccessibleDescription(void)
310 : throw (uno::RuntimeException, std::exception)
311 : {
312 158 : SolarMutexGuard aGuard;
313 158 : IsObjectValid();
314 158 : if (msDescription.isEmpty())
315 : {
316 158 : OUString sDescription(createAccessibleDescription());
317 :
318 158 : 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 158 : }
330 : }
331 158 : return msDescription;
332 : }
333 :
334 : OUString SAL_CALL
335 136 : ScAccessibleContextBase::getAccessibleName(void)
336 : throw (uno::RuntimeException, std::exception)
337 : {
338 136 : SolarMutexGuard aGuard;
339 136 : IsObjectValid();
340 136 : if (msName.isEmpty())
341 : {
342 26 : OUString sName(createAccessibleName());
343 : OSL_ENSURE(!sName.isEmpty(), "We should give always a name.");
344 :
345 26 : if (msName != sName)
346 : {
347 4 : AccessibleEventObject aEvent;
348 4 : aEvent.EventId = AccessibleEventId::NAME_CHANGED;
349 4 : aEvent.Source = uno::Reference< XAccessibleContext >(this);
350 4 : aEvent.OldValue <<= msName;
351 4 : aEvent.NewValue <<= sName;
352 :
353 4 : msName = sName;
354 :
355 4 : CommitChange(aEvent);
356 26 : }
357 : }
358 136 : return msName;
359 : }
360 :
361 : uno::Reference<XAccessibleRelationSet> SAL_CALL
362 8 : ScAccessibleContextBase::getAccessibleRelationSet()
363 : throw (uno::RuntimeException, std::exception)
364 : {
365 8 : return new utl::AccessibleRelationSetHelper();
366 : }
367 :
368 : uno::Reference<XAccessibleStateSet> SAL_CALL
369 0 : ScAccessibleContextBase::getAccessibleStateSet(void)
370 : throw (uno::RuntimeException, std::exception)
371 : {
372 0 : return uno::Reference<XAccessibleStateSet>();
373 : }
374 :
375 : lang::Locale SAL_CALL
376 26 : ScAccessibleContextBase::getLocale(void)
377 : throw (IllegalAccessibleComponentStateException,
378 : uno::RuntimeException, std::exception)
379 : {
380 26 : SolarMutexGuard aGuard;
381 26 : IsObjectValid();
382 26 : if (mxParent.is())
383 : {
384 : uno::Reference<XAccessibleContext> xParentContext (
385 26 : mxParent->getAccessibleContext());
386 26 : if (xParentContext.is())
387 52 : return xParentContext->getLocale ();
388 : }
389 :
390 : // No locale and no parent. Therefore throw exception to indicate this
391 : // cluelessness.
392 26 : throw IllegalAccessibleComponentStateException ();
393 : }
394 :
395 : //===== XAccessibleEventBroadcaster =====================================
396 :
397 : void SAL_CALL
398 92 : ScAccessibleContextBase::addAccessibleEventListener(
399 : const uno::Reference<XAccessibleEventListener>& xListener)
400 : throw (uno::RuntimeException, std::exception)
401 : {
402 92 : if (xListener.is())
403 : {
404 92 : SolarMutexGuard aGuard;
405 92 : IsObjectValid();
406 92 : if (!IsDefunc())
407 : {
408 92 : if (!mnClientId)
409 58 : mnClientId = comphelper::AccessibleEventNotifier::registerClient( );
410 92 : comphelper::AccessibleEventNotifier::addEventListener( mnClientId, xListener );
411 92 : }
412 : }
413 92 : }
414 :
415 : void SAL_CALL
416 144 : ScAccessibleContextBase::removeAccessibleEventListener(
417 : const uno::Reference<XAccessibleEventListener>& xListener)
418 : throw (uno::RuntimeException, std::exception)
419 : {
420 144 : if (xListener.is())
421 : {
422 144 : SolarMutexGuard aGuard;
423 144 : if (!IsDefunc() && mnClientId)
424 : {
425 26 : sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( mnClientId, xListener );
426 26 : 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 24 : comphelper::AccessibleEventNotifier::revokeClient( mnClientId );
433 24 : mnClientId = 0;
434 : }
435 144 : }
436 : }
437 144 : }
438 :
439 : //===== XAccessibleEventListener ========================================
440 :
441 66 : void SAL_CALL ScAccessibleContextBase::disposing(
442 : const lang::EventObject& rSource )
443 : throw (uno::RuntimeException, std::exception)
444 : {
445 66 : SolarMutexGuard aGuard;
446 66 : if (rSource.Source == mxParent)
447 66 : dispose();
448 66 : }
449 :
450 162 : void SAL_CALL ScAccessibleContextBase::notifyEvent(
451 : const AccessibleEventObject& /* aEvent */ )
452 : throw (uno::RuntimeException, std::exception)
453 : {
454 162 : }
455 :
456 : //===== XServiceInfo ========================================================
457 0 : OUString SAL_CALL ScAccessibleContextBase::getImplementationName(void)
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(void)
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(void)
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(void)
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 146 : void ScAccessibleContextBase::CommitChange(const AccessibleEventObject& rEvent) const
517 : {
518 146 : if (mnClientId)
519 102 : comphelper::AccessibleEventNotifier::addEvent( mnClientId, rEvent );
520 146 : }
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 20 : void ScAccessibleContextBase::CommitFocusLost() const
535 : {
536 20 : AccessibleEventObject aEvent;
537 20 : aEvent.EventId = AccessibleEventId::STATE_CHANGED;
538 20 : aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this));
539 20 : aEvent.OldValue <<= AccessibleStateType::FOCUSED;
540 :
541 20 : CommitChange(aEvent);
542 :
543 20 : vcl::unohelper::NotifyAccessibleStateEventGlobally(aEvent);
544 20 : }
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 4694 : void ScAccessibleContextBase::IsObjectValid() const
561 : throw (lang::DisposedException)
562 : {
563 4694 : if (rBHelper.bDisposed || rBHelper.bInDispose)
564 0 : throw lang::DisposedException();
565 4922 : }
566 :
567 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|