1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "checklistmenu.hxx"
21 #include "checklistmenu.hrc"
22 #include "strload.hxx"
24 #include <vcl/decoview.hxx>
25 #include <tools/wintypes.hxx>
27 #include "AccessibleFilterMenu.hxx"
28 #include "AccessibleFilterTopWindow.hxx"
30 #include <com/sun/star/accessibility/XAccessible.hpp>
31 #include <com/sun/star/accessibility/XAccessibleContext.hpp>
32 #include "svtools/fmtfield.hxx"
33 #include "document.hxx"
35 using ::com::sun::star::uno::Reference
;
36 using ::com::sun::star::accessibility::XAccessible
;
37 using ::com::sun::star::accessibility::XAccessibleContext
;
39 using ::boost::unordered_map
;
40 using ::std::auto_ptr
;
42 ScMenuFloatingWindow::MenuItemData::MenuItemData() :
43 mbEnabled(true), mbSeparator(false),
44 mpAction(static_cast<ScCheckListMenuWindow::Action
*>(NULL
)),
45 mpSubMenuWin(static_cast<ScMenuFloatingWindow
*>(NULL
))
49 // ----------------------------------------------------------------------------
51 ScMenuFloatingWindow::SubMenuItemData::SubMenuItemData(ScMenuFloatingWindow
* pParent
) :
53 mnMenuPos(MENU_NOT_SELECTED
),
56 maTimer
.SetTimeoutHdl( LINK(this, ScMenuFloatingWindow::SubMenuItemData
, TimeoutHdl
) );
57 maTimer
.SetTimeout(mpParent
->GetSettings().GetMouseSettings().GetMenuDelay());
60 void ScMenuFloatingWindow::SubMenuItemData::reset()
63 mnMenuPos
= MENU_NOT_SELECTED
;
67 IMPL_LINK_NOARG(ScMenuFloatingWindow::SubMenuItemData
, TimeoutHdl
)
69 mpParent
->handleMenuTimeout(this);
73 // ----------------------------------------------------------------------------
75 size_t ScMenuFloatingWindow::MENU_NOT_SELECTED
= 999;
77 ScMenuFloatingWindow::ScMenuFloatingWindow(Window
* pParent
, ScDocument
* pDoc
, sal_uInt16 nMenuStackLevel
) :
78 PopupMenuFloatingWindow(pParent
),
81 maName("ScMenuFloatingWindow"),
82 mnSelectedMenu(MENU_NOT_SELECTED
),
83 mnClickedMenu(MENU_NOT_SELECTED
),
85 mpParentMenu(dynamic_cast<ScMenuFloatingWindow
*>(pParent
))
87 SetMenuStackLevel(nMenuStackLevel
);
89 // TODO: How do we get the right font to use here ?
90 const sal_uInt16 nPopupFontHeight
= 12;
91 const StyleSettings
& rStyle
= GetSettings().GetStyleSettings();
92 maLabelFont
= rStyle
.GetLabelFont();
93 maLabelFont
.SetHeight(nPopupFontHeight
);
96 SetText( OUString("ScMenuFloatingWindow") );
99 ScMenuFloatingWindow::~ScMenuFloatingWindow()
104 void ScMenuFloatingWindow::PopupModeEnd()
109 void ScMenuFloatingWindow::MouseMove(const MouseEvent
& rMEvt
)
111 const Point
& rPos
= rMEvt
.GetPosPixel();
112 size_t nSelectedMenu
= getEnclosingMenuItem(rPos
);
113 setSelectedMenuItem(nSelectedMenu
, true, false);
115 Window::MouseMove(rMEvt
);
118 void ScMenuFloatingWindow::MouseButtonDown(const MouseEvent
& rMEvt
)
120 const Point
& rPos
= rMEvt
.GetPosPixel();
121 mnClickedMenu
= getEnclosingMenuItem(rPos
);
122 Window::MouseButtonDown(rMEvt
);
125 void ScMenuFloatingWindow::MouseButtonUp(const MouseEvent
& rMEvt
)
127 executeMenuItem(mnClickedMenu
);
128 mnClickedMenu
= MENU_NOT_SELECTED
;
129 Window::MouseButtonUp(rMEvt
);
132 void ScMenuFloatingWindow::KeyInput(const KeyEvent
& rKEvt
)
134 if (maMenuItems
.empty())
136 Window::KeyInput(rKEvt
);
140 const KeyCode
& rKeyCode
= rKEvt
.GetKeyCode();
141 bool bHandled
= true;
142 size_t nSelectedMenu
= mnSelectedMenu
;
143 size_t nLastMenuPos
= maMenuItems
.size() - 1;
144 switch (rKeyCode
.GetCode())
148 if (nLastMenuPos
== 0)
149 // There is only one menu item. Do nothing.
152 size_t nOldPos
= nSelectedMenu
;
154 if (nSelectedMenu
== MENU_NOT_SELECTED
|| nSelectedMenu
== 0)
155 nSelectedMenu
= nLastMenuPos
;
159 // Loop until a non-separator menu item is found.
160 while (nSelectedMenu
!= nOldPos
)
162 if (maMenuItems
[nSelectedMenu
].mbSeparator
)
167 nSelectedMenu
= nLastMenuPos
;
173 setSelectedMenuItem(nSelectedMenu
, false, false);
178 if (nLastMenuPos
== 0)
179 // There is only one menu item. Do nothing.
182 size_t nOldPos
= nSelectedMenu
;
184 if (nSelectedMenu
== MENU_NOT_SELECTED
|| nSelectedMenu
== nLastMenuPos
)
189 // Loop until a non-separator menu item is found.
190 while (nSelectedMenu
!= nOldPos
)
192 if (maMenuItems
[nSelectedMenu
].mbSeparator
)
194 if (nSelectedMenu
== nLastMenuPos
)
203 setSelectedMenuItem(nSelectedMenu
, false, false);
208 mpParentMenu
->endSubMenu(this);
212 if (mnSelectedMenu
>= maMenuItems
.size() || mnSelectedMenu
== MENU_NOT_SELECTED
)
215 const MenuItemData
& rMenu
= maMenuItems
[mnSelectedMenu
];
216 if (!rMenu
.mbEnabled
|| !rMenu
.mpSubMenuWin
)
219 maOpenTimer
.mnMenuPos
= mnSelectedMenu
;
220 maOpenTimer
.mpSubMenu
= rMenu
.mpSubMenuWin
.get();
225 if (nSelectedMenu
!= MENU_NOT_SELECTED
)
226 executeMenuItem(nSelectedMenu
);
233 Window::KeyInput(rKEvt
);
236 void ScMenuFloatingWindow::Paint(const Rectangle
& /*rRect*/)
238 const StyleSettings
& rStyle
= GetSettings().GetStyleSettings();
239 Color aBackColor
= rStyle
.GetMenuColor();
240 Color aBorderColor
= rStyle
.GetShadowColor();
242 Rectangle
aCtrlRect(Point(0, 0), GetOutputSizePixel());
245 bool bNativeDrawn
= true;
246 if (IsNativeControlSupported(CTRL_MENU_POPUP
, PART_ENTIRE_CONTROL
))
249 bNativeDrawn
= DrawNativeControl(
250 CTRL_MENU_POPUP
, PART_ENTIRE_CONTROL
, aCtrlRect
, CTRL_STATE_ENABLED
,
251 ImplControlValue(), OUString());
254 bNativeDrawn
= false;
258 SetFillColor(aBackColor
);
259 SetLineColor(aBorderColor
);
264 SetTextColor(rStyle
.GetMenuTextColor());
268 Reference
<XAccessible
> ScMenuFloatingWindow::CreateAccessible()
270 if (!mxAccessible
.is())
272 Reference
<XAccessible
> xAccParent
= mpParentMenu
?
273 mpParentMenu
->GetAccessible() : GetAccessibleParentWindow()->GetAccessible();
275 mxAccessible
.set(new ScAccessibleFilterMenu(xAccParent
, this, maName
, 999));
276 ScAccessibleFilterMenu
* p
= static_cast<ScAccessibleFilterMenu
*>(
279 vector
<MenuItemData
>::const_iterator itr
, itrBeg
= maMenuItems
.begin(), itrEnd
= maMenuItems
.end();
280 for (itr
= itrBeg
; itr
!= itrEnd
; ++itr
)
282 size_t nPos
= ::std::distance(itrBeg
, itr
);
283 p
->appendMenuItem(itr
->maText
, itr
->mbEnabled
, nPos
);
290 void ScMenuFloatingWindow::addMenuItem(const OUString
& rText
, bool bEnabled
, Action
* pAction
)
293 aItem
.maText
= rText
;
294 aItem
.mbEnabled
= bEnabled
;
295 aItem
.mpAction
.reset(pAction
);
296 maMenuItems
.push_back(aItem
);
299 void ScMenuFloatingWindow::addSeparator()
302 aItem
.mbSeparator
= true;
303 maMenuItems
.push_back(aItem
);
306 ScMenuFloatingWindow
* ScMenuFloatingWindow::addSubMenuItem(const OUString
& rText
, bool bEnabled
)
309 aItem
.maText
= rText
;
310 aItem
.mbEnabled
= bEnabled
;
311 aItem
.mpSubMenuWin
.reset(new ScMenuFloatingWindow(this, mpDoc
, GetMenuStackLevel()+1));
312 aItem
.mpSubMenuWin
->setName(rText
);
313 maMenuItems
.push_back(aItem
);
314 return aItem
.mpSubMenuWin
.get();
317 void ScMenuFloatingWindow::handlePopupEnd()
319 clearSelectedMenuItem();
322 Size
ScMenuFloatingWindow::getMenuSize() const
324 if (maMenuItems
.empty())
327 vector
<MenuItemData
>::const_iterator itr
= maMenuItems
.begin(), itrEnd
= maMenuItems
.end();
329 for (; itr
!= itrEnd
; ++itr
)
331 if (itr
->mbSeparator
)
334 nTextWidth
= ::std::max(GetTextWidth(itr
->maText
), nTextWidth
);
337 size_t nLastPos
= maMenuItems
.size()-1;
340 getMenuItemPosSize(nLastPos
, aPos
, aSize
);
341 aPos
.X() += nTextWidth
+ 15;
342 aPos
.Y() += aSize
.Height() + 5;
343 return Size(aPos
.X(), aPos
.Y());
346 void ScMenuFloatingWindow::drawMenuItem(size_t nPos
)
348 if (nPos
>= maMenuItems
.size())
353 getMenuItemPosSize(nPos
, aPos
, aSize
);
355 DecorationView
aDecoView(this);
357 long nYOffset
= (aSize
.Height() - maLabelFont
.GetHeight())/2;
358 DrawCtrlText(Point(aPos
.X()+nXOffset
, aPos
.Y() + nYOffset
), maMenuItems
[nPos
].maText
, 0, STRING_LEN
,
359 maMenuItems
[nPos
].mbEnabled
? TEXT_DRAW_MNEMONIC
: TEXT_DRAW_DISABLE
);
361 if (maMenuItems
[nPos
].mpSubMenuWin
)
363 long nFontHeight
= maLabelFont
.GetHeight();
364 Point aMarkerPos
= aPos
;
365 aMarkerPos
.Y() += aSize
.Height()/2 - nFontHeight
/4 + 1;
366 aMarkerPos
.X() += aSize
.Width() - nFontHeight
+ nFontHeight
/4;
367 Size
aMarkerSize(nFontHeight
/2, nFontHeight
/2);
368 aDecoView
.DrawSymbol(Rectangle(aMarkerPos
, aMarkerSize
),
369 SYMBOL_SPIN_RIGHT
, GetTextColor(), 0);
373 void ScMenuFloatingWindow::drawSeparator(size_t nPos
)
377 getMenuItemPosSize(nPos
, aPos
, aSize
);
378 Rectangle
aRegion(aPos
,aSize
);
380 if (IsNativeControlSupported(CTRL_MENU_POPUP
, PART_ENTIRE_CONTROL
))
382 Push(PUSH_CLIPREGION
);
383 IntersectClipRegion(aRegion
);
384 Rectangle
aCtrlRect(Point(0,0), GetOutputSizePixel());
386 CTRL_MENU_POPUP
, PART_ENTIRE_CONTROL
, aCtrlRect
, CTRL_STATE_ENABLED
,
387 ImplControlValue(), OUString());
392 bool bNativeDrawn
= false;
393 if (IsNativeControlSupported(CTRL_MENU_POPUP
, PART_MENU_SEPARATOR
))
395 ControlState nState
= 0;
396 const MenuItemData
& rData
= maMenuItems
[nPos
];
398 nState
|= CTRL_STATE_ENABLED
;
400 bNativeDrawn
= DrawNativeControl(
401 CTRL_MENU_POPUP
, PART_MENU_SEPARATOR
,
402 aRegion
, nState
, ImplControlValue(), OUString());
407 const StyleSettings
& rStyle
= GetSettings().GetStyleSettings();
408 Point aTmpPos
= aPos
;
409 aTmpPos
.Y() += aSize
.Height()/2;
410 SetLineColor(rStyle
.GetShadowColor());
411 DrawLine(aTmpPos
, Point(aSize
.Width()+aTmpPos
.X(), aTmpPos
.Y()));
413 SetLineColor(rStyle
.GetLightColor());
414 DrawLine(aTmpPos
, Point(aSize
.Width()+aTmpPos
.X(), aTmpPos
.Y()));
419 void ScMenuFloatingWindow::drawAllMenuItems()
421 size_t n
= maMenuItems
.size();
422 for (size_t i
= 0; i
< n
; ++i
)
424 if (maMenuItems
[i
].mbSeparator
)
429 highlightMenuItem(i
, i
== mnSelectedMenu
);
433 const Font
& ScMenuFloatingWindow::getLabelFont() const
438 void ScMenuFloatingWindow::executeMenuItem(size_t nPos
)
440 if (nPos
>= maMenuItems
.size())
443 if (!maMenuItems
[nPos
].mpAction
)
444 // no action is defined.
447 maMenuItems
[nPos
].mpAction
->execute();
448 terminateAllPopupMenus();
451 void ScMenuFloatingWindow::setSelectedMenuItem(size_t nPos
, bool bSubMenuTimer
, bool bEnsureSubMenu
)
453 if (mnSelectedMenu
== nPos
)
459 // Dismiss any child popup menu windows.
460 if (mnSelectedMenu
< maMenuItems
.size() &&
461 maMenuItems
[mnSelectedMenu
].mpSubMenuWin
&&
462 maMenuItems
[mnSelectedMenu
].mpSubMenuWin
->IsVisible())
464 maMenuItems
[mnSelectedMenu
].mpSubMenuWin
->ensureSubMenuNotVisible();
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 if (!IsVisible() && mpParentMenu
)
471 mpParentMenu
->ensureSubMenuVisible(this);
474 selectMenuItem(mnSelectedMenu
, false, bSubMenuTimer
);
475 selectMenuItem(nPos
, true, bSubMenuTimer
);
476 mnSelectedMenu
= nPos
;
478 fireMenuHighlightedEvent();
481 size_t ScMenuFloatingWindow::getSelectedMenuItem() const
483 return mnSelectedMenu
;
486 void ScMenuFloatingWindow::handleMenuTimeout(SubMenuItemData
* pTimer
)
488 if (pTimer
== &maOpenTimer
)
490 // Close any open submenu immediately.
491 if (maCloseTimer
.mpSubMenu
)
493 maCloseTimer
.mpSubMenu
->EndPopupMode();
494 maCloseTimer
.mpSubMenu
= NULL
;
495 maCloseTimer
.maTimer
.Stop();
498 launchSubMenu(false);
500 else if (pTimer
== &maCloseTimer
)
503 if (maCloseTimer
.mpSubMenu
)
505 maOpenTimer
.mpSubMenu
= NULL
;
507 maCloseTimer
.mpSubMenu
->EndPopupMode();
508 maCloseTimer
.mpSubMenu
= NULL
;
510 highlightMenuItem(maOpenTimer
.mnMenuPos
, false);
511 maOpenTimer
.mnMenuPos
= MENU_NOT_SELECTED
;
516 void ScMenuFloatingWindow::queueLaunchSubMenu(size_t nPos
, ScMenuFloatingWindow
* pMenu
)
521 // Set the submenu on launch queue.
522 if (maOpenTimer
.mpSubMenu
)
524 if (maOpenTimer
.mpSubMenu
== pMenu
)
526 if (pMenu
== maCloseTimer
.mpSubMenu
)
527 maCloseTimer
.reset();
531 // new submenu is being requested.
535 maOpenTimer
.mpSubMenu
= pMenu
;
536 maOpenTimer
.mnMenuPos
= nPos
;
537 maOpenTimer
.maTimer
.Start();
540 void ScMenuFloatingWindow::queueCloseSubMenu()
542 if (!maOpenTimer
.mpSubMenu
)
543 // There is no submenu to close.
546 // Stop any submenu on queue for opening.
547 maOpenTimer
.maTimer
.Stop();
549 maCloseTimer
.mpSubMenu
= maOpenTimer
.mpSubMenu
;
550 maCloseTimer
.mnMenuPos
= maOpenTimer
.mnMenuPos
;
551 maCloseTimer
.maTimer
.Start();
554 void ScMenuFloatingWindow::launchSubMenu(bool bSetMenuPos
)
558 getMenuItemPosSize(maOpenTimer
.mnMenuPos
, aPos
, aSize
);
559 ScMenuFloatingWindow
* pSubMenu
= maOpenTimer
.mpSubMenu
;
564 sal_uInt32 nOldFlags
= GetPopupModeFlags();
565 SetPopupModeFlags(nOldFlags
| FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE
);
566 pSubMenu
->resizeToFitMenuItems(); // set the size before launching the popup to get it positioned correctly.
567 pSubMenu
->StartPopupMode(
568 Rectangle(aPos
,aSize
), (FLOATWIN_POPUPMODE_RIGHT
| FLOATWIN_POPUPMODE_GRABFOCUS
));
569 pSubMenu
->AddPopupModeWindow(this);
571 pSubMenu
->setSelectedMenuItem(0, false, false); // select menu item after the popup becomes fully visible.
572 SetPopupModeFlags(nOldFlags
);
575 void ScMenuFloatingWindow::endSubMenu(ScMenuFloatingWindow
* pSubMenu
)
580 pSubMenu
->EndPopupMode();
583 size_t nMenuPos
= getSubMenuPos(pSubMenu
);
584 if (nMenuPos
!= MENU_NOT_SELECTED
)
586 highlightMenuItem(nMenuPos
, true);
587 mnSelectedMenu
= nMenuPos
;
588 fireMenuHighlightedEvent();
592 void ScMenuFloatingWindow::fillMenuItemsToAccessible(ScAccessibleFilterMenu
* pAccMenu
) const
594 vector
<MenuItemData
>::const_iterator itr
, itrBeg
= maMenuItems
.begin(), itrEnd
= maMenuItems
.end();
595 for (itr
= itrBeg
; itr
!= itrEnd
; ++itr
)
597 size_t nPos
= ::std::distance(itrBeg
, itr
);
598 pAccMenu
->appendMenuItem(itr
->maText
, itr
->mbEnabled
, nPos
);
602 void ScMenuFloatingWindow::resizeToFitMenuItems()
604 SetOutputSizePixel(getMenuSize());
607 void ScMenuFloatingWindow::selectMenuItem(size_t nPos
, bool bSelected
, bool bSubMenuTimer
)
609 if (nPos
>= maMenuItems
.size() || nPos
== MENU_NOT_SELECTED
)
615 if (!maMenuItems
[nPos
].mbEnabled
)
621 highlightMenuItem(nPos
, bSelected
);
626 mpParentMenu
->setSubMenuFocused(this);
630 if (maMenuItems
[nPos
].mpSubMenuWin
)
632 ScMenuFloatingWindow
* pSubMenu
= maMenuItems
[nPos
].mpSubMenuWin
.get();
633 queueLaunchSubMenu(nPos
, pSubMenu
);
641 void ScMenuFloatingWindow::clearSelectedMenuItem()
643 selectMenuItem(mnSelectedMenu
, false, false);
644 mnSelectedMenu
= MENU_NOT_SELECTED
;
647 ScMenuFloatingWindow
* ScMenuFloatingWindow::getSubMenuWindow(size_t nPos
) const
649 if (maMenuItems
.size() <= nPos
)
652 return maMenuItems
[nPos
].mpSubMenuWin
.get();
655 bool ScMenuFloatingWindow::isMenuItemSelected(size_t nPos
) const
657 return nPos
== mnSelectedMenu
;
660 void ScMenuFloatingWindow::setName(const OUString
& rName
)
665 const OUString
& ScMenuFloatingWindow::getName() const
670 void ScMenuFloatingWindow::highlightMenuItem(size_t nPos
, bool bSelected
)
672 if (nPos
== MENU_NOT_SELECTED
)
675 const StyleSettings
& rStyle
= GetSettings().GetStyleSettings();
676 Color aBackColor
= rStyle
.GetMenuColor();
677 SetFillColor(aBackColor
);
678 SetLineColor(aBackColor
);
682 getMenuItemPosSize(nPos
, aPos
, aSize
);
683 Rectangle
aRegion(aPos
,aSize
);
685 if (IsNativeControlSupported(CTRL_MENU_POPUP
, PART_ENTIRE_CONTROL
))
687 Push(PUSH_CLIPREGION
);
688 IntersectClipRegion(Rectangle(aPos
, aSize
));
689 Rectangle
aCtrlRect(Point(0,0), GetOutputSizePixel());
691 CTRL_MENU_POPUP
, PART_ENTIRE_CONTROL
, aCtrlRect
, CTRL_STATE_ENABLED
,
692 ImplControlValue(), OUString());
697 bool bNativeDrawn
= true;
698 if (IsNativeControlSupported(CTRL_MENU_POPUP
, PART_MENU_ITEM
))
700 ControlState nState
= bSelected
? CTRL_STATE_SELECTED
: 0;
701 if (maMenuItems
[nPos
].mbEnabled
)
702 nState
|= CTRL_STATE_ENABLED
;
703 bNativeDrawn
= DrawNativeControl(
704 CTRL_MENU_POPUP
, PART_MENU_ITEM
, aRegion
, nState
, ImplControlValue(), OUString());
707 bNativeDrawn
= false;
713 aBackColor
= rStyle
.GetMenuHighlightColor();
714 SetFillColor(aBackColor
);
715 SetLineColor(aBackColor
);
717 DrawRect(Rectangle(aPos
,aSize
));
720 Color aTextColor
= bSelected
? rStyle
.GetMenuHighlightTextColor() : rStyle
.GetMenuTextColor();
721 SetTextColor(aTextColor
);
725 void ScMenuFloatingWindow::getMenuItemPosSize(size_t nPos
, Point
& rPos
, Size
& rSize
) const
727 size_t nCount
= maMenuItems
.size();
731 const sal_uInt16 nLeftMargin
= 5;
732 const sal_uInt16 nTopMargin
= 5;
733 const sal_uInt16 nMenuItemHeight
= static_cast<sal_uInt16
>(maLabelFont
.GetHeight()*1.8);
734 const sal_uInt16 nSepHeight
= static_cast<sal_uInt16
>(maLabelFont
.GetHeight()*0.8);
736 Point
aPos1(nLeftMargin
, nTopMargin
);
738 for (size_t i
= 0; i
< nPos
; ++i
)
739 rPos
.Y() += maMenuItems
[i
].mbSeparator
? nSepHeight
: nMenuItemHeight
;
741 Size aWndSize
= GetSizePixel();
742 sal_uInt16 nH
= maMenuItems
[nPos
].mbSeparator
? nSepHeight
: nMenuItemHeight
;
743 rSize
= Size(aWndSize
.Width() - nLeftMargin
*2, nH
);
746 ScMenuFloatingWindow
* ScMenuFloatingWindow::getParentMenuWindow() const
751 size_t ScMenuFloatingWindow::getEnclosingMenuItem(const Point
& rPos
) const
753 size_t n
= maMenuItems
.size();
754 for (size_t i
= 0; i
< n
; ++i
)
758 getMenuItemPosSize(i
, aPos
, aSize
);
759 Rectangle
aRect(aPos
, aSize
);
760 if (aRect
.IsInside(rPos
))
761 return maMenuItems
[i
].mbSeparator
? MENU_NOT_SELECTED
: i
;
763 return MENU_NOT_SELECTED
;
766 size_t ScMenuFloatingWindow::getSubMenuPos(ScMenuFloatingWindow
* pSubMenu
)
768 size_t n
= maMenuItems
.size();
769 for (size_t i
= 0; i
< n
; ++i
)
771 if (maMenuItems
[i
].mpSubMenuWin
.get() == pSubMenu
)
774 return MENU_NOT_SELECTED
;
777 void ScMenuFloatingWindow::fireMenuHighlightedEvent()
779 if (mnSelectedMenu
== MENU_NOT_SELECTED
)
782 if (!mxAccessible
.is())
785 Reference
<XAccessibleContext
> xAccCxt
= mxAccessible
->getAccessibleContext();
789 Reference
<XAccessible
> xAccMenu
= xAccCxt
->getAccessibleChild(mnSelectedMenu
);
793 VclAccessibleEvent
aEvent(VCLEVENT_MENU_HIGHLIGHT
, xAccMenu
);
794 FireVclEvent(&aEvent
);
797 void ScMenuFloatingWindow::setSubMenuFocused(ScMenuFloatingWindow
* pSubMenu
)
799 maCloseTimer
.reset();
800 size_t nMenuPos
= getSubMenuPos(pSubMenu
);
801 if (mnSelectedMenu
!= nMenuPos
)
803 highlightMenuItem(nMenuPos
, true);
804 mnSelectedMenu
= nMenuPos
;
808 void ScMenuFloatingWindow::ensureSubMenuVisible(ScMenuFloatingWindow
* pSubMenu
)
811 mpParentMenu
->ensureSubMenuVisible(this);
813 if (pSubMenu
->IsVisible())
816 // Find the menu position of the submenu.
817 size_t nMenuPos
= getSubMenuPos(pSubMenu
);
818 if (nMenuPos
!= MENU_NOT_SELECTED
)
820 setSelectedMenuItem(nMenuPos
, false, false);
824 getMenuItemPosSize(nMenuPos
, aPos
, aSize
);
826 sal_uInt32 nOldFlags
= GetPopupModeFlags();
827 SetPopupModeFlags(nOldFlags
| FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE
);
828 pSubMenu
->resizeToFitMenuItems(); // set the size before launching the popup to get it positioned correctly.
829 pSubMenu
->StartPopupMode(
830 Rectangle(aPos
,aSize
), (FLOATWIN_POPUPMODE_RIGHT
| FLOATWIN_POPUPMODE_GRABFOCUS
));
831 pSubMenu
->AddPopupModeWindow(this);
832 SetPopupModeFlags(nOldFlags
);
836 void ScMenuFloatingWindow::ensureSubMenuNotVisible()
838 if (mnSelectedMenu
<= maMenuItems
.size() &&
839 maMenuItems
[mnSelectedMenu
].mpSubMenuWin
&&
840 maMenuItems
[mnSelectedMenu
].mpSubMenuWin
->IsVisible())
842 maMenuItems
[mnSelectedMenu
].mpSubMenuWin
->ensureSubMenuNotVisible();
848 void ScMenuFloatingWindow::terminateAllPopupMenus()
852 mpParentMenu
->terminateAllPopupMenus();
855 ScDocument
* ScMenuFloatingWindow::getDoc()
860 // ============================================================================
862 ScCheckListMenuWindow::Config::Config() :
863 mbAllowEmptySet(true), mbRTL(false)
867 ScCheckListMenuWindow::Member::Member() :
868 mbVisible(true), mbDate(false), mbLeaf(false)
872 // ----------------------------------------------------------------------------
874 ScCheckListMenuWindow::CancelButton::CancelButton(ScCheckListMenuWindow
* pParent
) :
875 ::CancelButton(pParent
), mpParent(pParent
) {}
877 void ScCheckListMenuWindow::CancelButton::Click()
879 mpParent
->EndPopupMode();
880 ::CancelButton::Click();
883 // ----------------------------------------------------------------------------
885 ScCheckListMenuWindow::ScCheckListMenuWindow(Window
* pParent
, ScDocument
* pDoc
) :
886 ScMenuFloatingWindow(pParent
, pDoc
),
887 maChecks(this, WB_HASBUTTONS
| WB_HASLINES
| WB_HASLINESATROOT
| WB_HASBUTTONSATROOT
),
888 maChkToggleAll(this, 0),
889 maBtnSelectSingle (this, 0),
890 maBtnUnselectSingle(this, 0),
894 mpExtendedData(NULL
),
896 mpPopupEndAction(NULL
),
898 mePrevToggleAllState(STATE_DONTKNOW
)
900 maTabStopCtrls
.reserve(7);
901 maTabStopCtrls
.push_back(this);
902 maTabStopCtrls
.push_back(&maChecks
);
903 maTabStopCtrls
.push_back(&maChkToggleAll
);
904 maTabStopCtrls
.push_back(&maBtnSelectSingle
);
905 maTabStopCtrls
.push_back(&maBtnUnselectSingle
);
906 maTabStopCtrls
.push_back(&maBtnOk
);
907 maTabStopCtrls
.push_back(&maBtnCancel
);
909 // Enable type-ahead search in the check list box.
910 maChecks
.SetStyle(maChecks
.GetStyle() | WB_QUICK_SEARCH
);
913 ScCheckListMenuWindow::~ScCheckListMenuWindow()
917 void ScCheckListMenuWindow::getSectionPosSize(
918 Point
& rPos
, Size
& rSize
, SectionType eType
) const
920 // constant parameters.
921 const long nListBoxMargin
= 5; // horizontal distance from the side of the dialog to the listbox border.
922 const long nListBoxInnerPadding
= 5;
923 const long nTopMargin
= 5;
924 const long nMenuHeight
= maMenuSize
.getHeight();
925 const long nSingleItemBtnAreaHeight
= 32; // height of the middle area below the list box where the single-action buttons are.
926 const long nBottomBtnAreaHeight
= 50; // height of the bottom area where the OK and Cancel buttons are.
927 const long nBtnWidth
= 90;
928 const long nLabelHeight
= getLabelFont().GetHeight();
929 const long nBtnHeight
= nLabelHeight
*2;
930 const long nBottomMargin
= 10;
931 const long nMenuListMargin
= 5;
933 // parameters calculated from constants.
934 const long nListBoxWidth
= maWndSize
.Width() - nListBoxMargin
*2;
935 const long nListBoxHeight
= maWndSize
.Height() - nTopMargin
- nMenuHeight
-
936 nMenuListMargin
- nSingleItemBtnAreaHeight
- nBottomBtnAreaHeight
;
938 const long nSingleBtnAreaY
= nTopMargin
+ nMenuHeight
+ nListBoxHeight
+ nMenuListMargin
- 1;
948 case LISTBOX_AREA_OUTER
:
950 rPos
= Point(nListBoxMargin
, nTopMargin
+ nMenuHeight
+ nMenuListMargin
);
951 rSize
= Size(nListBoxWidth
, nListBoxHeight
);
954 case LISTBOX_AREA_INNER
:
956 rPos
= Point(nListBoxMargin
, nTopMargin
+ nMenuHeight
+ nMenuListMargin
);
957 rPos
.X() += nListBoxInnerPadding
;
958 rPos
.Y() += nListBoxInnerPadding
;
960 rSize
= Size(nListBoxWidth
, nListBoxHeight
);
961 rSize
.Width() -= nListBoxInnerPadding
*2;
962 rSize
.Height() -= nListBoxInnerPadding
*2;
965 case SINGLE_BTN_AREA
:
967 rPos
= Point(nListBoxMargin
, nSingleBtnAreaY
);
968 rSize
= Size(nListBoxWidth
, nSingleItemBtnAreaHeight
);
971 case CHECK_TOGGLE_ALL
:
973 long h
= std::min(maChkToggleAll
.CalcMinimumSize().Height(), 26L);
974 rPos
= Point(nListBoxMargin
, nSingleBtnAreaY
);
976 rPos
.Y() += (nSingleItemBtnAreaHeight
- h
)/2;
980 case BTN_SINGLE_SELECT
:
983 rPos
= Point(nListBoxMargin
, nSingleBtnAreaY
);
984 rPos
.X() += nListBoxWidth
- h
- 10 - h
- 10;
985 rPos
.Y() += (nSingleItemBtnAreaHeight
- h
)/2;
989 case BTN_SINGLE_UNSELECT
:
992 rPos
= Point(nListBoxMargin
, nSingleBtnAreaY
);
993 rPos
.X() += nListBoxWidth
- h
- 10;
994 rPos
.Y() += (nSingleItemBtnAreaHeight
- h
)/2;
1000 long x
= (maWndSize
.Width() - nBtnWidth
*2)/3;
1001 long y
= maWndSize
.Height() - nBottomMargin
- nBtnHeight
;
1003 rSize
= Size(nBtnWidth
, nBtnHeight
);
1008 long x
= (maWndSize
.Width() - nBtnWidth
*2)/3*2 + nBtnWidth
;
1009 long y
= maWndSize
.Height() - nBottomMargin
- nBtnHeight
;
1011 rSize
= Size(nBtnWidth
, nBtnHeight
);
1019 void ScCheckListMenuWindow::packWindow()
1021 maMenuSize
= getMenuSize();
1023 if (maWndSize
.Width() < maMenuSize
.Width())
1024 // Widen the window to fit the menu items.
1025 maWndSize
.Width() = maMenuSize
.Width();
1027 // Set proper window height based on the number of menu items.
1028 if (maWndSize
.Height() < maMenuSize
.Height()*2.8)
1029 maWndSize
.Height() = maMenuSize
.Height()*2.8;
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.
1034 SetOutputSizePixel(maWndSize
);
1036 const StyleSettings
& rStyle
= GetSettings().GetStyleSettings();
1040 getSectionPosSize(aPos
, aSize
, WHOLE
);
1041 SetOutputSizePixel(aSize
);
1043 getSectionPosSize(aPos
, aSize
, BTN_OK
);
1044 maBtnOk
.SetPosSizePixel(aPos
, aSize
);
1045 maBtnOk
.SetFont(getLabelFont());
1046 maBtnOk
.SetClickHdl( LINK(this, ScCheckListMenuWindow
, ButtonHdl
) );
1049 getSectionPosSize(aPos
, aSize
, BTN_CANCEL
);
1050 maBtnCancel
.SetPosSizePixel(aPos
, aSize
);
1051 maBtnCancel
.SetFont(getLabelFont());
1054 getSectionPosSize(aPos
, aSize
, LISTBOX_AREA_INNER
);
1055 maChecks
.SetPosSizePixel(aPos
, aSize
);
1056 maChecks
.SetFont(getLabelFont());
1057 maChecks
.SetCheckButtonHdl( LINK(this, ScCheckListMenuWindow
, CheckHdl
) );
1060 getSectionPosSize(aPos
, aSize
, CHECK_TOGGLE_ALL
);
1061 maChkToggleAll
.SetPosSizePixel(aPos
, aSize
);
1062 maChkToggleAll
.SetFont(getLabelFont());
1063 maChkToggleAll
.SetText(SC_STRLOAD(RID_POPUP_FILTER
, STR_BTN_TOGGLE_ALL
));
1064 maChkToggleAll
.SetTextColor(rStyle
.GetMenuTextColor());
1065 maChkToggleAll
.SetControlBackground(rStyle
.GetMenuColor());
1066 maChkToggleAll
.SetClickHdl( LINK(this, ScCheckListMenuWindow
, TriStateHdl
) );
1067 maChkToggleAll
.Show();
1069 getSectionPosSize(aPos
, aSize
, BTN_SINGLE_SELECT
);
1070 maBtnSelectSingle
.SetPosSizePixel(aPos
, aSize
);
1071 maBtnSelectSingle
.SetQuickHelpText(SC_STRLOAD(RID_POPUP_FILTER
, STR_BTN_SELECT_CURRENT
));
1072 maBtnSelectSingle
.SetModeImage(Image(ScResId(RID_IMG_SELECT_CURRENT
)));
1073 maBtnSelectSingle
.SetClickHdl( LINK(this, ScCheckListMenuWindow
, ButtonHdl
) );
1074 maBtnSelectSingle
.Show();
1076 getSectionPosSize(aPos
, aSize
, BTN_SINGLE_UNSELECT
);
1077 maBtnUnselectSingle
.SetPosSizePixel(aPos
, aSize
);
1078 maBtnUnselectSingle
.SetQuickHelpText(SC_STRLOAD(RID_POPUP_FILTER
, STR_BTN_UNSELECT_CURRENT
));
1079 maBtnUnselectSingle
.SetModeImage(Image(ScResId(RID_IMG_UNSELECT_CURRENT
)));
1080 maBtnUnselectSingle
.SetClickHdl( LINK(this, ScCheckListMenuWindow
, ButtonHdl
) );
1081 maBtnUnselectSingle
.Show();
1084 void ScCheckListMenuWindow::setAllMemberState(bool bSet
)
1086 size_t n
= maMembers
.size();
1087 for (size_t i
= 0; i
< n
; ++i
)
1088 maChecks
.CheckEntry( maMembers
[i
].maName
, maMembers
[i
].mpParent
, bSet
);
1090 if (!maConfig
.mbAllowEmptySet
)
1091 // We need to have at least one member selected.
1092 maBtnOk
.Enable(maChecks
.GetCheckedEntryCount() != 0);
1095 void ScCheckListMenuWindow::selectCurrentMemberOnly(bool bSet
)
1097 setAllMemberState(!bSet
);
1098 SvTreeListEntry
* pEntry
= maChecks
.GetCurEntry();
1099 maChecks
.CheckEntry(pEntry
, bSet
);
1102 void ScCheckListMenuWindow::cycleFocus(bool bReverse
)
1104 maTabStopCtrls
[mnCurTabStop
]->SetFakeFocus(false);
1105 maTabStopCtrls
[mnCurTabStop
]->LoseFocus();
1106 if (mnCurTabStop
== 0)
1107 clearSelectedMenuItem();
1111 if (mnCurTabStop
> 0)
1114 mnCurTabStop
= maTabStopCtrls
.size() - 1;
1119 if (mnCurTabStop
>= maTabStopCtrls
.size())
1122 maTabStopCtrls
[mnCurTabStop
]->SetFakeFocus(true);
1123 maTabStopCtrls
[mnCurTabStop
]->GrabFocus();
1126 IMPL_LINK( ScCheckListMenuWindow
, ButtonHdl
, Button
*, pBtn
)
1128 if (pBtn
== &maBtnOk
)
1130 else if (pBtn
== &maBtnSelectSingle
)
1132 selectCurrentMemberOnly(true);
1133 CheckHdl(&maChecks
);
1135 else if (pBtn
== &maBtnUnselectSingle
)
1137 selectCurrentMemberOnly(false);
1138 CheckHdl(&maChecks
);
1143 IMPL_LINK_NOARG(ScCheckListMenuWindow
, TriStateHdl
)
1145 switch (mePrevToggleAllState
)
1148 maChkToggleAll
.SetState(STATE_CHECK
);
1149 setAllMemberState(true);
1152 maChkToggleAll
.SetState(STATE_NOCHECK
);
1153 setAllMemberState(false);
1155 case STATE_DONTKNOW
:
1157 maChkToggleAll
.SetState(STATE_CHECK
);
1158 setAllMemberState(true);
1162 mePrevToggleAllState
= maChkToggleAll
.GetState();
1166 IMPL_LINK( ScCheckListMenuWindow
, CheckHdl
, SvTreeListBox
*, pChecks
)
1168 if (pChecks
!= &maChecks
)
1170 SvTreeListEntry
* pEntry
= pChecks
->GetHdlEntry();
1172 maChecks
.CheckEntry( pEntry
, ( pChecks
->GetCheckButtonState( pEntry
) == SV_BUTTON_CHECKED
) );
1173 size_t nNumChecked
= maChecks
.GetCheckedEntryCount();
1174 if (nNumChecked
== maMembers
.size())
1175 // all members visible
1176 maChkToggleAll
.SetState(STATE_CHECK
);
1177 else if (nNumChecked
== 0)
1178 // no members visible
1179 maChkToggleAll
.SetState(STATE_NOCHECK
);
1181 maChkToggleAll
.SetState(STATE_DONTKNOW
);
1183 if (!maConfig
.mbAllowEmptySet
)
1184 // We need to have at least one member selected.
1185 maBtnOk
.Enable(nNumChecked
!= 0);
1187 mePrevToggleAllState
= maChkToggleAll
.GetState();
1191 void ScCheckListMenuWindow::MouseMove(const MouseEvent
& rMEvt
)
1193 ScMenuFloatingWindow::MouseMove(rMEvt
);
1195 size_t nSelectedMenu
= getSelectedMenuItem();
1196 if (nSelectedMenu
== MENU_NOT_SELECTED
)
1197 queueCloseSubMenu();
1200 long ScCheckListMenuWindow::Notify(NotifyEvent
& rNEvt
)
1202 switch (rNEvt
.GetType())
1206 const KeyEvent
* pKeyEvent
= rNEvt
.GetKeyEvent();
1207 const KeyCode
& rCode
= pKeyEvent
->GetKeyCode();
1208 bool bShift
= rCode
.IsShift();
1209 if (rCode
.GetCode() == KEY_TAB
)
1217 return ScMenuFloatingWindow::Notify(rNEvt
);
1220 void ScCheckListMenuWindow::Paint(const Rectangle
& rRect
)
1222 ScMenuFloatingWindow::Paint(rRect
);
1224 const StyleSettings
& rStyle
= GetSettings().GetStyleSettings();
1225 Color aMemberBackColor
= rStyle
.GetFieldColor();
1226 Color aBorderColor
= rStyle
.GetShadowColor();
1230 getSectionPosSize(aPos
, aSize
, LISTBOX_AREA_OUTER
);
1232 // Member list box background
1233 SetFillColor(aMemberBackColor
);
1234 SetLineColor(aBorderColor
);
1235 DrawRect(Rectangle(aPos
,aSize
));
1237 // Single-action button box
1238 getSectionPosSize(aPos
, aSize
, SINGLE_BTN_AREA
);
1239 SetFillColor(rStyle
.GetMenuColor());
1240 DrawRect(Rectangle(aPos
,aSize
));
1243 Window
* ScCheckListMenuWindow::GetPreferredKeyInputWindow()
1245 return maTabStopCtrls
[mnCurTabStop
];
1248 Reference
<XAccessible
> ScCheckListMenuWindow::CreateAccessible()
1250 if (!mxAccessible
.is())
1252 mxAccessible
.set(new ScAccessibleFilterTopWindow(
1253 GetAccessibleParentWindow()->GetAccessible(), this, getName()));
1254 ScAccessibleFilterTopWindow
* pAccTop
= static_cast<ScAccessibleFilterTopWindow
*>(mxAccessible
.get());
1255 fillMenuItemsToAccessible(pAccTop
);
1257 pAccTop
->setAccessibleChild(
1258 maChecks
.CreateAccessible(), ScAccessibleFilterTopWindow::LISTBOX
);
1259 pAccTop
->setAccessibleChild(
1260 maChkToggleAll
.CreateAccessible(), ScAccessibleFilterTopWindow::TOGGLE_ALL
);
1261 pAccTop
->setAccessibleChild(
1262 maBtnSelectSingle
.CreateAccessible(), ScAccessibleFilterTopWindow::SINGLE_ON_BTN
);
1263 pAccTop
->setAccessibleChild(
1264 maBtnUnselectSingle
.CreateAccessible(), ScAccessibleFilterTopWindow::SINGLE_OFF_BTN
);
1265 pAccTop
->setAccessibleChild(
1266 maBtnOk
.CreateAccessible(), ScAccessibleFilterTopWindow::OK_BTN
);
1267 pAccTop
->setAccessibleChild(
1268 maBtnCancel
.CreateAccessible(), ScAccessibleFilterTopWindow::CANCEL_BTN
);
1271 return mxAccessible
;
1274 void ScCheckListMenuWindow::setMemberSize(size_t n
)
1276 maMembers
.reserve(n
);
1279 void ScCheckListMenuWindow::addDateMember(const OUString
& rsName
, double nVal
, bool bVisible
)
1281 ScDocument
* pDoc
= getDoc();
1284 SvNumberFormatter
* pFormatter
= pDoc
->GetFormatTable();
1288 OUString
sFormat("YYYY/MMMM/DD");
1289 Color
* pColor
= NULL
;
1290 pFormatter
->GetPreviewString(sFormat
,
1296 maChecks
.SetUpdateMode(false);
1297 sal_Int32 nIndex
= 0;
1299 SvTreeListEntry
* pParent
= NULL
;
1303 OUString sPart
= rsDate
.getToken( 0, '/', nIndex
);
1304 bool bLeaf
= ( ++count
== 3 );
1305 SvTreeListEntry
* pChild
= maChecks
.FindEntry( pParent
, sPart
);
1309 pChild
= maChecks
.SvTreeListBox::InsertEntry( sPart
, pParent
, sal_False
, LISTBOX_APPEND
, NULL
, SvLBoxButtonKind_enabledCheckbox
);
1311 pChild
= maChecks
.SvTreeListBox::InsertEntry( sPart
, pParent
, sal_True
, LISTBOX_APPEND
, NULL
, SvLBoxButtonKind_enabledCheckbox
);
1313 aMember
.maName
= sPart
;
1314 aMember
.maRealName
= rsName
;
1315 aMember
.mbDate
= true;
1316 aMember
.mbLeaf
= bLeaf
;
1317 aMember
.mbVisible
= bVisible
;
1318 aMember
.mpParent
= pParent
;
1319 maMembers
.push_back(aMember
);
1323 } while ( nIndex
>= 0 );
1324 maChecks
.SetUpdateMode(true);
1328 void ScCheckListMenuWindow::addMember(const OUString
& rName
, bool bVisible
)
1331 aMember
.maName
= rName
;
1332 aMember
.mbDate
= false;
1333 aMember
.mbLeaf
= true;
1334 aMember
.mbVisible
= bVisible
;
1335 aMember
.mpParent
= NULL
;
1336 maMembers
.push_back(aMember
);
1339 ScCheckListBox::ScCheckListBox( Window
* pParent
, WinBits nWinStyle
)
1340 : SvTreeListBox( pParent
, nWinStyle
), mpCheckButton( NULL
)
1345 SvTreeListEntry
* ScCheckListBox::FindEntry( SvTreeListEntry
* pParent
, const OUString
& sNode
)
1347 sal_uInt16 nRootPos
= 0;
1348 SvTreeListEntry
* pEntry
= pParent
? FirstChild( pParent
) : GetEntry( nRootPos
);
1351 if ( sNode
.equals(GetEntryText( pEntry
)) )
1354 pEntry
= pParent
? NextSibling( pEntry
) : GetEntry( ++nRootPos
);
1359 void ScCheckListBox::Init()
1361 mpCheckButton
= new SvLBoxButtonData( this );
1362 EnableCheckButton( mpCheckButton
);
1363 SetNodeDefaultImages();
1366 sal_Bool
ScCheckListBox::IsChecked( OUString
& sName
, SvTreeListEntry
* pParent
)
1368 SvTreeListEntry
* pEntry
= FindEntry( pParent
, sName
);
1369 if ( pEntry
&& GetCheckButtonState( pEntry
) == SV_BUTTON_CHECKED
)
1374 void ScCheckListBox::CheckEntry( OUString
& sName
, SvTreeListEntry
* pParent
, sal_Bool bCheck
)
1376 SvTreeListEntry
* pEntry
= FindEntry( pParent
, sName
);
1378 CheckEntry( pEntry
, bCheck
);
1381 // Recursively check all children of pParent
1382 void ScCheckListBox::CheckAllChildren( SvTreeListEntry
* pParent
, sal_Bool bCheck
)
1386 SetCheckButtonState(
1387 pParent
, bCheck
? SvButtonState( SV_BUTTON_CHECKED
) :
1388 SvButtonState( SV_BUTTON_UNCHECKED
) );
1390 SvTreeListEntry
* pEntry
= pParent
? FirstChild( pParent
) : First();
1393 CheckAllChildren( pEntry
, bCheck
);
1394 pEntry
= NextSibling( pEntry
);
1398 void ScCheckListBox::CheckEntry( SvTreeListEntry
* pParent
, sal_Bool bCheck
)
1400 // recursively check all items below pParent
1401 CheckAllChildren( pParent
, bCheck
);
1402 // checking pParent can affect ancestors, e.g. if ancestor is unchecked and pParent is
1403 // now checked then the ancestor needs to be checked also
1404 SvTreeListEntry
* pAncestor
= GetParent(pParent
);
1409 // if any first level children checked then ancestor
1410 // needs to be checked, similarly if no first level children
1411 // checked then ancestor needs to be unchecked
1412 SvTreeListEntry
* pChild
= FirstChild( pAncestor
);
1413 bool bChildChecked
= false;
1417 if ( GetCheckButtonState( pChild
) == SV_BUTTON_CHECKED
)
1419 bChildChecked
= true;
1422 pChild
= NextSibling( pChild
);
1424 SetCheckButtonState(
1425 pAncestor
, bChildChecked
? SvButtonState( SV_BUTTON_CHECKED
) :
1426 SvButtonState( SV_BUTTON_UNCHECKED
) );
1427 pAncestor
= GetParent(pAncestor
);
1432 SvTreeListEntry
* ScCheckListBox::CountCheckedEntries( SvTreeListEntry
* pParent
, sal_uLong
& nCount
) const
1434 if ( pParent
&& GetCheckButtonState( pParent
) == SV_BUTTON_CHECKED
)
1436 // Iterate over the children
1437 SvTreeListEntry
* pEntry
= pParent
? FirstChild( pParent
) : First();
1440 CountCheckedEntries( pEntry
, nCount
);
1441 pEntry
= NextSibling( pEntry
);
1446 sal_uInt16
ScCheckListBox::GetCheckedEntryCount() const
1448 sal_uLong nCount
= 0;
1449 CountCheckedEntries( NULL
, nCount
);
1453 void ScCheckListBox::ExpandChildren( SvTreeListEntry
* pParent
)
1457 // Iterate over the children
1458 SvTreeListEntry
* pEntry
= pParent
? FirstChild( pParent
) : First();
1461 ExpandChildren( pEntry
);
1462 pEntry
= NextSibling( pEntry
);
1466 void ScCheckListBox::KeyInput( const KeyEvent
& rKEvt
)
1468 const KeyCode
& rKey
= rKEvt
.GetKeyCode();
1470 if ( rKey
.GetCode() == KEY_RETURN
|| rKey
.GetCode() == KEY_SPACE
)
1472 SvTreeListEntry
* pEntry
= GetCurEntry();
1476 sal_Bool bCheck
= ( GetCheckButtonState( pEntry
) == SV_BUTTON_CHECKED
);
1477 CheckEntry( pEntry
, !bCheck
);
1478 if ( bCheck
!= ( GetCheckButtonState( pEntry
) == SV_BUTTON_CHECKED
) )
1482 else if ( GetEntryCount() )
1483 SvTreeListBox::KeyInput( rKEvt
);
1486 void ScCheckListMenuWindow::initMembers()
1488 size_t n
= maMembers
.size();
1489 size_t nVisMemCount
= 0;
1490 maChecks
.SetUpdateMode(false);
1491 for (size_t i
= 0; i
< n
; ++i
)
1493 if ( !maMembers
[ i
].mbDate
)
1495 maChecks
.InsertEntry(maMembers
[i
].maName
, NULL
, sal_False
, LISTBOX_APPEND
, NULL
,
1496 SvLBoxButtonKind_enabledCheckbox
);
1499 maChecks
.CheckEntry( maMembers
[i
].maName
, maMembers
[i
].mpParent
, maMembers
[i
].mbVisible
);
1500 // Expand first node of checked dates
1501 if ( maMembers
[ i
].mpParent
== NULL
&& maChecks
.IsChecked( maMembers
[i
].maName
, maMembers
[i
].mpParent
) )
1502 maChecks
.Expand( maChecks
.FindEntry( NULL
, maMembers
[ i
].maName
) );
1504 if (maMembers
[i
].mbVisible
)
1507 if (nVisMemCount
== n
)
1509 // all members visible
1510 maChkToggleAll
.SetState(STATE_CHECK
);
1511 mePrevToggleAllState
= STATE_CHECK
;
1513 else if (nVisMemCount
== 0)
1515 // no members visible
1516 maChkToggleAll
.SetState(STATE_NOCHECK
);
1517 mePrevToggleAllState
= STATE_NOCHECK
;
1521 maChkToggleAll
.SetState(STATE_DONTKNOW
);
1522 mePrevToggleAllState
= STATE_DONTKNOW
;
1524 maChecks
.SetUpdateMode(true);
1527 void ScCheckListMenuWindow::setConfig(const Config
& rConfig
)
1532 bool ScCheckListMenuWindow::isAllSelected() const
1534 return maChkToggleAll
.IsChecked();
1537 void ScCheckListMenuWindow::getResult(ResultType
& rResult
)
1540 size_t n
= maMembers
.size();
1541 for (size_t i
= 0; i
< n
; ++i
)
1543 if ( maMembers
[i
].mbLeaf
)
1545 bool bState
= maChecks
.IsChecked( maMembers
[i
].maName
, maMembers
[i
].mpParent
);
1547 if ( maMembers
[i
].mbDate
)
1548 sName
= maMembers
[i
].maRealName
;
1550 sName
= maMembers
[i
].maName
;
1551 aResult
.insert(ResultType::value_type(sName
, bState
));
1554 rResult
.swap(aResult
);
1557 void ScCheckListMenuWindow::launch(const Rectangle
& rRect
)
1560 if (!maConfig
.mbAllowEmptySet
)
1561 // We need to have at least one member selected.
1562 maBtnOk
.Enable(maChecks
.GetCheckedEntryCount() != 0);
1564 Rectangle
aRect(rRect
);
1567 // In RTL mode, the logical "left" is visual "right".
1568 long nLeft
= aRect
.Left() - aRect
.GetWidth();
1569 aRect
.Left() = nLeft
;
1571 else if (maWndSize
.Width() < aRect
.GetWidth())
1573 // Target rectangle (i.e. cell width) is wider than the window.
1574 // Simulate right-aligned launch by modifying the target rectangle
1576 long nDiff
= aRect
.GetWidth() - maWndSize
.Width();
1577 aRect
.Left() += nDiff
;
1580 StartPopupMode(aRect
, (FLOATWIN_POPUPMODE_DOWN
| FLOATWIN_POPUPMODE_GRABFOCUS
));
1581 cycleFocus(); // Set initial focus to the check list box.
1584 void ScCheckListMenuWindow::close(bool bOK
)
1586 if (bOK
&& mpOKAction
.get())
1587 mpOKAction
->execute();
1592 void ScCheckListMenuWindow::setExtendedData(ExtendedData
* p
)
1594 mpExtendedData
.reset(p
);
1597 ScCheckListMenuWindow::ExtendedData
* ScCheckListMenuWindow::getExtendedData()
1599 return mpExtendedData
.get();
1602 void ScCheckListMenuWindow::setOKAction(Action
* p
)
1604 mpOKAction
.reset(p
);
1607 void ScCheckListMenuWindow::setPopupEndAction(Action
* p
)
1609 mpPopupEndAction
.reset(p
);
1612 void ScCheckListMenuWindow::handlePopupEnd()
1614 clearSelectedMenuItem();
1615 if (mpPopupEndAction
)
1616 mpPopupEndAction
->execute();
1619 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */