use crate::properties::PropertyList;
#[derive(Debug, Clone)]
pub struct Table<'a> {
pub properties: PropertyList<'a>,
pub columns: Vec<TableColumn<'a>>,
pub header: Option<TableBody<'a>>,
pub body: Vec<TableBody<'a>>,
pub footer: Option<TableBody<'a>>,
pub border_collapse: BorderCollapse,
}
#[derive(Debug, Clone)]
pub struct TableColumn<'a> {
pub properties: PropertyList<'a>,
pub column_width: ColumnWidth,
pub number_columns_repeated: usize,
}
#[derive(Debug, Clone)]
pub struct TableBody<'a> {
pub properties: PropertyList<'a>,
pub rows: Vec<TableRow<'a>>,
}
#[derive(Debug, Clone)]
pub struct TableRow<'a> {
pub properties: PropertyList<'a>,
pub cells: Vec<TableCell<'a>>,
pub height: Option<crate::Length>,
}
#[derive(Debug, Clone)]
pub struct TableCell<'a> {
pub properties: PropertyList<'a>,
pub number_columns_spanned: usize,
pub number_rows_spanned: usize,
pub blocks: Vec<super::Block<'a>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BorderCollapse {
Separate,
Collapse,
}
impl Default for BorderCollapse {
fn default() -> Self {
Self::Separate
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ColumnWidth {
Fixed(crate::Length),
Proportional(f64),
Auto,
}
impl<'a> Table<'a> {
pub fn new(properties: PropertyList<'a>) -> Self {
Self {
properties,
columns: Vec::new(),
header: None,
body: Vec::new(),
footer: None,
border_collapse: BorderCollapse::default(),
}
}
pub fn column_count(&self) -> usize {
self.columns.iter()
.map(|col| col.number_columns_repeated)
.sum()
}
pub fn column_width(&self, index: usize) -> Option<&ColumnWidth> {
let mut current_idx = 0;
for col in &self.columns {
if current_idx <= index && index < current_idx + col.number_columns_repeated {
return Some(&col.column_width);
}
current_idx += col.number_columns_repeated;
}
None
}
}
impl<'a> TableColumn<'a> {
pub fn new(properties: PropertyList<'a>, column_width: ColumnWidth) -> Self {
Self {
properties,
column_width,
number_columns_repeated: 1,
}
}
}
impl<'a> TableBody<'a> {
pub fn new(properties: PropertyList<'a>) -> Self {
Self {
properties,
rows: Vec::new(),
}
}
pub fn row_count(&self) -> usize {
self.rows.len()
}
}
impl<'a> TableRow<'a> {
pub fn new(properties: PropertyList<'a>) -> Self {
Self {
properties,
cells: Vec::new(),
height: None,
}
}
pub fn cell_count(&self) -> usize {
self.cells.len()
}
}
impl<'a> TableCell<'a> {
pub fn new(properties: PropertyList<'a>) -> Self {
Self {
properties,
number_columns_spanned: 1,
number_rows_spanned: 1,
blocks: Vec::new(),
}
}
pub fn spans_columns(&self) -> bool {
self.number_columns_spanned > 1
}
pub fn spans_rows(&self) -> bool {
self.number_rows_spanned > 1
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_table_creation() {
let props = PropertyList::new();
let table = Table::new(props);
assert_eq!(table.column_count(), 0);
assert!(table.header.is_none());
assert_eq!(table.body.len(), 0);
}
#[test]
fn test_column_count() {
let props = PropertyList::new();
let mut table = Table::new(props);
let col1 = TableColumn::new(PropertyList::new(), ColumnWidth::Auto);
let mut col2 = TableColumn::new(PropertyList::new(), ColumnWidth::Proportional(2.0));
col2.number_columns_repeated = 3;
table.columns.push(col1);
table.columns.push(col2);
assert_eq!(table.column_count(), 4); }
#[test]
fn test_column_width_lookup() {
let props = PropertyList::new();
let mut table = Table::new(props);
let col1 = TableColumn::new(PropertyList::new(), ColumnWidth::Fixed(crate::Length::from_pt(100.0)));
let mut col2 = TableColumn::new(PropertyList::new(), ColumnWidth::Auto);
col2.number_columns_repeated = 2;
table.columns.push(col1);
table.columns.push(col2);
match table.column_width(0) {
Some(ColumnWidth::Fixed(len)) => assert_eq!(*len, crate::Length::from_pt(100.0)),
_ => panic!("Expected Fixed width"),
}
assert!(matches!(table.column_width(1), Some(ColumnWidth::Auto)));
assert!(matches!(table.column_width(2), Some(ColumnWidth::Auto)));
assert!(table.column_width(3).is_none());
}
#[test]
fn test_cell_spanning() {
let props = PropertyList::new();
let mut cell = TableCell::new(props);
assert!(!cell.spans_columns());
assert!(!cell.spans_rows());
cell.number_columns_spanned = 2;
cell.number_rows_spanned = 3;
assert!(cell.spans_columns());
assert!(cell.spans_rows());
}
#[test]
fn test_border_collapse_default() {
let props = PropertyList::new();
let table = Table::new(props);
assert_eq!(table.border_collapse, BorderCollapse::Separate);
}
}