diff options
author | Kohei Yoshida <kohei.yoshida@suse.com> | 2011-09-12 21:12:57 -0400 |
---|---|---|
committer | Kohei Yoshida <kohei.yoshida@suse.com> | 2011-09-12 21:14:01 -0400 |
commit | 7a60be6e00ce3ad15f9976f607f26e52e7d06fa7 (patch) | |
tree | aaeec748b45bfa01353f88792a4686e9d917694f /sc | |
parent | 0bc368babc36542cd157803fb9fefb4260f0a9e2 (diff) |
Move ScCheckListMenuWindow and ScMenuFloatingWindow into own files.
Diffstat (limited to 'sc')
-rw-r--r-- | sc/AllLangResTarget_sc.mk | 2 | ||||
-rw-r--r-- | sc/Library_sc.mk | 1 | ||||
-rw-r--r-- | sc/source/ui/Accessibility/AccessibleFilterMenu.cxx | 2 | ||||
-rw-r--r-- | sc/source/ui/Accessibility/AccessibleFilterMenuItem.cxx | 2 | ||||
-rw-r--r-- | sc/source/ui/Accessibility/AccessibleFilterTopWindow.cxx | 2 | ||||
-rw-r--r-- | sc/source/ui/cctrl/checklistmenu.cxx | 1197 | ||||
-rw-r--r-- | sc/source/ui/cctrl/checklistmenu.src (renamed from sc/source/ui/cctrl/dpcontrol.src) | 2 | ||||
-rw-r--r-- | sc/source/ui/cctrl/dpcontrol.cxx | 1170 | ||||
-rw-r--r-- | sc/source/ui/inc/checklistmenu.hrc (renamed from sc/source/ui/inc/dpcontrol.hrc) | 4 | ||||
-rw-r--r-- | sc/source/ui/inc/checklistmenu.hxx | 309 | ||||
-rw-r--r-- | sc/source/ui/inc/dpcontrol.hxx | 277 | ||||
-rw-r--r-- | sc/source/ui/view/gridwin.cxx | 1 | ||||
-rw-r--r-- | sc/source/ui/view/gridwin2.cxx | 3 |
13 files changed, 1518 insertions, 1454 deletions
diff --git a/sc/AllLangResTarget_sc.mk b/sc/AllLangResTarget_sc.mk index e789ac3ada05..ced78741f38e 100644 --- a/sc/AllLangResTarget_sc.mk +++ b/sc/AllLangResTarget_sc.mk @@ -70,7 +70,7 @@ $(eval $(call gb_SrsTarget_add_files,sc/res,\ sc/source/ui/src/sortdlg.src \ sc/source/ui/src/attrdlg.src \ sc/source/ui/src/filter.src \ - sc/source/ui/cctrl/dpcontrol.src \ + sc/source/ui/cctrl/checklistmenu.src \ sc/source/ui/navipi/navipi.src \ sc/source/ui/docshell/tpstat.src \ sc/source/ui/pagedlg/pagedlg.src \ diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk index 27b142fb079e..2d8620895f16 100644 --- a/sc/Library_sc.mk +++ b/sc/Library_sc.mk @@ -308,6 +308,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\ sc/source/ui/attrdlg/condfrmt \ sc/source/ui/attrdlg/scabstdlg \ sc/source/ui/cctrl/cbuttonw \ + sc/source/ui/cctrl/checklistmenu \ sc/source/ui/cctrl/dpcontrol \ sc/source/ui/cctrl/popmenu \ sc/source/ui/cctrl/tbinsert \ diff --git a/sc/source/ui/Accessibility/AccessibleFilterMenu.cxx b/sc/source/ui/Accessibility/AccessibleFilterMenu.cxx index ce7e7d4de919..aeaab23bf107 100644 --- a/sc/source/ui/Accessibility/AccessibleFilterMenu.cxx +++ b/sc/source/ui/Accessibility/AccessibleFilterMenu.cxx @@ -41,7 +41,7 @@ #include "editeng/editdata.hxx" #include "editeng/outliner.hxx" #include "vcl/unohelp.hxx" -#include "dpcontrol.hxx" +#include "checklistmenu.hxx" #include <com/sun/star/accessibility/XAccessible.hpp> #include <com/sun/star/accessibility/XAccessibleStateSet.hpp> diff --git a/sc/source/ui/Accessibility/AccessibleFilterMenuItem.cxx b/sc/source/ui/Accessibility/AccessibleFilterMenuItem.cxx index bff9ad5bd88e..097d35cc3b83 100644 --- a/sc/source/ui/Accessibility/AccessibleFilterMenuItem.cxx +++ b/sc/source/ui/Accessibility/AccessibleFilterMenuItem.cxx @@ -31,7 +31,7 @@ #include "precompiled_sc.hxx" #include "AccessibleGlobal.hxx" #include "AccessibleFilterMenuItem.hxx" -#include "dpcontrol.hxx" +#include "checklistmenu.hxx" #include <com/sun/star/accessibility/XAccessible.hpp> #include <com/sun/star/accessibility/XAccessibleStateSet.hpp> diff --git a/sc/source/ui/Accessibility/AccessibleFilterTopWindow.cxx b/sc/source/ui/Accessibility/AccessibleFilterTopWindow.cxx index 74110c16d3df..e556a498e03c 100644 --- a/sc/source/ui/Accessibility/AccessibleFilterTopWindow.cxx +++ b/sc/source/ui/Accessibility/AccessibleFilterTopWindow.cxx @@ -31,7 +31,7 @@ #include "precompiled_sc.hxx" #include "AccessibleFilterTopWindow.hxx" #include "AccessibleFilterMenu.hxx" -#include "dpcontrol.hxx" +#include "checklistmenu.hxx" #include <com/sun/star/accessibility/AccessibleRole.hpp> diff --git a/sc/source/ui/cctrl/checklistmenu.cxx b/sc/source/ui/cctrl/checklistmenu.cxx new file mode 100644 index 000000000000..76b75c01d5ae --- /dev/null +++ b/sc/source/ui/cctrl/checklistmenu.cxx @@ -0,0 +1,1197 @@ +/* + * Version: MPL 1.1 / GPLv3+ / LGPLv3+ + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License or as specified alternatively below. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * Major Contributor(s): + * Copyright (C) 2011 Kohei Yoshida <kohei.yoshida@suse.com> + * + * All Rights Reserved. + * + * For minor contributions see the git repository. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 3 or later (the "GPLv3+"), or + * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"), + * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable + * instead of those above. + */ + +#include "checklistmenu.hxx" +#include "checklistmenu.hrc" +#include "strload.hxx" + +#include <vcl/decoview.hxx> +#include <tools/wintypes.hxx> + +#include "AccessibleFilterMenu.hxx" +#include "AccessibleFilterTopWindow.hxx" + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::accessibility::XAccessible; +using ::com::sun::star::accessibility::XAccessibleContext; +using ::rtl::OUString; +using ::rtl::OUStringHash; +using ::std::vector; +using ::boost::unordered_map; +using ::std::auto_ptr; + +ScMenuFloatingWindow::MenuItemData::MenuItemData() : + mbEnabled(true), + mpAction(static_cast<ScCheckListMenuWindow::Action*>(NULL)), + mpSubMenuWin(static_cast<ScMenuFloatingWindow*>(NULL)) +{ +} + +// ---------------------------------------------------------------------------- + +ScMenuFloatingWindow::SubMenuItemData::SubMenuItemData(ScMenuFloatingWindow* pParent) : + mpSubMenu(NULL), + mnMenuPos(MENU_NOT_SELECTED), + mpParent(pParent) +{ + maTimer.SetTimeoutHdl( LINK(this, ScMenuFloatingWindow::SubMenuItemData, TimeoutHdl) ); + maTimer.SetTimeout(mpParent->GetSettings().GetMouseSettings().GetMenuDelay()); +} + +void ScMenuFloatingWindow::SubMenuItemData::reset() +{ + mpSubMenu = NULL; + mnMenuPos = MENU_NOT_SELECTED; + maTimer.Stop(); +} + +IMPL_LINK( ScMenuFloatingWindow::SubMenuItemData, TimeoutHdl, void*, EMPTYARG ) +{ + mpParent->handleMenuTimeout(this); + return 0; +} + +// ---------------------------------------------------------------------------- + +size_t ScMenuFloatingWindow::MENU_NOT_SELECTED = 999; + +ScMenuFloatingWindow::ScMenuFloatingWindow(Window* pParent, ScDocument* pDoc, sal_uInt16 nMenuStackLevel) : + PopupMenuFloatingWindow(pParent), + maOpenTimer(this), + maCloseTimer(this), + maName(RTL_CONSTASCII_USTRINGPARAM("ScMenuFloatingWindow")), + mnSelectedMenu(MENU_NOT_SELECTED), + mnClickedMenu(MENU_NOT_SELECTED), + mpDoc(pDoc), + mpParentMenu(dynamic_cast<ScMenuFloatingWindow*>(pParent)), + mpActiveSubMenu(NULL) +{ + SetMenuStackLevel(nMenuStackLevel); + + // TODO: How do we get the right font to use here ? + const sal_uInt16 nPopupFontHeight = 12; + const StyleSettings& rStyle = GetSettings().GetStyleSettings(); + maLabelFont = rStyle.GetLabelFont(); + maLabelFont.SetHeight(nPopupFontHeight); + SetFont(maLabelFont); + + SetText( OUString(RTL_CONSTASCII_USTRINGPARAM("ScMenuFloatingWindow")) ); + SetPopupModeEndHdl( LINK(this, ScMenuFloatingWindow, PopupEndHdl) ); +} + +ScMenuFloatingWindow::~ScMenuFloatingWindow() +{ + EndPopupMode(); +} + +void ScMenuFloatingWindow::MouseMove(const MouseEvent& rMEvt) +{ + const Point& rPos = rMEvt.GetPosPixel(); + size_t nSelectedMenu = getEnclosingMenuItem(rPos); + setSelectedMenuItem(nSelectedMenu, true, false); + + Window::MouseMove(rMEvt); +} + +void ScMenuFloatingWindow::MouseButtonDown(const MouseEvent& rMEvt) +{ + const Point& rPos = rMEvt.GetPosPixel(); + mnClickedMenu = getEnclosingMenuItem(rPos); + Window::MouseButtonDown(rMEvt); +} + +void ScMenuFloatingWindow::MouseButtonUp(const MouseEvent& rMEvt) +{ + executeMenuItem(mnClickedMenu); + mnClickedMenu = MENU_NOT_SELECTED; + Window::MouseButtonUp(rMEvt); +} + +void ScMenuFloatingWindow::KeyInput(const KeyEvent& rKEvt) +{ + const KeyCode& rKeyCode = rKEvt.GetKeyCode(); + bool bHandled = true; + size_t nSelectedMenu = mnSelectedMenu; + size_t nLastMenuPos = maMenuItems.size() - 1; + switch (rKeyCode.GetCode()) + { + case KEY_UP: + if (nSelectedMenu == MENU_NOT_SELECTED || nSelectedMenu == 0) + nSelectedMenu = nLastMenuPos; + else + --nSelectedMenu; + setSelectedMenuItem(nSelectedMenu, false, false); + break; + case KEY_DOWN: + if (nSelectedMenu == MENU_NOT_SELECTED || nSelectedMenu == nLastMenuPos) + nSelectedMenu = 0; + else + ++nSelectedMenu; + setSelectedMenuItem(nSelectedMenu, false, false); + break; + case KEY_LEFT: + if (mpParentMenu) + mpParentMenu->endSubMenu(this); + break; + case KEY_RIGHT: + { + if (mnSelectedMenu >= maMenuItems.size() || mnSelectedMenu == MENU_NOT_SELECTED) + break; + + const MenuItemData& rMenu = maMenuItems[mnSelectedMenu]; + if (!rMenu.mbEnabled || !rMenu.mpSubMenuWin) + break; + + maOpenTimer.mnMenuPos = mnSelectedMenu; + maOpenTimer.mpSubMenu = rMenu.mpSubMenuWin.get(); + launchSubMenu(true); + } + break; + case KEY_RETURN: + if (nSelectedMenu != MENU_NOT_SELECTED) + executeMenuItem(nSelectedMenu); + break; + default: + bHandled = false; + } + + if (!bHandled) + Window::KeyInput(rKEvt); +} + +void ScMenuFloatingWindow::Paint(const Rectangle& /*rRect*/) +{ + const StyleSettings& rStyle = GetSettings().GetStyleSettings(); + Color aBackColor = rStyle.GetMenuColor(); + Color aBorderColor = rStyle.GetShadowColor(); + + Rectangle aCtrlRect(Point(0, 0), GetOutputSizePixel()); + + // Window background + bool bNativeDrawn = true; + if (IsNativeControlSupported(CTRL_MENU_POPUP, PART_ENTIRE_CONTROL)) + { + SetClipRegion(); + bNativeDrawn = DrawNativeControl( + CTRL_MENU_POPUP, PART_ENTIRE_CONTROL, aCtrlRect, CTRL_STATE_ENABLED, + ImplControlValue(), OUString()); + } + else + bNativeDrawn = false; + + if (!bNativeDrawn) + { + SetFillColor(aBackColor); + SetLineColor(aBorderColor); + DrawRect(aCtrlRect); + } + + // Menu items + SetTextColor(rStyle.GetMenuTextColor()); + drawAllMenuItems(); +} + +Reference<XAccessible> ScMenuFloatingWindow::CreateAccessible() +{ + if (!mxAccessible.is()) + { + Reference<XAccessible> xAccParent = mpParentMenu ? + mpParentMenu->GetAccessible() : GetAccessibleParentWindow()->GetAccessible(); + + mxAccessible.set(new ScAccessibleFilterMenu(xAccParent, this, maName, 999, getDoc())); + ScAccessibleFilterMenu* p = static_cast<ScAccessibleFilterMenu*>( + mxAccessible.get()); + + vector<MenuItemData>::const_iterator itr, itrBeg = maMenuItems.begin(), itrEnd = maMenuItems.end(); + for (itr = itrBeg; itr != itrEnd; ++itr) + { + size_t nPos = ::std::distance(itrBeg, itr); + p->appendMenuItem(itr->maText, itr->mbEnabled, nPos); + } + } + + return mxAccessible; +} + +void ScMenuFloatingWindow::addMenuItem(const OUString& rText, bool bEnabled, Action* pAction) +{ + MenuItemData aItem; + aItem.maText = rText; + aItem.mbEnabled = bEnabled; + aItem.mpAction.reset(pAction); + maMenuItems.push_back(aItem); +} + +ScMenuFloatingWindow* ScMenuFloatingWindow::addSubMenuItem(const OUString& rText, bool bEnabled) +{ + MenuItemData aItem; + aItem.maText = rText; + aItem.mbEnabled = bEnabled; + aItem.mpSubMenuWin.reset(new ScMenuFloatingWindow(this, mpDoc, GetMenuStackLevel()+1)); + aItem.mpSubMenuWin->setName(rText); + maMenuItems.push_back(aItem); + return aItem.mpSubMenuWin.get(); +} + +void ScMenuFloatingWindow::drawMenuItem(size_t nPos) +{ + if (nPos >= maMenuItems.size()) + return; + + Point aPos; + Size aSize; + getMenuItemPosSize(nPos, aPos, aSize); + + DecorationView aDecoView(this); + long nXOffset = 5; + long nYOffset = (aSize.Height() - maLabelFont.GetHeight())/2; + DrawCtrlText(Point(aPos.X()+nXOffset, aPos.Y() + nYOffset), maMenuItems[nPos].maText, 0, STRING_LEN, + maMenuItems[nPos].mbEnabled ? TEXT_DRAW_MNEMONIC : TEXT_DRAW_DISABLE); + + if (maMenuItems[nPos].mpSubMenuWin) + { + long nFontHeight = maLabelFont.GetHeight(); + Point aMarkerPos = aPos; + aMarkerPos.Y() += aSize.Height()/2 - nFontHeight/4 + 1; + aMarkerPos.X() += aSize.Width() - nFontHeight + nFontHeight/4; + Size aMarkerSize(nFontHeight/2, nFontHeight/2); + aDecoView.DrawSymbol(Rectangle(aMarkerPos, aMarkerSize), + SYMBOL_SPIN_RIGHT, GetTextColor(), 0); + } +} + +void ScMenuFloatingWindow::drawAllMenuItems() +{ + size_t n = maMenuItems.size(); + for (size_t i = 0; i < n; ++i) + highlightMenuItem(i, i == mnSelectedMenu); +} + +const Font& ScMenuFloatingWindow::getLabelFont() const +{ + return maLabelFont; +} + +void ScMenuFloatingWindow::executeMenuItem(size_t nPos) +{ + if (nPos >= maMenuItems.size()) + return; + + if (!maMenuItems[nPos].mpAction) + // no action is defined. + return; + + maMenuItems[nPos].mpAction->execute(); + terminateAllPopupMenus(); +} + +void ScMenuFloatingWindow::setSelectedMenuItem(size_t nPos, bool bSubMenuTimer, bool bEnsureSubMenu) +{ + if (mnSelectedMenu == nPos) + // nothing to do. + return; + + if (bEnsureSubMenu) + { + // Dismiss any child popup menu windows. + if (mnSelectedMenu < maMenuItems.size() && + maMenuItems[mnSelectedMenu].mpSubMenuWin && + maMenuItems[mnSelectedMenu].mpSubMenuWin->IsVisible()) + { + maMenuItems[mnSelectedMenu].mpSubMenuWin->ensureSubMenuNotVisible(); + } + + // The popup is not visible, yet a menu item is selected. The request + // most likely comes from the accessible object. Make sure this + // window, as well as all its parent windows are visible. + if (!IsVisible() && mpParentMenu) + mpParentMenu->ensureSubMenuVisible(this); + } + + selectMenuItem(mnSelectedMenu, false, bSubMenuTimer); + selectMenuItem(nPos, true, bSubMenuTimer); + mnSelectedMenu = nPos; + + fireMenuHighlightedEvent(); +} + +size_t ScMenuFloatingWindow::getSelectedMenuItem() const +{ + return mnSelectedMenu; +} + +void ScMenuFloatingWindow::handleMenuTimeout(SubMenuItemData* pTimer) +{ + if (pTimer == &maOpenTimer) + { + // Close any open submenu immediately. + if (maCloseTimer.mpSubMenu) + { + maCloseTimer.mpSubMenu->EndPopupMode(); + maCloseTimer.mpSubMenu = NULL; + maCloseTimer.maTimer.Stop(); + } + + launchSubMenu(false); + } + else if (pTimer == &maCloseTimer) + { + // end submenu. + if (maCloseTimer.mpSubMenu) + { + maOpenTimer.mpSubMenu = NULL; + + maCloseTimer.mpSubMenu->EndPopupMode(); + maCloseTimer.mpSubMenu = NULL; + + highlightMenuItem(maOpenTimer.mnMenuPos, false); + maOpenTimer.mnMenuPos = MENU_NOT_SELECTED; + } + } +} + +void ScMenuFloatingWindow::queueLaunchSubMenu(size_t nPos, ScMenuFloatingWindow* pMenu) +{ + if (!pMenu) + return; + + // Set the submenu on launch queue. + if (maOpenTimer.mpSubMenu) + { + if (maOpenTimer.mpSubMenu == pMenu) + { + if (pMenu == maCloseTimer.mpSubMenu) + maCloseTimer.reset(); + return; + } + + // new submenu is being requested. + queueCloseSubMenu(); + } + + maOpenTimer.mpSubMenu = pMenu; + maOpenTimer.mnMenuPos = nPos; + maOpenTimer.maTimer.Start(); +} + +void ScMenuFloatingWindow::queueCloseSubMenu() +{ + if (!maOpenTimer.mpSubMenu) + // There is no submenu to close. + return; + + // Stop any submenu on queue for opening. + maOpenTimer.maTimer.Stop(); + + maCloseTimer.mpSubMenu = maOpenTimer.mpSubMenu; + maCloseTimer.mnMenuPos = maOpenTimer.mnMenuPos; + maCloseTimer.maTimer.Start(); +} + +void ScMenuFloatingWindow::launchSubMenu(bool bSetMenuPos) +{ + Point aPos; + Size aSize; + getMenuItemPosSize(maOpenTimer.mnMenuPos, aPos, aSize); + ScMenuFloatingWindow* pSubMenu = maOpenTimer.mpSubMenu; + + if (!pSubMenu) + return; + + sal_uInt32 nOldFlags = GetPopupModeFlags(); + SetPopupModeFlags(nOldFlags | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE); + pSubMenu->resizeToFitMenuItems(); // set the size before launching the popup to get it positioned correctly. + pSubMenu->StartPopupMode( + Rectangle(aPos,aSize), (FLOATWIN_POPUPMODE_RIGHT | FLOATWIN_POPUPMODE_GRABFOCUS)); + pSubMenu->AddPopupModeWindow(this); + if (bSetMenuPos) + pSubMenu->setSelectedMenuItem(0, false, false); // select menu item after the popup becomes fully visible. + SetPopupModeFlags(nOldFlags); +} + +void ScMenuFloatingWindow::endSubMenu(ScMenuFloatingWindow* pSubMenu) +{ + if (!pSubMenu) + return; + + pSubMenu->EndPopupMode(); + maOpenTimer.reset(); + + size_t nMenuPos = getSubMenuPos(pSubMenu); + if (nMenuPos != MENU_NOT_SELECTED) + { + highlightMenuItem(nMenuPos, true); + mnSelectedMenu = nMenuPos; + fireMenuHighlightedEvent(); + } +} + +void ScMenuFloatingWindow::fillMenuItemsToAccessible(ScAccessibleFilterMenu* pAccMenu) const +{ + vector<MenuItemData>::const_iterator itr, itrBeg = maMenuItems.begin(), itrEnd = maMenuItems.end(); + for (itr = itrBeg; itr != itrEnd; ++itr) + { + size_t nPos = ::std::distance(itrBeg, itr); + pAccMenu->appendMenuItem(itr->maText, itr->mbEnabled, nPos); + } +} + +ScDocument* ScMenuFloatingWindow::getDoc() +{ + return mpDoc; +} + +void ScMenuFloatingWindow::resizeToFitMenuItems() +{ + if (maMenuItems.empty()) + return; + + vector<MenuItemData>::const_iterator itr = maMenuItems.begin(), itrEnd = maMenuItems.end(); + long nTextWidth = 0; + for (; itr != itrEnd; ++itr) + nTextWidth = ::std::max(GetTextWidth(itr->maText), nTextWidth); + + size_t nLastPos = maMenuItems.size()-1; + Point aPos; + Size aSize; + getMenuItemPosSize(nLastPos, aPos, aSize); + aPos.X() += nTextWidth + 15; + aPos.Y() += aSize.Height() + 5; + SetOutputSizePixel(Size(aPos.X(), aPos.Y())); +} + +void ScMenuFloatingWindow::selectMenuItem(size_t nPos, bool bSelected, bool bSubMenuTimer) +{ + if (nPos >= maMenuItems.size() || nPos == MENU_NOT_SELECTED) + { + queueCloseSubMenu(); + return; + } + + if (!maMenuItems[nPos].mbEnabled) + { + queueCloseSubMenu(); + return; + } + + highlightMenuItem(nPos, bSelected); + + if (bSelected) + { + if (mpParentMenu) + mpParentMenu->setSubMenuFocused(this); + + if (bSubMenuTimer) + { + if (maMenuItems[nPos].mpSubMenuWin) + { + ScMenuFloatingWindow* pSubMenu = maMenuItems[nPos].mpSubMenuWin.get(); + queueLaunchSubMenu(nPos, pSubMenu); + } + else + queueCloseSubMenu(); + } + } +} + +void ScMenuFloatingWindow::clearSelectedMenuItem() +{ + selectMenuItem(mnSelectedMenu, false, false); + mnSelectedMenu = MENU_NOT_SELECTED; +} + +ScMenuFloatingWindow* ScMenuFloatingWindow::getSubMenuWindow(size_t nPos) const +{ + if (maMenuItems.size() <= nPos) + return NULL; + + return maMenuItems[nPos].mpSubMenuWin.get(); +} + +bool ScMenuFloatingWindow::isMenuItemSelected(size_t nPos) const +{ + return nPos == mnSelectedMenu; +} + +void ScMenuFloatingWindow::setName(const OUString& rName) +{ + maName = rName; +} + +const OUString& ScMenuFloatingWindow::getName() const +{ + return maName; +} + +void ScMenuFloatingWindow::highlightMenuItem(size_t nPos, bool bSelected) +{ + if (nPos == MENU_NOT_SELECTED) + return; + + const StyleSettings& rStyle = GetSettings().GetStyleSettings(); + Color aBackColor = rStyle.GetMenuColor(); + SetFillColor(aBackColor); + SetLineColor(aBackColor); + + Point aPos; + Size aSize; + getMenuItemPosSize(nPos, aPos, aSize); + Rectangle aRegion(aPos,aSize); + + if (IsNativeControlSupported(CTRL_MENU_POPUP, PART_ENTIRE_CONTROL)) + { + Push(PUSH_CLIPREGION); + IntersectClipRegion(Rectangle(aPos, aSize)); + Rectangle aCtrlRect(Point(0,0), GetOutputSizePixel()); + DrawNativeControl( + CTRL_MENU_POPUP, PART_ENTIRE_CONTROL, aCtrlRect, CTRL_STATE_ENABLED, + ImplControlValue(), OUString()); + + Pop(); + } + + bool bNativeDrawn = true; + if (IsNativeControlSupported(CTRL_MENU_POPUP, PART_MENU_ITEM)) + { + ControlState nState = bSelected ? CTRL_STATE_SELECTED : 0; + if (maMenuItems[nPos].mbEnabled) + nState |= CTRL_STATE_ENABLED; + bNativeDrawn = DrawNativeControl( + CTRL_MENU_POPUP, PART_MENU_ITEM, aRegion, nState, ImplControlValue(), OUString()); + } + else + bNativeDrawn = false; + + if (!bNativeDrawn) + { + if (bSelected) + { + aBackColor = rStyle.GetMenuHighlightColor(); + SetFillColor(aBackColor); + SetLineColor(aBackColor); + } + DrawRect(Rectangle(aPos,aSize)); + } + + Color aTextColor = bSelected ? rStyle.GetMenuHighlightTextColor() : rStyle.GetMenuTextColor(); + SetTextColor(aTextColor); + drawMenuItem(nPos); +} + +void ScMenuFloatingWindow::getMenuItemPosSize(size_t nPos, Point& rPos, Size& rSize) const +{ + const sal_uInt16 nLeftMargin = 5; + const sal_uInt16 nTopMargin = 5; + const sal_uInt16 nMenuItemHeight = static_cast< sal_uInt16 >( maLabelFont.GetHeight()*1.8 ); + + Size aWndSize = GetSizePixel(); + + Point aPos1(nLeftMargin, nTopMargin); + Size aSize1(aWndSize.Width() - nLeftMargin*2, nMenuItemHeight); + + rPos = aPos1; + rPos.Y() += aSize1.Height()*nPos; + rSize = aSize1; +} + +ScMenuFloatingWindow* ScMenuFloatingWindow::getParentMenuWindow() const +{ + return mpParentMenu; +} + +size_t ScMenuFloatingWindow::getEnclosingMenuItem(const Point& rPos) const +{ + size_t n = maMenuItems.size(); + for (size_t i = 0; i < n; ++i) + { + Point aPos; + Size aSize; + getMenuItemPosSize(i, aPos, aSize); + Rectangle aRect(aPos, aSize); + if (aRect.IsInside(rPos)) + return i; + } + return MENU_NOT_SELECTED; +} + +size_t ScMenuFloatingWindow::getSubMenuPos(ScMenuFloatingWindow* pSubMenu) +{ + size_t n = maMenuItems.size(); + for (size_t i = 0; i < n; ++i) + { + if (maMenuItems[i].mpSubMenuWin.get() == pSubMenu) + return i; + } + return MENU_NOT_SELECTED; +} + +void ScMenuFloatingWindow::fireMenuHighlightedEvent() +{ + if (mnSelectedMenu == MENU_NOT_SELECTED) + return; + + if (!mxAccessible.is()) + return; + + Reference<XAccessibleContext> xAccCxt = mxAccessible->getAccessibleContext(); + if (!xAccCxt.is()) + return; + + Reference<XAccessible> xAccMenu = xAccCxt->getAccessibleChild(mnSelectedMenu); + if (!xAccMenu.is()) + return; + + VclAccessibleEvent aEvent(VCLEVENT_MENU_HIGHLIGHT, xAccMenu); + FireVclEvent(&aEvent); +} + +void ScMenuFloatingWindow::setSubMenuFocused(ScMenuFloatingWindow* pSubMenu) +{ + maCloseTimer.reset(); + size_t nMenuPos = getSubMenuPos(pSubMenu); + if (mnSelectedMenu != nMenuPos) + { + highlightMenuItem(nMenuPos, true); + mnSelectedMenu = nMenuPos; + } +} + +void ScMenuFloatingWindow::ensureSubMenuVisible(ScMenuFloatingWindow* pSubMenu) +{ + if (mpParentMenu) + mpParentMenu->ensureSubMenuVisible(this); + + if (pSubMenu->IsVisible()) + return; + + // Find the menu position of the submenu. + size_t nMenuPos = getSubMenuPos(pSubMenu); + if (nMenuPos != MENU_NOT_SELECTED) + { + setSelectedMenuItem(nMenuPos, false, false); + + Point aPos; + Size aSize; + getMenuItemPosSize(nMenuPos, aPos, aSize); + + sal_uInt32 nOldFlags = GetPopupModeFlags(); + SetPopupModeFlags(nOldFlags | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE); + pSubMenu->resizeToFitMenuItems(); // set the size before launching the popup to get it positioned correctly. + pSubMenu->StartPopupMode( + Rectangle(aPos,aSize), (FLOATWIN_POPUPMODE_RIGHT | FLOATWIN_POPUPMODE_GRABFOCUS)); + pSubMenu->AddPopupModeWindow(this); + SetPopupModeFlags(nOldFlags); + } +} + +void ScMenuFloatingWindow::ensureSubMenuNotVisible() +{ + if (mnSelectedMenu <= maMenuItems.size() && + maMenuItems[mnSelectedMenu].mpSubMenuWin && + maMenuItems[mnSelectedMenu].mpSubMenuWin->IsVisible()) + { + maMenuItems[mnSelectedMenu].mpSubMenuWin->ensureSubMenuNotVisible(); + } + + EndPopupMode(); +} + +void ScMenuFloatingWindow::terminateAllPopupMenus() +{ + EndPopupMode(); + if (mpParentMenu) + mpParentMenu->terminateAllPopupMenus(); +} + +IMPL_LINK( ScMenuFloatingWindow, PopupEndHdl, void*, EMPTYARG ) +{ + clearSelectedMenuItem(); + return 0; +} + +// ============================================================================ + +ScCheckListMenuWindow::Member::Member() : + mbVisible(true) +{ +} + +// ---------------------------------------------------------------------------- + +ScCheckListMenuWindow::CancelButton::CancelButton(ScCheckListMenuWindow* pParent) : + ::CancelButton(pParent), mpParent(pParent) {} + +void ScCheckListMenuWindow::CancelButton::Click() +{ + mpParent->EndPopupMode(); + ::CancelButton::Click(); +} + +// ---------------------------------------------------------------------------- + +ScCheckListMenuWindow::ScCheckListMenuWindow(Window* pParent, ScDocument* pDoc) : + ScMenuFloatingWindow(pParent, pDoc), + maChecks(this, 0), + maChkToggleAll(this, 0), + maBtnSelectSingle (this, 0), + maBtnUnselectSingle(this, 0), + maBtnOk(this), + maBtnCancel(this), + mnCurTabStop(0), + mpExtendedData(NULL), + mpOKAction(NULL), + maWndSize(240, 330), + mePrevToggleAllState(STATE_DONTKNOW) +{ + maTabStopCtrls.reserve(7); + maTabStopCtrls.push_back(this); + maTabStopCtrls.push_back(&maChecks); + maTabStopCtrls.push_back(&maChkToggleAll); + maTabStopCtrls.push_back(&maBtnSelectSingle); + maTabStopCtrls.push_back(&maBtnUnselectSingle); + maTabStopCtrls.push_back(&maBtnOk); + maTabStopCtrls.push_back(&maBtnCancel); + + const StyleSettings& rStyle = GetSettings().GetStyleSettings(); + + Point aPos; + Size aSize; + getSectionPosSize(aPos, aSize, WHOLE); + SetOutputSizePixel(aSize); + + getSectionPosSize(aPos, aSize, BTN_OK); + maBtnOk.SetPosSizePixel(aPos, aSize); + maBtnOk.SetFont(getLabelFont()); + maBtnOk.SetClickHdl( LINK(this, ScCheckListMenuWindow, ButtonHdl) ); + maBtnOk.Show(); + + getSectionPosSize(aPos, aSize, BTN_CANCEL); + maBtnCancel.SetPosSizePixel(aPos, aSize); + maBtnCancel.SetFont(getLabelFont()); + maBtnCancel.Show(); + + getSectionPosSize(aPos, aSize, LISTBOX_AREA_INNER); + maChecks.SetPosSizePixel(aPos, aSize); + maChecks.SetFont(getLabelFont()); + maChecks.SetCheckButtonHdl( LINK(this, ScCheckListMenuWindow, CheckHdl) ); + maChecks.Show(); + + getSectionPosSize(aPos, aSize, CHECK_TOGGLE_ALL); + maChkToggleAll.SetPosSizePixel(aPos, aSize); + maChkToggleAll.SetFont(getLabelFont()); + maChkToggleAll.SetText(ScRscStrLoader(RID_POPUP_FILTER, STR_BTN_TOGGLE_ALL).GetString()); + maChkToggleAll.SetTextColor(rStyle.GetMenuTextColor()); + maChkToggleAll.SetControlBackground(rStyle.GetMenuColor()); + maChkToggleAll.SetClickHdl( LINK(this, ScCheckListMenuWindow, TriStateHdl) ); + maChkToggleAll.Show(); + + getSectionPosSize(aPos, aSize, BTN_SINGLE_SELECT); + maBtnSelectSingle.SetPosSizePixel(aPos, aSize); + maBtnSelectSingle.SetQuickHelpText(ScRscStrLoader(RID_POPUP_FILTER, STR_BTN_SELECT_CURRENT).GetString()); + maBtnSelectSingle.SetModeImage(Image(ScResId(RID_IMG_SELECT_CURRENT))); + maBtnSelectSingle.SetClickHdl( LINK(this, ScCheckListMenuWindow, ButtonHdl) ); + maBtnSelectSingle.Show(); + + getSectionPosSize(aPos, aSize, BTN_SINGLE_UNSELECT); + maBtnUnselectSingle.SetPosSizePixel(aPos, aSize); + maBtnUnselectSingle.SetQuickHelpText(ScRscStrLoader(RID_POPUP_FILTER, STR_BTN_UNSELECT_CURRENT).GetString()); + maBtnUnselectSingle.SetModeImage(Image(ScResId(RID_IMG_UNSELECT_CURRENT))); + maBtnUnselectSingle.SetClickHdl( LINK(this, ScCheckListMenuWindow, ButtonHdl) ); + maBtnUnselectSingle.Show(); +} + +ScCheckListMenuWindow::~ScCheckListMenuWindow() +{ +} + +void ScCheckListMenuWindow::getSectionPosSize(Point& rPos, Size& rSize, SectionType eType) const +{ + // constant parameters. + const sal_uInt16 nListBoxMargin = 5; // horizontal distance from the side of the dialog to the listbox border. + const sal_uInt16 nListBoxInnerPadding = 5; + const sal_uInt16 nTopMargin = 5; + const sal_uInt16 nMenuHeight = 60; + const sal_uInt16 nSingleItemBtnAreaHeight = 32; // height of the middle area below the list box where the single-action buttons are. + const sal_uInt16 nBottomBtnAreaHeight = 50; // height of the bottom area where the OK and Cancel buttons are. + const sal_uInt16 nBtnWidth = 90; + const sal_uInt16 nLabelHeight = static_cast< sal_uInt16 >( getLabelFont().GetHeight() ); + const sal_uInt16 nBtnHeight = nLabelHeight*2; + const sal_uInt16 nBottomMargin = 10; + const sal_uInt16 nMenuListMargin = 20; + + // parameters calculated from constants. + const sal_uInt16 nListBoxWidth = static_cast< sal_uInt16 >( maWndSize.Width() - nListBoxMargin*2 ); + const sal_uInt16 nListBoxHeight = static_cast< sal_uInt16 >( maWndSize.Height() - nTopMargin - nMenuHeight - + nMenuListMargin - nSingleItemBtnAreaHeight - nBottomBtnAreaHeight ); + + const sal_uInt16 nSingleBtnAreaY = nTopMargin + nMenuHeight + nListBoxHeight + nMenuListMargin - 1; + + switch (eType) + { + case WHOLE: + { + rPos = Point(0, 0); + rSize = maWndSize; + } + break; + case LISTBOX_AREA_OUTER: + { + rPos = Point(nListBoxMargin, nTopMargin + nMenuHeight + nMenuListMargin); + rSize = Size(nListBoxWidth, nListBoxHeight); + } + break; + case LISTBOX_AREA_INNER: + { + rPos = Point(nListBoxMargin, nTopMargin + nMenuHeight + nMenuListMargin); + rPos.X() += nListBoxInnerPadding; + rPos.Y() += nListBoxInnerPadding; + + rSize = Size(nListBoxWidth, nListBoxHeight); + rSize.Width() -= nListBoxInnerPadding*2; + rSize.Height() -= nListBoxInnerPadding*2; + } + break; + case SINGLE_BTN_AREA: + { + rPos = Point(nListBoxMargin, nSingleBtnAreaY); + rSize = Size(nListBoxWidth, nSingleItemBtnAreaHeight); + } + break; + case CHECK_TOGGLE_ALL: + { + long h = nLabelHeight*3/2; // check box height is heuristically 150% of the text height. + rPos = Point(nListBoxMargin, nSingleBtnAreaY); + rPos.X() += 5; + rPos.Y() += (nSingleItemBtnAreaHeight - h)/2; + rSize = Size(70, h); + } + break; + case BTN_SINGLE_SELECT: + { + long h = 26; + rPos = Point(nListBoxMargin, nSingleBtnAreaY); + rPos.X() += 150; + rPos.Y() += (nSingleItemBtnAreaHeight - h)/2; + rSize = Size(h, h); + } + break; + case BTN_SINGLE_UNSELECT: + { + long h = 26; + rPos = Point(nListBoxMargin, nSingleBtnAreaY); + rPos.X() += 150 + h + 10; + rPos.Y() += (nSingleItemBtnAreaHeight - h)/2; + rSize = Size(h, h); + } + break; + case BTN_OK: + { + long x = (maWndSize.Width() - nBtnWidth*2)/3; + long y = maWndSize.Height() - nBottomMargin - nBtnHeight; + rPos = Point(x, y); + rSize = Size(nBtnWidth, nBtnHeight); + } + break; + case BTN_CANCEL: + { + long x = (maWndSize.Width() - nBtnWidth*2)/3*2 + nBtnWidth; + long y = maWndSize.Height() - nBottomMargin - nBtnHeight; + rPos = Point(x, y); + rSize = Size(nBtnWidth, nBtnHeight); + } + break; + default: + ; + } +} + +void ScCheckListMenuWindow::setAllMemberState(bool bSet) +{ + size_t n = maMembers.size(); + for (size_t i = 0; i < n; ++i) + maChecks.CheckEntryPos(static_cast< sal_uInt16 >( i ), bSet); +} + +void ScCheckListMenuWindow::selectCurrentMemberOnly(bool bSet) +{ + setAllMemberState(!bSet); + sal_uInt16 nSelected = maChecks.GetSelectEntryPos(); + maChecks.CheckEntryPos(nSelected, bSet); +} + +void ScCheckListMenuWindow::cycleFocus(bool bReverse) +{ + maTabStopCtrls[mnCurTabStop]->SetFakeFocus(false); + maTabStopCtrls[mnCurTabStop]->LoseFocus(); + if (mnCurTabStop == 0) + clearSelectedMenuItem(); + + if (bReverse) + { + if (mnCurTabStop > 0) + --mnCurTabStop; + else + mnCurTabStop = maTabStopCtrls.size() - 1; + } + else + { + ++mnCurTabStop; + if (mnCurTabStop >= maTabStopCtrls.size()) + mnCurTabStop = 0; + } + maTabStopCtrls[mnCurTabStop]->SetFakeFocus(true); + maTabStopCtrls[mnCurTabStop]->GrabFocus(); +} + +IMPL_LINK( ScCheckListMenuWindow, ButtonHdl, Button*, pBtn ) +{ + if (pBtn == &maBtnOk) + close(true); + else if (pBtn == &maBtnSelectSingle) + { + selectCurrentMemberOnly(true); + CheckHdl(&maChecks); + } + else if (pBtn == &maBtnUnselectSingle) + { + selectCurrentMemberOnly(false); + CheckHdl(&maChecks); + } + return 0; +} + +IMPL_LINK( ScCheckListMenuWindow, TriStateHdl, TriStateBox*, EMPTYARG ) +{ + switch (mePrevToggleAllState) + { + case STATE_NOCHECK: + maChkToggleAll.SetState(STATE_CHECK); + setAllMemberState(true); + break; + case STATE_CHECK: + maChkToggleAll.SetState(STATE_NOCHECK); + setAllMemberState(false); + break; + case STATE_DONTKNOW: + default: + maChkToggleAll.SetState(STATE_CHECK); + setAllMemberState(true); + break; + } + + mePrevToggleAllState = maChkToggleAll.GetState(); + return 0; +} + +IMPL_LINK( ScCheckListMenuWindow, CheckHdl, SvTreeListBox*, pChecks ) +{ + if (pChecks != &maChecks) + return 0; + + size_t nNumChecked = maChecks.GetCheckedEntryCount(); + if (nNumChecked == maMembers.size()) + // all members visible + maChkToggleAll.SetState(STATE_CHECK); + else if (nNumChecked == 0) + // no members visible + maChkToggleAll.SetState(STATE_NOCHECK); + else + maChkToggleAll.SetState(STATE_DONTKNOW); + + mePrevToggleAllState = maChkToggleAll.GetState(); + return 0; +} + +void ScCheckListMenuWindow::MouseMove(const MouseEvent& rMEvt) +{ + ScMenuFloatingWindow::MouseMove(rMEvt); + + size_t nSelectedMenu = getSelectedMenuItem(); + if (nSelectedMenu == MENU_NOT_SELECTED) + queueCloseSubMenu(); +} + +long ScCheckListMenuWindow::Notify(NotifyEvent& rNEvt) +{ + switch (rNEvt.GetType()) + { + case EVENT_KEYUP: + { + const KeyEvent* pKeyEvent = rNEvt.GetKeyEvent(); + const KeyCode& rCode = pKeyEvent->GetKeyCode(); + bool bShift = rCode.IsShift(); + if (rCode.GetCode() == KEY_TAB) + { + cycleFocus(bShift); + return true; + } + } + break; + } + return ScMenuFloatingWindow::Notify(rNEvt); +} + +void ScCheckListMenuWindow::Paint(const Rectangle& rRect) +{ + ScMenuFloatingWindow::Paint(rRect); + + const StyleSettings& rStyle = GetSettings().GetStyleSettings(); + Color aMemberBackColor = rStyle.GetFieldColor(); + Color aBorderColor = rStyle.GetShadowColor(); + + Point aPos; + Size aSize; + getSectionPosSize(aPos, aSize, LISTBOX_AREA_OUTER); + + // Member list box background + SetFillColor(aMemberBackColor); + SetLineColor(aBorderColor); + DrawRect(Rectangle(aPos,aSize)); + + // Single-action button box + getSectionPosSize(aPos, aSize, SINGLE_BTN_AREA); + SetFillColor(rStyle.GetMenuColor()); + DrawRect(Rectangle(aPos,aSize)); +} + +Window* ScCheckListMenuWindow::GetPreferredKeyInputWindow() +{ + return maTabStopCtrls[mnCurTabStop]; +} + +Reference<XAccessible> ScCheckListMenuWindow::CreateAccessible() +{ + if (!mxAccessible.is()) + { + mxAccessible.set(new ScAccessibleFilterTopWindow( + GetAccessibleParentWindow()->GetAccessible(), this, getName(), getDoc())); + ScAccessibleFilterTopWindow* pAccTop = static_cast<ScAccessibleFilterTopWindow*>(mxAccessible.get()); + fillMenuItemsToAccessible(pAccTop); + + pAccTop->setAccessibleChild( + maChecks.CreateAccessible(), ScAccessibleFilterTopWindow::LISTBOX); + pAccTop->setAccessibleChild( + maChkToggleAll.CreateAccessible(), ScAccessibleFilterTopWindow::TOGGLE_ALL); + pAccTop->setAccessibleChild( + maBtnSelectSingle.CreateAccessible(), ScAccessibleFilterTopWindow::SINGLE_ON_BTN); + pAccTop->setAccessibleChild( + maBtnUnselectSingle.CreateAccessible(), ScAccessibleFilterTopWindow::SINGLE_OFF_BTN); + pAccTop->setAccessibleChild( + maBtnOk.CreateAccessible(), ScAccessibleFilterTopWindow::OK_BTN); + pAccTop->setAccessibleChild( + maBtnCancel.CreateAccessible(), ScAccessibleFilterTopWindow::CANCEL_BTN); + } + + return mxAccessible; +} + +void ScCheckListMenuWindow::setMemberSize(size_t n) +{ + maMembers.reserve(n); +} + +void ScCheckListMenuWindow::addMember(const OUString& rName, bool bVisible) +{ + Member aMember; + aMember.maName = rName; + aMember.mbVisible = bVisible; + maMembers.push_back(aMember); +} + +void ScCheckListMenuWindow::initMembers() +{ + size_t n = maMembers.size(); + size_t nVisMemCount = 0; + for (size_t i = 0; i < n; ++i) + { + maChecks.InsertEntry(maMembers[i].maName); + maChecks.CheckEntryPos(static_cast< sal_uInt16 >( i ), maMembers[i].mbVisible); + if (maMembers[i].mbVisible) + ++nVisMemCount; + } + if (nVisMemCount == n) + { + // all members visible + maChkToggleAll.SetState(STATE_CHECK); + mePrevToggleAllState = STATE_CHECK; + } + else if (nVisMemCount == 0) + { + // no members visible + maChkToggleAll.SetState(STATE_NOCHECK); + mePrevToggleAllState = STATE_NOCHECK; + } + else + { + maChkToggleAll.SetState(STATE_DONTKNOW); + mePrevToggleAllState = STATE_DONTKNOW; + } +} + +const Size& ScCheckListMenuWindow::getWindowSize() const +{ + return maWndSize; +} + +void ScCheckListMenuWindow::getResult(boost::unordered_map<OUString, bool, OUStringHash>& rResult) +{ + typedef boost::unordered_map<OUString, bool, OUStringHash> ResultMap; + ResultMap aResult; + size_t n = maMembers.size(); + for (size_t i = 0; i < n; ++i) + { + bool bState = maChecks.IsChecked(static_cast< sal_uInt16 >( i )); + aResult.insert(ResultMap::value_type(maMembers[i].maName, bState)); + } + rResult.swap(aResult); +} + +void ScCheckListMenuWindow::close(bool bOK) +{ + if (bOK && mpOKAction.get()) + mpOKAction->execute(); + + EndPopupMode(); +} + +void ScCheckListMenuWindow::setExtendedData(ExtendedData* p) +{ + mpExtendedData.reset(p); +} + +ScCheckListMenuWindow::ExtendedData* ScCheckListMenuWindow::getExtendedData() +{ + return mpExtendedData.get(); +} + +void ScCheckListMenuWindow::setOKAction(Action* p) +{ + mpOKAction.reset(p); +} diff --git a/sc/source/ui/cctrl/dpcontrol.src b/sc/source/ui/cctrl/checklistmenu.src index b38548369be5..9247596499b2 100644 --- a/sc/source/ui/cctrl/dpcontrol.src +++ b/sc/source/ui/cctrl/checklistmenu.src @@ -25,7 +25,7 @@ * ************************************************************************/ -#include "dpcontrol.hrc" +#include "checklistmenu.hrc" Resource RID_POPUP_FILTER { diff --git a/sc/source/ui/cctrl/dpcontrol.cxx b/sc/source/ui/cctrl/dpcontrol.cxx index 41888aef658b..d9f072f62a57 100644 --- a/sc/source/ui/cctrl/dpcontrol.cxx +++ b/sc/source/ui/cctrl/dpcontrol.cxx @@ -32,33 +32,16 @@ // INCLUDE --------------------------------------------------------------- #include "dpcontrol.hxx" -#include "dpcontrol.hrc" #include <vcl/outdev.hxx> #include <vcl/settings.hxx> -#include <tools/wintypes.hxx> -#include <vcl/decoview.hxx> -#include "strload.hxx" #include "global.hxx" #include "scitems.hxx" #include "document.hxx" #include "docpool.hxx" #include "patattr.hxx" -#include "AccessibleFilterMenu.hxx" -#include "AccessibleFilterTopWindow.hxx" - -#include <com/sun/star/accessibility/XAccessible.hpp> -#include <com/sun/star/accessibility/XAccessibleContext.hpp> - -using ::com::sun::star::uno::Reference; -using ::com::sun::star::accessibility::XAccessible; -using ::com::sun::star::accessibility::XAccessibleContext; -using ::rtl::OUString; -using ::rtl::OUStringHash; -using ::std::vector; -using ::boost::unordered_map; -using ::std::auto_ptr; +using rtl::OUString; ScDPFieldButton::ScDPFieldButton(OutputDevice* pOutDev, const StyleSettings* pStyle, const Fraction* pZoomX, const Fraction* pZoomY, ScDocument* pDoc) : mpDoc(pDoc), @@ -270,1155 +253,4 @@ void ScDPFieldButton::drawPopupButton() } } -// ============================================================================ - -ScMenuFloatingWindow::MenuItemData::MenuItemData() : - mbEnabled(true), - mpAction(static_cast<ScCheckListMenuWindow::Action*>(NULL)), - mpSubMenuWin(static_cast<ScMenuFloatingWindow*>(NULL)) -{ -} - -// ---------------------------------------------------------------------------- - -ScMenuFloatingWindow::SubMenuItemData::SubMenuItemData(ScMenuFloatingWindow* pParent) : - mpSubMenu(NULL), - mnMenuPos(MENU_NOT_SELECTED), - mpParent(pParent) -{ - maTimer.SetTimeoutHdl( LINK(this, ScMenuFloatingWindow::SubMenuItemData, TimeoutHdl) ); - maTimer.SetTimeout(mpParent->GetSettings().GetMouseSettings().GetMenuDelay()); -} - -void ScMenuFloatingWindow::SubMenuItemData::reset() -{ - mpSubMenu = NULL; - mnMenuPos = MENU_NOT_SELECTED; - maTimer.Stop(); -} - -IMPL_LINK( ScMenuFloatingWindow::SubMenuItemData, TimeoutHdl, void*, EMPTYARG ) -{ - mpParent->handleMenuTimeout(this); - return 0; -} - -// ---------------------------------------------------------------------------- - -size_t ScMenuFloatingWindow::MENU_NOT_SELECTED = 999; - -ScMenuFloatingWindow::ScMenuFloatingWindow(Window* pParent, ScDocument* pDoc, sal_uInt16 nMenuStackLevel) : - PopupMenuFloatingWindow(pParent), - maOpenTimer(this), - maCloseTimer(this), - maName(RTL_CONSTASCII_USTRINGPARAM("ScMenuFloatingWindow")), - mnSelectedMenu(MENU_NOT_SELECTED), - mnClickedMenu(MENU_NOT_SELECTED), - mpDoc(pDoc), - mpParentMenu(dynamic_cast<ScMenuFloatingWindow*>(pParent)), - mpActiveSubMenu(NULL) -{ - SetMenuStackLevel(nMenuStackLevel); - - // TODO: How do we get the right font to use here ? - const sal_uInt16 nPopupFontHeight = 12; - const StyleSettings& rStyle = GetSettings().GetStyleSettings(); - maLabelFont = rStyle.GetLabelFont(); - maLabelFont.SetHeight(nPopupFontHeight); - SetFont(maLabelFont); - - SetText( OUString(RTL_CONSTASCII_USTRINGPARAM("ScMenuFloatingWindow")) ); - SetPopupModeEndHdl( LINK(this, ScMenuFloatingWindow, PopupEndHdl) ); -} - -ScMenuFloatingWindow::~ScMenuFloatingWindow() -{ - EndPopupMode(); -} - -void ScMenuFloatingWindow::MouseMove(const MouseEvent& rMEvt) -{ - const Point& rPos = rMEvt.GetPosPixel(); - size_t nSelectedMenu = getEnclosingMenuItem(rPos); - setSelectedMenuItem(nSelectedMenu, true, false); - - Window::MouseMove(rMEvt); -} - -void ScMenuFloatingWindow::MouseButtonDown(const MouseEvent& rMEvt) -{ - const Point& rPos = rMEvt.GetPosPixel(); - mnClickedMenu = getEnclosingMenuItem(rPos); - Window::MouseButtonDown(rMEvt); -} - -void ScMenuFloatingWindow::MouseButtonUp(const MouseEvent& rMEvt) -{ - executeMenuItem(mnClickedMenu); - mnClickedMenu = MENU_NOT_SELECTED; - Window::MouseButtonUp(rMEvt); -} - -void ScMenuFloatingWindow::KeyInput(const KeyEvent& rKEvt) -{ - const KeyCode& rKeyCode = rKEvt.GetKeyCode(); - bool bHandled = true; - size_t nSelectedMenu = mnSelectedMenu; - size_t nLastMenuPos = maMenuItems.size() - 1; - switch (rKeyCode.GetCode()) - { - case KEY_UP: - if (nSelectedMenu == MENU_NOT_SELECTED || nSelectedMenu == 0) - nSelectedMenu = nLastMenuPos; - else - --nSelectedMenu; - setSelectedMenuItem(nSelectedMenu, false, false); - break; - case KEY_DOWN: - if (nSelectedMenu == MENU_NOT_SELECTED || nSelectedMenu == nLastMenuPos) - nSelectedMenu = 0; - else - ++nSelectedMenu; - setSelectedMenuItem(nSelectedMenu, false, false); - break; - case KEY_LEFT: - if (mpParentMenu) - mpParentMenu->endSubMenu(this); - break; - case KEY_RIGHT: - { - if (mnSelectedMenu >= maMenuItems.size() || mnSelectedMenu == MENU_NOT_SELECTED) - break; - - const MenuItemData& rMenu = maMenuItems[mnSelectedMenu]; - if (!rMenu.mbEnabled || !rMenu.mpSubMenuWin) - break; - - maOpenTimer.mnMenuPos = mnSelectedMenu; - maOpenTimer.mpSubMenu = rMenu.mpSubMenuWin.get(); - launchSubMenu(true); - } - break; - case KEY_RETURN: - if (nSelectedMenu != MENU_NOT_SELECTED) - executeMenuItem(nSelectedMenu); - break; - default: - bHandled = false; - } - - if (!bHandled) - Window::KeyInput(rKEvt); -} - -void ScMenuFloatingWindow::Paint(const Rectangle& /*rRect*/) -{ - const StyleSettings& rStyle = GetSettings().GetStyleSettings(); - Color aBackColor = rStyle.GetMenuColor(); - Color aBorderColor = rStyle.GetShadowColor(); - - Rectangle aCtrlRect(Point(0, 0), GetOutputSizePixel()); - - // Window background - bool bNativeDrawn = true; - if (IsNativeControlSupported(CTRL_MENU_POPUP, PART_ENTIRE_CONTROL)) - { - SetClipRegion(); - bNativeDrawn = DrawNativeControl( - CTRL_MENU_POPUP, PART_ENTIRE_CONTROL, aCtrlRect, CTRL_STATE_ENABLED, - ImplControlValue(), OUString()); - } - else - bNativeDrawn = false; - - if (!bNativeDrawn) - { - SetFillColor(aBackColor); - SetLineColor(aBorderColor); - DrawRect(aCtrlRect); - } - - // Menu items - SetTextColor(rStyle.GetMenuTextColor()); - drawAllMenuItems(); -} - -Reference<XAccessible> ScMenuFloatingWindow::CreateAccessible() -{ - if (!mxAccessible.is()) - { - Reference<XAccessible> xAccParent = mpParentMenu ? - mpParentMenu->GetAccessible() : GetAccessibleParentWindow()->GetAccessible(); - - mxAccessible.set(new ScAccessibleFilterMenu(xAccParent, this, maName, 999, getDoc())); - ScAccessibleFilterMenu* p = static_cast<ScAccessibleFilterMenu*>( - mxAccessible.get()); - - vector<MenuItemData>::const_iterator itr, itrBeg = maMenuItems.begin(), itrEnd = maMenuItems.end(); - for (itr = itrBeg; itr != itrEnd; ++itr) - { - size_t nPos = ::std::distance(itrBeg, itr); - p->appendMenuItem(itr->maText, itr->mbEnabled, nPos); - } - } - - return mxAccessible; -} - -void ScMenuFloatingWindow::addMenuItem(const OUString& rText, bool bEnabled, Action* pAction) -{ - MenuItemData aItem; - aItem.maText = rText; - aItem.mbEnabled = bEnabled; - aItem.mpAction.reset(pAction); - maMenuItems.push_back(aItem); -} - -ScMenuFloatingWindow* ScMenuFloatingWindow::addSubMenuItem(const OUString& rText, bool bEnabled) -{ - MenuItemData aItem; - aItem.maText = rText; - aItem.mbEnabled = bEnabled; - aItem.mpSubMenuWin.reset(new ScMenuFloatingWindow(this, mpDoc, GetMenuStackLevel()+1)); - aItem.mpSubMenuWin->setName(rText); - maMenuItems.push_back(aItem); - return aItem.mpSubMenuWin.get(); -} - -void ScMenuFloatingWindow::drawMenuItem(size_t nPos) -{ - if (nPos >= maMenuItems.size()) - return; - - Point aPos; - Size aSize; - getMenuItemPosSize(nPos, aPos, aSize); - - DecorationView aDecoView(this); - long nXOffset = 5; - long nYOffset = (aSize.Height() - maLabelFont.GetHeight())/2; - DrawCtrlText(Point(aPos.X()+nXOffset, aPos.Y() + nYOffset), maMenuItems[nPos].maText, 0, STRING_LEN, - maMenuItems[nPos].mbEnabled ? TEXT_DRAW_MNEMONIC : TEXT_DRAW_DISABLE); - - if (maMenuItems[nPos].mpSubMenuWin) - { - long nFontHeight = maLabelFont.GetHeight(); - Point aMarkerPos = aPos; - aMarkerPos.Y() += aSize.Height()/2 - nFontHeight/4 + 1; - aMarkerPos.X() += aSize.Width() - nFontHeight + nFontHeight/4; - Size aMarkerSize(nFontHeight/2, nFontHeight/2); - aDecoView.DrawSymbol(Rectangle(aMarkerPos, aMarkerSize), - SYMBOL_SPIN_RIGHT, GetTextColor(), 0); - } -} - -void ScMenuFloatingWindow::drawAllMenuItems() -{ - size_t n = maMenuItems.size(); - for (size_t i = 0; i < n; ++i) - highlightMenuItem(i, i == mnSelectedMenu); -} - -const Font& ScMenuFloatingWindow::getLabelFont() const -{ - return maLabelFont; -} - -void ScMenuFloatingWindow::executeMenuItem(size_t nPos) -{ - if (nPos >= maMenuItems.size()) - return; - - if (!maMenuItems[nPos].mpAction) - // no action is defined. - return; - - maMenuItems[nPos].mpAction->execute(); - terminateAllPopupMenus(); -} - -void ScMenuFloatingWindow::setSelectedMenuItem(size_t nPos, bool bSubMenuTimer, bool bEnsureSubMenu) -{ - if (mnSelectedMenu == nPos) - // nothing to do. - return; - - if (bEnsureSubMenu) - { - // Dismiss any child popup menu windows. - if (mnSelectedMenu < maMenuItems.size() && - maMenuItems[mnSelectedMenu].mpSubMenuWin && - maMenuItems[mnSelectedMenu].mpSubMenuWin->IsVisible()) - { - maMenuItems[mnSelectedMenu].mpSubMenuWin->ensureSubMenuNotVisible(); - } - - // The popup is not visible, yet a menu item is selected. The request - // most likely comes from the accessible object. Make sure this - // window, as well as all its parent windows are visible. - if (!IsVisible() && mpParentMenu) - mpParentMenu->ensureSubMenuVisible(this); - } - - selectMenuItem(mnSelectedMenu, false, bSubMenuTimer); - selectMenuItem(nPos, true, bSubMenuTimer); - mnSelectedMenu = nPos; - - fireMenuHighlightedEvent(); -} - -size_t ScMenuFloatingWindow::getSelectedMenuItem() const -{ - return mnSelectedMenu; -} - -void ScMenuFloatingWindow::handleMenuTimeout(SubMenuItemData* pTimer) -{ - if (pTimer == &maOpenTimer) - { - // Close any open submenu immediately. - if (maCloseTimer.mpSubMenu) - { - maCloseTimer.mpSubMenu->EndPopupMode(); - maCloseTimer.mpSubMenu = NULL; - maCloseTimer.maTimer.Stop(); - } - - launchSubMenu(false); - } - else if (pTimer == &maCloseTimer) - { - // end submenu. - if (maCloseTimer.mpSubMenu) - { - maOpenTimer.mpSubMenu = NULL; - - maCloseTimer.mpSubMenu->EndPopupMode(); - maCloseTimer.mpSubMenu = NULL; - - highlightMenuItem(maOpenTimer.mnMenuPos, false); - maOpenTimer.mnMenuPos = MENU_NOT_SELECTED; - } - } -} - -void ScMenuFloatingWindow::queueLaunchSubMenu(size_t nPos, ScMenuFloatingWindow* pMenu) -{ - if (!pMenu) - return; - - // Set the submenu on launch queue. - if (maOpenTimer.mpSubMenu) - { - if (maOpenTimer.mpSubMenu == pMenu) - { - if (pMenu == maCloseTimer.mpSubMenu) - maCloseTimer.reset(); - return; - } - - // new submenu is being requested. - queueCloseSubMenu(); - } - - maOpenTimer.mpSubMenu = pMenu; - maOpenTimer.mnMenuPos = nPos; - maOpenTimer.maTimer.Start(); -} - -void ScMenuFloatingWindow::queueCloseSubMenu() -{ - if (!maOpenTimer.mpSubMenu) - // There is no submenu to close. - return; - - // Stop any submenu on queue for opening. - maOpenTimer.maTimer.Stop(); - - maCloseTimer.mpSubMenu = maOpenTimer.mpSubMenu; - maCloseTimer.mnMenuPos = maOpenTimer.mnMenuPos; - maCloseTimer.maTimer.Start(); -} - -void ScMenuFloatingWindow::launchSubMenu(bool bSetMenuPos) -{ - Point aPos; - Size aSize; - getMenuItemPosSize(maOpenTimer.mnMenuPos, aPos, aSize); - ScMenuFloatingWindow* pSubMenu = maOpenTimer.mpSubMenu; - - if (!pSubMenu) - return; - - sal_uInt32 nOldFlags = GetPopupModeFlags(); - SetPopupModeFlags(nOldFlags | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE); - pSubMenu->resizeToFitMenuItems(); // set the size before launching the popup to get it positioned correctly. - pSubMenu->StartPopupMode( - Rectangle(aPos,aSize), (FLOATWIN_POPUPMODE_RIGHT | FLOATWIN_POPUPMODE_GRABFOCUS)); - pSubMenu->AddPopupModeWindow(this); - if (bSetMenuPos) - pSubMenu->setSelectedMenuItem(0, false, false); // select menu item after the popup becomes fully visible. - SetPopupModeFlags(nOldFlags); -} - -void ScMenuFloatingWindow::endSubMenu(ScMenuFloatingWindow* pSubMenu) -{ - if (!pSubMenu) - return; - - pSubMenu->EndPopupMode(); - maOpenTimer.reset(); - - size_t nMenuPos = getSubMenuPos(pSubMenu); - if (nMenuPos != MENU_NOT_SELECTED) - { - highlightMenuItem(nMenuPos, true); - mnSelectedMenu = nMenuPos; - fireMenuHighlightedEvent(); - } -} - -void ScMenuFloatingWindow::fillMenuItemsToAccessible(ScAccessibleFilterMenu* pAccMenu) const -{ - vector<MenuItemData>::const_iterator itr, itrBeg = maMenuItems.begin(), itrEnd = maMenuItems.end(); - for (itr = itrBeg; itr != itrEnd; ++itr) - { - size_t nPos = ::std::distance(itrBeg, itr); - pAccMenu->appendMenuItem(itr->maText, itr->mbEnabled, nPos); - } -} - -ScDocument* ScMenuFloatingWindow::getDoc() -{ - return mpDoc; -} - -void ScMenuFloatingWindow::resizeToFitMenuItems() -{ - if (maMenuItems.empty()) - return; - - vector<MenuItemData>::const_iterator itr = maMenuItems.begin(), itrEnd = maMenuItems.end(); - long nTextWidth = 0; - for (; itr != itrEnd; ++itr) - nTextWidth = ::std::max(GetTextWidth(itr->maText), nTextWidth); - - size_t nLastPos = maMenuItems.size()-1; - Point aPos; - Size aSize; - getMenuItemPosSize(nLastPos, aPos, aSize); - aPos.X() += nTextWidth + 15; - aPos.Y() += aSize.Height() + 5; - SetOutputSizePixel(Size(aPos.X(), aPos.Y())); -} - -void ScMenuFloatingWindow::selectMenuItem(size_t nPos, bool bSelected, bool bSubMenuTimer) -{ - if (nPos >= maMenuItems.size() || nPos == MENU_NOT_SELECTED) - { - queueCloseSubMenu(); - return; - } - - if (!maMenuItems[nPos].mbEnabled) - { - queueCloseSubMenu(); - return; - } - - highlightMenuItem(nPos, bSelected); - - if (bSelected) - { - if (mpParentMenu) - mpParentMenu->setSubMenuFocused(this); - - if (bSubMenuTimer) - { - if (maMenuItems[nPos].mpSubMenuWin) - { - ScMenuFloatingWindow* pSubMenu = maMenuItems[nPos].mpSubMenuWin.get(); - queueLaunchSubMenu(nPos, pSubMenu); - } - else - queueCloseSubMenu(); - } - } -} - -void ScMenuFloatingWindow::clearSelectedMenuItem() -{ - selectMenuItem(mnSelectedMenu, false, false); - mnSelectedMenu = MENU_NOT_SELECTED; -} - -ScMenuFloatingWindow* ScMenuFloatingWindow::getSubMenuWindow(size_t nPos) const -{ - if (maMenuItems.size() <= nPos) - return NULL; - - return maMenuItems[nPos].mpSubMenuWin.get(); -} - -bool ScMenuFloatingWindow::isMenuItemSelected(size_t nPos) const -{ - return nPos == mnSelectedMenu; -} - -void ScMenuFloatingWindow::setName(const OUString& rName) -{ - maName = rName; -} - -const OUString& ScMenuFloatingWindow::getName() const -{ - return maName; -} - -void ScMenuFloatingWindow::highlightMenuItem(size_t nPos, bool bSelected) -{ - if (nPos == MENU_NOT_SELECTED) - return; - - const StyleSettings& rStyle = GetSettings().GetStyleSettings(); - Color aBackColor = rStyle.GetMenuColor(); - SetFillColor(aBackColor); - SetLineColor(aBackColor); - - Point aPos; - Size aSize; - getMenuItemPosSize(nPos, aPos, aSize); - Rectangle aRegion(aPos,aSize); - - if (IsNativeControlSupported(CTRL_MENU_POPUP, PART_ENTIRE_CONTROL)) - { - Push(PUSH_CLIPREGION); - IntersectClipRegion(Rectangle(aPos, aSize)); - Rectangle aCtrlRect(Point(0,0), GetOutputSizePixel()); - DrawNativeControl( - CTRL_MENU_POPUP, PART_ENTIRE_CONTROL, aCtrlRect, CTRL_STATE_ENABLED, - ImplControlValue(), OUString()); - - Pop(); - } - - bool bNativeDrawn = true; - if (IsNativeControlSupported(CTRL_MENU_POPUP, PART_MENU_ITEM)) - { - ControlState nState = bSelected ? CTRL_STATE_SELECTED : 0; - if (maMenuItems[nPos].mbEnabled) - nState |= CTRL_STATE_ENABLED; - bNativeDrawn = DrawNativeControl( - CTRL_MENU_POPUP, PART_MENU_ITEM, aRegion, nState, ImplControlValue(), OUString()); - } - else - bNativeDrawn = false; - - if (!bNativeDrawn) - { - if (bSelected) - { - aBackColor = rStyle.GetMenuHighlightColor(); - SetFillColor(aBackColor); - SetLineColor(aBackColor); - } - DrawRect(Rectangle(aPos,aSize)); - } - - Color aTextColor = bSelected ? rStyle.GetMenuHighlightTextColor() : rStyle.GetMenuTextColor(); - SetTextColor(aTextColor); - drawMenuItem(nPos); -} - -void ScMenuFloatingWindow::getMenuItemPosSize(size_t nPos, Point& rPos, Size& rSize) const -{ - const sal_uInt16 nLeftMargin = 5; - const sal_uInt16 nTopMargin = 5; - const sal_uInt16 nMenuItemHeight = static_cast< sal_uInt16 >( maLabelFont.GetHeight()*1.8 ); - - Size aWndSize = GetSizePixel(); - - Point aPos1(nLeftMargin, nTopMargin); - Size aSize1(aWndSize.Width() - nLeftMargin*2, nMenuItemHeight); - - rPos = aPos1; - rPos.Y() += aSize1.Height()*nPos; - rSize = aSize1; -} - -ScMenuFloatingWindow* ScMenuFloatingWindow::getParentMenuWindow() const -{ - return mpParentMenu; -} - -size_t ScMenuFloatingWindow::getEnclosingMenuItem(const Point& rPos) const -{ - size_t n = maMenuItems.size(); - for (size_t i = 0; i < n; ++i) - { - Point aPos; - Size aSize; - getMenuItemPosSize(i, aPos, aSize); - Rectangle aRect(aPos, aSize); - if (aRect.IsInside(rPos)) - return i; - } - return MENU_NOT_SELECTED; -} - -size_t ScMenuFloatingWindow::getSubMenuPos(ScMenuFloatingWindow* pSubMenu) -{ - size_t n = maMenuItems.size(); - for (size_t i = 0; i < n; ++i) - { - if (maMenuItems[i].mpSubMenuWin.get() == pSubMenu) - return i; - } - return MENU_NOT_SELECTED; -} - -void ScMenuFloatingWindow::fireMenuHighlightedEvent() -{ - if (mnSelectedMenu == MENU_NOT_SELECTED) - return; - - if (!mxAccessible.is()) - return; - - Reference<XAccessibleContext> xAccCxt = mxAccessible->getAccessibleContext(); - if (!xAccCxt.is()) - return; - - Reference<XAccessible> xAccMenu = xAccCxt->getAccessibleChild(mnSelectedMenu); - if (!xAccMenu.is()) - return; - - VclAccessibleEvent aEvent(VCLEVENT_MENU_HIGHLIGHT, xAccMenu); - FireVclEvent(&aEvent); -} - -void ScMenuFloatingWindow::setSubMenuFocused(ScMenuFloatingWindow* pSubMenu) -{ - maCloseTimer.reset(); - size_t nMenuPos = getSubMenuPos(pSubMenu); - if (mnSelectedMenu != nMenuPos) - { - highlightMenuItem(nMenuPos, true); - mnSelectedMenu = nMenuPos; - } -} - -void ScMenuFloatingWindow::ensureSubMenuVisible(ScMenuFloatingWindow* pSubMenu) -{ - if (mpParentMenu) - mpParentMenu->ensureSubMenuVisible(this); - - if (pSubMenu->IsVisible()) - return; - - // Find the menu position of the submenu. - size_t nMenuPos = getSubMenuPos(pSubMenu); - if (nMenuPos != MENU_NOT_SELECTED) - { - setSelectedMenuItem(nMenuPos, false, false); - - Point aPos; - Size aSize; - getMenuItemPosSize(nMenuPos, aPos, aSize); - - sal_uInt32 nOldFlags = GetPopupModeFlags(); - SetPopupModeFlags(nOldFlags | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE); - pSubMenu->resizeToFitMenuItems(); // set the size before launching the popup to get it positioned correctly. - pSubMenu->StartPopupMode( - Rectangle(aPos,aSize), (FLOATWIN_POPUPMODE_RIGHT | FLOATWIN_POPUPMODE_GRABFOCUS)); - pSubMenu->AddPopupModeWindow(this); - SetPopupModeFlags(nOldFlags); - } -} - -void ScMenuFloatingWindow::ensureSubMenuNotVisible() -{ - if (mnSelectedMenu <= maMenuItems.size() && - maMenuItems[mnSelectedMenu].mpSubMenuWin && - maMenuItems[mnSelectedMenu].mpSubMenuWin->IsVisible()) - { - maMenuItems[mnSelectedMenu].mpSubMenuWin->ensureSubMenuNotVisible(); - } - - EndPopupMode(); -} - -void ScMenuFloatingWindow::terminateAllPopupMenus() -{ - EndPopupMode(); - if (mpParentMenu) - mpParentMenu->terminateAllPopupMenus(); -} - -IMPL_LINK( ScMenuFloatingWindow, PopupEndHdl, void*, EMPTYARG ) -{ - clearSelectedMenuItem(); - return 0; -} - -// ============================================================================ - -ScCheckListMenuWindow::Member::Member() : - mbVisible(true) -{ -} - -// ---------------------------------------------------------------------------- - -ScCheckListMenuWindow::CancelButton::CancelButton(ScCheckListMenuWindow* pParent) : - ::CancelButton(pParent), mpParent(pParent) {} - -void ScCheckListMenuWindow::CancelButton::Click() -{ - mpParent->EndPopupMode(); - ::CancelButton::Click(); -} - -// ---------------------------------------------------------------------------- - -ScCheckListMenuWindow::ScCheckListMenuWindow(Window* pParent, ScDocument* pDoc) : - ScMenuFloatingWindow(pParent, pDoc), - maChecks(this, 0), - maChkToggleAll(this, 0), - maBtnSelectSingle (this, 0), - maBtnUnselectSingle(this, 0), - maBtnOk(this), - maBtnCancel(this), - mnCurTabStop(0), - mpExtendedData(NULL), - mpOKAction(NULL), - maWndSize(240, 330), - mePrevToggleAllState(STATE_DONTKNOW) -{ - maTabStopCtrls.reserve(7); - maTabStopCtrls.push_back(this); - maTabStopCtrls.push_back(&maChecks); - maTabStopCtrls.push_back(&maChkToggleAll); - maTabStopCtrls.push_back(&maBtnSelectSingle); - maTabStopCtrls.push_back(&maBtnUnselectSingle); - maTabStopCtrls.push_back(&maBtnOk); - maTabStopCtrls.push_back(&maBtnCancel); - - const StyleSettings& rStyle = GetSettings().GetStyleSettings(); - - Point aPos; - Size aSize; - getSectionPosSize(aPos, aSize, WHOLE); - SetOutputSizePixel(aSize); - - getSectionPosSize(aPos, aSize, BTN_OK); - maBtnOk.SetPosSizePixel(aPos, aSize); - maBtnOk.SetFont(getLabelFont()); - maBtnOk.SetClickHdl( LINK(this, ScCheckListMenuWindow, ButtonHdl) ); - maBtnOk.Show(); - - getSectionPosSize(aPos, aSize, BTN_CANCEL); - maBtnCancel.SetPosSizePixel(aPos, aSize); - maBtnCancel.SetFont(getLabelFont()); - maBtnCancel.Show(); - - getSectionPosSize(aPos, aSize, LISTBOX_AREA_INNER); - maChecks.SetPosSizePixel(aPos, aSize); - maChecks.SetFont(getLabelFont()); - maChecks.SetCheckButtonHdl( LINK(this, ScCheckListMenuWindow, CheckHdl) ); - maChecks.Show(); - - getSectionPosSize(aPos, aSize, CHECK_TOGGLE_ALL); - maChkToggleAll.SetPosSizePixel(aPos, aSize); - maChkToggleAll.SetFont(getLabelFont()); - maChkToggleAll.SetText(ScRscStrLoader(RID_POPUP_FILTER, STR_BTN_TOGGLE_ALL).GetString()); - maChkToggleAll.SetTextColor(rStyle.GetMenuTextColor()); - maChkToggleAll.SetControlBackground(rStyle.GetMenuColor()); - maChkToggleAll.SetClickHdl( LINK(this, ScCheckListMenuWindow, TriStateHdl) ); - maChkToggleAll.Show(); - - getSectionPosSize(aPos, aSize, BTN_SINGLE_SELECT); - maBtnSelectSingle.SetPosSizePixel(aPos, aSize); - maBtnSelectSingle.SetQuickHelpText(ScRscStrLoader(RID_POPUP_FILTER, STR_BTN_SELECT_CURRENT).GetString()); - maBtnSelectSingle.SetModeImage(Image(ScResId(RID_IMG_SELECT_CURRENT))); - maBtnSelectSingle.SetClickHdl( LINK(this, ScCheckListMenuWindow, ButtonHdl) ); - maBtnSelectSingle.Show(); - - getSectionPosSize(aPos, aSize, BTN_SINGLE_UNSELECT); - maBtnUnselectSingle.SetPosSizePixel(aPos, aSize); - maBtnUnselectSingle.SetQuickHelpText(ScRscStrLoader(RID_POPUP_FILTER, STR_BTN_UNSELECT_CURRENT).GetString()); - maBtnUnselectSingle.SetModeImage(Image(ScResId(RID_IMG_UNSELECT_CURRENT))); - maBtnUnselectSingle.SetClickHdl( LINK(this, ScCheckListMenuWindow, ButtonHdl) ); - maBtnUnselectSingle.Show(); -} - -ScCheckListMenuWindow::~ScCheckListMenuWindow() -{ -} - -void ScCheckListMenuWindow::getSectionPosSize(Point& rPos, Size& rSize, SectionType eType) const -{ - // constant parameters. - const sal_uInt16 nListBoxMargin = 5; // horizontal distance from the side of the dialog to the listbox border. - const sal_uInt16 nListBoxInnerPadding = 5; - const sal_uInt16 nTopMargin = 5; - const sal_uInt16 nMenuHeight = 60; - const sal_uInt16 nSingleItemBtnAreaHeight = 32; // height of the middle area below the list box where the single-action buttons are. - const sal_uInt16 nBottomBtnAreaHeight = 50; // height of the bottom area where the OK and Cancel buttons are. - const sal_uInt16 nBtnWidth = 90; - const sal_uInt16 nLabelHeight = static_cast< sal_uInt16 >( getLabelFont().GetHeight() ); - const sal_uInt16 nBtnHeight = nLabelHeight*2; - const sal_uInt16 nBottomMargin = 10; - const sal_uInt16 nMenuListMargin = 20; - - // parameters calculated from constants. - const sal_uInt16 nListBoxWidth = static_cast< sal_uInt16 >( maWndSize.Width() - nListBoxMargin*2 ); - const sal_uInt16 nListBoxHeight = static_cast< sal_uInt16 >( maWndSize.Height() - nTopMargin - nMenuHeight - - nMenuListMargin - nSingleItemBtnAreaHeight - nBottomBtnAreaHeight ); - - const sal_uInt16 nSingleBtnAreaY = nTopMargin + nMenuHeight + nListBoxHeight + nMenuListMargin - 1; - - switch (eType) - { - case WHOLE: - { - rPos = Point(0, 0); - rSize = maWndSize; - } - break; - case LISTBOX_AREA_OUTER: - { - rPos = Point(nListBoxMargin, nTopMargin + nMenuHeight + nMenuListMargin); - rSize = Size(nListBoxWidth, nListBoxHeight); - } - break; - case LISTBOX_AREA_INNER: - { - rPos = Point(nListBoxMargin, nTopMargin + nMenuHeight + nMenuListMargin); - rPos.X() += nListBoxInnerPadding; - rPos.Y() += nListBoxInnerPadding; - - rSize = Size(nListBoxWidth, nListBoxHeight); - rSize.Width() -= nListBoxInnerPadding*2; - rSize.Height() -= nListBoxInnerPadding*2; - } - break; - case SINGLE_BTN_AREA: - { - rPos = Point(nListBoxMargin, nSingleBtnAreaY); - rSize = Size(nListBoxWidth, nSingleItemBtnAreaHeight); - } - break; - case CHECK_TOGGLE_ALL: - { - long h = nLabelHeight*3/2; // check box height is heuristically 150% of the text height. - rPos = Point(nListBoxMargin, nSingleBtnAreaY); - rPos.X() += 5; - rPos.Y() += (nSingleItemBtnAreaHeight - h)/2; - rSize = Size(70, h); - } - break; - case BTN_SINGLE_SELECT: - { - long h = 26; - rPos = Point(nListBoxMargin, nSingleBtnAreaY); - rPos.X() += 150; - rPos.Y() += (nSingleItemBtnAreaHeight - h)/2; - rSize = Size(h, h); - } - break; - case BTN_SINGLE_UNSELECT: - { - long h = 26; - rPos = Point(nListBoxMargin, nSingleBtnAreaY); - rPos.X() += 150 + h + 10; - rPos.Y() += (nSingleItemBtnAreaHeight - h)/2; - rSize = Size(h, h); - } - break; - case BTN_OK: - { - long x = (maWndSize.Width() - nBtnWidth*2)/3; - long y = maWndSize.Height() - nBottomMargin - nBtnHeight; - rPos = Point(x, y); - rSize = Size(nBtnWidth, nBtnHeight); - } - break; - case BTN_CANCEL: - { - long x = (maWndSize.Width() - nBtnWidth*2)/3*2 + nBtnWidth; - long y = maWndSize.Height() - nBottomMargin - nBtnHeight; - rPos = Point(x, y); - rSize = Size(nBtnWidth, nBtnHeight); - } - break; - default: - ; - } -} - -void ScCheckListMenuWindow::setAllMemberState(bool bSet) -{ - size_t n = maMembers.size(); - for (size_t i = 0; i < n; ++i) - maChecks.CheckEntryPos(static_cast< sal_uInt16 >( i ), bSet); -} - -void ScCheckListMenuWindow::selectCurrentMemberOnly(bool bSet) -{ - setAllMemberState(!bSet); - sal_uInt16 nSelected = maChecks.GetSelectEntryPos(); - maChecks.CheckEntryPos(nSelected, bSet); -} - -void ScCheckListMenuWindow::cycleFocus(bool bReverse) -{ - maTabStopCtrls[mnCurTabStop]->SetFakeFocus(false); - maTabStopCtrls[mnCurTabStop]->LoseFocus(); - if (mnCurTabStop == 0) - clearSelectedMenuItem(); - - if (bReverse) - { - if (mnCurTabStop > 0) - --mnCurTabStop; - else - mnCurTabStop = maTabStopCtrls.size() - 1; - } - else - { - ++mnCurTabStop; - if (mnCurTabStop >= maTabStopCtrls.size()) - mnCurTabStop = 0; - } - maTabStopCtrls[mnCurTabStop]->SetFakeFocus(true); - maTabStopCtrls[mnCurTabStop]->GrabFocus(); -} - -IMPL_LINK( ScCheckListMenuWindow, ButtonHdl, Button*, pBtn ) -{ - if (pBtn == &maBtnOk) - close(true); - else if (pBtn == &maBtnSelectSingle) - { - selectCurrentMemberOnly(true); - CheckHdl(&maChecks); - } - else if (pBtn == &maBtnUnselectSingle) - { - selectCurrentMemberOnly(false); - CheckHdl(&maChecks); - } - return 0; -} - -IMPL_LINK( ScCheckListMenuWindow, TriStateHdl, TriStateBox*, EMPTYARG ) -{ - switch (mePrevToggleAllState) - { - case STATE_NOCHECK: - maChkToggleAll.SetState(STATE_CHECK); - setAllMemberState(true); - break; - case STATE_CHECK: - maChkToggleAll.SetState(STATE_NOCHECK); - setAllMemberState(false); - break; - case STATE_DONTKNOW: - default: - maChkToggleAll.SetState(STATE_CHECK); - setAllMemberState(true); - break; - } - - mePrevToggleAllState = maChkToggleAll.GetState(); - return 0; -} - -IMPL_LINK( ScCheckListMenuWindow, CheckHdl, SvTreeListBox*, pChecks ) -{ - if (pChecks != &maChecks) - return 0; - - size_t nNumChecked = maChecks.GetCheckedEntryCount(); - if (nNumChecked == maMembers.size()) - // all members visible - maChkToggleAll.SetState(STATE_CHECK); - else if (nNumChecked == 0) - // no members visible - maChkToggleAll.SetState(STATE_NOCHECK); - else - maChkToggleAll.SetState(STATE_DONTKNOW); - - mePrevToggleAllState = maChkToggleAll.GetState(); - return 0; -} - -void ScCheckListMenuWindow::MouseMove(const MouseEvent& rMEvt) -{ - ScMenuFloatingWindow::MouseMove(rMEvt); - - size_t nSelectedMenu = getSelectedMenuItem(); - if (nSelectedMenu == MENU_NOT_SELECTED) - queueCloseSubMenu(); -} - -long ScCheckListMenuWindow::Notify(NotifyEvent& rNEvt) -{ - switch (rNEvt.GetType()) - { - case EVENT_KEYUP: - { - const KeyEvent* pKeyEvent = rNEvt.GetKeyEvent(); - const KeyCode& rCode = pKeyEvent->GetKeyCode(); - bool bShift = rCode.IsShift(); - if (rCode.GetCode() == KEY_TAB) - { - cycleFocus(bShift); - return true; - } - } - break; - } - return ScMenuFloatingWindow::Notify(rNEvt); -} - -void ScCheckListMenuWindow::Paint(const Rectangle& rRect) -{ - ScMenuFloatingWindow::Paint(rRect); - - const StyleSettings& rStyle = GetSettings().GetStyleSettings(); - Color aMemberBackColor = rStyle.GetFieldColor(); - Color aBorderColor = rStyle.GetShadowColor(); - - Point aPos; - Size aSize; - getSectionPosSize(aPos, aSize, LISTBOX_AREA_OUTER); - - // Member list box background - SetFillColor(aMemberBackColor); - SetLineColor(aBorderColor); - DrawRect(Rectangle(aPos,aSize)); - - // Single-action button box - getSectionPosSize(aPos, aSize, SINGLE_BTN_AREA); - SetFillColor(rStyle.GetMenuColor()); - DrawRect(Rectangle(aPos,aSize)); -} - -Window* ScCheckListMenuWindow::GetPreferredKeyInputWindow() -{ - return maTabStopCtrls[mnCurTabStop]; -} - -Reference<XAccessible> ScCheckListMenuWindow::CreateAccessible() -{ - if (!mxAccessible.is()) - { - mxAccessible.set(new ScAccessibleFilterTopWindow( - GetAccessibleParentWindow()->GetAccessible(), this, getName(), getDoc())); - ScAccessibleFilterTopWindow* pAccTop = static_cast<ScAccessibleFilterTopWindow*>(mxAccessible.get()); - fillMenuItemsToAccessible(pAccTop); - - pAccTop->setAccessibleChild( - maChecks.CreateAccessible(), ScAccessibleFilterTopWindow::LISTBOX); - pAccTop->setAccessibleChild( - maChkToggleAll.CreateAccessible(), ScAccessibleFilterTopWindow::TOGGLE_ALL); - pAccTop->setAccessibleChild( - maBtnSelectSingle.CreateAccessible(), ScAccessibleFilterTopWindow::SINGLE_ON_BTN); - pAccTop->setAccessibleChild( - maBtnUnselectSingle.CreateAccessible(), ScAccessibleFilterTopWindow::SINGLE_OFF_BTN); - pAccTop->setAccessibleChild( - maBtnOk.CreateAccessible(), ScAccessibleFilterTopWindow::OK_BTN); - pAccTop->setAccessibleChild( - maBtnCancel.CreateAccessible(), ScAccessibleFilterTopWindow::CANCEL_BTN); - } - - return mxAccessible; -} - -void ScCheckListMenuWindow::setMemberSize(size_t n) -{ - maMembers.reserve(n); -} - -void ScCheckListMenuWindow::addMember(const OUString& rName, bool bVisible) -{ - Member aMember; - aMember.maName = rName; - aMember.mbVisible = bVisible; - maMembers.push_back(aMember); -} - -void ScCheckListMenuWindow::initMembers() -{ - size_t n = maMembers.size(); - size_t nVisMemCount = 0; - for (size_t i = 0; i < n; ++i) - { - maChecks.InsertEntry(maMembers[i].maName); - maChecks.CheckEntryPos(static_cast< sal_uInt16 >( i ), maMembers[i].mbVisible); - if (maMembers[i].mbVisible) - ++nVisMemCount; - } - if (nVisMemCount == n) - { - // all members visible - maChkToggleAll.SetState(STATE_CHECK); - mePrevToggleAllState = STATE_CHECK; - } - else if (nVisMemCount == 0) - { - // no members visible - maChkToggleAll.SetState(STATE_NOCHECK); - mePrevToggleAllState = STATE_NOCHECK; - } - else - { - maChkToggleAll.SetState(STATE_DONTKNOW); - mePrevToggleAllState = STATE_DONTKNOW; - } -} - -const Size& ScCheckListMenuWindow::getWindowSize() const -{ - return maWndSize; -} - -void ScCheckListMenuWindow::getResult(boost::unordered_map<OUString, bool, OUStringHash>& rResult) -{ - typedef boost::unordered_map<OUString, bool, OUStringHash> ResultMap; - ResultMap aResult; - size_t n = maMembers.size(); - for (size_t i = 0; i < n; ++i) - { - bool bState = maChecks.IsChecked(static_cast< sal_uInt16 >( i )); - aResult.insert(ResultMap::value_type(maMembers[i].maName, bState)); - } - rResult.swap(aResult); -} - -void ScCheckListMenuWindow::close(bool bOK) -{ - if (bOK && mpOKAction.get()) - mpOKAction->execute(); - - EndPopupMode(); -} - -void ScCheckListMenuWindow::setExtendedData(ExtendedData* p) -{ - mpExtendedData.reset(p); -} - -ScCheckListMenuWindow::ExtendedData* ScCheckListMenuWindow::getExtendedData() -{ - return mpExtendedData.get(); -} - -void ScCheckListMenuWindow::setOKAction(Action* p) -{ - mpOKAction.reset(p); -} - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/inc/dpcontrol.hrc b/sc/source/ui/inc/checklistmenu.hrc index 687f999970ad..bc4beea77bad 100644 --- a/sc/source/ui/inc/dpcontrol.hrc +++ b/sc/source/ui/inc/checklistmenu.hrc @@ -25,8 +25,8 @@ * ************************************************************************/ -#ifndef __DPCONTROL_HRC__ -#define __DPCONTROL_HRC__ +#ifndef __SC_CHECKLISTMENU_HRC__ +#define __SC_CHECKLISTMENU_HRC__ #include <sc.hrc> diff --git a/sc/source/ui/inc/checklistmenu.hxx b/sc/source/ui/inc/checklistmenu.hxx new file mode 100644 index 000000000000..bd2914b28b08 --- /dev/null +++ b/sc/source/ui/inc/checklistmenu.hxx @@ -0,0 +1,309 @@ +/* + * Version: MPL 1.1 / GPLv3+ / LGPLv3+ + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License or as specified alternatively below. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * Major Contributor(s): + * Copyright (C) 2011 Kohei Yoshida <kohei.yoshida@suse.com> + * + * All Rights Reserved. + * + * For minor contributions see the git repository. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 3 or later (the "GPLv3+"), or + * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"), + * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable + * instead of those above. + */ + +#ifndef __SC_CHECKLISTMENU_HXX__ +#define __SC_CHECKLISTMENU_HXX__ + +#include "vcl/popupmenuwindow.hxx" +#include "vcl/button.hxx" +#include "vcl/scrbar.hxx" +#include "vcl/timer.hxx" +#include "svx/checklbx.hxx" + +#include <memory> +#include <boost/unordered_map.hpp> + +namespace com { namespace sun { namespace star { + + namespace accessibility { + class XAccessible; + } + +}}} + +class ScDocument; +class ScAccessibleFilterMenu; + +class ScMenuFloatingWindow : public PopupMenuFloatingWindow +{ +public: + static size_t MENU_NOT_SELECTED; + /** + * Action to perform when an event takes place. Create a sub-class of + * this to implement the desired action. + */ + class Action + { + public: + virtual void execute() = 0; + }; + + explicit ScMenuFloatingWindow(Window* pParent, ScDocument* pDoc, sal_uInt16 nMenuStackLevel = 0); + virtual ~ScMenuFloatingWindow(); + + virtual void MouseMove(const MouseEvent& rMEvt); + virtual void MouseButtonDown(const MouseEvent& rMEvt); + virtual void MouseButtonUp(const MouseEvent& rMEvt); + virtual void KeyInput(const KeyEvent& rKEvt); + virtual void Paint(const Rectangle& rRect); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible(); + + void addMenuItem(const ::rtl::OUString& rText, bool bEnabled, Action* pAction); + ScMenuFloatingWindow* addSubMenuItem(const ::rtl::OUString& rText, bool bEnabled); + void setSelectedMenuItem(size_t nPos, bool bSubMenuTimer, bool bEnsureSubMenu); + void selectMenuItem(size_t nPos, bool bSelected, bool bSubMenuTimer); + void clearSelectedMenuItem(); + ScMenuFloatingWindow* getSubMenuWindow(size_t nPos) const; + bool isMenuItemSelected(size_t nPos) const; + size_t getSelectedMenuItem() const; + + void setName(const ::rtl::OUString& rName); + const ::rtl::OUString& getName() const; + + void executeMenuItem(size_t nPos); + void getMenuItemPosSize(size_t nPos, Point& rPos, Size& rSize) const; + ScMenuFloatingWindow* getParentMenuWindow() const; + +protected: + + void drawMenuItem(size_t nPos); + void drawAllMenuItems(); + const Font& getLabelFont() const; + + void queueLaunchSubMenu(size_t nPos, ScMenuFloatingWindow* pMenu); + void queueCloseSubMenu(); + void launchSubMenu(bool bSetMenuPos); + void endSubMenu(ScMenuFloatingWindow* pSubMenu); + + void fillMenuItemsToAccessible(ScAccessibleFilterMenu* pAccMenu) const; + + ScDocument* getDoc(); + +protected: + ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessible > mxAccessible; + +private: + struct SubMenuItemData; + void handleMenuTimeout(SubMenuItemData* pTimer); + + void resizeToFitMenuItems(); + void highlightMenuItem(size_t nPos, bool bSelected); + + size_t getEnclosingMenuItem(const Point& rPos) const; + size_t getSubMenuPos(ScMenuFloatingWindow* pSubMenu); + + /** + * Fire a menu highlight event since the accessibility framework needs + * this to track focus on menu items. + */ + void fireMenuHighlightedEvent(); + + /** + * Make sure that the specified submenu is permanently up, the submenu + * close timer is not active, and the correct menu item associated with + * the submenu is highlighted. + */ + void setSubMenuFocused(ScMenuFloatingWindow* pSubMenu); + + /** + * When a menu item of an invisible submenu is selected, we need to make + * sure that all its parent menu(s) are visible, with the right menu item + * highlighted in each of the parents. Calling this method ensures it. + */ + void ensureSubMenuVisible(ScMenuFloatingWindow* pSubMenu); + + /** + * Dismiss any visible child submenus when a menu item of a parent menu is + * selected. + */ + void ensureSubMenuNotVisible(); + + /** + * Dismiss all visible popup menus and set focus back to the application + * window. This method is called e.g. when a menu action is fired. + */ + void terminateAllPopupMenus(); + + DECL_LINK( PopupEndHdl, void* ); + +private: + + struct MenuItemData + { + ::rtl::OUString maText; + bool mbEnabled; + + ::boost::shared_ptr<Action> mpAction; + ::boost::shared_ptr<ScMenuFloatingWindow> mpSubMenuWin; + + MenuItemData(); + }; + + ::std::vector<MenuItemData> maMenuItems; + + struct SubMenuItemData + { + Timer maTimer; + ScMenuFloatingWindow* mpSubMenu; + size_t mnMenuPos; + + DECL_LINK( TimeoutHdl, void* ); + + SubMenuItemData(ScMenuFloatingWindow* pParent); + void reset(); + + private: + ScMenuFloatingWindow* mpParent; + }; + SubMenuItemData maOpenTimer; + SubMenuItemData maCloseTimer; + + Font maLabelFont; + + // Name of this menu window, taken from the menu item of the parent window + // that launches it (if this is a sub menu). If this is a top-level menu + // window, then this name can be anything. + ::rtl::OUString maName; + + size_t mnSelectedMenu; + size_t mnClickedMenu; + + ScDocument* mpDoc; + + ScMenuFloatingWindow* mpParentMenu; + ScMenuFloatingWindow* mpActiveSubMenu; +}; + +/** + * This class implements a popup window for field button, for quick access + * of hide-item list, and possibly more stuff related to field options. + */ +class ScCheckListMenuWindow : public ScMenuFloatingWindow +{ +public: + /** + * Extended data that the client code may need to store. Create a + * sub-class of this and store data there. + */ + struct ExtendedData {}; + + explicit ScCheckListMenuWindow(Window* pParent, ScDocument* pDoc); + virtual ~ScCheckListMenuWindow(); + + virtual void MouseMove(const MouseEvent& rMEvt); + virtual long Notify(NotifyEvent& rNEvt); + virtual void Paint(const Rectangle& rRect); + virtual Window* GetPreferredKeyInputWindow(); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible(); + + void setMemberSize(size_t n); + void addMember(const ::rtl::OUString& rName, bool bVisible); + void initMembers(); + + const Size& getWindowSize() const; + + void getResult(::boost::unordered_map< ::rtl::OUString, bool, ::rtl::OUStringHash>& rResult); + void close(bool bOK); + + /** + * Set auxiliary data that the client code might need. Note that this + * popup window class manages its life time; no explicit deletion of the + * instance is needed in the client code. + */ + void setExtendedData(ExtendedData* p); + + /** + * Get the store auxiliary data, or NULL if no such data is stored. + */ + ExtendedData* getExtendedData(); + + void setOKAction(Action* p); + +private: + struct Member + { + ::rtl::OUString maName; + bool mbVisible; + + Member(); + }; + + class CancelButton : public ::CancelButton + { + public: + CancelButton(ScCheckListMenuWindow* pParent); + + virtual void Click(); + + private: + ScCheckListMenuWindow* mpParent; + }; + + enum SectionType { + WHOLE, // entire window + LISTBOX_AREA_OUTER, // box enclosing the check box items. + LISTBOX_AREA_INNER, // box enclosing the check box items. + SINGLE_BTN_AREA, // box enclosing the single-action buttons. + CHECK_TOGGLE_ALL, // check box for toggling all items. + BTN_SINGLE_SELECT, + BTN_SINGLE_UNSELECT, + BTN_OK, // OK button + BTN_CANCEL, // Cancel button + }; + void getSectionPosSize(Point& rPos, Size& rSize, SectionType eType) const; + + void setAllMemberState(bool bSet); + void selectCurrentMemberOnly(bool bSet); + void cycleFocus(bool bReverse = false); + + DECL_LINK( ButtonHdl, Button* ); + DECL_LINK( TriStateHdl, TriStateBox* ); + DECL_LINK( CheckHdl, SvTreeListBox* ); + +private: + SvxCheckListBox maChecks; + + TriStateBox maChkToggleAll; + ImageButton maBtnSelectSingle; + ImageButton maBtnUnselectSingle; + + OKButton maBtnOk; + CancelButton maBtnCancel; + + ::std::vector<Window*> maTabStopCtrls; + size_t mnCurTabStop; + + ::std::vector<Member> maMembers; + ::std::auto_ptr<ExtendedData> mpExtendedData; + ::std::auto_ptr<Action> mpOKAction; + + const Size maWndSize; /// hard-coded window size. + TriState mePrevToggleAllState; +}; + +#endif diff --git a/sc/source/ui/inc/dpcontrol.hxx b/sc/source/ui/inc/dpcontrol.hxx index e225340037c6..42d0cf637bd2 100644 --- a/sc/source/ui/inc/dpcontrol.hxx +++ b/sc/source/ui/inc/dpcontrol.hxx @@ -32,23 +32,9 @@ #include "rtl/ustring.hxx" #include "tools/gen.hxx" #include "tools/fract.hxx" -#include "vcl/popupmenuwindow.hxx" -#include "vcl/button.hxx" -#include "vcl/scrbar.hxx" -#include "vcl/timer.hxx" -#include "svx/checklbx.hxx" #include <boost/shared_ptr.hpp> #include <memory> -#include <boost/unordered_map.hpp> - -namespace com { namespace sun { namespace star { - - namespace accessibility { - class XAccessible; - } - -}}} class OutputDevice; class Point; @@ -56,7 +42,6 @@ class Size; class StyleSettings; class Window; class ScDocument; -class ScAccessibleFilterMenu; /** * This class takes care of physically drawing field button controls inside @@ -99,268 +84,6 @@ private: bool mbPopupLeft; }; -// ============================================================================ - -class ScMenuFloatingWindow : public PopupMenuFloatingWindow -{ -public: - static size_t MENU_NOT_SELECTED; - /** - * Action to perform when an event takes place. Create a sub-class of - * this to implement the desired action. - */ - class Action - { - public: - virtual void execute() = 0; - }; - - explicit ScMenuFloatingWindow(Window* pParent, ScDocument* pDoc, sal_uInt16 nMenuStackLevel = 0); - virtual ~ScMenuFloatingWindow(); - - virtual void MouseMove(const MouseEvent& rMEvt); - virtual void MouseButtonDown(const MouseEvent& rMEvt); - virtual void MouseButtonUp(const MouseEvent& rMEvt); - virtual void KeyInput(const KeyEvent& rKEvt); - virtual void Paint(const Rectangle& rRect); - virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible(); - - void addMenuItem(const ::rtl::OUString& rText, bool bEnabled, Action* pAction); - ScMenuFloatingWindow* addSubMenuItem(const ::rtl::OUString& rText, bool bEnabled); - void setSelectedMenuItem(size_t nPos, bool bSubMenuTimer, bool bEnsureSubMenu); - void selectMenuItem(size_t nPos, bool bSelected, bool bSubMenuTimer); - void clearSelectedMenuItem(); - ScMenuFloatingWindow* getSubMenuWindow(size_t nPos) const; - bool isMenuItemSelected(size_t nPos) const; - size_t getSelectedMenuItem() const; - - void setName(const ::rtl::OUString& rName); - const ::rtl::OUString& getName() const; - - void executeMenuItem(size_t nPos); - void getMenuItemPosSize(size_t nPos, Point& rPos, Size& rSize) const; - ScMenuFloatingWindow* getParentMenuWindow() const; - -protected: - - void drawMenuItem(size_t nPos); - void drawAllMenuItems(); - const Font& getLabelFont() const; - - void queueLaunchSubMenu(size_t nPos, ScMenuFloatingWindow* pMenu); - void queueCloseSubMenu(); - void launchSubMenu(bool bSetMenuPos); - void endSubMenu(ScMenuFloatingWindow* pSubMenu); - - void fillMenuItemsToAccessible(ScAccessibleFilterMenu* pAccMenu) const; - - ScDocument* getDoc(); - -protected: - ::com::sun::star::uno::Reference< - ::com::sun::star::accessibility::XAccessible > mxAccessible; - -private: - struct SubMenuItemData; - void handleMenuTimeout(SubMenuItemData* pTimer); - - void resizeToFitMenuItems(); - void highlightMenuItem(size_t nPos, bool bSelected); - - size_t getEnclosingMenuItem(const Point& rPos) const; - size_t getSubMenuPos(ScMenuFloatingWindow* pSubMenu); - - /** - * Fire a menu highlight event since the accessibility framework needs - * this to track focus on menu items. - */ - void fireMenuHighlightedEvent(); - - /** - * Make sure that the specified submenu is permanently up, the submenu - * close timer is not active, and the correct menu item associated with - * the submenu is highlighted. - */ - void setSubMenuFocused(ScMenuFloatingWindow* pSubMenu); - - /** - * When a menu item of an invisible submenu is selected, we need to make - * sure that all its parent menu(s) are visible, with the right menu item - * highlighted in each of the parents. Calling this method ensures it. - */ - void ensureSubMenuVisible(ScMenuFloatingWindow* pSubMenu); - - /** - * Dismiss any visible child submenus when a menu item of a parent menu is - * selected. - */ - void ensureSubMenuNotVisible(); - - /** - * Dismiss all visible popup menus and set focus back to the application - * window. This method is called e.g. when a menu action is fired. - */ - void terminateAllPopupMenus(); - - DECL_LINK( PopupEndHdl, void* ); - -private: - - struct MenuItemData - { - ::rtl::OUString maText; - bool mbEnabled; - - ::boost::shared_ptr<Action> mpAction; - ::boost::shared_ptr<ScMenuFloatingWindow> mpSubMenuWin; - - MenuItemData(); - }; - - ::std::vector<MenuItemData> maMenuItems; - - struct SubMenuItemData - { - Timer maTimer; - ScMenuFloatingWindow* mpSubMenu; - size_t mnMenuPos; - - DECL_LINK( TimeoutHdl, void* ); - - SubMenuItemData(ScMenuFloatingWindow* pParent); - void reset(); - - private: - ScMenuFloatingWindow* mpParent; - }; - SubMenuItemData maOpenTimer; - SubMenuItemData maCloseTimer; - - Font maLabelFont; - - // Name of this menu window, taken from the menu item of the parent window - // that launches it (if this is a sub menu). If this is a top-level menu - // window, then this name can be anything. - ::rtl::OUString maName; - - size_t mnSelectedMenu; - size_t mnClickedMenu; - - ScDocument* mpDoc; - - ScMenuFloatingWindow* mpParentMenu; - ScMenuFloatingWindow* mpActiveSubMenu; -}; - -// ============================================================================ - -/** - * This class implements a popup window for field button, for quick access - * of hide-item list, and possibly more stuff related to field options. - */ -class ScCheckListMenuWindow : public ScMenuFloatingWindow -{ -public: - /** - * Extended data that the client code may need to store. Create a - * sub-class of this and store data there. - */ - struct ExtendedData {}; - - explicit ScCheckListMenuWindow(Window* pParent, ScDocument* pDoc); - virtual ~ScCheckListMenuWindow(); - - virtual void MouseMove(const MouseEvent& rMEvt); - virtual long Notify(NotifyEvent& rNEvt); - virtual void Paint(const Rectangle& rRect); - virtual Window* GetPreferredKeyInputWindow(); - virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible(); - - void setMemberSize(size_t n); - void addMember(const ::rtl::OUString& rName, bool bVisible); - void initMembers(); - - const Size& getWindowSize() const; - - void getResult(::boost::unordered_map< ::rtl::OUString, bool, ::rtl::OUStringHash>& rResult); - void close(bool bOK); - - /** - * Set auxiliary data that the client code might need. Note that this - * popup window class manages its life time; no explicit deletion of the - * instance is needed in the client code. - */ - void setExtendedData(ExtendedData* p); - - /** - * Get the store auxiliary data, or NULL if no such data is stored. - */ - ExtendedData* getExtendedData(); - - void setOKAction(Action* p); - -private: - struct Member - { - ::rtl::OUString maName; - bool mbVisible; - - Member(); - }; - - class CancelButton : public ::CancelButton - { - public: - CancelButton(ScCheckListMenuWindow* pParent); - - virtual void Click(); - - private: - ScCheckListMenuWindow* mpParent; - }; - - enum SectionType { - WHOLE, // entire window - LISTBOX_AREA_OUTER, // box enclosing the check box items. - LISTBOX_AREA_INNER, // box enclosing the check box items. - SINGLE_BTN_AREA, // box enclosing the single-action buttons. - CHECK_TOGGLE_ALL, // check box for toggling all items. - BTN_SINGLE_SELECT, - BTN_SINGLE_UNSELECT, - BTN_OK, // OK button - BTN_CANCEL, // Cancel button - }; - void getSectionPosSize(Point& rPos, Size& rSize, SectionType eType) const; - - void setAllMemberState(bool bSet); - void selectCurrentMemberOnly(bool bSet); - void cycleFocus(bool bReverse = false); - - DECL_LINK( ButtonHdl, Button* ); - DECL_LINK( TriStateHdl, TriStateBox* ); - DECL_LINK( CheckHdl, SvTreeListBox* ); - -private: - SvxCheckListBox maChecks; - - TriStateBox maChkToggleAll; - ImageButton maBtnSelectSingle; - ImageButton maBtnUnselectSingle; - - OKButton maBtnOk; - CancelButton maBtnCancel; - - ::std::vector<Window*> maTabStopCtrls; - size_t mnCurTabStop; - - ::std::vector<Member> maMembers; - ::std::auto_ptr<ExtendedData> mpExtendedData; - ::std::auto_ptr<Action> mpOKAction; - - const Size maWndSize; /// hard-coded window size. - TriState mePrevToggleAllState; -}; - #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx index 1e66a2b7f8c6..69c7a52d7c58 100644 --- a/sc/source/ui/view/gridwin.cxx +++ b/sc/source/ui/view/gridwin.cxx @@ -124,6 +124,7 @@ #include "tabprotection.hxx" #include "postit.hxx" #include "dpcontrol.hxx" +#include "checklistmenu.hxx" #include "clipparam.hxx" #include "cellsh.hxx" #include "overlayobject.hxx" diff --git a/sc/source/ui/view/gridwin2.cxx b/sc/source/ui/view/gridwin2.cxx index eb5b4e34a68e..bf983922ce45 100644 --- a/sc/source/ui/view/gridwin2.cxx +++ b/sc/source/ui/view/gridwin2.cxx @@ -52,8 +52,9 @@ #include "dpoutput.hxx" // ScDPPositionData #include "dpshttab.hxx" #include "dbdocfun.hxx" +#include "checklistmenu.hxx" #include "dpcontrol.hxx" -#include "dpcontrol.hrc" +#include "checklistmenu.hrc" #include "strload.hxx" #include "userlist.hxx" |