213 lines
8.0 KiB
C++
213 lines
8.0 KiB
C++
#include "sessionmodel.h"
|
|
#include "ollie9pclient.h"
|
|
|
|
SessionModel::SessionModel(Ollie9pClient *client, QObject *parent)
|
|
: QAbstractListModel(parent), m_client(client)
|
|
{
|
|
connect(m_client, &Ollie9pClient::sessionsChanged, this, &SessionModel::rebuild);
|
|
connect(m_client, &Ollie9pClient::agentStateChanged, this, &SessionModel::updateAgentState);
|
|
rebuild();
|
|
}
|
|
|
|
int SessionModel::rowCount(const QModelIndex &parent) const
|
|
{
|
|
return parent.isValid() ? 0 : m_rows.size();
|
|
}
|
|
|
|
QVariant SessionModel::data(const QModelIndex &index, int role) const
|
|
{
|
|
if (!index.isValid() || index.row() < 0 || index.row() >= m_rows.size()) return {};
|
|
const Row &r = m_rows.at(index.row());
|
|
switch (role) {
|
|
case TypeRole: return r.type;
|
|
case IdRole: return r.id;
|
|
case ParentIdRole: return r.parentId;
|
|
case AgentIdRole: return r.agentId;
|
|
case LevelRole: return r.level;
|
|
case ExpandedRole: return r.expanded;
|
|
case ParentExpandedRole: return r.parentExpanded;
|
|
case HasChildrenRole: return r.hasChildren;
|
|
case StateRole: return r.state;
|
|
case ModelRole: return r.model;
|
|
case DisplayNameRole: return r.displayName;
|
|
case BaseNameRole: return r.baseName;
|
|
case ConnectionColorRole: return r.connectionColor;
|
|
case PausedRole: return r.paused;
|
|
default: return {};
|
|
}
|
|
}
|
|
|
|
QHash<int, QByteArray> SessionModel::roleNames() const
|
|
{
|
|
return {{TypeRole, "type"}, {IdRole, "id"}, {ParentIdRole, "parentId"},
|
|
{AgentIdRole, "agentId"}, {LevelRole, "level"}, {ExpandedRole, "expanded"},
|
|
{ParentExpandedRole, "parentExpanded"}, {HasChildrenRole, "hasChildren"},
|
|
{StateRole, "state"}, {ModelRole, "model"},
|
|
{DisplayNameRole, "displayName"}, {BaseNameRole, "baseName"},
|
|
{ConnectionColorRole, "connectionColor"}, {PausedRole, "paused"}};
|
|
}
|
|
|
|
QString SessionModel::connectionColor(const QVariantMap &session)
|
|
{
|
|
const bool paused = session.value("paused").toBool();
|
|
const bool connected = session.value("connected").toBool();
|
|
if (paused && connected) return "yellow";
|
|
if (paused) return "gray";
|
|
return connected ? "green" : "red";
|
|
}
|
|
|
|
void SessionModel::appendSession(const QVariantMap &session)
|
|
{
|
|
const QString id = session.value("id").toString();
|
|
const QString name = session.value("name").toString().isEmpty() ? id : session.value("name").toString();
|
|
const QVariantList agents = session.value("agents").toList();
|
|
const bool paused = session.value("paused").toBool();
|
|
const bool expanded = m_expanded.value(id, true);
|
|
m_expanded[id] = expanded;
|
|
|
|
Row row;
|
|
row.type = "session"; row.id = id; row.expanded = expanded; row.paused = paused;
|
|
row.baseName = name;
|
|
row.displayName = agents.isEmpty() ? name : name + " (" + QString::number(agents.size()) + ")";
|
|
row.connectionColor = connectionColor(session);
|
|
m_rows.append(row);
|
|
|
|
// Build agent tree starting from top-level agents (no parent)
|
|
appendAgentTree(id, agents, QString(), 1, expanded, paused);
|
|
}
|
|
|
|
void SessionModel::appendAgentTree(const QString &sessionId, const QVariantList &agents,
|
|
const QString &parentAgentId, int level, bool parentExpanded, bool paused)
|
|
{
|
|
// Find all agents at this level (with matching parentAgentId)
|
|
for (const QVariant &value : agents) {
|
|
const QVariantMap agent = value.toMap();
|
|
const QString agentParent = agent.value("parentAgentId").toString();
|
|
|
|
// Check if this agent belongs at this level
|
|
if (agentParent != parentAgentId) continue;
|
|
|
|
const QString agentId = agent.value("id").toString();
|
|
|
|
// Check if this agent has children
|
|
bool hasChildren = false;
|
|
for (const QVariant &v : agents) {
|
|
if (v.toMap().value("parentAgentId").toString() == agentId) {
|
|
hasChildren = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Track expansion for agents with children
|
|
bool expanded = true;
|
|
if (hasChildren) {
|
|
expanded = m_agentExpanded.value(agentId, true);
|
|
m_agentExpanded[agentId] = expanded;
|
|
}
|
|
|
|
Row child;
|
|
child.type = "agent";
|
|
child.parentId = sessionId;
|
|
child.agentId = agentId;
|
|
child.parentAgentId = parentAgentId;
|
|
child.level = level;
|
|
child.parentExpanded = parentExpanded;
|
|
child.expanded = expanded;
|
|
child.hasChildren = hasChildren;
|
|
child.state = agent.value("state").toString();
|
|
if (child.state.isEmpty()) child.state = "idle";
|
|
child.displayName = agent.value("name").toString();
|
|
child.paused = paused;
|
|
m_rows.append(child);
|
|
|
|
// Recursively add children of this agent (only if expanded and parent is expanded)
|
|
appendAgentTree(sessionId, agents, agentId, level + 1, parentExpanded && expanded, paused);
|
|
}
|
|
}
|
|
|
|
void SessionModel::rebuild()
|
|
{
|
|
beginResetModel();
|
|
m_rows.clear();
|
|
QSet<QString> present;
|
|
bool haveActive = false;
|
|
bool haveInactive = false;
|
|
for (const QVariant &value : m_client->sessions()) {
|
|
const QVariantMap session = value.toMap();
|
|
const bool paused = session.value("paused").toBool();
|
|
if (paused && !haveInactive) {
|
|
Row header; header.type = "header"; header.displayName = "Inactive"; m_rows.append(header); haveInactive = true;
|
|
} else if (!paused && !haveActive) {
|
|
Row header; header.type = "header"; header.displayName = "Active"; m_rows.append(header); haveActive = true;
|
|
}
|
|
const QString id = session.value("id").toString();
|
|
present.insert(id);
|
|
appendSession(session);
|
|
}
|
|
for (auto it = m_expanded.begin(); it != m_expanded.end();) {
|
|
if (!present.contains(it.key())) it = m_expanded.erase(it); else ++it;
|
|
}
|
|
endResetModel();
|
|
emit countChanged();
|
|
}
|
|
|
|
void SessionModel::updateVisibility()
|
|
{
|
|
for (int i = 0; i < m_rows.size(); ++i) {
|
|
if (m_rows[i].type != "session") continue;
|
|
for (int j = i + 1; j < m_rows.size() && m_rows[j].type != "session"; ++j)
|
|
m_rows[j].parentExpanded = m_rows[i].expanded;
|
|
}
|
|
if (!m_rows.isEmpty()) emit dataChanged(index(0), index(m_rows.size() - 1), {ParentExpandedRole, ExpandedRole});
|
|
}
|
|
|
|
void SessionModel::setExpanded(int index, bool expanded)
|
|
{
|
|
if (index < 0 || index >= m_rows.size()) return;
|
|
const Row &row = m_rows[index];
|
|
if (row.type == "session") {
|
|
m_rows[index].expanded = expanded;
|
|
m_expanded[row.id] = expanded;
|
|
} else if (row.type == "agent" && row.hasChildren) {
|
|
m_rows[index].expanded = expanded;
|
|
m_agentExpanded[row.agentId] = expanded;
|
|
} else {
|
|
return;
|
|
}
|
|
rebuild(); // Rebuild to update visibility
|
|
}
|
|
|
|
QVariantMap SessionModel::get(int index) const
|
|
{
|
|
QVariantMap result;
|
|
if (index < 0 || index >= m_rows.size()) return result;
|
|
const Row &r = m_rows.at(index);
|
|
result["type"] = r.type; result["id"] = r.id; result["parentId"] = r.parentId;
|
|
result["agentId"] = r.agentId; result["parentAgentId"] = r.parentAgentId;
|
|
result["level"] = r.level; result["expanded"] = r.expanded;
|
|
result["parentExpanded"] = r.parentExpanded; result["hasChildren"] = r.hasChildren;
|
|
result["state"] = r.state;
|
|
result["model"] = r.model; result["displayName"] = r.displayName;
|
|
result["baseName"] = r.baseName; result["connectionColor"] = r.connectionColor;
|
|
result["paused"] = r.paused; result["name"] = r.displayName;
|
|
return result;
|
|
}
|
|
|
|
QString SessionModel::firstAgentId(const QString &sessionId) const
|
|
{
|
|
for (const Row &row : m_rows)
|
|
if (row.type == "agent" && row.parentId == sessionId) return row.agentId;
|
|
return {};
|
|
}
|
|
|
|
void SessionModel::updateAgentState(const QString &sessionId, const QString &agentId, const QString &state)
|
|
{
|
|
for (int i = 0; i < m_rows.size(); ++i) {
|
|
if (m_rows[i].type == "agent" && m_rows[i].parentId == sessionId && m_rows[i].agentId == agentId) {
|
|
m_rows[i].state = state;
|
|
emit dataChanged(index(i), index(i), {StateRole});
|
|
return;
|
|
}
|
|
}
|
|
}
|