switched to nlohmann Json

This commit is contained in:
Anthony Rabine 2023-05-14 23:02:06 +02:00
parent ca36d4ac32
commit 868d4fdc8e
8 changed files with 198 additions and 200 deletions

View file

@ -556,71 +556,15 @@ void MainWindow::OpenProjectDialog()
void MainWindow::OpenProject(const QString &filePath)
{
bool success = false;
QString errorMsg;
QString errorMsg = tr("General error");
m_project.Initialize(filePath.toStdString());
QFile loadFile(m_project.GetProjectFilePath().c_str());
nlohmann::json model;
if (loadFile.open(QIODevice::ReadOnly))
{
QJsonParseError err;
QJsonDocument loadDoc = QJsonDocument::fromJson(loadFile.readAll(), &err);
if (err.error == QJsonParseError::NoError)
{
QJsonObject projectRoot = loadDoc.object();
if (projectRoot.contains("project"))
{
QJsonObject projectData = projectRoot["project"].toObject();
m_project.SetName(projectData["name"].toString().toStdString());
m_project.SetUuid(projectData["uuid"].toString().toStdString());
QJsonArray resourcesData = projectData["resources"].toArray();
for (const auto &r : resourcesData)
{
Resource rData;
QJsonObject obj = r.toObject();
rData.type = obj["type"].toString().toStdString();
rData.format = obj["format"].toString().toStdString();
rData.description = obj["description"].toString().toStdString();
rData.file = obj["file"].toString().toStdString();
m_resourcesDock->Append(rData);
}
if (projectRoot.contains("nodegraph"))
{
QJsonObject nodeData = projectRoot["nodegraph"].toObject();
m_model.load(nodeData);
success = true;
}
else
{
errorMsg = tr("Missing nodegraph section in JSON file.");
}
}
else
{
errorMsg = tr("Missing project section in JSON file.");
}
}
else
{
errorMsg = err.errorString();
}
}
else
{
errorMsg = tr("Could not open project file.");
}
if (success)
if (m_project.Load(filePath.toStdString(), model))
{
m_model.Load(model);
EnableProject();
}
else
@ -633,41 +577,8 @@ void MainWindow::OpenProject(const QString &filePath)
void MainWindow::SaveProject()
{
QJsonObject jsonModel = m_model.save();
// QJsonObject jsonModel = m_model.save();
QJsonObject projectData;
projectData["name"] = m_project.GetName().c_str();
projectData["uuid"] = m_project.GetUuid().c_str();
QJsonArray resourcesData;
for (std::vector<Resource>::const_iterator it = m_project.Begin(); it != m_project.End(); ++it)
{
auto &r = *it;
QJsonObject obj;
obj["type"] = r.type.c_str();
obj["format"] = r.format.c_str();
obj["description"] = r.description.c_str();
obj["file"] = r.file.c_str();
resourcesData.append(obj);
}
projectData["resources"] = resourcesData;
QJsonObject saveData;
saveData["project"] = projectData;
saveData["nodegraph"] = jsonModel;
QJsonDocument doc(saveData);
qDebug() << doc.toJson();
QFile f(m_project.GetProjectFilePath().c_str());
if (!f.open(QIODevice::WriteOnly | QIODevice::Text))
return;
QTextStream fout(&f);
fout << doc.toJson();
statusBar()->showMessage(tr("Saved '%1'").arg(m_project.GetProjectFilePath().c_str()), 2000);
}

View file

@ -9,6 +9,7 @@
#include <QtWidgets/QFileDialog>
#include <QMenu>
MediaNodeModel::MediaNodeModel(StoryGraphModel &model)
: m_model(model)
, m_widget(new QWidget())
@ -46,27 +47,25 @@ MediaNodeModel::MediaNodeModel(StoryGraphModel &model)
});
}
QJsonObject MediaNodeModel::save() const
nlohmann::json MediaNodeModel::ToJson() const
{
QJsonObject obj = NodeDelegateModel::save();
// Always start with generic
nlohmann::json j = StoryNodeBase::ToJson();
// Merge two objects
QVariantMap map = obj.toVariantMap();
map.insert(m_mediaData);
return QJsonObject::fromVariantMap(map);
j.merge_patch(m_mediaData);
return j;
}
void MediaNodeModel::load(const QJsonObject &mediaData)
void MediaNodeModel::FromJson(nlohmann::json &j)
{
m_mediaData = mediaData.toVariantMap();
m_mediaData = j;
// Display loaded image
QString imagePath = m_mediaData["image"].toString();
std::string imagePath = m_mediaData["image"].get<std::string>();
if (!imagePath.isEmpty())
if (imagePath.size() > 0)
{
setImage(imagePath);
setImage(imagePath.c_str());
}
}
@ -76,7 +75,7 @@ void MediaNodeModel::setImage(const QString &imagePath)
if (pix.isNull())
{
std::cout << "!!!!!!! " << m_mediaData["image"].toString().toStdString() << std::endl;
std::cout << "!!!!!!! " << m_mediaData["image"].get<std::string>() << std::endl;
}
int w = m_ui.image->width();
@ -85,15 +84,14 @@ void MediaNodeModel::setImage(const QString &imagePath)
m_ui.image->setPixmap(pix);
}
void MediaNodeModel::setInternalData(const QVariant &value)
void MediaNodeModel::setInternalData(const nlohmann::json &j)
{
QJsonObject obj = value.toJsonObject();
if (obj.contains("image")) {
setImage(obj.value("image").toString());
if (j.contains("image")) {
setImage(j["image"].get<std::string>().c_str());
}
// Merge new data into local object
m_mediaData.insert(obj.toVariantMap());
m_mediaData.merge_patch(j);
}
unsigned int MediaNodeModel::nPorts(PortType portType) const

View file

@ -36,11 +36,10 @@ public:
QString name() const override { return QString("MediaNode"); }
public:
QJsonObject save() const override;
virtual nlohmann::json ToJson() const override;
virtual void FromJson(nlohmann::json &j) override;
void load(QJsonObject const &mediaData) override;
void setInternalData(const QVariant &value) override;
void setInternalData(const nlohmann::json &j) override;
public:
virtual QString modelName() const { return QString("MediaNode"); }
@ -57,6 +56,7 @@ public:
bool resizable() const override { return true; }
protected:
bool eventFilter(QObject *object, QEvent *event) override;
@ -69,6 +69,6 @@ private:
Ui::mediaNodeUi m_ui;
std::shared_ptr<NodeData> m_nodeData;
QVariantMap m_mediaData;
nlohmann::json m_mediaData;
void setImage(const QString &fileName);
};

