Refactoring. Move system plugins to seperate DLLs.

This commit is contained in:
qianlifeng
2015-01-03 15:20:34 +08:00
parent 203965043e
commit 4243843951
134 changed files with 2209 additions and 1158 deletions

View File

@@ -0,0 +1,53 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
using Wox.Infrastructure.Storage.UserSettings;
namespace Wox.Plugin.Program
{
internal class FileChangeWatcher
{
private static bool isIndexing = false;
private static List<string> watchedPath = new List<string>();
public static void AddWatch(string path, bool includingSubDirectory = true)
{
if (watchedPath.Contains(path)) return;
if (!Directory.Exists(path))
{
Debug.WriteLine(string.Format("FileChangeWatcher: {0} doesn't exist", path),"WoxDebug");
return;
}
watchedPath.Add(path);
foreach (string fileType in UserSettingStorage.Instance.ProgramSuffixes.Split(';'))
{
FileSystemWatcher watcher = new FileSystemWatcher
{
Path = path,
IncludeSubdirectories = includingSubDirectory,
Filter = string.Format("*.{0}", fileType),
EnableRaisingEvents = true
};
watcher.Changed += FileChanged;
watcher.Created += FileChanged;
watcher.Deleted += FileChanged;
watcher.Renamed += FileChanged;
}
}
private static void FileChanged(object source, FileSystemEventArgs e)
{
if (!isIndexing)
{
ThreadPool.QueueUserWorkItem(o =>
{
Programs.IndexPrograms();
isIndexing = false;
});
}
}
}
}

View File

