diff --git a/src/gui/mainFrame.cpp b/src/gui/mainFrame.cpp index 8d1acbb..7a089ac 100644 --- a/src/gui/mainFrame.cpp +++ b/src/gui/mainFrame.cpp @@ -23,8 +23,10 @@ MainFrame::MainFrame(dBus::Bus &bus) // Initialization SetIcon(wxICON(AAAA_ICON)); - const wxSize minSize(1200, 900); + const wxSize minSize(1024, 768); + const wxSize maxSize(1200, -1); SetMinSize(minSize); + SetMaxSize(maxSize); SetSize(minSize); // Creating controls diff --git a/src/gui/requirementsPanel/requirementDetailPanel/requirementDetailPanel.cpp b/src/gui/requirementsPanel/requirementDetailPanel/requirementDetailPanel.cpp index 49541aa..01de239 100644 --- a/src/gui/requirementsPanel/requirementDetailPanel/requirementDetailPanel.cpp +++ b/src/gui/requirementsPanel/requirementDetailPanel/requirementDetailPanel.cpp @@ -1,15 +1,16 @@ #include "requirementDetailPanel.h" +#include + using namespace std; using namespace gui; //-------------------------------------------------------------- /* Constructor */ RequirementDetailPanel::RequirementDetailPanel(wxWindow *parentWindow, dBus::Bus &bus) - : wxScrolledWindow(parentWindow, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER | wxVSCROLL) + : wxPanel(parentWindow /*, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER*/) , m_bus(bus) { // Initialization - SetScrollRate(0, 10); // Set the scroll rate for the panel (vertical only) // Creating controls createControls(); @@ -20,24 +21,35 @@ RequirementDetailPanel::RequirementDetailPanel(wxWindow *parentWindow, dBus::Bus /* Creating controls */ void RequirementDetailPanel::createControls() { - const auto mainPanel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(500, -1), wxSIMPLE_BORDER); + const auto mainPanel = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL); + mainPanel->SetScrollRate(0, 10); // Set the scroll rate for the panel (vertical only) + + const auto closeButton = new wxButton(this, wxID_ANY, _("Close")); + const auto saveButton = new wxButton(this, wxID_ANY, _("Save")); + const auto discardButton = new wxButton(this, wxID_ANY, _("Discard")); // 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()); + ctrlSizer->Add(createControls_metadata(mainPanel), wxSizerFlags(0).Expand().Border(wxALL & ~wxTOP, 5)); + ctrlSizer->Add(createControls_details(mainPanel), wxSizerFlags(0).Expand().Border(wxALL & ~wxTOP, 5)); + ctrlSizer->Add(createControls_classification(mainPanel), wxSizerFlags(0).Expand().Border(wxALL & ~wxTOP & ~wxBOTTOM, 5)); mainPanel->SetSizer(ctrlSizer); + const auto buttonSizer = new wxBoxSizer(wxVERTICAL); + buttonSizer->Add(closeButton, wxSizerFlags(0).Expand()); + buttonSizer->AddStretchSpacer(1); + buttonSizer->Add(discardButton, wxSizerFlags(0).Expand().Border(wxBOTTOM, 5)); + buttonSizer->Add(saveButton, wxSizerFlags(0).Expand()); + const auto mainSizer = new wxBoxSizer(wxHORIZONTAL); - mainSizer->Add(mainPanel, wxSizerFlags(0).Expand()); - mainSizer->AddStretchSpacer(1); + mainSizer->Add(mainPanel, wxSizerFlags(1).Expand().Border(wxLEFT | wxRIGHT, 5)); + mainSizer->Add(buttonSizer, wxSizerFlags(0).Expand().Border(wxALL, 5)); SetSizer(mainSizer); // Set the virtual size to match the size of the child panel, // enabling scrolling if necessary - FitInside(); + mainPanel->FitInside(); // Harmonize the sizes of the title controls to ensure they have the same width updateTitleSizes(); @@ -47,46 +59,30 @@ void RequirementDetailPanel::createControls() /* Creating controls for requirement metadata (ID, UUID, name, description, etc.) */ wxSizer *RequirementDetailPanel::createControls_metadata(wxWindow *owner) { - struct Item - { - wxWindow *titleCtrl; - wxWindow *inputCtrl; - }; - std::vector items; + const auto uuidTitleCtrl = createTitle(owner, _T("UUID:")); + const auto idTitleCtrl = createTitle(owner, _T("ID:")); + const auto authorTitleCtrl = createTitle(owner, _("Author:")); + const auto createdAtTitleCtrl = createTitle(owner, _("Created at:")); + const auto updatedAtTitleCtrl = createTitle(owner, _("Updated at:")); - { - 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); - } + const auto uuidValueCtrl = new wxTextCtrl(owner, wxID_ANY); + const auto idValueCtrl = new wxTextCtrl(owner, wxID_ANY); + const auto authorValueCtrl = new wxTextCtrl(owner, wxID_ANY); + const auto createdAtValueCtrl = new wxTextCtrl(owner, wxID_ANY); + const auto updatedAtValueCtrl = new wxTextCtrl(owner, wxID_ANY); // 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->Add(uuidTitleCtrl, wxSizerFlags(0).Expand().CenterVertical()); + ctrlSizer->Add(uuidValueCtrl, wxSizerFlags(1).Expand()); + ctrlSizer->Add(idTitleCtrl, wxSizerFlags(0).Expand().CenterVertical()); + ctrlSizer->Add(idValueCtrl, wxSizerFlags(1).Expand()); + ctrlSizer->Add(authorTitleCtrl, wxSizerFlags(0).Expand().CenterVertical()); + ctrlSizer->Add(authorValueCtrl, wxSizerFlags(1).Expand()); + ctrlSizer->Add(createdAtTitleCtrl, wxSizerFlags(0).Expand().CenterVertical()); + ctrlSizer->Add(createdAtValueCtrl, wxSizerFlags(1).Expand()); + ctrlSizer->Add(updatedAtTitleCtrl, wxSizerFlags(0).Expand().CenterVertical()); + ctrlSizer->Add(updatedAtValueCtrl, wxSizerFlags(1).Expand()); ctrlSizer->AddGrowableCol(1, 1); // Controls positioning @@ -99,55 +95,28 @@ wxSizer *RequirementDetailPanel::createControls_metadata(wxWindow *owner) /* 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 items; + const auto titleTitleCtrl = createTitle(owner, _("Title:")); + const auto descriptionTitleCtrl = createTitle(owner, _("Description:")); + const auto acceptanceCriteriaTitleCtrl = createTitle(owner, _("Acceptance criteria:")); - { - 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); + const auto titleValueCtrl = new wxTextCtrl(owner, wxID_ANY); + const auto descriptionValueCtrl = new wxTextCtrl(owner, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_TAB | wxTE_MULTILINE); + const auto acceptanceCriteriaValueCtrl = new wxTextCtrl(owner, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_TAB | wxTE_MULTILINE); + const auto smartCheckBoxCtrl = new wxCheckBox(owner, wxID_ANY, _("S.M.A.R.T.")); - 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); - } + descriptionValueCtrl->SetMinSize(wxSize(-1, 200)); + acceptanceCriteriaValueCtrl->SetMinSize(wxSize(-1, 100)); // 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->Add(titleTitleCtrl, wxSizerFlags(0).Expand().CenterVertical()); + ctrlSizer->Add(titleValueCtrl, wxSizerFlags(1).Expand()); + ctrlSizer->Add(descriptionTitleCtrl, wxSizerFlags(0).Expand()); + ctrlSizer->Add(descriptionValueCtrl, wxSizerFlags(1).Expand()); + ctrlSizer->Add(acceptanceCriteriaTitleCtrl, wxSizerFlags(0).Expand()); + ctrlSizer->Add(acceptanceCriteriaValueCtrl, wxSizerFlags(1).Expand()); + ctrlSizer->AddStretchSpacer(); + ctrlSizer->Add(smartCheckBoxCtrl, wxSizerFlags(1).Expand()); ctrlSizer->AddGrowableCol(1, 1); const auto localSizer = new wxStaticBoxSizer(wxVERTICAL, owner, "Details"); @@ -159,41 +128,26 @@ wxSizer *RequirementDetailPanel::createControls_details(wxWindow *owner) /* Creating controls for requirement classification (e.g., priority, severity, etc.) */ wxSizer *RequirementDetailPanel::createControls_classification(wxWindow *owner) { - struct Item - { - wxWindow *titleCtrl; - wxWindow *inputCtrl; - }; - std::vector items; + const auto typeTitleCtrl = createTitle(owner, _("Type:")); + const auto categoryTitleCtrl = createTitle(owner, _("Category:")); + const auto priorityTitleCtrl = createTitle(owner, _("Priority:")); + const auto statusTitleCtrl = createTitle(owner, _("Status:")); - { - 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); - } + const auto typeValueCtrl = new wxTextCtrl(owner, wxID_ANY); + const auto categoryValueCtrl = new wxTextCtrl(owner, wxID_ANY); + const auto priorityValueCtrl = new wxTextCtrl(owner, wxID_ANY); + const auto statusValueCtrl = new wxTextCtrl(owner, wxID_ANY); // 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->Add(typeTitleCtrl, wxSizerFlags(0).Expand().CenterVertical()); + ctrlSizer->Add(typeValueCtrl, wxSizerFlags(1).Expand()); + ctrlSizer->Add(categoryTitleCtrl, wxSizerFlags(0).Expand().CenterVertical()); + ctrlSizer->Add(categoryValueCtrl, wxSizerFlags(1).Expand()); + ctrlSizer->Add(priorityTitleCtrl, wxSizerFlags(0).Expand().CenterVertical()); + ctrlSizer->Add(priorityValueCtrl, wxSizerFlags(1).Expand()); + ctrlSizer->Add(statusTitleCtrl, wxSizerFlags(0).Expand().CenterVertical()); + ctrlSizer->Add(statusValueCtrl, wxSizerFlags(1).Expand()); ctrlSizer->AddGrowableCol(1, 1); const auto localSizer = new wxStaticBoxSizer(wxVERTICAL, owner, "Classification"); @@ -211,6 +165,7 @@ wxStaticText *RequirementDetailPanel::createTitle(wxWindow *owner, const wxStrin wxDefaultPosition, wxDefaultSize, wxST_NO_AUTORESIZE | wxALIGN_RIGHT); + ctrl->SetFont(GetFont().Italic()); m_titleControls.push_back(ctrl); diff --git a/src/gui/requirementsPanel/requirementDetailPanel/requirementDetailPanel.h b/src/gui/requirementsPanel/requirementDetailPanel/requirementDetailPanel.h index 5da44ce..f352415 100644 --- a/src/gui/requirementsPanel/requirementDetailPanel/requirementDetailPanel.h +++ b/src/gui/requirementsPanel/requirementDetailPanel/requirementDetailPanel.h @@ -6,7 +6,7 @@ namespace gui { //-------------------------------------------------------------- -class RequirementDetailPanel : public wxScrolledWindow +class RequirementDetailPanel : public wxPanel { public: RequirementDetailPanel() = delete; // Default constructor diff --git a/src/gui/requirementsPanel/requirementListPanel/requirementTreeModel.h b/src/gui/requirementsPanel/requirementListPanel/requirementTreeModel.h new file mode 100644 index 0000000..4559234 --- /dev/null +++ b/src/gui/requirementsPanel/requirementListPanel/requirementTreeModel.h @@ -0,0 +1,72 @@ +#pragma once + +#include +#include +#include + +namespace gui +{ +//-------------------------------------------------------------- +struct RequirementData +{ + std::string uuid; + std::string id; + std::string title; + + RequirementData *parent; + std::vector> children; + + RequirementData(std::string uuid_, std::string id_, std::string title_) + : uuid(std::move(uuid_)) + , id(std::move(id_)) + , title(std::move(title_)) + { + } + + // Adds a child requirement + RequirementData *AddChild(std::unique_ptr child) + { + child->parent = this; + children.push_back(std::move(child)); + return children.back().get(); + } +}; +//-------------------------------------------------------------- + +/* --- */ + +//-------------------------------------------------------------- +class RequirementTreeModel : public wxDataViewModel +{ + public: + RequirementTreeModel(); // Default constructor + virtual ~RequirementTreeModel() = default; // Default destructor + RequirementTreeModel(const RequirementTreeModel &obj) = delete; // Copy constructor + RequirementTreeModel(RequirementTreeModel &&obj) noexcept = delete; // Move constructor + RequirementTreeModel &operator=(const RequirementTreeModel &obj) = delete; // Copy assignment operator + RequirementTreeModel &operator=(RequirementTreeModel &&obj) noexcept = delete; // Move assignment operator + + // wxDataViewModel overrides methods + unsigned GetColumnCount() const override; + wxString GetColumnType(unsigned) const override; + + void GetValue(wxVariant &variant, const wxDataViewItem &item, unsigned col) const override; + bool SetValue(const wxVariant &variant, const wxDataViewItem &item, unsigned col) override; + + wxDataViewItem GetParent(const wxDataViewItem &item) const override; + bool IsContainer(const wxDataViewItem &item) const override; + bool HasContainerColumns(const wxDataViewItem &) const override; + + unsigned GetChildren(const wxDataViewItem &item, wxDataViewItemArray &children) const override; + + // Tree data model specific methods + RequirementData *AddRootRequirement(std::unique_ptr requirementData); // Add a root requirement to the tree + RequirementData *AddChildRequirement(RequirementData *parent, std::unique_ptr requirementData); // Add a child requirement to a parent requirement + void clear(); + RequirementData *GetRequirementData(const wxDataViewItem &item) const; // Get the requirement data associated with a given item + + protected: + std::vector> m_rootRequirement; +}; +//-------------------------------------------------------------- +} // namespace gui diff --git a/src/gui/requirementsPanel/requirementsPanel.cpp b/src/gui/requirementsPanel/requirementsPanel.cpp index 02f94e9..0177663 100644 --- a/src/gui/requirementsPanel/requirementsPanel.cpp +++ b/src/gui/requirementsPanel/requirementsPanel.cpp @@ -29,6 +29,7 @@ void RequirementsPanel::createControls() 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)); + //mainSizer->AddStretchSpacer(1); SetSizer(mainSizer); }