Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
+404
@@ -0,0 +1,404 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
*
|
||||
* MainWindow for settings editor
|
||||
*
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "main_window.h"
|
||||
#include "ui_main_window.h"
|
||||
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
|
||||
#include <QAction>
|
||||
#include <QFile>
|
||||
#include <QFileDialog>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
|
||||
namespace SettingsEditor
|
||||
{
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: NGLMainWindow(parent)
|
||||
, m_ui(new Ui::MainWindow)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
enableTextEdit(false);
|
||||
|
||||
QMenu *fileMenu = m_menu[QLatin1String("File")];
|
||||
fileMenu->addSeparator();
|
||||
|
||||
QAction *action;
|
||||
action = new QAction(tr("Load Settings"), this);
|
||||
action->setShortcut(QKeySequence(tr("Ctrl+l")));
|
||||
connect(action, &QAction::triggered, this, &MainWindow::onLoadFromExport);
|
||||
fileMenu->addAction(action);
|
||||
|
||||
action = new QAction(tr("Save Settings"), this);
|
||||
action->setShortcut(QKeySequence(tr("Ctrl+s")));
|
||||
connect(action, &QAction::triggered, this, &MainWindow::onSaveSettings);
|
||||
fileMenu->addAction(action);
|
||||
|
||||
action = new QAction(tr("Export Settings"), this);
|
||||
action->setShortcut(QKeySequence(tr("Ctrl+e")));
|
||||
connect(action, &QAction::triggered, this, &MainWindow::onExportSettings);
|
||||
fileMenu->addAction(action);
|
||||
|
||||
action = new QAction(tr("Load Default"), this);
|
||||
action->setShortcut(QKeySequence(tr("Ctrl+d")));
|
||||
connect(action, &QAction::triggered, this, &MainWindow::onLoadPresetFromTemplate);
|
||||
fileMenu->addAction(action);
|
||||
|
||||
onLoadPresetFromTemplate();
|
||||
|
||||
m_ui->twPath->expandAll();
|
||||
|
||||
connect(m_ui->twPath, &QTreeWidget::currentItemChanged, this, &MainWindow::oncurrentItemChanged);
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
void MainWindow::oncurrentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
|
||||
{
|
||||
if (previous)
|
||||
{
|
||||
if (previous->parent())
|
||||
{
|
||||
QPair<SettingType, QVariant> value = m_data.value(craftKey(previous->parent()->text(0), previous->text(0)));
|
||||
|
||||
switch (value.first)
|
||||
{
|
||||
case StringList:
|
||||
value.second = QVariant(m_ui->teValueEdit->toPlainText().split(QRegularExpression{QStringLiteral(R"-((\r\n?|\n))-")}));
|
||||
break;
|
||||
case FunctionKeys:
|
||||
value.second = QVariant(m_ui->functionKeysEdit->value());
|
||||
break;
|
||||
case Json:
|
||||
case String:
|
||||
value.second = QVariant(m_ui->teValueEdit->toPlainText());
|
||||
break;
|
||||
case Boolean:
|
||||
value.second = m_ui->cbBoolValue->isChecked();
|
||||
break;
|
||||
}
|
||||
const QString key(craftKey(previous->parent()->text(0), previous->text(0)));
|
||||
if (m_data[key] != value)
|
||||
{
|
||||
setWindowModified(true);
|
||||
m_data[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (current)
|
||||
{
|
||||
if (current->parent())
|
||||
{
|
||||
const auto it = m_data.constFind(craftKey(current->parent()->text(0), current->text(0)));
|
||||
const QVariant &val = it.value().second;
|
||||
switch (it.value().first)
|
||||
{
|
||||
case StringList:
|
||||
enableTextEdit();
|
||||
m_ui->teValueEdit->setPlainText(val.toStringList().join(QLatin1Char('\n')));
|
||||
break;
|
||||
case Json:
|
||||
enableTextEdit();
|
||||
m_ui->teValueEdit->setPlainText(val.toString());
|
||||
break;
|
||||
case String:
|
||||
enableTextEdit();
|
||||
m_ui->teValueEdit->setPlainText(val.toString());
|
||||
break;
|
||||
case FunctionKeys:
|
||||
enableFunctionKeyEdit();
|
||||
m_ui->functionKeysEdit->setValue(val);
|
||||
break;
|
||||
case Boolean:
|
||||
enableBoolEdit();
|
||||
m_ui->cbBoolValue->setChecked(val.toBool());
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
enableTextEdit(false);
|
||||
}
|
||||
else
|
||||
enableTextEdit(false);
|
||||
}
|
||||
|
||||
void MainWindow::onSaveSettings()
|
||||
{
|
||||
if (saveSettings(m_settingsFileName))
|
||||
setWindowModified(false);
|
||||
}
|
||||
|
||||
void MainWindow::onExportSettings()
|
||||
{
|
||||
// save current data in edit field
|
||||
oncurrentItemChanged(m_ui->twPath->currentItem(), m_ui->twPath->currentItem());
|
||||
|
||||
const QString filename = QFileDialog::getSaveFileName(this,
|
||||
tr("Save File"),
|
||||
QStringLiteral("project_settings.json"),
|
||||
tr("Project Settings files (*.json)"));
|
||||
saveSettings(filename);
|
||||
}
|
||||
|
||||
bool MainWindow::saveSettings(const QString &filename)
|
||||
{
|
||||
if (filename.isEmpty())
|
||||
return false;
|
||||
|
||||
QFile f(filename);
|
||||
if (!f.open(QIODevice::WriteOnly))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Error writing file"),
|
||||
tr("Could not write file '%1', error: %2").arg(filename, f.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonObject obj;
|
||||
for (int t = 0; t < m_ui->twPath->topLevelItemCount(); ++t)
|
||||
{
|
||||
QJsonObject tlObj;
|
||||
const QTreeWidgetItem *tlItem = m_ui->twPath->topLevelItem(t);
|
||||
for (int g = 0; g < tlItem->childCount(); ++g)
|
||||
{
|
||||
QJsonObject groupObj;
|
||||
const QTreeWidgetItem *groupItem = tlItem->child(g);
|
||||
const QString groupName = groupItem->text(0);
|
||||
for (int i = 0; i < groupItem->childCount(); ++i)
|
||||
{
|
||||
const QTreeWidgetItem *item = groupItem->child(i);
|
||||
const QString itemName = item->text(0);
|
||||
const QString key = craftKey(groupName, itemName);
|
||||
const QString type = typeToString(m_data[craftKey(groupName, itemName)].first);
|
||||
QJsonValue val;
|
||||
switch (m_data[craftKey(groupName, itemName)].first)
|
||||
{
|
||||
case String:
|
||||
val = m_data[key].second.toString();
|
||||
break;
|
||||
case FunctionKeys:
|
||||
val = m_data[key].second.toString();
|
||||
break;
|
||||
case Json:
|
||||
val = QJsonDocument::fromJson(m_data[key].second.toByteArray()).object();
|
||||
break;
|
||||
case StringList:
|
||||
{
|
||||
QJsonArray arr;
|
||||
const QStringList sl = m_data[key].second.toStringList();
|
||||
for (const QString &s : sl)
|
||||
arr.append(s);
|
||||
val = arr;
|
||||
break;
|
||||
}
|
||||
case Boolean:
|
||||
val = m_data[key].second.toBool();
|
||||
break;
|
||||
}
|
||||
groupObj[itemName] = QJsonObject{{QStringLiteral("Default"), val}, {QStringLiteral("Type"), type}};
|
||||
}
|
||||
tlObj[groupName] = groupObj;
|
||||
}
|
||||
obj[tlItem->text(0)] = tlObj;
|
||||
}
|
||||
QJsonDocument doc(obj);
|
||||
f.write(doc.toJson());
|
||||
f.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainWindow::onLoadFromExport()
|
||||
{
|
||||
const QString filename = QFileDialog::getOpenFileName(this,
|
||||
tr("Load File"),
|
||||
QString(),
|
||||
tr("Project Settings files (*.json)"));
|
||||
|
||||
if (filename.isEmpty())
|
||||
return;
|
||||
|
||||
QFile input(filename);
|
||||
if (!input.open(QIODevice::ReadOnly))
|
||||
return;
|
||||
|
||||
if (loadSettings(filename))
|
||||
{
|
||||
m_settingsFileName = filename;
|
||||
setWindowTitle(filename + QStringLiteral("[*]"));
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onLoadPresetFromTemplate()
|
||||
{
|
||||
loadSettings(QStringLiteral(":/project_settings.json"));
|
||||
}
|
||||
|
||||
bool MainWindow::loadSettings(const QString &filename)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Loading settings from " << filename;
|
||||
QFile f(filename);
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Error reading file"),
|
||||
tr("Could not read file '%1', error: %2").arg(filename, f.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool firstLoad = m_data.isEmpty();
|
||||
|
||||
QJsonParseError jErr;
|
||||
const QByteArray ba = f.readAll();
|
||||
const QJsonObject settings = QJsonDocument::fromJson(ba, &jErr).object();
|
||||
if (jErr.error != QJsonParseError::NoError)
|
||||
{
|
||||
if (jErr.offset >= 0)
|
||||
{
|
||||
QByteArray code = ba.mid(jErr.offset - 40, 80);
|
||||
QMessageBox::warning(this, tr("Json parser error"),
|
||||
tr("%1 (fragment: '%2')").arg(jErr.errorString(), QString::fromUtf8(code)));
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning(this, tr("Json parser error"),
|
||||
jErr.errorString());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const QStringList &settingsKeys = settings.keys();
|
||||
|
||||
for (const auto &setting : settingsKeys)
|
||||
{
|
||||
QTreeWidgetItem *settingTreeItem = firstLoad ? new QTreeWidgetItem(m_ui->twPath, QStringList(setting)) : nullptr; // only build tree on first load
|
||||
|
||||
const QJsonObject groups = settings.value(setting).toObject();
|
||||
const QStringList &groupKeys = groups.keys();
|
||||
for (const auto &group : groupKeys)
|
||||
{
|
||||
QTreeWidgetItem *groupTreeItem = firstLoad ? new QTreeWidgetItem(settingTreeItem, QStringList(group)) : nullptr; // only build tree on first load
|
||||
const QStringList &itemKeys = groups[group].toObject().keys();
|
||||
for (const auto &key : itemKeys)
|
||||
{
|
||||
if (groupTreeItem)
|
||||
groupTreeItem->addChild(new QTreeWidgetItem(QStringList(key)));
|
||||
|
||||
const QJsonObject obj = groups[group].toObject()[key].toObject();
|
||||
const auto strType = obj[QStringLiteral("Type")].toString();
|
||||
const auto type = stringToType(strType);
|
||||
const QJsonValue jVal =obj[QStringLiteral("Default")];
|
||||
QVariant val;
|
||||
switch (type)
|
||||
{
|
||||
case Json:
|
||||
val = QJsonDocument(jVal.toObject()).toJson();
|
||||
break;
|
||||
case StringList:
|
||||
{
|
||||
const QJsonArray arr = jVal.toArray();
|
||||
QStringList sl;
|
||||
sl.reserve(arr.size());
|
||||
for (const auto &ele : arr)
|
||||
sl.push_back(ele.toString());
|
||||
val = sl;
|
||||
break;
|
||||
}
|
||||
case FunctionKeys:
|
||||
val = jVal.toVariant();
|
||||
break;
|
||||
case String:
|
||||
val = jVal.toString();
|
||||
break;
|
||||
case Boolean:
|
||||
val = jVal.toBool();
|
||||
break;
|
||||
}
|
||||
m_data.insert(craftKey(group, key), qMakePair(type, val));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// load new data into edit field
|
||||
oncurrentItemChanged(m_ui->twPath->currentItem(), nullptr); // nullptr -> prevent saving existing data
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainWindow::enableTextEdit(bool enabled)
|
||||
{
|
||||
m_ui->stackedWidget->setCurrentIndex(0);
|
||||
m_ui->teValueEdit->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void MainWindow::enableFunctionKeyEdit()
|
||||
{
|
||||
m_ui->stackedWidget->setCurrentIndex(2);
|
||||
}
|
||||
|
||||
void MainWindow::enableBoolEdit()
|
||||
{
|
||||
m_ui->stackedWidget->setCurrentIndex(1);
|
||||
}
|
||||
|
||||
void MainWindow::setVersionView()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString MainWindow::craftKey(const QString &group, const QString &key)
|
||||
{
|
||||
return group + QLatin1Char('.') + key;
|
||||
}
|
||||
|
||||
QString MainWindow::typeToString(SettingType t)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case String:
|
||||
return QStringLiteral("String");
|
||||
case StringList:
|
||||
return QStringLiteral("StringList");
|
||||
case Json:
|
||||
return QStringLiteral("Json");
|
||||
case FunctionKeys:
|
||||
return QStringLiteral("FunctionKeys");
|
||||
case Boolean:
|
||||
return QStringLiteral("Boolean");
|
||||
}
|
||||
Q_ASSERT(false);
|
||||
return QStringLiteral("Unknown (%1)").arg(t);
|
||||
}
|
||||
|
||||
MainWindow::SettingType MainWindow::stringToType(const QString &s)
|
||||
{
|
||||
if (s == typeToString(String))
|
||||
return String;
|
||||
if (s == typeToString(StringList))
|
||||
return StringList;
|
||||
if (s == typeToString(Json))
|
||||
return Json;
|
||||
if (s == typeToString(FunctionKeys))
|
||||
return FunctionKeys;
|
||||
if (s == typeToString(Boolean))
|
||||
return Boolean;
|
||||
Q_ASSERT(false);
|
||||
return String;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user