| /******************************************************************************* | 
 |  * 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 { return (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"; | 
 |   private const string _backgroundcolor2Path = "v:fill/@color2"; | 
 |  | 
 |   /// <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); | 
 |       } | 
 |       int res; | 
 |       if (int.TryParse( | 
 |           col, | 
 |           NumberStyles.AllowHexSpecifier, | 
 |           CultureInfo.InvariantCulture, | 
 |           out 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); | 
 |       } | 
 |       int res; | 
 |       if (int.TryParse( | 
 |           col, | 
 |           NumberStyles.AllowHexSpecifier, | 
 |           CultureInfo.InvariantCulture, | 
 |           out 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); | 
 |       } | 
 |  | 
 |       Single ret; | 
 |       if (Single.TryParse(wt, NumberStyles.Any, CultureInfo.InvariantCulture, out 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 { | 
 |       string value; | 
 |       GetStyle(GetXmlNodeString(_textboxStylePath), "mso-fit-shape-to-text", out 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 { return 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 { return 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 { return GetXmlNodeString(_stylePath); } | 
 |     set { SetXmlNodeString(_stylePath, value); } | 
 |   } | 
 |  | 
 |   ulong IRangeId.RangeID { | 
 |     get { | 
 |       return ExcelCellBase.GetCellId(Range.Worksheet.SheetID, Range.Start.Row, Range.Start.Column); | 
 |     } | 
 |     set {} | 
 |   } | 
 | } |