File indexing completed on 2024-03-24 15:25:58

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      * Updates the style of @p hamburgerMenuButton based on its parent's style and q->priority().
0128      */
0129     void updateButtonStyle(QToolButton *hamburgerMenuButton) const;
0130 
0131 public:
0132     KHamburgerMenu *const q_ptr;
0133 
0134 protected:
0135     /** @see newMenu(). Do not confuse this menu with QAction::menu(). */
0136     std::unique_ptr<QMenu> m_actualMenu;
0137     /** @see KHamburgerMenu::setMenuBarAdvertised() */
0138     bool m_advertiseMenuBar = true;
0139     /** @see newMenuBarAdvertisementMenu() */
0140     std::unique_ptr<QMenu> m_menuBarAdvertisementMenu;
0141     /** @see KHamburgerMenu::hideActionsOf() */
0142     std::forward_list<QPointer<const QWidget>> m_widgetsWithActionsToBeHidden;
0143     /** The menu that was used as a base when newMenu() was last called. With this we
0144      * make sure to reset the m_actualMenu if the q->menu() has been changed or replaced. */
0145     QPointer<QMenu> m_lastUsedMenu;
0146     /** Makes sure there are no redundant event listeners of the same class. */
0147     std::unique_ptr<ListenerContainer> m_listeners;
0148     /** The action that is put into QMenus to represent the KHamburgerMenu.
0149      * @see KHamburgerMenu::addToMenu() */
0150     QPointer<QAction> m_menuAction;
0151     /** @see KHamburgerMenu::setMenuBar() */
0152     QPointer<QMenuBar> m_menuBar;
0153     /** @see resetMenu() */
0154     bool m_menuResetNeeded = false;
0155     /** @see KHamburgerMenu::setShowMenuBarAction */
0156     QPointer<QAction> m_showMenuBarAction;
0157     /** Keeps track of changes to the "Show Menubar" button text. */
0158     QString m_showMenuBarText;
0159     QString m_showMenuBarWithAllActionsText;
0160     /** Identifies if the application set an icon for "Help" menu. */
0161     bool m_helpIconIsSet = false;
0162 };
0163 
0164 #endif // KHamburgerMenu_P_H