diff options
-rw-r--r-- | core/CMakeLists.txt | 2 | ||||
-rw-r--r-- | core/src/Entrypoint/main.cpp | 2 | ||||
-rw-r--r-- | core/src/Model/Items.cpp | 10 | ||||
-rw-r--r-- | core/src/Model/Items.hpp | 3 | ||||
-rw-r--r-- | core/src/Model/Project.cpp | 40 | ||||
-rw-r--r-- | core/src/Model/Project.hpp | 21 | ||||
-rw-r--r-- | core/src/Model/Stock.cpp | 1 | ||||
-rw-r--r-- | core/src/Model/Stock.hpp | 1 | ||||
-rw-r--r-- | core/src/Model/TransactionDatabase.cpp | 41 | ||||
-rw-r--r-- | core/src/Model/TransactionDatabase.hpp | 34 | ||||
-rw-r--r-- | core/src/Model/fwd.hpp | 3 | ||||
-rw-r--r-- | core/src/UI/UI_MainWindow.cpp | 31 |
12 files changed, 135 insertions, 54 deletions
diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 53dd498..0432ed1 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -37,7 +37,7 @@ add_source_group(MODEL_MODULE_SOURCES src/Model/GlobalStates.cpp src/Model/Items.cpp src/Model/Project.cpp - src/Model/Stock.cpp + src/Model/TransactionDatabase.cpp ) add_source_group(UI_MODULE_SOURCES diff --git a/core/src/Entrypoint/main.cpp b/core/src/Entrypoint/main.cpp index 357c333..4f5dc4b 100644 --- a/core/src/Entrypoint/main.cpp +++ b/core/src/Entrypoint/main.cpp @@ -12,8 +12,6 @@ #include "Utils/I18n.hpp" #include "Utils/Sigslot.hpp" -#include <glad/glad.h> -#include <GLFW/glfw3.h> #include <IconsFontAwesome.h> #include <imgui.h> #include <argparse/argparse.hpp> diff --git a/core/src/Model/Items.cpp b/core/src/Model/Items.cpp index 7679eb9..2951666 100644 --- a/core/src/Model/Items.cpp +++ b/core/src/Model/Items.cpp @@ -8,14 +8,24 @@ void ProductItem::SetDescription(std::string description) { mDescription = std::move(description); } +int ProductItem::GetStock() const { + return mStock; +} + +void ProductItem::SetStock(int stock) { + mStock = stock; +} + Json::Value ProductItem::Serialize() const { Json::Value elm; elm["Description"] = mDescription; + elm["Stock"] = mStock; return elm; } void ProductItem::Deserialize(const Json::Value& elm) { mDescription = elm["Description"].asString(); + mStock = elm["Stock"].asInt(); } const std::string& FactoryItem::GetDescription() const { diff --git a/core/src/Model/Items.hpp b/core/src/Model/Items.hpp index e20a290..14b62f3 100644 --- a/core/src/Model/Items.hpp +++ b/core/src/Model/Items.hpp @@ -175,12 +175,15 @@ public: class ProductItem : public ItemBase<ProductItem> { private: std::string mDescription; + int mStock = 0; public: using ItemBase::ItemBase; const std::string& GetDescription() const; void SetDescription(std::string description); + int GetStock() const; + void SetStock(int stock); Json::Value Serialize() const; void Deserialize(const Json::Value& elm); diff --git a/core/src/Model/Project.cpp b/core/src/Model/Project.cpp index cdb88c6..c20e0c8 100644 --- a/core/src/Model/Project.cpp +++ b/core/src/Model/Project.cpp @@ -21,23 +21,22 @@ void ReadItemList(ItemList<T>& list, const fs::path& filePath) { } } -Project Project::Load(const fs::path& projectFilePath) { +Project::Project(const fs::path& rootPath) + : mRootPath{ rootPath } + , mRootPathString{ mRootPath.string() } + , mDb(*this) { // TODO better diagnostic const char* kInvalidFormatErr = "Failed to load project: invalid format."; - std::ifstream ifs(projectFilePath); + std::ifstream ifs(rootPath / "cplt_project.json"); if (!ifs) { std::string message; message += "Failed to load project file at '"; - message += projectFilePath.string(); + message += rootPath.string(); message += "'."; throw std::runtime_error(message); } - Project proj; - proj.mRootPath = projectFilePath.parent_path(); - proj.mRootPathString = proj.mRootPath.string(); - { Json::Value root; ifs >> root; @@ -48,30 +47,23 @@ Project Project::Load(const fs::path& projectFilePath) { } if (auto& name = croot["Name"]; name.isString()) { - proj.mName = name.asString(); + mName = name.asString(); } else { throw std::runtime_error(kInvalidFormatErr); } } - auto itemsDir = proj.mRootPath / "items"; - ReadItemList(proj.Products, itemsDir / "products.json"); - ReadItemList(proj.Factories, itemsDir / "factories.json"); - ReadItemList(proj.Customers, itemsDir / "customers.json"); - - return proj; -} - -Project Project::LoadDir(const std::filesystem::path& projectPath) { - return Load(projectPath / "cplt_project.json"); + auto itemsDir = mRootPath / "items"; + ReadItemList(Products, itemsDir / "products.json"); + ReadItemList(Factories, itemsDir / "factories.json"); + ReadItemList(Customers, itemsDir / "customers.json"); } -Project Project::Create(std::string name, const fs::path& path) { - Project proj; - proj.mRootPath = path; - proj.mRootPathString = path.string(); - proj.mName = std::move(name); - return proj; +Project::Project(std::filesystem::path rootPath, std::string name) + : mRootPath{ std::move(rootPath) } + , mRootPathString{ mRootPath.string() } + , mName{ std::move(name) } + , mDb(*this) { } const fs::path& Project::GetPath() const { diff --git a/core/src/Model/Project.hpp b/core/src/Model/Project.hpp index 280eaf3..8d437ea 100644 --- a/core/src/Model/Project.hpp +++ b/core/src/Model/Project.hpp @@ -1,10 +1,11 @@ #pragma once #include "Model/Items.hpp" +#include "Model/TransactionDatabase.hpp" +#include <json/forwards.h> #include <filesystem> #include <string> -#include <json/forwards.h> class Project { public: @@ -16,15 +17,20 @@ private: std::filesystem::path mRootPath; std::string mRootPathString; std::string mName; + TransactionDatabase mDb; public: - /// Load the project from a cplt_project.json file. - static Project Load(const std::filesystem::path& projectFilePath); - /// Load the project from the directory containing the cplt_project.json file. - static Project LoadDir(const std::filesystem::path& projectPath); + /// Load the project from a directory containing the cplt_project.json file. + Project(const std::filesystem::path& rootPath); + /// Create a project with the given name in the given path. Note that the path should be a directory that will contain the project files once created. /// This function assumes the given directory will exist and is empty. - static Project Create(std::string name, const std::filesystem::path& path); + Project(std::filesystem::path rootPath, std::string name); + + Project(const Project&) = delete; + Project& operator=(const Project&) = delete; + Project(Project&&) = default; + Project& operator=(Project&&) = default; /// Path to a *directory* that contains the project file. const std::filesystem::path& GetPath() const; @@ -35,7 +41,4 @@ public: Json::Value Serialize(); void WriteToDisk(); - -private: - Project() = default; }; diff --git a/core/src/Model/Stock.cpp b/core/src/Model/Stock.cpp deleted file mode 100644 index a56de03..0000000 --- a/core/src/Model/Stock.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "Stock.hpp" diff --git a/core/src/Model/Stock.hpp b/core/src/Model/Stock.hpp deleted file mode 100644 index 6f70f09..0000000 --- a/core/src/Model/Stock.hpp +++ /dev/null @@ -1 +0,0 @@ -#pragma once diff --git a/core/src/Model/TransactionDatabase.cpp b/core/src/Model/TransactionDatabase.cpp new file mode 100644 index 0000000..c28db0d --- /dev/null +++ b/core/src/Model/TransactionDatabase.cpp @@ -0,0 +1,41 @@ +#include "TransactionDatabase.hpp" + +#include "Model/Project.hpp" + +#include <filesystem> +#include <stdexcept> +#include <string> + +namespace fs = std::filesystem; + +static bool TableExists(sqlite3* db, const char* table, const char* column = nullptr) { + return sqlite3_table_column_metadata(db, nullptr, table, column, nullptr, nullptr, nullptr, nullptr, nullptr) == SQLITE_OK; +} + +TransactionDatabase::TransactionDatabase(Project& project) + : mProject{ &project } + , mDatabase{ nullptr } { + + fs::path dbDir = project.GetPath() / "databases"; + fs::create_directories(dbDir); + + fs::path dbPath = dbDir / "transactions.sqlite3"; +#if PLATFORM_WIN32 + if (int rc = sqlite3_open16(dbPath.c_str(), &mDatabase); rc) { +#else + if (int rc = sqlite3_open(transactionDbPath.c_str(), &mDatabase); rc) { +#endif + sqlite3_close(mDatabase); + + std::string message; + message += "Failed to open SQLite database for transactions. Error code: "; + message += rc; + message += "."; + throw std::runtime_error(message); + } +} + +TransactionDatabase::~TransactionDatabase() { + sqlite3_close(mDatabase); + mDatabase = nullptr; +} diff --git a/core/src/Model/TransactionDatabase.hpp b/core/src/Model/TransactionDatabase.hpp new file mode 100644 index 0000000..191a8b8 --- /dev/null +++ b/core/src/Model/TransactionDatabase.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include "cplt_fwd.hpp" + +#include <sqlite3.h> +#include <cstdint> + +struct DeliveryId { + int64_t id; +}; + +class DeliveryTable { +}; + +class OrdersTable { +}; + +class PurchasesTable { +}; + +class TransactionDatabase { +private: + Project* mProject; + sqlite3* mDatabase; + +public: + TransactionDatabase(Project& project); + ~TransactionDatabase(); + + TransactionDatabase(const TransactionDatabase&) = delete; + TransactionDatabase& operator=(const TransactionDatabase&) = delete; + TransactionDatabase(TransactionDatabase&&) = default; + TransactionDatabase& operator=(TransactionDatabase&&) = default; +}; diff --git a/core/src/Model/fwd.hpp b/core/src/Model/fwd.hpp index 146f74a..2d8d2ec 100644 --- a/core/src/Model/fwd.hpp +++ b/core/src/Model/fwd.hpp @@ -14,3 +14,6 @@ class CustomerItem; // Project.hpp class Project; + +// TransactionDatabase.hpp +class TransactionDatabase; diff --git a/core/src/UI/UI_MainWindow.cpp b/core/src/UI/UI_MainWindow.cpp index 661c535..a47efab 100644 --- a/core/src/UI/UI_MainWindow.cpp +++ b/core/src/UI/UI_MainWindow.cpp @@ -15,18 +15,6 @@ namespace fs = std::filesystem; namespace { -bool LoadProjectAt(const std::filesystem::path& path) { - auto& uis = UIState::GetInstance(); - try { - auto project = Project::Load(path); - uis.SetCurrentProject(std::make_unique<Project>(std::move(project))); - - return true; - } catch (const std::exception& e) { - return false; - } -} - void ProjectTab_Normal() { auto ls = LocaleStrings::Instance.get(); auto& gs = GlobalStates::GetInstance(); @@ -100,8 +88,7 @@ void ProjectTab_NoProject() { if (ImGui::Button(ls->DialogConfirm.Get(), !dirNameIsValid || projectName.empty())) { ImGui::CloseCurrentPopup(); - auto project = Project::Create(std::move(projectName), dirPath); - uis.SetCurrentProject(std::make_unique<Project>(std::move(project))); + uis.SetCurrentProject(std::make_unique<Project>(std::move(dirPath), std::move(projectName))); // Dialog just got closed, reset states projectName = ""; @@ -123,7 +110,14 @@ void ProjectTab_NoProject() { auto selection = pfd::open_file(ls->OpenProjectDialogTitle.Get()).result(); if (!selection.empty()) { fs::path path(selection[0]); - openErrorDialog = !LoadProjectAt(path); + + try { + // Project's constructor wants a path to directory containing cplt_project.json + uis.SetCurrentProject(std::make_unique<Project>(path.parent_path())); + openErrorDialog = false; + } catch (const std::exception& e) { + openErrorDialog = true; + } } } @@ -154,7 +148,12 @@ void ProjectTab_NoProject() { ImGui::SameLine(); if (ImGui::Button(ICON_FA_FOLDER_OPEN)) { - openErrorDialog = !LoadProjectAt(path / "cplt_project.json"); + try { + uis.SetCurrentProject(std::make_unique<Project>(path)); + openErrorDialog = false; + } catch (const std::exception& e) { + openErrorDialog = true; + } } if (ImGui::IsItemHovered()) { ImGui::SetTooltip("%s", ls->OpenRecentProjectTooltip.Get()); |