External/OxyPlot/OxyPlot/Reporting/ReportWriters/HtmlReportWriter.cs
author moel.mich
Tue, 30 Dec 2014 16:02:52 +0000
changeset 428 3c1cdc197b24
permissions -rw-r--r--
Added a new "Undefined" control mode. Changed the GPU fan control to restore to default (auto) settings when the Open Hardware Monitor closes (unless the control remained in "Undefined" mode).
     1 // --------------------------------------------------------------------------------------------------------------------
     2 // <copyright file="HtmlReportWriter.cs" company="OxyPlot">
     3 //   The MIT License (MIT)
     4 //
     5 //   Copyright (c) 2012 Oystein Bjorke
     6 //
     7 //   Permission is hereby granted, free of charge, to any person obtaining a
     8 //   copy of this software and associated documentation files (the
     9 //   "Software"), to deal in the Software without restriction, including
    10 //   without limitation the rights to use, copy, modify, merge, publish,
    11 //   distribute, sublicense, and/or sell copies of the Software, and to
    12 //   permit persons to whom the Software is furnished to do so, subject to
    13 //   the following conditions:
    14 //
    15 //   The above copyright notice and this permission notice shall be included
    16 //   in all copies or substantial portions of the Software.
    17 //
    18 //   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
    19 //   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    20 //   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    21 //   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    22 //   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    23 //   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    24 //   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    25 // </copyright>
    26 // <summary>
    27 //   Specifies the html element type to use when writing plots.
    28 // </summary>
    29 // --------------------------------------------------------------------------------------------------------------------
    30 namespace OxyPlot.Reporting
    31 {
    32     using System.Collections.Generic;
    33     using System.IO;
    34     using System.Text;
    35 
    36     /// <summary>
    37     /// Specifies the html element type to use when writing plots.
    38     /// </summary>
    39     public enum HtmlPlotElementType
    40     {
    41         /// <summary>
    42         /// Use the embed tag and reference an external svg file.
    43         /// </summary>
    44         Embed,
    45 
    46         /// <summary>
    47         /// Use the object tag and reference an external svg file.
    48         /// </summary>
    49         Object,
    50 
    51         /// <summary>
    52         /// Use the svg tag and include the plot inline.
    53         /// </summary>
    54         Svg
    55     }
    56 
    57     /// <summary>
    58     /// HTML5 report writer.
    59     /// </summary>
    60     public class HtmlReportWriter : XmlWriterBase, IReportWriter
    61     {
    62         /// <summary>
    63         /// The text measurer.
    64         /// </summary>
    65         private readonly IRenderContext textMeasurer;
    66 
    67         /// <summary>
    68         /// The figure counter.
    69         /// </summary>
    70         private int figureCounter;
    71 
    72         /// <summary>
    73         /// The style.
    74         /// </summary>
    75         private ReportStyle style;
    76 
    77         /// <summary>
    78         /// Initializes a new instance of the <see cref="HtmlReportWriter"/> class.
    79         /// </summary>
    80         /// <param name="stream">
    81         /// The stream.
    82         /// </param>
    83         /// <param name="textMeasurer">
    84         /// The text measurer.
    85         /// </param>
    86         public HtmlReportWriter(Stream stream, IRenderContext textMeasurer = null)
    87             : base(stream)
    88         {
    89             this.textMeasurer = textMeasurer;
    90             this.WriteHtmlElement();
    91             this.PlotElementType = HtmlPlotElementType.Svg;
    92         }
    93 
    94         /// <summary>
    95         /// Gets or sets the type of the plot element.
    96         /// </summary>
    97         /// <value>
    98         /// The type of the plot element.
    99         /// </value>
   100         public HtmlPlotElementType PlotElementType { get; set; }
   101 
   102         /// <summary>
   103         /// Closes this instance.
   104         /// </summary>
   105         public override void Close()
   106         {
   107             this.WriteEndElement();
   108             this.WriteEndElement();
   109             base.Close();
   110         }
   111 
   112         /// <summary>
   113         /// Writes the class ID.
   114         /// </summary>
   115         /// <param name="className">
   116         /// The class.
   117         /// </param>
   118         /// <param name="id">
   119         /// The id.
   120         /// </param>
   121         public void WriteClassId(string className, string id = null)
   122         {
   123             if (className != null)
   124             {
   125                 this.WriteAttributeString("class", className);
   126             }
   127 
   128             if (id != null)
   129             {
   130                 this.WriteAttributeString("id", id);
   131             }
   132         }
   133 
   134         /// <summary>
   135         /// Writes the drawing.
   136         /// </summary>
   137         /// <param name="d">
   138         /// The drawing.
   139         /// </param>
   140         public void WriteDrawing(DrawingFigure d)
   141         {
   142             this.WriteStartFigure();
   143             this.WriteRaw(d.Content);
   144             this.WriteEndFigure(d.FigureText);
   145         }
   146 
   147         /// <summary>
   148         /// Writes the equation.
   149         /// </summary>
   150         /// <param name="equation">
   151         /// The equation.
   152         /// </param>
   153         public void WriteEquation(Equation equation)
   154         {
   155             // todo: MathML?
   156         }
   157 
   158         /// <summary>
   159         /// Writes the header.
   160         /// </summary>
   161         /// <param name="h">
   162         /// The header.
   163         /// </param>
   164         public void WriteHeader(Header h)
   165         {
   166             if (h.Text == null)
   167             {
   168                 return;
   169             }
   170 
   171             this.WriteStartElement("h" + h.Level);
   172             this.WriteString(h.ToString());
   173             this.WriteEndElement();
   174         }
   175 
   176         /// <summary>
   177         /// Writes the image.
   178         /// </summary>
   179         /// <param name="i">
   180         /// The image.
   181         /// </param>
   182         public void WriteImage(Image i)
   183         {
   184             // this requires the image to be located in the same folder as the html
   185             string localFileName = i.Source;
   186             this.WriteStartFigure();
   187             this.WriteStartElement("img");
   188             this.WriteAttributeString("src", localFileName);
   189             this.WriteAttributeString("alt", i.FigureText);
   190             this.WriteEndElement();
   191             this.WriteEndFigure(i.FigureText);
   192         }
   193 
   194         /// <summary>
   195         /// Writes the paragraph.
   196         /// </summary>
   197         /// <param name="p">
   198         /// The paragraph.
   199         /// </param>
   200         public void WriteParagraph(Paragraph p)
   201         {
   202             this.WriteElementString("p", p.Text);
   203         }
   204 
   205         /// <summary>
   206         /// Writes the plot.
   207         /// </summary>
   208         /// <param name="plot">
   209         /// The plot.
   210         /// </param>
   211         public void WritePlot(PlotFigure plot)
   212         {
   213             this.WriteStartFigure();
   214             switch (this.PlotElementType)
   215             {
   216                 case HtmlPlotElementType.Embed:
   217                 case HtmlPlotElementType.Object:
   218                     // TODO: need a Func<string,Stream> to provide streams for the plot files?
   219 
   220                     //string source = string.Format(
   221                     //    "{0}_Plot{1}.svg", Path.GetFileNameWithoutExtension(this.outputFile), plot.FigureNumber);
   222                     //plot.PlotModel.SaveSvg(this.GetFullFileName(source), plot.Width, plot.Height, this.textMeasurer);
   223                     //this.WriteStartElement(this.PlotElementType == HtmlPlotElementType.Embed ? "embed" : "object");
   224                     //this.WriteAttributeString("src", source);
   225                     //this.WriteAttributeString("type", "image/svg+xml");
   226                     //this.WriteEndElement();
   227                     break;
   228                 case HtmlPlotElementType.Svg:
   229                     this.WriteRaw(plot.PlotModel.ToSvg(plot.Width, plot.Height, false, this.textMeasurer));
   230                     break;
   231             }
   232 
   233             this.WriteEndFigure(plot.FigureText);
   234         }
   235 
   236         /// <summary>
   237         /// The write report.
   238         /// </summary>
   239         /// <param name="report">
   240         /// The report.
   241         /// </param>
   242         /// <param name="reportStyle">
   243         /// The style.
   244         /// </param>
   245         public void WriteReport(Report report, ReportStyle reportStyle)
   246         {
   247             this.style = reportStyle;
   248             this.WriteHtmlHeader(report.Title, null, CreateCss(reportStyle));
   249             report.Write(this);
   250         }
   251 
   252         /// <summary>
   253         /// Writes the items.
   254         /// </summary>
   255         /// <param name="t">
   256         /// The table.
   257         /// </param>
   258         public void WriteRows(Table t)
   259         {
   260             IList<TableColumn> columns = t.Columns;
   261 
   262             foreach (var c in columns)
   263             {
   264                 this.WriteStartElement("col");
   265                 this.WriteAttributeString("align", GetAlignmentString(c.Alignment));
   266                 if (double.IsNaN(c.Width))
   267                 {
   268                     this.WriteAttributeString("width", c.Width + "pt");
   269                 }
   270 
   271                 this.WriteEndElement();
   272             }
   273 
   274             foreach (var row in t.Rows)
   275             {
   276                 if (row.IsHeader)
   277                 {
   278                     this.WriteStartElement("thead");
   279                 }
   280 
   281                 this.WriteStartElement("tr");
   282                 int j = 0;
   283                 foreach (var c in row.Cells)
   284                 {
   285                     bool isHeader = row.IsHeader || t.Columns[j++].IsHeader;
   286 
   287                     this.WriteStartElement("td");
   288                     if (isHeader)
   289                     {
   290                         this.WriteAttributeString("class", "header");
   291                     }
   292 
   293                     this.WriteString(c.Content);
   294                     this.WriteEndElement();
   295                 }
   296 
   297                 this.WriteEndElement(); // tr
   298                 if (row.IsHeader)
   299                 {
   300                     this.WriteEndElement(); // thead
   301                 }
   302             }
   303         }
   304 
   305         /// <summary>
   306         /// Writes the table.
   307         /// </summary>
   308         /// <param name="t">
   309         /// The t.
   310         /// </param>
   311         public void WriteTable(Table t)
   312         {
   313             if (t.Rows == null || t.Columns == null)
   314             {
   315                 return;
   316             }
   317 
   318             this.WriteStartElement("table");
   319 
   320             // WriteAttributeString("border", "1");
   321             // WriteAttributeString("width", "60%");
   322             if (t.Caption != null)
   323             {
   324                 this.WriteStartElement("caption");
   325                 this.WriteString(t.GetFullCaption(this.style));
   326                 this.WriteEndElement();
   327             }
   328 
   329             this.WriteRows(t);
   330 
   331             this.WriteEndElement(); // table
   332         }
   333 
   334         /// <summary>
   335         /// Creates the css section.
   336         /// </summary>
   337         /// <param name="style">
   338         /// The style.
   339         /// </param>
   340         /// <returns>
   341         /// The css.
   342         /// </returns>
   343         private static string CreateCss(ReportStyle style)
   344         {
   345             var css = new StringBuilder();
   346             css.AppendLine("body { " + ParagraphStyleToCss(style.BodyTextStyle) + " }");
   347             for (int i = 0; i < style.HeaderStyles.Length; i++)
   348             {
   349                 css.AppendLine("h" + (i + 1) + " {" + ParagraphStyleToCss(style.HeaderStyles[i]) + " }");
   350             }
   351 
   352             css.AppendLine("table caption { " + ParagraphStyleToCss(style.TableCaptionStyle) + " }");
   353             css.AppendLine("thead { " + ParagraphStyleToCss(style.TableHeaderStyle) + " }");
   354             css.AppendLine("td { " + ParagraphStyleToCss(style.TableTextStyle) + " }");
   355             css.AppendLine("td.header { " + ParagraphStyleToCss(style.TableHeaderStyle) + " }");
   356             css.AppendLine("figuretext { " + ParagraphStyleToCss(style.FigureTextStyle) + " }");
   357 
   358             css.Append(
   359                 @"body { margin:20pt; }
   360             table { border: solid 1px black; margin: 8pt; border-collapse:collapse; }
   361             td { padding: 0 2pt 0 2pt; border-left: solid 1px black; border-right: solid 1px black;}
   362             thead { border:solid 1px black; }
   363             .content, .content td { border: none; }
   364             .figure { margin: 8pt;}
   365             .table { margin: 8pt;}
   366             .table caption { margin: 4pt;}
   367             .table thead td { padding: 2pt;}");
   368             return css.ToString();
   369         }
   370 
   371         /// <summary>
   372         /// Gets the alignment string.
   373         /// </summary>
   374         /// <param name="a">
   375         /// The alignment type.
   376         /// </param>
   377         /// <returns>
   378         /// An alignment string.
   379         /// </returns>
   380         private static string GetAlignmentString(Alignment a)
   381         {
   382             return a.ToString().ToLower();
   383         }
   384 
   385         /// <summary>
   386         /// Converts a paragraphes style to css.
   387         /// </summary>
   388         /// <param name="s">
   389         /// The style.
   390         /// </param>
   391         /// <returns>
   392         /// A css string.
   393         /// </returns>
   394         private static string ParagraphStyleToCss(ParagraphStyle s)
   395         {
   396             var css = new StringBuilder();
   397             if (s.FontFamily != null)
   398             {
   399                 css.Append(string.Format("font-family:{0};", s.FontFamily));
   400             }
   401 
   402             css.Append(string.Format("font-size:{0}pt;", s.FontSize));
   403             if (s.Bold)
   404             {
   405                 css.Append(string.Format("font-weight:bold;"));
   406             }
   407 
   408             return css.ToString();
   409         }
   410 
   411         /// <summary>
   412         /// Initializes this instance.
   413         /// </summary>
   414         private void WriteHtmlElement()
   415         {
   416             this.WriteStartElement("html", "http://www.w3.org/1999/xhtml");
   417         }
   418 
   419         /// <summary>
   420         /// Writes the div.
   421         /// </summary>
   422         /// <param name="divstyle">
   423         /// The style of the div.
   424         /// </param>
   425         /// <param name="content">
   426         /// The content.
   427         /// </param>
   428         private void WriteDiv(string divstyle, string content)
   429         {
   430             this.WriteStartElement("div");
   431             this.WriteAttributeString("class", divstyle);
   432             this.WriteString(content);
   433             this.WriteEndElement();
   434         }
   435 
   436         /// <summary>
   437         /// Writes the end figure.
   438         /// </summary>
   439         /// <param name="text">
   440         /// The figure text.
   441         /// </param>
   442         private void WriteEndFigure(string text)
   443         {
   444             this.WriteDiv("figuretext", string.Format("Fig {0}. {1}", this.figureCounter, text));
   445             this.WriteEndElement();
   446         }
   447 
   448         /// <summary>
   449         /// Writes the HTML header.
   450         /// </summary>
   451         /// <param name="title">
   452         /// The title.
   453         /// </param>
   454         /// <param name="cssPath">
   455         /// The CSS path.
   456         /// </param>
   457         /// <param name="cssStyle">
   458         /// The style.
   459         /// </param>
   460         private void WriteHtmlHeader(string title, string cssPath, string cssStyle)
   461         {
   462             this.WriteStartElement("head");
   463 
   464             if (title != null)
   465             {
   466                 this.WriteElementString("title", title);
   467             }
   468 
   469             if (cssPath != null)
   470             {
   471                 this.WriteStartElement("link");
   472                 this.WriteAttributeString("href", cssPath);
   473                 this.WriteAttributeString("rel", "stylesheet");
   474                 this.WriteAttributeString("type", "text/css");
   475                 this.WriteEndElement(); // link
   476             }
   477 
   478             if (cssStyle != null)
   479             {
   480                 this.WriteStartElement("style");
   481                 this.WriteAttributeString("type", "text/css");
   482                 this.WriteRaw(cssStyle);
   483                 this.WriteEndElement();
   484             }
   485 
   486             this.WriteEndElement(); // head
   487             this.WriteStartElement("body");
   488         }
   489 
   490         /// <summary>
   491         /// Writes the start figure element.
   492         /// </summary>
   493         private void WriteStartFigure()
   494         {
   495             this.figureCounter++;
   496             this.WriteStartElement("p");
   497             this.WriteClassId("figure");
   498         }
   499 
   500     }
   501 }