blob: 45acddaa2d617d38885887c27c969cd67277ed3a [file] [log] [blame]
/*******************************************************************************
* 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.Globalization;
using System.Xml;
namespace OfficeOpenXml.Style.XmlAccess;
/// <summary>
/// Xml access class xfs records. This is the top level style object.
/// </summary>
public sealed class ExcelXfs : StyleXmlHelper {
private readonly 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) =>
Enum.TryParse<ExcelHorizontalAlignment>(align, true, out var result)
? result
: ExcelHorizontalAlignment.General;
private ExcelVerticalAlignment GetVerticalAlign(string align) =>
Enum.TryParse<ExcelVerticalAlignment>(align, true, out var result)
? result
: ExcelVerticalAlignment.Bottom;
private int _xfID;
/// <summary>
/// Style index
/// </summary>
public int XfId {
get => _xfID;
set => _xfID = value;
}
private int _numFmtId;
internal int NumberFormatId {
get => _numFmtId;
set {
_numFmtId = value;
ApplyNumberFormat = (value > 0);
}
}
private int _fontId;
internal int FontId {
get => _fontId;
set => _fontId = value;
}
private int _fillId;
internal int FillId {
get => _fillId;
set => _fillId = value;
}
private int _borderId;
internal int BorderId {
get => _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; }
public ExcelStyles Styles { get; private set; }
/// <summary>
/// Numberformat properties
/// </summary>
public ExcelNumberFormatXml Numberformat => _styles.NumberFormats[_numFmtId < 0 ? 0 : _numFmtId];
/// <summary>
/// Font properties
/// </summary>
public ExcelFontXml Font => _styles.Fonts[_fontId < 0 ? 0 : _fontId];
/// <summary>
/// Fill properties
/// </summary>
public ExcelFillXml Fill => _styles.Fills[_fillId < 0 ? 0 : _fillId];
/// <summary>
/// Border style properties
/// </summary>
public ExcelBorderXml Border => _styles.Borders[_borderId < 0 ? 0 : _borderId];
private const string _horizontalAlignPath = "d:alignment/@horizontal";
private ExcelHorizontalAlignment _horizontalAlignment = ExcelHorizontalAlignment.General;
/// <summary>
/// Horizontal alignment
/// </summary>
public ExcelHorizontalAlignment HorizontalAlignment {
get => _horizontalAlignment;
set => _horizontalAlignment = value;
}
private const string _verticalAlignPath = "d:alignment/@vertical";
private ExcelVerticalAlignment _verticalAlignment = ExcelVerticalAlignment.Bottom;
/// <summary>
/// Vertical alignment
/// </summary>
public ExcelVerticalAlignment VerticalAlignment {
get => _verticalAlignment;
set => _verticalAlignment = value;
}
private const string _wrapTextPath = "d:alignment/@wrapText";
private bool _wrapText;
/// <summary>
/// Wraped text
/// </summary>
public bool WrapText {
get => _wrapText;
set => _wrapText = value;
}
private readonly string textRotationPath = "d:alignment/@textRotation";
private int _textRotation;
/// <summary>
/// Text rotation angle
/// </summary>
public int TextRotation {
get => (_textRotation == int.MinValue ? 0 : _textRotation);
set => _textRotation = value;
}
private const string _lockedPath = "d:protection/@locked";
private bool _locked = true;
/// <summary>
/// Locked when sheet is protected
/// </summary>
public bool Locked {
get => _locked;
set => _locked = value;
}
private const string _hiddenPath = "d:protection/@hidden";
private bool _hidden;
/// <summary>
/// Hide formulas when sheet is protected
/// </summary>
public bool Hidden {
get => _hidden;
set => _hidden = value;
}
private const string _readingOrderPath = "d:alignment/@readingOrder";
private ExcelReadingOrder _readingOrder = ExcelReadingOrder.ContextDependent;
/// <summary>
/// Readingorder
/// </summary>
public ExcelReadingOrder ReadingOrder {
get => _readingOrder;
set => _readingOrder = value;
}
private const string _shrinkToFitPath = "d:alignment/@shrinkToFit";
private bool _shrinkToFit;
/// <summary>
/// Shrink to fit
/// </summary>
public bool ShrinkToFit {
get => _shrinkToFit;
set => _shrinkToFit = value;
}
private const string _indentPath = "d:alignment/@indent";
private int _indent;
/// <summary>
/// Indentation
/// </summary>
public int Indent {
get => (_indent == int.MinValue ? 0 : _indent);
set => _indent = value;
}
internal void RegisterEvent(ExcelXfs xf) {
// RegisterEvent(xf, xf.Xf_ChangedEvent);
}
internal override string Id =>
XfId
+ "|"
+ NumberFormatId
+ "|"
+ FontId
+ "|"
+ FillId
+ "|"
+ BorderId
+ VerticalAlignment
+ "|"
+ HorizontalAlignment
+ "|"
+ WrapText
+ "|"
+ ReadingOrder
+ "|"
+ isBuildIn
+ TextRotation
+ Locked
+ Hidden
+ ShrinkToFit
+ Indent;
//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<ExcelXfs> xfsCol,
StyleBase styleObject,
eStyleClass styleClass,
eStyleProperty styleProperty,
object value) {
ExcelXfs newXfs = 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("Invalid property for class style."));
}
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("Invalid property for class Border."));
}
break;
default:
throw (new("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("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(NameSpaceManager);
}
fill.PatternType = (ExcelFillStyle)value;
break;
case eStyleProperty.Color:
case eStyleProperty.Tint:
case eStyleProperty.IndexedColor:
case eStyleProperty.AutoColor:
if (fill is ExcelGradientFillXml) {
fill = new(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(Fill.NameSpaceManager);
fill.GradientColor1.Rgb = "FFFFFFFF";
fill.GradientColor2.Rgb = "FF4F81BD";
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(NameSpaceManager) {
Format = value.ToString(),
NumFmtId = _styles.NumberFormats.NextId++,
};
_styles.NumberFormats.Add(value.ToString(), item);
}
return item.NumFmtId;
}
throw (new("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("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) {
SetXmlNodeString(_horizontalAlignPath, SetAlignString(_horizontalAlignment));
}
if (doSetXfId) {
SetXmlNodeString("@xfId", _styles.CellStyleXfs[_xfID].newID.ToString());
}
if (_verticalAlignment != ExcelVerticalAlignment.Bottom) {
SetXmlNodeString(_verticalAlignPath, SetAlignString(_verticalAlignment));
}
if (_wrapText) {
SetXmlNodeString(_wrapTextPath, "1");
}
if (_readingOrder != ExcelReadingOrder.ContextDependent) {
SetXmlNodeString(_readingOrderPath, ((int)_readingOrder).ToString());
}
if (_shrinkToFit) {
SetXmlNodeString(_shrinkToFitPath, "1");
}
if (_indent > 0) {
SetXmlNodeString(_indentPath, _indent.ToString());
}
if (_textRotation > 0) {
SetXmlNodeString(textRotationPath, _textRotation.ToString());
}
if (!_locked) {
SetXmlNodeString(_lockedPath, "0");
}
if (_hidden) {
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);
}
}