Browse Source

fix bugs in SearchPanel + add documentation comments

pull/23/head
Siegfried Pammer 15 years ago
parent
commit
3990aedb27
  1. 20
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Search/ISearchStrategy.cs
  2. 10
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Search/SearchCommands.cs
  3. 9
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Search/SearchPanel.xaml
  4. 72
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Search/SearchPanel.xaml.cs
  5. 7
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Search/SearchStrategyFactory.cs

20
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Search/ISearchStrategy.cs

@ -10,33 +10,45 @@ using ICSharpCode.AvalonEdit.Document;
namespace ICSharpCode.AvalonEdit.Search namespace ICSharpCode.AvalonEdit.Search
{ {
/// <summary> /// <summary>
/// Description of ISearchStrategy. /// Basic interface for search algorithms.
/// </summary> /// </summary>
public interface ISearchStrategy public interface ISearchStrategy
{ {
/// <summary>
/// Finds all matches for a predicate in the given ITextSource.
/// </summary>
/// <remarks>This method is thread-safe.</remarks>
IEnumerable<ISearchResult> FindAll(ITextSource document); IEnumerable<ISearchResult> FindAll(ITextSource document);
} }
/// <summary>
/// Represents a search result.
/// </summary>
public interface ISearchResult : ISegment public interface ISearchResult : ISegment
{ {
} }
/// <inheritdoc/>
public class SearchPatternException : Exception, ISerializable public class SearchPatternException : Exception, ISerializable
{ {
/// <inheritdoc/>
public SearchPatternException() public SearchPatternException()
{ {
} }
public SearchPatternException(string message) : base(message) /// <inheritdoc/>
public SearchPatternException(string message) : base(message)
{ {
} }
/// <inheritdoc/>
public SearchPatternException(string message, Exception innerException) : base(message, innerException) public SearchPatternException(string message, Exception innerException) : base(message, innerException)
{ {
} }
// This constructor is needed for serialization. // This constructor is needed for serialization.
/// <inheritdoc/>
protected SearchPatternException(SerializationInfo info, StreamingContext context) : base(info, context) protected SearchPatternException(SerializationInfo info, StreamingContext context) : base(info, context)
{ {
} }

10
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Search/SearchCommands.cs

@ -14,12 +14,22 @@ using ICSharpCode.AvalonEdit.Rendering;
namespace ICSharpCode.AvalonEdit.Search namespace ICSharpCode.AvalonEdit.Search
{ {
/// <summary>
/// Search commands for AvalonEdit.
/// </summary>
public static class SearchCommands public static class SearchCommands
{ {
/// <summary>
/// Finds the next occurrence in the file.
/// </summary>
public static readonly RoutedCommand FindNext = new RoutedCommand( public static readonly RoutedCommand FindNext = new RoutedCommand(
"FindNext", typeof(SearchPanel), "FindNext", typeof(SearchPanel),
new InputGestureCollection { new KeyGesture(Key.F3) } new InputGestureCollection { new KeyGesture(Key.F3) }
); );
/// <summary>
/// Finds the previous occurrence in the file.
/// </summary>
public static readonly RoutedCommand FindPrevious = new RoutedCommand( public static readonly RoutedCommand FindPrevious = new RoutedCommand(
"FindPrevious", typeof(SearchPanel), "FindPrevious", typeof(SearchPanel),
new InputGestureCollection { new KeyGesture(Key.F3, ModifierKeys.Shift) } new InputGestureCollection { new KeyGesture(Key.F3, ModifierKeys.Shift) }

9
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Search/SearchPanel.xaml

@ -16,7 +16,7 @@
<Popup StaysOpen="False"> <Popup StaysOpen="False">
<Border Background="White" BorderBrush="DimGray" BorderThickness="1"> <Border Background="White" BorderBrush="DimGray" BorderThickness="1">
<StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical">
<CheckBox x:FieldModifier="private" x:Name="matchCase" Content="Match case" Margin="3" /> <CheckBox x:FieldModifier="private" x:Name="matchCase" Content="Match case" Margin="3" />
<CheckBox x:FieldModifier="private" x:Name="wholeWords" Content="Match whole words" Margin="3" /> <CheckBox x:FieldModifier="private" x:Name="wholeWords" Content="Match whole words" Margin="3" />
<CheckBox x:FieldModifier="private" x:Name="useRegex" Content="Use Regular Expressions" Margin="3" /> <CheckBox x:FieldModifier="private" x:Name="useRegex" Content="Use Regular Expressions" Margin="3" />
</StackPanel> </StackPanel>
@ -30,10 +30,11 @@
<Button Margin="3" Height="24" Width="24" Command="local:SearchCommands.FindNext" ToolTip="Find Next (F3)"> <Button Margin="3" Height="24" Width="24" Command="local:SearchCommands.FindNext" ToolTip="Find Next (F3)">
<Image Width="16" Height="16" Stretch="Fill" Source="next.png" /> <Image Width="16" Height="16" Stretch="Fill" Source="next.png" />
</Button> </Button>
<Button Click="CloseClick" HorizontalAlignment="Right" VerticalAlignment="Top" Height="16" Width="16"> <Button Click="CloseClick" Height="16" Width="16" HorizontalAlignment="Right" VerticalAlignment="Top"
VerticalContentAlignment="Center" HorizontalContentAlignment="Center">
<Grid> <Grid>
<Line X1="2" Y1="2" X2="8" Y2="8" Stroke="Black" StrokeThickness="1" /> <Line X1="0" Y1="0" X2="8" Y2="8" Stroke="Black" StrokeThickness="1" />
<Line X1="8" Y1="2" X2="2" Y2="8" Stroke="Black" StrokeThickness="1" /> <Line X1="8" Y1="0" X2="0" Y2="8" Stroke="Black" StrokeThickness="1" />
</Grid> </Grid>
</Button> </Button>
</StackPanel> </StackPanel>

72
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Search/SearchPanel.xaml.cs

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Windows; using System.Windows;
@ -30,13 +31,16 @@ namespace ICSharpCode.AvalonEdit.Search
SearchResult currentResult; SearchResult currentResult;
FoldingManager foldingManager; FoldingManager foldingManager;
public bool UseRegex { get { return useRegex.IsChecked == true; } } bool UseRegex { get { return useRegex.IsChecked == true; } }
public bool MatchCase { get { return matchCase.IsChecked == true; } } bool MatchCase { get { return matchCase.IsChecked == true; } }
public bool WholeWords { get { return wholeWords.IsChecked == true; } } bool WholeWords { get { return wholeWords.IsChecked == true; } }
string searchPattern; string searchPattern;
ISearchStrategy strategy; ISearchStrategy strategy;
/// <summary>
/// Gets/sets the content of the search box and the search string.
/// </summary>
public string SearchPattern { public string SearchPattern {
get { return searchPattern; } get { return searchPattern; }
set { set {
@ -45,18 +49,16 @@ namespace ICSharpCode.AvalonEdit.Search
} }
} }
void UpdateSearch(bool throwException = true) void UpdateSearch()
{ {
if (!string.IsNullOrEmpty(searchPattern)) { messageView.IsOpen = false;
try { strategy = SearchStrategyFactory.Create(searchPattern ?? "", !MatchCase, UseRegex, WholeWords);
strategy = SearchStrategyFactory.Create(searchPattern, !MatchCase, UseRegex, WholeWords); DoSearch(true);
DoSearch(true);
} catch (SearchPatternException) {
if (throwException) throw;
}
}
} }
/// <summary>
/// Creates a new SearchPanel and attaches it to a text area.
/// </summary>
public SearchPanel(TextArea textArea) public SearchPanel(TextArea textArea)
{ {
if (textArea == null) if (textArea == null)
@ -73,13 +75,25 @@ namespace ICSharpCode.AvalonEdit.Search
textArea.Document.TextChanged += delegate { DoSearch(false); }; textArea.Document.TextChanged += delegate { DoSearch(false); };
this.Loaded += delegate { searchTextBox.Focus(); }; this.Loaded += delegate { searchTextBox.Focus(); };
useRegex.Checked += delegate { UpdateSearch(false); }; useRegex.Checked += ValidateSearchText;
matchCase.Checked += delegate { UpdateSearch(false); }; matchCase.Checked += ValidateSearchText;
wholeWords.Checked += delegate { UpdateSearch(false); }; wholeWords.Checked += ValidateSearchText;
useRegex.Unchecked += delegate { UpdateSearch(false); }; useRegex.Unchecked += ValidateSearchText;
matchCase.Unchecked += delegate { UpdateSearch(false); }; matchCase.Unchecked += ValidateSearchText;
wholeWords.Unchecked += delegate { UpdateSearch(false); }; wholeWords.Unchecked += ValidateSearchText;
}
void ValidateSearchText(object sender, RoutedEventArgs e)
{
var be = searchTextBox.GetBindingExpression(TextBox.TextProperty);
try {
Validation.ClearInvalid(be);
UpdateSearch();
} catch (SearchPatternException ex) {
var ve = new ValidationError(be.ParentBinding.ValidationRules[0], be, ex.Message, ex);
Validation.MarkInvalid(be, ve);
}
} }
/// <summary> /// <summary>
@ -91,6 +105,9 @@ namespace ICSharpCode.AvalonEdit.Search
searchTextBox.SelectAll(); searchTextBox.SelectAll();
} }
/// <summary>
/// Moves to the next occurrence in the file.
/// </summary>
public void FindNext() public void FindNext()
{ {
SearchResult result = null; SearchResult result = null;
@ -104,6 +121,9 @@ namespace ICSharpCode.AvalonEdit.Search
} }
} }
/// <summary>
/// Moves to the previous occurrence in the file.
/// </summary>
public void FindPrevious() public void FindPrevious()
{ {
SearchResult result = null; SearchResult result = null;
@ -155,17 +175,21 @@ namespace ICSharpCode.AvalonEdit.Search
{ {
switch (e.Key) { switch (e.Key) {
case Key.Enter: case Key.Enter:
try { e.Handled = true;
messageView.IsOpen = false; messageView.IsOpen = false;
messageView.Content = null; if ((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift)
UpdateSearch(); FindPrevious();
} catch (SearchPatternException ex) { else
messageView.Content = "Error: " + ex.Message; FindNext();
var error = Validation.GetErrors(searchTextBox).FirstOrDefault();
if (error != null) {
messageView.Content = "Error: " + error.ErrorContent;
messageView.PlacementTarget = searchTextBox; messageView.PlacementTarget = searchTextBox;
messageView.IsOpen = true; messageView.IsOpen = true;
} }
break; break;
case Key.Escape: case Key.Escape:
e.Handled = true;
CloseClick(sender, e); CloseClick(sender, e);
break; break;
} }

7
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Search/SearchStrategyFactory.cs

@ -3,11 +3,18 @@
using System; using System;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Windows.Controls;
namespace ICSharpCode.AvalonEdit.Search namespace ICSharpCode.AvalonEdit.Search
{ {
/// <summary>
/// Provides factory methods for ISearchStrategies.
/// </summary>
public class SearchStrategyFactory public class SearchStrategyFactory
{ {
/// <summary>
/// Creates a default ISearchStrategy with the given parameters.
/// </summary>
public static ISearchStrategy Create(string searchPattern, bool ignoreCase, bool useRegularExpressions, bool matchWholeWords) public static ISearchStrategy Create(string searchPattern, bool ignoreCase, bool useRegularExpressions, bool matchWholeWords)
{ {
if (searchPattern == null) if (searchPattern == null)

Loading…
Cancel
Save