File indexing completed on 2025-07-13 05:02:37
0001 /* 0002 SPDX-FileCopyrightText: 2020 Kai Uwe Broulik <kde@broulik.de> 0003 0004 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "modulesmodel.h" 0008 0009 #include <QCollator> 0010 0011 #include <KConfig> 0012 #include <KConfigGroup> 0013 0014 #include <algorithm> 0015 0016 #include "debug.h" 0017 0018 ModulesModel::ModulesModel(QObject *parent) 0019 : QAbstractListModel(parent) 0020 { 0021 } 0022 0023 ModulesModel::~ModulesModel() = default; 0024 0025 int ModulesModel::rowCount(const QModelIndex &parent) const 0026 { 0027 if (parent.isValid()) { 0028 return 0; 0029 } 0030 0031 return m_data.count(); 0032 } 0033 0034 QVariant ModulesModel::data(const QModelIndex &index, int role) const 0035 { 0036 if (!checkIndex(index)) { 0037 return QVariant(); 0038 } 0039 0040 const auto &item = m_data.at(index.row()); 0041 0042 switch (role) { 0043 case Qt::DisplayRole: 0044 return item.display; 0045 case DescriptionRole: 0046 return item.description; 0047 case TypeRole: 0048 return item.type; 0049 case AutoloadEnabledRole: 0050 if (item.type == KDEDConfig::AutostartType) { 0051 return item.autoloadEnabled; 0052 } 0053 return QVariant(); 0054 case StatusRole: { 0055 if (!m_runningModulesKnown) { 0056 return KDEDConfig::UnknownStatus; 0057 } 0058 if (m_runningModules.contains(item.moduleName)) { 0059 return KDEDConfig::Running; 0060 } 0061 return KDEDConfig::NotRunning; 0062 } 0063 case ModuleNameRole: 0064 return item.moduleName; 0065 case ImmutableRole: 0066 return item.immutable; 0067 } 0068 0069 return QVariant(); 0070 } 0071 0072 bool ModulesModel::representsDefault() const 0073 { 0074 bool isDefault = true; 0075 for (int i = 0; i < m_data.count(); ++i) { 0076 auto &item = m_data[i]; 0077 if (item.type != KDEDConfig::AutostartType || item.immutable) { 0078 continue; 0079 } 0080 isDefault &= item.autoloadEnabled; 0081 } 0082 return isDefault; 0083 } 0084 0085 bool ModulesModel::needsSave() const 0086 { 0087 bool save = false; 0088 for (int i = 0; i < m_data.count(); ++i) { 0089 auto &item = m_data[i]; 0090 if (item.type != KDEDConfig::AutostartType || item.immutable) { 0091 continue; 0092 } 0093 save |= item.autoloadEnabled != item.savedAutoloadEnabled; 0094 } 0095 return save; 0096 } 0097 0098 bool ModulesModel::setData(const QModelIndex &index, const QVariant &value, int role) 0099 { 0100 bool dirty = false; 0101 0102 if (!checkIndex(index)) { 0103 return dirty; 0104 } 0105 0106 auto &item = m_data[index.row()]; 0107 0108 if (item.type != KDEDConfig::AutostartType || item.immutable) { 0109 return dirty; 0110 } 0111 0112 switch (role) { 0113 case AutoloadEnabledRole: { 0114 const bool autoloadEnabled = value.toBool(); 0115 if (item.autoloadEnabled != autoloadEnabled) { 0116 item.autoloadEnabled = autoloadEnabled; 0117 dirty = true; 0118 } 0119 Q_EMIT autoloadedModulesChanged(); 0120 break; 0121 } 0122 } 0123 0124 if (dirty) { 0125 Q_EMIT dataChanged(index, index, {role}); 0126 } 0127 0128 return dirty; 0129 } 0130 0131 QHash<int, QByteArray> ModulesModel::roleNames() const 0132 { 0133 return { 0134 {Qt::DisplayRole, QByteArrayLiteral("display")}, 0135 {DescriptionRole, QByteArrayLiteral("description")}, 0136 {TypeRole, QByteArrayLiteral("type")}, 0137 {AutoloadEnabledRole, QByteArrayLiteral("autoloadEnabled")}, 0138 {StatusRole, QByteArrayLiteral("status")}, 0139 {ModuleNameRole, QByteArrayLiteral("moduleName")}, 0140 {ImmutableRole, QByteArrayLiteral("immutable")}, 0141 }; 0142 } 0143 0144 void ModulesModel::load() 0145 { 0146 beginResetModel(); 0147 0148 m_data.clear(); 0149 0150 KConfig kdedrc(QStringLiteral("kded5rc"), KConfig::NoGlobals); 0151 0152 QStringList knownModules; 0153 0154 QList<ModulesModelData> autostartModules; 0155 QList<ModulesModelData> onDemandModules; 0156 0157 const auto modules = KPluginMetaData::findPlugins(QStringLiteral("kf6/kded")); 0158 for (const KPluginMetaData &module : modules) { 0159 QString servicePath = module.fileName(); 0160 0161 // autoload defaults to false if it is not found 0162 const bool autoload = module.value(QStringLiteral("X-KDE-Kded-autoload"), false); 0163 0164 // keep estimating dbusModuleName in sync with KDEDModule (kdbusaddons) and kded (kded) 0165 // currently (KF5) the module name in the D-Bus object path is set by the pluginId 0166 const QString dbusModuleName = module.pluginId(); 0167 qCDebug(KCM_KDED) << "reading kded info from" << servicePath << "autoload =" << autoload << "dbus module name =" << dbusModuleName; 0168 0169 if (knownModules.contains(dbusModuleName)) { 0170 continue; 0171 } 0172 0173 knownModules.append(dbusModuleName); 0174 0175 KConfigGroup cg(&kdedrc, QStringLiteral("Module-%1").arg(dbusModuleName)); 0176 const bool autoloadEnabled = cg.readEntry("autoload", true); 0177 const bool immutable = cg.isEntryImmutable("autoload"); 0178 0179 ModulesModelData data{module.name(), module.description(), KDEDConfig::UnknownType, autoloadEnabled, dbusModuleName, immutable, autoloadEnabled}; 0180 0181 // The logic has to be identical to Kded::initModules. 0182 // They interpret X-KDE-Kded-autoload as false if not specified 0183 // X-KDE-Kded-load-on-demand as true if not specified 0184 if (autoload) { 0185 data.type = KDEDConfig::AutostartType; 0186 autostartModules << data; 0187 } else if (module.value(QStringLiteral("X-KDE-Kded-load-on-demand"), false)) { 0188 data.type = KDEDConfig::OnDemandType; 0189 onDemandModules << data; 0190 } else { 0191 qCWarning(KCM_KDED) << "kcmkded: Module" << module.name() << "from file" << module.fileName() << "not loaded on demand or startup! Skipping."; 0192 continue; 0193 } 0194 } 0195 0196 QCollator collator; 0197 // Otherwise "Write" daemon with quotes will be at the top 0198 collator.setIgnorePunctuation(true); 0199 auto sortAlphabetically = [&collator](const ModulesModelData &a, const ModulesModelData &b) { 0200 return collator.compare(a.display, b.display) < 0; 0201 }; 0202 0203 std::sort(autostartModules.begin(), autostartModules.end(), sortAlphabetically); 0204 std::sort(onDemandModules.begin(), onDemandModules.end(), sortAlphabetically); 0205 0206 m_data << autostartModules << onDemandModules; 0207 0208 endResetModel(); 0209 } 0210 0211 bool ModulesModel::runningModulesKnown() const 0212 { 0213 return m_runningModulesKnown; 0214 } 0215 0216 void ModulesModel::setRunningModulesKnown(bool known) 0217 { 0218 if (m_runningModulesKnown != known) { 0219 m_runningModulesKnown = known; 0220 Q_EMIT dataChanged(index(0, 0), index(m_data.count() - 1, 0), {StatusRole}); 0221 } 0222 } 0223 0224 QStringList ModulesModel::runningModules() const 0225 { 0226 return m_runningModules; 0227 } 0228 0229 void ModulesModel::setRunningModules(const QStringList &runningModules) 0230 { 0231 if (m_runningModules == runningModules) { 0232 return; 0233 } 0234 0235 m_runningModules = runningModules; 0236 if (m_runningModulesKnown) { 0237 Q_EMIT dataChanged(index(0, 0), index(m_data.count() - 1, 0), {StatusRole}); 0238 } 0239 } 0240 0241 void ModulesModel::refreshAutoloadEnabledSavedState() 0242 { 0243 for (int i = 0; i < m_data.count(); ++i) { 0244 auto &item = m_data[i]; 0245 item.savedAutoloadEnabled = item.autoloadEnabled; 0246 } 0247 }