mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Further Refactor UI Code and Implement Engine Selection and Everything Setting UI
This commit is contained in:
parent
70e9a0ca84
commit
d36d15c887
13 changed files with 714 additions and 329 deletions
|
|
@ -8,6 +8,7 @@
|
|||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||
<Nullable>warnings</Nullable>
|
||||
<ApplicationIcon />
|
||||
<StartupObject />
|
||||
</PropertyGroup>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
using Flow.Launcher.Plugin.Everything.Everything;
|
||||
using JetBrains.Annotations;
|
||||
using System;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Explorer.Helper;
|
||||
|
||||
public static class SortOptionTranslationHelper
|
||||
{
|
||||
[CanBeNull]
|
||||
public static IPublicAPI API { get; internal set; }
|
||||
|
||||
public static string GetTranslatedName(this SortOption sortOption)
|
||||
{
|
||||
const string prefix = "flowlauncher_plugin_everything_sort_by_";
|
||||
|
||||
ArgumentNullException.ThrowIfNull(API);
|
||||
|
||||
var enumName = Enum.GetName(sortOption);
|
||||
var splited = enumName.Split('_');
|
||||
var name = string.Join('_', splited[..^1]);
|
||||
var direction = splited[^1];
|
||||
|
||||
return $"{API.GetTranslation(prefix + name.ToLower())} {API.GetTranslation(prefix + direction.ToLower())}";
|
||||
}
|
||||
}
|
||||
|
|
@ -24,7 +24,12 @@
|
|||
<system:String x:Key="plugin_explorer_generalsetting_header">General Setting</system:String>
|
||||
<system:String x:Key="plugin_explorer_manageactionkeywords_header">Customise Action Keywords</system:String>
|
||||
<system:String x:Key="plugin_explorer_quickaccesslinks_header">Quick Access Links</system:String>
|
||||
<system:String x:Key="plugin_explorer_everything_setting_header">Everything Setting</system:String>
|
||||
<system:String x:Key="plugin_explorer_everything_sort_option">Sort Option:</system:String>
|
||||
<system:String x:Key="plugin_explorer_launch_hidden">Launch Hidden</system:String>
|
||||
<system:String x:Key="plugin_explorer_editor_path">Editor Path</system:String>
|
||||
<system:String x:Key="plugin_explorer_indexsearchexcludedpaths_header">Index Search Excluded Paths</system:String>
|
||||
<system:String x:Key="plugin_explorer_use_location_as_working_dir">Use search result's location as executable working directory</system:String>
|
||||
<system:String x:Key="plugin_explorer_usewindowsindexfordirectorysearch">Use Index Search For Path Search</system:String>
|
||||
<system:String x:Key="plugin_explorer_usewindowsindexfordirectorysearch_tooltip">Turning this on will return indexed directories/files faster, but if a directory/file is not indexed it will not show up. If a directory/file has been added to Index Search Excluded Path then it will still show up even if this option is on</system:String>
|
||||
<system:String x:Key="plugin_explorer_manageindexoptions">Indexing Options</system:String>
|
||||
|
|
@ -37,7 +42,11 @@
|
|||
<system:String x:Key="plugin_explorer_actionkeyword_done">Done</system:String>
|
||||
<system:String x:Key="plugin_explorer_actionkeyword_enabled">Enabled</system:String>
|
||||
<system:String x:Key="plugin_explorer_actionkeyword_enabled_tooltip">When disabled Flow will not execute this search option, and will additionally revert back to '*' to free up the action keyword</system:String>
|
||||
|
||||
<system:String x:Key="plugin_explorer_engine_everything">Everything</system:String>
|
||||
<system:String x:Key="plugin_explorer_engine_windows_index">Windows Index</system:String>
|
||||
<system:String x:Key="plugin_explorer_path_enumeration_engine_none">Direct Enumeration</system:String>
|
||||
|
||||
|
||||
<!--Plugin Infos-->
|
||||
<system:String x:Key="plugin_explorer_plugin_name">Explorer</system:String>
|
||||
<system:String x:Key="plugin_explorer_plugin_description">Search and manage files and folders. Explorer utilises Windows Index Search</system:String>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Flow.Launcher.Infrastructure.Storage;
|
||||
using Flow.Launcher.Plugin.Explorer.Helper;
|
||||
using Flow.Launcher.Plugin.Explorer.Search;
|
||||
using Flow.Launcher.Plugin.Explorer.Search.Everything;
|
||||
using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks;
|
||||
|
|
@ -16,7 +17,7 @@ namespace Flow.Launcher.Plugin.Explorer
|
|||
{
|
||||
public class Main : ISettingProvider, IAsyncPlugin, IContextMenu, IPluginI18n
|
||||
{
|
||||
internal PluginInitContext Context { get; set; }
|
||||
internal static PluginInitContext Context { get; set; }
|
||||
|
||||
internal Settings Settings;
|
||||
|
||||
|
|
@ -50,6 +51,9 @@ namespace Flow.Launcher.Plugin.Explorer
|
|||
contextMenu = new ContextMenu(Context, Settings, viewModel);
|
||||
searchManager = new SearchManager(Settings, Context);
|
||||
ResultManager.Init(Context, Settings);
|
||||
|
||||
SortOptionTranslationHelper.API = context.API;
|
||||
|
||||
EverythingApiDllImport.Load(Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "EverythingSDK",
|
||||
Environment.Is64BitProcess ? "Everything64.dll" : "Everything86.dll"));
|
||||
return Task.CompletedTask;
|
||||
|
|
|
|||
|
|
@ -83,17 +83,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo
|
|||
{
|
||||
Log.Exception(nameof(DirectoryInfoSearch), "Error occured while searching path", e);
|
||||
|
||||
results.Add(
|
||||
new Result
|
||||
{
|
||||
Title = string.Format(SearchManager.Context.API.GetTranslation(
|
||||
"plugin_explorer_directoryinfosearch_error"),
|
||||
e.Message),
|
||||
Score = 501,
|
||||
IcoPath = Constants.ExplorerIconImagePath
|
||||
});
|
||||
|
||||
return results;
|
||||
throw;
|
||||
}
|
||||
|
||||
// Initial ordering, this order can be updated later by UpdateResultView.MainViewModel based on history of user selection.
|
||||
|
|
|
|||
|
|
@ -53,9 +53,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
|||
if (string.IsNullOrEmpty(query.Search))
|
||||
return QuickAccess.AccessLinkListAll(query, Settings.QuickAccessLinks);
|
||||
|
||||
var quickaccessLinks = QuickAccess.AccessLinkListMatched(query, Settings.QuickAccessLinks);
|
||||
var quickAccessLinks = QuickAccess.AccessLinkListMatched(query, Settings.QuickAccessLinks);
|
||||
|
||||
results.UnionWith(quickaccessLinks);
|
||||
results.UnionWith(quickAccessLinks);
|
||||
}
|
||||
|
||||
IEnumerable<SearchResult> searchResults;
|
||||
|
|
@ -164,7 +164,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
|||
|
||||
var recursiveIndicatorIndex = query.Search.IndexOf('>');
|
||||
|
||||
if (recursiveIndicatorIndex > 0 && Settings.PathEnumerationEngine != Settings.PathTraversalEngineOption.Direct)
|
||||
if (recursiveIndicatorIndex > 0 && Settings.PathEnumerationEngine != Settings.PathEnumerationEngineOption.Direct)
|
||||
{
|
||||
directoryResult =
|
||||
await Settings.PathEnumerator.EnumerateAsync(query.Search[..recursiveIndicatorIndex],
|
||||
|
|
@ -176,7 +176,23 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
|||
}
|
||||
else
|
||||
{
|
||||
directoryResult = DirectoryInfoSearch.TopLevelDirectorySearch(query, query.Search, token);
|
||||
try
|
||||
{
|
||||
directoryResult = DirectoryInfoSearch.TopLevelDirectorySearch(query, query.Search, token);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
results.Add(
|
||||
new Result
|
||||
{
|
||||
Title = string.Format(SearchManager.Context.API.GetTranslation(
|
||||
"plugin_explorer_directoryinfosearch_error"),
|
||||
e.Message),
|
||||
Score = 501,
|
||||
IcoPath = Constants.ExplorerIconImagePath
|
||||
});
|
||||
directoryResult = new List<SearchResult>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -104,6 +104,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
|
|||
///</summary>
|
||||
public string QueryForAllFilesAndFolders(string userSearchString)
|
||||
{
|
||||
if (string.IsNullOrEmpty(userSearchString))
|
||||
userSearchString = "*";
|
||||
|
||||
// Generate SQL from constructed parameters, converting the userSearchString from AQS->WHERE clause
|
||||
return CreateBaseQuery().GenerateSQLFromUserQuery(userSearchString) + " AND " + QueryWhereRestrictionsForAllFilesAndFoldersSearch
|
||||
+ QueryOrderByFileNameRestriction;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using Flow.Launcher.Plugin.Explorer.Search.WindowsIndex;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
|
|
@ -15,14 +16,22 @@ namespace Flow.Launcher.Plugin.Explorer
|
|||
{
|
||||
public int MaxResult { get; set; } = 100;
|
||||
|
||||
public ObservableCollection<AccessLink> QuickAccessLinks { get; set; } = new ();
|
||||
public ObservableCollection<AccessLink> QuickAccessLinks { get; set; } = new();
|
||||
|
||||
// as at v1.7.0 this is to maintain backwards compatibility, need to be removed afterwards.
|
||||
public ObservableCollection<AccessLink> QuickFolderAccessLinks { get; set; } = new ();
|
||||
public ObservableCollection<AccessLink> QuickFolderAccessLinks { get; set; } = new();
|
||||
|
||||
public ObservableCollection<AccessLink> IndexSearchExcludedSubdirectoryPaths { get; set; } = new ObservableCollection<AccessLink>();
|
||||
|
||||
public string EditorPath { get; set; } = "";
|
||||
|
||||
|
||||
public bool UseLocationAsWorkingDir { get; set; } = false;
|
||||
|
||||
public bool ShowWindowsContextMenu { get; set; } = true;
|
||||
|
||||
public bool UseWindowsIndexForDirectorySearch { get; set; } = false;
|
||||
|
||||
public ObservableCollection<AccessLink> IndexSearchExcludedSubdirectoryPaths { get; set; } = new ObservableCollection<AccessLink>();
|
||||
|
||||
public string SearchActionKeyword { get; set; } = Query.GlobalPluginWildcardSign;
|
||||
|
||||
|
|
@ -44,76 +53,86 @@ namespace Flow.Launcher.Plugin.Explorer
|
|||
|
||||
public bool QuickAccessKeywordEnabled { get; set; }
|
||||
|
||||
public bool LaunchHidden { get; set; } = false;
|
||||
|
||||
|
||||
public bool WarnWindowsSearchServiceOff { get; set; } = true;
|
||||
|
||||
private IReadOnlyList<IIndexProvider> _indexProviders;
|
||||
private IReadOnlyList<IContentIndexProvider> _fileContentIndexProviders;
|
||||
private IReadOnlyList<IPathEnumerable> _pathEnumerables;
|
||||
public Settings()
|
||||
{
|
||||
var everythingManager = new EverythingSearchManager(this);
|
||||
var windowsIndexManager = new WindowsIndexSearchManager(this);
|
||||
|
||||
_indexProviders = new List<IIndexProvider>()
|
||||
{
|
||||
everythingManager,
|
||||
windowsIndexManager
|
||||
};
|
||||
private EverythingSearchManager _everythingManagerInstance;
|
||||
private WindowsIndexSearchManager _windowsIndexSearchManager;
|
||||
|
||||
#region SearchEngine
|
||||
|
||||
public PathEnumerationEngineOption PathEnumerationEngine { get; set; }
|
||||
|
||||
private EverythingSearchManager EverythingManagerInstance => _everythingManagerInstance ??= new EverythingSearchManager(this);
|
||||
private WindowsIndexSearchManager WindowsIndexSearchManager => _windowsIndexSearchManager ??= new WindowsIndexSearchManager(this);
|
||||
|
||||
_pathEnumerables = new List<IPathEnumerable>()
|
||||
{
|
||||
everythingManager,
|
||||
windowsIndexManager
|
||||
};
|
||||
|
||||
_fileContentIndexProviders = new List<IContentIndexProvider>
|
||||
{
|
||||
windowsIndexManager,
|
||||
everythingManager,
|
||||
};
|
||||
}
|
||||
|
||||
public IndexSearchEngineOption IndexSearchEngine { get; set; }
|
||||
[JsonIgnore]
|
||||
public IIndexProvider IndexProvider => _indexProviders[(int)IndexSearchEngine];
|
||||
|
||||
public PathTraversalEngineOption PathEnumerationEngine { get; set; }
|
||||
public IIndexProvider IndexProvider => IndexSearchEngine switch
|
||||
{
|
||||
IndexSearchEngineOption.Everything => EverythingManagerInstance,
|
||||
IndexSearchEngineOption.WindowsIndex => WindowsIndexSearchManager,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(IndexSearchEngine))
|
||||
};
|
||||
|
||||
[JsonIgnore]
|
||||
public IPathEnumerable PathEnumerator => _pathEnumerables[(int)PathEnumerationEngine];
|
||||
public IPathEnumerable PathEnumerator => PathEnumerationEngine switch
|
||||
{
|
||||
PathEnumerationEngineOption.Everything => EverythingManagerInstance,
|
||||
PathEnumerationEngineOption.WindowsIndex => WindowsIndexSearchManager,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(PathEnumerationEngine))
|
||||
};
|
||||
|
||||
public ContentIndexSearchEngineOption ContentSearchEngine { get; set; }
|
||||
[JsonIgnore]
|
||||
public IContentIndexProvider ContentIndexProvider => _fileContentIndexProviders[(int)ContentSearchEngine];
|
||||
|
||||
public enum PathTraversalEngineOption
|
||||
public IContentIndexProvider ContentIndexProvider => ContentSearchEngine switch
|
||||
{
|
||||
ContentIndexSearchEngineOption.Everything => EverythingManagerInstance,
|
||||
ContentIndexSearchEngineOption.WindowsIndex => WindowsIndexSearchManager,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(ContentSearchEngine))
|
||||
};
|
||||
|
||||
public enum PathEnumerationEngineOption
|
||||
{
|
||||
[Description("plugin_explorer_engine_everything")]
|
||||
Everything,
|
||||
[Description("plugin_explorer_engine_windows_index")]
|
||||
WindowsIndex,
|
||||
[Description("plugin_explorer_path_enumeration_engine_none")]
|
||||
Direct
|
||||
}
|
||||
|
||||
public enum IndexSearchEngineOption
|
||||
{
|
||||
[Description("plugin_explorer_engine_everything")]
|
||||
Everything,
|
||||
[Description("plugin_explorer_engine_windows_index")]
|
||||
WindowsIndex
|
||||
}
|
||||
|
||||
|
||||
public enum ContentIndexSearchEngineOption
|
||||
{
|
||||
[Description("plugin_explorer_engine_everything")]
|
||||
Everything,
|
||||
[Description("plugin_explorer_engine_windows_index")]
|
||||
WindowsIndex
|
||||
}
|
||||
|
||||
public bool LaunchHidden { get; set; } = false;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Everything Settings
|
||||
|
||||
|
||||
public string EverythingInstalledPath { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public SortOption[] SortOptions { get; set; } = Enum.GetValues<SortOption>();
|
||||
|
||||
public SortOption SortOption { get; set; } = SortOption.NAME_ASCENDING;
|
||||
|
||||
|
||||
public bool EnableEverythingContentSearch { get; set; } = false;
|
||||
|
||||
#endregion
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Explorer.ViewModels;
|
||||
|
||||
public class EnumBindingModel<T> where T : struct, Enum
|
||||
{
|
||||
public static IReadOnlyList<EnumBindingModel<T>> CreateList()
|
||||
{
|
||||
return Enum.GetValues<T>()
|
||||
.Select(value => new EnumBindingModel<T>
|
||||
{
|
||||
Value = value, LocalizationKey = GetDescriptionAttr(value)
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public EnumBindingModel<T> From(T value)
|
||||
{
|
||||
var name = value.ToString();
|
||||
var description = GetDescriptionAttr(value);
|
||||
|
||||
return new EnumBindingModel<T>
|
||||
{
|
||||
Name = name,
|
||||
LocalizationKey = description,
|
||||
Value = value
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetDescriptionAttr(T source)
|
||||
{
|
||||
var fi = source.GetType().GetField(source.ToString());
|
||||
|
||||
var attributes = (DescriptionAttribute[])fi?.GetCustomAttributes(
|
||||
typeof(DescriptionAttribute), false);
|
||||
|
||||
return attributes is { Length: > 0 } ? attributes[0].Description : source.ToString();
|
||||
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
private string LocalizationKey { get; set; }
|
||||
public string Description => Main.Context.API.GetTranslation(LocalizationKey);
|
||||
public T Value { get; set; }
|
||||
}
|
||||
|
|
@ -1,27 +1,41 @@
|
|||
using Flow.Launcher.Core.Plugin;
|
||||
using Flow.Launcher.Infrastructure.Storage;
|
||||
using Flow.Launcher.Plugin.Explorer.Search;
|
||||
using Flow.Launcher.Plugin.Explorer.Search.Everything;
|
||||
using Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions;
|
||||
using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks;
|
||||
using Flow.Launcher.Plugin.Explorer.Views;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Input;
|
||||
using MessageBox = System.Windows.Forms.MessageBox;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
||||
{
|
||||
public class SettingsViewModel
|
||||
public class SettingsViewModel : BaseModel
|
||||
{
|
||||
public Settings Settings { get; set; }
|
||||
|
||||
internal PluginInitContext Context { get; set; }
|
||||
|
||||
public IReadOnlyList<EnumBindingModel<Settings.IndexSearchEngineOption>> IndexSearchEngines { get; set; }
|
||||
public IReadOnlyList<EnumBindingModel<Settings.ContentIndexSearchEngineOption>> ContentIndexSearchEngines { get; set; }
|
||||
public IReadOnlyList<EnumBindingModel<Settings.PathEnumerationEngineOption>> PathEnumerationEngines { get; set; }
|
||||
|
||||
public SettingsViewModel(PluginInitContext context, Settings settings)
|
||||
{
|
||||
Context = context;
|
||||
Settings = settings;
|
||||
|
||||
InitializeEngineSelection();
|
||||
InitializeActionKeywordModels();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -30,17 +44,84 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
Context.API.SaveSettingJsonStorage<Settings>();
|
||||
}
|
||||
|
||||
#region Engine Selection
|
||||
|
||||
private EnumBindingModel<Settings.IndexSearchEngineOption> _selectedIndexSearchEngine;
|
||||
private EnumBindingModel<Settings.ContentIndexSearchEngineOption> _selectedContentSearchEngine;
|
||||
private EnumBindingModel<Settings.PathEnumerationEngineOption> _selectedPathEnumerationEngine;
|
||||
|
||||
|
||||
public EnumBindingModel<Settings.IndexSearchEngineOption> SelectedIndexSearchEngine
|
||||
{
|
||||
get => _selectedIndexSearchEngine;
|
||||
set
|
||||
{
|
||||
_selectedIndexSearchEngine = value;
|
||||
Settings.IndexSearchEngine = value.Value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public EnumBindingModel<Settings.ContentIndexSearchEngineOption> SelectedContentSearchEngine
|
||||
{
|
||||
get => _selectedContentSearchEngine;
|
||||
set
|
||||
{
|
||||
_selectedContentSearchEngine = value;
|
||||
Settings.ContentSearchEngine = value.Value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public EnumBindingModel<Settings.PathEnumerationEngineOption> SelectedPathEnumerationEngine
|
||||
{
|
||||
get => _selectedPathEnumerationEngine;
|
||||
set
|
||||
{
|
||||
_selectedPathEnumerationEngine = value;
|
||||
Settings.PathEnumerationEngine = value.Value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeEngineSelection()
|
||||
{
|
||||
IndexSearchEngines = EnumBindingModel<Settings.IndexSearchEngineOption>.CreateList();
|
||||
ContentIndexSearchEngines = EnumBindingModel<Settings.ContentIndexSearchEngineOption>.CreateList();
|
||||
PathEnumerationEngines = EnumBindingModel<Settings.PathEnumerationEngineOption>.CreateList();
|
||||
|
||||
SelectedIndexSearchEngine = IndexSearchEngines.FirstOrDefault(x => x.Value == Settings.IndexSearchEngine);
|
||||
_selectedContentSearchEngine = ContentIndexSearchEngines.FirstOrDefault(x => x.Value == Settings.ContentSearchEngine);
|
||||
_selectedPathEnumerationEngine = PathEnumerationEngines.FirstOrDefault(x => x.Value == Settings.PathEnumerationEngine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region ActionKeyword
|
||||
|
||||
private void InitializeActionKeywordModels()
|
||||
{
|
||||
ActionKeywordsModels = new List<ActionKeywordModel>
|
||||
{
|
||||
new(Settings.ActionKeyword.SearchActionKeyword,
|
||||
Context.API.GetTranslation("plugin_explorer_actionkeywordview_search")),
|
||||
new(Settings.ActionKeyword.FileContentSearchActionKeyword,
|
||||
Context.API.GetTranslation("plugin_explorer_actionkeywordview_filecontentsearch")),
|
||||
new(Settings.ActionKeyword.PathSearchActionKeyword,
|
||||
Context.API.GetTranslation("plugin_explorer_actionkeywordview_pathsearch")),
|
||||
new(Settings.ActionKeyword.IndexSearchActionKeyword,
|
||||
Context.API.GetTranslation("plugin_explorer_actionkeywordview_indexsearch")),
|
||||
new(Settings.ActionKeyword.QuickAccessActionKeyword,
|
||||
Context.API.GetTranslation("plugin_explorer_actionkeywordview_quickaccess"))
|
||||
};
|
||||
}
|
||||
|
||||
public IReadOnlyList<ActionKeywordModel> ActionKeywordsModels { get; set; }
|
||||
|
||||
public AccessLink SelectedQuickAccessLink { get; set; }
|
||||
public AccessLink SelectedIndexSearchExcludedPath { get; set; }
|
||||
public ActionKeywordModel SelectedActionKeyword { get; set; }
|
||||
|
||||
|
||||
|
||||
public ICommand RemoveLinkCommand => new RelayCommand(RemoveLink);
|
||||
public ICommand EditLinkCommand => new RelayCommand(EditLink);
|
||||
public ICommand AddLinkCommand => new RelayCommand(AddLink);
|
||||
|
||||
public ICommand EditActionKeywordCommand => new RelayCommand(EditActionKeyword);
|
||||
|
||||
private void EditActionKeyword(object obj)
|
||||
|
|
@ -53,130 +134,116 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
|
||||
var actionKeywordWindow = new ActionKeywordSetting(actionKeyword, Context.API);
|
||||
|
||||
if (actionKeywordWindow.ShowDialog() ?? false)
|
||||
if (!(actionKeywordWindow.ShowDialog() ?? false))
|
||||
{
|
||||
if (actionKeyword.Enabled && !actionKeywordWindow.KeywordEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (actionKeyword.Enabled, actionKeywordWindow.KeywordEnabled)
|
||||
{
|
||||
case (true, false):
|
||||
Context.API.RemoveActionKeyword(Context.CurrentPluginMetadata.ID, actionKeyword.Keyword);
|
||||
}
|
||||
else if (!actionKeyword.Enabled && actionKeywordWindow.KeywordEnabled)
|
||||
{
|
||||
Context.API.AddActionKeyword(Context.CurrentPluginMetadata.ID, actionKeyword.Keyword);
|
||||
}
|
||||
else if (actionKeyword.Enabled && actionKeywordWindow.KeywordEnabled)
|
||||
{
|
||||
break;
|
||||
case (true, true):
|
||||
// same keyword will have dialog result false
|
||||
Context.API.RemoveActionKeyword(Context.CurrentPluginMetadata.ID, actionKeyword.Keyword);
|
||||
Context.API.AddActionKeyword(Context.CurrentPluginMetadata.ID, actionKeywordWindow.ActionKeyword);
|
||||
}
|
||||
|
||||
(actionKeyword.Keyword, actionKeyword.Enabled) = (actionKeywordWindow.ActionKeyword, actionKeywordWindow.KeywordEnabled);
|
||||
break;
|
||||
case (false, true):
|
||||
Context.API.AddActionKeyword(Context.CurrentPluginMetadata.ID, actionKeyword.Keyword);
|
||||
break;
|
||||
case (false, false):
|
||||
throw new ArgumentException(
|
||||
$"Both false in {nameof(actionKeyword)}.{nameof(actionKeyword.Enabled)} and {nameof(actionKeywordWindow)}.{nameof(actionKeywordWindow.KeywordEnabled)} should suggest that the ShowDialog() result is false");
|
||||
}
|
||||
|
||||
(actionKeyword.Keyword, actionKeyword.Enabled) = (actionKeywordWindow.ActionKeyword, actionKeywordWindow.KeywordEnabled);
|
||||
|
||||
}
|
||||
|
||||
private AccessLink? PromptUserSelectPath(ResultType type, string initialDirectory = null)
|
||||
#endregion
|
||||
|
||||
#region AccessLinks
|
||||
|
||||
public AccessLink SelectedQuickAccessLink { get; set; }
|
||||
public AccessLink SelectedIndexSearchExcludedPath { get; set; }
|
||||
|
||||
|
||||
|
||||
public ICommand RemoveLinkCommand => new RelayCommand(RemoveLink);
|
||||
public ICommand EditLinkCommand => new RelayCommand(EditLink);
|
||||
public ICommand AddLinkCommand => new RelayCommand(AddLink);
|
||||
|
||||
public void AppendLink(string containerName, AccessLink link)
|
||||
{
|
||||
AccessLink newAccessLink = null;
|
||||
|
||||
if (type is ResultType.Folder)
|
||||
var container = containerName switch
|
||||
{
|
||||
var folderBrowserDialog = new FolderBrowserDialog();
|
||||
|
||||
if (initialDirectory is not null)
|
||||
folderBrowserDialog.InitialDirectory = initialDirectory;
|
||||
|
||||
if (folderBrowserDialog.ShowDialog() != DialogResult.OK)
|
||||
return newAccessLink;
|
||||
|
||||
newAccessLink = new AccessLink { Path = folderBrowserDialog.SelectedPath };
|
||||
}
|
||||
else if (type is ResultType.File)
|
||||
{
|
||||
var openFileDialog = new OpenFileDialog();
|
||||
if (initialDirectory is not null)
|
||||
openFileDialog.InitialDirectory = initialDirectory;
|
||||
|
||||
if (openFileDialog.ShowDialog() != DialogResult.OK)
|
||||
return newAccessLink;
|
||||
|
||||
newAccessLink = new AccessLink { Path = openFileDialog.FileName };
|
||||
}
|
||||
return newAccessLink;
|
||||
"QuickAccessLink" => Settings.QuickAccessLinks,
|
||||
"IndexSearchExcludedPath" => Settings.IndexSearchExcludedSubdirectoryPaths,
|
||||
_ => throw new ArgumentException($"Unknown container name: {containerName}")
|
||||
};
|
||||
container.Add(link);
|
||||
}
|
||||
|
||||
private void EditLink(object obj)
|
||||
private void EditLink(object commandParameter)
|
||||
{
|
||||
if (obj is not string container) return;
|
||||
|
||||
AccessLink selectedLink;
|
||||
ObservableCollection<AccessLink> collection;
|
||||
|
||||
switch (container)
|
||||
(AccessLink selectedLink, ObservableCollection<AccessLink> collection) = commandParameter switch
|
||||
{
|
||||
case "QuickAccessLink":
|
||||
if (SelectedQuickAccessLink == null)
|
||||
{
|
||||
ShowUnselectedMessage();
|
||||
return;
|
||||
}
|
||||
selectedLink = SelectedQuickAccessLink;
|
||||
collection = Settings.QuickAccessLinks;
|
||||
break;
|
||||
case "IndexSearchExcludedPaths":
|
||||
if (SelectedIndexSearchExcludedPath == null)
|
||||
{
|
||||
ShowUnselectedMessage();
|
||||
return;
|
||||
}
|
||||
selectedLink = SelectedIndexSearchExcludedPath;
|
||||
collection = Settings.IndexSearchExcludedSubdirectoryPaths;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
"QuickAccessLink" => (SelectedQuickAccessLink, Settings.QuickAccessLinks),
|
||||
"IndexSearchExcludedPath" => (SelectedIndexSearchExcludedPath, Settings.IndexSearchExcludedSubdirectoryPaths),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(commandParameter))
|
||||
};
|
||||
|
||||
if (selectedLink is null)
|
||||
{
|
||||
ShowUnselectedMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
var link = PromptUserSelectPath(selectedLink.Type,
|
||||
var path = PromptUserSelectPath(selectedLink.Type,
|
||||
selectedLink.Type == ResultType.Folder
|
||||
? selectedLink.Path
|
||||
: Path.GetDirectoryName(selectedLink.Path));
|
||||
|
||||
if (link is null)
|
||||
if (path is null)
|
||||
return;
|
||||
|
||||
collection.Remove(selectedLink);
|
||||
collection.Add(link);
|
||||
collection.Add(new AccessLink
|
||||
{
|
||||
Path = path, Type = selectedLink.Type,
|
||||
});
|
||||
}
|
||||
|
||||
private void ShowUnselectedMessage()
|
||||
{
|
||||
string warning = Context.API.GetTranslation("plugin_explorer_make_selection_warning");
|
||||
var warning = Context.API.GetTranslation("plugin_explorer_make_selection_warning");
|
||||
MessageBox.Show(warning);
|
||||
}
|
||||
|
||||
private void AddLink(object obj)
|
||||
|
||||
private void AddLink(object commandParameter)
|
||||
{
|
||||
if (obj is not string container) return;
|
||||
var container = commandParameter switch
|
||||
{
|
||||
"QuickAccessLink" => Settings.QuickAccessLinks,
|
||||
"IndexSearchExcludedPaths" => Settings.IndexSearchExcludedSubdirectoryPaths,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(commandParameter))
|
||||
};
|
||||
|
||||
ArgumentNullException.ThrowIfNull(container);
|
||||
|
||||
var folderBrowserDialog = new FolderBrowserDialog();
|
||||
|
||||
if (folderBrowserDialog.ShowDialog() != DialogResult.OK)
|
||||
return;
|
||||
|
||||
var newAccessLink = new AccessLink { Path = folderBrowserDialog.SelectedPath };
|
||||
|
||||
|
||||
switch (container)
|
||||
var newAccessLink = new AccessLink
|
||||
{
|
||||
case "QuickAccessLink":
|
||||
if (SelectedQuickAccessLink == null) return;
|
||||
Settings.QuickAccessLinks.Add(newAccessLink);
|
||||
break;
|
||||
case "IndexSearchExcludedPaths":
|
||||
if (SelectedIndexSearchExcludedPath == null) return;
|
||||
Settings.IndexSearchExcludedSubdirectoryPaths.Add(newAccessLink);
|
||||
break;
|
||||
}
|
||||
Path = folderBrowserDialog.SelectedPath
|
||||
};
|
||||
|
||||
container.Add(newAccessLink);
|
||||
}
|
||||
|
||||
private void RemoveLink(object obj)
|
||||
|
|
@ -197,11 +264,38 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
Save();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private string? PromptUserSelectPath(ResultType type, string initialDirectory = null)
|
||||
{
|
||||
string path = null;
|
||||
|
||||
internal void RemoveLinkFromQuickAccess(AccessLink selectedRow) => Settings.QuickAccessLinks.Remove(selectedRow);
|
||||
if (type is ResultType.Folder)
|
||||
{
|
||||
var folderBrowserDialog = new FolderBrowserDialog();
|
||||
|
||||
if (initialDirectory is not null)
|
||||
folderBrowserDialog.InitialDirectory = initialDirectory;
|
||||
|
||||
if (folderBrowserDialog.ShowDialog() != DialogResult.OK)
|
||||
return path;
|
||||
|
||||
path = folderBrowserDialog.SelectedPath;
|
||||
}
|
||||
else if (type is ResultType.File)
|
||||
{
|
||||
var openFileDialog = new OpenFileDialog();
|
||||
if (initialDirectory is not null)
|
||||
openFileDialog.InitialDirectory = initialDirectory;
|
||||
|
||||
if (openFileDialog.ShowDialog() != DialogResult.OK)
|
||||
return path;
|
||||
|
||||
path = openFileDialog.FileName;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
internal void RemoveAccessLinkFromExcludedIndexPaths(AccessLink selectedRow) => Settings.IndexSearchExcludedSubdirectoryPaths.Remove(selectedRow);
|
||||
|
||||
internal static void OpenWindowsIndexingOptions()
|
||||
{
|
||||
|
|
@ -215,22 +309,69 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
Process.Start(psi);
|
||||
}
|
||||
|
||||
internal void UpdateActionKeyword(Settings.ActionKeyword modifiedActionKeyword, string newActionKeyword, string oldActionKeyword) =>
|
||||
PluginManager.ReplaceActionKeyword(Context.CurrentPluginMetadata.ID, oldActionKeyword, newActionKeyword);
|
||||
public bool UseWindowsIndexForDirectorySearch
|
||||
{
|
||||
get => Settings.UseWindowsIndexForDirectorySearch;
|
||||
set => Settings.UseWindowsIndexForDirectorySearch = value;
|
||||
}
|
||||
public ICommand OpenEditorPath => new RelayCommand(_ =>
|
||||
{
|
||||
var path = PromptUserSelectPath(ResultType.File, Settings.EditorPath != null ? Path.GetDirectoryName(Settings.EditorPath) : null);
|
||||
if (path is null)
|
||||
return;
|
||||
|
||||
internal bool IsActionKeywordAlreadyAssigned(string newActionKeyword) => PluginManager.ActionKeywordRegistered(newActionKeyword);
|
||||
EditorPath = path;
|
||||
});
|
||||
|
||||
internal bool IsNewActionKeywordGlobal(string newActionKeyword) => newActionKeyword == Query.GlobalPluginWildcardSign;
|
||||
|
||||
public bool UseWindowsIndexForDirectorySearch {
|
||||
get
|
||||
{
|
||||
return Settings.UseWindowsIndexForDirectorySearch;
|
||||
}
|
||||
public string EditorPath
|
||||
{
|
||||
get => Settings.EditorPath;
|
||||
set
|
||||
{
|
||||
Settings.UseWindowsIndexForDirectorySearch = value;
|
||||
Settings.EditorPath = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region Everything FastSortWarning
|
||||
|
||||
public Visibility FastSortWarningVisibility
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return EverythingApi.IsFastSortOption(Settings.SortOption) ? Visibility.Collapsed : Visibility.Visible;
|
||||
}
|
||||
catch (IPCErrorException)
|
||||
{
|
||||
// this error occurs if the Everything service is not running, in this instance show the warning and
|
||||
// update the message to let user know in the settings panel.
|
||||
return Visibility.Visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
public string SortOptionWarningMessage
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
// this method is used to determine if Everything service is running because as at Everything v1.4.1
|
||||
// the sdk does not provide a dedicated interface to determine if it is running.
|
||||
return EverythingApi.IsFastSortOption(Settings.SortOption) ? string.Empty
|
||||
: Context.API.GetTranslation("flowlauncher_plugin_everything_nonfastsort_warning");
|
||||
}
|
||||
catch (IPCErrorException)
|
||||
{
|
||||
return Context.API.GetTranslation("flowlauncher_plugin_everything_is_not_running");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
using Flow.Launcher.Plugin.Everything.Everything;
|
||||
using Flow.Launcher.Plugin.Explorer.Helper;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Explorer.Views.Converters;
|
||||
|
||||
public class EnumNameConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return value is SortOption option ? option.GetTranslatedName() : value;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
xmlns:qa="clr-namespace:Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks"
|
||||
xmlns:viewModels="clr-namespace:Flow.Launcher.Plugin.Explorer.ViewModels"
|
||||
xmlns:views="clr-namespace:Flow.Launcher.Plugin.Explorer.Views"
|
||||
xmlns:converters="clr-namespace:Flow.Launcher.Plugin.Explorer.Views.Converters"
|
||||
d:DataContext="{d:DesignInstance viewModels:SettingsViewModel}"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
|
|
@ -15,7 +16,7 @@
|
|||
<DataTemplate x:Key="ListViewTemplateAccessLinks" DataType="qa:AccessLink">
|
||||
<TextBlock Margin="0,5,0,5" Text="{Binding Path, Mode=OneTime}" />
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="ListViewActionKeywords" DataType="views:ActionKeywordView">
|
||||
<DataTemplate x:Key="ListViewActionKeywords" DataType="{x:Type views:ActionKeywordModel}">
|
||||
<Grid>
|
||||
<TextBlock
|
||||
Margin="0,5,0,0"
|
||||
|
|
@ -53,6 +54,7 @@
|
|||
</TextBlock>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
<converters:EnumNameConverter x:Key="EnumNameConverter" />
|
||||
</UserControl.Resources>
|
||||
<Grid Margin="10">
|
||||
<Grid.RowDefinitions>
|
||||
|
|
@ -61,32 +63,145 @@
|
|||
</Grid.RowDefinitions>
|
||||
<StackPanel Grid.Row="0" Margin="20,35,0,0">
|
||||
<StackPanel>
|
||||
<Expander
|
||||
Header="{DynamicResource plugin_explorer_generalsetting_header}">
|
||||
<Expander
|
||||
Margin="15"
|
||||
Header="{DynamicResource plugin_explorer_generalsetting_header}"
|
||||
Expanded="SettingExpander_OnExpanded"
|
||||
Collapsed="SettingExpander_OnCollapsed">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<StackPanel.Resources>
|
||||
<DataTemplate x:Key="EnumBindingModelItemTemplate">
|
||||
<TextBlock Text="{Binding Description}" />
|
||||
</DataTemplate>
|
||||
</StackPanel.Resources>
|
||||
<CheckBox
|
||||
Name="UseWindowsIndexForDirectorySearch"
|
||||
Margin="12,10,0,0"
|
||||
Content="{DynamicResource plugin_explorer_usewindowsindexfordirectorysearch}"
|
||||
IsChecked="{Binding UseWindowsIndexForDirectorySearch}"
|
||||
ToolTip="{DynamicResource plugin_explorer_usewindowsindexfordirectorysearch_tooltip}" />
|
||||
<ComboBox
|
||||
Width="200"
|
||||
ItemsSource="{Binding Settings.SortOptions, Mode=OneWay}"
|
||||
SelectedItem="{Binding Settings.SortOption}" />
|
||||
<CheckBox
|
||||
Margin="12,10,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
Content="{DynamicResource plugin_explorer_use_location_as_working_dir}"
|
||||
IsChecked="{Binding Settings.UseLocationAsWorkingDir}" />
|
||||
<CheckBox
|
||||
Margin="12,10,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
Content="{DynamicResource plugin_explorer_launch_hidden}"
|
||||
IsChecked="{Binding Settings.LaunchHidden}" />
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="10,6,6,6"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Text="{DynamicResource plugin_explorer_editor_path}" />
|
||||
<TextBox
|
||||
Margin="15"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
TextWrapping="NoWrap"
|
||||
MaxWidth="250"
|
||||
Text="{Binding EditorPath}" />
|
||||
<Button
|
||||
MinWidth="50"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="15"
|
||||
Command="{Binding OpenEditorPath}"
|
||||
Content="..." />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="Index Search Engine" />
|
||||
<ComboBox
|
||||
Margin="15"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Width="250"
|
||||
ItemsSource="{Binding IndexSearchEngines }"
|
||||
SelectedItem="{Binding SelectedIndexSearchEngine}"
|
||||
ItemTemplate="{StaticResource EnumBindingModelItemTemplate}">
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="Content Search Engine" />
|
||||
<ComboBox
|
||||
Margin="15"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Width="250"
|
||||
ItemsSource="{Binding ContentIndexSearchEngines }"
|
||||
SelectedItem="{Binding SelectedContentSearchEngine}"
|
||||
ItemTemplate="{StaticResource EnumBindingModelItemTemplate}">
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="Path Enumeration Engine" />
|
||||
<ComboBox
|
||||
Margin="15"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Width="250"
|
||||
ItemsSource="{Binding PathEnumerationEngines }"
|
||||
SelectedItem="{Binding SelectedPathEnumerationEngine}"
|
||||
ItemTemplate="{StaticResource EnumBindingModelItemTemplate}">
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button
|
||||
Margin="15"
|
||||
Content="Open Window Index Option"
|
||||
Click="btnOpenIndexingOptions_Click"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Expander>
|
||||
<Expander
|
||||
Name="expActionKeywords"
|
||||
Margin="15"
|
||||
Header="{DynamicResource plugin_explorer_everything_setting_header}"
|
||||
Expanded="SettingExpander_OnExpanded"
|
||||
Collapsed="SettingExpander_OnCollapsed">
|
||||
<DockPanel>
|
||||
<TextBlock
|
||||
Text="{DynamicResource plugin_explorer_everything_sort_option}"
|
||||
Margin="15" />
|
||||
<ComboBox
|
||||
DockPanel.Dock="Left"
|
||||
Width="200"
|
||||
VerticalAlignment="Center"
|
||||
ItemsSource="{Binding Settings.SortOptions, Mode=OneWay}"
|
||||
SelectedItem="{Binding Settings.SortOption}"
|
||||
SelectionChanged="EverythingSortOptionChanged">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<TextBlock Text="{Binding Converter={StaticResource EnumNameConverter}}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
<TextBlock
|
||||
Name="tbFastSortWarning"
|
||||
DockPanel.Dock="Right"
|
||||
Margin="0 0 10 0"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="Orange"
|
||||
Text="{Binding SortOptionWarningMessage, Mode=OneTime}"
|
||||
TextAlignment="Left"
|
||||
TextWrapping="Wrap"
|
||||
Visibility="{Binding FastSortWarningVisibility, Mode=OneTime}" />
|
||||
</DockPanel>
|
||||
</Expander>
|
||||
<Expander
|
||||
Margin="15"
|
||||
Height="auto"
|
||||
Expanded="expActionKeywords_Click"
|
||||
Expanded="SettingExpander_OnExpanded"
|
||||
Collapsed="SettingExpander_OnCollapsed"
|
||||
Header="{DynamicResource plugin_explorer_manageactionkeywords_header}">
|
||||
<DockPanel HorizontalAlignment="Stretch">
|
||||
<ListView
|
||||
x:Name="lbxActionKeywords"
|
||||
DockPanel.Dock="Top"
|
||||
ItemTemplate="{StaticResource ListViewActionKeywords}"
|
||||
SelectedItem="{Binding SelectedActionKeyword}"/>
|
||||
ItemsSource="{Binding ActionKeywordsModels}"
|
||||
SelectedItem="{Binding SelectedActionKeyword}" />
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
|
|
@ -95,81 +210,89 @@
|
|||
</DockPanel>
|
||||
</Expander>
|
||||
<Expander
|
||||
Margin="15"
|
||||
Expanded="SettingExpander_OnExpanded"
|
||||
Collapsed="SettingExpander_OnCollapsed"
|
||||
Name="expAccessLinks"
|
||||
Margin="0,10,0,0"
|
||||
Header="{DynamicResource plugin_explorer_quickaccesslinks_header}">
|
||||
<DockPanel HorizontalAlignment="Stretch">
|
||||
<ListView
|
||||
x:Name="lbxAccessLinks"
|
||||
Height="200"
|
||||
AllowDrop="True"
|
||||
DockPanel.Dock="Top"
|
||||
ItemTemplate="{StaticResource ListViewTemplateAccessLinks}"
|
||||
ItemsSource="{Binding Settings.QuickAccessLinks}"
|
||||
SelectedItem="{Binding SelectedQuickAccessLink}" />
|
||||
<StackPanel
|
||||
HorizontalAlignment="Right"
|
||||
DockPanel.Dock="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Command="{Binding RemoveLinkCommand}"
|
||||
CommandParameter="QuickAccessLink"
|
||||
Content="{DynamicResource plugin_explorer_delete}" />
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Command="{Binding EditLinkCommand}"
|
||||
CommandParameter="QuickAccessLink"
|
||||
Content="{DynamicResource plugin_explorer_edit}" />
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Command="{Binding AddLinkCommand}"
|
||||
CommandParameter="QuickAccessLink"
|
||||
Content="{DynamicResource plugin_explorer_add}" />
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
<ScrollViewer>
|
||||
<DockPanel HorizontalAlignment="Stretch">
|
||||
<ListView
|
||||
x:Name="lbxAccessLinks"
|
||||
Height="200"
|
||||
AllowDrop="True"
|
||||
DragEnter="lbxAccessLinks_DragEnter"
|
||||
Drop="LbxAccessLinks_OnDrop"
|
||||
DockPanel.Dock="Top"
|
||||
ItemTemplate="{StaticResource ListViewTemplateAccessLinks}"
|
||||
ItemsSource="{Binding Settings.QuickAccessLinks}"
|
||||
SelectedItem="{Binding SelectedQuickAccessLink}" />
|
||||
<StackPanel
|
||||
HorizontalAlignment="Right"
|
||||
DockPanel.Dock="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Command="{Binding RemoveLinkCommand}"
|
||||
CommandParameter="QuickAccessLink"
|
||||
Content="{DynamicResource plugin_explorer_delete}" />
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Command="{Binding EditLinkCommand}"
|
||||
CommandParameter="QuickAccessLink"
|
||||
Content="{DynamicResource plugin_explorer_edit}" />
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Command="{Binding AddLinkCommand}"
|
||||
CommandParameter="QuickAccessLink"
|
||||
Content="{DynamicResource plugin_explorer_add}" />
|
||||
</StackPanel>
|
||||
</DockPanel></ScrollViewer>
|
||||
</Expander>
|
||||
<Expander
|
||||
x:Name="expExcludedPaths"
|
||||
Margin="0,10,0,0"
|
||||
Margin="15"
|
||||
Expanded="SettingExpander_OnExpanded"
|
||||
Collapsed="SettingExpander_OnCollapsed"
|
||||
Header="{DynamicResource plugin_explorer_indexsearchexcludedpaths_header}">
|
||||
<DockPanel HorizontalAlignment="Stretch">
|
||||
<ListView
|
||||
Name="lbxExcludedPaths"
|
||||
AllowDrop="True"
|
||||
DockPanel.Dock="Top"
|
||||
DragEnter="lbxAccessLinks_DragEnter"
|
||||
Drop="lbxAccessLinks_Drop"
|
||||
ItemTemplate="{StaticResource ListViewActionKeywords}"
|
||||
ItemsSource="{Binding Settings.IndexSearchExcludedSubdirectoryPaths}"
|
||||
SelectedItem="{Binding SelectedIndexSearchExcludedPath}" />
|
||||
<StackPanel
|
||||
HorizontalAlignment="Right"
|
||||
DockPanel.Dock="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Command="{Binding RemoveLinkCommand}"
|
||||
CommandParameter="IndexSearchExcludedPaths"
|
||||
Content="{DynamicResource plugin_explorer_delete}" />
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Command="{Binding EditLinkCommand}"
|
||||
CommandParameter="IndexSearchExcludedPaths"
|
||||
Content="{DynamicResource plugin_explorer_edit}" />
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Command="{Binding AddLinkCommand}"
|
||||
CommandParameter="IndexSearchExcludedPaths"
|
||||
Content="{DynamicResource plugin_explorer_add}" />
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
<ScrollViewer>
|
||||
<DockPanel HorizontalAlignment="Stretch">
|
||||
<ListView
|
||||
Name="lbxExcludedPaths"
|
||||
AllowDrop="True"
|
||||
DockPanel.Dock="Top"
|
||||
DragEnter="lbxAccessLinks_DragEnter"
|
||||
Drop="LbxExcludedPaths_OnDrop"
|
||||
ItemTemplate="{StaticResource ListViewActionKeywords}"
|
||||
ItemsSource="{Binding Settings.IndexSearchExcludedSubdirectoryPaths}"
|
||||
SelectedItem="{Binding SelectedIndexSearchExcludedPath}" />
|
||||
<StackPanel
|
||||
HorizontalAlignment="Right"
|
||||
DockPanel.Dock="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Command="{Binding RemoveLinkCommand}"
|
||||
CommandParameter="IndexSearchExcludedPaths"
|
||||
Content="{DynamicResource plugin_explorer_delete}" />
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Command="{Binding EditLinkCommand}"
|
||||
CommandParameter="IndexSearchExcludedPaths"
|
||||
Content="{DynamicResource plugin_explorer_edit}" />
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Command="{Binding AddLinkCommand}"
|
||||
CommandParameter="IndexSearchExcludedPaths"
|
||||
Content="{DynamicResource plugin_explorer_add}" />
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</ScrollViewer>
|
||||
</Expander>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
|
|
|||
|
|
@ -6,10 +6,14 @@ using System.ComponentModel;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using DataFormats = System.Windows.DataFormats;
|
||||
using DragDropEffects = System.Windows.DragDropEffects;
|
||||
using DragEventArgs = System.Windows.DragEventArgs;
|
||||
using ListView = System.Windows.Controls.ListView;
|
||||
using MessageBox = System.Windows.MessageBox;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Explorer.Views
|
||||
|
|
@ -23,6 +27,7 @@ namespace Flow.Launcher.Plugin.Explorer.Views
|
|||
|
||||
private List<ActionKeywordModel> actionKeywordsListView;
|
||||
|
||||
|
||||
public ExplorerSettings(SettingsViewModel viewModel)
|
||||
{
|
||||
DataContext = viewModel;
|
||||
|
|
@ -33,105 +38,36 @@ namespace Flow.Launcher.Plugin.Explorer.Views
|
|||
|
||||
DataContext = viewModel;
|
||||
|
||||
lbxAccessLinks.ItemsSource = this.viewModel.Settings.QuickAccessLinks;
|
||||
|
||||
lbxExcludedPaths.ItemsSource = this.viewModel.Settings.IndexSearchExcludedSubdirectoryPaths;
|
||||
|
||||
actionKeywordsListView = new List<ActionKeywordModel>
|
||||
{
|
||||
new(Settings.ActionKeyword.SearchActionKeyword,
|
||||
viewModel.Context.API.GetTranslation("plugin_explorer_actionkeywordview_search")),
|
||||
new(Settings.ActionKeyword.FileContentSearchActionKeyword,
|
||||
viewModel.Context.API.GetTranslation("plugin_explorer_actionkeywordview_filecontentsearch")),
|
||||
new(Settings.ActionKeyword.PathSearchActionKeyword,
|
||||
viewModel.Context.API.GetTranslation("plugin_explorer_actionkeywordview_pathsearch")),
|
||||
new(Settings.ActionKeyword.IndexSearchActionKeyword,
|
||||
viewModel.Context.API.GetTranslation("plugin_explorer_actionkeywordview_indexsearch")),
|
||||
new(Settings.ActionKeyword.QuickAccessActionKeyword,
|
||||
viewModel.Context.API.GetTranslation("plugin_explorer_actionkeywordview_quickaccess"))
|
||||
};
|
||||
|
||||
lbxActionKeywords.ItemsSource = actionKeywordsListView;
|
||||
|
||||
ActionKeywordModel.Init(viewModel.Settings);
|
||||
|
||||
lbxAccessLinks.Items.SortDescriptions.Add(new SortDescription("Path", ListSortDirection.Ascending));
|
||||
|
||||
lbxExcludedPaths.Items.SortDescriptions.Add(new SortDescription("Path", ListSortDirection.Ascending));
|
||||
}
|
||||
|
||||
|
||||
private void expActionKeywords_Click(object sender, RoutedEventArgs e)
|
||||
|
||||
|
||||
private void AccessLinkDragDrop(string containerName, DragEventArgs e)
|
||||
{
|
||||
if (expExcludedPaths.IsExpanded)
|
||||
expExcludedPaths.IsExpanded = false;
|
||||
var files = (string[])e.Data.GetData(DataFormats.FileDrop);
|
||||
|
||||
if (expAccessLinks.IsExpanded)
|
||||
expAccessLinks.IsExpanded = false;
|
||||
}
|
||||
|
||||
|
||||
private void expAccessLinks_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (expExcludedPaths.IsExpanded)
|
||||
expExcludedPaths.IsExpanded = false;
|
||||
|
||||
if (expActionKeywords.IsExpanded)
|
||||
expActionKeywords.IsExpanded = false;
|
||||
}
|
||||
|
||||
private void expExcludedPaths_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (expAccessLinks.IsExpanded)
|
||||
expAccessLinks.IsExpanded = false;
|
||||
|
||||
if (expActionKeywords.IsExpanded)
|
||||
expActionKeywords.IsExpanded = false;
|
||||
}
|
||||
|
||||
|
||||
private void lbxAccessLinks_Drop(object sender, DragEventArgs e)
|
||||
{
|
||||
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
|
||||
|
||||
if (files != null && files.Count() > 0)
|
||||
if (files == null || !files.Any())
|
||||
{
|
||||
if (expAccessLinks.IsExpanded && viewModel.Settings.QuickAccessLinks == null)
|
||||
viewModel.Settings.QuickAccessLinks = new();
|
||||
|
||||
foreach (string s in files)
|
||||
return;
|
||||
}
|
||||
foreach (var s in files)
|
||||
{
|
||||
if (Directory.Exists(s))
|
||||
{
|
||||
if (Directory.Exists(s))
|
||||
var newFolderLink = new AccessLink
|
||||
{
|
||||
var newFolderLink = new AccessLink { Path = s };
|
||||
|
||||
AddAccessLink(newFolderLink);
|
||||
}
|
||||
Path = s
|
||||
};
|
||||
viewModel.AppendLink(containerName, newFolderLink);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddAccessLink(AccessLink newAccessLink)
|
||||
{
|
||||
if (expAccessLinks.IsExpanded
|
||||
&& !viewModel.Settings.QuickAccessLinks.Any(x => x.Path == newAccessLink.Path))
|
||||
{
|
||||
if (viewModel.Settings.QuickAccessLinks == null)
|
||||
viewModel.Settings.QuickAccessLinks = new();
|
||||
|
||||
viewModel.Settings.QuickAccessLinks.Add(newAccessLink);
|
||||
}
|
||||
|
||||
if (expExcludedPaths.IsExpanded
|
||||
&& !viewModel.Settings.IndexSearchExcludedSubdirectoryPaths.Any(x => x.Path == newAccessLink.Path))
|
||||
{
|
||||
if (viewModel.Settings.IndexSearchExcludedSubdirectoryPaths == null)
|
||||
viewModel.Settings.IndexSearchExcludedSubdirectoryPaths = new ();
|
||||
|
||||
viewModel.Settings.IndexSearchExcludedSubdirectoryPaths.Add(newAccessLink);
|
||||
}
|
||||
}
|
||||
|
||||
private void lbxAccessLinks_DragEnter(object sender, DragEventArgs e)
|
||||
{
|
||||
if (e.Data.GetDataPresent(DataFormats.FileDrop))
|
||||
|
|
@ -148,5 +84,53 @@ namespace Flow.Launcher.Plugin.Explorer.Views
|
|||
{
|
||||
SettingsViewModel.OpenWindowsIndexingOptions();
|
||||
}
|
||||
private void EverythingSortOptionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (tbFastSortWarning is not null)
|
||||
{
|
||||
tbFastSortWarning.Visibility = viewModel.FastSortWarningVisibility;
|
||||
tbFastSortWarning.Text = viewModel.SortOptionWarningMessage;
|
||||
}
|
||||
}
|
||||
private void SettingExpander_OnExpanded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is not Expander expander)
|
||||
return;
|
||||
|
||||
var parentContainer = VisualTreeHelper.GetParent(expander);
|
||||
|
||||
if (parentContainer is not StackPanel stackPanel)
|
||||
return;
|
||||
|
||||
foreach (UIElement child in stackPanel.Children)
|
||||
{
|
||||
if (child != expander)
|
||||
child.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
private void SettingExpander_OnCollapsed(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is not Expander expander)
|
||||
return;
|
||||
|
||||
var parentContainer = VisualTreeHelper.GetParent(expander);
|
||||
|
||||
if (parentContainer is not StackPanel stackPanel)
|
||||
return;
|
||||
|
||||
foreach (UIElement child in stackPanel.Children)
|
||||
{
|
||||
if (child != expander)
|
||||
child.Visibility = Visibility.Visible;
|
||||
}
|
||||
}
|
||||
private void LbxAccessLinks_OnDrop(object sender, DragEventArgs e)
|
||||
{
|
||||
AccessLinkDragDrop("QuickAccessLink", e);
|
||||
}
|
||||
private void LbxExcludedPaths_OnDrop(object sender, DragEventArgs e)
|
||||
{
|
||||
AccessLinkDragDrop("IndexSearchExcludedPath", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue