[runtime] Fix corlib out of date error with disabled COM
[mono.git] / mcs / class / referencesource / System.Activities.Presentation / System.Activities.Presentation / System / Activities / Presentation / ErrorReporting.cs
1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4
5 namespace System.Activities.Presentation
6 {
7     using System.Activities.Presentation.Internal.PropertyEditing;
8     using System.Activities.Presentation.View;
9     using System.Diagnostics;
10     using System.Runtime;
11     using System.Text;
12     using System.Threading;
13     using System.Windows;
14     using System.Windows.Controls;
15     using System.Windows.Input;
16     using System.Globalization;
17     using System.Diagnostics.CodeAnalysis;
18
19     [Fx.Tag.XamlVisible(false)]
20     internal static class ErrorReporting
21     {
22         private static WeakReference activeDesignerViewReference;
23
24         internal static DesignerView ActiveDesignerView
25         {
26             get
27             {
28                 if (activeDesignerViewReference != null)
29                 {
30                     return activeDesignerViewReference.Target as DesignerView;
31                 }
32
33                 return null;
34             }
35             set
36             {
37                 if (value == null)
38                 {
39                     activeDesignerViewReference = null;
40                 }
41                 else
42                 {
43                     activeDesignerViewReference = new WeakReference(value);
44                 }
45             }
46         }
47
48         public static void ShowErrorMessage(string message)
49         {
50             ShowErrorMessage(message, false);
51         }
52
53         public static void ShowAlertMessage(string message)
54         {
55             ShowAlertMessage(message, false);
56         }
57
58         public static void ShowErrorMessage(string message, string details)
59         {
60             if (string.IsNullOrEmpty(details))
61             {
62                 ShowErrorMessage(message);
63             }
64             else
65             {
66                 ShowErrorMessage(string.Format(CultureInfo.CurrentUICulture, "{0}\n\n\"{1}\"", message, details));
67             }
68         }
69
70         public static void ShowErrorMessage(string message, bool includeStackTrace)
71         {
72             string stackTrace = null;
73             if (includeStackTrace)
74             {
75                 //generate stack trace
76                 stackTrace = new StackTrace().ToString();
77                 //remove top frame from the trace (which is a call to ShowErrorMessage)
78                 stackTrace = stackTrace.Remove(0, stackTrace.IndexOf(Environment.NewLine, StringComparison.Ordinal) + 1);
79             }
80             ShowMessageBox(message, MessageBoxImage.Error, stackTrace);
81         }
82
83         public static void ShowAlertMessage(string message, bool includeStackTrace)
84         {
85             string stackTrace = null;
86             if (includeStackTrace)
87             {
88                 //generate stack trace
89                 stackTrace = new StackTrace().ToString();
90                 //remove top frame from the trace (which is a call to ShowAlertMessage)
91                 stackTrace = stackTrace.Remove(0, stackTrace.IndexOf(Environment.NewLine, StringComparison.Ordinal) + 1);
92             }
93             ShowMessageBox(message, MessageBoxImage.Warning, stackTrace);
94         }
95
96         public static void ShowErrorMessage(Exception err)
97         {
98             if (null != err)
99             {
100                 ShowMessageBox(string.Format(CultureInfo.InvariantCulture, "{0}:\r\n{1}", err.GetType().Name, err.Message), MessageBoxImage.Error, err.StackTrace);
101             }
102         }
103
104         static void ShowMessageBox(string message, MessageBoxImage icon, string stackTrace)
105         {
106             //determine an icon
107             string iconName = icon == MessageBoxImage.Error ? "TextBoxErrorIcon" :
108                 icon == MessageBoxImage.Warning ? "WarningValidationIcon" : string.Empty;
109
110             //set properties
111             var dlg = new ErrorDialog()
112             {
113                 ErrorDescription = message ?? "<null>",
114                 Icon = EditorResources.GetIcons()[iconName],
115                 StackTrace = stackTrace,
116                 StackTraceVisibility = string.IsNullOrEmpty(stackTrace) ? Visibility.Collapsed : Visibility.Visible,
117                 Context = null != ActiveDesignerView ? ActiveDesignerView.Context : null,
118                 Owner = ActiveDesignerView,
119             };
120             //show error window
121             dlg.Show();
122         }
123
124         sealed class ErrorDialog : WorkflowElementDialog
125         {
126             public string ErrorDescription { get; set; }
127
128             public Visibility StackTraceVisibility { get; set; }
129
130             public string StackTrace { get; set; }
131
132             [SuppressMessage(FxCop.Category.Performance, FxCop.Rule.AvoidUncalledPrivateCode,
133                 Justification = "This property is accessed by XAML")]
134             public object Icon { get; set; }
135
136             protected override void OnInitialized(EventArgs e)
137             {
138                 this.Title = SR.WorkflowDesignerErrorPresenterTitle;
139                 this.Content = new ContentPresenter()
140                 {
141                     ContentTemplate = (DataTemplate)EditorResources.GetResources()["ErrorPresenterDialogTemplate"],
142                     Content = this,
143                 };
144                 this.MinWidth = 365;
145                 this.WindowResizeMode = ResizeMode.NoResize;
146                 this.WindowSizeToContent = SizeToContent.WidthAndHeight;
147                 //handle loaded event
148                 this.Loaded += this.OnDialogWindowLoaded;
149                 base.OnInitialized(e);
150             }
151
152             void OnDialogWindowLoaded(object s, RoutedEventArgs e)
153             {
154                 //get the containing window
155                 var parentWindow = VisualTreeUtils.FindVisualAncestor<Window>(this);
156                 //and handle KeyDown event - in case of Esc, we should close the dialog
157                 parentWindow.KeyDown += OnWindowKeyDown;
158
159                 //add Copy command support - when user presses Ctrl+C, copy content of the error into clipboard
160                 var copyBinding = new CommandBinding(ApplicationCommands.Copy);
161                 copyBinding.PreviewCanExecute += OnCopyCanExecute;
162                 copyBinding.Executed += OnCopyExecuted;
163                 parentWindow.CommandBindings.Add(copyBinding);
164             }
165
166             void OnWindowKeyDown(object s, KeyEventArgs e)
167             {
168                 //Esc - close the dialog box
169                 if (e.Key == Key.Escape)
170                 {
171                     ((Window)s).DialogResult = false;
172                     e.Handled = true;
173                 }
174             }
175
176             void OnCopyCanExecute(object s, CanExecuteRoutedEventArgs e)
177             {
178                 //do not allow text boxes to handle the ApplicationCommand.Copy, i will handle it myself
179                 e.CanExecute = true;
180                 e.ContinueRouting = false;
181                 e.Handled = true;
182             }
183
184             void OnCopyExecuted(object s, ExecutedRoutedEventArgs e)
185             {
186                 //build a string with detailed error description
187                 StringBuilder error = new StringBuilder();
188                 error.Append('-', 25);
189                 error.Append(Environment.NewLine);
190                 error.Append(this.Title);
191                 error.Append(Environment.NewLine);
192                 error.Append('-', 25);
193                 error.Append(Environment.NewLine);
194                 error.Append(this.ErrorDescription);
195                 error.Append(Environment.NewLine);
196                 if (this.StackTraceVisibility == Visibility.Visible)
197                 {
198                     error.Append('-', 25);
199                     error.Append(Environment.NewLine);
200                     error.Append(this.StackTrace);
201                     error.Append(Environment.NewLine);
202                 }
203                 error.Append('-', 25);
204                 error.Append(Environment.NewLine);
205                 string result = error.ToString();
206
207                 //attempt to set the value into clipboard - according to MSDN - if a call fails, it means some other process is accessing clipboard
208                 //so sleep and retry
209                 for (int i = 0; i < 10; ++i)
210                 {
211                     try
212                     {
213                         Clipboard.SetText(result);
214                         break;
215                     }
216                     catch (Exception err)
217                     {
218                         if (Fx.IsFatal(err))
219                         {
220                             throw;
221                         }
222                         Thread.Sleep(50);
223                     }
224                 }
225                 e.Handled = true;
226             }
227         }
228     }
229 }