diff --git a/src/api/requirement.h b/src/api/requirement.h index 887254d..6f8c4b8 100644 --- a/src/api/requirement.h +++ b/src/api/requirement.h @@ -1,26 +1,51 @@ #pragma once +#include #include -#include namespace api::requirement { //-------------------------------------------------------------- +using TimePoint = std::chrono::system_clock::time_point; +//-------------------------------------------------------------- +enum class Status +{ + Draft, // The requirement is in draft state and has not been finalized + InReview, // The requirement is currently being reviewed by stakeholders + Approved, // The requirement has been approved and is ready for implementation + Rejected // The requirement has been rejected and will not be implemented +}; +//-------------------------------------------------------------- +struct Metadata +{ + std::string uuid; // Unique identifier for the requirement, generated automatically + std::string id; // Unique identifier for the requirement, provided by the user (e.g., "REQ-001") + std::string author; // Name of the person who created the requirement + TimePoint created_at; // Creation timestamp + TimePoint updated_at; // Last update timestamp +}; +//-------------------------------------------------------------- +struct Details +{ + std::string name; // Short name or title of the requirement + std::string description; // Detailed description of the requirement + std::string acceptance_criteria; // Criteria that must be met for the requirement to be considered complete + bool is_smart; // SMART indicator (Specific, Measurable, Achievable, Relevant, Time-bound) +}; +//-------------------------------------------------------------- +struct Classification +{ + std::string type; // Type of the requirement (e.g., "Functional", "Non-Functional", "Performance", etc.) + std::string category; // Category of the requirement (e.g., "UI", "Backend", "Security", etc.) + int priority; // Priority level of the requirement (e.g., 1 for highest priority, 5 for lowest) + Status status; // Current status of the requirement (e.g., "Draft", "In Review", "Approved", "Rejected", etc.) +}; +//-------------------------------------------------------------- struct Requirement { - std::string uuid; - std::string parent_uuid; - std::string id; - std::string type; - std::string name; - std::string description; - std::vector sub_requirements; - - /* Default constructor */ - Requirement() - { - uuid = sdi_toolBox::generic::UuidGenerator::uuid_v4(); // Generate a unique UUID for the requirement - } + Metadata metadata; // General information about the requirement + Details details; // Detailed information about the requirement + Classification classification; // Classification information about the requirement }; //-------------------------------------------------------------- @@ -37,11 +62,11 @@ struct RequirementEvent : dBus::api::DefaultData + +using namespace std; +using namespace core::project; +//-------------------------------------------------------------- +/* Default constructor */ +RequirementManager::RequirementManager() +{ + m_rootRequirement = make_shared(*this); // Create the root requirement item and set it as the root requirement +} +//-------------------------------------------------------------- +/* Get the root requirement */ +RequirementManager::RequirementItemPtr RequirementManager::getRootRequirement() const +{ + return m_rootRequirement; // Return the root requirement item pointer +} +//-------------------------------------------------------------- +/* Get the vector of child requirement items of the root requirement */ +std::vector RequirementManager::getRootRequirementChild() const +{ + return m_rootRequirement->getChildren(); // Return the vector of child requirement items of the root requirement +} +//-------------------------------------------------------------- +/* Get a requirement by its UUID */ +RequirementManager::RequirementItemPtr RequirementManager::getRequirement(const std::string &uuid) const +{ + if (m_requirementsByUuid.contains(uuid)) + return m_requirementsByUuid.at(uuid); // Return the requirement item pointer if found in the map + return {}; // Return nullptr if the requirement with the given UUID is not found +} +//-------------------------------------------------------------- +/* Get the vector of child requirement items of a requirement by its UUID */ +std::vector RequirementManager::getRequirementChildren(const std::string &uuid) const +{ + if (m_requirementsByUuid.contains(uuid)) + return m_requirementsByUuid.at(uuid)->getChildren(); // Return the vector of child requirement items if the requirement with the given UUID is found in the map + return {}; // Return an empty vector if the requirement with the given UUID is not found +} +//-------------------------------------------------------------- +/* Generate a unique UUID string that is not already registered in the manager's internal map */ +std::string RequirementManager::generateUniqueUuid() const +{ + std::string uuid; + do + { + uuid = sdi_toolBox::generic::UuidGenerator::uuid_v4(); // Generate a random UUID v4 string + } while (isRequirementRegistered(uuid)); // Check if the generated UUID is already registered + + return uuid; // Return the unique UUID string +} +//-------------------------------------------------------------- +/* Check if a requirement with the given UUID is registered in the manager's internal map */ +bool RequirementManager::isRequirementRegistered(const std::string &uuid) const +{ + return m_requirementsByUuid.contains(uuid); +} +//-------------------------------------------------------------- +/* Register a requirement in the manager's internal map for quick lookup by UUID */ +void RequirementManager::registerRequirement(const RequirementItemPtr &requirement) +{ + m_requirementsByUuid[requirement->metadata.uuid] = requirement; +} +//-------------------------------------------------------------- +/* Unregister a requirement from the manager's internal map */ +void RequirementManager::unregisterRequirement(const std::string &uuid) +{ + m_requirementsByUuid.erase(uuid); +} +//-------------------------------------------------------------- \ No newline at end of file diff --git a/src/core/projectManager/RequirementManager.h b/src/core/projectManager/RequirementManager.h new file mode 100644 index 0000000..31d83bc --- /dev/null +++ b/src/core/projectManager/RequirementManager.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include +#include + +namespace core::project +{ +class RequirementItem; +//-------------------------------------------------------------- +class RequirementManager +{ + using RequirementItemPtr = std::shared_ptr; + + public: + RequirementManager(); // Default constructor + virtual ~RequirementManager() = default; // Default destructor + RequirementManager(const RequirementManager &obj) = delete; // Copy constructor + RequirementManager(RequirementManager &&obj) noexcept = delete; // Move constructor + RequirementManager &operator=(const RequirementManager &obj) = delete; // Copy assignment operator + RequirementManager &operator=(RequirementManager &&obj) noexcept = delete; // Move assignment operator + + [[nodiscard]] RequirementItemPtr getRootRequirement() const; // Get the root requirement + [[nodiscard]] std::vector getRootRequirementChild() const; // Get the vector of child requirement items of the root requirement + + [[nodiscard]] RequirementItemPtr getRequirement(const std::string &uuid) const; // Get a requirement by its UUID + [[nodiscard]] std::vector getRequirementChildren(const std::string &uuid) const; // Get the vector of child requirement items of a requirement by its UUID + + // Requirement management functions + [[nodiscard]] std::string generateUniqueUuid() const; // Generate a unique UUID string that is not already registered in the manager's internal map + [[nodiscard]] bool isRequirementRegistered(const std::string &uuid) const; // Check if a requirement with the given UUID is registered in the manager's internal map + void registerRequirement(const RequirementItemPtr &requirement); // Register a requirement in the manager's internal map for quick lookup by UUID + void unregisterRequirement(const std::string &uuid); // Unregister a requirement from the manager's internal map + + protected: + RequirementItemPtr m_rootRequirement; // Root requirement of the current project + std::unordered_map m_requirementsByUuid; // Map of requirement UUID to requirement pointer for quick lookup + + private: +}; +//-------------------------------------------------------------- +} // namespace core::project diff --git a/src/core/projectManager/projectData.cpp b/src/core/projectManager/projectData.cpp deleted file mode 100644 index 371b5fe..0000000 --- a/src/core/projectManager/projectData.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "projectData.h" - -using namespace std; -using namespace core::project; -//-------------------------------------------------------------- -/* Get the root requirement */ -ProjectData::RequirementPtr ProjectData::getRootRequirement() -{ - return m_rootRequirement; -} -//-------------------------------------------------------------- \ No newline at end of file diff --git a/src/core/projectManager/projectData.h b/src/core/projectManager/projectData.h deleted file mode 100644 index 99ec345..0000000 --- a/src/core/projectManager/projectData.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include -#include - -namespace core::project -{ -//-------------------------------------------------------------- -class ProjectData -{ - using RequirementPtr = std::shared_ptr; - - public: - ProjectData() = default; // Default constructor - virtual ~ProjectData() = default; // Default destructor - ProjectData(const ProjectData &obj) = delete; // Copy constructor - ProjectData(ProjectData &&obj) noexcept = delete; // Move constructor - ProjectData &operator=(const ProjectData &obj) = delete; // Copy assignment operator - ProjectData &operator=(ProjectData &&obj) noexcept = delete; // Move assignment operator - - RequirementPtr getRootRequirement(); // Get the root requirement - - protected: - RequirementPtr m_rootRequirement; // Root requirement of the current project - - private: -}; -//-------------------------------------------------------------- -} // namespace core::project diff --git a/src/core/projectManager/projectManager.cpp b/src/core/projectManager/projectManager.cpp index d09930f..6a52d77 100644 --- a/src/core/projectManager/projectManager.cpp +++ b/src/core/projectManager/projectManager.cpp @@ -1,6 +1,6 @@ #include "projectManager.h" -#include "projectData.h" +#include "RequirementManager.h" using namespace std; using namespace core::project; @@ -117,7 +117,7 @@ void ProjectManager::on_projectOperationEvent(const ProjectOperationMessage_ptr /* Process a file creation event */ void ProjectManager::on_projectCreateFileEvent(const ProjectOperationMessage_ptr &message) { - m_projectData = make_shared(); + m_requirementManager = make_shared(); message->responsePromise.set_value(); } @@ -165,7 +165,7 @@ void ProjectManager::on_projectSaveFileEvent(const ProjectOperationMessage_ptr & /* Process a file close event */ void ProjectManager::on_projectCloseFileEvent(const ProjectOperationMessage_ptr &message) { - m_projectData = {}; + m_requirementManager = {}; message->responsePromise.set_value(); } //-------------------------------------------------------------- diff --git a/src/core/projectManager/projectManager.h b/src/core/projectManager/projectManager.h index a9eb5e3..d8379ea 100644 --- a/src/core/projectManager/projectManager.h +++ b/src/core/projectManager/projectManager.h @@ -8,11 +8,11 @@ namespace core::project { -class ProjectData; +class RequirementManager; //-------------------------------------------------------------- class ProjectManager : public dBus::Node { - using ProjectPtr = std::shared_ptr; + using RequirementManagerPtr = std::shared_ptr; public: ProjectManager() = delete; // Default constructor @@ -27,7 +27,7 @@ class ProjectManager : public dBus::Node protected: std::filesystem::path m_filePath; // Path of the currently opened project file - ProjectPtr m_projectData; // Current project data, including the root requirement and all its sub-requirements + RequirementManagerPtr m_requirementManager; // Pointer to the requirement manager of the current project private: void openFile(const std::filesystem::path &filePath); // Open a project file and load the requirements diff --git a/src/core/projectManager/requirementItem.cpp b/src/core/projectManager/requirementItem.cpp new file mode 100644 index 0000000..b3c6841 --- /dev/null +++ b/src/core/projectManager/requirementItem.cpp @@ -0,0 +1,56 @@ +#include "requirementItem.h" + +#include "RequirementManager.h" + +using namespace std; +using namespace core::project; +//-------------------------------------------------------------- +/* Constructor */ +RequirementItem::RequirementItem(RequirementManager &manager, const std::shared_ptr &parentRequirement) + : m_requirementManager(manager) +{ + // Initialization + metadata.uuid = m_requirementManager.generateUniqueUuid(); // Generate a unique UUID for this requirement item + m_parent = parentRequirement; // Set the m_parent requirement item + + // Register this requirement item in the manager's internal map + m_requirementManager.registerRequirement(shared_from_this()); +} +//-------------------------------------------------------------- +/* Append a child requirement item to this requirement item */ +void RequirementItem::appendChild(const api::requirement::Requirement &child) +{ + // Create a new requirement item for the child requirement and set this requirement item as its m_parent + const auto childItem = make_shared(m_requirementManager); + childItem->metadata = child.metadata; + childItem->details = child.details; + childItem->classification = child.classification; + + // Prepare requirement links + childItem->metadata.uuid = m_requirementManager.generateUniqueUuid(); // Generate a unique UUID for this requirement item + childItem->m_parent = shared_from_this(); + + // Register this requirement item in the manager's internal map + m_requirementManager.registerRequirement(childItem); +} +//-------------------------------------------------------------- +/* Remove a child requirement item from this requirement item by its UUID */ +void RequirementItem::removeChild(const std::string &childUuid) +{ + // Unregister the child requirement item from the manager's internal map + m_requirementManager.unregisterRequirement(childUuid); + + // Find the child requirement item with the given UUID + const auto it = ranges::find_if(m_children, + [&childUuid](const RequirementItemPtr &child) + { return child->metadata.uuid == childUuid; }); + if (it != m_children.end()) + m_children.erase(it); // Remove the child requirement item from the vector of children +} +//-------------------------------------------------------------- +/* Get the vector of child requirement items of this requirement item */ +std::vector RequirementItem::getChildren() const +{ + return m_children; +} +//-------------------------------------------------------------- diff --git a/src/core/projectManager/requirementItem.h b/src/core/projectManager/requirementItem.h new file mode 100644 index 0000000..fdd89eb --- /dev/null +++ b/src/core/projectManager/requirementItem.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include + +namespace core::project +{ +class RequirementManager; +//-------------------------------------------------------------- +class RequirementItem : public std::enable_shared_from_this + , public api::requirement::Requirement +{ + using RequirementItemPtr = std::shared_ptr; + + public: + RequirementItem() = delete; // Default constructor + virtual ~RequirementItem() = default; // Default destructor + RequirementItem(const RequirementItem &obj) = delete; // Copy constructor + RequirementItem(RequirementItem &&obj) noexcept = delete; // Move constructor + RequirementItem &operator=(const RequirementItem &obj) = delete; // Copy assignment operator + RequirementItem &operator=(RequirementItem &&obj) noexcept = delete; // Move assignment operator + + explicit RequirementItem(RequirementManager &manager, // Constructor + const std::shared_ptr &parentRequirement = nullptr); + + // Children management functions + void appendChild(const api::requirement::Requirement &child); // Append a child requirement item to this requirement item + void removeChild(const std::string &childUuid); // Remove a child requirement item from this requirement item by its UUID + [[nodiscard]] std::vector getChildren() const; // Get the vector of child requirement items of this requirement item + + protected: + RequirementManager &m_requirementManager; // Reference to the requirement manager that owns this requirement item + std::weak_ptr m_parent; // Weak pointer to the m_parent requirement item (nullptr for root) + std::vector m_children; // Vector of shared pointers to child requirement items +}; +//-------------------------------------------------------------- +} // namespace core::project