feat: show fake statusbar with path
This commit is contained in:
+178
-14
@@ -12,12 +12,14 @@
|
||||
#include <QItemSelectionModel>
|
||||
#include <QLabel>
|
||||
#include <QMenu>
|
||||
#include <QRandomGenerator>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QTimer>
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent), m_trayIcon(nullptr), m_authManager(new AuthManager(this)), m_settingsDialog(nullptr),
|
||||
m_authDialog(nullptr), m_data(nullptr), m_networkStreamModel(nullptr), m_particleListModel(nullptr)
|
||||
m_authDialog(nullptr), m_data(nullptr), m_networkStreamModel(nullptr), m_particleListModel(nullptr),
|
||||
m_selectedParticleRow(-1)
|
||||
{
|
||||
m_authDialog = new AuthDialog(m_authManager, this);
|
||||
|
||||
@@ -25,6 +27,51 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
ui->setupUi(this);
|
||||
// this->setWindowFlags(Qt::FramelessWindowHint);
|
||||
|
||||
// Style for grey status bar text
|
||||
QString statusBarLabelStyle = "QLabel { color: #808080; }";
|
||||
QString pingLabelStyle = "QLabel { color: #00AA00; }"; // Green for ping
|
||||
|
||||
m_currentPathLabel = new QLabel(this);
|
||||
m_currentPathLabel->setMargin(5);
|
||||
m_currentPathLabel->setStyleSheet(statusBarLabelStyle);
|
||||
QFont font = QFont();
|
||||
font.setStyle(QFont::StyleItalic);
|
||||
m_currentPathLabel->setFont(font);
|
||||
ui->statusbar->addWidget(m_currentPathLabel);
|
||||
|
||||
// Add spacer to push right-aligned items to the right
|
||||
ui->statusbar->addPermanentWidget(new QLabel(""), 1);
|
||||
|
||||
// Ping indicator (green text)
|
||||
m_pingLabel = new QLabel(this);
|
||||
m_pingLabel->setMargin(5);
|
||||
m_pingLabel->setMinimumWidth(100);
|
||||
m_pingLabel->setAlignment(Qt::AlignCenter);
|
||||
m_pingLabel->setStyleSheet(pingLabelStyle);
|
||||
ui->statusbar->addPermanentWidget(m_pingLabel);
|
||||
|
||||
// Position indicator (vim-style)
|
||||
m_positionLabel = new QLabel(this);
|
||||
m_positionLabel->setMargin(5);
|
||||
m_positionLabel->setMinimumWidth(50);
|
||||
m_positionLabel->setAlignment(Qt::AlignCenter);
|
||||
m_positionLabel->setStyleSheet(statusBarLabelStyle);
|
||||
ui->statusbar->addPermanentWidget(m_positionLabel);
|
||||
|
||||
// Storage indicator
|
||||
m_storageLabel = new QLabel(this);
|
||||
m_storageLabel->setMargin(5);
|
||||
m_storageLabel->setMinimumWidth(60);
|
||||
m_storageLabel->setAlignment(Qt::AlignCenter);
|
||||
m_storageLabel->setStyleSheet(statusBarLabelStyle);
|
||||
ui->statusbar->addPermanentWidget(m_storageLabel);
|
||||
|
||||
// Setup ping timer to oscillate every 500ms
|
||||
m_pingTimer = new QTimer(this);
|
||||
connect(m_pingTimer, &QTimer::timeout, this, &MainWindow::updatePingIndicator);
|
||||
m_pingTimer->start(500);
|
||||
updatePingIndicator();
|
||||
|
||||
ui->splitter->setStretchFactor(0, 1);
|
||||
ui->splitter->setStretchFactor(1, 1);
|
||||
ui->splitter->setStretchFactor(2, 2);
|
||||
@@ -126,21 +173,15 @@ void MainWindow::setupModels()
|
||||
ui->particlesView->setTextElideMode(Qt::ElideRight);
|
||||
|
||||
// Connect selection changes
|
||||
connect(ui->topLevelParticlesView->selectionModel(),
|
||||
&QItemSelectionModel::selectionChanged,
|
||||
this,
|
||||
connect(ui->topLevelParticlesView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
|
||||
&MainWindow::onTreeSelectionChanged);
|
||||
|
||||
// Connect particle selection changes
|
||||
connect(ui->particlesView->selectionModel(),
|
||||
&QItemSelectionModel::selectionChanged,
|
||||
this,
|
||||
connect(ui->particlesView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
|
||||
&MainWindow::onParticleSelectionChanged);
|
||||
}
|
||||
|
||||
void MainWindow::onTreeSelectionChanged(
|
||||
const QItemSelection &selected,
|
||||
const QItemSelection &deselected)
|
||||
void MainWindow::onTreeSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
|
||||
{
|
||||
Q_UNUSED(deselected);
|
||||
|
||||
@@ -156,6 +197,12 @@ void MainWindow::onTreeSelectionChanged(
|
||||
{
|
||||
QString streamId = m_networkStreamModel->streamIdFromIndex(index);
|
||||
m_particleListModel->setStreamId(streamId);
|
||||
m_selectedStreamId = streamId;
|
||||
|
||||
// Also track the parent network
|
||||
QModelIndex parentIndex = m_networkStreamModel->parent(index);
|
||||
QString networkId = m_networkStreamModel->networkIdFromIndex(parentIndex);
|
||||
m_selectedNetworkName = networkId;
|
||||
|
||||
// Auto-select first unseen particle (or first particle if all seen)
|
||||
int unseenRow = m_particleListModel->firstUnseenRow();
|
||||
@@ -166,32 +213,149 @@ void MainWindow::onTreeSelectionChanged(
|
||||
}
|
||||
else if (m_particleListModel->rowCount() > 0)
|
||||
{
|
||||
ui->particlesView->setCurrentIndex(m_particleListModel->index(0, 0));
|
||||
ui->particlesView->setCurrentIndex(m_particleListModel->index(m_particleListModel->rowCount() - 1, 0));
|
||||
ui->particlesView->setFocus();
|
||||
}
|
||||
}
|
||||
else // network selected
|
||||
{
|
||||
m_particleListModel->setStreamId(QString());
|
||||
m_selectedStreamId.clear();
|
||||
m_selectedParticleRow = -1;
|
||||
|
||||
QString networkId = m_networkStreamModel->networkIdFromIndex(index);
|
||||
m_selectedNetworkName = networkId;
|
||||
}
|
||||
|
||||
updateStatusBar();
|
||||
}
|
||||
|
||||
void MainWindow::onParticleSelectionChanged(
|
||||
const QItemSelection &selected,
|
||||
const QItemSelection &deselected)
|
||||
void MainWindow::onParticleSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
|
||||
{
|
||||
Q_UNUSED(deselected);
|
||||
|
||||
if (selected.indexes().isEmpty())
|
||||
{
|
||||
ui->label->setText("");
|
||||
ui->label_2->setText("");
|
||||
m_selectedParticleId.clear();
|
||||
m_selectedParticleRow = -1;
|
||||
updateStatusBar();
|
||||
return;
|
||||
}
|
||||
|
||||
QModelIndex index = selected.indexes().first();
|
||||
m_selectedParticleRow = index.row();
|
||||
const Particle *particle = m_particleListModel->particleAtRow(index.row());
|
||||
if (particle)
|
||||
{
|
||||
ui->label->setText(particle->summary);
|
||||
ui->label_2->setText(particle->createdBy);
|
||||
m_selectedParticleId = particle->id;
|
||||
}
|
||||
|
||||
updateStatusBar();
|
||||
}
|
||||
|
||||
void MainWindow::updateStatusBar()
|
||||
{
|
||||
QStringList pathComponents;
|
||||
|
||||
// Add network if selected
|
||||
if (!m_selectedNetworkName.isEmpty())
|
||||
{
|
||||
for (const auto &network : m_data->networks())
|
||||
{
|
||||
if (network.id == m_selectedNetworkName)
|
||||
{
|
||||
pathComponents << network.name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add stream if selected
|
||||
if (!m_selectedStreamId.isEmpty() && !m_selectedNetworkName.isEmpty())
|
||||
{
|
||||
const QList<Stream> &streams = m_data->streamsForNetwork(m_selectedNetworkName);
|
||||
for (const auto &stream : streams)
|
||||
{
|
||||
if (stream.id == m_selectedStreamId)
|
||||
{
|
||||
pathComponents << stream.name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add particle if selected
|
||||
if (!m_selectedParticleId.isEmpty() && !m_selectedStreamId.isEmpty())
|
||||
{
|
||||
const QList<Particle> &particles = m_data->particlesForStream(m_selectedStreamId);
|
||||
for (const auto &particle : particles)
|
||||
{
|
||||
if (particle.id == m_selectedParticleId)
|
||||
{
|
||||
pathComponents << particle.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_currentPathLabel->setText(pathComponents.join(" > "));
|
||||
|
||||
// Update position indicator (vim-style)
|
||||
if (!m_selectedStreamId.isEmpty())
|
||||
{
|
||||
int totalCount = m_particleListModel->rowCount();
|
||||
if (totalCount == 0)
|
||||
{
|
||||
m_positionLabel->setText("");
|
||||
}
|
||||
else if (totalCount == 1)
|
||||
{
|
||||
m_positionLabel->setText("All");
|
||||
}
|
||||
else if (m_selectedParticleRow == 0)
|
||||
{
|
||||
m_positionLabel->setText("Top");
|
||||
}
|
||||
else if (m_selectedParticleRow == totalCount - 1)
|
||||
{
|
||||
m_positionLabel->setText("Bot");
|
||||
}
|
||||
else if (m_selectedParticleRow >= 0)
|
||||
{
|
||||
int percent = (m_selectedParticleRow * 100) / (totalCount - 1);
|
||||
m_positionLabel->setText(QString::number(percent) + "%");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_positionLabel->setText("");
|
||||
}
|
||||
|
||||
// Update storage indicator with pseudo-random size based on stream ID
|
||||
uint hash = qHash(m_selectedStreamId);
|
||||
int sizeKB = 50 + (hash % 950); // Random size between 50-1000 kB
|
||||
m_storageLabel->setText(QString::number(sizeKB) + " kB");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_positionLabel->setText("");
|
||||
m_storageLabel->setText("");
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::updatePingIndicator()
|
||||
{
|
||||
// Oscillate ping between 15-35ms
|
||||
static int basePing = 23;
|
||||
int variation = (QRandomGenerator::global()->bounded(21)) - 10; // -10 to +10
|
||||
int currentPing = basePing + variation;
|
||||
if (currentPing < 15)
|
||||
currentPing = 15;
|
||||
if (currentPing > 35)
|
||||
currentPing = 35;
|
||||
|
||||
m_pingLabel->setText("connected " + QString::number(currentPing) + "ms");
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ QT_BEGIN_NAMESPACE
|
||||
class QSystemTrayIcon;
|
||||
class AuthManager;
|
||||
class QItemSelection;
|
||||
class QLabel;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class AuthDialog;
|
||||
@@ -57,6 +58,18 @@ private:
|
||||
Data *m_data;
|
||||
NetworkStreamModel *m_networkStreamModel;
|
||||
ParticleListModel *m_particleListModel;
|
||||
|
||||
void updateStatusBar();
|
||||
void updatePingIndicator();
|
||||
QString m_selectedParticleId;
|
||||
QString m_selectedNetworkName;
|
||||
QString m_selectedStreamId;
|
||||
int m_selectedParticleRow;
|
||||
QLabel *m_currentPathLabel;
|
||||
QLabel *m_positionLabel;
|
||||
QLabel *m_storageLabel;
|
||||
QLabel *m_pingLabel;
|
||||
QTimer *m_pingTimer;
|
||||
};
|
||||
|
||||
#endif // LLINK_MAINWINDOW_H
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "networkstreammodel.h"
|
||||
|
||||
NetworkStreamModel::NetworkStreamModel(Data *data, QObject *parent)
|
||||
: QAbstractItemModel(parent), m_data(data)
|
||||
NetworkStreamModel::NetworkStreamModel(Data *data, QObject *parent) : QAbstractItemModel(parent), m_data(data)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -82,7 +81,7 @@ int NetworkStreamModel::rowCount(const QModelIndex &parent) const
|
||||
int NetworkStreamModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
return 2; // Column 0: name, Column 1: unseen count
|
||||
return 2; // Column 0: name, Column 1: unseen count
|
||||
}
|
||||
|
||||
QVariant NetworkStreamModel::data(const QModelIndex &index, int role) const
|
||||
@@ -103,7 +102,7 @@ QVariant NetworkStreamModel::data(const QModelIndex &index, int role) const
|
||||
int actualNetworkIndex = static_cast<int>(id & 0xFFFFFFFF);
|
||||
if (actualNetworkIndex >= 0 && actualNetworkIndex < m_data->networks().size())
|
||||
{
|
||||
return m_data->networks().at(actualNetworkIndex).name;
|
||||
return m_data->networks().at(actualNetworkIndex).name.toUpper();
|
||||
}
|
||||
}
|
||||
// Networks don't show unseen count in column 1
|
||||
@@ -179,6 +178,29 @@ QString NetworkStreamModel::streamIdFromIndex(const QModelIndex &index) const
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString NetworkStreamModel::networkIdFromIndex(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
quintptr id = index.internalId();
|
||||
int networkIndex = static_cast<int>((id >> 32) & 0xFFFFFFFF);
|
||||
|
||||
// Check if this is a stream item (not a network)
|
||||
if (networkIndex == 0xFFFFFFFF)
|
||||
{
|
||||
int actualNetworkIndex = static_cast<int>(id & 0xFFFFFFFF);
|
||||
if (actualNetworkIndex >= 0 && actualNetworkIndex < m_data->networks().size())
|
||||
{
|
||||
return m_data->networks().at(actualNetworkIndex).id;
|
||||
}
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool NetworkStreamModel::isStreamItem(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
|
||||
@@ -21,6 +21,7 @@ public:
|
||||
// Helper methods for MainWindow
|
||||
QString streamIdFromIndex(const QModelIndex &index) const;
|
||||
bool isStreamItem(const QModelIndex &index) const;
|
||||
QString networkIdFromIndex(const QModelIndex &index) const;
|
||||
|
||||
private:
|
||||
Data *m_data;
|
||||
|
||||
Reference in New Issue
Block a user