diff --git a/OpenXmlFormats/Drawing/SpreadsheetDrawing.cs b/OpenXmlFormats/Drawing/SpreadsheetDrawing.cs index c04219fab..e821e7c3b 100644 --- a/OpenXmlFormats/Drawing/SpreadsheetDrawing.cs +++ b/OpenXmlFormats/Drawing/SpreadsheetDrawing.cs @@ -1394,7 +1394,12 @@ public int SizeOfOneCellAnchorArray() public static CT_Drawing Parse(XmlDocument xmldoc, XmlNamespaceManager namespaceManager) { - XmlNodeList cellanchorNodes = xmldoc.SelectNodes("/xdr:wsDr/*", namespaceManager); + XmlNode root = xmldoc.SelectSingleNode("/xdr:wsDr", namespaceManager); + if (root == null) + { + return new CT_Drawing(); + } + XmlNodeList cellanchorNodes = root.SelectNodes("descendant::xdr:oneCellAnchor|descendant::xdr:twoCellAnchor|descendant::xdr:absCellAnchor", namespaceManager); CT_Drawing ctDrawing = new CT_Drawing(); foreach (XmlNode node in cellanchorNodes) { diff --git a/OpenXmlFormats/Spreadsheet/Sheet/CT_Table.cs b/OpenXmlFormats/Spreadsheet/Sheet/CT_Table.cs index 5648f3d14..95e72dc94 100644 --- a/OpenXmlFormats/Spreadsheet/Sheet/CT_Table.cs +++ b/OpenXmlFormats/Spreadsheet/Sheet/CT_Table.cs @@ -703,6 +703,25 @@ public void RemoveTableColumn(int columnIndex) { this.tableColumn.RemoveAt(columnIndex); } + + internal CT_TableColumn GetTableColumnArray(int v) + { + if (this.tableColumnField == null) + return null; + if (v < 0 || v >= this.tableColumn.Count) + throw new ArgumentOutOfRangeException(); + return tableColumnField[v]; + } + + public CT_TableColumn AddNewTableColumn() + { + if(this.tableColumnField==null) + this.tableColumnField = new List (); + var c = new CT_TableColumn(); + this.tableColumnField.Add(c); + return c; + } + [XmlElement] public List tableColumn { diff --git a/ooxml/XSSF/UserModel/XSSFCell.cs b/ooxml/XSSF/UserModel/XSSFCell.cs index 42b49450a..4fb5dbe14 100644 --- a/ooxml/XSSF/UserModel/XSSFCell.cs +++ b/ooxml/XSSF/UserModel/XSSFCell.cs @@ -759,12 +759,22 @@ public ICellStyle CellStyle } } } - + /// + /// POI currently supports these formula types: + /// + /// + /// + /// + /// + /// POI does not support formulas. + /// + /// true if the cell is of a formula type POI can handle + /// private bool IsFormulaCell { get { - if (_cell.f != null || ((XSSFSheet)Sheet).IsCellInArrayFormulaContext(this)) + if ((_cell.f != null && _cell.f.t != ST_CellFormulaType.dataTable) || ((XSSFSheet)Sheet).IsCellInArrayFormulaContext(this)) { return true; } @@ -773,7 +783,12 @@ private bool IsFormulaCell } /// - /// Return the cell type. + /// Return the cell type. Tables in an array formula return + /// for all cells, even though the formula is only defined + /// in the OOXML file for the top left cell of the array. + /// + /// NOTE: POI does not support data table formulas. + /// Cells in a data table appear to POI as plain cells typed from their cached value. /// public CellType CellType { diff --git a/ooxml/XSSF/UserModel/XSSFSheet.cs b/ooxml/XSSF/UserModel/XSSFSheet.cs index e89169556..6341f2973 100644 --- a/ooxml/XSSF/UserModel/XSSFSheet.cs +++ b/ooxml/XSSF/UserModel/XSSFSheet.cs @@ -3742,7 +3742,7 @@ public XSSFTable CreateTable() false); XSSFTable table = rp.DocumentPart as XSSFTable; tbl.id = rp.Relationship.Id; - + table.GetCTTable().id = (uint)tableNumber; tables[tbl.id] = table; return table; diff --git a/ooxml/XSSF/UserModel/XSSFTable.cs b/ooxml/XSSF/UserModel/XSSFTable.cs index 9228ed8fc..8c3f7f5a5 100644 --- a/ooxml/XSSF/UserModel/XSSFTable.cs +++ b/ooxml/XSSF/UserModel/XSSFTable.cs @@ -241,6 +241,26 @@ public List GetXmlColumnPrs() } return xmlColumnPrs; } + + public void AddColumn() + { + // Ensure we have Table Columns + CT_TableColumns columns = ctTable.tableColumns; + if (columns == null) + { + columns = ctTable.AddNewTableColumns(); + } + + // Add another Column, and give it a sensible ID + CT_TableColumn column = columns.AddNewTableColumn(); + int num = columns.tableColumn.Count; + columns.count = (uint)num; + column.id = (uint)num; + + // Have the Headers updated if possible + UpdateHeaders(); + } + /** * @return the name of the Table, if set */ @@ -369,41 +389,38 @@ public XSSFTableColumn CreateColumn(String columnName, int columnIndex) 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() + + /// + /// + /// Get or set 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 + /// + /// + /// 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 AreaReference CellReferences { - return new AreaReference( + get + { + 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); + ); + } + set + { + SetCellRef(value); + } } + protected void SetCellRef(AreaReference refs) { @@ -476,6 +493,7 @@ public long NumberOfMappedColumns return ctTable.tableColumns.count; } } + public int ColumnCount { get @@ -610,15 +628,23 @@ public int RowCount } - /** - * Synchronize table headers with cell values in the parent sheet. - * Headers must be in sync, otherwise Excel will display a - * "Found unreadable content" message on startup. - * - * If calling both {@link #updateReferences()} and - * {@link #updateHeaders()}, {@link #updateReferences()} - * should be called first. - */ + /// + /// + /// Synchronize table headers with cell values in the parent sheet. + /// Headers must be in sync, otherwise Excel will display a + /// "Found unreadable content" message on startup. + /// + /// + /// If calling both and + /// , + /// should be called first. + /// + /// + /// Note that a Table must have a header. To reproduce + /// the equivalent of inserting a table in Excel without Headers, + /// manually add cells with values of "Column1", "Column2" etc first. + /// + /// public void UpdateHeaders() { XSSFSheet sheet = (XSSFSheet)GetParent(); @@ -630,6 +656,7 @@ public void UpdateHeaders() int firstHeaderColumn = ref1.Col; XSSFRow row = sheet.GetRow(headerRow) as XSSFRow; + DataFormatter formatter = new DataFormatter(); if (row != null && row.GetCTRow() != null) { @@ -642,7 +669,7 @@ public void UpdateHeaders() { if (row.GetCell(cellnum) is XSSFCell cell) { - col.name = cell.StringCellValue; + col.name = formatter.FormatCellValue(cell); } cellnum++; } diff --git a/testcases/ooxml/XSSF/UserModel/TestUnfixedBugs.cs b/testcases/ooxml/XSSF/UserModel/TestUnfixedBugs.cs index eead8663d..53a7f913c 100644 --- a/testcases/ooxml/XSSF/UserModel/TestUnfixedBugs.cs +++ b/testcases/ooxml/XSSF/UserModel/TestUnfixedBugs.cs @@ -355,43 +355,6 @@ private void checkRow57423(ISheet testSheet, int rowNum, String contents) ClassicAssert.AreEqual(contents, cell.ToString(), "Did not have expected contents at rownum " + rowNum); //ClassicAssert.AreEqual(contents + ".0", cell.ToString(), "Did not have expected contents at rownum " + rowNum); } - - [Test] - public void test58325_one() - { - check58325(XSSFTestDataSamples.OpenSampleWorkbook("58325_lt.xlsx"), 1); - } - [Test] - [Ignore("TODO FIX CI TESTS")] - public void test58325_three() - { - check58325(XSSFTestDataSamples.OpenSampleWorkbook("58325_db.xlsx"), 3); - } - private void check58325(XSSFWorkbook wb, int expectedShapes) - { - XSSFSheet sheet = wb.GetSheet("MetasNM001") as XSSFSheet; - ClassicAssert.IsNotNull(sheet); - StringBuilder str = new StringBuilder(); - str.Append("sheet " + sheet.SheetName + " - "); - XSSFDrawing drawing = sheet.GetDrawingPatriarch(); - //drawing = ((XSSFSheet)sheet).createDrawingPatriarch(); - List shapes = drawing.GetShapes(); - str.Append("drawing.Shapes.size() = " + shapes.Count); - IEnumerator it = shapes.GetEnumerator(); - while (it.MoveNext()) - { - XSSFShape shape = it.Current; - str.Append(", " + shape.ToString()); - str.Append(", Col1:" + ((XSSFClientAnchor)shape.GetAnchor()).Col1); - str.Append(", Col2:" + ((XSSFClientAnchor)shape.GetAnchor()).Col2); - str.Append(", Row1:" + ((XSSFClientAnchor)shape.GetAnchor()).Row1); - str.Append(", Row2:" + ((XSSFClientAnchor)shape.GetAnchor()).Row2); - } - - ClassicAssert.AreEqual(expectedShapes, shapes.Count, - "Having shapes: " + str); - } - } } diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFShape.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFShape.cs index f467b45dc..74c00051f 100644 --- a/testcases/ooxml/XSSF/UserModel/TestXSSFShape.cs +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFShape.cs @@ -1,577 +1,68 @@ -using NPOI.OpenXmlFormats.Dml; -using NPOI.OpenXmlFormats.Dml.Spreadsheet; -using NPOI.SS.UserModel; -using NPOI.Util; -using NPOI.XSSF; -using NPOI.XSSF.UserModel; -using NUnit.Framework;using NUnit.Framework.Legacy; +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + using System; using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.CompilerServices; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NPOI.XSSF; +using NPOI.XSSF.UserModel; +using NUnit.Framework; +using NUnit.Framework.Legacy; namespace TestCases.XSSF.UserModel { [TestFixture] - internal class TestXSSFShapes + internal class TestXSSFShape { [Test] - public void TestShapeLineEndingCapType() - { - - XSSFWorkbook wb = new XSSFWorkbook(); - XSSFSheet sheet = (XSSFSheet)wb.CreateSheet(); - XSSFDrawing drawing = (XSSFDrawing)sheet.CreateDrawingPatriarch(); - - XSSFClientAnchor anchor = new XSSFClientAnchor(0,0,0,0, 1,1,2,2); - - XSSFConnector cxn = drawing.CreateConnector(anchor); - cxn.Name = "sp1"; - cxn.LineEndingCapType = NPOI.SS.UserModel.LineEndingCapType.Round; - - XSSFWorkbook rbwb = (XSSFWorkbook)XSSFITestDataProvider.instance.WriteOutAndReadBack(wb); - - XSSFSheet rb_sht = (XSSFSheet)rbwb.GetSheetAt(0); - XSSFDrawing dr = (XSSFDrawing)rb_sht.GetDrawingPatriarch(); - List lstShp = dr.GetShapes(); - foreach(var sp in lstShp) - { - if(sp.Name == "sp1") - { - ClassicAssert.AreEqual(NPOI.SS.UserModel.LineEndingCapType.Round, sp.LineEndingCapType); - return; - } - } - ClassicAssert.True(false); - } - [Test] - public void TestShapeCompoundLineType() + public void Test58325_one() { - - XSSFWorkbook wb = new XSSFWorkbook(); - XSSFSheet sheet = (XSSFSheet)wb.CreateSheet(); - XSSFDrawing drawing = (XSSFDrawing)sheet.CreateDrawingPatriarch(); - - XSSFClientAnchor anchor = new XSSFClientAnchor(0,0,0,0, 1,1,2,2); - - XSSFConnector cxn = drawing.CreateConnector(anchor); - cxn.Name = "sp2"; - cxn.CompoundLineType = NPOI.SS.UserModel.CompoundLineType.DoubleLines; - - XSSFWorkbook rbwb = (XSSFWorkbook)XSSFITestDataProvider.instance.WriteOutAndReadBack(wb); - - XSSFSheet rb_sht = (XSSFSheet)rbwb.GetSheetAt(0); - XSSFDrawing dr = (XSSFDrawing)rb_sht.GetDrawingPatriarch(); - List lstShp = dr.GetShapes(); - foreach(var sp in lstShp) - { - if(sp.Name == "sp2") - { - ClassicAssert.AreEqual(NPOI.SS.UserModel.CompoundLineType.DoubleLines, sp.CompoundLineType); - return; - } - } - ClassicAssert.True(false); + Check58325(XSSFTestDataSamples.OpenSampleWorkbook("58325_lt.xlsx"), 1); } - [Test] - public void TestGetShapes() + public void Test58325_three() { - XSSFWorkbook wb = XSSFTestDataSamples.OpenSampleWorkbook("TestGetShapes.xlsx"); - XSSFSheet sheet = (XSSFSheet)wb.GetSheet("Sheet0"); - - XSSFDrawing drawing = sheet.GetDrawingPatriarch(); - - List lstShp = drawing.GetShapes(); - foreach(var sp in lstShp) - { - Debug.WriteLine($"name:[{sp.Name}]"); - switch(sp.Name) - { - case "first": - case "second": - case "third": - case "L01": - case "L02": - case "L03": - break; - default: - Assert.Fail($"name is invalid [{sp.Name}]"); - break; - } - } + Check58325(XSSFTestDataSamples.OpenSampleWorkbook("58325_db.xlsx"), 3); } - - [Test] - public void TestShapeTextWrap() + private void Check58325(XSSFWorkbook wb, int expectedShapes) { - XSSFWorkbook wb = XSSFTestDataSamples.OpenSampleWorkbook("TestShapeTextWrap.xlsx"); - XSSFSheet sheet = (XSSFSheet)wb.GetSheet("Sheet1"); + XSSFSheet sheet = wb.GetSheet("MetasNM001") as XSSFSheet; + ClassicAssert.IsNotNull(sheet); + StringBuilder str = new StringBuilder(); + str.Append("sheet " + sheet.SheetName + " - "); XSSFDrawing drawing = sheet.GetDrawingPatriarch(); - - List lstShp = drawing.GetShapes(); - foreach(var sp in lstShp) - { - if(sp.Name == "shape1") - { - ClassicAssert.AreEqual(true, ((XSSFSimpleShape)sp).WordWrap); - XSSFTestDataSamples.WriteOut(wb, "TestShapeTextWrap-1-"); - ((XSSFSimpleShape)sp).WordWrap = false; - XSSFWorkbook rbwb = (XSSFWorkbook)XSSFITestDataProvider.instance.WriteOutAndReadBack(wb); - ClassicAssert.AreEqual(false, ((XSSFSimpleShape)sp).WordWrap); - XSSFTestDataSamples.WriteOut(wb, "TestShapeTextWrap-2-"); - } - } - } - - [Test] - public void TestShapeInset() - { - XSSFWorkbook wb = new XSSFWorkbook(); - XSSFSheet sht0 = (XSSFSheet)wb.CreateSheet(); - XSSFDrawing drawing = (XSSFDrawing)sht0.CreateDrawingPatriarch(); - - //----- create - var ca0 = new XSSFClientAnchor(sht0, Units.ToEMU(100), Units.ToEMU(100), Units.ToEMU(200), Units.ToEMU(200)); - var sp0 = drawing.CreateSimpleShape(ca0); - sp0.LineStyle = LineStyle.Solid; - sp0.LineStyleColor = 0xff00000; - ClassicAssert.AreEqual(7.2, sp0.LeftInset); - ClassicAssert.AreEqual(false, sp0.GetCTShape().txBody.bodyPr.IsSetLIns()); - ClassicAssert.AreEqual(3.6, sp0.TopInset); - ClassicAssert.AreEqual(false, sp0.GetCTShape().txBody.bodyPr.IsSetTIns()); - ClassicAssert.AreEqual(7.2, sp0.RightInset); - ClassicAssert.AreEqual(false, sp0.GetCTShape().txBody.bodyPr.IsSetRIns()); - ClassicAssert.AreEqual(3.6, sp0.BottomInset); - ClassicAssert.AreEqual(false, sp0.GetCTShape().txBody.bodyPr.IsSetBIns()); - XSSFTestDataSamples.WriteOut(wb, "TestShapeTextWrap-1-"); - - //----- zero - sp0.LeftInset = 0; - sp0.TopInset = 0; - sp0.RightInset = 0; - sp0.BottomInset = 0; - XSSFWorkbook rbwb1 = (XSSFWorkbook)XSSFITestDataProvider.instance.WriteOutAndReadBack(wb); - var sht1 = rbwb1.GetSheet("sheet0"); - var dw1 = ((XSSFSheet)sht1).GetDrawingPatriarch(); - XSSFSimpleShape sp1 = (XSSFSimpleShape)dw1.GetShapes()[0]; - ClassicAssert.AreEqual(0, sp1.LeftInset); - ClassicAssert.AreEqual(true, sp1.GetCTShape().txBody.bodyPr.IsSetLIns()); - ClassicAssert.AreEqual(0, sp1.TopInset); - ClassicAssert.AreEqual(true, sp1.GetCTShape().txBody.bodyPr.IsSetTIns()); - ClassicAssert.AreEqual(0, sp1.RightInset); - ClassicAssert.AreEqual(true, sp1.GetCTShape().txBody.bodyPr.IsSetRIns()); - ClassicAssert.AreEqual(0, sp1.BottomInset); - ClassicAssert.AreEqual(true, sp1.GetCTShape().txBody.bodyPr.IsSetBIns()); - XSSFTestDataSamples.WriteOut(rbwb1, "TestShapeTextWrap-2-"); - - //----- others - sp1.LeftInset = 3.6; - sp1.TopInset = 1.8; - sp1.RightInset = 3.6; - sp1.BottomInset = 1.8; - XSSFWorkbook rbwb2 = (XSSFWorkbook)XSSFITestDataProvider.instance.WriteOutAndReadBack(rbwb1); - var sht2 = rbwb2.GetSheet("sheet0"); - var dw2 = ((XSSFSheet)sht2).GetDrawingPatriarch(); - XSSFSimpleShape sp2 = (XSSFSimpleShape)dw2.GetShapes()[0]; - ClassicAssert.AreEqual(3.6, sp2.LeftInset); - ClassicAssert.AreEqual(true, sp2.GetCTShape().txBody.bodyPr.IsSetLIns()); - ClassicAssert.AreEqual(1.8, sp2.TopInset); - ClassicAssert.AreEqual(true, sp2.GetCTShape().txBody.bodyPr.IsSetTIns()); - ClassicAssert.AreEqual(3.6, sp2.RightInset); - ClassicAssert.AreEqual(true, sp2.GetCTShape().txBody.bodyPr.IsSetRIns()); - ClassicAssert.AreEqual(1.8, sp2.BottomInset); - ClassicAssert.AreEqual(true, sp2.GetCTShape().txBody.bodyPr.IsSetBIns()); - XSSFTestDataSamples.WriteOut(rbwb2, "TestShapeTextWrap-3-"); - } - - [Test] - public void TestLockWithSheet() - { - XSSFWorkbook wb = new XSSFWorkbook(); - XSSFSheet sheet = (XSSFSheet)wb.CreateSheet(); - XSSFDrawing drawing = (XSSFDrawing)sheet.CreateDrawingPatriarch(); - - // simple shape - XSSFClientAnchor ca0; - ca0 = new XSSFClientAnchor(sheet, Units.ToEMU(100), Units.ToEMU(100), Units.ToEMU(200), Units.ToEMU(200)); - XSSFSimpleShape shp0 = drawing.CreateSimpleShape(ca0); - shp0.Name = "S00"; - shp0.cellanchor.clientData.fLocksWithSheet = true; - - // connector shape - XSSFClientAnchor ca1; - ca1 = new XSSFClientAnchor(sheet, Units.ToEMU(250), Units.ToEMU(250), Units.ToEMU(350), Units.ToEMU(350)); - XSSFConnector shp1 = drawing.CreateConnector(ca1); - shp1.Name = "L00"; - shp1.cellanchor.clientData.fLocksWithSheet = true; - - XSSFTestDataSamples.WriteOut(wb, "TestLockWithSheet1-"); - - XSSFWorkbook rbwb = (XSSFWorkbook)XSSFITestDataProvider.instance.WriteOutAndReadBack(wb); - - XSSFSheet rb_sht = (XSSFSheet)rbwb.GetSheetAt(0); - XSSFDrawing dr = (XSSFDrawing)rb_sht.GetDrawingPatriarch(); - List lstShp = dr.GetShapes(); - foreach(var sp in lstShp) - { - switch(sp.Name) - { - case "S00": - case "L00": - ClassicAssert.AreEqual(sp.cellanchor.clientData.fLocksWithSheet, true, "shape name:[{0}]", new object[] { sp.Name }); - break; - default: - break; - } - } - - shp0.cellanchor.clientData.fLocksWithSheet = false; - shp1.cellanchor.clientData.fLocksWithSheet = false; - - XSSFTestDataSamples.WriteOut(wb, "TestLockWithSheet2-"); - - XSSFWorkbook rbwb1 = (XSSFWorkbook)XSSFITestDataProvider.instance.WriteOutAndReadBack(wb); - XSSFSheet rb_sht1 = (XSSFSheet)rbwb1.GetSheetAt(0); - XSSFDrawing dr1 = (XSSFDrawing)rb_sht1.GetDrawingPatriarch(); - List lstShp1 = dr1.GetShapes(); - - foreach(var sp in lstShp1) - { - switch(sp.Name) - { - case "S00": - case "L00": - ClassicAssert.AreEqual(sp.cellanchor.clientData.fLocksWithSheet, false, "shape name:[{0}]", new object[] { sp.Name }); - break; - default: - break; - } - } - } - - [Test] - public void TestGroupLockWithSheet() - { - XSSFWorkbook wb = new XSSFWorkbook(); - XSSFSheet sheet = (XSSFSheet)wb.CreateSheet(); - XSSFDrawing drawing = (XSSFDrawing)sheet.CreateDrawingPatriarch(); - - //----- first group - XSSFClientAnchor ganchor1; - ganchor1 = new XSSFClientAnchor(sheet, Units.ToEMU(100), Units.ToEMU(200), Units.ToEMU(200), Units.ToEMU(100)); - ganchor1.AnchorType = AnchorType.DontMoveAndResize; - XSSFShapeGroup grp1= drawing.CreateGroup( ganchor1 ); - grp1.Name = "first"; - - // connector shape - XSSFChildAnchor ca1; - ca1 = new XSSFChildAnchor(Units.ToEMU(100), Units.ToEMU(200), Units.ToEMU(200), Units.ToEMU(100)); - XSSFConnector shp1 = grp1.CreateConnector( ca1 ); - shp1.Name = "L01"; - shp1.cellanchor.clientData.fLocksWithSheet = true; - - //----- second group - XSSFChildGroupAnchor ganchor2; - ganchor2 = new XSSFChildGroupAnchor(Units.ToEMU(110), Units.ToEMU(110), Units.ToEMU(190), Units.ToEMU(190)); - XSSFShapeGroup grp2 = grp1.CreateGroup( ganchor2 ); - grp2.Name = "second"; - - // connector shape - XSSFChildAnchor ca2; - ca2 = new XSSFChildAnchor(Units.ToEMU(110), Units.ToEMU(110), Units.ToEMU(190), Units.ToEMU(190)); - XSSFConnector shp2 = grp2.CreateConnector(ca2); - shp2.Name = "L02"; - shp2.cellanchor.clientData.fLocksWithSheet = true; - - //----- third group - XSSFChildGroupAnchor ganchor3; - ganchor3 = new XSSFChildGroupAnchor(Units.ToEMU(120), Units.ToEMU(120), Units.ToEMU(180), Units.ToEMU(180)); - XSSFShapeGroup grp3 = grp2.CreateGroup( ganchor3 ); - grp3.Name = "third"; - - // connector shape - XSSFChildAnchor ca3; - ca3 = new XSSFChildAnchor(Units.ToEMU(120), Units.ToEMU(150), Units.ToEMU(180), Units.ToEMU(150)); - XSSFConnector shp3 = grp3.CreateConnector(ca3); - shp3.Name = "L03"; - shp3.cellanchor.clientData.fLocksWithSheet = false; - - ClassicAssert.AreEqual(shp1.cellanchor.clientData.fLocksWithSheet, false); - - XSSFTestDataSamples.WriteOut(wb, "TestGroupLockWithSheet"); - } - - [Test] - public void TestRecursiveGroup() - { - XSSFWorkbook wb = new XSSFWorkbook(); - XSSFSheet sheet = (XSSFSheet)wb.CreateSheet(); - XSSFDrawing drawing = (XSSFDrawing)sheet.CreateDrawingPatriarch(); - XSSFFont font = wb.GetStylesSource().GetFontAt( 0 ); - font.SetScheme(FontScheme.NONE); - - //----- first group - XSSFClientAnchor ganchor1; - ganchor1 = new XSSFClientAnchor(sheet, Units.ToEMU(50), Units.ToEMU(400), Units.ToEMU(400), Units.ToEMU(50)); - ganchor1.AnchorType = AnchorType.DontMoveAndResize; - XSSFShapeGroup grp1= drawing.CreateGroup( ganchor1 ); - grp1.Name = "G00"; - - // simple shape - XSSFChildAnchor ca1; - ca1 = new XSSFChildAnchor(Units.ToEMU(100), Units.ToEMU(200), Units.ToEMU(200), Units.ToEMU(100)); - XSSFSimpleShape shp1 = grp1.CreateSimpleShape( ca1 ); - shp1.Name = "S00"; - - // connector shape - XSSFChildAnchor ca2; - ca2 = new XSSFChildAnchor(Units.ToEMU(100), Units.ToEMU(200), Units.ToEMU(200), Units.ToEMU(100)); - XSSFConnector shp2 = grp1.CreateConnector( ca2 ); - shp2.Name = "L00"; - shp2.cellanchor.clientData.fLocksWithSheet = true; - - int x = 300; - int y = 300; - int cx = 310; - int cy = 310; - XSSFShapeGroup grp = grp1; - for(var ct = 1; ct < 5; ct++) - { - //----- second group - XSSFChildGroupAnchor ganchor; - ganchor = new XSSFChildGroupAnchor(Units.ToEMU(x - 25), Units.ToEMU(y - 25), Units.ToEMU(cx+25), Units.ToEMU(cy+25)); - grp = grp.CreateGroup(ganchor); - grp.Name = $"G{ct}"; - - // simple shape - XSSFChildAnchor ca; - ca = new XSSFChildAnchor(Units.ToEMU(x), Units.ToEMU(x), Units.ToEMU(cx), Units.ToEMU(cy)); - XSSFSimpleShape Sshp = grp.CreateSimpleShape( ca ); - Sshp.Name = $"S{ct:00}"; - Sshp.LineStyle = LineStyle.Solid; - Sshp.LineStyleColor = 0x00FF00; - - // connector shape - ca = new XSSFChildAnchor(Units.ToEMU(x), Units.ToEMU(y), Units.ToEMU(cx), Units.ToEMU(cy)); - XSSFConnector Cshp = grp.CreateConnector( ca ); - Cshp.Name = $"L{ct:00}"; - Cshp.cellanchor.clientData.fLocksWithSheet = true; - - x += 25; - y += 25; - cx += 25; - cy += 25; - } - - grp1.AutoFit(sheet); - XSSFTestDataSamples.WriteOut(wb, "TestRecursiveGroup"); - } - - [Test] - public void TestInnerPproduct() - { - DblVect2D b = new DblVect2D(1, 0); - for(double Theta = 0; Theta < Math.PI; Theta+=Math.PI/180.0) - { - DblVect2D c = new DblVect2D(Math.Cos(Theta), Math.Sin(Theta)); - - Debug.WriteLine($"{Theta/Math.PI*180}\t{Theta}\t{c.x}\t{c.y}\t={b.InnerProduct(c)}+$E$1"); - } - } - - [Test] - public void TestBuildFreeform_base() - { - XSSFWorkbook wb = new XSSFWorkbook(); - XSSFSheet sheet = (XSSFSheet)wb.CreateSheet(); - XSSFDrawing drawing = (XSSFDrawing)sheet.CreateDrawingPatriarch(); - XSSFFont font = wb.GetStylesSource().GetFontAt( 0 ); - font.SetScheme(FontScheme.NONE); - - // free form shape - var bff = new BuildFreeForm(); - bff.AddNode(new Coords(Units.ToEMU(100), Units.ToEMU(180))); - bff.AddNode(new Coords(Units.ToEMU(200), Units.ToEMU(200))); - bff.AddNode(new Coords(Units.ToEMU(300), Units.ToEMU(150))); - bff.AddNode(new Coords(Units.ToEMU(400), Units.ToEMU(50))); - if(bff.Build()) - { - var shp = drawing.CreateFreeform(sheet, bff); - shp.SetLineStyleColor(0, 0, 0); - - XSSFTestDataSamples.WriteOut(wb, "TestBuildFreeform_base"); - } - } - - [Test] - public void TestBuildFreeform() - { - XSSFWorkbook wb0 = XSSFTestDataSamples.OpenSampleWorkbook("TestBuildFreeform.xlsx"); - XSSFSheet sheet0 = (XSSFSheet)wb0.GetSheet("Sheet1"); - XSSFDrawing drawing0 = sheet0.GetDrawingPatriarch(); - List lstShp0 = drawing0.GetShapes(); - - XSSFWorkbook wb1 = new XSSFWorkbook(); - XSSFSheet sheet1 = (XSSFSheet)wb1.CreateSheet(sheet0.SheetName); - XSSFDrawing drawing1 = (XSSFDrawing)sheet1.CreateDrawingPatriarch(); - XSSFFont font = wb1.GetStylesSource().GetFontAt( 0 ); - font.SetScheme(FontScheme.NONE); - - foreach(var sp in lstShp0) - { - if(sp.Name.Substring(0, 2) == "FF") - //if(sp.Name.Substring(0, 4) == "FF01") - { - var bff = new BuildFreeForm(); - - var spPr = ((XSSFSimpleShape)sp).GetCTShape().spPr; - var cg = spPr.custGeom; - for(int ct = 0; ct< cg.cxnLst.cxn.Count; ct++) - { - var cd = GetGeomGuide(cg.gdLst.gd, ct); - if( cd != null){ - cd.Add(new Coords(spPr.xfrm.off.x, spPr.xfrm.off.y)); - bff.AddNode(cd); - } - } - if(bff.Build()) - { - var shp = drawing1.CreateFreeform(sheet1, bff); - shp.SetLineStyleColor(0, 0, 0); - shp.Name = sp.Name; - } - } - } - XSSFTestDataSamples.WriteOut(wb1, "TestBuildFreeform"); - - var rbwb = (XSSFWorkbook)XSSFITestDataProvider.instance.WriteOutAndReadBack(wb1); - var rbsheet = (XSSFSheet) rbwb.GetSheet("Sheet1"); - var rbdrawing = rbsheet.GetDrawingPatriarch(); - var rblstShp = rbdrawing.GetShapes(); - foreach(var sp0 in lstShp0) - { - if(sp0.Name.Substring(0, 2) == "FF") - { - var spPr0 = ((XSSFSimpleShape)sp0).GetCTShape().spPr; - var cg0 = spPr0.custGeom; - - foreach(var rbsp in rblstShp) - { - if(sp0.Name == rbsp.Name) - { - var rbspPr = ((XSSFSimpleShape)rbsp).GetCTShape().spPr; - var rbcg = rbspPr.custGeom; //read back custom geometry - - ClassicAssert.IsFalse(!Compeare(spPr0.xfrm.off.x, rbspPr.xfrm.off.x), $"{sp0.Name}-xfrm.off.x:{spPr0.xfrm.off.x}!={rbspPr.xfrm.off.x}"); - ClassicAssert.IsFalse(!Compeare(spPr0.xfrm.off.y, rbspPr.xfrm.off.y), $"{sp0.Name}-xfrm.off.y:{spPr0.xfrm.off.y}!={rbspPr.xfrm.off.y}"); - ClassicAssert.IsFalse(!Compeare(spPr0.xfrm.ext.cx, rbspPr.xfrm.ext.cx), $"{sp0.Name}-xfrm.off.x:{spPr0.xfrm.ext.cx}!={rbspPr.xfrm.ext.cx}"); - ClassicAssert.IsFalse(!Compeare(spPr0.xfrm.ext.cy, rbspPr.xfrm.ext.cy), $"{sp0.Name}-xfrm.off.y:{spPr0.xfrm.ext.cy}!={rbspPr.xfrm.ext.cy}"); - - ClassicAssert.AreEqual(cg0.cxnLst.cxn.Count, rbcg.cxnLst.cxn.Count, $"Count:{cg0.cxnLst.cxn.Count}!={rbcg.cxnLst.cxn.Count}"); - - for(int ct = 0; ct< cg0.cxnLst.cxn.Count; ct++) - { - var cd0 = GetGeomGuide(cg0.gdLst.gd, ct); - if(cd0 != null) - { - var rbcd = GetGeomGuide(rbcg.gdLst.gd, ct); - if(rbcd != null) - { - ClassicAssert.IsFalse(!Compeare(cd0.x, rbcd.x), $"{sp0.Name}-gdLst.x{ct}:{cd0.x}!={rbcd.x}"); - ClassicAssert.IsFalse(!Compeare(cd0.y, rbcd.y), $"{sp0.Name}-gdLst.y{ct}:{cd0.y}!={rbcd.y}"); - } - else - { - throw new Exception(); - } - } - else - { - throw new Exception(); - } - } - var ogph = cg0.pathLst.path[0]; - var rbph = rbcg.pathLst.path[0]; - ClassicAssert.IsFalse(!Compeare(ogph.w, rbph.w), $"{sp0.Name}-path.w:{ogph.w}!={rbph.w}"); - ClassicAssert.IsFalse(!Compeare(ogph.h, rbph.h), $"{sp0.Name}-path.h:{ogph.h}!={rbph.h}"); - - ClassicAssert.IsFalse(!Compeare(ogph.moveto.pt.x, rbph.moveto.pt.x), $"{sp0.Name}-moveto.x:{ogph.moveto.pt.x}!={rbph.moveto.pt.x}"); - ClassicAssert.IsFalse(!Compeare(ogph.moveto.pt.y, rbph.moveto.pt.y), $"{sp0.Name}-moveto.y:{ogph.moveto.pt.y}!={rbph.moveto.pt.y}"); - - ClassicAssert.AreEqual(ogph.cubicBezTo.Count, rbph.cubicBezTo.Count, $"cubicBezTo.Count:{ogph.cubicBezTo.Count}!={rbph.cubicBezTo.Count}"); - - for(int i = 0; i ggs - , int ct - ) { - long x = 0; - long y = 0; - - var gdX = Search(ggs, $"connsiteX{ct}"); - if(gdX != null) - { - string[] fmla = gdX.fmla.Split(new char[] { ' ' }); - x = long.Parse(fmla[1]); - } - var gdY = Search(ggs, $"connsiteY{ct}"); - if(gdY != null) - { - string[] fmla = gdY.fmla.Split(new char[] { ' ' }); - y = long.Parse(fmla[1]); - } - if(gdX == null || gdY ==null) - { - return null; - } - - return new Coords(x, y); - } - - private CT_GeomGuide Search(List Gds, string name) - { - foreach(var gd in Gds) - { - if(gd.name == name) - { - return gd; - } - } - return null; - } - private bool Compeare(long B, long C, long a = 5) - { - if(B-a<=C && C<=B+a) - { - return true; - } - return false; - } - - private bool Compeare(string B, string C, long a = 5) - { - long b = long.Parse(B); - long c = long.Parse(C); - if(b-a<=c && c<=b+a) - { - return true; - } - return false; + //drawing = ((XSSFSheet)sheet).createDrawingPatriarch(); + List shapes = drawing.GetShapes(); + str.Append("drawing.Shapes.size() = " + shapes.Count); + IEnumerator it = shapes.GetEnumerator(); + while (it.MoveNext()) + { + XSSFShape shape = it.Current; + str.Append(", " + shape.ToString()); + str.Append(", Col1:" + ((XSSFClientAnchor)shape.GetAnchor()).Col1); + str.Append(", Col2:" + ((XSSFClientAnchor)shape.GetAnchor()).Col2); + str.Append(", Row1:" + ((XSSFClientAnchor)shape.GetAnchor()).Row1); + str.Append(", Row2:" + ((XSSFClientAnchor)shape.GetAnchor()).Row2); + } + + ClassicAssert.AreEqual(expectedShapes, shapes.Count, + "Having shapes: " + str); } } -} +} \ No newline at end of file diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFShapes.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFShapes.cs new file mode 100644 index 000000000..53f76dcb5 --- /dev/null +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFShapes.cs @@ -0,0 +1,592 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for Additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +using NPOI.OpenXmlFormats.Dml; +using NPOI.SS.UserModel; +using NPOI.Util; +using NPOI.XSSF; +using NPOI.XSSF.UserModel; +using NUnit.Framework;using NUnit.Framework.Legacy; +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace TestCases.XSSF.UserModel +{ + [TestFixture] + internal class TestXSSFShapes + { + [Test] + public void TestShapeLineEndingCapType() + { + + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet(); + XSSFDrawing drawing = (XSSFDrawing)sheet.CreateDrawingPatriarch(); + + XSSFClientAnchor anchor = new XSSFClientAnchor(0,0,0,0, 1,1,2,2); + + XSSFConnector cxn = drawing.CreateConnector(anchor); + cxn.Name = "sp1"; + cxn.LineEndingCapType = NPOI.SS.UserModel.LineEndingCapType.Round; + + XSSFWorkbook rbwb = (XSSFWorkbook)XSSFITestDataProvider.instance.WriteOutAndReadBack(wb); + + XSSFSheet rb_sht = (XSSFSheet)rbwb.GetSheetAt(0); + XSSFDrawing dr = (XSSFDrawing)rb_sht.GetDrawingPatriarch(); + List lstShp = dr.GetShapes(); + foreach(var sp in lstShp) + { + if(sp.Name == "sp1") + { + ClassicAssert.AreEqual(NPOI.SS.UserModel.LineEndingCapType.Round, sp.LineEndingCapType); + return; + } + } + ClassicAssert.True(false); + } + [Test] + public void TestShapeCompoundLineType() + { + + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet(); + XSSFDrawing drawing = (XSSFDrawing)sheet.CreateDrawingPatriarch(); + + XSSFClientAnchor anchor = new XSSFClientAnchor(0,0,0,0, 1,1,2,2); + + XSSFConnector cxn = drawing.CreateConnector(anchor); + cxn.Name = "sp2"; + cxn.CompoundLineType = NPOI.SS.UserModel.CompoundLineType.DoubleLines; + + XSSFWorkbook rbwb = (XSSFWorkbook)XSSFITestDataProvider.instance.WriteOutAndReadBack(wb); + + XSSFSheet rb_sht = (XSSFSheet)rbwb.GetSheetAt(0); + XSSFDrawing dr = (XSSFDrawing)rb_sht.GetDrawingPatriarch(); + List lstShp = dr.GetShapes(); + foreach(var sp in lstShp) + { + if(sp.Name == "sp2") + { + ClassicAssert.AreEqual(NPOI.SS.UserModel.CompoundLineType.DoubleLines, sp.CompoundLineType); + return; + } + } + ClassicAssert.True(false); + } + + [Test] + public void TestGetShapes() + { + XSSFWorkbook wb = XSSFTestDataSamples.OpenSampleWorkbook("TestGetShapes.xlsx"); + XSSFSheet sheet = (XSSFSheet)wb.GetSheet("Sheet0"); + + XSSFDrawing drawing = sheet.GetDrawingPatriarch(); + + List lstShp = drawing.GetShapes(); + foreach(var sp in lstShp) + { + Debug.WriteLine($"name:[{sp.Name}]"); + switch(sp.Name) + { + case "first": + case "second": + case "third": + case "L01": + case "L02": + case "L03": + break; + default: + Assert.Fail($"name is invalid [{sp.Name}]"); + break; + } + } + } + + [Test] + public void TestShapeTextWrap() + { + XSSFWorkbook wb = XSSFTestDataSamples.OpenSampleWorkbook("TestShapeTextWrap.xlsx"); + XSSFSheet sheet = (XSSFSheet)wb.GetSheet("Sheet1"); + XSSFDrawing drawing = sheet.GetDrawingPatriarch(); + + List lstShp = drawing.GetShapes(); + foreach(var sp in lstShp) + { + if(sp.Name == "shape1") + { + ClassicAssert.AreEqual(true, ((XSSFSimpleShape)sp).WordWrap); + XSSFTestDataSamples.WriteOut(wb, "TestShapeTextWrap-1-"); + ((XSSFSimpleShape)sp).WordWrap = false; + XSSFWorkbook rbwb = (XSSFWorkbook)XSSFITestDataProvider.instance.WriteOutAndReadBack(wb); + ClassicAssert.AreEqual(false, ((XSSFSimpleShape)sp).WordWrap); + XSSFTestDataSamples.WriteOut(wb, "TestShapeTextWrap-2-"); + } + } + } + + [Test] + public void TestShapeInset() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sht0 = (XSSFSheet)wb.CreateSheet(); + XSSFDrawing drawing = (XSSFDrawing)sht0.CreateDrawingPatriarch(); + + //----- create + var ca0 = new XSSFClientAnchor(sht0, Units.ToEMU(100), Units.ToEMU(100), Units.ToEMU(200), Units.ToEMU(200)); + var sp0 = drawing.CreateSimpleShape(ca0); + sp0.LineStyle = LineStyle.Solid; + sp0.LineStyleColor = 0xff00000; + ClassicAssert.AreEqual(7.2, sp0.LeftInset); + ClassicAssert.AreEqual(false, sp0.GetCTShape().txBody.bodyPr.IsSetLIns()); + ClassicAssert.AreEqual(3.6, sp0.TopInset); + ClassicAssert.AreEqual(false, sp0.GetCTShape().txBody.bodyPr.IsSetTIns()); + ClassicAssert.AreEqual(7.2, sp0.RightInset); + ClassicAssert.AreEqual(false, sp0.GetCTShape().txBody.bodyPr.IsSetRIns()); + ClassicAssert.AreEqual(3.6, sp0.BottomInset); + ClassicAssert.AreEqual(false, sp0.GetCTShape().txBody.bodyPr.IsSetBIns()); + XSSFTestDataSamples.WriteOut(wb, "TestShapeTextWrap-1-"); + + //----- zero + sp0.LeftInset = 0; + sp0.TopInset = 0; + sp0.RightInset = 0; + sp0.BottomInset = 0; + XSSFWorkbook rbwb1 = (XSSFWorkbook)XSSFITestDataProvider.instance.WriteOutAndReadBack(wb); + var sht1 = rbwb1.GetSheet("sheet0"); + var dw1 = ((XSSFSheet)sht1).GetDrawingPatriarch(); + XSSFSimpleShape sp1 = (XSSFSimpleShape)dw1.GetShapes()[0]; + ClassicAssert.AreEqual(0, sp1.LeftInset); + ClassicAssert.AreEqual(true, sp1.GetCTShape().txBody.bodyPr.IsSetLIns()); + ClassicAssert.AreEqual(0, sp1.TopInset); + ClassicAssert.AreEqual(true, sp1.GetCTShape().txBody.bodyPr.IsSetTIns()); + ClassicAssert.AreEqual(0, sp1.RightInset); + ClassicAssert.AreEqual(true, sp1.GetCTShape().txBody.bodyPr.IsSetRIns()); + ClassicAssert.AreEqual(0, sp1.BottomInset); + ClassicAssert.AreEqual(true, sp1.GetCTShape().txBody.bodyPr.IsSetBIns()); + XSSFTestDataSamples.WriteOut(rbwb1, "TestShapeTextWrap-2-"); + + //----- others + sp1.LeftInset = 3.6; + sp1.TopInset = 1.8; + sp1.RightInset = 3.6; + sp1.BottomInset = 1.8; + XSSFWorkbook rbwb2 = (XSSFWorkbook)XSSFITestDataProvider.instance.WriteOutAndReadBack(rbwb1); + var sht2 = rbwb2.GetSheet("sheet0"); + var dw2 = ((XSSFSheet)sht2).GetDrawingPatriarch(); + XSSFSimpleShape sp2 = (XSSFSimpleShape)dw2.GetShapes()[0]; + ClassicAssert.AreEqual(3.6, sp2.LeftInset); + ClassicAssert.AreEqual(true, sp2.GetCTShape().txBody.bodyPr.IsSetLIns()); + ClassicAssert.AreEqual(1.8, sp2.TopInset); + ClassicAssert.AreEqual(true, sp2.GetCTShape().txBody.bodyPr.IsSetTIns()); + ClassicAssert.AreEqual(3.6, sp2.RightInset); + ClassicAssert.AreEqual(true, sp2.GetCTShape().txBody.bodyPr.IsSetRIns()); + ClassicAssert.AreEqual(1.8, sp2.BottomInset); + ClassicAssert.AreEqual(true, sp2.GetCTShape().txBody.bodyPr.IsSetBIns()); + XSSFTestDataSamples.WriteOut(rbwb2, "TestShapeTextWrap-3-"); + } + + [Test] + public void TestLockWithSheet() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet(); + XSSFDrawing drawing = (XSSFDrawing)sheet.CreateDrawingPatriarch(); + + // simple shape + XSSFClientAnchor ca0; + ca0 = new XSSFClientAnchor(sheet, Units.ToEMU(100), Units.ToEMU(100), Units.ToEMU(200), Units.ToEMU(200)); + XSSFSimpleShape shp0 = drawing.CreateSimpleShape(ca0); + shp0.Name = "S00"; + shp0.cellanchor.clientData.fLocksWithSheet = true; + + // connector shape + XSSFClientAnchor ca1; + ca1 = new XSSFClientAnchor(sheet, Units.ToEMU(250), Units.ToEMU(250), Units.ToEMU(350), Units.ToEMU(350)); + XSSFConnector shp1 = drawing.CreateConnector(ca1); + shp1.Name = "L00"; + shp1.cellanchor.clientData.fLocksWithSheet = true; + + XSSFTestDataSamples.WriteOut(wb, "TestLockWithSheet1-"); + + XSSFWorkbook rbwb = (XSSFWorkbook)XSSFITestDataProvider.instance.WriteOutAndReadBack(wb); + + XSSFSheet rb_sht = (XSSFSheet)rbwb.GetSheetAt(0); + XSSFDrawing dr = (XSSFDrawing)rb_sht.GetDrawingPatriarch(); + List lstShp = dr.GetShapes(); + foreach(var sp in lstShp) + { + switch(sp.Name) + { + case "S00": + case "L00": + ClassicAssert.AreEqual(sp.cellanchor.clientData.fLocksWithSheet, true, "shape name:[{0}]", new object[] { sp.Name }); + break; + default: + break; + } + } + + shp0.cellanchor.clientData.fLocksWithSheet = false; + shp1.cellanchor.clientData.fLocksWithSheet = false; + + XSSFTestDataSamples.WriteOut(wb, "TestLockWithSheet2-"); + + XSSFWorkbook rbwb1 = (XSSFWorkbook)XSSFITestDataProvider.instance.WriteOutAndReadBack(wb); + XSSFSheet rb_sht1 = (XSSFSheet)rbwb1.GetSheetAt(0); + XSSFDrawing dr1 = (XSSFDrawing)rb_sht1.GetDrawingPatriarch(); + List lstShp1 = dr1.GetShapes(); + + foreach(var sp in lstShp1) + { + switch(sp.Name) + { + case "S00": + case "L00": + ClassicAssert.AreEqual(sp.cellanchor.clientData.fLocksWithSheet, false, "shape name:[{0}]", new object[] { sp.Name }); + break; + default: + break; + } + } + } + + [Test] + public void TestGroupLockWithSheet() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet(); + XSSFDrawing drawing = (XSSFDrawing)sheet.CreateDrawingPatriarch(); + + //----- first group + XSSFClientAnchor ganchor1; + ganchor1 = new XSSFClientAnchor(sheet, Units.ToEMU(100), Units.ToEMU(200), Units.ToEMU(200), Units.ToEMU(100)); + ganchor1.AnchorType = AnchorType.DontMoveAndResize; + XSSFShapeGroup grp1= drawing.CreateGroup( ganchor1 ); + grp1.Name = "first"; + + // connector shape + XSSFChildAnchor ca1; + ca1 = new XSSFChildAnchor(Units.ToEMU(100), Units.ToEMU(200), Units.ToEMU(200), Units.ToEMU(100)); + XSSFConnector shp1 = grp1.CreateConnector( ca1 ); + shp1.Name = "L01"; + shp1.cellanchor.clientData.fLocksWithSheet = true; + + //----- second group + XSSFChildGroupAnchor ganchor2; + ganchor2 = new XSSFChildGroupAnchor(Units.ToEMU(110), Units.ToEMU(110), Units.ToEMU(190), Units.ToEMU(190)); + XSSFShapeGroup grp2 = grp1.CreateGroup( ganchor2 ); + grp2.Name = "second"; + + // connector shape + XSSFChildAnchor ca2; + ca2 = new XSSFChildAnchor(Units.ToEMU(110), Units.ToEMU(110), Units.ToEMU(190), Units.ToEMU(190)); + XSSFConnector shp2 = grp2.CreateConnector(ca2); + shp2.Name = "L02"; + shp2.cellanchor.clientData.fLocksWithSheet = true; + + //----- third group + XSSFChildGroupAnchor ganchor3; + ganchor3 = new XSSFChildGroupAnchor(Units.ToEMU(120), Units.ToEMU(120), Units.ToEMU(180), Units.ToEMU(180)); + XSSFShapeGroup grp3 = grp2.CreateGroup( ganchor3 ); + grp3.Name = "third"; + + // connector shape + XSSFChildAnchor ca3; + ca3 = new XSSFChildAnchor(Units.ToEMU(120), Units.ToEMU(150), Units.ToEMU(180), Units.ToEMU(150)); + XSSFConnector shp3 = grp3.CreateConnector(ca3); + shp3.Name = "L03"; + shp3.cellanchor.clientData.fLocksWithSheet = false; + + ClassicAssert.AreEqual(shp1.cellanchor.clientData.fLocksWithSheet, false); + + XSSFTestDataSamples.WriteOut(wb, "TestGroupLockWithSheet"); + } + + [Test] + public void TestRecursiveGroup() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet(); + XSSFDrawing drawing = (XSSFDrawing)sheet.CreateDrawingPatriarch(); + XSSFFont font = wb.GetStylesSource().GetFontAt( 0 ); + font.SetScheme(FontScheme.NONE); + + //----- first group + XSSFClientAnchor ganchor1; + ganchor1 = new XSSFClientAnchor(sheet, Units.ToEMU(50), Units.ToEMU(400), Units.ToEMU(400), Units.ToEMU(50)); + ganchor1.AnchorType = AnchorType.DontMoveAndResize; + XSSFShapeGroup grp1= drawing.CreateGroup( ganchor1 ); + grp1.Name = "G00"; + + // simple shape + XSSFChildAnchor ca1; + ca1 = new XSSFChildAnchor(Units.ToEMU(100), Units.ToEMU(200), Units.ToEMU(200), Units.ToEMU(100)); + XSSFSimpleShape shp1 = grp1.CreateSimpleShape( ca1 ); + shp1.Name = "S00"; + + // connector shape + XSSFChildAnchor ca2; + ca2 = new XSSFChildAnchor(Units.ToEMU(100), Units.ToEMU(200), Units.ToEMU(200), Units.ToEMU(100)); + XSSFConnector shp2 = grp1.CreateConnector( ca2 ); + shp2.Name = "L00"; + shp2.cellanchor.clientData.fLocksWithSheet = true; + + int x = 300; + int y = 300; + int cx = 310; + int cy = 310; + XSSFShapeGroup grp = grp1; + for(var ct = 1; ct < 5; ct++) + { + //----- second group + XSSFChildGroupAnchor ganchor; + ganchor = new XSSFChildGroupAnchor(Units.ToEMU(x - 25), Units.ToEMU(y - 25), Units.ToEMU(cx+25), Units.ToEMU(cy+25)); + grp = grp.CreateGroup(ganchor); + grp.Name = $"G{ct}"; + + // simple shape + XSSFChildAnchor ca; + ca = new XSSFChildAnchor(Units.ToEMU(x), Units.ToEMU(x), Units.ToEMU(cx), Units.ToEMU(cy)); + XSSFSimpleShape Sshp = grp.CreateSimpleShape( ca ); + Sshp.Name = $"S{ct:00}"; + Sshp.LineStyle = LineStyle.Solid; + Sshp.LineStyleColor = 0x00FF00; + + // connector shape + ca = new XSSFChildAnchor(Units.ToEMU(x), Units.ToEMU(y), Units.ToEMU(cx), Units.ToEMU(cy)); + XSSFConnector Cshp = grp.CreateConnector( ca ); + Cshp.Name = $"L{ct:00}"; + Cshp.cellanchor.clientData.fLocksWithSheet = true; + + x += 25; + y += 25; + cx += 25; + cy += 25; + } + + grp1.AutoFit(sheet); + XSSFTestDataSamples.WriteOut(wb, "TestRecursiveGroup"); + } + + [Test] + public void TestInnerPproduct() + { + DblVect2D b = new DblVect2D(1, 0); + for(double Theta = 0; Theta < Math.PI; Theta+=Math.PI/180.0) + { + DblVect2D c = new DblVect2D(Math.Cos(Theta), Math.Sin(Theta)); + + Debug.WriteLine($"{Theta/Math.PI*180}\t{Theta}\t{c.x}\t{c.y}\t={b.InnerProduct(c)}+$E$1"); + } + } + + [Test] + public void TestBuildFreeform_base() + { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = (XSSFSheet)wb.CreateSheet(); + XSSFDrawing drawing = (XSSFDrawing)sheet.CreateDrawingPatriarch(); + XSSFFont font = wb.GetStylesSource().GetFontAt( 0 ); + font.SetScheme(FontScheme.NONE); + + // free form shape + var bff = new BuildFreeForm(); + bff.AddNode(new Coords(Units.ToEMU(100), Units.ToEMU(180))); + bff.AddNode(new Coords(Units.ToEMU(200), Units.ToEMU(200))); + bff.AddNode(new Coords(Units.ToEMU(300), Units.ToEMU(150))); + bff.AddNode(new Coords(Units.ToEMU(400), Units.ToEMU(50))); + if(bff.Build()) + { + var shp = drawing.CreateFreeform(sheet, bff); + shp.SetLineStyleColor(0, 0, 0); + + XSSFTestDataSamples.WriteOut(wb, "TestBuildFreeform_base"); + } + } + + [Test] + public void TestBuildFreeform() + { + XSSFWorkbook wb0 = XSSFTestDataSamples.OpenSampleWorkbook("TestBuildFreeform.xlsx"); + XSSFSheet sheet0 = (XSSFSheet)wb0.GetSheet("Sheet1"); + XSSFDrawing drawing0 = sheet0.GetDrawingPatriarch(); + List lstShp0 = drawing0.GetShapes(); + + XSSFWorkbook wb1 = new XSSFWorkbook(); + XSSFSheet sheet1 = (XSSFSheet)wb1.CreateSheet(sheet0.SheetName); + XSSFDrawing drawing1 = (XSSFDrawing)sheet1.CreateDrawingPatriarch(); + XSSFFont font = wb1.GetStylesSource().GetFontAt( 0 ); + font.SetScheme(FontScheme.NONE); + + foreach(var sp in lstShp0) + { + if(sp.Name.Substring(0, 2) == "FF") + //if(sp.Name.Substring(0, 4) == "FF01") + { + var bff = new BuildFreeForm(); + + var spPr = ((XSSFSimpleShape)sp).GetCTShape().spPr; + var cg = spPr.custGeom; + for(int ct = 0; ct< cg.cxnLst.cxn.Count; ct++) + { + var cd = GetGeomGuide(cg.gdLst.gd, ct); + if( cd != null){ + cd.Add(new Coords(spPr.xfrm.off.x, spPr.xfrm.off.y)); + bff.AddNode(cd); + } + } + if(bff.Build()) + { + var shp = drawing1.CreateFreeform(sheet1, bff); + shp.SetLineStyleColor(0, 0, 0); + shp.Name = sp.Name; + } + } + } + XSSFTestDataSamples.WriteOut(wb1, "TestBuildFreeform"); + + var rbwb = (XSSFWorkbook)XSSFITestDataProvider.instance.WriteOutAndReadBack(wb1); + var rbsheet = (XSSFSheet) rbwb.GetSheet("Sheet1"); + var rbdrawing = rbsheet.GetDrawingPatriarch(); + var rblstShp = rbdrawing.GetShapes(); + foreach(var sp0 in lstShp0) + { + if(sp0.Name.Substring(0, 2) == "FF") + { + var spPr0 = ((XSSFSimpleShape)sp0).GetCTShape().spPr; + var cg0 = spPr0.custGeom; + + foreach(var rbsp in rblstShp) + { + if(sp0.Name == rbsp.Name) + { + var rbspPr = ((XSSFSimpleShape)rbsp).GetCTShape().spPr; + var rbcg = rbspPr.custGeom; //read back custom geometry + + ClassicAssert.IsFalse(!Compeare(spPr0.xfrm.off.x, rbspPr.xfrm.off.x), $"{sp0.Name}-xfrm.off.x:{spPr0.xfrm.off.x}!={rbspPr.xfrm.off.x}"); + ClassicAssert.IsFalse(!Compeare(spPr0.xfrm.off.y, rbspPr.xfrm.off.y), $"{sp0.Name}-xfrm.off.y:{spPr0.xfrm.off.y}!={rbspPr.xfrm.off.y}"); + ClassicAssert.IsFalse(!Compeare(spPr0.xfrm.ext.cx, rbspPr.xfrm.ext.cx), $"{sp0.Name}-xfrm.off.x:{spPr0.xfrm.ext.cx}!={rbspPr.xfrm.ext.cx}"); + ClassicAssert.IsFalse(!Compeare(spPr0.xfrm.ext.cy, rbspPr.xfrm.ext.cy), $"{sp0.Name}-xfrm.off.y:{spPr0.xfrm.ext.cy}!={rbspPr.xfrm.ext.cy}"); + + ClassicAssert.AreEqual(cg0.cxnLst.cxn.Count, rbcg.cxnLst.cxn.Count, $"Count:{cg0.cxnLst.cxn.Count}!={rbcg.cxnLst.cxn.Count}"); + + for(int ct = 0; ct< cg0.cxnLst.cxn.Count; ct++) + { + var cd0 = GetGeomGuide(cg0.gdLst.gd, ct); + if(cd0 != null) + { + var rbcd = GetGeomGuide(rbcg.gdLst.gd, ct); + if(rbcd != null) + { + ClassicAssert.IsFalse(!Compeare(cd0.x, rbcd.x), $"{sp0.Name}-gdLst.x{ct}:{cd0.x}!={rbcd.x}"); + ClassicAssert.IsFalse(!Compeare(cd0.y, rbcd.y), $"{sp0.Name}-gdLst.y{ct}:{cd0.y}!={rbcd.y}"); + } + else + { + throw new Exception(); + } + } + else + { + throw new Exception(); + } + } + var ogph = cg0.pathLst.path[0]; + var rbph = rbcg.pathLst.path[0]; + ClassicAssert.IsFalse(!Compeare(ogph.w, rbph.w), $"{sp0.Name}-path.w:{ogph.w}!={rbph.w}"); + ClassicAssert.IsFalse(!Compeare(ogph.h, rbph.h), $"{sp0.Name}-path.h:{ogph.h}!={rbph.h}"); + + ClassicAssert.IsFalse(!Compeare(ogph.moveto.pt.x, rbph.moveto.pt.x), $"{sp0.Name}-moveto.x:{ogph.moveto.pt.x}!={rbph.moveto.pt.x}"); + ClassicAssert.IsFalse(!Compeare(ogph.moveto.pt.y, rbph.moveto.pt.y), $"{sp0.Name}-moveto.y:{ogph.moveto.pt.y}!={rbph.moveto.pt.y}"); + + ClassicAssert.AreEqual(ogph.cubicBezTo.Count, rbph.cubicBezTo.Count, $"cubicBezTo.Count:{ogph.cubicBezTo.Count}!={rbph.cubicBezTo.Count}"); + + for(int i = 0; i ggs + , int ct + ) { + long x = 0; + long y = 0; + + var gdX = Search(ggs, $"connsiteX{ct}"); + if(gdX != null) + { + string[] fmla = gdX.fmla.Split(new char[] { ' ' }); + x = long.Parse(fmla[1]); + } + var gdY = Search(ggs, $"connsiteY{ct}"); + if(gdY != null) + { + string[] fmla = gdY.fmla.Split(new char[] { ' ' }); + y = long.Parse(fmla[1]); + } + if(gdX == null || gdY ==null) + { + return null; + } + + return new Coords(x, y); + } + + private CT_GeomGuide Search(List Gds, string name) + { + foreach(var gd in Gds) + { + if(gd.name == name) + { + return gd; + } + } + return null; + } + private bool Compeare(long B, long C, long a = 5) + { + if(B-a<=C && C<=B+a) + { + return true; + } + return false; + } + + private bool Compeare(string B, string C, long a = 5) + { + long b = long.Parse(B); + long c = long.Parse(C); + if(b-a<=c && c<=b+a) + { + return true; + } + return false; + } + } +} diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFTable.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFTable.cs index a528baa2e..e0420aac5 100644 --- a/testcases/ooxml/XSSF/UserModel/TestXSSFTable.cs +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFTable.cs @@ -283,7 +283,7 @@ public void FormatAsTable() row.CreateCell(2).SetCellValue("Value3"); XSSFTable table = sh.CreateTable(); - table.SetCellReferences(new AreaReference(new CellReference(0, 0), new CellReference(1, 2))); + table.CellReferences = new AreaReference(new CellReference(0, 0), new CellReference(1, 2)); wb.Close(); } @@ -296,5 +296,94 @@ public void GetEndCellReferenceFromSingleCellTable() wb.Close(); } + [Test] + public void TestDifferentHeaderTypes() + { + + XSSFWorkbook wb = XSSFTestDataSamples.OpenSampleWorkbook("TablesWithDifferentHeaders.xlsx"); + ClassicAssert.AreEqual(3, wb.NumberOfSheets); + XSSFSheet s; + XSSFTable t; + + // TODO Nicer column fetching + + s = wb.GetSheet("IntHeaders") as XSSFSheet; + ClassicAssert.AreEqual(1, s.GetTables().Count); + t = s.GetTables()[0]; + ClassicAssert.AreEqual("A1:B2", t.CellReferences.FormatAsString()); + ClassicAssert.AreEqual("12", t.GetCTTable().tableColumns.GetTableColumnArray(0).name); + ClassicAssert.AreEqual("34", t.GetCTTable().tableColumns.GetTableColumnArray(1).name); + + s = wb.GetSheet("FloatHeaders") as XSSFSheet; + ClassicAssert.AreEqual(1, s.GetTables().Count); + t = s.GetTables()[0]; + ClassicAssert.AreEqual("A1:B2", t.CellReferences.FormatAsString()); + ClassicAssert.AreEqual("12.34", t.GetCTTable().tableColumns.GetTableColumnArray(0).name); + ClassicAssert.AreEqual("34.56", t.GetCTTable().tableColumns.GetTableColumnArray(1).name); + + s = wb.GetSheet("NoExplicitHeaders") as XSSFSheet; + ClassicAssert.AreEqual(1, s.GetTables().Count); + t = s.GetTables()[0]; + ClassicAssert.AreEqual("A1:B3", t.CellReferences.FormatAsString()); + ClassicAssert.AreEqual("Column1", t.GetCTTable().tableColumns.GetTableColumnArray(0).name); + ClassicAssert.AreEqual("Column2", t.GetCTTable().tableColumns.GetTableColumnArray(1).name); + + wb.Close(); + } + + /// + /// See https://stackoverflow.com/questions/44407111/apache-poi-cant-format-filled-cells-as-numeric + /// + [Test] + public void TestNumericCellsInTable() + { + + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet s = wb.CreateSheet() as XSSFSheet; + + // Create some cells, some numeric, some not + ICell c1 = s.CreateRow(0).CreateCell(0); + ICell c2 = s.GetRow(0).CreateCell(1); + ICell c3 = s.GetRow(0).CreateCell(2); + ICell c4 = s.CreateRow(1).CreateCell(0); + ICell c5 = s.GetRow(1).CreateCell(1); + ICell c6 = s.GetRow(1).CreateCell(2); + + // Inserting values; some numeric strings, some alphabetical strings + c1.SetCellValue(12); + c2.SetCellValue(34.56); + c3.SetCellValue("ABCD"); + c4.SetCellValue("AB"); + c5.SetCellValue("CD"); + c6.SetCellValue("EF"); + + // Setting up the CTTable + XSSFTable t = s.CreateTable(); + t.Name = "TableTest"; + t.DisplayName = "CT_Table_Test"; + t.AddColumn(); + t.AddColumn(); + t.AddColumn(); + t.CellReferences = (new AreaReference( + new CellReference(c1), new CellReference(c6) + )); + + // Save and re-load + wb = XSSFTestDataSamples.WriteOutAndReadBack(wb); + s = wb.GetSheetAt(0) as XSSFSheet; + + // Check + ClassicAssert.AreEqual(1, s.GetTables().Count); + t = s.GetTables()[0]; + ClassicAssert.AreEqual("A1", t.StartCellReference.FormatAsString()); + ClassicAssert.AreEqual("C2", t.EndCellReference.FormatAsString()); + + // TODO Nicer column fetching + ClassicAssert.AreEqual("12", t.GetCTTable().tableColumns.GetTableColumnArray(0).name); + ClassicAssert.AreEqual("34.56", t.GetCTTable().tableColumns.GetTableColumnArray(1).name); + ClassicAssert.AreEqual("ABCD", t.GetCTTable().tableColumns.GetTableColumnArray(2).name); + // Done + wb.Close(); + } } } diff --git a/testcases/test-data/spreadsheet/TablesWithDifferentHeaders.xlsx b/testcases/test-data/spreadsheet/TablesWithDifferentHeaders.xlsx new file mode 100644 index 000000000..c9bb110ad Binary files /dev/null and b/testcases/test-data/spreadsheet/TablesWithDifferentHeaders.xlsx differ