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.
332 lines
8.7 KiB
332 lines
8.7 KiB
// 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.Dynamic; |
|
using System.Linq; |
|
using System.Windows; |
|
using System.Windows.Controls; |
|
using System.Windows.Input; |
|
using System.Windows.Media; |
|
using ICSharpCode.Core.Presentation; |
|
using ICSharpCode.NRefactory; |
|
using ICSharpCode.SharpDevelop; |
|
using ICSharpCode.SharpDevelop.Gui.Pads; |
|
using ICSharpCode.SharpDevelop.Services; |
|
|
|
namespace Debugger.AddIn.Pads.ParallelPad |
|
{ |
|
public class FrameSelectedEventArgs : EventArgs |
|
{ |
|
public StackFrame Item { |
|
get; |
|
private set; |
|
} |
|
|
|
public Location Location { |
|
get; |
|
private set; |
|
} |
|
|
|
public FrameSelectedEventArgs(StackFrame item, Location location) |
|
{ |
|
Item = item; |
|
Location = location; |
|
} |
|
} |
|
|
|
public partial class ThreadStack : UserControl |
|
{ |
|
public static SolidColorBrush SelectedBrush = new SolidColorBrush(Color.FromRgb(84, 169, 255)); |
|
|
|
public static readonly DependencyProperty IsSelectedProperty = |
|
DependencyProperty.Register("IsSelected", typeof(bool), typeof(ThreadStack), |
|
new FrameworkPropertyMetadata()); |
|
|
|
public event EventHandler StackSelected; |
|
|
|
public event EventHandler<FrameSelectedEventArgs> FrameSelected; |
|
|
|
ObservableCollection<ParallelStackFrameModel> itemCollection = new ObservableCollection<ParallelStackFrameModel>(); |
|
|
|
ToolTip toolTip = new ToolTip(); |
|
List<uint> threadIds = new List<uint>(); |
|
|
|
public ThreadStack() |
|
{ |
|
InitializeComponent(); |
|
datagrid.ToolTip = toolTip; |
|
datagrid.ToolTipOpening += OnToolTipOpening; |
|
datagrid.PreviewMouseMove += new MouseEventHandler(datagrid_PreviewMouseMove); |
|
datagrid.MouseLeave += delegate { toolTip.IsOpen = false; }; |
|
} |
|
|
|
#region Public Properties |
|
|
|
public Process Process { get; set; } |
|
|
|
public int Level { get; set; } |
|
|
|
public bool IsSelected { |
|
get { return (bool)GetValue(IsSelectedProperty); } |
|
set { |
|
if (value) { |
|
BorderParent.BorderBrush = SelectedBrush; |
|
BorderParent.BorderThickness = new Thickness(5); |
|
} |
|
else { |
|
BorderParent.BorderBrush = Brushes.Black; |
|
BorderParent.BorderThickness = new Thickness(3); |
|
} |
|
|
|
SetValue(IsSelectedProperty, value); |
|
|
|
SelectParent(value); |
|
} |
|
} |
|
|
|
public List<ThreadStack> ThreadStackParents { get; set; } |
|
|
|
public List<ThreadStack> ThreadStackChildren { get; set; } |
|
|
|
public List<uint> ThreadIds { |
|
get { return threadIds; } |
|
} |
|
|
|
public ObservableCollection<ParallelStackFrameModel> ItemCollection { |
|
get { return itemCollection; } |
|
set { |
|
itemCollection = value; |
|
this.datagrid.ItemsSource = itemCollection; |
|
} |
|
} |
|
|
|
#endregion |
|
|
|
#region Public Methods |
|
|
|
public void UpdateThreadIds(bool isTask, params uint[] threadIds) |
|
{ |
|
var list = new List<uint>(); |
|
foreach (uint id in threadIds) { |
|
if (!this.threadIds.Contains(id)) { |
|
list.Add(id); |
|
} |
|
} |
|
this.threadIds.AddRange(list); |
|
|
|
if (this.threadIds.Count > 1) { |
|
string suffix = isTask ? " Tasks" : " Threads"; |
|
this.HeaderText.Text = this.threadIds.Count.ToString() + suffix; |
|
} |
|
else { |
|
this.HeaderText.Text = isTask ? "1 Task" : "1 Thread"; |
|
} |
|
} |
|
|
|
public void ClearImages() |
|
{ |
|
foreach (ParallelStackFrameModel item in itemCollection) { |
|
if (!item.IsRunningStackFrame) |
|
item.Image = null; |
|
} |
|
} |
|
|
|
#endregion |
|
|
|
#region Private Methods |
|
|
|
private void SelectParent(bool isSelected) |
|
{ |
|
if (this.ThreadStackParents == null || this.ThreadStackParents.Count == 0) |
|
return; |
|
|
|
foreach (var ts in this.ThreadStackParents) |
|
if (ts != null) |
|
ts.IsSelected = isSelected; |
|
} |
|
|
|
void datagrid_PreviewMouseMove(object sender, MouseEventArgs e) |
|
{ |
|
var result = VisualTreeHelper.HitTest(this, e.GetPosition(this)); |
|
if (result != null) |
|
{ |
|
var row = TryFindParent<DataGridRow>(result.VisualHit); |
|
if (row != null) |
|
{ |
|
datagrid.SelectedItem = row.DataContext; |
|
e.Handled = true; |
|
} |
|
} |
|
} |
|
|
|
private void Datagrid_MouseDoubleClick(object sender, MouseButtonEventArgs e) |
|
{ |
|
if (Process.IsRunning) return; |
|
|
|
ParallelStackFrameModel selectedItem = datagrid.SelectedItem as ParallelStackFrameModel; |
|
if (selectedItem != null) { |
|
if (ThreadIds.Count > 1) { |
|
datagrid.ContextMenu = CreateContextMenu(selectedItem); |
|
datagrid.ContextMenu.IsOpen = true; |
|
} |
|
else |
|
{ |
|
SelectFrame(ThreadIds[0], selectedItem); |
|
} |
|
} |
|
} |
|
|
|
private void SelectFrame(uint threadId, ParallelStackFrameModel selectedItem) |
|
{ |
|
if (selectedItem == null) |
|
return; |
|
|
|
var thread = Process.Threads.FirstOrDefault(t => t.ID == threadId); |
|
if (thread == null) |
|
return; |
|
|
|
if (StackSelected != null) |
|
StackSelected(this, EventArgs.Empty); |
|
|
|
this.IsSelected = true; |
|
|
|
foreach(var frame in thread.Callstack) |
|
{ |
|
if (frame.GetMethodName() == selectedItem.MethodName) |
|
{ |
|
if (!selectedItem.IsRunningStackFrame) |
|
selectedItem.Image = PresentationResourceService.GetImage("Icons.48x48.CurrentFrame").Source; |
|
|
|
SourcecodeSegment nextStatement = frame.NextStatement; |
|
if (nextStatement != null) { |
|
var location = new Location(nextStatement.StartColumn, nextStatement.StartLine); |
|
FileService.JumpToFilePosition( |
|
nextStatement.Filename, location.Line, location.Column); |
|
|
|
if (FrameSelected != null) |
|
FrameSelected(this, new FrameSelectedEventArgs(frame, location)); |
|
} |
|
|
|
break; |
|
} |
|
} |
|
} |
|
|
|
private void Datagrid_MouseRightButtonUp(object sender, MouseButtonEventArgs e) |
|
{ |
|
if (Process.IsRunning) return; |
|
|
|
ParallelStackFrameModel selectedItem = datagrid.SelectedItem as ParallelStackFrameModel; |
|
if (selectedItem == null) |
|
return; |
|
|
|
datagrid.ContextMenu = CreateContextMenu(selectedItem); |
|
datagrid.ContextMenu.IsOpen = true; |
|
} |
|
|
|
ContextMenu CreateContextMenu(ParallelStackFrameModel item) |
|
{ |
|
var menu = new ContextMenu(); |
|
|
|
foreach (var id in ThreadIds) { |
|
MenuItem m = new MenuItem(); |
|
m.IsCheckable = true; |
|
m.IsChecked = id == WindowsDebugger.CurrentThread.ID; |
|
m.Click += delegate(object sender, RoutedEventArgs e) { |
|
var menuItem = e.OriginalSource as MenuItem; |
|
SelectFrame((uint)menuItem.Tag, item); |
|
}; |
|
m.Tag = id; |
|
m.Header = id.ToString() + ":" + item.MethodName; |
|
|
|
menu.Items.Add(m); |
|
} |
|
|
|
return menu; |
|
} |
|
|
|
private void OnToolTipOpening(object sender, ToolTipEventArgs e) |
|
{ |
|
if (Process.IsRunning) |
|
return; |
|
|
|
StackPanel panel = new StackPanel(); |
|
|
|
ParallelStackFrameModel selectedItem = datagrid.SelectedItem as ParallelStackFrameModel; |
|
if (selectedItem == null) { |
|
panel.Children.Add(new TextBlock { Text = "No item selected" }); |
|
this.toolTip.Content = panel; |
|
return; |
|
} |
|
|
|
foreach(var thread in Process.Threads) |
|
{ |
|
if (ThreadIds.Contains(thread.ID)) |
|
{ |
|
foreach (var frame in thread.Callstack) |
|
{ |
|
if (selectedItem.MethodName == frame.GetMethodName()) |
|
{ |
|
TextBlock tb = new TextBlock(); |
|
tb.Text = thread.ID + ": " + CallStackPad.GetFullName(frame); |
|
panel.Children.Add(tb); |
|
} |
|
} |
|
} |
|
} |
|
|
|
this.toolTip.Content = panel; |
|
} |
|
|
|
#endregion |
|
|
|
#region Static Methods |
|
|
|
private static T TryFindParent<T>(DependencyObject child) where T : DependencyObject |
|
{ |
|
if (child is T) return child as T; |
|
|
|
DependencyObject parentObject = GetParentObject(child); |
|
if (parentObject == null) return null; |
|
|
|
var parent = parentObject as T; |
|
if (parent != null && parent is T) |
|
{ |
|
return parent; |
|
} |
|
else |
|
{ |
|
return TryFindParent<T>(parentObject); |
|
} |
|
} |
|
|
|
private static DependencyObject GetParentObject(DependencyObject child) |
|
{ |
|
if (child == null) return null; |
|
|
|
ContentElement contentElement = child as ContentElement; |
|
if (contentElement != null) |
|
{ |
|
DependencyObject parent = ContentOperations.GetParent(contentElement); |
|
if (parent != null) return parent; |
|
|
|
FrameworkContentElement fce = contentElement as FrameworkContentElement; |
|
return fce != null ? fce.Parent : null; |
|
} |
|
|
|
FrameworkElement frameworkElement = child as FrameworkElement; |
|
if (frameworkElement != null) |
|
{ |
|
DependencyObject parent = frameworkElement.Parent; |
|
if (parent != null) return parent; |
|
} |
|
|
|
return VisualTreeHelper.GetParent(child); |
|
} |
|
|
|
#endregion |
|
} |
|
} |