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