Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/formula refactoring after delete rows #419

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ReoGrid/Core/Cell.cs
Original file line number Diff line number Diff line change
Expand Up @@ -972,7 +972,7 @@ private void ValidateAssociation()
[NonSerialized]
internal STNode formulaTree;

internal STNode FormulaTree { get { return this.formulaTree; } set { this.formulaTree = value; } }
internal STNode FormulaSyntaxTree { get { return this.formulaTree; } set { this.formulaTree = value; } }
#endif

/// <summary>
Expand Down
6 changes: 3 additions & 3 deletions ReoGrid/Core/Formula.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,11 @@ internal void SetCellFormula(Cell cell, STNode node)
{
IterateToAddReference(cell, node, referencedRanges, true);

cell.FormulaTree = node;
cell.FormulaSyntaxTree = node;
}
catch (CircularReferenceException crex)
{
cell.FormulaTree = null;
cell.FormulaSyntaxTree = null;
cell.InnerFormula = null;

cell.formulaStatus = FormulaStatus.CircularReference;
Expand Down Expand Up @@ -401,7 +401,7 @@ internal void RecalcCell(Cell cell, Stack<List<Cell>> dirtyCellStack = null)
{
try
{
value = Evaluator.CheckAndGetDefaultValue(cell, Evaluator.Evaluate(cell, cell.FormulaTree)).value;
value = Evaluator.CheckAndGetDefaultValue(cell, Evaluator.Evaluate(cell, cell.FormulaSyntaxTree)).value;

cell.formulaStatus = FormulaStatus.Normal;
}
Expand Down
12 changes: 12 additions & 0 deletions ReoGrid/Core/Header.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
using unvell.ReoGrid.Actions;
using unvell.ReoGrid.Utility;
using System.Collections;
using unvell.ReoGrid.Formula;

#if OUTLINE
using unvell.ReoGrid.Outline;
Expand Down Expand Up @@ -2145,6 +2146,17 @@ internal void DeleteRows(int row, int count, RemoveRowsAction action)
}
#endregion // Update frozen rows

#region Update Formulas
IterateCells(row + count, 0, MaxContentRow - row - count + 1, MaxContentCol + 1, true, (ir, ic, icell) =>
{
if (icell.HasFormula)
{
FormulaRefactor.OffsetFormulaReferences(this, icell, row + count, 0, -count, 0);
}
return true;
});
#endregion Update Formulas

suspendingUIUpdates = false;

UpdateViewportController();
Expand Down
2 changes: 1 addition & 1 deletion ReoGrid/Core/Range.cs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ public void DeleteRangeData(RangePosition range, bool checkReadonly = false)

cell.InnerFormula = null;
#if FORMULA
cell.FormulaTree = null;
cell.FormulaSyntaxTree = null;
this.ClearCellReferenceList(cell);

if (formulaDirtyCells.Contains(cell))
Expand Down
2 changes: 1 addition & 1 deletion ReoGrid/Formula/Evaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class Evaluator
public static FormulaValue Evaluate(Cell cell)
{
if (cell == null) return null;
return Evaluate(cell.Worksheet == null ? null : cell.Worksheet.workbook, cell, cell.FormulaTree);
return Evaluate(cell.Worksheet == null ? null : cell.Worksheet.workbook, cell, cell.FormulaSyntaxTree);
}

public static FormulaValue Evaluate(IWorkbook workbook, string input)
Expand Down
2 changes: 1 addition & 1 deletion ReoGrid/Formula/Parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,7 @@ public override string ToString()
}

/// <summary>
/// Create a copy from this stnode.
/// Create a copy from this syntax tree node.
/// </summary>
/// <returns>The copied stnode.</returns>
public virtual object Clone()
Expand Down
114 changes: 108 additions & 6 deletions ReoGrid/Formula/Refactor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class FormulaRefactor
{
#region Generator
/// <summary>
/// Generate formula from a syntax tree in memory
/// Generate formula from a syntax tree in memory.
/// </summary>
/// <param name="node">root node of syntax tree used to generate formula</param>
/// <returns>formula generated from a syntax tree</returns>
Expand All @@ -48,7 +48,7 @@ internal static string Generate(string input, STNode node)
}

/// <summary>
/// Generate formula form a syntax tree in memory by specified format styles
/// Generate formula form a syntax tree in memory by specified format styles.
/// </summary>
/// <param name="node">root node of syntax tree used to generate formula</param>
/// <param name="flag">generating format style flags</param>
Expand Down Expand Up @@ -179,7 +179,7 @@ internal static void Reuse(Worksheet sheet, CellPosition fromPosition, RangePosi
#region Arguments Check
if (cell == null
|| string.IsNullOrEmpty(cell.InnerFormula)
|| cell.FormulaTree == null)
|| cell.FormulaSyntaxTree == null)
{
throw new InvalidOperationException("cannot found formula from specified position, try reset formula for the cell again");
}
Expand All @@ -195,8 +195,8 @@ internal static void Reuse(Worksheet sheet, CellPosition fromPosition, RangePosi
}
#endregion // Arguments Check

