Merge pull request #798 from Wox-launcher/dev

History query related refactoring
This commit is contained in:
bao-qian 2016-06-23 22:24:10 +01:00 committed by GitHub
commit 746bc7d7bd
10 changed files with 318 additions and 417 deletions

View file

@ -1,12 +0,0 @@
using System.Windows;
namespace Wox.Helper
{
public static class VisibilityExtensions
{
public static bool IsVisible(this Visibility visibility)
{
return visibility == Visibility.Visible;
}
}
}

View file

@ -36,6 +36,7 @@
<KeyBinding Key="K" Modifiers="Ctrl" Command="{Binding SelectPrevItemCommand}"></KeyBinding>
<KeyBinding Key="U" Modifiers="Ctrl" Command="{Binding SelectPrevPageCommand}"></KeyBinding>
<KeyBinding Key="O" Modifiers="Ctrl" Command="{Binding LoadContextMenuCommand}"></KeyBinding>
<KeyBinding Key="H" Modifiers="Ctrl" Command="{Binding LoadHistoryCommand}"></KeyBinding>
<KeyBinding Key="Enter" Modifiers="Shift" Command="{Binding LoadContextMenuCommand}"></KeyBinding>
<KeyBinding Key="Enter" Command="{Binding OpenResultCommand}"></KeyBinding>
<KeyBinding Key="D1" Modifiers="Alt" Command="{Binding OpenResultCommand}" CommandParameter="0"></KeyBinding>
@ -53,6 +54,7 @@
<TextBox Style="{DynamicResource QueryBoxStyle}"
Text="{Binding QueryText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
PreviewDragOver="OnPreviewDragOver"
TextChanged="OnTextChanged"
AllowDrop="True"
Visibility="Visible"
x:Name="QueryTextBox">
@ -70,12 +72,15 @@
Style="{DynamicResource PendingLineStyle}" Visibility="{Binding ProgressBarVisibility, Mode=TwoWay}"
Y1="0" Y2="0" X2="100" Height="2" Width="752" StrokeThickness="1">
</Line>
<ContentControl Visibility="{Binding ResultListBoxVisibility}" >
<ContentControl>
<wox:ResultListBox DataContext="{Binding Results}" PreviewMouseDown="OnPreviewMouseButtonDown" />
</ContentControl>
<ContentControl Visibility="{Binding ContextMenuVisibility}">
<ContentControl>
<wox:ResultListBox DataContext="{Binding ContextMenu}" PreviewMouseDown="OnPreviewMouseButtonDown" />
</ContentControl>
<ContentControl>
<wox:ResultListBox DataContext="{Binding History}" PreviewMouseDown="OnPreviewMouseButtonDown" />
</ContentControl>
</StackPanel>
</Border>
</Window>

View file

@ -57,7 +57,7 @@ namespace Wox
{
if (e.PropertyName == nameof(MainViewModel.MainWindowVisibility))
{
if (_viewModel.MainWindowVisibility.IsVisible())
if (Visibility == Visibility.Visible)
{
Activate();
QueryTextBox.Focus();
@ -227,5 +227,10 @@ namespace Wox
e.Handled = true;
}
}
private void OnTextChanged(object sender, TextChangedEventArgs e)
{
QueryTextBox.CaretIndex = QueryTextBox.Text.Length;
}
}
}

View file

@ -11,6 +11,7 @@
SelectedItem="{Binding SelectedItem, Mode=OneWayToSource}"
HorizontalContentAlignment="Stretch" ItemsSource="{Binding Results}"
Margin="{Binding Margin}"
Visibility="{Binding Visbility}"
Style="{DynamicResource BaseListboxStyle}" Focusable="False"
KeyboardNavigation.DirectionalNavigation="Cycle" SelectionMode="Single"
VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Standard"
@ -41,10 +42,10 @@
<RowDefinition Height="Auto" x:Name="SubTitleRowDefinition" />
</Grid.RowDefinitions>
<TextBlock Style="{DynamicResource ItemTitleStyle}" DockPanel.Dock="Left"
VerticalAlignment="Center" ToolTip="{Binding Title}" x:Name="Title"
Text="{Binding Title}" />
<TextBlock Style="{DynamicResource ItemSubTitleStyle}" ToolTip="{Binding SubTitle}"
Grid.Row="1" x:Name="SubTitle" Text="{Binding SubTitle}" />
VerticalAlignment="Center" ToolTip="{Binding Result.Title}" x:Name="Title"
Text="{Binding Result.Title}" />
<TextBlock Style="{DynamicResource ItemSubTitleStyle}" ToolTip="{Binding Result.SubTitle}"
Grid.Row="1" x:Name="SubTitle" Text="{Binding Result.SubTitle}" />
</Grid>
</Grid>
</Button.Content>

