diff --git a/OpenXmlFormats/Spreadsheet/Styles/CT_Border.cs b/OpenXmlFormats/Spreadsheet/Styles/CT_Border.cs index 5967f3cff..c906b59bb 100644 --- a/OpenXmlFormats/Spreadsheet/Styles/CT_Border.cs +++ b/OpenXmlFormats/Spreadsheet/Styles/CT_Border.cs @@ -154,20 +154,20 @@ public bool IsSetDiagonal() { return this.diagonalField != null; } - public void unsetDiagonal() + public void UnsetDiagonal() { this.diagonalField = null; } - public void unsetRight() + public void UnsetRight() { this.rightField = null; } - public void unsetLeft() + public void UnsetLeft() { this.leftField = null; } - public void unsetTop() + public void UnsetTop() { this.topField = null; } @@ -230,6 +230,38 @@ public CT_BorderPr AddNewBottom() return this.bottomField; } + public bool IsSetVertical() + { + return verticalField != null; + } + + public CT_BorderPr AddNewVertical() + { + verticalField = new CT_BorderPr(); + return verticalField; + } + + public void UnsetVertical() + { + verticalField = null; + } + + public bool IsSetHorizontal() + { + return horizontalField != null; + } + + public CT_BorderPr AddNewHorizontal() + { + horizontalField = new CT_BorderPr(); + return horizontalField; + } + + public void UnsetHorizontal() + { + horizontalField = null; + } + [XmlElement(Namespace = "http://schemas.openxmlformats.org/spreadsheetml/2006/main")] public CT_BorderPr left { diff --git a/OpenXmlFormats/Spreadsheet/Styles/CT_BorderPr.cs b/OpenXmlFormats/Spreadsheet/Styles/CT_BorderPr.cs index 26336c1ab..1b691607d 100644 --- a/OpenXmlFormats/Spreadsheet/Styles/CT_BorderPr.cs +++ b/OpenXmlFormats/Spreadsheet/Styles/CT_BorderPr.cs @@ -17,11 +17,13 @@ public class CT_BorderPr private CT_Color colorField; private ST_BorderStyle styleField; + private bool styleFieldSpecified; public static CT_BorderPr Parse(XmlNode node, XmlNamespaceManager namespaceManager) { if (node == null) return null; CT_BorderPr ctObj = new CT_BorderPr(); + ctObj.styleFieldSpecified = node.Attributes["style"] != null; if (node.Attributes["style"] != null) ctObj.style = (ST_BorderStyle)Enum.Parse(typeof(ST_BorderStyle), node.Attributes["style"].Value); foreach (XmlNode childNode in node.ChildNodes) @@ -71,7 +73,7 @@ public void UnsetColor() } public bool IsSetStyle() { - return styleField != ST_BorderStyle.none; + return styleFieldSpecified; } [XmlElement] @@ -97,15 +99,29 @@ public ST_BorderStyle style } set { + this.styleFieldSpecified = value != ST_BorderStyle.none; this.styleField = value; } } + public bool styleSpecified + { + get + { + return this.styleFieldSpecified; + } + set + { + this.styleFieldSpecified = value; + } + } + public CT_BorderPr Copy() { var res = new CT_BorderPr(); res.colorField = this.colorField == null ? null : this.colorField.Copy(); res.style = this.style; + res.styleSpecified = this.styleSpecified; return res; } } diff --git a/OpenXmlFormats/Spreadsheet/Styles/CT_Colors.cs b/OpenXmlFormats/Spreadsheet/Styles/CT_Colors.cs index 071b591b3..08c625cd3 100644 --- a/OpenXmlFormats/Spreadsheet/Styles/CT_Colors.cs +++ b/OpenXmlFormats/Spreadsheet/Styles/CT_Colors.cs @@ -75,6 +75,11 @@ internal void Write(StreamWriter sw, string nodeName) sw.Write(string.Format("", nodeName)); } + public bool IsSetIndexedColors() + { + return this.indexedColors != null; + } + [XmlArray(Order = 0)] [XmlArrayItem("rgbColor", IsNullable = false)] public List indexedColors @@ -112,6 +117,8 @@ public static CT_RgbColor Parse(XmlNode node, XmlNamespaceManager namespaceManag if (node == null) return null; CT_RgbColor ctObj = new CT_RgbColor(); + if(node.Attributes["rgb"] != null) + ctObj.rgbHex = node.Attributes["rgb"].Value; ctObj.rgb = XmlHelper.ReadBytes(node.Attributes["rgb"]); return ctObj; } @@ -140,6 +147,12 @@ public byte[] rgb this.rgbField = value; } } + [XmlIgnore] + public string rgbHex + { + get; + set; + } } diff --git a/main/HSSF/UserModel/HSSFBorderFormatting.cs b/main/HSSF/UserModel/HSSFBorderFormatting.cs index 936265490..6a4e355c7 100644 --- a/main/HSSF/UserModel/HSSFBorderFormatting.cs +++ b/main/HSSF/UserModel/HSSFBorderFormatting.cs @@ -326,5 +326,80 @@ public bool IsForwardDiagonalOn } } + /// + /// HSSF doesn't support table borders, so always + /// + /// + public BorderStyle BorderVertical { get => BorderStyle.None; set { /*nothing, Not available for HSSF.*/ ; } } + + /// + /// HSSF doesn't support table borders, so always + /// + /// + public BorderStyle BorderHorizontal { get => BorderStyle.None; set { /*nothing, Not available for HSSF.*/ ; } } + + /// + /// HSSF Doesn't support table borders, so always + /// + /// + public short VerticalBorderColor + { + get + { + return HSSFColor.Automatic.Index; + } + set + { + //nothing, Not available for HSSF. + } + } + + /// + /// HSSF Doesn't support table borders, so always + /// + /// + public IColor VerticalBorderColorColor + { + get + { + return HSSFColor.Automatic.GetInstance(); + } + set + { + //nothing, Not available for HSSF. + } + } + + /// + /// HSSF Doesn't support table borders, so always + /// + /// + public short HorizontalBorderColor + { + get + { + return HSSFColor.Automatic.Index; + } + set + { + //nothing, Not available for HSSF. + } + } + + /// + /// HSSF Doesn't support table borders, so always + /// + /// + public IColor HorizontalBorderColorColor + { + get + { + return HSSFColor.Automatic.GetInstance(); + } + set + { + //nothing, Not available for HSSF. + } + } } } \ No newline at end of file diff --git a/main/HSSF/UserModel/HSSFExtendedColor.cs b/main/HSSF/UserModel/HSSFExtendedColor.cs index c079fb238..089f6fec6 100644 --- a/main/HSSF/UserModel/HSSFExtendedColor.cs +++ b/main/HSSF/UserModel/HSSFExtendedColor.cs @@ -18,6 +18,7 @@ limitations under the License. namespace NPOI.HSSF.UserModel { using System; + using NPOI.HSSF.Util; using NPOI.SS.UserModel; using RecordExtendedColor = NPOI.HSSF.Record.Common.ExtendedColor; @@ -177,6 +178,25 @@ public override double Tint color.Tint = (/*setter*/value); } } + + protected override byte[] IndexedRGB + { + get + { + if (IsIndexed && Index > 0) { + int indexNum = Index; + HSSFColor indexed = HSSFColor.GetIndexHash()[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 rgb; + } + } // else + return null; + } + } } } \ No newline at end of file diff --git a/main/SS/Formula/Eval/RefListEval.cs b/main/SS/Formula/Eval/RefListEval.cs index a9e2bfeab..3d5ccdf57 100644 --- a/main/SS/Formula/Eval/RefListEval.cs +++ b/main/SS/Formula/Eval/RefListEval.cs @@ -1,9 +1,28 @@ -using System; +/* ==================================================================== + 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; using System.Text; namespace NPOI.SS.Formula.Eval { + /// + /// Handling of a list of values, e.g. the 2nd argument in RANK(A1,(B1,B2,B3),1) + /// public class RefListEval:ValueEval { private List list = new List(); diff --git a/main/SS/Formula/Functions/Rank.cs b/main/SS/Formula/Functions/Rank.cs index bfdaf7e62..ace591377 100644 --- a/main/SS/Formula/Functions/Rank.cs +++ b/main/SS/Formula/Functions/Rank.cs @@ -42,13 +42,10 @@ public class Rank : Var2or3ArgFunction public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) { - - AreaEval aeRange; - double result; try { ValueEval ve = OperandResolver.GetSingleValue(arg0, srcRowIndex, srcColumnIndex); - result = OperandResolver.CoerceValueToDouble(ve); + double result = OperandResolver.CoerceValueToDouble(ve); if (Double.IsNaN(result) || Double.IsInfinity(result)) { throw new EvaluationException(ErrorEval.NUM_ERROR); @@ -57,7 +54,7 @@ public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEva { return eval(result, listEval, true); } - aeRange = ConvertRangeArg(arg1); + AreaEval aeRange = ConvertRangeArg(arg1); return eval(result, aeRange, true); } catch (EvaluationException e) @@ -68,12 +65,10 @@ public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEva public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1, ValueEval arg2) { - double result; - try { ValueEval ve = OperandResolver.GetSingleValue(arg0, srcRowIndex, srcColumnIndex); - result = OperandResolver.CoerceValueToDouble(ve); + double result = OperandResolver.CoerceValueToDouble(ve); if (Double.IsNaN(result) || Double.IsInfinity(result)) { throw new EvaluationException(ErrorEval.NUM_ERROR); @@ -128,22 +123,16 @@ private static NumberEval eval(double arg0, RefListEval aeRange, bool descending { int rank = 1; - List replaceList = new List(); - for (int i = 0; i < aeRange.GetList().Count; i++) + var list = aeRange.GetList(); + for (int i = 0; i < list.Count; i++) { - ValueEval ve = aeRange.GetList()[i]; - if (ve is RefEval) - { - { - replaceList.Add(i); - } - } - foreach (var index in replaceList) + ValueEval ve = list[i]; + if(ve is RefEval) { - ValueEval targetVe = aeRange.GetList()[i]; - aeRange.GetList()[index] = ((RefEval)targetVe).GetInnerValueEval(((RefEval)ve).FirstSheetIndex); + list[i] = ((RefEval)ve).GetInnerValueEval(((RefEval)ve).FirstSheetIndex); } Double value; + ve = list[i]; if (ve is NumberEval numberEval) { value = numberEval.NumberValue; diff --git a/main/SS/Formula/PTG/NamePtg.cs b/main/SS/Formula/PTG/NamePtg.cs index 9e3d9e56a..ddb7e1550 100644 --- a/main/SS/Formula/PTG/NamePtg.cs +++ b/main/SS/Formula/PTG/NamePtg.cs @@ -47,7 +47,7 @@ public NamePtg(int nameIndex) public NamePtg(ILittleEndianInput in1) { - field_1_label_index = in1.ReadShort(); + field_1_label_index = in1.ReadUShort(); field_2_zero = in1.ReadShort(); } diff --git a/main/SS/Formula/WorkbookEvaluator.cs b/main/SS/Formula/WorkbookEvaluator.cs index 03ceeece4..08a37f069 100644 --- a/main/SS/Formula/WorkbookEvaluator.cs +++ b/main/SS/Formula/WorkbookEvaluator.cs @@ -676,8 +676,6 @@ public ValueEval EvaluateFormula(OperationEvaluationContext ec, Ptg[] ptgs) ValueEval opResult; if (ptg is OperationPtg optg) { - if (optg is UnionPtg) { continue; } - int numops = optg.NumberOfOperands; ValueEval[] ops = new ValueEval[numops]; diff --git a/main/SS/UserModel/BorderFormatting.cs b/main/SS/UserModel/BorderFormatting.cs index 36bceb131..462b5b39a 100644 --- a/main/SS/UserModel/BorderFormatting.cs +++ b/main/SS/UserModel/BorderFormatting.cs @@ -35,6 +35,14 @@ public interface IBorderFormatting BorderStyle BorderTop { get; set; } + /// + /// Only valid for range borders, such as table styles + /// + BorderStyle BorderVertical { get; set; } + /// + /// Only valid for range borders, such as table styles + /// + BorderStyle BorderHorizontal { get; set; } short BottomBorderColor { get; set; } short DiagonalBorderColor { get; set; } @@ -53,5 +61,22 @@ public interface IBorderFormatting IColor RightBorderColorColor { get; set; } IColor TopBorderColorColor { get; set; } + /// + /// Range internal borders. Only relevant for range styles, such as table formatting + /// + short VerticalBorderColor { get; set; } + /// + /// Range internal borders. Only relevant for range styles, such as table formatting + /// + IColor VerticalBorderColorColor { get; set; } + + /// + /// Range internal borders. Only relevant for range styles, such as table formatting + /// + short HorizontalBorderColor { get; set; } + /// + /// Range internal borders. Only relevant for range styles, such as table formatting + /// + IColor HorizontalBorderColorColor { get; set; } } } \ No newline at end of file diff --git a/main/SS/UserModel/ExtendedColor.cs b/main/SS/UserModel/ExtendedColor.cs index 73d3b9e7e..c3c7252d5 100644 --- a/main/SS/UserModel/ExtendedColor.cs +++ b/main/SS/UserModel/ExtendedColor.cs @@ -91,17 +91,9 @@ protected byte[] GetRGBOrARGB() { if (IsIndexed && Index > 0) { - int indexNum = Index; - var hashIndex = HSSFColor.GetIndexHash(); - HSSFColor indexed = null; - if (hashIndex.TryGetValue(indexNum, out HSSFColor value)) - indexed = value; - if (indexed != null) + byte[] rgb = IndexedRGB; + if (rgb != 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 rgb; } } @@ -109,7 +101,10 @@ protected byte[] GetRGBOrARGB() // Grab the colour return StoredRGB; } - + /// + /// + /// index color RGB bytes, if == true, null if not indexed or index is invalid + protected abstract byte[] IndexedRGB { get; } /** * Standard Red Green Blue ctColor value (RGB) with applied tint. * Alpha values are ignored. diff --git a/main/SS/UserModel/IndexedColors.cs b/main/SS/UserModel/IndexedColors.cs index a5ff8cde0..ddcb72cf0 100644 --- a/main/SS/UserModel/IndexedColors.cs +++ b/main/SS/UserModel/IndexedColors.cs @@ -36,6 +36,14 @@ namespace NPOI.SS.UserModel */ public class IndexedColors { + public static readonly IndexedColors Black1; + public static readonly IndexedColors White1; + public static readonly IndexedColors Red1; + public static readonly IndexedColors BrightGreen1; + public static readonly IndexedColors Blue1; + public static readonly IndexedColors Yellow1; + public static readonly IndexedColors Pink1; + public static readonly IndexedColors Turquoise1; public static readonly IndexedColors Black; public static readonly IndexedColors White; public static readonly IndexedColors Red; @@ -55,6 +63,7 @@ public class IndexedColors public static readonly IndexedColors CornflowerBlue; public static readonly IndexedColors Maroon; public static readonly IndexedColors LemonChiffon; + public static readonly IndexedColors LightTurquoise1; public static readonly IndexedColors Orchid; public static readonly IndexedColors Coral; public static readonly IndexedColors RoyalBlue; @@ -98,6 +107,14 @@ public class IndexedColors static readonly Dictionary mappingIndex = null; static IndexedColors() { + Black1 = new IndexedColors(0, new HSSFColor.Black()); + White1 = new IndexedColors(1, new HSSFColor.White()); + Red1 = new IndexedColors(2, new HSSFColor.Red()); + BrightGreen1 = new IndexedColors(3, new HSSFColor.BrightGreen()); + Blue1 = new IndexedColors(4, new HSSFColor.Blue()); + Yellow1 = new IndexedColors(5, new HSSFColor.Yellow()); + Pink1 = new IndexedColors(6, new HSSFColor.Pink()); + Turquoise1 = new IndexedColors(7, new HSSFColor.Turquoise()); Black = new IndexedColors(8, new HSSFColor.Black()); White = new IndexedColors(9, new HSSFColor.White()); Red = new IndexedColors(10, new HSSFColor.Red()); @@ -117,6 +134,7 @@ static IndexedColors() CornflowerBlue = new IndexedColors(24, new HSSFColor.CornflowerBlue()); Maroon = new IndexedColors(25, new HSSFColor.Maroon()); LemonChiffon = new IndexedColors(26, new HSSFColor.LemonChiffon()); + LightTurquoise1 = new IndexedColors(27, new HSSFColor.LemonChiffon()); Orchid = new IndexedColors(28, new HSSFColor.Orchid()); Coral = new IndexedColors(29, new HSSFColor.Coral()); RoyalBlue = new IndexedColors(30, new HSSFColor.RoyalBlue()); @@ -149,6 +167,14 @@ static IndexedColors() mappingName = new Dictionary(); + mappingName.Add("black1", IndexedColors.Black); + mappingName.Add("white1", IndexedColors.White); + mappingName.Add("red1", IndexedColors.Red); + mappingName.Add("brightgreen1", IndexedColors.BrightGreen); + mappingName.Add("blue1", IndexedColors.Blue); + mappingName.Add("yellow1", IndexedColors.Yellow); + mappingName.Add("pink1", IndexedColors.Pink); + mappingName.Add("turquoise1", IndexedColors.Turquoise); mappingName.Add("black", IndexedColors.Black); mappingName.Add("white", IndexedColors.White); mappingName.Add("red", IndexedColors.Red); @@ -168,6 +194,7 @@ static IndexedColors() mappingName.Add("cornflowerblue", IndexedColors.CornflowerBlue); mappingName.Add("maroon", IndexedColors.Maroon); mappingName.Add("lemonchiffon", IndexedColors.LemonChiffon); + mappingName.Add("lightturquoise1", IndexedColors.LightTurquoise); mappingName.Add("orchid", IndexedColors.Orchid); mappingName.Add("coral", IndexedColors.Coral); mappingName.Add("royalblue", IndexedColors.RoyalBlue); @@ -200,6 +227,14 @@ static IndexedColors() mappingIndex = new Dictionary(); + mappingIndex.Add(0, IndexedColors.Black); + mappingIndex.Add(1, IndexedColors.White); + mappingIndex.Add(2, IndexedColors.Red); + mappingIndex.Add(3, IndexedColors.BrightGreen); + mappingIndex.Add(4, IndexedColors.Blue); + mappingIndex.Add(5, IndexedColors.Yellow); + mappingIndex.Add(6, IndexedColors.Pink); + mappingIndex.Add(7, IndexedColors.Turquoise); mappingIndex.Add(8, IndexedColors.Black); mappingIndex.Add(9, IndexedColors.White); mappingIndex.Add(10, IndexedColors.Red); @@ -219,6 +254,7 @@ static IndexedColors() mappingIndex.Add(24, IndexedColors.CornflowerBlue); mappingIndex.Add(25, IndexedColors.Maroon); mappingIndex.Add(26, IndexedColors.LemonChiffon); + mappingIndex.Add(27, IndexedColors.LightTurquoise); mappingIndex.Add(28, IndexedColors.Orchid); mappingIndex.Add(29, IndexedColors.Coral); mappingIndex.Add(30, IndexedColors.RoyalBlue); diff --git a/main/SS/UserModel/Table.cs b/main/SS/UserModel/Table.cs index aa1a12ceb..11d7f58db 100644 --- a/main/SS/UserModel/Table.cs +++ b/main/SS/UserModel/Table.cs @@ -38,54 +38,89 @@ public static class Table */ public interface ITable { - /** - * Get the top-left column index relative to the sheet - * @return table start column index on sheet - */ + /// + /// Get the top-left column index relative to the sheet + /// int StartColIndex { get; } - /** - * Get the top-left row index on the sheet - * @return table start row index on sheet - */ + /// + /// Get the top-left row index on the sheet + /// int StartRowIndex { get; } - /** - * Get the bottom-right column index on the sheet - * @return table end column index on sheet - */ + /// + /// Get the bottom-right column index on the sheet + /// int EndColIndex { get; } - /** - * Get the bottom-right row index - * @return table end row index on sheet - */ + /// + /// Get the bottom-right row index + /// int EndRowIndex { get; } - /** - * Get the name of the table. - * @return table name - */ + /// + /// Get the name of the table. + /// String Name { get; } - - /** - * Returns the index of a given named column in the table (names are case insensitive in XSSF). - * Note this list is lazily loaded and cached for performance. - * Changes to the underlying table structure are not reflected in later calls - * unless XSSFTable.UpdateHeaders() is called to reset the cache. - * @param columnHeader the column header name to Get the table column index of - * @return column index corresponding to columnHeader - */ + /// + /// Get the name of the table style, if there is one. + /// May be a built-in name or user-defined. + /// + string StyleName { get; } + /// + /// Returns the index of a given named column in the table (names are case insensitive in XSSF). + /// Note this list is lazily loaded and cached for performance. + /// Changes to the underlying table structure are not reflected in later calls + /// unless XSSFTable.updateHeaders() is called to reset the cache. + /// + /// the column header name to Get the table column index of + /// column index corresponding to columnHeader int FindColumnIndex(String columnHeader); - /** - * Returns the sheet name that the table belongs to. - */ + /// + /// Returns the sheet name that the table belongs to. + /// String SheetName { get; } - /** - * Returns true iff the table has a 'Totals' row - */ + /// + /// Note: This is misleading. The OOXML spec indicates this is true if the totals row + /// has ever been shown, not whether or not it is currently displayed. + /// Use > 0 to decide whether or not the totals row is visible. + /// + /// true if a totals row has ever been shown for this table + /// @see #getTotalsRowCount() + /// + /// @since 3.15 beta 2 + /// bool IsHasTotalsRow { get; } + /// + /// + /// 0 for no totals rows, 1 for totals row shown. + /// Values > 1 are not currently used by Excel up through 2016, and the OOXML spec + /// doesn't define how they would be implemented. + /// + /// + /// @since 3.17 beta 1 + /// + int TotalsRowCount { get; } + + /// + /// + /// 0 for no header rows, 1 for table headers shown. + /// Values > 1 might be used by Excel for pivot tables? + /// + /// + /// @since 3.17 beta 1 + /// + int HeaderRowCount { get; } /// /// TableStyleInfo for this instance /// ITableStyleInfo Style { get; } + /// + /// checks if the given cell is part of the table. Includes checking that they are on the same sheet. + /// + /// + /// true if the table and cell are on the same sheet and the cell is within the table range. + /// + /// @since 3.17 beta 1 + /// + bool Contains(ICell cell); } } \ No newline at end of file diff --git a/main/SS/UserModel/TableStyleType.cs b/main/SS/UserModel/TableStyleType.cs index 148206852..b980f585f 100644 --- a/main/SS/UserModel/TableStyleType.cs +++ b/main/SS/UserModel/TableStyleType.cs @@ -15,6 +15,9 @@ the License. You may obtain a copy of the License at limitations under the License. ==================================================================== */ +using NPOI.SS.Util; +using System; + namespace NPOI.SS.UserModel { /// @@ -81,4 +84,188 @@ public enum TableStyleType /***/ thirdRowSubheading } + + public static class TableStyleTypeExtension + { + public static CellRangeAddressBase GetRange(this TableStyleType styleType, ITable table, ICell cell) + { + switch(styleType) + { + case TableStyleType.wholeTable: + return new CellRangeAddress(table.StartRowIndex, table.EndRowIndex, table.StartColIndex, table.EndColIndex); + case TableStyleType.firstColumnStripe: + return GetFirstColumnStripeRange(table, cell); + case TableStyleType.secondColumnStripe: + return GetSecondColumnStripeRange(table, cell); + case TableStyleType.firstRowStripe: + return GetFirstRowStripeRange(table, cell); + case TableStyleType.secondRowStripe: + return GetSecondRowStripeRange(table, cell); + case TableStyleType.lastColumn: + if (! table.Style.IsShowLastColumn) return null; + return new CellRangeAddress(table.StartRowIndex, table.EndRowIndex, table.EndColIndex, table.EndColIndex); + case TableStyleType.firstColumn: + if (! table.Style.IsShowFirstColumn) return null; + return new CellRangeAddress(table.StartRowIndex, table.EndRowIndex, table.StartColIndex, table.StartColIndex); + case TableStyleType.headerRow: + if (table.HeaderRowCount < 1) return null; + return new CellRangeAddress(table.StartRowIndex, table.StartRowIndex + table.HeaderRowCount -1, table.StartColIndex, table.EndColIndex); + case TableStyleType.totalRow: + if (table.TotalsRowCount < 1) return null; + return new CellRangeAddress(table.EndRowIndex - table.TotalsRowCount +1, table.EndRowIndex, table.StartColIndex, table.EndColIndex); + case TableStyleType.firstHeaderCell: + if (table.HeaderRowCount < 1) return null; + return new CellRangeAddress(table.StartRowIndex, table.StartRowIndex, table.StartColIndex, table.StartColIndex); + case TableStyleType.lastHeaderCell: + if (table.HeaderRowCount < 1) return null; + return new CellRangeAddress(table.StartRowIndex, table.StartRowIndex, table.EndColIndex, table.EndColIndex); + case TableStyleType.firstTotalCell: + if (table.TotalsRowCount < 1) return null; + return new CellRangeAddress(table.EndRowIndex - table.TotalsRowCount +1, table.EndRowIndex, table.StartColIndex, table.StartColIndex); + case TableStyleType.lastTotalCell: + if (table.TotalsRowCount < 1) return null; + return new CellRangeAddress(table.EndRowIndex - table.TotalsRowCount +1, table.EndRowIndex, table.EndColIndex, table.EndColIndex); + default: + return null; + } + } + + private static CellRangeAddress GetFirstColumnStripeRange(ITable table, ICell cell) + { + ITableStyleInfo info = table.Style; + if (! info.IsShowColumnStripes) return null; + IDifferentialStyleProvider c1Style = info.Style.GetStyle(TableStyleType.firstColumnStripe); + IDifferentialStyleProvider c2Style = info.Style.GetStyle(TableStyleType.secondColumnStripe); + int c1Stripe = c1Style == null ? 1 : Math.Max(1, c1Style.StripeSize); + int c2Stripe = c2Style == null ? 1 : Math.Max(1, c2Style.StripeSize); + + int firstStart = table.StartColIndex; + int secondStart = firstStart + c1Stripe; + int c = cell.ColumnIndex; + + // look for the stripe containing c, accounting for the style element stripe size + // could do fancy math, but tables can't be that wide, a simple loop is fine + // if not in this type of stripe, return null + while (true) { + if (firstStart > c) break; + if (c >= firstStart && c <= secondStart -1) return new CellRangeAddress(table.StartRowIndex, table.EndRowIndex, firstStart, secondStart - 1); + firstStart = secondStart + c2Stripe; + secondStart = firstStart + c1Stripe; + } + return null; + } + + private static CellRangeAddress GetSecondColumnStripeRange(ITable table, ICell cell) + { + ITableStyleInfo info = table.Style; + if (! info.IsShowColumnStripes) return null; + + IDifferentialStyleProvider c1Style = info.Style.GetStyle(TableStyleType.firstColumnStripe); + IDifferentialStyleProvider c2Style = info.Style.GetStyle(TableStyleType.secondColumnStripe); + int c1Stripe = c1Style == null ? 1 : Math.Max(1, c1Style.StripeSize); + int c2Stripe = c2Style == null ? 1 : Math.Max(1, c2Style.StripeSize); + + int firstStart = table.StartColIndex; + int secondStart = firstStart + c1Stripe; + int c = cell.ColumnIndex; + + // look for the stripe containing c, accounting for the style element stripe size + // could do fancy math, but tables can't be that wide, a simple loop is fine + // if not in this type of stripe, return null + while (true) { + if (firstStart > c) break; + if (c >= secondStart && c <= secondStart + c2Stripe -1) return new CellRangeAddress(table.StartRowIndex, table.EndRowIndex, secondStart, secondStart + c2Stripe - 1); + firstStart = secondStart + c2Stripe; + secondStart = firstStart + c1Stripe; + } + return null; + } + + private static CellRangeAddress GetFirstRowStripeRange(ITable table, ICell cell) + { + ITableStyleInfo info = table.Style; + if (! info.IsShowRowStripes) return null; + + IDifferentialStyleProvider c1Style = info.Style.GetStyle(TableStyleType.firstRowStripe); + IDifferentialStyleProvider c2Style = info.Style.GetStyle(TableStyleType.secondRowStripe); + int c1Stripe = c1Style == null ? 1 : Math.Max(1, c1Style.StripeSize); + int c2Stripe = c2Style == null ? 1 : Math.Max(1, c2Style.StripeSize); + + int firstStart = table.StartRowIndex + table.HeaderRowCount; + int secondStart = firstStart + c1Stripe; + int c = cell.RowIndex; + + // look for the stripe containing c, accounting for the style element stripe size + // could do fancy math, but tables can't be that wide, a simple loop is fine + // if not in this type of stripe, return null + while (true) { + if (firstStart > c) break; + if (c >= firstStart && c <= secondStart -1) + return new CellRangeAddress(firstStart, secondStart - 1, table.StartColIndex, table.EndColIndex); + firstStart = secondStart + c2Stripe; + secondStart = firstStart + c1Stripe; + } + return null; + } + + private static CellRangeAddress GetSecondRowStripeRange(ITable table, ICell cell) + { + ITableStyleInfo info = table.Style; + if(!info.IsShowRowStripes) + return null; + + IDifferentialStyleProvider c1Style = info.Style.GetStyle(TableStyleType.firstRowStripe); + IDifferentialStyleProvider c2Style = info.Style.GetStyle(TableStyleType.secondRowStripe); + int c1Stripe = c1Style == null ? 1 : Math.Max(1, c1Style.StripeSize); + int c2Stripe = c2Style == null ? 1 : Math.Max(1, c2Style.StripeSize); + + int firstStart = table.StartRowIndex + table.HeaderRowCount; + int secondStart = firstStart + c1Stripe; + int c = cell.RowIndex; + + // look for the stripe containing c, accounting for the style element stripe size + // could do fancy math, but tables can't be that wide, a simple loop is fine + // if not in this type of stripe, return null + while(true) + { + if(firstStart > c) + break; + if(c >= secondStart && c <= secondStart +c2Stripe -1) + return new CellRangeAddress(secondStart, secondStart + c2Stripe - 1, table.StartColIndex, table.EndColIndex); + firstStart = secondStart + c2Stripe; + secondStart = firstStart + c1Stripe; + } + return null; + } + + /// + /// A range is returned only for the part of the table matching this enum instance and containing the given cell. + /// Null is returned for all other cases, such as: + /// + /// Cell on a different sheet than the table + /// Cell outside the table + /// this Enum part is not included in the table (i.e. no header/totals row) + /// this Enum is for a table part not yet implemented in POI, such as pivot table elements + /// + /// The returned range can be used to determine how style options may or may not apply to this cell. + /// For example, borders only apply to the outer boundary of a table, while the + /// rest of the styling, such as font and color, could apply to all the interior cells as well. + /// + /// table to evaluate + /// to evaluate + /// range in the table representing this class of cells, if it contains the given cell, or null if not applicable. + /// Stripe style types return only the stripe range containing the given cell, or null. + /// + public static CellRangeAddressBase AppliesTo(this TableStyleType styleType, ITable table, ICell cell) + { + if (table == null || cell == null) return null; + if ( ! cell.Sheet.SheetName.Equals(table.SheetName)) return null; + if ( ! table.Contains(cell)) return null; + + CellRangeAddressBase range = styleType.GetRange(table, cell); + if (range != null && range.IsInRange(cell.RowIndex, cell.ColumnIndex)) return range; + // else + return null; + } + } } diff --git a/main/SS/Util/CellRangeAddressBase.cs b/main/SS/Util/CellRangeAddressBase.cs index f0baafded..bde525e23 100644 --- a/main/SS/Util/CellRangeAddressBase.cs +++ b/main/SS/Util/CellRangeAddressBase.cs @@ -1,6 +1,8 @@ namespace NPOI.SS.Util { + using EnumsNET; using System; + using System.Collections.Generic; /** * See OOO documentation: excelfileformat.pdf sec 2.5.14 - 'Cell Range Address'

