Improve conversion of bytes to human readable string
Fixes issues like showing 0 MiB when the value is just slightly less then 1 MiB.
This commit is contained in:
parent
db2594a87c
commit
5bdd3fa95d
7 changed files with 125 additions and 44 deletions
|
|
@ -5,6 +5,7 @@
|
||||||
#include "ResultTableModelUtil.h"
|
#include "ResultTableModelUtil.h"
|
||||||
#include "CustomDataRole.h"
|
#include "CustomDataRole.h"
|
||||||
#include "AbstractEditorFactory.h"
|
#include "AbstractEditorFactory.h"
|
||||||
|
#include "utils/HumanReadableBytes.h"
|
||||||
|
|
||||||
PgLabItemDelegate::PgLabItemDelegate(QObject *parent)
|
PgLabItemDelegate::PgLabItemDelegate(QObject *parent)
|
||||||
: QStyledItemDelegate(parent)
|
: QStyledItemDelegate(parent)
|
||||||
|
|
@ -111,37 +112,11 @@ void PgLabItemDelegate::initStyleOption(QStyleOptionViewItem *option,
|
||||||
else {
|
else {
|
||||||
forground_color = GetDefaultColorForType(oid);
|
forground_color = GetDefaultColorForType(oid);
|
||||||
if (meaning == DataMeaning::Bytes) {
|
if (meaning == DataMeaning::Bytes) {
|
||||||
QString suffix;
|
option->text = HandleBytes(value.toLongLong(), forground_color);
|
||||||
auto s = value.toLongLong();
|
|
||||||
double val;
|
|
||||||
if (s > 1024 * 1024 * 1000) {
|
|
||||||
val = s / (1024 * 1024 * 1024);
|
|
||||||
suffix = "GiB";
|
|
||||||
forground_color = QColorConstants::Svg::darkorange;
|
|
||||||
option->font.setBold(true);
|
|
||||||
}
|
|
||||||
else if (s > 1024 * 1000) {
|
|
||||||
val = s / (1024 * 1024);
|
|
||||||
suffix = "MiB";
|
|
||||||
forground_color = QColorConstants::Svg::darkgoldenrod;
|
|
||||||
}
|
|
||||||
else if (s > 1000) {
|
|
||||||
val = s / 1024;
|
|
||||||
suffix = "KiB";
|
|
||||||
forground_color = QColorConstants::Svg::darkgreen;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
val = s;
|
|
||||||
suffix = "B";
|
|
||||||
forground_color = QColorConstants::Svg::darkblue;
|
|
||||||
}
|
|
||||||
option->text = QString{ "%1 %2" }.arg(val, 0, 'g', 3).arg(suffix) ;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
auto str = value.toString();
|
auto str = value.toString();
|
||||||
auto s = str.left(100);
|
auto s = str.left(100);
|
||||||
// auto f = s.indexOf('\n');
|
|
||||||
// option->text = ((f > 0) ? s.left(f) : s).toString();
|
|
||||||
option->text = s;
|
option->text = s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -161,6 +136,24 @@ void PgLabItemDelegate::initStyleOption(QStyleOptionViewItem *option,
|
||||||
option->styleObject = nullptr;
|
option->styleObject = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString PgLabItemDelegate::HandleBytes(qlonglong s, QColor &forground_color) const
|
||||||
|
{
|
||||||
|
auto str = HumanReadableBytes(s);
|
||||||
|
if (s > 1024 * 1024 * 1024) {
|
||||||
|
forground_color = QColorConstants::Svg::darkorange;
|
||||||
|
}
|
||||||
|
else if (s > 1024 * 1024) {
|
||||||
|
forground_color = QColorConstants::Svg::darkgoldenrod;
|
||||||
|
}
|
||||||
|
else if (s > 1024) {
|
||||||
|
forground_color = QColorConstants::Svg::darkgreen;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
forground_color = QColorConstants::Svg::darkblue;
|
||||||
|
}
|
||||||
|
return QString::fromStdString(str);
|
||||||
|
}
|
||||||
|
|
||||||
void PgLabItemDelegate::paint(QPainter *painter,
|
void PgLabItemDelegate::paint(QPainter *painter,
|
||||||
const QStyleOptionViewItem &option, const QModelIndex &index) const
|
const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AbstractEditorFactory *m_editorFactory = nullptr;
|
AbstractEditorFactory *m_editorFactory = nullptr;
|
||||||
|
QString HandleBytes(qlonglong s, QColor &forground_color) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PGLABITEMDELEGATE_H
|
#endif // PGLABITEMDELEGATE_H
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,8 @@ SOURCES += \
|
||||||
catalog/PgLanguage.cpp \
|
catalog/PgLanguage.cpp \
|
||||||
catalog/PgAcl.cpp \
|
catalog/PgAcl.cpp \
|
||||||
catalog/PgSequence.cpp \
|
catalog/PgSequence.cpp \
|
||||||
catalog/PgSequenceContainer.cpp
|
catalog/PgSequenceContainer.cpp \
|
||||||
|
utils/HumanReadableBytes.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
Pglablib.h \
|
Pglablib.h \
|
||||||
|
|
@ -162,7 +163,8 @@ HEADERS += \
|
||||||
catalog/PgLanguage.h \
|
catalog/PgLanguage.h \
|
||||||
catalog/PgAcl.h \
|
catalog/PgAcl.h \
|
||||||
catalog/PgSequence.h \
|
catalog/PgSequence.h \
|
||||||
catalog/PgSequenceContainer.h
|
catalog/PgSequenceContainer.h \
|
||||||
|
utils/HumanReadableBytes.h
|
||||||
|
|
||||||
unix {
|
unix {
|
||||||
target.path = /usr/lib
|
target.path = /usr/lib
|
||||||
|
|
|
||||||
56
pglablib/utils/HumanReadableBytes.cpp
Normal file
56
pglablib/utils/HumanReadableBytes.cpp
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
#include "HumanReadableBytes.h"
|
||||||
|
#include <iomanip>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct scale {
|
||||||
|
int64_t scale;
|
||||||
|
const char* prefix;
|
||||||
|
};
|
||||||
|
|
||||||
|
void fmt(std::ostringstream &o, double d)
|
||||||
|
{
|
||||||
|
;
|
||||||
|
if (d < 10.0)
|
||||||
|
{
|
||||||
|
o << fixed << setprecision(2) << d;
|
||||||
|
//return std::format("{:.3g}", d);
|
||||||
|
}
|
||||||
|
else if (d < 100.0)
|
||||||
|
{
|
||||||
|
o << fixed << setprecision(1) << d;
|
||||||
|
//return std::format("{:.3g}", d);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
o << fixed << setprecision(0) << d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string HumanReadableBytes(uint64_t bytes)
|
||||||
|
{
|
||||||
|
static scale scales[] = {
|
||||||
|
{ 1024ll * 1024 * 1024 * 1024, "Ti" },
|
||||||
|
{ 1024ll * 1024 * 1024, "Gi" },
|
||||||
|
{ 1024ll * 1024, "Mi" },
|
||||||
|
{ 1024ll, "ki" },
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostringstream out;
|
||||||
|
for (int i = 0; i < (sizeof(scales) / sizeof(scale)); ++i)
|
||||||
|
{
|
||||||
|
if (bytes >= scales[i].scale)
|
||||||
|
{
|
||||||
|
fmt(out, bytes / double(scales[i].scale));
|
||||||
|
out << " " << scales[i].prefix << "B";
|
||||||
|
return out.str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out << bytes << " B";
|
||||||
|
return out.str();
|
||||||
|
}
|
||||||
5
pglablib/utils/HumanReadableBytes.h
Normal file
5
pglablib/utils/HumanReadableBytes.h
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
std::string HumanReadableBytes(uint64_t bytes);
|
||||||
|
|
@ -18,6 +18,7 @@ SOURCES += main.cpp \
|
||||||
tst_ConvertLangToSqlString.cpp \
|
tst_ConvertLangToSqlString.cpp \
|
||||||
tst_ConvertToMultiLineCString.cpp \
|
tst_ConvertToMultiLineCString.cpp \
|
||||||
tst_ExplainJsonParser.cpp \
|
tst_ExplainJsonParser.cpp \
|
||||||
|
tst_HumanReadableBytes.cpp \
|
||||||
tst_escapeConnectionStringValue.cpp \
|
tst_escapeConnectionStringValue.cpp \
|
||||||
tst_expected.cpp \
|
tst_expected.cpp \
|
||||||
tst_SqlLexer.cpp \
|
tst_SqlLexer.cpp \
|
||||||
|
|
|
||||||
23
tests/pglabtests/tst_HumanReadableBytes.cpp
Normal file
23
tests/pglabtests/tst_HumanReadableBytes.cpp
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <gmock/gmock-matchers.h>
|
||||||
|
#include "PrintTo_Qt.h"
|
||||||
|
|
||||||
|
#include "utils/HumanReadableBytes.h"
|
||||||
|
|
||||||
|
TEST(HumanReadableBytesTest, bytes7)
|
||||||
|
{
|
||||||
|
auto s = HumanReadableBytes(7);
|
||||||
|
ASSERT_EQ("7 B", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(HumanReadableBytesTest, bytes1023)
|
||||||
|
{
|
||||||
|
auto s = HumanReadableBytes(1023);
|
||||||
|
ASSERT_EQ("1023 B", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(HumanReadableBytesTest, bytes1k)
|
||||||
|
{
|
||||||
|
auto s = HumanReadableBytes(1024);
|
||||||
|
ASSERT_EQ("1.00 kiB", s);
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue