diff --git a/ICSharpCode.AvalonEdit/GoToPanel.cs b/ICSharpCode.AvalonEdit/GoToPanel.cs
new file mode 100644
index 00000000..51cc438a
--- /dev/null
+++ b/ICSharpCode.AvalonEdit/GoToPanel.cs
@@ -0,0 +1,438 @@
+// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+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 System.Windows.Threading;
+using ICSharpCode.AvalonEdit.Document;
+using ICSharpCode.AvalonEdit.Editing;
+using ICSharpCode.AvalonEdit.Folding;
+using ICSharpCode.AvalonEdit.Rendering;
+
+namespace ICSharpCode.AvalonEdit.Search
+{
+ ///
+ /// Provides go to functionality for AvalonEdit. It is displayed in the top-right corner of the TextArea.
+ ///
+ public class GoToPanel : Control
+ {
+ TextArea textArea;
+ GoToInputHandler handler;
+ TextDocument currentDocument;
+ SearchResultBackgroundRenderer renderer;
+ TextBox searchTextBox;
+ Popup dropdownPopup;
+ GoToPanelAdorner adorner;
+
+ #region
+
+ ///
+ /// Dependency property for .
+ ///
+ public static readonly DependencyProperty SearchPatternProperty =
+ DependencyProperty.Register("SearchPattern", typeof(string), typeof(GoToPanel));
+
+ ///
+ /// Gets/sets the search pattern.
+ ///
+ public string SearchPattern {
+ get { return (string)GetValue(SearchPatternProperty); }
+ set { SetValue(SearchPatternProperty, value); }
+ }
+
+ ///
+ /// Dependency property for .
+ ///
+ public static readonly DependencyProperty MarkerBrushProperty =
+ DependencyProperty.Register("MarkerBrush", typeof(Brush), typeof(GoToPanel),
+ new FrameworkPropertyMetadata(Brushes.LightGreen, MarkerBrushChangedCallback));
+
+ ///
+ /// Gets/sets the Brush used for marking search results in the TextView.
+ ///
+ public Brush MarkerBrush {
+ get { return (Brush)GetValue(MarkerBrushProperty); }
+ set { SetValue(MarkerBrushProperty, value); }
+ }
+
+ ///
+ /// Dependency property for .
+ ///
+ public static readonly DependencyProperty LocalizationProperty =
+ DependencyProperty.Register("Localization", typeof(Localization), typeof(GoToPanel),
+ new FrameworkPropertyMetadata(new Localization()));
+
+ ///
+ /// Gets/sets the localization for the GoToPanel.
+ ///
+ public Localization Localization {
+ get { return (Localization)GetValue(LocalizationProperty); }
+ set { SetValue(LocalizationProperty, value); }
+ }
+ #endregion
+
+ static void MarkerBrushChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ GoToPanel panel = d as GoToPanel;
+ if (panel != null) {
+ panel.renderer.MarkerBrush = (Brush)e.NewValue;
+ }
+ }
+
+ static GoToPanel()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(GoToPanel), new FrameworkPropertyMetadata(typeof(GoToPanel)));
+ }
+
+ ISearchStrategy strategy;
+
+ ///
+ /// Creates a new GoToPanel.
+ ///
+ GoToPanel()
+ {
+ }
+
+ ///
+ /// Attaches this GoToPanel to a TextArea instance.
+ ///
+ [Obsolete("Use the Install method instead")]
+ public void Attach(TextArea textArea)
+ {
+ if (textArea == null)
+ throw new ArgumentNullException("textArea");
+ AttachInternal(textArea);
+ }
+
+ ///
+ /// Creates a GoToPanel and installs it to the TextEditor's TextArea.
+ ///
+ /// This is a convenience wrapper.
+ public static GoToPanel Install(TextEditor editor)
+ {
+ if (editor == null)
+ throw new ArgumentNullException("editor");
+ return Install(editor.TextArea);
+ }
+
+ ///
+ /// Creates a GoToPanel and installs it to the TextArea.
+ ///
+ public static GoToPanel Install(TextArea textArea)
+ {
+ if (textArea == null)
+ throw new ArgumentNullException("textArea");
+ GoToPanel panel = new GoToPanel();
+ panel.AttachInternal(textArea);
+ panel.handler = new GoToInputHandler(textArea, panel);
+ textArea.DefaultInputHandler.NestedInputHandlers.Add(panel.handler);
+ return panel;
+ }
+
+ ///
+ /// Adds the commands used by GoToPanel to the given CommandBindingCollection.
+ ///
+ public void RegisterCommands(CommandBindingCollection commandBindings)
+ {
+ handler.RegisterGlobalCommands(commandBindings);
+ }
+
+ ///
+ /// Removes the GoToPanel from the TextArea.
+ ///
+ public void Uninstall()
+ {
+ CloseAndRemove();
+ textArea.DefaultInputHandler.NestedInputHandlers.Remove(handler);
+ }
+
+ void AttachInternal(TextArea textArea)
+ {
+ this.textArea = textArea;
+ adorner = new GoToPanelAdorner(textArea, this);
+ DataContext = this;
+
+ renderer = new SearchResultBackgroundRenderer();
+ currentDocument = textArea.Document;
+ if (currentDocument != null)
+ currentDocument.TextChanged += textArea_Document_TextChanged;
+ textArea.DocumentChanged += textArea_DocumentChanged;
+ KeyDown += SearchLayerKeyDown;
+
+ this.CommandBindings.Add(new CommandBinding(SearchCommands.GoTo, (sender, e) => GoToNext()));
+ this.CommandBindings.Add(new CommandBinding(SearchCommands.CloseGoToPanel, (sender, e) => Close()));
+ IsClosed = true;
+ }
+
+ void textArea_DocumentChanged(object sender, EventArgs e)
+ {
+ if (currentDocument != null)
+ currentDocument.TextChanged -= textArea_Document_TextChanged;
+ currentDocument = textArea.Document;
+ if (currentDocument != null) {
+ currentDocument.TextChanged += textArea_Document_TextChanged;
+ //DoSearch(false);
+ }
+ }
+
+ void textArea_Document_TextChanged(object sender, EventArgs e)
+ {
+ //DoSearch(false);
+ }
+
+ ///
+ public override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+
+ searchTextBox = Template.FindName("PART_searchTextBox", this) as TextBox;
+ dropdownPopup = Template.FindName("PART_dropdownPopup", this) as Popup;
+ }
+
+
+ ///
+ /// Reactivates the GoToPanel by setting the focus on the search box and selecting all text.
+ ///
+ public void Reactivate()
+ {
+ if (searchTextBox == null)
+ return;
+ searchTextBox.Focus();
+ searchTextBox.SelectAll();
+ }
+
+ ///
+ /// Moves to the found line in the file.
+ ///
+ public void GoToNext()
+ {
+ if (SearchPattern == "" || SearchPattern == null)
+ {
+ SearchPattern = "1";
+ messageView.Content = Localization.Null;
+ return;
+ }
+
+ else if (SearchPattern.All(char.IsDigit))
+ {
+ int Line = Int32.Parse(SearchPattern);
+
+ //messageView.Content = null;
+
+ if (Line > textArea.Document.LineCount)
+ {
+ messageView.IsOpen = true;
+ messageView.Content = Localization.OverBounds;
+ messageView.PlacementTarget = searchTextBox;
+ Line = 1;
+ return;
+ }
+
+ else if (SearchPattern.All(char.IsDigit))
+ {
+ messageView.Content = null;
+ textArea.Caret.Offset = textArea.Document.GetOffset(Line, 0);
+ textArea.Caret.BringCaretToView();
+ textArea.Caret.Show();
+ }
+
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ ToolTip messageView = new ToolTip { Placement = PlacementMode.Bottom, StaysOpen = true, Focusable = false };
+
+ void SelectResult(SearchResult result)
+ {
+ textArea.Caret.Offset = result.StartOffset;
+ textArea.Selection = Selection.Create(textArea, result.StartOffset, result.EndOffset);
+ textArea.Caret.BringCaretToView();
+ // show caret even if the editor does not have the Keyboard Focus
+ textArea.Caret.Show();
+ }
+
+ void SearchLayerKeyDown(object sender, KeyEventArgs e)
+ {
+ switch (e.Key) {
+ case Key.Enter:
+ e.Handled = true;
+ GoToNext();
+ if (searchTextBox != null) {
+ var error = Validation.GetErrors(searchTextBox).FirstOrDefault();
+ if (error != null) {
+ //messageView.Content = Localization.ErrorText + " " + error.ErrorContent;
+ messageView.PlacementTarget = searchTextBox;
+ messageView.IsOpen = true;
+ }
+ }
+ break;
+ case Key.Escape:
+ e.Handled = true;
+ Close();
+ break;
+ }
+ }
+
+ ///
+ /// Gets whether the Panel is already closed.
+ ///
+ public bool IsClosed { get; private set; }
+
+ ///
+ /// Closes the GoToPanel.
+ ///
+ public void Close()
+ {
+ bool hasFocus = this.IsKeyboardFocusWithin;
+
+ var layer = AdornerLayer.GetAdornerLayer(textArea);
+ if (layer != null)
+ layer.Remove(adorner);
+ if (dropdownPopup != null)
+ dropdownPopup.IsOpen = false;
+ messageView.IsOpen = false;
+ textArea.TextView.BackgroundRenderers.Remove(renderer);
+ if (hasFocus)
+ textArea.Focus();
+ IsClosed = true;
+
+ // Clear existing search results so that the segments don't have to be maintained
+ renderer.CurrentResults.Clear();
+ }
+
+ ///
+ /// Closes the GoToPanel and removes it.
+ ///
+ [Obsolete("Use the Uninstall method instead!")]
+ public void CloseAndRemove()
+ {
+ Close();
+ textArea.DocumentChanged -= textArea_DocumentChanged;
+ if (currentDocument != null)
+ currentDocument.TextChanged -= textArea_Document_TextChanged;
+ }
+
+ ///
+ /// Opens the an existing GoTo panel.
+ ///
+ public void Open()
+ {
+ if (!IsClosed) return;
+ var layer = AdornerLayer.GetAdornerLayer(textArea);
+ if (layer != null)
+ layer.Add(adorner);
+ textArea.TextView.BackgroundRenderers.Add(renderer);
+ IsClosed = false;
+ //DoSearch(false);
+ }
+
+ ///
+ /// Fired when GoToSearchOptions are changed inside the GoToPanel.
+ ///
+ public event EventHandler GoToSearchOptionsChanged;
+
+ ///
+ /// Raises the event.
+ ///
+ protected virtual void GoToOnSearchOptionsChanged(GoToSearchOptionsChangedEventArgs e)
+ {
+ if (GoToSearchOptionsChanged != null) {
+ GoToSearchOptionsChanged(this, e);
+ }
+ }
+ }
+
+ ///
+ /// Creats a new instance of GoToOptionsChangedEventArgs
+ ///
+ public class GoToSearchOptionsChangedEventArgs : EventArgs
+ {
+ ///
+ /// Gets the search pattern.
+ ///
+ public string SearchPattern { get; private set; }
+
+ ///
+ /// Gets whether the search pattern should be interpreted case-sensitive.
+ ///
+ public bool MatchCase { get; private set; }
+
+ ///
+ /// Gets whether the search pattern should be interpreted as regular expression.
+ ///
+ public bool UseRegex { get; private set; }
+
+ ///
+ /// Gets whether the search pattern should only match whole words.
+ ///
+ public bool WholeWords { get; private set; }
+
+ ///
+ /// Creates a new GoToSearchOptionsChangedEventArgs instance.
+ ///
+ public GoToSearchOptionsChangedEventArgs(string searchPattern, bool matchCase, bool useRegex, bool wholeWords)
+ {
+ this.SearchPattern = searchPattern;
+ this.MatchCase = matchCase;
+ this.UseRegex = useRegex;
+ this.WholeWords = wholeWords;
+ }
+ }
+
+ class GoToPanelAdorner : Adorner
+ {
+ GoToPanel panel;
+
+ public GoToPanelAdorner(TextArea textArea, GoToPanel panel)
+ : base(textArea)
+ {
+ this.panel = panel;
+ AddVisualChild(panel);
+ }
+
+ protected override int VisualChildrenCount {
+ get { return 1; }
+ }
+
+ protected override Visual GetVisualChild(int index)
+ {
+ if (index != 0)
+ throw new ArgumentOutOfRangeException();
+ return panel;
+ }
+
+ protected override Size ArrangeOverride(Size finalSize)
+ {
+ panel.Arrange(new Rect(new Point(0, 0), finalSize));
+ return new Size(panel.ActualWidth, panel.ActualHeight);
+ }
+ }
+}
diff --git a/ICSharpCode.AvalonEdit/GoToPanel.xaml b/ICSharpCode.AvalonEdit/GoToPanel.xaml
new file mode 100644
index 00000000..a3e60da6
--- /dev/null
+++ b/ICSharpCode.AvalonEdit/GoToPanel.xaml
@@ -0,0 +1,31 @@
+
+
+
\ No newline at end of file
diff --git a/ICSharpCode.AvalonEdit/Localization.cs b/ICSharpCode.AvalonEdit/Localization.cs
new file mode 100644
index 00000000..b6b46055
--- /dev/null
+++ b/ICSharpCode.AvalonEdit/Localization.cs
@@ -0,0 +1,95 @@
+// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+using System;
+using System.ComponentModel;
+
+namespace ICSharpCode.AvalonEdit.Search
+{
+ ///
+ /// Holds default texts for buttons and labels in the SearchPanel. Override properties to add other languages.
+ ///
+ public class Localization
+ {
+ ///
+ /// Default: 'Match case'
+ ///
+ public virtual string MatchCaseText {
+ get { return "Match case"; }
+ }
+
+ ///
+ /// Default: 'Match whole words'
+ ///
+ public virtual string MatchWholeWordsText {
+ get { return "Match whole words"; }
+ }
+
+
+ ///
+ /// Default: 'Use regular expressions'
+ ///
+ public virtual string UseRegexText {
+ get { return "Use regular expressions"; }
+ }
+
+ ///
+ /// Default: 'Find next (F3)'
+ ///
+ public virtual string FindNextText {
+ get { return "Find next (F3)"; }
+ }
+
+ ///
+ /// Default: 'Find previous (Shift+F3)'
+ ///
+ public virtual string FindPreviousText {
+ get { return "Find previous (Shift+F3)"; }
+ }
+
+ ///
+ /// Default: 'Error: '
+ ///
+ public virtual string ErrorText {
+ get { return "Error: "; }
+ }
+
+ ///
+ /// Default: 'No matches found!'
+ ///
+ public virtual string NoMatchesFoundText {
+ get { return "No matches found!"; }
+ }
+
+ ///
+ /// Default: 'No matches found!'
+ ///
+ public virtual string OverBounds
+ {
+ get { return "Over Bounds of Document!"; }
+ }
+
+ ///
+ /// Default: 'No matches found!'
+ ///
+ public virtual string Null
+ {
+ get { return "Box is empty!"; }
+ }
+ }
+}
diff --git a/ICSharpCode.AvalonEdit/SearchCommands.cs b/ICSharpCode.AvalonEdit/SearchCommands.cs
new file mode 100644
index 00000000..6d1c1c5c
--- /dev/null
+++ b/ICSharpCode.AvalonEdit/SearchCommands.cs
@@ -0,0 +1,243 @@
+// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Threading;
+using ICSharpCode.AvalonEdit.Document;
+using ICSharpCode.AvalonEdit.Editing;
+using ICSharpCode.AvalonEdit.Rendering;
+
+namespace ICSharpCode.AvalonEdit.Search
+{
+ ///
+ /// Search commands for AvalonEdit.
+ ///
+ public static class SearchCommands
+ {
+ ///
+ /// Finds the next occurrence in the file.
+ ///
+ public static readonly RoutedCommand FindNext = new RoutedCommand(
+ "FindNext", typeof(SearchPanel),
+ new InputGestureCollection { new KeyGesture(Key.F3) }
+ );
+
+ ///
+ /// Finds the line in the file.
+ ///
+ public static readonly RoutedCommand GoTo = new RoutedCommand(
+ "GoTo", typeof(GoToPanel),
+ new InputGestureCollection { new KeyGesture(Key.G, ModifierKeys.Control) }
+ );
+
+ ///
+ /// Finds the previous occurrence in the file.
+ ///
+ public static readonly RoutedCommand FindPrevious = new RoutedCommand(
+ "FindPrevious", typeof(SearchPanel),
+ new InputGestureCollection { new KeyGesture(Key.F3, ModifierKeys.Shift) }
+ );
+
+ ///
+ /// Closes the SearchPanel.
+ ///
+ public static readonly RoutedCommand CloseSearchPanel = new RoutedCommand(
+ "CloseSearchPanel", typeof(SearchPanel),
+ new InputGestureCollection { new KeyGesture(Key.Escape) }
+ );
+
+ ///
+ /// Closes the SearchPanel.
+ ///
+ public static readonly RoutedCommand CloseGoToPanel = new RoutedCommand(
+ "CloseGoToPanel", typeof(GoToPanel),
+ new InputGestureCollection { new KeyGesture(Key.Escape) }
+ );
+ }
+
+ ///
+ /// TextAreaInputHandler that registers all search-related commands.
+ ///
+ public class SearchInputHandler : TextAreaInputHandler
+ {
+ ///
+ /// Creates a new SearchInputHandler and registers the search-related commands.
+ ///
+ [Obsolete("Use SearchPanel.Install instead")]
+ public SearchInputHandler(TextArea textArea)
+ : base(textArea)
+ {
+ RegisterCommands(this.CommandBindings);
+ panel = SearchPanel.Install(textArea);
+ }
+
+ internal SearchInputHandler(TextArea textArea, SearchPanel panel)
+ : base(textArea)
+ {
+ RegisterCommands(this.CommandBindings);
+ this.panel = panel;
+ }
+
+ internal void RegisterGlobalCommands(CommandBindingCollection commandBindings)
+ {
+ commandBindings.Add(new CommandBinding(ApplicationCommands.Find, ExecuteFind));
+ commandBindings.Add(new CommandBinding(SearchCommands.FindNext, ExecuteFindNext, CanExecuteWithOpenSearchPanel));
+ commandBindings.Add(new CommandBinding(SearchCommands.FindPrevious, ExecuteFindPrevious, CanExecuteWithOpenSearchPanel));
+ }
+
+ void RegisterCommands(ICollection commandBindings)
+ {
+
+ commandBindings.Add(new CommandBinding(ApplicationCommands.Find, ExecuteFind));
+ commandBindings.Add(new CommandBinding(SearchCommands.FindNext, ExecuteFindNext, CanExecuteWithOpenSearchPanel));
+ commandBindings.Add(new CommandBinding(SearchCommands.FindPrevious, ExecuteFindPrevious, CanExecuteWithOpenSearchPanel));
+ commandBindings.Add(new CommandBinding(SearchCommands.CloseSearchPanel, ExecuteCloseSearchPanel, CanExecuteWithOpenSearchPanel));
+ }
+
+ SearchPanel panel;
+
+ void ExecuteFind(object sender, ExecutedRoutedEventArgs e)
+ {
+ panel.Open();
+ if (!(TextArea.Selection.IsEmpty || TextArea.Selection.IsMultiline))
+ panel.SearchPattern = TextArea.Selection.GetText();
+ Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Input, (Action)delegate { panel.Reactivate(); });
+ }
+
+ void CanExecuteWithOpenSearchPanel(object sender, CanExecuteRoutedEventArgs e)
+ {
+ if (panel.IsClosed) {
+ e.CanExecute = false;
+ // Continue routing so that the key gesture can be consumed by another component.
+ e.ContinueRouting = true;
+ } else {
+ e.CanExecute = true;
+ e.Handled = true;
+ }
+ }
+
+ void ExecuteFindNext(object sender, ExecutedRoutedEventArgs e)
+ {
+ if (!panel.IsClosed) {
+ panel.FindNext();
+ e.Handled = true;
+ }
+ }
+
+ void ExecuteFindPrevious(object sender, ExecutedRoutedEventArgs e)
+ {
+ if (!panel.IsClosed) {
+ panel.FindPrevious();
+ e.Handled = true;
+ }
+ }
+
+ void ExecuteCloseSearchPanel(object sender, ExecutedRoutedEventArgs e)
+ {
+ if (!panel.IsClosed) {
+ panel.Close();
+ e.Handled = true;
+ }
+ }
+
+ ///
+ /// Fired when SearchOptions are modified inside the SearchPanel.
+ ///
+ public event EventHandler SearchOptionsChanged {
+ add { panel.SearchOptionsChanged += value; }
+ remove { panel.SearchOptionsChanged -= value; }
+ }
+ }
+
+
+
+ ///
+ /// TextAreaInputHandler that registers the goto line commands.
+ ///
+ public class GoToInputHandler : TextAreaInputHandler
+ {
+ ///
+ /// Creates a new SearchInputHandler and registers the search-related commands.
+ ///
+ [Obsolete("Use SearchPanel.Install instead")]
+ public GoToInputHandler(TextArea textArea)
+ : base(textArea)
+ {
+ RegisterCommands(this.CommandBindings);
+ panel2 = GoToPanel.Install(textArea);
+ }
+
+ internal GoToInputHandler(TextArea textArea, GoToPanel panel2)
+ : base(textArea)
+ {
+ RegisterCommands(this.CommandBindings);
+ this.panel2 = panel2;
+ }
+
+ internal void RegisterGlobalCommands(CommandBindingCollection commandBindings)
+ {
+ commandBindings.Add(new CommandBinding(AvalonEditCommands.GoTo, ExecuteGoTo));
+ }
+
+ void RegisterCommands(ICollection commandBindings)
+ {
+ commandBindings.Add(new CommandBinding(AvalonEditCommands.GoTo, ExecuteGoTo));
+ commandBindings.Add(new CommandBinding(SearchCommands.CloseGoToPanel, ExecuteCloseSearchPanel, CanExecuteWithOpenSearchPanel));
+ }
+
+ GoToPanel panel2;
+
+ void ExecuteGoTo(object sender, ExecutedRoutedEventArgs e)
+ {
+ panel2.Open();
+ if (!(TextArea.Selection.IsEmpty || TextArea.Selection.IsMultiline))
+ panel2.SearchPattern = TextArea.Selection.GetText();
+ Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Input, (Action)delegate { panel2.Reactivate(); });
+ }
+
+ void CanExecuteWithOpenSearchPanel(object sender, CanExecuteRoutedEventArgs e)
+ {
+ if (panel2.IsClosed)
+ {
+ e.CanExecute = false;
+ // Continue routing so that the key gesture can be consumed by another component.
+ e.ContinueRouting = true;
+ }
+ else
+ {
+ e.CanExecute = true;
+ e.Handled = true;
+ }
+ }
+
+ void ExecuteCloseSearchPanel(object sender, ExecutedRoutedEventArgs e)
+ {
+ if (!panel2.IsClosed)
+ {
+ panel2.Close();
+ e.Handled = true;
+ }
+ }
+ }
+}