private void ShowNotifyDialog(string severity, string messageText, Exception exception, string reportButtonLabel, string secondaryButtonLabel) { // Before we do anything that might be "risky", put the problem in the log. ProblemReportApi.LogProblem(exception, messageText, severity); // ENHANCE: Allow the caller to pass in the control, which would be at the front of this. //System.Windows.Forms.Control control = Form.ActiveForm ?? FatalExceptionHandler.ControlOnUIThread; var control = GetControlToUse(); var isSyncRequired = false; SafeInvoke.InvokeIfPossible("Show Error Reporter", control, isSyncRequired, () => { // Uses a browser dialog to show the problem report try { StartupScreenManager.CloseSplashScreen(); // if it's still up, it'll be on top of the dialog var message = GetMessage(messageText, exception); if (!Api.BloomServer.ServerIsListening) { // There's no hope of using the HtmlErrorReporter dialog if our server is not yet running. // We'll likely get errors, maybe Javascript alerts, that won't lead to a clean fallback to // the exception handler below. Besides, failure of HtmlErrorReporter in these circumstances // is expected; we just want to cleanly report the original problem, not to report a // failure of error handling. // Note: HtmlErrorReporter supports up to 3 buttons (OK, Report, and [Secondary action]), but the fallback reporter only supports a max of two. // Well, just going to have to drop the secondary action. ShowFallbackProblemDialog(severity, exception, messageText, null, false); return; } object props = new { level = ProblemLevel.kNotify, reportLabel = reportButtonLabel, secondaryLabel = secondaryButtonLabel, message = message }; // Precondition: we must be on the UI thread for Gecko to work. using (var dlg = BrowserDialogFactory.CreateReactDialog("problemReportBundle", props)) { dlg.FormBorderStyle = FormBorderStyle.FixedToolWindow; // Allows the window to be dragged around dlg.ControlBox = true; // Add controls like the X button back to the top bar dlg.Text = ""; // Remove the title from the WinForms top bar dlg.Width = 620; // 360px was experimentally determined as what was needed for the longest known text for NotifyUserOfProblem // (which is "Before saving, Bloom did an integrity check of your book [...]" from BookStorage.cs) // You can make this height taller if need be. // A scrollbar will appear if the height is not tall enough for the text dlg.Height = 360; // ShowDialog will cause this thread to be blocked (because it spins up a modal) until the dialog is closed. BloomServer.RegisterThreadBlocking(); try { dlg.ShowDialog(); // Take action if the user clicked a button other than Close if (dlg.CloseSource == "closedByAlternateButton" && OnSecondaryActionPressed != null) { OnSecondaryActionPressed(exception, message); } else if (dlg.CloseSource == "closedByReportButton") { if (OnReportButtonPressed != null) { OnReportButtonPressed(exception, message); } else { DefaultOnReportPressed(exception, message); } } // Note: With the way LibPalaso's ErrorReport is designed, // its intention is that after OnShowDetails is invoked and closed, you will not come back to the Notify Dialog // This code has been implemented to follow that model // // But now that we have more options, it might be nice to come back to this dialog. // If so, you'd need to add/update some code in this section. } finally { ResetToDefaults(); BloomServer.RegisterThreadUnblocked(); } } } catch (Exception errorReporterException) { Logger.WriteError("*** HtmlErrorReporter threw an exception trying to display", errorReporterException); // At this point our problem reporter has failed for some reason, so we want the old WinForms handler // to report both the original error for which we tried to open our dialog and this new one where // the dialog itself failed. // In order to do that, we create a new exception with the original exception (if there was one) as the // inner exception. We include the message of the exception we just caught. Then we call the // old WinForms fatal exception report directly. // In any case, both of the errors will be logged by now. var message = "Bloom's error reporting failed: " + errorReporterException.Message; // Fallback to Winforms in case of trouble getting the browser to work var fallbackReporter = new WinFormsErrorReporter(); // Food for thought: is it really fatal of the Notify Dialog had an exception? Maybe NonFatal makes more sense fallbackReporter.ReportFatalException(new ApplicationException(message, exception ?? errorReporterException)); } }); }