ListTableSource.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. using System.Collections;
  2. using System.Data;
  3. namespace Terminal.Gui;
  4. /// <summary>
  5. /// <see cref="ITableSource"/> implementation that wraps a <see cref="System.Collections.IList"/>. This class is
  6. /// mutable: changes are permitted to the wrapped <see cref="IList"/>.
  7. /// </summary>
  8. public class ListTableSource : ITableSource
  9. {
  10. /// <summary>The list this source wraps.</summary>
  11. public IList List;
  12. /// <summary>The style this source uses.</summary>
  13. public ListColumnStyle Style;
  14. private readonly TableView _tableView;
  15. private Rectangle _lastBounds;
  16. private IList _lastList;
  17. private int _lastMaxCellWidth;
  18. private int _lastMinCellWidth;
  19. private ListColumnStyle _lastStyle;
  20. /// <summary>
  21. /// Creates a new columned list table instance based on the data in <paramref name="list"/> and dimensions from
  22. /// <paramref name="tableView"/>.
  23. /// </summary>
  24. /// <param name="list"></param>
  25. /// <param name="tableView"></param>
  26. /// <param name="style"></param>
  27. public ListTableSource (IList list, TableView tableView, ListColumnStyle style)
  28. {
  29. List = list;
  30. _tableView = tableView;
  31. Style = style;
  32. DataTable = CreateTable (CalculateColumns ());
  33. // TODO: Determine the best event for this
  34. tableView.DrawingContent += TableView_DrawContent;
  35. }
  36. /// <inheritdoc/>
  37. public ListTableSource (IList list, TableView tableView) : this (list, tableView, new ListColumnStyle ()) { }
  38. /// <summary>The number of items in the IList source</summary>
  39. public int Count => List.Count;
  40. /// <summary>The data table this source wraps.</summary>
  41. public DataTable DataTable { get; private set; }
  42. /// <inheritdoc/>
  43. public object this [int row, int col]
  44. {
  45. get
  46. {
  47. int idx;
  48. if (Style.Orientation == Orientation.Vertical)
  49. {
  50. idx = col * Rows + row;
  51. }
  52. else
  53. {
  54. idx = row * Columns + col;
  55. }
  56. if (idx < 0 || idx >= Count)
  57. {
  58. return null;
  59. }
  60. return List [idx];
  61. }
  62. }
  63. /// <inheritdoc/>
  64. public int Rows => DataTable.Rows.Count;
  65. /// <inheritdoc/>
  66. public int Columns => DataTable.Columns.Count;
  67. /// <inheritdoc/>
  68. public string [] ColumnNames => Enumerable.Range (0, Columns).Select (n => n.ToString ()).ToArray ();
  69. private int CalculateColumns ()
  70. {
  71. int cols;
  72. int colWidth = CalculateMaxLength ();
  73. if (colWidth > _tableView.MaxCellWidth)
  74. {
  75. colWidth = _tableView.MaxCellWidth;
  76. }
  77. if (_tableView.MinCellWidth > 0 && colWidth < _tableView.MinCellWidth)
  78. {
  79. if (_tableView.MinCellWidth > _tableView.MaxCellWidth)
  80. {
  81. colWidth = _tableView.MaxCellWidth;
  82. }
  83. else
  84. {
  85. colWidth = _tableView.MinCellWidth;
  86. }
  87. }
  88. if (Style.Orientation == Orientation.Vertical != Style.ScrollParallel)
  89. {
  90. float f = (float)_tableView.Viewport.Height - _tableView.GetHeaderHeight ();
  91. cols = (int)Math.Ceiling (Count / f);
  92. }
  93. else
  94. {
  95. cols = (int)Math.Ceiling (((float)_tableView.Viewport.Width - 1) / colWidth) - 2;
  96. }
  97. return cols > 1 ? cols : 1;
  98. }
  99. /// <summary>Returns the size in characters of the longest value read from <see cref="ListTableSource.List"/></summary>
  100. /// <returns></returns>
  101. private int CalculateMaxLength ()
  102. {
  103. if (List is null || Count == 0)
  104. {
  105. return 0;
  106. }
  107. var maxLength = 0;
  108. foreach (object t in List)
  109. {
  110. int l;
  111. if (t is string s)
  112. {
  113. l = s.GetColumns ();
  114. }
  115. else
  116. {
  117. l = t.ToString ().Length;
  118. }
  119. if (l > maxLength)
  120. {
  121. maxLength = l;
  122. }
  123. }
  124. return maxLength;
  125. }
  126. /// <summary>Creates a DataTable from an IList to display in a <see cref="TableView"/></summary>
  127. private DataTable CreateTable (int cols = 1)
  128. {
  129. var table = new DataTable ();
  130. for (var col = 0; col < cols; col++)
  131. {
  132. table.Columns.Add (new DataColumn (col.ToString ()));
  133. }
  134. for (var row = 0; row < Count / table.Columns.Count; row++)
  135. {
  136. table.Rows.Add ();
  137. }
  138. // return partial row
  139. if (Count % table.Columns.Count != 0)
  140. {
  141. table.Rows.Add ();
  142. }
  143. return table;
  144. }
  145. private void TableView_DrawContent (object sender, DrawEventArgs e)
  146. {
  147. if (!_tableView.Viewport.Equals (_lastBounds)
  148. || _tableView.MaxCellWidth != _lastMaxCellWidth
  149. || _tableView.MinCellWidth != _lastMinCellWidth
  150. || Style != _lastStyle
  151. || List != _lastList)
  152. {
  153. DataTable = CreateTable (CalculateColumns ());
  154. }
  155. _lastBounds = _tableView.Viewport;
  156. _lastMinCellWidth = _tableView.MaxCellWidth;
  157. _lastMaxCellWidth = _tableView.MaxCellWidth;
  158. _lastStyle = Style;
  159. _lastList = List;
  160. }
  161. }