Warning, file /plasma/libksysguard/formatter/Formatter.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2019 Vlad Zahorodnii <vlad.zahorodnii@kde.org> 0003 0004 formatBootTimestamp is based on TimeUtil class: 0005 SPDX-FileCopyrightText: 2014 Gregor Mi <codestruct@posteo.org> 0006 0007 SPDX-License-Identifier: LGPL-2.0-or-later 0008 */ 0009 0010 #include "Formatter.h" 0011 0012 #include <KFormat> 0013 #include <KLocalizedString> 0014 0015 #include <QFontMetrics> 0016 #include <QLocale> 0017 #include <QTime> 0018 0019 #include <cmath> 0020 #include <ctime> 0021 0022 #include <time.h> 0023 #include <unistd.h> 0024 0025 #include "formatter_debug.h" 0026 0027 namespace KSysGuard 0028 { 0029 // TODO: Is there a bit nicer way to handle formatting? 0030 0031 static KLocalizedString unitFormat(Unit unit) 0032 { 0033 const static KLocalizedString B = ki18nc("Bytes unit symbol", "%1 B"); 0034 const static KLocalizedString KiB = ki18nc("Kilobytes unit symbol", "%1 KiB"); 0035 const static KLocalizedString MiB = ki18nc("Megabytes unit symbol", "%1 MiB"); 0036 const static KLocalizedString GiB = ki18nc("Gigabytes unit symbol", "%1 GiB"); 0037 const static KLocalizedString TiB = ki18nc("Terabytes unit symbol", "%1 TiB"); 0038 const static KLocalizedString PiB = ki18nc("Petabytes unit symbol", "%1 PiB"); 0039 0040 const static KLocalizedString bps = ki18nc("Bytes per second unit symbol", "%1 B/s"); 0041 const static KLocalizedString Kbps = ki18nc("Kilobytes per second unit symbol", "%1 KiB/s"); 0042 const static KLocalizedString Mbps = ki18nc("Megabytes per second unit symbol", "%1 MiB/s"); 0043 const static KLocalizedString Gbps = ki18nc("Gigabytes per second unit symbol", "%1 GiB/s"); 0044 const static KLocalizedString Tbps = ki18nc("Terabytes per second unit symbol", "%1 TiB/s"); 0045 const static KLocalizedString Pbps = ki18nc("Petabytes per second unit symbol", "%1 PiB/s"); 0046 0047 const static KLocalizedString bitsps = ki18nc("Bits per second unit symbol", "%1 bps"); 0048 const static KLocalizedString Kbitsps = ki18nc("Kilobits per second unit symbol", "%1 Kbps"); 0049 const static KLocalizedString Mbitsps = ki18nc("Megabits per second unit symbol", "%1 Mbps"); 0050 const static KLocalizedString Gbitsps = ki18nc("Gigabits per second unit symbol", "%1 Gbps"); 0051 const static KLocalizedString Tbitsps = ki18nc("Terabits per second unit symbol", "%1 Tbps"); 0052 const static KLocalizedString Pbitsps = ki18nc("Petabits per second unit symbol", "%1 Pbps"); 0053 0054 const static KLocalizedString Hz = ki18nc("Hertz unit symbol", "%1 Hz"); 0055 const static KLocalizedString kHz = ki18nc("Kilohertz unit symbol", "%1 kHz"); 0056 const static KLocalizedString MHz = ki18nc("Megahertz unit symbol", "%1 MHz"); 0057 const static KLocalizedString GHz = ki18nc("Gigahertz unit symbol", "%1 GHz"); 0058 const static KLocalizedString THz = ki18nc("Terahertz unit symbol", "%1 THz"); 0059 const static KLocalizedString PHz = ki18nc("Petahertz unit symbol", "%1 PHz"); 0060 0061 const static KLocalizedString percent = ki18nc("Percent unit", "%1%"); 0062 const static KLocalizedString RPM = ki18nc("Revolutions per minute unit symbol", "%1 RPM"); 0063 const static KLocalizedString C = ki18nc("Celsius unit symbol", "%1°C"); 0064 const static KLocalizedString dBm = ki18nc("Decibels unit symbol", "%1 dBm"); 0065 const static KLocalizedString s = ki18nc("Seconds unit symbol", "%1s"); 0066 const static KLocalizedString V = ki18nc("Volts unit symbol", "%1 V"); 0067 const static KLocalizedString W = ki18nc("Watts unit symbol", "%1 W"); 0068 const static KLocalizedString Wh = ki18nc("Watt-hours unit symbol", "%1 Wh"); 0069 const static KLocalizedString rate = ki18nc("Rate unit symbol", "%1 s⁻¹"); 0070 const static KLocalizedString A = ki18nc("Ampere unit symbol", "%1 A"); 0071 const static KLocalizedString unitless = ki18nc("Unitless", "%1"); 0072 0073 switch (unit) { 0074 case UnitByte: 0075 return B; 0076 case UnitKiloByte: 0077 return KiB; 0078 case UnitMegaByte: 0079 return MiB; 0080 case UnitGigaByte: 0081 return GiB; 0082 case UnitTeraByte: 0083 return TiB; 0084 case UnitPetaByte: 0085 return PiB; 0086 0087 case UnitByteRate: 0088 return bps; 0089 case UnitKiloByteRate: 0090 return Kbps; 0091 case UnitMegaByteRate: 0092 return Mbps; 0093 case UnitGigaByteRate: 0094 return Gbps; 0095 case UnitTeraByteRate: 0096 return Tbps; 0097 case UnitPetaByteRate: 0098 return Pbps; 0099 0100 case UnitBitRate: 0101 return bitsps; 0102 case UnitKiloBitRate: 0103 return Kbitsps; 0104 case UnitMegaBitRate: 0105 return Mbitsps; 0106 case UnitGigaBitRate: 0107 return Gbitsps; 0108 case UnitTeraBitRate: 0109 return Tbitsps; 0110 case UnitPetaBitRate: 0111 return Pbitsps; 0112 0113 case UnitHertz: 0114 return Hz; 0115 case UnitKiloHertz: 0116 return kHz; 0117 case UnitMegaHertz: 0118 return MHz; 0119 case UnitGigaHertz: 0120 return GHz; 0121 case UnitTeraHertz: 0122 return THz; 0123 case UnitPetaHertz: 0124 return PHz; 0125 0126 case UnitCelsius: 0127 return C; 0128 case UnitDecibelMilliWatts: 0129 return dBm; 0130 case UnitPercent: 0131 return percent; 0132 case UnitRate: 0133 return rate; 0134 case UnitRpm: 0135 return RPM; 0136 case UnitSecond: 0137 return s; 0138 case UnitVolt: 0139 return V; 0140 case UnitWatt: 0141 return W; 0142 case UnitWattHour: 0143 return Wh; 0144 case UnitAmpere: 0145 return A; 0146 0147 default: 0148 return unitless; 0149 } 0150 } 0151 0152 static int unitOrder(Unit unit) 0153 { 0154 switch (unit) { 0155 case UnitByte: 0156 case UnitKiloByte: 0157 case UnitMegaByte: 0158 case UnitGigaByte: 0159 case UnitTeraByte: 0160 case UnitPetaByte: 0161 case UnitByteRate: 0162 case UnitKiloByteRate: 0163 case UnitMegaByteRate: 0164 case UnitGigaByteRate: 0165 case UnitTeraByteRate: 0166 case UnitPetaByteRate: 0167 case UnitBitRate: 0168 case UnitKiloBitRate: 0169 case UnitMegaBitRate: 0170 case UnitGigaBitRate: 0171 case UnitTeraBitRate: 0172 case UnitPetaBitRate: 0173 return 1024; 0174 0175 case UnitHertz: 0176 case UnitKiloHertz: 0177 case UnitMegaHertz: 0178 case UnitGigaHertz: 0179 case UnitTeraHertz: 0180 case UnitPetaHertz: 0181 case UnitWatt: 0182 case UnitWattHour: 0183 case UnitAmpere: 0184 return 1000; 0185 0186 default: 0187 return 0; 0188 } 0189 } 0190 0191 static Unit unitBase(Unit unit) 0192 { 0193 switch (unit) { 0194 case UnitByte: 0195 case UnitKiloByte: 0196 case UnitMegaByte: 0197 case UnitGigaByte: 0198 case UnitTeraByte: 0199 case UnitPetaByte: 0200 return UnitByte; 0201 0202 case UnitByteRate: 0203 case UnitKiloByteRate: 0204 case UnitMegaByteRate: 0205 case UnitGigaByteRate: 0206 case UnitTeraByteRate: 0207 case UnitPetaByteRate: 0208 return UnitByteRate; 0209 0210 case UnitBitRate: 0211 case UnitKiloBitRate: 0212 case UnitMegaBitRate: 0213 case UnitGigaBitRate: 0214 case UnitTeraBitRate: 0215 case UnitPetaBitRate: 0216 return UnitBitRate; 0217 0218 case UnitHertz: 0219 case UnitKiloHertz: 0220 case UnitMegaHertz: 0221 case UnitGigaHertz: 0222 case UnitTeraHertz: 0223 case UnitPetaHertz: 0224 return UnitHertz; 0225 0226 default: 0227 return unit; 0228 } 0229 } 0230 0231 static Unit adjustedUnit(qreal value, Unit unit, MetricPrefix prefix) 0232 { 0233 const int order = unitOrder(unit); 0234 if (!order) { 0235 return unit; 0236 } 0237 0238 const Unit baseUnit = unitBase(unit); 0239 const MetricPrefix basePrefix = MetricPrefix(unit - baseUnit); 0240 0241 if (prefix == MetricPrefixAutoAdjust) { 0242 const qreal absoluteValue = value * std::pow(order, int(basePrefix)); 0243 if (absoluteValue > 0) { 0244 const int targetPrefix = std::log2(absoluteValue) / std::log2(order); 0245 if (targetPrefix <= MetricPrefixLast) { 0246 prefix = MetricPrefix(targetPrefix); 0247 } 0248 } 0249 if (prefix == MetricPrefixAutoAdjust) { 0250 prefix = basePrefix; 0251 } 0252 } 0253 0254 const Unit newUnit = Unit(prefix + baseUnit); 0255 // If there is no prefixed unit (e.g. no UnitKiloWatt), 0256 // don't overflow into the following unrelated units. 0257 if (unitBase(newUnit) != baseUnit) { 0258 return unit; 0259 } 0260 0261 return newUnit; 0262 } 0263 0264 static QString formatNumber(const QVariant &value, Unit unit, MetricPrefix prefix, FormatOptions options) 0265 { 0266 qreal amount = value.toDouble(); 0267 0268 if (!options.testFlag(FormatOptionShowNull) && (qFuzzyIsNull(amount) || qIsNaN(amount))) { 0269 return QString(); 0270 } 0271 0272 const Unit adjusted = adjustedUnit(amount, unit, prefix); 0273 if (adjusted != unit) { 0274 amount /= std::pow(unitOrder(unit), adjusted - unit); 0275 } 0276 0277 const int precision = (value.type() != QVariant::Double && adjusted <= unit) ? 0 : 1; 0278 const QString text = QLocale().toString(amount, 'f', precision); 0279 0280 return unitFormat(adjusted).subs(text).toString(); 0281 } 0282 0283 static QString formatTime(const QVariant &value) 0284 { 0285 return KFormat().formatDuration(value.toLongLong() * 1000); 0286 } 0287 0288 static QString formatTicks(const QVariant &value) 0289 { 0290 auto seconds = value.toLongLong() / sysconf(_SC_CLK_TCK); 0291 return KFormat().formatDuration(seconds * 1000); 0292 } 0293 0294 static QString formatBootTimestamp(const QVariant &value) 0295 { 0296 timespec tp; 0297 #ifdef Q_OS_LINUX 0298 clock_gettime(CLOCK_BOOTTIME, &tp); 0299 #else 0300 clock_gettime(CLOCK_MONOTONIC, &tp); 0301 #endif 0302 0303 const QDateTime systemBootTime = QDateTime::currentDateTime().addSecs(-tp.tv_sec); 0304 0305 const qreal secondsSinceSystemBoot = value.toReal() / sysconf(_SC_CLK_TCK); 0306 const QDateTime absoluteTimeSinceBoot = systemBootTime.addSecs(secondsSinceSystemBoot); 0307 0308 return KFormat().formatRelativeDateTime(absoluteTimeSinceBoot, QLocale::ShortFormat); 0309 } 0310 0311 qreal Formatter::scaleDownFactor(const QVariant &value, Unit unit, MetricPrefix targetPrefix) 0312 { 0313 const Unit adjusted = adjustedUnit(value.toDouble(), unit, targetPrefix); 0314 if (adjusted == unit) { 0315 return 1; 0316 } 0317 0318 return std::pow(unitOrder(unit), adjusted - unit); 0319 } 0320 0321 KLocalizedString Formatter::localizedString(const QVariant &value, Unit unit, MetricPrefix targetPrefix) 0322 { 0323 const Unit adjusted = adjustedUnit(value.toDouble(), unit, targetPrefix); 0324 return unitFormat(adjusted); 0325 } 0326 0327 QString Formatter::formatValue(const QVariant &value, Unit unit, MetricPrefix targetPrefix, FormatOptions options) 0328 { 0329 switch (unit) { 0330 case UnitByte: 0331 case UnitKiloByte: 0332 case UnitMegaByte: 0333 case UnitGigaByte: 0334 case UnitTeraByte: 0335 case UnitPetaByte: 0336 case UnitByteRate: 0337 case UnitKiloByteRate: 0338 case UnitMegaByteRate: 0339 case UnitGigaByteRate: 0340 case UnitTeraByteRate: 0341 case UnitPetaByteRate: 0342 case UnitBitRate: 0343 case UnitKiloBitRate: 0344 case UnitMegaBitRate: 0345 case UnitGigaBitRate: 0346 case UnitTeraBitRate: 0347 case UnitPetaBitRate: 0348 case UnitHertz: 0349 case UnitKiloHertz: 0350 case UnitMegaHertz: 0351 case UnitGigaHertz: 0352 case UnitTeraHertz: 0353 case UnitPetaHertz: 0354 case UnitPercent: 0355 case UnitRate: 0356 case UnitRpm: 0357 case UnitCelsius: 0358 case UnitDecibelMilliWatts: 0359 case UnitVolt: 0360 case UnitWatt: 0361 case UnitWattHour: 0362 case UnitSecond: 0363 case UnitAmpere: 0364 return formatNumber(value, unit, targetPrefix, options); 0365 0366 case UnitBootTimestamp: 0367 return formatBootTimestamp(value); 0368 case UnitTime: 0369 return formatTime(value); 0370 case UnitNone: 0371 return formatNumber(value, unit, MetricPrefix::MetricPrefixUnity, options); 0372 case UnitTicks: 0373 return formatTicks(value); 0374 0375 default: 0376 return value.toString(); 0377 } 0378 } 0379 0380 QString Formatter::symbol(Unit unit) 0381 { 0382 // TODO: Is it possible to avoid duplication of these symbols? 0383 switch (unit) { 0384 case UnitByte: 0385 return i18nc("Bytes unit symbol", "B"); 0386 case UnitKiloByte: 0387 return i18nc("Kilobytes unit symbol", "KiB"); 0388 case UnitMegaByte: 0389 return i18nc("Megabytes unit symbol", "MiB"); 0390 case UnitGigaByte: 0391 return i18nc("Gigabytes unit symbol", "GiB"); 0392 case UnitTeraByte: 0393 return i18nc("Terabytes unit symbol", "TiB"); 0394 case UnitPetaByte: 0395 return i18nc("Petabytes unit symbol", "PiB"); 0396 0397 case UnitByteRate: 0398 return i18nc("Bytes per second unit symbol", "B/s"); 0399 case UnitKiloByteRate: 0400 return i18nc("Kilobytes per second unit symbol", "KiB/s"); 0401 case UnitMegaByteRate: 0402 return i18nc("Megabytes per second unit symbol", "MiB/s"); 0403 case UnitGigaByteRate: 0404 return i18nc("Gigabytes per second unit symbol", "GiB/s"); 0405 case UnitTeraByteRate: 0406 return i18nc("Terabytes per second unit symbol", "TiB/s"); 0407 case UnitPetaByteRate: 0408 return i18nc("Petabytes per second unit symbol", "PiB/s"); 0409 0410 case UnitBitRate: 0411 return i18nc("Bits per second unit symbol", "bps"); 0412 case UnitKiloBitRate: 0413 return i18nc("Kilobits per second unit symbol", "Kbps"); 0414 case UnitMegaBitRate: 0415 return i18nc("Megabits per second unit symbol", "Mbps"); 0416 case UnitGigaBitRate: 0417 return i18nc("Gigabits per second unit symbol", "Gbps"); 0418 case UnitTeraBitRate: 0419 return i18nc("Terabits per second unit symbol", "Tbps"); 0420 case UnitPetaBitRate: 0421 return i18nc("Petabits per second unit symbol", "Pbps"); 0422 0423 case UnitHertz: 0424 return i18nc("Hertz unit symbol", "Hz"); 0425 case UnitKiloHertz: 0426 return i18nc("Kilohertz unit symbol", "kHz"); 0427 case UnitMegaHertz: 0428 return i18nc("Megahertz unit symbol", "MHz"); 0429 case UnitGigaHertz: 0430 return i18nc("Gigahertz unit symbol", "GHz"); 0431 case UnitTeraHertz: 0432 return i18nc("Terahertz unit symbol", "THz"); 0433 case UnitPetaHertz: 0434 return i18nc("Petahertz unit symbol", "PHz"); 0435 0436 case UnitPercent: 0437 return i18nc("Percent unit", "%"); 0438 case UnitRpm: 0439 return i18nc("Revolutions per minute unit symbol", "RPM"); 0440 case UnitCelsius: 0441 return i18nc("Celsius unit symbol", "°C"); 0442 case UnitDecibelMilliWatts: 0443 return i18nc("Decibels unit symbol", "dBm"); 0444 case UnitSecond: 0445 return i18nc("Seconds unit symbol", "s"); 0446 case UnitVolt: 0447 return i18nc("Volts unit symbol", "V"); 0448 case UnitWatt: 0449 return i18nc("Watts unit symbol", "W"); 0450 case UnitWattHour: 0451 return i18nc("Watt-hours unit symbol", "Wh"); 0452 case UnitRate: 0453 return i18nc("Rate unit symbol", "s⁻¹"); 0454 case UnitAmpere: 0455 return i18nc("Ampere unit symbol", "A"); 0456 0457 default: 0458 return QString(); 0459 } 0460 } 0461 0462 qreal Formatter::maximumLength(Unit unit, const QFont &font) 0463 { 0464 auto order = unitOrder(unit); 0465 0466 QString maximum; 0467 switch (unitBase(unit)) { 0468 case UnitByte: 0469 maximum = formatValue(order - 0.5, UnitMegaByte, MetricPrefixMega); 0470 break; 0471 case UnitByteRate: 0472 maximum = formatValue(order - 0.5, UnitMegaByteRate, MetricPrefixMega); 0473 break; 0474 case UnitBitRate: 0475 maximum = formatValue(order - 0.5, UnitMegaBitRate, MetricPrefixMega); 0476 break; 0477 case UnitHertz: 0478 maximum = formatValue(order - 0.5, UnitMegaHertz, MetricPrefixMega); 0479 break; 0480 case UnitPercent: 0481 maximum = formatValue(9999.9, UnitPercent); 0482 break; 0483 default: 0484 return -1.0; 0485 } 0486 0487 auto metrics = QFontMetrics{font}; 0488 return metrics.horizontalAdvance(maximum); 0489 } 0490 0491 } // namespace KSysGuard