use densa_data::{DataError, Filter, LiveTable, Order, RecordId, View, ViewId, ViewSpec};
use densa_grid::{CellStyle, CellText, Column, GridModel, Palette, SortOrder};
use crate::live::LiveGrid;
use crate::table::{CellState, TableError};
#[derive(Debug)]
pub struct LiveModel {
table: LiveTable,
grid: LiveGrid,
columns: Vec<Column>,
view: ViewId,
filter: Option<Filter>,
sort: Option<(usize, SortOrder)>,
instance: u64,
columns_revision: u64,
generation: u64,
}
impl LiveModel {
pub fn new(mut table: LiveTable) -> Result<Self, DataError> {
let view = table.add_view(ViewSpec::new())?;
let grid = LiveGrid::new(&table);
Ok(Self {
columns: grid.columns(),
grid,
view,
filter: None,
sort: None,
instance: table.instance(),
table,
columns_revision: 0,
generation: 0,
})
}
pub fn table(&self) -> &LiveTable {
&self.table
}
pub fn table_mut(&mut self) -> &mut LiveTable {
&mut self.table
}
pub fn view(&self) -> Option<View<'_>> {
self.table.view(self.view)
}
pub fn record(&self, index: usize) -> Option<RecordId> {
self.view()?.record(index)
}
pub fn filter(&self) -> Option<&Filter> {
self.filter.as_ref()
}
pub fn set_filter(&mut self, filter: Option<Filter>) -> Result<(), DataError> {
self.replace_view(filter, self.sort)
}
pub fn set_decimals(
&mut self,
column: usize,
decimals: Option<usize>,
) -> Result<(), TableError> {
self.grid.set_decimals(column, decimals)?;
self.read_columns();
Ok(())
}
pub fn set_column_chars(&mut self, column: usize, chars: usize) -> Result<(), TableError> {
self.grid.set_column_chars(column, chars)?;
self.read_columns();
Ok(())
}
fn read_columns(&mut self) {
self.columns = self.grid.columns();
self.columns_revision = self.columns_revision.wrapping_add(1);
}
fn replace_view(
&mut self,
filter: Option<Filter>,
sort: Option<(usize, SortOrder)>,
) -> Result<(), DataError> {
let view = self.table.add_view(self.spec(filter.clone(), sort))?;
self.table.remove_view(self.view);
self.view = view;
self.filter = filter;
self.sort = sort;
Ok(())
}
fn spec(&self, filter: Option<Filter>, sort: Option<(usize, SortOrder)>) -> ViewSpec {
let mut spec = ViewSpec::new();
if let Some(filter) = filter {
spec = spec.filter(filter);
}
if let Some((column, order)) = sort {
if let Some(name) = self.sort_name(column) {
let order = match order {
SortOrder::Descending => Order::Descending,
_ => Order::Ascending,
};
spec = spec.sort_by(name, order);
}
}
spec
}
fn sort_name(&self, column: usize) -> Option<String> {
let schema = self.table.schema();
let name = schema.fields().get(column)?.name();
let (first, _) = schema.column_with_name(name)?;
(first == column).then(|| name.clone())
}
fn adopt_table(&mut self) {
self.instance = self.table.instance();
self.generation = self.generation.wrapping_add(1);
if self
.sort
.is_some_and(|(column, _)| self.sort_name(column).is_none())
{
self.sort = None;
}
if self.view().is_none() {
let spec = self.spec(self.filter.clone(), self.sort);
let view = self.table.add_view(spec).or_else(|_| {
self.filter = None;
self.sort = None;
self.table.add_view(ViewSpec::new())
});
if let Ok(view) = view {
self.view = view;
}
}
}
}
impl GridModel for LiveModel {
fn columns(&self) -> &[Column] {
&self.columns
}
fn rows(&self) -> usize {
self.view().map_or(0, |view| view.len())
}
fn cell(&self, row: usize, column: usize, text: &mut CellText, palette: &Palette) -> CellStyle {
let at = self.view().and_then(|view| view.row(row));
let state = match at {
Some(at) if self.grid.is_synced(&self.table) => self.grid.write(at, column, text),
_ => CellState::OutOfRange,
};
let color = if state == CellState::Value {
palette.text
} else {
palette.dim_text
};
CellStyle::new(color)
}
fn prepare(&mut self) {
let replaced = self.instance != self.table.instance();
if replaced {
self.adopt_table();
}
let widths = self.grid.widths();
self.grid.sync(&self.table);
if replaced || widths != self.grid.widths() {
self.read_columns();
}
}
fn sort(&mut self, column: usize, order: SortOrder) -> bool {
self.sort_name(column).is_some()
&& self
.replace_view(self.filter.clone(), Some((column, order)))
.is_ok()
}
fn sort_state(&self) -> Option<(usize, SortOrder)> {
self.sort
}
fn row_key(&self, row: usize) -> Option<u64> {
self.record(row).map(RecordId::to_bits)
}
fn row_of_key(&self, key: u64) -> Option<usize> {
self.view()?.position(RecordId::from_bits(key))
}
fn columns_revision(&self) -> u64 {
self.columns_revision
}
fn generation(&self) -> u64 {
self.generation
}
}