File indexing completed on 2025-02-16 10:03:26
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 <KNS3/knewstuff_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 * @since 5.10 0162 */ 0163 class KNEWSTUFF_EXPORT KMoreTools 0164 { 0165 friend class KMoreToolsService; 0166 friend class KMoreToolsServicePrivate; 0167 0168 public: 0169 /** 0170 * Specify how should be determined if a service is installed or not 0171 */ 0172 enum ServiceLocatingMode { 0173 /** 0174 * by existence of desktop file (discoverable by KService) 0175 */ 0176 ServiceLocatingMode_Default, 0177 0178 /** 0179 * by existence of executable defined in the TryExec or Exec line of 0180 * the provided kmt-desktopfile 0181 */ 0182 ServiceLocatingMode_ByProvidedExecLine, 0183 }; 0184 0185 /** 0186 * Specify where a menu item be placed by default 0187 */ 0188 enum MenuSection { 0189 /** 0190 * The item is placed in the main section (default) 0191 */ 0192 MenuSection_Main, 0193 0194 /** 0195 * The item is placed in the "More" submenu. 0196 */ 0197 MenuSection_More, 0198 }; 0199 0200 // /* * 0201 // * todo/later: introduce when needed 0202 // */ 0203 // enum NotInstalledSectionOption 0204 // { 0205 // /* * 0206 // * default 0207 // */ 0208 // NotInstalledSection_Show, 0209 // 0210 // /* * 0211 // * Even if there are non-installed apps the Not-Installed section will 0212 // * not be shown 0213 // */ 0214 // NotInstalledSection_Hide 0215 // }; 0216 0217 /** 0218 * Specify if the Configure dialog be accessible from the menu 0219 * (via a "Configure..." menu item) 0220 */ 0221 enum ConfigureDialogAccessibleSetting { 0222 /** 0223 * Always show the "Configure..." menu item 0224 * (default) 0225 */ 0226 ConfigureDialogAccessible_Always, 0227 0228 /** 0229 * Defensively show the "Configure..." menu item 0230 * 0231 * The "Configure..." menu item will only be shown if there are non-installed 0232 * apps. 0233 * Rationale (suggestion): Do not clutter menu more than needed in standard 0234 * cases. But when there are not-installed apps the configure dialog can 0235 * be used to find out more about these apps. 0236 * 0237 * Note, that the "Configure..." menu item still becomes visible when the 0238 * user holds the Ctrl key while opening the menu. 0239 */ 0240 ConfigureDialogAccessible_Defensive, 0241 }; 0242 0243 public: 0244 /** 0245 * @param uniqueId defines two things 0246 * 1) the config section name where the user settings done by the Configure 0247 * dialog will be stored. 0248 * 2) the location where the kmt-desktopfiles should be installed because 0249 * there they will be searched by default. 0250 * If @p uniqueId contains slashes they will result in subdirectories. 0251 * The default location can be overridden by 0252 * registerServiceByDesktopEntryName's kmtDesktopfileSubdir parameter. 0253 * This is currently used in KMoreToolsPresets implementation to 0254 * separate the kmt-desktopfiles location from the user's config section 0255 * name. 0256 * 0257 * Install Desktopfiles 0258 * -------------------- 0259 * Example 1 (CMakeLists.txt if uniqueId = "dolphin/statusbar-diskspace-menu"): 0260 * \verbatim 0261 # note the trailing slash ------------. (it makes sure only the contents of the directory is copied) 0262 # | ----fix--- 0263 # v ------ uniqueId----------------- 0264 install(DIRECTORY statusbar/kmt-desktopfiles/ DESTINATION ${KDE_INSTALL_DATADIR_KF5}/kmoretools/dolphin/statusbar-diskspace-menu) 0265 \endverbatim 0266 0267 Example 2: 0268 \verbatim 0269 ------ uniqueId-------------- 0270 install(DIRECTORY kmt-desktopfiles/ DESTINATION ${KDE_INSTALL_DATADIR_KF5}/kmoretools/kate/addons/project/git-tools) 0271 \endverbatim 0272 * 0273 * ### About ${KDE_INSTALL_DATADIR_KF5} 0274 * 0275 * In general, ${KDE_INSTALL_DATADIR_KF5}/kmoretools/hallo ends up in /usr/share/kf5/kmoretools/hallo. 0276 * 0277 * To use it, you need to add \verbatim include(KDEInstallDirs) \endverbatim to your CMakeLists.txt. 0278 */ 0279 explicit KMoreTools(const QString &uniqueId); 0280 0281 ~KMoreTools(); 0282 0283 KMoreTools(const KMoreTools &) = delete; 0284 KMoreTools &operator=(const KMoreTools &) = delete; 0285 0286 /** 0287 * Registers a service with KMoreTools. 0288 * 0289 * If the method is called more than once for the same desktopEntryName 0290 * the service is located again and the old service is replaced with the 0291 * new one. 0292 * 0293 * @param desktopEntryName is the name of the desktopfile (without the 0294 * .desktop extension) 0295 * The desktop file is 0296 * 1. either already installed. Then the information of the installed file 0297 * is used. 0298 * 2. or not installed and kmt-desktopfile is present. Then the information 0299 * of the app-local copy of desktopfile located in the kmt-desktopfiles 0300 * directory is used 0301 * 3. or not installed and no kmt-desktopfile provided. In this case 0302 * KMoreToolsService::setHomepageUrl should be used so that at least a 0303 * website link can be displayed. 0304 * 0305 * @param kmtDesktopfileSubdir when not empty overrides the @p uniqueId 0306 * parameter from the ctor when it comes to searching a kmt-desktopfile. 0307 * Default value is the empty string. 0308 * 0309 * @param serviceLocatingMode == ServiceLocatingMode_ByProvidedExecLine: 0310 * Some programs don't install a desktop file of their own (e.g. gitk). 0311 * If set to true then installed desktop files are not searched 0312 * but the provided in kmt-desktopfiles will be used to extract exec line. 0313 * The exec line will be used to determine if the executable is installed. 0314 * 0315 * @return a KMoreToolsService pointer which lives as long as KMoreTools, so 0316 * do not store it for later use. 0317 * @return nullptr if the kmt provided desktop file is faulty. 0318 * This kind of error must be fixed before you ship your application. 0319 * This case is only used for unit tests. 0320 */ 0321 KMoreToolsService *registerServiceByDesktopEntryName(const QString &desktopEntryName, 0322 const QString &kmtDesktopfileSubdir = QString(), 0323 ServiceLocatingMode serviceLocatingMode = ServiceLocatingMode_Default); 0324 0325 /** 0326 * @returns the interface to build the menu. It is a singleton instance 0327 * for each different @p userConfigPostfix (which is "" by default). 0328 * So repeated calls with same parameter will return the same object. 0329 * 0330 * The pointer lives as long as KMoreTools. 0331 * 0332 * @param userConfigPostfix is empty by default. You can use it to specify 0333 * a postfix for the user config section. So you can build different menus 0334 * which can be configured separately. (This is used in unit tests to 0335 * separated test cases.) 0336 * 0337 * @sa KMoreToolsMenuBuilder::clear() 0338 */ 0339 KMoreToolsMenuBuilder *menuBuilder(const QString &userConfigPostfix = QString()) const; 0340 0341 private: 0342 const std::unique_ptr<KMoreToolsPrivate> d; 0343 }; 0344 0345 // -------------------------------------------------------------------------------------- 0346 // -------------------------------------------------------------------------------------- 0347 0348 class KMoreToolsServicePrivate; 0349 0350 /** 0351 * A service described in a .desktop file (kmt-desktopfile) which will be 0352 * called "registered service". 0353 * 0354 * A registered service can either be installed (isInstalled() == true) 0355 * or - if not found on the system - not installed (isInstalled() == false). 0356 * 0357 * @since 5.10 0358 */ 0359 class KNEWSTUFF_EXPORT KMoreToolsService 0360 { 0361 friend class KMoreTools; 0362 friend class KMoreToolsPrivate; 0363 0364 public: 0365 ~KMoreToolsService(); 0366 0367 KMoreToolsService(const KMoreToolsService &) = delete; 0368 KMoreToolsService &operator=(const KMoreToolsService &) = delete; 0369 0370 /** 0371 * @return the desktop entry name which the service is identified by and with which 0372 * it was registered (see registerServiceByDesktopEntryName). 0373 * 0374 * Filename without .desktop: e.g. if the desktop file is named 0375 * "org.kde.ksnapshot.desktop" then the desktop entry name is 0376 * "org.kde.ksnapshot". 0377 */ 0378 QString desktopEntryName() const; 0379 0380 /** 0381 * @returns true if the desktopfile with the given 0382 * desktopname (name of the .desktop file without the .desktop) 0383 * is installed on the system 0384 */ 0385 bool isInstalled() const; 0386 0387 /** 0388 * @returns the KService represented by an installed desktop file. 0389 * 0390 * @note that this might be nullptr even if isInstalled() is true. 0391 * This can only happen when ServiceLocatingMode::ServiceLocatingMode_ByProvidedExecLine 0392 * is used in registerServiceByDesktopEntryName. (Then the kmt-desktopfile's 0393 * Exec line is used to determine if a program is installed) 0394 */ 0395 KService::Ptr installedService() const; 0396 0397 /** 0398 * @returns a non-null KService::Ptr if app-local kmt-desktopfile is 0399 * found and valid 0400 */ 0401 KService::Ptr kmtProvidedService() const; 0402 0403 /** 0404 * @return the icon provided by the KMoreTools' user and not the installed one. 0405 * (e.g. QGit currently has got a blank icon installed) 0406 */ 0407 QIcon kmtProvidedIcon() const; 0408 0409 /** 0410 * @see setHomepageUrl() 0411 */ 0412 QUrl homepageUrl() const; 0413 0414 /** 0415 * Sets the homepage url the user is shown when a service is not installed. 0416 * This way the user gets some information of how to install the 0417 * application. 0418 */ 0419 void setHomepageUrl(const QUrl &url); 0420 0421 /** 0422 * @see setMaxUrlArgCount() 0423 */ 0424 int maxUrlArgCount() const; 0425 0426 /** 0427 * In KMoreToolsMenuFactory some minor magic is done. In the context of 0428 * connecting the action trigger signal we need to know the maximum number 0429 * of URL arguments a given service can accept. Usually a number between 0430 * 0 and 1. Sometimes 2. 0431 * E.g. kdf must not be called with any positional argument. 0432 * E.g. gitg can be called with zero or one arguments. 0433 */ 0434 void setMaxUrlArgCount(int maxUrlArgCount); 0435 0436 /** 0437 * @param formatString supports the following placeholders: 0438 * 0439 * 1. $GenericName 0440 * 2. $Name 0441 * 3. $DesktopEntryName 0442 * 0443 * which are replaced by the corresponding desktop file entries. 0444 * 0445 * If a value for a placeholder is not available (or empty) 0446 * (e.g. if no desktop file is available (not installed or not provided 0447 * via kmt-desktopfiles)) then the next one is used until 3. is reached which 0448 * is always available. Example: the formatString is "$GenericName", but 0449 * the GenericName field is not available. So $Name is used. If this is 0450 * also not available, $DesktopEntryName is used. 0451 * 0452 * @sa KMoreToolsMenuItem::setInitialItemText 0453 * @sa KMoreToolsMenuBuilder::setInitialItemTextTemplate 0454 */ 0455 QString formatString(const QString &formatString) const; 0456 0457 /** 0458 * 1. Icon from installed desktop file 0459 * If 1. is not found not found then... 0460 * 2. icon from kmt desktop file (which is then searched in the kmt-desktopfiles 0461 * directory, must have extension .svg or .png) 0462 * If 2. is not not found then... 0463 * 3. no icon 0464 */ 0465 QIcon icon() const; 0466 0467 /** 0468 * Will override the "Exec=" line of the service. Will only apply if the 0469 * service is installed. 0470 * 0471 * @see KService::setExec(...) 0472 */ 0473 void setExec(const QString &exec); 0474 0475 /** 0476 * Returns the associated appstream id that was previously set with setAppstreamId(). 0477 * If no appstream id was set, an empty string is returned. 0478 * 0479 * @return The service's appstream id. 0480 * 0481 * @since 5.48 0482 */ 0483 QString appstreamId() const; 0484 0485 /** 0486 * Sets the appstream id of the service. This is used to create a 0487 * appstream url for installing the service via a software store 0488 * (e.g. Discover). For instance, the appstream id for filelight is 0489 * "org.kde.filelight.desktop". 0490 * 0491 * @param id the appstream id 0492 * 0493 * @since 5.48 0494 */ 0495 void setAppstreamId(const QString &); 0496 0497 private: 0498 /** 0499 * @param kmtDesktopfileSubdir where to find kmt-desktopfiles 0500 * @param desktopEntryName name of the desktopfile without the .desktop extension 0501 * @param isInstalled true if desktop file is installed 0502 * @param installedService not nullptr if @p isInstalled is true 0503 * @param kmtDesktopfile not null if app-local kmt-desktopfile is found and valid 0504 */ 0505 KMoreToolsService(const QString &kmtDesktopfileSubdir, 0506 const QString &desktopEntryName, 0507 bool isInstalled, 0508 KService::Ptr installedService, 0509 KService::Ptr kmtDesktopfile); 0510 0511 /** 0512 * No copy semantic => private and no implementation 0513 */ 0514 KMoreToolsService(const KMoreTools &); 0515 0516 const std::unique_ptr<KMoreToolsServicePrivate> d; 0517 }; 0518 0519 // -------------------------------------------------------------------------------------- 0520 // -------------------------------------------------------------------------------------- 0521 0522 class KMoreToolsMenuItem; 0523 class KMoreToolsMenuBuilderPrivate; 0524 0525 /** 0526 * Define how the default structure of the menu should look like. 0527 * 0528 * Depending on if the added service is installed or not a "Not installed" section 0529 * will be automatically added to the generated menu. 0530 * 0531 * @since 5.10 0532 */ 0533 class KNEWSTUFF_EXPORT KMoreToolsMenuBuilder 0534 { 0535 friend class KMoreToolsPrivate; 0536 friend class KMoreTools; 0537 friend class KMoreToolsTest; 0538 friend class KMoreToolsTest2; 0539 friend class KMoreToolsTestInteractive; 0540 0541 public: 0542 ~KMoreToolsMenuBuilder(); 0543 0544 KMoreToolsMenuBuilder(const KMoreToolsMenuBuilder &) = delete; 0545 KMoreToolsMenuBuilder &operator=(const KMoreToolsMenuBuilder &) = delete; 0546 0547 /** 0548 * Affects addMenuItem() if called before it. 0549 * 0550 * see KMoreToolsService::formatString, see KMoreToolsMenuItem::setInitialItemText 0551 * 0552 * The default template text is "$GenericName". 0553 */ 0554 void setInitialItemTextTemplate(const QString &templateText); 0555 0556 /** 0557 * Adds a registered service (which can installed or not) to the menu. 0558 * If the service is not installed it will be shown in the "Not installed" 0559 * section. 0560 * 0561 * @param registeredService will be added to a the menu. A unique menu 0562 * itemId will be generated automatically from the desktopEntryName. 0563 * See also KMoreToolsMenuItem::id(). 0564 * 0565 * @param defaultLocation is KMoreTools::MenuSection_Main by default. 0566 * 0567 * The registeredService->isInstalled() result will be respected. E.g. if the service 0568 * is not installed it will be placed in the "Not installed" section in the more 0569 * location of the menu even if @p defaultLocation was main location. 0570 * 0571 * See also KMoreToolsMenuItem ctor 0572 * 0573 * @sa KMoreToolsMenuItem::action() 0574 */ 0575 KMoreToolsMenuItem *addMenuItem(KMoreToolsService *registeredService, KMoreTools::MenuSection defaultLocation = KMoreTools::MenuSection_Main); 0576 0577 /** 0578 * Adds an action to the menu which is created and managed by the caller. 0579 * 0580 * @param action to be added to the menu. 0581 * 0582 * @param itemId is a unique (for this menu) id for the item. The itemId 0583 * _may_ be not unique. Then a unique id is generated automatically by 0584 * using some postfix. But it is better if you specify something sensible 0585 * because the itemId is used to find the items in the user config. 0586 * Otherwise the user config can be messed up if the order or number 0587 * of default menu items changes. NOTE, that the QAction::text is NOT 0588 * used to generate the unique id because the text is translated and 0589 * therefore not stable. 0590 * 0591 * @sa KMoreToolsMenuItem::action() 0592 */ 0593 KMoreToolsMenuItem *addMenuItem(QAction *action, const QString &itemId, KMoreTools::MenuSection defaultLocation = KMoreTools::MenuSection_Main); 0594 0595 /** 0596 * Clears all added menu items. This can be useful if the menuBuilder is reused more than once. 0597 * 0598 * @sa KMoreToolsService::menuBuilder 0599 */ 0600 void clear(); 0601 0602 /** 0603 * Builds the actual menu and appends all items (main items, 0604 * more submenu with a potential "not installed" section) to the @p menu. 0605 * 0606 * @param menu the menu where the items should be appended to 0607 * 0608 * @param configureDialogAccessibleSetting determines when the 0609 * "Configure..." menu item should be added to the menu 0610 * 0611 * @param moreMenu if not nullptr then it will be set to the pointer to the 0612 * "More" menu in case it was created. 0613 * Otherwise the pointer will set to nullptr. 0614 * This can be used to add some custom items to the @p menu. 0615 */ 0616 void buildByAppendingToMenu(QMenu *menu, 0617 KMoreTools::ConfigureDialogAccessibleSetting configureDialogAccessibleSetting = KMoreTools::ConfigureDialogAccessible_Always, 0618 QMenu **outMoreMenu = nullptr); 0619 0620 private: 0621 /** 0622 * for unit testing / get as debug string 0623 */ 0624 QString menuStructureAsString(bool mergeWithUserConfig) const; 0625 0626 /** 0627 * for unit testing 0628 */ 0629 void showConfigDialog(const QString &title); 0630 0631 /** 0632 * (needed because QMap needs a default ctor) 0633 */ 0634 KMoreToolsMenuBuilder(); 0635 0636 /** 0637 * internal usage 0638 */ 0639 KMoreToolsMenuBuilder(const QString &uniqueId, const QString &userConfigPostfix); 0640 0641 /** 0642 * No copy semantic => private and no implementation 0643 */ 0644 KMoreToolsMenuBuilder(const KMoreTools &); 0645 0646 const std::unique_ptr<KMoreToolsMenuBuilderPrivate> d; 0647 }; 0648 0649 // -------------------------------------------------------------------------------------- 0650 // -------------------------------------------------------------------------------------- 0651 0652 class KMoreToolsMenuItemPrivate; 0653 0654 /** 0655 * Represents a menu item of a service (application, tool or variant of the same 0656 * service with different parameters). 0657 * 0658 * The service might be installed or not. 0659 * 0660 * The corresponding QAction will be created for installed services. 0661 * 0662 * @note that for not-installed services action() returns nullptr. 0663 * 0664 * @since 5.10 0665 */ 0666 class KNEWSTUFF_EXPORT KMoreToolsMenuItem 0667 { 0668 friend class KMoreToolsMenuBuilderPrivate; 0669 friend class KMoreToolsMenuBuilder; 0670 0671 public: 0672 KMoreToolsMenuItem(const KMoreToolsMenuItem &) = delete; 0673 KMoreToolsMenuItem &operator=(const KMoreToolsMenuItem &) = delete; 0674 0675 /** 0676 * Auto-generated unique id that tries to be as stable as possible even if the 0677 * menu gets restructured after the user did some customization that was 0678 * persisted in a config file. 0679 * 0680 * @note It is possible to add the same service more than once (and then 0681 * hopefully change the action text). When the order of those are changed, 0682 * the id will not be consistent (because internally an increasing number is used) 0683 * If you have issues with this you can solve this by manually 0684 * calling setId (e.g. 'desktopEntryName' + 'x'). 0685 */ 0686 QString id() const; 0687 0688 /** 0689 * (Optional) to help with stable ids (see id()) 0690 * 0691 * todo: make sure that if this is called, uniqueness of ids will be assured. 0692 * todo: make sure to show error if the id contains characters other than 0693 * alphanumerica, dashes and underscores etc. 0694 */ 0695 void setId(const QString &id); 0696 0697 /** 0698 * @return the underlying KMoreToolsService instance, 0699 * see KMoreToolsMenuBuilder::addMenuItem (with KKmoreToolsService* argument). 0700 * Or nullptr when KMoreToolsMenuBuilder::addMenuItem (with QAction* argument 0701 * was used). 0702 */ 0703 KMoreToolsService *registeredService() const; 0704 0705 /** 0706 * see KMoreToolsMenuBuilder::addMenuItem 0707 */ 0708 KMoreTools::MenuSection defaultLocation() const; 0709 0710 /** 0711 * see setInitialItemText() 0712 */ 0713 QString initialItemText() const; 0714 0715 /** 0716 * Sets the initial text of a menu item. 0717 * 0718 * Menu items of a non-installed service will get this text. 0719 * If the service is installed and you would like to change the item text, 0720 * you can retrieve the created QAction (action()) 0721 * and modify the text using QAction's methods (QAction::setText()). 0722 * 0723 * @see 0724 * - initialItemText() 0725 * - action() 0726 * - You can use the static method KMoreToolsService::formatString here. 0727 */ 0728 void setInitialItemText(const QString &itemText); 0729 0730 /** 0731 * Case 1 0732 * ------ 0733 * KMoreToolsMenuBuilder::addMenuItem was called with KKmoreToolsService* argument. 0734 * 0735 * the corresponding QAction which will be added to the actual menu when 0736 * underlying service is installed or else - if not installed - nullptr. 0737 * 0738 * So you can change the created action as you desire. 0739 * 0740 * We return nullptr because not-installed services will get a submenu with 0741 * other items like opening a website instead of an single action. 0742 * 0743 * To change the item's text even for not-installed services use initialItemText() 0744 * 0745 * Note, that once the method was invoked the first time the action is created 0746 * an then reused. 0747 * 0748 * Case 2 0749 * ------ 0750 * KMoreToolsMenuBuilder::addMenuItem was called with QAction* argument. 0751 * The added action will be returned. 0752 * 0753 * @see KMoreToolsService::isInstalled 0754 */ 0755 QAction *action() const; 0756 0757 private: // internal usage 0758 /** 0759 * Sets the initial item text. 0760 */ 0761 KMoreToolsMenuItem(KMoreToolsService *registeredService, KMoreTools::MenuSection defaultLocation, const QString &initialItemTextTemplate); 0762 0763 KMoreToolsMenuItem(QAction *action, const QString &itemId, KMoreTools::MenuSection defaultLocation); 0764 0765 ~KMoreToolsMenuItem(); 0766 0767 private: 0768 const std::unique_ptr<KMoreToolsMenuItemPrivate> d; 0769 }; 0770 0771 #endif // KMORETOOLS_H