<commit_before>-- @docclass
--[[
  TODO:
    * Make table headers more robust.
    * Get dynamic row heights working with text wrapping.
]]

TABLE_SORTING_ASC = 0
TABLE_SORTING_DESC = 1

UITable = extends(UIWidget, "UITable")

-- Initialize default values
function UITable.create()
  local table = UITable.internalCreate()
  table.headerRow = nil
  table.headerColumns = {}
  table.dataSpace = nil
  table.rows = {}
  table.rowBaseStyle = nil
  table.columns = {}
  table.columnWidth = {}
  table.columBaseStyle = nil
  table.headerRowBaseStyle = nil
  table.headerColumnBaseStyle = nil
  table.selectedRow = nil
  table.defaultColumnWidth = 80
  table.sortColumn = -1
  table.sortType = TABLE_SORTING_ASC
  table.autoSort = false

  return table
end

-- Clear table values
function UITable:onDestroy()
  for _,row in pairs(self.rows) do
    row.onClick = nil
  end
  self.rows = {}
  self.columns = {}
  self.headerRow = nil
  self.headerColumns = {}
  self.columnWidth = {}
  self.selectedRow = nil

  if self.dataSpace then
    self.dataSpace:destroyChildren()
    self.dataSpace = nil
  end
end

-- Detect if a header is already defined
function UITable:onSetup()
  local header = self:getChildById('header')
  if header then
    self:setHeader(header)
  end
end

-- Parse table related styles
function UITable:onStyleApply(styleName, styleNode)
  for name, value in pairs(styleNode) do
    if value ~= false then
      if name == 'table-data' then
        addEvent(function()
          self:setTableData(self:getParent():getChildById(value))
        end)
      elseif name == 'column-style' then
        addEvent(function()
          self:setColumnStyle(value)
        end)
      elseif name == 'row-style' then
        addEvent(function()
          self:setRowStyle(value)
        end)
      elseif name == 'header-column-style' then
        addEvent(function()
          self:setHeaderColumnStyle(value)
        end)
      elseif name == 'header-row-style' then
        addEvent(function()
          self:setHeaderRowStyle(value)
        end)
      end
    end
  end
end

function UITable:setColumnWidth(width)
  if self:hasHeader() then return end
  self.columnWidth = width
end

function UITable:setDefaultColumnWidth(width)
  self.defaultColumnWidth = width
end

-- Check if the table has a header
function UITable:hasHeader()
  return self.headerRow ~= nil
end

-- Clear all rows
function UITable:clearData()
  if not self.dataSpace then
    return
  end
  self.dataSpace:destroyChildren()
  self.selectedRow = nil
  self.columns = {}
  self.rows = {}
end

-- Set existing child as header
function UITable:setHeader(headerWidget)
  self:removeHeader()

  if self.dataSpace then
    local newHeight = self.dataSpace:getHeight()-headerRow:getHeight()-self.dataSpace:getMarginTop()
    self.dataSpace:applyStyle({ height = newHeight })
  end

  self.headerColumns = {}
  self.columnWidth = {}
  for colId, column in pairs(headerWidget:getChildren()) do
    column.colId = colId
    column.table = self
    table.insert(self.columnWidth, column:getWidth())
    table.insert(self.headerColumns, column)
  end

  self.headerRow = headerWidget
end

-- Create and add header from table data
function UITable:addHeader(data)
  if not data or type(data) ~= 'table' then
    g_logger.error('UITable:addHeaderRow - table columns must be provided in a table')
    return
  end

  self:removeHeader()

  -- build header columns
  local columns = {}
  for colId, column in pairs(data) do
    local col = g_ui.createWidget(self.headerColumnBaseStyle)
    col.colId = colId
    col.table = self
    for type, value in pairs(column) do
      if type == 'width' then
        col:setWidth(value)
      elseif type == 'height' then
        col:setHeight(value)
      elseif type == 'text' then
        col:setText(tr(value))
      elseif type == 'onClick' then<commit_msg>Removed tr() from UIHeader<commit_after>-- @docclass
--[[
  TODO:
    * Make table headers more robust.
    * Get dynamic row heights working with text wrapping.
]]

