diff --git a/OpenXmlFormats/Spreadsheet/Sheet/CT_Col.cs b/OpenXmlFormats/Spreadsheet/Sheet/CT_Col.cs index ccbeb90c9..0a89aac12 100644 --- a/OpenXmlFormats/Spreadsheet/Sheet/CT_Col.cs +++ b/OpenXmlFormats/Spreadsheet/Sheet/CT_Col.cs @@ -37,8 +37,8 @@ public class CT_Col private byte outlineLevelField; - private bool collapsedField = true; - private bool collapsedSpecifiedField = true; + private bool collapsedField = false; + private bool collapsedSpecifiedField = false; [XmlAttribute] public uint min @@ -279,7 +279,7 @@ public static CT_Col Parse(XmlNode node, XmlNamespaceManager namespaceManager) CT_Col ctObj = new CT_Col(); ctObj.min = XmlHelper.ReadUInt(node.Attributes["min"]); ctObj.max = XmlHelper.ReadUInt(node.Attributes["max"]); - ctObj.width = XmlHelper.ReadDouble(node.Attributes["width"]); + ctObj.widthField = XmlHelper.ReadDouble(node.Attributes["width"]); if (node.Attributes["style"] != null) ctObj.style = XmlHelper.ReadUInt(node.Attributes["style"]); else @@ -287,9 +287,9 @@ public static CT_Col Parse(XmlNode node, XmlNamespaceManager namespaceManager) ctObj.hidden = XmlHelper.ReadBool(node.Attributes["hidden"]); ctObj.bestFit = XmlHelper.ReadBool(node.Attributes["bestFit"]); ctObj.outlineLevel = XmlHelper.ReadByte(node.Attributes["outlineLevel"]); - ctObj.customWidth = XmlHelper.ReadBool(node.Attributes["customWidth"]); + ctObj.customWidthField = XmlHelper.ReadBool(node.Attributes["customWidth"]); ctObj.phonetic = XmlHelper.ReadBool(node.Attributes["phonetic"]); - ctObj.collapsed = XmlHelper.ReadBool(node.Attributes["collapsed"]); + ctObj.collapsedField = XmlHelper.ReadBool(node.Attributes["collapsed"]); return ctObj; } @@ -347,14 +347,79 @@ public CT_Col Copy() return col; } + /// + /// Checks if is adjacent or intersecting with + /// current column and can be combined with it. If that is the case - + /// will modify current to have + /// and of both columns. + /// + /// to combine with + /// Thrown if + /// cannot be combined with current + /// + public void CombineWith(CT_Col col) + { + if(!IsAdjacentAndCanBeCombined(col)) + { + throw new InvalidOperationException($"Columns [{this}] and " + + $"[{col}] could not be combined"); + } + + min = Math.Min(min, col.min); + max = Math.Max(max, col.max); + } + + /// + /// Checks if is adjacent or intersecting with + /// current column and can be combined with it. + /// + /// to check + /// true if is adjacent or + /// intersecting and have equal properties with current + /// ; false otherwise + public bool IsAdjacentAndCanBeCombined(CT_Col col) + { + return IsAdjacentOrIntersecting(col) && HasEqualProperties(col); + } + + private bool HasEqualProperties(CT_Col col) + { + return bestFitField == col.bestFitField + && collapsedField == col.collapsedField + && collapsedSpecifiedField == col.collapsedSpecifiedField + && customWidthField == col.customWidthField + && hiddenField == col.hiddenField + && outlineLevelField == col.outlineLevelField + && phoneticField == col.phoneticField + && styleField == col.styleField + && widthField == col.widthField + && widthSpecifiedField == col.widthSpecifiedField; + } + + private bool IsAdjacentOrIntersecting(CT_Col col) + { + return IsAdjacent(col) || IsIntersecting(col); + } + + private bool IsAdjacent(CT_Col col) + { + return min == col.max + 1 || max == col.min - 1; + } + + private bool IsIntersecting(CT_Col col) + { + return (min >= col.min && min <= col.max) || (max <= col.max && max >= col.min) || + (col.min >= min && col.min <= max) || (col.max <= max && col.max >= min); + } + public override bool Equals(object obj) { - if (obj == null) - return false; - if (!(obj is CT_Col)) + if (obj is not CT_Col col) + { return false; - CT_Col col = obj as CT_Col; - return col.min == this.min && col.max == this.max; + } + + return col.min == min && col.max == max && HasEqualProperties(col); } public override int GetHashCode() diff --git a/OpenXmlFormats/Spreadsheet/Sheet/CT_Cols.cs b/OpenXmlFormats/Spreadsheet/Sheet/CT_Cols.cs index 1fe35ef4f..46c430213 100644 --- a/OpenXmlFormats/Spreadsheet/Sheet/CT_Cols.cs +++ b/OpenXmlFormats/Spreadsheet/Sheet/CT_Cols.cs @@ -1,10 +1,9 @@ -using System; +using NPOI.SS; +using System; using System.Collections.Generic; - -using System.Text; -using System.Xml.Serialization; -using System.Xml; using System.IO; +using System.Xml; +using System.Xml.Serialization; namespace NPOI.OpenXmlFormats.Spreadsheet { @@ -53,10 +52,14 @@ public void RemoveCol(int index) } public void RemoveCols(IList toRemove) { - if (colField == null) return; + if (colField == null) + { + return; + } + foreach (CT_Col c in toRemove) { - colField.Remove(c); + _ = colField.Remove(c); } } public int sizeOfColArray() @@ -68,7 +71,6 @@ public CT_Col GetColArray(int index) return colField[index]; } - public List GetColList() { return colField; @@ -86,37 +88,115 @@ public List col } } - public static CT_Cols Parse(XmlNode node, XmlNamespaceManager namespaceManager) + public static CT_Cols Parse(XmlNode node, XmlNamespaceManager namespaceManager, int lastColumn) { if (node == null) + { return null; - CT_Cols ctObj = new CT_Cols(); - ctObj.col = new List(); + } + + CT_Cols ctObj = new CT_Cols + { + col = new List() + }; foreach (XmlNode childNode in node.ChildNodes) { if (childNode.LocalName == "col") - ctObj.col.Add(CT_Col.Parse(childNode, namespaceManager)); + { + CT_Col ctCol = CT_Col.Parse(childNode, namespaceManager); + + if (ctCol.min != ctCol.max) + { + BreakUpCtCol(ctObj, ctCol, lastColumn); + } + else + { + ctObj.col.Add(ctCol); + } + } } + return ctObj; } + /// + /// For ease of use of columns in NPOI break up s + /// that span over multiple physical columns into individual + /// s for each physical column. + /// + /// + /// + private static void BreakUpCtCol(CT_Cols ctObj, CT_Col ctCol, int lastColumn) + { + int max = ctCol.max >= SpreadsheetVersion.EXCEL2007.LastColumnIndex - 1 + ? lastColumn + : (int)ctCol.max; + for (int i = (int)ctCol.min; i <= max; i++) + { + CT_Col breakOffCtCol = ctCol.Copy(); + breakOffCtCol.min = (uint)i; + breakOffCtCol.max = (uint)i; + + ctObj.col.Add(breakOffCtCol); + } + } internal void Write(StreamWriter sw, string nodeName) { + List combinedCols = CombineCols(col); + sw.Write(string.Format("<{0}", nodeName)); sw.Write(">"); - if (this.col != null) + + if (combinedCols != null) { - foreach (CT_Col x in this.col) + foreach (CT_Col x in combinedCols) { x.Write(sw, "col"); } } + sw.Write(string.Format("", nodeName)); } + /// + /// Broken up by the method + /// s are combined into spans + /// + private static List CombineCols(List cols) + { + List combinedCols = new List(); + + cols.Sort((c1, c2) => c1.min.CompareTo(c2.min)); + + CT_Col lastCol = null; + + foreach (CT_Col col in cols) + { + if (lastCol == null) + { + lastCol = col; + continue; + } + + if (col.IsAdjacentAndCanBeCombined(lastCol)) + { + lastCol.CombineWith(col); + continue; + } + + combinedCols.Add(lastCol); + lastCol = col; + } + if (lastCol != null) + { + combinedCols.Add(lastCol); + } + + return combinedCols; + } public void SetColArray(CT_Col[] colArray) { diff --git a/OpenXmlFormats/Spreadsheet/Sheet/CT_Row.cs b/OpenXmlFormats/Spreadsheet/Sheet/CT_Row.cs index 8ecc3930c..1074690a5 100644 --- a/OpenXmlFormats/Spreadsheet/Sheet/CT_Row.cs +++ b/OpenXmlFormats/Spreadsheet/Sheet/CT_Row.cs @@ -7,6 +7,7 @@ using System.Xml; using NPOI.OpenXml4Net.Util; using System.IO; +using NPOI.SS.Util; namespace NPOI.OpenXmlFormats.Spreadsheet { @@ -45,6 +46,8 @@ public class CT_Row private bool phField; private double dyDescentField; //x14ac:dyDescent + private int lastCellField = -1; + public static CT_Row Parse(XmlNode node, XmlNamespaceManager namespaceManager) { if (node == null) @@ -68,9 +71,26 @@ public static CT_Row Parse(XmlNode node, XmlNamespaceManager namespaceManager) foreach (XmlNode childNode in node.ChildNodes) { if (childNode.LocalName == "extLst") + { ctObj.extLst = CT_ExtensionList.Parse(childNode, namespaceManager); + } else if (childNode.LocalName == "c") - ctObj.c.Add(CT_Cell.Parse(childNode, namespaceManager)); + { + CT_Cell cell = CT_Cell.Parse(childNode, namespaceManager); + ctObj.c.Add(cell); + + if (cell.r == null) + { + continue; + } + + var cellNum = new CellReference(cell.r).Col; + + if (cellNum > ctObj.lastCellField) + { + ctObj.lastCellField = cellNum; + } + } } return ctObj; } @@ -383,6 +403,17 @@ public bool ph this.phField = value; } } + + /// + /// An index of the last non-empty cell in the row + /// + public int lastCell + { + get + { + return this.lastCellField; + } + } } } diff --git a/OpenXmlFormats/Spreadsheet/Sheet/CT_SheetData.cs b/OpenXmlFormats/Spreadsheet/Sheet/CT_SheetData.cs index 4a51ebdf8..66e435ff6 100644 --- a/OpenXmlFormats/Spreadsheet/Sheet/CT_SheetData.cs +++ b/OpenXmlFormats/Spreadsheet/Sheet/CT_SheetData.cs @@ -12,6 +12,7 @@ namespace NPOI.OpenXmlFormats.Spreadsheet [XmlType(Namespace = "http://schemas.openxmlformats.org/spreadsheetml/2006/main")] public class CT_SheetData { + private int lastColumnField = 0; public static CT_SheetData Parse(XmlNode node, XmlNamespaceManager namespaceManager) { @@ -19,16 +20,24 @@ public static CT_SheetData Parse(XmlNode node, XmlNamespaceManager namespaceMana return null; CT_SheetData ctObj = new CT_SheetData(); ctObj.row = new List(); + foreach (XmlNode childNode in node.ChildNodes) { if (childNode.LocalName == "row") - ctObj.row.Add(CT_Row.Parse(childNode, namespaceManager)); + { + CT_Row row = CT_Row.Parse(childNode, namespaceManager); + ctObj.row.Add(row); + + if (row.lastCell > ctObj.lastColumnField) + { + ctObj.lastColumnField = row.lastCell; + } + } } + return ctObj; } - - internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); @@ -45,7 +54,7 @@ internal void Write(StreamWriter sw, string nodeName) - private List rowField = null; // [0..*] + private List rowField = null; // [0..*] //public CT_SheetData() //{ @@ -115,5 +124,14 @@ public bool rowSpecified { get { return null != rowField; } } + + [XmlIgnore] + public int lastColumn + { + get + { + return this.lastColumnField; + } + } } } diff --git a/OpenXmlFormats/Spreadsheet/Sheet/CT_Worksheet.cs b/OpenXmlFormats/Spreadsheet/Sheet/CT_Worksheet.cs index 78cf6949d..fec7a12b0 100644 --- a/OpenXmlFormats/Spreadsheet/Sheet/CT_Worksheet.cs +++ b/OpenXmlFormats/Spreadsheet/Sheet/CT_Worksheet.cs @@ -99,6 +99,7 @@ public static CT_Worksheet Parse(XmlNode node, XmlNamespaceManager namespaceMana CT_Worksheet ctObj = new CT_Worksheet(); ctObj.cols = new List(); ctObj.conditionalFormatting = new List(); + XmlNode cols = null; foreach (XmlNode childNode in node.ChildNodes) { if (childNode.LocalName == "sheetPr") @@ -174,10 +175,16 @@ public static CT_Worksheet Parse(XmlNode node, XmlNamespaceManager namespaceMana else if (childNode.LocalName == "extLst") ctObj.extLst = CT_ExtensionList.Parse(childNode, namespaceManager); else if (childNode.LocalName == "cols") - ctObj.cols.Add(CT_Cols.Parse(childNode, namespaceManager)); + cols = childNode; else if (childNode.LocalName == "conditionalFormatting") ctObj.conditionalFormatting.Add(CT_ConditionalFormatting.Parse(childNode, namespaceManager)); } + + if (cols != null) + { + ctObj.cols.Add(CT_Cols.Parse(cols, namespaceManager, ctObj.sheetData.lastColumn)); + } + return ctObj; } @@ -186,7 +193,8 @@ public static CT_Worksheet Parse(XmlNode node, XmlNamespaceManager namespaceMana internal void Write(Stream stream, bool leaveOpen) { StreamWriter sw = new StreamWriter(stream); - try { + try + { sw.Write(""); sw.Write(""); sw.Flush(); - } finally + } + finally { - if (!leaveOpen ) + if (!leaveOpen) { sw?.Close(); } @@ -352,7 +361,8 @@ public CT_Hyperlinks AddNewHyperlinks() } public CT_ConditionalFormatting AddNewConditionalFormatting() { - if (null == conditionalFormattingField) { conditionalFormattingField = new List(); } + if (null == conditionalFormattingField) + { conditionalFormattingField = new List(); } CT_ConditionalFormatting cf = new CT_ConditionalFormatting(); this.conditionalFormattingField.Add(cf); return cf; @@ -444,7 +454,8 @@ public void RemoveCols(int index) } public CT_Cols AddNewCols() { - if (null == colsField) { colsField = new List(); } + if (null == colsField) + { colsField = new List(); } CT_Cols newCols = new CT_Cols(); this.colsField.Add(newCols); return newCols; diff --git a/main/HSSF/UserModel/HSSFSheet.cs b/main/HSSF/UserModel/HSSFSheet.cs index d4017a8c0..5cfea2188 100644 --- a/main/HSSF/UserModel/HSSFSheet.cs +++ b/main/HSSF/UserModel/HSSFSheet.cs @@ -3373,5 +3373,10 @@ public CellAddress ActiveCell _sheet.ActiveCellCol = col; } } + + IEnumerator IEnumerable.GetEnumerator() + { + return rows.Values.GetEnumerator(); + } } } diff --git a/main/SS/Formula/FormulaShifter.cs b/main/SS/Formula/FormulaShifter.cs index a9381bff1..01ffdb0a5 100644 --- a/main/SS/Formula/FormulaShifter.cs +++ b/main/SS/Formula/FormulaShifter.cs @@ -30,7 +30,9 @@ private enum ShiftMode { RowMove, RowCopy, - SheetMove + SheetMove, + ColumnMove, + ColumnCopy } /// /// Extern sheet index of sheet where moving is occurring @@ -164,6 +166,42 @@ public static FormulaShifter CreateForRowCopy( version); } + public static FormulaShifter CreateForColumnShift( + int externSheetIndex, + string sheetName, + int firstMovedColumnIndex, + int lastMovedColumnIndex, + int numberOfColumnsToMove, + SpreadsheetVersion version) + { + return new FormulaShifter( + externSheetIndex, + sheetName, + firstMovedColumnIndex, + lastMovedColumnIndex, + numberOfColumnsToMove, + ShiftMode.ColumnMove, + version); + } + + public static FormulaShifter CreateForColumnCopy( + int externSheetIndex, + string sheetName, + int firstMovedColumnIndex, + int lastMovedColumnIndex, + int numberOfColumnsToMove, + SpreadsheetVersion version) + { + return new FormulaShifter( + externSheetIndex, + sheetName, + firstMovedColumnIndex, + lastMovedColumnIndex, + numberOfColumnsToMove, + ShiftMode.ColumnCopy, + version); + } + public static FormulaShifter CreateForSheetShift( int srcSheetIndex, int dstSheetIndex) @@ -217,6 +255,10 @@ private Ptg AdjustPtg(Ptg ptg, int currentExternSheetIx) // * row copy on same sheet // * row copy between different sheetsin the same workbook return AdjustPtgDueToRowCopy(ptg); + case ShiftMode.ColumnMove: + return AdjustPtgDueToColumnMove(ptg, currentExternSheetIx); + case ShiftMode.ColumnCopy: + return AdjustPtgDueToColumnCopy(ptg); case ShiftMode.SheetMove: return AdjustPtgDueToSheetMove(ptg); default: @@ -310,6 +352,91 @@ private Ptg AdjustPtgDueToRowMove(Ptg ptg, int currentExternSheetIx) return null; } + /// + /// + /// + /// + /// + /// in-place modified ptg (if column move would cause Ptg to + /// change), deleted ref ptg (if column move causes an error), + /// or null (if no Ptg change is needed) + private Ptg AdjustPtgDueToColumnMove(Ptg ptg, int currentExternSheetIx) + { + if (ptg is RefPtg refPtg) + { + if (currentExternSheetIx != _externSheetIndex) + { + // local refs on other sheets are unaffected + return null; + } + + return ColumnMoveRefPtg(refPtg); + } + + if (ptg is Ref3DPtg rptg) + { + if (_externSheetIndex != rptg.ExternSheetIndex) + { + // only move 3D refs that refer to the sheet with + // cells being moved (currentExternSheetIx is irrelevant) + return null; + } + + return ColumnMoveRefPtg(rptg); + } + + if (ptg is Ref3DPxg rpxg) + { + if (rpxg.ExternalWorkbookNumber > 0 || + !_sheetName.Equals(rpxg.SheetName)) + { + // only move 3D refs that refer to the sheet with cells + // being moved + return null; + } + + return ColumnMoveRefPtg(rpxg); + } + + if (ptg is Area2DPtgBase areaPtgBase) + { + if (currentExternSheetIx != _externSheetIndex) + { + // local refs on other sheets are unaffected + return ptg; + } + + return ColumnMoveAreaPtg(areaPtgBase); + } + + if (ptg is Area3DPtg aptg) + { + if (_externSheetIndex != aptg.ExternSheetIndex) + { + // only move 3D refs that refer to the sheet with cells + // being moved (currentExternSheetIx is irrelevant) + return null; + } + + return ColumnMoveAreaPtg(aptg); + } + + if (ptg is Area3DPxg apxg) + { + if (apxg.ExternalWorkbookNumber > 0 || + !_sheetName.Equals(apxg.SheetName)) + { + // only move 3D refs that refer to the sheet with cells + // being moved + return null; + } + + return ColumnMoveAreaPtg(apxg); + } + + return null; + } + /// /// Call this on any ptg reference contained in a row of cells that was /// copied. If the ptg reference is relative, the references will be @@ -362,6 +489,56 @@ private Ptg AdjustPtgDueToRowCopy(Ptg ptg) return null; } + /// + /// Call this on any ptg reference contained in a column of cells that was + /// copied. If the ptg reference is relative, the references will be + /// shifted by the distance that the columns were copied. Make sure to only call + /// AdjustPtgDueToColumnCopy on formula cells that are copied (unless column + /// shifting, where references outside of the shifted region need to be + /// updated to reflect the shift, a copy is self-contained). + /// + /// the ptg to shift + /// deleted ref ptg, in-place modified ptg, or null + /// If Ptg would be shifted off the first or last row of a sheet, + /// return deleted ref + /// If Ptg needs to be changed, modifies Ptg in-place + /// If Ptg doesn't need to be changed, returns null + /// + private Ptg AdjustPtgDueToColumnCopy(Ptg ptg) + { + if (ptg is RefPtg refPtg) + { + return ColumnCopyRefPtg(refPtg); + } + + if (ptg is Ref3DPtg rptg) + { + return ColumnCopyRefPtg(rptg); + } + + if (ptg is Ref3DPxg rpxg) + { + return ColumnCopyRefPtg(rpxg); + } + + if (ptg is Area2DPtgBase areaPtgBase) + { + return ColumnCopyAreaPtg(areaPtgBase); + } + + if (ptg is Area3DPtg aptg) + { + return ColumnCopyAreaPtg(aptg); + } + + if (ptg is Area3DPxg apxg) + { + return ColumnCopyAreaPtg(apxg); + } + + return null; + } + private Ptg AdjustPtgDueToSheetMove(Ptg ptg) { if (ptg is Ref3DPtg refPtg) @@ -407,6 +584,7 @@ private Ptg AdjustPtgDueToSheetMove(Ptg ptg) return null; } + private Ptg RowMoveRefPtg(RefPtgBase rptg) { int refRow = rptg.Row; @@ -444,6 +622,43 @@ private Ptg RowMoveRefPtg(RefPtgBase rptg) refRow + ", " + refRow + ")"); } + private Ptg ColumnMoveRefPtg(RefPtgBase rptg) + { + int refColumn = rptg.Column; + if (_firstMovedIndex <= refColumn && refColumn <= _lastMovedIndex) + { + // Columns being moved completely enclose the ref. - move the area + // ref along with the columns regardless of destination + rptg.Column = refColumn + _amountToMove; + return rptg; + } + // else rules for adjusting area may also depend on the destination + // of the moved columns + + int destFirstColumnIndex = _firstMovedIndex + _amountToMove; + int destLastColumnIndex = _lastMovedIndex + _amountToMove; + + // ref is outside source columns + // check for clashes with destination + + if (destLastColumnIndex < refColumn || refColumn < destFirstColumnIndex) + { + // destination columns are completely outside ref + return null; + } + + if (destFirstColumnIndex <= refColumn && refColumn <= destLastColumnIndex) + { + // destination columns enclose the area (possibly exactly) + return CreateDeletedRef(rptg); + } + + throw new InvalidOperationException( + "Situation not covered: (" + _firstMovedIndex + ", " + + _lastMovedIndex + ", " + _amountToMove + ", " + + refColumn + ", " + refColumn + ")"); + } + private Ptg RowMoveAreaPtg(AreaPtgBase aptg) { int aFirstRow = aptg.FirstRow; @@ -610,6 +825,172 @@ private Ptg RowMoveAreaPtg(AreaPtgBase aptg) aFirstRow + ", " + aLastRow + ")"); } + private Ptg ColumnMoveAreaPtg(AreaPtgBase aptg) + { + int aFirstColumn = aptg.FirstColumn; + int aLastColumn = aptg.LastColumn; + if (_firstMovedIndex <= aFirstColumn && aLastColumn <= _lastMovedIndex) + { + // Columns being moved completely enclose the area ref. - move the + // area ref along with the columns regardless of destination + aptg.FirstColumn = aFirstColumn + _amountToMove; + aptg.LastColumn = aLastColumn + _amountToMove; + return aptg; + } + // else rules for adjusting area may also depend on the destination + // of the moved columns + + int destFirstColumnIndex = _firstMovedIndex + _amountToMove; + int destLastColumnIndex = _lastMovedIndex + _amountToMove; + + if (aFirstColumn < _firstMovedIndex && _lastMovedIndex < aLastColumn) + { + // Columns moved were originally *completely* within the area ref + + // If the destination of the columns overlaps either the left + // or right of the area ref there will be a change + if (destFirstColumnIndex < aFirstColumn + && aFirstColumn <= destLastColumnIndex) + { + // truncate the left of the area by the moved columns + aptg.FirstColumn = destLastColumnIndex + 1; + return aptg; + } + else if (destFirstColumnIndex <= aLastColumn + && aLastColumn < destLastColumnIndex) + { + // truncate the right of the area by the moved columns + aptg.LastColumn = destFirstColumnIndex - 1; + return aptg; + } + // else - columns have moved completely outside the area ref, + // or still remain completely within the area ref + return null; // - no change to the area + } + + if (_firstMovedIndex <= aFirstColumn && aFirstColumn <= _lastMovedIndex) + { + // Columns moved include the first column of the area ref, but not + // the last column btw: (aLastColumn > _lastMovedIndex) + if (_amountToMove < 0) + { + // simple case - expand area by shifting left to the left + aptg.FirstColumn = aFirstColumn + _amountToMove; + return aptg; + } + + if (destFirstColumnIndex > aLastColumn) + { + // in this case, excel ignores the column move + return null; + } + + int newFirstColumnIx = aFirstColumn + _amountToMove; + if (destLastColumnIndex < aLastColumn) + { + // end of area is preserved (will remain exact same column) + // the left area column is moved simply + aptg.FirstColumn = newFirstColumnIx; + return aptg; + } + // else - right area column has been replaced - both area left and + // right may move now + int areaRemainingLeftColumnIx = _lastMovedIndex + 1; + if (destFirstColumnIndex > areaRemainingLeftColumnIx) + { + // old left column of area has moved deep within the area, and + // exposed a new left column + newFirstColumnIx = areaRemainingLeftColumnIx; + } + + aptg.FirstColumn = newFirstColumnIx; + aptg.LastColumn = Math.Max(aLastColumn, destLastColumnIndex); + return aptg; + } + + if (_firstMovedIndex <= aLastColumn && aLastColumn <= _lastMovedIndex) + { + // Columns moved include the last column of the area ref, but not the + // first. btw: (aFirstColumn < _firstMovedIndex) + if (_amountToMove > 0) + { + // simple case - expand area by shifting right to the right + aptg.LastColumn = aLastColumn + _amountToMove; + return aptg; + } + + if (destLastColumnIndex < aFirstColumn) + { + // in this case, excel ignores the column move + return null; + } + + int newLastColumnIx = aLastColumn + _amountToMove; + if (destFirstColumnIndex > aFirstColumn) + { + // left of area is preserved (will remain exact same column) + // the right area column is moved simply + aptg.LastColumn = newLastColumnIx; + return aptg; + } + // else - left area column has been replaced - both area left and + // right may move now + int areaRemainingRightColumnIx = _firstMovedIndex - 1; + if (destLastColumnIndex < areaRemainingRightColumnIx) + { + // old right column of area has moved left deep within the + // area, and exposed a new right column + newLastColumnIx = areaRemainingRightColumnIx; + } + + aptg.FirstColumn = Math.Min(aFirstColumn, destFirstColumnIndex); + aptg.LastColumn = newLastColumnIx; + return aptg; + } + // else source columns include none of the columns of the area ref + // check for clashes with destination + + if (destLastColumnIndex < aFirstColumn || aLastColumn < destFirstColumnIndex) + { + // destination columns are completely outside area ref + return null; + } + + if (destFirstColumnIndex <= aFirstColumn && aLastColumn <= destLastColumnIndex) + { + // destination columns enclose the area (possibly exactly) + return CreateDeletedRef(aptg); + } + + if (aFirstColumn <= destFirstColumnIndex && destLastColumnIndex <= aLastColumn) + { + // destination columns are within area ref (possibly exact on left + // or right, but not both) + return null; // - no change to area + } + + if (destFirstColumnIndex < aFirstColumn && aFirstColumn <= destLastColumnIndex) + { + // dest columns overlap left of area + // - truncate the left + aptg.FirstColumn = destLastColumnIndex + 1; + return aptg; + } + + if (destFirstColumnIndex <= aLastColumn && aLastColumn < destLastColumnIndex) + { + // dest columns overlap right of area + // - truncate the right + aptg.LastColumn = destFirstColumnIndex - 1; + return aptg; + } + + throw new InvalidOperationException( + "Situation not covered: (" + _firstMovedIndex + ", " + + _lastMovedIndex + ", " + _amountToMove + ", " + + aFirstColumn + ", " + aLastColumn + ")"); + } + /// /// Modifies rptg in-place and return a reference to rptg if the cell /// reference would move due to a row copy operation @@ -635,6 +1016,31 @@ private Ptg RowCopyRefPtg(RefPtgBase rptg) return null; } + /// + /// Modifies rptg in-place and return a reference to rptg if the cell + /// reference would move due to a column copy operation + /// + /// + /// null or {@link #RefErrorPtg} if no change was + /// made + private Ptg ColumnCopyRefPtg(RefPtgBase rptg) + { + int refColumn = rptg.Column; + if (rptg.IsColRelative) + { + int destColumnIndex = _firstMovedIndex + _amountToMove; + if (destColumnIndex < 0 || _version.LastColumnIndex < destColumnIndex) + { + return CreateDeletedRef(rptg); + } + + rptg.Column = refColumn + _amountToMove; + return rptg; + } + + return null; + } + /// /// Modifies aptg in-place and return a reference to aptg if the first /// or last row of of the Area reference would move due to a row @@ -684,6 +1090,55 @@ private Ptg RowCopyAreaPtg(AreaPtgBase aptg) return changed ? aptg : null; } + /// + /// Modifies aptg in-place and return a reference to aptg if the first + /// or last column of of the Area reference would move due to a column + /// copy operation + /// + /// + /// null or if no change + /// was made + private Ptg ColumnCopyAreaPtg(AreaPtgBase aptg) + { + bool changed = false; + + int aFirstColumn = aptg.FirstColumn; + int aLastColumn = aptg.LastColumn; + + if (aptg.IsFirstColRelative) + { + int destFirstColumnIndex = aFirstColumn + _amountToMove; + if (destFirstColumnIndex < 0 + || _version.LastColumnIndex < destFirstColumnIndex) + { + return CreateDeletedRef(aptg); + } + + aptg.FirstColumn = destFirstColumnIndex; + changed = true; + } + + if (aptg.IsLastColRelative) + { + int destLastColumnIndex = aLastColumn + _amountToMove; + if (destLastColumnIndex < 0 + || _version.LastColumnIndex < destLastColumnIndex) + { + return CreateDeletedRef(aptg); + } + + aptg.LastColumn = destLastColumnIndex; + changed = true; + } + + if (changed) + { + aptg.SortTopLeftToBottomRight(); + } + + return changed ? aptg : null; + } + private static Ptg CreateDeletedRef(Ptg ptg) { if (ptg is RefPtg) diff --git a/main/SS/UserModel/CellCopyPolicy.cs b/main/SS/UserModel/CellCopyPolicy.cs index bc41524e7..a87ecef0a 100644 --- a/main/SS/UserModel/CellCopyPolicy.cs +++ b/main/SS/UserModel/CellCopyPolicy.cs @@ -33,6 +33,9 @@ public class CellCopyPolicy public static bool DEFAULT_COPY_ROW_HEIGHT_POLICY = true; public static bool DEFAULT_CONDENSE_ROWS_POLICY = false; + // column-level policies + public static bool DEFAULT_COPY_COLUMN_WIDTH_POLICY = true; + // sheet-level policies public static bool DEFAULT_COPY_MERGED_REGIONS_POLICY = true; @@ -47,6 +50,9 @@ public class CellCopyPolicy private bool copyRowHeight = DEFAULT_COPY_ROW_HEIGHT_POLICY; private bool condenseRows = DEFAULT_CONDENSE_ROWS_POLICY; + // column-level policies + private bool copyColumnWidth = DEFAULT_COPY_COLUMN_WIDTH_POLICY; + // sheet-level policies private bool copyMergedRegions = DEFAULT_COPY_MERGED_REGIONS_POLICY; @@ -72,6 +78,8 @@ public CellCopyPolicy(CellCopyPolicy other) copyRowHeight = other.IsCopyRowHeight; condenseRows = other.IsCondenseRows; + copyColumnWidth = other.copyColumnWidth; + copyMergedRegions = other.IsCopyMergedRegions; } @@ -89,6 +97,8 @@ private CellCopyPolicy(Builder builder) copyRowHeight = builder.copyRowHeight; condenseRows = builder.condenseRows; + copyColumnWidth = builder.copyColumnWidth; + copyMergedRegions = builder.copyMergedRegions; } @@ -105,6 +115,9 @@ public class Builder internal bool copyRowHeight = DEFAULT_COPY_ROW_HEIGHT_POLICY; internal bool condenseRows = DEFAULT_CONDENSE_ROWS_POLICY; + // column-level policies + internal bool copyColumnWidth = DEFAULT_COPY_COLUMN_WIDTH_POLICY; + // sheet-level policies internal bool copyMergedRegions = DEFAULT_COPY_MERGED_REGIONS_POLICY; @@ -148,12 +161,20 @@ public Builder RowHeight(bool copyRowHeight) this.copyRowHeight = copyRowHeight; return this; } + public Builder CondenseRows(bool condenseRows) { this.condenseRows = condenseRows; return this; } + // column-level policies + public Builder ColumnWidth(bool copyColumnWidth) + { + this.copyColumnWidth = copyColumnWidth; + return this; + } + // sheet-level policies public Builder MergedRegions(bool copyMergedRegions) { @@ -176,6 +197,7 @@ public Builder CreateBuilder() .MergeHyperlink(mergeHyperlink) .RowHeight(copyRowHeight) .CondenseRows(condenseRows) + .ColumnWidth(copyColumnWidth) .MergedRegions(copyMergedRegions); return builder; } @@ -295,6 +317,24 @@ public bool IsCondenseRows } } + /* + * Column-level policies + */ + /** + * @return the copyColumnWidth + */ + public bool IsCopyColumnWidth + { + get + { + return copyColumnWidth; + } + set + { + this.copyColumnWidth = value; + } + } + /* * Sheet-level policies */ diff --git a/main/SS/UserModel/Column.cs b/main/SS/UserModel/Column.cs new file mode 100644 index 000000000..7e72c4804 --- /dev/null +++ b/main/SS/UserModel/Column.cs @@ -0,0 +1,176 @@ +/* ==================================================================== + 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 System.Collections.Generic; + +namespace NPOI.SS.UserModel +{ + /// + /// High level representation of a column of a spreadsheet. + /// + public interface IColumn : IEnumerable + { + /// + /// Use this to create new cells within the column and return it. + /// The cell that is returned is a . The type can be Changed + /// either through calling or . + /// + /// the row number this cell represents + /// a high level representation of the Created cell + /// if columnIndex is less than 0 or greater than 16384, + /// the maximum number of columns supported by the SpreadsheetML format(.xlsx) + ICell CreateCell(int rowIndex); + + /// + /// Use this to create new cells within the column and return it. + /// + /// the row number this cell represents + /// the cell's data type + /// a high level representation of the Created cell. + /// if columnIndex is less than 0 or greater than 16384, + /// the maximum number of columns supported by the SpreadsheetML format(.xlsx) + ICell CreateCell(int rowIndex, CellType type); + + /// + /// Remove the Cell from this column. + /// + /// the cell to remove + /// + void RemoveCell(ICell cell); + + /// + /// Get column number this column represents + /// + /// the column number (0 based) + int ColumnNum { get; set; } + + /// + /// Returns the cell at the given (0 based) index, + /// with the from the parent Workbook. + /// + /// + /// the cell at the given (0 based) index + ICell GetCell(int cellNum); + + /// + /// Returns the cell at the given (0 based) index, with the specified + /// + /// + /// + /// the cell at the given (0 based) index + /// if cellnum is less than 0 or the specified MissingCellPolicy is invalid + ICell GetCell(int cellNum, MissingCellPolicy policy); + + /// + /// Get the number of the first cell Contained in this column. + /// + /// short representing the first logical cell in the column, + /// or -1 if the column does not contain any cells. + short FirstCellNum { get; } + + /// + /// Gets the index of the last cell Contained in this column PLUS ONE. The result also + /// happens to be the 1-based column number of the last cell. This value can be used as a + /// standard upper bound when iterating over cells: + /// + /// short representing the last logical cell in the column PLUS ONE, + /// or -1 if the column does not contain any cells. + short LastCellNum { get; } + + /// + /// Gets the number of defined cells (NOT number of cells in the actual column!). + /// That is to say if only rows 0,4,5 have values then there would be 3. + /// + /// int representing the number of defined cells in the column. + int PhysicalNumberOfCells { get; } + + /// + /// Get whether or not to display this column with 0 width + /// + bool ZeroWidth { get; set; } + + /// + /// Get the column's width. + /// If the height is not Set, the default worksheet value is returned + /// + /// column height + double Width { get; set; } + + /// + /// Is this column formatted? Most aren't, but some columns + /// do have whole-column styles. For those that do, you + /// can get the formatting from + /// + bool IsFormatted { get; } + + /// + /// Is the column width set to best fit the content? + /// + bool IsBestFit { get; set; } + + /// + /// Returns the Sheet this column belongs to + /// + /// the Sheet that owns this column + ISheet Sheet { get; } + + /// + /// Returns the whole-column cell style. Most columns won't + /// have one of these, so will return null. Call + /// to check first. + /// + ICellStyle ColumnStyle { get; set; } + + /// + /// Remove the Cell from this column. + /// + /// the cell to remove + /// + void MoveCell(ICell cell, int newRow); + + /// + /// Copy the current column to the target column + /// + /// column index of the target column + /// the new copied column object + IColumn CopyColumnTo(int targetIndex); + + /// + /// Copy the source cell to the target cell. If the target cell exists, the new copied cell will be inserted before the existing one + /// + /// index of the source cell + /// index of the target cell + /// the new copied cell object + ICell CopyCell(int sourceIndex, int targetIndex); + + /// + /// Get cells in the column + /// + List Cells { get; } + + /// + /// Returns the columns outline level. Increased as you + /// put it into more groups (outlines), reduced as + /// you take it out of them. + /// + int OutlineLevel { get; set; } + + bool Hidden { get; set; } + + bool Collapsed { get; set; } + } +} diff --git a/main/SS/UserModel/Helpers/RowShifter.cs b/main/SS/UserModel/Helpers/RowShifter.cs index bb7adb06c..db07347fa 100644 --- a/main/SS/UserModel/Helpers/RowShifter.cs +++ b/main/SS/UserModel/Helpers/RowShifter.cs @@ -51,17 +51,13 @@ public List ShiftMergedRegions(int startRow, int endRow, int n ISet removedIndices = new HashSet(); //move merged regions completely if they fall within the new region boundaries when they are Shifted var size = sheet.NumMergedRegions; + var lastCol = sheet.Any() ? sheet.Max(r => r.LastCellNum) : 0; for (var i = 0; i < size; i++) { var merged = sheet.GetMergedRegion(i); // remove merged region that overlaps Shifting - var lastCol = sheet.GetRow(startRow) != null - ? sheet.GetRow(startRow).LastCellNum - : sheet.GetRow(endRow) != null - ? sheet.GetRow(endRow).LastCellNum - : 0; if (RemovalNeeded(merged, startRow, endRow, n, lastCol)) { removedIndices.Add(i); @@ -105,25 +101,11 @@ public List ShiftMergedRegions(int startRow, int endRow, int n // Keep in sync with {@link ColumnShifter#removalNeeded} private bool RemovalNeeded(CellRangeAddress merged, int startRow, int endRow, int n, int lastCol) { - var movedRows = endRow - startRow + 1; - // build a range of the rows that are overwritten, i.e. the target-area, but without // rows that are moved along - CellRangeAddress overwrite; - if (n > 0) - { - // area is moved down => overwritten area is [endRow + n - movedRows, endRow + n] - var firstRow = Math.Max(endRow + 1, endRow + n - movedRows); - var lastRow = endRow + n; - overwrite = new CellRangeAddress(firstRow, lastRow, 0, lastCol); - } - else - { - // area is moved up => overwritten area is [startRow + n, startRow + n + movedRows] - var firstRow = startRow + n; - var lastRow = Math.Min(startRow - 1, startRow + n + movedRows); - overwrite = new CellRangeAddress(firstRow, lastRow, 0, lastCol); - } + var firstRow = startRow + n; + var lastRow = endRow + n; + CellRangeAddress overwrite = new CellRangeAddress(firstRow, lastRow, 0, lastCol); // if the merged-region and the overwritten area intersect, we need to remove it return merged.Intersects(overwrite); diff --git a/main/SS/UserModel/Sheet.cs b/main/SS/UserModel/Sheet.cs index 3f9aba37d..da44d541a 100644 --- a/main/SS/UserModel/Sheet.cs +++ b/main/SS/UserModel/Sheet.cs @@ -82,7 +82,7 @@ public enum PanePosition : byte /// The most common type of sheet is the worksheet, which is represented as a grid of cells. Worksheet cells can /// contain text, numbers, dates, and formulas. Cells can also be formatted. /// - public interface ISheet + public interface ISheet : IEnumerable { /// diff --git a/main/SS/Util/CellUtil.cs b/main/SS/Util/CellUtil.cs index 9b2fa02af..45578a5ef 100644 --- a/main/SS/Util/CellUtil.cs +++ b/main/SS/Util/CellUtil.cs @@ -129,6 +129,30 @@ public static ICell CopyCell(IRow row, int sourceIndex, int targetIndex) return CopyCell(oldCell, newCell, sourceIndex, targetIndex); } + public static ICell CopyCell(IColumn column, int sourceIndex, int targetIndex) + { + // Grab a copy of the old/new cell + ICell oldCell = column.GetCell(sourceIndex); + + // If the old cell is null jump to next cell + if (oldCell == null) + { + return null; + } + + ICell newCell = column.GetCell(targetIndex); + if (newCell == null) //not exist + { + newCell = column.CreateCell(targetIndex); + } + else + { + //TODO:shift cells + } + + return CopyCell(oldCell, newCell, sourceIndex, targetIndex); + } + private static ICell CopyCell(ICell oldCell, ICell newCell, int sourceIndex, int targetIndex) { if (sourceIndex == targetIndex) diff --git a/ooxml/XSSF/Streaming/SXSSFSheet.cs b/ooxml/XSSF/Streaming/SXSSFSheet.cs index b6ce8057c..5357d4f95 100644 --- a/ooxml/XSSF/Streaming/SXSSFSheet.cs +++ b/ooxml/XSSF/Streaming/SXSSFSheet.cs @@ -1474,5 +1474,10 @@ public void AutoSizeRow(int row, bool useMergedCells) { throw new NotImplementedException(); } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable) _sh).GetEnumerator(); + } } } diff --git a/ooxml/XSSF/UserModel/Helpers/ColumnHelper.cs b/ooxml/XSSF/UserModel/Helpers/ColumnHelper.cs index 58fce033d..376ccf935 100644 --- a/ooxml/XSSF/UserModel/Helpers/ColumnHelper.cs +++ b/ooxml/XSSF/UserModel/Helpers/ColumnHelper.cs @@ -28,6 +28,7 @@ namespace NPOI.XSSF.UserModel.Helpers /// (the data part of a sheet). Note - within POI, we use 0 based column /// indexes, but the column defInitions in the XML are 1 based! /// + [Obsolete("Use XSSFColumn object for all things column")] public class ColumnHelper { private readonly CT_Worksheet worksheet; diff --git a/ooxml/XSSF/UserModel/Helpers/ColumnShifter.cs b/ooxml/XSSF/UserModel/Helpers/ColumnShifter.cs new file mode 100644 index 000000000..a58bac4d7 --- /dev/null +++ b/ooxml/XSSF/UserModel/Helpers/ColumnShifter.cs @@ -0,0 +1,158 @@ +/* ==================================================================== + 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.Formula; +using NPOI.SS.UserModel; +using NPOI.SS.Util; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace NPOI.XSSF.UserModel.Helpers +{ + /// + /// Helper for Shifting columns left or right + /// This abstract class exists to consolidate duplicated code between + /// XSSFColumnShifter and HSSFColumnShifter + /// + public abstract class ColumnShifter + { + protected XSSFSheet sheet; + + public ColumnShifter(XSSFSheet sh) + { + sheet = sh; + } + + /// + /// Shifts, grows, or shrinks the merged regions due to a column Shift. + /// Merged regions that are completely overlaid by Shifting will + /// be deleted. + /// + /// the column to start Shifting + /// the column to end Shifting + /// the number of columns to shift + /// an array of affected merged regions, doesn't contain + /// deleted ones + public List ShiftMergedRegions( + int startColumn, + int endColumn, + int n) + { + List shiftedRegions = new List(); + ISet removedIndices = new HashSet(); + //move merged regions completely if they fall within the new region + //boundaries when they are Shifted + int size = sheet.NumMergedRegions; + + for (int i = 0; i < size; i++) + { + CellRangeAddress merged = sheet.GetMergedRegion(i); + + // remove merged region that overlaps Shifting + if (RemovalNeeded(merged, startColumn, endColumn, n)) + { + _ = removedIndices.Add(i); + continue; + } + + bool inStart = merged.FirstColumn >= startColumn + || merged.LastColumn >= startColumn; + bool inEnd = merged.FirstColumn <= endColumn || + merged.LastColumn <= endColumn; + + //don't check if it's not within the Shifted area + if (!inStart || !inEnd) + { + continue; + } + + //only shift if the region outside the Shifted columns is not + //merged too + if (!merged.ContainsColumn(startColumn - 1) + && !merged.ContainsColumn(endColumn + 1)) + { + merged.FirstColumn += n; + merged.LastColumn += n; + //have to Remove/add it back + shiftedRegions.Add(merged); + _ = removedIndices.Add(i); + } + } + + if (removedIndices.Count != 0) + { + sheet.RemoveMergedRegions(removedIndices.ToList()); + } + + //read so it doesn't Get Shifted again + foreach (CellRangeAddress region in shiftedRegions) + { + _ = sheet.AddMergedRegion(region); + } + + return shiftedRegions; + } + + // Keep in sync with {@link ColumnShifter#removalNeeded} + private bool RemovalNeeded( + CellRangeAddress merged, + int startColumn, + int endColumn, + int n) + { + int firstColumn = startColumn + n; + int lastColumn = endColumn + n; + CellRangeAddress overwrite = + new CellRangeAddress(0, sheet.LastRowNum, firstColumn, lastColumn); + + // if the merged-region and the overwritten area intersect, + // we need to remove it + return merged.Intersects(overwrite); + } + + /// + /// Updated named ranges + /// + /// + public abstract void UpdateNamedRanges(FormulaShifter Shifter); + + /// + /// Update formulas. + /// + /// + public abstract void UpdateFormulas(FormulaShifter Shifter); + + /// + /// Update the formulas in specified column using the formula Shifting + /// policy specified by Shifter + /// + /// the column to update the formulas on + /// the formula Shifting policy + public abstract void UpdateColumnFormulas(IColumn column, FormulaShifter Shifter); + + public abstract void UpdateConditionalFormatting(FormulaShifter Shifter); + + /// + /// Shift the Hyperlink anchors (not the hyperlink text, even if the + /// hyperlink is of type LINK_DOCUMENT and refers to a cell that was + /// Shifted). Hyperlinks do not track the content they point to. + /// + /// the formula Shifting policy + public abstract void UpdateHyperlinks(FormulaShifter Shifter); + } +} diff --git a/ooxml/XSSF/UserModel/Helpers/XSSFColumnShifter.cs b/ooxml/XSSF/UserModel/Helpers/XSSFColumnShifter.cs new file mode 100644 index 000000000..618fc53b1 --- /dev/null +++ b/ooxml/XSSF/UserModel/Helpers/XSSFColumnShifter.cs @@ -0,0 +1,57 @@ +/* ==================================================================== + 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.OOXML.XSSF.UserModel.Helpers; +using NPOI.SS.Formula; +using NPOI.SS.UserModel; + +namespace NPOI.XSSF.UserModel.Helpers +{ + public class XSSFColumnShifter : ColumnShifter + { + public XSSFColumnShifter(XSSFSheet sh) + : base(sh) + { + sheet = sh; + } + + public override void UpdateConditionalFormatting(FormulaShifter formulaShifter) + { + XSSFRowColShifter.UpdateConditionalFormatting(sheet, formulaShifter); + } + + public override void UpdateFormulas(FormulaShifter formulaShifter) + { + XSSFRowColShifter.UpdateFormulas(sheet, formulaShifter); + } + + public override void UpdateHyperlinks(FormulaShifter formulaShifter) + { + XSSFRowColShifter.UpdateHyperlinks(sheet, formulaShifter); + } + + public override void UpdateNamedRanges(FormulaShifter formulaShifter) + { + XSSFRowColShifter.UpdateNamedRanges(sheet, formulaShifter); + } + + public override void UpdateColumnFormulas(IColumn column, FormulaShifter formulaShifter) + { + XSSFRowColShifter.UpdateColumnFormulas(column, formulaShifter); + } + } +} diff --git a/ooxml/XSSF/UserModel/Helpers/XSSFRowColShifter.cs b/ooxml/XSSF/UserModel/Helpers/XSSFRowColShifter.cs index 6b77d7eb6..9e780904c 100644 --- a/ooxml/XSSF/UserModel/Helpers/XSSFRowColShifter.cs +++ b/ooxml/XSSF/UserModel/Helpers/XSSFRowColShifter.cs @@ -150,7 +150,92 @@ private static string ShiftFormula(IRow row, string formula, FormulaShifter Shif catch (FormulaParseException fpe) { // Log, but don't change, rather than breaking - Console.WriteLine($"Error shifting formula on row {row.RowNum}, {fpe}"); + Console.WriteLine("Error shifting formula on row " + + row.RowNum + ", " + fpe); + return formula; + } + } + + /// + /// Update the formulas in specified column using the formula shifting + /// policy specified by shifter + /// + /// the column to update the formulas on + /// the formula shifting policy + public static void UpdateColumnFormulas(IColumn column, FormulaShifter Shifter) + { + XSSFSheet sheet = (XSSFSheet)column.Sheet; + + foreach (ICell c in column) + { + XSSFCell cell = (XSSFCell)c; + + CT_Cell ctCell = cell.GetCTCell(); + if (ctCell.IsSetF()) + { + CT_CellFormula f = ctCell.f; + string formula = f.Value; + if (formula.Length > 0) + { + string ShiftedFormula = ShiftFormula(column, formula, Shifter); + if (ShiftedFormula != null) + { + f.Value = ShiftedFormula; + if (f.t == ST_CellFormulaType.shared) + { + int si = (int)f.si; + CT_CellFormula sf = sheet.GetSharedFormula(si); + sf.Value = ShiftedFormula; + } + } + } + + if (f.isSetRef()) + { + //Range of cells which the formula applies to. + string ref1 = f.@ref; + string ShiftedRef = ShiftFormula(column, ref1, Shifter); + if (ShiftedRef != null) + { + f.@ref = ShiftedRef; + } + } + } + } + } + + /// + /// Shift a formula using the supplied FormulaShifter + /// + /// the row of the cell this formula belongs to. + /// Used to get a reference to the parent workbook. + /// the formula to shift + /// the FormulaShifter object that operates on + /// the Parsed formula tokens + /// the Shifted formula if the formula was changed, null if + /// the formula wasn't modified + private static string ShiftFormula(IColumn column, string formula, FormulaShifter Shifter) + { + ISheet sheet = column.Sheet; + IWorkbook wb = sheet.Workbook; + int sheetIndex = wb.GetSheetIndex(sheet); + XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.Create(wb); + try + { + SS.Formula.PTG.Ptg[] ptgs = + FormulaParser.Parse(formula, fpb, FormulaType.Cell, sheetIndex, -1); + string ShiftedFmla = null; + if (Shifter.AdjustFormula(ptgs, sheetIndex)) + { + ShiftedFmla = FormulaRenderer.ToFormulaString(fpb, ptgs); + } + + return ShiftedFmla; + } + catch (FormulaParseException fpe) + { + // Log, but don't change, rather than breaking + Console.WriteLine($"Error shifting formula on column {column.ColumnNum}, {fpe}"); return formula; } } @@ -246,7 +331,7 @@ public static void UpdateConditionalFormatting(ISheet sheet, FormulaShifter Shif else { refs += " " + a.FormatAsString(); - } + } } cf.sqref = refs; diff --git a/ooxml/XSSF/UserModel/XSSFCell.cs b/ooxml/XSSF/UserModel/XSSFCell.cs index a09c14cd1..ade079766 100644 --- a/ooxml/XSSF/UserModel/XSSFCell.cs +++ b/ooxml/XSSF/UserModel/XSSFCell.cs @@ -683,7 +683,12 @@ public int ColumnIndex { get { - return this._cellNum; + return _cellNum; + } + + internal set + { + _cellNum = value; } } diff --git a/ooxml/XSSF/UserModel/XSSFColumn.cs b/ooxml/XSSF/UserModel/XSSFColumn.cs new file mode 100644 index 000000000..518e346cf --- /dev/null +++ b/ooxml/XSSF/UserModel/XSSFColumn.cs @@ -0,0 +1,753 @@ +/* ==================================================================== + 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.OpenXmlFormats.Spreadsheet; +using NPOI.SS; +using NPOI.SS.Formula; +using NPOI.SS.UserModel; +using NPOI.SS.Util; +using NPOI.Util; +using NPOI.XSSF.Model; +using NPOI.XSSF.UserModel.Helpers; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace NPOI.XSSF.UserModel +{ + public class XSSFColumn : IColumn, IComparable + { + #region Private properties + private static readonly POILogger _logger = + POILogFactory.GetLogger(typeof(XSSFColumn)); + + /// + /// the xml node Containing defInition for this column + /// + private readonly CT_Col _column; + + /// + /// the parent sheet + /// + private readonly XSSFSheet _sheet; + + private readonly StylesTable _stylesSource; + #endregion + + #region Public properties + /// + /// XSSFSheet this column belongs to + /// + public ISheet Sheet + { + get + { + return _sheet; + } + } + + /// + /// Get the number of the first cell Contained in this column. + /// + /// short representing the first logical cell in the column, + /// or -1 if the column does not contain any cells. + public short FirstCellNum + { + get + { + return (short)(Cells.Count == 0 ? -1 : GetFirstKey()); + } + } + + /// + /// Gets the index of the last cell Contained in this column PLUS + /// ONE. The result also happens to be the 1-based row number of + /// the last cell. This value can be used as a standard upper bound + /// when iterating over cells: + /// + /// short representing the last logical cell in the column + /// PLUS ONE, or -1 if the column does not contain any cells. + public short LastCellNum + { + get + { + return (short)(Cells.Count == 0 ? -1 : GetLastKey() + 1); + } + } + + /// + /// Get the column's width. + /// If the width is not Set, the default worksheet value is returned, + /// See + /// + /// column width + public double Width + { + get + { + return _column.width == 0 + ? _sheet.DefaultColumnWidth + : _column.width; + } + + set + { + if (value < 0) + { + if (_column.IsSetWidth()) + { + _column.UnsetWidth(); + } + + if (_column.IsSetCustomWidth()) + { + _column.UnsetCustomWidth(); + } + } + else + { + _column.width = value; + _column.customWidth = true; + + } + } + } + + /// + /// Gets the number of defined cells (NOT number of cells in the actual + /// column!). That is to say if only rows 0,4,5 have values then + /// there would be 3. + /// + /// int representing the number of defined cells in the column. + public int PhysicalNumberOfCells + { + get + { + return Cells.Count; + } + } + + /// + /// Get column number this column represents + /// + /// the column number (0 based) + public int ColumnNum + { + get + { + return (int)_column.min - 1; + } + + set + { + int maxColumn = SpreadsheetVersion.EXCEL2007.LastColumnIndex; + if (value < 0 || value > maxColumn) + { + throw new ArgumentException("Invalid column number (" + value + + ") outside allowable range (0.." + maxColumn + ")"); + } + + // As current implementation of XSSFColumn is breaking CT_Col + // objects that span over multiple columns into individual + // columns we need to set min and max values to the same value. + _column.min = (uint)(value + 1); + _column.max = (uint)(value + 1); + } + } + + /// + /// Get whether or not to display this column with 0 width + /// + public bool ZeroWidth + { + get + { + return _column.hidden; + } + + set + { + _column.hidden = value; + } + } + + /// + /// Is this column formatted? Most aren't, but some columns + /// do have whole-column styles. For those that do, you + /// can get the formatting from + /// + public bool IsFormatted + { + get + { + return _column.IsSetStyle(); + } + } + + /// + /// Is the column width set to best fit the content? + /// + public bool IsBestFit + { + get + { + return _column.bestFit; + } + + set + { + _column.bestFit = value; + } + } + + /// + /// Returns the whole-column cell style. Most columns won't + /// have one of these, so will return null. Call + /// to check first. + /// + public ICellStyle ColumnStyle + { + get + { + return IsFormatted + && _stylesSource != null + && _stylesSource.NumCellStyles > 0 + ? _stylesSource.GetStyleAt((int)_column.style) + : (ICellStyle)null; + } + + set + { + if (value == null) + { + if (_column.IsSetStyle()) + { + _column.UnsetStyle(); + } + } + else + { + XSSFCellStyle xStyle = (XSSFCellStyle)value; + xStyle.VerifyBelongsToStylesSource(_stylesSource); + + long idx = _stylesSource.PutStyle(xStyle); + _column.style = (uint)idx; + } + + foreach (ICell cell in Cells) + { + cell.CellStyle = value; + } + } + } + + public List Cells + { + get + { + List cells = new List(); + + foreach (IRow row in _sheet.Cast()) + { + foreach (ICell cell in row.Where(c => c.ColumnIndex == ColumnNum)) + { + cells.Add(cell); + _sheet.OnReadCell((XSSFCell)cell); + } + } + + return cells; + } + } + + public int OutlineLevel + { + get + { + return _column.outlineLevel; + } + + set + { + _column.outlineLevel = (byte)value; + } + } + + public bool Hidden + { + get + { + return _column.hidden; + } + + set + { + _column.hidden = value; + } + } + + public bool Collapsed + { + get + { + return _column.collapsed; + } + + set + { + _column.collapsed = value; + } + } + #endregion + + #region Constructor + /// + /// Construct an XSSFColumn. + /// + /// the xml node Containing defInitions for this column. + /// the parent sheet. + public XSSFColumn(CT_Col column, XSSFSheet sheet) + { + _column = column; + _sheet = sheet; + + if (!column.IsSetNumber()) + { + // Certain file format writers skip the column number + // Assume no gaps, and give this the next column number + int nextColumnNum = sheet.LastColumnNum + 2; + if (nextColumnNum == 2 && sheet.PhysicalNumberOfColumns == 0) + { + nextColumnNum = 1; + } + + // As current implementation of XSSFColumn is breaking CT_Col + // objects that span over multiple columns into individual + // columns we need to set min and max values to the same value. + _column.min = (uint)nextColumnNum + 1; + _column.max = (uint)nextColumnNum + 1; + } + + _stylesSource = ((XSSFWorkbook)sheet.Workbook).GetStylesSource(); + } + #endregion + + #region Public methods + /// + /// Use this to create new cells within the column and return it. The + /// cell that is returned is a . The type + /// can be Changed either through calling + /// or . + /// + /// the row number this cell represents + /// a high level representation of the Created cell + /// if columnIndex is + /// less than 0 or greater than 16384, the maximum number of columns + /// supported by the SpreadsheetML format(.xlsx) + public ICell CreateCell(int rowIndex) + { + return CreateCell(rowIndex, CellType.Blank); + } + + /// + /// Use this to create new cells within the column and return it. + /// + /// the row number this cell represents + /// the cell's data type + /// a high level representation of the Created cell. + /// if columnIndex is + /// less than 0 or greater than 16384, the maximum number of columns + /// supported by the SpreadsheetML format(.xlsx) + public ICell CreateCell(int rowIndex, CellType type) + { + if (rowIndex > SpreadsheetVersion.EXCEL2007.LastRowIndex || + rowIndex < 0) + { + throw new ArgumentOutOfRangeException( + "Row index should be between 0 and " + + SpreadsheetVersion.EXCEL2007.LastRowIndex + ". Input was " + + rowIndex); + } + + ValidateCellType(type); + + IRow row = Sheet.GetRow(rowIndex) ?? Sheet.CreateRow(rowIndex); + ICell newCell = row.CreateCell(ColumnNum, type); + + if (IsFormatted) + { + newCell.CellStyle = ColumnStyle; + } + + return newCell; + } + + /// + /// Returns the cell at the given (0 based) index, + /// with the from the parent Workbook. + /// + /// + /// the cell at the given (0 based) index + public ICell GetCell(int cellNum) + { + return GetCell(cellNum, _sheet.Workbook.MissingCellPolicy); + } + + /// + /// Returns the cell at the given (0 based) index, with the specified + /// + /// + /// + /// + /// the cell at the given (0 based) index + /// if cellnum is less than 0 or + /// the specified MissingCellPolicy is invalid + public ICell GetCell(int cellNum, MissingCellPolicy policy) + { + if (cellNum < 0 || cellNum > SpreadsheetVersion.EXCEL2007.LastRowIndex) + { + throw new ArgumentOutOfRangeException( + "Cell number should be between 0 and " + + SpreadsheetVersion.EXCEL2007.LastRowIndex + ". Input was " + + cellNum); + } + + XSSFCell cell = (XSSFCell)RetrieveCell(cellNum); + + switch (policy) + { + case MissingCellPolicy.RETURN_NULL_AND_BLANK: + return cell; + case MissingCellPolicy.RETURN_BLANK_AS_NULL: + bool isBlank = cell != null && cell.CellType == CellType.Blank; + return isBlank ? null : cell; + case MissingCellPolicy.CREATE_NULL_AS_BLANK: + return cell ?? CreateCell(cellNum, CellType.Blank); + default: + throw new ArgumentException("Illegal policy " + policy + " (" + policy + ")"); + } + } + + /// + /// Remove the Cell from this column. + /// + /// the cell to remove + /// + public void RemoveCell(ICell cell) + { + if (cell == null) + { + throw new ArgumentException("Cell can not be null"); + } + + if (cell.ColumnIndex != ColumnNum) + { + throw new ArgumentException("Specified cell does not belong " + + "to this column"); + } + + IRow row = _sheet.GetRow(cell.RowIndex); + + row.RemoveCell(cell); + } + + /// + /// Copy the cells from srcColumn to this column If this column is not + /// a blank column, this will merge the two columns, overwriting the + /// cells in this column with the cells in srcColumn If srcColumn is + /// null, overwrite cells in destination column with blank values, + /// styles, etc per cell copy policy srcColumn may be from a different + /// sheet in the same workbook + /// + /// the column to copy from + /// the policy to determine what gets copied + public void CopyColumnFrom(IColumn srcColumn, CellCopyPolicy policy) + { + if (srcColumn == null) + { + // srcColumn is blank. Overwrite cells with blank values, + // blank styles, etc per cell copy policy + foreach (ICell destCell in this) + { + XSSFCell srcCell = null; + + ((XSSFCell)destCell).CopyCellFrom(srcCell, policy); + } + + if (policy.IsCopyMergedRegions) + { + // Remove MergedRegions in dest column + int destColumnNum = ColumnNum; + int index = 0; + HashSet indices = new HashSet(); + foreach (CellRangeAddress destRegion in Sheet.MergedRegions) + { + if (destColumnNum == destRegion.FirstColumn + && destColumnNum == destRegion.LastColumn) + { + _ = indices.Add(index); + } + + index++; + } + + (Sheet as XSSFSheet).RemoveMergedRegions(indices.ToList()); + } + + if (policy.IsCopyColumnWidth) + { + // clear row height + Width = -1; + } + } + else + { + foreach (ICell c in srcColumn) + { + XSSFCell srcCell = (XSSFCell)c; + XSSFCell destCell = + CreateCell(srcCell.RowIndex, srcCell.CellType) as XSSFCell; + destCell.CopyCellFrom(srcCell, policy); + } + + XSSFColumnShifter columnShifter = new XSSFColumnShifter(_sheet); + int sheetIndex = _sheet.Workbook.GetSheetIndex(_sheet); + string sheetName = _sheet.Workbook.GetSheetName(sheetIndex); + int srcColumnNum = srcColumn.ColumnNum; + int destColumnNum = ColumnNum; + int columnDifference = destColumnNum - srcColumnNum; + FormulaShifter shifter = FormulaShifter.CreateForColumnCopy( + sheetIndex, + sheetName, + srcColumnNum, + srcColumnNum, + columnDifference, + SpreadsheetVersion.EXCEL2007); + columnShifter.UpdateColumnFormulas(this, shifter); + + if (policy.IsCopyMergedRegions) + { + foreach (CellRangeAddress srcRegion in srcColumn.Sheet.MergedRegions) + { + if (srcColumnNum == srcRegion.FirstColumn + && srcColumnNum == srcRegion.LastColumn) + { + CellRangeAddress destRegion = srcRegion.Copy(); + destRegion.FirstColumn = destColumnNum; + destRegion.LastColumn = destColumnNum; + _ = Sheet.AddMergedRegion(destRegion); + } + } + } + + if (policy.IsCopyColumnWidth) + { + Width = srcColumn.Width; + } + } + } + + public void MoveCell(ICell cell, int newColumn) + { + throw new NotImplementedException(); + } + + public IColumn CopyColumnTo(int targetIndex) + { + return ((XSSFSheet)Sheet).CopyColumn(ColumnNum, targetIndex); + } + + public ICell CopyCell(int sourceIndex, int targetIndex) + { + return CellUtil.CopyCell(this, sourceIndex, targetIndex); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// Returns the underlying CT_Col xml node Containing all cell + /// defInitions in this column + /// + /// the underlying CT_Col xml node + public CT_Col GetCTCol() + { + return _column; + } + #endregion + + #region Internal methods + /// + /// update cell references when Shifting columns + /// + /// n the number of columns to move + internal void Shift(int n) + { + int columnNum = ColumnNum + n; + CalculationChain calcChain = + ((XSSFWorkbook)_sheet.Workbook).GetCalculationChain(); + int sheetId = (int)_sheet.sheet.sheetId; + string msg = "Column[columnNum=" + ColumnNum + "] contains cell(s) " + + "included in a multi-cell array formula. You cannot change " + + "part of an array."; + + foreach (ICell c in this) + { + XSSFCell cell = (XSSFCell)c; + + if (cell.IsPartOfArrayFormulaGroup) + { + cell.NotifyArrayFormulaChanging(msg); + } + + //remove the reference in the calculation chain + calcChain?.RemoveItem(sheetId, cell.GetReference()); + + CT_Cell ctCell = cell.GetCTCell(); + string r = new CellReference(cell.RowIndex, columnNum) + .FormatAsString(); + ctCell.r = r; + cell.ColumnIndex = columnNum; + } + + ColumnNum = columnNum; + } + + /// + /// Fired when the document is written to an output stream. + /// See + /// + internal void OnDocumentWrite() + { + + } + #endregion + + #region IEnumerable and IComparable members + /// + /// Cell iterator over the physically defined cell + /// + /// an iterator over cells in this column. + public List.Enumerator CellIterator() + { + return Cells.GetEnumerator(); + } + + /// + /// Alias for to allow foreach loops + /// + /// an iterator over cells in this row. + public IEnumerator GetEnumerator() + { + return CellIterator(); + } + + /// + /// Compares two objects. Two columns are + /// equal if they belong to the same worksheet and their column indexes + /// are equal. + /// + /// the to be compared. + /// + /// the value 0 if the column number of this + /// is equal to the column number of the argument + /// a value less than 0 if the column number of this this + /// is numerically less than the column number + /// of the argument a value greater than 0 if + /// the column number of this this is + /// numerically greater than the column number of the + /// argument + /// + /// if the argument column belongs + /// to a different worksheet + public int CompareTo(XSSFColumn other) + { + return Sheet != other.Sheet + ? throw new ArgumentException( + "The compared columns must belong to the same sheet") + : ColumnNum.CompareTo(other.ColumnNum); + } + + public override bool Equals(object obj) + { + return obj is XSSFColumn other + && ColumnNum == other.ColumnNum + && Sheet == other.Sheet; + } + + public override int GetHashCode() + { + return _column.GetHashCode(); + } + #endregion + + #region Private methods + /// + /// formatted xml representation of this column + /// + /// formatted xml representation of this column + public override string ToString() + { + return _column.ToString(); + } + + private void ValidateCellType(CellType cellType) + { + switch (cellType) + { + case CellType.Blank: + case CellType.Numeric: + case CellType.String: + case CellType.Formula: + case CellType.Boolean: + case CellType.Error: + break; + default: + throw new ArgumentException("Illegal cell type: " + cellType); + } + } + + /// + /// Get the xssfcell representing a given column (logical cell) + /// 0-based. If you ask for a cell that is not defined, then + /// you Get a null. + /// This is the basic call, with no policies applied + /// + /// 0 based row number + /// Cell representing that row or null if Undefined. + private ICell RetrieveCell(int cellnum) + { + IRow row = Sheet.GetRow(cellnum); + + return row?.GetCell(ColumnNum); + } + + private int GetFirstKey() + { + return Cells.Min(c => c.RowIndex); + } + + private int GetLastKey() + { + return Cells.Max(c => c.RowIndex); + } + #endregion + } +} diff --git a/ooxml/XSSF/UserModel/XSSFRow.cs b/ooxml/XSSF/UserModel/XSSFRow.cs index d2a46397b..59dfe6930 100644 --- a/ooxml/XSSF/UserModel/XSSFRow.cs +++ b/ooxml/XSSF/UserModel/XSSFRow.cs @@ -236,8 +236,8 @@ public ICellStyle RowStyle return _stylesSource.GetStyleAt((int)_row.s); } - return null; - } + return null; + } set { diff --git a/ooxml/XSSF/UserModel/XSSFSheet.cs b/ooxml/XSSF/UserModel/XSSFSheet.cs index 1aa198aa5..a32cee007 100644 --- a/ooxml/XSSF/UserModel/XSSFSheet.cs +++ b/ooxml/XSSF/UserModel/XSSFSheet.cs @@ -65,6 +65,7 @@ public partial class XSSFSheet : POIXMLDocumentPart, ISheet internal CT_Worksheet worksheet; private readonly SortedList _rows = new SortedList(); + private readonly SortedList _columns = new SortedList(); private List hyperlinks; private ColumnHelper columnHelper; private CommentsTable sheetComments; @@ -276,6 +277,29 @@ public int FirstRowNum } } + /// + /// Gets the first column on the sheet + /// + public int FirstColumnNum + { + get + { + if (_columns.Count == 0) + { + return 0; + } + else + { + foreach (int key in _columns.Keys) + { + return key; + } + + throw new ArgumentOutOfRangeException(); + } + } + } + /// /// Flag indicating whether the Fit to Page print option is enabled. /// @@ -423,6 +447,14 @@ public int LastRowNum } } + public int LastColumnNum + { + get + { + return _columns.Count == 0 ? 0 : GetLastKey(_columns.Keys); + } + } + /// /// Returns the list of merged regions. If you want multiple regions, /// this is faster than calling {@link #getMergedRegion(int)} each time. @@ -512,6 +544,18 @@ public int PhysicalNumberOfRows } } + /// + /// Returns the number of phsyically defined columns (NOT the number of + /// columns in the sheet) + /// + public int PhysicalNumberOfColumns + { + get + { + return _columns.Count; + } + } + /// /// Gets the print Setup object. /// @@ -1219,7 +1263,7 @@ internal virtual void Read(Stream is1) } InitRows(worksheet); - columnHelper = new ColumnHelper(worksheet); + InitColumns(worksheet); // Look for bits we're interested in foreach (RelationPart rp in RelationParts) @@ -1253,6 +1297,7 @@ internal override void OnDocumentCreate() { worksheet = NewSheet(); InitRows(worksheet); + InitColumns(worksheet); columnHelper = new ColumnHelper(worksheet); hyperlinks = new List(); } @@ -1463,6 +1508,11 @@ CT_Hyperlink[] ctHls row.OnDocumentWrite(); } + foreach (XSSFColumn column in _columns.Values) + { + column.OnDocumentWrite(); + } + new WorksheetDocument(worksheet).Save(stream, leaveOpen); // Bug 52233: Ensure that we have a col-array even if write() removed it @@ -1556,6 +1606,11 @@ internal void OnDeleteFormula(XSSFCell cell, XSSFEvaluationWorkbook evalWb) } } } + + IEnumerator IEnumerable.GetEnumerator() + { + return _rows.Values.GetEnumerator(); + } #endregion #region Public methods @@ -1567,9 +1622,10 @@ public CT_Worksheet GetCTWorksheet() { return worksheet; } - + public ColumnHelper GetColumnHelper() { + columnHelper = columnHelper ?? new ColumnHelper(worksheet); return columnHelper; } @@ -1649,8 +1705,9 @@ public void AutoSizeColumn(int column, bool useMergedCells) width = maxColumnWidth; } - SetColumnWidth(column, width); - columnHelper.SetColBestFit(column, true); + IColumn col = GetColumn(column, true); + col.Width = width / 256; + col.IsBestFit = true; } } @@ -1908,6 +1965,66 @@ public virtual IRow CreateRow(int rownum) return r; } + /// + /// Create a new column within the sheet and return the high level + /// representation. See + /// + /// column number + /// High level object representing a + /// column in the sheet + public virtual IColumn CreateColumn(int columnnum) + { + CT_Col ctCol; + XSSFColumn prev = _columns.ContainsKey(columnnum) ? _columns[columnnum] : null; + if (prev != null) + { + // the Cells in an existing column are invalidated on-purpose, in + // order to clean up correctly, we need to call the remove, so + // things like ArrayFormulas and CalculationChain updates are + // done correctly. We remove the cell this way as the internal + // cell-list is changed by the remove call and thus would cause + // ConcurrentModificationException otherwise + while (prev.FirstCellNum != -1) + { + prev.RemoveCell(prev.GetCell(prev.FirstCellNum)); + } + + ctCol = prev.GetCTCol(); + ctCol.Set(new CT_Col()); + } + else + { + if (worksheet.cols.FirstOrDefault() is null) + { + worksheet.AddNewCols(); + } + + if (_columns.Count == 0 || columnnum > GetLastKey(_columns.Keys)) + { + // we can append the new column at the end + ctCol = worksheet.cols.FirstOrDefault().AddNewCol(); + } + else + { + // get number of columns where column index < columnnum + // --> this tells us where our column should go + int idx = HeadMapCount(_columns.Keys, columnnum); + + ctCol = worksheet.cols.FirstOrDefault().InsertNewCol(idx); + } + } + + ctCol.SetNumber((uint)columnnum + 1); + + XSSFColumn c = new XSSFColumn(ctCol, this) + { + ColumnNum = columnnum + }; + + _columns[columnnum] = c; + return c; + } + /// /// Creates a split pane. Any existing freezepane or split pane is /// overwritten. @@ -2031,27 +2148,11 @@ public List GetHyperlinkList() /// the width in units of 1/256th of a character width public double GetColumnWidth(int columnIndex) { - CT_Col col = columnHelper.GetColumn(columnIndex, false); - - double width = 0; - - if (col != null && col.IsSetWidth()) - width = col.width; - else - { - CT_SheetFormatPr pr = worksheet.sheetFormatPr; - if (pr != null) - { - if (pr.defaultColWidth != 0.0) - width = pr.defaultColWidth; - else if (pr.baseColWidth != 0) - width = pr.baseColWidth + 5; - } - - if (width == 0) - width = DefaultColumnWidth; - } + IColumn col = GetColumn(columnIndex); + double width = (col == null) + ? DefaultColumnWidth + : col.Width; return Math.Round(width * 256, 2); } @@ -2267,6 +2368,29 @@ public IRow GetRow(int rownum) return null; } + /// + /// Returns the logical column ( 0-based). If you ask for a column that is + /// not defined you get a null. This is to say column 4 represents the + /// fifth column on a sheet. + /// + /// column to get + /// representing the columnnumber or null + /// if its not defined on the sheet + public IColumn GetColumn(int columnnum, bool createIfNull = false) + { + if (_columns.ContainsKey(columnnum)) + { + return _columns[columnnum]; + } + + if (createIfNull) + { + return CreateColumn(columnnum); + } + + return null; + } + /// /// Group between (0 based) columns /// @@ -2274,7 +2398,13 @@ public IRow GetRow(int rownum) /// public void GroupColumn(int fromColumn, int toColumn) { - GroupColumn1Based(fromColumn + 1, toColumn + 1); + for (int i = fromColumn; i <= toColumn; i++) + { + IColumn column = GetColumn(i, true); + column.OutlineLevel++; + } + + SetSheetFormatPrOutlineLevelCol(); } /// @@ -2303,8 +2433,8 @@ public bool IsColumnBroken(int column) /// hidden - false if the column is visible public bool IsColumnHidden(int columnIndex) { - CT_Col col = columnHelper.GetColumn(columnIndex, false); - return col != null && col.hidden; + IColumn col = GetColumn(columnIndex); + return col != null && col.Hidden; } /// @@ -2493,6 +2623,64 @@ public void RemoveRow(IRow row) } } + /// + /// Remove a column from this sheet. All cells Contained in the column are + /// Removed as well + /// + /// the column to Remove. + /// + public void RemoveColumn(IColumn column) + { + if (column == null) + { + throw new ArgumentException("Column can't be null"); + } + + if (column.Sheet != this) + { + throw new ArgumentException("Specified column does not belong to" + + " this sheet"); + } + + // collect cells into a temporary array to avoid ConcurrentModificationException + List cellsToDelete = new List(); + foreach (ICell cell in column) + { + cellsToDelete.Add((XSSFCell)cell); + } + + foreach (XSSFCell cell in cellsToDelete) + { + column.RemoveCell(cell); + } + + // also remove any comment located in that column + if (sheetComments != null) + { + foreach (CellAddress ref1 in GetCellComments().Keys) + { + if (ref1.Column == column.ColumnNum) + { + sheetComments.RemoveComment(ref1); + } + } + } + + if (hyperlinks != null) + { + foreach (XSSFHyperlink link in new List(hyperlinks)) + { + CellReference ref1 = new CellReference(link.CellRef); + if (ref1.Col == column.ColumnNum) + { + hyperlinks.Remove(link); + } + } + } + + DestroyColumn(column); + } + /// /// Removes the page break at the indicated row /// @@ -2544,13 +2732,27 @@ public void SetColumnBreak(int column) public void SetColumnGroupCollapsed(int columnNumber, bool collapsed) { - if (collapsed) + IColumn col = GetColumn(columnNumber); + + if (col == null) { - CollapseColumn(columnNumber); + return; } - else + + SortedDictionary group = GetAdjacentOutlineColumns(col); + + int lastColumnIndex = group.Keys.Max(); + + foreach (KeyValuePair columnEntry in group) { - ExpandColumn(columnNumber); + if (columnEntry.Key == lastColumnIndex) + { + columnEntry.Value.Collapsed = collapsed; + } + else + { + columnEntry.Value.Hidden = collapsed; + } } } @@ -2561,7 +2763,8 @@ public void SetColumnGroupCollapsed(int columnNumber, bool collapsed) /// the visiblity state of the column public void SetColumnHidden(int columnIndex, bool hidden) { - columnHelper.SetColHidden(columnIndex, hidden); + IColumn column = GetColumn(columnIndex, true); + column.Hidden = hidden; } /// @@ -2631,13 +2834,14 @@ public void SetColumnWidth(int columnIndex, double width) "individual cell is 255 characters."); } - columnHelper.SetColWidth(columnIndex, width / 256); - columnHelper.SetCustomWidth(columnIndex, true); + IColumn column = GetColumn(columnIndex, true); + column.Width = (double)width / 256; } public void SetDefaultColumnStyle(int column, ICellStyle style) { - columnHelper.SetColDefaultStyle(column, style); + IColumn col = GetColumn(column, true); + col.ColumnStyle = style; } /// @@ -2857,6 +3061,24 @@ public void ShiftRows(int startRow, int endRow, int n) ShiftRows(startRow, endRow, n, false, false); } + /// + /// Shifts columns between startColumn and endColumn n number of columns. If you + /// use a negative number, it will shift columns left. Code ensures that + /// columns don't wrap around. + /// Calls ShiftColumns(startColumn, endColumn, n, false, false); + /// + /// Additionally Shifts merged regions that are completely defined in + /// these columns (ie. merged 2 cells on a column to be Shifted). + /// + /// + /// the column to start Shifting + /// the column to end Shifting + /// the number of column to shift + public void ShiftColumns(int startColumn, int endColumn, int n) + { + ShiftColumns(startColumn, endColumn, n, false, false); + } + /// /// Shifts rows between startRow and endRow n number of rows. If you /// use a negative number, it will shift rows up. Code ensures that @@ -2892,6 +3114,46 @@ public void ShiftRows(int startRow, int endRow, int n, bool copyRowHeight, bool RebuildRows(); } + /// + /// Shifts columns between startColumn and endColumn n number of columns. If you + /// use a negative number, it will shift columns left. Code ensures that + /// columns don't wrap around + /// + /// Additionally Shifts merged regions thatare completely defined in + /// these columns (ie. merged 2 cells on a column to be Shifted). + /// + /// + /// the column to start Shifting + /// the column to end Shifting + /// the number of columns to shift + /// whether to copy the column width during + /// the shift + /// whether to set the original + /// column's width to the default + //YK: GetXYZArray() array accessors are deprecated in xmlbeans with JDK 1.5 support + public void ShiftColumns( + int startColumn, + int endColumn, + int n, + bool copyColumnWidth, + bool resetOriginalColumnWidth) + { + int sheetIndex = Workbook.GetSheetIndex(this); + string sheetName = Workbook.GetSheetName(sheetIndex); + FormulaShifter shifter = FormulaShifter.CreateForColumnShift( + sheetIndex, sheetName, startColumn, endColumn, n, SpreadsheetVersion.EXCEL2007); + RemoveOverwrittenColumns(startColumn, endColumn, n); + ShiftCommentsAndColumns(startColumn, endColumn, n, copyColumnWidth); + + XSSFColumnShifter columnShifter = new XSSFColumnShifter(this); + columnShifter.ShiftMergedRegions(startColumn, endColumn, n); + columnShifter.UpdateNamedRanges(shifter); + columnShifter.UpdateFormulas(shifter); + columnShifter.UpdateConditionalFormatting(shifter); + columnShifter.UpdateHyperlinks(shifter); + RebuildColumns(); + } + /// /// Returns the CellStyle that applies to the given (0 based) column, /// or null if no style has been set for that column @@ -2900,8 +3162,14 @@ public void ShiftRows(int startRow, int endRow, int n, bool copyRowHeight, bool /// public ICellStyle GetColumnStyle(int column) { - int idx = columnHelper.GetColDefaultStyle(column); - return Workbook.GetCellStyleAt(idx == -1 ? 0 : idx); + IColumn col = GetColumn(column); + + if (col != null) + { + return col.ColumnStyle; + } + + return Workbook.GetCellStyleAt(0); } /// @@ -2952,25 +3220,24 @@ public int FindEndOfRowOutlineGroup(int row) public void UngroupColumn(int fromColumn, int toColumn) { - CT_Cols cols = worksheet.GetColsArray(0); for (int index = fromColumn; index <= toColumn; index++) { - CT_Col col = columnHelper.GetColumn(index, false); + IColumn col = GetColumn(index); if (col != null) { - short outlineLevel = col.outlineLevel; - col.outlineLevel = (byte)(outlineLevel - 1); - index = (int)col.max; + int outlineLevel = col.OutlineLevel; + col.OutlineLevel = outlineLevel - 1 < 0 ? 0 : outlineLevel - 1; - if (col.outlineLevel <= 0) + if (col.OutlineLevel == 0 + && col.FirstCellNum == -1 + && (col.ColumnStyle == null + || col.ColumnStyle.Index == Workbook.GetCellStyleAt(0).Index)) { - int colIndex = columnHelper.GetIndexOfColumn(cols, col); - worksheet.GetColsArray(0).RemoveCol(colIndex); + DestroyColumn(col); } } } - worksheet.SetColsArray(0, cols); SetSheetFormatPrOutlineLevelCol(); } @@ -3575,6 +3842,163 @@ public IRow CopyRow(int sourceIndex, int targetIndex) return SheetUtil.CopyRow(this, sourceIndex, targetIndex); } + /// + /// Copy the source column to the target column. If the target column + /// exists, the new copied column will be inserted before the + /// existing one + /// + /// source index + /// target index + /// the new copied column object + public IColumn CopyColumn(int sourceIndex, int targetIndex) + { + if (sourceIndex == targetIndex) + { + throw new ArgumentException( + "sourceIndex and targetIndex cannot be same"); + } + + // Get the source / new column + IColumn newColumn = GetColumn(targetIndex); + IColumn sourceColumn = GetColumn(sourceIndex); + + // If the column exist in destination, push right all columns + // by 1 else create a new column + if (newColumn != null) + { + ShiftColumns(targetIndex, LastColumnNum, 1); + } + + newColumn = CreateColumn(targetIndex); + newColumn.Width = sourceColumn.Width; //copy column width + + // Loop through source cells to add to new column + for (int i = sourceColumn.FirstCellNum; i < sourceColumn.LastCellNum; i++) + { + // Grab a copy of the old/new cell + ICell oldCell = sourceColumn.GetCell(i); + + // If the old cell is null jump to next cell + if (oldCell == null) + { + continue; + } + + ICell newCell = newColumn.CreateCell(i); + + if (oldCell.CellStyle != null) + { + // apply style from old cell to new cell + newCell.CellStyle = oldCell.CellStyle; + } + + if (oldCell.CellComment != null) + { + CopyComment(oldCell, newCell); + } + + // If there is a cell hyperlink, copy + if (oldCell.Hyperlink != null) + { + newCell.Hyperlink = oldCell.Hyperlink; + } + + // Set the cell data type + newCell.SetCellType(oldCell.CellType); + + // Set the cell data value + switch (oldCell.CellType) + { + case CellType.Blank: + newCell.SetCellValue(oldCell.StringCellValue); + break; + case CellType.Boolean: + newCell.SetCellValue(oldCell.BooleanCellValue); + break; + case CellType.Error: + newCell.SetCellErrorValue(oldCell.ErrorCellValue); + break; + case CellType.Formula: + newCell.SetCellFormula(oldCell.CellFormula); + break; + case CellType.Numeric: + newCell.SetCellValue(oldCell.NumericCellValue); + break; + case CellType.String: + newCell.SetCellValue(oldCell.RichStringCellValue); + break; + } + } + + // If there are are any merged regions in the source column, + // copy to new column + for (int i = 0; i < NumMergedRegions; i++) + { + CellRangeAddress cellRangeAddress = GetMergedRegion(i); + if (cellRangeAddress != null + && cellRangeAddress.FirstColumn == sourceColumn.ColumnNum) + { + CellRangeAddress newCellRangeAddress = new CellRangeAddress( + cellRangeAddress.FirstRow, + cellRangeAddress.LastRow, + newColumn.ColumnNum, + newColumn.ColumnNum + cellRangeAddress.LastColumn - cellRangeAddress.FirstColumn); + AddMergedRegion(newCellRangeAddress); + } + } + + return newColumn; + } + + /// + /// This method will destroy the List object + /// without affecting the cells, formulas, styles, etc contained in the + /// sheet. It isuseful for when you've just created an IColumn to do + /// some manipulation on and don't need it anymore, and don't want to + /// leave it around in the sheet. + /// to destroy + /// If is + /// null or if it doesn't belong to this + public void DestroyColumns(List columnsToDestroy) + { + foreach (IColumn column in columnsToDestroy) + { + DestroyColumn(column); + } + } + + /// + /// This method will destroy the object without + /// affecting the cells, formulas, styles, etc contained in the sheet. + /// It isuseful for when you've just created an IColumn to do some + /// manipulation on and don't need it anymore, and don't want to leave + /// it around in the sheet. + /// + /// to destroy + /// If is + /// null or if it doesn't belong to this + public void DestroyColumn(IColumn column) + { + if (column == null) + { + throw new ArgumentException("Column can't be null"); + } + + if (column.Sheet != this) + { + throw new ArgumentException("Specified column does not belong to" + + " this sheet"); + } + + _columns.Remove(column.ColumnNum); + + CT_Cols ctCols = worksheet.cols.FirstOrDefault(); + CT_Col ctCol = ((XSSFColumn)column).GetCTCol(); + int colIndex = GetIndexOfColumn(ctCols, ctCol); + + ctCols.RemoveCol(colIndex); // Note that columns in worksheet.sheetData is 1-based. + } + public void ShowInPane(int toprow, int leftcol) { CellReference cellReference = new CellReference(toprow, leftcol); @@ -3902,13 +4326,13 @@ public List GetPivotTables() public int GetColumnOutlineLevel(int columnIndex) { - CT_Col col = columnHelper.GetColumn(columnIndex, false); + IColumn col = GetColumn(columnIndex); if (col == null) { return 0; } - return col.outlineLevel; + return col.OutlineLevel; } public bool IsDate1904() @@ -4060,15 +4484,34 @@ private void InitRows(CT_Worksheet worksheetParam) } } - /// - /// Create a new CT_Worksheet instance with all values set to defaults - /// - /// a new instance - private static CT_Worksheet NewSheet() + private void InitColumns(CT_Worksheet worksheetParam) { - CT_Worksheet worksheet = new CT_Worksheet(); - CT_SheetFormatPr ctFormat = worksheet.AddNewSheetFormatPr(); - ctFormat.defaultRowHeight = DEFAULT_ROW_HEIGHT; + _columns.Clear(); + + CT_Cols ctCols = worksheetParam.cols.FirstOrDefault() ?? worksheetParam.AddNewCols(); + + if (ctCols.sizeOfColArray() > 0) + { + foreach (CT_Col column in ctCols.col) + { + XSSFColumn c = new XSSFColumn(column, this); + if (!_columns.ContainsKey(c.ColumnNum)) + { + _columns.Add(c.ColumnNum, c); + } + } + } + } + + /// + /// Create a new CT_Worksheet instance with all values set to defaults + /// + /// a new instance + private static CT_Worksheet NewSheet() + { + CT_Worksheet worksheet = new CT_Worksheet(); + CT_SheetFormatPr ctFormat = worksheet.AddNewSheetFormatPr(); + ctFormat.defaultRowHeight = DEFAULT_ROW_HEIGHT; CT_SheetView ctView = worksheet.AddNewSheetViews().AddNewSheetView(); ctView.workbookViewId = 0; @@ -4125,7 +4568,7 @@ private int AddMergedRegion(CellRangeAddress region, bool validate) : worksheet.AddNewMergeCells(); CT_MergeCell ctMergeCell = ctMergeCells.AddNewMergeCell(); ctMergeCell.@ref = region.FormatAsString(); - return ctMergeCells.sizeOfMergeCellArray(); + return ctMergeCells.sizeOfMergeCellArray() - 1; } /// @@ -4347,43 +4790,6 @@ private CT_OutlinePr EnsureOutlinePr() } - private void GroupColumn1Based(int fromColumn, int toColumn) - { - CT_Cols ctCols = worksheet.GetColsArray(0); - CT_Col ctCol = new CT_Col(); - - // copy attributes, as they might be removed by merging with the - // new column TODO: check if this fix is really necessary or if the - // sweeping algorithm in addCleanColIntoCols needs to be adapted... - CT_Col fixCol_before = columnHelper.GetColumn1Based(toColumn, false); - if (fixCol_before != null) - { - fixCol_before = fixCol_before.Copy(); - } - - ctCol.min = (uint)fromColumn; - ctCol.max = (uint)toColumn; - columnHelper.AddCleanColIntoCols(ctCols, ctCol); - - CT_Col fixCol_after = columnHelper.GetColumn1Based(toColumn, false); - if (fixCol_before != null && fixCol_after != null) - { - columnHelper.SetColumnAttributes(fixCol_before, fixCol_after); - } - - for (int index = fromColumn; index <= toColumn; index++) - { - CT_Col col = columnHelper.GetColumn1Based(index, false); - //col must exist - short outlineLevel = col.outlineLevel; - col.outlineLevel = (byte)(outlineLevel + 1); - index = (int)col.max; - } - - worksheet.SetColsArray(0, ctCols); - SetSheetFormatPrOutlineLevelCol(); - } - /// /// Do not leave the width attribute undefined (see #52186). /// @@ -4442,405 +4848,40 @@ private bool ListIsEmpty(List list) return true; } - private void CollapseColumn(int columnNumber) + private SortedDictionary GetAdjacentOutlineColumns(IColumn col) { - CT_Cols cols = worksheet.GetColsArray(0); - CT_Col col = columnHelper.GetColumn(columnNumber, false); - int colInfoIx = columnHelper.GetIndexOfColumn(cols, col); - if (colInfoIx == -1) - { - return; - } - // Find the start of the group. - int groupStartColInfoIx = FindStartOfColumnOutlineGroup(colInfoIx); - - CT_Col columnInfo = cols.GetColArray(groupStartColInfoIx); + SortedDictionary group = new SortedDictionary() { { col.ColumnNum, col } }; - // Hide all the columns until the end of the group - int lastColMax = SetGroupHidden(groupStartColInfoIx, columnInfo - .outlineLevel, true); - - // write collapse field - SetColumn(lastColMax + 1, 0, null, null, true); - - } - - private void SetColumn(int targetColumnIx, int? style, - int? level, bool? hidden, bool? collapsed) - { - CT_Cols cols = worksheet.GetColsArray(0); - CT_Col ci = null; - - for (int k = 0; k < cols.sizeOfColArray(); k++) - { - CT_Col tci = cols.GetColArray(k); - if (tci.min >= targetColumnIx - && tci.max <= targetColumnIx) - { - ci = tci; - break; - } - - if (tci.min > targetColumnIx) - { - // call column infos after k are for later columns - break; // exit now so k will be the correct insert pos - } - } - - if (ci == null) - { - // okay so there ISN'T a column info record that covers this - // column so lets create one! - CT_Col nci = new CT_Col - { - min = (uint)targetColumnIx, - max = (uint)targetColumnIx - }; - UnsetCollapsed((bool)collapsed, nci); - columnHelper.AddCleanColIntoCols(cols, nci); - return; - } - - bool styleChanged = style != null - && ci.style != style; - bool levelChanged = level != null - && ci.outlineLevel != level; - bool hiddenChanged = hidden != null - && ci.hidden != hidden; - bool collapsedChanged = collapsed != null - && ci.collapsed != collapsed; - bool columnChanged = levelChanged || hiddenChanged - || collapsedChanged || styleChanged; - if (!columnChanged) + for (int i = col.ColumnNum - 1; i >= 0; i--) { - // do nothing...nothing Changed. - return; - } - - if (ci.min == targetColumnIx && ci.max == targetColumnIx) - { - // ColumnInfo ci for a single column, the target column - UnsetCollapsed((bool)collapsed, ci); - return; - } + IColumn columnToTheLeft = GetColumn(i); - if (ci.min == targetColumnIx || ci.max == targetColumnIx) - { - // The target column is at either end of the multi-column - // ColumnInfo ci we'll just divide the info and create a - // new one - if (ci.min == targetColumnIx) - { - ci.min = (uint)(targetColumnIx + 1); - } - else - { - ci.max = (uint)(targetColumnIx - 1); - } - - CT_Col nci = columnHelper.CloneCol(cols, ci); - nci.min = (uint)targetColumnIx; - UnsetCollapsed((bool)collapsed, nci); - columnHelper.AddCleanColIntoCols(cols, nci); - - } - else - { - // split to 3 records - CT_Col ciStart = ci; - CT_Col ciMid = columnHelper.CloneCol(cols, ci); - CT_Col ciEnd = columnHelper.CloneCol(cols, ci); - int lastcolumn = (int)ci.max; - - ciStart.max = (uint)(targetColumnIx - 1); - - ciMid.min = (uint)targetColumnIx; - ciMid.max = (uint)targetColumnIx; - UnsetCollapsed((bool)collapsed, ciMid); - columnHelper.AddCleanColIntoCols(cols, ciMid); - - ciEnd.min = (uint)(targetColumnIx + 1); - ciEnd.max = (uint)lastcolumn; - columnHelper.AddCleanColIntoCols(cols, ciEnd); - } - } - - private void UnsetCollapsed(bool collapsed, CT_Col ci) - { - if (collapsed) - { - ci.collapsed = collapsed; - } - else - { - ci.UnsetCollapsed(); - } - } - - /// - /// Sets all adjacent columns of the same outline level to the - /// specified hidden status. - /// - /// the col info index of the start of the - /// outline group - /// - /// - /// the column index of the last column in the - /// outline group - private int SetGroupHidden(int pIdx, int level, bool hidden) - { - CT_Cols cols = worksheet.GetColsArray(0); - int idx = pIdx; - CT_Col columnInfo = cols.GetColArray(idx); - while (idx < cols.sizeOfColArray()) - { - columnInfo.hidden = hidden; - if (idx + 1 < cols.sizeOfColArray()) - { - CT_Col nextColumnInfo = cols.GetColArray(idx + 1); - - if (!IsAdjacentBefore(columnInfo, nextColumnInfo)) - { - break; - } - - if (nextColumnInfo.outlineLevel < level) - { - break; - } - - columnInfo = nextColumnInfo; - } - - idx++; - } - - return (int)columnInfo.max; - } - - private bool IsAdjacentBefore(CT_Col col, CT_Col other_col) - { - return col.max == (other_col.min - 1); - } - - private int FindStartOfColumnOutlineGroup(int pIdx) - { - // Find the start of the group. - CT_Cols cols = worksheet.GetColsArray(0); - CT_Col columnInfo = cols.GetColArray(pIdx); - int level = columnInfo.outlineLevel; - int idx = pIdx; - while (idx != 0) - { - CT_Col prevColumnInfo = cols.GetColArray(idx - 1); - if (!IsAdjacentBefore(prevColumnInfo, columnInfo)) - { - break; - } - - if (prevColumnInfo.outlineLevel < level) + if (columnToTheLeft == null || columnToTheLeft.OutlineLevel < col.OutlineLevel) { break; } - idx--; - columnInfo = prevColumnInfo; + group.Add(i, columnToTheLeft); } - return idx; - } + int idx; - private int FindEndOfColumnOutlineGroup(int colInfoIndex) - { - CT_Cols cols = worksheet.GetColsArray(0); - // Find the end of the group. - CT_Col columnInfo = cols.GetColArray(colInfoIndex); - int level = columnInfo.outlineLevel; - int idx = colInfoIndex; - while (idx < cols.sizeOfColArray() - 1) + for (idx = col.ColumnNum + 1; idx <= SpreadsheetVersion.EXCEL2007.LastColumnIndex; idx++) { - CT_Col nextColumnInfo = cols.GetColArray(idx + 1); - if (!IsAdjacentBefore(columnInfo, nextColumnInfo)) - { - break; - } + IColumn columnToTheRight = GetColumn(idx); - if (nextColumnInfo.outlineLevel < level) + if (columnToTheRight == null || columnToTheRight.OutlineLevel < col.OutlineLevel) { break; } - idx++; - columnInfo = nextColumnInfo; - } - - return idx; - } - - private void ExpandColumn(int columnIndex) - { - CT_Cols cols = worksheet.GetColsArray(0); - CT_Col col = columnHelper.GetColumn(columnIndex, false); - int colInfoIx = columnHelper.GetIndexOfColumn(cols, col); - - int idx = FindColInfoIdx((int)col.max, colInfoIx); - if (idx == -1) - { - return; - } - - // If it is already expanded do nothing. - if (!IsColumnGroupCollapsed(idx)) - { - return; + group.Add(idx, columnToTheRight); } - // Find the start/end of the group. - int startIdx = FindStartOfColumnOutlineGroup(idx); - int endIdx = FindEndOfColumnOutlineGroup(idx); + // add the column behind the group to set colapsed to + group.Add(idx, GetColumn(idx, true)); - // expand: colapsed bit must be unset hidden bit Gets unset _if_ - // surrounding groups are expanded you can determine this by - // looking at the hidden bit of the enclosing group. You will have - // to look at the start and the end of the current group to - // determine which is the enclosing group hidden bit only is - // altered for this outline level. ie. don't uncollapse Contained - // groups - CT_Col columnInfo = cols.GetColArray(endIdx); - if (!IsColumnGroupHiddenByParent(idx)) - { - int outlineLevel = columnInfo.outlineLevel; - bool nestedGroup = false; - for (int i = startIdx; i <= endIdx; i++) - { - CT_Col ci = cols.GetColArray(i); - if (outlineLevel == ci.outlineLevel) - { - ci.UnsetHidden(); - if (nestedGroup) - { - nestedGroup = false; - ci.collapsed = true; - } - } - else - { - nestedGroup = true; - } - } - } - // Write collapse flag (stored in a single col info record after - // this outline group) - SetColumn((int)columnInfo.max + 1, null, null, - false, false); - } - - private bool IsColumnGroupHiddenByParent(int idx) - { - CT_Cols cols = worksheet.GetColsArray(0); - // Look out outline details of end - int endLevel = 0; - bool endHidden = false; - int endOfOutlineGroupIdx = FindEndOfColumnOutlineGroup(idx); - if (endOfOutlineGroupIdx < cols.sizeOfColArray()) - { - CT_Col nextInfo = cols.GetColArray(endOfOutlineGroupIdx + 1); - if (IsAdjacentBefore(cols.GetColArray(endOfOutlineGroupIdx), - nextInfo)) - { - endLevel = nextInfo.outlineLevel; - endHidden = nextInfo.hidden; - } - } - // Look out outline details of start - int startLevel = 0; - bool startHidden = false; - int startOfOutlineGroupIdx = FindStartOfColumnOutlineGroup(idx); - if (startOfOutlineGroupIdx > 0) - { - CT_Col prevInfo = cols.GetColArray(startOfOutlineGroupIdx - 1); - - if (IsAdjacentBefore(prevInfo, cols - .GetColArray(startOfOutlineGroupIdx))) - { - startLevel = prevInfo.outlineLevel; - startHidden = prevInfo.hidden; - } - } - - if (endLevel > startLevel) - { - return endHidden; - } - - return startHidden; - } - - private int FindColInfoIdx(int columnValue, int fromColInfoIdx) - { - CT_Cols cols = worksheet.GetColsArray(0); - - if (columnValue < 0) - { - throw new ArgumentException( - "column parameter out of range: " + columnValue); - } - - if (fromColInfoIdx < 0) - { - throw new ArgumentException( - "fromIdx parameter out of range: " + fromColInfoIdx); - } - - for (int k = fromColInfoIdx; k < cols.sizeOfColArray(); k++) - { - CT_Col ci = cols.GetColArray(k); - - if (ContainsColumn(ci, columnValue)) - { - return k; - } - - if (ci.min > fromColInfoIdx) - { - break; - } - } - - return -1; - } - - private bool ContainsColumn(CT_Col col, int columnIndex) - { - return col.min <= columnIndex && columnIndex <= col.max; - } - - /// - /// 'Collapsed' state is stored in a single column col info record - /// immediately after the outline group - /// - /// - /// a bool represented if the column is collapsed - private bool IsColumnGroupCollapsed(int idx) - { - CT_Cols cols = worksheet.GetColsArray(0); - int endOfOutlineGroupIdx = FindEndOfColumnOutlineGroup(idx); - int nextColInfoIx = endOfOutlineGroupIdx + 1; - if (nextColInfoIx >= cols.sizeOfColArray()) - { - return false; - } - - CT_Col nextColInfo = cols.GetColArray(nextColInfoIx); - - CT_Col col = cols.GetColArray(endOfOutlineGroupIdx); - if (!IsAdjacentBefore(col, nextColInfo)) - { - return false; - } - - return nextColInfo.collapsed; + return group; } private CT_SheetView GetSheetTypeSheetView() @@ -5118,6 +5159,35 @@ private void RemoveOverwrittenRows(int startRow, int endRow, int n) worksheet.sheetData.RemoveRows(ctRowsToRemove); } + + private void RemoveOverwrittenColumns(int startColumn, int endColumn, int n) + { + if (worksheet.cols.FirstOrDefault() is null) + { + throw new RuntimeException("There is no columns in XML part"); + } + + List columnsToRemove = new List(); + + // first remove all columns which will be overwritten + for (int i = startColumn + n; i <= endColumn + n; i++) + { + // check if we should remove this column as it will be overwritten + // by the data later + if (ShouldRemoveAtIndex(startColumn, endColumn, n, i)) + { + IColumn column = GetColumn(i, true); + + columnsToRemove.Add(column); + } + } + + foreach (IColumn column in columnsToRemove) + { + RemoveColumn(column); + } + } + private void RebuildRows() { //rebuild the _rows map @@ -5141,6 +5211,27 @@ private void RebuildRows() worksheet.sheetData.row.Sort((row1, row2) => row1.r.CompareTo(row2.r)); } } + + private void RebuildColumns() + { + //rebuild the _columns map + Dictionary map = new Dictionary(); + foreach (XSSFColumn c in _columns.Values) + { + map.Add(c.ColumnNum, c); + } + + _columns.Clear(); + + foreach (KeyValuePair kv in map) + { + _columns.Add(kv.Key, kv.Value); + } + + // Sort CT_Cols by index asc. + worksheet.cols.FirstOrDefault()?.col.Sort((col1, col2) => col1.min.CompareTo(col2.min)); + } + private void ShiftCommentsAndRows(int startRow, int endRow, int n, bool copyRowHeight) { SortedDictionary commentsToShift = @@ -5247,6 +5338,121 @@ private void ValidateCellsForCopyComment(ICell sourceCell, ICell targetCell) } } + private void ShiftCommentsAndColumns(int startColumn, int endColumn, int n, bool copyColumnWidth) + { + SortedDictionary commentsToShift = + new SortedDictionary(new ShiftCommentComparator(n)); + + List columnsToDestroy = new List(); + + for (int i = startColumn; i <= endColumn; i++) + { + if (!_columns.ContainsKey(i)) + { + columnsToDestroy.Add(CreateColumn(i)); + } + } + + var sortedColumns = n < 0 + ? new SortedDictionary(_columns) + : new SortedDictionary(_columns).Reverse(); + + foreach (KeyValuePair columnDict in sortedColumns) + { + XSSFColumn column = columnDict.Value; + int columnNum = column.ColumnNum; + + if (sheetComments != null) + { + // calculate the new columnNum + int newColumnNum = ShiftedRowOrColumnNumber(startColumn, endColumn, n, columnNum); + + // is there a change necessary for the current column? + if (newColumnNum != columnNum) + { + List commentAddresses = sheetComments.GetCellAddresses(); + foreach (CellAddress cellAddress in commentAddresses) + { + if (cellAddress.Column == columnNum) + { + XSSFComment oldComment = sheetComments + .FindCellComment(cellAddress); + if (oldComment != null) + { + CT_Shape commentShape = + GetVMLDrawing(false) + .FindCommentShape( + oldComment.Row, + oldComment.Column); + + XSSFComment xssfComment = + new XSSFComment( + sheetComments, + oldComment.GetCTComment(), + commentShape); + + if (commentsToShift.ContainsKey(xssfComment)) + { + commentsToShift[xssfComment] = newColumnNum; + } + else + { + commentsToShift.Add(xssfComment, newColumnNum); + } + } + } + } + } + } + + if (columnNum < startColumn || columnNum > endColumn) + { + continue; + } + + if (!copyColumnWidth) + { + column.Width = -1; + } + + column.Shift(n); + } + + // adjust all the affected comment-structures now + // the Map is sorted and thus provides them in the order that we need here, + // i.e. from right to left if Shifting right, vice-versa otherwise + foreach (KeyValuePair entry in commentsToShift) + { + entry.Key.Column = entry.Value; + } + + RebuildColumns(); + RebuildRowCells(); + DestroyColumns(columnsToDestroy); + } + + private int GetIndexOfColumn(CT_Cols ctCols, CT_Col ctCol) + { + for (int i = 0; i < ctCols.sizeOfColArray(); i++) + { + if (ctCols.GetColArray(i).min == ctCol.min + && ctCols.GetColArray(i).max == ctCol.max) + { + return i; + } + } + + return -1; + } + + private void RebuildRowCells() + { + foreach (XSSFRow row in _rows.Values) + { + row.RebuildCells(); + } + } + private int ShiftedRowOrColumnNumber(int startIndex, int endIndex, int n, int index) { // no change if before any affected index diff --git a/testcases/main/HSSF/Extractor/TestOldExcelExtractor.cs b/testcases/main/HSSF/Extractor/TestOldExcelExtractor.cs index 2c023846c..28980ae97 100644 --- a/testcases/main/HSSF/Extractor/TestOldExcelExtractor.cs +++ b/testcases/main/HSSF/Extractor/TestOldExcelExtractor.cs @@ -27,6 +27,7 @@ namespace TestCases.HSSF.Extractor using System.Text; using TestCases; using TestCases.HSSF; + using System.Threading; /** * Unit tests for the Excel 5/95 and Excel 4 (and older) text @@ -42,6 +43,11 @@ private static OldExcelExtractor CreateExtractor(String sampleFileName) return new OldExcelExtractor(file); } + public TestOldExcelExtractor() + { + Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); + } + [Test] public void TestSimpleExcel3() { diff --git a/testcases/main/SS/Formula/Atp/TestNetworkdaysFunction.cs b/testcases/main/SS/Formula/Atp/TestNetworkdaysFunction.cs index 4c6c6bb47..573c9d427 100644 --- a/testcases/main/SS/Formula/Atp/TestNetworkdaysFunction.cs +++ b/testcases/main/SS/Formula/Atp/TestNetworkdaysFunction.cs @@ -47,6 +47,12 @@ public class TestNetworkdaysFunction private static String THIRD_HOLIDAY = formatter.Format(new DateTime(2009, JANUARY, 21), CultureInfo.CurrentCulture); private static OperationEvaluationContext EC = new OperationEvaluationContext(null, null, 1, 1, 1, null); + + public TestNetworkdaysFunction() + { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); + } + [Test] public void TestFailWhenNoArguments() { diff --git a/testcases/main/SS/Formula/Functions/TestBesselJ.cs b/testcases/main/SS/Formula/Functions/TestBesselJ.cs index 0ffa03526..914788beb 100644 --- a/testcases/main/SS/Formula/Functions/TestBesselJ.cs +++ b/testcases/main/SS/Formula/Functions/TestBesselJ.cs @@ -24,6 +24,7 @@ public void TestInvalid() [Test] public void TestNumError() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); confirmNumError("22.5", "-40"); } @@ -31,6 +32,7 @@ public void TestNumError() [Test] public void TestMicrosoftExample1() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); HSSFWorkbook wb = new HSSFWorkbook(); ISheet sheet = wb.CreateSheet(); IRow row = sheet.CreateRow(0); diff --git a/testcases/main/SS/Formula/Functions/TestComplex.cs b/testcases/main/SS/Formula/Functions/TestComplex.cs index 1c19e80c3..b26b8fd84 100644 --- a/testcases/main/SS/Formula/Functions/TestComplex.cs +++ b/testcases/main/SS/Formula/Functions/TestComplex.cs @@ -52,6 +52,7 @@ private static void ConfirmValueError(String msg, String real_num, String i_num, [Test] public void TestBasic() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); ConfirmValue("Complex number with 3 and 4 as the real and imaginary coefficients (3 + 4i)", "3", "4", "", "3+4i"); ConfirmValue("Complex number with 3 and 4 as the real and imaginary coefficients, and j as the suffix (3 + 4j)", "3", "4", "j", "3+4j"); diff --git a/testcases/main/SS/Formula/Functions/TestDec2Bin.cs b/testcases/main/SS/Formula/Functions/TestDec2Bin.cs index 8db8f5820..8a2f70e4e 100644 --- a/testcases/main/SS/Formula/Functions/TestDec2Bin.cs +++ b/testcases/main/SS/Formula/Functions/TestDec2Bin.cs @@ -33,6 +33,10 @@ namespace TestCases.SS.Formula.Functions [TestFixture] public class TestDec2Bin { + public TestDec2Bin() + { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); + } private static ValueEval invokeValue(String number1) { diff --git a/testcases/main/SS/Formula/Functions/TestDec2Hex.cs b/testcases/main/SS/Formula/Functions/TestDec2Hex.cs index ccbf88dc0..8532b4105 100644 --- a/testcases/main/SS/Formula/Functions/TestDec2Hex.cs +++ b/testcases/main/SS/Formula/Functions/TestDec2Hex.cs @@ -33,6 +33,10 @@ namespace TestCases.SS.Formula.Functions [TestFixture] public class TestDec2Hex { + public TestDec2Hex() + { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); + } private static ValueEval invokeValue(String number1, String number2) { diff --git a/testcases/main/SS/Formula/Functions/TestDelta.cs b/testcases/main/SS/Formula/Functions/TestDelta.cs index ab1cf1274..dcb0ee429 100644 --- a/testcases/main/SS/Formula/Functions/TestDelta.cs +++ b/testcases/main/SS/Formula/Functions/TestDelta.cs @@ -52,6 +52,7 @@ private static void ConfirmValueError(String number1, String number2) [Test] public void TestBasic() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); ConfirmValue("5", "4", 0); // Checks whether 5 Equals 4 (0) ConfirmValue("5", "5", 1); // Checks whether 5 Equals 5 (1) diff --git a/testcases/main/SS/Formula/Functions/TestDollarDe.cs b/testcases/main/SS/Formula/Functions/TestDollarDe.cs index fc8983af1..0b23f3100 100644 --- a/testcases/main/SS/Formula/Functions/TestDollarDe.cs +++ b/testcases/main/SS/Formula/Functions/TestDollarDe.cs @@ -23,12 +23,14 @@ public void TestInvalid() [Test] public void TestNumError() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); confirmNumError("22.5", "-40"); } [Test] public void TestDiv0() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); confirmDiv0("22.5", "0"); confirmDiv0("22.5", "0.9"); confirmDiv0("22.5", "-0.9"); @@ -38,6 +40,7 @@ public void TestDiv0() [Test] public void TestMicrosoftExample1() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); HSSFWorkbook wb = new HSSFWorkbook(); var sheet = wb.CreateSheet(); var row = sheet.CreateRow(0); diff --git a/testcases/main/SS/Formula/Functions/TestDollarFr.cs b/testcases/main/SS/Formula/Functions/TestDollarFr.cs index ba27cb66a..78673f7aa 100644 --- a/testcases/main/SS/Formula/Functions/TestDollarFr.cs +++ b/testcases/main/SS/Formula/Functions/TestDollarFr.cs @@ -23,12 +23,14 @@ public void TestInvalid() [Test] public void TestNumError() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); confirmNumError("22.5", "-40"); } [Test] public void TestDiv0() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); confirmDiv0("22.5", "0"); confirmDiv0("22.5", "0.9"); confirmDiv0("22.5", "-0.9"); @@ -38,6 +40,7 @@ public void TestDiv0() [Test] public void TestMicrosoftExample1() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); HSSFWorkbook wb = new HSSFWorkbook(); var sheet = wb.CreateSheet(); var row = sheet.CreateRow(0); diff --git a/testcases/main/SS/Formula/Functions/TestFixed.cs b/testcases/main/SS/Formula/Functions/TestFixed.cs index 90c5af45d..96fc0f17f 100644 --- a/testcases/main/SS/Formula/Functions/TestFixed.cs +++ b/testcases/main/SS/Formula/Functions/TestFixed.cs @@ -51,6 +51,7 @@ public void SetUp() [Test] public void TestValid() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); // thousands separator Confirm("FIXED(1234.56789,2,TRUE)", "1234.57"); Confirm("FIXED(1234.56789,2,FALSE)", "1,234.57"); @@ -88,6 +89,7 @@ public void TestValid() [Test] public void TestOptionalParams() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); Fixed fixedFunc = new Fixed(); ValueEval Evaluate = fixedFunc.Evaluate(0, 0, new NumberEval(1234.56789)); Assert.IsTrue(Evaluate is StringEval); diff --git a/testcases/main/SS/Formula/Functions/TestNormDist.cs b/testcases/main/SS/Formula/Functions/TestNormDist.cs index 63db499cf..fc03854c0 100644 --- a/testcases/main/SS/Formula/Functions/TestNormDist.cs +++ b/testcases/main/SS/Formula/Functions/TestNormDist.cs @@ -17,6 +17,7 @@ public class TestNormDist [Test] public void TestBasic() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); confirmValue("42", "40", "1.5", true, 0.908788780274132); confirmValue("42", "40", "1.5", false, 0.109340049783996); } @@ -29,6 +30,7 @@ public void TestInvalid() [Test] public void TestNumError() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); confirmNumError("42", "40", "0", false); confirmNumError("42", "40", "0", true); confirmNumError("42", "40", "-0.1", false); @@ -40,6 +42,7 @@ public void TestNumError() [Test] public void TestMicrosoftExample1() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); HSSFWorkbook wb = new HSSFWorkbook(); ISheet sheet = wb.CreateSheet(); SS.Util.Utils.AddRow(sheet, 0, "Data", "Description"); diff --git a/testcases/main/SS/Formula/Functions/TestNormInv.cs b/testcases/main/SS/Formula/Functions/TestNormInv.cs index 17e2d82cf..fe13b4506 100644 --- a/testcases/main/SS/Formula/Functions/TestNormInv.cs +++ b/testcases/main/SS/Formula/Functions/TestNormInv.cs @@ -18,6 +18,7 @@ public class TestNormInv [Test] public void TestBasic() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); confirmValue("0.908789", "40", "1.5", 42.000002); } @@ -30,6 +31,7 @@ public void TestInvalid() [Test] public void TestNumError() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); confirmNumError("0.5", "40", "0"); confirmNumError("0.5", "40", "-0.1"); confirmNumError("-0.5", "40", "0.1"); @@ -42,6 +44,7 @@ public void TestNumError() [Test] public void TestMicrosoftExample1() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); HSSFWorkbook wb = new HSSFWorkbook(); ISheet sheet = wb.CreateSheet(); SS.Util.Utils.AddRow(sheet, 0, "Data", "Description"); diff --git a/testcases/main/SS/Formula/Functions/TestNormSDist.cs b/testcases/main/SS/Formula/Functions/TestNormSDist.cs index 79500d3f9..4fcc890ef 100644 --- a/testcases/main/SS/Formula/Functions/TestNormSDist.cs +++ b/testcases/main/SS/Formula/Functions/TestNormSDist.cs @@ -17,6 +17,7 @@ public class TestNormSDist [Test] public void TestBasic() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); confirmValue("1.333333", 0.908788726); } @@ -28,6 +29,7 @@ public void TestInvalid() [Test] public void TestMicrosoftExample1() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); HSSFWorkbook wb = new HSSFWorkbook(); ISheet sheet = wb.CreateSheet(); IRow row = sheet.CreateRow(0); diff --git a/testcases/main/SS/Formula/Functions/TestNormSInv.cs b/testcases/main/SS/Formula/Functions/TestNormSInv.cs index f5e3a1a3e..8429515e9 100644 --- a/testcases/main/SS/Formula/Functions/TestNormSInv.cs +++ b/testcases/main/SS/Formula/Functions/TestNormSInv.cs @@ -17,6 +17,7 @@ public class TestNormSInv [Test] public void TestBasic() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); confirmValue("0.9088", 1.3334); } @@ -28,6 +29,7 @@ public void TestInvalid() [Test] public void TestNumError() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); confirmNumError("0"); confirmNumError("-0.5"); confirmNumError("1"); @@ -36,6 +38,7 @@ public void TestNumError() [Test] public void TestMicrosoftExample1() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); HSSFWorkbook wb = new HSSFWorkbook(); ISheet sheet = wb.CreateSheet(); IRow row = sheet.CreateRow(0); diff --git a/testcases/main/SS/Formula/Functions/TestNumberValue.cs b/testcases/main/SS/Formula/Functions/TestNumberValue.cs index 131505a0f..8df22a2b5 100644 --- a/testcases/main/SS/Formula/Functions/TestNumberValue.cs +++ b/testcases/main/SS/Formula/Functions/TestNumberValue.cs @@ -12,6 +12,7 @@ public class TestNumberValue [Test] public void TestMicrosoftExample1() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); HSSFWorkbook wb = new HSSFWorkbook(); var sheet = wb.CreateSheet(); var row = sheet.CreateRow(0); @@ -23,6 +24,7 @@ public void TestMicrosoftExample1() [Test] public void TestMicrosoftExample2() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); HSSFWorkbook wb = new HSSFWorkbook(); var sheet = wb.CreateSheet(); var row = sheet.CreateRow(0); diff --git a/testcases/main/SS/Formula/Functions/TestNumericFunction.cs b/testcases/main/SS/Formula/Functions/TestNumericFunction.cs index ef8cc96e1..c0439192d 100644 --- a/testcases/main/SS/Formula/Functions/TestNumericFunction.cs +++ b/testcases/main/SS/Formula/Functions/TestNumericFunction.cs @@ -41,6 +41,7 @@ public void TestSIGN() [Test] public void TestDOLLAR() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); HSSFWorkbook wb = new HSSFWorkbook(); ICell cell = wb.CreateSheet().CreateRow(0).CreateCell(0); HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); diff --git a/testcases/main/SS/Formula/Functions/TestQuotient.cs b/testcases/main/SS/Formula/Functions/TestQuotient.cs index 43b07f58a..67e261dc8 100644 --- a/testcases/main/SS/Formula/Functions/TestQuotient.cs +++ b/testcases/main/SS/Formula/Functions/TestQuotient.cs @@ -54,6 +54,7 @@ private static void ConfirmValueError(String msg, String numerator, String denom [Test] public void TestBasic() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); ConfirmValue("int portion of 5/2 (2)", "5", "2", "2"); ConfirmValue("int portion of 4.5/3.1 (1)", "4.5", "3.1", "1"); @@ -65,6 +66,7 @@ public void TestBasic() [Test] public void TestErrors() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); ConfirmValueError("numerator is nonnumeric", "ABCD", "", ErrorEval.VALUE_INVALID); ConfirmValueError("denominator is nonnumeric", "", "ABCD", ErrorEval.VALUE_INVALID); diff --git a/testcases/main/SS/Formula/Functions/TestStandardize.cs b/testcases/main/SS/Formula/Functions/TestStandardize.cs index 337acfbca..2a4049314 100644 --- a/testcases/main/SS/Formula/Functions/TestStandardize.cs +++ b/testcases/main/SS/Formula/Functions/TestStandardize.cs @@ -17,6 +17,7 @@ public class TestStandardize [Test] public void TestBasic() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); confirmValue("42", "40", "1.5", 1.33333333); } @@ -29,6 +30,7 @@ public void TestInvalid() [Test] public void TestNumError() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); confirmNumError("42", "40", "0"); confirmNumError("42", "40", "-0.1"); } @@ -36,6 +38,7 @@ public void TestNumError() [Test] public void TestMicrosoftExample1() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); HSSFWorkbook wb = new HSSFWorkbook(); ISheet sheet = wb.CreateSheet(); SS.Util.Utils.AddRow(sheet, 0, "Data", "Description"); diff --git a/testcases/main/SS/Formula/Functions/TestTDist.cs b/testcases/main/SS/Formula/Functions/TestTDist.cs index b9c4cf589..ccf9d9b42 100644 --- a/testcases/main/SS/Formula/Functions/TestTDist.cs +++ b/testcases/main/SS/Formula/Functions/TestTDist.cs @@ -16,6 +16,7 @@ public class TestTDist [Test] public void TestBasic() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); confirmValue("5.968191467", "8", "1", 0.00016754180265310392); confirmValue("5.968191467", "8", "2", 0.00033508360530620784); confirmValue("5.968191467", "8.2", "2.2", 0.00033508360530620784); @@ -34,6 +35,7 @@ public void TestInvalid() [Test] public void TestNumError() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); confirmNumError("5.968191467", "8", "0"); confirmNumError("-5.968191467", "8", "2"); } @@ -42,6 +44,7 @@ public void TestNumError() [Test] public void testMicrosoftExample1() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); HSSFWorkbook wb = new HSSFWorkbook(); ISheet sheet = wb.CreateSheet(); SS.Util.Utils.AddRow(sheet, 0, "Data", "Description"); diff --git a/testcases/main/SS/Formula/Functions/TestText.cs b/testcases/main/SS/Formula/Functions/TestText.cs index d7793d765..60efc3b4e 100644 --- a/testcases/main/SS/Formula/Functions/TestText.cs +++ b/testcases/main/SS/Formula/Functions/TestText.cs @@ -67,6 +67,7 @@ public void TestTextWithStringFirstArg() [Test] public void TestTextWithDecimalFormatSecondArg() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); ValueEval numArg = new NumberEval(321321.321); ValueEval formatArg = new StringEval("#,###.00000"); ValueEval[] args = { numArg, formatArg }; @@ -96,6 +97,7 @@ public void TestTextWithDecimalFormatSecondArg() [Test] public void TestTextWithFractionFormatSecondArg() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); ValueEval numArg = new NumberEval(321.321); ValueEval formatArg = new StringEval("# #/#"); ValueEval[] args = { numArg, formatArg }; diff --git a/testcases/main/SS/UserModel/TestFractionFormat.cs b/testcases/main/SS/UserModel/TestFractionFormat.cs index 7a40f2242..31336fa9a 100644 --- a/testcases/main/SS/UserModel/TestFractionFormat.cs +++ b/testcases/main/SS/UserModel/TestFractionFormat.cs @@ -21,6 +21,8 @@ limitations under the License. using NUnit.Framework; using System.IO; using System.Text.RegularExpressions; +using System.Threading; + namespace TestCases.SS.UserModel { @@ -34,6 +36,7 @@ public class TestFractionFormat [Test] public void TestSingle() { + Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); FractionFormat f = new FractionFormat("", "##"); string val = "321.321"; String ret = f.Format(val); diff --git a/testcases/main/Util/TestStringUtil.cs b/testcases/main/Util/TestStringUtil.cs index 053db9168..33572904a 100644 --- a/testcases/main/Util/TestStringUtil.cs +++ b/testcases/main/Util/TestStringUtil.cs @@ -20,7 +20,7 @@ namespace TestCases.Util { using System; using System.Text; - + using System.Threading; using NPOI.Util; using NUnit.Framework; /** @@ -248,6 +248,7 @@ public void TestPutUncompressedUnicode() [Test] public void Join() { + Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); Assert.AreEqual("", StringUtil.Join(",")); // degenerate case: nothing to join Assert.AreEqual("abc", StringUtil.Join(",", "abc")); // degenerate case: one thing to join, no trailing comma Assert.AreEqual("abc|def|ghi", StringUtil.Join("|", "abc", "def", "ghi")); diff --git a/testcases/ooxml/XSSF/Streaming/SheetDataWriterTests.cs b/testcases/ooxml/XSSF/Streaming/SheetDataWriterTests.cs index b2778ca25..4a8ac2a77 100644 --- a/testcases/ooxml/XSSF/Streaming/SheetDataWriterTests.cs +++ b/testcases/ooxml/XSSF/Streaming/SheetDataWriterTests.cs @@ -19,7 +19,9 @@ limitations under the License. using NPOI.XSSF.UserModel; using NSubstitute; using NUnit.Framework; +using System.Globalization; using System.IO; +using System.Threading; namespace TestCases.XSSF.Streaming { @@ -33,6 +35,7 @@ public class SheetDataWriterTests [SetUp] public void Init() { + Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); var _xssfsheet = Substitute.For(); var _workbook = Substitute.For(); var _sheet = Substitute.For(_workbook, _xssfsheet); @@ -73,7 +76,7 @@ public void IfWritingRowWithCustomHeightShouldIncludeCustomHeightXml() var lines = File.ReadAllLines(_objectToTest.TemporaryFilePath()); Assert.True(lines.Length == 2); - Assert.AreEqual("", lines[0]); + Assert.AreEqual($"", lines[0]); Assert.AreEqual("", lines[1]); diff --git a/testcases/ooxml/XSSF/UserModel/Helpers/TestColumnHelper.cs b/testcases/ooxml/XSSF/UserModel/Helpers/TestColumnHelper.cs index 74a8b6b3f..a532a05ce 100644 --- a/testcases/ooxml/XSSF/UserModel/Helpers/TestColumnHelper.cs +++ b/testcases/ooxml/XSSF/UserModel/Helpers/TestColumnHelper.cs @@ -20,6 +20,7 @@ limitations under the License. using NPOI.XSSF.Model; using NPOI.XSSF.UserModel.Helpers; using NPOI.XSSF.UserModel; +using System; namespace TestCases.XSSF.UserModel.Helpers { @@ -28,6 +29,7 @@ namespace TestCases.XSSF.UserModel.Helpers * */ [TestFixture] + [Obsolete("Use XSSFColumn object for all things column")] public class TestColumnHelper { [Test] diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFColGrouping.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFColGrouping.cs index f7c1cb2f3..e5bcc737e 100644 --- a/testcases/ooxml/XSSF/UserModel/TestXSSFColGrouping.cs +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFColGrouping.cs @@ -107,17 +107,14 @@ public void TestMergingOverlappingCols_OVERLAPS_2_WRAPS() XSSFWorkbook wb = new XSSFWorkbook(); XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("test"); - CT_Cols cols = sheet.GetCTWorksheet().GetColsArray(0); - CT_Col col = cols.AddNewCol(); - col.min=(1 + 1); - col.max=(4 + 1); - col.width=(20); - col.customWidth=(true); + sheet.CreateColumn(1).Width = 20; + sheet.CreateColumn(2).Width = 20; + sheet.CreateColumn(3).Width = 20; + sheet.CreateColumn(4).Width = 20; sheet.GroupColumn((short)2, (short)3); - sheet.GetCTWorksheet().GetColsArray(0); - //logger.log(POILogger.DEBUG, "testMergingOverlappingCols_OVERLAPS_2_WRAPS/cols:" + cols); + CT_Cols cols = sheet.GetCTWorksheet().GetColsArray(0); Assert.AreEqual(0, cols.GetColArray(0).outlineLevel); Assert.AreEqual(2, cols.GetColArray(0).min); // 1 based @@ -126,15 +123,20 @@ public void TestMergingOverlappingCols_OVERLAPS_2_WRAPS() Assert.AreEqual(1, cols.GetColArray(1).outlineLevel); Assert.AreEqual(3, cols.GetColArray(1).min); // 1 based - Assert.AreEqual(4, cols.GetColArray(1).max); // 1 based + Assert.AreEqual(3, cols.GetColArray(1).max); // 1 based Assert.AreEqual(true, cols.GetColArray(1).customWidth); - Assert.AreEqual(0, cols.GetColArray(2).outlineLevel); - Assert.AreEqual(5, cols.GetColArray(2).min); // 1 based - Assert.AreEqual(5, cols.GetColArray(2).max); // 1 based + Assert.AreEqual(1, cols.GetColArray(2).outlineLevel); + Assert.AreEqual(4, cols.GetColArray(2).min); // 1 based + Assert.AreEqual(4, cols.GetColArray(2).max); // 1 based Assert.AreEqual(true, cols.GetColArray(2).customWidth); - Assert.AreEqual(3, cols.sizeOfColArray()); + Assert.AreEqual(0, cols.GetColArray(3).outlineLevel); + Assert.AreEqual(5, cols.GetColArray(3).min); // 1 based + Assert.AreEqual(5, cols.GetColArray(3).max); // 1 based + Assert.AreEqual(true, cols.GetColArray(3).customWidth); + + Assert.AreEqual(4, cols.sizeOfColArray()); wb = XSSFTestDataSamples.WriteOutAndReadBack(wb, "testMergingOverlappingCols_OVERLAPS_2_WRAPS"); sheet = (XSSFSheet)wb.GetSheet("test"); @@ -154,17 +156,13 @@ public void TestMergingOverlappingCols_OVERLAPS_1_WRAPS() XSSFWorkbook wb = new XSSFWorkbook(); XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("test"); - CT_Cols cols = sheet.GetCTWorksheet().GetColsArray(0); - CT_Col col = cols.AddNewCol(); - col.min=(2 + 1); - col.max=(4 + 1); - col.width=(20); - col.customWidth=(true); + sheet.CreateColumn(2).Width = 20; + sheet.CreateColumn(3).Width = 20; + sheet.CreateColumn(4).Width = 20; sheet.GroupColumn((short)1, (short)5); - cols = sheet.GetCTWorksheet().GetColsArray(0); - //logger.log(POILogger.DEBUG, "testMergingOverlappingCols_OVERLAPS_1_WRAPS/cols:" + cols); + CT_Cols cols = sheet.GetCTWorksheet().GetColsArray(0); Assert.AreEqual(1, cols.GetColArray(0).outlineLevel); Assert.AreEqual(2, cols.GetColArray(0).min); // 1 based @@ -173,15 +171,25 @@ public void TestMergingOverlappingCols_OVERLAPS_1_WRAPS() Assert.AreEqual(1, cols.GetColArray(1).outlineLevel); Assert.AreEqual(3, cols.GetColArray(1).min); // 1 based - Assert.AreEqual(5, cols.GetColArray(1).max); // 1 based + Assert.AreEqual(3, cols.GetColArray(1).max); // 1 based Assert.AreEqual(true, cols.GetColArray(1).customWidth); Assert.AreEqual(1, cols.GetColArray(2).outlineLevel); - Assert.AreEqual(6, cols.GetColArray(2).min); // 1 based - Assert.AreEqual(6, cols.GetColArray(2).max); // 1 based - Assert.AreEqual(false, cols.GetColArray(2).customWidth); + Assert.AreEqual(4, cols.GetColArray(2).min); // 1 based + Assert.AreEqual(4, cols.GetColArray(2).max); // 1 based + Assert.AreEqual(true, cols.GetColArray(2).customWidth); - Assert.AreEqual(3, cols.sizeOfColArray()); + Assert.AreEqual(1, cols.GetColArray(3).outlineLevel); + Assert.AreEqual(5, cols.GetColArray(3).min); // 1 based + Assert.AreEqual(5, cols.GetColArray(3).max); // 1 based + Assert.AreEqual(true, cols.GetColArray(3).customWidth); + + Assert.AreEqual(1, cols.GetColArray(4).outlineLevel); + Assert.AreEqual(6, cols.GetColArray(4).min); // 1 based + Assert.AreEqual(6, cols.GetColArray(4).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(4).customWidth); + + Assert.AreEqual(5, cols.sizeOfColArray()); wb = XSSFTestDataSamples.WriteOutAndReadBack(wb, "testMergingOverlappingCols_OVERLAPS_1_WRAPS"); sheet = (XSSFSheet)wb.GetSheet("test"); @@ -201,17 +209,13 @@ public void TestMergingOverlappingCols_OVERLAPS_1_MINOR() XSSFWorkbook wb = new XSSFWorkbook(); XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("test"); - CT_Cols cols = sheet.GetCTWorksheet().GetColsArray(0); - CT_Col col = cols.AddNewCol(); - col.min=(2 + 1); - col.max=(4 + 1); - col.width=(20); - col.customWidth=(true); + sheet.CreateColumn(2).Width = 20; + sheet.CreateColumn(3).Width = 20; + sheet.CreateColumn(4).Width = 20; - sheet.GroupColumn((short)3, (short)5); + sheet.GroupColumn(3, 5); - cols = sheet.GetCTWorksheet().GetColsArray(0); - //logger.log(POILogger.DEBUG, "testMergingOverlappingCols_OVERLAPS_1_MINOR/cols:" + cols); + CT_Cols cols = sheet.GetCTWorksheet().GetColsArray(0); Assert.AreEqual(0, cols.GetColArray(0).outlineLevel); Assert.AreEqual(3, cols.GetColArray(0).min); // 1 based @@ -220,15 +224,20 @@ public void TestMergingOverlappingCols_OVERLAPS_1_MINOR() Assert.AreEqual(1, cols.GetColArray(1).outlineLevel); Assert.AreEqual(4, cols.GetColArray(1).min); // 1 based - Assert.AreEqual(5, cols.GetColArray(1).max); // 1 based + Assert.AreEqual(4, cols.GetColArray(1).max); // 1 based Assert.AreEqual(true, cols.GetColArray(1).customWidth); Assert.AreEqual(1, cols.GetColArray(2).outlineLevel); - Assert.AreEqual(6, cols.GetColArray(2).min); // 1 based - Assert.AreEqual(6, cols.GetColArray(2).max); // 1 based - Assert.AreEqual(false, cols.GetColArray(2).customWidth); + Assert.AreEqual(5, cols.GetColArray(2).min); // 1 based + Assert.AreEqual(5, cols.GetColArray(2).max); // 1 based + Assert.AreEqual(true, cols.GetColArray(2).customWidth); + + Assert.AreEqual(1, cols.GetColArray(3).outlineLevel); + Assert.AreEqual(6, cols.GetColArray(3).min); // 1 based + Assert.AreEqual(6, cols.GetColArray(3).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(3).customWidth); - Assert.AreEqual(3, cols.sizeOfColArray()); + Assert.AreEqual(4, cols.sizeOfColArray()); wb = XSSFTestDataSamples.WriteOutAndReadBack(wb, "testMergingOverlappingCols_OVERLAPS_1_MINOR"); sheet = (XSSFSheet)wb.GetSheet("test"); @@ -249,14 +258,13 @@ public void TestMergingOverlappingCols_OVERLAPS_2_MINOR() XSSFWorkbook wb = new XSSFWorkbook(); XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("test"); - CT_Cols cols = sheet.GetCTWorksheet().GetColsArray(0); - CT_Col col = cols.AddNewCol(); - col.min=(2 + 1); - col.max=(4 + 1); - col.width=(20); - col.customWidth=(true); + sheet.CreateColumn(2).Width = 20; + sheet.CreateColumn(3).Width = 20; + sheet.CreateColumn(4).Width = 20; - sheet.GroupColumn((short)1, (short)3); + sheet.GroupColumn(1, 3); + + CT_Cols cols = sheet.GetCTWorksheet().GetColsArray(0); cols = sheet.GetCTWorksheet().GetColsArray(0); //logger.log(POILogger.DEBUG, "testMergingOverlappingCols_OVERLAPS_2_MINOR/cols:" + cols); @@ -268,15 +276,20 @@ public void TestMergingOverlappingCols_OVERLAPS_2_MINOR() Assert.AreEqual(1, cols.GetColArray(1).outlineLevel); Assert.AreEqual(3, cols.GetColArray(1).min); // 1 based - Assert.AreEqual(4, cols.GetColArray(1).max); // 1 based + Assert.AreEqual(3, cols.GetColArray(1).max); // 1 based Assert.AreEqual(true, cols.GetColArray(1).customWidth); - Assert.AreEqual(0, cols.GetColArray(2).outlineLevel); - Assert.AreEqual(5, cols.GetColArray(2).min); // 1 based - Assert.AreEqual(5, cols.GetColArray(2).max); // 1 based + Assert.AreEqual(1, cols.GetColArray(2).outlineLevel); + Assert.AreEqual(4, cols.GetColArray(2).min); // 1 based + Assert.AreEqual(4, cols.GetColArray(2).max); // 1 based Assert.AreEqual(true, cols.GetColArray(2).customWidth); - Assert.AreEqual(3, cols.sizeOfColArray()); + Assert.AreEqual(0, cols.GetColArray(3).outlineLevel); + Assert.AreEqual(5, cols.GetColArray(3).min); // 1 based + Assert.AreEqual(5, cols.GetColArray(3).max); // 1 based + Assert.AreEqual(true, cols.GetColArray(3).customWidth); + + Assert.AreEqual(4, cols.sizeOfColArray()); wb = XSSFTestDataSamples.WriteOutAndReadBack(wb, "testMergingOverlappingCols_OVERLAPS_2_MINOR"); sheet = (XSSFSheet)wb.GetSheet("test"); diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFColumn.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFColumn.cs new file mode 100644 index 000000000..d2702cf4e --- /dev/null +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFColumn.cs @@ -0,0 +1,867 @@ +/* ==================================================================== + 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.UserModel; +using NPOI.SS.Util; +using NPOI.Util; +using NPOI.XSSF.UserModel; +using NUnit.Framework; +using System; +using System.IO; +using System.Linq; + +namespace TestCases.XSSF.UserModel +{ + [TestFixture] + public class TestXSSFColumn + { + public TestXSSFColumn() + { + + } + + [Test] + public void Sheet_SheetIsNotNull() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + int columnIndex = 10; + IColumn column = sheet.CreateColumn(columnIndex); + + Assert.NotNull(column.Sheet); + Assert.AreEqual(column.Sheet, sheet); + + FileInfo file = TempFile.CreateTempFile("poi-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + IColumn columnLoaded = sheetLoaded.GetColumn(columnIndex); + + Assert.NotNull(columnLoaded.Sheet); + Assert.AreEqual(columnLoaded.Sheet, sheetLoaded); + } + + [Test] + public void FirstCellNumTest() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + int columnIndex = 10; + IColumn column1 = sheet.CreateColumn(columnIndex); + IColumn column2 = sheet.CreateColumn(columnIndex + 1); + int firstRowNum = 5; + int numOfCells = 10; + + for (int i = 0; i < numOfCells; i++) + { + _ = column2.CreateCell(firstRowNum + i); + } + + for (int i = 0; i < numOfCells; i++) + { + _ = column2.CreateCell(firstRowNum + 20 + i); + } + + Assert.AreEqual(-1, column1.FirstCellNum); + Assert.AreEqual(firstRowNum, column2.FirstCellNum); + + FileInfo file = TempFile.CreateTempFile("poi-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + IColumn column1Loaded = sheetLoaded.GetColumn(columnIndex); + IColumn column2Loaded = sheetLoaded.GetColumn(columnIndex + 1); + + Assert.AreEqual(-1, column1Loaded.FirstCellNum); + Assert.AreEqual(firstRowNum, column2Loaded.FirstCellNum); + } + + [Test] + public void LastCellNumTest() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + int columnIndex = 10; + IColumn column1 = sheet.CreateColumn(columnIndex); + IColumn column2 = sheet.CreateColumn(columnIndex + 1); + int firstRowNum = 5; + int numOfCells = 10; + + for (int i = 0; i < numOfCells; i++) + { + _ = column2.CreateCell(firstRowNum + i); + } + + for (int i = 0; i < numOfCells; i++) + { + _ = column2.CreateCell(firstRowNum + 20 + i); + } + + Assert.AreEqual(-1, column1.LastCellNum); + Assert.AreEqual(firstRowNum + 30, column2.LastCellNum); + + FileInfo file = TempFile.CreateTempFile("poi-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + IColumn column1Loaded = sheetLoaded.GetColumn(columnIndex); + IColumn column2Loaded = sheetLoaded.GetColumn(columnIndex + 1); + + Assert.AreEqual(-1, column1Loaded.LastCellNum); + Assert.AreEqual(firstRowNum + 30, column2Loaded.LastCellNum); + } + + [Test] + public void WidthTest() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + int columnIndex = 10; + IColumn column1 = sheet.CreateColumn(columnIndex); + IColumn column2 = sheet.CreateColumn(columnIndex + 1); + short width = 20; + + column2.Width = width; + + Assert.AreEqual(sheet.DefaultColumnWidth, column1.Width); + Assert.AreEqual(width, column2.Width); + + FileInfo file = TempFile.CreateTempFile("poi-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + IColumn column1Loaded = sheetLoaded.GetColumn(columnIndex); + IColumn column2Loaded = sheetLoaded.GetColumn(columnIndex + 1); + + Assert.AreEqual(sheetLoaded.DefaultColumnWidth, column1Loaded.Width); + Assert.AreEqual(width, column2Loaded.Width); + } + + [Test] + public void PhysicalNumberOfCellsTest() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + int columnIndex = 10; + IColumn column1 = sheet.CreateColumn(columnIndex); + IColumn column2 = sheet.CreateColumn(columnIndex + 1); + int firstRowNum = 5; + int numOfCells = 10; + + for (int i = 0; i < numOfCells; i++) + { + _ = column2.CreateCell(firstRowNum + i); + } + + for (int i = 0; i < numOfCells; i++) + { + _ = column2.CreateCell(firstRowNum + 20 + i); + } + + column2.RemoveCell( + sheet.GetRow(firstRowNum).GetCell(column2.ColumnNum)); + + Assert.AreEqual(0, column1.PhysicalNumberOfCells); + Assert.AreEqual((numOfCells * 2) - 1, column2.PhysicalNumberOfCells); + + FileInfo file = TempFile.CreateTempFile("poi-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + IColumn column1Loaded = sheetLoaded.GetColumn(columnIndex); + IColumn column2Loaded = sheetLoaded.GetColumn(columnIndex + 1); + + Assert.AreEqual(0, column1Loaded.PhysicalNumberOfCells); + Assert.AreEqual((numOfCells * 2) - 1, column2Loaded.PhysicalNumberOfCells); + } + + [Test] + public void ZeroWidthTest() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + int columnIndex = 10; + IColumn column1 = sheet.CreateColumn(columnIndex); + IColumn column2 = sheet.CreateColumn(columnIndex + 1); + short width = 20; + + column2.Width = width; + column2.ZeroWidth = true; + + Assert.IsFalse(column1.ZeroWidth); + Assert.AreEqual(sheet.DefaultColumnWidth, column1.Width); + Assert.IsTrue(column2.ZeroWidth); + Assert.AreEqual(width, column2.Width); + + FileInfo file = TempFile.CreateTempFile("poi-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + IColumn column1Loaded = sheetLoaded.GetColumn(columnIndex); + IColumn column2Loaded = sheetLoaded.GetColumn(columnIndex + 1); + + Assert.IsFalse(column1Loaded.ZeroWidth); + Assert.AreEqual(sheetLoaded.DefaultColumnWidth, column1Loaded.Width); + Assert.IsTrue(column2Loaded.ZeroWidth); + Assert.AreEqual(width, column2Loaded.Width); + } + + [Test] + public void ColumnStyleTest() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + int columnIndex = 10; + IColumn column1 = sheet.CreateColumn(columnIndex); + IColumn column2 = sheet.CreateColumn(columnIndex + 1); + IColumn column3 = sheet.CreateColumn(columnIndex + 2); + + ICellStyle cellStyle = wb.CreateCellStyle(); + cellStyle.BorderLeft = BorderStyle.Double; + + column2.ColumnStyle = cellStyle; + column3.ColumnStyle = cellStyle; + + Assert.IsNull(column1.ColumnStyle); + Assert.AreEqual(BorderStyle.None, column1.CreateCell(1).CellStyle.BorderLeft); + Assert.IsNotNull(column2.ColumnStyle); + Assert.AreEqual(BorderStyle.Double, column2.ColumnStyle.BorderLeft); + Assert.AreEqual(BorderStyle.Double, column2.CreateCell(1).CellStyle.BorderLeft); + Assert.AreEqual(BorderStyle.Double, column3.ColumnStyle.BorderLeft); + Assert.AreEqual(BorderStyle.Double, column3.CreateCell(1).CellStyle.BorderLeft); + + column3.ColumnStyle = null; + + Assert.IsNull(column3.ColumnStyle); + Assert.AreEqual(BorderStyle.None, column3.Cells.FirstOrDefault().CellStyle.BorderLeft); + + FileInfo file = TempFile.CreateTempFile("poi-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + IColumn column1Loaded = sheetLoaded.GetColumn(columnIndex); + IColumn column2Loaded = sheetLoaded.GetColumn(columnIndex + 1); + IColumn column3Loaded = sheetLoaded.GetColumn(columnIndex + 2); + + Assert.IsNull(column1Loaded.ColumnStyle); + Assert.AreEqual(BorderStyle.None, column1Loaded.GetCell(1).CellStyle.BorderLeft); + Assert.IsNotNull(column2Loaded.ColumnStyle); + Assert.AreEqual(BorderStyle.Double, column2Loaded.ColumnStyle.BorderLeft); + Assert.AreEqual(BorderStyle.Double, column2Loaded.GetCell(1).CellStyle.BorderLeft); + Assert.IsNull(column3Loaded.ColumnStyle); + Assert.AreEqual(BorderStyle.None, column3Loaded.Cells.FirstOrDefault().CellStyle.BorderLeft); + } + + [Test] + public void IsFormattedTest() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + int columnIndex = 10; + IColumn column1 = sheet.CreateColumn(columnIndex); + IColumn column2 = sheet.CreateColumn(columnIndex + 1); + + ICellStyle cellStyle = wb.CreateCellStyle(); + cellStyle.BorderLeft = BorderStyle.Double; + + column2.ColumnStyle = cellStyle; + + Assert.IsFalse(column1.IsFormatted); + Assert.IsTrue(column2.IsFormatted); + + FileInfo file = TempFile.CreateTempFile("poi-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + IColumn column1Loaded = sheetLoaded.GetColumn(columnIndex); + IColumn column2Loaded = sheetLoaded.GetColumn(columnIndex + 1); + + Assert.IsFalse(column1Loaded.IsFormatted); + Assert.IsTrue(column2Loaded.IsFormatted); + } + + [Test] + public void CreateCell_WithValidIndex_CellCreated() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + int columnIndex = 10; + int rowIndex = 10; + IColumn column = sheet.CreateColumn(columnIndex); + ICell cell = column.CreateCell(rowIndex); + + Assert.NotNull(cell); + Assert.AreEqual(CellType.Blank, cell.CellType); + Assert.NotNull(sheet.GetRow(rowIndex)); + Assert.NotNull(sheet.GetRow(rowIndex).GetCell(columnIndex)); + + FileInfo file = TempFile.CreateTempFile("poi-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + ICell cellLoaded = sheetLoaded.GetColumn(columnIndex).GetCell(rowIndex); + + Assert.NotNull(cellLoaded); + Assert.AreEqual(CellType.Blank, cellLoaded.CellType); + Assert.NotNull(sheetLoaded.GetRow(rowIndex)); + Assert.NotNull(sheetLoaded.GetRow(rowIndex).GetCell(columnIndex)); + } + + [Test] + public void CreateCell_WithInValidIndex_ExceptiomnIsThrown() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + int columnIndex = 10; + + IColumn column = sheet.CreateColumn(columnIndex); + + _ = Assert.Throws(() => column.CreateCell(-1)); + _ = Assert.Throws(() => column.CreateCell(2000000)); + } + + [Test] + public void CreateCell_WithValidIndexVariousTypes_CellsCreatedWithCorrectTypes() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + int columnIndex = 10; + IColumn column = sheet.CreateColumn(columnIndex); + _ = column.CreateCell(0, CellType.Blank); + _ = column.CreateCell(1, CellType.Boolean); + _ = column.CreateCell(2, CellType.Error); + _ = column.CreateCell(3, CellType.Formula); + _ = column.CreateCell(4, CellType.Numeric); + _ = column.CreateCell(5, CellType.String); + + for (int i = 0; i <= 5; i++) + { + Assert.NotNull(sheet.GetRow(i)); + Assert.NotNull(sheet.GetRow(i).GetCell(columnIndex)); + } + + Assert.AreEqual(CellType.Blank, sheet.GetRow(0).GetCell(columnIndex).CellType); + Assert.AreEqual(CellType.Boolean, sheet.GetRow(1).GetCell(columnIndex).CellType); + Assert.AreEqual(CellType.Error, sheet.GetRow(2).GetCell(columnIndex).CellType); + Assert.AreEqual(CellType.Formula, sheet.GetRow(3).GetCell(columnIndex).CellType); + Assert.AreEqual(CellType.Blank, sheet.GetRow(4).GetCell(columnIndex).CellType); // Numeric cell with no data will return blank by default + Assert.AreEqual(CellType.String, sheet.GetRow(5).GetCell(columnIndex).CellType); + + _ = Assert.Throws(() => column.CreateCell(6, CellType.Unknown)); + Assert.IsNull(sheet.GetRow(6)); + Assert.IsNull(column.GetCell(6)); + + FileInfo file = TempFile.CreateTempFile("poi-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + + for (int i = 0; i <= 5; i++) + { + Assert.NotNull(sheetLoaded.GetRow(i)); + Assert.NotNull(sheetLoaded.GetRow(i).GetCell(columnIndex)); + } + + Assert.AreEqual(CellType.Blank, sheetLoaded.GetRow(0).GetCell(columnIndex).CellType); + Assert.AreEqual(CellType.Boolean, sheetLoaded.GetRow(1).GetCell(columnIndex).CellType); + Assert.AreEqual(CellType.Error, sheetLoaded.GetRow(2).GetCell(columnIndex).CellType); + Assert.AreEqual(CellType.Formula, sheetLoaded.GetRow(3).GetCell(columnIndex).CellType); + Assert.AreEqual(CellType.Blank, sheetLoaded.GetRow(4).GetCell(columnIndex).CellType); + Assert.AreEqual(CellType.String, sheetLoaded.GetRow(5).GetCell(columnIndex).CellType); + + Assert.IsNull(sheetLoaded.GetRow(6)); + Assert.IsNull(sheetLoaded.GetColumn(columnIndex).GetCell(6)); + } + + [Test] + public void GetCell_GetExistingAndNonExistinCells_CellsReturnedWhenExistsNullsWhenNot() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + int columnIndex = 10; + int rowIndex = 10; + IColumn column = sheet.CreateColumn(columnIndex); + _ = column.CreateCell(rowIndex); + ICell cell = column.GetCell(rowIndex); + _ = sheet.CreateRow(rowIndex + 1).CreateCell(columnIndex); + + Assert.IsNotNull(cell); + Assert.AreEqual(columnIndex, cell.ColumnIndex); + Assert.AreEqual(rowIndex, cell.RowIndex); + Assert.IsNull(column.GetCell(0)); + Assert.IsNotNull(column.GetCell(rowIndex + 1)); + + FileInfo file = TempFile.CreateTempFile("poi-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + IColumn columnLoaded = sheetLoaded.GetColumn(columnIndex); + ICell cellLoaded = columnLoaded.GetCell(rowIndex); + + Assert.IsNotNull(cellLoaded); + Assert.AreEqual(columnIndex, cellLoaded.ColumnIndex); + Assert.AreEqual(rowIndex, cellLoaded.RowIndex); + Assert.IsNull(columnLoaded.GetCell(0)); + Assert.IsNotNull(columnLoaded.GetCell(rowIndex + 1)); + } + + [Test] + public void GetCell_GetExistingCells_CellsReturned() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + int columnIndex = 10; + int rowIndex = 10; + IColumn column = sheet.CreateColumn(columnIndex); + + _ = column.CreateCell(rowIndex, CellType.Blank); + column.CreateCell(rowIndex + 1, CellType.Blank).SetCellValue(1); + _ = column.CreateCell(rowIndex + 2, CellType.Numeric); + column.CreateCell(rowIndex + 3, CellType.Numeric).SetCellValue(1); + + Assert.IsNotNull(column.GetCell(rowIndex, MissingCellPolicy.RETURN_NULL_AND_BLANK)); + Assert.IsNotNull(column.GetCell(rowIndex + 1, MissingCellPolicy.RETURN_NULL_AND_BLANK)); + Assert.IsNotNull(column.GetCell(rowIndex + 2, MissingCellPolicy.RETURN_NULL_AND_BLANK)); + Assert.IsNotNull(column.GetCell(rowIndex + 3, MissingCellPolicy.RETURN_NULL_AND_BLANK)); + Assert.IsNull(column.GetCell(rowIndex + 4, MissingCellPolicy.RETURN_NULL_AND_BLANK)); + + Assert.IsNull(column.GetCell(rowIndex, MissingCellPolicy.RETURN_BLANK_AS_NULL)); + Assert.IsNotNull(column.GetCell(rowIndex + 1, MissingCellPolicy.RETURN_BLANK_AS_NULL)); + Assert.IsNull(column.GetCell(rowIndex + 2, MissingCellPolicy.RETURN_BLANK_AS_NULL)); + Assert.IsNotNull(column.GetCell(rowIndex + 3, MissingCellPolicy.RETURN_BLANK_AS_NULL)); + Assert.IsNull(column.GetCell(rowIndex + 4, MissingCellPolicy.RETURN_BLANK_AS_NULL)); + + Assert.IsNotNull(column.GetCell(rowIndex, MissingCellPolicy.CREATE_NULL_AS_BLANK)); + Assert.IsNotNull(column.GetCell(rowIndex + 1, MissingCellPolicy.CREATE_NULL_AS_BLANK)); + Assert.IsNotNull(column.GetCell(rowIndex + 2, MissingCellPolicy.CREATE_NULL_AS_BLANK)); + Assert.IsNotNull(column.GetCell(rowIndex + 3, MissingCellPolicy.CREATE_NULL_AS_BLANK)); + Assert.IsNotNull(column.GetCell(rowIndex + 4, MissingCellPolicy.CREATE_NULL_AS_BLANK)); + } + + [Test] + public void RemoveCell_RemoveExistingCells_CellsAreRemoved() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + int columnIndex = 10; + int rowIndex = 10; + int middleRowIndex = 15; + int initialNumberOfCells = 10; + IColumn column = sheet.CreateColumn(columnIndex); + + for (int i = 0; i < initialNumberOfCells; i++) + { + _ = column.CreateCell(rowIndex + i); + } + + Assert.AreEqual(initialNumberOfCells, column.PhysicalNumberOfCells); + Assert.AreEqual(rowIndex, column.FirstCellNum); + Assert.AreEqual(rowIndex + initialNumberOfCells, column.LastCellNum); + + column.RemoveCell(column.GetCell(column.FirstCellNum)); + column.RemoveCell(column.GetCell(column.LastCellNum - 1)); + column.RemoveCell(column.GetCell(middleRowIndex)); + + Assert.AreEqual(initialNumberOfCells - 3, column.PhysicalNumberOfCells); + Assert.AreEqual(rowIndex + 1, column.FirstCellNum); + Assert.AreEqual(rowIndex + initialNumberOfCells - 1, column.LastCellNum); + Assert.IsNull(column.GetCell(rowIndex)); + Assert.IsNull(column.GetCell(middleRowIndex)); + Assert.IsNull(column.GetCell(rowIndex + initialNumberOfCells)); + Assert.IsNull(sheet.GetRow(rowIndex).GetCell(columnIndex)); + Assert.IsNull(sheet.GetRow(middleRowIndex).GetCell(columnIndex)); + Assert.IsNull(sheet.GetRow(rowIndex + initialNumberOfCells - 1).GetCell(columnIndex)); + } + + [Test] + public void RemoveCell_RemoveCellNotBelongingToColumn_ExceptionThrownCellIsNotRemoved() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + int columnIndex = 10; + int rowIndex = 10; + IColumn column = sheet.CreateColumn(columnIndex); + IRow row = sheet.CreateRow(rowIndex); + ICell cell = row.CreateCell(columnIndex + 1); + + _ = Assert.Throws(() => column.RemoveCell(cell)); + _ = Assert.Throws(() => column.RemoveCell(null)); + Assert.IsNotNull(row.GetCell(columnIndex + 1)); + } + + [Test] + public void CopyColumnFrom_CopyOverExistingCells_ExistingCellsAreReplacedByCellsFromCopiedColumn() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFFormulaEvaluator fe = new XSSFFormulaEvaluator(wb); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + XSSFDrawing dg = (XSSFDrawing)sheet.CreateDrawingPatriarch(); + XSSFComment comment = (XSSFComment)dg.CreateCellComment(new XSSFClientAnchor()); + comment.Author = "POI"; + comment.String = new XSSFRichTextString("A new comment"); + int originalColIndex = 1; + int copyColIndex = 4; + short width = 20; + int mergedRegionFirstRow = 10; + int mergedRegionLastRow = 20; + int firstFormulaCellValue = 10; + int secondFormulaCellValue = 20; + int formulaResult = firstFormulaCellValue + secondFormulaCellValue; + int cellToBeErasedRowIndex = 25; + + XSSFColumn anotherColumn = (XSSFColumn)sheet.CreateColumn(copyColIndex); + anotherColumn.CreateCell(0).SetCellValue("POI"); + anotherColumn.Width = (short)(width * 2); + anotherColumn.CreateCell(0).SetCellValue("POI"); + anotherColumn.CreateCell(cellToBeErasedRowIndex).SetCellValue("POI"); + XSSFColumn originalColumn = (XSSFColumn)sheet.CreateColumn(originalColIndex); + originalColumn.Width = width; + XSSFCell formulaCell1 = (XSSFCell)originalColumn.CreateCell(0); + formulaCell1.SetCellFormula("C1 + D1"); + formulaCell1.CellComment = comment; + sheet.CreateColumn(originalColIndex + 1).CreateCell(0).SetCellValue(firstFormulaCellValue); + sheet.CreateColumn(originalColIndex + 2).CreateCell(0).SetCellValue(secondFormulaCellValue); + sheet.GetRow(0).CreateCell(originalColIndex + 1 + 3).SetCellValue(firstFormulaCellValue); + sheet.GetRow(0).CreateCell(originalColIndex + 2 + 3).SetCellValue(secondFormulaCellValue); + originalColumn.CreateCell(mergedRegionFirstRow).SetCellValue("POI"); + _ = sheet.AddMergedRegion( + new CellRangeAddress( + mergedRegionFirstRow, + mergedRegionLastRow, + originalColumn.ColumnNum, + originalColumn.ColumnNum)); + CellRangeAddress originaMergedRegion = sheet.GetMergedRegion(0); + + fe.EvaluateAll(); + + Assert.AreEqual("POI", sheet.GetRow(mergedRegionFirstRow).GetCell(originalColIndex).StringCellValue); + Assert.AreEqual("POI", formulaCell1.CellComment.Author); + Assert.AreEqual(formulaResult, formulaCell1.NumericCellValue); + Assert.AreEqual(1, sheet.NumMergedRegions); + Assert.NotNull(originaMergedRegion); + + anotherColumn.CopyColumnFrom(originalColumn, new CellCopyPolicy()); + CellRangeAddress copyMergedRegion = sheet.GetMergedRegion(1); + fe.EvaluateAll(); + + XSSFCell formulaCell2 = (XSSFCell)sheet.GetColumn(copyColIndex).GetCell(0); + + Assert.AreEqual(copyColIndex, anotherColumn.ColumnNum); + Assert.AreEqual(1, sheet.FirstColumnNum); + Assert.AreEqual(4, sheet.LastColumnNum); + Assert.AreEqual(width, anotherColumn.Width); + Assert.AreEqual("POI", sheet.GetRow(mergedRegionFirstRow).GetCell(copyColIndex).StringCellValue); + Assert.AreEqual("F1+G1", formulaCell2.CellFormula); + Assert.AreEqual(formulaResult, formulaCell2.NumericCellValue); + //Assert.IsNull(anotherColumn.GetCell(cellToBeErasedRowIndex)); + Assert.AreEqual(2, sheet.NumMergedRegions); + Assert.NotNull(originaMergedRegion); + Assert.NotNull(copyMergedRegion); + Assert.AreEqual(mergedRegionFirstRow, copyMergedRegion.FirstRow); + Assert.AreEqual(mergedRegionLastRow, copyMergedRegion.LastRow); + Assert.AreEqual(anotherColumn.ColumnNum, copyMergedRegion.FirstColumn); + Assert.AreEqual(anotherColumn.ColumnNum, copyMergedRegion.LastColumn); + + FileInfo file = TempFile.CreateTempFile("CopyColumnFrom-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFFormulaEvaluator feLoaded = new XSSFFormulaEvaluator(wbLoaded); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + XSSFColumn originalColumnLoaded = (XSSFColumn)sheetLoaded.GetColumn(originalColIndex); + XSSFColumn copyColumnLoaded = (XSSFColumn)sheetLoaded.GetColumn(copyColIndex); + XSSFCell formulaCellLoaded = (XSSFCell)copyColumnLoaded.GetCell(0); + CellRangeAddress originalMergedRegionLoaded = sheet.GetMergedRegion(0); + CellRangeAddress copyMergedRegionLoaded = sheet.GetMergedRegion(1); + + feLoaded.EvaluateAll(); + + Assert.AreEqual(1, sheetLoaded.FirstColumnNum); + Assert.AreEqual(4, sheetLoaded.LastColumnNum); + Assert.AreEqual(width, copyColumnLoaded.Width); + Assert.AreEqual(firstFormulaCellValue, sheetLoaded.GetColumn(originalColIndex + 1).GetCell(0).NumericCellValue); + Assert.AreEqual(secondFormulaCellValue, sheetLoaded.GetColumn(originalColIndex + 2).GetCell(0).NumericCellValue); + Assert.AreEqual("POI", sheetLoaded.GetRow(mergedRegionFirstRow).GetCell(copyColIndex).StringCellValue); + Assert.AreEqual("F1+G1", formulaCellLoaded.CellFormula); + Assert.AreEqual(formulaResult, formulaCellLoaded.NumericCellValue); + Assert.NotNull(originalMergedRegionLoaded); + Assert.AreEqual(mergedRegionFirstRow, originalMergedRegionLoaded.FirstRow); + Assert.AreEqual(mergedRegionLastRow, originalMergedRegionLoaded.LastRow); + Assert.AreEqual(originalColumnLoaded.ColumnNum, originalMergedRegionLoaded.FirstColumn); + Assert.AreEqual(originalColumnLoaded.ColumnNum, originalMergedRegionLoaded.LastColumn); + Assert.NotNull(copyMergedRegionLoaded); + Assert.AreEqual(mergedRegionFirstRow, copyMergedRegionLoaded.FirstRow); + Assert.AreEqual(mergedRegionLastRow, copyMergedRegionLoaded.LastRow); + Assert.AreEqual(copyColumnLoaded.ColumnNum, copyMergedRegionLoaded.FirstColumn); + Assert.AreEqual(copyColumnLoaded.ColumnNum, copyMergedRegionLoaded.LastColumn); + } + + [Test] + public void CopyColumnFrom_CopyOntoEmptyColumn_CopiedCellsAreAddedToColumn() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFFormulaEvaluator fe = new XSSFFormulaEvaluator(wb); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + XSSFDrawing dg = (XSSFDrawing)sheet.CreateDrawingPatriarch(); + XSSFComment comment = (XSSFComment)dg.CreateCellComment(new XSSFClientAnchor()); + comment.Author = "POI"; + comment.String = new XSSFRichTextString("A new comment"); + int originalColIndex = 1; + int copyColIndex = 4; + short width = 20; + int mergedRegionFirstRow = 10; + int mergedRegionLastRow = 20; + int firstFormulaCellValue = 10; + int secondFormulaCellValue = 20; + int formulaResult = firstFormulaCellValue + secondFormulaCellValue; + + XSSFColumn anotherColumn = (XSSFColumn)sheet.CreateColumn(copyColIndex); + XSSFColumn originalColumn = (XSSFColumn)sheet.CreateColumn(originalColIndex); + originalColumn.Width = width; + XSSFCell formulaCell1 = (XSSFCell)originalColumn.CreateCell(0); + formulaCell1.SetCellFormula("C1 + D1"); + formulaCell1.CellComment = comment; + sheet.CreateColumn(originalColIndex + 1).CreateCell(0).SetCellValue(firstFormulaCellValue); + sheet.CreateColumn(originalColIndex + 2).CreateCell(0).SetCellValue(secondFormulaCellValue); + sheet.GetRow(0).CreateCell(originalColIndex + 1 + 3).SetCellValue(firstFormulaCellValue); + sheet.GetRow(0).CreateCell(originalColIndex + 2 + 3).SetCellValue(secondFormulaCellValue); + originalColumn.CreateCell(mergedRegionFirstRow).SetCellValue("POI"); + _ = sheet.AddMergedRegion( + new CellRangeAddress( + mergedRegionFirstRow, + mergedRegionLastRow, + originalColumn.ColumnNum, + originalColumn.ColumnNum)); + CellRangeAddress originaMergedRegion = sheet.GetMergedRegion(0); + + fe.EvaluateAll(); + + Assert.AreEqual("POI", sheet.GetRow(mergedRegionFirstRow).GetCell(originalColIndex).StringCellValue); + Assert.AreEqual("POI", formulaCell1.CellComment.Author); + Assert.AreEqual(formulaResult, formulaCell1.NumericCellValue); + Assert.AreEqual(1, sheet.NumMergedRegions); + Assert.NotNull(originaMergedRegion); + + anotherColumn.CopyColumnFrom(originalColumn, new CellCopyPolicy() { IsCopyColumnWidth = false }); + CellRangeAddress copyMergedRegion = sheet.GetMergedRegion(1); + fe.EvaluateAll(); + + XSSFCell formulaCell2 = (XSSFCell)sheet.GetColumn(copyColIndex).GetCell(0); + + Assert.AreEqual(copyColIndex, anotherColumn.ColumnNum); + Assert.AreEqual(1, sheet.FirstColumnNum); + Assert.AreEqual(4, sheet.LastColumnNum); + Assert.AreNotEqual(width, anotherColumn.Width); + Assert.AreEqual("POI", sheet.GetRow(mergedRegionFirstRow).GetCell(copyColIndex).StringCellValue); + Assert.AreEqual("F1+G1", formulaCell2.CellFormula); + Assert.AreEqual(formulaResult, formulaCell2.NumericCellValue); + Assert.AreEqual(2, sheet.NumMergedRegions); + Assert.NotNull(originaMergedRegion); + Assert.NotNull(copyMergedRegion); + Assert.AreEqual(mergedRegionFirstRow, copyMergedRegion.FirstRow); + Assert.AreEqual(mergedRegionLastRow, copyMergedRegion.LastRow); + Assert.AreEqual(anotherColumn.ColumnNum, copyMergedRegion.FirstColumn); + Assert.AreEqual(anotherColumn.ColumnNum, copyMergedRegion.LastColumn); + + FileInfo file = TempFile.CreateTempFile("CopyColumnFrom-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFFormulaEvaluator feLoaded = new XSSFFormulaEvaluator(wbLoaded); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + XSSFColumn originalColumnLoaded = (XSSFColumn)sheetLoaded.GetColumn(originalColIndex); + XSSFColumn copyColumnLoaded = (XSSFColumn)sheetLoaded.GetColumn(copyColIndex); + XSSFCell formulaCellLoaded = (XSSFCell)copyColumnLoaded.GetCell(0); + CellRangeAddress originalMergedRegionLoaded = sheet.GetMergedRegion(0); + CellRangeAddress copyMergedRegionLoaded = sheet.GetMergedRegion(1); + + feLoaded.EvaluateAll(); + + Assert.AreEqual(1, sheetLoaded.FirstColumnNum); + Assert.AreEqual(4, sheetLoaded.LastColumnNum); + + Assert.AreNotEqual(width, copyColumnLoaded.Width); + Assert.AreEqual(firstFormulaCellValue, sheetLoaded.GetColumn(originalColIndex + 1).GetCell(0).NumericCellValue); + Assert.AreEqual(secondFormulaCellValue, sheetLoaded.GetColumn(originalColIndex + 2).GetCell(0).NumericCellValue); + Assert.AreEqual("POI", sheetLoaded.GetRow(mergedRegionFirstRow).GetCell(copyColIndex).StringCellValue); + Assert.AreEqual("F1+G1", formulaCellLoaded.CellFormula); + Assert.AreEqual(formulaResult, formulaCellLoaded.NumericCellValue); + Assert.NotNull(originalMergedRegionLoaded); + Assert.AreEqual(mergedRegionFirstRow, originalMergedRegionLoaded.FirstRow); + Assert.AreEqual(mergedRegionLastRow, originalMergedRegionLoaded.LastRow); + Assert.AreEqual(originalColumnLoaded.ColumnNum, originalMergedRegionLoaded.FirstColumn); + Assert.AreEqual(originalColumnLoaded.ColumnNum, originalMergedRegionLoaded.LastColumn); + Assert.NotNull(copyMergedRegionLoaded); + Assert.AreEqual(mergedRegionFirstRow, copyMergedRegionLoaded.FirstRow); + Assert.AreEqual(mergedRegionLastRow, copyMergedRegionLoaded.LastRow); + Assert.AreEqual(copyColumnLoaded.ColumnNum, copyMergedRegionLoaded.FirstColumn); + Assert.AreEqual(copyColumnLoaded.ColumnNum, copyMergedRegionLoaded.LastColumn); + } + + [Test] + public void CopyColumnFrom_CopyFromNull_ExistingCellsAreReplacedWithNull() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + int copyColIndex = 4; + int cellToBeErasedRowIndex = 25; + + XSSFColumn anotherColumn = (XSSFColumn)sheet.CreateColumn(copyColIndex); + anotherColumn.CreateCell(0).SetCellValue("POI"); + anotherColumn.CreateCell(cellToBeErasedRowIndex).SetCellValue("POI"); + + anotherColumn.CopyColumnFrom(null, new CellCopyPolicy()); + + Assert.AreEqual(copyColIndex, anotherColumn.ColumnNum); + Assert.AreEqual(4, sheet.FirstColumnNum); + Assert.AreEqual(4, sheet.LastColumnNum); + Assert.AreEqual("", anotherColumn.GetCell(0).StringCellValue); + Assert.AreEqual("", anotherColumn.GetCell(cellToBeErasedRowIndex).StringCellValue); + } + + [Test] + public void CopyColumnFrom_FromExternalSheet() + { + XSSFWorkbook workbook = new XSSFWorkbook(); + XSSFSheet srcSheet = (XSSFSheet)workbook.CreateSheet("src"); + XSSFSheet destSheet = workbook.CreateSheet("dest") as XSSFSheet; + _ = workbook.CreateSheet("other"); + + IColumn srcColumn = srcSheet.CreateColumn(0); + int col = 0; + //Test 2D and 3D Ref Ptgs (Pxg for OOXML Workbooks) + srcColumn.CreateCell(col++).CellFormula = "E5"; + srcColumn.CreateCell(col++).CellFormula = "src!E5"; + srcColumn.CreateCell(col++).CellFormula = "dest!E5"; + srcColumn.CreateCell(col++).CellFormula = "other!E5"; + + //Test 2D and 3D Ref Ptgs with absolute column + srcColumn.CreateCell(col++).CellFormula = "$E5"; + srcColumn.CreateCell(col++).CellFormula = "src!$E5"; + srcColumn.CreateCell(col++).CellFormula = "dest!$E5"; + srcColumn.CreateCell(col++).CellFormula = "other!$E5"; + + //Test 2D and 3D Area Ptgs (Pxg for OOXML Workbooks) + srcColumn.CreateCell(col++).CellFormula = "SUM(E5:$E10)"; + srcColumn.CreateCell(col++).CellFormula = "SUM(src!E5:$E10)"; + srcColumn.CreateCell(col++).CellFormula = "SUM(dest!E5:$E10)"; + srcColumn.CreateCell(col++).CellFormula = "SUM(other!E5:$E10)"; + ////////////////// + XSSFColumn destColumn = destSheet.CreateColumn(1) as XSSFColumn; + destColumn.CopyColumnFrom(srcColumn, new CellCopyPolicy()); + + ////////////////// + + //Test 2D and 3D Ref Ptgs (Pxg for OOXML Workbooks) + col = 0; + ICell cell = destColumn.GetCell(col++); + Assert.IsNotNull(cell); + Assert.AreEqual("F5", cell.CellFormula, "RefPtg"); + + cell = destColumn.GetCell(col++); + Assert.IsNotNull(cell); + Assert.AreEqual("src!F5", cell.CellFormula, "Ref3DPtg"); + + cell = destColumn.GetCell(col++); + Assert.IsNotNull(cell); + Assert.AreEqual("dest!F5", cell.CellFormula, "Ref3DPtg"); + + cell = destColumn.GetCell(col++); + Assert.IsNotNull(cell); + Assert.AreEqual("other!F5", cell.CellFormula, "Ref3DPtg"); + + ///////////////////////////////////////////// + + //Test 2D and 3D Ref Ptgs with absolute column (Ptg column number shouldn't change) + cell = destColumn.GetCell(col++); + Assert.IsNotNull(cell); + Assert.AreEqual("$E5", cell.CellFormula, "RefPtg"); + + cell = destColumn.GetCell(col++); + Assert.IsNotNull(cell); + Assert.AreEqual("src!$E5", cell.CellFormula, "Ref3DPtg"); + + cell = destColumn.GetCell(col++); + Assert.IsNotNull(cell); + Assert.AreEqual("dest!$E5", cell.CellFormula, "Ref3DPtg"); + + cell = destColumn.GetCell(col++); + Assert.IsNotNull(cell); + Assert.AreEqual("other!$E5", cell.CellFormula, "Ref3DPtg"); + + ////////////////////////////////////////// + + //Test 2D and 3D Area Ptgs (Pxg for OOXML Workbooks) + // Note: absolute column changes from last cell to first cell in order + // to maintain topLeft:bottomRight order + cell = destColumn.GetCell(col++); + Assert.IsNotNull(cell); + Assert.AreEqual("SUM($E5:F10)", cell.CellFormula, "Area2DPtg"); + + cell = destColumn.GetCell(col++); + Assert.IsNotNull(cell); + Assert.AreEqual("SUM(src!$E5:F10)", cell.CellFormula, "Area3DPtg"); + + cell = destColumn.GetCell(col++); + Assert.IsNotNull(destColumn.GetCell(6)); + Assert.AreEqual("SUM(dest!$E5:F10)", cell.CellFormula, "Area3DPtg"); + + cell = destColumn.GetCell(col++); + Assert.IsNotNull(destColumn.GetCell(7)); + Assert.AreEqual("SUM(other!$E5:F10)", cell.CellFormula, "Area3DPtg"); + + workbook.Close(); + }//*/ + } +} diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFSheet.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFSheet.cs index e2ddaae7b..694692d14 100644 --- a/testcases/ooxml/XSSF/UserModel/TestXSSFSheet.cs +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFSheet.cs @@ -19,6 +19,7 @@ limitations under the License. using NPOI.OpenXmlFormats.Spreadsheet; using NPOI.POIFS.Crypt; using NPOI.SS; +using NPOI.SS.Formula.Functions; using NPOI.SS.UserModel; using NPOI.SS.Util; using NPOI.Util; @@ -60,6 +61,268 @@ public void TestTestGetSetMargin() { BaseTestGetSetMargin(new double[] { 0.7, 0.7, 0.75, 0.75, 0.3, 0.3 }); } + + [Test] + public void ShiftRows_ShiftRowsWithVariousMergedRegions_RowsShiftedWithMergedRegion() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + + for (int i = 0; i < 12; i++) + { + sheet.CreateRow(i).CreateCell(0).SetCellValue(i); + } + + sheet.GetRow(1).CreateCell(1).SetCellValue("regionOutsideShiftedRowsOnTop"); + int regionOutsideToTheLeftId = sheet.AddMergedRegion(new CellRangeAddress(1, 1, 1, 2)); + + sheet.GetRow(2).CreateCell(3).SetCellValue("regionInsideShiftedRows"); + int regionInsideId = sheet.AddMergedRegion(new CellRangeAddress(2, 3, 3, 4)); + + sheet.GetRow(4).CreateCell(5).SetCellValue("regionRighBelowTheShiftedRows"); + int regionRighNextToId = sheet.AddMergedRegion(new CellRangeAddress(4, 5, 5, 6)); + + sheet.GetRow(6).CreateCell(7).SetCellValue("regionInTheWayOfTheShift"); + int regionInTheWayOfTheShiftId = sheet.AddMergedRegion(new CellRangeAddress(6, 7, 7, 8)); + + sheet.GetRow(10).CreateCell(9).SetCellValue("regionOutsideShiftedRowsBelow"); + int regionOutsideToTheRightId = sheet.AddMergedRegion(new CellRangeAddress(10, 11, 9, 10)); + + sheet.GetRow(1).CreateCell(11).SetCellValue("regionThatEndsWithinShiftedRows"); + int regionThatEndsWithinShiftedRowsId = sheet.AddMergedRegion(new CellRangeAddress(1, 2, 11, 12)); + + sheet.GetRow(1).CreateCell(13).SetCellValue("regionThatEndsOnLastShiftedRow"); + int regionThatEndsOnLastShiftedRowId = sheet.AddMergedRegion(new CellRangeAddress(1, 3, 13, 14)); + + sheet.GetRow(1).CreateCell(15).SetCellValue("regionThatEndsOutsideShiftedRows"); + int regionThatEndsOutsideShiftedRowsId = sheet.AddMergedRegion(new CellRangeAddress(1, 4, 15, 16)); + + sheet.GetRow(1).CreateCell(17).SetCellValue("reallyLongRegion"); + int reallyLongRegionId = sheet.AddMergedRegion(new CellRangeAddress(1, 11, 17, 18)); + + Assert.AreEqual("regionOutsideShiftedRowsOnTop", sheet.GetRow(1).GetCell(1).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("B2:C2"))); + + Assert.AreEqual("regionInsideShiftedRows", sheet.GetRow(2).GetCell(3).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("D3:E4"))); + + Assert.AreEqual("regionRighBelowTheShiftedRows", sheet.GetRow(4).GetCell(5).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("F5:G6"))); + + Assert.AreEqual("regionInTheWayOfTheShift", sheet.GetRow(6).GetCell(7).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("H7:I8"))); + + Assert.AreEqual("regionOutsideShiftedRowsBelow", sheet.GetRow(10).GetCell(9).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("J11:K12"))); + + Assert.AreEqual("regionThatEndsWithinShiftedRows", sheet.GetRow(1).GetCell(11).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("L2:M3"))); + + Assert.AreEqual("regionThatEndsOnLastShiftedRow", sheet.GetRow(1).GetCell(13).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("N2:O4"))); + + Assert.AreEqual("regionThatEndsOutsideShiftedRows", sheet.GetRow(1).GetCell(15).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("P2:Q5"))); + + Assert.AreEqual("reallyLongRegion", sheet.GetRow(1).GetCell(17).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("R2:S12"))); + + sheet.ShiftRows(2, 3, 4); + + Assert.AreEqual("regionOutsideShiftedRowsOnTop", sheet.GetRow(1).GetCell(1).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("B2:C2"))); + + Assert.AreEqual("regionInsideShiftedRows", sheet.GetRow(6).GetCell(3).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("D7:E8"))); + + Assert.AreEqual("regionRighBelowTheShiftedRows", sheet.GetRow(4).GetCell(5).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("F5:G6"))); + + Assert.IsNull(sheet.GetRow(6).GetCell(7)); + Assert.False(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("H7:I8"))); + + Assert.AreEqual("regionOutsideShiftedRowsBelow", sheet.GetRow(10).GetCell(9).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("J11:K12"))); + + Assert.AreEqual("regionThatEndsWithinShiftedRows", sheet.GetRow(1).GetCell(11).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("L2:M3"))); + + Assert.AreEqual("regionThatEndsOnLastShiftedRow", sheet.GetRow(1).GetCell(13).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("N2:O4"))); + + Assert.AreEqual("regionThatEndsOutsideShiftedRows", sheet.GetRow(1).GetCell(15).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("P2:Q5"))); + + Assert.AreEqual("reallyLongRegion", sheet.GetRow(1).GetCell(17).StringCellValue); + Assert.False(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("R2:S12"))); + + FileInfo file = TempFile.CreateTempFile("ShiftRows-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + + Assert.AreEqual("regionOutsideShiftedRowsOnTop", sheetLoaded.GetRow(1).GetCell(1).StringCellValue); + Assert.True(sheetLoaded.MergedRegions.Any(r => r.FormatAsString().Equals("B2:C2"))); + + Assert.AreEqual("regionInsideShiftedRows", sheetLoaded.GetRow(6).GetCell(3).StringCellValue); + Assert.True(sheetLoaded.MergedRegions.Any(r => r.FormatAsString().Equals("D7:E8"))); + + Assert.AreEqual("regionRighBelowTheShiftedRows", sheetLoaded.GetRow(4).GetCell(5).StringCellValue); + Assert.True(sheetLoaded.MergedRegions.Any(r => r.FormatAsString().Equals("F5:G6"))); + + Assert.IsNull(sheetLoaded.GetRow(6).GetCell(7)); + Assert.False(sheetLoaded.MergedRegions.Any(r => r.FormatAsString().Equals("H7:I8"))); + + Assert.AreEqual("regionOutsideShiftedRowsBelow", sheetLoaded.GetRow(10).GetCell(9).StringCellValue); + Assert.True(sheetLoaded.MergedRegions.Any(r => r.FormatAsString().Equals("J11:K12"))); + + Assert.AreEqual("regionThatEndsWithinShiftedRows", sheetLoaded.GetRow(1).GetCell(11).StringCellValue); + Assert.True(sheetLoaded.MergedRegions.Any(r => r.FormatAsString().Equals("L2:M3"))); + + Assert.AreEqual("regionThatEndsOnLastShiftedRow", sheetLoaded.GetRow(1).GetCell(13).StringCellValue); + Assert.True(sheetLoaded.MergedRegions.Any(r => r.FormatAsString().Equals("N2:O4"))); + + Assert.AreEqual("regionThatEndsOutsideShiftedRows", sheetLoaded.GetRow(1).GetCell(15).StringCellValue); + Assert.True(sheetLoaded.MergedRegions.Any(r => r.FormatAsString().Equals("P2:Q5"))); + + Assert.AreEqual("reallyLongRegion", sheetLoaded.GetRow(1).GetCell(17).StringCellValue); + Assert.False(sheetLoaded.MergedRegions.Any(r => r.FormatAsString().Equals("R2:S12"))); + } + + [Test] + public void ShiftColumns_ShiftColumnsWithVariousMergedRegions_ColumnsShiftedWithMergedRegion() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + _ = sheet.CreateRow(0); + + for (int i = 0; i < 12; i++) + { + sheet.GetRow(0).CreateCell(i).SetCellValue(i); + } + + sheet.CreateRow(1).CreateCell(1).SetCellValue("regionOutsideShiftedColumnsToTheLeft"); + int regionOutsideToTheLeftId = sheet.AddMergedRegion(new CellRangeAddress(1, 2, 1, 1)); + + sheet.CreateRow(3).CreateCell(2).SetCellValue("regionInsideShiftedColumns"); + int regionInsideId = sheet.AddMergedRegion(new CellRangeAddress(3, 4, 2, 3)); + + sheet.CreateRow(5).CreateCell(4).SetCellValue("regionRighNextToTheShiftedColumns"); + int regionRighNextToId = sheet.AddMergedRegion(new CellRangeAddress(5, 6, 4, 5)); + + sheet.CreateRow(7).CreateCell(6).SetCellValue("regionInTheWayOfTheShift"); + int regionInTheWayOfTheShiftId = sheet.AddMergedRegion(new CellRangeAddress(7, 8, 6, 7)); + + sheet.CreateRow(9).CreateCell(10).SetCellValue("regionOutsideShiftedColumnsToTheRight"); + int regionOutsideToTheRightId = sheet.AddMergedRegion(new CellRangeAddress(9, 10, 10, 11)); + + sheet.CreateRow(11).CreateCell(1).SetCellValue("regionThatEndsWithinShiftedColumns"); + int regionThatEndsWithinShiftedColumnsId = sheet.AddMergedRegion(new CellRangeAddress(11, 12, 1, 2)); + + sheet.CreateRow(13).CreateCell(1).SetCellValue("regionThatEndsOnLastShiftedColumn"); + int regionThatEndsOnLastShiftedColumnId = sheet.AddMergedRegion(new CellRangeAddress(13, 14, 1, 3)); + + sheet.CreateRow(15).CreateCell(1).SetCellValue("regionThatEndsOutsideShiftedColumns"); + int regionThatEndsOutsideShiftedColumnsId = sheet.AddMergedRegion(new CellRangeAddress(15, 16, 1, 4)); + + sheet.CreateRow(17).CreateCell(1).SetCellValue("reallyLongRegion"); + int reallyLongRegionId = sheet.AddMergedRegion(new CellRangeAddress(17, 18, 1, 11)); + + Assert.AreEqual("regionOutsideShiftedColumnsToTheLeft", sheet.GetRow(1).GetCell(1).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("B2:B3"))); + + Assert.AreEqual("regionInsideShiftedColumns", sheet.GetRow(3).GetCell(2).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("C4:D5"))); + + Assert.AreEqual("regionRighNextToTheShiftedColumns", sheet.GetRow(5).GetCell(4).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("E6:F7"))); + + Assert.AreEqual("regionInTheWayOfTheShift", sheet.GetRow(7).GetCell(6).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("G8:H9"))); + + Assert.AreEqual("regionOutsideShiftedColumnsToTheRight", sheet.GetRow(9).GetCell(10).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("K10:L11"))); + + Assert.AreEqual("regionThatEndsWithinShiftedColumns", sheet.GetRow(11).GetCell(1).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("B12:C13"))); + + Assert.AreEqual("regionThatEndsOnLastShiftedColumn", sheet.GetRow(13).GetCell(1).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("B14:D15"))); + + Assert.AreEqual("regionThatEndsOutsideShiftedColumns", sheet.GetRow(15).GetCell(1).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("B16:E17"))); + + Assert.AreEqual("reallyLongRegion", sheet.GetRow(17).GetCell(1).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("B18:L19"))); + + sheet.ShiftColumns(2, 3, 4); + + Assert.AreEqual("regionOutsideShiftedColumnsToTheLeft", sheet.GetRow(1).GetCell(1).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("B2:B3"))); + + Assert.AreEqual("regionInsideShiftedColumns", sheet.GetRow(3).GetCell(6).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("G4:H5"))); + + Assert.AreEqual("regionRighNextToTheShiftedColumns", sheet.GetRow(5).GetCell(4).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("E6:F7"))); + + Assert.IsNull(sheet.GetRow(7).GetCell(6)); + Assert.False(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("G8:H9"))); + + Assert.AreEqual("regionOutsideShiftedColumnsToTheRight", sheet.GetRow(9).GetCell(10).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("K10:L11"))); + + Assert.AreEqual("regionThatEndsWithinShiftedColumns", sheet.GetRow(11).GetCell(1).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("B12:C13"))); + + Assert.AreEqual("regionThatEndsOnLastShiftedColumn", sheet.GetRow(13).GetCell(1).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("B14:D15"))); + + Assert.AreEqual("regionThatEndsOutsideShiftedColumns", sheet.GetRow(15).GetCell(1).StringCellValue); + Assert.True(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("B16:E17"))); + + Assert.AreEqual("reallyLongRegion", sheet.GetRow(17).GetCell(1).StringCellValue); + Assert.False(sheet.MergedRegions.Any(r => r.FormatAsString().Equals("B18:L19"))); + + FileInfo file = TempFile.CreateTempFile("ShiftCols1-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + + Assert.AreEqual("regionOutsideShiftedColumnsToTheLeft", sheetLoaded.GetRow(1).GetCell(1).StringCellValue); + Assert.True(sheetLoaded.MergedRegions.Any(r => r.FormatAsString().Equals("B2:B3"))); + + Assert.AreEqual("regionInsideShiftedColumns", sheetLoaded.GetRow(3).GetCell(6).StringCellValue); + Assert.True(sheetLoaded.MergedRegions.Any(r => r.FormatAsString().Equals("G4:H5"))); + + Assert.AreEqual("regionRighNextToTheShiftedColumns", sheetLoaded.GetRow(5).GetCell(4).StringCellValue); + Assert.True(sheetLoaded.MergedRegions.Any(r => r.FormatAsString().Equals("E6:F7"))); + + Assert.IsNull(sheetLoaded.GetRow(7).GetCell(6)); + Assert.False(sheetLoaded.MergedRegions.Any(r => r.FormatAsString().Equals("G8:H9"))); + + Assert.AreEqual("regionOutsideShiftedColumnsToTheRight", sheetLoaded.GetRow(9).GetCell(10).StringCellValue); + Assert.True(sheetLoaded.MergedRegions.Any(r => r.FormatAsString().Equals("K10:L11"))); + + Assert.AreEqual("regionThatEndsWithinShiftedColumns", sheetLoaded.GetRow(11).GetCell(1).StringCellValue); + Assert.True(sheetLoaded.MergedRegions.Any(r => r.FormatAsString().Equals("B12:C13"))); + + Assert.AreEqual("regionThatEndsOnLastShiftedColumn", sheetLoaded.GetRow(13).GetCell(1).StringCellValue); + Assert.True(sheetLoaded.MergedRegions.Any(r => r.FormatAsString().Equals("B14:D15"))); + + Assert.AreEqual("regionThatEndsOutsideShiftedColumns", sheetLoaded.GetRow(15).GetCell(1).StringCellValue); + Assert.True(sheetLoaded.MergedRegions.Any(r => r.FormatAsString().Equals("B16:E17"))); + + Assert.AreEqual("reallyLongRegion", sheetLoaded.GetRow(17).GetCell(1).StringCellValue); + Assert.False(sheetLoaded.MergedRegions.Any(r => r.FormatAsString().Equals("B18:L19"))); + } + [Test] public void TestExistingHeaderFooter() { @@ -134,27 +397,27 @@ public void TestGetAllHeadersFooters() Assert.IsNotNull(sheet.FirstHeader); Assert.AreEqual("", sheet.OddFooter.Left); - sheet.OddFooter.Left = ("odd footer left"); + sheet.OddFooter.Left = "odd footer left"; Assert.AreEqual("odd footer left", sheet.OddFooter.Left); Assert.AreEqual("", sheet.EvenFooter.Left); - sheet.EvenFooter.Left = ("even footer left"); + sheet.EvenFooter.Left = "even footer left"; Assert.AreEqual("even footer left", sheet.EvenFooter.Left); Assert.AreEqual("", sheet.FirstFooter.Left); - sheet.FirstFooter.Left = ("first footer left"); + sheet.FirstFooter.Left = "first footer left"; Assert.AreEqual("first footer left", sheet.FirstFooter.Left); Assert.AreEqual("", sheet.OddHeader.Left); - sheet.OddHeader.Left = ("odd header left"); + sheet.OddHeader.Left = "odd header left"; Assert.AreEqual("odd header left", sheet.OddHeader.Left); Assert.AreEqual("", sheet.OddHeader.Right); - sheet.OddHeader.Right = ("odd header right"); + sheet.OddHeader.Right = "odd header right"; Assert.AreEqual("odd header right", sheet.OddHeader.Right); Assert.AreEqual("", sheet.OddHeader.Center); - sheet.OddHeader.Center = ("odd header center"); + sheet.OddHeader.Center = "odd header center"; Assert.AreEqual("odd header center", sheet.OddHeader.Center); // Defaults are odd @@ -172,9 +435,7 @@ public void TestAutoSizeColumn() sheet.AutoSizeColumn(13); - ColumnHelper columnHelper = sheet.GetColumnHelper(); - CT_Col col = columnHelper.GetColumn(13, false); - Assert.IsTrue(col.bestFit); + Assert.IsTrue(sheet.GetColumn(13).IsBestFit); workbook.Close(); } @@ -186,10 +447,10 @@ public void TestAutoSizeRow() XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = (XSSFSheet)workbook.CreateSheet("Sheet 1"); - var row = sheet.CreateRow(0); - var cell = row.CreateCell(13); + IRow row = sheet.CreateRow(0); + ICell cell = row.CreateCell(13); cell.SetCellValue("test"); - var font = cell.CellStyle.GetFont(workbook); + IFont font = cell.CellStyle.GetFont(workbook); font.FontHeightInPoints = 20; cell.CellStyle.SetFont(font); row.Height = 100; @@ -215,9 +476,9 @@ public void TestSetCellComment() CommentsTable comments = sheet.GetCommentsTable(false); CT_Comments ctComments = comments.GetCTComments(); - cell.CellComment = (comment); + cell.CellComment = comment; Assert.AreEqual("A1", ctComments.commentList.GetCommentArray(0).@ref); - comment.Author = ("test A1 author"); + comment.Author = "test A1 author"; Assert.AreEqual("test A1 author", comments.GetAuthor((int)ctComments.commentList.GetCommentArray(0).authorId)); workbook.Close(); @@ -282,7 +543,6 @@ public void TestRemoveMergedRegion_lowlevel() workbook.Close(); } - [Test] public void TestSetDefaultColumnStyle() { @@ -290,17 +550,23 @@ public void TestSetDefaultColumnStyle() XSSFSheet sheet = (XSSFSheet)workbook.CreateSheet(); CT_Worksheet ctWorksheet = sheet.GetCTWorksheet(); StylesTable stylesTable = workbook.GetStylesSource(); - XSSFFont font = new XSSFFont(); - font.FontName = ("Cambria"); + XSSFFont font = new XSSFFont + { + FontName = "Cambria" + }; stylesTable.PutFont(font); - CT_Xf cellStyleXf = new CT_Xf(); - cellStyleXf.fontId = (1); - cellStyleXf.fillId = 0; - cellStyleXf.borderId = 0; - cellStyleXf.numFmtId = 0; + CT_Xf cellStyleXf = new CT_Xf + { + fontId = 1, + fillId = 0, + borderId = 0, + numFmtId = 0 + }; stylesTable.PutCellStyleXf(cellStyleXf); - CT_Xf cellXf = new CT_Xf(); - cellXf.xfId = (1); + CT_Xf cellXf = new CT_Xf + { + xfId = 1 + }; stylesTable.PutCellXf(cellXf); XSSFCellStyle cellStyle = new XSSFCellStyle(1, 1, stylesTable, null); Assert.AreEqual(1, cellStyle.FontIndex); @@ -321,18 +587,39 @@ public void TestGroupUngroupColumn() sheet.GroupColumn(2, 7); sheet.GroupColumn(10, 11); CT_Cols cols = sheet.GetCTWorksheet().GetColsArray(0); - Assert.AreEqual(2, cols.sizeOfColArray()); + Assert.AreEqual(8, cols.sizeOfColArray()); List colArray = cols.GetColList(); Assert.IsNotNull(colArray); Assert.AreEqual((uint)(2 + 1), colArray[0].min); // 1 based - Assert.AreEqual((uint)(7 + 1), colArray[0].max); // 1 based + Assert.AreEqual((uint)(2 + 1), colArray[0].max); // 1 based Assert.AreEqual(1, colArray[0].outlineLevel); + + Assert.AreEqual((uint)(3 + 1), colArray[1].min); // 1 based + Assert.AreEqual((uint)(3 + 1), colArray[1].max); // 1 based + Assert.AreEqual(1, colArray[1].outlineLevel); + + Assert.AreEqual((uint)(4 + 1), colArray[2].min); // 1 based + Assert.AreEqual((uint)(4 + 1), colArray[2].max); // 1 based + Assert.AreEqual(1, colArray[2].outlineLevel); + + Assert.AreEqual((uint)(5 + 1), colArray[3].min); // 1 based + Assert.AreEqual((uint)(5 + 1), colArray[3].max); // 1 based + Assert.AreEqual(1, colArray[3].outlineLevel); + + Assert.AreEqual((uint)(6 + 1), colArray[4].min); // 1 based + Assert.AreEqual((uint)(6 + 1), colArray[4].max); // 1 based + Assert.AreEqual(1, colArray[4].outlineLevel); + + Assert.AreEqual((uint)(7 + 1), colArray[5].min); // 1 based + Assert.AreEqual((uint)(7 + 1), colArray[5].max); // 1 based + Assert.AreEqual(1, colArray[5].outlineLevel); + Assert.AreEqual(0, sheet.GetColumnOutlineLevel(0)); //two level sheet.GroupColumn(1, 2); cols = sheet.GetCTWorksheet().GetColsArray(0); - Assert.AreEqual(4, cols.sizeOfColArray()); + Assert.AreEqual(9, cols.sizeOfColArray()); colArray = cols.GetColList(); Assert.AreEqual(2, colArray[1].outlineLevel); @@ -340,7 +627,7 @@ public void TestGroupUngroupColumn() sheet.GroupColumn(6, 8); sheet.GroupColumn(2, 3); cols = sheet.GetCTWorksheet().GetColsArray(0); - Assert.AreEqual(7, cols.sizeOfColArray()); + Assert.AreEqual(10, cols.sizeOfColArray()); colArray = cols.GetColList(); Assert.AreEqual(3, colArray[1].outlineLevel); Assert.AreEqual(3, sheet.GetCTWorksheet().sheetFormatPr.outlineLevelCol); @@ -352,12 +639,108 @@ public void TestGroupUngroupColumn() sheet.UngroupColumn(4, 6); sheet.UngroupColumn(2, 2); colArray = cols.GetColList(); - Assert.AreEqual(4, colArray.Count); + Assert.AreEqual(6, colArray.Count); Assert.AreEqual(2, sheet.GetCTWorksheet().sheetFormatPr.outlineLevelCol); workbook.Close(); } + [Test] + public void UngroupColumn_SimpleOneLevelUngroupNoOverlaps_ColumnsUngroupedAndDestroyed() + { + XSSFWorkbook workbook = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)workbook.CreateSheet(); + ICellStyle style = workbook.CreateCellStyle(); + style.BorderLeft = BorderStyle.Double; + + sheet.GroupColumn(2, 7); + sheet.GroupColumn(10, 11); + sheet.GetColumn(2).CreateCell(0); + sheet.GetColumn(10).ColumnStyle = style; + + Assert.AreEqual(8, sheet.GetCTWorksheet().cols[0].col.Count); + + for (int i = 2; i <= 7; i++) + { + Assert.AreEqual(1, sheet.GetColumn(i).OutlineLevel); + } + + for (int i = 10; i <= 11; i++) + { + Assert.AreEqual(1, sheet.GetColumn(i).OutlineLevel); + } + + sheet.UngroupColumn(2, 7); + sheet.UngroupColumn(10, 11); + + Assert.AreEqual(2, sheet.GetCTWorksheet().cols[0].col.Count); + Assert.AreEqual(0, sheet.GetColumn(2).OutlineLevel); + Assert.AreEqual(0, sheet.GetColumn(10).OutlineLevel); + + FileInfo file = TempFile.CreateTempFile("poi-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + workbook.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheetAt(0); + + Assert.AreEqual(2, sheetLoaded.GetCTWorksheet().cols[0].col.Count); + Assert.AreEqual(0, sheetLoaded.GetColumn(2).OutlineLevel); + Assert.AreEqual(0, sheetLoaded.GetColumn(10).OutlineLevel); + + wbLoaded.Close(); + } + + [Test] + public void UngroupColumn_TwoOverlappingGroups_ColumnsUngroupedAndDestroyed() + { + XSSFWorkbook workbook = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)workbook.CreateSheet(); + ICellStyle style = workbook.CreateCellStyle(); + style.BorderLeft = BorderStyle.Double; + + sheet.GroupColumn(2, 7); + sheet.GroupColumn(6, 11); + sheet.GetColumn(2).CreateCell(0); + sheet.GetColumn(6).ColumnStyle = style; + + Assert.AreEqual(10, sheet.GetCTWorksheet().cols[0].col.Count); + + for (int i = 2; i <= 11; i++) + { + if (i == 6 || i == 7) + { + Assert.AreEqual(2, sheet.GetColumn(i).OutlineLevel); + } + else + { + Assert.AreEqual(1, sheet.GetColumn(i).OutlineLevel); + } + } + + sheet.UngroupColumn(2, 7); + sheet.UngroupColumn(6, 11); + + Assert.AreEqual(2, sheet.GetCTWorksheet().cols[0].col.Count); + Assert.AreEqual(0, sheet.GetColumn(2).OutlineLevel); + Assert.AreEqual(0, sheet.GetColumn(6).OutlineLevel); + + FileInfo file = TempFile.CreateTempFile("poi-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + workbook.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheetAt(0); + + Assert.AreEqual(2, sheetLoaded.GetCTWorksheet().cols[0].col.Count); + Assert.AreEqual(0, sheetLoaded.GetColumn(2).OutlineLevel); + Assert.AreEqual(0, sheetLoaded.GetColumn(6).OutlineLevel); + + wbLoaded.Close(); + } + [Test] public void TestGroupUngroupRow() { @@ -383,7 +766,6 @@ public void TestGroupUngroupRow() Assert.AreEqual(2, ctrow.outlineLevel); Assert.AreEqual(2, sheet.GetCTWorksheet().sheetFormatPr.outlineLevelRow); - sheet.UngroupRow(8, 10); Assert.AreEqual(4, sheet.PhysicalNumberOfRows); Assert.AreEqual(1, sheet.GetCTWorksheet().sheetFormatPr.outlineLevelRow); @@ -434,226 +816,641 @@ public void TestSetColumnGroupCollapsed() { XSSFWorkbook wb1 = new XSSFWorkbook(); XSSFSheet sheet1 = (XSSFSheet)wb1.CreateSheet(); - CT_Cols cols = sheet1.GetCTWorksheet().GetColsArray(0); + Assert.AreEqual(0, cols.sizeOfColArray()); - sheet1.GroupColumn((short)4, (short)7); - sheet1.GroupColumn((short)9, (short)12); + sheet1.GroupColumn(4, 7); + sheet1.GroupColumn(9, 12); - Assert.AreEqual(2, cols.sizeOfColArray()); + Assert.AreEqual(8, cols.sizeOfColArray()); Assert.AreEqual(false, cols.GetColArray(0).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(0).IsSetCollapsed()); - Assert.AreEqual(5, cols.GetColArray(0).min); // 1 based - Assert.AreEqual(8, cols.GetColArray(0).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(0).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(0).collapsed); + Assert.AreEqual(1, cols.GetColArray(0).outlineLevel); + Assert.AreEqual(4 + 1, cols.GetColArray(0).min); // 1 based + Assert.AreEqual(4 + 1, cols.GetColArray(0).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(1).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(1).IsSetCollapsed()); - Assert.AreEqual(10, cols.GetColArray(1).min); // 1 based - Assert.AreEqual(13, cols.GetColArray(1).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(1).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(1).collapsed); + Assert.AreEqual(1, cols.GetColArray(1).outlineLevel); + Assert.AreEqual(5 + 1, cols.GetColArray(1).min); // 1 based + Assert.AreEqual(5 + 1, cols.GetColArray(1).max); // 1 based - sheet1.GroupColumn((short)10, (short)11); - Assert.AreEqual(4, cols.sizeOfColArray()); + Assert.AreEqual(false, cols.GetColArray(2).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(2).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(2).collapsed); + Assert.AreEqual(1, cols.GetColArray(2).outlineLevel); + Assert.AreEqual(6 + 1, cols.GetColArray(2).min); // 1 based + Assert.AreEqual(6 + 1, cols.GetColArray(2).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(3).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(3).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(3).collapsed); + Assert.AreEqual(1, cols.GetColArray(3).outlineLevel); + Assert.AreEqual(7 + 1, cols.GetColArray(3).min); // 1 based + Assert.AreEqual(7 + 1, cols.GetColArray(3).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(4).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(4).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(4).collapsed); + Assert.AreEqual(1, cols.GetColArray(4).outlineLevel); + Assert.AreEqual(9 + 1, cols.GetColArray(4).min); // 1 based + Assert.AreEqual(9 + 1, cols.GetColArray(4).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(5).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(5).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(5).collapsed); + Assert.AreEqual(1, cols.GetColArray(5).outlineLevel); + Assert.AreEqual(10 + 1, cols.GetColArray(5).min); // 1 based + Assert.AreEqual(10 + 1, cols.GetColArray(5).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(6).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(6).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(6).collapsed); + Assert.AreEqual(1, cols.GetColArray(6).outlineLevel); + Assert.AreEqual(11 + 1, cols.GetColArray(6).min); // 1 based + Assert.AreEqual(11 + 1, cols.GetColArray(6).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(7).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(7).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(7).collapsed); + Assert.AreEqual(1, cols.GetColArray(7).outlineLevel); + Assert.AreEqual(12 + 1, cols.GetColArray(7).min); // 1 based + Assert.AreEqual(12 + 1, cols.GetColArray(7).max); // 1 based + + sheet1.GroupColumn(10, 11); + + Assert.AreEqual(8, cols.sizeOfColArray()); Assert.AreEqual(false, cols.GetColArray(0).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(0).IsSetCollapsed()); - Assert.AreEqual(5, cols.GetColArray(0).min); // 1 based - Assert.AreEqual(8, cols.GetColArray(0).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(0).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(0).collapsed); + Assert.AreEqual(1, cols.GetColArray(0).outlineLevel); + Assert.AreEqual(4 + 1, cols.GetColArray(0).min); // 1 based + Assert.AreEqual(4 + 1, cols.GetColArray(0).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(1).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(1).IsSetCollapsed()); - Assert.AreEqual(10, cols.GetColArray(1).min); // 1 based - Assert.AreEqual(10, cols.GetColArray(1).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(1).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(1).collapsed); + Assert.AreEqual(1, cols.GetColArray(1).outlineLevel); + Assert.AreEqual(5 + 1, cols.GetColArray(1).min); // 1 based + Assert.AreEqual(5 + 1, cols.GetColArray(1).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(2).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(2).IsSetCollapsed()); - Assert.AreEqual(11, cols.GetColArray(2).min); // 1 based - Assert.AreEqual(12, cols.GetColArray(2).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(2).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(2).collapsed); + Assert.AreEqual(1, cols.GetColArray(2).outlineLevel); + Assert.AreEqual(6 + 1, cols.GetColArray(2).min); // 1 based + Assert.AreEqual(6 + 1, cols.GetColArray(2).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(3).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(3).IsSetCollapsed()); - Assert.AreEqual(13, cols.GetColArray(3).min); // 1 based - Assert.AreEqual(13, cols.GetColArray(3).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(3).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(3).collapsed); + Assert.AreEqual(1, cols.GetColArray(3).outlineLevel); + Assert.AreEqual(7 + 1, cols.GetColArray(3).min); // 1 based + Assert.AreEqual(7 + 1, cols.GetColArray(3).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(4).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(4).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(4).collapsed); + Assert.AreEqual(1, cols.GetColArray(4).outlineLevel); + Assert.AreEqual(9 + 1, cols.GetColArray(4).min); // 1 based + Assert.AreEqual(9 + 1, cols.GetColArray(4).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(5).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(5).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(5).collapsed); + Assert.AreEqual(2, cols.GetColArray(5).outlineLevel); + Assert.AreEqual(10 + 1, cols.GetColArray(5).min); // 1 based + Assert.AreEqual(10 + 1, cols.GetColArray(5).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(6).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(6).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(6).collapsed); + Assert.AreEqual(2, cols.GetColArray(6).outlineLevel); + Assert.AreEqual(11 + 1, cols.GetColArray(6).min); // 1 based + Assert.AreEqual(11 + 1, cols.GetColArray(6).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(7).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(7).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(7).collapsed); + Assert.AreEqual(1, cols.GetColArray(7).outlineLevel); + Assert.AreEqual(12 + 1, cols.GetColArray(7).min); // 1 based + Assert.AreEqual(12 + 1, cols.GetColArray(7).max); // 1 based // collapse columns - 1 - sheet1.SetColumnGroupCollapsed((short)5, true); - Assert.AreEqual(5, cols.sizeOfColArray()); + sheet1.SetColumnGroupCollapsed(5, true); + + Assert.AreEqual(9, cols.sizeOfColArray()); Assert.AreEqual(true, cols.GetColArray(0).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(0).IsSetCollapsed()); - Assert.AreEqual(5, cols.GetColArray(0).min); // 1 based - Assert.AreEqual(8, cols.GetColArray(0).max); // 1 based - Assert.AreEqual(false, cols.GetColArray(1).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(1).IsSetCollapsed()); - Assert.AreEqual(9, cols.GetColArray(1).min); // 1 based - Assert.AreEqual(9, cols.GetColArray(1).max); // 1 based - Assert.AreEqual(false, cols.GetColArray(2).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(2).IsSetCollapsed()); - Assert.AreEqual(10, cols.GetColArray(2).min); // 1 based - Assert.AreEqual(10, cols.GetColArray(2).max); // 1 based - Assert.AreEqual(false, cols.GetColArray(3).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(3).IsSetCollapsed()); - Assert.AreEqual(11, cols.GetColArray(3).min); // 1 based - Assert.AreEqual(12, cols.GetColArray(3).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(0).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(0).collapsed); + Assert.AreEqual(1, cols.GetColArray(0).outlineLevel); + Assert.AreEqual(4 + 1, cols.GetColArray(0).min); // 1 based + Assert.AreEqual(4 + 1, cols.GetColArray(0).max); // 1 based + + Assert.AreEqual(true, cols.GetColArray(1).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(1).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(1).collapsed); + Assert.AreEqual(1, cols.GetColArray(1).outlineLevel); + Assert.AreEqual(5 + 1, cols.GetColArray(1).min); // 1 based + Assert.AreEqual(5 + 1, cols.GetColArray(1).max); // 1 based + + Assert.AreEqual(true, cols.GetColArray(2).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(2).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(2).collapsed); + Assert.AreEqual(1, cols.GetColArray(2).outlineLevel); + Assert.AreEqual(6 + 1, cols.GetColArray(2).min); // 1 based + Assert.AreEqual(6 + 1, cols.GetColArray(2).max); // 1 based + + Assert.AreEqual(true, cols.GetColArray(3).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(3).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(3).collapsed); + Assert.AreEqual(1, cols.GetColArray(3).outlineLevel); + Assert.AreEqual(7 + 1, cols.GetColArray(3).min); // 1 based + Assert.AreEqual(7 + 1, cols.GetColArray(3).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(4).IsSetHidden()); Assert.AreEqual(true, cols.GetColArray(4).IsSetCollapsed()); - Assert.AreEqual(13, cols.GetColArray(4).min); // 1 based - Assert.AreEqual(13, cols.GetColArray(4).max); // 1 based + Assert.AreEqual(true, cols.GetColArray(4).collapsed); + Assert.AreEqual(0, cols.GetColArray(4).outlineLevel); + Assert.AreEqual(8 + 1, cols.GetColArray(4).min); // 1 based + Assert.AreEqual(8 + 1, cols.GetColArray(4).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(5).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(5).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(5).collapsed); + Assert.AreEqual(1, cols.GetColArray(5).outlineLevel); + Assert.AreEqual(9 + 1, cols.GetColArray(5).min); // 1 based + Assert.AreEqual(9 + 1, cols.GetColArray(5).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(6).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(6).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(6).collapsed); + Assert.AreEqual(2, cols.GetColArray(6).outlineLevel); + Assert.AreEqual(10 + 1, cols.GetColArray(6).min); // 1 based + Assert.AreEqual(10 + 1, cols.GetColArray(6).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(7).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(7).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(7).collapsed); + Assert.AreEqual(2, cols.GetColArray(7).outlineLevel); + Assert.AreEqual(11 + 1, cols.GetColArray(7).min); // 1 based + Assert.AreEqual(11 + 1, cols.GetColArray(7).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(8).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(8).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(8).collapsed); + Assert.AreEqual(1, cols.GetColArray(8).outlineLevel); + Assert.AreEqual(12 + 1, cols.GetColArray(8).min); // 1 based + Assert.AreEqual(12 + 1, cols.GetColArray(8).max); // 1 based // expand columns - 1 - sheet1.SetColumnGroupCollapsed((short)5, false); + sheet1.SetColumnGroupCollapsed(5, false); Assert.AreEqual(false, cols.GetColArray(0).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(0).IsSetCollapsed()); - Assert.AreEqual(5, cols.GetColArray(0).min); // 1 based - Assert.AreEqual(8, cols.GetColArray(0).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(0).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(0).collapsed); + Assert.AreEqual(1, cols.GetColArray(0).outlineLevel); + Assert.AreEqual(4 + 1, cols.GetColArray(0).min); // 1 based + Assert.AreEqual(4 + 1, cols.GetColArray(0).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(1).IsSetHidden()); Assert.AreEqual(false, cols.GetColArray(1).IsSetCollapsed()); - Assert.AreEqual(9, cols.GetColArray(1).min); // 1 based - Assert.AreEqual(9, cols.GetColArray(1).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(1).collapsed); + Assert.AreEqual(1, cols.GetColArray(1).outlineLevel); + Assert.AreEqual(5 + 1, cols.GetColArray(1).min); // 1 based + Assert.AreEqual(5 + 1, cols.GetColArray(1).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(2).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(2).IsSetCollapsed()); - Assert.AreEqual(10, cols.GetColArray(2).min); // 1 based - Assert.AreEqual(10, cols.GetColArray(2).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(2).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(2).collapsed); + Assert.AreEqual(1, cols.GetColArray(2).outlineLevel); + Assert.AreEqual(6 + 1, cols.GetColArray(2).min); // 1 based + Assert.AreEqual(6 + 1, cols.GetColArray(2).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(3).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(3).IsSetCollapsed()); - Assert.AreEqual(11, cols.GetColArray(3).min); // 1 based - Assert.AreEqual(12, cols.GetColArray(3).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(3).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(3).collapsed); + Assert.AreEqual(1, cols.GetColArray(3).outlineLevel); + Assert.AreEqual(7 + 1, cols.GetColArray(3).min); // 1 based + Assert.AreEqual(7 + 1, cols.GetColArray(3).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(4).IsSetHidden()); Assert.AreEqual(true, cols.GetColArray(4).IsSetCollapsed()); - Assert.AreEqual(13, cols.GetColArray(4).min); // 1 based - Assert.AreEqual(13, cols.GetColArray(4).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(4).collapsed); + Assert.AreEqual(0, cols.GetColArray(4).outlineLevel); + Assert.AreEqual(8 + 1, cols.GetColArray(4).min); // 1 based + Assert.AreEqual(8 + 1, cols.GetColArray(4).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(5).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(5).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(5).collapsed); + Assert.AreEqual(1, cols.GetColArray(5).outlineLevel); + Assert.AreEqual(9 + 1, cols.GetColArray(5).min); // 1 based + Assert.AreEqual(9 + 1, cols.GetColArray(5).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(6).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(6).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(6).collapsed); + Assert.AreEqual(2, cols.GetColArray(6).outlineLevel); + Assert.AreEqual(10 + 1, cols.GetColArray(6).min); // 1 based + Assert.AreEqual(10 + 1, cols.GetColArray(6).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(7).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(7).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(7).collapsed); + Assert.AreEqual(2, cols.GetColArray(7).outlineLevel); + Assert.AreEqual(11 + 1, cols.GetColArray(7).min); // 1 based + Assert.AreEqual(11 + 1, cols.GetColArray(7).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(8).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(8).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(8).collapsed); + Assert.AreEqual(1, cols.GetColArray(8).outlineLevel); + Assert.AreEqual(12 + 1, cols.GetColArray(8).min); // 1 based + Assert.AreEqual(12 + 1, cols.GetColArray(8).max); // 1 based //collapse - 2 - sheet1.SetColumnGroupCollapsed((short)9, true); - Assert.AreEqual(6, cols.sizeOfColArray()); + sheet1.SetColumnGroupCollapsed(9, true); + + Assert.AreEqual(10, cols.sizeOfColArray()); + Assert.AreEqual(false, cols.GetColArray(0).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(0).IsSetCollapsed()); - Assert.AreEqual(5, cols.GetColArray(0).min); // 1 based - Assert.AreEqual(8, cols.GetColArray(0).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(0).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(0).collapsed); + Assert.AreEqual(1, cols.GetColArray(0).outlineLevel); + Assert.AreEqual(4 + 1, cols.GetColArray(0).min); // 1 based + Assert.AreEqual(4 + 1, cols.GetColArray(0).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(1).IsSetHidden()); Assert.AreEqual(false, cols.GetColArray(1).IsSetCollapsed()); - Assert.AreEqual(9, cols.GetColArray(1).min); // 1 based - Assert.AreEqual(9, cols.GetColArray(1).max); // 1 based - Assert.AreEqual(true, cols.GetColArray(2).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(2).IsSetCollapsed()); - Assert.AreEqual(10, cols.GetColArray(2).min); // 1 based - Assert.AreEqual(10, cols.GetColArray(2).max); // 1 based - Assert.AreEqual(true, cols.GetColArray(3).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(3).IsSetCollapsed()); - Assert.AreEqual(11, cols.GetColArray(3).min); // 1 based - Assert.AreEqual(12, cols.GetColArray(3).max); // 1 based - Assert.AreEqual(true, cols.GetColArray(4).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(1).collapsed); + Assert.AreEqual(1, cols.GetColArray(1).outlineLevel); + Assert.AreEqual(5 + 1, cols.GetColArray(1).min); // 1 based + Assert.AreEqual(5 + 1, cols.GetColArray(1).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(2).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(2).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(2).collapsed); + Assert.AreEqual(1, cols.GetColArray(2).outlineLevel); + Assert.AreEqual(6 + 1, cols.GetColArray(2).min); // 1 based + Assert.AreEqual(6 + 1, cols.GetColArray(2).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(3).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(3).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(3).collapsed); + Assert.AreEqual(1, cols.GetColArray(3).outlineLevel); + Assert.AreEqual(7 + 1, cols.GetColArray(3).min); // 1 based + Assert.AreEqual(7 + 1, cols.GetColArray(3).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(4).IsSetHidden()); Assert.AreEqual(true, cols.GetColArray(4).IsSetCollapsed()); - Assert.AreEqual(13, cols.GetColArray(4).min); // 1 based - Assert.AreEqual(13, cols.GetColArray(4).max); // 1 based - Assert.AreEqual(false, cols.GetColArray(5).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(5).IsSetCollapsed()); - Assert.AreEqual(14, cols.GetColArray(5).min); // 1 based - Assert.AreEqual(14, cols.GetColArray(5).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(4).collapsed); + Assert.AreEqual(0, cols.GetColArray(4).outlineLevel); + Assert.AreEqual(8 + 1, cols.GetColArray(4).min); // 1 based + Assert.AreEqual(8 + 1, cols.GetColArray(4).max); // 1 based + Assert.AreEqual(true, cols.GetColArray(5).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(5).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(5).collapsed); + Assert.AreEqual(1, cols.GetColArray(5).outlineLevel); + Assert.AreEqual(9 + 1, cols.GetColArray(5).min); // 1 based + Assert.AreEqual(9 + 1, cols.GetColArray(5).max); // 1 based + + Assert.AreEqual(true, cols.GetColArray(6).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(6).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(6).collapsed); + Assert.AreEqual(2, cols.GetColArray(6).outlineLevel); + Assert.AreEqual(10 + 1, cols.GetColArray(6).min); // 1 based + Assert.AreEqual(10 + 1, cols.GetColArray(6).max); // 1 based + + Assert.AreEqual(true, cols.GetColArray(7).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(7).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(7).collapsed); + Assert.AreEqual(2, cols.GetColArray(7).outlineLevel); + Assert.AreEqual(11 + 1, cols.GetColArray(7).min); // 1 based + Assert.AreEqual(11 + 1, cols.GetColArray(7).max); // 1 based + + Assert.AreEqual(true, cols.GetColArray(8).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(8).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(8).collapsed); + Assert.AreEqual(1, cols.GetColArray(8).outlineLevel); + Assert.AreEqual(12 + 1, cols.GetColArray(8).min); // 1 based + Assert.AreEqual(12 + 1, cols.GetColArray(8).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(9).IsSetHidden()); + Assert.AreEqual(true, cols.GetColArray(9).IsSetCollapsed()); + Assert.AreEqual(true, cols.GetColArray(9).collapsed); + Assert.AreEqual(0, cols.GetColArray(9).outlineLevel); + Assert.AreEqual(13 + 1, cols.GetColArray(9).min); // 1 based + Assert.AreEqual(13 + 1, cols.GetColArray(9).max); // 1 based //expand - 2 - sheet1.SetColumnGroupCollapsed((short)9, false); - Assert.AreEqual(6, cols.sizeOfColArray()); - Assert.AreEqual(14, cols.GetColArray(5).min); + sheet1.SetColumnGroupCollapsed(9, false); - //outline level 2: the line under ==> collapsed==True - Assert.AreEqual(2, cols.GetColArray(3).outlineLevel); - Assert.AreEqual(true, cols.GetColArray(4).IsSetCollapsed()); + Assert.AreEqual(10, cols.sizeOfColArray()); Assert.AreEqual(false, cols.GetColArray(0).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(0).IsSetCollapsed()); - Assert.AreEqual(5, cols.GetColArray(0).min); // 1 based - Assert.AreEqual(8, cols.GetColArray(0).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(0).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(0).collapsed); + Assert.AreEqual(1, cols.GetColArray(0).outlineLevel); + Assert.AreEqual(4 + 1, cols.GetColArray(0).min); // 1 based + Assert.AreEqual(4 + 1, cols.GetColArray(0).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(1).IsSetHidden()); Assert.AreEqual(false, cols.GetColArray(1).IsSetCollapsed()); - Assert.AreEqual(9, cols.GetColArray(1).min); // 1 based - Assert.AreEqual(9, cols.GetColArray(1).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(1).collapsed); + Assert.AreEqual(1, cols.GetColArray(1).outlineLevel); + Assert.AreEqual(5 + 1, cols.GetColArray(1).min); // 1 based + Assert.AreEqual(5 + 1, cols.GetColArray(1).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(2).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(2).IsSetCollapsed()); - Assert.AreEqual(10, cols.GetColArray(2).min); // 1 based - Assert.AreEqual(10, cols.GetColArray(2).max); // 1 based - Assert.AreEqual(true, cols.GetColArray(3).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(3).IsSetCollapsed()); - Assert.AreEqual(11, cols.GetColArray(3).min); // 1 based - Assert.AreEqual(12, cols.GetColArray(3).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(2).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(2).collapsed); + Assert.AreEqual(1, cols.GetColArray(2).outlineLevel); + Assert.AreEqual(6 + 1, cols.GetColArray(2).min); // 1 based + Assert.AreEqual(6 + 1, cols.GetColArray(2).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(3).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(3).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(3).collapsed); + Assert.AreEqual(1, cols.GetColArray(3).outlineLevel); + Assert.AreEqual(7 + 1, cols.GetColArray(3).min); // 1 based + Assert.AreEqual(7 + 1, cols.GetColArray(3).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(4).IsSetHidden()); Assert.AreEqual(true, cols.GetColArray(4).IsSetCollapsed()); - Assert.AreEqual(13, cols.GetColArray(4).min); // 1 based - Assert.AreEqual(13, cols.GetColArray(4).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(4).collapsed); + Assert.AreEqual(0, cols.GetColArray(4).outlineLevel); + Assert.AreEqual(8 + 1, cols.GetColArray(4).min); // 1 based + Assert.AreEqual(8 + 1, cols.GetColArray(4).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(5).IsSetHidden()); Assert.AreEqual(false, cols.GetColArray(5).IsSetCollapsed()); - Assert.AreEqual(14, cols.GetColArray(5).min); // 1 based - Assert.AreEqual(14, cols.GetColArray(5).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(5).collapsed); + Assert.AreEqual(1, cols.GetColArray(5).outlineLevel); + Assert.AreEqual(9 + 1, cols.GetColArray(5).min); // 1 based + Assert.AreEqual(9 + 1, cols.GetColArray(5).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(6).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(6).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(6).collapsed); + Assert.AreEqual(2, cols.GetColArray(6).outlineLevel); + Assert.AreEqual(10 + 1, cols.GetColArray(6).min); // 1 based + Assert.AreEqual(10 + 1, cols.GetColArray(6).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(7).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(7).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(7).collapsed); + Assert.AreEqual(2, cols.GetColArray(7).outlineLevel); + Assert.AreEqual(11 + 1, cols.GetColArray(7).min); // 1 based + Assert.AreEqual(11 + 1, cols.GetColArray(7).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(8).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(8).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(8).collapsed); + Assert.AreEqual(1, cols.GetColArray(8).outlineLevel); + Assert.AreEqual(12 + 1, cols.GetColArray(8).min); // 1 based + Assert.AreEqual(12 + 1, cols.GetColArray(8).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(9).IsSetHidden()); + Assert.AreEqual(true, cols.GetColArray(9).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(9).collapsed); + Assert.AreEqual(0, cols.GetColArray(9).outlineLevel); + Assert.AreEqual(13 + 1, cols.GetColArray(9).min); // 1 based + Assert.AreEqual(13 + 1, cols.GetColArray(9).max); // 1 based //DOCUMENTARE MEGLIO IL DISCORSO DEL LIVELLO //collapse - 3 - sheet1.SetColumnGroupCollapsed((short)10, true); - Assert.AreEqual(6, cols.sizeOfColArray()); + sheet1.SetColumnGroupCollapsed(10, true); + + Assert.AreEqual(10, cols.sizeOfColArray()); + Assert.AreEqual(false, cols.GetColArray(0).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(0).IsSetCollapsed()); - Assert.AreEqual(5, cols.GetColArray(0).min); // 1 based - Assert.AreEqual(8, cols.GetColArray(0).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(0).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(0).collapsed); + Assert.AreEqual(1, cols.GetColArray(0).outlineLevel); + Assert.AreEqual(4 + 1, cols.GetColArray(0).min); // 1 based + Assert.AreEqual(4 + 1, cols.GetColArray(0).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(1).IsSetHidden()); Assert.AreEqual(false, cols.GetColArray(1).IsSetCollapsed()); - Assert.AreEqual(9, cols.GetColArray(1).min); // 1 based - Assert.AreEqual(9, cols.GetColArray(1).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(1).collapsed); + Assert.AreEqual(1, cols.GetColArray(1).outlineLevel); + Assert.AreEqual(5 + 1, cols.GetColArray(1).min); // 1 based + Assert.AreEqual(5 + 1, cols.GetColArray(1).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(2).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(2).IsSetCollapsed()); - Assert.AreEqual(10, cols.GetColArray(2).min); // 1 based - Assert.AreEqual(10, cols.GetColArray(2).max); // 1 based - Assert.AreEqual(true, cols.GetColArray(3).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(3).IsSetCollapsed()); - Assert.AreEqual(11, cols.GetColArray(3).min); // 1 based - Assert.AreEqual(12, cols.GetColArray(3).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(2).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(2).collapsed); + Assert.AreEqual(1, cols.GetColArray(2).outlineLevel); + Assert.AreEqual(6 + 1, cols.GetColArray(2).min); // 1 based + Assert.AreEqual(6 + 1, cols.GetColArray(2).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(3).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(3).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(3).collapsed); + Assert.AreEqual(1, cols.GetColArray(3).outlineLevel); + Assert.AreEqual(7 + 1, cols.GetColArray(3).min); // 1 based + Assert.AreEqual(7 + 1, cols.GetColArray(3).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(4).IsSetHidden()); Assert.AreEqual(true, cols.GetColArray(4).IsSetCollapsed()); - Assert.AreEqual(13, cols.GetColArray(4).min); // 1 based - Assert.AreEqual(13, cols.GetColArray(4).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(4).collapsed); + Assert.AreEqual(0, cols.GetColArray(4).outlineLevel); + Assert.AreEqual(8 + 1, cols.GetColArray(4).min); // 1 based + Assert.AreEqual(8 + 1, cols.GetColArray(4).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(5).IsSetHidden()); Assert.AreEqual(false, cols.GetColArray(5).IsSetCollapsed()); - Assert.AreEqual(14, cols.GetColArray(5).min); // 1 based - Assert.AreEqual(14, cols.GetColArray(5).max); // 1 based - + Assert.AreEqual(false, cols.GetColArray(5).collapsed); + Assert.AreEqual(1, cols.GetColArray(5).outlineLevel); + Assert.AreEqual(9 + 1, cols.GetColArray(5).min); // 1 based + Assert.AreEqual(9 + 1, cols.GetColArray(5).max); // 1 based + + Assert.AreEqual(true, cols.GetColArray(6).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(6).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(6).collapsed); + Assert.AreEqual(2, cols.GetColArray(6).outlineLevel); + Assert.AreEqual(10 + 1, cols.GetColArray(6).min); // 1 based + Assert.AreEqual(10 + 1, cols.GetColArray(6).max); // 1 based + + Assert.AreEqual(true, cols.GetColArray(7).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(7).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(7).collapsed); + Assert.AreEqual(2, cols.GetColArray(7).outlineLevel); + Assert.AreEqual(11 + 1, cols.GetColArray(7).min); // 1 based + Assert.AreEqual(11 + 1, cols.GetColArray(7).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(8).IsSetHidden()); + Assert.AreEqual(true, cols.GetColArray(8).IsSetCollapsed()); + Assert.AreEqual(true, cols.GetColArray(8).collapsed); + Assert.AreEqual(1, cols.GetColArray(8).outlineLevel); + Assert.AreEqual(12 + 1, cols.GetColArray(8).min); // 1 based + Assert.AreEqual(12 + 1, cols.GetColArray(8).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(9).IsSetHidden()); + Assert.AreEqual(true, cols.GetColArray(9).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(9).collapsed); + Assert.AreEqual(0, cols.GetColArray(9).outlineLevel); + Assert.AreEqual(13 + 1, cols.GetColArray(9).min); // 1 based + Assert.AreEqual(13 + 1, cols.GetColArray(9).max); // 1 based //expand - 3 - sheet1.SetColumnGroupCollapsed((short)10, false); - Assert.AreEqual(6, cols.sizeOfColArray()); - Assert.AreEqual(false, cols.GetColArray(0).hidden); - Assert.AreEqual(false, cols.GetColArray(5).hidden); - Assert.AreEqual(false, cols.GetColArray(4).IsSetCollapsed()); - - // write out and give back - // Save and re-load - XSSFWorkbook wb2 = XSSFTestDataSamples.WriteOutAndReadBack(wb1); - wb1.Close(); - sheet1 = (XSSFSheet)wb2.GetSheetAt(0); - Assert.AreEqual(6, cols.sizeOfColArray()); + sheet1.SetColumnGroupCollapsed(10, false); Assert.AreEqual(false, cols.GetColArray(0).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(0).IsSetCollapsed()); - Assert.AreEqual(5, cols.GetColArray(0).min); // 1 based - Assert.AreEqual(8, cols.GetColArray(0).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(0).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(0).collapsed); + Assert.AreEqual(1, cols.GetColArray(0).outlineLevel); + Assert.AreEqual(4 + 1, cols.GetColArray(0).min); // 1 based + Assert.AreEqual(4 + 1, cols.GetColArray(0).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(1).IsSetHidden()); Assert.AreEqual(false, cols.GetColArray(1).IsSetCollapsed()); - Assert.AreEqual(9, cols.GetColArray(1).min); // 1 based - Assert.AreEqual(9, cols.GetColArray(1).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(1).collapsed); + Assert.AreEqual(1, cols.GetColArray(1).outlineLevel); + Assert.AreEqual(5 + 1, cols.GetColArray(1).min); // 1 based + Assert.AreEqual(5 + 1, cols.GetColArray(1).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(2).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(2).IsSetCollapsed()); - Assert.AreEqual(10, cols.GetColArray(2).min); // 1 based - Assert.AreEqual(10, cols.GetColArray(2).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(2).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(2).collapsed); + Assert.AreEqual(1, cols.GetColArray(2).outlineLevel); + Assert.AreEqual(6 + 1, cols.GetColArray(2).min); // 1 based + Assert.AreEqual(6 + 1, cols.GetColArray(2).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(3).IsSetHidden()); - Assert.AreEqual(true, cols.GetColArray(3).IsSetCollapsed()); - Assert.AreEqual(11, cols.GetColArray(3).min); // 1 based - Assert.AreEqual(12, cols.GetColArray(3).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(3).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(3).collapsed); + Assert.AreEqual(1, cols.GetColArray(3).outlineLevel); + Assert.AreEqual(7 + 1, cols.GetColArray(3).min); // 1 based + Assert.AreEqual(7 + 1, cols.GetColArray(3).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(4).IsSetHidden()); - Assert.AreEqual(false, cols.GetColArray(4).IsSetCollapsed()); - Assert.AreEqual(13, cols.GetColArray(4).min); // 1 based - Assert.AreEqual(13, cols.GetColArray(4).max); // 1 based + Assert.AreEqual(true, cols.GetColArray(4).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(4).collapsed); + Assert.AreEqual(0, cols.GetColArray(4).outlineLevel); + Assert.AreEqual(8 + 1, cols.GetColArray(4).min); // 1 based + Assert.AreEqual(8 + 1, cols.GetColArray(4).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(5).IsSetHidden()); Assert.AreEqual(false, cols.GetColArray(5).IsSetCollapsed()); - Assert.AreEqual(14, cols.GetColArray(5).min); // 1 based - Assert.AreEqual(14, cols.GetColArray(5).max); // 1 based + Assert.AreEqual(false, cols.GetColArray(5).collapsed); + Assert.AreEqual(1, cols.GetColArray(5).outlineLevel); + Assert.AreEqual(9 + 1, cols.GetColArray(5).min); // 1 based + Assert.AreEqual(9 + 1, cols.GetColArray(5).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(6).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(6).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(6).collapsed); + Assert.AreEqual(2, cols.GetColArray(6).outlineLevel); + Assert.AreEqual(10 + 1, cols.GetColArray(6).min); // 1 based + Assert.AreEqual(10 + 1, cols.GetColArray(6).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(7).IsSetHidden()); + Assert.AreEqual(false, cols.GetColArray(7).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(7).collapsed); + Assert.AreEqual(2, cols.GetColArray(7).outlineLevel); + Assert.AreEqual(11 + 1, cols.GetColArray(7).min); // 1 based + Assert.AreEqual(11 + 1, cols.GetColArray(7).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(8).IsSetHidden()); + Assert.AreEqual(true, cols.GetColArray(8).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(8).collapsed); + Assert.AreEqual(1, cols.GetColArray(8).outlineLevel); + Assert.AreEqual(12 + 1, cols.GetColArray(8).min); // 1 based + Assert.AreEqual(12 + 1, cols.GetColArray(8).max); // 1 based + + Assert.AreEqual(false, cols.GetColArray(9).IsSetHidden()); + Assert.AreEqual(true, cols.GetColArray(9).IsSetCollapsed()); + Assert.AreEqual(false, cols.GetColArray(9).collapsed); + Assert.AreEqual(0, cols.GetColArray(9).outlineLevel); + Assert.AreEqual(13 + 1, cols.GetColArray(9).min); // 1 based + Assert.AreEqual(13 + 1, cols.GetColArray(9).max); // 1 based + + // write out and give back + // Save and re-load + XSSFWorkbook wb2 = XSSFTestDataSamples.WriteOutAndReadBack(wb1); + wb1.Close(); + var sheet2 = (XSSFSheet)wb2.GetSheetAt(0); + var cols2 = sheet2.GetCTWorksheet().GetColsArray(0); + Assert.AreEqual(10, cols2.sizeOfColArray()); + + Assert.AreEqual(false, cols2.GetColArray(0).IsSetHidden()); + Assert.AreEqual(false, cols2.GetColArray(0).IsSetCollapsed()); + Assert.AreEqual(false, cols2.GetColArray(0).collapsed); + Assert.AreEqual(1, cols2.GetColArray(0).outlineLevel); + Assert.AreEqual(4 + 1, cols2.GetColArray(0).min); // 1 based + Assert.AreEqual(4 + 1, cols2.GetColArray(0).max); // 1 based + + Assert.AreEqual(false, cols2.GetColArray(1).IsSetHidden()); + Assert.AreEqual(false, cols2.GetColArray(1).IsSetCollapsed()); + Assert.AreEqual(false, cols2.GetColArray(1).collapsed); + Assert.AreEqual(1, cols2.GetColArray(1).outlineLevel); + Assert.AreEqual(5 + 1, cols2.GetColArray(1).min); // 1 based + Assert.AreEqual(5 + 1, cols2.GetColArray(1).max); // 1 based + + Assert.AreEqual(false, cols2.GetColArray(2).IsSetHidden()); + Assert.AreEqual(false, cols2.GetColArray(2).IsSetCollapsed()); + Assert.AreEqual(false, cols2.GetColArray(2).collapsed); + Assert.AreEqual(1, cols2.GetColArray(2).outlineLevel); + Assert.AreEqual(6 + 1, cols2.GetColArray(2).min); // 1 based + Assert.AreEqual(6 + 1, cols2.GetColArray(2).max); // 1 based + + Assert.AreEqual(false, cols2.GetColArray(3).IsSetHidden()); + Assert.AreEqual(false, cols2.GetColArray(3).IsSetCollapsed()); + Assert.AreEqual(false, cols2.GetColArray(3).collapsed); + Assert.AreEqual(1, cols2.GetColArray(3).outlineLevel); + Assert.AreEqual(7 + 1, cols2.GetColArray(3).min); // 1 based + Assert.AreEqual(7 + 1, cols2.GetColArray(3).max); // 1 based + + Assert.AreEqual(false, cols2.GetColArray(4).IsSetHidden()); + Assert.AreEqual(false, cols2.GetColArray(4).IsSetCollapsed()); + Assert.AreEqual(false, cols2.GetColArray(4).collapsed); + Assert.AreEqual(0, cols2.GetColArray(4).outlineLevel); + Assert.AreEqual(8 + 1, cols2.GetColArray(4).min); // 1 based + Assert.AreEqual(8 + 1, cols2.GetColArray(4).max); // 1 based + + Assert.AreEqual(false, cols2.GetColArray(5).IsSetHidden()); + Assert.AreEqual(false, cols2.GetColArray(5).IsSetCollapsed()); + Assert.AreEqual(false, cols2.GetColArray(5).collapsed); + Assert.AreEqual(1, cols2.GetColArray(5).outlineLevel); + Assert.AreEqual(9 + 1, cols2.GetColArray(5).min); // 1 based + Assert.AreEqual(9 + 1, cols2.GetColArray(5).max); // 1 based + + Assert.AreEqual(false, cols2.GetColArray(6).IsSetHidden()); + Assert.AreEqual(false, cols2.GetColArray(6).IsSetCollapsed()); + Assert.AreEqual(false, cols2.GetColArray(6).collapsed); + Assert.AreEqual(2, cols2.GetColArray(6).outlineLevel); + Assert.AreEqual(10 + 1, cols2.GetColArray(6).min); // 1 based + Assert.AreEqual(10 + 1, cols2.GetColArray(6).max); // 1 based + + Assert.AreEqual(false, cols2.GetColArray(7).IsSetHidden()); + Assert.AreEqual(false, cols2.GetColArray(7).IsSetCollapsed()); + Assert.AreEqual(false, cols2.GetColArray(7).collapsed); + Assert.AreEqual(2, cols2.GetColArray(7).outlineLevel); + Assert.AreEqual(11 + 1, cols2.GetColArray(7).min); // 1 based + Assert.AreEqual(11 + 1, cols2.GetColArray(7).max); // 1 based + + Assert.AreEqual(false, cols2.GetColArray(8).IsSetHidden()); + Assert.AreEqual(false, cols2.GetColArray(8).IsSetCollapsed()); + Assert.AreEqual(false, cols2.GetColArray(8).collapsed); + Assert.AreEqual(1, cols2.GetColArray(8).outlineLevel); + Assert.AreEqual(12 + 1, cols2.GetColArray(8).min); // 1 based + Assert.AreEqual(12 + 1, cols2.GetColArray(8).max); // 1 based + + Assert.AreEqual(false, cols2.GetColArray(9).IsSetHidden()); + Assert.AreEqual(false, cols2.GetColArray(9).IsSetCollapsed()); + Assert.AreEqual(false, cols2.GetColArray(9).collapsed); + Assert.AreEqual(0, cols2.GetColArray(9).outlineLevel); + Assert.AreEqual(13 + 1, cols2.GetColArray(9).min); // 1 based + Assert.AreEqual(13 + 1, cols2.GetColArray(9).max); // 1 based wb2.Close(); } @@ -720,7 +1517,6 @@ public void TestSetRowGroupCollapsed() Assert.AreEqual(false, ((XSSFRow)sheet1.GetRow(18)).GetCTRow().IsSetCollapsed()); Assert.AreEqual(false, ((XSSFRow)sheet1.GetRow(18)).GetCTRow().IsSetHidden()); - // Save and re-load XSSFWorkbook wb2 = XSSFTestDataSamples.WriteOutAndReadBack(wb1); sheet1 = (XSSFSheet)wb2.GetSheetAt(0); @@ -806,9 +1602,21 @@ public void Test47862() // //a span of columns [1,5] - Assert.AreEqual(1, cols.sizeOfColArray()); + Assert.AreEqual(5, cols.sizeOfColArray()); CT_Col col = cols.GetColArray(0); Assert.AreEqual((uint)1, col.min); + Assert.AreEqual((uint)1, col.max); + col = cols.GetColArray(1); + Assert.AreEqual((uint)2, col.min); + Assert.AreEqual((uint)2, col.max); + col = cols.GetColArray(2); + Assert.AreEqual((uint)3, col.min); + Assert.AreEqual((uint)3, col.max); + col = cols.GetColArray(3); + Assert.AreEqual((uint)4, col.min); + Assert.AreEqual((uint)4, col.max); + col = cols.GetColArray(4); + Assert.AreEqual((uint)5, col.min); Assert.AreEqual((uint)5, col.max); double swidth = 15.77734375; //width of columns in the span Assert.AreEqual(swidth, col.width, 0.0); @@ -866,7 +1674,7 @@ public void Test47804() XSSFWorkbook wb1 = XSSFTestDataSamples.OpenSampleWorkbook("47804.xlsx"); XSSFSheet sheet = (XSSFSheet)wb1.GetSheetAt(0); CT_Cols cols = sheet.GetCTWorksheet().GetColsArray(0); - Assert.AreEqual(2, cols.sizeOfColArray()); + Assert.AreEqual(4, cols.sizeOfColArray()); CT_Col col; // // @@ -876,9 +1684,15 @@ public void Test47804() //a span of columns [2,4] col = cols.GetColArray(0); Assert.AreEqual((uint)2, col.min); + Assert.AreEqual((uint)2, col.max); + col = cols.GetColArray(1); + Assert.AreEqual((uint)3, col.min); + Assert.AreEqual((uint)3, col.max); + col = cols.GetColArray(2); + Assert.AreEqual((uint)4, col.min); Assert.AreEqual((uint)4, col.max); //individual column - col = cols.GetColArray(1); + col = cols.GetColArray(3); Assert.AreEqual((uint)7, col.min); Assert.AreEqual((uint)7, col.max); @@ -919,7 +1733,7 @@ public void Test47804() Assert.AreEqual((uint)7, col.max); //serialize and check again - XSSFWorkbook wb2 = (XSSFWorkbook)XSSFTestDataSamples.WriteOutAndReadBack(wb1); + XSSFWorkbook wb2 = XSSFTestDataSamples.WriteOutAndReadBack(wb1); wb1.Close(); sheet = (XSSFSheet)wb2.GetSheetAt(0); @@ -1000,7 +1814,6 @@ public void TestCommentsTable() row3.CreateCell(2); row3.CreateCell(5); - List xrow = sheetData.row; Assert.AreEqual(3, xrow.Count); @@ -1047,7 +1860,6 @@ public void TestCommentsTable() Assert.AreEqual("D1", xcell[2].r); Assert.AreEqual("F1", xcell[3].r); - Assert.AreEqual(0, xrow[1].SizeOfCArray()); Assert.AreEqual(2u, xrow[1].r); @@ -1096,7 +1908,6 @@ public void TestProtectSheet_lowlevel() int actualVal = int.Parse(pr.password, NumberStyles.HexNumber); Assert.AreEqual(hashVal, actualVal, "well known value for top secret hash should match"); - sheet.ProtectSheet(null); Assert.IsNull(sheet.GetCTWorksheet().sheetProtection, "protectSheet(null) should unset CTSheetProtection"); @@ -1126,7 +1937,6 @@ public void protectSheet_emptyPassword() wb.Close(); } - [Test] public void ProtectSheet_lowlevel_2013() { @@ -1160,7 +1970,7 @@ public void Test49966() Assert.AreEqual(0, calcChain.GetCTCalcChain().SizeOfCArray(), "XSSFSheet#RemoveRow did not clear calcChain entries"); //calcChain should be gone - XSSFWorkbook wb2 = (XSSFWorkbook)XSSFTestDataSamples.WriteOutAndReadBack(wb1); + XSSFWorkbook wb2 = XSSFTestDataSamples.WriteOutAndReadBack(wb1); wb1.Close(); Assert.IsNull(wb2.GetCalculationChain()); @@ -1210,22 +2020,21 @@ public void TestSetForceFormulaRecalculation() Assert.IsFalse(sheet.ForceFormulaRecalculation); // Set - sheet.ForceFormulaRecalculation = (true); + sheet.ForceFormulaRecalculation = true; Assert.AreEqual(true, sheet.ForceFormulaRecalculation); // calcMode="manual" is unset when forceFormulaRecalculation=true CT_CalcPr calcPr = wb1.GetCTWorkbook().AddNewCalcPr(); - calcPr.calcMode = (ST_CalcMode.manual); - sheet.ForceFormulaRecalculation = (true); + calcPr.calcMode = ST_CalcMode.manual; + sheet.ForceFormulaRecalculation = true; Assert.AreEqual(ST_CalcMode.auto, calcPr.calcMode); // Check - sheet.ForceFormulaRecalculation = (false); + sheet.ForceFormulaRecalculation = false; Assert.AreEqual(false, sheet.ForceFormulaRecalculation); - // Save, re-load, and re-check - XSSFWorkbook wb2 = (XSSFWorkbook)XSSFTestDataSamples.WriteOutAndReadBack(wb1); + XSSFWorkbook wb2 = XSSFTestDataSamples.WriteOutAndReadBack(wb1); wb1.Close(); sheet = (XSSFSheet)wb2.GetSheet("Sheet 1"); @@ -1251,7 +2060,7 @@ public void Bug54607() private void runGetTopRow(String file, bool isXSSF, params int[] topRows) { - IWorkbook wb = (isXSSF) ? + IWorkbook wb = isXSSF ? wb = XSSFTestDataSamples.OpenSampleWorkbook(file) : wb = HSSFTestDataSamples.OpenSampleWorkbook(file); @@ -1261,6 +2070,7 @@ private void runGetTopRow(String file, bool isXSSF, params int[] topRows) Assert.IsNotNull(sh.SheetName); Assert.AreEqual(topRows[si], sh.TopRow, "Did not match for sheet " + si); } + Assert.Warn("test about SXSSFWorkbook was commented"); // for XSSF also test with SXSSF if (isXSSF) @@ -1280,12 +2090,13 @@ private void runGetTopRow(String file, bool isXSSF, params int[] topRows) swb.Close(); } } + wb.Close(); } private void runGetLeftCol(String file, bool isXSSF, params int[] topRows) { - IWorkbook wb = (isXSSF) ? + IWorkbook wb = isXSSF ? wb = XSSFTestDataSamples.OpenSampleWorkbook(file) : wb = HSSFTestDataSamples.OpenSampleWorkbook(file); @@ -1307,8 +2118,10 @@ private void runGetLeftCol(String file, bool isXSSF, params int[] topRows) Assert.IsNotNull(sh.SheetName); Assert.AreEqual(topRows[si], sh.LeftCol, "Did not match for sheet " + si); } + swb.Close(); } + wb.Close(); } @@ -1376,22 +2189,22 @@ private XSSFWorkbook SetupSheet() XSSFWorkbook wb = new XSSFWorkbook(); XSSFSheet sheet = wb.CreateSheet() as XSSFSheet; - IRow row1 = sheet.CreateRow((short)0); - ICell cell = row1.CreateCell((short)0); + IRow row1 = sheet.CreateRow(0); + ICell cell = row1.CreateCell(0); cell.SetCellValue("Names"); - ICell cell2 = row1.CreateCell((short)1); + ICell cell2 = row1.CreateCell(1); cell2.SetCellValue("#"); - IRow row2 = sheet.CreateRow((short)1); - ICell cell3 = row2.CreateCell((short)0); + IRow row2 = sheet.CreateRow(1); + ICell cell3 = row2.CreateCell(0); cell3.SetCellValue("Jane"); - ICell cell4 = row2.CreateCell((short)1); + ICell cell4 = row2.CreateCell(1); cell4.SetCellValue(3); - IRow row3 = sheet.CreateRow((short)2); - ICell cell5 = row3.CreateCell((short)0); + IRow row3 = sheet.CreateRow(2); + ICell cell5 = row3.CreateCell(0); cell5.SetCellValue("John"); - ICell cell6 = row3.CreateCell((short)1); + ICell cell6 = row3.CreateCell(1); cell6.SetCellValue(3); return wb; @@ -1529,7 +2342,6 @@ public void TestCreateComment() wb.Close(); } - protected void testCopyOneRow(String copyRowsTestWorkbook) { double FLOAT_PRECISION = 1e-9; @@ -1907,7 +2719,7 @@ public void TestIgnoredErrors() Dictionary> ignoredErrors = sheet.GetIgnoredErrors(); Assert.AreEqual(1, ignoredErrors.Count); Assert.AreEqual(1, ignoredErrors[IgnoredErrorType.NumberStoredAsText].Count); - var it = ignoredErrors[IgnoredErrorType.NumberStoredAsText].GetEnumerator(); + IEnumerator it = ignoredErrors[IgnoredErrorType.NumberStoredAsText].GetEnumerator(); it.MoveNext(); Assert.AreEqual("B2:D4", it.Current.FormatAsString()); @@ -1930,7 +2742,7 @@ public void TestIgnoredErrorsMultipleTypes() Dictionary> ignoredErrors = sheet.GetIgnoredErrors(); Assert.AreEqual(2, ignoredErrors.Count); Assert.AreEqual(1, ignoredErrors[IgnoredErrorType.Formula].Count); - var it = ignoredErrors[IgnoredErrorType.Formula].GetEnumerator(); + IEnumerator it = ignoredErrors[IgnoredErrorType.Formula].GetEnumerator(); it.MoveNext(); Assert.AreEqual("B2:D4", it.Current.FormatAsString()); Assert.AreEqual(1, ignoredErrors[IgnoredErrorType.EvaluationError].Count); @@ -1964,7 +2776,7 @@ public void TestIgnoredErrorsMultipleCalls() Dictionary> ignoredErrors = sheet.GetIgnoredErrors(); Assert.AreEqual(2, ignoredErrors.Count); Assert.AreEqual(1, ignoredErrors[IgnoredErrorType.Formula].Count); - var it = ignoredErrors[IgnoredErrorType.Formula].GetEnumerator(); + IEnumerator it = ignoredErrors[IgnoredErrorType.Formula].GetEnumerator(); it.MoveNext(); Assert.AreEqual("B2:D4", it.Current.FormatAsString()); Assert.AreEqual(1, ignoredErrors[IgnoredErrorType.EvaluationError].Count); @@ -2027,8 +2839,10 @@ public void TabColor() Assert.AreEqual(expected, (wb.GetSheet("indexedRed") as XSSFSheet).TabColor); // test regular-colored (non-indexed, ARGB) sheet - expected = new XSSFColor(); - expected.ARGBHex = "FF7F2700"; + expected = new XSSFColor + { + ARGBHex = "FF7F2700" + }; Assert.AreEqual(expected, (wb.GetSheet("customOrange") as XSSFSheet).TabColor); } finally @@ -2065,7 +2879,7 @@ private void AddComments(ICreationHelper helper, ISheet sheet) anchor.Col2 = 2; anchor.Row2 = 3 + i; IComment comment = drawing.CreateCellComment(anchor); - comment.String = (helper.CreateRichTextString("BugTesting")); + comment.String = helper.CreateRichTextString("BugTesting"); IRow row = sheet.GetRow(0 + i); if (row == null) { diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFSheetColumns.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFSheetColumns.cs new file mode 100644 index 000000000..572f3ce21 --- /dev/null +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFSheetColumns.cs @@ -0,0 +1,690 @@ +/* ==================================================================== + 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.UserModel; +using NPOI.SS.Util; +using NPOI.Util; +using NPOI.XSSF.UserModel; +using NUnit.Framework; +using System; +using System.IO; + +namespace TestCases.XSSF.UserModel +{ + [TestFixture] + public class TestXSSFSheetColumns + { + public TestXSSFSheetColumns() + { + + } + + [Test] + public void FirstColumnNum_ReturnsCorrectNumber() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + + _ = sheet.CreateColumn(10); + + Assert.AreEqual(10, sheet.FirstColumnNum); + + FileInfo file = TempFile.CreateTempFile("poi-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + + Assert.AreEqual(10, sheetLoaded.FirstColumnNum); + } + + [Test] + public void LastColumnNum_ReturnsCorrectNumber() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + + _ = sheet.CreateColumn(10); + + Assert.AreEqual(10, sheet.LastColumnNum); + + FileInfo file = TempFile.CreateTempFile("poi-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + + Assert.AreEqual(10, sheetLoaded.LastColumnNum); + } + + [Test] + public void PhysicalNumberOfColumns_ReturnsCorrectNumber() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + int colNumber = 12; + + for (int i = 0; i < colNumber; i++) + { + _ = sheet.CreateColumn(i); + } + + Assert.AreEqual(0, sheet.FirstColumnNum); + Assert.AreEqual(colNumber - 1, sheet.LastColumnNum); + Assert.AreEqual(colNumber, sheet.PhysicalNumberOfColumns); + + FileInfo file = TempFile.CreateTempFile("poi-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + + Assert.AreEqual(0, sheetLoaded.FirstColumnNum); + Assert.AreEqual(colNumber - 1, sheetLoaded.LastColumnNum); + Assert.AreEqual(colNumber, sheetLoaded.PhysicalNumberOfColumns); + } + + [Test] + public void CreateColumn_AtIndex6_ColumnIsCreatedWithCorrectIndex() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + int colIndex = 6; + + _ = sheet.CreateColumn(colIndex); + + IColumn column = sheet.GetColumn(colIndex); + + Assert.NotNull(column); + Assert.AreEqual(colIndex, column.ColumnNum); + + FileInfo file = TempFile.CreateTempFile("poi-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + IColumn columnLoaded = sheetLoaded.GetColumn(colIndex); + + Assert.NotNull(columnLoaded); + Assert.AreEqual(colIndex, columnLoaded.ColumnNum); + } + + [Test] + public void CreateColumn_AtIndex6Twice_ColumnIsCreatedWithCorrectIndexAndNoCells() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + int colIndex = 6; + + sheet.CreateColumn(colIndex).CreateCell(0).SetCellValue(1); + IColumn column = sheet.GetColumn(colIndex); + + Assert.NotNull(column); + Assert.AreEqual(colIndex, column.ColumnNum); + Assert.AreEqual(1, column.GetCell(0).NumericCellValue); + + IColumn columnOverwrite = sheet.CreateColumn(colIndex); + + Assert.NotNull(columnOverwrite); + Assert.AreEqual(colIndex, columnOverwrite.ColumnNum); + Assert.IsNull(columnOverwrite.GetCell(0)); + + FileInfo file = TempFile.CreateTempFile("poi-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + IColumn columnLoaded = sheetLoaded.GetColumn(colIndex); + + Assert.NotNull(columnLoaded); + Assert.AreEqual(colIndex, columnLoaded.ColumnNum); + Assert.IsNull(columnLoaded.GetCell(0)); + } + + [Test] + public void GetColumn_GetExistingColumn_ReturnsAColumn() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + + _ = sheet.CreateColumn(10); + IColumn column = sheet.GetColumn(10); + + Assert.NotNull(column); + Assert.AreEqual(10, column.ColumnNum); + + FileInfo file = TempFile.CreateTempFile("poi-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + IColumn columnLoaded = sheetLoaded.GetColumn(10); + + Assert.NotNull(columnLoaded); + Assert.AreEqual(10, columnLoaded.ColumnNum); + } + + [Test] + public void GetColumn_GetNonExistingColumn_ReturnsNull() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + + IColumn column = sheet.GetColumn(10); + + Assert.IsNull(column); + + FileInfo file = TempFile.CreateTempFile("poi-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + IColumn columnLoaded = sheetLoaded.GetColumn(10); + + Assert.IsNull(columnLoaded); + } + + [Test] + public void RemoveColumn_RemoveExistingColumn_ColumnIsRemoved() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + + _ = sheet.CreateColumn(1); + _ = sheet.CreateColumn(2); + _ = sheet.CreateColumn(3); + + Assert.NotNull(sheet.GetColumn(1)); + Assert.NotNull(sheet.GetColumn(2)); + Assert.NotNull(sheet.GetColumn(3)); + Assert.AreEqual(1, sheet.FirstColumnNum); + Assert.AreEqual(3, sheet.LastColumnNum); + + sheet.RemoveColumn(sheet.GetColumn(3)); + + Assert.IsNull(sheet.GetColumn(3)); + Assert.AreEqual(1, sheet.FirstColumnNum); + Assert.AreEqual(2, sheet.LastColumnNum); + + _ = sheet.CreateColumn(3); + + sheet.RemoveColumn(sheet.GetColumn(1)); + + Assert.IsNull(sheet.GetColumn(1)); + Assert.AreEqual(2, sheet.FirstColumnNum); + Assert.AreEqual(3, sheet.LastColumnNum); + + _ = sheet.CreateColumn(1); + + Assert.NotNull(sheet.GetColumn(3)); + Assert.AreEqual(3, sheet.LastColumnNum); + + sheet.RemoveColumn(sheet.GetColumn(2)); + + Assert.IsNull(sheet.GetColumn(2)); + Assert.AreEqual(1, sheet.FirstColumnNum); + Assert.AreEqual(3, sheet.LastColumnNum); + + FileInfo file = TempFile.CreateTempFile("poi-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + + Assert.IsNull(sheetLoaded.GetColumn(2)); + Assert.AreEqual(1, sheetLoaded.FirstColumnNum); + Assert.AreEqual(3, sheetLoaded.LastColumnNum); + } + + [Test] + public void RemoveColumn_RemoveNonExistingColumn_ExceptionIsThrown() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + + _ = sheet.CreateColumn(1); + _ = sheet.CreateColumn(2); + _ = sheet.CreateColumn(3); + + Assert.NotNull(sheet.GetColumn(1)); + Assert.NotNull(sheet.GetColumn(2)); + Assert.NotNull(sheet.GetColumn(3)); + Assert.AreEqual(1, sheet.FirstColumnNum); + Assert.AreEqual(3, sheet.LastColumnNum); + + _ = Assert.Throws(() => sheet.RemoveColumn(sheet.GetColumn(4))); + } + + /// + /// Tests sets up a column with formula, merged region with data in it + /// custom width and comments and copies in to a place where there is no + /// column exsits yet. The outcome is exact copy of the column is created + /// in a new index with no data loss. + /// + [Test] + public void CopyColumn_ColumnWithDataCommentsFormulasMergedRegionsCopiedToNewPlace_ColumncopiedWithAllItsContents() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFFormulaEvaluator fe = new XSSFFormulaEvaluator(wb); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + XSSFDrawing dg = (XSSFDrawing)sheet.CreateDrawingPatriarch(); + XSSFComment comment = (XSSFComment)dg.CreateCellComment(new XSSFClientAnchor()); + comment.Author = "POI"; + comment.String = new XSSFRichTextString("A new comment"); + int originalColIndex = 1; + int copyColIndex = 4; + short width = 20; + int mergedRegionFirstRow = 10; + int mergedRegionLastRow = 20; + + XSSFColumn originalColumn = (XSSFColumn)sheet.CreateColumn(originalColIndex); + originalColumn.Width = width; + XSSFCell formulaCell1 = (XSSFCell)originalColumn.CreateCell(0); + formulaCell1.SetCellFormula("C1 + D1"); + formulaCell1.CellComment = comment; + sheet.CreateColumn(originalColIndex + 1).CreateCell(0).SetCellValue(10); + sheet.CreateColumn(originalColIndex + 2).CreateCell(0).SetCellValue(20); + originalColumn.CreateCell(mergedRegionFirstRow).SetCellValue("POI"); + _ = sheet.AddMergedRegion( + new CellRangeAddress( + mergedRegionFirstRow, + mergedRegionLastRow, + originalColumn.ColumnNum, + originalColumn.ColumnNum + 1)); + CellRangeAddress originaMergedRegion = sheet.GetMergedRegion(0); + + fe.EvaluateAll(); + + Assert.AreEqual("POI", sheet.GetRow(mergedRegionFirstRow).GetCell(originalColIndex).StringCellValue); + Assert.AreEqual("POI", formulaCell1.CellComment.Author); + Assert.AreEqual(30, formulaCell1.NumericCellValue); + Assert.AreEqual(1, sheet.NumMergedRegions); + Assert.NotNull(originaMergedRegion); + + XSSFColumn copyColumn = (XSSFColumn)sheet.CopyColumn(originalColIndex, copyColIndex); + CellRangeAddress copyMergedRegion = sheet.GetMergedRegion(1); + fe.EvaluateAll(); + + XSSFCell formulaCell2 = (XSSFCell)sheet.GetColumn(copyColIndex).GetCell(0); + + Assert.AreEqual(1, sheet.FirstColumnNum); + Assert.AreEqual(4, sheet.LastColumnNum); + Assert.AreEqual(width, copyColumn.Width); + //Assert.AreEqual("POI", sheet.GetRow(mergedRegionFirstRow).GetCell(copyColIndex).StringCellValue); + Assert.AreEqual("POI", formulaCell2.CellComment.Author); + Assert.AreEqual("C1 + D1", formulaCell2.CellFormula); + Assert.AreEqual(30, formulaCell2.NumericCellValue); + Assert.AreEqual(2, sheet.NumMergedRegions); + Assert.NotNull(originaMergedRegion); + Assert.NotNull(copyMergedRegion); + Assert.AreEqual(mergedRegionFirstRow, copyMergedRegion.FirstRow); + Assert.AreEqual(mergedRegionLastRow, copyMergedRegion.LastRow); + Assert.AreEqual(copyColumn.ColumnNum, copyMergedRegion.FirstColumn); + Assert.AreEqual(copyColumn.ColumnNum + 1, copyMergedRegion.LastColumn); + + FileInfo file = TempFile.CreateTempFile("ShiftCols-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFFormulaEvaluator feLoaded = new XSSFFormulaEvaluator(wbLoaded); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + XSSFColumn originalColumnLoaded = (XSSFColumn)sheetLoaded.GetColumn(originalColIndex); + XSSFColumn copyColumnLoaded = (XSSFColumn)sheetLoaded.GetColumn(copyColIndex); + XSSFCell formulaCellLoaded = (XSSFCell)copyColumnLoaded.GetCell(0); + CellRangeAddress originalMergedRegionLoaded = sheet.GetMergedRegion(0); + CellRangeAddress copyMergedRegionLoaded = sheet.GetMergedRegion(1); + + feLoaded.EvaluateAll(); + + Assert.AreEqual(1, sheetLoaded.FirstColumnNum); + Assert.AreEqual(4, sheetLoaded.LastColumnNum); + Assert.AreEqual(width, copyColumnLoaded.Width); + Assert.AreEqual(10, sheetLoaded.GetColumn(originalColIndex + 1).GetCell(0).NumericCellValue); + Assert.AreEqual(20, sheetLoaded.GetColumn(originalColIndex + 2).GetCell(0).NumericCellValue); + Assert.AreEqual("POI", sheetLoaded.GetRow(mergedRegionFirstRow).GetCell(copyColIndex).StringCellValue); + Assert.AreEqual("POI", formulaCellLoaded.CellComment.Author); + Assert.AreEqual("C1 + D1", formulaCellLoaded.CellFormula); + Assert.AreEqual(30, formulaCellLoaded.NumericCellValue); + Assert.NotNull(originalMergedRegionLoaded); + Assert.AreEqual(mergedRegionFirstRow, originalMergedRegionLoaded.FirstRow); + Assert.AreEqual(mergedRegionLastRow, originalMergedRegionLoaded.LastRow); + Assert.AreEqual(originalColumnLoaded.ColumnNum, originalMergedRegionLoaded.FirstColumn); + Assert.AreEqual(originalColumnLoaded.ColumnNum + 1, originalMergedRegionLoaded.LastColumn); + Assert.NotNull(copyMergedRegionLoaded); + Assert.AreEqual(mergedRegionFirstRow, copyMergedRegionLoaded.FirstRow); + Assert.AreEqual(mergedRegionLastRow, copyMergedRegionLoaded.LastRow); + Assert.AreEqual(copyColumnLoaded.ColumnNum, copyMergedRegionLoaded.FirstColumn); + Assert.AreEqual(copyColumnLoaded.ColumnNum + 1, copyMergedRegionLoaded.LastColumn); + } + + /// + /// Tests sets up a column with formula, merged region with data in it + /// custom width and comments and copies in to a place of pre-existing + /// column. The outcome is pre-existing column gets shifted to the right, + /// exact copy of the copied column is created in it's place with no data loss. + /// + [Test] + public void CopyColumn_ColumnWithDataCommentsFormulasMergedRegionsCopiedToPlaceOfExistingColumn_ExistingColumnIsShiftedColumnCopied() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFFormulaEvaluator fe = new XSSFFormulaEvaluator(wb); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + XSSFDrawing dg = (XSSFDrawing)sheet.CreateDrawingPatriarch(); + XSSFComment comment = (XSSFComment)dg.CreateCellComment(new XSSFClientAnchor()); + comment.Author = "POI"; + comment.String = new XSSFRichTextString("A new comment"); + int originalColIndex = 1; + int copyColIndex = 4; + short width = 20; + int mergedRegionFirstRow = 10; + int mergedRegionLastRow = 20; + + XSSFColumn anotherColumn = (XSSFColumn)sheet.CreateColumn(copyColIndex); + anotherColumn.CreateCell(0).SetCellValue("POI"); + anotherColumn.Width = (short)(width * 2); + XSSFColumn originalColumn = (XSSFColumn)sheet.CreateColumn(originalColIndex); + originalColumn.Width = width; + XSSFCell formulaCell1 = (XSSFCell)originalColumn.CreateCell(0); + formulaCell1.SetCellFormula("C1 + D1"); + formulaCell1.CellComment = comment; + sheet.CreateColumn(originalColIndex + 1).CreateCell(0).SetCellValue(10); + sheet.CreateColumn(originalColIndex + 2).CreateCell(0).SetCellValue(20); + originalColumn.CreateCell(mergedRegionFirstRow).SetCellValue("POI"); + _ = sheet.AddMergedRegion( + new CellRangeAddress( + mergedRegionFirstRow, + mergedRegionLastRow, + originalColumn.ColumnNum, + originalColumn.ColumnNum + 1)); + CellRangeAddress originaMergedRegion = sheet.GetMergedRegion(0); + + fe.EvaluateAll(); + + Assert.AreEqual("POI", sheet.GetRow(mergedRegionFirstRow).GetCell(originalColIndex).StringCellValue); + Assert.AreEqual("POI", formulaCell1.CellComment.Author); + Assert.AreEqual(30, formulaCell1.NumericCellValue); + Assert.AreEqual(1, sheet.NumMergedRegions); + Assert.NotNull(originaMergedRegion); + + XSSFColumn copyColumn = (XSSFColumn)sheet.CopyColumn(originalColIndex, copyColIndex); + CellRangeAddress copyMergedRegion = sheet.GetMergedRegion(1); + fe.EvaluateAll(); + + XSSFCell formulaCell2 = (XSSFCell)sheet.GetColumn(copyColIndex).GetCell(0); + + Assert.AreEqual(copyColIndex + 1, anotherColumn.ColumnNum); + Assert.AreEqual("POI", sheet.GetRow(0).GetCell(copyColIndex + 1).StringCellValue); + Assert.AreEqual(1, sheet.FirstColumnNum); + Assert.AreEqual(5, sheet.LastColumnNum); + Assert.AreEqual(width, copyColumn.Width); + Assert.AreEqual("POI", sheet.GetRow(mergedRegionFirstRow).GetCell(copyColIndex).StringCellValue); + Assert.AreEqual("POI", formulaCell2.CellComment.Author); + Assert.AreEqual("C1 + D1", formulaCell2.CellFormula); + Assert.AreEqual(30, formulaCell2.NumericCellValue); + Assert.AreEqual(2, sheet.NumMergedRegions); + Assert.NotNull(originaMergedRegion); + Assert.NotNull(copyMergedRegion); + Assert.AreEqual(mergedRegionFirstRow, copyMergedRegion.FirstRow); + Assert.AreEqual(mergedRegionLastRow, copyMergedRegion.LastRow); + Assert.AreEqual(copyColumn.ColumnNum, copyMergedRegion.FirstColumn); + Assert.AreEqual(copyColumn.ColumnNum + 1, copyMergedRegion.LastColumn); + + FileInfo file = TempFile.CreateTempFile("ShiftCols-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFFormulaEvaluator feLoaded = new XSSFFormulaEvaluator(wbLoaded); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + XSSFColumn originalColumnLoaded = (XSSFColumn)sheetLoaded.GetColumn(originalColIndex); + XSSFColumn copyColumnLoaded = (XSSFColumn)sheetLoaded.GetColumn(copyColIndex); + XSSFCell formulaCellLoaded = (XSSFCell)copyColumnLoaded.GetCell(0); + CellRangeAddress originalMergedRegionLoaded = sheet.GetMergedRegion(0); + CellRangeAddress copyMergedRegionLoaded = sheet.GetMergedRegion(1); + + feLoaded.EvaluateAll(); + + Assert.AreEqual(1, sheetLoaded.FirstColumnNum); + Assert.AreEqual(5, sheetLoaded.LastColumnNum); + Assert.AreEqual(width, copyColumnLoaded.Width); + Assert.AreEqual(10, sheetLoaded.GetColumn(originalColIndex + 1).GetCell(0).NumericCellValue); + Assert.AreEqual(20, sheetLoaded.GetColumn(originalColIndex + 2).GetCell(0).NumericCellValue); + Assert.AreEqual("POI", sheetLoaded.GetRow(mergedRegionFirstRow).GetCell(copyColIndex).StringCellValue); + Assert.AreEqual("POI", formulaCellLoaded.CellComment.Author); + Assert.AreEqual("C1 + D1", formulaCellLoaded.CellFormula); + Assert.AreEqual(30, formulaCellLoaded.NumericCellValue); + Assert.NotNull(originalMergedRegionLoaded); + Assert.AreEqual(mergedRegionFirstRow, originalMergedRegionLoaded.FirstRow); + Assert.AreEqual(mergedRegionLastRow, originalMergedRegionLoaded.LastRow); + Assert.AreEqual(originalColumnLoaded.ColumnNum, originalMergedRegionLoaded.FirstColumn); + Assert.AreEqual(originalColumnLoaded.ColumnNum + 1, originalMergedRegionLoaded.LastColumn); + Assert.NotNull(copyMergedRegionLoaded); + Assert.AreEqual(mergedRegionFirstRow, copyMergedRegionLoaded.FirstRow); + Assert.AreEqual(mergedRegionLastRow, copyMergedRegionLoaded.LastRow); + Assert.AreEqual(copyColumnLoaded.ColumnNum, copyMergedRegionLoaded.FirstColumn); + Assert.AreEqual(copyColumnLoaded.ColumnNum + 1, copyMergedRegionLoaded.LastColumn); + } + + [Test] + public void ShiftColumns_Shift2ColumnsWithCommentsAndFormulasAndOverlapingMergedRegion_ColumnsShiftedCommentsShiftedFormulasAreUpdatedMergedRegionRemoved() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFFormulaEvaluator fe = new XSSFFormulaEvaluator(wb); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + XSSFDrawing dg = (XSSFDrawing)sheet.CreateDrawingPatriarch(); + XSSFComment comment = (XSSFComment)dg.CreateCellComment(new XSSFClientAnchor()); + comment.Author = "POI"; + comment.String = new XSSFRichTextString("A new comment"); + + XSSFCell mergedRegionStart = (XSSFCell)sheet.CreateRow(10).CreateCell(0); + mergedRegionStart.SetCellValue("MERGED"); + int mergedRegionIndex = sheet.AddMergedRegion(new CellRangeAddress(10, 11, 0, 10)); + CellRangeAddress mergedRegion = sheet.GetMergedRegion(mergedRegionIndex); + + XSSFCell formulaCell = (XSSFCell)sheet.CreateColumn(1).CreateCell(0); + formulaCell.SetCellFormula("C1 + D1"); + XSSFCell cell1 = (XSSFCell)sheet.CreateColumn(2).CreateCell(0); + cell1.SetCellValue(10); + cell1.CellComment = comment; + sheet.CreateColumn(3).CreateCell(0).SetCellValue(20); + + fe.EvaluateAll(); + + Assert.AreEqual("POI", sheet.GetColumn(2).GetCell(0).CellComment.Author); + Assert.AreEqual(30, formulaCell.NumericCellValue); + Assert.AreEqual("MERGED", sheet.GetRow(10).GetCell(0).StringCellValue); + Assert.AreEqual(1, sheet.NumMergedRegions); + Assert.NotNull(mergedRegion); + Assert.AreEqual("A11:K12", mergedRegion.FormatAsString()); + + sheet.ShiftColumns(2, 3, 4); + fe.EvaluateAll(); + + Assert.AreEqual(1, sheet.FirstColumnNum); + Assert.AreEqual(7, sheet.LastColumnNum); + Assert.AreEqual(10, sheet.GetColumn(6).GetCell(0).NumericCellValue); + Assert.AreEqual(20, sheet.GetColumn(7).GetCell(0).NumericCellValue); + cell1 = (XSSFCell)sheet.GetColumn(6).GetCell(0); + Assert.AreEqual("POI", cell1.CellComment.Author); + Assert.AreEqual("G1+H1", formulaCell.CellFormula); + Assert.AreEqual(30, formulaCell.NumericCellValue); + Assert.AreEqual("MERGED", sheet.GetRow(10).GetCell(0).StringCellValue); + Assert.AreEqual(0, sheet.NumMergedRegions); + + FileInfo file = TempFile.CreateTempFile("ShiftCols-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFFormulaEvaluator feLoaded = new XSSFFormulaEvaluator(wbLoaded); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + XSSFCell formulaCellLoaded = (XSSFCell)sheetLoaded.GetColumn(1).GetCell(0); + + feLoaded.EvaluateAll(); + + Assert.IsNull(sheetLoaded.GetColumn(2)); + Assert.AreEqual(1, sheetLoaded.FirstColumnNum); + Assert.AreEqual(7, sheetLoaded.LastColumnNum); + Assert.AreEqual(10, sheetLoaded.GetColumn(6).GetCell(0).NumericCellValue); + Assert.AreEqual(20, sheetLoaded.GetColumn(7).GetCell(0).NumericCellValue); + Assert.AreEqual("POI", sheetLoaded.GetColumn(6).GetCell(0).CellComment.Author); + Assert.AreEqual("G1+H1", formulaCellLoaded.CellFormula); + Assert.AreEqual(30, formulaCellLoaded.NumericCellValue); + Assert.AreEqual("MERGED", sheetLoaded.GetRow(10).GetCell(0).StringCellValue); + Assert.AreEqual(0, sheetLoaded.NumMergedRegions); + } + + [Test] + public void ShiftColumns_Shift1ColumnWithCommentsAndFormulas_ColumnShiftedCommentShiftedFormulaUpdated() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFFormulaEvaluator fe = new XSSFFormulaEvaluator(wb); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + XSSFDrawing dg = (XSSFDrawing)sheet.CreateDrawingPatriarch(); + XSSFComment comment = (XSSFComment)dg.CreateCellComment(new XSSFClientAnchor()); + comment.Author = "POI"; + comment.String = new XSSFRichTextString("A new comment"); + + XSSFCell formulaCell = (XSSFCell)sheet.CreateColumn(1).CreateCell(0); + formulaCell.SetCellFormula("C1 + D1"); + XSSFCell cell1 = (XSSFCell)sheet.CreateColumn(2).CreateCell(0); + cell1.SetCellValue(10); + cell1.CellComment = comment; + sheet.CreateColumn(3).CreateCell(0).SetCellValue(20); + + fe.EvaluateAll(); + + Assert.AreEqual("POI", sheet.GetColumn(2).GetCell(0).CellComment.Author); + Assert.AreEqual(30, formulaCell.NumericCellValue); + + sheet.ShiftColumns(2, 2, 4); + fe.EvaluateAll(); + + Assert.AreEqual(1, sheet.FirstColumnNum); + Assert.AreEqual(6, sheet.LastColumnNum); + Assert.AreEqual(10, sheet.GetColumn(6).GetCell(0).NumericCellValue); + Assert.AreEqual(20, sheet.GetColumn(3).GetCell(0).NumericCellValue); + cell1 = (XSSFCell)sheet.GetColumn(6).GetCell(0); + Assert.AreEqual("POI", cell1.CellComment.Author); + Assert.AreEqual("G1+D1", formulaCell.CellFormula); + Assert.AreEqual(30, formulaCell.NumericCellValue); + + FileInfo file = TempFile.CreateTempFile("ShiftCols-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFFormulaEvaluator feLoaded = new XSSFFormulaEvaluator(wbLoaded); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + XSSFCell formulaCellLoaded = (XSSFCell)sheetLoaded.GetColumn(1).GetCell(0); + + feLoaded.EvaluateAll(); + + Assert.IsNull(sheetLoaded.GetColumn(2)); + Assert.AreEqual(1, sheetLoaded.FirstColumnNum); + Assert.AreEqual(6, sheetLoaded.LastColumnNum); + Assert.AreEqual(10, sheetLoaded.GetColumn(6).GetCell(0).NumericCellValue); + Assert.AreEqual(20, sheetLoaded.GetColumn(3).GetCell(0).NumericCellValue); + Assert.AreEqual("POI", sheetLoaded.GetColumn(6).GetCell(0).CellComment.Author); + Assert.AreEqual("G1+D1", formulaCellLoaded.CellFormula); + Assert.AreEqual(30, formulaCellLoaded.NumericCellValue); + } + + /// + /// This test trys to shift a column which doesn't exist, but there are + /// cells that would fall into that column. The expected behaviour is + /// that system will create a column object, shift it updating formulas + /// and moving cell values and comments and then will destroy created + /// column objects, leaving cells in new places + /// + [Test] + public void ShiftColumns_ShiftNonExistingColumnWithCellsAndComments_CellsAreShiftedNocolumsCreated() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFFormulaEvaluator fe = new XSSFFormulaEvaluator(wb); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet("sheet1"); + XSSFDrawing dg = (XSSFDrawing)sheet.CreateDrawingPatriarch(); + XSSFComment comment = (XSSFComment)dg.CreateCellComment(new XSSFClientAnchor()); + comment.Author = "POI"; + comment.String = new XSSFRichTextString("A new comment"); + + XSSFCell formulaCell = (XSSFCell)sheet.CreateColumn(1).CreateCell(0); + formulaCell.SetCellFormula("C1 + D2"); + sheet.CreateColumn(2).CreateCell(0).SetCellValue(10); + XSSFRow row = (XSSFRow)sheet.CreateRow(1); + XSSFCell cell1 = (XSSFCell)row.CreateCell(3); + cell1.SetCellValue(20); + cell1.CellComment = comment; + + fe.EvaluateAll(); + + Assert.AreEqual("POI", row.GetCell(3).CellComment.Author); + Assert.AreEqual(30, formulaCell.NumericCellValue); + Assert.AreEqual(1, sheet.FirstColumnNum); + Assert.AreEqual(2, sheet.LastColumnNum); + + sheet.ShiftColumns(3, 3, 4); + fe.EvaluateAll(); + + Assert.AreEqual("POI", row.GetCell(7).CellComment.Author); + Assert.AreEqual("C1+H2", formulaCell.CellFormula); + Assert.AreEqual(30, formulaCell.NumericCellValue); + Assert.AreEqual(1, sheet.FirstColumnNum); + Assert.AreEqual(2, sheet.LastColumnNum); + + FileInfo file = TempFile.CreateTempFile("ShiftCols-", ".xlsx"); + Stream output = File.OpenWrite(file.FullName); + wb.Write(output); + output.Close(); + + XSSFWorkbook wbLoaded = new XSSFWorkbook(file.ToString()); + XSSFFormulaEvaluator feLoaded = new XSSFFormulaEvaluator(wbLoaded); + XSSFSheet sheetLoaded = (XSSFSheet)wbLoaded.GetSheet("sheet1"); + XSSFRow rowLoaded = (XSSFRow)sheet.GetRow(1); + XSSFCell formulaCellLoaded = (XSSFCell)sheet.GetRow(0).GetCell(1); + + feLoaded.EvaluateAll(); + + Assert.AreEqual("POI", rowLoaded.GetCell(7).CellComment.Author); + Assert.AreEqual("C1+H2", formulaCellLoaded.CellFormula); + Assert.AreEqual(30, formulaCellLoaded.NumericCellValue); + Assert.AreEqual(1, sheetLoaded.FirstColumnNum); + Assert.AreEqual(2, sheetLoaded.LastColumnNum); + }//*/ + } +} \ No newline at end of file diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFTextRun.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFTextRun.cs index 5239716c9..09f5e8a51 100644 --- a/testcases/ooxml/XSSF/UserModel/TestXSSFTextRun.cs +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFTextRun.cs @@ -22,6 +22,7 @@ namespace TestCases.XSSF.UserModel using NPOI.XSSF.UserModel; using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; + using System.Threading; [TestFixture] public class TestXSSFTextRun @@ -29,6 +30,7 @@ public class TestXSSFTextRun [Test] public void TestXSSFTextParagraph() { + Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); XSSFWorkbook wb = new XSSFWorkbook(); try { diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFWorkbook.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFWorkbook.cs index 5d608a845..d5328e9a6 100644 --- a/testcases/ooxml/XSSF/UserModel/TestXSSFWorkbook.cs +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFWorkbook.cs @@ -67,12 +67,17 @@ public void SaveLoadNew() ISheet sheet1 = wb1.CreateSheet("sheet1"); ISheet sheet2 = wb1.CreateSheet("sheet2"); wb1.CreateSheet("sheet3"); + ISheet sheet4 = wb1.CreateSheet("sheet4"); IRichTextString rts = wb1.GetCreationHelper().CreateRichTextString("hello world"); sheet1.CreateRow(0).CreateCell((short)0).SetCellValue(1.2); sheet1.CreateRow(1).CreateCell((short)0).SetCellValue(rts); sheet2.CreateRow(0); + ((XSSFSheet)sheet2).CreateColumn(0); + + ((XSSFSheet)sheet4).CreateColumn(0).CreateCell(0).SetCellValue(1.2); + ((XSSFSheet)sheet4).CreateColumn(1).CreateCell(0).SetCellValue(rts); Assert.AreEqual(0, wb1.GetSheetAt(0).FirstRowNum); Assert.AreEqual(1, wb1.GetSheetAt(0).LastRowNum); @@ -80,6 +85,17 @@ public void SaveLoadNew() Assert.AreEqual(0, wb1.GetSheetAt(1).LastRowNum); Assert.AreEqual(0, wb1.GetSheetAt(2).FirstRowNum); Assert.AreEqual(0, wb1.GetSheetAt(2).LastRowNum); + Assert.AreEqual(0, wb1.GetSheetAt(3).FirstRowNum); + Assert.AreEqual(0, wb1.GetSheetAt(3).LastRowNum); + + Assert.AreEqual(0, ((XSSFSheet)wb1.GetSheetAt(0)).FirstColumnNum); + Assert.AreEqual(0, ((XSSFSheet)wb1.GetSheetAt(0)).LastColumnNum); + Assert.AreEqual(0, ((XSSFSheet)wb1.GetSheetAt(1)).FirstColumnNum); + Assert.AreEqual(0, ((XSSFSheet)wb1.GetSheetAt(1)).LastColumnNum); + Assert.AreEqual(0, ((XSSFSheet)wb1.GetSheetAt(2)).FirstColumnNum); + Assert.AreEqual(0, ((XSSFSheet)wb1.GetSheetAt(2)).LastColumnNum); + Assert.AreEqual(0, ((XSSFSheet)wb1.GetSheetAt(3)).FirstColumnNum); + Assert.AreEqual(1, ((XSSFSheet)wb1.GetSheetAt(3)).LastColumnNum); FileInfo file = TempFile.CreateTempFile("poi-", ".xlsx"); Stream out1 = File.OpenWrite(file.FullName); @@ -98,15 +114,16 @@ public void SaveLoadNew() pkg.GetPart(PackagingUriHelper.CreatePartName("/xl/workbook.xml")); // Links to the three sheets, shared strings and styles Assert.IsTrue(wbPart.HasRelationships); - Assert.AreEqual(5, wbPart.Relationships.Size); + Assert.AreEqual(6, wbPart.Relationships.Size); wb1.Close(); // Load back the XSSFWorkbook XSSFWorkbook wb2 = new XSSFWorkbook(pkg); - Assert.AreEqual(3, wb2.NumberOfSheets); + Assert.AreEqual(4, wb2.NumberOfSheets); Assert.IsNotNull(wb2.GetSheetAt(0)); Assert.IsNotNull(wb2.GetSheetAt(1)); Assert.IsNotNull(wb2.GetSheetAt(2)); + Assert.IsNotNull(wb2.GetSheetAt(3)); Assert.IsNotNull(wb2.GetSharedStringSource()); Assert.IsNotNull(wb2.GetStylesSource()); @@ -117,10 +134,23 @@ public void SaveLoadNew() Assert.AreEqual(0, wb2.GetSheetAt(1).LastRowNum); Assert.AreEqual(0, wb2.GetSheetAt(2).FirstRowNum); Assert.AreEqual(0, wb2.GetSheetAt(2).LastRowNum); + Assert.AreEqual(0, wb2.GetSheetAt(3).FirstRowNum); + Assert.AreEqual(0, wb2.GetSheetAt(3).LastRowNum); + + Assert.AreEqual(0, ((XSSFSheet)wb1.GetSheetAt(0)).FirstColumnNum); + Assert.AreEqual(0, ((XSSFSheet)wb1.GetSheetAt(0)).LastColumnNum); + Assert.AreEqual(0, ((XSSFSheet)wb1.GetSheetAt(1)).FirstColumnNum); + Assert.AreEqual(0, ((XSSFSheet)wb1.GetSheetAt(1)).LastColumnNum); + Assert.AreEqual(0, ((XSSFSheet)wb1.GetSheetAt(2)).FirstColumnNum); + Assert.AreEqual(0, ((XSSFSheet)wb1.GetSheetAt(2)).LastColumnNum); + Assert.AreEqual(0, ((XSSFSheet)wb1.GetSheetAt(3)).FirstColumnNum); + Assert.AreEqual(1, ((XSSFSheet)wb1.GetSheetAt(3)).LastColumnNum); sheet1 = wb2.GetSheetAt(0); Assert.AreEqual(1.2, sheet1.GetRow(0).GetCell(0).NumericCellValue, 0.0001); + Assert.AreEqual(1.2, ((XSSFSheet)sheet4).GetColumn(0).GetCell(0).NumericCellValue, 0.0001); Assert.AreEqual("hello world", sheet1.GetRow(1).GetCell(0).RichStringCellValue.String); + Assert.AreEqual("hello world", ((XSSFSheet)sheet4).GetColumn(1).GetCell(0).RichStringCellValue.String); pkg.Close(); } @@ -843,6 +873,7 @@ public void LoadWorkbookWithPivotTable() [Test] public void AddPivotTableToWorkbookWithLoadedPivotTable() { + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); String fileName = "ooxml-pivottable.xlsx"; XSSFWorkbook wb = new XSSFWorkbook();