File indexing completed on 2024-05-12 04:42:02
0001 /* 0002 SPDX-FileCopyrightText: 2015 Gregor Mi <codestruct@posteo.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-or-later 0005 */ 0006 0007 #ifndef KMORETOOLS_H 0008 #define KMORETOOLS_H 0009 0010 #include <QMenu> 0011 #include <QString> 0012 #include <QUrl> 0013 0014 #include <KService> 0015 0016 #include <memory> 0017 0018 #include <kmoretools_export.h> 0019 0020 class KMoreToolsService; 0021 class KMoreToolsMenuBuilder; 0022 class KMoreToolsPrivate; 0023 0024 /** 0025 * Helps to create user-configurable menus with tools which are potentially not yet installed. 0026 * 0027 * This class is one entry point of the KMoreTools API. 0028 * See also KMoreToolsMenuFactory. 0029 * 0030 * @note This is a new API (published within KNewStuff since April 2015). Its current 0031 * target are KDE applications which are part of the kdesrcbuild infrastructure. 0032 * Here, it is possible to find all usages and to adapt to API changes when needed. 0033 * So, if you use this in your own application, beware that there might be API 0034 * changes when more use cases are developed. 0035 * 0036 * 0037 * Introduction 0038 * ------------ 0039 * KMoreTools helps to build user-configurable menus with tools which 0040 * might not installed yet. These tools may also take URL arguments supplied 0041 * by the application. 0042 * 0043 * The user will see a menu item for a tool even if it is not installed (in the 0044 * 'More' section). Furthermore, it makes long menus shorter by providing a 0045 * main and more section. 0046 * It provides a 'Configure menu' dialog to make the menu user-configurable. 0047 * 0048 * It does this in the following ways: 0049 * - Provide an API to define external applications for a given context. 0050 * - If a defined application is not installed (yet) the application is (optionally) 0051 * still presented to the user with a hint that it is not installed and a link 0052 * to the homepage (later with integration to package management). 0053 * This increases the discoverability of useful applications the user never 0054 * heard about yet. 0055 * - In case of many applications for a given context, it provides a GUI to the 0056 * user to hand-pick favorite tools. 0057 * This makes it easier for application developers to add alternative 0058 * application/tool suggestions without worrying about cluttered menus. 0059 * - Menu items can be (automatically) moved to the "More" submenu. 0060 * - Reduce translation effort by re-using .desktop files of the services added 0061 * to the menu. 0062 * 0063 * 0064 * Details 0065 * ------- 0066 * The term "kmt-desktopfile" refers to a 1:1 copy of a .desktop file. The 0067 * kmt-desktopfile is provided by the application that uses KMoreTools 0068 * and must be installed to subdirectories of /usr/share/kf5/kmoretools/ 0069 * - e.g. /usr/share/kf5/kmoretools/dolphin/statusbar-diskspace-menu/ 0070 * - e.g. /usr/share/kf5/kmoretools/kate/addons/project/git-tools/ 0071 * - generally, 'QStandardPaths::GenericDataLocation'/kf5/kmoretools/'uniqueId' 0072 * 0073 * See KMoreTools::KMoreTools for hints of how to install this correctly 0074 * using cmake. 0075 * 0076 * The kmt-desktopfiles are used to get ready-made translations for application 0077 * name and description even if the application is not installed. You can 0078 * also provide an icon which is used in the not-installed section when the 0079 * application is not installed yet. 0080 * 0081 * For details about the resulting menu structure, see KMoreToolsMenuBuilder. 0082 * 0083 * See also https://community.kde.org/Scratchpad/KMoreToolsFramework (outdated) 0084 * 0085 * 0086 * Rationale for the "Not installed" section 0087 * ----------------------------------------- 0088 * - Increase discoverability and visibility of useful free software that have 0089 * inherently low budget for marketing. 0090 * - Make interconnection of different free software packages as effortless as 0091 * possible (in terms of creating and maintaining the menu). 0092 * - Provide expert (i.e. your) knowledge to useful free software alternatives 0093 * to solve a certain task. 0094 * - Give novice users hints about tools that are useful in a particular 0095 * context even if they are not installed. 0096 * - Improve self-documentation of applications. 0097 * 0098 * 0099 * Presets 0100 * ------- 0101 * Before installing desktop files in your application you might take a look 0102 * at KMoreToolsPresets or KMoreToolsMenuFactory which might already contain 0103 * the needed tools. 0104 * 0105 * 0106 * Screenshots 0107 * ----------- 0108 * This section shows screenshots of usage examples. 0109 * 0110 * ### KSnapshot's Send To... menu 0111 * 0112 * Last updated: 2015-04-17, uncommitted demo, source code: 0113 * src/kde/kdegraphics/ksnapshot/ksnapshotsendtoactions.cpp 0114 * 0115 * Note, that the last item in the 'More' menu in the following screenshot was 0116 * added by KSnapshot's code. 0117 * 0118 * \image html kmoretools-ksnapshot-sendto-1.png "Send To menu" width=100px 0119 * 0120 * ### Dolphins's Space info menu 0121 * 0122 * Last updated: 2015-04-17, uncommitted demo, source code: src/kde/applications/dolphin/src/statusbar/spaceinfotoolsmenu.cpp 0123 * 0124 * \image html kmoretools-dolphin-spaceinfo-1.png "Space info menu" width=100px 0125 * 0126 * ### Kate's Project plugin git menu 0127 * 0128 * Last updated: 2015-03-25, uncommitted demo, source code: 0129 * src/kde/applications/kate/addons/project/kateprojecttreeviewcontextmenu.cpp 0130 * 0131 * \image html kmoretools-kate-project-1-all-installed.png "All git tools installed" width=100px 0132 * 0133 * \image html kmoretools-kate-project-2-two-not-installed.png "Not all git tools installed" width=100px 0134 * 0135 * \image html kmoretools-kate-project-3-config-dialog-all-installed.png "'Configure menu' dialog" width=100px 0136 * 0137 * ### Kate's Project plugin git menu 0138 * 0139 * Last updated: 2015-04-17, source code: src/frameworks/knewstuff/tests/kmoretools/kmoretoolstest.cpp 0140 * 0141 * \image html kmoretools-tests-configure-dialog-notinstalledapps.png "Configure dialog when there are non-installed apps" width=100px 0142 * 0143 * 0144 * FAQ 0145 * --- 0146 * ### Why is everything based on desktopfiles? 0147 * 0148 * - With desktopfiles translation can be reused. 0149 * - Definition of application icon can be reused. 0150 * - They provide a unified interface for dealing with program arguments. 0151 * 0152 * 0153 * todo later 0154 * ---------- 0155 * - question: KMoreTools::registerServiceByDesktopEntryName(): 0156 * - warn if service is not of Type=Application (KService::isApplication()) or just leave it? 0157 * Add support for package managers to install software (e.g. muon discover) 0158 * - maybe: kmt-desktopfiles: add a config file that can configure the homepage URLs 0159 * and e.g. the package name if needed for package manager support 0160 * 0161 */ 0162 class KMORETOOLS_EXPORT KMoreTools 0163 { 0164 friend class KMoreToolsService; 0165 friend class KMoreToolsServicePrivate; 0166 0167 public: 0168 /** 0169 * Specify how should be determined if a service is installed or not 0170 */ 0171 enum ServiceLocatingMode { 0172 /** 0173 * by existence of desktop file (discoverable by KService) 0174 */ 0175 ServiceLocatingMode_Default, 0176 0177 /** 0178 * by existence of executable defined in the TryExec or Exec line of 0179 * the provided kmt-desktopfile 0180 */ 0181 ServiceLocatingMode_ByProvidedExecLine, 0182 }; 0183 0184 /** 0185 * Specify where a menu item be placed by default 0186 */ 0187 enum MenuSection { 0188 /** 0189 * The item is placed in the main section (default) 0190 */ 0191 MenuSection_Main, 0192 0193 /** 0194 * The item is placed in the "More" submenu. 0195 */ 0196 MenuSection_More, 0197 }; 0198 0199 // /* * 0200 // * todo/later: introduce when needed 0201 // */ 0202 // enum NotInstalledSectionOption 0203 // { 0204 // /* * 0205 // * default 0206 // */ 0207 // NotInstalledSection_Show, 0208 // 0209 // /* * 0210 // * Even if there are non-installed apps the Not-Installed section will 0211 // * not be shown 0212 // */ 0213 // NotInstalledSection_Hide 0214 // }; 0215 0216 /** 0217 * Specify if the Configure dialog be accessible from the menu 0218 * (via a "Configure..." menu item) 0219 */ 0220 enum ConfigureDialogAccessibleSetting { 0221 /** 0222 * Always show the "Configure..." menu item 0223 * (default) 0224 */ 0225 ConfigureDialogAccessible_Always, 0226 0227 /** 0228 * Defensively show the "Configure..." menu item 0229 * 0230 * The "Configure..." menu item will only be shown if there are non-installed 0231 * apps. 0232 * Rationale (suggestion): Do not clutter menu more than needed in standard 0233 * cases. But when there are not-installed apps the configure dialog can 0234 * be used to find out more about these apps. 0235 * 0236 * Note, that the "Configure..." menu item still becomes visible when the 0237 * user holds the Ctrl key while opening the menu. 0238 */ 0239 ConfigureDialogAccessible_Defensive, 0240 }; 0241 0242 public: 0243 /** 0244 * @param uniqueId defines two things 0245 * 1) the config section name where the user settings done by the Configure 0246 * dialog will be stored. 0247 * 2) the location where the kmt-desktopfiles should be installed because 0248 * there they will be searched by default. 0249 * If @p uniqueId contains slashes they will result in subdirectories. 0250 * The default location can be overridden by 0251 * registerServiceByDesktopEntryName's kmtDesktopfileSubdir parameter. 0252 * This is currently used in KMoreToolsPresets implementation to 0253 * separate the kmt-desktopfiles location from the user's config section 0254 * name. 0255 * 0256 * Install Desktopfiles 0257 * -------------------- 0258 * Example 1 (CMakeLists.txt if uniqueId = "dolphin/statusbar-diskspace-menu"): 0259 * \verbatim 0260 # note the trailing slash ------------. (it makes sure only the contents of the directory is copied) 0261 # | ----fix--- 0262 # v ------ uniqueId----------------- 0263 install(DIRECTORY statusbar/kmt-desktopfiles/ DESTINATION ${KDE_INSTALL_DATADIR_KF5}/kmoretools/dolphin/statusbar-diskspace-menu) 0264 \endverbatim 0265 0266 Example 2: 0267 \verbatim 0268 ------ uniqueId-------------- 0269 install(DIRECTORY kmt-desktopfiles/ DESTINATION ${KDE_INSTALL_DATADIR_KF5}/kmoretools/kate/addons/project/git-tools) 0270 \endverbatim 0271 * 0272 * ### About ${KDE_INSTALL_DATADIR_KF5} 0273 * 0274 * In general, ${KDE_INSTALL_DATADIR_KF5}/kmoretools/hallo ends up in /usr/share/kf5/kmoretools/hallo. 0275 * 0276 * To use it, you need to add \verbatim include(KDEInstallDirs) \endverbatim to your CMakeLists.txt. 0277 */ 0278 explicit KMoreTools(const QString &uniqueId); 0279 0280 ~KMoreTools(); 0281 0282 KMoreTools(const KMoreTools &) = delete; 0283 KMoreTools &operator=(const KMoreTools &) = delete; 0284 0285 /** 0286 * Registers a service with KMoreTools. 0287 * 0288 * If the method is called more than once for the same desktopEntryName 0289 * the service is located again and the old service is replaced with the 0290 * new one. 0291 * 0292 * @param desktopEntryName is the name of the desktopfile (without the 0293 * .desktop extension) 0294 * The desktop file is 0295 * 1. either already installed. Then the information of the installed file 0296 * is used. 0297 * 2. or not installed and kmt-desktopfile is present. Then the information 0298 * of the app-local copy of desktopfile located in the kmt-desktopfiles 0299 * directory is used 0300 * 3. or not installed and no kmt-desktopfile provided. In this case 0301 * KMoreToolsService::setHomepageUrl should be used so that at least a 0302 * website link can be displayed. 0303 * 0304 * @param kmtDesktopfileSubdir when not empty overrides the @p uniqueId 0305 * parameter from the ctor when it comes to searching a kmt-desktopfile. 0306 * Default value is the empty string. 0307 * 0308 * @param serviceLocatingMode == ServiceLocatingMode_ByProvidedExecLine: 0309 * Some programs don't install a desktop file of their own (e.g. gitk). 0310 * If set to true then installed desktop files are not searched 0311 * but the provided in kmt-desktopfiles will be used to extract exec line. 0312 * The exec line will be used to determine if the executable is installed. 0313 * 0314 * @return a KMoreToolsService pointer which lives as long as KMoreTools, so 0315 * do not store it for later use. 0316 * @return nullptr if the kmt provided desktop file is faulty. 0317 * This kind of error must be fixed before you ship your application. 0318 * This case is only used for unit tests. 0319 */ 0320 KMoreToolsService *registerServiceByDesktopEntryName(const QString &desktopEntryName, 0321 const QString &kmtDesktopfileSubdir = QString(), 0322 ServiceLocatingMode serviceLocatingMode = ServiceLocatingMode_Default); 0323 0324 /** 0325 * @returns the interface to build the menu. It is a singleton instance 0326 * for each different @p userConfigPostfix (which is "" by default). 0327 * So repeated calls with same parameter will return the same object. 0328 * 0329 * The pointer lives as long as KMoreTools. 0330 * 0331 * @param userConfigPostfix is empty by default. You can use it to specify 0332 * a postfix for the user config section. So you can build different menus 0333 * which can be configured separately. (This is used in unit tests to 0334 * separated test cases.) 0335 * 0336 * @sa KMoreToolsMenuBuilder::clear() 0337 */ 0338 KMoreToolsMenuBuilder *menuBuilder(const QString &userConfigPostfix = QString()) const; 0339 0340 private: 0341 const std::unique_ptr<KMoreToolsPrivate> d; 0342 }; 0343 0344 // -------------------------------------------------------------------------------------- 0345 // -------------------------------------------------------------------------------------- 0346 0347 class KMoreToolsServicePrivate; 0348 0349 /** 0350 * A service described in a .desktop file (kmt-desktopfile) which will be 0351 * called "registered service". 0352 * 0353 * A registered service can either be installed (isInstalled() == true) 0354 * or - if not found on the system - not installed (isInstalled() == false). 0355 */ 0356 class KMORETOOLS_EXPORT KMoreToolsService 0357 { 0358 friend class KMoreTools; 0359 friend class KMoreToolsPrivate; 0360 0361 public: 0362 ~KMoreToolsService(); 0363 0364 KMoreToolsService(const KMoreToolsService &) = delete; 0365 KMoreToolsService &operator=(const KMoreToolsService &) = delete; 0366 0367 /** 0368 * @return the desktop entry name which the service is identified by and with which 0369 * it was registered (see registerServiceByDesktopEntryName). 0370 * 0371 * Filename without .desktop: e.g. if the desktop file is named 0372 * "org.kde.ksnapshot.desktop" then the desktop entry name is 0373 * "org.kde.ksnapshot". 0374 */ 0375 QString desktopEntryName() const; 0376 0377 /** 0378 * @returns true if the desktopfile with the given 0379 * desktopname (name of the .desktop file without the .desktop) 0380 * is installed on the system 0381 */ 0382 bool isInstalled() const; 0383 0384 /** 0385 * @returns the KService represented by an installed desktop file. 0386 * 0387 * @note that this might be nullptr even if isInstalled() is true. 0388 * This can only happen when ServiceLocatingMode::ServiceLocatingMode_ByProvidedExecLine 0389 * is used in registerServiceByDesktopEntryName. (Then the kmt-desktopfile's 0390 * Exec line is used to determine if a program is installed) 0391 */ 0392 KService::Ptr installedService() const; 0393 0394 /** 0395 * @returns a non-null KService::Ptr if app-local kmt-desktopfile is 0396 * found and valid 0397 */ 0398 KService::Ptr kmtProvidedService() const; 0399 0400 /** 0401 * @return the icon provided by the KMoreTools' user and not the installed one. 0402 * (e.g. QGit currently has got a blank icon installed) 0403 */ 0404 QIcon kmtProvidedIcon() const; 0405 0406 /** 0407 * @see setHomepageUrl() 0408 */ 0409 QUrl homepageUrl() const; 0410 0411 /** 0412 * Sets the homepage url the user is shown when a service is not installed. 0413 * This way the user gets some information of how to install the 0414 * application. 0415 */ 0416 void setHomepageUrl(const QUrl &url); 0417 0418 /** 0419 * @see setMaxUrlArgCount() 0420 */ 0421 int maxUrlArgCount() const; 0422 0423 /** 0424 * In KMoreToolsMenuFactory some minor magic is done. In the context of 0425 * connecting the action trigger signal we need to know the maximum number 0426 * of URL arguments a given service can accept. Usually a number between 0427 * 0 and 1. Sometimes 2. 0428 * E.g. kdf must not be called with any positional argument. 0429 * E.g. gitg can be called with zero or one arguments. 0430 */ 0431 void setMaxUrlArgCount(int maxUrlArgCount); 0432 0433 /** 0434 * @param formatString supports the following placeholders: 0435 * 0436 * 1. $GenericName 0437 * 2. $Name 0438 * 3. $DesktopEntryName 0439 * 0440 * which are replaced by the corresponding desktop file entries. 0441 * 0442 * If a value for a placeholder is not available (or empty) 0443 * (e.g. if no desktop file is available (not installed or not provided 0444 * via kmt-desktopfiles)) then the next one is used until 3. is reached which 0445 * is always available. Example: the formatString is "$GenericName", but 0446 * the GenericName field is not available. So $Name is used. If this is 0447 * also not available, $DesktopEntryName is used. 0448 * 0449 * @sa KMoreToolsMenuItem::setInitialItemText 0450 * @sa KMoreToolsMenuBuilder::setInitialItemTextTemplate 0451 */ 0452 QString formatString(const QString &formatString) const; 0453 0454 /** 0455 * 1. Icon from installed desktop file 0456 * If 1. is not found not found then... 0457 * 2. icon from kmt desktop file (which is then searched in the kmt-desktopfiles 0458 * directory, must have extension .svg or .png) 0459 * If 2. is not not found then... 0460 * 3. no icon 0461 */ 0462 QIcon icon() const; 0463 0464 /** 0465 * Will override the "Exec=" line of the service. Will only apply if the 0466 * service is installed. 0467 * 0468 * @see KService::setExec(...) 0469 */ 0470 void setExec(const QString &exec); 0471 0472 /** 0473 * Returns the associated appstream id that was previously set with setAppstreamId(). 0474 * If no appstream id was set, an empty string is returned. 0475 * 0476 * @return The service's appstream id. 0477 */ 0478 QString appstreamId() const; 0479 0480 /** 0481 * Sets the appstream id of the service. This is used to create a 0482 * appstream url for installing the service via a software store 0483 * (e.g. Discover). For instance, the appstream id for filelight is 0484 * "org.kde.filelight.desktop". 0485 * 0486 * @param id the appstream id 0487 */ 0488 void setAppstreamId(const QString &); 0489 0490 private: 0491 /** 0492 * @param kmtDesktopfileSubdir where to find kmt-desktopfiles 0493 * @param desktopEntryName name of the desktopfile without the .desktop extension 0494 * @param isInstalled true if desktop file is installed 0495 * @param installedService not nullptr if @p isInstalled is true 0496 * @param kmtDesktopfile not null if app-local kmt-desktopfile is found and valid 0497 */ 0498 KMoreToolsService(const QString &kmtDesktopfileSubdir, 0499 const QString &desktopEntryName, 0500 bool isInstalled, 0501 KService::Ptr installedService, 0502 KService::Ptr kmtDesktopfile); 0503 0504 /** 0505 * No copy semantic => private and no implementation 0506 */ 0507 KMoreToolsService(const KMoreTools &); 0508 0509 const std::unique_ptr<KMoreToolsServicePrivate> d; 0510 }; 0511 0512 // -------------------------------------------------------------------------------------- 0513 // -------------------------------------------------------------------------------------- 0514 0515 class KMoreToolsMenuItem; 0516 class KMoreToolsMenuBuilderPrivate; 0517 0518 /** 0519 * Define how the default structure of the menu should look like. 0520 * 0521 * Depending on if the added service is installed or not a "Not installed" section 0522 * will be automatically added to the generated menu. 0523 */ 0524 class KMORETOOLS_EXPORT KMoreToolsMenuBuilder 0525 { 0526 friend class KMoreToolsPrivate; 0527 friend class KMoreTools; 0528 friend class KMoreToolsTest; 0529 friend class KMoreToolsTest2; 0530 friend class KMoreToolsTestInteractive; 0531 0532 public: 0533 ~KMoreToolsMenuBuilder(); 0534 0535 KMoreToolsMenuBuilder(const KMoreToolsMenuBuilder &) = delete; 0536 KMoreToolsMenuBuilder &operator=(const KMoreToolsMenuBuilder &) = delete; 0537 0538 /** 0539 * Affects addMenuItem() if called before it. 0540 * 0541 * see KMoreToolsService::formatString, see KMoreToolsMenuItem::setInitialItemText 0542 * 0543 * The default template text is "$GenericName". 0544 */ 0545 void setInitialItemTextTemplate(const QString &templateText); 0546 0547 /** 0548 * Adds a registered service (which can installed or not) to the menu. 0549 * If the service is not installed it will be shown in the "Not installed" 0550 * section. 0551 * 0552 * @param registeredService will be added to a the menu. A unique menu 0553 * itemId will be generated automatically from the desktopEntryName. 0554 * See also KMoreToolsMenuItem::id(). 0555 * 0556 * @param defaultLocation is KMoreTools::MenuSection_Main by default. 0557 * 0558 * The registeredService->isInstalled() result will be respected. E.g. if the service 0559 * is not installed it will be placed in the "Not installed" section in the more 0560 * location of the menu even if @p defaultLocation was main location. 0561 * 0562 * See also KMoreToolsMenuItem ctor 0563 * 0564 * @sa KMoreToolsMenuItem::action() 0565 */ 0566 KMoreToolsMenuItem *addMenuItem(KMoreToolsService *registeredService, KMoreTools::MenuSection defaultLocation = KMoreTools::MenuSection_Main); 0567 0568 /** 0569 * Adds an action to the menu which is created and managed by the caller. 0570 * 0571 * @param action to be added to the menu. 0572 * 0573 * @param itemId is a unique (for this menu) id for the item. The itemId 0574 * _may_ be not unique. Then a unique id is generated automatically by 0575 * using some postfix. But it is better if you specify something sensible 0576 * because the itemId is used to find the items in the user config. 0577 * Otherwise the user config can be messed up if the order or number 0578 * of default menu items changes. NOTE, that the QAction::text is NOT 0579 * used to generate the unique id because the text is translated and 0580 * therefore not stable. 0581 * 0582 * @sa KMoreToolsMenuItem::action() 0583 */ 0584 KMoreToolsMenuItem *addMenuItem(QAction *action, const QString &itemId, KMoreTools::MenuSection defaultLocation = KMoreTools::MenuSection_Main); 0585 0586 /** 0587 * Clears all added menu items. This can be useful if the menuBuilder is reused more than once. 0588 * 0589 * @sa KMoreToolsService::menuBuilder 0590 */ 0591 void clear(); 0592 0593 /** 0594 * Builds the actual menu and appends all items (main items, 0595 * more submenu with a potential "not installed" section) to the @p menu. 0596 * 0597 * @param menu the menu where the items should be appended to 0598 * 0599 * @param configureDialogAccessibleSetting determines when the 0600 * "Configure..." menu item should be added to the menu 0601 * 0602 * @param moreMenu if not nullptr then it will be set to the pointer to the 0603 * "More" menu in case it was created. 0604 * Otherwise the pointer will set to nullptr. 0605 * This can be used to add some custom items to the @p menu. 0606 */ 0607 void buildByAppendingToMenu(QMenu *menu, 0608 KMoreTools::ConfigureDialogAccessibleSetting configureDialogAccessibleSetting = KMoreTools::ConfigureDialogAccessible_Always, 0609 QMenu **outMoreMenu = nullptr); 0610 0611 private: 0612 /** 0613 * for unit testing / get as debug string 0614 */ 0615 QString menuStructureAsString(bool mergeWithUserConfig) const; 0616 0617 /** 0618 * for unit testing 0619 */ 0620 void showConfigDialog(const QString &title); 0621 0622 /** 0623 * (needed because QMap needs a default ctor) 0624 */ 0625 KMoreToolsMenuBuilder(); 0626 0627 /** 0628 * internal usage 0629 */ 0630 KMoreToolsMenuBuilder(const QString &uniqueId, const QString &userConfigPostfix); 0631 0632 /** 0633 * No copy semantic => private and no implementation 0634 */ 0635 KMoreToolsMenuBuilder(const KMoreTools &); 0636 0637 const std::unique_ptr<KMoreToolsMenuBuilderPrivate> d; 0638 }; 0639 0640 // -------------------------------------------------------------------------------------- 0641 // -------------------------------------------------------------------------------------- 0642 0643 class KMoreToolsMenuItemPrivate; 0644 0645 /** 0646 * Represents a menu item of a service (application, tool or variant of the same 0647 * service with different parameters). 0648 * 0649 * The service might be installed or not. 0650 * 0651 * The corresponding QAction will be created for installed services. 0652 * 0653 * @note that for not-installed services action() returns nullptr. 0654 */ 0655 class KMORETOOLS_EXPORT KMoreToolsMenuItem 0656 { 0657 friend class KMoreToolsMenuBuilderPrivate; 0658 friend class KMoreToolsMenuBuilder; 0659 0660 public: 0661 KMoreToolsMenuItem(const KMoreToolsMenuItem &) = delete; 0662 KMoreToolsMenuItem &operator=(const KMoreToolsMenuItem &) = delete; 0663 0664 /** 0665 * Auto-generated unique id that tries to be as stable as possible even if the 0666 * menu gets restructured after the user did some customization that was 0667 * persisted in a config file. 0668 * 0669 * @note It is possible to add the same service more than once (and then 0670 * hopefully change the action text). When the order of those are changed, 0671 * the id will not be consistent (because internally an increasing number is used) 0672 * If you have issues with this you can solve this by manually 0673 * calling setId (e.g. 'desktopEntryName' + 'x'). 0674 */ 0675 QString id() const; 0676 0677 /** 0678 * (Optional) to help with stable ids (see id()) 0679 * 0680 * todo: make sure that if this is called, uniqueness of ids will be assured. 0681 * todo: make sure to show error if the id contains characters other than 0682 * alphanumerica, dashes and underscores etc. 0683 */ 0684 void setId(const QString &id); 0685 0686 /** 0687 * @return the underlying KMoreToolsService instance, 0688 * see KMoreToolsMenuBuilder::addMenuItem (with KKmoreToolsService* argument). 0689 * Or nullptr when KMoreToolsMenuBuilder::addMenuItem (with QAction* argument 0690 * was used). 0691 */ 0692 KMoreToolsService *registeredService() const; 0693 0694 /** 0695 * see KMoreToolsMenuBuilder::addMenuItem 0696 */ 0697 KMoreTools::MenuSection defaultLocation() const; 0698 0699 /** 0700 * see setInitialItemText() 0701 */ 0702 QString initialItemText() const; 0703 0704 /** 0705 * Sets the initial text of a menu item. 0706 * 0707 * Menu items of a non-installed service will get this text. 0708 * If the service is installed and you would like to change the item text, 0709 * you can retrieve the created QAction (action()) 0710 * and modify the text using QAction's methods (QAction::setText()). 0711 * 0712 * @see 0713 * - initialItemText() 0714 * - action() 0715 * - You can use the static method KMoreToolsService::formatString here. 0716 */ 0717 void setInitialItemText(const QString &itemText); 0718 0719 /** 0720 * Case 1 0721 * ------ 0722 * KMoreToolsMenuBuilder::addMenuItem was called with KKmoreToolsService* argument. 0723 * 0724 * the corresponding QAction which will be added to the actual menu when 0725 * underlying service is installed or else - if not installed - nullptr. 0726 * 0727 * So you can change the created action as you desire. 0728 * 0729 * We return nullptr because not-installed services will get a submenu with 0730 * other items like opening a website instead of an single action. 0731 * 0732 * To change the item's text even for not-installed services use initialItemText() 0733 * 0734 * Note, that once the method was invoked the first time the action is created 0735 * an then reused. 0736 * 0737 * Case 2 0738 * ------ 0739 * KMoreToolsMenuBuilder::addMenuItem was called with QAction* argument. 0740 * The added action will be returned. 0741 * 0742 * @see KMoreToolsService::isInstalled 0743 */ 0744 QAction *action() const; 0745 0746 private: // internal usage 0747 /** 0748 * Sets the initial item text. 0749 */ 0750 KMoreToolsMenuItem(KMoreToolsService *registeredService, KMoreTools::MenuSection defaultLocation, const QString &initialItemTextTemplate); 0751 0752 KMoreToolsMenuItem(QAction *action, const QString &itemId, KMoreTools::MenuSection defaultLocation); 0753 0754 ~KMoreToolsMenuItem(); 0755 0756 private: 0757 const std::unique_ptr<KMoreToolsMenuItemPrivate> d; 0758 }; 0759 0760 #endif // KMORETOOLS_H