/* -*- 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/. */ #pragma once #include #include #include #include #include #include #include class ScCheckListMenuControl; class ScViewData; struct ScCheckListMember; struct ImplSVEvent; struct ScCheckListMember { enum DatePartType { YEAR, MONTH, DAY, }; OUString maName; // node name OUString maRealName; double mnValue; // number value of filter condition bool mbVisible; bool mbHiddenByOtherFilter; bool mbDate; bool mbLeaf; bool mbValue; // true if the filter condition is value DatePartType meDatePartType; // To store Year and Month if the member if DAY type std::vector maDateParts; ScCheckListMember(); std::unique_ptr mxParent; }; class ScCheckListMenuWindow; class ScListSubMenuControl; /** * This class implements a popup window for the auto filter dropdown. */ class ScCheckListMenuControl final { 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() {} // return true to dismiss the popup virtual bool execute() = 0; }; struct ResultEntry { OUString aName; double nValue; // number value of filter condition bool bValid; bool bDate; bool bValue; // true if the filter condition is value 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 && bValue == rhs.bValue && nValue == rhs.nValue; } }; typedef std::set ResultType; struct MenuItemData { bool mbEnabled:1; std::shared_ptr mxAction; std::unique_ptr mxSubMenuWin; MenuItemData(); }; /** * 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(); }; ScCheckListMenuControl(weld::Widget* pParent, ScViewData& rViewData, bool bTreeMode, int nWidth, bool bIsMultiField = false); ~ScCheckListMenuControl(); void addMenuItem(const OUString& rText, Action* pAction); void addSeparator(); ScListSubMenuControl* addSubMenuItem(const OUString& rText, bool bEnabled, bool bColorMenu); void selectMenuItem(size_t nPos, bool bSubMenuTimer); void queueLaunchSubMenu(size_t nPos, ScListSubMenuControl* pMenu); void setMemberSize(size_t n); void addDateMember(const OUString& rName, double nVal, bool bVisible, bool bHiddenByOtherFilter); void addMember(const OUString& rName, const double nVal, bool bVisible, bool bHiddenByOtherFilter, bool bValue = false); void clearMembers(); size_t initMembers(int nMaxMemberWidth = -1); void setConfig(const Config& rConfig); bool isAllSelected() const; void getResult(ResultType& rResult); void launch(weld::Widget* pWidget, const tools::Rectangle& rRect); void close(bool bOK); void StartPopupMode(weld::Widget* pParent, const tools::Rectangle& rRect); void EndPopupMode(); size_t getSubMenuPos(const ScListSubMenuControl* pSubMenu); void setSubMenuFocused(const ScListSubMenuControl* pSubMenu); void queueCloseSubMenu(); void clearSelectedMenuItem(); /** * 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(); ScViewData& GetViewData() const { return mrViewData; } void GrabFocus(); void setOKAction(Action* p); void setPopupEndAction(Action* p); void setFieldChangedAction(Action* p); int GetTextWidth(const OUString& rsName) const; int IncreaseWindowWidthToFitText(int nMaxTextWidth); /** * 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(); void endSubMenu(ScListSubMenuControl& rSubMenu); void addFields(const std::vector& aFields); tools::Long getField(); private: std::vector maMenuItems; /** * Calculate the appropriate window size based on the menu items. */ void prepWindow(); void setAllMemberState(bool bSet); void selectCurrentMemberOnly(bool bSet); void updateMemberParents(const weld::TreeIter* pLeaf, size_t nIdx); std::unique_ptr ShowCheckEntry(const OUString& sName, ScCheckListMember& rMember, bool bShow = true, bool bCheck = true); void CheckEntry(std::u16string_view sName, const weld::TreeIter* pParent, bool bCheck); void CheckEntry(const weld::TreeIter& rEntry, bool bCheck); void GetRecursiveChecked(const weld::TreeIter* pEntry, std::unordered_set& vOut, OUString& rLabel); std::unordered_set GetAllChecked(); bool IsChecked(std::u16string_view sName, const weld::TreeIter* pParent); int GetCheckedEntryCount() const; void CheckAllChildren(const weld::TreeIter& rEntry, bool bCheck); void setSelectedMenuItem(size_t nPos); std::unique_ptr FindEntry(const weld::TreeIter* pParent, std::u16string_view sNode); void executeMenuItem(size_t nPos); /** * Get the area of the active row. Suitable as the parent rectangle * argument for Executing a popup */ tools::Rectangle GetSubMenuParentRect(); struct SubMenuItemData; void handleMenuTimeout(const SubMenuItemData* pTimer); void launchSubMenu(); void CreateDropDown(); DECL_LINK(ButtonHdl, weld::Button&, void); DECL_LINK(TriStateHdl, weld::Toggleable&, void); void Check(const weld::TreeIter* pIter); DECL_LINK(CheckHdl, const weld::TreeView::iter_col&, void); DECL_LINK(PopupModeEndHdl, weld::Popover&, void); DECL_LINK(SearchEditTimeoutHdl, Timer*, void); DECL_LINK(ComboChangedHdl, weld::ComboBox&, void); DECL_LINK(EdModifyHdl, weld::Entry&, void); DECL_LINK(EdActivateHdl, weld::Entry&, bool); DECL_LINK(RowActivatedHdl, weld::TreeView& rMEvt, bool); DECL_LINK(SelectHdl, weld::TreeView&, void); DECL_LINK(TreeSizeAllocHdl, const Size&, void); DECL_LINK(KeyInputHdl, const KeyEvent&, bool); DECL_LINK(MenuKeyInputHdl, const KeyEvent&, bool); DECL_LINK(MouseEnterHdl, const MouseEvent&, bool); DECL_LINK(PostPopdownHdl, void*, void); void SetDropdownPos(); DECL_LINK(SetDropdownPosHdl, void*, void); DECL_LINK(CommandHdl, const CommandEvent&, bool); void ResizeToRequest(); void DropPendingEvents(); private: std::unique_ptr mxBuilder; std::unique_ptr mxPopover; std::unique_ptr mxContainer; std::unique_ptr mxMenu; std::unique_ptr mxScratchIter; std::unique_ptr mxNonMenu; std::unique_ptr mxFieldsComboLabel; std::unique_ptr mxFieldsCombo; std::unique_ptr mxEdSearch; std::unique_ptr mxBox; std::unique_ptr mxListChecks; std::unique_ptr mxTreeChecks; weld::TreeView* mpChecks; std::unique_ptr mxChkToggleAll; std::unique_ptr mxBtnSelectSingle; std::unique_ptr mxBtnUnselectSingle; std::unique_ptr mxButtonBox; std::unique_ptr mxBtnOk; std::unique_ptr mxBtnCancel; std::unique_ptr mxContextMenu; ScopedVclPtr mxDropDown; std::vector maMembers; // For Dates std::map maYearMonthMap; std::unique_ptr mxExtendedData; std::unique_ptr mxOKAction; std::unique_ptr mxPopupEndAction; std::unique_ptr mxFieldChangedAction; Config maConfig; Size maAllocatedSize; int mnCheckWidthReq; /// matching width request for mxChecks int mnWndWidth; /// whole window width. int mnCheckListVisibleRows; TriState mePrevToggleAllState; size_t mnSelectedMenu; ScViewData& mrViewData; ImplSVEvent* mnAsyncPostPopdownId; ImplSVEvent* mnAsyncSetDropdownPosId; bool mbHasDates; bool mbIsPoppedUp; struct SubMenuItemData { Timer maTimer; ScListSubMenuControl* mpSubMenu; size_t mnMenuPos; DECL_LINK( TimeoutHdl, Timer*, void ); SubMenuItemData(ScCheckListMenuControl* pParent); void reset(); private: ScCheckListMenuControl* mpParent; }; SubMenuItemData maOpenTimer; SubMenuItemData maCloseTimer; Timer maSearchEditTimer; bool mbIsMultiField; }; class ScListSubMenuControl final { public: ScListSubMenuControl(weld::Widget* pParent, ScCheckListMenuControl& rParentControl, bool bColorMenu); void setPopupStartAction(ScCheckListMenuControl::Action* p); void GrabFocus(); bool IsVisible() const; void StartPopupMode(weld::Widget* pParent, const tools::Rectangle& rRect); void EndPopupMode(); void addMenuItem(const OUString& rText, ScCheckListMenuControl::Action* pAction); // nMenu of 0 for background color, nMenu of 1 for text color void addMenuColorItem(const OUString& rText, bool bActive, VirtualDevice& rImage, int nMenu, ScCheckListMenuControl::Action* pAction); void addSeparator(); void clearMenuItems(); void resizeToFitMenuItems(); ScViewData& GetViewData() const { return mrParentControl.GetViewData(); } ScCheckListMenuControl::ExtendedData* getExtendedData() { return mrParentControl.getExtendedData(); } VclPtr create_virtual_device() const { return mxMenu->create_virtual_device(); } /** * 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: std::unique_ptr mxBuilder; std::unique_ptr mxPopover; std::unique_ptr mxContainer; std::unique_ptr mxMenu; std::unique_ptr mxBackColorMenu; std::unique_ptr mxTextColorMenu; std::unique_ptr mxScratchIter; std::unique_ptr mxPopupStartAction; std::vector maMenuItems; ScCheckListMenuControl& mrParentControl; int mnBackColorMenuPrefHeight; int mnTextColorMenuPrefHeight; bool mbColorMenu; DECL_LINK(RowActivatedHdl, weld::TreeView& rMEvt, bool); DECL_LINK(ColorSelChangedHdl, weld::TreeView&, void); DECL_LINK(MenuKeyInputHdl, const KeyEvent&, bool); void SetupMenu(weld::TreeView& rMenu); void executeMenuItem(ScCheckListMenuControl::Action* pAction); void addItem(ScCheckListMenuControl::Action* pAction); }; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */