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