ollie/kde/gui/sessionmodel.cpp

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;
}
}
}