using FastReport.Cloud.StorageClient; using FastReport.Cloud.StorageClient.Dropbox; using FastReport.Cloud.StorageClient.FastCloud; using FastReport.Cloud.StorageClient.Ftp; using FastReport.Cloud.StorageClient.S3; using FastReport.Controls; using FastReport.Design; using FastReport.Export; using FastReport.Messaging; using FastReport.Utils; using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Design; using System.IO; using System.Windows.Forms; #if !AVALONIA using FastReport.Cloud.StorageClient.Box; using FastReport.Cloud.StorageClient.GoogleDrive; using FastReport.Cloud.StorageClient.SkyDrive; using Box = FastReport.Cloud.StorageClient.Box; using GoogleDrive = FastReport.Cloud.StorageClient.GoogleDrive; using SkyDrive = FastReport.Cloud.StorageClient.SkyDrive; #endif #if !DEBUG using FastReport.Forms; #endif namespace FastReport.Preview { /// /// Represents a Windows Forms control used to preview a report. /// /// /// To use this control, place it on a form and link it to a report using the report's /// property. To show a report, call /// the Report.Show method: /// /// report1.Preview = previewControl1; /// report1.Show(); /// /// Use this control's methods such as , etc. to /// handle the preview. Call method to clear the preview. /// You can specify whether the standard toolbar is visible in the /// property. The property allows you to hide/show the statusbar. /// /// [ToolboxItem(true), ToolboxBitmap(typeof(Report), "Resources.PreviewControl.bmp")] public partial class PreviewControl : UserControl { #region Fields private Report report; private List documents; private bool toolbarVisible; private bool statusbarVisible; private Color pageBorderColor; private Color activePageBorderColor; private PreviewButtons buttons; private PreviewExports exports; private PreviewClouds clouds; private float defaultZoom; private bool locked; private PreviewTab currentPreview; private bool fastScrolling; private Timer uploadTimer; private UIStyle uiStyle; private bool useBackColor; private FRTabControl tabControl; private Point pageOffset; private string saveInitialDirectory; private ToolStripZoomControl zoomControl; private bool updatingZoom; #endregion #region Properties /// /// Occurs when current page number is changed. /// public event EventHandler PageChanged; /// /// Occurs when UIStyle property is changed. /// public event EventHandler UIStyleChanged; /// /// Gets a reference to the report. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public Report Report { get { return report; } } /// /// Obsolete. Gets or sets the color of page border. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [EditorBrowsable(EditorBrowsableState.Never)] public Color PageBorderColor { get { return pageBorderColor; } set { pageBorderColor = value; } } /// /// Gets or sets the color of active page border. /// [DefaultValue(typeof(Color), "255, 199, 60")] public Color ActivePageBorderColor { get { return activePageBorderColor; } set { activePageBorderColor = value; } } /// /// Gets or sets the first page offset from the top left corner of the control. /// public Point PageOffset { get { return pageOffset; } set { pageOffset = value; } } /// /// Gets or sets a value indicating whether the toolbar is visible. /// [DefaultValue(true)] public bool ToolbarVisible { get { return toolbarVisible; } set { toolbarVisible = value; toolStrip.Visible = value; } } /// /// Gets or sets a value indicating whether the statusbar is visible. /// [DefaultValue(true)] public bool StatusbarVisible { get { return statusbarVisible; } set { statusbarVisible = value; statusStrip.Visible = value; } } /// /// Gets or sets a value indicating whether the outline control is visible. /// [DefaultValue(false)] public bool OutlineVisible { get { return outlineControl.Visible; } set { splitContainer1.Panel1Collapsed = !value; outlineControl.Visible = value; btnOutline.Checked = value; } } /// /// Specifies the set of buttons available in the toolbar. /// [DefaultValue(PreviewButtons.All)] public PreviewButtons Buttons { get { return buttons; } set { buttons = value; UpdateButtons(); } } /// /// Specifies the set of exports that will be available in the preview's "save" menu. /// [DefaultValue(PreviewExports.All)] public PreviewExports Exports { get { return exports; } set { exports = value; UpdateButtons(); } } /// /// Specifies the set of exports in clouds that will be available in the preview's "save" menu. /// [DefaultValue(PreviewClouds.All)] public PreviewClouds Clouds { get { return clouds; } set { clouds = value; UpdateButtons(); } } /// /// Gets or sets a value indicating whether the fast scrolling method should be used. /// /// /// If you enable this property, the gradient background will be disabled. /// [DefaultValue(false)] public bool FastScrolling { get { return fastScrolling; } set { fastScrolling = value; } } /// /// Gets or sets the visual style. /// public UIStyle UIStyle { get { return uiStyle; } set { uiStyle = value; UpdateUIStyle(); UIStyleChanged?.Invoke(this, EventArgs.Empty); } } /// /// Gets or sets a value indicating that the BackColor property must be used to draw the background area. /// /// /// By default, the background area is drawn using the color defined in the current UIStyle. /// [DefaultValue(false)] public bool UseBackColor { get { return useBackColor; } set { useBackColor = value; UpdateUIStyle(); } } /// /// Gets the preview window's toolbar. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public ToolStrip ToolBar { get { return toolStrip; } } /// /// Gets the preview window's statusbar. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public StatusStrip StatusBar { get { return statusStrip; } } /// /// Gets or sets the initial directory that is displayed by a save file dialog. /// public string SaveInitialDirectory { get { return saveInitialDirectory; } set { saveInitialDirectory = value; } } internal float DefaultZoom { get { return defaultZoom; } } internal PreviewTab CurrentPreview { get { return currentPreview; } } private bool IsPreviewEmpty { get { return CurrentPreview == null || CurrentPreview.Disabled; } } #endregion #region Private Methods private void CreateOpenList() { var openLocal = new ToolStripMenuItem(Res.Get("Preview,OpenLocal")); openLocal.Image = this.GetImage(1); openLocal.Font = DrawUtils.DefaultFont; openLocal.Click += btnOpenLocal_Click; var openViaCloud = new ToolStripMenuItem(Res.Get("Preview,OpenViaCloud")); openViaCloud.Image = this.GetImage(261); openViaCloud.Font = DrawUtils.DefaultFont; openViaCloud.Click += btnOpenViaCloud_Click; btnOpen.DropDownItems.Clear(); btnOpen.DropDownItems.AddRange(new ToolStripItem[] { openLocal, openViaCloud }); } private void CreateSaveList() { var saveLocal = new ToolStripMenuItem(Res.Get("Preview,SaveLocal")); saveLocal.Font = DrawUtils.DefaultFont; saveLocal.Click += btnSaveLocal_Click; var saveToCloud = new ToolStripMenuItem(Res.Get("Preview,SaveToCloud")); saveToCloud.Image = this.GetImage(262); saveToCloud.Font = DrawUtils.DefaultFont; saveToCloud.Click += btnSaveToCloud_Click; var savePrepared = new ToolStripMenuItem(Res.Get("Preview,SaveNative")); savePrepared.Font = DrawUtils.DefaultFont; savePrepared.DropDownItems.AddRange(new ToolStripItem[] { saveLocal, saveToCloud }); btnSave.DropDownItems.Clear(); btnSave.DropDownItems.Add(savePrepared); CreateExportList(btnSave, Export_Click); CreateCloudList(btnSave, SaveToCloud_Click); //CreateMessengersList(btnSave, SendViaMessenger_Click); } private void CreateItems(ExportsOptions.ExportsTreeNode root, ToolStripDropDownItem button, EventHandler handler) { foreach (var node in root.Nodes) { if (node.IsCategory) { var categoryItem = createButtonItem(node); CreateItems(node, categoryItem, handler); if (categoryItem.DropDownItems.Count > 0) button.DropDownItems.Add(categoryItem); } else if (node.ExportType != null) { bool enabled = node.Enabled; if (node.IsExport) { if (Enum.TryParse(node.Tag.Object.Name, out var res)) enabled = (Exports & res) != 0; } else if (node.IsCloud) { if (Enum.TryParse(node.Name, out var res)) enabled = (Clouds & res) != 0; } /*else if (node.IsMessenger) { if (Enum.TryParse(node.Name, out var res)) enabled = (Messengers & res) != 0; }*/ if (enabled) { var item = createButtonItem(node); item.Click += handler; button.DropDownItems.Add(item); } } } } private ToolStripMenuItem createButtonItem(ExportsOptions.ExportsTreeNode node) { var item = new ToolStripMenuItem(node.ToString() + (node.IsCategory ? "" : "...")); item.Tag = node.Tag; item.Name = node.Name; item.Image = node.Image ?? this.GetImage(node.ImageIndex); item.Font = DrawUtils.DefaultFont; return item; } private void CreateExportList(ToolStripDropDownItem button, EventHandler handler) { var options = ExportsOptions.GetInstance(); CreateItems(options.ExportsMenu, button, handler); } private void CreateCloudList(ToolStripDropDownItem button, EventHandler handler) { var options = ExportsOptions.GetInstance(); var categoryItem = createButtonItem(options.CloudMenu); CreateItems(options.CloudMenu, categoryItem, handler); if (categoryItem.DropDownItems.Count > 0) { button.DropDownItems.Add(new ToolStripSeparator()); button.DropDownItems.Add(categoryItem); } } private void CreateMessengersList(ToolStripDropDownItem button, EventHandler handler) { var options = ExportsOptions.GetInstance(); var categoryItem = createButtonItem(options.MessengerMenu); CreateItems(options.MessengerMenu, categoryItem, handler); if (categoryItem.DropDownItems.Count > 0) { button.DropDownItems.Add(new ToolStripSeparator()); button.DropDownItems.Add(categoryItem); } } private void UpdateButtons() { btnPrint.Available = (Buttons & PreviewButtons.Print) != 0; btnOpen.Available = (Buttons & PreviewButtons.Open) != 0; btnSave.Available = (Buttons & PreviewButtons.Save) != 0; btnDesign.Available = (Buttons & PreviewButtons.Design) != 0; btnEmail.Available = (Buttons & PreviewButtons.Email) != 0 && !Config.EmailSettings.UseMAPI; btnFind.Available = (Buttons & PreviewButtons.Find) != 0; btnOutline.Available = (Buttons & PreviewButtons.Outline) != 0; btnPageSetup.Available = (Buttons & PreviewButtons.PageSetup) != 0; btnEdit.Available = (Buttons & PreviewButtons.Edit) != 0; btnWatermark.Available = (Buttons & PreviewButtons.Watermark) != 0; btnFirst.Available = (Buttons & PreviewButtons.Navigator) != 0; btnPrior.Available = (Buttons & PreviewButtons.Navigator) != 0; tbPageNo.Available = (Buttons & PreviewButtons.Navigator) != 0; lblTotalPages.Available = (Buttons & PreviewButtons.Navigator) != 0; btnNext.Available = (Buttons & PreviewButtons.Navigator) != 0; btnLast.Available = (Buttons & PreviewButtons.Navigator) != 0; btnClose.Available = (Buttons & PreviewButtons.Close) != 0; } private List GetPageOfTabs() { List list = new List(); foreach (var tab in tabControl.Tabs) { if (tab is PreviewTab) list.Add((tab as PreviewTab).PreparedPages); } return list; } private void Export_Click(object sender, EventArgs e) { if (IsPreviewEmpty) return; ObjectInfo info = (sender as ToolStripMenuItem).Tag as ObjectInfo; if (info == null) Save(); else { ExportBase export = Activator.CreateInstance(info.Object) as ExportBase; export.CurPage = CurrentPreview.PageNo; export.AllowSaveSettings = true; export.ShowProgress = true; try { export.Export(Report, GetPageOfTabs()); } #if !DEBUG catch (Exception ex) { using (ExceptionForm form = new ExceptionForm(ex)) { form.ShowDialog(); } } #endif finally { } } } private async void Design() { if (Report == null) return; using (Report designedReport = new Report()) { designedReport.FileName = Report.FileName; if (!String.IsNullOrEmpty(Report.FileName)) designedReport.Load(designedReport.FileName); else using (MemoryStream repStream = new MemoryStream()) { Report.Save(repStream); repStream.Position = 0; designedReport.Load(repStream); } Report.Dictionary.ReRegisterData(designedReport.Dictionary); #if AVALONIA if (await designedReport.DesignAsync()) #else if (designedReport.Design()) #endif { Report.PreparedPages.Clear(); Report.PreparedPages.ClearPageCache(); try { Report.LoadFromString(designedReport.SaveToString()); } catch (Exception ex) { FRMessageBox.Error(ex.Message); } if (CurrentPreview != null) { Report.Preview = CurrentPreview.Preview; Report.Show(); } } } } private void SaveToCloud_Click(object sender, EventArgs e) { if (IsPreviewEmpty) { return; } ObjectInfo info = (sender as ToolStripMenuItem).Tag as ObjectInfo; if (info != null) { CloudStorageClient client = Activator.CreateInstance(info.Object) as CloudStorageClient; if (client is FtpStorageClient) { XmlItem xi = Config.Root.FindItem("FtpServer").FindItem("StorageSettings"); string server = xi.GetProp("FtpServer"); string username = xi.GetProp("FtpUsername"); FtpStorageClientForm form = new FtpStorageClientForm(server, username, "", Report); form.ShowDialog(); } else if (client is DropboxStorageClient) { XmlItem xi = Config.Root.FindItem("DropboxCloud").FindItem("StorageSettings"); string accessToken = xi.GetProp("AccessToken"); if (String.IsNullOrEmpty(accessToken)) { ApplicationInfoForm appInfoDialog = new ApplicationInfoForm(); appInfoDialog.ShowDialog(); accessToken = appInfoDialog.AccessToken; } DropboxStorageClientForm form = new DropboxStorageClientForm(accessToken, Report); form.ShowDialog(); } else if (client is FastCloudStorageClient) { FastCloudStorageClientSimpleForm form = new FastCloudStorageClientSimpleForm(Report); form.ShowDialog(); } #if !AVALONIA else if (client is BoxStorageClient) { XmlItem xi = Config.Root.FindItem("BoxCloud").FindItem("StorageSettings"); string id = xi.GetProp("ClientId"); string secret = xi.GetProp("ClientSecret"); DialogResult clientInfoDialogDialogResult = DialogResult.OK; if (String.IsNullOrEmpty(id) || String.IsNullOrEmpty(secret)) { Box.ClientInfoForm clientInfoDialog = new Box.ClientInfoForm(); clientInfoDialog.ShowDialog(); id = clientInfoDialog.Id; secret = clientInfoDialog.Secret; clientInfoDialogDialogResult = clientInfoDialog.DialogResult; } if (clientInfoDialogDialogResult == DialogResult.OK) { BoxStorageClientForm form = new BoxStorageClientForm(new SkyDrive.ClientInfo("", id, secret), Report); form.ShowDialog(); } } else if (client is GoogleDriveStorageClient) { XmlItem xi = Config.Root.FindItem("GoogleDriveCloud").FindItem("StorageSettings"); string id = xi.GetProp("ClientId"); string secret = xi.GetProp("ClientSecret"); if (String.IsNullOrEmpty(id) || String.IsNullOrEmpty(secret)) { GoogleDrive.ClientInfoForm clientInfoDialog = new GoogleDrive.ClientInfoForm(); clientInfoDialog.ShowDialog(); id = clientInfoDialog.Id; secret = clientInfoDialog.Secret; } GoogleDriveStorageClientForm form = new GoogleDriveStorageClientForm(new SkyDrive.ClientInfo("", id, secret), Report); form.ShowDialog(); } else if (client is SkyDriveStorageClient) { XmlItem xi = Config.Root.FindItem("SkyDriveCloud").FindItem("StorageSettings"); string id = xi.GetProp("ClientId"); string secret = xi.GetProp("ClientSecret"); if (String.IsNullOrEmpty(id) || String.IsNullOrEmpty(secret)) { SkyDrive.ClientInfoForm appInfoDialog = new SkyDrive.ClientInfoForm(); appInfoDialog.ShowDialog(); id = appInfoDialog.Id; secret = appInfoDialog.Secret; } SkyDriveStorageClientForm form = new SkyDriveStorageClientForm(new SkyDrive.ClientInfo("", id, secret), Report); form.ShowDialog(); } #endif else if (client is S3StorageClient) { XmlItem xi = Config.Root.FindItem("S3").FindItem("StorageSettings"); string accessKeyId = xi.GetProp("AccessKeyId"); string secretAccessKey = xi.GetProp("SecretAccessKey"); string region = xi.GetProp("Region"); string host = xi.GetProp("Host"); Cloud.StorageClient.S3.ClientInfoForm appInfoDialog = new Cloud.StorageClient.S3.ClientInfoForm(); appInfoDialog.AccessKeyId = accessKeyId; appInfoDialog.SecretAccessKey = secretAccessKey; appInfoDialog.Region = region; appInfoDialog.Host = host; if (appInfoDialog.ShowDialog() == DialogResult.OK) { accessKeyId = appInfoDialog.AccessKeyId; secretAccessKey = appInfoDialog.SecretAccessKey; region = appInfoDialog.Region; host = appInfoDialog.Host; } else return; S3ClientForm form = new S3ClientForm(accessKeyId, secretAccessKey, region, host, Report); form.Client.AfterUpload += PreviewControl_AfterUpload; form.Client.BeforeUpload += Client_BeforeUpload; form.ShowDialog(); } } } private void Client_BeforeUpload(object sender, EventArgs e) { ShowPerformance(Res.Get("Preview,Uploading")); uploadTimer.Start(); } private void Timer_Tick(object sender, EventArgs e) { if (lblPerformance.Text.Contains("...")) lblPerformance.Text = lblPerformance.Text.Replace("...", ""); else lblPerformance.Text += "."; } private void PreviewControl_AfterUpload(object sender, EventArgs e) { ShowPerformance(Res.Get("Preview,UploadDone")); } private void tabControl1_TabClosed(object sender, EventArgs e) { DeleteTab(sender as PreviewTab); } private void tabControl1_TabChanged(object sender, EventArgs e) { if (locked) return; currentPreview = tabControl.SelectedTab as PreviewTab; if (currentPreview != null && !currentPreview.Fake) { UpdateOutline(); UpdateZoom(currentPreview.Zoom); UpdatePageNumbers(currentPreview.PageNo, currentPreview.PageCount); } } private void tabControl_Resize(object sender, EventArgs e) { UpdateDocumentLayout(); } private bool CanDisposeTabReport(PreviewTab tab) { if (tab == null || tab.Report == null) return false; // if the preview is owned by Report, do not dispose if (report == tab.Report) return false; // check if the same Report is used in other tabs foreach (PreviewTab t in documents) { if (t != tab && t.Report == tab.Report) { return false; } } return true; } private void Localize() { MyRes res = new MyRes("Preview"); btnPrint.Text = res.Get("PrintText"); btnPrint.ToolTipText = res.Get("Print"); btnOpen.ToolTipText = res.Get("Open"); btnOpen.Text = res.Get("OpenText"); btnDesign.Text = res.Get("DesignText"); btnDesign.ToolTipText = res.Get("Design"); btnSave.ToolTipText = res.Get("Save"); btnSave.Text = res.Get("SaveText"); btnEmail.ToolTipText = res.Get("Email"); btnFind.ToolTipText = res.Get("Find"); btnOutline.ToolTipText = res.Get("Outline"); btnPageSetup.ToolTipText = res.Get("PageSetup"); btnEdit.ToolTipText = res.Get("Edit"); btnWatermark.ToolTipText = res.Get("Watermark"); btnFirst.ToolTipText = res.Get("First"); btnPrior.ToolTipText = res.Get("Prior"); btnNext.ToolTipText = res.Get("Next"); lblTotalPages.Text = String.Format(Res.Get("Misc,ofM"), 1); btnLast.ToolTipText = res.Get("Last"); btnClose.Text = Res.Get("Buttons,Close"); } private void Init() { outlineControl.SetPreview(this); uploadTimer = new Timer(); uploadTimer.Interval = 1500; uploadTimer.Tick += Timer_Tick; pageBorderColor = Color.FromArgb(80, 80, 80); activePageBorderColor = Color.FromArgb(255, 199, 60); pageOffset = new Point(10, 10); defaultZoom = 1; buttons = PreviewButtons.All; exports = Config.PreviewSettings.Exports; clouds = Config.PreviewSettings.Clouds; RestoreState(); UpdateButtons(); zoomControl.ZoomValue = Zoom; } public void RestoreState() { var storage = new ControlStorageService(this, "Preview"); defaultZoom = storage.GetFloat("Zoom", 1); splitContainer1.SplitterDistance = storage.GetDip("OutlineWidth", 250, 50, 800); } public void SaveState() { Clear(); outlineControl.Hide(); var storage = new ControlStorageService(this, "Preview"); storage.SetFloat("Zoom", Zoom); storage.SetDip("OutlineWidth", splitContainer1.SplitterDistance); } private void UpdateDocumentLayout() { foreach (PreviewTab tab in documents) { tab.UpdatePages(); } } private void UpdateUIStyle() { toolStrip.Renderer = statusStrip.Renderer = UIStyleUtils.GetToolStripRenderer(UIStyle); zoomControl.UIStyle = UIStyle; var table = UIStyleUtils.GetColorTable(UIStyle); if (!UseBackColor) BackColor = table.Workspace.WorkspaceBackColor; tabControl.Style = table.Workspace; foreach (PreviewTab tab in documents) { tab.Style = UIStyle; } } private void UpdateOutline() { outlineControl.PreparedPages = currentPreview.PreparedPages; OutlineVisible = !currentPreview.PreparedPages.Outline.IsEmpty; } private void AddFakeTab() { PreviewTab tab = new PreviewTab(this, null, "", null); tab.Fake = true; documents.Add(tab); tab.AddToTabControl(tabControl); } private void UpdateTabsVisible() { tabControl.ShowTabs = documents.Count > 1 && !documents[0].Fake; } private PreviewTab FindTab(string text) { foreach (PreviewTab tab in documents) { if (tab.Text == text) return tab; } return null; } private PreviewTab FindTabByHyperlinkValue(string value) { foreach (PreviewTab tab in documents) { if (tab.HyperlinkValue == value) return tab; } return null; } #endregion #region Public Methods internal void SetReport(Report report) { this.report = report; } internal void UpdatePageNumbers(int pageNo, int totalPages) { lblStatus.Text = String.Format(Res.Get("Misc,PageNofM"), pageNo, totalPages); tbPageNo.Text = pageNo.ToString(); lblTotalPages.Text = String.Format(Res.Get("Misc,ofM"), totalPages); if (PageChanged != null) PageChanged(this, EventArgs.Empty); } internal void UpdateZoom(float zoom) { updatingZoom = true; zoomControl.ZoomValue = zoom; updatingZoom = false; } internal void UpdateUrl(string url) { lblUrl.Text = url; } internal void ShowPerformance(string text) { uploadTimer.Stop(); lblPerformance.Text = text; } internal void DoClick() { OnClick(EventArgs.Empty); } // Clears all tabs except the first one. This method is used in the report.Prepare. // It is needed to avoid flickering when using stand-alone PreviewControl. // When report is prepared and ShowPrepared method is called, the "fake" tab will // be replaced with the new tab. internal void ClearTabsExceptFirst() { while (documents.Count > 1) { DeleteTab(documents[documents.Count - 1]); } if (documents.Count == 1) documents[0].Fake = true; } internal PreviewTab AddPreviewTab(Report report, string text, Hyperlink hyperlink, bool setActive) { PreviewTab tab = new PreviewTab(this, report, text, hyperlink); documents.Add(tab); if (documents.Count == 2 && documents[0].Fake) DeleteTab(documents[0]); var rescale = tabControl.Dpi() / (float)tab.Dpi(); tab.AddToTabControl(tabControl); tab.Scale(new SizeF(rescale, rescale)); tab.UnlockLayout(); UpdateTabsVisible(); tab.UpdatePages(); if (setActive) tabControl.SelectedTab = tab; else tabControl.Refresh(); return tab; } /// /// Adds a new report tab to the preview control. /// /// The Report object that contains the prepared report. /// The title for the new tab. /// /// Prepare the report using its Prepare method before you pass it to the report parameter. /// public void AddTab(Report report, string text) { if (this.report == null) SetReport(report); AddPreviewTab(report, text, null, true); } /// /// Switches to the tab with specified text. /// /// Text of the tab. /// true if the tab with specified text exists, or false if there is no such tab. public bool SwitchToTab(string text) { PreviewTab tab = FindTab(text); if (tab != null) { tabControl.SelectedTab = tab; return true; } return false; } internal bool SwitchToTab(Hyperlink hyperlink) { PreviewTab tab = FindTabByHyperlinkValue(hyperlink.Value); if (tab != null) { tabControl.SelectedTab = tab; return true; } return false; } /// /// Deletes the report tab with specified text. /// /// The text of the tab. public void DeleteTab(string text) { PreviewTab tab = FindTab(text); if (tab != null) DeleteTab(tab); } /// /// Checks if the tab with specified text exists. /// /// The text of the tab. /// true if the tab exists. public bool TabExists(string text) { return FindTab(text) != null; } internal void DeleteTab(PreviewTab tab) { if (CanDisposeTabReport(tab)) tab.Report.Dispose(); documents.Remove(tab); tabControl.Tabs.Remove(tab); tab.Dispose(); uploadTimer.Dispose(); UpdateTabsVisible(); } /// /// Displays the text in the status bar. /// /// Text to display. public void ShowStatus(string text) { int tick = Environment.TickCount; if (tick - lastTick < 50 && !string.IsNullOrEmpty(text)) return; lastTick = tick; lblStatus.Text = text; statusStrip.Refresh(); Application.DoEvents(); } internal void Lock() { locked = true; } internal void Unlock() { locked = false; } /// /// Sets the focus to the preview control. /// public new void Focus() { if (currentPreview != null) currentPreview.Focus(); } /// /// Updates the control appearance and layout on dpi change. /// public void UpdateDpiDependencies() { Font = this.LogicalToDevice(DrawUtils.DefaultFont); tabControl.Font = Font; toolStrip.Font = Font; statusStrip.Font = Font; tbPageNo.Font = Font; outlineControl.Font = Font; outlineControl.UpdateDpiDependencies(); toolStrip.Height = this.LogicalToDevice(26); statusStrip.Height = this.LogicalToDevice(26); statusStrip.Padding = new Padding(6, 0, 0, 0); tabControl.UpdateDpiDependencies(); btnPrint.Image = this.GetImage(195); btnOpen.Image = this.GetImage(1); btnSave.Image = this.GetImage(2); btnDesign.Image = this.GetImage(68); btnEmail.Image = this.GetImage(200); btnFind.Image = this.GetImage(181); btnOutline.Image = this.GetImage(196); btnPageSetup.Image = this.GetImage(13); btnEdit.Image = this.GetImage(198); btnWatermark.Image = this.GetImage(194); btnFirst.Image = this.GetImage(185); btnPrior.Image = this.GetImage(186); btnNext.Image = this.GetImage(187); btnLast.Image = this.GetImage(188); tbPageNo.Size = this.LogicalToDevice(new Size(40, 21)); lblStatus.Size = this.LogicalToDevice(new Size(280, 21)); zoomControl.Size = this.LogicalToDevice(new Size(280, 26)); CreateOpenList(); CreateSaveList(); UpdateDocumentLayout(); } #endregion #region Async Prepare /// /// Gets the value indicating that async report is running. /// /// /// This value can be used to abort the report when you close the form that contains the report preview control. /// public bool IsAsyncReportRunning { get; private set; } // we have to call this separately before AsyncReportStart to set this flag (case: clicking reports in the reports list too fast leads to NRE) internal void SetAsyncReportRunning() => IsAsyncReportRunning = true; internal void AsyncReportStart() { Report.PreparedPages.PageAdded += AsyncReportPageAdded; // update buttons btnClose.Text = Res.Get("Buttons,Cancel"); EnableButtons(false); lblStatus.Text = ""; uploadTimer.Stop(); lblPerformance.Text = ""; tbPageNo.Text = "0"; } private int lastTick; private void AsyncReportPageAdded(object sender, EventArgs e) { int tick = Environment.TickCount; if (tick - lastTick < 50 && Report.PreparedPages.Count > 100) return; Application.DoEvents(); if (Report.Engine.FinalPass) { OutlineVisible = !Report.PreparedPages.Outline.IsEmpty; CurrentPreview.UpdatePages(); } lastTick = Environment.TickCount; } internal void AsyncReportFinish() { IsAsyncReportRunning = false; Report.PreparedPages.PageAdded -= AsyncReportPageAdded; Report.PreparedPages.ClearPageCache(); UpdateOutline(); CurrentPreview.UpdatePages(); // update buttons btnClose.Text = Res.Get("Buttons,Close"); EnableButtons(true); } private void EnableButtons(bool enable) { foreach (ToolStripItem button in ToolBar.Items) { if (button == btnFirst) break; button.Enabled = enable; } } #endregion #region Event handlers private void btnDesign_Click(object sender, EventArgs e) { Design(); } private void btnPrint_Click(object sender, EventArgs e) { Print(); } private void btnOpenLocal_Click(object sender, EventArgs e) { Load(); } private void btnOpenViaCloud_Click(object sender, EventArgs e) { var stream = CloudCommands.LoadPreviewFile(); if (stream != null) Load(stream); } private void btnSaveLocal_Click(object sender, EventArgs e) { Save(); } private void btnSaveToCloud_Click(object sender, EventArgs e) { CloudCommands.SavePreviewFile(currentPreview.Report); } private void btnEmail_Click(object sender, EventArgs e) { SendEmail(); } private void btnFind_Click(object sender, EventArgs e) { Find(); } private void btnZoom100_Click(object sender, EventArgs e) { Zoom = 1; } private void btnZoomWholePage_Click(object sender, EventArgs e) { ZoomWholePage(); } private void btnZoomPageWidth_Click(object sender, EventArgs e) { ZoomPageWidth(); } private void slider_ValueChanged(object sender, EventArgs e) { if (updatingZoom || CurrentPreview == null) return; Zoom = zoomControl.ZoomValue; CurrentPreview.Focus(); } private void btnEdit_Click(object sender, EventArgs e) { EditPage(); } private void btnFirst_Click(object sender, EventArgs e) { First(); } private void btnPrior_Click(object sender, EventArgs e) { Prior(); } private void btnNext_Click(object sender, EventArgs e) { Next(); } private void btnLast_Click(object sender, EventArgs e) { Last(); } private void cbxPageNo_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) { try { PageNo = int.Parse(tbPageNo.Text); } catch { PageNo = PageCount; } CurrentPreview.Focus(); } } private void tbPageNo_KeyPress(object sender, KeyPressEventArgs e) { if (e.KeyChar != '\b' && (e.KeyChar < '0' || e.KeyChar > '9')) e.Handled = true; } private void btnWatermark_Click(object sender, EventArgs e) { EditWatermark(); } private void btnOutline_Click(object sender, EventArgs e) { OutlineVisible = btnOutline.Checked; } private void btnPageSetup_Click(object sender, EventArgs e) { PageSetup(); } private void btnClose_Click(object sender, EventArgs e) { if (IsAsyncReportRunning) { Report.Abort(); return; } #if WPF System.Windows.Window.GetWindow(control)?.Close(); #elif AVALONIA (Avalonia.Controls.TopLevel.GetTopLevel(control) as Avalonia.Controls.Window)?.Close(); #else if (FindForm() != null) FindForm().Close(); #endif } #endregion #region Preview commands /// /// Prints the current report. /// /// true if report was printed; false if user cancels the "Print" dialog. public bool Print() { if (CurrentPreview == null) return false; return CurrentPreview.Print(); } /// /// Saves the current report to a .fpx file using the "Save FIle" dialog. /// public void Save() { if (CurrentPreview == null) return; CurrentPreview.Save(); } /// /// Saves the current report to a specified .fpx file. /// public void Save(string fileName) { if (CurrentPreview == null) return; CurrentPreview.Save(fileName); } /// /// Saves the current report to a stream. /// public void Save(Stream stream) { if (CurrentPreview == null) return; CurrentPreview.Save(stream); } private bool PreLoad() { if (CurrentPreview == null) return false; if (documents.Count == 1 && documents[0].Fake) { Report report = new Report(); report.SetPreparedPages(new PreparedPages(report)); AddTab(report, ""); } return true; } private void PostLoad() { UpdateOutline(); } /// /// Loads the report from a .fpx file using the "Open File" dialog. /// public new void Load() { if (CurrentPreview == null) return; CurrentPreview.Load(); UpdateOutline(); } /// /// Loads the report from a specified .fpx file. /// public new void Load(string fileName) { if (CurrentPreview == null) return; CurrentPreview.Load(fileName); UpdateOutline(); } /// /// Load the report from a stream. /// /// The stream to load from. public new void Load(Stream stream) { if (CurrentPreview == null) return; CurrentPreview.Load(stream); UpdateOutline(); } /// /// Sends an email. /// public void SendEmail() { if (CurrentPreview == null) return; CurrentPreview.SendEmail(); } /// /// Finds the text in the current report using the "Find Text" dialog. /// public void Find() { if (CurrentPreview == null) return; CurrentPreview.Find(); } /// /// Finds the specified text in the current report. /// /// Text to find. /// A value indicating whether the search is case-sensitive. /// A value indicating whether the search matches whole words only. /// true if text found. public bool Find(string text, bool matchCase, bool wholeWord) { if (CurrentPreview == null) return false; return CurrentPreview.Find(text, matchCase, wholeWord); } /// /// Finds the next occurence of text specified in the Find method. /// /// true if text found. public bool FindNext() { if (CurrentPreview == null) return false; return CurrentPreview.FindNext(); } /// /// Navigates to the first page. /// public void First() { if (CurrentPreview == null) return; CurrentPreview.First(); } /// /// Navigates to the previuos page. /// public void Prior() { if (CurrentPreview == null) return; CurrentPreview.Prior(); } /// /// Navigates to the next page. /// public void Next() { if (CurrentPreview == null) return; CurrentPreview.Next(); } /// /// Navigates to the last page. /// public void Last() { if (CurrentPreview == null) return; CurrentPreview.Last(); } /// /// Gets or sets the current page number. /// /// /// This value is 1-based. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public int PageNo { get { if (CurrentPreview == null) return 1; return CurrentPreview.PageNo; } set { if (CurrentPreview == null) return; CurrentPreview.PageNo = value; } } /// /// Gets the pages count in the current report. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public int PageCount { get { if (CurrentPreview == null) return 0; return CurrentPreview.PageCount; } } /// /// Gets or sets the zoom factor. /// /// /// 1 corresponds to 100% zoom. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public float Zoom { get { if (CurrentPreview == null) return 1; return CurrentPreview.Zoom; } set { if (CurrentPreview != null) { CurrentPreview.Zoom = value; updatingZoom = true; zoomControl.ZoomValue = value; updatingZoom = false; } } } /// /// Zooms in. /// public void ZoomIn() { if (CurrentPreview == null) return; CurrentPreview.ZoomIn(); } /// /// Zooms out. /// public void ZoomOut() { if (CurrentPreview == null) return; CurrentPreview.ZoomOut(); } /// /// Zooms to fit the page width. /// public void ZoomPageWidth() { if (CurrentPreview == null) return; CurrentPreview.ZoomPageWidth(); } /// /// Zooms to fit the whole page. /// public void ZoomWholePage() { if (CurrentPreview == null) return; CurrentPreview.ZoomWholePage(); } /// /// Edits the current page in the designer. /// public void EditPage() { if (CurrentPreview == null) return; CurrentPreview.EditPage(); } /// /// Edits the watermark. /// public void EditWatermark() { if (CurrentPreview == null) return; CurrentPreview.EditWatermark(); } /// /// Edits the page settings. /// public void PageSetup() { if (CurrentPreview == null) return; CurrentPreview.PageSetup(); } /// /// Navigates to the specified position inside a specified page. /// /// The page number (1-based). /// The position inside a page, in pixels. public void PositionTo(int pageNo, PointF point) { if (CurrentPreview == null) return; CurrentPreview.PositionTo(pageNo, point); } /// /// Clears the preview. /// public void Clear() { while (documents.Count > 0) { DeleteTab(documents[0]); } lblStatus.Text = ""; tbPageNo.Text = ""; } /// /// Refresh the report. /// public void RefreshReport() { if (CurrentPreview == null) return; CurrentPreview.RefreshReport(); } #endregion /// /// Initializes a new instance of the class. /// public PreviewControl() { // we need this to ensure that static constructor of the Report was called. Report report = new Report(); report.Dispose(); documents = new List(); InitializeComponent(); tabControl = new FRTabControl(); tabControl.Parent = splitContainer1.Panel2; tabControl.ShowCaption = false; tabControl.TabOrientation = TabOrientation.Top; tabControl.Dock = DockStyle.Fill; tabControl.Name = "tabControl"; tabControl.Resize += tabControl_Resize; tabControl.SelectedTabChanged += tabControl1_TabChanged; tabControl.TabClosed += tabControl1_TabClosed; zoomControl = new ToolStripZoomControl(); zoomControl.ZoomPageWidthClick += btnZoomPageWidth_Click; zoomControl.ZoomWholePageClick += btnZoomWholePage_Click; zoomControl.Zoom100Click += btnZoom100_Click; zoomControl.ValueChanged += slider_ValueChanged; statusStrip.Items.Add(zoomControl); #if (WPF || AVALONIA) toolStrip.BorderThickness = new Padding(0); var shadow = toolStrip.SetShadow(DockStyle.Bottom); UIStyleChanged += (s, e) => shadow.Color = UIStyleUtils.GetColorTable(UIStyle).ToolStripBorder; #endif toolbarVisible = true; statusbarVisible = true; OutlineVisible = false; UIStyle = Config.UIStyle; Localize(); Init(); AddFakeTab(); UpdateDpiDependencies(); } } }