2026-04-06 00:20:51 -05:00

207 lines
6.7 KiB
C++

#include <Client/ConsoleTheme.h>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QDir>
QTextCharFormat ConsoleStyleEntry::toFormat() const
{
QTextCharFormat fmt;
if (color.isValid())
fmt.setForeground(color);
if (bold)
fmt.setFontWeight(QFont::Bold);
if (italic)
fmt.setFontItalic(true);
if (underline)
fmt.setFontUnderline(true);
return fmt;
}
ConsoleStyleEntry ConsoleStyleEntry::fromJson(const QJsonObject& obj)
{
return fromJson(obj, ConsoleStyleEntry());
}
ConsoleStyleEntry ConsoleStyleEntry::fromJson(const QJsonObject& obj, const ConsoleStyleEntry& fallback)
{
ConsoleStyleEntry entry = fallback;
if (obj.contains("color"))
entry.color = QColor(obj["color"].toString());
if (obj.contains("bold"))
entry.bold = obj["bold"].toBool();
if (obj.contains("italic"))
entry.italic = obj["italic"].toBool();
if (obj.contains("underline"))
entry.underline = obj["underline"].toBool();
return entry;
}
QString ConsoleBackground::toStyleSheet(bool showImage) const
{
return QString("background-color: %1; border: 1px solid #2A2A2A; border-radius: 4px;").arg(color.name());
}
QString ConsoleBackground::toColorOnlyStyleSheet() const
{
return QString("background-color: %1; border: 1px solid #2A2A2A; border-radius: 4px;").arg(color.name());
}
ConsoleBackground ConsoleBackground::fromJson(const QJsonObject& obj)
{
ConsoleBackground bg;
if (obj.contains("color"))
bg.color = QColor(obj["color"].toString());
if (obj.contains("image")) {
bg.type = Image;
bg.imagePath = obj["image"].toString();
if (obj.contains("dimming"))
bg.dimming = qBound(0, obj["dimming"].toInt(70), 100);
}
return bg;
}
ConsoleThemeData ConsoleThemeData::fromJson(const QJsonObject& root)
{
ConsoleThemeData theme;
if (root.contains("background"))
theme.background = ConsoleBackground::fromJson(root["background"].toObject());
if (root.contains("text"))
theme.textColor = QColor(root["text"].toString());
// Agent console section
QJsonObject console = root.contains("console") ? root["console"].toObject() : QJsonObject();
if (console.contains("debug"))
theme.debug = ConsoleStyleEntry::fromJson(console["debug"].toObject(), ConsoleStyleEntry(QColor("#606060")));
if (console.contains("status")) {
QJsonObject st = console["status"].toObject();
if (st.contains("success"))
theme.statusSuccess = QColor(st["success"].toString());
if (st.contains("error"))
theme.statusError = QColor(st["error"].toString());
if (st.contains("info"))
theme.statusInfo = QColor(st["info"].toString());
}
if (console.contains("operator"))
theme.operatorStyle = ConsoleStyleEntry::fromJson(console["operator"].toObject(), ConsoleStyleEntry(QColor("#808080")));
if (console.contains("task"))
theme.task = ConsoleStyleEntry::fromJson(console["task"].toObject(), ConsoleStyleEntry(QColor("#606060")));
if (console.contains("agent"))
theme.agent = ConsoleStyleEntry::fromJson(console["agent"].toObject(), ConsoleStyleEntry(QColor("#808080"), false, false, true));
if (console.contains("command"))
theme.command = ConsoleStyleEntry::fromJson(console["command"].toObject(), ConsoleStyleEntry(QColor("#E0E0E0"), true));
if (console.contains("input")) {
QJsonObject inp = console["input"].toObject();
if (inp.contains("symbol"))
theme.input.symbol = inp["symbol"].toString();
theme.input.style = ConsoleStyleEntry::fromJson(inp, ConsoleStyleEntry(QColor("#808080")));
}
// Log section
QJsonObject log = root.contains("log") ? root["log"].toObject() : QJsonObject();
if (log.contains("debug"))
theme.logDebug = ConsoleStyleEntry::fromJson(log["debug"].toObject(), ConsoleStyleEntry(QColor("#606060")));
if (log.contains("operator_connect"))
theme.operatorConnect = ConsoleStyleEntry::fromJson(log["operator_connect"].toObject(), ConsoleStyleEntry(QColor("#E0E0E0")));
if (log.contains("operator_disconnect"))
theme.operatorDisconnect = ConsoleStyleEntry::fromJson(log["operator_disconnect"].toObject(), ConsoleStyleEntry(QColor("#808080")));
if (log.contains("agent_new"))
theme.agentNew = ConsoleStyleEntry::fromJson(log["agent_new"].toObject(), ConsoleStyleEntry(QColor("#39FF14")));
if (log.contains("tunnel"))
theme.tunnel = ConsoleStyleEntry::fromJson(log["tunnel"].toObject(), ConsoleStyleEntry(QColor("#FDFD96")));
if (log.contains("listener_start"))
theme.listenerStart = ConsoleStyleEntry::fromJson(log["listener_start"].toObject(), ConsoleStyleEntry(QColor("#FFA500")));
if (log.contains("listener_stop"))
theme.listenerStop = ConsoleStyleEntry::fromJson(log["listener_stop"].toObject(), ConsoleStyleEntry(QColor("#FFA500")));
return theme;
}
ConsoleThemeManager& ConsoleThemeManager::instance()
{
static ConsoleThemeManager mgr;
return mgr;
}
QString ConsoleThemeManager::userThemeDir()
{
QString dir = QDir(QDir::homePath()).filePath(".adaptix/themes/console");
QDir().mkpath(dir);
return dir;
}
QStringList ConsoleThemeManager::availableThemes() const
{
QStringList themes;
QDir resDir(":/console-themes");
for (const auto& entry : resDir.entryList({"*.json"}, QDir::Files))
themes << QFileInfo(entry).baseName();
QDir userDir(userThemeDir());
for (const auto& entry : userDir.entryList({"*.json"}, QDir::Files)) {
QString name = QFileInfo(entry).baseName();
if (!themes.contains(name))
themes << name;
}
return themes;
}
QString ConsoleThemeManager::resolveThemePath(const QString& name) const
{
QString userPath = userThemeDir() + "/" + name + ".json";
if (QFile::exists(userPath))
return userPath;
return QString(":/console-themes/%1.json").arg(name);
}
void ConsoleThemeManager::loadTheme(const QString& name)
{
m_themeName = name;
QString path = resolveThemePath(name);
QFile file(path);
if (!file.open(QIODevice::ReadOnly)) {
m_theme = ConsoleThemeData();
Q_EMIT themeChanged();
return;
}
QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
file.close();
m_theme = ConsoleThemeData::fromJson(doc.object());
Q_EMIT themeChanged();
}
bool ConsoleThemeManager::importTheme(const QString& filePath)
{
QFileInfo fi(filePath);
if (!fi.exists() || fi.suffix().toLower() != "json")
return false;
QString destDir = userThemeDir();
QString destPath = destDir + "/" + fi.fileName();
if (QFile::exists(destPath))
QFile::remove(destPath);
return QFile::copy(filePath, destPath);
}