diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
commit | 940b4d1848e8c70ab7642901a68594e8016caffc (patch) | |
tree | eb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /sc/source/ui/inc/checklistmenu.hxx | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream.tar.xz libreoffice-upstream.zip |
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sc/source/ui/inc/checklistmenu.hxx')
-rw-r--r-- | sc/source/ui/inc/checklistmenu.hxx | 447 |
1 files changed, 447 insertions, 0 deletions
diff --git a/sc/source/ui/inc/checklistmenu.hxx b/sc/source/ui/inc/checklistmenu.hxx new file mode 100644 index 000000000..5e988e31e --- /dev/null +++ b/sc/source/ui/inc/checklistmenu.hxx @@ -0,0 +1,447 @@ +/* -*- 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 <vcl/popupmenuwindow.hxx> +#include <vcl/button.hxx> +#include <vcl/edit.hxx> +#include <vcl/timer.hxx> +#include <vcl/svlbitm.hxx> + +#include <memory> +#include <unordered_set> +#include <unordered_map> +#include <map> +#include <set> + +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<css::accessibility::XAccessible> 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<css::accessibility::XAccessible> 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<Action> mpAction; + VclPtr<ScMenuFloatingWindow> mpSubMenuWin; + + MenuItemData(); + }; + + std::vector<MenuItemData> maMenuItems; + + struct SubMenuItemData + { + Timer maTimer; + VclPtr<ScMenuFloatingWindow> mpSubMenu; + size_t mnMenuPos; + + DECL_LINK( TimeoutHdl, Timer*, void ); + + SubMenuItemData(ScMenuFloatingWindow* pParent); + void reset(); + + private: + VclPtr<ScMenuFloatingWindow> 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<ScMenuFloatingWindow> mpParentMenu; +}; + +class ScCheckListMenuWindow; + +template <class T> struct VclPtr_hash; +template <> struct VclPtr_hash< VclPtr<vcl::Window> > +{ + size_t operator()( const VclPtr<vcl::Window>& r ) const + { + return reinterpret_cast<size_t>(r.get()); + } +}; + +class ScTabStops +{ +private: + typedef std::unordered_map< VclPtr<vcl::Window>, size_t, VclPtr_hash<VclPtr<vcl::Window>> > ControlToPosMap; + VclPtr<ScCheckListMenuWindow> mpMenuWindow; + ControlToPosMap maControlToPos; + std::vector<VclPtr<vcl::Window>> 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<SvLBoxButtonData> 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<OUString>& vOut, OUString& rLabel ); + std::unordered_set<OUString> 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<OUString> 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<ResultEntry> 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<ExtendedData> 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<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 + 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<ScSearchEdit> maEdSearch; + VclPtr<ScCheckListBox> maChecks; + + VclPtr<CheckBox> maChkToggleAll; + VclPtr<ImageButton> maBtnSelectSingle; + VclPtr<ImageButton> maBtnUnselectSingle; + + VclPtr<OKButton> maBtnOk; + VclPtr<CancelButton> maBtnCancel; + + std::vector<ScCheckListMember> maMembers; + // For Dates + std::map<OUString, size_t> maYearMonthMap; + + std::unique_ptr<ExtendedData> mpExtendedData; + std::unique_ptr<Action> mpOKAction; + std::unique_ptr<Action> 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: */ |