| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sc.hxx" |
| |
| // 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 ::std::hash_map; |
| using ::std::auto_ptr; |
| |
| ScDPFieldButton::ScDPFieldButton(OutputDevice* pOutDev, const StyleSettings* pStyle, const Fraction* pZoomX, const Fraction* pZoomY, ScDocument* pDoc) : |
| mpDoc(pDoc), |
| mpOutDev(pOutDev), |
| mpStyle(pStyle), |
| mbBaseButton(true), |
| mbPopupButton(false), |
| mbHasHiddenMember(false), |
| mbPopupPressed(false), |
| mbPopupLeft(false) |
| { |
| if (pZoomX) |
| maZoomX = *pZoomX; |
| else |
| maZoomX = Fraction(1, 1); |
| |
| if (pZoomY) |
| maZoomY = *pZoomY; |
| else |
| maZoomY = Fraction(1, 1); |
| } |
| |
| ScDPFieldButton::~ScDPFieldButton() |
| { |
| } |
| |
| void ScDPFieldButton::setText(const OUString& rText) |
| { |
| maText = rText; |
| } |
| |
| void ScDPFieldButton::setBoundingBox(const Point& rPos, const Size& rSize, bool bLayoutRTL) |
| { |
| maPos = rPos; |
| maSize = rSize; |
| if (bLayoutRTL) |
| { |
| // rPos is the logical-left position, adjust maPos to visual-left (inside the cell border) |
| maPos.X() -= maSize.Width() - 1; |
| } |
| } |
| |
| void ScDPFieldButton::setDrawBaseButton(bool b) |
| { |
| mbBaseButton = b; |
| } |
| |
| void ScDPFieldButton::setDrawPopupButton(bool b) |
| { |
| mbPopupButton = b; |
| } |
| |
| void ScDPFieldButton::setHasHiddenMember(bool b) |
| { |
| mbHasHiddenMember = b; |
| } |
| |
| void ScDPFieldButton::setPopupPressed(bool b) |
| { |
| mbPopupPressed = b; |
| } |
| |
| void ScDPFieldButton::setPopupLeft(bool b) |
| { |
| mbPopupLeft = b; |
| } |
| |
| void ScDPFieldButton::draw() |
| { |
| const long nMargin = 2; |
| bool bOldMapEnablaed = mpOutDev->IsMapModeEnabled(); |
| mpOutDev->EnableMapMode(false); |
| |
| if (mbBaseButton) |
| { |
| // Background |
| Rectangle aRect(maPos, maSize); |
| mpOutDev->SetLineColor(mpStyle->GetFaceColor()); |
| mpOutDev->SetFillColor(mpStyle->GetFaceColor()); |
| mpOutDev->DrawRect(aRect); |
| |
| // Border lines |
| mpOutDev->SetLineColor(mpStyle->GetLightColor()); |
| mpOutDev->DrawLine(Point(maPos), Point(maPos.X(), maPos.Y()+maSize.Height()-1)); |
| mpOutDev->DrawLine(Point(maPos), Point(maPos.X()+maSize.Width()-1, maPos.Y())); |
| |
| mpOutDev->SetLineColor(mpStyle->GetShadowColor()); |
| mpOutDev->DrawLine(Point(maPos.X(), maPos.Y()+maSize.Height()-1), |
| Point(maPos.X()+maSize.Width()-1, maPos.Y()+maSize.Height()-1)); |
| mpOutDev->DrawLine(Point(maPos.X()+maSize.Width()-1, maPos.Y()), |
| Point(maPos.X()+maSize.Width()-1, maPos.Y()+maSize.Height()-1)); |
| |
| // Field name. |
| // Get the font and size the same way as in scenario selection (lcl_DrawOneFrame in gridwin4.cxx) |
| Font aTextFont( mpStyle->GetAppFont() ); |
| if ( mpDoc ) |
| { |
| // use ScPatternAttr::GetFont only for font size |
| Font aAttrFont; |
| static_cast<const ScPatternAttr&>(mpDoc->GetPool()->GetDefaultItem(ATTR_PATTERN)). |
| GetFont( aAttrFont, SC_AUTOCOL_BLACK, mpOutDev, &maZoomY ); |
| aTextFont.SetSize( aAttrFont.GetSize() ); |
| } |
| mpOutDev->SetFont(aTextFont); |
| mpOutDev->SetTextColor(mpStyle->GetButtonTextColor()); |
| |
| Point aTextPos = maPos; |
| long nTHeight = mpOutDev->GetTextHeight(); |
| aTextPos.setX(maPos.getX() + nMargin); |
| aTextPos.setY(maPos.getY() + (maSize.Height()-nTHeight)/2); |
| |
| mpOutDev->Push(PUSH_CLIPREGION); |
| mpOutDev->IntersectClipRegion(aRect); |
| mpOutDev->DrawText(aTextPos, maText); |
| mpOutDev->Pop(); |
| } |
| |
| if (mbPopupButton) |
| drawPopupButton(); |
| |
| mpOutDev->EnableMapMode(bOldMapEnablaed); |
| } |
| |
| void ScDPFieldButton::getPopupBoundingBox(Point& rPos, Size& rSize) const |
| { |
| long nW = maSize.getWidth() / 2; |
| long nH = maSize.getHeight(); |
| if (nW > 18) |
| nW = 18; |
| if (nH > 18) |
| nH = 18; |
| |
| // #i114944# AutoFilter button is left-aligned in RTL. |
| // DataPilot button is always right-aligned for now, so text output isn't affected. |
| if (mbPopupLeft) |
| rPos.setX(maPos.getX()); |
| else |
| rPos.setX(maPos.getX() + maSize.getWidth() - nW); |
| rPos.setY(maPos.getY() + maSize.getHeight() - nH); |
| rSize.setWidth(nW); |
| rSize.setHeight(nH); |
| } |
| |
| void ScDPFieldButton::drawPopupButton() |
| { |
| Point aPos; |
| Size aSize; |
| getPopupBoundingBox(aPos, aSize); |
| |
| // Background & outer black border |
| mpOutDev->SetLineColor(COL_BLACK); |
| mpOutDev->SetFillColor(mpStyle->GetFaceColor()); |
| mpOutDev->DrawRect(Rectangle(aPos, aSize)); |
| |
| if (!mbPopupPressed) |
| { |
| // border lines |
| mpOutDev->SetLineColor(mpStyle->GetLightColor()); |
| mpOutDev->DrawLine(Point(aPos.X()+1, aPos.Y()+1), Point(aPos.X()+1, aPos.Y()+aSize.Height()-2)); |
| mpOutDev->DrawLine(Point(aPos.X()+1, aPos.Y()+1), Point(aPos.X()+aSize.Width()-2, aPos.Y()+1)); |
| |
| mpOutDev->SetLineColor(mpStyle->GetShadowColor()); |
| mpOutDev->DrawLine(Point(aPos.X()+1, aPos.Y()+aSize.Height()-2), |
| Point(aPos.X()+aSize.Width()-2, aPos.Y()+aSize.Height()-2)); |
| mpOutDev->DrawLine(Point(aPos.X()+aSize.Width()-2, aPos.Y()+1), |
| Point(aPos.X()+aSize.Width()-2, aPos.Y()+aSize.Height()-2)); |
| } |
| |
| // the arrowhead |
| Color aArrowColor = mbHasHiddenMember ? mpStyle->GetHighlightLinkColor() : mpStyle->GetButtonTextColor(); |
| mpOutDev->SetLineColor(aArrowColor); |
| mpOutDev->SetFillColor(aArrowColor); |
| Point aCenter(aPos.X() + (aSize.Width() >> 1), aPos.Y() + (aSize.Height() >> 1)); |
| Point aPos1, aPos2; |
| aPos1.X() = aCenter.X() - 4; |
| aPos2.X() = aCenter.X() + 4; |
| aPos1.Y() = aCenter.Y() - 3; |
| aPos2.Y() = aCenter.Y() - 3; |
| |
| if (mbPopupPressed) |
| { |
| aPos1.X() += 1; |
| aPos2.X() += 1; |
| aPos1.Y() += 1; |
| aPos2.Y() += 1; |
| } |
| |
| do |
| { |
| ++aPos1.X(); |
| --aPos2.X(); |
| ++aPos1.Y(); |
| ++aPos2.Y(); |
| mpOutDev->DrawLine(aPos1, aPos2); |
| } |
| while (aPos1 != aPos2); |
| |
| if (mbHasHiddenMember) |
| { |
| // tiny little box to display in presence of hidden member(s). |
| Point aBoxPos(aPos.X() + aSize.Width() - 5, aPos.Y() + aSize.Height() - 5); |
| if (mbPopupPressed) |
| { |
| aBoxPos.X() += 1; |
| aBoxPos.Y() += 1; |
| } |
| Size aBoxSize(3, 3); |
| mpOutDev->DrawRect(Rectangle(aBoxPos, aBoxSize)); |
| } |
| } |
| |
| // ============================================================================ |
| |
| ScMenuFloatingWindow::MenuItemData::MenuItemData() : |
| mbEnabled(true), |
| mpAction(static_cast<ScDPFieldPopupWindow::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(OUString::createFromAscii("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::createFromAscii("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; |
| } |
| |
| // ============================================================================ |
| |
| ScDPFieldPopupWindow::Member::Member() : |
| mbVisible(true) |
| { |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| ScDPFieldPopupWindow::CancelButton::CancelButton(ScDPFieldPopupWindow* pParent) : |
| ::CancelButton(pParent), mpParent(pParent) {} |
| |
| void ScDPFieldPopupWindow::CancelButton::Click() |
| { |
| mpParent->EndPopupMode(); |
| ::CancelButton::Click(); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| ScDPFieldPopupWindow::ScDPFieldPopupWindow(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); |
| Size aOutSize = GetOutputSizePixel(); |
| |
| getSectionPosSize(aPos, aSize, BTN_OK); |
| maBtnOk.SetPosSizePixel(aPos, aSize); |
| maBtnOk.SetFont(getLabelFont()); |
| maBtnOk.SetClickHdl( LINK(this, ScDPFieldPopupWindow, 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, ScDPFieldPopupWindow, 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.SetControlBackground(rStyle.GetMenuColor()); |
| maChkToggleAll.SetClickHdl( LINK(this, ScDPFieldPopupWindow, 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)), BMP_COLOR_NORMAL); |
| maBtnSelectSingle.SetClickHdl( LINK(this, ScDPFieldPopupWindow, 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)), BMP_COLOR_NORMAL); |
| maBtnUnselectSingle.SetClickHdl( LINK(this, ScDPFieldPopupWindow, ButtonHdl) ); |
| maBtnUnselectSingle.Show(); |
| } |
| |
| ScDPFieldPopupWindow::~ScDPFieldPopupWindow() |
| { |
| } |
| |
| void ScDPFieldPopupWindow::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 ScDPFieldPopupWindow::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 ScDPFieldPopupWindow::selectCurrentMemberOnly(bool bSet) |
| { |
| setAllMemberState(!bSet); |
| sal_uInt16 nSelected = maChecks.GetSelectEntryPos(); |
| maChecks.CheckEntryPos(nSelected, bSet); |
| } |
| |
| void ScDPFieldPopupWindow::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( ScDPFieldPopupWindow, 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( ScDPFieldPopupWindow, 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( ScDPFieldPopupWindow, 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 ScDPFieldPopupWindow::MouseMove(const MouseEvent& rMEvt) |
| { |
| ScMenuFloatingWindow::MouseMove(rMEvt); |
| |
| size_t nSelectedMenu = getSelectedMenuItem(); |
| if (nSelectedMenu == MENU_NOT_SELECTED) |
| queueCloseSubMenu(); |
| } |
| |
| long ScDPFieldPopupWindow::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 ScDPFieldPopupWindow::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* ScDPFieldPopupWindow::GetPreferredKeyInputWindow() |
| { |
| return maTabStopCtrls[mnCurTabStop]; |
| } |
| |
| Reference<XAccessible> ScDPFieldPopupWindow::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 ScDPFieldPopupWindow::setMemberSize(size_t n) |
| { |
| maMembers.reserve(n); |
| } |
| |
| void ScDPFieldPopupWindow::addMember(const OUString& rName, bool bVisible) |
| { |
| Member aMember; |
| aMember.maName = rName; |
| aMember.mbVisible = bVisible; |
| maMembers.push_back(aMember); |
| } |
| |
| void ScDPFieldPopupWindow::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& ScDPFieldPopupWindow::getWindowSize() const |
| { |
| return maWndSize; |
| } |
| |
| void ScDPFieldPopupWindow::getResult(hash_map<OUString, bool, OUStringHash>& rResult) |
| { |
| typedef hash_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 ScDPFieldPopupWindow::close(bool bOK) |
| { |
| if (bOK && mpOKAction.get()) |
| mpOKAction->execute(); |
| |
| EndPopupMode(); |
| } |
| |
| void ScDPFieldPopupWindow::setExtendedData(ExtendedData* p) |
| { |
| mpExtendedData.reset(p); |
| } |
| |
| ScDPFieldPopupWindow::ExtendedData* ScDPFieldPopupWindow::getExtendedData() |
| { |
| return mpExtendedData.get(); |
| } |
| |
| void ScDPFieldPopupWindow::setOKAction(Action* p) |
| { |
| mpOKAction.reset(p); |
| } |
| |