/******************************************************************************* * 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 Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ using System; using System.Collections.Generic; using System.Globalization; using System.Text; using System.Xml; using System.Drawing; namespace OfficeOpenXml.Style.XmlAccess { /// /// Xml access class xfs records. This is the top level style object. /// public sealed class ExcelXfs : StyleXmlHelper { ExcelStyles _styles; internal ExcelXfs(XmlNamespaceManager nameSpaceManager, ExcelStyles styles) : base(nameSpaceManager) { _styles = styles; isBuildIn = false; } internal ExcelXfs(XmlNamespaceManager nsm, XmlNode topNode, ExcelStyles styles) : base(nsm, topNode) { _styles = styles; _xfID = GetXmlNodeInt("@xfId"); if (_xfID == 0) isBuildIn = true; //Normal taggen _numFmtId = GetXmlNodeInt("@numFmtId"); _fontId = GetXmlNodeInt("@fontId"); _fillId = GetXmlNodeInt("@fillId"); _borderId = GetXmlNodeInt("@borderId"); _readingOrder = GetReadingOrder(GetXmlNodeString(readingOrderPath)); _indent = GetXmlNodeInt(indentPath); _shrinkToFit = GetXmlNodeString(shrinkToFitPath) == "1" ? true : false; _verticalAlignment = GetVerticalAlign(GetXmlNodeString(verticalAlignPath)); _horizontalAlignment = GetHorizontalAlign(GetXmlNodeString(horizontalAlignPath)); _wrapText = GetXmlNodeBool(wrapTextPath); _textRotation = GetXmlNodeInt(textRotationPath); _hidden = GetXmlNodeBool(hiddenPath); _locked = GetXmlNodeBool(lockedPath,true); } private ExcelReadingOrder GetReadingOrder(string value) { switch(value) { case "1": return ExcelReadingOrder.LeftToRight; case "2": return ExcelReadingOrder.RightToLeft; default: return ExcelReadingOrder.ContextDependent; } } private ExcelHorizontalAlignment GetHorizontalAlign(string align) { if (align == "") return ExcelHorizontalAlignment.General; align = align.Substring(0, 1).ToUpper(CultureInfo.InvariantCulture) + align.Substring(1, align.Length - 1); try { return (ExcelHorizontalAlignment)Enum.Parse(typeof(ExcelHorizontalAlignment), align); } catch { return ExcelHorizontalAlignment.General; } } private ExcelVerticalAlignment GetVerticalAlign(string align) { if (align == "") return ExcelVerticalAlignment.Bottom; align = align.Substring(0, 1).ToUpper(CultureInfo.InvariantCulture) + align.Substring(1, align.Length - 1); try { return (ExcelVerticalAlignment)Enum.Parse(typeof(ExcelVerticalAlignment), align); } catch { return ExcelVerticalAlignment.Bottom; } } internal void Xf_ChangedEvent(object sender, EventArgs e) { //if (_cell != null) //{ // if (!Styles.ChangedCells.ContainsKey(_cell.Id)) // { // //_cell.Style = ""; // _cell.SetNewStyleID(int.MinValue.ToString()); // Styles.ChangedCells.Add(_cell.Id, _cell); // } //} } int _xfID; /// /// Style index /// public int XfId { get { return _xfID; } set { _xfID = value; } } #region Internal Properties int _numFmtId; internal int NumberFormatId { get { return _numFmtId; } set { _numFmtId = value; ApplyNumberFormat = (value>0); } } int _fontId; internal int FontId { get { return _fontId; } set { _fontId = value; } } int _fillId; internal int FillId { get { return _fillId; } set { _fillId = value; } } int _borderId; internal int BorderId { get { return _borderId; } set { _borderId = value; } } private bool isBuildIn { get; set; } internal bool ApplyNumberFormat { get; set; } internal bool ApplyFont { get; set; } internal bool ApplyFill { get; set; } internal bool ApplyBorder { get; set; } internal bool ApplyAlignment { get; set; } internal bool ApplyProtection { get; set; } #endregion #region Public Properties public ExcelStyles Styles { get; private set; } /// /// Numberformat properties /// public ExcelNumberFormatXml Numberformat { get { return _styles.NumberFormats[_numFmtId < 0 ? 0 : _numFmtId]; } } /// /// Font properties /// public ExcelFontXml Font { get { return _styles.Fonts[_fontId < 0 ? 0 : _fontId]; } } /// /// Fill properties /// public ExcelFillXml Fill { get { return _styles.Fills[_fillId < 0 ? 0 : _fillId]; } } /// /// Border style properties /// public ExcelBorderXml Border { get { return _styles.Borders[_borderId < 0 ? 0 : _borderId]; } } const string horizontalAlignPath = "d:alignment/@horizontal"; ExcelHorizontalAlignment _horizontalAlignment = ExcelHorizontalAlignment.General; /// /// Horizontal alignment /// public ExcelHorizontalAlignment HorizontalAlignment { get { return _horizontalAlignment; } set { _horizontalAlignment = value; } } const string verticalAlignPath = "d:alignment/@vertical"; ExcelVerticalAlignment _verticalAlignment=ExcelVerticalAlignment.Bottom; /// /// Vertical alignment /// public ExcelVerticalAlignment VerticalAlignment { get { return _verticalAlignment; } set { _verticalAlignment = value; } } const string wrapTextPath = "d:alignment/@wrapText"; bool _wrapText=false; /// /// Wraped text /// public bool WrapText { get { return _wrapText; } set { _wrapText = value; } } string textRotationPath = "d:alignment/@textRotation"; int _textRotation = 0; /// /// Text rotation angle /// public int TextRotation { get { return (_textRotation == int.MinValue ? 0 : _textRotation); } set { _textRotation = value; } } const string lockedPath = "d:protection/@locked"; bool _locked = true; /// /// Locked when sheet is protected /// public bool Locked { get { return _locked; } set { _locked = value; } } const string hiddenPath = "d:protection/@hidden"; bool _hidden = false; /// /// Hide formulas when sheet is protected /// public bool Hidden { get { return _hidden; } set { _hidden = value; } } const string readingOrderPath = "d:alignment/@readingOrder"; ExcelReadingOrder _readingOrder = ExcelReadingOrder.ContextDependent; /// /// Readingorder /// public ExcelReadingOrder ReadingOrder { get { return _readingOrder; } set { _readingOrder = value; } } const string shrinkToFitPath = "d:alignment/@shrinkToFit"; bool _shrinkToFit = false; /// /// Shrink to fit /// public bool ShrinkToFit { get { return _shrinkToFit; } set { _shrinkToFit = value; } } const string indentPath = "d:alignment/@indent"; int _indent = 0; /// /// Indentation /// public int Indent { get { return (_indent == int.MinValue ? 0 : _indent); } set { _indent=value; } } #endregion internal void RegisterEvent(ExcelXfs xf) { // RegisterEvent(xf, xf.Xf_ChangedEvent); } internal override string Id { get { return XfId + "|" + NumberFormatId.ToString() + "|" + FontId.ToString() + "|" + FillId.ToString() + "|" + BorderId.ToString() + VerticalAlignment.ToString() + "|" + HorizontalAlignment.ToString() + "|" + WrapText.ToString() + "|" + ReadingOrder.ToString() + "|" + isBuildIn.ToString() + TextRotation.ToString() + Locked.ToString() + Hidden.ToString() + ShrinkToFit.ToString() + Indent.ToString(); //return Numberformat.Id + "|" + Font.Id + "|" + Fill.Id + "|" + Border.Id + VerticalAlignment.ToString() + "|" + HorizontalAlignment.ToString() + "|" + WrapText.ToString() + "|" + ReadingOrder.ToString(); } } internal ExcelXfs Copy() { return Copy(_styles); } internal ExcelXfs Copy(ExcelStyles styles) { ExcelXfs newXF = new ExcelXfs(NameSpaceManager, styles); newXF.NumberFormatId = _numFmtId; newXF.FontId = _fontId; newXF.FillId = _fillId; newXF.BorderId = _borderId; newXF.XfId = _xfID; newXF.ReadingOrder = _readingOrder; newXF.HorizontalAlignment = _horizontalAlignment; newXF.VerticalAlignment = _verticalAlignment; newXF.WrapText = _wrapText; newXF.ShrinkToFit = _shrinkToFit; newXF.Indent = _indent; newXF.TextRotation = _textRotation; newXF.Locked = _locked; newXF.Hidden = _hidden; return newXF; } internal int GetNewID(ExcelStyleCollection xfsCol, StyleBase styleObject, eStyleClass styleClass, eStyleProperty styleProperty, object value) { ExcelXfs newXfs = this.Copy(); switch(styleClass) { case eStyleClass.Numberformat: newXfs.NumberFormatId = GetIdNumberFormat(styleProperty, value); styleObject.SetIndex(newXfs.NumberFormatId); break; case eStyleClass.Font: { newXfs.FontId = GetIdFont(styleProperty, value); styleObject.SetIndex(newXfs.FontId); break; } case eStyleClass.Fill: case eStyleClass.FillBackgroundColor: case eStyleClass.FillPatternColor: newXfs.FillId = GetIdFill(styleClass, styleProperty, value); styleObject.SetIndex(newXfs.FillId); break; case eStyleClass.GradientFill: case eStyleClass.FillGradientColor1: case eStyleClass.FillGradientColor2: newXfs.FillId = GetIdGradientFill(styleClass, styleProperty, value); styleObject.SetIndex(newXfs.FillId); break; case eStyleClass.Border: case eStyleClass.BorderBottom: case eStyleClass.BorderDiagonal: case eStyleClass.BorderLeft: case eStyleClass.BorderRight: case eStyleClass.BorderTop: newXfs.BorderId = GetIdBorder(styleClass, styleProperty, value); styleObject.SetIndex(newXfs.BorderId); break; case eStyleClass.Style: switch(styleProperty) { case eStyleProperty.XfId: newXfs.XfId = (int)value; break; case eStyleProperty.HorizontalAlign: newXfs.HorizontalAlignment=(ExcelHorizontalAlignment)value; break; case eStyleProperty.VerticalAlign: newXfs.VerticalAlignment = (ExcelVerticalAlignment)value; break; case eStyleProperty.WrapText: newXfs.WrapText = (bool)value; break; case eStyleProperty.ReadingOrder: newXfs.ReadingOrder = (ExcelReadingOrder)value; break; case eStyleProperty.ShrinkToFit: newXfs.ShrinkToFit=(bool)value; break; case eStyleProperty.Indent: newXfs.Indent = (int)value; break; case eStyleProperty.TextRotation: newXfs.TextRotation = (int)value; break; case eStyleProperty.Locked: newXfs.Locked = (bool)value; break; case eStyleProperty.Hidden: newXfs.Hidden = (bool)value; break; default: throw (new Exception("Invalid property for class style.")); } break; default: break; } int id = xfsCol.FindIndexByID(newXfs.Id); if (id < 0) { return xfsCol.Add(newXfs.Id, newXfs); } return id; } private int GetIdBorder(eStyleClass styleClass, eStyleProperty styleProperty, object value) { ExcelBorderXml border = Border.Copy(); switch (styleClass) { case eStyleClass.BorderBottom: SetBorderItem(border.Bottom, styleProperty, value); break; case eStyleClass.BorderDiagonal: SetBorderItem(border.Diagonal, styleProperty, value); break; case eStyleClass.BorderLeft: SetBorderItem(border.Left, styleProperty, value); break; case eStyleClass.BorderRight: SetBorderItem(border.Right, styleProperty, value); break; case eStyleClass.BorderTop: SetBorderItem(border.Top, styleProperty, value); break; case eStyleClass.Border: if (styleProperty == eStyleProperty.BorderDiagonalUp) { border.DiagonalUp = (bool)value; } else if (styleProperty == eStyleProperty.BorderDiagonalDown) { border.DiagonalDown = (bool)value; } else { throw (new Exception("Invalid property for class Border.")); } break; default: throw (new Exception("Invalid class/property for class Border.")); } int subId; string id = border.Id; subId = _styles.Borders.FindIndexByID(id); if (subId == int.MinValue) { return _styles.Borders.Add(id, border); } return subId; } private void SetBorderItem(ExcelBorderItemXml excelBorderItem, eStyleProperty styleProperty, object value) { if(styleProperty==eStyleProperty.Style) { excelBorderItem.Style = (ExcelBorderStyle)value; } else if (styleProperty == eStyleProperty.Color || styleProperty== eStyleProperty.Tint || styleProperty==eStyleProperty.IndexedColor) { if (excelBorderItem.Style == ExcelBorderStyle.None) { throw(new Exception("Can't set bordercolor when style is not set.")); } excelBorderItem.Color.Rgb = value.ToString(); } } private int GetIdFill(eStyleClass styleClass, eStyleProperty styleProperty, object value) { ExcelFillXml fill = Fill.Copy(); switch (styleProperty) { case eStyleProperty.PatternType: if (fill is ExcelGradientFillXml) { fill = new ExcelFillXml(NameSpaceManager); } fill.PatternType = (ExcelFillStyle)value; break; case eStyleProperty.Color: case eStyleProperty.Tint: case eStyleProperty.IndexedColor: case eStyleProperty.AutoColor: if (fill is ExcelGradientFillXml) { fill = new ExcelFillXml(NameSpaceManager); } if (fill.PatternType == ExcelFillStyle.None) { throw (new ArgumentException("Can't set color when patterntype is not set.")); } ExcelColorXml destColor; if (styleClass==eStyleClass.FillPatternColor) { destColor = fill.PatternColor; } else { destColor = fill.BackgroundColor; } if (styleProperty == eStyleProperty.Color) { destColor.Rgb = value.ToString(); } else if (styleProperty == eStyleProperty.Tint) { destColor.Tint = (decimal)value; } else if (styleProperty == eStyleProperty.IndexedColor) { destColor.Indexed = (int)value; } else { destColor.Auto = (bool)value; } break; default: throw (new ArgumentException("Invalid class/property for class Fill.")); } int subId; string id = fill.Id; subId = _styles.Fills.FindIndexByID(id); if (subId == int.MinValue) { return _styles.Fills.Add(id, fill); } return subId; } private int GetIdGradientFill(eStyleClass styleClass, eStyleProperty styleProperty, object value) { ExcelGradientFillXml fill; if(Fill is ExcelGradientFillXml) { fill = (ExcelGradientFillXml)Fill.Copy(); } else { fill = new ExcelGradientFillXml(Fill.NameSpaceManager); fill.GradientColor1.SetColor(Color.White); fill.GradientColor2.SetColor(Color.FromArgb(79,129,189)); fill.Type=ExcelFillGradientType.Linear; fill.Degree=90; fill.Top = double.NaN; fill.Bottom = double.NaN; fill.Left = double.NaN; fill.Right = double.NaN; } switch (styleProperty) { case eStyleProperty.GradientType: fill.Type = (ExcelFillGradientType)value; break; case eStyleProperty.GradientDegree: fill.Degree = (double)value; break; case eStyleProperty.GradientTop: fill.Top = (double)value; break; case eStyleProperty.GradientBottom: fill.Bottom = (double)value; break; case eStyleProperty.GradientLeft: fill.Left = (double)value; break; case eStyleProperty.GradientRight: fill.Right = (double)value; break; case eStyleProperty.Color: case eStyleProperty.Tint: case eStyleProperty.IndexedColor: case eStyleProperty.AutoColor: ExcelColorXml destColor; if (styleClass == eStyleClass.FillGradientColor1) { destColor = fill.GradientColor1; } else { destColor = fill.GradientColor2; } if (styleProperty == eStyleProperty.Color) { destColor.Rgb = value.ToString(); } else if (styleProperty == eStyleProperty.Tint) { destColor.Tint = (decimal)value; } else if (styleProperty == eStyleProperty.IndexedColor) { destColor.Indexed = (int)value; } else { destColor.Auto = (bool)value; } break; default: throw (new ArgumentException("Invalid class/property for class Fill.")); } int subId; string id = fill.Id; subId = _styles.Fills.FindIndexByID(id); if (subId == int.MinValue) { return _styles.Fills.Add(id, fill); } return subId; } private int GetIdNumberFormat(eStyleProperty styleProperty, object value) { if (styleProperty == eStyleProperty.Format) { ExcelNumberFormatXml item=null; if (!_styles.NumberFormats.FindByID(value.ToString(), ref item)) { item = new ExcelNumberFormatXml(NameSpaceManager) { Format = value.ToString(), NumFmtId = _styles.NumberFormats.NextId++ }; _styles.NumberFormats.Add(value.ToString(), item); } return item.NumFmtId; } else { throw (new Exception("Invalid property for class Numberformat")); } } private int GetIdFont(eStyleProperty styleProperty, object value) { ExcelFontXml fnt = Font.Copy(); switch (styleProperty) { case eStyleProperty.Name: fnt.Name = value.ToString(); break; case eStyleProperty.Size: fnt.Size = (float)value; break; case eStyleProperty.Family: fnt.Family = (int)value; break; case eStyleProperty.Bold: fnt.Bold = (bool)value; break; case eStyleProperty.Italic: fnt.Italic = (bool)value; break; case eStyleProperty.Strike: fnt.Strike = (bool)value; break; case eStyleProperty.UnderlineType: fnt.UnderLineType = (ExcelUnderLineType)value; break; case eStyleProperty.Color: fnt.Color.Rgb=value.ToString(); break; case eStyleProperty.VerticalAlign: fnt.VerticalAlign = ((ExcelVerticalAlignmentFont)value) == ExcelVerticalAlignmentFont.None ? "" : value.ToString().ToLower(CultureInfo.InvariantCulture); break; default: throw (new Exception("Invalid property for class Font")); } int subId; string id = fnt.Id; subId = _styles.Fonts.FindIndexByID(id); if (subId == int.MinValue) { return _styles.Fonts.Add(id,fnt); } return subId; } internal override XmlNode CreateXmlNode(XmlNode topNode) { return CreateXmlNode(topNode, false); } internal XmlNode CreateXmlNode(XmlNode topNode, bool isCellStyleXsf) { TopNode = topNode; var doSetXfId = (!isCellStyleXsf && _xfID > int.MinValue && _styles.CellStyleXfs.Count > 0 && _styles.CellStyleXfs[_xfID].newID > int.MinValue); if (_numFmtId >= 0) { SetXmlNodeString("@numFmtId", _numFmtId.ToString()); if(doSetXfId) SetXmlNodeString("@applyNumberFormat", "1"); } if (_fontId >= 0) { SetXmlNodeString("@fontId", _styles.Fonts[_fontId].newID.ToString()); if (doSetXfId) SetXmlNodeString("@applyFont", "1"); } if (_fillId >= 0) { SetXmlNodeString("@fillId", _styles.Fills[_fillId].newID.ToString()); if (doSetXfId) SetXmlNodeString("@applyFill", "1"); } if (_borderId >= 0) { SetXmlNodeString("@borderId", _styles.Borders[_borderId].newID.ToString()); if (doSetXfId) SetXmlNodeString("@applyBorder", "1"); } if(_horizontalAlignment != ExcelHorizontalAlignment.General) this.SetXmlNodeString(horizontalAlignPath, SetAlignString(_horizontalAlignment)); if (doSetXfId) { SetXmlNodeString("@xfId", _styles.CellStyleXfs[_xfID].newID.ToString()); } if (_verticalAlignment != ExcelVerticalAlignment.Bottom) this.SetXmlNodeString(verticalAlignPath, SetAlignString(_verticalAlignment)); if(_wrapText) this.SetXmlNodeString(wrapTextPath, "1"); if(_readingOrder!=ExcelReadingOrder.ContextDependent) this.SetXmlNodeString(readingOrderPath, ((int)_readingOrder).ToString()); if (_shrinkToFit) this.SetXmlNodeString(shrinkToFitPath, "1"); if (_indent > 0) SetXmlNodeString(indentPath, _indent.ToString()); if (_textRotation > 0) this.SetXmlNodeString(textRotationPath, _textRotation.ToString()); if (!_locked) this.SetXmlNodeString(lockedPath, "0"); if (_hidden) this.SetXmlNodeString(hiddenPath, "1"); return TopNode; } private string SetAlignString(Enum align) { string newName = Enum.GetName(align.GetType(), align); return newName.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + newName.Substring(1, newName.Length - 1); } } }