diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/TreeModel/TreeNode.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/TreeModel/TreeNode.cs index ea2619da8f..27e9ca633e 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/TreeModel/TreeNode.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/TreeModel/TreeNode.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Drawing; +using ICSharpCode.SharpDevelop.Debugging; namespace Debugger.AddIn.TreeModel { @@ -14,7 +15,7 @@ namespace Debugger.AddIn.TreeModel /// A node in the variable tree. /// The node is imutable. /// - public class TreeNode: IComparable + public class TreeNode: IComparable, ITreeNode { Image image = null; string name = string.Empty; @@ -32,7 +33,8 @@ namespace Debugger.AddIn.TreeModel set { name = value; } } - public virtual string Text { + public virtual string Text + { get { return text; } protected set { text = value; } } @@ -47,9 +49,12 @@ namespace Debugger.AddIn.TreeModel protected set { childNodes = value; } } + IEnumerable ITreeNode.ChildNodes { + get { return this.childNodes; } + } + public TreeNode() { - } public TreeNode(Image image, string name, string text, string type, IEnumerable childNodes) diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/GridVisualizerWindow.xaml.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/GridVisualizerWindow.xaml.cs index e587fbb569..fd40d26d95 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/GridVisualizerWindow.xaml.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/GridVisualizerWindow.xaml.cs @@ -35,6 +35,10 @@ namespace Debugger.AddIn.Visualizers.GridVisualizer public GridVisualizerWindow() { InitializeComponent(); + + this.debuggerService = DebuggerService.CurrentDebugger as WindowsDebugger; + if (debuggerService == null) + throw new ApplicationException("Only windows debugger is currently supported"); } private void btnInspect_Click(object sender, RoutedEventArgs e) @@ -45,10 +49,6 @@ namespace Debugger.AddIn.Visualizers.GridVisualizer if (listViewScroller != null) listViewScroller.ScrollToVerticalOffset(0); - this.debuggerService = DebuggerService.CurrentDebugger as WindowsDebugger; - if (debuggerService == null) - throw new ApplicationException("Only windows debugger is currently supported"); - Value val = null; try { @@ -77,9 +77,9 @@ namespace Debugger.AddIn.Visualizers.GridVisualizer DebugType iEnumerableType, itemType; if (val.Type.ResolveIEnumerableImplementation(out iEnumerableType, out itemType)) { - var lazyListViewWrapper = new LazyItemsControl(this.listView); + var lazyListViewWrapper = new LazyItemsControl(this.listView, 24); var enumerableValuesProvider = new EnumerableValuesProvider(val.ExpressionTree, iEnumerableType, itemType); - lazyListViewWrapper.ItemsSource = enumerableValuesProvider.ItemsSource; + lazyListViewWrapper.ItemsSource = new VirtualizingIEnumerable(enumerableValuesProvider.ItemsSource); gridValuesProvider = enumerableValuesProvider; } else diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/LazyListView.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/LazyListView.cs index 9bbd217aeb..c5cc69fee1 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/LazyListView.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/LazyListView.cs @@ -10,58 +10,4 @@ using System.Windows.Controls; namespace Debugger.AddIn.Visualizers.GridVisualizer { - /// - /// ListView that takes VirtualizingIEnumerable as source, - /// and requests additional items from the source as needed when scrolling. - /// - public class LazyItemsControl - { - private ItemsControl itemsControl; - - public LazyItemsControl(ItemsControl wrappedItemsControl) - { - if (wrappedItemsControl == null) - throw new ArgumentNullException("wrappedListView"); - - this.itemsControl = wrappedItemsControl; - this.itemsControl.AddHandler(ScrollViewer.ScrollChangedEvent, new ScrollChangedEventHandler(handleListViewScroll)); - } - - - /// The collection that underlying ItemsControl sees. - private VirtualizingIEnumerable itemsSourceVirtualized; - - private IEnumerable itemsSource; - /// - /// IEnumerable providing all the items. LazyItemsControl pulls next items from this source when scrolled to bottom. - /// - public IEnumerable ItemsSource - { - get - { - return itemsSource; - } - set - { - this.itemsSource = value; - // virtualize IEnumerable and use it as ItemsControl source - // -> ItemsControl sees only a few items, more are added when scrolled to bottom - this.itemsSourceVirtualized = new VirtualizingIEnumerable(value); - this.itemsSourceVirtualized.AddNextItems(25); - this.itemsControl.ItemsSource = this.itemsSourceVirtualized; - } - } - - private void handleListViewScroll(object sender, ScrollChangedEventArgs e) - { - if (e.VerticalChange > 0) - { - // scrolled to bottom - if (e.VerticalOffset == this.itemsSourceVirtualized.Count - e.ViewportHeight) - { - this.itemsSourceVirtualized.AddNextItems(1); - } - } - } - } } diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/ValueProviders/VirtualizingIEnumerable.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/ValueProviders/VirtualizingIEnumerable.cs index 748948c3af..aa69f2d809 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/ValueProviders/VirtualizingIEnumerable.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/ValueProviders/VirtualizingIEnumerable.cs @@ -10,34 +10,5 @@ using System.Collections.ObjectModel; namespace Debugger.AddIn.Visualizers.GridVisualizer { - /// - /// A wrapper around IEnumerable<T> with RequestNextItems method for pulling additional items - /// from the IEnumerable<T> when needed. - /// Can be used as source for . - /// (Used to wrap EnumerableValuesProvider.ItemsSource) - /// - public class VirtualizingIEnumerable : ObservableCollection - { - private IEnumerator originalSourceEnumerator; - - public VirtualizingIEnumerable(IEnumerable originalSource) - { - if (originalSource == null) - throw new ArgumentNullException("originalSource"); - - this.originalSourceEnumerator = originalSource.GetEnumerator(); - } - - /// - /// Requests next items from underlying IEnumerable source and adds them to the collection. - /// - public void AddNextItems(int count) - { - for (int i = 0; i < count; i++) - { - if (!originalSourceEnumerator.MoveNext()) break; - this.Add(originalSourceEnumerator.Current); - } - } - } + } diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj index ec790d33de..291ff24730 100644 --- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj +++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj @@ -215,6 +215,14 @@ + + DebuggerTooltipControl.xaml + Code + + + + + @@ -772,6 +780,7 @@ + @@ -866,6 +875,7 @@ + diff --git a/src/Main/Base/Project/Src/Services/Debugger/DebuggerTooltipControl.xaml b/src/Main/Base/Project/Src/Services/Debugger/DebuggerTooltipControl.xaml new file mode 100644 index 0000000000..0792407e32 --- /dev/null +++ b/src/Main/Base/Project/Src/Services/Debugger/DebuggerTooltipControl.xaml @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Main/Base/Project/Src/Services/Debugger/DebuggerTooltipControl.xaml.cs b/src/Main/Base/Project/Src/Services/Debugger/DebuggerTooltipControl.xaml.cs new file mode 100644 index 0000000000..2ae7b1c88f --- /dev/null +++ b/src/Main/Base/Project/Src/Services/Debugger/DebuggerTooltipControl.xaml.cs @@ -0,0 +1,103 @@ +// +// +// +// +// $Revision$ +// +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; + +namespace ICSharpCode.SharpDevelop.Debugging +{ + /// + /// Default Control used as content of SharpDevelop debugger tooltips. + /// + public partial class DebuggerTooltipControl : UserControl, ITooltip + { + public DebuggerTooltipControl() + { + InitializeComponent(); + } + + private LazyItemsControl lazyGrid; + + private IEnumerable itemsSource; + public IEnumerable ItemsSource + { + set + { + this.itemsSource = value; + this.lazyGrid = new LazyItemsControl(this.dataGrid, 12); + lazyGrid.ItemsSource = new VirtualizingIEnumerable(value); + this.dataGrid.AddHandler(ScrollViewer.ScrollChangedEvent, new ScrollChangedEventHandler(handleScroll)); + + if (this.lazyGrid.ItemsSourceTotalCount != null) + { + btnUp.Visibility = btnDown.Visibility = + this.lazyGrid.ItemsSourceTotalCount.Value <= 10 ? Visibility.Collapsed : Visibility.Visible; + } + } + get + { + return this.itemsSource; + } + } + + /// + /// Determines whether DebuggerTooltipControl should be displayed in WPF Popup. + /// + public bool ShowAsPopup { + get { + return true; + } + } + + /// + /// Closes the debugger Popup containing this control. Also closes all child Popups. + /// + /// + public bool Close() + { + throw new NotImplementedException(); + } + + private void Expander_Click(object sender, RoutedEventArgs e) + { + var clickedButton = (ToggleButton)e.OriginalSource; + Point buttonPos = clickedButton.PointToScreen(new Point(0, 0)); + + if (clickedButton.IsChecked.GetValueOrDefault(false)) + { + // open child Popup + } + else + { + // close child Popups + } + } + + private void handleScroll(object sender, ScrollChangedEventArgs e) + { + btnUp.IsEnabled = !this.lazyGrid.IsScrolledToStart; + btnDown.IsEnabled = !this.lazyGrid.IsScrolledToEnd; + } + + void BtnUp_Click(object sender, RoutedEventArgs e) + { + this.lazyGrid.ScrollViewer.ScrollUp(1); + } + + void BtnDown_Click(object sender, RoutedEventArgs e) + { + this.lazyGrid.ScrollViewer.ScrollDown(1); + } + } +} \ No newline at end of file diff --git a/src/Main/Base/Project/Src/Services/Debugger/ITooltip.cs b/src/Main/Base/Project/Src/Services/Debugger/ITooltip.cs new file mode 100644 index 0000000000..d2d0d4dd62 --- /dev/null +++ b/src/Main/Base/Project/Src/Services/Debugger/ITooltip.cs @@ -0,0 +1,29 @@ +// +// +// +// +// $Revision$ +// +using System; + +namespace ICSharpCode.SharpDevelop.Debugging +{ + /// + /// Content of debugger tooltip, specifying whether it should be displayed in a WPF Popup. + /// + public interface ITooltip + { + /// + /// If true, this ITooltip will be displayed in a WPF Popup. + /// Otherwise this will be displayed in a WPF Tooltip. + /// WPF Popups are (unlike WPF Tooltips) focusable. + /// + bool ShowAsPopup { get; } + + /// + /// Closes this debugger tooltip. + /// + /// True if Close succeeded, false otherwise. + bool Close(); + } +} diff --git a/src/Main/Base/Project/Src/Services/Debugger/ITreeNode.cs b/src/Main/Base/Project/Src/Services/Debugger/ITreeNode.cs new file mode 100644 index 0000000000..f308e43c8a --- /dev/null +++ b/src/Main/Base/Project/Src/Services/Debugger/ITreeNode.cs @@ -0,0 +1,25 @@ +// +// +// +// +// $Revision$ +// +using System; +using System.Collections.Generic; + +namespace ICSharpCode.SharpDevelop.Debugging +{ + /// + /// Node that can be bound to DebuggerTooltipControl. + /// + public interface ITreeNode + { + string Name { get; } + + string Text { get; } + + string Type { get; } + + IEnumerable ChildNodes { get; } + } +} diff --git a/src/Main/Base/Project/Src/Services/Debugger/LazyItemsControl.cs b/src/Main/Base/Project/Src/Services/Debugger/LazyItemsControl.cs new file mode 100644 index 0000000000..65daca8c3b --- /dev/null +++ b/src/Main/Base/Project/Src/Services/Debugger/LazyItemsControl.cs @@ -0,0 +1,120 @@ +// +// +// +// +// $Revision$ +// +using System; +using System.Collections.Generic; +using System.Windows.Controls; + +namespace ICSharpCode.SharpDevelop.Debugging +{ + /// + /// ItemsControl wrapper that takes VirtualizingIEnumerable as source, + /// and adds additional items from the source to underlying ItemsControl when scrolled to bottom. + /// + public class LazyItemsControl + { + private ItemsControl itemsControl; + private int initialItemsCount; + + /// + /// Creates new instance of LazyItemsControl. + /// + /// ItemsControl to wrap and add items to it when scrolled to bottom. + /// Number of items to be initially displayed in wrapped ItemsControl. + public LazyItemsControl(ItemsControl wrappedItemsControl, int initialItemsCount) + { + if (wrappedItemsControl == null) + throw new ArgumentNullException("wrappedItemsControl"); + + this.initialItemsCount = initialItemsCount; + this.itemsControl = wrappedItemsControl; + this.itemsControl.AddHandler(ScrollViewer.ScrollChangedEvent, new ScrollChangedEventHandler(handleScroll)); + } + + private ScrollViewer scrollViewerCached; + public ScrollViewer ScrollViewer + { + get + { + if (this.scrollViewerCached == null) + this.scrollViewerCached = this.itemsControl.GetScrollViewer(); + return this.scrollViewerCached; + } + } + + public bool IsScrolledToStart + { + get + { + if (ScrollViewer == null) // Visual tree not initialized yet + return false; + return ScrollViewer.VerticalOffset == 0; + } + } + + public bool IsScrolledToEnd + { + get + { + if (itemsSourceTotalCount == null) { + // not scrolled to end of IEnumerable yet + return false; + } + // already scrolled to end of IEnumerable + int totalItems = itemsSourceTotalCount.Value; + return (ScrollViewer.VerticalOffset >= totalItems - ScrollViewer.ViewportHeight); + } + } + + private int? itemsSourceTotalCount = null; + /// Items count of underlying IEnumerable. Null until scrolled to the end of IEnumerable. + public int? ItemsSourceTotalCount + { + get + { + return this.itemsSourceTotalCount; + } + } + + private VirtualizingIEnumerable itemsSource; + /// The collection that underlying ItemsControl sees. + public VirtualizingIEnumerable ItemsSource + { + get + { + return itemsSource; + } + set + { + this.itemsSource = value; + addNextItems(this.itemsSource, initialItemsCount); + this.itemsControl.ItemsSource = value; + } + } + + private void addNextItems(VirtualizingIEnumerable sourceToAdd, int nItems) + { + sourceToAdd.AddNextItems(nItems); + if (!sourceToAdd.HasNext) + { + // all items from IEnumerable have been added + this.itemsSourceTotalCount = sourceToAdd.Count; + } + } + + private void handleScroll(object sender, ScrollChangedEventArgs e) + { + if (e.VerticalChange > 0) + { + // scrolled to bottom + if (e.VerticalOffset >= this.itemsSource.Count - e.ViewportHeight) + { + addNextItems(this.itemsSource, (int)e.VerticalChange); + } + } + } + } +} diff --git a/src/Main/Base/Project/Src/Services/Debugger/VirtualizingIEnumerable.cs b/src/Main/Base/Project/Src/Services/Debugger/VirtualizingIEnumerable.cs new file mode 100644 index 0000000000..fb601c0e1e --- /dev/null +++ b/src/Main/Base/Project/Src/Services/Debugger/VirtualizingIEnumerable.cs @@ -0,0 +1,58 @@ +// +// +// +// +// $Revision$ +// +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace ICSharpCode.SharpDevelop.Debugging +{ + /// + /// A wrapper around IEnumerable<T> with AddNextItems method for pulling additional items + /// from underlying IEnumerable<T>. + /// Can be used as source for . + /// + public class VirtualizingIEnumerable : ObservableCollection + { + private IEnumerator originalSourceEnumerator; + + public VirtualizingIEnumerable(IEnumerable originalSource) + { + if (originalSource == null) + throw new ArgumentNullException("originalSource"); + + this.originalSourceEnumerator = originalSource.GetEnumerator(); + } + + private bool hasNext = true; + /// + /// False if all items from underlying IEnumerable have already been added. + /// + public bool HasNext + { + get + { + return this.hasNext; + } + } + + /// + /// Requests next items from underlying IEnumerable source and adds them to the collection. + /// + public void AddNextItems(int count) + { + for (int i = 0; i < count; i++) + { + if (!originalSourceEnumerator.MoveNext()) + { + this.hasNext = false; + break; + } + this.Add(originalSourceEnumerator.Current); + } + } + } +} diff --git a/src/Main/Base/Project/Src/Util/ScrollUtils.cs b/src/Main/Base/Project/Src/Util/ScrollUtils.cs new file mode 100644 index 0000000000..abf9808ddb --- /dev/null +++ b/src/Main/Base/Project/Src/Util/ScrollUtils.cs @@ -0,0 +1,67 @@ +// +// +// +// +// $Revision$ +// +using System; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; + +namespace ICSharpCode.SharpDevelop +{ + /// + /// Scrolling related helpers. + /// + public static class ScrollUtils + { + /// + /// Searches VisualTree of given object for a ScrollViewer. + /// + public static ScrollViewer GetScrollViewer(this DependencyObject o) + { + var scrollViewer = o as ScrollViewer; + if (scrollViewer != null) { + return scrollViewer; + } + + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(o); i++) + { + var child = VisualTreeHelper.GetChild(o, i); + var result = GetScrollViewer(child); + if (result != null) { + return result; + } + } + return null; + } + + /// + /// Scrolls ScrollViewer up by given offset. + /// + /// Offset by which to scroll up. Should be positive. + public static void ScrollUp(this ScrollViewer scrollViewer, double offset) + { + ScrollUtils.ScrollByVerticalOffset(scrollViewer, -offset); + } + + /// + /// Scrolls ScrollViewer down by given offset. + /// + /// Offset by which to scroll down. Should be positive. + public static void ScrollDown(this ScrollViewer scrollViewer, double offset) + { + ScrollUtils.ScrollByVerticalOffset(scrollViewer, offset); + } + + /// + /// Scrolls ScrollViewer by given vertical offset. + /// + public static void ScrollByVerticalOffset(this ScrollViewer scrollViewer, double offset) + { + scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + offset); + } + } +}