|
@@ -9,25 +9,34 @@ using NPOI.SS.UserModel;
|
|
|
using NPOI.XSSF.UserModel;
|
|
|
using NCell = NPOI.SS.UserModel.ICell;
|
|
|
using NRow = NPOI.SS.UserModel.IRow;
|
|
|
+using NFont = NPOI.SS.UserModel.IFont;
|
|
|
using NSheet = NPOI.SS.UserModel.ISheet;
|
|
|
using NDataFormat = NPOI.SS.UserModel.IDataFormat;
|
|
|
using NCellStyle = NPOI.SS.UserModel.ICellStyle;
|
|
|
using NPOI.SS.Util;
|
|
|
+using NPOI.OpenXmlFormats.Spreadsheet;
|
|
|
+using System.Security.Policy;
|
|
|
+using System.Drawing;
|
|
|
+using NPOI.HSSF.Util;
|
|
|
+using NPOI.HSSF.UserModel;
|
|
|
|
|
|
namespace InABox.Scripting
|
|
|
{
|
|
|
|
|
|
public class RowEnumerator : IEnumerator<Row>
|
|
|
{
|
|
|
+ public Sheet Sheet { get; }
|
|
|
+
|
|
|
private IEnumerator _enumerator { get; set; }
|
|
|
|
|
|
- public Row Current => new Row(_enumerator.Current as NRow);
|
|
|
+ public Row Current => new Row((_enumerator.Current as NRow)!, Sheet);
|
|
|
|
|
|
- object IEnumerator.Current => new Row(_enumerator.Current as NRow);
|
|
|
+ object IEnumerator.Current => new Row((_enumerator.Current as NRow)!, Sheet);
|
|
|
|
|
|
- internal RowEnumerator(IEnumerator enumerator)
|
|
|
+ internal RowEnumerator(IEnumerator enumerator, Sheet sheet)
|
|
|
{
|
|
|
_enumerator = enumerator;
|
|
|
+ Sheet = sheet;
|
|
|
}
|
|
|
|
|
|
public bool MoveNext()
|
|
@@ -51,9 +60,18 @@ namespace InABox.Scripting
|
|
|
|
|
|
public string Name => _sheet.SheetName;
|
|
|
|
|
|
- internal Sheet(NSheet sheet)
|
|
|
+ public int FirstRow => _sheet.FirstRowNum;
|
|
|
+
|
|
|
+ public int LastRow => _sheet.LastRowNum;
|
|
|
+
|
|
|
+ public Spreadsheet Spreadsheet { get; }
|
|
|
+
|
|
|
+ ISpreadsheet ISheet.Spreadsheet => Spreadsheet;
|
|
|
+
|
|
|
+ internal Sheet(NSheet sheet, Spreadsheet spreadsheet)
|
|
|
{
|
|
|
_sheet = sheet;
|
|
|
+ Spreadsheet = spreadsheet;
|
|
|
}
|
|
|
|
|
|
public IEnumerable<IRow> Rows()
|
|
@@ -62,22 +80,41 @@ namespace InABox.Scripting
|
|
|
var row = 0;
|
|
|
while (enumerator.MoveNext() && row <= int.MaxValue)
|
|
|
{
|
|
|
- yield return new Row((NRow)enumerator.Current);
|
|
|
+ yield return new Row((NRow)enumerator.Current, this);
|
|
|
row++;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public IEnumerator<IRow> RowEnumerator()
|
|
|
{
|
|
|
- return new RowEnumerator(_sheet.GetRowEnumerator());
|
|
|
+ return new RowEnumerator(_sheet.GetRowEnumerator(), this);
|
|
|
}
|
|
|
|
|
|
public IRow NewRow()
|
|
|
{
|
|
|
var row = _sheet.CreateRow(_sheet.LastRowNum + 1);
|
|
|
- return new Row(row);
|
|
|
+ return new Row(row, this);
|
|
|
+ }
|
|
|
+
|
|
|
+ public IRow? GetRow(int row)
|
|
|
+ {
|
|
|
+ var nRow = _sheet.GetRow(row);
|
|
|
+ if (nRow is null) return null;
|
|
|
+ return new Row(nRow, this);
|
|
|
+ }
|
|
|
+
|
|
|
+ public float GetRowHeight(int row)
|
|
|
+ {
|
|
|
+ return _sheet.GetRow(row)?.HeightInPoints ?? _sheet.DefaultRowHeightInPoints;
|
|
|
}
|
|
|
|
|
|
+ public float GetColumnWidth(int column)
|
|
|
+ {
|
|
|
+ if (_sheet.IsColumnHidden(column)) return 0f;
|
|
|
+ var width = _sheet.GetColumnWidth(column) / 256f;
|
|
|
+ if (width <= 0f) return float.MinValue;
|
|
|
+ return width;
|
|
|
+ }
|
|
|
public ISheet SetColumnWidth(int column, float charWidth)
|
|
|
{
|
|
|
_sheet.SetColumnWidth(column, (int)Math.Round(charWidth * 256));
|
|
@@ -90,6 +127,14 @@ namespace InABox.Scripting
|
|
|
_sheet.AddMergedRegion(range);
|
|
|
return this;
|
|
|
}
|
|
|
+
|
|
|
+ public IEnumerable<CellRange> GetMergedCells()
|
|
|
+ {
|
|
|
+ foreach(var region in _sheet.MergedRegions)
|
|
|
+ {
|
|
|
+ yield return new CellRange(region.FirstRow, region.LastRow, region.FirstColumn, region.LastColumn);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
public class Row : IRow
|
|
@@ -98,9 +143,18 @@ namespace InABox.Scripting
|
|
|
|
|
|
public int RowNumber => _row.RowNum;
|
|
|
|
|
|
- internal Row(NRow row)
|
|
|
+ public int FirstColumn => _row.FirstCellNum;
|
|
|
+
|
|
|
+ public int LastColumn => _row.LastCellNum;
|
|
|
+
|
|
|
+ public Sheet Sheet { get; }
|
|
|
+
|
|
|
+ ISheet IRow.Sheet => Sheet;
|
|
|
+
|
|
|
+ internal Row(NRow row, Sheet sheet)
|
|
|
{
|
|
|
_row = row;
|
|
|
+ Sheet = sheet;
|
|
|
}
|
|
|
public string ExtractString(int column, bool uppercase = false)
|
|
|
{
|
|
@@ -186,12 +240,25 @@ namespace InABox.Scripting
|
|
|
throw new Exception("Unable to find Column: " + name);
|
|
|
}
|
|
|
|
|
|
- public ICell GetCell(int column) => new Cell(_row.GetCell(column));
|
|
|
+ public ICell? GetCell(int column)
|
|
|
+ {
|
|
|
+ var nCell = _row.GetCell(column);
|
|
|
+ if (nCell is null) return null;
|
|
|
+ return new Cell(nCell, this);
|
|
|
+ }
|
|
|
|
|
|
public ICell NewCell(int column)
|
|
|
{
|
|
|
var cell = _row.CreateCell(column);
|
|
|
- return new Cell(cell);
|
|
|
+ return new Cell(cell, this);
|
|
|
+ }
|
|
|
+
|
|
|
+ public IEnumerable<ICell> Cells()
|
|
|
+ {
|
|
|
+ foreach(var cell in _row)
|
|
|
+ {
|
|
|
+ yield return new Cell(cell, this);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -200,9 +267,14 @@ namespace InABox.Scripting
|
|
|
|
|
|
private NCell _cell;
|
|
|
|
|
|
- internal Cell(NCell cell)
|
|
|
+ IRow ICell.Row => Row;
|
|
|
+
|
|
|
+ public Row Row { get; }
|
|
|
+
|
|
|
+ internal Cell(NCell cell, Row row)
|
|
|
{
|
|
|
_cell = cell;
|
|
|
+ Row = row;
|
|
|
}
|
|
|
|
|
|
public string GetValue()
|
|
@@ -214,7 +286,7 @@ namespace InABox.Scripting
|
|
|
return _cell.StringCellValue;
|
|
|
}
|
|
|
|
|
|
- return _cell.ToString();
|
|
|
+ return _cell.ToString() ?? "";
|
|
|
}
|
|
|
|
|
|
public bool? GetBoolValue()
|
|
@@ -313,24 +385,31 @@ namespace InABox.Scripting
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
+ public ICellStyle GetStyle()
|
|
|
+ {
|
|
|
+ return new CellStyle(_cell.CellStyle, Row.Sheet.Spreadsheet);
|
|
|
+ }
|
|
|
public ICell SetStyle(ICellStyle style)
|
|
|
{
|
|
|
- _cell.CellStyle = (style as CellStyle)._style;
|
|
|
+ _cell.CellStyle = (style as CellStyle)!._style;
|
|
|
return this;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public class SheetEnumerator : IEnumerator<Sheet>
|
|
|
{
|
|
|
- public Sheet Current => new(_enumerator.Current);
|
|
|
+ public Spreadsheet Spreadsheet { get; }
|
|
|
+
|
|
|
+ public Sheet Current => new(_enumerator.Current, Spreadsheet);
|
|
|
|
|
|
private IEnumerator<NSheet> _enumerator { get; }
|
|
|
|
|
|
- object IEnumerator.Current => new Sheet(_enumerator.Current);
|
|
|
+ object IEnumerator.Current => new Sheet(_enumerator.Current, Spreadsheet);
|
|
|
|
|
|
- internal SheetEnumerator(IEnumerator<NSheet> enumerator)
|
|
|
+ internal SheetEnumerator(IEnumerator<NSheet> enumerator, Spreadsheet spreadsheet)
|
|
|
{
|
|
|
_enumerator = enumerator;
|
|
|
+ Spreadsheet = spreadsheet;
|
|
|
}
|
|
|
|
|
|
public void Dispose()
|
|
@@ -359,6 +438,64 @@ namespace InABox.Scripting
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ public class Font : IFont
|
|
|
+ {
|
|
|
+ public Spreadsheet Spreadsheet { get; set; }
|
|
|
+
|
|
|
+ internal NFont _font { get; }
|
|
|
+ public bool Bold { get => _font.IsBold; set => _font.IsBold = value; }
|
|
|
+ public bool Italic { get => _font.IsItalic; set => throw new NotImplementedException(); }
|
|
|
+ public UnderlineType Underline
|
|
|
+ {
|
|
|
+ get => _font.Underline switch
|
|
|
+ {
|
|
|
+ FontUnderlineType.None => UnderlineType.None,
|
|
|
+ FontUnderlineType.Single => UnderlineType.Single,
|
|
|
+ FontUnderlineType.Double => UnderlineType.Double,
|
|
|
+ FontUnderlineType.SingleAccounting => UnderlineType.SingleAccounting,
|
|
|
+ FontUnderlineType.DoubleAccounting => UnderlineType.DoubleAccounting,
|
|
|
+ _ => UnderlineType.None,
|
|
|
+ };
|
|
|
+ set
|
|
|
+ {
|
|
|
+ _font.Underline = value switch
|
|
|
+ {
|
|
|
+ UnderlineType.None => FontUnderlineType.None,
|
|
|
+ UnderlineType.Single => FontUnderlineType.Single,
|
|
|
+ UnderlineType.Double => FontUnderlineType.Double,
|
|
|
+ UnderlineType.SingleAccounting => FontUnderlineType.SingleAccounting,
|
|
|
+ UnderlineType.DoubleAccounting => FontUnderlineType.DoubleAccounting,
|
|
|
+ _ => FontUnderlineType.None
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+ public Color Colour {
|
|
|
+ get
|
|
|
+ {
|
|
|
+ if(_font is XSSFFont xFont)
|
|
|
+ {
|
|
|
+ return CellStyle.ConvertColour(xFont.GetXSSFColor());
|
|
|
+ }
|
|
|
+ else if(_font is HSSFFont hFont && Spreadsheet.Workbook is HSSFWorkbook workbook)
|
|
|
+ {
|
|
|
+ return CellStyle.ConvertColour(hFont.GetHSSFColor(workbook));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return CellStyle.ColourFromIndex(_font.Color);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public double FontSize { get => _font.FontHeightInPoints; set => _font.FontHeightInPoints = value; }
|
|
|
+
|
|
|
+ public Font(NFont font, Spreadsheet spreadsheet)
|
|
|
+ {
|
|
|
+ _font = font;
|
|
|
+ Spreadsheet = spreadsheet;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
public class CellStyle : ICellStyle
|
|
|
{
|
|
|
internal NCellStyle _style { get; }
|
|
@@ -367,9 +504,68 @@ namespace InABox.Scripting
|
|
|
set => _style.DataFormat = value.FormatIndex;
|
|
|
}
|
|
|
|
|
|
- public CellStyle(NCellStyle style)
|
|
|
+ ISpreadsheet ICellStyle.Spreadsheet => Spreadsheet;
|
|
|
+
|
|
|
+ public Spreadsheet Spreadsheet { get; }
|
|
|
+
|
|
|
+ public Color Background => ConvertColour(_style.FillBackgroundColorColor);
|
|
|
+
|
|
|
+ public Color Foreground => ConvertColour(_style.FillForegroundColorColor);
|
|
|
+
|
|
|
+ public IFont Font => new Font(_style.GetFont(Spreadsheet.Workbook), Spreadsheet);
|
|
|
+
|
|
|
+ public CellStyle(NCellStyle style, Spreadsheet spreadsheet)
|
|
|
{
|
|
|
_style = style;
|
|
|
+ Spreadsheet = spreadsheet;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static Color ColourFromIndex(short index)
|
|
|
+ {
|
|
|
+ int indexNum = index;
|
|
|
+ var hashIndex = HSSFColor.GetIndexHash();
|
|
|
+ HSSFColor? indexed = null;
|
|
|
+ if (hashIndex.ContainsKey(indexNum))
|
|
|
+ indexed = hashIndex[indexNum];
|
|
|
+ if (indexed != null)
|
|
|
+ {
|
|
|
+ byte[] rgb = new byte[3];
|
|
|
+ rgb[0] = (byte)indexed.GetTriplet()[0];
|
|
|
+ rgb[1] = (byte)indexed.GetTriplet()[1];
|
|
|
+ rgb[2] = (byte)indexed.GetTriplet()[2];
|
|
|
+ return Color.FromArgb(255, rgb[0], rgb[1], rgb[2]);
|
|
|
+ }
|
|
|
+ return Color.Empty;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static Color ConvertColour(IColor? colour)
|
|
|
+ {
|
|
|
+ if(colour is null)
|
|
|
+ {
|
|
|
+ return Color.Empty;
|
|
|
+ }
|
|
|
+ if(colour is ExtendedColor extendedColour)
|
|
|
+ {
|
|
|
+ if (extendedColour.IsIndexed)
|
|
|
+ {
|
|
|
+ return ColourFromIndex(extendedColour.Index);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ var argb = extendedColour.ARGB;
|
|
|
+ return Color.FromArgb(argb[0], argb[1], argb[2], argb[3]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if(colour is HSSFColor hssfColour)
|
|
|
+ {
|
|
|
+ var rgb = hssfColour.RGB;
|
|
|
+ return Color.FromArgb(255, rgb[0], rgb[1], rgb[2]);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Logger.Send(LogType.Error, "", $"Unknown NPOI Colour class {colour.GetType()}");
|
|
|
+ return Color.Empty;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -378,7 +574,6 @@ namespace InABox.Scripting
|
|
|
|
|
|
public IWorkbook Workbook;
|
|
|
|
|
|
- private NCellStyle DateStyle;
|
|
|
private NDataFormat DataFormat;
|
|
|
|
|
|
private Spreadsheet(IWorkbook workbook)
|
|
@@ -395,18 +590,18 @@ namespace InABox.Scripting
|
|
|
|
|
|
public ISheet GetSheet(int index)
|
|
|
{
|
|
|
- return new Sheet(Workbook.GetSheetAt(index));
|
|
|
+ return new Sheet(Workbook.GetSheetAt(index), this);
|
|
|
}
|
|
|
|
|
|
public ISheet GetSheet(string name)
|
|
|
{
|
|
|
- return new Sheet(Workbook.GetSheet(name));
|
|
|
+ return new Sheet(Workbook.GetSheet(name), this);
|
|
|
}
|
|
|
|
|
|
public IEnumerator<ISheet> SheetEnumerator()
|
|
|
{
|
|
|
var enumerator = Workbook.GetEnumerator();
|
|
|
- return new SheetEnumerator(enumerator);
|
|
|
+ return new SheetEnumerator(enumerator, this);
|
|
|
}
|
|
|
|
|
|
public IEnumerable<ISheet> Sheets()
|
|
@@ -431,20 +626,20 @@ namespace InABox.Scripting
|
|
|
public ISheet NewSheet(string name)
|
|
|
{
|
|
|
var sheet = Workbook.CreateSheet(name);
|
|
|
- return new Sheet(sheet);
|
|
|
+ return new Sheet(sheet, this);
|
|
|
}
|
|
|
|
|
|
public ISheet NewSheet()
|
|
|
{
|
|
|
var sheet = Workbook.CreateSheet();
|
|
|
- return new Sheet(sheet);
|
|
|
+ return new Sheet(sheet, this);
|
|
|
}
|
|
|
|
|
|
public ICellStyle NewStyle()
|
|
|
{
|
|
|
var style = Workbook.CreateCellStyle();
|
|
|
var x = style.GetDataFormatString();
|
|
|
- return new CellStyle(style);
|
|
|
+ return new CellStyle(style, this);
|
|
|
}
|
|
|
|
|
|
public IDataFormat GetDataFormat(string format)
|