SmartTableDataTableModel.h

The model behind Set Data Table, and the stand-in a cell class is given for a row.

Source/SmartTables/Public/SmartTableDataTableModel.h

A table over a UDataTable, which is the other shape of data most projects already have.

A column binds to a field of the row struct by name. That lookup falls back to the authored name, which is the only reason a Blueprint row struct works at all: its fields carry an id on disk.

Rows are read where they sit, and no value is ever copied out. A row is known by its name, so a selection lives through rows being added to the asset.

Class
USmartTableDataTableModel
Extends
USmartTableModel
Members
29
Blueprint nodes
2

Public functions 3

Set Data TableSetDataTablenode
UFUNCTION( BlueprintCallable, Category = "Smart Tables|Model" ) void SetDataTable( UDataTable * InDataTable )

Points this model at an asset. Every binding resolves again, the stand-ins go, and edits to the new asset come back here.

Get Data TableGetDataTablepure node
UFUNCTION( BlueprintPure, Category = "Smart Tables|Model" ) UDataTable * GetDataTable() const

The asset this model reads, or null before one is set.

SetColumns
void SetColumns( const TArray< FSmartTableColumn > & InColumns )

Given by the table, which owns the column names. Every binding resolves again, and the rows redraw.

Protected functions 6

GetNumRows_Implementationoverride
virtual int32 GetNumRows_Implementation() override
GetCellText_Implementationoverride
virtual FText GetCellText_Implementation( int32 NaturalRow, FName ColumnId ) override
GetCellSortKey_Implementationoverride
virtual FSmartTableSortKey GetCellSortKey_Implementation( int32 NaturalRow, FName ColumnId ) override
GetRowId_Implementationoverride
virtual FName GetRowId_Implementation( int32 NaturalRow ) override
GetRowItem_Implementationoverride
virtual UObject * GetRowItem_Implementation( int32 NaturalRow ) override
NaturalRowOfItem_Implementationoverride
virtual int32 NaturalRowOfItem_Implementation( UObject * Item ) override

Private functions 8

ResolveBindings
void ResolveBindings()

Resolves every column against the row struct, and warns for each one that resolves against nothing. A column broken in both its value binding and its sort binding warns twice, once in each category. A repeated ColumnId is passed over, since only the first of them is ever reached.

BeginDestroyoverride
virtual void BeginDestroy() override
GetCellEditor_Implementationoverride
virtual ESmartTableCellEditor GetCellEditor_Implementation( int32 NaturalRow, FName ColumnId ) override
SetCellText_Implementationoverride
virtual bool SetCellText_Implementation( int32 NaturalRow, FName ColumnId, const FText & Value ) override
HandleDataTableChanged
void HandleDataTableChanged()

The asset moved under this model: a row edited, added or dropped in the DataTable editor.

Values need nothing here, since rows are read where they sit. The row names do need reading again, and first: everything else in this class names a row by its place in that array.

The stand-ins go with them. One left naming a dropped row is a cell that stops reading, with nothing in the log saying why.

IndexOfColumn
int32 IndexOfColumn( FName ColumnId ) const
UnresolvedSignaturestatic
static FString UnresolvedSignature( const struct FSmartTableColumn & Column, const UScriptStruct & RowStruct )

What the warning for a column was about: both the bindings it names, and the struct they failed against, reduced to one string that is only ever compared.

RowData
uint8 * RowData( int32 NaturalRow ) const

A pointer that is not const out of a const function, exactly as UDataTable::FindRowUnchecked is declared. The row memory belongs to the asset, so whether this model is const says nothing about it. Readers narrow it on their own, and the one writer is SetCellText.

Private variables 10

DataTableChangedHandle
FDelegateHandle DataTableChangedHandle

Kept so the delegate comes off again: on a swap of the asset, and once more in BeginDestroy.

ColumnOrderById
TMap< FName, int32 > ColumnOrderById

Column id to its place in Columns. SetColumns builds it again from nothing, and a repeated id keeps the place of the first column carrying it.

Data TableDataTable
UPROPERTY( Transient ) TObjectPtr< UDataTable > DataTable
Transient
Never saved.

The asset in use. Transient, since a model is built at runtime and never saved.

ColumnsColumns
UPROPERTY( Transient ) TArray< FSmartTableColumn > Columns
Transient
Never saved.

Reflected because a column carries a CellClass, which the garbage collector has to see.

Row ProxiesRowProxies
UPROPERTY( Transient ) TMap< FName, TObjectPtr< USmartTableDataTableRow > > RowProxies
Transient
Never saved.

One stand-in per row, built only for the rows something asked the item of.

RowNames
TArray< FName > RowNames

The row names of the asset, in the order it lists them. This is natural space.

ValueBindings
TArray< SmartTable::FBinding > ValueBindings

One per entry in Columns. Resolved when the asset or the columns change, and never per cell.

SortBindings
TArray< SmartTable::FBinding > SortBindings
UnresolvedWarnings
TMap< FName, FString > UnresolvedWarnings

What this model has already warned about, per column, and what that warning was about.

The value is a signature: both binding names, the path of the struct they failed against, and a hash of its field list. Warning again turns on whether that signature moved, and never on whether the column is still broken.

The field list is in there because a User Defined Struct is built again in place. It is the same object at the same path, carrying different fields. The path on its own would never move.

NoRowStructWarnedFor
FString NoRowStructWarnedFor

The asset the no row struct warning was last given for. Empty until it has been given once.

That warning names an asset and never a column, so UnresolvedWarnings has no key for it. Resolving runs again on every edit to the asset, and with nothing kept here it would warn on each one.

USmartTableDataTableRow class

What a cell class is given for a DataTable row.

The table and the row name, and nothing else. Those two are what the built-in Get Data Table Row node takes, so a Blueprint cell over a DataTable is that node plus a pin.

One is built the first time something asks for the item of a row, and kept from then on. A CellClass column asks. A double click, the row menu and a query for the selected item all ask too.

Public variables 2

Data TableDataTablebp read
UPROPERTY( BlueprintReadOnly, Category = "Smart Tables" ) TObjectPtr< UDataTable > DataTable

The asset this row lives in.

Row NameRowNamebp read
UPROPERTY( BlueprintReadOnly, Category = "Smart Tables" ) FName RowName

Which row, by the name the asset files it under.

Next: SmartTableKeptRow.h