Browse Source
git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4848 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61shortcuts
5 changed files with 263 additions and 197 deletions
@ -0,0 +1,245 @@
@@ -0,0 +1,245 @@
|
||||
/* |
||||
* Created by SharpDevelop. |
||||
* User: daniel |
||||
* Date: 31.08.2009 |
||||
* Time: 14:55 |
||||
* |
||||
* To change this template use Tools | Options | Coding | Edit Standard Headers. |
||||
*/ |
||||
using System; |
||||
using System.Diagnostics; |
||||
using System.Linq; |
||||
using System.Windows; |
||||
using System.Windows.Controls; |
||||
using System.Windows.Controls.Primitives; |
||||
using System.Windows.Input; |
||||
|
||||
using ICSharpCode.AvalonEdit.Editing; |
||||
using ICSharpCode.AvalonEdit.Rendering; |
||||
using ICSharpCode.SharpDevelop; |
||||
using ICSharpCode.SharpDevelop.Dom; |
||||
using ICSharpCode.SharpDevelop.Editor; |
||||
using ICSharpCode.SharpDevelop.Editor.AvalonEdit; |
||||
using ICSharpCode.SharpDevelop.Editor.Commands; |
||||
|
||||
namespace ICSharpCode.AvalonEdit.AddIn |
||||
{ |
||||
/// <summary>
|
||||
/// The text editor use inside the CodeEditor.
|
||||
/// There can be two CodeEditorView instances in a single CodeEditor if split-view
|
||||
/// is enabled.
|
||||
/// </summary>
|
||||
public class CodeEditorView : TextEditor |
||||
{ |
||||
public ITextEditor Adapter { get; set; } |
||||
|
||||
public CodeEditorView() |
||||
{ |
||||
this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Help, OnHelpExecuted)); |
||||
|
||||
this.MouseHover += TextEditorMouseHover; |
||||
this.MouseHoverStopped += TextEditorMouseHoverStopped; |
||||
this.MouseLeave += TextEditorMouseLeave; |
||||
this.TextArea.TextView.MouseDown += TextViewMouseDown; |
||||
} |
||||
|
||||
#region Help
|
||||
void OnHelpExecuted(object sender, ExecutedRoutedEventArgs e) |
||||
{ |
||||
ShowHelp(); |
||||
} |
||||
|
||||
public void ShowHelp() |
||||
{ |
||||
// Resolve expression at cursor and show help
|
||||
TextArea textArea = this.TextArea; |
||||
IExpressionFinder expressionFinder = ParserService.GetExpressionFinder(this.Adapter.FileName); |
||||
if (expressionFinder == null) |
||||
return; |
||||
string textContent = this.Text; |
||||
ExpressionResult expressionResult = expressionFinder.FindFullExpression(textContent, textArea.Caret.Offset); |
||||
string expression = expressionResult.Expression; |
||||
if (expression != null && expression.Length > 0) { |
||||
ResolveResult result = ParserService.Resolve(expressionResult, textArea.Caret.Line, textArea.Caret.Column, this.Adapter.FileName, textContent); |
||||
TypeResolveResult trr = result as TypeResolveResult; |
||||
if (trr != null) { |
||||
HelpProvider.ShowHelp(trr.ResolvedClass); |
||||
} |
||||
MemberResolveResult mrr = result as MemberResolveResult; |
||||
if (mrr != null) { |
||||
HelpProvider.ShowHelp(mrr.ResolvedMember); |
||||
} |
||||
} |
||||
} |
||||
#endregion
|
||||
|
||||
#region Tooltip
|
||||
ToolTip toolTip; |
||||
Popup popup; |
||||
|
||||
void TextEditorMouseHover(object sender, MouseEventArgs e) |
||||
{ |
||||
Debug.Assert(sender == this); |
||||
ToolTipRequestEventArgs args = new ToolTipRequestEventArgs(this.Adapter); |
||||
var pos = GetPositionFromPoint(e.GetPosition(this)); |
||||
args.InDocument = pos.HasValue; |
||||
if (pos.HasValue) { |
||||
args.LogicalPosition = AvalonEditDocumentAdapter.ToLocation(pos.Value); |
||||
} |
||||
|
||||
TextMarkerService textMarkerService = this.Adapter.GetService(typeof(ITextMarkerService)) as TextMarkerService; |
||||
if (args.InDocument && textMarkerService != null) { |
||||
var markersAtOffset = textMarkerService.GetMarkersAtOffset(args.Editor.Document.PositionToOffset(args.LogicalPosition.Line, args.LogicalPosition.Column)); |
||||
|
||||
ITextMarker markerWithToolTip = markersAtOffset.FirstOrDefault(marker => marker.ToolTip != null); |
||||
|
||||
if (markerWithToolTip != null) { |
||||
args.ShowToolTip(markerWithToolTip.ToolTip); |
||||
} |
||||
} |
||||
|
||||
if (!args.Handled) { |
||||
// if request wasn't handled by a marker, pass it to the ToolTipRequestService
|
||||
ToolTipRequestService.RequestToolTip(args); |
||||
} |
||||
|
||||
if (args.ContentToShow != null) { |
||||
var contentToShowITooltip = args.ContentToShow as ITooltip; |
||||
|
||||
if (contentToShowITooltip != null && contentToShowITooltip.ShowAsPopup) { |
||||
if (!(args.ContentToShow is UIElement)) { |
||||
throw new NotSupportedException("Content to show in Popup must be UIElement: " + args.ContentToShow); |
||||
} |
||||
if (popup == null) { |
||||
popup = CreatePopup(); |
||||
} |
||||
if (TryCloseExistingPopup(false)) { |
||||
// when popup content decides to close, close the popup
|
||||
contentToShowITooltip.Closed += (closedSender, closedArgs) => { popup.IsOpen = false; }; |
||||
popup.Child = (UIElement)args.ContentToShow; |
||||
//ICSharpCode.SharpDevelop.Debugging.DebuggerService.CurrentDebugger.IsProcessRunningChanged
|
||||
SetPopupPosition(popup, e); |
||||
popup.IsOpen = true; |
||||
} |
||||
e.Handled = true; |
||||
} else { |
||||
if (toolTip == null) { |
||||
toolTip = new ToolTip(); |
||||
toolTip.Closed += ToolTipClosed; |
||||
} |
||||
toolTip.Content = args.ContentToShow; |
||||
toolTip.IsOpen = true; |
||||
e.Handled = true; |
||||
} |
||||
} else { |
||||
// close popup if mouse hovered over empty area
|
||||
if (popup != null) { |
||||
e.Handled = true; |
||||
} |
||||
TryCloseExistingPopup(false); |
||||
} |
||||
} |
||||
|
||||
bool TryCloseExistingPopup(bool mouseClick) |
||||
{ |
||||
bool canClose = true; |
||||
if (popup != null) { |
||||
var popupContentITooltip = popup.Child as ITooltip; |
||||
if (popupContentITooltip != null) { |
||||
canClose = popupContentITooltip.Close(mouseClick); |
||||
} |
||||
if (canClose) { |
||||
popup.IsOpen = false; |
||||
} |
||||
} |
||||
return canClose; |
||||
} |
||||
|
||||
void SetPopupPosition(Popup popup, MouseEventArgs mouseArgs) |
||||
{ |
||||
var popupPosition = GetPopupPosition(mouseArgs); |
||||
popup.HorizontalOffset = popupPosition.X; |
||||
popup.VerticalOffset = popupPosition.Y; |
||||
} |
||||
|
||||
/// <summary> Returns Popup position based on mouse position, in device independent units </summary>
|
||||
Point GetPopupPosition(MouseEventArgs mouseArgs) |
||||
{ |
||||
Point mousePos = mouseArgs.GetPosition(this); |
||||
Point positionInPixels; |
||||
// align Popup with line bottom
|
||||
TextViewPosition? logicalPos = GetPositionFromPoint(mousePos); |
||||
if (logicalPos.HasValue) { |
||||
var textView = this.TextArea.TextView; |
||||
positionInPixels = |
||||
textView.PointToScreen( |
||||
textView.GetVisualPosition(logicalPos.Value, VisualYPosition.LineBottom) - textView.ScrollOffset); |
||||
positionInPixels.X -= 4; |
||||
} else { |
||||
positionInPixels = PointToScreen(mousePos + new Vector(-4, 6)); |
||||
} |
||||
// use device independent units, because Popup Left/Top are in independent units
|
||||
return positionInPixels.TransformFromDevice(this); |
||||
} |
||||
|
||||
Popup CreatePopup() |
||||
{ |
||||
popup = new Popup(); |
||||
popup.Closed += PopupClosed; |
||||
popup.Placement = PlacementMode.Absolute; |
||||
popup.StaysOpen = true; |
||||
return popup; |
||||
} |
||||
|
||||
void TextEditorMouseHoverStopped(object sender, MouseEventArgs e) |
||||
{ |
||||
if (toolTip != null) { |
||||
toolTip.IsOpen = false; |
||||
e.Handled = true; |
||||
} |
||||
} |
||||
|
||||
void TextEditorMouseLeave(object sender, MouseEventArgs e) |
||||
{ |
||||
if (popup != null && !popup.IsMouseOver) { |
||||
// do not close popup if mouse moved from editor to popup
|
||||
TryCloseExistingPopup(false); |
||||
} |
||||
} |
||||
|
||||
void ToolTipClosed(object sender, RoutedEventArgs e) |
||||
{ |
||||
toolTip = null; |
||||
} |
||||
|
||||
void PopupClosed(object sender, EventArgs e) |
||||
{ |
||||
popup = null; |
||||
} |
||||
#endregion
|
||||
|
||||
#region Ctrl+Click Go To Definition
|
||||
void TextViewMouseDown(object sender, MouseButtonEventArgs e) |
||||
{ |
||||
// close existing popup immediately on text editor mouse down
|
||||
TryCloseExistingPopup(false); |
||||
if (e.ChangedButton == MouseButton.Left && Keyboard.Modifiers == ModifierKeys.Control) { |
||||
var position = GetPositionFromPoint(e.GetPosition(this)); |
||||
if (position != null) { |
||||
GoToDefinition.Run(this.Adapter, this.Document.GetOffset(position.Value)); |
||||
e.Handled = true; |
||||
} |
||||
} |
||||
} |
||||
#endregion
|
||||
|
||||
public void JumpTo(int line, int column) |
||||
{ |
||||
TryCloseExistingPopup(true); |
||||
|
||||
// the adapter sets the caret position and takes care of scrolling
|
||||
this.Adapter.JumpTo(line, column); |
||||
this.Focus(); |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue