Changeset View
Changeset View
Standalone View
Standalone View
Modules/about-distro/src/Module.cpp
1 | /* | 1 | /* | ||
---|---|---|---|---|---|
2 | Copyright (C) 2012-2014 Harald Sitter <apachelogger@ubuntu.com> | 2 | Copyright (C) 2012-2020 Harald Sitter <sitter@kde.org> | ||
3 | 3 | | |||
4 | This program is free software; you can redistribute it and/or | 4 | This program is free software; you can redistribute it and/or | ||
5 | modify it under the terms of the GNU General Public License as | 5 | modify it under the terms of the GNU General Public License as | ||
6 | published by the Free Software Foundation; either version 2 of | 6 | published by the Free Software Foundation; either version 2 of | ||
7 | the License or (at your option) version 3 or any later version | 7 | the License or (at your option) version 3 or any later version | ||
8 | accepted by the membership of KDE e.V. (or its successor approved | 8 | accepted by the membership of KDE e.V. (or its successor approved | ||
9 | by the membership of KDE e.V.), which shall act as a proxy | 9 | by the membership of KDE e.V.), which shall act as a proxy | ||
10 | defined in Section 14 of version 3 of the license. | 10 | defined in Section 14 of version 3 of the license. | ||
Show All 33 Lines | |||||
44 | #elif defined(Q_OS_FREEBSD) | 44 | #elif defined(Q_OS_FREEBSD) | ||
45 | #include <sys/types.h> | 45 | #include <sys/types.h> | ||
46 | #include <sys/sysctl.h> | 46 | #include <sys/sysctl.h> | ||
47 | #endif | 47 | #endif | ||
48 | #include <sys/utsname.h> | 48 | #include <sys/utsname.h> | ||
49 | 49 | | |||
50 | #include "Version.h" | 50 | #include "Version.h" | ||
51 | 51 | | |||
52 | // Generic dumpable info entry. | ||||
53 | // This encapsulates a table entry so that it may be put into the UI | ||||
54 | // and also serialized into textual form for copy to clipboard. | ||||
55 | // All entries that are meant to be serializable should derive from this! | ||||
56 | // This class may either be subclassed or used as-is if label/value are trivial | ||||
57 | // to obtain. | ||||
58 | class Entry | ||||
59 | { | ||||
60 | public: | ||||
61 | enum class Language { | ||||
62 | System, | ||||
63 | English | ||||
64 | }; | ||||
65 | | ||||
66 | Entry(const KLocalizedString &label_, const QString &value_) | ||||
67 | : label(label_) | ||||
68 | , value(value_) | ||||
69 | { | ||||
70 | Q_ASSERT(label.isEmpty() || localizedLabel(Language::English).endsWith(':')); | ||||
71 | } | ||||
72 | | ||||
73 | ~Entry() = default; | ||||
74 | | ||||
75 | // When false this entry is garbage (e.g. incomplete data) and shouldn't be rendered. | ||||
76 | bool isValid() const | ||||
77 | { | ||||
78 | return !label.toString().isEmpty() && !value.isEmpty(); | ||||
79 | } | ||||
80 | | ||||
81 | // Returns textual representation of entry. | ||||
82 | QString diagnosticLine(Language language = Language::System) const | ||||
83 | { | ||||
84 | // FIXME: This isn't really working for right-to-left | ||||
85 | // The answer probably is in uncide control characters, but | ||||
86 | // didn't work when tried. | ||||
87 | // Essentially what needs to happen is that the label should be RTL | ||||
88 | // that is to say the colon should be on the left, BUT englishy words | ||||
89 | // within that should be LTR, everything besides the label should be LTR | ||||
90 | // because we do not localize the values I don't think? | ||||
91 | return localizedLabel(language) + ' ' + value + '\n'; | ||||
92 | } | ||||
93 | | ||||
94 | // Descriptive label | ||||
95 | KLocalizedString label; | ||||
96 | // Value of the entry (e.g. the version of plasma) | ||||
97 | QString value; | ||||
98 | | ||||
99 | private: | ||||
100 | QString localizedLabel(Language language) const | ||||
101 | { | ||||
102 | switch (language) { | ||||
103 | case Language::System: | ||||
104 | return label.toString(); | ||||
105 | case Language::English: | ||||
106 | // https://bugs.kde.org/show_bug.cgi?id=416247 | ||||
107 | return label.toString(QStringList { QStringLiteral("en_US") }); | ||||
108 | } | ||||
109 | Q_UNREACHABLE(); | ||||
110 | return QStringLiteral("Unknown Label Language %1 (bug in KInfocenter!):").arg( | ||||
111 | QString::number(static_cast<int>(language))); | ||||
112 | } | ||||
113 | }; | ||||
114 | | ||||
115 | class PlasmaEntry : public Entry | ||||
116 | { | ||||
117 | public: | ||||
118 | PlasmaEntry() : Entry(ki18n("KDE Plasma Version:"), plasmaVersion()) | ||||
119 | { | ||||
120 | // Since Plasma version detection isn't based on a library query it can fail | ||||
121 | // in weird cases; instead of admitting defeat we simply hide everything :P | ||||
122 | if (value.isEmpty()) { | ||||
123 | return; | ||||
124 | } | ||||
125 | } | ||||
126 | | ||||
127 | static QString plasmaVersion() | ||||
128 | { | ||||
129 | const QStringList &filePaths = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, | ||||
130 | QStringLiteral("xsessions/plasma.desktop")); | ||||
131 | | ||||
132 | if (filePaths.length() < 1) { | ||||
133 | return QString(); | ||||
134 | } | ||||
135 | | ||||
136 | // Despite the fact that there can be multiple desktop files we simply take | ||||
137 | // the first one as users usually don't have xsessions/ in their $HOME | ||||
138 | // data location, so the first match should (usually) be the only one and | ||||
139 | // reflect the plasma session run. | ||||
140 | KDesktopFile desktopFile(filePaths.first()); | ||||
141 | return desktopFile.desktopGroup().readEntry("X-KDE-PluginInfo-Version", QString()); | ||||
142 | } | ||||
143 | }; | ||||
144 | | ||||
145 | class KernelEntry : public Entry | ||||
146 | { | ||||
147 | public: | ||||
148 | KernelEntry() : Entry(ki18n("Kernel Version:"), kernelVersion()) | ||||
149 | { | ||||
150 | } | ||||
151 | | ||||
152 | static QString kernelVersion() | ||||
153 | { | ||||
154 | struct utsname utsName; | ||||
155 | if (uname(&utsName) == 0) { | ||||
156 | return QString::fromLatin1(utsName.release); | ||||
157 | } | ||||
158 | return QString(); | ||||
159 | } | ||||
160 | }; | ||||
161 | | ||||
162 | class BitEntry : public Entry | ||||
163 | { | ||||
164 | public: | ||||
165 | BitEntry() : Entry(ki18n("OS Type:"), bitString()) | ||||
166 | { | ||||
167 | } | ||||
168 | | ||||
169 | static QString bitString() | ||||
170 | { | ||||
171 | const int bits = QT_POINTER_SIZE == 8 ? 64 : 32; | ||||
172 | return i18nc("@label %1 is the CPU bit width (e.g. 32 or 64)", | ||||
173 | "%1-bit", QString::number(bits)); | ||||
174 | } | ||||
175 | }; | ||||
176 | | ||||
177 | class CPUEntry : public Entry | ||||
178 | { | ||||
179 | public: | ||||
180 | CPUEntry() : Entry(KLocalizedString(), QString()) | ||||
181 | { | ||||
182 | const QList<Solid::Device> list = Solid::Device::listFromType(Solid::DeviceInterface::Processor); | ||||
183 | | ||||
184 | label = ki18np("Processor:", "Processors:").subs(list.count()); | ||||
185 | | ||||
186 | // Format processor string | ||||
187 | // Group by processor name | ||||
188 | QMap<QString, int> processorMap; | ||||
189 | for (const Solid::Device &device : list) { | ||||
190 | const QString name = device.product(); | ||||
191 | auto it = processorMap.find(name); | ||||
192 | if (it == processorMap.end()) { | ||||
193 | processorMap.insert(name, 1); | ||||
194 | } else { | ||||
195 | ++it.value(); | ||||
196 | } | ||||
197 | } | ||||
198 | // Create a formatted list of grouped processors | ||||
199 | QStringList names; | ||||
200 | names.reserve(processorMap.count()); | ||||
201 | for (auto it = processorMap.constBegin(); it != processorMap.constEnd(); ++it) { | ||||
202 | const int count = it.value(); | ||||
203 | QString name = it.key(); | ||||
204 | name.replace(QStringLiteral("(TM)"), QChar(8482)); | ||||
205 | name.replace(QStringLiteral("(R)"), QChar(174)); | ||||
206 | name = name.simplified(); | ||||
207 | names.append(QStringLiteral("%1 × %2").arg(count).arg(name)); | ||||
208 | } | ||||
209 | | ||||
210 | value = names.join(QLatin1String(", ")); | ||||
211 | } | ||||
212 | }; | ||||
213 | | ||||
214 | class MemoryEntry : public Entry | ||||
215 | { | ||||
216 | public: | ||||
217 | MemoryEntry() : Entry(ki18n("Memory:"), text()) | ||||
218 | { | ||||
219 | } | ||||
220 | | ||||
52 | static qlonglong calculateTotalRam() | 221 | static qlonglong calculateTotalRam() | ||
53 | { | 222 | { | ||
54 | qlonglong ret = -1; | 223 | qlonglong ret = -1; | ||
55 | #ifdef Q_OS_LINUX | 224 | #ifdef Q_OS_LINUX | ||
56 | struct sysinfo info; | 225 | struct sysinfo info; | ||
57 | if (sysinfo(&info) == 0) | 226 | if (sysinfo(&info) == 0) | ||
58 | // manpage "sizes are given as multiples of mem_unit bytes" | 227 | // manpage "sizes are given as multiples of mem_unit bytes" | ||
59 | ret = qlonglong(info.totalram) * info.mem_unit; | 228 | ret = qlonglong(info.totalram) * info.mem_unit; | ||
60 | #elif defined(Q_OS_FREEBSD) | 229 | #elif defined(Q_OS_FREEBSD) | ||
61 | /* Stuff for sysctl */ | 230 | /* Stuff for sysctl */ | ||
62 | size_t len; | 231 | size_t len; | ||
63 | 232 | | |||
64 | unsigned long memory; | 233 | unsigned long memory; | ||
65 | len = sizeof(memory); | 234 | len = sizeof(memory); | ||
66 | sysctlbyname("hw.physmem", &memory, &len, NULL, 0); | 235 | sysctlbyname("hw.physmem", &memory, &len, NULL, 0); | ||
67 | 236 | | |||
68 | ret = memory; | 237 | ret = memory; | ||
69 | #endif | 238 | #endif | ||
70 | return ret; | 239 | return ret; | ||
71 | } | 240 | } | ||
72 | 241 | | |||
242 | static QString text() | ||||
243 | { | ||||
244 | const qlonglong totalRam = calculateTotalRam(); | ||||
245 | if (totalRam > 0) { | ||||
246 | return i18nc("@label %1 is the formatted amount of system memory (e.g. 7,7 GiB)", | ||||
247 | "%1 of RAM", KFormat().formatByteSize(totalRam)); | ||||
248 | } | ||||
249 | return i18nc("Unknown amount of RAM", "Unknown"); | ||||
250 | } | ||||
251 | }; | ||||
252 | | ||||
253 | // Label with font styling for section heading such as 'Software' | ||||
254 | class SectionLabel : public QLabel | ||||
255 | { | ||||
256 | public: | ||||
257 | explicit SectionLabel(const QString &text, QWidget *parent = nullptr) | ||||
258 | : QLabel(text, parent) | ||||
259 | { | ||||
260 | QFont font; | ||||
261 | font.setBold(true); | ||||
262 | font.setWeight(75); | ||||
263 | setFont(font); | ||||
264 | } | ||||
265 | }; | ||||
266 | | ||||
73 | Module::Module(QWidget *parent, const QVariantList &args) : | 267 | Module::Module(QWidget *parent, const QVariantList &args) : | ||
74 | KCModule(parent, args), | 268 | KCModule(parent, args), | ||
75 | ui(new Ui::Module) | 269 | ui(new Ui::Module) | ||
76 | { | 270 | { | ||
77 | KAboutData *aboutData = new KAboutData(QStringLiteral("kcm-about-distro"), | 271 | KAboutData *aboutData = new KAboutData(QStringLiteral("kcm-about-distro"), | ||
78 | i18nc("@title", "About Distribution"), | 272 | i18nc("@title", "About System"), | ||
79 | QString::fromLatin1(global_s_versionStringFull), | 273 | QString::fromLatin1(global_s_versionStringFull), | ||
80 | QString(), | 274 | QString(), | ||
81 | KAboutLicense::LicenseKey::GPL_V3, | 275 | KAboutLicense::LicenseKey::GPL_V3, | ||
82 | i18nc("@info:credit", "Copyright 2012-2014 Harald Sitter")); | 276 | i18nc("@info:credit", "Copyright 2012-2020 Harald Sitter")); | ||
83 | 277 | | |||
84 | aboutData->addAuthor(i18nc("@info:credit", "Harald Sitter"), | 278 | aboutData->addAuthor(i18nc("@info:credit", "Harald Sitter"), | ||
85 | i18nc("@info:credit", "Author"), | 279 | i18nc("@info:credit", "Author"), | ||
86 | QStringLiteral("apachelogger@kubuntu.org")); | 280 | QStringLiteral("sitter@kde.org")); | ||
87 | 281 | | |||
88 | setAboutData(aboutData); | 282 | setAboutData(aboutData); | ||
89 | 283 | | |||
90 | ui->setupUi(this); | 284 | ui->setupUi(this); | ||
91 | 285 | | |||
92 | QFont font = ui->nameVersionLabel->font(); | 286 | QFont font = ui->nameVersionLabel->font(); | ||
93 | font.setPixelSize(24); | 287 | font.setPixelSize(24); | ||
94 | font.setBold(true); | 288 | font.setBold(true); | ||
Show All 26 Lines | |||||
121 | 315 | | |||
122 | Module::~Module() | 316 | Module::~Module() | ||
123 | { | 317 | { | ||
124 | delete ui; | 318 | delete ui; | ||
125 | } | 319 | } | ||
126 | 320 | | |||
127 | void Module::load() | 321 | void Module::load() | ||
128 | { | 322 | { | ||
129 | labelsForClipboard.clear(); | 323 | // load is called lazly, but also from the ctor -> prevent double init. | ||
130 | englishTextForClipboard = QStringLiteral(""); | 324 | static bool initd = false; | ||
131 | loadSoftware(); | 325 | if (initd) { | ||
132 | loadHardware(); | 326 | return; | ||
327 | } | ||||
328 | initd = true; | ||||
329 | | ||||
330 | loadOSData(); | ||||
331 | loadEntries(); | ||||
133 | } | 332 | } | ||
134 | 333 | | |||
135 | void Module::save() | 334 | void Module::save() | ||
136 | { | 335 | { | ||
137 | } | 336 | } | ||
138 | 337 | | |||
139 | void Module::defaults() | 338 | void Module::defaults() | ||
140 | { | 339 | { | ||
141 | } | 340 | } | ||
142 | 341 | | |||
143 | void Module::loadSoftware() | 342 | void Module::loadOSData() | ||
144 | { | 343 | { | ||
145 | // NOTE: do not include globals, otherwise kdeglobals could provide values | 344 | // NOTE: do not include globals, otherwise kdeglobals could provide values | ||
146 | // even though we only explicitly want them from our own config. | 345 | // even though we only explicitly want them from our own config. | ||
147 | KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("kcm-about-distrorc"), | 346 | KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("kcm-about-distrorc"), | ||
148 | KConfig::NoGlobals); | 347 | KConfig::NoGlobals); | ||
149 | KConfigGroup cg = KConfigGroup(config, "General"); | 348 | KConfigGroup cg = KConfigGroup(config, "General"); | ||
150 | 349 | | |||
151 | KOSRelease os; | 350 | KOSRelease os; | ||
Show All 11 Lines | |||||
163 | const QString distroName = cg.readEntry("Name", os.name()); | 362 | const QString distroName = cg.readEntry("Name", os.name()); | ||
164 | const QString osrVersion = cg.readEntry("UseOSReleaseVersion", false) | 363 | const QString osrVersion = cg.readEntry("UseOSReleaseVersion", false) | ||
165 | ? os.version() | 364 | ? os.version() | ||
166 | : os.versionId(); | 365 | : os.versionId(); | ||
167 | const QString versionId = cg.readEntry("Version", osrVersion); | 366 | const QString versionId = cg.readEntry("Version", osrVersion); | ||
168 | const QString distroNameVersion = QStringLiteral("%1 %2").arg(distroName, versionId); | 367 | const QString distroNameVersion = QStringLiteral("%1 %2").arg(distroName, versionId); | ||
169 | ui->nameVersionLabel->setText(distroNameVersion); | 368 | ui->nameVersionLabel->setText(distroNameVersion); | ||
170 | 369 | | |||
171 | const auto dummyDistroDescriptionLabel = new QLabel(i18nc("@title:row", "Operating System:"), this); | 370 | // Insert a dummy entry for debug info dumps. | ||
172 | dummyDistroDescriptionLabel->hide(); | 371 | m_entries.push_back(new Entry(ki18n("Operating System:"), distroNameVersion)); | ||
173 | labelsForClipboard << qMakePair(dummyDistroDescriptionLabel, ui->nameVersionLabel); | | |||
174 | englishTextForClipboard += QStringLiteral("Operating System: %1\n").arg(distroNameVersion); | | |||
175 | 372 | | |||
176 | const QString variant = cg.readEntry("Variant", os.variant()); | 373 | const QString variant = cg.readEntry("Variant", os.variant()); | ||
177 | if (variant.isEmpty()) { | 374 | if (variant.isEmpty()) { | ||
178 | ui->variantLabel->hide(); | 375 | ui->variantLabel->hide(); | ||
179 | } else { | 376 | } else { | ||
180 | ui->variantLabel->setText(variant); | 377 | ui->variantLabel->setText(variant); | ||
181 | } | 378 | } | ||
182 | 379 | | |||
183 | const QString url = cg.readEntry("Website", os.homeUrl()); | 380 | const QString url = cg.readEntry("Website", os.homeUrl()); | ||
184 | if (url.isEmpty()) { | 381 | if (url.isEmpty()) { | ||
185 | ui->urlLabel->hide(); | 382 | ui->urlLabel->hide(); | ||
186 | } else { | 383 | } else { | ||
187 | ui->urlLabel->setText(QStringLiteral("<a href='%1'>%1</a>").arg(url)); | 384 | ui->urlLabel->setText(QStringLiteral("<a href='%1'>%1</a>").arg(url)); | ||
188 | } | 385 | } | ||
189 | | ||||
190 | // Since Plasma version detection isn't based on a library query it can fail | | |||
191 | // in weird cases; instead of admitting defeat we simply hide everything :P | | |||
192 | const QString plasma = plasmaVersion(); | | |||
193 | if (plasma.isEmpty()) { | | |||
194 | ui->plasma->hide(); | | |||
195 | ui->plasmaLabel->hide(); | | |||
196 | } else { | | |||
197 | ui->plasmaLabel->setText(plasma); | | |||
198 | labelsForClipboard << qMakePair(ui->plasma, ui->plasmaLabel); | | |||
199 | englishTextForClipboard += QStringLiteral("KDE Plasma Version: %1\n").arg(plasma); | | |||
200 | } | | |||
201 | | ||||
202 | const QString frameworksVersion = KCoreAddons::versionString(); | | |||
203 | ui->frameworksLabel->setText(frameworksVersion); | | |||
204 | labelsForClipboard << qMakePair(ui->frameworksLabelKey, ui->frameworksLabel); | | |||
205 | englishTextForClipboard += QStringLiteral("KDE Frameworks Version: %1\n").arg(frameworksVersion); | | |||
206 | | ||||
207 | const QString qversion = QString::fromLatin1(qVersion()); | | |||
208 | ui->qtLabel->setText(qversion); | | |||
209 | labelsForClipboard << qMakePair(ui->qt, ui->qtLabel); | | |||
210 | englishTextForClipboard += QStringLiteral("Qt Version: %1\n").arg(qversion); | | |||
211 | } | 386 | } | ||
212 | 387 | | |||
213 | void Module::loadHardware() | 388 | void Module::loadEntries() | ||
214 | { | 389 | { | ||
215 | struct utsname utsName; | 390 | auto addSectionHeader = [this](const QString &text) | ||
216 | if(uname(&utsName) != 0) { | 391 | { | ||
217 | ui->kernel->hide(); | 392 | int row = ui->infoGrid->rowCount(); | ||
218 | ui->kernelLabel->hide(); | 393 | // Random sizes stolen from original UI file values :S | ||
219 | } else { | 394 | ui->infoGrid->addItem(new QSpacerItem(17, 21, QSizePolicy::Minimum, QSizePolicy::Fixed), row, 1, 1, 1); | ||
220 | QString kernelVersion = QString::fromLatin1(utsName.release); | 395 | ++row; | ||
221 | ui->kernelLabel->setText(kernelVersion); | 396 | ui->infoGrid->addWidget(new SectionLabel(text), row, 1, Qt::AlignLeft); | ||
222 | labelsForClipboard << qMakePair(ui->kernel, ui->kernelLabel); | 397 | ++row; | ||
223 | englishTextForClipboard += QStringLiteral("Kernel Version: %1\n").arg(kernelVersion); | 398 | }; | ||
224 | } | 399 | | ||
225 | 400 | auto addEntriesToGrid = [this](std::vector<const Entry *> entries) | |||
226 | const int bits = QT_POINTER_SIZE == 8 ? 64 : 32; | 401 | { | ||
227 | const QString bitsStr = QString::number(bits); | 402 | int row = ui->infoGrid->rowCount(); | ||
228 | ui->bitsLabel->setText(i18nc("@label %1 is the CPU bit width (e.g. 32 or 64)", | 403 | for (auto entry : entries) { | ||
229 | "%1-bit", bitsStr)); | 404 | if (!entry->isValid()) { | ||
230 | labelsForClipboard << qMakePair(ui->bitsKey, ui->bitsLabel); | 405 | continue; | ||
231 | englishTextForClipboard += QStringLiteral("OS Type: %1-bit\n").arg(bitsStr); | 406 | } | ||
232 | 407 | ui->infoGrid->addWidget(new QLabel(entry->label.toString()), row, 0, Qt::AlignRight); | |||
233 | const QList<Solid::Device> list = Solid::Device::listFromType(Solid::DeviceInterface::Processor); | 408 | ui->infoGrid->addWidget(new QLabel(entry->value), row, 1, Qt::AlignLeft); | ||
234 | ui->processor->setText(i18np("Processor:", "Processors:", list.count())); | 409 | m_entries.push_back(entry); | ||
235 | // Format processor string | 410 | ++row; | ||
236 | // Group by processor name | 411 | } | ||
237 | QMap<QString, int> processorMap; | 412 | }; | ||
238 | Q_FOREACH(const Solid::Device &device, list) { | 413 | | ||
239 | const QString name = device.product(); | 414 | // software | ||
240 | auto it = processorMap.find(name); | 415 | addSectionHeader(i18nc("@title:group", "Software")); | ||
241 | if (it == processorMap.end()) { | 416 | addEntriesToGrid({ | ||
242 | processorMap.insert(name, 1); | 417 | new PlasmaEntry(), | ||
243 | } else { | 418 | new Entry(ki18n("KDE Frameworks Version:"), KCoreAddons::versionString()), | ||
244 | ++it.value(); | 419 | new Entry(ki18n("Qt Version:"), QString::fromLatin1(qVersion())), | ||
245 | } | 420 | new KernelEntry(), | ||
246 | } | 421 | new BitEntry() | ||
247 | // Create a formatted list of grouped processors | 422 | }); | ||
248 | QStringList names; | 423 | | ||
249 | names.reserve(processorMap.count()); | 424 | // hardware | ||
250 | for (auto it = processorMap.constBegin(); it != processorMap.constEnd(); ++it) { | 425 | addSectionHeader(i18nc("@title:group", "Hardware")); | ||
251 | const int count = it.value(); | 426 | addEntriesToGrid({ | ||
252 | QString name = it.key(); | 427 | new CPUEntry(), | ||
253 | name.replace(QStringLiteral("(TM)"), QChar(8482)); | 428 | new MemoryEntry() | ||
254 | name.replace(QStringLiteral("(R)"), QChar(174)); | 429 | }); | ||
255 | name = name.simplified(); | | |||
256 | names.append(QStringLiteral("%1 × %2").arg(count).arg(name)); | | |||
257 | } | | |||
258 | | ||||
259 | const QString processorLabel = names.join(QLatin1String(", ")); | | |||
260 | ui->processorLabel->setText(processorLabel); | | |||
261 | if (ui->processorLabel->text().isEmpty()) { | | |||
262 | ui->processor->setHidden(true); | | |||
263 | ui->processorLabel->setHidden(true); | | |||
264 | } else { | | |||
265 | labelsForClipboard << qMakePair(ui->processor, ui->processorLabel); | | |||
266 | englishTextForClipboard += QStringLiteral("Processors: %1\n").arg(processorLabel); | | |||
267 | } | | |||
268 | | ||||
269 | const qlonglong totalRam = calculateTotalRam(); | | |||
270 | const QString memoryLabel = totalRam > 0 | | |||
271 | ? i18nc("@label %1 is the formatted amount of system memory (e.g. 7,7 GiB)", | | |||
272 | "%1 of RAM", KFormat().formatByteSize(totalRam)) | | |||
273 | : i18nc("Unknown amount of RAM", "Unknown"); | | |||
274 | ui->memoryLabel->setText(memoryLabel); | | |||
275 | labelsForClipboard << qMakePair(ui->memory, ui->memoryLabel); | | |||
276 | englishTextForClipboard += QStringLiteral("Memory: %1\n").arg(KFormat().formatByteSize(totalRam)); | | |||
277 | } | 430 | } | ||
278 | 431 | | |||
279 | void Module::copyToClipboard() | 432 | void Module::copyToClipboard() | ||
280 | { | 433 | { | ||
281 | QString text; | 434 | QString text; | ||
282 | // note that this loop does not necessarily represent the same order as in the GUI | 435 | for (auto entry : m_entries) { | ||
283 | for (auto labelPair : qAsConst(labelsForClipboard)) { | 436 | text += entry->diagnosticLine(Entry::Language::System); | ||
284 | const auto valueLabel = labelPair.second; | | |||
285 | if (!valueLabel->isHidden()) { | | |||
286 | const auto descriptionLabelText = labelPair.first->text(); | | |||
287 | const auto valueLabelText = valueLabel->text(); | | |||
288 | text += i18nc("%1 is a label already including a colon, %2 is the corresponding value", "%1 %2", descriptionLabelText, valueLabelText) + QStringLiteral("\n"); | | |||
289 | } | | |||
290 | } | 437 | } | ||
291 | | ||||
292 | QGuiApplication::clipboard()->setText(text); | 438 | QGuiApplication::clipboard()->setText(text); | ||
293 | } | 439 | } | ||
294 | 440 | | |||
295 | void Module::copyToClipboardInEnglish() | 441 | void Module::copyToClipboardInEnglish() | ||
296 | { | 442 | { | ||
297 | QGuiApplication::clipboard()->setText(englishTextForClipboard); | 443 | QString text; | ||
298 | } | 444 | for (auto entry : m_entries) { | ||
299 | 445 | text += entry->diagnosticLine(Entry::Language::English); | |||
300 | QString Module::plasmaVersion() const | | |||
301 | { | | |||
302 | const QStringList &filePaths = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, | | |||
303 | QStringLiteral("xsessions/plasma.desktop")); | | |||
304 | | ||||
305 | if (filePaths.length() < 1) { | | |||
306 | return QString(); | | |||
307 | } | 446 | } | ||
308 | 447 | QGuiApplication::clipboard()->setText(text); | |||
309 | // Despite the fact that there can be multiple desktop files we simply take | | |||
310 | // the first one as users usually don't have xsessions/ in their $HOME | | |||
311 | // data location, so the first match should (usually) be the only one and | | |||
312 | // reflect the plasma session run. | | |||
313 | KDesktopFile desktopFile(filePaths.first()); | | |||
314 | return desktopFile.desktopGroup().readEntry("X-KDE-PluginInfo-Version", QString()); | | |||
315 | } | 448 | } |