diff --git a/Plugins/Wox.Plugin.Folder/ContextMenuLoader.cs b/Plugins/Wox.Plugin.Folder/ContextMenuLoader.cs new file mode 100644 index 000000000..92fae4620 --- /dev/null +++ b/Plugins/Wox.Plugin.Folder/ContextMenuLoader.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Windows; +using Wox.Infrastructure.Logger; + +namespace Wox.Plugin.Folder +{ + internal class ContextMenuLoader : IContextMenu + { + private readonly PluginInitContext _context; + + public ContextMenuLoader(PluginInitContext context) + { + _context = context; + } + + public List LoadContextMenus(Result selectedResult) + { + var contextMenus = new List(); + if (selectedResult.ContextData is SearchResult record) + { + if (record.Type == ResultType.File) + { + contextMenus.Add(CreateOpenWithEditorResult(record)); + contextMenus.Add(CreateOpenContainingFolderResult(record)); + } + + var icoPath = (record.Type == ResultType.File) ? Main.FileImagePath : Main.FolderImagePath; + var fileOrFolder = (record.Type == ResultType.File) ? "file" : "folder"; + contextMenus.Add(new Result + { + Title = "Copy Path", + SubTitle = $"Copy the path of {fileOrFolder} into the clipboard", + Action = (context) => + { + try + { + Clipboard.SetText(record.FullPath); + return true; + } + catch (Exception e) + { + var message = "Fail to set text in clipboard"; + LogException(message, e); + _context.API.ShowMsg(message); + return false; + } + }, + IcoPath = icoPath + }); + + contextMenus.Add(new Result + { + Title = "Copy", + SubTitle = $"Copy the {fileOrFolder} to the clipboard", + Action = (context) => + { + try + { + Clipboard.SetFileDropList(new System.Collections.Specialized.StringCollection { record.FullPath }); + return true; + } + catch (Exception e) + { + var message = $"Fail to set {fileOrFolder} in clipboard"; + LogException(message, e); + _context.API.ShowMsg(message); + return false; + } + + }, + IcoPath = icoPath + }); + + if (record.Type == ResultType.File || record.Type == ResultType.Folder) + contextMenus.Add(new Result + { + Title = "Delete", + Action = (context) => + { + try + { + if (record.Type == ResultType.File) + File.Delete(record.FullPath); + else + Directory.Delete(record.FullPath); + } + catch(Exception e) + { + var message = $"Fail to delete {fileOrFolder} at {record.FullPath}"; + LogException(message, e); + _context.API.ShowMsg(message); + return false; + } + + return true; + }, + IcoPath = icoPath + }); + + } + + return contextMenus; + } + + private Result CreateOpenContainingFolderResult(SearchResult record) + { + return new Result + { + Title = "Open containing folder", + Action = _ => + { + try + { + Process.Start("explorer.exe", $" /select,\"{record.FullPath}\""); + } + catch(Exception e) + { + var message = $"Fail to open file at {record.FullPath}"; + LogException(message, e); + _context.API.ShowMsg(message); + return false; + } + + return true; + }, + IcoPath = Main.FolderImagePath + }; + } + + + private Result CreateOpenWithEditorResult(SearchResult record) + { + string editorPath = "notepad.exe"; // TODO add the ability to create a custom editor + + var name = "Open With Editor: " + Path.GetFileNameWithoutExtension(editorPath); + return new Result + { + Title = name, + Action = _ => + { + try + { + Process.Start(editorPath, record.FullPath); + return true; + } + catch (Exception e) + { + var message = $"Fail to editor for file at {record.FullPath}"; + LogException(message, e); + _context.API.ShowMsg(message); + return false; + } + }, + IcoPath = editorPath + }; + } + + public void LogException(string message, Exception e) + { + Log.Exception($"|Wox.Plugin.Folder.ContextMenu|{message}", e); + } + } + + public class SearchResult + { + public string FullPath { get; set; } + public ResultType Type { get; set; } + } + + public enum ResultType + { + Volume, + Folder, + File + } +} \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Folder/Images/file.png b/Plugins/Wox.Plugin.Folder/Images/file.png new file mode 100644 index 000000000..36156767a Binary files /dev/null and b/Plugins/Wox.Plugin.Folder/Images/file.png differ diff --git a/Plugins/Wox.Plugin.Folder/Main.cs b/Plugins/Wox.Plugin.Folder/Main.cs index d7b5a1569..4fff0d40c 100644 --- a/Plugins/Wox.Plugin.Folder/Main.cs +++ b/Plugins/Wox.Plugin.Folder/Main.cs @@ -10,13 +10,18 @@ using Wox.Infrastructure.Storage; namespace Wox.Plugin.Folder { - public class Main : IPlugin, ISettingProvider, IPluginI18n, ISavable + public class Main : IPlugin, ISettingProvider, IPluginI18n, ISavable, IContextMenu { + public const string FolderImagePath = "Images\\folder.png"; + public const string FileImagePath = "Images\\file.png"; + + private static List _driverNames; private PluginInitContext _context; private readonly Settings _settings; private readonly PluginJsonStorage _storage; + private IContextMenu _contextMenuLoader; public Main() { @@ -37,6 +42,7 @@ namespace Wox.Plugin.Folder public void Init(PluginInitContext context) { _context = context; + _contextMenuLoader = new ContextMenuLoader(context); InitialDriverList(); } @@ -45,7 +51,7 @@ namespace Wox.Plugin.Folder var results = GetUserFolderResults(query); string search = query.Search.ToLower(); - if (_driverNames != null && !_driverNames.Any(search.StartsWith)) + if (!IsDriveOrSharedFolder(search)) return results; results.AddRange(QueryInternal_Directory_Exists(query)); @@ -59,6 +65,26 @@ namespace Wox.Plugin.Folder return results; } + private static bool IsDriveOrSharedFolder(string search) + { + if (search.StartsWith(@"\\")) + { // share folder + return true; + } + + if (_driverNames != null && _driverNames.Any(search.StartsWith)) + { // normal drive letter + return true; + } + + if (_driverNames == null && search.Length > 2 && char.IsLetter(search[0]) && search[1] == ':') + { // when we don't have the drive letters we can try... + return true; // we don't know so let's give it the possibility + } + + return false; + } + private Result CreateFolderResult(string title, string path, Query query) { return new Result @@ -88,7 +114,8 @@ namespace Wox.Plugin.Folder changeTo : query.ActionKeyword + " " + changeTo); return false; - } + }, + ContextData = new SearchResult { Type = ResultType.Folder, FullPath = path } }; } @@ -217,7 +244,8 @@ namespace Wox.Plugin.Folder } return true; - } + }, + ContextData = new SearchResult { Type = ResultType.File, FullPath = filePath} }; return result; } @@ -254,5 +282,10 @@ namespace Wox.Plugin.Folder { return _context.API.GetTranslation("wox_plugin_folder_plugin_description"); } + + public List LoadContextMenus(Result selectedResult) + { + return _contextMenuLoader.LoadContextMenus(selectedResult); + } } } \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Folder/Wox.Plugin.Folder.csproj b/Plugins/Wox.Plugin.Folder/Wox.Plugin.Folder.csproj index 6a05ebd26..e0305a648 100644 --- a/Plugins/Wox.Plugin.Folder/Wox.Plugin.Folder.csproj +++ b/Plugins/Wox.Plugin.Folder/Wox.Plugin.Folder.csproj @@ -58,6 +58,7 @@ Properties\SolutionAssemblyInfo.cs + @@ -80,6 +81,9 @@ PreserveNewest + + PreserveNewest + MSBuild:Compile Designer diff --git a/Wox.Infrastructure/Logger/Log.cs b/Wox.Infrastructure/Logger/Log.cs index dfa05c715..ff72dff1c 100644 --- a/Wox.Infrastructure/Logger/Log.cs +++ b/Wox.Infrastructure/Logger/Log.cs @@ -87,7 +87,7 @@ namespace Wox.Infrastructure.Logger do { - logger.Error($"Exception fulle name:\n <{e.GetType().FullName}>"); + logger.Error($"Exception full name:\n <{e.GetType().FullName}>"); logger.Error($"Exception message:\n <{e.Message}>"); logger.Error($"Exception stack trace:\n <{e.StackTrace}>"); logger.Error($"Exception source:\n <{e.Source}>");