diff --git a/OpenXmlFormats/Drawing/BaseTypes.cs b/OpenXmlFormats/Drawing/BaseTypes.cs index 3f7d5d9f9..cea985a58 100644 --- a/OpenXmlFormats/Drawing/BaseTypes.cs +++ b/OpenXmlFormats/Drawing/BaseTypes.cs @@ -3095,7 +3095,7 @@ public static CT_Hyperlink Parse(XmlNode node, XmlNamespaceManager namespaceMana if (node == null) return null; CT_Hyperlink ctObj = new CT_Hyperlink(); - ctObj.id = XmlHelper.ReadString(node.Attributes["id"]); + ctObj.id = XmlHelper.ReadString(node.Attributes["r:id"]); ctObj.invalidUrl = XmlHelper.ReadString(node.Attributes["invalidUrl"]); ctObj.action = XmlHelper.ReadString(node.Attributes["action"]); ctObj.tgtFrame = XmlHelper.ReadString(node.Attributes["tgtFrame"]); @@ -3117,15 +3117,15 @@ public static CT_Hyperlink Parse(XmlNode node, XmlNamespaceManager namespaceMana internal void Write(StreamWriter sw, string nodeName) { - sw.Write(string.Format(""); if (this.snd != null) this.snd.Write(sw, "snd"); @@ -3135,8 +3135,6 @@ internal void Write(StreamWriter sw, string nodeName) } public CT_Hyperlink() { - //this.extLstField = new CT_OfficeArtExtensionList(); - //this.sndField = new CT_EmbeddedWAVAudioFile(); this.invalidUrlField = ""; this.actionField = ""; this.tgtFrameField = ""; diff --git a/OpenXmlFormats/Drawing/Chart/Chart.cs b/OpenXmlFormats/Drawing/Chart/Chart.cs index 2c6d3fc6d..d25909499 100644 --- a/OpenXmlFormats/Drawing/Chart/Chart.cs +++ b/OpenXmlFormats/Drawing/Chart/Chart.cs @@ -74,6 +74,8 @@ public static CT_ChartSpace Parse(XmlNode node, XmlNamespaceManager namespaceMan ctObj.lang = CT_TextLanguageID.Parse(childNode, namespaceManager); else if (childNode.LocalName == "roundedCorners") ctObj.roundedCorners = CT_Boolean.Parse(childNode, namespaceManager); + else if (childNode.LocalName == "AlternateContent") + ctObj.alternateContent = Vml.CT_AlternateContent.Parse(childNode, namespaceManager); else if (childNode.LocalName == "style") ctObj.style = CT_Style.Parse(childNode, namespaceManager); else if (childNode.LocalName == "clrMapOvr") @@ -117,6 +119,8 @@ internal void Write(Stream stream) this.lang.Write(sw, "lang"); if (this.roundedCorners != null) this.roundedCorners.Write(sw, "roundedCorners"); + if (this.alternateContent != null) + this.alternateContent.Write(sw, "AlternateContent"); if (this.style != null) this.style.Write(sw, "style"); if (this.clrMapOvr != null) @@ -197,6 +201,19 @@ public CT_Boolean roundedCorners } } + Vml.CT_AlternateContent alternateContentField = null; + public Vml.CT_AlternateContent alternateContent + { + get + { + return alternateContentField; + } + set + { + this.alternateContentField = value; + } + } + [XmlElement(Order = 3)] public CT_Style style { @@ -428,8 +445,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } } @@ -513,8 +529,7 @@ internal void Write(StreamWriter sw, string nodeName) XmlHelper.WriteAttribute(sw, "horizontalDpi", this.horizontalDpi); XmlHelper.WriteAttribute(sw, "verticalDpi", this.verticalDpi); XmlHelper.WriteAttribute(sw, "copies", this.copies); - sw.Write(">"); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } [XmlAttribute] @@ -711,8 +726,7 @@ internal void Write(StreamWriter sw, string nodeName) XmlHelper.WriteAttribute(sw, "b", this.b); XmlHelper.WriteAttribute(sw, "header", this.header); XmlHelper.WriteAttribute(sw, "footer", this.footer); - sw.Write(">"); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } [XmlAttribute] @@ -1520,8 +1534,7 @@ internal void Write(StreamWriter sw, string nodeName) sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } } @@ -2219,8 +2232,7 @@ internal void Write(StreamWriter sw, string nodeName) sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } [XmlAttribute] @@ -2297,8 +2309,7 @@ internal void Write(StreamWriter sw, string nodeName) sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } } @@ -3228,8 +3239,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } [XmlAttribute] @@ -4061,8 +4071,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } private ST_Crosses valField; @@ -4123,8 +4132,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } [XmlAttribute] @@ -4165,8 +4173,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } private ST_TimeUnit valField; @@ -4783,8 +4790,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } [XmlAttribute] @@ -4828,8 +4834,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } [XmlAttribute] @@ -4870,8 +4875,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } private ST_LblAlgn valField; @@ -5716,8 +5720,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } [XmlAttribute] @@ -6673,8 +6676,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } } @@ -6763,8 +6765,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } @@ -6923,8 +6924,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } private ST_PictureFormat valField; @@ -6982,8 +6982,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } private double valField; @@ -7656,8 +7655,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } } @@ -7997,8 +7995,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } [XmlAttribute] @@ -8067,8 +8064,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } public CT_Order() @@ -8122,8 +8118,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } [XmlAttribute] @@ -8533,8 +8528,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } private ST_ErrDir valField; @@ -8590,8 +8584,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } private ST_ErrBarType valField; @@ -8663,8 +8656,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } [XmlAttribute] @@ -9356,7 +9348,7 @@ public class CT_MultiLvlStrData private CT_UnsignedInt ptCountField; - private List lvlField; + private List lvlField; private List extLstField; @@ -9365,14 +9357,14 @@ public static CT_MultiLvlStrData Parse(XmlNode node, XmlNamespaceManager namespa if (node == null) return null; CT_MultiLvlStrData ctObj = new CT_MultiLvlStrData(); - ctObj.lvl = new List(); + ctObj.lvl = new List(); ctObj.extLst = new List(); foreach (XmlNode childNode in node.ChildNodes) { if (childNode.LocalName == "ptCount") ctObj.ptCount = CT_UnsignedInt.Parse(childNode, namespaceManager); else if (childNode.LocalName == "lvl") - ctObj.lvl.Add(CT_StrVal.Parse(childNode, namespaceManager)); + ctObj.lvl.Add(CT_Lvl.Parse(childNode, namespaceManager)); else if (childNode.LocalName == "extLst") ctObj.extLst.Add(CT_Extension.Parse(childNode, namespaceManager)); } @@ -9387,9 +9379,9 @@ internal void Write(StreamWriter sw, string nodeName) sw.Write(">"); if (this.ptCount != null) this.ptCount.Write(sw, "ptCount"); - if (this.lvl != null) + if (this.lvl != null && this.lvl.Count > 0) { - foreach (CT_StrVal x in this.lvl) + foreach (CT_Lvl x in this.lvl) { x.Write(sw, "lvl"); } @@ -9422,7 +9414,7 @@ public CT_UnsignedInt ptCount } [XmlElement(Order = 1)] - public List lvl + public List lvl { get { @@ -9709,8 +9701,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } [XmlAttribute] @@ -9759,8 +9750,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } [XmlAttribute] @@ -9831,8 +9821,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } [XmlAttribute] @@ -9882,8 +9871,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } [XmlAttribute] @@ -9950,8 +9938,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } private sbyte valField; @@ -10008,8 +9995,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } [XmlAttribute] @@ -10281,18 +10267,18 @@ internal void Write(StreamWriter sw, string nodeName) x.Write(sw, "dateAx"); } } - if (this.catAx != null) + if (this.valAx != null) { - foreach (CT_CatAx x in this.catAx) + foreach (CT_ValAx x in this.valAx) { - x.Write(sw, "catAx"); + x.Write(sw, "valAx"); } } - if (this.valAx != null) + if (this.catAx != null) { - foreach (CT_ValAx x in this.valAx) + foreach (CT_CatAx x in this.catAx) { - x.Write(sw, "valAx"); + x.Write(sw, "catAx"); } } if (this.spPr != null) @@ -10689,8 +10675,7 @@ internal void Write(StreamWriter sw, string nodeName) sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } [XmlAttribute] @@ -10754,8 +10739,7 @@ internal void Write(StreamWriter sw, string nodeName) sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } } @@ -10790,8 +10774,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } @@ -10833,8 +10816,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } @@ -10890,8 +10872,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } @@ -11252,7 +11233,7 @@ public class CT_Chart private CT_Boolean autoTitleDeletedField; - private List pivotFmtsField; + private CT_PivotFmts pivotFmtsField; private CT_View3D view3DField; @@ -11282,7 +11263,6 @@ public static CT_Chart Parse(XmlNode node, XmlNamespaceManager namespaceManager) if (node == null) return null; CT_Chart ctObj = new CT_Chart(); - ctObj.pivotFmts = new List(); ctObj.extLst = new List(); foreach (XmlNode childNode in node.ChildNodes) { @@ -11290,6 +11270,8 @@ public static CT_Chart Parse(XmlNode node, XmlNamespaceManager namespaceManager) ctObj.title = CT_Title.Parse(childNode, namespaceManager); else if (childNode.LocalName == "autoTitleDeleted") ctObj.autoTitleDeleted = CT_Boolean.Parse(childNode, namespaceManager); + else if (childNode.LocalName == "pivotFmts") + ctObj.pivotFmts = CT_PivotFmts.Parse(childNode, namespaceManager); else if (childNode.LocalName == "view3D") ctObj.view3D = CT_View3D.Parse(childNode, namespaceManager); else if (childNode.LocalName == "floor") @@ -11308,8 +11290,6 @@ public static CT_Chart Parse(XmlNode node, XmlNamespaceManager namespaceManager) ctObj.dispBlanksAs = CT_DispBlanksAs.Parse(childNode, namespaceManager); else if (childNode.LocalName == "showDLblsOverMax") ctObj.showDLblsOverMax = CT_Boolean.Parse(childNode, namespaceManager); - else if (childNode.LocalName == "pivotFmts") - ctObj.pivotFmts.Add(CT_PivotFmt.Parse(childNode, namespaceManager)); else if (childNode.LocalName == "extLst") ctObj.extLst.Add(CT_Extension.Parse(childNode, namespaceManager)); } @@ -11326,6 +11306,8 @@ internal void Write(StreamWriter sw, string nodeName) this.title.Write(sw, "title"); if (this.autoTitleDeleted != null) this.autoTitleDeleted.Write(sw, "autoTitleDeleted"); + if (this.pivotFmts != null) + this.pivotFmts.Write(sw, "pivotFmts"); if (this.view3D != null) this.view3D.Write(sw, "view3D"); if (this.floor != null) @@ -11344,13 +11326,7 @@ internal void Write(StreamWriter sw, string nodeName) this.dispBlanksAs.Write(sw, "dispBlanksAs"); if (this.showDLblsOverMax != null) this.showDLblsOverMax.Write(sw, "showDLblsOverMax"); - if (this.pivotFmts != null) - { - foreach (CT_PivotFmt x in this.pivotFmts) - { - x.Write(sw, "pivotFmts"); - } - } + if (this.extLst != null) { foreach (CT_Extension x in this.extLst) @@ -11423,7 +11399,7 @@ public CT_Boolean autoTitleDeleted } [XmlElement(Order = 2)] - public List pivotFmts + public CT_PivotFmts pivotFmts { get { @@ -11742,7 +11718,7 @@ internal void Write(StreamWriter sw, string nodeName) sw.Write(string.Format(""); if (this.name != null) - sw.Write(string.Format("{0}", this.name)); + sw.Write(string.Format("{0}", this.name)); if (this.fmtId != null) this.fmtId.Write(sw, "fmtId"); if (this.extLst != null) @@ -11819,8 +11795,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } private byte valField; @@ -11877,8 +11852,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } } @@ -11921,9 +11895,32 @@ public List ext [XmlRoot(Namespace = "http://schemas.openxmlformats.org/drawingml/2006/chart", IsNullable = true)] public class CT_Lvl { - private List ptField; + public static CT_Lvl Parse(XmlNode node, XmlNamespaceManager namespaceManager) + { + if (node == null) + return null; + CT_Lvl ctObj = new CT_Lvl(); + ctObj.pt = new List(); + foreach (XmlNode childNode in node.ChildNodes) + { + if (childNode.LocalName == "pt") + ctObj.pt.Add(CT_StrVal.Parse(childNode, namespaceManager)); + } + return ctObj; + } + + internal void Write(StreamWriter sw, string nodeName) + { + sw.Write(string.Format("", nodeName)); + foreach (CT_StrVal x in this.pt) + { + x.Write(sw, "pt"); + } + sw.Write(string.Format("", nodeName)); + } + public CT_Lvl() { //this.ptField = new List(); @@ -12011,9 +12008,37 @@ public List bandFmt [XmlRoot(Namespace = "http://schemas.openxmlformats.org/drawingml/2006/chart", IsNullable = true)] public class CT_PivotFmts { - private List pivotFmtField; + public static CT_PivotFmts Parse(XmlNode node, XmlNamespaceManager namespaceManager) + { + if (node == null) + return null; + CT_PivotFmts ctObj = new CT_PivotFmts(); + ctObj.pivotFmt = new List(); + foreach (XmlNode childNode in node.ChildNodes) + { + if (childNode.LocalName == "pivotFmt") + ctObj.pivotFmt.Add(CT_PivotFmt.Parse(childNode, namespaceManager)); + } + return ctObj; + } + + internal void Write(StreamWriter sw, string nodeName) + { + if (this.pivotFmt.Count == 0) + { + return; + } + + sw.Write(string.Format("", nodeName)); + foreach (CT_PivotFmt x in this.pivotFmt) + { + x.Write(sw, "pivotFmt"); + } + sw.Write(string.Format("", nodeName)); + } + public CT_PivotFmts() { //this.pivotFmtField = new List(); diff --git a/OpenXmlFormats/Drawing/ShapeGeometry.cs b/OpenXmlFormats/Drawing/ShapeGeometry.cs index eae05e7fa..29241fbba 100644 --- a/OpenXmlFormats/Drawing/ShapeGeometry.cs +++ b/OpenXmlFormats/Drawing/ShapeGeometry.cs @@ -928,15 +928,20 @@ internal static CT_GeomGuideList Parse(XmlNode node, XmlNamespaceManager namespa internal void Write(StreamWriter sw, string nodeName) { - sw.Write("", nodeName); - if (this.gdField != null) + sw.Write(""); + } + else { + sw.Write(">"); foreach (CT_GeomGuide gg in gdField) { gg.Write(sw, "gd"); } + sw.Write("", nodeName); } - sw.Write("", nodeName); } } diff --git a/OpenXmlFormats/Drawing/ShapeProperties.cs b/OpenXmlFormats/Drawing/ShapeProperties.cs index a5387ed27..bceb18202 100644 --- a/OpenXmlFormats/Drawing/ShapeProperties.cs +++ b/OpenXmlFormats/Drawing/ShapeProperties.cs @@ -1192,13 +1192,13 @@ public static CT_NonVisualGroupDrawingShapeProps Parse(XmlNode node, XmlNamespac internal void Write(StreamWriter sw, string nodeName) { - sw.Write(string.Format(""); if (this.grpSpLocks != null) this.grpSpLocks.Write(sw, "grpSpLocks"); if (this.extLst != null) this.extLst.Write(sw, "extLst"); - sw.Write(string.Format("", nodeName)); + sw.Write(string.Format("", nodeName)); } public CT_NonVisualGroupDrawingShapeProps() @@ -1377,10 +1377,17 @@ internal void Write(StreamWriter sw, string nodeName) XmlHelper.WriteAttribute(sw, "noChangeArrowheads", this.noChangeArrowheads, false); XmlHelper.WriteAttribute(sw, "noChangeShapeType", this.noChangeShapeType, false); XmlHelper.WriteAttribute(sw, "noTextEdit", this.noTextEdit, false); - sw.Write(">"); - if(this.extLst!=null) + + if (this.extLst == null) + { + sw.Write("/>"); + } + else + { + sw.Write(">"); this.extLst.Write(sw, "extLst"); - sw.Write(string.Format("", nodeName)); + sw.Write(string.Format("", nodeName)); + } } public CT_ShapeLocking() { @@ -1626,17 +1633,23 @@ public static CT_GroupLocking Parse(XmlNode node, XmlNamespaceManager namespaceM internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format(""); - if (this.extLst != null) - this.extLst.Write(sw, "extLst"); - sw.Write(string.Format("", nodeName)); + if(this.noGrp) + XmlHelper.WriteAttribute(sw, "noGrp", this.noGrp); + if(this.noUngrp) + XmlHelper.WriteAttribute(sw, "noUngrp", this.noUngrp); + if(this.noSelect) + XmlHelper.WriteAttribute(sw, "noSelect", this.noSelect); + if(this.noRot) + XmlHelper.WriteAttribute(sw, "noRot", this.noRot); + if(this.noChangeAspect) + XmlHelper.WriteAttribute(sw, "noChangeAspect", this.noChangeAspect); + if(this.noMove) + XmlHelper.WriteAttribute(sw, "noMove", this.noMove); + if(this.noResize) + XmlHelper.WriteAttribute(sw, "noResize", this.noResize); + sw.Write("/>"); + /*if (this.extLst != null) + this.extLst.Write(sw, "extLst");*/ } [XmlElement(Order = 0)] @@ -2198,7 +2211,7 @@ public static CT_GroupShapeProperties Parse(XmlNode node, XmlNamespaceManager na internal void Write(StreamWriter sw, string nodeName) { - sw.Write(string.Format(""); @@ -2224,7 +2237,7 @@ internal void Write(StreamWriter sw, string nodeName) this.scene3d.Write(sw, "scene3d"); if (this.extLst != null) this.extLst.Write(sw, "extLst"); - sw.Write(string.Format("", nodeName)); + sw.Write(string.Format("", nodeName)); } public CT_GroupShapeProperties() diff --git a/OpenXmlFormats/Drawing/SpreadsheetDrawing.cs b/OpenXmlFormats/Drawing/SpreadsheetDrawing.cs index d6b6ac89b..2ff68226c 100644 --- a/OpenXmlFormats/Drawing/SpreadsheetDrawing.cs +++ b/OpenXmlFormats/Drawing/SpreadsheetDrawing.cs @@ -7,6 +7,7 @@ using System.ComponentModel; using System.Text; using NPOI.OpenXml4Net.Util; +using NPOI.OpenXmlFormats.Vml; namespace NPOI.OpenXmlFormats.Dml.Spreadsheet { @@ -1270,8 +1271,7 @@ internal void Write(StreamWriter sw, string nodeName) sw.Write(string.Format(""); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } bool _fLocksWithSheet; bool _fPrintsWithSheet; @@ -1449,8 +1449,8 @@ public CT_Marker from get { return fromField; } set { fromField = value; } } - Vml.Spreadsheet.CT_AlternateContent alternateContentField = null; - public Vml.Spreadsheet.CT_AlternateContent alternateContent + CT_AlternateContent alternateContentField = null; + public CT_AlternateContent alternateContent { get { @@ -1563,7 +1563,7 @@ internal static CT_OneCellAnchor Parse(XmlNode node, XmlNamespaceManager namespa } else if (childNode.LocalName == "AlternateContent") { - oneCellAnchor.alternateContent = Vml.Spreadsheet.CT_AlternateContent.Parse(childNode, namespaceManager); + oneCellAnchor.alternateContent = CT_AlternateContent.Parse(childNode, namespaceManager); } else if (childNode.LocalName == "clientData") { @@ -1807,6 +1807,20 @@ public CT_Marker to set { toField = value; } } + private Vml.CT_AlternateContent alternateContentField = null; + + public Vml.CT_AlternateContent alternateContent + { + get + { + return alternateContentField; + } + set + { + this.alternateContentField = value; + } + } + #region Choice - one of CT_Shape, CT_GroupShape, CT_GraphicalObjectFrame, CT_Connector or CT_Picture [XmlElement] @@ -1863,6 +1877,10 @@ public void Write(StreamWriter sw) this.graphicalObjectField.Write(sw, "graphicFrame"); else if (this.pictureField != null) this.picture.Write(sw, "pic"); + if (this.alternateContent != null) + { + this.alternateContent.Write(sw, "AlternateContent"); + } if (this.clientData != null) { this.clientData.Write(sw, "clientData"); @@ -1906,6 +1924,10 @@ internal static CT_TwoCellAnchor Parse(XmlNode node, XmlNamespaceManager namespa { twoCellAnchor.graphicFrame = CT_GraphicalObjectFrame.Parse(childNode, namespaceManager); } + else if (childNode.LocalName == "AlternateContent") + { + twoCellAnchor.alternateContent = Vml.CT_AlternateContent.Parse(childNode, namespaceManager); + } else if (childNode.LocalName == "clientData") { twoCellAnchor.clientData = CT_AnchorClientData.Parse(childNode, namespaceManager); diff --git a/OpenXmlFormats/Drawing/spreadsheetShape.cs b/OpenXmlFormats/Drawing/spreadsheetShape.cs index 7636aa2a8..232e54b68 100644 --- a/OpenXmlFormats/Drawing/spreadsheetShape.cs +++ b/OpenXmlFormats/Drawing/spreadsheetShape.cs @@ -596,8 +596,14 @@ public class CT_GroupShape CT_GroupShapeProperties grpSpPrField; CT_GroupShapeNonVisual nvGrpSpPrField; CT_Connector connectorField = null; - CT_Picture pictureField = null; - CT_Shape shapeField = null; + List pictures = null; + List shapes = null; + + public CT_GroupShape() + { + this.pictures = new List(); + this.shapes = new List(); + } public void Set(CT_GroupShape groupShape) { @@ -622,13 +628,15 @@ public CT_Connector AddNewCxnSp() } public CT_Shape AddNewSp() { - shapeField = new CT_Shape(); + var shapeField = new CT_Shape(); + shapes.Add(shapeField); return shapeField; } public CT_Picture AddNewPic() { - pictureField = new CT_Picture(); - return pictureField; + var pic=new CT_Picture(); + pictures.Add(pic); + return pic; } public CT_GroupShapeNonVisual nvGrpSpPr @@ -653,6 +661,16 @@ public static CT_GroupShape Parse(XmlNode node, XmlNamespaceManager namespaceMan ctObj.nvGrpSpPr = CT_GroupShapeNonVisual.Parse(childNode, namespaceManager); else if (childNode.LocalName == "grpSpPr") ctObj.grpSpPr = CT_GroupShapeProperties.Parse(childNode, namespaceManager); + else if (childNode.LocalName == "pic") + { + var pic = CT_Picture.Parse(childNode, namespaceManager); + ctObj.pictures.Add(pic); + } + else if (childNode.LocalName == "sp") + { + var shape = CT_Shape.Parse(childNode, namespaceManager); + ctObj.shapes.Add(shape); + } } return ctObj; } @@ -664,9 +682,23 @@ internal void Write(StreamWriter sw, string nodeName) sw.Write(string.Format(""); if (this.nvGrpSpPr != null) - this.nvGrpSpPr.Write(sw, "nvGrpSpPr"); + this.nvGrpSpPr.Write(sw, "xdr:nvGrpSpPr"); if (this.grpSpPr != null) - this.grpSpPr.Write(sw, "grpSpPr"); + this.grpSpPr.Write(sw, "xdr:grpSpPr"); + if (this.shapes.Count > 0) + { + foreach (var shape in this.shapes) + { + shape.Write(sw, "sp"); + } + } + if (this.pictures.Count > 0) + { + foreach (var pic in this.pictures) + { + pic.Write(sw, "pic"); + } + } sw.Write(string.Format("", nodeName)); } @@ -697,13 +729,13 @@ public static CT_GroupShapeNonVisual Parse(XmlNode node, XmlNamespaceManager nam internal void Write(StreamWriter sw, string nodeName) { - sw.Write(string.Format(""); if (this.cNvPr != null) this.cNvPr.Write(sw, "cNvPr"); if (this.cNvGrpSpPr != null) - this.cNvGrpSpPr.Write(sw, "cNvGrpSpPr"); - sw.Write(string.Format("", nodeName)); + this.cNvGrpSpPr.Write(sw, "xdr:cNvGrpSpPr"); + sw.Write(string.Format("", nodeName)); } public CT_NonVisualGroupDrawingShapeProps AddNewCNvGrpSpPr() diff --git a/OpenXmlFormats/NPOI.OpenXmlFormats.Core.csproj b/OpenXmlFormats/NPOI.OpenXmlFormats.Core.csproj index d42848f4d..5b33678cb 100644 --- a/OpenXmlFormats/NPOI.OpenXmlFormats.Core.csproj +++ b/OpenXmlFormats/NPOI.OpenXmlFormats.Core.csproj @@ -22,6 +22,7 @@ + diff --git a/OpenXmlFormats/NPOI.OpenXmlFormats.csproj b/OpenXmlFormats/NPOI.OpenXmlFormats.csproj index a8b9271bb..907ea16c7 100644 --- a/OpenXmlFormats/NPOI.OpenXmlFormats.csproj +++ b/OpenXmlFormats/NPOI.OpenXmlFormats.csproj @@ -72,7 +72,7 @@ ..\solution\Lib\.net45\ TRACE;HIDE_UNREACHABLE_CODE true - 1591 + 1591;1587;1570 pdbonly AnyCPU 7.3 @@ -183,6 +183,7 @@ + @@ -291,11 +292,20 @@ + + {10fa8538-157a-4380-a4f6-8e2c3ee92cae} + NPOI + {c9f265b7-ece3-4755-b0b1-79536575c2a9} NPOI.OpenXml4Net + + + 4.0.0 + + diff --git a/OpenXmlFormats/Properties/AssemblyInfo.cs b/OpenXmlFormats/Properties/AssemblyInfo.cs index 790ca743f..a318a3782 100644 --- a/OpenXmlFormats/Properties/AssemblyInfo.cs +++ b/OpenXmlFormats/Properties/AssemblyInfo.cs @@ -33,8 +33,8 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("2.5.5.0")] -[assembly: AssemblyFileVersion("2.5.5.0")] +[assembly: AssemblyVersion("2.6.0.0")] +[assembly: AssemblyFileVersion("2.6.0.0")] [assembly: AssemblyInformationalVersion("2.0.0.0")] #if NETSTANDARD2_1 || NETSTANDARD2_0 || NET40 [assembly: AllowPartiallyTrustedCallers] diff --git a/OpenXmlFormats/Spreadsheet/AutoFilter.cs b/OpenXmlFormats/Spreadsheet/AutoFilter.cs index 5b61099e7..298141f0b 100644 --- a/OpenXmlFormats/Spreadsheet/AutoFilter.cs +++ b/OpenXmlFormats/Spreadsheet/AutoFilter.cs @@ -140,23 +140,14 @@ public class CT_FilterColumn private bool showButtonField; + private CT_CustomFilters customFiltersField; + public CT_FilterColumn() { this.hiddenButtonField = false; this.showButtonField = true; } - //[XmlAttribute] - //public object Item - //{ - // get - // { - // return this.itemField; - // } - // set - // { - // this.itemField = value; - // } - //} + [XmlAttribute] public uint colId { @@ -196,6 +187,19 @@ public bool showButton } } + [XmlAttribute] + public CT_CustomFilters customFilters + { + get + { + return this.customFiltersField; + } + set + { + this.customFiltersField = value; + } + } + public static CT_FilterColumn Parse(XmlNode node, XmlNamespaceManager namespaceManager) { if (node == null) @@ -204,12 +208,12 @@ public static CT_FilterColumn Parse(XmlNode node, XmlNamespaceManager namespaceM ctObj.colId = XmlHelper.ReadUInt(node.Attributes["colId"]); ctObj.hiddenButton = XmlHelper.ReadBool(node.Attributes["hiddenButton"]); ctObj.showButton = XmlHelper.ReadBool(node.Attributes["showButton"]); - //TODO: implement http://www.schemacentral.com/sc/ooxml/t-ssml_CT_FilterColumn.html - //foreach (XmlNode childNode in node.ChildNodes) - //{ - // if (childNode.LocalName == "Item") - // ctObj.Item = new Object(); - //} + + foreach (XmlNode childNode in node.ChildNodes) + { + if (childNode.LocalName == "customFilters") + ctObj.customFilters = CT_CustomFilters.Parse(childNode, namespaceManager); + } return ctObj; } @@ -219,10 +223,23 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "colId", this.colId, true); - XmlHelper.WriteAttribute(sw, "hiddenButton", this.hiddenButton); - XmlHelper.WriteAttribute(sw, "showButton", this.showButton); - sw.Write(">"); - sw.Write(string.Format("", nodeName)); + XmlHelper.WriteAttribute(sw, "hiddenButton", this.hiddenButton, false); + XmlHelper.WriteAttribute(sw, "showButton", this.showButton, false); + + if (this.customFilters == null || this.customFilters.customFilter.Count == 0) + { + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.customFilters != null && this.customFilters.customFilter.Count > 0) + { + if (this.customFilters != null) + this.customFilters.Write(sw, "customFilters"); + } + sw.Write(string.Format("", nodeName)); + } } } @@ -317,6 +334,46 @@ public bool and this.andField = value; } } + + public static CT_CustomFilters Parse(XmlNode node, XmlNamespaceManager namespaceManager) + { + if (node == null) + return null; + CT_CustomFilters ctObj = new CT_CustomFilters(); + if (node.Attributes["and"] != null) + ctObj.and = XmlHelper.ReadBool(node.Attributes["and"]); + + ctObj.customFilterField = new List(); + foreach (XmlNode childNode in node.ChildNodes) + { + if (childNode.LocalName == "customFilter") + ctObj.customFilter.Add(CT_CustomFilter.Parse(childNode, namespaceManager)); + } + return ctObj; + } + + internal void Write(StreamWriter sw, string nodeName) + { + sw.Write(string.Format("<{0}", nodeName)); + XmlHelper.WriteAttribute(sw, "and", this.and, false); + + if (this.customFilter == null || this.customFilter.Count == 0) + { + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.customFilter != null && this.customFilter.Count > 0) + { + foreach (CT_CustomFilter x in this.customFilter) + { + x.Write(sw, "customFilter"); + } + } + sw.Write(string.Format("", nodeName)); + } + } } public class CT_CustomFilter @@ -355,6 +412,27 @@ public string val this.valField = value; } } + + public static CT_CustomFilter Parse(XmlNode node, XmlNamespaceManager namespaceManager) + { + if (node == null) + return null; + CT_CustomFilter ctObj = new CT_CustomFilter(); + if (node.Attributes["operator"] != null + && Enum.TryParse(XmlHelper.ReadString(node.Attributes["operator"]), out ST_FilterOperator _operator)) + ctObj.@operator = _operator; + if (node.Attributes["val"] != null) + ctObj.val = XmlHelper.ReadString(node.Attributes["val"]); + return ctObj; + } + + internal void Write(StreamWriter sw, string nodeName) + { + sw.Write(string.Format("<{0}", nodeName)); + XmlHelper.WriteAttribute(sw, "operator", this.@operator.ToString(), true); + XmlHelper.WriteAttribute(sw, "val", this.val, true); + sw.Write("/>"); + } } public enum ST_FilterOperator @@ -900,73 +978,71 @@ public bool iconIdSpecified public enum ST_IconSetType { - - - [XmlEnum("3Arrows")] + [Description("3Arrows")] Item3Arrows, - [XmlEnum("3ArrowsGray")] + [Description("3ArrowsGray")] Item3ArrowsGray, - [XmlEnum("3Flags")] + [Description("3Flags")] Item3Flags, - [XmlEnum("3TrafficLights1")] + [Description("3TrafficLights1")] Item3TrafficLights1, - [XmlEnum("3TrafficLights2")] + [Description("3TrafficLights2")] Item3TrafficLights2, - [XmlEnum("3Signs")] + [Description("3Signs")] Item3Signs, - [XmlEnum("3Symbols")] + [Description("3Symbols")] Item3Symbols, - [XmlEnum("3Symbols2")] + [Description("3Symbols2")] Item3Symbols2, - [XmlEnum("4Arrows")] + [Description("4Arrows")] Item4Arrows, - [XmlEnum("4ArrowsGray")] + [Description("4ArrowsGray")] Item4ArrowsGray, - [XmlEnum("4RedToBlack")] + [Description("4RedToBlack")] Item4RedToBlack, - [XmlEnum("4Rating")] + [Description("4Rating")] Item4Rating, - [XmlEnum("4TrafficLights")] + [Description("4TrafficLights")] Item4TrafficLights, - [XmlEnum("5Arrows")] + [Description("5Arrows")] Item5Arrows, - [XmlEnum("5ArrowsGray")] + [Description("5ArrowsGray")] Item5ArrowsGray, - [XmlEnum("5Rating")] + [Description("5Rating")] Item5Rating, - [XmlEnum("5Quarters")] + [Description("5Quarters")] Item5Quarters, } diff --git a/OpenXmlFormats/Spreadsheet/BaseTypes.cs b/OpenXmlFormats/Spreadsheet/BaseTypes.cs index ebe7a34e3..97b874554 100644 --- a/OpenXmlFormats/Spreadsheet/BaseTypes.cs +++ b/OpenXmlFormats/Spreadsheet/BaseTypes.cs @@ -41,15 +41,29 @@ public byte[] ToBytes() public class CT_GradientStop { - private int positionField; + private double positionField; private CT_Color colorField; + public double position + { + get { + return positionField; + } + set { positionField = value; } + } + + public CT_Color AddNewColor() + { + this.colorField = new CT_Color(); + return colorField; + } + public static CT_GradientStop Parse(XmlNode node, XmlNamespaceManager namespaceManager) { if (node == null) return null; CT_GradientStop ctObj = new CT_GradientStop(); - ctObj.positionField = XmlHelper.ReadInt(node.Attributes["position"]); + ctObj.positionField = XmlHelper.ReadDouble(node.Attributes["position"]); foreach (XmlNode childNode in node.ChildNodes) { if (childNode.LocalName == "color") @@ -133,7 +147,22 @@ internal void Write(StreamWriter sw, string nodeName) } sw.Write(string.Format("", nodeName)); } - + public CT_GradientStop AddNewStop() + { + var newstop = new CT_GradientStop(); + if (this.stop == null) + this.stop = new List(); + this.stop.Add(newstop); + return newstop; + } + public CT_GradientStop GetStopArray(int index) + { + if (this.stop == null) + { + return null; + } + return this.stop[index]; + } [XmlElement] public List stop { diff --git a/OpenXmlFormats/Spreadsheet/Document/WorksheetDocument.cs b/OpenXmlFormats/Spreadsheet/Document/WorksheetDocument.cs index e5a9a1638..e6fe1b673 100644 --- a/OpenXmlFormats/Spreadsheet/Document/WorksheetDocument.cs +++ b/OpenXmlFormats/Spreadsheet/Document/WorksheetDocument.cs @@ -29,9 +29,9 @@ public void SetChartsheet(CT_Worksheet sheet) { this.sheet = sheet; } - public void Save(Stream stream) + public void Save(Stream stream, bool leaveOpen) { - this.sheet.Write(stream); + this.sheet.Write(stream, leaveOpen); } } } diff --git a/OpenXmlFormats/Spreadsheet/PivotTable/CT_PivotCacheDefinition.cs b/OpenXmlFormats/Spreadsheet/PivotTable/CT_PivotCacheDefinition.cs index 0798c8948..3091e1d14 100644 --- a/OpenXmlFormats/Spreadsheet/PivotTable/CT_PivotCacheDefinition.cs +++ b/OpenXmlFormats/Spreadsheet/PivotTable/CT_PivotCacheDefinition.cs @@ -89,6 +89,9 @@ internal void Write(StreamWriter sw) sw.Write(""); - if (this.page != null) + + if (this.page == null || this.page.Count == 0) { - foreach (CT_PCDSCPage x in this.page) + sw.Write("/>"); + } + else + { + sw.Write(">"); + + if (this.page != null && this.page.Count > 0) { - x.Write(sw, "page"); + foreach (CT_PCDSCPage x in this.page) + { + x.Write(sw, "page"); + } } + + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List pageField; @@ -827,15 +840,25 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.pageItem != null) + + if (this.pageItem == null || this.pageItem.Count == 0) + { + sw.Write("/>"); + } + else { - foreach (CT_PageItem x in this.pageItem) + sw.Write(">"); + + if (this.pageItem != null && this.pageItem.Count > 0) { - x.Write(sw, "pageItem"); + foreach (CT_PageItem x in this.pageItem) + { + x.Write(sw, "pageItem"); + } } + + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List pageItemField; @@ -911,8 +934,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "name", this.name); - sw.Write(">"); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } private string nameField; @@ -960,15 +982,25 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.rangeSet != null) + + if (this.rangeSet == null || this.rangeSet.Count == 0) { - foreach (CT_RangeSet x in this.rangeSet) + sw.Write("/>"); + } + else + { + sw.Write(">"); + + if (this.rangeSet != null && this.rangeSet.Count > 0) { - x.Write(sw, "rangeSet"); + foreach (CT_RangeSet x in this.rangeSet) + { + x.Write(sw, "rangeSet"); + } } + + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List rangeSetField; @@ -1062,8 +1094,7 @@ internal void Write(StreamWriter sw, string nodeName) XmlHelper.WriteAttribute(sw, "name", this.name); XmlHelper.WriteAttribute(sw, "sheet", this.sheet); XmlHelper.WriteAttribute(sw, "r:id", this.id); - sw.Write(">"); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } private uint i1Field; @@ -1276,12 +1307,20 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "autoPage", this.autoPage); - sw.Write(">"); - if (this.pages != null) - this.pages.Write(sw, "pages"); - if (this.rangeSets != null) - this.rangeSets.Write(sw, "rangeSets"); - sw.Write(string.Format("", nodeName)); + + if (this.pages == null && this.rangeSets == null) + { + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.pages != null) + this.pages.Write(sw, "pages"); + if (this.rangeSets != null) + this.rangeSets.Write(sw, "rangeSets"); + sw.Write(string.Format("", nodeName)); + } } private CT_Pages pagesField; @@ -1366,8 +1405,7 @@ internal void Write(StreamWriter sw, string nodeName) XmlHelper.WriteAttribute(sw, "name", this.name); XmlHelper.WriteAttribute(sw, "sheet", this.sheet); XmlHelper.WriteAttribute(sw, "r:id", this.id); - sw.Write(">"); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } private string refField; @@ -1486,18 +1524,24 @@ internal void Write(StreamWriter sw, string nodeName) sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "type", this.type.ToString()); XmlHelper.WriteAttribute(sw, "connectionId", this.connectionId); - sw.Write(">"); - if (this.worksheetSource != null) - this.worksheetSource.Write(sw, "worksheetSource"); - if (this.consolidation != null) - this.consolidation.Write(sw, "consolidation"); - if (this.extLst != null) - this.extLst.Write(sw, "extLst"); - sw.Write(string.Format("", nodeName)); + if (this.worksheetSource == null && this.consolidation == null && this.extLst == null) + { + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.worksheetSource != null) + this.worksheetSource.Write(sw, "worksheetSource"); + if (this.consolidation != null) + this.consolidation.Write(sw, "consolidation"); + if (this.extLst != null) + this.extLst.Write(sw, "extLst"); + sw.Write(string.Format("", nodeName)); + } } - private object itemField; private ST_SourceType typeField; @@ -1628,15 +1672,26 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.cacheField != null) + + if (this.cacheField == null || this.cacheField.Count == 0) { - foreach (CT_CacheField x in this.cacheField) + sw.Write("/>"); + } + else + { + sw.Write(">"); + + if (this.cacheField != null && this.cacheField.Count > 0) { - x.Write(sw, "cacheField"); + + foreach (CT_CacheField x in this.cacheField) + { + x.Write(sw, "cacheField"); + } } + + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List cacheFieldField; @@ -1785,39 +1840,62 @@ public static CT_SharedItems Parse(XmlNode node, XmlNamespaceManager namespaceMa internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - XmlHelper.WriteAttribute(sw, "containsSemiMixedTypes", this.containsSemiMixedTypes); - XmlHelper.WriteAttribute(sw, "containsNonDate", this.containsNonDate); - XmlHelper.WriteAttribute(sw, "containsDate", this.containsDate); - XmlHelper.WriteAttribute(sw, "containsString", this.containsString); - XmlHelper.WriteAttribute(sw, "containsBlank", this.containsBlank); - XmlHelper.WriteAttribute(sw, "containsMixedTypes", this.containsMixedTypes); - XmlHelper.WriteAttribute(sw, "containsNumber", this.containsNumber); - XmlHelper.WriteAttribute(sw, "containsInteger", this.containsInteger); - XmlHelper.WriteAttribute(sw, "minValue", this.minValue); - XmlHelper.WriteAttribute(sw, "maxValue", this.maxValue); + if (!this.containsSemiMixedTypes) + XmlHelper.WriteAttribute(sw, "containsSemiMixedTypes", this.containsSemiMixedTypes); + if (!this.containsNonDate) + XmlHelper.WriteAttribute(sw, "containsNonDate", this.containsNonDate); + XmlHelper.WriteAttribute(sw, "containsDate", this.containsDate, false); + if (!this.containsString) + XmlHelper.WriteAttribute(sw, "containsString", this.containsString); + XmlHelper.WriteAttribute(sw, "containsBlank", this.containsBlank, false); + XmlHelper.WriteAttribute(sw, "containsMixedTypes", this.containsMixedTypes, false); + XmlHelper.WriteAttribute(sw, "containsNumber", this.containsNumber, false); + XmlHelper.WriteAttribute(sw, "containsInteger", this.containsInteger, false); + if (this.containsNumber) + { + XmlHelper.WriteAttribute(sw, "minValue", this.minValue, true); + XmlHelper.WriteAttribute(sw, "maxValue", this.maxValue, true); + } + else + { + XmlHelper.WriteAttribute(sw, "minValue", this.minValue); + XmlHelper.WriteAttribute(sw, "maxValue", this.maxValue); + } + XmlHelper.WriteAttribute(sw, "minDate", this.minDate); XmlHelper.WriteAttribute(sw, "maxDate", this.maxDate); XmlHelper.WriteAttribute(sw, "count", this.count); - XmlHelper.WriteAttribute(sw, "longText", this.longText); - sw.Write(">"); + XmlHelper.WriteAttribute(sw, "longText", this.longText, false); - foreach (object o in this.Items) + if (this.Items == null || this.Items.Count == 0) { - if (o is CT_Number) - ((CT_Number)o).Write(sw, "n"); - else if (o is CT_Boolean) - ((CT_Boolean)o).Write(sw, "b"); - else if (o is CT_DateTime) - ((CT_DateTime)o).Write(sw, "d"); - else if (o is CT_Error) - ((CT_Error)o).Write(sw, "e"); - else if (o is CT_Missing) - ((CT_Missing)o).Write(sw, "m"); - else if (o is CT_String) - ((CT_String)o).Write(sw, "s"); + sw.Write("/>"); } + else + { + sw.Write(">"); - sw.Write(string.Format("", nodeName)); + if (this.Items != null && this.Items.Count > 0) + { + foreach (object o in this.Items) + { + if (o is CT_Number) + ((CT_Number)o).Write(sw, "n"); + else if (o is CT_Boolean) + ((CT_Boolean)o).Write(sw, "b"); + else if (o is CT_DateTime) + ((CT_DateTime)o).Write(sw, "d"); + else if (o is CT_Error) + ((CT_Error)o).Write(sw, "e"); + else if (o is CT_Missing) + ((CT_Missing)o).Write(sw, "m"); + else if (o is CT_String) + ((CT_String)o).Write(sw, "s"); + } + } + + sw.Write(string.Format("", nodeName)); + } } private List itemsField; @@ -2206,31 +2284,44 @@ internal void Write(StreamWriter sw, string nodeName) XmlHelper.WriteAttribute(sw, "name", this.name); XmlHelper.WriteAttribute(sw, "caption", this.caption); XmlHelper.WriteAttribute(sw, "propertyName", this.propertyName); - XmlHelper.WriteAttribute(sw, "serverField", this.serverField); - XmlHelper.WriteAttribute(sw, "uniqueList", this.uniqueList); - XmlHelper.WriteAttribute(sw, "numFmtId", this.numFmtId); + XmlHelper.WriteAttribute(sw, "serverField", this.serverField, false); + if (!this.uniqueList) + XmlHelper.WriteAttribute(sw, "uniqueList", this.uniqueList); + XmlHelper.WriteAttribute(sw, "numFmtId", this.numFmtId, true); XmlHelper.WriteAttribute(sw, "formula", this.formula); XmlHelper.WriteAttribute(sw, "sqlType", this.sqlType); XmlHelper.WriteAttribute(sw, "hierarchy", this.hierarchy); XmlHelper.WriteAttribute(sw, "level", this.level); - XmlHelper.WriteAttribute(sw, "databaseField", this.databaseField); + if (!this.databaseField) + XmlHelper.WriteAttribute(sw, "databaseField", this.databaseField); XmlHelper.WriteAttribute(sw, "mappingCount", this.mappingCount); - XmlHelper.WriteAttribute(sw, "memberPropertyField", this.memberPropertyField); - sw.Write(">"); - if (this.sharedItems != null) - this.sharedItems.Write(sw, "sharedItems"); - if (this.fieldGroup != null) - this.fieldGroup.Write(sw, "fieldGroup"); - if (this.extLst != null) - this.extLst.Write(sw, "extLst"); - if (this.mpMap != null) + XmlHelper.WriteAttribute(sw, "memberPropertyField", this.memberPropertyField, false); + + if (this.sharedItems == null + && this.fieldGroup == null + && this.extLst == null + && (this.mpMap == null || this.mpMap.Count == 0)) { - foreach (CT_X x in this.mpMap) + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.sharedItems != null) + this.sharedItems.Write(sw, "sharedItems"); + if (this.fieldGroup != null) + this.fieldGroup.Write(sw, "fieldGroup"); + if (this.extLst != null) + this.extLst.Write(sw, "extLst"); + if (this.mpMap != null && this.mpMap.Count > 0) { - x.Write(sw, "mpMap"); + foreach (CT_X x in this.mpMap) + { + x.Write(sw, "mpMap"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private CT_SharedItems sharedItemsField; @@ -2273,10 +2364,10 @@ internal void Write(StreamWriter sw, string nodeName) public CT_CacheField() { - this.extLstField = new CT_ExtensionList(); + //this.extLstField = new CT_ExtensionList(); this.mpMapField = new List(); - this.fieldGroupField = new CT_FieldGroup(); - this.sharedItemsField = new CT_SharedItems(); + //this.fieldGroupField = new CT_FieldGroup(); + //this.sharedItemsField = new CT_SharedItems(); this.serverFieldField = false; this.uniqueListField = true; this.sqlTypeField = 0; @@ -2299,7 +2390,7 @@ public CT_SharedItems sharedItems } } - [XmlElement(Order = 1)] + [XmlElement(Order = 1, IsNullable = true)] public CT_FieldGroup fieldGroup { get @@ -2325,7 +2416,7 @@ public List mpMap } } - [XmlElement(Order = 3)] + [XmlElement(Order = 3, IsNullable = true)] public CT_ExtensionList extLst { get @@ -2576,15 +2667,23 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.cacheHierarchy != null) + + if (this.cacheHierarchy == null || this.cacheHierarchy.Count == 0) { - foreach (CT_CacheHierarchy x in this.cacheHierarchy) + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.cacheHierarchy != null && this.cacheHierarchy.Count > 0) { - x.Write(sw, "cacheHierarchy"); + foreach (CT_CacheHierarchy x in this.cacheHierarchy) + { + x.Write(sw, "cacheHierarchy"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List cacheHierarchyField; @@ -2673,20 +2772,28 @@ public static CT_Boolean Parse(XmlNode node, XmlNamespaceManager namespaceManage internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - XmlHelper.WriteAttribute(sw, "v", this.v); - XmlHelper.WriteAttribute(sw, "u", this.u); - XmlHelper.WriteAttribute(sw, "f", this.f); - XmlHelper.WriteAttribute(sw, "c", this.c); - XmlHelper.WriteAttribute(sw, "cp", this.cp); - sw.Write(">"); - if (this.x != null) + XmlHelper.WriteAttribute(sw, "v", this.v, true); + XmlHelper.WriteAttribute(sw, "u", this.u, false); + XmlHelper.WriteAttribute(sw, "f", this.f, false); + XmlHelper.WriteAttribute(sw, "c", this.c, false); + XmlHelper.WriteAttribute(sw, "cp", this.cp, false); + + if (this.x == null || this.x.Count == 0) + { + sw.Write("/>"); + } + else { - foreach (CT_X x in this.x) + sw.Write(">"); + if (this.x != null && this.x.Count > 0) { - x.Write(sw, "x"); + foreach (CT_X x in this.x) + { + x.Write(sw, "x"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List xField; @@ -2874,11 +2981,9 @@ public static CT_X Parse(XmlNode node, XmlNamespaceManager namespaceManager) internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - XmlHelper.WriteAttribute(sw, "v", this.v); - sw.Write(">"); - sw.Write(string.Format("", nodeName)); + XmlHelper.WriteAttribute(sw, "v", this.v, false); + sw.Write("/>"); } - } @@ -2917,19 +3022,27 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "v", this.v); - XmlHelper.WriteAttribute(sw, "u", this.u); - XmlHelper.WriteAttribute(sw, "f", this.f); - XmlHelper.WriteAttribute(sw, "c", this.c); - XmlHelper.WriteAttribute(sw, "cp", this.cp); - sw.Write(">"); - if (this.x != null) + XmlHelper.WriteAttribute(sw, "u", this.u, false); + XmlHelper.WriteAttribute(sw, "f", this.f, false); + XmlHelper.WriteAttribute(sw, "c", this.c, false); + XmlHelper.WriteAttribute(sw, "cp", this.cp, false); + + if (this.x == null || this.x.Count == 0) + { + sw.Write("/>"); + } + else { - foreach (CT_X x in this.x) + sw.Write(">"); + if (this.x != null && this.x.Count > 0) { - x.Write(sw, "x"); + foreach (CT_X x in this.x) + { + x.Write(sw, "x"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List xField; @@ -3406,31 +3519,38 @@ public static CT_Error Parse(XmlNode node, XmlNamespaceManager namespaceManager) internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - XmlHelper.WriteAttribute(sw, "v", this.v); - XmlHelper.WriteAttribute(sw, "u", this.u); - XmlHelper.WriteAttribute(sw, "f", this.f); - XmlHelper.WriteAttribute(sw, "c", this.c); - XmlHelper.WriteAttribute(sw, "cp", this.cp); - XmlHelper.WriteAttribute(sw, "in", this.@in); + XmlHelper.WriteAttribute(sw, "v", this.v, true); + XmlHelper.WriteAttribute(sw, "u", this.u, false); + XmlHelper.WriteAttribute(sw, "f", this.f, false); + XmlHelper.WriteAttribute(sw, "c", this.c, false); + XmlHelper.WriteAttribute(sw, "cp", this.cp, false); + XmlHelper.WriteAttribute(sw, "in", this.@in, false); XmlHelper.WriteAttribute(sw, "bc", this.bc); XmlHelper.WriteAttribute(sw, "fc", this.fc); - XmlHelper.WriteAttribute(sw, "i", this.i); - XmlHelper.WriteAttribute(sw, "un", this.un); - XmlHelper.WriteAttribute(sw, "st", this.st); - XmlHelper.WriteAttribute(sw, "b", this.b); - sw.Write(">"); - if (this.tpls != null) - this.tpls.Write(sw, "tpls"); - if (this.x != null) + XmlHelper.WriteAttribute(sw, "i", this.i, false); + XmlHelper.WriteAttribute(sw, "un", this.un, false); + XmlHelper.WriteAttribute(sw, "st", this.st, false); + XmlHelper.WriteAttribute(sw, "b", this.b, false); + + if ((this.tpls == null || this.tpls.tpl.Count == 0) && (this.x == null || this.x.Count == 0)) { - foreach (CT_X x in this.x) + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.tpls != null) + this.tpls.Write(sw, "tpls"); + if (this.x != null && this.x.Count > 0) { - x.Write(sw, "x"); + foreach (CT_X x in this.x) + { + x.Write(sw, "x"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } - } @@ -3513,15 +3633,23 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "c", this.c); - sw.Write(">"); - if (this.tpl != null) + + if (this.tpl == null || this.tpl.Count == 0) + { + sw.Write("/>"); + } + else { - foreach (CT_Tuple x in this.tpl) + sw.Write(">"); + if (this.tpl != null && this.tpl.Count > 0) { - x.Write(sw, "tpl"); + foreach (CT_Tuple x in this.tpl) + { + x.Write(sw, "tpl"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } } @@ -3631,8 +3759,7 @@ internal void Write(StreamWriter sw, string nodeName) XmlHelper.WriteAttribute(sw, "fld", this.fld); XmlHelper.WriteAttribute(sw, "hier", this.hier); XmlHelper.WriteAttribute(sw, "item", this.item); - sw.Write(">"); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } } @@ -3955,33 +4082,41 @@ public static CT_Missing Parse(XmlNode node, XmlNamespaceManager namespaceManage internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - XmlHelper.WriteAttribute(sw, "u", this.u); - XmlHelper.WriteAttribute(sw, "f", this.f); - XmlHelper.WriteAttribute(sw, "c", this.c); - XmlHelper.WriteAttribute(sw, "cp", this.cp); - XmlHelper.WriteAttribute(sw, "in", this.@in); + XmlHelper.WriteAttribute(sw, "u", this.u, false); + XmlHelper.WriteAttribute(sw, "f", this.f, false); + XmlHelper.WriteAttribute(sw, "c", this.c, false); + XmlHelper.WriteAttribute(sw, "cp", this.cp, false); + XmlHelper.WriteAttribute(sw, "in", this.@in, false); XmlHelper.WriteAttribute(sw, "bc", this.bc); XmlHelper.WriteAttribute(sw, "fc", this.fc); - XmlHelper.WriteAttribute(sw, "i", this.i); - XmlHelper.WriteAttribute(sw, "un", this.un); - XmlHelper.WriteAttribute(sw, "st", this.st); - XmlHelper.WriteAttribute(sw, "b", this.b); - sw.Write(">"); - if (this.tpls != null) + XmlHelper.WriteAttribute(sw, "i", this.i, false); + XmlHelper.WriteAttribute(sw, "un", this.un, false); + XmlHelper.WriteAttribute(sw, "st", this.st, false); + XmlHelper.WriteAttribute(sw, "b", this.b, false); + + if ((this.tpls == null || this.tpls.Count == 0) && (this.x == null || this.x.Count == 0)) { - foreach (CT_Tuples x in this.tpls) - { - x.Write(sw, "tpls"); - } + sw.Write("/>"); } - if (this.x != null) + else { - foreach (CT_X x in this.x) + sw.Write(">"); + if (this.tpls != null && this.tpls.Count > 0) + { + foreach (CT_Tuples x in this.tpls) + { + x.Write(sw, "tpls"); + } + } + if (this.x != null && this.x.Count > 0) { - x.Write(sw, "x"); + foreach (CT_X x in this.x) + { + x.Write(sw, "x"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } } @@ -4316,46 +4451,48 @@ public static CT_Number Parse(XmlNode node, XmlNamespaceManager namespaceManager return ctObj; } - - internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - XmlHelper.WriteAttribute(sw, "v", this.v); - XmlHelper.WriteAttribute(sw, "u", this.u); - XmlHelper.WriteAttribute(sw, "f", this.f); - XmlHelper.WriteAttribute(sw, "c", this.c); - XmlHelper.WriteAttribute(sw, "cp", this.cp); - XmlHelper.WriteAttribute(sw, "in", this.@in); + XmlHelper.WriteAttribute(sw, "v", this.v, true); + XmlHelper.WriteAttribute(sw, "u", this.u, false); + XmlHelper.WriteAttribute(sw, "f", this.f, false); + XmlHelper.WriteAttribute(sw, "c", this.c, false); + XmlHelper.WriteAttribute(sw, "cp", this.cp, false); + XmlHelper.WriteAttribute(sw, "in", this.@in, false); XmlHelper.WriteAttribute(sw, "bc", this.bc); XmlHelper.WriteAttribute(sw, "fc", this.fc); - XmlHelper.WriteAttribute(sw, "i", this.i); - XmlHelper.WriteAttribute(sw, "un", this.un); - XmlHelper.WriteAttribute(sw, "st", this.st); - XmlHelper.WriteAttribute(sw, "b", this.b); - sw.Write(">"); - if (this.tpls != null) + XmlHelper.WriteAttribute(sw, "i", this.i, false); + XmlHelper.WriteAttribute(sw, "un", this.un, false); + XmlHelper.WriteAttribute(sw, "st", this.st, false); + XmlHelper.WriteAttribute(sw, "b", this.b, false); + + if ((this.tpls == null || this.tpls.Count == 0) && (this.x == null || this.x.Count == 0)) { - foreach (CT_Tuples x in this.tpls) - { - x.Write(sw, "tpls"); - } + sw.Write("/>"); } - if (this.x != null) + else { - foreach (CT_X x in this.x) + sw.Write(">"); + if (this.tpls != null && this.tpls.Count > 0) { - x.Write(sw, "x"); + foreach (CT_Tuples x in this.tpls) + { + x.Write(sw, "tpls"); + } } + if (this.x != null && this.x.Count > 0) + { + foreach (CT_X x in this.x) + { + x.Write(sw, "x"); + } + } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } - } - - - [XmlType(Namespace = "http://schemas.openxmlformats.org/spreadsheetml/2006/main")] [XmlRoot(Namespace = "http://schemas.openxmlformats.org/spreadsheetml/2006/main", IsNullable = true)] public partial class CT_String @@ -4687,34 +4824,42 @@ public static CT_String Parse(XmlNode node, XmlNamespaceManager namespaceManager internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - XmlHelper.WriteAttribute(sw, "v", this.v); - XmlHelper.WriteAttribute(sw, "u", this.u); - XmlHelper.WriteAttribute(sw, "f", this.f); - XmlHelper.WriteAttribute(sw, "c", this.c); - XmlHelper.WriteAttribute(sw, "cp", this.cp); - XmlHelper.WriteAttribute(sw, "in", this.@in); + XmlHelper.WriteAttribute(sw, "v", this.v, true); + XmlHelper.WriteAttribute(sw, "u", this.u, false); + XmlHelper.WriteAttribute(sw, "f", this.f, false); + XmlHelper.WriteAttribute(sw, "c", this.c, false); + XmlHelper.WriteAttribute(sw, "cp", this.cp, false); + XmlHelper.WriteAttribute(sw, "in", this.@in, false); XmlHelper.WriteAttribute(sw, "bc", this.bc); XmlHelper.WriteAttribute(sw, "fc", this.fc); - XmlHelper.WriteAttribute(sw, "i", this.i); - XmlHelper.WriteAttribute(sw, "un", this.un); - XmlHelper.WriteAttribute(sw, "st", this.st); - XmlHelper.WriteAttribute(sw, "b", this.b); - sw.Write(">"); - if (this.tpls != null) + XmlHelper.WriteAttribute(sw, "i", this.i, false); + XmlHelper.WriteAttribute(sw, "un", this.un, false); + XmlHelper.WriteAttribute(sw, "st", this.st, false); + XmlHelper.WriteAttribute(sw, "b", this.b, false); + + if ((this.tpls == null || this.tpls.Count == 0) && (this.x == null || this.x.Count == 0)) { - foreach (CT_Tuples x in this.tpls) - { - x.Write(sw, "tpls"); - } + sw.Write("/>"); } - if (this.x != null) + else { - foreach (CT_X x in this.x) + sw.Write(">"); + if (this.tpls != null && this.tpls.Count > 0) + { + foreach (CT_Tuples x in this.tpls) + { + x.Write(sw, "tpls"); + } + } + if (this.x != null && this.x.Count > 0) { - x.Write(sw, "x"); + foreach (CT_X x in this.x) + { + x.Write(sw, "x"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } } @@ -4754,14 +4899,22 @@ internal void Write(StreamWriter sw, string nodeName) sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "par", this.par); XmlHelper.WriteAttribute(sw, "base", this.@base); - sw.Write(">"); - if (this.rangePr != null) - this.rangePr.Write(sw, "rangePr"); - if (this.discretePr != null) - this.discretePr.Write(sw, "discretePr"); - if (this.groupItems != null) - this.groupItems.Write(sw, "groupItems"); - sw.Write(string.Format("", nodeName)); + + if (this.rangePr == null && this.discretePr == null && this.groupItems == null) + { + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.rangePr != null) + this.rangePr.Write(sw, "rangePr"); + if (this.discretePr != null) + this.discretePr.Write(sw, "discretePr"); + if (this.groupItems != null) + this.groupItems.Write(sw, "groupItems"); + sw.Write(string.Format("", nodeName)); + } } private CT_RangePr rangePrField; @@ -4921,8 +5074,7 @@ internal void Write(StreamWriter sw, string nodeName) XmlHelper.WriteAttribute(sw, "startDate", this.startDate); XmlHelper.WriteAttribute(sw, "endDate", this.endDate); XmlHelper.WriteAttribute(sw, "groupInterval", this.groupInterval); - sw.Write(">"); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } private bool autoStartField; @@ -5179,15 +5331,23 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.x != null) + + if (this.x == null || this.x.Count == 0) + { + sw.Write("/>"); + } + else { - foreach (CT_Index x in this.x) + sw.Write(">"); + if (this.x != null && this.x.Count > 0) { - x.Write(sw, "x"); + foreach (CT_Index x in this.x) + { + x.Write(sw, "x"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List xField; @@ -5292,23 +5452,30 @@ public static CT_GroupItems Parse(XmlNode node, XmlNamespaceManager namespaceMan internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - sw.Write(">"); - foreach (object o in this.Items) + if (this.Items == null || this.Items.Count == 0) + { + sw.Write("/>"); + } + else { - if (o is CT_Error) - ((CT_Error)o).Write(sw, "e"); - else if (o is CT_Boolean) - ((CT_Boolean)o).Write(sw, "b"); - else if (o is CT_DateTime) - ((CT_DateTime)o).Write(sw, "d"); - else if (o is CT_Number) - ((CT_Number)o).Write(sw, "n"); - else if (o is CT_Missing) - ((CT_Missing)o).Write(sw, "m"); - else if (o is CT_String) - ((CT_String)o).Write(sw, "s"); + sw.Write(">"); + foreach (object o in this.Items) + { + if (o is CT_Error) + ((CT_Error)o).Write(sw, "e"); + else if (o is CT_Boolean) + ((CT_Boolean)o).Write(sw, "b"); + else if (o is CT_DateTime) + ((CT_DateTime)o).Write(sw, "d"); + else if (o is CT_Number) + ((CT_Number)o).Write(sw, "n"); + else if (o is CT_Missing) + ((CT_Missing)o).Write(sw, "m"); + else if (o is CT_String) + ((CT_String)o).Write(sw, "s"); + } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List itemsField; @@ -5396,15 +5563,23 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.fieldUsage != null) + + if (this.fieldUsage == null || this.fieldUsage.Count == 0) + { + sw.Write("/>"); + } + else { - foreach (CT_FieldUsage x in this.fieldUsage) + sw.Write(">"); + if (this.fieldUsage != null && this.fieldUsage.Count > 0) { - x.Write(sw, "fieldUsage"); + foreach (CT_FieldUsage x in this.fieldUsage) + { + x.Write(sw, "fieldUsage"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List fieldUsageField; @@ -5480,9 +5655,8 @@ public static CT_FieldUsage Parse(XmlNode node, XmlNamespaceManager namespaceMan internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - XmlHelper.WriteAttribute(sw, "x", this.x); - sw.Write(">"); - sw.Write(string.Format("", nodeName)); + XmlHelper.WriteAttribute(sw, "x", this.x, true); + sw.Write("/>"); } private int xField; @@ -5530,15 +5704,23 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.groupLevel != null) + + if (this.groupLevel == null || this.groupLevel.Count == 0) { - foreach (CT_GroupLevel x in this.groupLevel) + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.groupLevel != null && this.groupLevel.Count > 0) { - x.Write(sw, "groupLevel"); + foreach (CT_GroupLevel x in this.groupLevel) + { + x.Write(sw, "groupLevel"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List groupLevelField; @@ -5629,12 +5811,20 @@ internal void Write(StreamWriter sw, string nodeName) XmlHelper.WriteAttribute(sw, "caption", this.caption); XmlHelper.WriteAttribute(sw, "user", this.user); XmlHelper.WriteAttribute(sw, "customRollUp", this.customRollUp); - sw.Write(">"); - if (this.groups != null) - this.groups.Write(sw, "groups"); - if (this.extLst != null) - this.extLst.Write(sw, "extLst"); - sw.Write(string.Format("", nodeName)); + + if (this.groups == null && this.extLst == null) + { + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.groups != null) + this.groups.Write(sw, "groups"); + if (this.extLst != null) + this.extLst.Write(sw, "extLst"); + sw.Write(string.Format("", nodeName)); + } } private CT_Groups groupsField; @@ -5767,15 +5957,23 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.group != null) + + if (this.group == null || this.group.Count == 0) { - foreach (CT_LevelGroup x in this.group) + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.group != null && this.group.Count > 0) { - x.Write(sw, "group"); + foreach (CT_LevelGroup x in this.group) + { + x.Write(sw, "group"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List groupField; @@ -5865,10 +6063,18 @@ internal void Write(StreamWriter sw, string nodeName) XmlHelper.WriteAttribute(sw, "caption", this.caption); XmlHelper.WriteAttribute(sw, "uniqueParent", this.uniqueParent); XmlHelper.WriteAttribute(sw, "id", this.id); - sw.Write(">"); - if (this.groupMembers != null) - this.groupMembers.Write(sw, "groupMembers"); - sw.Write(string.Format("", nodeName)); + + if (this.groupMembers == null) + { + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.groupMembers != null) + this.groupMembers.Write(sw, "groupMembers"); + sw.Write(string.Format("", nodeName)); + } } private CT_GroupMembers groupMembersField; @@ -6011,15 +6217,23 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.groupMember != null) + + if (this.groupMember == null || this.groupMember.Count == 0) + { + sw.Write("/>"); + } + else { - foreach (CT_GroupMember x in this.groupMember) + sw.Write(">"); + if (this.groupMember != null && this.groupMember.Count > 0) { - x.Write(sw, "groupMember"); + foreach (CT_GroupMember x in this.groupMember) + { + x.Write(sw, "groupMember"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List groupMemberField; @@ -6098,8 +6312,7 @@ internal void Write(StreamWriter sw, string nodeName) sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "uniqueName", this.uniqueName); XmlHelper.WriteAttribute(sw, "group", this.group); - sw.Write(">"); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } private string uniqueNameField; @@ -6205,7 +6418,7 @@ public static CT_CacheHierarchy Parse(XmlNode node, XmlNamespaceManager namespac internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - XmlHelper.WriteAttribute(sw, "uniqueName", this.uniqueName); + XmlHelper.WriteAttribute(sw, "uniqueName", this.uniqueName, true); XmlHelper.WriteAttribute(sw, "caption", this.caption); XmlHelper.WriteAttribute(sw, "measure", this.measure); XmlHelper.WriteAttribute(sw, "set", this.set); @@ -6221,20 +6434,28 @@ internal void Write(StreamWriter sw, string nodeName) XmlHelper.WriteAttribute(sw, "displayFolder", this.displayFolder); XmlHelper.WriteAttribute(sw, "measureGroup", this.measureGroup); XmlHelper.WriteAttribute(sw, "measures", this.measures); - XmlHelper.WriteAttribute(sw, "count", this.count); + XmlHelper.WriteAttribute(sw, "count", this.count, true); XmlHelper.WriteAttribute(sw, "oneField", this.oneField); XmlHelper.WriteAttribute(sw, "memberValueDatatype", this.memberValueDatatype); XmlHelper.WriteAttribute(sw, "unbalanced", this.unbalanced); XmlHelper.WriteAttribute(sw, "unbalancedGroup", this.unbalancedGroup); XmlHelper.WriteAttribute(sw, "hidden", this.hidden); - sw.Write(">"); - if (this.fieldsUsage != null) - this.fieldsUsage.Write(sw, "fieldsUsage"); - if (this.groupLevels != null) - this.groupLevels.Write(sw, "groupLevels"); - if (this.extLst != null) - this.extLst.Write(sw, "extLst"); - sw.Write(string.Format("", nodeName)); + + if (this.fieldsUsage == null && this.groupLevels == null && this.extLst == null) + { + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.fieldsUsage != null) + this.fieldsUsage.Write(sw, "fieldsUsage"); + if (this.groupLevels != null) + this.groupLevels.Write(sw, "groupLevels"); + if (this.extLst != null) + this.extLst.Write(sw, "extLst"); + sw.Write(string.Format("", nodeName)); + } } private CT_FieldsUsage fieldsUsageField; @@ -6297,9 +6518,9 @@ internal void Write(StreamWriter sw, string nodeName) public CT_CacheHierarchy() { - this.extLstField = new CT_ExtensionList(); - this.groupLevelsField = new CT_GroupLevels(); - this.fieldsUsageField = new CT_FieldsUsage(); + //this.extLstField = new CT_ExtensionList(); + //this.groupLevelsField = new CT_GroupLevels(); + //this.fieldsUsageField = new CT_FieldsUsage(); this.measureField = false; this.setField = false; this.iconSetField = 0; @@ -6727,15 +6948,22 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.kpi != null) + if (this.kpi == null || this.kpi.Count == 0) + { + sw.Write("/>"); + } + else { - foreach (CT_PCDKPI x in this.kpi) + sw.Write(">"); + if (this.kpi != null && this.kpi.Count > 0) { - x.Write(sw, "kpi"); + foreach (CT_PCDKPI x in this.kpi) + { + x.Write(sw, "kpi"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List kpiField; @@ -6831,8 +7059,7 @@ internal void Write(StreamWriter sw, string nodeName) XmlHelper.WriteAttribute(sw, "trend", this.trend); XmlHelper.WriteAttribute(sw, "weight", this.weight); XmlHelper.WriteAttribute(sw, "time", this.time); - sw.Write(">"); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } private string uniqueNameField; @@ -7034,18 +7261,29 @@ public static CT_TupleCache Parse(XmlNode node, XmlNamespaceManager namespaceMan internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - sw.Write(">"); - if (this.entries != null) - this.entries.Write(sw, "entries"); - if (this.sets != null) - this.sets.Write(sw, "sets"); - if (this.queryCache != null) - this.queryCache.Write(sw, "queryCache"); - if (this.serverFormats != null) - this.serverFormats.Write(sw, "serverFormats"); - if (this.extLst != null) - this.extLst.Write(sw, "extLst"); - sw.Write(string.Format("", nodeName)); + if (this.entries == null + && this.sets == null + && this.queryCache == null + && this.serverFormats == null + && this.extLst == null) + { + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.entries != null) + this.entries.Write(sw, "entries"); + if (this.sets != null) + this.sets.Write(sw, "sets"); + if (this.queryCache != null) + this.queryCache.Write(sw, "queryCache"); + if (this.serverFormats != null) + this.serverFormats.Write(sw, "serverFormats"); + if (this.extLst != null) + this.extLst.Write(sw, "extLst"); + sw.Write(string.Format("", nodeName)); + } } private CT_PCDSDTCEntries entriesField; @@ -7174,19 +7412,26 @@ public static CT_PCDSDTCEntries Parse(XmlNode node, XmlNamespaceManager namespac internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - sw.Write(">"); - foreach (object o in this.Items) + if (this.Items == null || this.Items.Count == 0) { - if (o is CT_Missing) - ((CT_Missing)o).Write(sw, "m"); - else if (o is CT_Number) - ((CT_Number)o).Write(sw, "n"); - else if (o is CT_Error) - ((CT_Error)o).Write(sw, "e"); - else if (o is CT_String) - ((CT_String)o).Write(sw, "s"); + sw.Write("/>"); + } + else + { + sw.Write(">"); + foreach (object o in this.Items) + { + if (o is CT_Missing) + ((CT_Missing)o).Write(sw, "m"); + else if (o is CT_Number) + ((CT_Number)o).Write(sw, "n"); + else if (o is CT_Error) + ((CT_Error)o).Write(sw, "e"); + else if (o is CT_String) + ((CT_String)o).Write(sw, "s"); + } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List itemsField; @@ -7272,15 +7517,23 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.set != null) + + if (this.set == null || this.set.Count == 0) + { + sw.Write("/>"); + } + else { - foreach (CT_Set x in this.set) + sw.Write(">"); + if (this.set != null && this.set.Count > 0) { - x.Write(sw, "set"); + foreach (CT_Set x in this.set) + { + x.Write(sw, "set"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List setField; @@ -7376,17 +7629,25 @@ internal void Write(StreamWriter sw, string nodeName) XmlHelper.WriteAttribute(sw, "setDefinition", this.setDefinition); XmlHelper.WriteAttribute(sw, "sortType", this.sortType.ToString()); XmlHelper.WriteAttribute(sw, "queryFailed", this.queryFailed); - sw.Write(">"); - if (this.sortByTuple != null) - this.sortByTuple.Write(sw, "sortByTuple"); - if (this.tpls != null) + + if (this.sortByTuple == null && (this.tpls == null || this.tpls.Count == 0)) + { + sw.Write("/>"); + } + else { - foreach (CT_Tuples x in this.tpls) + sw.Write(">"); + if (this.sortByTuple != null) + this.sortByTuple.Write(sw, "sortByTuple"); + if (this.tpls != null && this.tpls.Count > 0) { - x.Write(sw, "tpls"); + foreach (CT_Tuples x in this.tpls) + { + x.Write(sw, "tpls"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List tplsField; @@ -7578,15 +7839,22 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.query != null) + if (this.query == null || this.query.Count == 0) + { + sw.Write("/>"); + } + else { - foreach (CT_Query x in this.query) + sw.Write(">"); + if (this.query != null && this.query.Count > 0) { - x.Write(sw, "query"); + foreach (CT_Query x in this.query) + { + x.Write(sw, "query"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List queryField; @@ -7667,10 +7935,17 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "mdx", this.mdx); - sw.Write(">"); - if (this.tpls != null) - this.tpls.Write(sw, "tpls"); - sw.Write(string.Format("", nodeName)); + if (this.tpls == null) + { + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.tpls != null) + this.tpls.Write(sw, "tpls"); + sw.Write(string.Format("", nodeName)); + } } private CT_Tuples tplsField; @@ -7738,15 +8013,23 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.serverFormat != null) + + if (this.serverFormat == null || this.serverFormat.Count == 0) + { + sw.Write("/>"); + } + else { - foreach (CT_ServerFormat x in this.serverFormat) + sw.Write(">"); + if (this.serverFormat != null && this.serverFormat.Count > 0) { - x.Write(sw, "serverFormat"); + foreach (CT_ServerFormat x in this.serverFormat) + { + x.Write(sw, "serverFormat"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List serverFormatField; @@ -7824,8 +8107,7 @@ internal void Write(StreamWriter sw, string nodeName) sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "culture", this.culture); XmlHelper.WriteAttribute(sw, "format", this.format); - sw.Write(">"); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } private string cultureField; @@ -7888,15 +8170,22 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.calculatedItem != null) + if (this.calculatedItem == null || this.calculatedItem.Count == 0) + { + sw.Write("/>"); + } + else { - foreach (CT_CalculatedItem x in this.calculatedItem) + sw.Write(">"); + if (this.calculatedItem != null && this.calculatedItem.Count > 0) { - x.Write(sw, "calculatedItem"); + foreach (CT_CalculatedItem x in this.calculatedItem) + { + x.Write(sw, "calculatedItem"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List calculatedItemField; @@ -7982,12 +8271,19 @@ internal void Write(StreamWriter sw, string nodeName) sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "field", this.field); XmlHelper.WriteAttribute(sw, "formula", this.formula); - sw.Write(">"); - if (this.pivotArea != null) - this.pivotArea.Write(sw, "pivotArea"); - if (this.extLst != null) - this.extLst.Write(sw, "extLst"); - sw.Write(string.Format("", nodeName)); + if (this.pivotArea == null && this.extLst == null) + { + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.pivotArea != null) + this.pivotArea.Write(sw, "pivotArea"); + if (this.extLst != null) + this.extLst.Write(sw, "extLst"); + sw.Write(string.Format("", nodeName)); + } } private CT_PivotArea pivotAreaField; @@ -8101,15 +8397,23 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.calculatedMember != null) + + if (this.calculatedMember == null || this.calculatedMember.Count == 0) + { + sw.Write("/>"); + } + else { - foreach (CT_CalculatedMember x in this.calculatedMember) + sw.Write(">"); + if (this.calculatedMember != null && this.calculatedMember.Count > 0) { - x.Write(sw, "calculatedMember"); + foreach (CT_CalculatedMember x in this.calculatedMember) + { + x.Write(sw, "calculatedMember"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List calculatedMemberField; @@ -8204,10 +8508,18 @@ internal void Write(StreamWriter sw, string nodeName) XmlHelper.WriteAttribute(sw, "parent", this.parent); XmlHelper.WriteAttribute(sw, "solveOrder", this.solveOrder); XmlHelper.WriteAttribute(sw, "set", this.set); - sw.Write(">"); - if (this.extLst != null) - this.extLst.Write(sw, "extLst"); - sw.Write(string.Format("", nodeName)); + + if (this.extLst == null) + { + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.extLst != null) + this.extLst.Write(sw, "extLst"); + sw.Write(string.Format("", nodeName)); + } } private CT_ExtensionList extLstField; @@ -8369,15 +8681,22 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.dimension != null) + if (this.dimension == null || this.dimension.Count == 0) + { + sw.Write("/>"); + } + else { - foreach (CT_PivotDimension x in this.dimension) + sw.Write(">"); + if (this.dimension != null && this.dimension.Count > 0) { - x.Write(sw, "dimension"); + foreach (CT_PivotDimension x in this.dimension) + { + x.Write(sw, "dimension"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List dimensionField; @@ -8460,8 +8779,7 @@ internal void Write(StreamWriter sw, string nodeName) XmlHelper.WriteAttribute(sw, "name", this.name); XmlHelper.WriteAttribute(sw, "uniqueName", this.uniqueName); XmlHelper.WriteAttribute(sw, "caption", this.caption); - sw.Write(">"); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } private bool measureField; @@ -8560,15 +8878,22 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.measureGroup != null) + if (this.measureGroup == null || this.measureGroup.Count == 0) { - foreach (CT_MeasureGroup x in this.measureGroup) + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.measureGroup != null && this.measureGroup.Count > 0) { - x.Write(sw, "measureGroup"); + foreach (CT_MeasureGroup x in this.measureGroup) + { + x.Write(sw, "measureGroup"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List measureGroupField; @@ -8646,8 +8971,7 @@ internal void Write(StreamWriter sw, string nodeName) sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "name", this.name); XmlHelper.WriteAttribute(sw, "caption", this.caption); - sw.Write(">"); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } private string nameField; @@ -8710,15 +9034,23 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.map != null) + + if (this.map == null || this.map.Count == 0) + { + sw.Write("/>"); + } + else { - foreach (CT_MeasureDimensionMap x in this.map) + sw.Write(">"); + if (this.map != null && this.map.Count > 0) { - x.Write(sw, "map"); + foreach (CT_MeasureDimensionMap x in this.map) + { + x.Write(sw, "map"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List mapField; diff --git a/OpenXmlFormats/Spreadsheet/PivotTable/CT_PivotCacheRecords.cs b/OpenXmlFormats/Spreadsheet/PivotTable/CT_PivotCacheRecords.cs index c5bae177b..1c45a507e 100644 --- a/OpenXmlFormats/Spreadsheet/PivotTable/CT_PivotCacheRecords.cs +++ b/OpenXmlFormats/Spreadsheet/PivotTable/CT_PivotCacheRecords.cs @@ -19,73 +19,42 @@ public static CT_PivotCacheRecords Parse(XmlNode node, XmlNamespaceManager names CT_PivotCacheRecords ctObj = new CT_PivotCacheRecords(); if (node.Attributes["count"] != null) ctObj.count = XmlHelper.ReadUInt(node.Attributes["count"]); - ctObj.r = new List(); + ctObj.r = new List(); foreach (XmlNode childNode in node.ChildNodes) { if (childNode.LocalName == "extLst") - ctObj.extLst = CT_ExtensionList.Parse(childNode, namespaceManager); - else if (childNode.LocalName == "n") - { - ctObj.r.Add(CT_Number.Parse(childNode, namespaceManager)); - } - else if (childNode.LocalName == "b") - { - ctObj.r.Add(CT_Boolean.Parse(childNode, namespaceManager)); - } - else if (childNode.LocalName == "d") - { - ctObj.r.Add(CT_DateTime.Parse(childNode, namespaceManager)); - } - else if (childNode.LocalName == "e") { - ctObj.r.Add(CT_Error.Parse(childNode, namespaceManager)); - } - else if (childNode.LocalName == "m") - { - ctObj.r.Add(CT_Missing.Parse(childNode, namespaceManager)); - } - else if (childNode.LocalName == "s") - { - ctObj.r.Add(CT_String.Parse(childNode, namespaceManager)); + ctObj.extLst = CT_ExtensionList.Parse(childNode, namespaceManager); } - else if (childNode.LocalName == "x") + else if (childNode.LocalName == "r") { - ctObj.r.Add(CT_Index.Parse(childNode, namespaceManager)); + ctObj.rField.Add(CT_PivotCacheRecord.Parse(childNode, namespaceManager)); } } return ctObj; } - - internal void Write(StreamWriter sw) { sw.Write(""); sw.Write(""); if (this.extLst != null) this.extLst.Write(sw, "extLst"); - foreach (object o in this.r) + if (this.r != null && this.r.Count > 0) { - if (o is CT_Number) - ((CT_Number)o).Write(sw, "n"); - else if (o is CT_Boolean) - ((CT_Boolean)o).Write(sw, "b"); - else if (o is CT_DateTime) - ((CT_DateTime)o).Write(sw, "d"); - else if (o is CT_Error) - ((CT_Error)o).Write(sw, "e"); - else if (o is CT_Missing) - ((CT_Missing)o).Write(sw, "m"); - else if (o is CT_String) - ((CT_String)o).Write(sw, "s"); - else if (o is CT_Index) - ((CT_Index)o).Write(sw, "x"); + foreach (CT_PivotCacheRecord o in this.r) + { + o.Write(sw); + } } - sw.Write(string.Format("")); + sw.Write(""); } public void Save(Stream stream) @@ -96,7 +65,8 @@ public void Save(Stream stream) this.Write(sw); } } - private List rField; + + private List rField; private CT_ExtensionList extLstField; @@ -104,21 +74,8 @@ public void Save(Stream stream) private bool countFieldSpecified; - public CT_PivotCacheRecords() - { - this.extLstField = new CT_ExtensionList(); - this.rField = new List(); - } - [System.Xml.Serialization.XmlArrayAttribute(Order = 0)] - [System.Xml.Serialization.XmlArrayItemAttribute("b", typeof(CT_Boolean), IsNullable = false)] - [System.Xml.Serialization.XmlArrayItemAttribute("d", typeof(CT_DateTime), IsNullable = false)] - [System.Xml.Serialization.XmlArrayItemAttribute("e", typeof(CT_Error), IsNullable = false)] - [System.Xml.Serialization.XmlArrayItemAttribute("m", typeof(CT_Missing), IsNullable = false)] - [System.Xml.Serialization.XmlArrayItemAttribute("n", typeof(CT_Number), IsNullable = false)] - [System.Xml.Serialization.XmlArrayItemAttribute("s", typeof(CT_String), IsNullable = false)] - [System.Xml.Serialization.XmlArrayItemAttribute("x", typeof(CT_Index), IsNullable = false)] - public List r + public List r { get { @@ -169,5 +126,98 @@ public bool countSpecified } } } - + + [XmlType(Namespace = "http://schemas.openxmlformats.org/spreadsheetml/2006/main")] + [XmlRoot(Namespace = "http://schemas.openxmlformats.org/spreadsheetml/2006/main", IsNullable = true)] + public partial class CT_PivotCacheRecord + { + private List items; + + public static CT_PivotCacheRecord Parse(XmlNode node, XmlNamespaceManager namespaceManager) + { + CT_PivotCacheRecord ctObj = new CT_PivotCacheRecord(); + ctObj.fields = new List(); + + foreach (XmlNode childNode in node.ChildNodes) + { + if (childNode.LocalName == "n") + { + ctObj.fields.Add(CT_Number.Parse(childNode, namespaceManager)); + } + else if (childNode.LocalName == "b") + { + ctObj.fields.Add(CT_Boolean.Parse(childNode, namespaceManager)); + } + else if (childNode.LocalName == "d") + { + ctObj.fields.Add(CT_DateTime.Parse(childNode, namespaceManager)); + } + else if (childNode.LocalName == "e") + { + ctObj.fields.Add(CT_Error.Parse(childNode, namespaceManager)); + } + else if (childNode.LocalName == "m") + { + ctObj.fields.Add(CT_Missing.Parse(childNode, namespaceManager)); + } + else if (childNode.LocalName == "s") + { + ctObj.fields.Add(CT_String.Parse(childNode, namespaceManager)); + } + else if (childNode.LocalName == "x") + { + ctObj.fields.Add(CT_Index.Parse(childNode, namespaceManager)); + } + } + + return ctObj; + } + + [System.Xml.Serialization.XmlArrayItemAttribute("b", typeof(CT_Boolean), IsNullable = false)] + [System.Xml.Serialization.XmlArrayItemAttribute("d", typeof(CT_DateTime), IsNullable = false)] + [System.Xml.Serialization.XmlArrayItemAttribute("e", typeof(CT_Error), IsNullable = false)] + [System.Xml.Serialization.XmlArrayItemAttribute("m", typeof(CT_Missing), IsNullable = false)] + [System.Xml.Serialization.XmlArrayItemAttribute("n", typeof(CT_Number), IsNullable = false)] + [System.Xml.Serialization.XmlArrayItemAttribute("s", typeof(CT_String), IsNullable = false)] + [System.Xml.Serialization.XmlArrayItemAttribute("x", typeof(CT_Index), IsNullable = false)] + public List fields + { + get + { + return this.items; + } + set + { + this.items = value; + } + } + + internal void Write(StreamWriter sw) + { + if (this.fields != null && fields.Count > 0) + { + sw.Write(""); + + foreach (object o in this.fields) + { + if (o is CT_Number) + ((CT_Number)o).Write(sw, "n"); + else if (o is CT_Boolean) + ((CT_Boolean)o).Write(sw, "b"); + else if (o is CT_DateTime) + ((CT_DateTime)o).Write(sw, "d"); + else if (o is CT_Error) + ((CT_Error)o).Write(sw, "e"); + else if (o is CT_Missing) + ((CT_Missing)o).Write(sw, "m"); + else if (o is CT_String) + ((CT_String)o).Write(sw, "s"); + else if (o is CT_Index) + ((CT_Index)o).Write(sw, "x"); + } + + sw.Write(""); + } + } + } } diff --git a/OpenXmlFormats/Spreadsheet/PivotTable/CT_PivotTableDefinition.cs b/OpenXmlFormats/Spreadsheet/PivotTable/CT_PivotTableDefinition.cs index ea305a444..bd118404a 100644 --- a/OpenXmlFormats/Spreadsheet/PivotTable/CT_PivotTableDefinition.cs +++ b/OpenXmlFormats/Spreadsheet/PivotTable/CT_PivotTableDefinition.cs @@ -193,8 +193,11 @@ internal void Write(StreamWriter sw) sw.Write("")); + sw.Write(""); } public void Save(Stream stream) { @@ -1892,14 +1895,13 @@ public static CT_Location Parse(XmlNode node, XmlNamespaceManager namespaceManag internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - XmlHelper.WriteAttribute(sw, "ref", this.@ref); - XmlHelper.WriteAttribute(sw, "firstHeaderRow", this.firstHeaderRow); - XmlHelper.WriteAttribute(sw, "firstDataRow", this.firstDataRow); - XmlHelper.WriteAttribute(sw, "firstDataCol", this.firstDataCol); + XmlHelper.WriteAttribute(sw, "ref", this.@ref, true); + XmlHelper.WriteAttribute(sw, "firstHeaderRow", this.firstHeaderRow, true); + XmlHelper.WriteAttribute(sw, "firstDataRow", this.firstDataRow, true); + XmlHelper.WriteAttribute(sw, "firstDataCol", this.firstDataCol, true); XmlHelper.WriteAttribute(sw, "rowPageCount", this.rowPageCount); XmlHelper.WriteAttribute(sw, "colPageCount", this.colPageCount); - sw.Write(">"); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } private string refField; @@ -2030,15 +2032,22 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.pivotField != null) + if (this.pivotField == null || this.pivotField.Count == 0) { - foreach (CT_PivotField x in this.pivotField) + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.pivotField != null && this.pivotField.Count > 0) { - x.Write(sw, "pivotField"); + foreach (CT_PivotField x in this.pivotField) + { + x.Write(sw, "pivotField"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List pivotFieldField; @@ -2243,61 +2252,70 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "name", this.name); - XmlHelper.WriteAttribute(sw, "axis", this.axis.ToString()); - XmlHelper.WriteAttribute(sw, "dataField", this.dataField); + if (this.axis != null) + XmlHelper.WriteAttribute(sw, "axis", this.axis.ToString()); + XmlHelper.WriteAttribute(sw, "dataField", this.dataField, true); XmlHelper.WriteAttribute(sw, "subtotalCaption", this.subtotalCaption); - XmlHelper.WriteAttribute(sw, "showDropDowns", this.showDropDowns); - XmlHelper.WriteAttribute(sw, "hiddenLevel", this.hiddenLevel); - XmlHelper.WriteAttribute(sw, "uniqueMemberProperty", this.uniqueMemberProperty); - XmlHelper.WriteAttribute(sw, "compact", this.compact); - XmlHelper.WriteAttribute(sw, "allDrilled", this.allDrilled); - XmlHelper.WriteAttribute(sw, "numFmtId", this.numFmtId); - XmlHelper.WriteAttribute(sw, "outline", this.outline); + XmlHelper.WriteAttribute(sw, "showDropDowns", this.showDropDowns, false, true); + XmlHelper.WriteAttribute(sw, "hiddenLevel", this.hiddenLevel, false); + XmlHelper.WriteAttribute(sw, "uniqueMemberProperty", this.uniqueMemberProperty, false); + XmlHelper.WriteAttribute(sw, "compact", this.compact, false, true); + XmlHelper.WriteAttribute(sw, "allDrilled", this.allDrilled, false); + XmlHelper.WriteAttribute(sw, "numFmtId", this.numFmtId, false); + XmlHelper.WriteAttribute(sw, "outline", this.outline, false, true); XmlHelper.WriteAttribute(sw, "subtotalTop", this.subtotalTop); - XmlHelper.WriteAttribute(sw, "dragToRow", this.dragToRow); - XmlHelper.WriteAttribute(sw, "dragToCol", this.dragToCol); - XmlHelper.WriteAttribute(sw, "multipleItemSelectionAllowed", this.multipleItemSelectionAllowed); - XmlHelper.WriteAttribute(sw, "dragToPage", this.dragToPage); - XmlHelper.WriteAttribute(sw, "dragToData", this.dragToData); - XmlHelper.WriteAttribute(sw, "dragOff", this.dragOff); + XmlHelper.WriteAttribute(sw, "dragToRow", this.dragToRow, false, true); + XmlHelper.WriteAttribute(sw, "dragToCol", this.dragToCol, false, true); + XmlHelper.WriteAttribute(sw, "multipleItemSelectionAllowed", this.multipleItemSelectionAllowed, false); + XmlHelper.WriteAttribute(sw, "dragToPage", this.dragToPage, false, true); + XmlHelper.WriteAttribute(sw, "dragToData", this.dragToData, false, true); + XmlHelper.WriteAttribute(sw, "dragOff", this.dragOff, false, true); XmlHelper.WriteAttribute(sw, "showAll", this.showAll); - XmlHelper.WriteAttribute(sw, "insertBlankRow", this.insertBlankRow); - XmlHelper.WriteAttribute(sw, "serverField", this.serverField); - XmlHelper.WriteAttribute(sw, "insertPageBreak", this.insertPageBreak); - XmlHelper.WriteAttribute(sw, "autoShow", this.autoShow); - XmlHelper.WriteAttribute(sw, "topAutoShow", this.topAutoShow); - XmlHelper.WriteAttribute(sw, "hideNewItems", this.hideNewItems); - XmlHelper.WriteAttribute(sw, "measureFilter", this.measureFilter); - XmlHelper.WriteAttribute(sw, "includeNewItemsInFilter", this.includeNewItemsInFilter); - XmlHelper.WriteAttribute(sw, "itemPageCount", this.itemPageCount); - XmlHelper.WriteAttribute(sw, "sortType", this.sortType.ToString()); - XmlHelper.WriteAttribute(sw, "dataSourceSort", this.dataSourceSort); - XmlHelper.WriteAttribute(sw, "nonAutoSortDefault", this.nonAutoSortDefault); - XmlHelper.WriteAttribute(sw, "rankBy", this.rankBy); + XmlHelper.WriteAttribute(sw, "insertBlankRow", this.insertBlankRow, false); + XmlHelper.WriteAttribute(sw, "serverField", this.serverField, false); + XmlHelper.WriteAttribute(sw, "insertPageBreak", this.insertPageBreak, false); + XmlHelper.WriteAttribute(sw, "autoShow", this.autoShow, false); + XmlHelper.WriteAttribute(sw, "topAutoShow", this.topAutoShow, false, true); + XmlHelper.WriteAttribute(sw, "hideNewItems", this.hideNewItems, false); + XmlHelper.WriteAttribute(sw, "measureFilter", this.measureFilter, false); + XmlHelper.WriteAttribute(sw, "includeNewItemsInFilter", this.includeNewItemsInFilter, false); + XmlHelper.WriteAttribute(sw, "itemPageCount", this.itemPageCount, false); + if (this.sortType != ST_FieldSortType.manual) + XmlHelper.WriteAttribute(sw, "sortType", this.sortType.ToString()); + XmlHelper.WriteAttribute(sw, "dataSourceSort", this.dataSourceSort, false); + XmlHelper.WriteAttribute(sw, "nonAutoSortDefault", this.nonAutoSortDefault, false); + XmlHelper.WriteAttribute(sw, "rankBy", this.rankBy, false); XmlHelper.WriteAttribute(sw, "defaultSubtotal", this.defaultSubtotal); - XmlHelper.WriteAttribute(sw, "sumSubtotal", this.sumSubtotal); - XmlHelper.WriteAttribute(sw, "countASubtotal", this.countASubtotal); - XmlHelper.WriteAttribute(sw, "avgSubtotal", this.avgSubtotal); - XmlHelper.WriteAttribute(sw, "maxSubtotal", this.maxSubtotal); - XmlHelper.WriteAttribute(sw, "minSubtotal", this.minSubtotal); - XmlHelper.WriteAttribute(sw, "productSubtotal", this.productSubtotal); - XmlHelper.WriteAttribute(sw, "countSubtotal", this.countSubtotal); - XmlHelper.WriteAttribute(sw, "stdDevSubtotal", this.stdDevSubtotal); - XmlHelper.WriteAttribute(sw, "stdDevPSubtotal", this.stdDevPSubtotal); - XmlHelper.WriteAttribute(sw, "varSubtotal", this.varSubtotal); - XmlHelper.WriteAttribute(sw, "varPSubtotal", this.varPSubtotal); - XmlHelper.WriteAttribute(sw, "showPropCell", this.showPropCell); - XmlHelper.WriteAttribute(sw, "showPropTip", this.showPropTip); - XmlHelper.WriteAttribute(sw, "showPropAsCaption", this.showPropAsCaption); - XmlHelper.WriteAttribute(sw, "defaultAttributeDrillState", this.defaultAttributeDrillState); - sw.Write(">"); - if (this.items != null) - this.items.Write(sw, "items"); - if (this.autoSortScope != null) - this.autoSortScope.Write(sw, "autoSortScope"); - if (this.extLst != null) - this.extLst.Write(sw, "extLst"); - sw.Write(string.Format("", nodeName)); + XmlHelper.WriteAttribute(sw, "sumSubtotal", this.sumSubtotal, false); + XmlHelper.WriteAttribute(sw, "countASubtotal", this.countASubtotal, false); + XmlHelper.WriteAttribute(sw, "avgSubtotal", this.avgSubtotal, false); + XmlHelper.WriteAttribute(sw, "maxSubtotal", this.maxSubtotal, false); + XmlHelper.WriteAttribute(sw, "minSubtotal", this.minSubtotal, false); + XmlHelper.WriteAttribute(sw, "productSubtotal", this.productSubtotal, false); + XmlHelper.WriteAttribute(sw, "countSubtotal", this.countSubtotal, false); + XmlHelper.WriteAttribute(sw, "stdDevSubtotal", this.stdDevSubtotal, false); + XmlHelper.WriteAttribute(sw, "stdDevPSubtotal", this.stdDevPSubtotal, false); + XmlHelper.WriteAttribute(sw, "varSubtotal", this.varSubtotal, false); + XmlHelper.WriteAttribute(sw, "varPSubtotal", this.varPSubtotal, false); + XmlHelper.WriteAttribute(sw, "showPropCell", this.showPropCell, false); + XmlHelper.WriteAttribute(sw, "showPropTip", this.showPropTip, false); + XmlHelper.WriteAttribute(sw, "showPropAsCaption", this.showPropAsCaption, false); + XmlHelper.WriteAttribute(sw, "defaultAttributeDrillState", this.defaultAttributeDrillState, false); + if (this.items == null && this.autoSortScope == null && this.extLst == null) + { + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.items != null) + this.items.Write(sw, "items"); + if (this.autoSortScope != null) + this.autoSortScope.Write(sw, "autoSortScope"); + if (this.extLst != null) + this.extLst.Write(sw, "extLst"); + sw.Write(string.Format("", nodeName)); + } } private CT_Items itemsField; @@ -2308,7 +2326,7 @@ internal void Write(StreamWriter sw, string nodeName) private string nameField; - private ST_Axis axisField; + private ST_Axis? axisField; private bool axisFieldSpecified; @@ -2412,9 +2430,9 @@ internal void Write(StreamWriter sw, string nodeName) public CT_PivotField() { - this.extLstField = new CT_ExtensionList(); - this.autoSortScopeField = new CT_AutoSortScope(); - this.itemsField = new CT_Items(); + //this.extLstField = new CT_ExtensionList(); + //this.autoSortScopeField = new CT_AutoSortScope(); + //this.itemsField = new CT_Items(); this.dataFieldField = false; this.showDropDownsField = true; this.hiddenLevelField = false; @@ -2511,7 +2529,7 @@ public string name } [System.Xml.Serialization.XmlAttributeAttribute()] - public ST_Axis axis + public ST_Axis? axis { get { @@ -3250,15 +3268,22 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.item != null) + if (this.item == null || this.item.Count == 0) { - foreach (CT_Item x in this.item) + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.item != null && this.item.Count > 0) { - x.Write(sw, "item"); + foreach (CT_Item x in this.item) + { + x.Write(sw, "item"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List itemField; @@ -3369,19 +3394,19 @@ public static CT_Item Parse(XmlNode node, XmlNamespaceManager namespaceManager) internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - XmlHelper.WriteAttribute(sw, "n", this.n); - XmlHelper.WriteAttribute(sw, "t", this.t.ToString()); - XmlHelper.WriteAttribute(sw, "h", this.h); - XmlHelper.WriteAttribute(sw, "s", this.s); - XmlHelper.WriteAttribute(sw, "sd", this.sd); - XmlHelper.WriteAttribute(sw, "f", this.f); - XmlHelper.WriteAttribute(sw, "m", this.m); - XmlHelper.WriteAttribute(sw, "c", this.c); - XmlHelper.WriteAttribute(sw, "x", this.x); - XmlHelper.WriteAttribute(sw, "d", this.d); - XmlHelper.WriteAttribute(sw, "e", this.e); - sw.Write(">"); - sw.Write(string.Format("", nodeName)); + XmlHelper.WriteAttribute(sw, "n", this.n, false); + if (this.t != ST_ItemType.data) + XmlHelper.WriteAttribute(sw, "t", this.t.ToString()); + XmlHelper.WriteAttribute(sw, "h", this.h, false); + XmlHelper.WriteAttribute(sw, "s", this.s, false); + XmlHelper.WriteAttribute(sw, "sd", this.sd, false, true); + XmlHelper.WriteAttribute(sw, "f", this.f, false); + XmlHelper.WriteAttribute(sw, "m", this.m, false); + XmlHelper.WriteAttribute(sw, "c", this.c, false); + XmlHelper.WriteAttribute(sw, "x", this.x, true); + XmlHelper.WriteAttribute(sw, "d", this.d, false); + XmlHelper.WriteAttribute(sw, "e", this.e, false, true); + sw.Write("/>"); } private string nField; @@ -3665,10 +3690,17 @@ public static CT_AutoSortScope Parse(XmlNode node, XmlNamespaceManager namespace internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - sw.Write(">"); - if (this.pivotArea != null) - this.pivotArea.Write(sw, "pivotArea"); - sw.Write(string.Format("", nodeName)); + if (this.pivotArea == null) + { + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.pivotArea != null) + this.pivotArea.Write(sw, "pivotArea"); + sw.Write(string.Format("", nodeName)); + } } private CT_PivotArea pivotAreaField; @@ -3738,15 +3770,22 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.field != null) + if (this.field == null || this.field.Count == 0) + { + sw.Write("/>"); + } + else { - foreach (CT_Field x in this.field) + sw.Write(">"); + if (this.field != null && this.field.Count > 0) { - x.Write(sw, "field"); + foreach (CT_Field x in this.field) + { + x.Write(sw, "field"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List fieldField; @@ -3831,9 +3870,8 @@ public static CT_Field Parse(XmlNode node, XmlNamespaceManager namespaceManager) internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - XmlHelper.WriteAttribute(sw, "x", this.x); - sw.Write(">"); - sw.Write(string.Format("", nodeName)); + XmlHelper.WriteAttribute(sw, "x", this.x, true); + sw.Write("/>"); } private int xField; @@ -3881,15 +3919,22 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.i != null) + if (this.i == null || this.i.Count == 0) + { + sw.Write("/>"); + } + else { - foreach (CT_I x in this.i) + sw.Write(">"); + if (this.i != null && this.i.Count > 0) { - x.Write(sw, "i"); + foreach (CT_I x in this.i) + { + x.Write(sw, "i"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List iField; @@ -3975,18 +4020,27 @@ public static CT_I Parse(XmlNode node, XmlNamespaceManager namespaceManager) internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - XmlHelper.WriteAttribute(sw, "t", this.t.ToString()); + if (this.t != ST_ItemType.data) + XmlHelper.WriteAttribute(sw, "t", this.t.ToString()); XmlHelper.WriteAttribute(sw, "r", this.r); XmlHelper.WriteAttribute(sw, "i", this.i); - sw.Write(">"); - if (this.x != null) + + if (this.x == null || this.x.Count == 0) { - foreach (CT_X x in this.x) + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.x != null && this.x.Count > 0) { - x.Write(sw, "x"); + foreach (CT_X x in this.x) + { + x.Write(sw, "x"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List xField; @@ -4090,15 +4144,23 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.field != null) + + if (this.field == null || this.field.Count == 0) + { + sw.Write("/>"); + } + else { - foreach (CT_Field x in this.field) + sw.Write(">"); + if (this.field != null && this.field.Count > 0) { - x.Write(sw, "field"); + foreach (CT_Field x in this.field) + { + x.Write(sw, "field"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List fieldField; @@ -4184,15 +4246,23 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.i != null) + + if (this.i == null || this.i.Count == 0) + { + sw.Write("/>"); + } + else { - foreach (CT_I x in this.i) + sw.Write(">"); + if (this.i != null && this.i.Count > 0) { - x.Write(sw, "i"); + foreach (CT_I x in this.i) + { + x.Write(sw, "i"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List iField; @@ -4275,15 +4345,23 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.pageField != null) + + if (this.pageField == null || this.pageField.Count == 0) { - foreach (CT_PageField x in this.pageField) + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.pageField != null && this.pageField.Count > 0) { - x.Write(sw, "pageField"); + foreach (CT_PageField x in this.pageField) + { + x.Write(sw, "pageField"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List pageFieldField; @@ -4386,15 +4464,23 @@ public static CT_PageField Parse(XmlNode node, XmlNamespaceManager namespaceMana internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - XmlHelper.WriteAttribute(sw, "fld", this.fld); - XmlHelper.WriteAttribute(sw, "item", this.item); - XmlHelper.WriteAttribute(sw, "hier", this.hier); - XmlHelper.WriteAttribute(sw, "name", this.name); - XmlHelper.WriteAttribute(sw, "cap", this.cap); - sw.Write(">"); - if (this.extLst != null) - this.extLst.Write(sw, "extLst"); - sw.Write(string.Format("", nodeName)); + XmlHelper.WriteAttribute(sw, "fld", this.fld, true); + XmlHelper.WriteAttribute(sw, "item", this.item, false); + XmlHelper.WriteAttribute(sw, "hier", this.hier, false); + XmlHelper.WriteAttribute(sw, "name", this.name, false); + XmlHelper.WriteAttribute(sw, "cap", this.cap, false); + + if (this.extLst == null || this.extLst.ext.Count == 0) + { + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.extLst != null) + this.extLst.Write(sw, "extLst"); + sw.Write(string.Format("", nodeName)); + } } private CT_ExtensionList extLstField; @@ -4415,7 +4501,6 @@ internal void Write(StreamWriter sw, string nodeName) public CT_PageField() { - this.extLstField = new CT_ExtensionList(); } [System.Xml.Serialization.XmlElementAttribute(Order = 0)] @@ -4552,15 +4637,23 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.dataField != null) + + if (this.dataField == null || this.dataField.Count == 0) { - foreach (CT_DataField x in this.dataField) + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.dataField != null && this.dataField.Count > 0) { - x.Write(sw, "dataField"); + foreach (CT_DataField x in this.dataField) + { + x.Write(sw, "dataField"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List dataFieldField; @@ -4667,16 +4760,24 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "name", this.name); - XmlHelper.WriteAttribute(sw, "fld", this.fld); - XmlHelper.WriteAttribute(sw, "subtotal", this.subtotal.ToString()); - XmlHelper.WriteAttribute(sw, "showDataAs", this.showDataAs.ToString()); - XmlHelper.WriteAttribute(sw, "baseField", this.baseField); - XmlHelper.WriteAttribute(sw, "baseItem", this.baseItem); - XmlHelper.WriteAttribute(sw, "numFmtId", this.numFmtId); - sw.Write(">"); - if (this.extLst != null) - this.extLst.Write(sw, "extLst"); - sw.Write(string.Format("", nodeName)); + XmlHelper.WriteAttribute(sw, "fld", this.fld, true); + XmlHelper.WriteAttribute(sw, "subtotal", this.subtotal.ToString(), false); + XmlHelper.WriteAttribute(sw, "showDataAs", this.showDataAs.ToString(), false); + XmlHelper.WriteAttribute(sw, "baseField", this.baseField, true); + XmlHelper.WriteAttribute(sw, "baseItem", this.baseItem, true); + XmlHelper.WriteAttribute(sw, "numFmtId", this.numFmtId, false); + + if (this.extLst == null) + { + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.extLst != null) + this.extLst.Write(sw, "extLst"); + sw.Write(string.Format("", nodeName)); + } } private CT_ExtensionList extLstField; @@ -4699,7 +4800,7 @@ internal void Write(StreamWriter sw, string nodeName) public CT_DataField() { - this.extLstField = new CT_ExtensionList(); + //this.extLstField = new CT_ExtensionList(); this.subtotalField = ST_DataConsolidateFunction.sum; this.showDataAsField = ST_ShowDataAs.normal; this.baseFieldField = -1; @@ -4892,15 +4993,22 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.format != null) + if (this.format == null || this.format.Count == 0) { - foreach (CT_Format x in this.format) + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.format != null && this.format.Count > 0) { - x.Write(sw, "format"); + foreach (CT_Format x in this.format) + { + x.Write(sw, "format"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List formatField; @@ -4972,14 +5080,21 @@ public static CT_Format Parse(XmlNode node, XmlNamespaceManager namespaceManager internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - XmlHelper.WriteAttribute(sw, "action", this.action.ToString()); + XmlHelper.WriteAttribute(sw, "action", this.action.ToString(), false, ST_FormatAction.formatting.ToString()); XmlHelper.WriteAttribute(sw, "dxfId", this.dxfId); - sw.Write(">"); - if (this.pivotArea != null) - this.pivotArea.Write(sw, "pivotArea"); - if (this.extLst != null) - this.extLst.Write(sw, "extLst"); - sw.Write(string.Format("", nodeName)); + if (this.pivotArea == null && (this.extLst == null || this.extLst.ext.Count == 0)) + { + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.pivotArea != null) + this.pivotArea.Write(sw, "pivotArea"); + if (this.extLst != null && this.extLst.ext.Count != 0) + this.extLst.Write(sw, "extLst"); + sw.Write(string.Format("", nodeName)); + } } private CT_PivotArea pivotAreaField; @@ -5115,15 +5230,23 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.conditionalFormat != null) + + if (this.conditionalFormat == null || this.conditionalFormat.Count == 0) + { + sw.Write("/>"); + } + else { - foreach (CT_ConditionalFormat x in this.conditionalFormat) + sw.Write(">"); + if (this.conditionalFormat != null && this.conditionalFormat.Count > 0) { - x.Write(sw, "conditionalFormat"); + foreach (CT_ConditionalFormat x in this.conditionalFormat) + { + x.Write(sw, "conditionalFormat"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List conditionalFormatField; @@ -5200,12 +5323,20 @@ internal void Write(StreamWriter sw, string nodeName) XmlHelper.WriteAttribute(sw, "scope", this.scope.ToString()); XmlHelper.WriteAttribute(sw, "type", this.type.ToString()); XmlHelper.WriteAttribute(sw, "priority", this.priority); - sw.Write(">"); - if (this.pivotAreas != null) - this.pivotAreas.Write(sw, "pivotAreas"); - if (this.extLst != null) - this.extLst.Write(sw, "extLst"); - sw.Write(string.Format("", nodeName)); + + if (this.pivotAreas == null && this.extLst == null) + { + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.pivotAreas != null) + this.pivotAreas.Write(sw, "pivotAreas"); + if (this.extLst != null) + this.extLst.Write(sw, "extLst"); + sw.Write(string.Format("", nodeName)); + } } private CT_PivotAreas pivotAreasField; @@ -5220,7 +5351,6 @@ internal void Write(StreamWriter sw, string nodeName) public CT_ConditionalFormat() { - this.extLstField = new CT_ExtensionList(); this.pivotAreasField = new CT_PivotAreas(); this.scopeField = ST_Scope.selection; this.typeField = ST_Type.none; @@ -5323,15 +5453,23 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.pivotArea != null) + + if (this.pivotArea == null || this.pivotArea.Count == 0) { - foreach (CT_PivotArea x in this.pivotArea) + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.pivotArea != null && this.pivotArea.Count > 0) { - x.Write(sw, "pivotArea"); + foreach (CT_PivotArea x in this.pivotArea) + { + x.Write(sw, "pivotArea"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List pivotAreaField; @@ -5451,15 +5589,23 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.chartFormat != null) + + if (this.chartFormat == null || this.chartFormat.Count == 0) { - foreach (CT_ChartFormat x in this.chartFormat) + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.chartFormat != null && this.chartFormat.Count > 0) { - x.Write(sw, "chartFormat"); + foreach (CT_ChartFormat x in this.chartFormat) + { + x.Write(sw, "chartFormat"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List chartFormatField; @@ -5531,13 +5677,21 @@ public static CT_ChartFormat Parse(XmlNode node, XmlNamespaceManager namespaceMa internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - XmlHelper.WriteAttribute(sw, "chart", this.chart); - XmlHelper.WriteAttribute(sw, "format", this.format); + XmlHelper.WriteAttribute(sw, "chart", this.chart, true); + XmlHelper.WriteAttribute(sw, "format", this.format, true); XmlHelper.WriteAttribute(sw, "series", this.series); - sw.Write(">"); - if (this.pivotArea != null) - this.pivotArea.Write(sw, "pivotArea"); - sw.Write(string.Format("", nodeName)); + + if (this.pivotArea == null) + { + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.pivotArea != null) + this.pivotArea.Write(sw, "pivotArea"); + sw.Write(string.Format("", nodeName)); + } } private CT_PivotArea pivotAreaField; @@ -5637,15 +5791,22 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.pivotHierarchy != null) + if (this.pivotHierarchy == null || this.pivotHierarchy.Count == 0) { - foreach (CT_PivotHierarchy x in this.pivotHierarchy) + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.pivotHierarchy != null && this.pivotHierarchy.Count > 0) { - x.Write(sw, "pivotHierarchy"); + foreach (CT_PivotHierarchy x in this.pivotHierarchy) + { + x.Write(sw, "pivotHierarchy"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List pivotHierarchyField; @@ -5750,30 +5911,38 @@ public static CT_PivotHierarchy Parse(XmlNode node, XmlNamespaceManager namespac internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - XmlHelper.WriteAttribute(sw, "outline", this.outline); - XmlHelper.WriteAttribute(sw, "multipleItemSelectionAllowed", this.multipleItemSelectionAllowed); - XmlHelper.WriteAttribute(sw, "subtotalTop", this.subtotalTop); - XmlHelper.WriteAttribute(sw, "showInFieldList", this.showInFieldList); - XmlHelper.WriteAttribute(sw, "dragToRow", this.dragToRow); - XmlHelper.WriteAttribute(sw, "dragToCol", this.dragToCol); - XmlHelper.WriteAttribute(sw, "dragToPage", this.dragToPage); - XmlHelper.WriteAttribute(sw, "dragToData", this.dragToData); - XmlHelper.WriteAttribute(sw, "dragOff", this.dragOff); - XmlHelper.WriteAttribute(sw, "includeNewItemsInFilter", this.includeNewItemsInFilter); + XmlHelper.WriteAttribute(sw, "outline", this.outline, false); + XmlHelper.WriteAttribute(sw, "multipleItemSelectionAllowed", this.multipleItemSelectionAllowed, false); + XmlHelper.WriteAttribute(sw, "subtotalTop", this.subtotalTop, false); + XmlHelper.WriteAttribute(sw, "showInFieldList", this.showInFieldList, false, true); + XmlHelper.WriteAttribute(sw, "dragToRow", this.dragToRow, false, true); + XmlHelper.WriteAttribute(sw, "dragToCol", this.dragToCol, false, true); + XmlHelper.WriteAttribute(sw, "dragToPage", this.dragToPage, false, true); + XmlHelper.WriteAttribute(sw, "dragToData", this.dragToData, false); + XmlHelper.WriteAttribute(sw, "dragOff", this.dragOff, false, true); + XmlHelper.WriteAttribute(sw, "includeNewItemsInFilter", this.includeNewItemsInFilter, false); XmlHelper.WriteAttribute(sw, "caption", this.caption); - sw.Write(">"); - if (this.mps != null) - this.mps.Write(sw, "mps"); - if (this.extLst != null) - this.extLst.Write(sw, "extLst"); - if (this.members != null) + + if (this.mps == null && this.extLst == null && (this.members == null || this.members.Count == 0)) + { + sw.Write("/>"); + } + else { - foreach (CT_Members x in this.members) + sw.Write(">"); + if (this.mps != null) + this.mps.Write(sw, "mps"); + if (this.extLst != null) + this.extLst.Write(sw, "extLst"); + if (this.members != null && this.members.Count > 0) { - x.Write(sw, "members"); + foreach (CT_Members x in this.members) + { + x.Write(sw, "members"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private CT_MemberProperties mpsField; @@ -5806,9 +5975,9 @@ internal void Write(StreamWriter sw, string nodeName) public CT_PivotHierarchy() { - this.extLstField = new CT_ExtensionList(); - this.membersField = new List(); - this.mpsField = new CT_MemberProperties(); + //this.extLstField = new CT_ExtensionList(); + //this.membersField = new List(); + //this.mpsField = new CT_MemberProperties(); this.outlineField = false; this.multipleItemSelectionAllowedField = false; this.subtotalTopField = false; @@ -6043,15 +6212,23 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.mp != null) + + if (this.mp == null || this.mp.Count == 0) { - foreach (CT_MemberProperty x in this.mp) + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.mp != null && this.mp.Count > 0) { - x.Write(sw, "mp"); + foreach (CT_MemberProperty x in this.mp) + { + x.Write(sw, "mp"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List mpField; @@ -6151,8 +6328,7 @@ internal void Write(StreamWriter sw, string nodeName) XmlHelper.WriteAttribute(sw, "pLen", this.pLen); XmlHelper.WriteAttribute(sw, "level", this.level); XmlHelper.WriteAttribute(sw, "field", this.field); - sw.Write(">"); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } private string nameField; @@ -6393,15 +6569,22 @@ internal void Write(StreamWriter sw, string nodeName) sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); XmlHelper.WriteAttribute(sw, "level", this.level); - sw.Write(">"); - if (this.member != null) + if (this.member == null || this.member.Count == 0) + { + sw.Write("/>"); + } + else { - foreach (CT_Member x in this.member) + sw.Write(">"); + if (this.member != null && this.member.Count > 0) { - x.Write(sw, "member"); + foreach (CT_Member x in this.member) + { + x.Write(sw, "member"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List memberField; @@ -6507,8 +6690,7 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "name", this.name); - sw.Write(">"); - sw.Write(string.Format("", nodeName)); + sw.Write("/>"); } private string nameField; @@ -6559,13 +6741,12 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "name", this.name); - XmlHelper.WriteAttribute(sw, "showRowHeaders", this.showRowHeaders); - XmlHelper.WriteAttribute(sw, "showColHeaders", this.showColHeaders); - XmlHelper.WriteAttribute(sw, "showRowStripes", this.showRowStripes); - XmlHelper.WriteAttribute(sw, "showColStripes", this.showColStripes); - XmlHelper.WriteAttribute(sw, "showLastColumn", this.showLastColumn); - sw.Write(">"); - sw.Write(string.Format("", nodeName)); + XmlHelper.WriteAttribute(sw, "showRowHeaders", this.showRowHeaders, false); + XmlHelper.WriteAttribute(sw, "showColHeaders", this.showColHeaders, false); + XmlHelper.WriteAttribute(sw, "showRowStripes", this.showRowStripes, false); + XmlHelper.WriteAttribute(sw, "showColStripes", this.showColStripes, false); + XmlHelper.WriteAttribute(sw, "showLastColumn", this.showLastColumn, false); + sw.Write("/>"); } private string nameField; @@ -6763,15 +6944,22 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.filter != null) + if (this.filter == null || this.filter.Count == 0) { - foreach (CT_PivotFilter x in this.filter) + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.filter != null && this.filter.Count > 0) { - x.Write(sw, "filter"); + foreach (CT_PivotFilter x in this.filter) + { + x.Write(sw, "filter"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List filterField; @@ -6857,23 +7045,30 @@ public static CT_PivotFilter Parse(XmlNode node, XmlNamespaceManager namespaceMa internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - XmlHelper.WriteAttribute(sw, "fld", this.fld); - XmlHelper.WriteAttribute(sw, "mpFld", this.mpFld); - XmlHelper.WriteAttribute(sw, "type", this.type.ToString()); - XmlHelper.WriteAttribute(sw, "evalOrder", this.evalOrder); - XmlHelper.WriteAttribute(sw, "id", this.id); - XmlHelper.WriteAttribute(sw, "iMeasureHier", this.iMeasureHier); - XmlHelper.WriteAttribute(sw, "iMeasureFld", this.iMeasureFld); - XmlHelper.WriteAttribute(sw, "name", this.name); - XmlHelper.WriteAttribute(sw, "description", this.description); - XmlHelper.WriteAttribute(sw, "stringValue1", this.stringValue1); - XmlHelper.WriteAttribute(sw, "stringValue2", this.stringValue2); - sw.Write(">"); - if (this.autoFilter != null) - this.autoFilter.Write(sw, "autoFilter"); - if (this.extLst != null) - this.extLst.Write(sw, "extLst"); - sw.Write(string.Format("", nodeName)); + XmlHelper.WriteAttribute(sw, "fld", this.fld, true); + XmlHelper.WriteAttribute(sw, "mpFld", this.mpFld, false); + XmlHelper.WriteAttribute(sw, "type", this.type.ToString(), true); + XmlHelper.WriteAttribute(sw, "evalOrder", this.evalOrder, false); + XmlHelper.WriteAttribute(sw, "id", this.id, true); + XmlHelper.WriteAttribute(sw, "iMeasureHier", this.iMeasureHier, false); + XmlHelper.WriteAttribute(sw, "iMeasureFld", this.iMeasureFld, true); + XmlHelper.WriteAttribute(sw, "name", this.name, false); + XmlHelper.WriteAttribute(sw, "description", this.description, false); + XmlHelper.WriteAttribute(sw, "stringValue1", this.stringValue1, false); + XmlHelper.WriteAttribute(sw, "stringValue2", this.stringValue2, false); + if (this.autoFilter == null && this.extLst == null) + { + sw.Write("/>"); + } + else + { + sw.Write(">"); + if (this.autoFilter != null) + this.autoFilter.Write(sw, "autoFilter"); + if (this.extLst != null) + this.extLst.Write(sw, "extLst"); + sw.Write(string.Format("", nodeName)); + } } private CT_AutoFilter autoFilterField; @@ -6910,7 +7105,6 @@ internal void Write(StreamWriter sw, string nodeName) public CT_PivotFilter() { - this.extLstField = new CT_ExtensionList(); this.autoFilterField = new CT_AutoFilter(); this.evalOrderField = 0; } @@ -7360,15 +7554,22 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.rowHierarchyUsage != null) + if (this.rowHierarchyUsage == null || this.rowHierarchyUsage.Count == 0) + { + sw.Write("/>"); + } + else { - foreach (CT_HierarchyUsage x in this.rowHierarchyUsage) + sw.Write(">"); + if (this.rowHierarchyUsage != null && this.rowHierarchyUsage.Count > 0) { - x.Write(sw, "rowHierarchyUsage"); + foreach (CT_HierarchyUsage x in this.rowHierarchyUsage) + { + x.Write(sw, "rowHierarchyUsage"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List rowHierarchyUsageField; @@ -7444,9 +7645,8 @@ public static CT_HierarchyUsage Parse(XmlNode node, XmlNamespaceManager namespac internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - XmlHelper.WriteAttribute(sw, "hierarchyUsage", this.hierarchyUsage); - sw.Write(">"); - sw.Write(string.Format("", nodeName)); + XmlHelper.WriteAttribute(sw, "hierarchyUsage", this.hierarchyUsage, true); + sw.Write("/>"); } private int hierarchyUsageField; @@ -7494,15 +7694,22 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "count", this.count); - sw.Write(">"); - if (this.colHierarchyUsage != null) + if (this.colHierarchyUsage == null || this.colHierarchyUsage.Count == 0) + { + sw.Write("/>"); + } + else { - foreach (CT_HierarchyUsage x in this.colHierarchyUsage) + sw.Write(">"); + if (this.colHierarchyUsage != null && this.colHierarchyUsage.Count > 0) { - x.Write(sw, "colHierarchyUsage"); + foreach (CT_HierarchyUsage x in this.colHierarchyUsage) + { + x.Write(sw, "colHierarchyUsage"); + } } + sw.Write(string.Format("", nodeName)); } - sw.Write(string.Format("", nodeName)); } private List colHierarchyUsageField; diff --git a/OpenXmlFormats/Spreadsheet/Sheet.cs b/OpenXmlFormats/Spreadsheet/Sheet.cs index b47649b68..8e4b8f0b8 100644 --- a/OpenXmlFormats/Spreadsheet/Sheet.cs +++ b/OpenXmlFormats/Spreadsheet/Sheet.cs @@ -1633,12 +1633,12 @@ public static CT_PivotArea Parse(XmlNode node, XmlNamespaceManager namespaceMana ctObj.field = XmlHelper.ReadInt(node.Attributes["field"]); if (node.Attributes["type"] != null) ctObj.type = (ST_PivotAreaType)Enum.Parse(typeof(ST_PivotAreaType), node.Attributes["type"].Value); - ctObj.dataOnly = XmlHelper.ReadBool(node.Attributes["dataOnly"]); + ctObj.dataOnly = XmlHelper.ReadBool(node.Attributes["dataOnly"], true); ctObj.labelOnly = XmlHelper.ReadBool(node.Attributes["labelOnly"]); ctObj.grandRow = XmlHelper.ReadBool(node.Attributes["grandRow"]); ctObj.grandCol = XmlHelper.ReadBool(node.Attributes["grandCol"]); ctObj.cacheIndex = XmlHelper.ReadBool(node.Attributes["cacheIndex"]); - ctObj.outline = XmlHelper.ReadBool(node.Attributes["outline"]); + ctObj.outline = XmlHelper.ReadBool(node.Attributes["outline"], true); ctObj.offset = XmlHelper.ReadString(node.Attributes["offset"]); ctObj.collapsedLevelsAreSubtotals = XmlHelper.ReadBool(node.Attributes["collapsedLevelsAreSubtotals"]); if (node.Attributes["axis"] != null) @@ -1658,21 +1658,22 @@ internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); XmlHelper.WriteAttribute(sw, "field", this.field); - XmlHelper.WriteAttribute(sw, "type", this.type.ToString()); - XmlHelper.WriteAttribute(sw, "dataOnly", this.dataOnly); - XmlHelper.WriteAttribute(sw, "labelOnly", this.labelOnly); - XmlHelper.WriteAttribute(sw, "grandRow", this.grandRow); - XmlHelper.WriteAttribute(sw, "grandCol", this.grandCol); - XmlHelper.WriteAttribute(sw, "cacheIndex", this.cacheIndex); - XmlHelper.WriteAttribute(sw, "outline", this.outline); + if (this.type != ST_PivotAreaType.normal) + XmlHelper.WriteAttribute(sw, "type", this.type.ToString()); + XmlHelper.WriteAttribute(sw, "dataOnly", this.dataOnly, false, true); + XmlHelper.WriteAttribute(sw, "labelOnly", this.labelOnly, false); + XmlHelper.WriteAttribute(sw, "grandRow", this.grandRow, false); + XmlHelper.WriteAttribute(sw, "grandCol", this.grandCol, false); + XmlHelper.WriteAttribute(sw, "cacheIndex", this.cacheIndex, false); + XmlHelper.WriteAttribute(sw, "outline", this.outline, false, true); XmlHelper.WriteAttribute(sw, "offset", this.offset); - XmlHelper.WriteAttribute(sw, "collapsedLevelsAreSubtotals", this.collapsedLevelsAreSubtotals); + XmlHelper.WriteAttribute(sw, "collapsedLevelsAreSubtotals", this.collapsedLevelsAreSubtotals, false); XmlHelper.WriteAttribute(sw, "axis", this.axis.ToString()); XmlHelper.WriteAttribute(sw, "fieldPosition", this.fieldPosition); sw.Write(">"); if (this.references != null) this.references.Write(sw, "references"); - if (this.extLst != null) + if (this.extLst != null && this.extLst.ext.Count != 0) this.extLst.Write(sw, "extLst"); sw.Write(string.Format("", nodeName)); } @@ -2058,23 +2059,23 @@ public static CT_PivotAreaReference Parse(XmlNode node, XmlNamespaceManager name internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - XmlHelper.WriteAttribute(sw, "field", this.field); + XmlHelper.WriteAttribute(sw, "field", this.field, true); XmlHelper.WriteAttribute(sw, "count", this.count); - XmlHelper.WriteAttribute(sw, "selected", this.selected); - XmlHelper.WriteAttribute(sw, "byPosition", this.byPosition); - XmlHelper.WriteAttribute(sw, "relative", this.relative); - XmlHelper.WriteAttribute(sw, "defaultSubtotal", this.defaultSubtotal); - XmlHelper.WriteAttribute(sw, "sumSubtotal", this.sumSubtotal); - XmlHelper.WriteAttribute(sw, "countASubtotal", this.countASubtotal); - XmlHelper.WriteAttribute(sw, "avgSubtotal", this.avgSubtotal); - XmlHelper.WriteAttribute(sw, "maxSubtotal", this.maxSubtotal); - XmlHelper.WriteAttribute(sw, "minSubtotal", this.minSubtotal); - XmlHelper.WriteAttribute(sw, "productSubtotal", this.productSubtotal); - XmlHelper.WriteAttribute(sw, "countSubtotal", this.countSubtotal); - XmlHelper.WriteAttribute(sw, "stdDevSubtotal", this.stdDevSubtotal); - XmlHelper.WriteAttribute(sw, "stdDevPSubtotal", this.stdDevPSubtotal); - XmlHelper.WriteAttribute(sw, "varSubtotal", this.varSubtotal); - XmlHelper.WriteAttribute(sw, "varPSubtotal", this.varPSubtotal); + XmlHelper.WriteAttribute(sw, "selected", this.selected, false, true); + XmlHelper.WriteAttribute(sw, "byPosition", this.byPosition, false); + XmlHelper.WriteAttribute(sw, "relative", this.relative, false); + XmlHelper.WriteAttribute(sw, "defaultSubtotal", this.defaultSubtotal, false); + XmlHelper.WriteAttribute(sw, "sumSubtotal", this.sumSubtotal, false); + XmlHelper.WriteAttribute(sw, "countASubtotal", this.countASubtotal, false); + XmlHelper.WriteAttribute(sw, "avgSubtotal", this.avgSubtotal, false); + XmlHelper.WriteAttribute(sw, "maxSubtotal", this.maxSubtotal, false); + XmlHelper.WriteAttribute(sw, "minSubtotal", this.minSubtotal, false); + XmlHelper.WriteAttribute(sw, "productSubtotal", this.productSubtotal, false); + XmlHelper.WriteAttribute(sw, "countSubtotal", this.countSubtotal, false); + XmlHelper.WriteAttribute(sw, "stdDevSubtotal", this.stdDevSubtotal, false); + XmlHelper.WriteAttribute(sw, "stdDevPSubtotal", this.stdDevPSubtotal, false); + XmlHelper.WriteAttribute(sw, "varSubtotal", this.varSubtotal, false); + XmlHelper.WriteAttribute(sw, "varPSubtotal", this.varPSubtotal, false); sw.Write(">"); if (this.extLst != null) this.extLst.Write(sw, "extLst"); @@ -2090,8 +2091,8 @@ internal void Write(StreamWriter sw, string nodeName) public CT_PivotAreaReference() { - this.extLstField = new CT_ExtensionList(); - this.xField = new List(); + //this.extLstField = new CT_ExtensionList(); + //this.xField = new List(); this.selectedField = true; this.byPositionField = false; this.relativeField = false; @@ -2109,6 +2110,7 @@ public CT_PivotAreaReference() this.varPSubtotalField = false; } + [XmlAttribute] public List x { get @@ -2121,6 +2123,7 @@ public List x } } + [XmlAttribute] public CT_ExtensionList extLst { get @@ -2133,6 +2136,7 @@ public CT_ExtensionList extLst } } + [XmlAttribute] public uint field { get @@ -2158,6 +2162,7 @@ public bool fieldSpecified } } + [XmlAttribute] public uint count { get @@ -2183,6 +2188,7 @@ public bool countSpecified } } + [XmlAttribute] [DefaultValue(true)] public bool selected { @@ -2196,6 +2202,7 @@ public bool selected } } + [XmlAttribute] [DefaultValue(false)] public bool byPosition { @@ -2209,6 +2216,7 @@ public bool byPosition } } + [XmlAttribute] [DefaultValue(false)] public bool relative { @@ -2222,6 +2230,7 @@ public bool relative } } + [XmlAttribute] [DefaultValue(false)] public bool defaultSubtotal { @@ -2235,6 +2244,7 @@ public bool defaultSubtotal } } + [XmlAttribute] [DefaultValue(false)] public bool sumSubtotal { @@ -2248,6 +2258,7 @@ public bool sumSubtotal } } + [XmlAttribute] [DefaultValue(false)] public bool countASubtotal { @@ -2261,6 +2272,7 @@ public bool countASubtotal } } + [XmlAttribute] [DefaultValue(false)] public bool avgSubtotal { @@ -2274,6 +2286,7 @@ public bool avgSubtotal } } + [XmlAttribute] [DefaultValue(false)] public bool maxSubtotal { @@ -2287,6 +2300,7 @@ public bool maxSubtotal } } + [XmlAttribute] [DefaultValue(false)] public bool minSubtotal { @@ -2300,6 +2314,7 @@ public bool minSubtotal } } + [XmlAttribute] [DefaultValue(false)] public bool productSubtotal { @@ -2313,6 +2328,7 @@ public bool productSubtotal } } + [XmlAttribute] [DefaultValue(false)] public bool countSubtotal { @@ -2326,6 +2342,7 @@ public bool countSubtotal } } + [XmlAttribute] [DefaultValue(false)] public bool stdDevSubtotal { @@ -2339,6 +2356,7 @@ public bool stdDevSubtotal } } + [XmlAttribute] [DefaultValue(false)] public bool stdDevPSubtotal { @@ -2352,6 +2370,7 @@ public bool stdDevPSubtotal } } + [XmlAttribute] [DefaultValue(false)] public bool varSubtotal { @@ -2365,6 +2384,7 @@ public bool varSubtotal } } + [XmlAttribute] [DefaultValue(false)] public bool varPSubtotal { @@ -2386,6 +2406,7 @@ public class CT_Index private uint vField; + [XmlAttribute()] public uint v { get @@ -2409,7 +2430,7 @@ public static CT_Index Parse(XmlNode node, XmlNamespaceManager namespaceManager) internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - XmlHelper.WriteAttribute(sw, "v", this.v); + XmlHelper.WriteAttribute(sw, "v", this.v, true); sw.Write(">"); sw.Write(string.Format("", nodeName)); } diff --git a/OpenXmlFormats/Spreadsheet/Sheet/CT_Table.cs b/OpenXmlFormats/Spreadsheet/Sheet/CT_Table.cs index 16fbe947d..5648f3d14 100644 --- a/OpenXmlFormats/Spreadsheet/Sheet/CT_Table.cs +++ b/OpenXmlFormats/Spreadsheet/Sheet/CT_Table.cs @@ -198,7 +198,10 @@ internal void Write(StreamWriter sw) this.extLst.Write(sw, "extLst"); sw.Write(""); } - + public bool IsSetAutoFilter + { + get { return this.autoFilterField != null; } + } [XmlElement] public CT_AutoFilter autoFilter { @@ -621,11 +624,21 @@ public bool connectionIdSpecified } } - internal CT_TableStyleInfo AddNewTableStyleInfo() + public CT_TableStyleInfo AddNewTableStyleInfo() { this.tableStyleInfoField = new CT_TableStyleInfo(); return this.tableStyleInfoField; } + + public CT_TableColumns AddNewTableColumns() + { + this.tableColumnsField = new CT_TableColumns(); + return this.tableColumnsField; + } + public bool IsSetTableStyleInfo() + { + return this.tableStyleInfoField != null; + } } [Serializable] [XmlType(Namespace = "http://schemas.openxmlformats.org/spreadsheetml/2006/main")] @@ -658,8 +671,6 @@ public static CT_TableColumns Parse(XmlNode node, XmlNamespaceManager namespaceM return ctObj; } - - internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); @@ -674,7 +685,24 @@ internal void Write(StreamWriter sw, string nodeName) } sw.Write(string.Format("", nodeName)); } - + public CT_TableColumn InsertNewTableColumn(int columnIndex) + { + var newTableColumn = new CT_TableColumn(); + this.tableColumn.Insert(columnIndex,newTableColumn); + return newTableColumn; + } + public List GetTableColumnList() + { + if (this.tableColumnField == null) + { + this.tableColumnField = new List(); + } + return this.tableColumnField; + } + public void RemoveTableColumn(int columnIndex) + { + this.tableColumn.RemoveAt(columnIndex); + } [XmlElement] public List tableColumn { diff --git a/OpenXmlFormats/Spreadsheet/Sheet/CT_Worksheet.cs b/OpenXmlFormats/Spreadsheet/Sheet/CT_Worksheet.cs index 2881e80bf..78cf6949d 100644 --- a/OpenXmlFormats/Spreadsheet/Sheet/CT_Worksheet.cs +++ b/OpenXmlFormats/Spreadsheet/Sheet/CT_Worksheet.cs @@ -183,10 +183,10 @@ public static CT_Worksheet Parse(XmlNode node, XmlNamespaceManager namespaceMana - internal void Write(Stream stream) + internal void Write(Stream stream, bool leaveOpen) { - using (StreamWriter sw = new StreamWriter(stream)) - { + StreamWriter sw = new StreamWriter(stream); + try { sw.Write(""); sw.Write(""); + sw.Flush(); + } finally + { + if (!leaveOpen ) + { + sw?.Close(); + } } } diff --git a/OpenXmlFormats/Spreadsheet/Styles.cs b/OpenXmlFormats/Spreadsheet/Styles.cs index 3f104e5b8..b66a3d6ad 100644 --- a/OpenXmlFormats/Spreadsheet/Styles.cs +++ b/OpenXmlFormats/Spreadsheet/Styles.cs @@ -622,7 +622,7 @@ public static CT_IntProperty Parse(XmlNode node, XmlNamespaceManager namespaceMa internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - XmlHelper.WriteAttribute(sw, "val", this.val); + XmlHelper.WriteAttribute(sw, "val", this.val, true); sw.Write("/>"); } } diff --git a/OpenXmlFormats/Spreadsheet/Styles/CT_Colors.cs b/OpenXmlFormats/Spreadsheet/Styles/CT_Colors.cs index 5f958b4e4..071b591b3 100644 --- a/OpenXmlFormats/Spreadsheet/Styles/CT_Colors.cs +++ b/OpenXmlFormats/Spreadsheet/Styles/CT_Colors.cs @@ -240,11 +240,10 @@ public bool rgbSpecified } public void SetRgb(byte R, byte G, byte B) { - this.rgbField = new byte[4]; - this.rgbField[0] = 0; - this.rgbField[1] = R; - this.rgbField[2] = G; - this.rgbField[3] = B; + this.rgbField = new byte[3]; + this.rgbField[0] = R; + this.rgbField[1] = G; + this.rgbField[2] = B; rgbSpecified = true; } public bool IsSetRgb() diff --git a/OpenXmlFormats/Spreadsheet/Styles/CT_Dxfs.cs b/OpenXmlFormats/Spreadsheet/Styles/CT_Dxfs.cs index 42985d1c5..d1786dd35 100644 --- a/OpenXmlFormats/Spreadsheet/Styles/CT_Dxfs.cs +++ b/OpenXmlFormats/Spreadsheet/Styles/CT_Dxfs.cs @@ -199,6 +199,10 @@ public CT_Border AddNewBorder() this.borderField = border; return border; } + public bool IsSetNumFmt() + { + return numFmtField != null; + } public bool IsSetFont() { return fontField != null; diff --git a/OpenXmlFormats/Spreadsheet/Styles/CT_Fill.cs b/OpenXmlFormats/Spreadsheet/Styles/CT_Fill.cs index 7cc220b61..cd44f227f 100644 --- a/OpenXmlFormats/Spreadsheet/Styles/CT_Fill.cs +++ b/OpenXmlFormats/Spreadsheet/Styles/CT_Fill.cs @@ -40,6 +40,15 @@ public CT_PatternFill AddNewPatternFill() this.patternFillField = new CT_PatternFill(); return GetPatternFill(); } + public CT_GradientFill AddNewGradientFill() + { + this.gradientFillField = new CT_GradientFill(); + return this.gradientFillField; + } + public void UnsetPatternFill() + { + this.patternFillField = null; + } public bool IsSetPatternFill() { return this.patternFillField != null; diff --git a/OpenXmlFormats/Spreadsheet/Workbook/CT_PivotCache.cs b/OpenXmlFormats/Spreadsheet/Workbook/CT_PivotCache.cs index 6543cc9a0..2b627e882 100644 --- a/OpenXmlFormats/Spreadsheet/Workbook/CT_PivotCache.cs +++ b/OpenXmlFormats/Spreadsheet/Workbook/CT_PivotCache.cs @@ -102,7 +102,7 @@ public static CT_PivotCache Parse(XmlNode node, XmlNamespaceManager namespaceMan internal void Write(StreamWriter sw, string nodeName) { sw.Write(string.Format("<{0}", nodeName)); - XmlHelper.WriteAttribute(sw, "cacheId", this.cacheId); + XmlHelper.WriteAttribute(sw, "cacheId", this.cacheId, true); XmlHelper.WriteAttribute(sw, "r:id", this.id); sw.Write(">"); sw.Write(string.Format("", nodeName)); diff --git a/OpenXmlFormats/Spreadsheet/Workbook/CT_WebPublishObjects.cs b/OpenXmlFormats/Spreadsheet/Workbook/CT_WebPublishObjects.cs index 89ed133f0..c3ce69654 100644 --- a/OpenXmlFormats/Spreadsheet/Workbook/CT_WebPublishObjects.cs +++ b/OpenXmlFormats/Spreadsheet/Workbook/CT_WebPublishObjects.cs @@ -6,55 +6,52 @@ using System.Text; using System.Xml; using System.Xml.Serialization; +using EnumsNET; namespace NPOI.OpenXmlFormats.Spreadsheet -{ - +{ public enum ST_TargetScreenSize { - - - [XmlEnum("544x376")] + [Description("544x376")] Item544x376, - - [XmlEnum("640x480")] + [Description("640x480")] Item640x480, - [XmlEnum("720x512")] + [Description("720x512")] Item720x512, - [XmlEnum("800x600")] + [Description("800x600")] Item800x600, - [XmlEnum("1024x768")] + [Description("1024x768")] Item1024x768, - [XmlEnum("1152x882")] + [Description("1152x882")] Item1152x882, - [XmlEnum("1152x900")] + [Description("1152x900")] Item1152x900, - [XmlEnum("1280x1024")] + [Description("1280x1024")] Item1280x1024, - [XmlEnum("1600x1200")] + [Description("1600x1200")] Item1600x1200, - [XmlEnum("1800x1440")] + [Description("1800x1440")] Item1800x1440, - [XmlEnum("1920x1200")] + [Description("1920x1200")] Item1920x1200, } [Serializable] @@ -90,7 +87,9 @@ public static CT_WebPublishing Parse(XmlNode node, XmlNamespaceManager namespace ctObj.vml = XmlHelper.ReadBool(node.Attributes["vml"]); ctObj.allowPng = XmlHelper.ReadBool(node.Attributes["allowPng"]); if (node.Attributes["targetScreenSize"] != null) - ctObj.targetScreenSize = (ST_TargetScreenSize)Enum.Parse(typeof(ST_TargetScreenSize), node.Attributes["targetScreenSize"].Value); + { + ctObj.targetScreenSize = Enums.Parse(node.Attributes["targetScreenSize"].Value,false, EnumFormat.Description); + } ctObj.dpi = XmlHelper.ReadUInt(node.Attributes["dpi"]); ctObj.codePage = XmlHelper.ReadUInt(node.Attributes["codePage"]); return ctObj; diff --git a/OpenXmlFormats/Spreadsheet/Workbook/CT_Workbook.cs b/OpenXmlFormats/Spreadsheet/Workbook/CT_Workbook.cs index bae040809..55f7720ef 100644 --- a/OpenXmlFormats/Spreadsheet/Workbook/CT_Workbook.cs +++ b/OpenXmlFormats/Spreadsheet/Workbook/CT_Workbook.cs @@ -113,10 +113,15 @@ public static CT_Workbook Parse(XmlNode node, XmlNamespaceManager namespaceManag internal void Write(StreamWriter sw) { sw.Write(""); - sw.Write(""); + sw.Write(""); if (this.fileVersion != null) this.fileVersion.Write(sw, "fileVersion"); if (this.fileSharing != null) diff --git a/OpenXmlFormats/Vml/CT_AlternateContent.cs b/OpenXmlFormats/Vml/CT_AlternateContent.cs new file mode 100644 index 000000000..ebe447748 --- /dev/null +++ b/OpenXmlFormats/Vml/CT_AlternateContent.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Xml; + +namespace NPOI.OpenXmlFormats.Vml +{ + public class CT_AlternateContent + { + public string InnerXml { get; set; } + public CT_AlternateContent() + { + } + public static CT_AlternateContent Parse(XmlNode node, XmlNamespaceManager namespaceManager) + { + if (node == null) + return null; + + var ac = new CT_AlternateContent(); + if (string.IsNullOrEmpty(node.InnerXml)) + { + return ac; + } + ac.InnerXml = node.InnerXml; + return ac; + } + internal void Write(StreamWriter sw, string nodeName) + { + sw.Write(string.Format("", nodeName)); + } + else + { + sw.Write(">"); + sw.Write(this.InnerXml); + sw.Write(string.Format("", nodeName)); + } + } + } +} diff --git a/OpenXmlFormats/Vml/SpreadsheetDrawing.cs b/OpenXmlFormats/Vml/SpreadsheetDrawing.cs index 2170c06e6..01710a493 100644 --- a/OpenXmlFormats/Vml/SpreadsheetDrawing.cs +++ b/OpenXmlFormats/Vml/SpreadsheetDrawing.cs @@ -9,42 +9,6 @@ namespace NPOI.OpenXmlFormats.Vml.Spreadsheet { - public class CT_AlternateContent - { - public string innerXml { get; set; } - public CT_AlternateContent() - { - } - public static CT_AlternateContent Parse(XmlNode node, XmlNamespaceManager namespaceManager) - { - if (node == null) - return null; - - var ac = new CT_AlternateContent(); - if (string.IsNullOrEmpty(node.InnerXml)) - { - return ac; - } - ac.innerXml = node.InnerXml; - return ac; - } - internal void Write(StreamWriter sw, string nodeName) - { - sw.Write(string.Format("", nodeName)); - } - else - { - sw.Write(">"); - sw.Write(this.innerXml); - sw.Write(string.Format("", nodeName)); - } - - } - - } [System.ComponentModel.DesignerCategory("code")] public class CT_ClientData { diff --git a/OpenXmlFormats/Wordprocessing/FormField.cs b/OpenXmlFormats/Wordprocessing/FormField.cs index 1377dddb1..e35d2d0a7 100644 --- a/OpenXmlFormats/Wordprocessing/FormField.cs +++ b/OpenXmlFormats/Wordprocessing/FormField.cs @@ -120,9 +120,6 @@ internal void Write(StreamWriter sw, string nodeName) [XmlRoot(Namespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main", IsNullable = true)] public class CT_FldChar { - - private object itemField; - private ST_FldCharType fldCharTypeField; private ST_OnOff fldLockField; diff --git a/OpenXmlFormats/Wordprocessing/HdrFtr.cs b/OpenXmlFormats/Wordprocessing/HdrFtr.cs index 425c71a1d..23e287052 100644 --- a/OpenXmlFormats/Wordprocessing/HdrFtr.cs +++ b/OpenXmlFormats/Wordprocessing/HdrFtr.cs @@ -832,6 +832,17 @@ public CT_FtnEdn AddNewFootnote() footnoteField.Add(f); return f; } + public void RemoveFootnote(int pos) + { + this.footnoteField.RemoveAt(pos); + } + public int SizeOfFootnoteArray + { + get + { + return this.footnoteField.Count; + } + } } @@ -849,7 +860,7 @@ public class CT_FtnEdn private bool typeFieldSpecified; - private string idField = string.Empty; + private int idField = -1; public static CT_FtnEdn Parse(XmlNode node, XmlNamespaceManager namespaceManager) { @@ -858,7 +869,7 @@ public static CT_FtnEdn Parse(XmlNode node, XmlNamespaceManager namespaceManager CT_FtnEdn ctObj = new CT_FtnEdn(); if (node.Attributes["w:type"] != null) ctObj.type = (ST_FtnEdn)Enum.Parse(typeof(ST_FtnEdn), node.Attributes["w:type"].Value); - ctObj.id = XmlHelper.ReadString(node.Attributes["w:id"]); + ctObj.id = XmlHelper.ReadInt(node.Attributes["w:id"]); foreach (XmlNode childNode in node.ChildNodes) { @@ -1175,7 +1186,7 @@ public bool typeSpecified } [XmlAttribute(Form = XmlSchemaForm.Qualified, DataType = "integer", Namespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main")] - public string id + public int id { get { diff --git a/OpenXmlFormats/Wordprocessing/Paragraph.cs b/OpenXmlFormats/Wordprocessing/Paragraph.cs index 462e9c485..2a96d793f 100644 --- a/OpenXmlFormats/Wordprocessing/Paragraph.cs +++ b/OpenXmlFormats/Wordprocessing/Paragraph.cs @@ -4555,6 +4555,13 @@ public CT_OnOff AddNewB() return this.bField; } + public CT_Shd AddNewShd() + { + if (this.shdField == null) + this.shdField = new CT_Shd(); + return this.shdField; + } + public CT_OnOff AddNewBCs() { if (this.bCsField == null) @@ -4759,6 +4766,13 @@ public bool IsSetSpacing() return this.spacingField != null; } + public CT_Highlight AddNewHighlight() + { + if (this.highlightField == null) + this.highlightField = new CT_Highlight(); + return this.highlightField; + } + public CT_SignedTwipsMeasure AddNewSpacing() { if (this.spacingField == null) @@ -4770,12 +4784,6 @@ public bool IsSetHighlight() { return this.highlightField != null; } - - internal CT_Highlight AddNewHighlight() - { - this.highlightField = new CT_Highlight(); - return this.highlightField; - } } diff --git a/OpenXmlFormats/Wordprocessing/Run.cs b/OpenXmlFormats/Wordprocessing/Run.cs index c84c6b54f..a3de32cd6 100644 --- a/OpenXmlFormats/Wordprocessing/Run.cs +++ b/OpenXmlFormats/Wordprocessing/Run.cs @@ -20,7 +20,6 @@ public class CT_R { private CT_RPr rPrField; - private ArrayList itemsField; private List itemsElementNameField; @@ -30,6 +29,8 @@ public class CT_R private byte[] rsidDelField; private byte[] rsidRField; + + Vml.CT_AlternateContent alternateContentField = null; public CT_R() { @@ -50,6 +51,17 @@ public CT_RPr rPr this.rPrField = value; } } + public Vml.CT_AlternateContent alternateContent + { + get + { + return alternateContentField; + } + set + { + this.alternateContentField = value; + } + } [XmlElement("annotationRef", typeof(CT_Empty), Order = 1)] [XmlElement("br", typeof(CT_Br), Order = 1)] @@ -165,6 +177,23 @@ public CT_RPr AddNewRPr() return this.rPrField; } + + public CT_Empty AddNewFootnoteRef() + { + return AddNewObject(RunItemsChoiceType.footnoteRef); + } + public IList GetFootnoteRefList() + { + return GetObjectList(RunItemsChoiceType.footnoteRef); + } + public CT_Empty GetFootnoteRefArray(int pos) + { + return GetObjectArray(pos, RunItemsChoiceType.footnoteRef); + } + public CT_FtnEdnRef AddNewFootnoteReference() + { + return AddNewObject(RunItemsChoiceType.footnoteReference); + } public CT_Empty AddNewTab() { return AddNewObject(RunItemsChoiceType.tab); @@ -373,10 +402,13 @@ public static CT_R Parse(XmlNode node, XmlNamespaceManager namespaceManager) ctObj.rsidRPr = XmlHelper.ReadBytes(node.Attributes["w:rsidRPr"]); ctObj.rsidDel = XmlHelper.ReadBytes(node.Attributes["w:rsidDel"]); ctObj.rsidR = XmlHelper.ReadBytes(node.Attributes["w:rsidR"]); + foreach (XmlNode childNode in node.ChildNodes) { if (childNode.LocalName == "rPr") + { ctObj.rPr = CT_RPr.Parse(childNode, namespaceManager); + } else if (childNode.LocalName == "instrText") { ctObj.Items.Add(CT_Text.Parse(childNode, namespaceManager)); @@ -442,6 +474,10 @@ public static CT_R Parse(XmlNode node, XmlNamespaceManager namespaceManager) ctObj.Items.Add(CT_Drawing.Parse(childNode, namespaceManager)); ctObj.ItemsElementName.Add(RunItemsChoiceType.drawing); } + else if (childNode.LocalName == "AlternateContent") + { + ctObj.alternateContent = Vml.CT_AlternateContent.Parse(childNode, namespaceManager); + } else if (childNode.LocalName == "endnoteRef") { ctObj.Items.Add(new CT_Empty()); @@ -550,6 +586,7 @@ internal void Write(StreamWriter sw, string nodeName) sw.Write(">"); if (this.rPr != null) this.rPr.Write(sw, "rPr"); + int i = 0; foreach (object o in this.Items) { @@ -619,6 +656,10 @@ internal void Write(StreamWriter sw, string nodeName) sw.Write(""); i++; } + if (this.alternateContent != null) + { + this.alternateContent.Write(sw, "AlternateContent"); + } sw.Write(string.Format("", nodeName)); } @@ -632,6 +673,11 @@ public IList GetTabList() { return GetObjectList(RunItemsChoiceType.tab); } + + public IList GetFootnoteReferenceList() + { + return GetObjectList(RunItemsChoiceType.footnoteReference); + } } diff --git a/OpenXmlFormats/Wordprocessing/Table.cs b/OpenXmlFormats/Wordprocessing/Table.cs index 9c0d769c3..a1f629ab4 100644 --- a/OpenXmlFormats/Wordprocessing/Table.cs +++ b/OpenXmlFormats/Wordprocessing/Table.cs @@ -6,7 +6,8 @@ using System.Xml; using System.Collections; using NPOI.OpenXml4Net.Util; - +using System.Linq; +using NPOI.Util; namespace NPOI.OpenXmlFormats.Wordprocessing { @@ -1176,6 +1177,10 @@ public class CT_TblPrBase private CT_ShortHexNumber tblLookField; + private CT_String tblCaptionField; + + private CT_String tblDescriptionField; + public CT_TblPrBase() { } @@ -1216,6 +1221,10 @@ public static CT_TblPrBase Parse(XmlNode node, XmlNamespaceManager namespaceMana ctObj.tblCellMar = CT_TblCellMar.Parse(childNode, namespaceManager); else if (childNode.LocalName == "tblLook") ctObj.tblLook = CT_ShortHexNumber.Parse(childNode, namespaceManager); + else if (childNode.LocalName == "tblCaption") + ctObj.tblCaption = CT_String.Parse(childNode, namespaceManager); + else if (childNode.LocalName == "tblDescription") + ctObj.tblDescription = CT_String.Parse(childNode, namespaceManager); } return ctObj; } @@ -1256,6 +1265,10 @@ internal void Write(StreamWriter sw, string nodeName) this.tblCellMar.Write(sw, "tblCellMar"); if (this.tblLook != null) this.tblLook.Write(sw, "tblLook"); + if (this.tblCaption != null) + this.tblCaption.Write(sw, "tblCaption"); + if (this.tblDescription != null) + this.tblDescription.Write(sw, "tblDescription"); sw.Write(string.Format("", nodeName)); } @@ -1454,6 +1467,32 @@ public CT_ShortHexNumber tblLook } } + [XmlElement(Order = 15)] + public CT_String tblCaption + { + get + { + return this.tblCaptionField; + } + set + { + this.tblCaptionField = value; + } + } + + [XmlElement(Order = 16)] + public CT_String tblDescription + { + get + { + return this.tblDescriptionField; + } + set + { + this.tblDescriptionField = value; + } + } + public bool IsSetTblW() { return this.tblW != null; @@ -2776,6 +2815,10 @@ public static new CT_TblPr Parse(XmlNode node, XmlNamespaceManager namespaceMana ctObj.tblCellMar = CT_TblCellMar.Parse(childNode, namespaceManager); else if (childNode.LocalName == "tblLook") ctObj.tblLook = CT_ShortHexNumber.Parse(childNode, namespaceManager); + else if (childNode.LocalName == "tblCaption") + ctObj.tblCaption = CT_String.Parse(childNode, namespaceManager); + else if (childNode.LocalName == "tblDescription") + ctObj.tblDescription = CT_String.Parse(childNode, namespaceManager); } return ctObj; } @@ -2818,6 +2861,10 @@ internal new void Write(StreamWriter sw, string nodeName) this.tblCellMar.Write(sw, "tblCellMar"); if (this.tblLook != null) this.tblLook.Write(sw, "tblLook"); + if (this.tblCaption != null) + this.tblCaption.Write(sw, "tblCaption"); + if (this.tblDescription != null) + this.tblDescription.Write(sw, "tblDescription"); sw.Write(string.Format("", nodeName)); } @@ -3838,9 +3885,7 @@ public class CT_TrPr : CT_TrPrBase public CT_TrPr() { - //this.trPrChangeField = new CT_TrPrChange(); - //this.delField = new CT_TrackChange(); - //this.insField = new CT_TrackChange(); + } public static new CT_TrPr Parse(XmlNode node, XmlNamespaceManager namespaceManager) { @@ -5678,6 +5723,21 @@ internal void Write(StreamWriter sw, string nodeName) } sw.Write(string.Format("", nodeName)); } + public CT_Row Copy() + { + CT_Row ctRow = new CT_Row(); + ctRow.paraIdField = this.paraIdField?.ToArray(); + ctRow.rsidRField = this.rsidRField?.ToArray(); + ctRow.rsidDelField = this.rsidDelField?.ToArray(); + ctRow.rsidRPrField = this.rsidRPrField?.ToArray(); + ctRow.rsidTrField = this.rsidTrField?.ToArray(); + ctRow.textIdField = this.textIdField?.ToArray(); + ctRow.trPrField = this.trPrField?.Copy(); + ctRow.tblPrExField = this.tblPrExField?.Copy(); + ctRow.itemsElementNameField = this.itemsElementNameField.Copy(); + ctRow.itemsField = this.itemsField.Copy(); + return ctRow; + } public void RemoveTc(int pos) { RemoveObject(ItemsChoiceTableRowType.tc, pos); diff --git a/README.md b/README.md index 2e8d1bcca..a98f0cee1 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,33 @@ +## Statement about Russian Invasion War ## + +This project fully supports Ukraine people to fight against Russian army. This is definitely an invasion. Ukraine are actually China's friend for a long time. Most core parts of China aircraft carrier, airplane are provided by Ukraine companies. I DON'T see any reason that we should support Russia instead Ukraine. + +However, I don't wanna stop Russian developers from using NPOI. They are also victims. They cannot change Putin's or Russia Government's mind in any case. But if possible, Russian developers may help impact your government although it's risky. Thank you! + NPOI =================== [![NuGet Badge](https://buildstats.info/nuget/NPOI)](https://www.nuget.org/packages/NPOI) [![Ko-Fi](https://img.shields.io/static/v1?style=flat-square&message=Support%20the%20Project&color=success&style=plastic&logo=ko-fi&label=$$)](https://ko-fi.com/tonyqus) -[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg?style=flat-square&logo=Apache)](License.md) -[![Badge](https://img.shields.io/badge/link-996.icu-red.svg)](https://996.icu/#/en_US) +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg?style=flat-square&logo=Apache)](LICENSE) [![traffic](https://api.segment.io/v1/pixel/track?data=ewogICJ3cml0ZUtleSI6ICJBV2NjaWd1UkhKODBuNkJ4WlI4cHRaRzBINzY0RmJObCIsCiAgInVzZXJJZCI6ICJ0b255cXVzIiwKICAiZXZlbnQiOiAiTlBPSSBIb21lcGFnZSIKfQ== )](#) + + GitHub contributors +
This project is the .NET version of POI Java project. With NPOI, you can read/write Office 2003/2007 files very easily.
+[Who is using NPOI?](https://github.com/nissl-lab/npoi/issues/705) + +Telegram User Group +================ +Join us on telegram: https://t.me/npoidevs + +NOTE: QQ or wechat is not recommended. + Get Started with NPOI ============ [Getting Started with NPOI](https://github.com/nissl-lab/npoi/wiki/Getting-Started-with-NPOI) @@ -17,21 +36,17 @@ Get Started with NPOI [ORM on NPOI](https://github.com/nissl-lab/npoi/wiki/ORM-on-NPOI) -[Stop using Dotnetcore/NPOI nuget package. It’s obsolete!](https://tonyqus.medium.com/stop-using-dotnetcore-npoi-nuget-package-its-too-obsolete-6d0aeedb3319) - -[The real history of Dotnetcore.NPOI](https://tonyqus.medium.com/the-real-history-of-dotnetcore-npoi-999bb5e140c7) +[NPOI Changelog](https://github.com/nissl-lab/npoi/wiki/Changelog) -[中国哪些公司在用.NET](https://github.com/dotnet-cn/jobs) +Replace DotnetCore.NPOI with NPOI ASAP +=========== +NPOI NEVER joins China NCC (.NET Core Community) group. They are cheating. The readme.md in Dotnetcore.npoi repo is full of lies. What they want to do is just to destory NPOI since they cannot make use of reputation of this component any more. That's why I'm always saying they are evil. The whole NCC group is evil. -[起底开源邪教NCC组织](https://github.com/nissl-lab/npoi/wiki/起底开源邪教NCC组织) +NPOI从未加入过中国NCC开源组织,他们在欺骗公众!Dotnetcore.npoi的readme.md完全是诽谤,一堆谎言。他们想做的无非就是想毁掉NPOI,因为他们不能再用NPOI来行骗了。这也是我为什么一直说他们很邪恶,整个NCC组织就是一个邪教。 -[NPOI Changelog](https://github.com/nissl-lab/npoi/wiki/Changelog) - -Telegram User Group -================ -Join us on telegram: https://t.me/npoidevs +[Stop using Dotnetcore/NPOI nuget package. It’s obsolete!](https://tonyqus.medium.com/stop-using-dotnetcore-npoi-nuget-package-its-too-obsolete-6d0aeedb3319) -NOTE: QQ or wechat is not recommended. +[The real history of Dotnetcore.NPOI](https://tonyqus.medium.com/the-real-history-of-dotnetcore-npoi-999bb5e140c7) [中文版](https://zhuanlan.zhihu.com/p/506975972) Advantage of NPOI ================= @@ -59,3 +74,5 @@ System Requirement .NET Standard 2.0 (.NET Core 2.x) .NET Framework 4.0 and above + +No Loongson CPU (NPOI will NOT support any issues running on LoognArch architecture. This CPU is a shit) diff --git a/logo/nexmeetup_qrcode.png b/logo/nexmeetup_qrcode.png deleted file mode 100644 index 82ddba803..000000000 Binary files a/logo/nexmeetup_qrcode.png and /dev/null differ diff --git a/main/HSSF/Model/InternalWorkbook.cs b/main/HSSF/Model/InternalWorkbook.cs index 3213b6da7..6dc7c4a12 100644 --- a/main/HSSF/Model/InternalWorkbook.cs +++ b/main/HSSF/Model/InternalWorkbook.cs @@ -74,6 +74,7 @@ public class InternalWorkbook "Workbook", // as per BIFF8 spec "WORKBOOK", // Typically from third party programs "BOOK", // Typically odd Crystal Reports exports + "WorkBook", // Another third party program special }; /** * Name of older (pre-Excel 97) Workbook streams, which @@ -656,10 +657,6 @@ public void SetSheetName(int sheetnum, String sheetname) { CheckSheets(sheetnum); - // YK: Mimic Excel and silently truncate sheet names longer than 31 characters - if (sheetname.Length > 31) - sheetname = sheetname.Substring(0, 31); - BoundSheetRecord sheet =boundsheets[sheetnum]; sheet.Sheetname=sheetname; } diff --git a/main/HSSF/Record/Aggregates/RowRecordsAggregate.cs b/main/HSSF/Record/Aggregates/RowRecordsAggregate.cs index 2a2a8fb61..cfd926e42 100644 --- a/main/HSSF/Record/Aggregates/RowRecordsAggregate.cs +++ b/main/HSSF/Record/Aggregates/RowRecordsAggregate.cs @@ -41,13 +41,17 @@ public class RowRecordsAggregate : RecordAggregate private SortedList _rowRecords; //private int size = 0; private ValueRecordsAggregate _valuesAgg; + private List _hyperlinkRecordRecords; private List _unknownRecords; private SharedValueManager _sharedValueManager; // Cache values to speed up performance of // getStartRowNumberForBlock / getEndRowNumberForBlock, see Bugzilla 47405 private RowRecord[] _rowRecordValues = null; - + public IEnumerable HyperlinkRecordRecords + { + get { return _hyperlinkRecordRecords; } + } /** Creates a new instance of ValueRecordsAggregate */ @@ -60,6 +64,7 @@ private RowRecordsAggregate(SharedValueManager svm) { _rowRecords = new SortedList(); _valuesAgg = new ValueRecordsAggregate(); + _hyperlinkRecordRecords = new List(); _unknownRecords = new List(); _sharedValueManager = svm; } @@ -124,6 +129,10 @@ public override void VisitContainedRecords(RecordVisitor rv) // Calculate Offset from the start of a DBCellRecord to the first Row cellRecord.RowOffset = (pos); rv.VisitRecord(cellRecord); + } + foreach (Record _hyperlinkRecord in _hyperlinkRecordRecords) + { + rv.VisitRecord(_hyperlinkRecord); } foreach (Record _unknownRecord in _unknownRecords) { @@ -149,6 +158,9 @@ public RowRecordsAggregate(RecordStream rs, SharedValueManager svm) case DConRefRecord.sid: AddUnknownRecord(rec); continue; + case HyperlinkRecord.sid: + _hyperlinkRecordRecords.Add((HyperlinkRecord)rec); + continue; case DBCellRecord.sid: // end of 'Row Block'. Should only occur after cell records // ignore DBCELL records because POI generates them upon re-serialization diff --git a/main/HSSF/Record/CFRule12Record.cs b/main/HSSF/Record/CFRule12Record.cs index 17ba7651f..c11e2e769 100644 --- a/main/HSSF/Record/CFRule12Record.cs +++ b/main/HSSF/Record/CFRule12Record.cs @@ -484,6 +484,17 @@ protected override int DataSize public CellRangeAddress GetAssociatedRange() { return futureHeader.AssociatedRange; } + + public int Priority + { + get + { + return priority; + } + set { + this.priority = value; + } + } } } \ No newline at end of file diff --git a/main/HSSF/Record/Crypto/Biff8EncryptionKey.cs b/main/HSSF/Record/Crypto/Biff8EncryptionKey.cs index d69ae4f38..13631e065 100644 --- a/main/HSSF/Record/Crypto/Biff8EncryptionKey.cs +++ b/main/HSSF/Record/Crypto/Biff8EncryptionKey.cs @@ -135,7 +135,7 @@ internal RC4 CreateRC4(int keyBlockNo) { using (MD5 md5 = new MD5CryptoServiceProvider()) { - using (MemoryStream baos = new MemoryStream(4)) + using (MemoryStream baos = RecyclableMemory.GetStream(4)) { new LittleEndianOutputStream(baos).WriteInt(keyBlockNo); byte[] baosToArray = baos.ToArray(); diff --git a/main/HSSF/Record/DrawingRecordForBiffViewer.cs b/main/HSSF/Record/DrawingRecordForBiffViewer.cs index 66f9f2f1e..be6a0facb 100644 --- a/main/HSSF/Record/DrawingRecordForBiffViewer.cs +++ b/main/HSSF/Record/DrawingRecordForBiffViewer.cs @@ -48,7 +48,7 @@ public DrawingRecordForBiffViewer(DrawingRecord r) private static RecordInputStream ConvertToInputStream(DrawingRecord r) { byte[] data = r.Serialize(); - using (MemoryStream ms = new MemoryStream(data)) + using (MemoryStream ms = NPOI.Util.RecyclableMemory.GetStream(data)) { RecordInputStream rinp = new RecordInputStream(ms); rinp.NextRecord(); diff --git a/main/HSSF/Record/EmbeddedObjectRefSubRecord.cs b/main/HSSF/Record/EmbeddedObjectRefSubRecord.cs index 3fd6ec0aa..acf790bd9 100644 --- a/main/HSSF/Record/EmbeddedObjectRefSubRecord.cs +++ b/main/HSSF/Record/EmbeddedObjectRefSubRecord.cs @@ -183,7 +183,7 @@ public override short Sid private static Ptg ReadRefPtg(byte[] formulaRawBytes) { - using (MemoryStream ms = new MemoryStream(formulaRawBytes)) + using (MemoryStream ms = RecyclableMemory.GetStream(formulaRawBytes)) { ILittleEndianInput in1 = new LittleEndianInputStream(ms); byte ptgSid = (byte)in1.ReadByte(); diff --git a/main/HSSF/Record/EscherAggregate.cs b/main/HSSF/Record/EscherAggregate.cs index db2d7f3a3..08329cb03 100644 --- a/main/HSSF/Record/EscherAggregate.cs +++ b/main/HSSF/Record/EscherAggregate.cs @@ -435,84 +435,86 @@ public static EscherAggregate CreateAggregate(List records, int locF IEscherRecordFactory recordFactory = new CustomEscherRecordFactory(shapeRecords); // Create one big buffer - MemoryStream stream = new MemoryStream(); - EscherAggregate agg = new EscherAggregate(false); - int loc = locFirstDrawingRecord; - while (loc + 1 < records.Count - && (IsDrawingLayerRecord(GetSid(records, loc)))) + using (MemoryStream stream = RecyclableMemory.GetStream()) { - try + EscherAggregate agg = new EscherAggregate(false); + int loc = locFirstDrawingRecord; + while (loc + 1 < records.Count + && (IsDrawingLayerRecord(GetSid(records, loc)))) { - if (!(GetSid(records, loc) == DrawingRecord.sid || GetSid(records, loc) == ContinueRecord.sid)) + try { - loc++; - continue; - } - if (GetSid(records, loc) == DrawingRecord.sid) - { - byte[] data = ((DrawingRecord)records[loc]).RecordData; - stream.Write(data, 0, data.Length); + if (!(GetSid(records, loc) == DrawingRecord.sid || GetSid(records, loc) == ContinueRecord.sid)) + { + loc++; + continue; + } + if (GetSid(records, loc) == DrawingRecord.sid) + { + byte[] data = ((DrawingRecord)records[loc]).RecordData; + stream.Write(data, 0, data.Length); + } + else + { + byte[] data = ((ContinueRecord)records[loc]).Data; + stream.Write(data, 0, data.Length); + } } - else + catch (IOException e) { - byte[] data = ((ContinueRecord)records[loc]).Data; - stream.Write(data, 0, data.Length); + throw new RuntimeException("Couldn't get data from drawing/continue records", e); } + loc++; } - catch (IOException e) + + // Decode the shapes + // agg.escherRecords = new ArrayList(); + int pos = 0; + byte[] buffer = stream.ToArray(); + while (pos < buffer.Length) { - throw new RuntimeException("Couldn't get data from drawing/continue records", e); + EscherRecord r = recordFactory.CreateRecord(buffer, pos); + int bytesRead = r.FillFields(buffer, pos, recordFactory); + agg.AddEscherRecord(r); + pos += bytesRead; } - loc++; - } - // Decode the shapes - // agg.escherRecords = new ArrayList(); - int pos = 0; - byte[] buffer = stream.ToArray(); - while (pos < buffer.Length) - { - EscherRecord r = recordFactory.CreateRecord(buffer, pos); - int bytesRead = r.FillFields(buffer, pos, recordFactory); - agg.AddEscherRecord(r); - pos += bytesRead; - } + // Associate the object records with the shapes + loc = locFirstDrawingRecord + 1; + int shapeIndex = 0; - // Associate the object records with the shapes - loc = locFirstDrawingRecord + 1; - int shapeIndex = 0; - - while (loc < records.Count && IsDrawingLayerRecord(GetSid(records, loc))) - { - if (!IsObjectRecord(records, loc)) + while (loc < records.Count && IsDrawingLayerRecord(GetSid(records, loc))) { + if (!IsObjectRecord(records, loc)) + { + loc++; + continue; + } + Record objRecord = (Record)records[loc]; + agg.shapeToObj[shapeRecords[shapeIndex++]] = objRecord; loc++; - continue; - } - Record objRecord = (Record)records[loc]; - agg.shapeToObj[shapeRecords[shapeIndex++]] = objRecord; - loc++; - } - // any NoteRecords that follow the drawing block must be aggregated and and saved in the tailRec collection - //put noterecord into tailsRec - while (loc < records.Count) - { - if (GetSid(records, loc) == NoteRecord.sid) - { - NoteRecord r = (NoteRecord)records[(loc)]; - agg.tailRec[r.ShapeId] = r; } - else + // any NoteRecords that follow the drawing block must be aggregated and and saved in the tailRec collection + //put noterecord into tailsRec + while (loc < records.Count) { - break; + if (GetSid(records, loc) == NoteRecord.sid) + { + NoteRecord r = (NoteRecord)records[(loc)]; + agg.tailRec[r.ShapeId] = r; + } + else + { + break; + } + loc++; } - loc++; + int locLastDrawingRecord = loc; + //records.SubList(locFirstDrawingRecord, locLastDrawingRecord).Clear(); + records.RemoveRange(locFirstDrawingRecord, locLastDrawingRecord - locFirstDrawingRecord); + records.Insert(locFirstDrawingRecord, agg); + return agg; } - int locLastDrawingRecord = loc; - //records.SubList(locFirstDrawingRecord, locLastDrawingRecord).Clear(); - records.RemoveRange(locFirstDrawingRecord, locLastDrawingRecord - locFirstDrawingRecord); - records.Insert(locFirstDrawingRecord, agg); - return agg; } /** diff --git a/main/HSSF/Record/ObjRecord.cs b/main/HSSF/Record/ObjRecord.cs index be8fef792..54e9651c7 100644 --- a/main/HSSF/Record/ObjRecord.cs +++ b/main/HSSF/Record/ObjRecord.cs @@ -92,7 +92,7 @@ public ObjRecord(RecordInputStream in1) // throw new RecordFormatException(msg); //} subrecords = new List(); - using (MemoryStream bais = new MemoryStream(subRecordData)) + using (MemoryStream bais = RecyclableMemory.GetStream(subRecordData)) { LittleEndianInputStream subRecStream = new LittleEndianInputStream(bais); CommonObjectDataSubRecord cmo = (CommonObjectDataSubRecord)SubRecord.CreateSubRecord(subRecStream, 0); diff --git a/main/HSSF/Record/Record.cs b/main/HSSF/Record/Record.cs index 6779b837e..67012a504 100644 --- a/main/HSSF/Record/Record.cs +++ b/main/HSSF/Record/Record.cs @@ -19,7 +19,7 @@ namespace NPOI.HSSF.Record { - + using NPOI.Util; using System; using System.IO; @@ -110,7 +110,7 @@ public Record CloneViaReserialise() // Do it via a re-serialization // It's a cheat, but it works... byte[] b = Serialize(); - using (MemoryStream ms = new MemoryStream(b)) + using (MemoryStream ms = RecyclableMemory.GetStream(b)) { RecordInputStream rinp = new RecordInputStream(ms); rinp.NextRecord(); diff --git a/main/HSSF/Record/RecordInputStream.cs b/main/HSSF/Record/RecordInputStream.cs index b51d1bf5e..02c36d912 100644 --- a/main/HSSF/Record/RecordInputStream.cs +++ b/main/HSSF/Record/RecordInputStream.cs @@ -543,7 +543,7 @@ public byte[] ReadAllContinuedRemainder() { //Using a ByteArrayOutputStream is just an easy way to Get a //growable array of the data. - using (MemoryStream out1 = new MemoryStream(2 * MAX_RECORD_DATA_SIZE)) + using (MemoryStream out1 = RecyclableMemory.GetStream(2 * MAX_RECORD_DATA_SIZE)) { while (true) diff --git a/main/HSSF/Record/SubRecord/SubRecord.cs b/main/HSSF/Record/SubRecord/SubRecord.cs index 2ccfd9fa8..673c8fa74 100644 --- a/main/HSSF/Record/SubRecord/SubRecord.cs +++ b/main/HSSF/Record/SubRecord/SubRecord.cs @@ -65,7 +65,7 @@ public static SubRecord CreateSubRecord(ILittleEndianInput in1, CommonObjectType public byte[] Serialize() { int size = DataSize + 4; - using (MemoryStream baos = new MemoryStream(size)) + using (MemoryStream baos = RecyclableMemory.GetStream(size)) { Serialize(new LittleEndianOutputStream(baos)); if (baos.Length != size) diff --git a/main/HSSF/UserModel/HSSFCell.cs b/main/HSSF/UserModel/HSSFCell.cs index 40f64eb1d..2a3eaea87 100644 --- a/main/HSSF/UserModel/HSSFCell.cs +++ b/main/HSSF/UserModel/HSSFCell.cs @@ -32,6 +32,7 @@ namespace NPOI.HSSF.UserModel using System.Globalization; using System.Collections.Generic; using NPOI.Util; + using NPOI.SS.Formula.Eval; /// /// High level representation of a cell in a row of a spReadsheet. @@ -515,6 +516,20 @@ public void SetCellValue(DateTime value) SetCellValue(DateUtil.GetExcelDate(value, this.book.IsDate1904())); } +#if NET6_0_OR_GREATER + /// + /// Set a date value for the cell. Excel treats dates as numeric so you will need to format the cell as + /// a date. + /// + /// the date value to Set this cell to. For formulas we'll Set the + /// precalculated value, for numerics we'll Set its value. For other types we + /// will Change the cell to a numeric cell and Set its value. + public void SetCellValue(DateOnly value) + { + SetCellValue(DateUtil.GetExcelDate(value, this.book.IsDate1904())); + } +#endif + /// /// Set a string value for the cell. Please note that if you are using @@ -651,7 +666,78 @@ public String CellFormula SetCellFormula(value); } } + /// + /// Called when this an array formula in this cell is deleted. + /// + /// a customized exception message for the case if deletion of the cell is impossible. If null, a default message will be generated + internal void TryToDeleteArrayFormula(String message) + { + if (!IsPartOfArrayFormulaGroup) + return; + CellRangeAddress arrayFormulaRange = ArrayFormulaRange; + if (arrayFormulaRange.NumberOfCells > 1) + { + if (message == null) + { + message = "Cell " + new CellReference(this).FormatAsString() + " is part of a multi-cell array formula. " + + "You cannot change part of an array."; + } + throw new InvalidOperationException(message); + } + //un-register the single-cell array formula from the parent sheet through public interface + Row.Sheet.RemoveArrayFormula(this); + } + public void RemoveFormula() + { + if (CellType != CellType.Formula) + { + return; + } + + if (IsPartOfArrayFormulaGroup) + { + TryToDeleteArrayFormula(null); + return; + } + NotifyFormulaChanging(); + + switch (CachedFormulaResultType) + { + case CellType.Numeric: + double numericValue = ((FormulaRecordAggregate)_record).FormulaRecord.Value; + _record = new NumberRecord(); + ((NumberRecord)_record).Value = numericValue; + cellType = CellType.Numeric; + break; + case CellType.String: + _record = new NumberRecord(); + ((NumberRecord)_record).Value = 0; + cellType = CellType.String; + break; + case CellType.Boolean: + bool booleanValue = ((FormulaRecordAggregate)_record).FormulaRecord.CachedBooleanValue; + _record = new BoolErrRecord(); + ((BoolErrRecord)_record).SetValue(booleanValue); + cellType = CellType.Boolean; + break; + case CellType.Error: + byte errorValue = (byte)((FormulaRecordAggregate)_record).FormulaRecord.CachedErrorValue; + _record = new BoolErrRecord(); + try + { + ((BoolErrRecord)_record).SetValue(errorValue); + } + catch (ArgumentException) + { + ((BoolErrRecord)_record).SetValue((byte)ErrorEval.REF_INVALID.ErrorCode); + } + cellType = CellType.Error; + break; + default: + throw new InvalidOperationException(); + } + } public void SetCellFormula(String formula) { if (IsPartOfArrayFormulaGroup) diff --git a/main/HSSF/UserModel/HSSFConditionalFormattingRule.cs b/main/HSSF/UserModel/HSSFConditionalFormattingRule.cs index bbad8d0e1..62e8ad4c4 100644 --- a/main/HSSF/UserModel/HSSFConditionalFormattingRule.cs +++ b/main/HSSF/UserModel/HSSFConditionalFormattingRule.cs @@ -79,13 +79,13 @@ private HSSFFontFormatting GetFontFormatting(bool Create) FontFormatting fontFormatting = cfRuleRecord.FontFormatting; if (fontFormatting != null) { - cfRuleRecord.FontFormatting=(fontFormatting); + cfRuleRecord.FontFormatting = (fontFormatting); return new HSSFFontFormatting(cfRuleRecord, workbook); } else if (Create) { fontFormatting = new FontFormatting(); - cfRuleRecord.FontFormatting=(fontFormatting); + cfRuleRecord.FontFormatting = (fontFormatting); return new HSSFFontFormatting(cfRuleRecord, workbook); } else @@ -116,13 +116,13 @@ private HSSFBorderFormatting GetBorderFormatting(bool Create) BorderFormatting borderFormatting = cfRuleRecord.BorderFormatting; if (borderFormatting != null) { - cfRuleRecord.BorderFormatting=(borderFormatting); + cfRuleRecord.BorderFormatting = (borderFormatting); return new HSSFBorderFormatting(cfRuleRecord, workbook); } else if (Create) { borderFormatting = new BorderFormatting(); - cfRuleRecord.BorderFormatting=(borderFormatting); + cfRuleRecord.BorderFormatting = (borderFormatting); return new HSSFBorderFormatting(cfRuleRecord, workbook); } else @@ -152,13 +152,13 @@ private HSSFPatternFormatting GetPatternFormatting(bool Create) PatternFormatting patternFormatting = cfRuleRecord.PatternFormatting; if (patternFormatting != null) { - cfRuleRecord.PatternFormatting=(patternFormatting); + cfRuleRecord.PatternFormatting = (patternFormatting); return new HSSFPatternFormatting(cfRuleRecord, workbook); } else if (Create) { patternFormatting = new PatternFormatting(); - cfRuleRecord.PatternFormatting=(patternFormatting); + cfRuleRecord.PatternFormatting = (patternFormatting); return new HSSFPatternFormatting(cfRuleRecord, workbook); } else @@ -284,7 +284,7 @@ public IColorScaleFormatting ColorScaleFormatting { return GetColorScaleFormatting(false); } - + } /** * create a new color scale / gradient formatting object if it does not exist, @@ -358,5 +358,48 @@ protected internal static String ToFormulaString(Ptg[] parsedExpression, HSSFWor } return HSSFFormulaParser.ToFormulaString(workbook, parsedExpression); } + public bool StopIfTrue + { + get + { + return true; + } + } + public string Text + { + get { return null; } + } + public int Priority + { + get { + CFRule12Record rule12 = GetCFRule12Record(false); + if (rule12 == null) return 0; + return rule12.Priority; + } + } + public ExcelNumberFormat NumberFormat + { + get + { + return null; + } + } + public ConditionFilterType? ConditionFilterType + { + get + { + if (ConditionType == ConditionType.Filter) + return null; + else + return SS.UserModel.ConditionFilterType.FILTER; + } + } + public IConditionFilterData FilterConfiguration + { + get + { + return null; + } + } } } \ No newline at end of file diff --git a/main/HSSF/UserModel/HSSFEvaluationCell.cs b/main/HSSF/UserModel/HSSFEvaluationCell.cs index d15512d6b..58083d1a6 100644 --- a/main/HSSF/UserModel/HSSFEvaluationCell.cs +++ b/main/HSSF/UserModel/HSSFEvaluationCell.cs @@ -21,6 +21,7 @@ namespace NPOI.HSSF.UserModel { using System; using NPOI.SS.Formula; + using NPOI.SS.Util; /// /// HSSF wrapper for a cell under evaluation @@ -130,5 +131,19 @@ public CellType CachedFormulaResultType { get { return _cell.CachedFormulaResultType; } } + + public bool IsPartOfArrayFormulaGroup + { + get + { + return _cell.IsPartOfArrayFormulaGroup; + } + } + + public CellRangeAddress ArrayFormulaRange + { + + get { return _cell.ArrayFormulaRange; } + } } } \ No newline at end of file diff --git a/main/HSSF/UserModel/HSSFPicture.cs b/main/HSSF/UserModel/HSSFPicture.cs index ce53506d3..98123b624 100644 --- a/main/HSSF/UserModel/HSSFPicture.cs +++ b/main/HSSF/UserModel/HSSFPicture.cs @@ -208,7 +208,7 @@ public Size GetImageDimension() byte[] data = bse.BlipRecord.PictureData; //int type = bse.BlipTypeWin32; - using (MemoryStream ms = new MemoryStream(data)) + using (MemoryStream ms = RecyclableMemory.GetStream(data)) { using (Image img = Image.FromStream(ms)) { diff --git a/main/HSSF/UserModel/HSSFShape.cs b/main/HSSF/UserModel/HSSFShape.cs index 7bcf5c43c..9d8bf20a4 100644 --- a/main/HSSF/UserModel/HSSFShape.cs +++ b/main/HSSF/UserModel/HSSFShape.cs @@ -387,7 +387,7 @@ public int RotationDegree { get { - using (MemoryStream bos = new MemoryStream()) + using (MemoryStream bos = RecyclableMemory.GetStream()) { EscherSimpleProperty property = (EscherSimpleProperty)GetOptRecord().Lookup(EscherProperties.TRANSFORM__ROTATION); if (null == property) diff --git a/main/HSSF/UserModel/HSSFSheet.cs b/main/HSSF/UserModel/HSSFSheet.cs index 10e08457a..95351e126 100644 --- a/main/HSSF/UserModel/HSSFSheet.cs +++ b/main/HSSF/UserModel/HSSFSheet.cs @@ -1535,16 +1535,16 @@ public void ShiftRows(int startRow, int endRow, int n, bool copyRowHeight, bool // Nothing to do return; } - - NoteRecord[] noteRecs; - // Shift comments + // Move comments from the source row to the + // destination row. Note that comments can + // exist for cells which are null + // If the row shift would shift the comments off the sheet + // (above the first row or below the last row), this code will shift the + // comments to the first or last row, rather than moving them out of + // bounds or deleting them if (moveComments) { - noteRecs = _sheet.GetNoteRecords(); - } - else - { - noteRecs = NoteRecord.EMPTY_ARRAY; + moveCommentsForRowShift(startRow, endRow, n); } RowShifter rowShifter = new HSSFRowShifter(this); // Shift Merged Regions @@ -1552,21 +1552,7 @@ public void ShiftRows(int startRow, int endRow, int n, bool copyRowHeight, bool // Shift Row Breaks _sheet.PageSettings.ShiftRowBreaks(startRow, endRow, n); - - // Delete overwritten hyperlinks - int firstOverwrittenRow = startRow + n; - int lastOverwrittenRow = endRow + n; - foreach (HSSFHyperlink link in GetHyperlinkList()) - { - // If hyperlink is fully contained in the rows that will be overwritten, delete the hyperlink - if (firstOverwrittenRow <= link.FirstRow && - link.FirstRow <= lastOverwrittenRow && - lastOverwrittenRow <= link.LastRow && - link.LastRow <= lastOverwrittenRow) - { - RemoveHyperlink(link); - } - } + deleteOverwrittenHyperlinksForRowShift(startRow, endRow, n); for (int rowNum = s; rowNum >= startRow && rowNum <= endRow && rowNum >= 0 && rowNum < 65536; rowNum += inc) { @@ -1624,32 +1610,42 @@ public void ShiftRows(int startRow, int endRow, int n, bool copyRowHeight, bool } // Now zap all the cells in the source row row.RemoveAllCells(); + } + // Re-compute the first and last rows of the sheet as needed + recomputeFirstAndLastRowsForRowShift(startRow, endRow, n); + + //if (endRow == lastrow || endRow + n > lastrow) lastrow = Math.Min(endRow + n, SpreadsheetVersion.EXCEL97.LastRowIndex); + //if (startRow == firstrow || startRow + n < firstrow) firstrow = Math.Max(startRow + n, 0); - // Move comments from the source row to the - // destination row. Note that comments can - // exist for cells which are null - if (moveComments) + int sheetIndex = _workbook.GetSheetIndex(this); + String sheetName = _workbook.GetSheetName(sheetIndex); + int externSheetIndex = book.CheckExternSheet(sheetIndex); + FormulaShifter formulaShifter = FormulaShifter.CreateForRowShift(externSheetIndex, sheetName, startRow, endRow, n, SpreadsheetVersion.EXCEL97); + // Update formulas that refer to rows that have been moved + updateFormulasForShift(formulaShifter); + } + private void updateFormulasForShift(FormulaShifter formulaShifter) + { + int sheetIndex = _workbook.GetSheetIndex(this); + int externSheetIndex = book.CheckExternSheet(sheetIndex); + + _sheet.UpdateFormulasAfterCellShift(formulaShifter, externSheetIndex); + + int nSheets = _workbook.NumberOfSheets; + for (int i = 0; i < nSheets; i++) + { + InternalSheet otherSheet = ((HSSFSheet)_workbook.GetSheetAt(i)).Sheet; + if (otherSheet == this._sheet) { - // This code would get simpler if NoteRecords could be organised by HSSFRow. - HSSFPatriarch patriarch = CreateDrawingPatriarch() as HSSFPatriarch; - int lastChildIndex = patriarch.Children.Count - 1; - for (int i = lastChildIndex; i >= 0; i--) - { - HSSFShape shape = patriarch.Children[(i)]; - if (!(shape is HSSFComment)) - { - continue; - } - HSSFComment comment = (HSSFComment)shape; - if (comment.Row != rowNum) - { - continue; - } - comment.Row = (rowNum + n); - } + continue; } + int otherExtSheetIx = book.CheckExternSheet(i); + otherSheet.UpdateFormulasAfterCellShift(formulaShifter, otherExtSheetIx); } - // Re-compute the first and last rows of the sheet as needed + _workbook.Workbook.UpdateNamesAfterCellShift(formulaShifter); + } + private void recomputeFirstAndLastRowsForRowShift(int startRow, int endRow, int n) + { if (n > 0) { // Rows are moving down @@ -1692,31 +1688,48 @@ public void ShiftRows(int startRow, int endRow, int n, bool copyRowHeight, bool } } } - //if (endRow == lastrow || endRow + n > lastrow) lastrow = Math.Min(endRow + n, SpreadsheetVersion.EXCEL97.LastRowIndex); - //if (startRow == firstrow || startRow + n < firstrow) firstrow = Math.Max(startRow + n, 0); - - // Update any formulas on this _sheet that point to - // rows which have been moved - int sheetIndex = _workbook.GetSheetIndex(this); - String sheetName = _workbook.GetSheetName(sheetIndex); - int externSheetIndex = book.CheckExternSheet(sheetIndex); - FormulaShifter shifter = FormulaShifter.CreateForRowShift(externSheetIndex, sheetName, startRow, endRow, n, SpreadsheetVersion.EXCEL97); - _sheet.UpdateFormulasAfterCellShift(shifter, externSheetIndex); - - int nSheets = _workbook.NumberOfSheets; - for (int i = 0; i < nSheets; i++) + } + private void deleteOverwrittenHyperlinksForRowShift(int startRow, int endRow, int n) + { + int firstOverwrittenRow = startRow + n; + int lastOverwrittenRow = endRow + n; + foreach (HSSFHyperlink link in GetHyperlinkList()) { - InternalSheet otherSheet = ((HSSFSheet)_workbook.GetSheetAt(i)).Sheet; - if (otherSheet == this._sheet) + // If hyperlink is fully contained in the rows that will be overwritten, delete the hyperlink + if (firstOverwrittenRow <= link.FirstRow && + link.FirstRow <= lastOverwrittenRow && + lastOverwrittenRow <= link.LastRow && + link.LastRow <= lastOverwrittenRow) + { + RemoveHyperlink(link); + } + } + } + private void moveCommentsForRowShift(int startRow, int endRow, int n) + { + HSSFPatriarch patriarch = CreateDrawingPatriarch() as HSSFPatriarch; + int lastChildIndex = patriarch.Children.Count - 1; + for (int i = lastChildIndex; i >= 0; i--) + { + HSSFShape shape = patriarch.Children[(i)]; + if (!(shape is HSSFComment)) { continue; } - int otherExtSheetIx = book.CheckExternSheet(i); - otherSheet.UpdateFormulasAfterCellShift(shifter, otherExtSheetIx); + HSSFComment comment = (HSSFComment)shape; + int r = comment.Row; + if (startRow <= r && r <= endRow) + { + comment.Row = clip(r + n); + } } - _workbook.Workbook.UpdateNamesAfterCellShift(shifter); } - + private static int clip(int row) + { + return Math.Min( + Math.Max(0, row), + SpreadsheetVersion.EXCEL97.LastRowIndex); + } /// /// Inserts the chart records. /// @@ -2419,6 +2432,15 @@ public IHyperlink GetHyperlink(int row, int column) { return new HSSFHyperlink(link); } + } + else if (rec is RowRecordsAggregate rra) { + foreach (var link in rra.HyperlinkRecordRecords) + { + if (link.FirstColumn == column && link.FirstRow == row) + { + return new HSSFHyperlink(link); + } + } } } return null; @@ -2448,6 +2470,14 @@ public List GetHyperlinkList() if (rec is HyperlinkRecord){ HyperlinkRecord link = (HyperlinkRecord)rec; hyperlinkList.Add(new HSSFHyperlink(link)); + } + else if (rec is RowRecordsAggregate rra) { + foreach (var link in rra.HyperlinkRecordRecords) + { + if (link is HyperlinkRecord hylink){ + hyperlinkList.Add(new HSSFHyperlink(link)); + } + } } } return hyperlinkList; diff --git a/main/HSSF/UserModel/HSSFWorkbook.cs b/main/HSSF/UserModel/HSSFWorkbook.cs index 596a2e176..0b72923bb 100644 --- a/main/HSSF/UserModel/HSSFWorkbook.cs +++ b/main/HSSF/UserModel/HSSFWorkbook.cs @@ -877,7 +877,9 @@ public ISheet CreateSheet(String sheetname) if (workbook.ContainsSheetName(sheetname, _sheets.Count)) throw new ArgumentException("The workbook already contains a sheet named '" + sheetname + "'"); - HSSFSheet sheet = new HSSFSheet(this); + WorkbookUtil.ValidateSheetName(sheetname); + + HSSFSheet sheet = new HSSFSheet(this); workbook.SetSheetName(_sheets.Count, sheetname); _sheets.Add(sheet); @@ -1346,19 +1348,7 @@ public override void Write(FileInfo newFile) fs.Close(); } } - - /// - /// Write out this workbook to an Outputstream. Constructs - /// a new POI POIFSFileSystem, passes in the workbook binary representation and - /// Writes it out. - /// - /// If {@code stream} is a {@link java.io.FileOutputStream} on a networked drive - /// or has a high cost/latency associated with each written byte, - /// consider wrapping the OutputStream in a {@link java.io.BufferedOutputStream} - /// to improve write performance. - /// - /// - /// the java OutputStream you wish to Write the XLS to + public override void Write(Stream stream) { NPOIFSFileSystem fs = new NPOIFSFileSystem(); @@ -1372,6 +1362,16 @@ public override void Write(Stream stream) fs.Close(); } } + /// + /// Write out this workbook to an Outputstream. Constructs + /// a new POI POIFSFileSystem, passes in the workbook binary representation and + /// Writes it out. + /// + /// the stream you wish to Write the XLS to + public void Write(Stream stream, bool leaveOpen) + { + this.Write(stream); + } /** Writes the workbook out to a brand new, empty POIFS */ private void Write(NPOIFSFileSystem fs) @@ -1403,7 +1403,7 @@ private void Write(NPOIFSFileSystem fs) // going to be preserving nodes List excepts = new List(1); - using (MemoryStream newMemoryStream = new MemoryStream(GetBytes())) + using (MemoryStream newMemoryStream = RecyclableMemory.GetStream(GetBytes())) { // Write out the Workbook stream fs.CreateDocument(newMemoryStream, "Workbook"); @@ -2028,9 +2028,11 @@ public int AddOlePackage(POIFSFileSystem poiData, String label, String fileName, } } - MemoryStream bos = new MemoryStream(); - poiData.WriteFileSystem(bos); - return AddOlePackage(bos.ToArray(), label, fileName, command); + using (MemoryStream bos = RecyclableMemory.GetStream()) + { + poiData.WriteFileSystem(bos); + return AddOlePackage(bos.ToArray(), label, fileName, command); + } } public int AddOlePackage(byte[] oleData, String label, String fileName, String command) @@ -2062,9 +2064,11 @@ public int AddOlePackage(byte[] oleData, String label, String fileName, String c oleDir.CreateDocument("\u0001Ole", new MemoryStream(oleBytes)); Ole10Native oleNative = new Ole10Native(label, fileName, command, oleData); - MemoryStream bos = new MemoryStream(); - oleNative.WriteOut(bos); - oleDir.CreateDocument(Ole10Native.OLE10_NATIVE, new MemoryStream(bos.ToArray())); + using (MemoryStream bos = RecyclableMemory.GetStream()) + { + oleNative.WriteOut(bos); + oleDir.CreateDocument(Ole10Native.OLE10_NATIVE, new MemoryStream(bos.ToArray())); + } return storageId; } diff --git a/main/HSSF/UserModel/Helpers/HSSFRowColShifter.cs b/main/HSSF/UserModel/Helpers/HSSFRowColShifter.cs new file mode 100644 index 000000000..06e33288c --- /dev/null +++ b/main/HSSF/UserModel/Helpers/HSSFRowColShifter.cs @@ -0,0 +1,97 @@ +using NPOI.SS.Formula; +using NPOI.SS.Formula.PTG; +using NPOI.SS.UserModel; +using NPOI.Util; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.HSSF.UserModel.Helpers +{ + public class HSSFRowColShifter + { + private static POILogger log = POILogFactory.GetLogger(typeof(HSSFRowColShifter)); + + /// + /// Update formulas. + /// + /// + /// + public static void UpdateFormulas(ISheet sheet, FormulaShifter formulaShifter) + { + //update formulas on the parent sheet + UpdateSheetFormulas(sheet, formulaShifter); + + //update formulas on other sheets + IWorkbook wb = sheet.Workbook; + foreach (ISheet sh in wb) + { + if (sheet == sh) continue; + UpdateSheetFormulas(sh, formulaShifter); + } + } + public static void UpdateSheetFormulas(ISheet sh, FormulaShifter formulashifter) + { + foreach (IRow r in sh) + { + HSSFRow row = (HSSFRow)r; + UpdateRowFormulas(row, formulashifter); + } + } + /// + /// Update the formulas in specified row using the formula shifting policy specified by shifter + /// + /// the row to update the formulas on + /// the formula shifting policy + public static void UpdateRowFormulas(IRow row, FormulaShifter formulaShifter) + { + ISheet sheet = row.Sheet; + foreach (ICell c in row) + { + HSSFCell cell = (HSSFCell)c; + String formula = cell.CellFormula; + if (formula.Length > 0) + { + String shiftedFormula = ShiftFormula(row, formula, formulaShifter); + cell.SetCellFormula(shiftedFormula); + } + } + } + /// + /// Shift a formula using the supplied FormulaShifter + /// + /// the row of the cell this formula belongs to. Used to get a reference to the parent workbook. + /// the formula to shift + /// the FormulaShifter object that operates on the parsed formula tokens + /// the shifted formula if the formula was changed, null if the formula wasn't modified + public static String ShiftFormula(IRow row, String formula, FormulaShifter formulaShifter) + { + ISheet sheet = row.Sheet; + IWorkbook wb = sheet.Workbook; + int sheetIndex = wb.GetSheetIndex(sheet); + int rowIndex = row.RowNum; + HSSFEvaluationWorkbook fpb = HSSFEvaluationWorkbook.Create((HSSFWorkbook)wb); + + try + { + Ptg[] ptgs = FormulaParser.Parse(formula, fpb, FormulaType.Cell, sheetIndex, rowIndex); + String shiftedFmla; + if (formulaShifter.AdjustFormula(ptgs, sheetIndex)) + { + shiftedFmla = FormulaRenderer.ToFormulaString(fpb, ptgs); + } + else + { + shiftedFmla = formula; + } + return shiftedFmla; + } + catch (FormulaParseException fpe) + { + // Log, but don't change, rather than breaking + log.Log(POILogger.ERROR, "Error shifting formula on row "+row.RowNum.ToString(),fpe); + return formula; + } + } + } +} diff --git a/main/HSSF/UserModel/Helpers/HSSFRowShifter.cs b/main/HSSF/UserModel/Helpers/HSSFRowShifter.cs index 481f04a8d..adcea94e3 100644 --- a/main/HSSF/UserModel/Helpers/HSSFRowShifter.cs +++ b/main/HSSF/UserModel/Helpers/HSSFRowShifter.cs @@ -20,6 +20,7 @@ namespace NPOI.HSSF.UserModel.helpers using System; using NPOI.HSSF.UserModel; + using NPOI.HSSF.UserModel.Helpers; using NPOI.SS.Formula; using NPOI.SS.Formula.Eval; using NPOI.SS.UserModel; @@ -52,9 +53,9 @@ public override void UpdateFormulas(FormulaShifter Shifter) } - public override void UpdateRowFormulas(IRow row, FormulaShifter Shifter) + public override void UpdateRowFormulas(IRow row, FormulaShifter formulaShifter) { - throw new NotImplementedException("updateRowFormulas"); + HSSFRowColShifter.UpdateRowFormulas(row, formulaShifter); } public override void UpdateConditionalFormatting(FormulaShifter Shifter) diff --git a/main/NPOI.Core.csproj b/main/NPOI.Core.csproj index f6533e4f5..88d64c0ec 100644 --- a/main/NPOI.Core.csproj +++ b/main/NPOI.Core.csproj @@ -1,7 +1,7 @@  - netstandard2.0;netstandard2.1 + netstandard2.0;netstandard2.1;net6.0 false NPOI NPOI @@ -23,8 +23,11 @@ + + + - + @@ -32,4 +35,4 @@ - + \ No newline at end of file diff --git a/main/NPOI.csproj b/main/NPOI.csproj index 01351d704..5b1ebd328 100644 --- a/main/NPOI.csproj +++ b/main/NPOI.csproj @@ -73,7 +73,7 @@ TRACE;HIDE_UNREACHABLE_CODE ..\solution\Lib\.net45\NPOI.XML true - 1591 + 1591;1587;1570 pdbonly AnyCPU 7.3 @@ -217,6 +217,7 @@ + @@ -282,21 +283,36 @@ + + + + + + + + + + + + + + + @@ -311,8 +327,19 @@ + + + + + + + + + + + @@ -321,7 +348,9 @@ + + @@ -502,7 +531,15 @@ + + + + + + + + @@ -1117,7 +1154,6 @@ - @@ -1308,6 +1344,7 @@ + @@ -1357,11 +1394,20 @@ + + 4.0.0 + + + 4.15.0 + + + 1.4.1 + 1.8.9 - 1.3.2 + 1.3.3 diff --git a/main/POIFS/Storage/HeaderBlockWriter.cs b/main/POIFS/Storage/HeaderBlockWriter.cs index bc3d6f5d0..b6146fb77 100644 --- a/main/POIFS/Storage/HeaderBlockWriter.cs +++ b/main/POIFS/Storage/HeaderBlockWriter.cs @@ -172,23 +172,24 @@ public void WriteBlocks(Stream stream) public void WriteBlock(ByteBuffer block) { - MemoryStream ms = new MemoryStream(_header_block.BigBlockSize.GetBigBlockSize()); - - _header_block.WriteData(ms); + using (MemoryStream ms = RecyclableMemory.GetStream(_header_block.BigBlockSize.GetBigBlockSize())) + { + _header_block.WriteData(ms); - block.Write(ms.ToArray()); + block.Write(ms.ToArray()); + } } public void WriteBlock(byte[] block) { - MemoryStream ms = new MemoryStream(_header_block.BigBlockSize.GetBigBlockSize()); - - _header_block.WriteData(ms); + using (MemoryStream ms = RecyclableMemory.GetStream(_header_block.BigBlockSize.GetBigBlockSize())) + { + _header_block.WriteData(ms); - //block = ms.ToArray(); - byte[] temp = ms.ToArray(); - Array.Copy(temp, 0, block, 0, temp.Length); + byte[] temp = ms.ToArray(); + Array.Copy(temp, 0, block, 0, temp.Length); + } } } } diff --git a/main/POIFS/Storage/SmallDocumentBlock.cs b/main/POIFS/Storage/SmallDocumentBlock.cs index 1dc6c8247..71137ced2 100644 --- a/main/POIFS/Storage/SmallDocumentBlock.cs +++ b/main/POIFS/Storage/SmallDocumentBlock.cs @@ -148,7 +148,7 @@ public static int Fill(POIFSBigBlockSize bigBlockSize,IList BlockWritable [] store, int size) { - using (MemoryStream stream = new MemoryStream()) + using (MemoryStream stream = Util.RecyclableMemory.GetStream()) { for (int j = 0; j < store.Length; j++) @@ -156,11 +156,11 @@ public static int Fill(POIFSBigBlockSize bigBlockSize,IList store[j].WriteBlocks(stream); } byte[] data = stream.ToArray(); - SmallDocumentBlock[] rval = new SmallDocumentBlock[ ConvertToBlockCount(size) ]; + SmallDocumentBlock[] rval = new SmallDocumentBlock[ConvertToBlockCount(size)]; for (int index = 0; index < rval.Length; index++) { - rval[index] = new SmallDocumentBlock(bigBlocksSize,data, index); + rval[index] = new SmallDocumentBlock(bigBlocksSize, data, index); } return rval; } diff --git a/main/Properties/AssemblyInfo.cs b/main/Properties/AssemblyInfo.cs index 203e9bc0c..a68e2de2a 100644 --- a/main/Properties/AssemblyInfo.cs +++ b/main/Properties/AssemblyInfo.cs @@ -33,8 +33,8 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("2.5.5.0")] -[assembly: AssemblyFileVersion("2.5.5.0")] +[assembly: AssemblyVersion("2.6.0.0")] +[assembly: AssemblyFileVersion("2.6.0.0")] [assembly: AssemblyInformationalVersion("2.0.0.0")] [assembly: InternalsVisibleTo("NPOI.TestCases, PublicKey=002400000480000094000000060200000024000052534131000400000100010095ccd95af3b39d8bc20544d3f47fd24b53ebc5ccb693eaed116290629f8cd882c827ebd511ad59449224f0718d3f9d03b64945a6c8b6644266001b8c8426185330e3d96da70ae16d4acc21b8d4d480f1385c7e924273179375aa88f81380a72fb115712a313379d16aed4aa36208ee3b4a5dd785b06a07b2d868e3227f4495b5", AllInternalsVisible = true)] diff --git a/main/SS/Formula/Atp/AnalysisToolPak.cs b/main/SS/Formula/Atp/AnalysisToolPak.cs index 9db9f5a20..449f646f3 100644 --- a/main/SS/Formula/Atp/AnalysisToolPak.cs +++ b/main/SS/Formula/Atp/AnalysisToolPak.cs @@ -78,7 +78,7 @@ public override FreeRefFunction FindFunction(String name) r(m, "AVERAGEIFS", AverageIfs.instance); r(m, "BAHTTEXT", null); r(m, "BESSELI", null); - r(m, "BESSELJ", null); + r(m, "BESSELJ", BesselJ.instance); r(m, "BESSELK", null); r(m, "BESSELY", null); r(m, "BIN2DEC", Bin2Dec.instance); @@ -107,8 +107,8 @@ public override FreeRefFunction FindFunction(String name) r(m, "DEC2OCT", null); r(m, "DELTA", Delta.instance); r(m, "DISC", null); - r(m, "DOLLARDE", null); - r(m, "DOLLARFR", null); + r(m, "DOLLARDE", DollarDe.instance); + r(m, "DOLLARFR", DollarFr.instance); r(m, "DURATION", null); r(m, "EDATE", EDate.Instance); r(m, "EFFECT", null); @@ -154,6 +154,11 @@ public override FreeRefFunction FindFunction(String name) r(m, "MULTINOMIAL", null); r(m, "NETWORKDAYS", NetworkdaysFunction.instance); r(m, "NOMINAL", null); + r(m, "NORM.DIST", NormDist.instance); + r(m, "NORM.S.DIST", NormSDist.instance); + r(m, "NORM.INV", NormInv.instance); + r(m, "NORM.S.INV", NormSInv.instance); + r(m, "NUMBERVALUE", NumberValueFunction.instance); r(m, "OCT2BIN", null); r(m, "OCT2DEC", Oct2Dec.instance); r(m, "OCT2HEX", null); @@ -178,7 +183,10 @@ public override FreeRefFunction FindFunction(String name) r(m, "TEXTJOIN", TextJoinFunction.instance); r(m, "WEEKNUM", WeekNum.instance); r(m, "WORKDAY", WorkdayFunction.instance); + r(m, "WORKDAY.INTL", WorkdayIntlFunction.instance); r(m, "XIRR", null); + r(m, "XLOOKUP", XLookupFunction.instance); + r(m, "XMATCH", XMatchFunction.instance); r(m, "XNPV", null); r(m, "YEARFRAC", YearFrac.instance); r(m, "YIELD", null); diff --git a/main/SS/Formula/Atp/IfError.cs b/main/SS/Formula/Atp/IfError.cs index 0c30ba7bb..140da53ad 100644 --- a/main/SS/Formula/Atp/IfError.cs +++ b/main/SS/Formula/Atp/IfError.cs @@ -57,15 +57,7 @@ private static ValueEval EvaluateInternal(ValueEval arg, ValueEval iferror, int arg = WorkbookEvaluator.DereferenceResult(arg, srcCellRow, srcCellCol); if (arg is ErrorEval) { - //if the 2nd argument is missing, use an empty string as default - if (iferror is MissingArgEval) - { - return new StringEval(string.Empty); - } - else - { - return iferror; - } + return iferror; } else { diff --git a/main/SS/Formula/Atp/Switch.cs b/main/SS/Formula/Atp/Switch.cs index 917c578ce..747a7a0ca 100644 --- a/main/SS/Formula/Atp/Switch.cs +++ b/main/SS/Formula/Atp/Switch.cs @@ -23,7 +23,7 @@ public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) { expression = OperandResolver.GetSingleValue(args[0], ec.RowIndex, ec.ColumnIndex); } - catch (Exception e) + catch (Exception) { return ErrorEval.NA; } @@ -51,7 +51,7 @@ public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) } } - catch (EvaluationException e) + catch (EvaluationException) { return ErrorEval.NA; } diff --git a/main/SS/Formula/Atp/WorkdayCalculator.cs b/main/SS/Formula/Atp/WorkdayCalculator.cs index 06c4364e6..b900fac31 100644 --- a/main/SS/Formula/Atp/WorkdayCalculator.cs +++ b/main/SS/Formula/Atp/WorkdayCalculator.cs @@ -15,6 +15,7 @@ limitations under the License. ==================================================================== */ using System; +using System.Collections.Generic; using NPOI.SS.UserModel; namespace NPOI.SS.Formula.Atp { @@ -27,7 +28,7 @@ public class WorkdayCalculator { public static WorkdayCalculator instance = new WorkdayCalculator(); - + private static Dictionary> weekendTypeMap = new Dictionary>(); /** * Constructor. */ @@ -36,6 +37,24 @@ private WorkdayCalculator() // enforcing singleton } + static WorkdayCalculator() + { + weekendTypeMap.Add(1, new List() { 7, 1 }); + weekendTypeMap.Add(2, new List() { 1, 2 }); + weekendTypeMap.Add(3, new List() { 2, 3 }); + weekendTypeMap.Add(4, new List() { 3, 4 }); + weekendTypeMap.Add(5, new List() { 4, 5 }); + weekendTypeMap.Add(6, new List() { 5, 6 }); + weekendTypeMap.Add(7, new List() { 6, 7 }); + weekendTypeMap.Add(11, new List() { 2 }); + weekendTypeMap.Add(12, new List() { 3 }); + weekendTypeMap.Add(13, new List() { 4 }); + weekendTypeMap.Add(14, new List() { 5 }); + weekendTypeMap.Add(15, new List() { 6 }); + weekendTypeMap.Add(16, new List() { 7 }); + weekendTypeMap.Add(17, new List() { 1 }); + } + /** * Calculate how many workdays are there between a start and an end date, as excel representations, considering a range of holidays. * @@ -93,8 +112,61 @@ public DateTime CalculateWorkdays(double start, int workdays, double[] holidays) //} while (skippedDays != 0); return endDate; } + /** + * Calculate the workday past x workdays from a starting date, considering a range of holidays. + * + * @param start start date. + * @param workdays number of workdays to be past from starting date. + * @param weekendType weekend parameter (see https://support.microsoft.com/en-us/office/workday-intl-function-a378391c-9ba7-4678-8a39-39611a9bf81d) + * @param holidays an array of holidays. + * @return date past x workdays. + */ + public DateTime CalculateWorkdays(double start, int workdays, int weekendType, double[] holidays) + { + List weekendDays = new List() { 7, 1 }; + if (weekendTypeMap.ContainsKey(weekendType)) + weekendDays= weekendTypeMap[weekendType]; + DateTime startDate = DateUtil.GetJavaDate(start); + int direction = workdays < 0 ? -1 : 1; + var endDate=startDate; + double excelEndDate = DateUtil.GetExcelDate(endDate); + while (workdays != 0) + { + endDate=endDate.AddDays(6*direction); + excelEndDate += direction; + if (!isWeekend(endDate, weekendDays) && !isHoliday(excelEndDate, holidays)) + { + workdays -= direction; + } + } + return endDate; + } + private bool isWeekend(DateTime date, List weekendDays) + { + return weekendDays.Contains(((int)date.DayOfWeek) + 1); + } /** + * @param aDate a given date. + * @param holidays an array of holidays. + * @return true if date is a holiday, false otherwise. + */ + protected bool isHoliday(double aDate, double[] holidays) + { + foreach (double holiday in holidays) + { + if (Math.Round(holiday) == Math.Round(aDate)) + { + return true; + } + } + return false; + } + public List GetValidWeekendTypes() + { + return new List(weekendTypeMap.Keys); + } + /** * Calculates how many days of week past between a start and an end date. * * @param start start date. diff --git a/main/SS/Formula/Atp/WorkdayIntlFunction.cs b/main/SS/Formula/Atp/WorkdayIntlFunction.cs new file mode 100644 index 000000000..db6547d4b --- /dev/null +++ b/main/SS/Formula/Atp/WorkdayIntlFunction.cs @@ -0,0 +1,64 @@ +using NPOI.SS.Formula.Eval; +using NPOI.SS.Formula.Functions; +using NPOI.SS.UserModel; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.Formula.Atp +{ + public class WorkdayIntlFunction: FreeRefFunction + { + public static FreeRefFunction instance = new WorkdayIntlFunction(ArgumentsEvaluator.instance); + + private ArgumentsEvaluator evaluator; + + private WorkdayIntlFunction(ArgumentsEvaluator anEvaluator) + { + // enforces singleton + this.evaluator = anEvaluator; + } + /** + * Evaluate for WORKDAY. Given a date, a number of days and a optional date or interval of holidays, determines which date it is past + * number of parametrized workdays. + * + * @return {@link ValueEval} with date as its value. + */ + public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) + { + if (args.Length < 2 || args.Length > 4) + { + return ErrorEval.VALUE_INVALID; + } + + int srcCellRow = ec.RowIndex; + int srcCellCol = ec.ColumnIndex; + + double start; + int days; + int weekendType = 1; + double[] holidays; + try + { + start = this.evaluator.EvaluateDateArg(args[0], srcCellRow, srcCellCol); + days = (int)Math.Floor(this.evaluator.EvaluateNumberArg(args[1], srcCellRow, srcCellCol)); + if (args.Length >= 3) + { + weekendType = (int)this.evaluator.EvaluateNumberArg(args[2], srcCellRow, srcCellCol); + if (!WorkdayCalculator.instance.GetValidWeekendTypes().Contains(weekendType)) + { + return ErrorEval.NUM_ERROR; + } + } + ValueEval holidaysCell = args.Length>=4 ? args[3] : null; + holidays = this.evaluator.EvaluateDatesArg(holidaysCell, srcCellRow, srcCellCol); + return new NumberEval(DateUtil.GetExcelDate( + WorkdayCalculator.instance.CalculateWorkdays(start, days, weekendType, holidays))); + } + catch (EvaluationException) + { + return ErrorEval.VALUE_INVALID; + } + } + } +} diff --git a/main/SS/Formula/Atp/XLookupFunction.cs b/main/SS/Formula/Atp/XLookupFunction.cs new file mode 100644 index 000000000..182e5cd9c --- /dev/null +++ b/main/SS/Formula/Atp/XLookupFunction.cs @@ -0,0 +1,277 @@ +using NPOI.SS.Formula.Eval; +using NPOI.SS.Formula.Functions; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.Formula.Atp +{ + class XLookupFunction : FreeRefFunction, ArrayFunction + { + public static FreeRefFunction instance = new XLookupFunction(ArgumentsEvaluator.instance); + + private ArgumentsEvaluator evaluator; + + private XLookupFunction(ArgumentsEvaluator anEvaluator) + { + // enforces singleton + this.evaluator = anEvaluator; + } + public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) + { + int srcRowIndex = ec.RowIndex; + int srcColumnIndex = ec.ColumnIndex; + return _evaluate(args, srcRowIndex, srcColumnIndex, ec.IsSingleValue); + } + + public ValueEval EvaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex) + { + return _evaluate(args, srcRowIndex, srcColumnIndex, false); + } + + private String LaxValueToString(ValueEval eval) + { + return (eval is MissingArgEval) ? "" : OperandResolver.CoerceValueToString(eval); + } + private ValueEval _evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex, bool isSingleValue) + { + if (args.Length < 3) + { + return ErrorEval.VALUE_INVALID; + } + String notFound = null; + if (args.Length > 3) + { + try + { + ValueEval notFoundValue = OperandResolver.GetSingleValue(args[3], srcRowIndex, srcColumnIndex); + String notFoundText = LaxValueToString(notFoundValue); + if (notFoundText != null) + { + String trimmedText = notFoundText.Trim(); + if (trimmedText.Length > 0) + { + notFound = trimmedText; + } + } + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + } + LookupUtils.MatchMode matchMode = LookupUtils.MatchMode.ExactMatch; + if (args.Length > 4) + { + try + { + ValueEval matchModeValue = OperandResolver.GetSingleValue(args[4], srcRowIndex, srcColumnIndex); + int matchInt = OperandResolver.CoerceValueToInt(matchModeValue); + matchMode = LookupUtils.GetMatchMode(matchInt); + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + catch (Exception ) + { + return ErrorEval.VALUE_INVALID; + } + } + LookupUtils.SearchMode searchMode = LookupUtils.SearchMode.IterateForward; + if (args.Length > 5) + { + try + { + ValueEval searchModeValue = OperandResolver.GetSingleValue(args[5], srcRowIndex, srcColumnIndex); + int searchInt = OperandResolver.CoerceValueToInt(searchModeValue); + searchMode = LookupUtils.GetSearchMode(searchInt); + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + catch (Exception) + { + return ErrorEval.VALUE_INVALID; + } + } + return evaluate(srcRowIndex, srcColumnIndex, args[0], args[1], args[2], notFound, matchMode, searchMode, isSingleValue); + } + private ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval lookupEval, ValueEval indexEval, + ValueEval returnEval, String notFound, LookupUtils.MatchMode matchMode, + LookupUtils.SearchMode searchMode, bool isSingleValue) + { + try + { + ValueEval lookupValue = OperandResolver.GetSingleValue(lookupEval, srcRowIndex, srcColumnIndex); + TwoDEval tableArray = LookupUtils.ResolveTableArrayArg(indexEval); + int matchedRow; + try + { + matchedRow = LookupUtils.XlookupIndexOfValue(lookupValue, LookupUtils.CreateColumnVector(tableArray, 0), matchMode, searchMode); + } + catch (EvaluationException e) + { + if (ErrorEval.NA.Equals(e.GetErrorEval())) + { + if (string.IsNullOrEmpty(notFound)) + { + if (returnEval is AreaEval) { + AreaEval area = (AreaEval)returnEval; + int width = area.Width; + if (isSingleValue || width <= 1) + { + return new StringEval(notFound); + } + return new NotFoundAreaEval(notFound, width); + } else + { + return new StringEval(notFound); + } + } + return ErrorEval.NA; + } + else + { + return e.GetErrorEval(); + } + } + if (returnEval is AreaEval) { + AreaEval area = (AreaEval)returnEval; + if (isSingleValue) + { + return area.GetRelativeValue(matchedRow, 0); + } + return area.Offset(matchedRow, matchedRow, 0, area.Width - 1); + } else + { + return returnEval; + } + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + } + + class NotFoundAreaEval : AreaEval + { + private int _width; + private string _notFound; + public NotFoundAreaEval(string notFound, int width) + { + _width = width; + _notFound = notFound; + } + public int FirstRow + { + get { return 0; } + } + + public int LastRow + { + get { return 0; } + } + + public int FirstColumn + { + get { return 0; } + } + + public int LastColumn + { + get { return _width - 1; } + } + + public int Width + { + get { return _width; } + } + + public int Height + { + get { return 1; } + } + + public bool IsRow + { + get { return false; } + } + + public bool IsColumn + { + get { return false; } + } + + public int FirstSheetIndex + { + get { return 0; } + } + + public int LastSheetIndex + { + get { return 0; } + } + + public bool Contains(int row, int col) + { + throw new NotImplementedException(); + } + + public bool ContainsColumn(int col) + { + throw new NotImplementedException(); + } + + public bool ContainsRow(int row) + { + throw new NotImplementedException(); + } + + public ValueEval GetAbsoluteValue(int row, int col) + { + if (col == 0) + { + return new StringEval(_notFound); + } + return new StringEval(""); + } + + public TwoDEval GetColumn(int columnIndex) + { + throw null; + } + + public ValueEval GetRelativeValue(int relativeRowIndex, int relativeColumnIndex) + { + return GetAbsoluteValue(relativeRowIndex, relativeColumnIndex); + } + + public TwoDEval GetRow(int rowIndex) + { + throw null; + } + + public ValueEval GetValue(int sheetIndex, int rowIndex, int columnIndex) + { + return GetAbsoluteValue(rowIndex, columnIndex); + } + + public ValueEval GetValue(int rowIndex, int columnIndex) + { + return GetAbsoluteValue(rowIndex, columnIndex); + } + + public bool IsSubTotal(int rowIndex, int columnIndex) + { + return false; + } + + public AreaEval Offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) + { + throw null; + } + } + } +} diff --git a/main/SS/Formula/Atp/XMatchFunction.cs b/main/SS/Formula/Atp/XMatchFunction.cs new file mode 100644 index 000000000..431542b36 --- /dev/null +++ b/main/SS/Formula/Atp/XMatchFunction.cs @@ -0,0 +1,99 @@ +using NPOI.SS.Formula.Eval; +using NPOI.SS.Formula.Functions; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.Formula.Atp +{ + public class XMatchFunction : FreeRefFunction + { + + public static FreeRefFunction instance = new XMatchFunction(ArgumentsEvaluator.instance); + + private ArgumentsEvaluator evaluator; + + private XMatchFunction(ArgumentsEvaluator anEvaluator) + { + // enforces singleton + this.evaluator = anEvaluator; + } + public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) + { + int srcRowIndex = ec.RowIndex; + int srcColumnIndex = ec.ColumnIndex; + return _evaluate(args, srcRowIndex, srcColumnIndex); + } + + private ValueEval _evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) + { + if (args.Length < 2) + { + return ErrorEval.VALUE_INVALID; + } + LookupUtils.MatchMode matchMode = LookupUtils.MatchMode.ExactMatch; + if (args.Length > 2) + { + try + { + ValueEval matchModeValue = OperandResolver.GetSingleValue(args[2], srcRowIndex, srcColumnIndex); + int matchInt = OperandResolver.CoerceValueToInt(matchModeValue); + matchMode = LookupUtils.GetMatchMode(matchInt); + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + catch (Exception e) + { + return ErrorEval.VALUE_INVALID; + } + } + LookupUtils.SearchMode searchMode = LookupUtils.SearchMode.IterateForward; + if (args.Length > 3) + { + try + { + ValueEval searchModeValue = OperandResolver.GetSingleValue(args[3], srcRowIndex, srcColumnIndex); + int searchInt = OperandResolver.CoerceValueToInt(searchModeValue); + searchMode = LookupUtils.GetSearchMode(searchInt); + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + catch (Exception e) + { + return ErrorEval.VALUE_INVALID; + } + } + return evaluate(srcRowIndex, srcColumnIndex, args[0], args[1], matchMode, searchMode); + } + + private ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval lookupEval, ValueEval indexEval, + LookupUtils.MatchMode matchMode, LookupUtils.SearchMode searchMode) + { + try + { + ValueEval lookupValue = OperandResolver.GetSingleValue(lookupEval, srcRowIndex, srcColumnIndex); + TwoDEval tableArray = LookupUtils.ResolveTableArrayArg(indexEval); + ValueVector vector; + if (tableArray.IsColumn) + { + vector = LookupUtils.CreateColumnVector(tableArray, 0); + } + else + { + vector = LookupUtils.CreateRowVector(tableArray, 0); + } + int matchedIdx = LookupUtils.XlookupIndexOfValue(lookupValue, vector, matchMode, searchMode); + return new NumberEval((double)matchedIdx + 1); + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + } + } +} + diff --git a/main/SS/Formula/CacheAreaEval.cs b/main/SS/Formula/CacheAreaEval.cs new file mode 100644 index 000000000..c043e3ab6 --- /dev/null +++ b/main/SS/Formula/CacheAreaEval.cs @@ -0,0 +1,116 @@ +using NPOI.SS.Formula.Eval; +using NPOI.SS.Formula.PTG; +using NPOI.SS.Util; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.Formula +{ + public class CacheAreaEval:AreaEvalBase + { + ValueEval[] _values; + public CacheAreaEval(AreaI ptg, ValueEval[] values):base(ptg) + { + _values = values; + } + public CacheAreaEval(int firstRow, int firstColumn, int lastRow, int lastColumn, ValueEval[] values): + base(firstRow, firstColumn, lastRow, lastColumn) + { + _values = values; + } + public override ValueEval GetRelativeValue(int relativeRowIndex, int relativeColumnIndex) + { + return GetRelativeValue(-1, relativeRowIndex, relativeColumnIndex); + } + + public override ValueEval GetRelativeValue(int sheetIndex, int relativeRowIndex, int relativeColumnIndex) + { + int oneDimensionalIndex = relativeRowIndex * Width + relativeColumnIndex; + return _values[oneDimensionalIndex]; + } + public override AreaEval Offset(int relFirstRowIx, int relLastRowIx, + int relFirstColIx, int relLastColIx) + { + + AreaI area = new OffsetArea(FirstRow, FirstColumn, + relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx); + + int height = area.LastRow - area.FirstRow + 1; + int width = area.LastColumn - area.FirstColumn + 1; + + ValueEval[] newVals = new ValueEval[height * width]; + + int startRow = area.FirstRow - FirstRow; + int startCol = area.FirstColumn - FirstColumn; + + for (int j = 0; j < height; j++) + { + for (int i = 0; i < width; i++) + { + ValueEval temp; + + /* CacheAreaEval is only temporary value representation, does not equal sheet selection + * so any attempts going beyond the selection results in BlankEval + */ + if (startRow + j > LastRow || startCol + i > LastColumn) + { + temp = BlankEval.instance; + } + else + { + temp = _values[(startRow + j) * Width + (startCol + i)]; + } + newVals[j * width + i] = temp; + } + } + + return new CacheAreaEval(area, newVals); + } + public override TwoDEval GetRow(int rowIndex) + { + if (rowIndex >= Height) + { + throw new ArgumentException("Invalid rowIndex " + rowIndex + + ". Allowable range is (0.." + Height + ")."); + } + int absRowIndex = FirstRow + rowIndex; + ValueEval[] values = new ValueEval[Width]; + + for (int i = 0; i < values.Length; i++) + { + values[i] = GetRelativeValue(rowIndex, i); + } + return new CacheAreaEval(absRowIndex, FirstColumn, absRowIndex, LastColumn, values); + } + + public override TwoDEval GetColumn(int columnIndex) + { + if (columnIndex >= Width) + { + throw new ArgumentException("Invalid columnIndex " + columnIndex + + ". Allowable range is (0.." + Width + ")."); + } + int absColIndex = FirstColumn+ columnIndex; + ValueEval[] values = new ValueEval[Height]; + + for (int i = 0; i < values.Length; i++) + { + values[i] = GetRelativeValue(i, columnIndex); + } + + return new CacheAreaEval(FirstRow, absColIndex, LastRow, absColIndex, values); + } + + public override string ToString() + { + CellReference crA = new CellReference(FirstRow, FirstColumn); + CellReference crB = new CellReference(LastRow, LastColumn); + return GetType().Name + "[" + + crA.FormatAsString() + + ':' + + crB.FormatAsString() + + "]"; + } + } +} diff --git a/main/SS/Formula/ConditionalFormattingEvaluator.cs b/main/SS/Formula/ConditionalFormattingEvaluator.cs new file mode 100644 index 000000000..cc2a12cb4 --- /dev/null +++ b/main/SS/Formula/ConditionalFormattingEvaluator.cs @@ -0,0 +1,123 @@ +using NPOI.SS.UserModel; +using NPOI.SS.Util; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.Formula +{ + public class ConditionalFormattingEvaluator + { + private WorkbookEvaluator workbookEvaluator; + private IWorkbook workbook; + + private Dictionary> formats = new Dictionary>(); + private SortedDictionary> values = new SortedDictionary>(); + + public ConditionalFormattingEvaluator(IWorkbook wb, IWorkbookEvaluatorProvider provider) + { + this.workbook = wb; + this.workbookEvaluator = provider.GetWorkbookEvaluator(); + } + protected WorkbookEvaluator WorkbookEvaluator + { + get + { + return workbookEvaluator; + } + } + public List GetConditionalFormattingForCell(CellReference cellRef) + { + List rules = values[cellRef]; + + if (rules == null) + { + // compute and cache them + rules = new List(); + + ISheet sheet; + if (cellRef.SheetName != null) + { + sheet = workbook.GetSheet(cellRef.SheetName); + } + else + { + sheet = workbook.GetSheetAt(workbook.ActiveSheetIndex); + } + + /* + * Per Excel help: + * https://support.office.com/en-us/article/Manage-conditional-formatting-rule-precedence-e09711a3-48df-4bcb-b82c-9d8b8b22463d#__toc269129417 + * stopIfTrue is true for all rules from HSSF files, and an explicit value for XSSF files. + * thus the explicit ordering of the rule lists in #getFormattingRulesForSheet(Sheet) + */ + bool stopIfTrue = false; + foreach (EvaluationConditionalFormatRule rule in GetRules(sheet)) + { + + if (stopIfTrue) + { + continue; // a previous rule matched and wants no more evaluations + } + + if (rule.Matches(cellRef)) + { + rules.Add(rule); + stopIfTrue = rule.Rule.StopIfTrue; + } + } + rules.Sort(); + values.Add(cellRef, rules); + } + + return rules; + } + public List GetConditionalFormattingForCell(ICell cell) + { + return GetConditionalFormattingForCell(GetRef(cell)); + } + public static CellReference GetRef(ICell cell) + { + return new CellReference(cell.Sheet.SheetName, cell.RowIndex, cell.ColumnIndex, false, false); + } + + protected List GetRules(ISheet sheet) + { + String sheetName = sheet.SheetName; + List rules = formats[sheetName]; + if (rules == null) + { + if (formats.ContainsKey(sheetName)) + { + return new List(); + } + ISheetConditionalFormatting scf = sheet.SheetConditionalFormatting; + int count = scf.NumConditionalFormattings; + rules = new List(count); + formats.Add(sheetName, rules); + for (int i = 0; i < count; i++) + { + IConditionalFormatting f = scf.GetConditionalFormattingAt(i); + //optimization, as this may be expensive for lots of ranges + CellRangeAddress[] regions = f.GetFormattingRanges(); + for (int r = 0; r < f.NumberOfRules; r++) + { + IConditionalFormattingRule rule = f.GetRule(r); + rules.Add(new EvaluationConditionalFormatRule(workbookEvaluator, sheet, f, i, rule, r, regions)); + } + } + // need them in formatting and priority order so logic works right + rules.Sort(); + } + return rules; + } + public void ClearAllCachedFormats() + { + formats.Clear(); + } + public void ClearAllCachedValues() + { + values.Clear(); + } + } +} diff --git a/main/SS/Formula/DataValidationEvaluator.cs b/main/SS/Formula/DataValidationEvaluator.cs new file mode 100644 index 000000000..8ca3e96b5 --- /dev/null +++ b/main/SS/Formula/DataValidationEvaluator.cs @@ -0,0 +1,27 @@ +using NPOI.SS.UserModel; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.Formula +{ + public class DataValidationEvaluator + { + /** + * Note that this assumes the cell cached value is up to date and in sync with data edits + * + * @param cell The {@link Cell} to check. + * @param type The {@link CellType} to check for. + * @return true if the cell or cached cell formula result type match the given type + */ + public static bool IsType(ICell cell, CellType type) + { + CellType cellType = cell.CellType; + return cellType == type + || (cellType == CellType.Formula + && cell.CachedFormulaResultType == type + ); + } + + } +} diff --git a/main/SS/Formula/Eval/Forked/ForkedEvaluationCell.cs b/main/SS/Formula/Eval/Forked/ForkedEvaluationCell.cs index d8550b00b..6b3594c39 100644 --- a/main/SS/Formula/Eval/Forked/ForkedEvaluationCell.cs +++ b/main/SS/Formula/Eval/Forked/ForkedEvaluationCell.cs @@ -19,6 +19,8 @@ using NPOI.SS.Formula; using NPOI.SS.Formula.Eval; using NPOI.SS.UserModel; +using NPOI.SS.Util; + namespace NPOI.SS.Formula.Eval.Forked { @@ -171,6 +173,18 @@ public int ColumnIndex return _masterCell.ColumnIndex; } } + public bool IsPartOfArrayFormulaGroup + { + get + { + return _masterCell.IsPartOfArrayFormulaGroup; + } + } + + public CellRangeAddress ArrayFormulaRange + { + get { return _masterCell.ArrayFormulaRange; } + } public CellType CachedFormulaResultType { get { return _masterCell.CachedFormulaResultType; } diff --git a/main/SS/Formula/Eval/Forked/ForkedEvaluationWorkbook.cs b/main/SS/Formula/Eval/Forked/ForkedEvaluationWorkbook.cs index 1deda4777..7a32e7cad 100644 --- a/main/SS/Formula/Eval/Forked/ForkedEvaluationWorkbook.cs +++ b/main/SS/Formula/Eval/Forked/ForkedEvaluationWorkbook.cs @@ -172,6 +172,11 @@ public void ClearAllCachedResultValues() { _masterBook.ClearAllCachedResultValues(); } + + public SpreadsheetVersion GetSpreadsheetVersion() + { + return _masterBook.GetSpreadsheetVersion(); + } } } \ No newline at end of file diff --git a/main/SS/Formula/Eval/FunctionEval.cs b/main/SS/Formula/Eval/FunctionEval.cs index 1a7dc7a5e..5564875f7 100644 --- a/main/SS/Formula/Eval/FunctionEval.cs +++ b/main/SS/Formula/Eval/FunctionEval.cs @@ -171,7 +171,7 @@ private static Function[] ProduceFunctions() retval[72] = CalendarFieldFunction.MINUTE; retval[73] = CalendarFieldFunction.SECOND; retval[74] = new Now(); - retval[75] = new NotImplementedFunction("AREAS"); // AREAS + retval[75] = new Areas(); retval[76] = new Rows(); // ROWS retval[77] = new Columns(); // COLUMNS retval[FunctionID.OFFSET] = new Offset(); //nominally 78 @@ -179,7 +179,7 @@ private static Function[] ProduceFunctions() retval[80] = new NotImplementedFunction("RELREF"); // RELREF retval[81] = new NotImplementedFunction("ARGUMENT"); // ARGUMENT retval[82] = TextFunction.SEARCH; - retval[83] = new NotImplementedFunction("TRANSPOSE"); // TRANSPOSE + retval[83] = MatrixFunction.TRANSPOSE; // TRANSPOSE retval[84] = new NotImplementedFunction("ERROR"); // ERROR retval[85] = new NotImplementedFunction("STEP"); // STEP retval[86] = new NotImplementedFunction("TYPE"); // TYPE @@ -236,7 +236,7 @@ private static Function[] ProduceFunctions() retval[137] = new NotImplementedFunction("FWriteLN"); // FWriteLN retval[138] = new NotImplementedFunction("FWrite"); // FWrite retval[139] = new NotImplementedFunction("FPOS"); // FPOS - retval[140] = new NotImplementedFunction("DATEVALUE"); // DATEVALUE + retval[140] = new DateValue(); // DATEVALUE retval[141] = new NotImplementedFunction("TIMEVALUE"); // TIMEVALUE retval[142] = new NotImplementedFunction("SLN"); // SLN retval[143] = new NotImplementedFunction("SYD"); // SYD @@ -259,9 +259,9 @@ private static Function[] ProduceFunctions() retval[160] = new NotImplementedFunction("GetCHARTITEM"); // GetCHARTITEM retval[161] = new NotImplementedFunction("DIALOGBOX"); // DIALOGBOX retval[162] = TextFunction.CLEAN; // CLEAN - retval[163] = new NotImplementedFunction("MDETERM"); // MDETERM - retval[164] = new NotImplementedFunction("MINVERSE"); // MINVERSE - retval[165] = new NotImplementedFunction("MMULT"); // MMULT + retval[163] = MatrixFunction.MDETERM; // MDETERM + retval[164] = MatrixFunction.MINVERSE; // MINVERSE + retval[165] = MatrixFunction.MMULT; // MMULT retval[166] = new NotImplementedFunction("FILES"); // FILES retval[167] = new IPMT(); retval[168] = new PPMT(); @@ -310,7 +310,7 @@ private static Function[] ProduceFunctions() retval[219] = new Address(); // AddRESS retval[220] = new Days360(); // DAYS360 retval[221] = new Today(); // TODAY - retval[222] = new NotImplementedFunction("VDB"); // VDB + retval[222] = new NotImplementedFunction("VDB"); // VDB- retval[227] = AggregateFunction.MEDIAN; // MEDIAN retval[228] = new Sumproduct(); // SUMPRODUCT retval[229] = NumericFunction.SINH; // SINH @@ -375,15 +375,15 @@ private static Function[] ProduceFunctions() retval[290] = new NotImplementedFunction("LOGNORMDIST"); // LOGNORMDIST retval[291] = new NotImplementedFunction("LOGINV"); // LOGINV retval[292] = new NotImplementedFunction("NEGBINOMDIST"); // NEGBINOMDIST - retval[293] = new NotImplementedFunction("NORMDIST"); // NORMDIST - retval[294] = new NotImplementedFunction("NORMSDIST"); // NORMSDIST - retval[295] = new NotImplementedFunction("NORMINV"); // NORMINV - retval[296] = new NotImplementedFunction("NORMSINV"); // NORMSINV - retval[297] = new NotImplementedFunction("STANDARDIZE"); // STANDARDIZE + retval[293] = NormDist.instance; // NORMDIST + retval[294] = NormSDist.instance; // NORMSDIST + retval[295] = NormInv.instance; // NORMINV + retval[296] = NormSInv.instance; // NORMSINV + retval[297] = Standardize.instance; // STANDARDIZE retval[298] = new Odd(); // ODD retval[299] = new NotImplementedFunction("PERMUT"); // PERMUT retval[300] = NumericFunction.POISSON; // POISSON - retval[301] = new NotImplementedFunction("TDIST"); // TDIST + retval[301] = TDist.instance; // TDIST retval[302] = new NotImplementedFunction("WEIBULL"); // WEIBULL retval[303] = new Sumxmy2(); // SUMXMY2 retval[304] = new Sumx2my2(); // SUMX2MY2 @@ -411,7 +411,7 @@ private static Function[] ProduceFunctions() retval[326] = AggregateFunction.SMALL; // SMALL retval[327] = new NotImplementedFunction("QUARTILE"); // QUARTILE retval[328] = AggregateFunction.PERCENTILE; // PERCENTILE - retval[329] = new NotImplementedFunction("PERCENTRANK"); // PERCENTRANK + retval[329] = PercentRank.instance; // PERCENTRANK retval[330] = new Mode(); // MODE retval[331] = new NotImplementedFunction("TRIMMEAN"); // TRIMMEAN retval[332] = new NotImplementedFunction("TINV"); // TINV diff --git a/main/SS/Formula/Eval/OperandResolver.cs b/main/SS/Formula/Eval/OperandResolver.cs index 96c69bb79..b9f6b2697 100644 --- a/main/SS/Formula/Eval/OperandResolver.cs +++ b/main/SS/Formula/Eval/OperandResolver.cs @@ -17,6 +17,7 @@ namespace NPOI.SS.Formula.Eval { + using NPOI.SS.Util; using System; using System.Globalization; @@ -387,5 +388,43 @@ public static String CoerceValueToString(ValueEval ve) } throw new InvalidOperationException("Unexpected eval (" + ve.GetType().Name + ")"); } + /** + * Retrieves a single value from an area evaluation utilizing the 2D indices of the cell + * within its own area reference to index the value in the area evaluation. + * + * @param ae area reference after evaluation + * @param cell the source cell of the formula that contains its 2D indices + * @return a NumberEval, StringEval, BoolEval or BlankEval. or ErrorEval + * Never null. + */ + + public static ValueEval GetElementFromArray(AreaEval ae, IEvaluationCell cell) + { + CellRangeAddress range = cell.ArrayFormulaRange; + int relativeRowIndex = cell.RowIndex - range.FirstRow; + int relativeColIndex = cell.ColumnIndex - range.FirstColumn; + + if (ae.IsColumn) + { + if (ae.IsRow) + { + return ae.GetRelativeValue(0, 0); + } + else if (relativeRowIndex < ae.Height) + { + return ae.GetRelativeValue(relativeRowIndex, 0); + } + } + else if (!ae.IsRow && relativeRowIndex < ae.Height && relativeColIndex < ae.Width) + { + return ae.GetRelativeValue(relativeRowIndex, relativeColIndex); + } + else if (ae.IsRow && relativeColIndex < ae.Width) + { + return ae.GetRelativeValue(0, relativeColIndex); + } + + return ErrorEval.NA; + } } } \ No newline at end of file diff --git a/main/SS/Formula/Eval/RefListEval.cs b/main/SS/Formula/Eval/RefListEval.cs new file mode 100644 index 000000000..cfe3dec60 --- /dev/null +++ b/main/SS/Formula/Eval/RefListEval.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.Formula.Eval +{ + public class RefListEval:ValueEval + { + private List list = new List(); + + public RefListEval(ValueEval v1, ValueEval v2) + { + Add(v1); + Add(v2); + } + + private void Add(ValueEval v) + { + // flatten multiple nested RefListEval + if (v is RefListEval) { + list.AddRange(((RefListEval)v).list); + } else + { + list.Add(v); + } + } + + public List GetList() + { + return list; + } + } +} diff --git a/main/SS/Formula/Eval/RelationalOperationEval/RelationalOperationEval.cs b/main/SS/Formula/Eval/RelationalOperationEval/RelationalOperationEval.cs index c70b75487..5fc3a3d38 100644 --- a/main/SS/Formula/Eval/RelationalOperationEval/RelationalOperationEval.cs +++ b/main/SS/Formula/Eval/RelationalOperationEval/RelationalOperationEval.cs @@ -35,16 +35,16 @@ namespace NPOI.SS.Formula.Eval * @author Amol S. Deshmukh < amolweb at ya hoo Dot com > * */ - public abstract class RelationalOperationEval : Fixed2ArgFunction + public abstract class RelationalOperationEval : Fixed2ArgFunction, ArrayFunction { private static int DoCompare(ValueEval va, ValueEval vb) { - // special cases when one operand is blank - if (va == BlankEval.instance) + // special cases when one operand is blank or missing + if (va == BlankEval.instance|| va is MissingArgEval) { return CompareBlank(vb); } - if (vb == BlankEval.instance) + if (vb == BlankEval.instance || vb is MissingArgEval) { return -CompareBlank(va); } @@ -98,25 +98,30 @@ private static int DoCompare(ValueEval va, ValueEval vb) throw new ArgumentException("Bad operand types (" + va.GetType().Name + "), (" + vb.GetType().Name + ")"); } - private static int CompareBlank(ValueEval v) { - if (v == BlankEval.instance) { - return 0; - } - if (v is BoolEval) { - BoolEval boolEval = (BoolEval) v; - return boolEval.BooleanValue ? -1 : 0; - } - if (v is NumberEval) { - NumberEval ne = (NumberEval) v; + private static int CompareBlank(ValueEval v) + { + if (v == BlankEval.instance|| v is MissingArgEval) + { + return 0; + } + if (v is BoolEval) + { + BoolEval boolEval = (BoolEval)v; + return boolEval.BooleanValue ? -1 : 0; + } + if (v is NumberEval) + { + NumberEval ne = (NumberEval)v; //return ne.NumberValue.CompareTo(0.0); return NumberComparer.Compare(0.0, ne.NumberValue); - } - if (v is StringEval) { - StringEval se = (StringEval) v; - return se.StringValue.Length < 1 ? 0 : -1; - } - throw new ArgumentException("bad value class (" + v.GetType().Name + ")"); - } + } + if (v is StringEval) + { + StringEval se = (StringEval)v; + return se.StringValue.Length < 1 ? 0 : -1; + } + throw new ArgumentException("bad value class (" + v.GetType().Name + ")"); + } public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) { @@ -136,7 +141,110 @@ public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEva bool result = ConvertComparisonResult(cmpResult); return BoolEval.ValueOf(result); } + public ValueEval EvaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex) + { + ValueEval arg0 = args[0]; + ValueEval arg1 = args[1]; + + int w1, w2, h1, h2; + int a1FirstCol = 0, a1FirstRow = 0; + if (arg0 is AreaEval) + { + AreaEval ae = (AreaEval)arg0; + w1 = ae.Width; + h1 = ae.Height; + a1FirstCol = ae.FirstColumn; + a1FirstRow = ae.FirstRow; + } + else if (arg0 is RefEval) + { + RefEval ref1 = (RefEval)arg0; + w1 = 1; + h1 = 1; + a1FirstCol = ref1.Column; + a1FirstRow = ref1.Row; + } + else + { + w1 = 1; + h1 = 1; + } + int a2FirstCol = 0, a2FirstRow = 0; + if (arg1 is AreaEval) + { + AreaEval ae = (AreaEval)arg1; + w2 = ae.Width; + h2 = ae.Height; + a2FirstCol = ae.FirstColumn; + a2FirstRow = ae.FirstRow; + } + else if (arg1 is RefEval) + { + RefEval ref1 = (RefEval)arg1; + w2 = 1; + h2 = 1; + a2FirstCol = ref1.Column; + a2FirstRow = ref1.Row; + } + else + { + w2 = 1; + h2 = 1; + } + + int width = Math.Max(w1, w2); + int height = Math.Max(h1, h2); + ValueEval[] vals = new ValueEval[height * width]; + + int idx = 0; + for (int i = 0; i < height; i++) + { + for (int j = 0; j < width; j++) + { + ValueEval vA; + try + { + vA = OperandResolver.GetSingleValue(arg0, a1FirstRow + i, a1FirstCol + j); + } + catch (EvaluationException e) + { + vA = e.GetErrorEval(); + } + ValueEval vB; + try + { + vB = OperandResolver.GetSingleValue(arg1, a2FirstRow + i, a2FirstCol + j); + } + catch (EvaluationException e) + { + vB = e.GetErrorEval(); + } + if (vA is ErrorEval) + { + vals[idx++] = vA; + } + else if (vB is ErrorEval) + { + vals[idx++] = vB; + } + else + { + int cmpResult = DoCompare(vA, vB); + bool result = ConvertComparisonResult(cmpResult); + vals[idx++] = BoolEval.ValueOf(result); + } + + } + } + + if (vals.Length == 1) + { + return vals[0]; + } + + return new CacheAreaEval(srcRowIndex, srcColumnIndex, srcRowIndex + height - 1, srcColumnIndex + width - 1, vals); + } public abstract bool ConvertComparisonResult(int cmpResult); diff --git a/main/SS/Formula/Eval/TwoOperandNumeric/TwoOperandNumericOperation.cs b/main/SS/Formula/Eval/TwoOperandNumeric/TwoOperandNumericOperation.cs index 3371f34ed..7f68604cc 100644 --- a/main/SS/Formula/Eval/TwoOperandNumeric/TwoOperandNumericOperation.cs +++ b/main/SS/Formula/Eval/TwoOperandNumeric/TwoOperandNumericOperation.cs @@ -4,21 +4,22 @@ namespace NPOI.SS.Formula.Eval { - public abstract class TwoOperandNumericOperation : Fixed2ArgFunction + public abstract class TwoOperandNumericOperation : Fixed2ArgFunction, ArrayFunction { - //public int Type - //{ - // get - // { - // // TODO - remove - // throw new Exception("obsolete code should not be called"); - // } - //} protected double SingleOperandEvaluate(ValueEval arg, int srcCellRow, int srcCellCol) { ValueEval ve = OperandResolver.GetSingleValue(arg, srcCellRow, srcCellCol); return OperandResolver.CoerceValueToDouble(ve); } + public ValueEval EvaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex) + { + if (args.Length != 2) + { + return ErrorEval.VALUE_INVALID; + } + Func func = this.Evaluate; + return new ArrayEval(func).Evaluate(srcRowIndex, srcColumnIndex, args[0], args[1]); + } public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) { @@ -55,5 +56,37 @@ public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEva public static NPOI.SS.Formula.Functions.Function MultiplyEval = new MultiplyEval(); public static NPOI.SS.Formula.Functions.Function PowerEval = new PowerEval(); public static NPOI.SS.Formula.Functions.Function SubtractEval = new SubtractEval(); + + private class ArrayEval : MatrixFunction.TwoArrayArg + { + Func _evaluateFunc = null; + public ArrayEval(Func evalFunc) + { + _evaluateFunc = evalFunc; + } + + private MatrixFunction.MutableValueCollector instance = new MatrixFunction.MutableValueCollector(false, true); + + protected override double[] CollectValues(ValueEval arg) + { + return instance.collectValues(arg); + } + + protected override double[,] Evaluate(double[,] d1, double[,] d2) + { + int width = d1.GetLength(1) < d2.GetLength(1) ? d1.GetLength(1) : d2.GetLength(1); + int height = (d1.GetLength(0) < d2.GetLength(0)) ? d1.GetLength(0) : d2.GetLength(0); + + double[,] result = new double[height, width]; + + for (int j = 0; j < height; j++) { + for (int i = 0; i < width; i++) { + result[j, i] = _evaluateFunc(d1[j, i], d2[j, i]); + + } + } + return result; + } + } } } \ No newline at end of file diff --git a/main/SS/Formula/EvaluationCell.cs b/main/SS/Formula/EvaluationCell.cs index 799cbb7d9..851594b20 100644 --- a/main/SS/Formula/EvaluationCell.cs +++ b/main/SS/Formula/EvaluationCell.cs @@ -19,17 +19,19 @@ namespace NPOI.SS.Formula { using System; using NPOI.SS.UserModel; + using NPOI.SS.Util; + /** - * Abstracts a cell for the purpose of formula evaluation. This interface represents both formula - * and non-formula cells.
- * - * Implementors of this class must implement {@link #HashCode()} and {@link #Equals(Object)} - * To provide an identity relationship based on the underlying HSSF or XSSF cell

- * - * For POI internal use only - * - * @author Josh Micich - */ +* Abstracts a cell for the purpose of formula evaluation. This interface represents both formula +* and non-formula cells.
+* +* Implementors of this class must implement {@link #HashCode()} and {@link #Equals(Object)} +* To provide an identity relationship based on the underlying HSSF or XSSF cell

+* +* For POI internal use only +* +* @author Josh Micich +*/ public interface IEvaluationCell { // consider method Object GetUnderlyingCell() To reduce memory consumption in formula cell cache @@ -43,6 +45,8 @@ public interface IEvaluationCell bool BooleanCellValue { get; } int ErrorCellValue { get; } Object IdentityKey { get; } + bool IsPartOfArrayFormulaGroup { get; } + CellRangeAddress ArrayFormulaRange { get; } CellType CachedFormulaResultType { get; } } } \ No newline at end of file diff --git a/main/SS/Formula/EvaluationConditionalFormatRule.cs b/main/SS/Formula/EvaluationConditionalFormatRule.cs new file mode 100644 index 000000000..cdc1b74b8 --- /dev/null +++ b/main/SS/Formula/EvaluationConditionalFormatRule.cs @@ -0,0 +1,805 @@ +using EnumsNET; +using NPOI.SS.Formula.Eval; +using NPOI.SS.Formula.Functions; +using NPOI.SS.UserModel; +using NPOI.SS.Util; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.Formula +{ + public enum OperatorEnum:byte + { + NO_COMPARISON=0, + BETWEEN=1, + NOT_BETWEEN=2, + EQUAL=3, + NOT_EQUAL=4, + GREATER_THAN=5, + LESS_THAN=6, + GREATER_OR_EQUAL=7, + LESS_OR_EQUAL=8 + } + public class OperatorEnumHelper + { + public static bool IsValid(OperatorEnum @operator, object cellValue, object v1, object v2) { + if (cellValue == null) + return false; + switch(@operator) + { + case OperatorEnum.NO_COMPARISON: + return false; + case OperatorEnum.BETWEEN: + if (cellValue is Double) + { + // use zero for null + double n1 = v1==null? 0:(double)v1; + double n2 = v2 == null ? 0 : (double)v2; + return (double)cellValue - n1 >= 0 && (double)cellValue - n2 <= 0; + } + else if (cellValue is String) + { + String n1 = v1 == null ? "" : (String)v1; + String n2 = v2 == null ? "" : (String)v2; + return string.Compare((String)cellValue, n1, true) >= 0 && string.Compare((String)cellValue, n2, true) <= 0; + } + else if (cellValue is Boolean) + return false; + return false; + case OperatorEnum.EQUAL: + if (v1 == null) + return false; + if (cellValue is Double) + { + return (double)cellValue >= 0; + } + else if (cellValue is String) + { + return string.Compare((String)cellValue, (String)v1, true) == 0; + } + else if (cellValue is Boolean) + { + bool n1 = (bool)v1; + return (bool)cellValue==n1; + } + return false; + case OperatorEnum.NOT_EQUAL: + if (v1 == null) + return true; + if (cellValue is String) + { + String n1 = (String)v1; + return string.Compare((String)cellValue, n1, true) != 0; + } + else if (cellValue is Boolean) + { + bool n1 = (bool)v1; + return (bool)cellValue != n1; + } + return false; + case OperatorEnum.GREATER_THAN: + if (cellValue is Double) + { + // use zero for null + double n1 = v1 == null ? 0 : (double)v1; + return (double)cellValue> n1; + } + else if (cellValue is String) + { + String n1 = v1 == null ? "" : (String)v1; + return string.Compare((String)cellValue, n1, true) > 0; + } + else if (cellValue is Boolean) + { + if (v1 == null) + return true; + bool n1 = (bool)v1; + return ((bool)cellValue).CompareTo(n1)>0; + } + return false; + case OperatorEnum.LESS_THAN: + if (cellValue is Double) + { + // use zero for null + double n1 = v1 == null ? 0 : (double)v1; + return (double)cellValue= n1; + } + else if (cellValue is String) + { + if (v1 == null) + return true; + return string.Compare((String)cellValue, (String)v1, true) >= 0; + } + else if (cellValue is Boolean) + { + if (v1 == null) + return false; + bool n1 = (bool)v1; + return ((bool)cellValue).CompareTo(n1) >= 0; + } + return false; + case OperatorEnum.LESS_OR_EQUAL: + if (cellValue is Double) + { + // use zero for null + double n1 = v1 == null ? 0 : (double)v1; + return (double)cellValue <= n1; + } + else if (cellValue is String) + { + if (v1 == null) + return false; + return string.Compare((String)cellValue, (String)v1, true) <= 0; + } + else if (cellValue is Boolean) + { + if (v1 == null) + return false; + bool n1 = (bool)v1; + return ((bool)cellValue).CompareTo(n1) <= 0; + } + return false; + } + return false; + + } + public static bool IsValidForIncompatibleTypes(OperatorEnum @operator) + { + if (@operator == OperatorEnum.NOT_BETWEEN || @operator == OperatorEnum.NOT_EQUAL) + return true; + else + return false; + } + } + public class EvaluationConditionalFormatRule: IComparable + { + /** + * Note: this class has a natural ordering that is inconsistent with equals. + */ + protected class ValueAndFormat : IComparable + { + private double? value; + private String str; + private String format; + private DecimalFormat decimalTextFormat; + + public ValueAndFormat(Double value, String format, DecimalFormat df) + { + this.value = value; + this.format = format; + str = null; + decimalTextFormat = df; + } + + public ValueAndFormat(String value, String format) + { + this.value = null; + this.format = format; + str = value; + decimalTextFormat = null; + } + + public bool IsNumber + { + get + { + return value != null; + } + } + + public double? Value + { + get + { + return value; + } + } + + public String String + { + get + { + return str; + } + } + + public override String ToString() + { + if (IsNumber) + { + return decimalTextFormat.Format(Value.Value); + } + else + { + return this.String; + } + } + + + public override bool Equals(Object obj) + { + if (!(obj is ValueAndFormat)) + { + return false; + } + ValueAndFormat o = (ValueAndFormat)obj; + return (value == o.value || value.Equals(o.value)) + && (format == o.format || format.Equals(o.format)) + && (str == o.str || str.Equals(o.str)); + } + + /** + * Note: this class has a natural ordering that is inconsistent with equals. + * @param o + * @return value comparison + */ + public int CompareTo(ValueAndFormat o) + { + if (value == null && o.value != null) + { + return 1; + } + if (o.value == null && value != null) + { + return -1; + } + int cmp = value == null ? 0 : value.Value.CompareTo(o.value); + if (cmp != 0) + { + return cmp; + } + + if (str == null && o.str != null) + { + return 1; + } + if (o.str == null && str != null) + { + return -1; + } + + return str == null ? 0 : str.CompareTo(o.str); + } + + + public override int GetHashCode() + { + return (str == null ? 0 : str.GetHashCode()) * 37 * 37 + 37 * (value == null ? 0 : value.GetHashCode()) + (format == null ? 0 : format.GetHashCode()); + } + + public static bool operator <(ValueAndFormat left, ValueAndFormat right) + { + return left.CompareTo(right) < 0; + } + + public static bool operator <=(ValueAndFormat left, ValueAndFormat right) + { + return left.CompareTo(right) <= 0; + } + + public static bool operator >(ValueAndFormat left, ValueAndFormat right) + { + return left.CompareTo(right) > 0; + } + + public static bool operator >=(ValueAndFormat left, ValueAndFormat right) + { + return left.CompareTo(right) >= 0; + } + } + + private WorkbookEvaluator workbookEvaluator; + private ISheet sheet; + private IConditionalFormatting formatting; + private IConditionalFormattingRule rule; + + /* cached values */ + private CellRangeAddress[] regions; + /** + * Depending on the rule type, it may want to know about certain values in the region when evaluating {@link #matches(CellReference)}, + * such as top 10, unique, duplicate, average, etc. This collection stores those if needed so they are not repeatedly calculated + */ + private Dictionary> meaningfulRegionValues = new Dictionary>(); + + private int priority; + private int formattingIndex; + private int ruleIndex; + private String formula1; + private String formula2; + private String text; + // cached for performance, used with cell text comparisons, which are case insensitive and need to be Locale aware (contains, starts with, etc.) + private String lowerText; + + private OperatorEnum @operator; + private ConditionType type; + // cached for performance, to avoid reading the XMLBean every time a conditionally formatted cell is rendered + private ExcelNumberFormat numberFormat; + // cached for performance, used to format numeric cells for string comparisons. See Bug #61764 for explanation + private DecimalFormat decimalTextFormat; + public EvaluationConditionalFormatRule(WorkbookEvaluator workbookEvaluator, ISheet sheet, IConditionalFormatting formatting, int formattingIndex, IConditionalFormattingRule rule, int ruleIndex, CellRangeAddress[] regions) + { + this.workbookEvaluator = workbookEvaluator; + this.sheet = sheet; + this.formatting = formatting; + this.rule = rule; + this.formattingIndex = formattingIndex; + this.ruleIndex = ruleIndex; + + this.priority = rule.Priority; + + this.regions = regions; + formula1 = rule.Formula1; + formula2 = rule.Formula2; + + text = rule.Text; + lowerText = text == null ? null : text.ToLowerInvariant(); + + numberFormat = rule.NumberFormat; + + @operator = (OperatorEnum)rule.ComparisonOperation; + type = rule.ConditionType; + } + public ISheet Sheet { get { return sheet; } } + public IConditionalFormatting Formatting { get { return formatting; } } + public int FormattingIndex { get { return formattingIndex; } } + public IConditionalFormattingRule Rule { get { return rule; } } + public int RuleIndex { get { return ruleIndex; } } + public CellRangeAddress[] Regions { get { return regions; } } + public int Priority { get { return priority; } } + public string Formula1 { get { return formula1; } } + public string Formula2 { get { return formula2; } } + public string Text { get { return text; } } + public ConditionType Type { get { return type; } } + public OperatorEnum Operator { get { return @operator; } } + public ExcelNumberFormat NumberFormat + { + get + { + return numberFormat; + } + } + public override bool Equals(object obj) + { + if (obj == null) + { + return false; + } + if (obj.GetType()!=this.GetType()) + { + return false; + } + EvaluationConditionalFormatRule r = (EvaluationConditionalFormatRule)obj; + return Sheet.SheetName.Equals(r.Sheet.SheetName, StringComparison.InvariantCultureIgnoreCase) + && FormattingIndex == r.FormattingIndex + && RuleIndex == r.RuleIndex; + } + public int CompareTo(EvaluationConditionalFormatRule o) + { + int cmp = Sheet.SheetName.CompareTo(o.Sheet.SheetName); + if (cmp != 0) + { + return cmp; + } + + int x = Priority; + int y = o.Priority; + // logic from Integer.compare() + cmp = x-y; + if (cmp != 0) + { + return cmp; + } + + cmp = FormattingIndex - o.FormattingIndex; + if (cmp != 0) + { + return cmp; + } + return RuleIndex-o.RuleIndex; + } + private ValueEval UnwrapEval(ValueEval eval) + { + ValueEval comp = eval; + + while (comp is RefEval) { + RefEval reference = (RefEval)comp; + comp = reference.GetInnerValueEval(reference.FirstSheetIndex); + } + return comp; + } + private bool CheckValue(ICell cell, CellRangeAddress region) + { + if (cell == null || DataValidationEvaluator.IsType(cell, CellType.Blank) + || DataValidationEvaluator.IsType(cell, CellType.Error) + || (DataValidationEvaluator.IsType(cell, CellType.String) + && string.IsNullOrEmpty(cell.StringCellValue) + ) + ) + { + return false; + } + + ValueEval eval = UnwrapEval(workbookEvaluator.Evaluate(rule.Formula1, ConditionalFormattingEvaluator.GetRef(cell), region)); + + String f2 = rule.Formula2; + ValueEval eval2 = BlankEval.instance; + if (f2 != null && f2.Length > 0) + { + eval2 = UnwrapEval(workbookEvaluator.Evaluate(f2, ConditionalFormattingEvaluator.GetRef(cell), region)); + } + // we assume the cell has been evaluated, and the current formula value stored + if (DataValidationEvaluator.IsType(cell, CellType.Boolean) + && (eval == BlankEval.instance || eval is BoolEval) + && (eval2 == BlankEval.instance || eval2 is BoolEval) + ) { + return OperatorEnumHelper.IsValid(@operator, cell.BooleanCellValue, eval == BlankEval.instance ? (bool?)null : ((BoolEval)eval).BooleanValue, eval2 == BlankEval.instance ? (bool?)null : ((BoolEval)eval2).BooleanValue); + } + if (DataValidationEvaluator.IsType(cell, CellType.Numeric) + && (eval == BlankEval.instance || eval is NumberEval ) + && (eval2 == BlankEval.instance || eval2 is NumberEval) + ) { + return OperatorEnumHelper.IsValid(@operator, cell.NumericCellValue, eval==BlankEval.instance ? (double?)null : ((NumberEval)eval).NumberValue, eval2 == BlankEval.instance ? (double?)null : ((NumberEval)eval2).NumberValue); + } + if (DataValidationEvaluator.IsType(cell, CellType.String) + && (eval == BlankEval.instance || eval is StringEval ) + && (eval2 == BlankEval.instance || eval2 is StringEval) + ) { + return OperatorEnumHelper.IsValid(@operator, cell.StringCellValue, eval == BlankEval.instance ? null : ((StringEval)eval).StringValue, eval2 == BlankEval.instance ? null : ((StringEval)eval2).StringValue); + } + + return OperatorEnumHelper.IsValidForIncompatibleTypes(@operator); + } + private bool CheckFormula(CellReference reference, CellRangeAddress region) + { + ValueEval comp = UnwrapEval(workbookEvaluator.Evaluate(rule.Formula1, reference, region)); + + // Copied for now from DataValidationEvaluator.ValidationEnum.FORMULA#isValidValue() + if (comp is BlankEval) { + return true; + } + if (comp is ErrorEval) { + return false; + } + if (comp is BoolEval) { + return ((BoolEval)comp).BooleanValue; + } + // empirically tested in Excel - 0=false, any other number = true/valid + // see test file DataValidationEvaluations.xlsx + if (comp is NumberEval) { + return ((NumberEval)comp).NumberValue != 0; + } + return false; // anything else is false, such as text + } + internal bool Matches(CellReference reference) + { + // first check that it is in one of the regions defined for this format + CellRangeAddress region = null; + foreach (CellRangeAddress r in regions) + { + if (r.IsInRange(reference)) + { + region = r; + break; + } + } + + if (region == null) + { + // cell not in range of this rule + return false; + } + + ConditionType ruleType = this.Rule.ConditionType; + + // these rules apply to all cells in a region. Specific condition criteria + // may specify no special formatting for that value partition, but that's display logic + if (ruleType.Equals(ConditionType.ColorScale) + || ruleType.Equals(ConditionType.DataBar) + || ruleType.Equals(ConditionType.IconSet)) + { + return true; + } + + ICell cell = null; + IRow row = sheet.GetRow(reference.Row); + if (row != null) + { + cell = row.GetCell(reference.Col); + } + + if (ruleType.Equals(ConditionType.CellValueIs)) + { + // undefined cells never match a VALUE_IS condition + if (cell == null) return false; + return CheckValue(cell, region); + } + if (ruleType.Equals(ConditionType.Formula)) + { + return CheckFormula(reference, region); + } + if (ruleType.Equals(ConditionType.Filter)) + { + return CheckFilter(cell, reference, region); + } + // TODO: anything else, we don't handle yet, such as top 10 + return false; + } + private bool CheckFilter(ICell cell, CellReference reference, CellRangeAddress region) + { + ConditionFilterType? filterType = rule.ConditionFilterType; + if (filterType == null) + { + return false; + } + ValueAndFormat cv = GetCellValue(cell); + switch (filterType) + { + case ConditionFilterType.FILTER: + return false; // we don't evaluate HSSF filters yet + case ConditionFilterType.TOP_10: + // from testing, Excel only operates on numbers and dates (which are stored as numbers) in the range. + // numbers stored as text are ignored, but numbers formatted as text are treated as numbers. + + return GetMeaningfulValues(region, true, (allValues)=> { + IConditionFilterData fc = rule.FilterConfiguration; + + if (!fc.Bottom) + { + allValues.Sort(); + allValues.Reverse(); + } + else + { + allValues.Sort(); + } + + int limit = (int)fc.Rank; + if (fc.Percent) + { + limit = allValues.Count * limit / 100; + } + if (allValues.Count <= limit) + { + return allValues; + } + return allValues.GetRange(0, limit); + }).Contains(cv); + case ConditionFilterType.UNIQUE_VALUES: + // Per Excel help, "duplicate" means matching value AND format + // https://support.office.com/en-us/article/Filter-for-unique-values-or-remove-duplicate-values-ccf664b0-81d6-449b-bbe1-8daaec1e83c2 + return GetMeaningfulValues(region, true, (allValues) => { + allValues.Sort(); + List unique = new List(); + + for (int i = 0; i < allValues.Count; i++) + { + ValueAndFormat v = allValues[i]; + // skip this if the current value matches the next one, or is the last one and matches the previous one + if ((i < allValues.Count - 1 && v.Equals(allValues[i + 1])) || (i > 0 && i == allValues.Count - 1 && v.Equals(allValues[i - 1]))) + { + // current value matches next value, skip both + i++; + continue; + } + unique.Add(v); + } + + return unique; + }).Contains(cv); + case ConditionFilterType.DUPLICATE_VALUES: + // Per Excel help, "duplicate" means matching value AND format + // https://support.office.com/en-us/article/Filter-for-unique-values-or-remove-duplicate-values-ccf664b0-81d6-449b-bbe1-8daaec1e83c2 + return GetMeaningfulValues(region, true, (allValues) => { + allValues.Sort(); + List dup = new List(); + + for (int i = 0; i < allValues.Count; i++) + { + ValueAndFormat v = allValues[i]; + // skip this if the current value matches the next one, or is the last one and matches the previous one + if ((i < allValues.Count - 1 && v.Equals(allValues[i + 1])) || (i > 0 && i == allValues.Count - 1 && v.Equals(allValues[i - 1]))) + { + // current value matches next value, add one + dup.Add(v); + i++; + } + } + return dup; + }).Contains(cv); + case ConditionFilterType.ABOVE_AVERAGE: + // from testing, Excel only operates on numbers and dates (which are stored as numbers) in the range. + // numbers stored as text are ignored, but numbers formatted as text are treated as numbers. + + IConditionFilterData conf = rule.FilterConfiguration; + + // actually ordered, so iteration order is predictable + List values = GetMeaningfulValues(region, false, (allValues) => { + double total = 0; + ValueEval[] pop = new ValueEval[allValues.Count]; + for (int i = 0; i < allValues.Count; i++) + { + ValueAndFormat v = allValues[i]; + total += (double)v.Value; + pop[i] = new NumberEval((double)v.Value); + } + + List avgSet = new List(1); + avgSet.Add(new ValueAndFormat(allValues.Count == 0 ? 0 : total / allValues.Count, null, decimalTextFormat)); + + double stdDev2 = allValues.Count <= 1 ? 0 : ((NumberEval)AggregateFunction.STDEV.Evaluate(pop, 0, 0)).NumberValue; + avgSet.Add(new ValueAndFormat(stdDev2, null, decimalTextFormat)); + return avgSet; + }); + double? val = cv.IsNumber ? cv.Value : null; + if (val == null) + { + return false; + } + + double avg = (double)values[0].Value; + double stdDev = (double)values[1].Value; + + /* + * use StdDev, aboveAverage, equalAverage to find: + * comparison value + * operator type + */ + + double comp = conf.StdDev > 0 ? (avg + (conf.AboveAverage ? 1 : -1) * stdDev * conf.StdDev) : avg; + + OperatorEnum op; + if (conf.AboveAverage) + { + if (conf.EqualAverage) + { + op = OperatorEnum.GREATER_OR_EQUAL; + } + else + { + op = OperatorEnum.GREATER_THAN; + } + } + else + { + if (conf.EqualAverage) + { + op = OperatorEnum.LESS_OR_EQUAL; + } + else + { + op = OperatorEnum.LESS_THAN; + } + } + return OperatorEnumHelper.IsValid(op, val, comp, null); + case ConditionFilterType.CONTAINS_TEXT: + // implemented both by a cfRule "text" attribute and a formula. Use the text. + return text == null ? false : cv.ToString().ToLowerInvariant().Contains(lowerText); + case ConditionFilterType.NOT_CONTAINS_TEXT: + // implemented both by a cfRule "text" attribute and a formula. Use the text. + return text == null ? true : !cv.ToString().ToLowerInvariant().Contains(lowerText); + case ConditionFilterType.BEGINS_WITH: + // implemented both by a cfRule "text" attribute and a formula. Use the text. + return cv.ToString().ToLowerInvariant().StartsWith(lowerText); + case ConditionFilterType.ENDS_WITH: + // implemented both by a cfRule "text" attribute and a formula. Use the text. + return cv.ToString().ToLowerInvariant().EndsWith(lowerText); + case ConditionFilterType.CONTAINS_BLANKS: + try + { + String v = cv.String; + // see TextFunction.TRIM for implementation + return v == null || v.Trim().Length == 0; + } + catch (Exception e) + { + // not a valid string value, and not a blank cell (that's checked earlier) + return false; + } + case ConditionFilterType.NOT_CONTAINS_BLANKS: + try + { + String v = cv.String; + // see TextFunction.TRIM for implementation + return v != null && v.Trim().Length > 0; + } + catch (Exception e) + { + // not a valid string value, but not blank + return true; + } + case ConditionFilterType.CONTAINS_ERRORS: + return cell != null && DataValidationEvaluator.IsType(cell, CellType.Error); + case ConditionFilterType.NOT_CONTAINS_ERRORS: + return cell == null || !DataValidationEvaluator.IsType(cell, CellType.Error); + case ConditionFilterType.TIME_PERIOD: + // implemented both by a cfRule "text" attribute and a formula. Use the formula. + return CheckFormula(reference, region); + default: + return false; + } + } + private List GetMeaningfulValues(CellRangeAddress region, bool withText, Func, List> func) + { + if (meaningfulRegionValues.ContainsKey(region)) + { + return meaningfulRegionValues[region]; + } + List values = new List(); + List allValues = new List((region.LastColumn - region.FirstColumn + 1) * (region.LastRow - region.FirstRow + 1)); + + for (int r = region.FirstRow; r <= region.LastRow; r++) + { + IRow row = sheet.GetRow(r); + if (row == null) + { + continue; + } + for (int c = region.FirstColumn; c <= region.LastColumn; c++) + { + ICell cell = row.GetCell(c); + ValueAndFormat cv = GetCellValue(cell); + if (withText || cv.IsNumber) + { + allValues.Add(cv); + } + } + } + values = func(allValues); + meaningfulRegionValues.Add(region, values); + + return values; + } + private ValueAndFormat GetCellValue(ICell cell) + { + if (cell != null) + { + String format = cell.CellStyle.GetDataFormatString(); + CellType type = cell.CellType; + if (type == CellType.Formula) + { + type = cell.CachedFormulaResultType; + } + switch (type) + { + case CellType.Numeric: + return new ValueAndFormat(cell.NumericCellValue, format, decimalTextFormat); + case CellType.String: + case CellType.Boolean: + return new ValueAndFormat(cell.StringCellValue, format); + default: + break; + } + } + return new ValueAndFormat("", ""); + } + public override int GetHashCode() + { + int hash = sheet.SheetName.GetHashCode(); + hash = 31 * hash + formattingIndex; + hash = 31 * hash + ruleIndex; + return hash; + } + } +} diff --git a/main/SS/Formula/EvaluationWorkbook.cs b/main/SS/Formula/EvaluationWorkbook.cs index 157938aa3..08bb4e833 100644 --- a/main/SS/Formula/EvaluationWorkbook.cs +++ b/main/SS/Formula/EvaluationWorkbook.cs @@ -128,6 +128,8 @@ public interface IEvaluationWorkbook * @see WorkbookEvaluator#clearAllCachedResultValues() */ void ClearAllCachedResultValues(); + + SpreadsheetVersion GetSpreadsheetVersion(); } public class ExternalName diff --git a/main/SS/Formula/FormulaCellCacheEntrySet.cs b/main/SS/Formula/FormulaCellCacheEntrySet.cs index e8fd3357f..c1ebfcb9f 100644 --- a/main/SS/Formula/FormulaCellCacheEntrySet.cs +++ b/main/SS/Formula/FormulaCellCacheEntrySet.cs @@ -92,7 +92,7 @@ public void Add(CellCacheEntry cce) private static bool AddInternal(CellCacheEntry[] arr, CellCacheEntry cce) { - int startIx = cce.GetHashCode() % arr.Length; + int startIx = Math.Abs(cce.GetHashCode() % arr.Length); for (int i = startIx; i < arr.Length; i++) { @@ -156,7 +156,7 @@ public bool Remove(CellCacheEntry cce) // else - usual case // delete single element (without re-Hashing) - int startIx = cce.GetHashCode() % arr.Length; + int startIx = Math.Abs(cce.GetHashCode() % arr.Length); // note - can't exit loops upon finding null because of potential previous deletes for (int i = startIx; i < arr.Length; i++) diff --git a/main/SS/Formula/PTG/FormulaShifter.cs b/main/SS/Formula/FormulaShifter.cs similarity index 100% rename from main/SS/Formula/PTG/FormulaShifter.cs rename to main/SS/Formula/FormulaShifter.cs diff --git a/main/SS/Formula/FormulaType.cs b/main/SS/Formula/FormulaType.cs index b6f99491d..eccd2bc7f 100644 --- a/main/SS/Formula/FormulaType.cs +++ b/main/SS/Formula/FormulaType.cs @@ -15,25 +15,41 @@ limitations under the License. ==================================================================== */ +using System; + namespace NPOI.SS.Formula { + internal class SingleValueAttribute : Attribute + { + private bool _isSingleValue=false; + public SingleValueAttribute(bool isSingleValue) + { + this._isSingleValue = isSingleValue; + } + public bool IsSingleValue + { + get { return _isSingleValue; } + } + } - /** - * Enumeration of various formula types.
- * - * For POI internal use only - * - * @author Josh Micich - */ + ///

+ /// Enumeration of various formula types. For internal use only + /// public enum FormulaType:int { + [SingleValue(true)] Cell = 0, + [SingleValue(true)] Shared = 1, + [SingleValue(false)] Array = 2, + [SingleValue(true)] CondFormat = 3, + [SingleValue(false)] NamedRange = 4, // this constant is currently very specific. The exact differences from general data // validation formulas or conditional format formulas is not known yet + [SingleValue(false)] DataValidationList = 5, } } \ No newline at end of file diff --git a/main/SS/Formula/Functions/Areas.cs b/main/SS/Formula/Functions/Areas.cs new file mode 100644 index 000000000..b986452d6 --- /dev/null +++ b/main/SS/Formula/Functions/Areas.cs @@ -0,0 +1,34 @@ +using NPOI.SS.Formula.Eval; +using NPOI.SS.Formula.PTG; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.Formula.Functions +{ + public class Areas : Function + { + public ValueEval Evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) + { + if (args.Length == 0) + { + return ErrorEval.VALUE_INVALID; + } + try + { + ValueEval valueEval = args[0]; + int result = 1; + if (valueEval is RefListEval) { + RefListEval refListEval = (RefListEval)valueEval; + result = refListEval.GetList().Count; + } + NumberEval numberEval = new NumberEval(new NumberPtg(result)); + return numberEval; + } + catch (Exception e) + { + return ErrorEval.VALUE_INVALID; + } + } + } +} diff --git a/main/SS/Formula/Functions/ArrayFunction.cs b/main/SS/Formula/Functions/ArrayFunction.cs new file mode 100644 index 000000000..f6f1aaff9 --- /dev/null +++ b/main/SS/Formula/Functions/ArrayFunction.cs @@ -0,0 +1,19 @@ +using NPOI.SS.Formula.Eval; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.Formula.Functions +{ + public interface ArrayFunction + { + /// + /// - Excel uses the error code #NUM! instead of IEEE NaN, so when numeric functions evaluate to Double#NaN be sure to translate the result to ErrorEval#NUM_ERROR. + /// + /// the evaluated function arguments. Empty values are represented with BlankEval or MissingArgEval, never null + /// row index of the cell containing the formula under evaluation + /// column index of the cell containing the formula under evaluation + /// The evaluated result, possibly an ErrorEval, never null + ValueEval EvaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex); + } +} diff --git a/main/SS/Formula/Functions/BesselJ.cs b/main/SS/Formula/Functions/BesselJ.cs new file mode 100644 index 000000000..e8aacb648 --- /dev/null +++ b/main/SS/Formula/Functions/BesselJ.cs @@ -0,0 +1,54 @@ +using NPOI.SS.Formula.Eval; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.Formula.Functions +{ + public class BesselJ:Fixed2ArgFunction, FreeRefFunction + { + public static FreeRefFunction instance = new BesselJ(); + public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg1, ValueEval arg2) + { + try + { + double xval = EvaluateValue(arg1, srcRowIndex, srcColumnIndex); + if (double.IsNaN(xval)) + { + return ErrorEval.VALUE_INVALID; + } + Double orderDouble = EvaluateValue(arg2, srcRowIndex, srcColumnIndex); + if (double.IsNaN(orderDouble)) + { + return ErrorEval.VALUE_INVALID; + } + int order = (int)orderDouble; + if (order < 0) + { + return ErrorEval.NUM_ERROR; + } + + var result=MathNet.Numerics.SpecialFunctions.BesselJ(order, xval); + return new NumberEval(result); + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + } + public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) + { + if (args.Length == 2) + { + return Evaluate(ec.RowIndex, ec.ColumnIndex, args[0], args[1]); + } + return ErrorEval.VALUE_INVALID; + } + private static Double EvaluateValue(ValueEval arg, int srcRowIndex, int srcColumnIndex) + { + ValueEval veText = OperandResolver.GetSingleValue(arg, srcRowIndex, srcColumnIndex); + String strText1 = OperandResolver.CoerceValueToString(veText); + return OperandResolver.ParseDouble(strText1); + } + } +} diff --git a/main/SS/Formula/Functions/Boolean/BooleanFunction.cs b/main/SS/Formula/Functions/Boolean/BooleanFunction.cs index f9a8be222..41d76d4cd 100644 --- a/main/SS/Formula/Functions/Boolean/BooleanFunction.cs +++ b/main/SS/Formula/Functions/Boolean/BooleanFunction.cs @@ -43,7 +43,7 @@ private bool Calculate(ValueEval[] args) { bool result = InitialResultValue; - bool atleastOneNonBlank = false; + bool atLeastOneNonBlank = false; /* * Note: no short-circuit bool loop exit because any ErrorEvals will override the result @@ -65,7 +65,7 @@ private bool Calculate(ValueEval[] args) if (tempVe != null) { result = PartialEvaluate(result, Convert.ToBoolean(tempVe, CultureInfo.InvariantCulture)); - atleastOneNonBlank = true; + atLeastOneNonBlank = true; } } } @@ -84,7 +84,7 @@ private bool Calculate(ValueEval[] args) if (tempVe != null) { result = PartialEvaluate(result, tempVe.Value); - atleastOneNonBlank = true; + atLeastOneNonBlank = true; } } continue; @@ -96,7 +96,7 @@ private bool Calculate(ValueEval[] args) //} if (arg == MissingArgEval.instance) { - tempVe = null; // you can leave out parameters, they are simply ignored + tempVe = false; // missing parameters are treated as FALSE } else { @@ -107,11 +107,11 @@ private bool Calculate(ValueEval[] args) if (tempVe != null) { result = PartialEvaluate(result, Convert.ToBoolean(tempVe, CultureInfo.InvariantCulture)); - atleastOneNonBlank = true; + atLeastOneNonBlank = true; } } - if (!atleastOneNonBlank) + if (!atLeastOneNonBlank) { throw new EvaluationException(ErrorEval.VALUE_INVALID); } diff --git a/main/SS/Formula/Functions/DateValue.cs b/main/SS/Formula/Functions/DateValue.cs new file mode 100644 index 000000000..c42548b1e --- /dev/null +++ b/main/SS/Formula/Functions/DateValue.cs @@ -0,0 +1,110 @@ +using NPOI.SS.Formula.Eval; +using NPOI.SS.Formula.Functions; +using NPOI.SS.UserModel; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using System.Text.RegularExpressions; + +namespace NPOI.SS.Formula.Functions +{ + public class DateValue : Fixed1ArgFunction + { + private class Format + { + public Regex pattern; + public bool hasYear; + public int yearIndex; + public int monthIndex; + public int dayIndex; + + public Format(string patternString, String groupOrder) + { + this.pattern = new Regex(patternString, RegexOptions.Compiled); + this.hasYear = groupOrder.Contains("y"); + if (hasYear) + { + yearIndex = groupOrder.IndexOf("y"); + } + monthIndex = groupOrder.IndexOf("m"); + dayIndex = groupOrder.IndexOf("d"); + } + private static List formats = new List(); + static Format() + { + formats.Add(new Format("^(\\d{4})-(\\w+)-(\\d{1,2})$", "ymd")); + formats.Add(new Format("^(\\d{1,2})-(\\w+)-(\\d{4})$", "dmy")); + formats.Add(new Format("^(\\w+)-(\\d{1,2})$", "md")); + formats.Add(new Format("^(\\w+)/(\\d{1,2})/(\\d{4})$", "mdy")); + formats.Add(new Format("^(\\d{4})/(\\w+)/(\\d{1,2})$", "ymd")); + formats.Add(new Format("^(\\w+)/(\\d{1,2})$", "md")); + } + public static List Values() + { + return formats; + } + } + + public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEval dateTextArg) + { + try + { + String dateText = OperandResolver.CoerceValueToString( + OperandResolver.GetSingleValue(dateTextArg, srcRowIndex, srcColumnIndex)); + if (string.IsNullOrEmpty(dateText)) + { + return BlankEval.instance; + } + foreach (Format format in Format.Values()) + { + var m = format.pattern.Match(dateText); + if (m.Success) + { + var matchGroups = m.Groups; + List groups = new List(); + for (int i = 1; i <= matchGroups.Count; ++i) + { + groups.Add(matchGroups[i].Value); + } + int year = format.hasYear + ? int.Parse(groups[format.yearIndex]) + : DateTime.Now.Year; + int month = parseMonth(groups[format.monthIndex]); + int day = int.Parse(groups[format.dayIndex]); + return new NumberEval(DateUtil.GetExcelDate(new DateTime(year, month, day))); + } + } + } + catch (FormatException e) + { + return ErrorEval.VALUE_INVALID; + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + return ErrorEval.VALUE_INVALID; + } + private int parseMonth(String monthPart) + { + try + { + return int.Parse(monthPart); + } + catch (FormatException ignored) + { + } + + string[] months = DateTimeFormatInfo.InvariantInfo.MonthNames; + for (int month = 0; month < months.Length; ++month) + { + if (months[month].ToLower().StartsWith(monthPart.ToLower())) + { + return month + 1; + } + } + return -1; + } + } +} diff --git a/main/SS/Formula/Functions/Days360.cs b/main/SS/Formula/Functions/Days360.cs index 793b55eb3..bf104a314 100644 --- a/main/SS/Formula/Functions/Days360.cs +++ b/main/SS/Formula/Functions/Days360.cs @@ -49,43 +49,39 @@ public class Days360 : Var2or3ArgFunction public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) { - double result; try { double d0 = NumericFunction.SingleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex); double d1 = NumericFunction.SingleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex); - result = Evaluate(d0, d1, false); + return new NumberEval(Evaluate(d0, d1, false)); } catch (EvaluationException e) { return e.GetErrorEval(); } - return new NumberEval(result); } public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1, ValueEval arg2) { - double result; try { double d0 = NumericFunction.SingleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex); double d1 = NumericFunction.SingleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex); ValueEval ve = OperandResolver.GetSingleValue(arg2, srcRowIndex, srcColumnIndex); bool? method = OperandResolver.CoerceValueToBoolean(ve, false); - result = Evaluate(d0, d1, method == null ? false : method.Value); + return new NumberEval(Evaluate(d0, d1, method != null && (bool)method)); } catch (EvaluationException e) { return e.GetErrorEval(); } - return new NumberEval(result); } private double Evaluate(double d0, double d1, bool method) { DateTime realStart = GetDate(d0); DateTime realEnd = GetDate(d1); int[] startingDate = GetStartingDate(realStart, method); - int[] endingDate = GetEndingDate(realEnd, realStart, method); + int[] endingDate = GetEndingDate(realEnd, startingDate, method); return (endingDate[0] * 360 + endingDate[1] * 30 + endingDate[2]) - @@ -97,11 +93,12 @@ private DateTime GetDate(double date) } private int[] GetStartingDate(DateTime realStart, bool method) { - DateTime d = realStart; - int dd = Math.Min(30, d.Day); - - if (method == false && IsLastDayOfMonth(d)) dd = 30; - return new int[] { d.Year, d.Month, dd }; + int yyyy = realStart.Year; + int mm = realStart.Month; + int dd = Math.Min(30, realStart.Day); + + if (!method&& IsLastDayOfMonth(realStart)) dd = 30; + return new int[] { yyyy, mm, dd }; } private static int[] GetEndingDate(DateTime realEnd, DateTime realStart, bool method) @@ -129,6 +126,27 @@ private static int[] GetEndingDate(DateTime realEnd, DateTime realStart, bool me return new int[] { yyyy, mm, dd }; } + private static int[] GetEndingDate(DateTime realEnd, int[] startingDate, bool method) + { + int yyyy = realEnd.Year; + int mm = realEnd.Month; + int dd = Math.Min(30, realEnd.Day); + + if (!method && realEnd.Day == 31) + { + if (startingDate[2] < 30) + { + yyyy = realEnd.Year; + mm = realEnd.Month+1; + dd = 1; + } + else + { + dd = 30; + } + } + return new int[] { yyyy, mm, dd }; + } private DateTime GetEndingDateAccordingToStartingDate(double date, DateTime startingDate, bool method) { DateTime endingDate = DateUtil.GetJavaDate(date, false); diff --git a/main/SS/Formula/Functions/Dollar.cs b/main/SS/Formula/Functions/Dollar.cs index 92c1e52c5..3fab3d949 100644 --- a/main/SS/Formula/Functions/Dollar.cs +++ b/main/SS/Formula/Functions/Dollar.cs @@ -18,17 +18,83 @@ * Created on May 6, 2005 * */ +using NPOI.SS.Formula.Eval; +using NPOI.SS.Util; +using System; +using System.Text; + namespace NPOI.SS.Formula.Functions { /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ - public class Dollar : OneArg + public class Dollar : Function { - public override double Evaluate(double d) + protected static double singleOperandEvaluate(ValueEval arg, int srcRowIndex, int srcColumnIndex) { - return d; + if (arg == null) + { + throw new ArgumentException("arg must not be null"); + } + ValueEval ve = OperandResolver.GetSingleValue(arg, srcRowIndex, srcColumnIndex); + double result = OperandResolver.CoerceValueToDouble(ve); + checkValue(result); + return result; + } + public static void checkValue(double result) + { + if (Double.IsNaN(result) || Double.IsInfinity(result)) + { + throw new EvaluationException(ErrorEval.NUM_ERROR); + } + } + + public ValueEval Evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) + { + if (args.Length != 1 && args.Length != 2) + { + return ErrorEval.VALUE_INVALID; + } + try + { + double val = singleOperandEvaluate(args[0], srcRowIndex, srcColumnIndex); + double d1 = args.Length == 1 ? 2.0 : singleOperandEvaluate(args[1], srcRowIndex, srcColumnIndex); + // second arg converts to int by truncating toward zero + int nPlaces = (int)d1; + + if (nPlaces > 127) + { + return ErrorEval.VALUE_INVALID; + } + if (nPlaces < 0) + { + d1 = Math.Abs(d1); + double temp = val / Math.Pow(10, d1); + temp = Math.Round(temp, 0); + val = temp* Math.Pow(10, d1); + } + StringBuilder decimalPlacesFormat = new StringBuilder(); + if (nPlaces > 0) + { + decimalPlacesFormat.Append('.'); + } + for (int i = 0; i < nPlaces; i++) + { + decimalPlacesFormat.Append('0'); + } + StringBuilder decimalFormatString = new StringBuilder(); + decimalFormatString.Append("$#,##0").Append(decimalPlacesFormat) + .Append(";($#,##0").Append(decimalPlacesFormat).Append(')'); + + DecimalFormat df = new DecimalFormat(decimalFormatString.ToString()); + + return new StringEval(df.Format(val)); + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } } } } \ No newline at end of file diff --git a/main/SS/Formula/Functions/DollarDe.cs b/main/SS/Formula/Functions/DollarDe.cs new file mode 100644 index 000000000..a8b4cd741 --- /dev/null +++ b/main/SS/Formula/Functions/DollarDe.cs @@ -0,0 +1,78 @@ +using NPOI.SS.Formula.Eval; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.Formula.Functions +{ + public class DollarDe : Fixed2ArgFunction, FreeRefFunction + { + public static FreeRefFunction instance = new DollarDe(); + private static Double evaluateValue(ValueEval arg, int srcRowIndex, int srcColumnIndex) + { + ValueEval veText = OperandResolver.GetSingleValue(arg, srcRowIndex, srcColumnIndex); + String strText1 = OperandResolver.CoerceValueToString(veText); + return OperandResolver.ParseDouble(strText1); + } + public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg1, ValueEval arg2) + { + try + { + Double number1 = evaluateValue(arg1, srcRowIndex, srcColumnIndex); + if (Double.IsNaN(number1)) + { + return ErrorEval.VALUE_INVALID; + } + Double number2 = evaluateValue(arg2, srcRowIndex, srcColumnIndex); + if (Double.IsNaN(number2)) + { + return ErrorEval.VALUE_INVALID; + } + int fraction = (int)number2; + if (fraction < 0) + { + return ErrorEval.NUM_ERROR; + } + else if (fraction == 0) + { + return ErrorEval.DIV_ZERO; + } + int fractionLength = fraction.ToString().Length; + + bool negative = false; + long valueLong = (long)number1; + if (valueLong < 0) + { + negative = true; + valueLong = -valueLong; + number1 = -number1; + } + double valueFractional = number1 - valueLong; + if (valueFractional == 0.0) + { + return new NumberEval(valueLong); + } + double inflated = valueFractional * Math.Pow(10, fractionLength); + double result = inflated / fraction + valueLong; + if (negative) + { + result = result*-1; + } + return new NumberEval(result); + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + } + public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) + { + if (args.Length == 2) + { + return Evaluate(ec.RowIndex, ec.ColumnIndex, args[0], args[1]); + } + + return ErrorEval.VALUE_INVALID; + } + } +} diff --git a/main/SS/Formula/Functions/DollarFr.cs b/main/SS/Formula/Functions/DollarFr.cs new file mode 100644 index 000000000..b7d35534a --- /dev/null +++ b/main/SS/Formula/Functions/DollarFr.cs @@ -0,0 +1,81 @@ +using NPOI.SS.Formula.Eval; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.Formula.Functions +{ + public class DollarFr : Fixed2ArgFunction, FreeRefFunction + { + public static FreeRefFunction instance = new DollarFr(); + public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg1, ValueEval arg2) + { + try + { + Double number1 = evaluateValue(arg1, srcRowIndex, srcColumnIndex); + if (Double.IsNaN(number1)) + { + return ErrorEval.VALUE_INVALID; + } + Double number2 = evaluateValue(arg2, srcRowIndex, srcColumnIndex); + if (Double.IsNaN(number2)) + { + return ErrorEval.VALUE_INVALID; + } + int fraction = (int)number2; + if (fraction < 0) + { + return ErrorEval.NUM_ERROR; + } + else if (fraction == 0) + { + return ErrorEval.DIV_ZERO; + } + int fractionLength = fraction.ToString().Length; + + bool negative = false; + long valueLong = (long)number1; + if (valueLong < 0) + { + negative = true; + valueLong = -valueLong; + number1 = -number1; + } + + double valueFractional = number1 - valueLong; + if (valueFractional == 0.0) + { + return new NumberEval(valueLong); + } + + double result = valueFractional * fraction / Math.Pow(10, fractionLength)+valueLong; + + if (negative) + { + result = result*-1; + } + + return new NumberEval(result); + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + } + public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) + { + if (args.Length == 2) + { + return Evaluate(ec.RowIndex, ec.ColumnIndex, args[0], args[1]); + } + + return ErrorEval.VALUE_INVALID; + } + private static Double evaluateValue(ValueEval arg, int srcRowIndex, int srcColumnIndex) + { + ValueEval veText = OperandResolver.GetSingleValue(arg, srcRowIndex, srcColumnIndex); + String strText1 = OperandResolver.CoerceValueToString(veText); + return OperandResolver.ParseDouble(strText1); + } +} +} diff --git a/main/SS/Formula/Functions/Hlookup.cs b/main/SS/Formula/Functions/Hlookup.cs index 059e5b5e2..184f242dd 100644 --- a/main/SS/Formula/Functions/Hlookup.cs +++ b/main/SS/Formula/Functions/Hlookup.cs @@ -59,7 +59,7 @@ public ValueEval Evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) ValueEval lookupValue = OperandResolver.GetSingleValue(args[0], srcCellRow, srcCellCol); AreaEval tableArray = LookupUtils.ResolveTableArrayArg(args[1]); bool IsRangeLookup = LookupUtils.ResolveRangeLookupArg(arg3, srcCellRow, srcCellCol); - int colIndex = LookupUtils.LookupIndexOfValue(lookupValue, LookupUtils.CreateRowVector(tableArray, 0), IsRangeLookup); + int colIndex = LookupUtils.lookupFirstIndexOfValue(lookupValue, LookupUtils.CreateRowVector(tableArray, 0), IsRangeLookup); int rowIndex = LookupUtils.ResolveRowOrColIndexArg(args[2], srcCellRow, srcCellCol); ValueVector resultCol = CreateResultColumnVector(tableArray, rowIndex); return resultCol.GetItem(colIndex); diff --git a/main/SS/Formula/Functions/Logical/Isref.cs b/main/SS/Formula/Functions/Logical/Isref.cs index b830b2ebf..7af474edb 100644 --- a/main/SS/Formula/Functions/Logical/Isref.cs +++ b/main/SS/Formula/Functions/Logical/Isref.cs @@ -30,7 +30,7 @@ public class Isref : Fixed1ArgFunction { public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) { - if (arg0 is RefEval || arg0 is AreaEval) + if (arg0 is RefEval || arg0 is AreaEval || arg0 is RefListEval) { return BoolEval.TRUE; } diff --git a/main/SS/Formula/Functions/Lookup.cs b/main/SS/Formula/Functions/Lookup.cs index 07344542c..f21e9bd5f 100644 --- a/main/SS/Formula/Functions/Lookup.cs +++ b/main/SS/Formula/Functions/Lookup.cs @@ -86,7 +86,7 @@ public ValueEval Evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) // Excel seems to handle this by accessing past the end of the result vector. throw new Exception("Lookup vector and result vector of differing sizes not supported yet"); } - int index = LookupUtils.LookupIndexOfValue(lookupValue, lookupVector, true); + int index = LookupUtils.lookupFirstIndexOfValue(lookupValue, lookupVector, true); return resultVector.GetItem(index); } diff --git a/main/SS/Formula/Functions/LookupUtils.cs b/main/SS/Formula/Functions/LookupUtils.cs index 6f841c79a..1ec6fbcd8 100644 --- a/main/SS/Formula/Functions/LookupUtils.cs +++ b/main/SS/Formula/Functions/LookupUtils.cs @@ -23,6 +23,8 @@ namespace NPOI.SS.Formula.Functions using NPOI.SS.Formula.Eval; using System.Globalization; using System.Text.RegularExpressions; + using System.Collections.Generic; + using EnumsNET; /** * Common functionality used by VLOOKUP, HLOOKUP, LOOKUP and MATCH @@ -31,6 +33,50 @@ namespace NPOI.SS.Formula.Functions */ internal class LookupUtils { + private static Dictionary matchModeMap = new Dictionary(); + private static Dictionary searchModeMap = new Dictionary(); + + static LookupUtils() + { + foreach (var value in Enums.GetValues()) + { + matchModeMap.Add((int)value, value); + } + foreach (var value in Enums.GetValues()) + { + searchModeMap.Add((int)value, value); + } + } + public static MatchMode GetMatchMode(int m) + { + if (!matchModeMap.ContainsKey(m)) + { + throw new ArgumentException("unknown match mode " + m); + } + return matchModeMap[m]; + } + public static SearchMode GetSearchMode(int s) + { + if (!searchModeMap.ContainsKey(s)) + { + throw new ArgumentException("unknown search mode " + s); + } + return searchModeMap[s]; + } + public enum MatchMode : int + { + ExactMatch = 0, + ExactMatchFallbackToSmallerValue = -1, + ExactMatchFallbackToLargerValue = 1, + WildcardMatch = 2 + } + public enum SearchMode + { + IterateForward = 1, + IterateBackward = -1, + BinarySearchForward = 2, + BinarySearchBackward = -2 + } internal class RowVector : ValueVector { @@ -170,10 +216,10 @@ public static ValueVector CreateVector(RefEval re) private class StringLookupComparer : LookupValueComparerBase { - private String _value; - private Regex _wildCardPattern; - private bool _matchExact; - private bool _isMatchFunction; + protected String _value; + protected Regex _wildCardPattern; + protected bool _matchExact; + protected bool _isMatchFunction; public StringLookupComparer(StringEval se, bool matchExact, bool isMatchFunction) : base(se) @@ -184,22 +230,19 @@ public StringLookupComparer(StringEval se, bool matchExact, bool isMatchFunction _matchExact = matchExact; _isMatchFunction = isMatchFunction; } - - protected override CompareResult CompareSameType(ValueEval other) + protected virtual String ConvertToString(ValueEval other) { StringEval se = (StringEval)other; - - String stringValue = se.StringValue; - if (_wildCardPattern != null) + return se.StringValue; + } + protected override CompareResult CompareSameType(ValueEval other) + { + String stringValue = ConvertToString(other); + if (_wildCardPattern != null && (_isMatchFunction || !_matchExact)) { MatchCollection matcher = _wildCardPattern.Matches(stringValue); bool matches = matcher.Count > 0; - - if (_isMatchFunction || - !_matchExact) - { - return CompareResult.ValueOf(matches); - } + return CompareResult.ValueOf(matches); } return CompareResult.ValueOf(String.Compare(_value, stringValue, true)); @@ -209,6 +252,30 @@ protected override String GetValueAsString() return _value; } } + private class TolerantStringLookupComparer : StringLookupComparer + { + static StringEval ConvertToStringEval(ValueEval eval) + { + if (eval is StringEval) + { + return (StringEval)eval; + } + String sv = OperandResolver.CoerceValueToString(eval); + return new StringEval(sv); + } + + public TolerantStringLookupComparer(ValueEval eval, bool matchExact, bool isMatchFunction) : + base(ConvertToStringEval(eval), matchExact, isMatchFunction) + { + + } + + protected override String ConvertToString(ValueEval other) + { + return OperandResolver.CoerceValueToString(other); + } + } + private class NumberLookupComparer : LookupValueComparerBase { private double _value; @@ -256,10 +323,10 @@ protected override String GetValueAsString() */ public static int ResolveRowOrColIndexArg(ValueEval rowColIndexArg, int srcCellRow, int srcCellCol) { - if(rowColIndexArg == null) { + if (rowColIndexArg == null) { throw new ArgumentException("argument must not be null"); } - + ValueEval veRowColIndexArg; try { veRowColIndexArg = OperandResolver.GetSingleValue(rowColIndexArg, srcCellRow, (short)srcCellCol); @@ -268,11 +335,11 @@ public static int ResolveRowOrColIndexArg(ValueEval rowColIndexArg, int srcCellR throw EvaluationException.InvalidRef(); } int oneBasedIndex; - if(veRowColIndexArg is StringEval) { - StringEval se = (StringEval) veRowColIndexArg; + if (veRowColIndexArg is StringEval) { + StringEval se = (StringEval)veRowColIndexArg; String strVal = se.StringValue; Double dVal = OperandResolver.ParseDouble(strVal); - if(Double.IsNaN(dVal)) { + if (Double.IsNaN(dVal)) { // String does not resolve to a number. Raise #REF! error. throw EvaluationException.InvalidRef(); // This includes text booleans "TRUE" and "FALSE". They are not valid. @@ -301,8 +368,8 @@ public static AreaEval ResolveTableArrayArg(ValueEval eval) return (AreaEval)eval; } - if(eval is RefEval) { - RefEval refEval = (RefEval) eval; + if (eval is RefEval) { + RefEval refEval = (RefEval)eval; // Make this cell ref look like a 1x1 area ref. // It doesn't matter if eval is a 2D or 3D ref, because that detail is never asked of AreaEval. @@ -322,12 +389,13 @@ public static AreaEval ResolveTableArrayArg(ValueEval eval) */ public static bool ResolveRangeLookupArg(ValueEval rangeLookupArg, int srcCellRow, int srcCellCol) { - if (rangeLookupArg == null) + ValueEval valEval = OperandResolver.GetSingleValue(rangeLookupArg, srcCellRow, srcCellCol); + if (valEval == MissingArgEval.instance) { - // range_lookup arg not provided - return true; // default Is TRUE + // Tricky: + // forth arg exists but is not supplied: "=VLOOKUP(A1,A2:A4,2,)" + return false; } - ValueEval valEval = OperandResolver.GetSingleValue(rangeLookupArg, srcCellRow, srcCellCol); if (valEval is BlankEval) { // Tricky: @@ -353,10 +421,10 @@ public static bool ResolveRangeLookupArg(ValueEval rangeLookupArg, int srcCellRo } // TODO move parseBoolean to OperandResolver bool? b = Countif.ParseBoolean(stringValue); - if (b!=null) + if (b != null) { // string Converted to bool OK - return b==true?true:false; + return b == true ? true : false; } //// Even more trickiness: //// Note - even if the StringEval represents a number value (for example "1"), @@ -374,7 +442,7 @@ public static bool ResolveRangeLookupArg(ValueEval rangeLookupArg, int srcCellRo throw new Exception("Unexpected eval type (" + valEval.GetType().Name + ")"); } - public static int LookupIndexOfValue(ValueEval lookupValue, ValueVector vector, bool isRangeLookup) + public static int lookupFirstIndexOfValue(ValueEval lookupValue, ValueVector vector, bool isRangeLookup) { LookupValueComparer lookupComparer = CreateLookupComparer(lookupValue, isRangeLookup, false); int result; @@ -384,7 +452,25 @@ public static int LookupIndexOfValue(ValueEval lookupValue, ValueVector vector, } else { - result = LookupIndexOfExactValue(lookupComparer, vector); + result = lookupFirstIndexOfValue(lookupComparer, vector, MatchMode.ExactMatch); + } + if (result < 0) + { + throw new EvaluationException(ErrorEval.NA); + } + return result; + } + public static int XlookupIndexOfValue(ValueEval lookupValue, ValueVector vector, MatchMode matchMode, SearchMode searchMode) + { + LookupValueComparer lookupComparer = CreateTolerantLookupComparer(lookupValue, true, true); + int result; + if (searchMode == SearchMode.IterateBackward || searchMode == SearchMode.BinarySearchBackward) + { + result = lookupLastIndexOfValue(lookupComparer, vector, matchMode); + } + else + { + result = lookupFirstIndexOfValue(lookupComparer, vector, matchMode); } if (result < 0) { @@ -392,7 +478,6 @@ public static int LookupIndexOfValue(ValueEval lookupValue, ValueVector vector, } return result; } - /** * Finds first (lowest index) exact occurrence of specified value. @@ -401,22 +486,133 @@ public static int LookupIndexOfValue(ValueEval lookupValue, ValueVector vector, * tableArray. For HLOOKUP this Is the first row of the tableArray. * @return zero based index into the vector, -1 if value cannot be found */ - private static int LookupIndexOfExactValue(LookupValueComparer lookupComparer, ValueVector vector) + private static int lookupFirstIndexOfValue(LookupValueComparer lookupComparer, ValueVector vector, MatchMode matchMode) { // Find first occurrence of lookup value int size = vector.Size; + int bestMatchIdx = -1; + ValueEval bestMatchEval = null; for (int i = 0; i < size; i++) { - if (lookupComparer.CompareTo(vector.GetItem(i)).IsEqual) + ValueEval valueEval = vector.GetItem(i); + CompareResult result = lookupComparer.CompareTo(valueEval); + if (result.IsEqual) { return i; } + switch (matchMode) + { + case MatchMode.ExactMatchFallbackToLargerValue: + if (result.IsLessThan) + { + if (bestMatchEval == null) + { + bestMatchIdx = i; + bestMatchEval = valueEval; + } + else + { + LookupValueComparer matchComparer = CreateTolerantLookupComparer(valueEval, true, true); + if (matchComparer.CompareTo(bestMatchEval).IsLessThan) + { + bestMatchIdx = i; + bestMatchEval = valueEval; + } + } + } + break; + case MatchMode.ExactMatchFallbackToSmallerValue: + if (result.IsGreaterThan) + { + if (bestMatchEval == null) + { + bestMatchIdx = i; + bestMatchEval = valueEval; + } + else + { + LookupValueComparer matchComparer = CreateTolerantLookupComparer(valueEval, true, true); + if (matchComparer.CompareTo(bestMatchEval).IsGreaterThan) + { + bestMatchIdx = i; + bestMatchEval = valueEval; + } + } + } + break; + } } - return -1; + return bestMatchIdx; } - + /** + * Finds last (greatest index) matching occurrence of specified value. + * @param lookupComparer the value to be found in column or row vector + * @param vector the values to be searched. For VLOOKUP this is the first column of the + * tableArray. For HLOOKUP this is the first row of the tableArray. + * @param matchMode + * @return zero based index into the vector, -1 if value cannot be found + */ + private static int lookupLastIndexOfValue(LookupValueComparer lookupComparer, ValueVector vector, + MatchMode matchMode) + { + // find last occurrence of lookup value + int size = vector.Size; + int bestMatchIdx = -1; + ValueEval bestMatchEval = null; + for (int i = size - 1; i >= 0; i--) + { + ValueEval valueEval = vector.GetItem(i); + CompareResult result = lookupComparer.CompareTo(valueEval); + if (result.IsEqual) + { + return i; + } + switch (matchMode) + { + case MatchMode.ExactMatchFallbackToLargerValue: + if (result.IsLessThan) + { + if (bestMatchEval == null) + { + bestMatchIdx = i; + bestMatchEval = valueEval; + } + else + { + LookupValueComparer matchComparer = CreateTolerantLookupComparer(valueEval, true, true); + if (matchComparer.CompareTo(bestMatchEval).IsLessThan) + { + bestMatchIdx = i; + bestMatchEval = valueEval; + } + } + } + break; + case MatchMode.ExactMatchFallbackToSmallerValue: + if (result.IsGreaterThan) + { + if (bestMatchEval == null) + { + bestMatchIdx = i; + bestMatchEval = valueEval; + } + else + { + LookupValueComparer matchComparer = CreateTolerantLookupComparer(valueEval, true, true); + if (matchComparer.CompareTo(bestMatchEval).IsGreaterThan) + { + bestMatchIdx = i; + bestMatchEval = valueEval; + } + } + } + break; + } + } + return bestMatchIdx; + } /** * Excel has funny behaviour when the some elements in the search vector are the wrong type. @@ -542,6 +738,20 @@ public static LookupValueComparer CreateLookupComparer(ValueEval lookupValue, bo } throw new ArgumentException("Bad lookup value type (" + lookupValue.GetType().Name + ")"); } + private static LookupValueComparer CreateTolerantLookupComparer(ValueEval lookupValue, bool matchExact, bool isMatchFunction) + { + if (lookupValue == BlankEval.instance) + { + return new TolerantStringLookupComparer(new StringEval(""), matchExact, isMatchFunction); + } + if (lookupValue is BoolEval) { + return new BooleanLookupComparer((BoolEval)lookupValue); + } + if (matchExact && lookupValue is NumberEval) { + return new NumberLookupComparer((NumberEval)lookupValue); + } + return new TolerantStringLookupComparer(lookupValue, matchExact, isMatchFunction); + } } /** * Enumeration to support 4 valued comparison results.

diff --git a/main/SS/Formula/Functions/Matrix/MMult.cs b/main/SS/Formula/Functions/Matrix/MMult.cs new file mode 100644 index 000000000..c2e9fc335 --- /dev/null +++ b/main/SS/Formula/Functions/Matrix/MMult.cs @@ -0,0 +1,31 @@ +using MathNet.Numerics.LinearAlgebra; +using NPOI.SS.Formula.Eval; +using System; +using System.Collections.Generic; +using System.Text; +using static NPOI.SS.Formula.Functions.MatrixFunction; + +namespace NPOI.SS.Formula.Functions +{ + public class MMulti: TwoArrayArg + { + private MutableValueCollector instance = new MutableValueCollector(false, false); + protected override double[] CollectValues(ValueEval arg) + { + double[] values = instance.collectValues(arg); + + /* handle case where MMULT is operating on an array that is not completely filled*/ + if (arg is AreaEval && values.Length == 1) + throw new EvaluationException(ErrorEval.VALUE_INVALID); + + return values; + } + protected override double[,] Evaluate(double[,] d1, double[,] d2) + { + var first= Matrix.Build.DenseOfArray(d1); + var second = Matrix.Build.DenseOfArray(d2); + + return (first * second).ToArray(); + } + } +} diff --git a/main/SS/Formula/Functions/Matrix/MatrixFunction.cs b/main/SS/Formula/Functions/Matrix/MatrixFunction.cs new file mode 100644 index 000000000..23921c223 --- /dev/null +++ b/main/SS/Formula/Functions/Matrix/MatrixFunction.cs @@ -0,0 +1,269 @@ +using NPOI.SS.Formula.Eval; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.Formula.Functions +{ + public class MatrixFunction + { + public static Function MDETERM = new Mdeterm(); + public static Function TRANSPOSE = new Transpose(); + public static Function MMULT = new MMulti(); + public static Function MINVERSE = new Minverse(); + + /* retrieves 1D array from 2D array after calculations */ + private static double[] extractDoubleArray(double[,] matrix) + { + int idx = 0; + + if (matrix == null || matrix.GetLength(0) < 1 || matrix.GetLength(1) < 1) + { + throw new EvaluationException(ErrorEval.VALUE_INVALID); + } + + double[] vector = new double[matrix.GetLength(0) * matrix.GetLength(1)]; + + for (int j = 0; j < matrix.GetLength(0); j++) + { + for (int i = 0; i < matrix.GetLength(1); i++) + { + vector[idx++] = matrix[j,i]; + } + } + return vector; + } + public static void CheckValues(double[] results) + { + for (int idx = 0; idx < results.Length; idx++) + { + if (Double.IsNaN(results[idx]) || Double.IsInfinity(results[idx])) + { + throw new EvaluationException(ErrorEval.NUM_ERROR); + } + } + } + /* converts 1D array to 2D array for calculations */ + private static double[,] fillDoubleArray(double[] vector, int rows, int cols) + { + int i = 0, j = 0; + + if (rows < 1 || cols < 1 || vector.Length < 1) + { + throw new EvaluationException(ErrorEval.VALUE_INVALID); + } + + double[,] matrix = new double[rows, cols]; + + for (int idx = 0; idx < vector.Length; idx++) + { + if (j < matrix.GetLength(0)) + { + if (i == matrix.GetLength(1)) + { + i = 0; + j++; + } + matrix[j, i++] = vector[idx]; + } + } + + return matrix; + } + public abstract class OneArrayArg : Fixed1ArgFunction + { + protected OneArrayArg() + { + //no fields to initialize + } + + public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) + { + if (arg0 is AreaEval) + { + double[] result = null; + double[,] resultArray; + int width = 1, height = 1; + + try + { + double[] values = CollectValues(arg0); + double[,] array = fillDoubleArray(values, ((AreaEval)arg0).Height, ((AreaEval)arg0).Width); + resultArray = Evaluate(array); + width = resultArray.GetLength(1); + height = resultArray.GetLength(0); + result = extractDoubleArray(resultArray); + + CheckValues(result); + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + + ValueEval[] vals = new ValueEval[result.Length]; + + for (int idx = 0; idx < result.Length; idx++) + { + vals[idx] = new NumberEval(result[idx]); + } + + if (result.Length == 1) + { + return vals[0]; + } + else + { + /* find a better solution */ + return new CacheAreaEval(((AreaEval)arg0).FirstRow, ((AreaEval)arg0).FirstColumn, + ((AreaEval)arg0).FirstRow + height - 1, + ((AreaEval)arg0).FirstColumn + width - 1, vals); + } + } + else + { + double[,] result = null; + try + { + double value = NumericFunction.SingleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex); + double[,] temp = { { value } }; + result = Evaluate(temp); + NumericFunction.CheckValue(result[0, 0]); + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + + return new NumberEval(result[0, 0]); + } + } + + protected abstract double[,] Evaluate(double[,] d1); + protected abstract double[] CollectValues(ValueEval arg); + } + public abstract class TwoArrayArg : Fixed2ArgFunction + { + protected TwoArrayArg() + { + //no fields to initialize + } + + + public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) + { + double[] result; + int width = 1, height = 1; + + try + { + double[,] array0, array1, resultArray; + + if (arg0 is AreaEval) + { + try + { + double[] values = CollectValues(arg0); + array0 = fillDoubleArray(values, ((AreaEval)arg0).Height, ((AreaEval)arg0).Width); + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + } + else + { + try + { + double value = NumericFunction.SingleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex); + array0 = new double[,] { { value } }; + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + } + + if (arg1 is AreaEval) + { + try + { + double[] values = CollectValues(arg1); + array1 = fillDoubleArray(values, ((AreaEval)arg1).Height, ((AreaEval)arg1).Width); + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + } + else + { + try + { + double value = NumericFunction.SingleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex); + array1 = new double[,] { { value } }; + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + } + + resultArray = Evaluate(array0, array1); + width = resultArray.GetLength(1); + height = resultArray.GetLength(0); + result = extractDoubleArray(resultArray); + CheckValues(result); + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + catch (ArgumentException ) + { + return ErrorEval.VALUE_INVALID; + } + + + ValueEval[] vals = new ValueEval[result.Length]; + + for (int idx = 0; idx < result.Length; idx++) + { + vals[idx] = new NumberEval(result[idx]); + } + + if (result.Length == 1) + return vals[0]; + else + { + return new CacheAreaEval(((AreaEval)arg0).FirstRow, ((AreaEval)arg0).FirstColumn, + ((AreaEval)arg0).FirstRow + height - 1, + ((AreaEval)arg0).FirstColumn + width - 1, vals); + } + + } + + protected abstract double[,] Evaluate(double[,] d1, double[,] d2); + protected abstract double[] CollectValues(ValueEval arg); + + } + + + public class MutableValueCollector : MultiOperandNumericFunction + { + public MutableValueCollector(bool isReferenceBoolCounted, bool isBlankCounted) : + base(isReferenceBoolCounted, isBlankCounted) + { + + } + public double[] collectValues(params ValueEval[] operands) + { + return GetNumberArray(operands); + } + protected internal override double Evaluate(double[] values) + { + throw new InvalidOperationException("should not be called"); + } + } + } +} diff --git a/main/SS/Formula/Functions/Matrix/Mdeterm.cs b/main/SS/Formula/Functions/Matrix/Mdeterm.cs new file mode 100644 index 000000000..4ef1d1b10 --- /dev/null +++ b/main/SS/Formula/Functions/Matrix/Mdeterm.cs @@ -0,0 +1,35 @@ +using MathNet.Numerics.LinearAlgebra; +using NPOI.SS.Formula.Eval; +using System; +using System.Collections.Generic; +using System.Text; +using static NPOI.SS.Formula.Functions.MatrixFunction; + +namespace NPOI.SS.Formula.Functions +{ + public class Mdeterm:OneArrayArg + { + private MutableValueCollector instance = new MutableValueCollector(false, false); + protected override double[] CollectValues(ValueEval arg) + { + double[] values = instance.collectValues(arg); + + /* handle case where MDETERM is operating on an array that that is not completely filled*/ + if (arg is AreaEval && values.Length == 1) + throw new EvaluationException(ErrorEval.VALUE_INVALID); + + return values; + } + protected override double[,] Evaluate(double[,] d1) + { + if (d1.GetLength(0) != d1.GetLength(1)) + { + throw new EvaluationException(ErrorEval.VALUE_INVALID); + } + var temp = Matrix.Build.DenseOfArray(d1); + var result = new double[1, 1]; + result[0, 0] = temp.LU().Determinant; + return result; + } + } +} diff --git a/main/SS/Formula/Functions/Matrix/Minverse.cs b/main/SS/Formula/Functions/Matrix/Minverse.cs new file mode 100644 index 000000000..fa6763b94 --- /dev/null +++ b/main/SS/Formula/Functions/Matrix/Minverse.cs @@ -0,0 +1,34 @@ +using MathNet.Numerics.LinearAlgebra; +using NPOI.SS.Formula.Eval; +using System; +using System.Collections.Generic; +using System.Text; +using static NPOI.SS.Formula.Functions.MatrixFunction; + +namespace NPOI.SS.Formula.Functions +{ + public class Minverse : OneArrayArg + { + private MutableValueCollector instance = new MutableValueCollector(false, false); + + protected override double[] CollectValues(ValueEval arg) + { + double[] values = instance.collectValues(arg); + + /* handle case where MDETERM is operating on an array that that is not completely filled*/ + if (arg is AreaEval && values.Length == 1) + throw new EvaluationException(ErrorEval.VALUE_INVALID); + + return values; + } + protected override double[,] Evaluate(double[,] d1) + { + if (d1.GetLength(0) != d1.GetLength(1)) + { + throw new EvaluationException(ErrorEval.VALUE_INVALID); + } + var temp = Matrix.Build.DenseOfArray(d1); + return temp.Inverse().ToArray(); + } + } +} diff --git a/main/SS/Formula/Functions/Matrix/Transpose.cs b/main/SS/Formula/Functions/Matrix/Transpose.cs new file mode 100644 index 000000000..7ffcff8cc --- /dev/null +++ b/main/SS/Formula/Functions/Matrix/Transpose.cs @@ -0,0 +1,25 @@ +using MathNet.Numerics.LinearAlgebra; +using NPOI.SS.Formula.Eval; +using System; +using System.Collections.Generic; +using System.Text; +using static NPOI.SS.Formula.Functions.MatrixFunction; + +namespace NPOI.SS.Formula.Functions +{ + public class Transpose : OneArrayArg + { + private MutableValueCollector instance = new MutableValueCollector(false, true); + + protected override double[] CollectValues(ValueEval arg) + { + return instance.collectValues(arg); + } + + protected override double[,] Evaluate(double[,] d1) + { + var temp = Matrix.Build.DenseOfArray(d1); + return temp.Transpose().ToArray(); + } + } +} diff --git a/main/SS/Formula/Functions/MultiOperandNumericFunction.cs b/main/SS/Formula/Functions/MultiOperandNumericFunction.cs index eadb75812..134f5a935 100644 --- a/main/SS/Formula/Functions/MultiOperandNumericFunction.cs +++ b/main/SS/Formula/Functions/MultiOperandNumericFunction.cs @@ -233,7 +233,7 @@ private void CollectValue(ValueEval ve, bool isViaReference, DoubleList temp) return; } throw new InvalidOperationException("Invalid ValueEval type passed for conversion: (" - + ve.GetType() + ")"); + + ve.GetType().Name + ")"); } /** * Returns a double array that contains values for the numeric cells diff --git a/main/SS/Formula/Functions/NormDist.cs b/main/SS/Formula/Functions/NormDist.cs new file mode 100644 index 000000000..11c8e8dd7 --- /dev/null +++ b/main/SS/Formula/Functions/NormDist.cs @@ -0,0 +1,70 @@ +using NPOI.SS.Formula.Eval; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.Formula.Functions +{ + public class NormDist : Fixed4ArgFunction, FreeRefFunction + { + public static NormDist instance = new NormDist(); + internal static double probability(double x, double mean, double stdev, bool cumulative) + { + var normalDistribution = new MathNet.Numerics.Distributions.Normal(mean, stdev); + return cumulative ? normalDistribution.CumulativeDistribution(x) : normalDistribution.Density(x); + } + public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg1, ValueEval arg2, ValueEval arg3, ValueEval arg4) + { + try + { + Double xval = evaluateValue(arg1, srcRowIndex, srcColumnIndex); + if (double.IsNaN(xval)) + { + return ErrorEval.VALUE_INVALID; + } + Double mean = evaluateValue(arg2, srcRowIndex, srcColumnIndex); + if (double.IsNaN(mean)) + { + return ErrorEval.VALUE_INVALID; + } + Double stdev = evaluateValue(arg3, srcRowIndex, srcColumnIndex); + if (double.IsNaN(stdev)) + { + return ErrorEval.VALUE_INVALID; + } + else if (stdev <= 0) + { + return ErrorEval.NUM_ERROR; + } + var cumulative = OperandResolver.CoerceValueToBoolean(arg4, false); + if (cumulative==null) + { + return ErrorEval.VALUE_INVALID; + } + + return new NumberEval(probability( + xval, mean, stdev, (bool)cumulative)); + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + } + public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) + { + if (args.Length == 4) + { + return Evaluate(ec.RowIndex, ec.ColumnIndex, args[0], args[1], args[2], args[3]); + } + + return ErrorEval.VALUE_INVALID; + } + + private static Double evaluateValue(ValueEval arg, int srcRowIndex, int srcColumnIndex) + { + ValueEval veText = OperandResolver.GetSingleValue(arg, srcRowIndex, srcColumnIndex); + String strText1 = OperandResolver.CoerceValueToString(veText); + return OperandResolver.ParseDouble(strText1); + } + } +} \ No newline at end of file diff --git a/main/SS/Formula/Functions/NormInv.cs b/main/SS/Formula/Functions/NormInv.cs new file mode 100644 index 000000000..2a4b0775e --- /dev/null +++ b/main/SS/Formula/Functions/NormInv.cs @@ -0,0 +1,68 @@ +using NPOI.SS.Formula.Eval; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.Formula.Functions +{ + public class NormInv:Fixed3ArgFunction,FreeRefFunction + { + public static NormInv instance = new NormInv(); + internal static double inverse(double probability, double mean, double stdev) + { + var normalDistribution = new MathNet.Numerics.Distributions.Normal(mean, stdev); + return normalDistribution.InverseCumulativeDistribution(probability); + } + public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg1, ValueEval arg2, ValueEval arg3) + { + try + { + Double probability = evaluateValue(arg1, srcRowIndex, srcColumnIndex); + if (double.IsNaN(probability)) + { + return ErrorEval.VALUE_INVALID; + } + else if (probability <= 0 || probability >= 1) + { + return ErrorEval.NUM_ERROR; + } + Double mean = evaluateValue(arg2, srcRowIndex, srcColumnIndex); + if (double.IsNaN(mean)) + { + return ErrorEval.VALUE_INVALID; + } + Double stdev = evaluateValue(arg3, srcRowIndex, srcColumnIndex); + if (double.IsNaN(stdev)) + { + return ErrorEval.VALUE_INVALID; + } + else if (stdev <= 0) + { + return ErrorEval.NUM_ERROR; + } + + return new NumberEval(inverse( + probability, mean, stdev)); + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + } + public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) + { + if (args.Length == 3) + { + return Evaluate(ec.RowIndex, ec.ColumnIndex, args[0], args[1], args[2]); + } + + return ErrorEval.VALUE_INVALID; + } + private static Double evaluateValue(ValueEval arg, int srcRowIndex, int srcColumnIndex) + { + ValueEval veText = OperandResolver.GetSingleValue(arg, srcRowIndex, srcColumnIndex); + String strText1 = OperandResolver.CoerceValueToString(veText); + return OperandResolver.ParseDouble(strText1); + } + } +} diff --git a/main/SS/Formula/Functions/NormSDist.cs b/main/SS/Formula/Functions/NormSDist.cs new file mode 100644 index 000000000..a803ddf9b --- /dev/null +++ b/main/SS/Formula/Functions/NormSDist.cs @@ -0,0 +1,48 @@ +using NPOI.SS.Formula.Eval; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.Formula.Functions +{ + public class NormSDist : Fixed1ArgFunction, FreeRefFunction + { + public static NormSDist instance = new NormSDist(); + public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg1) + { + try + { + Double xval = evaluateValue(arg1, srcRowIndex, srcColumnIndex); + if (double.IsNaN(xval)) + { + return ErrorEval.VALUE_INVALID; + } + else if (xval < 0) + { + return ErrorEval.NUM_ERROR; + } + + return new NumberEval(NormDist.probability(xval, 0, 1, true)); + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + } + public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) + { + if (args.Length == 1) + { + return Evaluate(ec.RowIndex, ec.ColumnIndex, args[0]); + } + + return ErrorEval.VALUE_INVALID; + } + private static Double evaluateValue(ValueEval arg, int srcRowIndex, int srcColumnIndex) + { + ValueEval veText = OperandResolver.GetSingleValue(arg, srcRowIndex, srcColumnIndex); + String strText1 = OperandResolver.CoerceValueToString(veText); + return OperandResolver.ParseDouble(strText1); + } + } +} diff --git a/main/SS/Formula/Functions/NormSInv.cs b/main/SS/Formula/Functions/NormSInv.cs new file mode 100644 index 000000000..1b627bf1d --- /dev/null +++ b/main/SS/Formula/Functions/NormSInv.cs @@ -0,0 +1,48 @@ +using NPOI.SS.Formula.Eval; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.Formula.Functions +{ + public class NormSInv:Fixed1ArgFunction, FreeRefFunction + { + public static NormSInv instance = new NormSInv(); + public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg1) + { + try + { + Double probability = evaluateValue(arg1, srcRowIndex, srcColumnIndex); + if (double.IsNaN(probability)) + { + return ErrorEval.VALUE_INVALID; + } + else if (probability <= 0 || probability >= 1) + { + return ErrorEval.NUM_ERROR; + } + + return new NumberEval(NormInv.inverse(probability, 0, 1)); + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + } + public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) + { + if (args.Length == 1) + { + return Evaluate(ec.RowIndex, ec.ColumnIndex, args[0]); + } + + return ErrorEval.VALUE_INVALID; + } + private static Double evaluateValue(ValueEval arg, int srcRowIndex, int srcColumnIndex) + { + ValueEval veText = OperandResolver.GetSingleValue(arg, srcRowIndex, srcColumnIndex); + String strText1 = OperandResolver.CoerceValueToString(veText); + return OperandResolver.ParseDouble(strText1); + } + } +} diff --git a/main/SS/Formula/Functions/NumberValueFunction.cs b/main/SS/Formula/Functions/NumberValueFunction.cs new file mode 100644 index 000000000..736717919 --- /dev/null +++ b/main/SS/Formula/Functions/NumberValueFunction.cs @@ -0,0 +1,106 @@ +using NPOI.SS.Formula.Eval; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace NPOI.SS.Formula.Functions +{ + public class NumberValueFunction : FreeRefFunction + { + public static FreeRefFunction instance = new NumberValueFunction(); + + public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) + { + string decSep = Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator; + string groupSep = Thread.CurrentThread.CurrentCulture.NumberFormat.NumberGroupSeparator; + String text = null; + Double result = Double.NaN; + ValueEval v1 = null; + ValueEval v2 = null; + ValueEval v3 = null; + try + { + if (args.Length == 1) + { + v1 = OperandResolver.GetSingleValue(args[0], ec.RowIndex, ec.ColumnIndex); + text = OperandResolver.CoerceValueToString(v1); + } + else if (args.Length == 2) + { + v1 = OperandResolver.GetSingleValue(args[0], ec.RowIndex, ec.ColumnIndex); + v2 = OperandResolver.GetSingleValue(args[1], ec.RowIndex, ec.ColumnIndex); + text = OperandResolver.CoerceValueToString(v1); + decSep = OperandResolver.CoerceValueToString(v2).Substring(0, 1); //If multiple characters are used in the Decimal_separator or Group_separator arguments, only the first character is used. + } + else if (args.Length == 3) + { + v1 = OperandResolver.GetSingleValue(args[0], ec.RowIndex, ec.ColumnIndex); + v2 = OperandResolver.GetSingleValue(args[1], ec.RowIndex, ec.ColumnIndex); + v3 = OperandResolver.GetSingleValue(args[2], ec.RowIndex, ec.ColumnIndex); + text = OperandResolver.CoerceValueToString(v1); + decSep = OperandResolver.CoerceValueToString(v2).Substring(0, 1); //If multiple characters are used in the Decimal_separator or Group_separator arguments, only the first character is used. + groupSep = OperandResolver.CoerceValueToString(v3).Substring(0, 1); //If multiple characters are used in the Decimal_separator or Group_separator arguments, only the first character is used. + } + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + + if (text == "") + text = "0"; //If an empty string ("") is specified as the Text argument, the result is 0. + text = text.Replace(" ", ""); //Empty spaces in the Text argument are ignored, even in the middle of the argument. For example, " 3 000 " is returned as 3000. + String[] parts = text.Split(new string[] { decSep }, StringSplitOptions.RemoveEmptyEntries); + String sigPart = ""; + String decPart = ""; + if (parts.Length > 2) return ErrorEval.VALUE_INVALID; //If a decimal separator is used more than once in the Text argument, NUMBERVALUE returns the #VALUE! error value. + if (parts.Length > 1) + { + sigPart = parts[0]; + decPart = parts[1]; + if (decPart.Contains(groupSep)) return ErrorEval.VALUE_INVALID; //If the group separator occurs after the decimal separator in the Text argument, NUMBERVALUE returns the #VALUE! error value. + sigPart = sigPart.Replace(groupSep, ""); //If the group separator occurs before the decimal separator in the Text argument , the group separator is ignored. + text = sigPart + "." + decPart; + } + else if (parts.Length > 0) + { + sigPart = parts[0]; + sigPart = sigPart.Replace(groupSep, ""); //If the group separator occurs before the decimal separator in the Text argument , the group separator is ignored. + text = sigPart; + } + // If the Text argument ends in one or more percent signs(%), they are used in the calculation of the result. + //Multiple percent signs are additive if they are used in the Text argument just as they are if they are used in a formula. + //For example, =NUMBERVALUE("9%%") returns the same result (0.0009) as the formula =9%%. + int countPercent = 0; + while (text.EndsWith("%")) + { + countPercent++; + text = text.Substring(0, text.Length - 1); + } + + try + { + result = Double.Parse(text); + result = result / Math.Pow(100, countPercent); //If the Text argument ends in one or more percent signs (%), they are used in the calculation of the result. + checkValue(result); + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + catch (Exception) + { + return ErrorEval.VALUE_INVALID; //If any of the arguments are not valid, NUMBERVALUE returns the #VALUE! error value. + } + + return new NumberEval(result); + } + private static void checkValue(double result) + { + if (Double.IsNaN(result) || Double.IsInfinity(result)) { + throw new EvaluationException(ErrorEval.NUM_ERROR); + } + } + } +} diff --git a/main/SS/Formula/Functions/Offset.cs b/main/SS/Formula/Functions/Offset.cs index 26ad32e26..b21b37dfc 100644 --- a/main/SS/Formula/Functions/Offset.cs +++ b/main/SS/Formula/Functions/Offset.cs @@ -225,7 +225,7 @@ public AreaEval Offset(int relFirstRowIx, int relLastRowIx,int relFirstColIx, in public ValueEval Evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) { - if (args.Length < 3 || args.Length > 5) + if (args.Length < 1 || args.Length > 5) { return ErrorEval.VALUE_INVALID; } @@ -233,12 +233,14 @@ public ValueEval Evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) try { BaseRef baseRef = EvaluateBaseRef(args[0]); - int rowOffset = EvaluateIntArg(args[1], srcCellRow, srcCellCol); - int columnOffset = EvaluateIntArg(args[2], srcCellRow, srcCellCol); + // optional arguments + // If offsets are omitted, it is assumed to be 0. + int rowOffset = (args[1] is MissingArgEval) ? 0 : EvaluateIntArg(args[1], srcCellRow, srcCellCol); + int columnOffset = (args[2] is MissingArgEval) ? 0 : EvaluateIntArg(args[2], srcCellRow, srcCellCol); int height = baseRef.Height; int width = baseRef.Width; // optional arguments - // If height or width is omitted, it is assumed to be the same height or width as reference. + // If height or width are omitted, it is assumed to be the same height or width as reference. switch (args.Length) { case 5: diff --git a/main/SS/Formula/Functions/PercentRank.cs b/main/SS/Formula/Functions/PercentRank.cs new file mode 100644 index 000000000..04d6b7c7a --- /dev/null +++ b/main/SS/Formula/Functions/PercentRank.cs @@ -0,0 +1,155 @@ +using NPOI.SS.Formula.Eval; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.Formula.Functions +{ + ///

+ /// Implementation of 'Analysis Toolpak' the Excel function PERCENTRANK() + /// + public class PercentRank : Function + { + public static Function instance = new PercentRank(); + private PercentRank() + { + // Enforce singleton + } + public ValueEval Evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) + { + if (args.Length < 2) + { + return ErrorEval.VALUE_INVALID; + } + double x; + try + { + ValueEval ev = OperandResolver.GetSingleValue(args[1], srcRowIndex, srcColumnIndex); + x = OperandResolver.CoerceValueToDouble(ev); + } + catch (EvaluationException e) + { + ValueEval error = e.GetErrorEval(); + if (error == ErrorEval.NUM_ERROR) + { + return error; + } + return ErrorEval.NUM_ERROR; + } + + List numbers = new List(); + try + { + List values = getValues(args[0], srcRowIndex, srcColumnIndex); + foreach (ValueEval ev in values) + { + if (ev is BlankEval || ev is MissingArgEval) + { + //skip + } + else + { + numbers.Add(OperandResolver.CoerceValueToDouble(ev)); + } + } + } + catch (EvaluationException e) + { + ValueEval error = e.GetErrorEval(); + if (error != ErrorEval.NA) + { + return error; + } + return ErrorEval.NUM_ERROR; + } + + if (numbers.Count==0) + { + return ErrorEval.NUM_ERROR; + } + + int significance = 3; + if (args.Length > 2) + { + try + { + ValueEval ev = OperandResolver.GetSingleValue(args[2], srcRowIndex, srcColumnIndex); + significance = OperandResolver.CoerceValueToInt(ev); + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + } + + return calculateRank(numbers, x, significance, true); + } + private ValueEval calculateRank(List numbers, double x, int significance, bool recurse) + { + double closestMatchBelow = Double.MinValue; + double closestMatchAbove = Double.MaxValue; + if (recurse) + { + foreach (Double d in numbers) + { + if (d <= x && d > closestMatchBelow) closestMatchBelow = d; + if (d > x && d < closestMatchAbove) closestMatchAbove = d; + } + } + if (!recurse || closestMatchBelow == x || closestMatchAbove == x) + { + int lessThanCount = 0; + int greaterThanCount = 0; + foreach (Double d in numbers) + { + if (d < x) lessThanCount++; + else if (d > x) greaterThanCount++; + } + if (greaterThanCount == numbers.Count|| lessThanCount == numbers.Count) + { + return ErrorEval.NA; + } + var result = (double)lessThanCount / (double)(lessThanCount + greaterThanCount); + return new NumberEval(Math.Floor(result*Math.Pow(10,significance))/Math.Pow(10, significance)); + } + else + { + ValueEval belowRank = calculateRank(numbers, closestMatchBelow, significance, false); + if (!(belowRank is NumberEval)) { + return belowRank; + } + ValueEval aboveRank = calculateRank(numbers, closestMatchAbove, significance, false); + if (!(aboveRank is NumberEval)) { + return aboveRank; + } + NumberEval below = (NumberEval)belowRank; + NumberEval above = (NumberEval)aboveRank; + double diff = closestMatchAbove - closestMatchBelow; + double pos = x - closestMatchBelow; + double rankDiff = above.NumberValue - below.NumberValue; + var result = below.NumberValue + (rankDiff * (pos / diff)); + return new NumberEval(Math.Round(result,significance)); + } + } + private List getValues(ValueEval eval, int srcRowIndex, int srcColumnIndex) + { + if (eval is AreaEval) + { + AreaEval ae = (AreaEval)eval; + List list = new List(); + for (int r = ae.FirstRow; r <= ae.LastRow; r++) + { + for (int c = ae.FirstColumn; c <= ae.LastColumn; c++) + { + list.Add(OperandResolver.GetSingleValue(ae.GetAbsoluteValue(r, c), r, c)); + } + } + return list; + } + else + { + return new List() { OperandResolver.GetSingleValue(eval, srcRowIndex, srcColumnIndex) }; + } + } + } +} diff --git a/main/SS/Formula/Functions/Rank.cs b/main/SS/Formula/Functions/Rank.cs index 9d506be5a..d85862c5f 100644 --- a/main/SS/Formula/Functions/Rank.cs +++ b/main/SS/Formula/Functions/Rank.cs @@ -18,6 +18,7 @@ */ using System; +using System.Collections.Generic; using NPOI.SS.Formula.Eval; namespace NPOI.SS.Formula.Functions @@ -52,21 +53,23 @@ public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEva { throw new EvaluationException(ErrorEval.NUM_ERROR); } + if (arg1 is RefListEval) + { + return eval(result, ((RefListEval)arg1), true); + } aeRange = ConvertRangeArg(arg1); + return eval(result, aeRange, true); } catch (EvaluationException e) { return e.GetErrorEval(); } - return eval(srcRowIndex, srcColumnIndex, result, aeRange, true); } public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1, ValueEval arg2) { - - AreaEval aeRange; double result; - bool order = false; + try { ValueEval ve = OperandResolver.GetSingleValue(arg0, srcRowIndex, srcColumnIndex); @@ -75,8 +78,7 @@ public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEva { throw new EvaluationException(ErrorEval.NUM_ERROR); } - aeRange = ConvertRangeArg(arg1); - + bool order = false; ve = OperandResolver.GetSingleValue(arg2, srcRowIndex, srcColumnIndex); int order_value = OperandResolver.CoerceValueToInt(ve); if (order_value == 0) @@ -89,17 +91,21 @@ public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEva } else throw new EvaluationException(ErrorEval.NUM_ERROR); + if (arg1 is RefListEval) + { + return eval(result, ((RefListEval)arg1), order); + } + AreaEval aeRange = ConvertRangeArg(arg1); + return eval(result, aeRange, order); } catch (EvaluationException e) { return e.GetErrorEval(); } - return eval(srcRowIndex, srcColumnIndex, result, aeRange, order); } - private static ValueEval eval(int srcRowIndex, int srcColumnIndex, double arg0, AreaEval aeRange, bool descending_order) + private static ValueEval eval(double arg0, AreaEval aeRange, bool descending_order) { - int rank = 1; int height = aeRange.Height; int width = aeRange.Width; @@ -107,7 +113,6 @@ private static ValueEval eval(int srcRowIndex, int srcColumnIndex, double arg0, { for (int c = 0; c < width; c++) { - Double value = GetValue(aeRange, r, c); if (Double.IsNaN(value)) continue; if (descending_order && value > arg0 || !descending_order && value < arg0) @@ -118,7 +123,43 @@ private static ValueEval eval(int srcRowIndex, int srcColumnIndex, double arg0, } return new NumberEval(rank); } + private static ValueEval eval(double arg0, RefListEval aeRange, bool descending_order) + { + int rank = 1; + List replaceList = new List(); + for (int i = 0; i < aeRange.GetList().Count; i++) + { + ValueEval ve = aeRange.GetList()[i]; + if (ve is RefEval) + { + { + replaceList.Add(i); + } + } + foreach (var index in replaceList) + { + ValueEval targetVe = aeRange.GetList()[i]; + aeRange.GetList()[index] = ((RefEval)targetVe).GetInnerValueEval(((RefEval)ve).FirstSheetIndex); + } + Double value; + if (ve is NumberEval) + { + value = ((NumberEval)ve).NumberValue; + } + else + { + continue; + } + + if (descending_order && value > arg0 || !descending_order && value < arg0) + { + rank++; + } + } + + return new NumberEval(rank); + } private static Double GetValue(AreaEval aeRange, int relRowIndex, int relColIndex) { diff --git a/main/SS/Formula/Functions/Standardize.cs b/main/SS/Formula/Functions/Standardize.cs new file mode 100644 index 000000000..201db2613 --- /dev/null +++ b/main/SS/Formula/Functions/Standardize.cs @@ -0,0 +1,59 @@ +using NPOI.SS.Formula.Eval; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.Formula.Functions +{ + public class Standardize:Fixed3ArgFunction,FreeRefFunction + { + public static Standardize instance = new Standardize(); + public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg1, ValueEval arg2, ValueEval arg3) + { + try + { + Double xval = evaluateValue(arg1, srcRowIndex, srcColumnIndex); + if (double.IsNaN(xval)) + { + return ErrorEval.VALUE_INVALID; + } + Double mean = evaluateValue(arg2, srcRowIndex, srcColumnIndex); + if (double.IsNaN(mean)) + { + return ErrorEval.VALUE_INVALID; + } + Double stdev = evaluateValue(arg3, srcRowIndex, srcColumnIndex); + if (double.IsNaN(stdev)) + { + return ErrorEval.VALUE_INVALID; + } + else if (stdev <= 0) + { + return ErrorEval.NUM_ERROR; + } + + var result = (xval - mean)/stdev; + return new NumberEval(result); + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + } + public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) + { + if (args.Length == 3) + { + return Evaluate(ec.RowIndex, ec.ColumnIndex, args[0], args[1], args[2]); + } + + return ErrorEval.VALUE_INVALID; + } + private static Double evaluateValue(ValueEval arg, int srcRowIndex, int srcColumnIndex) + { + ValueEval veText = OperandResolver.GetSingleValue(arg, srcRowIndex, srcColumnIndex); + String strText1 = OperandResolver.CoerceValueToString(veText); + return OperandResolver.ParseDouble(strText1); + } + } +} diff --git a/main/SS/Formula/Functions/Sumifs.cs b/main/SS/Formula/Functions/Sumifs.cs index 6b1649eed..ff3eb51ed 100644 --- a/main/SS/Formula/Functions/Sumifs.cs +++ b/main/SS/Formula/Functions/Sumifs.cs @@ -140,7 +140,7 @@ internal static double CalcMatchingCells(AreaEval[] ranges, IMatchPredicate[] pr AreaEval aeRange = ranges[i]; IMatchPredicate mp = predicates[i]; - if (!mp.Matches(aeRange.GetRelativeValue(r, c))) + if (mp == null || !mp.Matches(aeRange.GetRelativeValue(r, c))) { matches = false; break; @@ -187,4 +187,4 @@ internal static AreaEval ConvertRangeArg(ValueEval eval) } -} \ No newline at end of file +} diff --git a/main/SS/Formula/Functions/TDist.cs b/main/SS/Formula/Functions/TDist.cs new file mode 100644 index 000000000..e4ab1b1af --- /dev/null +++ b/main/SS/Formula/Functions/TDist.cs @@ -0,0 +1,84 @@ +using MathNet.Numerics.Distributions; +using NPOI.SS.Formula.Eval; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.Formula.Functions +{ + public class TDist : Fixed3ArgFunction, FreeRefFunction + { + public static TDist instance = new TDist(); + static double tdistOneTail(double x, int degreesOfFreedom) + { + return 1 - StudentT.CDF(0, 1, degreesOfFreedom, x); + } + + static double tdistTwoTails(double x, int degreesOfFreedom) + { + return 2 * tdistOneTail(x, degreesOfFreedom); + } + + public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg1, ValueEval arg2, ValueEval arg3) + { + try + { + Double number1 = evaluateValue(arg1, srcRowIndex, srcColumnIndex); + if (double.IsNaN(number1)) + { + return ErrorEval.VALUE_INVALID; + } + else if (number1 < 0) + { + return ErrorEval.NUM_ERROR; + } + Double number2 = evaluateValue(arg2, srcRowIndex, srcColumnIndex); + if (double.IsNaN(number2)) + { + return ErrorEval.VALUE_INVALID; + } + int degreesOfFreedom = (int)number2; + if (degreesOfFreedom < 1) + { + return ErrorEval.NUM_ERROR; + } + Double number3 = evaluateValue(arg3, srcRowIndex, srcColumnIndex); + if (double.IsNaN(number3)) + { + return ErrorEval.VALUE_INVALID; + } + int tails = (int)number3; + if (!(tails == 1 || tails == 2)) + { + return ErrorEval.NUM_ERROR; + } + + if (tails == 2) + { + return new NumberEval(tdistTwoTails(number1, degreesOfFreedom)); + } + + return new NumberEval(tdistOneTail(number1, degreesOfFreedom)); + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + } + public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) + { + if (args.Length == 3) + { + return Evaluate(ec.RowIndex, ec.ColumnIndex, args[0], args[1], args[2]); + } + + return ErrorEval.VALUE_INVALID; + } + private static Double evaluateValue(ValueEval arg, int srcRowIndex, int srcColumnIndex) + { + ValueEval veText = OperandResolver.GetSingleValue(arg, srcRowIndex, srcColumnIndex); + String strText1 = OperandResolver.CoerceValueToString(veText); + return OperandResolver.ParseDouble(strText1); + } + } +} diff --git a/main/SS/Formula/Functions/Vlookup.cs b/main/SS/Formula/Functions/Vlookup.cs index a5c0c7e95..7e612b267 100644 --- a/main/SS/Formula/Functions/Vlookup.cs +++ b/main/SS/Formula/Functions/Vlookup.cs @@ -100,7 +100,7 @@ public class Vlookup : Var3or4ArgFunction ValueEval lookupValue = OperandResolver.GetSingleValue(lookup_value, srcRowIndex, srcColumnIndex); TwoDEval tableArray = LookupUtils.ResolveTableArrayArg(table_array); bool isRangeLookup = LookupUtils.ResolveRangeLookupArg(range_lookup, srcRowIndex, srcColumnIndex); - int rowIndex = LookupUtils.LookupIndexOfValue(lookupValue, LookupUtils.CreateColumnVector(tableArray, 0), isRangeLookup); + int rowIndex = LookupUtils.lookupFirstIndexOfValue(lookupValue, LookupUtils.CreateColumnVector(tableArray, 0), isRangeLookup); int colIndex = LookupUtils.ResolveRowOrColIndexArg(col_index, srcRowIndex, srcColumnIndex); ValueVector resultCol = CreateResultColumnVector(tableArray, colIndex); return resultCol.GetItem(rowIndex); diff --git a/main/SS/Formula/Functions/WeekNum.cs b/main/SS/Formula/Functions/WeekNum.cs index e953f8611..a8467196a 100644 --- a/main/SS/Formula/Functions/WeekNum.cs +++ b/main/SS/Formula/Functions/WeekNum.cs @@ -20,6 +20,8 @@ using NPOI.SS.Util; using NPOI.SS.UserModel; using System.Globalization; +using System.Collections.Generic; + namespace NPOI.SS.Formula.Functions { @@ -46,6 +48,8 @@ public class WeekNum : Fixed2ArgFunction, FreeRefFunction { public static FreeRefFunction instance = new WeekNum(); + private static NumberEval DEFAULT_RETURN_TYPE = new NumberEval(1); + private static List VALID_RETURN_TYPES = new List() { 1, 2, 11, 12, 13, 14, 15, 16, 17, 21 }; public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEval serialNumVE, ValueEval returnTypeVE) { @@ -58,22 +62,34 @@ public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEva { return ErrorEval.VALUE_INVALID; } - //Calendar serialNumCalendar = new GregorianCalendar(); - //serialNumCalendar.setTime(DateUtil.GetJavaDate(serialNum, false)); - DateTime serialNumCalendar = DateUtil.GetJavaDate(serialNum, false); - + DateTime serialNumCalendar; + try + { + serialNumCalendar = DateUtil.GetJavaDate(serialNum, false); + } + catch (Exception ) + { + return ErrorEval.NUM_ERROR; + } int returnType = 0; try { ValueEval ve = OperandResolver.GetSingleValue(returnTypeVE, srcRowIndex, srcColumnIndex); returnType = OperandResolver.CoerceValueToInt(ve); + if (ve is MissingArgEval) + { + returnType = (int)DEFAULT_RETURN_TYPE.NumberValue; + } + else { + returnType = OperandResolver.CoerceValueToInt(ve); + } } catch (EvaluationException) { return ErrorEval.NUM_ERROR; } - if (returnType != 1 && returnType != 2) + if (!VALID_RETURN_TYPES.Contains(returnType)) { return ErrorEval.NUM_ERROR; } @@ -81,24 +97,53 @@ public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEva return new NumberEval(this.getWeekNo(serialNumCalendar, returnType)); } + public int getWeekNo(DateTime dt, int weekStartOn) { GregorianCalendar cal = new GregorianCalendar(); int weekOfYear; - if (weekStartOn == 1) + if (weekStartOn == 1 || weekStartOn == 17) { weekOfYear = cal.GetWeekOfYear(dt, CalendarWeekRule.FirstDay, DayOfWeek.Sunday); } - else + else if (weekStartOn == 2 || weekStartOn == 11) { weekOfYear = cal.GetWeekOfYear(dt, CalendarWeekRule.FirstDay, DayOfWeek.Monday); } + else if (weekStartOn == 12) + { + weekOfYear = cal.GetWeekOfYear(dt, CalendarWeekRule.FirstDay, DayOfWeek.Tuesday); + } + else if (weekStartOn == 13) + { + weekOfYear = cal.GetWeekOfYear(dt, CalendarWeekRule.FirstDay, DayOfWeek.Wednesday); + } + else if (weekStartOn == 14) + { + weekOfYear = cal.GetWeekOfYear(dt, CalendarWeekRule.FirstDay, DayOfWeek.Thursday); + } + else if (weekStartOn == 15) + { + weekOfYear = cal.GetWeekOfYear(dt, CalendarWeekRule.FirstDay, DayOfWeek.Friday); + } + else if (weekStartOn == 16) + { + weekOfYear = cal.GetWeekOfYear(dt, CalendarWeekRule.FirstDay, DayOfWeek.Saturday); + } + else + { + weekOfYear = cal.GetWeekOfYear(dt, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday); + } return weekOfYear; } public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) { - if (args.Length == 2) + if (args.Length == 1) + { + return Evaluate(ec.RowIndex, ec.ColumnIndex, args[0], DEFAULT_RETURN_TYPE); + } + else if (args.Length == 2) { return Evaluate(ec.RowIndex, ec.ColumnIndex, args[0], args[1]); } diff --git a/main/SS/Formula/OperationEvaluationContext.cs b/main/SS/Formula/OperationEvaluationContext.cs index 1d6f7b665..5736ca6db 100644 --- a/main/SS/Formula/OperationEvaluationContext.cs +++ b/main/SS/Formula/OperationEvaluationContext.cs @@ -25,10 +25,18 @@ public class OperationEvaluationContext private int _rowIndex; private int _columnIndex; private EvaluationTracker _tracker; + private bool _isSingleValue; private WorkbookEvaluator _bookEvaluator; - + private bool _isInArrayContext; + public OperationEvaluationContext(WorkbookEvaluator bookEvaluator, IEvaluationWorkbook workbook, int sheetIndex, int srcRowNum, - int srcColNum, EvaluationTracker tracker) + int srcColNum, EvaluationTracker tracker) + : this(bookEvaluator, workbook, sheetIndex, srcRowNum, srcColNum, tracker, isSingleValue: true) + { + } + + public OperationEvaluationContext(WorkbookEvaluator bookEvaluator, IEvaluationWorkbook workbook, int sheetIndex, int srcRowNum, + int srcColNum, EvaluationTracker tracker, bool isSingleValue) { _bookEvaluator = bookEvaluator; _workbook = workbook; @@ -36,13 +44,30 @@ public class OperationEvaluationContext _rowIndex = srcRowNum; _columnIndex = srcColNum; _tracker = tracker; + _isSingleValue = isSingleValue; + } + public bool IsArraymode + { + get + { + return _isInArrayContext; + } + set { + _isInArrayContext = value; + } } - public IEvaluationWorkbook GetWorkbook() { return _workbook; } + public bool IsSingleValue + { + get + { + return _isSingleValue; + } + } public int RowIndex { get @@ -367,6 +392,44 @@ public ValueEval GetArea3DEval(Area3DPxg aptg) return new LazyAreaEval(aptg.FirstRow, aptg.FirstColumn, aptg.LastRow, aptg.LastColumn, sre); } + public ValueEval GetAreaValueEval(int firstRowIndex, int firstColumnIndex, + int lastRowIndex, int lastColumnIndex, Object[,] tokens) + { + + ValueEval[] values = new ValueEval[tokens.GetLength(0) * tokens.GetLength(1)]; + + int index = 0; + for (int jdx = 0; jdx < tokens.GetLength(0); jdx++) + { + for (int idx = 0; idx < tokens.GetLength(1); idx++) + { + values[index++] = convertObjectEval(tokens[jdx,idx]); + } + } + + return new CacheAreaEval(firstRowIndex, firstColumnIndex, lastRowIndex, + lastColumnIndex, values); + } + private ValueEval convertObjectEval(Object token) + { + if (token == null) + { + throw new ArgumentNullException("Array item cannot be null"); + } + if (token is String) { + return new StringEval((String)token); + } + if (token is Double) { + return new NumberEval(((Double)token)); + } + if (token is Boolean) { + return BoolEval.ValueOf((Boolean)token); + } + if (token is Constant.ErrorConstant) { + return ErrorEval.ValueOf(((Constant.ErrorConstant)token).ErrorCode); + } + throw new ArgumentException("Unexpected constant class (" + token.GetType().Name + ")"); + } public ValueEval GetNameXEval(NameXPtg nameXPtg) { ExternalSheet externSheet = _workbook.GetExternalSheet(nameXPtg.SheetRefIndex); @@ -512,4 +575,4 @@ private ValueEval GetExternalNameXEval(ExternalName externName, String workbookN } } } -} \ No newline at end of file +} diff --git a/main/SS/Formula/OperationEvaluatorFactory.cs b/main/SS/Formula/OperationEvaluatorFactory.cs index af7a820ab..41df31acf 100644 --- a/main/SS/Formula/OperationEvaluatorFactory.cs +++ b/main/SS/Formula/OperationEvaluatorFactory.cs @@ -67,8 +67,7 @@ private static Hashtable InitialiseInstancesMap() return m; } - private static void Add(Hashtable m, OperationPtg ptgKey, - NPOI.SS.Formula.Functions.Function instance) + private static void Add(Hashtable m, OperationPtg ptgKey, Functions.Function instance) { // make sure ptg has single private constructor because map lookups assume singleton keys ConstructorInfo[] cc = ptgKey.GetType().GetConstructors(); @@ -94,26 +93,66 @@ private static Hashtable InitialiseInstancesMap() } NPOI.SS.Formula.Functions.Function result = _instancesByPtgClass[ptg] as NPOI.SS.Formula.Functions.Function; - if (result != null) + FreeRefFunction udfFunc = null; + if (result == null) { - return result.Evaluate(args, ec.RowIndex, (short)ec.ColumnIndex); + if (ptg is AbstractFunctionPtg) + { + AbstractFunctionPtg fptg = (AbstractFunctionPtg)ptg; + int functionIndex = fptg.FunctionIndex; + switch (functionIndex) + { + case NPOI.SS.Formula.Function.FunctionMetadataRegistry.FUNCTION_INDEX_INDIRECT: + udfFunc = Indirect.instance; + break; + case NPOI.SS.Formula.Function.FunctionMetadataRegistry.FUNCTION_INDEX_EXTERNAL: + udfFunc = UserDefinedFunction.instance; + break; + default: + result = FunctionEval.GetBasicFunction(functionIndex); + break; + } + } } - if (ptg is AbstractFunctionPtg) + if (result != null) { - AbstractFunctionPtg fptg = (AbstractFunctionPtg)ptg; - int functionIndex = fptg.FunctionIndex; - switch (functionIndex) + if (result is ArrayFunction) { - case NPOI.SS.Formula.Function.FunctionMetadataRegistry.FUNCTION_INDEX_INDIRECT: - return Indirect.instance.Evaluate(args, ec); - case NPOI.SS.Formula.Function.FunctionMetadataRegistry.FUNCTION_INDEX_EXTERNAL: - return UserDefinedFunction.instance.Evaluate(args, ec); + ArrayFunction func = (ArrayFunction)result; + ValueEval eval = EvaluateArrayFunction(func, args, ec); + if (eval != null) + { + return eval; + } } - - return FunctionEval.GetBasicFunction(functionIndex).Evaluate(args, ec.RowIndex, ec.ColumnIndex); + return result.Evaluate(args, ec.RowIndex, (short)ec.ColumnIndex); + } + else if (udfFunc != null) + { + return udfFunc.Evaluate(args, ec); } throw new Exception("Unexpected operation ptg class (" + ptg.GetType().Name + ")"); } + public static ValueEval EvaluateArrayFunction(ArrayFunction func, ValueEval[] args, + OperationEvaluationContext ec) + { + IEvaluationSheet evalSheet = ec.GetWorkbook().GetSheet(ec.SheetIndex); + IEvaluationCell evalCell = evalSheet.GetCell(ec.RowIndex, ec.ColumnIndex); + if (evalCell != null) + { + if (evalCell.IsPartOfArrayFormulaGroup) + { + // array arguments must be evaluated relative to the function defining range + Util.CellRangeAddress ca = evalCell.ArrayFormulaRange; + return func.EvaluateArray(args, ca.FirstRow, ca.FirstColumn); + } + else if (ec.IsArraymode) + { + return func.EvaluateArray(args, ec.RowIndex, ec.ColumnIndex); + } + } + return null; + } } } \ No newline at end of file diff --git a/main/SS/Formula/PTG/ArrayPtg.cs b/main/SS/Formula/PTG/ArrayPtg.cs index a6c59f009..d3feaadaf 100644 --- a/main/SS/Formula/PTG/ArrayPtg.cs +++ b/main/SS/Formula/PTG/ArrayPtg.cs @@ -95,19 +95,18 @@ public ArrayPtg(Object[][] values2d) _reserved1Short = 0; _reserved2Byte = 0; } - public Object[][] GetTokenArrayValues() + public Object[,] GetTokenArrayValues() { if (_arrayValues == null) { throw new InvalidOperationException("array values not read yet"); } - Object[][] result = new Object[_nRows][]; + Object[,] result = new Object[_nRows,_nColumns]; for (int r = 0; r < _nRows; r++) { - result[r] = new object[_nColumns]; for (int c = 0; c < _nColumns; c++) { - result[r][c] = _arrayValues[GetValueIndex(c, r)]; + result[r,c] = _arrayValues[GetValueIndex(c, r)]; } } return result; diff --git a/main/SS/Formula/UserDefinedFunction.cs b/main/SS/Formula/UserDefinedFunction.cs index 4d5a3df4d..d9ddc3c23 100644 --- a/main/SS/Formula/UserDefinedFunction.cs +++ b/main/SS/Formula/UserDefinedFunction.cs @@ -41,6 +41,14 @@ public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) int nOutGoingArgs = nIncomingArgs - 1; ValueEval[] outGoingArgs = new ValueEval[nOutGoingArgs]; Array.Copy(args, 1, outGoingArgs, 0, nOutGoingArgs); + if (targetFunc is ArrayFunction) { + ArrayFunction func = (ArrayFunction)targetFunc; + ValueEval eval = OperationEvaluatorFactory.EvaluateArrayFunction(func, outGoingArgs, ec); + if (eval != null) + { + return eval; + } + } return targetFunc.Evaluate(outGoingArgs, ec); } } diff --git a/main/SS/Formula/WorkbookEvaluator.cs b/main/SS/Formula/WorkbookEvaluator.cs index 56f262d8f..c0ce65fa9 100644 --- a/main/SS/Formula/WorkbookEvaluator.cs +++ b/main/SS/Formula/WorkbookEvaluator.cs @@ -32,6 +32,7 @@ namespace NPOI.SS.Formula using NPOI.SS.Formula.PTG; using NPOI.Util; using NPOI.SS.Formula.Function; + using EnumsNET; /** * Evaluates formula cells.

@@ -258,12 +259,104 @@ public ValueEval Evaluate(IEvaluationCell srcCell) int sheetIndex = GetSheetIndex(srcCell.Sheet); return EvaluateAny(srcCell, sheetIndex, srcCell.RowIndex, srcCell.ColumnIndex, new EvaluationTracker(_cache)); } + /** + * Evaluate a formula outside a cell value, e.g. conditional format rules or data validation expressions + * + * @param formula to evaluate + * @param ref defines the optional sheet and row/column base for the formula, if it is relative + * @return value + */ + public ValueEval Evaluate(String formula, CellReference reference) + { + String sheetName = reference == null ? null : reference.SheetName; + int sheetIndex; + if (sheetName == null) + { + sheetIndex = -1; // workbook scope only + } + else + { + sheetIndex = Workbook.GetSheetIndex(sheetName); + } + int rowIndex = reference == null ? -1 : reference.Row; + int colIndex = reference == null ? -1 : reference.Col; + OperationEvaluationContext ec = new OperationEvaluationContext( + this, + Workbook, + sheetIndex, + rowIndex, + colIndex, + new EvaluationTracker(_cache) + ); + Ptg[] ptgs = FormulaParser.Parse(formula, (IFormulaParsingWorkbook)Workbook, FormulaType.Cell, sheetIndex, rowIndex); + return EvaluateNameFormula(ptgs, ec); + } + public ValueEval Evaluate(String formula, CellReference target, CellRangeAddressBase region) + { + return Evaluate(formula, target, region, FormulaType.Cell); + } + private ValueEval Evaluate(String formula, CellReference target, CellRangeAddressBase region, FormulaType formulaType) + { + String sheetName = target == null ? null : target.SheetName; + if (sheetName == null) throw new ArgumentException("Sheet name is required"); + int sheetIndex = Workbook.GetSheetIndex(sheetName); + Ptg[] ptgs = FormulaParser.Parse(formula, (IFormulaParsingWorkbook)Workbook, formulaType, sheetIndex, target.Row); - /** - * @return never null, never {@link BlankEval} - */ - private ValueEval EvaluateAny(IEvaluationCell srcCell, int sheetIndex, + AdjustRegionRelativeReference(ptgs, target, region); + + OperationEvaluationContext ec = new OperationEvaluationContext(this, Workbook, sheetIndex, target.Row, target.Col, new EvaluationTracker(_cache), + formulaType.GetAttributes().Get().IsSingleValue); + return EvaluateNameFormula(ptgs, ec); + } + protected bool AdjustRegionRelativeReference(Ptg[] ptgs, CellReference target, CellRangeAddressBase region) + { + if (!region.IsInRange(target)) + { + throw new ArgumentException(target + " is not within " + region); + } + + //return adjustRegionRelativeReference(ptgs, target.getRow() - region.getFirstRow(), target.getCol() - region.getFirstColumn()); + + int deltaRow = target.Row; + int deltaColumn = target.Col; + + bool shifted = false; + foreach(Ptg ptg in ptgs) + { + // base class for cell reference "things" + if (ptg is RefPtgBase) { + RefPtgBase reference = (RefPtgBase)ptg; + // re-calculate cell references + SpreadsheetVersion version = _workbook.GetSpreadsheetVersion(); + if (reference.IsRowRelative) + { + int rowIndex = reference.Row + deltaRow; + if (rowIndex > version.MaxRows) + { + throw new IndexOutOfRangeException(version.Name + " files can only have " + version.MaxRows + " rows, but row " + rowIndex + " was requested."); + } + reference.Row = rowIndex; + shifted = true; + } + if (reference.IsColRelative) + { + int colIndex = reference.Column + deltaColumn; + if (colIndex > version.MaxColumns) + { + throw new IndexOutOfRangeException(version.Name + " files can only have " + version.MaxColumns + " columns, but column " + colIndex + " was requested."); + } + reference.Column = colIndex; + shifted = true; + } + } + } + return shifted; + } + /** + * @return never null, never {@link BlankEval} + */ + private ValueEval EvaluateAny(IEvaluationCell srcCell, int sheetIndex, int rowIndex, int columnIndex, EvaluationTracker tracker) { bool shouldCellDependencyBeRecorded = _stabilityClassifier == null ? true @@ -454,6 +547,9 @@ public ValueEval EvaluateFormula(OperationEvaluationContext ec, Ptg[] ptgs) + "): " + Arrays.ToString(ptgs).Replace("\\Qorg.apache.poi.ss.formula.ptg.\\E", "")); dbgEvaluationOutputIndent++; } + + IEvaluationSheet evalSheet = ec.GetWorkbook().GetSheet(ec.SheetIndex); + IEvaluationCell evaluationCell = evalSheet.GetCell(ec.RowIndex, ec.ColumnIndex); Stack stack = new Stack(); for (int i = 0, iSize = ptgs.Length; i < iSize; i++) @@ -463,7 +559,7 @@ public ValueEval EvaluateFormula(OperationEvaluationContext ec, Ptg[] ptgs) Ptg ptg = ptgs[i]; if (dbgEvaluationOutputIndent > 0) { - EVAL_LOG.Log(POILogger.INFO, dbgIndentStr + " * ptg " + i + ": " + ptg.ToString()); + EVAL_LOG.Log(POILogger.INFO, dbgIndentStr + " * ptg " + i + ": " + ptg.ToString()+", stack:"+stack); } if (ptg is AttrPtg) { @@ -507,44 +603,48 @@ public ValueEval EvaluateFormula(OperationEvaluationContext ec, Ptg[] ptgs) } if (attrPtg.IsOptimizedIf) { - ValueEval arg0 = stack.Pop(); - bool evaluatedPredicate; - try + if (!evaluationCell.IsPartOfArrayFormulaGroup) { - evaluatedPredicate = IfFunc.EvaluateFirstArg(arg0, ec.RowIndex, ec.ColumnIndex); - } - catch (EvaluationException e) - { - stack.Push(e.GetErrorEval()); - int dist = attrPtg.Data; - i += CountTokensToBeSkipped(ptgs, i, dist); - attrPtg = (AttrPtg)ptgs[i]; - dist = attrPtg.Data + 1; - i += CountTokensToBeSkipped(ptgs, i, dist); - continue; - } - if (evaluatedPredicate) - { - // nothing to skip - true param folows - } - else - { - int dist = attrPtg.Data; - i += CountTokensToBeSkipped(ptgs, i, dist); - Ptg nextPtg = ptgs[i + 1]; - if (ptgs[i] is AttrPtg && nextPtg is FuncVarPtg && - // in order to verify that there is no third param, we need to check - // if we really have the IF next or some other FuncVarPtg as third param, e.g. ROW()/COLUMN()! - ((FuncVarPtg)nextPtg).FunctionIndex == FunctionMetadataRegistry.FUNCTION_INDEX_IF) - { - // this is an if statement without a false param (as opposed to MissingArgPtg as the false param) - i++; - stack.Push(BoolEval.FALSE); - } + ValueEval arg0 = stack.Pop(); + bool evaluatedPredicate; + try + { + evaluatedPredicate = IfFunc.EvaluateFirstArg(arg0, ec.RowIndex, ec.ColumnIndex); + } + catch (EvaluationException e) + { + stack.Push(e.GetErrorEval()); + int dist = attrPtg.Data; + i += CountTokensToBeSkipped(ptgs, i, dist); + attrPtg = (AttrPtg)ptgs[i]; + dist = attrPtg.Data + 1; + i += CountTokensToBeSkipped(ptgs, i, dist); + continue; + } + if (evaluatedPredicate) + { + // nothing to skip - true param folows + } + else + { + int dist = attrPtg.Data; + i += CountTokensToBeSkipped(ptgs, i, dist); + Ptg nextPtg = ptgs[i + 1]; + if (ptgs[i] is AttrPtg && nextPtg is FuncVarPtg && + // in order to verify that there is no third param, we need to check + // if we really have the IF next or some other FuncVarPtg as third param, e.g. ROW()/COLUMN()! + ((FuncVarPtg)nextPtg).FunctionIndex == FunctionMetadataRegistry.FUNCTION_INDEX_IF) + { + // this is an if statement without a false param (as opposed to MissingArgPtg as the false param) + i++; + stack.Push(arg0); + stack.Push(BoolEval.FALSE); + } + } } continue; } - if (attrPtg.IsSkip) + if (attrPtg.IsSkip && !evaluationCell.IsPartOfArrayFormulaGroup) { int dist = attrPtg.Data + 1; i += CountTokensToBeSkipped(ptgs, i, dist); @@ -566,8 +666,17 @@ public ValueEval EvaluateFormula(OperationEvaluationContext ec, Ptg[] ptgs) // can ignore, rest of Tokens for this expression are in OK RPN order continue; } - if (ptg is MemErrPtg) { continue; } - + if (ptg is MemErrPtg) + { + continue; + } + if (ptg is UnionPtg) + { + ValueEval v2 = stack.Pop(); + ValueEval v1 = stack.Pop(); + stack.Push(new RefListEval(v1, v2)); + continue; + } ValueEval opResult; if (ptg is OperationPtg) { @@ -608,7 +717,15 @@ public ValueEval EvaluateFormula(OperationEvaluationContext ec, Ptg[] ptgs) { throw new InvalidOperationException("evaluation stack not empty"); } - ValueEval result = DereferenceResult(value, ec.RowIndex, ec.ColumnIndex); + ValueEval result; + if (ec.IsSingleValue) + { + result = DereferenceResult(value, ec); + } + else + { + result = value; + } if (dbgEvaluationOutputIndent > 0) { EVAL_LOG.Log(POILogger.INFO, dbgIndentStr + "finshed eval of " @@ -675,6 +792,42 @@ public static ValueEval DereferenceResult(ValueEval evaluationResult, int srcRow return value; } /** + * Dereferences a single value from any AreaEval or RefEval evaluation + * result. If the supplied evaluationResult is just a plain value, it is + * returned as-is. + * + * @return a {@link NumberEval}, {@link StringEval}, {@link BoolEval}, or + * {@link ErrorEval}. Never null. {@link BlankEval} is + * converted to {@link NumberEval#ZERO} + */ + public static ValueEval DereferenceResult(ValueEval evaluationResult, OperationEvaluationContext ec) + { + ValueEval value; + + if (ec == null) + { + throw new ArgumentNullException("OperationEvaluationContext ec is null"); + } + if (ec.GetWorkbook() == null) + { + throw new ArgumentNullException("OperationEvaluationContext ec.getWorkbook() is null"); + } + + IEvaluationSheet evalSheet = ec.GetWorkbook().GetSheet(ec.SheetIndex); + IEvaluationCell evalCell = evalSheet.GetCell(ec.RowIndex, ec.ColumnIndex); + + if (evalCell.IsPartOfArrayFormulaGroup && evaluationResult is AreaEval) + { + value = OperandResolver.GetElementFromArray((AreaEval)evaluationResult, evalCell); + } + else + { + value = DereferenceResult(evaluationResult, ec.RowIndex, ec.ColumnIndex); + } + + return value; + } + /** * returns an appropriate Eval impl instance for the Ptg. The Ptg must be * one of: Area3DPtg, AreaPtg, ReferencePtg, Ref3DPtg, IntPtg, NumberPtg, * StringPtg, BoolPtg
special Note: OperationPtg subtypes cannot be @@ -756,6 +909,10 @@ private ValueEval GetEvalForPtg(Ptg ptg, OperationEvaluationContext ec) AreaPtg aptg = (AreaPtg)ptg; return ec.GetAreaEval(aptg.FirstRow, aptg.FirstColumn, aptg.LastRow, aptg.LastColumn); } + if (ptg is ArrayPtg) { + ArrayPtg aptg = (ArrayPtg)ptg; + return ec.GetAreaValueEval(0, 0, aptg.RowCount - 1, aptg.ColumnCount - 1, aptg.GetTokenArrayValues()); + } if (ptg is UnknownPtg) { @@ -902,4 +1059,4 @@ public bool DebugEvaluationOutputForNextEval set { dbgEvaluationOutputForNextEval = value; } } } -} \ No newline at end of file +} diff --git a/main/SS/UserModel/Cell.cs b/main/SS/UserModel/Cell.cs index a17bc330f..4a3db1654 100644 --- a/main/SS/UserModel/Cell.cs +++ b/main/SS/UserModel/Cell.cs @@ -125,6 +125,17 @@ CellType CellType /// void SetCellValue(DateTime value); +#if NET6_0_OR_GREATER + ///

+ /// Converts the supplied date to its equivalent Excel numeric value and Sets that into the cell. + /// + /// the numeric value to set this cell to. For formulas we'll set the + /// precalculated value, for numerics we'll set its value. For other types we will change + /// the cell to a numerics cell and set its value. + /// + void SetCellValue(DateOnly value); +#endif + /// /// Set a rich string value for the cell. /// @@ -157,7 +168,14 @@ CellType CellType ///
/// if the cell type returned by GetCellType() is not CELL_TYPE_FORMULA String CellFormula { get; set; } - + /// + /// Removes formula, if any. + /// + /// If cell was blank, leaves it as is. + /// If it is a part of an array formula group, blanks the cell. + /// If has a regular formula, removes the formula preserving the "cached" value. + /// + void RemoveFormula(); /// /// Sets formula for this cell. /// diff --git a/main/SS/UserModel/Color.cs b/main/SS/UserModel/Color.cs index 9240b51a8..17b3dbe1d 100644 --- a/main/SS/UserModel/Color.cs +++ b/main/SS/UserModel/Color.cs @@ -2,7 +2,7 @@ { public interface IColor { - //short Indexed { get; } - //byte[] RGB { get; } + short Indexed { get; } + byte[] RGB { get; } } } diff --git a/main/SS/UserModel/ConditionFilterData.cs b/main/SS/UserModel/ConditionFilterData.cs new file mode 100644 index 000000000..0ad78f1f5 --- /dev/null +++ b/main/SS/UserModel/ConditionFilterData.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.UserModel +{ + public interface IConditionFilterData + { + /** + * @return true if the flag is missing or set to true + */ + bool AboveAverage{ get; } + + /** + * @return true if the flag is set + */ + bool Bottom{ get; } + + /** + * @return true if the flag is set + */ + bool EqualAverage{ get; } + + /** + * @return true if the flag is set + */ + bool Percent{ get; } + + /** + * @return value, or 0 if not used/defined + */ + long Rank{ get; } + + /** + * @return value, or 0 if not used/defined + */ + int StdDev{ get; } + } +} diff --git a/main/SS/UserModel/ConditionFilterType.cs b/main/SS/UserModel/ConditionFilterType.cs new file mode 100644 index 000000000..2c8f8ae8a --- /dev/null +++ b/main/SS/UserModel/ConditionFilterType.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.UserModel +{ + public enum ConditionFilterType + { + FILTER, + TOP_10, + UNIQUE_VALUES, + DUPLICATE_VALUES, + CONTAINS_TEXT, + NOT_CONTAINS_TEXT, + BEGINS_WITH, + ENDS_WITH, + CONTAINS_BLANKS, + NOT_CONTAINS_BLANKS, + CONTAINS_ERRORS, + NOT_CONTAINS_ERRORS, + TIME_PERIOD, + ABOVE_AVERAGE + } +} diff --git a/main/SS/UserModel/ConditionalFormattingRule.cs b/main/SS/UserModel/ConditionalFormattingRule.cs index 89eb8511b..f6f44b2ef 100644 --- a/main/SS/UserModel/ConditionalFormattingRule.cs +++ b/main/SS/UserModel/ConditionalFormattingRule.cs @@ -129,6 +129,29 @@ public interface IConditionalFormattingRule * @return the second formula */ String Formula2 { get; } + + /// + /// XSSF rules store textual condition values as an attribute and also as a formula that needs shifting. Using the attribute is simpler/faster. + /// HSSF rules don't have this and return null. We can fall back on the formula for those (AFAIK). + /// @return condition text if it exists, or null + /// + String Text { get; } + + /// + /// The priority of the rule, if defined, otherwise 0. + /// For XSSF, this should always be set.For HSSF, only newer style rules + /// have this set, older ones will return 0. + /// + /// + int Priority {get; } + + bool StopIfTrue { get; } + + ExcelNumberFormat NumberFormat { get; } + + ConditionFilterType? ConditionFilterType { get; } + + IConditionFilterData FilterConfiguration { get; } } } \ No newline at end of file diff --git a/main/SS/UserModel/DataConsolidateFunction.cs b/main/SS/UserModel/DataConsolidateFunction.cs index 2a0f9c8e5..7a1d02dc3 100644 --- a/main/SS/UserModel/DataConsolidateFunction.cs +++ b/main/SS/UserModel/DataConsolidateFunction.cs @@ -26,17 +26,17 @@ namespace NPOI.SS.UserModel */ public class DataConsolidateFunction { - public static DataConsolidateFunction AVERAGE = new DataConsolidateFunction(1, "Average"), - COUNT = new DataConsolidateFunction(2, "Count"), - COUNT_NUMS = new DataConsolidateFunction(3, "Count"), - MAX = new DataConsolidateFunction(4, "Max"), - MIN = new DataConsolidateFunction(5, "Min"), - PRODUCT = new DataConsolidateFunction(6, "Product"), - STD_DEV = new DataConsolidateFunction(7, "StdDev"), - STD_DEVP = new DataConsolidateFunction(8, "StdDevp"), - SUM = new DataConsolidateFunction(9, "Sum"), - VAR = new DataConsolidateFunction(10, "Var"), - VARP = new DataConsolidateFunction(11, "Varp"); + public static DataConsolidateFunction AVERAGE = new DataConsolidateFunction(0, "Average"), + COUNT = new DataConsolidateFunction(1, "Count"), + COUNT_NUMS = new DataConsolidateFunction(2, "Count"), + MAX = new DataConsolidateFunction(3, "Max"), + MIN = new DataConsolidateFunction(4, "Min"), + PRODUCT = new DataConsolidateFunction(5, "Product"), + STD_DEV = new DataConsolidateFunction(6, "StdDev"), + STD_DEVP = new DataConsolidateFunction(7, "StdDevp"), + SUM = new DataConsolidateFunction(8, "Sum"), + VAR = new DataConsolidateFunction(9, "Var"), + VARP = new DataConsolidateFunction(10, "Varp"); private int value; private String name; diff --git a/main/SS/UserModel/DateUtil.cs b/main/SS/UserModel/DateUtil.cs index a3d62b0f2..a9b0a3580 100644 --- a/main/SS/UserModel/DateUtil.cs +++ b/main/SS/UserModel/DateUtil.cs @@ -239,6 +239,46 @@ public static double GetExcelDate(DateTime date, bool use1904windowing) return value; } +#if NET6_0_OR_GREATER + /// + /// Given a Date, Converts it into a double representing its internal Excel representation, + /// which Is the number of days since 1/1/1900. Fractional days represent hours, minutes, and seconds. + /// + /// The date. + /// Should 1900 or 1904 date windowing be used? + /// Excel representation of Date (-1 if error - test for error by Checking for less than 0.1) + public static double GetExcelDate(DateOnly date, bool use1904windowing) + { + if ((!use1904windowing && date.Year < 1900) //1900 date system must bigger than 1900 + || (use1904windowing && date.Year < 1904)) //1904 date system must bigger than 1904 + { + return BAD_DATE; + } + + DateOnly startdate; + if (use1904windowing) + { + startdate = new DateOnly(1904, 1, 1); + } + else + { + startdate = new DateOnly(1900, 1, 1); + } + + double value = (date.ToDateTime(TimeOnly.MinValue) - startdate.ToDateTime(TimeOnly.MinValue)).TotalDays + 1; + + if (!use1904windowing && value >= 60) + { + value++; + } + else if (use1904windowing) + { + value--; + } + return value; + } +#endif + /// /// Given an Excel date with using 1900 date windowing, and converts it to a java.util.Date. /// Excel Dates and Times are stored without any timezone @@ -843,7 +883,9 @@ public static bool IsCellInternalDateFormatted(ICell cell) public static bool IsValidExcelDate(double value) { //return true; - return value > -Double.Epsilon; + + const int maxDate = 2958465; // 31/12/9999 + return value > -Double.Epsilon && value <= maxDate; } } diff --git a/main/SS/UserModel/DifferentialStyleProvider.cs b/main/SS/UserModel/DifferentialStyleProvider.cs new file mode 100644 index 000000000..a05fc63c9 --- /dev/null +++ b/main/SS/UserModel/DifferentialStyleProvider.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.UserModel +{ + public interface DifferentialStyleProvider + { + IBorderFormatting BorderFormatting { get; } + IFontFormatting FontFormatting { get; } + IPatternFormatting PatternFormatting { get; } + ExcelNumberFormat NumberFormat { get; } + int StripeSize { get; } + } +} diff --git a/main/SS/UserModel/ExcelNumberFormat.cs b/main/SS/UserModel/ExcelNumberFormat.cs new file mode 100644 index 000000000..497081930 --- /dev/null +++ b/main/SS/UserModel/ExcelNumberFormat.cs @@ -0,0 +1,55 @@ +using NPOI.SS.Formula; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.UserModel +{ + public class ExcelNumberFormat + { + private int idx; + private String format; + public ExcelNumberFormat(int idx, String format) + { + this.idx = idx; + this.format = format; + } + public static ExcelNumberFormat From(ICellStyle style) + { + if (style == null) return null; + return new ExcelNumberFormat(style.DataFormat, style.GetDataFormatString()); + } + + public static ExcelNumberFormat From(ICell cell, ConditionalFormattingEvaluator cfEvaluator) + { + if (cell == null) return null; + + ExcelNumberFormat nf = null; + + if (cfEvaluator != null) + { + // first one wins (priority order, per Excel help) + List rules = cfEvaluator.GetConditionalFormattingForCell(cell); + foreach (EvaluationConditionalFormatRule rule in rules) + { + nf = rule.NumberFormat; + if (nf != null) break; + } + } + if (nf == null) + { + ICellStyle style = cell.CellStyle; + nf = ExcelNumberFormat.From(style); + } + return nf; + } + public int Idx + { + get { return idx; } + } + public String Format + { + get { return format; } + } + } +} diff --git a/main/SS/UserModel/ExtendedColor.cs b/main/SS/UserModel/ExtendedColor.cs index 43c03786a..16c0f9d47 100644 --- a/main/SS/UserModel/ExtendedColor.cs +++ b/main/SS/UserModel/ExtendedColor.cs @@ -60,6 +60,11 @@ protected void SetColor(Color clr) */ public abstract short Index { get; } + public virtual short Indexed + { + get { return Index; } + } + /** * Index of Theme color, if {@link #isThemed()} is true */ diff --git a/main/SS/UserModel/Helpers/BaseRowColShifter.cs b/main/SS/UserModel/Helpers/BaseRowColShifter.cs new file mode 100644 index 000000000..ed9b3fa11 --- /dev/null +++ b/main/SS/UserModel/Helpers/BaseRowColShifter.cs @@ -0,0 +1,72 @@ +using NPOI.SS.Formula; +using NPOI.SS.Formula.PTG; +using NPOI.SS.Util; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.UserModel.Helpers +{ + public abstract class BaseRowColShifter + { + //Update named ranges + public abstract void UpdateNamedRanges(FormulaShifter formulaShifter); + + /** + * Update formulas. + */ + public abstract void updateFormulas(FormulaShifter formulaShifter); + + /** + * Shifts, grows, or shrinks the merged regions due to a row shift + * ({@link RowShifter}) or column shift ({@link ColumnShifter}). + * Merged regions that are completely overlaid by shifting will be deleted. + * + * @param start the first row or column to be shifted + * @param end the last row or column to be shifted + * @param n the number of rows or columns to shift + * @return a list of affected merged regions, excluding contain deleted ones + */ + public abstract List shiftMergedRegions(int start, int end, int n); + + /** + * Update conditional formatting + * @param formulaShifter The {@link FormulaShifter} to use + */ + public abstract void updateConditionalFormatting(FormulaShifter formulaShifter); + + /** + * Shift the Hyperlink anchors (not the hyperlink text, even if the hyperlink + * is of type LINK_DOCUMENT and refers to a cell that was shifted). Hyperlinks + * do not track the content they point to. + * + * @param formulaShifter the formula shifting policy + */ + public abstract void updateHyperlinks(FormulaShifter formulaShifter); + + + + public static CellRangeAddress ShiftRange(FormulaShifter Shifter, CellRangeAddress cra, int currentExternSheetIx) + { + // FormulaShifter works well in terms of Ptgs - so convert CellRangeAddress to AreaPtg (and back) here + AreaPtg aptg = new AreaPtg(cra.FirstRow, cra.LastRow, cra.FirstColumn, cra.LastColumn, false, false, false, false); + Ptg[] ptgs = { aptg, }; + + if (!Shifter.AdjustFormula(ptgs, currentExternSheetIx)) + { + return cra; + } + Ptg ptg0 = ptgs[0]; + if (ptg0 is AreaPtg) + { + AreaPtg bptg = (AreaPtg)ptg0; + return new CellRangeAddress(bptg.FirstRow, bptg.LastRow, bptg.FirstColumn, bptg.LastColumn); + } + if (ptg0 is AreaErrPtg) + { + return null; + } + throw new InvalidOperationException("Unexpected Shifted ptg class (" + ptg0.GetType().Name + ")"); + } + } +} diff --git a/main/SS/UserModel/Helpers/RowShifter.cs b/main/SS/UserModel/Helpers/RowShifter.cs index 490e9c560..6a7b9b6dc 100644 --- a/main/SS/UserModel/Helpers/RowShifter.cs +++ b/main/SS/UserModel/Helpers/RowShifter.cs @@ -20,6 +20,7 @@ namespace NPOI.SS.UserModel.Helpers using NPOI.SS.Formula; using NPOI.SS.UserModel; using NPOI.SS.Util; + using System; using System.Collections.Generic; using System.Linq; @@ -57,7 +58,8 @@ public List ShiftMergedRegions(int startRow, int endRow, int n CellRangeAddress merged = sheet.GetMergedRegion(i); // remove merged region that overlaps Shifting - if (startRow + n <= merged.FirstRow && endRow + n >= merged.LastRow) + var lastCol=sheet.GetRow(startRow) != null ? sheet.GetRow(startRow).LastCellNum : sheet.GetRow(endRow) != null ? sheet.GetRow(endRow).LastCellNum : 0; + if (removalNeeded(merged, startRow, endRow, n, lastCol )) { removedIndices.Add(i); continue; @@ -75,15 +77,15 @@ public List ShiftMergedRegions(int startRow, int endRow, int n //only shift if the region outside the Shifted rows is not merged too if (!merged.ContainsRow(startRow - 1) && !merged.ContainsRow(endRow + 1)) { - merged.FirstRow = (/*setter*/merged.FirstRow + n); - merged.LastRow = (/*setter*/merged.LastRow + n); + merged.FirstRow = merged.FirstRow + n; + merged.LastRow =merged.LastRow + n; //have to Remove/add it back ShiftedRegions.Add(merged); removedIndices.Add(i); } } - if (!(removedIndices.Count==0)/*.IsEmpty()*/) + if (removedIndices.Count!=0) { sheet.RemoveMergedRegions(removedIndices.ToList()); } @@ -96,6 +98,68 @@ public List ShiftMergedRegions(int startRow, int endRow, int n return ShiftedRegions; } + // Keep in sync with {@link ColumnShifter#removalNeeded} + private bool removalNeeded(CellRangeAddress merged, int startRow, int endRow, int n, int lastCol) + { + int movedRows = endRow - startRow + 1; + + // build a range of the rows that are overwritten, i.e. the target-area, but without + // rows that are moved along + CellRangeAddress overwrite; + if (n > 0) + { + // area is moved down => overwritten area is [endRow + n - movedRows, endRow + n] + int firstRow = Math.Max(endRow + 1, endRow + n - movedRows); + int lastRow = endRow + n; + overwrite = new CellRangeAddress(firstRow, lastRow, 0, lastCol); + } + else + { + // area is moved up => overwritten area is [startRow + n, startRow + n + movedRows] + int firstRow = startRow + n; + int lastRow = Math.Min(startRow - 1, startRow + n + movedRows); + overwrite = new CellRangeAddress(firstRow, lastRow, 0, lastCol); + } + + // if the merged-region and the overwritten area intersect, we need to remove it + return merged.Intersects(overwrite); + } + + /** + * Verify that the given column indices and step denote a valid range of columns to shift + * + * @param firstShiftColumnIndex the column to start shifting + * @param lastShiftColumnIndex the column to end shifting + * @param step length of the shifting step + */ + public static void ValidateShiftParameters(int firstShiftColumnIndex, int lastShiftColumnIndex, int step) + { + if (step < 0) + { + throw new ArgumentException("Shifting step may not be negative, but had " + step); + } + if (firstShiftColumnIndex > lastShiftColumnIndex) + { + throw new ArgumentException(String.Format("Incorrect shifting range : %d-%d", firstShiftColumnIndex, lastShiftColumnIndex)); + } + } + + /** + * Verify that the given column indices and step denote a valid range of columns to shift to the left + * + * @param firstShiftColumnIndex the column to start shifting + * @param lastShiftColumnIndex the column to end shifting + * @param step length of the shifting step + */ + public static void ValidateShiftLeftParameters(int firstShiftColumnIndex, int lastShiftColumnIndex, int step) + { + ValidateShiftParameters(firstShiftColumnIndex, lastShiftColumnIndex, step); + + if (firstShiftColumnIndex - step < 0) + { + throw new InvalidOperationException("Column index less than zero: " + (firstShiftColumnIndex + step)); + } + } /** * Updated named ranges */ diff --git a/main/SS/UserModel/TableStyle.cs b/main/SS/UserModel/TableStyle.cs new file mode 100644 index 000000000..fbd8ab751 --- /dev/null +++ b/main/SS/UserModel/TableStyle.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.UserModel +{ + public interface ITableStyle + { + string Name { get; } + int Index { get; } + bool IsBuiltin { get; } + DifferentialStyleProvider GetStyle(TableStyleType type); + } +} diff --git a/main/SS/UserModel/TableStyleInfo.cs b/main/SS/UserModel/TableStyleInfo.cs new file mode 100644 index 000000000..33b9f41bc --- /dev/null +++ b/main/SS/UserModel/TableStyleInfo.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.UserModel +{ + public interface ITableStyleInfo + { + bool IsShowColumnStripes { get; set; } + /// + /// return true if alternating row styles should be applied + /// + bool IsShowRowStripes { get; set; } + /// + /// return true if the distinct first column style should be applied + /// + bool IsShowFirstColumn { get; set; } + + /// + /// return true if the distinct last column style should be applied + /// + bool IsShowLastColumn { get; set; } + /// + /// return the name of the style (may reference a built-in style) + /// + String Name { get; set; } + + /// + /// style definition + /// + ITableStyle Style { get; } + } +} diff --git a/main/SS/UserModel/TableStyleType.cs b/main/SS/UserModel/TableStyleType.cs new file mode 100644 index 000000000..acd1e22b0 --- /dev/null +++ b/main/SS/UserModel/TableStyleType.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.SS.UserModel +{ + public enum TableStyleType + { + wholeTable, + pageFieldLabels,// pivot only + pageFieldValues,// pivot only + firstColumnStripe, + secondColumnStripe, + firstRowStripe, + secondRowStripe, + lastColumn, + firstColumn, + headerRow, + totalRow, + firstHeaderCell, + lastHeaderCell, + firstTotalCell, + lastTotalCell, + /* these are for pivot tables only */ + /***/ + firstSubtotalColumn, + /***/ + secondSubtotalColumn, + /***/ + thirdSubtotalColumn, + /***/ + blankRow, + /***/ + firstSubtotalRow, + /***/ + secondSubtotalRow, + /***/ + thirdSubtotalRow, + /***/ + firstColumnSubheading, + /***/ + secondColumnSubheading, + /***/ + thirdColumnSubheading, + /***/ + firstRowSubheading, + /***/ + secondRowSubheading, + /***/ + thirdRowSubheading + } +} diff --git a/main/SS/UserModel/Workbook.cs b/main/SS/UserModel/Workbook.cs index 7bed60150..13827b1b3 100644 --- a/main/SS/UserModel/Workbook.cs +++ b/main/SS/UserModel/Workbook.cs @@ -241,7 +241,7 @@ public interface IWorkbook : ICloseable /// Write out this workbook to an OutPutstream. /// /// the stream you wish to write to - void Write(Stream stream); + void Write(Stream stream, bool leaveOpen); /// /// the total number of defined names in this workbook diff --git a/main/SS/Util/AreaReference.cs b/main/SS/Util/AreaReference.cs index 08d68265e..e45b2ac82 100644 --- a/main/SS/Util/AreaReference.cs +++ b/main/SS/Util/AreaReference.cs @@ -105,7 +105,59 @@ public AreaReference(String reference, SpreadsheetVersion version) _isSingleCell = part0.Equals(part1); } } - + public AreaReference(CellReference topLeft, CellReference botRight, SpreadsheetVersion version) + { + _version = (null != version) ? version : DEFAULT_SPREADSHEET_VERSION; + bool swapRows = topLeft.Row > botRight.Row; + bool swapCols = topLeft.Col > botRight.Col; + if (swapRows || swapCols) + { + int firstRow; + int lastRow; + int firstColumn; + int lastColumn; + bool firstRowAbs; + bool lastRowAbs; + bool firstColAbs; + bool lastColAbs; + if (swapRows) + { + firstRow = botRight.Row; + firstRowAbs = botRight.IsRowAbsolute; + lastRow = topLeft.Row; + lastRowAbs = topLeft.IsRowAbsolute; + } + else + { + firstRow = topLeft.Row; + firstRowAbs = topLeft.IsRowAbsolute; + lastRow = botRight.Row; + lastRowAbs = botRight.IsRowAbsolute; + } + if (swapCols) + { + firstColumn = botRight.Col; + firstColAbs = botRight.IsColAbsolute; + lastColumn = topLeft.Col; + lastColAbs = topLeft.IsColAbsolute; + } + else + { + firstColumn = topLeft.Col; + firstColAbs = topLeft.IsColAbsolute; + lastColumn = botRight.Col; + lastColAbs = botRight.IsColAbsolute; + } + _firstCell = new CellReference(firstRow, firstColumn, firstRowAbs, firstColAbs); + _lastCell = new CellReference(lastRow, lastColumn, lastRowAbs, lastColAbs); + } + else + { + _firstCell = topLeft; + _lastCell = botRight; + } + _isSingleCell = false; + } private static bool IsPlainColumn(String refPart) { for (int i = refPart.Length - 1; i >= 0; i--) diff --git a/main/SS/Util/CellRangeAddressBase.cs b/main/SS/Util/CellRangeAddressBase.cs index 71a91daa7..79ccd4587 100644 --- a/main/SS/Util/CellRangeAddressBase.cs +++ b/main/SS/Util/CellRangeAddressBase.cs @@ -96,6 +96,10 @@ public bool IsInRange(int rowInd, int colInd) return _firstRow <= rowInd && rowInd <= _lastRow && //containsRow _firstCol <= colInd && colInd <= _lastCol; //containsColumn } + public bool IsInRange(CellReference reference) + { + return IsInRange(reference.Row, reference.Col); + } public bool IsFullColumnRange { get diff --git a/main/SS/Util/CellUtil.cs b/main/SS/Util/CellUtil.cs index e4918b699..ba8bd19ec 100644 --- a/main/SS/Util/CellUtil.cs +++ b/main/SS/Util/CellUtil.cs @@ -366,7 +366,7 @@ public static void SetFont(ICell cell, IFont font) * @param properties The properties to be added to a cell style, as {propertyName: propertyValue}. * @since POI 3.14 beta 2 */ - public static void SetCellStyleProperties(ICell cell, Dictionary properties) + public static void SetCellStyleProperties(ICell cell, Dictionary properties, bool cloneExistingStyles=false) { IWorkbook workbook = cell.Sheet.Workbook; ICellStyle originalStyle = cell.CellStyle; @@ -395,6 +395,10 @@ public static void SetCellStyleProperties(ICell cell, Dictionary if (newStyle == null) { newStyle = workbook.CreateCellStyle(); + if (cloneExistingStyles) + { + newStyle.CloneStyleFrom(originalStyle); + } SetFormatProperties(newStyle, workbook, values); } diff --git a/main/SS/Util/SheetUtil.cs b/main/SS/Util/SheetUtil.cs index dc65b2773..aa887831a 100644 --- a/main/SS/Util/SheetUtil.cs +++ b/main/SS/Util/SheetUtil.cs @@ -411,13 +411,17 @@ public static double GetColumnWidth(ISheet sheet, int column, bool useMergedCell * @param useMergedCells whether to use merged cells * @param firstRow 0-based index of the first row to consider (inclusive) * @param lastRow 0-based index of the last row to consider (inclusive) + * @param maxRows limit the scope to maxRows rows to speed up the function, or leave 0 (optional) * @return the width in pixels or -1 if cell is empty */ - public static double GetColumnWidth(ISheet sheet, int column, bool useMergedCells, int firstRow, int lastRow) + public static double GetColumnWidth(ISheet sheet, int column, bool useMergedCells, int firstRow, int lastRow, int maxRows=0) { DataFormatter formatter = new DataFormatter(); int defaultCharWidth = GetDefaultCharWidth(sheet.Workbook); + // No need to explore the whole sheet: explore only the first maxRows lines + if (maxRows > 0 && lastRow - firstRow > maxRows) lastRow = firstRow + maxRows; + double width = -1; for (int rowIdx = firstRow; rowIdx <= lastRow; ++rowIdx) { diff --git a/main/Util/LittleEndianByteArrayOutputStream.cs b/main/Util/LittleEndianByteArrayOutputStream.cs index ef0dfbdf2..eecb1701e 100644 --- a/main/Util/LittleEndianByteArrayOutputStream.cs +++ b/main/Util/LittleEndianByteArrayOutputStream.cs @@ -123,5 +123,9 @@ public ILittleEndianOutput CreateDelayedOutput(int size) _writeIndex += size; return result; } + public override string ToString() + { + return System.BitConverter.ToString(_buf); + } } } \ No newline at end of file diff --git a/main/Util/ObjectExtensions.cs b/main/Util/ObjectExtensions.cs index 3dc79e039..b732237de 100644 --- a/main/Util/ObjectExtensions.cs +++ b/main/Util/ObjectExtensions.cs @@ -1,8 +1,9 @@ using System.Collections.Generic; using System.Reflection; -using System.ArrayExtensions; +using System; +using NPOI.Util.ArrayExtensions; -namespace System +namespace NPOI.Util { public static class ObjectExtensions { diff --git a/main/Util/RecyclableMemory.cs b/main/Util/RecyclableMemory.cs new file mode 100644 index 000000000..ce1f842df --- /dev/null +++ b/main/Util/RecyclableMemory.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading; + +namespace NPOI.Util +{ + public static class RecyclableMemory + { + private static Microsoft.IO.RecyclableMemoryStreamManager _memoryManager; + private static bool _dataInitialized = false; + private static object _dataLock = new object(); + + private static Microsoft.IO.RecyclableMemoryStreamManager MemoryManager + { + get + { + return LazyInitializer.EnsureInitialized(ref _memoryManager, ref _dataInitialized, ref _dataLock); + } + } + + public static void SetRecyclableMemoryStreamManager(Microsoft.IO.RecyclableMemoryStreamManager recyclableMemoryStreamManager) + { + _dataInitialized = recyclableMemoryStreamManager is object; + _memoryManager = recyclableMemoryStreamManager; + } + + public static MemoryStream GetStream() + { + return MemoryManager.GetStream(); + } + public static MemoryStream GetStream(byte[] array) + { + return MemoryManager.GetStream(array); + } + + public static MemoryStream GetStream(int capacity) + { + return MemoryManager.GetStream(null, capacity); + } + } +} \ No newline at end of file diff --git a/main/packages.config b/main/packages.config index d460d74a6..7e45f57f7 100644 --- a/main/packages.config +++ b/main/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/ooxml/NPOI.OOXML.Core.csproj b/ooxml/NPOI.OOXML.Core.csproj index 806d95d45..bc51cd2a6 100644 --- a/ooxml/NPOI.OOXML.Core.csproj +++ b/ooxml/NPOI.OOXML.Core.csproj @@ -1,7 +1,7 @@  - netstandard2.0;netstandard2.1 + netstandard2.0;netstandard2.1;net6.0 false NPOI.OOXML NPOI.OOXML @@ -30,6 +30,14 @@ + + + + + + + + diff --git a/ooxml/NPOI.OOXML.csproj b/ooxml/NPOI.OOXML.csproj index b78cb0ab8..b3f2329ef 100644 --- a/ooxml/NPOI.OOXML.csproj +++ b/ooxml/NPOI.OOXML.csproj @@ -73,7 +73,7 @@ TRACE;HIDE_UNREACHABLE_CODE ..\solution\Lib\.net45\NPOI.OOXML.XML true - 1591 + 1591;1587;1570 pdbonly AnyCPU 7.3 @@ -199,6 +199,7 @@ Code + @@ -208,9 +209,11 @@ + + @@ -222,6 +225,7 @@ + @@ -234,6 +238,7 @@ + @@ -243,6 +248,7 @@ + @@ -279,6 +285,9 @@ + + + @@ -386,7 +395,11 @@ - + + + 4.0.0 + + {10fa8538-157a-4380-a4f6-8e2c3ee92cae} diff --git a/ooxml/POIFS/Crypt/Agile/AgileEncryptionHeader.cs b/ooxml/POIFS/Crypt/Agile/AgileEncryptionHeader.cs index 81520f177..1c40de0a5 100644 --- a/ooxml/POIFS/Crypt/Agile/AgileEncryptionHeader.cs +++ b/ooxml/POIFS/Crypt/Agile/AgileEncryptionHeader.cs @@ -42,7 +42,7 @@ protected internal AgileEncryptionHeader(EncryptionDocument ed) throw new NullReferenceException("keyData not Set"); } } - catch (Exception e) + catch (Exception) { throw new EncryptedDocumentException("Unable to parse keyData"); } diff --git a/ooxml/POIFS/Crypt/Dsig/OOXMLURIDereferencer.cs b/ooxml/POIFS/Crypt/Dsig/OOXMLURIDereferencer.cs index 641af01e0..8b5791256 100644 --- a/ooxml/POIFS/Crypt/Dsig/OOXMLURIDereferencer.cs +++ b/ooxml/POIFS/Crypt/Dsig/OOXMLURIDereferencer.cs @@ -102,7 +102,7 @@ public IData dereference(IURIReference uriReference, SignedXml context) throw new NotImplementedException(); } } - catch (IOException e) + catch (IOException) { //throw new URIReferenceException("I/O error: " + e.Message, e); throw new NotImplementedException(); @@ -128,7 +128,7 @@ private PackagePart FindPart(Uri uri) { ppn = PackagingUriHelper.CreatePartName(path); } - catch (InvalidFormatException e) + catch (InvalidFormatException) { //Console.WriteLine(POILogger.WARN, "illegal part name (not expected)", uri); return null; diff --git a/ooxml/POIFS/Crypt/Dsig/SignatureConfig.cs b/ooxml/POIFS/Crypt/Dsig/SignatureConfig.cs index 699db9c26..5c085f330 100644 --- a/ooxml/POIFS/Crypt/Dsig/SignatureConfig.cs +++ b/ooxml/POIFS/Crypt/Dsig/SignatureConfig.cs @@ -38,9 +38,9 @@ public class SignatureConfig { private ThreadLocal opcPackage = new ThreadLocal(); - ///private ThreadLocal signatureFactory = new ThreadLocal(); - ///private ThreadLocal keyInfoFactory = new ThreadLocal(); - ///private ThreadLocal provider = new ThreadLocal(); + //private ThreadLocal signatureFactory = new ThreadLocal(); + //private ThreadLocal keyInfoFactory = new ThreadLocal(); + //private ThreadLocal provider = new ThreadLocal(); private List signatureFacets = new List(); private HashAlgorithm digestAlgo = HashAlgorithm.sha1; diff --git a/ooxml/POIXMLDocumentPart.cs b/ooxml/POIXMLDocumentPart.cs index f84942061..aebff9d42 100644 --- a/ooxml/POIXMLDocumentPart.cs +++ b/ooxml/POIXMLDocumentPart.cs @@ -24,6 +24,7 @@ namespace NPOI using NPOI.OpenXml4Net.Exceptions; using System.Xml; using NPOI.OpenXml4Net.OPC.Internal; + using System.Diagnostics; /** * Represents an entry of a OOXML namespace. @@ -318,7 +319,7 @@ public PackageRelationship GetPackageRelationship() String partName = GetPackagePart().PartName.Name; foreach (PackageRelationship rel in pkg.Relationships) { - if (rel.TargetUri.ToString().Equals(partName)) + if (rel.TargetUri.OriginalString.Equals(partName)) { return rel; } @@ -401,32 +402,27 @@ public String GetRelationId(POIXMLDocumentPart part) return null; } - /** - * Add a new child POIXMLDocumentPart - * - * @param part the child to add - * - * @deprecated in POI 3.14, scheduled for removal in POI 3.16 - */ - [Obsolete("deprecated in POI 3.14, scheduled for removal in POI 3.16")] + /// + /// Add a new child POIXMLDocumentPart + /// + /// + /// the child to add + [Obsolete("deprecated in POI 3.14, scheduled for removal in POI 3.16")] public void AddRelation(String id, POIXMLDocumentPart part) { PackageRelationship pr = part.GetPackagePart().GetRelationship(id); AddRelation(pr, part); } - - /** - * Add a new child POIXMLDocumentPart - * - * @param relId the preferred relation id, when null the next free relation id will be used - * @param relationshipType the package relationship type - * @param part the child to add - * - * @since 3.14-Beta1 - */ + /// + /// Add a new child POIXMLDocumentPart + /// + /// the preferred relation id, when null the next free relation id will be used + /// the package relationship type + /// the child to add + /// public RelationPart AddRelation(String relId, POIXMLRelation relationshipType, POIXMLDocumentPart part) { - PackageRelationship pr = FindExistingRelation(part); + PackageRelationship pr = this.packagePart.FindExistingRelation(part.GetPackagePart()); if (pr == null) { PackagePartName ppn = part.GetPackagePart().PartName; @@ -436,13 +432,11 @@ public RelationPart AddRelation(String relId, POIXMLRelation relationshipType, P AddRelation(pr, part); return new RelationPart(pr, part); } - - /** - * Add a new child POIXMLDocumentPart - * - * @param pr the relationship of the child - * @param part the child to add - */ + /// + /// Add a new child POIXMLDocumentPart + /// + /// the relationship of the child + /// the child to add private void AddRelation(PackageRelationship pr, POIXMLDocumentPart part) { if (relations.ContainsKey(pr.Id)) @@ -453,36 +447,6 @@ private void AddRelation(PackageRelationship pr, POIXMLDocumentPart part) } - /// - /// Check if the new part was already added before via PackagePart.addRelationship() - /// - /// to find the relationship for - /// The existing relationship, or null if there isn't yet one - private PackageRelationship FindExistingRelation(POIXMLDocumentPart part) - { - String ppn = part.GetPackagePart().PartName.Name; - try - { - foreach (PackageRelationship pr in packagePart.Relationships) - { - PackagePart pp = packagePart.GetRelatedPart(pr); - if (pr.TargetMode == TargetMode.External) - { - continue; - } - if (ppn.Equals(pp.PartName.Name)) - { - return pr; - } - } - } - catch (InvalidFormatException e) - { - throw new POIXMLException("invalid package relationships", e); - } - return null; - } - /** * Remove the relation to the specified part in this namespace and remove the * part, if it is no longer needed. diff --git a/ooxml/POIXMLFactory.cs b/ooxml/POIXMLFactory.cs index cad3ee149..0beebce0d 100644 --- a/ooxml/POIXMLFactory.cs +++ b/ooxml/POIXMLFactory.cs @@ -63,7 +63,7 @@ public virtual POIXMLDocumentPart CreateDocumentPart(POIXMLDocumentPart parent, { return CreateDocumentPart(cls, PARENT_PART, new Object[] { parent, part }); } - catch (MissingMethodException e) + catch (MissingMethodException) { return CreateDocumentPart(cls, ORPHAN_PART, new Object[] { part }); } @@ -138,7 +138,7 @@ protected PackageRelationship GetPackageRelationship(POIXMLDocumentPart parent, String partName = part.PartName.Name; foreach (PackageRelationship pr in parent.GetPackagePart().Relationships) { - String packName = pr.TargetUri.ToString();// toASCIIString(); + String packName = pr.TargetUri.OriginalString;// toASCIIString(); if (packName.Equals(partName, StringComparison.CurrentCultureIgnoreCase)) { return pr; diff --git a/ooxml/Properties/AssemblyInfo.cs b/ooxml/Properties/AssemblyInfo.cs index 555bd2c07..a24a6643e 100644 --- a/ooxml/Properties/AssemblyInfo.cs +++ b/ooxml/Properties/AssemblyInfo.cs @@ -33,8 +33,8 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("2.5.5.0")] -[assembly: AssemblyFileVersion("2.5.5.0")] +[assembly: AssemblyVersion("2.6.0.0")] +[assembly: AssemblyFileVersion("2.6.0.0")] [assembly: AssemblyInformationalVersion("2.0.0.0")] //[assembly: InternalsVisibleTo("ooxml.Testcases")] diff --git a/ooxml/Resources/presetTableStyles.xml b/ooxml/Resources/presetTableStyles.xml new file mode 100644 index 000000000..f83f2e33c --- /dev/null +++ b/ooxml/Resources/presetTableStyles.xml @@ -0,0 +1,18070 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ooxml/Util/PackageHelper.cs b/ooxml/Util/PackageHelper.cs index 1d1a13b28..9c3acc602 100644 --- a/ooxml/Util/PackageHelper.cs +++ b/ooxml/Util/PackageHelper.cs @@ -101,7 +101,7 @@ public string CreateTempFile() foreach (PackageRelationship rel in rels) { PackagePart p; if(rel.TargetMode == TargetMode.External){ - part_tgt.AddExternalRelationship(rel.TargetUri.ToString(), rel.RelationshipType, rel.Id); + part_tgt.AddExternalRelationship(rel.TargetUri.OriginalString, rel.RelationshipType, rel.Id); //external relations don't have associated namespace parts continue; } diff --git a/ooxml/XSSF/Extractor/XSSFExportToXml.cs b/ooxml/XSSF/Extractor/XSSFExportToXml.cs index b7566321d..4dbfb1a45 100644 --- a/ooxml/XSSF/Extractor/XSSFExportToXml.cs +++ b/ooxml/XSSF/Extractor/XSSFExportToXml.cs @@ -190,7 +190,7 @@ public void ExportToXML(Stream os, String encoding, bool validate) if (cell != null) { XSSFXmlColumnPr pointer = tableColumns[j - startColumnIndex]; - String localXPath = pointer.GetLocalXPath(); + String localXPath = pointer.LocalXPath; XmlNode currentNode = GetNodeByXPath(localXPath, tableRootNode, doc, false); ST_XmlDataType dataType = pointer.GetXmlDataType(); diff --git a/ooxml/XSSF/Model/CommentsTable.cs b/ooxml/XSSF/Model/CommentsTable.cs index f17903552..3712a75f9 100644 --- a/ooxml/XSSF/Model/CommentsTable.cs +++ b/ooxml/XSSF/Model/CommentsTable.cs @@ -24,7 +24,7 @@ namespace NPOI.XSSF.Model using NPOI.SS.UserModel; using NPOI.SS.Util; using NPOI.XSSF.UserModel; - using OpenXmlFormats.Spreadsheet; + using NPOI.OpenXmlFormats.Spreadsheet; public class CommentsTable : POIXMLDocumentPart { @@ -184,9 +184,16 @@ public XSSFComment FindCellComment(CellAddress cellAddress) [Obsolete("deprecated 2015-11-23 (circa POI 3.14beta1). Use {@link CommentsTable#getCTComment(CellAddress)} instead")] public CT_Comment GetCTComment(String ref1) { + prepareCTCommentCache(); return GetCTComment(new CellAddress(ref1)); } + public List GetCellAddresses() + { + prepareCTCommentCache(); + return new List(commentRefs.Keys); + } + /** * Get the underlying CTComment xmlbean for a comment located at cellRef, if it exists * @@ -337,6 +344,19 @@ public CT_Comments GetCTComments() { return comments; } + + private void prepareCTCommentCache() + { + // Create the cache if needed + if (commentRefs == null) + { + commentRefs = new Dictionary(); + foreach (CT_Comment comment in comments.commentList.GetCommentArray()) + { + commentRefs.Add(new CellAddress(comment.@ref), comment); + } + } + } } } diff --git a/ooxml/XSSF/Model/ExternalLinksTable.cs b/ooxml/XSSF/Model/ExternalLinksTable.cs index d04744d41..990b871d9 100644 --- a/ooxml/XSSF/Model/ExternalLinksTable.cs +++ b/ooxml/XSSF/Model/ExternalLinksTable.cs @@ -107,7 +107,7 @@ public virtual String LinkedFileName PackageRelationship rel = GetPackagePart().GetRelationship(rId); if (rel != null && rel.TargetMode == TargetMode.External) { - return rel.TargetUri.ToString(); + return rel.TargetUri.OriginalString; } else { diff --git a/ooxml/XSSF/Model/StylesTable.cs b/ooxml/XSSF/Model/StylesTable.cs index 678dc610d..47cc5e62f 100644 --- a/ooxml/XSSF/Model/StylesTable.cs +++ b/ooxml/XSSF/Model/StylesTable.cs @@ -27,6 +27,7 @@ using NPOI.XSSF.UserModel.Extensions; using System.Collections.ObjectModel; using NPOI.SS; +using NPOI.OOXML.XSSF.UserModel; namespace NPOI.XSSF.Model { @@ -48,7 +49,8 @@ public class StylesTable : POIXMLDocumentPart private List xfs = new List(); private List dxfs = new List(); - + private Dictionary tableStyles = new Dictionary(); + private IIndexedColorMap indexedColors = new DefaultIndexedColorMap(); /** * The first style id available for use as a custom style */ @@ -149,7 +151,23 @@ public void SetTheme(ThemesTable theme) border.SetThemesTable(theme); } } - + public ITableStyle GetTableStyle(String name) + { + if (name == null) return null; + try + { + return XSSFBuiltinTableStyle.GetStyle( + (XSSFBuiltinTableStyleEnum)Enum.Parse(typeof(XSSFBuiltinTableStyleEnum), name)); + } + catch + { + return GetExplicitTableStyle(name); + } + } + public ITableStyle GetExplicitTableStyle(String name) + { + return tableStyles[name]; + } /** * If there isn't currently a {@link ThemesTable} for the * current Workbook, then creates one and sets it up. @@ -168,7 +186,7 @@ public void EnsureThemesTable() * @throws IOException if an error occurs while Reading. */ - protected void ReadFrom(XmlDocument xmldoc) + internal void ReadFrom(XmlDocument xmldoc) { try { @@ -183,7 +201,8 @@ protected void ReadFrom(XmlDocument xmldoc) foreach (CT_NumFmt nfmt in ctfmts.numFmt) { short formatId = (short)nfmt.numFmtId; - numberFormats.Add(formatId, nfmt.formatCode); + if(!numberFormats.ContainsKey(formatId)) + numberFormats.Add(formatId, nfmt.formatCode); } } @@ -229,6 +248,17 @@ protected void ReadFrom(XmlDocument xmldoc) if (styleDxfs != null) dxfs.AddRange(styleDxfs.dxf); + + CT_TableStyles ctTableStyles = styleSheet.tableStyles; + if (ctTableStyles != null) + { + int idx = 0; + foreach (CT_TableStyle style in ctTableStyles.tableStyle) + { + tableStyles.Add(style.name, new XSSFTableStyle(idx, styleDxfs, style, indexedColors)); + idx++; + } + } } catch (XmlException e) { @@ -293,7 +323,7 @@ public int PutNumberFormat(String fmt) { return GetNumberFormatId(fmt); } - catch (InvalidOperationException e) + catch (InvalidOperationException ) { throw new InvalidOperationException("Found the format, but couldn't figure out where - should never happen!"); } @@ -905,6 +935,11 @@ public XSSFFont FindFont(bool bold, short color, short fontHeight, String name, } return null; } + + public IIndexedColorMap GetIndexedColors() + { + return indexedColors; + } } } diff --git a/ooxml/XSSF/Streaming/SXSSFCell.cs b/ooxml/XSSF/Streaming/SXSSFCell.cs index d8c0c57ac..e26f2849a 100644 --- a/ooxml/XSSF/Streaming/SXSSFCell.cs +++ b/ooxml/XSSF/Streaming/SXSSFCell.cs @@ -131,7 +131,38 @@ public string CellFormula ((FormulaValue)_value).Value = value; } } - + public void RemoveFormula() + { + if (CellType != CellType.Formula) + { + return; + } + switch (CachedFormulaResultType) + { + case CellType.Numeric: + double numericValue = ((NumericFormulaValue)_value).PreEvaluatedValue; + _value = new NumericValue(); + ((NumericValue)_value).Value = numericValue; + break; + case CellType.String: + String stringValue = ((StringFormulaValue)_value).PreEvaluatedValue; + _value = new PlainStringValue(); + ((PlainStringValue)_value).Value = stringValue; + break; + case CellType.Boolean: + bool booleanValue = ((BooleanFormulaValue)_value).PreEvaluatedValue; + _value = new BooleanValue(); + ((BooleanValue)_value).Value = booleanValue; + break; + case CellType.Error: + byte errorValue = (byte)((ErrorFormulaValue)_value).PreEvaluatedValue; + _value = new ErrorValue(); + ((ErrorValue)_value).Value = errorValue; + break; + default: + throw new InvalidOperationException(); + } + } public ICellStyle CellStyle { get @@ -825,6 +856,25 @@ public void SetCellValue(DateTime value) SetCellValue((DateTime?)value); } +#if NET6_0_OR_GREATER + public void SetCellValue(DateOnly value) + { + bool date1904 = ((SXSSFWorkbook)Sheet.Workbook).XssfWorkbook.IsDate1904(); + SetCellValue(DateUtil.GetExcelDate(value, date1904)); + } + + public void SetCellValue(DateOnly? value) + { + if (!value.HasValue) + { + SetCellType(CellType.Blank); + return; + } + + SetCellValue(value.Value); + } +#endif + public void SetBlank() { SetCellType(CellType.Blank); diff --git a/ooxml/XSSF/Streaming/SXSSFEvaluationCell.cs b/ooxml/XSSF/Streaming/SXSSFEvaluationCell.cs index ae153c40b..6884f757a 100644 --- a/ooxml/XSSF/Streaming/SXSSFEvaluationCell.cs +++ b/ooxml/XSSF/Streaming/SXSSFEvaluationCell.cs @@ -17,6 +17,7 @@ using System; using NPOI.SS.Formula; using NPOI.SS.UserModel; +using NPOI.SS.Util; using NPOI.XSSF.UserModel; namespace NPOI.XSSF.Streaming @@ -137,13 +138,24 @@ public String StringCellValue return _cell.RichStringCellValue.String; } } - /** - * Will return {@link CellType} in a future version of POI. - * For forwards compatibility, do not hard-code cell type literals in your code. - * - * @return cell type of cached formula result - */ + public bool IsPartOfArrayFormulaGroup + { + get + { + return _cell.IsPartOfArrayFormulaGroup; + } + } + public CellRangeAddress ArrayFormulaRange + { + get + { + return _cell.ArrayFormulaRange; + } + } + /// + /// Will return CellType in a future version of POI. For forwards compatibility, do not hard-code cell type literals in your code. + /// public CellType CachedFormulaResultType { get diff --git a/ooxml/XSSF/Streaming/SXSSFRow.cs b/ooxml/XSSF/Streaming/SXSSFRow.cs index 2fbf5b18b..d12cd7cc7 100644 --- a/ooxml/XSSF/Streaming/SXSSFRow.cs +++ b/ooxml/XSSF/Streaming/SXSSFRow.cs @@ -31,11 +31,11 @@ public class SXSSFRow : IRow, IComparable private bool _zHeight; // row zero-height (this is somehow different than being hidden) private float _height = -1; - private int _FirstCellNum = -1; - private int _LastCellNum = -1; + private int _firstCellNum = -1; + private int _lastCellNum = -1; // use Boolean to have a tri-state for on/off/undefined - public bool? Hidden { get; set; } - public bool? Collapsed { get; set; } + public virtual bool? Hidden { get; set; } + public virtual bool? Collapsed { get; set; } public SXSSFRow(SXSSFSheet sheet) { @@ -46,7 +46,7 @@ public CellIterator AllCellsIterator() { return new CellIterator(LastCellNum, new SortedDictionary(_cells)); } - public bool HasCustomHeight() + public virtual bool HasCustomHeight() { return Height != -1; } @@ -60,14 +60,7 @@ public short FirstCellNum { get { - try - { - return (short) _FirstCellNum; - } - catch - { - return -1; - } + return (short) _firstCellNum; } } @@ -93,7 +86,7 @@ public float HeightInPoints } } - public bool IsFormatted + public virtual bool IsFormatted { get { @@ -105,12 +98,12 @@ public short LastCellNum { get { - return (short) _LastCellNum; + return (short) _lastCellNum; } } - public int OutlineLevel { get; set; } + public virtual int OutlineLevel { get; set; } public int PhysicalNumberOfCells { @@ -138,7 +131,7 @@ internal int RowStyleIndex } } - public ICellStyle RowStyle + public virtual ICellStyle RowStyle { get { @@ -165,7 +158,7 @@ public ISheet Sheet get { return _sheet; } } - public bool ZeroHeight + public virtual bool ZeroHeight { get { return _zHeight; } @@ -249,14 +242,14 @@ public ICell CreateCell(int column, CellType type) private void UpdateIndexWhenAdd(int cellnum) { - if (cellnum < _FirstCellNum || _FirstCellNum == -1) + if (cellnum < _firstCellNum || _firstCellNum == -1) { - _FirstCellNum = cellnum; + _firstCellNum = cellnum; } - if (cellnum >= _LastCellNum) + if (cellnum >= _lastCellNum) { - _LastCellNum = cellnum + 1; + _lastCellNum = cellnum + 1; } } @@ -319,12 +312,12 @@ public void RemoveCell(ICell cell) { int index = GetCellIndex((SXSSFCell)cell); _cells.Remove(index); - if (index == _FirstCellNum) + if (index == _firstCellNum) { InvalidateFirstCellNum(); } - if (index >= (_LastCellNum -1)) + if (index >= _lastCellNum -1) { InvalidateLastCellNum(); } @@ -334,11 +327,11 @@ private void InvalidateFirstCellNum() { if (_cells.Keys.Count == 0) { - _FirstCellNum = 0; + _firstCellNum = -1; } else { - _FirstCellNum = _cells.Keys.Min(); + _firstCellNum = _cells.Keys.Min(); } } @@ -346,11 +339,11 @@ private void InvalidateLastCellNum() { if (_cells.Count == 0) { - _LastCellNum = 0; + _lastCellNum = -1; } else { - _LastCellNum = _cells.Keys.Max() + 1; + _lastCellNum = _cells.Keys.Max() + 1; } } diff --git a/ooxml/XSSF/Streaming/SXSSFSheet.cs b/ooxml/XSSF/Streaming/SXSSFSheet.cs index 72cae76b7..532299f50 100644 --- a/ooxml/XSSF/Streaming/SXSSFSheet.cs +++ b/ooxml/XSSF/Streaming/SXSSFSheet.cs @@ -1375,8 +1375,8 @@ public void FlushRows() var firstRowNum = _rows.Keys.Min(); // Update the best fit column widths for auto-sizing just before the rows are flushed - // _autoSizeColumnTracker.UpdateColumnWidths(row); var firstRow = _rows[firstRowNum]; + _autoSizeColumnTracker.Value?.UpdateColumnWidths(firstRow); _writer.WriteRow(firstRowNum, firstRow); _rows.Remove(firstRowNum); lastFlushedRowNumber = firstRowNum; diff --git a/ooxml/XSSF/Streaming/SXSSFWorkbook.cs b/ooxml/XSSF/Streaming/SXSSFWorkbook.cs index b85f4b444..4d9d7befc 100644 --- a/ooxml/XSSF/Streaming/SXSSFWorkbook.cs +++ b/ooxml/XSSF/Streaming/SXSSFWorkbook.cs @@ -648,6 +648,7 @@ public ISheet CreateSheet() public ISheet CreateSheet(string sheetname) { + SS.Util.WorkbookUtil.ValidateSheetName(sheetname); return CreateAndRegisterSXSSFSheet(XssfWorkbook.CreateSheet(sheetname)); } @@ -751,7 +752,10 @@ public void Close() // it's a newly created one XssfWorkbook.Close(); } - + public void Write(Stream stream, bool leaveOpen = false) + { + this.Write(stream); + } public void Write(Stream stream) { FlushSheets(); @@ -967,6 +971,9 @@ public bool IsDate1904() { return XssfWorkbook.IsDate1904(); } + + + //TODO: missing method isDate1904, isHidden, setHidden private class SheetEnumerator : IEnumerator where T : class, ISheet diff --git a/ooxml/XSSF/UserModel/BaseXSSFEvaluationWorkbook.cs b/ooxml/XSSF/UserModel/BaseXSSFEvaluationWorkbook.cs index cd16bfe4c..ce507904f 100644 --- a/ooxml/XSSF/UserModel/BaseXSSFEvaluationWorkbook.cs +++ b/ooxml/XSSF/UserModel/BaseXSSFEvaluationWorkbook.cs @@ -90,7 +90,7 @@ private int ResolveBookIndex(String bookName) { return Int32.Parse(bookName); } - catch (FormatException e) { } + catch (FormatException ) { } // Look up an External Link Table for this name List tables = _uBook.ExternalLinksTable; diff --git a/ooxml/XSSF/UserModel/DefaultIndexedColorMap.cs b/ooxml/XSSF/UserModel/DefaultIndexedColorMap.cs new file mode 100644 index 000000000..6fca78557 --- /dev/null +++ b/ooxml/XSSF/UserModel/DefaultIndexedColorMap.cs @@ -0,0 +1,22 @@ +using NPOI.HSSF.Util; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.OOXML.XSSF.UserModel +{ + public class DefaultIndexedColorMap:IIndexedColorMap + { + public byte[] GetRGB(int index) + { + return GetDefaultRGB(index); + } + public static byte[] GetDefaultRGB(int index) + { + HSSFColor hssfColor = HSSFColor.GetIndexHash()[index]; + if (hssfColor == null) return null; + byte[] rgbShort = hssfColor.GetTriplet(); + return rgbShort; + } + } +} diff --git a/ooxml/XSSF/UserModel/Extensions/XSSFCellFill.cs b/ooxml/XSSF/UserModel/Extensions/XSSFCellFill.cs index b8fc5c450..b21365972 100644 --- a/ooxml/XSSF/UserModel/Extensions/XSSFCellFill.cs +++ b/ooxml/XSSF/UserModel/Extensions/XSSFCellFill.cs @@ -160,7 +160,7 @@ private CT_PatternFill EnsureCTPatternFill() * @return CT_Fill */ - internal CT_Fill GetCTFill() + public CT_Fill GetCTFill() { return _fill; } diff --git a/ooxml/XSSF/UserModel/Helpers/XSSFRowColShifter.cs b/ooxml/XSSF/UserModel/Helpers/XSSFRowColShifter.cs new file mode 100644 index 000000000..38e064054 --- /dev/null +++ b/ooxml/XSSF/UserModel/Helpers/XSSFRowColShifter.cs @@ -0,0 +1,238 @@ +using NPOI.OpenXmlFormats.Spreadsheet; +using NPOI.SS.Formula; +using NPOI.SS.Formula.PTG; +using NPOI.SS.UserModel; +using NPOI.SS.UserModel.Helpers; +using NPOI.SS.Util; +using NPOI.XSSF.UserModel; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.OOXML.XSSF.UserModel.Helpers +{ + public class XSSFRowColShifter + { + /// + /// Updated named ranges + /// + /// + public static void UpdateNamedRanges(ISheet sheet, FormulaShifter shifter) + { + IWorkbook wb = sheet.Workbook; + XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.Create(wb); + foreach (IName name in wb.GetAllNames()) + { + String formula = name.RefersToFormula; + int sheetIndex = name.SheetIndex; + + Ptg[] ptgs = FormulaParser.Parse(formula, fpb, FormulaType.NamedRange, sheetIndex, -1); + if (shifter.AdjustFormula(ptgs, sheetIndex)) + { + String shiftedFmla = FormulaRenderer.ToFormulaString(fpb, ptgs); + name.RefersToFormula = shiftedFmla; + } + } + } + /// + /// Update formulas. + /// + /// + /// + public static void UpdateFormulas(ISheet sheet, FormulaShifter shifter) + { + //update formulas on the parent sheet + UpdateSheetFormulas(sheet, shifter); + + //update formulas on other sheets + IWorkbook wb = sheet.Workbook; + foreach (XSSFSheet sh in wb) + { + if (sheet == sh) continue; + UpdateSheetFormulas(sh, shifter); + } + } + + public static void UpdateSheetFormulas(ISheet sh, FormulaShifter Shifter) + { + foreach (IRow r in sh) + { + XSSFRow row = (XSSFRow)r; + UpdateRowFormulas(row, Shifter); + } + } + /// + /// Update the formulas in specified row using the formula shifting policy specified by shifter + /// + /// the row to update the formulas on + /// the formula shifting policy + public static void UpdateRowFormulas(IRow row, FormulaShifter Shifter) + { + XSSFSheet sheet = (XSSFSheet)row.Sheet; + foreach (ICell c in row) + { + XSSFCell cell = (XSSFCell)c; + + CT_Cell ctCell = cell.GetCTCell(); + if (ctCell.IsSetF()) + { + CT_CellFormula f = ctCell.f; + String formula = f.Value; + if (formula.Length > 0) + { + String ShiftedFormula = ShiftFormula(row, formula, Shifter); + if (ShiftedFormula != null) + { + f.Value = (ShiftedFormula); + if (f.t == ST_CellFormulaType.shared) + { + int si = (int)f.si; + CT_CellFormula sf = sheet.GetSharedFormula(si); + sf.Value = (ShiftedFormula); + } + } + } + + if (f.isSetRef()) + { //Range of cells which the formula applies to. + String ref1 = f.@ref; + String ShiftedRef = ShiftFormula(row, ref1, Shifter); + if (ShiftedRef != null) f.@ref = ShiftedRef; + } + } + + } + } + /// + /// Shift a formula using the supplied FormulaShifter + /// + /// the row of the cell this formula belongs to. Used to get a reference to the parent workbook. + /// the formula to shift + /// the FormulaShifter object that operates on the Parsed formula tokens + /// the Shifted formula if the formula was changed, null if the formula wasn't modified + private static String ShiftFormula(IRow row, String formula, FormulaShifter Shifter) + { + ISheet sheet = row.Sheet; + IWorkbook wb = sheet.Workbook; + int sheetIndex = wb.GetSheetIndex(sheet); + XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.Create(wb); + try + { + Ptg[] ptgs = FormulaParser.Parse(formula, fpb, FormulaType.Cell, sheetIndex, -1); + String ShiftedFmla = null; + if (Shifter.AdjustFormula(ptgs, sheetIndex)) + { + ShiftedFmla = FormulaRenderer.ToFormulaString(fpb, ptgs); + } + return ShiftedFmla; + } + catch (FormulaParseException fpe) + { + // Log, but don't change, rather than breaking + Console.WriteLine("Error shifting formula on row {0}, {1}", row.RowNum, fpe); + return formula; + } + } + /// + /// Shift the Hyperlink anchors(not the hyperlink text, even if the hyperlink is of type LINK_DOCUMENT and refers to a cell that was shifted). Hyperlinks do not track the content they point to. + /// + /// + /// + public static void UpdateHyperlinks(ISheet sheet, FormulaShifter shifter) + { + XSSFSheet xsheet = (XSSFSheet)sheet; + int sheetIndex = xsheet.GetWorkbook().GetSheetIndex(sheet); + List hyperlinkList = sheet.GetHyperlinkList(); + + foreach (IHyperlink hyperlink1 in hyperlinkList) + { + XSSFHyperlink hyperlink = hyperlink1 as XSSFHyperlink; + String cellRef = hyperlink.CellRef; + CellRangeAddress cra = CellRangeAddress.ValueOf(cellRef); + CellRangeAddress shiftedRange = BaseRowColShifter.ShiftRange(shifter, cra, sheetIndex); + if (shiftedRange != null && shiftedRange != cra) + { + // shiftedRange should not be null. If shiftedRange is null, that means + // that a hyperlink wasn't deleted at the beginning of shiftRows when + // identifying rows that should be removed because they will be overwritten + hyperlink.SetCellReference(shiftedRange.FormatAsString()); + } + } + } + public static void UpdateConditionalFormatting(ISheet sheet, FormulaShifter Shifter) + { + XSSFSheet xsheet = (XSSFSheet)sheet; + XSSFWorkbook wb = xsheet.Workbook as XSSFWorkbook; + int sheetIndex = wb.GetSheetIndex(sheet); + + + XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.Create(wb); + CT_Worksheet ctWorksheet = xsheet.GetCTWorksheet(); + List conditionalFormattingArray = ctWorksheet.conditionalFormatting; + // iterate backwards due to possible calls to ctWorksheet.removeConditionalFormatting(j) + for (int j = conditionalFormattingArray.Count - 1; j >= 0; j--) + { + CT_ConditionalFormatting cf = conditionalFormattingArray[j]; + + List cellRanges = new List(); + String[] regions = cf.sqref.ToString().Split(new char[] { ' ' }); + for (int i = 0; i < regions.Length; i++) + { + cellRanges.Add(CellRangeAddress.ValueOf(regions[i])); + } + + bool Changed = false; + List temp = new List(); + for (int i = 0; i < cellRanges.Count; i++) + { + CellRangeAddress craOld = cellRanges[i]; + CellRangeAddress craNew = BaseRowColShifter.ShiftRange(Shifter, craOld, sheetIndex); + if (craNew == null) + { + Changed = true; + continue; + } + temp.Add(craNew); + if (craNew != craOld) + { + Changed = true; + } + } + + if (Changed) + { + int nRanges = temp.Count; + if (nRanges == 0) + { + conditionalFormattingArray.RemoveAt(j); + continue; + } + string refs = string.Empty; + foreach (CellRangeAddress a in temp) + { + if (refs.Length == 0) + refs = a.FormatAsString(); + else + refs += " " + a.FormatAsString(); + } + cf.sqref = refs; + } + + foreach (CT_CfRule cfRule in cf.cfRule) + { + List formulas = cfRule.formula; + for (int i = 0; i < formulas.Count; i++) + { + String formula = formulas[i]; + Ptg[] ptgs = FormulaParser.Parse(formula, fpb, FormulaType.Cell, sheetIndex, -1); + if (Shifter.AdjustFormula(ptgs, sheetIndex)) + { + String ShiftedFmla = FormulaRenderer.ToFormulaString(fpb, ptgs); + formulas[i] = ShiftedFmla; + } + } + } + } + } + } +} diff --git a/ooxml/XSSF/UserModel/Helpers/XSSFRowShifter.cs b/ooxml/XSSF/UserModel/Helpers/XSSFRowShifter.cs index 8820b315b..12186a1b2 100644 --- a/ooxml/XSSF/UserModel/Helpers/XSSFRowShifter.cs +++ b/ooxml/XSSF/UserModel/Helpers/XSSFRowShifter.cs @@ -24,6 +24,7 @@ using NPOI.OpenXmlFormats.Spreadsheet; using System.Linq; using NPOI.SS.UserModel.Helpers; +using NPOI.OOXML.XSSF.UserModel.Helpers; namespace NPOI.XSSF.UserModel.Helpers { @@ -39,272 +40,30 @@ public XSSFRowShifter(XSSFSheet sh) sheet = sh; } - /** - * Shift merged regions - * - * @param startRow the row to start Shifting - * @param endRow the row to end Shifting - * @param n the number of rows to shift - * @return an array of affected cell regions - */ - [Obsolete("deprecated POI 3.15 beta 2. Use ShiftMergedRegions(int, int, int) instead.")] - public List ShiftMerged(int startRow, int endRow, int n) + public override void UpdateConditionalFormatting(FormulaShifter formulaShifter) { - return ShiftMergedRegions(startRow, endRow, n); + XSSFRowColShifter.UpdateConditionalFormatting(sheet, formulaShifter); } - - /** - * Updated named ranges - */ - public override void UpdateNamedRanges(FormulaShifter shifter) + public override void UpdateFormulas(FormulaShifter formulaShifter) { - IWorkbook wb = sheet.Workbook; - XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.Create(wb); - foreach (IName name in wb.GetAllNames()) - { - String formula = name.RefersToFormula; - int sheetIndex = name.SheetIndex; - - Ptg[] ptgs = FormulaParser.Parse(formula, fpb, FormulaType.NamedRange, sheetIndex, -1); - if (shifter.AdjustFormula(ptgs, sheetIndex)) - { - String shiftedFmla = FormulaRenderer.ToFormulaString(fpb, ptgs); - name.RefersToFormula = shiftedFmla; - } - - } + XSSFRowColShifter.UpdateFormulas(sheet, formulaShifter); } - /** - * Update formulas. - */ - public override void UpdateFormulas(FormulaShifter shifter) + public override void UpdateHyperlinks(FormulaShifter formulaShifter) { - //update formulas on the parent sheet - UpdateSheetFormulas(sheet, shifter); - - //update formulas on other sheets - IWorkbook wb = sheet.Workbook; - foreach (XSSFSheet sh in wb) - { - if (sheet == sh) continue; - UpdateSheetFormulas(sh, shifter); - } + XSSFRowColShifter.UpdateHyperlinks(sheet, formulaShifter); } - private void UpdateSheetFormulas(ISheet sh, FormulaShifter Shifter) + public override void UpdateNamedRanges(FormulaShifter formulaShifter) { - foreach (IRow r in sh) - { - XSSFRow row = (XSSFRow)r; - UpdateRowFormulas(row, Shifter); - } - } - /// - /// Update the formulas in specified row using the formula shifting policy specified by shifter - /// - /// the row to update the formulas on - /// the formula shifting policy - public override void UpdateRowFormulas(IRow row, FormulaShifter Shifter) - { - XSSFSheet sheet = (XSSFSheet)row.Sheet; - foreach (ICell c in row) - { - XSSFCell cell = (XSSFCell)c; - - CT_Cell ctCell = cell.GetCTCell(); - if (ctCell.IsSetF()) - { - CT_CellFormula f = ctCell.f; - String formula = f.Value; - if (formula.Length > 0) - { - String ShiftedFormula = ShiftFormula(row, formula, Shifter); - if (ShiftedFormula != null) - { - f.Value = (ShiftedFormula); - if (f.t == ST_CellFormulaType.shared) - { - int si = (int)f.si; - CT_CellFormula sf = sheet.GetSharedFormula(si); - sf.Value = (ShiftedFormula); - } - } - } - - if (f.isSetRef()) - { //Range of cells which the formula applies to. - String ref1 = f.@ref; - String ShiftedRef = ShiftFormula(row, ref1, Shifter); - if (ShiftedRef != null) f.@ref = ShiftedRef; - } - } - - } + XSSFRowColShifter.UpdateNamedRanges(sheet, formulaShifter); } - /** - * Shift a formula using the supplied FormulaShifter - * - * @param row the row of the cell this formula belongs to. Used to get a reference to the parent workbook. - * @param formula the formula to shift - * @param Shifter the FormulaShifter object that operates on the Parsed formula tokens - * @return the Shifted formula if the formula was Changed, - * null if the formula wasn't modified - */ - private static String ShiftFormula(IRow row, String formula, FormulaShifter Shifter) + public override void UpdateRowFormulas(IRow row, FormulaShifter formulaShifter) { - ISheet sheet = row.Sheet; - IWorkbook wb = sheet.Workbook; - int sheetIndex = wb.GetSheetIndex(sheet); - XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.Create(wb); - try - { - Ptg[] ptgs = FormulaParser.Parse(formula, fpb, FormulaType.Cell, sheetIndex, -1); - String ShiftedFmla = null; - if (Shifter.AdjustFormula(ptgs, sheetIndex)) - { - ShiftedFmla = FormulaRenderer.ToFormulaString(fpb, ptgs); - } - return ShiftedFmla; - } - catch (FormulaParseException fpe) - { - // Log, but don't change, rather than breaking - Console.WriteLine("Error shifting formula on row {0}, {1}", row.RowNum, fpe); - return formula; - } + XSSFRowColShifter.UpdateRowFormulas(row, formulaShifter); } - - public override void UpdateConditionalFormatting(FormulaShifter Shifter) - { - XSSFSheet xsheet = (XSSFSheet)sheet; - XSSFWorkbook wb = xsheet.Workbook as XSSFWorkbook; - int sheetIndex = wb.GetSheetIndex(sheet); - - - XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.Create(wb); - CT_Worksheet ctWorksheet = xsheet.GetCTWorksheet(); - List conditionalFormattingArray = ctWorksheet.conditionalFormatting; - // iterate backwards due to possible calls to ctWorksheet.removeConditionalFormatting(j) - for (int j = conditionalFormattingArray.Count - 1; j >= 0; j--) - { - CT_ConditionalFormatting cf = conditionalFormattingArray[j]; - - List cellRanges = new List(); - String[] regions = cf.sqref.ToString().Split(new char[] { ' ' }); - for (int i = 0; i < regions.Length; i++) - { - cellRanges.Add(CellRangeAddress.ValueOf(regions[i])); - } - - bool Changed = false; - List temp = new List(); - for (int i = 0; i < cellRanges.Count; i++) - { - CellRangeAddress craOld = cellRanges[i]; - CellRangeAddress craNew = ShiftRange(Shifter, craOld, sheetIndex); - if (craNew == null) - { - Changed = true; - continue; - } - temp.Add(craNew); - if (craNew != craOld) - { - Changed = true; - } - } - - if (Changed) - { - int nRanges = temp.Count; - if (nRanges == 0) - { - conditionalFormattingArray.RemoveAt(j); - continue; - } - string refs = string.Empty; - foreach (CellRangeAddress a in temp) - { - if (refs.Length == 0) - refs = a.FormatAsString(); - else - refs += " " + a.FormatAsString(); - } - cf.sqref = refs; - } - - foreach (CT_CfRule cfRule in cf.cfRule) - { - List formulas = cfRule.formula; - for (int i = 0; i < formulas.Count; i++) - { - String formula = formulas[i]; - Ptg[] ptgs = FormulaParser.Parse(formula, fpb, FormulaType.Cell, sheetIndex, -1); - if (Shifter.AdjustFormula(ptgs, sheetIndex)) - { - String ShiftedFmla = FormulaRenderer.ToFormulaString(fpb, ptgs); - formulas[i] = ShiftedFmla; - } - } - } - } - } - - /** - * Shift the Hyperlink anchors (not the hyperlink text, even if the hyperlink - * is of type LINK_DOCUMENT and refers to a cell that was shifted). Hyperlinks - * do not track the content they point to. - * - * @param shifter - */ - public override void UpdateHyperlinks(FormulaShifter shifter) - { - XSSFSheet xsheet = (XSSFSheet)sheet; - int sheetIndex = xsheet.GetWorkbook().GetSheetIndex(sheet); - List hyperlinkList = sheet.GetHyperlinkList(); - - foreach (IHyperlink hyperlink1 in hyperlinkList) - { - XSSFHyperlink hyperlink = hyperlink1 as XSSFHyperlink; - String cellRef = hyperlink.CellRef; - CellRangeAddress cra = CellRangeAddress.ValueOf(cellRef); - CellRangeAddress shiftedRange = ShiftRange(shifter, cra, sheetIndex); - if (shiftedRange != null && shiftedRange != cra) - { - // shiftedRange should not be null. If shiftedRange is null, that means - // that a hyperlink wasn't deleted at the beginning of shiftRows when - // identifying rows that should be removed because they will be overwritten - hyperlink.SetCellReference(shiftedRange.FormatAsString()); - } - } - } - - private static CellRangeAddress ShiftRange(FormulaShifter Shifter, CellRangeAddress cra, int currentExternSheetIx) - { - // FormulaShifter works well in terms of Ptgs - so convert CellRangeAddress to AreaPtg (and back) here - AreaPtg aptg = new AreaPtg(cra.FirstRow, cra.LastRow, cra.FirstColumn, cra.LastColumn, false, false, false, false); - Ptg[] ptgs = { aptg, }; - - if (!Shifter.AdjustFormula(ptgs, currentExternSheetIx)) - { - return cra; - } - Ptg ptg0 = ptgs[0]; - if (ptg0 is AreaPtg) - { - AreaPtg bptg = (AreaPtg)ptg0; - return new CellRangeAddress(bptg.FirstRow, bptg.LastRow, bptg.FirstColumn, bptg.LastColumn); - } - if (ptg0 is AreaErrPtg) - { - return null; - } - throw new InvalidOperationException("Unexpected Shifted ptg class (" + ptg0.GetType().Name + ")"); - } - } } diff --git a/ooxml/XSSF/UserModel/Helpers/XSSFXmlColumnPr.cs b/ooxml/XSSF/UserModel/Helpers/XSSFXmlColumnPr.cs index 3756dfe2e..cc104af09 100644 --- a/ooxml/XSSF/UserModel/Helpers/XSSFXmlColumnPr.cs +++ b/ooxml/XSSF/UserModel/Helpers/XSSFXmlColumnPr.cs @@ -36,33 +36,46 @@ public class XSSFXmlColumnPr { private XSSFTable table; - private CT_TableColumn ctTableColumn; + private XSSFTableColumn tableColumn; private CT_XmlColumnPr ctXmlColumnPr; + internal XSSFXmlColumnPr(XSSFTableColumn tableColumn, CT_XmlColumnPr ctXmlColumnPr) + { + this.table = tableColumn.GetTable(); + this.tableColumn = tableColumn; + this.ctXmlColumnPr = ctXmlColumnPr; + } + [Obsolete] public XSSFXmlColumnPr(XSSFTable table, CT_TableColumn ctTableColum, CT_XmlColumnPr CT_XmlColumnPr) { this.table = table; - this.ctTableColumn = ctTableColum; + this.tableColumn = table.GetColumns()[table.FindColumnIndex(ctTableColum.name)]; this.ctXmlColumnPr = CT_XmlColumnPr; } - public long GetMapId() + public long MapId { - return ctXmlColumnPr.mapId; + get { + return ctXmlColumnPr.mapId; + } } - public String GetXPath() + public String XPath { - return ctXmlColumnPr.xpath; + get { + return ctXmlColumnPr.xpath; + } } - /** - * (see Open Office XML Part 4: chapter 3.5.1.3) - * @return An integer representing the unique identifier of this column. - */ - public long GetId() + /// + /// (see Open Office XML Part 4: chapter 3.5.1.3) An integer representing the unique identifier of this column. + /// + public long Id { - return ctTableColumn.id; + get + { + return tableColumn.Id; + } } @@ -71,17 +84,20 @@ public long GetId() * * @return the local XPath */ - public String GetLocalXPath() + public String LocalXPath { - StringBuilder localXPath = new StringBuilder(); - int numberOfCommonXPathAxis = table.GetCommonXpath().Split(new char[] { '/' }).Length - 1; - - String[] xPathTokens = ctXmlColumnPr.xpath.Split(new char[] { '/' }); - for (int i = numberOfCommonXPathAxis; i < xPathTokens.Length; i++) + get { - localXPath.Append("/" + xPathTokens[i]); + StringBuilder localXPath = new StringBuilder(); + int numberOfCommonXPathAxis = table.GetCommonXpath().Split(new char[] { '/' }).Length - 1; + + String[] xPathTokens = ctXmlColumnPr.xpath.Split(new char[] { '/' }); + for (int i = numberOfCommonXPathAxis; i < xPathTokens.Length; i++) + { + localXPath.Append("/" + xPathTokens[i]); + } + return localXPath.ToString(); } - return localXPath.ToString(); } public ST_XmlDataType GetXmlDataType() diff --git a/ooxml/XSSF/UserModel/IndexedColorMap.cs b/ooxml/XSSF/UserModel/IndexedColorMap.cs new file mode 100644 index 000000000..65ede7b36 --- /dev/null +++ b/ooxml/XSSF/UserModel/IndexedColorMap.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.OOXML.XSSF.UserModel +{ + public interface IIndexedColorMap + { + byte[] GetRGB(int index); + } +} diff --git a/ooxml/XSSF/UserModel/XSSFBuiltinTableStyle.cs b/ooxml/XSSF/UserModel/XSSFBuiltinTableStyle.cs new file mode 100644 index 000000000..82a91f23b --- /dev/null +++ b/ooxml/XSSF/UserModel/XSSFBuiltinTableStyle.cs @@ -0,0 +1,413 @@ +using EnumsNET; +using NPOI.SS.UserModel; +using NPOI.XSSF.Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; + +namespace NPOI.XSSF.UserModel +{ + 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 + { +#if NETSTANDARD2_1 || NETSTANDARD2_0 + const string presetTableStylesResourceName = "NPOI.OOXML.Resources.presetTableStyles.xml"; +#else + const string presetTableStylesResourceName= "presetTableStyles.xml"; +#endif + + private static Dictionary styleMap = new Dictionary(); + public static ITableStyle GetStyle(XSSFBuiltinTableStyleEnum style) + { + Init(); + return styleMap[style]; + } + public static bool IsBuiltinStyle(ITableStyle style) + { + if (style == null) + return false; + return Enums.GetNames().Any(x=>x==style.Name); + } + private static void Init() + { + if (styleMap.Count > 0) + return; + 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) + { + String styleName = child.Name; + if (!Enum.TryParse(styleName, out XSSFBuiltinTableStyleEnum builtIn)) + { + continue; + } + var dxfsNode = child.SelectSingleNode("dxfs"); + var tableStyleNode = child.SelectSingleNode("tableStyles"); + StylesTable styles = new StylesTable(); + var styleXmlDocument = new XmlDocument(); + styleXmlDocument.LoadXml(StyleXML(dxfsNode, tableStyleNode)); + styles.ReadFrom(styleXmlDocument); + styleMap.Add(builtIn,new XSSFBuiltinTypeStyleStyle(builtIn, styles.GetExplicitTableStyle(styleName))); + } + } + } + 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); + + StringBuilder sb = new StringBuilder(); + sb.Append("\n") + .Append("\n"); + sb.Append(dxfsNode.OuterXml); + sb.Append(tableStyleNode.OuterXml); + sb.Append(""); + return sb.ToString(); + } + protected class XSSFBuiltinTypeStyleStyle : ITableStyle + { + + private XSSFBuiltinTableStyleEnum builtIn; + private ITableStyle style; + + /** + * @param builtIn + * @param style + */ + internal XSSFBuiltinTypeStyleStyle(XSSFBuiltinTableStyleEnum builtIn, ITableStyle style) + { + this.builtIn = builtIn; + this.style = style; + } + + public String Name + { + get + { + return style.Name; + } + } + + public int Index + { + get + { + return (int)builtIn; + } + } + + public bool IsBuiltin + { + get + { + return true; + } + } + + public DifferentialStyleProvider GetStyle(TableStyleType type) + { + return style.GetStyle(type); + } + + } +} +} diff --git a/ooxml/XSSF/UserModel/XSSFCell.cs b/ooxml/XSSF/UserModel/XSSFCell.cs index be06e2e27..5bee6acb9 100644 --- a/ooxml/XSSF/UserModel/XSSFCell.cs +++ b/ooxml/XSSF/UserModel/XSSFCell.cs @@ -529,6 +529,24 @@ public String CellFormula } } + public void RemoveFormula() + { + if (CellType == CellType.Blank) + return; + + if (IsPartOfArrayFormulaGroup) + { + TryToDeleteArrayFormula(null); + return; + } + ((XSSFWorkbook)_row.Sheet.Workbook).OnDeleteFormula(this); + if (_cell.IsSetF()) + { + ((XSSFSheet)_row.Sheet).OnDeleteFormula(this, null); + _cell.unsetF(); + } + } + /** * package/hierarchy use only - reuse an existing evaluation workbook if available for caching * @@ -614,21 +632,43 @@ internal void SetCellArrayFormula(String formula, CellRangeAddress range) cellFormula.t = (ST_CellFormulaType.array); cellFormula.@ref = (range.FormatAsString()); } + /// + /// Called when this an array formula in this cell is deleted. + /// + /// a customized exception message for the case if deletion of the cell is impossible. If null, a default message will be generated + internal void TryToDeleteArrayFormula(String message) + { + if (!IsPartOfArrayFormulaGroup) + return; + CellRangeAddress arrayFormulaRange = ArrayFormulaRange; + if (arrayFormulaRange.NumberOfCells > 1) + { + if (message == null) + { + message = "Cell " + new CellReference(this).FormatAsString() + " is part of a multi-cell array formula. " + + "You cannot change part of an array."; + } + throw new InvalidOperationException(message); + } + //un-register the single-cell array formula from the parent sheet through public interface + Row.Sheet.RemoveArrayFormula(this); + } private void SetFormula(String formula, FormulaType formulaType) { - IWorkbook wb = _row.Sheet.Workbook; + XSSFWorkbook wb = (XSSFWorkbook)_row.Sheet.Workbook; if (formula == null) { - ((XSSFWorkbook)wb).OnDeleteFormula(this); - if (_cell.IsSetF()) _cell.unsetF(); + RemoveFormula(); return; } - IFormulaParsingWorkbook fpb = XSSFEvaluationWorkbook.Create(wb); - //validate through the FormulaParser - FormulaParser.Parse(formula, fpb, formulaType, wb.GetSheetIndex(this.Sheet), RowIndex); - + if (wb.CellFormulaValidation) + { + IFormulaParsingWorkbook fpb = XSSFEvaluationWorkbook.Create(wb); + //validate through the FormulaParser + FormulaParser.Parse(formula, fpb, formulaType, wb.GetSheetIndex(this.Sheet), RowIndex); + } CT_CellFormula f = new CT_CellFormula(); f.Value = formula; _cell.f= (f); @@ -821,6 +861,26 @@ public void SetCellValue(DateTime value) bool date1904 = Sheet.Workbook.IsDate1904(); SetCellValue(DateUtil.GetExcelDate(value, date1904)); } + +#if NET6_0_OR_GREATER + public void SetCellValue(DateOnly value) + { + bool date1904 = Sheet.Workbook.IsDate1904(); + SetCellValue(DateUtil.GetExcelDate(value, date1904)); + } + + public void SetCellValue(DateOnly? value) + { + if (value == null) + { + SetCellType(CellType.Blank); + return; + } + + SetCellValue(value.Value); + } +#endif + /// /// Returns the error message, such as #VALUE! /// diff --git a/ooxml/XSSF/UserModel/XSSFCellStyle.cs b/ooxml/XSSF/UserModel/XSSFCellStyle.cs index afc1b9341..14a2012bb 100644 --- a/ooxml/XSSF/UserModel/XSSFCellStyle.cs +++ b/ooxml/XSSF/UserModel/XSSFCellStyle.cs @@ -1434,7 +1434,7 @@ public BorderDiagonal BorderDiagonal } set { - CT_Border ct = GetCTBorder(copy: true); + CT_Border ct = GetCTBorder(); if (value == BorderDiagonal.Both) { ct.diagonalDown = true; diff --git a/ooxml/XSSF/UserModel/XSSFChartSheet.cs b/ooxml/XSSF/UserModel/XSSFChartSheet.cs index f6d94f641..2b4daccf1 100644 --- a/ooxml/XSSF/UserModel/XSSFChartSheet.cs +++ b/ooxml/XSSF/UserModel/XSSFChartSheet.cs @@ -96,23 +96,25 @@ protected override NPOI.OpenXmlFormats.Spreadsheet.CT_LegacyDrawing GetCTLegacyD } - internal override void Write(Stream out1) + internal override void Write(Stream out1, bool leaveOpen=false) { new ChartsheetDocument(this.chartsheet).Save(out1); } private static byte[] blankWorksheet() { - MemoryStream out1 = new MemoryStream(); - try - { - new XSSFSheet().Write(out1); - } - catch (IOException e) - { - throw new RuntimeException(e); + using (MemoryStream out1 = RecyclableMemory.GetStream()) + { + try + { + new XSSFSheet().Write(out1); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + return out1.ToArray(); } - return out1.ToArray(); } } diff --git a/ooxml/XSSF/UserModel/XSSFColor.cs b/ooxml/XSSF/UserModel/XSSFColor.cs index 93627c5c0..ebf28aa18 100644 --- a/ooxml/XSSF/UserModel/XSSFColor.cs +++ b/ooxml/XSSF/UserModel/XSSFColor.cs @@ -52,7 +52,7 @@ public XSSFColor(System.Drawing.Color clr) : this() { - ctColor.SetRgb((byte)clr.R, (byte)clr.G, (byte)clr.B); + ctColor.SetRgb(clr.R, clr.G, clr.B); } public XSSFColor(byte[] rgb) diff --git a/ooxml/XSSF/UserModel/XSSFConditionFilterData.cs b/ooxml/XSSF/UserModel/XSSFConditionFilterData.cs new file mode 100644 index 000000000..082375eb2 --- /dev/null +++ b/ooxml/XSSF/UserModel/XSSFConditionFilterData.cs @@ -0,0 +1,27 @@ +using NPOI.OpenXmlFormats.Spreadsheet; +using NPOI.SS.UserModel; +using System; + +namespace NPOI.OOXML.XSSF.UserModel +{ + public class XSSFConditionFilterData:IConditionFilterData + { + private CT_CfRule _cfRule; + public XSSFConditionFilterData(CT_CfRule cfRule) + { + _cfRule = cfRule; + } + + public bool AboveAverage => _cfRule.aboveAverage; + + public bool Bottom => _cfRule.bottom; + + public bool EqualAverage => _cfRule.equalAverage; + + public bool Percent => _cfRule.percent; + + public long Rank => _cfRule.rank; + + public int StdDev => _cfRule.stdDev; + } +} diff --git a/ooxml/XSSF/UserModel/XSSFConditionalFormattingRule.cs b/ooxml/XSSF/UserModel/XSSFConditionalFormattingRule.cs index 97c88ec44..117f949b0 100644 --- a/ooxml/XSSF/UserModel/XSSFConditionalFormattingRule.cs +++ b/ooxml/XSSF/UserModel/XSSFConditionalFormattingRule.cs @@ -17,6 +17,8 @@ * ==================================================================== */ +using EnumsNET; +using NPOI.OOXML.XSSF.UserModel; using NPOI.OpenXmlFormats.Spreadsheet; using NPOI.SS.UserModel; using NPOI.XSSF.Model; @@ -38,6 +40,7 @@ public class XSSFConditionalFormattingRule : IConditionalFormattingRule private XSSFSheet _sh; private static Dictionary typeLookup = new Dictionary(); + private static Dictionary filterTypeLookup = new Dictionary(); static XSSFConditionalFormattingRule() { typeLookup.Add(ST_CfType.cellIs, ConditionTypeClass.CellValueIs); @@ -60,6 +63,20 @@ static XSSFConditionalFormattingRule() typeLookup.Add(ST_CfType.notContainsErrors, ConditionTypeClass.Filter); typeLookup.Add(ST_CfType.timePeriod, ConditionTypeClass.Filter); typeLookup.Add(ST_CfType.aboveAverage, ConditionTypeClass.Filter); + + filterTypeLookup.Add(ST_CfType.top10, SS.UserModel.ConditionFilterType.TOP_10); + filterTypeLookup.Add(ST_CfType.uniqueValues, SS.UserModel.ConditionFilterType.UNIQUE_VALUES); + filterTypeLookup.Add(ST_CfType.duplicateValues, SS.UserModel.ConditionFilterType.DUPLICATE_VALUES); + filterTypeLookup.Add(ST_CfType.containsText, SS.UserModel.ConditionFilterType.CONTAINS_TEXT); + filterTypeLookup.Add(ST_CfType.notContainsText, SS.UserModel.ConditionFilterType.NOT_CONTAINS_TEXT); + filterTypeLookup.Add(ST_CfType.beginsWith, SS.UserModel.ConditionFilterType.BEGINS_WITH); + filterTypeLookup.Add(ST_CfType.endsWith, SS.UserModel.ConditionFilterType.ENDS_WITH); + filterTypeLookup.Add(ST_CfType.containsBlanks, SS.UserModel.ConditionFilterType.CONTAINS_BLANKS); + filterTypeLookup.Add(ST_CfType.notContainsBlanks, SS.UserModel.ConditionFilterType.NOT_CONTAINS_BLANKS); + filterTypeLookup.Add(ST_CfType.containsErrors, SS.UserModel.ConditionFilterType.CONTAINS_ERRORS); + filterTypeLookup.Add(ST_CfType.notContainsErrors, SS.UserModel.ConditionFilterType.NOT_CONTAINS_ERRORS); + filterTypeLookup.Add(ST_CfType.timePeriod, SS.UserModel.ConditionFilterType.TIME_PERIOD); + filterTypeLookup.Add(ST_CfType.aboveAverage, SS.UserModel.ConditionFilterType.ABOVE_AVERAGE); } /*package*/ public XSSFConditionalFormattingRule(XSSFSheet sh) @@ -278,7 +295,7 @@ public XSSFIconMultiStateFormatting CreateMultiStateFormatting(IconSet iconSet) // Set the type of the icon set if (iconSet.name != null) { - ST_IconSetType xIconSet = XmlEnumParser.ForName(iconSet.name, ST_IconSetType.Item3TrafficLights1); + ST_IconSetType xIconSet =Enums.Parse(iconSet.name, false, EnumFormat.Description); icons.iconSet = xIconSet; } @@ -448,6 +465,57 @@ public String Formula2 } } + public bool StopIfTrue + { + get + { + return _cfRule.stopIfTrue; + } + } + public String Text + { + get + { + return _cfRule.text; + } + } + public int Priority + { + get + { + int priority = _cfRule.priority; + // priorities start at 1, if it is less, it is undefined, use definition order in caller + return priority >= 1 ? priority : 0; + } + } + public ExcelNumberFormat NumberFormat + { + get + { + CT_Dxf dxf = GetDxf(false); + if (dxf == null || !dxf.IsSetNumFmt()) return null; + + CT_NumFmt numFmt = dxf.numFmt; + return new ExcelNumberFormat((int)numFmt.numFmtId, numFmt.formatCode); + } + } + + public ConditionFilterType? ConditionFilterType + { + get + { + if (!filterTypeLookup.ContainsKey(_cfRule.type)) + return null; + return filterTypeLookup[_cfRule.type]; + } + } + public IConditionFilterData FilterConfiguration + { + get + { + return new XSSFConditionFilterData(_cfRule); + } + } } } diff --git a/ooxml/XSSF/UserModel/XSSFDxfStyleProvider.cs b/ooxml/XSSF/UserModel/XSSFDxfStyleProvider.cs new file mode 100644 index 000000000..9cabb22c9 --- /dev/null +++ b/ooxml/XSSF/UserModel/XSSFDxfStyleProvider.cs @@ -0,0 +1,56 @@ +using NPOI.OpenXmlFormats.Spreadsheet; +using NPOI.SS.UserModel; +using NPOI.XSSF.UserModel; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.OOXML.XSSF.UserModel +{ + public class XSSFDxfStyleProvider : DifferentialStyleProvider + { + private IIndexedColorMap colorMap; + private IBorderFormatting border; + private IFontFormatting font; + private ExcelNumberFormat number; + private IPatternFormatting fill; + private int stripeSize; + + public XSSFDxfStyleProvider(CT_Dxf dxf, int stripeSize, IIndexedColorMap colorMap) + { + this.stripeSize = stripeSize; + this.colorMap = colorMap; + if (dxf == null) + { + border = null; + font = null; + number = null; + fill = null; + } + else + { + border = dxf.IsSetBorder() ? new XSSFBorderFormatting(dxf.border) : null; + font = dxf.IsSetFont() ? new XSSFFontFormatting(dxf.font) : null; + if (dxf.IsSetNumFmt()) + { + CT_NumFmt numFmt = dxf.numFmt; + number = new ExcelNumberFormat((int)numFmt.numFmtId, numFmt.formatCode); + } + else + { + number = null; + } + fill = dxf.IsSetFill() ? new XSSFPatternFormatting(dxf.fill) : null; + } + } + public IBorderFormatting BorderFormatting => border; + + public IFontFormatting FontFormatting => font; + + public IPatternFormatting PatternFormatting => fill; + + public ExcelNumberFormat NumberFormat => number; + + public int StripeSize => stripeSize; + } +} diff --git a/ooxml/XSSF/UserModel/XSSFEvaluationCell.cs b/ooxml/XSSF/UserModel/XSSFEvaluationCell.cs index 0401f51c5..717e09716 100644 --- a/ooxml/XSSF/UserModel/XSSFEvaluationCell.cs +++ b/ooxml/XSSF/UserModel/XSSFEvaluationCell.cs @@ -19,6 +19,8 @@ using NPOI.XSSF.UserModel; using System; using NPOI.SS.UserModel; +using NPOI.SS.Util; + namespace NPOI.XSSF.UserModel { @@ -121,14 +123,22 @@ public virtual String StringCellValue } } - #region IEvaluationCell Ա + public bool IsPartOfArrayFormulaGroup + { + get + { + return _cell.IsPartOfArrayFormulaGroup; + } + } + public CellRangeAddress ArrayFormulaRange + { + get { return _cell.ArrayFormulaRange; } + } public virtual CellType CachedFormulaResultType { get { return _cell.CachedFormulaResultType; } } - - #endregion } } diff --git a/ooxml/XSSF/UserModel/XSSFHyperlink.cs b/ooxml/XSSF/UserModel/XSSFHyperlink.cs index 97c0db10f..63a57ee5c 100644 --- a/ooxml/XSSF/UserModel/XSSFHyperlink.cs +++ b/ooxml/XSSF/UserModel/XSSFHyperlink.cs @@ -83,7 +83,7 @@ public XSSFHyperlink(CT_Hyperlink ctHyperlink, PackageRelationship hyperlinkRel) else { Uri target = _externalRel.TargetUri; - _location = target.ToString(); + _location = target.OriginalString; if (ctHyperlink.location != null) { // URI fragment diff --git a/ooxml/XSSF/UserModel/XSSFIconMultiStateFormatting.cs b/ooxml/XSSF/UserModel/XSSFIconMultiStateFormatting.cs index ec6ee0f78..e4e8f0f5c 100644 --- a/ooxml/XSSF/UserModel/XSSFIconMultiStateFormatting.cs +++ b/ooxml/XSSF/UserModel/XSSFIconMultiStateFormatting.cs @@ -19,6 +19,7 @@ namespace NPOI.XSSF.UserModel { using System; + using EnumsNET; using NPOI.OpenXmlFormats.Spreadsheet; using NPOI.SS.UserModel; using NPOI.XSSF.Util; @@ -46,7 +47,7 @@ public IconSet IconSet } set { - ST_IconSetType xIconSet = XmlEnumParser.ForName(value.name, ST_IconSetType.Item3TrafficLights1); + ST_IconSetType xIconSet = Enums.Parse(value.name, false, EnumFormat.Description); _iconset.iconSet = (xIconSet); } } diff --git a/ooxml/XSSF/UserModel/XSSFRichTextString.cs b/ooxml/XSSF/UserModel/XSSFRichTextString.cs index 919d5402d..fa999adce 100644 --- a/ooxml/XSSF/UserModel/XSSFRichTextString.cs +++ b/ooxml/XSSF/UserModel/XSSFRichTextString.cs @@ -79,7 +79,7 @@ public XSSFRichTextString(String str) { st = new CT_Rst(); st.t = str; - PreserveSpaces(st.t); + //PreserveSpaces(st.t); } @@ -279,12 +279,12 @@ public void Append(String text, XSSFFont font) //convert string into a text Run: string CT_RElt lt = st.AddNewR(); lt.t = st.t; - PreserveSpaces(lt.t); + //PreserveSpaces(lt.t); st.unsetT(); } CT_RElt lt2 = st.AddNewR(); lt2.t= (text); - PreserveSpaces(lt2.t); + //PreserveSpaces(lt2.t); if (font != null) { @@ -441,7 +441,7 @@ public String String { ClearFormatting(); st.t = value; - PreserveSpaces(st.t); + //PreserveSpaces(st.t); } } @@ -692,7 +692,7 @@ CT_Rst BuildCTRst(String text, SortedDictionary formats) CT_RElt run = st.AddNewR(); String fragment = text.Substring(runStartIdx, runEndIdx - runStartIdx); run.t = (fragment); - PreserveSpaces(run.t); + //PreserveSpaces(run.t); CT_RPrElt fmt = kv.Value; if (fmt != null) { diff --git a/ooxml/XSSF/UserModel/XSSFSheet.cs b/ooxml/XSSF/UserModel/XSSFSheet.cs index a5d45ce97..07f598105 100644 --- a/ooxml/XSSF/UserModel/XSSFSheet.cs +++ b/ooxml/XSSF/UserModel/XSSFSheet.cs @@ -3200,6 +3200,23 @@ public void ShiftRows(int startRow, int endRow, int n) */ //YK: GetXYZArray() array accessors are deprecated in xmlbeans with JDK 1.5 support public void ShiftRows(int startRow, int endRow, int n, bool copyRowHeight, bool resetOriginalRowHeight) + { + int sheetIndex = Workbook.GetSheetIndex(this); + String sheetName = Workbook.GetSheetName(sheetIndex); + FormulaShifter shifter = FormulaShifter.CreateForRowShift( + sheetIndex, sheetName, startRow, endRow, n, SpreadsheetVersion.EXCEL2007); + removeOverwritten(startRow, endRow, n); + shiftCommentsAndRows(startRow, endRow, n, copyRowHeight); + + XSSFRowShifter rowShifter = new XSSFRowShifter(this); + rowShifter.ShiftMergedRegions(startRow, endRow, n); + rowShifter.UpdateNamedRanges(shifter); + rowShifter.UpdateFormulas(shifter); + rowShifter.UpdateConditionalFormatting(shifter); + rowShifter.UpdateHyperlinks(shifter); + rebuildRows(); + } + private void removeOverwritten(int startRow, int endRow, int n) { XSSFVMLDrawing vml = GetVMLDrawing(false); List rowsToRemove = new List(); @@ -3269,9 +3286,29 @@ public void ShiftRows(int startRow, int endRow, int n, bool copyRowHeight, bool _rows.Remove(rowKey); } worksheet.sheetData.RemoveRows(ctRowsToRemove); - // then do the actual moving and also adjust comments/rowHeight - // we need to sort it in a way so the Shifting does not mess up the structures, - // i.e. when Shifting down, start from down and go up, when Shifting up, vice-versa + } + private void rebuildRows() + { + //rebuild the _rows map + Dictionary map = new Dictionary(); + foreach (XSSFRow r in _rows.Values) + { + map.Add(r.RowNum, r); + } + _rows.Clear(); + //_rows.putAll(map); + foreach (KeyValuePair kv in map) + { + _rows.Add(kv.Key, kv.Value); + } + + // Sort CTRows by index asc. + // not found at poi 3.15 + if (worksheet.sheetData.row != null) + worksheet.sheetData.row.Sort((row1, row2) => row1.r.CompareTo(row2.r)); + } + private void shiftCommentsAndRows(int startRow, int endRow, int n, bool copyRowHeight) + { SortedDictionary commentsToShift = new SortedDictionary(new ShiftCommentComparator(n)); foreach (KeyValuePair rowDict in _rows) @@ -3287,24 +3324,21 @@ public void ShiftRows(int startRow, int endRow, int n, bool copyRowHeight, bool // is there a change necessary for the current row? if (newrownum != rownum) { - CT_CommentList lst = sheetComments.GetCTComments().commentList; - foreach (CT_Comment comment in lst.comment) + var commentAddresses = sheetComments.GetCellAddresses(); + foreach (var cellAddress in commentAddresses) { - String oldRef = comment.@ref; - CellReference ref1 = new CellReference(oldRef); - - // is this comment part of the current row? - if (ref1.Row == rownum) + if (cellAddress.Row == rownum) { - XSSFComment xssfComment = new XSSFComment(sheetComments, comment, - vml == null ? null : vml.FindCommentShape(rownum, ref1.Col)); - - // we should not perform the Shifting right here as we would then find - // already Shifted comments and would shift them again... - if (commentsToShift.ContainsKey(xssfComment)) - commentsToShift[xssfComment] = newrownum; - else - commentsToShift.Add(xssfComment, newrownum); + XSSFComment oldComment = sheetComments.FindCellComment(cellAddress); + if (oldComment!=null) + { + XSSFComment xssfComment = new XSSFComment(sheetComments, oldComment.GetCTComment(), + oldComment.GetCTShape()); + if (commentsToShift.ContainsKey(xssfComment)) + commentsToShift[xssfComment] = newrownum; + else + commentsToShift.Add(xssfComment, newrownum); + } } } } @@ -3315,7 +3349,7 @@ public void ShiftRows(int startRow, int endRow, int n, bool copyRowHeight, bool if (!copyRowHeight) { row.Height = (/*setter*/(short)-1); - } + } row.Shift(n); } @@ -3325,39 +3359,9 @@ public void ShiftRows(int startRow, int endRow, int n, bool copyRowHeight, bool // i.e. from down to up if Shifting down, vice-versa otherwise foreach (KeyValuePair entry in commentsToShift) { - entry.Key.Row = (/*setter*/entry.Value); - } - - XSSFRowShifter rowShifter = new XSSFRowShifter(this); - - int sheetIndex = Workbook.GetSheetIndex(this); - String sheetName = Workbook.GetSheetName(sheetIndex); - FormulaShifter shifter = FormulaShifter.CreateForRowShift( - sheetIndex, sheetName, startRow, endRow, n, SpreadsheetVersion.EXCEL2007); - - rowShifter.UpdateNamedRanges(shifter); - rowShifter.UpdateFormulas(shifter); - rowShifter.ShiftMergedRegions(startRow, endRow, n); - rowShifter.UpdateConditionalFormatting(shifter); - rowShifter.UpdateHyperlinks(shifter); - - //rebuild the _rows map - Dictionary map = new Dictionary(); - foreach (XSSFRow r in _rows.Values) - { - map.Add(r.RowNum, r); - } - _rows.Clear(); - //_rows.putAll(map); - foreach (KeyValuePair kv in map) - { - _rows.Add(kv.Key, kv.Value); + entry.Key.Row = entry.Value; } - - // Sort CTRows by index asc. - // not found at poi 3.15 - if (worksheet.sheetData.row != null) - worksheet.sheetData.row.Sort((row1, row2) => row1.r.CompareTo(row2.r)); + rebuildRows(); } private class ShiftCommentComparator : IComparer { @@ -3752,7 +3756,7 @@ protected internal override void Commit() out1.Close(); } - internal virtual void Write(Stream stream) + internal virtual void Write(Stream stream, bool leaveOpen=false) { bool setToNull = false; if (worksheet.sizeOfColsArray() == 1) @@ -3804,7 +3808,7 @@ NPOI.OpenXmlFormats.Spreadsheet.CT_Hyperlink[] ctHls map[ST_RelationshipId.NamespaceURI] = "r"; //xmlOptions.SetSaveSuggestedPrefixes(map); - new WorksheetDocument(worksheet).Save(stream); + new WorksheetDocument(worksheet).Save(stream, leaveOpen); // Bug 52233: Ensure that we have a col-array even if write() removed it if (setToNull) @@ -4773,10 +4777,11 @@ public ISheet CopySheet(String name, Boolean copyStyle) try { - using (MemoryStream out1 = new MemoryStream()) + using (MemoryStream ms = RecyclableMemory.GetStream()) { - this.Write(out1); - clonedSheet.Read(new MemoryStream(out1.ToArray())); + this.Write(ms, true); + ms.Position = 0; + clonedSheet.Read(ms); } } catch (IOException e) @@ -4805,7 +4810,7 @@ public ISheet CopySheet(String name, Boolean copyStyle) continue; } //skip printerSettings.bin part - if (r.GetPackagePart().PartName.Name == "/xl/printerSettings/printerSettings1.bin") + if (r.GetPackagePart().PartName.Name.StartsWith("/xl/printerSettings/printerSettings")) continue; PackageRelationship rel = r.GetPackageRelationship(); clonedSheet.GetPackagePart().AddRelationship( @@ -5424,7 +5429,53 @@ private ISet GetErrorTypes(CT_IgnoredError err) } return result; } + /** + * when a cell with a 'master' shared formula is removed, the next cell in the range becomes the master + * @param cell The cell that is removed + * @param evalWb BaseXSSFEvaluationWorkbook in use, if one exists + */ + internal void OnDeleteFormula(XSSFCell cell, XSSFEvaluationWorkbook evalWb) + { + CT_CellFormula f = cell.GetCTCell().f; + if (f != null && f.t == ST_CellFormulaType.shared && f.isSetRef() && f.Value != null) + { + bool breakit = false; + CellRangeAddress ref1 = CellRangeAddress.ValueOf(f.@ref); + if (ref1.NumberOfCells > 1) + { + for (int i = cell.RowIndex; i <= ref1.LastRow; i++) + { + XSSFRow row = (XSSFRow)GetRow(i); + if (row != null) + { + for (int j = cell.ColumnIndex; j <= ref1.LastColumn; j++) + { + XSSFCell nextCell = (XSSFCell)row.GetCell(j); + if (nextCell != null && nextCell != cell && nextCell.CellType == CellType.Formula) + { + CT_CellFormula nextF = nextCell.GetCTCell().f; + if (nextF.t == ST_CellFormulaType.shared && nextF.si == f.si) + { + nextF.Value = nextCell.GetCellFormula(evalWb); + CellRangeAddress nextRef = new CellRangeAddress( + nextCell.RowIndex, ref1.LastRow, + nextCell.ColumnIndex, ref1.LastColumn); + nextF.@ref=nextRef.FormatAsString(); + + sharedFormulas[(int)nextF.si]= nextF; + breakit = true; + break; + } + } + } + if (breakit) + break; + } + } + } + } + } } } diff --git a/ooxml/XSSF/UserModel/XSSFTable.cs b/ooxml/XSSF/UserModel/XSSFTable.cs index 59f3d22bb..d797b4b5c 100644 --- a/ooxml/XSSF/UserModel/XSSFTable.cs +++ b/ooxml/XSSF/UserModel/XSSFTable.cs @@ -28,6 +28,9 @@ using NPOI.SS.UserModel; using System.Text.RegularExpressions; using System.Globalization; +using NPOI.SS; +using System.Linq; +using NPOI.OOXML.XSSF.UserModel; namespace NPOI.XSSF.UserModel { @@ -47,8 +50,8 @@ namespace NPOI.XSSF.UserModel public class XSSFTable : POIXMLDocumentPart, ITable { private CT_Table ctTable; - private List xmlColumnPr; - private CT_TableColumn[] ctColumns; + private List xmlColumnPrs; + private List tableColumns; private Dictionary columnMap; private CellReference startCellReference; private CellReference endCellReference; @@ -129,7 +132,7 @@ public bool MapsTo(long id) foreach (XSSFXmlColumnPr pointer in pointers) { - if (pointer.GetMapId() == id) + if (pointer.MapId == id) { maps = true; break; @@ -138,19 +141,6 @@ public bool MapsTo(long id) return maps; } - - private CT_TableColumn[] TableColumns - { - get - { - if (ctColumns == null) - { - ctColumns = ctTable.tableColumns.tableColumn.ToArray(); - } - return ctColumns; - } - - } /** * * Calculates the xpath of the root element for the table. This will be the common part @@ -166,11 +156,11 @@ public String GetCommonXpath() Array commonTokens = null; - foreach (CT_TableColumn column in TableColumns) + foreach (XSSFTableColumn column in GetColumns()) { - if (column.xmlColumnPr != null) + if (column.GetXmlColumnPr() != null) { - String xpath = column.xmlColumnPr.xpath; + String xpath = column.GetXmlColumnPr().XPath; String[] tokens = xpath.Split(new char[] { '/' }); if (commonTokens==null) { @@ -212,24 +202,25 @@ public String GetCommonXpath() * Note this list is static - once read, it does not notice later changes to the underlying column structures * @return List of XSSFXmlColumnPr */ + [Obsolete] public List GetXmlColumnPrs() { - if (xmlColumnPr == null) + if (xmlColumnPrs == null) { - xmlColumnPr = new List(); + xmlColumnPrs = new List(); foreach (CT_TableColumn column in ctTable.tableColumns.tableColumn) { if (column.xmlColumnPr != null) { XSSFXmlColumnPr columnPr = new XSSFXmlColumnPr(this, column, column.xmlColumnPr); - xmlColumnPr.Add(columnPr); + xmlColumnPrs.Add(columnPr); } } } - return xmlColumnPr; + return xmlColumnPrs; } - + private string name; /** * @return the name of the Table, if set */ @@ -237,18 +228,202 @@ public String Name { get { - return ctTable.name; + if (name == null) + { + Name = ctTable.name; + } + return name; } set { + if (value == null) + { + ctTable.name=null; + name = null; + return; + } ctTable.name = value; + name = value; } } + public XSSFTableColumn CreateColumn(String columnName) + { + return CreateColumn(columnName, this.ColumnCount); + } + public XSSFTableColumn CreateColumn(String columnName, int columnIndex) + { + + int columnCount = ColumnCount; + if (columnIndex < 0 || columnIndex > columnCount) + { + throw new ArgumentException("Column index out of bounds"); + } + + // Ensure we have Table Columns + CT_TableColumns columns = ctTable.tableColumns; + if (columns == null) + { + columns = ctTable.AddNewTableColumns(); + } + // check if name is unique and calculate unique column id + long nextColumnId = 0; + foreach (XSSFTableColumn tableColumn in this.GetColumns()) + { + if (columnName != null && columnName.Equals(tableColumn.Name,StringComparison.InvariantCultureIgnoreCase)) + { + throw new ArgumentException("Column '" + columnName + + "' already exists. Column names must be unique per table."); + } + nextColumnId = Math.Max(nextColumnId, tableColumn.Id); + } + // Bug #62740, the logic was just re-using the existing max ID, not incrementing beyond it. + nextColumnId++; + + // Add the new Column + CT_TableColumn column = columns.InsertNewTableColumn(columnIndex); + columns.count = columns.count; + + column.id = (uint)nextColumnId; + if (columnName != null) + { + column.name = columnName; + } + else + { + column.name = "Column " + nextColumnId; + } + + /*if (ctTable.@ref != null) + { + // calculate new area + int newColumnCount = columnCount + 1; + CellReference tableStart = StartCellReference; + CellReference tableEnd = EndCellReference; + SpreadsheetVersion version = GetXSSFSheet().GetWorkbook().SpreadsheetVersion; + CellReference newTableEnd = new CellReference(tableEnd.Row, + tableStart.Col + newColumnCount - 1); + AreaReference newTableArea = new AreaReference(tableStart, newTableEnd, version); + + SetCellRef(newTableArea); + }*/ + + UpdateHeaders(); + + return GetColumns()[columnIndex]; + } + /** + * Get the area reference for the cells which this table covers. The area + * includes header rows and totals rows. + * + * Does not track updates to underlying changes to CTTable To synchronize + * with changes to the underlying CTTable, call {@link #updateReferences()}. + * + * @return the area of the table + * @see "Open Office XML Part 4: chapter 3.5.1.2, attribute ref" + */ + public AreaReference GetCellReferences() + { + return new AreaReference( + StartCellReference, + EndCellReference, + SpreadsheetVersion.EXCEL2007 + ); + } + /** + * Set the area reference for the cells which this table covers. The area + * includes includes header rows and totals rows. Automatically synchronizes + * any changes by calling {@link #updateHeaders()}. + * + * Note: The area's width should be identical to the amount of columns in + * the table or the table may be invalid. All header rows, totals rows and + * at least one data row must fit inside the area. Updating the area with + * this method does not create or remove any columns and does not change any + * cell values. + * + * @see "Open Office XML Part 4: chapter 3.5.1.2, attribute ref" + */ + public void SetCellReferences(AreaReference refs) + { + SetCellRef(refs); + } + protected void SetCellRef(AreaReference refs) + { + + // Strip the sheet name, + // CTWorksheet.getTableParts defines in which sheet the table is + String reference = refs.FormatAsString(); + if (reference.IndexOf('!') != -1) + { + reference = reference.Substring(reference.IndexOf('!') + 1); + } + + // Update + ctTable.@ref = reference; + if (ctTable.IsSetAutoFilter) + { + String filterRef; + int totalsRowCount = TotalsRowCount; + if (totalsRowCount == 0) + { + filterRef = reference; + } + else + { + CellReference start = new CellReference(refs.FirstCell.Row, refs.FirstCell.Col); + // account for footer row(s) in auto-filter range, which doesn't include footers + CellReference end = new CellReference(refs.LastCell.Row - totalsRowCount, refs.LastCell.Col); + // this won't have sheet references because we built the cell references without them + filterRef = new AreaReference(start, end, SpreadsheetVersion.EXCEL2007).FormatAsString(); + } + ctTable.autoFilter.@ref =filterRef; + } + + // Have everything recomputed + 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 + { + if (!ctTable.IsSetTableStyleInfo()) return null; + return new XSSFTableStyleInfo(((XSSFWorkbook)((XSSFSheet)GetParent()).Workbook).GetStylesSource(), ctTable.tableStyleInfo); + } + } /** * @return the display name of the Table, if set */ - public String DisplayName + public string DisplayName { get { @@ -264,6 +439,7 @@ public String DisplayName /** * @return the number of mapped table columns (see Open Office XML Part 4: chapter 3.5.1.4) */ + [Obsolete] public long NumberOfMappedColumns { get @@ -271,8 +447,42 @@ public long NumberOfMappedColumns return ctTable.tableColumns.count; } } - - + public int ColumnCount + { + get + { + CT_TableColumns tableColumns = ctTable.tableColumns; + if (tableColumns == null) + { + return 0; + } + // Casting to int should be safe here - tables larger than the + // sheet (which holds the actual data of the table) can't exists. + return (int)tableColumns.tableColumn.Count(); + } + } + /// + /// 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. + /// + public int TotalsRowCount + { + get { + return (int)ctTable.totalsRowCount; + } + } + /// + /// 0 for no header rows, 1 for table headers shown. + /// Values > 1 might be used by Excel for pivot tables? + /// + public int HeaderRowCount + { + get + { + return (int)ctTable.headerRowCount; + } + } /** * @return The reference for the cell in the top-left part of the table * (see Open Office XML Part 4: chapter 3.5.1.2, attribute ref) @@ -402,9 +612,11 @@ public void UpdateHeaders() } cellnum++; } - ctColumns = null; - columnMap = null; } + tableColumns = null; + columnMap = null; + xmlColumnPrs = null; + commonXPath = null; } /** * Gets the relative column index of a column in this table having the header name column. @@ -423,12 +635,13 @@ public int FindColumnIndex(String columnHeader) if (columnHeader == null) return -1; if (columnMap == null) { - columnMap = new Dictionary(TableColumns.Length * 3 / 2); + int count = ColumnCount; + columnMap = new Dictionary(count * 3 / 2); int i = 0; - foreach (CT_TableColumn column in TableColumns) + foreach (XSSFTableColumn column in GetColumns()) { - columnMap.Add(column.name.ToUpper(CultureInfo.CurrentCulture), i); + columnMap.Add(column.Name.ToUpper(CultureInfo.CurrentCulture), i); i++; } } @@ -440,7 +653,38 @@ public int FindColumnIndex(String columnHeader) idx = columnMap[testKey]; return idx; } - + /// + /// Note this list is static - once read, it does not notice later changes to the underlying column structures + /// + /// + public List GetColumns() + { + if (tableColumns == null) + { + var columns = new List(); + CT_TableColumns ctTableColumns = ctTable.tableColumns; + if (ctTableColumns != null) + { + foreach (CT_TableColumn column in ctTableColumns.GetTableColumnList()) + { + XSSFTableColumn tableColumn = new XSSFTableColumn(this, column); + columns.Add(tableColumn); + } + } + tableColumns = columns; + } + return tableColumns; + } + public void RemoveColumn(XSSFTableColumn column) + { + int columnIndex = GetColumns().IndexOf(column); + if (columnIndex >= 0) + { + ctTable.tableColumns.RemoveTableColumn(columnIndex); + UpdateReferences(); + UpdateHeaders(); + } + } public String SheetName { get @@ -449,12 +693,20 @@ public String SheetName } } + /// + /// This is misleading. The Spec indicates this is true if the totals row + /// hasever been shown, not whether or not it is currently displayed. + /// public bool IsHasTotalsRow { get { return ctTable.totalsRowShown; } + set + { + ctTable.totalsRowShown = value; + } } public int StartColIndex @@ -488,5 +740,20 @@ public int EndRowIndex return EndCellReference.Row; } } + public bool Contains(CellReference cell) + { + if (cell == null) return false; + // check if cell is on the same sheet as the table + if (! SheetName.Equals(cell.SheetName)) return false; + // check if the cell is inside the table + if (cell.Row >= StartRowIndex + && cell.Row <= EndRowIndex + && cell.Col >= StartColIndex + && cell.Col <= EndColIndex) + { + return true; + } + return false; + } } } \ No newline at end of file diff --git a/ooxml/XSSF/UserModel/XSSFTableColumn.cs b/ooxml/XSSF/UserModel/XSSFTableColumn.cs new file mode 100644 index 000000000..09a29b159 --- /dev/null +++ b/ooxml/XSSF/UserModel/XSSFTableColumn.cs @@ -0,0 +1,58 @@ +using NPOI.OpenXmlFormats.Spreadsheet; +using NPOI.XSSF.UserModel.Helpers; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.XSSF.UserModel +{ + public class XSSFTableColumn + { + private XSSFTable table; + private CT_TableColumn ctTableColumn; + private XSSFXmlColumnPr xmlColumnPr; + internal XSSFTableColumn(XSSFTable table, CT_TableColumn ctTableColumn) + { + this.table = table; + this.ctTableColumn = ctTableColumn; + } + /// + /// Get the table which contains this column + /// + /// the table containing this column + public XSSFTable GetTable() + { + return table; + } + public long Id { + get { + return ctTableColumn.id; + } + set + { + ctTableColumn.id = (uint)value; + } + } + public string Name + { + get { return ctTableColumn.name; } + set { ctTableColumn.name = value; } + } + public XSSFXmlColumnPr GetXmlColumnPr() + { + if (xmlColumnPr == null) + { + CT_XmlColumnPr ctXmlColumnPr = ctTableColumn.xmlColumnPr; + if (ctXmlColumnPr != null) + { + xmlColumnPr = new XSSFXmlColumnPr(this, ctXmlColumnPr); + } + } + return xmlColumnPr; + } + public int ColumnIndex + { + get { return table.FindColumnIndex(this.Name); } + } + } +} diff --git a/ooxml/XSSF/UserModel/XSSFTableStyle.cs b/ooxml/XSSF/UserModel/XSSFTableStyle.cs new file mode 100644 index 000000000..7fb00a66e --- /dev/null +++ b/ooxml/XSSF/UserModel/XSSFTableStyle.cs @@ -0,0 +1,59 @@ +using NPOI.OpenXmlFormats.Spreadsheet; +using NPOI.SS.UserModel; +using NPOI.XSSF.UserModel; +using System; +using System.Collections.Generic; +using EnumsNET; + +namespace NPOI.OOXML.XSSF.UserModel +{ + public class XSSFTableStyle : ITableStyle + { + private String name; + private int index; + private Dictionary elementMap = new Dictionary(); + + public XSSFTableStyle(int index, CT_Dxfs dxfs, CT_TableStyle tableStyle, IIndexedColorMap colorMap) + { + this.name = tableStyle.name; + this.index = index; + + List dxfList = dxfs.dxf; + + foreach (CT_TableStyleElement element in tableStyle.tableStyleElement) + { + TableStyleType type = Enums.Parse(element.type.GetName()); + DifferentialStyleProvider dstyle = null; + if (element.dxfIdSpecified) + { + int idx = (int)element.dxfId; + CT_Dxf dxf; + dxf = dxfList[idx]; + int stripeSize = 0; + if (element.size!=0) stripeSize = (int)element.size; + if (dxf != null) dstyle = new XSSFDxfStyleProvider(dxf, stripeSize, colorMap); + } + elementMap.Add(type, dstyle); + } + } + public string Name + { + get { return name; } + } + + public int Index + { + get { return index; } + } + + public bool IsBuiltin + { + get { return false; } + } + + public DifferentialStyleProvider GetStyle(TableStyleType type) + { + return elementMap[type]; + } + } +} diff --git a/ooxml/XSSF/UserModel/XSSFTableStyleInfo.cs b/ooxml/XSSF/UserModel/XSSFTableStyleInfo.cs new file mode 100644 index 000000000..68cf6a06e --- /dev/null +++ b/ooxml/XSSF/UserModel/XSSFTableStyleInfo.cs @@ -0,0 +1,81 @@ +using NPOI.OpenXmlFormats.Spreadsheet; +using NPOI.SS.UserModel; +using NPOI.XSSF.Model; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NPOI.OOXML.XSSF.UserModel +{ + public class XSSFTableStyleInfo : ITableStyleInfo + { + private CT_TableStyleInfo styleInfo; + private StylesTable stylesTable; + private ITableStyle style; + private bool columnStripes; + private bool rowStripes; + private bool firstColumn; + private bool lastColumn; + + public XSSFTableStyleInfo(StylesTable stylesTable, CT_TableStyleInfo tableStyleInfo) + { + this.columnStripes = tableStyleInfo.showColumnStripes; + this.rowStripes = tableStyleInfo.showRowStripes; + this.firstColumn = tableStyleInfo.showFirstColumn; + this.lastColumn = tableStyleInfo.showLastColumn; + this.style = stylesTable.GetTableStyle(tableStyleInfo.name); + this.stylesTable = stylesTable; + this.styleInfo = tableStyleInfo; + } + public bool IsShowColumnStripes + { + get { return columnStripes; } + set { + this.columnStripes = value; + styleInfo.showColumnStripes=value; + } + } + + public bool IsShowRowStripes + { + get { return rowStripes; } + set { + this.rowStripes = value; + styleInfo.showRowStripes = value; + } + } + + public bool IsShowFirstColumn + { + get { return firstColumn; } + set + { + this.firstColumn = value; + styleInfo.showFirstColumn = value; + } + } + + public bool IsShowLastColumn + { + get { return lastColumn; } + set { + this.lastColumn = value; + styleInfo.showLastColumn = value; + } + } + + public string Name + { + get { return style.Name; } + set { + styleInfo.name = value; + style = stylesTable.GetTableStyle(value); + } + } + + public ITableStyle Style + { + get { return style; } + } + } +} diff --git a/ooxml/XSSF/UserModel/XSSFWorkbook.cs b/ooxml/XSSF/UserModel/XSSFWorkbook.cs index e489ca337..6ded36602 100644 --- a/ooxml/XSSF/UserModel/XSSFWorkbook.cs +++ b/ooxml/XSSF/UserModel/XSSFWorkbook.cs @@ -148,7 +148,7 @@ public class XSSFWorkbook : POIXMLDocument, IWorkbook * See {@link NPOI.ss.usermodel.Row.MissingCellPolicy} */ private MissingCellPolicy _missingCellPolicy = MissingCellPolicy.RETURN_NULL_AND_BLANK; - + private bool cellFormulaValidation = true; /** * array of pictures for this workbook */ @@ -596,6 +596,7 @@ public ISheet CloneSheet(int sheetNum, String newName) else { ValidateSheetName(newName); + WorkbookUtil.ValidateSheetName(newName); } XSSFSheet clonedSheet = CreateSheet(newName) as XSSFSheet; @@ -624,7 +625,7 @@ public ISheet CloneSheet(int sheetNum, String newName) if (pr.TargetMode == TargetMode.External) { clonedSheet.GetPackagePart().AddExternalRelationship - (pr.TargetUri.ToString(), pr.RelationshipType, null); + (pr.TargetUri.OriginalString, pr.RelationshipType, null); } } } @@ -635,10 +636,11 @@ public ISheet CloneSheet(int sheetNum, String newName) try { - using (MemoryStream out1 = new MemoryStream()) + using (MemoryStream ms = RecyclableMemory.GetStream()) { - srcSheet.Write(out1); - clonedSheet.Read(new MemoryStream(out1.ToArray())); + srcSheet.Write(ms, true); + ms.Position = 0; + clonedSheet.Read(ms); } } catch (IOException e) @@ -728,7 +730,7 @@ private String GetUniqueSheetName(String srcName) uniqueIndex++; baseName = srcName.Substring(0, bracketPos).Trim(); } - catch (FormatException e) + catch (FormatException) { // contents of brackets not numeric } @@ -880,9 +882,6 @@ public ISheet CreateSheet(String sheetname) } ValidateSheetName(sheetname); - - // YK: Mimic Excel and silently tRuncate sheet names longer than 31 characters - if (sheetname.Length > 31) sheetname = sheetname.Substring(0, 31); WorkbookUtil.ValidateSheetName(sheetname); CT_Sheet sheet = AddSheet(sheetname); @@ -2362,7 +2361,11 @@ public List PivotTables this.pivotTables = value; } } - + public bool CellFormulaValidation + { + get { return this.cellFormulaValidation; } + set { this.cellFormulaValidation = false; } + } #region IWorkbook Members diff --git a/ooxml/XSSF/Util/XmlEnumParser.cs b/ooxml/XSSF/Util/XmlEnumParser.cs index 75b74e9ea..2e575ad34 100644 --- a/ooxml/XSSF/Util/XmlEnumParser.cs +++ b/ooxml/XSSF/Util/XmlEnumParser.cs @@ -8,6 +8,7 @@ namespace NPOI.XSSF.Util { + [Obsolete] public class XmlEnumParser { private static Dictionary values; diff --git a/ooxml/XWPF/Usermodel/XWPFDocument.cs b/ooxml/XWPF/Usermodel/XWPFDocument.cs index c0663e87c..97a678f08 100644 --- a/ooxml/XWPF/Usermodel/XWPFDocument.cs +++ b/ooxml/XWPF/Usermodel/XWPFDocument.cs @@ -214,7 +214,7 @@ private void InitHyperlinks() while (relIter.MoveNext()) { PackageRelationship rel = relIter.Current; - hyperlinks.Add(new XWPFHyperlink(rel.Id, rel.TargetUri.ToString())); + hyperlinks.Add(new XWPFHyperlink(rel.Id, rel.TargetUri.OriginalString)); } } catch (InvalidDataException e) @@ -238,7 +238,7 @@ private void InitFootnotes() EndnotesDocument endnotesDocument = EndnotesDocument.Parse(xmldoc, NamespaceManager); foreach (CT_FtnEdn ctFtnEdn in endnotesDocument.Endnotes.endnote) { - endnotes.Add(Int32.Parse(ctFtnEdn.id), new XWPFFootnote(this, ctFtnEdn)); + endnotes.Add(ctFtnEdn.id, new XWPFFootnote(this, ctFtnEdn)); } } } @@ -966,10 +966,43 @@ public XWPFFootnote AddFootnote(CT_FtnEdn note) public XWPFFootnote AddEndnote(CT_FtnEdn note) { XWPFFootnote endnote = new XWPFFootnote(this, note); - endnotes.Add(int.Parse(note.id), endnote); + endnotes.Add(note.id, endnote); return endnote; } + /// + /// Create a new footnote and add it to the document. + /// + /// + /// The new note will have one paragraph with the style "FootnoteText" + /// and one run containing the required footnote reference with the + /// style "FootnoteReference". + /// + /// New XWPFFootnote. + public XWPFFootnote CreateFootnote() + { + XWPFFootnotes footnotes = this.CreateFootnotes(); + + XWPFFootnote footnote = footnotes.CreateFootnote(); + return footnote; + } + /// + /// Remove the specified footnote if present. + /// + /// + /// + public bool RemoveFootnote(int pos) + { + if (null != footnotes) + { + return footnotes.RemoveFootnote(pos); + } + else + { + return false; + } + } + /** * remove a BodyElement from bodyElements array list * @param pos diff --git a/ooxml/XWPF/Usermodel/XWPFFootnote.cs b/ooxml/XWPF/Usermodel/XWPFFootnote.cs index 977c8e7a1..4ffa6e21e 100644 --- a/ooxml/XWPF/Usermodel/XWPFFootnote.cs +++ b/ooxml/XWPF/Usermodel/XWPFFootnote.cs @@ -249,7 +249,110 @@ public POIXMLDocumentPart Owner return footnotes; } } + public int Id + { + get + { + return this.ctFtnEdn.id; + } + } + public List GetParagraphs() + { + return paragraphs; + } + /** + * Appends a new {@link XWPFParagraph} to this footnote. + * + * @return The new {@link XWPFParagraph} + */ + public XWPFParagraph CreateParagraph() + { + XWPFParagraph p = new XWPFParagraph(this.ctFtnEdn.AddNewP(), this); + paragraphs.Add(p); + bodyElements.Add(p); + + // If the paragraph is the first paragraph in the footnote, + // ensure that it has a footnote reference run. + if (p.Equals(GetParagraphs()[0])) + { + EnsureFootnoteRef(p); + } + return p; + } + + /** + * Ensure that the specified paragraph has a reference marker for this + * footnote by adding a footnote reference if one is not found. + *

This method is for the first paragraph in the footnote, not + * paragraphs that will refer to the footnote. For references to + * the footnote, use {@link XWPFParagraph#addFootnoteReference(XWPFFootnote)}. + *

+ *

The first run of the first paragraph in a footnote should + * contain a {@link CTFtnEdnRef} object.

+ * + * @param p The {@link XWPFParagraph} to ensure + */ + public void EnsureFootnoteRef(XWPFParagraph p) + { + + XWPFRun r = null; + if (p.Runs.Count > 0) + { + r = p.Runs[0]; + } + if (r == null) + { + r = p.CreateRun(); + } + CT_R ctr = r.GetCTR(); + bool foundRef = false; + foreach (CT_FtnEdnRef reference in ctr.GetFootnoteReferenceList()) + { + if (Id.ToString().Equals(reference.id)) + { + foundRef = true; + break; + } + } + if (!foundRef) + { + ctr.AddNewRPr().AddNewRStyle().val="FootnoteReference"; + ctr.AddNewFootnoteRef(); + } + } + + /** + * Appends a new {@link XWPFTable} to this footnote + * + * @return The new {@link XWPFTable} + */ + public XWPFTable CreateTable() + { + XWPFTable table = new XWPFTable(ctFtnEdn.AddNewTbl(), this); + if (bodyElements.Count == 0) + { + XWPFParagraph p = CreateParagraph(); + EnsureFootnoteRef(p); + } + bodyElements.Add(table); + tables.Add(table); + return table; + } + + /** + * Appends a new {@link XWPFTable} to this footnote + * @param rows Number of rows to initialize the table with + * @param cols Number of columns to initialize the table with + * @return the new {@link XWPFTable} with the specified number of rows and columns + */ + public XWPFTable CreateTable(int rows, int cols) + { + XWPFTable table = new XWPFTable(ctFtnEdn.AddNewTbl(), this, rows, cols); + bodyElements.Add(table); + tables.Add(table); + return table; + } /** * * @param cursor diff --git a/ooxml/XWPF/Usermodel/XWPFFootnotes.cs b/ooxml/XWPF/Usermodel/XWPFFootnotes.cs index 01ed32009..4aba717ab 100644 --- a/ooxml/XWPF/Usermodel/XWPFFootnotes.cs +++ b/ooxml/XWPF/Usermodel/XWPFFootnotes.cs @@ -123,7 +123,7 @@ public List GetFootnotesList() public XWPFFootnote GetFootnoteById(int id) { foreach(XWPFFootnote note in listFootnote) { - if(note.GetCTFtnEdn().id == id.ToString()) + if(note.GetCTFtnEdn().id == id) return note; } return null; @@ -167,7 +167,44 @@ public void SetXWPFDocument(XWPFDocument doc) { document = doc; } + /// + /// Create a new footnote and add it to the document. + /// + /// + /// The new note will have one paragraph with the style "FootnoteText" + /// and one run containing the required footnote reference with the + /// style "FootnoteReference". + /// + /// New XWPFFootnote + public XWPFFootnote CreateFootnote() + { + CT_FtnEdn newNote = new CT_FtnEdn(); + newNote.type = ST_FtnEdn.normal; + + XWPFFootnote footnote = AddFootnote(newNote); + int id = ctFootnotes.SizeOfFootnoteArray; + footnote.GetCTFtnEdn().id = id; + return footnote; + } + /// + /// Remove the specified footnote if present. + /// + /// + /// + public bool RemoveFootnote(int pos) + { + if (ctFootnotes.SizeOfFootnoteArray >= pos - 1) + { + ctFootnotes.RemoveFootnote(pos); + listFootnote.RemoveAt(pos); + return true; + } + else + { + return false; + } + } /** * @see NPOI.XWPF.UserModel.IBody#getPart() */ @@ -182,6 +219,8 @@ public XWPFDocument GetXWPFDocument() return (XWPFDocument)GetParent(); } } + + }//end class diff --git a/ooxml/XWPF/Usermodel/XWPFParagraph.cs b/ooxml/XWPF/Usermodel/XWPFParagraph.cs index a3ee5349b..d5b393792 100644 --- a/ooxml/XWPF/Usermodel/XWPFParagraph.cs +++ b/ooxml/XWPF/Usermodel/XWPFParagraph.cs @@ -1647,6 +1647,19 @@ public XWPFHyperlinkRun CreateHyperlinkRun(string rId) iRuns.Add(xwpfRun); return xwpfRun; } + /// + /// Add a new run with a reference to the specified footnote. The footnote reference run will have the style name "FootnoteReference". + /// + /// Footnote to which to add a reference. + public void AddFootnoteReference(XWPFFootnote footnote) + { + XWPFRun run = CreateRun(); + CT_R ctRun = run.GetCTR(); + var rstyle=ctRun.AddNewRPr().AddNewRStyle(); + rstyle.val="FootnoteReference"; + var footnoteRef = ctRun.AddNewFootnoteReference(); + footnoteRef.id= footnote.Id.ToString(); + } } } \ No newline at end of file diff --git a/ooxml/XWPF/Usermodel/XWPFRun.cs b/ooxml/XWPF/Usermodel/XWPFRun.cs index 9cf6ee837..d91326240 100644 --- a/ooxml/XWPF/Usermodel/XWPFRun.cs +++ b/ooxml/XWPF/Usermodel/XWPFRun.cs @@ -279,7 +279,7 @@ public bool IsBold { get { - CT_RPr pr = run.rPr; + CT_RPr pr = GetRunProperties(false); if (pr == null || !pr.IsSetB()) { return false; @@ -288,7 +288,7 @@ public bool IsBold } set { - CT_RPr pr = run.IsSetRPr() ? run.rPr : run.AddNewRPr(); + CT_RPr pr = GetRunProperties(true); CT_OnOff bold = pr.IsSetB() ? pr.b : pr.AddNewB(); bold.val = value; } @@ -302,8 +302,8 @@ public String GetColor() String color = null; if (run.IsSetRPr()) { - CT_RPr pr = run.rPr; - if (pr.IsSetColor()) + CT_RPr pr = GetRunProperties(false); + if (pr!=null&&pr.IsSetColor()) { NPOI.OpenXmlFormats.Wordprocessing.CT_Color clr = pr.color; color = clr.val; //clr.xgetVal().getStringValue(); @@ -318,7 +318,7 @@ public String GetColor() */ public void SetColor(String rgbStr) { - CT_RPr pr = run.IsSetRPr() ? run.rPr : run.AddNewRPr(); + CT_RPr pr = GetRunProperties(true); NPOI.OpenXmlFormats.Wordprocessing.CT_Color color = pr.IsSetColor() ? pr.color : pr.AddNewColor(); color.val = (rgbStr); } @@ -386,14 +386,14 @@ public bool IsItalic { get { - CT_RPr pr = run.rPr; + CT_RPr pr = GetRunProperties(false); if (pr == null || !pr.IsSetI()) return false; return IsCTOnOff(pr.i); } set { - CT_RPr pr = run.IsSetRPr() ? run.rPr : run.AddNewRPr(); + CT_RPr pr = GetRunProperties(true); CT_OnOff italic = pr.IsSetI() ? pr.i : pr.AddNewI(); italic.val = value; } @@ -411,11 +411,36 @@ public UnderlinePatterns Underline { get { - CT_RPr pr = run.rPr; - return (pr != null && pr.IsSetU() && pr.u.val != null) ? - EnumConverter.ValueOf(pr.u.val) : UnderlinePatterns.None; + var value = UnderlinePatterns.None; + CT_Underline underline = GetCTUnderline(false); + if (underline != null) + { + ST_Underline baseValue = underline.val; + value = EnumConverter.ValueOf(baseValue); + } + return value; + } + set { + CT_Underline underline = GetCTUnderline(true); + underline.val = EnumConverter.ValueOf(value); } } + /** + * Get the CTUnderline for the run. + * @param create Create a new underline if necessary + * @return The underline, or null create is false and there is no underline. + */ + private CT_Underline GetCTUnderline(bool create) + { + CT_RPr pr = GetRunProperties(true); + CT_Underline underline = pr.u; + if (create && underline == null) + { + underline = pr.AddNewU(); + } + return underline; + } + internal void InsertText(CT_Text text, int textIndex) { run.GetTList().Insert(textIndex, text); @@ -526,24 +551,6 @@ public string Text return text.ToString(); } } - /** - * Specifies that the contents of this run.should be displayed along with an - * underline appearing directly below the character heigh - * If this element is not present, the default value is to leave the - * formatting applied at previous level in the style hierarchy. If this - * element is never applied in the style hierarchy, then an underline shall - * not be applied to the contents of this run. - * - * @param value - - * underline type - * @see UnderlinePatterns : all possible patterns that could be applied - */ - public void SetUnderline(UnderlinePatterns value) - { - CT_RPr pr = run.IsSetRPr() ? run.rPr : run.AddNewRPr(); - CT_Underline underline = (pr.u == null) ? pr.AddNewU() : pr.u; - underline.val = EnumConverter.ValueOf(value); - } /** * Specifies that the contents of this run.shall be displayed with a single @@ -1153,7 +1160,7 @@ XWPFPicture AddPicture(Stream pictureData, int pictureType, String filename, int prstGeom.prst = (ST_ShapeType.rect); prstGeom.AddNewAvLst(); - using (var ms = new MemoryStream()) + using (var ms = RecyclableMemory.GetStream()) { StreamWriter sw = new StreamWriter(ms); pic.Write(sw, "pic:pic"); @@ -1269,7 +1276,29 @@ static void preserveSpaces(CT_Text xs) xs.space = "preserve"; } } - + public String Lang + { + get + { + CT_RPr pr = GetRunProperties(false); + Object lang = pr == null || !pr.IsSetLang() ? null : pr.lang.val; + return (String)lang; + } + set { + CT_RPr pr = GetRunProperties(true); + CT_Language ctLang = pr.IsSetLang() ? pr.lang : pr.AddNewLang(); + ctLang.val = value; + } + } + protected CT_RPr GetRunProperties(bool create) + { + CT_RPr pr = run.IsSetRPr() ? run.rPr : null; + if (create && pr == null) + { + pr = run.AddNewRPr(); + } + return pr; + } /** * Returns the string version of the text, with tabs and * carriage returns in place of their xml equivalents. diff --git a/ooxml/XWPF/Usermodel/XWPFSDTContentCell.cs b/ooxml/XWPF/Usermodel/XWPFSDTContentCell.cs index d54fd4980..1074720fd 100644 --- a/ooxml/XWPF/Usermodel/XWPFSDTContentCell.cs +++ b/ooxml/XWPF/Usermodel/XWPFSDTContentCell.cs @@ -167,7 +167,6 @@ private bool IsStartToken(object cursor, String string1) //{ // return true; //} - return false; } diff --git a/ooxml/XWPF/Usermodel/XWPFStyles.cs b/ooxml/XWPF/Usermodel/XWPFStyles.cs index 0a063bf24..1f8145b52 100644 --- a/ooxml/XWPF/Usermodel/XWPFStyles.cs +++ b/ooxml/XWPF/Usermodel/XWPFStyles.cs @@ -35,7 +35,7 @@ public class XWPFStyles : POIXMLDocumentPart { private CT_Styles ctStyles; private List listStyle = new List(); - + public IReadOnlyList listOfStyles { get => listStyle; } private XWPFLatentStyles latentStyles; private XWPFDefaultRunStyle defaultRunStyle; private XWPFDefaultParagraphStyle defaultParaStyle; diff --git a/ooxml/XWPF/Usermodel/XWPFTable.cs b/ooxml/XWPF/Usermodel/XWPFTable.cs index 7c9941cd7..5b64de3d0 100644 --- a/ooxml/XWPF/Usermodel/XWPFTable.cs +++ b/ooxml/XWPF/Usermodel/XWPFTable.cs @@ -654,6 +654,58 @@ public int CellMarginRight } } + public string TableCaption + { + get + { + CT_TblPr tblPr = GetTrPr(); + if (tblPr.tblCaption != null) + return tblPr.tblCaption.val; + else + return string.Empty; + } + set + { + CT_TblPr tblPr = GetTrPr(); + if (tblPr.tblCaption == null) + { + CT_String caption = new CT_String(); + caption.val = value; + tblPr.tblCaption = caption; + } + else + { + tblPr.tblCaption.val = value; + } + } + } + + public string TableDescription + { + get + { + CT_TblPr tblPr = GetTrPr(); + if (tblPr.tblDescription != null) + return tblPr.tblDescription.val; + else + return string.Empty; + } + set + { + CT_TblPr tblPr = GetTrPr(); + if (tblPr.tblDescription == null) + { + CT_String desc = new CT_String(); + desc.val = value; + tblPr.tblDescription = desc; + } + else + { + tblPr.tblDescription.val = value; + } + } + } + public void SetCellMargins(int top, int left, int bottom, int right) { CT_TblPr tblPr = GetTrPr(); @@ -807,6 +859,7 @@ public XWPFTableRow GetRow(CT_Row row) } return null; } + }// end class } \ No newline at end of file diff --git a/ooxml/XWPF/Usermodel/XWPFTableRow.cs b/ooxml/XWPF/Usermodel/XWPFTableRow.cs index d20e1c212..c909079e4 100644 --- a/ooxml/XWPF/Usermodel/XWPFTableRow.cs +++ b/ooxml/XWPF/Usermodel/XWPFTableRow.cs @@ -107,7 +107,12 @@ public XWPFTableCell AddNewTableCell() tableCells.Add(tableCell); return tableCell; } - + public XWPFTableRow CloneRow() + { + XWPFTableRow clonedRow= new XWPFTableRow(ctRow.Copy(), this.table); + table.AddRow(clonedRow); + return clonedRow; + } /** * This element specifies the height of the current table row within the diff --git a/ooxml/packages.config b/ooxml/packages.config index d460d74a6..7e45f57f7 100644 --- a/ooxml/packages.config +++ b/ooxml/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/openxml4Net/Exceptions/InvalidFormatException.cs b/openxml4Net/Exceptions/InvalidFormatException.cs index 655b1ed91..bcee376ab 100644 --- a/openxml4Net/Exceptions/InvalidFormatException.cs +++ b/openxml4Net/Exceptions/InvalidFormatException.cs @@ -6,8 +6,6 @@ namespace NPOI.OpenXml4Net.Exceptions { public class InvalidFormatException:OpenXml4NetException { - private string p; - private InvalidFormatException ex; public InvalidFormatException(String message):base(message) { diff --git a/openxml4Net/Exceptions/OpenXML4NetException.cs b/openxml4Net/Exceptions/OpenXML4NetException.cs index 8a7a2a4a2..ae8ba25cd 100644 --- a/openxml4Net/Exceptions/OpenXML4NetException.cs +++ b/openxml4Net/Exceptions/OpenXML4NetException.cs @@ -5,9 +5,6 @@ namespace NPOI.OpenXml4Net { public class OpenXml4NetException : Exception { - private Exceptions.InvalidFormatException ex; - - public OpenXml4NetException(String msg) : base(msg) { diff --git a/openxml4Net/NPOI.OpenXml4Net.csproj b/openxml4Net/NPOI.OpenXml4Net.csproj index 3342421de..382ffe597 100644 --- a/openxml4Net/NPOI.OpenXml4Net.csproj +++ b/openxml4Net/NPOI.OpenXml4Net.csproj @@ -73,7 +73,7 @@ TRACE;HIDE_UNREACHABLE_CODE ..\solution\Lib\.net45\NPOI.OpenXml4Net.XML true - 1591 + 1591;1587;1570 pdbonly AnyCPU 7.3 diff --git a/openxml4Net/OPC/Internal/ContentType.cs b/openxml4Net/OPC/Internal/ContentType.cs index 507b265d6..ad5971c24 100644 --- a/openxml4Net/OPC/Internal/ContentType.cs +++ b/openxml4Net/OPC/Internal/ContentType.cs @@ -45,7 +45,6 @@ public class ContentType:IComparable /** * Parameters */ - Hashtable p; private Dictionary parameters; /** diff --git a/openxml4Net/OPC/PackagePart.cs b/openxml4Net/OPC/PackagePart.cs index ea7e7375e..75b0463ba 100644 --- a/openxml4Net/OPC/PackagePart.cs +++ b/openxml4Net/OPC/PackagePart.cs @@ -112,7 +112,15 @@ public abstract class PackagePart : RelationshipSource, IComparable { } - + /// + /// Check if the new part was already added before via PackagePart.addRelationship() + /// + /// to find the relationship for + /// The existing relationship, or null if there isn't yet one + public PackageRelationship FindExistingRelation(PackagePart packagePart) + { + return _relationships.FindExistingInternalRelation(packagePart); + } /** * Adds an external relationship to a part (except relationships part). * @@ -503,7 +511,7 @@ public PackagePart GetRelatedPart(PackageRelationship rel) { target = PackagingUriHelper.ParseUri(t.Substring(0, t.IndexOf('#')), UriKind.Absolute); } - catch (UriFormatException e) + catch (UriFormatException) { throw new InvalidFormatException("Invalid target URI: " + t); } diff --git a/openxml4Net/OPC/PackageRelationshipCollection.cs b/openxml4Net/OPC/PackageRelationshipCollection.cs index 087f2e001..417e44ba6 100644 --- a/openxml4Net/OPC/PackageRelationshipCollection.cs +++ b/openxml4Net/OPC/PackageRelationshipCollection.cs @@ -30,6 +30,10 @@ public class PackageRelationshipCollection : IEnumerator * Package relationships ordered by type. */ private SortedList relationshipsByType; + /** + * A lookup of internal relationships to avoid + */ + private SortedList internalRelationshipsByTargetName; /** * This relationshipPart. @@ -62,6 +66,7 @@ public PackageRelationshipCollection() { relationshipsByID = new SortedList(); relationshipsByType = new SortedList(new DuplicateComparer()); + internalRelationshipsByTargetName = new SortedList(); } class DuplicateComparer : IComparer { @@ -195,6 +200,10 @@ private static PackagePartName GetRelationshipPartName(PackagePart part) */ public void AddRelationship(PackageRelationship relPart) { + if (relPart == null || string.IsNullOrEmpty(relPart.Id)) + { + throw new ArgumentException("invalid relationship part/id"); + } relationshipsByID[relPart.Id] = relPart; relationshipsByType[relPart.RelationshipType] = relPart; } @@ -235,6 +244,10 @@ public void AddRelationship(PackageRelationship relPart) sourcePart, targetUri, targetMode, relationshipType, id); relationshipsByID[rel.Id] = rel; relationshipsByType[rel.RelationshipType] = rel; + if (targetMode == TargetMode.Internal) + { + internalRelationshipsByTargetName.Add(targetUri.OriginalString, rel); + } return rel; } @@ -257,6 +270,8 @@ public void RemoveRelationship(String id) if (relationshipsByType.Values[i] == rel) relationshipsByType.RemoveAt(i); } + + internalRelationshipsByTargetName.RemoveAt(internalRelationshipsByTargetName.IndexOfValue(rel)); } } } @@ -338,7 +353,7 @@ private void ParseRelationshipsPart(PackagePart relPart) // Check OPC compliance M4.1 rule bool fCorePropertiesRelationship = false; - ///xmlRelationshipsDoc.ChildNodes.GetEnumerator(); + //xmlRelationshipsDoc.ChildNodes.GetEnumerator(); XPathNavigator xpathnav = xmlRelationshipsDoc.CreateNavigator(); XmlNamespaceManager nsMgr = new XmlNamespaceManager(xpathnav.NameTable); nsMgr.AddNamespace("x", PackageNamespaces.RELATIONSHIPS); @@ -451,8 +466,15 @@ public void Clear() { relationshipsByID.Clear(); relationshipsByType.Clear(); + internalRelationshipsByTargetName.Clear(); + } + public PackageRelationship FindExistingInternalRelation(PackagePart packagePart) + { + var pn=packagePart.PartName.Name; + if (!internalRelationshipsByTargetName.ContainsKey(pn)) + return null; + return internalRelationshipsByTargetName[pn]; } - public override String ToString() { String str; diff --git a/openxml4Net/Properties/AssemblyInfo.cs b/openxml4Net/Properties/AssemblyInfo.cs index 429c9a8a4..eb6e36ed4 100644 --- a/openxml4Net/Properties/AssemblyInfo.cs +++ b/openxml4Net/Properties/AssemblyInfo.cs @@ -33,8 +33,8 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("2.5.5.0")] -[assembly: AssemblyFileVersion("2.5.5.0")] +[assembly: AssemblyVersion("2.6.0.0")] +[assembly: AssemblyFileVersion("2.6.0.0")] [assembly: AssemblyInformationalVersion("2.0.0.0")] #if NETSTANDARD2_1 || NETSTANDARD2_0 || NET40 [assembly: AllowPartiallyTrustedCallers] diff --git a/openxml4Net/Util/XmlHelper.cs b/openxml4Net/Util/XmlHelper.cs index d084f1b8d..c18f12cc8 100644 --- a/openxml4Net/Util/XmlHelper.cs +++ b/openxml4Net/Util/XmlHelper.cs @@ -176,7 +176,7 @@ public static double ReadDouble(XmlAttribute attr) else { double v; - if (double.TryParse(s, NumberStyles.Number, CultureInfo.InvariantCulture, out v)) + if (double.TryParse(s, NumberStyles.Number|NumberStyles.Float| NumberStyles.AllowExponent, CultureInfo.InvariantCulture, out v)) { return v; } @@ -312,9 +312,9 @@ public static void WriteAttribute(StreamWriter sw, string attributeName, bool va { WriteAttribute(sw, attributeName, value, true); } - public static void WriteAttribute(StreamWriter sw, string attributeName, bool value, bool writeIfBlank) + public static void WriteAttribute(StreamWriter sw, string attributeName, bool value, bool writeIfBlank, bool defaultValue = false) { - if (value == false && !writeIfBlank) + if (value == defaultValue && !writeIfBlank) return; WriteAttribute(sw, attributeName, value ? "1" : "0"); } @@ -339,13 +339,28 @@ public static void WriteAttribute(StreamWriter sw, string attributeName, int val { WriteAttribute(sw, attributeName, value, false); } + public static void WriteAttribute(StreamWriter sw, string attributeName, uint value, bool writeIfBlank) + { + if (value == 0 && !writeIfBlank) + return; + + WriteAttribute(sw, attributeName, value.ToString(CultureInfo.InvariantCulture)); + } + public static void WriteAttribute(StreamWriter sw, string attributeName, uint value) + { + WriteAttribute(sw, attributeName, value, false); + } public static void WriteAttribute(StreamWriter sw, string attributeName, string value) { WriteAttribute(sw, attributeName, value, false); } public static void WriteAttribute(StreamWriter sw, string attributeName, string value, bool writeIfBlank) { - if (string.IsNullOrEmpty(value) && !writeIfBlank) + WriteAttribute(sw, attributeName, value, writeIfBlank, string.Empty); + } + public static void WriteAttribute(StreamWriter sw, string attributeName, string value, bool writeIfBlank, string defaultValue) + { + if ((string.IsNullOrEmpty(value) || defaultValue.Equals(value)) && !writeIfBlank) return; sw.Write(string.Format(" {0}=\"{1}\"", attributeName, value == null ? string.Empty : EncodeXml(value))); } @@ -356,26 +371,22 @@ public static void WriteAttribute(StreamWriter sw, string attributeName, byte[] WriteAttribute(sw, attributeName, BitConverter.ToString(value).Replace("-", ""), false); } + public static void WriteAttribute(StreamWriter sw, string attributeName, uint value, uint defaultValue, bool writeIfBlank = false) { if(value != defaultValue) - WriteAttribute(sw, attributeName, (int)value, true); + WriteAttribute(sw, attributeName, value, true); else if(writeIfBlank) - WriteAttribute(sw, attributeName, (int)value, writeIfBlank); - } - public static void WriteAttribute(StreamWriter sw, string attributeName, uint value, bool writeIfBlank = false) - { - WriteAttribute(sw, attributeName, (int)value, writeIfBlank); + WriteAttribute(sw, attributeName, value, writeIfBlank); } public static void WriteAttribute(StreamWriter sw, string attributeName, DateTime? value) { if (value == null) return; - WriteAttribute(sw, attributeName, value.ToString(), false); - //how to write xsd:datetime data - throw new NotImplementedException(); + WriteAttribute(sw, attributeName, value.Value.ToString("yyyy-MM-ddTHH:mm:ss"), false); } + public static void LoadXmlSafe(XmlDocument xmlDoc, Stream stream) { XmlReaderSettings settings = new XmlReaderSettings(); diff --git a/openxml4Net/packages.config b/openxml4Net/packages.config index c8abe76cc..04ff7ff2c 100644 --- a/openxml4Net/packages.config +++ b/openxml4Net/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/testcases/main/HSSF/Model/TestFormulaParser.cs b/testcases/main/HSSF/Model/TestFormulaParser.cs index 69b655a8f..0ec96af3a 100644 --- a/testcases/main/HSSF/Model/TestFormulaParser.cs +++ b/testcases/main/HSSF/Model/TestFormulaParser.cs @@ -1239,9 +1239,9 @@ public void TestParseArray() Assert.AreEqual("{1,2,2,#REF!;FALSE,3,3,2}", ptgs[0].ToFormulaString()); ArrayPtg aptg = (ArrayPtg)ptgs[0]; - Object[][] values = aptg.GetTokenArrayValues(); - Assert.AreEqual(ErrorConstant.ValueOf(FormulaError.REF.Code), values[0][3]); - Assert.AreEqual(false, values[1][0]); + Object[,] values = aptg.GetTokenArrayValues(); + Assert.AreEqual(ErrorConstant.ValueOf(FormulaError.REF.Code), values[0,3]); + Assert.AreEqual(false, values[1,0]); } [Test] public void TestParseStringElementInArray() @@ -1249,7 +1249,7 @@ public void TestParseStringElementInArray() Ptg[] ptgs; ptgs = ParseFormula("MAX({\"5\"},3)"); ConfirmTokenClasses(ptgs, typeof(ArrayPtg), typeof(IntPtg), typeof(FuncVarPtg)); - object element = ((ArrayPtg)ptgs[0]).GetTokenArrayValues()[0][0]; + object element = ((ArrayPtg)ptgs[0]).GetTokenArrayValues()[0,0]; if (element is UnicodeString) { // this would cause ClassCastException below @@ -1290,14 +1290,14 @@ public void TestParseArrayNegativeElement() throw e; } ConfirmTokenClasses(ptgs, typeof(ArrayPtg)); - Object element = ((ArrayPtg)ptgs[0]).GetTokenArrayValues()[0][0]; + Object element = ((ArrayPtg)ptgs[0]).GetTokenArrayValues()[0,0]; Assert.AreEqual(-42.0, (Double)element, 0.0); // Should be able to handle whitespace between unary minus and digits (Excel // accepts this formula after presenting the user with a Confirmation dialog). ptgs = ParseFormula("{- 5}"); - element = ((ArrayPtg)ptgs[0]).GetTokenArrayValues()[0][0]; + element = ((ArrayPtg)ptgs[0]).GetTokenArrayValues()[0,0]; Assert.AreEqual(-5.0, (Double)element, 0.0); } [Test] diff --git a/testcases/main/HSSF/Record/TestNameRecord.cs b/testcases/main/HSSF/Record/TestNameRecord.cs index 1e64d0d4f..332350090 100644 --- a/testcases/main/HSSF/Record/TestNameRecord.cs +++ b/testcases/main/HSSF/Record/TestNameRecord.cs @@ -698,9 +698,9 @@ private void assert_bug50244(NameRecord nr) ArrayPtg arr = (ArrayPtg)ptg[0]; Assert.AreEqual(696, arr.RowCount); Assert.AreEqual(1, arr.ColumnCount); - Object[][] vals = arr.GetTokenArrayValues(); - Assert.AreEqual("1.T20.001", vals[0][0]); - Assert.AreEqual("1.T20.010", vals[vals.Length - 1][0]); + Object[,] vals = arr.GetTokenArrayValues(); + Assert.AreEqual("1.T20.001", vals[0,0]); + Assert.AreEqual("1.T20.010", vals[vals.Length - 1,0]); } [Test] public void TestBug57923() diff --git a/testcases/main/HSSF/UserModel/TestBugs.cs b/testcases/main/HSSF/UserModel/TestBugs.cs index be176cd74..1c6ed5e6c 100644 --- a/testcases/main/HSSF/UserModel/TestBugs.cs +++ b/testcases/main/HSSF/UserModel/TestBugs.cs @@ -3485,5 +3485,33 @@ public void Test53564() //fos.Close(); wb.Close(); } + + + // follow https://svn.apache.org/viewvc?view=revision&revision=1896552 to write a unit test for this fix. + [Test] + public void Test52447() + { + IWorkbook wb=null; + try + { + wb = HSSFTestDataSamples.OpenSampleWorkbook("52447.xls"); + } catch { + Assert.IsNotNull(wb); + } + } + + [Test] + public void TestAmazonDownloadFile() + { + IWorkbook wb = null; + try + { + wb = HSSFTestDataSamples.OpenSampleWorkbook("ca_apparel_browse_tree_guide._TTH_.xls"); + } + catch + { + Assert.IsNotNull(wb); + } + } } } \ No newline at end of file diff --git a/testcases/main/HSSF/UserModel/TestDataValidation.cs b/testcases/main/HSSF/UserModel/TestDataValidation.cs index 62b2c8f8d..428f97078 100644 --- a/testcases/main/HSSF/UserModel/TestDataValidation.cs +++ b/testcases/main/HSSF/UserModel/TestDataValidation.cs @@ -50,7 +50,7 @@ public void AssertDataValidation(IWorkbook wb) MemoryStream baos = new MemoryStream(22000); try { - wb.Write(baos); + wb.Write(baos, false); baos.Close(); } catch (IOException e) @@ -165,7 +165,7 @@ public void TestAddToExistingSheet() MemoryStream baos = new MemoryStream(); try { - wb.Write(baos); + wb.Write(baos, false); } catch (IOException e) { diff --git a/testcases/main/HSSF/UserModel/TestHSSFDateUtil.cs b/testcases/main/HSSF/UserModel/TestHSSFDateUtil.cs index 527d242ab..f17393232 100644 --- a/testcases/main/HSSF/UserModel/TestHSSFDateUtil.cs +++ b/testcases/main/HSSF/UserModel/TestHSSFDateUtil.cs @@ -489,7 +489,7 @@ public void AbsoluteDayYearTooLow() HSSFDateUtil.AbsoluteDay(calendar, false); Assert.Fail("Should fail here"); } - catch (ArgumentException e) + catch (ArgumentException ) { // expected here } @@ -500,7 +500,7 @@ public void AbsoluteDayYearTooLow() HSSFDateUtil.AbsoluteDay(calendar, true); Assert.Fail("Should fail here"); } - catch (ArgumentException e) + catch (ArgumentException ) { // expected here } diff --git a/testcases/main/HSSF/UserModel/TestHSSFSheet.cs b/testcases/main/HSSF/UserModel/TestHSSFSheet.cs index 856723e3c..e9ee8f5d3 100644 --- a/testcases/main/HSSF/UserModel/TestHSSFSheet.cs +++ b/testcases/main/HSSF/UserModel/TestHSSFSheet.cs @@ -696,9 +696,8 @@ public void TestTopRow() /** cell with formula becomes null on cloning a sheet*/ [Test] - public new void Test35084() + public void Test35084() { - HSSFWorkbook wb = new HSSFWorkbook(); NPOI.SS.UserModel.ISheet s = wb.CreateSheet("Sheet1"); IRow r = s.CreateRow(0); @@ -1066,18 +1065,15 @@ public void TestLongSheetNames() HSSFWorkbook wb = new HSSFWorkbook(); String SAME_PREFIX = "A123456789B123456789C123456789"; // 30 chars - wb.CreateSheet(SAME_PREFIX + "Dxxxx"); try { wb.CreateSheet(SAME_PREFIX + "Dyyyy"); // identical up to the 32nd char - throw new AssertionException("Expected exception not thrown"); + Assert.Fail("Expected exception not thrown"); } catch (ArgumentException e) { - Assert.AreEqual("The workbook already contains a sheet named 'A123456789B123456789C123456789Dyyyy'", e.Message); + Assert.IsTrue(e.Message.StartsWith("sheetName 'A123456789B123456789C123456789Dyyyy' is invalid")); } - wb.CreateSheet(SAME_PREFIX + "Exxxx"); // OK - differs in the 31st char - wb.Close(); } /** diff --git a/testcases/main/HSSF/UserModel/TestHSSFWorkbook.cs b/testcases/main/HSSF/UserModel/TestHSSFWorkbook.cs index 70100b06e..1837bb22f 100644 --- a/testcases/main/HSSF/UserModel/TestHSSFWorkbook.cs +++ b/testcases/main/HSSF/UserModel/TestHSSFWorkbook.cs @@ -657,7 +657,7 @@ public void Bug47920() ClassID clsid1 = fs1.Root.StorageClsid; MemoryStream out1 = new MemoryStream(4096); - wb.Write(out1); + wb.Write(out1, false); byte[] bytes = out1.ToArray(); POIFSFileSystem fs2 = new POIFSFileSystem(new MemoryStream(bytes)); ClassID clsid2 = fs2.Root.StorageClsid; @@ -1173,7 +1173,7 @@ public void Bug54500() Assert.AreEqual("ASheet!A1", name.RefersToFormula); MemoryStream stream = new MemoryStream(); - wb.Write(stream); + wb.Write(stream, false); assertSheetOrder(wb, "Sheet1", "Sheet2", "Sheet3", "ASheet"); Assert.AreEqual("ASheet!A1", name.RefersToFormula); @@ -1184,7 +1184,7 @@ public void Bug54500() Assert.AreEqual("ASheet!A1", name.RefersToFormula); MemoryStream stream2 = new MemoryStream(); - wb.Write(stream2); + wb.Write(stream2, false); assertSheetOrder(wb, "Sheet1", "Sheet3", "ASheet"); Assert.AreEqual("ASheet!A1", name.RefersToFormula); @@ -1295,7 +1295,7 @@ public void TestRewriteFileBug58480() private void WriteAndCloseWorkbook(IWorkbook workbook, FileInfo file) { ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); - workbook.Write(bytesOut); + workbook.Write(bytesOut, false); workbook.Close(); byte[] byteArray = bytesOut.ToByteArray(); @@ -1359,7 +1359,7 @@ public void InvalidInPlaceWrite() wb.Write(); Assert.Fail("Shouldn't work for new files"); } - catch (InvalidOperationException e) { } + catch (InvalidOperationException) { } // Can't work for InputStream opened files wb = new HSSFWorkbook( @@ -1369,7 +1369,7 @@ public void InvalidInPlaceWrite() wb.Write(); Assert.Fail("Shouldn't work for InputStream"); } - catch (InvalidOperationException e) { } + catch (InvalidOperationException) { } // Can't work for OPOIFS OPOIFSFileSystem ofs = new OPOIFSFileSystem( @@ -1380,7 +1380,7 @@ public void InvalidInPlaceWrite() wb.Write(); Assert.Fail("Shouldn't work for OPOIFSFileSystem"); } - catch (InvalidOperationException e) { } + catch (InvalidOperationException) { } // Can't work for Read-Only files NPOIFSFileSystem fs = new NPOIFSFileSystem( @@ -1391,7 +1391,7 @@ public void InvalidInPlaceWrite() wb.Write(); Assert.Fail("Shouldn't work for Read Only"); } - catch (InvalidOperationException e) { } + catch (InvalidOperationException) { } } [Test] diff --git a/testcases/main/HSSF/UserModel/TestMatrixFormulasFromBinarySpreadsheet.cs b/testcases/main/HSSF/UserModel/TestMatrixFormulasFromBinarySpreadsheet.cs new file mode 100644 index 000000000..3081a048d --- /dev/null +++ b/testcases/main/HSSF/UserModel/TestMatrixFormulasFromBinarySpreadsheet.cs @@ -0,0 +1,187 @@ +using NPOI.HSSF.UserModel; +using NPOI.SS.Formula.Eval; +using NPOI.SS.UserModel; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Text; + +namespace TestCases.HSSF.UserModel +{ + [TestFixture] + public class TestMatrixFormulasFromBinarySpreadsheet + { + private static HSSFWorkbook workbook; + private static ISheet sheet; + private static IFormulaEvaluator evaluator; + + private static class Navigator + { + /** + * Name of the test spreadsheet (found in the standard test data folder) + */ + public const String FILENAME = "MatrixFormulaEvalTestData.xls"; + /** + * Row (zero-based) in the spreadsheet where operations start + */ + public const int START_OPERATORS_ROW_INDEX = 1; + /** + * Column (zero-based) in the spreadsheet where operations start + */ + public const int START_OPERATORS_COL_INDEX = 0; + /** + * Column (zero-based) in the spreadsheet where evaluations start + */ + public const int START_RESULT_COL_INDEX = 7; + /** + * Column separation in the spreadsheet between evaluations and expected results + */ + public const int COL_OFF_EXPECTED_RESULT = 3; + /** + * Row separation in the spreadsheet between operations + */ + public const int ROW_OFF_NEXT_OP = 4; + /** + * Used to indicate when there are no more operations left + */ + public const String END_OF_TESTS = ""; + + } + + + public static List data() + { + // Function "Text" uses custom-formats which are locale specific + // can't set the locale on a per-testrun execution, as some settings have been + // already set, when we would try to change the locale by then + + workbook = HSSFTestDataSamples.OpenSampleWorkbook(Navigator.FILENAME); + sheet = workbook.GetSheetAt(0); + evaluator = new HSSFFormulaEvaluator(workbook); + + List data = new List(); + + processFunctionGroup(data, Navigator.START_OPERATORS_ROW_INDEX, null); + + return data; + } + /** + * @param startRowIndex row index in the spreadsheet where the first function/operator is found + * @param testFocusFunctionName name of a single function/operator to test alone. + * Typically pass null to test all functions + */ + private static void processFunctionGroup(List data, int startRowIndex, String testFocusFunctionName) + { + for (int rowIndex = startRowIndex; true; rowIndex += Navigator.ROW_OFF_NEXT_OP) + { + IRow r = sheet.GetRow(rowIndex); + String targetFunctionName = getTargetFunctionName(r); + Assert.IsNotNull("Test spreadsheet cell empty on row (" + + (rowIndex) + "). Expected function name or '" + + Navigator.END_OF_TESTS + "'", targetFunctionName); + if (targetFunctionName.Equals(Navigator.END_OF_TESTS)) + { + // found end of functions list + break; + } + if (testFocusFunctionName == null || targetFunctionName.Equals(testFocusFunctionName, StringComparison.InvariantCultureIgnoreCase)) + { + data.Add(new Object[] { targetFunctionName, rowIndex }); + } + } + } + [TestCaseSource(nameof(data))] + public void processFunctionRow(String targetFunctionName, int formulasRowIdx) + { + int endColNum = Navigator.START_RESULT_COL_INDEX + Navigator.COL_OFF_EXPECTED_RESULT; + + for (int rowNum = formulasRowIdx; rowNum < formulasRowIdx + Navigator.ROW_OFF_NEXT_OP - 1; rowNum++) + { + for (int colNum = Navigator.START_RESULT_COL_INDEX; colNum < endColNum; colNum++) + { + IRow r = sheet.GetRow(rowNum); + + /* mainly to escape row failures on MDETERM which only returns a scalar */ + if (r == null) + { + continue; + } + + ICell c = sheet.GetRow(rowNum).GetCell(colNum); + + if (c == null || c.CellType != CellType.Formula) + { + continue; + } + + CellValue actValue = evaluator.Evaluate(c); + ICell expValue = sheet.GetRow(rowNum).GetCell(colNum + Navigator.COL_OFF_EXPECTED_RESULT); + + String msg = String.Format("Function '{0}': Formula: {1} @ {2}:{3}" + , targetFunctionName, c.CellFormula, rowNum, colNum); + + Assert.IsNotNull(expValue, msg + " - Bad setup data expected value is null"); + Assert.IsNotNull(actValue, msg + " - actual value was null"); + + CellType cellType = expValue.CellType; + switch (cellType) + { + case CellType.Blank: + Assert.AreEqual(CellType.Blank, actValue.CellType, msg); + break; + case CellType.Boolean: + Assert.AreEqual(CellType.Boolean, actValue.CellType, msg); + Assert.AreEqual(expValue.BooleanCellValue, actValue.BooleanValue, msg); + break; + case CellType.Error: + Assert.AreEqual(CellType.Error, actValue.CellType, msg); + Assert.AreEqual(ErrorEval.GetText(expValue.ErrorCellValue), ErrorEval.GetText(actValue.ErrorValue), msg); + break; + case CellType.Formula: // will never be used, since we will call method after formula evaluation + Assert.Fail("Cannot expect formula as result of formula evaluation: " + msg); + break; + case CellType.Numeric: + Assert.AreEqual(CellType.Numeric, actValue.CellType, msg); + Assert.AreEqual(expValue.NumericCellValue, actValue.NumberValue, msg); + break; + case CellType.String: + Assert.AreEqual(CellType.String, actValue.CellType, msg); + Assert.AreEqual(expValue.RichStringCellValue.String, actValue.StringValue, msg); + break; + default: + Assert.Fail("Unexpected cell type: " + cellType); + break; + } + } + } + } + /** + * @return null if cell is missing, empty or Blank + */ + private static String getTargetFunctionName(IRow r) + { + if (r == null) + { + Assert.Warn("Warning - given null row, can't figure out function name"); + return null; + } + ICell cell = r.GetCell(Navigator.START_OPERATORS_COL_INDEX); + //Assert.Warn(Navigator.START_OPERATORS_COL_INDEX.ToString()); + if (cell == null) + { + Assert.Warn("Warning - Row " + r.RowNum + " has no cell " + Navigator.START_OPERATORS_COL_INDEX + ", can't figure out function name"); + return null; + } + if (cell.CellType == CellType.Blank) + { + return null; + } + if (cell.CellType == CellType.String) + { + return cell.RichStringCellValue.String; + } + throw new AssertionException("Bad cell type for 'function name' column: (" + + cell.CellType + ") row (" + (r.RowNum + 1) + ")"); + } + } +} \ No newline at end of file diff --git a/testcases/main/HSSF/UserModel/TestOLE2Embeding.cs b/testcases/main/HSSF/UserModel/TestOLE2Embeding.cs index b779df846..58f4e8c9f 100644 --- a/testcases/main/HSSF/UserModel/TestOLE2Embeding.cs +++ b/testcases/main/HSSF/UserModel/TestOLE2Embeding.cs @@ -157,7 +157,7 @@ static POIFSFileSystem GetSampleXLS() sheet.CreateRow(5).CreateCell(2).SetCellValue("yo dawg i herd you like embeddet objekts, so we Put a ole in your ole so you can save a file while you save a file"); MemoryStream bos = new MemoryStream(); - wb.Write(bos); + wb.Write(bos, false); wb.Close(); POIFSFileSystem poifs = new POIFSFileSystem(new MemoryStream(bos.ToArray())); diff --git a/testcases/main/NPOI.TestCases.csproj b/testcases/main/NPOI.TestCases.csproj index d14f69665..fb70238e5 100644 --- a/testcases/main/NPOI.TestCases.csproj +++ b/testcases/main/NPOI.TestCases.csproj @@ -245,6 +245,7 @@ + @@ -718,8 +719,11 @@ 3.13.1 + + 4.2.1 + - 1.3.2 + 1.3.3
diff --git a/testcases/main/POIFS/Crypt/TestCipherAlgorithm.cs b/testcases/main/POIFS/Crypt/TestCipherAlgorithm.cs index 4b9f5a3ba..54588e53b 100644 --- a/testcases/main/POIFS/Crypt/TestCipherAlgorithm.cs +++ b/testcases/main/POIFS/Crypt/TestCipherAlgorithm.cs @@ -26,7 +26,7 @@ public void Test() CipherAlgorithm.FromEcmaId(0); Assert.Fail("Should throw exception"); } - catch (EncryptedDocumentException e) + catch (EncryptedDocumentException) { // expected } @@ -36,7 +36,7 @@ public void Test() CipherAlgorithm.FromXmlId("AES", 1); Assert.Fail("Should throw exception"); } - catch (EncryptedDocumentException e) + catch (EncryptedDocumentException) { // expected } @@ -46,7 +46,7 @@ public void Test() CipherAlgorithm.FromXmlId("RC1", 0x40); Assert.Fail("Should throw exception"); } - catch (EncryptedDocumentException e) + catch (EncryptedDocumentException) { // expected } diff --git a/testcases/main/SS/Format/TestCellFormatResult.cs b/testcases/main/SS/Format/TestCellFormatResult.cs index a9ee94c2f..c94628772 100644 --- a/testcases/main/SS/Format/TestCellFormatResult.cs +++ b/testcases/main/SS/Format/TestCellFormatResult.cs @@ -36,7 +36,7 @@ public void TestNullTextRaisesException() CellFormatResult result = new CellFormatResult(applies, text, textColor); Assert.Fail("Cannot Initialize CellFormatResult with null text parameter"); } - catch (ArgumentException e) + catch (ArgumentException ) { //Expected } diff --git a/testcases/main/SS/Formula/Atp/TestXMatchFunction.cs b/testcases/main/SS/Formula/Atp/TestXMatchFunction.cs new file mode 100644 index 000000000..71214fcff --- /dev/null +++ b/testcases/main/SS/Formula/Atp/TestXMatchFunction.cs @@ -0,0 +1,119 @@ +using NPOI.HSSF.UserModel; +using NPOI.SS.UserModel; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Text; + +namespace TestCases.SS.Formula.Atp +{ + [TestFixture] + public class TestXMatchFunction + { + [Test] + public void TestMicrosoftExample0() + { + HSSFWorkbook wb = initNumWorkbook("Grape"); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + ICell cell = wb.GetSheetAt(0).GetRow(2).CreateCell(5); + Util.Utils.AssertDouble(fe, cell, "XMATCH(E3,C3:C7)", 2); + Util.Utils.AssertError(fe, cell, "XMATCH(\"Gra\",C3:C7)", FormulaError.NA); + } + + [Test] + public void TestMicrosoftExample1() + { + HSSFWorkbook wb = initNumWorkbook("Gra"); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + ICell cell = wb.GetSheetAt(0).GetRow(2).CreateCell(5); + Util.Utils.AssertDouble(fe, cell, "XMATCH(E3,C3:C7,1)", 2); + Util.Utils.AssertDouble(fe, cell, "XMATCH(E3,C3:C7,-1)", 5); + Util.Utils.AssertDouble(fe, cell, "XMATCH(\"Gra\",C3:C7,1)", 2); + Util.Utils.AssertDouble(fe, cell, "XMATCH(\"Graz\",C3:C7,1)", 3); + Util.Utils.AssertDouble(fe, cell, "XMATCH(\"Graz\",C3:C7,-1)", 2); + } + + [Test] + public void TestMicrosoftExample2() + { + //the result in this example is correct but the description seems wrong from my testing + //the result is based on the position and not a count + HSSFWorkbook wb = initWorkbook2(); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + ICell cell = wb.GetSheetAt(0).GetRow(3).CreateCell(5); + Util.Utils.AssertDouble(fe, cell, "XMATCH(F2,C3:C9,1)", 4); + Util.Utils.AssertDouble(fe, cell, "XMATCH(F2,C3:C9,-1)", 5); + Util.Utils.AssertError(fe, cell, "XMATCH(F2,C3:C9,2)", FormulaError.NA); + //Util.Utils.AssertDouble(fe, cell, "XMATCH(35000,C3:C9,1)", 2); + //Util.Utils.AssertDouble(fe, cell, "XMATCH(36000,C3:C9,1)", 1); + } + + [Test] + public void TestMicrosoftExample3() + { + HSSFWorkbook wb = initWorkbook3(); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + ICell cell = wb.GetSheetAt(0).GetRow(2).CreateCell(3); + Util.Utils.AssertDouble(fe, cell, "INDEX(C6:E12,XMATCH(B3,B6:B12),XMATCH(C3,C5:E5))", 8492); + + } + + [Test] + public void TestMicrosoftExample4() + { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + ICell cell = wb.CreateSheet().CreateRow(0).CreateCell(0); + Util.Utils.AssertDouble(fe, cell, "XMATCH(4,{5,4,3,2,1})", 2); + Util.Utils.AssertDouble(fe, cell, "XMATCH(4.5,{5,4,3,2,1},1)", 1); + } + private HSSFWorkbook initNumWorkbook(String lookup) + { + HSSFWorkbook wb = new HSSFWorkbook(); + ISheet sheet = wb.CreateSheet(); + SS.Util.Utils.AddRow(sheet, 0); + SS.Util.Utils.AddRow(sheet, 1, null, null, "Product", null, "Product", "Position"); + SS.Util.Utils.AddRow(sheet, 2, null, null, "Apple", null, lookup); + SS.Util.Utils.AddRow(sheet, 3, null, null, "Grape"); + SS.Util.Utils.AddRow(sheet, 4, null, null, "Pear"); + SS.Util.Utils.AddRow(sheet, 5, null, null, "Banana"); + SS.Util.Utils.AddRow(sheet, 6, null, null, "Cherry"); + return wb; + } + + private HSSFWorkbook initWorkbook2() + { + HSSFWorkbook wb = new HSSFWorkbook(); + ISheet sheet = wb.CreateSheet(); + SS.Util.Utils.AddRow(sheet, 0); + SS.Util.Utils.AddRow(sheet, 1, null, "Sales Rep", "Total Sales", null, "Bonus", 15000); + SS.Util.Utils.AddRow(sheet, 2, null, "Michael Neipper", 42000); + SS.Util.Utils.AddRow(sheet, 3, null, "Jan Kotas", 35000); + SS.Util.Utils.AddRow(sheet, 4, null, "Nancy Freehafer", 25000); + SS.Util.Utils.AddRow(sheet, 5, null, "Andrew Cencini", 15901); + SS.Util.Utils.AddRow(sheet, 6, null, "Anne Hellung-Larsen", 13801); + SS.Util.Utils.AddRow(sheet, 7, null, "Nancy Freehafer", 12181); + SS.Util.Utils.AddRow(sheet, 8, null, "Mariya Sergienko", 9201); + return wb; + } + + private HSSFWorkbook initWorkbook3() + { + HSSFWorkbook wb = new HSSFWorkbook(); + ISheet sheet = wb.CreateSheet(); + SS.Util.Utils.AddRow(sheet, 0); + SS.Util.Utils.AddRow(sheet, 1, null, "Sales Rep", "Month", "Total"); + SS.Util.Utils.AddRow(sheet, 2, null, "Andrew Cencini", "Feb"); + SS.Util.Utils.AddRow(sheet, 3); + SS.Util.Utils.AddRow(sheet, 4, null, "Sales Rep", "Jan", "Feb", "Mar"); + SS.Util.Utils.AddRow(sheet, 5, null, "Michael Neipper", 3174, 6804, 4713); + SS.Util.Utils.AddRow(sheet, 6, null, "Jan Kotas", 1656, 8643, 3445); + SS.Util.Utils.AddRow(sheet, 7, null, "Nancy Freehafer", 2706, 2310, 6606); + SS.Util.Utils.AddRow(sheet, 8, null, "Andrew Cencini", 4930, 8492, 4474); + SS.Util.Utils.AddRow(sheet, 9, null, "Anne Hellung-Larsen", 6394, 9846, 4368); + SS.Util.Utils.AddRow(sheet, 10, null, "Nancy Freehafer", 2539, 8996, 4084); + SS.Util.Utils.AddRow(sheet, 11, null, "Mariya Sergienko", 4468, 5206, 7343); + return wb; + } + } +} \ No newline at end of file diff --git a/testcases/main/SS/Formula/Eval/TestFormulaBugs.cs b/testcases/main/SS/Formula/Eval/TestFormulaBugs.cs index 40d32c9e1..31262899a 100644 --- a/testcases/main/SS/Formula/Eval/TestFormulaBugs.cs +++ b/testcases/main/SS/Formula/Eval/TestFormulaBugs.cs @@ -96,7 +96,7 @@ public void Test27405() try { FileStream fileOut = new FileStream("27405output.xls", FileMode.Create); - wb.Write(fileOut); + wb.Write(fileOut, false); fileOut.Close(); } catch (IOException e) diff --git a/testcases/main/SS/Formula/Eval/TestMissingArgEval.cs b/testcases/main/SS/Formula/Eval/TestMissingArgEval.cs index 11fd5a46c..93be65f8e 100644 --- a/testcases/main/SS/Formula/Eval/TestMissingArgEval.cs +++ b/testcases/main/SS/Formula/Eval/TestMissingArgEval.cs @@ -60,6 +60,65 @@ public void TestEvaluateMissingArgs() Assert.AreEqual("abc", fe.Evaluate(cell).StringValue); } [Test] + public void TestCompareMissingArgs() + { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + ISheet sheet = wb.CreateSheet("Sheet1"); + ICell cell = sheet.CreateRow(0).CreateCell(0); + + cell.SetCellFormula("iferror(0/0,)<0"); + fe.ClearAllCachedResultValues(); + CellValue cv = fe.Evaluate(cell); + Assert.IsFalse(cv.BooleanValue); + + cell.SetCellFormula("iferror(0/0,)<=0"); + fe.ClearAllCachedResultValues(); + cv = fe.Evaluate(cell); + Assert.IsTrue(cv.BooleanValue); + + cell.SetCellFormula("iferror(0/0,)=0"); + fe.ClearAllCachedResultValues(); + cv = fe.Evaluate(cell); + Assert.IsTrue(cv.BooleanValue); + + cell.SetCellFormula("iferror(0/0,)>=0"); + fe.ClearAllCachedResultValues(); + cv = fe.Evaluate(cell); + Assert.IsTrue(cv.BooleanValue); + + cell.SetCellFormula("iferror(0/0,)>0"); + fe.ClearAllCachedResultValues(); + cv = fe.Evaluate(cell); + Assert.IsFalse(cv.BooleanValue); + + // invert above for code coverage + cell.SetCellFormula("0=iferror(0/0,)"); + fe.ClearAllCachedResultValues(); + cv = fe.Evaluate(cell); + Assert.IsTrue(cv.BooleanValue); + + cell.SetCellFormula("0>iferror(0/0,)"); + fe.ClearAllCachedResultValues(); + cv = fe.Evaluate(cell); + Assert.IsFalse(cv.BooleanValue); + } + [Test] public void TestCountFuncs() { HSSFWorkbook wb = new HSSFWorkbook(); diff --git a/testcases/main/SS/Formula/Functions/TestAreas.cs b/testcases/main/SS/Formula/Functions/TestAreas.cs new file mode 100644 index 000000000..a139cc093 --- /dev/null +++ b/testcases/main/SS/Formula/Functions/TestAreas.cs @@ -0,0 +1,45 @@ +using NPOI.HSSF.UserModel; +using NPOI.SS.UserModel; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Text; + +namespace TestCases.SS.Formula.Functions +{ + [TestFixture] + public class TestAreas + { + [Test] + public void TestBasic() + { + HSSFWorkbook wb = new HSSFWorkbook(); + ICell cell = wb.CreateSheet().CreateRow(0).CreateCell(0); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + + String formulaText = "AREAS(B1)"; + confirmResult(fe, cell, formulaText, 1.0); + + formulaText = "AREAS(B2:D4)"; + confirmResult(fe, cell, formulaText, 1.0); + + formulaText = "AREAS((B2:D4,E5,F6:I9))"; + confirmResult(fe, cell, formulaText, 3.0); + + formulaText = "AREAS((B2:D4,E5,C3,E4))"; + confirmResult(fe, cell, formulaText, 4.0); + + formulaText = "AREAS((I9))"; + confirmResult(fe, cell, formulaText, 1.0); + } + + private static void confirmResult(HSSFFormulaEvaluator fe, ICell cell, String formulaText, Double expectedResult) + { + cell.SetCellFormula(formulaText); + fe.NotifyUpdateCell(cell); + CellValue result = fe.Evaluate(cell); + Assert.AreEqual(CellType.Numeric,result.CellType); + Assert.AreEqual(expectedResult, result.NumberValue); + } + } +} diff --git a/testcases/main/SS/Formula/Functions/TestBesselJ.cs b/testcases/main/SS/Formula/Functions/TestBesselJ.cs new file mode 100644 index 000000000..0ffa03526 --- /dev/null +++ b/testcases/main/SS/Formula/Functions/TestBesselJ.cs @@ -0,0 +1,72 @@ +using NPOI.HSSF.UserModel; +using NPOI.SS.Formula; +using NPOI.SS.Formula.Eval; +using NPOI.SS.Formula.Functions; +using NPOI.SS.UserModel; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Text; + +namespace TestCases.SS.Formula.Functions +{ + [TestFixture] + public class TestBesselJ + { + private static OperationEvaluationContext ec = new OperationEvaluationContext(null, null, 0, 0, 0, null); + + [Test] + public void TestInvalid() + { + confirmInvalidError("A1", "B2"); + } + + [Test] + public void TestNumError() + { + confirmNumError("22.5", "-40"); + } + + //https://support.microsoft.com/en-us/office/besselj-function-839cb181-48de-408b-9d80-bd02982d94f7 + [Test] + public void TestMicrosoftExample1() + { + HSSFWorkbook wb = new HSSFWorkbook(); + ISheet sheet = wb.CreateSheet(); + IRow row = sheet.CreateRow(0); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + ICell cell = row.CreateCell(0); + //this tolerance is too high but commons-math3 and excel don't match up as closely as we'd like + double tolerance = 0.000001; + SS.Util.Utils.AssertDouble(fe, cell, "BESSELJ(1.9, 2)", 0.329925829, tolerance); + SS.Util.Utils.AssertDouble(fe, cell, "BESSELJ(1.9, 2.5)", 0.329925829, tolerance); + } + + private static ValueEval invokeValue(String number1, String number2) + { + ValueEval[] args = new ValueEval[] { new StringEval(number1), new StringEval(number2) }; + return BesselJ.instance.Evaluate(args, ec); + } + + private static void confirmValue(String number1, String number2, double expected) + { + ValueEval result = invokeValue(number1, number2); + Assert.IsTrue(result is NumberEval); + Assert.AreEqual(expected, ((NumberEval)result).NumberValue, 0.00000000000001); + } + + private static void confirmInvalidError(String number1, String number2) + { + ValueEval result = invokeValue(number1, number2); + Assert.IsTrue(result is ErrorEval); + Assert.AreEqual(ErrorEval.VALUE_INVALID, result); + } + + private static void confirmNumError(String number1, String number2) + { + ValueEval result = invokeValue(number1, number2); + Assert.IsTrue(result is ErrorEval); + Assert.AreEqual(ErrorEval.NUM_ERROR, result); + } + } +} diff --git a/testcases/main/SS/Formula/Functions/TestDateValue.cs b/testcases/main/SS/Formula/Functions/TestDateValue.cs new file mode 100644 index 000000000..db15e13b3 --- /dev/null +++ b/testcases/main/SS/Formula/Functions/TestDateValue.cs @@ -0,0 +1,59 @@ +using NPOI.SS.Formula.Eval; +using NPOI.SS.Formula.Functions; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Text; + +namespace TestCases.SS.Formula.Functions +{ + [TestFixture] + public class TestDateValue + { + private ValueEval invokeDateValue(ValueEval text) + { + return new DateValue().Evaluate(0, 0, text); + } + + private void confirmDateValue(ValueEval text, double expected) + { + ValueEval result = invokeDateValue(text); + Assert.IsTrue(result is NumberEval); + Assert.AreEqual(expected, ((NumberEval)result).NumberValue, 0.0001); + } + + private void confirmDateValue(ValueEval text, BlankEval expected) + { + ValueEval result = invokeDateValue(text); + Assert.IsTrue(result is BlankEval); + } + + private void confirmDateValue(ValueEval text, ErrorEval expected) + { + ValueEval result = invokeDateValue(text); + Assert.IsTrue(result is ErrorEval); + Assert.AreEqual(expected.ErrorCode, ((ErrorEval)result).ErrorCode); + } + [Test] + public void TestDateValues() + { + confirmDateValue(new StringEval("2020-02-01"), 43862); + confirmDateValue(new StringEval("01-02-2020"), 43862); + confirmDateValue(new StringEval("2020-FEB-01"), 43862); + confirmDateValue(new StringEval("2020-Feb-01"), 43862); + confirmDateValue(new StringEval("2020-FEBRUARY-01"), 43862); + //confirmDateValue(new StringEval("FEB-01"), 43862); + confirmDateValue(new StringEval("2/1/2020"), 43862); + //confirmDateValue(new StringEval("2/1"), 43862); + confirmDateValue(new StringEval("2020/2/1"), 43862); + confirmDateValue(new StringEval("2020/FEB/1"), 43862); + confirmDateValue(new StringEval("FEB/1/2020"), 43862); + confirmDateValue(new StringEval("2020/02/01"), 43862); + + confirmDateValue(new StringEval(""), BlankEval.instance); + confirmDateValue(BlankEval.instance, BlankEval.instance); + + confirmDateValue(new StringEval("non-date text"), ErrorEval.VALUE_INVALID); + } + } +} diff --git a/testcases/main/SS/Formula/Functions/TestDays360.cs b/testcases/main/SS/Formula/Functions/TestDays360.cs index 35cb48fa7..55f3548e7 100644 --- a/testcases/main/SS/Formula/Functions/TestDays360.cs +++ b/testcases/main/SS/Formula/Functions/TestDays360.cs @@ -76,12 +76,6 @@ public void TestBasic() // longer time spans Confirm(562, 2008, 8, 11, 2010, 3, 3); Confirm(916, 2007, 2, 23, 2009, 9, 9); - } - - private static void Confirm(int expResult, int y1, int m1, int d1, int y2, int m2, int d2) - { - Confirm(expResult, MakeDate(y1, m1, d1), MakeDate(y2, m2, d2), false); - Confirm(-expResult, MakeDate(y2, m2, d2), MakeDate(y1, m1, d1), false); // other tests Confirm(1, MakeDate(1993, 2, 28), MakeDate(1993, 3, 1), false); @@ -89,6 +83,17 @@ private static void Confirm(int expResult, int y1, int m1, int d1, int y2, int m Confirm(-2, MakeDate(1993, 2, 28), MakeDate(1993, 2, 28), false); Confirm(3, MakeDate(1993, 2, 28), MakeDate(1993, 3, 1), true); Confirm(2, MakeDate(1996, 2, 29), MakeDate(1996, 3, 1), true); + + // from https://support.office.com/en-us/article/DAYS360-function-B9A509FD-49EF-407E-94DF-0CBDA5718C2A + Confirm(1, MakeDate(2011, 1, 30), MakeDate(2011, 2, 1), false); + Confirm(360, MakeDate(2011, 1, 1), MakeDate(2011, 12, 31), false); + Confirm(30, MakeDate(2011, 1, 1), MakeDate(2011, 2, 1), false); + } + + private static void Confirm(int expResult, int y1, int m1, int d1, int y2, int m2, int d2) + { + Confirm(expResult, MakeDate(y1, m1, d1), MakeDate(y2, m2, d2), false); + Confirm(-expResult, MakeDate(y2, m2, d2), MakeDate(y1, m1, d1), false); } /** * The method parameter only Makes a difference when the second parameter @@ -118,6 +123,24 @@ public void TestMonthBoundaries() // leap year ConfirmMonthBoundary(false, 2012, 2, -1, 1, 2, 3, 4); ConfirmMonthBoundary(true, 2012, 2, 0, 1, 2, 3, 4); + + // bug 60029 + DateTime start = MakeDate(2018, 2, 28); + DateTime end = MakeDate(2018, 3, 31); + Confirm(30, start, end, false); + + // examples from https://support.office.com/en-us/article/DAYS360-function-B9A509FD-49EF-407E-94DF-0CBDA5718C2A + start = MakeDate(2011, 1, 30); + end = MakeDate(2011, 2, 1); + Confirm(1, start, end, false); + + start = MakeDate(2011, 1, 1); + end = MakeDate(2011, 12, 31); + Confirm(360, start, end, false); + + start = MakeDate(2011, 1, 1); + end = MakeDate(2011, 2, 1); + Confirm(30, start, end, false); } @@ -151,13 +174,11 @@ private static void Confirm(int expResult, DateTime firstArg, DateTime secondArg { ve = invokeDays360(Convert(firstArg), Convert(secondArg)); } - if (ve is NumberEval) - { - Assert.IsTrue(ve is NumberEval, "wrong return type (" + ve.GetType().Name + ")"); - NumberEval numberEval = (NumberEval)ve; - String err = String.Format("days360({0},{1},{2}) wrong result", firstArg, secondArg, method); - Assert.AreEqual(expResult, numberEval.NumberValue, err); - } + Assert.IsTrue(ve is NumberEval, "wrong return type (" + ve.GetType().Name + ")"); + + NumberEval numberEval = (NumberEval)ve; + String err = String.Format("days360({0},{1},{2}) wrong result", firstArg, secondArg, method); + Assert.AreEqual(expResult, numberEval.NumberValue, err); } private static ValueEval invokeDays360(params ValueEval[] args) { diff --git a/testcases/main/SS/Formula/Functions/TestDec2Hex.cs b/testcases/main/SS/Formula/Functions/TestDec2Hex.cs index 8106fdd90..ccbf88dc0 100644 --- a/testcases/main/SS/Formula/Functions/TestDec2Hex.cs +++ b/testcases/main/SS/Formula/Functions/TestDec2Hex.cs @@ -101,7 +101,7 @@ public void TestBasic() Assert.AreEqual("549755813887", maxLong); ConfirmValue("Converts the max supported value to hexadecimal", maxLong, "7FFFFFFFFF"); - String minLong = (-549755813888l).ToString(); + String minLong = (-549755813888L).ToString(); Assert.AreEqual("-549755813888", minLong); ConfirmValue("Converts the min supported value to hexadecimal", minLong, "FF80000000"); diff --git a/testcases/main/SS/Formula/Functions/TestDollarDe.cs b/testcases/main/SS/Formula/Functions/TestDollarDe.cs new file mode 100644 index 000000000..fc8983af1 --- /dev/null +++ b/testcases/main/SS/Formula/Functions/TestDollarDe.cs @@ -0,0 +1,91 @@ +using NPOI.HSSF.UserModel; +using NPOI.SS.Formula; +using NPOI.SS.Formula.Eval; +using NPOI.SS.Formula.Functions; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Text; + +namespace TestCases.SS.Formula.Functions +{ + [TestFixture] + public class TestDollarDe + { + private static OperationEvaluationContext ec = new OperationEvaluationContext(null, null, 0, 0, 0, null); + + [Test] + public void TestInvalid() + { + confirmInvalidError("A1", "B2"); + } + + [Test] + public void TestNumError() + { + confirmNumError("22.5", "-40"); + } + + [Test] + public void TestDiv0() + { + confirmDiv0("22.5", "0"); + confirmDiv0("22.5", "0.9"); + confirmDiv0("22.5", "-0.9"); + } + + //https://support.microsoft.com/en-us/office/dollarde-function-db85aab0-1677-428a-9dfd-a38476693427 + [Test] + public void TestMicrosoftExample1() + { + HSSFWorkbook wb = new HSSFWorkbook(); + var sheet = wb.CreateSheet(); + var row = sheet.CreateRow(0); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + var cell = row.CreateCell(0); + double tolerance = 0.000000000000001; + SS.Util.Utils.AssertDouble(fe, cell, "DOLLARDE(1.02,16)", 1.125, tolerance); + SS.Util.Utils.AssertDouble(fe, cell, "DOLLARDE(1.02,16.9)", 1.125, tolerance); + SS.Util.Utils.AssertDouble(fe, cell, "DOLLARDE(1.32,16)", 3.0, tolerance); + SS.Util.Utils.AssertDouble(fe, cell, "DOLLARDE(-1.02,16)", -1.125, tolerance); + SS.Util.Utils.AssertDouble(fe, cell, "DOLLARDE(1.1,32)", 1.3125, tolerance); + SS.Util.Utils.AssertDouble(fe, cell, "DOLLARDE(1.1,32.1)", 1.3125, tolerance); + SS.Util.Utils.AssertDouble(fe, cell, "DOLLARDE(1.0,32)", 1.0, tolerance); + SS.Util.Utils.AssertDouble(fe, cell, "DOLLARDE(1.000001,32)", 1.000003125, tolerance); + } + + private static ValueEval invokeValue(String number1, String number2) + { + ValueEval[] args = new ValueEval[] { new StringEval(number1), new StringEval(number2) }; + return DollarDe.instance.Evaluate(args, ec); + } + + private static void confirmValue(String number1, String number2, double expected) + { + ValueEval result = invokeValue(number1, number2); + Assert.IsTrue(result is NumberEval); + Assert.AreEqual(expected, ((NumberEval)result).NumberValue, 0.00000000000001); + } + + private static void confirmInvalidError(String number1, String number2) + { + ValueEval result = invokeValue(number1, number2); + Assert.IsTrue(result is ErrorEval); + Assert.AreEqual(ErrorEval.VALUE_INVALID, result); + } + + private static void confirmNumError(String number1, String number2) + { + ValueEval result = invokeValue(number1, number2); + Assert.IsTrue(result is ErrorEval); + Assert.AreEqual(ErrorEval.NUM_ERROR, result); + } + + private static void confirmDiv0(String number1, String number2) + { + ValueEval result = invokeValue(number1, number2); + Assert.IsTrue(result is ErrorEval); + Assert.AreEqual(ErrorEval.DIV_ZERO, result); + } + } +} diff --git a/testcases/main/SS/Formula/Functions/TestDollarFr.cs b/testcases/main/SS/Formula/Functions/TestDollarFr.cs new file mode 100644 index 000000000..ba27cb66a --- /dev/null +++ b/testcases/main/SS/Formula/Functions/TestDollarFr.cs @@ -0,0 +1,87 @@ +using NPOI.HSSF.UserModel; +using NPOI.SS.Formula; +using NPOI.SS.Formula.Eval; +using NPOI.SS.Formula.Functions; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Text; + +namespace TestCases.SS.Formula.Functions +{ + [TestFixture] + public class TestDollarFr + { + private static OperationEvaluationContext ec = new OperationEvaluationContext(null, null, 0, 0, 0, null); + + [Test] + public void TestInvalid() + { + confirmInvalidError("A1", "B2"); + } + + [Test] + public void TestNumError() + { + confirmNumError("22.5", "-40"); + } + + [Test] + public void TestDiv0() + { + confirmDiv0("22.5", "0"); + confirmDiv0("22.5", "0.9"); + confirmDiv0("22.5", "-0.9"); + } + + //https://support.microsoft.com/en-us/office/dollarde-function-db85aab0-1677-428a-9dfd-a38476693427 + [Test] + public void TestMicrosoftExample1() + { + HSSFWorkbook wb = new HSSFWorkbook(); + var sheet = wb.CreateSheet(); + var row = sheet.CreateRow(0); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + var cell = row.CreateCell(0); + double tolerance = 0.000000000000001; + SS.Util.Utils.AssertDouble(fe, cell, "DOLLARFR(1.125,16)", 1.02, tolerance); + SS.Util.Utils.AssertDouble(fe, cell, "DOLLARFR(-1.125,16)", -1.02, tolerance); + SS.Util.Utils.AssertDouble(fe, cell, "DOLLARFR(1.000125,16)", 1.00002, tolerance); + SS.Util.Utils.AssertDouble(fe, cell, "DOLLARFR(1.125,32)", 1.04, tolerance); + } + + private static ValueEval invokeValue(String number1, String number2) + { + ValueEval[] args = new ValueEval[] { new StringEval(number1), new StringEval(number2) }; + return DollarDe.instance.Evaluate(args, ec); + } + + private static void confirmValue(String number1, String number2, double expected) + { + ValueEval result = invokeValue(number1, number2); + Assert.IsTrue(result is NumberEval); + Assert.AreEqual(expected, ((NumberEval)result).NumberValue, 0.00000000000001); + } + + private static void confirmInvalidError(String number1, String number2) + { + ValueEval result = invokeValue(number1, number2); + Assert.IsTrue(result is ErrorEval); + Assert.AreEqual(ErrorEval.VALUE_INVALID, result); + } + + private static void confirmNumError(String number1, String number2) + { + ValueEval result = invokeValue(number1, number2); + Assert.IsTrue(result is ErrorEval); + Assert.AreEqual(ErrorEval.NUM_ERROR, result); + } + + private static void confirmDiv0(String number1, String number2) + { + ValueEval result = invokeValue(number1, number2); + Assert.IsTrue(result is ErrorEval); + Assert.AreEqual(ErrorEval.DIV_ZERO, result); + } + } +} diff --git a/testcases/main/SS/Formula/Functions/TestNormDist.cs b/testcases/main/SS/Formula/Functions/TestNormDist.cs new file mode 100644 index 000000000..63db499cf --- /dev/null +++ b/testcases/main/SS/Formula/Functions/TestNormDist.cs @@ -0,0 +1,82 @@ +using NPOI.HSSF.UserModel; +using NPOI.SS.Formula; +using NPOI.SS.Formula.Eval; +using NPOI.SS.Formula.Functions; +using NPOI.SS.UserModel; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Text; + +namespace TestCases.SS.Formula.Functions +{ + [TestFixture] + public class TestNormDist + { + private static OperationEvaluationContext ec = new OperationEvaluationContext(null, null, 0, 0, 0, null); + [Test] + public void TestBasic() + { + confirmValue("42", "40", "1.5", true, 0.908788780274132); + confirmValue("42", "40", "1.5", false, 0.109340049783996); + } + [Test] + public void TestInvalid() + { + confirmInvalidError("A1", "B2", "C2", false); + } + + [Test] + public void TestNumError() + { + confirmNumError("42", "40", "0", false); + confirmNumError("42", "40", "0", true); + confirmNumError("42", "40", "-0.1", false); + confirmNumError("42", "40", "-0.1", true); + } + + //https://support.microsoft.com/en-us/office/normdist-function-126db625-c53e-4591-9a22-c9ff422d6d58 + //https://support.microsoft.com/en-us/office/norm-dist-function-edb1cc14-a21c-4e53-839d-8082074c9f8d + [Test] + public void TestMicrosoftExample1() + { + HSSFWorkbook wb = new HSSFWorkbook(); + ISheet sheet = wb.CreateSheet(); + SS.Util.Utils.AddRow(sheet, 0, "Data", "Description"); + SS.Util.Utils.AddRow(sheet, 1, 42, "Value for which you want the distribution"); + SS.Util.Utils.AddRow(sheet, 2, 40, "Arithmetic mean of the distribution"); + SS.Util.Utils.AddRow(sheet, 3, 1.5, "Standard deviation of the distribution"); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + ICell cell = wb.GetSheetAt(0).GetRow(0).CreateCell(100); + SS.Util.Utils.AssertDouble(fe, cell, "NORMDIST(A2,A3,A4,TRUE)", 0.908788780274132, 0.00000000000001); + SS.Util.Utils.AssertDouble(fe, cell, "NORM.DIST(A2,A3,A4,TRUE)", 0.908788780274132, 0.00000000000001); + } + + private static ValueEval invokeValue(String number1, String number2, String number3, bool cumulative) + { + ValueEval[] args = new ValueEval[] { new StringEval(number1), new StringEval(number2), new StringEval(number3), BoolEval.ValueOf(cumulative) }; + return NormDist.instance.Evaluate(args, ec); + } + + private static void confirmValue(String number1, String number2, String number3, bool cumulative, double expected) + { + ValueEval result = invokeValue(number1, number2, number3, cumulative); + Assert.IsTrue(result is NumberEval); + Assert.AreEqual(expected, ((NumberEval)result).NumberValue, 0.00000000000001); + } + + private static void confirmInvalidError(String number1, String number2, String number3, bool cumulative) + { + ValueEval result = invokeValue(number1, number2, number3, cumulative); + Assert.IsTrue(result is ErrorEval); + Assert.AreEqual(ErrorEval.VALUE_INVALID, result); + } + + private static void confirmNumError(String number1, String number2, String number3, bool cumulative) + { + ValueEval result = invokeValue(number1, number2, number3, cumulative); + Assert.IsTrue(result is ErrorEval); + Assert.AreEqual(ErrorEval.NUM_ERROR, result); + } + } +} \ No newline at end of file diff --git a/testcases/main/SS/Formula/Functions/TestNormInv.cs b/testcases/main/SS/Formula/Functions/TestNormInv.cs new file mode 100644 index 000000000..17e2d82cf --- /dev/null +++ b/testcases/main/SS/Formula/Functions/TestNormInv.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Text; +using NPOI.HSSF.UserModel; +using NPOI.SS.Formula; +using NPOI.SS.Formula.Eval; +using NPOI.SS.Formula.Functions; +using NPOI.SS.UserModel; +using NUnit.Framework; + +namespace TestCases.SS.Formula.Functions +{ + [TestFixture] + public class TestNormInv + { + private static OperationEvaluationContext ec = new OperationEvaluationContext(null, null, 0, 0, 0, null); + + [Test] + public void TestBasic() + { + confirmValue("0.908789", "40", "1.5", 42.000002); + } + + [Test] + public void TestInvalid() + { + confirmInvalidError("A1", "B2", "C2"); + } + + [Test] + public void TestNumError() + { + confirmNumError("0.5", "40", "0"); + confirmNumError("0.5", "40", "-0.1"); + confirmNumError("-0.5", "40", "0.1"); + confirmNumError("0", "40", "0.1"); + confirmNumError("1", "40", "0.1"); + confirmNumError("1.5", "40", "0.1"); + } + //https://support.microsoft.com/en-us/office/norminv-function-87981ab8-2de0-4cb0-b1aa-e21d4cb879b8 + //https://support.microsoft.com/en-us/office/norm-inv-function-54b30935-fee7-493c-bedb-2278a9db7e13 + [Test] + public void TestMicrosoftExample1() + { + HSSFWorkbook wb = new HSSFWorkbook(); + ISheet sheet = wb.CreateSheet(); + SS.Util.Utils.AddRow(sheet, 0, "Data", "Description"); + SS.Util.Utils.AddRow(sheet, 1, 0.908789, "Probability corresponding to the normal distribution"); + SS.Util.Utils.AddRow(sheet, 2, 40, "Arithmetic mean of the distribution"); + SS.Util.Utils.AddRow(sheet, 3, 1.5, "Standard deviation of the distribution"); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + ICell cell = wb.GetSheetAt(0).GetRow(0).CreateCell(100); + SS.Util.Utils.AssertDouble(fe, cell, "NORMINV(A2,A3,A4)", 42.000002, 0.000001); + SS.Util.Utils.AssertDouble(fe, cell, "NORM.INV(A2,A3,A4)", 42.000002, 0.000001); + } + private static ValueEval invokeValue(String number1, String number2, String number3) + { + ValueEval[] args = new ValueEval[] { new StringEval(number1), new StringEval(number2), new StringEval(number3) }; + return NormInv.instance.Evaluate(args, ec); + } + + private static void confirmValue(String number1, String number2, String number3, double expected) + { + ValueEval result = invokeValue(number1, number2, number3); + Assert.IsTrue(result is NumberEval); + Assert.AreEqual(expected, ((NumberEval)result).NumberValue, 0.0000001); + } + + private static void confirmInvalidError(String number1, String number2, String number3) + { + ValueEval result = invokeValue(number1, number2, number3); + Assert.IsTrue(result is ErrorEval); + Assert.AreEqual(ErrorEval.VALUE_INVALID, result); + } + + private static void confirmNumError(String number1, String number2, String number3) + { + ValueEval result = invokeValue(number1, number2, number3); + Assert.IsTrue(result is ErrorEval); + Assert.AreEqual(ErrorEval.NUM_ERROR, result); + } + } +} \ No newline at end of file diff --git a/testcases/main/SS/Formula/Functions/TestNormSDist.cs b/testcases/main/SS/Formula/Functions/TestNormSDist.cs new file mode 100644 index 000000000..79500d3f9 --- /dev/null +++ b/testcases/main/SS/Formula/Functions/TestNormSDist.cs @@ -0,0 +1,59 @@ +using NPOI.SS.Formula; +using System; +using System.Collections.Generic; +using System.Text; +using NUnit.Framework; +using NPOI.SS.Formula.Eval; +using NPOI.SS.Formula.Functions; +using NPOI.HSSF.UserModel; +using NPOI.SS.UserModel; + +namespace TestCases.SS.Formula.Functions +{ + [TestFixture] + public class TestNormSDist + { + private static OperationEvaluationContext ec = new OperationEvaluationContext(null, null, 0, 0, 0, null); + [Test] + public void TestBasic() + { + confirmValue("1.333333", 0.908788726); + } + + [Test] + public void TestInvalid() + { + confirmInvalidError("A1"); + } + [Test] + public void TestMicrosoftExample1() + { + HSSFWorkbook wb = new HSSFWorkbook(); + ISheet sheet = wb.CreateSheet(); + IRow row = sheet.CreateRow(0); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + ICell cell = row.CreateCell(0); + SS.Util.Utils.AssertDouble(fe, cell, "NORMSDIST(1.333333)", 0.908788726, 0.000001); + SS.Util.Utils.AssertDouble(fe, cell, "NORM.S.DIST(1.333333)", 0.908788726, 0.000001); + } + private static ValueEval invokeValue(String number1) + { + ValueEval[] args = new ValueEval[] { new StringEval(number1) }; + return NormSDist.instance.Evaluate(args, ec); + } + + private static void confirmValue(String number1, double expected) + { + ValueEval result = invokeValue(number1); + Assert.IsTrue(result is NumberEval); + Assert.AreEqual(expected, ((NumberEval)result).NumberValue, 0.0000001); + } + + private static void confirmInvalidError(String number1) + { + ValueEval result = invokeValue(number1); + Assert.IsTrue(result is ErrorEval); + Assert.AreEqual(ErrorEval.VALUE_INVALID, result); + } + } +} diff --git a/testcases/main/SS/Formula/Functions/TestNormSInv.cs b/testcases/main/SS/Formula/Functions/TestNormSInv.cs new file mode 100644 index 000000000..f5e3a1a3e --- /dev/null +++ b/testcases/main/SS/Formula/Functions/TestNormSInv.cs @@ -0,0 +1,73 @@ +using NPOI.SS.Formula; +using System; +using System.Collections.Generic; +using System.Text; +using NUnit.Framework; +using NPOI.SS.Formula.Eval; +using NPOI.SS.Formula.Functions; +using NPOI.HSSF.UserModel; +using NPOI.SS.UserModel; + +namespace TestCases.SS.Formula.Functions +{ + [TestFixture] + public class TestNormSInv + { + private static OperationEvaluationContext ec = new OperationEvaluationContext(null, null, 0, 0, 0, null); + [Test] + public void TestBasic() + { + confirmValue("0.9088", 1.3334); + } + + [Test] + public void TestInvalid() + { + confirmInvalidError("A1"); + } + [Test] + public void TestNumError() + { + confirmNumError("0"); + confirmNumError("-0.5"); + confirmNumError("1"); + confirmNumError("1.5"); + } + [Test] + public void TestMicrosoftExample1() + { + HSSFWorkbook wb = new HSSFWorkbook(); + ISheet sheet = wb.CreateSheet(); + IRow row = sheet.CreateRow(0); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + ICell cell = row.CreateCell(0); + SS.Util.Utils.AssertDouble(fe, cell, "NORMSINV(0.9088)", 1.3334, 0.00001); + SS.Util.Utils.AssertDouble(fe, cell, "NORM.S.INV(0.9088)", 1.3334, 0.00001); + } + private static ValueEval invokeValue(String number1) + { + ValueEval[] args = new ValueEval[] { new StringEval(number1) }; + return NormSInv.instance.Evaluate(args, ec); + } + + private static void confirmValue(String number1, double expected) + { + ValueEval result = invokeValue(number1); + Assert.IsTrue(result is NumberEval); + Assert.AreEqual(expected, ((NumberEval)result).NumberValue, 0.00001); + } + + private static void confirmInvalidError(String number1) + { + ValueEval result = invokeValue(number1); + Assert.IsTrue(result is ErrorEval); + Assert.AreEqual(ErrorEval.VALUE_INVALID, result); + } + private static void confirmNumError(String number1) + { + ValueEval result = invokeValue(number1); + Assert.IsTrue(result is ErrorEval); + Assert.AreEqual(ErrorEval.NUM_ERROR, result); + } + } +} diff --git a/testcases/main/SS/Formula/Functions/TestNumberValue.cs b/testcases/main/SS/Formula/Functions/TestNumberValue.cs new file mode 100644 index 000000000..131505a0f --- /dev/null +++ b/testcases/main/SS/Formula/Functions/TestNumberValue.cs @@ -0,0 +1,34 @@ +using NPOI.HSSF.UserModel; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Text; + +namespace TestCases.SS.Formula.Functions +{ + [TestFixture] + public class TestNumberValue + { + [Test] + public void TestMicrosoftExample1() + { + HSSFWorkbook wb = new HSSFWorkbook(); + var sheet = wb.CreateSheet(); + var row = sheet.CreateRow(0); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + var cell = row.CreateCell(0); + SS.Util.Utils.AssertDouble(fe, cell, "NUMBERVALUE(\"2.500,27\",\",\",\".\")", 2500.27, 0.000000000001); + } + + [Test] + public void TestMicrosoftExample2() + { + HSSFWorkbook wb = new HSSFWorkbook(); + var sheet = wb.CreateSheet(); + var row = sheet.CreateRow(0); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + var cell = row.CreateCell(0); + SS.Util.Utils.AssertDouble(fe, cell, "NUMBERVALUE(\"3.5%\")", 0.035, 0.000000000001); + } + } +} diff --git a/testcases/main/SS/Formula/Functions/TestNumericFunction.cs b/testcases/main/SS/Formula/Functions/TestNumericFunction.cs new file mode 100644 index 000000000..d534809d0 --- /dev/null +++ b/testcases/main/SS/Formula/Functions/TestNumericFunction.cs @@ -0,0 +1,55 @@ +using NPOI.HSSF.UserModel; +using NPOI.SS.UserModel; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Text; + +namespace TestCases.SS.Formula.Functions +{ + [TestFixture] + public class TestNumericFunction + { + [Test] + public void TestINT() + { + HSSFWorkbook wb = new HSSFWorkbook(); + ICell cell = wb.CreateSheet().CreateRow(0).CreateCell(0); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + SS.Util.Utils.AssertDouble(fe, cell, "INT(880000000.0001)", 880000000.0); + //the following INT(-880000000.0001) resulting in -880000001.0 has been observed in excel + //see also https://support.microsoft.com/en-us/office/int-function-a6c4af9e-356d-4369-ab6a-cb1fd9d343ef + SS.Util.Utils.AssertDouble(fe, cell, "INT(-880000000.0001)", -880000001.0); + SS.Util.Utils.AssertDouble(fe, cell, "880000000*0.00849", 7471200.0); + SS.Util.Utils.AssertDouble(fe, cell, "880000000*0.00849/3", 2490400.0); + SS.Util.Utils.AssertDouble(fe, cell, "INT(880000000*0.00849/3)", 2490400.0); + } + + [Test] + public void TestSIGN() + { + HSSFWorkbook wb = new HSSFWorkbook(); + ICell cell = wb.CreateSheet().CreateRow(0).CreateCell(0); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + //https://support.microsoft.com/en-us/office/sign-function-109c932d-fcdc-4023-91f1-2dd0e916a1d8 + SS.Util.Utils.AssertDouble(fe, cell, "SIGN(10)", 1.0); + SS.Util.Utils.AssertDouble(fe, cell, "SIGN(4-4)", 0.0); + SS.Util.Utils.AssertDouble(fe, cell, "SIGN(-0.00001)", -1.0); + } + + [Test] + public void TestDOLLAR() + { + HSSFWorkbook wb = new HSSFWorkbook(); + ICell cell = wb.CreateSheet().CreateRow(0).CreateCell(0); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + //https://support.microsoft.com/en-us/office/dollar-function-a6cd05d9-9740-4ad3-a469-8109d18ff611 + SS.Util.Utils.AssertString(fe, cell, "DOLLAR(1234.567,2)", "$1,234.57"); + SS.Util.Utils.AssertString(fe, cell, "DOLLAR(-1234.567,0)", "($1,235)"); + SS.Util.Utils.AssertString(fe, cell, "DOLLAR(-1234.567,-2)", "($1,200)"); + SS.Util.Utils.AssertString(fe, cell, "DOLLAR(-0.123,4)", "($0.1230)"); + SS.Util.Utils.AssertString(fe, cell, "DOLLAR(99.888)", "$99.89"); + SS.Util.Utils.AssertString(fe, cell, "DOLLAR(123456789.567,2)", "$123,456,789.57"); + } + } +} diff --git a/testcases/main/SS/Formula/Functions/TestOffset.cs b/testcases/main/SS/Formula/Functions/TestOffset.cs index e36a52d20..69ddb5755 100644 --- a/testcases/main/SS/Formula/Functions/TestOffset.cs +++ b/testcases/main/SS/Formula/Functions/TestOffset.cs @@ -17,9 +17,10 @@ namespace TestCases.SS.Formula.Functions { - + using NPOI.HSSF.UserModel; using NPOI.SS.Formula.Eval; using NPOI.SS.Formula.Functions; + using NPOI.SS.UserModel; using NUnit.Framework; /** @@ -103,6 +104,20 @@ public void TestLinearOffsetRange() Assert.IsTrue(lor.IsOutOfBounds(0, 16383)); Assert.IsFalse(lor.IsOutOfBounds(0, 65535)); } + + [Test] + public void TestOffsetWithEmpty23Arguments() + { + IWorkbook workbook = new HSSFWorkbook(); + ICell cell = workbook.CreateSheet().CreateRow(0).CreateCell(0); + cell.SetCellFormula("OFFSET(B1,,)"); + string value = "EXPECTED_VALUE"; + ICell valueCell = cell.Row.CreateCell(1); + valueCell.SetCellValue(value); + workbook.GetCreationHelper().CreateFormulaEvaluator().EvaluateAll(); + Assert.AreEqual(CellType.String, cell.CachedFormulaResultType); + Assert.AreEqual(value, cell.StringCellValue); + } } } \ No newline at end of file diff --git a/testcases/main/SS/Formula/Functions/TestPercentRank.cs b/testcases/main/SS/Formula/Functions/TestPercentRank.cs new file mode 100644 index 000000000..129c4eeab --- /dev/null +++ b/testcases/main/SS/Formula/Functions/TestPercentRank.cs @@ -0,0 +1,76 @@ +using NPOI.HSSF.UserModel; +using NPOI.SS.UserModel; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Text; + +namespace TestCases.SS.Formula.Functions +{ + [TestFixture] + public class TestPercentRank + { + //https://support.microsoft.com/en-us/office/percentrank-function-f1b5836c-9619-4847-9fc9-080ec9024442 + [Test] + public void TestMicrosoftExample1() + { + HSSFWorkbook wb = initWorkbook1(); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + ICell cell = wb.GetSheetAt(0).GetRow(0).CreateCell(100); + confirmNumericResult(fe, cell, "PERCENTRANK(A2:A11,2)", 0.333); + confirmNumericResult(fe, cell, "PERCENTRANK(A2:A11,8,2)", 0.66); + confirmNumericResult(fe, cell, "PERCENTRANK(A2:A11,8,4)", 0.6666); + confirmNumericResult(fe, cell, "PERCENTRANK(A2:A11,4)", 0.555); + confirmNumericResult(fe, cell, "PERCENTRANK(A2:A11,8)", 0.666); + confirmNumericResult(fe, cell, "PERCENTRANK(A2:A11,5)", 0.583); + + } + + [Test] + public void TestErrorCases() + { + HSSFWorkbook wb = initWorkbook1(); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + ICell cell = wb.GetSheetAt(0).GetRow(0).CreateCell(100); + confirmErrorResult(fe, cell, "PERCENTRANK(A2:A11,0)", FormulaError.NA); + confirmErrorResult(fe, cell, "PERCENTRANK(A2:A11,100)", FormulaError.NA); + confirmErrorResult(fe, cell, "PERCENTRANK(B2:B11,100)", FormulaError.NUM); + + } + + private HSSFWorkbook initWorkbook1() + { + HSSFWorkbook wb = new HSSFWorkbook(); + ISheet sheet = wb.CreateSheet(); + SS.Util.Utils.AddRow(sheet, 0, "Data"); + SS.Util.Utils.AddRow(sheet, 1, 13); + SS.Util.Utils.AddRow(sheet, 2, 12); + SS.Util.Utils.AddRow(sheet, 3, 11); + SS.Util.Utils.AddRow(sheet, 4, 8); + SS.Util.Utils.AddRow(sheet, 5, 4); + SS.Util.Utils.AddRow(sheet, 6, 3); + SS.Util.Utils.AddRow(sheet, 7, 2); + SS.Util.Utils.AddRow(sheet, 8, 1); + SS.Util.Utils.AddRow(sheet, 9, 1); + SS.Util.Utils.AddRow(sheet, 10, 1); + return wb; + } + + private static void confirmNumericResult(HSSFFormulaEvaluator fe, ICell cell, String formulaText, double expectedResult) + { + cell.SetCellFormula(formulaText); + fe.NotifyUpdateCell(cell); + CellValue result = fe.Evaluate(cell); + Assert.AreEqual(CellType.Numeric, result.CellType); + Assert.AreEqual(expectedResult, result.NumberValue, 0.0001); + } + + private static void confirmErrorResult(HSSFFormulaEvaluator fe, ICell cell, String formulaText, FormulaError expectedResult) + { + cell.SetCellFormula(formulaText); + fe.NotifyUpdateCell(cell); + CellValue result = fe.Evaluate(cell); + Assert.AreEqual(expectedResult.Code, result.ErrorValue); + } + } +} diff --git a/testcases/main/SS/Formula/Functions/TestStandardize.cs b/testcases/main/SS/Formula/Functions/TestStandardize.cs new file mode 100644 index 000000000..337acfbca --- /dev/null +++ b/testcases/main/SS/Formula/Functions/TestStandardize.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Text; +using NPOI.HSSF.UserModel; +using NPOI.SS.Formula; +using NPOI.SS.Formula.Eval; +using NPOI.SS.Formula.Functions; +using NPOI.SS.UserModel; +using NUnit.Framework; + +namespace TestCases.SS.Formula.Functions +{ + [TestFixture] + public class TestStandardize + { + private static OperationEvaluationContext ec = new OperationEvaluationContext(null, null, 0, 0, 0, null); + [Test] + public void TestBasic() + { + confirmValue("42", "40", "1.5", 1.33333333); + } + + [Test] + public void TestInvalid() + { + confirmInvalidError("A1", "B2", "C2"); + } + + [Test] + public void TestNumError() + { + confirmNumError("42", "40", "0"); + confirmNumError("42", "40", "-0.1"); + } + //https://support.microsoft.com/en-us/office/standardize-function-81d66554-2d54-40ec-ba83-6437108ee775 + [Test] + public void TestMicrosoftExample1() + { + HSSFWorkbook wb = new HSSFWorkbook(); + ISheet sheet = wb.CreateSheet(); + SS.Util.Utils.AddRow(sheet, 0, "Data", "Description"); + SS.Util.Utils.AddRow(sheet, 1, 42, "Value to normalize"); + SS.Util.Utils.AddRow(sheet, 2, 40, "Arithmetic mean of the distribution"); + SS.Util.Utils.AddRow(sheet, 3, 1.5, "Standard deviation of the distribution"); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + ICell cell = wb.GetSheetAt(0).GetRow(0).CreateCell(100); + SS.Util.Utils.AssertDouble(fe, cell, "STANDARDIZE(A2,A3,A4)", 1.33333333, 0.000001); + } + private static ValueEval invokeValue(String number1, String number2, String number3) + { + ValueEval[] args = new ValueEval[] { new StringEval(number1), new StringEval(number2), new StringEval(number3) }; + return Standardize.instance.Evaluate(args, ec); + } + + private static void confirmValue(String number1, String number2, String number3, double expected) + { + ValueEval result = invokeValue(number1, number2, number3); + Assert.IsTrue(result is NumberEval); + Assert.AreEqual(expected, ((NumberEval)result).NumberValue, 0.0000001); + } + + private static void confirmInvalidError(String number1, String number2, String number3) + { + ValueEval result = invokeValue(number1, number2, number3); + Assert.IsTrue(result is ErrorEval); + Assert.AreEqual(ErrorEval.VALUE_INVALID, result); + } + + private static void confirmNumError(String number1, String number2, String number3) + { + ValueEval result = invokeValue(number1, number2, number3); + Assert.IsTrue(result is ErrorEval); + Assert.AreEqual(ErrorEval.NUM_ERROR, result); + } + } +} \ No newline at end of file diff --git a/testcases/main/SS/Formula/Functions/TestTDist.cs b/testcases/main/SS/Formula/Functions/TestTDist.cs new file mode 100644 index 000000000..b9c4cf589 --- /dev/null +++ b/testcases/main/SS/Formula/Functions/TestTDist.cs @@ -0,0 +1,84 @@ +using NPOI.HSSF.UserModel; +using NPOI.SS.Formula; +using NPOI.SS.Formula.Eval; +using NPOI.SS.Formula.Functions; +using NPOI.SS.UserModel; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Text; + +namespace TestCases.SS.Formula.Functions +{ + public class TestTDist + { + private static OperationEvaluationContext ec = new OperationEvaluationContext(null, null, 0, 0, 0, null); + [Test] + public void TestBasic() + { + confirmValue("5.968191467", "8", "1", 0.00016754180265310392); + confirmValue("5.968191467", "8", "2", 0.00033508360530620784); + confirmValue("5.968191467", "8.2", "2.2", 0.00033508360530620784); + confirmValue("5.968191467", "8.9", "2.9", 0.00033508360530620784); + } + + [Test] + public void TestInvalid() + { + confirmInvalidError("A1", "B2", "C2"); + confirmInvalidError("5.968191467", "8", "C2"); + confirmInvalidError("5.968191467", "B2", "2"); + confirmInvalidError("A1", "8", "2"); + } + + [Test] + public void TestNumError() + { + confirmNumError("5.968191467", "8", "0"); + confirmNumError("-5.968191467", "8", "2"); + } + + //https://support.microsoft.com/en-us/office/tdist-function-630a7695-4021-4853-9468-4a1f9dcdd192 + [Test] + public void testMicrosoftExample1() + { + HSSFWorkbook wb = new HSSFWorkbook(); + ISheet sheet = wb.CreateSheet(); + SS.Util.Utils.AddRow(sheet, 0, "Data", "Description"); + SS.Util.Utils.AddRow(sheet, 1, 1.959999998, "Value at which to evaluate the distribution"); + SS.Util.Utils.AddRow(sheet, 2, 60, "Degrees of freedom"); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + ICell cell = wb.GetSheetAt(0).GetRow(0).CreateCell(100); + SS.Util.Utils.AssertDouble(fe, cell, "TDIST(A2,A3,2)", 0.054644930, 0.01); + SS.Util.Utils.AssertDouble(fe, cell, "TDIST(A2,A3,1)", 0.027322465, 0.01); + + } + private static ValueEval invokeValue(String number1, String number2, String number3) + { + ValueEval[] args = new ValueEval[] { new StringEval(number1), new StringEval(number2), new StringEval(number3) }; + return TDist.instance.Evaluate(args, ec); + } + + private static void confirmValue(String number1, String number2, String number3, double expected) + { + ValueEval result = invokeValue(number1, number2, number3); + Assert.IsTrue(result is NumberEval); + Assert.AreEqual(expected, ((NumberEval)result).NumberValue, 0.0); + } + + private static void confirmInvalidError(String number1, String number2, String number3) + { + ValueEval result = invokeValue(number1, number2, number3); + Assert.IsTrue(result is ErrorEval); + Assert.AreEqual(ErrorEval.VALUE_INVALID, result); + } + + private static void confirmNumError(String number1, String number2, String number3) + { + ValueEval result = invokeValue(number1, number2, number3); + Assert.IsTrue(result is ErrorEval); + Assert.AreEqual(ErrorEval.NUM_ERROR, result); + } + } + +} diff --git a/testcases/main/SS/Formula/Functions/TestWeekNumFunc.cs b/testcases/main/SS/Formula/Functions/TestWeekNumFunc.cs new file mode 100644 index 000000000..705ed5d02 --- /dev/null +++ b/testcases/main/SS/Formula/Functions/TestWeekNumFunc.cs @@ -0,0 +1,83 @@ +using NPOI.SS.Formula; +using NPOI.SS.Formula.Eval; +using NPOI.SS.Formula.Functions; +using NPOI.SS.UserModel; +using NPOI.Util; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Text; + +namespace TestCases.SS.Formula.Functions +{ + [TestFixture] + public class TestWeekNumFunc + { + private static double TOLERANCE = 0.001; + private static OperationEvaluationContext DEFAULT_CONTEXT = + new OperationEvaluationContext(null, null, 0, 1, 0, null); + + [Test] + public void TestEvaluate() + { + var localDate = DateTime.Parse("2012-03-09"); + double date = DateUtil.GetExcelDate(localDate); + assertEvaluateEquals(10.0, date); + assertEvaluateEquals(10.0, date, 1); + assertEvaluateEquals(11.0, date, 2); + assertEvaluateEquals(11.0, date, 11); + assertEvaluateEquals(11.0, date, 12); + assertEvaluateEquals(11.0, date, 13); + assertEvaluateEquals(11.0, date, 14); + assertEvaluateEquals(11.0, date, 15); + assertEvaluateEquals(10.0, date, 16); + assertEvaluateEquals(10.0, date, 17); + assertEvaluateEquals(10.0, date, 21); + } + [Test] + public void TestEvaluateInvalid() + { + assertEvaluateEquals("no args", ErrorEval.VALUE_INVALID); + assertEvaluateEquals("too many args", ErrorEval.VALUE_INVALID, new NumberEval(1.0), new NumberEval(1.0), new NumberEval(1.0)); + assertEvaluateEquals("negative date", ErrorEval.NUM_ERROR, new NumberEval(-1.0)); + assertEvaluateEquals("cannot coerce serial_number to number", ErrorEval.VALUE_INVALID, new StringEval("")); + assertEvaluateEquals("cannot coerce return_type to number", ErrorEval.NUM_ERROR, new NumberEval(1.0), new StringEval("")); + assertEvaluateEquals("return_type is blank", ErrorEval.NUM_ERROR, new StringEval("2"), BlankEval.instance); + assertEvaluateEquals("invalid return_type", ErrorEval.NUM_ERROR, new NumberEval(1.0), new NumberEval(18.0)); + } + + // for testing invalid invocations + private void assertEvaluateEquals(String message, ErrorEval expected, params ValueEval[] args) + { + String formula = "WEEKNUM(" + StringUtil.Join(args, ", ") + ")"; + ValueEval result = WeekNum.instance.Evaluate(args, DEFAULT_CONTEXT); + Assert.AreEqual(expected, result, formula + ": " + message); + } + + private void assertEvaluateEquals(double expected, double dateValue) + { + String formula = "WEEKNUM(" + dateValue + ")"; + ValueEval[] args = new ValueEval[] { new NumberEval(dateValue) }; + ValueEval result = WeekNum.instance.Evaluate(args, DEFAULT_CONTEXT); + if (result is NumberEval) { + Assert.AreEqual(expected, ((NumberEval)result).NumberValue, TOLERANCE, formula); + } else + { + Assert.Fail("unexpected eval result " + result); + } + } + + private void assertEvaluateEquals(double expected, double dateValue, double return_type) + { + String formula = "WEEKNUM(" + dateValue + ", " + return_type + ")"; + ValueEval[] args = new ValueEval[] { new NumberEval(dateValue), new NumberEval(return_type) }; + ValueEval result = WeekNum.instance.Evaluate(args, DEFAULT_CONTEXT); + if (result is NumberEval) { + Assert.AreEqual(expected, ((NumberEval)result).NumberValue, TOLERANCE, formula); + } else + { + Assert.Fail("unexpected eval result " + result); + } + } + } +} diff --git a/testcases/main/SS/Formula/Functions/TestWeekdayFunc.cs b/testcases/main/SS/Formula/Functions/TestWeekdayFunc.cs index 5a83291ba..a6ef380b4 100644 --- a/testcases/main/SS/Formula/Functions/TestWeekdayFunc.cs +++ b/testcases/main/SS/Formula/Functions/TestWeekdayFunc.cs @@ -21,51 +21,73 @@ namespace TestCases.SS.Formula.Functions using NPOI.SS.Formula.Eval; using NPOI.SS.Formula.Functions; + using NPOI.Util; using NUnit.Framework; [TestFixture] public class TestWeekdayFunc { + private static double TOLERANCE = 0.001; + + private void assertEvaluateEquals(double expected, double serial_number) + { + String formula = "WEEKDAY(" + serial_number + ")"; + ValueEval[] args = new ValueEval[] { new NumberEval(serial_number) }; + NumberEval result = (NumberEval)WeekdayFunc.instance.Evaluate(args, 0, 0); + Assert.AreEqual(expected, result.NumberValue, TOLERANCE, formula); + } + private void assertEvaluateEquals(double expected, double serial_number, double return_type) + { + String formula = "WEEKDAY(" + serial_number + ", " + return_type + ")"; + ValueEval[] args = new ValueEval[] { new NumberEval(serial_number), new NumberEval(return_type) }; + NumberEval result = (NumberEval)WeekdayFunc.instance.Evaluate(args, 0, 0); + Assert.AreEqual(expected, result.NumberValue, TOLERANCE, formula); + } [Test] public void TestEvaluate() { - Assert.AreEqual(2.0, ((NumberEval)WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(1.0) }, 0, 0)).NumberValue, 0.001); - Assert.AreEqual(2.0, ((NumberEval)WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(1.0), new NumberEval(1.0) }, 0, 0)).NumberValue, 0.001); - Assert.AreEqual(1.0, ((NumberEval)WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(1.0), new NumberEval(2.0) }, 0, 0)).NumberValue, 0.001); - Assert.AreEqual(0.0, ((NumberEval)WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(1.0), new NumberEval(3.0) }, 0, 0)).NumberValue, 0.001); - Assert.AreEqual(1.0, ((NumberEval)WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(1.0), new NumberEval(11.0) }, 0, 0)).NumberValue, 0.001); - Assert.AreEqual(7.0, ((NumberEval)WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(1.0), new NumberEval(12.0) }, 0, 0)).NumberValue, 0.001); - Assert.AreEqual(6.0, ((NumberEval)WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(1.0), new NumberEval(13.0) }, 0, 0)).NumberValue, 0.001); - Assert.AreEqual(5.0, ((NumberEval)WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(1.0), new NumberEval(14.0) }, 0, 0)).NumberValue, 0.001); - Assert.AreEqual(4.0, ((NumberEval)WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(1.0), new NumberEval(15.0) }, 0, 0)).NumberValue, 0.001); - Assert.AreEqual(3.0, ((NumberEval)WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(1.0), new NumberEval(16.0) }, 0, 0)).NumberValue, 0.001); - Assert.AreEqual(2.0, ((NumberEval)WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(1.0), new NumberEval(17.0) }, 0, 0)).NumberValue, 0.001); + assertEvaluateEquals(2.0, 1.0); + assertEvaluateEquals(2.0, 1.0, 1.0); + assertEvaluateEquals(1.0, 1.0, 2.0); + assertEvaluateEquals(0.0, 1.0, 3.0); + assertEvaluateEquals(1.0, 1.0, 11.0); + assertEvaluateEquals(7.0, 1.0, 12.0); + assertEvaluateEquals(6.0, 1.0, 13.0); + assertEvaluateEquals(5.0, 1.0, 14.0); + assertEvaluateEquals(4.0, 1.0, 15.0); + assertEvaluateEquals(3.0, 1.0, 16.0); + assertEvaluateEquals(2.0, 1.0, 17.0); - Assert.AreEqual(3.0, ((NumberEval)WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(39448.0) }, 0, 0)).NumberValue, 0.001); - Assert.AreEqual(3.0, ((NumberEval)WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(39448.0), new NumberEval(1.0) }, 0, 0)).NumberValue, 0.001); - Assert.AreEqual(2.0, ((NumberEval)WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(39448.0), new NumberEval(2.0) }, 0, 0)).NumberValue, 0.001); - Assert.AreEqual(1.0, ((NumberEval)WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(39448.0), new NumberEval(3.0) }, 0, 0)).NumberValue, 0.001); - Assert.AreEqual(2.0, ((NumberEval)WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(39448.0), new NumberEval(11.0) }, 0, 0)).NumberValue, 0.001); - Assert.AreEqual(1.0, ((NumberEval)WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(39448.0), new NumberEval(12.0) }, 0, 0)).NumberValue, 0.001); - Assert.AreEqual(7.0, ((NumberEval)WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(39448.0), new NumberEval(13.0) }, 0, 0)).NumberValue, 0.001); - Assert.AreEqual(6.0, ((NumberEval)WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(39448.0), new NumberEval(14.0) }, 0, 0)).NumberValue, 0.001); - Assert.AreEqual(5.0, ((NumberEval)WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(39448.0), new NumberEval(15.0) }, 0, 0)).NumberValue, 0.001); - Assert.AreEqual(4.0, ((NumberEval)WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(39448.0), new NumberEval(16.0) }, 0, 0)).NumberValue, 0.001); - Assert.AreEqual(3.0, ((NumberEval)WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(39448.0), new NumberEval(17.0) }, 0, 0)).NumberValue, 0.001); + assertEvaluateEquals(3.0, 39448.0); + assertEvaluateEquals(3.0, 39448.0, 1.0); + assertEvaluateEquals(2.0, 39448.0, 2.0); + assertEvaluateEquals(1.0, 39448.0, 3.0); + assertEvaluateEquals(2.0, 39448.0, 11.0); + assertEvaluateEquals(1.0, 39448.0, 12.0); + assertEvaluateEquals(7.0, 39448.0, 13.0); + assertEvaluateEquals(6.0, 39448.0, 14.0); + assertEvaluateEquals(5.0, 39448.0, 15.0); + assertEvaluateEquals(4.0, 39448.0, 16.0); + assertEvaluateEquals(3.0, 39448.0, 17.0); + } + // for testing invalid invocations + private void assertEvaluateEquals(String message, ErrorEval expected, params ValueEval[] args) + { + String formula = "WEEKDAY(" + StringUtil.Join(args, ", ") + ")"; + ValueEval result = WeekdayFunc.instance.Evaluate(args, 0, 0); + Assert.AreEqual(expected, result, formula + ": " + message); } - [Test] public void TestEvaluateInvalid() { - Assert.AreEqual(ErrorEval.VALUE_INVALID, WeekdayFunc.instance.Evaluate(new ValueEval[] { }, 0, 0)); - Assert.AreEqual(ErrorEval.VALUE_INVALID, WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(1.0), new NumberEval(1.0), new NumberEval(1.0) }, 0, 0)); - - Assert.AreEqual(ErrorEval.NUM_ERROR, WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(-1.0) }, 0, 0)); - Assert.AreEqual(ErrorEval.VALUE_INVALID, WeekdayFunc.instance.Evaluate(new ValueEval[] { new StringEval("") }, 0, 0)); - Assert.AreEqual(ErrorEval.VALUE_INVALID, WeekdayFunc.instance.Evaluate(new ValueEval[] { new StringEval("1"), new StringEval("") }, 0, 0)); - Assert.AreEqual(ErrorEval.NUM_ERROR, WeekdayFunc.instance.Evaluate(new ValueEval[] { new StringEval("2"), BlankEval.instance }, 0, 0)); - Assert.AreEqual(ErrorEval.NUM_ERROR, WeekdayFunc.instance.Evaluate(new ValueEval[] { new StringEval("3"), MissingArgEval.instance }, 0, 0)); - Assert.AreEqual(ErrorEval.NUM_ERROR, WeekdayFunc.instance.Evaluate(new ValueEval[] { new NumberEval(1.0), new NumberEval(18.0) }, 0, 0)); + assertEvaluateEquals("no args", ErrorEval.VALUE_INVALID); + assertEvaluateEquals("too many args", ErrorEval.VALUE_INVALID, new NumberEval(1.0), new NumberEval(1.0), new NumberEval(1.0)); + assertEvaluateEquals("negative date", ErrorEval.NUM_ERROR, new NumberEval(-1.0)); + assertEvaluateEquals("cannot coerce serial_number to number", ErrorEval.VALUE_INVALID, new StringEval("")); + assertEvaluateEquals("cannot coerce return_type to number", ErrorEval.VALUE_INVALID, new StringEval("1"), new StringEval("")); + assertEvaluateEquals("return_type is blank", ErrorEval.NUM_ERROR, new StringEval("2"), BlankEval.instance); + assertEvaluateEquals("return_type is missing", ErrorEval.NUM_ERROR, new StringEval("3"), MissingArgEval.instance); + assertEvaluateEquals("invalid return_type", ErrorEval.NUM_ERROR, new NumberEval(1.0), new NumberEval(18.0)); } } } \ No newline at end of file diff --git a/testcases/main/SS/Formula/PTG/TestArrayPtg.cs b/testcases/main/SS/Formula/PTG/TestArrayPtg.cs index c34a410ed..2361da8d9 100644 --- a/testcases/main/SS/Formula/PTG/TestArrayPtg.cs +++ b/testcases/main/SS/Formula/PTG/TestArrayPtg.cs @@ -64,15 +64,15 @@ public void TestReadWriteTokenValueBytes() ArrayPtg ptg = Create(ENCODED_PTG_DATA, ENCODED_CONSTANT_DATA); Assert.AreEqual(3, ptg.ColumnCount); Assert.AreEqual(2, ptg.RowCount); - Object[][] values = ptg.GetTokenArrayValues(); + Object[,] values = ptg.GetTokenArrayValues(); Assert.AreEqual(2, values.Length); - Assert.AreEqual(true, values[0][0]); - Assert.AreEqual("ABCD", values[0][1]); - Assert.AreEqual(0d, values[1][0]); - Assert.AreEqual(false, values[1][1]); - Assert.AreEqual("FG", values[1][2]); + Assert.AreEqual(true, values[0,0]); + Assert.AreEqual("ABCD", values[0,1]); + Assert.AreEqual(0d, values[1,0]); + Assert.AreEqual(false, values[1,1]); + Assert.AreEqual("FG", values[1,2]); byte[] outBuf = new byte[ENCODED_CONSTANT_DATA.Length]; ptg.WriteTokenValueBytes(new LittleEndianByteArrayOutputStream(outBuf, 0)); diff --git a/testcases/main/SS/Formula/TestFormulaShifter.cs b/testcases/main/SS/Formula/TestFormulaShifter.cs index 2bec1a513..858ef4d1f 100644 --- a/testcases/main/SS/Formula/TestFormulaShifter.cs +++ b/testcases/main/SS/Formula/TestFormulaShifter.cs @@ -271,7 +271,7 @@ public void TestInvalidArgument() FormulaShifter.CreateForRowShift(1, "name", 1, 2, 0, SpreadsheetVersion.EXCEL97); Assert.Fail("Should catch exception here"); } - catch (ArgumentException e) + catch (ArgumentException) { // expected here } @@ -280,7 +280,7 @@ public void TestInvalidArgument() FormulaShifter.CreateForRowShift(1, "name", 2, 1, 2, SpreadsheetVersion.EXCEL97); Assert.Fail("Should catch exception here"); } - catch (ArgumentException e) + catch (ArgumentException) { // expected here } diff --git a/testcases/main/SS/Formula/TestWorkbookEvaluator.cs b/testcases/main/SS/Formula/TestWorkbookEvaluator.cs index 2cd41aa1d..3314ea837 100644 --- a/testcases/main/SS/Formula/TestWorkbookEvaluator.cs +++ b/testcases/main/SS/Formula/TestWorkbookEvaluator.cs @@ -41,7 +41,10 @@ public class TestWorkbookEvaluator private static ValueEval EvaluateFormula(Ptg[] ptgs) { - OperationEvaluationContext ec = new OperationEvaluationContext(null, null, 0, 0, 0, null); + HSSFWorkbook wb = new HSSFWorkbook(); + wb.CreateSheet().CreateRow(0).CreateCell(0); + IEvaluationWorkbook ewb = HSSFEvaluationWorkbook.Create(wb); + OperationEvaluationContext ec = new OperationEvaluationContext(null, ewb, 0, 0, 0, null); return new WorkbookEvaluator(null, null, null).EvaluateFormula(ec, ptgs); } diff --git a/testcases/main/SS/UserModel/BaseTestBugzillaIssues.cs b/testcases/main/SS/UserModel/BaseTestBugzillaIssues.cs index aff2e911c..18376c24a 100644 --- a/testcases/main/SS/UserModel/BaseTestBugzillaIssues.cs +++ b/testcases/main/SS/UserModel/BaseTestBugzillaIssues.cs @@ -1111,7 +1111,7 @@ public void Test57973() IFont font = wb.CreateFont(); font.FontName = ("Arial"); font.FontHeightInPoints = ((short)14); - font.Boldweight = (short)FontBoldWeight.Bold;// (Font.BOLDWEIGHT_BOLD); + font.IsBold=true; font.Color = (IndexedColors.Red.Index); str2.ApplyFont(font); diff --git a/testcases/main/SS/UserModel/BaseTestCloneSheet.cs b/testcases/main/SS/UserModel/BaseTestCloneSheet.cs index 17fbb5209..cf0368b69 100644 --- a/testcases/main/SS/UserModel/BaseTestCloneSheet.cs +++ b/testcases/main/SS/UserModel/BaseTestCloneSheet.cs @@ -85,7 +85,7 @@ public void TestCloneSheetIntValid() wb.CloneSheet(2); Assert.Fail("ShouldFail"); } - catch (ArgumentException e) + catch (ArgumentException) { // expected here } @@ -101,7 +101,7 @@ public void TestCloneSheetIntInvalid() wb.CloneSheet(1); Assert.Fail("Should Fail"); } - catch (ArgumentException e) + catch (ArgumentException) { // expected here } diff --git a/testcases/main/SS/UserModel/BaseTestSheet.cs b/testcases/main/SS/UserModel/BaseTestSheet.cs index fda9687ce..2076d8f82 100644 --- a/testcases/main/SS/UserModel/BaseTestSheet.cs +++ b/testcases/main/SS/UserModel/BaseTestSheet.cs @@ -357,7 +357,7 @@ public void AddMergedRegionWithSingleCellShouldFail() sheet.AddMergedRegion(region); Assert.Fail("Should not be able to add a single-cell merged region (" + region.FormatAsString() + ")"); } - catch (ArgumentException e) + catch (ArgumentException) { // expected } diff --git a/testcases/main/SS/UserModel/BaseTestSheetUpdateArrayFormulas.cs b/testcases/main/SS/UserModel/BaseTestSheetUpdateArrayFormulas.cs index 49b2af015..945ee5626 100644 --- a/testcases/main/SS/UserModel/BaseTestSheetUpdateArrayFormulas.cs +++ b/testcases/main/SS/UserModel/BaseTestSheetUpdateArrayFormulas.cs @@ -650,7 +650,7 @@ public void ShouldNotBeAbleToCreateArrayFormulaOnPreexistingMergedRegion() sheet.SetArrayFormula("SUM(A1:A3)", arrayFormula); Assert.Fail("expected exception: should not be able to create an array formula that intersects with a merged region"); } - catch (InvalidOperationException e) + catch (InvalidOperationException) { // expected } diff --git a/testcases/main/SS/UserModel/BaseTestWorkbook.cs b/testcases/main/SS/UserModel/BaseTestWorkbook.cs index f2584b788..5838dbd67 100644 --- a/testcases/main/SS/UserModel/BaseTestWorkbook.cs +++ b/testcases/main/SS/UserModel/BaseTestWorkbook.cs @@ -262,41 +262,27 @@ public void TestCreateSheetWithLongNames() IWorkbook wb1 = _testDataProvider.CreateWorkbook(); String sheetName1 = "My very long sheet name which is longer than 31 chars"; - String tRuncatedSheetName1 = sheetName1.Substring(0, 31); - ISheet sh1 = wb1.CreateSheet(sheetName1); - Assert.AreEqual(tRuncatedSheetName1, sh1.SheetName); - Assert.AreSame(sh1, wb1.GetSheet(tRuncatedSheetName1)); - // now via wb.SetSheetName - wb1.SetSheetName(0, sheetName1); - Assert.AreEqual(tRuncatedSheetName1, sh1.SheetName); - Assert.AreSame(sh1, wb1.GetSheet(tRuncatedSheetName1)); - - String sheetName2 = "My very long sheet name which is longer than 31 chars " + - "and sheetName2.Substring(0, 31) == sheetName1.Substring(0, 31)"; try { - ISheet sh2 = wb1.CreateSheet(sheetName2); + ISheet sh1 = wb1.CreateSheet(sheetName1); Assert.Fail("expected exception"); } - catch (ArgumentException e) + catch (ArgumentException ex) { - // expected during successful Test - Assert.AreEqual("The workbook already contains a sheet named 'My very long sheet name which is longer than 31 chars and sheetName2.Substring(0, 31) == sheetName1.Substring(0, 31)'", e.Message); + Assert.IsTrue(ex.Message.StartsWith("sheetName 'My very long sheet name which is longer than 31 chars' is invalid")); + } + try + { + wb1.CreateSheet("test"); + // now via wb.SetSheetName + wb1.SetSheetName(0, sheetName1); + Assert.Fail("expected exception"); + } + catch (ArgumentException ex) + { + Assert.IsTrue(ex.Message.StartsWith("sheetName 'My very long sheet name which is longer than 31 chars' is invalid")); } - - String sheetName3 = "POI allows creating sheets with names longer than 31 characters"; - String tRuncatedSheetName3 = sheetName3.Substring(0, 31); - ISheet sh3 = wb1.CreateSheet(sheetName3); - Assert.AreEqual(tRuncatedSheetName3, sh3.SheetName); - Assert.AreSame(sh3, wb1.GetSheet(tRuncatedSheetName3)); - - //serialize and read again - IWorkbook wb2 = _testDataProvider.WriteOutAndReadBack(wb1); wb1.Close(); - Assert.AreEqual(2, wb2.NumberOfSheets); - Assert.AreEqual(0, wb2.GetSheetIndex(tRuncatedSheetName1)); - Assert.AreEqual(1, wb2.GetSheetIndex(tRuncatedSheetName3)); - wb2.Close(); } [Test] @@ -847,7 +833,7 @@ public void Test58499() OutputStream os = new NullOutputStream(); try { - workbook.Write(os); + workbook.Write(os, false); } finally { diff --git a/testcases/main/SS/Util/TestDateFormatConverter.cs b/testcases/main/SS/Util/TestDateFormatConverter.cs index 911066d4f..d5696c7a9 100644 --- a/testcases/main/SS/Util/TestDateFormatConverter.cs +++ b/testcases/main/SS/Util/TestDateFormatConverter.cs @@ -122,7 +122,7 @@ private void OutputLocaleDataFormats(DateTime date, bool dates, bool times, int FileStream outputStream = new FileStream(filename, FileMode.Create); try { - workbook.Write(outputStream); + workbook.Write(outputStream, false); } finally { diff --git a/testcases/main/SS/Util/Utils.cs b/testcases/main/SS/Util/Utils.cs index b53f07f8a..ce1f54be3 100644 --- a/testcases/main/SS/Util/Utils.cs +++ b/testcases/main/SS/Util/Utils.cs @@ -8,14 +8,20 @@ namespace TestCases.SS.Util { public static class Utils { - - public static void AssertDouble(IFormulaEvaluator fe, ICell cell, string formula, double expectedResult) + public static void AssertString(IFormulaEvaluator fe, ICell cell, string formula, string expectedResult) { cell.SetCellFormula(formula); - var result = fe.Evaluate(cell).NumberValue; + var result = fe.Evaluate(cell).StringValue; fe.ClearAllCachedResultValues(); Assert.AreEqual(expectedResult, result); } + public static void AssertDouble(IFormulaEvaluator fe, ICell cell, string formula, double expectedResult, double delta=0.0) + { + cell.SetCellFormula(formula); + var result = fe.Evaluate(cell).NumberValue; + fe.ClearAllCachedResultValues(); + Assert.AreEqual(expectedResult, result, delta); + } public static void AssertError(IFormulaEvaluator fe, ICell cell, string formula, FormulaError expectedError) { diff --git a/testcases/ooxml/NPOI.OOXML.TestCases.csproj b/testcases/ooxml/NPOI.OOXML.TestCases.csproj index 6f59cb820..29cc244cf 100644 --- a/testcases/ooxml/NPOI.OOXML.TestCases.csproj +++ b/testcases/ooxml/NPOI.OOXML.TestCases.csproj @@ -228,7 +228,6 @@ - @@ -311,11 +310,14 @@ 3.13.1 + + 4.2.1 + 1.8.9 - 1.3.2 + 1.3.3
diff --git a/testcases/ooxml/POIFS/Crypt/TestSecureTempZip.cs b/testcases/ooxml/POIFS/Crypt/TestSecureTempZip.cs index 491ba8ca7..eb774cdd1 100644 --- a/testcases/ooxml/POIFS/Crypt/TestSecureTempZip.cs +++ b/testcases/ooxml/POIFS/Crypt/TestSecureTempZip.cs @@ -37,7 +37,7 @@ public class TestSecureTempZip * Test case for #59841 - this is an example on how to use encrypted temp files, * which are streamed into POI opposed to having everything in memory */ - [Test] + [Ignore("not implemented")] public void ProtectedTempZip() { FileInfo tmpFile = TempFile.CreateTempFile("protectedXlsx", ".zip"); diff --git a/testcases/ooxml/POIFS/Crypt/TestSignatureInfo.cs b/testcases/ooxml/POIFS/Crypt/TestSignatureInfo.cs index 007e343b7..76b912420 100644 --- a/testcases/ooxml/POIFS/Crypt/TestSignatureInfo.cs +++ b/testcases/ooxml/POIFS/Crypt/TestSignatureInfo.cs @@ -242,7 +242,7 @@ public void TestSignSpreadsheet() throw new NotImplementedException(); } - [Test] + [Ignore("not implemented")] public void TestSignEnvelopingDocument() { String testFile = "hello-world-unsigned.xlsx"; //OPCPackage pkg = OPCPackage.Open(copy(testdata.GetFile(testFile)), PackageAccess.READ_WRITE); @@ -476,7 +476,7 @@ public void TestSignSpreadsheet() throw new NotImplementedException(); } - [Test] + [Ignore("not implemented")] public void TestNonSha1() { String testFile = "hello-world-unsigned.xlsx"; InitKeyPair("Test", "CN=Test"); diff --git a/testcases/ooxml/SS/TestWorkbookFactory.cs b/testcases/ooxml/SS/TestWorkbookFactory.cs index b50dff5ac..ca24f721c 100644 --- a/testcases/ooxml/SS/TestWorkbookFactory.cs +++ b/testcases/ooxml/SS/TestWorkbookFactory.cs @@ -359,7 +359,7 @@ public void TestEmptyInputStream() WorkbookFactory.Create(emptyStream,true); Assert.Fail("Shouldn't be able to create for an empty stream"); } - catch (EmptyFileException e) + catch (EmptyFileException ) { } } @@ -376,7 +376,7 @@ public void TestEmptyFile() WorkbookFactory.Create(emptyFile.FullName); Assert.Fail("Shouldn't be able to create for an empty file"); } - catch (EmptyFileException e) + catch (EmptyFileException ) { } emptyFile.Delete(); diff --git a/testcases/ooxml/SS/UserModel/TestFormulaParser.cs b/testcases/ooxml/SS/UserModel/TestFormulaParser.cs index 5cd608b9b..6fcd9de95 100644 --- a/testcases/ooxml/SS/UserModel/TestFormulaParser.cs +++ b/testcases/ooxml/SS/UserModel/TestFormulaParser.cs @@ -38,7 +38,7 @@ public void TestHSSFFailsForOver65536() FormulaParser.Parse("Sheet1!1:65537", workbook, FormulaType.Cell, 0); Assert.Fail("Expected exception"); } - catch (FormulaParseException expected) + catch (FormulaParseException) { } } diff --git a/testcases/ooxml/XSSF/SXSSFITestDataProvider.cs b/testcases/ooxml/XSSF/SXSSFITestDataProvider.cs index a9c387f71..dbc5876ed 100644 --- a/testcases/ooxml/XSSF/SXSSFITestDataProvider.cs +++ b/testcases/ooxml/XSSF/SXSSFITestDataProvider.cs @@ -66,7 +66,7 @@ public IWorkbook WriteOutAndReadBack(IWorkbook wb) try { MemoryStream baos = new MemoryStream(8192); - wb.Write(baos); + wb.Write(baos, false); Stream is1 = new MemoryStream(baos.ToArray()); result = new XSSFWorkbook(is1); } diff --git a/testcases/ooxml/XSSF/Streaming/SheetDataWriterTests.cs b/testcases/ooxml/XSSF/Streaming/SheetDataWriterTests.cs index ca58d8fde..c2d5add08 100644 --- a/testcases/ooxml/XSSF/Streaming/SheetDataWriterTests.cs +++ b/testcases/ooxml/XSSF/Streaming/SheetDataWriterTests.cs @@ -16,6 +16,7 @@ ==================================================================== */ using NPOI.SS.UserModel; using NPOI.XSSF.Streaming; +using NPOI.XSSF.UserModel; using NSubstitute; using NUnit.Framework; using System.IO; @@ -32,7 +33,10 @@ public class SheetDataWriterTests [SetUp] public void Init() { - _row = Substitute.For(); + var _xssfsheet = Substitute.For(); + var _workbook = Substitute.For(); + var _sheet = Substitute.For(_workbook, _xssfsheet); + _row = Substitute.For(_sheet); _cell = Substitute.For(); } diff --git a/testcases/ooxml/XSSF/Streaming/TestSXSSFWorkbook.cs b/testcases/ooxml/XSSF/Streaming/TestSXSSFWorkbook.cs index 9ac06a4a8..d0c37a37b 100644 --- a/testcases/ooxml/XSSF/Streaming/TestSXSSFWorkbook.cs +++ b/testcases/ooxml/XSSF/Streaming/TestSXSSFWorkbook.cs @@ -450,7 +450,7 @@ private static void saveTwice(IWorkbook wb) try { NullOutputStream out1 = new NullOutputStream(); - wb.Write(out1); + wb.Write(out1, false); out1.Close(); } catch (Exception e) diff --git a/testcases/ooxml/XSSF/TestXLookupFunction.cs b/testcases/ooxml/XSSF/TestXLookupFunction.cs new file mode 100644 index 000000000..70c66d72c --- /dev/null +++ b/testcases/ooxml/XSSF/TestXLookupFunction.cs @@ -0,0 +1,58 @@ +using NPOI.SS.UserModel; +using NPOI.SS.Util; +using NPOI.Util; +using NPOI.XSSF.UserModel; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace TestCases.XSSF +{ + [TestFixture] + public class TestXLookupFunction + { + [Test] + public void TestMicrosoftExample1() + { + String formulaText = "XLOOKUP(B2,B5:B14,C5:D14)"; + XSSFWorkbook wb = initWorkbook2(); + XSSFFormulaEvaluator fe = new XSSFFormulaEvaluator(wb); + ISheet sheet = wb.GetSheetAt(0); + IRow row1 = sheet.GetRow(1); + String col1 = CellReference.ConvertNumToColString(2); + String col2 = CellReference.ConvertNumToColString(3); + String cellRef = $"{col1}2:{col2}2"; + sheet.SetArrayFormula(formulaText, CellRangeAddress.ValueOf(cellRef)); + fe.EvaluateAll(); + FileInfo fi = TempFile.CreateTempFile("xlook", ".xlsx"); + using (FileStream file = new FileStream(fi.FullName, FileMode.Open, FileAccess.ReadWrite)) + { + wb.Write(file, false); + } + Assert.AreEqual("Dianne Pugh", row1.GetCell(2).StringCellValue); + //next assertion fails, cell D2 ends up with Dianne Pugh + Assert.AreEqual("Finance", row1.GetCell(3).StringCellValue); + } + private XSSFWorkbook initWorkbook2() + { + XSSFWorkbook wb = new XSSFWorkbook(); + ISheet sheet = wb.CreateSheet(); + SS.Util.Utils.AddRow(sheet, 0, null, "Emp Id", "Employee Name", "Department"); + SS.Util.Utils.AddRow(sheet, 1, null, 8389); + SS.Util.Utils.AddRow(sheet, 3, null, "Emp Id", "Employee Name", "Department"); + SS.Util.Utils.AddRow(sheet, 4, null, 4390, "Ned Lanning", "Marketing"); + SS.Util.Utils.AddRow(sheet, 5, null, 8604, "Margo Hendrix", "Sales"); + SS.Util.Utils.AddRow(sheet, 6, null, 8389, "Dianne Pugh", "Finance"); + SS.Util.Utils.AddRow(sheet, 7, null, 4937, "Earlene McCarty", "Accounting"); + SS.Util.Utils.AddRow(sheet, 8, null, 8299, "Mia Arnold", "Operation"); + SS.Util.Utils.AddRow(sheet, 9, null, 2643, "Jorge Fellows", "Executive"); + SS.Util.Utils.AddRow(sheet, 10, null, 5243, "Rose Winters", "Sales"); + SS.Util.Utils.AddRow(sheet, 11, null, 9693, "Carmela Hahn", "Finance"); + SS.Util.Utils.AddRow(sheet, 12, null, 1636, "Delia Cochran", "Accounting"); + SS.Util.Utils.AddRow(sheet, 13, null, 6703, "Marguerite Cervantes", "Marketing"); + return wb; + } + } +} diff --git a/testcases/ooxml/XSSF/TestXSSFCloneSheet.cs b/testcases/ooxml/XSSF/TestXSSFCloneSheet.cs index 8889f9dae..aad263620 100644 --- a/testcases/ooxml/XSSF/TestXSSFCloneSheet.cs +++ b/testcases/ooxml/XSSF/TestXSSFCloneSheet.cs @@ -54,7 +54,7 @@ public TestXSSFCloneSheet() try { wb.CloneSheet(0, VALID_SHEET_NAME); Assert.Fail("Should fail"); - } catch (ArgumentException e) { + } catch (ArgumentException) { // expected here } Assert.AreEqual(1, wb.NumberOfSheets); diff --git a/testcases/ooxml/XSSF/TestXSSFOffset.cs b/testcases/ooxml/XSSF/TestXSSFOffset.cs new file mode 100644 index 000000000..4a95cc398 --- /dev/null +++ b/testcases/ooxml/XSSF/TestXSSFOffset.cs @@ -0,0 +1,27 @@ +using NPOI.SS.UserModel; +using NPOI.XSSF.UserModel; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Text; + +namespace TestCases.XSSF +{ + [TestFixture] + class TestXSSFOffset + { + [Test] + public void TestOffsetWithEmpty23Arguments() + { + IWorkbook workbook = new XSSFWorkbook(); + ICell cell = workbook.CreateSheet().CreateRow(0).CreateCell(0); + cell.SetCellFormula("OFFSET(B1,,)"); + String value = "EXPECTED_VALUE"; + ICell valueCell = cell.Row.CreateCell(1); + valueCell.SetCellValue(value); + workbook.GetCreationHelper().CreateFormulaEvaluator().EvaluateAll(); + Assert.AreEqual(CellType.String, cell.CachedFormulaResultType); + Assert.AreEqual(value, cell.StringCellValue); + } + } +} diff --git a/testcases/ooxml/XSSF/UserModel/BaseTestXSSFPivotTable.cs b/testcases/ooxml/XSSF/UserModel/BaseTestXSSFPivotTable.cs index 5ccd19245..9e0aec053 100644 --- a/testcases/ooxml/XSSF/UserModel/BaseTestXSSFPivotTable.cs +++ b/testcases/ooxml/XSSF/UserModel/BaseTestXSSFPivotTable.cs @@ -293,34 +293,6 @@ public void TestAddDataColumnWithOffsetData() offsetPivotTable.AddColumnLabel(DataConsolidateFunction.SUM, 0); } - [Ignore("not found in poi")] - [Test] - public void Test58294() - { - //XSSFWorkbook wb = new XSSFWorkbook("C:\\temp\\test1.xlsx"); - //XSSFSheet sheet = wb.GetSheetAt(1) as XSSFSheet; - //XSSFSheet sheet0 = wb.GetSheetAt(0) as XSSFSheet; - //sheet0.SetActiveCell("A4"); - //XSSFPivotTable pivotTable = sheet0.CreatePivotTable(new AreaReference("A3:H6"), new CellReference("A4"), sheet); - //pivotTable.AddRowLabel(1); - //pivotTable.AddRowLabel(3); - //pivotTable.AddRowLabel(5); - //pivotTable.AddColumnLabel(DataConsolidateFunction.SUM, 6, "Sum of days with hauls"); - //pivotTable.AddColumnLabel(DataConsolidateFunction.SUM, 7, "Sum of days site cutoff"); - ////checkPivotTables(wb); - //FileStream fileOut = new FileStream("c:\\temp\\test2new.xlsx", FileMode.Create, FileAccess.ReadWrite); - //try - //{ - // wb.Write(fileOut); - //} - //finally - //{ - // fileOut.Close(); - //} - //XSSFWorkbook wbBack = XSSFTestDataSamples.WriteOutAndReadBack(wb); - ////checkPivotTables(wbBack); - //wb.Close(); - } private void checkPivotTables(XSSFWorkbook wb) { IList pivotTables = (wb.GetSheetAt(0) as XSSFSheet).GetPivotTables(); diff --git a/testcases/ooxml/XSSF/UserModel/Extensions/TestXSSFCellFill.cs b/testcases/ooxml/XSSF/UserModel/Extensions/TestXSSFCellFill.cs index f5ce083d0..4c9a9db5b 100644 --- a/testcases/ooxml/XSSF/UserModel/Extensions/TestXSSFCellFill.cs +++ b/testcases/ooxml/XSSF/UserModel/Extensions/TestXSSFCellFill.cs @@ -76,7 +76,7 @@ public void TestColorFromTheme() XSSFCell cellWithThemeColor = (XSSFCell)wb.GetSheetAt(0).GetRow(10).GetCell(0); //color RGB will be extracted from theme XSSFColor foregroundColor = (XSSFColor)((XSSFCellStyle)cellWithThemeColor.CellStyle).FillForegroundColorColor; - byte[] rgb = foregroundColor.GetRgb(); + byte[] rgb = foregroundColor.RGB; byte[] rgbWithTint = foregroundColor.GetRgbWithTint(); // Dk2 Assert.AreEqual(rgb[0], 31); diff --git a/testcases/ooxml/XSSF/UserModel/TestUnfixedBugs.cs b/testcases/ooxml/XSSF/UserModel/TestUnfixedBugs.cs index 1ebb57ba5..79e2c31db 100644 --- a/testcases/ooxml/XSSF/UserModel/TestUnfixedBugs.cs +++ b/testcases/ooxml/XSSF/UserModel/TestUnfixedBugs.cs @@ -247,7 +247,7 @@ public void TestBug55752() Stream stream = new FileStream("55752.xlsx", FileMode.Create, FileAccess.ReadWrite); try { - wb.Write(stream); + wb.Write(stream, false); } finally { diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFBugs.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFBugs.cs index 9e461da5e..8d3137542 100644 --- a/testcases/ooxml/XSSF/UserModel/TestXSSFBugs.cs +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFBugs.cs @@ -300,7 +300,7 @@ public void Bug48539() { wb.Close(); } - + } /** @@ -690,10 +690,10 @@ public void Test49966() sheet.GetRow(1).GetCell(0).SetCellFormula("A1"); // stay sheet.GetRow(2).GetCell(0).SetCellFormula(null); // go sheet.GetRow(3).GetCell(0).SetCellType(CellType.Formula); // stay - + XSSFTestDataSamples.WriteOutAndReadBack(wb1).Close(); sheet.GetRow(4).GetCell(0).SetCellType(CellType.String); // go - + XSSFTestDataSamples.WriteOutAndReadBack(wb1).Close(); validateCells(sheet); @@ -701,14 +701,14 @@ public void Test49966() sheet.GetRow(5).GetCell(0) // go ); validateCells(sheet); - + XSSFTestDataSamples.WriteOutAndReadBack(wb1).Close(); sheet.GetRow(6).GetCell(0).SetCellType(CellType.Blank); // go - + XSSFTestDataSamples.WriteOutAndReadBack(wb1).Close(); sheet.GetRow(7).GetCell(0).SetCellValue((String)null); // go - + XSSFTestDataSamples.WriteOutAndReadBack(wb1).Close(); // Save and check @@ -964,7 +964,7 @@ public void Test50784() XSSFFont fr = wb.GetFontAt(cr.CellStyle.FontIndex) as XSSFFont; XSSFColor colr = fr.GetXSSFColor(); // No theme, has colours Assert.AreEqual(0, colr.Theme); - Assert.IsNotNull(colr.GetRgb()); + Assert.IsNotNull(colr.RGB); // Column 0 has a font with colours from a theme XSSFCell ct = r.GetCell(0) as XSSFCell; @@ -973,8 +973,8 @@ public void Test50784() // Has a theme, which has the colours on it Assert.AreEqual(9, colt.Theme); XSSFColor themeC = wb.GetTheme().GetThemeColor(colt.Theme); - Assert.IsNotNull(themeC.GetRgb()); - Assert.IsNotNull(colt.GetRgb()); + Assert.IsNotNull(themeC.RGB); + Assert.IsNotNull(colt.RGB); Assert.AreEqual(themeC.ARGBHex, colt.ARGBHex); // The same colour wb.Close(); @@ -1483,7 +1483,7 @@ public void Test51963() XSSFName name = wb.GetName("Intekon.ProdCodes") as XSSFName; Assert.AreEqual("'Abc,1'!$A$1:$A$2", name.RefersToFormula); - AreaReference ref1 = new AreaReference(name.RefersToFormula); + AreaReference ref1 = new AreaReference(name.RefersToFormula, NPOI.SS.SpreadsheetVersion.EXCEL2007); Assert.AreEqual(0, ref1.FirstCell.Row); Assert.AreEqual(0, ref1.FirstCell.Col); Assert.AreEqual(1, ref1.LastCell.Row); @@ -1497,8 +1497,8 @@ public void Test51963() * eg =SUM($Sheet1.C1:$Sheet4.C1) * DISABLED As we can't currently Evaluate these */ - [Ignore("by poi")] - [Test] + [Ignore("by poi")] + [Test] public void Test48703() { XSSFWorkbook wb = XSSFTestDataSamples.OpenSampleWorkbook("48703.xlsx"); @@ -1628,7 +1628,7 @@ public void Test55692() WorkbookFactory.Create(inpA); Assert.Fail("Should've raised a EncryptedDocumentException error"); } - catch (EncryptedDocumentException e) { } + catch (EncryptedDocumentException ) { } // Via a POIFSFileSystem POIFSFileSystem fsP = new POIFSFileSystem(inpB); @@ -1637,7 +1637,7 @@ public void Test55692() WorkbookFactory.Create(fsP); Assert.Fail("Should've raised a EncryptedDocumentException error"); } - catch (EncryptedDocumentException e) { } + catch (EncryptedDocumentException) { } // Via a NPOIFSFileSystem NPOIFSFileSystem fsNP = new NPOIFSFileSystem(inpC); @@ -1646,7 +1646,7 @@ public void Test55692() WorkbookFactory.Create(fsNP); Assert.Fail("Should've raised a EncryptedDocumentException error"); } - catch (EncryptedDocumentException e) { } + catch (EncryptedDocumentException) { } } [Test] public void Bug53282() @@ -1928,7 +1928,7 @@ private void saveAndReloadReport(IWorkbook wb, FileInfo outFile) } FileStream fileOutStream = new FileStream(outFile.FullName, FileMode.Open, FileAccess.ReadWrite); - wb.Write(fileOutStream); + wb.Write(fileOutStream, false); fileOutStream.Close(); //System.out.Println("File \""+outFile.Name+"\" has been saved successfully"); @@ -2151,7 +2151,7 @@ public void Bug56800_xlsb() new XSSFWorkbook(pkg).Close(); Assert.Fail(".xlsb files not supported"); } - catch (XLSBUnsupportedException e) + catch (XLSBUnsupportedException) { // Good, detected and warned } @@ -2162,7 +2162,7 @@ public void Bug56800_xlsb() WorkbookFactory.Create(pkg).Close(); Assert.Fail(".xlsb files not supported"); } - catch (XLSBUnsupportedException e) + catch (XLSBUnsupportedException) { // Good, detected and warned } @@ -2174,7 +2174,7 @@ public void Bug56800_xlsb() WorkbookFactory.Create(xlsbFile.FullName).Close(); Assert.Fail(".xlsb files not supported"); } - catch (XLSBUnsupportedException e) + catch (XLSBUnsupportedException) { // Good, detected and warned } @@ -2644,7 +2644,8 @@ public void TestBug56295_MergeXlslsWithStyles() * Excel treats this as not-bulleted, so now do we */ [Test] - public void TestBug57826() { + public void TestBug57826() + { XSSFWorkbook workbook = XSSFTestDataSamples.OpenSampleWorkbook("57826.xlsx"); Assert.IsTrue(workbook.NumberOfSheets >= 1, "no sheets in workbook"); @@ -2664,7 +2665,7 @@ public void TestBug56295_MergeXlslsWithStyles() // No bulleting info included Assert.AreEqual("test ok", text); - + workbook.Close(); } @@ -3195,7 +3196,7 @@ private void CreateXls() ICellStyle style = workbook.CreateCellStyle(); style.Rotation = ((short)-90); cell1.CellStyle = (style); - workbook.Write(fileOut); + workbook.Write(fileOut, false); fileOut.Close(); workbook.Close(); } @@ -3210,7 +3211,7 @@ private void CreateXlsx() ICellStyle style = workbook.CreateCellStyle(); style.Rotation = ((short)-90); cell1.CellStyle = (style); - workbook.Write(fileOut); + workbook.Write(fileOut, false); fileOut.Close(); workbook.Close(); } @@ -3359,6 +3360,24 @@ public void TestWorkdayFunction() String result = form.FormatCellValue(cell, evaluator); Assert.AreEqual("09 Mar 2016", result); } + + [Test] + public void Bug61063() + { + IWorkbook wb = XSSFTestDataSamples.OpenSampleWorkbook("61063.xlsx"); + + IFormulaEvaluator eval = wb.GetCreationHelper().CreateFormulaEvaluator(); + ISheet s = wb.GetSheetAt(0); + + IRow r = s.GetRow(3); + ICell c = r.GetCell(0); + Assert.AreEqual(CellType.Formula, c.CellType); + eval.DebugEvaluationOutputForNextEval = true; + CellValue cv = eval.Evaluate(c); + Assert.IsNotNull(cv); + Assert.AreEqual(2.0, cv.NumberValue, 0.00001); + wb.Close(); + } } } \ No newline at end of file diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFCell.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFCell.cs index ad122c83f..8a49f6cf1 100644 --- a/testcases/ooxml/XSSF/UserModel/TestXSSFCell.cs +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFCell.cs @@ -28,6 +28,7 @@ using System.Collections.Generic; using NPOI.XSSF; using NPOI.XSSF.UserModel; +using NPOI.SS.Formula; namespace TestCases.XSSF.UserModel { @@ -160,6 +161,51 @@ public void TestFormulaString() Assert.AreEqual(CellType.Blank, cell.CellType); Assert.AreEqual(ST_CellType.n, ctCell.t); Assert.AreEqual(cell.StringCellValue, ""); + + // check behavior with setCellFormulaValidation + String invalidFormula = "A", validFormula = "A2"; + FormulaParseException fpe = null; + // check that default is true + Assert.IsTrue(wb.CellFormulaValidation); + + // check that valid formula does not throw exception + try + { + cell.SetCellFormula(validFormula); + } + catch (FormulaParseException e) + { + fpe = e; + } + Assert.IsNull(fpe); + + // check that invalid formula does throw exception + try + { + cell.SetCellFormula(invalidFormula); + } + catch (FormulaParseException e) + { + fpe = e; + } + Assert.IsNotNull(fpe); + fpe = null; + + // set cell formula validation to false + wb.CellFormulaValidation = false; + Assert.IsFalse(wb.CellFormulaValidation); + + // check that neither valid nor invalid formula throw an exception + try + { + cell.SetCellFormula(validFormula); + cell.SetCellFormula(invalidFormula); + } + catch (FormulaParseException e) + { + fpe = e; + } + Assert.IsNull(fpe); } /** diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFCellStyle.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFCellStyle.cs index 81f64074a..82aa454a0 100644 --- a/testcases/ooxml/XSSF/UserModel/TestXSSFCellStyle.cs +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFCellStyle.cs @@ -415,10 +415,10 @@ public void TestGetSetBottomBorderColor() clr = new XSSFColor(Color.Cyan); cellStyle.SetBottomBorderColor(clr); Assert.AreEqual(clr.GetCTColor().ToString(), cellStyle.BottomBorderXSSFColor.GetCTColor().ToString()); - byte[] rgb = cellStyle.BottomBorderXSSFColor.GetRgb(); + byte[] rgb = cellStyle.BottomBorderXSSFColor.RGB; Assert.AreEqual(Color.Cyan.ToArgb(), Color.FromArgb(rgb[0] & 0xFF, rgb[1] & 0xFF, rgb[2] & 0xFF).ToArgb()); //another border was Added to the styles table - Assert.AreEqual(num, stylesTable.GetBorders().Count); + Assert.AreEqual(num+1, stylesTable.GetBorders().Count); //passing null unsets the color cellStyle.SetBottomBorderColor(null); @@ -456,7 +456,7 @@ public void TestGetSetTopBorderColor() clr = new XSSFColor(Color.Cyan); cellStyle.SetTopBorderColor(clr); Assert.AreEqual(clr.GetCTColor().ToString(), cellStyle.TopBorderXSSFColor.GetCTColor().ToString()); - byte[] rgb = cellStyle.TopBorderXSSFColor.GetRgb(); + byte[] rgb = cellStyle.TopBorderXSSFColor.RGB; Assert.AreEqual(Color.Cyan.ToArgb(), Color.FromArgb(rgb[0], rgb[1], rgb[2]).ToArgb()); //another border was added to the styles table Assert.AreEqual(num, stylesTable.GetBorders().Count); @@ -497,7 +497,7 @@ public void TestGetSetLeftBorderColor() clr = new XSSFColor(Color.Cyan); cellStyle.SetLeftBorderColor(clr); Assert.AreEqual(clr.GetCTColor().ToString(), cellStyle.LeftBorderXSSFColor.GetCTColor().ToString()); - byte[] rgb = cellStyle.LeftBorderXSSFColor.GetRgb(); + byte[] rgb = cellStyle.LeftBorderXSSFColor.RGB; Assert.AreEqual(Color.Cyan.ToArgb(), Color.FromArgb(rgb[0] & 0xFF, rgb[1] & 0xFF, rgb[2] & 0xFF).ToArgb()); //another border was Added to the styles table Assert.AreEqual(num, stylesTable.GetBorders().Count); @@ -538,7 +538,7 @@ public void TestGetSetRightBorderColor() clr = new XSSFColor(Color.Cyan); cellStyle.SetRightBorderColor(clr); Assert.AreEqual(clr.GetCTColor().ToString(), cellStyle.RightBorderXSSFColor.GetCTColor().ToString()); - byte[] rgb = cellStyle.RightBorderXSSFColor.GetRgb(); + byte[] rgb = cellStyle.RightBorderXSSFColor.RGB; Assert.AreEqual(Color.Cyan.ToArgb(), Color.FromArgb(rgb[0] & 0xFF, rgb[1] & 0xFF, rgb[2] & 0xFF).ToArgb()); //another border was Added to the styles table Assert.AreEqual(num, stylesTable.GetBorders().Count); @@ -580,7 +580,7 @@ public void TestGetSetFillBackgroundColor() clr = new XSSFColor(Color.Cyan); cellStyle.SetFillBackgroundColor(clr); // TODO this testcase assumes that cellStyle creates a new CT_Fill, but the implementation changes the existing style. - do not know whats right 8-( Assert.AreEqual(clr.GetCTColor().ToString(), ((XSSFColor)cellStyle.FillBackgroundColorColor).GetCTColor().ToString()); - byte[] rgb = ((XSSFColor)cellStyle.FillBackgroundColorColor).GetRgb(); + byte[] rgb = ((XSSFColor)cellStyle.FillBackgroundColorColor).RGB; Assert.AreEqual(Color.Cyan.ToArgb(), Color.FromArgb(rgb[0] & 0xFF, rgb[1] & 0xFF, rgb[2] & 0xFF).ToArgb()); //another border was added to the styles table Assert.AreEqual(num + 1, stylesTable.GetFills().Count); diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFComment.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFComment.cs index 5c437e1cf..1f87d9a6a 100644 --- a/testcases/ooxml/XSSF/UserModel/TestXSSFComment.cs +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFComment.cs @@ -285,7 +285,7 @@ public void TestBug58175a() FileStream out1 = new FileStream("C:\\temp\\58175.xlsx", FileMode.CreateNew, FileAccess.ReadWrite); try { - wb.Write(out1); + wb.Write(out1, false); } finally { diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFDrawing.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFDrawing.cs index c27ee9ee1..f4d7dc14d 100644 --- a/testcases/ooxml/XSSF/UserModel/TestXSSFDrawing.cs +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFDrawing.cs @@ -800,7 +800,7 @@ public void TestBug56835CellComment() Drawing.CreateCellComment(anchor); Assert.Fail("Should fail if we try to add the same comment for the same cell"); } - catch (ArgumentException e) + catch (ArgumentException ) { // expected } diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFHyperlink.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFHyperlink.cs index b884c58a5..69fabc2a7 100644 --- a/testcases/ooxml/XSSF/UserModel/TestXSSFHyperlink.cs +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFHyperlink.cs @@ -245,7 +245,7 @@ private static void doTestHyperlinkContents(XSSFSheet sheet) sheet.GetRow(16).GetCell(2).Hyperlink.Type); Assert.AreEqual(null, sheet.GetRow(16).GetCell(2).Hyperlink.Label); - Assert.AreEqual("mailto:dev@poi.apache.org?subject=XSSF Hyperlinks", + Assert.AreEqual("mailto:dev@poi.apache.org?subject=XSSF%20Hyperlinks", sheet.GetRow(16).GetCell(2).Hyperlink.Address); } [Test] diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFRichTextString.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFRichTextString.cs index 1170580f7..b9295ed96 100644 --- a/testcases/ooxml/XSSF/UserModel/TestXSSFRichTextString.cs +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFRichTextString.cs @@ -127,7 +127,7 @@ public void TestApplyFontWithStyles() rt.ApplyFont(0, 10, (short)1); Assert.Fail("Fails without styles in the table"); } - catch (ArgumentOutOfRangeException e) + catch (ArgumentOutOfRangeException ) { // expected } diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFSheetRowGrouping.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFSheetRowGrouping.cs index b353be187..d9c77ed0f 100644 --- a/testcases/ooxml/XSSF/UserModel/TestXSSFSheetRowGrouping.cs +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFSheetRowGrouping.cs @@ -333,7 +333,7 @@ private void CheckWorkbookGrouping(IWorkbook wb, bool[] collapsed, bool[] hidden + sheet.FirstRowNum + "-" + sheet.LastRowNum + ")"); for (int i = sheet.FirstRowNum; i < sheet.LastRowNum; i++) { - if (collapsed[i - sheet.FirstRowNum] == null) + if (i - sheet.FirstRowNum<0 || i - sheet.FirstRowNum>=collapsed.Length) { continue; } diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFSheetShiftRows.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFSheetShiftRows.cs index 2fa9c4c43..212e0f3f7 100644 --- a/testcases/ooxml/XSSF/UserModel/TestXSSFSheetShiftRows.cs +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFSheetShiftRows.cs @@ -352,7 +352,7 @@ public void TestRemoveSheetAndAdjustActiveSheet() wb.RemoveSheetAt(0); Assert.Fail("Should catch exception as no more sheets are there"); } - catch (ArgumentException e) + catch (ArgumentException) { // expected } diff --git a/testcases/ooxml/XSSF/XSSFTestDataSamples.cs b/testcases/ooxml/XSSF/XSSFTestDataSamples.cs index 8acb10a9a..7c4fd81d8 100644 --- a/testcases/ooxml/XSSF/XSSFTestDataSamples.cs +++ b/testcases/ooxml/XSSF/XSSFTestDataSamples.cs @@ -69,7 +69,7 @@ public static IWorkbook WriteOutAndReadBack(IWorkbook wb) { Stopwatch sw = new Stopwatch(); sw.Start(); - wb.Write(baos); + wb.Write(baos, false); sw.Stop(); Debug.WriteLine("XSSFWorkbook write time: " + sw.ElapsedMilliseconds + "ms"); using (Stream is1 = new MemoryStream(baos.ToArray())) @@ -177,7 +177,7 @@ public static XSSFWorkbook WriteOutAndReadBack(XSSFWorkbook wb, String testName) FileStream out1 = file.Create(); try { - wb.Write(out1); + wb.Write(out1, false); } finally { @@ -196,7 +196,7 @@ public static XSSFWorkbook WriteOutAndReadBack(XSSFWorkbook wb, String testName) public static ByteArrayOutputStream WriteOut(R wb) where R : IWorkbook { ByteArrayOutputStream out1 = new ByteArrayOutputStream(8192); - wb.Write(out1); + wb.Write(out1, false); return out1; } diff --git a/testcases/ooxml/XWPF/UserModel/TestXWPFFootnote.cs b/testcases/ooxml/XWPF/UserModel/TestXWPFFootnote.cs new file mode 100644 index 000000000..306262e9b --- /dev/null +++ b/testcases/ooxml/XWPF/UserModel/TestXWPFFootnote.cs @@ -0,0 +1,136 @@ +using NPOI.OpenXmlFormats.Wordprocessing; +using NPOI.XWPF.UserModel; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Text; + +namespace TestCases.XWPF.UserModel +{ + [TestFixture] + public class TestXWPFFootnote + { + private XWPFDocument docOut; + private String p1Text; + private String p2Text; + private int footnoteId; + private XWPFFootnote footnote; + + [SetUp] + public void SetUp() + { + docOut = new XWPFDocument(); + p1Text = "First paragraph in footnote"; + p2Text = "Second paragraph in footnote"; + + // NOTE: XWPFDocument.CreateFootnote() delegates directly + // to XWPFFootnotes.CreateFootnote() so this tests + // both creation of new XWPFFootnotes in document + // and XWPFFootnotes.CreateFootnote(); + + // NOTE: Creating the footnote does not automatically + // create a first paragraph. + footnote = docOut.CreateFootnote(); + footnoteId = footnote.Id; + } + [Test] + public void TestAddParagraphsToFootnote() + { + + // Add a run to the first paragraph: + + XWPFParagraph p1 = footnote.CreateParagraph(); + p1.CreateRun().SetText(p1Text); + + // Create a second paragraph: + + XWPFParagraph p = footnote.CreateParagraph(); + Assert.IsNotNull(p, "Paragraph is null"); + p.CreateRun().SetText(p2Text); + + XWPFDocument docIn = XWPFTestDataSamples.WriteOutAndReadBack(docOut); + + XWPFFootnote testFootnote = docIn.GetFootnoteByID(footnoteId); + Assert.IsNotNull(testFootnote); + + Assert.AreEqual(2, testFootnote.GetParagraphs().Count); + XWPFParagraph testP1 = testFootnote.GetParagraphs()[0]; + Assert.AreEqual(p1Text, testP1.Text); + + XWPFParagraph testP2 = testFootnote.GetParagraphs()[1]; + Assert.AreEqual(p2Text, testP2.Text); + + // The first paragraph added using CreateParagraph() should + // have the required footnote reference added to the first + // run. + + // Verify that we have a footnote reference in the first paragraph and not + // in the second paragraph. + + XWPFRun r1 = testP1.Runs[0]; + Assert.IsNotNull(r1); + Assert.IsTrue(r1.GetCTR().GetFootnoteRefList().Count > 0, "No footnote reference in testP1"); + Assert.IsNotNull(r1.GetCTR().GetFootnoteRefArray(0), "No footnote reference in testP1"); + + XWPFRun r2 = testP2.Runs[0]; + Assert.IsNotNull(r2, "Expected a run in testP2"); + Assert.IsTrue(r2.GetCTR().GetFootnoteRefList().Count == 0, "Found a footnote reference in testP2"); + + } + [Test] + public void TestAddTableToFootnote() + { + XWPFTable table = footnote.CreateTable(); + Assert.IsNotNull(table); + + XWPFDocument docIn = XWPFTestDataSamples.WriteOutAndReadBack(docOut); + + XWPFFootnote testFootnote = docIn.GetFootnoteByID(footnoteId); + XWPFTable testTable = testFootnote.GetTableArray(0); + Assert.IsNotNull(testTable); + + table = footnote.CreateTable(2, 3); + Assert.AreEqual(2, table.NumberOfRows); + Assert.AreEqual(3, table.GetRow(0).GetTableCells().Count); + + // If the table is the first body element of the footnote then + // a paragraph with the footnote reference should have been + // added automatically. + + Assert.AreEqual(3, footnote.BodyElements.Count, "Expected 3 body elements"); + IBodyElement testP1 = footnote.BodyElements[0]; + Assert.IsTrue(testP1 is XWPFParagraph, "Expected a paragraph, got " + testP1.GetType().Name); + XWPFRun r1 = ((XWPFParagraph)testP1).Runs[0]; + Assert.IsNotNull(r1); + Assert.IsTrue(r1.GetCTR().GetFootnoteRefList().Count > 0, "No footnote reference in testP1"); + Assert.IsNotNull(r1.GetCTR().GetFootnoteRefArray(0), "No footnote reference in testP1"); + + } + [Test] + public void TestRemoveFootnote() + { + // NOTE: XWPFDocument.removeFootnote() delegates directly to + // XWPFFootnotes. + docOut.CreateFootnote(); + Assert.AreEqual(2, docOut.GetFootnotes().Count, "Expected 2 footnotes"); + Assert.IsNotNull(docOut.GetFootnotes()[1], "Didn't get second footnote"); + bool result = docOut.RemoveFootnote(0); + Assert.IsTrue(result, "Remove footnote did not return true"); + Assert.AreEqual(1, docOut.GetFootnotes().Count, "Expected 1 footnote after removal"); + } + [Test] + public void TestAddFootnoteRefToParagraph() + { + XWPFParagraph p = docOut.CreateParagraph(); + var runs = p.Runs; + Assert.AreEqual(0, runs.Count, "Expected no runs in new paragraph"); + p.AddFootnoteReference(footnote); + XWPFRun run = p.Runs[0]; + CT_R ctr = run.GetCTR(); + Assert.IsNotNull(run, "Expected a run"); + CT_FtnEdnRef ref1 = ctr.GetFootnoteReferenceList()[0]; + Assert.IsNotNull(ref1); + Assert.AreEqual(footnote.Id.ToString(), ref1.id, "Footnote ID and reference ID did not match"); + } + } +} \ No newline at end of file diff --git a/testcases/ooxml/XWPF/UserModel/TestXWPFFootnotes.cs b/testcases/ooxml/XWPF/UserModel/TestXWPFFootnotes.cs index a1451b0d6..ebc8c2ab3 100644 --- a/testcases/ooxml/XWPF/UserModel/TestXWPFFootnotes.cs +++ b/testcases/ooxml/XWPF/UserModel/TestXWPFFootnotes.cs @@ -27,23 +27,32 @@ namespace TestCases.XWPF.UserModel [TestFixture] public class TestXWPFFootnotes { - + [Test] + public void TestCreateFootnotes() + { + XWPFDocument docOut = new XWPFDocument(); + XWPFFootnotes footnotes = docOut.CreateFootnotes(); + Assert.IsNotNull(footnotes); + XWPFFootnotes secondFootnotes = docOut.CreateFootnotes(); + Assert.AreSame(footnotes, secondFootnotes); + docOut.Close(); + } [Test] public void TestAddFootnotesToDocument() { XWPFDocument docOut = new XWPFDocument(); - int noteId = 1; - - XWPFFootnotes footnotes = docOut.CreateFootnotes(); - CT_FtnEdn ctNote = new CT_FtnEdn(); - ctNote.id = (noteId.ToString()); - ctNote.type = (ST_FtnEdn.normal); - footnotes.AddFootnote(ctNote); + // NOTE: XWPFDocument.createFootnote() delegates directly + // to XWPFFootnotes.createFootnote() so this tests + // both creation of new XWPFFootnotes in document + // and XWPFFootnotes.createFootnote(); + XWPFFootnote footnote = docOut.CreateFootnote(); + int noteId = footnote.Id; XWPFDocument docIn = XWPFTestDataSamples.WriteOutAndReadBack(docOut); XWPFFootnote note = docIn.GetFootnoteByID(noteId); + Assert.IsNotNull(note); Assert.AreEqual(note.GetCTFtnEdn().type, ST_FtnEdn.normal); } diff --git a/testcases/ooxml/XWPF/UserModel/TestXWPFRun.cs b/testcases/ooxml/XWPF/UserModel/TestXWPFRun.cs index cebf28508..f7f481633 100644 --- a/testcases/ooxml/XWPF/UserModel/TestXWPFRun.cs +++ b/testcases/ooxml/XWPF/UserModel/TestXWPFRun.cs @@ -147,7 +147,7 @@ public void TestSetGetUnderline() XWPFRun run = new XWPFRun(ctRun, p); Assert.AreEqual(UnderlinePatterns.Dash, run.Underline); - run.SetUnderline(UnderlinePatterns.None); + run.Underline = UnderlinePatterns.None; Assert.AreEqual(ST_Underline.none, rpr.u.val); } diff --git a/testcases/ooxml/XWPF/UserModel/TestXWPFTable.cs b/testcases/ooxml/XWPF/UserModel/TestXWPFTable.cs index 30d7718fd..1bc83ff05 100644 --- a/testcases/ooxml/XWPF/UserModel/TestXWPFTable.cs +++ b/testcases/ooxml/XWPF/UserModel/TestXWPFTable.cs @@ -173,6 +173,7 @@ public void TestSetGetMargins() int r = table.CellMarginRight; Assert.AreEqual(450, r); } + [Test] public void TestSetGetHBorders() { @@ -266,5 +267,53 @@ public void TestCreateTable() } doc.Package.Revert(); } + + [Test] + public void TestSetTableCaption() + { + // create a table + XWPFDocument doc = new XWPFDocument(); + CT_Tbl ctTable = new CT_Tbl(); + XWPFTable table = new XWPFTable(ctTable, doc); + + //Set Caption + table.TableCaption = "%TABLECAPTION%"; + + //Check + CT_String tblCaption = table.GetCTTbl().tblPr.tblCaption; + Assert.IsNotNull(tblCaption); + Assert.AreEqual("%TABLECAPTION%", tblCaption.val); + } + + [Test] + public void TestSetTableDescription() + { + // create a table + XWPFDocument doc = new XWPFDocument(); + CT_Tbl ctTable = new CT_Tbl(); + XWPFTable table = new XWPFTable(ctTable, doc); + + //Set Description + table.TableDescription = "%TABLEDESCRIPTION%"; + + //Check + CT_String tblDesc = table.GetCTTbl().tblPr.tblDescription; + Assert.IsNotNull(tblDesc); + Assert.AreEqual("%TABLEDESCRIPTION%", tblDesc.val); + } + + [Test] + public void TestReadTableCaptionAndDescription() + { + // open an document with table containing Table caption and Table Description + XWPFDocument doc = XWPFTestDataSamples.OpenSampleDocument("table_properties.docx"); + + //Get Table + var table = doc.Tables[0]; + + //Assert Table Caption & Description + Assert.AreEqual("Table Title", table.TableCaption); + Assert.AreEqual("Table Description", table.TableDescription); + } } } \ No newline at end of file diff --git a/testcases/openxml4net/NPOI.OOXML4Net.Testcases.csproj b/testcases/openxml4net/NPOI.OOXML4Net.Testcases.csproj index 68d931e2d..5e87f75b7 100644 --- a/testcases/openxml4net/NPOI.OOXML4Net.Testcases.csproj +++ b/testcases/openxml4net/NPOI.OOXML4Net.Testcases.csproj @@ -162,6 +162,9 @@ 3.13.1 + + 4.2.1 + - - - - - - - - - - - diff --git a/tools/JavaToCSharp/Configuration/J2CSSection.cs b/tools/JavaToCSharp/Configuration/J2CSSection.cs deleted file mode 100644 index 323cdfaec..000000000 --- a/tools/JavaToCSharp/Configuration/J2CSSection.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Configuration; - -namespace JavaToCSharp.Configuration -{ - public class J2CSSection : ConfigurationSection - { - [ConfigurationProperty("Rules", IsDefaultCollection = true)] - [ConfigurationCollection(typeof(RuleSection))] - public RuleSectionCollection Rules - { - get { return this["Rules"] as RuleSectionCollection; } - } - } -} diff --git a/tools/JavaToCSharp/Configuration/RuleSection.cs b/tools/JavaToCSharp/Configuration/RuleSection.cs deleted file mode 100644 index 4e2d7968c..000000000 --- a/tools/JavaToCSharp/Configuration/RuleSection.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Configuration; - -namespace JavaToCSharp.Configuration -{ - public class RuleSection : ConfigurationElement - { - public RuleSection() { } - public RuleSection(string name, string pattern, string replacement) - { - this["name"] = name; - this["pattern"] = name; - this["replacement"] = name; - } - - [ConfigurationProperty("name", IsRequired = true)] - public string Name { - get { return (string)this["name"]; } - set { this["name"] = value; } - } - [ConfigurationProperty("pattern", IsRequired = true)] - public string Pattern - { - get { return (string)this["pattern"]; } - set { this["pattern"] = value; } - } - [ConfigurationProperty("replacement", IsRequired = true)] - public string Replacement - { - get { return (string)this["replacement"]; } - set { this["replacement"] = value; } - } - [ConfigurationProperty("type", IsRequired = false)] - public string Type - { - get { return (string)this["type"]; } - set { this["type"] = value; } - } - } -} diff --git a/tools/JavaToCSharp/Configuration/RuleSectionCollection.cs b/tools/JavaToCSharp/Configuration/RuleSectionCollection.cs deleted file mode 100644 index 0a484dbc7..000000000 --- a/tools/JavaToCSharp/Configuration/RuleSectionCollection.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Configuration; - -namespace JavaToCSharp.Configuration -{ - public class RuleSectionCollection : ConfigurationElementCollection - { - public void Add(RuleSection element) - { - BaseAdd(element); - } - - public void Remove(string name) - { - BaseRemove(name); - } - - public override ConfigurationElementCollectionType CollectionType - { - get - { - return ConfigurationElementCollectionType.AddRemoveClearMap; - } - } - protected override ConfigurationElement CreateNewElement() - { - return new RuleSection(); - } - protected override object GetElementKey(ConfigurationElement element) - { - return ((RuleSection)element).Name; - } - public new RuleSection this[string name] - { - get { return (RuleSection)BaseGet(name); } - } - } -} diff --git a/tools/JavaToCSharp/IRule.cs b/tools/JavaToCSharp/IRule.cs deleted file mode 100644 index 504132004..000000000 --- a/tools/JavaToCSharp/IRule.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Text; -using System.Text.RegularExpressions; - - -namespace JavaToCSharp -{ - public interface IRule - { - bool Execute(string strOrigin, out string strOutput, int iRowNumber); - } - - public abstract class Rule: IRule - { - #region IRuleExecutor Members - - public abstract bool Execute(string strOrigin, out string strOutput,int iRowNumber); - - public abstract string RuleName { get; } - - #endregion - } -} diff --git a/tools/JavaToCSharp/JavaToCSharp.csproj b/tools/JavaToCSharp/JavaToCSharp.csproj deleted file mode 100644 index 078416599..000000000 --- a/tools/JavaToCSharp/JavaToCSharp.csproj +++ /dev/null @@ -1,78 +0,0 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {766E09AF-B872-444D-BD76-C8BB17E38DAC} - Exe - Properties - JavaToCSharp - JavaToCSharp - v3.0 - 512 - - - - - 3.5 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - PreserveNewest - - - PreserveNewest - - - - - \ No newline at end of file diff --git a/tools/JavaToCSharp/JavaToCSharp.csproj.user b/tools/JavaToCSharp/JavaToCSharp.csproj.user deleted file mode 100644 index c829caefd..000000000 --- a/tools/JavaToCSharp/JavaToCSharp.csproj.user +++ /dev/null @@ -1,9 +0,0 @@ - - - - ShowAllFiles - - - PackageHelper.java - - \ No newline at end of file diff --git a/tools/JavaToCSharp/JavaToCSharp.gpState b/tools/JavaToCSharp/JavaToCSharp.gpState deleted file mode 100644 index 159ffa107..000000000 --- a/tools/JavaToCSharp/JavaToCSharp.gpState +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/tools/JavaToCSharp/JavaToCSharp.sln b/tools/JavaToCSharp/JavaToCSharp.sln deleted file mode 100644 index 7e89443a4..000000000 --- a/tools/JavaToCSharp/JavaToCSharp.sln +++ /dev/null @@ -1,22 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JavaToCSharp", "JavaToCSharp.csproj", "{766E09AF-B872-444D-BD76-C8BB17E38DAC}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {766E09AF-B872-444D-BD76-C8BB17E38DAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {766E09AF-B872-444D-BD76-C8BB17E38DAC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {766E09AF-B872-444D-BD76-C8BB17E38DAC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {766E09AF-B872-444D-BD76-C8BB17E38DAC}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/tools/JavaToCSharp/Program.cs b/tools/JavaToCSharp/Program.cs deleted file mode 100644 index 519803b67..000000000 --- a/tools/JavaToCSharp/Program.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using JavaToCSharp.Configuration; -using System.Configuration; -using JavaToCSharp.Rules; - -namespace JavaToCSharp -{ - class Program - { - static void Main(string[] args) - { - if (args.Length == 0) - { - Console.WriteLine("Missing Argument - file name"); - return; - } - - RuleEngine re = new RuleEngine(); - re.LoadRules(); - re.Run(args[0]); - } - } -} diff --git a/tools/JavaToCSharp/Properties/AssemblyInfo.cs b/tools/JavaToCSharp/Properties/AssemblyInfo.cs deleted file mode 100644 index ef773070d..000000000 --- a/tools/JavaToCSharp/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("JavaToCSharp")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("JavaToCSharp")] -[assembly: AssemblyCopyright("Copyright © 2009")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("73559d31-ce9e-4298-9c0a-93cc2dc4e7a3")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tools/JavaToCSharp/RuleEngine.cs b/tools/JavaToCSharp/RuleEngine.cs deleted file mode 100644 index 0b109db24..000000000 --- a/tools/JavaToCSharp/RuleEngine.cs +++ /dev/null @@ -1,110 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.IO; -using System.Reflection; -using JavaToCSharp.Configuration; -using System.Configuration; -using JavaToCSharp.Rules; - -namespace JavaToCSharp -{ - public class RuleEngine - { - List rules = new List(); - - public void AddRule(Rule rule) - { - rules.Add(rule); - } - - /// - /// Loads the rules. - /// - public void LoadRules() - { - //load from app.config - J2CSSection config = - ConfigurationManager.GetSection( - "J2CS") as J2CSSection; - foreach (RuleSection rs in config.Rules) - { - EquivalentRule r = new EquivalentRule(rs.Name); - r.Pattern = rs.Pattern; - r.Replacement = rs.Replacement; - //Console.WriteLine(r.ToString()); - AddRule(r); - } - //load from assembly - Assembly asm = Assembly.GetExecutingAssembly(); - string nameSpace = "JavaToCSharp.Rules"; - foreach (Type type in asm.GetTypes()) - { - if (type.Namespace == nameSpace && !type.IsAbstract && type.Name != "EquivalentRule") - AddRule(Activator.CreateInstance(type) as Rule); - } - } - - protected static void Log(string message) - { - Console.WriteLine(message); - } - protected static void LogTip(string message) - { - Console.WriteLine(message); - } - - protected void LogExecute(string ruleName,int iRowNumber) - { - Log(string.Format("[Line {0}] {1}", iRowNumber, ruleName)); - } - - //protected void LogFind(string strOrigin, int iRowNumber) - //{ - // Log(string.Format("[{0}]", this.RuleName)); - // Log(string.Format("(Line: {0}): {1}", iRowNumber, strOrigin.Trim().Replace("\r", ""))); - //} - - //protected void LogAttention(string strOrigin, int iRowNumber) - //{ - // LogTip(string.Format("[{0}]", this.RuleName)); - // LogTip(string.Format("(Line: {0}): {1}", iRowNumber, strOrigin.Trim().Replace("\r", ""))); - //} - public void Run(string path) - { - //read from file - if (!File.Exists(path)) - { - Console.WriteLine("File not found"); - return; - } - StreamReader sr = new StreamReader(path, true); - string strOrigin = sr.ReadToEnd(); - sr.Close(); - - //run rules - StringBuilder sb = new StringBuilder(); - string[] arrInput = strOrigin.Split(new char[] { '\n' }); - for (int i = 0; i < arrInput.Length; i++) - { - string tmp = arrInput[i].Replace("\r", ""); - - int ruleNum = i + 1; - foreach (Rule rule in rules) - { - if (rule.Execute(tmp, out tmp, ruleNum)) - { - LogExecute(rule.RuleName, ruleNum); - } - } - sb.AppendLine(tmp); - } - - //save result to file - StreamWriter sw = new StreamWriter(path, false); - sw.Write(sb.ToString()); - sw.Close(); - } - - } -} diff --git a/tools/JavaToCSharp/Rules/CapitalizeRule.cs b/tools/JavaToCSharp/Rules/CapitalizeRule.cs deleted file mode 100644 index 5700fab29..000000000 --- a/tools/JavaToCSharp/Rules/CapitalizeRule.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Text.RegularExpressions; - - -namespace JavaToCSharp.Rules -{ - public class CapitalizeRule : Rule - { - public override string RuleName - { - get { return "Capitalize Rule"; } - } - - const string pattern = @"(remove|add|apply|process|make|rename|change|run|equal|confirm|write|compare|separate|notify|contain|clone|ungroup|trim|isNaN|substring|classify|init|show|shift|replace|check|single|create|eval|append|convert|clear|fill|serialize|find|indexOf|lastIndexOf|resolve|parse|toString|coerce|lookup|valueOf|hook|unhook)\S+"; - - string CapitalizeString(Match matchString) - { - string strTemp = matchString.ToString(); - strTemp = char.ToUpper(strTemp[0]) + strTemp.Substring(1, strTemp.Length - 1); - return strTemp; - } - - - public override bool Execute(string strOrigin, out string strOutput, int iRowNumber) - { - Regex regex = new Regex(pattern); - string result = strOrigin; - bool changedFlag = false; - if (regex.IsMatch(strOrigin)) - { - result = regex.Replace(strOrigin, new MatchEvaluator(CapitalizeString)); - changedFlag = true; - } - strOutput = result; - return changedFlag; - } - } -} diff --git a/tools/JavaToCSharp/Rules/DeleteRule.cs b/tools/JavaToCSharp/Rules/DeleteRule.cs deleted file mode 100644 index fca26c788..000000000 --- a/tools/JavaToCSharp/Rules/DeleteRule.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Text.RegularExpressions; - -namespace JavaToCSharp.Rules -{ - public class DeleteRule : Rule - { - public override string RuleName - { - get { return "Delete Keyword"; } - } - - const string pattern = @"\sfinal\s|\sthrows\s[a-zA-Z]+Exception|\.doubleValue\(\)"; - - public override bool Execute(string strOrigin, out string strOutput, int iRowNumber) - { - Regex regex = new Regex(pattern); - string result = strOrigin; - bool changedFlag = false; - if (regex.IsMatch(strOrigin)) - { - result = regex.Replace(strOrigin," "); - changedFlag = true; - } - strOutput = result; - return changedFlag; - } - } -} diff --git a/tools/JavaToCSharp/Rules/EquivalentExceptionRule.cs b/tools/JavaToCSharp/Rules/EquivalentExceptionRule.cs deleted file mode 100644 index c8c6293bc..000000000 --- a/tools/JavaToCSharp/Rules/EquivalentExceptionRule.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text.RegularExpressions; - -namespace JavaToCSharp.Rules -{ - public abstract class EquivalentExceptionRule : EquivalentRule - { - protected override sealed string Replacement - { - get { return this.Pattern; } - } - } - - - public class EquivalentRuleException1 : EquivalentExceptionRule - { - - protected override string Pattern - { - get { return @"RuntimeException"; } - } - - public override string ReplaceString(Match match) - { - return "Exception"; - } - } - - public class EquivalentRuleException2 : EquivalentExceptionRule - { - - protected override string Pattern - { - get { return @"ClassCastException"; } - } - - public override string ReplaceString(Match match) - { - return "InvalidCastException"; - } - } - - public class EquivalentRuleException3 : EquivalentExceptionRule - { - - protected override string Pattern - { - get { return @"UnsupportedEncodingException"; } - } - - public override string ReplaceString(Match match) - { - return "EncoderFallbackException"; - } - } - - public class EquivalentRuleException4 : EquivalentExceptionRule - { - - protected override string Pattern - { - get { return @"AssertionFailedError"; } - } - - public override string ReplaceString(Match match) - { - return "AssertFailedException"; - } - } - - public class EquivalentRuleException5 : EquivalentExceptionRule - { - - protected override string Pattern - { - get { return @"IllegalArgumentException"; } - } - - public override string ReplaceString(Match match) - { - return "ArgumentException"; - } - } - public class EquivalentRuleException6 : EquivalentExceptionRule - { - - protected override string Pattern - { - get { return @"NumberFormatException"; } - } - - public override string ReplaceString(Match match) - { - return "FormatException"; - } - } - public class EquivalentRuleException7 : EquivalentExceptionRule - { - - protected override string Pattern - { - get { return @"IllegalAccessError|IllegalStateException"; } - } - - public override string ReplaceString(Match match) - { - return "InvalidOperationException"; - } - } - -} diff --git a/tools/JavaToCSharp/Rules/EquivalentRule.cs b/tools/JavaToCSharp/Rules/EquivalentRule.cs deleted file mode 100644 index c77ed943e..000000000 --- a/tools/JavaToCSharp/Rules/EquivalentRule.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Text.RegularExpressions; - -namespace JavaToCSharp.Rules -{ - public class EquivalentRule : Rule - { - public EquivalentRule() - { - - } - public EquivalentRule(string name) - { - this._name = name; - } - - string _name; - public override string RuleName - { - get { return _name; } - } - - public virtual string Replacement - { - get; - set; - } - - public virtual string Pattern - { - get; - set; - } - - protected virtual string ReplaceString(Match match) - { - return this.Replacement; - } - - public override sealed bool Execute(string strOrigin, out string strOutput, int iRowNumber) - { - Regex regex = new Regex(this.Pattern); - string result=strOrigin; - bool changedFlag = false; - - if (regex.IsMatch(strOrigin)) - { - result= regex.Replace(strOrigin, new MatchEvaluator(ReplaceString)); - changedFlag = true; - } - strOutput = result; - return changedFlag; - } - public override string ToString() - { - return string.Format("Equivalent Rule '{0}'", this.RuleName); - } - } -} diff --git a/tools/JavaToCSharp/Rules/OtherRule.cs b/tools/JavaToCSharp/Rules/OtherRule.cs deleted file mode 100644 index 78c7ab208..000000000 --- a/tools/JavaToCSharp/Rules/OtherRule.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Text.RegularExpressions; - -namespace JavaToCSharp.Rules -{ - class NPOINamespaceRule:EquivalentRule - { - public override string RuleName - { - get - { - return "namespace"; - } - } - - public override string Pattern - { - get { return @"org\.apache\.poi\.([a-zA-Z]+)\."; } - } - - public override string Replacement - { - get { return "namespace"; } - } - protected override string ReplaceString(System.Text.RegularExpressions.Match match) - { - return "NPOI."+match.Groups[1].Value.ToUpper()+"."; - } - } - - public class EquivalentRule1 : EquivalentRule - { - public override string RuleName - { - get - { - return "new Double"; - } - } - - public override string Replacement - { - get { return "new Double"; } - } - - public override string Pattern - { - get { return @"new Double\((.+)\)"; } - } - - protected override string ReplaceString(Match match) - { - return match.Groups[1].Value; - } - } - public class EquivalentRule2 : EquivalentRule - { - public override string Replacement - { - get { return ".charAt(i)"; } - } - - public override string Pattern - { - get { return @"\.charAt\((\w+)\)"; } - } - - protected override string ReplaceString(Match match) - { - return string.Format("[{0}]", match.Groups[1].Value); - } - } - - - public class EquivalentRule3 : EquivalentRule - { - public override string Replacement - { - get { return "read"; } - } - - public override string Pattern - { - get { return @"(\s|\.)(read\S)"; } - } - - protected override string ReplaceString(Match match) - { - string strTemp = match.Groups[2].Value; - return match.Groups[1].Value + char.ToUpper(strTemp[0]) + strTemp.Substring(1, strTemp.Length - 1); - } - - - } -} diff --git a/tools/JavaToCSharp/Rules/RemoveGetRule.cs b/tools/JavaToCSharp/Rules/RemoveGetRule.cs deleted file mode 100644 index 30a92bd20..000000000 --- a/tools/JavaToCSharp/Rules/RemoveGetRule.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Text.RegularExpressions; - -namespace JavaToCSharp.Rules -{ - public class RemoveGetRule : EquivalentRule - { - public override string Replacement - { - get { return "GetXXX()"; } - } - - public override string Pattern - { - get { return @"Get(FirstRow|Col|XFIndex|Data|LastRow|Column|Sid|Author|TotalSize|Row|FirstColumn|LastColumn|InnerValueEval|Height|Width|StringValue|ExternSheetIndex|Sheet|ColumnIndex|RowIndex)\(\)"; } - } - - protected override string ReplaceString(Match match) - { - return match.Groups[1].Value; - } - } -} diff --git a/tools/JavaToCSharp/Rules/foreachRule.cs b/tools/JavaToCSharp/Rules/foreachRule.cs deleted file mode 100644 index 527607350..000000000 --- a/tools/JavaToCSharp/Rules/foreachRule.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JavaToCSharp.Rules -{ - public class foreachRule : Rule - { - public override bool Execute(string strOrigin, out string strOutput, int iRowNumber) - { - string trimmedStr= strOrigin.Trim(); - strOutput = strOrigin; - if (!trimmedStr.StartsWith("for(") && !trimmedStr.StartsWith("for (")) - { - return false; - } - if (strOutput.IndexOf(":", 4) < 0) - return false; - strOutput = strOutput.Replace("for(", "foreach("); - strOutput = strOutput.Replace("for (", "foreach ("); - strOutput = strOutput.Replace(" : ", " in "); - return true; - } - public override string RuleName - { - get { return "for(Type x : y)"; } - } - } -} diff --git a/tools/JavaToCSharp/Rules/getIndexerRule.cs b/tools/JavaToCSharp/Rules/getIndexerRule.cs deleted file mode 100644 index 4f61fcb3f..000000000 --- a/tools/JavaToCSharp/Rules/getIndexerRule.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Text.RegularExpressions; - -namespace JavaToCSharp.Rules -{ - public class getIndexerRule : Rule - { - string ReplaceString(Match matchString) - { - string strTemp = matchString.Groups[1].Value; - return string.Format("[{0}]",strTemp); - } - - public override bool Execute(string strOrigin, out string strOutput, int iRowNumber) - { - strOutput = strOrigin; - Regex regex=new Regex(@"\.get\((\s+\w+\s+)\)",RegexOptions.IgnoreCase); - - bool changedFlag = false; - if (regex.IsMatch(strOrigin)) - { - strOutput = regex.Replace(strOrigin, new MatchEvaluator(ReplaceString)); - changedFlag = true; - } - return changedFlag; - } - public override string RuleName - { - get { return ".get(i)"; } - } - } -} diff --git a/tools/JavaToCSharp/Rules/skiplineRule.cs b/tools/JavaToCSharp/Rules/skiplineRule.cs deleted file mode 100644 index 8b9e9e37a..000000000 --- a/tools/JavaToCSharp/Rules/skiplineRule.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Text.RegularExpressions; - -namespace JavaToCSharp.Rules -{ - public class skiplineRule:Rule - { - public override bool Execute(string strOrigin, out string strOutput, int iRowNumber) - { - Regex regex = new Regex(@"(import|using)\s(java\.)", RegexOptions.IgnoreCase); - - if (regex.IsMatch(strOrigin)) - { - strOutput = string.Empty; - return true; - } - strOutput = strOrigin; - return false; - } - public override string RuleName - { - get { return "Skip this line"; } - } - } -} diff --git a/tools/JavaToCSharp/batchrename.ps1 b/tools/JavaToCSharp/batchrename.ps1 deleted file mode 100644 index 21bae074f..000000000 --- a/tools/JavaToCSharp/batchrename.ps1 +++ /dev/null @@ -1 +0,0 @@ -dir a\*.java | foreach { move-item -literal $_ $_.Name.Replace(".java", ".cs")} \ No newline at end of file diff --git a/tools/JavaToCSharp/run.ps1 b/tools/JavaToCSharp/run.ps1 deleted file mode 100644 index 148279b47..000000000 --- a/tools/JavaToCSharp/run.ps1 +++ /dev/null @@ -1,5 +0,0 @@ -$folder="a"; -foreach ($file in Get-ChildItem $folder) -{ -.\JavaToCSharp "$folder\$file"; -} \ No newline at end of file diff --git a/tools/LoadAndSaveBack/LoadAndSaveBack.csproj b/tools/LoadAndSaveBack/LoadAndSaveBack.csproj deleted file mode 100644 index 9c86660af..000000000 --- a/tools/LoadAndSaveBack/LoadAndSaveBack.csproj +++ /dev/null @@ -1,81 +0,0 @@ - - - - - Debug - AnyCPU - {222522DC-3C3F-4D75-B72B-98B736FB202A} - Exe - Properties - LoadAndSaveBack - LoadAndSaveBack - v4.5 - 512 - - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - - - - 1.3.1 - - - - - {10fa8538-157a-4380-a4f6-8e2c3ee92cae} - NPOI - - - {6beed965-b9a0-4ffa-b96d-0f380a97331a} - NPOI.OOXML - - - {c9f265b7-ece3-4755-b0b1-79536575c2a9} - NPOI.OpenXml4Net - - - {a6874784-2875-4f40-9e8f-8385a640f5d6} - NPOI.OpenXmlFormats - - - - - \ No newline at end of file diff --git a/tools/LoadAndSaveBack/LoadAndSaveBack.sln b/tools/LoadAndSaveBack/LoadAndSaveBack.sln deleted file mode 100644 index f464d77bc..000000000 --- a/tools/LoadAndSaveBack/LoadAndSaveBack.sln +++ /dev/null @@ -1,44 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LoadAndSaveBack", "LoadAndSaveBack.csproj", "{222522DC-3C3F-4D75-B72B-98B736FB202A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPOI", "..\..\main\NPOI.csproj", "{10FA8538-157A-4380-A4F6-8E2C3EE92CAE}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPOI.OOXML", "..\..\ooxml\NPOI.OOXML.csproj", "{6BEED965-B9A0-4FFA-B96D-0F380A97331A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPOI.OpenXml4Net", "..\..\openxml4Net\NPOI.OpenXml4Net.csproj", "{C9F265B7-ECE3-4755-B0B1-79536575C2A9}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPOI.OpenXmlFormats", "..\..\OpenXmlFormats\NPOI.OpenXmlFormats.csproj", "{A6874784-2875-4F40-9E8F-8385A640F5D6}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {222522DC-3C3F-4D75-B72B-98B736FB202A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {222522DC-3C3F-4D75-B72B-98B736FB202A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {222522DC-3C3F-4D75-B72B-98B736FB202A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {222522DC-3C3F-4D75-B72B-98B736FB202A}.Release|Any CPU.Build.0 = Release|Any CPU - {10FA8538-157A-4380-A4F6-8E2C3EE92CAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {10FA8538-157A-4380-A4F6-8E2C3EE92CAE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {10FA8538-157A-4380-A4F6-8E2C3EE92CAE}.Release|Any CPU.ActiveCfg = Debug|Any CPU - {10FA8538-157A-4380-A4F6-8E2C3EE92CAE}.Release|Any CPU.Build.0 = Debug|Any CPU - {6BEED965-B9A0-4FFA-B96D-0F380A97331A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6BEED965-B9A0-4FFA-B96D-0F380A97331A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6BEED965-B9A0-4FFA-B96D-0F380A97331A}.Release|Any CPU.ActiveCfg = Debug|Any CPU - {6BEED965-B9A0-4FFA-B96D-0F380A97331A}.Release|Any CPU.Build.0 = Debug|Any CPU - {C9F265B7-ECE3-4755-B0B1-79536575C2A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C9F265B7-ECE3-4755-B0B1-79536575C2A9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C9F265B7-ECE3-4755-B0B1-79536575C2A9}.Release|Any CPU.ActiveCfg = Debug|Any CPU - {C9F265B7-ECE3-4755-B0B1-79536575C2A9}.Release|Any CPU.Build.0 = Debug|Any CPU - {A6874784-2875-4F40-9E8F-8385A640F5D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A6874784-2875-4F40-9E8F-8385A640F5D6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A6874784-2875-4F40-9E8F-8385A640F5D6}.Release|Any CPU.ActiveCfg = Debug|Any CPU - {A6874784-2875-4F40-9E8F-8385A640F5D6}.Release|Any CPU.Build.0 = Debug|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/tools/LoadAndSaveBack/Program.cs b/tools/LoadAndSaveBack/Program.cs deleted file mode 100644 index 8d5eaeb7e..000000000 --- a/tools/LoadAndSaveBack/Program.cs +++ /dev/null @@ -1,54 +0,0 @@ -using NPOI.SS.UserModel; -using NPOI.XSSF.UserModel; -using NPOI.XWPF.UserModel; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; - -namespace LoadAndSaveBack -{ - class Program - { - enum RunMode - { - Excel, - Word - } - static void Main(string[] args) - { - if (args.Length != 2) - return; - - string src = args[0]; - string target = args[1]; - - - RunMode mode= RunMode.Excel; - if (src.Contains(".docx")) - mode = RunMode.Word; - - if (mode == RunMode.Excel) - { - Stream rfs = File.OpenRead(src); - IWorkbook workbook = new XSSFWorkbook(rfs); - rfs.Close(); - using (FileStream fs = File.Create(target)) - { - workbook.Write(fs); - } - } - else - { - Stream rfs = File.OpenRead(src); - XWPFDocument workbook = new XWPFDocument(rfs); - rfs.Close(); - using (FileStream fs = File.Create(target)) - { - workbook.Write(fs); - } - } - } - } -} diff --git a/tools/LoadAndSaveBack/Properties/AssemblyInfo.cs b/tools/LoadAndSaveBack/Properties/AssemblyInfo.cs deleted file mode 100644 index 03e69dd21..000000000 --- a/tools/LoadAndSaveBack/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("LoadAndSaveBack")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("LoadAndSaveBack")] -[assembly: AssemblyCopyright("Copyright © 2013")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("a4ac1d0b-c61b-4db0-bc67-5854ab2ef441")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tools/LoadAndSaveBack/app.config b/tools/LoadAndSaveBack/app.config deleted file mode 100644 index c5e1daefd..000000000 --- a/tools/LoadAndSaveBack/app.config +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/tools/POIFS Browser/AboutDialog.Designer.cs b/tools/POIFS Browser/AboutDialog.Designer.cs deleted file mode 100644 index 70a7d083c..000000000 --- a/tools/POIFS Browser/AboutDialog.Designer.cs +++ /dev/null @@ -1,126 +0,0 @@ -namespace NPOI.Tools.POIFSBrowser -{ - partial class AboutDialog - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.flowLayoutPanel1 = new NPOI.Tools.POIFSBrowser.AboutDialog.EtchedBorderedPanel(); - this.okButton = new System.Windows.Forms.Button(); - this.pictureBox1 = new System.Windows.Forms.PictureBox(); - this.label1 = new System.Windows.Forms.Label(); - this.webSiteLink = new System.Windows.Forms.LinkLabel(); - this.flowLayoutPanel1.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); - this.SuspendLayout(); - // - // flowLayoutPanel1 - // - this.flowLayoutPanel1.BackColor = System.Drawing.SystemColors.Control; - this.flowLayoutPanel1.Controls.Add(this.okButton); - this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Bottom; - this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 110); - this.flowLayoutPanel1.Name = "flowLayoutPanel1"; - this.flowLayoutPanel1.Size = new System.Drawing.Size(524, 30); - this.flowLayoutPanel1.TabIndex = 1; - // - // okButton - // - this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.okButton.DialogResult = System.Windows.Forms.DialogResult.OK; - this.okButton.Location = new System.Drawing.Point(438, 3); - this.okButton.Name = "okButton"; - this.okButton.Size = new System.Drawing.Size(83, 25); - this.okButton.TabIndex = 0; - this.okButton.Text = "OK"; - this.okButton.UseVisualStyleBackColor = true; - // - // pictureBox1 - // - this.pictureBox1.Image = global::NPOI.Tools.POIFSBrowser.Properties.Resources.NET_h_rgb_2; - this.pictureBox1.Location = new System.Drawing.Point(184, 12); - this.pictureBox1.Name = "pictureBox1"; - this.pictureBox1.Size = new System.Drawing.Size(328, 81); - this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize; - this.pictureBox1.TabIndex = 0; - this.pictureBox1.TabStop = false; - // - // label1 - // - this.label1.Location = new System.Drawing.Point(12, 9); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(166, 46); - this.label1.TabIndex = 2; - this.label1.Text = "Developed by using open source NPOI library which is available at:"; - // - // webSiteLink - // - this.webSiteLink.AutoSize = true; - this.webSiteLink.Location = new System.Drawing.Point(12, 55); - this.webSiteLink.Name = "webSiteLink"; - this.webSiteLink.Size = new System.Drawing.Size(170, 13); - this.webSiteLink.TabIndex = 3; - this.webSiteLink.TabStop = true; - this.webSiteLink.Text = "http://www.codeplex.com/NPOI"; - this.webSiteLink.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.webSiteLink_LinkClicked); - // - // AboutDialog - // - this.AcceptButton = this.okButton; - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.BackColor = System.Drawing.Color.White; - this.ClientSize = new System.Drawing.Size(524, 140); - this.Controls.Add(this.webSiteLink); - this.Controls.Add(this.label1); - this.Controls.Add(this.flowLayoutPanel1); - this.Controls.Add(this.pictureBox1); - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(162))); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; - this.MaximizeBox = false; - this.MinimizeBox = false; - this.Name = "AboutDialog"; - this.ShowIcon = false; - this.ShowInTaskbar = false; - this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "About POIFS Browser"; - this.flowLayoutPanel1.ResumeLayout(false); - ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.PictureBox pictureBox1; - private EtchedBorderedPanel flowLayoutPanel1; - private System.Windows.Forms.Button okButton; - private System.Windows.Forms.Label label1; - private System.Windows.Forms.LinkLabel webSiteLink; - } -} \ No newline at end of file diff --git a/tools/POIFS Browser/AboutDialog.cs b/tools/POIFS Browser/AboutDialog.cs deleted file mode 100644 index 2267a81d7..000000000 --- a/tools/POIFS Browser/AboutDialog.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Windows.Forms; - -namespace NPOI.Tools.POIFSBrowser -{ - public partial class AboutDialog : Form - { - private static AboutDialog _instance; - public static AboutDialog Instance - { - get - { - if (_instance == null) - { - _instance = new AboutDialog(); - } - - return _instance; - } - } - - private AboutDialog() - { - InitializeComponent(); - } - - private void webSiteLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) - { - System.Diagnostics.Process.Start(webSiteLink.Text); - } - - private class EtchedBorderedPanel : Panel - { - protected override void OnPaint(PaintEventArgs e) - { - base.OnPaint(e); - - ControlPaint.DrawBorder3D(e.Graphics, this.ClientRectangle, Border3DStyle.Etched, Border3DSide.Top); - } - } - } -} \ No newline at end of file diff --git a/tools/POIFS Browser/AboutDialog.resx b/tools/POIFS Browser/AboutDialog.resx deleted file mode 100644 index 19dc0dd8b..000000000 --- a/tools/POIFS Browser/AboutDialog.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/tools/POIFS Browser/AbstractTreeNode.cs b/tools/POIFS Browser/AbstractTreeNode.cs deleted file mode 100644 index cb2cb2147..000000000 --- a/tools/POIFS Browser/AbstractTreeNode.cs +++ /dev/null @@ -1,73 +0,0 @@ - -/* ==================================================================== - 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. -==================================================================== */ - -/* ================================================================ - * POIFS Browser - * Author: NPOI Team - * HomePage: http://www.codeplex.com/npoi - * Contributors: - * Huseyin Tufekcilerli 2008.11 1.0 - * Tony Qu 2009.2.18 1.2 alpha - * - * ==============================================================*/ - -using System; -using System.Windows.Forms; -using NPOI.POIFS.FileSystem; - -namespace NPOI.Tools.POIFSBrowser -{ - internal abstract class AbstractTreeNode : TreeNode, IComparable - { - public EntryNode EntryNode { get; private set; } - - public AbstractTreeNode(EntryNode entryNode) - : base(entryNode.Name) - { - this.EntryNode = entryNode; - } - - protected void ChangeImage(string imageKey) - { - this.ImageKey = this.SelectedImageKey = imageKey; - } - - #region IComparable Members - - public int CompareTo(AbstractTreeNode other) - { - bool b1 = this is DirectoryTreeNode; - bool b2 = other is DirectoryTreeNode; - - if (b1 && !b2) - { - return -1; - } - else if (!b1 && b2) - { - return 1; - } - else - { - return this.Text.CompareTo(other.Text); - } - } - - #endregion - } -} \ No newline at end of file diff --git a/tools/POIFS Browser/DirectoryTreeNode.cs b/tools/POIFS Browser/DirectoryTreeNode.cs deleted file mode 100644 index f2a517ccd..000000000 --- a/tools/POIFS Browser/DirectoryTreeNode.cs +++ /dev/null @@ -1,278 +0,0 @@ -/* ==================================================================== - 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. -==================================================================== */ - -/* ================================================================ - * POIFS Browser - * Author: NPOI Team - * HomePage: http://www.codeplex.com/npoi - * Contributors: - * Huseyin Tufekcilerli 2008.11 1.0 - * Tony Qu 2009.2.18 1.2 alpha - * Tony Qu 2009.3.4 1.2 beta 1 - * - * ==============================================================*/ - -using System; -using System.Collections.Generic; -using System.Windows.Forms; -using System.Collections; - -using NPOI.POIFS.FileSystem; -using NPOI.HSSF.Record; -using NPOI.HSSF.Util; -using NPOI.HSSF.UserModel; -using NPOI.HSSF.Record.Aggregates; -using NPOI.SS.Util; -using NPOI.DDF; -using NPOI.HSSF.Record.Chart; - -namespace NPOI.Tools.POIFSBrowser -{ - internal class DirectoryTreeNode : AbstractTreeNode - { - public DirectoryNode DirectoryNode { get; private set; } - private bool _isExpanded; - - public DirectoryTreeNode(DirectoryNode dn) - : base(dn) - { - - this.DirectoryNode = dn; - - ChangeImage("Folder"); - - this.Nodes.Add(string.Empty); // Dummy node - } - - - internal void OnExpanded() - { - if (!_isExpanded) - { - this.TreeView.BeginUpdate(); - this.Nodes.Clear(); - this.Nodes.AddRange(GetChildren(this.DirectoryNode,null)); - - ChangeImage("FolderOpen"); - - this.TreeView.EndUpdate(); - - _isExpanded = true; - } - } - - internal void OnCollapsed() - { - ChangeImage("Folder"); - } - - internal static TreeNode[] GetChildren(DirectoryNode node,object innerDoc) - { - var children = new List(); - - var entries = node.Entries; - - while (entries.MoveNext()) - { - EntryNode entry = entries.Current as EntryNode; - AbstractTreeNode treeNode; - if (entry is DirectoryNode) - { - treeNode = new DirectoryTreeNode(entry as DirectoryNode); - - var o = entry as DirectoryNode; - } - else - { - var o = entry as DocumentNode; - - treeNode = new DocumentTreeNode(entry as DocumentNode); - - #region handle Excel BIFF records - - if (treeNode.Text.ToLower() == "workbook") - { - HandleWorkbook(treeNode, (HSSFWorkbook)innerDoc); - } - //else if(treeNode.Text.ToLower() == "worddocument") - //{ - // HandleWord(treeNode, (HWPFDocument)innerDoc); - //} - - #endregion - } - - children.Add(treeNode); - } - - children.Sort(); - - return children.ToArray(); - } - - //static void HandleWord(TreeNode treeNode, HWPFDocument hwpf) - //{ - // TreeNode paragraphsNode = CreateFolderNode(treeNode, "Paragraphs"); - // List papxs = hwpf.ParagraphTable.GetParagraphs(); - // foreach (PAPX papx in papxs) - // { - // TreeNode tn = new TreeNode("PAPX"); - // paragraphsNode.Nodes.Add(tn); - // } - // foreach(FieldsDocumentPart part in Enum.GetValues(typeof(FieldsDocumentPart))) - // { - // LoadDocumentPart(hwpf, treeNode, part.ToString(), part); - // } - // TreeNode docTextNode = new TreeNode("DocumentText"); - // docTextNode.Tag = hwpf.GetDocumentText(); - // treeNode.Nodes.Add(docTextNode); - //} - static TreeNode CreateFolderNode(TreeNode parent, string name) - { - TreeNode newnode = new TreeNode(name); - newnode.ImageKey = "Folder"; - newnode.SelectedImageKey = "Folder"; - parent.Nodes.Add(newnode); - return newnode; - } - //static void LoadDocumentPart(HWPFDocument hwpf,TreeNode parent,string partName,FieldsDocumentPart part) - //{ - - // TreeNode mainNode = new TreeNode(partName); - // mainNode.ImageKey = "Folder"; - // mainNode.SelectedImageKey = "Folder"; - // parent.Nodes.Add(mainNode); - // Fields fields = hwpf.GetFields(); - // foreach (Field field in fields.GetFields(part)) - // { - // TreeNode tn = new TreeNode("Field"); - // mainNode.Nodes.Add(tn); - // } - //} - - - static void HandleWorkbook(TreeNode treeNode,HSSFWorkbook hssfworkbook) - { - - if (hssfworkbook.NumberOfSheets > 0) - { - treeNode.ImageKey = "Folder"; - treeNode.SelectedImageKey = "Folder"; - for (int i = 0; i < hssfworkbook.NumberOfSheets; i++) - { - string sheettext = string.Format("Sheet {0}", i + 1); - TreeNode sheetnode = - treeNode.Nodes.Add(sheettext, sheettext, "Folder", "Folder"); - - HSSFSheet hssfsheet=((HSSFSheet)hssfworkbook.GetSheetAt(i)); - EscherAggregate ea = hssfsheet.DrawingEscherAggregate; - IEnumerator iterator1 = hssfsheet.Sheet.Records.GetEnumerator(); - int chartIndex = 1; - while (iterator1.MoveNext()) - { - if (iterator1.Current is BOFRecord) - { - BOFRecord bof = (BOFRecord)iterator1.Current; - if (bof.Type == BOFRecordType.Chart) - { - string chartTitle = string.Format("Chart {0}" , chartIndex); - TreeNode chartnode = sheetnode.Nodes.Add(chartTitle, chartTitle, "Folder", "Folder"); - chartnode.Nodes.Add(new RecordTreeNode(bof)); - while (iterator1.MoveNext()) - { - if (iterator1.Current is RecordAggregate) - { - RecordAggregate record = (RecordAggregate)iterator1.Current; - chartnode.Nodes.Add(new RecordAggregateTreeNode(record)); - } - else /*if(iterator1.Current is Record)*/ - { - chartnode.Nodes.Add(new RecordTreeNode((Record)iterator1.Current)); - } - if (iterator1.Current is EOFRecord) - break; - } - chartIndex++; - } - } - else if (iterator1.Current is Record) - { - Record record = (Record)iterator1.Current; - sheetnode.Nodes.Add(new RecordTreeNode(record)); - } - else if (iterator1.Current is RecordAggregate) - { - RecordAggregate record = (RecordAggregate)iterator1.Current; - sheetnode.Nodes.Add(new RecordAggregateTreeNode(record)); - } - } - //RecordTreeNode rtn = new DirectoryTreeNode(); - if (ea != null) - { - foreach (EscherRecord er in ea.EscherRecords) - { - sheetnode.Nodes.Add(new EscherRecordTreeNode(er)); - } - } - } - - } - else - { - treeNode.ImageKey = "Binary"; - } - IEnumerator iterator2 = hssfworkbook.Workbook.Records.GetEnumerator(); - while (iterator2.MoveNext()) - { - if (iterator2.Current is Record) //&& !(iterator2.Current is UnknownRecord)) - { - Record record = (Record)iterator2.Current; - if (record is DrawingGroupRecord) - { - hssfworkbook.GetAllPictures(); - } - treeNode.Nodes.Add(new RecordTreeNode(record)); - } - else if (iterator2.Current is RecordBase) - { - RecordBase record = (RecordBase)iterator2.Current; - treeNode.Nodes.Add(record.GetType().Name); - } - } - - - } - - private class RecordVisitor1 : RecordVisitor - { - private TreeNode node; - public RecordVisitor1(TreeNode psNode) - { - node = psNode; - } - #region RecordVisitor 成员 - - public void VisitRecord(Record r) - { - node.Nodes.Add(new RecordTreeNode(r)); - } - - #endregion - } - - } -} \ No newline at end of file diff --git a/tools/POIFS Browser/DocumentTreeNode.cs b/tools/POIFS Browser/DocumentTreeNode.cs deleted file mode 100644 index b11088d84..000000000 --- a/tools/POIFS Browser/DocumentTreeNode.cs +++ /dev/null @@ -1,61 +0,0 @@ -/* ==================================================================== - 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. -==================================================================== */ - -/* ================================================================ - * POIFS Browser - * Author: NPOI Team - * HomePage: http://www.codeplex.com/npoi - * Contributors: - * Huseyin Tufekcilerli 2008.11 1.0 - * Tony Qu 2009.2.18 1.2 alpha - * - * ==============================================================*/ - -using NPOI.POIFS.FileSystem; -using System.IO; -using NPOI.Util; - -namespace NPOI.Tools.POIFSBrowser -{ - internal class DocumentTreeNode : AbstractTreeNode - { - public DocumentNode DocumentNode { get; private set; } - - public DocumentTreeNode(DocumentNode documentNode) - : base(documentNode) - { - this.DocumentNode = documentNode; - - ChangeImage(documentNode.Name.EndsWith("SummaryInformation") ? "SummaryStream" - : "File"); - } - - public Stream GetDocumentStream() - { - var document = this.DocumentNode.Document; - - var dst = new byte[document.Size]; - - if (document.Size > 0) - { - document.Read(dst, 0); - } - - return new ByteArrayInputStream(dst); - } - } -} \ No newline at end of file diff --git a/tools/POIFS Browser/EscherPropertyTreeNode.cs b/tools/POIFS Browser/EscherPropertyTreeNode.cs deleted file mode 100644 index c1cc321ee..000000000 --- a/tools/POIFS Browser/EscherPropertyTreeNode.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using NPOI.DDF; - -namespace NPOI.Tools.POIFSBrowser -{ - public class EscherPropertyTreeNode:AbstractRecordTreeNode - { - - - public EscherPropertyTreeNode(EscherProperty ep) - { - this.Record = ep; - this.Text = ep.Name; - this.ImageKey = "Binary"; - } - - public override bool HasBinary - { - get { return true; } - } - - public override byte[] GetBytes() - { - - if (this.Record is EscherSimpleProperty) - { - EscherSimpleProperty esp = (EscherSimpleProperty)this.Record; - byte[] data = new byte[esp.PropertySize]; - esp.SerializeSimplePart(data, 0); - return data; - } - else if (this.Record is EscherComplexProperty) - { - EscherComplexProperty esp = (EscherComplexProperty)this.Record; - byte[] data = new byte[esp.PropertySize]; - esp.SerializeComplexPart(data, 0); - return data; - } - return null; - - } - } -} diff --git a/tools/POIFS Browser/EscherRecordTreeNode.cs b/tools/POIFS Browser/EscherRecordTreeNode.cs deleted file mode 100644 index c76dc11c0..000000000 --- a/tools/POIFS Browser/EscherRecordTreeNode.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Windows.Forms; - -using NPOI.DDF; - -namespace NPOI.Tools.POIFSBrowser -{ - public class EscherRecordTreeNode : AbstractRecordTreeNode - { - public EscherRecordTreeNode(EscherRecord record) - { - this.Record = record; - this.Text = record.GetType().Name; - if(record.ChildRecords.Count>0) - this.ImageKey = "Folder"; - else - this.ImageKey = "Binary"; - - if (record is AbstractEscherOptRecord) - { - AbstractEscherOptRecord rec = ((AbstractEscherOptRecord)record); - foreach (EscherProperty ep in rec.EscherProperties ) - { - EscherPropertyTreeNode cnode = new EscherPropertyTreeNode(ep); - this.Nodes.Add(cnode); - } - } - else - { - GetChildren(this); - } - } - - private void GetChildren(EscherRecordTreeNode node) - { - EscherRecord record=((EscherRecord)node.Record); - for (int i = 0; i < record.ChildRecords.Count; i++) - { - EscherRecordTreeNode cnode=new EscherRecordTreeNode((EscherRecord)record.ChildRecords[i]); - this.Nodes.Add(cnode); - } - } - - public override byte[] GetBytes() - { - EscherRecord record=(EscherRecord)this.Record; - byte[] bytes=new byte[record.RecordSize]; - record.Serialize(0, bytes); - return bytes; - } - - public override bool HasBinary - { - get { return true; } - } - } -} diff --git a/tools/POIFS Browser/HSSF/AbstractRecordTreeNode.cs b/tools/POIFS Browser/HSSF/AbstractRecordTreeNode.cs deleted file mode 100644 index 2667b5a98..000000000 --- a/tools/POIFS Browser/HSSF/AbstractRecordTreeNode.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using System.Collections; -using System.Text; -using System.Windows.Forms; -using System.Reflection; - -using NPOI.HSSF.Record; -using NPOI.SS.Formula.PTG; - -namespace NPOI.Tools.POIFSBrowser -{ - public abstract class AbstractRecordTreeNode:TreeNode - { - public abstract bool HasBinary { get; } - - public object Record { get; protected set; } - - public virtual ListViewItem[] GetPropertyList() - { - ArrayList tmplist = new ArrayList(); - - PropertyInfo[] properties = Record.GetType().GetProperties(); - int n = 1; - foreach (PropertyInfo property in properties) - { - string propertyValueText = "(null)"; - string propertyValueType = ""; - try - { - object propertyValue = property.GetValue(this.Record, null); - - - if (propertyValue != null) - { - //parse Ptg array - if (propertyValue is Ptg[]) - { - propertyValueText = ""; - Ptg[] ptgs=(Ptg[])propertyValue; - for(int i=0;i - /// Required designer variable. - ///
- private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.components = new System.ComponentModel.Container(); - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); - this.menuStrip = new System.Windows.Forms.MenuStrip(); - this.fileMenu = new System.Windows.Forms.ToolStripMenuItem(); - this.fileOpenMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.fileMenSeparator1 = new System.Windows.Forms.ToolStripSeparator(); - this.fileExitMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.aboutMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.statusStrip = new System.Windows.Forms.StatusStrip(); - this.toolStrip = new System.Windows.Forms.ToolStrip(); - this.openToolStripButton = new System.Windows.Forms.ToolStripButton(); - this.refreshToolScripButton = new System.Windows.Forms.ToolStripButton(); - this.mainSplitContainer = new System.Windows.Forms.SplitContainer(); - this.documentsGroupBox = new System.Windows.Forms.GroupBox(); - this.documentTreeView = new System.Windows.Forms.TreeView(); - this.documentTreeContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); - this.saveAsMenu = new System.Windows.Forms.ToolStripMenuItem(); - this.iconsImageList = new System.Windows.Forms.ImageList(this.components); - this.streamGroupBox = new System.Windows.Forms.GroupBox(); - this.streamTabControl = new System.Windows.Forms.TabControl(); - this.tabPageBinary = new System.Windows.Forms.TabPage(); - this.viewableTextBox = new System.Windows.Forms.TextBox(); - this.tabPageProperties = new System.Windows.Forms.TabPage(); - this.propertiesListView = new System.Windows.Forms.ListView(); - this.columnId = new System.Windows.Forms.ColumnHeader(); - this.columnName = new System.Windows.Forms.ColumnHeader(); - this.columnType = new System.Windows.Forms.ColumnHeader(); - this.columnValue = new System.Windows.Forms.ColumnHeader(); - this.menuStrip.SuspendLayout(); - this.toolStrip.SuspendLayout(); - this.mainSplitContainer.Panel1.SuspendLayout(); - this.mainSplitContainer.Panel2.SuspendLayout(); - this.mainSplitContainer.SuspendLayout(); - this.documentsGroupBox.SuspendLayout(); - this.documentTreeContextMenu.SuspendLayout(); - this.streamGroupBox.SuspendLayout(); - this.streamTabControl.SuspendLayout(); - this.tabPageBinary.SuspendLayout(); - this.tabPageProperties.SuspendLayout(); - this.SuspendLayout(); - // - // menuStrip - // - this.menuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.fileMenu, - this.helpToolStripMenuItem}); - this.menuStrip.Location = new System.Drawing.Point(0, 0); - this.menuStrip.Name = "menuStrip"; - this.menuStrip.Size = new System.Drawing.Size(784, 25); - this.menuStrip.TabIndex = 0; - this.menuStrip.Text = "menuStrip1"; - // - // fileMenu - // - this.fileMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.fileOpenMenuItem, - this.fileMenSeparator1, - this.fileExitMenuItem}); - this.fileMenu.Name = "fileMenu"; - this.fileMenu.Size = new System.Drawing.Size(39, 21); - this.fileMenu.Text = "&File"; - // - // fileOpenMenuItem - // - this.fileOpenMenuItem.Image = global::NPOI.Tools.POIFSBrowser.Properties.Resources.Open; - this.fileOpenMenuItem.Name = "fileOpenMenuItem"; - this.fileOpenMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.O))); - this.fileOpenMenuItem.Size = new System.Drawing.Size(164, 22); - this.fileOpenMenuItem.Text = "&Open..."; - this.fileOpenMenuItem.Click += new System.EventHandler(this.Open_Click); - // - // fileMenSeparator1 - // - this.fileMenSeparator1.Name = "fileMenSeparator1"; - this.fileMenSeparator1.Size = new System.Drawing.Size(161, 6); - // - // fileExitMenuItem - // - this.fileExitMenuItem.Name = "fileExitMenuItem"; - this.fileExitMenuItem.Size = new System.Drawing.Size(164, 22); - this.fileExitMenuItem.Text = "E&xit"; - this.fileExitMenuItem.Click += new System.EventHandler(this.fileExitMenuItem_Click); - // - // helpToolStripMenuItem - // - this.helpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.aboutMenuItem}); - this.helpToolStripMenuItem.Name = "helpToolStripMenuItem"; - this.helpToolStripMenuItem.Size = new System.Drawing.Size(47, 21); - this.helpToolStripMenuItem.Text = "&Help"; - // - // aboutMenuItem - // - this.aboutMenuItem.Name = "aboutMenuItem"; - this.aboutMenuItem.Size = new System.Drawing.Size(120, 22); - this.aboutMenuItem.Text = "&About..."; - this.aboutMenuItem.Click += new System.EventHandler(this.aboutMenuItem_Click); - // - // statusStrip - // - this.statusStrip.Location = new System.Drawing.Point(0, 542); - this.statusStrip.Name = "statusStrip"; - this.statusStrip.Size = new System.Drawing.Size(784, 22); - this.statusStrip.TabIndex = 1; - this.statusStrip.Text = "statusStrip1"; - // - // toolStrip - // - this.toolStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.openToolStripButton, - this.refreshToolScripButton}); - this.toolStrip.Location = new System.Drawing.Point(0, 25); - this.toolStrip.Name = "toolStrip"; - this.toolStrip.Size = new System.Drawing.Size(784, 25); - this.toolStrip.TabIndex = 2; - this.toolStrip.Text = "toolStrip1"; - // - // openToolStripButton - // - this.openToolStripButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; - this.openToolStripButton.Image = global::NPOI.Tools.POIFSBrowser.Properties.Resources.Open; - this.openToolStripButton.ImageTransparentColor = System.Drawing.Color.Magenta; - this.openToolStripButton.Name = "openToolStripButton"; - this.openToolStripButton.Size = new System.Drawing.Size(23, 22); - this.openToolStripButton.Text = "Open File"; - this.openToolStripButton.ToolTipText = "Open Document"; - this.openToolStripButton.Click += new System.EventHandler(this.Open_Click); - // - // refreshToolScripButton - // - this.refreshToolScripButton.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; - this.refreshToolScripButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; - this.refreshToolScripButton.Image = global::NPOI.Tools.POIFSBrowser.Properties.Resources.arrow_refresh; - this.refreshToolScripButton.ImageTransparentColor = System.Drawing.Color.Magenta; - this.refreshToolScripButton.Name = "refreshToolScripButton"; - this.refreshToolScripButton.Size = new System.Drawing.Size(23, 22); - this.refreshToolScripButton.Text = "Refresh File"; - this.refreshToolScripButton.Click += new System.EventHandler(this.refreshToolScripButton_Click); - // - // mainSplitContainer - // - this.mainSplitContainer.Dock = System.Windows.Forms.DockStyle.Fill; - this.mainSplitContainer.Location = new System.Drawing.Point(0, 50); - this.mainSplitContainer.Name = "mainSplitContainer"; - // - // mainSplitContainer.Panel1 - // - this.mainSplitContainer.Panel1.Controls.Add(this.documentsGroupBox); - this.mainSplitContainer.Panel1.Padding = new System.Windows.Forms.Padding(3, 0, 0, 0); - // - // mainSplitContainer.Panel2 - // - this.mainSplitContainer.Panel2.Controls.Add(this.streamGroupBox); - this.mainSplitContainer.Panel2.Padding = new System.Windows.Forms.Padding(0, 0, 3, 0); - this.mainSplitContainer.Size = new System.Drawing.Size(784, 492); - this.mainSplitContainer.SplitterDistance = 261; - this.mainSplitContainer.TabIndex = 3; - // - // documentsGroupBox - // - this.documentsGroupBox.Controls.Add(this.documentTreeView); - this.documentsGroupBox.Dock = System.Windows.Forms.DockStyle.Fill; - this.documentsGroupBox.Location = new System.Drawing.Point(3, 0); - this.documentsGroupBox.Name = "documentsGroupBox"; - this.documentsGroupBox.Padding = new System.Windows.Forms.Padding(3, 3, 3, 6); - this.documentsGroupBox.Size = new System.Drawing.Size(258, 492); - this.documentsGroupBox.TabIndex = 1; - this.documentsGroupBox.TabStop = false; - this.documentsGroupBox.Text = "Documents"; - // - // documentTreeView - // - this.documentTreeView.ContextMenuStrip = this.documentTreeContextMenu; - this.documentTreeView.Dock = System.Windows.Forms.DockStyle.Fill; - this.documentTreeView.ImageIndex = 0; - this.documentTreeView.ImageList = this.iconsImageList; - this.documentTreeView.Location = new System.Drawing.Point(3, 17); - this.documentTreeView.Name = "documentTreeView"; - this.documentTreeView.SelectedImageIndex = 0; - this.documentTreeView.Size = new System.Drawing.Size(252, 469); - this.documentTreeView.TabIndex = 0; - this.documentTreeView.AfterCollapse += new System.Windows.Forms.TreeViewEventHandler(this.documentTreeView_AfterCollapse); - this.documentTreeView.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.documentTreeView_AfterSelect); - this.documentTreeView.AfterExpand += new System.Windows.Forms.TreeViewEventHandler(this.documentTreeView_AfterExpand); - // - // documentTreeContextMenu - // - this.documentTreeContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.saveAsMenu}); - this.documentTreeContextMenu.Name = "documentTreeContextMenu"; - this.documentTreeContextMenu.Size = new System.Drawing.Size(130, 26); - // - // saveAsMenu - // - this.saveAsMenu.Image = global::NPOI.Tools.POIFSBrowser.Properties.Resources.SaveAs; - this.saveAsMenu.Name = "saveAsMenu"; - this.saveAsMenu.Size = new System.Drawing.Size(129, 22); - this.saveAsMenu.Text = "Save as..."; - this.saveAsMenu.Click += new System.EventHandler(this.saveAsMenu_Click); - // - // iconsImageList - // - this.iconsImageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("iconsImageList.ImageStream"))); - this.iconsImageList.TransparentColor = System.Drawing.Color.Transparent; - this.iconsImageList.Images.SetKeyName(0, "File"); - this.iconsImageList.Images.SetKeyName(1, "Folder"); - this.iconsImageList.Images.SetKeyName(2, "FolderOpen"); - this.iconsImageList.Images.SetKeyName(3, "Property"); - this.iconsImageList.Images.SetKeyName(4, "Binary"); - this.iconsImageList.Images.SetKeyName(5, "SummaryStream"); - // - // streamGroupBox - // - this.streamGroupBox.Controls.Add(this.streamTabControl); - this.streamGroupBox.Dock = System.Windows.Forms.DockStyle.Fill; - this.streamGroupBox.Location = new System.Drawing.Point(0, 0); - this.streamGroupBox.Name = "streamGroupBox"; - this.streamGroupBox.Padding = new System.Windows.Forms.Padding(3, 3, 3, 6); - this.streamGroupBox.Size = new System.Drawing.Size(516, 492); - this.streamGroupBox.TabIndex = 1; - this.streamGroupBox.TabStop = false; - this.streamGroupBox.Text = "Stream"; - // - // streamTabControl - // - this.streamTabControl.Controls.Add(this.tabPageBinary); - this.streamTabControl.Controls.Add(this.tabPageProperties); - this.streamTabControl.Dock = System.Windows.Forms.DockStyle.Fill; - this.streamTabControl.ImageList = this.iconsImageList; - this.streamTabControl.Location = new System.Drawing.Point(3, 17); - this.streamTabControl.Name = "streamTabControl"; - this.streamTabControl.SelectedIndex = 0; - this.streamTabControl.Size = new System.Drawing.Size(510, 469); - this.streamTabControl.TabIndex = 2; - // - // tabPageBinary - // - this.tabPageBinary.Controls.Add(this.viewableTextBox); - this.tabPageBinary.ImageKey = "Binary"; - this.tabPageBinary.Location = new System.Drawing.Point(4, 23); - this.tabPageBinary.Name = "tabPageBinary"; - this.tabPageBinary.Padding = new System.Windows.Forms.Padding(3); - this.tabPageBinary.Size = new System.Drawing.Size(502, 442); - this.tabPageBinary.TabIndex = 0; - this.tabPageBinary.Text = "Binary"; - this.tabPageBinary.UseVisualStyleBackColor = true; - // - // viewableTextBox - // - this.viewableTextBox.Dock = System.Windows.Forms.DockStyle.Fill; - this.viewableTextBox.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(162))); - this.viewableTextBox.Location = new System.Drawing.Point(3, 3); - this.viewableTextBox.Multiline = true; - this.viewableTextBox.Name = "viewableTextBox"; - this.viewableTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Both; - this.viewableTextBox.Size = new System.Drawing.Size(496, 436); - this.viewableTextBox.TabIndex = 1; - this.viewableTextBox.WordWrap = false; - // - // tabPageProperties - // - this.tabPageProperties.Controls.Add(this.propertiesListView); - this.tabPageProperties.ImageKey = "Property"; - this.tabPageProperties.Location = new System.Drawing.Point(4, 23); - this.tabPageProperties.Name = "tabPageProperties"; - this.tabPageProperties.Padding = new System.Windows.Forms.Padding(3); - this.tabPageProperties.Size = new System.Drawing.Size(502, 442); - this.tabPageProperties.TabIndex = 1; - this.tabPageProperties.Text = "Properties"; - this.tabPageProperties.UseVisualStyleBackColor = true; - // - // propertiesListView - // - this.propertiesListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.columnId, - this.columnName, - this.columnType, - this.columnValue}); - this.propertiesListView.Dock = System.Windows.Forms.DockStyle.Fill; - this.propertiesListView.FullRowSelect = true; - this.propertiesListView.GridLines = true; - this.propertiesListView.Location = new System.Drawing.Point(3, 3); - this.propertiesListView.Name = "propertiesListView"; - this.propertiesListView.ShowItemToolTips = true; - this.propertiesListView.Size = new System.Drawing.Size(496, 436); - this.propertiesListView.SmallImageList = this.iconsImageList; - this.propertiesListView.TabIndex = 0; - this.propertiesListView.UseCompatibleStateImageBehavior = false; - this.propertiesListView.View = System.Windows.Forms.View.Details; - // - // columnId - // - this.columnId.Text = "ID"; - this.columnId.Width = 49; - // - // columnName - // - this.columnName.Text = "Name"; - this.columnName.Width = 150; - // - // columnType - // - this.columnType.Text = "Type"; - this.columnType.Width = 59; - // - // columnValue - // - this.columnValue.Text = "Value"; - this.columnValue.Width = 225; - // - // MainForm - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(784, 564); - this.Controls.Add(this.mainSplitContainer); - this.Controls.Add(this.toolStrip); - this.Controls.Add(this.statusStrip); - this.Controls.Add(this.menuStrip); - this.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(162))); - this.MainMenuStrip = this.menuStrip; - this.Name = "MainForm"; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; - this.Text = "POIFS Browser"; - this.menuStrip.ResumeLayout(false); - this.menuStrip.PerformLayout(); - this.toolStrip.ResumeLayout(false); - this.toolStrip.PerformLayout(); - this.mainSplitContainer.Panel1.ResumeLayout(false); - this.mainSplitContainer.Panel2.ResumeLayout(false); - this.mainSplitContainer.ResumeLayout(false); - this.documentsGroupBox.ResumeLayout(false); - this.documentTreeContextMenu.ResumeLayout(false); - this.streamGroupBox.ResumeLayout(false); - this.streamTabControl.ResumeLayout(false); - this.tabPageBinary.ResumeLayout(false); - this.tabPageBinary.PerformLayout(); - this.tabPageProperties.ResumeLayout(false); - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.MenuStrip menuStrip; - private System.Windows.Forms.ToolStripMenuItem fileMenu; - private System.Windows.Forms.StatusStrip statusStrip; - private System.Windows.Forms.ToolStrip toolStrip; - private System.Windows.Forms.SplitContainer mainSplitContainer; - private System.Windows.Forms.TreeView documentTreeView; - private System.Windows.Forms.ImageList iconsImageList; - private System.Windows.Forms.ToolStripMenuItem fileOpenMenuItem; - private System.Windows.Forms.ToolStripButton openToolStripButton; - private System.Windows.Forms.ListView propertiesListView; - private System.Windows.Forms.ColumnHeader columnId; - private System.Windows.Forms.ColumnHeader columnName; - private System.Windows.Forms.ColumnHeader columnType; - private System.Windows.Forms.ColumnHeader columnValue; - private System.Windows.Forms.GroupBox streamGroupBox; - private System.Windows.Forms.GroupBox documentsGroupBox; - private System.Windows.Forms.TextBox viewableTextBox; - private System.Windows.Forms.ContextMenuStrip documentTreeContextMenu; - private System.Windows.Forms.ToolStripMenuItem saveAsMenu; - private System.Windows.Forms.ToolStripMenuItem helpToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem aboutMenuItem; - private System.Windows.Forms.TabControl streamTabControl; - private System.Windows.Forms.TabPage tabPageBinary; - private System.Windows.Forms.TabPage tabPageProperties; - private System.Windows.Forms.ToolStripSeparator fileMenSeparator1; - private System.Windows.Forms.ToolStripMenuItem fileExitMenuItem; - private System.Windows.Forms.ToolStripButton refreshToolScripButton; - } -} - diff --git a/tools/POIFS Browser/MainForm.cs b/tools/POIFS Browser/MainForm.cs deleted file mode 100644 index f4cf2665c..000000000 --- a/tools/POIFS Browser/MainForm.cs +++ /dev/null @@ -1,278 +0,0 @@ -/* ==================================================================== - 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. -==================================================================== */ - -/* ================================================================ - * POIFS Browser - * Author: NPOI Team - * HomePage: http://www.codeplex.com/npoi - * Contributors: - * Huseyin Tufekcilerli 2008.11 1.0 - * Tony Qu 2009.2.18 1.2 alpha - * - * ==============================================================*/ - -using System; -using System.IO; -using System.Collections; -using System.Windows.Forms; - -using NPOI.HPSF; -using NPOI.POIFS.FileSystem; -using NPOI.HSSF.UserModel; -using NPOI.HSSF.Record; - -namespace NPOI.Tools.POIFSBrowser -{ - public partial class MainForm : Form - { - private POIFSFileSystem _currentFileSystem; - - - public MainForm() - { - InitializeComponent(); - } - - private void OpenDocument(string path) - { - HSSFWorkbook hssfworkbook = null; - //HWPFDocument hwpf = null; - - using (var stream = File.OpenRead(path)) - { - try - { - _currentFileSystem = new POIFSFileSystem(stream); - //supposing every Excel file has .xls as the extension - if (path.ToLower().IndexOf(".xls")>0) - { - hssfworkbook = new HSSFWorkbook(_currentFileSystem); - } - //else if (path.ToLower().IndexOf(".doc") > 0) - //{ - // hwpf =new HWPFDocument(_currentFileSystem); - //} - } - catch (Exception) - { - MessageBox.Show("Error opening file. Possibly the file is not an OLE2 Compund file.", - "Open File Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - } - - if (_currentFileSystem != null) - { - this.Text = string.Format("POIFS Browser - {0}", path); - documentTreeView.BeginUpdate(); - documentTreeView.Nodes.Clear(); - - TreeNode[] children=null; - if (hssfworkbook != null) - { - children = DirectoryTreeNode.GetChildren(_currentFileSystem.Root, hssfworkbook); - } - else - { - children = DirectoryTreeNode.GetChildren(_currentFileSystem.Root, null); - } - documentTreeView.Nodes.AddRange(children); - documentTreeView.EndUpdate(); - - } - } - - private void documentTreeView_AfterExpand(object sender, TreeViewEventArgs e) - { - var directoryTreeNode = e.Node as DirectoryTreeNode; - - if (directoryTreeNode != null) - { - directoryTreeNode.OnExpanded(); - } - } - - private void documentTreeView_AfterCollapse(object sender, TreeViewEventArgs e) - { - var directoryTreeNode = e.Node as DirectoryTreeNode; - - if (directoryTreeNode != null) - { - directoryTreeNode.OnCollapsed(); - } - } - - private void documentTreeView_AfterSelect(object sender, TreeViewEventArgs e) - { - ClearViewControls(); - - if (e.Node is DocumentTreeNode) - { - var documentTreeNode = e.Node as DocumentTreeNode; - var stream = documentTreeNode.GetDocumentStream(); - - var viewableArray = documentTreeNode.DocumentNode.Document.ViewableArray; - if (viewableArray.Length > 0) - { - viewableTextBox.Text = viewableArray.GetValue(0).ToString(); - } - - if (PropertySet.IsPropertySetStream(stream)) - { - var ps = PropertySetFactory.Create(stream); - - propertiesListView.Items.AddRange(PropertyListViewItem.Create(ps)); - - if (!streamTabControl.TabPages.ContainsKey("tabPageProperties")) - { - streamTabControl.TabPages.Add(tabPageProperties); - } - } - else - { - if (streamTabControl.TabPages.ContainsKey("tabPageProperties")) - { - streamTabControl.TabPages.Remove(tabPageProperties); - } - } - - if (!streamTabControl.TabPages.ContainsKey("tabPageBinary")) - { - streamTabControl.TabPages.Add(tabPageBinary); - } - - } - else if (e.Node is AbstractRecordTreeNode) - { - AbstractRecordTreeNode node = (AbstractRecordTreeNode)e.Node; - - if (node.HasBinary) - { - byte[] buffer = node.GetBytes(); - viewableTextBox.Text = NPOI.Util.HexDump.Dump(buffer, buffer.Length, 0); - if (!streamTabControl.TabPages.ContainsKey("tabPageBinary")) - { - streamTabControl.TabPages.Add(tabPageBinary); - } - } - else - { - if (streamTabControl.TabPages.ContainsKey("tabPageBinary")) - { - streamTabControl.TabPages.Remove(tabPageBinary); - } - } - if (!streamTabControl.TabPages.ContainsKey("tabPageProperties")) - { - streamTabControl.TabPages.Add(tabPageProperties); - } - propertiesListView.Items.AddRange(node.GetPropertyList()); - - if (!streamTabControl.TabPages.ContainsKey("tabPageBinary")) - { - streamTabControl.TabPages.Add(tabPageBinary); - } - } - else - { - if (!streamTabControl.TabPages.ContainsKey("tabPageProperties")) - { - streamTabControl.TabPages.Add(tabPageProperties); - } - } - - } - - private void ClearViewControls() - { - viewableTextBox.Clear(); - propertiesListView.Items.Clear(); - } - - private string filename; - private void Open_Click(object sender, EventArgs e) - { - var dialog = new OpenFileDialog() - { - Filter = "Microsoft Office 97-2003 Documents|*.xls;*.doc;*.ppt|POIFS File|*.poifs|All files (*.*)|*.*", - Multiselect = false, - Title = "Open OLE2 Compund Document", - }; - - var result = dialog.ShowDialog(this); - - if (result == DialogResult.OK) - { - filename = dialog.FileName; - OpenDocument(filename); - - ClearViewControls(); - } - } - - private void saveAsMenu_Click(object sender, EventArgs e) - { - - var documentTreeNode = documentTreeView.SelectedNode as DocumentTreeNode; - var directoryTreeNode = documentTreeView.SelectedNode as DirectoryTreeNode; - if (documentTreeNode != null) - { - var dialog = new SaveFileDialog() - { - Filter = "All files|*.*", - Title = "Save Document Stream As" - }; - - var result = dialog.ShowDialog(this); - - if (result == DialogResult.OK) - { - using (var stream = documentTreeNode.GetDocumentStream()) - using (var fileStream = File.OpenWrite(dialog.FileName)) - { - var bufferLength = 4096; - var buffer = new byte[bufferLength]; - int bytesRead; - - while ((bytesRead = stream.Read(buffer, 0, bufferLength)) > 0) - { - fileStream.Write(buffer, 0, bytesRead); - } - } - } - } - } - - private void aboutMenuItem_Click(object sender, EventArgs e) - { - AboutDialog.Instance.ShowDialog(this); - } - - private void fileExitMenuItem_Click(object sender, EventArgs e) - { - Application.Exit(); - } - - private void refreshToolScripButton_Click(object sender, EventArgs e) - { - if (string.IsNullOrEmpty(filename)) - return; - - OpenDocument(filename); - ClearViewControls(); - } - } -} diff --git a/tools/POIFS Browser/MainForm.resx b/tools/POIFS Browser/MainForm.resx deleted file mode 100644 index 2904e19a3..000000000 --- a/tools/POIFS Browser/MainForm.resx +++ /dev/null @@ -1,256 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 17, 17 - - - 132, 17 - - - 248, 17 - - - 485, 17 - - - 353, 17 - - - - AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj0yLjAuMC4w - LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 - ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAACk - GgAAAk1TRnQBSQFMAgEBBgEAAQwBAAEEAQABEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA - AwABIAMAAQEBAAEgBgABIP8AGwABsAGgAZAB/wFeAUYBLgH/AV4BRgEuAf8BXgFGAS4B/wFeAUYBLgH/ - AV4BRgEuAf8BXgFGAS4B/wFeAUYBLgH/AV4BRgEuAf8BXgFGAS4B/wFeAUYBLgH/GAABsAGYAZAB/wFe - AUYBLgH/AV4BRgEuAf8BXgFGAS4B/wFeAUYBLgH/AV4BRgEuAf8BXgFGAS4B/wFeAUYBLgH/AV4BRgEu - Af8BXgFGAS4B/wFeAUYBLgH/kAABsAGgAZAF/wGwAaABkAH/AbABoAGQAf8BsAGgAZAB/wGwAaABkAH/ - AbABoAGQAf8BsAGgAZAB/wGwAaABkAH/AbABoAGQAf8BXgFGAS4B/xgAAbABmAGQAf8C8AHgAf8C8AHg - Af8C8AHgAf8C8AHgAf8B8AHoAeAB/wHwAegB4AH/AfAB6AHgAf8B8AHoAeAB/wHwAegB4AH/AV4BRgEu - Af+QAAGwAaABkAr/AfgC/wPwAf8B8AHoAeAB/wHwAeAB0AH/AeAC0AH/AeAByAHAAf8BsAGgAZAB/wFe - AUYBLgH/GAABsAGYAZAB/wPwAv8ByAGBAv8ByAGBAv8ByAGBAv8ByAGBAv8ByAGBAv8ByAGBAv8ByAGB - Af8B8AHoAeAB/wFeAUYBLgH/kAABsAGgAZAK/wH4Av8D8AH/AfAB6AHgAf8B8AHgAdAB/wHgAtAB/wHg - AcgBwAH/AbABoAGQAf8BXgFGAS4B/xgAAbABmAGQAf8D8AL/AcgBkAL/AcgBkAL/AcgBkAL/AcgBkAL/ - AcgBkAL/AcgBkAL/AcgBgQH/AvAB4AH/AV4BRgEuAf+QAAGwAaABkA7/AfgB8AH/A/AB/wHwAuAB/wHw - AdgB0AH/AeAB0AHAAf8BsAGgAZAB/wFeAUYBLgH/GAABsAGYAZAB/wPwAv8ByAGQAf8BsAGYAZAB/wGw - AZgBkAH/AbABmAGQAf8BsAGYAZAB/wGwAZgBkAL/AdABkAH/A/AB/wFeAUYBLgH/kAABsAGgAZAJ/wGw - AXYBXgX/AbABdgFeAf8B8AHoAeAB/wHwAuAB/wHgAdgB0AH/AbABoAGQAf8BXgFGAS4B/xgAAbABmAGQ - Av8B+AHwAv8B0AGQAv8B0AGQAv8B0AGQAv8B0AGQAv8B0AGQAv8B0AGQAv8B0AGQAf8D8AH/AV4BRgEu - Af+QAAHAAagBkAX/AbABgQFuAf8BsAGBAV4B/wGwAXYBXgH/AbABgQFuAf8BwAGYAYEB/wHwAegB4AH/ - AfAB2AHQAf8BsAGgAZAB/wFeAUYBLgH/GAABsAGgAZAC/wH4AfAC/wHQAaAB/wGwAZgBkAL/AdABoAH/ - AbABmAGQAv8B0AGgAf8BsAGYAZAC/wHQAaAB/wPwAf8BXgFGAS4B/5AAAcABqAGgCf8BsAGBAW4F/wGw - AYgBbgH/A/AB/wHwAegB4AH/AfAC4AH/AbABoAGQAf8BXgFGAS4B/xgAAcABqAGQAv8B+AHwAv8B2AGg - Av8B2AGgAf8BsAGYAZAC/wHQAaAB/wGwAZgBkAL/AdgBoAL/AdABoAL/AfgB8AH/AV4BRgEuAf+QAAHA - AbABoAX/AbABiAFuAf8BsAGIAW4B/wGwAYEBbgH/AbABiAFuAf8BwAGQAYEB/wPwAf8B8AHoAeAB/wGw - AaABkAH/AV4BRgEuAf8YAAHAAagBoAL/AfgD/wHYAbAB/wGwAZgBkAL/AdgBsAH/AbABmAGQAv8B2AGw - Af8BsAGYAZAC/wHYAbAC/wH4AfAB/wFeAUYBLgH/kAAB0AGwAaAJ/wGwAYgBbgX/AbABiAFuBv8B+AHw - Af8BsAGgAZAB/wGwAaABkAH/AV4BRgEuAf8YAAHAAagBoAb/AdgBsAL/AdgBsAL/AdgBsAL/AdgBsAL/ - AdgBsAL/AdgBsAL/AdgBsAL/AfgB8AH/AV4BRgEuAf+QAAHQAbgBoBn/AbABoAGQAf8BXgFGAS4B/wFe - AUYBLgH/AV4BRgEuAf8YAAHAAbABoAb/AeABsAL/AeABsAL/AeABsAL/AeABsAL/AeABsAH/AbABmAGQ - Af8BXgFGAS4B/wFeAUYBLgH/AV4BRgEuAf+QAAHQAbgBsBn/AcABqAGQAf8B0AHIAcAB/wFeAUYBLgH/ - AeAB0AHAAf8YAAHQAbgBoAb/AeABwAL/AeABwAL/AeABwAL/AeABwAL/AeABwAH/AbABmAGQAf8B0AHI - AcAB/wFeAUYBLgH/AUwCSQGQkAAB4AHAAbAZ/wHAAagBoAH/AV4BRgEuAf8B4AHQAcAB/xwAAdABuAGw - Gf8BsAGgAZAB/wFeAUYBLgH/AUwCSQGQlAAB4AHAAbAB/wHgAcABsAH/AeABwAGwAf8B4AHAAbAB/wHg - AcABsAH/AdABwAGwAf8B0AG4AbAB/wHQAbABoAH/AeAB0AHAAf8gAAHQAbgBsAH/AdABuAGwAf8B0AG4 - AbAB/wHQAbgBsAH/AdABuAGwAf8B0AGwAaAB/wHAAbABoAH/AcABqAGgAf8BTAJJAZD/AP8AmgABsAGg - AZAB/wFYAUABKAH/AVgBQAEoAf8BWAFAASgB/wFYAUABKAH/AVgBQAEoAf8BWAFAASgB/wFYAUABKAH/ - AVgBQAEoAf8BWAFAASgB/wFYAUABKAH/TAABagGIAZAB/wFaAYEBkAH/AVoBcgGBAf8BSgFqAYEB/wFK - AVoBagH/AToBUgFaAf8BOgFCAUoB/wEqATIBOgH/ARoCKgH/AhoBKgH/AQoBEgEaAf8DCgH/AgoBGgH/ - DAABwAGgAZAB/wFbAUMBKwH/AVsBQwErAf8BWwFDASsB/wFbAUMBKwH/AVsBQwErAf8BWwFDASsB/wFb - AUMBKwH/AVsBQwErAf8BWwFDASsB/wFbAUMBKwH/AVsBQwErAf8YAAGwAaABkAX/AbABoAGQAf8BsAGg - AZAB/wGwAaABkAH/AbABoAGQAf8BsAGgAZAB/wGwAaABkAH/AbABoAGQAf8BsAGgAZAB/wFYAUABKAH/ - DAABaAGIAZAB/wFoAXABgQH/AVgCaAH/AUgCWAH/ATgCSAH/ASgBMAE4Af8BGAEgASgB/wEIAhgB/wII - ARgB/wIIARgB/wIIARgB/wIIARgB/wIIARgB/wIIARgB/wIIARgB/wQAAWoBiAGQAf8BkAGgAbAB/wFq - AbAB0AH/AQABkAHQAf8BAAGQAdAB/wEAAZAB0AH/AQABkAHAAf8BCgGIAcAB/wEKAYEBsAH/AQoBgQGw - Af8BGgFyAaAB/wEaAWoBkAH/ARoBQgFaAf8DMgFQCAABwAGoAZAC/wH4AfAC/wHwAeAB/wHwAegB4AH/ - AfAB4AHQAf8B8AHQAcAB/wHwAcgBsAH/AeABwAGgAf8B4AG4AaAB/wHgAbABkAH/AeABqAGQAf8BWwFD - ASsB/xgAAbABoAGQCv8B+AL/A/AB/wHwAegB4AH/AfAB4AHQAf8B4ALQAf8B4AHIAcAB/wGwAaABkAH/ - AVgBQAEoAf8MAAFoAYgBkAH/AaAB4AHwAf8BaAHQAfAB/wFIAbgB4AH/ASgBsAHgAf8BKAGoAeAB/wEY - AaAB0AH/ARgBmAHAAf8BGAGQAcAB/wEYAYEBsAH/ARgBgQGwAf8BCAGBAbAB/wEYAXABoAH/ARgBaAGQ - Af8BCAIYAf8EAAGBAYgBkAH/AYEBwAHQAf8BkAGoAbAB/wGBAeAC/wFaAdAC/wFKAcgC/wFKAcgC/wE6 - AcAB8AH/ASoBsAHwAf8BKgGoAfAB/wEaAaAB4AH/AQoBkAHQAf8BGgFiAYEB/wFVAk0BsAgAAcABqAGg - A/8B8AH/AcABqAGgAf8BsAKgAf8B8AHoAeAB/wGwAaABkAH/AbABmAGQAf8BsAGYAZAB/wGwAZgBkAH/ - AbABmAGQAf8B4AGwAZAB/wFbAUMBKwH/GAABsAGgAZAO/wH4AfAB/wPwAf8B8ALgAf8B8AHYAdAB/wHg - AdABwAH/AbABoAGQAf8BWAFAASgB/wwAAYEBiAGQAf8BsAHoAfAB/wGQAegC/wGBAeAC/wFoAdgC/wFo - AdAB8AH/AVgByAHwAf8BSAHAAfAB/wE4AbgB8AH/ASgBqAHwAf8BKAGoAeAB/wEYAZgB4AH/AQgBkAHQ - Af8BGAFwAaAB/wEYASABKAH/BAABgQGQAaAB/wGBAdAB8AH/AZABqAGwAf8BkAHAAdAB/wFqAdgC/wFa - AdAC/wFaAdAC/wFKAcgC/wFKAcAC/wE6AbgB8AH/ASoBsAHwAf8BKgGoAfAB/wEKAYgB0AH/ARoBQgFa - Af8DFwEgBAABwAGoAaAD/wHwA/8B8AL/AfgB8AL/AfAB4AH/AfAB6AHgAf8B8AHgAdAB/wHwAdABwAH/ - AfAByAGwAf8B4AHAAaAB/wHgAbgBoAH/AVsBQwErAf8YAAGwAaABkBL/AvAB/wHwAegB4AH/AfAC4AH/ - AeAB2AHQAf8BsAGgAZAB/wFYAUABKAH/DAABgQGQAaAB/wGwAegB8AH/AaAB6AL/AZAB6AL/AYEB4AL/ - AWgB2AL/AWgB0AHwAf8BWAHIAfAB/wFIAcAB8AH/ATgBuAHwAf8BKAGoAfAB/wEoAaAB4AH/ARgBmAHg - Af8BCAGBAbAB/wEoATABOAH/BAABgQGQAaAB/wGBAdgB8AH/AYEByAHgAf8BkAGoAbAB/wGBAeAC/wFq - AdAC/wFaAdgC/wFaAdAC/wFaAdAC/wFKAcgC/wE6AcAB8AH/AToBuAHwAf8BKgGwAfAB/wEaAWIBgQH/ - AUwCSQGQBAABwAGoAaAD/wHwAf8BsAGoAaAB/wGwAqAC/wH4AfAB/wGwAaABkAH/AbABmAGQAf8BsAGY - AZAB/wGwAZgBkAH/AbABmAGQAf8B4AHAAaAB/wFbAUMBKwH/GAABwAGoAZAS/wH4AfAB/wPwAf8B8AHo - AeAB/wHwAdgB0AH/AbABoAGQAf8BWAFAASgB/wwAAYEBkAGgAf8BsAHwAv8BsAHwAv8BoAHoAv8BkAHg - Av8BgQHgAv8BaAHYAv8BaAHQAfAB/wFYAcgB8AH/AUgBwAHwAf8BOAGwAfAB/wEoAagB8AH/ARgBoAHg - Af8BCAGBAbAB/wI4AUgB/wQAAYEBmAGgAf8BkAHgAfAB/wGQAeAC/wGQAagBsAH/AZABuAHAAf8BagHY - Av8BWgHYAv8BWgHYAv8BWgHYAv8BWgHQAv8BSgHQAv8BSgHIAv8BOgG4AfAB/wEqAaAB4AH/AVQBSwFO - AfADIQEwAcABsAGgA/8B8AP/AfAD/wHwA/8B8AL/AfgB8AL/AfAB4AH/AfAB6AHgAf8B8AHgAdAB/wHw - AdABwAH/AfAByAGwAf8BWwFDASsB/xgAAcABqAGgFv8B+AHwAf8B8AHoAeAB/wHwAuAB/wGwAaABkAH/ - AVgBQAEoAf8MAAGBAZgBoAH/AcAB8AL/AbAC8AH/AaAB8AL/AaAB6AL/AZAB4AL/AYEB4AL/AWgB2AL/ - AVgB0AHwAf8BWAHIAfAB/wFIAbgB8AH/ATgBsAHwAf8BKAGoAeAB/wEIAYgBwAH/AkgBWAH/BAABgQGY - AaAB/wGQAeAB8AH/AaAB6AL/AYEByAHgAf8BkAGoAbAB/wGBAeAC/wGBAeAC/wGBAeAC/wGBAeAC/wGB - AeAC/wGBAeAC/wGBAeAC/wFqAdgC/wFqAdgC/wFKAagB0AH/AVECTAGgAcABsAGgA/8B8AP/AfAD/wHw - A/8B8AP/AfAC/wH4AfAB/wHAAcgBwAH/ATsBWwFrAf8B8AHgAdAB/wHwAdABwAH/AVsBQwErAf8MAAMM - ARAIAAHAAbABoBb/AfgC/wPwAf8B8AHoAeAB/wGwAaABkAH/AVgBQAEoAf8MAAGBAZgBoAH/AcAB8AL/ - AbAB8AL/AbAB8AL/AaAB6AL/AZAB6AL/AZAB4AL/AYEB4AL/AWgB2AL/AVgB0AHwAf8BWAHIAfAB/wFI - AbgB8AH/ASgBqAHgAf8BCAGQAcAB/wFIAVgBaAH/BAABkAKgAf8BoAHoAfAB/wGgAegC/wGgAegC/wGQ - AbABwAH/AZABsAHAAf8BkAGoAbAB/wGQAagBsAH/AYEBoAGwAf8BgQGgAbAB/wGBAZgBoAH/AYEBmAGg - Af8BgQGQAaAB/wGBAZABoAH/AYEBiAGQAf8BagGIAZAB/wHAAbABoAX/AeAB6AHwAf8BWwFzAYEB/wPg - A/8B8AH/AcAByAHQAf8BSwFbAWsB/wErAagB0AH/ARsBMwE7Af8BsAKgAf8BWwFDASsB/wgAAUACPwFw - ATsBgQFLAf8IAAHQAbABoBr/AfgB8AH/A/AB/wGwAaABkAH/AVgBQAEoAf8MAAGQAqAB/wHAAfAC/wGw - AfAC/wGwAfAC/wGwAvAB/wGgAfAC/wGQAegC/wGQAeAC/wGBAeAC/wFoAdAC/wFYAdAB8AH/AUgBwAHw - Af8BSAG4AfAB/wEYAZgB0AH/AVgBaAGBAf8EAAGQAaABsAH/AaAB6AHwAf8BoAHwAv8BoAHoAv8BoAHo - Av8BgQHYAv8BWgHYAv8BWgHYAv8BWgHYAv8BWgHYAv8BWgHYAv8BWgHYAv8BagGIAZAB/wwAAdABsAGg - Bf8BkAGoAbAB/wGBAdAB4AH/AUsBWwFrAf8BsAG4AcAB/wFLAVsBawH/AVsBwAHgAf8BSwFbAWsB/wEr - AbgB8AH/AQsBIwErAf8BCwErATsB/wELASMBKwH/AUwCSQGQATsBcwE7Af8BSwGoAVsB/wgAAdABuAGg - Hf8BsAGgAZAB/wGwAaABkAH/AVgBQAEoAf8MAAGQAaABsAH/AcAB8AL/AcAB8AL/AcAB8AL/AcAB8AL/ - AbAB8AL/AbAB8AL/AaAB6AL/AZAB6AL/AZAB4AL/AYEB2AL/AWgB0AL/AWgByAHwAf8BWAHAAfAB/wFY - AWgBgQH/BAABkAGgAbAB/wGgAvAB/wGwAvAB/wGgAfAC/wGgAegC/wGgAegC/wFqAdgC/wGQAqAB/wGB - AZgBoAH/AYEBmAGgAf8BgQGQAaAB/wGBApAB/wFqAYgBkAH/DAAB0AG4AaAF/wHQAdgB4AH/AZABqAGw - Af8BgQHgAfAB/wFLAVsBawH/AYEB0AHgAf8BSwFbAWsB/wFbAdAB8AH/ATsBWwFrAf8BKwGwAeAB/wEb - AZgB0AH/ARsBiAGwAf8BGwFLAWsB/wFLAYgBWwH/AUsBsAFbAf8IAAHQAbgBsBn/AbABoAGQAf8BWAFA - ASgB/wFYAUABKAH/AVgBQAEoAf8MAAGQAaABsAH/AZABoAGwAf8BkAGgAbAB/wGQAaABsAH/AZABoAGw - Af8BkAGgAbAB/wGQAqAB/wGQAZgBoAH/AYEBmAGgAf8BgQGYAaAB/wGBAZgBoAH/AYEBmAGgAf8BgQGY - AaAB/wGBAZgBoAH/AToCOQFgBAABkAGoAbAB/wGgAdAB4AH/AbAC8AH/AbAC8AH/AaAB8AL/AaAB6AL/ - AZABoAGwAf8BRwJFAYAgAAHQAbgBoAH/AdABuAGgAf8B0AG4AaAB/wKwAaAB/wGQAagBsAH/AYEB4AHw - Af8BSwFbAWsB/wGBAeAB8AH/ATsBUwFrAf8BWwHQAfAB/wFLAcgB8AH/ATsBwAHwAf8BGwGwAeAB/wEb - AaAB0AH/AVsBmAFrAf8BSwG4AWsB/wgAAdABwAGwGf8BwAGoAZAB/wHQAcgBwAH/AVgBQAEoAf8BTAJJ - AZAMAAGQAagBsAH/AbAB6AHwAf8BsAHwAv8BsAHwAv8BsALwAf8BkAHgAfAB/wGQAaABsAH/AUcCRQGA - IAADMgFQAZABqAGwAf8BkAGoAbAB/wGQAagBsAH/AZABqAGwAf8BkAGoAbAB/wFMAkkBkDAAAZABqAGw - Af8BGwGBAaAB/wGQAagBsAH/AYEB4AHwAf8BOwFTAWsB/wGBAeAB8AH/AWsB2AHwAf8BWwHQAfAB/wFL - AcgB8AH/ATsBwAHwAf8BKwG4AfAB/wFrAagBgQH/AVsBwAGBAf8IAAHgAcABsBn/AcABqAGgAf8BWAFA - ASgB/wFMAkkBkBAAAyEBMAGQAagBsAH/AZABqAGwAf8BkAGoAbAB/wGQAagBsAH/AZABqAGwAf8DKgFA - cAABTAJJApABqAGwAf8BGwGBAaAB/wGQAagBsAH/AYEB4AHwAf8BgQHgAfAB/wGBAeAB8AH/AWsB2AHw - Af8BWwHQAfAB/wFbAbAB0AH/AYEBiAGQAf8BsAHAAaAB/wGQAdABoAH/CAAB4AHAAbAB/wHgAcABsAH/ - AeABwAGwAf8B4AHAAbAB/wHgAcABsAH/AdABwAGwAf8B0AG4AbAB/wHQAbABoAH/AUwCSQGQqAADMgFQ - AVUCTQGwAZABqAGwAf8BkAGgAbAB/wGQAqAB/wGBAZgBoAH/AYEBkAGgAf8BgQGIAZAB/wFHAkUBgAGg - AbgBoAH/AbABwAGgAf//AAEAAUIBTQE+BwABPgMAASgDAAFAAwABIAMAAQEBAAEBBgABARYAA/8BAAT/ - BAABwAEHAeABAwQAAcABBwHgAQMEAAHAAQcB4AEDBAABwAEHAeABAwQAAcABBwHgAQMEAAHAAQcB4AED - BAABwAEHAeABAwQAAcABBwHgAQMEAAHAAQcB4AEDBAABwAEHAeABAwQAAcABBwHgAQMEAAHAAQcB4AED - BAABwAEPAeABBwQAAcABHwHgAQ8EAAT/BAAI/wHAAQcC/wEAAQcBAAEPAcABBwEAAQEBAAEDAQABDwHA - AQcBAAEBAQABAwEAAQ8BwAEHAQABAQEAAQEBAAEPAcABBwEAAQEBAAEBAQABDwHAAQcBAAEBAwABDwHA - AQcBAAEBAwABDgHAAQcBAAEBAwABDAHAAQcBAAEBAQABBwIAAcABBwEAAQEBAAEHAgABwAEHAQABAQEA - Af8CAAHAAQcBAAH/AQEB/wHgAQABwAEPAQED/wHgAQABwAEfBP8B+AEACP8L - - - \ No newline at end of file diff --git a/tools/POIFS Browser/MockRecordVisitor.cs b/tools/POIFS Browser/MockRecordVisitor.cs deleted file mode 100644 index f873c1869..000000000 --- a/tools/POIFS Browser/MockRecordVisitor.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using NPOI.HSSF.Record.Aggregates; -using NPOI.HSSF.Record; - -namespace NPOI.Tools.POIFSBrowser -{ - public class MockRecordVisitor : RecordVisitor - { - - private List _list; - public MockRecordVisitor() - { - _list = new List(); - } - public void VisitRecord(Record r) - { - _list.Add(r); - } - public List Records - { - get { return _list; } - } - } -} diff --git a/tools/POIFS Browser/POIFSBrowser.csproj b/tools/POIFS Browser/POIFSBrowser.csproj deleted file mode 100644 index e7ea08622..000000000 --- a/tools/POIFS Browser/POIFSBrowser.csproj +++ /dev/null @@ -1,141 +0,0 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {1D3BE35D-A885-4A96-BE95-94F81307F4DE} - WinExe - Properties - NPOI.Tools.POIFSBrowser - POIFSBrowser - v4.0 - 512 - - - - - - - - - - - 3.5 - - - - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - AllRules.ruleset - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - AllRules.ruleset - - - - ..\..\solution\Lib\ICSharpCode.SharpZipLib.dll - - - ..\..\solution\Lib\NPOI.dll - - - - - - - - - - Form - - - AboutDialog.cs - - - - - - - - - - - Code - - - Form - - - MainForm.cs - - - - - - AboutDialog.cs - - - MainForm.cs - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - True - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/tools/POIFS Browser/POIFSBrowser.csproj.vspscc b/tools/POIFS Browser/POIFSBrowser.csproj.vspscc deleted file mode 100644 index b6d32892f..000000000 --- a/tools/POIFS Browser/POIFSBrowser.csproj.vspscc +++ /dev/null @@ -1,10 +0,0 @@ -"" -{ -"FILE_VERSION" = "9237" -"ENLISTMENT_CHOICE" = "NEVER" -"PROJECT_FILE_RELATIVE_PATH" = "" -"NUMBER_OF_EXCLUDED_FILES" = "0" -"ORIGINAL_PROJECT_FILE_PATH" = "" -"NUMBER_OF_NESTED_PROJECTS" = "0" -"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" -} diff --git a/tools/POIFS Browser/POIFSBrowser.sln b/tools/POIFS Browser/POIFSBrowser.sln deleted file mode 100644 index e5d30d06c..000000000 --- a/tools/POIFS Browser/POIFSBrowser.sln +++ /dev/null @@ -1,22 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.21005.1 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "POIFSBrowser", "POIFSBrowser.csproj", "{1D3BE35D-A885-4A96-BE95-94F81307F4DE}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {1D3BE35D-A885-4A96-BE95-94F81307F4DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1D3BE35D-A885-4A96-BE95-94F81307F4DE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1D3BE35D-A885-4A96-BE95-94F81307F4DE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1D3BE35D-A885-4A96-BE95-94F81307F4DE}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/tools/POIFS Browser/Program.cs b/tools/POIFS Browser/Program.cs deleted file mode 100644 index 7dcb3c433..000000000 --- a/tools/POIFS Browser/Program.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* ==================================================================== - 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. -==================================================================== */ - -/* ================================================================ - * POIFS Browser - * Author: NPOI Team - * HomePage: http://www.codeplex.com/npoi - * Contributors: - * Huseyin Tufekcilerli 2008.11 1.0 - * Tony Qu 2009.2.18 1.2 alpha - * - * ==============================================================*/ - -using System; -using System.Windows.Forms; - -namespace NPOI.Tools.POIFSBrowser -{ - static class Program - { - [STAThread] - static void Main() - { - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - Application.Run(new MainForm()); - } - } -} \ No newline at end of file diff --git a/tools/POIFS Browser/Properties/AssemblyInfo.cs b/tools/POIFS Browser/Properties/AssemblyInfo.cs deleted file mode 100644 index c608066ec..000000000 --- a/tools/POIFS Browser/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("POIFS Browser")] -[assembly: AssemblyDescription("NPOI.Tools.POIFSBrowser")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("NPOI Team")] -[assembly: AssemblyProduct("POIFS Browser")] -[assembly: AssemblyCopyright("Apache License 2.0")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("169c3ca6-4b0e-4d7e-8a5a-305805cfb201")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.2.4.0")] -[assembly: AssemblyFileVersion("1.2.4.0")] diff --git a/tools/POIFS Browser/Properties/Resources.Designer.cs b/tools/POIFS Browser/Properties/Resources.Designer.cs deleted file mode 100644 index d43c5a35c..000000000 --- a/tools/POIFS Browser/Properties/Resources.Designer.cs +++ /dev/null @@ -1,103 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18444 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace NPOI.Tools.POIFSBrowser.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NPOI.Tools.POIFSBrowser.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap arrow_refresh { - get { - object obj = ResourceManager.GetObject("arrow_refresh", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap NET_h_rgb_2 { - get { - object obj = ResourceManager.GetObject("NET_h_rgb_2", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap Open { - get { - object obj = ResourceManager.GetObject("Open", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap SaveAs { - get { - object obj = ResourceManager.GetObject("SaveAs", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - } -} diff --git a/tools/POIFS Browser/Properties/Resources.resx b/tools/POIFS Browser/Properties/Resources.resx deleted file mode 100644 index fd731f5cc..000000000 --- a/tools/POIFS Browser/Properties/Resources.resx +++ /dev/null @@ -1,133 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - ..\Resources\Open.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\SaveAs.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\NET_h_rgb_2.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\resources\arrow_refresh.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - \ No newline at end of file diff --git a/tools/POIFS Browser/Properties/Settings.Designer.cs b/tools/POIFS Browser/Properties/Settings.Designer.cs deleted file mode 100644 index 66866106d..000000000 --- a/tools/POIFS Browser/Properties/Settings.Designer.cs +++ /dev/null @@ -1,26 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18444 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace NPOI.Tools.POIFSBrowser.Properties { - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default { - get { - return defaultInstance; - } - } - } -} diff --git a/tools/POIFS Browser/Properties/Settings.settings b/tools/POIFS Browser/Properties/Settings.settings deleted file mode 100644 index 39645652a..000000000 --- a/tools/POIFS Browser/Properties/Settings.settings +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/tools/POIFS Browser/PropertyListViewItem.cs b/tools/POIFS Browser/PropertyListViewItem.cs deleted file mode 100644 index bab522dc4..000000000 --- a/tools/POIFS Browser/PropertyListViewItem.cs +++ /dev/null @@ -1,98 +0,0 @@ -/* ==================================================================== - 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. -==================================================================== */ - -/* ================================================================ - * POIFS Browser - * Author: NPOI Team - * HomePage: http://www.codeplex.com/npoi - * Contributors: - * Huseyin Tufekcilerli 2008.11 1.0 - * Tony Qu 2009.2.18 1.2 alpha - * - * ==============================================================*/ - -using System; -using System.Collections; -using System.Windows.Forms; -using NPOI.HPSF; -using NPOI.HPSF.Wellknown; - -namespace NPOI.Tools.POIFSBrowser -{ - internal class PropertyListViewItem : ListViewItem, IComparable - { - public Property Property { get; private set; } - public string TypeName { get; set; } - - private PropertyListViewItem(Property property, PropertyIDMap propertyIDMap) - : base(new string[] { - property.ID.ToString(), - propertyIDMap.ContainsKey(property.ID) ? - propertyIDMap[property.ID].ToString() : string.Empty, - property.Type.ToString(), - property.Value.ToString() - }) - { - this.Property = property; - - this.ImageKey = "Property"; - } - - public static PropertyListViewItem[] Create(PropertySet propertySet) - { - PropertyIDMap propertyIDMap; - - if (propertySet.IsDocumentSummaryInformation) - { - propertyIDMap = PropertyIDMap.DocumentSummaryInformationProperties; - } - else if (propertySet.IsSummaryInformation) - { - propertyIDMap = PropertyIDMap.SummaryInformationProperties; - } - else - { - propertyIDMap = new PropertyIDMap(new Hashtable()); - } - - var length = propertySet.Properties.Length; - var propertyListViewItems = new PropertyListViewItem[length]; - for (int i = 0; i < length; i++) - { - var property = propertySet.Properties[i]; - - //TODO:: filter empty name items - PropertyListViewItem tmp= new PropertyListViewItem(property, propertyIDMap); - - propertyListViewItems[i] =tmp ; - } - - System.Array.Sort(propertyListViewItems); - - return propertyListViewItems; - } - - #region IComparable Members - - public int CompareTo(PropertyListViewItem other) - { - return this.Property.ID.CompareTo(other.Property.ID); - } - - #endregion - } -} \ No newline at end of file diff --git a/tools/POIFS Browser/Resources/NET_h_rgb_2.png b/tools/POIFS Browser/Resources/NET_h_rgb_2.png deleted file mode 100644 index 6d4f42ab1..000000000 Binary files a/tools/POIFS Browser/Resources/NET_h_rgb_2.png and /dev/null differ diff --git a/tools/POIFS Browser/Resources/Open.png b/tools/POIFS Browser/Resources/Open.png deleted file mode 100644 index 6cec6869a..000000000 Binary files a/tools/POIFS Browser/Resources/Open.png and /dev/null differ diff --git a/tools/POIFS Browser/Resources/SaveAs.png b/tools/POIFS Browser/Resources/SaveAs.png deleted file mode 100644 index 5c1c127e8..000000000 Binary files a/tools/POIFS Browser/Resources/SaveAs.png and /dev/null differ diff --git a/tools/POIFS Browser/Resources/arrow_refresh.png b/tools/POIFS Browser/Resources/arrow_refresh.png deleted file mode 100644 index 0de26566d..000000000 Binary files a/tools/POIFS Browser/Resources/arrow_refresh.png and /dev/null differ diff --git a/tools/POIFS Browser/app.config b/tools/POIFS Browser/app.config deleted file mode 100644 index fcd0c9373..000000000 --- a/tools/POIFS Browser/app.config +++ /dev/null @@ -1,3 +0,0 @@ - - -