4.5 KiB
4.5 KiB
DataGrid Refactoring
Objective
Clearly separate data management and rendering responsibilities in the DataGrid system.
The current architecture mixes data mutation, formula computation, and rendering in the
same DataGrid class, which complicates cross-table formula management and code reasoning.
Guiding Principles
DataServicecan exist without rendering. The reverse is not true.- All data mutations go through
DataService. - Columns have two facets: data semantics (
ColumnDefinition) and UI presentation (ColumnUiState). - No more parent hierarchy where avoidable — access via
InstancesManager.get_by_type(). - The persistence key is
grid_id(stable), nottable_name(can change over time).
New Classes (core/data/)
DataServicesManager — SingleInstance
- Owns the
FormulaEngine(cross-table formula coordination) - Creates
DataServiceinstances on demand fromDataGridsManager - Provides access to
DataServiceinstances bygrid_id - Provides the resolver callback for
FormulaEngine:grid_id → DataStore
DataService — companion to DataGrid
- Owns
DataStoreandlist[ColumnDefinition] - Holds a reference to
DataServicesManagerforFormulaEngineaccess - Methods:
load_dataframe(df),add_row(),add_column(),set_data(col_id, row_index, value) - Mutations call
mark_data_changed()→ set dirty flag ensure_ready()→ recalculates formulas if dirty (called bymk_body_content_page())- Can exist without any rendering
DataStore — renamed from DatagridStore
- Pure persistence:
ne_df,ns_fast_access,ns_row_data,ns_total_rows DbObjectwith no business logic
ColumnDefinition
- Data semantics:
col_id,title,type,formula,col_index
Modified Classes
DataGridsRegistry — streamlined
- Persistence only:
put(),remove(),get_all_entries() - Loses:
get_columns(),get_column_type(),get_column_values(),get_row_count()
DatagridMetadataProvider — becomes a concrete SingleInstance
- No longer abstract / interface (only one concrete implementation exists)
- Reads from
DataServicesManagerandDataGridsRegistry - Holds:
style_presets,formatter_presets,all_tables_formats - Exposes:
list_tables(),list_columns(),list_column_values(),get_column_type(),list_style_presets(),list_format_presets()
DataGridsManager — pure UI
- Keeps:
TreeView,TabsManager, document state,Commands - Loses:
FormulaEngine, presets,DatagridMetadataProvider,_resolve_store_for_table()
DataGrid — pure rendering
- Keeps:
mk_*,render(),__ft__(),_state,_settings - Keeps:
_apply_sort(),_apply_filter(),_get_filtered_df() - Loses:
add_new_row(),add_new_column(),init_from_dataframe(),_recalculate_formulas(),_register_existing_formulas(),_df_store - Accesses its
DataServicevia itsgrid_id:InstancesManager.get_by_type(DataServicesManager).get_service(grid_id) mk_body_content_page()callsdata_service.ensure_ready()before rendering
DatagridState
columnschanges fromlist[DataGridColumnState]→list[ColumnUiState]- Everything else remains unchanged
DataGridColumnState — split into two classes
| Class | Belongs to | Fields |
|---|---|---|
ColumnDefinition |
DataService |
col_id, title, type, formula, col_index |
ColumnUiState |
DatagridState |
col_id, width, visible, format |
Structural Fix
Current bug: mark_data_changed() is defined in FormulaEngine but is never called
by DataGrid. Formulas are only recalculated defensively at render time.
After refactoring:
- Every mutation in
DataServicecallsmark_data_changed()→ dirty flag set mk_body_content_page()callsdata_service.ensure_ready()→ recalculates if dirty- Multiple mutations before a render = a single recalculation
Progress Tracking
- Create
DataStore(renameDatagridStore) - Create
ColumnDefinition - Create
DataService - Create
DataServicesManager - Refactor
DataGridsRegistry(streamline) - Refactor
DatagridMetadataProvider(make concrete) - Refactor
DataGridsManager(pure UI) - Refactor
DataGrid(pure rendering, splitDataGridColumnState) - Update tests
- Remove
init_from_dataframefromDataGrid(kept temporarily for transition) - Full split of
DataGridColumnStateintoColumnDefinition+ColumnUiStateinDatagridState