Skip to content
Merged
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
34 changes: 34 additions & 0 deletions ReoGrid/Core/AutoFillSerial/AutoFillSection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.Collections.Generic;
using System.Linq;

namespace unvell.ReoGrid
{
public class AutoFillSection
{
private readonly List<IAutoFillSectionEntry> entries = new List<IAutoFillSectionEntry>();

public AutoFillSection(IAutoFillSectionEntry entry)
{
entries.Add(entry);
}

public bool TryAdd(IAutoFillSectionEntry entry)
{
if (entries.First().IsSequenceOf(entry))
{
entries.Add(entry);
return true;
}

return false;
}

public object[] GetValues(int iteration)
{
var baseValue = entries.First().Value;
var incrementPerIteration = entries.Last().GetIncrementPerIteration(baseValue, entries.Count);

return entries.Select(entry => entry.GetIterationValue(baseValue, incrementPerIteration, iteration)).ToArray();
}
}
}
23 changes: 23 additions & 0 deletions ReoGrid/Core/AutoFillSerial/AutoFillSectionEntryFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using unvell.ReoGrid.Utility;

namespace unvell.ReoGrid
{
public static class AutoFillSectionEntryFactory
{
public static IAutoFillSectionEntry Create(object value)
{
if (value == null)
{
return new NullAutoFillSectionEntry();
}

double number;
if (CellUtility.TryGetNumberData(value, out number))
{
return new NumericalAutoFillSectionEntry(number);
}

return new TextAutoFillSectionEntry(value.ToString());
}
}
}
55 changes: 55 additions & 0 deletions ReoGrid/Core/AutoFillSerial/AutoFillSequence.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace unvell.ReoGrid
{
public class AutoFillSequence
{
private readonly List<AutoFillSection> sections = new List<AutoFillSection>();

public AutoFillSequence(IList<object> values)
{
if (values == null || values.Count == 0)
{
throw new ArgumentException("AutoFillSequence requires at least one value.");
}

var valueIndex = 0;

var entry = AutoFillSectionEntryFactory.Create(values[valueIndex++]);
var currentSection = new AutoFillSection(entry);
sections.Add(currentSection);

while (valueIndex < values.Count)
{
entry = AutoFillSectionEntryFactory.Create(values[valueIndex++]);
if (!currentSection.TryAdd(entry))
{
currentSection = new AutoFillSection(entry);
sections.Add(currentSection);
}
}
}

public object[] Extrapolate(int count)
{
List<object> result = new List<object>(count);

var iteration = 0;

while (result.Count < count)
{
// First iteration is the input values. So start iterating from 1.
iteration++;
foreach (var section in sections)
{
var items = section.GetValues(iteration);
result.AddRange(items.Take(count - result.Count));
}
}

return result.ToArray();
}
}
}
13 changes: 13 additions & 0 deletions ReoGrid/Core/AutoFillSerial/IAutoFillSectionEntry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace unvell.ReoGrid
{
public interface IAutoFillSectionEntry
{
object Value { get; }

bool IsSequenceOf(IAutoFillSectionEntry otherEntry);

object GetIterationValue(object baseValue, object incrementPerIteration, int iteration);

object GetIncrementPerIteration(object baseValue, int numberOfEntries);
}
}
22 changes: 22 additions & 0 deletions ReoGrid/Core/AutoFillSerial/NullAutoFillSectionEntry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace unvell.ReoGrid
{
public class NullAutoFillSectionEntry : IAutoFillSectionEntry
{
public object Value { get; }

public bool IsSequenceOf(IAutoFillSectionEntry otherEntry)
{
return otherEntry is NullAutoFillSectionEntry;
}

public object GetIterationValue(object baseValue, object incrementPerIteration, int iteration)
{
return null;
}

public object GetIncrementPerIteration(object baseValue, int numberOfEntries)
{
return null;
}
}
}
37 changes: 37 additions & 0 deletions ReoGrid/Core/AutoFillSerial/NumericalAutoFillSectionEntry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
namespace unvell.ReoGrid
{
public class NumericalAutoFillSectionEntry : IAutoFillSectionEntry
{
public object Value { get; }

public NumericalAutoFillSectionEntry(double value)
{
Value = value;
}

public bool IsSequenceOf(IAutoFillSectionEntry otherEntry)
{
return otherEntry is NumericalAutoFillSectionEntry;
}

public object GetIterationValue(object baseValue, object incrementPerIteration, int iteration)
{
var diff = GetDifferenceToBaseValue(baseValue);
var incr = (double)incrementPerIteration;

return (double)baseValue + diff + incr * iteration;
}

public object GetIncrementPerIteration(object baseValue, int numberOfEntries)
{
return numberOfEntries > 1
? (GetDifferenceToBaseValue(baseValue) / (numberOfEntries - 1)) * numberOfEntries
: 0;
}

private double GetDifferenceToBaseValue(object baseValue)
{
return (double)Value - (double)baseValue;
}
}
}
81 changes: 81 additions & 0 deletions ReoGrid/Core/AutoFillSerial/TextAutoFillSectionEntry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using System.Linq;

