diff --git a/Plugins/Wox.Plugin.CMD/CMD.cs b/Plugins/Wox.Plugin.CMD/CMD.cs index bb0a21272..b1e003d35 100644 --- a/Plugins/Wox.Plugin.CMD/CMD.cs +++ b/Plugins/Wox.Plugin.CMD/CMD.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; @@ -8,11 +9,12 @@ using WindowsInput; using WindowsInput.Native; using Wox.Infrastructure; using Wox.Infrastructure.Hotkey; +using Wox.Plugin.Features; using Control = System.Windows.Controls.Control; namespace Wox.Plugin.CMD { - public class CMD : IPlugin, ISettingProvider, IPluginI18n, IInstantSearch + public class CMD : IPlugin, ISettingProvider, IPluginI18n, IInstantQuery, IExclusiveQuery,IContextMenu { private PluginInitContext context; private bool WinRStroked; @@ -68,8 +70,7 @@ namespace Wox.Plugin.CMD { ExecuteCmd(m); return true; - }, - ContextMenu = GetContextMenus(m) + } })); } } @@ -100,8 +101,7 @@ namespace Wox.Plugin.CMD { ExecuteCmd(m.Key); return true; - }, - ContextMenu = GetContextMenus(m.Key) + } }; return ret; }).Where(o => o != null).Take(4); @@ -120,8 +120,7 @@ namespace Wox.Plugin.CMD { ExecuteCmd(cmd); return true; - }, - ContextMenu = GetContextMenus(cmd) + } }; return result; @@ -139,30 +138,11 @@ namespace Wox.Plugin.CMD { ExecuteCmd(m.Key); return true; - }, - ContextMenu = GetContextMenus(m.Key) + } }).Take(5); return history.ToList(); } - private List GetContextMenus(string cmd) - { - return new List() - { - new Result() - { - Title = "Run As Administrator", - Action = c => - { - context.API.HideApp(); - ExecuteCmd(cmd, true); - return true; - }, - IcoPath = "Images/cmd.png" - } - }; - } - private void ExecuteCmd(string cmd, bool runAsAdministrator = false) { if (context.API.ShellRun(cmd, runAsAdministrator)) @@ -211,10 +191,43 @@ namespace Wox.Plugin.CMD return Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Languages"); } - public bool IsInstantSearch(string query) + public string GetTranslatedPluginTitle() + { + return context.API.GetTranslation("wox_plugin_cmd_plugin_name"); + } + + public string GetTranslatedPluginDescription() + { + return context.API.GetTranslation("wox_plugin_cmd_plugin_description"); + } + + public bool IsInstantQuery(string query) { if (query.StartsWith(">")) return true; return false; } + + public bool IsExclusiveQuery(Query query) + { + return query.Search.StartsWith(">"); + } + + public List LoadContextMenus(Result selectedResult) + { + return new List() + { + new Result() + { + Title = "Run As Administrator", + Action = c => + { + context.API.HideApp(); + ExecuteCmd(selectedResult.Title, true); + return true; + }, + IcoPath = "Images/cmd.png" + } + }; + } } } \ No newline at end of file diff --git a/Plugins/Wox.Plugin.CMD/Languages/en.xaml b/Plugins/Wox.Plugin.CMD/Languages/en.xaml index 309a4867d..a37ee02a9 100644 --- a/Plugins/Wox.Plugin.CMD/Languages/en.xaml +++ b/Plugins/Wox.Plugin.CMD/Languages/en.xaml @@ -4,5 +4,7 @@ Replace Win+R Do not close Command Prompt after command execution + Shell + Provide executing commands from Wox. Commands should start with > \ No newline at end of file diff --git a/Plugins/Wox.Plugin.CMD/Languages/zh-cn.xaml b/Plugins/Wox.Plugin.CMD/Languages/zh-cn.xaml index 0847dda6c..9693f5f3c 100644 --- a/Plugins/Wox.Plugin.CMD/Languages/zh-cn.xaml +++ b/Plugins/Wox.Plugin.CMD/Languages/zh-cn.xaml @@ -1,8 +1,10 @@ - - - 替换 Win+R - 执行后不关闭命令窗口 - + + + 替换 Win+R + 执行后不关闭命令窗口 + 命令行 + 提供从Wox中执行命令行的能力,命令应该以>开头 + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.CMD/Languages/zh-tw.xaml b/Plugins/Wox.Plugin.CMD/Languages/zh-tw.xaml index 8ac28c363..7d318ff0b 100644 --- a/Plugins/Wox.Plugin.CMD/Languages/zh-tw.xaml +++ b/Plugins/Wox.Plugin.CMD/Languages/zh-tw.xaml @@ -1,8 +1,10 @@ - - - 替換 Win+R - 執行後不關閉命令窗口 - + + + 替換 Win+R + 執行後不關閉命令窗口 + 命令行 + 提供從Wox中執行命令行的能力,命令應該以>開頭 + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Caculator/Calculator.cs b/Plugins/Wox.Plugin.Caculator/Calculator.cs index da5e580a7..0f6acdfcc 100644 --- a/Plugins/Wox.Plugin.Caculator/Calculator.cs +++ b/Plugins/Wox.Plugin.Caculator/Calculator.cs @@ -1,11 +1,13 @@ using System.Collections.Generic; +using System.IO; +using System.Reflection; using System.Text.RegularExpressions; using System.Windows; using YAMP; namespace Wox.Plugin.Caculator { - public class Calculator : IPlugin + public class Calculator : IPlugin, IPluginI18n { private static Regex regValidExpressChar = new Regex( @"^(" + @@ -87,5 +89,20 @@ namespace Wox.Plugin.Caculator { this.context = context; } + + public string GetLanguagesFolder() + { + return Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Languages"); + } + + public string GetTranslatedPluginTitle() + { + return context.API.GetTranslation("wox_plugin_caculator_plugin_name"); + } + + public string GetTranslatedPluginDescription() + { + return context.API.GetTranslation("wox_plugin_caculator_plugin_description"); + } } } diff --git a/Plugins/Wox.Plugin.Caculator/Languages/en.xaml b/Plugins/Wox.Plugin.Caculator/Languages/en.xaml new file mode 100644 index 000000000..a286f18f5 --- /dev/null +++ b/Plugins/Wox.Plugin.Caculator/Languages/en.xaml @@ -0,0 +1,8 @@ + + + Calculator + Provide mathematical calculations.(Try 5*3-2 in Wox) + + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Caculator/Languages/zh-cn.xaml b/Plugins/Wox.Plugin.Caculator/Languages/zh-cn.xaml new file mode 100644 index 000000000..34d3fb24e --- /dev/null +++ b/Plugins/Wox.Plugin.Caculator/Languages/zh-cn.xaml @@ -0,0 +1,8 @@ + + + 计算器 + 为Wox提供数学计算能力。(试着在Wox输入 5*3-2) + + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Caculator/Languages/zh-tw.xaml b/Plugins/Wox.Plugin.Caculator/Languages/zh-tw.xaml new file mode 100644 index 000000000..a0f1a68e7 --- /dev/null +++ b/Plugins/Wox.Plugin.Caculator/Languages/zh-tw.xaml @@ -0,0 +1,8 @@ + + + 計算器 + 為Wox提供數學計算能力。(試著在Wox輸入 5*3-2) + + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Caculator/Wox.Plugin.Caculator.csproj b/Plugins/Wox.Plugin.Caculator/Wox.Plugin.Caculator.csproj index 0a3f8ef91..f56492528 100644 --- a/Plugins/Wox.Plugin.Caculator/Wox.Plugin.Caculator.csproj +++ b/Plugins/Wox.Plugin.Caculator/Wox.Plugin.Caculator.csproj @@ -1,95 +1,116 @@ - - - - - Debug - AnyCPU - {59BD9891-3837-438A-958D-ADC7F91F6F7E} - Library - Properties - Wox.Plugin.Caculator - Wox.Plugin.Caculator - v3.5 - 512 - ..\..\ - true - - - - true - full - false - ..\..\Output\Debug\Plugins\Wox.Plugin.Caculator\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Output\Release\Plugins\Wox.Plugin.Caculator\ - TRACE - prompt - 4 - false - - - - - - - - - - - - False - ..\..\packages\YAMP.1.4.0\lib\net35\YAMP.dll - - - - - - - - - - PreserveNewest - - - - - {4fd29318-a8ab-4d8f-aa47-60bc241b8da3} - Wox.Infrastructure - - - {8451ecdd-2ea4-4966-bb0a-7bbc40138e80} - Wox.Plugin - - - - - PreserveNewest - - - - - - - 这台计算机上缺少此项目引用的 NuGet 程序包。启用“NuGet 程序包还原”可下载这些程序包。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 - - - - - - - + + + + + Debug + AnyCPU + {59BD9891-3837-438A-958D-ADC7F91F6F7E} + Library + Properties + Wox.Plugin.Caculator + Wox.Plugin.Caculator + v3.5 + 512 + ..\..\ + true + + + + true + full + false + ..\..\Output\Debug\Plugins\Wox.Plugin.Caculator\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + ..\..\Output\Release\Plugins\Wox.Plugin.Caculator\ + TRACE + prompt + 4 + false + + + + + + + + + + + + False + ..\..\packages\YAMP.1.4.0\lib\net35\YAMP.dll + + + + + + + + + + PreserveNewest + + + + + {4fd29318-a8ab-4d8f-aa47-60bc241b8da3} + Wox.Infrastructure + + + {8451ecdd-2ea4-4966-bb0a-7bbc40138e80} + Wox.Plugin + + + + + PreserveNewest + + + + + MSBuild:Compile + Designer + PreserveNewest + + + + + MSBuild:Compile + Designer + PreserveNewest + + + + + MSBuild:Compile + Designer + PreserveNewest + + + + + + + 这台计算机上缺少此项目引用的 NuGet 程序包。启用“NuGet 程序包还原”可下载这些程序包。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 + + + + + + + + --> \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Color/Color.cs b/Plugins/Wox.Plugin.Color/Color.cs index 36581cca9..2dd5c6d83 100644 --- a/Plugins/Wox.Plugin.Color/Color.cs +++ b/Plugins/Wox.Plugin.Color/Color.cs @@ -4,13 +4,15 @@ using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; +using System.Reflection; using System.Windows; namespace Wox.Plugin.Color { - public sealed class ColorsPlugin : IPlugin + public sealed class ColorsPlugin : IPlugin, IPluginI18n { private string DIR_PATH = Path.Combine(Path.GetTempPath(), @"Plugins\Colors\"); + private PluginInitContext context; private const int IMG_SIZE = 32; private DirectoryInfo ColorsDirectory { get; set; } @@ -103,6 +105,23 @@ namespace Wox.Plugin.Color public void Init(PluginInitContext context) { + this.context = context; + } + + + public string GetLanguagesFolder() + { + return Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Languages"); + } + + public string GetTranslatedPluginTitle() + { + return context.API.GetTranslation("wox_plugin_color_plugin_name"); + } + + public string GetTranslatedPluginDescription() + { + return context.API.GetTranslation("wox_plugin_color_plugin_description"); } } } \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Color/Languages/en.xaml b/Plugins/Wox.Plugin.Color/Languages/en.xaml new file mode 100644 index 000000000..b87a8ae8d --- /dev/null +++ b/Plugins/Wox.Plugin.Color/Languages/en.xaml @@ -0,0 +1,8 @@ + + + Colors + Provide hex color preview.(Try #000 in Wox) + + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Color/Languages/zh-cn.xaml b/Plugins/Wox.Plugin.Color/Languages/zh-cn.xaml new file mode 100644 index 000000000..32aa83ae8 --- /dev/null +++ b/Plugins/Wox.Plugin.Color/Languages/zh-cn.xaml @@ -0,0 +1,8 @@ + + + 颜色 + 提供在Wox查询hex颜色。(尝试在Wox中输入#000) + + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Color/Languages/zh-tw.xaml b/Plugins/Wox.Plugin.Color/Languages/zh-tw.xaml new file mode 100644 index 000000000..b76a9521a --- /dev/null +++ b/Plugins/Wox.Plugin.Color/Languages/zh-tw.xaml @@ -0,0 +1,7 @@ + + + 顏色 + 提供在Wox查詢hex顏色。(嘗試在Wox中輸入#000) + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Color/Wox.Plugin.Color.csproj b/Plugins/Wox.Plugin.Color/Wox.Plugin.Color.csproj index 81347e2f1..8a0428fad 100644 --- a/Plugins/Wox.Plugin.Color/Wox.Plugin.Color.csproj +++ b/Plugins/Wox.Plugin.Color/Wox.Plugin.Color.csproj @@ -34,6 +34,7 @@ + @@ -62,6 +63,27 @@ Wox.Plugin + + + MSBuild:Compile + Designer + PreserveNewest + + + + + MSBuild:Compile + Designer + PreserveNewest + + + + + MSBuild:Compile + Designer + PreserveNewest + + + --> \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Everything/plugin.json b/Plugins/Wox.Plugin.Everything/plugin.json index 0f7418f95..8eb78934e 100644 --- a/Plugins/Wox.Plugin.Everything/plugin.json +++ b/Plugins/Wox.Plugin.Everything/plugin.json @@ -1,6 +1,6 @@ { "ID":"D2D2C23B084D411DB66FE0C79D6C2A6E", - "ActionKeyword":"f", + "ActionKeyword":"*", "Name":"Everything", "Description":"Search Everything", "Author":"qianlifeng,orzfly", diff --git a/Plugins/Wox.Plugin.Folder/FolderPlugin.cs b/Plugins/Wox.Plugin.Folder/FolderPlugin.cs index ed9127509..622acac0d 100644 --- a/Plugins/Wox.Plugin.Folder/FolderPlugin.cs +++ b/Plugins/Wox.Plugin.Folder/FolderPlugin.cs @@ -9,20 +9,21 @@ using Control = System.Windows.Controls.Control; namespace Wox.Plugin.Folder { - public class FolderPlugin : IPlugin, ISettingProvider,IPluginI18n + public class FolderPlugin : IPlugin, ISettingProvider, IPluginI18n { private static List driverNames; private PluginInitContext context; public Control CreateSettingPanel() { - return new FileSystemSettings(context); + return new FileSystemSettings(context.API); } public void Init(PluginInitContext context) { this.context = context; this.context.API.BackKeyDownEvent += ApiBackKeyDownEvent; + this.context.API.ResultItemDropEvent += API_ResultItemDropEvent; InitialDriverList(); if (FolderStorage.Instance.FolderLinks == null) { @@ -31,6 +32,38 @@ namespace Wox.Plugin.Folder } } + void API_ResultItemDropEvent(Result result, IDataObject dropObject, DragEventArgs e) + { + if (dropObject.GetDataPresent(DataFormats.FileDrop)) + { + HanldeFilesDrop(result, dropObject); + } + e.Handled = true; + } + + private void HanldeFilesDrop(Result targetResult, IDataObject dropObject) + { + List files = ((string[])dropObject.GetData(DataFormats.FileDrop, false)).ToList(); + context.API.ShowContextMenu(context.CurrentPluginMetadata, GetContextMenusForFileDrop(targetResult, files)); + } + + private static List GetContextMenusForFileDrop(Result targetResult, List files) + { + List contextMenus = new List(); + string folderPath = ((FolderLink) targetResult.ContextData).Path; + contextMenus.Add(new Result() + { + Title = "Copy to this folder", + IcoPath = "Images/copy.png", + Action = _ => + { + MessageBox.Show("Copy"); + return true; + } + }); + return contextMenus; + } + private void ApiBackKeyDownEvent(WoxKeyDownEventArgs e) { string query = e.Query; @@ -78,7 +111,8 @@ namespace Wox.Plugin.Folder } context.API.ChangeQuery(item.Path); return false; - } + }, + ContextData = item }).ToList(); if (driverNames != null && !driverNames.Any(input.StartsWith)) @@ -92,9 +126,7 @@ namespace Wox.Plugin.Folder results.AddRange(QueryInternal_Directory_Exists(input)); return results; - } - - private void InitialDriverList() + } private void InitialDriverList() { if (driverNames == null) { @@ -188,5 +220,15 @@ namespace Wox.Plugin.Folder { return Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Languages"); } + + public string GetTranslatedPluginTitle() + { + return context.API.GetTranslation("wox_plugin_folder_plugin_name"); + } + + public string GetTranslatedPluginDescription() + { + return context.API.GetTranslation("wox_plugin_folder_plugin_description"); + } } } \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Folder/FolderPluginSettings.xaml.cs b/Plugins/Wox.Plugin.Folder/FolderPluginSettings.xaml.cs index 64845005e..0b0c655a7 100644 --- a/Plugins/Wox.Plugin.Folder/FolderPluginSettings.xaml.cs +++ b/Plugins/Wox.Plugin.Folder/FolderPluginSettings.xaml.cs @@ -13,11 +13,11 @@ namespace Wox.Plugin.Folder /// public partial class FileSystemSettings : UserControl { - PluginInitContext context; + private IPublicAPI woxAPI; - public FileSystemSettings(PluginInitContext context) + public FileSystemSettings(IPublicAPI woxAPI) { - this.context = context; + this.woxAPI = woxAPI; InitializeComponent(); lbxFolders.ItemsSource = FolderStorage.Instance.FolderLinks; } @@ -27,7 +27,7 @@ namespace Wox.Plugin.Folder var selectedFolder = lbxFolders.SelectedItem as FolderLink; if (selectedFolder != null) { - string msg = string.Format(context.API.GetTranslation("wox_plugin_folder_delete_folder_link"), selectedFolder.Path); + string msg = string.Format(woxAPI.GetTranslation("wox_plugin_folder_delete_folder_link"), selectedFolder.Path); if (MessageBox.Show(msg, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.Yes) { @@ -37,7 +37,7 @@ namespace Wox.Plugin.Folder } else { - string warning = context.API.GetTranslation("wox_plugin_folder_select_folder_link_warning"); + string warning = woxAPI.GetTranslation("wox_plugin_folder_select_folder_link_warning"); MessageBox.Show(warning); } } @@ -61,7 +61,7 @@ namespace Wox.Plugin.Folder } else { - string warning = context.API.GetTranslation("wox_plugin_folder_select_folder_link_warning"); + string warning = woxAPI.GetTranslation("wox_plugin_folder_select_folder_link_warning"); MessageBox.Show(warning); } } diff --git a/Plugins/Wox.Plugin.Folder/Images/copy.png b/Plugins/Wox.Plugin.Folder/Images/copy.png new file mode 100644 index 000000000..91f0647e7 Binary files /dev/null and b/Plugins/Wox.Plugin.Folder/Images/copy.png differ diff --git a/Plugins/Wox.Plugin.Folder/Languages/en.xaml b/Plugins/Wox.Plugin.Folder/Languages/en.xaml index f9bbd6b3b..cee4e4d80 100644 --- a/Plugins/Wox.Plugin.Folder/Languages/en.xaml +++ b/Plugins/Wox.Plugin.Folder/Languages/en.xaml @@ -8,5 +8,8 @@ Folder Path Please select a folder link Are your sure to delete {0}? - + + Folder + Open favorite folder from wox directorily + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Folder/Languages/zh-cn.xaml b/Plugins/Wox.Plugin.Folder/Languages/zh-cn.xaml index 559b9f490..01b435ec4 100644 --- a/Plugins/Wox.Plugin.Folder/Languages/zh-cn.xaml +++ b/Plugins/Wox.Plugin.Folder/Languages/zh-cn.xaml @@ -1,12 +1,15 @@ - - - 删除 - 编辑 - 添加 - 文件夹路径 - 请选择一个文件夹 - 你确定要删除{0}吗? - + + + 删除 + 编辑 + 添加 + 文件夹路径 + 请选择一个文件夹 + 你确定要删除{0}吗? + + 文件夹 + 在Wox中直接打开收藏的文件夹 + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Folder/Languages/zh-tw.xaml b/Plugins/Wox.Plugin.Folder/Languages/zh-tw.xaml index 27ac71914..c2f6cd8ed 100644 --- a/Plugins/Wox.Plugin.Folder/Languages/zh-tw.xaml +++ b/Plugins/Wox.Plugin.Folder/Languages/zh-tw.xaml @@ -1,12 +1,15 @@ - - - 刪除 - 編輯 - 添加 - 文件夾路徑 - 請選擇一個文件夾 - 你確認要刪除{0}嗎? - + + + 刪除 + 編輯 + 添加 + 文件夾路徑 + 請選擇一個文件夾 + 你確認要刪除{0}嗎? + + 文件夾 + 在Wox中直接打開收藏的文件夾 + \ 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 5551d5c2a..162c2a12b 100644 --- a/Plugins/Wox.Plugin.Folder/Wox.Plugin.Folder.csproj +++ b/Plugins/Wox.Plugin.Folder/Wox.Plugin.Folder.csproj @@ -1,120 +1,123 @@ - - - - - Debug - AnyCPU - {787B8AA6-CA93-4C84-96FE-DF31110AD1C4} - Library - Properties - Wox.Plugin.Folder - Wox.Plugin.Folder - v3.5 - 512 - ..\..\ - true - - - - true - full - false - ..\..\Output\Debug\Plugins\Wox.Plugin.Folder\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Output\Release\Plugins\Wox.Plugin.Folder\ - TRACE - prompt - 4 - false - - - - ..\..\packages\Newtonsoft.Json.6.0.8\lib\net35\Newtonsoft.Json.dll - True - - - - - - - - - - - - - - - - - - FolderPluginSettings.xaml - - - - - - - - PreserveNewest - - - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - PreserveNewest - - - MSBuild:Compile - Designer - PreserveNewest - - - MSBuild:Compile - Designer - PreserveNewest - - - - - {4fd29318-a8ab-4d8f-aa47-60bc241b8da3} - Wox.Infrastructure - - - {8451ecdd-2ea4-4966-bb0a-7bbc40138e80} - Wox.Plugin - - - - - PreserveNewest - - - - - - - 这台计算机上缺少此项目引用的 NuGet 程序包。启用“NuGet 程序包还原”可下载这些程序包。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 - - - - + + + + + Debug + AnyCPU + {787B8AA6-CA93-4C84-96FE-DF31110AD1C4} + Library + Properties + Wox.Plugin.Folder + Wox.Plugin.Folder + v3.5 + 512 + ..\..\ + true + + + + true + full + false + ..\..\Output\Debug\Plugins\Wox.Plugin.Folder\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + ..\..\Output\Release\Plugins\Wox.Plugin.Folder\ + TRACE + prompt + 4 + false + + + + ..\..\packages\Newtonsoft.Json.6.0.8\lib\net35\Newtonsoft.Json.dll + True + + + + + + + + + + + + + + + + + + FolderPluginSettings.xaml + + + + + + + + PreserveNewest + + + + + MSBuild:Compile + Designer + + + PreserveNewest + + + MSBuild:Compile + Designer + PreserveNewest + + + MSBuild:Compile + Designer + PreserveNewest + + + MSBuild:Compile + Designer + PreserveNewest + + + + + {4fd29318-a8ab-4d8f-aa47-60bc241b8da3} + Wox.Infrastructure + + + {8451ecdd-2ea4-4966-bb0a-7bbc40138e80} + Wox.Plugin + + + + + PreserveNewest + + + + + + + 这台计算机上缺少此项目引用的 NuGet 程序包。启用“NuGet 程序包还原”可下载这些程序包。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 + + + + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Folder/plugin.json b/Plugins/Wox.Plugin.Folder/plugin.json index d9129e4d3..cd08d56e8 100644 --- a/Plugins/Wox.Plugin.Folder/plugin.json +++ b/Plugins/Wox.Plugin.Folder/plugin.json @@ -2,7 +2,7 @@ "ID":"B4D3B69656E14D44865C8D818EAE47C4", "ActionKeyword":"*", "Name":"Folder", - "Description":"Provide opening folder from wox directorily. You can add your favorite folders.", + "Description":"Open favorite folder from wox directorily", "Author":"qianlifeng", "Version":"1.0.0", "Language":"csharp", diff --git a/Plugins/Wox.Plugin.PluginIndicator/Languages/en.xaml b/Plugins/Wox.Plugin.PluginIndicator/Languages/en.xaml new file mode 100644 index 000000000..cd685365e --- /dev/null +++ b/Plugins/Wox.Plugin.PluginIndicator/Languages/en.xaml @@ -0,0 +1,8 @@ + + + Plugin Indicator + Provide plugin actionword suggestion + + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.PluginIndicator/Languages/zh-cn.xaml b/Plugins/Wox.Plugin.PluginIndicator/Languages/zh-cn.xaml new file mode 100644 index 000000000..e91f7923e --- /dev/null +++ b/Plugins/Wox.Plugin.PluginIndicator/Languages/zh-cn.xaml @@ -0,0 +1,8 @@ + + + 插件关键词提示 + 提供插件关键词搜索提示 + + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.PluginIndicator/Languages/zh-tw.xaml b/Plugins/Wox.Plugin.PluginIndicator/Languages/zh-tw.xaml new file mode 100644 index 000000000..753204816 --- /dev/null +++ b/Plugins/Wox.Plugin.PluginIndicator/Languages/zh-tw.xaml @@ -0,0 +1,8 @@ + + + 插件關鍵詞提示 + 提供插件關鍵詞搜索提示 + + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.PluginIndicator/PluginIndicator.cs b/Plugins/Wox.Plugin.PluginIndicator/PluginIndicator.cs index 645401339..fe0a2a8f4 100644 --- a/Plugins/Wox.Plugin.PluginIndicator/PluginIndicator.cs +++ b/Plugins/Wox.Plugin.PluginIndicator/PluginIndicator.cs @@ -1,11 +1,13 @@ using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Reflection; using Wox.Core.Plugin; using Wox.Core.UserSettings; namespace Wox.Plugin.PluginIndicator { - public class PluginIndicator : IPlugin + public class PluginIndicator : IPlugin,IPluginI18n { private List allPlugins = new List(); private PluginInitContext context; @@ -15,7 +17,7 @@ namespace Wox.Plugin.PluginIndicator List results = new List(); if (allPlugins.Count == 0) { - allPlugins = context.API.GetAllPlugins().Where(o => !PluginManager.IsSystemPlugin(o.Metadata)).ToList(); + allPlugins = context.API.GetAllPlugins().Where(o => !PluginManager.IsGenericPlugin(o.Metadata)).ToList(); } foreach (PluginMetadata metadata in allPlugins.Select(o => o.Metadata)) @@ -45,19 +47,6 @@ namespace Wox.Plugin.PluginIndicator } } - //results.AddRange(UserSettingStorage.Instance.WebSearches.Where(o => o.ActionWord.StartsWith(query.Search) && o.Enabled).Select(n => new Result() - //{ - // Title = n.ActionWord, - // SubTitle = string.Format("Activate {0} web search", n.ActionWord), - // Score = 100, - // IcoPath = "Images/work.png", - // Action = (c) => - // { - // context.API.ChangeQuery(n.ActionWord + " "); - // return false; - // } - //})); - return results; } @@ -65,5 +54,20 @@ namespace Wox.Plugin.PluginIndicator { this.context = context; } + + public string GetLanguagesFolder() + { + return Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Languages"); + } + + public string GetTranslatedPluginTitle() + { + return context.API.GetTranslation("wox_plugin_pluginindicator_plugin_name"); + } + + public string GetTranslatedPluginDescription() + { + return context.API.GetTranslation("wox_plugin_pluginindicator_plugin_description"); + } } } diff --git a/Plugins/Wox.Plugin.PluginIndicator/Wox.Plugin.PluginIndicator.csproj b/Plugins/Wox.Plugin.PluginIndicator/Wox.Plugin.PluginIndicator.csproj index 60d9fcf3d..b0b463c00 100644 --- a/Plugins/Wox.Plugin.PluginIndicator/Wox.Plugin.PluginIndicator.csproj +++ b/Plugins/Wox.Plugin.PluginIndicator/Wox.Plugin.PluginIndicator.csproj @@ -33,6 +33,7 @@ false + @@ -68,6 +69,27 @@ PreserveNewest + + + MSBuild:Compile + Designer + PreserveNewest + + + + + MSBuild:Compile + Designer + PreserveNewest + + + + + MSBuild:Compile + Designer + PreserveNewest + + + --> \ No newline at end of file diff --git a/Plugins/Wox.Plugin.PluginManagement/plugin.json b/Plugins/Wox.Plugin.PluginManagement/plugin.json index 173598b66..f07dcf479 100644 --- a/Plugins/Wox.Plugin.PluginManagement/plugin.json +++ b/Plugins/Wox.Plugin.PluginManagement/plugin.json @@ -2,7 +2,7 @@ "ID":"D2D2C23B084D422DB66FE0C79D6C2A6A", "ActionKeyword":"wpm", "Name":"Wox Plugin Management", - "Description":"Manage your plugins in Wox", + "Description":"Install/Remove/Update wox plugins", "Author":"qianlifeng", "Version":"1.0", "Language":"csharp", diff --git a/Plugins/Wox.Plugin.Program/FileChangeWatcher.cs b/Plugins/Wox.Plugin.Program/FileChangeWatcher.cs index 303970fd3..c6f6ec546 100644 --- a/Plugins/Wox.Plugin.Program/FileChangeWatcher.cs +++ b/Plugins/Wox.Plugin.Program/FileChangeWatcher.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.IO; using System.Threading; +using Wox.Infrastructure; namespace Wox.Plugin.Program { @@ -15,7 +16,7 @@ namespace Wox.Plugin.Program if (watchedPath.Contains(path)) return; if (!Directory.Exists(path)) { - Debug.WriteLine(string.Format("FileChangeWatcher: {0} doesn't exist", path),"WoxDebug"); + DebugHelper.WriteLine(string.Format("FileChangeWatcher: {0} doesn't exist", path)); return; } diff --git a/Plugins/Wox.Plugin.Program/Images/folder.png b/Plugins/Wox.Plugin.Program/Images/folder.png new file mode 100644 index 000000000..330cb2e4b Binary files /dev/null and b/Plugins/Wox.Plugin.Program/Images/folder.png differ diff --git a/Plugins/Wox.Plugin.Program/Languages/en.xaml b/Plugins/Wox.Plugin.Program/Languages/en.xaml index 3e9a4f1b6..84a3e064f 100644 --- a/Plugins/Wox.Plugin.Program/Languages/en.xaml +++ b/Plugins/Wox.Plugin.Program/Languages/en.xaml @@ -19,5 +19,11 @@ (Each suffix should split by ;) Sucessfully update file suffixes File suffixes can't be empty - + + Run As Administrator + Open containing folder + + Program + Search programs in Wox + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Program/Languages/zh-cn.xaml b/Plugins/Wox.Plugin.Program/Languages/zh-cn.xaml index 388734467..39e5f3b32 100644 --- a/Plugins/Wox.Plugin.Program/Languages/zh-cn.xaml +++ b/Plugins/Wox.Plugin.Program/Languages/zh-cn.xaml @@ -1,24 +1,30 @@ - - - - 删除 - 编辑 - 增加 - 位置 - 索引文件后缀 - 重新索引 - 索引中 - - - 请先选择一项 - 你确定要删除{0}吗? - - 更新 - Wox仅索引下列后缀的文件: - (每个后缀以英文状态下的分号分隔) - 成功更新索引文件后缀 - 文件后缀不能为空 - + + + + 删除 + 编辑 + 增加 + 位置 + 索引文件后缀 + 重新索引 + 索引中 + + + 请先选择一项 + 你确定要删除{0}吗? + + 更新 + Wox仅索引下列后缀的文件: + (每个后缀以英文状态下的分号分隔) + 成功更新索引文件后缀 + 文件后缀不能为空 + + 以管理员身份运行 + 打开所属文件夹 + + 程序 + 在Wox中搜索程序 + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Program/Languages/zh-tw.xaml b/Plugins/Wox.Plugin.Program/Languages/zh-tw.xaml index d56fc2d4c..93cf54cb9 100644 --- a/Plugins/Wox.Plugin.Program/Languages/zh-tw.xaml +++ b/Plugins/Wox.Plugin.Program/Languages/zh-tw.xaml @@ -1,24 +1,29 @@ - - - - 刪除 - 編輯 - 增加 - 位置 - 索引文件後綴 - 重新索引 - 索引中 - - - 請先選擇一項 - 你確定要刪除{0}嗎? - - 更新 - Wox僅索引下列後綴的文件: - (每個後綴以英文狀態下的分號分隔) - 成功更新索引文件後綴 - 文件後綴不能為空 - + + + + 刪除 + 編輯 + 增加 + 位置 + 索引文件後綴 + 重新索引 + 索引中 + + + 請先選擇一項 + 你確定要刪除{0}嗎? + + 更新 + Wox僅索引下列後綴的文件: + (每個後綴以英文狀態下的分號分隔) + 成功更新索引文件後綴 + 文件後綴不能為空 + + 以管理員身份運行 + 打開所屬文件夾 + + 程序 + 在Wox中搜索程序 \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Program/ProgramSources/FileSystemProgramSource.cs b/Plugins/Wox.Plugin.Program/ProgramSources/FileSystemProgramSource.cs index cb62dc831..f4997615e 100644 --- a/Plugins/Wox.Plugin.Program/ProgramSources/FileSystemProgramSource.cs +++ b/Plugins/Wox.Plugin.Program/ProgramSources/FileSystemProgramSource.cs @@ -16,7 +16,8 @@ namespace Wox.Plugin.Program.ProgramSources this.baseDirectory = baseDirectory; } - public FileSystemProgramSource(ProgramSource source):this(source.Location) + public FileSystemProgramSource(ProgramSource source) + : this(source.Location) { this.BonusPoints = source.BonusPoints; } @@ -50,17 +51,9 @@ namespace Wox.Plugin.Program.ProgramSources GetAppFromDirectory(subDirectory, list); } } - catch (UnauthorizedAccessException e) + catch (Exception e) { - Log.Warn(string.Format("Can't access to directory {0}", path)); - } - catch (DirectoryNotFoundException e) - { - Log.Warn(string.Format("Directory {0} doesn't exist", path)); - } - catch (PathTooLongException e) - { - Log.Warn(string.Format("File path too long: {0}", e.Message)); + Log.Warn(string.Format("GetAppFromDirectory failed: {0} - {1}", path, e.Message)); } } diff --git a/Plugins/Wox.Plugin.Program/Programs.cs b/Plugins/Wox.Plugin.Program/Programs.cs index 7028848b8..fad46efa3 100644 --- a/Plugins/Wox.Plugin.Program/Programs.cs +++ b/Plugins/Wox.Plugin.Program/Programs.cs @@ -9,10 +9,11 @@ using System.Windows; using Wox.Infrastructure; using Wox.Plugin.Program.ProgramSources; using IWshRuntimeLibrary; +using Wox.Plugin.Features; namespace Wox.Plugin.Program { - public class Programs : ISettingProvider, IPlugin, IPluginI18n + public class Programs : ISettingProvider, IPlugin, IPluginI18n, IContextMenu { private static object lockObject = new object(); private static List programs = new List(); @@ -38,46 +39,12 @@ namespace Wox.Plugin.Program SubTitle = c.ExecutePath, IcoPath = c.IcoPath, Score = c.Score, + ContextData = c, Action = (e) => { context.API.HideApp(); context.API.ShellRun(c.ExecutePath); return true; - }, - ContextMenu = new List() - { - new Result() - { - Title = "Run As Administrator", - Action = _ => - { - context.API.HideApp(); - context.API.ShellRun(c.ExecutePath,true); - return true; - }, - IcoPath = "Images/cmd.png" - }, - new Result() - { - Title = "Open Containing Folder", - Action = _ => - { - context.API.HideApp(); - String Path=c.ExecutePath; - //check if shortcut - if (Path.EndsWith(".lnk")) - { - //get location of shortcut - Path = ResolveShortcut(Path); - } - //get parent folder - Path=System.IO.Directory.GetParent(Path).FullName; - //open the folder - context.API.ShellRun("explorer.exe "+Path,false); - return true; - }, - IcoPath = "Images/folder.png" - } } }).ToList(); } @@ -85,8 +52,8 @@ namespace Wox.Plugin.Program static string ResolveShortcut(string filePath) { // IWshRuntimeLibrary is in the COM library "Windows Script Host Object Model" - IWshRuntimeLibrary.WshShell shell = new IWshRuntimeLibrary.WshShell(); - IWshRuntimeLibrary.IWshShortcut shortcut = (IWshRuntimeLibrary.IWshShortcut)shell.CreateShortcut(filePath); + WshShell shell = new WshShell(); + IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut(filePath); return shortcut.TargetPath; } @@ -103,17 +70,24 @@ namespace Wox.Plugin.Program public void Init(PluginInitContext context) { this.context = context; + this.context.API.ResultItemDropEvent += API_ResultItemDropEvent; using (new Timeit("Preload programs")) { programs = ProgramCacheStorage.Instance.Programs; } - Debug.WriteLine(string.Format("Preload {0} programs from cache", programs.Count), "Wox"); + DebugHelper.WriteLine(string.Format("Preload {0} programs from cache", programs.Count)); using (new Timeit("Program Index")) { IndexPrograms(); } } + void API_ResultItemDropEvent(Result result, IDataObject dropObject, DragEventArgs e) + { + + e.Handled = true; + } + public static void IndexPrograms() { lock (lockObject) @@ -216,5 +190,55 @@ namespace Wox.Plugin.Program { return Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Languages"); } + public string GetTranslatedPluginTitle() + { + return context.API.GetTranslation("wox_plugin_program_plugin_name"); + } + + public string GetTranslatedPluginDescription() + { + return context.API.GetTranslation("wox_plugin_program_plugin_description"); + } + + public List LoadContextMenus(Result selectedResult) + { + Program p = selectedResult.ContextData as Program; + List contextMenus = new List() + { + new Result() + { + Title = context.API.GetTranslation("wox_plugin_program_run_as_administrator"), + Action = _ => + { + context.API.HideApp(); + context.API.ShellRun(p.ExecutePath, true); + return true; + }, + IcoPath = "Images/cmd.png" + }, + new Result() + { + Title = context.API.GetTranslation("wox_plugin_program_open_containing_folder"), + Action = _ => + { + context.API.HideApp(); + String Path = p.ExecutePath; + //check if shortcut + if (Path.EndsWith(".lnk")) + { + //get location of shortcut + Path = ResolveShortcut(Path); + } + //get parent folder + Path = Directory.GetParent(Path).FullName; + //open the folder + context.API.ShellRun("explorer.exe " + Path, false); + return true; + }, + IcoPath = "Images/folder.png" + } + }; + return contextMenus; + } } -} +} \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Program/Wox.Plugin.Program.csproj b/Plugins/Wox.Plugin.Program/Wox.Plugin.Program.csproj index a517e1407..0f357736f 100644 --- a/Plugins/Wox.Plugin.Program/Wox.Plugin.Program.csproj +++ b/Plugins/Wox.Plugin.Program/Wox.Plugin.Program.csproj @@ -1,150 +1,153 @@ - - - - - Debug - AnyCPU - {FDB3555B-58EF-4AE6-B5F1-904719637AB4} - Library - Properties - Wox.Plugin.Program - Wox.Plugin.Program - v3.5 - 512 - ..\..\ - true - - - - true - full - false - ..\..\Output\Debug\Plugins\Wox.Plugin.Program\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Output\Release\Plugins\Wox.Plugin.Program\ - TRACE - prompt - 4 - false - - - - False - ..\..\packages\Newtonsoft.Json.6.0.8\lib\net35\Newtonsoft.Json.dll - - - - - - - - - - - - - - - - - - - - - ProgramSetting.xaml - - - - - - - - - ProgramSuffixes.xaml - - - - - - - - PreserveNewest - - - - - PreserveNewest - - - PreserveNewest - - - MSBuild:Compile - Designer - PreserveNewest - - - - - MSBuild:Compile - Designer - PreserveNewest - - - MSBuild:Compile - Designer - PreserveNewest - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - - - {4fd29318-a8ab-4d8f-aa47-60bc241b8da3} - Wox.Infrastructure - - - {8451ecdd-2ea4-4966-bb0a-7bbc40138e80} - Wox.Plugin - - - - - {F935DC20-1CF0-11D0-ADB9-00C04FD58A0B} - 1 - 0 - 0 - tlbimp - False - True - - - - - - - 这台计算机上缺少此项目引用的 NuGet 程序包。启用“NuGet 程序包还原”可下载这些程序包。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 - - - + + + + + Debug + AnyCPU + {FDB3555B-58EF-4AE6-B5F1-904719637AB4} + Library + Properties + Wox.Plugin.Program + Wox.Plugin.Program + v3.5 + 512 + ..\..\ + true + + + + true + full + false + ..\..\Output\Debug\Plugins\Wox.Plugin.Program\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + ..\..\Output\Release\Plugins\Wox.Plugin.Program\ + TRACE + prompt + 4 + false + + + + False + ..\..\packages\Newtonsoft.Json.6.0.8\lib\net35\Newtonsoft.Json.dll + + + + + + + + + + + + + + + + + + + + + ProgramSetting.xaml + + + + + + + + + ProgramSuffixes.xaml + + + + + + + + PreserveNewest + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + MSBuild:Compile + Designer + PreserveNewest + + + + + MSBuild:Compile + Designer + PreserveNewest + + + MSBuild:Compile + Designer + PreserveNewest + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + + + {4fd29318-a8ab-4d8f-aa47-60bc241b8da3} + Wox.Infrastructure + + + {8451ecdd-2ea4-4966-bb0a-7bbc40138e80} + Wox.Plugin + + + + + {F935DC20-1CF0-11D0-ADB9-00C04FD58A0B} + 1 + 0 + 0 + tlbimp + False + True + + + + + + + 这台计算机上缺少此项目引用的 NuGet 程序包。启用“NuGet 程序包还原”可下载这些程序包。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 + + + + --> \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Program/plugin.json b/Plugins/Wox.Plugin.Program/plugin.json index 9185aa7fe..9f374dded 100644 --- a/Plugins/Wox.Plugin.Program/plugin.json +++ b/Plugins/Wox.Plugin.Program/plugin.json @@ -2,7 +2,7 @@ "ID":"791FC278BA414111B8D1886DFE447410", "ActionKeyword":"*", "Name":"Program", - "Description":"Provide programs search for Wox.", + "Description":"Search programs in Wox", "Author":"qianlifeng", "Version":"1.0.0", "Language":"csharp", diff --git a/Plugins/Wox.Plugin.QueryHistory/QueryHistory.cs b/Plugins/Wox.Plugin.QueryHistory/QueryHistory.cs index 7f74a9e0b..838e08bfe 100644 --- a/Plugins/Wox.Plugin.QueryHistory/QueryHistory.cs +++ b/Plugins/Wox.Plugin.QueryHistory/QueryHistory.cs @@ -34,8 +34,6 @@ namespace Wox.Plugin.QueryHistory public void Init(PluginInitContext context) { this.context = context; - context.API.AfterWoxQueryEvent += API_AfterWoxQueryEvent; - context.API.BeforeWoxQueryEvent += API_BeforeWoxQueryEvent; } void API_BeforeWoxQueryEvent(WoxQueryEventArgs e) diff --git a/Plugins/Wox.Plugin.Sys/Languages/en.xaml b/Plugins/Wox.Plugin.Sys/Languages/en.xaml index 280d5ff50..a80f951b7 100644 --- a/Plugins/Wox.Plugin.Sys/Languages/en.xaml +++ b/Plugins/Wox.Plugin.Sys/Languages/en.xaml @@ -11,5 +11,8 @@ Close Wox Restart Wox Tweak this app - + + System Commands + Provide System related commands. e.g. shutdown,lock,setting etc. + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Sys/Languages/zh-cn.xaml b/Plugins/Wox.Plugin.Sys/Languages/zh-cn.xaml index 5abec64ce..ef7d49526 100644 --- a/Plugins/Wox.Plugin.Sys/Languages/zh-cn.xaml +++ b/Plugins/Wox.Plugin.Sys/Languages/zh-cn.xaml @@ -1,15 +1,18 @@ - - - 命令 - 描述 - - 关闭电脑 - 注销 - 锁定这台电脑 - 退出Wox - 重启Wox - 设置 - + + + 命令 + 描述 + + 关闭电脑 + 注销 + 锁定这台电脑 + 退出Wox + 重启Wox + 设置 + + 系统命令 + 系统系统相关的命令。例如,关机,锁定,设置等 + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Sys/Languages/zh-tw.xaml b/Plugins/Wox.Plugin.Sys/Languages/zh-tw.xaml index e393f0d8b..55abdbf43 100644 --- a/Plugins/Wox.Plugin.Sys/Languages/zh-tw.xaml +++ b/Plugins/Wox.Plugin.Sys/Languages/zh-tw.xaml @@ -1,15 +1,18 @@ - - - 命令 - 描述 - - 關閉電腦 - 註銷 - 鎖定這臺電腦 - 退出Wox - 重啟Wox - 設置 - + + + 命令 + 描述 + + 關閉電腦 + 註銷 + 鎖定這臺電腦 + 退出Wox + 重啟Wox + 設置 + + 系統命令 + 系統系統相關的命令。例如,關機,鎖定,設置等 + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Sys/Sys.cs b/Plugins/Wox.Plugin.Sys/Sys.cs index 80132b29e..1617772b0 100644 --- a/Plugins/Wox.Plugin.Sys/Sys.cs +++ b/Plugins/Wox.Plugin.Sys/Sys.cs @@ -4,6 +4,7 @@ using System.IO; using System.Reflection; using System.Runtime.InteropServices; using System.Windows.Forms; +using Wox.Infrastructure; namespace Wox.Plugin.Sys { @@ -42,7 +43,7 @@ namespace Wox.Plugin.Sys List results = new List(); foreach (Result availableResult in availableResults) { - if (availableResult.Title.ToLower().StartsWith(query.Search.ToLower())) + if (StringMatcher.IsMatch(availableResult.Title, query.Search) || StringMatcher.IsMatch(availableResult.SubTitle, query.Search)) { results.Add(availableResult); } @@ -142,5 +143,15 @@ namespace Wox.Plugin.Sys return Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Languages"); } - } + + public string GetTranslatedPluginTitle() + { + return context.API.GetTranslation("wox_plugin_sys_plugin_name"); + } + + public string GetTranslatedPluginDescription() + { + return context.API.GetTranslation("wox_plugin_sys_plugin_description"); + } + } } diff --git a/Plugins/Wox.Plugin.Url/Images/url.png b/Plugins/Wox.Plugin.Url/Images/url.png index 3b86b637d..90634f7a0 100644 Binary files a/Plugins/Wox.Plugin.Url/Images/url.png and b/Plugins/Wox.Plugin.Url/Images/url.png differ diff --git a/Plugins/Wox.Plugin.Url/Languages/en.xaml b/Plugins/Wox.Plugin.Url/Languages/en.xaml new file mode 100644 index 000000000..eec48e692 --- /dev/null +++ b/Plugins/Wox.Plugin.Url/Languages/en.xaml @@ -0,0 +1,11 @@ + + + Open url:{0} + Can't open url:{0} + + URL + Open the typed URL from Wox + + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Url/Languages/zh-cn.xaml b/Plugins/Wox.Plugin.Url/Languages/zh-cn.xaml new file mode 100644 index 000000000..4cab4182c --- /dev/null +++ b/Plugins/Wox.Plugin.Url/Languages/zh-cn.xaml @@ -0,0 +1,11 @@ + + + 打开链接:{0} + 无法打开链接:{0} + + URL + 从Wox打开链接 + + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Url/Languages/zh-tw.xaml b/Plugins/Wox.Plugin.Url/Languages/zh-tw.xaml new file mode 100644 index 000000000..e4d45de1d --- /dev/null +++ b/Plugins/Wox.Plugin.Url/Languages/zh-tw.xaml @@ -0,0 +1,11 @@ + + + 打開鏈接:{0} + 無法打開鏈接:{0} + + URL + 從Wox打開鏈接 + + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Url/UrlPlugin.cs b/Plugins/Wox.Plugin.Url/UrlPlugin.cs index b769a720b..ae871d2b2 100644 --- a/Plugins/Wox.Plugin.Url/UrlPlugin.cs +++ b/Plugins/Wox.Plugin.Url/UrlPlugin.cs @@ -1,15 +1,17 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; +using System.Reflection; using System.Text.RegularExpressions; using System.Windows; namespace Wox.Plugin.Url { - public class UrlPlugin : IPlugin + public class UrlPlugin : IPlugin, IPluginI18n { //based on https://gist.github.com/dperini/729294 - private const string urlPattern ="^" + + private const string urlPattern = "^" + // protocol identifier "(?:(?:https?|ftp)://|)" + // user:pass authentication @@ -42,6 +44,7 @@ namespace Wox.Plugin.Url "(?:/\\S*)?" + "$"; Regex reg = new Regex(urlPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase); + private PluginInitContext context; public List Query(Query query) { @@ -53,7 +56,7 @@ namespace Wox.Plugin.Url new Result { Title = raw, - SubTitle = "Open " + raw, + SubTitle = string.Format(context.API.GetTranslation("wox_plugin_url_open_url"),raw), IcoPath = "Images/url.png", Score = 8, Action = _ => @@ -69,7 +72,7 @@ namespace Wox.Plugin.Url } catch(Exception ex) { - MessageBox.Show(ex.Message, "Could not open " + raw); + context.API.ShowMsg(string.Format(context.API.GetTranslation("wox_plugin_url_canot_open_url"), raw)); return false; } } @@ -98,7 +101,22 @@ namespace Wox.Plugin.Url public void Init(PluginInitContext context) { + this.context = context; + } + public string GetLanguagesFolder() + { + return Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Languages"); + } + + public string GetTranslatedPluginTitle() + { + return context.API.GetTranslation("wox_plugin_url_plugin_name"); + } + + public string GetTranslatedPluginDescription() + { + return context.API.GetTranslation("wox_plugin_url_plugin_description"); } } } \ No newline at end of file diff --git a/Plugins/Wox.Plugin.Url/Wox.Plugin.Url.csproj b/Plugins/Wox.Plugin.Url/Wox.Plugin.Url.csproj index a35d32f5e..aabcb4525 100644 --- a/Plugins/Wox.Plugin.Url/Wox.Plugin.Url.csproj +++ b/Plugins/Wox.Plugin.Url/Wox.Plugin.Url.csproj @@ -64,6 +64,27 @@ PreserveNewest + + + MSBuild:Compile + Designer + PreserveNewest + + + + + MSBuild:Compile + Designer + PreserveNewest + + + + + MSBuild:Compile + Designer + PreserveNewest + + - 标题 - 启用 - 图标 - 选择图标 - 取消 - 非法的网页搜索 - 请输入标题 - 请输入触发关键字 - 请输入URL - 触发关键字已经存在,请选择一个新的关键字 - 操作成功 - + + + 删除 + 编辑 + 添加 + 触发关键字 + URL + 启用搜索建议 + 请选择一项 + 你确定要删除 {0} 吗? + + + + 标题 + 启用 + 图标 + 选择图标 + 取消 + 非法的网页搜索 + 请输入标题 + 请输入触发关键字 + 请输入URL + 触发关键字已经存在,请选择一个新的关键字 + 操作成功 + + 网页搜索 + 提供网页搜索能力 + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.WebSearch/Languages/zh-tw.xaml b/Plugins/Wox.Plugin.WebSearch/Languages/zh-tw.xaml index def9146a8..ec1f620ab 100644 --- a/Plugins/Wox.Plugin.WebSearch/Languages/zh-tw.xaml +++ b/Plugins/Wox.Plugin.WebSearch/Languages/zh-tw.xaml @@ -1,28 +1,31 @@ - - - 刪除 - 編輯 - 添加 - 觸發關鍵字 - URL - 啟用搜索建議 - 請選擇一項 - 你確定要刪除 {0} 嗎? - - - - 標題 - 啟用 - 圖標 - 選擇圖標 - 取消 - 非法的網頁搜索 - 請輸入標題 - 請輸入觸發關鍵字 - 請輸入URL - 觸發關鍵字已經存在,請選擇一個新的關鍵字 - 操作成功 - + + + 刪除 + 編輯 + 添加 + 觸發關鍵字 + URL + 啟用搜索建議 + 請選擇一項 + 你確定要刪除 {0} 嗎? + + + + 標題 + 啟用 + 圖標 + 選擇圖標 + 取消 + 非法的網頁搜索 + 請輸入標題 + 請輸入觸發關鍵字 + 請輸入URL + 觸發關鍵字已經存在,請選擇一個新的關鍵字 + 操作成功 + + 網頁搜索 + 提供網頁搜索能力 + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.WebSearch/WebSearchPlugin.cs b/Plugins/Wox.Plugin.WebSearch/WebQueryPlugin.cs similarity index 84% rename from Plugins/Wox.Plugin.WebSearch/WebSearchPlugin.cs rename to Plugins/Wox.Plugin.WebSearch/WebQueryPlugin.cs index 8a2a43011..6399a08f1 100644 --- a/Plugins/Wox.Plugin.WebSearch/WebSearchPlugin.cs +++ b/Plugins/Wox.Plugin.WebSearch/WebQueryPlugin.cs @@ -5,17 +5,22 @@ using System.IO; using System.Linq; using System.Reflection; using Wox.Core.UserSettings; +using Wox.Plugin.Features; using Wox.Plugin.WebSearch.SuggestionSources; namespace Wox.Plugin.WebSearch { - public class WebSearchPlugin : IPlugin, ISettingProvider, IPluginI18n, IInstantSearch + public class WebSearchPlugin : IPlugin, ISettingProvider, IPluginI18n, IInstantQuery, IExclusiveQuery { private PluginInitContext context; public List Query(Query query) { List results = new List(); + if (!query.Search.Contains(' ')) + { + return results; + } WebSearch webSearch = WebSearchStorage.Instance.WebSearches.FirstOrDefault(o => o.ActionWord == query.FirstSearch.Trim() && o.Enabled); @@ -98,15 +103,29 @@ namespace Wox.Plugin.WebSearch return Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Languages"); } - public bool IsInstantSearch(string query) + public string GetTranslatedPluginTitle() + { + return context.API.GetTranslation("wox_plugin_websearch_plugin_name"); + } + + public string GetTranslatedPluginDescription() + { + return context.API.GetTranslation("wox_plugin_websearch_plugin_description"); + } + + public bool IsInstantQuery(string query) { var strings = query.Split(' '); if (strings.Length > 1) { - return WebSearchStorage.Instance.EnableWebSearchSuggestion && - WebSearchStorage.Instance.WebSearches.Exists(o => o.ActionWord == strings[0] && o.Enabled); + return WebSearchStorage.Instance.WebSearches.Exists(o => o.ActionWord == strings[0] && o.Enabled); } return false; } + + public bool IsExclusiveQuery(Query query) + { + return IsInstantQuery(query.RawQuery); + } } } diff --git a/Plugins/Wox.Plugin.WebSearch/Wox.Plugin.WebSearch.csproj b/Plugins/Wox.Plugin.WebSearch/Wox.Plugin.WebSearch.csproj index 8c84b7b91..90a2c3dcc 100644 --- a/Plugins/Wox.Plugin.WebSearch/Wox.Plugin.WebSearch.csproj +++ b/Plugins/Wox.Plugin.WebSearch/Wox.Plugin.WebSearch.csproj @@ -1,147 +1,150 @@ - - - - - Debug - AnyCPU - {403B57F2-1856-4FC7-8A24-36AB346B763E} - Library - Properties - Wox.Plugin.WebSearch - Wox.Plugin.WebSearch - v3.5 - 512 - ..\..\ - true - - - - true - full - false - ..\..\Output\Debug\Plugins\Wox.Plugin.WebSearch\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Output\Release\Plugins\Wox.Plugin.WebSearch\ - TRACE - prompt - 4 - false - - - - False - ..\..\packages\Newtonsoft.Json.6.0.8\lib\net35\Newtonsoft.Json.dll - - - - - - - - - - - - - - - - - - - - - WebSearchesSetting.xaml - - - - WebSearchSetting.xaml - - - - - - MSBuild:Compile - Designer - PreserveNewest - - - MSBuild:Compile - Designer - PreserveNewest - - - MSBuild:Compile - Designer - PreserveNewest - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - - - - - - {B749F0DB-8E75-47DB-9E5E-265D16D0C0D2} - Wox.Core - - - {4fd29318-a8ab-4d8f-aa47-60bc241b8da3} - Wox.Infrastructure - - - {8451ecdd-2ea4-4966-bb0a-7bbc40138e80} - Wox.Plugin - - - - - - PreserveNewest - - - - - PreserveNewest - - - - - PreserveNewest - - - - - PreserveNewest - - - - - - - 这台计算机上缺少此项目引用的 NuGet 程序包。启用“NuGet 程序包还原”可下载这些程序包。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 - - - + + + + + Debug + AnyCPU + {403B57F2-1856-4FC7-8A24-36AB346B763E} + Library + Properties + Wox.Plugin.WebSearch + Wox.Plugin.WebSearch + v3.5 + 512 + ..\..\ + true + + + + true + full + false + ..\..\Output\Debug\Plugins\Wox.Plugin.WebSearch\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + ..\..\Output\Release\Plugins\Wox.Plugin.WebSearch\ + TRACE + prompt + 4 + false + + + + False + ..\..\packages\Newtonsoft.Json.6.0.8\lib\net35\Newtonsoft.Json.dll + + + + + + + + + + + + + + + + + + + + + WebSearchesSetting.xaml + + + + WebSearchSetting.xaml + + + + + + PreserveNewest + + + MSBuild:Compile + Designer + PreserveNewest + + + MSBuild:Compile + Designer + PreserveNewest + + + MSBuild:Compile + Designer + PreserveNewest + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + + + + + + {B749F0DB-8E75-47DB-9E5E-265D16D0C0D2} + Wox.Core + + + {4fd29318-a8ab-4d8f-aa47-60bc241b8da3} + Wox.Infrastructure + + + {8451ecdd-2ea4-4966-bb0a-7bbc40138e80} + Wox.Plugin + + + + + + PreserveNewest + + + + + PreserveNewest + + + + + PreserveNewest + + + + + PreserveNewest + + + + + + + 这台计算机上缺少此项目引用的 NuGet 程序包。启用“NuGet 程序包还原”可下载这些程序包。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 + + + + --> \ No newline at end of file diff --git a/Plugins/Wox.Plugin.WebSearch/plugin.json b/Plugins/Wox.Plugin.WebSearch/plugin.json index e1bb0fb63..5132ec9e4 100644 --- a/Plugins/Wox.Plugin.WebSearch/plugin.json +++ b/Plugins/Wox.Plugin.WebSearch/plugin.json @@ -2,7 +2,7 @@ "ID":"565B73353DBF4806919830B9202EE3BF", "ActionKeyword":"*", "Name":"Web Searches", - "Description":"Provide the web search ability.", + "Description":"Provide the web search ability", "Author":"qianlifeng", "Version":"1.0.0", "Language":"csharp", diff --git a/Wox.Core/AssemblyHelper.cs b/Wox.Core/AssemblyHelper.cs new file mode 100644 index 000000000..ac972ff55 --- /dev/null +++ b/Wox.Core/AssemblyHelper.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Wox.Core.Plugin; +using Wox.Infrastructure.Logger; +using Wox.Plugin; + +namespace Wox.Core +{ + internal class AssemblyHelper + { + public static List> LoadPluginInterfaces() where T : class + { + List> results = new List>(); + foreach (PluginPair pluginPair in PluginManager.AllPlugins) + { + //need to load types from AllPlugins + //PluginInitContext is only available in this instance + T type = pluginPair.Plugin as T; + if (type != null) + { + results.Add(new KeyValuePair(pluginPair,type)); + } + } + return results; + } + + public static List LoadInterfacesFromAppDomain() where T : class + { + var interfaceObjects = AppDomain.CurrentDomain.GetAssemblies() + .SelectMany(s => s.GetTypes()) + .Where(p => p.IsClass && !p.IsAbstract && p.GetInterfaces().Contains(typeof(T))); + + return interfaceObjects.Select(interfaceObject => (T) Activator.CreateInstance(interfaceObject)).ToList(); + } + } +} diff --git a/Wox.Core/Plugin/JsonRPCPlugin.cs b/Wox.Core/Plugin/JsonRPCPlugin.cs index fd0514af3..877ff10e9 100644 --- a/Wox.Core/Plugin/JsonRPCPlugin.cs +++ b/Wox.Core/Plugin/JsonRPCPlugin.cs @@ -8,6 +8,7 @@ using System.Windows.Forms; using Newtonsoft.Json; using Wox.Infrastructure.Logger; using Wox.Plugin; +using Wox.Core.Exception; namespace Wox.Core.Plugin { @@ -83,7 +84,7 @@ namespace Wox.Core.Plugin private void ExecuteWoxAPI(string method, object[] parameters) { MethodInfo methodInfo = PluginManager.API.GetType().GetMethod(method); - if (methodInfo != null) + if (methodInfo != null) { try { @@ -141,8 +142,7 @@ namespace Wox.Core.Plugin string error = errorReader.ReadToEnd(); if (!string.IsNullOrEmpty(error)) { - //todo: - // ErrorReporting.TryShowErrorMessageBox(error, new WoxJsonRPCException(error)); + throw new WoxJsonRPCException(error); } } } @@ -151,9 +151,9 @@ namespace Wox.Core.Plugin } } } - catch + catch(System.Exception e) { - return null; + throw new WoxJsonRPCException(e.Message); } return null; } diff --git a/Wox.Core/Plugin/PluginConfig.cs b/Wox.Core/Plugin/PluginConfig.cs index 6c96ef777..f47e1dac0 100644 --- a/Wox.Core/Plugin/PluginConfig.cs +++ b/Wox.Core/Plugin/PluginConfig.cs @@ -78,7 +78,6 @@ namespace Wox.Core.Plugin try { metadata = JsonConvert.DeserializeObject(File.ReadAllText(configPath)); - metadata.PluginType = PluginType.User; metadata.PluginDirectory = pluginDirectory; } catch (System.Exception) diff --git a/Wox.Core/Plugin/PluginInstaller.cs b/Wox.Core/Plugin/PluginInstaller.cs index df9939aaf..77577aa9b 100644 --- a/Wox.Core/Plugin/PluginInstaller.cs +++ b/Wox.Core/Plugin/PluginInstaller.cs @@ -112,7 +112,6 @@ namespace Wox.Core.Plugin try { metadata = JsonConvert.DeserializeObject(File.ReadAllText(configPath)); - metadata.PluginType = PluginType.User; metadata.PluginDirectory = pluginDirectory; } catch (System.Exception) diff --git a/Wox.Core/Plugin/PluginManager.cs b/Wox.Core/Plugin/PluginManager.cs index c9d15ec0b..b681463f4 100644 --- a/Wox.Core/Plugin/PluginManager.cs +++ b/Wox.Core/Plugin/PluginManager.cs @@ -1,16 +1,19 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Threading; using Wox.Core.Exception; +using Wox.Core.i18n; using Wox.Core.UI; using Wox.Core.UserSettings; using Wox.Infrastructure; using Wox.Infrastructure.Http; using Wox.Infrastructure.Logger; using Wox.Plugin; +using Wox.Plugin.Features; namespace Wox.Core.Plugin { @@ -21,8 +24,9 @@ namespace Wox.Core.Plugin { public const string ActionKeywordWildcardSign = "*"; private static List pluginMetadatas; - private static List instantSearches = new List(); - + private static List> instantSearches; + private static List> exclusiveSearchPlugins; + private static List> contextMenuPlugins; public static String DebuggerMode { get; private set; } public static IPublicAPI API { get; private set; } @@ -86,19 +90,25 @@ namespace Wox.Core.Plugin PluginPair pair = pluginPair; ThreadPool.QueueUserWorkItem(o => { - using (new Timeit(string.Format("Init {0}", pair.Metadata.Name))) + Stopwatch sw = new Stopwatch(); + sw.Start(); + pair.Plugin.Init(new PluginInitContext() { - pair.Plugin.Init(new PluginInitContext() - { - CurrentPluginMetadata = pair.Metadata, - Proxy = HttpProxy.Instance, - API = API - }); - } + CurrentPluginMetadata = pair.Metadata, + Proxy = HttpProxy.Instance, + API = API + }); + sw.Stop(); + DebugHelper.WriteLine(string.Format("Plugin init:{0} - {1}", pair.Metadata.Name, sw.ElapsedMilliseconds)); + pair.InitTime = sw.ElapsedMilliseconds; + InternationalizationManager.Instance.UpdatePluginMetadataTranslations(pair); }); } - LoadInstantSearches(); + ThreadPool.QueueUserWorkItem(o => + { + LoadInstantSearches(); + }); } public static void InstallPlugin(string path) @@ -110,6 +120,7 @@ namespace Wox.Core.Plugin { if (!string.IsNullOrEmpty(query.RawQuery.Trim())) { + query.Search = IsActionKeywordQuery(query) ? query.RawQuery.Substring(query.RawQuery.IndexOf(' ') + 1) : query.RawQuery; QueryDispatcher.QueryDispatcher.Dispatch(query); } } @@ -122,19 +133,36 @@ namespace Wox.Core.Plugin } } - public static bool IsUserPluginQuery(Query query) + /// + /// Check if a query contains valid action keyword + /// + /// + /// + public static bool IsActionKeywordQuery(Query query) { if (string.IsNullOrEmpty(query.RawQuery)) return false; var strings = query.RawQuery.Split(' '); - if(strings.Length == 1) return false; + if (strings.Length == 1) return false; var actionKeyword = strings[0].Trim(); if (string.IsNullOrEmpty(actionKeyword)) return false; - return plugins.Any(o => o.Metadata.PluginType == PluginType.User && o.Metadata.ActionKeyword == actionKeyword); + PluginPair pair = plugins.FirstOrDefault(o => o.Metadata.ActionKeyword == actionKeyword); + if (pair != null) + { + var customizedPluginConfig = UserSettingStorage.Instance.CustomizedPluginConfigs.FirstOrDefault(o => o.ID == pair.Metadata.ID); + if (customizedPluginConfig != null && customizedPluginConfig.Disabled) + { + return false; + } + + return true; + } + + return false; } - public static bool IsSystemPlugin(PluginMetadata metadata) + public static bool IsGenericPlugin(PluginMetadata metadata) { return metadata.ActionKeyword == ActionKeywordWildcardSign; } @@ -144,42 +172,53 @@ namespace Wox.Core.Plugin DebuggerMode = path; } - public static bool IsInstantSearch(string query) + public static bool IsInstantQuery(string query) { - return LoadInstantSearches().Any(o => o.IsInstantSearch(query)); + return LoadInstantSearches().Any(o => o.Value.IsInstantQuery(query)); } - private static List LoadInstantSearches() + public static bool IsInstantSearchPlugin(PluginMetadata pluginMetadata) { - if (instantSearches.Count > 0) return instantSearches; - List CSharpPluginMetadatas = pluginMetadatas.Where(o => o.Language.ToUpper() == AllowedLanguage.CSharp.ToUpper()).ToList(); + //todo:to improve performance, any instant search plugin that takes long than 200ms will not consider a instant plugin anymore + return pluginMetadata.Language.ToUpper() == AllowedLanguage.CSharp && + LoadInstantSearches().Any(o => o.Key.Metadata.ID == pluginMetadata.ID); + } - foreach (PluginMetadata metadata in CSharpPluginMetadatas) + internal static void ExecutePluginQuery(PluginPair pair, Query query) + { + try { - try + Stopwatch sw = new Stopwatch(); + sw.Start(); + List results = pair.Plugin.Query(query) ?? new List(); + results.ForEach(o => { - Assembly asm = Assembly.Load(AssemblyName.GetAssemblyName(metadata.ExecuteFilePath)); - List types = asm.GetTypes().Where(o => o.IsClass && !o.IsAbstract && o.GetInterfaces().Contains(typeof(IInstantSearch))).ToList(); - if (types.Count == 0) - { - continue; - } - - foreach (Type type in types) - { - instantSearches.Add(Activator.CreateInstance(type) as IInstantSearch); - } - } - catch (System.Exception e) + o.PluginID = pair.Metadata.ID; + }); + sw.Stop(); + DebugHelper.WriteLine(string.Format("Plugin query: {0} - {1}", pair.Metadata.Name, sw.ElapsedMilliseconds)); + pair.QueryCount += 1; + if (pair.QueryCount == 1) { - Log.Error(string.Format("Couldn't load plugin {0}: {1}", metadata.Name, e.Message)); -#if (DEBUG) - { - throw; - } -#endif + pair.AvgQueryTime = sw.ElapsedMilliseconds; } + else + { + pair.AvgQueryTime = (pair.AvgQueryTime + sw.ElapsedMilliseconds) / 2; + } + API.PushResults(query, pair.Metadata, results); } + catch (System.Exception e) + { + throw new WoxPluginException(pair.Metadata.Name, e); + } + } + + private static List> LoadInstantSearches() + { + if (instantSearches != null) return instantSearches; + + instantSearches = AssemblyHelper.LoadPluginInterfaces(); return instantSearches; } @@ -193,5 +232,73 @@ namespace Wox.Core.Plugin { return AllPlugins.FirstOrDefault(o => o.Metadata.ID == id); } + + internal static List> LoadExclusiveSearchPlugins() + { + if (exclusiveSearchPlugins != null) return exclusiveSearchPlugins; + exclusiveSearchPlugins = AssemblyHelper.LoadPluginInterfaces(); + return exclusiveSearchPlugins; + } + + internal static PluginPair GetExclusivePlugin(Query query) + { + KeyValuePair plugin = LoadExclusiveSearchPlugins().FirstOrDefault(o => o.Value.IsExclusiveQuery((query))); + return plugin.Key; + } + + internal static PluginPair GetActionKeywordPlugin(Query query) + { + //if a query doesn't contain at least one space, it should not be a action keword plugin query + if (!query.RawQuery.Contains(" ")) return null; + + PluginPair actionKeywordPluginPair = AllPlugins.FirstOrDefault(o => o.Metadata.ActionKeyword == query.GetActionKeyword()); + if (actionKeywordPluginPair != null) + { + var customizedPluginConfig = UserSettingStorage.Instance. + CustomizedPluginConfigs.FirstOrDefault(o => o.ID == actionKeywordPluginPair.Metadata.ID); + if (customizedPluginConfig != null && customizedPluginConfig.Disabled) + { + return null; + } + + return actionKeywordPluginPair; + } + + return null; + } + + internal static bool IsExclusivePluginQuery(Query query) + { + return GetExclusivePlugin(query) != null || GetActionKeywordPlugin(query) != null; + } + + public static List GetPluginContextMenus(Result result) + { + List contextContextMenus = new List(); + if (contextMenuPlugins == null) + { + contextMenuPlugins = AssemblyHelper.LoadPluginInterfaces(); + } + + var contextMenuPlugin = contextMenuPlugins.FirstOrDefault(o => o.Key.Metadata.ID == result.PluginID); + if (contextMenuPlugin.Value != null) + { + try + { + return contextMenuPlugin.Value.LoadContextMenus(result); + } + catch (System.Exception e) + { + Log.Error(string.Format("Couldn't load plugin context menus {0}: {1}", contextMenuPlugin.Key.Metadata.Name, e.Message)); +#if (DEBUG) + { + throw; + } +#endif + } + } + + return contextContextMenus; + } } } diff --git a/Wox.Core/Plugin/QueryDispatcher/BaseQueryDispatcher.cs b/Wox.Core/Plugin/QueryDispatcher/BaseQueryDispatcher.cs new file mode 100644 index 000000000..6c5c562c8 --- /dev/null +++ b/Wox.Core/Plugin/QueryDispatcher/BaseQueryDispatcher.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading; +using Wox.Infrastructure; +using Wox.Plugin; + +namespace Wox.Core.Plugin.QueryDispatcher +{ + public abstract class BaseQueryDispatcher : IQueryDispatcher + { + protected abstract List GetPlugins(Query query); + + public void Dispatch(Query query) + { + foreach (PluginPair pair in GetPlugins(query)) + { + PluginPair localPair = pair; + if (query.IsIntantQuery && PluginManager.IsInstantSearchPlugin(pair.Metadata)) + { + DebugHelper.WriteLine(string.Format("Plugin {0} is executing instant search.", pair.Metadata.Name)); + using (new Timeit(" => instant search took: ")) + { + PluginManager.ExecutePluginQuery(localPair, query); + } + } + else + { + ThreadPool.QueueUserWorkItem(state => + { + PluginManager.ExecutePluginQuery(localPair, query); + }); + } + } + } + } +} diff --git a/Wox.Core/Plugin/QueryDispatcher/ExclusiveQueryDispatcher.cs b/Wox.Core/Plugin/QueryDispatcher/ExclusiveQueryDispatcher.cs new file mode 100644 index 000000000..d0923c34c --- /dev/null +++ b/Wox.Core/Plugin/QueryDispatcher/ExclusiveQueryDispatcher.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using Wox.Core.Exception; +using Wox.Core.UserSettings; +using Wox.Infrastructure.Logger; +using Wox.Plugin; + +namespace Wox.Core.Plugin.QueryDispatcher +{ + public class ExclusiveQueryDispatcher : BaseQueryDispatcher + { + protected override List GetPlugins(Query query) + { + List pluginPairs = new List(); + var exclusivePluginPair = PluginManager.GetExclusivePlugin(query) ?? + PluginManager.GetActionKeywordPlugin(query); + if (exclusivePluginPair != null) + { + pluginPairs.Add(exclusivePluginPair); + } + + return pluginPairs; + } + + + + } +} diff --git a/Wox.Core/Plugin/QueryDispatcher/GenericQueryDispatcher.cs b/Wox.Core/Plugin/QueryDispatcher/GenericQueryDispatcher.cs new file mode 100644 index 000000000..5c53c556b --- /dev/null +++ b/Wox.Core/Plugin/QueryDispatcher/GenericQueryDispatcher.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using Wox.Core.Exception; +using Wox.Core.UserSettings; +using Wox.Infrastructure.Logger; +using Wox.Plugin; + +namespace Wox.Core.Plugin.QueryDispatcher +{ + public class GenericQueryDispatcher : BaseQueryDispatcher + { + protected override List GetPlugins(Query query) + { + return PluginManager.AllPlugins.Where(o => PluginManager.IsGenericPlugin(o.Metadata)).ToList(); + } + } +} \ No newline at end of file diff --git a/Wox.Core/Plugin/QueryDispatcher/QueryDispatcher.cs b/Wox.Core/Plugin/QueryDispatcher/QueryDispatcher.cs index e5f5b76bf..5d2062b48 100644 --- a/Wox.Core/Plugin/QueryDispatcher/QueryDispatcher.cs +++ b/Wox.Core/Plugin/QueryDispatcher/QueryDispatcher.cs @@ -1,22 +1,23 @@  +using System.Threading; +using Wox.Plugin; + namespace Wox.Core.Plugin.QueryDispatcher { internal static class QueryDispatcher { - private static readonly IQueryDispatcher UserPluginDispatcher = new UserPluginQueryDispatcher(); - private static readonly IQueryDispatcher SystemPluginDispatcher = new SystemPluginQueryDispatcher(); + private static readonly IQueryDispatcher exclusivePluginDispatcher = new ExclusiveQueryDispatcher(); + private static readonly IQueryDispatcher genericQueryDispatcher = new GenericQueryDispatcher(); - public static void Dispatch(Wox.Plugin.Query query) + public static void Dispatch(Query query) { - if (PluginManager.IsUserPluginQuery(query)) + if (PluginManager.IsExclusivePluginQuery(query)) { - query.Search = query.RawQuery.Substring(query.RawQuery.IndexOf(' ') + 1); - UserPluginDispatcher.Dispatch(query); + exclusivePluginDispatcher.Dispatch(query); } else { - query.Search = query.RawQuery; - SystemPluginDispatcher.Dispatch(query); + genericQueryDispatcher.Dispatch(query); } } } diff --git a/Wox.Core/Plugin/QueryDispatcher/SystemPluginQueryDispatcher.cs b/Wox.Core/Plugin/QueryDispatcher/SystemPluginQueryDispatcher.cs deleted file mode 100644 index 5cda7d3e3..000000000 --- a/Wox.Core/Plugin/QueryDispatcher/SystemPluginQueryDispatcher.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using Wox.Core.Exception; -using Wox.Core.UserSettings; -using Wox.Infrastructure.Logger; -using Wox.Plugin; - -namespace Wox.Core.Plugin.QueryDispatcher -{ - public class SystemPluginQueryDispatcher : IQueryDispatcher - { - private IEnumerable allSytemPlugins = PluginManager.AllPlugins.Where(o => PluginManager.IsSystemPlugin(o.Metadata)); - - public void Dispatch(Query query) - { - var queryPlugins = allSytemPlugins; - foreach (PluginPair pair in queryPlugins) - { - PluginPair pair1 = pair; - ThreadPool.QueueUserWorkItem(state => - { - try - { - List results = pair1.Plugin.Query(query); - results.ForEach(o => - { - o.PluginID = pair1.Metadata.ID; - }); - - PluginManager.API.PushResults(query, pair1.Metadata, results); - } - catch (System.Exception e) - { - throw new WoxPluginException(pair1.Metadata.Name,e); - } - }); - } - } - } -} \ No newline at end of file diff --git a/Wox.Core/Plugin/QueryDispatcher/UserPluginQueryDispatcher.cs b/Wox.Core/Plugin/QueryDispatcher/UserPluginQueryDispatcher.cs deleted file mode 100644 index c50344296..000000000 --- a/Wox.Core/Plugin/QueryDispatcher/UserPluginQueryDispatcher.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using Wox.Core.Exception; -using Wox.Core.UserSettings; -using Wox.Infrastructure.Logger; -using Wox.Plugin; - -namespace Wox.Core.Plugin.QueryDispatcher -{ - public class UserPluginQueryDispatcher : IQueryDispatcher - { - public void Dispatch(Query query) - { - PluginPair userPlugin = PluginManager.AllPlugins.FirstOrDefault(o => o.Metadata.ActionKeyword == query.GetActionKeyword()); - if (userPlugin != null && !string.IsNullOrEmpty(userPlugin.Metadata.ActionKeyword)) - { - var customizedPluginConfig = UserSettingStorage.Instance.CustomizedPluginConfigs.FirstOrDefault(o => o.ID == userPlugin.Metadata.ID); - if (customizedPluginConfig != null && customizedPluginConfig.Disabled) - { - //need to stop the loading animation - PluginManager.API.StopLoadingBar(); - return; - } - - ThreadPool.QueueUserWorkItem(t => - { - try - { - List results = userPlugin.Plugin.Query(query) ?? new List(); - results.ForEach(o => - { - o.PluginID = userPlugin.Metadata.ID; - }); - PluginManager.API.PushResults(query, userPlugin.Metadata, results); - } - catch (System.Exception e) - { - throw new WoxPluginException(userPlugin.Metadata.Name, e); - } - }); - } - } - } -} diff --git a/Wox.Core/UI/ResourceMerger.cs b/Wox.Core/UI/ResourceMerger.cs index 6d7a89298..542200ede 100644 --- a/Wox.Core/UI/ResourceMerger.cs +++ b/Wox.Core/UI/ResourceMerger.cs @@ -1,7 +1,9 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Windows; using Wox.Core.i18n; +using Wox.Core.Plugin; using Wox.Core.Theme; using Wox.Plugin; @@ -9,38 +11,28 @@ namespace Wox.Core.UI { public class ResourceMerger { - public static void ApplyResources() + internal static void ApplyResources() { Application.Current.Resources.MergedDictionaries.Clear(); ApplyPluginLanguages(); ApplyThemeAndLanguageResources(); } - private static void ApplyThemeAndLanguageResources() + internal static void ApplyThemeAndLanguageResources() { - var UIResourceType = typeof(IUIResource); - var UIResources = AppDomain.CurrentDomain.GetAssemblies() - .SelectMany(s => s.GetTypes()) - .Where(p => p.IsClass && !p.IsAbstract && UIResourceType.IsAssignableFrom(p)); - + var UIResources = AssemblyHelper.LoadInterfacesFromAppDomain(); foreach (var uiResource in UIResources) { - Application.Current.Resources.MergedDictionaries.Add( - ((IUIResource)Activator.CreateInstance(uiResource)).GetResourceDictionary()); + Application.Current.Resources.MergedDictionaries.Add(uiResource.GetResourceDictionary()); } } - public static void ApplyPluginLanguages() + internal static void ApplyPluginLanguages() { - var pluginI18nType = typeof(IPluginI18n); - var pluginI18ns = AppDomain.CurrentDomain.GetAssemblies() - .SelectMany(s => s.GetTypes()) - .Where(p => p.IsClass && !p.IsAbstract && pluginI18nType.IsAssignableFrom(p)); - + var pluginI18ns = AssemblyHelper.LoadInterfacesFromAppDomain(); foreach (var pluginI18n in pluginI18ns) { - string languageFile = InternationalizationManager.Instance.GetLanguageFile( - ((IPluginI18n)Activator.CreateInstance(pluginI18n)).GetLanguagesFolder()); + string languageFile = InternationalizationManager.Instance.GetLanguageFile(pluginI18n.GetLanguagesFolder()); if (!string.IsNullOrEmpty(languageFile)) { Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary @@ -50,5 +42,7 @@ namespace Wox.Core.UI } } } + + } } \ No newline at end of file diff --git a/Wox.Core/Updater/UpdaterManager.cs b/Wox.Core/Updater/UpdaterManager.cs index 258d3c0b6..21b43cfef 100644 --- a/Wox.Core/Updater/UpdaterManager.cs +++ b/Wox.Core/Updater/UpdaterManager.cs @@ -22,8 +22,8 @@ namespace Wox.Core.Updater { private static UpdaterManager instance; private const string VersionCheckURL = "https://api.getwox.com/release/latest/"; - //private const string UpdateFeedURL = "http://upgrade.getwox.com/update.xml"; - private const string UpdateFeedURL = "http://127.0.0.1:8888/update.xml"; + private const string UpdateFeedURL = "http://upgrade.getwox.com/update.xml"; + //private const string UpdateFeedURL = "http://127.0.0.1:8888/update.xml"; private static SemanticVersion currentVersion; public event EventHandler PrepareUpdateReady; diff --git a/Wox.Core/UserSettings/UserSettingStorage.cs b/Wox.Core/UserSettings/UserSettingStorage.cs index 436cfaf70..ff2cc107a 100644 --- a/Wox.Core/UserSettings/UserSettingStorage.cs +++ b/Wox.Core/UserSettings/UserSettingStorage.cs @@ -130,14 +130,7 @@ namespace Wox.Core.UserSettings OpacityMode = OpacityMode.Normal; LeaveCmdOpen = false; HideWhenDeactive = false; - CustomPluginHotkeys = new List() - { - new CustomPluginHotkey() - { - ActionKeyword = "history ", - Hotkey = "Alt + H" - } - }; + CustomPluginHotkeys = new List(); return this; } diff --git a/Wox.Core/Wox.Core.csproj b/Wox.Core/Wox.Core.csproj index 84940b303..fa06e3840 100644 --- a/Wox.Core/Wox.Core.csproj +++ b/Wox.Core/Wox.Core.csproj @@ -69,6 +69,8 @@ + + @@ -85,8 +87,8 @@ - - + + diff --git a/Wox.Core/i18n/Internationalization.cs b/Wox.Core/i18n/Internationalization.cs index d77232091..bf2157603 100644 --- a/Wox.Core/i18n/Internationalization.cs +++ b/Wox.Core/i18n/Internationalization.cs @@ -9,6 +9,7 @@ using Wox.Core.Exception; using Wox.Core.UI; using Wox.Core.UserSettings; using Wox.Infrastructure.Logger; +using Wox.Plugin; namespace Wox.Core.i18n { @@ -70,6 +71,7 @@ namespace Wox.Core.i18n UserSettingStorage.Instance.Language = language.LanguageCode; UserSettingStorage.Instance.Save(); ResourceMerger.ApplyResources(); + UpdateAllPluginMetadataTranslations(); } public ResourceDictionary GetResourceDictionary() @@ -109,6 +111,36 @@ namespace Wox.Core.i18n return GetLanguagePath(language); } + + internal void UpdateAllPluginMetadataTranslations() + { + List> plugins = AssemblyHelper.LoadPluginInterfaces(); + foreach (var plugin in plugins) + { + UpdatePluginMetadataTranslations(plugin.Key); + } + } + + internal void UpdatePluginMetadataTranslations(PluginPair pluginPair) + { + var pluginI18n = pluginPair.Plugin as IPluginI18n; + if (pluginI18n == null) return; + try + { + pluginPair.Metadata.Name = pluginI18n.GetTranslatedPluginTitle(); + pluginPair.Metadata.Description = pluginI18n.GetTranslatedPluginDescription(); + } + catch (System.Exception e) + { + Log.Warn("Update Plugin metadata translation failed:" + e.Message); +#if (DEBUG) + { + throw; + } +#endif + } + } + private string GetLanguagePath(Language language) { string path = Path.Combine(DefaultLanguageDirectory, language.LanguageCode + ".xaml"); diff --git a/Wox.CrashReporter/Properties/AssemblyInfo.cs b/Wox.CrashReporter/Properties/AssemblyInfo.cs index 688a8e327..13ef80c58 100644 --- a/Wox.CrashReporter/Properties/AssemblyInfo.cs +++ b/Wox.CrashReporter/Properties/AssemblyInfo.cs @@ -1,36 +1,19 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// 有关程序集的常规信息通过以下 -// 特性集控制。更改这些特性值可修改 -// 与程序集关联的信息。 -[assembly: AssemblyTitle("Wox.CrashReporter")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Wox.CrashReporter")] -[assembly: AssemblyCopyright("Copyright © 2015")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// 将 ComVisible 设置为 false 使此程序集中的类型 -// 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型, -// 则将该类型上的 ComVisible 特性设置为 true。 -[assembly: ComVisible(false)] - -// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID -[assembly: Guid("0ea3743c-2c0d-4b13-b9ce-e5e1f85aea23")] - -// 程序集的版本信息由下面四个值组成: -// -// 主版本 -// 次版本 -// 生成号 -// 修订号 -// -// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, -// 方法是按如下所示使用“*”: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的常规信息通过以下 +// 特性集控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("Wox.CrashReporter")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Wox.CrashReporter")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: ComVisible(false)] +[assembly: Guid("0ea3743c-2c0d-4b13-b9ce-e5e1f85aea23")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/Wox.CrashReporter/ReportWindow.xaml b/Wox.CrashReporter/ReportWindow.xaml index abd22798e..c9f7a92ff 100644 --- a/Wox.CrashReporter/ReportWindow.xaml +++ b/Wox.CrashReporter/ReportWindow.xaml @@ -35,7 +35,7 @@ - + diff --git a/Wox.CrashReporter/ReportWindow.xaml.cs b/Wox.CrashReporter/ReportWindow.xaml.cs index 7a6ec983c..ff948f795 100644 --- a/Wox.CrashReporter/ReportWindow.xaml.cs +++ b/Wox.CrashReporter/ReportWindow.xaml.cs @@ -12,6 +12,7 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; +using Exceptionless; using Wox.Core; using Wox.Core.Exception; using Wox.Core.i18n; @@ -19,6 +20,7 @@ using Wox.Core.UI; using Wox.Core.Updater; using Wox.Core.UserSettings; using Wox.Infrastructure.Http; +using Wox.Infrastructure.Logger; namespace Wox.CrashReporter { @@ -48,22 +50,24 @@ namespace Wox.CrashReporter string sendingMsg = InternationalizationManager.Instance.GetTranslation("reportWindow_sending"); tbSendReport.Content = sendingMsg; btnSend.IsEnabled = false; - ThreadPool.QueueUserWorkItem(o => SendReport()); + SendReport(); } private void SendReport() { - string error = string.Format("{{\"data\":{0}}}", ExceptionFormatter.FormatExcpetion(exception)); - string response = HttpRequest.Post(APIServer.ErrorReportURL, error, HttpProxy.Instance); - if (response.ToLower() == "ok") + Hide(); + ThreadPool.QueueUserWorkItem(o => { - MessageBox.Show(InternationalizationManager.Instance.GetTranslation("reportWindow_report_succeed")); - } - else - { - MessageBox.Show(InternationalizationManager.Instance.GetTranslation("reportWindow_report_failed")); - } - Dispatcher.Invoke(new Action(Close)); + string reproduceSteps = new TextRange(tbReproduceSteps.Document.ContentStart, tbReproduceSteps.Document.ContentEnd).Text; + exception.ToExceptionless() + .SetUserDescription(reproduceSteps) + .Submit(); + ExceptionlessClient.Current.ProcessQueue(); + Dispatcher.Invoke(new Action(() => + { + Close(); + })); + }); } private void btnCancel_Click(object sender, RoutedEventArgs e) diff --git a/Wox.CrashReporter/Wox.CrashReporter.csproj b/Wox.CrashReporter/Wox.CrashReporter.csproj index 565c82d81..822e39768 100644 --- a/Wox.CrashReporter/Wox.CrashReporter.csproj +++ b/Wox.CrashReporter/Wox.CrashReporter.csproj @@ -1,109 +1,118 @@ - - - - - Debug - AnyCPU - {2FEB2298-7653-4009-B1EA-FFFB1A768BCC} - Library - Properties - Wox.CrashReporter - Wox.CrashReporter - v3.5 - 512 - ..\ - true - - - - true - full - false - ..\Output\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\Output\Release\ - TRACE - prompt - 4 - false - - - - - - - - - - - - - - - - - - ReportWindow.xaml - - - - - Designer - MSBuild:Compile - - - - - {B749F0DB-8E75-47DB-9E5E-265D16D0C0D2} - Wox.Core - - - {4FD29318-A8AB-4D8F-AA47-60BC241B8DA3} - Wox.Infrastructure - - - {8451ECDD-2EA4-4966-BB0A-7BBC40138E80} - Wox.Plugin - - - - - PreserveNewest - - - PreserveNewest - - - - - PreserveNewest - - - - - PreserveNewest - - - - - - - 这台计算机上缺少此项目引用的 NuGet 程序包。启用“NuGet 程序包还原”可下载这些程序包。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 - - - - + + + + + Debug + AnyCPU + {2FEB2298-7653-4009-B1EA-FFFB1A768BCC} + Library + Properties + Wox.CrashReporter + Wox.CrashReporter + v3.5 + 512 + ..\ + true + + + + true + full + false + ..\Output\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + ..\Output\Release\ + TRACE + prompt + 4 + false + + + + ..\packages\Exceptionless.1.5.2121\lib\net35\Exceptionless.dll + + + ..\packages\Exceptionless.1.5.2121\lib\net35\Exceptionless.Models.dll + + + + + + + + + + + + + + + + + ReportWindow.xaml + + + + + Designer + MSBuild:Compile + + + + + {B749F0DB-8E75-47DB-9E5E-265D16D0C0D2} + Wox.Core + + + {4FD29318-A8AB-4D8F-AA47-60BC241B8DA3} + Wox.Infrastructure + + + {8451ECDD-2EA4-4966-BB0A-7BBC40138E80} + Wox.Plugin + + + + + PreserveNewest + + + PreserveNewest + + + + + PreserveNewest + + + + + PreserveNewest + + + + + + + + + + 这台计算机上缺少此项目引用的 NuGet 程序包。启用“NuGet 程序包还原”可下载这些程序包。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 + + + + \ No newline at end of file diff --git a/Wox.CrashReporter/packages.config b/Wox.CrashReporter/packages.config new file mode 100644 index 000000000..aaa9e6ed9 --- /dev/null +++ b/Wox.CrashReporter/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Wox.Infrastructure/DebugHelper.cs b/Wox.Infrastructure/DebugHelper.cs new file mode 100644 index 000000000..e31636b7e --- /dev/null +++ b/Wox.Infrastructure/DebugHelper.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; + +namespace Wox.Infrastructure +{ + public static class DebugHelper + { + public static void WriteLine(string msg) + { + return; + Debug.WriteLine(msg); + } + } +} diff --git a/Wox.Infrastructure/Logger/NLog.xsd b/Wox.Infrastructure/Logger/NLog.xsd index 481702860..edf2b7087 100644 --- a/Wox.Infrastructure/Logger/NLog.xsd +++ b/Wox.Infrastructure/Logger/NLog.xsd @@ -855,7 +855,7 @@ - + diff --git a/Wox.Infrastructure/Properties/AssemblyInfo.cs b/Wox.Infrastructure/Properties/AssemblyInfo.cs index b40c42166..092a40914 100644 --- a/Wox.Infrastructure/Properties/AssemblyInfo.cs +++ b/Wox.Infrastructure/Properties/AssemblyInfo.cs @@ -2,9 +2,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// 有关程序集的常规信息通过以下 -// 特性集控制。更改这些特性值可修改 -// 与程序集关联的信息。 + [assembly: AssemblyTitle("Wox.Infrastructure")] [assembly: AssemblyDescription("https://github.com/qianlifeng/Wox")] [assembly: AssemblyConfiguration("")] @@ -13,24 +11,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyCopyright("The MIT License (MIT)")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] - -// 将 ComVisible 设置为 false 使此程序集中的类型 -// 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型, -// 则将该类型上的 ComVisible 特性设置为 true。 [assembly: ComVisible(false)] - -// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID [assembly: Guid("aee57a31-29e5-4f03-a41f-7917910fe90f")] - -// 程序集的版本信息由下面四个值组成: -// -// 主版本 -// 次版本 -// 生成号 -// 修订号 -// -// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, -// 方法是按如下所示使用“*”: -// [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/Wox.Infrastructure/Storage/BinaryStorage.cs b/Wox.Infrastructure/Storage/BinaryStorage.cs index 7651ca770..9ad13bfaf 100644 --- a/Wox.Infrastructure/Storage/BinaryStorage.cs +++ b/Wox.Infrastructure/Storage/BinaryStorage.cs @@ -56,8 +56,9 @@ namespace Wox.Infrastructure.Storage } } } - catch (Exception) + catch (Exception e) { + Log.Error(e); serializedObject = LoadDefault(); #if (DEBUG) { diff --git a/Wox.Infrastructure/StringMatcher.cs b/Wox.Infrastructure/StringMatcher.cs new file mode 100644 index 000000000..4d3d9dd5a --- /dev/null +++ b/Wox.Infrastructure/StringMatcher.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Wox.Infrastructure +{ + public class StringMatcher + { + /// + /// Check if a candidate is match with the source + /// + /// + /// + /// Match score + public static int Match(string source, string candidate) + { + if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(candidate)) return 0; + + FuzzyMatcher matcher = FuzzyMatcher.Create(candidate); + int score = matcher.Evaluate(source).Score; + if (score > 0) return score; + + score = matcher.Evaluate(source.Unidecode()).Score; + return score; + } + + public static bool IsMatch(string source, string candidate) + { + return Match(source, candidate) > 0; + } + } +} diff --git a/Wox.Infrastructure/Timeit.cs b/Wox.Infrastructure/Timeit.cs index a29ea53ed..14dd1f62c 100644 --- a/Wox.Infrastructure/Timeit.cs +++ b/Wox.Infrastructure/Timeit.cs @@ -20,7 +20,7 @@ namespace Wox.Infrastructure public void Dispose() { stopwatch.Stop(); - Debug.WriteLine(name + ":" + stopwatch.ElapsedMilliseconds + "ms","Wox"); + DebugHelper.WriteLine(name + ":" + stopwatch.ElapsedMilliseconds + "ms"); } } } diff --git a/Wox.Infrastructure/Wox.Infrastructure.csproj b/Wox.Infrastructure/Wox.Infrastructure.csproj index ca13df96f..80a96bc32 100644 --- a/Wox.Infrastructure/Wox.Infrastructure.csproj +++ b/Wox.Infrastructure/Wox.Infrastructure.csproj @@ -58,6 +58,7 @@ + @@ -65,6 +66,7 @@ + diff --git a/Wox.Plugin/EventHandler.cs b/Wox.Plugin/EventHandler.cs index f3c6121f9..1bbe950a4 100644 --- a/Wox.Plugin/EventHandler.cs +++ b/Wox.Plugin/EventHandler.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Windows; using System.Windows.Input; namespace Wox.Plugin @@ -9,6 +10,8 @@ namespace Wox.Plugin public delegate void WoxKeyDownEventHandler(WoxKeyDownEventArgs e); public delegate void AfterWoxQueryEventHandler(WoxQueryEventArgs e); + public delegate void ResultItemDropEventHandler(Result result, IDataObject dropObject, DragEventArgs e); + /// /// Global keyboard events /// diff --git a/Wox.Plugin/Features/IContextMenu.cs b/Wox.Plugin/Features/IContextMenu.cs new file mode 100644 index 000000000..0fa42076b --- /dev/null +++ b/Wox.Plugin/Features/IContextMenu.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Wox.Plugin.Features +{ + public interface IContextMenu + { + List LoadContextMenus(Result selectedResult); + } +} \ No newline at end of file diff --git a/Wox.Plugin/Features/IExclusiveQuery.cs b/Wox.Plugin/Features/IExclusiveQuery.cs new file mode 100644 index 000000000..6c6acbf5e --- /dev/null +++ b/Wox.Plugin/Features/IExclusiveQuery.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Wox.Plugin.Features +{ + public interface IExclusiveQuery + { + bool IsExclusiveQuery(Query query); + } +} diff --git a/Wox.Plugin/Features/IInstantQuery.cs b/Wox.Plugin/Features/IInstantQuery.cs new file mode 100644 index 000000000..154f167e2 --- /dev/null +++ b/Wox.Plugin/Features/IInstantQuery.cs @@ -0,0 +1,7 @@ +namespace Wox.Plugin.Features +{ + public interface IInstantQuery + { + bool IsInstantQuery(string query); + } +} \ No newline at end of file diff --git a/Wox.Plugin/IInstantSearch.cs b/Wox.Plugin/IInstantSearch.cs deleted file mode 100644 index 0799f45f4..000000000 --- a/Wox.Plugin/IInstantSearch.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Wox.Plugin -{ - public interface IInstantSearch - { - bool IsInstantSearch(string query); - } -} diff --git a/Wox.Plugin/IPluginI18n.cs b/Wox.Plugin/IPluginI18n.cs index cb13dd02b..c1068ccab 100644 --- a/Wox.Plugin/IPluginI18n.cs +++ b/Wox.Plugin/IPluginI18n.cs @@ -12,5 +12,9 @@ namespace Wox.Plugin public interface IPluginI18n { string GetLanguagesFolder(); + + string GetTranslatedPluginTitle(); + + string GetTranslatedPluginDescription(); } -} +} \ No newline at end of file diff --git a/Wox.Plugin/IPublicAPI.cs b/Wox.Plugin/IPublicAPI.cs index 972d281f9..7928440ad 100644 --- a/Wox.Plugin/IPublicAPI.cs +++ b/Wox.Plugin/IPublicAPI.cs @@ -15,7 +15,13 @@ namespace Wox.Plugin /// /// /// - void PushResults(Query query,PluginMetadata plugin, List results); + void PushResults(Query query, PluginMetadata plugin, List results); + + /// + /// Show context menu with giving results + /// + /// + void ShowContextMenu(PluginMetadata plugin, List results); /// /// Execute command @@ -36,6 +42,12 @@ namespace Wox.Plugin /// void ChangeQuery(string query, bool requery = false); + /// + /// Just change the query text, this won't raise search + /// + /// + void ChangeQueryText(string query, bool selectAll = false); + /// /// Close Wox /// @@ -57,13 +69,13 @@ namespace Wox.Plugin /// Message title /// Message subtitle /// Message icon path (relative path to your plugin folder) - void ShowMsg(string title, string subTitle, string iconPath); + void ShowMsg(string title, string subTitle = "", string iconPath = ""); /// /// Open setting dialog /// void OpenSettingDialog(); - + /// /// Show loading animation /// @@ -111,13 +123,8 @@ namespace Wox.Plugin event WoxGlobalKeyboardEventHandler GlobalKeyboardEvent; /// - /// Fired after wox execute a query + /// Fired after drop to result item of current plugin /// - event AfterWoxQueryEventHandler AfterWoxQueryEvent; - - /// - /// Fired before wox start to execute a query - /// - event AfterWoxQueryEventHandler BeforeWoxQueryEvent; + event ResultItemDropEventHandler ResultItemDropEvent; } } diff --git a/Wox.Plugin/PluginMetadata.cs b/Wox.Plugin/PluginMetadata.cs index 406257f86..48e6c024f 100644 --- a/Wox.Plugin/PluginMetadata.cs +++ b/Wox.Plugin/PluginMetadata.cs @@ -24,10 +24,10 @@ namespace Wox.Plugin } public string ExecuteFileName { get; set; } + public string PluginDirectory { get; set; } public string ActionKeyword { get; set; } - public PluginType PluginType { get; set; } public string IcoPath { get; set; } diff --git a/Wox.Plugin/PluginPair.cs b/Wox.Plugin/PluginPair.cs index b3053c057..03aa657ce 100644 --- a/Wox.Plugin/PluginPair.cs +++ b/Wox.Plugin/PluginPair.cs @@ -10,6 +10,12 @@ namespace Wox.Plugin public IPlugin Plugin { get; set; } public PluginMetadata Metadata { get; set; } + internal long InitTime { get; set; } + + internal long AvgQueryTime { get; set; } + + internal int QueryCount { get; set; } + public override string ToString() { return Metadata.Name; diff --git a/Wox.Plugin/PluginType.cs b/Wox.Plugin/PluginType.cs deleted file mode 100644 index b8ffc6e12..000000000 --- a/Wox.Plugin/PluginType.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Wox.Plugin -{ - public enum PluginType - { - System, - User - } -} \ No newline at end of file diff --git a/Wox.Plugin/Query.cs b/Wox.Plugin/Query.cs index 4a0119914..79fe259be 100644 --- a/Wox.Plugin/Query.cs +++ b/Wox.Plugin/Query.cs @@ -13,8 +13,8 @@ namespace Wox.Plugin /// /// Search part of a query. - /// This will not include action keyword if regular plugin gets it, and if a system plugin gets it, it should be same as RawQuery. - /// Since we allow user to switch a regular plugin to system plugin, so this property will always give you the "real" query part of + /// This will not include action keyword if exclusive plugin gets it, otherwise it should be same as RawQuery. + /// Since we allow user to switch a exclusive plugin to generic plugin, so this property will always give you the "real" query part of /// the query /// public string Search { get; internal set; } @@ -33,6 +33,8 @@ namespace Wox.Plugin return string.Empty; } + internal bool IsIntantQuery { get; set; } + /// /// Return first search split by space if it has /// diff --git a/Wox.Plugin/Result.cs b/Wox.Plugin/Result.cs index 6c1938fa4..8e5523036 100644 --- a/Wox.Plugin/Result.cs +++ b/Wox.Plugin/Result.cs @@ -68,11 +68,17 @@ namespace Wox.Plugin this.SubTitle = SubTitle; } + [Obsolete("Use IContextMenu instead")] /// /// Context menus associate with this result /// public List ContextMenu { get; set; } + /// + /// Additional data associate with this result + /// + public object ContextData { get; set; } + /// /// Plugin ID that generate this result /// diff --git a/Wox.Plugin/Wox.Plugin.csproj b/Wox.Plugin/Wox.Plugin.csproj index 424272a20..25c14f4bd 100644 --- a/Wox.Plugin/Wox.Plugin.csproj +++ b/Wox.Plugin/Wox.Plugin.csproj @@ -46,7 +46,9 @@ - + + + @@ -55,7 +57,6 @@ - diff --git a/Wox.Test/QueryTest.cs b/Wox.Test/QueryTest.cs index 061e7d59f..03c766d5c 100644 --- a/Wox.Test/QueryTest.cs +++ b/Wox.Test/QueryTest.cs @@ -11,7 +11,7 @@ namespace Wox.Test public class QueryTest { [Test] - public void UserPluginQueryTest() + public void ExclusivePluginQueryTest() { Query q = new Query("f file.txt file2 file3"); q.Search = "file.txt file2 file3"; @@ -23,7 +23,7 @@ namespace Wox.Test } [Test] - public void SystemPluginQueryTest() + public void GenericPluginQueryTest() { Query q = new Query("file.txt file2 file3"); q.Search = q.RawQuery; diff --git a/Wox.Test/UrlPluginTest.cs b/Wox.Test/UrlPluginTest.cs index 79f95109a..daaa9641c 100644 --- a/Wox.Test/UrlPluginTest.cs +++ b/Wox.Test/UrlPluginTest.cs @@ -31,6 +31,7 @@ namespace Wox.Test Assert.IsFalse(urlPlugin.IsURL("wwww")); Assert.IsFalse(urlPlugin.IsURL("wwww.c")); + Assert.IsFalse(urlPlugin.IsURL("wwww.c")); } } } diff --git a/Wox.sln b/Wox.sln index 1759a11e0..4fa783561 100644 --- a/Wox.sln +++ b/Wox.sln @@ -10,6 +10,22 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wox", "Wox\Wox.csproj", "{DB90F671-D861-46BB-93A3-F1304F5BA1C5}" + ProjectSection(ProjectDependencies) = postProject + {D120E62B-EC59-4FB4-8129-EFDD4C446A5F} = {D120E62B-EC59-4FB4-8129-EFDD4C446A5F} + {230AE83F-E92E-4E69-8355-426B305DA9C0} = {230AE83F-E92E-4E69-8355-426B305DA9C0} + {1EE20B48-82FB-48A2-8086-675D6DDAB4F0} = {1EE20B48-82FB-48A2-8086-675D6DDAB4F0} + {0B9DE348-9361-4940-ADB6-F5953BFFCCEC} = {0B9DE348-9361-4940-ADB6-F5953BFFCCEC} + {FDB3555B-58EF-4AE6-B5F1-904719637AB4} = {FDB3555B-58EF-4AE6-B5F1-904719637AB4} + {FF742965-9A80-41A5-B042-D6C7D3A21708} = {FF742965-9A80-41A5-B042-D6C7D3A21708} + {59BD9891-3837-438A-958D-ADC7F91F6F7E} = {59BD9891-3837-438A-958D-ADC7F91F6F7E} + {C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0} = {C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0} + {787B8AA6-CA93-4C84-96FE-DF31110AD1C4} = {787B8AA6-CA93-4C84-96FE-DF31110AD1C4} + {F35190AA-4758-4D9E-A193-E3BDF6AD3567} = {F35190AA-4758-4D9E-A193-E3BDF6AD3567} + {FDED22C8-B637-42E8-824A-63B5B6E05A3A} = {FDED22C8-B637-42E8-824A-63B5B6E05A3A} + {A3DCCBCA-ACC1-421D-B16E-210896234C26} = {A3DCCBCA-ACC1-421D-B16E-210896234C26} + {049490F0-ECD2-4148-9B39-2135EC346EBE} = {049490F0-ECD2-4148-9B39-2135EC346EBE} + {403B57F2-1856-4FC7-8A24-36AB346B763E} = {403B57F2-1856-4FC7-8A24-36AB346B763E} + EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wox.Infrastructure", "Wox.Infrastructure\Wox.Infrastructure.csproj", "{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}" EndProject @@ -39,8 +55,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wox.Plugin.Color", "Plugins EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wox.CrashReporter", "Wox.CrashReporter\Wox.CrashReporter.csproj", "{2FEB2298-7653-4009-B1EA-FFFB1A768BCC}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wox.Plugin.QueryHistory", "Plugins\Wox.Plugin.QueryHistory\Wox.Plugin.QueryHistory.csproj", "{B552DCB6-692E-4B1D-9E0B-9096A2A7E6B0}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wox.UpdateFeedGenerator", "Wox.UpdateFeedGenerator\Wox.UpdateFeedGenerator.csproj", "{D120E62B-EC59-4FB4-8129-EFDD4C446A5F}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wox.Plugin.Everything", "Plugins\Wox.Plugin.Everything\Wox.Plugin.Everything.csproj", "{230AE83F-E92E-4E69-8355-426B305DA9C0}" @@ -119,10 +133,6 @@ Global {2FEB2298-7653-4009-B1EA-FFFB1A768BCC}.Debug|Any CPU.Build.0 = Debug|Any CPU {2FEB2298-7653-4009-B1EA-FFFB1A768BCC}.Release|Any CPU.ActiveCfg = Release|Any CPU {2FEB2298-7653-4009-B1EA-FFFB1A768BCC}.Release|Any CPU.Build.0 = Release|Any CPU - {B552DCB6-692E-4B1D-9E0B-9096A2A7E6B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B552DCB6-692E-4B1D-9E0B-9096A2A7E6B0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B552DCB6-692E-4B1D-9E0B-9096A2A7E6B0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B552DCB6-692E-4B1D-9E0B-9096A2A7E6B0}.Release|Any CPU.Build.0 = Release|Any CPU {D120E62B-EC59-4FB4-8129-EFDD4C446A5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D120E62B-EC59-4FB4-8129-EFDD4C446A5F}.Debug|Any CPU.Build.0 = Debug|Any CPU {D120E62B-EC59-4FB4-8129-EFDD4C446A5F}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -147,7 +157,6 @@ Global {0B9DE348-9361-4940-ADB6-F5953BFFCCEC} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} {A3DCCBCA-ACC1-421D-B16E-210896234C26} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} {F35190AA-4758-4D9E-A193-E3BDF6AD3567} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} - {B552DCB6-692E-4B1D-9E0B-9096A2A7E6B0} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} {230AE83F-E92E-4E69-8355-426B305DA9C0} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} EndGlobalSection EndGlobal diff --git a/Wox/App.config b/Wox/App.config index af328919a..55ab1e0d9 100644 --- a/Wox/App.config +++ b/Wox/App.config @@ -3,10 +3,10 @@ - + - - + + - + \ No newline at end of file diff --git a/Wox/Helper/ErrorReporting.cs b/Wox/Helper/ErrorReporting.cs index cff796318..d1de5c982 100644 --- a/Wox/Helper/ErrorReporting.cs +++ b/Wox/Helper/ErrorReporting.cs @@ -13,7 +13,6 @@ namespace Wox.Helper { public static void Report(Exception e) { - if (Debugger.IsAttached) return; Log.Error(ExceptionFormatter.FormatExcpetion(e)); new CrashReporter.CrashReporter(e).Show(); } diff --git a/Wox/ImageLoader/ImageLoader.cs b/Wox/ImageLoader/ImageLoader.cs index e0f87147e..8fa9f9c5d 100644 --- a/Wox/ImageLoader/ImageLoader.cs +++ b/Wox/ImageLoader/ImageLoader.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Drawing; using System.IO; using System.Runtime.InteropServices; @@ -79,42 +80,49 @@ namespace Wox.ImageLoader public static ImageSource Load(string path, bool addToCache = true) { + Stopwatch sw = new Stopwatch(); + sw.Start(); + if (string.IsNullOrEmpty(path)) return null; if (addToCache) { ImageCacheStroage.Instance.Add(path); } + ImageSource img = null; if (imageCache.ContainsKey(path)) { - return imageCache[path]; + img = imageCache[path]; } - - ImageSource img = null; - string ext = Path.GetExtension(path).ToLower(); - - if (path.StartsWith("data:", StringComparison.OrdinalIgnoreCase)) + else { - img = new BitmapImage(new Uri(path)); - } - else if (selfExts.Contains(ext) && File.Exists(path)) - { - img = GetIcon(path); - } - else if (!string.IsNullOrEmpty(path) && imageExts.Contains(ext) && File.Exists(path)) - { - img = new BitmapImage(new Uri(path)); - } + string ext = Path.GetExtension(path).ToLower(); - - if (img != null && addToCache) - { - if (!imageCache.ContainsKey(path)) + if (path.StartsWith("data:", StringComparison.OrdinalIgnoreCase)) { - imageCache.Add(path, img); + img = new BitmapImage(new Uri(path)); + } + else if (selfExts.Contains(ext) && File.Exists(path)) + { + img = GetIcon(path); + } + else if (!string.IsNullOrEmpty(path) && imageExts.Contains(ext) && File.Exists(path)) + { + img = new BitmapImage(new Uri(path)); + } + + + if (img != null && addToCache) + { + if (!imageCache.ContainsKey(path)) + { + imageCache.Add(path, img); + } } } + sw.Stop(); + DebugHelper.WriteLine(string.Format("Loading image path: {0} - {1}ms",path,sw.ElapsedMilliseconds)); return img; } diff --git a/Wox/Images/down.png b/Wox/Images/down.png new file mode 100644 index 000000000..b99380509 Binary files /dev/null and b/Wox/Images/down.png differ diff --git a/Wox/Images/history.png b/Wox/Images/history.png new file mode 100644 index 000000000..6bb070398 Binary files /dev/null and b/Wox/Images/history.png differ diff --git a/Wox/Images/menu.png b/Wox/Images/menu.png deleted file mode 100644 index d7395f4d9..000000000 Binary files a/Wox/Images/menu.png and /dev/null differ diff --git a/Wox/Images/up.png b/Wox/Images/up.png new file mode 100644 index 000000000..9a15464b2 Binary files /dev/null and b/Wox/Images/up.png differ diff --git a/Wox/Languages/en.xaml b/Wox/Languages/en.xaml index 54ad62c9a..aaa5953d3 100644 --- a/Wox/Languages/en.xaml +++ b/Wox/Languages/en.xaml @@ -5,8 +5,12 @@ Register hotkey: {0} failed Could not start {0} Invalid wox plugin file format - + Set as topmost in this query + Cancel topmost in this query + Execute query:{0} + Last execute time:{0} + Wox Settings General @@ -22,6 +26,8 @@ Action keyword Plugin Directory Author + Init time: {0}ms + Query time: {0}ms Theme diff --git a/Wox/Languages/zh-cn.xaml b/Wox/Languages/zh-cn.xaml index 39688d68f..7b2d632de 100644 --- a/Wox/Languages/zh-cn.xaml +++ b/Wox/Languages/zh-cn.xaml @@ -5,7 +5,10 @@ 注册热键:{0} 失败 启动命令 {0} 失败 不是合法的Wox插件格式 - + 在当前查询中置顶 + 取消置顶 + 执行查询:{0} + 上次执行时间:{0} Wox设置 @@ -22,7 +25,9 @@ 触发关键字 插件目录 作者 - + 加载耗时:{0}ms + 查询耗时:{0}ms + 主题 浏览更多主题 diff --git a/Wox/Languages/zh-tw.xaml b/Wox/Languages/zh-tw.xaml index 694cd3175..1e3d40e82 100644 --- a/Wox/Languages/zh-tw.xaml +++ b/Wox/Languages/zh-tw.xaml @@ -5,8 +5,11 @@ 註冊熱鍵:{0} 失敗 啟動命令 {0} 失敗 不是合法的Wox插件格式 - - + 在當前查詢中置頂 + 取消置頂 + 執行查詢:{0} + 上次執行時間:{0} + Wox設置 通用 @@ -22,7 +25,9 @@ 觸發關鍵字 插件目錄 作者 - + 加載耗時:{0}ms + 查詢耗時:{0}ms + 主題 瀏覽更多主題 diff --git a/Wox/MainWindow.xaml.cs b/Wox/MainWindow.xaml.cs index 1f408c20e..dafc53f4a 100644 --- a/Wox/MainWindow.xaml.cs +++ b/Wox/MainWindow.xaml.cs @@ -3,14 +3,15 @@ using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Drawing; +using System.IO; using System.Linq; using System.Net; +using System.Reflection; using System.Threading; using System.Windows; using System.Windows.Controls; using System.Windows.Forms; using System.Windows.Input; -using System.Windows.Interop; using System.Windows.Media.Animation; using NHotkey; using NHotkey.Wpf; @@ -24,16 +25,14 @@ using Wox.Infrastructure; using Wox.Infrastructure.Hotkey; using Wox.Plugin; using Wox.Storage; -using Brushes = System.Windows.Media.Brushes; -using Color = System.Windows.Media.Color; using ContextMenu = System.Windows.Forms.ContextMenu; using DataFormats = System.Windows.DataFormats; using DragEventArgs = System.Windows.DragEventArgs; +using IDataObject = System.Windows.IDataObject; using KeyEventArgs = System.Windows.Input.KeyEventArgs; using MenuItem = System.Windows.Forms.MenuItem; using MessageBox = System.Windows.MessageBox; using ToolTip = System.Windows.Controls.ToolTip; -using Wox.Infrastructure.Logger; namespace Wox { @@ -49,6 +48,8 @@ namespace Wox private ToolTip toolTip = new ToolTip(); private bool ignoreTextChange = false; + private List CurrentContextMenus = new List(); + private string textBeforeEnterContextMenuMode; #endregion @@ -67,6 +68,20 @@ namespace Wox })); } + public void ChangeQueryText(string query, bool selectAll = false) + { + Dispatcher.Invoke(new Action(() => + { + ignoreTextChange = true; + tbQuery.Text = query; + tbQuery.CaretIndex = tbQuery.Text.Length; + if (selectAll) + { + tbQuery.SelectAll(); + } + })); + } + public void CloseApp() { Dispatcher.Invoke(new Action(() => @@ -133,8 +148,7 @@ namespace Wox public event WoxKeyDownEventHandler BackKeyDownEvent; public event WoxGlobalKeyboardEventHandler GlobalKeyboardEvent; - public event AfterWoxQueryEventHandler AfterWoxQueryEvent; - public event AfterWoxQueryEventHandler BeforeWoxQueryEvent; + public event ResultItemDropEventHandler ResultItemDropEvent; public void PushResults(Query query, PluginMetadata plugin, List results) { @@ -143,18 +157,27 @@ namespace Wox o.PluginDirectory = plugin.PluginDirectory; o.PluginID = plugin.ID; o.OriginQuery = query; - if (o.ContextMenu != null) - { - o.ContextMenu.ForEach(t => - { - t.PluginDirectory = plugin.PluginDirectory; - t.PluginID = plugin.ID; - }); - } }); UpdateResultView(results); } + public void ShowContextMenu(PluginMetadata plugin, List results) + { + if (results != null && results.Count > 0) + { + results.ForEach(o => + { + o.PluginDirectory = plugin.PluginDirectory; + o.PluginID = plugin.ID; + o.ContextMenu = null; + }); + pnlContextMenu.Clear(); + pnlContextMenu.AddResults(results); + pnlContextMenu.Visibility = Visibility.Visible; + pnlResult.Visibility = Visibility.Collapsed; + } + } + #endregion public MainWindow() @@ -168,6 +191,7 @@ namespace Wox progressBar.ToolTip = toolTip; InitialTray(); pnlResult.LeftMouseClickEvent += SelectResult; + pnlResult.ItemDropEvent += pnlResult_ItemDropEvent; pnlContextMenu.LeftMouseClickEvent += SelectResult; pnlResult.RightMouseClickEvent += pnlResult_RightMouseClickEvent; @@ -192,6 +216,21 @@ namespace Wox }); } + void pnlResult_ItemDropEvent(Result result, IDataObject dropDataObject, DragEventArgs args) + { + PluginPair pluginPair = PluginManager.AllPlugins.FirstOrDefault(o => o.Metadata.ID == result.PluginID); + if (ResultItemDropEvent != null && pluginPair != null) + { + foreach (var delegateHandler in ResultItemDropEvent.GetInvocationList()) + { + if (delegateHandler.Target == pluginPair.Plugin) + { + delegateHandler.DynamicInvoke(result, dropDataObject, args); + } + } + } + } + private bool KListener_hookedKeyboardCallback(KeyEvent keyevent, int vkcode, SpecialKeyState state) { if (GlobalKeyboardEvent != null) @@ -243,7 +282,7 @@ namespace Wox private void CheckUpdate() { - UpdaterManager.Instance.PrepareUpdateReady+=OnPrepareUpdateReady; + UpdaterManager.Instance.PrepareUpdateReady += OnPrepareUpdateReady; UpdaterManager.Instance.UpdateError += OnUpdateError; UpdaterManager.Instance.CheckUpdate(); } @@ -343,13 +382,45 @@ namespace Wox notifyIcon.ContextMenu = new ContextMenu(childen); } + private void QueryContextMenu() + { + pnlContextMenu.Clear(); + var query = tbQuery.Text.ToLower(); + if (string.IsNullOrEmpty(query)) + { + pnlContextMenu.AddResults(CurrentContextMenus); + } + else + { + List filterResults = new List(); + foreach (Result contextMenu in CurrentContextMenus) + { + if (StringMatcher.IsMatch(contextMenu.Title, query) + || StringMatcher.IsMatch(contextMenu.SubTitle, query)) + { + filterResults.Add(contextMenu); + } + } + pnlContextMenu.AddResults(filterResults); + } + } + private void TextBoxBase_OnTextChanged(object sender, TextChangedEventArgs e) { if (ignoreTextChange) { ignoreTextChange = false; return; } - lastQuery = tbQuery.Text; toolTip.IsOpen = false; pnlResult.Dirty = true; + + if (IsInContextMenuMode) + { + QueryContextMenu(); + return; + } + + lastQuery = tbQuery.Text; + int searchDelay = GetSearchDelay(lastQuery); + Dispatcher.DelayInvoke("UpdateSearch", o => { @@ -363,7 +434,7 @@ namespace Wox }, TimeSpan.FromMilliseconds(100), null); queryHasReturn = false; Query query = new Query(lastQuery); - FireBeforeWoxQueryEvent(query); + query.IsIntantQuery = searchDelay == 0; Query(query); Dispatcher.DelayInvoke("ShowProgressbar", originQuery => { @@ -372,60 +443,36 @@ namespace Wox StartProgress(); } }, TimeSpan.FromMilliseconds(150), tbQuery.Text); - FireAfterWoxQueryEvent(query); - }, TimeSpan.FromMilliseconds(GetSearchDelay(lastQuery))); + //reset query history index after user start new query + ResetQueryHistoryIndex(); + }, TimeSpan.FromMilliseconds(searchDelay)); } + private void ResetQueryHistoryIndex() + { + QueryHistoryStorage.Instance.Reset(); + } private int GetSearchDelay(string query) { - if (!string.IsNullOrEmpty(query) && PluginManager.IsInstantSearch(query)) + if (!string.IsNullOrEmpty(query) && PluginManager.IsInstantQuery(query)) { + DebugHelper.WriteLine("execute query without delay"); return 0; } + + DebugHelper.WriteLine("execute query with 200ms delay"); return 200; } - private void FireAfterWoxQueryEvent(Query q) - { - if (AfterWoxQueryEvent != null) - { - //We shouldn't let those events slow down real query - //so I put it in the new thread - ThreadPool.QueueUserWorkItem(o => - { - AfterWoxQueryEvent(new WoxQueryEventArgs() - { - Query = q - }); - }); - } - } - - private void FireBeforeWoxQueryEvent(Query q) - { - if (BeforeWoxQueryEvent != null) - { - //We shouldn't let those events slow down real query - //so I put it in the new thread - ThreadPool.QueueUserWorkItem(o => - { - BeforeWoxQueryEvent(new WoxQueryEventArgs() - { - Query = q - }); - }); - } - } - private void Query(Query q) { PluginManager.Query(q); StopProgress(); - BackToResultMode(); } private void BackToResultMode() { + ChangeQueryText(textBeforeEnterContextMenuMode); pnlResult.Visibility = Visibility.Visible; pnlContextMenu.Visibility = Visibility.Collapsed; } @@ -447,6 +494,10 @@ namespace Wox private void HideWox() { + if (IsInContextMenuMode) + { + BackToResultMode(); + } Hide(); } @@ -467,6 +518,7 @@ namespace Wox Activate(); Focus(); tbQuery.Focus(); + ResetQueryHistoryIndex(); if (selectAll) tbQuery.SelectAll(); } @@ -508,25 +560,81 @@ namespace Wox e.Handled = true; break; + case Key.N: + case Key.J: + if (GlobalHotkey.Instance.CheckModifiers().CtrlPressed) + { + SelectNextItem(); + } + break; + + case Key.P: + case Key.K: + if (GlobalHotkey.Instance.CheckModifiers().CtrlPressed) + { + SelectPrevItem(); + } + break; + + case Key.O: + if (GlobalHotkey.Instance.CheckModifiers().CtrlPressed) + { + if (IsInContextMenuMode) + { + BackToResultMode(); + } + else + { + ShowContextMenu(GetActiveResult()); + } + } + break; + case Key.Down: - SelectNextItem(); + if (GlobalHotkey.Instance.CheckModifiers().CtrlPressed) + { + DisplayNextQuery(); + } + else + { + SelectNextItem(); + } e.Handled = true; break; case Key.Up: - SelectPrevItem(); + if (GlobalHotkey.Instance.CheckModifiers().CtrlPressed) + { + DisplayPrevQuery(); + } + else + { + SelectPrevItem(); + } e.Handled = true; break; + case Key.D: + if (GlobalHotkey.Instance.CheckModifiers().CtrlPressed) + { + pnlResult.SelectNextPage(); + } + break; + case Key.PageDown: pnlResult.SelectNextPage(); - toolTip.IsOpen = false; e.Handled = true; break; + case Key.U: + if (GlobalHotkey.Instance.CheckModifiers().CtrlPressed) + { + pnlResult.SelectPrevPage(); + } + break; + case Key.PageUp: pnlResult.SelectPrevPage(); - toolTip.IsOpen = false; e.Handled = true; break; @@ -584,6 +692,42 @@ namespace Wox } } + private void DisplayPrevQuery() + { + var prev = QueryHistoryStorage.Instance.Previous(); + DisplayQueryHistory(prev); + } + + private void DisplayNextQuery() + { + var nextQuery = QueryHistoryStorage.Instance.Next(); + DisplayQueryHistory(nextQuery); + } + + private void DisplayQueryHistory(HistoryItem history) + { + if (history != null) + { + ChangeQueryText(history.Query, true); + pnlResult.Dirty = true; + var executeQueryHistoryTitle = GetTranslation("executeQuery"); + var lastExecuteTime = GetTranslation("lastExecuteTime"); + UpdateResultViewInternal(new List() + { + new Result(){ + Title = string.Format(executeQueryHistoryTitle,history.Query), + SubTitle = string.Format(lastExecuteTime,history.ExecutedDateTime), + IcoPath = "Images\\history.png", + PluginDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), + Action = _ =>{ + ChangeQuery(history.Query,true); + return false; + } + } + }); + } + } + private void SelectItem(int index) { int zeroBasedIndex = index - 1; @@ -656,6 +800,7 @@ namespace Wox HideWox(); } UserSelectedRecordStorage.Instance.Add(result); + QueryHistoryStorage.Instance.Add(tbQuery.Text); } } } @@ -673,22 +818,67 @@ namespace Wox o.Score += UserSelectedRecordStorage.Instance.GetSelectedCount(o) * 5; }); List l = list.Where(o => o.OriginQuery != null && o.OriginQuery.RawQuery == lastQuery).ToList(); - Dispatcher.Invoke(new Action(() => + UpdateResultViewInternal(l); + } + } + + private void UpdateResultViewInternal(List list) + { + Dispatcher.Invoke(new Action(() => + { + pnlResult.AddResults(list); + })); + } + + private Result GetTopMostContextMenu(Result result) + { + if (TopMostRecordStorage.Instance.IsTopMost(result)) + { + return new Result(GetTranslation("cancelTopMostInThisQuery"), "Images\\down.png") { - pnlResult.AddResults(l); - })); + PluginDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), + Action = _ => + { + TopMostRecordStorage.Instance.Remove(result); + ShowMsg("Succeed", "", ""); + return false; + } + }; + } + else + { + return new Result(GetTranslation("setAsTopMostInThisQuery"), "Images\\up.png") + { + PluginDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), + Action = _ => + { + TopMostRecordStorage.Instance.AddOrUpdate(result); + ShowMsg("Succeed", "", ""); + return false; + } + }; } } private void ShowContextMenu(Result result) { - if (result.ContextMenu != null && result.ContextMenu.Count > 0) + List results = PluginManager.GetPluginContextMenus(result); + results.ForEach(o => { - pnlContextMenu.Clear(); - pnlContextMenu.AddResults(result.ContextMenu); - pnlContextMenu.Visibility = Visibility.Visible; - pnlResult.Visibility = Visibility.Collapsed; - } + o.PluginDirectory = PluginManager.GetPlugin(result.PluginID).Metadata.PluginDirectory; + o.PluginID = result.PluginID; + o.OriginQuery = result.OriginQuery; + }); + + results.Add(GetTopMostContextMenu(result)); + + textBeforeEnterContextMenuMode = tbQuery.Text; + ChangeQueryText(""); + pnlContextMenu.Clear(); + pnlContextMenu.AddResults(results); + CurrentContextMenus = results; + pnlContextMenu.Visibility = Visibility.Visible; + pnlResult.Visibility = Visibility.Collapsed; } public bool ShellRun(string cmd, bool runAsAdministrator = false) diff --git a/Wox/Msg.xaml b/Wox/Msg.xaml index f99c9d0bf..aa2474704 100644 --- a/Wox/Msg.xaml +++ b/Wox/Msg.xaml @@ -27,7 +27,7 @@ - + Title diff --git a/Wox/Msg.xaml.cs b/Wox/Msg.xaml.cs index bf61c06ab..9f9801cf3 100644 --- a/Wox/Msg.xaml.cs +++ b/Wox/Msg.xaml.cs @@ -57,8 +57,11 @@ namespace Wox { public void Show(string title, string subTitle, string icopath) { tbTitle.Text = title; tbSubTitle.Text = subTitle; + if (string.IsNullOrEmpty(subTitle)) + { + tbSubTitle.Visibility = Visibility.Collapsed; + } if (!File.Exists(icopath)) { - //icopath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath), "Images\\app.png"); imgIco.Source = new BitmapImage(new Uri("Images\\app.png", UriKind.Relative)); } else { diff --git a/Wox/Properties/AssemblyInfo.cs b/Wox/Properties/AssemblyInfo.cs index 525979aae..b4d5aea91 100644 --- a/Wox/Properties/AssemblyInfo.cs +++ b/Wox/Properties/AssemblyInfo.cs @@ -19,4 +19,5 @@ using System.Windows; ResourceDictionaryLocation.SourceAssembly )] [assembly: AssemblyVersion("1.1.0")] -[assembly: AssemblyFileVersion("1.1.0")] \ No newline at end of file +[assembly: AssemblyFileVersion("1.1.0")] +[assembly: Exceptionless.Configuration.Exceptionless("e0b256fbe9384498ba89aae2a6b7f8ab")] \ No newline at end of file diff --git a/Wox/ResultPanel.xaml b/Wox/ResultPanel.xaml index a156d6fc1..26b18f4f1 100644 --- a/Wox/ResultPanel.xaml +++ b/Wox/ResultPanel.xaml @@ -7,7 +7,7 @@ mc:Ignorable="d" d:DesignWidth="100" d:DesignHeight="100"> - + @@ -24,7 +24,7 @@ - + @@ -36,13 +36,12 @@ - + - diff --git a/Wox/ResultPanel.xaml.cs b/Wox/ResultPanel.xaml.cs index 7274a8c54..21251bb01 100644 --- a/Wox/ResultPanel.xaml.cs +++ b/Wox/ResultPanel.xaml.cs @@ -8,6 +8,7 @@ using System.Windows.Input; using System.Windows.Media; using Wox.Helper; using Wox.Plugin; +using Wox.Storage; using UserControl = System.Windows.Controls.UserControl; namespace Wox @@ -16,6 +17,7 @@ namespace Wox { public event Action LeftMouseClickEvent; public event Action RightMouseClickEvent; + public event Action ItemDropEvent; protected virtual void OnRightMouseClick(Result result) { @@ -33,7 +35,6 @@ namespace Wox public void AddResults(List results) { - if (Dirty) { Dirty = false; @@ -41,13 +42,30 @@ namespace Wox } foreach (var result in results) { - int position = GetInsertLocation(result.Score); + int position = 0; + if (IsTopMostResult(result)) + { + result.Score = int.MaxValue; + } + else + { + if (result.Score >= int.MaxValue) + { + result.Score = int.MaxValue - 1; + } + position = GetInsertLocation(result.Score); + } lbResults.Items.Insert(position, result); } lbResults.Margin = lbResults.Items.Count > 0 ? new Thickness { Top = 8 } : new Thickness { Top = 0 }; SelectFirst(); } + private bool IsTopMostResult(Result result) + { + return TopMostRecordStorage.Instance.IsTopMost(result); + } + private int GetInsertLocation(int currentScore) { int location = lbResults.Items.Count; @@ -112,21 +130,57 @@ namespace Wox public List GetVisibleResults() { - var theStackPanel = GetInnerStackPanel(lbResults); List visibleElements = new List(); - - for (int i = 0; i < theStackPanel.Children.Count; i++) + VirtualizingStackPanel virtualizingStackPanel = GetInnerStackPanel(lbResults); + for (int i = (int)virtualizingStackPanel.VerticalOffset; i <= virtualizingStackPanel.VerticalOffset + virtualizingStackPanel.ViewportHeight; i++) { - - if (i >= theStackPanel.VerticalOffset && i <= theStackPanel.VerticalOffset + theStackPanel.ViewportHeight) + ListBoxItem item = lbResults.ItemContainerGenerator.ContainerFromIndex(i) as ListBoxItem; + if (item != null) { - FrameworkElement element = theStackPanel.Children[i] as FrameworkElement; - visibleElements.Add(element.DataContext as Result); + visibleElements.Add(item.DataContext as Result); } } return visibleElements; } + private void UpdateItemNumber() + { + //VirtualizingStackPanel virtualizingStackPanel = GetInnerStackPanel(lbResults); + //int index = 0; + //for (int i = (int)virtualizingStackPanel.VerticalOffset; i <= virtualizingStackPanel.VerticalOffset + virtualizingStackPanel.ViewportHeight; i++) + //{ + // index++; + // ListBoxItem item = lbResults.ItemContainerGenerator.ContainerFromIndex(i) as ListBoxItem; + // if (item != null) + // { + // ContentPresenter myContentPresenter = FindVisualChild(item); + // if (myContentPresenter != null) + // { + // DataTemplate dataTemplate = myContentPresenter.ContentTemplate; + // TextBlock tbItemNumber = (TextBlock)dataTemplate.FindName("tbItemNumber", myContentPresenter); + // tbItemNumber.Text = index.ToString(); + // } + // } + //} + } + + private childItem FindVisualChild(DependencyObject obj) where childItem : DependencyObject + { + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) + { + DependencyObject child = VisualTreeHelper.GetChild(obj, i); + if (child != null && child is childItem) + return (childItem)child; + else + { + childItem childOfChild = FindVisualChild(child); + if (childOfChild != null) + return childOfChild; + } + } + return null; + } + private VirtualizingStackPanel GetInnerStackPanel(FrameworkElement element) { for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++) @@ -171,6 +225,10 @@ namespace Wox if (e.AddedItems.Count > 0 && e.AddedItems[0] != null) { lbResults.ScrollIntoView(e.AddedItems[0]); + Dispatcher.DelayInvoke("UpdateItemNumber", o => + { + UpdateItemNumber(); + }, TimeSpan.FromMilliseconds(3)); } } @@ -208,5 +266,20 @@ namespace Wox } Select(index); } + + private void ListBoxItem_OnDrop(object sender, DragEventArgs e) + { + var item = ItemsControl.ContainerFromElement(lbResults, e.OriginalSource as DependencyObject) as ListBoxItem; + if (item != null) + { + OnItemDropEvent(item.DataContext as Result, e.Data, e); + } + } + + protected virtual void OnItemDropEvent(Result obj, IDataObject data, DragEventArgs e) + { + var handler = ItemDropEvent; + if (handler != null) handler(obj, data, e); + } } } \ No newline at end of file diff --git a/Wox/SettingWindow.xaml b/Wox/SettingWindow.xaml index 99f0237d2..29043715d 100644 --- a/Wox/SettingWindow.xaml +++ b/Wox/SettingWindow.xaml @@ -19,7 +19,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -95,10 +95,12 @@ - + + + @@ -111,7 +113,7 @@ - + @@ -186,29 +188,12 @@ - - - - Normal - LayeredWindow - DWM - - - - - - - - - - - - + diff --git a/Wox/SettingWindow.xaml.cs b/Wox/SettingWindow.xaml.cs index b607281b0..019f80593 100644 --- a/Wox/SettingWindow.xaml.cs +++ b/Wox/SettingWindow.xaml.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Net; +using System.Threading; using System.Windows; using System.Windows.Controls; using System.Windows.Input; @@ -17,19 +18,26 @@ using Application = System.Windows.Forms.Application; using File = System.IO.File; using MessageBox = System.Windows.MessageBox; using System.Windows.Data; +using System.Windows.Forms; using Microsoft.Win32; using Wox.Core.i18n; using Wox.Core.Theme; using Wox.Core.Updater; using Wox.Core.UserSettings; +using Wox.Infrastructure; +using CheckBox = System.Windows.Controls.CheckBox; +using Control = System.Windows.Controls.Control; +using Cursors = System.Windows.Input.Cursors; +using HorizontalAlignment = System.Windows.HorizontalAlignment; namespace Wox { public partial class SettingWindow : Window { - public MainWindow MainWindow; + public readonly MainWindow MainWindow; bool settingsLoaded = false; private Dictionary featureControls = new Dictionary(); + private bool themeTabLoaded = false; public SettingWindow(MainWindow mainWindow) { @@ -74,8 +82,198 @@ namespace Wox #endregion - #region Theme + #region Proxy + cbEnableProxy.Checked += (o, e) => EnableProxy(); + cbEnableProxy.Unchecked += (o, e) => DisableProxy(); + cbEnableProxy.IsChecked = UserSettingStorage.Instance.ProxyEnabled; + tbProxyServer.Text = UserSettingStorage.Instance.ProxyServer; + tbProxyPort.Text = UserSettingStorage.Instance.ProxyPort.ToString(); + tbProxyUserName.Text = UserSettingStorage.Instance.ProxyUserName; + tbProxyPassword.Password = UserSettingStorage.Instance.ProxyPassword; + if (UserSettingStorage.Instance.ProxyEnabled) + { + EnableProxy(); + } + else + { + DisableProxy(); + } + + #endregion + + #region About + + tbVersion.Text = UpdaterManager.Instance.CurrentVersion.ToString(); + string activateTimes = string.Format(InternationalizationManager.Instance.GetTranslation("about_activate_times"), + UserSettingStorage.Instance.ActivateTimes); + tbActivatedTimes.Text = activateTimes; + + #endregion + + settingsLoaded = true; + } + + #region General + + private void LoadLanguages() + { + cbLanguages.ItemsSource = InternationalizationManager.Instance.LoadAvailableLanguages(); + cbLanguages.DisplayMemberPath = "Display"; + cbLanguages.SelectedValuePath = "LanguageCode"; + cbLanguages.SelectedValue = UserSettingStorage.Instance.Language; + cbLanguages.SelectionChanged += cbLanguages_SelectionChanged; + } + + void cbLanguages_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + InternationalizationManager.Instance.ChangeLanguage(cbLanguages.SelectedItem as Language); + } + + private void CbStartWithWindows_OnChecked(object sender, RoutedEventArgs e) + { + AddApplicationToStartup(); + UserSettingStorage.Instance.StartWoxOnSystemStartup = true; + UserSettingStorage.Instance.Save(); + } + + private void CbStartWithWindows_OnUnchecked(object sender, RoutedEventArgs e) + { + RemoveApplicationFromStartup(); + UserSettingStorage.Instance.StartWoxOnSystemStartup = false; + UserSettingStorage.Instance.Save(); + } + + private void AddApplicationToStartup() + { + using (RegistryKey key = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true)) + { + key.SetValue("Wox", "\"" + Application.ExecutablePath + "\" --hidestart"); + } + } + + private void RemoveApplicationFromStartup() + { + using (RegistryKey key = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true)) + { + key.DeleteValue("Wox", false); + } + } + + private bool CheckApplicationIsStartupWithWindow() + { + using (RegistryKey key = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true)) + { + return key.GetValue("Wox") != null; + } + } + + #endregion + + #region Hotkey + + void ctlHotkey_OnHotkeyChanged(object sender, System.EventArgs e) + { + if (ctlHotkey.CurrentHotkeyAvailable) + { + MainWindow.SetHotkey(ctlHotkey.CurrentHotkey.ToString(), delegate + { + if (!MainWindow.IsVisible) + { + MainWindow.ShowApp(); + } + else + { + MainWindow.HideApp(); + } + }); + MainWindow.RemoveHotkey(UserSettingStorage.Instance.Hotkey); + UserSettingStorage.Instance.Hotkey = ctlHotkey.CurrentHotkey.ToString(); + UserSettingStorage.Instance.Save(); + } + } + + + private void TabHotkey_OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + var tabItem = sender as TabItem; + var clickingBody = (tabItem.Content as UIElement).IsMouseOver; + if (!clickingBody) + { + OnHotkeyTabSelected(); + } + } + + private void OnHotkeyTabSelected() + { + ctlHotkey.OnHotkeyChanged += ctlHotkey_OnHotkeyChanged; + ctlHotkey.SetHotkey(UserSettingStorage.Instance.Hotkey, false); + lvCustomHotkey.ItemsSource = UserSettingStorage.Instance.CustomPluginHotkeys; + } + + private void BtnDeleteCustomHotkey_OnClick(object sender, RoutedEventArgs e) + { + CustomPluginHotkey item = lvCustomHotkey.SelectedItem as CustomPluginHotkey; + if (item == null) + { + MessageBox.Show(InternationalizationManager.Instance.GetTranslation("pleaseSelectAnItem")); + return; + } + + string deleteWarning = string.Format(InternationalizationManager.Instance.GetTranslation("deleteCustomHotkeyWarning"), item.Hotkey); + if (MessageBox.Show(deleteWarning, InternationalizationManager.Instance.GetTranslation("delete"), MessageBoxButton.YesNo) == MessageBoxResult.Yes) + { + UserSettingStorage.Instance.CustomPluginHotkeys.Remove(item); + lvCustomHotkey.Items.Refresh(); + UserSettingStorage.Instance.Save(); + MainWindow.RemoveHotkey(item.Hotkey); + } + } + + private void BtnEditCustomHotkey_OnClick(object sender, RoutedEventArgs e) + { + CustomPluginHotkey item = lvCustomHotkey.SelectedItem as CustomPluginHotkey; + if (item != null) + { + CustomQueryHotkeySetting window = new CustomQueryHotkeySetting(this); + window.UpdateItem(item); + window.ShowDialog(); + } + else + { + MessageBox.Show(InternationalizationManager.Instance.GetTranslation("pleaseSelectAnItem")); + } + } + + private void BtnAddCustomeHotkey_OnClick(object sender, RoutedEventArgs e) + { + new CustomQueryHotkeySetting(this).ShowDialog(); + } + + public void ReloadCustomPluginHotkeyView() + { + lvCustomHotkey.Items.Refresh(); + } + + #endregion + + #region Theme + + private void tbMoreThemes_MouseUp(object sender, MouseButtonEventArgs e) + { + Process.Start("http://www.getwox.com/theme"); + } + + private void OnThemeTabSelected() + { + using (new Timeit("theme load")) + { + var s = Fonts.SystemFontFamilies; + } + + if (themeTabLoaded) return; + + themeTabLoaded = true; if (!string.IsNullOrEmpty(UserSettingStorage.Instance.QueryBoxFont) && Fonts.SystemFontFamilies.Count(o => o.FamilyNames.Values.Contains(UserSettingStorage.Instance.QueryBoxFont)) > 0) { @@ -98,6 +296,7 @@ namespace Wox UserSettingStorage.Instance.ResultItemFontStretch )); } + resultPanelPreview.AddResults(new List() { new Result() @@ -157,8 +356,6 @@ namespace Wox } themeComboBox.SelectedItem = UserSettingStorage.Instance.Theme; - slOpacity.Value = UserSettingStorage.Instance.Opacity; - CbOpacityMode.SelectedItem = UserSettingStorage.Instance.OpacityMode; var wallpaper = WallpaperPathRetrieval.GetWallpaperPath(); if (wallpaper != null && File.Exists(wallpaper)) @@ -173,203 +370,23 @@ namespace Wox PreviewPanel.Background = new SolidColorBrush(wallpaperColor); } - //PreviewPanel - ThemeManager.Theme.ChangeTheme(UserSettingStorage.Instance.Theme); - #endregion + } - #region Plugin - - ctlHotkey.OnHotkeyChanged += ctlHotkey_OnHotkeyChanged; - ctlHotkey.SetHotkey(UserSettingStorage.Instance.Hotkey, false); - lvCustomHotkey.ItemsSource = UserSettingStorage.Instance.CustomPluginHotkeys; - - var plugins = new CompositeCollection + private void TabTheme_OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + var tabItem = sender as TabItem; + var clickingBody = (tabItem.Content as UIElement).IsMouseOver; + if (!clickingBody) { - new CollectionContainer - { - Collection = PluginManager.AllPlugins - } - }; - lbPlugins.ItemsSource = plugins; - lbPlugins.SelectedIndex = 0; - - #endregion - - #region Proxy - - cbEnableProxy.Checked += (o, e) => EnableProxy(); - cbEnableProxy.Unchecked += (o, e) => DisableProxy(); - cbEnableProxy.IsChecked = UserSettingStorage.Instance.ProxyEnabled; - tbProxyServer.Text = UserSettingStorage.Instance.ProxyServer; - tbProxyPort.Text = UserSettingStorage.Instance.ProxyPort.ToString(); - tbProxyUserName.Text = UserSettingStorage.Instance.ProxyUserName; - tbProxyPassword.Password = UserSettingStorage.Instance.ProxyPassword; - if (UserSettingStorage.Instance.ProxyEnabled) - { - EnableProxy(); - } - else - { - DisableProxy(); - } - - #endregion - - #region About - - tbVersion.Text = UpdaterManager.Instance.CurrentVersion.ToString(); - string activateTimes = string.Format(InternationalizationManager.Instance.GetTranslation("about_activate_times"), - UserSettingStorage.Instance.ActivateTimes); - tbActivatedTimes.Text = activateTimes; - - #endregion - - settingsLoaded = true; - } - - private void LoadLanguages() - { - cbLanguages.ItemsSource = InternationalizationManager.Instance.LoadAvailableLanguages(); - cbLanguages.DisplayMemberPath = "Display"; - cbLanguages.SelectedValuePath = "LanguageCode"; - cbLanguages.SelectedValue = UserSettingStorage.Instance.Language; - cbLanguages.SelectionChanged += cbLanguages_SelectionChanged; - } - - void cbLanguages_SelectionChanged(object sender, SelectionChangedEventArgs e) - { - InternationalizationManager.Instance.ChangeLanguage(cbLanguages.SelectedItem as Language); - } - - private void EnableProxy() - { - tbProxyPassword.IsEnabled = true; - tbProxyServer.IsEnabled = true; - tbProxyUserName.IsEnabled = true; - tbProxyPort.IsEnabled = true; - } - - private void DisableProxy() - { - tbProxyPassword.IsEnabled = false; - tbProxyServer.IsEnabled = false; - tbProxyUserName.IsEnabled = false; - tbProxyPort.IsEnabled = false; - } - - private void CbStartWithWindows_OnChecked(object sender, RoutedEventArgs e) - { - AddApplicationToStartup(); - UserSettingStorage.Instance.StartWoxOnSystemStartup = true; - UserSettingStorage.Instance.Save(); - } - - private void CbStartWithWindows_OnUnchecked(object sender, RoutedEventArgs e) - { - RemoveApplicationFromStartup(); - UserSettingStorage.Instance.StartWoxOnSystemStartup = false; - UserSettingStorage.Instance.Save(); - } - - private void AddApplicationToStartup() - { - using (RegistryKey key = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true)) - { - key.SetValue("Wox", "\"" + Application.ExecutablePath + "\" --hidestart"); + OnThemeTabSelected(); } } - private void RemoveApplicationFromStartup() - { - using (RegistryKey key = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true)) - { - key.DeleteValue("Wox", false); - } - } - - private bool CheckApplicationIsStartupWithWindow() - { - using (RegistryKey key = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true)) - { - return key.GetValue("Wox") != null; - } - } - - void ctlHotkey_OnHotkeyChanged(object sender, System.EventArgs e) - { - if (ctlHotkey.CurrentHotkeyAvailable) - { - MainWindow.SetHotkey(ctlHotkey.CurrentHotkey.ToString(), delegate - { - if (!MainWindow.IsVisible) - { - MainWindow.ShowApp(); - } - else - { - MainWindow.HideApp(); - } - }); - MainWindow.RemoveHotkey(UserSettingStorage.Instance.Hotkey); - UserSettingStorage.Instance.Hotkey = ctlHotkey.CurrentHotkey.ToString(); - UserSettingStorage.Instance.Save(); - } - } - - #region Custom Plugin Hotkey - - private void BtnDeleteCustomHotkey_OnClick(object sender, RoutedEventArgs e) - { - CustomPluginHotkey item = lvCustomHotkey.SelectedItem as CustomPluginHotkey; - if (item == null) - { - MessageBox.Show(InternationalizationManager.Instance.GetTranslation("pleaseSelectAnItem")); - return; - } - - string deleteWarning = string.Format(InternationalizationManager.Instance.GetTranslation("deleteCustomHotkeyWarning"), item.Hotkey); - if (MessageBox.Show(deleteWarning, InternationalizationManager.Instance.GetTranslation("delete"), MessageBoxButton.YesNo) == MessageBoxResult.Yes) - { - UserSettingStorage.Instance.CustomPluginHotkeys.Remove(item); - lvCustomHotkey.Items.Refresh(); - UserSettingStorage.Instance.Save(); - MainWindow.RemoveHotkey(item.Hotkey); - } - } - - private void BtnEditCustomHotkey_OnClick(object sender, RoutedEventArgs e) - { - CustomPluginHotkey item = lvCustomHotkey.SelectedItem as CustomPluginHotkey; - if (item != null) - { - CustomQueryHotkeySetting window = new CustomQueryHotkeySetting(this); - window.UpdateItem(item); - window.ShowDialog(); - } - else - { - MessageBox.Show(InternationalizationManager.Instance.GetTranslation("pleaseSelectAnItem")); - } - } - - private void BtnAddCustomeHotkey_OnClick(object sender, RoutedEventArgs e) - { - new CustomQueryHotkeySetting(this).ShowDialog(); - } - - public void ReloadCustomPluginHotkeyView() - { - lvCustomHotkey.Items.Refresh(); - } - - #endregion - - #region Theme private void ThemeComboBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e) { string themeName = themeComboBox.SelectedItem.ToString(); - ThemeManager.Theme.ChangeTheme(themeName); UserSettingStorage.Instance.Theme = themeName; + DelayChangeTheme(); UserSettingStorage.Instance.Save(); } @@ -379,9 +396,16 @@ namespace Wox string queryBoxFontName = cbQueryBoxFont.SelectedItem.ToString(); UserSettingStorage.Instance.QueryBoxFont = queryBoxFontName; this.cbQueryBoxFontFaces.SelectedItem = ((FontFamily)cbQueryBoxFont.SelectedItem).ChooseRegularFamilyTypeface(); - + DelayChangeTheme(); UserSettingStorage.Instance.Save(); - ThemeManager.Theme.ChangeTheme(UserSettingStorage.Instance.Theme); + } + + private void DelayChangeTheme() + { + Dispatcher.DelayInvoke("delayChangeTheme", o => + { + ThemeManager.Theme.ChangeTheme(UserSettingStorage.Instance.Theme); + }, TimeSpan.FromMilliseconds(100)); } private void CbQueryBoxFontFaces_OnSelectionChanged(object sender, SelectionChangedEventArgs e) @@ -401,7 +425,7 @@ namespace Wox UserSettingStorage.Instance.QueryBoxFontWeight = typeface.Weight.ToString(); UserSettingStorage.Instance.QueryBoxFontStyle = typeface.Style.ToString(); UserSettingStorage.Instance.Save(); - ThemeManager.Theme.ChangeTheme(UserSettingStorage.Instance.Theme); + DelayChangeTheme(); } } @@ -413,7 +437,7 @@ namespace Wox this.cbResultItemFontFaces.SelectedItem = ((FontFamily)cbResultItemFont.SelectedItem).ChooseRegularFamilyTypeface(); UserSettingStorage.Instance.Save(); - ThemeManager.Theme.ChangeTheme(UserSettingStorage.Instance.Theme); + DelayChangeTheme(); } private void CbResultItemFontFaces_OnSelectionChanged(object sender, SelectionChangedEventArgs e) @@ -431,39 +455,13 @@ namespace Wox UserSettingStorage.Instance.ResultItemFontWeight = typeface.Weight.ToString(); UserSettingStorage.Instance.ResultItemFontStyle = typeface.Style.ToString(); UserSettingStorage.Instance.Save(); - ThemeManager.Theme.ChangeTheme(UserSettingStorage.Instance.Theme); + DelayChangeTheme(); } } - private void slOpacity_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) - { - UserSettingStorage.Instance.Opacity = slOpacity.Value; - - if (UserSettingStorage.Instance.OpacityMode == OpacityMode.LayeredWindow) - PreviewMainPanel.Opacity = UserSettingStorage.Instance.Opacity; - else - PreviewMainPanel.Opacity = 1; - - ThemeManager.Theme.ChangeTheme(UserSettingStorage.Instance.Theme); - Dispatcher.DelayInvoke("delaySaveUserSetting", o => - { - UserSettingStorage.Instance.Save(); - }, TimeSpan.FromMilliseconds(1000)); - } #endregion - private void CbOpacityMode_OnSelectionChanged(object sender, SelectionChangedEventArgs e) - { - UserSettingStorage.Instance.OpacityMode = (OpacityMode)CbOpacityMode.SelectedItem; - UserSettingStorage.Instance.Save(); - - spOpacity.Visibility = UserSettingStorage.Instance.OpacityMode == OpacityMode.LayeredWindow ? Visibility.Visible : Visibility.Collapsed; - - if (UserSettingStorage.Instance.OpacityMode == OpacityMode.LayeredWindow) - PreviewMainPanel.Opacity = UserSettingStorage.Instance.Opacity; - else - PreviewMainPanel.Opacity = 1; - } + #region Plugin private void lbPlugins_OnSelectionChanged(object sender, SelectionChangedEventArgs e) { @@ -473,10 +471,13 @@ namespace Wox if (pair != null) { - //third-party plugin provider = pair.Plugin as ISettingProvider; pluginAuthor.Visibility = Visibility.Visible; pluginActionKeyword.Visibility = Visibility.Visible; + pluginInitTime.Text = + string.Format(InternationalizationManager.Instance.GetTranslation("plugin_init_time"), pair.InitTime); + pluginQueryTime.Text = + string.Format(InternationalizationManager.Instance.GetTranslation("plugin_query_time"), pair.AvgQueryTime); pluginActionKeywordTitle.Visibility = Visibility.Visible; tbOpenPluginDirecoty.Visibility = Visibility.Visible; pluginTitle.Text = pair.Metadata.Name; @@ -487,11 +488,6 @@ namespace Wox pluginId = pair.Metadata.ID; pluginIcon.Source = ImageLoader.ImageLoader.Load(pair.Metadata.FullIcoPath); } - else - { - //system plugin - provider = lbPlugins.SelectedItem as ISettingProvider; - } var customizedPluginConfig = UserSettingStorage.Instance.CustomizedPluginConfigs.FirstOrDefault(o => o.ID == pluginId); cbDisablePlugin.IsChecked = customizedPluginConfig != null && customizedPluginConfig.Disabled; @@ -607,11 +603,33 @@ namespace Wox Process.Start("http://www.getwox.com/plugin"); } - private void tbMoreThemes_MouseUp(object sender, MouseButtonEventArgs e) + private void OnPluginTabSelected() { - Process.Start("http://www.getwox.com/theme"); + var plugins = new CompositeCollection + { + new CollectionContainer + { + Collection = PluginManager.AllPlugins + } + }; + lbPlugins.ItemsSource = plugins; + lbPlugins.SelectedIndex = 0; } + private void TabPlugin_OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + var tabItem = sender as TabItem; + var clickingBody = (tabItem.Content as UIElement).IsMouseOver; + if (!clickingBody) + { + OnPluginTabSelected(); + } + } + + + #endregion + + #region Proxy private void btnSaveProxy_Click(object sender, RoutedEventArgs e) { UserSettingStorage.Instance.ProxyEnabled = cbEnableProxy.IsChecked ?? false; @@ -694,9 +712,31 @@ namespace Wox } } + private void EnableProxy() + { + tbProxyPassword.IsEnabled = true; + tbProxyServer.IsEnabled = true; + tbProxyUserName.IsEnabled = true; + tbProxyPort.IsEnabled = true; + } + + private void DisableProxy() + { + tbProxyPassword.IsEnabled = false; + tbProxyServer.IsEnabled = false; + tbProxyUserName.IsEnabled = false; + tbProxyPort.IsEnabled = false; + } + + #endregion + + #region About + private void tbWebsite_MouseUp(object sender, MouseButtonEventArgs e) { Process.Start("http://www.getwox.com"); } + + #endregion } } diff --git a/Wox/Storage/QueryHistoryStorage.cs b/Wox/Storage/QueryHistoryStorage.cs new file mode 100644 index 000000000..d39ebaad1 --- /dev/null +++ b/Wox/Storage/QueryHistoryStorage.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using Newtonsoft.Json; +using Wox.Infrastructure.Storage; + +namespace Wox.Storage +{ + public class QueryHistoryStorage : JsonStrorage + { + [JsonProperty] + private List History = new List(); + + private int MaxHistory = 300; + private int cursor = 0; + + protected override string ConfigFolder + { + get { return Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Config"); } + } + + protected override string ConfigName + { + get { return "QueryHistory"; } + } + + public HistoryItem Previous() + { + if (History.Count == 0 || cursor == 0) return null; + return History[--cursor]; + } + + public HistoryItem Next() + { + if (History.Count == 0 || cursor >= History.Count - 1) return null; + return History[++cursor]; + } + + public void Reset() + { + cursor = History.Count; + } + + public void Add(string query) + { + if (string.IsNullOrEmpty(query)) return; + if (History.Count > MaxHistory) + { + History.RemoveAt(0); + } + + if (History.Count > 0 && History.Last().Query == query) + { + History.Last().ExecutedDateTime = DateTime.Now; + } + else + { + History.Add(new HistoryItem() + { + Query = query, + ExecutedDateTime = DateTime.Now + }); + } + + if (History.Count % 5 == 0) + { + Save(); + } + + Reset(); + } + + public List GetHistory() + { + return History.OrderByDescending(o => o.ExecutedDateTime).ToList(); + } + } + + public class HistoryItem + { + public string Query { get; set; } + public DateTime ExecutedDateTime { get; set; } + + public string GetTimeAgo() + { + return DateTimeAgo(ExecutedDateTime); + } + + private string DateTimeAgo(DateTime dt) + { + TimeSpan span = DateTime.Now - dt; + if (span.Days > 365) + { + int years = (span.Days / 365); + if (span.Days % 365 != 0) + years += 1; + return String.Format("about {0} {1} ago", + years, years == 1 ? "year" : "years"); + } + if (span.Days > 30) + { + int months = (span.Days / 30); + if (span.Days % 31 != 0) + months += 1; + return String.Format("about {0} {1} ago", + months, months == 1 ? "month" : "months"); + } + if (span.Days > 0) + return String.Format("about {0} {1} ago", + span.Days, span.Days == 1 ? "day" : "days"); + if (span.Hours > 0) + return String.Format("about {0} {1} ago", + span.Hours, span.Hours == 1 ? "hour" : "hours"); + if (span.Minutes > 0) + return String.Format("about {0} {1} ago", + span.Minutes, span.Minutes == 1 ? "minute" : "minutes"); + if (span.Seconds > 5) + return String.Format("about {0} seconds ago", span.Seconds); + if (span.Seconds <= 5) + return "just now"; + return string.Empty; + } + } +} diff --git a/Wox/Storage/TopMostRecordStorage.cs b/Wox/Storage/TopMostRecordStorage.cs new file mode 100644 index 000000000..dc56ed550 --- /dev/null +++ b/Wox/Storage/TopMostRecordStorage.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using Wox.Infrastructure.Storage; + +namespace Wox.Storage +{ + public class TopMostRecordStorage : JsonStrorage + { + public Dictionary records = new Dictionary(); + + protected override string ConfigFolder + { + get { return Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Config"); } + } + + protected override string ConfigName + { + get { return "TopMostRecords"; } + } + + internal bool IsTopMost(Plugin.Result result) + { + return records.Any(o => o.Value.Title == result.Title + && o.Value.SubTitle == result.SubTitle + && o.Value.PluginID == result.PluginID + && o.Key == result.OriginQuery.RawQuery); + } + + internal void Remove(Plugin.Result result) + { + if (records.ContainsKey(result.OriginQuery.RawQuery)) + { + records.Remove(result.OriginQuery.RawQuery); + Save(); + } + } + + internal void AddOrUpdate(Plugin.Result result) + { + if (records.ContainsKey(result.OriginQuery.RawQuery)) + { + records[result.OriginQuery.RawQuery].Title = result.Title; + records[result.OriginQuery.RawQuery].SubTitle = result.SubTitle; + records[result.OriginQuery.RawQuery].PluginID = result.PluginID; + } + else + { + records.Add(result.OriginQuery.RawQuery, new TopMostRecord() + { + PluginID = result.PluginID, + Title = result.Title, + SubTitle = result.SubTitle, + }); + } + + Save(); + } + } + + + public class TopMostRecord + { + public string Title { get; set; } + public string SubTitle { get; set; } + public string PluginID { get; set; } + } +} diff --git a/Wox/Themes/Base.xaml b/Wox/Themes/Base.xaml index afaf5bb9a..39866e052 100644 --- a/Wox/Themes/Base.xaml +++ b/Wox/Themes/Base.xaml @@ -38,6 +38,12 @@ + + + + + + + + + #00AAF6 + + + + diff --git a/Wox/Wox.csproj b/Wox/Wox.csproj index 5102805cd..8ea87a58e 100644 --- a/Wox/Wox.csproj +++ b/Wox/Wox.csproj @@ -62,6 +62,14 @@ + + False + ..\packages\Exceptionless.1.5.2121\lib\net35\Exceptionless.dll + + + False + ..\packages\Exceptionless.1.5.2121\lib\net35\Exceptionless.Models.dll + False ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll @@ -114,7 +122,10 @@ + + + WoxUpdate.xaml @@ -179,6 +190,13 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + + Designer MSBuild:Compile @@ -239,6 +257,11 @@ Designer PreserveNewest + + MSBuild:Compile + Designer + PreserveNewest + Designer MSBuild:Compile @@ -314,9 +337,6 @@ PreserveNewest - - PreserveNewest - PreserveNewest diff --git a/Wox/ias03vpr.pm0 b/Wox/ias03vpr.pm0 new file mode 100644 index 000000000..2bf2868f8 --- /dev/null +++ b/Wox/ias03vpr.pm0 @@ -0,0 +1,850 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Net; +using System.Reflection; +using System.Threading; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Forms; +using System.Windows.Input; +using System.Windows.Media.Animation; +using NHotkey; +using NHotkey.Wpf; +using Wox.Core.i18n; +using Wox.Core.Plugin; +using Wox.Core.Theme; +using Wox.Core.Updater; +using Wox.Core.UserSettings; +using Wox.Helper; +using Wox.Infrastructure; +using Wox.Infrastructure.Hotkey; +using Wox.Plugin; +using Wox.Storage; +using ContextMenu = System.Windows.Forms.ContextMenu; +using DataFormats = System.Windows.DataFormats; +using DragEventArgs = System.Windows.DragEventArgs; +using IDataObject = System.Windows.IDataObject; +using KeyEventArgs = System.Windows.Input.KeyEventArgs; +using MenuItem = System.Windows.Forms.MenuItem; +using MessageBox = System.Windows.MessageBox; +using ToolTip = System.Windows.Controls.ToolTip; + +namespace Wox +{ + public partial class MainWindow : IPublicAPI + { + + #region Properties + + private readonly Storyboard progressBarStoryboard = new Storyboard(); + private NotifyIcon notifyIcon; + private bool queryHasReturn; + private string lastQuery; + private ToolTip toolTip = new ToolTip(); + + private bool ignoreTextChange = false; + + #endregion + + #region Public API + + public void ChangeQuery(string query, bool requery = false) + { + Dispatcher.Invoke(new Action(() => + { + tbQuery.Text = query; + tbQuery.CaretIndex = tbQuery.Text.Length; + if (requery) + { + TextBoxBase_OnTextChanged(null, null); + } + })); + } + + public void CloseApp() + { + Dispatcher.Invoke(new Action(() => + { + notifyIcon.Visible = false; + Close(); + Environment.Exit(0); + })); + } + + public void HideApp() + { + Dispatcher.Invoke(new Action(HideWox)); + } + + public void ShowApp() + { + Dispatcher.Invoke(new Action(() => ShowWox())); + } + + public void ShowMsg(string title, string subTitle, string iconPath) + { + Dispatcher.Invoke(new Action(() => + { + var m = new Msg { Owner = GetWindow(this) }; + m.Show(title, subTitle, iconPath); + })); + } + + public void OpenSettingDialog() + { + Dispatcher.Invoke(new Action(() => WindowOpener.Open(this))); + } + + public void StartLoadingBar() + { + Dispatcher.Invoke(new Action(StartProgress)); + } + + public void StopLoadingBar() + { + Dispatcher.Invoke(new Action(StopProgress)); + } + + public void InstallPlugin(string path) + { + Dispatcher.Invoke(new Action(() => PluginManager.InstallPlugin(path))); + } + + public void ReloadPlugins() + { + Dispatcher.Invoke(new Action(() => PluginManager.Init(this))); + } + + public string GetTranslation(string key) + { + return InternationalizationManager.Instance.GetTranslation(key); + } + + public List GetAllPlugins() + { + return PluginManager.AllPlugins; + } + + public event WoxKeyDownEventHandler BackKeyDownEvent; + public event WoxGlobalKeyboardEventHandler GlobalKeyboardEvent; + public event AfterWoxQueryEventHandler AfterWoxQueryEvent; + public event AfterWoxQueryEventHandler BeforeWoxQueryEvent; + public event ResultItemDropEventHandler ResultItemDropEvent; + + public void PushResults(Query query, PluginMetadata plugin, List results) + { + results.ForEach(o => + { + o.PluginDirectory = plugin.PluginDirectory; + o.PluginID = plugin.ID; + o.OriginQuery = query; + if (o.ContextMenu != null) + { + o.ContextMenu.ForEach(t => + { + t.PluginDirectory = plugin.PluginDirectory; + t.PluginID = plugin.ID; + }); + } + }); + UpdateResultView(results); + } + + public void ShowContextMenu(PluginMetadata plugin, List results) + { + if (results != null && results.Count > 0) + { + results.ForEach(o => + { + o.PluginDirectory = plugin.PluginDirectory; + o.PluginID = plugin.ID; + o.ContextMenu = null; + }); + pnlContextMenu.Clear(); + pnlContextMenu.AddResults(results); + pnlContextMenu.Visibility = Visibility.Visible; + pnlResult.Visibility = Visibility.Collapsed; + } + } + + #endregion + + public MainWindow() + { + InitializeComponent(); + ThreadPool.SetMaxThreads(30, 10); + ThreadPool.SetMinThreads(10, 5); + + WebRequest.RegisterPrefix("data", new DataWebRequestFactory()); + GlobalHotkey.Instance.hookedKeyboardCallback += KListener_hookedKeyboardCallback; + progressBar.ToolTip = toolTip; + InitialTray(); + pnlResult.LeftMouseClickEvent += SelectResult; + pnlResult.ItemDropEvent += pnlResult_ItemDropEvent; + pnlContextMenu.LeftMouseClickEvent += SelectResult; + pnlResult.RightMouseClickEvent += pnlResult_RightMouseClickEvent; + + ThemeManager.Theme.ChangeTheme(UserSettingStorage.Instance.Theme); + InternationalizationManager.Instance.ChangeLanguage(UserSettingStorage.Instance.Language); + + SetHotkey(UserSettingStorage.Instance.Hotkey, OnHotkey); + SetCustomPluginHotkey(); + + Closing += MainWindow_Closing; + //since MainWIndow implement IPublicAPI, so we need to finish ctor MainWindow object before + //PublicAPI invoke in plugin init methods. E.g FolderPlugin + ThreadPool.QueueUserWorkItem(o => + { + Thread.Sleep(50); + PluginManager.Init(this); + }); + ThreadPool.QueueUserWorkItem(o => + { + Thread.Sleep(50); + PreLoadImages(); + }); + } + + void pnlResult_ItemDropEvent(Result result, IDataObject dropDataObject, DragEventArgs args) + { + PluginPair pluginPair = PluginManager.AllPlugins.FirstOrDefault(o => o.Metadata.ID == result.PluginID); + if (ResultItemDropEvent != null && pluginPair != null) + { + foreach (var delegateHandler in ResultItemDropEvent.GetInvocationList()) + { + if (delegateHandler.Target == pluginPair.Plugin) + { + delegateHandler.DynamicInvoke(result, dropDataObject, args); + } + } + } + } + + private bool KListener_hookedKeyboardCallback(KeyEvent keyevent, int vkcode, SpecialKeyState state) + { + if (GlobalKeyboardEvent != null) + { + return GlobalKeyboardEvent((int)keyevent, vkcode, state); + } + return true; + } + + private void PreLoadImages() + { + ImageLoader.ImageLoader.PreloadImages(); + } + + void pnlResult_RightMouseClickEvent(Result result) + { + ShowContextMenuFromResult(result); + } + + void MainWindow_Closing(object sender, CancelEventArgs e) + { + UserSettingStorage.Instance.WindowLeft = Left; + UserSettingStorage.Instance.WindowTop = Top; + UserSettingStorage.Instance.Save(); + this.HideWox(); + e.Cancel = true; + } + + private void MainWindow_OnLoaded(object sender, RoutedEventArgs e) + { + if (UserSettingStorage.Instance.WindowLeft == 0 + && UserSettingStorage.Instance.WindowTop == 0) + { + Left = UserSettingStorage.Instance.WindowLeft + = (SystemParameters.PrimaryScreenWidth - ActualWidth) / 2; + Top = UserSettingStorage.Instance.WindowTop + = (SystemParameters.PrimaryScreenHeight - ActualHeight) / 5; + } + else + { + Left = UserSettingStorage.Instance.WindowLeft; + Top = UserSettingStorage.Instance.WindowTop; + } + + InitProgressbarAnimation(); + WindowIntelopHelper.DisableControlBox(this); + CheckUpdate(); + } + + private void CheckUpdate() + { + UpdaterManager.Instance.PrepareUpdateReady += OnPrepareUpdateReady; + UpdaterManager.Instance.UpdateError += OnUpdateError; + UpdaterManager.Instance.CheckUpdate(); + } + + void OnUpdateError(object sender, EventArgs e) + { + string updateError = InternationalizationManager.Instance.GetTranslation("update_wox_update_error"); + MessageBox.Show(updateError); + } + + private void OnPrepareUpdateReady(object sender, EventArgs e) + { + Dispatcher.Invoke(new Action(() => + { + new WoxUpdate().ShowDialog(); + })); + } + + public void SetHotkey(string hotkeyStr, EventHandler action) + { + var hotkey = new HotkeyModel(hotkeyStr); + try + { + HotkeyManager.Current.AddOrReplace(hotkeyStr, hotkey.CharKey, hotkey.ModifierKeys, action); + } + catch (Exception) + { + string errorMsg = string.Format(InternationalizationManager.Instance.GetTranslation("registerHotkeyFailed"), hotkeyStr); + MessageBox.Show(errorMsg); + } + } + + public void RemoveHotkey(string hotkeyStr) + { + if (!string.IsNullOrEmpty(hotkeyStr)) + { + HotkeyManager.Current.Remove(hotkeyStr); + } + } + + private void SetCustomPluginHotkey() + { + if (UserSettingStorage.Instance.CustomPluginHotkeys == null) return; + foreach (CustomPluginHotkey hotkey in UserSettingStorage.Instance.CustomPluginHotkeys) + { + CustomPluginHotkey hotkey1 = hotkey; + SetHotkey(hotkey.Hotkey, delegate + { + ShowApp(); + ChangeQuery(hotkey1.ActionKeyword, true); + }); + } + } + + private void OnHotkey(object sender, HotkeyEventArgs e) + { + ToggleWox(); + e.Handled = true; + } + + public void ToggleWox() + { + if (!IsVisible) + { + ShowWox(); + } + else + { + HideWox(); + } + } + + private void InitProgressbarAnimation() + { + var da = new DoubleAnimation(progressBar.X2, ActualWidth + 100, new Duration(new TimeSpan(0, 0, 0, 0, 1600))); + var da1 = new DoubleAnimation(progressBar.X1, ActualWidth, new Duration(new TimeSpan(0, 0, 0, 0, 1600))); + Storyboard.SetTargetProperty(da, new PropertyPath("(Line.X2)")); + Storyboard.SetTargetProperty(da1, new PropertyPath("(Line.X1)")); + progressBarStoryboard.Children.Add(da); + progressBarStoryboard.Children.Add(da1); + progressBarStoryboard.RepeatBehavior = RepeatBehavior.Forever; + progressBar.Visibility = Visibility.Hidden; + progressBar.BeginStoryboard(progressBarStoryboard); + } + + private void InitialTray() + { + notifyIcon = new NotifyIcon { Text = "Wox", Icon = Properties.Resources.app, Visible = true }; + notifyIcon.Click += (o, e) => ShowWox(); + var open = new MenuItem("Open"); + open.Click += (o, e) => ShowWox(); + var setting = new MenuItem("Settings"); + setting.Click += (o, e) => OpenSettingDialog(); + var exit = new MenuItem("Exit"); + exit.Click += (o, e) => CloseApp(); + MenuItem[] childen = { open, setting, exit }; + notifyIcon.ContextMenu = new ContextMenu(childen); + } + + private void TextBoxBase_OnTextChanged(object sender, TextChangedEventArgs e) + { + if (ignoreTextChange) { ignoreTextChange = false; return; } + + lastQuery = tbQuery.Text; + toolTip.IsOpen = false; + pnlResult.Dirty = true; + int searchDelay = GetSearchDelay(lastQuery); + + Dispatcher.DelayInvoke("UpdateSearch", + o => + { + Dispatcher.DelayInvoke("ClearResults", i => + { + // first try to use clear method inside pnlResult, which is more closer to the add new results + // and this will not bring splash issues.After waiting 100ms, if there still no results added, we + // must clear the result. otherwise, it will be confused why the query changed, but the results + // didn't. + if (pnlResult.Dirty) pnlResult.Clear(); + }, TimeSpan.FromMilliseconds(100), null); + queryHasReturn = false; + Query query = new Query(lastQuery); + query.IsIntantQuery = searchDelay == 0; + FireBeforeWoxQueryEvent(query); + Query(query); + Dispatcher.DelayInvoke("ShowProgressbar", originQuery => + { + if (!queryHasReturn && originQuery == tbQuery.Text && !string.IsNullOrEmpty(lastQuery)) + { + StartProgress(); + } + }, TimeSpan.FromMilliseconds(150), tbQuery.Text); + FireAfterWoxQueryEvent(query); + }, TimeSpan.FromMilliseconds(searchDelay)); + } + + private int GetSearchDelay(string query) + { + if (!string.IsNullOrEmpty(query) && PluginManager.IsInstantQuery(query)) + { + DebugHelper.WriteLine("execute query without delay"); + return 0; + } + + DebugHelper.WriteLine("execute query with 200ms delay"); + return 200; + } + + private void FireAfterWoxQueryEvent(Query q) + { + if (AfterWoxQueryEvent != null) + { + //We shouldn't let those events slow down real query + //so I put it in the new thread + ThreadPool.QueueUserWorkItem(o => + { + AfterWoxQueryEvent(new WoxQueryEventArgs() + { + Query = q + }); + }); + } + } + + private void FireBeforeWoxQueryEvent(Query q) + { + if (BeforeWoxQueryEvent != null) + { + //We shouldn't let those events slow down real query + //so I put it in the new thread + ThreadPool.QueueUserWorkItem(o => + { + BeforeWoxQueryEvent(new WoxQueryEventArgs() + { + Query = q + }); + }); + } + } + + private void Query(Query q) + { + PluginManager.Query(q); + StopProgress(); + BackToResultMode(); + } + + private void BackToResultMode() + { + pnlResult.Visibility = Visibility.Visible; + pnlContextMenu.Visibility = Visibility.Collapsed; + } + + private void Border_OnMouseDown(object sender, MouseButtonEventArgs e) + { + if (e.ChangedButton == MouseButton.Left) DragMove(); + } + + private void StartProgress() + { + progressBar.Visibility = Visibility.Visible; + } + + private void StopProgress() + { + progressBar.Visibility = Visibility.Hidden; + } + + private void HideWox() + { + Hide(); + } + + private void ShowWox(bool selectAll = true) + { + UserSettingStorage.Instance.IncreaseActivateTimes(); + if (!double.IsNaN(Left) && !double.IsNaN(Top)) + { + var origScreen = Screen.FromRectangle(new Rectangle((int)Left, (int)Top, (int)ActualWidth, (int)ActualHeight)); + var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position); + var coordX = (Left - origScreen.WorkingArea.Left) / (origScreen.WorkingArea.Width - ActualWidth); + var coordY = (Top - origScreen.WorkingArea.Top) / (origScreen.WorkingArea.Height - ActualHeight); + Left = (screen.WorkingArea.Width - ActualWidth) * coordX + screen.WorkingArea.Left; + Top = (screen.WorkingArea.Height - ActualHeight) * coordY + screen.WorkingArea.Top; + } + + Show(); + Activate(); + Focus(); + tbQuery.Focus(); + if (selectAll) tbQuery.SelectAll(); + } + + private void MainWindow_OnDeactivated(object sender, EventArgs e) + { + if (UserSettingStorage.Instance.HideWhenDeactive) + { + HideWox(); + } + } + + private void TbQuery_OnPreviewKeyDown(object sender, KeyEventArgs e) + { + //when alt is pressed, the real key should be e.SystemKey + Key key = (e.Key == Key.System ? e.SystemKey : e.Key); + switch (key) + { + case Key.Escape: + if (IsInContextMenuMode) + { + BackToResultMode(); + } + else + { + HideWox(); + } + e.Handled = true; + break; + + case Key.Tab: + if (GlobalHotkey.Instance.CheckModifiers().ShiftPressed) + { + SelectPrevItem(); + } + else + { + SelectNextItem(); + } + e.Handled = true; + break; + + case Key.N: + case Key.J: + if (GlobalHotkey.Instance.CheckModifiers().CtrlPressed) + { + SelectNextItem(); + } + break; + + case Key.P: + case Key.K: + if (GlobalHotkey.Instance.CheckModifiers().CtrlPressed) + { + SelectPrevItem(); + } + break; + + case Key.O: + if (GlobalHotkey.Instance.CheckModifiers().CtrlPressed) + { + if (IsInContextMenuMode) + { + BackToResultMode(); + } + else + { + ShowContextMenuFromResult(GetActiveResult()); + } + } + break; + + case Key.Down: + SelectNextItem(); + e.Handled = true; + break; + + case Key.Up: + SelectPrevItem(); + e.Handled = true; + break; + + case Key.D: + if (GlobalHotkey.Instance.CheckModifiers().CtrlPressed) + { + pnlResult.SelectNextPage(); + } + break; + + case Key.PageDown: + pnlResult.SelectNextPage(); + e.Handled = true; + break; + + case Key.U: + if (GlobalHotkey.Instance.CheckModifiers().CtrlPressed) + { + pnlResult.SelectPrevPage(); + } + break; + + case Key.PageUp: + pnlResult.SelectPrevPage(); + e.Handled = true; + break; + + case Key.Back: + if (BackKeyDownEvent != null) + { + BackKeyDownEvent(new WoxKeyDownEventArgs() + { + Query = tbQuery.Text, + keyEventArgs = e + }); + } + break; + + case Key.F1: + Process.Start("http://doc.getwox.com"); + break; + + case Key.Enter: + Result activeResult = GetActiveResult(); + if (GlobalHotkey.Instance.CheckModifiers().ShiftPressed) + { + ShowContextMenuFromResult(activeResult); + } + else + { + SelectResult(activeResult); + } + e.Handled = true; + break; + + case Key.D1: + SelectItem(1); + break; + + case Key.D2: + SelectItem(2); + break; + + case Key.D3: + SelectItem(3); + break; + + case Key.D4: + SelectItem(4); + break; + + case Key.D5: + SelectItem(5); + break; + case Key.D6: + SelectItem(6); + break; + + } + } + + private void SelectItem(int index) + { + int zeroBasedIndex = index - 1; + SpecialKeyState keyState = GlobalHotkey.Instance.CheckModifiers(); + if (keyState.AltPressed || keyState.CtrlPressed) + { + List visibleResults = pnlResult.GetVisibleResults(); + if (zeroBasedIndex < visibleResults.Count) + { + SelectResult(visibleResults[zeroBasedIndex]); + } + } + } + + private bool IsInContextMenuMode + { + get { return pnlContextMenu.Visibility == Visibility.Visible; } + } + + private Result GetActiveResult() + { + if (IsInContextMenuMode) + { + return pnlContextMenu.GetActiveResult(); + } + else + { + return pnlResult.GetActiveResult(); + } + } + + private void SelectPrevItem() + { + if (IsInContextMenuMode) + { + pnlContextMenu.SelectPrev(); + } + else + { + pnlResult.SelectPrev(); + } + toolTip.IsOpen = false; + } + + private void SelectNextItem() + { + if (IsInContextMenuMode) + { + pnlContextMenu.SelectNext(); + } + else + { + pnlResult.SelectNext(); + } + toolTip.IsOpen = false; + } + + private void SelectResult(Result result) + { + if (result != null) + { + if (result.Action != null) + { + bool hideWindow = result.Action(new ActionContext() + { + SpecialKeyState = GlobalHotkey.Instance.CheckModifiers() + }); + if (hideWindow) + { + HideWox(); + } + UserSelectedRecordStorage.Instance.Add(result); + } + } + } + + private void UpdateResultView(List list) + { + queryHasReturn = true; + progressBar.Dispatcher.Invoke(new Action(StopProgress)); + if (list == null || list.Count == 0) return; + + if (list.Count > 0) + { + list.ForEach(o => + { + o.Score += UserSelectedRecordStorage.Instance.GetSelectedCount(o) * 5; + if (o.ContextMenu == null) + { + o.ContextMenu = new List(); + } + HanleTopMost(o); + }); + List l = list.Where(o => o.OriginQuery != null && o.OriginQuery.RawQuery == lastQuery).ToList(); + Dispatcher.Invoke(new Action(() => + { + pnlResult.AddResults(l); + })); + } + } + + private void HanleTopMost(Result result) + { + if (TopMostRecordStorage.Instance.IsTopMost(result)) + { + result.ContextMenu.Add(new Result("Remove top most in this query", "Images\\down.png") + { + PluginDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), + Action = _ => + { + TopMostRecordStorage.Instance.Remove(result); + ShowMsg("Succeed", "", ""); + return false; + } + }); + } + else + { + result.ContextMenu.Add(new Result("Set as top most in this query", "Images\\up.png") + { + PluginDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), + Action = _ => + { + TopMostRecordStorage.Instance.Add(result); + ShowMsg("Succeed", "", ""); + return false; + } + }); + } + } + + private void ShowContextMenuFromResult(Result result) + { + if (result.ContextMenu != null && result.ContextMenu.Count > 0) + { + pnlContextMenu.Clear(); + pnlContextMenu.AddResults(result.ContextMenu); + pnlContextMenu.Visibility = Visibility.Visible; + pnlResult.Visibility = Visibility.Collapsed; + } + } + + public bool ShellRun(string cmd, bool runAsAdministrator = false) + { + try + { + if (string.IsNullOrEmpty(cmd)) + throw new ArgumentNullException(); + + WindowsShellRun.Start(cmd, runAsAdministrator); + return true; + } + catch (Exception ex) + { + string errorMsg = string.Format(InternationalizationManager.Instance.GetTranslation("couldnotStartCmd"), cmd); + ShowMsg(errorMsg, ex.Message, null); + } + return false; + } + + private void MainWindow_OnDrop(object sender, DragEventArgs e) + { + if (e.Data.GetDataPresent(DataFormats.FileDrop)) + { + // Note that you can have more than one file. + string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); + if (files[0].ToLower().EndsWith(".wox")) + { + PluginManager.InstallPlugin(files[0]); + } + else + { + MessageBox.Show(InternationalizationManager.Instance.GetTranslation("invalidWoxPluginFileFormat")); + } + } + } + + private void TbQuery_OnPreviewDragOver(object sender, DragEventArgs e) + { + e.Handled = true; + } + } +} \ No newline at end of file diff --git a/Wox/packages.config b/Wox/packages.config index 9f1a6d32b..054bbd20c 100644 --- a/Wox/packages.config +++ b/Wox/packages.config @@ -1,5 +1,6 @@  + diff --git a/Wox/su54u2mz.xrz b/Wox/su54u2mz.xrz new file mode 100644 index 000000000..b83197e8f --- /dev/null +++ b/Wox/su54u2mz.xrz @@ -0,0 +1,850 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Net; +using System.Reflection; +using System.Threading; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Forms; +using System.Windows.Input; +using System.Windows.Media.Animation; +using NHotkey; +using NHotkey.Wpf; +using Wox.Core.i18n; +using Wox.Core.Plugin; +using Wox.Core.Theme; +using Wox.Core.Updater; +using Wox.Core.UserSettings; +using Wox.Helper; +using Wox.Infrastructure; +using Wox.Infrastructure.Hotkey; +using Wox.Plugin; +using Wox.Storage; +using ContextMenu = System.Windows.Forms.ContextMenu; +using DataFormats = System.Windows.DataFormats; +using DragEventArgs = System.Windows.DragEventArgs; +using IDataObject = System.Windows.IDataObject; +using KeyEventArgs = System.Windows.Input.KeyEventArgs; +using MenuItem = System.Windows.Forms.MenuItem; +using MessageBox = System.Windows.MessageBox; +using ToolTip = System.Windows.Controls.ToolTip; + +namespace Wox +{ + public partial class MainWindow : IPublicAPI + { + + #region Properties + + private readonly Storyboard progressBarStoryboard = new Storyboard(); + private NotifyIcon notifyIcon; + private bool queryHasReturn; + private string lastQuery; + private ToolTip toolTip = new ToolTip(); + + private bool ignoreTextChange = false; + + #endregion + + #region Public API + + public void ChangeQuery(string query, bool requery = false) + { + Dispatcher.Invoke(new Action(() => + { + tbQuery.Text = query; + tbQuery.CaretIndex = tbQuery.Text.Length; + if (requery) + { + TextBoxBase_OnTextChanged(null, null); + } + })); + } + + public void CloseApp() + { + Dispatcher.Invoke(new Action(() => + { + notifyIcon.Visible = false; + Close(); + Environment.Exit(0); + })); + } + + public void HideApp() + { + Dispatcher.Invoke(new Action(HideWox)); + } + + public void ShowApp() + { + Dispatcher.Invoke(new Action(() => ShowWox())); + } + + public void ShowMsg(string title, string subTitle, string iconPath) + { + Dispatcher.Invoke(new Action(() => + { + var m = new Msg { Owner = GetWindow(this) }; + m.Show(title, subTitle, iconPath); + })); + } + + public void OpenSettingDialog() + { + Dispatcher.Invoke(new Action(() => WindowOpener.Open(this))); + } + + public void StartLoadingBar() + { + Dispatcher.Invoke(new Action(StartProgress)); + } + + public void StopLoadingBar() + { + Dispatcher.Invoke(new Action(StopProgress)); + } + + public void InstallPlugin(string path) + { + Dispatcher.Invoke(new Action(() => PluginManager.InstallPlugin(path))); + } + + public void ReloadPlugins() + { + Dispatcher.Invoke(new Action(() => PluginManager.Init(this))); + } + + public string GetTranslation(string key) + { + return InternationalizationManager.Instance.GetTranslation(key); + } + + public List GetAllPlugins() + { + return PluginManager.AllPlugins; + } + + public event WoxKeyDownEventHandler BackKeyDownEvent; + public event WoxGlobalKeyboardEventHandler GlobalKeyboardEvent; + public event AfterWoxQueryEventHandler AfterWoxQueryEvent; + public event AfterWoxQueryEventHandler BeforeWoxQueryEvent; + public event ResultItemDropEventHandler ResultItemDropEvent; + + public void PushResults(Query query, PluginMetadata plugin, List results) + { + results.ForEach(o => + { + o.PluginDirectory = plugin.PluginDirectory; + o.PluginID = plugin.ID; + o.OriginQuery = query; + if (o.ContextMenu != null) + { + o.ContextMenu.ForEach(t => + { + t.PluginDirectory = plugin.PluginDirectory; + t.PluginID = plugin.ID; + }); + } + }); + UpdateResultView(results); + } + + public void ShowContextMenu(PluginMetadata plugin, List results) + { + if (results != null && results.Count > 0) + { + results.ForEach(o => + { + o.PluginDirectory = plugin.PluginDirectory; + o.PluginID = plugin.ID; + o.ContextMenu = null; + }); + pnlContextMenu.Clear(); + pnlContextMenu.AddResults(results); + pnlContextMenu.Visibility = Visibility.Visible; + pnlResult.Visibility = Visibility.Collapsed; + } + } + + #endregion + + public MainWindow() + { + InitializeComponent(); + ThreadPool.SetMaxThreads(30, 10); + ThreadPool.SetMinThreads(10, 5); + + WebRequest.RegisterPrefix("data", new DataWebRequestFactory()); + GlobalHotkey.Instance.hookedKeyboardCallback += KListener_hookedKeyboardCallback; + progressBar.ToolTip = toolTip; + InitialTray(); + pnlResult.LeftMouseClickEvent += SelectResult; + pnlResult.ItemDropEvent += pnlResult_ItemDropEvent; + pnlContextMenu.LeftMouseClickEvent += SelectResult; + pnlResult.RightMouseClickEvent += pnlResult_RightMouseClickEvent; + + ThemeManager.Theme.ChangeTheme(UserSettingStorage.Instance.Theme); + InternationalizationManager.Instance.ChangeLanguage(UserSettingStorage.Instance.Language); + + SetHotkey(UserSettingStorage.Instance.Hotkey, OnHotkey); + SetCustomPluginHotkey(); + + Closing += MainWindow_Closing; + //since MainWIndow implement IPublicAPI, so we need to finish ctor MainWindow object before + //PublicAPI invoke in plugin init methods. E.g FolderPlugin + ThreadPool.QueueUserWorkItem(o => + { + Thread.Sleep(50); + PluginManager.Init(this); + }); + ThreadPool.QueueUserWorkItem(o => + { + Thread.Sleep(50); + PreLoadImages(); + }); + } + + void pnlResult_ItemDropEvent(Result result, IDataObject dropDataObject, DragEventArgs args) + { + PluginPair pluginPair = PluginManager.AllPlugins.FirstOrDefault(o => o.Metadata.ID == result.PluginID); + if (ResultItemDropEvent != null && pluginPair != null) + { + foreach (var delegateHandler in ResultItemDropEvent.GetInvocationList()) + { + if (delegateHandler.Target == pluginPair.Plugin) + { + delegateHandler.DynamicInvoke(result, dropDataObject, args); + } + } + } + } + + private bool KListener_hookedKeyboardCallback(KeyEvent keyevent, int vkcode, SpecialKeyState state) + { + if (GlobalKeyboardEvent != null) + { + return GlobalKeyboardEvent((int)keyevent, vkcode, state); + } + return true; + } + + private void PreLoadImages() + { + ImageLoader.ImageLoader.PreloadImages(); + } + + void pnlResult_RightMouseClickEvent(Result result) + { + ShowContextMenuFromResult(result); + } + + void MainWindow_Closing(object sender, CancelEventArgs e) + { + UserSettingStorage.Instance.WindowLeft = Left; + UserSettingStorage.Instance.WindowTop = Top; + UserSettingStorage.Instance.Save(); + this.HideWox(); + e.Cancel = true; + } + + private void MainWindow_OnLoaded(object sender, RoutedEventArgs e) + { + if (UserSettingStorage.Instance.WindowLeft == 0 + && UserSettingStorage.Instance.WindowTop == 0) + { + Left = UserSettingStorage.Instance.WindowLeft + = (SystemParameters.PrimaryScreenWidth - ActualWidth) / 2; + Top = UserSettingStorage.Instance.WindowTop + = (SystemParameters.PrimaryScreenHeight - ActualHeight) / 5; + } + else + { + Left = UserSettingStorage.Instance.WindowLeft; + Top = UserSettingStorage.Instance.WindowTop; + } + + InitProgressbarAnimation(); + WindowIntelopHelper.DisableControlBox(this); + CheckUpdate(); + } + + private void CheckUpdate() + { + UpdaterManager.Instance.PrepareUpdateReady += OnPrepareUpdateReady; + UpdaterManager.Instance.UpdateError += OnUpdateError; + UpdaterManager.Instance.CheckUpdate(); + } + + void OnUpdateError(object sender, EventArgs e) + { + string updateError = InternationalizationManager.Instance.GetTranslation("update_wox_update_error"); + MessageBox.Show(updateError); + } + + private void OnPrepareUpdateReady(object sender, EventArgs e) + { + Dispatcher.Invoke(new Action(() => + { + new WoxUpdate().ShowDialog(); + })); + } + + public void SetHotkey(string hotkeyStr, EventHandler action) + { + var hotkey = new HotkeyModel(hotkeyStr); + try + { + HotkeyManager.Current.AddOrReplace(hotkeyStr, hotkey.CharKey, hotkey.ModifierKeys, action); + } + catch (Exception) + { + string errorMsg = string.Format(InternationalizationManager.Instance.GetTranslation("registerHotkeyFailed"), hotkeyStr); + MessageBox.Show(errorMsg); + } + } + + public void RemoveHotkey(string hotkeyStr) + { + if (!string.IsNullOrEmpty(hotkeyStr)) + { + HotkeyManager.Current.Remove(hotkeyStr); + } + } + + private void SetCustomPluginHotkey() + { + if (UserSettingStorage.Instance.CustomPluginHotkeys == null) return; + foreach (CustomPluginHotkey hotkey in UserSettingStorage.Instance.CustomPluginHotkeys) + { + CustomPluginHotkey hotkey1 = hotkey; + SetHotkey(hotkey.Hotkey, delegate + { + ShowApp(); + ChangeQuery(hotkey1.ActionKeyword, true); + }); + } + } + + private void OnHotkey(object sender, HotkeyEventArgs e) + { + ToggleWox(); + e.Handled = true; + } + + public void ToggleWox() + { + if (!IsVisible) + { + ShowWox(); + } + else + { + HideWox(); + } + } + + private void InitProgressbarAnimation() + { + var da = new DoubleAnimation(progressBar.X2, ActualWidth + 100, new Duration(new TimeSpan(0, 0, 0, 0, 1600))); + var da1 = new DoubleAnimation(progressBar.X1, ActualWidth, new Duration(new TimeSpan(0, 0, 0, 0, 1600))); + Storyboard.SetTargetProperty(da, new PropertyPath("(Line.X2)")); + Storyboard.SetTargetProperty(da1, new PropertyPath("(Line.X1)")); + progressBarStoryboard.Children.Add(da); + progressBarStoryboard.Children.Add(da1); + progressBarStoryboard.RepeatBehavior = RepeatBehavior.Forever; + progressBar.Visibility = Visibility.Hidden; + progressBar.BeginStoryboard(progressBarStoryboard); + } + + private void InitialTray() + { + notifyIcon = new NotifyIcon { Text = "Wox", Icon = Properties.Resources.app, Visible = true }; + notifyIcon.Click += (o, e) => ShowWox(); + var open = new MenuItem("Open"); + open.Click += (o, e) => ShowWox(); + var setting = new MenuItem("Settings"); + setting.Click += (o, e) => OpenSettingDialog(); + var exit = new MenuItem("Exit"); + exit.Click += (o, e) => CloseApp(); + MenuItem[] childen = { open, setting, exit }; + notifyIcon.ContextMenu = new ContextMenu(childen); + } + + private void TextBoxBase_OnTextChanged(object sender, TextChangedEventArgs e) + { + if (ignoreTextChange) { ignoreTextChange = false; return; } + + lastQuery = tbQuery.Text; + toolTip.IsOpen = false; + pnlResult.Dirty = true; + int searchDelay = GetSearchDelay(lastQuery); + + Dispatcher.DelayInvoke("UpdateSearch", + o => + { + Dispatcher.DelayInvoke("ClearResults", i => + { + // first try to use clear method inside pnlResult, which is more closer to the add new results + // and this will not bring splash issues.After waiting 100ms, if there still no results added, we + // must clear the result. otherwise, it will be confused why the query changed, but the results + // didn't. + if (pnlResult.Dirty) pnlResult.Clear(); + }, TimeSpan.FromMilliseconds(100), null); + queryHasReturn = false; + Query query = new Query(lastQuery); + query.IsIntantQuery = searchDelay == 0; + FireBeforeWoxQueryEvent(query); + Query(query); + Dispatcher.DelayInvoke("ShowProgressbar", originQuery => + { + if (!queryHasReturn && originQuery == tbQuery.Text && !string.IsNullOrEmpty(lastQuery)) + { + StartProgress(); + } + }, TimeSpan.FromMilliseconds(150), tbQuery.Text); + FireAfterWoxQueryEvent(query); + }, TimeSpan.FromMilliseconds(searchDelay)); + } + + private int GetSearchDelay(string query) + { + if (!string.IsNullOrEmpty(query) && PluginManager.IsInstantQuery(query)) + { + DebugHelper.WriteLine("execute query without delay"); + return 0; + } + + DebugHelper.WriteLine("execute query with 200ms delay"); + return 200; + } + + private void FireAfterWoxQueryEvent(Query q) + { + if (AfterWoxQueryEvent != null) + { + //We shouldn't let those events slow down real query + //so I put it in the new thread + ThreadPool.QueueUserWorkItem(o => + { + AfterWoxQueryEvent(new WoxQueryEventArgs() + { + Query = q + }); + }); + } + } + + private void FireBeforeWoxQueryEvent(Query q) + { + if (BeforeWoxQueryEvent != null) + { + //We shouldn't let those events slow down real query + //so I put it in the new thread + ThreadPool.QueueUserWorkItem(o => + { + BeforeWoxQueryEvent(new WoxQueryEventArgs() + { + Query = q + }); + }); + } + } + + private void Query(Query q) + { + PluginManager.Query(q); + StopProgress(); + BackToResultMode(); + } + + private void BackToResultMode() + { + pnlResult.Visibility = Visibility.Visible; + pnlContextMenu.Visibility = Visibility.Collapsed; + } + + private void Border_OnMouseDown(object sender, MouseButtonEventArgs e) + { + if (e.ChangedButton == MouseButton.Left) DragMove(); + } + + private void StartProgress() + { + progressBar.Visibility = Visibility.Visible; + } + + private void StopProgress() + { + progressBar.Visibility = Visibility.Hidden; + } + + private void HideWox() + { + Hide(); + } + + private void ShowWox(bool selectAll = true) + { + UserSettingStorage.Instance.IncreaseActivateTimes(); + if (!double.IsNaN(Left) && !double.IsNaN(Top)) + { + var origScreen = Screen.FromRectangle(new Rectangle((int)Left, (int)Top, (int)ActualWidth, (int)ActualHeight)); + var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position); + var coordX = (Left - origScreen.WorkingArea.Left) / (origScreen.WorkingArea.Width - ActualWidth); + var coordY = (Top - origScreen.WorkingArea.Top) / (origScreen.WorkingArea.Height - ActualHeight); + Left = (screen.WorkingArea.Width - ActualWidth) * coordX + screen.WorkingArea.Left; + Top = (screen.WorkingArea.Height - ActualHeight) * coordY + screen.WorkingArea.Top; + } + + Show(); + Activate(); + Focus(); + tbQuery.Focus(); + if (selectAll) tbQuery.SelectAll(); + } + + private void MainWindow_OnDeactivated(object sender, EventArgs e) + { + if (UserSettingStorage.Instance.HideWhenDeactive) + { + HideWox(); + } + } + + private void TbQuery_OnPreviewKeyDown(object sender, KeyEventArgs e) + { + //when alt is pressed, the real key should be e.SystemKey + Key key = (e.Key == Key.System ? e.SystemKey : e.Key); + switch (key) + { + case Key.Escape: + if (IsInContextMenuMode) + { + BackToResultMode(); + } + else + { + HideWox(); + } + e.Handled = true; + break; + + case Key.Tab: + if (GlobalHotkey.Instance.CheckModifiers().ShiftPressed) + { + SelectPrevItem(); + } + else + { + SelectNextItem(); + } + e.Handled = true; + break; + + case Key.N: + case Key.J: + if (GlobalHotkey.Instance.CheckModifiers().CtrlPressed) + { + SelectNextItem(); + } + break; + + case Key.P: + case Key.K: + if (GlobalHotkey.Instance.CheckModifiers().CtrlPressed) + { + SelectPrevItem(); + } + break; + + case Key.O: + if (GlobalHotkey.Instance.CheckModifiers().CtrlPressed) + { + if (IsInContextMenuMode) + { + BackToResultMode(); + } + else + { + ShowContextMenuFromResult(GetActiveResult()); + } + } + break; + + case Key.Down: + SelectNextItem(); + e.Handled = true; + break; + + case Key.Up: + SelectPrevItem(); + e.Handled = true; + break; + + case Key.D: + if (GlobalHotkey.Instance.CheckModifiers().AltPressed) + { + pnlResult.SelectNextPage(); + } + break; + + case Key.PageDown: + pnlResult.SelectNextPage(); + e.Handled = true; + break; + + case Key.U: + if (GlobalHotkey.Instance.CheckModifiers().AltPressed) + { + pnlResult.SelectPrevPage(); + } + break; + + case Key.PageUp: + pnlResult.SelectPrevPage(); + e.Handled = true; + break; + + case Key.Back: + if (BackKeyDownEvent != null) + { + BackKeyDownEvent(new WoxKeyDownEventArgs() + { + Query = tbQuery.Text, + keyEventArgs = e + }); + } + break; + + case Key.F1: + Process.Start("http://doc.getwox.com"); + break; + + case Key.Enter: + Result activeResult = GetActiveResult(); + if (GlobalHotkey.Instance.CheckModifiers().ShiftPressed) + { + ShowContextMenuFromResult(activeResult); + } + else + { + SelectResult(activeResult); + } + e.Handled = true; + break; + + case Key.D1: + SelectItem(1); + break; + + case Key.D2: + SelectItem(2); + break; + + case Key.D3: + SelectItem(3); + break; + + case Key.D4: + SelectItem(4); + break; + + case Key.D5: + SelectItem(5); + break; + case Key.D6: + SelectItem(6); + break; + + } + } + + private void SelectItem(int index) + { + int zeroBasedIndex = index - 1; + SpecialKeyState keyState = GlobalHotkey.Instance.CheckModifiers(); + if (keyState.AltPressed || keyState.CtrlPressed) + { + List visibleResults = pnlResult.GetVisibleResults(); + if (zeroBasedIndex < visibleResults.Count) + { + SelectResult(visibleResults[zeroBasedIndex]); + } + } + } + + private bool IsInContextMenuMode + { + get { return pnlContextMenu.Visibility == Visibility.Visible; } + } + + private Result GetActiveResult() + { + if (IsInContextMenuMode) + { + return pnlContextMenu.GetActiveResult(); + } + else + { + return pnlResult.GetActiveResult(); + } + } + + private void SelectPrevItem() + { + if (IsInContextMenuMode) + { + pnlContextMenu.SelectPrev(); + } + else + { + pnlResult.SelectPrev(); + } + toolTip.IsOpen = false; + } + + private void SelectNextItem() + { + if (IsInContextMenuMode) + { + pnlContextMenu.SelectNext(); + } + else + { + pnlResult.SelectNext(); + } + toolTip.IsOpen = false; + } + + private void SelectResult(Result result) + { + if (result != null) + { + if (result.Action != null) + { + bool hideWindow = result.Action(new ActionContext() + { + SpecialKeyState = GlobalHotkey.Instance.CheckModifiers() + }); + if (hideWindow) + { + HideWox(); + } + UserSelectedRecordStorage.Instance.Add(result); + } + } + } + + private void UpdateResultView(List list) + { + queryHasReturn = true; + progressBar.Dispatcher.Invoke(new Action(StopProgress)); + if (list == null || list.Count == 0) return; + + if (list.Count > 0) + { + list.ForEach(o => + { + o.Score += UserSelectedRecordStorage.Instance.GetSelectedCount(o) * 5; + if (o.ContextMenu == null) + { + o.ContextMenu = new List(); + } + HanleTopMost(o); + }); + List l = list.Where(o => o.OriginQuery != null && o.OriginQuery.RawQuery == lastQuery).ToList(); + Dispatcher.Invoke(new Action(() => + { + pnlResult.AddResults(l); + })); + } + } + + private void HanleTopMost(Result result) + { + if (TopMostRecordStorage.Instance.IsTopMost(result)) + { + result.ContextMenu.Add(new Result("Remove top most in this query", "Images\\down.png") + { + PluginDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), + Action = _ => + { + TopMostRecordStorage.Instance.Remove(result); + ShowMsg("Succeed", "", ""); + return false; + } + }); + } + else + { + result.ContextMenu.Add(new Result("Set as top most in this query", "Images\\up.png") + { + PluginDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), + Action = _ => + { + TopMostRecordStorage.Instance.Add(result); + ShowMsg("Succeed", "", ""); + return false; + } + }); + } + } + + private void ShowContextMenuFromResult(Result result) + { + if (result.ContextMenu != null && result.ContextMenu.Count > 0) + { + pnlContextMenu.Clear(); + pnlContextMenu.AddResults(result.ContextMenu); + pnlContextMenu.Visibility = Visibility.Visible; + pnlResult.Visibility = Visibility.Collapsed; + } + } + + public bool ShellRun(string cmd, bool runAsAdministrator = false) + { + try + { + if (string.IsNullOrEmpty(cmd)) + throw new ArgumentNullException(); + + WindowsShellRun.Start(cmd, runAsAdministrator); + return true; + } + catch (Exception ex) + { + string errorMsg = string.Format(InternationalizationManager.Instance.GetTranslation("couldnotStartCmd"), cmd); + ShowMsg(errorMsg, ex.Message, null); + } + return false; + } + + private void MainWindow_OnDrop(object sender, DragEventArgs e) + { + if (e.Data.GetDataPresent(DataFormats.FileDrop)) + { + // Note that you can have more than one file. + string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); + if (files[0].ToLower().EndsWith(".wox")) + { + PluginManager.InstallPlugin(files[0]); + } + else + { + MessageBox.Show(InternationalizationManager.Instance.GetTranslation("invalidWoxPluginFileFormat")); + } + } + } + + private void TbQuery_OnPreviewDragOver(object sender, DragEventArgs e) + { + e.Handled = true; + } + } +} \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 76871e145..90e4a3550 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 1.1.1.{build} +version: 1.2.0.{build} configuration: Release @@ -15,7 +15,6 @@ build: after_test: - ps: .\deploy\nuget\pack.ps1 - cmd: .\deploy\UpdateGenerator\build.bat - #- cmd: .\deploy\Cleanup.bat deploy: provider: NuGet