From a611b22650d1e40593db4fb1bce29d925e49e932 Mon Sep 17 00:00:00 2001 From: rtk0c Date: Tue, 25 May 2021 23:56:02 -0700 Subject: More work on workflow management UI --- core/src/Model/GlobalStates.cpp | 10 +-- core/src/Model/GlobalStates.hpp | 4 +- core/src/Model/Project.cpp | 106 ++++++++++++++++++++++++++++-- core/src/Model/Project.hpp | 17 ++++- core/src/Model/Workflow/Workflow.hpp | 16 ++++- core/src/Model/Workflow/Workflow_Main.cpp | 14 ++++ core/src/Model/Workflow/fwd.hpp | 11 +++- 7 files changed, 157 insertions(+), 21 deletions(-) (limited to 'core/src/Model') diff --git a/core/src/Model/GlobalStates.cpp b/core/src/Model/GlobalStates.cpp index 4004f4a..a9b6806 100644 --- a/core/src/Model/GlobalStates.cpp +++ b/core/src/Model/GlobalStates.cpp @@ -45,8 +45,8 @@ void GlobalStates::Init(std::filesystem::path userDataDir) auto utf8String = path.string(); globalStateInstance->mRecentProjects.push_back(RecentProject{ - .path = std::move(path), - .cachedUtf8String = std::move(utf8String), + .Path = std::move(path), + .CachedUtf8String = std::move(utf8String), }); } } @@ -85,8 +85,8 @@ void GlobalStates::ClearRecentProjects() void GlobalStates::AddRecentProject(const Project& project) { mRecentProjects.push_back(RecentProject{ - .path = project.GetPath(), - .cachedUtf8String = project.GetPath().string(), + .Path = project.GetPath(), + .CachedUtf8String = project.GetPath().string(), }); MarkDirty(); } @@ -94,7 +94,7 @@ void GlobalStates::AddRecentProject(const Project& project) void GlobalStates::MoveProjectToTop(const Project& project) { for (auto it = mRecentProjects.begin(); it != mRecentProjects.end(); ++it) { - if (it->path == project.GetPath()) { + if (it->Path == project.GetPath()) { std::rotate(it, it + 1, mRecentProjects.end()); MarkDirty(); return; diff --git a/core/src/Model/GlobalStates.hpp b/core/src/Model/GlobalStates.hpp index d88f752..6970642 100644 --- a/core/src/Model/GlobalStates.hpp +++ b/core/src/Model/GlobalStates.hpp @@ -19,8 +19,8 @@ public: struct RecentProject { - std::filesystem::path path; - std::string cachedUtf8String; + std::filesystem::path Path; + std::string CachedUtf8String; }; public: diff --git a/core/src/Model/Project.cpp b/core/src/Model/Project.cpp index 74e7142..2d7c82a 100644 --- a/core/src/Model/Project.cpp +++ b/core/src/Model/Project.cpp @@ -1,5 +1,8 @@ #include "Project.hpp" +#include "Model/Workflow/Workflow.hpp" +#include "Utils/Macros.hpp" + #include #include #include @@ -25,7 +28,7 @@ void ReadItemList(ItemList& list, const fs::path& filePath) Project::Project(const fs::path& rootPath) : mRootPath{ rootPath } , mRootPathString{ mRootPath.string() } - , mDb(*this) + , Database(*this) { // TODO better diagnostic const char* kInvalidFormatErr = "Failed to load project: invalid format."; @@ -59,13 +62,30 @@ Project::Project(const fs::path& rootPath) ReadItemList(Products, itemsDir / "products.json"); ReadItemList(Factories, itemsDir / "factories.json"); ReadItemList(Customers, itemsDir / "customers.json"); + + auto workflowsDir = mRootPath / "workflows"; + fs::create_directories(workflowsDir); + + for (auto& entry : fs::directory_iterator(workflowsDir)) { + if (!entry.is_regular_file()) continue; + auto& path = entry.path(); + if (path.extension() != ".cplt-workflow") continue; + + auto name = path.stem().string(); + auto [it, DISCARD] = mWorkflows.insert(name, WorkflowInfo{}); + auto& info = it.value(); + + info.Name = std::move(name); + info.PathStringCache = path.string(); + info.Path = path; + } } Project::Project(std::filesystem::path rootPath, std::string name) : mRootPath{ std::move(rootPath) } , mRootPathString{ mRootPath.string() } , mName{ std::move(name) } - , mDb(*this) + , Database(*this) { } @@ -89,14 +109,68 @@ void Project::SetName(std::string name) mName = std::move(name); } -const TransactionModel& Project::GetTransactionsModel() const +const decltype(Project::mWorkflows)& Project::GetWorkflows() const +{ + return mWorkflows; +} + +std::unique_ptr Project::LoadWorkflow(std::string_view name) +{ + auto iter = mWorkflows.find(name); + if (iter == mWorkflows.end()) { + return iter.value().LoadFromDisk(); + } else { + return nullptr; + } +} + +std::unique_ptr Project::CreateWorkflow(std::string_view name) { - return mDb; + if (mWorkflows.find(name) != mWorkflows.end()) { + // Workflow with name already exists + return nullptr; + } + + auto workflow = std::make_unique(); + auto [it, DISCARD] = mWorkflows.insert(name, WorkflowInfo{}); + auto& info = it.value(); + + info.Name = name; + info.Path = GetWorkflowPath(name); + + return workflow; } -TransactionModel& Project::GetTransactionsModel() +bool Project::RemoveWorkflow(std::string_view name) { - return mDb; + auto iter = mWorkflows.find(name); + if (iter == mWorkflows.end()) { + return false; + } + auto& info = iter.value(); + + fs::remove(info.Path); + mWorkflows.erase(iter); + + return true; +} + +bool Project::RenameWorkflow(std::string_view name, std::string_view newName) +{ + auto iter = mWorkflows.find(name); + if (iter == mWorkflows.end()) return false; + + auto info = std::move(iter.value()); + + auto& oldPath = info.Path; + auto newPath = GetWorkflowPath(newName); + fs::rename(oldPath, newPath); + info.Path = std::move(newPath); + + mWorkflows.insert(newName, std::move(info)); + mWorkflows.erase(iter); + + return true; } Json::Value Project::Serialize() @@ -127,3 +201,23 @@ void Project::WriteToDisk() WriteItemList(Factories, itemsDir / "factories.json"); WriteItemList(Customers, itemsDir / "customers.json"); } + +std::filesystem::path Project::GetDatabasesDirectory() const +{ + return mRootPath / "databases"; +} + +std::filesystem::path Project::GetItemsDirectory() const +{ + return mRootPath / "items"; +} + +std::filesystem::path Project::GetWorkflowsDirectory() const +{ + return mRootPath / "workflows"; +} + +std::filesystem::path Project::GetWorkflowPath(std::string_view name) const +{ + return (mRootPath / "workflows" / name).concat(".cplt-workflow"); +} diff --git a/core/src/Model/Project.hpp b/core/src/Model/Project.hpp index 998befb..5f26532 100644 --- a/core/src/Model/Project.hpp +++ b/core/src/Model/Project.hpp @@ -4,8 +4,10 @@ #include "Model/TransactionsModel.hpp" #include +#include #include #include +#include class Project { @@ -13,12 +15,13 @@ public: ItemList Products; ItemList Factories; ItemList Customers; + TransactionModel Database; private: + tsl::array_map mWorkflows; std::filesystem::path mRootPath; std::string mRootPathString; std::string mName; - TransactionModel mDb; public: /// Load the project from a directory containing the cplt_project.json file. @@ -32,11 +35,19 @@ public: const std::filesystem::path& GetPath() const; const std::string& GetPathString() const; + std::filesystem::path GetDatabasesDirectory() const; + std::filesystem::path GetItemsDirectory() const; + std::filesystem::path GetWorkflowsDirectory() const; + std::filesystem::path GetWorkflowPath(std::string_view name) const; + const std::string& GetName() const; void SetName(std::string name); - const TransactionModel& GetTransactionsModel() const; - TransactionModel& GetTransactionsModel(); + const decltype(mWorkflows)& GetWorkflows() const; + std::unique_ptr LoadWorkflow(std::string_view name); + std::unique_ptr CreateWorkflow(std::string_view name); + bool RemoveWorkflow(std::string_view name); + bool RenameWorkflow(std::string_view name, std::string_view newName); Json::Value Serialize(); void WriteToDisk(); diff --git a/core/src/Model/Workflow/Workflow.hpp b/core/src/Model/Workflow/Workflow.hpp index 0aabcdc..99e4e90 100644 --- a/core/src/Model/Workflow/Workflow.hpp +++ b/core/src/Model/Workflow/Workflow.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -135,14 +136,14 @@ public: void DisconnectInput(uint32_t pinId); void DrawInputPinDebugInfo(uint32_t pinId) const; - const InputPin& GetInputPin(uint32_t pinId)const ; + const InputPin& GetInputPin(uint32_t pinId) const; ImNodes::PinId GetInputPinUniqueId(uint32_t pinId) const; void ConnectOutput(uint32_t pinId, WorkflowNode& dstNode, uint32_t dstPinId); void DisconnectOutput(uint32_t pinId); - void DrawOutputPinDebugInfo(uint32_t pinId)const; - const OutputPin& GetOutputPin(uint32_t pinId)const ; + void DrawOutputPinDebugInfo(uint32_t pinId) const; + const OutputPin& GetOutputPin(uint32_t pinId) const; ImNodes::PinId GetOutputPinUniqueId(uint32_t pinId) const; virtual void Evaluate(WorkflowEvaluationContext& ctx) = 0; @@ -170,6 +171,15 @@ protected: void OnDetach(); }; +struct WorkflowInfo +{ + std::string Name; + std::string PathStringCache = Path.string(); + std::filesystem::path Path; + + std::unique_ptr LoadFromDisk() const; +}; + class Workflow { private: diff --git a/core/src/Model/Workflow/Workflow_Main.cpp b/core/src/Model/Workflow/Workflow_Main.cpp index c9ae328..bfe007c 100644 --- a/core/src/Model/Workflow/Workflow_Main.cpp +++ b/core/src/Model/Workflow/Workflow_Main.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -319,6 +320,19 @@ void WorkflowNode::OnDetach() { } +std::unique_ptr WorkflowInfo::LoadFromDisk() const +{ + std::ifstream ifs(this->Path); + if (!ifs) return nullptr; + + auto workflow = std::make_unique(); + if (workflow->ReadFrom(ifs) == Workflow::RR_Success) { + return workflow; + } + + return nullptr; +} + const std::vector& Workflow::GetConnections() const { return mConnections; diff --git a/core/src/Model/Workflow/fwd.hpp b/core/src/Model/Workflow/fwd.hpp index 2323a91..b541e52 100644 --- a/core/src/Model/Workflow/fwd.hpp +++ b/core/src/Model/Workflow/fwd.hpp @@ -3,12 +3,19 @@ #include "Model/Workflow/Nodes/fwd.hpp" #include "Model/Workflow/Values/fwd.hpp" +// Evaluation.hpp +class WorkflowEvaluationError; +class WorkflowEvaluationContext; + +// SavedWorkflow.hpp +class SavedWorkflowCache; +class SavedWorkflow; + // Value.hpp class BaseValue; // Workflow.hpp class WorkflowConnection; class WorkflowNode; +struct WorkflowInfo; class Workflow; -class WorkflowEvaluationError; -class WorkflowEvaluationContext; -- cgit v1.2.3-70-g09d2