@@ -76,8 +78,10 @@ public void Validate(SpreadsheetVersion ssVersion) private static void ValidateRow(int row, SpreadsheetVersion ssVersion) { int maxrow = ssVersion.LastRowIndex; - if (row > maxrow) throw new ArgumentException("Maximum row number is " + maxrow); - if (row < 0) throw new ArgumentException("Minumum row number is 0"); + if(row > maxrow) + throw new ArgumentException("Maximum row number is " + maxrow); + if(row < 0) + throw new ArgumentException("Minumum row number is 0"); } /** @@ -87,8 +91,10 @@ private static void ValidateRow(int row, SpreadsheetVersion ssVersion) private static void ValidateColumn(int column, SpreadsheetVersion ssVersion) { int maxcol = ssVersion.LastColumnIndex; - if (column > maxcol) throw new ArgumentException("Maximum column number is " + maxcol); - if (column < 0) throw new ArgumentException("Minimum column number is 0"); + if(column > maxcol) + throw new ArgumentException("Maximum column number is " + maxcol); + if(column < 0) + throw new ArgumentException("Minimum column number is 0"); } public bool IsInRange(int rowInd, int colInd) { @@ -151,6 +157,31 @@ public bool Intersects(CellRangeAddressBase other) other._firstCol <= this._lastCol; } + ///

+ /// Useful for logic like table/range styling, where some elements apply based on relative position in a range. + /// + /// + /// + /// set of s occupied by the given coordinates. Empty if the coordinates are not in the range, never null. + /// + /// @since 3.17 beta 1 + /// + public ISet GetPosition(int rowInd, int colInd) + { + HashSet positions = new HashSet(); + if (rowInd > FirstRow && rowInd < LastRow && colInd > FirstColumn && colInd < LastColumn) { + positions.Add(CellPosition.INSIDE); + return positions; // entirely inside, matches no boundaries + } + // check edges + if (rowInd == FirstRow) positions.Add(CellPosition.TOP); + if (rowInd == LastRow) positions.Add(CellPosition.BOTTOM); + if (colInd == FirstColumn) positions.Add(CellPosition.LEFT); + if (colInd == LastColumn) positions.Add(CellPosition.RIGHT); + + return positions; + } + /** * @return column number for the upper left hand corner */ @@ -250,7 +281,8 @@ public int MaxColumn public override bool Equals(Object other) { - if (other is CellRangeAddressBase @base) { + if(other is CellRangeAddressBase @base) + { return ((MinRow == @base.MinRow) && (MaxRow == @base.MaxRow) && (MinColumn == @base.MinColumn) && @@ -268,4 +300,32 @@ public override int GetHashCode() return code; } } + + /// + /// Indicates a cell or range is in the given relative position in a range. + /// More than one of these may apply at once. + /// + public enum CellPosition + { + /// + /// range starting rows are equal */ + /// + TOP, + /// + /// range ending rows are equal */ + /// + BOTTOM, + /// + /// range starting columns are equal */ + /// + LEFT, + /// + /// range ending columns are equal */ + /// + RIGHT, + /// + /// a cell or range is completely inside another range, without touching any edges (a cell in this position can't be in any others) */ + /// + INSIDE + } } diff --git a/ooxml/XSSF/Model/StylesTable.cs b/ooxml/XSSF/Model/StylesTable.cs index 340bd80a1..1d632efab 100644 --- a/ooxml/XSSF/Model/StylesTable.cs +++ b/ooxml/XSSF/Model/StylesTable.cs @@ -49,7 +49,7 @@ public class StylesTable : POIXMLDocumentPart private readonly List dxfs = new List(); private readonly Dictionary tableStyles = new Dictionary(); - private readonly IIndexedColorMap indexedColors = new DefaultIndexedColorMap(); + private IIndexedColorMap indexedColors = new DefaultIndexedColorMap(); /** * The first style id available for use as a custom style */ @@ -139,6 +139,7 @@ public void SetTheme(ThemesTable theme) { this.theme = theme; + if (theme != null) theme.SetColorMap(indexedColors); // Pass the themes table along to things which need to // know about it, but have already been Created by now foreach (XSSFFont font in fonts) @@ -181,6 +182,14 @@ public ITableStyle GetExplicitTableStyle(String name) { return tableStyles[name]; } + + public ISet ExplicitTableStyleNames + { + get + { + return new HashSet(tableStyles.Keys); + } + } /** * If there isn't currently a {@link ThemesTable} for the * current Workbook, then creates one and sets it up. @@ -190,7 +199,7 @@ public void EnsureThemesTable() { if (theme != null) return; - theme = (ThemesTable)workbook.CreateRelationship(XSSFRelation.THEME, XSSFFactory.GetInstance()); + SetTheme((ThemesTable)workbook.CreateRelationship(XSSFRelation.THEME, XSSFFactory.GetInstance())); } /** * Read this shared styles table from an XML file. @@ -208,6 +217,9 @@ internal void ReadFrom(XmlDocument xmldoc) CT_Stylesheet styleSheet = doc.GetStyleSheet(); // Grab all the different bits we care about + // keep this first, as some constructors below want it + IIndexedColorMap customColors = CustomIndexedColorMap.FromColors(styleSheet.colors); + if (customColors != null) indexedColors = customColors; CT_NumFmts ctfmts = styleSheet.numFmts; if (ctfmts != null) { @@ -226,7 +238,7 @@ internal void ReadFrom(XmlDocument xmldoc) foreach (CT_Font font in ctfonts.font) { // Create the font and save it. Themes Table supplied later - XSSFFont f = new XSSFFont(font, idx); + XSSFFont f = new XSSFFont(font, idx, indexedColors); fonts.Add(f); idx++; } @@ -236,7 +248,7 @@ internal void ReadFrom(XmlDocument xmldoc) { foreach (CT_Fill fill in ctFills.fill) { - fills.Add(new XSSFCellFill(fill)); + fills.Add(new XSSFCellFill(fill, indexedColors)); } } @@ -245,7 +257,7 @@ internal void ReadFrom(XmlDocument xmldoc) { foreach (CT_Border border in ctborders.border) { - borders.Add(new XSSFCellBorder(border)); + borders.Add(new XSSFCellBorder(border, indexedColors)); } } @@ -817,8 +829,8 @@ private void Initialize() fonts.Add(xssfFont); CT_Fill[] ctFill = CreateDefaultFills(); - fills.Add(new XSSFCellFill(ctFill[0])); - fills.Add(new XSSFCellFill(ctFill[1])); + fills.Add(new XSSFCellFill(ctFill[0], indexedColors)); + fills.Add(new XSSFCellFill(ctFill[1], indexedColors)); CT_Border ctBorder = CreateDefaultBorder(); borders.Add(new XSSFCellBorder(ctBorder)); @@ -862,7 +874,7 @@ private static CT_Fill[] CreateDefaultFills() private static XSSFFont CreateDefaultFont() { CT_Font ctFont = new CT_Font(); - XSSFFont xssfFont = new XSSFFont(ctFont, 0); + XSSFFont xssfFont = new XSSFFont(ctFont, 0, null); xssfFont.FontHeightInPoints = (XSSFFont.DEFAULT_FONT_SIZE); xssfFont.Color = (XSSFFont.DEFAULT_FONT_COLOR);//SetTheme xssfFont.FontName = (XSSFFont.DEFAULT_FONT_NAME); @@ -957,9 +969,15 @@ public XSSFFont FindFont(bool bold, short color, short fontHeight, String name, return null; } - public IIndexedColorMap GetIndexedColors() + /// + /// default or custom indexed color to RGB mapping + /// + public IIndexedColorMap IndexedColors { - return indexedColors; + get + { + return indexedColors; + } } } } diff --git a/ooxml/XSSF/Model/ThemesTable.cs b/ooxml/XSSF/Model/ThemesTable.cs index 6ad184b73..83c4595f9 100644 --- a/ooxml/XSSF/Model/ThemesTable.cs +++ b/ooxml/XSSF/Model/ThemesTable.cs @@ -25,6 +25,7 @@ namespace NPOI.XSSF.Model using System; using System.Collections.Generic; using System.IO; + using NPOI.OOXML.XSSF.UserModel; /** * Class that represents theme of XLSX document. The theme includes specific @@ -45,6 +46,7 @@ public class ThemesTable : POIXMLDocumentPart public const int THEME_HLINK = 10; public const int THEME_FOLHLINK = 11; + private IIndexedColorMap colorMap; private ThemeDocument theme; /** * Create a new, empty ThemesTable @@ -90,6 +92,15 @@ internal ThemesTable(ThemeDocument theme) { this.theme = theme; } + + /// + /// called from when setting theme, used to adjust colors if a custom indexed mapping is defined + /// + /// + internal void SetColorMap(IIndexedColorMap colorMap) + { + this.colorMap = colorMap; + } /** * Convert a theme "index" into a color. * @param idx A theme "index" @@ -135,7 +146,7 @@ public XSSFColor GetThemeColor(int idx) { return null; } - return new XSSFColor(rgb); + return new XSSFColor(rgb, colorMap); } @@ -172,7 +183,7 @@ public void InheritFromThemeAsRequired(XSSFColor color) * @param out The stream to write to. * @throws IOException if an error occurs while writing. */ - public void writeTo(Stream out1) + public void WriteTo(Stream out1) { //XmlOptions options = new XmlOptions(DEFAULT_XML_OPTIONS); @@ -183,7 +194,7 @@ protected internal override void Commit() { PackagePart part = GetPackagePart(); Stream out1 = part.GetOutputStream(); - writeTo(out1); + WriteTo(out1); out1.Close(); } } diff --git a/ooxml/XSSF/UserModel/CustomIndexedColorMap.cs b/ooxml/XSSF/UserModel/CustomIndexedColorMap.cs new file mode 100644 index 000000000..1bab313e7 --- /dev/null +++ b/ooxml/XSSF/UserModel/CustomIndexedColorMap.cs @@ -0,0 +1,84 @@ +/* ==================================================================== + 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; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace NPOI.OOXML.XSSF.UserModel +{ + using NPOI.OpenXmlFormats.Spreadsheet; + + /// + /// custom index color map, i.e. from the styles.xml definition + /// + public class CustomIndexedColorMap : IIndexedColorMap + { + + private byte[][] colorIndex; + + /// + /// + /// array of RGB triplets indexed by color index + private CustomIndexedColorMap(byte[][] colors) + { + this.colorIndex = colors; + } + + public byte[] GetRGB(int index) + { + if(colorIndex == null || index < 0 || index >= colorIndex.Length) + return null; + return colorIndex[index]; + } + + /// + /// + /// OOXML spec says if this exists it must have all indexes. + /// + /// + /// From the OOXML Spec, Part 1, section 18.8.27: + /// + /// + /// + /// This element contains a sequence of RGB color values that correspond to color indexes (zero-based). When + /// using the default indexed color palette, the values are not written out, but instead are implied. When the color + /// palette has been modified from default, then the entire color palette is written out. + /// + /// + /// + /// CTColors from styles.xml possibly defining a custom color indexing scheme + /// custom indexed color map or null if none defined in the document + public static CustomIndexedColorMap FromColors(CT_Colors colors) + { + if(colors == null || !colors.IsSetIndexedColors()) + return null; + + List rgbColorList = colors.indexedColors; + byte[][] customColorIndex = new byte[rgbColorList.Count][]; + for(int i = 0; i < rgbColorList.Count; i++) + { + customColorIndex[i] = rgbColorList[i].rgb; + } + return new CustomIndexedColorMap(customColorIndex); + } + } +} + + diff --git a/ooxml/XSSF/UserModel/DefaultIndexedColorMap.cs b/ooxml/XSSF/UserModel/DefaultIndexedColorMap.cs index 6fca78557..d7be5fd5e 100644 --- a/ooxml/XSSF/UserModel/DefaultIndexedColorMap.cs +++ b/ooxml/XSSF/UserModel/DefaultIndexedColorMap.cs @@ -1,19 +1,46 @@ -using NPOI.HSSF.Util; +/* ==================================================================== + 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.HSSF.Util; using System; using System.Collections.Generic; using System.Text; namespace NPOI.OOXML.XSSF.UserModel { + /// + /// Uses the legacy colors defined in HSSF for index lookups + /// public class DefaultIndexedColorMap:IIndexedColorMap { public byte[] GetRGB(int index) { return GetDefaultRGB(index); } + /// + /// RGB bytes from HSSF default color by index + /// + /// + /// RGB bytes from HSSF default color by index public static byte[] GetDefaultRGB(int index) { - HSSFColor hssfColor = HSSFColor.GetIndexHash()[index]; + var colorDict = HSSFColor.GetIndexHash(); + colorDict.TryGetValue(index, out HSSFColor hssfColor); + //HSSFColor hssfColor = HSSFColor.GetIndexHash()[index]; if (hssfColor == null) return null; byte[] rgbShort = hssfColor.GetTriplet(); return rgbShort; diff --git a/ooxml/XSSF/UserModel/Extensions/XSSFCellBorder.cs b/ooxml/XSSF/UserModel/Extensions/XSSFCellBorder.cs index 199fc9b95..37a91b9e5 100644 --- a/ooxml/XSSF/UserModel/Extensions/XSSFCellBorder.cs +++ b/ooxml/XSSF/UserModel/Extensions/XSSFCellBorder.cs @@ -23,9 +23,11 @@ namespace NPOI.XSSF.UserModel.Extensions using NPOI.XSSF.UserModel; using NPOI.XSSF.Model; using NPOI.SS.UserModel; + using NPOI.OOXML.XSSF.UserModel; + /** - * The enumeration value indicating the side being used for a cell border. - */ +* The enumeration value indicating the side being used for a cell border. +*/ public enum BorderSide { TOP, RIGHT, BOTTOM, LEFT, DIAGONAL @@ -38,36 +40,43 @@ public enum BorderSide */ public class XSSFCellBorder { + private IIndexedColorMap _indexedColorMap; private ThemesTable _theme; private CT_Border border; /** * Creates a Cell Border from the supplied XML defInition */ - public XSSFCellBorder(CT_Border border, ThemesTable theme) - : this(border) + public XSSFCellBorder(CT_Border border, ThemesTable theme, IIndexedColorMap colorMap) + : this(border, colorMap) { this._theme = theme; } - /** - * Creates a Cell Border from the supplied XML defInition - */ - public XSSFCellBorder(CT_Border border) + public XSSFCellBorder(CT_Border border, IIndexedColorMap colorMap) { this.border = border; + this._indexedColorMap = colorMap; } - /** - * Creates a new, empty Cell Border. - * You need to attach this to the Styles Table - */ - public XSSFCellBorder() + /// + /// Creates a Cell Border from the supplied XML definition + /// + /// + public XSSFCellBorder(CT_Border border) + : this(border, null) { - border = new CT_Border(); } + /// + /// Creates a new, empty Cell Border. + /// You need to attach this to the Styles Table + /// + public XSSFCellBorder() + { + this.border = new CT_Border(); + } /** * Records the Themes Table that is associated with * the current font, used when looking up theme @@ -128,7 +137,7 @@ public XSSFColor GetBorderColor(BorderSide side) if (borderPr != null && borderPr.IsSetColor()) { - XSSFColor clr = new XSSFColor(borderPr.color); + XSSFColor clr = new XSSFColor(borderPr.color, _indexedColorMap); if (_theme != null) { _theme.InheritFromThemeAsRequired(clr); diff --git a/ooxml/XSSF/UserModel/Extensions/XSSFCellFill.cs b/ooxml/XSSF/UserModel/Extensions/XSSFCellFill.cs index 36656731f..15418533b 100644 --- a/ooxml/XSSF/UserModel/Extensions/XSSFCellFill.cs +++ b/ooxml/XSSF/UserModel/Extensions/XSSFCellFill.cs @@ -16,6 +16,7 @@ limitations under the License. ==================================================================== */ using NPOI.OpenXmlFormats.Spreadsheet; using NPOI.OpenXmlFormats; +using NPOI.OOXML.XSSF.UserModel; namespace NPOI.XSSF.UserModel.Extensions { @@ -25,7 +26,7 @@ namespace NPOI.XSSF.UserModel.Extensions */ public class XSSFCellFill { - + private IIndexedColorMap _indexedColorMap; private readonly CT_Fill _fill; /** @@ -33,9 +34,10 @@ public class XSSFCellFill * * @param fill - fill */ - public XSSFCellFill(CT_Fill fill) + public XSSFCellFill(CT_Fill fill, IIndexedColorMap colorMap) { _fill = fill; + _indexedColorMap = colorMap; } /** @@ -57,7 +59,7 @@ public XSSFColor GetFillBackgroundColor() if (ptrn == null) return null; CT_Color CT_Color = ptrn.bgColor; - return CT_Color == null ? null : new XSSFColor(CT_Color); + return CT_Color == null ? null : new XSSFColor(CT_Color, _indexedColorMap); } /** @@ -96,7 +98,7 @@ public XSSFColor GetFillForegroundColor() if (ptrn == null) return null; CT_Color ctColor = ptrn.fgColor; - return ctColor == null ? null : new XSSFColor(ctColor); + return ctColor == null ? null : new XSSFColor(ctColor, _indexedColorMap); } /** diff --git a/ooxml/XSSF/UserModel/XSSFBorderFormatting.cs b/ooxml/XSSF/UserModel/XSSFBorderFormatting.cs index b74956dbc..481a33b74 100644 --- a/ooxml/XSSF/UserModel/XSSFBorderFormatting.cs +++ b/ooxml/XSSF/UserModel/XSSFBorderFormatting.cs @@ -16,20 +16,23 @@ limitations under the License. ==================================================================== */ using NPOI.SS.UserModel; using NPOI.OpenXmlFormats.Spreadsheet; +using NPOI.OOXML.XSSF.UserModel; + namespace NPOI.XSSF.UserModel { - -/** - * @author Yegor Kozlov - */ + /** + * @author Yegor Kozlov + */ public class XSSFBorderFormatting : IBorderFormatting { + IIndexedColorMap _colorMap; readonly CT_Border _border; /*package*/ - internal XSSFBorderFormatting(CT_Border border) + internal XSSFBorderFormatting(CT_Border border, IIndexedColorMap colorMap) { _border = border; + _colorMap = colorMap; } #region IBorderFormatting Members @@ -38,14 +41,7 @@ public BorderStyle BorderBottom { get { - if (!_border.IsSetBottom()) - { - return BorderStyle.None; - } - else - { - return (BorderStyle)_border.bottom.style; - } + return GetBorderStyle(_border.bottom); } set { @@ -59,19 +55,12 @@ public BorderStyle BorderDiagonal { get { - if (!_border.IsSetDiagonal()) - { - return BorderStyle.None; - } - else - { - return (BorderStyle)_border.diagonal.style; - } + return GetBorderStyle(_border.diagonal); } set { CT_BorderPr pr = _border.IsSetDiagonal() ? _border.diagonal : _border.AddNewDiagonal(); - if (value == (short)BorderStyle.None) _border.unsetDiagonal(); + if (value == (short)BorderStyle.None) _border.UnsetDiagonal(); else pr.style = (ST_BorderStyle)value; } } @@ -80,20 +69,13 @@ public BorderStyle BorderLeft { get { - if (!_border.IsSetLeft()) - { - return BorderStyle.None; - } - else - { - return (BorderStyle)_border.left.style; - } + return GetBorderStyle(_border.left); } set { CT_BorderPr pr = _border.IsSetLeft() ? _border.left : _border.AddNewLeft(); - if (value == (short)BorderStyle.None) _border.unsetLeft(); - else pr.style = (ST_BorderStyle)(value); + if (value == (short)BorderStyle.None) _border.UnsetLeft(); + else pr.style = (ST_BorderStyle)value; } } @@ -101,20 +83,13 @@ public BorderStyle BorderRight { get { - if (!_border.IsSetRight()) - { - return BorderStyle.None; - } - else - { - return (BorderStyle)_border.right.style; - } + return GetBorderStyle(_border.right); } set { CT_BorderPr pr = _border.IsSetRight() ? _border.right : _border.AddNewRight(); - if (value == (short)BorderStyle.None) _border.unsetRight(); - else pr.style = (ST_BorderStyle)(value ); + if (value == (short)BorderStyle.None) _border.UnsetRight(); + else pr.style = (ST_BorderStyle)value; } } @@ -122,20 +97,13 @@ public BorderStyle BorderTop { get { - if (!_border.IsSetTop()) - { - return BorderStyle.None; - } - else - { - return (BorderStyle)_border.top.style; - } + return GetBorderStyle(_border.top); } set { CT_BorderPr pr = _border.IsSetTop() ? _border.top : _border.AddNewTop(); - if (value == (short)BorderStyle.None) _border.unsetTop(); - else pr.style = (ST_BorderStyle)(value ); + if (value == (short)BorderStyle.None) _border.UnsetTop(); + else pr.style = (ST_BorderStyle)value; } } @@ -143,16 +111,14 @@ public short BottomBorderColor { get { - XSSFColor color = BottomBorderColorColor as XSSFColor; - if (color == null) return 0; - return color.Indexed; + return GetIndexedColor(BottomBorderColorColor as XSSFColor); } set { CT_Color ctColor = new CT_Color(); - ctColor.indexed = (uint)(value); + ctColor.indexed = (uint)value; ctColor.indexedSpecified = true; - setBottomBorderColor(ctColor); + SetBottomBorderColor(ctColor); } } @@ -160,16 +126,14 @@ public short DiagonalBorderColor { get { - XSSFColor color = DiagonalBorderColorColor as XSSFColor; - if (color == null) return 0; - return color.Indexed; + return GetIndexedColor(DiagonalBorderColorColor as XSSFColor); } set { CT_Color ctColor = new CT_Color(); - ctColor.indexed = (uint)(value); + ctColor.indexed = (uint)value; ctColor.indexedSpecified = true; - setDiagonalBorderColor(ctColor); + SetDiagonalBorderColor(ctColor); } } @@ -177,16 +141,14 @@ public short LeftBorderColor { get { - XSSFColor color = LeftBorderColorColor as XSSFColor; - if (color == null) return 0; - return color.Indexed; + return GetIndexedColor(LeftBorderColorColor as XSSFColor); } set { CT_Color ctColor = new CT_Color(); ctColor.indexed = (uint)(value); ctColor.indexedSpecified = true; - setLeftBorderColor(ctColor); + SetLeftBorderColor(ctColor); } } @@ -194,16 +156,14 @@ public short RightBorderColor { get { - XSSFColor color = RightBorderColorColor as XSSFColor; - if (color == null) return 0; - return color.Indexed; + return GetIndexedColor(RightBorderColorColor as XSSFColor); } set { CT_Color ctColor = new CT_Color(); ctColor.indexed = (uint)(value); ctColor.indexedSpecified = true; - setRightBorderColor(ctColor); + SetRightBorderColor(ctColor); } } @@ -211,16 +171,14 @@ public short TopBorderColor { get { - XSSFColor color = RightBorderColorColor as XSSFColor; - if (color == null) return 0; - return color.Indexed; + return GetIndexedColor(RightBorderColorColor as XSSFColor); } set { CT_Color ctColor = new CT_Color(); ctColor.indexed = (uint)(value); ctColor.indexedSpecified = true; - setTopBorderColor(ctColor); + SetTopBorderColor(ctColor); } } @@ -228,19 +186,16 @@ public IColor BottomBorderColorColor { get { - if (!_border.IsSetBottom()) return null; - - CT_BorderPr pr = _border.bottom; - return new XSSFColor(pr.color); + return GetColor(_border.bottom); } set { XSSFColor xcolor = XSSFColor.ToXSSFColor(value); - if (xcolor == null) setBottomBorderColor((CT_Color)null); - else setBottomBorderColor(xcolor.GetCTColor()); + if (xcolor == null) SetBottomBorderColor((CT_Color)null); + else SetBottomBorderColor(xcolor.GetCTColor()); } } - public void setBottomBorderColor(CT_Color color) + public void SetBottomBorderColor(CT_Color color) { CT_BorderPr pr = _border.IsSetBottom() ? _border.bottom : _border.AddNewBottom(); if (color == null) @@ -256,19 +211,16 @@ public IColor DiagonalBorderColorColor { get { - if (!_border.IsSetDiagonal()) return null; - - CT_BorderPr pr = _border.diagonal; - return new XSSFColor(pr.color); + return GetColor(_border.diagonal); } set { XSSFColor xcolor = XSSFColor.ToXSSFColor(value); - if (xcolor == null) setDiagonalBorderColor((CT_Color)null); - else setDiagonalBorderColor(xcolor.GetCTColor()); + if (xcolor == null) SetDiagonalBorderColor((CT_Color)null); + else SetDiagonalBorderColor(xcolor.GetCTColor()); } } - public void setDiagonalBorderColor(CT_Color color) + public void SetDiagonalBorderColor(CT_Color color) { CT_BorderPr pr = _border.IsSetDiagonal() ? _border.diagonal : _border.AddNewDiagonal(); if (color == null) @@ -284,20 +236,17 @@ public IColor LeftBorderColorColor { get { - if (!_border.IsSetLeft()) return null; - - CT_BorderPr pr = _border.left; - return new XSSFColor(pr.color); + return GetColor(_border.left); } set { XSSFColor xcolor = XSSFColor.ToXSSFColor(value); - if (xcolor == null) setLeftBorderColor((CT_Color)null); - else setLeftBorderColor(xcolor.GetCTColor()); + if (xcolor == null) SetLeftBorderColor((CT_Color)null); + else SetLeftBorderColor(xcolor.GetCTColor()); } } - public void setLeftBorderColor(CT_Color color) + public void SetLeftBorderColor(CT_Color color) { CT_BorderPr pr = _border.IsSetLeft() ? _border.left : _border.AddNewLeft(); if (color == null) @@ -311,21 +260,19 @@ public void setLeftBorderColor(CT_Color color) } public IColor RightBorderColorColor { - get { - if (!_border.IsSetRight()) return null; - - CT_BorderPr pr = _border.right; - return new XSSFColor(pr.color); + get + { + return GetColor(_border.right); } set { XSSFColor xcolor = XSSFColor.ToXSSFColor(value); - if (xcolor == null) setRightBorderColor((CT_Color)null); - else setRightBorderColor(xcolor.GetCTColor()); + if (xcolor == null) SetRightBorderColor((CT_Color)null); + else SetRightBorderColor(xcolor.GetCTColor()); } } - public void setRightBorderColor(CT_Color color) + public void SetRightBorderColor(CT_Color color) { CT_BorderPr pr = _border.IsSetRight() ? _border.right : _border.AddNewRight(); if (color == null) @@ -340,20 +287,18 @@ public void setRightBorderColor(CT_Color color) public IColor TopBorderColorColor { - get { - if (!_border.IsSetTop()) return null; - - CT_BorderPr pr = _border.top; - return new XSSFColor(pr.color); + get + { + return GetColor(_border.top); } set { XSSFColor xcolor = XSSFColor.ToXSSFColor(value); - if (xcolor == null) setTopBorderColor((CT_Color)null); - else setTopBorderColor(xcolor.GetCTColor()); + if (xcolor == null) SetTopBorderColor((CT_Color)null); + else SetTopBorderColor(xcolor.GetCTColor()); } } - public void setTopBorderColor(CT_Color color) + public void SetTopBorderColor(CT_Color color) { CT_BorderPr pr = _border.IsSetTop() ? _border.top : _border.AddNewTop(); if (color == null) @@ -365,9 +310,134 @@ public void setTopBorderColor(CT_Color color) pr.color = (color); } } - #endregion - } -} + public BorderStyle BorderVertical + { + get => GetBorderStyle(_border.vertical); + set + { + CT_BorderPr pr = _border.IsSetVertical() ? _border.vertical : _border.AddNewVertical(); + if (value == BorderStyle.None) _border.UnsetVertical(); + else pr.style = (ST_BorderStyle)value; + } + } + public BorderStyle BorderHorizontal + { + get => GetBorderStyle(_border.horizontal); + set + { + CT_BorderPr pr = _border.IsSetHorizontal() ? _border.horizontal : _border.AddNewHorizontal(); + if (value == BorderStyle.None) _border.UnsetHorizontal(); + else pr.style = (ST_BorderStyle)value; + } + } + + + public short VerticalBorderColor + { + get + { + return GetIndexedColor(VerticalBorderColorColor as XSSFColor); + } + set + { + CT_Color ctColor = new CT_Color(); + ctColor.indexed = (uint)value; + SetVerticalBorderColor(ctColor); + } + } + public IColor VerticalBorderColorColor + { + get + { + return GetColor(_border.vertical); + } + set + { + XSSFColor xcolor = XSSFColor.ToXSSFColor(value); + if (xcolor == null) SetBottomBorderColor((CT_Color)null); + else SetVerticalBorderColor(xcolor.GetCTColor()); + } + } + public void SetVerticalBorderColor(CT_Color color) + { + CT_BorderPr pr = _border.IsSetVertical() ? _border.vertical : _border.AddNewVertical(); + if (color == null) + { + pr.UnsetColor(); + } + else + { + pr.color = color; + } + } + + public short HorizontalBorderColor + { + get + { + return GetIndexedColor(HorizontalBorderColorColor as XSSFColor); + } + set + { + CT_Color ctColor = new CT_Color(); + ctColor.indexed = (uint)value; + SetHorizontalBorderColor(ctColor); + } + } + + public IColor HorizontalBorderColorColor + { + get + { + return GetColor(_border.horizontal); + } + set + { + XSSFColor xcolor = XSSFColor.ToXSSFColor(value); + if (xcolor == null) SetBottomBorderColor((CT_Color)null); + else SetHorizontalBorderColor(xcolor.GetCTColor()); + } + } + + + public void SetHorizontalBorderColor(CT_Color color) + { + CT_BorderPr pr = _border.IsSetHorizontal() ? _border.horizontal : _border.AddNewHorizontal(); + if (color == null) + { + pr.UnsetColor(); + } + else + { + pr.color = color; + } + } + + + + /** + * @param borderPr + * @return BorderStyle from the given element's style, or NONE if border is null + */ + private static BorderStyle GetBorderStyle(CT_BorderPr borderPr) + { + if (borderPr == null) return BorderStyle.None; + ST_BorderStyle? ptrn = borderPr.style; + return ptrn == null ? BorderStyle.None : BorderStyleEnum.ValueOf((short)ptrn.Value); + } + + private static short GetIndexedColor(XSSFColor color) + { + return (short)(color == null ? 0 : color.Indexed); + } + + private XSSFColor GetColor(CT_BorderPr pr) + { + return pr == null ? null : new XSSFColor(pr.color, _colorMap); + } + #endregion + } +} diff --git a/ooxml/XSSF/UserModel/XSSFBuiltinTableStyle.cs b/ooxml/XSSF/UserModel/XSSFBuiltinTableStyle.cs index f94023bae..7ece6ed40 100644 --- a/ooxml/XSSF/UserModel/XSSFBuiltinTableStyle.cs +++ b/ooxml/XSSF/UserModel/XSSFBuiltinTableStyle.cs @@ -26,294 +26,298 @@ limitations under the License. namespace NPOI.XSSF.UserModel { - public enum XSSFBuiltinTableStyleEnum:int + /// + /// Table style names defined in the OOXML spec. + /// The actual styling is defined in presetTableStyles.xml + /// + public enum XSSFBuiltinTableStyleEnum : int { TableStyleDark1, - + TableStyleDark2, - + TableStyleDark3, - + TableStyleDark4, - + TableStyleDark5, - + TableStyleDark6, - + TableStyleDark7, - + TableStyleDark8, - + TableStyleDark9, - + TableStyleDark10, - + TableStyleDark11, - + TableStyleLight1, - + TableStyleLight2, - + TableStyleLight3, - + TableStyleLight4, - + TableStyleLight5, - + TableStyleLight6, - + TableStyleLight7, - + TableStyleLight8, - + TableStyleLight9, - + TableStyleLight10, - + TableStyleLight11, - + TableStyleLight12, - + TableStyleLight13, - + TableStyleLight14, - + TableStyleLight15, - + TableStyleLight16, - + TableStyleLight17, - + TableStyleLight18, - + TableStyleLight19, - + TableStyleLight20, - + TableStyleLight21, - + TableStyleMedium1, - + TableStyleMedium2, - + TableStyleMedium3, - + TableStyleMedium4, - + TableStyleMedium5, - + TableStyleMedium6, - + TableStyleMedium7, - + TableStyleMedium8, - + TableStyleMedium9, - + TableStyleMedium10, - + TableStyleMedium11, - + TableStyleMedium12, - + TableStyleMedium13, - + TableStyleMedium14, - + TableStyleMedium15, - + TableStyleMedium16, - + TableStyleMedium17, - + TableStyleMedium18, - + TableStyleMedium19, - + TableStyleMedium20, - + TableStyleMedium21, - + TableStyleMedium22, - + TableStyleMedium23, - + TableStyleMedium24, - + TableStyleMedium25, - + TableStyleMedium26, - + TableStyleMedium27, - + TableStyleMedium28, - + PivotStyleMedium1, - + PivotStyleMedium2, - + PivotStyleMedium3, - + PivotStyleMedium4, - + PivotStyleMedium5, - + PivotStyleMedium6, - + PivotStyleMedium7, - + PivotStyleMedium8, - + PivotStyleMedium9, - + PivotStyleMedium10, - + PivotStyleMedium11, - + PivotStyleMedium12, - + PivotStyleMedium13, - + PivotStyleMedium14, - + PivotStyleMedium15, - + PivotStyleMedium16, - + PivotStyleMedium17, - + PivotStyleMedium18, - + PivotStyleMedium19, - + PivotStyleMedium20, - + PivotStyleMedium21, - + PivotStyleMedium22, - + PivotStyleMedium23, - + PivotStyleMedium24, - + PivotStyleMedium25, - + PivotStyleMedium26, - + PivotStyleMedium27, - + PivotStyleMedium28, - + PivotStyleLight1, - + PivotStyleLight2, - + PivotStyleLight3, - + PivotStyleLight4, - + PivotStyleLight5, - + PivotStyleLight6, - + PivotStyleLight7, - + PivotStyleLight8, - + PivotStyleLight9, - + PivotStyleLight10, - + PivotStyleLight11, - + PivotStyleLight12, - + PivotStyleLight13, - + PivotStyleLight14, - + PivotStyleLight15, - + PivotStyleLight16, - + PivotStyleLight17, - + PivotStyleLight18, - + PivotStyleLight19, - + PivotStyleLight20, - + PivotStyleLight21, - + PivotStyleLight22, - + PivotStyleLight23, - + PivotStyleLight24, - + PivotStyleLight25, - + PivotStyleLight26, - + PivotStyleLight27, - + PivotStyleLight28, - + PivotStyleDark1, - + PivotStyleDark2, - + PivotStyleDark3, - + PivotStyleDark4, - + PivotStyleDark5, - + PivotStyleDark6, - + PivotStyleDark7, - + PivotStyleDark8, - + PivotStyleDark9, - + PivotStyleDark10, - + PivotStyleDark11, - + PivotStyleDark12, - + PivotStyleDark13, - + PivotStyleDark14, - + PivotStyleDark15, - + PivotStyleDark16, - + PivotStyleDark17, - + PivotStyleDark18, - + PivotStyleDark19, - + PivotStyleDark20, - + PivotStyleDark21, - + PivotStyleDark22, - + PivotStyleDark23, PivotStyleDark24, - + PivotStyleDark25, - + PivotStyleDark26, - + PivotStyleDark27, - + PivotStyleDark28 } public class XSSFBuiltinTableStyle @@ -328,24 +332,24 @@ public static ITableStyle GetStyle(XSSFBuiltinTableStyleEnum style) } public static bool IsBuiltinStyle(ITableStyle style) { - if (style == null) + if(style == null) return false; - return Enums.GetNames().Any(x=>x==style.Name); + return Enums.GetNames().Any(x => x==style.Name); } private static void Init() { - if (styleMap.Count > 0) + if(styleMap.Count > 0) return; - using (var xmlstream = typeof (XSSFBuiltinTableStyle).Assembly.GetManifestResourceStream(presetTableStylesResourceName)) + using(var xmlstream = typeof(XSSFBuiltinTableStyle).Assembly.GetManifestResourceStream(presetTableStylesResourceName)) { var xmlReader = new XmlTextReader(xmlstream); var xmlDocument = new XmlDocument(); xmlDocument.Load(xmlReader); var node = xmlDocument.SelectSingleNode("presetTableStyles"); - foreach (XmlNode child in node.ChildNodes) + foreach(XmlNode child in node.ChildNodes) { String styleName = child.Name; - if (!Enum.TryParse(styleName, out XSSFBuiltinTableStyleEnum builtIn)) + if(!Enum.TryParse(styleName, out XSSFBuiltinTableStyleEnum builtIn)) { continue; } @@ -355,11 +359,12 @@ private static void Init() var styleXmlDocument = new XmlDocument(); styleXmlDocument.LoadXml(StyleXML(dxfsNode, tableStyleNode)); styles.ReadFrom(styleXmlDocument); - styleMap.Add(builtIn,new XSSFBuiltinTypeStyleStyle(builtIn, styles.GetExplicitTableStyle(styleName))); + styleMap.Add(builtIn, new XSSFBuiltinTypeStyleStyle(builtIn, styles.GetExplicitTableStyle(styleName))); } } } - private static string StyleXML(XmlNode dxfsNode, XmlNode tableStyleNode) { + private static string StyleXML(XmlNode dxfsNode, XmlNode tableStyleNode) + { // built-ins doc uses 1-based dxf indexing, Excel uses 0 based. // add a dummy node to adjust properly. dxfsNode.InsertBefore(dxfsNode.OwnerDocument.CreateElement("dxf"), dxfsNode.FirstChild); @@ -376,51 +381,51 @@ private static string StyleXML(XmlNode dxfsNode, XmlNode tableStyleNode) { sb.Append(""); return sb.ToString(); } - protected class XSSFBuiltinTypeStyleStyle : ITableStyle + protected class XSSFBuiltinTypeStyleStyle : ITableStyle { - private XSSFBuiltinTableStyleEnum builtIn; - private ITableStyle style; + private XSSFBuiltinTableStyleEnum builtIn; + private ITableStyle style; - /** - * @param builtIn - * @param style - */ - internal XSSFBuiltinTypeStyleStyle(XSSFBuiltinTableStyleEnum builtIn, ITableStyle style) - { - this.builtIn = builtIn; - this.style = style; - } + /** + * @param builtIn + * @param style + */ + internal XSSFBuiltinTypeStyleStyle(XSSFBuiltinTableStyleEnum builtIn, ITableStyle style) + { + this.builtIn = builtIn; + this.style = style; + } - public String Name - { - get + public String Name { - return style.Name; + get + { + return style.Name; + } } - } - public int Index - { - get + public int Index { - return (int)builtIn; + get + { + return (int) builtIn; + } } - } - public bool IsBuiltin - { - get + public bool IsBuiltin { - return true; + get + { + return true; + } } - } - public IDifferentialStyleProvider GetStyle(TableStyleType type) - { - return style.GetStyle(type); - } + public IDifferentialStyleProvider GetStyle(TableStyleType type) + { + return style.GetStyle(type); + } + } } } -} diff --git a/ooxml/XSSF/UserModel/XSSFCellStyle.cs b/ooxml/XSSF/UserModel/XSSFCellStyle.cs index 0d70f9a2c..f3ebd25bd 100644 --- a/ooxml/XSSF/UserModel/XSSFCellStyle.cs +++ b/ooxml/XSSF/UserModel/XSSFCellStyle.cs @@ -204,7 +204,7 @@ public void CloneStyleFrom(ICellStyle source) } private void AddFill(CT_Fill fill) { - int idx = _stylesSource.PutFill(new XSSFCellFill(fill)); + int idx = _stylesSource.PutFill(new XSSFCellFill(fill, _stylesSource.IndexedColors)); _cellXf.fillId = (uint)(idx); _cellXf.applyFill = (true); @@ -212,7 +212,7 @@ private void AddFill(CT_Fill fill) private void AddBorder(CT_Border border) { - int idx = _stylesSource.PutBorder(new XSSFCellBorder(border, _theme)); + int idx = _stylesSource.PutBorder(new XSSFCellBorder(border, _theme, _stylesSource.IndexedColors)); _cellXf.borderId = (uint)(idx); _cellXf.applyBorder = (true); @@ -289,7 +289,7 @@ public BorderStyle BorderBottom else pr.style = (ST_BorderStyle)value; - int idx = _stylesSource.PutBorder(new XSSFCellBorder(ct, _theme)); + int idx = _stylesSource.PutBorder(new XSSFCellBorder(ct, _theme, _stylesSource.IndexedColors)); _cellXf.borderId = (uint)idx; _cellXf.applyBorder = (true); @@ -320,10 +320,10 @@ public BorderStyle BorderLeft { CT_Border ct = GetCTBorder(copy: true); CT_BorderPr pr = ct.IsSetLeft() ? ct.left : ct.AddNewLeft(); - if (value == BorderStyle.None) ct.unsetLeft(); + if (value == BorderStyle.None) ct.UnsetLeft(); else pr.style = (ST_BorderStyle)value; - int idx = _stylesSource.PutBorder(new XSSFCellBorder(ct, _theme)); + int idx = _stylesSource.PutBorder(new XSSFCellBorder(ct, _theme, _stylesSource.IndexedColors)); _cellXf.borderId = (uint)idx; _cellXf.applyBorder = (true); @@ -355,10 +355,10 @@ public BorderStyle BorderRight { CT_Border ct = GetCTBorder(copy: true); CT_BorderPr pr = ct.IsSetRight() ? ct.right : ct.AddNewRight(); - if (value == BorderStyle.None) ct.unsetRight(); + if (value == BorderStyle.None) ct.UnsetRight(); else pr.style = (ST_BorderStyle)value; - int idx = _stylesSource.PutBorder(new XSSFCellBorder(ct, _theme)); + int idx = _stylesSource.PutBorder(new XSSFCellBorder(ct, _theme, _stylesSource.IndexedColors)); _cellXf.borderId = (uint)idx; _cellXf.applyBorder = (true); @@ -389,10 +389,10 @@ public BorderStyle BorderTop { CT_Border ct = GetCTBorder(copy: true); CT_BorderPr pr = ct.IsSetTop() ? ct.top : ct.AddNewTop(); - if (value == BorderStyle.None) ct.unsetTop(); + if (value == BorderStyle.None) ct.UnsetTop(); else pr.style = (ST_BorderStyle)value; - int idx = _stylesSource.PutBorder(new XSSFCellBorder(ct, _theme)); + int idx = _stylesSource.PutBorder(new XSSFCellBorder(ct, _theme, _stylesSource.IndexedColors)); _cellXf.borderId = (uint)idx; _cellXf.applyBorder = (true); @@ -993,7 +993,7 @@ public void SetBottomBorderColor(XSSFColor color) if (color != null) pr.SetColor(color.GetCTColor()); else pr.UnsetColor(); - int idx = _stylesSource.PutBorder(new XSSFCellBorder(ct, _theme)); + int idx = _stylesSource.PutBorder(new XSSFCellBorder(ct, _theme, _stylesSource.IndexedColors)); _cellXf.borderId = (uint)idx; _cellXf.applyBorder = (true); @@ -1038,7 +1038,7 @@ public void SetFillBackgroundColor(XSSFColor color) ptrn.bgColor = color.GetCTColor(); } - int idx = _stylesSource.PutFill(new XSSFCellFill(ct)); + int idx = _stylesSource.PutFill(new XSSFCellFill(ct, _stylesSource.IndexedColors)); _cellXf.fillId = (uint)idx; _cellXf.applyFill = (true); @@ -1066,7 +1066,7 @@ public void SetFillForegroundColor(XSSFColor color) ptrn.fgColor = (color.GetCTColor()); } - int idx = _stylesSource.PutFill(new XSSFCellFill(ct)); + int idx = _stylesSource.PutFill(new XSSFCellFill(ct, _stylesSource.IndexedColors)); _cellXf.fillId = (uint)idx; _cellXf.applyFill = (true); @@ -1154,7 +1154,7 @@ public void SetDiagonalBorderColor(XSSFColor color) if (color != null) pr.color = (color.GetCTColor()); else pr.UnsetColor(); - int idx = _stylesSource.PutBorder(new XSSFCellBorder(ct, _theme)); + int idx = _stylesSource.PutBorder(new XSSFCellBorder(ct, _theme, _stylesSource.IndexedColors)); _cellXf.borderId = (uint)idx; _cellXf.applyBorder = (true); @@ -1173,7 +1173,7 @@ public void SetLeftBorderColor(XSSFColor color) if (color != null) pr.color = (color.GetCTColor()); else pr.UnsetColor(); - int idx = _stylesSource.PutBorder(new XSSFCellBorder(ct, _theme)); + int idx = _stylesSource.PutBorder(new XSSFCellBorder(ct, _theme, _stylesSource.IndexedColors)); _cellXf.borderId = (uint)idx; _cellXf.applyBorder = (true); @@ -1193,7 +1193,7 @@ public void SetRightBorderColor(XSSFColor color) if (color != null) pr.color = (color.GetCTColor()); else pr.UnsetColor(); - int idx = _stylesSource.PutBorder(new XSSFCellBorder(ct, _theme)); + int idx = _stylesSource.PutBorder(new XSSFCellBorder(ct, _theme, _stylesSource.IndexedColors)); _cellXf.borderId = (uint)(idx); _cellXf.applyBorder = (true); @@ -1216,7 +1216,7 @@ public void SetTopBorderColor(XSSFColor color) if (color != null) pr.color = color.GetCTColor(); else pr.UnsetColor(); - int idx = _stylesSource.PutBorder(new XSSFCellBorder(ct, _theme)); + int idx = _stylesSource.PutBorder(new XSSFCellBorder(ct, _theme, _stylesSource.IndexedColors)); _cellXf.borderId = (uint)idx; _cellXf.applyBorder = (true); @@ -1427,11 +1427,11 @@ public BorderStyle BorderDiagonalLineStyle CT_Border ct = GetCTBorder(copy: true); CT_BorderPr pr = ct.IsSetDiagonal() ? ct.diagonal : ct.AddNewDiagonal(); if (value == BorderStyle.None) - ct.unsetDiagonal(); + ct.UnsetDiagonal(); else pr.style = (ST_BorderStyle)value; - int idx = _stylesSource.PutBorder(new XSSFCellBorder(ct, _theme)); + int idx = _stylesSource.PutBorder(new XSSFCellBorder(ct, _theme, _stylesSource.IndexedColors)); _cellXf.borderId = (uint)idx; _cellXf.applyBorder = (true); @@ -1478,7 +1478,7 @@ public BorderDiagonal BorderDiagonal } else { - ct.unsetDiagonal(); + ct.UnsetDiagonal(); ct.diagonalDown = false; ct.diagonalDownSpecified = false; ct.diagonalUp = false; diff --git a/ooxml/XSSF/UserModel/XSSFColor.cs b/ooxml/XSSF/UserModel/XSSFColor.cs index 35346e7d8..d4bc11afd 100644 --- a/ooxml/XSSF/UserModel/XSSFColor.cs +++ b/ooxml/XSSF/UserModel/XSSFColor.cs @@ -23,6 +23,7 @@ limitations under the License. using NPOI.OpenXmlFormats.Spreadsheet; using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; +using NPOI.OOXML.XSSF.UserModel; namespace NPOI.XSSF.UserModel { @@ -34,21 +35,28 @@ public class XSSFColor : ExtendedColor { private CT_Color ctColor; + private IIndexedColorMap indexedColorMap; /** * Create an instance of XSSFColor from the supplied XML bean */ + [Obsolete("Remove it at NPOI 2.8.0")] public XSSFColor(CT_Color color) + : this(color, new DefaultIndexedColorMap()) + { + + } + public XSSFColor(CT_Color color, IIndexedColorMap map) { this.ctColor = color; + this.indexedColorMap = map; } - /** * Create an new instance of XSSFColor */ public XSSFColor() + : this(new CT_Color(), null) { - this.ctColor = new CT_Color(); } public XSSFColor(Color clr) @@ -64,15 +72,15 @@ public XSSFColor(Rgb24 clr) ctColor.SetRgb(clr.R, clr.G, clr.B); } - public XSSFColor(byte[] rgb) - : this() + public XSSFColor(byte[] rgb, IIndexedColorMap colorMap) + : this(new CT_Color(), colorMap) { ctColor.SetRgb(rgb); } - public XSSFColor(IndexedColors indexedColor) - : this() + public XSSFColor(IndexedColors indexedColor, IIndexedColorMap colorMap) + : this(new CT_Color(), colorMap) { ctColor.indexed = (uint)indexedColor.Index; } @@ -178,6 +186,20 @@ protected override byte[] StoredRGB } } + + protected override byte[] IndexedRGB + { + get + { + if (IsIndexed) + { + if (indexedColorMap != null) return indexedColorMap.GetRGB(Index); + return DefaultIndexedColorMap.GetDefaultRGB(Index); + } + return null; + } + + } /** * Standard Red Green Blue ctColor value (RGB). * If there was an A (Alpha) value, it will be stripped. diff --git a/ooxml/XSSF/UserModel/XSSFColorScaleFormatting.cs b/ooxml/XSSF/UserModel/XSSFColorScaleFormatting.cs index a26a764ec..be07a86d7 100644 --- a/ooxml/XSSF/UserModel/XSSFColorScaleFormatting.cs +++ b/ooxml/XSSF/UserModel/XSSFColorScaleFormatting.cs @@ -20,6 +20,7 @@ namespace NPOI.XSSF.UserModel { using System; using System.Collections.Generic; + using NPOI.OOXML.XSSF.UserModel; using NPOI.OpenXmlFormats.Spreadsheet; using NPOI.SS.UserModel; @@ -27,24 +28,29 @@ namespace NPOI.XSSF.UserModel * High level representation for Color Scale / Color Gradient Formatting * component of Conditional Formatting Settings */ - public class XSSFColorScaleFormatting : IColorScaleFormatting { + public class XSSFColorScaleFormatting : IColorScaleFormatting + { readonly CT_ColorScale _scale; + private IIndexedColorMap _indexedColorMap; /*package*/ - public XSSFColorScaleFormatting(CT_ColorScale scale) { + public XSSFColorScaleFormatting(CT_ColorScale scale, IIndexedColorMap colorMap) + { _scale = scale; + _indexedColorMap = colorMap; } public int NumControlPoints { get { return _scale.SizeOfCfvoArray(); } - set { - while (value < _scale.SizeOfCfvoArray()) + set + { + while(value < _scale.SizeOfCfvoArray()) { _scale.RemoveCfvo(_scale.SizeOfCfvoArray() - 1); _scale.RemoveColor(_scale.SizeOfColorArray() - 1); } - while (value > _scale.SizeOfCfvoArray()) + while(value > _scale.SizeOfCfvoArray()) { _scale.AddNewCfvo(); _scale.AddNewColor(); @@ -58,18 +64,18 @@ public IColor[] Colors { CT_Color[] ctcols = _scale.color.ToArray();//.ColorArray; XSSFColor[] c = new XSSFColor[ctcols.Length]; - for (int i = 0; i < ctcols.Length; i++) + for(int i = 0; i < ctcols.Length; i++) { - c[i] = new XSSFColor(ctcols[i]); + c[i] = new XSSFColor(ctcols[i], _indexedColorMap); } return c; } set { CT_Color[] ctcols = new CT_Color[value.Length]; - for (int i = 0; i < value.Length; i++) + for(int i = 0; i < value.Length; i++) { - ctcols[i] = ((XSSFColor)value[i]).GetCTColor(); + ctcols[i] = ((XSSFColor) value[i]).GetCTColor(); } _scale.color = new List(ctcols); } @@ -82,7 +88,7 @@ public IConditionalFormattingThreshold[] Thresholds CT_Cfvo[] cfvos = _scale.cfvo.ToArray(); XSSFConditionalFormattingThreshold[] t = new XSSFConditionalFormattingThreshold[cfvos.Length]; - for (int i = 0; i < cfvos.Length; i++) + for(int i = 0; i < cfvos.Length; i++) { t[i] = new XSSFConditionalFormattingThreshold(cfvos[i]); } @@ -91,18 +97,20 @@ public IConditionalFormattingThreshold[] Thresholds set { CT_Cfvo[] cfvos = new CT_Cfvo[value.Length]; - for (int i = 0; i < value.Length; i++) + for(int i = 0; i < value.Length; i++) { - cfvos[i] = ((XSSFConditionalFormattingThreshold)value[i]).CTCfvo; + cfvos[i] = ((XSSFConditionalFormattingThreshold) value[i]).CTCfvo; } _scale.cfvo = new List(cfvos); } } - public XSSFColor CreateColor() { - return new XSSFColor(_scale.AddNewColor()); + public XSSFColor CreateColor() + { + return new XSSFColor(_scale.AddNewColor(), _indexedColorMap); } - public IConditionalFormattingThreshold CreateThreshold() { + public IConditionalFormattingThreshold CreateThreshold() + { return new XSSFConditionalFormattingThreshold(_scale.AddNewCfvo()); } } diff --git a/ooxml/XSSF/UserModel/XSSFConditionalFormattingRule.cs b/ooxml/XSSF/UserModel/XSSFConditionalFormattingRule.cs index 42fdb04bb..35b61c2d3 100644 --- a/ooxml/XSSF/UserModel/XSSFConditionalFormattingRule.cs +++ b/ooxml/XSSF/UserModel/XSSFConditionalFormattingRule.cs @@ -136,7 +136,7 @@ public IBorderFormatting CreateBorderFormatting() border = dxf.border; } - return new XSSFBorderFormatting(border); + return new XSSFBorderFormatting(border, (_sh.Workbook as XSSFWorkbook).GetStylesSource().IndexedColors); } /** @@ -149,7 +149,7 @@ public IBorderFormatting BorderFormatting CT_Dxf dxf = GetDxf(false); if (dxf == null || !dxf.IsSetBorder()) return null; - return new XSSFBorderFormatting(dxf.border); + return new XSSFBorderFormatting(dxf.border, (_sh.Workbook as XSSFWorkbook).GetStylesSource().IndexedColors); } } @@ -172,7 +172,7 @@ public IFontFormatting CreateFontFormatting() font = dxf.font; } - return new XSSFFontFormatting(font); + return new XSSFFontFormatting(font, (_sh.Workbook as XSSFWorkbook).GetStylesSource().IndexedColors); } /** @@ -185,7 +185,7 @@ public IFontFormatting FontFormatting CT_Dxf dxf = GetDxf(false); if (dxf == null || !dxf.IsSetFont()) return null; - return new XSSFFontFormatting(dxf.font); + return new XSSFFontFormatting(dxf.font, (_sh.Workbook as XSSFWorkbook).GetStylesSource().IndexedColors); } } @@ -208,7 +208,7 @@ public IPatternFormatting CreatePatternFormatting() fill = dxf.fill; } - return new XSSFPatternFormatting(fill); + return new XSSFPatternFormatting(fill, (_sh.Workbook as XSSFWorkbook).GetStylesSource().IndexedColors); } /** @@ -221,7 +221,7 @@ public IPatternFormatting PatternFormatting CT_Dxf dxf = GetDxf(false); if (dxf == null || !dxf.IsSetFill()) return null; - return new XSSFPatternFormatting(dxf.fill); + return new XSSFPatternFormatting(dxf.fill, (_sh.Workbook as XSSFWorkbook).GetStylesSource().IndexedColors); } } @@ -254,7 +254,7 @@ public XSSFDataBarFormatting CreateDataBarFormatting(XSSFColor color) max.type = (ST_CfvoType)Enum.Parse(typeof(ST_CfvoType), RangeType.MAX.name); // Wrap and return - return new XSSFDataBarFormatting(bar); + return new XSSFDataBarFormatting(bar, (_sh.Workbook as XSSFWorkbook).GetStylesSource().IndexedColors); } public IDataBarFormatting DataBarFormatting { @@ -263,7 +263,7 @@ public IDataBarFormatting DataBarFormatting if (_cfRule.IsSetDataBar()) { CT_DataBar bar = _cfRule.dataBar; - return new XSSFDataBarFormatting(bar); + return new XSSFDataBarFormatting(bar, (_sh.Workbook as XSSFWorkbook).GetStylesSource().IndexedColors); } else { @@ -367,7 +367,7 @@ public XSSFColorScaleFormatting CreateColorScaleFormatting() } // Wrap and return - return new XSSFColorScaleFormatting(scale); + return new XSSFColorScaleFormatting(scale, (_sh.Workbook as XSSFWorkbook).GetStylesSource().IndexedColors); } public IColorScaleFormatting ColorScaleFormatting { @@ -376,7 +376,7 @@ public IColorScaleFormatting ColorScaleFormatting if (_cfRule.IsSetColorScale()) { CT_ColorScale scale = _cfRule.colorScale; - return new XSSFColorScaleFormatting(scale); + return new XSSFColorScaleFormatting(scale, (_sh.Workbook as XSSFWorkbook).GetStylesSource().IndexedColors); } else { diff --git a/ooxml/XSSF/UserModel/XSSFCreationHelper.cs b/ooxml/XSSF/UserModel/XSSFCreationHelper.cs index cbf91f6de..f534faf6d 100644 --- a/ooxml/XSSF/UserModel/XSSFCreationHelper.cs +++ b/ooxml/XSSF/UserModel/XSSFCreationHelper.cs @@ -14,6 +14,7 @@ the License. You may obtain a copy of the License at See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ +using NPOI.OpenXmlFormats.Spreadsheet; using NPOI.SS.UserModel; using NPOI.XSSF.UserModel; using System; @@ -72,7 +73,8 @@ public IClientAnchor CreateClientAnchor() public ExtendedColor CreateExtendedColor() { - return new XSSFColor(); + return new XSSFColor(new CT_Color(), + (workbook as XSSFWorkbook).GetStylesSource().IndexedColors); } } diff --git a/ooxml/XSSF/UserModel/XSSFDataBarFormatting.cs b/ooxml/XSSF/UserModel/XSSFDataBarFormatting.cs index c23ee43bd..1184c51db 100644 --- a/ooxml/XSSF/UserModel/XSSFDataBarFormatting.cs +++ b/ooxml/XSSF/UserModel/XSSFDataBarFormatting.cs @@ -19,6 +19,7 @@ namespace NPOI.XSSF.UserModel { using System; + using NPOI.OOXML.XSSF.UserModel; using NPOI.OpenXmlFormats.Spreadsheet; using NPOI.SS.UserModel; @@ -28,12 +29,14 @@ namespace NPOI.XSSF.UserModel */ public class XSSFDataBarFormatting : IDataBarFormatting { + IIndexedColorMap _colorMap; readonly CT_DataBar _databar; /*package*/ - public XSSFDataBarFormatting(CT_DataBar databar) + public XSSFDataBarFormatting(CT_DataBar databar, IIndexedColorMap colorMap) { _databar = databar; + _colorMap = colorMap; } public bool IsIconOnly @@ -92,7 +95,7 @@ public IColor Color { get { - return new XSSFColor(_databar.color); + return new XSSFColor(_databar.color, _colorMap); } set { diff --git a/ooxml/XSSF/UserModel/XSSFDxfStyleProvider.cs b/ooxml/XSSF/UserModel/XSSFDxfStyleProvider.cs index 7a4a17908..6f191933b 100644 --- a/ooxml/XSSF/UserModel/XSSFDxfStyleProvider.cs +++ b/ooxml/XSSF/UserModel/XSSFDxfStyleProvider.cs @@ -29,8 +29,8 @@ public XSSFDxfStyleProvider(CT_Dxf dxf, int stripeSize, IIndexedColorMap colorMa } else { - border = dxf.IsSetBorder() ? new XSSFBorderFormatting(dxf.border) : null; - font = dxf.IsSetFont() ? new XSSFFontFormatting(dxf.font) : null; + border = dxf.IsSetBorder() ? new XSSFBorderFormatting(dxf.border, colorMap) : null; + font = dxf.IsSetFont() ? new XSSFFontFormatting(dxf.font, colorMap) : null; if (dxf.IsSetNumFmt()) { CT_NumFmt numFmt = dxf.numFmt; @@ -40,7 +40,7 @@ public XSSFDxfStyleProvider(CT_Dxf dxf, int stripeSize, IIndexedColorMap colorMa { number = null; } - fill = dxf.IsSetFill() ? new XSSFPatternFormatting(dxf.fill) : null; + fill = dxf.IsSetFill() ? new XSSFPatternFormatting(dxf.fill, colorMap) : null; } } public IBorderFormatting BorderFormatting => border; diff --git a/ooxml/XSSF/UserModel/XSSFFont.cs b/ooxml/XSSF/UserModel/XSSFFont.cs index 21794f8ed..7f5c2b963 100644 --- a/ooxml/XSSF/UserModel/XSSFFont.cs +++ b/ooxml/XSSF/UserModel/XSSFFont.cs @@ -23,6 +23,7 @@ limitations under the License. using Dml = NPOI.OpenXmlFormats.Dml; using NPOI.XSSF.Model; using NPOI.Util; +using NPOI.OOXML.XSSF.UserModel; namespace NPOI.XSSF.UserModel { @@ -49,6 +50,7 @@ public class XSSFFont : IFont */ public static short DEFAULT_FONT_COLOR = IndexedColors.Black.Index; + private IIndexedColorMap _indexedColorMap; private ThemesTable _themes; private readonly CT_Font _ctFont; private short _index; @@ -64,10 +66,17 @@ public XSSFFont(CT_Font font) _index = 0; } - public XSSFFont(CT_Font font, int index) + /// + /// Called from parsing styles.xml + /// + /// + /// font index + /// colorMap for default or custom indexed colors + public XSSFFont(CT_Font font, int index, IIndexedColorMap colorMap) { _ctFont = font; _index = (short)index; + _indexedColorMap = colorMap; } /** @@ -202,7 +211,7 @@ public XSSFColor GetXSSFColor() Spreadsheet.CT_Color ctColor = _ctFont.sizeOfColorArray() == 0 ? null : _ctFont.GetColorArray(0); if (ctColor != null) { - XSSFColor color = new XSSFColor(ctColor); + XSSFColor color = new XSSFColor(ctColor, _indexedColorMap); if (_themes != null) { _themes.InheritFromThemeAsRequired(color); diff --git a/ooxml/XSSF/UserModel/XSSFFontFormatting.cs b/ooxml/XSSF/UserModel/XSSFFontFormatting.cs index 74b81dff3..07b6dd89f 100644 --- a/ooxml/XSSF/UserModel/XSSFFontFormatting.cs +++ b/ooxml/XSSF/UserModel/XSSFFontFormatting.cs @@ -16,6 +16,7 @@ * limitations under the License. * ==================================================================== */ +using NPOI.OOXML.XSSF.UserModel; using NPOI.OpenXmlFormats.Spreadsheet; using NPOI.SS.UserModel; using System; @@ -29,12 +30,14 @@ namespace NPOI.XSSF.UserModel */ public class XSSFFontFormatting : IFontFormatting { - CT_Font _font; + private IIndexedColorMap _colorMap; + private CT_Font _font; /*package*/ - internal XSSFFontFormatting(CT_Font font) + internal XSSFFontFormatting(CT_Font font, IIndexedColorMap colorMap) { _font = font; + _colorMap = colorMap; } /** @@ -97,7 +100,7 @@ public IColor FontColor { if (_font.sizeOfColorArray() == 0) return null; - return new XSSFColor(_font.GetColorArray(0)); + return new XSSFColor(_font.GetColorArray(0), _colorMap); } set { diff --git a/ooxml/XSSF/UserModel/XSSFPatternFormatting.cs b/ooxml/XSSF/UserModel/XSSFPatternFormatting.cs index 2ab9fdc3d..864759f8e 100644 --- a/ooxml/XSSF/UserModel/XSSFPatternFormatting.cs +++ b/ooxml/XSSF/UserModel/XSSFPatternFormatting.cs @@ -19,6 +19,7 @@ using NPOI.SS.UserModel; using NPOI.OpenXmlFormats.Spreadsheet; using System; +using NPOI.OOXML.XSSF.UserModel; namespace NPOI.XSSF.UserModel { @@ -27,11 +28,13 @@ namespace NPOI.XSSF.UserModel */ public class XSSFPatternFormatting : IPatternFormatting { + IIndexedColorMap _colorMap; readonly CT_Fill _fill; - public XSSFPatternFormatting(CT_Fill fill) + public XSSFPatternFormatting(CT_Fill fill, IIndexedColorMap colorMap) { _fill = fill; + _colorMap = colorMap; } public IColor FillBackgroundColorColor @@ -39,7 +42,7 @@ public IColor FillBackgroundColorColor get { if (!_fill.IsSetPatternFill()) return null; - return new XSSFColor(_fill.GetPatternFill().bgColor); + return new XSSFColor(_fill.GetPatternFill().bgColor, _colorMap); } set { @@ -67,7 +70,7 @@ public IColor FillForegroundColorColor { if (!_fill.IsSetPatternFill() || !_fill.GetPatternFill().IsSetFgColor()) return null; - return new XSSFColor(_fill.GetPatternFill().fgColor); + return new XSSFColor(_fill.GetPatternFill().fgColor, _colorMap); } set { diff --git a/ooxml/XSSF/UserModel/XSSFSheet.cs b/ooxml/XSSF/UserModel/XSSFSheet.cs index 960970fbc..e89169556 100644 --- a/ooxml/XSSF/UserModel/XSSFSheet.cs +++ b/ooxml/XSSF/UserModel/XSSFSheet.cs @@ -1170,7 +1170,7 @@ public XSSFColor TabColor return null; } - return new XSSFColor(pr.tabColor); + return new XSSFColor(pr.tabColor, (Workbook as XSSFWorkbook).GetStylesSource().IndexedColors); } set { @@ -3768,14 +3768,9 @@ public List GetTables() [Obsolete("deprecated 3.15-beta2. Removed in 3.17. Use {@link #setTabColor(XSSFColor)}.")] public void SetTabColor(int colorIndex) { - CT_SheetPr pr = worksheet.sheetPr; - if(pr == null) - { - pr = worksheet.AddNewSheetPr(); - } - - CT_Color color = new CT_Color { indexed = (uint) colorIndex }; - pr.tabColor = color; + IndexedColors indexedColor = IndexedColors.FromInt(colorIndex); + XSSFColor color = new XSSFColor(indexedColor, (Workbook as XSSFWorkbook).GetStylesSource().IndexedColors); + TabColor = color; } #region ISheet Members diff --git a/ooxml/XSSF/UserModel/XSSFTable.cs b/ooxml/XSSF/UserModel/XSSFTable.cs index 04db877cb..9228ed8fc 100644 --- a/ooxml/XSSF/UserModel/XSSFTable.cs +++ b/ooxml/XSSF/UserModel/XSSFTable.cs @@ -56,8 +56,12 @@ public class XSSFTable : POIXMLDocumentPart, ITable private CellReference startCellReference; private CellReference endCellReference; private String commonXPath; + private String name; + private String styleName; - + /// + /// empty implementation, not attached to a workbook/worksheet yet + /// public XSSFTable() : base() { @@ -79,6 +83,11 @@ protected XSSFTable(PackagePart part, PackageRelationship rel) { } + /// + /// read table XML + /// + /// + /// public void ReadFrom(XmlDocument xmlDoc) { try @@ -92,11 +101,19 @@ public void ReadFrom(XmlDocument xmlDoc) } } + /// + /// + /// + /// owning sheet public XSSFSheet GetXSSFSheet() { return (XSSFSheet)GetParent(); } + /// + /// write table XML to stream + /// + /// public void WriteTo(Stream out1) { UpdateHeaders(); @@ -114,6 +131,10 @@ protected internal override void Commit() out1.Close(); } + /// + /// get the underlying CTTable + /// + /// public CT_Table GetCTTable() { return ctTable; @@ -220,7 +241,6 @@ public List GetXmlColumnPrs() } return xmlColumnPrs; } - private string name; /** * @return the name of the Table, if set */ @@ -246,6 +266,43 @@ public String Name name = value; } } + + + /// + /// Get or set the name of the Table + /// + /// + /// @since 3.17 beta 1 + /// + public string StyleName + { + get { + if (styleName == null && ctTable.IsSetTableStyleInfo()) + { + StyleName = ctTable.tableStyleInfo.name; + } + return styleName; + } + set + { + if (value == null) + { + if (ctTable.IsSetTableStyleInfo()) + { + ctTable.tableStyleInfo.name =null; + } + styleName = null; + return; + } + if (!ctTable.IsSetTableStyleInfo()) + { + ctTable.AddNewTableStyleInfo(); + } + ctTable.tableStyleInfo.name = value; + styleName = value; + } + } + public XSSFTableColumn CreateColumn(String columnName) { return CreateColumn(columnName, this.ColumnCount); @@ -383,35 +440,7 @@ protected void SetCellRef(AreaReference refs) UpdateReferences(); UpdateHeaders(); } - private String styleName; - public string StyleName - { - get { - if (styleName == null && ctTable.IsSetTableStyleInfo()) - { - StyleName = ctTable.tableStyleInfo.name; - } - return styleName; - } - set - { - if (value == null) - { - if (ctTable.IsSetTableStyleInfo()) - { - ctTable.tableStyleInfo.name =null; - } - styleName = null; - return; - } - if (!ctTable.IsSetTableStyleInfo()) - { - ctTable.AddNewTableStyleInfo(); - } - ctTable.tableStyleInfo.name = value; - styleName = value; - } - } + public ITableStyleInfo Style { get @@ -761,5 +790,26 @@ public bool Contains(CellReference cell) } return false; } + + /// + /// + /// + /// + /// @since 3.17 beta 1 + /// + public bool Contains(ICell cell) + { + if (cell == null) return false; + // check if cell is on the same sheet as the table + if (!SheetName.Equals(cell.Sheet.SheetName)) return false; + // check if the cell is inside the table + if (cell.RowIndex >= StartRowIndex + && cell.RowIndex <= EndRowIndex + && cell.ColumnIndex >= StartColIndex + && cell.ColumnIndex <= EndColIndex) { + return true; + } + return false; + } } } \ No newline at end of file diff --git a/testcases/main/SS/Formula/TestWorkbookEvaluator.cs b/testcases/main/SS/Formula/TestWorkbookEvaluator.cs index bf8278434..fa4e28d65 100644 --- a/testcases/main/SS/Formula/TestWorkbookEvaluator.cs +++ b/testcases/main/SS/Formula/TestWorkbookEvaluator.cs @@ -369,7 +369,7 @@ private void TestIFEqualsFormulaEvaluation_eval( { TestIFEqualsFormulaEvaluation_evaluate(formula, cellType, expectedFormula, expectedValue); TestIFEqualsFormulaEvaluation_evaluateFormulaCell(formula, cellType, expectedFormula, expectedValue); - TestIFEqualsFormulaEvaluation_evaluateInCell(formula, cellType, expectedFormula, expectedValue); + TestIFEqualsFormulaEvaluation_evaluateInCell(formula, cellType, expectedValue); TestIFEqualsFormulaEvaluation_evaluateAll(formula, cellType, expectedFormula, expectedValue); TestIFEqualsFormulaEvaluation_evaluateAllFormulaCells(formula, cellType, expectedFormula, expectedValue); } @@ -529,7 +529,7 @@ private void TestIFEqualsFormulaEvaluation_evaluateFormulaCell( } private void TestIFEqualsFormulaEvaluation_evaluateInCell( - String formula, CellType cellType, String expectedFormula, double expectedResult) + String formula, CellType cellType, double expectedResult) { IWorkbook wb = TestIFEqualsFormulaEvaluation_setup(formula, cellType); ICell D1 = wb.GetSheet("IFEquals").GetRow(0).GetCell(3); diff --git a/testcases/main/SS/UserModel/TestIndexedColors.cs b/testcases/main/SS/UserModel/TestIndexedColors.cs index 0f147f304..92eb8d6e0 100644 --- a/testcases/main/SS/UserModel/TestIndexedColors.cs +++ b/testcases/main/SS/UserModel/TestIndexedColors.cs @@ -30,7 +30,7 @@ public class TestIndexedColors [Test] public void FromInt() { - int[] illegalIndices = { -1, 0, 27, 65 }; + int[] illegalIndices = { -1, 65 }; foreach (int index in illegalIndices) { try diff --git a/testcases/ooxml/XSSF/UserModel/Extensions/TestXSSFCellFill.cs b/testcases/ooxml/XSSF/UserModel/Extensions/TestXSSFCellFill.cs index 4513c33a9..508849ae0 100644 --- a/testcases/ooxml/XSSF/UserModel/Extensions/TestXSSFCellFill.cs +++ b/testcases/ooxml/XSSF/UserModel/Extensions/TestXSSFCellFill.cs @@ -31,7 +31,7 @@ public class TestXSSFCellFill public void TestGetFillBackgroundColor() { CT_Fill ctFill = new CT_Fill(); - XSSFCellFill cellFill = new XSSFCellFill(ctFill); + XSSFCellFill cellFill = new XSSFCellFill(ctFill, null); CT_PatternFill ctPatternFill = ctFill.AddNewPatternFill(); CT_Color bgColor = ctPatternFill.AddNewBgColor(); ClassicAssert.IsNotNull(cellFill.GetFillBackgroundColor()); @@ -43,7 +43,7 @@ public void TestGetFillBackgroundColor() public void TestGetFillForegroundColor() { CT_Fill ctFill = new CT_Fill(); - XSSFCellFill cellFill = new XSSFCellFill(ctFill); + XSSFCellFill cellFill = new XSSFCellFill(ctFill, null); CT_PatternFill ctPatternFill = ctFill.AddNewPatternFill(); CT_Color fgColor = ctPatternFill.AddNewFgColor(); ClassicAssert.IsNotNull(cellFill.GetFillForegroundColor()); @@ -55,7 +55,7 @@ public void TestGetFillForegroundColor() public void TestGetSetPatternType() { CT_Fill ctFill = new CT_Fill(); - XSSFCellFill cellFill = new XSSFCellFill(ctFill); + XSSFCellFill cellFill = new XSSFCellFill(ctFill, null); CT_PatternFill ctPatternFill = ctFill.AddNewPatternFill(); ctPatternFill.patternType = (ST_PatternType.solid); ClassicAssert.AreEqual(ST_PatternType.solid, cellFill.GetPatternType()); @@ -64,7 +64,7 @@ public void TestGetSetPatternType() public void TestGetNotModifies() { CT_Fill ctFill = new CT_Fill(); - XSSFCellFill cellFill = new XSSFCellFill(ctFill); + XSSFCellFill cellFill = new XSSFCellFill(ctFill, null); CT_PatternFill ctPatternFill = ctFill.AddNewPatternFill(); ctPatternFill.patternType = (ST_PatternType.darkDown); ClassicAssert.AreEqual(ST_PatternType.darkDown, cellFill.GetPatternType()); diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFBugs.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFBugs.cs index 2409b2db9..307511abc 100644 --- a/testcases/ooxml/XSSF/UserModel/TestXSSFBugs.cs +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFBugs.cs @@ -3460,7 +3460,6 @@ public void Test53611() } [Test] - [Ignore("TODO FIX CI TESTS")] public void Bug61063() { IWorkbook wb = XSSFTestDataSamples.OpenSampleWorkbook("61063.xlsx"); diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFCellStyle.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFCellStyle.cs index b7de5fd10..ce085d0e5 100644 --- a/testcases/ooxml/XSSF/UserModel/TestXSSFCellStyle.cs +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFCellStyle.cs @@ -59,7 +59,7 @@ public void SetUp() ClassicAssert.AreEqual(1, stylesTable.PutBorder(borderB)); ctFill = new CT_Fill(); - XSSFCellFill fill = new XSSFCellFill(ctFill); + XSSFCellFill fill = new XSSFCellFill(ctFill, null); long fillId = stylesTable.PutFill(fill); ClassicAssert.AreEqual(2, fillId); diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFColor.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFColor.cs index 71cea90ec..bcb870065 100644 --- a/testcases/ooxml/XSSF/UserModel/TestXSSFColor.cs +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFColor.cs @@ -17,6 +17,7 @@ limitations under the License. namespace TestCases.XSSF.UserModel { + using NPOI.OpenXmlFormats.Spreadsheet; using NPOI.XSSF; using NPOI.XSSF.UserModel; using NUnit.Framework;using NUnit.Framework.Legacy; @@ -174,6 +175,23 @@ public void TestARGBColour() ClassicAssert.AreEqual(255, rgb4.GetRgbWithTint()[0]); ClassicAssert.AreEqual(102, rgb4.GetRgbWithTint()[1]); ClassicAssert.AreEqual(102, rgb4.GetRgbWithTint()[2]); + + wb.Close(); + } + + [Test] + public void TestCustomIndexedColour() + { + XSSFWorkbook wb = XSSFTestDataSamples.OpenSampleWorkbook("customIndexedColors.xlsx"); + XSSFCell cell = wb.GetSheetAt(1).GetRow(0).GetCell(0) as XSSFCell; + XSSFColor color = cell.CellStyle.FillForegroundColorColor as XSSFColor; + CT_Colors ctColors = wb.GetStylesSource().GetCTStylesheet().colors; + + CT_RgbColor ctRgbColor = ctColors.indexedColors[color.Index]; + + string hexRgb = ctRgbColor.rgbHex; + + ClassicAssert.AreEqual(hexRgb, color.ARGBHex); } } diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFFont.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFFont.cs index a9ba4c00d..5d398bf67 100644 --- a/testcases/ooxml/XSSF/UserModel/TestXSSFFont.cs +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFFont.cs @@ -239,7 +239,7 @@ public void TestRgbColor() byte[] bytes = Encoding.ASCII.GetBytes(HexDump.ToHex(0xF1F1F1)); color.rgb = (bytes); - XSSFColor newColor = new XSSFColor(color); + XSSFColor newColor = new XSSFColor(color, null); xssfFont.SetColor(newColor); ClassicAssert.AreEqual(ctFont.GetColorArray(0).GetRgb()[2], newColor.RGB[2]); diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFSheet.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFSheet.cs index e2b00f208..d9ad241e9 100644 --- a/testcases/ooxml/XSSF/UserModel/TestXSSFSheet.cs +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFSheet.cs @@ -2871,7 +2871,7 @@ public void SetTabColor() { XSSFSheet sh = wb.CreateSheet() as XSSFSheet; ClassicAssert.IsTrue(sh.GetCTWorksheet().sheetPr == null || !sh.GetCTWorksheet().sheetPr.IsSetTabColor()); - sh.TabColor = new XSSFColor(IndexedColors.Red); + sh.TabColor = new XSSFColor(IndexedColors.Red, null); ClassicAssert.IsTrue(sh.GetCTWorksheet().sheetPr.IsSetTabColor()); ClassicAssert.AreEqual(IndexedColors.Red.Index, sh.GetCTWorksheet().sheetPr.tabColor.indexed); @@ -2891,8 +2891,8 @@ public void GetTabColor() XSSFSheet sh = wb.CreateSheet() as XSSFSheet; ClassicAssert.IsTrue(sh.GetCTWorksheet().sheetPr == null || !sh.GetCTWorksheet().sheetPr.IsSetTabColor()); ClassicAssert.IsNull(sh.TabColor); - sh.TabColor = new XSSFColor(IndexedColors.Red); - XSSFColor expected = new XSSFColor(IndexedColors.Red); + sh.TabColor = new XSSFColor(IndexedColors.Red, null); + XSSFColor expected = new XSSFColor(IndexedColors.Red, null); ClassicAssert.AreEqual(expected, sh.TabColor); } finally @@ -2912,7 +2912,7 @@ public void TabColor() ClassicAssert.IsNull((wb.GetSheet("default") as XSSFSheet).TabColor); // test indexed-colored sheet - XSSFColor expected = new XSSFColor(IndexedColors.Red); + XSSFColor expected = new XSSFColor(IndexedColors.Red, null); ClassicAssert.AreEqual(expected, (wb.GetSheet("indexedRed") as XSSFSheet).TabColor); // test regular-colored (non-indexed, ARGB) sheet diff --git a/testcases/test-data/spreadsheet/customIndexedColors.xlsx b/testcases/test-data/spreadsheet/customIndexedColors.xlsx new file mode 100644 index 000000000..62b6e1855 Binary files /dev/null and b/testcases/test-data/spreadsheet/customIndexedColors.xlsx differ