diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Debugger.AddIn.csproj b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Debugger.AddIn.csproj index 4da39c6ba2..b00fb63f24 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Debugger.AddIn.csproj +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Debugger.AddIn.csproj @@ -58,7 +58,6 @@ - Configuration\GlobalAssemblyInfo.cs @@ -66,11 +65,12 @@ - + + @@ -104,11 +104,6 @@ False False - - {B08385CD-F0CC-488C-B4F4-EEB34B6D2688} - TreeListView - False - {924EE450-603D-49C1-A8E5-4AFAA31CE6F3} @@ -123,6 +118,10 @@ + + {E73BB233-D88B-44A7-A98F-D71EE158381D} + Aga.Controls + diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Pads/DebuggerTreeListView.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Pads/DebuggerTreeListView.cs deleted file mode 100644 index 34e7b05a10..0000000000 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Pads/DebuggerTreeListView.cs +++ /dev/null @@ -1,37 +0,0 @@ -// -// -// -// -// $Revision$ -// - -using System; -using System.Windows.Forms; - -namespace ICSharpCode.SharpDevelop.Gui.Pads -{ - public class DebuggerTreeListView: TreeListView - { - static int updateInterval = 100; // ms - - Timer refreshingTimer; - - public DebuggerTreeListView() - { - refreshingTimer = new Timer(); - refreshingTimer.Interval = updateInterval; - refreshingTimer.Tick += delegate { - refreshingTimer.Enabled = false; - this.EndUpdate(); - }; - } - - public void DelayRefresh() - { - if (!refreshingTimer.Enabled) { - this.BeginUpdate(); - refreshingTimer.Enabled = true; - } - } - } -} diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Pads/LocalVarPad.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Pads/LocalVarPad.cs index d1923d11a2..24df9ebdae 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Pads/LocalVarPad.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Pads/LocalVarPad.cs @@ -6,22 +6,66 @@ // using System; +using System.Collections.Generic; using System.Windows.Forms; using ICSharpCode.Core; +using Aga.Controls.Tree; +using Aga.Controls.Tree.NodeControls; + using Debugger; namespace ICSharpCode.SharpDevelop.Gui.Pads { public class LocalVarPad : DebuggerPad { - DebuggerTreeListView localVarList; + class ItemIcon: NodeIcon { + protected override System.Drawing.Image GetIcon(TreeNodeAdv node) + { + return ((TreeViewNode)node).Icon; + } + } + + class ItemName: NodeTextBox { + protected override bool CanEdit(TreeNodeAdv node) + { + return false; + } + public override object GetValue(TreeNodeAdv node) + { + return ((TreeViewNode)node).Name; + } + } + + class ItemText: NodeTextBox { + protected override bool CanEdit(TreeNodeAdv node) + { + return ((TreeViewNode)node).CanEditText; + } + public override object GetValue(TreeNodeAdv node) + { + return ((TreeViewNode)node).Text; + } + } + + class ItemType: NodeTextBox { + protected override bool CanEdit(TreeNodeAdv node) + { + return false; + } + public override object GetValue(TreeNodeAdv node) + { + return ((TreeViewNode)node).Type; + } + } + + TreeViewAdv localVarList; Debugger.Process debuggedProcess; - ColumnHeader name = new ColumnHeader(); - ColumnHeader val = new ColumnHeader(); - ColumnHeader type = new ColumnHeader(); + TreeColumn nameColumn = new TreeColumn(); + TreeColumn valColumn = new TreeColumn(); + TreeColumn typeColumn = new TreeColumn(); public override Control Control { get { @@ -31,39 +75,53 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads protected override void InitializeComponents() { - //iconsService = (ClassBrowserIconsService)ServiceManager.Services.GetService(typeof(ClassBrowserIconsService)); - localVarList = new DebuggerTreeListView(); - localVarList.SmallImageList = DebuggerIcons.ImageList; - localVarList.ShowPlusMinus = true; - localVarList.FullRowSelect = true; - localVarList.Dock = DockStyle.Fill; - localVarList.Sorting = SortOrder.Ascending; - //localVarList.GridLines = false; - //localVarList.Activation = ItemActivation.OneClick; - localVarList.Columns.AddRange(new ColumnHeader[] {name, val, type} ); - name.Width = 250; - val.Width = 300; - type.Width = 250; - localVarList.Visible = false; - localVarList.SizeChanged += new EventHandler(localVarList_SizeChanged); - localVarList.BeforeExpand += new TreeListViewCancelEventHandler(localVarList_BeforeExpand); - localVarList.AfterExpand += new TreeListViewEventHandler(localVarList_AfterExpand); + localVarList = new TreeViewAdv(); + localVarList.Columns.Add(nameColumn); + localVarList.Columns.Add(valColumn); + localVarList.Columns.Add(typeColumn); + localVarList.UseColumns = true; + localVarList.SelectionMode = TreeSelectionMode.Single; + localVarList.LoadOnDemand = true; + localVarList.VisibleChanged += delegate { if (localVarList.Visible) RefreshPad(); }; + localVarList.SizeChanged += delegate { RefreshPad(); }; + + localVarList.Expanding += delegate(object sender, TreeViewAdvEventArgs e) { + if (e.Node is TreeViewNode) ((TreeViewNode)e.Node).OnExpanding(); + }; + localVarList.Expanded += delegate(object sender, TreeViewAdvEventArgs e) { + if (e.Node is TreeViewNode) ((TreeViewNode)e.Node).OnExpanded(); + }; + localVarList.Collapsed += delegate(object sender, TreeViewAdvEventArgs e) { + if (e.Node is TreeViewNode) ((TreeViewNode)e.Node).OnCollapsed(); + }; + + NodeIcon iconControl = new ItemIcon(); + iconControl.ParentColumn = nameColumn; + localVarList.NodeControls.Add(iconControl); + NodeTextBox nameControl = new ItemName(); + nameControl.ParentColumn = nameColumn; + localVarList.NodeControls.Add(nameControl); + + NodeTextBox textControl = new ItemText(); + textControl.ParentColumn = valColumn; + localVarList.NodeControls.Add(textControl); + + NodeTextBox typeControl = new ItemType(); + typeControl.ParentColumn = typeColumn; + localVarList.NodeControls.Add(typeControl); RedrawContent(); } public override void RedrawContent() { - name.Text = ResourceService.GetString("Global.Name"); - val.Text = ResourceService.GetString("Dialog.HighlightingEditor.Properties.Value"); - type.Text = ResourceService.GetString("ResourceEditor.ResourceEdit.TypeColumn"); - } - - // This is a walkarond for a visual issue - void localVarList_SizeChanged(object sender, EventArgs e) - { - localVarList.Visible = true; + nameColumn.Header = ResourceService.GetString("Global.Name"); + nameColumn.Width = 250; + valColumn.Header = ResourceService.GetString("Dialog.HighlightingEditor.Properties.Value"); + valColumn.Width = 300; + typeColumn.Header = ResourceService.GetString("ResourceEditor.ResourceEdit.TypeColumn"); + typeColumn.Width = 250; } protected override void SelectProcess(Debugger.Process process) @@ -85,37 +143,14 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads public override void RefreshPad() { - localVarList.BeginUpdate(); - localVarList.Items.Clear(); - if (debuggedProcess != null) { - foreach(NamedValue val in debuggedProcess.LocalVariables) { - localVarList.Items.Add(new TreeListViewDebuggerItem(val)); - } - } - localVarList.EndUpdate(); - } - - void localVarList_BeforeExpand(object sender, TreeListViewCancelEventArgs e) - { - if (debuggedProcess.IsPaused) { - ((TreeListViewDebuggerItem)e.Item).Populate(); + DateTime start = Debugger.Util.HighPrecisionTimer.Now; + if (debuggedProcess != null && debuggedProcess.SelectedFunction != null) { + TreeViewNode.UpdateNodes(localVarList, localVarList.Root.Children, new FunctionItem(debuggedProcess.SelectedFunction).SubItems); } else { - MessageService.ShowMessage("${res:MainWindow.Windows.Debug.LocalVariables.CannotExploreVariablesWhileRunning}"); - e.Cancel = true; - } - } - - void localVarList_AfterExpand(object sender, TreeListViewEventArgs e) - { - UpdateSubTree(e.Item); - } - - static void UpdateSubTree(TreeListViewItem tree) - { - foreach(TreeListViewItem item in tree.Items) { - ((TreeListViewDebuggerItem)item).Update(); - if (item.IsExpanded) UpdateSubTree(item); + TreeViewNode.UpdateNodes(localVarList, localVarList.Root.Children, new ListItem[0]); } + DateTime end = Debugger.Util.HighPrecisionTimer.Now; + LoggingService.InfoFormatted("Local Variables pad refreshed ({0} ms)", (end - start).TotalMilliseconds); } } } diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Pads/TreeListViewDebuggerItem.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Pads/TreeListViewDebuggerItem.cs deleted file mode 100644 index bf39a4b99d..0000000000 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Pads/TreeListViewDebuggerItem.cs +++ /dev/null @@ -1,88 +0,0 @@ -// -// -// -// -// $Revision$ -// - -using System; -using System.Drawing; -using System.Windows.Forms; - -using Debugger; - -namespace ICSharpCode.SharpDevelop.Gui.Pads -{ - public class TreeListViewDebuggerItem: TreeListViewItem - { - ListItem listItem; - - bool populated = false; - - public ListItem ListItem { - get { - return listItem; - } - } - - bool IsVisible { - get { - if (this.Parent == null) { - return true; - } else { - foreach(TreeListViewItem parent in this.ParentsInHierarch) { - if (!parent.IsExpanded) return false; - } - return true; - } - } - } - - public TreeListViewDebuggerItem(NamedValue val): this(new ValueItem(val)) - { - - } - - public TreeListViewDebuggerItem(ListItem listItem) - { - this.listItem = listItem; - - listItem.Changed += delegate { Update(); }; - - SubItems.Add(""); - SubItems.Add(""); - - Update(); - } - - public void Update() - { - if (!IsVisible) return; - - if (this.TreeListView != null) { - ((DebuggerTreeListView)this.TreeListView).DelayRefresh(); - } - - this.ImageIndex = listItem.ImageIndex; - this.SubItems[0].Text = listItem.Name; - this.SubItems[1].Text = listItem.Text; - this.SubItems[2].Text = listItem.Type; - - if (!IsExpanded && !populated && listItem.HasSubItems) { - Items.Add(new TreeListViewItem()); // Show plus sign - } - } - - public void Populate() - { - if (!populated) { - Items.Clear(); - this.Items.SortOrder = SortOrder.None; - foreach(ListItem subItem in listItem.SubItems) { - Items.Add(new TreeListViewDebuggerItem(subItem)); - } - populated = true; - } - } - } -} diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Variables/FunctionItem.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Variables/FunctionItem.cs new file mode 100644 index 0000000000..bcf980e4cc --- /dev/null +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Variables/FunctionItem.cs @@ -0,0 +1,77 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; + +namespace Debugger +{ + public class FunctionItem: ListItem + { + Function function; + + public Function Function { + get { + return function; + } + } + + public override int ImageIndex { + get { + return -1; + } + } + + public override string Name { + get { + return function.Name; + } + } + + public override string Text { + get { + return String.Empty; + } + } + + public override bool CanEditText { + get { + return false; + } + } + + public override string Type { + get { + return String.Empty; + } + } + + public override bool HasSubItems { + get { + return true; + } + } + + public override IList SubItems { + get { + List ret = new List(); + foreach(NamedValue val in function.LocalVariables) { + ret.Add(new ValueItem(val)); + } + return ret.AsReadOnly(); + } + } + + public FunctionItem(Function function) + { + this.function = function; + this.function.Process.DebuggeeStateChanged += delegate { + this.OnChanged(new ListItemEventArgs(this)); + }; + } + } +} diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Variables/TreeViewNode.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Variables/TreeViewNode.cs new file mode 100644 index 0000000000..c043a36c66 --- /dev/null +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Variables/TreeViewNode.cs @@ -0,0 +1,197 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Drawing; +using System.Windows.Forms; + +using Aga.Controls.Tree; + +using ICSharpCode.Core; + +namespace Debugger +{ + public partial class TreeViewNode: TreeNodeAdv + { + ListItem content; + Image icon; + string name; + string text; + bool canEditText; + string type; + + public ListItem Content { + get { + return content; + } + set { + if (content != null) { + content.Changed -= OnContentChanged; + } + content = value; + if (content != null) { + content.Changed += OnContentChanged; + } + Update(); + } + } + + public Image Icon { + get { return icon; } + } + + public string Name { + get { return name; } + } + + public string Text { + get { return text; } + } + + public bool CanEditText { + get { return canEditText; } + } + + public string Type { + get { return type; } + } + + void OnContentChanged(object sender, ListItemEventArgs e) + { + //Update(); + } + + public TreeViewNode(TreeViewAdv tree, ListItem content): base(tree, new object()) + { + this.Content = content; + } + + public void Update() + { + DoApplicationEvents(); + + DateTime start = Debugger.Util.HighPrecisionTimer.Now; + + this.IsLeaf = !Content.HasSubItems; + this.icon = content.Image; + this.name = content.Name; + this.text = content.Text; + this.canEditText = content.CanEditText; + this.type = content.Type; + //DateTime time = Debugger.Util.HighPrecisionTimer.Now; + //this.type = time.ToLongTimeString() + "." + time.Millisecond.ToString(); + + DateTime end = Debugger.Util.HighPrecisionTimer.Now; + + LoggingService.InfoFormatted("Updated node {0} ({1} ms)", FullName, (end - start).TotalMilliseconds); + + if (this.IsExpanded) { + UpdateNodes(Tree, this.Children, Content.SubItems); + } else { + Children.Clear(); + populated = false; + } + + this.Tree.FullUpdate(); + } + + public static void UpdateNodes(TreeViewAdv tree, Collection collection, IList contents) + { + // Add or overwrite existing items + for(int i = 0; i < contents.Count; i++) { + if (i < collection.Count) { + // Overwrite + ((TreeViewNode)collection[i]).Content = contents[i]; + } else { + // Add + collection.Add(new TreeViewNode(tree, contents[i])); + } + } + // Delete other nodes + while(collection.Count > contents.Count) { + collection.RemoveAt(collection.Count - 1); + } + + tree.FullUpdate(); + } + + bool populated = false; + + public void OnExpanding() + { + if (!populated) { + foreach(ListItem item in Content.SubItems) { + Children.Add(new TreeViewNode(Tree, item)); + } + populated = true; + this.IsExpandedOnce = true; + this.Tree.UpdateSelection(); + this.Tree.FullUpdate(); + } + } + + #region DoApplicationEvents() + + static DateTime nextDoEventsTime = Debugger.Util.HighPrecisionTimer.Now; + const double workLoad = 0.75; // Fraction of getting variables vs. repainting + const double maxFPS = 30; // ms this prevents too much drawing on good machine + const double maxWorkTime = 250; // ms this ensures minimal response on bad machine + + void DoApplicationEvents() + { + if (Debugger.Util.HighPrecisionTimer.Now > nextDoEventsTime) { + DateTime start = Debugger.Util.HighPrecisionTimer.Now; + Application.DoEvents(); + DateTime end = Debugger.Util.HighPrecisionTimer.Now; + double doEventsDuration = (end - start).TotalMilliseconds; + double minWorkTime = 1000 / maxFPS - doEventsDuration; // ms + double workTime = (doEventsDuration / (1 - workLoad)) * workLoad; + workTime = Math.Max(minWorkTime, Math.Min(maxWorkTime, workTime)); // Clamp + nextDoEventsTime = end.AddMilliseconds(workTime); + double fps = 1000 / (doEventsDuration + workTime); + LoggingService.InfoFormatted("Rendering: {0} ms => work budget: {1} ms ({2:f1} FPS)", doEventsDuration, workTime, fps); + } + } + + #endregion + + #region Maintain expanded state + + static Dictionary expandedNodes = new Dictionary(); + + string FullName { + get { + if (this.Parent != null && this.Parent is TreeViewNode) { + return ((TreeViewNode)this.Parent).FullName + "." + Content.Name; + } else { + return Content.Name; + } + } + } + + public void OnExpanded() + { + expandedNodes[FullName] = true; + // Expand children as well + foreach(TreeViewNode child in Children) { + string name = child.FullName; + if (expandedNodes.ContainsKey(name) && expandedNodes[name]) { + child.IsExpanded = true; + } + } + } + + public void OnCollapsed() + { + expandedNodes[FullName] = false; + } + + #endregion + } +} diff --git a/src/Libraries/TreeViewAdv/Aga.Controls/Tree/TreeNodeAdv.cs b/src/Libraries/TreeViewAdv/Aga.Controls/Tree/TreeNodeAdv.cs index c6356275a4..8c2da110fe 100644 --- a/src/Libraries/TreeViewAdv/Aga.Controls/Tree/TreeNodeAdv.cs +++ b/src/Libraries/TreeViewAdv/Aga.Controls/Tree/TreeNodeAdv.cs @@ -10,7 +10,7 @@ using System.Security.Permissions; namespace Aga.Controls.Tree { [Serializable] - public sealed class TreeNodeAdv: ISerializable + public class TreeNodeAdv: ISerializable { #region NodeCollection //TODO: use one common Parent-Children collection @@ -61,12 +61,12 @@ namespace Aga.Controls.Tree #endregion private Collection _nodes; - private ReadOnlyCollection _children; + private Collection _children; #region Properties private TreeViewAdv _tree; - internal TreeViewAdv Tree + public TreeViewAdv Tree { get { return _tree; } } @@ -121,14 +121,14 @@ namespace Aga.Controls.Tree public bool IsLeaf { get { return _isLeaf; } - internal set { _isLeaf = value; } + set { _isLeaf = value; } } private bool _isExpandedOnce; public bool IsExpandedOnce { get { return _isExpandedOnce; } - internal set { _isExpandedOnce = value; } + set { _isExpandedOnce = value; } } private bool _isExpanded; @@ -217,6 +217,7 @@ namespace Aga.Controls.Tree public object Tag { get { return _tag; } + set { _tag = value; } } internal Collection Nodes @@ -224,7 +225,7 @@ namespace Aga.Controls.Tree get { return _nodes; } } - public ReadOnlyCollection Children + public Collection Children { get { @@ -238,12 +239,12 @@ namespace Aga.Controls.Tree { } - internal TreeNodeAdv(TreeViewAdv tree, object tag) + public TreeNodeAdv(TreeViewAdv tree, object tag) { _row = -1; _tree = tree; _nodes = new NodeCollection(this); - _children = new ReadOnlyCollection(_nodes); + _children = _nodes; _tag = tag; } diff --git a/src/Libraries/TreeViewAdv/Aga.Controls/Tree/TreeViewAdv.cs b/src/Libraries/TreeViewAdv/Aga.Controls/Tree/TreeViewAdv.cs index e391885866..9ea9cdb450 100644 --- a/src/Libraries/TreeViewAdv/Aga.Controls/Tree/TreeViewAdv.cs +++ b/src/Libraries/TreeViewAdv/Aga.Controls/Tree/TreeViewAdv.cs @@ -466,7 +466,7 @@ namespace Aga.Controls.Tree return Math.Sqrt(Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2)); } - internal void FullUpdate() + public void FullUpdate() { _rowLayout.ClearCache(); CreateRowMap(); @@ -475,7 +475,7 @@ namespace Aga.Controls.Tree _needFullUpdate = false; } - internal void UpdateView() + public void UpdateView() { if (!_suspendUpdate) Invalidate(false); @@ -648,7 +648,7 @@ namespace Aga.Controls.Tree return node == _root; } - private void UpdateSelection() + public void UpdateSelection() { bool flag = false;