diff --git a/src/base/utils/misc.cpp b/src/base/utils/misc.cpp index 67ec2ec89..f25c2a630 100644 --- a/src/base/utils/misc.cpp +++ b/src/base/utils/misc.cpp @@ -84,6 +84,27 @@ namespace QT_TRANSLATE_NOOP3("misc", "PiB", "pebibytes (1024 tebibytes)"), QT_TRANSLATE_NOOP3("misc", "EiB", "exbibytes (1024 pebibytes)") }; + + // return best userfriendly storage unit (B, KiB, MiB, GiB, TiB, ...) + // use Binary prefix standards from IEC 60027-2 + // see http://en.wikipedia.org/wiki/Kilobyte + // value must be given in bytes + // to send numbers instead of strings with suffixes + bool splitToFriendlyUnit(const qint64 sizeInBytes, qreal &val, Utils::Misc::SizeUnit &unit) + { + if (sizeInBytes < 0) return false; + + int i = 0; + qreal rawVal = static_cast(sizeInBytes); + + while ((rawVal >= 1024.) && (i <= static_cast(Utils::Misc::SizeUnit::ExbiByte))) { + rawVal /= 1024.; + ++i; + } + val = rawVal; + unit = static_cast(i); + return true; + } } void Utils::Misc::shutdownComputer(const ShutdownDialogAction &action) @@ -237,52 +258,30 @@ QPoint Utils::Misc::screenCenter(const QWidget *w) } #endif -QString Utils::Misc::unitString(Utils::Misc::SizeUnit unit) -{ - return QCoreApplication::translate("misc", - units[static_cast(unit)].source, units[static_cast(unit)].comment); -} - -// return best userfriendly storage unit (B, KiB, MiB, GiB, TiB, ...) -// use Binary prefix standards from IEC 60027-2 -// see http://en.wikipedia.org/wiki/Kilobyte -// value must be given in bytes -// to send numbers instead of strings with suffixes -bool Utils::Misc::friendlyUnit(qint64 sizeInBytes, qreal &val, Utils::Misc::SizeUnit &unit) +QString Utils::Misc::unitString(const SizeUnit unit, const bool isSpeed) { - if (sizeInBytes < 0) return false; - - int i = 0; - qreal rawVal = static_cast(sizeInBytes); - - while ((rawVal >= 1024.) && (i <= static_cast(SizeUnit::ExbiByte))) { - rawVal /= 1024.; - ++i; - } - val = rawVal; - unit = static_cast(i); - return true; + const auto &unitString = units[static_cast(unit)]; + QString ret = QCoreApplication::translate("misc", unitString.source, unitString.comment); + if (isSpeed) + ret += QCoreApplication::translate("misc", "/s", "per second"); + return ret; } QString Utils::Misc::friendlyUnit(qint64 bytesValue, bool isSpeed) { SizeUnit unit; qreal friendlyVal; - if (!friendlyUnit(bytesValue, friendlyVal, unit)) + if (!splitToFriendlyUnit(bytesValue, friendlyVal, unit)) return QCoreApplication::translate("misc", "Unknown", "Unknown (size)"); - QString ret; - if (unit == SizeUnit::Byte) - ret = QString::number(bytesValue) + QString::fromUtf8(C_NON_BREAKING_SPACE) + unitString(unit); - else - ret = Utils::String::fromDouble(friendlyVal, friendlyUnitPrecision(unit)) + QString::fromUtf8(C_NON_BREAKING_SPACE) + unitString(unit); - if (isSpeed) - ret += QCoreApplication::translate("misc", "/s", "per second"); - return ret; + return Utils::String::fromDouble(friendlyVal, friendlyUnitPrecision(unit)) + + QString::fromUtf8(C_NON_BREAKING_SPACE) + + unitString(unit, isSpeed); } int Utils::Misc::friendlyUnitPrecision(SizeUnit unit) { // friendlyUnit's number of digits after the decimal point + if (unit == SizeUnit::Byte) return 0; if (unit <= SizeUnit::MebiByte) return 1; else if (unit == SizeUnit::GibiByte) return 2; else return 3; diff --git a/src/base/utils/misc.h b/src/base/utils/misc.h index f4f06461b..7cdcea2b6 100644 --- a/src/base/utils/misc.h +++ b/src/base/utils/misc.h @@ -79,11 +79,10 @@ namespace Utils QString boostVersionString(); QString libtorrentVersionString(); - QString unitString(SizeUnit unit); + QString unitString(SizeUnit unit, bool isSpeed = false); // return the best user friendly storage unit (B, KiB, MiB, GiB, TiB) // value must be given in bytes - bool friendlyUnit(qint64 sizeInBytes, qreal &val, SizeUnit &unit); QString friendlyUnit(qint64 bytesValue, bool isSpeed = false); int friendlyUnitPrecision(SizeUnit unit); qint64 sizeInBytes(qreal size, SizeUnit unit); diff --git a/src/gui/properties/speedplotview.cpp b/src/gui/properties/speedplotview.cpp index 63f41bb96..b5d15a14d 100644 --- a/src/gui/properties/speedplotview.cpp +++ b/src/gui/properties/speedplotview.cpp @@ -28,9 +28,11 @@ #include "speedplotview.h" +#include #include #include #include "base/global.h" +#include "base/unicodestrings.h" #include "base/utils/misc.h" namespace @@ -48,6 +50,63 @@ namespace const int HOUR6_BUF_SIZE = 5 * 60; const int DIVIDER_30MIN = MIN30_SEC / MIN30_BUF_SIZE; const int DIVIDER_6HOUR = HOUR6_SEC / HOUR6_BUF_SIZE; + + + // table of supposed nice steps for grid marks to get nice looking quarters of scale + const double roundingTable[] = {1.2, 1.6, 2, 2.4, 2.8, 3.2, 4, 6, 8}; + + struct SplittedValue + { + double arg; + Utils::Misc::SizeUnit unit; + qint64 sizeInBytes() const + { + return Utils::Misc::sizeInBytes(arg, unit); + } + }; + + SplittedValue getRoundedYScale(double value) + { + using Utils::Misc::SizeUnit; + + if (value == 0.0) return {0, SizeUnit::Byte}; + if (value <= 12.0) return {12, SizeUnit::Byte}; + + SizeUnit calculatedUnit = SizeUnit::Byte; + while (value > 1024) { + value /= 1024; + calculatedUnit = static_cast(static_cast(calculatedUnit) + 1); + } + + if (value > 100.0) { + int roundedValue = static_cast(value / 40) * 40; + while (roundedValue < value) + roundedValue += 40; + return {static_cast(roundedValue), calculatedUnit}; + } + + if (value > 10.0) { + int roundedValue = static_cast(value / 4) * 4; + while (roundedValue < value) + roundedValue += 4; + return {static_cast(roundedValue), calculatedUnit}; + } + + for (const auto &roundedValue : roundingTable) { + if (value <= roundedValue) + return {roundedValue, calculatedUnit}; + } + return {10.0, calculatedUnit}; + } + + QString formatLabel(const double argValue, const Utils::Misc::SizeUnit unit) + { + // check is there need for digits after decimal separator + const int precision = (argValue < 10) ? friendlyUnitPrecision(unit) : 0; + return QLocale::system().toString(argValue, 'f', precision) + + QString::fromUtf8(C_NON_BREAKING_SPACE) + + unitString(unit, true); + } } SpeedPlotView::Averager::Averager(int divider, boost::circular_buffer &sink) @@ -211,18 +270,16 @@ void SpeedPlotView::paintEvent(QPaintEvent *) QFontMetrics fontMetrics = painter.fontMetrics(); rect.adjust(4, 4, 0, -4); // Add padding - - quint64 maxY = maxYValue(); - + const SplittedValue niceScale = getRoundedYScale(maxYValue()); rect.adjust(0, fontMetrics.height(), 0, 0); // Add top padding for top speed text // draw Y axis speed labels QVector speedLabels = { - Utils::Misc::friendlyUnit(maxY, true), - Utils::Misc::friendlyUnit(0.75 * maxY, true), - Utils::Misc::friendlyUnit(0.5 * maxY, true), - Utils::Misc::friendlyUnit(0.25 * maxY, true), - Utils::Misc::friendlyUnit(0, true) + formatLabel(niceScale.arg, niceScale.unit), + formatLabel((0.75 * niceScale.arg), niceScale.unit), + formatLabel((0.50 * niceScale.arg), niceScale.unit), + formatLabel((0.25 * niceScale.arg), niceScale.unit), + formatLabel(0.0, niceScale.unit), }; int yAxisWidth = 0; @@ -264,8 +321,8 @@ void SpeedPlotView::paintEvent(QPaintEvent *) // draw graphs rect.adjust(3, 0, 0, 0); // Need, else graphs cross left gridline - double yMultiplier = (maxY == 0) ? 0.0 : static_cast(rect.height()) / maxY; - double xTickSize = static_cast(rect.width()) / m_viewablePointsCount; + const double yMultiplier = (niceScale.arg == 0.0) ? 0.0 : (rect.height() / niceScale.sizeInBytes()); + const double xTickSize = static_cast(rect.width()) / m_viewablePointsCount; boost::circular_buffer &queue = getCurrentData(); diff --git a/src/gui/search/searchjobwidget.cpp b/src/gui/search/searchjobwidget.cpp index be086862b..cc8f4afa2 100644 --- a/src/gui/search/searchjobwidget.cpp +++ b/src/gui/search/searchjobwidget.cpp @@ -315,6 +315,8 @@ void SearchJobWidget::updateFilter() void SearchJobWidget::fillFilterComboBoxes() { using Utils::Misc::SizeUnit; + using Utils::Misc::unitString; + QStringList unitStrings; unitStrings.append(unitString(SizeUnit::Byte)); unitStrings.append(unitString(SizeUnit::KibiByte));