File indexing completed on 2025-01-19 03:50:37

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2009-02-15
0007  * Description : contextmenu helper class
0008  *
0009  * SPDX-FileCopyrightText: 2009-2010 by Andi Clemens <andi dot clemens at gmail dot com>
0010  * SPDX-FileCopyrightText: 2010-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #ifndef DIGIKAM_CONTEXT_MENU_HELPER_H
0017 #define DIGIKAM_CONTEXT_MENU_HELPER_H
0018 
0019 // Qt includes
0020 
0021 #include <QObject>
0022 #include <QList>
0023 #include <QUrl>
0024 
0025 // Local includes
0026 
0027 #include "digikam_export.h"
0028 #include "digikam_config.h"
0029 #include "coredbalbuminfo.h"
0030 
0031 class QAction;
0032 class QMenu;
0033 class QPoint;
0034 class QString;
0035 
0036 namespace Digikam
0037 {
0038 
0039 class AbstractCheckableAlbumModel;
0040 class Album;
0041 class AlbumIconItem;
0042 class AlbumModificationHelper;
0043 class ItemInfo;
0044 class ItemFilterModel;
0045 class PAlbum;
0046 class TagModificationHelper;
0047 class TAlbum;
0048 
0049 /**
0050  * @brief A helper class to add actions and special menus to the context menu.
0051  *
0052  * The %ContextMenuHelper class helps adding commonly used actions and menus.
0053  * Use this class to add
0054  *  - actions from the actionCollection
0055  *  - standard actions (copy, paste, delete)
0056  *  - temporary actions
0057  *  - predefined special actions
0058  *  - predefined submenus
0059  *  to the menu.
0060  *
0061  * All addAction() methods take a special parameter 'addDisabled'. This
0062  * parameter controls if disabled actions are added to the menu. Normally
0063  * adding disabled actions is turned off, to clean up the menu and make it
0064  * more readable.
0065  *
0066  * If the %ContextMenuHelper class is used, you need to call its own exec() method,
0067  * instead the one from the parent menu. This way signals from
0068  * special menus can be emitted and connected to the appropriate slots.
0069  */
0070 class DIGIKAM_GUI_EXPORT ContextMenuHelper : public QObject      // clazy:exclude=ctor-missing-parent-argument
0071 {
0072     Q_OBJECT
0073 
0074 public:
0075 
0076     typedef const QList<qlonglong> imageIds;
0077 
0078 public:
0079 
0080     /**
0081      * Constructs the helper class.
0082      *
0083      * @param parent the menu the helper class is linked to
0084      */
0085     explicit ContextMenuHelper(QMenu* const parent);   // clazy:exclude=ctor-missing-parent-argument
0086     ~ContextMenuHelper() override;
0087 
0088     /**
0089      * Add an action from the actionCollection.
0090      *
0091      * This method adds actions from the actionCollection. The actionCollection can
0092      * be set in the constructor of the ContextMenuHelper class.
0093      *
0094      * @param name the name of the action in the actionCollection
0095      * @param addDisabled if set, disabled actions are added to the menu
0096      */
0097     void addAction(const QString& name, bool addDisabled = false);
0098 
0099     /**
0100      * Add a temporary action.
0101      *
0102      * Sometimes it is necessary to define actions that only exist in the current context menu content.
0103      * Use this method to add such an action.
0104      *
0105      * @param action the action to add
0106      * @param addDisabled if set, disabled actions are added to the menu
0107      */
0108     void addAction(QAction* const action, bool addDisabled = false);
0109 
0110     /**
0111      * Add a temporary action and assign it to a custom slot.
0112      *
0113      * Use this method if you want to add a temporary action and immediately connect it to the
0114      * receiving slot.
0115      *
0116      * @param action the action to add
0117      * @param recv the receiver of the triggered action
0118      * @param slot the slot to connect the triggered action to
0119      * @param addDisabled if set, disabled actions are added to the menu
0120      */
0121     void addAction(QAction* const action, QObject* const recv, const char* const slot, bool addDisabled = false);
0122 
0123     /**
0124      * Add the standard cut action and connect it to the appropriate slot
0125      *
0126      * @param recv the receiver of the triggered action
0127      * @param slot the slot to connect the triggered action to
0128      */
0129     void addStandardActionCut(QObject* const recv, const char* const slot);
0130 
0131     /**
0132      * Add the standard copy action and connect it to the appropriate slot
0133      *
0134      * @param recv the receiver of the triggered action
0135      * @param slot the slot to connect the triggered action to
0136      */
0137     void addStandardActionCopy(QObject* const recv, const char* const slot);
0138 
0139     /**
0140      * Add the standard paste action and connect it to the appropriate slot
0141      *
0142      * @param recv the receiver of the triggered action
0143      * @param slot the slot to connect the triggered action to
0144      */
0145     void addStandardActionPaste(QObject* const recv, const char* const slot);
0146 
0147     /**
0148      * Add the standard delete action and connect it to the appropriate slot
0149      *
0150      * @param recv the receiver of the triggered action
0151      * @param slot the slot to connect the triggered action to
0152      * @param quantity the number of the files that should be deleted. This parameter is used for
0153      * the action name and is normally used when deleting more then one item.
0154      */
0155     void addStandardActionItemDelete(QObject* const recv, const char* const slot, int quantity = 1);
0156 
0157     /**
0158      * Add the standard Image Quality Sorter action and connect it to the appropriate slot
0159      *
0160      * @param recv the receiver of the triggered action
0161      * @param slot the slot to connect the triggered action to
0162      */
0163     void addIQSAction(QObject* const recv, const char* const slot);
0164 
0165     /**
0166      * Add the lighttable action to the menu.
0167      *
0168      * Do not use addAction() to add the lighttable action, because we need
0169      * to handle special cases here. Depending on whether the lighttable window
0170      * has already been created and filled with items, we set different actions.
0171      */
0172     void addStandardActionLightTable();
0173 
0174     /**
0175      * Add the thumbnail action to the menu.
0176      *
0177      * Do not use addAction() to add the thumbnail action, because we need
0178      * to handle special cases here. Depending on whether the current view is
0179      * album or icon view, we set different actions.
0180      *
0181      * @param ids the selected items in the current view
0182      * @param album the current album the AlbumIconView is displaying
0183      */
0184     void addStandardActionThumbnail(const imageIds& ids, Album* const album);
0185 
0186     /**
0187      * Add section for main views for opening and moving/going to albums.
0188      *
0189      * This is a convenience function to ensure consistent menus and reduce
0190      * code duplication.
0191      *
0192      * @param imageIds the list of selected items
0193      * @param lightTable for the light table
0194      */
0195     void addOpenAndNavigateActions(const imageIds& ids, bool lightTable = false);
0196 
0197     /**
0198      * Add the services menu to the menu.
0199      *
0200      * The services menu is used to open the selected items in a different application.
0201      * It will query the item for registered services and provide them in a submenu.
0202      * The menu will be titled "Open With...".
0203      *
0204      * @param selectedItems the list of selected items
0205      */
0206     void addServicesMenu(const QList<QUrl>& selectedItems);
0207 
0208     /**
0209      * Add the Goto menu.
0210      *
0211      * This menu will provide the following actions for the given item:
0212      * - Goto Album
0213      * - Goto Date
0214      * - Goto Tag
0215      * To make this menu work, you need to run exec() from this class, otherwise the signals
0216      * are not emitted and you will not be able to react on triggered actions from this menu.
0217      * Make sure to connect the signals to the appropriate slots in the context menu handling method.
0218      *
0219      * @param imageIds the list of selected items
0220      * @see exec()
0221      * @see signalGotoAlbum() signalGotoDate() signalGotoTag()
0222      */
0223     void addGotoMenu(const imageIds& ids);
0224 
0225     /**
0226      * Add Queue Manager actions menu.
0227      */
0228     void addQueueManagerMenu();
0229 
0230     /**
0231      * Add actions to add, remove or edit a tag.
0232      * The tag modification helper is used to execute the action.
0233      * You must set the parent tag to use on modification helper.
0234      */
0235     void addActionNewTag(TagModificationHelper* const helper, TAlbum* const parentTag = nullptr);
0236     void addActionDeleteTag(TagModificationHelper* const helper, TAlbum* const tag);
0237     void addActionDeleteTags(TagModificationHelper* const helper, const QList<TAlbum*>& tags);
0238     void addActionEditTag(TagModificationHelper* const helper, TAlbum* const tag);
0239 
0240     /**
0241      * Add action to delete tags from people sidebar.
0242      */
0243     void addActionDeleteFaceTag(TagModificationHelper* const helper, TAlbum* const tag);
0244     void addActionDeleteFaceTags(TagModificationHelper* const helper, const QList<TAlbum*>& tags);
0245 
0246     /**
0247      * Add action to set tags as face tags.
0248      */
0249     void addActionTagToFaceTag(TagModificationHelper* const helper, TAlbum* const tag);
0250     void addActionTagsToFaceTags(TagModificationHelper* const helper, const QList<TAlbum*>& tags);
0251 
0252     /**
0253      * Add actions to add, remove or edit a tag.
0254      * The tag modification helper is used to execute the action.
0255      * You must set the parent tag to use on modification helper.
0256      */
0257     void addActionNewAlbum(AlbumModificationHelper* const helper, PAlbum* const parentAlbum = nullptr);
0258     void addActionDeleteAlbum(AlbumModificationHelper* const helper, PAlbum* const album);
0259     void addActionEditAlbum(AlbumModificationHelper* const helper, PAlbum* const album);
0260     void addActionRenameAlbum(AlbumModificationHelper* const helper, PAlbum* const album);
0261     void addActionResetAlbumIcon(AlbumModificationHelper* const helper, PAlbum* const album);
0262 
0263     /**
0264      * Add "Assign Tags" menu.
0265      *
0266      * This menu will provide a list of all tags available so that they can be assigned to the current
0267      * selected items.
0268      *
0269      * To make this menu work, you need to run exec() from this class, otherwise the signals
0270      * are not emitted and you will not be able to react on triggered actions from this menu.
0271      * Make sure to connect the signals to the appropriate slots in the context menu handling method.
0272      *
0273      * @param ids the selected items
0274      * @see exec()
0275      * @see signalAssignTag()
0276      */
0277     void addAssignTagsMenu(const imageIds& ids);
0278 
0279     /**
0280      * Add "Remove Tags" menu.
0281      *
0282      * This menu will provide a list of all tags assigned to the current items. Actions triggered in here
0283      * will remove the selected tag from the items.
0284      *
0285      * To make this menu work, you need to run exec() from this class, otherwise the signals
0286      * are not emitted and you will not be able to react on triggered actions from this menu.
0287      * Make sure to connect the signals to the appropriate slots in the context menu handling method.
0288      *
0289      * @param ids the selected items
0290      * @see exec()
0291      * @see signalRemoveTag()
0292      */
0293     void addRemoveTagsMenu(const imageIds& ids);
0294 
0295     /**
0296      * Add "Remove all Tags" action.
0297      *
0298      * Removes all tags from the selected item ids except face tags.
0299      *
0300      * @param ids the selected items
0301      */
0302     void addRemoveAllTags(const imageIds& ids);
0303 
0304     /**
0305      * Add a menu to create new tags from adressbook entries.
0306      */
0307     void addCreateTagFromAddressbookMenu();
0308 
0309     /**
0310     * Add "Pick/Color/Rating Labels" action.
0311     *
0312     * This action will provide methods to assign pick/color/rating labels to the currently selected items.
0313     *
0314     * To make this menu work, you need to run exec() from this class, otherwise the signals
0315     * are not emitted and you will not be able to react on triggered actions from this menu.
0316     * Make sure to connect the signals to the appropriate slots in the context menu handling method.
0317     *
0318     * @see exec()
0319     * @see signalAssignPickLabel()
0320     * @see signalAssignColorLabel()
0321     * @see signalAssignRating()
0322     */
0323     void addLabelsAction();
0324 
0325     /**
0326      * Add a "Group" menu.
0327      * This menu will provide actions open, close, add to, remove from, or split a group.
0328      *
0329      * addGroupActions will add the actions as a flat list, not in a submenu.
0330      * Note: Call setItemFilterModel before to have Open/Close group actions.
0331      */
0332     void addGroupMenu(const imageIds& ids, const QList<QAction*>& extraMenuItems = QList<QAction*>());
0333     void addGroupActions(const imageIds& ids);
0334 
0335     /**
0336      * Set a filter model.
0337      * Some of the group actions will operate directly on the model.
0338      */
0339     void setItemFilterModel(ItemFilterModel* const model);
0340 
0341     /**
0342      * Add a Select and Deselect menu to check and uncheck albums.
0343      * Note: Call setAlbumModel before, or this will have no effect.
0344      */
0345     void addAlbumCheckUncheckActions(Album* const album);
0346 
0347     /**
0348      * Set an album model.
0349      * The check/uncheck actions will operate directly on the model.
0350      */
0351     void setAlbumModel(AbstractCheckableAlbumModel* const model);
0352 
0353     /**
0354      * Add Import Webservices actions menu.
0355      */
0356     void addImportMenu();
0357 
0358     /**
0359      * Add Export Webservices actions menu.
0360      */
0361     void addExportMenu();
0362 
0363     /**
0364      * Add a submenu to the parent context menu.
0365      *
0366      * @param subMenu the submenu to be added
0367      */
0368     void addSubMenu(QMenu* subMenu);
0369 
0370     /**
0371      * Add a separator to the context menu
0372      */
0373     void addSeparator();
0374 
0375     /**
0376      * Execute the registered parent menu and evaluate the triggered actions.
0377      *
0378      * Always use this method instead the one from the parent menu.
0379      * It will ensure that the signals are emitted and special cases are handled.
0380      *
0381      * @param pos position of the triggered action in the registered menu
0382      * @param at the action that should be at the position pos
0383      * @return the triggered action
0384      */
0385     QAction* exec(const QPoint& pos, QAction* const at = nullptr);
0386 
0387 Q_SIGNALS:
0388 
0389     void signalSetThumbnail(const ItemInfo&);
0390     void signalGotoAlbum(const ItemInfo&);
0391     void signalGotoDate(const ItemInfo&);
0392     void signalGotoTag(int);
0393     void signalAssignTag(int);
0394     void signalRemoveTag(int);
0395     void signalAssignPickLabel(int);
0396     void signalAssignColorLabel(int);
0397     void signalAssignRating(int);
0398     void signalAddToExistingQueue(int);
0399     void signalAddNewTagFromABCMenu(const QString&);
0400     void signalPopupTagsView();
0401     void signalCreateGroup();
0402     void signalCreateGroupByTime();
0403     void signalCreateGroupByFilename();
0404     void signalCreateGroupByTimelapse();
0405     void signalUngroup();
0406     void signalRemoveFromGroup();
0407 
0408 private Q_SLOTS:
0409 
0410     void slotOpenWith();
0411     void slotOpenWith(QAction* action);
0412     void slotOpenInFileManager();
0413     void slotOpenImageFile();
0414     void slotDeselectAllAlbumItems();
0415     void slotOpenGroups();
0416     void slotCloseGroups();
0417     void slotOpenAllGroups();
0418     void slotCloseAllGroups();
0419     void slotSelectChildren();
0420     void slotDeselectChildren();
0421     void slotSelectParents();
0422     void slotDeselectParents();
0423     void slotRemoveAllTags();
0424 
0425 private:
0426 
0427     void setGroupsOpen(bool open);
0428     void setSelectedIds(const imageIds& ids);
0429     void setSelectedItems(const QList<QUrl>& urls);
0430 
0431     bool imageIdsHaveSameCategory(const imageIds& ids, DatabaseItem::Category category);
0432     QList<QAction*> groupMenuActions(const imageIds& ids);
0433 
0434 private:
0435 
0436     class Private;
0437     Private* const d;
0438 };
0439 
0440 } // namespace Digikam
0441 
0442 #endif // DIGIKAM_CONTEXT_MENU_HELPER_H