Skip to content

Commit 3f9cb3f

Browse files
Fixed NPE, added InsertColumn, extended test cases
1 parent a78d951 commit 3f9cb3f

File tree

2 files changed

+328
-149
lines changed

2 files changed

+328
-149
lines changed

NanoXLSX/Worksheet.cs

Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2629,13 +2629,14 @@ private static bool WorksheetExists(string name, Workbook workbook)
26292629

26302630
#endregion
26312631

2632-
#region Insert-Search-Replace
2632+
#region Insert-Search-Replace
26332633

26342634
/// <summary>
2635-
/// Inserts 'count' rows below the specified 'rowNumber'.
2636-
/// The 'new' rows inherit the style of the row above.
2637-
/// Note: Formulas are not adjusted.
2635+
/// Inserts 'count' rows below the specified 'rowNumber'. Existing cells are moved down by the number of new rows.
2636+
/// The inserted, new rows inherits the style of the original cell at the defined row number.
2637+
/// The inserted cells are empty. The values can be set later
26382638
/// </summary>
2639+
/// <remarks>Formulas / references are not adjusted</remarks>
26392640
/// <param name="rowNumber">Row number below which the new row(s) will be inserted.</param>
26402641
/// <param name="numberOfNewRows">Number of rows to insert.</param>
26412642
public void InsertRow(int rowNumber, int numberOfNewRows)
@@ -2665,7 +2666,6 @@ public void InsertRow(int rowNumber, int numberOfNewRows)
26652666
this.Cells.Remove(cell.Key);
26662667
}
26672668

2668-
26692669
// Fill the gap with new cells, using the same style as the first row.
26702670
foreach (Cell cell in upperRow)
26712671
{
@@ -2686,11 +2686,62 @@ public void InsertRow(int rowNumber, int numberOfNewRows)
26862686
}
26872687
}
26882688

2689+
/// <summary>
2690+
/// Inserts 'count' columns right of the specified 'columnNumber'. Existing cells are moved to the right by the number of new columns.
2691+
/// The inserted, new columns inherits the style of the original cell at the defined column number.
2692+
/// The inserted cells are empty. The values can be set later
2693+
/// </summary>
2694+
/// <remarks>Formulas are not adjusted</remarks>
2695+
/// <param name="columnNumber">Column number right which the new column(s) will be inserted.</param>
2696+
/// <param name="numberOfNewColumns">Number of columns to insert.</param>
2697+
public void InsertColumn(int columnNumber, int numberOfNewColumns)
2698+
{
2699+
var leftColumn = this.GetColumn(columnNumber);
2700+
var cellsToChange = this.Cells.Where(c => c.Value.CellAddress2.Column > columnNumber).ToList();
2701+
2702+
Dictionary<string, Cell> newCells = new Dictionary<string, Cell>();
2703+
foreach (var cell in cellsToChange)
2704+
{
2705+
var row = cell.Value.CellAddress2.Row;
2706+
var col = cell.Value.CellAddress2.Column;
2707+
Address newAddress = new Address(col + numberOfNewColumns, row);
2708+
2709+
Cell newCell = new Cell(cell.Value.Value, cell.Value.DataType, newAddress);
2710+
if (cell.Value.CellStyle != null)
2711+
{
2712+
newCell.SetStyle(cell.Value.CellStyle); // Apply the style from the "old" cell.
2713+
}
2714+
newCells.Add(newAddress.GetAddress(), newCell);
2715+
2716+
// Delete the original cells since the key cannot be changed.
2717+
this.Cells.Remove(cell.Key);
2718+
}
2719+
2720+
// Fill the gap with new cells, using the same style as the first row.
2721+
foreach (Cell cell in leftColumn)
2722+
{
2723+
for (int i = 0; i < numberOfNewColumns; i++)
2724+
{
2725+
Address newAddress = new Address(cell.CellAddress2.Column + 1 + i, cell.CellAddress2.Row);
2726+
Cell newCell = new Cell(null, Cell.CellType.EMPTY, newAddress);
2727+
if (cell.CellStyle != null)
2728+
newCell.SetStyle(cell.CellStyle);
2729+
this.Cells.Add(newAddress.GetAddress(), newCell);
2730+
}
2731+
}
2732+
2733+
// Re-add the previous cells from the copy back with a new key.
2734+
foreach (KeyValuePair<string, Cell> cellKeyValue in newCells)
2735+
{
2736+
this.Cells.Add(cellKeyValue.Key, cellKeyValue.Value); //cell.Value is the cell incl. Style etc.
2737+
}
2738+
}
2739+
26892740
/// <summary>
26902741
/// Searches for the first occurrence of the value.
26912742
/// </summary>
26922743
/// <param name="searchValue">The value to search for.</param>
2693-
/// <returns>The first cell containing the searched value or Null</returns>
2744+
/// <returns>The first cell containing the searched value or null if the value was not found</returns>
26942745
public Cell FirstCellByValue(object searchValue)
26952746
{
26962747
var cell = this.Cells.FirstOrDefault(c =>
@@ -2704,12 +2755,11 @@ public Cell FirstCellByValue(object searchValue)
27042755
/// Example: var cell = worksheet.FindCell(c => c.Value?.ToString().Contains("searchValue"));
27052756
/// </summary>
27062757
/// <param name="predicate"></param>
2707-
/// <returns>The first cell containing the searched value or Null</returns>
2758+
/// <returns>The first cell containing the searched value or null if the value was not found</returns>
27082759
public Cell FirstOrDefaultCell(Func<Cell, bool> predicate)
27092760
{
2710-
return this.Cells
2711-
.FirstOrDefault(c => predicate(c.Value))
2712-
.Value;
2761+
return this.Cells.Values
2762+
.FirstOrDefault(c => c != null && (c.Value == null || predicate(c)));
27132763
}
27142764

27152765
/// <summary>
@@ -2728,9 +2778,9 @@ public List<Cell> CellsByValue(object searchValue)
27282778
/// <summary>
27292779
/// Replaces all occurrences of 'oldValue' with 'newValue' and returns the number of replacements.
27302780
/// </summary>
2731-
/// <param name="oldValue"></param>
2732-
/// <param name="newValue"></param>
2733-
/// <returns>Count of replaced Cell-Values</returns>
2781+
/// <param name="oldValue">Old value</param>
2782+
/// <param name="newValue">New value that should replace the old one</param>
2783+
/// <returns>Count of replaced Cell values</returns>
27342784
public int ReplaceCellValue(object oldValue, object newValue)
27352785
{
27362786
int count = 0;

0 commit comments

Comments
 (0)