/******************************************************************************* * 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 OfficeOpenXml.Style.XmlAccess; using OfficeOpenXml.Drawing; using OfficeOpenXml.Style; /// <summary> /// Shape style /// </summary> public enum eShapeStyle { AccentBorderCallout1, AccentBorderCallout2, AccentBorderCallout3, AccentCallout1, AccentCallout2, AccentCallout3, ActionButtonBackPrevious, ActionButtonBeginning, ActionButtonBlank, ActionButtonDocument, ActionButtonEnd, ActionButtonForwardNext, ActionButtonHelp, ActionButtonHome, ActionButtonInformation, ActionButtonMovie, ActionButtonReturn, ActionButtonSound, Arc, BentArrow, BentConnector2, BentConnector3, BentConnector4, BentConnector5, BentUpArrow, Bevel, BlockArc, BorderCallout1, BorderCallout2, BorderCallout3, BracePair, BracketPair, Callout1, Callout2, Callout3, Can, ChartPlus, ChartStar, ChartX, Chevron, Chord, CircularArrow, Cloud, CloudCallout, Corner, CornerTabs, Cube, CurvedConnector2, CurvedConnector3, CurvedConnector4, CurvedConnector5, CurvedDownArrow, CurvedLeftArrow, CurvedRightArrow, CurvedUpArrow, Decagon, DiagStripe, Diamond, Dodecagon, Donut, DoubleWave, DownArrow, DownArrowCallout, Ellipse, EllipseRibbon, EllipseRibbon2, FlowChartAlternateProcess, FlowChartCollate, FlowChartConnector, FlowChartDecision, FlowChartDelay, FlowChartDisplay, FlowChartDocument, FlowChartExtract, FlowChartInputOutput, FlowChartInternalStorage, FlowChartMagneticDisk, FlowChartMagneticDrum, FlowChartMagneticTape, FlowChartManualInput, FlowChartManualOperation, FlowChartMerge, FlowChartMultidocument, FlowChartOfflineStorage, FlowChartOffpageConnector, FlowChartOnlineStorage, FlowChartOr, FlowChartPredefinedProcess, FlowChartPreparation, FlowChartProcess, FlowChartPunchedCard, FlowChartPunchedTape, FlowChartSort, FlowChartSummingJunction, FlowChartTerminator, FoldedCorner, Frame, Funnel, Gear6, Gear9, HalfFrame, Heart, Heptagon, Hexagon, HomePlate, HorizontalScroll, IrregularSeal1, IrregularSeal2, LeftArrow, LeftArrowCallout, LeftBrace, LeftBracket, LeftCircularArrow, LeftRightArrow, LeftRightArrowCallout, LeftRightCircularArrow, LeftRightRibbon, LeftRightUpArrow, LeftUpArrow, LightningBolt, Line, LineInv, MathDivide, MathEqual, MathMinus, MathMultiply, MathNotEqual, MathPlus, Moon, NonIsoscelesTrapezoid, NoSmoking, NotchedRightArrow, Octagon, Parallelogram, Pentagon, Pie, PieWedge, Plaque, PlaqueTabs, Plus, QuadArrow, QuadArrowCallout, Rect, Ribbon, Ribbon2, RightArrow, RightArrowCallout, RightBrace, RightBracket, Round1Rect, Round2DiagRect, Round2SameRect, RoundRect, RtTriangle, SmileyFace, Snip1Rect, Snip2DiagRect, Snip2SameRect, SnipRoundRect, SquareTabs, Star10, Star12, Star16, Star24, Star32, Star4, Star5, Star6, Star7, Star8, StraightConnector1, StripedRightArrow, Sun, SwooshArrow, Teardrop, Trapezoid, Triangle, UpArrow, UpArrowCallout, UpDownArrow, UpDownArrowCallout, UturnArrow, Wave, WedgeEllipseCallout, WedgeRectCallout, WedgeRoundRectCallout, VerticalScroll } /// <summary> /// Text alignment /// </summary> public enum eTextAlignment { Left, Center, Right, Distributed, Justified, JustifiedLow, ThaiDistributed } /// <summary> /// Fillstyle. /// </summary> public enum eFillStyle { NoFill, SolidFill, GradientFill, PatternFill, BlipFill, GroupFill } namespace OfficeOpenXml.Drawing { /// <summary> /// An Excel shape. /// </summary> public sealed class ExcelShape : ExcelDrawing { internal ExcelShape(ExcelDrawings drawings, XmlNode node) : base(drawings, node, "xdr:sp/xdr:nvSpPr/xdr:cNvPr/@name") { init(); } internal ExcelShape(ExcelDrawings drawings, XmlNode node, eShapeStyle style) : base(drawings, node, "xdr:sp/xdr:nvSpPr/xdr:cNvPr/@name") { init(); XmlElement shapeNode = node.OwnerDocument.CreateElement("xdr", "sp", ExcelPackage.schemaSheetDrawings); shapeNode.SetAttribute("macro", ""); shapeNode.SetAttribute("textlink", ""); node.AppendChild(shapeNode); shapeNode.InnerXml = ShapeStartXml(); node.AppendChild(shapeNode.OwnerDocument.CreateElement("xdr", "clientData", ExcelPackage.schemaSheetDrawings)); } private void init() { SchemaNodeOrder = new string[] { "prstGeom", "ln", "pPr", "defRPr", "solidFill", "uFill", "latin", "cs", "r", "rPr", "t" }; } #region "public methods" const string ShapeStylePath = "xdr:sp/xdr:spPr/a:prstGeom/@prst"; /// <summary> /// Shape style /// </summary> public eShapeStyle Style { get { string v = GetXmlNodeString(ShapeStylePath); try { return (eShapeStyle)Enum.Parse(typeof(eShapeStyle), v, true); } catch { throw (new Exception(string.Format("Invalid shapetype {0}", v))); } } set { string v = value.ToString(); v = v.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + v.Substring(1, v.Length - 1); SetXmlNodeString(ShapeStylePath, v); } } ExcelDrawingFill _fill = null; /// <summary> /// Fill /// </summary> public ExcelDrawingFill Fill { get { if (_fill == null) { _fill = new ExcelDrawingFill(NameSpaceManager, TopNode, "xdr:sp/xdr:spPr"); } return _fill; } } ExcelDrawingBorder _border = null; /// <summary> /// Border /// </summary> public ExcelDrawingBorder Border { get { if (_border == null) { _border = new ExcelDrawingBorder(NameSpaceManager, TopNode, "xdr:sp/xdr:spPr/a:ln"); } return _border; } } string[] paragraphNodeOrder = new string[] { "pPr", "defRPr", "solidFill", "uFill", "latin", "cs", "r", "rPr", "t" }; const string PARAGRAPH_PATH = "xdr:sp/xdr:txBody/a:p"; ExcelTextFont _font=null; public ExcelTextFont Font { get { if (_font == null) { XmlNode node = TopNode.SelectSingleNode(PARAGRAPH_PATH, NameSpaceManager); if(node==null) { Text=""; //Creates the node p element node = TopNode.SelectSingleNode(PARAGRAPH_PATH, NameSpaceManager); } _font = new ExcelTextFont(NameSpaceManager, TopNode, "xdr:sp/xdr:txBody/a:p/a:pPr/a:defRPr", paragraphNodeOrder); } return _font; } } const string TextPath = "xdr:sp/xdr:txBody/a:p/a:r/a:t"; /// <summary> /// Text inside the shape /// </summary> public string Text { get { return GetXmlNodeString(TextPath); } set { SetXmlNodeString(TextPath, value); } } string lockTextPath = "xdr:sp/@fLocksText"; /// <summary> /// Lock drawing /// </summary> public bool LockText { get { return GetXmlNodeBool(lockTextPath, true); } set { SetXmlNodeBool(lockTextPath, value); } } ExcelParagraphCollection _richText = null; /// <summary> /// Richtext collection. Used to format specific parts of the text /// </summary> public ExcelParagraphCollection RichText { get { if (_richText == null) { //XmlNode node=TopNode.SelectSingleNode(PARAGRAPH_PATH, NameSpaceManager); //if (node == null) //{ // CreateNode(PARAGRAPH_PATH); //} _richText = new ExcelParagraphCollection(NameSpaceManager, TopNode, PARAGRAPH_PATH, paragraphNodeOrder); } return _richText; } } const string TextAnchoringPath = "xdr:sp/xdr:txBody/a:bodyPr/@anchor"; /// <summary> /// Text Anchoring /// </summary> public eTextAnchoringType TextAnchoring { get { return GetTextAchoringEnum(GetXmlNodeString(TextAnchoringPath)); } set { SetXmlNodeString(TextAnchoringPath, GetTextAchoringText(value)); } } const string TextAnchoringCtlPath = "xdr:sp/xdr:txBody/a:bodyPr/@anchorCtr"; /// <summary> /// Specifies the centering of the text box. /// </summary> public bool TextAnchoringControl { get { return GetXmlNodeBool(TextAnchoringCtlPath); } set { if (value) { SetXmlNodeString(TextAnchoringCtlPath, "1"); } else { SetXmlNodeString(TextAnchoringCtlPath, "0"); } } } const string TEXT_ALIGN_PATH = "xdr:sp/xdr:txBody/a:p/a:pPr/@algn"; /// <summary> /// How the text is aligned /// </summary> public eTextAlignment TextAlignment { get { switch(GetXmlNodeString(TEXT_ALIGN_PATH)) { case "ctr": return eTextAlignment.Center; case "r": return eTextAlignment.Right; case "dist": return eTextAlignment.Distributed; case "just": return eTextAlignment.Justified; case "justLow": return eTextAlignment.JustifiedLow; case "thaiDist": return eTextAlignment.ThaiDistributed; default: return eTextAlignment.Left; } } set { switch (value) { case eTextAlignment.Right: SetXmlNodeString(TEXT_ALIGN_PATH, "r"); break; case eTextAlignment.Center: SetXmlNodeString(TEXT_ALIGN_PATH, "ctr"); break; case eTextAlignment.Distributed: SetXmlNodeString(TEXT_ALIGN_PATH, "dist"); break; case eTextAlignment.Justified: SetXmlNodeString(TEXT_ALIGN_PATH, "just"); break; case eTextAlignment.JustifiedLow: SetXmlNodeString(TEXT_ALIGN_PATH, "justLow"); break; case eTextAlignment.ThaiDistributed: SetXmlNodeString(TEXT_ALIGN_PATH, "thaiDist"); break; default: DeleteNode(TEXT_ALIGN_PATH); break; } } } const string INDENT_ALIGN_PATH = "xdr:sp/xdr:txBody/a:p/a:pPr/@lvl"; /// <summary> /// Indentation /// </summary> public int Indent { get { return GetXmlNodeInt(INDENT_ALIGN_PATH); } set { if (value < 0 || value > 8) { throw(new ArgumentOutOfRangeException("Indent level must be between 0 and 8")); } SetXmlNodeString(INDENT_ALIGN_PATH, value.ToString()); } } const string TextVerticalPath = "xdr:sp/xdr:txBody/a:bodyPr/@vert"; /// <summary> /// Vertical text /// </summary> public eTextVerticalType TextVertical { get { return GetTextVerticalEnum(GetXmlNodeString(TextVerticalPath)); } set { SetXmlNodeString(TextVerticalPath, GetTextVerticalText(value)); } } #endregion #region "Private Methods" private string ShapeStartXml() { StringBuilder xml = new StringBuilder(); xml.AppendFormat("<xdr:nvSpPr><xdr:cNvPr id=\"{0}\" name=\"{1}\" /><xdr:cNvSpPr /></xdr:nvSpPr><xdr:spPr><a:prstGeom prst=\"rect\"><a:avLst /></a:prstGeom></xdr:spPr><xdr:style><a:lnRef idx=\"2\"><a:schemeClr val=\"accent1\"><a:shade val=\"50000\" /></a:schemeClr></a:lnRef><a:fillRef idx=\"1\"><a:schemeClr val=\"accent1\" /></a:fillRef><a:effectRef idx=\"0\"><a:schemeClr val=\"accent1\" /></a:effectRef><a:fontRef idx=\"minor\"><a:schemeClr val=\"lt1\" /></a:fontRef></xdr:style><xdr:txBody><a:bodyPr vertOverflow=\"clip\" rtlCol=\"0\" anchor=\"ctr\" /><a:lstStyle /><a:p></a:p></xdr:txBody>", _id, Name); return xml.ToString(); } #endregion internal new string Id { get { return Name + Text; } } } }