#develop (short for SharpDevelop) is a free IDE for .NET programming languages.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

210 lines
6.0 KiB

// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// 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.Collections.Specialized;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Threading;
using System.Xml.Serialization;
using Debugger;
using Debugger.AddIn;
using Debugger.AddIn.Pads.Controls;
using Debugger.AddIn.TreeModel;
using ICSharpCode.Core;
using ICSharpCode.Core.Presentation;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Services;
using Exception = System.Exception;
namespace ICSharpCode.SharpDevelop.Gui.Pads
{
public class WatchPad : AbstractPadContent
{
DockPanel panel;
WatchList watchList;
static WatchPad instance;
public override object Control {
get { return panel; }
}
/// <remarks>Always check if Instance is null, might be null if pad is not opened!</remarks>
public static WatchPad Instance {
get { return instance; }
}
public WatchList WatchList {
get {
return watchList;
}
}
public WatchPad()
{
this.panel = new DockPanel();
instance = this;
watchList = new WatchList(WatchListType.Watch);
watchList.ContextMenu = MenuService.CreateContextMenu(this, "/SharpDevelop/Pads/WatchPad/ContextMenu");
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.ProjectAdded += delegate { LoadSavedNodes(); };
ProjectService.SolutionLoaded += delegate { LoadSavedNodes(); };
WindowsDebugger.RefreshingPads += RefreshPad;
WindowsDebugger.RefreshPads();
}
#region Saved nodes
void LoadSavedNodes()
{
var props = GetSavedVariablesProperties();
if (props == null)
return;
foreach (var element in props.Elements) {
watchList.WatchItems.Add(new TreeNode(element, null).ToSharpTreeNode());
}
}
void OnWatchItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
var props = GetSavedVariablesProperties();
if (props == null) return;
if (e.Action == NotifyCollectionChangedAction.Add) {
// add to saved data
foreach(var data in e.NewItems.OfType<TreeNode>()) {
props.Set(data.Name, (object)null);
}
}
if (e.Action == NotifyCollectionChangedAction.Remove) {
// remove from saved data
foreach(var data in e.OldItems.OfType<TreeNode>()) {
props.Remove(data.Name);
}
}
}
Properties GetSavedVariablesProperties()
{
if (ProjectService.CurrentProject == null)
return null;
if (ProjectService.CurrentProject.ProjectSpecificProperties == null)
return null;
var props = ProjectService.CurrentProject.ProjectSpecificProperties.Get("watchVars") as Properties;
if (props == null) {
ProjectService.CurrentProject.ProjectSpecificProperties.Set("watchVars", new Properties());
}
return ProjectService.CurrentProject.ProjectSpecificProperties.Get("watchVars") as Properties;
}
#endregion
void panel_KeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Insert) {
AddNewWatch();
e.Handled = true;
}
}
void watchList_KeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Delete) {
RemoveWatchCommand cmd = new RemoveWatchCommand { Owner = this };
cmd.Run();
}
}
void watchList_DoubleClick(object sender, MouseEventArgs e)
{
if (watchList.SelectedNode == null)
{
AddNewWatch();
}
}
void AddNewWatch()
{
AddWatchCommand command = new AddWatchCommand { Owner = this };
command.Run();
}
void ResetPad(object sender, EventArgs e)
{
string language = "CSharp";
if (ProjectService.CurrentProject != null)
language = ProjectService.CurrentProject.Language;
// rebuild list
var nodes = new List<TreeNodeWrapper>();
foreach (var nod in watchList.WatchItems.OfType<TreeNodeWrapper>())
nodes.Add(new TreeNode(nod.Node.Name, null).ToSharpTreeNode());
watchList.WatchItems.Clear();
foreach (var nod in nodes)
watchList.WatchItems.Add(nod);
}
TreeNodeWrapper UpdateNode(TreeNodeWrapper node, Process process)
{
try {
LoggingService.Info("Evaluating: " + (string.IsNullOrEmpty(node.Node.Name) ? "is null or empty!" : node.Node.Name));
//Value val = ExpressionEvaluator.Evaluate(nod.Name, nod.Language, debuggedProcess.SelectedStackFrame);
ValueNode valNode = new ValueNode(null, node.Node.Name, () => ((WindowsDebugger)DebuggerService.CurrentDebugger).GetExpression(node.Node.Name).Evaluate(process));
return valNode.ToSharpTreeNode();
} catch (GetValueException) {
string error = String.Format(StringParser.Parse("${res:MainWindow.Windows.Debug.Watch.InvalidExpression}"), node.Node.Name);
TreeNode infoNode = new TreeNode("Icons.16x16.Error", node.Node.Name, error, string.Empty, null);
return infoNode.ToSharpTreeNode();
}
}
protected void RefreshPad(object sender, DebuggerEventArgs dbg)
{
Process debuggedProcess = dbg.Process;
ResetPad(null, null);
if (debuggedProcess == null || debuggedProcess.IsRunning)
return;
using(new PrintTimes("Watch Pad refresh")) {
var nodes = watchList.WatchItems.OfType<TreeNodeWrapper>().ToArray();
watchList.WatchItems.Clear();
debuggedProcess.EnqueueForEach(
Dispatcher.CurrentDispatcher,
nodes,
n => watchList.WatchItems.Add(UpdateNode(n, debuggedProcess))
);
}
}
}
}