Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added ability to search objects using regular expressions #787

Merged
merged 6 commits into from
Feb 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public interface IObjectTreeViewModel : IViewModel
ObservableCollection<IObjectTreeRootItemViewModel> Types { get; }

bool IsInEditMode { get; }
void Search(string searchText);
void Search(string searchText, SearchMode searchMode);
void SetSelectionState(bool value);
bool? GetSelectionState();
IEnumerable<SerializationTableModel> GetSelectedObjects();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public interface IPickTablesViewModel : IViewModel

bool? TableSelectionThreeState { get; set; }
string SearchText { get; set; }
SearchMode SearchMode { get; set; }
IObjectTreeViewModel ObjectTree { get; }

/// <summary>
Expand Down
8 changes: 8 additions & 0 deletions src/GUI/EFCorePowerTools/Contracts/ViewModels/SearchMode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace EFCorePowerTools.Contracts.ViewModels
{
public enum SearchMode
{
Text,
RegularExpression
}
}
19 changes: 19 additions & 0 deletions src/GUI/EFCorePowerTools/Converter/EnumToBoolConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Globalization;
using System.Windows.Data;

namespace EFCorePowerTools.Converter
{
public class EnumToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value.Equals(parameter);
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value.Equals(true) ? parameter : Binding.DoNothing;
}
}
}
1 change: 1 addition & 0 deletions src/GUI/EFCorePowerTools/Dialogs/Converter.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<converter:CollectionCountToEnabledConverter x:Key="CollectionCountToEnabledConverter"/>
<converter:ColumnEnabledConverter x:Key="ColumnEnabledConverter"/>
<converter:EnumToLabelConverter x:Key="EnumToLabelConverter"/>
<converter:EnumToBoolConverter x:Key="EnumToBoolConverter"/>
<converter:LevelToWidthConverter x:Key="LevelToWidthConverter"/>
<converter:ObjectTypeIconToImageStyleConverter x:Key="ObjectTypeIconToImageStyleConverter" >
<converter:ObjectTypeIconToImageStyleConverter.ResourceDictionary>
Expand Down
55 changes: 48 additions & 7 deletions src/GUI/EFCorePowerTools/Dialogs/PickTablesDialog.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:converter="clr-namespace:EFCorePowerTools.Converter"
xmlns:ext="clr-namespace:EFCorePowerTools.Extensions"
xmlns:viewModels="clr-namespace:EFCorePowerTools.ViewModels"
xmlns:contractvm="clr-namespace:EFCorePowerTools.Contracts.ViewModels"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
mc:Ignorable="d"
Title="Choose Database Objects"
Expand Down Expand Up @@ -85,13 +85,13 @@
<Grid Margin="12,0"
Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" ></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="80"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition Width="20"></ColumnDefinition>
</Grid.ColumnDefinitions>
<CheckBox IsChecked="{Binding TableSelectionThreeState}"
Margin="0,0,0,0"
BorderThickness="2"
Margin="22,0,0,0"
IsThreeState="False"
VerticalAlignment="Center"
Grid.Column="0"/>
Expand All @@ -107,7 +107,46 @@
HorizontalAlignment="Stretch"
VerticalContentAlignment="Center"
Text="{Binding SearchText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Grid.Column="2" />
Grid.Column="2"
x:Name="Search">
</TextBox>

<Button Name="MainButton" Grid.Column="3" Height="22" BorderThickness="0,1,1,1" BorderBrush="{Binding BorderBrush, ElementName=Search}">
<Button.Content>
<Image Source="pack://application:,,,/EFCorePowerTools;component/Resources/GlyphDown_16x.png" Width="16"/>
</Button.Content>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="ContextPopup"
Storyboard.TargetProperty="IsOpen">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
</Button>
<Popup x:Name="ContextPopup"
PlacementTarget="{Binding ElementName=MainButton}"
Placement="Left"
VerticalOffset="{Binding ActualHeight, ElementName=MainButton}"
HorizontalOffset="{Binding ActualWidth, ElementName=MainButton}"
StaysOpen="False">
<Border BorderThickness="1" BorderBrush="LightGray" Background="{StaticResource DialogWindowBackgroundColor}">
<StackPanel>
<RadioButton Margin="8"
IsChecked="{Binding SearchMode, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static contractvm:SearchMode.Text}}"
Content="Use text search"></RadioButton>
<RadioButton Margin="8,0,8,8"
IsChecked="{Binding SearchMode, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static contractvm:SearchMode.RegularExpression}}"
Content="Use regular expression"></RadioButton>
</StackPanel>
</Border>
</Popup>
</Grid>

<TreeView Margin="12,0"
Expand All @@ -128,7 +167,7 @@
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>

