diff options
author | rtk0c <[email protected]> | 2022-06-27 18:27:13 -0700 |
---|---|---|
committer | rtk0c <[email protected]> | 2022-06-27 18:27:13 -0700 |
commit | 8f0dda5eab181b0f14f2652b4e984aaaae3f258c (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /core/src/Model/Template/TableTemplate.cpp | |
parent | fad6a88a13ab1f888ab25ad0aae19c1d63aa0623 (diff) |
Start from a clean slate
Diffstat (limited to 'core/src/Model/Template/TableTemplate.cpp')
-rw-r--r-- | core/src/Model/Template/TableTemplate.cpp | 591 |
1 files changed, 0 insertions, 591 deletions
diff --git a/core/src/Model/Template/TableTemplate.cpp b/core/src/Model/Template/TableTemplate.cpp deleted file mode 100644 index 57caac4..0000000 --- a/core/src/Model/Template/TableTemplate.cpp +++ /dev/null @@ -1,591 +0,0 @@ -#include "TableTemplate.hpp" - -#include "Utils/IO/StringIntegration.hpp" -#include "Utils/IO/TslArrayIntegration.hpp" -#include "Utils/IO/VectorIntegration.hpp" - -#include <xlsxwriter.h> -#include <algorithm> -#include <charconv> -#include <cstddef> -#include <cstdint> -#include <iostream> -#include <map> - -bool TableCell::IsDataHoldingCell() const -{ - return IsPrimaryCell() || !IsMergedCell(); -} - -bool TableCell::IsPrimaryCell() const -{ - return PrimaryCellLocation == Location; -} - -bool TableCell::IsMergedCell() const -{ - return PrimaryCellLocation.x == -1 || PrimaryCellLocation.y == -1; -} - -template <class TTableCell, class TStream> -void OperateStreamForTableCell(TTableCell& cell, TStream& proxy) -{ - proxy.template ObjectAdapted<DataStreamAdapters::String>(cell.Content); - proxy.Object(cell.Location); - proxy.Object(cell.PrimaryCellLocation); - proxy.Value(cell.SpanX); - proxy.Value(cell.SpanY); - proxy.Enum(cell.HorizontalAlignment); - proxy.Enum(cell.VerticalAlignment); - proxy.Enum(cell.Type); - proxy.Value(cell.DataId); -} - -void TableCell::ReadFromDataStream(InputDataStream& stream) -{ - ::OperateStreamForTableCell(*this, stream); -} - -void TableCell::WriteToDataStream(OutputDataStream& stream) const -{ - ::OperateStreamForTableCell(*this, stream); -} - -Vec2i TableArrayGroup::GetLeftCell() const -{ - return { Row, LeftCell }; -} - -Vec2i TableArrayGroup::GetRightCell() const -{ - return { Row, RightCell }; -} - -int TableArrayGroup::GetCount() const -{ - return RightCell - LeftCell + 1; -} - -Vec2i TableArrayGroup::FindCell(std::string_view name) -{ - // TODO - return Vec2i{}; -} - -template <class TMap> -static bool UpdateElementName(TMap& map, std::string_view oldName, std::string_view newName) -{ - auto iter = map.find(oldName); - if (iter == map.end()) { - return false; - } - - auto elm = iter.value(); - auto [DISCARD, inserted] = map.insert(newName, elm); - if (!inserted) { - return false; - } - - map.erase(iter); - return true; -} - -bool TableArrayGroup::UpdateCellName(std::string_view oldName, std::string_view newName) -{ - return ::UpdateElementName(mName2Cell, oldName, newName); -} - -template <class TTableArrayGroup, class TStream> -void OperateStreamForTableArrayGroup(TTableArrayGroup& group, TStream& stream) -{ - stream.Value(group.Row); - stream.Value(group.LeftCell); - stream.Value(group.RightCell); -} - -void TableArrayGroup::ReadFromDataStream(InputDataStream& stream) -{ - ::OperateStreamForTableArrayGroup(*this, stream); -} - -void TableArrayGroup::WriteToDataStream(OutputDataStream& stream) const -{ - ::OperateStreamForTableArrayGroup(*this, stream); -} - -TableInstantiationParameters::TableInstantiationParameters(const TableTemplate& table) - : mTable{ &table } -{ -} - -TableInstantiationParameters& TableInstantiationParameters::ResetTable(const TableTemplate& newTable) -{ - mTable = &newTable; - return *this; -} - -TableInstantiationParameters TableInstantiationParameters::RebindTable(const TableTemplate& newTable) const -{ - TableInstantiationParameters result(newTable); - result.SingularCells = this->SingularCells; - result.ArrayGroups = this->ArrayGroups; - return result; -} - -const TableTemplate& TableInstantiationParameters::GetTable() const -{ - return *mTable; -} - -bool TableTemplate::IsInstance(const Template* tmpl) -{ - return tmpl->GetKind() == KD_Table; -} - -TableTemplate::TableTemplate() - : Template(KD_Table) -{ -} - -int TableTemplate::GetTableWidth() const -{ - return mColumnWidths.size(); -} - -int TableTemplate::GetTableHeight() const -{ - return mRowHeights.size(); -} - -void TableTemplate::Resize(int newWidth, int newHeight) -{ - // TODO this doesn't gracefully handle resizing to a smaller size which trims some merged cells - - std::vector<TableCell> cells; - cells.reserve(newWidth * newHeight); - - int tableWidth = GetTableWidth(); - int tableHeight = GetTableHeight(); - - for (int y = 0; y < newHeight; ++y) { - if (y >= tableHeight) { - for (int x = 0; x < newWidth; ++x) { - cells.push_back(TableCell{}); - } - continue; - } - - for (int x = 0; x < newWidth; ++x) { - if (x >= tableWidth) { - cells.push_back(TableCell{}); - } else { - auto& cell = GetCell({ x, y }); - cells.push_back(std::move(cell)); - } - } - } - - mCells = std::move(cells); - mColumnWidths.resize(newWidth, 80); - mRowHeights.resize(newHeight, 20); -} - -int TableTemplate::GetRowHeight(int row) const -{ - return mRowHeights[row]; -} - -void TableTemplate::SetRowHeight(int row, int height) -{ - mRowHeights[row] = height; -} - -int TableTemplate::GetColumnWidth(int column) const -{ - return mColumnWidths[column]; -} - -void TableTemplate::SetColumnWidth(int column, int width) -{ - mColumnWidths[column] = width; -} - -const TableCell& TableTemplate::GetCell(Vec2i pos) const -{ - int tableWidth = GetTableWidth(); - return mCells[pos.y * tableWidth + pos.x]; -} - -TableCell& TableTemplate::GetCell(Vec2i pos) -{ - return const_cast<TableCell&>(const_cast<const TableTemplate*>(this)->GetCell(pos)); -} - -void TableTemplate::SetCellType(Vec2i pos, TableCell::CellType type) -{ - auto& cell = GetCell(pos); - if (cell.Type == type) { - return; - } - - switch (cell.Type) { - // Nothing to change - case TableCell::ConstantCell: break; - - case TableCell::SingularParametricCell: - mName2Parameters.erase(cell.Content); - break; - - case TableCell::ArrayParametricCell: { - auto& ag = mArrayGroups[cell.DataId]; - if (pos.x == ag.LeftCell) { - ag.LeftCell++; - } else if (pos.x == ag.RightCell) { - ag.RightCell--; - } else { - } - } break; - } - - switch (type) { - // Nothing to do - case TableCell::ConstantCell: break; - - case TableCell::SingularParametricCell: { - int idx = pos.y * GetTableWidth() + pos.x; - auto [DISCARD, inserted] = mName2Parameters.insert(cell.Content, idx); - - // Duplicate name - if (!inserted) { - return; - } - } break; - - case TableCell::ArrayParametricCell: { - auto ptr = AddArrayGroup(pos.y, pos.x, pos.x); - - // Duplicate name - if (ptr == nullptr) { - return; - } - } break; - } - - cell.Type = type; -} - -bool TableTemplate::UpdateParameterName(std::string_view oldName, std::string_view newName) -{ - return ::UpdateElementName(mName2Parameters, oldName, newName); -} - -int TableTemplate::GetArrayGroupCount() const -{ - return mArrayGroups.size(); -} - -const TableArrayGroup& TableTemplate::GetArrayGroup(int id) const -{ - return mArrayGroups[id]; -} - -TableArrayGroup& TableTemplate::GetArrayGroup(int id) -{ - return mArrayGroups[id]; -} - -TableArrayGroup* TableTemplate::AddArrayGroup(int row, int left, int right) -{ - // size_t max value: 18446744073709551615 - // ^~~~~~~~~~~~~~~~~~~~ 20 chars - char name[20]; - auto res = std::to_chars(std::begin(name), std::end(name), mArrayGroups.size()); - std::string_view nameStr(name, res.ptr - name); - - return AddArrayGroup(nameStr, row, left, right); -} - -TableArrayGroup* TableTemplate::AddArrayGroup(std::string_view name, int row, int left, int right) -{ - assert(row >= 0 && row < GetTableHeight()); - assert(left >= 0 && left < GetTableWidth()); - assert(right >= 0 && right < GetTableWidth()); - - // TODO check for overlap - - if (left > right) { - std::swap(left, right); - } - - auto [DISCARD, inserted] = mName2ArrayGroups.insert(name, (int)mArrayGroups.size()); - if (!inserted) { - return nullptr; - } - - mArrayGroups.push_back(TableArrayGroup{ - .Row = row, - .LeftCell = left, - .RightCell = right, - }); - auto& ag = mArrayGroups.back(); - - for (int x = left; x <= right; x++) { - auto& cell = GetCell({ x, row }); - - // Update type - cell.Type = TableCell::ArrayParametricCell; - - // Insert parameter name lookup - while (true) { - auto [DISCARD, inserted] = ag.mName2Cell.insert(cell.Content, x); - if (inserted) { - break; - } - - cell.Content += "-"; - } - } - - return &ag; -} - -bool TableTemplate::UpdateArrayGroupName(std::string_view oldName, std::string_view newName) -{ - return ::UpdateElementName(mName2ArrayGroups, oldName, newName); -} - -bool TableTemplate::ExtendArrayGroupLeft(int id, int n) -{ - assert(n > 0); - - auto& ag = mArrayGroups[id]; - ag.LeftCell -= n; - - return false; -} - -bool TableTemplate::ExtendArrayGroupRight(int id, int n) -{ - assert(n > 0); - - auto& ag = mArrayGroups[id]; - ag.RightCell += n; - - return false; -} - -TableCell* TableTemplate::FindCell(std::string_view name) -{ - auto iter = mName2Parameters.find(name); - if (iter != mName2Parameters.end()) { - return &mCells[iter.value()]; - } else { - return nullptr; - } -} - -TableArrayGroup* TableTemplate::FindArrayGroup(std::string_view name) -{ - auto iter = mName2ArrayGroups.find(name); - if (iter != mName2ArrayGroups.end()) { - return &mArrayGroups[iter.value()]; - } else { - return nullptr; - } -} - -TableTemplate::MergeCellsResult TableTemplate::MergeCells(Vec2i topLeft, Vec2i bottomRight) -{ - auto SortTwo = [](int& a, int& b) { - if (a > b) { - std::swap(a, b); - } - }; - SortTwo(topLeft.x, bottomRight.x); - SortTwo(topLeft.y, bottomRight.y); - - auto ResetProgress = [&]() { - for (int y = topLeft.y; y < bottomRight.y; ++y) { - for (int x = topLeft.x; x < bottomRight.x; ++x) { - auto& cell = GetCell({ x, y }); - cell.PrimaryCellLocation = { -1, -1 }; - } - } - }; - - for (int y = topLeft.y; y < bottomRight.y; ++y) { - for (int x = topLeft.x; x < bottomRight.x; ++x) { - auto& cell = GetCell({ x, y }); - if (cell.IsMergedCell()) { - ResetProgress(); - return MCR_CellAlreadyMerged; - } - - cell.PrimaryCellLocation = topLeft; - } - } - - auto& primaryCell = GetCell(topLeft); - primaryCell.SpanX = bottomRight.x - topLeft.x; - primaryCell.SpanY = bottomRight.y - topLeft.y; - - return MCR_Success; -} - -TableTemplate::BreakCellsResult TableTemplate::BreakCells(Vec2i topLeft) -{ - auto& primaryCell = GetCell(topLeft); - if (!primaryCell.IsMergedCell()) { - return BCR_CellNotMerged; - } - - for (int dy = 0; dy < primaryCell.SpanY; ++dy) { - for (int dx = 0; dx < primaryCell.SpanX; ++dx) { - auto& cell = GetCell({ topLeft.x + dx, topLeft.y + dy }); - cell.PrimaryCellLocation = { -1, -1 }; - } - } - - primaryCell.SpanX = 1; - primaryCell.SpanY = 1; - - return BCR_Success; -} - -lxw_workbook* TableTemplate::InstantiateToExcelWorkbook(const TableInstantiationParameters& params) const -{ - auto workbook = workbook_new("Table.xlsx"); - InstantiateToExcelWorksheet(workbook, params); - return workbook; -} - -lxw_worksheet* TableTemplate::InstantiateToExcelWorksheet(lxw_workbook* workbook, const TableInstantiationParameters& params) const -{ - auto worksheet = workbook_add_worksheet(workbook, "CpltExport.xlsx"); - - // Map: row number -> length of generated ranges - std::map<int, int> generatedRanges; - - for (size_t i = 0; i < mArrayGroups.size(); ++i) { - auto& info = mArrayGroups[i]; - auto& param = params.ArrayGroups[i]; - - auto iter = generatedRanges.find(i); - if (iter != generatedRanges.end()) { - int available = iter->second; - if (available >= param.size()) { - // Current space is enough to fit in this array group, skip - continue; - } - } - - // Not enough space to fit in this array group, update (or insert) the appropriate amount of generated rows - int row = i; - int count = param.size(); - generatedRanges.try_emplace(row, count); - } - - auto GetOffset = [&](int y) -> int { - // std::find_if <values less than y> - int verticalOffset = 0; - for (auto it = generatedRanges.begin(); it != generatedRanges.end() && it->first < y; ++it) { - verticalOffset += it->second; - } - return verticalOffset; - }; - - auto WriteCell = [&](int row, int col, const TableCell& cell, const char* text) -> void { - if (cell.IsPrimaryCell()) { - int lastRow = row + cell.SpanY - 1; - int lastCol = col + cell.SpanX - 1; - // When both `string` and `format` are null, the top-left cell contents are untouched (what we just wrote in the above switch) - worksheet_merge_range(worksheet, row, col, lastRow, lastCol, text, nullptr); - } else { - worksheet_write_string(worksheet, row, col, text, nullptr); - } - }; - - // Write/instantiate all array groups - for (size_t i = 0; i < mArrayGroups.size(); ++i) { - auto& groupInfo = mArrayGroups[i]; - auto& groupParams = params.ArrayGroups[i]; - - int rowCellCount = groupInfo.GetCount(); - int rowCount = groupParams.size(); - int baseRowIdx = groupInfo.Row + GetOffset(groupInfo.Row); - - // For each row that would be generated - for (int rowIdx = 0; rowIdx < rowCount; ++rowIdx) { - auto& row = groupParams[rowIdx]; - - // For each cell in the row - for (int rowCellIdx = 0; rowCellIdx < rowCellCount; ++rowCellIdx) { - // TODO support merged cells in array groups - worksheet_write_string(worksheet, baseRowIdx + rowIdx, rowCellIdx, row[rowCellIdx].c_str(), nullptr); - } - } - } - - int tableWidth = GetTableWidth(); - int tableHeight = GetTableHeight(); - - // Write all regular and singular parameter cells - for (int y = 0; y < tableHeight; ++y) { - for (int x = 0; x < tableWidth; ++x) { - auto& cell = GetCell({ x, y }); - - if (!cell.IsDataHoldingCell()) { - continue; - } - - switch (cell.Type) { - case TableCell::ConstantCell: { - int row = y + GetOffset(y); - int col = x; - - WriteCell(row, col, cell, cell.Content.c_str()); - } break; - - case TableCell::SingularParametricCell: { - int row = y + GetOffset(y); - int col = x; - - auto iter = params.SingularCells.find({ x, y }); - if (iter != params.SingularCells.end()) { - WriteCell(row, col, cell, iter.value().c_str()); - } - } break; - - // See loop above that processes whole array groups at the same time - case TableCell::ArrayParametricCell: break; - } - } - } - - return worksheet; -} - -class TableTemplate::Private -{ -public: - template <class TTableTemplate, class TProxy> - static void OperateStream(TTableTemplate& table, TProxy& proxy) - { - proxy.template ObjectAdapted<DataStreamAdapters::Vector<>>(table.mColumnWidths); - proxy.template ObjectAdapted<DataStreamAdapters::Vector<>>(table.mRowHeights); - proxy.template ObjectAdapted<DataStreamAdapters::Vector<>>(table.mCells); - proxy.template ObjectAdapted<DataStreamAdapters::Vector<>>(table.mArrayGroups); - proxy.template ObjectAdapted<DataStreamAdapters::TslArrayMap<>>(table.mName2Parameters); - proxy.template ObjectAdapted<DataStreamAdapters::TslArrayMap<>>(table.mName2ArrayGroups); - } -}; - -void TableTemplate::ReadFromDataStream(InputDataStream& stream) -{ - Private::OperateStream(*this, stream); -} - -void TableTemplate::WriteToDataStream(OutputDataStream& stream) const -{ - Private::OperateStream(*this, stream); -} |