Skip to main content

yew_datatable_core/table/
data_table.rs

1//! Main table instance that coordinates all table functionality.
2//!
3//! `DataTable` is the primary entry point for interacting with the data table.
4//! It manages columns, data, and state, and provides methods for all table operations.
5
6use crate::column::column_def::ColumnDef;
7use crate::column::column_id::ColumnId;
8use crate::row::data_table_row::DataTableRow;
9use crate::row::data_table_row_id::DataTableRowId;
10use crate::row::data_table_row_model::DataTableRowModel;
11use crate::state::data_table_state::DataTableState;
12use crate::table::data_table_options::DataTableOptions;
13use crate::table::data_table_options_builder::DataTableOptionsBuilder;
14
15/// Main table instance that coordinates all table functionality.
16///
17/// Manages columns, data, and state, providing methods for sorting,
18/// filtering, pagination, selection, and all other table operations.
19pub struct DataTable<T: Clone> {
20    /// Column definitions.
21    columns: Vec<ColumnDef<T>>,
22
23    /// Row model containing processed rows.
24    row_model: DataTableRowModel<T>,
25
26    /// Combined table state.
27    state: DataTableState,
28
29    /// Table options.
30    options: DataTableOptions,
31}
32
33impl<T: Clone> DataTable<T> {
34    /// Creates a new table with the given options.
35    ///
36    /// # Parameters
37    ///
38    /// - `options`: The table configuration options.
39    ///
40    /// # Returns
41    ///
42    /// - `DataTable<T>`: A new empty table instance.
43    pub fn new(options: DataTableOptions) -> Self {
44        Self {
45            columns: Vec::new(),
46            row_model: DataTableRowModel::default(),
47            state: DataTableState::new(),
48            options,
49        }
50    }
51
52    /// Creates a table with columns and data.
53    ///
54    /// # Parameters
55    ///
56    /// - `columns`: The column definitions.
57    /// - `data`: The raw data rows.
58    /// - `id_fn`: A function that generates a row ID from row data and index.
59    ///
60    /// # Returns
61    ///
62    /// - `DataTable<T>`: A new table with the provided columns and data.
63    pub fn with_data<F>(columns: Vec<ColumnDef<T>>, data: Vec<T>, id_fn: F) -> Self
64    where
65        F: Fn(&T, usize) -> DataTableRowId,
66    {
67        Self {
68            columns,
69            row_model: DataTableRowModel::new(data, id_fn),
70            state: DataTableState::new(),
71            options: DataTableOptions::default(),
72        }
73    }
74
75    /// Creates a table builder.
76    ///
77    /// # Returns
78    ///
79    /// - `DataTableOptionsBuilder`: A new options builder instance.
80    pub fn builder() -> DataTableOptionsBuilder {
81        DataTableOptionsBuilder::new()
82    }
83
84    /// Sets the column definitions.
85    ///
86    /// # Parameters
87    ///
88    /// - `columns`: The new column definitions.
89    pub fn set_columns(&mut self, columns: Vec<ColumnDef<T>>) {
90        // Replace the column definitions.
91        self.columns = columns;
92
93        // Mark the row model as needing reprocessing.
94        self.row_model.invalidate();
95    }
96
97    /// Sets the table data.
98    ///
99    /// # Parameters
100    ///
101    /// - `data`: The new raw data rows.
102    /// - `id_fn`: A function that generates a row ID from row data and index.
103    pub fn set_data<F>(&mut self, data: Vec<T>, id_fn: F)
104    where
105        F: Fn(&T, usize) -> DataTableRowId,
106    {
107        // Update the row model with new data.
108        self.row_model.set_data(data, id_fn);
109    }
110
111    /// Sets the data using index as row ID.
112    ///
113    /// # Parameters
114    ///
115    /// - `data`: The new raw data rows.
116    pub fn set_data_indexed(&mut self, data: Vec<T>) {
117        // Update the row model using index-based IDs.
118        self.row_model.set_data(data, |_, idx| DataTableRowId::from_index(idx));
119    }
120
121    /// Returns the column definitions.
122    ///
123    /// # Returns
124    ///
125    /// - `&[ColumnDef<T>]`: A slice of column definitions.
126    pub fn columns(&self) -> &[ColumnDef<T>] {
127        &self.columns
128    }
129
130    /// Returns a mutable reference to the state.
131    ///
132    /// # Returns
133    ///
134    /// - `&mut DataTableState`: A mutable reference to the table state.
135    pub fn state_mut(&mut self) -> &mut DataTableState {
136        &mut self.state
137    }
138
139    /// Returns the table state.
140    ///
141    /// # Returns
142    ///
143    /// - `&DataTableState`: A reference to the table state.
144    pub fn state(&self) -> &DataTableState {
145        &self.state
146    }
147
148    /// Returns the table options.
149    ///
150    /// # Returns
151    ///
152    /// - `&DataTableOptions`: A reference to the table options.
153    pub fn options(&self) -> &DataTableOptions {
154        &self.options
155    }
156
157    /// Returns the row model.
158    ///
159    /// # Returns
160    ///
161    /// - `&DataTableRowModel<T>`: A reference to the row model.
162    pub fn row_model(&self) -> &DataTableRowModel<T> {
163        &self.row_model
164    }
165
166    /// Processes the row model with current state.
167    pub fn process(&mut self) {
168        // Run the full processing pipeline.
169        self.row_model.process(
170            &self.columns,
171            &self.state.filtering,
172            &self.state.sorting,
173            &self.state.expanding,
174            &self.state.grouping,
175            &self.state.pagination,
176            &self.state.row_selection,
177        );
178    }
179
180    /// Returns visible rows after processing.
181    ///
182    /// # Returns
183    ///
184    /// - `impl Iterator<Item = &DataTableRow<T>>`: An iterator over visible rows.
185    pub fn visible_rows(&self) -> impl Iterator<Item = &DataTableRow<T>> {
186        self.row_model.visible_rows()
187    }
188
189    /// Returns the total number of rows.
190    ///
191    /// # Returns
192    ///
193    /// - `usize`: The total row count.
194    pub fn total_row_count(&self) -> usize {
195        self.row_model.total_row_count()
196    }
197
198    /// Returns the number of filtered rows.
199    ///
200    /// # Returns
201    ///
202    /// - `usize`: The filtered row count.
203    pub fn filtered_row_count(&self) -> usize {
204        self.row_model.filtered_row_count()
205    }
206
207    /// Returns the number of rows on the current page.
208    ///
209    /// # Returns
210    ///
211    /// - `usize`: The page row count.
212    pub fn page_row_count(&self) -> usize {
213        self.row_model.page_row_count()
214    }
215
216    /// Gets a row by ID.
217    ///
218    /// # Parameters
219    ///
220    /// - `id`: The row identifier to look up.
221    ///
222    /// # Returns
223    ///
224    /// - `Option<&DataTableRow<T>>`: The row if found.
225    pub fn get_row(&self, id: &DataTableRowId) -> Option<&DataTableRow<T>> {
226        self.row_model.get_row(id)
227    }
228
229    /// Returns visible column IDs in order.
230    ///
231    /// # Returns
232    ///
233    /// - `Vec<ColumnId>`: The ordered list of visible column IDs.
234    pub fn visible_column_ids(&self) -> Vec<ColumnId> {
235        // Collect all column IDs.
236        let all_ids: Vec<ColumnId> = self.columns.iter().map(|c| c.id().clone()).collect();
237
238        // Apply custom ordering.
239        let ordered = self.state.column_ordering.apply_order(&all_ids);
240
241        // Apply pinning to reorder left/center/right.
242        let pinned = self.state.column_pinning.apply_pinning(&ordered);
243
244        // Filter by visibility.
245        pinned
246            .into_iter()
247            .filter(|id| self.state.column_visibility.is_visible(id))
248            .collect()
249    }
250
251    /// Returns visible columns in order.
252    ///
253    /// # Returns
254    ///
255    /// - `Vec<&ColumnDef<T>>`: References to visible column definitions.
256    pub fn visible_columns(&self) -> Vec<&ColumnDef<T>> {
257        // Get visible column IDs and look up their definitions.
258        let visible_ids = self.visible_column_ids();
259        visible_ids
260            .iter()
261            .filter_map(|id| self.columns.iter().find(|c| c.id() == id))
262            .collect()
263    }
264
265    /// Gets a column by ID.
266    ///
267    /// # Parameters
268    ///
269    /// - `id`: The column identifier to look up.
270    ///
271    /// # Returns
272    ///
273    /// - `Option<&ColumnDef<T>>`: The column definition if found.
274    pub fn get_column(&self, id: &ColumnId) -> Option<&ColumnDef<T>> {
275        // Search for the column by ID.
276        self.columns.iter().find(|c| c.id() == id)
277    }
278
279    /// Toggles sorting for a column.
280    ///
281    /// # Parameters
282    ///
283    /// - `column_id`: The column identifier to toggle sorting for.
284    /// - `multi`: Whether to add to multi-sort list.
285    pub fn toggle_sort(&mut self, column_id: impl Into<ColumnId>, multi: bool) {
286        // Toggle the sort and invalidate the row model.
287        self.state.sorting.toggle_sort(column_id, multi);
288        self.row_model.invalidate();
289    }
290
291    /// Sets a column filter.
292    ///
293    /// # Parameters
294    ///
295    /// - `column_id`: The column identifier.
296    /// - `value`: The filter value text.
297    pub fn set_column_filter(&mut self, column_id: impl Into<ColumnId>, value: impl Into<String>) {
298        // Set the filter, reset pagination, and invalidate.
299        self.state.filtering.set_text_filter(column_id, value);
300        self.state.pagination.go_to_first();
301        self.row_model.invalidate();
302    }
303
304    /// Sets the global filter.
305    ///
306    /// # Parameters
307    ///
308    /// - `value`: The global search text.
309    pub fn set_global_filter(&mut self, value: impl Into<String>) {
310        // Set the global filter, reset pagination, and invalidate.
311        self.state.filtering.set_global_filter(value);
312        self.state.pagination.go_to_first();
313        self.row_model.invalidate();
314    }
315
316    /// Toggles row selection.
317    ///
318    /// # Parameters
319    ///
320    /// - `row_id`: The row identifier to toggle selection for.
321    pub fn toggle_row_selection(&mut self, row_id: DataTableRowId) {
322        // Toggle the row selection state.
323        self.state.row_selection.toggle(row_id);
324    }
325
326    /// Selects all filtered rows.
327    pub fn select_all_rows(&mut self) {
328        // Get filtered row IDs and select them all.
329        let ids = self.row_model.filtered_row_ids();
330        self.state.row_selection.select_all(ids);
331    }
332
333    /// Clears row selection.
334    pub fn clear_selection(&mut self) {
335        // Clear all selections.
336        self.state.row_selection.clear();
337    }
338
339    /// Toggles row expansion.
340    ///
341    /// # Parameters
342    ///
343    /// - `row_id`: The row identifier to toggle expansion for.
344    pub fn toggle_row_expansion(&mut self, row_id: DataTableRowId) {
345        // Toggle the expansion state and invalidate.
346        self.state.expanding.toggle(row_id);
347        self.row_model.invalidate();
348    }
349
350    /// Toggles column visibility.
351    ///
352    /// # Parameters
353    ///
354    /// - `column_id`: The column identifier to toggle visibility for.
355    pub fn toggle_column_visibility(&mut self, column_id: ColumnId) {
356        // Toggle the column visibility state.
357        self.state.column_visibility.toggle(column_id);
358    }
359
360    /// Goes to a specific page.
361    ///
362    /// # Parameters
363    ///
364    /// - `page`: The zero-based page index.
365    pub fn go_to_page(&mut self, page: usize) {
366        // Navigate to the specified page.
367        let row_count = self.filtered_row_count();
368        self.state.pagination.go_to_page(page, row_count);
369    }
370
371    /// Goes to the next page.
372    pub fn next_page(&mut self) {
373        // Navigate to the next page.
374        let row_count = self.filtered_row_count();
375        self.state.pagination.go_to_next(row_count);
376    }
377
378    /// Goes to the previous page.
379    pub fn previous_page(&mut self) {
380        // Navigate to the previous page.
381        self.state.pagination.go_to_previous();
382    }
383
384    /// Sets the page size.
385    ///
386    /// # Parameters
387    ///
388    /// - `size`: The new page size.
389    pub fn set_page_size(&mut self, size: usize) {
390        // Update the page size.
391        let row_count = self.filtered_row_count();
392        self.state.pagination.set_page_size(size, row_count);
393    }
394
395    /// Resets all table state.
396    pub fn reset(&mut self) {
397        // Reset all state and invalidate.
398        self.state.reset_all();
399        self.row_model.invalidate();
400    }
401}