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