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 <AccessibleSlideSorterObject.hxx>
21
22 #include <SlideSorter.hxx>
23 #include <controller/SlideSorterController.hxx>
24 #include <controller/SlsPageSelector.hxx>
25 #include <controller/SlsFocusManager.hxx>
26 #include <model/SlideSorterModel.hxx>
27 #include <model/SlsPageDescriptor.hxx>
28 #include <view/SlideSorterView.hxx>
29 #include <view/SlsLayouter.hxx>
30 #include <view/SlsPageObjectLayouter.hxx>
31 #include <com/sun/star/accessibility/AccessibleRole.hpp>
32 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
33 #include <com/sun/star/accessibility/IllegalAccessibleComponentStateException.hpp>
34 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
35 #include <comphelper/accessibleeventnotifier.hxx>
36 #include <cppuhelper/supportsservice.hxx>
37 #include <unotools/accessiblestatesethelper.hxx>
38 #include <sal/log.hxx>
39
40 #include <sdpage.hxx>
41 #include <sdresid.hxx>
42 #include <vcl/svapp.hxx>
43 #include <vcl/settings.hxx>
44
45 #include <strings.hrc>
46
47 using namespace ::com::sun::star;
48 using namespace ::com::sun::star::uno;
49 using namespace ::com::sun::star::accessibility;
50
51 namespace accessibility {
52
AccessibleSlideSorterObject(const Reference<XAccessible> & rxParent,::sd::slidesorter::SlideSorter & rSlideSorter,sal_uInt16 nPageNumber)53 AccessibleSlideSorterObject::AccessibleSlideSorterObject(
54 const Reference<XAccessible>& rxParent,
55 ::sd::slidesorter::SlideSorter& rSlideSorter,
56 sal_uInt16 nPageNumber)
57 : AccessibleSlideSorterObjectBase(::sd::MutexOwner::maMutex),
58 mxParent(rxParent),
59 mnPageNumber(nPageNumber),
60 mrSlideSorter(rSlideSorter),
61 mnClientId(0)
62 {
63 }
64
~AccessibleSlideSorterObject()65 AccessibleSlideSorterObject::~AccessibleSlideSorterObject()
66 {
67 if ( ! IsDisposed())
68 dispose();
69 }
70
FireAccessibleEvent(short nEventId,const uno::Any & rOldValue,const uno::Any & rNewValue)71 void AccessibleSlideSorterObject::FireAccessibleEvent (
72 short nEventId,
73 const uno::Any& rOldValue,
74 const uno::Any& rNewValue)
75 {
76 if (mnClientId != 0)
77 {
78 AccessibleEventObject aEventObject;
79
80 aEventObject.Source = Reference<XWeak>(this);
81 aEventObject.EventId = nEventId;
82 aEventObject.NewValue = rNewValue;
83 aEventObject.OldValue = rOldValue;
84
85 comphelper::AccessibleEventNotifier::addEvent(mnClientId, aEventObject);
86 }
87 }
88
disposing()89 void SAL_CALL AccessibleSlideSorterObject::disposing()
90 {
91 const SolarMutexGuard aSolarGuard;
92
93 // Send a disposing to all listeners.
94 if (mnClientId != 0)
95 {
96 comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing(mnClientId, *this);
97 mnClientId = 0;
98 }
99 }
100
101 //===== XAccessible ===========================================================
102
103 Reference<XAccessibleContext> SAL_CALL
getAccessibleContext()104 AccessibleSlideSorterObject::getAccessibleContext()
105 {
106 ThrowIfDisposed();
107 return this;
108 }
109
110 //===== XAccessibleContext ====================================================
111
getAccessibleChildCount()112 sal_Int32 SAL_CALL AccessibleSlideSorterObject::getAccessibleChildCount()
113 {
114 ThrowIfDisposed();
115 return 0;
116 }
117
getAccessibleChild(sal_Int32)118 Reference<XAccessible> SAL_CALL AccessibleSlideSorterObject::getAccessibleChild (sal_Int32 )
119 {
120 ThrowIfDisposed();
121 throw lang::IndexOutOfBoundsException();
122 }
123
getAccessibleParent()124 Reference<XAccessible> SAL_CALL AccessibleSlideSorterObject::getAccessibleParent()
125 {
126 ThrowIfDisposed();
127 return mxParent;
128 }
129
getAccessibleIndexInParent()130 sal_Int32 SAL_CALL AccessibleSlideSorterObject::getAccessibleIndexInParent()
131 {
132 ThrowIfDisposed();
133 const SolarMutexGuard aSolarGuard;
134 sal_Int32 nIndexInParent(-1);
135
136 if (mxParent.is())
137 {
138 Reference<XAccessibleContext> xParentContext (mxParent->getAccessibleContext());
139 if (xParentContext.is())
140 {
141 sal_Int32 nChildCount (xParentContext->getAccessibleChildCount());
142 for (sal_Int32 i=0; i<nChildCount; ++i)
143 if (xParentContext->getAccessibleChild(i).get()
144 == static_cast<XAccessible*>(this))
145 {
146 nIndexInParent = i;
147 break;
148 }
149 }
150 }
151
152 return nIndexInParent;
153 }
154
getAccessibleRole()155 sal_Int16 SAL_CALL AccessibleSlideSorterObject::getAccessibleRole()
156 {
157 ThrowIfDisposed();
158 return AccessibleRole::SHAPE;
159 }
160
getAccessibleDescription()161 OUString SAL_CALL AccessibleSlideSorterObject::getAccessibleDescription()
162 {
163 ThrowIfDisposed();
164 return SdResId(STR_PAGE);
165 }
166
getAccessibleName()167 OUString SAL_CALL AccessibleSlideSorterObject::getAccessibleName()
168 {
169 ThrowIfDisposed();
170 const SolarMutexGuard aSolarGuard;
171
172 SdPage* pPage = GetPage();
173 if (pPage != nullptr)
174 return pPage->GetName();
175 else
176 return OUString();
177 }
178
179 Reference<XAccessibleRelationSet> SAL_CALL
getAccessibleRelationSet()180 AccessibleSlideSorterObject::getAccessibleRelationSet()
181 {
182 ThrowIfDisposed();
183 return Reference<XAccessibleRelationSet>();
184 }
185
186 Reference<XAccessibleStateSet> SAL_CALL
getAccessibleStateSet()187 AccessibleSlideSorterObject::getAccessibleStateSet()
188 {
189 ThrowIfDisposed();
190 const SolarMutexGuard aSolarGuard;
191 rtl::Reference<::utl::AccessibleStateSetHelper> pStateSet = new ::utl::AccessibleStateSetHelper();
192
193 if (mxParent.is())
194 {
195 // Unconditional states.
196 pStateSet->AddState(AccessibleStateType::SELECTABLE);
197 pStateSet->AddState(AccessibleStateType::FOCUSABLE);
198 pStateSet->AddState(AccessibleStateType::ENABLED);
199 pStateSet->AddState(AccessibleStateType::VISIBLE);
200 pStateSet->AddState(AccessibleStateType::SHOWING);
201 pStateSet->AddState(AccessibleStateType::ACTIVE);
202 pStateSet->AddState(AccessibleStateType::SENSITIVE);
203
204 // Conditional states.
205 if (mrSlideSorter.GetController().GetPageSelector().IsPageSelected(mnPageNumber))
206 pStateSet->AddState(AccessibleStateType::SELECTED);
207 if (mrSlideSorter.GetController().GetFocusManager().GetFocusedPageIndex() == mnPageNumber)
208 if (mrSlideSorter.GetController().GetFocusManager().IsFocusShowing())
209 pStateSet->AddState(AccessibleStateType::FOCUSED);
210 }
211
212 return pStateSet;
213 }
214
getLocale()215 lang::Locale SAL_CALL AccessibleSlideSorterObject::getLocale()
216 {
217 ThrowIfDisposed();
218 // Delegate request to parent.
219 if (mxParent.is())
220 {
221 Reference<XAccessibleContext> xParentContext (mxParent->getAccessibleContext());
222 if (xParentContext.is())
223 return xParentContext->getLocale ();
224 }
225
226 // No locale and no parent. Therefore throw exception to indicate this
227 // cluelessness.
228 throw IllegalAccessibleComponentStateException();
229 }
230
231 //===== XAccessibleEventBroadcaster ===========================================
232
addAccessibleEventListener(const Reference<XAccessibleEventListener> & rxListener)233 void SAL_CALL AccessibleSlideSorterObject::addAccessibleEventListener(
234 const Reference<XAccessibleEventListener>& rxListener)
235 {
236 if (!rxListener.is())
237 return;
238
239 const osl::MutexGuard aGuard(maMutex);
240
241 if (IsDisposed())
242 {
243 uno::Reference<uno::XInterface> x (static_cast<lang::XComponent *>(this), uno::UNO_QUERY);
244 rxListener->disposing (lang::EventObject (x));
245 }
246 else
247 {
248 if (mnClientId == 0)
249 mnClientId = comphelper::AccessibleEventNotifier::registerClient();
250 comphelper::AccessibleEventNotifier::addEventListener(mnClientId, rxListener);
251 }
252 }
253
removeAccessibleEventListener(const Reference<XAccessibleEventListener> & rxListener)254 void SAL_CALL AccessibleSlideSorterObject::removeAccessibleEventListener(
255 const Reference<XAccessibleEventListener>& rxListener)
256 {
257 ThrowIfDisposed();
258 if (!(rxListener.is() && mnClientId))
259 return;
260
261 const osl::MutexGuard aGuard(maMutex);
262
263 sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( mnClientId, rxListener );
264 if ( !nListenerCount )
265 {
266 // no listeners anymore
267 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
268 // and at least to us not firing any events anymore, in case somebody calls
269 // NotifyAccessibleEvent, again
270 comphelper::AccessibleEventNotifier::revokeClient( mnClientId );
271 mnClientId = 0;
272 }
273 }
274
275 //===== XAccessibleComponent ==================================================
276
containsPoint(const awt::Point & aPoint)277 sal_Bool SAL_CALL AccessibleSlideSorterObject::containsPoint(const awt::Point& aPoint)
278 {
279 ThrowIfDisposed();
280 const awt::Size aSize (getSize());
281 return (aPoint.X >= 0)
282 && (aPoint.X < aSize.Width)
283 && (aPoint.Y >= 0)
284 && (aPoint.Y < aSize.Height);
285 }
286
287 Reference<XAccessible> SAL_CALL
getAccessibleAtPoint(const awt::Point &)288 AccessibleSlideSorterObject::getAccessibleAtPoint(const awt::Point& )
289 {
290 return nullptr;
291 }
292
getBounds()293 awt::Rectangle SAL_CALL AccessibleSlideSorterObject::getBounds()
294 {
295 ThrowIfDisposed ();
296
297 const SolarMutexGuard aSolarGuard;
298
299 ::tools::Rectangle aBBox (
300 mrSlideSorter.GetView().GetLayouter().GetPageObjectLayouter()->GetBoundingBox(
301 mrSlideSorter.GetModel().GetPageDescriptor(mnPageNumber),
302 ::sd::slidesorter::view::PageObjectLayouter::Part::PageObject,
303 ::sd::slidesorter::view::PageObjectLayouter::WindowCoordinateSystem));
304
305 if (mxParent.is())
306 {
307 Reference<XAccessibleComponent> xParentComponent(mxParent->getAccessibleContext(), UNO_QUERY);
308 if (xParentComponent.is())
309 {
310 awt::Rectangle aParentBBox (xParentComponent->getBounds());
311 aBBox.Intersection(::tools::Rectangle(
312 aParentBBox.X,
313 aParentBBox.Y,
314 aParentBBox.Width,
315 aParentBBox.Height));
316 }
317 }
318
319 return awt::Rectangle(
320 aBBox.Left(),
321 aBBox.Top(),
322 aBBox.GetWidth(),
323 aBBox.GetHeight());
324 }
325
getLocation()326 awt::Point SAL_CALL AccessibleSlideSorterObject::getLocation ()
327 {
328 ThrowIfDisposed ();
329 const awt::Rectangle aBBox (getBounds());
330 return awt::Point(aBBox.X, aBBox.Y);
331 }
332
getLocationOnScreen()333 awt::Point SAL_CALL AccessibleSlideSorterObject::getLocationOnScreen()
334 {
335 ThrowIfDisposed ();
336
337 const SolarMutexGuard aSolarGuard;
338
339 awt::Point aLocation (getLocation());
340
341 if (mxParent.is())
342 {
343 Reference<XAccessibleComponent> xParentComponent(mxParent->getAccessibleContext(),UNO_QUERY);
344 if (xParentComponent.is())
345 {
346 const awt::Point aParentLocationOnScreen(xParentComponent->getLocationOnScreen());
347 aLocation.X += aParentLocationOnScreen.X;
348 aLocation.Y += aParentLocationOnScreen.Y;
349 }
350 }
351
352 return aLocation;
353 }
354
getSize()355 awt::Size SAL_CALL AccessibleSlideSorterObject::getSize()
356 {
357 ThrowIfDisposed ();
358 const awt::Rectangle aBBox (getBounds());
359 return awt::Size(aBBox.Width,aBBox.Height);
360 }
361
grabFocus()362 void SAL_CALL AccessibleSlideSorterObject::grabFocus()
363 {
364 // nothing to do
365 }
366
getForeground()367 sal_Int32 SAL_CALL AccessibleSlideSorterObject::getForeground()
368 {
369 ThrowIfDisposed ();
370 svtools::ColorConfig aColorConfig;
371 Color nColor = aColorConfig.GetColorValue( svtools::FONTCOLOR ).nColor;
372 return static_cast<sal_Int32>(nColor);
373 }
374
getBackground()375 sal_Int32 SAL_CALL AccessibleSlideSorterObject::getBackground()
376 {
377 ThrowIfDisposed ();
378 Color nColor = Application::GetSettings().GetStyleSettings().GetWindowColor();
379 return sal_Int32(nColor);
380 }
381
382 // XServiceInfo
383 OUString SAL_CALL
getImplementationName()384 AccessibleSlideSorterObject::getImplementationName()
385 {
386 return "AccessibleSlideSorterObject";
387 }
388
supportsService(const OUString & sServiceName)389 sal_Bool SAL_CALL AccessibleSlideSorterObject::supportsService (const OUString& sServiceName)
390 {
391 return cppu::supportsService(this, sServiceName);
392 }
393
394 uno::Sequence< OUString> SAL_CALL
getSupportedServiceNames()395 AccessibleSlideSorterObject::getSupportedServiceNames()
396 {
397 ThrowIfDisposed ();
398
399 return uno::Sequence<OUString> {
400 OUString("com.sun.star.accessibility.Accessible"),
401 OUString("com.sun.star.accessibility.AccessibleContext")
402 };
403 }
404
ThrowIfDisposed()405 void AccessibleSlideSorterObject::ThrowIfDisposed()
406 {
407 if (rBHelper.bDisposed || rBHelper.bInDispose)
408 {
409 SAL_WARN("sd", "Calling disposed object. Throwing exception:");
410 throw lang::DisposedException ("object has been already disposed",
411 static_cast<uno::XWeak*>(this));
412 }
413 }
414
IsDisposed() const415 bool AccessibleSlideSorterObject::IsDisposed() const
416 {
417 return (rBHelper.bDisposed || rBHelper.bInDispose);
418 }
419
GetPage() const420 SdPage* AccessibleSlideSorterObject::GetPage() const
421 {
422 ::sd::slidesorter::model::SharedPageDescriptor pDescriptor(
423 mrSlideSorter.GetModel().GetPageDescriptor(mnPageNumber));
424 if (pDescriptor)
425 return pDescriptor->GetPage();
426 else
427 return nullptr;
428 }
429
430 } // end of namespace ::accessibility
431
432 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
433