btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / kits / shared / TextTable.cpp
blob2601205b3e381e2b5a89475416a03f429df3aaea
1 /*
2 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <TextTable.h>
9 #include <stdio.h>
11 #include <algorithm>
14 namespace BPrivate {
17 // #pragma mark - Column
20 struct TextTable::Column {
21 Column(const BString& title, enum alignment align, bool canTruncate)
23 fTitle(title),
24 fAlignment(align),
25 fCanBeTruncated(canTruncate),
26 fNeededWidth(0),
27 fWidth(0)
29 UpdateNeededWidth(fTitle);
30 fMinWidth = fNeededWidth;
33 const BString& Title() const
35 return fTitle;
38 enum alignment Alignment() const
40 return fAlignment;
43 bool CanBeTruncated() const
45 return fCanBeTruncated;
48 int32 NeededWidth() const
50 return fNeededWidth;
53 int32 MinWidth() const
55 return fMinWidth;
58 int32 Width() const
60 return fWidth;
63 void SetWidth(int32 width)
65 fWidth = width;
68 void UpdateNeededWidth(const BString& text)
70 // TODO: Full-width character support.
71 int32 textWidth = text.CountChars();
72 if (textWidth > fNeededWidth)
73 fNeededWidth = textWidth;
76 BString Format(const BString& text)
78 // TODO: Full-width character support.
79 int32 textWidth = text.CountChars();
80 if (textWidth == fWidth)
81 return text;
83 // truncate, if too long
84 if (textWidth > fWidth) {
85 BString result(text);
86 result.TruncateChars(fWidth);
87 return result;
90 // align, if too short
91 int32 missing = fWidth - textWidth;
92 switch (fAlignment) {
93 case B_ALIGN_LEFT:
94 default:
96 BString result(text);
97 result.Append(' ', missing);
98 return result;
101 case B_ALIGN_RIGHT:
103 BString result;
104 result.Append(' ', missing);
105 result.Append(text);
106 return result;
109 case B_ALIGN_CENTER:
111 BString result;
112 result.Append(' ', missing / 2);
113 result.Append(text);
114 result.Append(' ', missing - missing / 2);
115 return result;
120 private:
121 BString fTitle;
122 enum alignment fAlignment;
123 bool fCanBeTruncated;
124 int32 fNeededWidth;
125 int32 fMinWidth;
126 int32 fWidth;
130 // #pragma mark - TextTable
133 TextTable::TextTable()
135 fColumns(10, true),
136 fRows(100, true)
141 TextTable::~TextTable()
146 int32
147 TextTable::CountColumns() const
149 return fColumns.CountItems();
153 void
154 TextTable::AddColumn(const BString& title, enum alignment align,
155 bool canTruncate)
157 Column* column = new Column(title, align, canTruncate);
158 if (!fColumns.AddItem(column)) {
159 delete column;
160 throw std::bad_alloc();
165 int32
166 TextTable::CountRows() const
168 return fRows.CountItems();
172 BString
173 TextTable::TextAt(int32 rowIndex, int32 columnIndex) const
175 BStringList* row = fRows.ItemAt(rowIndex);
176 if (row == NULL)
177 return BString();
178 return row->StringAt(columnIndex);
182 void
183 TextTable::SetTextAt(int32 rowIndex, int32 columnIndex, const BString& text)
185 // If necessary append empty rows up to the specified row index.
186 while (rowIndex >= fRows.CountItems()) {
187 BStringList* row = new BStringList();
188 if (!fRows.AddItem(row)) {
189 delete row;
190 throw std::bad_alloc();
194 // If necessary append empty strings up to the specified column index.
195 BStringList* row = fRows.ItemAt(rowIndex);
196 while (columnIndex >= row->CountStrings()) {
197 if (!row->Add(BString()))
198 throw std::bad_alloc();
201 // set the text
202 if (!row->Replace(columnIndex, text))
203 throw std::bad_alloc();
207 void
208 TextTable::Print(int32 maxWidth)
210 int32 columnCount = fColumns.CountItems();
211 if (columnCount == 0)
212 return;
214 // determine the column widths
215 int32 rowCount = fRows.CountItems();
216 for (int32 rowIndex = 0; rowIndex < rowCount; rowIndex++) {
217 BStringList* row = fRows.ItemAt(rowIndex);
218 int32 rowColumnCount = std::min(row->CountStrings(), columnCount);
219 for (int32 columnIndex = 0; columnIndex < rowColumnCount;
220 columnIndex++) {
221 fColumns.ItemAt(columnIndex)->UpdateNeededWidth(
222 row->StringAt(columnIndex));
226 int32 neededWidth = (columnCount - 1) * 2;
227 // spacing
228 for (int32 i = 0; i < columnCount; i++)
229 neededWidth += fColumns.ItemAt(i)->NeededWidth();
231 int32 width = neededWidth;
232 int32 missingWidth = neededWidth - std::min(maxWidth, neededWidth);
234 for (int32 i = 0; i < columnCount; i++) {
235 Column* column = fColumns.ItemAt(i);
236 if (missingWidth > 0 && column->CanBeTruncated()) {
237 int32 truncateBy = std::min(missingWidth,
238 column->NeededWidth() - column->MinWidth());
239 column->SetWidth(column->NeededWidth() - truncateBy);
240 missingWidth -= truncateBy;
241 width -= truncateBy;
242 } else
243 column->SetWidth(column->NeededWidth());
246 // print the header
247 BString line;
248 for (int32 i = 0; i < columnCount; i++) {
249 if (i > 0)
250 line << " ";
252 Column* column = fColumns.ItemAt(i);
253 line << column->Format(column->Title());
255 line << '\n';
256 fputs(line.String(), stdout);
258 line.SetTo('-', width);
259 line << '\n';
260 fputs(line.String(), stdout);
262 // print the rows
263 for (int32 rowIndex = 0; rowIndex < rowCount; rowIndex++) {
264 line.Truncate(0);
265 BStringList* row = fRows.ItemAt(rowIndex);
266 for (int32 columnIndex = 0; columnIndex < columnCount; columnIndex++) {
267 if (columnIndex > 0)
268 line << " ";
270 line << fColumns.ItemAt(columnIndex)->Format(
271 row->StringAt(columnIndex));
274 line << '\n';
275 fputs(line.String(), stdout);
280 } // namespace BPrivate