using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using FastReport.Utils; using FastReport.Preview; using System.Drawing; namespace FastReport.Export { /// /// The base class for all export filters. /// public partial class ExportBase : Base { private PageRange pageRange; private string pageNumbers; private int curPage; private Stream stream; private string fileName; private List pages; private bool openAfter; private bool allowOpenAfter; private float zoom; private List generatedFiles; private bool allowSaveSettings; private bool showProgress; private int exportTickCount; private bool hasMultipleFiles; private bool shiftNonExportable; private string saveInitialDirectory; private List generatedStreams; private bool exportTabs; protected bool webPreview; #region Properties /// /// Gets list of generated streams. /// public List GeneratedStreams { get { return generatedStreams; } protected set { generatedStreams = value; } } /// /// Zoom factor for output file /// public float Zoom { get { return zoom; } set { zoom = value; } } /// /// File filter that can be used in the "Save file" dialog. /// public string FileFilter { get { return GetFileFilter(); } } /// /// Range of pages to export. /// public PageRange PageRange { get { return pageRange; } set { pageRange = value; } } /// /// Page numbers to export. /// /// /// Use page numbers separated by comma and/or page ranges, for example: "1,3-5,12". Empty string means /// that all pages need to be exported. /// public string PageNumbers { get { return pageNumbers; } set { pageNumbers = value; } } /// /// Current page number. /// /// /// Page number need to be exported if user selects "Current page" radiobutton in the export options dialog. /// This property is typically set to current page number in the preview window. /// public int CurPage { get { return curPage; } set { curPage = value; } } /// /// Open the document after export. /// public bool OpenAfterExport { get { return openAfter; } set { openAfter = value; } } /// /// Allows or disables the OpenAfterExport feature. /// public bool AllowOpenAfter { get { return allowOpenAfter; } set { allowOpenAfter = value; } } /// /// Gets or sets a value that determines whether to show progress window during export or not. /// public bool ShowProgress { get { return showProgress; } set { showProgress = value; } } /// /// Gets a list of files generated by this export. /// public List GeneratedFiles { get { return generatedFiles; } } /// /// Gets a value indicating that the export may produce multiple output files. /// public bool HasMultipleFiles { get { return hasMultipleFiles; } set { hasMultipleFiles = value; } } /// /// Gets or sets a value indicating that the report bands should be shifted, if page /// has any non-exportable bands /// public bool ShiftNonExportable { get { return shiftNonExportable; } set { shiftNonExportable = value; } } /// /// Gets or sets the initial directory that is displayed by a save file dialog. /// public string SaveInitialDirectory { get { return saveInitialDirectory; } set { saveInitialDirectory = value; } } /// /// Gets or sets a value indicating that pages will exporting from all open tabs. /// public bool ExportAllTabs { get { return exportTabs; } set { exportTabs = value; } } /// /// Stream to export to. /// protected Stream Stream { get { return stream; } } /// /// File name to export to. /// protected string FileName { get { return fileName; } } /// /// Array of page numbers to export. /// protected int[] Pages { get { return pages.ToArray(); } } internal bool AllowSaveSettings { get { return allowSaveSettings; } set { allowSaveSettings = value; } } #endregion #region Private Methods private bool Parse(string pageNumbers, int total) { pages.Clear(); string s = pageNumbers.Replace(" ", ""); if (s == "") return false; if (s[s.Length - 1] == '-') s += total.ToString(); s += ','; int i = 0; int j = 0; int n1 = 0; int n2 = 0; bool isRange = false; while (i < s.Length) { if (s[i] == ',') { n2 = int.Parse(s.Substring(j, i - j)); j = i + 1; if (isRange) { while (n1 <= n2) { pages.Add(n1 - 1); n1++; } } else pages.Add(n2 - 1); isRange = false; } else if (s[i] == '-') { isRange = true; n1 = int.Parse(s.Substring(j, i - j)); j = i + 1; } i++; } return true; } private void PreparePageNumbers() { pages.Clear(); int total = Report.PreparedPages.Count; if (PageRange == PageRange.Current) pages.Add(CurPage - 1); else if (!Parse(PageNumbers, total)) { for (int i = 0; i < total; i++) pages.Add(i); } // remove invalid page numbers for (int i = 0; i < pages.Count; i++) { if (pages[i] < 0 || pages[i] >= total) { pages.RemoveAt(i); i--; } } } private void OpenFile() { try { Process proc = new Process(); proc.EnableRaisingEvents = false; #if NETCOREAPP proc.StartInfo.FileName = "cmd"; proc.StartInfo.Arguments = $"/c \"{fileName}\""; proc.StartInfo.CreateNoWindow = true; #else proc.StartInfo = new ProcessStartInfo(fileName) { UseShellExecute = true }; #endif proc.Start(); } catch { } } private void SaveSettings() { XmlItem root = Config.Root.FindItem("Preview").FindItem("Exports").FindItem(ClassName); using (FRWriter writer = new FRWriter(root)) { root.Clear(); writer.Write(this); } } private void RestoreSettings() { XmlItem root = Config.Root.FindItem("Preview").FindItem("Exports").FindItem(ClassName); using (FRReader reader = new FRReader(null, root)) { reader.Read(this); } } #endregion #region Protected Methods /// /// Returns a file filter for a save dialog. /// /// String that contains a file filter, for example: "Bitmap image (*.bmp)|*.bmp" protected virtual string GetFileFilter() { return ""; } /// /// This method is called when the export starts. /// protected virtual void Start() { this.Report.OnExportParameters(new ExportParametersEventArgs(this)); } /// /// This method is called at the start of exports of each page. /// /// Page for export may be empty in this method. protected virtual void ExportPageBegin(ReportPage page) { page = GetOverlayPage(page); } /// /// This method is called at the end of exports of each page. /// /// Page for export may be empty in this method. protected virtual void ExportPageEnd(ReportPage page) { } /// /// This method is called for each band on exported page. /// /// Band, dispose after method compite. protected virtual void ExportBand(BandBase band) { band.UpdateWidth(); } /// /// This method is called when the export is finished. /// protected virtual void Finish() { } /// /// Gets a report page with specified index. /// /// Zero-based index of page. /// The prepared report page. protected ReportPage GetPage(int index) { ReportPage page = Report.PreparedPages.GetPage(index); return GetOverlayPage(page); } #endregion #region Public Methods /// public override void Assign(Base source) { BaseAssign(source); } /// public override void Serialize(FRWriter writer) { writer.WriteValue("PageRange", PageRange); writer.WriteStr("PageNumbers", PageNumbers); writer.WriteBool("OpenAfterExport", OpenAfterExport); writer.WriteBool("ExportAllTabs", ExportAllTabs); } /// /// Exports the report to a stream. /// /// Report to export. /// Stream to export to. /// /// This method does not show an export options dialog. If you want to show it, call /// method prior to calling this method, or use the "Export(Report report)" method instead. /// public void Export(Report report, Stream stream) { if (report == null || report.PreparedPages == null) return; SetReport(report); this.stream = stream; PreparePageNumbers(); GeneratedFiles.Clear(); exportTickCount = Environment.TickCount; if (pages.Count > 0) { if (!String.IsNullOrEmpty(FileName)) GeneratedFiles.Add(FileName); Start(); report.SetOperation(ReportOperation.Exporting); if (ShowProgress) Config.ReportSettings.OnStartProgress(Report); else Report.SetAborted(false); try { for (int i = 0; i < GetPagesCount(pages); i++) { if (ShowProgress) { Config.ReportSettings.OnProgress(Report, String.Format(Res.Get("Messages,ExportingPage"), i + 1, pages.Count), i + 1, pages.Count); } if (!Report.Aborted && i < pages.Count) ExportPageNew(pages[i]); else break; } } finally { Finish(); if (ShowProgress) Config.ReportSettings.OnProgress(Report, String.Empty); if (ShowProgress) Config.ReportSettings.OnFinishProgress(Report); report.SetOperation(ReportOperation.None); exportTickCount = Environment.TickCount - exportTickCount; ShowPerformance(exportTickCount); if (openAfter && AllowOpenAfter && stream != null) { stream.Close(); OpenFile(); } } } } public void InstantExportStart(Report report, Stream stream) { SetReport(report); this.stream = stream; GeneratedFiles.Clear(); if (!String.IsNullOrEmpty(FileName)) GeneratedFiles.Add(FileName); Start(); } public void InstantExportBeginPage(ReportPage page) { ExportPageBegin(page); } public void InstantExportExportBand(BandBase band) { ExportBand(band); } public void InstantExportEndPage(ReportPage page) { ExportPageEnd(page); } public void InstantExportFinish() { Finish(); } internal void ExportPageNew(int pageNo) { PreparedPage ppage = Report.PreparedPages.GetPreparedPage(pageNo); { ReportPage page = null; try { page = ppage.StartGetPage(pageNo); page.Width = ppage.PageSize.Width; page.Height = ppage.PageSize.Height; ExportPageBegin(page); float topShift = 0; foreach (Base obj in ppage.GetPageItems(page, false)) { BandBase band = obj as BandBase; if (shiftNonExportable && topShift != 0 && obj is BandBase && !(obj is PageFooterBand) && !band.PrintOnBottom) { band.Top -= topShift; } if (band.Exportable || webPreview) ExportBand(band); else if (obj != null) { if (shiftNonExportable) topShift += band.Height; obj.Dispose(); } } ExportPageEnd(page); } finally { ppage.EndGetPage(page); } if(page != null) page.Dispose(); } } /// /// Exports the report to a file. /// /// Report to export. /// File name to export to. /// /// This method does not show an export options dialog. If you want to show it, call /// method prior to calling this method, or use the "Export(Report report)" method instead. /// public void Export(Report report, string fileName) { this.fileName = fileName; using (FileStream stream = new FileStream(fileName, FileMode.Create)) { Export(report, stream); stream.Close(); } } internal string GetFileName(Report report) { return Path.GetFileNameWithoutExtension(Path.GetFileName(report.FileName)); } internal string GetFileExtension() { string extension = FileFilter; return extension.Substring(extension.LastIndexOf('.')); } internal void ExportAndZip(Report report, Stream stream) { string tempFolder = Config.GetTempFolder() + Path.GetRandomFileName(); Directory.CreateDirectory(tempFolder); try { string filePath = Path.Combine(tempFolder, GetFileName(report) + GetFileExtension()); Export(report, filePath); ZipArchive zip = new ZipArchive(); zip.AddDir(tempFolder); zip.SaveToStream(stream); } finally { Directory.Delete(tempFolder, true); } } #endregion /// /// Initializes a new instance of the class. /// public ExportBase() { pageNumbers = ""; pages = new List(); curPage = 1; fileName = ""; allowOpenAfter = true; zoom = 1; generatedFiles = new List(); exportTabs = false; shiftNonExportable = false; } } }