1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25
26 #include "precompiled_sc.hxx"
27 #include "AccessibleGlobal.hxx"
28 #include "AccessibleFilterMenu.hxx"
29 #include "AccessibleFilterMenuItem.hxx"
30 #include "unoguard.hxx"
31 #include "global.hxx"
32 #include "document.hxx"
33 #include "docpool.hxx"
34
35 #include "tools/gen.hxx"
36 #include "editeng/unoedsrc.hxx"
37 #include "editeng/editdata.hxx"
38 #include "editeng/outliner.hxx"
39 #include "vcl/unohelp.hxx"
40 #include "dpcontrol.hxx"
41
42 #include <com/sun/star/accessibility/XAccessible.hpp>
43 #include <com/sun/star/accessibility/XAccessibleStateSet.hpp>
44 #include <com/sun/star/accessibility/AccessibleRole.hpp>
45 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
46 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
47
48 using namespace ::com::sun::star;
49 using namespace ::com::sun::star::accessibility;
50 using namespace ::com::sun::star::accessibility::AccessibleStateType;
51
52 using ::com::sun::star::uno::Any;
53 using ::com::sun::star::uno::Reference;
54 using ::com::sun::star::uno::Sequence;
55 using ::com::sun::star::uno::UNO_QUERY;
56 using ::com::sun::star::lang::IndexOutOfBoundsException;
57 using ::com::sun::star::lang::IllegalArgumentException;
58 using ::com::sun::star::uno::RuntimeException;
59 using ::rtl::OUString;
60 using ::std::for_each;
61 using ::std::vector;
62
63 // ============================================================================
64
65 namespace {
66
67 class AddRemoveEventListener : public ::std::unary_function<void, Reference<XAccessible> >
68 {
69 public:
AddRemoveEventListener(const Reference<XAccessibleEventListener> & rListener,bool bAdd)70 explicit AddRemoveEventListener(const Reference<XAccessibleEventListener>& rListener, bool bAdd) :
71 mxListener(rListener), mbAdd(bAdd) {}
72
operator ()(const Reference<XAccessible> & xAccessible) const73 void operator() (const Reference<XAccessible>& xAccessible) const
74 {
75 if (!xAccessible.is())
76 return;
77
78 Reference<XAccessibleEventBroadcaster> xBc(xAccessible, UNO_QUERY);
79 if (xBc.is())
80 {
81 if (mbAdd)
82 xBc->addEventListener(mxListener);
83 else
84 xBc->removeEventListener(mxListener);
85 }
86 }
87 private:
88 Reference<XAccessibleEventListener> mxListener;
89 bool mbAdd;
90 };
91
92 }
93
94 // ============================================================================
95
ScAccessibleFilterMenu(const Reference<XAccessible> & rxParent,ScMenuFloatingWindow * pWin,const OUString & rName,size_t nMenuPos,ScDocument * pDoc)96 ScAccessibleFilterMenu::ScAccessibleFilterMenu(const Reference<XAccessible>& rxParent, ScMenuFloatingWindow* pWin, const OUString& rName, size_t nMenuPos, ScDocument* pDoc) :
97 ScAccessibleContextBase(rxParent, AccessibleRole::MENU),
98 mnMenuPos(nMenuPos),
99 mpWindow(pWin),
100 mpDoc(pDoc),
101 mbEnabled(true)
102 {
103 SetName(rName);
104 }
105
~ScAccessibleFilterMenu()106 ScAccessibleFilterMenu::~ScAccessibleFilterMenu()
107 {
108 }
109
110 // XAccessibleComponent
111
getAccessibleAtPoint(const::com::sun::star::awt::Point &)112 Reference<XAccessible> ScAccessibleFilterMenu::getAccessibleAtPoint( const ::com::sun::star::awt::Point& /*rPoint*/ )
113 throw (RuntimeException)
114 {
115 return this;
116 }
117
isVisible()118 sal_Bool ScAccessibleFilterMenu::isVisible() throw (RuntimeException)
119 {
120 return mpWindow->IsVisible();
121 }
122
grabFocus()123 void ScAccessibleFilterMenu::grabFocus()
124 throw (RuntimeException)
125 {
126 }
127
getForeground()128 sal_Int32 ScAccessibleFilterMenu::getForeground()
129 throw (RuntimeException)
130 {
131 return 0;
132 }
133
getBackground()134 sal_Int32 ScAccessibleFilterMenu::getBackground()
135 throw (RuntimeException)
136 {
137 return 0;
138 }
139
140 // XAccessibleContext
141
getAccessibleName()142 OUString ScAccessibleFilterMenu::getAccessibleName() throw (RuntimeException)
143 {
144 return ScAccessibleContextBase::getAccessibleName();
145 }
146
getAccessibleChildCount()147 sal_Int32 ScAccessibleFilterMenu::getAccessibleChildCount()
148 throw (RuntimeException)
149 {
150 return getMenuItemCount();
151 }
152
getAccessibleChild(sal_Int32 nIndex)153 Reference<XAccessible> ScAccessibleFilterMenu::getAccessibleChild(sal_Int32 nIndex)
154 throw (RuntimeException, IndexOutOfBoundsException)
155 {
156 if (maMenuItems.size() <= static_cast<size_t>(nIndex))
157 throw IndexOutOfBoundsException();
158
159 return maMenuItems[nIndex];
160 }
161
getAccessibleStateSet()162 Reference<XAccessibleStateSet> ScAccessibleFilterMenu::getAccessibleStateSet()
163 throw (RuntimeException)
164 {
165 updateStates();
166 return mxStateSet;
167 }
168
getImplementationName()169 OUString ScAccessibleFilterMenu::getImplementationName()
170 throw (RuntimeException)
171 {
172 return OUString::createFromAscii("ScAccessibleFilterMenu");
173 }
174
175 // XAccessibleEventBroadcaster
176
addEventListener(const::com::sun::star::uno::Reference<::com::sun::star::accessibility::XAccessibleEventListener> & xListener)177 void ScAccessibleFilterMenu::addEventListener(
178 const ::com::sun::star::uno::Reference<
179 ::com::sun::star::accessibility::XAccessibleEventListener>& xListener)
180 throw (com::sun::star::uno::RuntimeException)
181 {
182 ScAccessibleContextBase::addEventListener(xListener);
183 for_each(maMenuItems.begin(), maMenuItems.end(), AddRemoveEventListener(xListener, true));
184 }
185
removeEventListener(const::com::sun::star::uno::Reference<::com::sun::star::accessibility::XAccessibleEventListener> & xListener)186 void ScAccessibleFilterMenu::removeEventListener(
187 const ::com::sun::star::uno::Reference<
188 ::com::sun::star::accessibility::XAccessibleEventListener>& xListener)
189 throw (com::sun::star::uno::RuntimeException)
190 {
191 ScAccessibleContextBase::removeEventListener(xListener);
192 for_each(maMenuItems.begin(), maMenuItems.end(), AddRemoveEventListener(xListener, false));
193 }
194
195 // XAccessibleSelection
196
selectAccessibleChild(sal_Int32 nChildIndex)197 void ScAccessibleFilterMenu::selectAccessibleChild(sal_Int32 nChildIndex)
198 throw (IndexOutOfBoundsException, RuntimeException)
199 {
200 if (static_cast<size_t>(nChildIndex) >= maMenuItems.size())
201 throw IndexOutOfBoundsException();
202
203 mpWindow->setSelectedMenuItem(nChildIndex, false, true);
204 }
205
isAccessibleChildSelected(sal_Int32 nChildIndex)206 sal_Bool ScAccessibleFilterMenu::isAccessibleChildSelected(sal_Int32 nChildIndex)
207 throw (IndexOutOfBoundsException, RuntimeException)
208 {
209 if (static_cast<size_t>(nChildIndex) >= maMenuItems.size())
210 throw IndexOutOfBoundsException();
211
212 return mpWindow->isMenuItemSelected(static_cast<size_t>(nChildIndex));
213 }
214
clearAccessibleSelection()215 void ScAccessibleFilterMenu::clearAccessibleSelection() throw (RuntimeException)
216 {
217 mpWindow->clearSelectedMenuItem();
218 }
219
selectAllAccessibleChildren()220 void ScAccessibleFilterMenu::selectAllAccessibleChildren() throw (RuntimeException)
221 {
222 // not supported - this is a menu, you can't select all menu items.
223 }
224
getSelectedAccessibleChildCount()225 sal_Int32 ScAccessibleFilterMenu::getSelectedAccessibleChildCount() throw (RuntimeException)
226 {
227 // Since this is a menu, either one menu item is selected, or none at all.
228 return mpWindow->getSelectedMenuItem() == ScMenuFloatingWindow::MENU_NOT_SELECTED ? 0 : 1;
229 }
230
getSelectedAccessibleChild(sal_Int32 nChildIndex)231 Reference<XAccessible> ScAccessibleFilterMenu::getSelectedAccessibleChild(sal_Int32 nChildIndex)
232 throw (IndexOutOfBoundsException, RuntimeException)
233 {
234 if (static_cast<size_t>(nChildIndex) >= maMenuItems.size())
235 throw IndexOutOfBoundsException();
236
237 return maMenuItems[nChildIndex];
238 }
239
deselectAccessibleChild(sal_Int32 nChildIndex)240 void ScAccessibleFilterMenu::deselectAccessibleChild(sal_Int32 nChildIndex) throw (IndexOutOfBoundsException, RuntimeException)
241 {
242 if (static_cast<size_t>(nChildIndex) >= maMenuItems.size())
243 throw IndexOutOfBoundsException();
244
245 mpWindow->selectMenuItem(nChildIndex, false, false);
246 }
247
248 // XInterface
249
queryInterface(uno::Type const & rType)250 uno::Any SAL_CALL ScAccessibleFilterMenu::queryInterface( uno::Type const & rType )
251 throw (RuntimeException)
252 {
253 Any any = ScAccessibleContextBase::queryInterface(rType);
254 if (any.hasValue())
255 return any;
256
257 return ScAccessibleFilterMenu_BASE::queryInterface(rType);
258 }
259
acquire()260 void SAL_CALL ScAccessibleFilterMenu::acquire() throw ()
261 {
262 ScAccessibleContextBase::acquire();
263 }
264
release()265 void SAL_CALL ScAccessibleFilterMenu::release() throw ()
266 {
267 ScAccessibleContextBase::release();
268 }
269
270 // XTypeProvider
271
getImplementationId()272 Sequence<sal_Int8> ScAccessibleFilterMenu::getImplementationId()
273 throw (RuntimeException)
274 {
275 Sequence<sal_Int8> aId(16);
276 return aId;
277 }
278
GetBoundingBoxOnScreen() const279 Rectangle ScAccessibleFilterMenu::GetBoundingBoxOnScreen() const
280 throw (RuntimeException)
281 {
282 if (mnMenuPos == ScMenuFloatingWindow::MENU_NOT_SELECTED)
283 return Rectangle();
284
285 // Menu object's bounding box is the bounding box of the menu item that
286 // launches the menu, which belongs to the parent window.
287 ScMenuFloatingWindow* pParentWin = mpWindow->getParentMenuWindow();
288 if (!pParentWin)
289 return Rectangle();
290
291 if (!pParentWin->IsVisible())
292 return Rectangle();
293
294 Point aPos = pParentWin->OutputToAbsoluteScreenPixel(Point(0,0));
295 Point aMenuPos;
296 Size aMenuSize;
297 pParentWin->getMenuItemPosSize(mnMenuPos, aMenuPos, aMenuSize);
298 Rectangle aRect(aPos + aMenuPos, aMenuSize);
299 return aRect;
300 }
301
GetBoundingBox() const302 Rectangle ScAccessibleFilterMenu::GetBoundingBox() const
303 throw (RuntimeException)
304 {
305 if (mnMenuPos == ScMenuFloatingWindow::MENU_NOT_SELECTED)
306 return Rectangle();
307
308 // Menu object's bounding box is the bounding box of the menu item that
309 // launches the menu, which belongs to the parent window.
310 ScMenuFloatingWindow* pParentWin = mpWindow->getParentMenuWindow();
311 if (!pParentWin)
312 return Rectangle();
313
314 if (!pParentWin->IsVisible())
315 return Rectangle();
316
317 Point aMenuPos;
318 Size aMenuSize;
319 pParentWin->getMenuItemPosSize(mnMenuPos, aMenuPos, aMenuSize);
320 Rectangle aRect(aMenuPos, aMenuSize);
321 return aRect;
322 }
323
appendMenuItem(const OUString & rName,bool bEnabled,size_t nMenuPos)324 void ScAccessibleFilterMenu::appendMenuItem(const OUString& rName, bool bEnabled, size_t nMenuPos)
325 {
326 // Check whether this menu item is a sub menu or a regular menu item.
327 ScMenuFloatingWindow* pSubMenu = mpWindow->getSubMenuWindow(nMenuPos);
328 Reference<XAccessible> xAccessible;
329 if (pSubMenu)
330 {
331 xAccessible = pSubMenu->CreateAccessible();
332 ScAccessibleFilterMenu* p =
333 static_cast<ScAccessibleFilterMenu*>(xAccessible.get());
334 p->setEnabled(bEnabled);
335 p->setMenuPos(nMenuPos);
336 }
337 else
338 {
339 xAccessible.set(new ScAccessibleFilterMenuItem(this, mpWindow, rName, nMenuPos));
340 ScAccessibleFilterMenuItem* p =
341 static_cast<ScAccessibleFilterMenuItem*>(xAccessible.get());
342 p->setEnabled(bEnabled);
343 }
344 maMenuItems.push_back(xAccessible);
345 }
346
setMenuPos(size_t nMenuPos)347 void ScAccessibleFilterMenu::setMenuPos(size_t nMenuPos)
348 {
349 mnMenuPos = nMenuPos;
350 }
351
setEnabled(bool bEnabled)352 void ScAccessibleFilterMenu::setEnabled(bool bEnabled)
353 {
354 mbEnabled = bEnabled;
355 }
356
getMenuItemCount() const357 sal_Int32 ScAccessibleFilterMenu::getMenuItemCount() const
358 {
359 return maMenuItems.size();
360 }
361
isSelected() const362 bool ScAccessibleFilterMenu::isSelected() const
363 {
364 // Check to see if any of the child menu items is selected.
365 return mpWindow->isMenuItemSelected(mnMenuPos);
366 }
367
isFocused() const368 bool ScAccessibleFilterMenu::isFocused() const
369 {
370 return isSelected();
371 }
372
updateStates()373 void ScAccessibleFilterMenu::updateStates()
374 {
375 if (!mxStateSet.is())
376 mxStateSet.set(new ScAccessibleStateSet);
377
378 ScAccessibleStateSet* p = static_cast<ScAccessibleStateSet*>(
379 mxStateSet.get());
380
381 p->clear();
382
383 p->insert(ENABLED);
384 p->insert(FOCUSABLE);
385 p->insert(SELECTABLE);
386 p->insert(SENSITIVE);
387 p->insert(OPAQUE);
388
389 if (isFocused())
390 p->insert(FOCUSED);
391
392 if (isSelected())
393 p->insert(SELECTED);
394 }
395