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 @@ |
|||||||
|
/* |
||||||
|
* 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