Skip to content

Commit c0b3649

Browse files
committed
added export feature for PlainText and Excel-style
1 parent e6f5d49 commit c0b3649

4 files changed

Lines changed: 274 additions & 8 deletions

File tree

CompuMaster.Data/TextCell.vb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,25 @@ Namespace CompuMaster.Data
6666
End If
6767
End Function
6868

69+
''' <summary>
70+
''' Creates a copy of the current cell
71+
''' </summary>
72+
''' <returns></returns>
73+
Public Function Clone() As TextCell
74+
Dim NewCell As New TextCell(Me.Text)
75+
Return NewCell
76+
End Function
77+
78+
Public Overrides Function ToString() As String
79+
If Me.Text Is Nothing Then
80+
Return "{NULL}"
81+
ElseIf Me.Text = Nothing Then
82+
Return "{String.Empty}"
83+
Else
84+
Return Me.Text
85+
End If
86+
End Function
87+
6988
End Class
7089

7190
End Namespace

CompuMaster.Data/TextRow.vb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,22 @@ Namespace CompuMaster.Data
197197
Next
198198
End Sub
199199

200+
''' <summary>
201+
''' Creates a deep clone of this row (including all cells)
202+
''' </summary>
203+
''' <returns></returns>
204+
Public Function Clone() As TextRow
205+
Dim NewRow As New TextRow()
206+
For Each Cell As TextCell In Me.Cells
207+
NewRow.Cells.Add(Cell.Clone())
208+
Next
209+
Return NewRow
210+
End Function
211+
212+
Public Overrides Function ToString() As String
213+
Return MyBase.ToString() & ": cell count=" & Me.Count
214+
End Function
215+
200216
End Class
201217

202218
End Namespace

CompuMaster.Data/TextTable.vb

Lines changed: 169 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ Namespace CompuMaster.Data
3939
Me.AssignRowData(rows, columnFormatting)
4040
End Sub
4141

42+
Public Sub New(headers As System.Collections.Generic.List(Of TextRow), rows As System.Collections.Generic.List(Of TextRow))
43+
If headers Is Nothing Then Throw New ArgumentNullException(NameOf(headers))
44+
If rows Is Nothing Then Throw New ArgumentNullException(NameOf(rows))
45+
Me.Headers = headers
46+
Me.Rows = rows
47+
End Sub
48+
4249
'Public Sub New(table As DataTable, columnFormatting As DataTables.DataColumnToString)
4350
' Me.New(table, CType(Nothing, String), columnFormatting)
4451
'End Sub
@@ -156,17 +163,171 @@ Namespace CompuMaster.Data
156163
' Rows.Add(New TextRow(Cells))
157164
'End Sub
158165

159-
160-
Public Sub New(headers As System.Collections.Generic.List(Of TextRow), rows As System.Collections.Generic.List(Of TextRow))
161-
If headers Is Nothing Then Throw New ArgumentNullException(NameOf(headers))
162-
If rows Is Nothing Then Throw New ArgumentNullException(NameOf(rows))
163-
Me.Headers = headers
164-
Me.Rows = rows
165-
End Sub
166-
166+
''' <summary>
167+
''' Captions of the table (can be multiple rows)
168+
''' </summary>
169+
''' <returns></returns>
167170
Public Property Headers As System.Collections.Generic.List(Of TextRow)
171+
172+
''' <summary>
173+
''' Rows of the table
174+
''' </summary>
175+
''' <returns></returns>
168176
Public Property Rows As System.Collections.Generic.List(Of TextRow)
169177

