Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*
3 : : * Version: MPL 1.1 / GPLv3+ / LGPLv3+
4 : : *
5 : : * The contents of this file are subject to the Mozilla Public License Version
6 : : * 1.1 (the "License"); you may not use this file except in compliance with
7 : : * the License or as specified alternatively below. You may obtain a copy of
8 : : * the License at http://www.mozilla.org/MPL/
9 : : *
10 : : * Software distributed under the License is distributed on an "AS IS" basis,
11 : : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : : * for the specific language governing rights and limitations under the
13 : : * License.
14 : : *
15 : : * Major Contributor(s):
16 : : * Copyright (C) 2011 Kohei Yoshida <kohei.yoshida@suse.com>
17 : : *
18 : : * All Rights Reserved.
19 : : *
20 : : * For minor contributions see the git repository.
21 : : *
22 : : * Alternatively, the contents of this file may be used under the terms of
23 : : * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
24 : : * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
25 : : * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
26 : : * instead of those above.
27 : : */
28 : :
29 : : #include "checklistmenu.hxx"
30 : : #include "checklistmenu.hrc"
31 : : #include "strload.hxx"
32 : :
33 : : #include <vcl/decoview.hxx>
34 : : #include <tools/wintypes.hxx>
35 : :
36 : : #include "AccessibleFilterMenu.hxx"
37 : : #include "AccessibleFilterTopWindow.hxx"
38 : :
39 : : #include <com/sun/star/accessibility/XAccessible.hpp>
40 : : #include <com/sun/star/accessibility/XAccessibleContext.hpp>
41 : :
42 : : using ::com::sun::star::uno::Reference;
43 : : using ::com::sun::star::accessibility::XAccessible;
44 : : using ::com::sun::star::accessibility::XAccessibleContext;
45 : : using ::rtl::OUString;
46 : : using ::rtl::OUStringHash;
47 : : using ::std::vector;
48 : : using ::boost::unordered_map;
49 : : using ::std::auto_ptr;
50 : :
51 : 0 : ScMenuFloatingWindow::MenuItemData::MenuItemData() :
52 : : mbEnabled(true), mbSeparator(false),
53 : : mpAction(static_cast<ScCheckListMenuWindow::Action*>(NULL)),
54 [ # # ][ # # ]: 0 : mpSubMenuWin(static_cast<ScMenuFloatingWindow*>(NULL))
55 : : {
56 : 0 : }
57 : :
58 : : // ----------------------------------------------------------------------------
59 : :
60 : 0 : ScMenuFloatingWindow::SubMenuItemData::SubMenuItemData(ScMenuFloatingWindow* pParent) :
61 : : mpSubMenu(NULL),
62 : : mnMenuPos(MENU_NOT_SELECTED),
63 : 0 : mpParent(pParent)
64 : : {
65 [ # # ]: 0 : maTimer.SetTimeoutHdl( LINK(this, ScMenuFloatingWindow::SubMenuItemData, TimeoutHdl) );
66 [ # # ]: 0 : maTimer.SetTimeout(mpParent->GetSettings().GetMouseSettings().GetMenuDelay());
67 : 0 : }
68 : :
69 : 0 : void ScMenuFloatingWindow::SubMenuItemData::reset()
70 : : {
71 : 0 : mpSubMenu = NULL;
72 : 0 : mnMenuPos = MENU_NOT_SELECTED;
73 : 0 : maTimer.Stop();
74 : 0 : }
75 : :
76 : 0 : IMPL_LINK_NOARG(ScMenuFloatingWindow::SubMenuItemData, TimeoutHdl)
77 : : {
78 : 0 : mpParent->handleMenuTimeout(this);
79 : 0 : return 0;
80 : : }
81 : :
82 : : // ----------------------------------------------------------------------------
83 : :
84 : : size_t ScMenuFloatingWindow::MENU_NOT_SELECTED = 999;
85 : :
86 : 0 : ScMenuFloatingWindow::ScMenuFloatingWindow(Window* pParent, ScDocument* pDoc, sal_uInt16 nMenuStackLevel) :
87 : : PopupMenuFloatingWindow(pParent),
88 : : maOpenTimer(this),
89 : : maCloseTimer(this),
90 : : maName(RTL_CONSTASCII_USTRINGPARAM("ScMenuFloatingWindow")),
91 : : mnSelectedMenu(MENU_NOT_SELECTED),
92 : : mnClickedMenu(MENU_NOT_SELECTED),
93 : : mpDoc(pDoc),
94 : : mpParentMenu(dynamic_cast<ScMenuFloatingWindow*>(pParent)),
95 [ # # ][ # # ]: 0 : mpActiveSubMenu(NULL)
[ # # ][ # # ]
[ # # ][ # # ]
96 : : {
97 [ # # ]: 0 : SetMenuStackLevel(nMenuStackLevel);
98 : :
99 : : // TODO: How do we get the right font to use here ?
100 : 0 : const sal_uInt16 nPopupFontHeight = 12;
101 : 0 : const StyleSettings& rStyle = GetSettings().GetStyleSettings();
102 [ # # ]: 0 : maLabelFont = rStyle.GetLabelFont();
103 [ # # ]: 0 : maLabelFont.SetHeight(nPopupFontHeight);
104 [ # # ]: 0 : SetFont(maLabelFont);
105 : :
106 [ # # ][ # # ]: 0 : SetText( OUString(RTL_CONSTASCII_USTRINGPARAM("ScMenuFloatingWindow")) );
[ # # ][ # # ]
107 : 0 : }
108 : :
109 [ # # ][ # # ]: 0 : ScMenuFloatingWindow::~ScMenuFloatingWindow()
[ # # ]
110 : : {
111 [ # # ]: 0 : EndPopupMode();
112 [ # # ]: 0 : }
113 : :
114 : 0 : void ScMenuFloatingWindow::PopupModeEnd()
115 : : {
116 : 0 : handlePopupEnd();
117 : 0 : }
118 : :
119 : 0 : void ScMenuFloatingWindow::MouseMove(const MouseEvent& rMEvt)
120 : : {
121 : 0 : const Point& rPos = rMEvt.GetPosPixel();
122 : 0 : size_t nSelectedMenu = getEnclosingMenuItem(rPos);
123 : 0 : setSelectedMenuItem(nSelectedMenu, true, false);
124 : :
125 : 0 : Window::MouseMove(rMEvt);
126 : 0 : }
127 : :
128 : 0 : void ScMenuFloatingWindow::MouseButtonDown(const MouseEvent& rMEvt)
129 : : {
130 : 0 : const Point& rPos = rMEvt.GetPosPixel();
131 : 0 : mnClickedMenu = getEnclosingMenuItem(rPos);
132 : 0 : Window::MouseButtonDown(rMEvt);
133 : 0 : }
134 : :
135 : 0 : void ScMenuFloatingWindow::MouseButtonUp(const MouseEvent& rMEvt)
136 : : {
137 : 0 : executeMenuItem(mnClickedMenu);
138 : 0 : mnClickedMenu = MENU_NOT_SELECTED;
139 : 0 : Window::MouseButtonUp(rMEvt);
140 : 0 : }
141 : :
142 : 0 : void ScMenuFloatingWindow::KeyInput(const KeyEvent& rKEvt)
143 : : {
144 [ # # ]: 0 : if (maMenuItems.empty())
145 : : {
146 : 0 : Window::KeyInput(rKEvt);
147 : 0 : return;
148 : : }
149 : :
150 : 0 : const KeyCode& rKeyCode = rKEvt.GetKeyCode();
151 : 0 : bool bHandled = true;
152 : 0 : size_t nSelectedMenu = mnSelectedMenu;
153 : 0 : size_t nLastMenuPos = maMenuItems.size() - 1;
154 [ # # # # : 0 : switch (rKeyCode.GetCode())
# # ]
155 : : {
156 : : case KEY_UP:
157 : : {
158 [ # # ]: 0 : if (nLastMenuPos == 0)
159 : : // There is only one menu item. Do nothing.
160 : 0 : break;
161 : :
162 : 0 : size_t nOldPos = nSelectedMenu;
163 : :
164 [ # # ][ # # ]: 0 : if (nSelectedMenu == MENU_NOT_SELECTED || nSelectedMenu == 0)
165 : 0 : nSelectedMenu = nLastMenuPos;
166 : : else
167 : 0 : --nSelectedMenu;
168 : :
169 : : // Loop until a non-separator menu item is found.
170 [ # # ]: 0 : while (nSelectedMenu != nOldPos)
171 : : {
172 [ # # ]: 0 : if (maMenuItems[nSelectedMenu].mbSeparator)
173 : : {
174 [ # # ]: 0 : if (nSelectedMenu)
175 : 0 : --nSelectedMenu;
176 : : else
177 : 0 : nSelectedMenu = nLastMenuPos;
178 : : }
179 : : else
180 : 0 : break;
181 : : }
182 : :
183 : 0 : setSelectedMenuItem(nSelectedMenu, false, false);
184 : : }
185 : 0 : break;
186 : : case KEY_DOWN:
187 : : {
188 [ # # ]: 0 : if (nLastMenuPos == 0)
189 : : // There is only one menu item. Do nothing.
190 : 0 : break;
191 : :
192 : 0 : size_t nOldPos = nSelectedMenu;
193 : :
194 [ # # ][ # # ]: 0 : if (nSelectedMenu == MENU_NOT_SELECTED || nSelectedMenu == nLastMenuPos)
195 : 0 : nSelectedMenu = 0;
196 : : else
197 : 0 : ++nSelectedMenu;
198 : :
199 : : // Loop until a non-separator menu item is found.
200 [ # # ]: 0 : while (nSelectedMenu != nOldPos)
201 : : {
202 [ # # ]: 0 : if (maMenuItems[nSelectedMenu].mbSeparator)
203 : : {
204 [ # # ]: 0 : if (nSelectedMenu == nLastMenuPos)
205 : 0 : nSelectedMenu = 0;
206 : : else
207 : 0 : ++nSelectedMenu;
208 : : }
209 : : else
210 : 0 : break;
211 : : }
212 : :
213 : 0 : setSelectedMenuItem(nSelectedMenu, false, false);
214 : : }
215 : 0 : break;
216 : : case KEY_LEFT:
217 [ # # ]: 0 : if (mpParentMenu)
218 : 0 : mpParentMenu->endSubMenu(this);
219 : 0 : break;
220 : : case KEY_RIGHT:
221 : : {
222 [ # # ][ # # ]: 0 : if (mnSelectedMenu >= maMenuItems.size() || mnSelectedMenu == MENU_NOT_SELECTED)
[ # # ]
223 : 0 : break;
224 : :
225 : 0 : const MenuItemData& rMenu = maMenuItems[mnSelectedMenu];
226 [ # # ][ # # ]: 0 : if (!rMenu.mbEnabled || !rMenu.mpSubMenuWin)
[ # # ]
227 : 0 : break;
228 : :
229 : 0 : maOpenTimer.mnMenuPos = mnSelectedMenu;
230 : 0 : maOpenTimer.mpSubMenu = rMenu.mpSubMenuWin.get();
231 : 0 : launchSubMenu(true);
232 : : }
233 : 0 : break;
234 : : case KEY_RETURN:
235 [ # # ]: 0 : if (nSelectedMenu != MENU_NOT_SELECTED)
236 : 0 : executeMenuItem(nSelectedMenu);
237 : 0 : break;
238 : : default:
239 : 0 : bHandled = false;
240 : : }
241 : :
242 [ # # ]: 0 : if (!bHandled)
243 : 0 : Window::KeyInput(rKEvt);
244 : : }
245 : :
246 : 0 : void ScMenuFloatingWindow::Paint(const Rectangle& /*rRect*/)
247 : : {
248 : 0 : const StyleSettings& rStyle = GetSettings().GetStyleSettings();
249 : 0 : Color aBackColor = rStyle.GetMenuColor();
250 : 0 : Color aBorderColor = rStyle.GetShadowColor();
251 : :
252 [ # # ]: 0 : Rectangle aCtrlRect(Point(0, 0), GetOutputSizePixel());
253 : :
254 : : // Window background
255 : 0 : bool bNativeDrawn = true;
256 [ # # ][ # # ]: 0 : if (IsNativeControlSupported(CTRL_MENU_POPUP, PART_ENTIRE_CONTROL))
257 : : {
258 [ # # ]: 0 : SetClipRegion();
259 : : bNativeDrawn = DrawNativeControl(
260 : : CTRL_MENU_POPUP, PART_ENTIRE_CONTROL, aCtrlRect, CTRL_STATE_ENABLED,
261 [ # # ][ # # ]: 0 : ImplControlValue(), OUString());
262 : : }
263 : : else
264 : 0 : bNativeDrawn = false;
265 : :
266 [ # # ]: 0 : if (!bNativeDrawn)
267 : : {
268 [ # # ]: 0 : SetFillColor(aBackColor);
269 [ # # ]: 0 : SetLineColor(aBorderColor);
270 [ # # ]: 0 : DrawRect(aCtrlRect);
271 : : }
272 : :
273 : : // Menu items
274 [ # # ]: 0 : SetTextColor(rStyle.GetMenuTextColor());
275 [ # # ]: 0 : drawAllMenuItems();
276 : 0 : }
277 : :
278 : 0 : Reference<XAccessible> ScMenuFloatingWindow::CreateAccessible()
279 : : {
280 [ # # ]: 0 : if (!mxAccessible.is())
281 : : {
282 : : Reference<XAccessible> xAccParent = mpParentMenu ?
283 [ # # ][ # # ]: 0 : mpParentMenu->GetAccessible() : GetAccessibleParentWindow()->GetAccessible();
[ # # ][ # # ]
284 : :
285 [ # # ][ # # ]: 0 : mxAccessible.set(new ScAccessibleFilterMenu(xAccParent, this, maName, 999, getDoc()));
[ # # ]
286 : : ScAccessibleFilterMenu* p = static_cast<ScAccessibleFilterMenu*>(
287 [ # # ][ # # ]: 0 : mxAccessible.get());
288 : :
289 [ # # ][ # # ]: 0 : vector<MenuItemData>::const_iterator itr, itrBeg = maMenuItems.begin(), itrEnd = maMenuItems.end();
290 [ # # ][ # # ]: 0 : for (itr = itrBeg; itr != itrEnd; ++itr)
291 : : {
292 [ # # ]: 0 : size_t nPos = ::std::distance(itrBeg, itr);
293 [ # # ]: 0 : p->appendMenuItem(itr->maText, itr->mbEnabled, nPos);
294 : 0 : }
295 : : }
296 : :
297 : 0 : return mxAccessible;
298 : : }
299 : :
300 : 0 : void ScMenuFloatingWindow::addMenuItem(const OUString& rText, bool bEnabled, Action* pAction)
301 : : {
302 [ # # ]: 0 : MenuItemData aItem;
303 : 0 : aItem.maText = rText;
304 : 0 : aItem.mbEnabled = bEnabled;
305 [ # # ]: 0 : aItem.mpAction.reset(pAction);
306 [ # # ][ # # ]: 0 : maMenuItems.push_back(aItem);
307 : 0 : }
308 : :
309 : 0 : void ScMenuFloatingWindow::addSeparator()
310 : : {
311 [ # # ]: 0 : MenuItemData aItem;
312 : 0 : aItem.mbSeparator = true;
313 [ # # ][ # # ]: 0 : maMenuItems.push_back(aItem);
314 : 0 : }
315 : :
316 : 0 : ScMenuFloatingWindow* ScMenuFloatingWindow::addSubMenuItem(const OUString& rText, bool bEnabled)
317 : : {
318 [ # # ]: 0 : MenuItemData aItem;
319 : 0 : aItem.maText = rText;
320 : 0 : aItem.mbEnabled = bEnabled;
321 [ # # ][ # # ]: 0 : aItem.mpSubMenuWin.reset(new ScMenuFloatingWindow(this, mpDoc, GetMenuStackLevel()+1));
[ # # ][ # # ]
322 : 0 : aItem.mpSubMenuWin->setName(rText);
323 [ # # ]: 0 : maMenuItems.push_back(aItem);
324 [ # # ]: 0 : return aItem.mpSubMenuWin.get();
325 : : }
326 : :
327 : 0 : void ScMenuFloatingWindow::handlePopupEnd()
328 : : {
329 : 0 : clearSelectedMenuItem();
330 : 0 : }
331 : :
332 : 0 : Size ScMenuFloatingWindow::getMenuSize() const
333 : : {
334 [ # # ]: 0 : if (maMenuItems.empty())
335 : 0 : return Size();
336 : :
337 : 0 : vector<MenuItemData>::const_iterator itr = maMenuItems.begin(), itrEnd = maMenuItems.end();
338 : 0 : long nTextWidth = 0;
339 [ # # ][ # # ]: 0 : for (; itr != itrEnd; ++itr)
340 : : {
341 [ # # ]: 0 : if (itr->mbSeparator)
342 : 0 : continue;
343 : :
344 [ # # ][ # # ]: 0 : nTextWidth = ::std::max(GetTextWidth(itr->maText), nTextWidth);
[ # # ][ # # ]
345 : : }
346 : :
347 : 0 : size_t nLastPos = maMenuItems.size()-1;
348 : 0 : Point aPos;
349 : 0 : Size aSize;
350 [ # # ]: 0 : getMenuItemPosSize(nLastPos, aPos, aSize);
351 : 0 : aPos.X() += nTextWidth + 15;
352 : 0 : aPos.Y() += aSize.Height() + 5;
353 : 0 : return Size(aPos.X(), aPos.Y());
354 : : }
355 : :
356 : 0 : void ScMenuFloatingWindow::drawMenuItem(size_t nPos)
357 : : {
358 [ # # ]: 0 : if (nPos >= maMenuItems.size())
359 : 0 : return;
360 : :
361 : 0 : Point aPos;
362 : 0 : Size aSize;
363 [ # # ]: 0 : getMenuItemPosSize(nPos, aPos, aSize);
364 : :
365 : 0 : DecorationView aDecoView(this);
366 : 0 : long nXOffset = 5;
367 [ # # ]: 0 : long nYOffset = (aSize.Height() - maLabelFont.GetHeight())/2;
368 : 0 : DrawCtrlText(Point(aPos.X()+nXOffset, aPos.Y() + nYOffset), maMenuItems[nPos].maText, 0, STRING_LEN,
369 [ # # ]: 0 : maMenuItems[nPos].mbEnabled ? TEXT_DRAW_MNEMONIC : TEXT_DRAW_DISABLE);
[ # # # # ]
[ # # ]
370 : :
371 [ # # ]: 0 : if (maMenuItems[nPos].mpSubMenuWin)
372 : : {
373 [ # # ]: 0 : long nFontHeight = maLabelFont.GetHeight();
374 : 0 : Point aMarkerPos = aPos;
375 : 0 : aMarkerPos.Y() += aSize.Height()/2 - nFontHeight/4 + 1;
376 : 0 : aMarkerPos.X() += aSize.Width() - nFontHeight + nFontHeight/4;
377 : 0 : Size aMarkerSize(nFontHeight/2, nFontHeight/2);
378 : : aDecoView.DrawSymbol(Rectangle(aMarkerPos, aMarkerSize),
379 [ # # ][ # # ]: 0 : SYMBOL_SPIN_RIGHT, GetTextColor(), 0);
380 : : }
381 : : }
382 : :
383 : 0 : void ScMenuFloatingWindow::drawSeparator(size_t nPos)
384 : : {
385 : 0 : Point aPos;
386 : 0 : Size aSize;
387 [ # # ]: 0 : getMenuItemPosSize(nPos, aPos, aSize);
388 [ # # ]: 0 : Rectangle aRegion(aPos,aSize);
389 : :
390 [ # # ][ # # ]: 0 : if (IsNativeControlSupported(CTRL_MENU_POPUP, PART_ENTIRE_CONTROL))
391 : : {
392 [ # # ]: 0 : Push(PUSH_CLIPREGION);
393 [ # # ]: 0 : IntersectClipRegion(aRegion);
394 [ # # ]: 0 : Rectangle aCtrlRect(Point(0,0), GetOutputSizePixel());
395 : : DrawNativeControl(
396 : : CTRL_MENU_POPUP, PART_ENTIRE_CONTROL, aCtrlRect, CTRL_STATE_ENABLED,
397 [ # # ][ # # ]: 0 : ImplControlValue(), OUString());
398 : :
399 [ # # ]: 0 : Pop();
400 : : }
401 : :
402 : 0 : bool bNativeDrawn = false;
403 [ # # ][ # # ]: 0 : if (IsNativeControlSupported(CTRL_MENU_POPUP, PART_MENU_SEPARATOR))
404 : : {
405 : 0 : ControlState nState = 0;
406 : 0 : const MenuItemData& rData = maMenuItems[nPos];
407 [ # # ]: 0 : if (rData.mbEnabled)
408 : 0 : nState |= CTRL_STATE_ENABLED;
409 : :
410 : : bNativeDrawn = DrawNativeControl(
411 : : CTRL_MENU_POPUP, PART_MENU_SEPARATOR,
412 [ # # ][ # # ]: 0 : aRegion, nState, ImplControlValue(), OUString());
413 : : }
414 : :
415 [ # # ]: 0 : if (!bNativeDrawn)
416 : : {
417 : 0 : const StyleSettings& rStyle = GetSettings().GetStyleSettings();
418 : 0 : Point aTmpPos = aPos;
419 : 0 : aTmpPos.Y() += aSize.Height()/2;
420 [ # # ]: 0 : SetLineColor(rStyle.GetShadowColor());
421 [ # # ]: 0 : DrawLine(aTmpPos, Point(aSize.Width()+aTmpPos.X(), aTmpPos.Y()));
422 : 0 : ++aTmpPos.Y();
423 [ # # ]: 0 : SetLineColor(rStyle.GetLightColor());
424 [ # # ]: 0 : DrawLine(aTmpPos, Point(aSize.Width()+aTmpPos.X(), aTmpPos.Y()));
425 [ # # ]: 0 : SetLineColor();
426 : : }
427 : 0 : }
428 : :
429 : 0 : void ScMenuFloatingWindow::drawAllMenuItems()
430 : : {
431 : 0 : size_t n = maMenuItems.size();
432 [ # # ]: 0 : for (size_t i = 0; i < n; ++i)
433 : : {
434 [ # # ]: 0 : if (maMenuItems[i].mbSeparator)
435 : : // Separator
436 : 0 : drawSeparator(i);
437 : : else
438 : : // Normal menu item
439 : 0 : highlightMenuItem(i, i == mnSelectedMenu);
440 : : }
441 : 0 : }
442 : :
443 : 0 : const Font& ScMenuFloatingWindow::getLabelFont() const
444 : : {
445 : 0 : return maLabelFont;
446 : : }
447 : :
448 : 0 : void ScMenuFloatingWindow::executeMenuItem(size_t nPos)
449 : : {
450 [ # # ]: 0 : if (nPos >= maMenuItems.size())
451 : 0 : return;
452 : :
453 [ # # ]: 0 : if (!maMenuItems[nPos].mpAction)
454 : : // no action is defined.
455 : 0 : return;
456 : :
457 : 0 : maMenuItems[nPos].mpAction->execute();
458 : 0 : terminateAllPopupMenus();
459 : : }
460 : :
461 : 0 : void ScMenuFloatingWindow::setSelectedMenuItem(size_t nPos, bool bSubMenuTimer, bool bEnsureSubMenu)
462 : : {
463 [ # # ]: 0 : if (mnSelectedMenu == nPos)
464 : : // nothing to do.
465 : 0 : return;
466 : :
467 [ # # ]: 0 : if (bEnsureSubMenu)
468 : : {
469 : : // Dismiss any child popup menu windows.
470 [ # # # # : 0 : if (mnSelectedMenu < maMenuItems.size() &&
# # ][ # # ]
471 : 0 : maMenuItems[mnSelectedMenu].mpSubMenuWin &&
472 : 0 : maMenuItems[mnSelectedMenu].mpSubMenuWin->IsVisible())
473 : : {
474 : 0 : maMenuItems[mnSelectedMenu].mpSubMenuWin->ensureSubMenuNotVisible();
475 : : }
476 : :
477 : : // The popup is not visible, yet a menu item is selected. The request
478 : : // most likely comes from the accessible object. Make sure this
479 : : // window, as well as all its parent windows are visible.
480 [ # # ][ # # ]: 0 : if (!IsVisible() && mpParentMenu)
[ # # ]
481 : 0 : mpParentMenu->ensureSubMenuVisible(this);
482 : : }
483 : :
484 : 0 : selectMenuItem(mnSelectedMenu, false, bSubMenuTimer);
485 : 0 : selectMenuItem(nPos, true, bSubMenuTimer);
486 : 0 : mnSelectedMenu = nPos;
487 : :
488 : 0 : fireMenuHighlightedEvent();
489 : : }
490 : :
491 : 0 : size_t ScMenuFloatingWindow::getSelectedMenuItem() const
492 : : {
493 : 0 : return mnSelectedMenu;
494 : : }
495 : :
496 : 0 : void ScMenuFloatingWindow::handleMenuTimeout(SubMenuItemData* pTimer)
497 : : {
498 [ # # ]: 0 : if (pTimer == &maOpenTimer)
499 : : {
500 : : // Close any open submenu immediately.
501 [ # # ]: 0 : if (maCloseTimer.mpSubMenu)
502 : : {
503 : 0 : maCloseTimer.mpSubMenu->EndPopupMode();
504 : 0 : maCloseTimer.mpSubMenu = NULL;
505 : 0 : maCloseTimer.maTimer.Stop();
506 : : }
507 : :
508 : 0 : launchSubMenu(false);
509 : : }
510 [ # # ]: 0 : else if (pTimer == &maCloseTimer)
511 : : {
512 : : // end submenu.
513 [ # # ]: 0 : if (maCloseTimer.mpSubMenu)
514 : : {
515 : 0 : maOpenTimer.mpSubMenu = NULL;
516 : :
517 : 0 : maCloseTimer.mpSubMenu->EndPopupMode();
518 : 0 : maCloseTimer.mpSubMenu = NULL;
519 : :
520 : 0 : highlightMenuItem(maOpenTimer.mnMenuPos, false);
521 : 0 : maOpenTimer.mnMenuPos = MENU_NOT_SELECTED;
522 : : }
523 : : }
524 : 0 : }
525 : :
526 : 0 : void ScMenuFloatingWindow::queueLaunchSubMenu(size_t nPos, ScMenuFloatingWindow* pMenu)
527 : : {
528 [ # # ]: 0 : if (!pMenu)
529 : 0 : return;
530 : :
531 : : // Set the submenu on launch queue.
532 [ # # ]: 0 : if (maOpenTimer.mpSubMenu)
533 : : {
534 [ # # ]: 0 : if (maOpenTimer.mpSubMenu == pMenu)
535 : : {
536 [ # # ]: 0 : if (pMenu == maCloseTimer.mpSubMenu)
537 : 0 : maCloseTimer.reset();
538 : 0 : return;
539 : : }
540 : :
541 : : // new submenu is being requested.
542 : 0 : queueCloseSubMenu();
543 : : }
544 : :
545 : 0 : maOpenTimer.mpSubMenu = pMenu;
546 : 0 : maOpenTimer.mnMenuPos = nPos;
547 : 0 : maOpenTimer.maTimer.Start();
548 : : }
549 : :
550 : 0 : void ScMenuFloatingWindow::queueCloseSubMenu()
551 : : {
552 [ # # ]: 0 : if (!maOpenTimer.mpSubMenu)
553 : : // There is no submenu to close.
554 : 0 : return;
555 : :
556 : : // Stop any submenu on queue for opening.
557 : 0 : maOpenTimer.maTimer.Stop();
558 : :
559 : 0 : maCloseTimer.mpSubMenu = maOpenTimer.mpSubMenu;
560 : 0 : maCloseTimer.mnMenuPos = maOpenTimer.mnMenuPos;
561 : 0 : maCloseTimer.maTimer.Start();
562 : : }
563 : :
564 : 0 : void ScMenuFloatingWindow::launchSubMenu(bool bSetMenuPos)
565 : : {
566 : 0 : Point aPos;
567 : 0 : Size aSize;
568 [ # # ]: 0 : getMenuItemPosSize(maOpenTimer.mnMenuPos, aPos, aSize);
569 : 0 : ScMenuFloatingWindow* pSubMenu = maOpenTimer.mpSubMenu;
570 : :
571 [ # # ]: 0 : if (!pSubMenu)
572 : 0 : return;
573 : :
574 : 0 : sal_uInt32 nOldFlags = GetPopupModeFlags();
575 : 0 : SetPopupModeFlags(nOldFlags | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE);
576 [ # # ]: 0 : pSubMenu->resizeToFitMenuItems(); // set the size before launching the popup to get it positioned correctly.
577 : : pSubMenu->StartPopupMode(
578 [ # # ][ # # ]: 0 : Rectangle(aPos,aSize), (FLOATWIN_POPUPMODE_RIGHT | FLOATWIN_POPUPMODE_GRABFOCUS));
579 [ # # ]: 0 : pSubMenu->AddPopupModeWindow(this);
580 [ # # ]: 0 : if (bSetMenuPos)
581 [ # # ]: 0 : pSubMenu->setSelectedMenuItem(0, false, false); // select menu item after the popup becomes fully visible.
582 : 0 : SetPopupModeFlags(nOldFlags);
583 : : }
584 : :
585 : 0 : void ScMenuFloatingWindow::endSubMenu(ScMenuFloatingWindow* pSubMenu)
586 : : {
587 [ # # ]: 0 : if (!pSubMenu)
588 : 0 : return;
589 : :
590 : 0 : pSubMenu->EndPopupMode();
591 : 0 : maOpenTimer.reset();
592 : :
593 : 0 : size_t nMenuPos = getSubMenuPos(pSubMenu);
594 [ # # ]: 0 : if (nMenuPos != MENU_NOT_SELECTED)
595 : : {
596 : 0 : highlightMenuItem(nMenuPos, true);
597 : 0 : mnSelectedMenu = nMenuPos;
598 : 0 : fireMenuHighlightedEvent();
599 : : }
600 : : }
601 : :
602 : 0 : void ScMenuFloatingWindow::fillMenuItemsToAccessible(ScAccessibleFilterMenu* pAccMenu) const
603 : : {
604 : 0 : vector<MenuItemData>::const_iterator itr, itrBeg = maMenuItems.begin(), itrEnd = maMenuItems.end();
605 [ # # ][ # # ]: 0 : for (itr = itrBeg; itr != itrEnd; ++itr)
606 : : {
607 [ # # ]: 0 : size_t nPos = ::std::distance(itrBeg, itr);
608 [ # # ]: 0 : pAccMenu->appendMenuItem(itr->maText, itr->mbEnabled, nPos);
609 : : }
610 : 0 : }
611 : :
612 : 0 : ScDocument* ScMenuFloatingWindow::getDoc()
613 : : {
614 : 0 : return mpDoc;
615 : : }
616 : :
617 : 0 : void ScMenuFloatingWindow::resizeToFitMenuItems()
618 : : {
619 [ # # ]: 0 : SetOutputSizePixel(getMenuSize());
620 : 0 : }
621 : :
622 : 0 : void ScMenuFloatingWindow::selectMenuItem(size_t nPos, bool bSelected, bool bSubMenuTimer)
623 : : {
624 [ # # ][ # # ]: 0 : if (nPos >= maMenuItems.size() || nPos == MENU_NOT_SELECTED)
[ # # ]
625 : : {
626 : 0 : queueCloseSubMenu();
627 : 0 : return;
628 : : }
629 : :
630 [ # # ]: 0 : if (!maMenuItems[nPos].mbEnabled)
631 : : {
632 : 0 : queueCloseSubMenu();
633 : 0 : return;
634 : : }
635 : :
636 : 0 : highlightMenuItem(nPos, bSelected);
637 : :
638 [ # # ]: 0 : if (bSelected)
639 : : {
640 [ # # ]: 0 : if (mpParentMenu)
641 : 0 : mpParentMenu->setSubMenuFocused(this);
642 : :
643 [ # # ]: 0 : if (bSubMenuTimer)
644 : : {
645 [ # # ]: 0 : if (maMenuItems[nPos].mpSubMenuWin)
646 : : {
647 : 0 : ScMenuFloatingWindow* pSubMenu = maMenuItems[nPos].mpSubMenuWin.get();
648 : 0 : queueLaunchSubMenu(nPos, pSubMenu);
649 : : }
650 : : else
651 : 0 : queueCloseSubMenu();
652 : : }
653 : : }
654 : : }
655 : :
656 : 0 : void ScMenuFloatingWindow::clearSelectedMenuItem()
657 : : {
658 : 0 : selectMenuItem(mnSelectedMenu, false, false);
659 : 0 : mnSelectedMenu = MENU_NOT_SELECTED;
660 : 0 : }
661 : :
662 : 0 : ScMenuFloatingWindow* ScMenuFloatingWindow::getSubMenuWindow(size_t nPos) const
663 : : {
664 [ # # ]: 0 : if (maMenuItems.size() <= nPos)
665 : 0 : return NULL;
666 : :
667 : 0 : return maMenuItems[nPos].mpSubMenuWin.get();
668 : : }
669 : :
670 : 0 : bool ScMenuFloatingWindow::isMenuItemSelected(size_t nPos) const
671 : : {
672 : 0 : return nPos == mnSelectedMenu;
673 : : }
674 : :
675 : 0 : void ScMenuFloatingWindow::setName(const OUString& rName)
676 : : {
677 : 0 : maName = rName;
678 : 0 : }
679 : :
680 : 0 : const OUString& ScMenuFloatingWindow::getName() const
681 : : {
682 : 0 : return maName;
683 : : }
684 : :
685 : 0 : void ScMenuFloatingWindow::highlightMenuItem(size_t nPos, bool bSelected)
686 : : {
687 [ # # ]: 0 : if (nPos == MENU_NOT_SELECTED)
688 : 0 : return;
689 : :
690 : 0 : const StyleSettings& rStyle = GetSettings().GetStyleSettings();
691 : 0 : Color aBackColor = rStyle.GetMenuColor();
692 [ # # ]: 0 : SetFillColor(aBackColor);
693 [ # # ]: 0 : SetLineColor(aBackColor);
694 : :
695 : 0 : Point aPos;
696 : 0 : Size aSize;
697 [ # # ]: 0 : getMenuItemPosSize(nPos, aPos, aSize);
698 [ # # ]: 0 : Rectangle aRegion(aPos,aSize);
699 : :
700 [ # # ][ # # ]: 0 : if (IsNativeControlSupported(CTRL_MENU_POPUP, PART_ENTIRE_CONTROL))
701 : : {
702 [ # # ]: 0 : Push(PUSH_CLIPREGION);
703 [ # # ][ # # ]: 0 : IntersectClipRegion(Rectangle(aPos, aSize));
704 [ # # ]: 0 : Rectangle aCtrlRect(Point(0,0), GetOutputSizePixel());
705 : : DrawNativeControl(
706 : : CTRL_MENU_POPUP, PART_ENTIRE_CONTROL, aCtrlRect, CTRL_STATE_ENABLED,
707 [ # # ][ # # ]: 0 : ImplControlValue(), OUString());
708 : :
709 [ # # ]: 0 : Pop();
710 : : }
711 : :
712 : 0 : bool bNativeDrawn = true;
713 [ # # ][ # # ]: 0 : if (IsNativeControlSupported(CTRL_MENU_POPUP, PART_MENU_ITEM))
714 : : {
715 [ # # ]: 0 : ControlState nState = bSelected ? CTRL_STATE_SELECTED : 0;
716 [ # # ]: 0 : if (maMenuItems[nPos].mbEnabled)
717 : 0 : nState |= CTRL_STATE_ENABLED;
718 : : bNativeDrawn = DrawNativeControl(
719 [ # # ][ # # ]: 0 : CTRL_MENU_POPUP, PART_MENU_ITEM, aRegion, nState, ImplControlValue(), OUString());
720 : : }
721 : : else
722 : 0 : bNativeDrawn = false;
723 : :
724 [ # # ]: 0 : if (!bNativeDrawn)
725 : : {
726 [ # # ]: 0 : if (bSelected)
727 : : {
728 : 0 : aBackColor = rStyle.GetMenuHighlightColor();
729 [ # # ]: 0 : SetFillColor(aBackColor);
730 [ # # ]: 0 : SetLineColor(aBackColor);
731 : : }
732 [ # # ][ # # ]: 0 : DrawRect(Rectangle(aPos,aSize));
733 : : }
734 : :
735 [ # # ]: 0 : Color aTextColor = bSelected ? rStyle.GetMenuHighlightTextColor() : rStyle.GetMenuTextColor();
736 [ # # ]: 0 : SetTextColor(aTextColor);
737 [ # # ]: 0 : drawMenuItem(nPos);
738 : : }
739 : :
740 : 0 : void ScMenuFloatingWindow::getMenuItemPosSize(size_t nPos, Point& rPos, Size& rSize) const
741 : : {
742 : 0 : size_t nCount = maMenuItems.size();
743 [ # # ]: 0 : if (nPos >= nCount)
744 : 0 : return;
745 : :
746 : 0 : const sal_uInt16 nLeftMargin = 5;
747 : 0 : const sal_uInt16 nTopMargin = 5;
748 [ # # ]: 0 : const sal_uInt16 nMenuItemHeight = static_cast<sal_uInt16>(maLabelFont.GetHeight()*1.8);
749 [ # # ]: 0 : const sal_uInt16 nSepHeight = static_cast<sal_uInt16>(maLabelFont.GetHeight()*0.8);
750 : :
751 : 0 : Point aPos1(nLeftMargin, nTopMargin);
752 : 0 : rPos = aPos1;
753 [ # # ]: 0 : for (size_t i = 0; i < nPos; ++i)
754 [ # # ]: 0 : rPos.Y() += maMenuItems[i].mbSeparator ? nSepHeight : nMenuItemHeight;
755 : :
756 [ # # ]: 0 : Size aWndSize = GetSizePixel();
757 [ # # ]: 0 : sal_uInt16 nH = maMenuItems[nPos].mbSeparator ? nSepHeight : nMenuItemHeight;
758 : 0 : rSize = Size(aWndSize.Width() - nLeftMargin*2, nH);
759 : : }
760 : :
761 : 0 : ScMenuFloatingWindow* ScMenuFloatingWindow::getParentMenuWindow() const
762 : : {
763 : 0 : return mpParentMenu;
764 : : }
765 : :
766 : 0 : size_t ScMenuFloatingWindow::getEnclosingMenuItem(const Point& rPos) const
767 : : {
768 : 0 : size_t n = maMenuItems.size();
769 [ # # ]: 0 : for (size_t i = 0; i < n; ++i)
770 : : {
771 : 0 : Point aPos;
772 : 0 : Size aSize;
773 [ # # ]: 0 : getMenuItemPosSize(i, aPos, aSize);
774 [ # # ]: 0 : Rectangle aRect(aPos, aSize);
775 [ # # ][ # # ]: 0 : if (aRect.IsInside(rPos))
776 [ # # ]: 0 : return maMenuItems[i].mbSeparator ? MENU_NOT_SELECTED : i;
777 : : }
778 : 0 : return MENU_NOT_SELECTED;
779 : : }
780 : :
781 : 0 : size_t ScMenuFloatingWindow::getSubMenuPos(ScMenuFloatingWindow* pSubMenu)
782 : : {
783 : 0 : size_t n = maMenuItems.size();
784 [ # # ]: 0 : for (size_t i = 0; i < n; ++i)
785 : : {
786 [ # # ]: 0 : if (maMenuItems[i].mpSubMenuWin.get() == pSubMenu)
787 : 0 : return i;
788 : : }
789 : 0 : return MENU_NOT_SELECTED;
790 : : }
791 : :
792 : 0 : void ScMenuFloatingWindow::fireMenuHighlightedEvent()
793 : : {
794 [ # # ]: 0 : if (mnSelectedMenu == MENU_NOT_SELECTED)
795 : : return;
796 : :
797 [ # # ]: 0 : if (!mxAccessible.is())
798 : : return;
799 : :
800 [ # # ][ # # ]: 0 : Reference<XAccessibleContext> xAccCxt = mxAccessible->getAccessibleContext();
801 [ # # ]: 0 : if (!xAccCxt.is())
802 : : return;
803 : :
804 [ # # ][ # # ]: 0 : Reference<XAccessible> xAccMenu = xAccCxt->getAccessibleChild(mnSelectedMenu);
805 [ # # ]: 0 : if (!xAccMenu.is())
806 : : return;
807 : :
808 [ # # ]: 0 : VclAccessibleEvent aEvent(VCLEVENT_MENU_HIGHLIGHT, xAccMenu);
809 [ # # ][ # # ]: 0 : FireVclEvent(&aEvent);
[ # # ][ # # ]
810 : : }
811 : :
812 : 0 : void ScMenuFloatingWindow::setSubMenuFocused(ScMenuFloatingWindow* pSubMenu)
813 : : {
814 : 0 : maCloseTimer.reset();
815 : 0 : size_t nMenuPos = getSubMenuPos(pSubMenu);
816 [ # # ]: 0 : if (mnSelectedMenu != nMenuPos)
817 : : {
818 : 0 : highlightMenuItem(nMenuPos, true);
819 : 0 : mnSelectedMenu = nMenuPos;
820 : : }
821 : 0 : }
822 : :
823 : 0 : void ScMenuFloatingWindow::ensureSubMenuVisible(ScMenuFloatingWindow* pSubMenu)
824 : : {
825 [ # # ]: 0 : if (mpParentMenu)
826 : 0 : mpParentMenu->ensureSubMenuVisible(this);
827 : :
828 [ # # ]: 0 : if (pSubMenu->IsVisible())
829 : 0 : return;
830 : :
831 : : // Find the menu position of the submenu.
832 : 0 : size_t nMenuPos = getSubMenuPos(pSubMenu);
833 [ # # ]: 0 : if (nMenuPos != MENU_NOT_SELECTED)
834 : : {
835 [ # # ]: 0 : setSelectedMenuItem(nMenuPos, false, false);
836 : :
837 : 0 : Point aPos;
838 : 0 : Size aSize;
839 [ # # ]: 0 : getMenuItemPosSize(nMenuPos, aPos, aSize);
840 : :
841 : 0 : sal_uInt32 nOldFlags = GetPopupModeFlags();
842 : 0 : SetPopupModeFlags(nOldFlags | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE);
843 [ # # ]: 0 : pSubMenu->resizeToFitMenuItems(); // set the size before launching the popup to get it positioned correctly.
844 : : pSubMenu->StartPopupMode(
845 [ # # ][ # # ]: 0 : Rectangle(aPos,aSize), (FLOATWIN_POPUPMODE_RIGHT | FLOATWIN_POPUPMODE_GRABFOCUS));
846 [ # # ]: 0 : pSubMenu->AddPopupModeWindow(this);
847 : 0 : SetPopupModeFlags(nOldFlags);
848 : : }
849 : : }
850 : :
851 : 0 : void ScMenuFloatingWindow::ensureSubMenuNotVisible()
852 : : {
853 [ # # # # : 0 : if (mnSelectedMenu <= maMenuItems.size() &&
# # ][ # # ]
854 : 0 : maMenuItems[mnSelectedMenu].mpSubMenuWin &&
855 : 0 : maMenuItems[mnSelectedMenu].mpSubMenuWin->IsVisible())
856 : : {
857 : 0 : maMenuItems[mnSelectedMenu].mpSubMenuWin->ensureSubMenuNotVisible();
858 : : }
859 : :
860 : 0 : EndPopupMode();
861 : 0 : }
862 : :
863 : 0 : void ScMenuFloatingWindow::terminateAllPopupMenus()
864 : : {
865 : 0 : EndPopupMode();
866 [ # # ]: 0 : if (mpParentMenu)
867 : 0 : mpParentMenu->terminateAllPopupMenus();
868 : 0 : }
869 : :
870 : : // ============================================================================
871 : :
872 : 0 : ScCheckListMenuWindow::Config::Config() :
873 : 0 : mbAllowEmptySet(true)
874 : : {
875 : 0 : }
876 : :
877 : 0 : ScCheckListMenuWindow::Member::Member() :
878 : 0 : mbVisible(true)
879 : : {
880 : 0 : }
881 : :
882 : : // ----------------------------------------------------------------------------
883 : :
884 : 0 : ScCheckListMenuWindow::CancelButton::CancelButton(ScCheckListMenuWindow* pParent) :
885 : 0 : ::CancelButton(pParent), mpParent(pParent) {}
886 : :
887 : 0 : void ScCheckListMenuWindow::CancelButton::Click()
888 : : {
889 : 0 : mpParent->EndPopupMode();
890 : 0 : ::CancelButton::Click();
891 : 0 : }
892 : :
893 : : // ----------------------------------------------------------------------------
894 : :
895 : 0 : ScCheckListMenuWindow::ScCheckListMenuWindow(Window* pParent, ScDocument* pDoc) :
896 : : ScMenuFloatingWindow(pParent, pDoc),
897 : : maChecks(this, 0),
898 : : maChkToggleAll(this, 0),
899 : : maBtnSelectSingle (this, 0),
900 : : maBtnUnselectSingle(this, 0),
901 : : maBtnOk(this),
902 : : maBtnCancel(this),
903 : : mnCurTabStop(0),
904 : : mpExtendedData(NULL),
905 : : mpOKAction(NULL),
906 : : mpPopupEndAction(NULL),
907 : : maWndSize(200, 330),
908 [ # # ][ # # ]: 0 : mePrevToggleAllState(STATE_DONTKNOW)
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
909 : : {
910 [ # # ]: 0 : maTabStopCtrls.reserve(7);
911 [ # # ]: 0 : maTabStopCtrls.push_back(this);
912 [ # # ]: 0 : maTabStopCtrls.push_back(&maChecks);
913 [ # # ]: 0 : maTabStopCtrls.push_back(&maChkToggleAll);
914 [ # # ]: 0 : maTabStopCtrls.push_back(&maBtnSelectSingle);
915 [ # # ]: 0 : maTabStopCtrls.push_back(&maBtnUnselectSingle);
916 [ # # ]: 0 : maTabStopCtrls.push_back(&maBtnOk);
917 [ # # ]: 0 : maTabStopCtrls.push_back(&maBtnCancel);
918 : 0 : }
919 : :
920 [ # # ][ # # ]: 0 : ScCheckListMenuWindow::~ScCheckListMenuWindow()
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
921 : : {
922 [ # # ]: 0 : }
923 : :
924 : 0 : void ScCheckListMenuWindow::getSectionPosSize(
925 : : Point& rPos, Size& rSize, SectionType eType) const
926 : : {
927 : : // constant parameters.
928 : 0 : const long nListBoxMargin = 5; // horizontal distance from the side of the dialog to the listbox border.
929 : 0 : const long nListBoxInnerPadding = 5;
930 : 0 : const long nTopMargin = 5;
931 : 0 : const long nMenuHeight = maMenuSize.getHeight();
932 : 0 : const long nSingleItemBtnAreaHeight = 32; // height of the middle area below the list box where the single-action buttons are.
933 : 0 : const long nBottomBtnAreaHeight = 50; // height of the bottom area where the OK and Cancel buttons are.
934 : 0 : const long nBtnWidth = 90;
935 : 0 : const long nLabelHeight = getLabelFont().GetHeight();
936 : 0 : const long nBtnHeight = nLabelHeight*2;
937 : 0 : const long nBottomMargin = 10;
938 : 0 : const long nMenuListMargin = 5;
939 : :
940 : : // parameters calculated from constants.
941 : 0 : const long nListBoxWidth = maWndSize.Width() - nListBoxMargin*2;
942 : 0 : const long nListBoxHeight = maWndSize.Height() - nTopMargin - nMenuHeight -
943 : 0 : nMenuListMargin - nSingleItemBtnAreaHeight - nBottomBtnAreaHeight;
944 : :
945 : 0 : const long nSingleBtnAreaY = nTopMargin + nMenuHeight + nListBoxHeight + nMenuListMargin - 1;
946 : :
947 [ # # # # : 0 : switch (eType)
# # # # #
# ]
948 : : {
949 : : case WHOLE:
950 : : {
951 : 0 : rPos = Point(0, 0);
952 : 0 : rSize = maWndSize;
953 : : }
954 : 0 : break;
955 : : case LISTBOX_AREA_OUTER:
956 : : {
957 : 0 : rPos = Point(nListBoxMargin, nTopMargin + nMenuHeight + nMenuListMargin);
958 : 0 : rSize = Size(nListBoxWidth, nListBoxHeight);
959 : : }
960 : 0 : break;
961 : : case LISTBOX_AREA_INNER:
962 : : {
963 : 0 : rPos = Point(nListBoxMargin, nTopMargin + nMenuHeight + nMenuListMargin);
964 : 0 : rPos.X() += nListBoxInnerPadding;
965 : 0 : rPos.Y() += nListBoxInnerPadding;
966 : :
967 : 0 : rSize = Size(nListBoxWidth, nListBoxHeight);
968 : 0 : rSize.Width() -= nListBoxInnerPadding*2;
969 : 0 : rSize.Height() -= nListBoxInnerPadding*2;
970 : : }
971 : 0 : break;
972 : : case SINGLE_BTN_AREA:
973 : : {
974 : 0 : rPos = Point(nListBoxMargin, nSingleBtnAreaY);
975 : 0 : rSize = Size(nListBoxWidth, nSingleItemBtnAreaHeight);
976 : : }
977 : 0 : break;
978 : : case CHECK_TOGGLE_ALL:
979 : : {
980 : 0 : long h = nLabelHeight*3/2; // check box height is heuristically 150% of the text height.
981 : 0 : rPos = Point(nListBoxMargin, nSingleBtnAreaY);
982 : 0 : rPos.X() += 5;
983 : 0 : rPos.Y() += (nSingleItemBtnAreaHeight - h)/2;
984 : 0 : rSize = Size(70, h);
985 : : }
986 : 0 : break;
987 : : case BTN_SINGLE_SELECT:
988 : : {
989 : 0 : long h = 26;
990 : 0 : rPos = Point(nListBoxMargin, nSingleBtnAreaY);
991 : 0 : rPos.X() += nListBoxWidth - h - 10 - h - 10;
992 : 0 : rPos.Y() += (nSingleItemBtnAreaHeight - h)/2;
993 : 0 : rSize = Size(h, h);
994 : : }
995 : 0 : break;
996 : : case BTN_SINGLE_UNSELECT:
997 : : {
998 : 0 : long h = 26;
999 : 0 : rPos = Point(nListBoxMargin, nSingleBtnAreaY);
1000 : 0 : rPos.X() += nListBoxWidth - h - 10;
1001 : 0 : rPos.Y() += (nSingleItemBtnAreaHeight - h)/2;
1002 : 0 : rSize = Size(h, h);
1003 : : }
1004 : 0 : break;
1005 : : case BTN_OK:
1006 : : {
1007 : 0 : long x = (maWndSize.Width() - nBtnWidth*2)/3;
1008 : 0 : long y = maWndSize.Height() - nBottomMargin - nBtnHeight;
1009 : 0 : rPos = Point(x, y);
1010 : 0 : rSize = Size(nBtnWidth, nBtnHeight);
1011 : : }
1012 : 0 : break;
1013 : : case BTN_CANCEL:
1014 : : {
1015 : 0 : long x = (maWndSize.Width() - nBtnWidth*2)/3*2 + nBtnWidth;
1016 : 0 : long y = maWndSize.Height() - nBottomMargin - nBtnHeight;
1017 : 0 : rPos = Point(x, y);
1018 : 0 : rSize = Size(nBtnWidth, nBtnHeight);
1019 : : }
1020 : 0 : break;
1021 : : default:
1022 : : ;
1023 : : }
1024 : 0 : }
1025 : :
1026 : 0 : void ScCheckListMenuWindow::packWindow()
1027 : : {
1028 [ # # ]: 0 : maMenuSize = getMenuSize();
1029 : :
1030 [ # # ]: 0 : if (maWndSize.Width() < maMenuSize.Width())
1031 : : // Widen the window to fit the menu items.
1032 : 0 : maWndSize.Width() = maMenuSize.Width();
1033 : :
1034 : : // Set proper window height based on the number of menu items.
1035 [ # # ]: 0 : if (maWndSize.Height() < maMenuSize.Height()*2.8)
1036 : 0 : maWndSize.Height() = maMenuSize.Height()*2.8;
1037 : :
1038 : : // TODO: Make sure the window height never exceeds the height of the
1039 : : // screen. Also do adjustment based on the number of check box items.
1040 : :
1041 [ # # ]: 0 : SetOutputSizePixel(maWndSize);
1042 : :
1043 : 0 : const StyleSettings& rStyle = GetSettings().GetStyleSettings();
1044 : :
1045 : 0 : Point aPos;
1046 : 0 : Size aSize;
1047 [ # # ]: 0 : getSectionPosSize(aPos, aSize, WHOLE);
1048 [ # # ]: 0 : SetOutputSizePixel(aSize);
1049 : :
1050 [ # # ]: 0 : getSectionPosSize(aPos, aSize, BTN_OK);
1051 [ # # ]: 0 : maBtnOk.SetPosSizePixel(aPos, aSize);
1052 [ # # ]: 0 : maBtnOk.SetFont(getLabelFont());
1053 [ # # ]: 0 : maBtnOk.SetClickHdl( LINK(this, ScCheckListMenuWindow, ButtonHdl) );
1054 [ # # ]: 0 : maBtnOk.Show();
1055 : :
1056 [ # # ]: 0 : getSectionPosSize(aPos, aSize, BTN_CANCEL);
1057 [ # # ]: 0 : maBtnCancel.SetPosSizePixel(aPos, aSize);
1058 [ # # ]: 0 : maBtnCancel.SetFont(getLabelFont());
1059 [ # # ]: 0 : maBtnCancel.Show();
1060 : :
1061 [ # # ]: 0 : getSectionPosSize(aPos, aSize, LISTBOX_AREA_INNER);
1062 [ # # ]: 0 : maChecks.SetPosSizePixel(aPos, aSize);
1063 [ # # ]: 0 : maChecks.SetFont(getLabelFont());
1064 [ # # ]: 0 : maChecks.SetCheckButtonHdl( LINK(this, ScCheckListMenuWindow, CheckHdl) );
1065 [ # # ]: 0 : maChecks.Show();
1066 : :
1067 [ # # ]: 0 : getSectionPosSize(aPos, aSize, CHECK_TOGGLE_ALL);
1068 [ # # ]: 0 : maChkToggleAll.SetPosSizePixel(aPos, aSize);
1069 [ # # ]: 0 : maChkToggleAll.SetFont(getLabelFont());
1070 [ # # ][ # # ]: 0 : maChkToggleAll.SetText(ScRscStrLoader(RID_POPUP_FILTER, STR_BTN_TOGGLE_ALL).GetString());
[ # # ]
1071 [ # # ]: 0 : maChkToggleAll.SetTextColor(rStyle.GetMenuTextColor());
1072 [ # # ]: 0 : maChkToggleAll.SetControlBackground(rStyle.GetMenuColor());
1073 [ # # ]: 0 : maChkToggleAll.SetClickHdl( LINK(this, ScCheckListMenuWindow, TriStateHdl) );
1074 [ # # ]: 0 : maChkToggleAll.Show();
1075 : :
1076 [ # # ]: 0 : getSectionPosSize(aPos, aSize, BTN_SINGLE_SELECT);
1077 [ # # ]: 0 : maBtnSelectSingle.SetPosSizePixel(aPos, aSize);
1078 [ # # ][ # # ]: 0 : maBtnSelectSingle.SetQuickHelpText(ScRscStrLoader(RID_POPUP_FILTER, STR_BTN_SELECT_CURRENT).GetString());
[ # # ]
1079 [ # # ][ # # ]: 0 : maBtnSelectSingle.SetModeImage(Image(ScResId(RID_IMG_SELECT_CURRENT)));
[ # # ][ # # ]
1080 [ # # ]: 0 : maBtnSelectSingle.SetClickHdl( LINK(this, ScCheckListMenuWindow, ButtonHdl) );
1081 [ # # ]: 0 : maBtnSelectSingle.Show();
1082 : :
1083 [ # # ]: 0 : getSectionPosSize(aPos, aSize, BTN_SINGLE_UNSELECT);
1084 [ # # ]: 0 : maBtnUnselectSingle.SetPosSizePixel(aPos, aSize);
1085 [ # # ][ # # ]: 0 : maBtnUnselectSingle.SetQuickHelpText(ScRscStrLoader(RID_POPUP_FILTER, STR_BTN_UNSELECT_CURRENT).GetString());
[ # # ]
1086 [ # # ][ # # ]: 0 : maBtnUnselectSingle.SetModeImage(Image(ScResId(RID_IMG_UNSELECT_CURRENT)));
[ # # ][ # # ]
1087 [ # # ]: 0 : maBtnUnselectSingle.SetClickHdl( LINK(this, ScCheckListMenuWindow, ButtonHdl) );
1088 [ # # ]: 0 : maBtnUnselectSingle.Show();
1089 : 0 : }
1090 : :
1091 : 0 : void ScCheckListMenuWindow::setAllMemberState(bool bSet)
1092 : : {
1093 : 0 : size_t n = maMembers.size();
1094 [ # # ]: 0 : for (size_t i = 0; i < n; ++i)
1095 : 0 : maChecks.CheckEntryPos(static_cast<sal_uInt16>(i), bSet);
1096 : :
1097 [ # # ]: 0 : if (!maConfig.mbAllowEmptySet)
1098 : : // We need to have at least one member selected.
1099 : 0 : maBtnOk.Enable(maChecks.GetCheckedEntryCount() != 0);
1100 : 0 : }
1101 : :
1102 : 0 : void ScCheckListMenuWindow::selectCurrentMemberOnly(bool bSet)
1103 : : {
1104 : 0 : setAllMemberState(!bSet);
1105 : 0 : sal_uInt16 nSelected = maChecks.GetSelectEntryPos();
1106 : 0 : maChecks.CheckEntryPos(nSelected, bSet);
1107 : 0 : }
1108 : :
1109 : 0 : void ScCheckListMenuWindow::cycleFocus(bool bReverse)
1110 : : {
1111 : 0 : maTabStopCtrls[mnCurTabStop]->SetFakeFocus(false);
1112 : 0 : maTabStopCtrls[mnCurTabStop]->LoseFocus();
1113 [ # # ]: 0 : if (mnCurTabStop == 0)
1114 : 0 : clearSelectedMenuItem();
1115 : :
1116 [ # # ]: 0 : if (bReverse)
1117 : : {
1118 [ # # ]: 0 : if (mnCurTabStop > 0)
1119 : 0 : --mnCurTabStop;
1120 : : else
1121 : 0 : mnCurTabStop = maTabStopCtrls.size() - 1;
1122 : : }
1123 : : else
1124 : : {
1125 : 0 : ++mnCurTabStop;
1126 [ # # ]: 0 : if (mnCurTabStop >= maTabStopCtrls.size())
1127 : 0 : mnCurTabStop = 0;
1128 : : }
1129 : 0 : maTabStopCtrls[mnCurTabStop]->SetFakeFocus(true);
1130 : 0 : maTabStopCtrls[mnCurTabStop]->GrabFocus();
1131 : 0 : }
1132 : :
1133 : 0 : IMPL_LINK( ScCheckListMenuWindow, ButtonHdl, Button*, pBtn )
1134 : : {
1135 [ # # ]: 0 : if (pBtn == &maBtnOk)
1136 : 0 : close(true);
1137 [ # # ]: 0 : else if (pBtn == &maBtnSelectSingle)
1138 : : {
1139 : 0 : selectCurrentMemberOnly(true);
1140 : 0 : CheckHdl(&maChecks);
1141 : : }
1142 [ # # ]: 0 : else if (pBtn == &maBtnUnselectSingle)
1143 : : {
1144 : 0 : selectCurrentMemberOnly(false);
1145 : 0 : CheckHdl(&maChecks);
1146 : : }
1147 : 0 : return 0;
1148 : : }
1149 : :
1150 : 0 : IMPL_LINK_NOARG(ScCheckListMenuWindow, TriStateHdl)
1151 : : {
1152 [ # # # ]: 0 : switch (mePrevToggleAllState)
1153 : : {
1154 : : case STATE_NOCHECK:
1155 : 0 : maChkToggleAll.SetState(STATE_CHECK);
1156 : 0 : setAllMemberState(true);
1157 : 0 : break;
1158 : : case STATE_CHECK:
1159 : 0 : maChkToggleAll.SetState(STATE_NOCHECK);
1160 : 0 : setAllMemberState(false);
1161 : 0 : break;
1162 : : case STATE_DONTKNOW:
1163 : : default:
1164 : 0 : maChkToggleAll.SetState(STATE_CHECK);
1165 : 0 : setAllMemberState(true);
1166 : 0 : break;
1167 : : }
1168 : :
1169 : 0 : mePrevToggleAllState = maChkToggleAll.GetState();
1170 : 0 : return 0;
1171 : : }
1172 : :
1173 : 0 : IMPL_LINK( ScCheckListMenuWindow, CheckHdl, SvTreeListBox*, pChecks )
1174 : : {
1175 [ # # ]: 0 : if (pChecks != &maChecks)
1176 : 0 : return 0;
1177 : :
1178 : 0 : size_t nNumChecked = maChecks.GetCheckedEntryCount();
1179 [ # # ]: 0 : if (nNumChecked == maMembers.size())
1180 : : // all members visible
1181 : 0 : maChkToggleAll.SetState(STATE_CHECK);
1182 [ # # ]: 0 : else if (nNumChecked == 0)
1183 : : // no members visible
1184 : 0 : maChkToggleAll.SetState(STATE_NOCHECK);
1185 : : else
1186 : 0 : maChkToggleAll.SetState(STATE_DONTKNOW);
1187 : :
1188 [ # # ]: 0 : if (!maConfig.mbAllowEmptySet)
1189 : : // We need to have at least one member selected.
1190 : 0 : maBtnOk.Enable(nNumChecked != 0);
1191 : :
1192 : 0 : mePrevToggleAllState = maChkToggleAll.GetState();
1193 : 0 : return 0;
1194 : : }
1195 : :
1196 : 0 : void ScCheckListMenuWindow::MouseMove(const MouseEvent& rMEvt)
1197 : : {
1198 : 0 : ScMenuFloatingWindow::MouseMove(rMEvt);
1199 : :
1200 : 0 : size_t nSelectedMenu = getSelectedMenuItem();
1201 [ # # ]: 0 : if (nSelectedMenu == MENU_NOT_SELECTED)
1202 : 0 : queueCloseSubMenu();
1203 : 0 : }
1204 : :
1205 : 0 : long ScCheckListMenuWindow::Notify(NotifyEvent& rNEvt)
1206 : : {
1207 [ # # ]: 0 : switch (rNEvt.GetType())
1208 : : {
1209 : : case EVENT_KEYUP:
1210 : : {
1211 : 0 : const KeyEvent* pKeyEvent = rNEvt.GetKeyEvent();
1212 : 0 : const KeyCode& rCode = pKeyEvent->GetKeyCode();
1213 : 0 : bool bShift = rCode.IsShift();
1214 [ # # ]: 0 : if (rCode.GetCode() == KEY_TAB)
1215 : : {
1216 : 0 : cycleFocus(bShift);
1217 : 0 : return true;
1218 : : }
1219 : : }
1220 : 0 : break;
1221 : : }
1222 : 0 : return ScMenuFloatingWindow::Notify(rNEvt);
1223 : : }
1224 : :
1225 : 0 : void ScCheckListMenuWindow::Paint(const Rectangle& rRect)
1226 : : {
1227 [ # # ]: 0 : ScMenuFloatingWindow::Paint(rRect);
1228 : :
1229 : 0 : const StyleSettings& rStyle = GetSettings().GetStyleSettings();
1230 : 0 : Color aMemberBackColor = rStyle.GetFieldColor();
1231 : 0 : Color aBorderColor = rStyle.GetShadowColor();
1232 : :
1233 : 0 : Point aPos;
1234 : 0 : Size aSize;
1235 [ # # ]: 0 : getSectionPosSize(aPos, aSize, LISTBOX_AREA_OUTER);
1236 : :
1237 : : // Member list box background
1238 [ # # ]: 0 : SetFillColor(aMemberBackColor);
1239 [ # # ]: 0 : SetLineColor(aBorderColor);
1240 [ # # ][ # # ]: 0 : DrawRect(Rectangle(aPos,aSize));
1241 : :
1242 : : // Single-action button box
1243 [ # # ]: 0 : getSectionPosSize(aPos, aSize, SINGLE_BTN_AREA);
1244 [ # # ]: 0 : SetFillColor(rStyle.GetMenuColor());
1245 [ # # ][ # # ]: 0 : DrawRect(Rectangle(aPos,aSize));
1246 : 0 : }
1247 : :
1248 : 0 : Window* ScCheckListMenuWindow::GetPreferredKeyInputWindow()
1249 : : {
1250 : 0 : return maTabStopCtrls[mnCurTabStop];
1251 : : }
1252 : :
1253 : 0 : Reference<XAccessible> ScCheckListMenuWindow::CreateAccessible()
1254 : : {
1255 [ # # ]: 0 : if (!mxAccessible.is())
1256 : : {
1257 : : mxAccessible.set(new ScAccessibleFilterTopWindow(
1258 [ # # ][ # # ]: 0 : GetAccessibleParentWindow()->GetAccessible(), this, getName(), getDoc()));
[ # # ]
1259 [ # # ]: 0 : ScAccessibleFilterTopWindow* pAccTop = static_cast<ScAccessibleFilterTopWindow*>(mxAccessible.get());
1260 : 0 : fillMenuItemsToAccessible(pAccTop);
1261 : :
1262 : : pAccTop->setAccessibleChild(
1263 [ # # ]: 0 : maChecks.CreateAccessible(), ScAccessibleFilterTopWindow::LISTBOX);
1264 : : pAccTop->setAccessibleChild(
1265 [ # # ]: 0 : maChkToggleAll.CreateAccessible(), ScAccessibleFilterTopWindow::TOGGLE_ALL);
1266 : : pAccTop->setAccessibleChild(
1267 [ # # ]: 0 : maBtnSelectSingle.CreateAccessible(), ScAccessibleFilterTopWindow::SINGLE_ON_BTN);
1268 : : pAccTop->setAccessibleChild(
1269 [ # # ]: 0 : maBtnUnselectSingle.CreateAccessible(), ScAccessibleFilterTopWindow::SINGLE_OFF_BTN);
1270 : : pAccTop->setAccessibleChild(
1271 [ # # ]: 0 : maBtnOk.CreateAccessible(), ScAccessibleFilterTopWindow::OK_BTN);
1272 : : pAccTop->setAccessibleChild(
1273 [ # # ]: 0 : maBtnCancel.CreateAccessible(), ScAccessibleFilterTopWindow::CANCEL_BTN);
1274 : : }
1275 : :
1276 : 0 : return mxAccessible;
1277 : : }
1278 : :
1279 : 0 : void ScCheckListMenuWindow::setMemberSize(size_t n)
1280 : : {
1281 : 0 : maMembers.reserve(n);
1282 : 0 : }
1283 : :
1284 : 0 : void ScCheckListMenuWindow::addMember(const OUString& rName, bool bVisible)
1285 : : {
1286 : 0 : Member aMember;
1287 : 0 : aMember.maName = rName;
1288 : 0 : aMember.mbVisible = bVisible;
1289 [ # # ]: 0 : maMembers.push_back(aMember);
1290 : 0 : }
1291 : :
1292 : 0 : void ScCheckListMenuWindow::initMembers()
1293 : : {
1294 : 0 : size_t n = maMembers.size();
1295 : 0 : size_t nVisMemCount = 0;
1296 : 0 : maChecks.SetUpdateMode(false);
1297 [ # # ]: 0 : for (size_t i = 0; i < n; ++i)
1298 : : {
1299 [ # # ]: 0 : maChecks.InsertEntry(maMembers[i].maName);
1300 : 0 : maChecks.CheckEntryPos(static_cast< sal_uInt16 >( i ), maMembers[i].mbVisible);
1301 [ # # ]: 0 : if (maMembers[i].mbVisible)
1302 : 0 : ++nVisMemCount;
1303 : : }
1304 [ # # ]: 0 : if (nVisMemCount == n)
1305 : : {
1306 : : // all members visible
1307 : 0 : maChkToggleAll.SetState(STATE_CHECK);
1308 : 0 : mePrevToggleAllState = STATE_CHECK;
1309 : : }
1310 [ # # ]: 0 : else if (nVisMemCount == 0)
1311 : : {
1312 : : // no members visible
1313 : 0 : maChkToggleAll.SetState(STATE_NOCHECK);
1314 : 0 : mePrevToggleAllState = STATE_NOCHECK;
1315 : : }
1316 : : else
1317 : : {
1318 : 0 : maChkToggleAll.SetState(STATE_DONTKNOW);
1319 : 0 : mePrevToggleAllState = STATE_DONTKNOW;
1320 : : }
1321 : 0 : maChecks.SetUpdateMode(true);
1322 : 0 : }
1323 : :
1324 : 0 : void ScCheckListMenuWindow::setConfig(const Config& rConfig)
1325 : : {
1326 : 0 : maConfig = rConfig;
1327 : 0 : }
1328 : :
1329 : 0 : const Size& ScCheckListMenuWindow::getWindowSize() const
1330 : : {
1331 : 0 : return maWndSize;
1332 : : }
1333 : :
1334 : 0 : bool ScCheckListMenuWindow::isAllSelected() const
1335 : : {
1336 : 0 : return maChkToggleAll.IsChecked();
1337 : : }
1338 : :
1339 : 0 : void ScCheckListMenuWindow::getResult(ResultType& rResult)
1340 : : {
1341 [ # # ]: 0 : ResultType aResult;
1342 : 0 : size_t n = maMembers.size();
1343 [ # # ]: 0 : for (size_t i = 0; i < n; ++i)
1344 : : {
1345 [ # # ]: 0 : bool bState = maChecks.IsChecked(static_cast< sal_uInt16 >( i ));
1346 [ # # ]: 0 : aResult.insert(ResultType::value_type(maMembers[i].maName, bState));
1347 : : }
1348 [ # # ][ # # ]: 0 : rResult.swap(aResult);
1349 : 0 : }
1350 : :
1351 : 0 : void ScCheckListMenuWindow::launch(const Rectangle& rRect)
1352 : : {
1353 : 0 : packWindow();
1354 [ # # ]: 0 : if (!maConfig.mbAllowEmptySet)
1355 : : // We need to have at least one member selected.
1356 : 0 : maBtnOk.Enable(maChecks.GetCheckedEntryCount() != 0);
1357 : :
1358 : 0 : StartPopupMode(rRect, (FLOATWIN_POPUPMODE_DOWN | FLOATWIN_POPUPMODE_GRABFOCUS));
1359 : 0 : }
1360 : :
1361 : 0 : void ScCheckListMenuWindow::close(bool bOK)
1362 : : {
1363 [ # # ][ # # ]: 0 : if (bOK && mpOKAction.get())
[ # # ]
1364 : 0 : mpOKAction->execute();
1365 : :
1366 : 0 : EndPopupMode();
1367 : 0 : }
1368 : :
1369 : 0 : void ScCheckListMenuWindow::setExtendedData(ExtendedData* p)
1370 : : {
1371 : 0 : mpExtendedData.reset(p);
1372 : 0 : }
1373 : :
1374 : 0 : ScCheckListMenuWindow::ExtendedData* ScCheckListMenuWindow::getExtendedData()
1375 : : {
1376 : 0 : return mpExtendedData.get();
1377 : : }
1378 : :
1379 : 0 : void ScCheckListMenuWindow::setOKAction(Action* p)
1380 : : {
1381 : 0 : mpOKAction.reset(p);
1382 : 0 : }
1383 : :
1384 : 0 : void ScCheckListMenuWindow::setPopupEndAction(Action* p)
1385 : : {
1386 : 0 : mpPopupEndAction.reset(p);
1387 : 0 : }
1388 : :
1389 : 0 : void ScCheckListMenuWindow::handlePopupEnd()
1390 : : {
1391 : 0 : clearSelectedMenuItem();
1392 [ # # ]: 0 : if (mpPopupEndAction)
1393 : 0 : mpPopupEndAction->execute();
1394 : 0 : }
1395 : :
1396 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|