2 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
17 // #pragma mark - Column
20 struct TextTable::Column
{
21 Column(const BString
& title
, enum alignment align
, bool canTruncate
)
25 fCanBeTruncated(canTruncate
),
29 UpdateNeededWidth(fTitle
);
30 fMinWidth
= fNeededWidth
;
33 const BString
& Title() const
38 enum alignment
Alignment() const
43 bool CanBeTruncated() const
45 return fCanBeTruncated
;
48 int32
NeededWidth() const
53 int32
MinWidth() const
63 void SetWidth(int32 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
)
83 // truncate, if too long
84 if (textWidth
> fWidth
) {
86 result
.TruncateChars(fWidth
);
90 // align, if too short
91 int32 missing
= fWidth
- textWidth
;
97 result
.Append(' ', missing
);
104 result
.Append(' ', missing
);
112 result
.Append(' ', missing
/ 2);
114 result
.Append(' ', missing
- missing
/ 2);
122 enum alignment fAlignment
;
123 bool fCanBeTruncated
;
130 // #pragma mark - TextTable
133 TextTable::TextTable()
141 TextTable::~TextTable()
147 TextTable::CountColumns() const
149 return fColumns
.CountItems();
154 TextTable::AddColumn(const BString
& title
, enum alignment align
,
157 Column
* column
= new Column(title
, align
, canTruncate
);
158 if (!fColumns
.AddItem(column
)) {
160 throw std::bad_alloc();
166 TextTable::CountRows() const
168 return fRows
.CountItems();
173 TextTable::TextAt(int32 rowIndex
, int32 columnIndex
) const
175 BStringList
* row
= fRows
.ItemAt(rowIndex
);
178 return row
->StringAt(columnIndex
);
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
)) {
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();
202 if (!row
->Replace(columnIndex
, text
))
203 throw std::bad_alloc();
208 TextTable::Print(int32 maxWidth
)
210 int32 columnCount
= fColumns
.CountItems();
211 if (columnCount
== 0)
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
;
221 fColumns
.ItemAt(columnIndex
)->UpdateNeededWidth(
222 row
->StringAt(columnIndex
));
226 int32 neededWidth
= (columnCount
- 1) * 2;
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
;
243 column
->SetWidth(column
->NeededWidth());
248 for (int32 i
= 0; i
< columnCount
; i
++) {
252 Column
* column
= fColumns
.ItemAt(i
);
253 line
<< column
->Format(column
->Title());
256 fputs(line
.String(), stdout
);
258 line
.SetTo('-', width
);
260 fputs(line
.String(), stdout
);
263 for (int32 rowIndex
= 0; rowIndex
< rowCount
; rowIndex
++) {
265 BStringList
* row
= fRows
.ItemAt(rowIndex
);
266 for (int32 columnIndex
= 0; columnIndex
< columnCount
; columnIndex
++) {
270 line
<< fColumns
.ItemAt(columnIndex
)->Format(
271 row
->StringAt(columnIndex
));
275 fputs(line
.String(), stdout
);
280 } // namespace BPrivate