178+
''' <summary>
179+
''' Maximum number of columns in the table (including headers and rows)
180+
''' </summary>
181+
''' <returns></returns>
182+
Public Function ColumnCount() As Integer
183+
Dim MaxColumns As Integer = 0
184+
For MyCounter As Integer = 0 To Me.Headers.Count - 1
185+
MaxColumns = System.Math.Max(MaxColumns, Me.Headers(MyCounter).Cells.Count)
186+
Next
187+
For MyCounter As Integer = 0 To Me.Rows.Count - 1
188+
MaxColumns = System.Math.Max(MaxColumns, Me.Rows(MyCounter).Cells.Count)
189+
Next
190+
Return MaxColumns
191+
End Function
192+
193+
''' <summary>
194+
''' Convert TextTable to classic DataTable
195+
''' </summary>
196+
''' <returns></returns>
197+
Public Function ToDataTable() As DataTable
198+
'Collect column names from all header rows (if multiple header rows exist, combine their texts with line breaks)
199+
Dim ColumnNames As New System.Collections.Generic.List(Of String)
200+
For RowCounter As Integer = 0 To Me.Headers.Count - 1
201+
For ColCounter As Integer = 0 To Me.Headers(RowCounter).Cells.Count - 1
202+
If ColumnNames.Count <= ColCounter Then
203+
'Add new column
204+
ColumnNames.Add(Me.Headers(RowCounter).Cells(ColCounter).Text)
205+
Else
206+
'Column already exists -> extend column name if required
207+
Dim ExistingColumnName As String = ColumnNames(ColCounter)
208+
If ExistingColumnName <> Nothing Then
209+
ColumnNames(ColCounter) = ExistingColumnName & System.Environment.NewLine & Me.Headers(RowCounter).Cells(ColCounter).Text
210+
Else
211+
ColumnNames(ColCounter) = Me.Headers(RowCounter).Cells(ColCounter).Text
212+
End If
213+
End If
214+
Next
215+
Next
216+
217+
'Create DataTable with all columns
218+
Dim Result As New DataTable
219+
For ColCounter As Integer = 0 To ColumnNames.Count - 1
220+
Dim UniqueColumnName As String = DataTables.LookupUniqueColumnName(Result, ColumnNames(ColCounter))
221+
Result.Columns.Add(UniqueColumnName, GetType(String))
222+
Next
223+
224+
'Add all rows
225+
For RowCounter As Integer = 0 To Me.Rows.Count - 1
226+
Dim NewRow As DataRow = Result.NewRow
227+
For ColCounter As Integer = 0 To Me.Rows(RowCounter).Count - 1
228+
If Me.Rows(RowCounter).Cells(ColCounter).Text <> Nothing Then
229+
NewRow(ColCounter) = Me.Rows(RowCounter).Cells(ColCounter).Text
230+
End If
231+
Next
232+
Result.Rows.Add(NewRow)
233+
Next
234+
Return Result
235+
End Function
236+
237+
Private Shared Function OutputOptions(rowNumbering As Boolean) As CompuMaster.Data.ConvertToPlainTextTableOptions
238+
Dim Result = CompuMaster.Data.ConvertToPlainTextTableOptions.SimpleLayout
239+
Result.MinimumColumnWidth = 2
240+
Result.MaximumColumnWidth = 65535
241+
Result.RowNumbering = rowNumbering
242+
Return Result
243+
End Function
244+
245+
Public Function ToPlainTextTable() As String
246+
Return CompuMaster.Data.DataTables.ConvertToPlainTextTableFixedColumnWidths(Me.ToDataTable, OutputOptions(False))
247+
End Function
248+
249+
Public Function ToPlainTextTable(rowNumbering As Boolean) As String
250+
Return CompuMaster.Data.DataTables.ConvertToPlainTextTableFixedColumnWidths(Me.ToDataTable, OutputOptions(rowNumbering))
251+
End Function
252+
253+
''' <summary>
254+
''' Convert to plain text table with Excel-like column names (A, B, ..., Z, AA, AB, ..., AZ, BA, BB, ...) and row numbers (1-based)
255+
''' </summary>
256+
''' <returns></returns>
257+
Public Function ToPlainTextExcelTable() As String
258+
Return CompuMaster.Data.DataTables.ConvertToPlainTextTableFixedColumnWidths(Me.ToExcelStyleTextTable.ToDataTable, OutputOptions(False))
259+
End Function
260+
261+
''' <summary>
262+
''' Convert to TextTable with Excel-like column names (A, B, ..., Z, AA, AB, ..., AZ, BA, BB, ...) and row numbers (1-based)
263+
''' </summary>
264+
''' <returns></returns>
265+
Public Function ToExcelStyleTextTable() As TextTable
266+
'Prepare new header row with column letters
267+
Dim NewHeaderRows As New System.Collections.Generic.List(Of TextRow)
268+
With Nothing
269+
'Setup column names in letters
270+
Dim NewHeaderCells As New TextRow
271+
Dim MaxColumns As Integer = Me.ColumnCount()
272+
For MyCounter As Integer = 0 To MaxColumns - 1
273+
NewHeaderCells.Cells.Add(New TextCell(ExcelColumnName(MyCounter)))
274+
Next
275+
NewHeaderRows.Add(NewHeaderCells)
276+
End With
277+
278+
'Prepare new table data
279+
Dim NewDataRows As New System.Collections.Generic.List(Of TextRow)
280+
For RowCounter As Integer = 0 To Me.Headers.Count - 1 'Add all existing header rows as regular data rows
281+
NewDataRows.Add(Me.Headers(RowCounter).Clone)
282+
Next
283+
For RowCounter As Integer = 0 To Me.Rows.Count - 1 'Add all existing data rows
284+
NewDataRows.Add(Me.Rows(RowCounter).Clone)
285+
Next
286+
287+
'Create new table
288+
Dim Result As TextTable = New TextTable()
289+
Result.Headers = NewHeaderRows
290+
Result.Rows = NewDataRows
291+
292+
'Setup row numbers 1-based
293+
Result.ApplyRowNumbering()
294+
295+
Return Result
296+
End Function
297+
298+
''' <summary>
299+
''' Calculate Excel-like column name (A, B, ..., Z, AA, AB, ..., AZ, BA, BB, ...) for given 0-based column index
300+
''' </summary>
301+
''' <param name="columnIndex"></param>
302+
''' <returns></returns>
303+
Friend Shared ReadOnly Property ExcelColumnName(columnIndex As Integer) As String
304+
Get
305+
If columnIndex < 0 Then Throw New ArgumentOutOfRangeException(NameOf(columnIndex), "Must be a positive value")
306+
Dim x As Integer = columnIndex + 1
307+
If x >= 1 AndAlso x <= 26 Then
308+
Return Char.ConvertFromUtf32(x + 64)
309+
Else
310+
Return ExcelColumnName(CType(((x - x Mod 26) / 26) - 1, Integer)) & Char.ConvertFromUtf32((x Mod 26) + 64)
311+
End If
312+
End Get
313+
End Property
314+
315+
''' <summary>
316+
''' Creates a copy of the current table
317+
''' </summary>
318+
''' <returns></returns>
319+
Public Function Clone() As TextTable
320+
Dim NewHeaders As New System.Collections.Generic.List(Of TextRow)
321+
For MyCounter As Integer = 0 To Me.Headers.Count - 1
322+
NewHeaders.Add(Me.Headers(MyCounter).Clone)
323+
Next
324+
Dim NewRows As New System.Collections.Generic.List(Of TextRow)
325+
For MyCounter As Integer = 0 To Me.Rows.Count - 1
326+
NewRows.Add(Me.Rows(MyCounter).Clone)
327+
Next
328+
Return New TextTable(NewHeaders, NewRows)
329+
End Function
330+
170331
''' <summary>
171332
''' Text representation of table
172333
''' </summary>

