blob: 3392fc72bca7ced78de766c1795d3215fbdecc86 [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 2010-06-01
* Jan Källman License changed GPL-->LGPL 2011-12-16
*******************************************************************************/
using System;
using System.Drawing;
using System.Globalization;
using System.Xml;
namespace OfficeOpenXml.Drawing.Vml;
/// <summary>
/// Drawing object used for comments
/// </summary>
public class ExcelVmlDrawingComment : ExcelVmlDrawingBase, IRangeId {
internal ExcelVmlDrawingComment(XmlNode topNode, ExcelRangeBase range, XmlNamespaceManager ns)
: base(topNode, ns) {
Range = range;
SchemaNodeOrder = new[] {
"fill",
"stroke",
"shadow",
"path",
"textbox",
"ClientData",
"MoveWithCells",
"SizeWithCells",
"Anchor",
"Locked",
"AutoFill",
"LockText",
"TextHAlign",
"TextVAlign",
"Row",
"Column",
"Visible",
};
}
internal ExcelRangeBase Range { get; set; }
/// <summary>
/// Address in the worksheet
/// </summary>
public string Address => Range.Address;
private const string _verticalAlignmentPath = "x:ClientData/x:TextVAlign";
/// <summary>
/// Vertical alignment for text
/// </summary>
public eTextAlignVerticalVml VerticalAlignment {
get {
switch (GetXmlNodeString(_verticalAlignmentPath)) {
case "Center":
return eTextAlignVerticalVml.Center;
case "Bottom":
return eTextAlignVerticalVml.Bottom;
default:
return eTextAlignVerticalVml.Top;
}
}
set {
switch (value) {
case eTextAlignVerticalVml.Center:
SetXmlNodeString(_verticalAlignmentPath, "Center");
break;
case eTextAlignVerticalVml.Bottom:
SetXmlNodeString(_verticalAlignmentPath, "Bottom");
break;
default:
DeleteNode(_verticalAlignmentPath);
break;
}
}
}
private const string _horizontalAlignmentPath = "x:ClientData/x:TextHAlign";
/// <summary>
/// Horizontal alignment for text
/// </summary>
public eTextAlignHorizontalVml HorizontalAlignment {
get {
switch (GetXmlNodeString(_horizontalAlignmentPath)) {
case "Center":
return eTextAlignHorizontalVml.Center;
case "Right":
return eTextAlignHorizontalVml.Right;
default:
return eTextAlignHorizontalVml.Left;
}
}
set {
switch (value) {
case eTextAlignHorizontalVml.Center:
SetXmlNodeString(_horizontalAlignmentPath, "Center");
break;
case eTextAlignHorizontalVml.Right:
SetXmlNodeString(_horizontalAlignmentPath, "Right");
break;
default:
DeleteNode(_horizontalAlignmentPath);
break;
}
}
}
private const string _visiblePath = "x:ClientData/x:Visible";
/// <summary>
/// If the drawing object is visible.
/// </summary>
public bool Visible {
get => (TopNode.SelectSingleNode(_visiblePath, NameSpaceManager) != null);
set {
if (value) {
CreateNode(_visiblePath);
Style = SetStyle(Style, "visibility", "visible");
} else {
DeleteNode(_visiblePath);
Style = SetStyle(Style, "visibility", "hidden");
}
}
}
private const string _backgroundcolorPath = "@fillcolor";
/// <summary>
/// Background color
/// </summary>
public Color BackgroundColor {
get {
string col = GetXmlNodeString(_backgroundcolorPath);
if (col == "") {
return Color.FromArgb(0xff, 0xff, 0xe1);
}
if (col.StartsWith("#")) {
col = col.Substring(1, col.Length - 1);
}
if (int.TryParse(
col,
NumberStyles.AllowHexSpecifier,
CultureInfo.InvariantCulture,
out var res)) {
return Color.FromArgb(res);
}
return Color.Empty;
}
set {
string color = "#" + value.ToArgb().ToString("X").Substring(2, 6);
SetXmlNodeString(_backgroundcolorPath, color);
//SetXmlNode(BACKGROUNDCOLOR2_PATH, color);
}
}
private const string _linestylePath = "v:stroke/@dashstyle";
private const string _endcapPath = "v:stroke/@endcap";
/// <summary>
/// Linestyle for border
/// </summary>
public eLineStyleVml LineStyle {
get {
string v = GetXmlNodeString(_linestylePath);
if (v == "") {
return eLineStyleVml.Solid;
}
if (v == "1 1") {
v = GetXmlNodeString(_endcapPath);
return (eLineStyleVml)Enum.Parse(typeof(eLineStyleVml), v, true);
}
return (eLineStyleVml)Enum.Parse(typeof(eLineStyleVml), v, true);
}
set {
if (value == eLineStyleVml.Round || value == eLineStyleVml.Square) {
SetXmlNodeString(_linestylePath, "1 1");
if (value == eLineStyleVml.Round) {
SetXmlNodeString(_endcapPath, "round");
} else {
DeleteNode(_endcapPath);
}
} else {
string v = value.ToString();
v = v.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + v.Substring(1, v.Length - 1);
SetXmlNodeString(_linestylePath, v);
DeleteNode(_endcapPath);
}
}
}
private const string _linecolorPath = "@strokecolor";
/// <summary>
/// Line color
/// </summary>
public Color LineColor {
get {
string col = GetXmlNodeString(_linecolorPath);
if (col == "") {
return Color.Black;
}
if (col.StartsWith("#")) {
col = col.Substring(1, col.Length - 1);
}
if (int.TryParse(
col,
NumberStyles.AllowHexSpecifier,
CultureInfo.InvariantCulture,
out var res)) {
return Color.FromArgb(res);
}
return Color.Empty;
}
set {
string color = "#" + value.ToArgb().ToString("X").Substring(2, 6);
SetXmlNodeString(_linecolorPath, color);
}
}
private const string _linewidthPath = "@strokeweight";
/// <summary>
/// Width of the border
/// </summary>
public Single LineWidth {
get {
string wt = GetXmlNodeString(_linewidthPath);
if (wt == "") {
return (Single).75;
}
if (wt.EndsWith("pt")) {
wt = wt.Substring(0, wt.Length - 2);
}
if (Single.TryParse(wt, NumberStyles.Any, CultureInfo.InvariantCulture, out var ret)) {
return ret;
}
return 0;
}
set => SetXmlNodeString(_linewidthPath, value.ToString(CultureInfo.InvariantCulture) + "pt");
}
///// <summary>
///// Width of the Comment
///// </summary>
//public Single Width
//{
// get
// {
// string v;
// GetStyle("width", out v);
// if(v.EndsWith("pt"))
// {
// v = v.Substring(0, v.Length - 2);
// }
// short ret;
// if (short.TryParse(v,System.Globalization.NumberStyles.Any, CultureInfo.InvariantCulture, out ret))
// {
// return ret;
// }
// else
// {
// return 0;
// }
// }
// set
// {
// SetStyle("width", value.ToString("N2",CultureInfo.InvariantCulture) + "pt");
// }
//}
///// <summary>
///// Height of the Comment
///// </summary>
//public Single Height
//{
// get
// {
// string v;
// GetStyle("height", out v);
// if (v.EndsWith("pt"))
// {
// v = v.Substring(0, v.Length - 2);
// }
// short ret;
// if (short.TryParse(v, System.Globalization.NumberStyles.Any, CultureInfo.InvariantCulture, out ret))
// {
// return ret;
// }
// else
// {
// return 0;
// }
// }
// set
// {
// SetStyle("height", value.ToString("N2", CultureInfo.InvariantCulture) + "pt");
// }
//}
private const string _textboxStylePath = "v:textbox/@style";
/// <summary>
/// Autofits the drawingobject
/// </summary>
public bool AutoFit {
get {
GetStyle(GetXmlNodeString(_textboxStylePath), "mso-fit-shape-to-text", out var value);
return value == "t";
}
set =>
SetXmlNodeString(
_textboxStylePath,
SetStyle(GetXmlNodeString(_textboxStylePath), "mso-fit-shape-to-text", value ? "t" : ""));
}
private const string _lockedPath = "x:ClientData/x:Locked";
/// <summary>
/// If the object is locked when the sheet is protected
/// </summary>
public bool Locked {
get => GetXmlNodeBool(_lockedPath, false);
set => SetXmlNodeBool(_lockedPath, value, false);
}
private const string _lockTextPath = "x:ClientData/x:LockText";
/// <summary>
/// Specifies that the object's text is locked
/// </summary>
public bool LockText {
get => GetXmlNodeBool(_lockTextPath, false);
set => SetXmlNodeBool(_lockTextPath, value, false);
}
private ExcelVmlDrawingPosition _from;
/// <summary>
/// From position. For comments only when Visible=true.
/// </summary>
public ExcelVmlDrawingPosition From {
get {
if (_from == null) {
_from = new(
NameSpaceManager,
TopNode.SelectSingleNode("x:ClientData", NameSpaceManager),
0);
}
return _from;
}
}
private ExcelVmlDrawingPosition _to;
/// <summary>
/// To position. For comments only when Visible=true.
/// </summary>
public ExcelVmlDrawingPosition To {
get {
if (_to == null) {
_to = new(NameSpaceManager, TopNode.SelectSingleNode("x:ClientData", NameSpaceManager), 4);
}
return _to;
}
}
private const string _stylePath = "@style";
internal string Style {
get => GetXmlNodeString(_stylePath);
set => SetXmlNodeString(_stylePath, value);
}
ulong IRangeId.RangeID {
get => ExcelCellBase.GetCellId(Range.Worksheet.SheetID, Range.Start.Row, Range.Start.Column);
set {}
}
}