setup electron app with boilerplate
This commit is contained in:
@@ -0,0 +1,259 @@
|
||||
#include "networkstreammodel.h"
|
||||
#include <QBrush>
|
||||
#include <QColor>
|
||||
|
||||
NetworkStreamModel::NetworkStreamModel(Store *store, QObject *parent) : QAbstractItemModel(parent), m_store(store)
|
||||
{
|
||||
connect(m_store, &Store::networksChanged, this, [this]() {
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
});
|
||||
connect(m_store, &Store::streamsChanged, this, [this]() {
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
});
|
||||
|
||||
// Granular update: repaint a single stream row when its properties change (e.g. unseen count)
|
||||
connect(m_store, &Store::streamUpdated, this, [this](const QString &streamId) {
|
||||
const auto &networks = m_store->networks();
|
||||
for (int ni = 0; ni < networks.size(); ++ni)
|
||||
{
|
||||
const auto &streams = networks.at(ni).streams;
|
||||
for (int si = 0; si < static_cast<int>(streams.size()); ++si)
|
||||
{
|
||||
if (streams[si].id == streamId)
|
||||
{
|
||||
// Build indices for both columns of this stream row
|
||||
QModelIndex topLeft = index(si, 0, index(ni, 0));
|
||||
QModelIndex bottomRight = index(si, 1, index(ni, 0));
|
||||
emit dataChanged(topLeft, bottomRight, {Qt::DisplayRole, Qt::ForegroundRole});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QModelIndex NetworkStreamModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
if (!hasIndex(row, column, parent))
|
||||
{
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
if (!parent.isValid())
|
||||
{
|
||||
// Top-level item (Network)
|
||||
// Encode: networkIndex in lower 32 bits, -1 in upper 32 bits
|
||||
quintptr id = static_cast<quintptr>(row) | (static_cast<quintptr>(0xFFFFFFFF) << 32);
|
||||
return createIndex(row, column, id);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Child item (Stream)
|
||||
// Decode parent to get network index
|
||||
quintptr parentId = parent.internalId();
|
||||
int networkIndex = static_cast<int>(parentId & 0xFFFFFFFF);
|
||||
|
||||
// Encode: streamIndex in lower 32 bits, networkIndex in upper 32 bits
|
||||
quintptr id = static_cast<quintptr>(row) | (static_cast<quintptr>(networkIndex) << 32);
|
||||
return createIndex(row, column, id);
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex NetworkStreamModel::parent(const QModelIndex &child) const
|
||||
{
|
||||
if (!child.isValid())
|
||||
{
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
quintptr id = child.internalId();
|
||||
int networkIndex = static_cast<int>((id >> 32) & 0xFFFFFFFF);
|
||||
|
||||
// If networkIndex is 0xFFFFFFFF, this is a network item (no parent)
|
||||
if (networkIndex == 0xFFFFFFFF)
|
||||
{
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
// This is a stream item, return its parent network
|
||||
quintptr parentId = static_cast<quintptr>(networkIndex) | (static_cast<quintptr>(0xFFFFFFFF) << 32);
|
||||
return createIndex(networkIndex, 0, parentId);
|
||||
}
|
||||
|
||||
int NetworkStreamModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (!parent.isValid())
|
||||
{
|
||||
// Root level - return number of networks
|
||||
return m_store->networkCount();
|
||||
}
|
||||
|
||||
quintptr id = parent.internalId();
|
||||
int networkIndex = static_cast<int>((id >> 32) & 0xFFFFFFFF);
|
||||
|
||||
// If this is a network item, return number of streams
|
||||
if (networkIndex == 0xFFFFFFFF)
|
||||
{
|
||||
int actualNetworkIndex = static_cast<int>(id & 0xFFFFFFFF);
|
||||
if (actualNetworkIndex >= 0 && actualNetworkIndex < m_store->networks().size())
|
||||
{
|
||||
return static_cast<int>(m_store->networks().at(actualNetworkIndex).streams.size());
|
||||
}
|
||||
}
|
||||
|
||||
// Stream items have no children
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NetworkStreamModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
return 2; // Column 0: name, Column 1: unseen count
|
||||
}
|
||||
|
||||
QVariant NetworkStreamModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
quintptr id = index.internalId();
|
||||
int networkIndex = static_cast<int>((id >> 32) & 0xFFFFFFFF);
|
||||
|
||||
if (networkIndex == 0xFFFFFFFF)
|
||||
{
|
||||
int actualNetworkIndex = static_cast<int>(id & 0xFFFFFFFF);
|
||||
// This is a network item
|
||||
if (role == Qt::DisplayRole && index.column() == 0)
|
||||
{
|
||||
if (actualNetworkIndex >= 0 && actualNetworkIndex < m_store->networks().size())
|
||||
{
|
||||
return m_store->networks().at(actualNetworkIndex).name.toUpper();
|
||||
}
|
||||
} else if (role == Qt::DisplayRole && index.column() == 1)
|
||||
{
|
||||
if (actualNetworkIndex >= 0 && actualNetworkIndex < m_store->networks().size())
|
||||
{
|
||||
auto net = m_store->networks().at(actualNetworkIndex);
|
||||
return QString("%1/%2").arg(net.openStreamCount).arg(net.openStreamCapacity);
|
||||
}
|
||||
}
|
||||
// Networks don't show unseen count in column 1
|
||||
return QVariant();
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a stream item
|
||||
int streamIndex = static_cast<int>(id & 0xFFFFFFFF);
|
||||
if (networkIndex >= 0 && networkIndex < m_store->networks().size())
|
||||
{
|
||||
const auto &streams = m_store->networks().at(networkIndex).streams;
|
||||
|
||||
if (streamIndex >= 0 && streamIndex < static_cast<int>(streams.size()))
|
||||
{
|
||||
const Stream &stream = streams.at(streamIndex);
|
||||
|
||||
if (role == Qt::DisplayRole)
|
||||
{
|
||||
if (index.column() == 0)
|
||||
{
|
||||
// Column 0: stream name
|
||||
return stream.name;
|
||||
}
|
||||
else if (index.column() == 1)
|
||||
{
|
||||
// Column 1: unseen count (only show if > 0)
|
||||
if (stream.unseenCount > 0)
|
||||
{
|
||||
return stream.unseenCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (role == Qt::TextAlignmentRole && index.column() == 1)
|
||||
{
|
||||
// Right-align the unseen count
|
||||
return static_cast<int>(Qt::AlignRight | Qt::AlignVCenter);
|
||||
}
|
||||
else if (role == Qt::ForegroundRole)
|
||||
{
|
||||
// Make streams with no unseen items grey (fully caught up)
|
||||
if (stream.unseenCount == 0)
|
||||
{
|
||||
return QBrush(QColor(128, 128, 128));
|
||||
}
|
||||
// Streams with unseen items use default color
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QString NetworkStreamModel::streamIdFromIndex(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 streamIndex = static_cast<int>(id & 0xFFFFFFFF);
|
||||
if (networkIndex >= 0 && networkIndex < m_store->networks().size())
|
||||
{
|
||||
const auto &streams = m_store->networks().at(networkIndex).streams;
|
||||
|
||||
if (streamIndex >= 0 && streamIndex < static_cast<int>(streams.size()))
|
||||
{
|
||||
return streams.at(streamIndex).id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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_store->networks().size())
|
||||
{
|
||||
return m_store->networks().at(actualNetworkIndex).id;
|
||||
}
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool NetworkStreamModel::isStreamItem(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
quintptr id = index.internalId();
|
||||
int networkIndex = static_cast<int>((id >> 32) & 0xFFFFFFFF);
|
||||
|
||||
// If networkIndex is not 0xFFFFFFFF, this is a stream item
|
||||
return networkIndex != 0xFFFFFFFF;
|
||||
}
|
||||
Reference in New Issue
Block a user