using System; using System.Text; using System.Drawing; using System.IO; using System.Collections; using System.Collections.Generic; using FastReport.Utils; using System.Globalization; using FastReport.Format; namespace FastReport.Export.Xml { /// /// Represents the Excel 2003 XML export filter. /// public partial class XMLExport : ExportBase { #region Constants private const int xLMaxHeight = 409; private const float xdivider = 1.376f; private const float ydivider = 1.333f; #endregion #region Private fields private bool pageBreaks; private string creator; private bool dataOnly; private bool wysiwyg; private Dictionary sheets; private ExportMatrix matrix; private XMLSheet sh; private bool splitPages; private List commonStyles; #endregion private class XMLSheet { #region Constants private const float margDiv = 25.4F; #endregion #region Private fields private bool pageBreaks; private readonly string name; #endregion internal readonly ExportMatrix matrix; public void ExportSheet(Stream stream, StringBuilder builder) { int i, x, fx, fy, dx, dy; ExportIEMObject Obj; builder.AppendLine(""); // add table builder.Append(""); for (x = 1; x < matrix.Width; x++) builder.Append(""); WriteBuf(stream, builder); for (int y = 0; y < matrix.Height - 1; y++) { builder.Append(""); for (x = 0; x < matrix.Width; x++) { i = matrix.Cell(x, y); if (i != -1) { Obj = matrix.ObjectById(i); if (Obj.Counter == 0) { builder.Append(" 1) builder.Append("ss:MergeAcross=\"").Append(Convert.ToString(dx++ - 1)).Append("\" "); if (dy > 1) builder.Append("ss:MergeDown=\"").Append(Convert.ToString(dy++ - 1)).Append("\" "); builder.Append("ss:StyleID=\"s").Append(Obj.StyleIndex.ToString()).AppendLine("\">"); decimal value = 0; bool isNumeric = ExportUtils.ParseTextToDecimal(Obj.Text, Obj.Style.Format, out value); string type = isNumeric ? "ss:Type=\"Number\"" : "ss:Type=\"String\""; string data = Obj.HtmlTags ? "ss:Data" : "Data"; string xmlns = Obj.HtmlTags ? " xmlns=\"http://www.w3.org/TR/REC-html40\"" : String.Empty; string strValue = isNumeric ? Convert.ToString(value, CultureInfo.InvariantCulture.NumberFormat) : ExportUtils.XmlString(Obj.Text, Obj.TextRenderType); builder.Append("<").Append(data).Append(" ").Append(type).Append(xmlns). Append(">").Append(strValue).Append(""); } } } else builder.Append(""); } builder.AppendLine(""); if (builder.Length > 8192) WriteBuf(stream, builder); } builder.AppendLine("
"); builder.AppendLine(""); if (matrix.PagesCount > 0) { builder.AppendLine(""); if (matrix.Landscape(0)) builder.AppendLine(""); builder.AppendLine(string.Format(CultureInfo.InvariantCulture, "", matrix.PageBMargin(0) / margDiv, matrix.PageLMargin(0) / margDiv, matrix.PageRMargin(0) / margDiv, matrix.PageTMargin(0) / margDiv)); builder.AppendLine(""); builder.AppendLine(""); builder.AppendLine(""); builder.AppendLine("" + matrix.RawPaperSize(0).ToString() + ""); builder.AppendLine(""); } builder.AppendLine(""); // add page breaks if (pageBreaks) { builder.AppendLine(""); builder.AppendLine(""); int page = 0; for (i = 0; i <= matrix.Height - 1; i++) { if (matrix.YPosById(i) >= matrix.PageBreak(page)) { builder.AppendLine(""); builder.AppendLine(string.Format("{0}", i)); builder.AppendLine(""); page++; } } builder.AppendLine(""); builder.AppendLine(""); } builder.AppendLine("
"); WriteBuf(stream, builder); } public XMLSheet(ExportMatrix matrix, string name, bool pageBreaks) { this.matrix = matrix; this.name = name; this.pageBreaks = pageBreaks; } } #region Properties /// /// Gets or sets a value that determines whether to insert page breaks in the output file or not. /// /// public bool PageBreaks { get { return pageBreaks; } set { pageBreaks = value; } } /// /// Gets or sets a value that determines whether the wysiwyg mode should be used /// for better results. /// /// /// Default value is true. In wysiwyg mode, the resulting Excel file will look /// as close as possible to the prepared report. On the other side, it may have a lot /// of small rows/columns, which will make it less editable. If you set this property /// to false, the number of rows/columns in the resulting file will be decreased. /// You will get less wysiwyg, but more editable file. /// public bool Wysiwyg { get { return wysiwyg; } set { wysiwyg = value; } } /// /// Gets or sets the name of document creator. /// public string Creator { get { return creator; } set { creator = value; } } /// /// Gets or sets a value that determines whether to export the databand rows only. /// public bool DataOnly { get { return dataOnly; } set { dataOnly = value; } } /// /// Each report page is placed on a new Excel page. /// public bool SplitPages { get { return splitPages; } set { splitPages = value; } } #endregion #region Private Methods private static void WriteBuf(Stream stream, StringBuilder buf) { // write the resulting string to a stream byte[] bytes = Encoding.UTF8.GetBytes(buf.ToString()); stream.Write(bytes, 0, bytes.Length); buf.Length = 0; } private void ExportHeader(StringBuilder builder) { builder.AppendLine(""); builder.AppendLine(""); builder.Append(""); builder.AppendLine(""); builder.Append(""); builder.AppendLine(""); builder.Append("").Append(Report.ReportInfo.Name).AppendLine(""); builder.Append("").Append(Report.ReportInfo.Author).AppendLine(""); builder.Append("").Append(SystemFake.DateTime.Now.Date.ToString()).Append("T").Append(SystemFake.DateTime.Now.TimeOfDay.ToString()).AppendLine("Z"); builder.Append("").Append(Report.ReportInfo.Version).AppendLine(""); builder.AppendLine(""); builder.AppendLine(""); builder.AppendLine("False"); builder.AppendLine("False"); builder.AppendLine(""); } private void ExportSheets(Stream stream, StringBuilder builder) { foreach (XMLSheet sheet in sheets.Values) sheet.ExportSheet(stream, builder); builder.AppendLine(""); WriteBuf(stream, builder); } private void ExportXML(Stream stream) { StringBuilder builder = new StringBuilder(8448); ExportHeader(builder); ExportStyles(builder); ExportSheets(stream, builder); } #endregion #region StyleMethods internal void ExportStyles(StringBuilder builder) { builder.AppendLine(""); ExportIEMStyle EStyle; for (int x = 0; x < commonStyles.Count; x++) { EStyle = commonStyles[x]; builder.Append(""); } builder.AppendLine(""); } private string GetXMLWeight(float lineWeight) { float LineWeight = lineWeight * xdivider; return ((int)Math.Round(LineWeight > 3 ? 3 : LineWeight)).ToString(); } private string XmlAlign(HorzAlign horzAlign, VertAlign vertAlign, int angle) { string Fh = "Left", Fv = "Top"; if (angle == 0 || angle == 180) { if (horzAlign == HorzAlign.Left) Fh = "Left"; else if (horzAlign == HorzAlign.Right) Fh = "Right"; else if (horzAlign == HorzAlign.Center) Fh = "Center"; else if (horzAlign == HorzAlign.Justify) Fh = "Justify"; if (vertAlign == VertAlign.Top) Fv = "Top"; else if (vertAlign == VertAlign.Bottom) Fv = "Bottom"; else if (vertAlign == VertAlign.Center) Fv = "Center"; } else if (angle == 90) { if (horzAlign == HorzAlign.Left) Fv = "Top"; else if (horzAlign == HorzAlign.Right) Fv = "Bottom"; else if (horzAlign == HorzAlign.Center) Fv = "Center"; if (vertAlign == VertAlign.Top) Fh = "Right"; else if (vertAlign == VertAlign.Bottom) Fh = "Left"; else if (vertAlign == VertAlign.Center) Fh = "Center"; } else { if (horzAlign == HorzAlign.Left) Fv = "Bottom"; else if (horzAlign == HorzAlign.Right) Fv = "Top"; else if (horzAlign == HorzAlign.Center) Fv = "Center"; if (vertAlign == VertAlign.Top) Fh = "Right"; else if (vertAlign == VertAlign.Bottom) Fh = "Left"; else if (vertAlign == VertAlign.Center) Fh = "Center"; } return "ss:Horizontal=\"" + Fh + "\" ss:Vertical=\"" + Fv + "\""; } private string GetXMLBorders(ExportIEMStyle style) { StringBuilder result = new StringBuilder(128); result.AppendLine(""); if ((style.Border.Lines & BorderLines.Left) > 0) result.Append(""); if ((style.Border.Lines & BorderLines.Top) > 0) result.Append(""); if ((style.Border.Lines & BorderLines.Bottom) > 0) result.AppendLine(""); if ((style.Border.Lines & BorderLines.Right) > 0) result.AppendLine(""); result.Append(""); return result.ToString(); } private string GetXMLFont(ExportIEMStyle style) { StringBuilder result = new StringBuilder(128); result.Append(" 0 ? "ss:Bold=\"1\" " : String.Empty)). Append(((style.Font.Style & FontStyle.Italic) > 0 ? "ss:Italic=\"1\" " : String.Empty)). Append(((style.Font.Style & FontStyle.Underline) > 0 ? "ss:Underline=\"Single\" " : String.Empty)). Append("/>"); return result.ToString(); } private string GetXMLInterior(ExportIEMStyle style) { if (style.FillColor.A != 0) return ""; return String.Empty; } private string GetXMLAlignment(ExportIEMStyle style) { StringBuilder result = new StringBuilder(64); result.Append(" 0 && style.Angle <= 90) ? "ss:Rotate=\"" + (-style.Angle).ToString() + "\"" : String.Empty)). Append(((style.Angle > 90 && style.Angle <= 180) ? "ss:Rotate=\"" + (180 - style.Angle).ToString() + "\"" : String.Empty)). Append(((style.Angle > 180 && style.Angle < 270) ? "ss:Rotate=\"" + (270 - style.Angle).ToString() + "\"" : String.Empty)). Append(((style.Angle >= 270 && style.Angle < 360) ? "ss:Rotate=\"" + (360 - style.Angle).ToString() + "\"" : String.Empty)). Append("/>"); return result.ToString(); } private string GetXMLLineStyle(LineStyle style) { switch (style) { case LineStyle.Dash: return "Dash"; case LineStyle.DashDot: return "DashDot"; case LineStyle.DashDotDot: return "DashDotDot"; case LineStyle.Dot: return "Dot"; case LineStyle.Double: return "Double"; default: return "Continuous"; } } private string GetXMLFormat(ExportIEMStyle style) { if (style.Format is NumberFormat || style.Format is CurrencyFormat) { return "\r\n"; } return String.Empty; } #endregion #region Protected Methods /// protected override string GetFileFilter() { return new MyRes("FileFilters").Get("XlsFile"); } /// protected override void Start() { base.Start(); sheets = new Dictionary(); commonStyles = new List(); } /// protected override void ExportPageBegin(ReportPage page) { base.ExportPageBegin(page); if (sheets.ContainsKey(page.Name) && !SplitPages) { sh = sheets[page.Name] as XMLSheet; sh.matrix.AddPageBegin(page); } else { matrix = new ExportMatrix(); if (Wysiwyg) matrix.Inaccuracy = 0.5f; else matrix.Inaccuracy = 10; matrix.RotatedAsImage = false; matrix.PlainRich = true; matrix.AreaFill = true; matrix.CropAreaFill = true; matrix.Report = Report; matrix.Images = false; matrix.DataOnly = DataOnly; matrix.ShowProgress = ShowProgress; matrix.MaxCellHeight = ydivider * xLMaxHeight; matrix.AddPageBegin(page); matrix.Styles = commonStyles; } } /// protected override void ExportBand(BandBase band) { base.ExportBand(band); if (sheets.ContainsKey(band.Page.Name) && !SplitPages) { sh = sheets[band.Page.Name]; sh.matrix.AddBand(band, this); } else { matrix.AddBand(band, this); } } /// protected override void ExportPageEnd(ReportPage page) { if (sheets.ContainsKey(page.Name) && !SplitPages) { sh = sheets[page.Name] as XMLSheet; sh.matrix.AddPageEnd(page); } else { string new_page_name = page.Name; if (SplitPages) { if (sheets.ContainsKey(page.Name + "-1")) { int repeats = 2; while (sheets.ContainsKey(page.Name + "-" + repeats.ToString())) repeats++; new_page_name += "-" + repeats.ToString(); } else if (Report.PreparedPages.GetPage(sheets.Count + 1) != null && Report.PreparedPages.GetPage(sheets.Count + 1).Name == page.Name) { new_page_name += "-1"; } } matrix.AddPageEnd(page); sh = new XMLSheet(matrix, new_page_name, pageBreaks); sheets[new_page_name] = sh; } } /// protected override void Finish() { foreach (XMLSheet sheet in sheets.Values) sheet.matrix.Prepare(); MyRes Res = new MyRes("Export,Misc"); if (ShowProgress) Config.ReportSettings.OnProgress(Report, Res.Get("SaveFile")); ExportXML(Stream); } #endregion /// public override void Serialize(FRWriter writer) { base.Serialize(writer); writer.WriteBool("Wysiwyg", Wysiwyg); writer.WriteBool("PageBreaks", PageBreaks); writer.WriteBool("DataOnly", DataOnly); writer.WriteBool("SplitPages", SplitPages); } /// /// Initializes a new instance of the class. /// public XMLExport() { pageBreaks = true; Wysiwyg = true; creator = "FastReport"; } } }