diff --git a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/ProjectBrowserPad.cs b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/ProjectBrowserPad.cs index 77f448a523..44bc2b8a86 100644 --- a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/ProjectBrowserPad.cs +++ b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/ProjectBrowserPad.cs @@ -54,10 +54,11 @@ namespace ICSharpCode.SharpDevelop.Project instance = this; ProjectService.SolutionLoaded += ProjectServiceSolutionLoaded; ProjectService.SolutionClosed += ProjectServiceSolutionClosed; + ProjectService.SolutionPreferencesSaving += ProjectServiceSolutionPreferencesSaving; WorkbenchSingleton.Workbench.ActiveWorkbenchWindowChanged += ActiveWindowChanged; if (ProjectService.OpenSolution != null) { - projectBrowserPanel.ViewSolution(ProjectService.OpenSolution); + ProjectServiceSolutionLoaded(null, new SolutionEventArgs(ProjectService.OpenSolution)); } } @@ -66,9 +67,15 @@ namespace ICSharpCode.SharpDevelop.Project ProjectBrowserControl.TreeView.StartLabelEdit(node); } + void ProjectServiceSolutionPreferencesSaving(object sender, SolutionEventArgs e) + { + projectBrowserPanel.StoreViewState(e.Solution.Preferences.Properties); + } + void ProjectServiceSolutionLoaded(object sender, SolutionEventArgs e) { projectBrowserPanel.ViewSolution(e.Solution); + projectBrowserPanel.ReadViewState(e.Solution.Preferences.Properties); } void ProjectServiceSolutionClosed(object sender, EventArgs e) @@ -180,6 +187,5 @@ namespace ICSharpCode.SharpDevelop.Project } } #endregion - } } diff --git a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/ProjectBrowserPanel.cs b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/ProjectBrowserPanel.cs index d398c18a97..7b911c1a3f 100644 --- a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/ProjectBrowserPanel.cs +++ b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/ProjectBrowserPanel.cs @@ -8,6 +8,7 @@ using System; using System.ComponentModel; using System.Drawing; +using System.Text; using System.Windows.Forms; using ICSharpCode.Core; @@ -51,7 +52,7 @@ namespace ICSharpCode.SharpDevelop.Project projectBrowserControl.TreeView.BeforeSelect += TreeViewBeforeSelect; } - void TreeViewBeforeSelect(object sender, TreeViewCancelEventArgs e) + void TreeViewBeforeSelect(object sender, TreeViewCancelEventArgs e) { AbstractProjectBrowserTreeNode node = e.Node as AbstractProjectBrowserTreeNode; if (node == null) { @@ -71,6 +72,86 @@ namespace ICSharpCode.SharpDevelop.Project projectBrowserControl.ViewSolution(solution); } + /// + /// Writes the current view state into the memento. + /// + public void StoreViewState(Properties memento) + { + memento.Set("ProjectBrowserState", GetViewStateString(projectBrowserControl.TreeView)); + } + + /// + /// Reads the view state from the memento. + /// + public void ReadViewState(Properties memento) + { + ApplyViewStateString(memento.Get("ProjectBrowserState", ""), projectBrowserControl.TreeView); + } + + // example ViewStateString: + // [Main[ICSharpCode.SharpDevelop[Src[Gui[Pads[ProjectBrowser[]]]]Services[]]]] + // -> every node name is terminated by opening bracket + // -> only expanded nodes are included in the view state string + // -> after an opening bracket, an identifier or closing bracket must follow + // -> after a closing bracket, an identifier or closing bracket must follow + // -> nodes whose text contains '[' can not be saved + public static string GetViewStateString(TreeView treeView) + { + StringBuilder b = new StringBuilder(); + WriteViewStateString(b, treeView.Nodes[0]); + return b.ToString(); + } + static void WriteViewStateString(StringBuilder b, TreeNode node) + { + b.Append('['); + foreach (TreeNode subNode in node.Nodes) { + if (subNode.IsExpanded && subNode.Text.IndexOf('[') < 0) { + b.Append(subNode.Text); + WriteViewStateString(b, subNode); + } + } + b.Append(']'); + } + public static void ApplyViewStateString(string viewState, TreeView treeView) + { + if (viewState.Length == 0) + return; + int i = 0; + ApplyViewStateString(treeView.Nodes[0], viewState, ref i); + System.Diagnostics.Debug.Assert(i == viewState.Length - 1); + } + static void ApplyViewStateString(TreeNode node, string viewState, ref int pos) + { + if (viewState[pos++] != '[') + throw new ArgumentException("pos must point to '['"); + // expect an identifier or an closing bracket + while (viewState[pos] != ']') { + StringBuilder nameBuilder = new StringBuilder(); + char ch; + while ((ch = viewState[pos++]) != '[') { + nameBuilder.Append(ch); + } + pos -= 1; // go back to '[' character + string nodeText = nameBuilder.ToString(); + // find the node in question + TreeNode subNode = null; + if (node != null) { + foreach (TreeNode n in node.Nodes) { + if (n.Text == nodeText) { + subNode = n; + break; + } + } + } + if (subNode != null) { + subNode.Expand(); + } + ApplyViewStateString(subNode, viewState, ref pos); + // pos now points to the closing bracket of the inner view state + pos += 1; // move to next character + } + } + public void Clear() { projectBrowserControl.Clear(); diff --git a/src/Main/Base/Project/Src/Project/Solution/SolutionPreferences.cs b/src/Main/Base/Project/Src/Project/Solution/SolutionPreferences.cs index bc868d572f..bf66e907e9 100644 --- a/src/Main/Base/Project/Src/Project/Solution/SolutionPreferences.cs +++ b/src/Main/Base/Project/Src/Project/Solution/SolutionPreferences.cs @@ -14,6 +14,7 @@ namespace ICSharpCode.SharpDevelop.Project public class SolutionPreferences : IMementoCapable { Solution solution; + Properties properties = new Properties(); string startupProject = ""; string activeConfiguration = "Debug"; string activePlatform = "Any CPU"; @@ -23,6 +24,12 @@ namespace ICSharpCode.SharpDevelop.Project this.solution = solution; } + public Properties Properties { + get { + return properties; + } + } + public IProject StartupProject { get { if (startupProject.Length == 0) @@ -61,9 +68,9 @@ namespace ICSharpCode.SharpDevelop.Project /// /// Creates a new memento from the state. /// - public Properties CreateMemento() + Properties IMementoCapable.CreateMemento() { - Properties p = new Properties(); + Properties p = properties; p.Set("StartupProject", startupProject); p.Set("ActiveConfiguration", activeConfiguration); p.Set("ActivePlatform", activePlatform); @@ -73,7 +80,7 @@ namespace ICSharpCode.SharpDevelop.Project /// /// Sets the state to the given memento. /// - public void SetMemento(Properties memento) + void IMementoCapable.SetMemento(Properties memento) { startupProject = memento.Get("StartupProject", ""); string configuration = memento.Get("ActiveConfiguration", activeConfiguration); @@ -89,6 +96,8 @@ namespace ICSharpCode.SharpDevelop.Project this.ActiveConfiguration = configuration; this.ActivePlatform = platform; + + this.properties = memento; } } } diff --git a/src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs b/src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs index 538e862033..b54af80894 100644 --- a/src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs +++ b/src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs @@ -18,6 +18,7 @@ namespace ICSharpCode.SharpDevelop.Project static IProject currentProject; public static Solution OpenSolution { + [System.Diagnostics.DebuggerStepThrough] get { return openSolution; } @@ -218,16 +219,18 @@ namespace ICSharpCode.SharpDevelop.Project openSolution = Solution.Load(fileName); if (openSolution == null) return; - OnSolutionLoaded(new SolutionEventArgs(openSolution)); try { string file = GetPreferenceFileName(openSolution.FileName); if (FileUtility.IsValidFileName(file) && File.Exists(file)) { - openSolution.Preferences.SetMemento(Properties.Load(file)); + (openSolution.Preferences as IMementoCapable).SetMemento(Properties.Load(file)); } ApplyConfigurationAndReadPreferences(); } catch (Exception ex) { MessageService.ShowError(ex); } + // preferences must be read before OnSolutionLoad is called to enable + // the event listeners to read e.Solution.Preferences.Properties + OnSolutionLoaded(new SolutionEventArgs(openSolution)); } static void ApplyConfigurationAndReadPreferences() @@ -275,8 +278,10 @@ namespace ICSharpCode.SharpDevelop.Project solution.Save(solutionFile); openSolution = solution; - OnSolutionLoaded(new SolutionEventArgs(openSolution)); ApplyConfigurationAndReadPreferences(); + // preferences must be read before OnSolutionLoad is called to enable + // the event listeners to read e.Solution.Preferences.Properties + OnSolutionLoaded(new SolutionEventArgs(openSolution)); } public static void SaveSolution() @@ -307,14 +312,13 @@ namespace ICSharpCode.SharpDevelop.Project Directory.CreateDirectory(directory); } - string fullFileName; - Properties memento = openSolution.Preferences.CreateMemento(); - if (memento != null) { - fullFileName = GetPreferenceFileName(openSolution.FileName); - - if (FileUtility.IsValidFileName(fullFileName)) { - FileUtility.ObservedSave(new NamedFileOperationDelegate(memento.Save), fullFileName, FileErrorPolicy.Inform); - } + if (SolutionPreferencesSaving != null) + SolutionPreferencesSaving(null, new SolutionEventArgs(openSolution)); + Properties memento = (openSolution.Preferences as IMementoCapable).CreateMemento(); + + string fullFileName = GetPreferenceFileName(openSolution.FileName); + if (FileUtility.IsValidFileName(fullFileName)) { + FileUtility.ObservedSave(new NamedFileOperationDelegate(memento.Save), fullFileName, FileErrorPolicy.Inform); } foreach (IProject project in OpenSolution.Projects) { @@ -474,6 +478,12 @@ namespace ICSharpCode.SharpDevelop.Project public static event EventHandler SolutionClosing; public static event EventHandler SolutionClosed; + /// + /// Raised before the solution preferences are being saved. Allows you to save + /// your additional properties in the solution preferences. + /// + public static event EventHandler SolutionPreferencesSaving; + public static event ProjectEventHandler CurrentProjectChanged; public static event EventHandler ProjectItemAdded;