Skip to content
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
12 changes: 12 additions & 0 deletions Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ public void UpdatePluginSettings(List<PluginMetadata> metadatas)
if (Plugins.ContainsKey(metadata.ID))
{
var settings = Plugins[metadata.ID];

// TODO: Remove. This is one off for 1.2.0 release.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a note here, this is a one off, and will be deleted in the next release. It is needed as we introduced an additional action keyword.

I have also introduced version in plugin settings in the following commit to lay the ground work for handling future plugin meta updates.

// Introduced a new action keyword in Explorer, so need to update plugin setting in the UserData folder.
// This kind of plugin meta update should be handled by a dedicated method trigger by version bump.
if (metadata.ID == "572be03c74c642baae319fc283e561a8" && metadata.ActionKeywords.Count != settings.ActionKeywords.Count)
settings.ActionKeywords = metadata.ActionKeywords;

if (string.IsNullOrEmpty(settings.Version))
settings.Version = metadata.Version;

if (settings.ActionKeywords?.Count > 0)
{
metadata.ActionKeywords = settings.ActionKeywords;
Expand All @@ -28,6 +38,7 @@ public void UpdatePluginSettings(List<PluginMetadata> metadatas)
{
ID = metadata.ID,
Name = metadata.Name,
Version = metadata.Version,
ActionKeywords = metadata.ActionKeywords,
Disabled = metadata.Disabled
};
Expand All @@ -39,6 +50,7 @@ public class Plugin
{
public string ID { get; set; }
public string Name { get; set; }
public string Version { get; set; }
public List<string> ActionKeywords { get; set; } // a reference of the action keywords from plugin manager

/// <summary>
Expand Down
49 changes: 49 additions & 0 deletions Flow.Launcher.Test/Plugins/ExplorerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,55 @@ public void GivenTopLevelDirectorySearch_WhenIndexSearchNotRequired_ThenSearchMe
$"Actual number of results is {results.Count} {Environment.NewLine}");
}

[TestCase(@"some words", @"FREETEXT('some words')")]
public void GivenWindowsIndexSearch_WhenQueryWhereRestrictionsIsForFileContentSearch_ThenShouldReturnFreeTextString(
string querySearchString, string expectedString)
{
// Given
var queryConstructor = new QueryConstructor(new Settings());

//When
var resultString = queryConstructor.QueryWhereRestrictionsForFileContentSearch(querySearchString);

// Then
Assert.IsTrue(resultString == expectedString,
$"Expected QueryWhereRestrictions string: {expectedString}{Environment.NewLine} " +
$"Actual string was: {resultString}{Environment.NewLine}");
}

[TestCase("some words", "SELECT TOP 100 System.FileName, System.ItemPathDisplay, System.ItemType " +
"FROM SystemIndex WHERE FREETEXT('some words') AND scope='file:'")]
public void GivenWindowsIndexSearch_WhenSearchForFileContent_ThenQueryShouldUseExpectedString(
string userSearchString, string expectedString)
{
// Given
var queryConstructor = new QueryConstructor(new Settings());

//When
var resultString = queryConstructor.QueryForFileContentSearch(userSearchString);

// Then
Assert.IsTrue(resultString == expectedString,
$"Expected query string: {expectedString}{Environment.NewLine} " +
$"Actual string was: {resultString}{Environment.NewLine}");
}

public void GivenQuery_WhenActionKeywordForFileContentSearchExists_ThenFileContentSearchRequiredShouldReturnTrue()
{
// Given
var query = new Query { ActionKeyword = "doc:", Search = "search term" };

var searchManager = new SearchManager(new Settings(), new PluginInitContext());

// When
var result = searchManager.IsFileContentSearch(query.ActionKeyword);

// Then
Assert.IsTrue(result,
$"Expected True for file content search. {Environment.NewLine} " +
$"Actual result was: {result}{Environment.NewLine}");
}

[TestCase(@"c:\\", false)]
[TestCase(@"i:\", true)]
[TestCase(@"\c:\", false)]
Expand Down
2 changes: 1 addition & 1 deletion Flow.Launcher/Languages/en.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@
<system:String x:Key="done">Done</system:String>
<system:String x:Key="cannotFindSpecifiedPlugin">Can't find specified plugin</system:String>
<system:String x:Key="newActionKeywordsCannotBeEmpty">New Action Keyword can't be empty</system:String>
<system:String x:Key="newActionKeywordsHasBeenAssigned">New Action Keywords have been assigned to another plugin, please assign other new action keyword</system:String>
<system:String x:Key="newActionKeywordsHasBeenAssigned">This new Action Keyword is already assigned to another plugin, please choose a different one</system:String>
<system:String x:Key="success">Success</system:String>
<system:String x:Key="actionkeyword_tips">Use * if you don't want to specify an action keyword</system:String>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\Flow.Launcher.Core\Flow.Launcher.Core.csproj" />
<ProjectReference Include="..\..\Flow.Launcher.Infrastructure\Flow.Launcher.Infrastructure.csproj" />
<ProjectReference Include="..\..\Flow.Launcher.Plugin\Flow.Launcher.Plugin.csproj" />
</ItemGroup>
Expand Down
7 changes: 5 additions & 2 deletions Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">

<!--Dialogues-->
<system:String x:Key="plugin_explorer_make_selection_warning">Please make a selection first</system:String>
<system:String x:Key="plugin_explorer_select_folder_link_warning">Please select a folder link</system:String>
<system:String x:Key="plugin_explorer_delete_folder_link">Are you sure you want to delete {0}?</system:String>
<system:String x:Key="plugin_explorer_deletefilefolderconfirm">Are you sure you want to permanently delete this {0}?</system:String>
Expand All @@ -13,10 +14,12 @@
<system:String x:Key="plugin_explorer_delete">Delete</system:String>
<system:String x:Key="plugin_explorer_edit">Edit</system:String>
<system:String x:Key="plugin_explorer_add">Add</system:String>
<system:String x:Key="plugin_explorer_manageactionkeywords_header">Customise Action Keywords</system:String>
<system:String x:Key="plugin_explorer_quickfolderaccess_header">Quick Folder Access Paths</system:String>
<system:String x:Key="plugin_explorer_indexsearchexcludedpaths_header">Index Search Excluded Paths</system:String>
<system:String x:Key="plugin_explorer_manageindexoptions">Indexing Options</system:String>

<system:String x:Key="plugin_explorer_actionkeywordview_search">Search Activation:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">File Content Search:</system:String>

<!--Plugin Infos-->
<system:String x:Key="plugin_explorer_plugin_name">Explorer</system:String>
Expand Down
23 changes: 22 additions & 1 deletion Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,15 @@ internal List<Result> Search(Query query)

var quickFolderLinks = quickFolderAccess.FolderList(query, settings.QuickFolderAccessLinks, context);

if (quickFolderLinks.Count > 0)
if (quickFolderLinks.Count > 0 && query.ActionKeyword == settings.SearchActionKeyword)
return quickFolderLinks;

if (string.IsNullOrEmpty(querySearch))
return results;

if (IsFileContentSearch(query.ActionKeyword))
return WindowsIndexFileContentSearch(query, querySearch);

var isEnvironmentVariable = EnvironmentVariables.IsEnvironmentVariableSearch(querySearch);

if (isEnvironmentVariable)
Expand Down Expand Up @@ -74,6 +77,24 @@ internal List<Result> Search(Query query)
return results;
}

private List<Result> WindowsIndexFileContentSearch(Query query, string querySearchString)
{
var queryConstructor = new QueryConstructor(settings);

if (string.IsNullOrEmpty(querySearchString))
return new List<Result>();

return indexSearch.WindowsIndexSearch(querySearchString,
queryConstructor.CreateQueryHelper().ConnectionString,
queryConstructor.QueryForFileContentSearch,
query);
}

public bool IsFileContentSearch(string actionKeyword)
{
return actionKeyword == settings.FileContentSearchActionKeyword;
}

private List<Result> DirectoryInfoClassSearch(Query query, string querySearch)
{
var directoryInfoSearch = new DirectoryInfoSearch(context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,5 +117,23 @@ public string QueryWhereRestrictionsForAllFilesAndFoldersSearch()
{
return $"scope='file:'";
}

///<summary>
/// Search will be performed on all indexed file contents for the specified search keywords.
///</summary>
public string QueryForFileContentSearch(string userSearchString)
{
string query = "SELECT TOP " + settings.MaxResult + $" {CreateBaseQuery().QuerySelectColumns} FROM {SystemIndex} WHERE ";

return query + QueryWhereRestrictionsForFileContentSearch(userSearchString) + " AND " + QueryWhereRestrictionsForAllFilesAndFoldersSearch();
}

///<summary>
/// Set the required WHERE clause restriction to search within file content.
///</summary>
public string QueryWhereRestrictionsForFileContentSearch(string searchQuery)
{
return $"FREETEXT('{searchQuery}')";
}
}
}
6 changes: 6 additions & 0 deletions Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,11 @@ public class Settings

[JsonProperty]
public List<FolderLink> IndexSearchExcludedSubdirectoryPaths { get; set; } = new List<FolderLink>();

[JsonProperty]
public string SearchActionKeyword { get; set; } = Query.GlobalPluginWildcardSign;

[JsonProperty]
public string FileContentSearchActionKeyword { get; set; } = "doc:";
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Flow.Launcher.Infrastructure.Storage;
using Flow.Launcher.Core.Plugin;
using Flow.Launcher.Infrastructure.Storage;
using Flow.Launcher.Plugin.Explorer.Search;
using Flow.Launcher.Plugin.Explorer.Search.FolderLinks;
using System.Diagnostics;
Expand Down Expand Up @@ -40,5 +41,18 @@ internal void OpenWindowsIndexingOptions()

Process.Start(psi);
}

internal void UpdateActionKeyword(string newActionKeyword, string oldActionKeyword)
{
PluginManager.ReplaceActionKeyword(Context.CurrentPluginMetadata.ID, oldActionKeyword, newActionKeyword);

if (Settings.FileContentSearchActionKeyword == oldActionKeyword)
Settings.FileContentSearchActionKeyword = newActionKeyword;

if (Settings.SearchActionKeyword == oldActionKeyword)
Settings.SearchActionKeyword = newActionKeyword;
}

internal bool IsActionKeywordAlreadyAssigned(string newActionKeyword) => PluginManager.ActionKeywordRegistered(newActionKeyword);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<Window x:Class="Flow.Launcher.Plugin.Explorer.Views.ActionKeywordSetting"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:local="clr-namespace:Flow.Launcher.Plugin.Explorer.Views"
mc:Ignorable="d"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Title="Action Keyword Setting" Height="200" Width="500">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Margin="20 10 10 10" FontSize="14" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center"
HorizontalAlignment="Left" Text="Current Action Keyword:" />
<TextBox Name="txtCurrentActionKeyword"
Margin="10" Grid.Row="0" Width="105" Grid.Column="1"
VerticalAlignment="Center"
HorizontalAlignment="Left" />

<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row="1" Grid.Column="1">
<Button Click="OnConfirmButtonClick"
Margin="10 0 10 0" Width="80" Height="35"
Content="OK" />
<Button Click="OnCancelButtonClick"
Margin="10 0 10 0" Width="80" Height="35"
Content="Cancel" />
</StackPanel>
</Grid>
</Window>
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using Flow.Launcher.Plugin.Explorer.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace Flow.Launcher.Plugin.Explorer.Views
{
/// <summary>
/// Interaction logic for ActionKeywordSetting.xaml
/// </summary>
public partial class ActionKeywordSetting : Window
{
private SettingsViewModel settingsViewModel;

private ActionKeywordView currentActionKeyword;

private List<ActionKeywordView> actionKeywordListView;

public ActionKeywordSetting(SettingsViewModel settingsViewModel, List<ActionKeywordView> actionKeywordListView, ActionKeywordView selectedActionKeyword)
{
InitializeComponent();

this.settingsViewModel = settingsViewModel;

currentActionKeyword = selectedActionKeyword;

txtCurrentActionKeyword.Text = selectedActionKeyword.Keyword;

this.actionKeywordListView = actionKeywordListView;
}

private void OnConfirmButtonClick(object sender, RoutedEventArgs e)
{
var newActionKeyword = txtCurrentActionKeyword.Text;

if (string.IsNullOrEmpty(newActionKeyword))
return;

if (newActionKeyword == currentActionKeyword.Keyword)
{
Close();

return;
}

if(!settingsViewModel.IsActionKeywordAlreadyAssigned(newActionKeyword))
{
settingsViewModel.UpdateActionKeyword(newActionKeyword, currentActionKeyword.Keyword);

actionKeywordListView.Where(x => x.Description == currentActionKeyword.Description).FirstOrDefault().Keyword = newActionKeyword;

Close();

return;
}

MessageBox.Show(settingsViewModel.Context.API.GetTranslation("newActionKeywordsHasBeenAssigned"));
}

private void OnCancelButtonClick(object sender, RoutedEventArgs e)
{
Close();

return;
}
}
}
22 changes: 19 additions & 3 deletions Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<UserControl x:Class="Flow.Launcher.Plugin.Explorer.Views.ExplorerSettings"
<UserControl x:Class="Flow.Launcher.Plugin.Explorer.Views.ExplorerSettings"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Expand All @@ -17,6 +17,16 @@
Text="{Binding Nickname, Mode=OneTime}"
Margin="0,5,0,5" />
</DataTemplate>
<DataTemplate x:Key="ListViewActionKeywords">
<Grid>
<TextBlock
Text="{Binding Description, Mode=OneTime}"
Margin="0,5,0,0" />
<TextBlock
Text="{Binding Keyword, Mode=OneTime}"
Margin="150,5,0,0" />
</Grid>
</DataTemplate>
</UserControl.Resources>
<Grid Margin="10">
<Grid.RowDefinitions>
Expand All @@ -25,16 +35,22 @@
</Grid.RowDefinitions>
<ScrollViewer Margin="20 35 0 0" HorizontalScrollBarVisibility="Hidden" Grid.Row="0" VerticalScrollBarVisibility="Auto">
<StackPanel>
<Expander Name="expActionKeywords" Header="{DynamicResource plugin_explorer_manageactionkeywords_header}"
Expanded="expActionKeywords_Click" Collapsed="expActionKeywords_Collapsed">
<ListView x:Name="lbxActionKeywords"
ItemTemplate="{StaticResource ListViewActionKeywords}"/>
</Expander>
<Expander Name="expFolderLinks" Header="{DynamicResource plugin_explorer_quickfolderaccess_header}"
Expanded="expFolderLinks_Click" Collapsed="expFolderLinks_Click">
Expanded="expFolderLinks_Click" Collapsed="expFolderLinks_Collapsed"
Margin="0 10 0 0">
<ListView
x:Name="lbxFolderLinks" AllowDrop="True"
Drop="lbxFolders_Drop"
DragEnter="lbxFolders_DragEnter"
ItemTemplate="{StaticResource ListViewTemplateFolderLinks}"/>
</Expander>
<Expander x:Name="expExcludedPaths" Header="{DynamicResource plugin_explorer_indexsearchexcludedpaths_header}"
Expanded="expExcludedPaths_Click" Collapsed="expExcludedPaths_Click"
Expanded="expExcludedPaths_Click"
Margin="0 10 0 0">
<ListView
x:Name="lbxExcludedPaths" AllowDrop="True"
Expand Down
Loading