| /******************************************************************************* | |
| * You may amend and distribute as you like, but don't remove this header! | |
| * | |
| * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. | |
| * See http://www.codeplex.com/EPPlus for details. | |
| * | |
| * Copyright (C) 2011 Jan Källman | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
| * See the GNU Lesser General Public License for more details. | |
| * | |
| * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php | |
| * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html | |
| * | |
| * All code and executables are provided "as is" with no warranty either express or implied. | |
| * The author accepts no liability for any damage or loss of business that this product may cause. | |
| * | |
| * Code change notes: | |
| * | |
| * Author Change Date | |
| * ****************************************************************************** | |
| * Jan Källman Added 21-MAR-2011 | |
| * Jan Källman License changed GPL-->LGPL 2011-12-16 | |
| *******************************************************************************/ | |
| using System; | |
| using System.Collections; | |
| using System.Collections.Generic; | |
| using System.Xml; | |
| namespace AppsheetEpplus; | |
| /// <summary> | |
| /// Base collection class for pivottable fields | |
| /// </summary> | |
| /// <typeparam name="T"></typeparam> | |
| public class ExcelPivotTableFieldCollectionBase<T> : IEnumerable<T> { | |
| protected ExcelPivotTable _table; | |
| internal List<T> _list = new(); | |
| internal ExcelPivotTableFieldCollectionBase(ExcelPivotTable table) { | |
| _table = table; | |
| } | |
| public IEnumerator<T> GetEnumerator() { | |
| return _list.GetEnumerator(); | |
| } | |
| IEnumerator IEnumerable.GetEnumerator() { | |
| return _list.GetEnumerator(); | |
| } | |
| public int Count => _list.Count; | |
| internal void AddInternal(T field) { | |
| _list.Add(field); | |
| } | |
| internal void Clear() { | |
| _list.Clear(); | |
| } | |
| public T this[int index] { | |
| get { | |
| if (index < 0 || index >= _list.Count) { | |
| throw (new ArgumentOutOfRangeException("Index out of range")); | |
| } | |
| return _list[index]; | |
| } | |
| } | |
| } | |
| public class ExcelPivotTableFieldCollection | |
| : ExcelPivotTableFieldCollectionBase<ExcelPivotTableField> { | |
| internal ExcelPivotTableFieldCollection(ExcelPivotTable table, string topNode) | |
| : base(table) {} | |
| /// <summary> | |
| /// Indexer by name | |
| /// </summary> | |
| /// <param name="name"></param> | |
| /// <returns></returns> | |
| public ExcelPivotTableField this[string name] { | |
| get { | |
| foreach (var field in _list) { | |
| if (field.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)) { | |
| return field; | |
| } | |
| } | |
| return null; | |
| } | |
| } | |
| /// <summary> | |
| /// Returns the date group field. | |
| /// </summary> | |
| /// <param name="groupBy">The type of grouping</param> | |
| /// <returns>The matching field. If none is found null is returned</returns> | |
| public ExcelPivotTableField GetDateGroupField(eDateGroupBy groupBy) { | |
| foreach (var fld in _list) { | |
| if (fld.Grouping is ExcelPivotTableFieldDateGroup group && (group.GroupBy) == groupBy) { | |
| return fld; | |
| } | |
| } | |
| return null; | |
| } | |
| /// <summary> | |
| /// Returns the numeric group field. | |
| /// </summary> | |
| /// <returns>The matching field. If none is found null is returned</returns> | |
| public ExcelPivotTableField GetNumericGroupField() { | |
| foreach (var fld in _list) { | |
| if (fld.Grouping is ExcelPivotTableFieldNumericGroup) { | |
| return fld; | |
| } | |
| } | |
| return null; | |
| } | |
| } | |
| /// <summary> | |
| /// Collection class for Row and column fields in a Pivottable | |
| /// </summary> | |
| public class ExcelPivotTableRowColumnFieldCollection | |
| : ExcelPivotTableFieldCollectionBase<ExcelPivotTableField> { | |
| internal string _topNode; | |
| internal ExcelPivotTableRowColumnFieldCollection(ExcelPivotTable table, string topNode) | |
| : base(table) { | |
| _topNode = topNode; | |
| } | |
| /// <summary> | |
| /// Add a new row/column field | |
| /// </summary> | |
| /// <param name="field">The field</param> | |
| /// <returns>The new field</returns> | |
| public ExcelPivotTableField Add(ExcelPivotTableField field) { | |
| SetFlag(field, true); | |
| _list.Add(field); | |
| return field; | |
| } | |
| /// <summary> | |
| /// Insert a new row/column field | |
| /// </summary> | |
| /// <param name="field">The field</param> | |
| /// <param name="index">The position to insert the field</param> | |
| /// <returns>The new field</returns> | |
| internal ExcelPivotTableField Insert(ExcelPivotTableField field, int index) { | |
| SetFlag(field, true); | |
| _list.Insert(index, field); | |
| return field; | |
| } | |
| private void SetFlag(ExcelPivotTableField field, bool value) { | |
| switch (_topNode) { | |
| case "rowFields": | |
| if (field.IsColumnField || field.IsPageField) { | |
| throw (new( | |
| "This field is a column or page field. Can't add it to the RowFields collection")); | |
| } | |
| field.IsRowField = value; | |
| field.Axis = ePivotFieldAxis.Row; | |
| break; | |
| case "colFields": | |
| if (field.IsRowField || field.IsPageField) { | |
| throw (new( | |
| "This field is a row or page field. Can't add it to the ColumnFields collection")); | |
| } | |
| field.IsColumnField = value; | |
| field.Axis = ePivotFieldAxis.Column; | |
| break; | |
| case "pageFields": | |
| if (field.IsColumnField || field.IsRowField) { | |
| throw (new("Field is a column or row field. Can't add it to the PageFields collection")); | |
| } | |
| if (_table.Address._fromRow < 3) { | |
| throw (new( | |
| string.Format( | |
| "A pivot table with page fields must be located above row 3. Currenct location is {0}", | |
| _table.Address.Address))); | |
| } | |
| field.IsPageField = value; | |
| field.Axis = ePivotFieldAxis.Page; | |
| break; | |
| case "dataFields": | |
| break; | |
| } | |
| } | |
| /// <summary> | |
| /// Remove a field | |
| /// </summary> | |
| /// <param name="field"></param> | |
| public void Remove(ExcelPivotTableField field) { | |
| if (!_list.Contains(field)) { | |
| throw new ArgumentException("Field not in collection"); | |
| } | |
| SetFlag(field, false); | |
| _list.Remove(field); | |
| } | |
| /// <summary> | |
| /// Remove a field at a specific position | |
| /// </summary> | |
| /// <param name="index"></param> | |
| public void RemoveAt(int index) { | |
| if (index > -1 && index < _list.Count) { | |
| throw (new IndexOutOfRangeException()); | |
| } | |
| SetFlag(_list[index], false); | |
| _list.RemoveAt(index); | |
| } | |
| } | |
| /// <summary> | |
| /// Collection class for data fields in a Pivottable | |
| /// </summary> | |
| public class ExcelPivotTableDataFieldCollection | |
| : ExcelPivotTableFieldCollectionBase<ExcelPivotTableDataField> { | |
| internal ExcelPivotTableDataFieldCollection(ExcelPivotTable table) | |
| : base(table) {} | |
| /// <summary> | |
| /// Add a new datafield | |
| /// </summary> | |
| /// <param name="field">The field</param> | |
| /// <returns>The new datafield</returns> | |
| public ExcelPivotTableDataField Add(ExcelPivotTableField field) { | |
| var dataFieldsNode = field.TopNode.SelectSingleNode( | |
| "../../d:dataFields", | |
| field.NameSpaceManager); | |
| if (dataFieldsNode == null) { | |
| _table.CreateNode("d:dataFields"); | |
| dataFieldsNode = field.TopNode.SelectSingleNode("../../d:dataFields", field.NameSpaceManager); | |
| } | |
| XmlElement node = _table.PivotTableXml.CreateElement("dataField", ExcelPackage._schemaMain); | |
| node.SetAttribute("fld", field.Index.ToString()); | |
| dataFieldsNode.AppendChild(node); | |
| //XmlElement node = field.AppendField(dataFieldsNode, field.Index, "dataField", "fld"); | |
| field.SetXmlNodeBool("@dataField", true, false); | |
| var dataField = new ExcelPivotTableDataField(field.NameSpaceManager, node, field); | |
| ValidateDupName(dataField); | |
| _list.Add(dataField); | |
| return dataField; | |
| } | |
| private void ValidateDupName(ExcelPivotTableDataField dataField) { | |
| if (ExistsDfName(dataField.Field.Name, null)) { | |
| var index = 2; | |
| string name; | |
| do { | |
| name = dataField.Field.Name + "_" + index++; | |
| } while (ExistsDfName(name, null)); | |
| dataField.Name = name; | |
| } | |
| } | |
| internal bool ExistsDfName(string name, ExcelPivotTableDataField datafield) { | |
| foreach (var df in _list) { | |
| if (((!string.IsNullOrEmpty(df.Name) | |
| && df.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase) | |
| || (string.IsNullOrEmpty(df.Name) | |
| && df.Field.Name.Equals( | |
| name, | |
| StringComparison.InvariantCultureIgnoreCase)))) | |
| && datafield != df) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| /// <summary> | |
| /// Remove a datafield | |
| /// </summary> | |
| /// <param name="dataField"></param> | |
| public void Remove(ExcelPivotTableDataField dataField) { | |
| XmlElement node = | |
| dataField.Field.TopNode.SelectSingleNode( | |
| string.Format("../../d:dataFields/d:dataField[@fld={0}]", dataField.Index), | |
| dataField.NameSpaceManager) as XmlElement; | |
| if (node != null) { | |
| node.ParentNode.RemoveChild(node); | |
| } | |
| _list.Remove(dataField); | |
| } | |
| } |