#include "networkstreammodel.h" #include #include 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(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(row) | (static_cast(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(parentId & 0xFFFFFFFF); // Encode: streamIndex in lower 32 bits, networkIndex in upper 32 bits quintptr id = static_cast(row) | (static_cast(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((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(networkIndex) | (static_cast(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((id >> 32) & 0xFFFFFFFF); // If this is a network item, return number of streams if (networkIndex == 0xFFFFFFFF) { int actualNetworkIndex = static_cast(id & 0xFFFFFFFF); if (actualNetworkIndex >= 0 && actualNetworkIndex < m_store->networks().size()) { return static_cast(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((id >> 32) & 0xFFFFFFFF); if (networkIndex == 0xFFFFFFFF) { int actualNetworkIndex = static_cast(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(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(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(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((id >> 32) & 0xFFFFFFFF); // Check if this is a stream item (not a network) if (networkIndex != 0xFFFFFFFF) { int streamIndex = static_cast(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(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((id >> 32) & 0xFFFFFFFF); // Check if this is a stream item (not a network) if (networkIndex == 0xFFFFFFFF) { int actualNetworkIndex = static_cast(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((id >> 32) & 0xFFFFFFFF); // If networkIndex is not 0xFFFFFFFF, this is a stream item return networkIndex != 0xFFFFFFFF; }