View file

@ -0,0 +1,45 @@
using System;
namespace Wox.Storage
{
public class HistoryItem
{
public string Query { get; set; }
public DateTime ExecutedDateTime { get; set; }
public string GetTimeAgo()
{
return DateTimeAgo(ExecutedDateTime);
}
private string DateTimeAgo(DateTime dt)
{
var span = DateTime.Now - dt;
if (span.Days > 365)
{
int years = (span.Days / 365);
if (span.Days % 365 != 0)
years += 1;
return $"about {years} {(years == 1 ? "year" : "years")} ago";
}
if (span.Days > 30)
{
int months = (span.Days / 30);
if (span.Days % 31 != 0)
months += 1;
return $"about {months} {(months == 1 ? "month" : "months")} ago";
}
if (span.Days > 0)
return $"about {span.Days} {(span.Days == 1 ? "day" : "days")} ago";
if (span.Hours > 0)
return $"about {span.Hours} {(span.Hours == 1 ? "hour" : "hours")} ago";
if (span.Minutes > 0)
return $"about {span.Minutes} {(span.Minutes == 1 ? "minute" : "minutes")} ago";
if (span.Seconds > 5)
return $"about {span.Seconds} seconds ago";
if (span.Seconds <= 5)
return "just now";
return string.Empty;
}
}
}

View file