View file

@ -176,6 +176,17 @@ QVariant StoryGraphModel::nodeData(NodeId nodeId, NodeRole role) const
return result;
}
void StoryGraphModel::SetInternalData(NodeId nodeId, nlohmann::json &j)
{
auto it = _models.find(nodeId);
if (it == _models.end())
return;
auto &model = it->second;
model->setInternalData(j);
}
bool StoryGraphModel::setNodeData(NodeId nodeId, NodeRole role, QVariant value)
{
bool result = false;
@ -212,10 +223,8 @@ bool StoryGraphModel::setNodeData(NodeId nodeId, NodeRole role, QVariant value)
break;
case NodeRole::InternalData:
{
model->setInternalData(value);
break;
}
case NodeRole::InPortCount:
break;
@ -307,9 +316,63 @@ bool StoryGraphModel::deleteNode(NodeId const nodeId)
return true;
}
QJsonObject StoryGraphModel::saveNode(NodeId const nodeId) const
namespace QtNodes {
void to_json(nlohmann::json& j, const ConnectionId& p) {
j = nlohmann::json{
{"outNodeId", static_cast<qint64>(p.outNodeId)},
{"outPortIndex", static_cast<qint64>(p.outPortIndex)},
{"intNodeId", static_cast<qint64>(p.inNodeId)},
{"inPortIndex", static_cast<qint64>(p.inPortIndex)},
};
}
void from_json(const nlohmann::json& j, ConnectionId& p) {
// j.at("name").get_to(p.name);
// j.at("address").get_to(p.address);
// j.at("age").get_to(p.age);
}
} // namespace QtNodes
nlohmann::json StoryGraphModel::Save() const
{
QJsonObject nodeJson;
nlohmann::json j;
nlohmann::json nodesJsonArray;
for (auto const nodeId : allNodeIds()) {
nodesJsonArray.push_back(SaveNode(nodeId));
}
j["nodes"] = nodesJsonArray;
nlohmann::json connJsonArray;
for (auto const &cid : _connectivity) {
nlohmann::json o = cid;
connJsonArray.push_back(o);
}
j["connections"] = connJsonArray;
return j;
}
void StoryGraphModel::Load(const nlohmann::json &j)
{
nlohmann::json nodesJsonArray = j["nodes"];
for (auto& element : nodesJsonArray) {
LoadNode(element);
}
nlohmann::json connectionJsonArray = j["connections"];
for (auto& connection : connectionJsonArray) {
ConnectionId connId = connection.get<QtNodes::ConnectionId>();
// Restore the connection
addConnection(connId);
}
}
nlohmann::json StoryGraphModel::SaveNode(NodeId const nodeId) const
{
nlohmann::json nodeJson;
nodeJson["id"] = static_cast<qint64>(nodeId);
auto it = _models.find(nodeId);
@ -318,43 +381,25 @@ QJsonObject StoryGraphModel::saveNode(NodeId const nodeId) const
auto &model = it->second;
nodeJson["internal-data"] = model->save();
nodeJson["internal-data"] = model->ToJson();
{
QPointF const pos = nodeData(nodeId, NodeRole::Position).value<QPointF>();
QJsonObject posJson;
nlohmann::json posJson;
posJson["x"] = pos.x();
posJson["y"] = pos.y();
nodeJson["position"] = posJson;
nodeJson["inPortCount"] = QString::number(nodeData(nodeId, NodeRole::InPortCount).value<int>());
nodeJson["outPortCount"] = QString::number(nodeData(nodeId, NodeRole::OutPortCount).value<int>());
nodeJson["inPortCount"] = nodeData(nodeId, NodeRole::InPortCount).value<int>();
nodeJson["outPortCount"] = nodeData(nodeId, NodeRole::OutPortCount).value<int>();
}
return nodeJson;
}
QJsonObject StoryGraphModel::save() const
{
QJsonObject sceneJson;
QJsonArray nodesJsonArray;
for (auto const nodeId : allNodeIds()) {
nodesJsonArray.append(saveNode(nodeId));
}
sceneJson["nodes"] = nodesJsonArray;
QJsonArray connJsonArray;
for (auto const &cid : _connectivity) {
connJsonArray.append(QtNodes::toJson(cid));
}
sceneJson["connections"] = connJsonArray;
return sceneJson;
}
void StoryGraphModel::loadNode(QJsonObject const &nodeJson)
void StoryGraphModel::LoadNode(const nlohmann::json &nodeJson)
{
// Possibility of the id clash when reading it from json and not generating a
// new value.
@ -363,17 +408,17 @@ void StoryGraphModel::loadNode(QJsonObject const &nodeJson)
// loading.
// 2. When undoing the deletion command. Conflict is not possible
// because all the new ids were created past the removed nodes.
NodeId restoredNodeId = nodeJson["id"].toInt();
NodeId restoredNodeId = nodeJson["id"].get<int>();
_nextNodeId = std::max(_nextNodeId, restoredNodeId + 1);
QJsonObject const internalDataJson = nodeJson["internal-data"].toObject();
nlohmann::json internalDataJson = nodeJson["internal-data"];
QString delegateModelName = internalDataJson["model-name"].toString();
std::string delegateModelName = internalDataJson["model-name"].get<std::string>();
// std::unique_ptr<NodeDelegateModel> model = _registry->create(delegateModelName);
auto model = createNode(delegateModelName.toStdString());
auto model = createNode(delegateModelName);
if (model) {
// connect(model.get(),
@ -389,37 +434,18 @@ void StoryGraphModel::loadNode(QJsonObject const &nodeJson)
Q_EMIT nodeCreated(restoredNodeId);
QJsonObject posJson = nodeJson["position"].toObject();
QPointF const pos(posJson["x"].toDouble(), posJson["y"].toDouble());
nlohmann::json posJson = nodeJson["position"];
QPointF const pos(posJson["x"].get<double>(), posJson["y"].get<double>());
setNodeData(restoredNodeId, NodeRole::Position, pos);
_models[restoredNodeId]->load(internalDataJson);
_models[restoredNodeId]->FromJson(internalDataJson);
} else {
throw std::logic_error(std::string("No registered model with name ")
+ delegateModelName.toLocal8Bit().data());
throw std::logic_error(std::string("No registered model with name ") + delegateModelName);
}
}
void StoryGraphModel::load(QJsonObject const &jsonDocument)
{
QJsonArray nodesJsonArray = jsonDocument["nodes"].toArray();
for (QJsonValueRef nodeJson : nodesJsonArray) {
loadNode(nodeJson.toObject());
}
QJsonArray connectionJsonArray = jsonDocument["connections"].toArray();
for (QJsonValueRef connection : connectionJsonArray) {
QJsonObject connJson = connection.toObject();
ConnectionId connId = QtNodes::fromJson(connJson);
// Restore the connection
addConnection(connId);
}
}
void StoryGraphModel::addPort(NodeId nodeId, PortType portType, PortIndex portIndex)
{

View file

@ -96,19 +96,6 @@ public:
bool deleteNode(NodeId const nodeId) override;
QJsonObject saveNode(NodeId const) const override;
QJsonObject save() const;
/// @brief Creates a new node based on the informatoin in `nodeJson`.
/**
* @param nodeJson conains a `NodeId`, node's position, internal node
* information.
*/
void loadNode(QJsonObject const &nodeJson) override;
void load(QJsonObject const &jsonDocument);
void addPort(NodeId nodeId, PortType portType, PortIndex portIndex);
void removePort(NodeId nodeId, PortType portType, PortIndex first);
@ -132,6 +119,13 @@ public:
StoryProject &GetProject() { return m_project; };
void Clear();
void SetInternalData(NodeId nodeId, nlohmann::json &j);
nlohmann::json Save() const;
void Load(const nlohmann::json &j);
nlohmann::json SaveNode(NodeId const) const;
void LoadNode(const nlohmann::json &nodeJson); // Creates a new node
signals:
void sigChooseFile(NodeId id);

View file

@ -10,6 +10,7 @@
#include <QtNodes/NodeDelegateModel>
#include <QtNodes/NodeDelegateModelRegistry>
#include <QtNodes/Definitions>
#include "json.hpp"
using QtNodes::NodeData;
using QtNodes::NodeDataType;
@ -32,7 +33,18 @@ public:
void setNodeId(NodeId id) { m_nodeId = id; }
NodeId getNodeId() { return m_nodeId; }
virtual void setInternalData(const QVariant &value) {
virtual nlohmann::json ToJson() const {
nlohmann::json j;
j["model-name"] = name().toStdString();
return j;
}
virtual void FromJson(nlohmann::json &j) {
// default implementation does nothing
}
virtual void setInternalData(const nlohmann::json &j) {
// default impl
}

View file

@ -15,7 +15,7 @@ void StoryProject::New(const std::string &uuid, const std::string &file_path)
void StoryProject::Initialize(const std::string &file_path)
{
m_project_path = file_path;
m_project_file_path = file_path;
std::filesystem::path p(file_path);
m_working_dir= p.parent_path();
@ -33,12 +33,12 @@ void StoryProject::Initialize(const std::string &file_path)
m_initialized = true;
}
bool StoryProject::Load(const std::string &file_path)
bool StoryProject::Load(const std::string &file_path, nlohmann::json &model)
{
std::ifstream f(file_path);
bool success = false;
/*
std::filesystem::path p(file_path);
m_working_dir= p.parent_path();
@ -49,6 +49,37 @@ bool StoryProject::Load(const std::string &file_path)
nlohmann::json j = nlohmann::json::parse(f);
m_nodes.clear();
if (j.contains("project"))
{
nlohmann::json projectData = j["project"];
m_name = projectData["name"].get<std::string>();
m_uuid = projectData["uuid"].get<std::string>();
nlohmann::json resourcesData = projectData["resources"];
for (const auto &obj : resourcesData)
{
Resource rData;
rData.type = obj["type"].get<std::string>();
rData.format = obj["format"].get<std::string>();
rData.description = obj["description"].get<std::string>();
rData.file = obj["file"].get<std::string>();
m_resources.push_back(rData);
}
if (j.contains("nodegraph"))
{
model = j["nodegraph"];
success = true;
}
}
/*
if (j.contains("nodes"))
{
for (auto& element : j["nodes"])
@ -106,21 +137,42 @@ bool StoryProject::Load(const std::string &file_path)
success = true;
} catch(std::exception &e)
*/
}
catch(std::exception &e)
{
std::cout << e.what() << std::endl;
}
if (success)
{
CreateTree();
}
*/
return success;
}
void StoryProject::Save(const nlohmann::json &model)
{
nlohmann::json j;
j["project"] = { {"name", m_name}, {"uuid", m_uuid} };
{
nlohmann::json resourcesData;
for (auto &r : m_resources)
{
nlohmann::json obj = {{"type", r.type},
{"format", r.format},
{"description", r.description},
{"file", r.file}};
resourcesData.push_back(obj);
}
j["resources"] = resourcesData;
}
j["nodegraph"] = model;
std::ofstream o(m_project_file_path);
o << std::setw(4) << j << std::endl;
}
void StoryProject::CreateTree()
{
// Algorithm: level order traversal of N-ary tree
@ -259,7 +311,7 @@ void StoryProject::SetDisplayFormat(int w, int h)
std::string StoryProject::GetProjectFilePath() const
{
return m_project_path;
return m_project_file_path;
}
std::string StoryProject::GetWorkingDir() const

View file

@ -4,7 +4,9 @@
#include <vector>
#include <string>
#include <filesystem>
#include "json.hpp"
// FIXME : Structure très Lunii style, à utiliser pour la conversion peut-être ...
struct StoryNode
{
bool auto_jump;
@ -55,7 +57,9 @@ struct StoryProject
StoryNode *m_tree;
bool Load(const std::string &file_path);
bool Load(const std::string &file_path, nlohmann::json &model);
void Save(const nlohmann::json &model);
void CreateTree();
void Clear() {
m_uuid = "";
@ -102,6 +106,7 @@ public:
static void EraseString(std::string &theString, const std::string &toErase);
static std::string ToUpper(const std::string &input);
private:
// Project properties and location
std::string m_name; /// human readable name
@ -112,7 +117,7 @@ private:
std::vector<Resource> m_resources;
std::string m_working_dir; /// Temporary folder based on the uuid, where the archive is unzipped
std::string m_project_path; /// JSON project file
std::string m_project_file_path; /// JSON project file
int m_display_w{320};
int m_display_h{240};