Work on the graphical interface for presenting requirements details
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <dbus/api/api.h>
|
||||
#include <dbus/dBus.h>
|
||||
#include <filesystem>
|
||||
|
||||
namespace api::project
|
||||
@@ -18,8 +19,6 @@ enum class OperationType : uint8_t
|
||||
|
||||
/* --- */
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// Post event structs
|
||||
//--------------------------------------------------------------
|
||||
struct ProjectOperationEvent : dBus::api::DefaultData<dBus::makeID("project.file.operation")>
|
||||
{
|
||||
@@ -62,12 +61,6 @@ struct ProjectOperationEvent : dBus::api::DefaultData<dBus::makeID("project.file
|
||||
}
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
|
||||
/* --- */
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// Post event helpers
|
||||
//--------------------------------------------------------------
|
||||
inline dBus::api::PostReturnStatus postProjectOperationRequest(dBus::Bus &bus, const OperationType &operationType, const std::filesystem::path &filePath = "")
|
||||
{
|
||||
auto eventData = ProjectOperationEvent();
|
||||
@@ -77,4 +70,5 @@ inline dBus::api::PostReturnStatus postProjectOperationRequest(dBus::Bus &bus, c
|
||||
return dBus::api::requestData<decltype(eventData), void>(bus, eventData.getID(), eventData, dBus::MessageCategory::UI);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
using ProjectOperationMessage_ptr = std::shared_ptr<dBus::RequestMessage<ProjectOperationEvent, void>>;
|
||||
} // namespace api::project
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <chrono>
|
||||
#include <dbus/api/api.h>
|
||||
#include <dbus/dBus.h>
|
||||
|
||||
namespace api::requirement
|
||||
{
|
||||
@@ -27,7 +28,7 @@ struct Metadata
|
||||
//--------------------------------------------------------------
|
||||
struct Details
|
||||
{
|
||||
std::string name; // Short name or title of the requirement
|
||||
std::string title; // 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)
|
||||
@@ -52,42 +53,146 @@ struct Requirement
|
||||
/* --- */
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// Post event structs
|
||||
//--------------------------------------------------------------
|
||||
struct RequirementEvent : dBus::api::DefaultData<dBus::makeID("requirement.requirementEvent")>
|
||||
struct GetRequirementEvent : dBus::api::DefaultData<dBus::makeID("requirement.get")>
|
||||
{
|
||||
virtual ~RequirementEvent() = default; // Default destructor
|
||||
virtual ~GetRequirementEvent() = default; // Default destructor
|
||||
|
||||
Requirement requirementData;
|
||||
std::string uuid; // UUID of the requirement (empty for root-level requirements)
|
||||
|
||||
[[nodiscard]] std::string toString() const override
|
||||
{
|
||||
// return std::format("RequirementEvent: id={}, name={}, subRequirementsCount={}",
|
||||
// requirementData.id,
|
||||
// requirementData.name,
|
||||
// requirementData.description);
|
||||
return "";
|
||||
return std::format("GetRequirementEvent: uuid={}", uuid);
|
||||
}
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
inline std::expected<Requirement, dBus::ReturnStatus> postGetRequirementRequest(dBus::Bus &bus, const std::string &uuid)
|
||||
{
|
||||
auto eventData = GetRequirementEvent();
|
||||
eventData.uuid = std::move(uuid);
|
||||
return dBus::api::requestData<decltype(eventData), Requirement>(bus, eventData.getID(), eventData, dBus::MessageCategory::UI);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
using GetRequirementMessage_ptr = std::shared_ptr<dBus::RequestMessage<GetRequirementEvent, Requirement>>;
|
||||
|
||||
/* --- */
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// Post event helpers
|
||||
struct GetChildrenRequirementEvent : dBus::api::DefaultData<dBus::makeID("requirement.getChildren")>
|
||||
{
|
||||
virtual ~GetChildrenRequirementEvent() = default; // Default destructor
|
||||
|
||||
std::string uuid; // UUID of the requirement (empty for root-level requirements)
|
||||
|
||||
[[nodiscard]] std::string toString() const override
|
||||
{
|
||||
return std::format("GetChildrenRequirementEvent: uuid={}", uuid);
|
||||
}
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
inline std::expected<std::vector<Requirement>, dBus::ReturnStatus> postGetChildrenRequirementRequest(dBus::Bus &bus, const std::string &uuid)
|
||||
{
|
||||
auto eventData = GetChildrenRequirementEvent();
|
||||
eventData.uuid = std::move(uuid);
|
||||
return dBus::api::requestData<decltype(eventData), std::vector<Requirement>>(bus, eventData.getID(), eventData, dBus::MessageCategory::UI);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
using GetChildrenRequirementMessage_ptr = std::shared_ptr<dBus::RequestMessage<GetChildrenRequirementEvent, std::vector<Requirement>>>;
|
||||
|
||||
/* --- */
|
||||
|
||||
//--------------------------------------------------------------
|
||||
struct AddRequirementEvent : dBus::api::DefaultData<dBus::makeID("requirement.add")>
|
||||
{
|
||||
virtual ~AddRequirementEvent() = default; // Default destructor
|
||||
|
||||
std::string parentUuid; // UUID of the parent requirement (empty for root-level requirements)
|
||||
Requirement requirementData; // Data of the requirement to be added
|
||||
|
||||
[[nodiscard]] std::string toString() const override
|
||||
{
|
||||
return std::format("AddRequirementEvent: parentUuid={}, id={}, title={}",
|
||||
parentUuid,
|
||||
requirementData.metadata.id,
|
||||
requirementData.details.title);
|
||||
}
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
inline dBus::api::PostReturnStatus postAddRequirementRequest(dBus::Bus &bus, const std::string &parentUuid, const Requirement &requirement)
|
||||
{
|
||||
auto eventData = AddRequirementEvent();
|
||||
eventData.parentUuid = std::move(parentUuid);
|
||||
eventData.requirementData = std::move(requirement);
|
||||
return dBus::api::requestData<decltype(eventData), void>(bus, eventData.getID(), eventData, dBus::MessageCategory::UI);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
using AddRequirementMessage_ptr = std::shared_ptr<dBus::RequestMessage<AddRequirementEvent, void>>;
|
||||
|
||||
/* --- */
|
||||
|
||||
//--------------------------------------------------------------
|
||||
struct UpdateRequirementEvent : dBus::api::DefaultData<dBus::makeID("requirement.update")>
|
||||
{
|
||||
virtual ~UpdateRequirementEvent() = default; // Default destructor
|
||||
|
||||
Requirement requirementData; // Data of the requirement to be updated
|
||||
|
||||
[[nodiscard]] std::string toString() const override
|
||||
{
|
||||
return std::format("UpdateRequirementEvent: id={}, title={}",
|
||||
requirementData.metadata.id,
|
||||
requirementData.details.title);
|
||||
}
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
inline dBus::api::PostReturnStatus postUpdateRequirementRequest(dBus::Bus &bus, const Requirement &requirement)
|
||||
{
|
||||
auto eventData = UpdateRequirementEvent();
|
||||
eventData.requirementData = std::move(requirement);
|
||||
return dBus::api::requestData<decltype(eventData), void>(bus, eventData.getID(), eventData, dBus::MessageCategory::UI);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
using UpdateRequirementMessage_ptr = std::shared_ptr<dBus::RequestMessage<UpdateRequirementEvent, void>>;
|
||||
|
||||
/* --- */
|
||||
|
||||
//--------------------------------------------------------------
|
||||
struct DeleteRequirementEvent : dBus::api::DefaultData<dBus::makeID("requirement.delete")>
|
||||
{
|
||||
virtual ~DeleteRequirementEvent() = default; // Default destructor
|
||||
|
||||
Requirement requirementData; // Data of the requirement to be deleted
|
||||
|
||||
[[nodiscard]] std::string toString() const override
|
||||
{
|
||||
return std::format("DeleteRequirementEvent: id={}, title={}",
|
||||
requirementData.metadata.id,
|
||||
requirementData.details.title);
|
||||
}
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
inline dBus::api::PostReturnStatus postDeleteRequirementRequest(dBus::Bus &bus, const Requirement &requirement)
|
||||
{
|
||||
auto eventData = DeleteRequirementEvent();
|
||||
eventData.requirementData = std::move(requirement);
|
||||
return dBus::api::requestData<decltype(eventData), void>(bus, eventData.getID(), eventData, dBus::MessageCategory::UI);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
using DeleteRequirementMessage_ptr = std::shared_ptr<dBus::RequestMessage<DeleteRequirementEvent, void>>;
|
||||
|
||||
/* --- */
|
||||
|
||||
/* Post a requirement event to the bus. This function will post a
|
||||
* RequirementEvent containing the provided requirement data to the
|
||||
* bus, and return a PostReturnStatus indicating whether the post was
|
||||
* successful or if there were any issues (e.g., no subscribers,
|
||||
* timeout, etc.). */
|
||||
inline dBus::api::PostReturnStatus postRequirementRequest(dBus::Bus &bus,
|
||||
Requirement requirement)
|
||||
{
|
||||
auto eventData = RequirementEvent();
|
||||
eventData.requirementData = std::move(requirement);
|
||||
|
||||
return dBus::api::requestData<decltype(eventData), void>(bus, eventData.getID(), eventData, dBus::MessageCategory::UI);
|
||||
}
|
||||
// inline dBus::api::PostReturnStatus postRequirementRequest(dBus::Bus &bus,
|
||||
// Requirement requirement)
|
||||
//{
|
||||
// auto eventData = RequirementEvent();
|
||||
// eventData.requirementData = std::move(requirement);
|
||||
//
|
||||
// return dBus::api::requestData<decltype(eventData), void>(bus, eventData.getID(), eventData, dBus::MessageCategory::UI);
|
||||
// }
|
||||
//--------------------------------------------------------------
|
||||
} // namespace api::requirement
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "bars/menuBar.h"
|
||||
#include "bars/statusBar.h"
|
||||
#include "bars/toolBar.h"
|
||||
#include "requirementsPanel/requirementsPanel.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
@@ -18,7 +19,6 @@ using namespace gui;
|
||||
MainFrame::MainFrame(dBus::Bus &bus)
|
||||
: wxFrame(nullptr, wxID_ANY, _("kwa.Fr"), wxDefaultPosition, wxDefaultSize)
|
||||
, dBus::wxNode(this, bus)
|
||||
, m_bus(bus)
|
||||
{
|
||||
// Initialization
|
||||
SetIcon(wxICON(AAAA_ICON));
|
||||
@@ -36,6 +36,8 @@ MainFrame::MainFrame(dBus::Bus &bus)
|
||||
CenterOnScreen();
|
||||
|
||||
subscribe(dBus::makeID("log.message"));
|
||||
|
||||
// Iconize();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Creating controls */
|
||||
@@ -46,7 +48,10 @@ void MainFrame::createControls()
|
||||
const auto framePanel = new wxPanel(this /*, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER*/);
|
||||
m_toolBar = new ToolBar(framePanel);
|
||||
|
||||
m_pageNotebook = new wxNotebook(framePanel, wxID_ANY);
|
||||
m_pageNotebook = new wxNotebook(framePanel, wxID_ANY);
|
||||
m_requirementsPanel = new RequirementsPanel(m_pageNotebook, m_bus);
|
||||
|
||||
m_pageNotebook->AddPage(m_requirementsPanel, "Requirements", true);
|
||||
|
||||
// Controls positioning
|
||||
const auto mainSizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace gui
|
||||
class MenuBar;
|
||||
class StatusBar;
|
||||
class ToolBar;
|
||||
class RequirementsPanel;
|
||||
//--------------------------------------------------------------
|
||||
class MainFrame : public wxFrame
|
||||
, public dBus::wxNode
|
||||
@@ -18,7 +19,7 @@ class MainFrame : public wxFrame
|
||||
public:
|
||||
MainFrame() = delete; // Default constructor
|
||||
virtual ~MainFrame() = default; // Default destructor
|
||||
MainFrame(MainFrame &obj) = delete; // Copy constructor
|
||||
MainFrame(const MainFrame &obj) = delete; // Copy constructor
|
||||
MainFrame(MainFrame &&obj) noexcept = delete; // Move constructor
|
||||
MainFrame &operator=(const MainFrame &obj) = delete; // Copy assignment operator
|
||||
MainFrame &operator=(MainFrame &&obj) noexcept = delete; // Move assignment operator
|
||||
@@ -26,13 +27,14 @@ class MainFrame : public wxFrame
|
||||
explicit MainFrame(dBus::Bus &bus); // Constructor
|
||||
|
||||
protected:
|
||||
dBus::Bus &m_bus; // Reference to the application bus
|
||||
|
||||
// Controls
|
||||
MenuBar *m_menuBar = nullptr; // Menu bar handle
|
||||
StatusBar *m_statusBar = nullptr; // Status bar handle
|
||||
ToolBar *m_toolBar = nullptr; // Toolbar handle
|
||||
wxNotebook *m_pageNotebook = nullptr; // Main notebook handle
|
||||
|
||||
RequirementsPanel *m_requirementsPanel = nullptr; // Requirements panel handle
|
||||
|
||||
private:
|
||||
void createControls(); // Creating controls
|
||||
|
||||
|
||||
@@ -0,0 +1,233 @@
|
||||
#include "requirementDetailPanel.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace gui;
|
||||
//--------------------------------------------------------------
|
||||
/* Constructor */
|
||||
RequirementDetailPanel::RequirementDetailPanel(wxWindow *parentWindow, dBus::Bus &bus)
|
||||
: wxScrolledWindow(parentWindow, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER | wxVSCROLL)
|
||||
, m_bus(bus)
|
||||
{
|
||||
// Initialization
|
||||
SetScrollRate(0, 10); // Set the scroll rate for the panel (vertical only)
|
||||
|
||||
// Creating controls
|
||||
createControls();
|
||||
|
||||
// Post initialization
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Creating controls */
|
||||
void RequirementDetailPanel::createControls()
|
||||
{
|
||||
const auto mainPanel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(500, -1), wxSIMPLE_BORDER);
|
||||
|
||||
// Controls positioning
|
||||
const auto ctrlSizer = new wxBoxSizer(wxVERTICAL);
|
||||
ctrlSizer->Add(createControls_metadata(mainPanel), wxSizerFlags(0).Expand());
|
||||
ctrlSizer->Add(createControls_details(mainPanel), wxSizerFlags(0).Expand());
|
||||
ctrlSizer->Add(createControls_classification(mainPanel), wxSizerFlags(0).Expand());
|
||||
mainPanel->SetSizer(ctrlSizer);
|
||||
|
||||
const auto mainSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
mainSizer->Add(mainPanel, wxSizerFlags(0).Expand());
|
||||
mainSizer->AddStretchSpacer(1);
|
||||
|
||||
SetSizer(mainSizer);
|
||||
|
||||
// Set the virtual size to match the size of the child panel,
|
||||
// enabling scrolling if necessary
|
||||
FitInside();
|
||||
|
||||
// Harmonize the sizes of the title controls to ensure they have the same width
|
||||
updateTitleSizes();
|
||||
Layout();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Creating controls for requirement metadata (ID, UUID, name, description, etc.) */
|
||||
wxSizer *RequirementDetailPanel::createControls_metadata(wxWindow *owner)
|
||||
{
|
||||
struct Item
|
||||
{
|
||||
wxWindow *titleCtrl;
|
||||
wxWindow *inputCtrl;
|
||||
};
|
||||
std::vector<Item> items;
|
||||
|
||||
{
|
||||
const Item item{ .titleCtrl = createTitle(owner, _T("UUID:")),
|
||||
.inputCtrl = new wxTextCtrl(owner, wxID_ANY) };
|
||||
items.push_back(item);
|
||||
}
|
||||
{
|
||||
const Item item{ .titleCtrl = createTitle(owner, _T("ID:")),
|
||||
.inputCtrl = new wxTextCtrl(owner, wxID_ANY) };
|
||||
items.push_back(item);
|
||||
}
|
||||
{
|
||||
const Item item{ .titleCtrl = createTitle(owner, _("Author:")),
|
||||
.inputCtrl = new wxTextCtrl(owner, wxID_ANY) };
|
||||
items.push_back(item);
|
||||
}
|
||||
{
|
||||
const Item item{ .titleCtrl = createTitle(owner, _("Created at:")),
|
||||
.inputCtrl = new wxTextCtrl(owner, wxID_ANY) };
|
||||
items.push_back(item);
|
||||
}
|
||||
{
|
||||
const Item item{ .titleCtrl = createTitle(owner, _("Updated at:")),
|
||||
.inputCtrl = new wxTextCtrl(owner, wxID_ANY) };
|
||||
items.push_back(item);
|
||||
}
|
||||
|
||||
// Controls positioning
|
||||
const auto ctrlSizer = new wxFlexGridSizer(2, 5, 5);
|
||||
for (const auto &item : items)
|
||||
{
|
||||
ctrlSizer->Add(item.titleCtrl, wxSizerFlags(0).Expand().CenterVertical());
|
||||
ctrlSizer->Add(item.inputCtrl, wxSizerFlags(1).Expand());
|
||||
}
|
||||
ctrlSizer->AddGrowableCol(1, 1);
|
||||
|
||||
// Controls positioning
|
||||
const auto localSizer = new wxStaticBoxSizer(wxVERTICAL, owner, "Metadata");
|
||||
localSizer->Add(ctrlSizer, wxSizerFlags(0).Expand().Border(wxALL, 5));
|
||||
|
||||
return localSizer;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Creating controls for requirement details (e.g., custom attributes, child requirements, etc.) */
|
||||
wxSizer *RequirementDetailPanel::createControls_details(wxWindow *owner)
|
||||
{
|
||||
struct Item
|
||||
{
|
||||
wxWindow *titleCtrl;
|
||||
wxWindow *inputCtrl;
|
||||
};
|
||||
std::vector<Item> items;
|
||||
|
||||
{
|
||||
const Item item{ .titleCtrl = createTitle(owner, _("Title:")),
|
||||
.inputCtrl = new wxTextCtrl(owner, wxID_ANY) };
|
||||
items.push_back(item);
|
||||
}
|
||||
{
|
||||
const Item item{ .titleCtrl = createTitle(owner, _("Description:")),
|
||||
.inputCtrl = new wxTextCtrl(owner,
|
||||
wxID_ANY,
|
||||
wxEmptyString,
|
||||
wxDefaultPosition,
|
||||
wxDefaultSize,
|
||||
wxTE_PROCESS_TAB | wxTE_MULTILINE | wxVSCROLL | wxTE_AUTO_URL) };
|
||||
items.push_back(item);
|
||||
|
||||
item.inputCtrl->SetMinSize(wxSize(-1, 200));
|
||||
}
|
||||
{
|
||||
const Item item{ .titleCtrl = createTitle(owner, _("Acceptance criteria:")),
|
||||
.inputCtrl = new wxTextCtrl(owner,
|
||||
wxID_ANY,
|
||||
wxEmptyString,
|
||||
wxDefaultPosition,
|
||||
wxDefaultSize,
|
||||
wxTE_PROCESS_TAB | wxTE_MULTILINE | wxVSCROLL) };
|
||||
items.push_back(item);
|
||||
|
||||
item.inputCtrl->SetMinSize(wxSize(-1, 100));
|
||||
}
|
||||
{
|
||||
const Item item{ .titleCtrl = new wxPanel(owner),
|
||||
.inputCtrl = new wxCheckBox(owner, wxID_ANY, _("S.M.A.R.T.")) };
|
||||
items.push_back(item);
|
||||
}
|
||||
|
||||
// Controls positioning
|
||||
const auto ctrlSizer = new wxFlexGridSizer(2, 5, 5);
|
||||
for (const auto &item : items)
|
||||
{
|
||||
ctrlSizer->Add(item.titleCtrl, wxSizerFlags(0).Expand().CenterVertical());
|
||||
ctrlSizer->Add(item.inputCtrl, wxSizerFlags(1).Expand());
|
||||
}
|
||||
ctrlSizer->AddGrowableCol(1, 1);
|
||||
|
||||
const auto localSizer = new wxStaticBoxSizer(wxVERTICAL, owner, "Details");
|
||||
localSizer->Add(ctrlSizer, wxSizerFlags(0).Expand().Border(wxALL, 5));
|
||||
|
||||
return localSizer;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Creating controls for requirement classification (e.g., priority, severity, etc.) */
|
||||
wxSizer *RequirementDetailPanel::createControls_classification(wxWindow *owner)
|
||||
{
|
||||
struct Item
|
||||
{
|
||||
wxWindow *titleCtrl;
|
||||
wxWindow *inputCtrl;
|
||||
};
|
||||
std::vector<Item> items;
|
||||
|
||||
{
|
||||
const Item item{ .titleCtrl = createTitle(owner, "Type:"),
|
||||
.inputCtrl = new wxTextCtrl(owner, wxID_ANY) };
|
||||
items.push_back(item);
|
||||
}
|
||||
{
|
||||
const Item item{ .titleCtrl = createTitle(owner, "Category:"),
|
||||
.inputCtrl = new wxTextCtrl(owner, wxID_ANY) };
|
||||
items.push_back(item);
|
||||
}
|
||||
{
|
||||
const Item item{ .titleCtrl = createTitle(owner, "Priority:"),
|
||||
.inputCtrl = new wxTextCtrl(owner, wxID_ANY) };
|
||||
items.push_back(item);
|
||||
}
|
||||
{
|
||||
const Item item{ .titleCtrl = createTitle(owner, "Status:"),
|
||||
.inputCtrl = new wxTextCtrl(owner, wxID_ANY) };
|
||||
items.push_back(item);
|
||||
}
|
||||
|
||||
// Controls positioning
|
||||
const auto ctrlSizer = new wxFlexGridSizer(2, 5, 5);
|
||||
for (const auto &item : items)
|
||||
{
|
||||
ctrlSizer->Add(item.titleCtrl, wxSizerFlags(0).Expand().CenterVertical());
|
||||
ctrlSizer->Add(item.inputCtrl, wxSizerFlags(1).Expand());
|
||||
}
|
||||
ctrlSizer->AddGrowableCol(1, 1);
|
||||
|
||||
const auto localSizer = new wxStaticBoxSizer(wxVERTICAL, owner, "Classification");
|
||||
localSizer->Add(ctrlSizer, wxSizerFlags(0).Expand().Border(wxALL, 5));
|
||||
|
||||
return localSizer;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Helper function to create a section title control */
|
||||
wxStaticText *RequirementDetailPanel::createTitle(wxWindow *owner, const wxString &title)
|
||||
{
|
||||
const auto ctrl = new wxStaticText(owner,
|
||||
wxID_ANY,
|
||||
title,
|
||||
wxDefaultPosition,
|
||||
wxDefaultSize,
|
||||
wxST_NO_AUTORESIZE | wxALIGN_RIGHT);
|
||||
|
||||
m_titleControls.push_back(ctrl);
|
||||
|
||||
return ctrl;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Harmonize the sizes of the title controls to ensure they have the same width */
|
||||
void RequirementDetailPanel::updateTitleSizes() const
|
||||
{
|
||||
int maxWidth = 0;
|
||||
for (const auto &ctrl : m_titleControls)
|
||||
{
|
||||
maxWidth = std::max(maxWidth, ctrl->GetSize().GetWidth());
|
||||
}
|
||||
for (const auto &ctrl : m_titleControls)
|
||||
{
|
||||
ctrl->SetMinSize(wxSize(maxWidth, -1));
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <dBus/dBus.h>
|
||||
#include <wx/wx.h>
|
||||
|
||||
namespace gui
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
class RequirementDetailPanel : public wxScrolledWindow
|
||||
{
|
||||
public:
|
||||
RequirementDetailPanel() = delete; // Default constructor
|
||||
virtual ~RequirementDetailPanel() = default; // Default destructor
|
||||
RequirementDetailPanel(const RequirementDetailPanel &obj) = delete; // Copy constructor
|
||||
RequirementDetailPanel(RequirementDetailPanel &&obj) noexcept = delete; // Move constructor
|
||||
RequirementDetailPanel &operator=(const RequirementDetailPanel &obj) = delete; // Copy assignment operator
|
||||
RequirementDetailPanel &operator=(RequirementDetailPanel &&obj) noexcept = delete; // Move assignment operator
|
||||
|
||||
explicit RequirementDetailPanel(wxWindow *parentWindow, dBus::Bus &bus); // Constructor
|
||||
|
||||
protected:
|
||||
dBus::Bus &m_bus; // Reference to the application bus
|
||||
std::vector<wxControl *> m_titleControls; // Titles controls for each section (metadata, details, classification)
|
||||
|
||||
private:
|
||||
void createControls(); // Creating controls
|
||||
wxSizer *createControls_metadata(wxWindow *owner); // Creating controls for requirement metadata
|
||||
wxSizer *createControls_details(wxWindow *owner); // Creating controls for requirement details
|
||||
wxSizer *createControls_classification(wxWindow *owner); // Creating controls for requirement classification
|
||||
|
||||
wxStaticText *createTitle(wxWindow *owner, const wxString &title); // Helper function to create a section title control
|
||||
void updateTitleSizes() const; // Harmonize the sizes of the title controls to ensure they have the same width
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
} // namespace gui
|
||||
@@ -0,0 +1,23 @@
|
||||
#include "requirementListPanel.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace gui;
|
||||
//--------------------------------------------------------------
|
||||
/* Constructor */
|
||||
RequirementListPanel::RequirementListPanel(wxWindow *parentWindow, dBus::Bus &bus)
|
||||
: wxPanel(parentWindow, wxID_ANY, wxDefaultPosition, wxSize(300, -1), wxSIMPLE_BORDER)
|
||||
, m_bus(bus)
|
||||
{
|
||||
// Initialization
|
||||
|
||||
// Creating controls
|
||||
createControls();
|
||||
|
||||
// Post initialization
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Creating controls */
|
||||
void RequirementListPanel::createControls()
|
||||
{
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <dBus/dBus.h>
|
||||
#include <wx/wx.h>
|
||||
|
||||
namespace gui
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
class RequirementListPanel : public wxPanel
|
||||
{
|
||||
public:
|
||||
RequirementListPanel() = delete; // Default constructor
|
||||
virtual ~RequirementListPanel() = default; // Default destructor
|
||||
RequirementListPanel(const RequirementListPanel &obj) = delete; // Copy constructor
|
||||
RequirementListPanel(RequirementListPanel &&obj) noexcept = delete; // Move constructor
|
||||
RequirementListPanel &operator=(const RequirementListPanel &obj) = delete; // Copy assignment operator
|
||||
RequirementListPanel &operator=(RequirementListPanel &&obj) noexcept = delete; // Move assignment operator
|
||||
|
||||
explicit RequirementListPanel(wxWindow *parentWindow, dBus::Bus &bus); // Constructor
|
||||
|
||||
protected:
|
||||
dBus::Bus &m_bus; // Reference to the application bus
|
||||
|
||||
private:
|
||||
void createControls(); // Creating controls
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
} // namespace gui
|
||||
40
src/gui/requirementsPanel/requirementsPanel.cpp
Normal file
40
src/gui/requirementsPanel/requirementsPanel.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "requirementsPanel.h"
|
||||
|
||||
#include "requirementDetailPanel/requirementDetailPanel.h"
|
||||
#include "requirementListPanel/requirementListPanel.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace gui;
|
||||
//--------------------------------------------------------------
|
||||
/* Constructor */
|
||||
RequirementsPanel::RequirementsPanel(wxWindow *parentWindow, dBus::Bus &bus)
|
||||
: wxPanel(parentWindow, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER)
|
||||
, dBus::wxNode(this, bus)
|
||||
{
|
||||
// Initialization
|
||||
|
||||
// Creating controls
|
||||
createControls();
|
||||
|
||||
// Post initialization
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Creating controls */
|
||||
void RequirementsPanel::createControls()
|
||||
{
|
||||
m_requirementListPanel = new RequirementListPanel(this, m_bus);
|
||||
m_requirementDetailPanel = new RequirementDetailPanel(this, m_bus);
|
||||
|
||||
// Controls positioning
|
||||
const auto mainSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
mainSizer->Add(m_requirementListPanel, wxSizerFlags(0).Expand().Border(wxALL, 5));
|
||||
mainSizer->Add(m_requirementDetailPanel, wxSizerFlags(1).Expand().Border(wxALL, 5));
|
||||
|
||||
SetSizer(mainSizer);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* dBus message reception handler */
|
||||
void RequirementsPanel::on_receiveMessageFromBus(MessageID messageID, MessagePtr message)
|
||||
{
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
68
src/gui/requirementsPanel/requirementsPanel.h
Normal file
68
src/gui/requirementsPanel/requirementsPanel.h
Normal file
@@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include "gui/wxNode.h"
|
||||
|
||||
#include <dBus/dBus.h>
|
||||
#include <wx/wx.h>
|
||||
|
||||
namespace gui
|
||||
{
|
||||
class RequirementDetailPanel;
|
||||
class RequirementListPanel;
|
||||
|
||||
//--------------------------------------------------------------
|
||||
class RequirementsPanel : public wxPanel
|
||||
, public dBus::wxNode
|
||||
{
|
||||
public:
|
||||
RequirementsPanel() = delete; // Default constructor
|
||||
virtual ~RequirementsPanel() = default; // Default destructor
|
||||
RequirementsPanel(const RequirementsPanel &obj) = delete; // Copy constructor
|
||||
RequirementsPanel(RequirementsPanel &&obj) noexcept = delete; // Move constructor
|
||||
RequirementsPanel &operator=(const RequirementsPanel &obj) = delete; // Copy assignment operator
|
||||
RequirementsPanel &operator=(RequirementsPanel &&obj) noexcept = delete; // Move assignment operator
|
||||
|
||||
explicit RequirementsPanel(wxWindow *parentWindow, dBus::Bus &bus); // Constructor
|
||||
|
||||
protected:
|
||||
// Controls
|
||||
RequirementListPanel *m_requirementListPanel = nullptr; // Pointer to the requirement list panel control
|
||||
RequirementDetailPanel *m_requirementDetailPanel = nullptr; // Pointer to the requirement detail panel control
|
||||
|
||||
private:
|
||||
void createControls(); // Creating controls
|
||||
|
||||
// Events
|
||||
void on_receiveMessageFromBus(MessageID messageID, MessagePtr message) override; // dBus message reception handler
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
} // namespace gui
|
||||
|
||||
/*
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ ▼ Métadonnées │
|
||||
│ ID: [REQ-001] 🔒 │
|
||||
│ UUID: [abc-123-def] 🔒 │
|
||||
│ Auteur: [John Doe] 🔒 │
|
||||
│ Créé le: [2026-03-13 14:30] 🔒 │
|
||||
│ Modifié le: [2026-03-13 15:45] 🔒 │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ ▼ Détails │
|
||||
│ Nom: [________________] │
|
||||
│ Description: [ ] │
|
||||
│ [ ] │
|
||||
│ [________________] │
|
||||
│ Critères: [ ] │
|
||||
│ [________________] │
|
||||
│ □ SMART │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ ▼ Classification │
|
||||
│ Type: [Functional ▼] │
|
||||
│ Catégorie: [Backend ▼] │
|
||||
│ Priorité: ● ● ● ○ ○ (3/5) │
|
||||
│ Statut: ○ Draft ○ Review │
|
||||
│ ● Approved ○ Rejected │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ [Enregistrer] [Annuler] │
|
||||
└─────────────────────────────────────────────┘
|
||||
*/
|
||||
@@ -67,9 +67,12 @@ class wxNode : private dBus::Node
|
||||
// derived class to handle incoming messages from the bus
|
||||
virtual void on_receiveMessageFromBus(MessageID messageID, MessagePtr message) = 0;
|
||||
|
||||
using Node::m_bus; // Reference to the bus this node is connected to
|
||||
|
||||
protected:
|
||||
wxWindow *m_owner = nullptr; // Pointer to the owner window (for posting events to the GUI)
|
||||
std::jthread m_eventThread; // Thread for listening to messages from the bus
|
||||
wxWindow *m_owner = nullptr; // Pointer to the owner window (for posting events to the GUI)
|
||||
|
||||
std::jthread m_eventThread; // Thread for listening to messages from the bus
|
||||
|
||||
private:
|
||||
void startEventThread(); // Start the event thread to listen for messages from the bus
|
||||
|
||||
Reference in New Issue
Block a user