var rs = new ReplacableString(cell.InnerFormula);
STNode node = cell.FormulaTree;
var formulaString = new ReplacableString(cell.InnerFormula);
STNode node = cell.FormulaSyntaxTree;

Stack<List<Cell>> dirtyCells = new Stack<List<Cell>>();

Expand All @@ -212,7 +212,7 @@ internal static void Reuse(Worksheet sheet, CellPosition fromPosition, RangePosi
continue;
}

FormulaRefactor.CopyFormula(fromPosition, node, toCell, rs, dirtyCells);
FormulaRefactor.CopyFormula(fromPosition, node, toCell, formulaString, dirtyCells);

c += cell.Colspan;
}
Expand Down Expand Up @@ -340,6 +340,108 @@ internal static void CopyFormula(CellPosition fromPosition, STNode fromNode, Cel

}
#endregion // Reuse

internal static void OffsetFormulaReferences(Worksheet sheet, Cell cell, int startRow, int startCol,
int offsetRows, int offsetCols)
{
var node = cell.formulaTree;
var rs = new ReplacableString(cell.InnerFormula);

STNode.RecursivelyIterate(node, _n =>
{
switch (_n.Type)
{
case STNodeType.CELL:
#region Cell Offset
{
var refCellNode = (STCellNode)_n;

var newPos = refCellNode.Position;

if (refCellNode.Position.Row >= startRow
&& refCellNode.Position.Col >= startCol)
{
if (newPos.RowProperty == PositionProperty.Relative)
{
newPos.Row += offsetRows;
}

if (newPos.ColumnProperty == PositionProperty.Relative)
{
newPos.Col += offsetCols;
}
}

if (newPos.Row < 0 || newPos.Col < 0
|| newPos.Row >= sheet.rows.Count || newPos.Col >= sheet.cols.Count)
{
cell.formulaStatus = FormulaStatus.InvalidReference;
}

refCellNode.Position = newPos;

_n.Start += rs.Offset;
int diff = rs.Replace(_n.Start, _n.Length, newPos.ToAddress());
_n.Length += diff;
}
break;
#endregion // Cell Offset

case STNodeType.RANGE:
#region Range Offset
{
var refRangeNode = (STRangeNode)_n;
var newRange = refRangeNode.Range;

if (refRangeNode.Range.Row >= startRow
&& refRangeNode.Range.Col >= startCol)
{
if (newRange.StartRowProperty == PositionProperty.Relative)
{
newRange.Row += offsetRows;
}

if (newRange.StartColumnProperty == PositionProperty.Relative)
{
newRange.Col += offsetCols;
}
}

if (refRangeNode.Range.EndRow >= startRow
&& refRangeNode.Range.EndCol >= startCol)
{
if (newRange.StartRowProperty == PositionProperty.Relative)
{
newRange.Rows += offsetRows;
}

if (newRange.StartColumnProperty == PositionProperty.Relative)
{
newRange.Cols += offsetCols;
}
}

if (newRange.Row < 0 || newRange.Col < 0
|| newRange.Row >= sheet.rows.Count || newRange.Col >= sheet.cols.Count
|| newRange.EndRow < 0 || newRange.EndCol < 0
|| newRange.EndRow >= sheet.rows.Count || newRange.EndCol >= sheet.cols.Count)
{
cell.formulaStatus = FormulaStatus.InvalidReference;
}

refRangeNode.Range = newRange;

_n.Start += rs.Offset;
int diff = rs.Replace(_n.Start, _n.Length, newRange.ToAddress());
_n.Length += diff;
}
break;
#endregion // Range Offset
}
});

cell.InnerFormula = rs.ToString();
}
}

class ReplacableString
Expand Down
5 changes: 5 additions & 0 deletions ReoGrid/Worksheet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1171,6 +1171,11 @@ public void IterateCells(RangePosition range, bool skipEmptyCells, Func<int, int
this.IterateCells(fixedRange.Row, fixedRange.Col, fixedRange.Rows, fixedRange.Cols, skipEmptyCells, iterator);
}

public void IterateCells(int row, int col, int rows, int cols, Func<int, int, Cell, bool> iterator)
{
IterateCells(row, col, rows, cols, true, iterator);
}

/// <summary>
/// Iterate over all valid cells inside specified range. Invalid cells (merged by others cell) will be skipped.
/// </summary>
Expand Down