diff --git a/src/EPPlus/ExcelAddressBase.cs b/src/EPPlus/ExcelAddressBase.cs index daed37ed35..38e1d8dd1a 100644 --- a/src/EPPlus/ExcelAddressBase.cs +++ b/src/EPPlus/ExcelAddressBase.cs @@ -1333,8 +1333,9 @@ internal ExcelAddressBase AddColumnFirstAddress(int col, int cols, bool setFixed var toCol = GetColumn((setFixed && _toColFixed ? _toCol : _toCol + cols), setRefOnMinMax); if (col <= _fromCol) { - var fromCol = GetColumn((setFixed && _fromColFixed ? _fromCol : _fromCol + cols), setRefOnMinMax); - return new ExcelAddressBase(_fromRow, fromCol, _toRow, toCol, _fromRowFixed, _fromColFixed, _toRowFixed, _toColFixed, WorkSheetName, _address); + var fromCol = setFixed && _fromColFixed ? _fromCol : _fromCol + cols; + if (fromCol > ExcelPackage.MaxColumns) return null; + return new ExcelAddressBase(_fromRow, GetColumn(fromCol, setRefOnMinMax), _toRow, toCol, _fromRowFixed, _fromColFixed, _toRowFixed, _toColFixed, WorkSheetName, _address); } else { diff --git a/src/EPPlus/ExcelNamedRange.cs b/src/EPPlus/ExcelNamedRange.cs index e2718d161e..62449d582d 100644 --- a/src/EPPlus/ExcelNamedRange.cs +++ b/src/EPPlus/ExcelNamedRange.cs @@ -38,6 +38,7 @@ private enum NameRelativeType /// RelativeTableAddress = 2 } + ExcelWorksheet _sheet; /// /// A named range diff --git a/src/EPPlus/ExcelNamedRangeCollection.cs b/src/EPPlus/ExcelNamedRangeCollection.cs index a0c77a2879..9782ed35b8 100644 --- a/src/EPPlus/ExcelNamedRangeCollection.cs +++ b/src/EPPlus/ExcelNamedRangeCollection.cs @@ -179,22 +179,71 @@ internal void Insert(int rowFrom, int colFrom, int rows, int cols, int lowerLimi Insert(rowFrom, colFrom, rows, cols, n => true, lowerLimint, upperLimit); } - internal void Insert(int rowFrom, int colFrom, int rows, int cols, Func filter, int lowerLimint = 0, int upperLimit=int.MaxValue) + internal void Insert(int rowFrom, int colFrom, int rows, int cols, Func filter, int lowerLimit = 0, int upperLimit=int.MaxValue) { var namedRanges = this._list.Where(filter); foreach(var namedRange in namedRanges) { if (namedRange._fromRow <= 0) continue; var address = new ExcelAddressBase(namedRange.Address); - if (rows > 0 && address._toCol<=upperLimit && address._fromCol>=lowerLimint && address.Rows < ExcelPackage.MaxRows) + if (rows > 0 && address._toCol<=upperLimit && address._fromCol>=lowerLimit && address.Rows < ExcelPackage.MaxRows) { - address = address.AddRow(rowFrom, rows, false); + if(address._toRow + rows > ExcelPackage.MaxRows) + { + if (address._fromRowFixed == false) + { + //if relative the address should remain as is + } + else if (address._fromRowFixed | address._toRowFixed) + { + //This may look strange at a glance but appears to be how excel does it despite absolute refs + address = address.AddRow(rowFrom, rows, false, false); + } + else + { + //If over MaxRows this results in null + address = address.AddRow(rowFrom, rows, false); + } + } + else + { + //If over MaxRows this results in null + address = address.AddRow(rowFrom, rows, false); + } } - if(cols > 0 && colFrom > 0 && address._toRow <= upperLimit && address._fromRow >= lowerLimint && address.Columns < ExcelPackage.MaxColumns) + if(cols > 0 && colFrom > 0 && address._toRow <= upperLimit && address._fromRow >= lowerLimit && address.Columns < ExcelPackage.MaxColumns) { - address = address.AddColumn(colFrom, cols, false,false); + if (address._toCol + cols > ExcelPackage.MaxColumns) + { + if (address._toColFixed == false && address._fromColFixed == false) + { + //if relative the address should remain as is + } + else if (address._fromColFixed | address._toColFixed) + { + //This may look strange at a glance but appears to be how excel does it despite absolute refs + address = address.AddColumn(colFrom, cols, false, false); + } + else + { + address = address.AddColumn(colFrom, cols, false); + } + } + else + { + //If over MaxRows this results in null + address = address.AddColumn(colFrom, cols, false, false); + } + } + + if(address == null) + { + namedRange.Address = $"{namedRange.WorkSheetName}!{ExcelErrorValue.Values.Ref}"; + } + else + { + namedRange.Address = address.Address; } - namedRange.Address = address.Address; } } internal void Delete(int rowFrom, int colFrom, int rows, int cols, int lowerLimint = 0, int upperLimit = int.MaxValue) diff --git a/src/EPPlusTest/Core/Range/Insert/RangeInsertTests.cs b/src/EPPlusTest/Core/Range/Insert/RangeInsertTests.cs index 337fa837be..0543b7395d 100644 --- a/src/EPPlusTest/Core/Range/Insert/RangeInsertTests.cs +++ b/src/EPPlusTest/Core/Range/Insert/RangeInsertTests.cs @@ -1526,5 +1526,163 @@ public void EnsureInsertWorksCorrectlyWithColumnCollection() SaveAndCleanup(p); } } + + #region NamedRange insert Max row/col tests + [TestMethod] + public void InsertRowRangeMaxRelativeMultipleLines() + { + using (var p = OpenPackage("namedRangeMaxRelativeLargerRange.xlsx", true)) + { + var ws = p.Workbook.Worksheets.Add("ANamedRange"); + + string rangeString = "A1048570:A1048576"; + + //Add relative reference to max row + var namedRange = ws.Names.Add("EndNamedRangeA", ws.Cells[rangeString], true); + + //Insert row somewhere above max row + ws.InsertRow(347, 1, 346); + + //address should remain unchanged + Assert.AreEqual(rangeString, namedRange.Address); + SaveAndCleanup(p); + } + } + + [TestMethod] + public void InsertRowRangeMaxAbsoluteMultipleLines() + { + using (var p = OpenPackage("namedRangeMaxAbsoluteLargerRange.xlsx", true)) + { + var ws = p.Workbook.Worksheets.Add("ANamedRange"); + + //Add absolute reference to max row + var namedRange = ws.Names.Add("EndNamedRangeA", ws.Cells["A1048570:A1048576"]); + + //Insert row somewhere above max row + ws.InsertRow(347, 1, 346); + + //from row should be added to by one + Assert.AreEqual("$A$1048571:$A$1048576", namedRange.Address); + SaveAndCleanup(p); + } + } + + [TestMethod] + public void InsertRowNamedRangeMaxAbsolute() + { + using (var p = OpenPackage("namedRangeMaxAbsolute.xlsx", true)) + { + var ws = p.Workbook.Worksheets.Add("ANamedRange"); + + //Add absolute reference to max row + var namedRange = ws.Names.Add("EndNamedRangeA", ws.Cells["A1048576"]); + + //Insert row somewhere above max row + ws.InsertRow(347, 1, 346); + + Assert.AreEqual($"ANamedRange!{ExcelErrorValue.Values.Ref}", namedRange.Address); + Assert.AreEqual(null, namedRange.Value); + } + } + + [TestMethod] + public void InsertRowNamedRangeMaxRelative() + { + using (var p = OpenPackage("namedRangeMaxRelative.xlsx", true)) + { + var ws = p.Workbook.Worksheets.Add("ANamedRange"); + + var relativeRange = ws.Names.Add("EndNamedRangeB", ws.Cells["B1048576"], true); + + //Insert row somewhere above max row + ws.InsertRow(347, 1, 346); + + Assert.AreEqual("B1048576", relativeRange.Address); + SaveAndCleanup(p); + } + } + + //Column tests start + + [TestMethod] + public void InsertColNamedRangeMaxAbsolute() + { + using (var p = OpenPackage("namedRangeMaxColAbsolute.xlsx", true)) + { + var ws = p.Workbook.Worksheets.Add("colNamedRange"); + + var maxCols = ExcelPackage.MaxColumns; + + //Add absolute reference to max col + var namedRange = ws.Names.Add("EndNamedRangeMaxCols", ws.Cells[3, maxCols]); + + //Insert col somewhere left of max col + ws.InsertColumn(347, 1, 346); + + Assert.AreEqual($"colNamedRange!{ExcelErrorValue.Values.Ref}", namedRange.Address); + Assert.AreEqual(null, namedRange.Value); + } + } + + [TestMethod] + public void InsertColNamedRangeMaxRelative() + { + using (var p = OpenPackage("namedRangeMaxColRelative.xlsx", true)) + { + var ws = p.Workbook.Worksheets.Add("colNamedRange"); + + var maxCols = ExcelPackage.MaxColumns; + + //Add absolute reference to max col + var namedRange = ws.Names.Add("EndNamedRangeMaxCols", ws.Cells[3, maxCols], true); + + //Insert col somewhere left of max col + ws.InsertColumn(347, 1, 346); + + Assert.AreEqual("XFD3", namedRange.Address); + } + } + + [TestMethod] + public void InsertColRangeMaxRelativeMultipleLines() + { + using (var p = OpenPackage("namedRangeMaxColRelativeLargerRange.xlsx", true)) + { + var ws = p.Workbook.Worksheets.Add("ANamedRange"); + + string rangeString = "XFB3:XFD3"; + + //Add relative reference to max row + var namedRange = ws.Names.Add("EndNamedRangeA", ws.Cells[rangeString], true); + + //Insert col somewhere left of max col + ws.InsertColumn(347, 1, 346); + + //address should remain unchanged + Assert.AreEqual(rangeString, namedRange.Address); + } + } + + [TestMethod] + public void InsertColRangeMaxAbsoluteMultipleLines() + { + using (var p = OpenPackage("namedRangeMaxColAbsoluteLargerRange.xlsx", true)) + { + var ws = p.Workbook.Worksheets.Add("ANamedRange"); + + string rangeString = "XFB3:XFD3"; + + //Add relative reference to max row + var namedRange = ws.Names.Add("EndNamedRangeA", ws.Cells[rangeString]); + + //Insert col somewhere left of max col + ws.InsertColumn(347, 1, 346); + + //address should remain unchanged + Assert.AreEqual("$XFC$3:$XFD$3", namedRange.Address); + } + } + #endregion } } \ No newline at end of file diff --git a/src/EPPlusTest/WorkSheetTests.cs b/src/EPPlusTest/WorkSheetTests.cs index fa9e44a9c3..ed53a0be5f 100644 --- a/src/EPPlusTest/WorkSheetTests.cs +++ b/src/EPPlusTest/WorkSheetTests.cs @@ -2747,5 +2747,20 @@ internal ExcelRangeBase GenerateRowsFromTemplate(ExcelWorksheet wks, ExcelRangeB return wks.Cells[$"{originalTemplateRow}:{originalTemplateRow + insertCount}"]; } + + [TestMethod] + public void InsertRowIssue() + { + using (var p = OpenTemplatePackage("s1019.xlsx")) + { + var ws = p.Workbook.Worksheets.GetByName("披露附注"); + var namedRange = ws.Names["上一行"]; + + var adress = namedRange.Address; + + ws.InsertRow(347, 1, 346); + SaveAndCleanup(p); + } + } } }