File indexing completed on 2025-04-20 08:07:58
0001 /* 0002 This file is part of the KDE project 0003 SPDX-FileCopyrightText: 2007 Will Stephenson <wstephenson@kde.org> 0004 SPDX-FileCopyrightText: 2009 Ben Cooksley <bcooksley@kde.org> 0005 SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de> 0006 SPDX-FileCopyrightText: 2021 Harald Sitter <sitter@kde.org> 0007 0008 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0009 */ 0010 0011 #include "MenuItem.h" 0012 0013 #include "kcmmetadatahelpers.h" 0014 0015 #include <QList> 0016 #include <QString> 0017 0018 #include <KCModuleLoader> 0019 #include <KConfigGroup> 0020 #include <KDesktopFile> 0021 #include <KJsonUtils> 0022 #include <QFileInfo> 0023 0024 static bool childIsLessThan(MenuItem *left, MenuItem *right) 0025 { 0026 return left->weight() < right->weight(); 0027 } 0028 0029 class MenuItem::Private 0030 { 0031 public: 0032 Private() 0033 { 0034 } 0035 0036 MenuItem *parent; 0037 QList<MenuItem *> children; 0038 bool menu; 0039 QString name; 0040 QString category; 0041 int weight; 0042 KService::Ptr service; 0043 bool showDefaultIndicator = false; 0044 bool isCategoryOwner = false; 0045 QString comment; 0046 QString iconName; 0047 QString systemsettingsCategoryModule; 0048 bool isSystemsettingsCategory = false; 0049 bool isSystemsettingsRootCategory = false; 0050 bool isExternalAppModule = false; 0051 KPluginMetaData metaData; 0052 }; 0053 0054 MenuItem::MenuItem(bool isMenu, MenuItem *itsParent) 0055 : d(new Private()) 0056 { 0057 d->parent = itsParent; 0058 d->menu = isMenu; 0059 0060 if (d->parent) { 0061 d->parent->children().append(this); 0062 } 0063 } 0064 0065 MenuItem::~MenuItem() 0066 { 0067 qDeleteAll(d->children); 0068 delete d; 0069 } 0070 0071 void MenuItem::sortChildrenByWeight() 0072 { 0073 std::sort(d->children.begin(), d->children.end(), childIsLessThan); 0074 } 0075 0076 MenuItem *MenuItem::child(int index) 0077 { 0078 return d->children.at(index); 0079 } 0080 0081 QStringList MenuItem::keywords(bool doesRemoveDuplicates) const 0082 { 0083 QStringList listOfKeywords; 0084 const QJsonObject rawData = d->metaData.rawData(); 0085 // Add English keywords so users in other languages won't have to switch IME when searching. 0086 if (!QLocale().name().startsWith(QLatin1String("en_"))) { 0087 listOfKeywords << rawData[QStringLiteral("KPlugin")][QStringLiteral("Name")].toString(); 0088 listOfKeywords << d->metaData.value(QStringLiteral("X-KDE-Keywords"), QString()).split(QLatin1String(",")); 0089 } 0090 listOfKeywords << KJsonUtils::readTranslatedString(rawData, QStringLiteral("X-KDE-Keywords")).split(QStringLiteral(",")); 0091 listOfKeywords << d->name; 0092 for (MenuItem *child : std::as_const(d->children)) { 0093 listOfKeywords << child->keywords(false); 0094 } 0095 // Remove any soft hyphens (used in long words in some languages) 0096 listOfKeywords.replaceInStrings(QStringLiteral("\u00AD"), QString()); 0097 // Only remove duplicate keywords in the end 0098 if (doesRemoveDuplicates) { 0099 listOfKeywords.removeDuplicates(); 0100 } 0101 return listOfKeywords; 0102 } 0103 0104 MenuItem *MenuItem::parent() const 0105 { 0106 return d->parent; 0107 } 0108 0109 QList<MenuItem *> &MenuItem::children() const 0110 { 0111 return d->children; 0112 } 0113 0114 QString MenuItem::comment() const 0115 { 0116 return d->comment; 0117 } 0118 0119 QString MenuItem::iconName() const 0120 { 0121 return d->iconName; 0122 } 0123 0124 bool MenuItem::isExternalAppModule() const 0125 { 0126 return d->isExternalAppModule; 0127 } 0128 0129 bool MenuItem::isSystemsettingsCategory() const 0130 { 0131 return d->isSystemsettingsCategory; 0132 } 0133 0134 QString MenuItem::systemsettingsCategoryModule() const 0135 { 0136 return d->systemsettingsCategoryModule; 0137 } 0138 0139 bool MenuItem::isSystemsettingsRootCategory() const 0140 { 0141 return d->isSystemsettingsRootCategory; 0142 } 0143 0144 QString &MenuItem::name() const 0145 { 0146 return d->name; 0147 } 0148 0149 QString &MenuItem::category() const 0150 { 0151 return d->category; 0152 } 0153 0154 int MenuItem::weight() 0155 { 0156 return d->weight; 0157 } 0158 0159 bool MenuItem::menu() const 0160 { 0161 return d->menu; 0162 } 0163 0164 void MenuItem::setCategoryConfig(const KDesktopFile &file) 0165 { 0166 const KConfigGroup grp = file.desktopGroup(); 0167 d->category = grp.readEntry("X-KDE-System-Settings-Category"); 0168 if (d->category.isEmpty()) { 0169 d->category = grp.readEntry("X-KDE-KInfoCenter-Category"); 0170 } 0171 d->name = grp.readEntry("Name"); 0172 d->weight = grp.readEntry(QStringLiteral("X-KDE-Weight"), 100); 0173 d->comment = grp.readEntry("Comment"); 0174 d->iconName = grp.readEntry("Icon"); 0175 d->isSystemsettingsCategory = true; 0176 d->systemsettingsCategoryModule = grp.readEntry("X-KDE-System-Settings-Category-Module"); 0177 d->isSystemsettingsRootCategory = QFileInfo(file.fileName()).fileName() == QLatin1String("settings-root-category.desktop"); 0178 } 0179 0180 void MenuItem::setMetaData(const KPluginMetaData &data) 0181 { 0182 d->metaData = data; 0183 if (d->isSystemsettingsCategory) { 0184 return; 0185 } 0186 d->category = data.value(QStringLiteral("X-KDE-System-Settings-Category")); 0187 if (d->category.isEmpty()) { 0188 d->category = data.value(QStringLiteral("X-KDE-KInfoCenter-Category")); 0189 } 0190 d->name = data.name(); 0191 d->weight = data.value(QStringLiteral("X-KDE-Weight"), 100); 0192 d->comment = data.description(); 0193 d->iconName = data.iconName(); 0194 d->systemsettingsCategoryModule = data.value(QStringLiteral("X-KDE-System-Settings-Category-Module")); 0195 d->isExternalAppModule = data.value(QStringLiteral("IsExternalApp"), false); 0196 } 0197 0198 KPluginMetaData MenuItem::metaData() 0199 { 0200 return d->metaData; 0201 } 0202 0203 bool MenuItem::showDefaultIndicator() const 0204 { 0205 return d->showDefaultIndicator; 0206 } 0207 0208 bool MenuItem::isCategoryOwner() const 0209 { 0210 return d->isCategoryOwner; 0211 } 0212 0213 void MenuItem::setCategoryOwner(bool owner) 0214 { 0215 d->isCategoryOwner = owner; 0216 } 0217 0218 void MenuItem::updateDefaultIndicator() 0219 { 0220 d->showDefaultIndicator = false; 0221 if (isLibrary()) { 0222 std::unique_ptr<KCModuleData> moduleData(loadModuleData(d->metaData)); 0223 d->showDefaultIndicator = moduleData && !moduleData->isDefaults(); 0224 } 0225 0226 if (menu()) { 0227 for (auto child : std::as_const(children())) { 0228 d->showDefaultIndicator |= child->showDefaultIndicator(); 0229 } 0230 } 0231 if (d->parent) { 0232 d->parent->updateDefaultIndicator(); 0233 } 0234 } 0235 0236 void MenuItem::setDefaultIndicator(bool defaultIndicator) 0237 { 0238 d->showDefaultIndicator = defaultIndicator; 0239 if (menu()) { 0240 for (auto child : std::as_const(children())) { 0241 d->showDefaultIndicator |= child->showDefaultIndicator(); 0242 } 0243 } 0244 if (d->parent) { 0245 d->parent->updateDefaultIndicator(); 0246 } 0247 } 0248 0249 MenuItem *MenuItem::descendantForModule(const QString &moduleName) 0250 { 0251 if (d->service) { 0252 if (d->service->desktopEntryName() == moduleName) { 0253 return this; 0254 } 0255 } 0256 0257 if (d->metaData.isValid() && d->metaData.pluginId() == moduleName) { 0258 return this; 0259 } 0260 0261 for (auto child : std::as_const(d->children)) { 0262 MenuItem *candidate = child->descendantForModule(moduleName); 0263 if (candidate) { 0264 return candidate; 0265 } 0266 } 0267 0268 return nullptr; 0269 } 0270 0271 bool MenuItem::isLibrary() 0272 { 0273 return d->metaData.isValid() && !isExternalAppModule(); 0274 }