CompuMaster.Test.Tools.Data/TextTableTest.vb

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,76 @@ Namespace CompuMaster.Test.Data
268268
Assert.AreEqual(Expected, Output)
269269
End Sub
270270

271+
<Test>
272+
Public Sub ToExcelStyleTextTable()
273+
Dim TestTable As DataTable
274+
Dim TextTable As CompuMaster.Data.TextTable
275+
Dim Expected, Output As String
276+
277+
TestTable = TestTable1()
278+
TestTable.Columns(1).ColumnName &= ControlChars.CrLf & "Line2"
279+
TextTable = (New CompuMaster.Data.TextTable(TestTable)).ToExcelStyleTextTable
280+
281+
Dim ExpectedRowLineBreak As String
282+
Dim ExpectedCellLineBreak As String
283+
284+
Output = TextTable.ToPlainTextTable()
285+
Console.WriteLine(Output)
286+
287+
Assert.AreEqual("#", TextTable.Headers(0).Cells(0).Text)
288+
289+
ExpectedRowLineBreak = System.Environment.NewLine
290+
ExpectedCellLineBreak = System.Environment.NewLine
291+
Expected =
292+
"# |A |B |C " & ExpectedCellLineBreak &
293+
"--+--+---------------+-----------" & ExpectedRowLineBreak &
294+
"1 |ID|Value1 |Val2 " & ExpectedRowLineBreak &
295+
" | |Line2 | " & ExpectedCellLineBreak &
296+
"2 |1 |Hello world! |Line1 " & ExpectedRowLineBreak &
297+
" | | |Line2 " & ExpectedRowLineBreak &
298+
"3 |2 |Gotcha! | " & ExpectedRowLineBreak &
299+
"4 |3 |Hello world! | " & ExpectedRowLineBreak &
300+
"5 |4 |Not a duplicate| " & ExpectedRowLineBreak &
301+
"6 |5 |Hello world! |T " & ExpectedRowLineBreak &
302+
"7 |6 |GOTCHA! | " & ExpectedRowLineBreak &
303+
"8 |7 |Gotcha! | " & ExpectedRowLineBreak
304+
Assert.AreEqual(Expected, Output)
305+
End Sub
306+
307+
<Test>
308+
Public Sub ToPlainTextExcelTable()
309+
Dim TestTable As DataTable
310+
Dim TextTable As CompuMaster.Data.TextTable
311+
Dim Expected, Output As String
312+
313+
TestTable = TestTable1()
314+
TestTable.Columns(1).ColumnName &= ControlChars.CrLf & "Line2"
315+
TextTable = New CompuMaster.Data.TextTable(TestTable)
316+
317+
Dim ExpectedRowLineBreak As String
318+
Dim ExpectedCellLineBreak As String
319+
320+
Output = TextTable.ToPlainTextExcelTable()
321+
Console.WriteLine(Output)
322+
323+
ExpectedRowLineBreak = System.Environment.NewLine
324+
ExpectedCellLineBreak = System.Environment.NewLine
325+
Expected =
326+
"# |A |B |C " & ExpectedCellLineBreak &
327+
"--+--+---------------+-----------" & ExpectedRowLineBreak &
328+
"1 |ID|Value1 |Val2 " & ExpectedRowLineBreak &
329+
" | |Line2 | " & ExpectedCellLineBreak &
330+
"2 |1 |Hello world! |Line1 " & ExpectedRowLineBreak &
331+
" | | |Line2 " & ExpectedRowLineBreak &
332+
"3 |2 |Gotcha! | " & ExpectedRowLineBreak &
333+
"4 |3 |Hello world! | " & ExpectedRowLineBreak &
334+
"5 |4 |Not a duplicate| " & ExpectedRowLineBreak &
335+
"6 |5 |Hello world! |T " & ExpectedRowLineBreak &
336+
"7 |6 |GOTCHA! | " & ExpectedRowLineBreak &
337+
"8 |7 |Gotcha! | " & ExpectedRowLineBreak
338+
Assert.AreEqual(Expected, Output)
339+
End Sub
340+
271341
#Region "Test data"
272342
Private Function TestTable1() As DataTable
273343
Dim Result As New DataTable("test1")

0 commit comments

Comments
 (0)