namespace unvell.ReoGrid
{
public class TextAutoFillSectionEntry : IAutoFillSectionEntry
{
public object Value { get; }

private string textLeftOfDigit = string.Empty;
private string textRightOfDigit = string.Empty;
private bool hasDigit;

public TextAutoFillSectionEntry(string value)
{
var digits = "0123456789".ToCharArray();

var indexOfFirstDigit = value.IndexOfAny(digits);

if (indexOfFirstDigit == -1)
{
textLeftOfDigit = value;
}
else
{
hasDigit = true;
if (indexOfFirstDigit > 0)
{
textLeftOfDigit = value.Substring(0, indexOfFirstDigit);
value = value.Substring(indexOfFirstDigit);
}

var numberSequence = value.TakeWhile(c => digits.Contains(c)).ToArray();
textRightOfDigit = value.Substring(numberSequence.Length);

Value = double.Parse(new string(numberSequence));
}
}

public bool IsSequenceOf(IAutoFillSectionEntry otherEntry)
{
var otherTextEntry = otherEntry as TextAutoFillSectionEntry;
if (otherTextEntry == null)
{
return false;
}

return textLeftOfDigit.Equals(otherTextEntry.textLeftOfDigit)
&& textRightOfDigit.Equals(otherTextEntry.textRightOfDigit)
&& hasDigit == otherTextEntry.hasDigit;
}

public object GetIterationValue(object baseValue, object incrementPerIteration, int iteration)
{
var digitText = string.Empty;

if (hasDigit)
{
var diff = GetDifferenceToBaseValue(baseValue);
var incr = (double) incrementPerIteration;

digitText = ((double) baseValue + diff + incr * iteration).ToString();
}

return $"{textLeftOfDigit}{digitText}{textRightOfDigit}";
}

public object GetIncrementPerIteration(object baseValue, int numberOfEntries)
{
return numberOfEntries > 1 && hasDigit
? (GetDifferenceToBaseValue(baseValue) / (numberOfEntries - 1)) * numberOfEntries
: 0;
}

private double GetDifferenceToBaseValue(object baseValue)
{
return hasDigit
? (double)Value - (double)baseValue
: 0;
}
}
}
58 changes: 7 additions & 51 deletions ReoGrid/Core/Data.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,9 @@
#if FORMULA

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using unvell.ReoGrid.Formula;
using unvell.ReoGrid.Utility;

namespace unvell.ReoGrid
{
Expand Down Expand Up @@ -167,7 +165,11 @@ private void AutoFillSerialCells(List<CellPosition> fromCells, List<CellPosition
return;
}

double diff = GetCellsDifference(fromCells);
var autoFillSequenceInput = fromCells
.Select(cellPosition => this[cellPosition])
.ToList();
var autoFillSequence = new AutoFillSequence(autoFillSequenceInput);
var autoFillExtrapolatedValues = autoFillSequence.Extrapolate(toCells.Count);

for (var toCellIndex = 0; toCellIndex < toCells.Count; toCellIndex++)
{
Expand All @@ -177,62 +179,16 @@ private void AutoFillSerialCells(List<CellPosition> fromCells, List<CellPosition
var toCellPosition = toCells[toCellIndex];
var toCell = Cells[toCellPosition];

if (fromCell == null)
{
continue;
}

if (!string.IsNullOrEmpty(fromCell.InnerFormula))
if (!string.IsNullOrEmpty(fromCell?.InnerFormula))
{
FormulaRefactor.Reuse(this, fromCellPosition, new RangePosition(toCellPosition));
}
else
{
double refValue = 0;

if (CellUtility.TryGetNumberData(fromCell.Data, out refValue))
{
toCell.Data = refValue + diff * (fromCells.Count + toCellIndex - fromCellIndex);
}
toCell.Data = autoFillExtrapolatedValues[toCellIndex];
}
}
}

private double GetCellsDifference(List<CellPosition> fromCells)
{
double diff = 1;

if (fromCells.Count > 1)
{
for (var i = 0; i < fromCells.Count - 1; i++)
{
var cell1 = Cells[fromCells[i]];
var cell2 = Cells[fromCells[i+1]];

if (cell1 == null || cell2 == null)
{
continue;
}

double value1, value2;

if (CellUtility.TryGetNumberData(cell1, out value1) &&
CellUtility.TryGetNumberData(cell2, out value2))
{
if (i == 0)
{
diff = value2 - value1;
}
else
{
diff = (diff + (value2 - value1)) / 2;
}
}
}
}

return diff;
}
}
}

Expand Down
Loading