<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type viewModels:ObjectTreeRootItemViewModel}" ItemsSource="{Binding Path=Schemas}">
<HierarchicalDataTemplate.ItemContainerStyle>
Expand Down Expand Up @@ -296,7 +335,9 @@
Command="{Binding CancelCommand}" />
</StackPanel>
<StackPanel Grid.Row="2" VerticalAlignment="Bottom">
<StatusBar Visibility="Collapsed" Background="LemonChiffon" x:Name="statusBar">Unchecking an item may cause the related file to be removed.</StatusBar>
<StatusBar Visibility="Collapsed" Background="LemonChiffon" x:Name="statusBar">
<TextBlock Text="Unchecking an item may cause the related file to be removed." />
</StatusBar>
</StackPanel>
</Grid>
</dw:DialogWindow>
3 changes: 3 additions & 0 deletions src/GUI/EFCorePowerTools/EFCorePowerTools.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
<Compile Include="Contracts\ViewModels\ISchemaInformationViewModel.cs" />
<Compile Include="Contracts\ViewModels\ITableInformationViewModel.cs" />
<Compile Include="Contracts\ViewModels\IViewModel.cs" />
<Compile Include="Contracts\ViewModels\SearchMode.cs" />
<Compile Include="Contracts\ViewModels\ObjectTypeIcon.cs" />
<Compile Include="Contracts\Views\IAboutDialog.cs" />
<Compile Include="Contracts\Views\IAdvancedModelingOptionsDialog.cs" />
Expand All @@ -90,6 +91,7 @@
<Compile Include="Contracts\Views\IModelingOptionsDialog.cs" />
<Compile Include="Contracts\Views\IView.cs" />
<Compile Include="Converter\BoolInvertConverter.cs" />
<Compile Include="Converter\EnumToBoolConverter.cs" />
<Compile Include="Converter\LevelToWidthConverter.cs" />
<Compile Include="Converter\EnumToLabelConverter.cs" />
<Compile Include="Converter\ObjectTypeToImageStyleConverter.cs" />
Expand Down Expand Up @@ -396,6 +398,7 @@
<Content Include="Resources\efcreveng2.png" />
<Resource Include="Resources\ImportPackage_16x.png" />
<Resource Include="Resources\GlyphRight_16x.png" />
<Resource Include="Resources\GlyphDown_16x.png" />
<Content Include="Resources\license.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<IncludeInVSIX>true</IncludeInVSIX>
Expand Down
Binary file added src/GUI/EFCorePowerTools/Resources/GlyphDown_16x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 19 additions & 2 deletions src/GUI/EFCorePowerTools/ViewModels/ObjectTreeViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text.RegularExpressions;

public class ObjectTreeViewModel : ViewModelBase, IObjectTreeViewModel
{
Expand Down Expand Up @@ -41,11 +42,27 @@ public ObjectTreeViewModel(Func<ISchemaInformationViewModel> schemaInformationVi

public bool IsInEditMode { get => _objects.Any(o => o.IsEditing) || _objects.SelectMany(c => c.Columns).Any(o => o.IsEditing); }

public void Search(string searchText)
public void Search(string searchText, SearchMode searchMode)
{
var regex = new Regex(searchText, RegexOptions.None, new TimeSpan(0,0,3));

foreach (var obj in _objects)
{
obj.IsVisible = string.IsNullOrWhiteSpace(searchText) || obj.DisplayName.ToUpper().Contains(searchText.ToUpper());
if (searchMode == SearchMode.Text)
{
obj.IsVisible = string.IsNullOrWhiteSpace(searchText) || obj.DisplayName.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) >= 0;
}
else
{
try
{
obj.IsVisible = string.IsNullOrWhiteSpace(searchText) || regex.IsMatch(obj.DisplayName);
}
catch (RegexMatchTimeoutException)
{
obj.IsVisible = true;
}
}
}
}

Expand Down
19 changes: 16 additions & 3 deletions src/GUI/EFCorePowerTools/ViewModels/PickTablesViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class PickTablesViewModel : ViewModelBase, IPickTablesViewModel

private bool? _tableSelectionThreeState;
private string _searchText;
private SearchMode _searchMode = SearchMode.Text;

public PickTablesViewModel(IObjectTreeViewModel objectTreeViewModel)
{
Expand Down Expand Up @@ -55,7 +56,19 @@ public string SearchText
if (Equals(value, _searchText)) return;
_searchText = value;
RaisePropertyChanged();
var _ = HandleSearchTextChangeAsync(value);
var _ = HandleSearchTextChangeAsync(_searchText, _searchMode);
}
}

public SearchMode SearchMode
{
get => _searchMode;
set
{
if (Equals(value, _searchMode)) return;
_searchMode = value;
RaisePropertyChanged();
var _ = HandleSearchTextChangeAsync(_searchText, _searchMode);
}
}

Expand Down Expand Up @@ -83,13 +96,13 @@ private void HandleTableSelectionThreeStateChange(bool? selectionMode)
SearchText = string.Empty;
}

private async Task HandleSearchTextChangeAsync(string text)
private async Task HandleSearchTextChangeAsync(string text, SearchMode searchMode)
{
await Task.Delay(500); // Add a delay (like a debounce) so that not every character change triggers a search
if (text != SearchText)
return;

ObjectTree.Search(SearchText);
ObjectTree.Search(SearchText, SearchMode);
}

private void UpdateTableSelectionThreeState()
Expand Down
4 changes: 2 additions & 2 deletions src/GUI/UnitTests/ViewModels/ObjectTreeViewModelTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ public void SearchText_NoDirectFilter()
var preFilter = vm.Types.SelectMany(c => c.Schemas).SelectMany(c => c.Objects);

// Act
vm.Search("ref");
vm.Search("ref", SearchMode.Text);

// Assert
Assert.AreEqual(databaseObjects.Length, preFilter.Count());
Expand All @@ -261,7 +261,7 @@ public void SearchText_FilterAfterDelay()
vm.AddObjects(databaseObjects, null);

// Act
vm.Search("ref");
vm.Search("ref", SearchMode.Text);

// Assert
Assert.That(() =>
Expand Down