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