| /******************************************************************************* |
| * 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.Generic; |
| using System.Text; |
| using System.Xml; |
| |
| namespace OfficeOpenXml.Table.PivotTable |
| { |
| /// <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 List<T>(); |
| internal ExcelPivotTableFieldCollectionBase(ExcelPivotTable table) |
| { |
| _table = table; |
| } |
| public IEnumerator<T> GetEnumerator() |
| { |
| return _list.GetEnumerator(); |
| } |
| |
| System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() |
| { |
| return _list.GetEnumerator(); |
| } |
| public int Count |
| { |
| get |
| { |
| return _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 && (((ExcelPivotTableFieldDateGroup)fld.Grouping).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 Exception("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 Exception("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 Exception("Field is a column or row field. Can't add it to the PageFields collection")); |
| } |
| if (_table.Address._fromRow < 3) |
| { |
| throw(new Exception(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++.ToString(); |
| } |
| 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); |
| } |
| } |
| } |