/*******************************************************************************
* 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;
using System.Globalization;
namespace OfficeOpenXml.Table.PivotTable
{
///
/// Defines the axis for a PivotTable
///
public enum ePivotFieldAxis
{
///
/// None
///
None=-1,
///
/// Column axis
///
Column,
///
/// Page axis (Include Count Filter)
///
///
Page,
///
/// Row axis
///
Row,
///
/// Values axis
///
Values
}
///
/// Build-in table row functions
///
public enum DataFieldFunctions
{
Average,
Count,
CountNums,
Max,
Min,
Product,
None,
StdDev,
StdDevP,
Sum,
Var,
VarP
}
///
/// Defines the data formats for a field in the PivotTable
///
public enum eShowDataAs
{
///
/// Indicates the field is shown as the "difference from" a value.
///
Difference,
///
/// Indicates the field is shown as the "index.
///
Index,
///
/// Indicates that the field is shown as its normal datatype.
///
Normal,
///
/// /Indicates the field is show as the "percentage of" a value
///
Percent,
///
/// Indicates the field is shown as the "percentage difference from" a value.
///
PercentDiff,
///
/// Indicates the field is shown as the percentage of column.
///
PercentOfCol,
///
/// Indicates the field is shown as the percentage of row
///
PercentOfRow,
///
/// Indicates the field is shown as percentage of total.
///
PercentOfTotal,
///
/// Indicates the field is shown as running total in the table.
///
RunTotal,
}
///
/// Built-in subtotal functions
///
[Flags]
public enum eSubTotalFunctions
{
None=1,
Count=2,
CountA=4,
Avg=8,
Default=16,
Min=32,
Max=64,
Product=128,
StdDev=256,
StdDevP=512,
Sum=1024,
Var=2048,
VarP=4096
}
///
/// Data grouping
///
[Flags]
public enum eDateGroupBy
{
Years = 1,
Quarters = 2,
Months = 4,
Days = 8,
Hours = 16,
Minutes = 32,
Seconds = 64
}
///
/// Sorting
///
public enum eSortType
{
None,
Ascending,
Descending
}
///
/// A pivot table field.
///
public class ExcelPivotTableField : XmlHelper
{
internal ExcelPivotTable _table;
internal ExcelPivotTableField(XmlNamespaceManager ns, XmlNode topNode,ExcelPivotTable table, int index, int baseIndex) :
base(ns, topNode)
{
Index = index;
BaseIndex = baseIndex;
_table = table;
}
public int Index
{
get;
set;
}
internal int BaseIndex
{
get;
set;
}
///
/// Name of the field
///
public string Name
{
get
{
string v = GetXmlNodeString("@name");
if (v == "")
{
return _cacheFieldHelper.GetXmlNodeString("@name");
}
else
{
return GetXmlNodeString("@name");
}
}
set
{
SetXmlNodeString("@name", value);
}
}
///
/// Compact mode
///
public bool Compact
{
get
{
return GetXmlNodeBool("@compact");
}
set
{
SetXmlNodeBool("@compact",value);
}
}
///
/// A boolean that indicates whether the items in this field should be shown in Outline form
///
public bool Outline
{
get
{
return GetXmlNodeBool("@outline");
}
set
{
SetXmlNodeBool("@outline",value);
}
}
///
/// The custom text that is displayed for the subtotals label
///
public bool SubtotalTop
{
get
{
return GetXmlNodeBool("@subtotalTop");
}
set
{
SetXmlNodeBool("@subtotalTop",value);
}
}
///
/// A boolean that indicates whether to show all items for this field
///
public bool ShowAll
{
get
{
return GetXmlNodeBool("@showAll");
}
set
{
SetXmlNodeBool("@showAll",value);
}
}
///
/// The type of sort that is applied to this field
///
public eSortType Sort
{
get
{
string v = GetXmlNodeString("@sortType");
return v == "" ? eSortType.None : (eSortType)Enum.Parse(typeof(eSortType), v, true);
}
set
{
if (value == eSortType.None)
{
DeleteNode("@sortType");
}
else
{
SetXmlNodeString("@sortType", value.ToString().ToLower(CultureInfo.InvariantCulture));
}
}
}
///
/// A boolean that indicates whether manual filter is in inclusive mode
///
public bool IncludeNewItemsInFilter
{
get
{
return GetXmlNodeBool("@includeNewItemsInFilter");
}
set
{
SetXmlNodeBool("@includeNewItemsInFilter",value);
}
}
///
/// Enumeration of the different subtotal operations that can be applied to page, row or column fields
///
public eSubTotalFunctions SubTotalFunctions
{
get
{
eSubTotalFunctions ret = 0;
XmlNodeList nl = TopNode.SelectNodes("d:items/d:item/@t", NameSpaceManager);
if (nl.Count == 0) return eSubTotalFunctions.None;
foreach (XmlAttribute item in nl)
{
try
{
ret |= (eSubTotalFunctions)Enum.Parse(typeof(eSubTotalFunctions), item.Value, true);
}
catch (ArgumentException ex)
{
throw new ArgumentException("Unable to parse value of " + item.Value + " to a valid pivot table subtotal function", ex);
}
}
return ret;
}
set
{
if ((value & eSubTotalFunctions.None) == eSubTotalFunctions.None && (value != eSubTotalFunctions.None))
{
throw (new ArgumentException("Value None can not be combined with other values."));
}
if ((value & eSubTotalFunctions.Default) == eSubTotalFunctions.Default && (value != eSubTotalFunctions.Default))
{
throw (new ArgumentException("Value Default can not be combined with other values."));
}
// remove old attribute
XmlNodeList nl = TopNode.SelectNodes("d:items/d:item/@t", NameSpaceManager);
if (nl.Count > 0)
{
foreach (XmlAttribute item in nl)
{
DeleteNode("@" + item.Value + "Subtotal");
item.OwnerElement.ParentNode.RemoveChild(item.OwnerElement);
}
}
if (value==eSubTotalFunctions.None)
{
// for no subtotals, set defaultSubtotal to off
SetXmlNodeBool("@defaultSubtotal", false);
TopNode.InnerXml = "";
}
else
{
string innerXml = "";
int count = 0;
foreach (eSubTotalFunctions e in Enum.GetValues(typeof(eSubTotalFunctions)))
{
if ((value & e) == e)
{
var newTotalType = e.ToString();
var totalType = char.ToLower(newTotalType[0], CultureInfo.InvariantCulture) + newTotalType.Substring(1);
// add new attribute
SetXmlNodeBool("@" + totalType + "Subtotal", true);
innerXml += " ";
count++;
}
}
TopNode.InnerXml = string.Format("{1}", count, innerXml);
}
}
}
///
/// Type of axis
///
public ePivotFieldAxis Axis
{
get
{
switch(GetXmlNodeString("@axis"))
{
case "axisRow":
return ePivotFieldAxis.Row;
case "axisCol":
return ePivotFieldAxis.Column;
case "axisPage":
return ePivotFieldAxis.Page;
case "axisValues":
return ePivotFieldAxis.Values;
default:
return ePivotFieldAxis.None;
}
}
internal set
{
switch (value)
{
case ePivotFieldAxis.Row:
SetXmlNodeString("@axis","axisRow");
break;
case ePivotFieldAxis.Column:
SetXmlNodeString("@axis","axisCol");
break;
case ePivotFieldAxis.Values:
SetXmlNodeString("@axis", "axisValues");
break;
case ePivotFieldAxis.Page:
SetXmlNodeString("@axis", "axisPage");
break;
default:
DeleteNode("@axis");
break;
}
}
}
///
/// If the field is a row field
///
public bool IsRowField
{
get
{
return (TopNode.SelectSingleNode(string.Format("../../d:rowFields/d:field[@x={0}]", Index), NameSpaceManager) != null);
}
internal set
{
if (value)
{
var rowsNode = TopNode.SelectSingleNode("../../d:rowFields", NameSpaceManager);
if (rowsNode == null)
{
_table.CreateNode("d:rowFields");
}
rowsNode = TopNode.SelectSingleNode("../../d:rowFields", NameSpaceManager);
AppendField(rowsNode, Index, "field", "x");
if (BaseIndex == Index)
{
TopNode.InnerXml = " ";
}
else
{
TopNode.InnerXml = "";
}
}
else
{
XmlElement node = TopNode.SelectSingleNode(string.Format("../../d:rowFields/d:field[@x={0}]", Index), NameSpaceManager) as XmlElement;
if (node != null)
{
node.ParentNode.RemoveChild(node);
}
}
}
}
///
/// If the field is a column field
///
public bool IsColumnField
{
get
{
return (TopNode.SelectSingleNode(string.Format("../../d:colFields/d:field[@x={0}]", Index), NameSpaceManager) != null);
}
internal set
{
if (value)
{
var columnsNode = TopNode.SelectSingleNode("../../d:colFields", NameSpaceManager);
if (columnsNode == null)
{
_table.CreateNode("d:colFields");
}
columnsNode = TopNode.SelectSingleNode("../../d:colFields", NameSpaceManager);
AppendField(columnsNode, Index, "field", "x");
if (BaseIndex == Index)
{
TopNode.InnerXml = " ";
}
else
{
TopNode.InnerXml = "";
}
}
else
{
XmlElement node = TopNode.SelectSingleNode(string.Format("../../d:colFields/d:field[@x={0}]", Index), NameSpaceManager) as XmlElement;
if (node != null)
{
node.ParentNode.RemoveChild(node);
}
}
}
}
///
/// If the field is a datafield
///
public bool IsDataField
{
get
{
return GetXmlNodeBool("@dataField", false);
}
}
///
/// If the field is a page field.
///
public bool IsPageField
{
get
{
return (Axis==ePivotFieldAxis.Page);
}
internal set
{
if (value)
{
var dataFieldsNode = TopNode.SelectSingleNode("../../d:pageFields", NameSpaceManager);
if (dataFieldsNode == null)
{
_table.CreateNode("d:pageFields");
dataFieldsNode = TopNode.SelectSingleNode("../../d:pageFields", NameSpaceManager);
}
TopNode.InnerXml = " ";
XmlElement node = AppendField(dataFieldsNode, Index, "pageField", "fld");
_pageFieldSettings = new ExcelPivotTablePageFieldSettings(NameSpaceManager, node, this, Index);
}
else
{
_pageFieldSettings = null;
XmlElement node = TopNode.SelectSingleNode(string.Format("../../d:pageFields/d:pageField[@fld={0}]", Index), NameSpaceManager) as XmlElement;
if (node != null)
{
node.ParentNode.RemoveChild(node);
}
}
}
}
//public ExcelPivotGrouping DateGrouping
//{
//}
internal ExcelPivotTablePageFieldSettings _pageFieldSettings = null;
public ExcelPivotTablePageFieldSettings PageFieldSettings
{
get
{
return _pageFieldSettings;
}
}
internal eDateGroupBy DateGrouping
{
get;
set;
}
ExcelPivotTableFieldGroup _grouping=null;
///
/// Grouping settings.
/// Null if the field has no grouping otherwise ExcelPivotTableFieldNumericGroup or ExcelPivotTableFieldNumericGroup.
///
public ExcelPivotTableFieldGroup Grouping
{
get
{
return _grouping;
}
}
#region Private & internal Methods
internal XmlElement AppendField(XmlNode rowsNode, int index, string fieldNodeText, string indexAttrText)
{
XmlElement prevField = null, newElement;
foreach (XmlElement field in rowsNode.ChildNodes)
{
string x = field.GetAttribute(indexAttrText);
int fieldIndex;
if(int.TryParse(x, out fieldIndex))
{
if (fieldIndex == index) //Row already exists
{
return field;
}
//else if (fieldIndex > index)
//{
// newElement = rowsNode.OwnerDocument.CreateElement(fieldNodeText, ExcelPackage.schemaMain);
// newElement.SetAttribute(indexAttrText, index.ToString());
// rowsNode.InsertAfter(newElement, field);
//}
}
prevField=field;
}
newElement = rowsNode.OwnerDocument.CreateElement(fieldNodeText, ExcelPackage.schemaMain);
newElement.SetAttribute(indexAttrText, index.ToString());
rowsNode.InsertAfter(newElement, prevField);
return newElement;
}
internal XmlHelperInstance _cacheFieldHelper = null;
internal void SetCacheFieldNode(XmlNode cacheField)
{
_cacheFieldHelper = new XmlHelperInstance(NameSpaceManager, cacheField);
var groupNode = cacheField.SelectSingleNode("d:fieldGroup", NameSpaceManager);
if (groupNode!=null)
{
var groupBy = groupNode.SelectSingleNode("d:rangePr/@groupBy", NameSpaceManager);
if (groupBy==null)
{
_grouping = new ExcelPivotTableFieldNumericGroup(NameSpaceManager, cacheField);
}
else
{
DateGrouping=(eDateGroupBy)Enum.Parse(typeof(eDateGroupBy), groupBy.Value, true);
_grouping = new ExcelPivotTableFieldDateGroup(NameSpaceManager, groupNode);
}
}
}
#endregion
#region Grouping
internal ExcelPivotTableFieldDateGroup SetDateGroup(eDateGroupBy GroupBy, DateTime StartDate, DateTime EndDate, int interval)
{
ExcelPivotTableFieldDateGroup group;
group = new ExcelPivotTableFieldDateGroup(NameSpaceManager, _cacheFieldHelper.TopNode);
_cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsDate", true);
_cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsNonDate", false);
_cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsSemiMixedTypes", false);
group.TopNode.InnerXml += string.Format("", BaseIndex, GroupBy.ToString().ToLower(CultureInfo.InvariantCulture));
if (StartDate.Year < 1900)
{
_cacheFieldHelper.SetXmlNodeString("d:fieldGroup/d:rangePr/@startDate", "1900-01-01T00:00:00");
}
else
{
_cacheFieldHelper.SetXmlNodeString("d:fieldGroup/d:rangePr/@startDate", StartDate.ToString("s", CultureInfo.InvariantCulture));
_cacheFieldHelper.SetXmlNodeString("d:fieldGroup/d:rangePr/@autoStart", "0");
}
if (EndDate==DateTime.MaxValue)
{
_cacheFieldHelper.SetXmlNodeString("d:fieldGroup/d:rangePr/@endDate", "9999-12-31T00:00:00");
}
else
{
_cacheFieldHelper.SetXmlNodeString("d:fieldGroup/d:rangePr/@endDate", EndDate.ToString("s", CultureInfo.InvariantCulture));
_cacheFieldHelper.SetXmlNodeString("d:fieldGroup/d:rangePr/@autoEnd", "0");
}
int items = AddDateGroupItems(group, GroupBy, StartDate, EndDate, interval);
AddFieldItems(items);
_grouping = group;
return group;
}
internal ExcelPivotTableFieldNumericGroup SetNumericGroup(double start, double end, double interval)
{
ExcelPivotTableFieldNumericGroup group;
group = new ExcelPivotTableFieldNumericGroup(NameSpaceManager, _cacheFieldHelper.TopNode);
_cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsNumber", true);
_cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsInteger", true);
_cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsSemiMixedTypes", false);
_cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsString", false);
group.TopNode.InnerXml += string.Format("", BaseIndex, start.ToString(CultureInfo.InvariantCulture), end.ToString(CultureInfo.InvariantCulture), interval.ToString(CultureInfo.InvariantCulture));
int items = AddNumericGroupItems(group, start, end, interval);
AddFieldItems(items);
_grouping = group;
return group;
}
private int AddNumericGroupItems(ExcelPivotTableFieldNumericGroup group, double start, double end, double interval)
{
if (interval < 0)
{
throw (new Exception("The interval must be a positiv"));
}
if (start > end)
{
throw(new Exception("Then End number must be larger than the Start number"));
}
XmlElement groupItems = group.TopNode.SelectSingleNode("d:fieldGroup/d:groupItems", group.NameSpaceManager) as XmlElement;
int items = 2;
//First date
double index=start;
double nextIndex=start+interval;
AddGroupItem(groupItems, "<" + start.ToString(CultureInfo.InvariantCulture));
while (index < end)
{
AddGroupItem(groupItems, string.Format("{0}-{1}", index.ToString(CultureInfo.InvariantCulture), nextIndex.ToString(CultureInfo.InvariantCulture)));
index=nextIndex;
nextIndex+=interval;
items++;
}
AddGroupItem(groupItems, ">" + nextIndex.ToString(CultureInfo.InvariantCulture));
return items;
}
private void AddFieldItems(int items)
{
XmlElement prevNode = null;
XmlElement itemsNode = TopNode.SelectSingleNode("d:items", NameSpaceManager) as XmlElement;
for (int x = 0; x < items; x++)
{
var itemNode = itemsNode.OwnerDocument.CreateElement("item", ExcelPackage.schemaMain);
itemNode.SetAttribute("x", x.ToString());
if (prevNode == null)
{
itemsNode.PrependChild(itemNode);
}
else
{
itemsNode.InsertAfter(itemNode, prevNode);
}
prevNode = itemNode;
}
itemsNode.SetAttribute("count", (items + 1).ToString());
}
private int AddDateGroupItems(ExcelPivotTableFieldGroup group, eDateGroupBy GroupBy, DateTime StartDate, DateTime EndDate, int interval)
{
XmlElement groupItems = group.TopNode.SelectSingleNode("d:fieldGroup/d:groupItems", group.NameSpaceManager) as XmlElement;
int items = 2;
//First date
AddGroupItem(groupItems, "<" + StartDate.ToString("s", CultureInfo.InvariantCulture).Substring(0, 10));
switch (GroupBy)
{
case eDateGroupBy.Seconds:
case eDateGroupBy.Minutes:
AddTimeSerie(60, groupItems);
items += 60;
break;
case eDateGroupBy.Hours:
AddTimeSerie(24, groupItems);
items += 24;
break;
case eDateGroupBy.Days:
if (interval == 1)
{
DateTime dt = new DateTime(2008, 1, 1); //pick a year with 366 days
while (dt.Year == 2008)
{
AddGroupItem(groupItems, dt.ToString("dd-MMM"));
dt = dt.AddDays(1);
}
items += 366;
}
else
{
DateTime dt = StartDate;
items = 0;
while (dt < EndDate)
{
AddGroupItem(groupItems, dt.ToString("dd-MMM"));
dt = dt.AddDays(interval);
items++;
}
}
break;
case eDateGroupBy.Months:
AddGroupItem(groupItems, "jan");
AddGroupItem(groupItems, "feb");
AddGroupItem(groupItems, "mar");
AddGroupItem(groupItems, "apr");
AddGroupItem(groupItems, "may");
AddGroupItem(groupItems, "jun");
AddGroupItem(groupItems, "jul");
AddGroupItem(groupItems, "aug");
AddGroupItem(groupItems, "sep");
AddGroupItem(groupItems, "oct");
AddGroupItem(groupItems, "nov");
AddGroupItem(groupItems, "dec");
items += 12;
break;
case eDateGroupBy.Quarters:
AddGroupItem(groupItems, "Qtr1");
AddGroupItem(groupItems, "Qtr2");
AddGroupItem(groupItems, "Qtr3");
AddGroupItem(groupItems, "Qtr4");
items += 4;
break;
case eDateGroupBy.Years:
if(StartDate.Year>=1900 && EndDate!=DateTime.MaxValue)
{
for (int year = StartDate.Year; year <= EndDate.Year; year++)
{
AddGroupItem(groupItems, year.ToString());
}
items += EndDate.Year - StartDate.Year+1;
}
break;
default:
throw (new Exception("unsupported grouping"));
}
//Lastdate
AddGroupItem(groupItems, ">" + EndDate.ToString("s", CultureInfo.InvariantCulture).Substring(0, 10));
return items;
}
private void AddTimeSerie(int count, XmlElement groupItems)
{
for (int i = 0; i < count; i++)
{
AddGroupItem(groupItems, string.Format("{0:00}", i));
}
}
private void AddGroupItem(XmlElement groupItems, string value)
{
var s = groupItems.OwnerDocument.CreateElement("s", ExcelPackage.schemaMain);
s.SetAttribute("v", value);
groupItems.AppendChild(s);
}
#endregion
internal ExcelPivotTableFieldCollectionBase _items=null;
///
/// Pivottable field Items. Used for grouping.
///
public ExcelPivotTableFieldCollectionBase Items
{
get
{
if (_items == null)
{
_items = new ExcelPivotTableFieldCollectionBase(_table);
foreach (XmlNode node in TopNode.SelectNodes("d:items//d:item", NameSpaceManager))
{
var item = new ExcelPivotTableFieldItem(NameSpaceManager, node,this);
if (item.T == "")
{
_items.AddInternal(item);
}
}
//if (_grouping is ExcelPivotTableFieldDateGroup)
//{
// ExcelPivotTableFieldDateGroup dtgrp = ((ExcelPivotTableFieldDateGroup)_grouping);
// ExcelPivotTableFieldItem minItem=null, maxItem=null;
// foreach (var item in _items)
// {
// if (item.X == 0)
// {
// minItem = item;
// }
// else if (maxItem == null || maxItem.X < item.X)
// {
// maxItem = item;
// }
// }
// if (dtgrp.AutoStart)
// {
// _items._list.Remove(minItem);
// }
// if (dtgrp.AutoEnd)
// {
// _items._list.Remove(maxItem);
// }
//}
}
return _items;
}
}
///
/// Add numberic grouping to the field
///
/// Start value
/// End value
/// Interval
public void AddNumericGrouping(double Start, double End, double Interval)
{
ValidateGrouping();
SetNumericGroup(Start, End, Interval);
}
///
/// Add a date grouping on this field.
///
/// Group by
public void AddDateGrouping(eDateGroupBy groupBy)
{
AddDateGrouping(groupBy, DateTime.MinValue, DateTime.MaxValue,1);
}
///
/// Add a date grouping on this field.
///
/// Group by
/// Fixed start date. Use DateTime.MinValue for auto
/// Fixed end date. Use DateTime.MaxValue for auto
public void AddDateGrouping(eDateGroupBy groupBy, DateTime startDate, DateTime endDate)
{
AddDateGrouping(groupBy, startDate, endDate, 1);
}
///
/// Add a date grouping on this field.
///
/// Number of days when grouping on days
/// Fixed start date. Use DateTime.MinValue for auto
/// Fixed end date. Use DateTime.MaxValue for auto
public void AddDateGrouping(int days, DateTime startDate, DateTime endDate)
{
AddDateGrouping(eDateGroupBy.Days, startDate, endDate, days);
}
private void AddDateGrouping(eDateGroupBy groupBy, DateTime startDate, DateTime endDate, int groupInterval)
{
if (groupInterval < 1 || groupInterval >= Int16.MaxValue)
{
throw (new ArgumentOutOfRangeException("Group interval is out of range"));
}
if (groupInterval > 1 && groupBy != eDateGroupBy.Days)
{
throw (new ArgumentException("Group interval is can only be used when groupBy is Days"));
}
ValidateGrouping();
bool firstField = true;
List fields=new List();
//Seconds
if ((groupBy & eDateGroupBy.Seconds) == eDateGroupBy.Seconds)
{
fields.Add(AddField(eDateGroupBy.Seconds, startDate, endDate, ref firstField));
}
//Minutes
if ((groupBy & eDateGroupBy.Minutes) == eDateGroupBy.Minutes)
{
fields.Add(AddField(eDateGroupBy.Minutes, startDate, endDate, ref firstField));
}
//Hours
if ((groupBy & eDateGroupBy.Hours) == eDateGroupBy.Hours)
{
fields.Add(AddField(eDateGroupBy.Hours, startDate, endDate, ref firstField));
}
//Days
if ((groupBy & eDateGroupBy.Days) == eDateGroupBy.Days)
{
fields.Add(AddField(eDateGroupBy.Days, startDate, endDate, ref firstField, groupInterval));
}
//Month
if ((groupBy & eDateGroupBy.Months) == eDateGroupBy.Months)
{
fields.Add(AddField(eDateGroupBy.Months, startDate, endDate, ref firstField));
}
//Quarters
if ((groupBy & eDateGroupBy.Quarters) == eDateGroupBy.Quarters)
{
fields.Add(AddField(eDateGroupBy.Quarters, startDate, endDate, ref firstField));
}
//Years
if ((groupBy & eDateGroupBy.Years) == eDateGroupBy.Years)
{
fields.Add(AddField(eDateGroupBy.Years, startDate, endDate, ref firstField));
}
if (fields.Count > 1) _cacheFieldHelper.SetXmlNodeString("d:fieldGroup/@par", (_table.Fields.Count - 1).ToString());
if (groupInterval != 1)
{
_cacheFieldHelper.SetXmlNodeString("d:fieldGroup/d:rangePr/@groupInterval", groupInterval.ToString());
}
else
{
_cacheFieldHelper.DeleteNode("d:fieldGroup/d:rangePr/@groupInterval");
}
_items = null;
}
private void ValidateGrouping()
{
if (!(IsColumnField || IsRowField))
{
throw (new Exception("Field must be a row or column field"));
}
foreach (var field in _table.Fields)
{
if (field.Grouping != null)
{
throw (new Exception("Grouping already exists"));
}
}
}
private ExcelPivotTableField AddField(eDateGroupBy groupBy, DateTime startDate, DateTime endDate, ref bool firstField)
{
return AddField(groupBy, startDate, endDate, ref firstField,1);
}
private ExcelPivotTableField AddField(eDateGroupBy groupBy, DateTime startDate, DateTime endDate, ref bool firstField, int interval)
{
if (firstField == false)
{
//Pivot field
var topNode = _table.PivotTableXml.SelectSingleNode("//d:pivotFields", _table.NameSpaceManager);
var fieldNode = _table.PivotTableXml.CreateElement("pivotField", ExcelPackage.schemaMain);
fieldNode.SetAttribute("compact", "0");
fieldNode.SetAttribute("outline", "0");
fieldNode.SetAttribute("showAll", "0");
fieldNode.SetAttribute("defaultSubtotal", "0");
topNode.AppendChild(fieldNode);
var field = new ExcelPivotTableField(_table.NameSpaceManager, fieldNode, _table, _table.Fields.Count, Index);
field.DateGrouping = groupBy;
XmlNode rowColFields;
if (IsRowField)
{
rowColFields=TopNode.SelectSingleNode("../../d:rowFields", NameSpaceManager);
}
else
{
rowColFields = TopNode.SelectSingleNode("../../d:colFields", NameSpaceManager);
}
int fieldIndex, index = 0;
foreach (XmlElement rowfield in rowColFields.ChildNodes)
{
if (int.TryParse(rowfield.GetAttribute("x"), out fieldIndex))
{
if (_table.Fields[fieldIndex].BaseIndex == BaseIndex)
{
var newElement = rowColFields.OwnerDocument.CreateElement("field", ExcelPackage.schemaMain);
newElement.SetAttribute("x", field.Index.ToString());
rowColFields.InsertBefore(newElement, rowfield);
break;
}
}
index++;
}
if (IsRowField)
{
_table.RowFields.Insert(field, index);
}
else
{
_table.ColumnFields.Insert(field, index);
}
_table.Fields.AddInternal(field);
AddCacheField(field, startDate, endDate, interval);
return field;
}
else
{
firstField = false;
DateGrouping = groupBy;
Compact = false;
SetDateGroup(groupBy, startDate, endDate, interval);
return this;
}
}
private void AddCacheField(ExcelPivotTableField field, DateTime startDate, DateTime endDate, int interval)
{
//Add Cache definition field.
var cacheTopNode = _table.CacheDefinition.CacheDefinitionXml.SelectSingleNode("//d:cacheFields", _table.NameSpaceManager);
var cacheFieldNode = _table.CacheDefinition.CacheDefinitionXml.CreateElement("cacheField", ExcelPackage.schemaMain);
cacheFieldNode.SetAttribute("name", field.DateGrouping.ToString());
cacheFieldNode.SetAttribute("databaseField", "0");
cacheTopNode.AppendChild(cacheFieldNode);
field.SetCacheFieldNode(cacheFieldNode);
field.SetDateGroup(field.DateGrouping, startDate, endDate, interval);
}
}
}