@ -2,111 +2,36 @@
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Wox.Infrastructure.Storage;
using Wox.Plugin;
namespace Wox.Storage
{
public class QueryHistory
public class History
{
public List<HistoryItem> History = new List<HistoryItem>();
public List<HistoryItem> Items { get; set; } = new List<HistoryItem>();
private int MaxHistory = 300;
private int cursor;
public static PluginMetadata MetaData { get; } = new PluginMetadata
{ ID = "Query history", Name = "Query history" };
public HistoryItem Previous()
{
if (History.Count == 0 || cursor == 0) return null;
return History[--cursor];
}
public HistoryItem Next()
{
if (History.Count == 0 || cursor >= History.Count - 1) return null;
return History[++cursor];
}
public void Reset()
{
cursor = History.Count;
}
private int _maxHistory = 300;
public void Add(string query)
{
if (string.IsNullOrEmpty(query)) return;
if (History.Count > MaxHistory)
if (Items.Count > _maxHistory)
{
History.RemoveAt(0);
Items.RemoveAt(0);
}
if (History.Count > 0 && History.Last().Query == query)
if (Items.Count > 0 && Items.Last().Query == query)
{
History.Last().ExecutedDateTime = DateTime.Now;
Items.Last().ExecutedDateTime = DateTime.Now;
}
else
{
History.Add(new HistoryItem
Items.Add(new HistoryItem
{
Query = query,
ExecutedDateTime = DateTime.Now
});
}
Reset();
}
public List<HistoryItem> GetHistory()
{
return History.OrderByDescending(o => o.ExecutedDateTime).ToList();
}
}
public class HistoryItem
{
public string Query { get; set; }
public DateTime ExecutedDateTime { get; set; }
public string GetTimeAgo()
{
return DateTimeAgo(ExecutedDateTime);
}
private string DateTimeAgo(DateTime dt)
{
TimeSpan span = DateTime.Now - dt;
if (span.Days > 365)
{
int years = (span.Days / 365);
if (span.Days % 365 != 0)
years += 1;
return String.Format("about {0} {1} ago",
years, years == 1 ? "year" : "years");
}
if (span.Days > 30)
{
int months = (span.Days / 30);
if (span.Days % 31 != 0)
months += 1;
return String.Format("about {0} {1} ago",
months, months == 1 ? "month" : "months");
}
if (span.Days > 0)
return String.Format("about {0} {1} ago",
span.Days, span.Days == 1 ? "day" : "days");
if (span.Hours > 0)
return String.Format("about {0} {1} ago",
span.Hours, span.Hours == 1 ? "hour" : "hours");
if (span.Minutes > 0)
return String.Format("about {0} {1} ago",
span.Minutes, span.Minutes == 1 ? "minute" : "minutes");
if (span.Seconds > 5)
return String.Format("about {0} seconds ago", span.Seconds);
if (span.Seconds <= 5)
return "just now";
return string.Empty;
}
}
}

View file

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
@ -24,19 +25,15 @@ namespace Wox.ViewModel
{
#region Private Fields
private Visibility _contextMenuVisibility;
private bool _queryHasReturn;
private Query _lastQuery;
private bool _ignoreTextChange;
private string _queryTextBeforeLoadContextMenu;
private string _queryText;
private string _queryTextBeforeLeaveResults;
private readonly JsonStrorage<QueryHistory> _queryHistoryStorage;
private readonly JsonStrorage<History> _historyItemsStorage;
private readonly JsonStrorage<UserSelectedRecord> _userSelectedRecordStorage;
private readonly JsonStrorage<TopMostRecord> _topMostRecordStorage;
private readonly Settings _settings;
private readonly QueryHistory _queryHistory;
private readonly History _history;
private readonly UserSelectedRecord _userSelectedRecord;
private readonly TopMostRecord _topMostRecord;
@ -44,6 +41,8 @@ namespace Wox.ViewModel
private CancellationToken _updateToken;
private bool _saved;
private Internationalization _translator = InternationalizationManager.Instance;
#endregion
#region Constructor
@ -51,21 +50,24 @@ namespace Wox.ViewModel
public MainViewModel(Settings settings)
{
_saved = false;
_queryTextBeforeLoadContextMenu = "";
_queryTextBeforeLeaveResults = "";
_queryText = "";
_lastQuery = new Query();
_settings = settings;
_queryHistoryStorage = new JsonStrorage<QueryHistory>();
_historyItemsStorage = new JsonStrorage<History>();
_userSelectedRecordStorage = new JsonStrorage<UserSelectedRecord>();
_topMostRecordStorage = new JsonStrorage<TopMostRecord>();
_queryHistory = _queryHistoryStorage.Load();
_history = _historyItemsStorage.Load();
_userSelectedRecord = _userSelectedRecordStorage.Load();
_topMostRecord = _topMostRecordStorage.Load();
InitializeResultListBox();
InitializeContextMenu();
ContextMenu = new ResultsViewModel(_settings);
Results = new ResultsViewModel(_settings);
History = new ResultsViewModel(_settings);
_selectedResults = Results;
InitializeKeyCommands();
RegisterResultsUpdatedEvent();
@ -77,12 +79,11 @@ namespace Wox.ViewModel
{
foreach (var pair in PluginManager.GetPluginsForInterface<IResultUpdated>())
{
var plugin = (IResultUpdated) pair.Plugin;
var plugin = (IResultUpdated)pair.Plugin;
plugin.ResultsUpdated += (s, e) =>
{
Task.Run(() =>
{
PluginManager.UpdatePluginMetadata(e.Results, pair.Metadata, e.Query);
UpdateResultView(e.Results, pair.Metadata, e.Query);
}, _updateToken);
@ -95,9 +96,9 @@ namespace Wox.ViewModel
{
EscCommand = new RelayCommand(_ =>
{
if (ContextMenuVisibility.IsVisible())
if (!ResultsSelected())
{
ContextMenuVisibility = Visibility.Collapsed;
SelectedResults = Results;
}
else
{
@ -107,51 +108,22 @@ namespace Wox.ViewModel
SelectNextItemCommand = new RelayCommand(_ =>
{
if (ContextMenuVisibility.IsVisible())
{
ContextMenu.SelectNextResult();
}
else
{
Results.SelectNextResult();
}
SelectedResults.SelectNextResult();
});
SelectPrevItemCommand = new RelayCommand(_ =>
{
if (ContextMenuVisibility.IsVisible())
{
ContextMenu.SelectPrevResult();
}
else
{
Results.SelectPrevResult();
}
SelectedResults.SelectPrevResult();
});
/**
DisplayNextQueryCommand = new RelayCommand(_ =>
{
var nextQuery = _queryHistory.Next();
DisplayQueryHistory(nextQuery);
});
DisplayPrevQueryCommand = new RelayCommand(_ =>
{
var prev = _queryHistory.Previous();
DisplayQueryHistory(prev);
});
**/
SelectNextPageCommand = new RelayCommand(_ =>
{
Results.SelectNextPage();
SelectedResults.SelectNextPage();
});
SelectPrevPageCommand = new RelayCommand(_ =>
{
Results.SelectPrevPage();
SelectedResults.SelectPrevPage();
});
StartHelpCommand = new RelayCommand(_ =>
@ -161,14 +133,14 @@ namespace Wox.ViewModel
OpenResultCommand = new RelayCommand(index =>
{
var results = ContextMenuVisibility.IsVisible() ? ContextMenu : Results;
var results = SelectedResults;
if (index != null)
{
results.SelectedIndex = int.Parse(index.ToString());
}
var result = results.SelectedItem?.RawResult;
var result = results.SelectedItem?.Result;
if (result != null) // SelectedItem returns null if selection is empty.
{
bool hideWindow = result.Action != null && result.Action(new ActionContext
@ -181,83 +153,38 @@ namespace Wox.ViewModel
MainWindowVisibility = Visibility.Collapsed;
}
if (!ContextMenuVisibility.IsVisible())
if (ResultsSelected())
{
_userSelectedRecord.Add(result);
_queryHistory.Add(result.OriginQuery.RawQuery);
_history.Add(result.OriginQuery.RawQuery);
}
}
});
LoadContextMenuCommand = new RelayCommand(_ =>
{
if (!ContextMenuVisibility.IsVisible())
if (ResultsSelected())
{
var result = Results.SelectedItem?.RawResult;
if (result != null) // SelectedItem returns null if selection is empty.
{
var id = result.PluginID;
var menus = PluginManager.GetContextMenusForPlugin(result);
menus.Add(ContextMenuTopMost(result));
menus.Add(ContextMenuPluginInfo(id));
ContextMenu.Clear();
Task.Run(() =>
{
ContextMenu.AddResults(menus, id);
}, _updateToken);
ContextMenuVisibility = Visibility.Visible;
}
SelectedResults = ContextMenu;
}
else
{
ContextMenuVisibility = Visibility.Collapsed;
SelectedResults = Results;
}
});
}
private void InitializeResultListBox()
{
Results = new ResultsViewModel(_settings);
ResultListBoxVisibility = Visibility.Collapsed;
}
private void InitializeContextMenu()
{
ContextMenu = new ResultsViewModel(_settings);
ContextMenuVisibility = Visibility.Collapsed;
}
private void HandleQueryTextUpdated()
{
ProgressBarVisibility = Visibility.Hidden;
_updateSource?.Cancel();
_updateSource = new CancellationTokenSource();
_updateToken = _updateSource.Token;
if (ContextMenuVisibility.IsVisible())
LoadHistoryCommand = new RelayCommand(_ =>
{
QueryContextMenu();
}
else
{
string query = QueryText.Trim();
if (!string.IsNullOrEmpty(query))
if (ResultsSelected())
{
Query(query);
//reset query history index after user start new query
ResetQueryHistoryIndex();
SelectedResults = History;
History.SelectedIndex = _history.Items.Count - 1;
}
else
{
Results.Clear();
ResultListBoxVisibility = Visibility.Collapsed;
SelectedResults = Results;
}
}
});
}
#endregion
@ -265,192 +192,228 @@ namespace Wox.ViewModel
#region ViewModel Properties
public ResultsViewModel Results { get; private set; }
public ResultsViewModel ContextMenu { get; private set; }
public ResultsViewModel History { get; private set; }
private string _queryText;
public string QueryText
{
get { return _queryText; }
set
{
_queryText = value;
if (_ignoreTextChange)
{
_ignoreTextChange = false;
}
else
{
HandleQueryTextUpdated();
}
Query();
}
}
public bool QueryTextSelected { get; set; }
public Visibility ContextMenuVisibility
private ResultsViewModel _selectedResults;
private ResultsViewModel SelectedResults
{
get { return _contextMenuVisibility; }
get { return _selectedResults; }
set
{
_contextMenuVisibility = value;
_ignoreTextChange = true;
if (!value.IsVisible())
_selectedResults = value;
if (ResultsSelected())
{
QueryText = _queryTextBeforeLoadContextMenu;
ResultListBoxVisibility = Visibility.Visible;
ContextMenu.Visbility = Visibility.Collapsed;
History.Visbility = Visibility.Collapsed;
QueryText = _queryTextBeforeLeaveResults;
}
else
{
_queryTextBeforeLoadContextMenu = QueryText;
QueryText = "";
ResultListBoxVisibility = Visibility.Collapsed;
Results.Visbility = Visibility.Collapsed;
_queryTextBeforeLeaveResults = QueryText;
// Because of Fody's optimization
// setter won't be called when property value is not changed.
// so we need manually call Query()
// http://stackoverflow.com/posts/25895769/revisions
if (string.IsNullOrEmpty(QueryText))
{
Query();
}
else
{
QueryText = string.Empty;
}
}
_selectedResults.Visbility = Visibility.Visible;
}
}
public Visibility ProgressBarVisibility { get; set; }
public Visibility ResultListBoxVisibility { get; set; }
public Visibility MainWindowVisibility { get; set; }
public ICommand EscCommand { get; set; }
public ICommand SelectNextItemCommand { get; set; }
public ICommand SelectPrevItemCommand { get; set; }
//todo happlebao restore history command
public ICommand DisplayNextQueryCommand { get; set; }
public ICommand DisplayPrevQueryCommand { get; set; }
public ICommand SelectNextPageCommand { get; set; }
public ICommand SelectPrevPageCommand { get; set; }
public ICommand StartHelpCommand { get; set; }
public ICommand LoadContextMenuCommand { get; set; }
public ICommand LoadHistoryCommand { get; set; }
public ICommand OpenResultCommand { get; set; }
#endregion
#region Private Methods
public void Query()
{
if (ResultsSelected())
{
QueryResults();
}
else if (ContextMenuSelected())
{
QueryContextMenu();
}
else if (HistorySelected())
{
QueryHistory();
}
}
private void QueryContextMenu()
{
var contextMenuId = "Context Menu Id";
var query = QueryText.ToLower();
if (!string.IsNullOrEmpty(query))
{
const string id = "Context Menu ID";
var query = QueryText.ToLower().Trim();
ContextMenu.Clear();
List<Result> filterResults = new List<Result>();
foreach (var contextMenu in ContextMenu.Results)
{
if (StringMatcher.IsMatch(contextMenu.Title, query)
|| StringMatcher.IsMatch(contextMenu.SubTitle, query))
{
filterResults.Add(contextMenu.RawResult);
}
}
ContextMenu.Clear();
Task.Run(() =>
{
ContextMenu.AddResults(filterResults, contextMenuId);
}, _updateToken);
}
}
var selected = Results.SelectedItem?.Result;
private void Query(string text)
{
_queryHasReturn = false;
var query = PluginManager.QueryInit(text);
if (query != null)
if (selected != null) // SelectedItem returns null if selection is empty.
{
// handle the exclusiveness of plugin using action keyword
string lastKeyword = _lastQuery.ActionKeyword;
string keyword = query.ActionKeyword;
if (string.IsNullOrEmpty(lastKeyword))
var results = PluginManager.GetContextMenusForPlugin(selected);
results.Add(ContextMenuTopMost(selected));
results.Add(ContextMenuPluginInfo(selected.PluginID));
if (!string.IsNullOrEmpty(query))
{
if (!string.IsNullOrEmpty(keyword))
{
Results.RemoveResultsExcept(PluginManager.NonGlobalPlugins[keyword].Metadata);
}
var filtered = results.Where
(
r => StringMatcher.IsMatch(r.Title, query) ||
StringMatcher.IsMatch(r.SubTitle, query)
).ToList();
ContextMenu.AddResults(filtered, id);
}
else
{
if (string.IsNullOrEmpty(keyword))
{
Results.RemoveResultsFor(PluginManager.NonGlobalPlugins[lastKeyword].Metadata);
}
else if (lastKeyword != keyword)
{
Results.RemoveResultsExcept(PluginManager.NonGlobalPlugins[keyword].Metadata);
}
ContextMenu.AddResults(results, id);
}
_lastQuery = query;
Task.Delay(200, _updateToken).ContinueWith(_ =>
{
if (query.RawQuery == _lastQuery.RawQuery && !_queryHasReturn)
{
ProgressBarVisibility = Visibility.Visible;
}
}, _updateToken);
var plugins = PluginManager.ValidPluginsForQuery(query);
Task.Run(() =>
{
Parallel.ForEach(plugins, plugin =>
{
var config = _settings.PluginSettings.Plugins[plugin.Metadata.ID];
if (!config.Disabled)
{
var results = PluginManager.QueryForPlugin(plugin, query);
UpdateResultView(results, plugin.Metadata, query);
}
});
}, _updateToken);
}
}
private void ResetQueryHistoryIndex()
private void QueryHistory()
{
Results.RemoveResultsFor(QueryHistory.MetaData);
_queryHistory.Reset();
}
/**
private void DisplayQueryHistory(HistoryItem history)
{
if (history != null)
const string id = "Query History ID";
var query = QueryText.ToLower().Trim();
History.Clear();
var results = new List<Result>();
foreach (var h in _history.Items)
{
var historyMetadata = QueryHistory.MetaData;
QueryText = history.Query;
OnTextBoxSelected();
var executeQueryHistoryTitle = InternationalizationManager.Instance.GetTranslation("executeQuery");
var lastExecuteTime = InternationalizationManager.Instance.GetTranslation("lastExecuteTime");
Results.RemoveResultsExcept(historyMetadata);
var title = _translator.GetTranslation("executeQuery");
var time = _translator.GetTranslation("lastExecuteTime");
var result = new Result
{
Title = string.Format(executeQueryHistoryTitle, history.Query),
SubTitle = string.Format(lastExecuteTime, history.ExecutedDateTime),
Title = string.Format(title, h.Query),
SubTitle = string.Format(time, h.ExecutedDateTime),
IcoPath = "Images\\history.png",
PluginDirectory = Infrastructure.Constant.ProgramDirectory,
OriginQuery = new Query { RawQuery = h.Query },
Action = _ =>
{
QueryText = history.Query;
OnTextBoxSelected();
SelectedResults = Results;
QueryText = h.Query;
return false;
}
};
Task.Run(() =>
{
Results.AddResults(new List<Result> {result}, historyMetadata.ID);
}, _updateToken);
results.Add(result);
}
if (!string.IsNullOrEmpty(query))
{
var filtered = results.Where
(
r => StringMatcher.IsMatch(r.Title, query) ||
StringMatcher.IsMatch(r.SubTitle, query)
).ToList();
History.AddResults(filtered, id);
}
else
{
History.AddResults(results, id);
}
}
**/
private void QueryResults()
{
if (!string.IsNullOrEmpty(QueryText))
{
_updateSource?.Cancel();
_updateSource = new CancellationTokenSource();
_updateToken = _updateSource.Token;
ProgressBarVisibility = Visibility.Hidden;
_queryHasReturn = false;
var query = PluginManager.QueryInit(QueryText.Trim());
if (query != null)
{
// handle the exclusiveness of plugin using action keyword
string lastKeyword = _lastQuery.ActionKeyword;
string keyword = query.ActionKeyword;
if (string.IsNullOrEmpty(lastKeyword))
{
if (!string.IsNullOrEmpty(keyword))
{
Results.RemoveResultsExcept(PluginManager.NonGlobalPlugins[keyword].Metadata);
}
}
else
{
if (string.IsNullOrEmpty(keyword))
{
Results.RemoveResultsFor(PluginManager.NonGlobalPlugins[lastKeyword].Metadata);
}
else if (lastKeyword != keyword)
{
Results.RemoveResultsExcept(PluginManager.NonGlobalPlugins[keyword].Metadata);
}
}
_lastQuery = query;
Task.Delay(200, _updateToken).ContinueWith(_ =>
{
if (query.RawQuery == _lastQuery.RawQuery && !_queryHasReturn)
{
ProgressBarVisibility = Visibility.Visible;
}
}, _updateToken);
var plugins = PluginManager.ValidPluginsForQuery(query);
Task.Run(() =>
{
Parallel.ForEach(plugins, plugin =>
{
var config = _settings.PluginSettings.Plugins[plugin.Metadata.ID];
if (!config.Disabled)
{
var results = PluginManager.QueryForPlugin(plugin, query);
UpdateResultView(results, plugin.Metadata, query);
}
});
}, _updateToken);
}
}
else
{
Results.Clear();
Results.Visbility = Visibility.Collapsed;
}
}
private Result ContextMenuTopMost(Result result)
{
@ -461,7 +424,7 @@ namespace Wox.ViewModel
{
Title = InternationalizationManager.Instance.GetTranslation("cancelTopMostInThisQuery"),
IcoPath = "Images\\down.png",
PluginDirectory = Infrastructure.Constant.ProgramDirectory,
PluginDirectory = Constant.ProgramDirectory,
Action = _ =>
{
_topMostRecord.Remove(result);
@ -476,7 +439,7 @@ namespace Wox.ViewModel
{
Title = InternationalizationManager.Instance.GetTranslation("setAsTopMostInThisQuery"),
IcoPath = "Images\\up.png",
PluginDirectory = Infrastructure.Constant.ProgramDirectory,
PluginDirectory = Constant.ProgramDirectory,
Action = _ =>
{
_topMostRecord.AddOrUpdate(result);
@ -512,16 +475,33 @@ namespace Wox.ViewModel
return menu;
}
#endregion
private bool ResultsSelected()
{
var selected = SelectedResults == Results;
return selected;
}
private bool ContextMenuSelected()
{
var selected = SelectedResults == ContextMenu;
return selected;
}
private bool HistorySelected()
{
var selected = SelectedResults == History;
return selected;
}
#region Hotkey
internal void SetHotkey(string hotkeyStr, EventHandler<HotkeyEventArgs> action)
private void SetHotkey(string hotkeyStr, EventHandler<HotkeyEventArgs> action)
{
var hotkey = new HotkeyModel(hotkeyStr);
SetHotkey(hotkey, action);
}
public void SetHotkey(HotkeyModel hotkey, EventHandler<HotkeyEventArgs> action)
private void SetHotkey(HotkeyModel hotkey, EventHandler<HotkeyEventArgs> action)
{
string hotkeyStr = hotkey.ToString();
try
@ -566,8 +546,8 @@ namespace Wox.ViewModel
SetHotkey(hotkey.Hotkey, (s, e) =>
{
if (ShouldIgnoreHotkeys()) return;
QueryText = hotkey.ActionKeyword;
MainWindowVisibility = Visibility.Visible;
QueryText = hotkey.ActionKeyword;
});
}
}
@ -582,7 +562,7 @@ namespace Wox.ViewModel
private void ToggleWox()
{
if (!MainWindowVisibility.IsVisible())
if (MainWindowVisibility != Visibility.Visible)
{
MainWindowVisibility = Visibility.Visible;
}
@ -600,7 +580,7 @@ namespace Wox.ViewModel
{
if (!_saved)
{
_queryHistoryStorage.Save();
_historyItemsStorage.Save();
_userSelectedRecordStorage.Save();
_topMostRecordStorage.Save();
@ -627,7 +607,7 @@ namespace Wox.ViewModel
}
else
{
result.Score += _userSelectedRecord.GetSelectedCount(result)*5;
result.Score += _userSelectedRecord.GetSelectedCount(result) * 5;
}
}
@ -636,12 +616,12 @@ namespace Wox.ViewModel
Results.AddResults(list, metadata.ID);
}
if (list.Count > 0 && !ResultListBoxVisibility.IsVisible())
if (Results.Visbility != Visibility.Visible && list.Count > 0)
{
ResultListBoxVisibility = Visibility.Visible;
Results.Visbility = Visibility.Visible;
}
}
#endregion
}
}
}

View file

@ -1,6 +1,4 @@
using System;
using System.Windows.Media;
using System.Windows;
using System.Windows.Media;
using Wox.Infrastructure.Image;
using Wox.Plugin;
@ -9,86 +7,39 @@ namespace Wox.ViewModel
{
public class ResultViewModel : BaseModel
{
#region Private Fields
private bool _isSelected;
#endregion
#region Constructor
public ResultViewModel(Result result)
{
if (result != null)
{
RawResult = result;
Result = result;
}
}
public ImageSource Image => ImageLoader.Load(Result.IcoPath);
#endregion
#region ViewModel Properties
public string Title => RawResult.Title;
public string SubTitle => RawResult.SubTitle;
public string PluginID => RawResult.PluginID;
public ImageSource Image => ImageLoader.Load(RawResult.IcoPath);
public int Score
{
get { return RawResult.Score; }
set { RawResult.Score = value; }
}
public Query OriginQuery
{
get { return RawResult.OriginQuery; }
set { RawResult.OriginQuery = value; }
}
public Func<ActionContext, bool> Action
{
get { return RawResult.Action; }
set { RawResult.Action = value; }
}
#endregion
#region Properties
internal Result RawResult { get; }
#endregion
public void Update(ResultViewModel newResult)
{
RawResult.Score = newResult.RawResult.Score;
RawResult.OriginQuery = newResult.RawResult.OriginQuery;
}
public Result Result { get; }
public override bool Equals(object obj)
{
ResultViewModel r = obj as ResultViewModel;
var r = obj as ResultViewModel;
if (r != null)
{
return RawResult.Equals(r.RawResult);
return Result.Equals(r.Result);
}
else
{
return false;
}
return false;
}
public override int GetHashCode()
{
return RawResult.GetHashCode();
return Result.GetHashCode();
}
public override string ToString()
{
return RawResult.ToString();
return Result.ToString();
}
}

View file

@ -39,7 +39,7 @@ namespace Wox.ViewModel
#endregion
#region ViewModel Properties
#region Properties
public int MaxHeight => MaxResults * 50;
@ -47,6 +47,7 @@ namespace Wox.ViewModel
public ResultViewModel SelectedItem { get; set; }
public Thickness Margin { get; set; }
public Visibility Visbility { get; set; } = Visibility.Collapsed;
#endregion
@ -58,7 +59,7 @@ namespace Wox.ViewModel
for (; index < list.Count; index++)
{
var result = list[index];
if (newScore > result.RawResult.Score)
if (newScore > result.Result.Score)
{
break;
}
@ -113,12 +114,12 @@ namespace Wox.ViewModel
public void RemoveResultsExcept(PluginMetadata metadata)
{
Results.RemoveAll(r => r.RawResult.PluginID != metadata.ID);
Results.RemoveAll(r => r.Result.PluginID != metadata.ID);
}
public void RemoveResultsFor(PluginMetadata metadata)
{
Results.RemoveAll(r => r.PluginID == metadata.ID);
Results.RemoveAll(r => r.Result.PluginID == metadata.ID);
}
/// <summary>
@ -149,7 +150,7 @@ namespace Wox.ViewModel
{
var newResults = newRawResults.Select(r => new ResultViewModel(r)).ToList();
var results = Results.ToList();
var oldResults = results.Where(r => r.PluginID == resultId).ToList();
var oldResults = results.Where(r => r.Result.PluginID == resultId).ToList();
// intersection of A (old results) and B (new newResults)
var intersection = oldResults.Intersect(newResults).ToList();
@ -164,15 +165,15 @@ namespace Wox.ViewModel
foreach (var commonResult in intersection)
{
int oldIndex = results.IndexOf(commonResult);
int oldScore = results[oldIndex].Score;
int oldScore = results[oldIndex].Result.Score;
var newResult = newResults[newResults.IndexOf(commonResult)];
int newScore = newResult.Score;
int newScore = newResult.Result.Score;
if (newScore != oldScore)
{
var oldResult = results[oldIndex];
oldResult.Score = newScore;
oldResult.OriginQuery = newResult.OriginQuery;
oldResult.Result.Score = newScore;
oldResult.Result.OriginQuery = newResult.Result.OriginQuery;
results.RemoveAt(oldIndex);
int newIndex = InsertIndexOf(newScore, results);
@ -183,7 +184,7 @@ namespace Wox.ViewModel
// insert result in relative complement of A in B
foreach (var result in newResults.Except(intersection))
{
int newIndex = InsertIndexOf(result.Score, results);
int newIndex = InsertIndexOf(result.Result.Score, results);
results.Insert(newIndex, result);
}
@ -223,9 +224,9 @@ namespace Wox.ViewModel
{
this[i] = newResult;
}
else if (oldResult.Score != newResult.Score)
else if (oldResult.Result.Score != newResult.Result.Score)
{
this[i].Score = newResult.Score;
this[i].Result.Score = newResult.Result.Score;
}
}

View file

@ -159,13 +159,13 @@
<Link>Properties\SolutionAssemblyInfo.cs</Link>
</Compile>
<Compile Include="CrashReporter.cs" />
<Compile Include="Helper\VisibilityExtensions.cs" />
<Compile Include="Helper\SingletonWindowOpener.cs" />
<Compile Include="PublicAPIInstance.cs" />
<Compile Include="ReportWindow.xaml.cs" />
<Compile Include="ResultListBox.xaml.cs">
<DependentUpon>ResultListBox.xaml</DependentUpon>
</Compile>
<Compile Include="Storage\HistoryItem.cs" />
<Compile Include="Storage\QueryHistory.cs" />
<Compile Include="Storage\TopMostRecord.cs" />
<Compile Include="Storage\UserSelectedRecord.cs" />