diff --git a/main/HSSF/Model/InternalSheet.cs b/main/HSSF/Model/InternalSheet.cs index b4da517ba..55a345c07 100644 --- a/main/HSSF/Model/InternalSheet.cs +++ b/main/HSSF/Model/InternalSheet.cs @@ -2339,6 +2339,21 @@ public int GetColumnOutlineLevel(int columnIndex) return _columnInfos.GetOutlineLevel(columnIndex); } + public int MinColumnIndex + { + get + { + return _columnInfos.MinColumnIndex; + } + } + + public int MaxColumnIndex + { + get + { + return _columnInfos.MaxColumnIndex; + } + } } public class UnsupportedBOFType : RecordFormatException diff --git a/main/HSSF/Model/InternalWorkbook.cs b/main/HSSF/Model/InternalWorkbook.cs index a39a94124..c71942ef0 100644 --- a/main/HSSF/Model/InternalWorkbook.cs +++ b/main/HSSF/Model/InternalWorkbook.cs @@ -1001,11 +1001,12 @@ public int GetFontIndex(FontRecord font) } throw new ArgumentException("Could not find that font!"); } + /** - * Returns the StyleRecord for the given - * xfIndex, or null if that ExtendedFormat doesn't - * have a Style set. - */ + * Returns the StyleRecord for the given + * xfIndex, or null if that ExtendedFormat doesn't + * have a Style set. + */ public StyleRecord GetStyleRecord(int xfIndex) { // Style records always follow after @@ -1032,6 +1033,31 @@ public StyleRecord GetStyleRecord(int xfIndex) } return null; } + + /** + * Update the StyleRecord to point to the new + * given index. + * + * @param oldXf the extended format index that was previously associated with this StyleRecord + * @param newXf the extended format index that is now associated with this StyleRecord + */ + public void UpdateStyleRecord(int oldXf, int newXf) + { + // Style records always follow after + // the ExtendedFormat records + for(int i = records.Xfpos; i /// Excel can Get cranky if you give it files containing too @@ -217,49 +217,86 @@ public static void OptimiseCellStyles(HSSFWorkbook workbook) // Loop over each style, seeing if it is the same // as an earlier one. If it is, point users of the - // later duplicate copy to the earlier one, and + // later duplicate copy to the earlier one, and // mark the later one as needing deleting // Only work on user added ones, which come after 20 - for (int i = 21; i < newPos.Length; i++) + for(int i = 21; i < newPos.Length; i++) { // Check this one for being a duplicate // of an earlier one int earlierDuplicate = -1; - for (int j = 0; j < i && earlierDuplicate == -1; j++) + for(int j = 0; j < i && earlierDuplicate == -1; j++) { ExtendedFormatRecord xfCheck = workbook.Workbook.GetExFormatAt(j); - if (xfCheck.Equals(xfrs[i])) + if(xfCheck.Equals(xfrs[i]) && + // newer duplicate user defined styles + !IsUserDefined(workbook, j)) { earlierDuplicate = j; } } // If we got a duplicate, mark it as such - if (earlierDuplicate != -1) + if(earlierDuplicate != -1) { - newPos[i] = (short)earlierDuplicate; + newPos[i] = (short) earlierDuplicate; zapRecords[i] = true; } - // If we got a duplicate, mark the one we're keeping as used - if (earlierDuplicate != -1) - { - isUsed[earlierDuplicate] = true; - } } + // Loop over all the cells in the file, and identify any user defined // styles aren't actually being used (don't touch built-in ones) - for (int sheetNum = 0; sheetNum < workbook.NumberOfSheets; sheetNum++) + for(int sheetNum = 0; sheetNum < workbook.NumberOfSheets; sheetNum++) { - HSSFSheet s = (HSSFSheet)workbook.GetSheetAt(sheetNum); - foreach (IRow row in s) + HSSFSheet s = workbook.GetSheetAt(sheetNum) as HSSFSheet; + foreach(IRow row in s) { - foreach (ICell cellI in row) + foreach(ICell cellI in row) + { + HSSFCell cell = (HSSFCell) cellI; + short oldXf1 = cell.CellValueRecord.XFIndex; + // some documents contain invalid values here + if(oldXf1 < newPos.Length) + { + isUsed[oldXf1] = true; + } + } + + // also mark row style as being used + short oldXf = ((HSSFRow) row).RowRecord.XFIndex; + // some documents contain invalid values here + if(oldXf < newPos.Length) { - HSSFCell cell = (HSSFCell)cellI; - short oldXf = cell.CellValueRecord.XFIndex; isUsed[oldXf] = true; } } + + // also mark column styles as being used + for(int col = s.Sheet.MinColumnIndex; col <= s.Sheet.MaxColumnIndex; col++) + { + short oldXf = s.Sheet.GetXFIndexForColAt((short) col); + // some documents contain invalid values here + if(oldXf < newPos.Length) + { + isUsed[oldXf] = true; + } + } + } + + // Propagate isUsed for duplicates and always set user styles to being used to never optimize them away + for(int i = 21; i < isUsed.Length; i++) + { + // user defined styles are always "used" + if(IsUserDefined(workbook, i)) + { + isUsed[i] = true; + } + + // If we got a duplicate which is used, mark the one we're keeping as used + if(newPos[i] != i && isUsed[i]) + { + isUsed[newPos[i]] = true; + } } // Mark any that aren't used as needing zapping for (int i = 21; i < isUsed.Length; i++) @@ -288,6 +325,20 @@ public static void OptimiseCellStyles(HSSFWorkbook workbook) // Update the new position newPos[i] = newPosition; + // also update StyleRecord and Parent-link + if(i != newPosition && newPosition != 0) + { + workbook.Workbook.UpdateStyleRecord(i, newPosition); + + ExtendedFormatRecord exFormat = workbook.Workbook.GetExFormatAt(i); + short oldParent = exFormat.ParentIndex; + // some documents contain invalid values here + if(oldParent < newPos.Length) + { + short newParent = newPos[oldParent]; + exFormat.ParentIndex = newParent; + } + } } // Zap the un-needed user style records @@ -307,27 +358,55 @@ public static void OptimiseCellStyles(HSSFWorkbook workbook) } // Finally, update the cells to point at their new extended format records - for (int sheetNum = 0; sheetNum < workbook.NumberOfSheets; sheetNum++) + for(int sheetNum = 0; sheetNum < workbook.NumberOfSheets; sheetNum++) { - HSSFSheet s = (HSSFSheet)workbook.GetSheetAt(sheetNum); - //IEnumerator rIt = s.GetRowEnumerator(); - //while (rIt.MoveNext()) + HSSFSheet s = workbook.GetSheetAt(sheetNum) as HSSFSheet; foreach(IRow row in s) { - //HSSFRow row = (HSSFRow)rIt.Current; - //IEnumerator cIt = row.GetEnumerator(); - //while (cIt.MoveNext()) - foreach (ICell cell in row) + foreach(ICell cell in row) { - //ICell cell = (HSSFCell)cIt.Current; - short oldXf = ((HSSFCell)cell).CellValueRecord.XFIndex; - NPOI.SS.UserModel.ICellStyle newStyle = workbook.GetCellStyleAt( - newPos[oldXf] - ); - cell.CellStyle = (newStyle); + short oldXf1 = ((HSSFCell) cell).CellValueRecord.XFIndex; + // some documents contain invalid values here + if(oldXf1 >= newPos.Length) + { + continue; + } + HSSFCellStyle newStyle1 = workbook.GetCellStyleAt(newPos[oldXf1]) as HSSFCellStyle; + cell.CellStyle = newStyle1; } + + // adjust row column style + short oldXf = ((HSSFRow) row).RowRecord.XFIndex; + // some documents contain invalid values here + if(oldXf >= newPos.Length) + { + continue; + } + HSSFCellStyle newStyle = workbook.GetCellStyleAt(newPos[oldXf]) as HSSFCellStyle; + row.RowStyle = newStyle; + } + + // adjust cell column style + for(int col = s.Sheet.MinColumnIndex; col <= s.Sheet.MaxColumnIndex; col++) + { + short oldXf = s.Sheet.GetXFIndexForColAt((short) col); + // some documents contain invalid values here + if(oldXf >= newPos.Length) + { + continue; + } + HSSFCellStyle newStyle = workbook.GetCellStyleAt(newPos[oldXf]) as HSSFCellStyle; + s.SetDefaultColumnStyle(col, newStyle); } } } + + private static bool IsUserDefined(HSSFWorkbook workbook, int index) + { + StyleRecord styleRecord = workbook.Workbook.GetStyleRecord(index); + return styleRecord != null && + !styleRecord.IsBuiltin && + styleRecord.Name != null; + } } } \ No newline at end of file diff --git a/main/SS/Util/CellRangeAddress.cs b/main/SS/Util/CellRangeAddress.cs index 677284a9b..876d97618 100644 --- a/main/SS/Util/CellRangeAddress.cs +++ b/main/SS/Util/CellRangeAddress.cs @@ -24,7 +24,7 @@ public CellRangeAddress(int firstRow, int lastRow, int firstCol, int lastCol) { if (lastRow < firstRow || lastCol < firstCol) throw new ArgumentException("Invalid cell range, having lastRow < firstRow || lastCol < firstCol, " + - "had rows " + lastRow + " >= " + firstRow + " or cells " + lastCol + " >= " + firstCol); + "had rows " + lastRow + " >= " + firstRow + " or cells " + lastCol + " >= " + firstCol); } public CellRangeAddress(RecordInputStream in1) diff --git a/main/SS/Util/CellRangeAddressBase.cs b/main/SS/Util/CellRangeAddressBase.cs index bde525e23..750de8b28 100644 --- a/main/SS/Util/CellRangeAddressBase.cs +++ b/main/SS/Util/CellRangeAddressBase.cs @@ -1,8 +1,12 @@ namespace NPOI.SS.Util { using EnumsNET; + using NPOI.HSSF; + using NPOI.SS.UserModel; using System; + using System.Collections; using System.Collections.Generic; + using System.Collections.ObjectModel; /** * See OOO documentation: excelfileformat.pdf sec 2.5.14 - 'Cell Range Address'

