From 73bc1fcfbff5e68ba4233931037872501623bee7 Mon Sep 17 00:00:00 2001 From: Christian Hornung Date: Wed, 27 Aug 2008 19:40:59 +0000 Subject: [PATCH] Added some application state information to exception reports. Currently reported values are: installed 3rd party addins, OpenSolution, CurrentProject, Workbench.ActiveContent. More information can be added anywhere by registering a state getter with ICSharpCode.Core.ApplicationStateInfoService.RegisterStateGetter. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@3455 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Project/Src/Gui/WorkbenchSingleton.cs | 5 + .../Project/Src/Project/Solution/Solution.cs | 7 + .../Services/ProjectService/ProjectService.cs | 2 + src/Main/Core/Project/ICSharpCode.Core.csproj | 1 + .../Core/Project/Src/AddInTree/AddInTree.cs | 20 +++ .../Services/ApplicationStateInfoService.cs | 159 ++++++++++++++++++ .../Src/ExceptionBox.cs | 8 + 7 files changed, 202 insertions(+) create mode 100644 src/Main/Core/Project/Src/Services/ApplicationStateInfoService.cs diff --git a/src/Main/Base/Project/Src/Gui/WorkbenchSingleton.cs b/src/Main/Base/Project/Src/Gui/WorkbenchSingleton.cs index add7f89bf1..e273590a4b 100644 --- a/src/Main/Base/Project/Src/Gui/WorkbenchSingleton.cs +++ b/src/Main/Base/Project/Src/Gui/WorkbenchSingleton.cs @@ -19,6 +19,7 @@ namespace ICSharpCode.SharpDevelop.Gui const string uiIconStyle = "IconMenuItem.IconMenuStyle"; const string uiLanguageProperty = "CoreProperties.UILanguage"; const string workbenchMemento = "WorkbenchMemento"; + const string activeContentState = "Workbench.ActiveContent"; static STAThreadCaller caller; static IWorkbench workbench; @@ -115,6 +116,8 @@ namespace ICSharpCode.SharpDevelop.Gui workbench.SetMemento(PropertyService.Get(workbenchMemento, new Properties())); workbench.WorkbenchLayout = layout; + ApplicationStateInfoService.RegisterStateGetter(activeContentState, delegate { return WorkbenchSingleton.Workbench.ActiveContent; }); + OnWorkbenchCreated(); // initialize workbench-dependent services: @@ -141,6 +144,8 @@ namespace ICSharpCode.SharpDevelop.Gui Project.ProjectService.CloseSolution(); NavigationService.Unload(); + ApplicationStateInfoService.UnregisterStateGetter(activeContentState); + if (WorkbenchUnloaded != null) { WorkbenchUnloaded(null, EventArgs.Empty); } diff --git a/src/Main/Base/Project/Src/Project/Solution/Solution.cs b/src/Main/Base/Project/Src/Project/Solution/Solution.cs index a242f40dec..afeb4dc0f0 100644 --- a/src/Main/Base/Project/Src/Project/Solution/Solution.cs +++ b/src/Main/Base/Project/Src/Project/Solution/Solution.cs @@ -1186,5 +1186,12 @@ namespace ICSharpCode.SharpDevelop.Project feedbackSink.Done(true); } #endregion + + public override string ToString() + { + return "[Solution: FileName=" + (this.FileName ?? "") + + ", HasProjects=" + this.HasProjects.ToString(System.Globalization.CultureInfo.InvariantCulture) + + ", ReadOnly=" + this.ReadOnly.ToString(System.Globalization.CultureInfo.InvariantCulture) + "]"; + } } } diff --git a/src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs b/src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs index f69aa2a74a..662182b184 100644 --- a/src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs +++ b/src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs @@ -64,6 +64,8 @@ namespace ICSharpCode.SharpDevelop.Project WorkbenchSingleton.Workbench.ActiveViewContentChanged += ActiveViewContentChanged; FileService.FileRenamed += FileServiceFileRenamed; FileService.FileRemoved += FileServiceFileRemoved; + ApplicationStateInfoService.RegisterStateGetter("ProjectService.OpenSolution", delegate { return OpenSolution; }); + ApplicationStateInfoService.RegisterStateGetter("ProjectService.CurrentProject", delegate { return CurrentProject; }); } } diff --git a/src/Main/Core/Project/ICSharpCode.Core.csproj b/src/Main/Core/Project/ICSharpCode.Core.csproj index b4f1b6f98c..3e96226f01 100644 --- a/src/Main/Core/Project/ICSharpCode.Core.csproj +++ b/src/Main/Core/Project/ICSharpCode.Core.csproj @@ -81,6 +81,7 @@ + diff --git a/src/Main/Core/Project/Src/AddInTree/AddInTree.cs b/src/Main/Core/Project/Src/AddInTree/AddInTree.cs index 7eff7c570c..bfd28ca02b 100644 --- a/src/Main/Core/Project/Src/AddInTree/AddInTree.cs +++ b/src/Main/Core/Project/Src/AddInTree/AddInTree.cs @@ -36,6 +36,26 @@ namespace ICSharpCode.Core conditionEvaluators.Add("Compare", new CompareConditionEvaluator()); conditionEvaluators.Add("Ownerstate", new OwnerStateConditionEvaluator()); + + ApplicationStateInfoService.RegisterStateGetter("Installed 3rd party AddIns", GetInstalledThirdPartyAddInsListAsString); + } + + static object GetInstalledThirdPartyAddInsListAsString() + { + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + foreach (AddIn addIn in AddIns) { + if (!FileUtility.IsBaseDirectory(FileUtility.ApplicationRootPath, addIn.FileName)) { + if (sb.Length > 0) sb.Append(", "); + sb.Append("["); + sb.Append(addIn.Name); + sb.Append(", Enabled="); + sb.Append(addIn.Enabled); + sb.Append(", Action="); + sb.Append(addIn.Action.ToString()); + sb.Append("]"); + } + } + return sb.ToString(); } /// diff --git a/src/Main/Core/Project/Src/Services/ApplicationStateInfoService.cs b/src/Main/Core/Project/Src/Services/ApplicationStateInfoService.cs new file mode 100644 index 0000000000..b8ea8323cb --- /dev/null +++ b/src/Main/Core/Project/Src/Services/ApplicationStateInfoService.cs @@ -0,0 +1,159 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; + +namespace ICSharpCode.Core +{ + /// + /// This service is used to summarize important information + /// about the state of the application when an exception occurs. + /// + public static class ApplicationStateInfoService + { + static readonly Dictionary stateGetters = new Dictionary(StringComparer.InvariantCulture); + + /// + /// Registers a new method to be invoked to get information about the current state of the application. + /// + /// The title of the new state entry. + /// The method to be invoked to get the state value. + /// The is null. + /// A state getter with the specified is already registered. + public static void RegisterStateGetter(string title, StateGetter stateGetter) + { + lock(stateGetters) { + stateGetters.Add(title, stateGetter); + } + } + + /// + /// Determines whether a state getter with the specified title is already registered. + /// + /// The title to look for. + /// true, if a state getter with the specified title is already registered, otherwise false. + public static bool IsRegistered(string title) + { + lock(stateGetters) { + return stateGetters.ContainsKey(title); + } + } + + /// + /// Unregisters a state getter. + /// + /// The title of the state entry to remove. + /// true if the specified title was found and removed, otherwise false. + /// The is null. + public static bool UnregisterStateGetter(string title) + { + lock(stateGetters) { + return stateGetters.Remove(title); + } + } + + /// + /// Gets a snapshot of the current application state information from all registered state getters. + /// + /// A dictionary with the titles and results of all registered state getters. + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] + public static IDictionary GetCurrentApplicationStateInfo() + { + Dictionary state = new Dictionary(stateGetters.Count, stateGetters.Comparer); + lock(stateGetters) { + foreach (KeyValuePair entry in stateGetters) { + try { + state.Add(entry.Key, entry.Value()); + } catch (Exception ex) { + state.Add(entry.Key, new StateGetterExceptionInfo(ex)); + } + } + } + return state; + } + + /// + /// Appends the current application state information from all registered state getters + /// to the specified . + /// + /// The to append the state information to. + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] + public static void AppendFormatted(StringBuilder sb) + { + IFormattable f; + Exception e; + StateGetterExceptionInfo exceptionInfo; + + foreach (KeyValuePair entry in GetCurrentApplicationStateInfo()) { + e = null; + sb.Append(entry.Key); + sb.Append(": "); + + if (entry.Value == null) { + sb.AppendLine(""); + } else { + f = entry.Value as IFormattable; + if (f != null) { + try { + sb.AppendLine(f.ToString(null, CultureInfo.InvariantCulture)); + } catch (Exception ex) { + sb.AppendLine("--> Exception thrown by IFormattable.ToString:"); + e = ex; + } + } else { + exceptionInfo = entry.Value as StateGetterExceptionInfo; + if (exceptionInfo != null) { + sb.AppendLine("--> Exception thrown by the state getter:"); + e = exceptionInfo.Exception; + } else { + try { + sb.AppendLine(entry.Value.ToString()); + } catch (Exception ex) { + sb.AppendLine("--> Exception thrown by ToString:"); + e = ex; + } + } + } + } + + if (e != null) { + sb.AppendLine(e.ToString()); + } + } + } + + sealed class StateGetterExceptionInfo + { + readonly Exception exception; + + internal StateGetterExceptionInfo(Exception exception) + { + if (exception == null) + throw new ArgumentNullException("exception"); + this.exception = exception; + } + + internal Exception Exception { + get { return exception; } + } + + public override string ToString() + { + return "StateGetterExceptionInfo: " + this.exception.ToString(); + } + } + } + + /// + /// A delegate used to get information about the current state of the application. + /// + public delegate object StateGetter(); +} diff --git a/src/Main/ICSharpCode.SharpDevelop.Sda/Src/ExceptionBox.cs b/src/Main/ICSharpCode.SharpDevelop.Sda/Src/ExceptionBox.cs index c71625e79e..cc030c8f27 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Sda/Src/ExceptionBox.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Sda/Src/ExceptionBox.cs @@ -141,6 +141,14 @@ namespace ICSharpCode.SharpDevelop.Sda sb.AppendLine("Failed to append recent log messages."); sb.AppendLine(ex.ToString()); } + sb.AppendLine(); + sb.AppendLine("---- Post-error application state information:"); + try { + ApplicationStateInfoService.AppendFormatted(sb); + } catch (Exception ex) { + sb.AppendLine("Failed to append application state information."); + sb.AppendLine(ex.ToString()); + } return sb.ToString(); }