Skip to content

Commit

Permalink
(core): Implement late initialisation to Board
Browse files Browse the repository at this point in the history
* Rename operation methods
  • Loading branch information
smolBlackCat committed Oct 31, 2024
1 parent 311a0af commit 400c8bc
Show file tree
Hide file tree
Showing 13 changed files with 337 additions and 229 deletions.
321 changes: 172 additions & 149 deletions src/core/board.cpp
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
#include "board.h"

#include <bits/chrono.h>

#include <cctype>
#include <chrono>
#include <cstdlib>
#include <filesystem>
#include <format>
#include <iostream>
#include <regex>
#include <set>
#include <stdexcept>
#include <string>

#include "exceptions.h"

Expand Down Expand Up @@ -90,90 +84,7 @@ Board BoardBackend::load() {
board.last_modified =
std::chrono::floor<std::chrono::seconds>(lm_filepath);

auto list_element = board_element->FirstChildElement("list");

while (list_element) {
auto cur_cardlist_name = list_element->Attribute("name");

if (!cur_cardlist_name) {
throw board_parse_error{std::format(
"Failed to parse given Progress Board XML file: {}\n"
"A \"list\" element on line {} failed to parsed.",
settings["filepath"], list_element->GetLineNum())};
}

CardList cur_cardlist{cur_cardlist_name};
auto card_element = list_element->FirstChildElement("card");

while (card_element) {
auto cur_card_name = card_element->Attribute("name");
auto cur_card_color = card_element->Attribute("color");
auto cur_card_due_date = card_element->Attribute("due");
auto cur_card_complete =
card_element->BoolAttribute("complete");

if (!cur_card_name) {
throw board_parse_error{std::format(
"Failed to parse given Progress Board XML file: "
"{}\n"
"Failed to load {} \"list\" element\n"
"\"card\" element on line {} has no name attribute",
settings["filepath"], cur_cardlist_name,
card_element->GetLineNum())};
}

Date date{};

if (cur_card_due_date) {
const std::regex date_r{"\\d\\d\\d\\d-\\d\\d-\\d\\d"};

if (!std::regex_match(cur_card_due_date, date_r)) {
throw board_parse_error{std::format(
"Invalid due date at Card {}", cur_card_name)};
}
std::chrono::sys_seconds secs;

std::istringstream{std::string{cur_card_due_date}} >>
std::chrono::parse("%F", secs);
Date date{std::chrono::floor<std::chrono::days>(secs)};
date = date;
}

Card cur_card{
cur_card_name,
date,
cur_card_complete,
cur_card_color ? string_to_color(cur_card_color)
: NO_COLOR,
};

auto task_element = card_element->FirstChildElement("task");
while (task_element) {
cur_card.add_task(
Task{task_element->Attribute("name"),
task_element->BoolAttribute("done")});
task_element = task_element->NextSiblingElement("task");
}

auto notes_element =
card_element->FirstChildElement("notes");
if (notes_element) {
cur_card.set_notes(!notes_element->GetText()
? ""
: notes_element->GetText());
}

cur_card.set_modified(false);

cur_cardlist.add_card(cur_card);
card_element = card_element->NextSiblingElement("card");
}
cur_cardlist.set_modified(false);
board.add_cardlist(cur_cardlist);

list_element = list_element->NextSiblingElement("list");
}
board.set_modified(false);
board.modified = false;
return board;
}
case BackendType::CALDAV:
Expand All @@ -185,10 +96,14 @@ Board BoardBackend::load() {
Board BoardBackend::create(const std::string& name,
const std::string& background) {
Board board{*this};

// Because a new Board is created from scratch, it is essentially loaded
board.fully_loaded = true;

board.set_name(name);
board.set_background(background);

board.set_modified(false);

return board;
}

Expand Down Expand Up @@ -217,13 +132,106 @@ bool BoardBackend::set_attribute(const std::string& key,
}

bool BoardBackend::save(Board& board) {
switch (type) {
case BackendType::LOCAL:
return save_xml(board);
case BackendType::CALDAV:
return save_caldav(board);
case BackendType::NEXTCLOUD:
return save_nextcloud(board);
if (board.fully_loaded) {
switch (type) {
case BackendType::LOCAL:
return save_xml(board);
case BackendType::CALDAV:
return save_caldav(board);
case BackendType::NEXTCLOUD:
return save_nextcloud(board);
}
}
return false;
}

void BoardBackend::load_cardlists(Board& board) {
if (!board.fully_loaded) {
tinyxml2::XMLDocument doc;
doc.LoadFile(settings["filepath"].c_str());
board.fully_loaded = true;
auto list_element =
doc.FirstChildElement("board")->FirstChildElement("list");

while (list_element) {
auto cur_cardlist_name = list_element->Attribute("name");

if (!cur_cardlist_name) {
throw board_parse_error{std::format(
"Failed to parse given Progress Board XML file: {}\n"
"A \"list\" element on line {} failed to parsed.",
settings["filepath"], list_element->GetLineNum())};
}

CardList cur_cardlist{cur_cardlist_name};
auto card_element = list_element->FirstChildElement("card");

while (card_element) {
auto cur_card_name = card_element->Attribute("name");
auto cur_card_color = card_element->Attribute("color");
auto cur_card_due_date = card_element->Attribute("due");
auto cur_card_complete =
card_element->BoolAttribute("complete");

if (!cur_card_name) {
throw board_parse_error{std::format(
"Failed to parse given Progress Board XML file: "
"{}\n"
"Failed to load {} \"list\" element\n"
"\"card\" element on line {} has no name attribute",
settings["filepath"], cur_cardlist_name,
card_element->GetLineNum())};
}

Date date{};

if (cur_card_due_date) {
const std::regex date_r{"\\d\\d\\d\\d-\\d\\d-\\d\\d"};

if (!std::regex_match(cur_card_due_date, date_r)) {
throw board_parse_error{std::format(
"Invalid due date at Card {}", cur_card_name)};
}
std::chrono::sys_seconds secs;

std::istringstream{std::string{cur_card_due_date}} >>
std::chrono::parse("%F", secs);
Date date{std::chrono::floor<std::chrono::days>(secs)};
date = date;
}

Card cur_card{
cur_card_name,
date,
cur_card_complete,
cur_card_color ? string_to_color(cur_card_color) : NO_COLOR,
};

auto task_element = card_element->FirstChildElement("task");
while (task_element) {
cur_card.add(Task{task_element->Attribute("name"),
task_element->BoolAttribute("done")});
task_element = task_element->NextSiblingElement("task");
}

auto notes_element = card_element->FirstChildElement("notes");
if (notes_element) {
cur_card.set_notes(!notes_element->GetText()
? ""
: notes_element->GetText());
}

cur_card.set_modified(false);

cur_cardlist.add(cur_card);
card_element = card_element->NextSiblingElement("card");
}
cur_cardlist.set_modified(false);
board.add(cur_cardlist);

list_element = list_element->NextSiblingElement("list");
}
board.set_modified(false);
}
}

Expand Down Expand Up @@ -313,90 +321,105 @@ BackgroundType Board::set_background(const std::string& other, bool modify) {

const std::string& Board::get_background() const { return background; }

std::shared_ptr<CardList> Board::add_cardlist(const CardList& cardlist) {
for (auto& ccardlist : cardlists) {
if (*ccardlist == cardlist) {
return nullptr;
std::shared_ptr<CardList> Board::add(const CardList& cardlist) {
if (fully_loaded) {
for (auto& ccardlist : cardlists) {
if (*ccardlist == cardlist) {
return nullptr;
}
}
}

try {
std::shared_ptr<CardList> new_cardlist =
std::make_shared<CardList>(cardlist);
cardlists.push_back(new_cardlist);
modified = true;
return new_cardlist;
} catch (std::bad_alloc& err) {
return nullptr;
try {
std::shared_ptr<CardList> new_cardlist =
std::make_shared<CardList>(cardlist);
cardlists.push_back(new_cardlist);
modified = true;
return new_cardlist;
} catch (std::bad_alloc& err) {
return nullptr;
}
}
return nullptr;
}

bool Board::remove_cardlist(const CardList& cardlist) {
for (size_t i = 0; i < cardlists.size(); i++) {
if (cardlist == (*cardlists.at(i))) {
cardlists.erase(cardlists.begin() + i);
modified = true;
return true;
bool Board::remove(const CardList& cardlist) {
if (fully_loaded) {
for (size_t i = 0; i < cardlists.size(); i++) {
if (cardlist == (*cardlists.at(i))) {
cardlists.erase(cardlists.begin() + i);
modified = true;
return true;
}
}
}
return false;
}

void Board::reorder_cardlist(const CardList& next, const CardList& sibling) {
ssize_t next_i = -1;
ssize_t sibling_i = -1;

for (ssize_t i = 0; i < cardlists.size(); i++) {
if (*cardlists[i] == next) {
next_i = i;
} else if (*cardlists[i] == sibling) {
sibling_i = i;
void Board::reorder(const CardList& next, const CardList& sibling) {
if (fully_loaded) {
ssize_t next_i = -1;
ssize_t sibling_i = -1;

ssize_t c = 0;
for (auto& cardlist : cardlists) {
if (*cardlist == next) {
next_i = c;
} else if (*cardlist == sibling) {
sibling_i = c;
}
c++;
}
}

bool any_absent_item = next_i + sibling_i < 0;
bool is_same_item = next_i == sibling_i;
bool already_in_order = next_i - sibling_i == 1;
if (any_absent_item || is_same_item || already_in_order) {
return;
}
bool any_absent_item = next_i + sibling_i < 0;
bool is_same_item = next_i == sibling_i;
bool already_in_order = next_i - sibling_i == 1;
if (any_absent_item || is_same_item || already_in_order) {
return;
}

auto next_it = std::next(cardlists.begin(), next_i);
std::shared_ptr<CardList> temp_v = cardlists[next_i];
cardlists.erase(next_it);
auto next_it = std::next(cardlists.begin(), next_i);
std::shared_ptr<CardList> temp_v = cardlists[next_i];
cardlists.erase(next_it);

// Support for right to left drags and drops
if (next_i < sibling_i) {
sibling_i -= 1;
}
// Support for right to left drags and drops
if (next_i < sibling_i) {
sibling_i -= 1;
}

if (sibling_i == cardlists.size() - 1) {
cardlists.push_back(temp_v);
} else {
auto sibling_it = std::next(cardlists.begin(), sibling_i + 1);
cardlists.insert(sibling_it, temp_v);
if (sibling_i == cardlists.size() - 1) {
cardlists.push_back(temp_v);
} else {
auto sibling_it = std::next(cardlists.begin(), sibling_i + 1);
cardlists.insert(sibling_it, temp_v);
}
modified = true;
}
modified = true;
}

bool Board::save() { return backend.save(*this); }

void Board::load() { backend.load_cardlists(*this); }

const std::vector<std::shared_ptr<CardList>>& Board::get_cardlists() {
return cardlists;
}

void Board::set_modified(bool modified) {
Item::set_modified(modified);
if (fully_loaded) {
Item::set_modified(modified);

for (auto& cardlist : cardlists) {
cardlist->set_modified(modified);
for (auto& cardlist : cardlists) {
cardlist->set_modified(modified);
}
}
}

time_point<system_clock, seconds> Board::get_last_modified() const {
return last_modified;
}

bool Board::is_loaded() { return fully_loaded; }

bool Board::get_modified() {
for (auto& cardlist : cardlists) {
if (cardlist->get_modified()) {
Expand Down
Loading

0 comments on commit 400c8bc

Please sign in to comment.