diff --git a/data/resources/StringResources.resx b/data/resources/StringResources.resx
index cf578a4f55..3dd6afa578 100644
--- a/data/resources/StringResources.resx
+++ b/data/resources/StringResources.resx
@@ -5156,7 +5156,7 @@ Goto 'Options->Visual Style' and change the current language ambience.ASP.NET/IIS (Express) worker process ({0}) was not found.
- There's no Project Url specified or external program. Check the web server at Project Properties -> Debug tab.
+ There's no Project Url specified or external program. Check the web server at Project Properties -> Debug tab.
Server port:
diff --git a/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPad.cs b/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPad.cs
index 1fb2b894af..299fa04985 100644
--- a/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPad.cs
+++ b/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPad.cs
@@ -3,6 +3,8 @@
using System;
using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Linq;
using System.Windows;
using System.Windows.Input;
@@ -13,9 +15,10 @@ using Debugger.AddIn.TreeModel;
using ICSharpCode.Core;
using ICSharpCode.Core.Presentation;
using ICSharpCode.NRefactory;
+using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Project;
+using ICSharpCode.SharpDevelop.Project.SavedData;
using Exception = System.Exception;
-using ICSharpCode.SharpDevelop.Debugging;
namespace ICSharpCode.SharpDevelop.Gui.Pads
{
@@ -58,11 +61,98 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
watchList.Drop += watchList_Drop;
watchList.MouseDoubleClick += watchList_DoubleClick;
watchList.KeyUp += watchList_KeyUp;
+ watchList.WatchItems.CollectionChanged += OnWatchItemsCollectionChanged;
panel.Children.Add(watchList);
panel.KeyUp += new KeyEventHandler(panel_KeyUp);
+
+ // wire events that influence the items
+ LoadSavedNodes();
+ ProjectService.SolutionClosed += delegate { watchList.WatchItems.Clear(); };
+ ProjectService.SolutionPreferencesSaving += OnSolutionClosing;
+ ProjectService.ProjectRemoved += OnProjectRemoved;
+ ProjectService.ProjectAdded += OnProjectAdded;
+ ProjectService.SolutionLoaded += delegate { LoadSavedNodes(); };
+ }
+
+ #region Saved nodes
+
+ void AddNodes(Func predicate)
+ {
+ if (predicate == null)
+ throw new ArgumentNullException("predicate");
+
+ // get nodes of current projects
+ List temp = new List();
+ foreach (var data in SavedDataManager.GetSavedData().Where(predicate)) {
+ string[] v = data.SavedString.Split('|');
+
+ TextNode node = new TextNode(null, v[5], (SupportedLanguage)Enum.Parse(typeof(SupportedLanguage), v[7])) { ProjectName = data.ProjectName };
+ temp.Add(node);
+ }
+
+ // add them to watch list
+ temp.ForEach(d => { if (!watchList.WatchItems.Contains(d)) watchList.WatchItems.Add(d); } );
+ }
+
+ void LoadSavedNodes()
+ {
+ AddNodes(d => d.SavedDataType == ProjectSavedDataType.WatchVariables &&
+ ProjectService.OpenSolution.Projects.Any(p => p.Name == d.ProjectName));
+
+ // remove them temporarilly - they will be saved on exit
+ SavedDataManager.RemoveAll(d => d.SavedDataType == ProjectSavedDataType.WatchVariables &&
+ ProjectService.OpenSolution.Projects.Any(p => p.Name == d.ProjectName));
+ }
+
+ void OnSolutionClosing(object sender, SolutionEventArgs e)
+ {
+ foreach (var element in watchList.WatchItems) {
+ SavedDataManager.Add((IProjectSavedData)element);
+ }
+ }
+
+ void OnProjectAdded(object sender, ProjectEventArgs e)
+ {
+ AddNodes(d => d.SavedDataType == ProjectSavedDataType.WatchVariables && e.Project.Name == d.ProjectName);
+ }
+
+ void OnProjectRemoved(object sender, ProjectEventArgs e)
+ {
+ if (e.Project == null)
+ return;
+
+ // get the specific nodes from the list
+ List nodes = new List();
+ foreach (var element in watchList.WatchItems
+ .OfType()
+ .Where(tn => tn.ProjectName == e.Project.Name)) {
+ nodes.Add(element);
+ }
+
+ // remove nodes from the list
+ nodes.ForEach(n => watchList.WatchItems.Remove(n));
}
+ void OnWatchItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+ {
+ if (e.Action == NotifyCollectionChangedAction.Add) {
+ // add to saved data
+ var data = e.NewItems[0] as IProjectSavedData;
+ if (data != null)
+ SavedDataManager.Add(data);
+ }
+
+ if (e.Action == NotifyCollectionChangedAction.Remove) {
+ // remove from saved data
+ var data = e.OldItems[0] as IProjectSavedData;
+ if (data != null)
+ SavedDataManager.Remove(data);
+ }
+ }
+
+ #endregion
+
void panel_KeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Insert) {
diff --git a/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPadModel.cs b/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPadModel.cs
index 14365919db..f599aa0e12 100644
--- a/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPadModel.cs
+++ b/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPadModel.cs
@@ -2,20 +2,24 @@
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System;
-using System.Collections.Generic;
+using System.Text;
using Debugger.AddIn.TreeModel;
using ICSharpCode.NRefactory;
-using ICSharpCode.SharpDevelop.Debugging;
+using ICSharpCode.SharpDevelop.Project;
+using ICSharpCode.SharpDevelop.Project.SavedData;
namespace ICSharpCode.SharpDevelop.Gui.Pads
{
- public class TextNode : TreeNode, ISetText
+ public class TextNode : TreeNode, ISetText, IProjectSavedData
{
public TextNode(TreeNode parent, string text, SupportedLanguage language)
: base(parent)
{
this.Name = text;
this.Language = language;
+
+ if (ProjectService.CurrentProject != null)
+ ProjectName = ProjectService.CurrentProject.Name;
}
public override bool CanSetText {
@@ -37,6 +41,36 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
}
public SupportedLanguage Language { get; set; }
+
+ #region IProjectSavedData implementation
+
+ string savedString;
+
+ public string SavedString {
+ get {
+ StringBuilder sb = new StringBuilder();
+ sb.Append("ProjectName"); sb.Append('|'); sb.Append(ProjectName); sb.Append('|');
+ sb.Append("ProjectSavedDataType"); sb.Append('|'); sb.Append(SavedDataType); sb.Append('|');
+ sb.Append("FullName"); sb.Append('|'); sb.Append(FullName); sb.Append('|');
+ sb.Append("Language"); sb.Append('|'); sb.Append(Language.ToString());
+
+ savedString = sb.ToString();
+ return savedString;
+ }
+ set { savedString = value; }
+ }
+
+ public ProjectSavedDataType SavedDataType {
+ get {
+ return ProjectSavedDataType.WatchVariables;
+ }
+ }
+
+ public string ProjectName {
+ get; internal set;
+ }
+
+ #endregion
}
public class ErrorInfoNode : ICorDebug.InfoNode
diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
index 9518e0dcff..a294f06954 100644
--- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
+++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
@@ -243,6 +243,9 @@
SelectCulturePanel.xaml
Code
+
+
+
WebProjectOptionsPanel.xaml
@@ -848,6 +851,7 @@
+
diff --git a/src/Main/Base/Project/Src/Project/AbstractProject.cs b/src/Main/Base/Project/Src/Project/AbstractProject.cs
index 4655f7dce5..9da00fb957 100644
--- a/src/Main/Base/Project/Src/Project/AbstractProject.cs
+++ b/src/Main/Base/Project/Src/Project/AbstractProject.cs
@@ -7,12 +7,14 @@ using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
+using System.Linq;
using System.Xml.Linq;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Gui.OptionPanels;
+using ICSharpCode.SharpDevelop.Project.SavedData;
namespace ICSharpCode.SharpDevelop.Project
{
@@ -71,6 +73,7 @@ namespace ICSharpCode.SharpDevelop.Project
{
WorkbenchSingleton.AssertMainThread();
+ // breakpoints and files
Properties properties = new Properties();
properties.Set("bookmarks", ICSharpCode.SharpDevelop.Bookmarks.BookmarkManager.GetProjectBookmarks(this).ToArray());
List files = new List();
@@ -81,10 +84,15 @@ namespace ICSharpCode.SharpDevelop.Project
}
properties.Set("files", files.ToArray());
+ // web project properties
var webOptions = WebProjectsOptions.Instance.GetWebProjectOptions(Name);
if (webOptions != null)
properties.Set("WebProjectOptions", webOptions);
+ // other project data - logic in ProjectSavedDataConverter
+ properties.Set("projectSavedData_" + Name, SavedDataManager.GetSavedData()
+ .Where(d => d.ProjectName == Name).ToArray());
+
return properties;
}
@@ -99,7 +107,14 @@ namespace ICSharpCode.SharpDevelop.Project
filesToOpenAfterSolutionLoad.Add(fileName);
}
+ // web project properties
WebProjectsOptions.Instance.SetWebProjectOptions(Name, memento.Get("WebProjectOptions", new WebProjectOptions()) as WebProjectOptions);
+
+ // other project data - logic in ProjectSavedDataConverter
+ foreach(var data in memento.Get("projectSavedData_" + Name, new IProjectSavedData[0])
+ .Where(d => d.ProjectName == Name)) {
+ SavedDataManager.Add(data);
+ }
}
#endregion
diff --git a/src/Main/Base/Project/Src/Services/ProjectService/SavedData/IProjectSavedData.cs b/src/Main/Base/Project/Src/Services/ProjectService/SavedData/IProjectSavedData.cs
new file mode 100644
index 0000000000..f595ed5f8a
--- /dev/null
+++ b/src/Main/Base/Project/Src/Services/ProjectService/SavedData/IProjectSavedData.cs
@@ -0,0 +1,60 @@
+// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
+// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
+
+using System;
+using System.ComponentModel;
+using System.Collections.Generic;
+
+namespace ICSharpCode.SharpDevelop.Project.SavedData
+{
+ public enum ProjectSavedDataType
+ {
+ WatchVariables
+ }
+
+ ///
+ /// Interface for storing project specific data.
+ /// When implementing this, one should be carefull when and how
+ /// the SavedDataManager is used in order to not alter the other data.
+ ///
+ [TypeConverter(typeof(ProjectSavedDataConverter))]
+ public interface IProjectSavedData
+ {
+ ///
+ /// Saved data type.
+ ///
+ ProjectSavedDataType SavedDataType { get; }
+
+ ///
+ /// Saved data.
+ /// The format is: "ProjectName"|{0}|"ProjectSavedDataType"|{1}|(specific data splited by '|').
+ ///
+ string SavedString { get; set; }
+
+ ///
+ /// Gets the project name.
+ ///
+ string ProjectName { get; }
+ }
+
+ ///
+ /// Dummy data. Used to map the saved data and exposed to addins where project specific data can exist.
+ ///
+ public sealed class DummyProjectSavedData : IProjectSavedData
+ {
+ public ProjectSavedDataType SavedDataType { get; set; }
+
+ public string SavedString { get; set; }
+
+ public string ProjectName {
+ get {
+ if (string.IsNullOrEmpty(SavedString))
+ return string.Empty;
+
+ string[] v = SavedString.Split('|');
+
+ return v[1];
+ }
+ }
+ }
+}
diff --git a/src/Main/Base/Project/Src/Services/ProjectService/SavedData/ProjectSavedDataConverter.cs b/src/Main/Base/Project/Src/Services/ProjectService/SavedData/ProjectSavedDataConverter.cs
new file mode 100644
index 0000000000..8256ea7b43
--- /dev/null
+++ b/src/Main/Base/Project/Src/Services/ProjectService/SavedData/ProjectSavedDataConverter.cs
@@ -0,0 +1,54 @@
+// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
+// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
+
+using System;
+using System.ComponentModel;
+using System.Globalization;
+using System.Text;
+
+namespace ICSharpCode.SharpDevelop.Project.SavedData
+{
+ public sealed class ProjectSavedDataConverter : TypeConverter
+ {
+ public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
+ {
+ if (sourceType == typeof(string)) {
+ return true;
+ } else {
+ return base.CanConvertFrom(context, sourceType);
+ }
+ }
+
+ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
+ {
+ // convert from saved data(string) to objects
+ if (value is string) {
+ string[] v = ((string)value).Split('|');
+ ProjectSavedDataType type = (ProjectSavedDataType)Enum.Parse(typeof(ProjectSavedDataType), v[3]);
+ var data = new DummyProjectSavedData {
+ SavedString = (string)value,
+ SavedDataType = type
+ };
+ return data;
+ } else {
+ return base.ConvertFrom(context, culture, value);
+ }
+ }
+
+ public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
+ {
+ // convert objects to saved data(string)
+ var data = value as IProjectSavedData;
+ if (destinationType == typeof(string) && data != null) {
+ switch (data.SavedDataType) {
+ case ProjectSavedDataType.WatchVariables:
+ return data.SavedString;
+ default:
+ throw new Exception("Invalid value for ProjectSavedDataType");
+ }
+ } else {
+ return base.ConvertTo(context, culture, value, destinationType);
+ }
+ }
+ }
+}
diff --git a/src/Main/Base/Project/Src/Services/ProjectService/SavedData/SavedDataManager.cs b/src/Main/Base/Project/Src/Services/ProjectService/SavedData/SavedDataManager.cs
new file mode 100644
index 0000000000..2d7c6e735b
--- /dev/null
+++ b/src/Main/Base/Project/Src/Services/ProjectService/SavedData/SavedDataManager.cs
@@ -0,0 +1,81 @@
+// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
+// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
+
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+
+namespace ICSharpCode.SharpDevelop.Project.SavedData
+{
+ ///
+ /// Stores the project specific data.
+ ///
+ public static class SavedDataManager
+ {
+ static readonly List list;
+ static object _syncObject = new object();
+
+ static SavedDataManager()
+ {
+ list = new List();
+ ProjectService.SolutionClosed += delegate { list.Clear(); };
+ }
+
+ ///
+ /// Gets all saved data.
+ ///
+ ///
+ public static List GetSavedData()
+ {
+ return list;
+ }
+
+ ///
+ /// Adds a new data.
+ ///
+ ///
+ public static void Add(IProjectSavedData data)
+ {
+ if (data == null)
+ throw new ArgumentNullException("data");
+
+ if (!list.Contains(data)) {
+ lock (_syncObject) {
+ if (!list.Contains(data))
+ list.Add(data);
+ }
+ }
+ }
+
+ ///
+ /// Removes data.
+ ///
+ ///
+ public static void Remove(IProjectSavedData data)
+ {
+ if (data == null)
+ throw new ArgumentNullException("data");
+
+ if (list.Contains(data)) {
+ lock (_syncObject) {
+ if (list.Contains(data))
+ list.Remove(data);
+ }
+ }
+ }
+
+ ///
+ /// Removes all data that satisfies a predicate.
+ ///
+ ///
+ public static void RemoveAll(Predicate match)
+ {
+ if (match == null)
+ throw new ArgumentNullException("match");
+
+ lock (_syncObject) {
+ list.RemoveAll(match);
+ }
+ }
+ }
+}