This commit is contained in:
jolavillette 2025-12-30 08:04:37 +00:00 committed by GitHub
commit eb48c88fec
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 216 additions and 49 deletions

View file

@ -18,12 +18,18 @@
* *
*******************************************************************************/
/*******************************************************************************
* gui/statistics/RttStatistics.cpp *
*******************************************************************************/
#include <iostream>
#include <limits>
#include <QTimer>
#include <QObject>
#include <QPainter>
#include <QStylePainter>
#include <QHostAddress>
#include <QHash>
#include <retroshare/rsrtt.h>
#include <retroshare/rspeers.h>
@ -32,13 +38,49 @@
#include "gui/settings/rsharesettings.h"
// --- Custom Item for Sorting (Table) ---
class RttTreeItem : public QTreeWidgetItem {
public:
using QTreeWidgetItem::QTreeWidgetItem;
bool operator<(const QTreeWidgetItem &other) const {
int sortCol = treeWidget() ? treeWidget()->sortColumn() : 0;
// RTT Sort
if (sortCol == 1) {
QString txt1 = text(1);
QString txt2 = other.text(1);
long val1 = (txt1 == "?") ? std::numeric_limits<long>::max() : txt1.toLong();
long val2 = (txt2 == "?") ? std::numeric_limits<long>::max() : txt2.toLong();
return val1 < val2;
}
// IP Sort
if (sortCol == 3) {
QString s1 = text(3);
QString s2 = other.text(3);
QHostAddress ip1(s1); QHostAddress ip2(s2);
bool isTorI2p1 = s1.contains(".onion") || s1.contains(".i2p");
bool isTorI2p2 = s2.contains(".onion") || s2.contains(".i2p");
if (!ip1.isNull() && !ip2.isNull() && !isTorI2p1 && !isTorI2p2) {
if (ip1.protocol() != ip2.protocol()) return ip1.protocol() < ip2.protocol();
if (ip1.protocol() == QAbstractSocket::IPv4Protocol) return ip1.toIPv4Address() < ip2.toIPv4Address();
}
return s1 < s2;
}
return QTreeWidgetItem::operator<(other);
}
};
// --- Main Constructor ---
RttStatistics::RttStatistics(QWidget * /*parent*/)
{
setupUi(this) ;
m_bProcessSettings = false;
// Setup Graph in Tab 1
_tunnel_statistics_F->setWidget( _tst_CW = new RttStatisticsGraph(this) ) ;
_tunnel_statistics_F->setWidgetResizable(true);
_tunnel_statistics_F->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
@ -46,14 +88,24 @@ RttStatistics::RttStatistics(QWidget * /*parent*/)
_tunnel_statistics_F->viewport()->setBackgroundRole(QPalette::NoRole);
_tunnel_statistics_F->setFrameStyle(QFrame::NoFrame);
_tunnel_statistics_F->setFocusPolicy(Qt::NoFocus);
// Setup Table in Tab 2
treeWidget->setAlternatingRowColors(true);
treeWidget->setSortingEnabled(true);
treeWidget->sortByColumn(1, Qt::AscendingOrder);
// Timer for Table Update
m_timer = new QTimer(this);
connect(m_timer, SIGNAL(timeout()), this, SLOT(updateRttValues()));
m_timer->start(1000);
// load settings
processSettings(true);
}
RttStatistics::~RttStatistics()
{
if(m_timer) m_timer->stop();
// save settings
processSettings(false);
}
@ -66,23 +118,75 @@ void RttStatistics::processSettings(bool bLoad)
if (bLoad) {
// load settings
QByteArray state = Settings->value("TreeState").toByteArray();
if (!state.isEmpty()) treeWidget->header()->restoreState(state);
// state of splitter
//splitter->restoreState(Settings->value("Splitter").toByteArray());
tabWidget->setCurrentIndex(Settings->value("ActiveTab", 0).toInt());
} else {
// save settings
// state of splitter
//Settings->setValue("Splitter", splitter->saveState());
Settings->setValue("TreeState", treeWidget->header()->saveState());
Settings->setValue("ActiveTab", tabWidget->currentIndex());
}
Settings->endGroup();
m_bProcessSettings = false;
m_bProcessSettings = false;
}
// --- Table Update Logic (O(N) Optimized) ---
void RttStatistics::updateRttValues()
{
// Only update if the rtt tab is visible and the table view is selected
if (!isVisible() || tabWidget->currentIndex() != 1) return;
std::list<RsPeerId> idList;
if (!rsPeers) return;
rsPeers->getOnlineList(idList);
QHash<QString, QTreeWidgetItem*> existingItems;
for(int i = 0; i < treeWidget->topLevelItemCount(); ++i) {
QTreeWidgetItem* item = treeWidget->topLevelItem(i);
existingItems.insert(item->data(0, Qt::UserRole).toString(), item);
}
for(std::list<RsPeerId>::const_iterator it = idList.begin(); it != idList.end(); ++it)
{
std::string peerIdStr = (*it).toStdString();
QString qPeerId = QString::fromStdString(peerIdStr);
std::list<RsRttPongResult> results;
rsRtt->getPongResults(*it, 1, results);
int rttInMs = -1;
if (!results.empty()) {
float rttSec = results.back().mRTT;
if (rttSec > 0.000001f) rttInMs = (int)(rttSec * 1000.0f);
}
RsPeerDetails details;
rsPeers->getPeerDetails(*it, details);
QString peerName = QString::fromUtf8(details.name.c_str());
QString ipAddress = QString::fromStdString(details.extAddr);
QTreeWidgetItem* item = existingItems.take(qPeerId);
if (!item) {
item = new RttTreeItem(treeWidget);
item->setData(0, Qt::UserRole, qPeerId);
}
item->setText(0, peerName);
if (rttInMs != -1) item->setText(1, QString::number(rttInMs));
else item->setText(1, "?");
item->setText(2, qPeerId);
item->setText(3, ipAddress);
}
qDeleteAll(existingItems);
}
// --- Graph Source Implementation (Unchanged logic) ---
QString RttGraphSource::unitName() const
{
return QObject::tr("secs") ;
@ -109,8 +213,9 @@ void RttGraphSource::getValues(std::map<std::string,float>& vals) const
for(std::list<RsPeerId>::const_iterator it(idList.begin());it!=idList.end();++it)
{
rsRtt->getPongResults(*it, 1, results);
vals[(*it).toStdString()] = results.back().mRTT ;
if(!results.empty()) {
vals[(*it).toStdString()] = results.back().mRTT ;
}
}
}

