aboutsummaryrefslogtreecommitdiff
path: root/core/src/Model/Template/TableTemplate.hpp
blob: 754ebe131fb09854ce16a306e9ae27db949163e9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
#pragma once

#include "Model/Template/Template.hpp"
#include "Utils/Vector.hpp"
#include "Utils/VectorHash.hpp"
#include "cplt_fwd.hpp"

#include <tsl/array_map.h>
#include <tsl/robin_map.h>
#include <string>
#include <string_view>
#include <vector>

class TableCell
{
public:
	enum TextAlignment
	{
		/// For horizontal alignment, this means align left. For vertical alignment, this means align top.
		AlignAxisMin,
		/// Align middle of the text to the middle of the axis.
		AlignCenter,
		/// For horizontal alignment, this means align right. For vertical alignment, this means align bottom.
		AlignAxisMax,
	};

	enum CellType
	{
		ConstantCell,
		SingularParametricCell,
		ArrayParametricCell,
	};

public:
	std::string Content;
	Vec2i Location;
	/// Location of the primary (top left) cell, if this cell is a part of a merged group.
	/// Otherwise, either component of this field shall be -1.
	Vec2i PrimaryCellLocation{ -1, -1 };
	int SpanX = 0;
	int SpanY = 0;
	TextAlignment HorizontalAlignment = AlignCenter;
	TextAlignment VerticalAlignment = AlignCenter;
	CellType Type = ConstantCell;
	/// The id of the group description object, if this cell isn't a constant or singluar parameter cell. Otherwise, this value is -1.
	int DataId = -1;

public:
	/// Return whether this cell holds meaningful data, i.e. true when this cell is either unmerged or the primary cell of a merged range.
	bool IsDataHoldingCell() const;
	/// Return whether this cell is the primary (i.e. top left) cell of a merged range or not.
	bool IsPrimaryCell() const;
	/// Return whether this cell is a part of a merged range or not. Includes the primary cell.
	bool IsMergedCell() const;
};

// TODO support reverse (bottom to top) filling order
// TODO support horizontal filling order
/// Parameter group information for a grouped array of cells. When instanciated, an array of 0 or more
/// elements shall be provided by the user, which will replace the group of templated cells with a list
/// of rows, each instantiated with the n-th element in the provided array.
/// \code
///	[["foo", "bar", "foobar"],
///  ["a", "b", c"],
///  ["1", "2", "3"],
///  ["x", "y", "z"]]
/// // ... may be more
/// \endcode
/// This would create 4 rows of data in the place of the original parameter group.
///
/// If more than one array parameter groups are on the same row, they would share space between each other:
/// \code
///  | 2 elements was fed to it
///  |                 | 1 element was fed to it
///  V                 V
/// {~~~~~~~~~~~~~~~~}{~~~~~~~~~~~~~~}
/// +------+---------+---------------+
/// | Foo  | Example | Another group |
/// +------+---------+---------------+
/// | Cool | Example |               |
/// +------+---------+---------------+
/// \endcode
///
/// \see TableCell
/// \see TableInstantiationParameters
/// \see TableTemplate
class TableCellArrayGroup
{
public:
	/// Parameter name mapped to cell location (index from LeftCell).
	tsl::array_map<char, int> mName2Cell;
	int Row;
	/// Leftmost cell in this group
	int LeftCell;
	/// Rightmost cell in this group
	int RightCell;

public:
	Vec2i GetLeftCell() const;
	Vec2i GetRightCell() const;
	int GetCount() const;

	/// Find the location of the cell within this array group that has the given name.
	Vec2i FindCell(std::string_view name);
};

// Forward declaration of libxlsxwriter structs
struct lxw_workbook;
struct lxw_worksheet;

/// An object containing the necessary information to instanciate a table template.
/// \see TableTemplate
class TableInstantiationParameters
{
private:
	const TableTemplate* mTable;

public:
	tsl::robin_map<Vec2i, std::string> SingularCells;

	using ArrayGroupRow = std::vector<std::string>;
	using ArrayGroupData = std::vector<ArrayGroupRow>;
	std::vector<ArrayGroupData> ArrayGroups;

public:
	TableInstantiationParameters(const TableTemplate& table);

	TableInstantiationParameters& ResetTable(const TableTemplate& newTable);
	TableInstantiationParameters RebindTable(const TableTemplate& newTable) const;

	const TableTemplate& GetTable() const;
};

/// A table template, where individual cells can be filled by workflows instantiating this template. Merged cells,
/// parametric rows/columns, and grids are also supported.
///
/// This current supports exporting to xlsx files.
class TableTemplate : public Template
{
private:
	/// Map from parameter name to index of the parameter cell (stored in mCells).
	tsl::array_map<char, int> mName2Parameters;
	/// Map from array group name to the index of the array group (stored in mArrayGroups).
	tsl::array_map<char, int> mName2ArrayGroups;
	std::vector<TableCell> mCells;
	std::vector<TableCellArrayGroup> mArrayGroups;
	std::vector<int> mRowHeights;
	std::vector<int> mColumnWidths;

public:
	static bool IsInstance(const Template* tmpl);
	TableTemplate();

	int GetTableWidth() const;
	int GetTableHeight() const;
	void Resize(int newWidth, int newHeight);

	int GetRowHeight(int row) const;
	void SetRowHeight(int row, int height);
	int GetColumnWidth(int column) const;
	void SetColumnWidth(int column, int width);

	const TableCell& GetCell(Vec2i pos) const;
	TableCell& GetCell(Vec2i pos);
	void SetCellType(Vec2i pos, TableCell::CellType type);

	int GetArrayGroupCount() const;
	const TableCellArrayGroup& GetArrayGroup(int id) const;
	TableCellArrayGroup& GetArrayGroup(int id);
	TableCellArrayGroup& AddArrayGroup(int row, int left, int right);
	bool ExtendArrayGroupLeft(int id, int n);
	bool ExtendArrayGroupRight(int id, int n);

	/// Find a singular parameter cell by its name. This does not include cells within an array group.
	TableCell* FindCell(std::string_view name);

	/// Find an array group by its name.
	TableCellArrayGroup* FindArrayGroup(std::string_view name);

	enum MergeCellsResult
	{
		MCR_CellAlreadyMerged,
		MCR_Success,
	};
	MergeCellsResult MergeCells(Vec2i topLeft, Vec2i bottomRight);

	enum BreakCellsResult
	{
		BCR_CellNotMerged,
		BCR_Success,
	};
	BreakCellsResult BreakCells(Vec2i topLeft);

	lxw_workbook* InstantiateToExcelWorkbook(const TableInstantiationParameters& params) const;
	lxw_worksheet* InstantiateToExcelWorksheet(lxw_workbook* workbook, const TableInstantiationParameters& params) const;

	virtual ReadResult ReadFrom(std::istream& stream) override;
	virtual void WriteTo(std::ostream& stream) const override;
};