Skip to content

Enhanced Traffic Graph Widget with Multi-timeframe Support and Data Persistence #866

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 13 additions & 14 deletions src/qt/forms/debugwindow.ui
Original file line number Diff line number Diff line change
Expand Up @@ -665,20 +665,29 @@
<item>
<widget class="QSlider" name="sldGraphRange">
<property name="minimum">
<number>1</number>
<number>0</number>
</property>
<property name="maximum">
<number>288</number>
<number>2400</number>
</property>
<property name="singleStep">
<number>200</number>
</property>
<property name="pageStep">
<number>12</number>
<number>200</number>
</property>
<property name="value">
<number>6</number>
<number>0</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>200</number>
</property>
</widget>
</item>
<item>
Expand All @@ -694,16 +703,6 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnClearTrafficGraph">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're deleting this, maybe there should be a way for the user to insert a reference line?

For now, I'd move removal of anything to a separate PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The user can effectively remove the data by deleting the .dat file - is there any basis for being able to do this while the client is running?

<property name="text">
<string>&amp;Reset</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
Expand Down
34 changes: 34 additions & 0 deletions src/qt/guiutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,40 @@ QString formatBytes(uint64_t bytes)
return QObject::tr("%1 GB").arg(bytes / 1'000'000'000);
}

QString formatBytesps(float val)
{
if (val < 10)
//: "Bytes per second"
return QObject::tr("%1 B/s").arg(0.01 * int(val * 100 + 0.5));
if (val < 100)
//: "Bytes per second"
return QObject::tr("%1 B/s").arg(0.1 * int(val * 10 + 0.5));
if (val < 1'000)
//: "Bytes per second"
return QObject::tr("%1 B/s").arg(int(val + 0.5));
if (val < 10'000)
//: "Kilobytes per second"
return QObject::tr("%1 kB/s").arg(0.01 * int(val / 10 + 0.5));
if (val < 100'000)
//: "Kilobytes per second"
return QObject::tr("%1 kB/s").arg(0.1 * int(val / 100 + 0.5));
if (val < 1'000'000)
//: "Kilobytes per second"
return QObject::tr("%1 kB/s").arg(int(val / 1'000 + 0.5));
if (val < 10'000'000)
//: "Megabytes per second"
return QObject::tr("%1 MB/s").arg(0.01 * int(val / 10'000 + 0.5));
if (val < 100'000'000)
//: "Megabytes per second"
return QObject::tr("%1 MB/s").arg(0.1 * int(val / 100'000 + 0.5));
if (val < 10'000'000'000)
//: "Megabytes per second"
return QObject::tr("%1 MB/s").arg(long(val / 1'000'000 + 0.5));

//: "Gigabytes per second"
return QObject::tr("%1 GB/s").arg(long(val / 1'000'000'000 + 0.5));
}

qreal calculateIdealFontSize(int width, const QString& text, QFont font, qreal minPointSize, qreal font_size) {
while(font_size >= minPointSize) {
font.setPointSizeF(font_size);
Expand Down
1 change: 1 addition & 0 deletions src/qt/guiutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ namespace GUIUtil
QString formatNiceTimeOffset(qint64 secs);

QString formatBytes(uint64_t bytes);
QString formatBytesps(float bytes);

qreal calculateIdealFontSize(int width, const QString& text, QFont font, qreal minPointSize = 4, qreal startPointSize = 14);

Expand Down
61 changes: 51 additions & 10 deletions src/qt/rpcconsole.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@
using util::Join;

const int CONSOLE_HISTORY = 50;
const int INITIAL_TRAFFIC_GRAPH_MINS = 30;
const QSize FONT_RANGE(4, 40);
const char fontSizeSettingsKey[] = "consoleFontSize";

Expand Down Expand Up @@ -566,7 +565,6 @@ RPCConsole::RPCConsole(interfaces::Node& node, const PlatformStyle *_platformSty
connect(ui->clearButton, &QAbstractButton::clicked, [this] { clear(); });
connect(ui->fontBiggerButton, &QAbstractButton::clicked, this, &RPCConsole::fontBigger);
connect(ui->fontSmallerButton, &QAbstractButton::clicked, this, &RPCConsole::fontSmaller);
connect(ui->btnClearTrafficGraph, &QPushButton::clicked, ui->trafficGraph, &TrafficGraphWidget::clear);

// disable the wallet selector by default
ui->WalletSelector->setVisible(false);
Expand All @@ -578,7 +576,7 @@ RPCConsole::RPCConsole(interfaces::Node& node, const PlatformStyle *_platformSty
// based timer interface
m_node.rpcSetTimerInterfaceIfUnset(rpcTimerInterface);

setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we losing this default constant?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because it isn't needed - on startup it "defaults" to the first non-full range

setTrafficGraphRange(1); // 1 is the lowest setting (0 bumps up)
updateDetailWidget();

consoleFontSize = settings.value(fontSizeSettingsKey, QFont().pointSize()).toInt();
Expand Down Expand Up @@ -1166,21 +1164,64 @@ void RPCConsole::scrollToEnd()

void RPCConsole::on_sldGraphRange_valueChanged(int value)
{
const int multiplier = 5; // each position on the slider represents 5 min
int mins = value * multiplier;
setTrafficGraphRange(mins);
static int64_t last_click_time = 0;
static bool last_click_was_up = false;
unsigned int range = (value + 100) / 200 + 1; // minimum of 1, 0 reserve for scale bump
bool bouncing = false;
if (!m_slider_in_use) {
// Avoid accidental oscillation of direction due to rapid mouse clicks
int64_t now = GetTime<std::chrono::milliseconds>().count();
bool this_click_is_up = false;
if (value > m_set_slider_value) this_click_is_up = true;
if (now - last_click_time < 250 && this_click_is_up != last_click_was_up) {
bouncing = true;
ui->sldGraphRange->blockSignals(true);
ui->sldGraphRange->setValue(m_set_slider_value);
ui->sldGraphRange->blockSignals(false);
}
last_click_time = now;
last_click_was_up = this_click_is_up;
}
m_set_slider_value = value;
if (bouncing) return;
setTrafficGraphRange(range);
}

void RPCConsole::setTrafficGraphRange(int mins)
void RPCConsole::setTrafficGraphRange(int value)
{
ui->trafficGraph->setGraphRange(std::chrono::minutes{mins});
int mins = ui->trafficGraph->setGraphRange(value);
if (value)
m_set_slider_value = (value - 1) * 200;
else {
// When bumping, calculate the proper slider position based on the traffic graph's new value
unsigned int new_graph_value = ui->trafficGraph->getCurrentRangeIndex() + 1; // +1 because the index is 0-based
m_set_slider_value = (new_graph_value - 1) * 200;
ui->sldGraphRange->blockSignals(true);
ui->sldGraphRange->setValue(m_set_slider_value);
ui->sldGraphRange->blockSignals(false);
}
ui->lblGraphRange->setText(GUIUtil::formatDurationStr(std::chrono::minutes{mins}));
}

void RPCConsole::on_sldGraphRange_sliderReleased()
{
ui->sldGraphRange->setValue(m_set_slider_value);
m_slider_in_use = false;
}

void RPCConsole::on_sldGraphRange_sliderPressed() { m_slider_in_use = true; }

void RPCConsole::updateTrafficStats(quint64 totalBytesIn, quint64 totalBytesOut)
{
ui->lblBytesIn->setText(GUIUtil::formatBytes(totalBytesIn));
ui->lblBytesOut->setText(GUIUtil::formatBytes(totalBytesOut));
if (!m_slider_in_use && ui->trafficGraph->GraphRangeBump())
setTrafficGraphRange(0); // bump it up

// Add baseline values to the current node values
quint64 totalIn = totalBytesIn + ui->trafficGraph->getBaselineBytesRecv();
quint64 totalOut = totalBytesOut + ui->trafficGraph->getBaselineBytesSent();

ui->lblBytesIn->setText(GUIUtil::formatBytes(totalIn));
ui->lblBytesOut->setText(GUIUtil::formatBytes(totalOut));
}

void RPCConsole::updateDetailWidget()
Expand Down
9 changes: 6 additions & 3 deletions src/qt/rpcconsole.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ private Q_SLOTS:
void on_openDebugLogfileButton_clicked();
/** change the time range of the network traffic graph */
void on_sldGraphRange_valueChanged(int value);
void on_sldGraphRange_sliderReleased();
void on_sldGraphRange_sliderPressed();
/** update traffic statistics */
void updateTrafficStats(quint64 totalBytesIn, quint64 totalBytesOut);
void resizeEvent(QResizeEvent *event) override;
Expand Down Expand Up @@ -146,10 +148,9 @@ public Q_SLOTS:
} const ts;

void startExecutor();
void setTrafficGraphRange(int mins);
void setTrafficGraphRange(int value);

enum ColumnWidths
{
enum ColumnWidths {
ADDRESS_COLUMN_WIDTH = 200,
SUBVERSION_COLUMN_WIDTH = 150,
PING_COLUMN_WIDTH = 80,
Expand Down Expand Up @@ -177,6 +178,8 @@ public Q_SLOTS:
bool m_is_executing{false};
QByteArray m_peer_widget_header_state;
QByteArray m_banlist_widget_header_state;
bool m_slider_in_use{false};
int m_set_slider_value{0};

/** Update UI with latest network info from model. */
void updateNetworkState();
Expand Down
Loading
Loading