View file

@ -18,9 +18,16 @@
* *
*******************************************************************************/
/*******************************************************************************
* gui/statistics/RttStatistics.h *
*******************************************************************************/
#pragma once
#include <QPoint>
#include <QTimer>
#include <QTreeWidget>
#include <QHeaderView>
#include <retroshare/rsrtt.h>
#include <retroshare-gui/RsAutoUpdatePage.h>
@ -47,17 +54,19 @@ public:
class RttStatistics: public MainPage, public Ui::RttStatistics
{
Q_OBJECT
public:
RttStatistics(QWidget *parent = NULL) ;
~RttStatistics();
private slots:
void updateRttValues(); // Slot for table update
private:
void processSettings(bool bLoad);
bool m_bProcessSettings;
RttStatisticsGraph *_tst_CW ;
QTimer *m_timer; // Timer for the table
} ;

View file

@ -6,44 +6,97 @@
<rect>
<x>0</x>
<y>0</y>
<width>611</width>
<height>408</height>
<width>700</width>
<height>500</height>
</rect>
</property>
<property name="windowTitle">
<string>RTT Statistics</string>
</property>
<property name="windowIcon">
<iconset resource="images.qrc">
<normaloff>:/images/logo/logo_16.png</normaloff>:/images/logo/logo_16.png</iconset>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Vertical</enum>
<layout class="QVBoxLayout" name="verticalLayout_Main">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QScrollArea" name="_tunnel_statistics_F">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>593</width>
<height>390</height>
</rect>
</property>
</widget>
<widget class="QWidget" name="tab_graph">
<attribute name="title">
<string>Graph View</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_Graph">
<item row="0" column="0">
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QScrollArea" name="_tunnel_statistics_F">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>100</width>
<height>100</height>
</rect>
</property>
</widget>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_table">
<attribute name="title">
<string>Table View</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_Table">
<item>
<widget class="QTreeWidget" name="treeWidget">
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<column>
<property name="text">
<string>Peer Name</string>
</property>
</column>
<column>
<property name="text">
<string>RTT (ms)</string>
</property>
</column>
<column>
<property name="text">
<string>Node ID</string>
</property>
</column>
<column>
<property name="text">
<string>IP Address</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>