diff --git a/Plugins/Wox.Plugin.Calculator/DecimalSeparator.cs b/Plugins/Wox.Plugin.Calculator/DecimalSeparator.cs
new file mode 100644
index 000000000..5aad9b39a
--- /dev/null
+++ b/Plugins/Wox.Plugin.Calculator/DecimalSeparator.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Wox.Core;
+
+namespace Wox.Plugin.Caculator
+{
+ [TypeConverter(typeof(LocalizationConverter))]
+ public enum DecimalSeparator
+ {
+ [LocalizedDescription("wox_plugin_calculator_decimal_seperator_use_system_locale")]
+ UseSystemLocale,
+
+ [LocalizedDescription("wox_plugin_calculator_decimal_seperator_dot")]
+ Dot,
+
+ [LocalizedDescription("wox_plugin_calculator_decimal_seperator_comma")]
+ Comma
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Wox.Plugin.Calculator/Languages/de.xaml b/Plugins/Wox.Plugin.Calculator/Languages/de.xaml
index 286e4bc9b..eb6847af0 100644
--- a/Plugins/Wox.Plugin.Calculator/Languages/de.xaml
+++ b/Plugins/Wox.Plugin.Calculator/Languages/de.xaml
@@ -7,4 +7,10 @@
Keine Zahl (NaN)
Ausdruck falsch oder nicht vollständig (Klammern vergessen?)
Diese Zahl in die Zwischenablage kopieren
+ Dezimaltrennzeichen
+ Das Dezimaltrennzeichen, welches bei der Ausgabe verwendet werden soll.
+ Systemeinstellung nutzen
+ Komma (,)
+ Punkt (.)
+ Max. Nachkommastellen
\ No newline at end of file
diff --git a/Plugins/Wox.Plugin.Calculator/Languages/en.xaml b/Plugins/Wox.Plugin.Calculator/Languages/en.xaml
index 3b5fa32b3..0df0d3342 100644
--- a/Plugins/Wox.Plugin.Calculator/Languages/en.xaml
+++ b/Plugins/Wox.Plugin.Calculator/Languages/en.xaml
@@ -7,4 +7,10 @@
Not a number (NaN)
Expression wrong or incomplete (Did you forget some parentheses?)
Copy this number to the clipboard
+ Decimal separator
+ The decimal separator to be used in the output.
+ Use system locale
+ Comma (,)
+ Dot (.)
+ Max. decimal places
\ No newline at end of file
diff --git a/Plugins/Wox.Plugin.Calculator/Main.cs b/Plugins/Wox.Plugin.Calculator/Main.cs
index fab0b8e03..f2f7f7e18 100644
--- a/Plugins/Wox.Plugin.Calculator/Main.cs
+++ b/Plugins/Wox.Plugin.Calculator/Main.cs
@@ -1,12 +1,18 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Windows;
+using System.Windows.Controls;
using Mages.Core;
+using Wox.Infrastructure.Storage;
+using Wox.Plugin.Caculator.ViewModels;
+using Wox.Plugin.Caculator.Views;
namespace Wox.Plugin.Caculator
{
- public class Main : IPlugin, IPluginI18n
+ public class Main : IPlugin, IPluginI18n, ISavable, ISettingProvider
{
private static readonly Regex RegValidExpressChar = new Regex(
@"^(" +
@@ -21,20 +27,33 @@ namespace Wox.Plugin.Caculator
private static readonly Engine MagesEngine;
private PluginInitContext Context { get; set; }
+ private static Settings _settings;
+ private static SettingsViewModel _viewModel;
+
static Main()
{
- MagesEngine = new Engine();
+ MagesEngine = new Engine();
+ }
+
+ public void Init(PluginInitContext context)
+ {
+ Context = context;
+
+ _viewModel = new SettingsViewModel();
+ _settings = _viewModel.Settings;
}
public List Query(Query query)
{
- if (query.Search.Length <= 2 // don't affect when user only input "e" or "i" keyword
- || !RegValidExpressChar.IsMatch(query.Search)
- || !IsBracketComplete(query.Search)) return new List();
+ if (!CanCalculate(query))
+ {
+ return new List();
+ }
try
{
- var result = MagesEngine.Interpret(query.Search);
+ var expression = query.Search.Replace(",", ".");
+ var result = MagesEngine.Interpret(expression);
if (result.ToString() == "NaN")
result = Context.API.GetTranslation("wox_plugin_calculator_not_a_number");
@@ -42,14 +61,16 @@ namespace Wox.Plugin.Caculator
if (result is Function)
result = Context.API.GetTranslation("wox_plugin_calculator_expression_not_complete");
-
if (!string.IsNullOrEmpty(result?.ToString()))
{
+ decimal roundedResult = Math.Round(Convert.ToDecimal(result), _settings.MaxDecimalPlaces, MidpointRounding.AwayFromZero);
+ string newResult = ChangeDecimalSeparator(roundedResult, GetDecimalSeparator());
+
return new List
{
new Result
{
- Title = result.ToString(),
+ Title = newResult,
IcoPath = "Images/calculator.png",
Score = 300,
SubTitle = Context.API.GetTranslation("wox_plugin_calculator_copy_number_to_clipboard"),
@@ -57,7 +78,7 @@ namespace Wox.Plugin.Caculator
{
try
{
- Clipboard.SetText(result.ToString());
+ Clipboard.SetText(newResult);
return true;
}
catch (ExternalException)
@@ -78,6 +99,53 @@ namespace Wox.Plugin.Caculator
return new List();
}
+ private bool CanCalculate(Query query)
+ {
+ // Don't execute when user only input "e" or "i" keyword
+ if (query.Search.Length < 2)
+ {
+ return false;
+ }
+
+ if (!RegValidExpressChar.IsMatch(query.Search))
+ {
+ return false;
+ }
+
+ if (!IsBracketComplete(query.Search))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ private string ChangeDecimalSeparator(decimal value, string newDecimalSeparator)
+ {
+ if (String.IsNullOrEmpty(newDecimalSeparator))
+ {
+ return value.ToString();
+ }
+
+ var numberFormatInfo = new NumberFormatInfo
+ {
+ NumberDecimalSeparator = newDecimalSeparator
+ };
+ return value.ToString(numberFormatInfo);
+ }
+
+ private string GetDecimalSeparator()
+ {
+ string systemDecimalSeperator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
+ switch (_settings.DecimalSeparator)
+ {
+ case DecimalSeparator.UseSystemLocale: return systemDecimalSeperator;
+ case DecimalSeparator.Dot: return ".";
+ case DecimalSeparator.Comma: return ",";
+ default: return systemDecimalSeperator;
+ }
+ }
+
private bool IsBracketComplete(string query)
{
var matchs = RegBrackets.Matches(query);
@@ -96,12 +164,7 @@ namespace Wox.Plugin.Caculator
return leftBracketCount == 0;
}
-
- public void Init(PluginInitContext context)
- {
- Context = context;
- }
-
+
public string GetTranslatedPluginTitle()
{
return Context.API.GetTranslation("wox_plugin_caculator_plugin_name");
@@ -111,5 +174,15 @@ namespace Wox.Plugin.Caculator
{
return Context.API.GetTranslation("wox_plugin_caculator_plugin_description");
}
+
+ public Control CreateSettingPanel()
+ {
+ return new CalculatorSettings(_viewModel);
+ }
+
+ public void Save()
+ {
+ _viewModel.Save();
+ }
}
}
diff --git a/Plugins/Wox.Plugin.Calculator/Settings.cs b/Plugins/Wox.Plugin.Calculator/Settings.cs
new file mode 100644
index 000000000..ce01f2da0
--- /dev/null
+++ b/Plugins/Wox.Plugin.Calculator/Settings.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Wox.Plugin.Caculator
+{
+ public class Settings
+ {
+ public DecimalSeparator DecimalSeparator { get; set; } = DecimalSeparator.UseSystemLocale;
+ public int MaxDecimalPlaces { get; set; } = 10;
+ }
+}
diff --git a/Plugins/Wox.Plugin.Calculator/ViewModels/SettingsViewModel.cs b/Plugins/Wox.Plugin.Calculator/ViewModels/SettingsViewModel.cs
new file mode 100644
index 000000000..8550f47a5
--- /dev/null
+++ b/Plugins/Wox.Plugin.Calculator/ViewModels/SettingsViewModel.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Wox.Infrastructure.Storage;
+using Wox.Infrastructure.UserSettings;
+
+namespace Wox.Plugin.Caculator.ViewModels
+{
+ public class SettingsViewModel : BaseModel, ISavable
+ {
+ private readonly PluginJsonStorage _storage;
+
+ public SettingsViewModel()
+ {
+ _storage = new PluginJsonStorage();
+ Settings = _storage.Load();
+ }
+
+ public Settings Settings { get; set; }
+
+ public IEnumerable MaxDecimalPlacesRange => Enumerable.Range(1, 20);
+
+ public void Save()
+ {
+ _storage.Save();
+ }
+ }
+}
diff --git a/Plugins/Wox.Plugin.Calculator/Views/CalculatorSettings.xaml b/Plugins/Wox.Plugin.Calculator/Views/CalculatorSettings.xaml
new file mode 100644
index 000000000..183f10e5f
--- /dev/null
+++ b/Plugins/Wox.Plugin.Calculator/Views/CalculatorSettings.xaml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Plugins/Wox.Plugin.Calculator/Views/CalculatorSettings.xaml.cs b/Plugins/Wox.Plugin.Calculator/Views/CalculatorSettings.xaml.cs
new file mode 100644
index 000000000..c15bdda77
--- /dev/null
+++ b/Plugins/Wox.Plugin.Calculator/Views/CalculatorSettings.xaml.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using Wox.Plugin.Caculator.ViewModels;
+
+namespace Wox.Plugin.Caculator.Views
+{
+ ///
+ /// Interaction logic for CalculatorSettings.xaml
+ ///
+ public partial class CalculatorSettings : UserControl
+ {
+ private readonly SettingsViewModel _viewModel;
+ private readonly Settings _settings;
+
+ public CalculatorSettings(SettingsViewModel viewModel)
+ {
+ _viewModel = viewModel;
+ _settings = viewModel.Settings;
+ DataContext = viewModel;
+ InitializeComponent();
+ }
+
+ private void CalculatorSettings_Loaded(object sender, RoutedEventArgs e)
+ {
+ DecimalSeparatorComboBox.SelectedItem = _settings.DecimalSeparator;
+ MaxDecimalPlaces.SelectedItem = _settings.MaxDecimalPlaces;
+ }
+ }
+
+
+}
diff --git a/Plugins/Wox.Plugin.Calculator/Wox.Plugin.Calculator.csproj b/Plugins/Wox.Plugin.Calculator/Wox.Plugin.Calculator.csproj
index b0a091934..f24ad118e 100644
--- a/Plugins/Wox.Plugin.Calculator/Wox.Plugin.Calculator.csproj
+++ b/Plugins/Wox.Plugin.Calculator/Wox.Plugin.Calculator.csproj
@@ -46,14 +46,22 @@
+
+
Properties\SolutionAssemblyInfo.cs
+
+
+
+
+ CalculatorSettings.xaml
+
@@ -61,6 +69,10 @@
+
+ {B749F0DB-8E75-47DB-9E5E-265D16D0C0D2}
+ Wox.Core
+
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}
Wox.Infrastructure
@@ -122,12 +134,18 @@
10.3.0
- 1.5.0
+ 1.6.0
4.0.0
+
+
+ Designer
+ MSBuild:Compile
+
+
diff --git a/Plugins/Wox.Plugin.PluginIndicator/Main.cs b/Plugins/Wox.Plugin.PluginIndicator/Main.cs
index 5f9ec07be..54dcf007a 100644
--- a/Plugins/Wox.Plugin.PluginIndicator/Main.cs
+++ b/Plugins/Wox.Plugin.PluginIndicator/Main.cs
@@ -13,8 +13,7 @@ namespace Wox.Plugin.PluginIndicator
var results = from keyword in PluginManager.NonGlobalPlugins.Keys
where keyword.StartsWith(query.Terms[0])
let metadata = PluginManager.NonGlobalPlugins[keyword].Metadata
- let disabled = PluginManager.Settings.Plugins[metadata.ID].Disabled
- where !disabled
+ where !metadata.Disabled
select new Result
{
Title = keyword,
diff --git a/Plugins/Wox.Plugin.Sys/Images/checkupdate.png b/Plugins/Wox.Plugin.Sys/Images/checkupdate.png
new file mode 100644
index 000000000..955f6fdbb
Binary files /dev/null and b/Plugins/Wox.Plugin.Sys/Images/checkupdate.png differ
diff --git a/Plugins/Wox.Plugin.Sys/Main.cs b/Plugins/Wox.Plugin.Sys/Main.cs
index e888dbb37..f6be3a435 100644
--- a/Plugins/Wox.Plugin.Sys/Main.cs
+++ b/Plugins/Wox.Plugin.Sys/Main.cs
@@ -234,6 +234,20 @@ namespace Wox.Plugin.Sys
context.API.GetTranslation("wox_plugin_sys_dlgtext_all_applicableplugins_reloaded"));
return true;
}
+ },
+ new Result
+ {
+ Title = "Check For Update",
+ SubTitle = "Check for new Wox update",
+ IcoPath = "Images\\checkupdate.png",
+ Action = c =>
+ {
+ Application.Current.MainWindow.Hide();
+ context.API.CheckForNewUpdate();
+ context.API.ShowMsg("Please wait...",
+ "Checking for new update");
+ return true;
+ }
}
});
return results;
diff --git a/Plugins/Wox.Plugin.Sys/Wox.Plugin.Sys.csproj b/Plugins/Wox.Plugin.Sys/Wox.Plugin.Sys.csproj
index 09a1e761f..ffdfa5972 100644
--- a/Plugins/Wox.Plugin.Sys/Wox.Plugin.Sys.csproj
+++ b/Plugins/Wox.Plugin.Sys/Wox.Plugin.Sys.csproj
@@ -71,9 +71,15 @@
+
+ PreserveNewest
+
PreserveNewest
+
+ PreserveNewest
+
PreserveNewest
diff --git a/README.md b/README.md
index 2b9da637f..00069024a 100644
--- a/README.md
+++ b/README.md
@@ -19,11 +19,22 @@ Features
- Search for everything—applications, **uwp**, folders, files and more.
- Use *pinyin* to search for programs / 支持用 **拼音** 搜索程序
- wyy / wangyiyun → 网易云音乐
-- Keyword plugin search
- - search google with `g search_term`
+- Keyword plugin search `g search_term`
+- Search youtube, google, twitter and many more
- Build custom themes at http://www.wox.one/theme/builder
- Install plugins from http://www.wox.one/plugin
+**New from this fork:**
+- Portable mode
+- Drastically improved search experience
+- Search all subfolders and files
+- Option to always run CMD or Powershell as administrator
+- Run CMD, Powershell and programs as a different user
+- Manage what programs should be loaded
+- Highlighting of how results are matched during query search
+- Open web search result as a tab or a new window
+- Automatic update
+- Reload/update plugin data
Installation
------------
@@ -42,8 +53,8 @@ Versions marked as **pre-release** are unstable pre-release versions.
- Requirements:
- .net >= 4.5.2
- - [everything](https://www.voidtools.com/): `.exe` installer + use x64 if your windows is x64 + everything service is running
- - [python3](https://www.python.org/downloads/): `.exe` installer + add it to `%PATH%` or set it in WoX settings
+ - If you want to integrate with [everything](https://www.voidtools.com/): `.exe` installer + use x64 if your windows is x64 + everything service is running. Supported version is 1.3.4.686
+ - If you use python plugins, install [python3](https://www.python.org/downloads/): `.exe` installer + add it to `%PATH%` or set it in WoX settings
Usage
-----
diff --git a/Wox.Core/Plugin/PluginManager.cs b/Wox.Core/Plugin/PluginManager.cs
index fc9afb740..0166690b7 100644
--- a/Wox.Core/Plugin/PluginManager.cs
+++ b/Wox.Core/Plugin/PluginManager.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -92,21 +93,36 @@ namespace Wox.Core.Plugin
Settings.UpdatePluginSettings(_metadatas);
AllPlugins = PluginsLoader.Plugins(_metadatas, Settings);
}
+
+ ///
+ /// Call initialize for all plugins
+ ///
+ /// return the list of failed to init plugins or null for none
public static void InitializePlugins(IPublicAPI api)
{
API = api;
+ var failedPlugins = new ConcurrentQueue();
Parallel.ForEach(AllPlugins, pair =>
{
- var milliseconds = Stopwatch.Debug($"|PluginManager.InitializePlugins|Init method time cost for <{pair.Metadata.Name}>", () =>
+ try
{
- pair.Plugin.Init(new PluginInitContext
+ var milliseconds = Stopwatch.Debug($"|PluginManager.InitializePlugins|Init method time cost for <{pair.Metadata.Name}>", () =>
{
- CurrentPluginMetadata = pair.Metadata,
- API = API
+ pair.Plugin.Init(new PluginInitContext
+ {
+ CurrentPluginMetadata = pair.Metadata,
+ API = API
+ });
});
- });
- pair.Metadata.InitTime += milliseconds;
- Log.Info($"|PluginManager.InitializePlugins|Total init cost for <{pair.Metadata.Name}> is <{pair.Metadata.InitTime}ms>");
+ pair.Metadata.InitTime += milliseconds;
+ Log.Info($"|PluginManager.InitializePlugins|Total init cost for <{pair.Metadata.Name}> is <{pair.Metadata.InitTime}ms>");
+ }
+ catch (Exception e)
+ {
+ Log.Exception(nameof(PluginManager), $"Fail to Init plugin: {pair.Metadata.Name}", e);
+ pair.Metadata.Disabled = true;
+ failedPlugins.Enqueue(pair);
+ }
});
_contextMenuPlugins = GetPluginsForInterface();
@@ -121,6 +137,11 @@ namespace Wox.Core.Plugin
.ForEach(x => NonGlobalPlugins[x] = plugin);
}
+ if (failedPlugins.Any())
+ {
+ var failed = string.Join(",", failedPlugins.Select(x => x.Metadata.Name));
+ API.ShowMsg($"Fail to Init Plugins", $"Plugins: {failed} - fail to load and would be disabled, please contact plugin creator for help", "", false);
+ }
}
public static void InstallPlugin(string path)
@@ -128,35 +149,6 @@ namespace Wox.Core.Plugin
PluginInstaller.Install(path);
}
- public static Query QueryInit(string text) //todo is that possible to move it into type Query?
- {
- // replace multiple white spaces with one white space
- var terms = text.Split(new[] { Query.TermSeperater }, StringSplitOptions.RemoveEmptyEntries);
- var rawQuery = string.Join(Query.TermSeperater, terms);
- var actionKeyword = string.Empty;
- var search = rawQuery;
- var actionParameters = terms.ToList();
- if (terms.Length == 0) return null;
- if (NonGlobalPlugins.ContainsKey(terms[0]) &&
- !Settings.Plugins[NonGlobalPlugins[terms[0]].Metadata.ID].Disabled)
- {
- actionKeyword = terms[0];
- actionParameters = terms.Skip(1).ToList();
- search = string.Join(Query.TermSeperater, actionParameters.ToArray());
- }
- var query = new Query
- {
- Terms = terms,
- RawQuery = rawQuery,
- ActionKeyword = actionKeyword,
- Search = search,
- // Obsolete value initialisation
- ActionName = actionKeyword,
- ActionParameters = actionParameters
- };
- return query;
- }
-
public static List ValidPluginsForQuery(Query query)
{
if (NonGlobalPlugins.ContainsKey(query.ActionKeyword))
diff --git a/Wox.Core/Plugin/QueryBuilder.cs b/Wox.Core/Plugin/QueryBuilder.cs
new file mode 100644
index 000000000..b01a93291
--- /dev/null
+++ b/Wox.Core/Plugin/QueryBuilder.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Wox.Plugin;
+
+namespace Wox.Core.Plugin
+{
+ public static class QueryBuilder
+ {
+ public static Query Build(string text, Dictionary nonGlobalPlugins)
+ {
+ // replace multiple white spaces with one white space
+ var terms = text.Split(new[] { Query.TermSeperater }, StringSplitOptions.RemoveEmptyEntries);
+ if (terms.Length == 0)
+ { // nothing was typed
+ return null;
+ }
+
+ var rawQuery = string.Join(Query.TermSeperater, terms);
+ string actionKeyword, search;
+ string possibleActionKeyword = terms[0];
+ List actionParameters;
+ if (nonGlobalPlugins.TryGetValue(possibleActionKeyword, out var pluginPair) && !pluginPair.Metadata.Disabled)
+ { // use non global plugin for query
+ actionKeyword = possibleActionKeyword;
+ actionParameters = terms.Skip(1).ToList();
+ search = actionParameters.Count > 0 ? rawQuery.Substring(actionKeyword.Length + 1) : string.Empty;
+ }
+ else
+ { // non action keyword
+ actionKeyword = string.Empty;
+ actionParameters = terms.ToList();
+ search = rawQuery;
+ }
+
+ var query = new Query
+ {
+ Terms = terms,
+ RawQuery = rawQuery,
+ ActionKeyword = actionKeyword,
+ Search = search,
+ // Obsolete value initialisation
+ ActionName = actionKeyword,
+ ActionParameters = actionParameters
+ };
+
+ return query;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Wox.Core/Resource/LocalizationConverter.cs b/Wox.Core/Resource/LocalizationConverter.cs
new file mode 100644
index 000000000..d86bf5f7e
--- /dev/null
+++ b/Wox.Core/Resource/LocalizationConverter.cs
@@ -0,0 +1,37 @@
+using System;
+using System.ComponentModel;
+using System.Globalization;
+using System.Reflection;
+using System.Windows.Data;
+
+namespace Wox.Core
+{
+ public class LocalizationConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ if (targetType == typeof(string) && value != null)
+ {
+ FieldInfo fi = value.GetType().GetField(value.ToString());
+ if (fi != null)
+ {
+ string localizedDescription = string.Empty;
+ var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
+ if ((attributes.Length > 0) && (!String.IsNullOrEmpty(attributes[0].Description)))
+ {
+ localizedDescription = attributes[0].Description;
+ }
+
+ return (!String.IsNullOrEmpty(localizedDescription)) ? localizedDescription : value.ToString();
+ }
+ }
+
+ return string.Empty;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/Wox.Core/Resource/LocalizedDescriptionAttribute.cs b/Wox.Core/Resource/LocalizedDescriptionAttribute.cs
new file mode 100644
index 000000000..ef1257220
--- /dev/null
+++ b/Wox.Core/Resource/LocalizedDescriptionAttribute.cs
@@ -0,0 +1,27 @@
+using System.ComponentModel;
+using Wox.Core.Resource;
+
+namespace Wox.Core
+{
+ public class LocalizedDescriptionAttribute : DescriptionAttribute
+ {
+ private readonly Internationalization _translator;
+ private readonly string _resourceKey;
+
+ public LocalizedDescriptionAttribute(string resourceKey)
+ {
+ _translator = InternationalizationManager.Instance;
+ _resourceKey = resourceKey;
+ }
+
+ public override string Description
+ {
+ get
+ {
+ string description = _translator.GetTranslation(_resourceKey);
+ return string.IsNullOrWhiteSpace(description) ?
+ string.Format("[[{0}]]", _resourceKey) : description;
+ }
+ }
+ }
+}
diff --git a/Wox.Core/Updater.cs b/Wox.Core/Updater.cs
index 971995f5e..9262d78f4 100644
--- a/Wox.Core/Updater.cs
+++ b/Wox.Core/Updater.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
@@ -10,9 +10,11 @@ using JetBrains.Annotations;
using Squirrel;
using Newtonsoft.Json;
using Wox.Core.Resource;
+using Wox.Plugin.SharedCommands;
using Wox.Infrastructure;
using Wox.Infrastructure.Http;
using Wox.Infrastructure.Logger;
+using System.IO;
namespace Wox.Core
{
@@ -25,14 +27,14 @@ namespace Wox.Core
GitHubRepository = gitHubRepository;
}
- public async Task UpdateApp()
+ public async Task UpdateApp(bool silentIfLatestVersion = true)
{
- UpdateManager m;
- UpdateInfo u;
+ UpdateManager updateManager;
+ UpdateInfo newUpdateInfo;
try
{
- m = await GitHubUpdateManager(GitHubRepository);
+ updateManager = await GitHubUpdateManager(GitHubRepository);
}
catch (Exception e) when (e is HttpRequestException || e is WebException || e is SocketException)
{
@@ -43,42 +45,61 @@ namespace Wox.Core
try
{
// UpdateApp CheckForUpdate will return value only if the app is squirrel installed
- u = await m.CheckForUpdate().NonNull();
+ newUpdateInfo = await updateManager.CheckForUpdate().NonNull();
}
catch (Exception e) when (e is HttpRequestException || e is WebException || e is SocketException)
{
Log.Exception($"|Updater.UpdateApp|Check your connection and proxy settings to api.github.com.", e);
- m.Dispose();
+ updateManager.Dispose();
return;
}
- var fr = u.FutureReleaseEntry;
- var cr = u.CurrentlyInstalledVersion;
- Log.Info($"|Updater.UpdateApp|Future Release <{fr.Formatted()}>");
- if (fr.Version > cr.Version)
+ var newReleaseVersion = Version.Parse(newUpdateInfo.FutureReleaseEntry.Version.ToString());
+ var currentVersion = Version.Parse(Constant.Version);
+
+ Log.Info($"|Updater.UpdateApp|Future Release <{newUpdateInfo.FutureReleaseEntry.Formatted()}>");
+
+ if (newReleaseVersion <= currentVersion)
{
- try
- {
- await m.DownloadReleases(u.ReleasesToApply);
- }
- catch (Exception e) when (e is HttpRequestException || e is WebException || e is SocketException)
- {
- Log.Exception($"|Updater.UpdateApp|Check your connection and proxy settings to github-cloud.s3.amazonaws.com.", e);
- m.Dispose();
- return;
- }
-
- await m.ApplyReleases(u);
- await m.CreateUninstallerRegistryEntry();
-
- var newVersionTips = this.NewVersinoTips(fr.Version.ToString());
-
- MessageBox.Show(newVersionTips);
- Log.Info($"|Updater.UpdateApp|Update success:{newVersionTips}");
+ if (!silentIfLatestVersion)
+ MessageBox.Show("You already have the latest Wox version");
+ updateManager.Dispose();
+ return;
}
+ try
+ {
+ await updateManager.DownloadReleases(newUpdateInfo.ReleasesToApply);
+ }
+ catch (Exception e) when (e is HttpRequestException || e is WebException || e is SocketException)
+ {
+ Log.Exception($"|Updater.UpdateApp|Check your connection and proxy settings to github-cloud.s3.amazonaws.com.", e);
+ updateManager.Dispose();
+ return;
+ }
+
+ await updateManager.ApplyReleases(newUpdateInfo);
+
+ if (Constant.IsPortableMode)
+ {
+ var targetDestination = updateManager.RootAppDirectory + $"\\app-{newReleaseVersion.ToString()}\\{Constant.PortableFolderName}";
+ FilesFolders.Copy(Constant.PortableDataPath, targetDestination);
+ if (!FilesFolders.VerifyBothFolderFilesEqual(Constant.PortableDataPath, targetDestination))
+ MessageBox.Show(string.Format("Wox was not able to move your user profile data to the new update version. Please manually" +
+ "move your profile data folder from {0} to {1}", Constant.PortableDataPath, targetDestination));
+ }
+ else
+ {
+ await updateManager.CreateUninstallerRegistryEntry();
+ }
+
+ var newVersionTips = NewVersinoTips(newReleaseVersion.ToString());
+
+ MessageBox.Show(newVersionTips);
+ Log.Info($"|Updater.UpdateApp|Update success:{newVersionTips}");
+
// always dispose UpdateManager
- m.Dispose();
+ updateManager.Dispose();
}
[UsedImplicitly]
diff --git a/Wox.Core/Wox.Core.csproj b/Wox.Core/Wox.Core.csproj
index b3d0adc8b..cd95ed13e 100644
--- a/Wox.Core/Wox.Core.csproj
+++ b/Wox.Core/Wox.Core.csproj
@@ -55,6 +55,9 @@
+
+
+
diff --git a/Wox.Infrastructure/Logger/Log.cs b/Wox.Infrastructure/Logger/Log.cs
index 10e8128c5..349920076 100644
--- a/Wox.Infrastructure/Logger/Log.cs
+++ b/Wox.Infrastructure/Logger/Log.cs
@@ -11,7 +11,7 @@ namespace Wox.Infrastructure.Logger
{
public const string DirectoryName = "Logs";
- public static string CurrentLogDirectory { get; private set; }
+ public static string CurrentLogDirectory { get; }
static Log()
{
@@ -53,6 +53,14 @@ namespace Wox.Infrastructure.Logger
[MethodImpl(MethodImplOptions.Synchronized)]
public static void Exception(string className, string message, System.Exception exception, [CallerMemberName] string methodName = "")
+ {
+ var classNameWithMethod = CheckClassAndMessageAndReturnFullClassWithMethod(className, message, methodName);
+
+ ExceptionInternal(classNameWithMethod, message, exception);
+ }
+
+ private static string CheckClassAndMessageAndReturnFullClassWithMethod(string className, string message,
+ string methodName)
{
if (string.IsNullOrWhiteSpace(className))
{
@@ -60,16 +68,17 @@ namespace Wox.Infrastructure.Logger
}
if (string.IsNullOrWhiteSpace(message))
- { // todo: not sure we really need that
+ {
+ // todo: not sure we really need that
LogFaultyFormat($"Fail to specify a message during logging");
}
if (!string.IsNullOrWhiteSpace(methodName))
{
- className += "." + methodName;
+ return className + "." + methodName;
}
- ExceptionInternal(className, message, exception);
+ return className;
}
private static void ExceptionInternal(string classAndMethod, string message, System.Exception e)
@@ -140,18 +149,48 @@ namespace Wox.Infrastructure.Logger
LogInternal(message, LogLevel.Error);
}
+ public static void Error(string className, string message, [CallerMemberName] string methodName = "")
+ {
+ LogInternal(LogLevel.Error, className, message, methodName);
+ }
+
+ private static void LogInternal(LogLevel level, string className, string message, [CallerMemberName] string methodName = "")
+ {
+ var classNameWithMethod = CheckClassAndMessageAndReturnFullClassWithMethod(className, message, methodName);
+
+ var logger = LogManager.GetLogger(classNameWithMethod);
+
+ System.Diagnostics.Debug.WriteLine($"{level.Name}|{message}");
+ logger.Log(level, message);
+ }
+
+ public static void Debug(string className, string message, [CallerMemberName] string methodName = "")
+ {
+ LogInternal(LogLevel.Debug, className, message, methodName);
+ }
+
/// example: "|prefix|unprefixed"
public static void Debug(string message)
{
LogInternal(message, LogLevel.Debug);
}
+ public static void Info(string className, string message, [CallerMemberName] string methodName = "")
+ {
+ LogInternal(LogLevel.Info, className, message, methodName);
+ }
+
/// example: "|prefix|unprefixed"
public static void Info(string message)
{
LogInternal(message, LogLevel.Info);
}
+ public static void Warn(string className, string message, [CallerMemberName] string methodName = "")
+ {
+ LogInternal(LogLevel.Warn, className, message, methodName);
+ }
+
/// example: "|prefix|unprefixed"
public static void Warn(string message)
{
diff --git a/Wox.Infrastructure/UI/EnumBindingSource.cs b/Wox.Infrastructure/UI/EnumBindingSource.cs
new file mode 100644
index 000000000..c23aacd81
--- /dev/null
+++ b/Wox.Infrastructure/UI/EnumBindingSource.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Windows.Markup;
+
+namespace Wox.Infrastructure.UI
+{
+ public class EnumBindingSourceExtension : MarkupExtension
+ {
+ private Type _enumType;
+ public Type EnumType
+ {
+ get { return _enumType; }
+ set
+ {
+ if (value != _enumType)
+ {
+ if (value != null)
+ {
+ Type enumType = Nullable.GetUnderlyingType(value) ?? value;
+ if (!enumType.IsEnum)
+ {
+ throw new ArgumentException("Type must represent an enum.");
+ }
+ }
+
+ _enumType = value;
+ }
+ }
+ }
+
+ public EnumBindingSourceExtension() { }
+
+ public EnumBindingSourceExtension(Type enumType)
+ {
+ EnumType = enumType;
+ }
+
+ public override object ProvideValue(IServiceProvider serviceProvider)
+ {
+ if (_enumType == null)
+ {
+ throw new InvalidOperationException("The EnumType must be specified.");
+ }
+
+ Type actualEnumType = Nullable.GetUnderlyingType(_enumType) ?? _enumType;
+ Array enumValues = Enum.GetValues(actualEnumType);
+
+ if (actualEnumType == _enumType)
+ {
+ return enumValues;
+ }
+
+ Array tempArray = Array.CreateInstance(actualEnumType, enumValues.Length + 1);
+ enumValues.CopyTo(tempArray, 1);
+ return tempArray;
+ }
+ }
+}
diff --git a/Wox.Infrastructure/UserSettings/PluginSettings.cs b/Wox.Infrastructure/UserSettings/PluginSettings.cs
index c47fe7c15..346d98e53 100644
--- a/Wox.Infrastructure/UserSettings/PluginSettings.cs
+++ b/Wox.Infrastructure/UserSettings/PluginSettings.cs
@@ -28,7 +28,7 @@ namespace Wox.Infrastructure.UserSettings
{
ID = metadata.ID,
Name = metadata.Name,
- ActionKeywords = metadata.ActionKeywords,
+ ActionKeywords = metadata.ActionKeywords,
Disabled = metadata.Disabled
};
}
@@ -39,7 +39,11 @@ namespace Wox.Infrastructure.UserSettings
{
public string ID { get; set; }
public string Name { get; set; }
- public List ActionKeywords { get; set; }
+ public List ActionKeywords { get; set; } // a reference of the action keywords from plugin manager
+
+ ///
+ /// Used only to save the state of the plugin in settings
+ ///
public bool Disabled { get; set; }
}
}
diff --git a/Wox.Infrastructure/Wox.Infrastructure.csproj b/Wox.Infrastructure/Wox.Infrastructure.csproj
index 16194a35a..445454093 100644
--- a/Wox.Infrastructure/Wox.Infrastructure.csproj
+++ b/Wox.Infrastructure/Wox.Infrastructure.csproj
@@ -72,6 +72,7 @@
+
diff --git a/Wox.Infrastructure/Wox.cs b/Wox.Infrastructure/Wox.cs
index 35faa102c..d9599e07a 100644
--- a/Wox.Infrastructure/Wox.cs
+++ b/Wox.Infrastructure/Wox.cs
@@ -16,6 +16,7 @@ namespace Wox.Infrastructure
public static readonly string ApplicationDirectory = Directory.GetParent(ProgramDirectory).ToString();
public static readonly string RootDirectory = Directory.GetParent(ApplicationDirectory).ToString();
+ public static bool IsPortableMode;
public const string PortableFolderName = "UserData";
public static string PortableDataPath = Path.Combine(ProgramDirectory, PortableFolderName);
public static string RoamingDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Wox);
@@ -23,6 +24,7 @@ namespace Wox.Infrastructure
{
if (Directory.Exists(PortableDataPath))
{
+ IsPortableMode = true;
return PortableDataPath;
}
else
diff --git a/Wox.Plugin/IPublicAPI.cs b/Wox.Plugin/IPublicAPI.cs
index eb3f18fa7..754b76d36 100644
--- a/Wox.Plugin/IPublicAPI.cs
+++ b/Wox.Plugin/IPublicAPI.cs
@@ -70,13 +70,18 @@ namespace Wox.Plugin
///
void ReloadAllPluginData();
+ ///
+ /// Check for new Wox update
+ ///
+ void CheckForNewUpdate();
+
///
/// Show message box
///
/// Message title
/// Message subtitle
/// Message icon path (relative path to your plugin folder)
- void ShowMsg(string title, string subTitle = "", string iconPath = "");
+ void ShowMsg(string title, string subTitle = "", string iconPath = "", bool useMainWindowAsOwner = true);
///
/// Open setting dialog
diff --git a/Wox.Plugin/PluginMetadata.cs b/Wox.Plugin/PluginMetadata.cs
index 5b4feb88e..64b8b032c 100644
--- a/Wox.Plugin/PluginMetadata.cs
+++ b/Wox.Plugin/PluginMetadata.cs
@@ -46,6 +46,9 @@ namespace Wox.Plugin
[Obsolete("Use IcoPath")]
public string FullIcoPath => IcoPath;
+ ///
+ /// Init time include both plugin load time and init time
+ ///
[JsonIgnore]
public long InitTime { get; set; }
[JsonIgnore]
diff --git a/Wox.Plugin/SharedCommands/FilesFolders.cs b/Wox.Plugin/SharedCommands/FilesFolders.cs
index 767f00bb8..584a83bc6 100644
--- a/Wox.Plugin/SharedCommands/FilesFolders.cs
+++ b/Wox.Plugin/SharedCommands/FilesFolders.cs
@@ -42,7 +42,7 @@ namespace Wox.Plugin.SharedCommands
Copy(subdir.FullName, temppath);
}
}
- catch(Exception e)
+ catch (Exception e)
{
#if DEBUG
throw e;
@@ -69,7 +69,7 @@ namespace Wox.Plugin.SharedCommands
return true;
}
- catch(Exception e)
+ catch (Exception e)
{
#if DEBUG
throw e;
@@ -88,7 +88,7 @@ namespace Wox.Plugin.SharedCommands
if (Directory.Exists(path))
Directory.Delete(path, true);
}
- catch(Exception e)
+ catch (Exception e)
{
#if DEBUG
throw e;
diff --git a/Wox.Test/QueryBuilderTest.cs b/Wox.Test/QueryBuilderTest.cs
new file mode 100644
index 000000000..0402d2ae8
--- /dev/null
+++ b/Wox.Test/QueryBuilderTest.cs
@@ -0,0 +1,51 @@
+using System.Collections.Generic;
+using NUnit.Framework;
+using Wox.Core.Plugin;
+using Wox.Plugin;
+
+namespace Wox.Test
+{
+ public class QueryBuilderTest
+ {
+ [Test]
+ public void ExclusivePluginQueryTest()
+ {
+ var nonGlobalPlugins = new Dictionary
+ {
+ {">", new PluginPair {Metadata = new PluginMetadata {ActionKeywords = new List {">"}}}}
+ };
+
+ Query q = QueryBuilder.Build("> file.txt file2 file3", nonGlobalPlugins);
+
+ Assert.AreEqual("file.txt file2 file3", q.Search);
+ Assert.AreEqual(">", q.ActionKeyword);
+ }
+
+ [Test]
+ public void ExclusivePluginQueryIgnoreDisabledTest()
+ {
+ var nonGlobalPlugins = new Dictionary
+ {
+ {">", new PluginPair {Metadata = new PluginMetadata {ActionKeywords = new List {">"}, Disabled = true}}}
+ };
+
+ Query q = QueryBuilder.Build("> file.txt file2 file3", nonGlobalPlugins);
+
+ Assert.AreEqual("> file.txt file2 file3", q.Search);
+ }
+
+ [Test]
+ public void GenericPluginQueryTest()
+ {
+ Query q = QueryBuilder.Build("file.txt file2 file3", new Dictionary());
+
+ Assert.AreEqual("file.txt file2 file3", q.Search);
+ Assert.AreEqual("", q.ActionKeyword);
+
+ Assert.AreEqual("file.txt", q.FirstSearch);
+ Assert.AreEqual("file2", q.SecondSearch);
+ Assert.AreEqual("file3", q.ThirdSearch);
+ Assert.AreEqual("file2 file3", q.SecondToEndSearch);
+ }
+ }
+}
diff --git a/Wox.Test/QueryTest.cs b/Wox.Test/QueryTest.cs
deleted file mode 100644
index b7a0917ef..000000000
--- a/Wox.Test/QueryTest.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using NUnit.Framework;
-using Wox.Core.Plugin;
-using Wox.Plugin;
-
-namespace Wox.Test
-{
- public class QueryTest
- {
- [Test]
- [Ignore("Current query is tightly integrated with GUI, can't be tested.")]
- public void ExclusivePluginQueryTest()
- {
- Query q = PluginManager.QueryInit("> file.txt file2 file3");
-
- Assert.AreEqual(q.FirstSearch, "file.txt");
- Assert.AreEqual(q.SecondSearch, "file2");
- Assert.AreEqual(q.ThirdSearch, "file3");
- Assert.AreEqual(q.SecondToEndSearch, "file2 file3");
- }
-
- [Test]
- [Ignore("Current query is tightly integrated with GUI, can't be tested.")]
- public void GenericPluginQueryTest()
- {
- Query q = PluginManager.QueryInit("file.txt file2 file3");
-
- Assert.AreEqual(q.FirstSearch, "file.txt");
- Assert.AreEqual(q.SecondSearch, "file2");
- Assert.AreEqual(q.ThirdSearch, "file3");
- Assert.AreEqual(q.SecondToEndSearch, "file2 file3");
- }
- }
-}
diff --git a/Wox.Test/Wox.Test.csproj b/Wox.Test/Wox.Test.csproj
index 7a3ef1f0c..2b1e6a78a 100644
--- a/Wox.Test/Wox.Test.csproj
+++ b/Wox.Test/Wox.Test.csproj
@@ -45,7 +45,7 @@
-
+
diff --git a/Wox/PublicAPIInstance.cs b/Wox/PublicAPIInstance.cs
index ab198d6bf..58915f87b 100644
--- a/Wox/PublicAPIInstance.cs
+++ b/Wox/PublicAPIInstance.cs
@@ -5,6 +5,7 @@ using System.Net;
using System.Threading.Tasks;
using System.Windows;
using Squirrel;
+using Wox.Core;
using Wox.Core.Plugin;
using Wox.Core.Resource;
using Wox.Helper;
@@ -65,6 +66,11 @@ namespace Wox
UpdateManager.RestartApp();
}
+ public void CheckForNewUpdate()
+ {
+ _settingsVM.UpdateApp();
+ }
+
public void SaveAppAllSettings()
{
_mainVM.Save();
@@ -91,12 +97,12 @@ namespace Wox
_mainVM.MainWindowVisibility = Visibility.Visible;
}
- public void ShowMsg(string title, string subTitle = "", string iconPath = "")
+ public void ShowMsg(string title, string subTitle = "", string iconPath = "", bool useMainWindowAsOwner = true)
{
Application.Current.Dispatcher.Invoke(() =>
{
- var m = new Msg { Owner = Application.Current.MainWindow };
- m.Show(title, subTitle, iconPath);
+ var msg = useMainWindowAsOwner ? new Msg {Owner = Application.Current.MainWindow} : new Msg();
+ msg.Show(title, subTitle, iconPath);
});
}
diff --git a/Wox/SettingWindow.xaml b/Wox/SettingWindow.xaml
index a6f23814f..1eddd8ab6 100644
--- a/Wox/SettingWindow.xaml
+++ b/Wox/SettingWindow.xaml
@@ -33,7 +33,8 @@
-
+
@@ -51,8 +52,7 @@
-
+
diff --git a/Wox/SettingWindow.xaml.cs b/Wox/SettingWindow.xaml.cs
index 67d67351e..52addf362 100644
--- a/Wox/SettingWindow.xaml.cs
+++ b/Wox/SettingWindow.xaml.cs
@@ -215,7 +215,8 @@ namespace Wox
private void OnPluginToggled(object sender, RoutedEventArgs e)
{
var id = _viewModel.SelectedPlugin.PluginPair.Metadata.ID;
- _settings.PluginSettings.Plugins[id].Disabled = _viewModel.SelectedPlugin.PluginPair.Metadata.Disabled;
+ // used to sync the current status from the plugin manager into the setting to keep consistency after save
+ _settings.PluginSettings.Plugins[id].Disabled = _viewModel.SelectedPlugin.PluginPair.Metadata.Disabled;
}
private void OnPluginActionKeywordsClick(object sender, MouseButtonEventArgs e)
diff --git a/Wox/ViewModel/MainViewModel.cs b/Wox/ViewModel/MainViewModel.cs
index bd1314a27..acdd7c040 100644
--- a/Wox/ViewModel/MainViewModel.cs
+++ b/Wox/ViewModel/MainViewModel.cs
@@ -377,7 +377,7 @@ namespace Wox.ViewModel
ProgressBarVisibility = Visibility.Hidden;
_isQueryRunning = true;
- var query = PluginManager.QueryInit(QueryText.Trim());
+ var query = QueryBuilder.Build(QueryText.Trim(), PluginManager.NonGlobalPlugins);
if (query != null)
{
// handle the exclusiveness of plugin using action keyword
@@ -401,8 +401,7 @@ namespace Wox.ViewModel
{
Parallel.ForEach(plugins, parallelOptions, plugin =>
{
- var config = _settings.PluginSettings.Plugins[plugin.Metadata.ID];
- if (!config.Disabled)
+ if (!plugin.Metadata.Disabled)
{
var results = PluginManager.QueryForPlugin(plugin, query);
UpdateResultView(results, plugin.Metadata, query);
diff --git a/Wox/ViewModel/SettingWindowViewModel.cs b/Wox/ViewModel/SettingWindowViewModel.cs
index d26f86cb9..0a240aec7 100644
--- a/Wox/ViewModel/SettingWindowViewModel.cs
+++ b/Wox/ViewModel/SettingWindowViewModel.cs
@@ -47,7 +47,7 @@ namespace Wox.ViewModel
public async void UpdateApp()
{
- await _updater.UpdateApp();
+ await _updater.UpdateApp(false);
}
public void EnablePortableMode()
@@ -163,26 +163,11 @@ namespace Wox.ViewModel
{
get
{
- var plugins = PluginManager.AllPlugins;
- var settings = Settings.PluginSettings.Plugins;
- plugins.Sort((a, b) =>
- {
- var d1 = settings[a.Metadata.ID].Disabled;
- var d2 = settings[b.Metadata.ID].Disabled;
- if (d1 == d2)
- {
- return string.Compare(a.Metadata.Name, b.Metadata.Name, StringComparison.CurrentCulture);
- }
- else
- {
- return d1.CompareTo(d2);
- }
- });
-
- var metadatas = plugins.Select(p => new PluginViewModel
- {
- PluginPair = p,
- }).ToList();
+ var metadatas = PluginManager.AllPlugins
+ .OrderBy(x => x.Metadata.Disabled)
+ .ThenBy(y => y.Metadata.Name)
+ .Select(p => new PluginViewModel { PluginPair = p})
+ .ToList();
return metadatas;
}
}