Work on the graphical interface for presenting requirements details
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
#include "RequirementManager.h"
|
||||
#include "requirementManager.h"
|
||||
|
||||
#include "requirementItem.h"
|
||||
|
||||
|
||||
@@ -35,8 +35,6 @@ class RequirementManager
|
||||
protected:
|
||||
RequirementItemPtr m_rootRequirement; // Root requirement of the current project
|
||||
std::unordered_map<std::string, RequirementItemPtr> m_requirementsByUuid; // Map of requirement UUID to requirement pointer for quick lookup
|
||||
|
||||
private:
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
} // namespace core::project
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "projectManager.h"
|
||||
|
||||
#include "RequirementManager.h"
|
||||
#include "requirementItem.h"
|
||||
#include "requirementManager.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace core::project;
|
||||
@@ -33,8 +34,13 @@ void ProjectManager::saveFile(const std::filesystem::path &filePath)
|
||||
/* Run the bus listener thread */
|
||||
void ProjectManager::runBusListener()
|
||||
{
|
||||
// Subscribe to the bus for messages related to log entries
|
||||
// Subscribe to the bus for messages related to project file and requirement operations
|
||||
subscribe(dBus::makeID("project.file.operation"));
|
||||
subscribe(dBus::makeID("requirement.get"));
|
||||
subscribe(dBus::makeID("requirement.requirement.getChildren"));
|
||||
subscribe(dBus::makeID("requirement.add"));
|
||||
subscribe(dBus::makeID("requirement.update"));
|
||||
subscribe(dBus::makeID("requirement.delete"));
|
||||
|
||||
/* Start the bus listener thread to process incoming messages related to requirements.
|
||||
* The thread will continuously wait for messages and process them until a stop is requested. */
|
||||
@@ -79,43 +85,75 @@ void ProjectManager::processMessageBus(const Message_ptr &message)
|
||||
const auto messageType = message->getMessageTypeID();
|
||||
switch (messageType)
|
||||
{
|
||||
// Process project events
|
||||
case dBus::makeID("project.file.operation"):
|
||||
{
|
||||
// Process project operation request
|
||||
on_projectOperationEvent(message->as<dBus::RequestMessage<api::project::ProjectOperationEvent, void>>());
|
||||
on_projectOperationEvent(message);
|
||||
break;
|
||||
}
|
||||
|
||||
// Process requirement events
|
||||
case dBus::makeID("requirement.get"):
|
||||
{
|
||||
on_requirementGetEvent(message->as<dBus::RequestMessage<api::requirement::GetRequirementEvent, api::requirement::Requirement>>());
|
||||
break;
|
||||
}
|
||||
case dBus::makeID("requirement.getChildren"):
|
||||
{
|
||||
on_requirementGetChildrenEvent(message->as<dBus::RequestMessage<api::requirement::GetChildrenRequirementEvent, std::vector<api::requirement::Requirement>>>());
|
||||
break;
|
||||
}
|
||||
case dBus::makeID("requirement.add"):
|
||||
{
|
||||
on_requirementAddEvent(message->as<dBus::RequestMessage<api::requirement::AddRequirementEvent, void>>());
|
||||
break;
|
||||
}
|
||||
case dBus::makeID("requirement.update"):
|
||||
{
|
||||
on_requirementUpdateEvent(message->as<dBus::RequestMessage<api::requirement::UpdateRequirementEvent, void>>());
|
||||
break;
|
||||
}
|
||||
case dBus::makeID("requirement.delete"):
|
||||
{
|
||||
on_requirementDeleteEvent(message->as<dBus::RequestMessage<api::requirement::DeleteRequirementEvent, void>>());
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Process a file operation event */
|
||||
void ProjectManager::on_projectOperationEvent(const ProjectOperationMessage_ptr &message)
|
||||
void ProjectManager::on_projectOperationEvent(const Message_ptr &message)
|
||||
{
|
||||
const auto specializedMessage = message->as<dBus::RequestMessage<api::project::ProjectOperationEvent, void>>();
|
||||
|
||||
// Sanity check
|
||||
if (!message)
|
||||
if (!specializedMessage)
|
||||
return;
|
||||
|
||||
switch (message->value.operationType)
|
||||
switch (specializedMessage->value.operationType)
|
||||
{
|
||||
using enum api::project::OperationType;
|
||||
case Create:
|
||||
on_projectCreateFileEvent(message);
|
||||
on_projectCreateFileEvent(specializedMessage);
|
||||
break;
|
||||
case Open:
|
||||
on_projectOpenFileEvent(message);
|
||||
on_projectOpenFileEvent(specializedMessage);
|
||||
break;
|
||||
case Save:
|
||||
case SaveAs:
|
||||
on_projectSaveFileEvent(message);
|
||||
on_projectSaveFileEvent(specializedMessage);
|
||||
break;
|
||||
case Close:
|
||||
on_projectCloseFileEvent(message);
|
||||
on_projectCloseFileEvent(specializedMessage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Process a file creation event */
|
||||
void ProjectManager::on_projectCreateFileEvent(const ProjectOperationMessage_ptr &message)
|
||||
void ProjectManager::on_projectCreateFileEvent(const api::project::ProjectOperationMessage_ptr &message)
|
||||
{
|
||||
m_requirementManager = make_shared<RequirementManager>();
|
||||
|
||||
@@ -123,22 +161,22 @@ void ProjectManager::on_projectCreateFileEvent(const ProjectOperationMessage_ptr
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Process a file open event */
|
||||
void ProjectManager::on_projectOpenFileEvent(const ProjectOperationMessage_ptr &message)
|
||||
void ProjectManager::on_projectOpenFileEvent(const api::project::ProjectOperationMessage_ptr &message)
|
||||
{
|
||||
// message->responsePromise.set_exception(std::make_exception_ptr(std::runtime_error("Open operation not implemented")));
|
||||
try
|
||||
{
|
||||
openFile(message->value.filePath);
|
||||
|
||||
message->responsePromise.set_value();
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
message->responsePromise.set_exception(std::make_exception_ptr(e));
|
||||
}
|
||||
message->responsePromise.set_value();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Process a file save event */
|
||||
void ProjectManager::on_projectSaveFileEvent(const ProjectOperationMessage_ptr &message)
|
||||
void ProjectManager::on_projectSaveFileEvent(const api::project::ProjectOperationMessage_ptr &message)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -154,18 +192,176 @@ void ProjectManager::on_projectSaveFileEvent(const ProjectOperationMessage_ptr &
|
||||
throw std::runtime_error("File path is empty for Save operation");
|
||||
saveFile();
|
||||
}
|
||||
|
||||
message->responsePromise.set_value();
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
message->responsePromise.set_exception(std::make_exception_ptr(e));
|
||||
}
|
||||
message->responsePromise.set_value();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Process a file close event */
|
||||
void ProjectManager::on_projectCloseFileEvent(const ProjectOperationMessage_ptr &message)
|
||||
void ProjectManager::on_projectCloseFileEvent(const api::project::ProjectOperationMessage_ptr &message)
|
||||
{
|
||||
m_requirementManager = {};
|
||||
message->responsePromise.set_value();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Process a requirement get event */
|
||||
void ProjectManager::on_requirementGetEvent(const api::requirement::GetRequirementMessage_ptr &message) const
|
||||
{
|
||||
// Sanity check
|
||||
if (!message)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
// Sanity check
|
||||
if (!m_requirementManager)
|
||||
throw std::runtime_error("No project file is currently opened");
|
||||
|
||||
// Get requirement handle
|
||||
const auto requirement = m_requirementManager->getRequirement(message->value.uuid);
|
||||
if (!requirement)
|
||||
throw std::runtime_error("Requirement not found");
|
||||
|
||||
message->responsePromise.set_value(requirement->toRequirement());
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
message->responsePromise.set_exception(std::make_exception_ptr(e));
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Process a requirement get children event */
|
||||
void ProjectManager::on_requirementGetChildrenEvent(const api::requirement::GetChildrenRequirementMessage_ptr &message) const
|
||||
{
|
||||
// Sanity check
|
||||
if (!message)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
// Sanity check
|
||||
if (!m_requirementManager)
|
||||
throw std::runtime_error("No project file is currently opened");
|
||||
|
||||
// Get requirement handle
|
||||
const auto requirement = m_requirementManager->getRequirement(message->value.uuid);
|
||||
if (!requirement)
|
||||
throw std::runtime_error("Requirement not found");
|
||||
|
||||
// Get children requirements
|
||||
const auto &children = requirement->getChildren();
|
||||
vector<api::requirement::Requirement> childrenData;
|
||||
childrenData.reserve(children.size());
|
||||
for (const auto &child : children)
|
||||
childrenData.push_back(child->toRequirement());
|
||||
|
||||
message->responsePromise.set_value(childrenData);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
message->responsePromise.set_exception(std::make_exception_ptr(e));
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Process a requirement addition event */
|
||||
void ProjectManager::on_requirementAddEvent(const api::requirement::AddRequirementMessage_ptr &message) const
|
||||
{
|
||||
// Sanity check
|
||||
if (!message)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
// Sanity check
|
||||
if (!m_requirementManager)
|
||||
throw std::runtime_error("No project file is currently opened");
|
||||
|
||||
// Get parent requirement handle
|
||||
const auto parentRequirement = message->value.parentUuid.empty()
|
||||
? m_requirementManager->getRootRequirement()
|
||||
: m_requirementManager->getRequirement(message->value.parentUuid);
|
||||
if (!parentRequirement)
|
||||
throw std::runtime_error("Parent requirement not found");
|
||||
|
||||
// Append the new requirement to the parent requirement
|
||||
parentRequirement->appendChild(message->value.requirementData);
|
||||
|
||||
message->responsePromise.set_value();
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
message->responsePromise.set_exception(std::make_exception_ptr(e));
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Process a requirement update event */
|
||||
void ProjectManager::on_requirementUpdateEvent(const api::requirement::UpdateRequirementMessage_ptr &message) const
|
||||
{
|
||||
// Sanity check
|
||||
if (!message)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
// Sanity check
|
||||
if (!m_requirementManager)
|
||||
throw std::runtime_error("No project file is currently opened");
|
||||
|
||||
// Get requirement handle
|
||||
const auto requirement = m_requirementManager->getRequirement(message->value.requirementData.metadata.uuid);
|
||||
if (!requirement)
|
||||
throw std::runtime_error("Requirement not found");
|
||||
|
||||
// Update the requirement data
|
||||
requirement->update(message->value.requirementData);
|
||||
|
||||
message->responsePromise.set_value();
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
message->responsePromise.set_exception(std::make_exception_ptr(e));
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Process a requirement deletion event */
|
||||
void ProjectManager::on_requirementDeleteEvent(const api::requirement::DeleteRequirementMessage_ptr &message) const
|
||||
{
|
||||
// Sanity check
|
||||
if (!message)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
// Sanity check
|
||||
if (!m_requirementManager)
|
||||
throw std::runtime_error("No project file is currently opened");
|
||||
|
||||
// Get requirement handle
|
||||
const auto requirement = m_requirementManager->getRequirement(message->value.requirementData.metadata.uuid);
|
||||
if (!requirement)
|
||||
throw std::runtime_error("Requirement not found");
|
||||
|
||||
// Get parent requirement handle
|
||||
const auto parentRequirement = requirement->getParent();
|
||||
if (!parentRequirement)
|
||||
{
|
||||
// If the requirement to be deleted is the root requirement,
|
||||
// we cannot delete it as it is the base of the requirements hierarchy
|
||||
throw std::runtime_error("Cannot delete root requirement");
|
||||
}
|
||||
|
||||
// Remove the requirement from its parent
|
||||
parentRequirement->removeChild(requirement->metadata.uuid);
|
||||
|
||||
message->responsePromise.set_value();
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
message->responsePromise.set_exception(std::make_exception_ptr(e));
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
|
||||
@@ -41,12 +41,16 @@ class ProjectManager : public dBus::Node
|
||||
std::jthread m_busListenerThread; // Thread for listening to bus messages related to requirements
|
||||
|
||||
// Events processing
|
||||
using ProjectOperationMessage_ptr = std::shared_ptr<dBus::RequestMessage<api::project::ProjectOperationEvent, void>>;
|
||||
void on_projectOperationEvent(const ProjectOperationMessage_ptr &message); // Process a file operation event
|
||||
void on_projectCreateFileEvent(const ProjectOperationMessage_ptr &message); // Process a file creation event
|
||||
void on_projectOpenFileEvent(const ProjectOperationMessage_ptr &message); // Process a file opening event
|
||||
void on_projectSaveFileEvent(const ProjectOperationMessage_ptr &message); // Process a file saving event
|
||||
void on_projectCloseFileEvent(const ProjectOperationMessage_ptr &message); // Process a file closing event
|
||||
void on_projectOperationEvent(const Message_ptr &message); // Process a file operation event
|
||||
void on_projectCreateFileEvent(const api::project::ProjectOperationMessage_ptr &message); // Process a file creation event
|
||||
void on_projectOpenFileEvent(const api::project::ProjectOperationMessage_ptr &message); // Process a file opening event
|
||||
void on_projectSaveFileEvent(const api::project::ProjectOperationMessage_ptr &message); // Process a file saving event
|
||||
void on_projectCloseFileEvent(const api::project::ProjectOperationMessage_ptr &message); // Process a file closing event
|
||||
void on_requirementGetEvent(const api::requirement::GetRequirementMessage_ptr &message) const; // Process a requirement get event
|
||||
void on_requirementGetChildrenEvent(const api::requirement::GetChildrenRequirementMessage_ptr &message) const; // Process a requirement get children event
|
||||
void on_requirementAddEvent(const api::requirement::AddRequirementMessage_ptr &message) const; // Process a requirement addition event
|
||||
void on_requirementUpdateEvent(const api::requirement::UpdateRequirementMessage_ptr &message) const; // Process a requirement update event
|
||||
void on_requirementDeleteEvent(const api::requirement::DeleteRequirementMessage_ptr &message) const; // Process a requirement deletion event
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
} // namespace core::project
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "requirementItem.h"
|
||||
|
||||
#include "RequirementManager.h"
|
||||
#include "requirementManager.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace core::project;
|
||||
@@ -17,21 +17,45 @@ RequirementItem::RequirementItem(RequirementManager &manager, const std::shared_
|
||||
m_requirementManager.registerRequirement(shared_from_this());
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Convert this requirement item to an api::requirement::Requirement struct and return it */
|
||||
api::requirement::Requirement RequirementItem::toRequirement() const
|
||||
{
|
||||
return { .metadata = metadata,
|
||||
.details = details,
|
||||
.classification = classification };
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Update the data of this requirement item with the provided updated requirement data */
|
||||
void RequirementItem::update(const api::requirement::Requirement &updatedData)
|
||||
{
|
||||
const auto currentUUID = metadata.uuid; // Store the current UUID before updating
|
||||
|
||||
// Update the requirement data with the provided updated requirement data
|
||||
metadata = updatedData.metadata;
|
||||
details = updatedData.details;
|
||||
classification = updatedData.classification;
|
||||
|
||||
// Restore the original UUID to maintain consistency
|
||||
metadata.uuid = currentUUID;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Get the m_parent requirement item of this requirement item (nullptr for root) */
|
||||
RequirementItem::RequirementItemPtr RequirementItem::getParent() const
|
||||
{
|
||||
// Return the m_parent requirement item pointer if it exists
|
||||
// or nullptr if this requirement item is the root
|
||||
return m_parent.lock();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Append a child requirement item to this requirement item */
|
||||
void RequirementItem::appendChild(const api::requirement::Requirement &child)
|
||||
void RequirementItem::appendChild(const 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<RequirementItem>(m_requirementManager);
|
||||
childItem->metadata = child.metadata;
|
||||
childItem->details = child.details;
|
||||
childItem->classification = child.classification;
|
||||
const auto childItem = make_shared<RequirementItem>(m_requirementManager, shared_from_this());
|
||||
childItem->update(child); // Update the child requirement item with the provided child requirement data
|
||||
|
||||
// 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);
|
||||
// Append the child requirement item to the vector of children
|
||||
m_children.push_back(childItem);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Remove a child requirement item from this requirement item by its UUID */
|
||||
@@ -41,11 +65,24 @@ void RequirementItem::removeChild(const std::string &childUuid)
|
||||
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
|
||||
const auto childIt = ranges::find_if(m_children,
|
||||
[&childUuid](const RequirementItemPtr &child)
|
||||
{ return child->metadata.uuid == childUuid; });
|
||||
if (childIt == m_children.end())
|
||||
throw std::runtime_error("Child requirement item with UUID " + childUuid + " not found");
|
||||
|
||||
(*childIt)->removeChildren(); // Recursively remove all child requirement items of the child requirement item to be removed
|
||||
m_children.erase(childIt); // Remove the child requirement item from the vector of children
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Remove all child requirement items from this requirement item */
|
||||
void RequirementItem::removeChildren()
|
||||
{
|
||||
while (!m_children.empty())
|
||||
{
|
||||
const auto child = m_children.back(); // Get the last child requirement item
|
||||
removeChild(child->metadata.uuid);
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Get the vector of child requirement items of this requirement item */
|
||||
|
||||
@@ -24,10 +24,16 @@ class RequirementItem : public std::enable_shared_from_this<RequirementItem>
|
||||
explicit RequirementItem(RequirementManager &manager, // Constructor
|
||||
const std::shared_ptr<RequirementItem> &parentRequirement = nullptr);
|
||||
|
||||
// Management functions
|
||||
[[nodiscard]] Requirement toRequirement() const; // Convert this requirement item to an api::requirement::Requirement struct and return it
|
||||
void update(const Requirement &updatedData); // Update the data of this requirement item with the provided updated requirement data
|
||||
|
||||
// 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<RequirementItemPtr> getChildren() const; // Get the vector of child requirement items of this requirement item
|
||||
RequirementItemPtr getParent() const; // Get the m_parent requirement item of this requirement item
|
||||
void appendChild(const 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
|
||||
void removeChildren(); // Remove all child requirement items from this requirement item
|
||||
[[nodiscard]] std::vector<RequirementItemPtr> 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
|
||||
|
||||
Reference in New Issue
Block a user