diff --git a/OpenXmlFormats/Drawing/GraphicalObject.cs b/OpenXmlFormats/Drawing/GraphicalObject.cs index 99cef49b6..9e427b8e6 100644 --- a/OpenXmlFormats/Drawing/GraphicalObject.cs +++ b/OpenXmlFormats/Drawing/GraphicalObject.cs @@ -15,11 +15,13 @@ namespace NPOI.OpenXmlFormats.Dml [XmlRoot(Namespace = "http://schemas.openxmlformats.org/drawingml/2006/main", IsNullable = true)] public class CT_GraphicalObjectData { + public XmlNode DomNode { get; set; } public static CT_GraphicalObjectData Parse(XmlNode node, XmlNamespaceManager namespaceManager) { if (node == null) return null; CT_GraphicalObjectData ctObj = new CT_GraphicalObjectData(); + ctObj.DomNode = node; ctObj.uri = XmlHelper.ReadString(node.Attributes["uri"]); ctObj.Any = new List(); foreach (XmlNode childNode in node.ChildNodes) diff --git a/OpenXmlFormats/Spreadsheet/Styles/CT_Dxfs.cs b/OpenXmlFormats/Spreadsheet/Styles/CT_Dxfs.cs index d1786dd35..7d8a71185 100644 --- a/OpenXmlFormats/Spreadsheet/Styles/CT_Dxfs.cs +++ b/OpenXmlFormats/Spreadsheet/Styles/CT_Dxfs.cs @@ -12,7 +12,7 @@ namespace NPOI.OpenXmlFormats.Spreadsheet public class CT_Dxfs { - + private Dictionary dictAlternateContent = []; private List dxfField; private uint countField; @@ -23,12 +23,38 @@ public static CT_Dxfs Parse(XmlNode node, XmlNamespaceManager namespaceManager) if (node == null) return null; CT_Dxfs ctObj = new CT_Dxfs(); + ctObj.InnerXml = node.InnerXml; ctObj.count = XmlHelper.ReadUInt(node.Attributes["count"]); ctObj.dxfField = new List(); + int index = 0; foreach (XmlNode childNode in node.ChildNodes) { if (childNode.LocalName == "dxf") ctObj.dxf.Add(CT_Dxf.Parse(childNode, namespaceManager)); + else if(childNode.LocalName == "AlternateContent") + { + //styleSheet:dxfs maybe have schema like this + //mc:AlternateContent + // mc:Choice + // x:dxf + // mc:Fallback + // x:dxf + foreach (XmlNode acChildNode in childNode.ChildNodes) + { + if (acChildNode.LocalName == "Fallback") + { + foreach(XmlNode fbChild in acChildNode.ChildNodes) + { + if(fbChild.LocalName == "dxf") + { + ctObj.dxf.Add(CT_Dxf.Parse(fbChild, namespaceManager)); + } + } + } + } + ctObj.dictAlternateContent.Add(index, childNode.OuterXml); + } + index ++; } return ctObj; } @@ -43,10 +69,17 @@ internal void Write(StreamWriter sw, string nodeName) if (this.dxf.Count > 0) { sw.Write(">"); - foreach (CT_Dxf x in this.dxf) + for(int i=0; i", nodeName)); } else @@ -59,6 +92,9 @@ internal void Write(StreamWriter sw, string nodeName) public CT_Dxfs() { } + + public string InnerXml { get; set;} + [XmlElement] public List dxf { diff --git a/main/SS/UserModel/ClientAnchor.cs b/main/SS/UserModel/ClientAnchor.cs index 304d679fd..a9e2c64fa 100644 --- a/main/SS/UserModel/ClientAnchor.cs +++ b/main/SS/UserModel/ClientAnchor.cs @@ -18,127 +18,173 @@ namespace NPOI.SS.UserModel { public enum AnchorType : int { - /** - * Move and Resize With Anchor Cells - *

- * Specifies that the current drawing shall move and - * resize to maintain its row and column anchors (i.e. the - * object is anchored to the actual from and to row and column) - *

- */ + /// + /// + /// Move and Resize With Anchor Cells (0) + /// + /// + /// Specifies that the current Drawing shall Move and + /// resize to maintain its row and column anchors (i.e. the + /// object is anchored to the actual from and to row and column) + /// + /// MoveAndResize = 0, - /** - * Move With Cells but Do Not Resize - *

- * Specifies that the current drawing shall move with its - * row and column (i.e. the object is anchored to the - * actual from row and column), but that the size shall remain absolute. - *

- *

- * If Additional rows/columns are Added between the from and to locations of the drawing, - * the drawing shall move its to anchors as needed to maintain this same absolute size. - *

- */ + /// + /// + /// Don't Move but do Resize With Anchor Cells (1) + /// + /// + /// Specifies that the current Drawing shall not Move with its + /// row and column, but should be resized. This option is not normally + /// used, but is included for completeness. + /// + /// + /// Note: Excel has no Setting for this combination, nor does the ECMA standard. + /// + /// + DontMoveDoResize =1, + + /// + /// + /// Move With Cells but Do Not Resize (2) + /// + /// + /// Specifies that the current Drawing shall Move with its + /// row and column (i.e. the object is anchored to the + /// actual from row and column), but that the size shall remain absolute. + /// + /// + /// If additional rows/columns are added between the from and to locations of the Drawing, + /// the Drawing shall Move its to anchors as needed to maintain this same absolute size. + /// + /// MoveDontResize = 2, - /** - * Do Not Move or Resize With Underlying Rows/Columns - *

- * Specifies that the current start and end positions shall - * be maintained with respect to the distances from the - * absolute start point of the worksheet. - *

- *

- * If Additional rows/columns are Added before the - * drawing, the drawing shall move its anchors as needed - * to maintain this same absolute position. - *

- */ + /// + /// + /// Do Not Move or Resize With Underlying Rows/Columns (3) + /// + /// + /// Specifies that the current start and end positions shall + /// be maintained with respect to the distances from the + /// absolute start point of the worksheet. + /// + /// + /// If additional rows/columns are added before the + /// Drawing, the Drawing shall Move its anchors as needed + /// to maintain this same absolute position. + /// + /// DontMoveAndResize = 3 - } - /** - * A client anchor is attached to an excel worksheet. It anchors against a - * top-left and bottom-right cell. - * - * @author Yegor Kozlov - */ + /// + /// A client anchor is attached to an excel worksheet. It anchors against + /// absolute coordinates, a top-left cell and fixed height and width, or + /// a top-left and bottom-right cell, depending on the : + /// + /// == absolute top-left coordinates and width/height, no cell references + /// == fixed top-left cell reference, absolute width/height + /// == fixed top-left and bottom-right cell references, dynamic width/height + /// + /// Note this class only reports the current values for possibly calculated positions and sizes. + /// If the sheet row/column sizes or positions shift, this needs updating via external calculations. + /// public interface IClientAnchor { - - /** - * Returns the column (0 based) of the first cell. - * - * @return 0-based column of the first cell. - */ + /// + /// Get or set the column (0 based) of the first cell, or -1 if there is no top-left anchor cell. + /// This is the case for absolute positioning + /// + /// 0-based column of the first cell or -1 if none. int Col1 { get; set; } - /** - * Returns the column (0 based) of the second cell. - * - * @return 0-based column of the second cell. - */ + /// + /// Get or set the column (0 based) of the second cell, or -1 if there is no bottom-right anchor cell. + /// This is the case for absolute positioning () + /// and absolute sizing (. + /// + /// 0-based column of the second cell or -1 if none. int Col2 { get; set; } - /** - * Returns the row (0 based) of the first cell. - * - * @return 0-based row of the first cell. - */ + /// + /// Get or set the row (0 based) of the first cell, or -1 if there is no bottom-right anchor cell. + /// This is the case for absolute positioning (). + /// + /// 0-based row of the first cell or -1 if none. int Row1 { get; set; } - /** - * Returns the row (0 based) of the second cell. - * - * @return 0-based row of the second cell. - */ + /// + /// Get or set the row (0 based) of the second cell, or -1 if there is no bottom-right anchor cell. + /// This is the case for absolute positioning () + /// and absolute sizing (. + /// + /// 0-based row of the second cell or -1 if none. int Row2 { get; set; } - /** - * Returns the x coordinate within the first cell - * - * @return the x coordinate within the first cell - */ + /// + /// + /// Get or set the x coordinate within the first cell. + /// + /// + /// Note - XSSF and HSSF have a slightly different coordinate + /// system, values in XSSF are larger by a factor of + /// + /// + /// + /// the x coordinate within the first cell int Dx1 { get; set; } - /** - * Returns the y coordinate within the first cell - * - * @return the y coordinate within the first cell - */ + /// + /// + /// Get or set the y coordinate within the first cell + /// + /// + /// Note - XSSF and HSSF have a slightly different coordinate + /// system, values in XSSF are larger by a factor of + /// + /// + /// + /// the y coordinate within the first cell int Dy1 { get; set; } - /** - * Sets the y coordinate within the second cell - * - * @return the y coordinate within the second cell - */ + /// + /// + /// Get or set the y coordinate within the second cell + /// + /// + /// Note - XSSF and HSSF have a slightly different coordinate + /// system, values in XSSF are larger by a factor of + /// + /// + /// + /// the y coordinate within the second cell int Dy2 { get; set; } - /** - * Returns the x coordinate within the second cell - * - * @return the x coordinate within the second cell - */ + /// + /// + /// Get or set the x coordinate within the second cell + /// + /// + /// Note - XSSF and HSSF have a slightly different coordinate + /// system, values in XSSF are larger by a factor of + /// + /// + /// + /// the x coordinate within the second cell int Dx2 { get; set; } - /** - * s the anchor type - *

- * 0 = Move and size with Cells, 2 = Move but don't size with cells, 3 = Don't move or size with cells. - *

- * @return the anchor type - * @see #MOVE_AND_RESIZE - * @see #MOVE_DONT_RESIZE - * @see #DONT_MOVE_AND_RESIZE - */ + /// + /// Get or set the anchor type + /// Changed from returning an int to an enum in POI 3.14 beta 1. + /// + /// the anchor type AnchorType AnchorType { get; set; } } diff --git a/main/Util/Units.cs b/main/Util/Units.cs index 9a885216f..56ba67d2f 100644 --- a/main/Util/Units.cs +++ b/main/Util/Units.cs @@ -22,30 +22,49 @@ namespace NPOI.Util */ public class Units { - /** - * In Escher absolute distances are specified in - * English Metric Units (EMUs), occasionally referred to as A units; - * there are 360000 EMUs per centimeter, 914400 EMUs per inch, 12700 EMUs per point. - */ + /// + /// In Escher absolute distances are specified in + /// English Metric Units (EMUs), occasionally referred to as A units; + /// there are 360000 EMUs per centimeter, 914400 EMUs per inch, 12700 EMUs per point. + /// public static int EMU_PER_PIXEL = 9525; public static int EMU_PER_POINT = 12700; public static int EMU_PER_CENTIMETER = 360000; - /** - * Master DPI (576 pixels per inch). - * Used by the reference coordinate system in PowerPoint (HSLF) - */ + /// + /// Master DPI (576 pixels per inch). + /// Used by the reference coordinate system in PowerPoint (HSLF) + /// public static int MASTER_DPI = 576; - /** - * Pixels DPI (96 pixels per inch) - */ + /// + /// Pixels DPI (96 pixels per inch) + /// public static int PIXEL_DPI = 96; - /** - * Points DPI (72 pixels per inch) - */ + /// + /// Points DPI (72 pixels per inch) + /// public static int POINT_DPI = 72; + + /// + /// Width of one "standard character" of the default font in pixels. Same for Calibri and Arial. + /// "Standard character" defined as the widest digit character in the given font. + /// Copied from XSSFWorkbook, since that isn't available here. + ///

+ /// Note this is only valid for workbooks using the default Excel font. + ///

+ /// Would be nice to eventually support arbitrary document default fonts. + ///

+ public static float DEFAULT_CHARACTER_WIDTH = 7.0017f; + + /// + /// Column widths are in fractional characters, this is the EMU equivalent. + /// One character is defined as the widest value for the integers 0-9 in the + /// default font. + /// + public static int EMU_PER_CHARACTER = (int)(EMU_PER_PIXEL * DEFAULT_CHARACTER_WIDTH); + /// /// Converts points to EMUs /// @@ -55,43 +74,45 @@ public static int ToEMU(double value) { return (int)Math.Round(EMU_PER_POINT * value); } - /** - * Converts pixels to EMUs - * @param pixels pixels - * @return EMUs - */ + /// + /// Converts pixels to EMUs + /// + /// pixels + /// EMUs public static int PixelToEMU(int pixels) { return pixels * EMU_PER_PIXEL; } + + /// + /// Converts EMUs to points + /// + /// emu + /// points public static double ToPoints(long emu) { return (double)emu / EMU_PER_POINT; } - - /** - * Converts a value of type FixedPoint to a decimal number - * - * @param fixedPoint - * @return decimal number - * - * @see [MS-OSHARED] - 2.2.1.6 FixedPoint - */ + + /// + /// Converts a value of type FixedPoint to a floating point + /// + /// value in fixed point notation + /// floating point (double) + /// [MS-OSHARED] - 2.2.1.6 FixedPoint public static double FixedPointToDecimal(int fixedPoint) { int i = (fixedPoint >> 16); int f = (fixedPoint >> 0) & 0xFFFF; - return i + f / 65536.0; + return i + f / 65536d; } - /** - * Converts a value of type floating point to a FixedPoint - * - * @param floatPoint - * @return fixedPoint - * - * @see [MS-OSHARED] - 2.2.1.6 FixedPoint - */ + /// + /// Converts a value of type floating point to a FixedPoint + /// + /// value in floating point notation + /// fixedPoint value in fixed points notation + /// [MS-OSHARED] - 2.2.1.6 FixedPoint public static int DoubleToFixedPoint(double floatPoint) { double fractionalPart = floatPoint % 1d; @@ -133,5 +154,28 @@ public static double PixelToPoints(int pixel) points /= PIXEL_DPI; return points; } + + public static int CharactersToEMU(double characters) + { + return (int)characters * EMU_PER_CHARACTER; + } + + /// + /// + /// specified in 256ths of a standard character + /// equivalent EMUs + public static int ColumnWidthToEMU(int columnWidth) + { + return CharactersToEMU(columnWidth / 256d); + } + + /// + /// + /// (1/20th of a point) typically used for row heights + /// equivalent EMUs + public static int TwipsToEMU(short twips) + { + return (int)(twips / 20d * EMU_PER_POINT); + } } } \ No newline at end of file diff --git a/ooxml/POIXMLDocument.cs b/ooxml/POIXMLDocument.cs index 222f25ce0..38495b01c 100644 --- a/ooxml/POIXMLDocument.cs +++ b/ooxml/POIXMLDocument.cs @@ -116,21 +116,6 @@ protected PackagePart[] GetRelatedByType(String contentType) return parts; } - /** - * Checks that the supplied Stream (which MUST - * support mark and reSet, or be a PushbackStream) - * has a OOXML (zip) header at the start of it. - * If your Stream does not support mark / reSet, - * then wrap it in a PushBackStream, then be - * sure to always use that, and not the original! - * @param inp An Stream which supports either mark/reSet, or is a PushbackStream - */ - [Obsolete("Use the method from DocumentFactoryHelper")] - public static bool HasOOXMLHeader(Stream inp) - { - return DocumentFactoryHelper.HasOOXMLHeader(inp); - } - /** * Get the document properties. This gives you access to the * core ooxml properties, and the extended ooxml properties. diff --git a/ooxml/POIXMLDocumentPart.cs b/ooxml/POIXMLDocumentPart.cs index 04a5a83d2..22248e1e2 100644 --- a/ooxml/POIXMLDocumentPart.cs +++ b/ooxml/POIXMLDocumentPart.cs @@ -249,6 +249,7 @@ internal static XmlNamespaceManager CreateDefaultNSM() XmlNamespaceManager ns = new XmlNamespaceManager(nt); ns.AddNamespace(string.Empty, PackageNamespaces.SCHEMA_MAIN); ns.AddNamespace("d", PackageNamespaces.SCHEMA_MAIN); + ns.AddNamespace("x", PackageNamespaces.SCHEMA_MAIN); ns.AddNamespace("a", PackageNamespaces.SCHEMA_DRAWING); ns.AddNamespace("xdr", PackageNamespaces.SCHEMA_SHEETDRAWINGS); ns.AddNamespace("r", PackageNamespaces.SCHEMA_RELATIONSHIPS); diff --git a/ooxml/XSSF/Streaming/SXSSFPicture.cs b/ooxml/XSSF/Streaming/SXSSFPicture.cs index a27cb7461..0c95173e4 100644 --- a/ooxml/XSSF/Streaming/SXSSFPicture.cs +++ b/ooxml/XSSF/Streaming/SXSSFPicture.cs @@ -169,7 +169,7 @@ public XSSFClientAnchor GetPreferredSize(double scale) //assert(w > scaledWidth); double cw = GetColumnWidthInPixels(col2); double deltaW = w - scaledWidth; - int dx2 = (int)(XSSFShape.EMU_PER_PIXEL * (cw - deltaW)); + int dx2 = (int)(Units.EMU_PER_PIXEL * (cw - deltaW)); anchor.Col2 = (/*setter*/col2); anchor.Dx2 = (/*setter*/dx2); @@ -185,13 +185,13 @@ public XSSFClientAnchor GetPreferredSize(double scale) //assert(h > scaledHeight); double ch = GetRowHeightInPixels(row2); double deltaH = h - scaledHeight; - int dy2 = (int)(XSSFShape.EMU_PER_PIXEL * (ch - deltaH)); + int dy2 = (int)(Units.EMU_PER_PIXEL * (ch - deltaH)); anchor.Row2 = (/*setter*/row2); anchor.Dy2 = (/*setter*/dy2); CT_PositiveSize2D size2d = GetCTPicture().spPr.xfrm.ext; - size2d.cx = (/*setter*/(long)(scaledWidth * XSSFShape.EMU_PER_PIXEL)); - size2d.cy = (/*setter*/(long)(scaledHeight * XSSFShape.EMU_PER_PIXEL)); + size2d.cx = (/*setter*/(long)(scaledWidth * Units.EMU_PER_PIXEL)); + size2d.cy = (/*setter*/(long)(scaledHeight * Units.EMU_PER_PIXEL)); return anchor; } @@ -203,7 +203,7 @@ private float GetColumnWidthInPixels(int columnIndex) CT_Col col = sheet.GetColumnHelper().GetColumn(columnIndex, false); double numChars = col == null || !col.IsSetWidth() ? DEFAULT_COLUMN_WIDTH : col.width; - return (float)numChars * XSSFWorkbook.DEFAULT_CHARACTER_WIDTH; + return (float)numChars * Units.DEFAULT_CHARACTER_WIDTH; } private float GetRowHeightInPixels(int rowIndex) @@ -214,7 +214,7 @@ private float GetRowHeightInPixels(int rowIndex) SXSSFSheet sheet = _wb.GetSXSSFSheet(xssfSheet); IRow row = sheet.GetRow(rowIndex); float height = row != null ? row.HeightInPoints : sheet.DefaultRowHeightInPoints; - return height * XSSFShape.PIXEL_DPI / XSSFShape.POINT_DPI; + return height * Units.PIXEL_DPI / Units.POINT_DPI; } /// /// diff --git a/ooxml/XSSF/UserModel/Charts/XSSFCategoryAxis.cs b/ooxml/XSSF/UserModel/Charts/XSSFCategoryAxis.cs index d01b4fc6f..dec4f1cfb 100644 --- a/ooxml/XSSF/UserModel/Charts/XSSFCategoryAxis.cs +++ b/ooxml/XSSF/UserModel/Charts/XSSFCategoryAxis.cs @@ -34,6 +34,13 @@ public override long Id } } + public override CT_ShapeProperties Line + { + get + { + return ctCatAx.spPr; + } + } protected override CT_AxPos GetCTAxPos() { return ctCatAx.axPos; diff --git a/ooxml/XSSF/UserModel/Charts/XSSFChartAxis.cs b/ooxml/XSSF/UserModel/Charts/XSSFChartAxis.cs index 82eed5578..ddd94163a 100644 --- a/ooxml/XSSF/UserModel/Charts/XSSFChartAxis.cs +++ b/ooxml/XSSF/UserModel/Charts/XSSFChartAxis.cs @@ -252,7 +252,7 @@ public virtual AxisTickMark MinorTickMark protected abstract CT_TickMark GetMajorCTTickMark(); protected abstract CT_TickMark GetMinorCTTickMark(); public abstract CT_ChartLines GetMajorGridLines(); - + public abstract CT_ShapeProperties Line { get; } public abstract bool HasNumberFormat(); private static ST_Orientation FromAxisOrientation(AxisOrientation orientation) diff --git a/ooxml/XSSF/UserModel/Charts/XSSFDateAxis.cs b/ooxml/XSSF/UserModel/Charts/XSSFDateAxis.cs index 5af8e6a51..a09ae5d93 100644 --- a/ooxml/XSSF/UserModel/Charts/XSSFDateAxis.cs +++ b/ooxml/XSSF/UserModel/Charts/XSSFDateAxis.cs @@ -49,7 +49,7 @@ public override long Id } } - public CT_ShapeProperties Line + public override CT_ShapeProperties Line { get { diff --git a/ooxml/XSSF/UserModel/Charts/XSSFValueAxis.cs b/ooxml/XSSF/UserModel/Charts/XSSFValueAxis.cs index ad0ea59fc..f08129b87 100644 --- a/ooxml/XSSF/UserModel/Charts/XSSFValueAxis.cs +++ b/ooxml/XSSF/UserModel/Charts/XSSFValueAxis.cs @@ -53,6 +53,15 @@ public override long Id } } + public override CT_ShapeProperties Line + { + get + { + return ctValAx.spPr; + } + + } + public void SetCrossBetween(AxisCrossBetween crossBetween) { ctValAx.crossBetween.val= FromCrossBetween(crossBetween); diff --git a/ooxml/XSSF/UserModel/XSSFClientAnchor.cs b/ooxml/XSSF/UserModel/XSSFClientAnchor.cs index f98d419e5..8f4c8671a 100644 --- a/ooxml/XSSF/UserModel/XSSFClientAnchor.cs +++ b/ooxml/XSSF/UserModel/XSSFClientAnchor.cs @@ -16,9 +16,8 @@ limitations under the License. ==================================================================== */ using System; -using System.Security.Cryptography; +using NPOI.OpenXmlFormats.Dml; using NPOI.OpenXmlFormats.Dml.Spreadsheet; -using NPOI.OpenXmlFormats.Spreadsheet; using NPOI.SS; using NPOI.SS.UserModel; using NPOI.SS.Util; @@ -27,26 +26,56 @@ limitations under the License. namespace NPOI.XSSF.UserModel { - /** - * A client anchor is attached to an excel worksheet. It anchors against - * top-left and bottom-right cells. - * - * @author Yegor Kozlov - */ + /// + /// + /// A client anchor is attached to an excel worksheet. It anchors against: + /// + /// A fixed position and fixed size + /// A position relative to a cell (top-left) and a fixed size + /// A position relative to a cell (top-left) and sized relative to another cell (bottom right) + /// + /// + /// + /// which method is used is determined by the . + /// + /// public class XSSFClientAnchor : XSSFAnchor, IClientAnchor { - private int anchorType; + /// + /// placeholder for zeros when needed for dynamic position calculations + /// + private static CT_Marker EMPTY_MARKER = new CT_Marker(); - /** - * Starting anchor point - */ + private AnchorType anchorType; + + /// + /// Starting anchor point (top-left cell + relative offset) + /// if left null recalculate as needed from point + /// private CT_Marker cell1; - /** - * Ending anchor point - */ + /// + /// Ending anchor point (bottom-right cell + relative offset) + /// if left null, re-calculate as needed from size and cell1 + /// private CT_Marker cell2; + /// + /// if present, fixed size of the object to use instead of cell2, which is inferred instead + /// + private CT_PositiveSize2D size; + + /// + /// if present, fixed top-left position to use instead of cell1, which is inferred instead + /// + private CT_Point2D position; + + /// + /// sheet to base dynamic calculations on, if needed. Required if size and/or position or Set. + /// Not needed if cell1/2 are Set explicitly (dynamic sizing and position relative to cells). + /// + private XSSFSheet sheet; + public int left { get; @@ -64,50 +93,89 @@ public int height get; } - /** - * Creates a new client anchor and defaults all the anchor positions to 0. - */ - public XSSFClientAnchor() + /// + /// Creates a new client anchor and defaults all the anchor positions to 0. + /// Sets the type to relative to cell range A1:A1. + /// + public XSSFClientAnchor() : this(0, 0, 0, 0, 0, 0, 0, 0) { - cell1 = new CT_Marker(); - cell1.col= (0); - cell1.colOff=(0); - cell1.row=(0); - cell1.rowOff=(0); - cell2 = new CT_Marker(); - cell2.col=(0); - cell2.colOff=(0); - cell2.row=(0); - cell2.rowOff=(0); } - /** - * Creates a new client anchor and Sets the top-left and bottom-right - * coordinates of the anchor. - * - * @param dx1 the x coordinate within the first cell. - * @param dy1 the y coordinate within the first cell. - * @param dx2 the x coordinate within the second cell. - * @param dy2 the y coordinate within the second cell. - * @param col1 the column (0 based) of the first cell. - * @param row1 the row (0 based) of the first cell. - * @param col2 the column (0 based) of the second cell. - * @param row2 the row (0 based) of the second cell. - */ + /// + /// Creates a new client anchor and Sets the top-left and bottom-right + /// coordinates of the anchor by cell references and offsets. + /// Sets the type to . + /// + /// the x coordinate within the first cell. + /// the y coordinate within the first cell. + /// the x coordinate within the second cell. + /// the y coordinate within the second cell. + /// the column (0 based) of the first cell. + /// the row (0 based) of the first cell. + /// the column (0 based) of the second cell. + /// the row (0 based) of the second cell. public XSSFClientAnchor(int dx1, int dy1, int dx2, int dy2, int col1, int row1, int col2, int row2) - : this() { - + anchorType = AnchorType.MoveAndResize; + cell1 = new CT_Marker(); cell1.col = (col1); cell1.colOff = (dx1); cell1.row = (row1); cell1.rowOff = (dy1); + cell2 = new CT_Marker(); cell2.col = (col2); cell2.colOff = (dx2); cell2.row = (row2); cell2.rowOff = (dy2); } + /// + /// Create XSSFClientAnchor from existing xml beans, sized and positioned relative to a pair of cells. + /// Sets the type to . + /// + /// starting anchor point + /// ending anchor point + internal XSSFClientAnchor(CT_Marker cell1, CT_Marker cell2) + { + anchorType = AnchorType.MoveAndResize; + this.cell1 = cell1; + this.cell2 = cell2; + } + + /// + /// Create XSSFClientAnchor from existing xml beans, sized and positioned relative to a pair of cells. + /// Sets the type to . + /// + /// needed to calculate ending point based on column/row sizes + /// starting anchor point + /// object size, to calculate ending anchor point + internal XSSFClientAnchor(XSSFSheet sheet, CT_Marker cell1, CT_PositiveSize2D size) + { + anchorType = AnchorType.MoveDontResize; + this.sheet = sheet; + this.size = size; + this.cell1 = cell1; + // this.cell2 = calcCell(sheet, cell1, size.Cx, size.Cy); + } + + /// + /// Create XSSFClientAnchor from existing xml beans, sized and positioned relative to a pair of cells. + /// Sets the type to . + /// + /// needed to calculate starting and ending points based on column/row sizes + /// starting absolute position + /// object size, to calculate ending position + internal XSSFClientAnchor(XSSFSheet sheet, CT_Point2D position, CT_PositiveSize2D size) + { + anchorType = AnchorType.DontMoveAndResize; + this.sheet = sheet; + this.position = position; + this.size = size; + // zeros for row/col/offsets + // this.cell1 = calcCell(sheet, EMPTY_MARKER, position.Cx, position.Cy); + // this.cell2 = calcCell(sheet, cell1, size.Cx, size.Cy); + } + /// /// /// @@ -199,18 +267,6 @@ protected long EMUtoMakerRow(ISheet Sheet, int EMU, CT_Marker Mkr) { return -1; } - /** - * Create XSSFClientAnchor from existing xml beans - * - * @param cell1 starting anchor point - * @param cell2 ending anchor point - */ - internal XSSFClientAnchor(CT_Marker cell1, CT_Marker cell2) - { - this.cell1 = cell1; - this.cell2 = cell2; - } - /** * Create XSSFClientAnchor from existing xml beans * @@ -228,6 +284,78 @@ internal XSSFClientAnchor(CT_Marker cell1, CT_Marker cell2, int left, int top, i this.height = Math.Abs(bottom - top); } + /// + /// + /// sheet + /// starting point and offsets (may be zeros) + /// dimensions to calculate relative to starting point + private CT_Marker calcCell(CT_Marker cell, long w, long h) + { + CT_Marker c2 = new CT_Marker(); + + int r = cell.row; + int c = cell.col; + + int cw = Units.ColumnWidthToEMU((int)sheet.GetColumnWidth(c)); + + // start with width - offset, then keep adding column widths until the next one Puts us over w + long wPos = cw - cell.colOff; + + while (wPos < w) + { + c++; + cw = Units.ColumnWidthToEMU((int)sheet.GetColumnWidth(c)); + wPos += cw; + } + // now wPos >= w, so end column = c, now figure offset + c2.col = (c); + c2.colOff = (cw - (wPos - w)); + + int rh = Units.ToEMU(GetRowHeight(sheet, r)); + // start with height - offset, then keep adding row heights until the next one Puts us over h + long hPos = rh - cell.rowOff; + + while (hPos < h) + { + r++; + rh = Units.ToEMU(GetRowHeight(sheet, r)); + hPos += rh; + } + // now hPos >= h, so end row = r, now figure offset + c2.row = (r); + c2.rowOff = (rh - (hPos - h)); + + return c2; + } + + /// + /// + /// sheet + /// row + /// height in twips (1/20th of point) for row or default + private static float GetRowHeight(XSSFSheet sheet, int row) + { + XSSFRow r = sheet.GetRow(row) as XSSFRow; + return r == null ? sheet.DefaultRowHeightInPoints : r.HeightInPoints; + } + + private CT_Marker Cell1 + { + get + { + return cell1 != null ? cell1 : calcCell(EMPTY_MARKER, position.x, position.y); + } + } + + private CT_Marker Cell2 + { + get + { + return cell2 != null ? cell2 : calcCell(Cell1, size.cx, size.cy); + } + + } + public override bool Equals(Object o) { if (o == null || o is not XSSFClientAnchor anchor) return false; @@ -243,10 +371,14 @@ public override bool Equals(Object o) } + public override int GetHashCode() + { + return 42; // any arbitrary constant will do + } public override String ToString() { - return "from : " + cell1.ToString() + "; to: " + cell2.ToString(); + return "from : " + Cell1.ToString() + "; to: " + Cell2.ToString(); } /** @@ -259,7 +391,7 @@ internal CT_Marker From { get { - return cell1; + return Cell1; } set { @@ -277,7 +409,7 @@ public CT_Marker To { get { - return cell2; + return Cell2; } set { @@ -286,10 +418,36 @@ public CT_Marker To } - internal bool IsSet() + internal bool IsSet() + { + CT_Marker c1 = Cell1; + CT_Marker c2 = Cell2; + return !(c1.col == 0 && c2.col == 0 && + c1.row == 0 && c2.row == 0); + } + + /// absolute top-left position, or null if position is determined from the "from" cell + /// To use this, "from" must be Set to null. + /// + /// + /// @since POI 3.17 beta 1 + public CT_Point2D Position + { + get + { + return position; + } + set { position = value; } + } + + /// size or null, if size is determined from the to and from cells + /// To use this, "to" must be Set to null. + /// + /// @since POI 3.17 beta 1 + public CT_PositiveSize2D Size { - return !(cell1.col == 0 && cell2.col == 0 && - cell1.row == 0 && cell2.row == 0); + get { return size; } + set { size = value; } } #region IClientAnchor Members @@ -297,7 +455,7 @@ public override int Dx1 { get { - return (int)cell1.colOff; + return (int)Cell1.colOff; } set { @@ -309,7 +467,7 @@ public override int Dy1 { get { - return (int)cell1.rowOff; + return (int)Cell1.rowOff; } set { @@ -321,7 +479,7 @@ public override int Dy2 { get { - return (int)cell2.rowOff; + return (int)Cell2.rowOff; } set { @@ -333,7 +491,7 @@ public override int Dx2 { get { - return (int)cell2.colOff; + return (int)Cell2.colOff; } set { @@ -344,11 +502,11 @@ public AnchorType AnchorType { get { - return (AnchorType)this.anchorType; + return this.anchorType; } set { - this.anchorType = (int)value; + this.anchorType = value; } } @@ -360,7 +518,7 @@ public int Col1 } set { - cell1.col=value; + Cell1.col=value; } } @@ -368,7 +526,7 @@ public int Col2 { get { - return cell2.col; + return Cell2.col; } set { @@ -380,7 +538,7 @@ public int Row1 { get { - return cell1.row; + return Cell1.row; } set { @@ -392,7 +550,7 @@ public int Row2 { get { - return cell2.row; + return Cell2.row; } set { diff --git a/ooxml/XSSF/UserModel/XSSFDrawing.cs b/ooxml/XSSF/UserModel/XSSFDrawing.cs index d2ac7953f..da7658219 100644 --- a/ooxml/XSSF/UserModel/XSSFDrawing.cs +++ b/ooxml/XSSF/UserModel/XSSFDrawing.cs @@ -592,21 +592,34 @@ public List GetShapes() return lst; } - private static XSSFAnchor GetAnchorFromIEGAnchor(IEG_Anchor ctAnchor) + private XSSFAnchor GetAnchorFromIEGAnchor(IEG_Anchor ctAnchor) { - CT_Marker ctFrom=null, ctTo=null; + XSSFAnchor anchor = null; if (ctAnchor is CT_TwoCellAnchor cellAnchor) { - ctFrom = cellAnchor.from; - ctTo = cellAnchor.to; + CT_TwoCellAnchor ct = (CT_TwoCellAnchor)ctAnchor; + anchor = new XSSFClientAnchor(ct.from, ct.to); } else if (ctAnchor is CT_OneCellAnchor oneCellAnchor) { - ctFrom = oneCellAnchor.from; + CT_OneCellAnchor ct = (CT_OneCellAnchor)ctAnchor; + anchor = new XSSFClientAnchor(Sheet, ct.from, ct.ext); + } + else if (ctAnchor is CT_AbsoluteCellAnchor) + { + CT_AbsoluteCellAnchor ct = (CT_AbsoluteCellAnchor)ctAnchor; + anchor = new XSSFClientAnchor(Sheet, ct.pos, ct.ext); } - XSSFAnchor anchor = new XSSFClientAnchor(ctFrom, ctTo); return anchor; } + public XSSFSheet Sheet + { + get + { + return (XSSFSheet)GetParent(); + } + + } private static XSSFAnchor GetAnchorFromParent(XmlNode obj) { diff --git a/ooxml/XSSF/UserModel/XSSFGraphicFrame.cs b/ooxml/XSSF/UserModel/XSSFGraphicFrame.cs index 859607326..fa356e9cc 100644 --- a/ooxml/XSSF/UserModel/XSSFGraphicFrame.cs +++ b/ooxml/XSSF/UserModel/XSSFGraphicFrame.cs @@ -37,7 +37,6 @@ public class XSSFGraphicFrame : XSSFShape private static CT_GraphicalObjectFrame prototype = null; private CT_GraphicalObjectFrame graphicFrame; - private new XSSFClientAnchor anchor; /** * Construct a new XSSFGraphicFrame object. @@ -49,6 +48,27 @@ public XSSFGraphicFrame(XSSFDrawing Drawing, CT_GraphicalObjectFrame ctGraphicFr { this.drawing = Drawing; this.graphicFrame = ctGraphicFrame; + // TODO: there may be a better way to delegate this + CT_GraphicalObjectData graphicData = graphicFrame.graphic.graphicData; + if (graphicData != null) + { + XmlNodeList nodes = graphicData.DomNode.ChildNodes; + for (int i = 0; i < nodes.Count; i++) + { + XmlNode node = nodes.Item(i); + // if the frame references a chart, associate the chart with this instance + if (node.Name.Equals("c:chart")) + { + // this better succeed or the document is invalid + POIXMLDocumentPart relation = drawing.GetRelationById(node.Attributes.GetNamedItem("r:id").Value); + // Do XWPF charts need similar treatment? + if (relation is XSSFChart) + { + ((XSSFChart)relation).SetGraphicFrame(this); + } + } + } + } } @@ -63,28 +83,28 @@ internal CT_GraphicalObjectFrame GetCTGraphicalObjectFrame() public static CT_GraphicalObjectFrame Prototype() { - CT_GraphicalObjectFrame graphicFrame = new CT_GraphicalObjectFrame(); + CT_GraphicalObjectFrame graphicFrame = new CT_GraphicalObjectFrame(); - NPOI.OpenXmlFormats.Dml.Spreadsheet.CT_GraphicalObjectFrameNonVisual nvGraphic = graphicFrame.AddNewNvGraphicFramePr(); - NPOI.OpenXmlFormats.Dml.Spreadsheet.CT_NonVisualDrawingProps props = nvGraphic.AddNewCNvPr(); - props.id = (0); - props.name = ("Diagramm 1"); - nvGraphic.AddNewCNvGraphicFramePr(); + NPOI.OpenXmlFormats.Dml.Spreadsheet.CT_GraphicalObjectFrameNonVisual nvGraphic = graphicFrame.AddNewNvGraphicFramePr(); + NPOI.OpenXmlFormats.Dml.Spreadsheet.CT_NonVisualDrawingProps props = nvGraphic.AddNewCNvPr(); + props.id = (0); + props.name = ("Diagramm 1"); + nvGraphic.AddNewCNvGraphicFramePr(); - CT_Transform2D transform = graphicFrame.AddNewXfrm(); - CT_PositiveSize2D extPoint = transform.AddNewExt(); - CT_Point2D offPoint = transform.AddNewOff(); + CT_Transform2D transform = graphicFrame.AddNewXfrm(); + CT_PositiveSize2D extPoint = transform.AddNewExt(); + CT_Point2D offPoint = transform.AddNewOff(); - extPoint.cx=(0); - extPoint.cy=(0); - offPoint.x=(0); - offPoint.y=(0); + extPoint.cx=(0); + extPoint.cy=(0); + offPoint.x=(0); + offPoint.y=(0); - CT_GraphicalObject graphic = graphicFrame.AddNewGraphic(); + CT_GraphicalObject graphic = graphicFrame.AddNewGraphic(); - prototype = graphicFrame; + prototype = graphicFrame; return prototype; } @@ -139,7 +159,7 @@ private NPOI.OpenXmlFormats.Dml.Spreadsheet.CT_NonVisualDrawingProps GetNonVisua { get { - return anchor; + return (XSSFClientAnchor)anchor; } set { diff --git a/ooxml/XSSF/UserModel/XSSFShape.cs b/ooxml/XSSF/UserModel/XSSFShape.cs index 1d9fe2b1a..7cb04b4f2 100644 --- a/ooxml/XSSF/UserModel/XSSFShape.cs +++ b/ooxml/XSSF/UserModel/XSSFShape.cs @@ -18,6 +18,8 @@ limitations under the License. using NPOI.OpenXmlFormats.Dml; using NPOI.OpenXmlFormats.Dml.Spreadsheet; using NPOI.SS.UserModel; +using NPOI.Util; +using System; namespace NPOI.XSSF.UserModel { @@ -28,10 +30,13 @@ namespace NPOI.XSSF.UserModel */ public abstract class XSSFShape: IShape { + [Obsolete] public static int EMU_PER_PIXEL = 9525; + [Obsolete] public static int EMU_PER_POINT = 12700; - + [Obsolete] public static int POINT_DPI = 72; + [Obsolete] public static int PIXEL_DPI = 96; /** @@ -231,7 +236,7 @@ public virtual double LineWidth NPOI.OpenXmlFormats.Dml.Spreadsheet.CT_ShapeProperties props = GetShapeProperties(); if (props.IsSetLn()) { - return props.ln.w*1.0 / EMU_PER_POINT; + return props.ln.w*1.0 / Units.EMU_PER_POINT; } else { @@ -242,7 +247,7 @@ public virtual double LineWidth { NPOI.OpenXmlFormats.Dml.Spreadsheet.CT_ShapeProperties props = GetShapeProperties(); CT_LineProperties ln = props.IsSetLn() ? props.ln : props.AddNewLn(); - ln.w = (int)(value * EMU_PER_POINT); + ln.w = (int)(value * Units.EMU_PER_POINT); } } diff --git a/ooxml/XSSF/UserModel/XSSFSheet.cs b/ooxml/XSSF/UserModel/XSSFSheet.cs index 96be823c1..9ec08bef1 100644 --- a/ooxml/XSSF/UserModel/XSSFSheet.cs +++ b/ooxml/XSSF/UserModel/XSSFSheet.cs @@ -2235,7 +2235,7 @@ public double GetColumnWidth(int columnIndex) public double GetColumnWidthInPixels(int columnIndex) { double widthIn256 = GetColumnWidth(columnIndex); - return widthIn256 / 256.0 * XSSFWorkbook.DEFAULT_CHARACTER_WIDTH; + return widthIn256 / 256.0 * Units.DEFAULT_CHARACTER_WIDTH; } /// diff --git a/ooxml/XSSF/UserModel/XSSFTableStyle.cs b/ooxml/XSSF/UserModel/XSSFTableStyle.cs index bdd1aad00..05791bb79 100644 --- a/ooxml/XSSF/UserModel/XSSFTableStyle.cs +++ b/ooxml/XSSF/UserModel/XSSFTableStyle.cs @@ -27,8 +27,7 @@ public XSSFTableStyle(int index, CT_Dxfs dxfs, CT_TableStyle tableStyle, IIndexe if (element.dxfIdSpecified) { int idx = (int)element.dxfId; - CT_Dxf dxf; - dxf = dxfList[idx]; + CT_Dxf dxf = dxfList[idx]; int stripeSize = 0; if (element.size!=0) stripeSize = (int)element.size; if (dxf != null) dstyle = new XSSFDxfStyleProvider(dxf, stripeSize, colorMap); diff --git a/testcases/main/SS/UserModel/TestDataFormatter.cs b/testcases/main/SS/UserModel/TestDataFormatter.cs index a9dfcd417..e7b81977b 100644 --- a/testcases/main/SS/UserModel/TestDataFormatter.cs +++ b/testcases/main/SS/UserModel/TestDataFormatter.cs @@ -859,5 +859,27 @@ Excel displays the month instead of minutes." ClassicAssert.AreEqual("08:51", dfUS.FormatRawCellContents(42605.368761574071, -1, "hh:mm")); ClassicAssert.AreEqual("51:01", dfUS.FormatRawCellContents(42605.368761574071, -1, "mm:ss")); } + + /** + * bug 60422 : DataFormatter has issues with a specific NumberFormat in Germany default locale + * Currently, this test only passes if you set LocaleUtil.setUserLocale(Locale.ROOT) or Locale.US. + */ + [Test] + public void TestBug60422() + { + //LocaleUtil.setUserLocale(Locale.ROOT); + try + { + char euro = '\u20AC'; + DataFormatter df = new DataFormatter(CultureInfo.GetCultureInfo("de-DE")); + String formatString = String.Format("_-* #,##0.00\\ \"{0}\"_-;\\-* #,##0.00\\ \"{1}\"_-;_-* \"-\"??\\ \"{2}\"_-;_-@_-", + euro, euro, euro); + ClassicAssert.AreEqual("4.33 " + euro, df.FormatRawCellContents(4.33, 178, formatString)); + } + finally + { + //LocaleUtil.resetUserLocale(); + } + } } } \ No newline at end of file diff --git a/testcases/ooxml/TestDetectAsOOXML.cs b/testcases/ooxml/TestDetectAsOOXML.cs index 0466c60e4..9fe978ddd 100644 --- a/testcases/ooxml/TestDetectAsOOXML.cs +++ b/testcases/ooxml/TestDetectAsOOXML.cs @@ -75,8 +75,6 @@ public void TestFileCorruption() // detect header InputStream in1 = new PushbackInputStream(testInput, 10); ClassicAssert.IsFalse(DocumentFactoryHelper.HasOOXMLHeader(in1)); - //noinspection deprecation - ClassicAssert.IsFalse(POIXMLDocument.HasOOXMLHeader(in1)); // check if InputStream is still intact byte[] test = new byte[3]; diff --git a/testcases/ooxml/XSSF/Model/TestStylesTable.cs b/testcases/ooxml/XSSF/Model/TestStylesTable.cs index d4a22fecc..6e36cfa9b 100644 --- a/testcases/ooxml/XSSF/Model/TestStylesTable.cs +++ b/testcases/ooxml/XSSF/Model/TestStylesTable.cs @@ -326,7 +326,7 @@ public void MaxNumberOfDataFormats() } [Test] - public void addDataFormatsBeyondUpperLimit() + public void AddDataFormatsBeyondUpperLimit() { XSSFWorkbook wb = new XSSFWorkbook(); @@ -360,7 +360,7 @@ public void addDataFormatsBeyondUpperLimit() } [Test] - public void decreaseUpperLimitBelowCurrentNumDataFormats() + public void DecreaseUpperLimitBelowCurrentNumDataFormats() { XSSFWorkbook wb = new XSSFWorkbook(); @@ -392,6 +392,15 @@ public void decreaseUpperLimitBelowCurrentNumDataFormats() wb.Close(); } } + [Test] + public void TestLoadWithAlternateContent() + { + XSSFWorkbook workbook = XSSFTestDataSamples.OpenSampleWorkbook("style-alternate-content.xlsx"); + ClassicAssert.IsNotNull(workbook.GetStylesSource()); + StylesTable st = workbook.GetStylesSource(); + + ClassicAssert.IsNotNull(XSSFTestDataSamples.WriteOutAndReadBack(workbook)); + } } } diff --git a/testcases/test-data/spreadsheet/style-alternate-content.xlsx b/testcases/test-data/spreadsheet/style-alternate-content.xlsx new file mode 100644 index 000000000..9ae63becf Binary files /dev/null and b/testcases/test-data/spreadsheet/style-alternate-content.xlsx differ