processRules method

void processRules(
  1. int changedRow,
  2. int changedCol,
  3. String newValue
)

Executes all rules associated with a specific cell upon value change.

Implementation

void processRules(int changedRow, int changedCol, String newValue) {
  if (_formRules.isEmpty || _getTableDataCallback == null) return;

  bool stateChanged = false;
  List<List<String>> currentGrid = _getTableDataCallback!();

  for (var rule in _formRules) {
    if (rule.rowIndex == changedRow && rule.colIndex == changedCol) {
      String stateKey = "${changedRow}_${changedCol}";
      _cellStates.putIfAbsent(stateKey, () => CellFormState());

      final state = _cellStates[stateKey]!;
      String workingValue = newValue;

      // 1. Process Overrides
      if (rule.overrideValue != null) {
        String? overrideResult = rule.overrideValue!(newValue, currentGrid);
        if (overrideResult != null && overrideResult != newValue) {
          workingValue = overrideResult;
          state.isOverridden = true;

          if (rule.overrideMessage != null) {
            state.overrideMessage = rule.overrideMessage!(newValue, currentGrid);
          } else {
            state.overrideMessage = null;
          }

          // Update UI cursor cleanly
          final tController = _textControllers[stateKey];
          if (tController != null) {
            tController.text = workingValue;
            tController.selection = TextSelection.collapsed(offset: workingValue.length);
          }
        } else {
          state.isOverridden = false;
          state.overrideMessage = null;
        }
      }

      // 2. Process Validation (Always runs on the RAW newValue)
      String? errorResult = rule.validate(newValue, currentGrid);
      if (state.errorText != errorResult) {
        state.errorText = errorResult;
        stateChanged = true;
      }

      if (state.isOverridden) stateChanged = true;
    }
  }

  if (stateChanged) notifyListeners();
}