diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpCompletionBinding.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpCompletionBinding.cs index 3d23ca414f..3a6e0ab3c6 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpCompletionBinding.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpCompletionBinding.cs @@ -36,17 +36,7 @@ namespace CSharpBinding CSharpExpressionFinder ef = CreateExpressionFinder(editor.FileName); int cursor = editor.Caret.Offset; ExpressionContext context = null; - if (ch == '(') { - if (context != null) { - if (IsInComment(editor)) return CodeCompletionKeyPressResult.None; - new CtrlSpaceCompletionItemProvider(context).ShowCompletion(editor); - return CodeCompletionKeyPressResult.Completed; - } else if (EnableMethodInsight && CodeCompletionOptions.InsightEnabled) { - editor.ShowInsightWindow(new MethodInsightDataProvider()); - return CodeCompletionKeyPressResult.Completed; - } - return CodeCompletionKeyPressResult.None; - } else if (ch == '[') { + if (ch == '[') { var line = editor.Document.GetLineForOffset(cursor); /* TODO: AVALONEDIT Reimplement this if (TextUtilities.FindPrevWordStart(editor.ActiveTextAreaControl.Document, cursor) <= line.Offset) { diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/AvalonEdit.AddIn.csproj b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/AvalonEdit.AddIn.csproj index 3c1b84aa8a..9779b265ae 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/AvalonEdit.AddIn.csproj +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/AvalonEdit.AddIn.csproj @@ -70,6 +70,7 @@ Code + @@ -79,11 +80,6 @@ ICSharpCode.AvalonEdit False - - {2D18BE89-D210-49EB-A9DD-2246FBB3DF6D} - ICSharpCode.TextEditor - False - {3A9AE6AA-BC07-4A2F-972C-581E3AE2F195} NRefactory diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs index 7def95efe1..bc4580f66b 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs @@ -301,6 +301,9 @@ namespace ICSharpCode.AvalonEdit.AddIn // tell it to expect the text insertion completionWindow.ExpectInsertionBeforeStart = true; } + if (insightWindow != null) { + insightWindow.ExpectInsertionBeforeStart = true; + } return; } else if (result == CodeCompletionKeyPressResult.CompletedIncludeKeyInCompletion) { if (completionWindow != null) { @@ -317,11 +320,18 @@ namespace ICSharpCode.AvalonEdit.AddIn } } + TextEditor GetTextEditorFromRoutedCommand(object sender) + { + TextArea textArea = (TextArea)sender; + TextEditor textEditor = (TextEditor)textArea.GetService(typeof(TextEditor)); + Debug.Assert(textEditor != null); + return textEditor; + } + void OnCodeCompletion(object sender, ExecutedRoutedEventArgs e) { - TextEditor textEditor = (TextEditor)sender; - if (completionWindow != null) - completionWindow.Close(); + CloseExistingCompletionWindows(); + TextEditor textEditor = GetTextEditorFromRoutedCommand(sender); foreach (ICodeCompletionBinding cc in CodeCompletionBindings) { if (cc.CtrlSpace(GetAdapter(textEditor))) { e.Handled = true; @@ -332,7 +342,7 @@ namespace ICSharpCode.AvalonEdit.AddIn void OnDeleteLine(object sender, ExecutedRoutedEventArgs e) { - TextEditor textEditor = (TextEditor)sender; + TextEditor textEditor = GetTextEditorFromRoutedCommand(sender); e.Handled = true; using (textEditor.Document.RunUpdate()) { DocumentLine currentLine = textEditor.Document.GetLineByNumber(textEditor.TextArea.Caret.Line); @@ -342,19 +352,40 @@ namespace ICSharpCode.AvalonEdit.AddIn } CompletionWindow completionWindow; + SharpDevelopInsightWindow insightWindow; - internal void NotifyCompletionWindowOpened(CompletionWindow window) + void CloseExistingCompletionWindows() { if (completionWindow != null) { - // if there already is a completion window open, close it completionWindow.Close(); } + if (insightWindow != null) { + insightWindow.Close(); + } + } + + public SharpDevelopInsightWindow ActiveInsightWindow { + get { return insightWindow; } + } + + internal void NotifyCompletionWindowOpened(CompletionWindow window) + { + CloseExistingCompletionWindows(); completionWindow = window; window.Closed += delegate { completionWindow = null; }; } + internal void NotifyInsightWindowOpened(SharpDevelopInsightWindow window) + { + CloseExistingCompletionWindows(); + insightWindow = window; + window.Closed += delegate { + insightWindow = null; + }; + } + IFormattingStrategy formattingStrategy; public IFormattingStrategy FormattingStrategy { diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs index b641272f67..1ed944781c 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs @@ -6,7 +6,9 @@ // using System; +using System.Collections.Generic; using System.Linq; + using ICSharpCode.AvalonEdit.CodeCompletion; using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Editor; @@ -39,5 +41,27 @@ namespace ICSharpCode.AvalonEdit.AddIn codeEditor.NotifyCompletionWindowOpened(window); window.Show(); } + + public override IInsightWindow ShowInsightWindow(IEnumerable items) + { + if (items == null) + return null; + var insightWindow = new SharpDevelopInsightWindow(this.TextEditor.TextArea); + insightWindow.Items.AddRange(items); + if (insightWindow.Items.Count > 0) { + insightWindow.SelectedItem = insightWindow.Items[0]; + } else { + // don't open insight window when there are no items + return null; + } + codeEditor.NotifyInsightWindowOpened(insightWindow); + insightWindow.Show(); + + return insightWindow; + } + + public override IInsightWindow ActiveInsightWindow { + get { return codeEditor.ActiveInsightWindow; } + } } } diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/SharpDevelopInsightWindow.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/SharpDevelopInsightWindow.cs new file mode 100644 index 0000000000..317943a25b --- /dev/null +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/SharpDevelopInsightWindow.cs @@ -0,0 +1,114 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.ComponentModel; + +using ICSharpCode.AvalonEdit.CodeCompletion; +using ICSharpCode.SharpDevelop.Editor; + +namespace ICSharpCode.AvalonEdit.AddIn +{ + /// + /// Adapter between AvalonEdit InsightWindow and SharpDevelop IInsightWindow interface. + /// + public class SharpDevelopInsightWindow : OverloadInsightWindow, IInsightWindow + { + sealed class SDItemProvider : IOverloadProvider + { + readonly SharpDevelopInsightWindow insightWindow; + int selectedIndex; + + public SDItemProvider(SharpDevelopInsightWindow insightWindow) + { + this.insightWindow = insightWindow; + insightWindow.items.CollectionChanged += insightWindow_items_CollectionChanged; + } + + void insightWindow_items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + OnPropertyChanged("Count"); + OnPropertyChanged("CurrentHeader"); + OnPropertyChanged("CurrentContent"); + OnPropertyChanged("CurrentIndexText"); + } + + public event PropertyChangedEventHandler PropertyChanged; + + public int SelectedIndex { + get { + return selectedIndex; + } + set { + if (selectedIndex != value) { + selectedIndex = value; + OnPropertyChanged("SelectedIndex"); + OnPropertyChanged("CurrentHeader"); + OnPropertyChanged("CurrentContent"); + OnPropertyChanged("CurrentIndexText"); + } + } + } + + public int Count { + get { return insightWindow.Items.Count; } + } + + public string CurrentIndexText { + get { return (selectedIndex + 1).ToString() + " of " + this.Count.ToString(); } + } + + public object CurrentHeader { + get { + IInsightItem item = insightWindow.SelectedItem; + return item != null ? item.Header : null; + } + } + + public object CurrentContent { + get { + IInsightItem item = insightWindow.SelectedItem; + return item != null ? item.Content : null; + } + } + + void OnPropertyChanged(string propertyName) + { + if (PropertyChanged != null) { + PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + } + } + + readonly ObservableCollection items = new ObservableCollection(); + + public SharpDevelopInsightWindow(TextArea textArea) : base(textArea) + { + this.Provider = new SDItemProvider(this); + } + + public IList Items { + get { return items; } + } + + public IInsightItem SelectedItem { + get { + int index = this.Provider.SelectedIndex; + if (index < 0 || index >= items.Count) + return null; + else + return items[index]; + } + set { + this.Provider.SelectedIndex = items.IndexOf(value); + } + } + } +} diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.cs index 3736fe1d13..c71b9b601a 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.cs @@ -25,9 +25,6 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion /// public class CompletionWindow : CompletionWindowBase { - TextDocument document; - int startOffset; - int endOffset; readonly CompletionList completionList = new CompletionList(); ToolTip toolTip = new ToolTip(); @@ -48,8 +45,6 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion toolTip.Placement = PlacementMode.Right; toolTip.Closed += toolTip_Closed; - startOffset = endOffset = this.TextArea.Caret.Offset; - document = textArea.TextView.Document; completionList.InsertionRequested += completionList_InsertionRequested; completionList.SelectionChanged += completionList_SelectionChanged; } @@ -83,28 +78,10 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion { var item = completionList.SelectedItem; if (item != null) - item.Complete(this.TextArea, new AnchorSegment(this.TextArea.Document, startOffset, endOffset - startOffset), e); + item.Complete(this.TextArea, new AnchorSegment(this.TextArea.Document, this.StartOffset, this.EndOffset - this.StartOffset), e); Close(); } - /// - /// Gets/Sets the start offset of the edited text portion. - /// This text portion is used to determine the text used to select an entry in the completion list by typing. - /// - public int StartOffset { - get { return startOffset; } - set { startOffset = value; } - } - - /// - /// Gets/Sets the end offset of the edited text portion. - /// This text portion is used to determine the text used to select an entry in the completion list by typing. - /// - public int EndOffset { - get { return endOffset; } - set { endOffset = value; } - } - /// protected override void OnSourceInitialized(EventArgs e) { @@ -121,7 +98,6 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion protected override void AttachEvents() { base.AttachEvents(); - document.Changing += textArea_Document_Changing; this.TextArea.Caret.PositionChanged += CaretPositionChanged; this.TextArea.MouseWheel += textArea_MouseWheel; this.TextArea.PreviewTextInput += textArea_PreviewTextInput; @@ -131,7 +107,6 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion /// protected override void DetachEvents() { - document.Changing -= textArea_Document_Changing; this.TextArea.Caret.PositionChanged -= CaretPositionChanged; this.TextArea.MouseWheel -= textArea_MouseWheel; this.TextArea.PreviewTextInput -= textArea_PreviewTextInput; @@ -212,25 +187,6 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion return completionList.ScrollViewer ?? completionList.ListBox ?? (UIElement)completionList; } - /// - /// Gets/sets whether the completion window should expect text insertion at the start offset, - /// which not go into the completion region, but before it. - /// - /// This property allows only a single insertion, it is reset to false - /// when that insertion has occurred. - public bool ExpectInsertionBeforeStart { get; set; } - - void textArea_Document_Changing(object sender, DocumentChangeEventArgs e) - { - if (e.Offset == startOffset && e.RemovalLength == 0 && ExpectInsertionBeforeStart) { - startOffset = e.GetNewOffset(startOffset, AnchorMovementType.AfterInsertion); - this.ExpectInsertionBeforeStart = false; - } else { - startOffset = e.GetNewOffset(startOffset, AnchorMovementType.BeforeInsertion); - } - endOffset = e.GetNewOffset(endOffset, AnchorMovementType.AfterInsertion); - } - /// /// When this flag is set, code completion closes if the caret moves to the /// beginning of the allowed range. This is useful in Ctrl+Space and "complete when typing", @@ -241,15 +197,18 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion void CaretPositionChanged(object sender, EventArgs e) { int offset = this.TextArea.Caret.Offset; - if (offset == startOffset) { + if (offset == this.StartOffset) { if (CloseWhenCaretAtBeginning) Close(); return; } - if (offset < startOffset || offset > endOffset) { + if (offset < this.StartOffset || offset > this.EndOffset) { Close(); } else { - completionList.SelectItemWithStart(document.GetText(startOffset, offset - startOffset)); + TextDocument document = this.TextArea.Document; + if (document != null) { + completionList.SelectItemWithStart(document.GetText(this.StartOffset, offset - this.StartOffset)); + } } } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindowBase.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindowBase.cs index 8537602367..a97960ab5b 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindowBase.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindowBase.cs @@ -5,12 +5,12 @@ // $Revision$ // +using ICSharpCode.AvalonEdit.Document; using System; using System.Diagnostics; using System.Windows; using System.Windows.Input; using System.Windows.Threading; - using ICSharpCode.AvalonEdit.Gui; using ICSharpCode.AvalonEdit.Utils; @@ -34,6 +34,9 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion public TextArea TextArea { get; private set; } Window parentWindow; + TextDocument document; + int startOffset; + int endOffset; /// /// Creates a new CompletionWindowBase. @@ -46,6 +49,8 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion parentWindow = Window.GetWindow(textArea); this.Owner = parentWindow; this.AddHandler(MouseUpEvent, new MouseButtonEventHandler(OnMouseUp), true); + + startOffset = endOffset = this.TextArea.Caret.Offset; } #region Event Handlers @@ -54,11 +59,15 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion /// protected virtual void AttachEvents() { + document = this.TextArea.Document; + if (document != null) { + document.Changing += textArea_Document_Changing; + } this.TextArea.PreviewLostKeyboardFocus += TextAreaLostFocus; this.TextArea.TextView.ScrollOffsetChanged += TextViewScrollOffsetChanged; - this.TextArea.TextView.DocumentChanged += TextViewDocumentChanged; - this.TextArea.PreviewKeyDown += textArea_PreviewKeyDown; - this.TextArea.PreviewKeyUp += textArea_PreviewKeyUp; + this.TextArea.DocumentChanged += TextAreaDocumentChanged; + this.TextArea.PreviewKeyDown += TextAreaPreviewKeyDown; + this.TextArea.PreviewKeyUp += TextAreaPreviewKeyUp; if (parentWindow != null) { parentWindow.LocationChanged += parentWindow_LocationChanged; } @@ -69,23 +78,26 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion /// protected virtual void DetachEvents() { + if (document != null) { + document.Changing -= textArea_Document_Changing; + } this.TextArea.PreviewLostKeyboardFocus -= TextAreaLostFocus; this.TextArea.TextView.ScrollOffsetChanged -= TextViewScrollOffsetChanged; - this.TextArea.TextView.DocumentChanged -= TextViewDocumentChanged; - this.TextArea.PreviewKeyDown -= textArea_PreviewKeyDown; - this.TextArea.PreviewKeyUp -= textArea_PreviewKeyUp; + this.TextArea.DocumentChanged -= TextAreaDocumentChanged; + this.TextArea.PreviewKeyDown -= TextAreaPreviewKeyDown; + this.TextArea.PreviewKeyUp -= TextAreaPreviewKeyUp; if (parentWindow != null) { parentWindow.LocationChanged -= parentWindow_LocationChanged; } } - void textArea_PreviewKeyDown(object sender, KeyEventArgs e) + void TextAreaPreviewKeyDown(object sender, KeyEventArgs e) { e.Handled = RaiseEventPair(this, PreviewKeyDownEvent, KeyDownEvent, new KeyEventArgs(e.KeyboardDevice, e.InputSource, e.Timestamp, e.Key)); } - void textArea_PreviewKeyUp(object sender, KeyEventArgs e) + void TextAreaPreviewKeyUp(object sender, KeyEventArgs e) { e.Handled = RaiseEventPair(this, PreviewKeyUpEvent, KeyUpEvent, new KeyEventArgs(e.KeyboardDevice, e.InputSource, e.Timestamp, e.Key)); @@ -96,7 +108,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion UpdatePosition(); } - void TextViewDocumentChanged(object sender, EventArgs e) + void TextAreaDocumentChanged(object sender, EventArgs e) { Close(); } @@ -189,8 +201,13 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion protected override void OnSourceInitialized(EventArgs e) { base.OnSourceInitialized(e); - SetPosition(); AttachEvents(); + + if (document != null && this.StartOffset != this.TextArea.Caret.Offset) { + SetPosition(new TextViewPosition(document.GetLocation(this.StartOffset))); + } else { + SetPosition(this.TextArea.Caret.Position); + } } /// @@ -213,14 +230,14 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion Point visualLocation, visualLocationTop; /// - /// Positions the completion window at the caret position. + /// Positions the completion window at the specified position. /// - void SetPosition() + protected void SetPosition(TextViewPosition position) { TextView textView = this.TextArea.TextView; - visualLocation = textView.GetVisualPosition(this.TextArea.Caret.Position, VisualYPosition.LineBottom); - visualLocationTop = textView.GetVisualPosition(this.TextArea.Caret.Position, VisualYPosition.LineTop); + visualLocation = textView.GetVisualPosition(position, VisualYPosition.LineBottom); + visualLocationTop = textView.GetVisualPosition(position, VisualYPosition.LineTop); UpdatePosition(); } @@ -249,5 +266,42 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion this.Left = bounds.X; this.Top = bounds.Y; } + + /// + /// Gets/Sets the start of the text range in which the completion window stays open. + /// This text portion is used to determine the text used to select an entry in the completion list by typing. + /// + public int StartOffset { + get { return startOffset; } + set { startOffset = value; } + } + + /// + /// Gets/Sets the end of the text range in which the completion window stays open. + /// This text portion is used to determine the text used to select an entry in the completion list by typing. + /// + public int EndOffset { + get { return endOffset; } + set { endOffset = value; } + } + + /// + /// Gets/sets whether the completion window should expect text insertion at the start offset, + /// which not go into the completion region, but before it. + /// + /// This property allows only a single insertion, it is reset to false + /// when that insertion has occurred. + public bool ExpectInsertionBeforeStart { get; set; } + + void textArea_Document_Changing(object sender, DocumentChangeEventArgs e) + { + if (e.Offset == startOffset && e.RemovalLength == 0 && ExpectInsertionBeforeStart) { + startOffset = e.GetNewOffset(startOffset, AnchorMovementType.AfterInsertion); + this.ExpectInsertionBeforeStart = false; + } else { + startOffset = e.GetNewOffset(startOffset, AnchorMovementType.BeforeInsertion); + } + endOffset = e.GetNewOffset(endOffset, AnchorMovementType.AfterInsertion); + } } } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/IOverloadProvider.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/IOverloadProvider.cs new file mode 100644 index 0000000000..309bb7d45c --- /dev/null +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/IOverloadProvider.cs @@ -0,0 +1,46 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; + +namespace ICSharpCode.AvalonEdit.CodeCompletion +{ + /// + /// Provides the items for the OverloadViewer. + /// + public interface IOverloadProvider : INotifyPropertyChanged + { + /// + /// Gets/Sets the selected index. + /// + int SelectedIndex { get; set; } + + /// + /// Gets the number of overloads. + /// + int Count { get; } + + /// + /// Gets the text 'SelectedIndex of Count'. + /// + string CurrentIndexText { get; } + + /// + /// Gets the current header. + /// + object CurrentHeader { get; } + + /// + /// Gets the current content. + /// + object CurrentContent { get; } + } +} diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/InsightWindow.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/InsightWindow.cs index 1dd6501c25..fa0001b40b 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/InsightWindow.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/InsightWindow.cs @@ -5,33 +5,34 @@ // $Revision$ // +using ICSharpCode.AvalonEdit.Gui; using System; using System.Windows; -using ICSharpCode.AvalonEdit.Document; using System.Windows.Controls; +using ICSharpCode.AvalonEdit.Document; +using ICSharpCode.AvalonEdit.Utils; namespace ICSharpCode.AvalonEdit.CodeCompletion { /// - /// A popup-like window. + /// A popup-like window that is attached to a text segment. /// public class InsightWindow : CompletionWindowBase { - TextDocument document; - int startOffset; - int endOffset; + static InsightWindow() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(InsightWindow), + new FrameworkPropertyMetadata(typeof(InsightWindow))); + AllowsTransparencyProperty.OverrideMetadata(typeof(InsightWindow), + new FrameworkPropertyMetadata(Boxes.True)); + } /// /// Creates a new InsightWindow. /// public InsightWindow(TextArea textArea) : base(textArea) { - this.SizeToContent = SizeToContent.WidthAndHeight; - // prevent user from resizing window to 0x0 - this.MinHeight = 15; - this.MinWidth = 30; - - startOffset = endOffset = this.TextArea.Caret.Offset; + this.CloseAutomatically = true; } /// @@ -45,50 +46,27 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion get { return this.CloseAutomatically; } } - /// - /// Gets/Sets the start of the text range in which the insight window stays open. - /// Has no effect if CloseAutomatically is false. - /// - public int StartOffset { get; set; } - - /// - /// Gets/Sets the end of the text range in which the insight window stays open. - /// Has no effect if CloseAutomatically is false. - /// - public int EndOffset { get; set; } - /// protected override void AttachEvents() { base.AttachEvents(); - document = this.TextArea.Document; - if (document != null) { - document.Changing += textArea_Document_Changing; - } this.TextArea.Caret.PositionChanged += CaretPositionChanged; } /// protected override void DetachEvents() { - if (document != null) { - document.Changing -= textArea_Document_Changing; - } this.TextArea.Caret.PositionChanged -= CaretPositionChanged; base.DetachEvents(); } - void textArea_Document_Changing(object sender, DocumentChangeEventArgs e) - { - startOffset = e.GetNewOffset(startOffset, AnchorMovementType.BeforeInsertion); - endOffset = e.GetNewOffset(endOffset, AnchorMovementType.AfterInsertion); - } - void CaretPositionChanged(object sender, EventArgs e) { - int offset = this.TextArea.Caret.Offset; - if (offset < startOffset || offset > endOffset) { - Close(); + if (this.CloseAutomatically) { + int offset = this.TextArea.Caret.Offset; + if (offset < this.StartOffset || offset > this.EndOffset) { + Close(); + } } } } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/InsightWindow.xaml b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/InsightWindow.xaml new file mode 100644 index 0000000000..688e4b84fe --- /dev/null +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/InsightWindow.xaml @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/OverloadInsightWindow.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/OverloadInsightWindow.cs new file mode 100644 index 0000000000..63bdd4a6a1 --- /dev/null +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/OverloadInsightWindow.cs @@ -0,0 +1,56 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Windows; +using System.Windows.Input; + +namespace ICSharpCode.AvalonEdit.CodeCompletion +{ + /// + /// Insight window that shows an OverloadViewer. + /// + public class OverloadInsightWindow : InsightWindow + { + OverloadViewer overloadViewer = new OverloadViewer(); + + /// + /// Creates a new OverloadInsightWindow. + /// + public OverloadInsightWindow(TextArea textArea) : base(textArea) + { + overloadViewer.Margin = new Thickness(2,0,0,0); + this.Content = overloadViewer; + } + + /// + /// Gets/Sets the item provider. + /// + public IOverloadProvider Provider { + get { return overloadViewer.Provider; } + set { overloadViewer.Provider = value; } + } + + /// + protected override void OnKeyDown(KeyEventArgs e) + { + base.OnKeyDown(e); + if (!e.Handled && this.Provider.Count > 1) { + switch (e.Key) { + case Key.Up: + e.Handled = true; + overloadViewer.ChangeIndex(-1); + break; + case Key.Down: + e.Handled = true; + overloadViewer.ChangeIndex(+1); + break; + } + } + } + } +} diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/OverloadViewer.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/OverloadViewer.cs new file mode 100644 index 0000000000..a34377f837 --- /dev/null +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/OverloadViewer.cs @@ -0,0 +1,105 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Globalization; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; + +namespace ICSharpCode.AvalonEdit.CodeCompletion +{ + /// + /// Represents a text between "Up" and "Down" buttons. + /// + public class OverloadViewer : Control + { + static OverloadViewer() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(OverloadViewer), + new FrameworkPropertyMetadata(typeof(OverloadViewer))); + } + + /// + /// The text property. + /// + public static readonly DependencyProperty TextProperty = + DependencyProperty.Register("Text", typeof(string), typeof(OverloadViewer)); + + /// + /// Gets/Sets the text between the Up and Down buttons. + /// + public string Text { + get { return (string)GetValue(TextProperty); } + set { SetValue(TextProperty, value); } + } + + /// + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + Button upButton = (Button)this.Template.FindName("PART_UP", this); + upButton.Click += (sender, e) => { + e.Handled = true; + ChangeIndex(-1); + }; + + Button downButton = (Button)this.Template.FindName("PART_DOWN", this); + downButton.Click += (sender, e) => { + e.Handled = true; + ChangeIndex(+1); + }; + } + + /// + /// The ItemProvider property. + /// + public static readonly DependencyProperty ProviderProperty = + DependencyProperty.Register("Provider", typeof(IOverloadProvider), typeof(OverloadViewer)); + + /// + /// Gets/Sets the item provider. + /// + public IOverloadProvider Provider { + get { return (IOverloadProvider)GetValue(ProviderProperty); } + set { SetValue(ProviderProperty, value); } + } + + /// + /// Changes the selected index. + /// + /// The relative index change - usual values are +1 or -1. + public void ChangeIndex(int relativeIndexChange) + { + IOverloadProvider p = this.Provider; + if (p != null) { + int newIndex = p.SelectedIndex + relativeIndexChange; + if (newIndex < 0) + newIndex = p.Count - 1; + if (newIndex >= p.Count) + newIndex = 0; + p.SelectedIndex = newIndex; + } + } + } + + sealed class CollapseIfSingleOverloadConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return ((int)value < 2) ? Visibility.Collapsed : Visibility.Visible; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/Caret.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/Caret.cs index 8f76bf2f56..2f495eacad 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/Caret.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/Caret.cs @@ -57,6 +57,8 @@ namespace ICSharpCode.AvalonEdit.Gui /// /// Gets/Sets the position of the caret. + /// Retrieving this property will validate the visual column. + /// Use the property instead if you don't need the visual column. /// public TextViewPosition Position { get { @@ -83,6 +85,20 @@ namespace ICSharpCode.AvalonEdit.Gui } } + /// + /// Gets/Sets the location of the caret. + /// The getter of this property is faster than because it doesn't have + /// to validate the visual column. + /// + public TextLocation Location { + get { + return position; + } + set { + this.Position = new TextViewPosition(value); + } + } + /// /// Gets/Sets the caret line. /// diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/CaretNavigationCommandHandler.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/CaretNavigationCommandHandler.cs index 0b3bb5f077..5df4b6b2eb 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/CaretNavigationCommandHandler.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/CaretNavigationCommandHandler.cs @@ -166,7 +166,7 @@ namespace ICSharpCode.AvalonEdit.Gui #region Caret movement static void MoveCaret(TextArea textArea, CaretMovementType direction) { - DocumentLine caretLine = textArea.Document.GetLineByNumber(textArea.Caret.Position.Line); + DocumentLine caretLine = textArea.Document.GetLineByNumber(textArea.Caret.Line); VisualLine visualLine = textArea.TextView.GetOrConstructVisualLine(caretLine); TextViewPosition caretPosition = textArea.Caret.Position; TextLine textLine = visualLine.GetTextLine(caretPosition.VisualColumn); @@ -215,7 +215,7 @@ namespace ICSharpCode.AvalonEdit.Gui if (newVC < 0) newVC = visualLine.VisualLength; // when the caret is already at the start of the text, jump to start before whitespace - if (newVC == textArea.Caret.Position.VisualColumn) + if (newVC == textArea.Caret.VisualColumn) newVC = 0; int offset = visualLine.FirstDocumentLine.Offset + visualLine.GetRelativeOffset(newVC); SetCaretPosition(textArea, newVC, offset); diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/EditingCommandHandler.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/EditingCommandHandler.cs index 8857c3133d..d953aca789 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/EditingCommandHandler.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/EditingCommandHandler.cs @@ -106,7 +106,7 @@ namespace ICSharpCode.AvalonEdit.Gui start = start.NextLine; } } else { - string indentationString = textArea.Options.GetIndentationString(textArea.Caret.Position.VisualColumn); + string indentationString = textArea.Options.GetIndentationString(textArea.Caret.Column); textArea.ReplaceSelectionWithText(indentationString); } } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/SelectionLayer.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/SelectionLayer.cs index 948b767bc2..4a350008a9 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/SelectionLayer.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/SelectionLayer.cs @@ -24,7 +24,7 @@ namespace ICSharpCode.AvalonEdit.Gui TextViewWeakEventManager.ScrollOffsetChanged.AddListener(textView, this); } - public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e) + bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e) { if (managerType == typeof(TextViewWeakEventManager.VisualLinesChanged) || managerType == typeof(TextViewWeakEventManager.ScrollOffsetChanged)) diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextEditor.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextEditor.cs index f8cb410d4b..f821c9a044 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextEditor.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextEditor.cs @@ -47,17 +47,6 @@ namespace ICSharpCode.AvalonEdit { } - // Forward focus to TextArea. - /// - protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e) - { - base.OnGotKeyboardFocus(e); - if (!this.TextArea.IsKeyboardFocusWithin) { - Keyboard.Focus(this.TextArea); - e.Handled = true; - } - } - /// /// Creates a new TextEditor instance. /// @@ -66,11 +55,25 @@ namespace ICSharpCode.AvalonEdit if (textArea == null) throw new ArgumentNullException("textArea"); this.textArea = textArea; + + textArea.TextView.Services.AddService(typeof(TextEditor), this); + this.Options = textArea.Options; this.Document = new TextDocument(); textArea.SetBinding(TextArea.DocumentProperty, new Binding(DocumentProperty.Name) { Source = this }); textArea.SetBinding(TextArea.OptionsProperty, new Binding(OptionsProperty.Name) { Source = this }); } + + // Forward focus to TextArea. + /// + protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e) + { + base.OnGotKeyboardFocus(e); + if (!this.TextArea.IsKeyboardFocusWithin) { + Keyboard.Focus(this.TextArea); + e.Handled = true; + } + } #region Document property /// @@ -169,7 +172,6 @@ namespace ICSharpCode.AvalonEdit } /// - [EditorBrowsable(EditorBrowsableState.Advanced)] protected virtual bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e) { if (managerType == typeof(PropertyChangedWeakEventManager)) { diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs index 3dd62a1683..a12fc0126b 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs @@ -43,7 +43,8 @@ namespace ICSharpCode.AvalonEdit.Highlighting OnDocumentChanged(); } - bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e) + /// + protected virtual bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e) { if (managerType == typeof(TextViewWeakEventManager.DocumentChanged)) { OnDocumentChanged(); @@ -52,6 +53,11 @@ namespace ICSharpCode.AvalonEdit.Highlighting return false; } + bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e) + { + return ReceiveWeakEvent(managerType, sender, e); + } + void OnDocumentChanged() { if (highlighter != null && isInTextView) { diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj index 226f68a61f..e833bc8d46 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj @@ -81,6 +81,9 @@ + + + UndoStack.cs @@ -335,6 +338,7 @@ + diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/TextEditorOptions.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/TextEditorOptions.cs index 936725c13c..622cd53750 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/TextEditorOptions.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/TextEditorOptions.cs @@ -141,7 +141,7 @@ namespace ICSharpCode.AvalonEdit /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")] public string IndentationString { - get { return GetIndentationString(0); } + get { return GetIndentationString(1); } } /// @@ -149,11 +149,11 @@ namespace ICSharpCode.AvalonEdit /// public virtual string GetIndentationString(int column) { - if (column < 0) - throw new ArgumentOutOfRangeException("column", column, "Value must be non-negative."); + if (column < 1) + throw new ArgumentOutOfRangeException("column", column, "Value must be at least 1."); int indentationSize = this.IndentationSize; if (ConvertTabsToSpaces) { - return new string(' ', indentationSize - (column % indentationSize)); + return new string(' ', indentationSize - ((column - 1) % indentationSize)); } else { return "\t"; } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/themes/generic.xaml b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/themes/generic.xaml index ee74102dfa..412c1403cc 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/themes/generic.xaml +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/themes/generic.xaml @@ -5,6 +5,7 @@ +