1use densa_data::{DataError, Filter, LiveTable, Order, RecordId, View, ViewId, ViewSpec};
2use densa_grid::{CellStyle, CellText, Column, GridModel, Palette, SortOrder};
3
4use crate::live::LiveGrid;
5use crate::table::{CellState, TableError};
6
7#[derive(Debug)]
23pub struct LiveModel {
24 table: LiveTable,
25 grid: LiveGrid,
26 columns: Vec<Column>,
27 view: ViewId,
28 filter: Option<Filter>,
29 sort: Option<(usize, SortOrder)>,
30 instance: u64,
32 columns_revision: u64,
34 generation: u64,
35}
36
37impl LiveModel {
38 pub fn new(mut table: LiveTable) -> Result<Self, DataError> {
44 let view = table.add_view(ViewSpec::new())?;
45 let grid = LiveGrid::new(&table);
46 Ok(Self {
47 columns: grid.columns(),
48 grid,
49 view,
50 filter: None,
51 sort: None,
52 instance: table.instance(),
53 table,
54 columns_revision: 0,
55 generation: 0,
56 })
57 }
58
59 pub fn table(&self) -> &LiveTable {
61 &self.table
62 }
63
64 pub fn table_mut(&mut self) -> &mut LiveTable {
68 &mut self.table
69 }
70
71 pub fn view(&self) -> Option<View<'_>> {
74 self.table.view(self.view)
75 }
76
77 pub fn record(&self, index: usize) -> Option<RecordId> {
79 self.view()?.record(index)
80 }
81
82 pub fn filter(&self) -> Option<&Filter> {
84 self.filter.as_ref()
85 }
86
87 pub fn set_filter(&mut self, filter: Option<Filter>) -> Result<(), DataError> {
94 self.replace_view(filter, self.sort)
95 }
96
97 pub fn set_decimals(
103 &mut self,
104 column: usize,
105 decimals: Option<usize>,
106 ) -> Result<(), TableError> {
107 self.grid.set_decimals(column, decimals)?;
108 self.read_columns();
109 Ok(())
110 }
111
112 pub fn set_column_chars(&mut self, column: usize, chars: usize) -> Result<(), TableError> {
118 self.grid.set_column_chars(column, chars)?;
119 self.read_columns();
120 Ok(())
121 }
122
123 fn read_columns(&mut self) {
125 self.columns = self.grid.columns();
126 self.columns_revision = self.columns_revision.wrapping_add(1);
127 }
128
129 fn replace_view(
132 &mut self,
133 filter: Option<Filter>,
134 sort: Option<(usize, SortOrder)>,
135 ) -> Result<(), DataError> {
136 let view = self.table.add_view(self.spec(filter.clone(), sort))?;
137 self.table.remove_view(self.view);
138 self.view = view;
139 self.filter = filter;
140 self.sort = sort;
141 Ok(())
142 }
143
144 fn spec(&self, filter: Option<Filter>, sort: Option<(usize, SortOrder)>) -> ViewSpec {
147 let mut spec = ViewSpec::new();
148 if let Some(filter) = filter {
149 spec = spec.filter(filter);
150 }
151 if let Some((column, order)) = sort {
152 if let Some(name) = self.sort_name(column) {
153 let order = match order {
154 SortOrder::Descending => Order::Descending,
155 _ => Order::Ascending,
156 };
157 spec = spec.sort_by(name, order);
158 }
159 }
160 spec
161 }
162
163 fn sort_name(&self, column: usize) -> Option<String> {
166 let schema = self.table.schema();
167 let name = schema.fields().get(column)?.name();
168 let (first, _) = schema.column_with_name(name)?;
169 (first == column).then(|| name.clone())
170 }
171
172 fn adopt_table(&mut self) {
175 self.instance = self.table.instance();
176 self.generation = self.generation.wrapping_add(1);
177 if self
178 .sort
179 .is_some_and(|(column, _)| self.sort_name(column).is_none())
180 {
181 self.sort = None;
182 }
183 if self.view().is_none() {
184 let spec = self.spec(self.filter.clone(), self.sort);
185 let view = self.table.add_view(spec).or_else(|_| {
186 self.filter = None;
187 self.sort = None;
188 self.table.add_view(ViewSpec::new())
189 });
190 if let Ok(view) = view {
191 self.view = view;
192 }
193 }
194 }
195}
196
197impl GridModel for LiveModel {
198 fn columns(&self) -> &[Column] {
199 &self.columns
200 }
201
202 fn rows(&self) -> usize {
203 self.view().map_or(0, |view| view.len())
204 }
205
206 fn cell(&self, row: usize, column: usize, text: &mut CellText, palette: &Palette) -> CellStyle {
207 let at = self.view().and_then(|view| view.row(row));
208 let state = match at {
209 Some(at) if self.grid.is_synced(&self.table) => self.grid.write(at, column, text),
210 _ => CellState::OutOfRange,
211 };
212 let color = if state == CellState::Value {
213 palette.text
214 } else {
215 palette.dim_text
216 };
217 CellStyle::new(color)
218 }
219
220 fn prepare(&mut self) {
221 let replaced = self.instance != self.table.instance();
222 if replaced {
223 self.adopt_table();
224 }
225 let widths = self.grid.widths();
226 self.grid.sync(&self.table);
227 if replaced || widths != self.grid.widths() {
230 self.read_columns();
231 }
232 }
233
234 fn sort(&mut self, column: usize, order: SortOrder) -> bool {
235 self.sort_name(column).is_some()
236 && self
237 .replace_view(self.filter.clone(), Some((column, order)))
238 .is_ok()
239 }
240
241 fn sort_state(&self) -> Option<(usize, SortOrder)> {
242 self.sort
243 }
244
245 fn row_key(&self, row: usize) -> Option<u64> {
246 self.record(row).map(RecordId::to_bits)
247 }
248
249 fn row_of_key(&self, key: u64) -> Option<usize> {
250 self.view()?.position(RecordId::from_bits(key))
251 }
252
253 fn columns_revision(&self) -> u64 {
254 self.columns_revision
255 }
256
257 fn generation(&self) -> u64 {
258 self.generation
259 }
260}