From bf5dabb16971e1482f07339ec60ab5880f6943bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Monta=C3=B1ana=20G=C3=B3mez?= Date: Thu, 14 Mar 2024 23:41:05 +0100 Subject: [PATCH] Add pagination to b_manage --- src/common/Colors.h | 15 +++++++++++ src/manage/CommandParser.cpp | 4 +-- src/manage/CommandParser.h | 2 +- src/manage/ManageResults.cpp | 51 +++++++++++++++++++++++++++--------- src/manage/ManageResults.h | 3 +++ src/manage/Paginator.hpp | 29 ++++++++++++++++++++ 6 files changed, 89 insertions(+), 15 deletions(-) create mode 100644 src/manage/Paginator.hpp diff --git a/src/common/Colors.h b/src/common/Colors.h index 6818a2c..9c8da43 100644 --- a/src/common/Colors.h +++ b/src/common/Colors.h @@ -12,4 +12,19 @@ public: static std::string WHITE() { return "\033[1;37m"; } static std::string IBLUE() { return "\033[0;94m"; } static std::string RESET() { return "\033[0m"; } + static std::string BOLD() { return "\033[1m"; } + static std::string UNDERLINE() { return "\033[4m"; } + static std::string BLINK() { return "\033[5m"; } + static std::string REVERSE() { return "\033[7m"; } + static std::string CONCEALED() { return "\033[8m"; } + static std::string BLACK() { return "\033[1;30m"; } + static std::string IBROWN() { return "\033[0;93m"; } + static std::string IRED() { return "\033[0;91m"; } + static std::string IWHITE() { return "\033[0;97m"; } + static std::string IGREEN() { return "\033[0;92m"; } + static std::string IYELLOW() { return "\033[0;93m"; } + static std::string ICYAN() { return "\033[0;96m"; } + static std::string IBLACK() { return "\033[0;90m"; } + static std::string IMAGENTA() { return "\033[0;95m"; } + static std::string CLRSCR() { return "\033[2J\033[1;1H"; } }; diff --git a/src/manage/CommandParser.cpp b/src/manage/CommandParser.cpp index f4bce28..5c8c96d 100644 --- a/src/manage/CommandParser.cpp +++ b/src/manage/CommandParser.cpp @@ -10,7 +10,7 @@ namespace platform { { std::cout << Colors::RED() << message << Colors::RESET() << std::endl; } - std::pair CommandParser::parse(const std::string& color, const std::vector>& options, const char defaultCommand, const int maxIndex) + std::pair CommandParser::parse(const std::string& color, const std::vector>& options, const char defaultCommand, const int minIndex, const int maxIndex) { bool finished = false; while (!finished) { @@ -36,7 +36,7 @@ namespace platform { if (all_of(line.begin(), line.end(), ::isdigit)) { command = defaultCommand; index = stoi(line); - if (index > maxIndex || index < 0) { + if (index > maxIndex || index < minIndex) { messageError("Index out of range"); continue; } diff --git a/src/manage/CommandParser.h b/src/manage/CommandParser.h index 65aa544..8bbbc5e 100644 --- a/src/manage/CommandParser.h +++ b/src/manage/CommandParser.h @@ -8,7 +8,7 @@ namespace platform { class CommandParser { public: CommandParser() = default; - std::pair parse(const std::string& color, const std::vector>& options, const char defaultCommand, const int maxIndex); + std::pair parse(const std::string& color, const std::vector>& options, const char defaultCommand, const int minIndex, const int maxIndex); char getCommand() const { return command; }; int getIndex() const { return index; }; private: diff --git a/src/manage/ManageResults.cpp b/src/manage/ManageResults.cpp index 5d32828..9f031e5 100644 --- a/src/manage/ManageResults.cpp +++ b/src/manage/ManageResults.cpp @@ -23,6 +23,8 @@ namespace platform { this->numFiles = results.size(); } } + paginator = Paginator(numFiles, results.size()); + page = 1; } void ManageResults::doMenu() { @@ -41,10 +43,10 @@ namespace platform { void ManageResults::list() { auto temp = ConfigLocale(); - std::string suffix = numFiles != results.size() ? " of " + std::to_string(results.size()) : ""; + auto [index_from, index_to] = paginator.getOffset(page); std::stringstream oss; - oss << "Results on screen: " << numFiles << suffix; - std::cout << Colors::GREEN() << oss.str() << std::endl; + oss << index_to - index_from + 1 << " Results on screen - Page " << page << " of " << paginator.getPages(); + std::cout << Colors::CLRSCR() << Colors::GREEN() << oss.str() << std::endl; std::cout << std::string(oss.str().size(), '-') << std::endl; if (complete) { std::cout << Colors::MAGENTA() << "Only listing complete results" << std::endl; @@ -57,13 +59,10 @@ namespace platform { int maxTitle = results.maxTitleSize(); std::cout << Colors::GREEN() << " # Date " << std::setw(maxModel) << std::left << "Model" << " Score Name Score C/P Duration Title" << std::endl; std::cout << "=== ========== " << std::string(maxModel, '=') << " =========== =========== === ========= " << std::string(maxTitle, '=') << std::endl; - for (auto& result : results) { + for (int i = index_from; i <= index_to; i++) { auto color = (i % 2) ? Colors::BLUE() : Colors::CYAN(); - std::cout << color << std::setw(3) << std::fixed << std::right << i++ << " "; - std::cout << result.to_string(maxModel) << std::endl; - if (i == numFiles) { - break; - } + std::cout << color << std::setw(3) << std::fixed << std::right << i << " "; + std::cout << results.at(i).to_string(maxModel) << std::endl; } } bool ManageResults::confirmAction(const std::string& intent, const std::string& fileName) const @@ -166,7 +165,10 @@ namespace platform { {"title", 't', true}, {"set A", 'a', true}, {"set B", 'b', true}, - {"compare A~B", 'c', false} + {"compare A~B", 'c', false}, + {"Page", 'p', true}, + {"Page+", '+', false }, + {"Page-", '-', false} }; // tuple std::vector> listOptions = { @@ -178,11 +180,36 @@ namespace platform { auto parser = CommandParser(); while (!finished) { if (indexList) { - std::tie(option, index) = parser.parse(Colors::GREEN(), mainOptions, 'r', numFiles - 1); + auto [min_index, max_index] = paginator.getOffset(page); + std::tie(option, index) = parser.parse(Colors::GREEN(), mainOptions, 'r', min_index, max_index); } else { - std::tie(option, subIndex) = parser.parse(Colors::BLUE(), listOptions, 'r', results.at(index).getJson()["results"].size() - 1); + std::tie(option, subIndex) = parser.parse(Colors::BLUE(), listOptions, 'r', 0, results.at(index).getJson()["results"].size() - 1); } switch (option) { + case 'p': + if (paginator.valid(index)) { + page = index; + list(); + } else { + std::cout << Colors::RED() << "Invalid page!" << Colors::RESET() << std::endl; + } + break; + case '+': + if (paginator.hasNext(page)) { + page++; + list(); + } else { + std::cout << Colors::RED() << "No more pages!" << Colors::RESET() << std::endl; + } + break; + case '-': + if (paginator.hasPrev(page)) { + page--; + list(); + } else { + std::cout << Colors::RED() << "First page already!" << Colors::RESET() << std::endl; + } + break; case 'q': finished = true; break; diff --git a/src/manage/ManageResults.h b/src/manage/ManageResults.h index 394c9ec..53ba83c 100644 --- a/src/manage/ManageResults.h +++ b/src/manage/ManageResults.h @@ -2,6 +2,7 @@ #include #include "ResultsManager.h" +#include "Paginator.hpp" namespace platform { class ManageResults { @@ -23,6 +24,8 @@ namespace platform { bool complete; bool partial; bool compare; + int page; + Paginator paginator; ResultsManager results; lxw_workbook* workbook; }; diff --git a/src/manage/Paginator.hpp b/src/manage/Paginator.hpp new file mode 100644 index 0000000..a524cd7 --- /dev/null +++ b/src/manage/Paginator.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +class Paginator { +public: + Paginator() = default; + Paginator(int pageSize, int total) : pageSize(pageSize), total(total) + { + numPages = (total + pageSize - 1) / pageSize; + }; + ~Paginator() = default; + int getPageSize() const { return pageSize; } + int getTotal() const { return total; } + std::pair getOffset(int page) const + { + if (page > numPages) + throw std::out_of_range("page out of range"); + return { (page - 1) * pageSize, std::min(total - 1, page * pageSize - 1) }; + } + int getPages() const { return numPages; } + bool valid(int page) const { return page > 0 && page <= numPages; } + bool hasPrev(int page) const { return page > 1; } + bool hasNext(int page) const { return page < getPages(); } +private: + int pageSize; + int total; + int numPages; +}; \ No newline at end of file