@@ -11,7 +15,7 @@ * * @author Josh Micich */ - public abstract class CellRangeAddressBase + public abstract class CellRangeAddressBase : IEnumerable { // /** max 65536 rows in BIFF8 */ @@ -59,11 +63,11 @@ protected CellRangeAddressBase(int firstRow, int lastRow, int firstCol, int last //} /** - * Validate the range limits against the supplied version of Excel - * - * @param ssVersion the version of Excel to validate against - * @throws IllegalArgumentException if the range limits are outside of the allowed range - */ + * Validate the range limits against the supplied version of Excel + * + * @param ssVersion the version of Excel to validate against + * @throws IllegalArgumentException if the range limits are outside of the allowed range + */ public void Validate(SpreadsheetVersion ssVersion) { ValidateRow(_firstRow, ssVersion); @@ -72,9 +76,9 @@ public void Validate(SpreadsheetVersion ssVersion) ValidateColumn(_lastCol, ssVersion); } /** - * Runs a bounds check for row numbers - * @param row - */ + * Runs a bounds check for row numbers + * @param row + */ private static void ValidateRow(int row, SpreadsheetVersion ssVersion) { int maxrow = ssVersion.LastRowIndex; @@ -96,15 +100,73 @@ private static void ValidateColumn(int column, SpreadsheetVersion ssVersion) if(column < 0) throw new ArgumentException("Minimum column number is 0"); } + ///

+ /// Determines if the given coordinates lie within the bounds + /// of this range. + /// + /// The row, 0-based. + /// The column, 0-based. + /// True if the coordinates lie within the bounds, false otherwise. + /// @see #intersects(CellRangeAddressBase) for checking if two ranges overlap public bool IsInRange(int rowInd, int colInd) { return _firstRow <= rowInd && rowInd <= _lastRow && //containsRow _firstCol <= colInd && colInd <= _lastCol; //containsColumn } + /// + /// + /// Determines if the given lies within the bounds + /// of this range. + /// + /// + /// NOTE: It is up to the caller to ensure the reference is + /// for the correct sheet, since this instance doesn't have a sheet reference. + /// + /// + /// the CellReference to check + /// True if the reference lies within the bounds, false otherwise. + /// @see #intersects(CellRangeAddressBase) for checking if two ranges overlap public bool IsInRange(CellReference reference) { return IsInRange(reference.Row, reference.Col); } + + /// + /// + /// Determines if the given lies within the bounds + /// of this range. + /// + /// + /// NOTE: It is up to the caller to ensure the reference is + /// for the correct sheet, since this instance doesn't have a sheet reference. + /// + /// + /// the CellAddress to check + /// True if the reference lies within the bounds, false otherwise. + /// @see #intersects(CellRangeAddressBase) for checking if two ranges overlap + public bool IsInRange(CellAddress ref1) + { + return IsInRange(ref1.Row, ref1.Column); + } + + /// + /// + /// Determines if the given lies within the bounds + /// of this range. + /// + /// + /// NOTE: It is up to the caller to ensure the reference is + /// for the correct sheet, since this instance doesn't have a sheet reference. + /// + /// + /// the Cell to check + /// True if the cell lies within the bounds, false otherwise. + /// @see #intersects(CellRangeAddressBase) for checking if two ranges overlap + public bool IsInRange(ICell cell) + { + return IsInRange(cell.RowIndex, cell.ColumnIndex); + } + public bool IsFullColumnRange { get @@ -168,19 +230,19 @@ public bool Intersects(CellRangeAddressBase other) /// public ISet GetPosition(int rowInd, int colInd) { - HashSet positions = new HashSet(); - if (rowInd > FirstRow && rowInd < LastRow && colInd > FirstColumn && colInd < LastColumn) { - positions.Add(CellPosition.INSIDE); - return positions; // entirely inside, matches no boundaries - } - // check edges - if (rowInd == FirstRow) positions.Add(CellPosition.TOP); - if (rowInd == LastRow) positions.Add(CellPosition.BOTTOM); - if (colInd == FirstColumn) positions.Add(CellPosition.LEFT); - if (colInd == LastColumn) positions.Add(CellPosition.RIGHT); - - return positions; - } + HashSet positions = new HashSet(); + if (rowInd > FirstRow && rowInd < LastRow && colInd > FirstColumn && colInd < LastColumn) { + positions.Add(CellPosition.INSIDE); + return positions; // entirely inside, matches no boundaries + } + // check edges + if (rowInd == FirstRow) positions.Add(CellPosition.TOP); + if (rowInd == LastRow) positions.Add(CellPosition.BOTTOM); + if (colInd == FirstColumn) positions.Add(CellPosition.LEFT); + if (colInd == LastColumn) positions.Add(CellPosition.RIGHT); + + return positions; + } /** * @return column number for the upper left hand corner @@ -240,6 +302,7 @@ public int NumberOfCells return (_lastRow - _firstRow + 1) * (_lastCol - _firstCol + 1); } } + public override String ToString() { CellReference crA = new CellReference(_firstRow, _firstCol); @@ -299,7 +362,86 @@ public override int GetHashCode() (MaxRow << 24)); return code; } - } + + /// + /// Returns an enumerator over the CellAddresses in this cell range in row-major order. + /// + /// + public IEnumerator GetEnumerator() + { + return new RowMajorCellAddressEnumerator(this); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + private class RowMajorCellAddressEnumerator : IEnumerator + { + + private int firstRow, firstCol, lastRow, lastCol; + private int r, c; + public RowMajorCellAddressEnumerator(CellRangeAddressBase ref1) + { + r = firstRow = ref1.FirstRow; + c = firstCol = ref1.FirstColumn; + lastRow = ref1.LastRow; + lastCol = ref1.LastColumn; + + // whole row and whole column ranges currently not supported + if(firstRow < 0) + throw new InvalidOperationException("First row cannot be negative."); + if(firstCol < 0) + throw new InvalidOperationException("First column cannot be negative."); + + // avoid infinite iteration + if(firstRow > lastRow) + throw new InvalidOperationException("First row cannot be greater than last row."); + if(firstCol > lastCol) + throw new InvalidOperationException("First column cannot be greater than last column."); + } + + public CellAddress Current { get; private set; } + + object IEnumerator.Current => Current; + + public void Dispose() + { + + } + + public bool MoveNext() + { + if(r <= lastRow && c <= lastCol) + { + CellAddress addr = new CellAddress(r, c); + // row major order + if(c < lastCol) + { + c++; + } + else + { //c >= lastCol, end of row reached + c = firstCol; //CR + r++; //LF + } + Current = addr; + return true; + } + else + { + Current = null; + return false; + } + } + + public void Reset() + { + throw new InvalidOperationException(); + } + } + +} /// /// Indicates a cell or range is in the given relative position in a range. diff --git a/main/SS/Util/CellRangeUtil.cs b/main/SS/Util/CellRangeUtil.cs index 22fdfb4a2..3d2c4003a 100644 --- a/main/SS/Util/CellRangeUtil.cs +++ b/main/SS/Util/CellRangeUtil.cs @@ -126,6 +126,7 @@ private static List MergeCellRanges(List cel } somethingGotMerged = true; // overwrite range1 with first result + range1 = mergeResult[0]; cellRangeList[i] = mergeResult[0]; // remove range2 cellRangeList.RemoveAt(j--); diff --git a/ooxml/XSSF/UserModel/Extensions/XSSFCellAlignment.cs b/ooxml/XSSF/UserModel/Extensions/XSSFCellAlignment.cs index 68d70fa17..5d6089812 100644 --- a/ooxml/XSSF/UserModel/Extensions/XSSFCellAlignment.cs +++ b/ooxml/XSSF/UserModel/Extensions/XSSFCellAlignment.cs @@ -78,6 +78,22 @@ public HorizontalAlignment Horizontal } } + public ReadingOrder ReadingOrder + { + get + { + if(cellAlignement != null && cellAlignement.readingOrderSpecified) + { + return (ReadingOrder)cellAlignement.readingOrder; + } + return ReadingOrder.CONTEXT; + } + set + { + cellAlignement.readingOrder = (long)value; + } + } + /** * Get the number of spaces to indent the text in the cell * diff --git a/ooxml/XSSF/UserModel/XSSFRow.cs b/ooxml/XSSF/UserModel/XSSFRow.cs index 3c4410735..c2e2e0f41 100644 --- a/ooxml/XSSF/UserModel/XSSFRow.cs +++ b/ooxml/XSSF/UserModel/XSSFRow.cs @@ -485,8 +485,8 @@ public void CopyRowFrom(IRow srcRow, CellCopyPolicy policy) int srcRowNum = srcRow.RowNum; int destRowNum = RowNum; int rowDifference = destRowNum - srcRowNum; - FormulaShifter shifter = FormulaShifter.CreateForRowCopy(sheetIndex, sheetName, srcRowNum, srcRowNum, rowDifference, SpreadsheetVersion.EXCEL2007); - rowShifter.UpdateRowFormulas(this, shifter); + FormulaShifter formulaShifter = FormulaShifter.CreateForRowCopy(sheetIndex, sheetName, srcRowNum, srcRowNum, rowDifference, SpreadsheetVersion.EXCEL2007); + rowShifter.UpdateRowFormulas(this, formulaShifter); // Copy merged regions that are fully contained on the row // FIXME: is this something that rowShifter could be doing? if (policy.IsCopyMergedRegions) diff --git a/ooxml/XSSF/UserModel/XSSFWorkbook.cs b/ooxml/XSSF/UserModel/XSSFWorkbook.cs index 4fcb7d3b5..e31e0e715 100644 --- a/ooxml/XSSF/UserModel/XSSFWorkbook.cs +++ b/ooxml/XSSF/UserModel/XSSFWorkbook.cs @@ -211,12 +211,7 @@ public XSSFWorkbook(OPCPackage pkg) Load(XSSFFactory.GetInstance()); // some broken Workbooks miss this... - if (!workbook.IsSetBookViews()) - { - CT_BookViews bvs = workbook.AddNewBookViews(); - CT_BookView bv = bvs.AddNewWorkbookView(); - bv.activeTab = (0); - } + SetBookViewsIfMissing(); } /** * Constructs a XSSFWorkbook object, by buffering the whole stream into memory @@ -233,20 +228,8 @@ public XSSFWorkbook(OPCPackage pkg) * */ public XSSFWorkbook(Stream fileStream, bool readOnly = false) - : base(PackageHelper.Open(fileStream, readOnly)) + : this(PackageHelper.Open(fileStream, readOnly)) { - BeforeDocumentRead(); - - //build a tree of POIXMLDocumentParts, this workbook being the root - Load(XSSFFactory.GetInstance()); - - // some broken Workbooks miss this... - if (!workbook.IsSetBookViews()) - { - CT_BookViews bvs = workbook.AddNewBookViews(); - CT_BookView bv = bvs.AddNewWorkbookView(); - bv.activeTab = (0); - } } /** @@ -447,9 +430,7 @@ private void OnWorkbookCreate() CT_WorkbookPr workbookPr = workbook.AddNewWorkbookPr(); workbookPr.date1904 = (false); - CT_BookViews bvs = workbook.AddNewBookViews(); - CT_BookView bv = bvs.AddNewWorkbookView(); - bv.activeTab = 0; + SetBookViewsIfMissing(); workbook.AddNewSheets(); ExtendedProperties expProps = GetProperties().ExtendedProperties; @@ -477,6 +458,15 @@ private void OnWorkbookCreate() pivotTables = new List(); } + private void SetBookViewsIfMissing() + { + if(!workbook.IsSetBookViews()) + { + CT_BookViews bvs = workbook.AddNewBookViews(); + CT_BookView bv = bvs.AddNewWorkbookView(); + bv.activeTab = 0; + } + } /** * Create a new SpreadsheetML namespace and Setup the default minimal content */ diff --git a/testcases/main/HSSF/UserModel/TestHSSFOptimiser.cs b/testcases/main/HSSF/UserModel/TestHSSFOptimiser.cs index 149c43a36..f8285c6f8 100644 --- a/testcases/main/HSSF/UserModel/TestHSSFOptimiser.cs +++ b/testcases/main/HSSF/UserModel/TestHSSFOptimiser.cs @@ -329,5 +329,401 @@ public void TestOptimiseStylesCheckActualStyles() ClassicAssert.AreEqual(BorderStyle.DashDot, r.GetCell(1).CellStyle.BorderBottom); ClassicAssert.AreEqual(BorderStyle.Thick, r.GetCell(2).CellStyle.BorderBottom); } + + [Test] + public void TestColumnAndRowStyles() + { + HSSFWorkbook wb = new HSSFWorkbook(); + ClassicAssert.AreEqual(21, wb.NumCellStyles, + "Usually we have 21 pre-defined styles in a newly created Workbook, see InternalWorkbook.CreateWorkbook()"); + + HSSFSheet sheet = wb.CreateSheet() as HSSFSheet; + + IRow row = sheet.CreateRow(0); + row.CreateCell(0); + row.CreateCell(1); + row.RowStyle = CreateColorStyle(wb, IndexedColors.Red); + + row = sheet.CreateRow(1); + row.CreateCell(0); + row.CreateCell(1); + row.RowStyle = CreateColorStyle(wb, IndexedColors.Red); + + sheet.SetDefaultColumnStyle(0, CreateColorStyle(wb, IndexedColors.Red)); + sheet.SetDefaultColumnStyle(1, CreateColorStyle(wb, IndexedColors.Red)); + + // now the color should be equal for those two columns and rows + CheckColumnStyles(sheet, 0, 1, false); + CheckRowStyles(sheet, 0, 1, false); + + // Optimise styles + HSSFOptimiser.OptimiseCellStyles(wb); + + // We should have the same style-objects for these two columns and rows + CheckColumnStyles(sheet, 0, 1, true); + CheckRowStyles(sheet, 0, 1, true); + } + + [Test] + public void TestUnusedStyle() + { + HSSFWorkbook wb = new HSSFWorkbook(); + ClassicAssert.AreEqual(21, wb.NumCellStyles, + "Usually we have 21 pre-defined styles in a newly created Workbook, see InternalWorkbook.CreateWorkbook()"); + + HSSFSheet sheet = wb.CreateSheet() as HSSFSheet; + + IRow row = sheet.CreateRow(0); + row.CreateCell(0); + row.CreateCell(1).CellStyle = CreateColorStyle(wb, IndexedColors.Green); + + + row = sheet.CreateRow(1); + row.CreateCell(0); + row.CreateCell(1).CellStyle = CreateColorStyle(wb, IndexedColors.Red); + + + // Create style. But don't use it. + for(int i = 0; i < 3; i++) + { + // Set Cell Color : AQUA + CreateColorStyle(wb, IndexedColors.Aqua); + } + + ClassicAssert.AreEqual(21 + 2 + 3, wb.NumCellStyles); + ClassicAssert.AreEqual(IndexedColors.Green.Index, sheet.GetRow(0).GetCell(1).CellStyle.FillForegroundColor); + ClassicAssert.AreEqual(IndexedColors.Red.Index, sheet.GetRow(1).GetCell(1).CellStyle.FillForegroundColor); + + // Optimise styles + HSSFOptimiser.OptimiseCellStyles(wb); + + ClassicAssert.AreEqual(21 + 2, wb.NumCellStyles); + ClassicAssert.AreEqual(IndexedColors.Green.Index, sheet.GetRow(0).GetCell(1).CellStyle.FillForegroundColor); + ClassicAssert.AreEqual(IndexedColors.Red.Index, sheet.GetRow(1).GetCell(1).CellStyle.FillForegroundColor); + } + + [Test] + public void TestUnusedStyleOneUsed() + { + HSSFWorkbook wb = new HSSFWorkbook(); + ClassicAssert.AreEqual(21, wb.NumCellStyles, + "Usually we have 21 pre-defined styles in a newly created Workbook, see InternalWorkbook.CreateWorkbook()"); + + HSSFSheet sheet = wb.CreateSheet() as HSSFSheet; + + IRow row = sheet.CreateRow(0); + row.CreateCell(0); + row.CreateCell(1).CellStyle = CreateColorStyle(wb, IndexedColors.Green); + + // Create style. But don't use it. + for(int i = 0; i < 3; i++) + { + // Set Cell Color : AQUA + CreateColorStyle(wb, IndexedColors.Aqua); + } + + row = sheet.CreateRow(1); + row.CreateCell(0).CellStyle = CreateColorStyle(wb, IndexedColors.Aqua); + row.CreateCell(1).CellStyle = CreateColorStyle(wb, IndexedColors.Red); + + ClassicAssert.AreEqual(21 + 3 + 3, wb.NumCellStyles); + ClassicAssert.AreEqual(IndexedColors.Green.Index, sheet.GetRow(0).GetCell(1).CellStyle.FillForegroundColor); + ClassicAssert.AreEqual(IndexedColors.Aqua.Index, sheet.GetRow(1).GetCell(0).CellStyle.FillForegroundColor); + ClassicAssert.AreEqual(IndexedColors.Red.Index, sheet.GetRow(1).GetCell(1).CellStyle.FillForegroundColor); + + // Optimise styles + HSSFOptimiser.OptimiseCellStyles(wb); + + ClassicAssert.AreEqual(21 + 3, wb.NumCellStyles); + ClassicAssert.AreEqual(IndexedColors.Green.Index, sheet.GetRow(0).GetCell(1).CellStyle.FillForegroundColor); + ClassicAssert.AreEqual(IndexedColors.Aqua.Index, sheet.GetRow(1).GetCell(0).CellStyle.FillForegroundColor); + ClassicAssert.AreEqual(IndexedColors.Red.Index, sheet.GetRow(1).GetCell(1).CellStyle.FillForegroundColor); + } + + [Test] + public void TestDefaultColumnStyleWitoutCell() + { + HSSFWorkbook wb = new HSSFWorkbook(); + ClassicAssert.AreEqual(21, wb.NumCellStyles, + "Usually we have 21 pre-defined styles in a newly created Workbook, see InternalWorkbook.CreateWorkbook()"); + + HSSFSheet sheet = wb.CreateSheet() as HSSFSheet; + + //Set CellStyle and RowStyle and ColumnStyle + for(int i = 0; i < 2; i++) + { + sheet.CreateRow(i); + } + + // Create a test font and style, and use them + int obj_cnt = wb.NumCellStyles; + int cnt = wb.NumCellStyles; + + // Set Column Color : Red + sheet.SetDefaultColumnStyle(3, + CreateColorStyle(wb, IndexedColors.Red)); + obj_cnt++; + + // Set Column Color : Red + sheet.SetDefaultColumnStyle(4, + CreateColorStyle(wb, IndexedColors.Red)); + obj_cnt++; + + ClassicAssert.AreEqual(obj_cnt, wb.NumCellStyles); + + // now the color should be equal for those two columns and rows + CheckColumnStyles(sheet, 3, 4, false); + + // Optimise styles + HSSFOptimiser.OptimiseCellStyles(wb); + + // We should have the same style-objects for these two columns and rows + CheckColumnStyles(sheet, 3, 4, true); + + // (GREEN + RED + BLUE + CORAL) + YELLOW(2*2) + ClassicAssert.AreEqual(cnt + 1, wb.NumCellStyles); + } + + [Test] + public void TestUserDefinedStylesAreNeverOptimizedAway() + { + HSSFWorkbook wb = new HSSFWorkbook(); + ClassicAssert.AreEqual(21, wb.NumCellStyles, + "Usually we have 21 pre-defined styles in a newly created Workbook, see InternalWorkbook.CreateWorkbook()"); + + HSSFSheet sheet = wb.CreateSheet() as HSSFSheet; + + //Set CellStyle and RowStyle and ColumnStyle + for(int i = 0; i < 2; i++) + { + sheet.CreateRow(i); + } + + // Create a test font and style, and use them + int obj_cnt = wb.NumCellStyles; + int cnt = wb.NumCellStyles; + for(int i = 0; i < 3; i++) + { + HSSFCellStyle s1 = null; + if(i == 0) + { + // Set cell color : +2(user style + proxy of it) + s1 = (HSSFCellStyle) CreateColorStyle(wb, IndexedColors.Yellow); + s1.UserStyleName = "user define"; + obj_cnt += 2; + } + + HSSFRow row = sheet.GetRow(1) as HSSFRow; + row.CreateCell(i).CellStyle = s1; + } + + // Create style. But don't use it. + for(int i = 3; i < 6; i++) + { + // Set Cell Color : AQUA + CreateColorStyle(wb, IndexedColors.Aqua); + obj_cnt++; + } + + // Set cell color : +2(user style + proxy of it) + HSSFCellStyle s = (HSSFCellStyle) CreateColorStyle(wb,IndexedColors.Yellow); + s.UserStyleName = "user define2"; + obj_cnt += 2; + + sheet.CreateRow(10).CreateCell(0).CellStyle = s; + + ClassicAssert.AreEqual(obj_cnt, wb.NumCellStyles); + + // Confirm user style name + CheckUserStyles(sheet); + + // Optimise styles + HSSFOptimiser.OptimiseCellStyles(wb); + + // Confirm user style name + CheckUserStyles(sheet); + + // (GREEN + RED + BLUE + CORAL) + YELLOW(2*2) + ClassicAssert.AreEqual(cnt + 2 * 2, wb.NumCellStyles); + } + + [Test] + public void TestBug57517() + { + HSSFWorkbook wb = new HSSFWorkbook(); + ClassicAssert.AreEqual(21, wb.NumCellStyles, + "Usually we have 21 pre-defined styles in a newly created Workbook, see InternalWorkbook.CreateWorkbook()"); + + HSSFSheet sheet = wb.CreateSheet() as HSSFSheet; + + //Set CellStyle and RowStyle and ColumnStyle + for(int i = 0; i < 2; i++) + { + sheet.CreateRow(i); + } + + // Create a test font and style, and use them + int obj_cnt = wb.NumCellStyles; + int cnt = wb.NumCellStyles; + for(int i = 0; i < 3; i++) + { + // Set Cell Color : GREEN + HSSFRow row = sheet.GetRow(0) as HSSFRow; + row.CreateCell(i).CellStyle = CreateColorStyle(wb, IndexedColors.Green); + obj_cnt++; + + // Set Column Color : Red + sheet.SetDefaultColumnStyle(i + 3, CreateColorStyle(wb, IndexedColors.Red)); + obj_cnt++; + + // Set Row Color : Blue + row = sheet.CreateRow(i + 3) as HSSFRow; + row.RowStyle = CreateColorStyle(wb, IndexedColors.Blue); + obj_cnt++; + + HSSFCellStyle s1 = null; + if(i == 0) + { + // Set cell color : +2(user style + proxy of it) + s1 = (HSSFCellStyle) CreateColorStyle(wb, IndexedColors.Yellow); + s1.UserStyleName = "user define"; + obj_cnt += 2; + } + + row = sheet.GetRow(1) as HSSFRow; + row.CreateCell(i).CellStyle = s1; + + } + + // Create style. But don't use it. + for(int i = 3; i < 6; i++) + { + // Set Cell Color : AQUA + CreateColorStyle(wb, IndexedColors.Aqua); + obj_cnt++; + } + + // Set CellStyle and RowStyle and ColumnStyle + for(int i = 9; i < 11; i++) + { + sheet.CreateRow(i); + } + + //Set 0 or 255 index of ColumnStyle. + HSSFCellStyle s = (HSSFCellStyle) CreateColorStyle(wb, IndexedColors.Coral); + obj_cnt++; + sheet.SetDefaultColumnStyle(0, s); + sheet.SetDefaultColumnStyle(255, s); + + // Create a test font and style, and use them + for(int i = 3; i < 6; i++) + { + // Set Cell Color : GREEN + HSSFRow row = sheet.GetRow(0 + 9) as HSSFRow; + row.CreateCell(i - 3).CellStyle = CreateColorStyle(wb, IndexedColors.Green); + obj_cnt++; + + // Set Column Color : Red + sheet.SetDefaultColumnStyle(i + 3, + CreateColorStyle(wb, IndexedColors.Red)); + obj_cnt++; + + // Set Row Color : Blue + row = sheet.CreateRow(i + 3) as HSSFRow; + row.RowStyle = CreateColorStyle(wb, IndexedColors.Blue); + obj_cnt++; + + if(i == 3) + { + // Set cell color : +2(user style + proxy of it) + s = (HSSFCellStyle) CreateColorStyle(wb, + IndexedColors.Yellow); + s.UserStyleName = "user define2"; + obj_cnt += 2; + } + + row = sheet.GetRow(1 + 9) as HSSFRow; + row.CreateCell(i - 3).CellStyle = s; + } + + ClassicAssert.AreEqual(obj_cnt, wb.NumCellStyles); + + // now the color should be equal for those two columns and rows + CheckColumnStyles(sheet, 3, 4, false); + CheckRowStyles(sheet, 3, 4, false); + + // Confirm user style name + CheckUserStyles(sheet); + + // out = new FileOutputStream(new File(tmpDirName, "out.xls")); + // wb.write(out); + // out.Close(); + + // Optimise styles + HSSFOptimiser.OptimiseCellStyles(wb); + + // out = new FileOutputStream(new File(tmpDirName, "out_optimised.xls")); + // wb.write(out); + // out.Close(); + + // We should have the same style-objects for these two columns and rows + CheckColumnStyles(sheet, 3, 4, true); + CheckRowStyles(sheet, 3, 4, true); + + // Confirm user style name + CheckUserStyles(sheet); + + // (GREEN + RED + BLUE + CORAL) + YELLOW(2*2) + ClassicAssert.AreEqual(cnt + 4 + 2 * 2, wb.NumCellStyles); + } + + private void CheckUserStyles(HSSFSheet sheet) + { + HSSFCellStyle parentStyle1 = (sheet.GetRow(1).GetCell(0).CellStyle as HSSFCellStyle).ParentStyle; + ClassicAssert.IsNotNull(parentStyle1); + ClassicAssert.AreEqual(parentStyle1.UserStyleName, "user define"); + + HSSFCellStyle parentStyle10 = (sheet.GetRow(10).GetCell(0).CellStyle as HSSFCellStyle).ParentStyle; + ClassicAssert.IsNotNull(parentStyle10); + ClassicAssert.AreEqual(parentStyle10.UserStyleName, "user define2"); + } + + private void CheckColumnStyles(HSSFSheet sheet, int col1, int col2, bool checkEquals) + { + // we should have the same color for the column styles + HSSFCellStyle columnStyle1 = sheet.GetColumnStyle(col1) as HSSFCellStyle; + ClassicAssert.IsNotNull(columnStyle1); + HSSFCellStyle columnStyle2 = sheet.GetColumnStyle(col2) as HSSFCellStyle; + ClassicAssert.IsNotNull(columnStyle2); + ClassicAssert.AreEqual(columnStyle1.FillForegroundColor, columnStyle2.FillForegroundColor); + if(checkEquals) + { + ClassicAssert.AreEqual(columnStyle1.Index, columnStyle2.Index); + ClassicAssert.AreEqual(columnStyle1, columnStyle2); + } + } + + private void CheckRowStyles(HSSFSheet sheet, int row1, int row2, bool checkEquals) + { + // we should have the same color for the row styles + HSSFCellStyle rowStyle1 = sheet.GetRow(row1).RowStyle as HSSFCellStyle; + ClassicAssert.IsNotNull(rowStyle1); + HSSFCellStyle rowStyle2 = sheet.GetRow(row2).RowStyle as HSSFCellStyle; + ClassicAssert.IsNotNull(rowStyle2); + ClassicAssert.AreEqual(rowStyle1.FillForegroundColor, rowStyle2.FillForegroundColor); + if(checkEquals) + { + ClassicAssert.AreEqual(rowStyle1.Index, rowStyle2.Index); + ClassicAssert.AreEqual(rowStyle1, rowStyle2); + } + } + + private ICellStyle CreateColorStyle(IWorkbook wb, IndexedColors c) + { + ICellStyle cs = wb.CreateCellStyle(); + cs.FillPattern = FillPattern.SolidForeground; + cs.FillForegroundColor = c.Index; + return cs; + } } } \ No newline at end of file diff --git a/testcases/main/SS/Util/TestCellRangeAddress.cs b/testcases/main/SS/Util/TestCellRangeAddress.cs index 772c8573d..b60c81e4b 100644 --- a/testcases/main/SS/Util/TestCellRangeAddress.cs +++ b/testcases/main/SS/Util/TestCellRangeAddress.cs @@ -15,11 +15,14 @@ the License. You may obtain a copy of the License at limitations under the License. ==================================================================== */ using NPOI.SS.Util; -using NUnit.Framework;using NUnit.Framework.Legacy; +using NUnit.Framework; +using NUnit.Framework.Legacy; using TestCases.HSSF.Record; using NPOI.Util; using System.IO; using System; +using System.Collections; +using System.Collections.Generic; namespace TestCases.SS.Util { //import java.io.ByteArrayOutputStream; @@ -211,12 +214,14 @@ public void TestEquals() // Invert first/last row, but refer to same area ref2.FirstRow = (2); ref2.LastRow = (1); - ClassicAssert.AreEqual(ref1, ref2); + //ClassicAssert.AreEqual(ref1, ref2); + ClassicAssert.True(ref1.Equals(ref2)); // Invert first/last column, but refer to same area ref2.FirstColumn = (4); ref2.LastColumn = (3); - ClassicAssert.AreEqual(ref1, ref2); + //ClassicAssert.AreEqual(ref1, ref2); + ClassicAssert.True(ref1.Equals(ref2)); // Refer to a different area ClassicAssert.AreNotEqual(ref1, new CellRangeAddress(3, 4, 1, 2)); @@ -292,7 +297,49 @@ public void ContainsColumn() ClassicAssert.IsFalse(region.ContainsColumn(6)); } - + [Test] + public void TestIterator() + { + CellRangeAddress A1_B2 = new CellRangeAddress(0, 1, 0, 1); + + // the cell address iterator iterates in row major order + IEnumerator iter = A1_B2.GetEnumerator(); + iter.MoveNext(); + ClassicAssert.AreEqual(new CellAddress(0, 0), iter.Current, "A1"); + iter.MoveNext(); + ClassicAssert.AreEqual(new CellAddress(0, 1), iter.Current, "B1"); + iter.MoveNext(); + ClassicAssert.AreEqual(new CellAddress(1, 0), iter.Current, "A2"); + iter.MoveNext(); + ClassicAssert.AreEqual(new CellAddress(1, 1), iter.Current, "B2"); + + ClassicAssert.IsFalse(iter.MoveNext()); + //try + //{ + // iter.next(); + // Assert.Fail("Expected NoSuchElementException"); + //} + //catch(NoSuchElementException e) { + // //expected + //} + //try + //{ + // iter.remove(); + // Assert.Fail("Expected UnsupportedOperationException"); + //} + //catch(UnsupportedOperationException e) { + // //expected + //} + + // for each interface + int count = 0; + foreach(CellAddress addr in A1_B2) + { + ClassicAssert.IsNotNull(addr); + count++; + } + ClassicAssert.AreEqual(4, count); + } private static void assertIntersects(CellRangeAddress regionA, CellRangeAddress regionB) { diff --git a/testcases/main/SS/Util/TestCellRangeUtil.cs b/testcases/main/SS/Util/TestCellRangeUtil.cs new file mode 100644 index 000000000..34b3318e2 --- /dev/null +++ b/testcases/main/SS/Util/TestCellRangeUtil.cs @@ -0,0 +1,114 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + + +using NPOI.SS.Util; +using NPOI.Util; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace TestCases.SS.Util +{ + + /// + /// + /// Tests CellRangeUtil. + /// + /// + /// + /// + /// + [TestFixture] + public sealed class TestCellRangeUtil + { + + private static CellRangeAddress A1 = new CellRangeAddress(0, 0, 0, 0); + private static CellRangeAddress B1 = new CellRangeAddress(0, 0, 1, 1); + private static CellRangeAddress A2 = new CellRangeAddress(1, 1, 0, 0); + private static CellRangeAddress B2 = new CellRangeAddress(1, 1, 1, 1); + private static CellRangeAddress A1_B2 = new CellRangeAddress(0, 1, 0, 1); + private static CellRangeAddress A1_B1 = new CellRangeAddress(0, 0, 0, 1); + private static CellRangeAddress A1_A2 = new CellRangeAddress(0, 1, 0, 0); + + [Test] + public void TestMergeCellRanges() + { + // Note that the order of the output array elements does not matter + // And that there may be more than one valid outputs for a given input. Any valid output is accepted. + // POI should use a strategy that is consistent and predictable (it currently is not). + + // Fully mergeable + // A B + // 1 x x A1,A2,B1,B2 --> A1:B2 + // 2 x x + AssertCellRangesEqual(AsArray(A1_B2), Merge(A1, B1, A2, B2)); + AssertCellRangesEqual(AsArray(A1_B2), Merge(A1, B2, A2, B1)); + + // Partially mergeable: multiple possible merges + // A B + // 1 x x A1,A2,B1 --> A1:B1,A2 or A1:A2,B1 + // 2 x + AssertCellRangesEqual(AsArray(A1_B1, A2), Merge(A1, B1, A2)); + AssertCellRangesEqual(AsArray(A1_A2, B1), Merge(A2, A1, B1)); + AssertCellRangesEqual(AsArray(A1_B1, A2), Merge(B1, A2, A1)); + + // Not mergeable + // A B + // 1 x A1,B2 --> A1,B2 + // 2 x + AssertCellRangesEqual(AsArray(A1, B2), Merge(A1, B2)); + AssertCellRangesEqual(AsArray(B2, A1), Merge(B2, A1)); + } + + private void AssertCellRangesEqual(CellRangeAddress[] a, CellRangeAddress[] b) + { + ClassicAssert.AreEqual(GetCellAddresses(a), GetCellAddresses(b)); + CollectionAssert.AreEquivalent(a, b); + //assertArrayEquals(a, b); + } + + private static HashSet GetCellAddresses(CellRangeAddress[] ranges) + { + HashSet set = new HashSet(); + foreach(CellRangeAddress range in ranges) + { + foreach(var ca in range) + { + set.Add(ca); + } + } + return set; + } + + private static CellRangeAddress[] AsArray(params CellRangeAddress[] ts) + { + return ts; + } + + private static CellRangeAddress[] Merge(params CellRangeAddress[] ranges) + { + return CellRangeUtil.MergeCellRanges(ranges); + } + } +} + + diff --git a/testcases/ooxml/XSSF/EventUserModel/TestXSSFReader.cs b/testcases/ooxml/XSSF/EventUserModel/TestXSSFReader.cs index 6149c4c94..168f5b263 100644 --- a/testcases/ooxml/XSSF/EventUserModel/TestXSSFReader.cs +++ b/testcases/ooxml/XSSF/EventUserModel/TestXSSFReader.cs @@ -26,12 +26,14 @@ namespace TestCases.XSSF.EventUserModel { using NPOI; using NPOI.OpenXml4Net.OPC; + using NPOI.SS.UserModel; using NPOI.Util; using NPOI.XSSF; using NPOI.XSSF.EventUserModel; using NPOI.XSSF.Model; using NPOI.XSSF.UserModel; using NUnit.Framework; + using NUnit.Framework.Internal; using NUnit.Framework.Legacy; @@ -348,6 +350,20 @@ public void Test61034() } pkg.Close(); } + [Test] + [Ignore("until we fix issue https://bz.apache.org/bugzilla/show_bug.cgi?id=61701")] + public void Test61701() + { + XSSFWorkbook workbook = XSSFTestDataSamples.OpenSampleWorkbook("simple-table-named-range.xlsx"); + try + { + IName name = workbook.GetName("total"); + Console.WriteLine("workbook.getName(\"total\").getSheetName() returned: " + name.SheetName); + } + catch(Exception) { + workbook.Close(); + } + } } } diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFCellStyle.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFCellStyle.cs index 6b47e6636..18ec31d01 100644 --- a/testcases/ooxml/XSSF/UserModel/TestXSSFCellStyle.cs +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFCellStyle.cs @@ -770,15 +770,19 @@ public void TestGetSetAlignement() public void TestGetSetReadingOrder() { ClassicAssert.AreEqual(ReadingOrder.CONTEXT, cellStyle.ReadingOrder); + ClassicAssert.AreEqual((long)ReadingOrder.CONTEXT, cellStyle.GetCellAlignment().GetCTCellAlignment().readingOrder); cellStyle.ReadingOrder = ReadingOrder.LEFT_TO_RIGHT; ClassicAssert.AreEqual(ReadingOrder.LEFT_TO_RIGHT, cellStyle.ReadingOrder); + ClassicAssert.AreEqual((long) ReadingOrder.LEFT_TO_RIGHT, cellStyle.GetCellAlignment().GetCTCellAlignment().readingOrder); cellStyle.ReadingOrder=ReadingOrder.RIGHT_TO_LEFT; ClassicAssert.AreEqual(ReadingOrder.RIGHT_TO_LEFT, cellStyle.ReadingOrder); + ClassicAssert.AreEqual((long) ReadingOrder.RIGHT_TO_LEFT, cellStyle.GetCellAlignment().GetCTCellAlignment().readingOrder); cellStyle.ReadingOrder = ReadingOrder.CONTEXT; ClassicAssert.AreEqual(ReadingOrder.CONTEXT, cellStyle.ReadingOrder); + ClassicAssert.AreEqual((long) ReadingOrder.CONTEXT, cellStyle.GetCellAlignment().GetCTCellAlignment().readingOrder); } [Test] public void TestGetSetVerticalAlignment() diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFComment.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFComment.cs index ea9ae2130..57aef6af3 100644 --- a/testcases/ooxml/XSSF/UserModel/TestXSSFComment.cs +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFComment.cs @@ -15,8 +15,6 @@ the License. You may obtain a copy of the License at limitations under the License. ==================================================================== */ -using System; -using System.IO; using NPOI.HSSF.UserModel; using NPOI.OpenXmlFormats.Spreadsheet; using NPOI.OpenXmlFormats.Vml; @@ -26,7 +24,11 @@ limitations under the License. using NPOI.XSSF.Model; using NPOI.XSSF.Streaming; using NPOI.XSSF.UserModel; -using NUnit.Framework;using NUnit.Framework.Legacy; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System; +using System.IO; +using System.Xml.Linq; using TestCases.SS.UserModel; namespace TestCases.XSSF.UserModel @@ -295,6 +297,52 @@ public void TestBug58175a() wb.Close(); } } + + [Test] + public void TestBug55814() + { + XSSFWorkbook wb = XSSFTestDataSamples.OpenSampleWorkbook("55814.xlsx"); + try + { + + int oldsheetIndex = wb.GetSheetIndex("example"); + ISheet oldsheet = wb.GetSheetAt(oldsheetIndex); + + IComment comment = oldsheet.GetRow(0).GetCell(0).CellComment; + ClassicAssert.AreEqual("Comment Here\n", comment.String.String); + + ISheet newsheet = wb.CloneSheet(oldsheetIndex); + + wb.RemoveSheetAt(oldsheetIndex); + + //wb.write(new FileOutputStream("/tmp/outnocomment.xlsx")); + + comment = newsheet.GetRow(0).GetCell(0).CellComment; + ClassicAssert.IsNotNull(comment, "Should have a comment on A1 in the new sheet"); + ClassicAssert.AreEqual("Comment Here\n", comment.String.String); + + XSSFWorkbook wbBack = XSSFTestDataSamples.WriteOutAndReadBack(wb); + ClassicAssert.IsNotNull(wbBack); + wbBack.Close(); + } + catch(Exception) + { + wb.Close(); + } + wb = XSSFTestDataSamples.OpenSampleWorkbook("55814.xlsx"); + try + { + int oldsheetIndex = wb.GetSheetIndex("example"); + ISheet newsheet = wb.GetSheetAt(oldsheetIndex); + IComment comment = newsheet.GetRow(0).GetCell(0).CellComment; + ClassicAssert.AreEqual("Comment Here\n", comment.String.String); + } + catch(Exception) + { + wb.Close(); + }; + } + [Test] public void Bug57838DeleteRowsWthCommentsBug() { diff --git a/testcases/test-data/spreadsheet/55814.xlsx b/testcases/test-data/spreadsheet/55814.xlsx new file mode 100644 index 000000000..ae6d9eccd Binary files /dev/null and b/testcases/test-data/spreadsheet/55814.xlsx differ diff --git a/testcases/test-data/spreadsheet/simple-table-named-range.xlsx b/testcases/test-data/spreadsheet/simple-table-named-range.xlsx new file mode 100644 index 000000000..877094f3e Binary files /dev/null and b/testcases/test-data/spreadsheet/simple-table-named-range.xlsx differ