@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
namespace Wox.Plugin.Program
{
public interface IProgramSource
{
List<Program> LoadPrograms();
int BonusPoints { get; set; }
}
[Serializable]
public abstract class AbstractProgramSource : IProgramSource
{
public abstract List<Program> LoadPrograms();
public int BonusPoints
{
get; set;
}
protected Program CreateEntry(string file)
{
var p = new Program()
{
Title = Path.GetFileNameWithoutExtension(file),
IcoPath = file,
ExecutePath = file
};
switch (Path.GetExtension(file).ToLower())
{
case ".exe":
p.ExecuteName = Path.GetFileName(file);
try
{
FileVersionInfo versionInfo = FileVersionInfo.GetVersionInfo(file);
if (!string.IsNullOrEmpty(versionInfo.FileDescription))
{
p.Title = versionInfo.FileDescription;
}
}
catch (Exception) { }
break;
}
return p;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -0,0 +1,6 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
</ResourceDictionary>

View File

@@ -0,0 +1,34 @@
using System;
using Wox.Infrastructure;
namespace Wox.Plugin.Program
{
[Serializable]
public class Program
{
private static readonly global::System.Text.RegularExpressions.Regex AbbrRegexp = new global::System.Text.RegularExpressions.Regex("[^A-Z0-9]", global::System.Text.RegularExpressions.RegexOptions.Compiled);
private string m_Title;
public string Title
{
get
{
return m_Title;
}
set
{
m_Title = value;
string pinyin = m_Title.Unidecode();
PinyinTitle = pinyin;
AbbrTitle = AbbrRegexp.Replace(global::System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(pinyin), "");
if (AbbrTitle.Length < 2) AbbrTitle = null;
}
}
public string PinyinTitle { get; private set; }
public string AbbrTitle { get; private set; }
public string IcoPath { get; set; }
public string ExecutePath { get; set; }
public string ExecuteName { get; set; }
public int Score { get; set; }
public IProgramSource Source { get; set; }
}
}

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using Wox.Infrastructure.Storage;
namespace Wox.Plugin.Program
{
[Serializable]
public class ProgramCacheStorage : BinaryStorage<ProgramCacheStorage>
{
public List<Program> Programs = new List<Program>();
protected override string ConfigName
{
get { return "ProgramIndexCache"; }
}
}
}

View File

@@ -0,0 +1,49 @@
<UserControl x:Class="Wox.Plugin.Program.ProgramSetting"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:infrastructure="clr-namespace:Wox.Infrastructure;assembly=Wox.Infrastructure"
xmlns:program="clr-namespace:Wox.Plugin.Program"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="600">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis" />
</UserControl.Resources>
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Right">
<Button Height="30" HorizontalAlignment="Right" x:Name="btnProgramSuffixes" Width="130" Click="BtnProgramSuffixes_OnClick">Index file suffixes</Button>
<Button Height="30" HorizontalAlignment="Right" Margin="10 0 0 0" x:Name="btnReindex" Width="100" Click="btnReindex_Click">Re-Index</Button>
</StackPanel>
<ListView x:Name="programSourceView" Grid.Row="1">
<ListView.View>
<GridView>
<GridViewColumn Header="Location" Width="400">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Location, ConverterParameter=(null), Converter={program:StringEmptyConverter}}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<DockPanel Grid.Row="2">
<StackPanel x:Name="indexingPanel" Visibility="Hidden" HorizontalAlignment="Left" Orientation="Horizontal">
<ProgressBar x:Name="progressBarIndexing" Height="20" Width="80" Minimum="0" Maximum="100" IsIndeterminate="True"></ProgressBar>
<TextBlock Margin="10 0 0 0" Height="20" HorizontalAlignment="Center">Indexing</TextBlock>
</StackPanel>
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
<Button x:Name="btnDeleteProgramSource" Click="btnDeleteProgramSource_OnClick" Width="100" Margin="10" Content="Delete"/>
<Button x:Name="btnEditProgramSource" Click="btnEditProgramSource_OnClick" Width="100" Margin="10" Content="Edit"/>
<Button x:Name="btnAddProgramSource" Click="btnAddProgramSource_OnClick" Width="100" Margin="10" Content="Add"/>
</StackPanel>
</DockPanel>
</Grid>
</UserControl>

View File

@@ -0,0 +1,106 @@
using System;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using Wox.Infrastructure.Storage.UserSettings;
namespace Wox.Plugin.Program
{
/// <summary>
/// Interaction logic for ProgramSetting.xaml
/// </summary>
public partial class ProgramSetting : UserControl
{
public ProgramSetting()
{
InitializeComponent();
Loaded += Setting_Loaded;
}
private void Setting_Loaded(object sender, RoutedEventArgs e)
{
programSourceView.ItemsSource = UserSettingStorage.Instance.ProgramSources;
}
private void ReIndexing()
{
programSourceView.Items.Refresh();
ThreadPool.QueueUserWorkItem(t =>
{
Dispatcher.Invoke(new Action(() => { indexingPanel.Visibility = Visibility.Visible; }));
Programs.IndexPrograms();
Dispatcher.Invoke(new Action(() => { indexingPanel.Visibility = Visibility.Hidden; }));
});
}
private void btnAddProgramSource_OnClick(object sender, RoutedEventArgs e)
{
var folderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog();
if (folderBrowserDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
string path = folderBrowserDialog.SelectedPath;
UserSettingStorage.Instance.ProgramSources.Add(new ProgramSource()
{
Location = path,
Type = "FileSystemProgramSource",
Enabled = true
});
UserSettingStorage.Instance.Save();
ReIndexing();
}
}
private void btnDeleteProgramSource_OnClick(object sender, RoutedEventArgs e)
{
ProgramSource selectedProgramSource = programSourceView.SelectedItem as ProgramSource;
if (selectedProgramSource != null)
{
if (MessageBox.Show("Are your sure to delete " + selectedProgramSource.Location, "Delete ProgramSource",
MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
UserSettingStorage.Instance.ProgramSources.Remove(selectedProgramSource);
UserSettingStorage.Instance.Save();
ReIndexing();
}
}
else
{
MessageBox.Show("Please select a program source");
}
}
private void btnEditProgramSource_OnClick(object sender, RoutedEventArgs e)
{
ProgramSource selectedProgramSource = programSourceView.SelectedItem as ProgramSource;
if (selectedProgramSource != null)
{
//todo: update
var folderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog();
if (folderBrowserDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
string path = folderBrowserDialog.SelectedPath;
selectedProgramSource.Location = path;
UserSettingStorage.Instance.Save();
ReIndexing();
}
}
else
{
MessageBox.Show("Please select a program source");
}
}
private void btnReindex_Click(object sender, RoutedEventArgs e)
{
ReIndexing();
}
private void BtnProgramSuffixes_OnClick(object sender, RoutedEventArgs e)
{
ProgramSuffixes p = new ProgramSuffixes();
p.ShowDialog();
}
}
}

View File

@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using Wox.Infrastructure.Storage.UserSettings;
namespace Wox.Plugin.Program.ProgramSources
{
[Serializable]
[global::System.ComponentModel.Browsable(false)]
public class AppPathsProgramSource: AbstractProgramSource
{
public AppPathsProgramSource()
{
this.BonusPoints = -10;
}
public AppPathsProgramSource(ProgramSource source)
: this()
{
this.BonusPoints = source.BonusPoints;
}
public override List<Program> LoadPrograms()
{
var list = new List<Program>();
ReadAppPaths(@"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths", list);
ReadAppPaths(@"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\App Paths", list); //TODO: need test more on 64-bit
return list;
}
private void ReadAppPaths(string rootpath, List<Program> list)
{
using (var root = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(rootpath))
{
if (root == null) return;
foreach (var item in root.GetSubKeyNames())
{
using (var key = root.OpenSubKey(item))
{
object path = key.GetValue("");
if (path is string && global::System.IO.File.Exists((string)path))
{
var entry = CreateEntry((string)path);
entry.ExecuteName = item;
list.Add(entry);
}
key.Close();
}
}
}
}
public override string ToString()
{
return typeof(AppPathsProgramSource).Name;
}
}
}

View File

@@ -0,0 +1,40 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
using Wox.Infrastructure.Storage.UserSettings;
namespace Wox.Plugin.Program.ProgramSources
{
[Serializable]
[global::System.ComponentModel.Browsable(false)]
public class CommonStartMenuProgramSource : FileSystemProgramSource
{
[DllImport("shell32.dll")]
static extern bool SHGetSpecialFolderPath(IntPtr hwndOwner, [Out] StringBuilder lpszPath, int nFolder, bool fCreate);
const int CSIDL_COMMON_PROGRAMS = 0x17;
private static string getPath()
{
StringBuilder commonStartMenuPath = new StringBuilder(560);
SHGetSpecialFolderPath(IntPtr.Zero, commonStartMenuPath, CSIDL_COMMON_PROGRAMS, false);
return commonStartMenuPath.ToString();
}
public CommonStartMenuProgramSource()
: base(getPath())
{
}
public CommonStartMenuProgramSource(ProgramSource source)
: this()
{
this.BonusPoints = source.BonusPoints;
}
public override string ToString()
{
return typeof(CommonStartMenuProgramSource).Name;
}
}
}

View File

@@ -0,0 +1,152 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Wox.Infrastructure.Storage.UserSettings;
namespace Wox.Plugin.SystemPlugins.Program.ProgramSources {
//TODO: Consider Removing
/// <summary>
///
/// </summary>
public class FileSystemFolderSourceShallow : FileSystemProgramSource {
//private static Dictionary<string, DirectoryInfo[]> parentDirectories = new Dictionary<string, DirectoryInfo[]>();
public FileSystemFolderSourceShallow(string baseDirectory)
: base(baseDirectory) { }
public FileSystemFolderSourceShallow(ProgramSource source)
: base(source) { }
public override List<Program> LoadPrograms() {
List<Program> list = new List<Program>();
foreach (var Folder in Directory.GetDirectories(BaseDirectory)) {
list.Add(CreateEntry(Folder));
}
foreach (string file in Directory.GetFiles(base.BaseDirectory)) {
if (Suffixes.Any(o => file.EndsWith("." + o))) {
list.Add(CreateEntry(file));
}
}
return list;
}
public override string ToString() {
return typeof(UserStartMenuProgramSource).Name;
}
/*
public class FolderSource : IProgramSource {
private PluginInitContext context;
public string Location { get; set; }
public int BonusPoints { get; set; }
public FolderSource(string Location) {
this.Location = Location;
}
public List<Program> LoadPrograms() {
List<Result> results = new List<Result>();
if (Directory.Exists(Location)) {
// show all child directory
if (Location.EndsWith("\\") || Location.EndsWith("/")) {
var dirInfo = new DirectoryInfo(Location);
var dirs = dirInfo.GetDirectories();
var parentDirKey = Location.TrimEnd('\\', '/');
if (!parentDirectories.ContainsKey(parentDirKey))
parentDirectories.Add(parentDirKey, dirs);
foreach (var dir in dirs) {
if ((dir.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
continue;
var dirPath = dir.FullName;
Result result = new Result {
Title = dir.Name,
IcoPath = "Images/folder.png",
Action = (c) => {
context.ChangeQuery(dirPath);
return false;
}
};
results.Add(result);
}
if (results.Count == 0) {
Result result = new Result {
Title = "Open this directory",
SubTitle = "No files in this directory",
IcoPath = "Images/folder.png",
Action = (c) => {
Process.Start(Location);
return true;
}
};
results.Add(result);
}
}
else {
Result result = new Result {
Title = "Open this directory",
SubTitle = string.Format("path: {0}", Location),
Score = 50,
IcoPath = "Images/folder.png",
Action = (c) => {
Process.Start(Location);
return true;
}
};
results.Add(result);
}
}
// change to search in current directory
var parentDir = Path.GetDirectoryName(Location);
if (!string.IsNullOrEmpty(parentDir) && results.Count == 0) {
parentDir = parentDir.TrimEnd('\\', '/');
if (parentDirectories.ContainsKey(parentDir)) {
var dirs = parentDirectories[parentDir];
var queryFileName = Path.GetFileName(Location).ToLower();
var fuzzy = FuzzyMatcher.Create(queryFileName);
foreach (var dir in dirs) {
if ((dir.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
continue;
var matchResult = fuzzy.Evaluate(dir.Name);
if (!matchResult.Success)
continue;
var dirPath = dir.FullName;
Result result = new Result {
Title = dir.Name,
IcoPath = "Images/folder.png",
Score = matchResult.Score,
Action = (c) => {
context.ChangeQuery(dirPath);
return false;
}
};
results.Add(result);
}
}
}
throw new Exception("Debug this!");
}
}
*/
}
}

View File

@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Wox.Infrastructure.Storage.UserSettings;
using Log = Wox.Infrastructure.Logger.Log;
namespace Wox.Plugin.Program.ProgramSources
{
[Serializable]
public class FileSystemProgramSource : AbstractProgramSource
{
private string baseDirectory;
public FileSystemProgramSource(string baseDirectory)
{
this.baseDirectory = baseDirectory;
}
public FileSystemProgramSource(ProgramSource source):this(source.Location)
{
this.BonusPoints = source.BonusPoints;
}
public override List<Program> LoadPrograms()
{
List<Program> list = new List<Program>();
if (Directory.Exists(baseDirectory))
{
GetAppFromDirectory(baseDirectory, list);
FileChangeWatcher.AddWatch(baseDirectory);
}
return list;
}
private void GetAppFromDirectory(string path, List<Program> list)
{
try
{
foreach (string file in Directory.GetFiles(path))
{
if (UserSettingStorage.Instance.ProgramSuffixes.Split(';').Any(o => file.EndsWith("." + o)))
{
Program p = CreateEntry(file);
list.Add(p);
}
}
foreach (var subDirectory in Directory.GetDirectories(path))
{
GetAppFromDirectory(subDirectory, list);
}
}
catch (UnauthorizedAccessException 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));
}
}
public override string ToString()
{
return typeof(FileSystemProgramSource).Name + ":" + this.baseDirectory;
}
}
}

View File

@@ -0,0 +1,26 @@
using System;
using Wox.Infrastructure.Storage.UserSettings;
namespace Wox.Plugin.Program.ProgramSources
{
[Serializable]
[global::System.ComponentModel.Browsable(false)]
public class UserStartMenuProgramSource : FileSystemProgramSource
{
public UserStartMenuProgramSource()
: base(Environment.GetFolderPath(Environment.SpecialFolder.Programs))
{
}
public UserStartMenuProgramSource(ProgramSource source)
: this()
{
this.BonusPoints = source.BonusPoints;
}
public override string ToString()
{
return typeof(UserStartMenuProgramSource).Name;
}
}
}

View File

@@ -0,0 +1,17 @@
<Window x:Class="Wox.Plugin.Program.ProgramSuffixes"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
Width="400"
Height="170"
WindowStartupLocation="CenterScreen"
d:DesignHeight="400" d:DesignWidth="300">
<StackPanel>
<TextBlock Margin="10 10 0 0" Foreground="Gray">Wox will only index files that end with following suffixes.</TextBlock>
<TextBlock Margin="10 0 0 0" Foreground="Gray">Each suffix should split by ;</TextBlock>
<TextBox x:Name="tbSuffixes" Margin="10"/>
<Button HorizontalAlignment="Right" Height="30" Width="80" Click="ButtonBase_OnClick" Margin="10">Update</Button>
</StackPanel>
</Window>

View File

@@ -0,0 +1,30 @@
using System.Windows;
using Wox.Infrastructure.Storage.UserSettings;
namespace Wox.Plugin.Program
{
/// <summary>
/// ProgramSuffixes.xaml 的交互逻辑
/// </summary>
public partial class ProgramSuffixes
{
public ProgramSuffixes()
{
InitializeComponent();
tbSuffixes.Text = UserSettingStorage.Instance.ProgramSuffixes;
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
if (string.IsNullOrEmpty(tbSuffixes.Text))
{
MessageBox.Show("File suffixes can't be empty");
return;
}
UserSettingStorage.Instance.ProgramSuffixes = tbSuffixes.Text;
MessageBox.Show("Sucessfully update file suffixes");
}
}
}

View File

@@ -0,0 +1,180 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Wox.Infrastructure;
using Wox.Infrastructure.Storage.UserSettings;
using Wox.Plugin.Program.ProgramSources;
namespace Wox.Plugin.Program
{
public class Programs : ISettingProvider,IPlugin
{
private static object lockObject = new object();
private static List<Program> programs = new List<Program>();
private static List<IProgramSource> sources = new List<IProgramSource>();
private static Dictionary<string, Type> SourceTypes = new Dictionary<string, Type>() {
{"FileSystemProgramSource", typeof(FileSystemProgramSource)},
{"CommonStartMenuProgramSource", typeof(CommonStartMenuProgramSource)},
{"UserStartMenuProgramSource", typeof(UserStartMenuProgramSource)},
{"AppPathsProgramSource", typeof(AppPathsProgramSource)},
};
private PluginInitContext context;
public List<Result> Query(Query query)
{
if (query.RawQuery.Trim().Length <= 1) return new List<Result>();
var fuzzyMather = FuzzyMatcher.Create(query.RawQuery);
List<Program> returnList = programs.Where(o => MatchProgram(o, fuzzyMather)).ToList();
returnList.ForEach(ScoreFilter);
returnList = returnList.OrderByDescending(o => o.Score).ToList();
return returnList.Select(c => new Result()
{
Title = c.Title,
SubTitle = c.ExecutePath,
IcoPath = c.IcoPath,
Score = c.Score,
Action = (e) =>
{
context.API.HideApp();
context.API.ShellRun(c.ExecutePath);
return true;
},
ContextMenu = new List<Result>()
{
new Result()
{
Title = "Run As Administrator",
Action = _ =>
{
context.API.HideApp();
context.API.ShellRun(c.ExecutePath,true);
return true;
},
IcoPath = "Images/cmd.png"
}
}
}).ToList();
}
private bool MatchProgram(Program program, FuzzyMatcher matcher)
{
if ((program.Score = matcher.Evaluate(program.Title).Score) > 0) return true;
if ((program.Score = matcher.Evaluate(program.PinyinTitle).Score) > 0) return true;
if (program.AbbrTitle != null && (program.Score = matcher.Evaluate(program.AbbrTitle).Score) > 0) return true;
if (program.ExecuteName != null && (program.Score = matcher.Evaluate(program.ExecuteName).Score) > 0) return true;
return false;
}
public void Init(PluginInitContext context)
{
this.context = context;
programs = ProgramCacheStorage.Instance.Programs;
using (new Timeit("Program Index"))
{
IndexPrograms();
}
}
public static void IndexPrograms()
{
lock (lockObject)
{
List<ProgramSource> programSources = new List<ProgramSource>();
programSources.AddRange(LoadDeaultProgramSources());
if (UserSettingStorage.Instance.ProgramSources != null &&
UserSettingStorage.Instance.ProgramSources.Count(o => o.Enabled) > 0)
{
programSources.AddRange(UserSettingStorage.Instance.ProgramSources.Where(o => o.Enabled));
}
sources.Clear();
programSources.ForEach(source =>
{
Type sourceClass;
if (SourceTypes.TryGetValue(source.Type, out sourceClass))
{
ConstructorInfo constructorInfo = sourceClass.GetConstructor(new[] { typeof(ProgramSource) });
if (constructorInfo != null)
{
IProgramSource programSource =
constructorInfo.Invoke(new object[] { source }) as IProgramSource;
sources.Add(programSource);
}
}
});
var tempPrograms = new List<Program>();
foreach (var source in sources)
{
var list = source.LoadPrograms();
list.ForEach(o =>
{
o.Source = source;
});
tempPrograms.AddRange(list);
}
// filter duplicate program
programs = tempPrograms.GroupBy(x => new { x.ExecutePath, x.ExecuteName })
.Select(g => g.First()).ToList();
ProgramCacheStorage.Instance.Programs = programs;
ProgramCacheStorage.Instance.Save();
}
}
/// <summary>
/// Load program sources that wox always provide
/// </summary>
private static List<ProgramSource> LoadDeaultProgramSources()
{
var list = new List<ProgramSource>();
list.Add(new ProgramSource()
{
BonusPoints = 0,
Enabled = true,
Type = "CommonStartMenuProgramSource"
});
list.Add(new ProgramSource()
{
BonusPoints = 0,
Enabled = true,
Type = "UserStartMenuProgramSource"
});
list.Add(new ProgramSource()
{
BonusPoints = -10,
Enabled = true,
Type = "AppPathsProgramSource"
});
return list;
}
private void ScoreFilter(Program p)
{
p.Score += p.Source.BonusPoints;
if (p.Title.Contains("启动") || p.Title.ToLower().Contains("start"))
p.Score += 10;
if (p.Title.Contains("帮助") || p.Title.ToLower().Contains("help") || p.Title.Contains("文档") || p.Title.ToLower().Contains("documentation"))
p.Score -= 10;
if (p.Title.Contains("卸载") || p.Title.ToLower().Contains("uninstall"))
p.Score -= 20;
}
#region ISettingProvider Members
public System.Windows.Controls.Control CreateSettingPanel()
{
return new ProgramSetting();
}
#endregion
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的常规信息通过以下
// 特性集控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("Wox.Plugin.Program")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Wox.Plugin.Program")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 使此程序集中的类型
// 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
// 则将该类型上的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("82f60d9a-9280-4b6a-8b21-f3c694cb7e1d")]
// 程序集的版本信息由下面四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
// 方法是按如下所示使用“*”:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,26 @@
using System;
using System.Windows.Data;
using System.Windows.Markup;
namespace Wox.Plugin.Program
{
public class StringEmptyConverter : MarkupExtension, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return string.IsNullOrEmpty((string)value) ? parameter : value;
}
public object ConvertBack(
object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
}

View File

@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{FDB3555B-58EF-4AE6-B5F1-904719637AB4}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Wox.Plugin.Program</RootNamespace>
<AssemblyName>Wox.Plugin.Program</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
<RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\Output\Debug\Plugins\Wox.Plugin.Program\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="log4net">
<HintPath>..\..\packages\log4net.2.0.3\lib\net35-full\log4net.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\Newtonsoft.Json.6.0.7\lib\net35\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="FileChangeWatcher.cs" />
<Compile Include="IProgramSource.cs" />
<Compile Include="Program.cs" />
<Compile Include="ProgramCacheStorage.cs" />
<Compile Include="Programs.cs" />
<Compile Include="ProgramSetting.xaml.cs">
<DependentUpon>ProgramSetting.xaml</DependentUpon>
</Compile>
<Compile Include="ProgramSources\AppPathsProgramSource.cs" />
<Compile Include="ProgramSources\CommonStartMenuProgramSource.cs" />
<Compile Include="ProgramSources\FileSystemProgramSource.cs" />
<Compile Include="ProgramSources\UserStartMenuProgramSource.cs" />
<Compile Include="ProgramSuffixes.xaml.cs">
<DependentUpon>ProgramSuffixes.xaml</DependentUpon>
</Compile>
<Compile Include="StringEmptyConverter.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="plugin.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Include="Images\program.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<Content Include="Languages\en.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Page Include="ProgramSetting.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="ProgramSuffixes.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Wox.Infrastructure\Wox.Infrastructure.csproj">
<Project>{4fd29318-a8ab-4d8f-aa47-60bc241b8da3}</Project>
<Name>Wox.Infrastructure</Name>
</ProjectReference>
<ProjectReference Include="..\..\Wox.Plugin\Wox.Plugin.csproj">
<Project>{8451ecdd-2ea4-4966-bb0a-7bbc40138e80}</Project>
<Name>Wox.Plugin</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。启用“NuGet 程序包还原”可下载这些程序包。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="log4net" version="2.0.3" targetFramework="net35" />
<package id="Newtonsoft.Json" version="6.0.7" targetFramework="net35" />
</packages>

View File

@@ -0,0 +1,12 @@
{
"ID":"791FC278BA414111B8D1886DFE447410",
"ActionKeyword":"*",
"Name":"Program",
"Description":"Provide programs search for Wox.",
"Author":"qianlifeng",
"Version":"1.0.0",
"Language":"csharp",
"Website":"http://www.getwox.com/plugin",
"ExecuteFileName":"Wox.Plugin.Program.dll",
"IcoPath":"Images\\program.png"
}