/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef INCLUDED_SC_SOURCE_UI_INC_CHECKLISTMENU_HXX #define INCLUDED_SC_SOURCE_UI_INC_CHECKLISTMENU_HXX #include #include #include #include #include #include #include #include #include #include namespace com::sun::star { namespace accessibility { class XAccessible; } } class ScDocument; class ScAccessibleFilterMenu; class ScMenuFloatingWindow : public PopupMenuFloatingWindow { public: static constexpr size_t MENU_NOT_SELECTED = 999; /** * Action to perform when an event takes place. Create a sub-class of * this to implement the desired action. */ class Action { public: virtual ~Action() {} virtual void execute() = 0; }; explicit ScMenuFloatingWindow(vcl::Window* pParent, ScDocument* pDoc, sal_uInt16 nMenuStackLevel = 0); virtual ~ScMenuFloatingWindow() override; void dispose() override; virtual void PopupModeEnd() override; virtual void MouseMove(const MouseEvent& rMEvt) override; virtual void MouseButtonDown(const MouseEvent& rMEvt) override; virtual void MouseButtonUp(const MouseEvent& rMEvt) override; virtual void KeyInput(const KeyEvent& rKEvt) override; virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override; virtual css::uno::Reference CreateAccessible() override; void addMenuItem(const OUString& rText, Action* pAction); void addSeparator(); ScMenuFloatingWindow* addSubMenuItem(const 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 { return mnSelectedMenu;} void setName(const OUString& rName); const OUString& getName() const { return maName;} void executeMenuItem(size_t nPos); void getMenuItemPosSize(size_t nPos, Point& rPos, Size& rSize) const; ScMenuFloatingWindow* getParentMenuWindow() const { return mpParentMenu;} protected: virtual void handlePopupEnd(); Size getMenuSize() const; void drawMenuItem(vcl::RenderContext& rRenderContext, size_t nPos); void drawSeparator(vcl::RenderContext& rRenderContext, size_t nPos); void drawAllMenuItems(vcl::RenderContext& rRenderContext); const vcl::Font& getLabelFont() const { return maLabelFont; } void queueLaunchSubMenu(size_t nPos, ScMenuFloatingWindow* pMenu); void queueCloseSubMenu(); void launchSubMenu(bool bSetMenuPos); void endSubMenu(ScMenuFloatingWindow* pSubMenu); void fillMenuItemsToAccessible(ScAccessibleFilterMenu* pAccMenu) const; ScDocument* getDoc() { return mpDoc;} protected: css::uno::Reference mxAccessible; private: struct SubMenuItemData; void handleMenuTimeout(const SubMenuItemData* pTimer); void resizeToFitMenuItems(); void highlightMenuItem(vcl::RenderContext& rRenderContext, size_t nPos, bool bSelected); size_t getEnclosingMenuItem(const Point& rPos) const; size_t getSubMenuPos(const 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(const 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(); private: struct MenuItemData { OUString maText; bool mbEnabled:1; bool mbSeparator:1; std::shared_ptr mpAction; VclPtr mpSubMenuWin; MenuItemData(); }; std::vector maMenuItems; struct SubMenuItemData { Timer maTimer; VclPtr mpSubMenu; size_t mnMenuPos; DECL_LINK( TimeoutHdl, Timer*, void ); SubMenuItemData(ScMenuFloatingWindow* pParent); void reset(); private: VclPtr mpParent; }; SubMenuItemData maOpenTimer; SubMenuItemData maCloseTimer; vcl::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. OUString maName; size_t mnSelectedMenu; size_t mnClickedMenu; ScDocument* mpDoc; VclPtr mpParentMenu; }; class ScCheckListMenuWindow; template struct VclPtr_hash; template <> struct VclPtr_hash< VclPtr > { size_t operator()( const VclPtr& r ) const { return reinterpret_cast(r.get()); } }; class ScTabStops { private: typedef std::unordered_map< VclPtr, size_t, VclPtr_hash> > ControlToPosMap; VclPtr mpMenuWindow; ControlToPosMap maControlToPos; std::vector> maControls; size_t mnCurTabStop; public: ScTabStops( ScCheckListMenuWindow* mpMenuWin ); ~ScTabStops(); void AddTabStop( vcl::Window* pWin ); void SetTabStop( vcl::Window* pWin ); void CycleFocus( bool bReverse = false ); void clear(); }; struct ScCheckListMember; class ScCheckListBox : public SvTreeListBox { std::unique_ptr mpCheckButton; ScTabStops* mpTabStops; bool mbSeenMouseButtonDown; void CountCheckedEntries( SvTreeListEntry* pParent, sal_uLong& nCount ) const; void CheckAllChildren( SvTreeListEntry* pEntry, bool bCheck ); public: ScCheckListBox( vcl::Window* pParent ); virtual ~ScCheckListBox() override { disposeOnce(); } virtual void dispose() override { mpCheckButton.reset(); SvTreeListBox::dispose(); } void Init(); void CheckEntry( const OUString& sName, SvTreeListEntry* pParent, bool bCheck ); void CheckEntry( SvTreeListEntry* pEntry, bool bCheck ); SvTreeListEntry* ShowCheckEntry( const OUString& sName, ScCheckListMember& rMember, bool bShow = true, bool bCheck = true ); void GetRecursiveChecked( SvTreeListEntry* pEntry, std::unordered_set& vOut, OUString& rLabel ); std::unordered_set GetAllChecked(); bool IsChecked( const OUString& sName, SvTreeListEntry* pParent ); SvTreeListEntry* FindEntry( SvTreeListEntry* pParent, const OUString& sNode ); sal_uInt16 GetCheckedEntryCount() const; virtual void KeyInput( const KeyEvent& rKEvt ) override; virtual void MouseButtonDown(const MouseEvent& rMEvt) override; virtual void MouseButtonUp(const MouseEvent& rMEvt) override; void SetTabStopsContainer( ScTabStops* pTabStops ) { mpTabStops = pTabStops; } }; class ScSearchEdit : public Edit { private: ScTabStops* mpTabStops; public: ScSearchEdit(Window* pParent) : Edit(pParent) , mpTabStops(nullptr) { set_id("search_edit"); } virtual void MouseButtonDown( const MouseEvent& rMEvt ) override; void SetTabStopsContainer( ScTabStops* pTabStops ) { mpTabStops = pTabStops; } }; struct ScCheckListMember { enum DatePartType { YEAR, MONTH, DAY, }; OUString maName; // node name OUString maRealName; bool mbVisible; bool mbDate; bool mbLeaf; DatePartType meDatePartType; // To store Year and Month if the member if DAY type std::vector maDateParts; ScCheckListMember(); SvTreeListEntry* mpParent; }; /** * 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: struct ResultEntry { OUString aName; bool bValid; bool bDate; bool operator<(const ResultEntry& rhs) const { return aName < rhs.aName; } bool operator == (const ResultEntry& rhs) const { return aName == rhs.aName && bValid == rhs.bValid && bDate == rhs.bDate; } }; typedef std::set ResultType; /** * Extended data that the client code may need to store. Create a * sub-class of this and store data there. */ struct ExtendedData { virtual ~ExtendedData() {} }; /** * Configuration options for this popup window. */ struct Config { bool mbAllowEmptySet; bool mbRTL; Config(); }; explicit ScCheckListMenuWindow(vcl::Window* pParent, ScDocument* pDoc, int nWidth = -1); virtual ~ScCheckListMenuWindow() override; virtual void dispose() override; virtual void MouseMove(const MouseEvent& rMEvt) override; virtual bool EventNotify(NotifyEvent& rNEvt) override; virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override; virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override; void setMemberSize(size_t n); void setHasDates(bool bHasDates); void addDateMember(const OUString& rName, double nVal, bool bVisible); void addMember(const OUString& rName, bool bVisible); size_t initMembers(); void setConfig(const Config& rConfig); bool isAllSelected() const; void getResult(ResultType& rResult); void launch(const tools::Rectangle& rRect); 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(std::unique_ptr p); /** * Get the store auxiliary data, or NULL if no such data is stored. */ ExtendedData* getExtendedData(); void setOKAction(Action* p); void setPopupEndAction(Action* p); protected: virtual void handlePopupEnd() override; private: class CancelButton : public ::CancelButton { public: CancelButton(ScCheckListMenuWindow* pParent); virtual ~CancelButton() override; virtual void dispose() override; virtual void Click() override; private: VclPtr 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 EDIT_SEARCH, // Search box }; void getSectionPosSize(Point& rPos, Size& rSize, SectionType eType) const; /** * Calculate the appropriate window size, the position and size of each * control based on the menu items. */ void packWindow(); void setAllMemberState(bool bSet); void selectCurrentMemberOnly(bool bSet); void updateMemberParents( const SvTreeListEntry* pLeaf, size_t nIdx ); DECL_LINK( ButtonHdl, Button*, void ); DECL_LINK( TriStateHdl, Button*, void ); DECL_LINK( CheckHdl, SvTreeListBox*, void ); DECL_LINK( EdModifyHdl, Edit&, void ); private: VclPtr maEdSearch; VclPtr maChecks; VclPtr maChkToggleAll; VclPtr maBtnSelectSingle; VclPtr maBtnUnselectSingle; VclPtr maBtnOk; VclPtr maBtnCancel; std::vector maMembers; // For Dates std::map maYearMonthMap; std::unique_ptr mpExtendedData; std::unique_ptr mpOKAction; std::unique_ptr mpPopupEndAction; Config maConfig; Size maWndSize; /// whole window size. Size maMenuSize; /// size of all menu items combined. TriState mePrevToggleAllState; ScTabStops maTabStops; bool mbHasDates; }; #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */