diff --git a/Plugins/WinAlfred.Plugin.Fanyi/HttpRequest.cs b/Plugins/WinAlfred.Plugin.Fanyi/HttpRequest.cs new file mode 100644 index 000000000..385ccec7a --- /dev/null +++ b/Plugins/WinAlfred.Plugin.Fanyi/HttpRequest.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Security; +using System.Security.Cryptography.X509Certificates; +using System.Text; + +//From:http://blog.csdn.net/zhoufoxcn/article/details/6404236 +namespace WinAlfred.Plugin.Fanyi +{ + /// + /// 有关HTTP请求的辅助类 + /// + public class HttpRequest + { + private static readonly string DefaultUserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"; + /// + /// 创建GET方式的HTTP请求 + /// + /// 请求的URL + /// 请求的超时时间 + /// 请求的客户端浏览器信息,可以为空 + /// 随同HTTP请求发送的Cookie信息,如果不需要身份验证可以为空 + /// + public static HttpWebResponse CreateGetHttpResponse(string url, int? timeout, string userAgent, CookieCollection cookies) + { + if (string.IsNullOrEmpty(url)) + { + throw new ArgumentNullException("url"); + } + HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest; + request.Method = "GET"; + request.UserAgent = DefaultUserAgent; + if (!string.IsNullOrEmpty(userAgent)) + { + request.UserAgent = userAgent; + } + if (timeout.HasValue) + { + request.Timeout = timeout.Value; + } + if (cookies != null) + { + request.CookieContainer = new CookieContainer(); + request.CookieContainer.Add(cookies); + } + return request.GetResponse() as HttpWebResponse; + } + /// + /// 创建POST方式的HTTP请求 + /// + /// 请求的URL + /// 随同请求POST的参数名称及参数值字典 + /// 请求的超时时间 + /// 请求的客户端浏览器信息,可以为空 + /// 发送HTTP请求时所用的编码 + /// 随同HTTP请求发送的Cookie信息,如果不需要身份验证可以为空 + /// + public static HttpWebResponse CreatePostHttpResponse(string url, IDictionary parameters, int? timeout, string userAgent, Encoding requestEncoding, CookieCollection cookies) + { + if (string.IsNullOrEmpty(url)) + { + throw new ArgumentNullException("url"); + } + if (requestEncoding == null) + { + throw new ArgumentNullException("requestEncoding"); + } + HttpWebRequest request = null; + //如果是发送HTTPS请求 + if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase)) + { + ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult); + request = WebRequest.Create(url) as HttpWebRequest; + request.ProtocolVersion = HttpVersion.Version10; + } + else + { + request = WebRequest.Create(url) as HttpWebRequest; + } + request.Method = "POST"; + request.ContentType = "application/x-www-form-urlencoded"; + + if (!string.IsNullOrEmpty(userAgent)) + { + request.UserAgent = userAgent; + } + else + { + request.UserAgent = DefaultUserAgent; + } + + if (timeout.HasValue) + { + request.Timeout = timeout.Value; + } + if (cookies != null) + { + request.CookieContainer = new CookieContainer(); + request.CookieContainer.Add(cookies); + } + //如果需要POST数据 + if (!(parameters == null || parameters.Count == 0)) + { + StringBuilder buffer = new StringBuilder(); + int i = 0; + foreach (string key in parameters.Keys) + { + if (i > 0) + { + buffer.AppendFormat("&{0}={1}", key, parameters[key]); + } + else + { + buffer.AppendFormat("{0}={1}", key, parameters[key]); + } + i++; + } + byte[] data = requestEncoding.GetBytes(buffer.ToString()); + using (Stream stream = request.GetRequestStream()) + { + stream.Write(data, 0, data.Length); + } + } + return request.GetResponse() as HttpWebResponse; + } + + private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors) + { + return true; //总是接受 + } + } +} diff --git a/Plugins/WinAlfred.Plugin.Fanyi/Images/translate.png b/Plugins/WinAlfred.Plugin.Fanyi/Images/translate.png new file mode 100644 index 000000000..11be5bc95 Binary files /dev/null and b/Plugins/WinAlfred.Plugin.Fanyi/Images/translate.png differ diff --git a/Plugins/WinAlfred.Plugin.Fanyi/Main.cs b/Plugins/WinAlfred.Plugin.Fanyi/Main.cs new file mode 100644 index 000000000..cdbbc4167 --- /dev/null +++ b/Plugins/WinAlfred.Plugin.Fanyi/Main.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Reflection; +using System.Text; +using System.Threading; +using System.Windows.Forms; +using System.Windows.Forms.VisualStyles; +using Newtonsoft.Json; + +namespace WinAlfred.Plugin.Fanyi +{ + public class TranslateResult + { + public string from { get; set; } + public string to { get; set; } + public List trans_result { get; set; } + + } + + public class SrcDst + { + public string src { get; set; } + public string dst { get; set; } + } + + public class Main : IPlugin + { + private string translateURL = "http://openapi.baidu.com/public/2.0/bmt/translate"; + private string baiduKey = "SnPcDY3iH5jDbklRewkG2D2v"; + + static public string AssemblyDirectory + { + get + { + string codeBase = Assembly.GetExecutingAssembly().CodeBase; + UriBuilder uri = new UriBuilder(codeBase); + string path = Uri.UnescapeDataString(uri.Path); + return Path.GetDirectoryName(path); + } + } + + public List Query(Query query) + { + List results = new List(); + if (query.ActionParameters.Count == 0) + { + results.Add(new Result() + { + Title = "Start to translate between Chinese and English", + SubTitle = "Powered by baidu api", + IcoPath = "Images\\translate.png" + }); + return results; + } + + Dictionary data = new Dictionary(); + data.Add("from", "auto"); + data.Add("to", "auto"); + data.Add("q", query.RawQuery.Substring(3)); + data.Add("client_id", baiduKey); + HttpWebResponse response = HttpRequest.CreatePostHttpResponse(translateURL, data, null, null, Encoding.UTF8, null); + Stream s = response.GetResponseStream(); + if (s != null) + { + StreamReader reader = new StreamReader(s, Encoding.UTF8); + string json = reader.ReadToEnd(); + TranslateResult o = JsonConvert.DeserializeObject(json); + foreach (SrcDst srcDst in o.trans_result) + { + string dst = srcDst.dst; + results.Add(new Result() + { + Title = dst, + SubTitle = "Copy to clipboard", + IcoPath = "Images\\translate.png", + Action = () => + { + Clipboard.SetText(dst); + context.ShowMsg("translation has been copyed to your clipboard.", "", + AssemblyDirectory + "\\Images\\translate.png"); + } + }); + } + } + + return results; + } + + public static string GetHtmlStr(string url) + { + try + { + WebRequest rGet = WebRequest.Create(url); + WebResponse rSet = rGet.GetResponse(); + Stream s = rSet.GetResponseStream(); + StreamReader reader = new StreamReader(s, Encoding.UTF8); + return reader.ReadToEnd(); + } + catch (WebException) + { + //连接失败 + return null; + } + } + + public void Init(PluginInitContext context) + { + this.context = context; + } + + private PluginInitContext context { get; set; } + } +} diff --git a/Plugins/WinAlfred.Plugin.System/Properties/AssemblyInfo.cs b/Plugins/WinAlfred.Plugin.Fanyi/Properties/AssemblyInfo.cs similarity index 81% rename from Plugins/WinAlfred.Plugin.System/Properties/AssemblyInfo.cs rename to Plugins/WinAlfred.Plugin.Fanyi/Properties/AssemblyInfo.cs index 9f1336c2f..7e841771e 100644 --- a/Plugins/WinAlfred.Plugin.System/Properties/AssemblyInfo.cs +++ b/Plugins/WinAlfred.Plugin.Fanyi/Properties/AssemblyInfo.cs @@ -1,36 +1,36 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// 有关程序集的常规信息通过以下 -// 特性集控制。更改这些特性值可修改 -// 与程序集关联的信息。 -[assembly: AssemblyTitle("WinAlfred.Plugin.System")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyProduct("WinAlfred.Plugin.System")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2013")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// 将 ComVisible 设置为 false 使此程序集中的类型 -// 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型, -// 则将该类型上的 ComVisible 特性设置为 true。 -[assembly: ComVisible(false)] - -// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID -[assembly: Guid("5cdfe514-80c9-4d82-94e7-c6f79a26ccda")] - -// 程序集的版本信息由下面四个值组成: -// -// 主版本 -// 次版本 -// 生成号 -// 修订号 -// -// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, -// 方法是按如下所示使用“*”: -// [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("WinAlfred.Plugin.Fanyi")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("WinAlfred.Plugin.Fanyi")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 使此程序集中的类型 +// 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型, +// 则将该类型上的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("5b55da55-94f5-4248-af75-5eb40409a8ca")] + +// 程序集的版本信息由下面四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, +// 方法是按如下所示使用“*”: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Plugins/WinAlfred.Plugin.System/WinAlfred.Plugin.System.csproj b/Plugins/WinAlfred.Plugin.Fanyi/WinAlfred.Plugin.Fanyi.csproj similarity index 74% rename from Plugins/WinAlfred.Plugin.System/WinAlfred.Plugin.System.csproj rename to Plugins/WinAlfred.Plugin.Fanyi/WinAlfred.Plugin.Fanyi.csproj index a8dacb8d1..30bee4c18 100644 --- a/Plugins/WinAlfred.Plugin.System/WinAlfred.Plugin.System.csproj +++ b/Plugins/WinAlfred.Plugin.Fanyi/WinAlfred.Plugin.Fanyi.csproj @@ -4,13 +4,15 @@ Debug AnyCPU - {E515011D-A769-418B-8761-ABE6F29827A0} + {353769D3-D11C-4D86-BD06-AC8C1D68642B} Library Properties - WinAlfred.Plugin.System - WinAlfred.Plugin.System + WinAlfred.Plugin.Fanyi + WinAlfred.Plugin.Fanyi v3.5 512 + ..\..\ + true true @@ -30,6 +32,12 @@ 4 + + ..\..\packages\HtmlAgilityPack.1.4.6\lib\Net20\HtmlAgilityPack.dll + + + ..\..\packages\Newtonsoft.Json.5.0.8\lib\net35\Newtonsoft.Json.dll + @@ -39,6 +47,7 @@ + @@ -49,18 +58,20 @@ + Always - + + - xcopy /Y $(TargetDir)$(TargetFileName) $(SolutionDir)WinAlfred\bin\Debug\Plugins\System\ -xcopy /Y $(TargetDir)plugin.ini $(SolutionDir)WinAlfred\bin\Debug\Plugins\System\ -xcopy /Y $(ProjectDir)Images\*.* $(SolutionDir)WinAlfred\bin\Debug\Plugins\System\Images\ + xcopy /Y $(TargetDir)$(TargetFileName) $(SolutionDir)WinAlfred\bin\Debug\Plugins\Fanyi\ +xcopy /Y $(TargetDir)plugin.ini $(SolutionDir)WinAlfred\bin\Debug\Plugins\Fanyi\ +xcopy /Y $(ProjectDir)Images\*.* $(SolutionDir)WinAlfred\bin\Debug\Plugins\Fanyi\Images\ + \ No newline at end of file diff --git a/WinAlfred.Plugin.System/packages.config b/WinAlfred.Plugin.System/packages.config new file mode 100644 index 000000000..9520f36d8 --- /dev/null +++ b/WinAlfred.Plugin.System/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/WinAlfred.Plugin/IPlugin.cs b/WinAlfred.Plugin/IPlugin.cs index 87a68f68e..e159235e7 100644 --- a/WinAlfred.Plugin/IPlugin.cs +++ b/WinAlfred.Plugin/IPlugin.cs @@ -5,6 +5,6 @@ namespace WinAlfred.Plugin public interface IPlugin { List Query(Query query); - void Init(); + void Init(PluginInitContext context); } } \ No newline at end of file diff --git a/WinAlfred.Plugin/PluginInitContext.cs b/WinAlfred.Plugin/PluginInitContext.cs new file mode 100644 index 000000000..70025c258 --- /dev/null +++ b/WinAlfred.Plugin/PluginInitContext.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace WinAlfred.Plugin +{ + public class PluginInitContext + { + public List Plugins { get; set; } + + public Action ChangeQuery { get; set; } + public Action CloseApp { get; set; } + public Action HideApp { get; set; } + public Action ShowApp { get; set; } + public Action ShowMsg { get; set; } + } +} diff --git a/WinAlfred.Plugin/PluginMetadata.cs b/WinAlfred.Plugin/PluginMetadata.cs index 23d54b8c2..167e299e5 100644 --- a/WinAlfred.Plugin/PluginMetadata.cs +++ b/WinAlfred.Plugin/PluginMetadata.cs @@ -16,5 +16,6 @@ namespace WinAlfred.Plugin public string ExecuteFileName { get; set; } public string PluginDirecotry { get; set; } public string ActionKeyword { get; set; } + public PluginType PluginType { get; set; } } } diff --git a/WinAlfred.Plugin/PluginType.cs b/WinAlfred.Plugin/PluginType.cs new file mode 100644 index 000000000..1db293c16 --- /dev/null +++ b/WinAlfred.Plugin/PluginType.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace WinAlfred.Plugin +{ + public enum PluginType + { + System, + ThirdParty + } +} diff --git a/WinAlfred.Plugin/Result.cs b/WinAlfred.Plugin/Result.cs index a66b8851d..784670c7c 100644 --- a/WinAlfred.Plugin/Result.cs +++ b/WinAlfred.Plugin/Result.cs @@ -11,11 +11,35 @@ namespace WinAlfred.Plugin public string IcoPath { get; set; } public Action Action { get; set; } public int Score { get; set; } + + public bool DontHideWinAlfredAfterAction { get; set; } + + //todo: this should be controlled by system, not visible to users + /// + /// Only resulsts that originQuery match with curren query will be displayed in the panel + /// + public Query OriginQuery { get; set; } + /// + /// context results connected with current reuslt, usually, it can use <- or -> navigate context results + /// public List ContextResults { get; set; } /// /// you don't need to set this property if you are developing a plugin /// public string PluginDirectory { get; set; } + + public new bool Equals(object obj) + { + if (obj == null || !(obj is Result)) return false; + + Result r = (Result)obj; + return r.Title == Title && r.SubTitle == SubTitle; + } + + public override string ToString() + { + return Title + SubTitle; + } } } \ No newline at end of file diff --git a/WinAlfred.Plugin/WinAlfred.Plugin.csproj b/WinAlfred.Plugin/WinAlfred.Plugin.csproj index e0b1b3869..efcee86f4 100644 --- a/WinAlfred.Plugin/WinAlfred.Plugin.csproj +++ b/WinAlfred.Plugin/WinAlfred.Plugin.csproj @@ -60,7 +60,9 @@ + + diff --git a/WinAlfred.sln b/WinAlfred.sln index 6c6a89568..eca79e1fa 100644 --- a/WinAlfred.sln +++ b/WinAlfred.sln @@ -7,13 +7,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinAlfred.Plugin", "WinAlfr EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugin", "Plugin", "{3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinAlfred.Plugin.System", "Plugins\WinAlfred.Plugin.System\WinAlfred.Plugin.System.csproj", "{E515011D-A769-418B-8761-ABE6F29827A0}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinAlfred", "WinAlfred\WinAlfred.csproj", "{DB90F671-D861-46BB-93A3-F1304F5BA1C5}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PyWinAlfred", "PyWinAlfred\PyWinAlfred.vcxproj", "{D03FD663-38A8-4C1A-8431-EB44F93E7EBA}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinAlfred.Plugin.System", "WinAlfred.Plugin.System\WinAlfred.Plugin.System.csproj", "{69CE0206-CB41-453D-88AF-DF86092EF9B8}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PyWinAlfred.Test", "PyWinAlfred.Test\PyWinAlfred.Test.vcxproj", "{05D72D92-4010-4F92-A147-906930241573}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinAlfred.Plugin.Fanyi", "Plugins\WinAlfred.Plugin.Fanyi\WinAlfred.Plugin.Fanyi.csproj", "{353769D3-D11C-4D86-BD06-AC8C1D68642B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -54,26 +52,12 @@ Global {8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Debug|x86.Build.0 = Debug|Any CPU {8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Release|Any CPU.ActiveCfg = Release|Any CPU {8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Release|Any CPU.Build.0 = Release|Any CPU - {8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Release|Mixed Platforms.ActiveCfg = Release|x86 - {8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Release|Mixed Platforms.Build.0 = Release|x86 + {8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Release|Mixed Platforms.Build.0 = Release|Any CPU {8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Release|Win32.ActiveCfg = Release|x86 {8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Release|Win32.Build.0 = Release|x86 {8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Release|x64.ActiveCfg = Release|Any CPU {8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Release|x86.ActiveCfg = Release|Any CPU - {E515011D-A769-418B-8761-ABE6F29827A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E515011D-A769-418B-8761-ABE6F29827A0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E515011D-A769-418B-8761-ABE6F29827A0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {E515011D-A769-418B-8761-ABE6F29827A0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {E515011D-A769-418B-8761-ABE6F29827A0}.Debug|Win32.ActiveCfg = Debug|Any CPU - {E515011D-A769-418B-8761-ABE6F29827A0}.Debug|x64.ActiveCfg = Debug|Any CPU - {E515011D-A769-418B-8761-ABE6F29827A0}.Debug|x86.ActiveCfg = Debug|Any CPU - {E515011D-A769-418B-8761-ABE6F29827A0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E515011D-A769-418B-8761-ABE6F29827A0}.Release|Any CPU.Build.0 = Release|Any CPU - {E515011D-A769-418B-8761-ABE6F29827A0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {E515011D-A769-418B-8761-ABE6F29827A0}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {E515011D-A769-418B-8761-ABE6F29827A0}.Release|Win32.ActiveCfg = Release|Any CPU - {E515011D-A769-418B-8761-ABE6F29827A0}.Release|x64.ActiveCfg = Release|Any CPU - {E515011D-A769-418B-8761-ABE6F29827A0}.Release|x86.ActiveCfg = Release|Any CPU {DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Debug|Any CPU.Build.0 = Debug|Any CPU {DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU @@ -88,45 +72,39 @@ Global {DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Release|Win32.ActiveCfg = Release|Any CPU {DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Release|x64.ActiveCfg = Release|Any CPU {DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Release|x86.ActiveCfg = Release|Any CPU - {D03FD663-38A8-4C1A-8431-EB44F93E7EBA}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {D03FD663-38A8-4C1A-8431-EB44F93E7EBA}.Debug|Mixed Platforms.ActiveCfg = Debug|x64 - {D03FD663-38A8-4C1A-8431-EB44F93E7EBA}.Debug|Mixed Platforms.Build.0 = Debug|x64 - {D03FD663-38A8-4C1A-8431-EB44F93E7EBA}.Debug|Win32.ActiveCfg = Debug|Win32 - {D03FD663-38A8-4C1A-8431-EB44F93E7EBA}.Debug|Win32.Build.0 = Debug|Win32 - {D03FD663-38A8-4C1A-8431-EB44F93E7EBA}.Debug|x64.ActiveCfg = Debug|x64 - {D03FD663-38A8-4C1A-8431-EB44F93E7EBA}.Debug|x64.Build.0 = Debug|x64 - {D03FD663-38A8-4C1A-8431-EB44F93E7EBA}.Debug|x86.ActiveCfg = Debug|Win32 - {D03FD663-38A8-4C1A-8431-EB44F93E7EBA}.Debug|x86.Build.0 = Debug|Win32 - {D03FD663-38A8-4C1A-8431-EB44F93E7EBA}.Release|Any CPU.ActiveCfg = Release|Win32 - {D03FD663-38A8-4C1A-8431-EB44F93E7EBA}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {D03FD663-38A8-4C1A-8431-EB44F93E7EBA}.Release|Mixed Platforms.Build.0 = Release|Win32 - {D03FD663-38A8-4C1A-8431-EB44F93E7EBA}.Release|Win32.ActiveCfg = Release|Win32 - {D03FD663-38A8-4C1A-8431-EB44F93E7EBA}.Release|Win32.Build.0 = Release|Win32 - {D03FD663-38A8-4C1A-8431-EB44F93E7EBA}.Release|x64.ActiveCfg = Release|x64 - {D03FD663-38A8-4C1A-8431-EB44F93E7EBA}.Release|x64.Build.0 = Release|x64 - {D03FD663-38A8-4C1A-8431-EB44F93E7EBA}.Release|x86.ActiveCfg = Release|Win32 - {D03FD663-38A8-4C1A-8431-EB44F93E7EBA}.Release|x86.Build.0 = Release|Win32 - {05D72D92-4010-4F92-A147-906930241573}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {05D72D92-4010-4F92-A147-906930241573}.Debug|Mixed Platforms.ActiveCfg = Debug|x64 - {05D72D92-4010-4F92-A147-906930241573}.Debug|Mixed Platforms.Build.0 = Debug|x64 - {05D72D92-4010-4F92-A147-906930241573}.Debug|Win32.ActiveCfg = Debug|Win32 - {05D72D92-4010-4F92-A147-906930241573}.Debug|Win32.Build.0 = Debug|Win32 - {05D72D92-4010-4F92-A147-906930241573}.Debug|x64.ActiveCfg = Debug|Win32 - {05D72D92-4010-4F92-A147-906930241573}.Debug|x86.ActiveCfg = Debug|Win32 - {05D72D92-4010-4F92-A147-906930241573}.Debug|x86.Build.0 = Debug|Win32 - {05D72D92-4010-4F92-A147-906930241573}.Release|Any CPU.ActiveCfg = Release|Win32 - {05D72D92-4010-4F92-A147-906930241573}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {05D72D92-4010-4F92-A147-906930241573}.Release|Mixed Platforms.Build.0 = Release|Win32 - {05D72D92-4010-4F92-A147-906930241573}.Release|Win32.ActiveCfg = Release|Win32 - {05D72D92-4010-4F92-A147-906930241573}.Release|Win32.Build.0 = Release|Win32 - {05D72D92-4010-4F92-A147-906930241573}.Release|x64.ActiveCfg = Release|Win32 - {05D72D92-4010-4F92-A147-906930241573}.Release|x86.ActiveCfg = Release|Win32 - {05D72D92-4010-4F92-A147-906930241573}.Release|x86.Build.0 = Release|Win32 + {69CE0206-CB41-453D-88AF-DF86092EF9B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {69CE0206-CB41-453D-88AF-DF86092EF9B8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {69CE0206-CB41-453D-88AF-DF86092EF9B8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {69CE0206-CB41-453D-88AF-DF86092EF9B8}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {69CE0206-CB41-453D-88AF-DF86092EF9B8}.Debug|Win32.ActiveCfg = Debug|Any CPU + {69CE0206-CB41-453D-88AF-DF86092EF9B8}.Debug|x64.ActiveCfg = Debug|Any CPU + {69CE0206-CB41-453D-88AF-DF86092EF9B8}.Debug|x86.ActiveCfg = Debug|Any CPU + {69CE0206-CB41-453D-88AF-DF86092EF9B8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {69CE0206-CB41-453D-88AF-DF86092EF9B8}.Release|Any CPU.Build.0 = Release|Any CPU + {69CE0206-CB41-453D-88AF-DF86092EF9B8}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {69CE0206-CB41-453D-88AF-DF86092EF9B8}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {69CE0206-CB41-453D-88AF-DF86092EF9B8}.Release|Win32.ActiveCfg = Release|Any CPU + {69CE0206-CB41-453D-88AF-DF86092EF9B8}.Release|x64.ActiveCfg = Release|Any CPU + {69CE0206-CB41-453D-88AF-DF86092EF9B8}.Release|x86.ActiveCfg = Release|Any CPU + {353769D3-D11C-4D86-BD06-AC8C1D68642B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {353769D3-D11C-4D86-BD06-AC8C1D68642B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {353769D3-D11C-4D86-BD06-AC8C1D68642B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {353769D3-D11C-4D86-BD06-AC8C1D68642B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {353769D3-D11C-4D86-BD06-AC8C1D68642B}.Debug|Win32.ActiveCfg = Debug|Any CPU + {353769D3-D11C-4D86-BD06-AC8C1D68642B}.Debug|x64.ActiveCfg = Debug|Any CPU + {353769D3-D11C-4D86-BD06-AC8C1D68642B}.Debug|x86.ActiveCfg = Debug|Any CPU + {353769D3-D11C-4D86-BD06-AC8C1D68642B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {353769D3-D11C-4D86-BD06-AC8C1D68642B}.Release|Any CPU.Build.0 = Release|Any CPU + {353769D3-D11C-4D86-BD06-AC8C1D68642B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {353769D3-D11C-4D86-BD06-AC8C1D68642B}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {353769D3-D11C-4D86-BD06-AC8C1D68642B}.Release|Win32.ActiveCfg = Release|Any CPU + {353769D3-D11C-4D86-BD06-AC8C1D68642B}.Release|x64.ActiveCfg = Release|Any CPU + {353769D3-D11C-4D86-BD06-AC8C1D68642B}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {E515011D-A769-418B-8761-ABE6F29827A0} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} + {353769D3-D11C-4D86-BD06-AC8C1D68642B} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} EndGlobalSection EndGlobal diff --git a/WinAlfred/App.config b/WinAlfred/App.config index 01c0f5391..e1eb5518f 100644 --- a/WinAlfred/App.config +++ b/WinAlfred/App.config @@ -17,4 +17,4 @@ - + diff --git a/WinAlfred/App.xaml b/WinAlfred/App.xaml index ba0967d5d..43657b441 100644 --- a/WinAlfred/App.xaml +++ b/WinAlfred/App.xaml @@ -1,7 +1,7 @@  + > + diff --git a/WinAlfred/App.xaml.cs b/WinAlfred/App.xaml.cs index cc2295037..dfb3747a1 100644 --- a/WinAlfred/App.xaml.cs +++ b/WinAlfred/App.xaml.cs @@ -1,11 +1,28 @@ -using System.Windows; - -namespace WinAlfred -{ - /// - /// App.xaml 的交互逻辑 - /// - public partial class App : Application - { - } -} +using System; +using System.Threading; +using System.Windows; + +namespace WinAlfred +{ + /// + /// App.xaml 的交互逻辑 + /// + public partial class App : Application + { + protected override void OnStartup(StartupEventArgs e) + { + base.OnStartup(e); + bool startupFlag; + Mutex mutex = new Mutex(true, "WinAlfred", out startupFlag); + if (!startupFlag) + { + Environment.Exit(0); + } + else + { + MainWindow mainWindow = new MainWindow(); + mainWindow.Show(); + } + } + } +} diff --git a/WinAlfred/Commands/BaseCommand.cs b/WinAlfred/Commands/BaseCommand.cs new file mode 100644 index 000000000..fd16c8ab5 --- /dev/null +++ b/WinAlfred/Commands/BaseCommand.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using WinAlfred.Plugin; + +namespace WinAlfred.Commands +{ + public abstract class BaseCommand + { + private MainWindow window; + + public abstract void Dispatch(Query query); + + //TODO:Ugly, we should subscribe events here, instead of just use usercontrol as the parameter + protected BaseCommand(MainWindow window) + { + this.window = window; + } + + protected void UpdateResultView(List results) + { + window.OnUpdateResultView(results); + } + } +} diff --git a/WinAlfred/Commands/Command.cs b/WinAlfred/Commands/Command.cs new file mode 100644 index 000000000..7e9af536e --- /dev/null +++ b/WinAlfred/Commands/Command.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using WinAlfred.Helper; +using WinAlfred.Plugin; + +namespace WinAlfred.Commands +{ + public class Command + { + private PluginCommand pluginCmd; + private SystemCommand systemCmd; + + public Command(MainWindow window) + { + pluginCmd = new PluginCommand(window); + systemCmd = new SystemCommand(window); + } + + public void DispatchCommand(Query query) + { + systemCmd.Dispatch(query); + pluginCmd.Dispatch(query); + } + } +} diff --git a/WinAlfred/Commands/PluginCommand.cs b/WinAlfred/Commands/PluginCommand.cs new file mode 100644 index 000000000..f30b667ac --- /dev/null +++ b/WinAlfred/Commands/PluginCommand.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using WinAlfred.Helper; +using WinAlfred.Plugin; +using WinAlfred.PluginLoader; + +namespace WinAlfred.Commands +{ + public class PluginCommand : BaseCommand + { + public PluginCommand(MainWindow mainWindow) + : base(mainWindow) + { + + } + + public override void Dispatch(Query q) + { + + foreach (PluginPair pair in Plugins.AllPlugins) + { + if (pair.Metadata.ActionKeyword == q.ActionName) + { + PluginPair pair1 = pair; + ThreadPool.QueueUserWorkItem(state => + { + try + { + List r = pair1.Plugin.Query(q); + r.ForEach(o => + { + o.PluginDirectory = pair1.Metadata.PluginDirecotry; + o.OriginQuery = q; + }); + UpdateResultView(r); + } + catch (Exception queryException) + { + Log.Error(string.Format("Plugin {0} query failed: {1}", pair1.Metadata.Name, + queryException.Message)); +#if (DEBUG) + { + throw; + } +#endif + } + }); + } + } + } + } +} diff --git a/WinAlfred/Commands/SystemCommand.cs b/WinAlfred/Commands/SystemCommand.cs new file mode 100644 index 000000000..7ecad9820 --- /dev/null +++ b/WinAlfred/Commands/SystemCommand.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using WinAlfred.Plugin; +using WinAlfred.PluginLoader; + +namespace WinAlfred.Commands +{ + public class SystemCommand : BaseCommand + { + private List systemPlugins; + + public SystemCommand(MainWindow window) + : base(window) + { + systemPlugins = Plugins.AllPlugins.Where(o => o.Metadata.PluginType == PluginType.System).ToList(); + } + + public override void Dispatch(Query query) + { + foreach (PluginPair pair in systemPlugins) + { + PluginPair pair1 = pair; + ThreadPool.QueueUserWorkItem(state => + { + List results = pair1.Plugin.Query(query); + foreach (Result result in results) + { + result.PluginDirectory = pair1.Metadata.PluginDirecotry; + result.OriginQuery = query; + } + if(results.Count > 0) UpdateResultView(results); + }); + } + } + } +} diff --git a/WinAlfred/DispatcherExtensions.cs b/WinAlfred/DispatcherExtensions.cs new file mode 100644 index 000000000..15a56bfa7 --- /dev/null +++ b/WinAlfred/DispatcherExtensions.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Threading; + +namespace WinAlfred +{ + public static class DispatcherExtensions + { + private static Dictionary timers = + new Dictionary(); + private static readonly object syncRoot = new object(); + + public static string DelayInvoke(this Dispatcher dispatcher, string namedInvocation, + Action action, TimeSpan delay, + DispatcherPriority priority = DispatcherPriority.Normal) + { + return DelayInvoke(dispatcher, namedInvocation, action, delay, string.Empty, priority); + } + + public static string DelayInvoke(this Dispatcher dispatcher, string namedInvocation, + Action action, TimeSpan delay, string arg, + DispatcherPriority priority = DispatcherPriority.Normal) + { + lock (syncRoot) + { + if (String.IsNullOrEmpty(namedInvocation)) + { + namedInvocation = Guid.NewGuid().ToString(); + } + else + { + RemoveTimer(namedInvocation); + } + var timer = new DispatcherTimer(delay, priority, (s, e) => + { + RemoveTimer(namedInvocation); + action(arg); + }, dispatcher); + timer.Start(); + timers.Add(namedInvocation, timer); + return namedInvocation; + } + } + + + public static void CancelNamedInvocation(this Dispatcher dispatcher, string namedInvocation) + { + lock (syncRoot) + { + RemoveTimer(namedInvocation); + } + } + + private static void RemoveTimer(string namedInvocation) + { + if (!timers.ContainsKey(namedInvocation)) return; + timers[namedInvocation].Stop(); + timers.Remove(namedInvocation); + } + + } +} diff --git a/WinAlfred/Helper/KeyboardHook.cs b/WinAlfred/Helper/KeyboardHook.cs index 97a775534..be717a541 100644 --- a/WinAlfred/Helper/KeyboardHook.cs +++ b/WinAlfred/Helper/KeyboardHook.cs @@ -85,6 +85,7 @@ namespace WinAlfred.Helper if (!RegisterHotKey(window.Handle, currentId, (uint)xModifier, (uint)key)) { Log.Error("Couldn’t register the hot key."); + MessageBox.Show("Couldn’t register the hot key."); #if (DEBUG) { throw new InvalidOperationException("Couldn’t register the hot key."); diff --git a/WinAlfred/Helper/SelectedRecords.cs b/WinAlfred/Helper/SelectedRecords.cs new file mode 100644 index 000000000..21b49bd26 --- /dev/null +++ b/WinAlfred/Helper/SelectedRecords.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.Serialization.Formatters.Binary; +using System.Windows.Documents; +using WinAlfred.Plugin; + +namespace WinAlfred.Helper +{ + public class SelectedRecords + { + private int hasAddedCount = 0; + private Dictionary dict = new Dictionary(); + private string filePath = Directory.GetCurrentDirectory() + "\\selectedRecords.dat"; + + public void LoadSelectedRecords() + { + if (File.Exists(filePath)) + { + FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); + BinaryFormatter b = new BinaryFormatter(); + dict = (Dictionary)b.Deserialize(fileStream); + fileStream.Close(); + } + + if (dict.Count > 1000) + { + List onlyOnceKeys = (from c in dict where c.Value == 1 select c.Key).ToList(); + foreach (string onlyOnceKey in onlyOnceKeys) + { + dict.Remove(onlyOnceKey); + } + } + } + + public void AddSelect(Result result) + { + hasAddedCount++; + if (hasAddedCount == 10) + { + SaveSelectedRecords(); + hasAddedCount = 0; + } + + if (dict.ContainsKey(result.ToString())) + { + dict[result.ToString()] += 1; + } + else + { + dict.Add(result.ToString(), 1); + } + } + + public int GetSelectedCount(Result result) + { + if (dict.ContainsKey(result.ToString())) + { + return dict[result.ToString()]; + } + return 0; + } + + private void SaveSelectedRecords() + { + FileStream fileStream = new FileStream("selectedRecords.dat", FileMode.Create); + BinaryFormatter b = new BinaryFormatter(); + b.Serialize(fileStream, dict); + fileStream.Close(); + } + } +} diff --git a/WinAlfred/Images/bookmark.png b/WinAlfred/Images/bookmark.png new file mode 100644 index 000000000..b8aee3564 Binary files /dev/null and b/WinAlfred/Images/bookmark.png differ diff --git a/WinAlfred/Images/close.png b/WinAlfred/Images/close.png new file mode 100644 index 000000000..5ddfe20b8 Binary files /dev/null and b/WinAlfred/Images/close.png differ diff --git a/WinAlfred/Images/cmd.png b/WinAlfred/Images/cmd.png new file mode 100644 index 000000000..4e4ca0944 Binary files /dev/null and b/WinAlfred/Images/cmd.png differ diff --git a/WinAlfred/Images/enter.png b/WinAlfred/Images/enter.png new file mode 100644 index 000000000..0999b37cd Binary files /dev/null and b/WinAlfred/Images/enter.png differ diff --git a/WinAlfred/Images/exit.png b/WinAlfred/Images/exit.png new file mode 100644 index 000000000..af7c73824 Binary files /dev/null and b/WinAlfred/Images/exit.png differ diff --git a/Plugins/WinAlfred.Plugin.System/Images/lock.png b/WinAlfred/Images/folder.png similarity index 59% rename from Plugins/WinAlfred.Plugin.System/Images/lock.png rename to WinAlfred/Images/folder.png index 5a1593aaf..330cb2e4b 100644 Binary files a/Plugins/WinAlfred.Plugin.System/Images/lock.png and b/WinAlfred/Images/folder.png differ diff --git a/WinAlfred/Images/lock.png b/WinAlfred/Images/lock.png new file mode 100644 index 000000000..3eaa9abaa Binary files /dev/null and b/WinAlfred/Images/lock.png differ diff --git a/WinAlfred/Images/logoff.png b/WinAlfred/Images/logoff.png new file mode 100644 index 000000000..73c1379b2 Binary files /dev/null and b/WinAlfred/Images/logoff.png differ diff --git a/WinAlfred/Images/work.png b/WinAlfred/Images/work.png new file mode 100644 index 000000000..aa447afd8 Binary files /dev/null and b/WinAlfred/Images/work.png differ diff --git a/WinAlfred/MainWindow.xaml b/WinAlfred/MainWindow.xaml index 0d1d3d8bb..02da826d8 100644 --- a/WinAlfred/MainWindow.xaml +++ b/WinAlfred/MainWindow.xaml @@ -12,9 +12,15 @@ ShowInTaskbar="False" Icon="Images\ico.png" > - - - - + + + + + + + + + + diff --git a/WinAlfred/MainWindow.xaml.cs b/WinAlfred/MainWindow.xaml.cs index 7eea9d383..35fd1f299 100644 --- a/WinAlfred/MainWindow.xaml.cs +++ b/WinAlfred/MainWindow.xaml.cs @@ -1,34 +1,56 @@ using System; using System.Collections.Generic; -using System.IO.Ports; using System.Linq; using System.Threading; using System.Windows; using System.Windows.Controls; using System.Windows.Forms; using System.Windows.Input; -using System.Windows.Threading; +using System.Windows.Media.Animation; +using System.Windows.Shapes; +using IWshRuntimeLibrary; +using Microsoft.Win32; +using WinAlfred.Commands; using WinAlfred.Helper; using WinAlfred.Plugin; using WinAlfred.PluginLoader; using KeyEventArgs = System.Windows.Input.KeyEventArgs; +using MessageBox = System.Windows.MessageBox; +using Timer = System.Threading.Timer; namespace WinAlfred { - public partial class MainWindow : Window + public partial class MainWindow { private KeyboardHook hook = new KeyboardHook(); - public List plugins = new List(); - private List results = new List(); - private NotifyIcon notifyIcon = null; + private NotifyIcon notifyIcon; + private Command cmdDispatcher; + Storyboard progressBarStoryboard = new Storyboard(); + private bool queryHasReturn = false; + SelectedRecords selectedRecords = new SelectedRecords(); public MainWindow() { InitializeComponent(); + hook.KeyPressed += OnHotKey; hook.RegisterHotKey(XModifierKeys.Alt, Keys.Space); resultCtrl.resultItemChangedEvent += resultCtrl_resultItemChangedEvent; - ThreadPool.SetMaxThreads(10, 5); + ThreadPool.SetMaxThreads(30, 10); + InitProgressbarAnimation(); + } + + private void InitProgressbarAnimation() + { + DoubleAnimation da = new DoubleAnimation(progressBar.X2, Width + 100, new Duration(new TimeSpan(0, 0, 0, 0, 1600))); + DoubleAnimation da1 = new DoubleAnimation(progressBar.X1, Width, 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() @@ -38,11 +60,7 @@ namespace WinAlfred System.Windows.Forms.MenuItem open = new System.Windows.Forms.MenuItem("Open"); open.Click += (o, e) => ShowWinAlfred(); System.Windows.Forms.MenuItem exit = new System.Windows.Forms.MenuItem("Exit"); - exit.Click += (o, e) => - { - notifyIcon.Visible = false; - Close(); - }; + exit.Click += (o, e) => CloseApp(); System.Windows.Forms.MenuItem[] childen = { open, exit }; notifyIcon.ContextMenu = new System.Windows.Forms.ContextMenu(childen); } @@ -50,7 +68,7 @@ namespace WinAlfred private void resultCtrl_resultItemChangedEvent() { Height = resultCtrl.pnlContainer.ActualHeight + tbQuery.Height + tbQuery.Margin.Top + tbQuery.Margin.Bottom; - resultCtrl.Margin = results.Count > 0 ? new Thickness { Bottom = 10, Left = 10, Right = 10 } : new Thickness { Bottom = 0, Left = 10, Right = 10 }; + resultCtrl.Margin = resultCtrl.GetCurrentResultCount() > 0 ? new Thickness { Bottom = 10, Left = 10, Right = 10 } : new Thickness { Bottom = 0, Left = 10, Right = 10 }; } private void OnHotKey(object sender, KeyPressedEventArgs e) @@ -65,40 +83,53 @@ namespace WinAlfred } } + protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) + { + base.OnMouseLeftButtonDown(e); + + // Begin dragging the window + this.DragMove(); + } + private void TextBoxBase_OnTextChanged(object sender, TextChangedEventArgs e) { - string query = tbQuery.Text; - ThreadPool.QueueUserWorkItem(state => - { - results.Clear(); - foreach (PluginPair pair in plugins) - { - var q = new Query(query); - if (pair.Metadata.ActionKeyword == q.ActionName) - { - try - { - results.AddRange(pair.Plugin.Query(q)); - results.ForEach(o => o.PluginDirectory = pair.Metadata.PluginDirecotry); - } - catch (Exception queryException) - { - Log.Error(string.Format("Plugin {0} query failed: {1}", pair.Metadata.Name, - queryException.Message)); -#if (DEBUG) - { - throw; - } -#endif - } - } - } - resultCtrl.Dispatcher.Invoke(new Action(() => - { - resultCtrl.AddResults(results.OrderByDescending(o => o.Score).ToList()); - resultCtrl.SelectFirst(); - })); - }); + resultCtrl.Dirty = true; + Dispatcher.DelayInvoke("UpdateSearch", + o => + { + Dispatcher.DelayInvoke("ClearResults", i => + { + // first try to use clear method inside resultCtrl, which is more closer to the add new results + // and this will not bring splash issues.After waiting 30ms, 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 (resultCtrl.Dirty) resultCtrl.Clear(); + }, TimeSpan.FromMilliseconds(30), null); + var q = new Query(tbQuery.Text); + cmdDispatcher.DispatchCommand(q); + queryHasReturn = false; + if (Plugins.HitThirdpartyKeyword(q)) + { + Dispatcher.DelayInvoke("ShowProgressbar", originQuery => + { + if (!queryHasReturn && originQuery == tbQuery.Text) + { + StartProgress(); + } + }, TimeSpan.FromSeconds(1), tbQuery.Text); + } + + }, TimeSpan.FromMilliseconds(300)); + } + + private void StartProgress() + { + progressBar.Visibility = Visibility.Visible; + } + + private void StopProgress() + { + progressBar.Visibility = Visibility.Hidden; } private void HideWinAlfred() @@ -108,19 +139,46 @@ namespace WinAlfred private void ShowWinAlfred() { - tbQuery.SelectAll(); Show(); - Focus(); - FocusManager.SetFocusedElement(this, tbQuery); + //FocusManager.SetFocusedElement(this, tbQuery); + tbQuery.Focusable = true; + Keyboard.Focus(tbQuery); + tbQuery.SelectAll(); + + if (!tbQuery.IsKeyboardFocused) + { + MessageBox.Show("didnt focus"); + } + } + + private void SetAutoStart(bool IsAtuoRun) + { + string LnkPath = Environment.GetFolderPath(Environment.SpecialFolder.Startup) + "//WinAlfred.lnk"; + if (IsAtuoRun) + { + WshShell shell = new WshShell(); + IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut(LnkPath); + shortcut.TargetPath = System.Reflection.Assembly.GetExecutingAssembly().Location; + shortcut.WorkingDirectory = Environment.CurrentDirectory; + shortcut.WindowStyle = 1; //normal window + shortcut.Description = "WinAlfred"; + shortcut.Save(); + } + else + { + System.IO.File.Delete(LnkPath); + } } private void MainWindow_OnLoaded(object sender, RoutedEventArgs e) { - plugins.AddRange(new PythonPluginLoader().LoadPlugin()); - plugins.AddRange(new CSharpPluginLoader().LoadPlugin()); - - ShowWinAlfred(); + Plugins.Init(this); + cmdDispatcher = new Command(this); InitialTray(); + selectedRecords.LoadSelectedRecords(); + SetAutoStart(true); + //var engine = new Jurassic.ScriptEngine(); + //MessageBox.Show(engine.Evaluate("5 * 10 + 2").ToString()); } private void TbQuery_OnPreviewKeyDown(object sender, KeyEventArgs e) @@ -143,11 +201,70 @@ namespace WinAlfred break; case Key.Enter: - resultCtrl.AcceptSelect(); - HideWinAlfred(); + Result result = resultCtrl.AcceptSelect(); + if (result != null) + { + selectedRecords.AddSelect(result); + if (!result.DontHideWinAlfredAfterAction) + { + HideWinAlfred(); + } + } e.Handled = true; break; } } + + public void OnUpdateResultView(List list) + { + queryHasReturn = true; + progressBar.Dispatcher.Invoke(new Action(StopProgress)); + if (list.Count > 0) + { + list.ForEach(o => + { + o.Score += selectedRecords.GetSelectedCount(o); + }); + resultCtrl.Dispatcher.Invoke(new Action(() => + { + List l = list.Where(o => o.OriginQuery != null && o.OriginQuery.RawQuery == tbQuery.Text).OrderByDescending(o => o.Score).ToList(); + resultCtrl.AddResults(l); + })); + } + } + + #region Public API + + //Those method can be invoked by plugins + + public void ChangeQuery(string query) + { + tbQuery.Text = query; + tbQuery.CaretIndex = tbQuery.Text.Length; + } + + public void CloseApp() + { + notifyIcon.Visible = false; + Close(); + } + + public void HideApp() + { + HideWinAlfred(); + } + + public void ShowApp() + { + ShowWinAlfred(); + } + + public void ShowMsg(string title, string subTitle, string iconPath) + { + Msg m = new Msg { Owner = GetWindow(this) }; + m.Show(title, subTitle, iconPath); + } + + #endregion } } \ No newline at end of file diff --git a/WinAlfred/Msg.xaml b/WinAlfred/Msg.xaml new file mode 100644 index 000000000..06d7a65d6 --- /dev/null +++ b/WinAlfred/Msg.xaml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + Title + sdfdsf + + + + diff --git a/WinAlfred/Msg.xaml.cs b/WinAlfred/Msg.xaml.cs new file mode 100644 index 000000000..5959f7286 --- /dev/null +++ b/WinAlfred/Msg.xaml.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Forms; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; +using Timer = System.Threading.Timer; + +namespace WinAlfred +{ + public partial class Msg : Window + { + Storyboard fadeOutStoryboard = new Storyboard(); + private bool closing = false; + + public Msg() + { + InitializeComponent(); + + Left = Screen.PrimaryScreen.WorkingArea.Right - this.Width; + Top = Screen.PrimaryScreen.Bounds.Bottom; + showAnimation.From = Screen.PrimaryScreen.Bounds.Bottom; + showAnimation.To = Screen.PrimaryScreen.WorkingArea.Bottom - Height; + + // Create the fade out storyboard + fadeOutStoryboard.Completed += new EventHandler(fadeOutStoryboard_Completed); + DoubleAnimation fadeOutAnimation = new DoubleAnimation(Screen.PrimaryScreen.WorkingArea.Bottom - Height, Screen.PrimaryScreen.Bounds.Bottom, new Duration(TimeSpan.FromSeconds(0.3))) + { + AccelerationRatio = 0.2 + }; + Storyboard.SetTarget(fadeOutAnimation, this); + Storyboard.SetTargetProperty(fadeOutAnimation, new PropertyPath(TopProperty)); + fadeOutStoryboard.Children.Add(fadeOutAnimation); + + imgClose.Source = new BitmapImage(new Uri(AppDomain.CurrentDomain.BaseDirectory + "\\Images\\close.png")); + imgClose.MouseUp += imgClose_MouseUp; + } + + void imgClose_MouseUp(object sender, MouseButtonEventArgs e) + { + if (!closing) + { + closing = true; + fadeOutStoryboard.Begin(); + } + } + + private void fadeOutStoryboard_Completed(object sender, EventArgs e) + { + Close(); + } + + public void Show(string title, string subTitle, string icopath) + { + tbTitle.Text = title; + tbSubTitle.Text = subTitle; + if (!File.Exists(icopath)) + { + icopath = AppDomain.CurrentDomain.BaseDirectory + "Images\\ico.png"; + } + imgIco.Source = new BitmapImage(new Uri(icopath)); + Show(); + + Dispatcher.DelayInvoke("ShowMsg", + o => + { + if (!closing) + { + closing = true; + Dispatcher.Invoke(new Action(fadeOutStoryboard.Begin)); + } + }, TimeSpan.FromSeconds(3)); + } + } +} diff --git a/WinAlfred/PluginLoader/BasePluginLoader.cs b/WinAlfred/PluginLoader/BasePluginLoader.cs index d16042b49..6a48e7aa0 100644 --- a/WinAlfred/PluginLoader/BasePluginLoader.cs +++ b/WinAlfred/PluginLoader/BasePluginLoader.cs @@ -1,8 +1,11 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; +using System.Reflection; using WinAlfred.Helper; using WinAlfred.Plugin; +using WinAlfred.Plugin.System; namespace WinAlfred.PluginLoader { @@ -21,11 +24,27 @@ namespace WinAlfred.PluginLoader private static void ParsePlugins() { - ParseDirectories(); - ParsePackagedPlugin(); + ParseSystemPlugins(); + ParseThirdPartyPlugins(); } - private static void ParseDirectories() + private static void ParseSystemPlugins() + { + PluginMetadata metadata = new PluginMetadata(); + metadata.Name = "System Plugins"; + metadata.Author = "System"; + metadata.Description = "system plugins collection"; + metadata.Language = AllowedLanguage.CSharp; + metadata.Version = "1.0"; + metadata.PluginType = PluginType.System; + metadata.ActionKeyword = "*"; + metadata.ExecuteFileName = "WinAlfred.Plugin.System.dll"; + metadata.ExecuteFilePath = AppDomain.CurrentDomain.BaseDirectory + metadata.ExecuteFileName; + metadata.PluginDirecotry = AppDomain.CurrentDomain.BaseDirectory; + pluginMetadatas.Add(metadata); + } + + private static void ParseThirdPartyPlugins() { string[] directories = Directory.GetDirectories(PluginPath); foreach (string directory in directories) @@ -35,11 +54,6 @@ namespace WinAlfred.PluginLoader } } - private static void ParsePackagedPlugin() - { - - } - private static PluginMetadata GetMetadataFromIni(string directory) { string iniPath = directory + "\\" + PluginConfigName; @@ -50,7 +64,6 @@ namespace WinAlfred.PluginLoader return null; } - try { PluginMetadata metadata = new PluginMetadata(); @@ -60,6 +73,7 @@ namespace WinAlfred.PluginLoader metadata.Description = ini.GetSetting("plugin", "Description"); metadata.Language = ini.GetSetting("plugin", "Language"); metadata.Version = ini.GetSetting("plugin", "Version"); + metadata.PluginType = PluginType.ThirdParty; metadata.ActionKeyword = ini.GetSetting("plugin", "ActionKeyword"); metadata.ExecuteFilePath = AppDomain.CurrentDomain.BaseDirectory + directory + "\\" + ini.GetSetting("plugin", "ExecuteFile"); metadata.PluginDirecotry = AppDomain.CurrentDomain.BaseDirectory + directory + "\\"; diff --git a/WinAlfred/PluginLoader/CSharpPluginLoader.cs b/WinAlfred/PluginLoader/CSharpPluginLoader.cs index db857a830..25346eb3f 100644 --- a/WinAlfred/PluginLoader/CSharpPluginLoader.cs +++ b/WinAlfred/PluginLoader/CSharpPluginLoader.cs @@ -5,6 +5,7 @@ using System.Reflection; using System.Threading; using WinAlfred.Helper; using WinAlfred.Plugin; +using WinAlfred.Plugin.System; namespace WinAlfred.PluginLoader { @@ -20,28 +21,23 @@ namespace WinAlfred.PluginLoader try { Assembly asm = Assembly.LoadFile(metadata.ExecuteFilePath); - List types = asm.GetTypes().Where(o => o.GetInterfaces().Contains(typeof (IPlugin))).ToList(); + List types = asm.GetTypes().Where(o => o.IsClass && o.GetInterfaces().Contains(typeof(IPlugin)) || o.GetInterfaces().Contains(typeof(ISystemPlugin))).ToList(); if (types.Count == 0) { Log.Error(string.Format("Cound't load plugin {0}: didn't find the class who implement IPlugin", metadata.Name)); continue; } - if (types.Count > 1) - { - Log.Error( - string.Format( - "Cound't load plugin {0}: find more than one class who implement IPlugin, there should only one class implement IPlugin", - metadata.Name)); - continue; - } - PluginPair pair = new PluginPair() + foreach (Type type in types) { - Plugin = Activator.CreateInstance(types[0]) as IPlugin, - Metadata = metadata - }; - plugins.Add(pair); + PluginPair pair = new PluginPair() + { + Plugin = Activator.CreateInstance(type) as IPlugin, + Metadata = metadata + }; + plugins.Add(pair); + } } catch (Exception e) { @@ -61,10 +57,7 @@ namespace WinAlfred.PluginLoader private void InitPlugin(List plugins) { - foreach (IPlugin plugin in plugins.Select(pluginPair => pluginPair.Plugin)) - { - new Thread(plugin.Init).Start(); - } + } } } diff --git a/WinAlfred/PluginLoader/Plugins.cs b/WinAlfred/PluginLoader/Plugins.cs new file mode 100644 index 000000000..06bbceb65 --- /dev/null +++ b/WinAlfred/PluginLoader/Plugins.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using WinAlfred.Plugin; + +namespace WinAlfred.PluginLoader +{ + public static class Plugins + { + private static List plugins = new List(); + + public static void Init(MainWindow window) + { + plugins.Clear(); + plugins.AddRange(new PythonPluginLoader().LoadPlugin()); + plugins.AddRange(new CSharpPluginLoader().LoadPlugin()); + foreach (IPlugin plugin in plugins.Select(pluginPair => pluginPair.Plugin)) + { + IPlugin plugin1 = plugin; + ThreadPool.QueueUserWorkItem(o => plugin1.Init(new PluginInitContext() + { + Plugins = plugins, + ChangeQuery = s => window.ChangeQuery(s), + CloseApp = window.CloseApp, + HideApp = window.HideApp, + ShowApp = window.ShowApp, + ShowMsg = (title, subTitle, iconPath) => window.ShowMsg(title, subTitle, iconPath) + })); + } + } + + public static List AllPlugins + { + get { return plugins; } + } + + public static bool HitThirdpartyKeyword(Query query) + { + if (string.IsNullOrEmpty(query.ActionName)) return false; + + return plugins.Any(o => o.Metadata.PluginType == PluginType.ThirdParty && o.Metadata.ActionKeyword == query.ActionName); + } + } +} diff --git a/WinAlfred/PluginLoader/PythonPluginLoader.cs b/WinAlfred/PluginLoader/PythonPluginLoader.cs index baa5052c4..955ec55ef 100644 --- a/WinAlfred/PluginLoader/PythonPluginLoader.cs +++ b/WinAlfred/PluginLoader/PythonPluginLoader.cs @@ -22,10 +22,6 @@ namespace WinAlfred.PluginLoader plugins.Add(pair); } - foreach (IPlugin plugin in plugins.Select(pluginPair => pluginPair.Plugin)) - { - new Thread(plugin.Init).Start(); - } return plugins; } } diff --git a/WinAlfred/PluginLoader/PythonPluginWrapper.cs b/WinAlfred/PluginLoader/PythonPluginWrapper.cs index c9647a573..2dad73816 100644 --- a/WinAlfred/PluginLoader/PythonPluginWrapper.cs +++ b/WinAlfred/PluginLoader/PythonPluginWrapper.cs @@ -55,7 +55,7 @@ namespace WinAlfred.PluginLoader } - public void Init() + public void Init(PluginInitContext context) { InitPythonEnv(); } diff --git a/WinAlfred/Properties/Resources.Designer.cs b/WinAlfred/Properties/Resources.Designer.cs index 5b4270b0d..c04e7374e 100644 --- a/WinAlfred/Properties/Resources.Designer.cs +++ b/WinAlfred/Properties/Resources.Designer.cs @@ -1,73 +1,73 @@ -//------------------------------------------------------------------------------ -// -// 此代码由工具生成。 -// 运行时版本:4.0.30319.18052 -// -// 对此文件的更改可能会导致不正确的行为,并且如果 -// 重新生成代码,这些更改将会丢失。 -// -//------------------------------------------------------------------------------ - -namespace WinAlfred.Properties { - using System; - - - /// - /// 一个强类型的资源类,用于查找本地化的字符串等。 - /// - // 此类是由 StronglyTypedResourceBuilder - // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 - // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen - // (以 /str 作为命令选项),或重新生成 VS 项目。 - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// 返回此类使用的缓存的 ResourceManager 实例。 - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WinAlfred.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// 使用此强类型资源类,为所有资源查找 - /// 重写当前线程的 CurrentUICulture 属性。 - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// 查找类似于 (Icon) 的 System.Drawing.Icon 类型的本地化资源。 - /// - internal static System.Drawing.Icon app { - get { - object obj = ResourceManager.GetObject("app", resourceCulture); - return ((System.Drawing.Icon)(obj)); - } - } - } -} +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.18052 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace WinAlfred.Properties { + using System; + + + /// + /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// 返回此类使用的缓存的 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WinAlfred.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 使用此强类型资源类,为所有资源查找 + /// 重写当前线程的 CurrentUICulture 属性。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// 查找类似于 (Icon) 的 System.Drawing.Icon 类型的本地化资源。 + /// + internal static System.Drawing.Icon app { + get { + object obj = ResourceManager.GetObject("app", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + } +} diff --git a/WinAlfred/Properties/Settings.Designer.cs b/WinAlfred/Properties/Settings.Designer.cs index d6abbf65e..caf9c18c1 100644 --- a/WinAlfred/Properties/Settings.Designer.cs +++ b/WinAlfred/Properties/Settings.Designer.cs @@ -1,26 +1,26 @@ -//------------------------------------------------------------------------------ -// -// 此代码由工具生成。 -// 运行时版本:4.0.30319.18052 -// -// 对此文件的更改可能会导致不正确的行为,并且如果 -// 重新生成代码,这些更改将会丢失。 -// -//------------------------------------------------------------------------------ - -namespace WinAlfred.Properties { - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default { - get { - return defaultInstance; - } - } - } -} +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.18052 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace WinAlfred.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/WinAlfred/ResultItem.xaml b/WinAlfred/ResultItem.xaml index c20bdecc6..34d3ef4d2 100644 --- a/WinAlfred/ResultItem.xaml +++ b/WinAlfred/ResultItem.xaml @@ -21,9 +21,9 @@ Title sdfdsf - - - + + + diff --git a/WinAlfred/ResultItem.xaml.cs b/WinAlfred/ResultItem.xaml.cs index ec251335d..389ee3af3 100644 --- a/WinAlfred/ResultItem.xaml.cs +++ b/WinAlfred/ResultItem.xaml.cs @@ -1,8 +1,12 @@ using System; +using System.Drawing; +using System.IO; +using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Imaging; using WinAlfred.Plugin; +using Brush = System.Windows.Media.Brush; namespace WinAlfred { @@ -23,6 +27,15 @@ namespace WinAlfred selected = value; BrushConverter bc = new BrushConverter(); Background = selected ? (Brush)(bc.ConvertFrom("#d1d1d1")) : (Brush)(bc.ConvertFrom("#ebebeb")); + if (selected) + { + img.Visibility = Visibility.Visible; + img.Source = new BitmapImage(new Uri(Directory.GetCurrentDirectory()+"\\Images\\enter.png")); + } + else + { + img.Visibility = Visibility.Hidden; + } } } @@ -39,10 +52,36 @@ namespace WinAlfred tbTitle.Text = result.Title; tbSubTitle.Text = result.SubTitle; - if (!string.IsNullOrEmpty(result.IcoPath)) + string path = string.Empty; + if (!string.IsNullOrEmpty(result.IcoPath) && result.IcoPath.Contains(":\\") && File.Exists(result.IcoPath)) { - imgIco.Source = new BitmapImage(new Uri(result.PluginDirectory + result.IcoPath)); + path = result.IcoPath; } + else if (!string.IsNullOrEmpty(result.IcoPath) && File.Exists(result.PluginDirectory + result.IcoPath)) + { + path = result.PluginDirectory + result.IcoPath; + } + + if (!string.IsNullOrEmpty(path)) + { + if (path.ToLower().EndsWith(".exe") || path.ToLower().EndsWith(".lnk")) + { + imgIco.Source = GetIcon(path); + } + else + { + imgIco.Source = new BitmapImage(new Uri(path)); + } + } + } + + public static ImageSource GetIcon(string fileName) + { + Icon icon = Icon.ExtractAssociatedIcon(fileName); + return System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon( + icon.Handle, + new Int32Rect(0, 0, icon.Width, icon.Height), + BitmapSizeOptions.FromEmptyOptions()); } } } diff --git a/WinAlfred/ResultPanel.xaml.cs b/WinAlfred/ResultPanel.xaml.cs index 40314fcad..26aa8f959 100644 --- a/WinAlfred/ResultPanel.xaml.cs +++ b/WinAlfred/ResultPanel.xaml.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using System.Windows; using System.Windows.Controls; using WinAlfred.Plugin; @@ -7,6 +8,8 @@ namespace WinAlfred { public partial class ResultPanel : UserControl { + public bool Dirty { get; set; } + public delegate void ResultItemsChanged(); public event ResultItemsChanged resultItemChangedEvent; @@ -19,15 +22,26 @@ namespace WinAlfred public void AddResults(List results) { - pnlContainer.Children.Clear(); + if (results.Count == 0) return; + + if (Dirty) + { + Dirty = false; + pnlContainer.Children.Clear(); + } + for (int i = 0; i < results.Count; i++) { Result result = results[i]; - ResultItem control = new ResultItem(result); - control.SetIndex(i + 1); - pnlContainer.Children.Add(control); + if (!CheckExisted(result)) + { + ResultItem control = new ResultItem(result); + control.SetIndex(i + 1); + pnlContainer.Children.Insert(GetInsertLocation(result.Score), control); + } } + SelectFirst(); pnlContainer.UpdateLayout(); double resultItemHeight = 0; @@ -37,11 +51,43 @@ namespace WinAlfred if (resultItem != null) resultItemHeight = resultItem.ActualHeight; } - pnlContainer.Height = results.Count * resultItemHeight; + pnlContainer.Height = pnlContainer.Children.Count * resultItemHeight; OnResultItemChangedEvent(); } - private int GetCurrentSelectedResultIndex() + private bool CheckExisted(Result result) + { + return pnlContainer.Children.Cast().Any(child => child.Result.Equals(result)); + } + + private int GetInsertLocation(int currentScore) + { + int location = pnlContainer.Children.Count; + if (pnlContainer.Children.Count == 0) return 0; + if (currentScore > ((ResultItem)pnlContainer.Children[0]).Result.Score) return 0; + + for (int index = 1; index < pnlContainer.Children.Count; index++) + { + ResultItem next = pnlContainer.Children[index] as ResultItem; + ResultItem prev = pnlContainer.Children[index - 1] as ResultItem; + if (next != null && prev != null) + { + if ((currentScore >= next.Result.Score && currentScore <= prev.Result.Score)) + { + location = index; + } + } + } + + return location; + } + + public int GetCurrentResultCount() + { + return pnlContainer.Children.Count; + } + + public int GetCurrentSelectedResultIndex() { for (int i = 0; i < pnlContainer.Children.Count; i++) { @@ -114,7 +160,7 @@ namespace WinAlfred if (index < oldIndex) { //move up and old item is at the top of the scroll view - if ( newItemBottomPoint.Y - sv.VerticalOffset == 0) + if (newItemBottomPoint.Y - sv.VerticalOffset == 0) { scrollPosition = sv.VerticalOffset - resultItemControl.ActualHeight; } @@ -146,19 +192,35 @@ namespace WinAlfred Select(0); } - public void AcceptSelect() + public Result AcceptSelect() { int index = GetCurrentSelectedResultIndex(); + if (index < 0) return null; + var resultItemControl = pnlContainer.Children[index] as ResultItem; if (resultItemControl != null) { - if (resultItemControl.Result.Action != null) resultItemControl.Result.Action(); + if (resultItemControl.Result.Action != null) + { + resultItemControl.Result.Action(); + } + + return resultItemControl.Result; } + + return null; } public ResultPanel() { InitializeComponent(); } + + public void Clear() + { + pnlContainer.Children.Clear(); + pnlContainer.Height = 0; + OnResultItemChangedEvent(); + } } } \ No newline at end of file diff --git a/WinAlfred/WinAlfred.csproj b/WinAlfred/WinAlfred.csproj index 02dcadb30..66418b728 100644 --- a/WinAlfred/WinAlfred.csproj +++ b/WinAlfred/WinAlfred.csproj @@ -9,7 +9,7 @@ Properties WinAlfred WinAlfred - v4.0 + v3.5 512 {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 4 @@ -39,22 +39,47 @@ app.ico + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + prompt + MinimumRecommendedRules.ruleset + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + + ..\packages\log4net.2.0.3\lib\net35-full\log4net.dll ..\packages\Newtonsoft.Json.5.0.8\lib\net35\Newtonsoft.Json.dll + + + + + + @@ -64,12 +89,21 @@ MSBuild:Compile Designer - + + + + + + + Msg.xaml + + + @@ -78,6 +112,7 @@ ResultItem.xaml + MSBuild:Compile Designer @@ -90,6 +125,10 @@ MainWindow.xaml Code + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -128,6 +167,10 @@ + + {69ce0206-cb41-453d-88af-df86092ef9b8} + WinAlfred.Plugin.System + {8451ECDD-2EA4-4966-BB0A-7BBC40138E80} WinAlfred.Plugin @@ -148,8 +191,22 @@ + + + {F935DC20-1CF0-11D0-ADB9-00C04FD58A0B} + 1 + 0 + 0 + tlbimp + False + True + + + + xcopy /Y $(ProjectDir)Images\*.* $(SolutionDir)WinAlfred\bin\Debug\Images\ +