/*******************************************************************************
* 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.Linq;
using OfficeOpenXml.Utils;
namespace OfficeOpenXml.Table.PivotTable
{
public enum eSourceType
{
///
/// Indicates that the cache contains data that consolidates ranges.
///
Consolidation,
///
/// Indicates that the cache contains data from an external data source.
///
External,
///
/// Indicates that the cache contains a scenario summary report
///
Scenario,
///
/// Indicates that the cache contains worksheet data
///
Worksheet
}
///
/// Cache definition. This class defines the source data. Note that one cache definition can be shared between many pivot tables.
///
public class ExcelPivotCacheDefinition : XmlHelper
{
internal ExcelPivotCacheDefinition(XmlNamespaceManager ns, ExcelPivotTable pivotTable) :
base(ns, null)
{
foreach (var r in pivotTable.Part.GetRelationshipsByType(ExcelPackage.schemaRelationships + "/pivotCacheDefinition"))
{
Relationship = r;
}
CacheDefinitionUri = UriHelper.ResolvePartUri(Relationship.SourceUri, Relationship.TargetUri);
var pck = pivotTable.WorkSheet._package.Package;
Part = pck.GetPart(CacheDefinitionUri);
CacheDefinitionXml = new XmlDocument();
LoadXmlSafe(CacheDefinitionXml, Part.GetStream());
TopNode = CacheDefinitionXml.DocumentElement;
PivotTable = pivotTable;
if (CacheSource == eSourceType.Worksheet)
{
var worksheetName = GetXmlNodeString(_sourceWorksheetPath);
if (pivotTable.WorkSheet.Workbook.Worksheets.Any(t => t.Name == worksheetName))
{
_sourceRange = pivotTable.WorkSheet.Workbook.Worksheets[worksheetName].Cells[GetXmlNodeString(_sourceAddressPath)];
}
}
}
internal ExcelPivotCacheDefinition(XmlNamespaceManager ns, ExcelPivotTable pivotTable, ExcelRangeBase sourceAddress, int tblId) :
base(ns, null)
{
PivotTable = pivotTable;
var pck = pivotTable.WorkSheet._package.Package;
//CacheDefinition
CacheDefinitionXml = new XmlDocument();
LoadXmlSafe(CacheDefinitionXml, GetStartXml(sourceAddress), Encoding.UTF8);
CacheDefinitionUri = GetNewUri(pck, "/xl/pivotCache/pivotCacheDefinition{0}.xml", tblId);
Part = pck.CreatePart(CacheDefinitionUri, ExcelPackage.schemaPivotCacheDefinition);
TopNode = CacheDefinitionXml.DocumentElement;
//CacheRecord. Create an empty one.
CacheRecordUri = GetNewUri(pck, "/xl/pivotCache/pivotCacheRecords{0}.xml", tblId);
var cacheRecord = new XmlDocument();
cacheRecord.LoadXml("");
var recPart = pck.CreatePart(CacheRecordUri, ExcelPackage.schemaPivotCacheRecords);
cacheRecord.Save(recPart.GetStream());
RecordRelationship = Part.CreateRelationship(UriHelper.ResolvePartUri(CacheDefinitionUri, CacheRecordUri), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/pivotCacheRecords");
RecordRelationshipID = RecordRelationship.Id;
CacheDefinitionXml.Save(Part.GetStream());
}
///
/// Reference to the internal package part
///
internal Packaging.ZipPackagePart Part
{
get;
set;
}
///
/// Provides access to the XML data representing the cache definition in the package.
///
public XmlDocument CacheDefinitionXml { get; private set; }
///
/// The package internal URI to the pivottable cache definition Xml Document.
///
public Uri CacheDefinitionUri
{
get;
internal set;
}
internal Uri CacheRecordUri
{
get;
set;
}
internal Packaging.ZipPackageRelationship Relationship
{
get;
set;
}
internal Packaging.ZipPackageRelationship RecordRelationship
{
get;
set;
}
internal string RecordRelationshipID
{
get
{
return GetXmlNodeString("@r:id");
}
set
{
SetXmlNodeString("@r:id", value);
}
}
///
/// Referece to the PivoTable object
///
public ExcelPivotTable PivotTable
{
get;
private set;
}
const string _sourceWorksheetPath="d:cacheSource/d:worksheetSource/@sheet";
const string _sourceAddressPath = "d:cacheSource/d:worksheetSource/@ref";
internal ExcelRangeBase _sourceRange = null;
///
/// The source data range when the pivottable has a worksheet datasource.
/// The number of columns in the range must be intact if this property is changed.
/// The range must be in the same workbook as the pivottable.
///
public ExcelRangeBase SourceRange
{
get
{
if (_sourceRange == null)
{
if (CacheSource == eSourceType.Worksheet)
{
var ws = PivotTable.WorkSheet.Workbook.Worksheets[GetXmlNodeString(_sourceWorksheetPath)];
if (ws != null)
{
_sourceRange = ws.Cells[GetXmlNodeString(_sourceAddressPath)];
}
}
else
{
throw (new ArgumentException("The cachesource is not a worksheet"));
}
}
return _sourceRange;
}
set
{
if (PivotTable.WorkSheet.Workbook != value.Worksheet.Workbook)
{
throw (new ArgumentException("Range must be in the same package as the pivottable"));
}
var sr=SourceRange;
if (value.End.Column - value.Start.Column != sr.End.Column - sr.Start.Column)
{
throw (new ArgumentException("Can not change the number of columns(fields) in the SourceRange"));
}
SetXmlNodeString(_sourceWorksheetPath, value.Worksheet.Name);
SetXmlNodeString(_sourceAddressPath, value.FirstAddress);
_sourceRange = value;
}
}
///
/// Type of source data
///
public eSourceType CacheSource
{
get
{
var s=GetXmlNodeString("d:cacheSource/@type");
if (s == "")
{
return eSourceType.Worksheet;
}
else
{
return (eSourceType)Enum.Parse(typeof(eSourceType), s, true);
}
}
}
private string GetStartXml(ExcelRangeBase sourceAddress)
{
string xml="";
xml += "";
xml += string.Format(" ", sourceAddress.Address, sourceAddress.WorkSheet);
xml += "";
xml += string.Format("", sourceAddress._toCol - sourceAddress._fromCol + 1);
var sourceWorksheet = PivotTable.WorkSheet.Workbook.Worksheets[sourceAddress.WorkSheet];
for (int col = sourceAddress._fromCol; col <= sourceAddress._toCol; col++)
{
if (sourceWorksheet == null || sourceWorksheet._values.GetValue(sourceAddress._fromRow, col) == null || sourceWorksheet._values.GetValue(sourceAddress._fromRow, col).ToString().Trim() == "")
{
xml += string.Format("", col - sourceAddress._fromCol + 1);
}
else
{
xml += string.Format("", sourceWorksheet._values.GetValue(sourceAddress._fromRow, col));
}
//xml += " ";
xml += " ";
xml += "";
}
xml += "";
xml += "";
return xml;
}
}
}