diff --git a/data/resources/StringResources.resx b/data/resources/StringResources.resx index 98bace9f94..ac4d13f4e8 100644 --- a/data/resources/StringResources.resx +++ b/data/resources/StringResources.resx @@ -4500,6 +4500,9 @@ has been changed externally do you want to reload it? Unhandled exception has occured + + Saved + Can't deserialize form. Possible reason: Initialize component method was changed manually. diff --git a/data/resources/image/BitmapResources/BitmapResources-data/Icons.16x16.Refresh.png b/data/resources/image/BitmapResources/BitmapResources-data/Icons.16x16.Refresh.png new file mode 100644 index 0000000000..51c3c653ce Binary files /dev/null and b/data/resources/image/BitmapResources/BitmapResources-data/Icons.16x16.Refresh.png differ diff --git a/data/resources/image/BitmapResources/BitmapResources.res b/data/resources/image/BitmapResources/BitmapResources.res index eaf2aa2126..c409431afa 100644 --- a/data/resources/image/BitmapResources/BitmapResources.res +++ b/data/resources/image/BitmapResources/BitmapResources.res @@ -226,6 +226,7 @@ Icons.16x16.OpenFileIcon = BitmapResources-data\Icons.1 Icons.16x16.HtmlElements.FieldSetElement = BitmapResources-data\Icons.16x16.HtmlElements.FieldSetElement.png Icons.16x16.SplitWindow = BitmapResources-data\Icons.16x16.SplitWindow.png Icons.16x16.DeleteHistory = BitmapResources-data\Icons.16x16.DeleteHistory.png +Icons.16x16.Refresh = BitmapResources-data\Icons.16x16.Refresh.png #pad icons PadIcons.ErrorList = PadIcons\ErrorList.png @@ -347,6 +348,8 @@ Bookmarks.DisableAllBreakpoints = Bookmarks\DisableAllBreakpoi Bookmarks.NextBreakpoint = Bookmarks\NextBreakpoint.png Bookmarks.PrevBreakpoint = Bookmarks\PrevBreakpoint.png +Bookmarks.Pin = Bookmarks\Pin.png + #backend icons C#.ProjectIcon = backendicons\CSharp\SmallProject.png C#.FileIcon = backendicons\CSharp\SmallFile.png diff --git a/data/resources/image/BitmapResources/Bookmarks/Pin.png b/data/resources/image/BitmapResources/Bookmarks/Pin.png new file mode 100644 index 0000000000..a93b751c8b Binary files /dev/null and b/data/resources/image/BitmapResources/Bookmarks/Pin.png differ diff --git a/src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin b/src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin index 3d4cc96e78..89209b2151 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin +++ b/src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin @@ -14,7 +14,14 @@ - + + + + + 3.0 - - 3.0 - 4.0 @@ -160,7 +157,26 @@ EditBreakpointScriptWindow.xaml Code + + + DebuggerTooltipControl.xaml + + + + PinCloseControl.xaml + + + PinDebuggerControl.xaml + + + + + + VisualizerPicker.xaml + + + @@ -252,7 +268,6 @@ - Component @@ -304,6 +319,7 @@ + @@ -354,6 +370,11 @@ + + + + + @@ -375,6 +396,7 @@ False + diff --git a/src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/WatchList.xaml.cs b/src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/WatchList.xaml.cs index 8e793188cf..82ce6d4bd0 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/WatchList.xaml.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/WatchList.xaml.cs @@ -11,6 +11,7 @@ using System.Windows.Input; using System.Windows.Media; using Debugger.AddIn.TreeModel; +using ICSharpCode.SharpDevelop.Debugging; namespace Debugger.AddIn.Pads.Controls { diff --git a/src/AddIns/Debugger/Debugger.AddIn/Pads/LocalVarPad.cs b/src/AddIns/Debugger/Debugger.AddIn/Pads/LocalVarPad.cs index 4b64b1caea..c2669f3ce7 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Pads/LocalVarPad.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Pads/LocalVarPad.cs @@ -7,6 +7,7 @@ using Debugger.AddIn.Pads.Controls; using Debugger.AddIn.TreeModel; using ICSharpCode.Core; using Exception = System.Exception; +using TreeNode = Debugger.AddIn.TreeModel.TreeNode; namespace ICSharpCode.SharpDevelop.Gui.Pads { diff --git a/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPad.cs b/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPad.cs index e6e43021b2..5ff26e1fbc 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPad.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPad.cs @@ -15,6 +15,7 @@ using ICSharpCode.Core.Presentation; using ICSharpCode.NRefactory; using ICSharpCode.SharpDevelop.Project; using Exception = System.Exception; +using ICSharpCode.SharpDevelop.Debugging; namespace ICSharpCode.SharpDevelop.Gui.Pads { diff --git a/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPadCommands.cs b/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPadCommands.cs index 7e48745708..d5723c9858 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPadCommands.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPadCommands.cs @@ -17,6 +17,7 @@ using ICSharpCode.NRefactory; using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Gui.Pads; using ICSharpCode.SharpDevelop.Project; +using ICSharpCode.SharpDevelop.Debugging; namespace Debugger.AddIn { diff --git a/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPadModel.cs b/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPadModel.cs index 84fbf600ee..ce3906bf27 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPadModel.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPadModel.cs @@ -1,17 +1,14 @@ // 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 ICSharpCode.NRefactory; using System; -using System.Windows.Forms; -using Aga.Controls.Tree; -using Aga.Controls.Tree.NodeControls; using Debugger.AddIn.TreeModel; -using TreeNode = Debugger.AddIn.TreeModel.TreeNode; +using ICSharpCode.NRefactory; +using ICSharpCode.SharpDevelop.Debugging; namespace ICSharpCode.SharpDevelop.Gui.Pads { - public class TextNode : Debugger.AddIn.TreeModel.TreeNode, ISetText + public class TextNode : TreeNode, ISetText { public TextNode(string text, SupportedLanguage language) { @@ -25,7 +22,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads } } - public new bool SetText(string text) + public override bool SetText(string text) { this.Text = text; return true; @@ -47,62 +44,4 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads IconImage = DebuggerResourceService.GetImage("Icons.16x16.Error"); } } - - public sealed class WatchItemName: NodeTextBox { - public WatchItemName() - { - this.EditEnabled = true; - this.EditOnClick = true; - } - protected override bool CanEdit(TreeNodeAdv node) - { - TreeNode content = ((TreeViewVarNode)node).Content; - return (content is ISetText) && ((ISetText)content).CanSetText; - } - public override object GetValue(TreeNodeAdv node) - { - if (node is TreeViewVarNode) { - return ((TreeViewVarNode)node).Content.Name; - } else { - // Happens during incremental search - return base.GetValue(node); - } - } - public override void SetValue(TreeNodeAdv node, object value) - { - if (string.IsNullOrEmpty(value as string)) - MessageBox.Show("You can not set name to an empty string!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - else - { -// if (((TreeViewVarNode)node).Content is ExpressionNode) { -// WatchPad.Instance.Watches.RemoveAll(item => item.Name == ((ExpressionNode)((TreeViewVarNode)node).Content).Name); -// ((ExpressionNode)((TreeViewVarNode)node).Content).Name = value.ToString(); -// } else { -// if (((TreeViewVarNode)node).Content is TextNode) { -// WatchPad.Instance.Watches.RemoveAll(item => item.Name == ((TextNode)((TreeViewVarNode)node).Content).Name); -// ((TextNode)((TreeViewVarNode)node).Content).Name = value.ToString(); -// } -// } -// -// WatchPad.Instance.Watches.Add(new TextNode(value as string, SupportedLanguage.CSharp)); - } - } - public override void MouseDown(TreeNodeAdvMouseEventArgs args) - { - if (args.Node == null) { - base.MouseDown(args); - return; - } - TreeNode content = ((TreeViewVarNode)args.Node).Content; - if (content is IContextMenu && args.Button == MouseButtons.Right) { - ContextMenuStrip menu = ((IContextMenu)content).GetContextMenu(); - if (menu != null) { - menu.Show(args.Node.Tree, args.Location); - args.Handled = true; - } - } else { - base.MouseDown(args); - } - } - } } diff --git a/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs b/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs index 5e62a70437..70cb6d607e 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs @@ -11,7 +11,7 @@ using System.Text; using System.Windows.Forms; using Debugger; -using Debugger.AddIn; +using Debugger.AddIn.Tooltips; using Debugger.AddIn.TreeModel; using Debugger.Interop.CorPublish; using ICSharpCode.Core; @@ -400,12 +400,36 @@ namespace ICSharpCode.SharpDevelop.Services /// Gets the tooltip control that shows the value of given variable. /// Return null if no tooltip is available. /// - public object GetTooltipControl(string variableName) + public object GetTooltipControl(Location logicalPosition, string variableName) { try { var tooltipExpression = GetExpression(variableName); - ExpressionNode expressionNode = new ExpressionNode(ExpressionNode.GetImageForLocalVariable(), variableName, tooltipExpression); - return new DebuggerTooltipControl(expressionNode); + string imageName; + var image = ExpressionNode.GetImageForLocalVariable(out imageName); + ExpressionNode expressionNode = new ExpressionNode(image, variableName, tooltipExpression); + expressionNode.ImageName = imageName; + return new DebuggerTooltipControl(logicalPosition, expressionNode); + } catch (GetValueException) { + return null; + } + } + + public ITreeNode GetNode(string variable, string currentImageName = null) + { + try { + var expression = GetExpression(variable); + string imageName; + IImage image; + if (string.IsNullOrEmpty(currentImageName)) { + image = ExpressionNode.GetImageForLocalVariable(out imageName); + } + else { + image = new ResourceServiceImage(currentImageName); + imageName = currentImageName; + } + ExpressionNode expressionNode = new ExpressionNode(image, variable, expression); + expressionNode.ImageName = imageName; + return expressionNode; } catch (GetValueException) { return null; } diff --git a/src/Main/Base/Project/Src/Services/Debugger/Tooltips/DebuggerPopup.cs b/src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerPopup.cs similarity index 88% rename from src/Main/Base/Project/Src/Services/Debugger/Tooltips/DebuggerPopup.cs rename to src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerPopup.cs index 2f045b5450..87529f37e1 100644 --- a/src/Main/Base/Project/Src/Services/Debugger/Tooltips/DebuggerPopup.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerPopup.cs @@ -8,20 +8,22 @@ using System.Windows.Controls.Primitives; using System.Windows.Input; using ICSharpCode.Core; +using ICSharpCode.NRefactory; +using ICSharpCode.SharpDevelop.Debugging; using ICSharpCode.SharpDevelop.Gui; -namespace ICSharpCode.SharpDevelop.Debugging +namespace Debugger.AddIn.Tooltips { /// /// Popup containing . /// public class DebuggerPopup : Popup { - private DebuggerTooltipControl contentControl; + internal DebuggerTooltipControl contentControl; - public DebuggerPopup(DebuggerTooltipControl parentControl) + public DebuggerPopup(DebuggerTooltipControl parentControl, Location logicalPosition, bool showPins = true) { - this.contentControl = new DebuggerTooltipControl(parentControl); + this.contentControl = new DebuggerTooltipControl(parentControl, logicalPosition, showPins); this.contentControl.containingPopup = this; this.Child = this.contentControl; this.IsLeaf = false; @@ -63,7 +65,7 @@ namespace ICSharpCode.SharpDevelop.Debugging public IEnumerable ItemsSource { get { return this.contentControl.ItemsSource; } - set { this.contentControl.ItemsSource = value; } + set { this.contentControl.SetItemsSource(value); } } private bool isLeaf; @@ -97,4 +99,4 @@ namespace ICSharpCode.SharpDevelop.Debugging this.IsOpen = false; } } -} +} \ No newline at end of file diff --git a/src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml b/src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml new file mode 100644 index 0000000000..2d2a44abba --- /dev/null +++ b/src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml.cs b/src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml.cs new file mode 100644 index 0000000000..b3fbf47370 --- /dev/null +++ b/src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml.cs @@ -0,0 +1,407 @@ +// 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.Generic; +using System.Globalization; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Shapes; + +using ICSharpCode.Core; +using ICSharpCode.NRefactory; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Bookmarks; +using ICSharpCode.SharpDevelop.Debugging; +using ICSharpCode.SharpDevelop.Editor; +using ICSharpCode.SharpDevelop.Gui; +using Services.Debugger.Tooltips; + +namespace Debugger.AddIn.Tooltips +{ + /// + /// Default Control used as content of SharpDevelop debugger tooltips. + /// + public partial class DebuggerTooltipControl : UserControl, ITooltip + { + private const double ChildPopupOpenXOffet = 16; + private const double ChildPopupOpenYOffet = 15; + private const int InitialItemsCount = 12; + private const int VisibleItemsCount = 11; + + private bool showPins = true; + private LazyItemsControl lazyGrid; + private IEnumerable itemsSource; + readonly Location logicalPosition; + + public DebuggerTooltipControl(Location logicalPosition) + { + this.logicalPosition = logicalPosition; + InitializeComponent(); + + Loaded += new RoutedEventHandler(OnLoaded); + } + + public DebuggerTooltipControl(Location logicalPosition, ITreeNode node) + : this(logicalPosition, new ITreeNode[] { node }) + { + + } + + public DebuggerTooltipControl(Location logicalPosition, IEnumerable nodes) + : this(logicalPosition) + { + this.itemsSource = nodes; + } + + public DebuggerTooltipControl(DebuggerTooltipControl parentControl, Location logicalPosition, bool showPins = true) + : this(logicalPosition) + { + this.parentControl = parentControl; + this.showPins = showPins; + } + + private void OnLoaded(object sender, RoutedEventArgs e) + { + if (!showPins) { + dataGrid.Columns[5].Visibility = Visibility.Collapsed; + } + + SetItemsSource(this.itemsSource); + } + + public event RoutedEventHandler Closed; + protected void OnClosed() + { + if (this.Closed != null) { + this.Closed(this, new RoutedEventArgs()); + } + } + + public IEnumerable ItemsSource { + get { return this.itemsSource; } + } + + public void SetItemsSource(IEnumerable value) { + this.itemsSource = value; + this.lazyGrid = new LazyItemsControl(this.dataGrid, InitialItemsCount); + + // HACK for updating the pins in tooltip + var observable = new List(); + this.itemsSource.ForEach(item => observable.Add(item)); + + // verify if at the line of the root there's a pin bookmark + ITextEditorProvider provider = WorkbenchSingleton.Workbench.ActiveViewContent as ITextEditorProvider; + var editor = provider.TextEditor; + if (editor != null) { + var pin = BookmarkManager.Bookmarks.Find( + b => b is PinBookmark && + b.Location.Line == logicalPosition.Line && + b.FileName == editor.FileName) as PinBookmark; + + if (pin != null) { + observable.ForEach(item => { // TODO: find a way not to use "observable" + if (pin.ContainsNode(item)) + item.IsPinned = true; + }); + } + } + + var source = new VirtualizingIEnumerable(observable); + lazyGrid.ItemsSource = source; + this.dataGrid.AddHandler(ScrollViewer.ScrollChangedEvent, new ScrollChangedEventHandler(handleScroll)); + + if (this.lazyGrid.ItemsSourceTotalCount != null) { + // hide up/down buttons if too few items + btnUp.Visibility = btnDown.Visibility = + this.lazyGrid.ItemsSourceTotalCount.Value <= VisibleItemsCount ? Visibility.Collapsed : Visibility.Visible; + } + } + + //public Location LogicalPosition { get; set; } + + /// + public bool ShowAsPopup + { + get + { + return true; + } + } + + /// + public bool Close(bool mouseClick) + { + if (mouseClick || (!mouseClick && !isChildExpanded)) { + CloseChildPopups(); + return true; + } else { + return false; + } + } + + private DebuggerPopup childPopup { get; set; } + private DebuggerTooltipControl parentControl { get; set; } + internal DebuggerPopup containingPopup { get; set; } + + bool isChildExpanded + { + get + { + return this.childPopup != null && this.childPopup.IsOpen; + } + } + + private ToggleButton expandedButton; + + /// + /// Closes the child popup of this control, if it exists. + /// + public void CloseChildPopups() + { + if (this.expandedButton != null) { + this.expandedButton.IsChecked = false; + this.expandedButton = null; + // nice simple example of indirect recursion + this.childPopup.CloseSelfAndChildren(); + } + } + + public void CloseOnLostFocus() + { + // when we close, parent becomes leaf + if (this.containingPopup != null) { + this.containingPopup.IsLeaf = true; + } + if (!this.IsMouseOver) { + if (this.containingPopup != null) { + this.containingPopup.IsOpen = false; + this.containingPopup.IsLeaf = false; + } + if (this.parentControl != null) { + this.parentControl.CloseOnLostFocus(); + } + OnClosed(); + } else { + // leaf closed because of click inside this control - stop the closing chain + if (this.expandedButton != null && !this.expandedButton.IsMouseOver) { + this.expandedButton.IsChecked = false; + this.expandedButton = null; + } + } + } + + private void btnExpander_Click(object sender, RoutedEventArgs e) + { + var clickedButton = (ToggleButton)e.OriginalSource; + var clickedNode = (ITreeNode)clickedButton.DataContext; + // use device independent units, because child popup Left/Top are in independent units + Point buttonPos = clickedButton.PointToScreen(new Point(0, 0)).TransformFromDevice(clickedButton); + + if (clickedButton.IsChecked.GetValueOrDefault(false)) { + CloseChildPopups(); + this.expandedButton = clickedButton; + + // open child Popup + if (this.childPopup == null) { + this.childPopup = new DebuggerPopup(this, logicalPosition); + this.childPopup.Placement = PlacementMode.Absolute; + } + if (this.containingPopup != null) { + this.containingPopup.IsLeaf = false; + } + this.childPopup.IsLeaf = true; + this.childPopup.HorizontalOffset = buttonPos.X + ChildPopupOpenXOffet; + this.childPopup.VerticalOffset = buttonPos.Y + ChildPopupOpenYOffet; + this.childPopup.ItemsSource = clickedNode.ChildNodes; + this.childPopup.Open(); + } else { + CloseChildPopups(); + } + } + + 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); + } + + #region Edit value in tooltip + + void TextBox_KeyUp(object sender, KeyEventArgs e) + { + if (e.Key == Key.Escape) { + dataGrid.Focus(); + return; + } + + if (e.Key == Key.Enter) { + dataGrid.Focus(); + // set new value + var textBox = (TextBox)e.OriginalSource; + var newValue = textBox.Text; + var node = ((FrameworkElement)sender).DataContext as ITreeNode; + SaveNewValue(node, textBox.Text); + } + } + + void TextBox_LostFocus(object sender, RoutedEventArgs e) + { + var textBox = (TextBox)e.OriginalSource; + var newValue = textBox.Text; + var node = ((FrameworkElement)sender).DataContext as ITreeNode; + SaveNewValue(node, textBox.Text); + } + + void SaveNewValue(ITreeNode node, string newValue) + { + if(node != null && node.SetText(newValue)) { + // show adorner + var adornerLayer = AdornerLayer.GetAdornerLayer(dataGrid); + var adorners = adornerLayer.GetAdorners(dataGrid); + if (adorners != null && adorners.Length != 0) + adornerLayer.Remove(adorners[0]); + SavedAdorner adorner = new SavedAdorner(dataGrid); + adornerLayer.Add(adorner); + } + } + + #endregion + + #region Pining checked/unchecked + + void PinButton_Checked(object sender, RoutedEventArgs e) + { + ITextEditorProvider provider = WorkbenchSingleton.Workbench.ActiveViewContent as ITextEditorProvider; + var editor = provider.TextEditor; + if (editor == null) return; + var node = (ITreeNode)(((ToggleButton)(e.OriginalSource)).DataContext); + + if (!string.IsNullOrEmpty(editor.FileName)) { + + // verify if at the line of the root there's a pin bookmark + var pin = BookmarkManager.Bookmarks.Find( + b => b is PinBookmark && + b.LineNumber == logicalPosition.Line && + b.FileName == editor.FileName) as PinBookmark; + + if (pin == null) { + pin = new PinBookmark(editor.FileName, logicalPosition); + // show pinned DebuggerPopup + if (pin.Popup == null) { + pin.Popup = new PinDebuggerControl(); + pin.Popup.Mark = pin; + Rect rect = new Rect(this.DesiredSize); + var point = this.PointToScreen(rect.TopRight); + pin.Popup.Location = new Point { X = 500, Y = point.Y - 150 }; + pin.Nodes.Add(node); + pin.Popup.ItemsSource = pin.Nodes; + } + + // do actions + pin.Popup.Open(); + BookmarkManager.AddMark(pin); + } + else + { + if (!pin.ContainsNode(node)) { + pin.Nodes.Add(node); + pin.Popup.ItemsSource = pin.Nodes; + } + } + } + } + + void PinButton_Unchecked(object sender, RoutedEventArgs e) + { + ITextEditorProvider provider = WorkbenchSingleton.Workbench.ActiveViewContent as ITextEditorProvider; + var editor = provider.TextEditor; + if (editor == null) return; + + if (!string.IsNullOrEmpty(editor.FileName)) { + // remove from pinned DebuggerPopup + var pin = BookmarkManager.Bookmarks.Find( + b => b is PinBookmark && + b.LineNumber == logicalPosition.Line && + b.FileName == editor.FileName) as PinBookmark; + if (pin == null) return; + + ToggleButton button = (ToggleButton)e.OriginalSource; + pin.RemoveNode((ITreeNode)button.DataContext); + pin.Popup.ItemsSource = pin.Nodes; + // remove if no more data pins are available + if (pin.Nodes.Count == 0) { + pin.Popup.Close(); + + BookmarkManager.RemoveMark(pin); + } + } + } + + #endregion + + #region Saved Adorner + + class SavedAdorner : Adorner + { + public SavedAdorner(UIElement adornedElement) : base(adornedElement) + { + Loaded += delegate { Show(); }; + } + + protected override void OnRender(DrawingContext drawingContext) + { + Rect adornedElementRect = new Rect(this.AdornedElement.DesiredSize); + + // Some arbitrary drawing implements. + var formatedText = new FormattedText(StringParser.Parse("${res:ICSharpCode.SharpDevelop.Debugging.SavedString}"), + CultureInfo.CurrentCulture, + FlowDirection.LeftToRight, + new Typeface(new FontFamily("Arial"), + FontStyles.Normal, + FontWeights.Black, + FontStretches.Expanded), + 8d, + Brushes.Black); + + + drawingContext.DrawText(formatedText, + new Point(adornedElementRect.TopRight.X - formatedText.Width - 2, + adornedElementRect.TopRight.Y)); + } + + private void Show() + { + DoubleAnimation animation = new DoubleAnimation(); + animation.From = 1; + animation.To = 0; + + animation.Duration = new Duration(TimeSpan.FromSeconds(2)); + animation.SetValue(Storyboard.TargetProperty, this); + animation.SetValue(Storyboard.TargetPropertyProperty, new PropertyPath(Rectangle.OpacityProperty)); + + Storyboard board = new Storyboard(); + board.Children.Add(animation); + + board.Begin(this); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Main/Base/Project/Src/Services/Debugger/Tooltips/LazyItemsControl.cs b/src/AddIns/Debugger/Debugger.AddIn/Tooltips/LazyItemsControl.cs similarity index 97% rename from src/Main/Base/Project/Src/Services/Debugger/Tooltips/LazyItemsControl.cs rename to src/AddIns/Debugger/Debugger.AddIn/Tooltips/LazyItemsControl.cs index d769bfafb8..f4af8a0aa7 100644 --- a/src/Main/Base/Project/Src/Services/Debugger/Tooltips/LazyItemsControl.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Tooltips/LazyItemsControl.cs @@ -5,7 +5,9 @@ using System; using System.Collections.Generic; using System.Windows.Controls; -namespace ICSharpCode.SharpDevelop.Debugging +using ICSharpCode.SharpDevelop; + +namespace Debugger.AddIn.Tooltips { /// /// ItemsControl wrapper that takes VirtualizingIEnumerable as source, diff --git a/src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinCloseControl.xaml b/src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinCloseControl.xaml new file mode 100644 index 0000000000..c2fc077e1e --- /dev/null +++ b/src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinCloseControl.xaml @@ -0,0 +1,29 @@ + + + + + + + + + + + - object GetTooltipControl(string variable); + object GetTooltipControl(Location logicalPosition, string variable); /// /// Queries the debugger whether it is possible to set the instruction pointer to a given position. diff --git a/src/Main/Base/Project/Src/Services/Debugger/Tooltips/DebuggerTooltipControl.xaml b/src/Main/Base/Project/Src/Services/Debugger/Tooltips/DebuggerTooltipControl.xaml deleted file mode 100644 index f9af4fca25..0000000000 --- a/src/Main/Base/Project/Src/Services/Debugger/Tooltips/DebuggerTooltipControl.xaml +++ /dev/null @@ -1,205 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Main/Base/Project/Src/Services/Debugger/Tooltips/DebuggerTooltipControl.xaml.cs b/src/Main/Base/Project/Src/Services/Debugger/Tooltips/DebuggerTooltipControl.xaml.cs deleted file mode 100644 index 7fe7c0ee6d..0000000000 --- a/src/Main/Base/Project/Src/Services/Debugger/Tooltips/DebuggerTooltipControl.xaml.cs +++ /dev/null @@ -1,196 +0,0 @@ -// 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.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; -using ICSharpCode.SharpDevelop.Editor; - -namespace ICSharpCode.SharpDevelop.Debugging -{ - /// - /// Default Control used as content of SharpDevelop debugger tooltips. - /// - public partial class DebuggerTooltipControl : UserControl, ITooltip - { - private readonly double ChildPopupOpenXOffet = 16; - private readonly double ChildPopupOpenYOffet = 15; - private readonly int InitialItemsCount = 12; - private readonly int VisibleItemsCount = 11; - - public DebuggerTooltipControl() - { - InitializeComponent(); - } - - public DebuggerTooltipControl(ITreeNode node) - : this(new ITreeNode[] { node }) - { - } - - public DebuggerTooltipControl(IEnumerable nodes) - : this() - { - this.ItemsSource = nodes; - } - - public DebuggerTooltipControl(DebuggerTooltipControl parentControl) - : this() - { - this.parentControl = parentControl; - } - - public event RoutedEventHandler Closed; - protected void OnClosed() - { - if (this.Closed != null) { - this.Closed(this, new RoutedEventArgs()); - } - } - - private LazyItemsControl lazyGrid; - - private IEnumerable itemsSource; - public IEnumerable ItemsSource - { - get { return this.itemsSource; } - set - { - this.itemsSource = value; - this.lazyGrid = new LazyItemsControl(this.dataGrid, InitialItemsCount); - lazyGrid.ItemsSource = new VirtualizingIEnumerable(value); - this.dataGrid.AddHandler(ScrollViewer.ScrollChangedEvent, new ScrollChangedEventHandler(handleScroll)); - - if (this.lazyGrid.ItemsSourceTotalCount != null) { - // hide up/down buttons if too few items - btnUp.Visibility = btnDown.Visibility = - this.lazyGrid.ItemsSourceTotalCount.Value <= VisibleItemsCount ? Visibility.Collapsed : Visibility.Visible; - } - } - - } - - /// - public bool ShowAsPopup - { - get - { - return true; - } - } - - /// - public bool Close(bool mouseClick) - { - if (mouseClick || (!mouseClick && !isChildExpanded)) { - CloseChildPopups(); - return true; - } else { - return false; - } - } - - DebuggerPopup childPopup { get; set; } - DebuggerTooltipControl parentControl { get; set; } - internal DebuggerPopup containingPopup { get; set; } - - bool isChildExpanded - { - get - { - return this.childPopup != null && this.childPopup.IsOpen; - } - } - - private ToggleButton expandedButton; - - /// - /// Closes the child popup of this control, if it exists. - /// - public void CloseChildPopups() - { - if (this.expandedButton != null) { - this.expandedButton.IsChecked = false; - this.expandedButton = null; - // nice simple example of indirect recursion - this.childPopup.CloseSelfAndChildren(); - } - } - - public void CloseOnLostFocus() - { - // when we close, parent becomes leaf - if (this.containingPopup != null) { - this.containingPopup.IsLeaf = true; - } - if (!this.IsMouseOver) { - if (this.containingPopup != null) { - this.containingPopup.IsOpen = false; - this.containingPopup.IsLeaf = false; - } - if (this.parentControl != null) { - this.parentControl.CloseOnLostFocus(); - } - OnClosed(); - } else { - // leaf closed because of click inside this control - stop the closing chain - if (this.expandedButton != null && !this.expandedButton.IsMouseOver) { - this.expandedButton.IsChecked = false; - this.expandedButton = null; - } - } - } - - private void btnExpander_Click(object sender, RoutedEventArgs e) - { - var clickedButton = (ToggleButton)e.OriginalSource; - var clickedNode = (ITreeNode)clickedButton.DataContext; - // use device independent units, because child popup Left/Top are in independent units - Point buttonPos = clickedButton.PointToScreen(new Point(0, 0)).TransformFromDevice(clickedButton); - - if (clickedButton.IsChecked.GetValueOrDefault(false)) { - CloseChildPopups(); - this.expandedButton = clickedButton; - - // open child Popup - if (this.childPopup == null) { - this.childPopup = new DebuggerPopup(this); - this.childPopup.Placement = PlacementMode.Absolute; - } - if (this.containingPopup != null) { - this.containingPopup.IsLeaf = false; - } - this.childPopup.IsLeaf = true; - this.childPopup.HorizontalOffset = buttonPos.X + ChildPopupOpenXOffet; - this.childPopup.VerticalOffset = buttonPos.Y + ChildPopupOpenYOffet; - this.childPopup.ItemsSource = clickedNode.ChildNodes; - this.childPopup.Open(); - } else { - CloseChildPopups(); - } - } - - 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); - } - } -} diff --git a/src/Main/Base/Project/Src/Services/Debugger/Tooltips/IPinDebuggerControl.cs b/src/Main/Base/Project/Src/Services/Debugger/Tooltips/IPinDebuggerControl.cs new file mode 100644 index 0000000000..b3e531820c --- /dev/null +++ b/src/Main/Base/Project/Src/Services/Debugger/Tooltips/IPinDebuggerControl.cs @@ -0,0 +1,20 @@ +// 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.Generic; +using System.Windows; + +using ICSharpCode.SharpDevelop.Debugging; + +namespace Services.Debugger.Tooltips +{ + public interface IPinDebuggerControl + { + void Open(); + void Close(); + PinBookmark Mark { get; set; } + IEnumerable ItemsSource { set; } + Point Location { get; set; } + } +} diff --git a/src/Main/Base/Project/Src/Services/Debugger/Tooltips/ITreeNode.cs b/src/Main/Base/Project/Src/Services/Debugger/Tooltips/ITreeNode.cs index abc88cdd3b..59762e5870 100644 --- a/src/Main/Base/Project/Src/Services/Debugger/Tooltips/ITreeNode.cs +++ b/src/Main/Base/Project/Src/Services/Debugger/Tooltips/ITreeNode.cs @@ -10,12 +10,18 @@ namespace ICSharpCode.SharpDevelop.Debugging /// /// Node that can be bound to . /// - public interface ITreeNode + public interface ITreeNode : IComparable { string Name { get; } + string FullName { get; } + + string ImageName { get; } + string Text { get; } + bool CanSetText { get; } + string Type { get; } ImageSource ImageSource { get; } @@ -27,5 +33,9 @@ namespace ICSharpCode.SharpDevelop.Debugging IEnumerable VisualizerCommands { get; } bool HasVisualizerCommands { get; } + + bool IsPinned { get; set; } + + bool SetText(string newValue); } } diff --git a/src/Main/Base/Project/Src/Services/Debugger/Tooltips/PinBookmark.cs b/src/Main/Base/Project/Src/Services/Debugger/Tooltips/PinBookmark.cs new file mode 100644 index 0000000000..cf758a382b --- /dev/null +++ b/src/Main/Base/Project/Src/Services/Debugger/Tooltips/PinBookmark.cs @@ -0,0 +1,102 @@ +// 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.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Windows; + +using ICSharpCode.Core; +using ICSharpCode.NRefactory; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Bookmarks; +using ICSharpCode.SharpDevelop.Debugging; + +namespace Services.Debugger.Tooltips +{ + public class PinBookmark : SDBookmark + { + string tooltip; + + public IPinDebuggerControl Popup { get; set; } + + public static readonly IImage PinImage = new ResourceServiceImage("Bookmarks.Pin"); + + public PinBookmark(FileName fileName, Location location) : base(fileName, location) + { + Nodes = new ObservableCollection(); + IsVisibleInBookmarkPad = false; + } + + /// + /// Pin's position relative to the layer BUT ABSOLUTE TO THE SCREEN. + /// + public Nullable PinPosition { get; set; } + + /// + /// Nodes inside the pin control. + /// + public ObservableCollection Nodes { get; set; } + + /// + /// Image, Name, Text + /// + public List> SavedNodes { get; set; } + + public string Comment { get; set; } + + public override IImage Image { + get { + return PinImage; + } + } + + public string Tooltip { + get { return tooltip; } + set { tooltip = value; } + } + + public override bool CanDragDrop { + get { return true; } + } + + public override void Drop(int lineNumber) + { + this.Location = new Location(ColumnNumber, lineNumber); + } + } + + public static class PinBookmarkExtensions + { + public static bool ContainsNode(this PinBookmark mark, ITreeNode node) + { + if (mark == null) + throw new ArgumentNullException("mark is null"); + if (node == null) + throw new ArgumentNullException("Node is null"); + + foreach (var currentNode in mark.Nodes) { + if (node.FullName == currentNode.FullName) + return true; + } + + return false; + } + + public static void RemoveNode(this PinBookmark mark, ITreeNode node) + { + if (mark == null) + throw new ArgumentNullException("mark is null"); + if (node == null) + throw new ArgumentNullException("Node is null"); + + foreach (var currentNode in mark.Nodes) { + if (node.FullName == currentNode.FullName) { + mark.Nodes.Remove(currentNode); + return; + } + } + } + } +} diff --git a/src/Main/Base/Project/Src/Services/LanguageBinding/LanguageBindingDescriptor.cs b/src/Main/Base/Project/Src/Services/LanguageBinding/LanguageBindingDescriptor.cs index 5371c06fca..0311e62d79 100644 --- a/src/Main/Base/Project/Src/Services/LanguageBinding/LanguageBindingDescriptor.cs +++ b/src/Main/Base/Project/Src/Services/LanguageBinding/LanguageBindingDescriptor.cs @@ -24,6 +24,9 @@ namespace ICSharpCode.SharpDevelop internal bool CanAttach(ITextEditor editor) { + if (Extensions == null || Extensions.Length == 0) + return true; + if (!string.IsNullOrEmpty(editor.FileName)) { string extension = Path.GetExtension(editor.FileName).ToLowerInvariant(); foreach (var ext in Extensions) { diff --git a/src/Main/StartUp/Project/Resources/BitmapResources.resources b/src/Main/StartUp/Project/Resources/BitmapResources.resources index 00029d6f0b..0b467fe1f0 100644 Binary files a/src/Main/StartUp/Project/Resources/BitmapResources.resources and b/src/Main/StartUp/Project/Resources/BitmapResources.resources differ