TABLE_SORTING_ASC = 0
TABLE_SORTING_DESC = 1

UITable = extends(UIWidget, "UITable")

-- Initialize default values
function UITable.create()
  local table = UITable.internalCreate()
  table.headerRow = nil
  table.headerColumns = {}
  table.dataSpace = nil
  table.rows = {}
  table.rowBaseStyle = nil
  table.columns = {}
  table.columnWidth = {}
  table.columBaseStyle = nil
  table.headerRowBaseStyle = nil
  table.headerColumnBaseStyle = nil
  table.selectedRow = nil
  table.defaultColumnWidth = 80
  table.sortColumn = -1
  table.sortType = TABLE_SORTING_ASC
  table.autoSort = false

  return table
end

-- Clear table values
function UITable:onDestroy()
  for _,row in pairs(self.rows) do
    row.onClick = nil
  end
  self.rows = {}
  self.columns = {}
  self.headerRow = nil
  self.headerColumns = {}
  self.columnWidth = {}
  self.selectedRow = nil

  if self.dataSpace then
    self.dataSpace:destroyChildren()
    self.dataSpace = nil
  end
end

-- Detect if a header is already defined
function UITable:onSetup()
  local header = self:getChildById('header')
  if header then
    self:setHeader(header)
  end
end

-- Parse table related styles
function UITable:onStyleApply(styleName, styleNode)
  for name, value in pairs(styleNode) do
    if value ~= false then
      if name == 'table-data' then
        addEvent(function()
          self:setTableData(self:getParent():getChildById(value))
        end)
      elseif name == 'column-style' then
        addEvent(function()
          self:setColumnStyle(value)
        end)
      elseif name == 'row-style' then
        addEvent(function()
          self:setRowStyle(value)
        end)
      elseif name == 'header-column-style' then
        addEvent(function()
          self:setHeaderColumnStyle(value)
        end)
      elseif name == 'header-row-style' then
        addEvent(function()
          self:setHeaderRowStyle(value)
        end)
      end
    end
  end
end

function UITable:setColumnWidth(width)
  if self:hasHeader() then return end
  self.columnWidth = width
end

function UITable:setDefaultColumnWidth(width)
  self.defaultColumnWidth = width
end

-- Check if the table has a header
function UITable:hasHeader()
  return self.headerRow ~= nil
end

-- Clear all rows
function UITable:clearData()
  if not self.dataSpace then
    return
  end
  self.dataSpace:destroyChildren()
  self.selectedRow = nil
  self.columns = {}
  self.rows = {}
end

-- Set existing child as header
function UITable:setHeader(headerWidget)
  self:removeHeader()

  if self.dataSpace then
    local newHeight = self.dataSpace:getHeight()-headerRow:getHeight()-self.dataSpace:getMarginTop()
    self.dataSpace:applyStyle({ height = newHeight })
  end

  self.headerColumns = {}
  self.columnWidth = {}
  for colId, column in pairs(headerWidget:getChildren()) do
    column.colId = colId
    column.table = self
    table.insert(self.columnWidth, column:getWidth())
    table.insert(self.headerColumns, column)
  end

  self.headerRow = headerWidget
end

-- Create and add header from table data
function UITable:addHeader(data)
  if not data or type(data) ~= 'table' then
    g_logger.error('UITable:addHeaderRow - table columns must be provided in a table')
    return
  end

  self:removeHeader()

  -- build header columns
  local columns = {}
  for colId, column in pairs(data) do
    local col = g_ui.createWidget(self.headerColumnBaseStyle)
    col.colId = colId
    col.table = self
    for type, value in pairs(column) do
      if type == 'width' then
        col:setWidth(value)
      elseif type == 'height' then
        col:setHeight(value)
      elseif type == 'text' then
        col:setText(value)
      elseif type == 'onClick' then
{'fraction_non_alphanumeric': 0.09724557092978145, 'fraction_numerical': 0.00129315918789603, 'mean_word_length': 3.1941431670281997, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5084310', 'n_tokens_mistral': 2391, 'n_tokens_neox': 2360, 'n_words': 636}