File indexing completed on 2024-12-01 03:39:09
0001 /* 0002 This file is part of the KDE project 0003 SPDX-FileCopyrightText: 2021 Felix Ernst <fe.a.ernst@gmail.com> 0004 0005 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0006 */ 0007 0008 #ifndef KHamburgerMenu_P_H 0009 #define KHamburgerMenu_P_H 0010 0011 #include "khamburgermenu.h" 0012 0013 #include <QWidgetAction> 0014 0015 #include <QPointer> 0016 #include <QScopedPointer> 0017 0018 #include <forward_list> 0019 #include <unordered_set> 0020 0021 class ListenerContainer; 0022 0023 class QMenu; 0024 class QMenuBar; 0025 class QToolButton; 0026 0027 /** 0028 * The private class of KHamburgerMenu used for the PIMPL idiom. 0029 * \internal 0030 */ 0031 class KHamburgerMenuPrivate : public QObject 0032 { 0033 Q_OBJECT 0034 Q_DECLARE_PUBLIC(KHamburgerMenu) 0035 0036 public: 0037 explicit KHamburgerMenuPrivate(KHamburgerMenu *qq); 0038 0039 ~KHamburgerMenuPrivate() override; 0040 0041 /** @see KHamburgerMenu::setMenuBar() */ 0042 void setMenuBar(QMenuBar *menuBar); 0043 0044 /** @see KHamburgerMenu::setMenuBar() */ 0045 QMenuBar *menuBar() const; 0046 0047 /** @see KHamburgerMenu::setMenuBarAdvertised() */ 0048 void setMenuBarAdvertised(bool advertise); 0049 0050 /** @see KHamburgerMenu::setMenuBarAdvertised() */ 0051 bool menuBarAdvertised() const; 0052 0053 /** @see KHamburgerMenu::setShowMenuBarAction() */ 0054 void setShowMenuBarAction(QAction *showMenuBarAction); 0055 0056 /** @see KHamburgerMenu::insertIntoMenuBefore() */ 0057 void insertIntoMenuBefore(QMenu *menu, QAction *before); 0058 0059 /** @see KHamburgerMenu::hideActionsOf() */ 0060 void hideActionsOf(QWidget *widget); 0061 0062 /** @see KHamburgerMenu::showActionsOf() */ 0063 void showActionsOf(QWidget *widget); 0064 0065 /** @see KHamburgerMenu::createWidget() */ 0066 QWidget *createWidget(QWidget *parent); 0067 0068 /** 0069 * This method only returns exclusive actions. The idea is to remove any @p nonExclusives 0070 * from @p from and all of its sub-menus. This means a copy of @p from is created when 0071 * necessary that has a menu() that only contains the exclusive actions from @p from. 0072 * @param from the action this method extracts the exclusive actions from. 0073 * @param parent the widget that is to become the parent if a copy of @p from needs 0074 * to be created. 0075 * @param nonExclusives the actions which will not be anywhere within the returned action. 0076 * @return either nullptr, @p from unchanged or a copy of @p from without the @p nonExclusives. 0077 * In the last case, the caller gets ownership of this new copy with parent @p parent. 0078 */ 0079 QAction *actionWithExclusivesFrom(QAction *from, QWidget *parent, std::unordered_set<const QAction *> &nonExclusives) const; 0080 0081 /** 0082 * @return a new menu with all actions from KHamburgerMenu::menu() which aren't 0083 * exempted from being displayed (@see hideActionsOf()). 0084 * Next adds the help menu. 0085 * At last adds a special sub-menu by calling newMenuBarAdvertisementMenu() if this step 0086 * was not explicitly set to be skipped (@see KHamburgerMenu::setMenuBarAdvertised()). 0087 */ 0088 std::unique_ptr<QMenu> newMenu(); 0089 0090 /** 0091 * @return a special sub-menu that advertises actions of the menu bar which would otherwise 0092 * not be visible or discoverable for the user 0093 * @see KHamburgerMenu::setMenuBarAdvertised() 0094 */ 0095 std::unique_ptr<QMenu> newMenuBarAdvertisementMenu(std::unordered_set<const QAction *> &visibleActions); 0096 0097 /** @see resetMenu() */ 0098 inline void notifyMenuResetNeeded() 0099 { 0100 m_menuResetNeeded = true; 0101 } 0102 0103 /** 0104 * Does nothing if m_menuResetNeeded is false. 0105 * Otherwise deletes m_actualMenu and creates a newMenu() in its place. This new menu 0106 * is then set to be used whenever the hamburger menu is opened. 0107 * @see newMenu() 0108 */ 0109 void resetMenu(); 0110 0111 /** 0112 * Sets the correct visibility for KHamburgerMenu buttons based on the visibility of the 0113 * menu bar (@see setMenuBar()). 0114 * Also sets the correct visibility of the menu item (@see addToMenu()) based on the visibility 0115 * of the menu bar and of the KHamburgerMenu buttons. 0116 */ 0117 void updateVisibility(); 0118 0119 protected: 0120 /** 0121 * Makes the KHamburgerMenu buttons change style just like other toolbuttons would 0122 * when their associated action changes. 0123 */ 0124 void slotActionChanged(); 0125 0126 /** 0127 * When m_menuBar->isVisible(): Opens the first menu of the menu bar. 0128 * Otherwise it acts the same way as clicking on a visible KHamburgerMenu button. 0129 * If no KHamburgerMenu button is visible, open its menu anyway. 0130 * 0131 * @note The action triggered signal is not emitted when a normal button that contains a menu 0132 * is pressed. So this slot will effectively only be called by keyboard shortcut. 0133 */ 0134 void slotActionTriggered(); 0135 0136 /** 0137 * Updates the style of @p hamburgerMenuButton based on its parent's style and q->priority(). 0138 */ 0139 void updateButtonStyle(QToolButton *hamburgerMenuButton) const; 0140 0141 public: 0142 KHamburgerMenu *const q_ptr; 0143 0144 protected: 0145 /** @see newMenu(). Do not confuse this menu with QAction::menu(). */ 0146 std::unique_ptr<QMenu> m_actualMenu; 0147 /** @see KHamburgerMenu::setMenuBarAdvertised() */ 0148 bool m_advertiseMenuBar = true; 0149 /** @see newMenuBarAdvertisementMenu() */ 0150 std::unique_ptr<QMenu> m_menuBarAdvertisementMenu; 0151 /** @see KHamburgerMenu::hideActionsOf() */ 0152 std::forward_list<QPointer<const QWidget>> m_widgetsWithActionsToBeHidden; 0153 /** The menu that was used as a base when newMenu() was last called. With this we 0154 * make sure to reset the m_actualMenu if the q->menu() has been changed or replaced. */ 0155 QPointer<QMenu> m_lastUsedMenu; 0156 /** Makes sure there are no redundant event listeners of the same class. */ 0157 std::unique_ptr<ListenerContainer> m_listeners; 0158 /** The action that is put into QMenus to represent the KHamburgerMenu. 0159 * @see KHamburgerMenu::addToMenu() */ 0160 QPointer<QAction> m_menuAction; 0161 /** @see KHamburgerMenu::setMenuBar() */ 0162 QPointer<QMenuBar> m_menuBar; 0163 /** @see resetMenu() */ 0164 bool m_menuResetNeeded = false; 0165 /** @see KHamburgerMenu::setShowMenuBarAction */ 0166 QPointer<QAction> m_showMenuBarAction; 0167 /** Keeps track of changes to the "Show Menubar" button text. */ 0168 QString m_showMenuBarText; 0169 QString m_showMenuBarWithAllActionsText; 0170 /** Identifies if the application set an icon for "Help" menu. */ 0171 bool m_helpIconIsSet = false; 0172 }; 0173 0174 #endif // KHamburgerMenu_P_H