Bring history back

1. bring history back, disabled in
56d08663410916df0a4e408da6e4af3d2a2722c0
2. fix #632 #722
3. hotkey: ctrl+H
This commit is contained in:
bao-qian
2016-06-23 22:17:47 +01:00
parent b589a1a13e
commit 15c5e9833a
5 changed files with 231 additions and 237 deletions

View File

@@ -36,6 +36,7 @@
<KeyBinding Key="K" Modifiers="Ctrl" Command="{Binding SelectPrevItemCommand}"></KeyBinding> <KeyBinding Key="K" Modifiers="Ctrl" Command="{Binding SelectPrevItemCommand}"></KeyBinding>
<KeyBinding Key="U" Modifiers="Ctrl" Command="{Binding SelectPrevPageCommand}"></KeyBinding> <KeyBinding Key="U" Modifiers="Ctrl" Command="{Binding SelectPrevPageCommand}"></KeyBinding>
<KeyBinding Key="O" Modifiers="Ctrl" Command="{Binding LoadContextMenuCommand}"></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" Modifiers="Shift" Command="{Binding LoadContextMenuCommand}"></KeyBinding>
<KeyBinding Key="Enter" Command="{Binding OpenResultCommand}"></KeyBinding> <KeyBinding Key="Enter" Command="{Binding OpenResultCommand}"></KeyBinding>
<KeyBinding Key="D1" Modifiers="Alt" Command="{Binding OpenResultCommand}" CommandParameter="0"></KeyBinding> <KeyBinding Key="D1" Modifiers="Alt" Command="{Binding OpenResultCommand}" CommandParameter="0"></KeyBinding>
@@ -77,6 +78,9 @@
<ContentControl> <ContentControl>
<wox:ResultListBox DataContext="{Binding ContextMenu}" PreviewMouseDown="OnPreviewMouseButtonDown" /> <wox:ResultListBox DataContext="{Binding ContextMenu}" PreviewMouseDown="OnPreviewMouseButtonDown" />
</ContentControl> </ContentControl>
<ContentControl>
<wox:ResultListBox DataContext="{Binding History}" PreviewMouseDown="OnPreviewMouseButtonDown" />
</ContentControl>
</StackPanel> </StackPanel>
</Border> </Border>
</Window> </Window>

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.Collections.Generic;
using System.Linq; using System.Linq;
using Newtonsoft.Json; using Newtonsoft.Json;
using Wox.Infrastructure.Storage;
using Wox.Plugin; using Wox.Plugin;
namespace Wox.Storage 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 _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;
}
public void Add(string query) public void Add(string query)
{ {
if (string.IsNullOrEmpty(query)) return; 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 else
{ {
History.Add(new HistoryItem Items.Add(new HistoryItem
{ {
Query = query, Query = query,
ExecutedDateTime = DateTime.Now 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

@@ -27,14 +27,13 @@ namespace Wox.ViewModel
private bool _queryHasReturn; private bool _queryHasReturn;
private Query _lastQuery; private Query _lastQuery;
private string _queryTextBeforeLoadContextMenu; private string _queryTextBeforeLeaveResults;
private string _queryText;
private readonly JsonStrorage<QueryHistory> _queryHistoryStorage; private readonly JsonStrorage<History> _historyItemsStorage;
private readonly JsonStrorage<UserSelectedRecord> _userSelectedRecordStorage; private readonly JsonStrorage<UserSelectedRecord> _userSelectedRecordStorage;
private readonly JsonStrorage<TopMostRecord> _topMostRecordStorage; private readonly JsonStrorage<TopMostRecord> _topMostRecordStorage;
private readonly Settings _settings; private readonly Settings _settings;
private readonly QueryHistory _queryHistory; private readonly History _history;
private readonly UserSelectedRecord _userSelectedRecord; private readonly UserSelectedRecord _userSelectedRecord;
private readonly TopMostRecord _topMostRecord; private readonly TopMostRecord _topMostRecord;
@@ -42,6 +41,8 @@ namespace Wox.ViewModel
private CancellationToken _updateToken; private CancellationToken _updateToken;
private bool _saved; private bool _saved;
private Internationalization _translator = InternationalizationManager.Instance;
#endregion #endregion
#region Constructor #region Constructor
@@ -49,21 +50,22 @@ namespace Wox.ViewModel
public MainViewModel(Settings settings) public MainViewModel(Settings settings)
{ {
_saved = false; _saved = false;
_queryTextBeforeLoadContextMenu = ""; _queryTextBeforeLeaveResults = "";
_queryText = ""; _queryText = "";
_lastQuery = new Query(); _lastQuery = new Query();
_settings = settings; _settings = settings;
_queryHistoryStorage = new JsonStrorage<QueryHistory>(); _historyItemsStorage = new JsonStrorage<History>();
_userSelectedRecordStorage = new JsonStrorage<UserSelectedRecord>(); _userSelectedRecordStorage = new JsonStrorage<UserSelectedRecord>();
_topMostRecordStorage = new JsonStrorage<TopMostRecord>(); _topMostRecordStorage = new JsonStrorage<TopMostRecord>();
_queryHistory = _queryHistoryStorage.Load(); _history = _historyItemsStorage.Load();
_userSelectedRecord = _userSelectedRecordStorage.Load(); _userSelectedRecord = _userSelectedRecordStorage.Load();
_topMostRecord = _topMostRecordStorage.Load(); _topMostRecord = _topMostRecordStorage.Load();
ContextMenu = new ResultsViewModel(_settings); ContextMenu = new ResultsViewModel(_settings);
Results = new ResultsViewModel(_settings); Results = new ResultsViewModel(_settings);
History = new ResultsViewModel(_settings);
_selectedResults = Results; _selectedResults = Results;
InitializeKeyCommands(); InitializeKeyCommands();
@@ -82,7 +84,6 @@ namespace Wox.ViewModel
{ {
Task.Run(() => Task.Run(() =>
{ {
PluginManager.UpdatePluginMetadata(e.Results, pair.Metadata, e.Query); PluginManager.UpdatePluginMetadata(e.Results, pair.Metadata, e.Query);
UpdateResultView(e.Results, pair.Metadata, e.Query); UpdateResultView(e.Results, pair.Metadata, e.Query);
}, _updateToken); }, _updateToken);
@@ -115,21 +116,6 @@ namespace Wox.ViewModel
SelectedResults.SelectPrevResult(); SelectedResults.SelectPrevResult();
}); });
/**
DisplayNextQueryCommand = new RelayCommand(_ =>
{
var nextQuery = _queryHistory.Next();
DisplayQueryHistory(nextQuery);
});
DisplayPrevQueryCommand = new RelayCommand(_ =>
{
var prev = _queryHistory.Previous();
DisplayQueryHistory(prev);
});
**/
SelectNextPageCommand = new RelayCommand(_ => SelectNextPageCommand = new RelayCommand(_ =>
{ {
SelectedResults.SelectNextPage(); SelectedResults.SelectNextPage();
@@ -170,7 +156,7 @@ namespace Wox.ViewModel
if (ResultsSelected()) if (ResultsSelected())
{ {
_userSelectedRecord.Add(result); _userSelectedRecord.Add(result);
_queryHistory.Add(result.OriginQuery.RawQuery); _history.Add(result.OriginQuery.RawQuery);
} }
} }
}); });
@@ -187,6 +173,18 @@ namespace Wox.ViewModel
} }
}); });
LoadHistoryCommand = new RelayCommand(_ =>
{
if (ResultsSelected())
{
SelectedResults = History;
History.SelectedIndex = _history.Items.Count - 1;
}
else
{
SelectedResults = Results;
}
});
} }
#endregion #endregion
@@ -194,38 +192,22 @@ namespace Wox.ViewModel
#region ViewModel Properties #region ViewModel Properties
public ResultsViewModel Results { get; private set; } public ResultsViewModel Results { get; private set; }
public ResultsViewModel ContextMenu { get; private set; } public ResultsViewModel ContextMenu { get; private set; }
public ResultsViewModel History { get; private set; }
private string _queryText;
public string QueryText public string QueryText
{ {
get { return _queryText; } get { return _queryText; }
set set
{ {
_queryText = value; _queryText = value;
ProgressBarVisibility = Visibility.Hidden; Query();
_updateSource?.Cancel();
_updateSource = new CancellationTokenSource();
_updateToken = _updateSource.Token;
if (ResultsSelected())
{
QueryResults();
}
else
{
QueryContextMenu();
}
} }
} }
public bool QueryTextSelected { get; set; } public bool QueryTextSelected { get; set; }
private ResultsViewModel _selectedResults; private ResultsViewModel _selectedResults;
private ResultsViewModel SelectedResults private ResultsViewModel SelectedResults
{ {
get { return _selectedResults; } get { return _selectedResults; }
@@ -234,14 +216,28 @@ namespace Wox.ViewModel
_selectedResults = value; _selectedResults = value;
if (ResultsSelected()) if (ResultsSelected())
{ {
QueryText = _queryTextBeforeLoadContextMenu;
ContextMenu.Visbility = Visibility.Collapsed; ContextMenu.Visbility = Visibility.Collapsed;
History.Visbility = Visibility.Collapsed;
QueryText = _queryTextBeforeLeaveResults;
} }
else else
{ {
_queryTextBeforeLoadContextMenu = QueryText;
QueryText = "";
Results.Visbility = 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; _selectedResults.Visbility = Visibility.Visible;
} }
@@ -254,22 +250,34 @@ namespace Wox.ViewModel
public ICommand EscCommand { get; set; } public ICommand EscCommand { get; set; }
public ICommand SelectNextItemCommand { get; set; } public ICommand SelectNextItemCommand { get; set; }
public ICommand SelectPrevItemCommand { 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 SelectNextPageCommand { get; set; }
public ICommand SelectPrevPageCommand { get; set; } public ICommand SelectPrevPageCommand { get; set; }
public ICommand StartHelpCommand { get; set; } public ICommand StartHelpCommand { get; set; }
public ICommand LoadContextMenuCommand { get; set; } public ICommand LoadContextMenuCommand { get; set; }
public ICommand LoadHistoryCommand { get; set; }
public ICommand OpenResultCommand { get; set; } public ICommand OpenResultCommand { get; set; }
#endregion #endregion
#region Private Methods public void Query()
{
if (ResultsSelected())
{
QueryResults();
}
else if (ContextMenuSelected())
{
QueryContextMenu();
}
else if (HistorySelected())
{
QueryHistory();
}
}
private void QueryContextMenu() private void QueryContextMenu()
{ {
const string contextMenuId = "Context Menu Id"; const string id = "Context Menu ID";
var query = QueryText.ToLower().Trim(); var query = QueryText.ToLower().Trim();
ContextMenu.Clear(); ContextMenu.Clear();
@@ -277,11 +285,9 @@ namespace Wox.ViewModel
if (selected != null) // SelectedItem returns null if selection is empty. if (selected != null) // SelectedItem returns null if selection is empty.
{ {
var id = selected.PluginID;
var results = PluginManager.GetContextMenusForPlugin(selected); var results = PluginManager.GetContextMenusForPlugin(selected);
results.Add(ContextMenuTopMost(selected)); results.Add(ContextMenuTopMost(selected));
results.Add(ContextMenuPluginInfo(id)); results.Add(ContextMenuPluginInfo(selected.PluginID));
if (!string.IsNullOrEmpty(query)) if (!string.IsNullOrEmpty(query))
{ {
@@ -290,22 +296,116 @@ namespace Wox.ViewModel
r => StringMatcher.IsMatch(r.Title, query) || r => StringMatcher.IsMatch(r.Title, query) ||
StringMatcher.IsMatch(r.SubTitle, query) StringMatcher.IsMatch(r.SubTitle, query)
).ToList(); ).ToList();
ContextMenu.AddResults(filtered, contextMenuId); ContextMenu.AddResults(filtered, id);
} }
else else
{ {
ContextMenu.AddResults(results, contextMenuId); ContextMenu.AddResults(results, id);
} }
} }
} }
private void QueryHistory()
{
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 title = _translator.GetTranslation("executeQuery");
var time = _translator.GetTranslation("lastExecuteTime");
var result = new Result
{
Title = string.Format(title, h.Query),
SubTitle = string.Format(time, h.ExecutedDateTime),
IcoPath = "Images\\history.png",
OriginQuery = new Query { RawQuery = h.Query },
Action = _ =>
{
SelectedResults = Results;
QueryText = h.Query;
return false;
}
};
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() private void QueryResults()
{ {
if (!string.IsNullOrEmpty(QueryText)) if (!string.IsNullOrEmpty(QueryText))
{ {
Query(QueryText.Trim()); _updateSource?.Cancel();
//reset query history index after user start new query _updateSource = new CancellationTokenSource();
ResetQueryHistoryIndex(); _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 else
{ {
@@ -314,98 +414,6 @@ namespace Wox.ViewModel
} }
} }
private void Query(string text)
{
_queryHasReturn = false;
var query = PluginManager.QueryInit(text);
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);
}
}
private void ResetQueryHistoryIndex()
{
Results.RemoveResultsFor(QueryHistory.MetaData);
_queryHistory.Reset();
}
/**
private void DisplayQueryHistory(HistoryItem history)
{
if (history != null)
{
var historyMetadata = QueryHistory.MetaData;
QueryText = history.Query;
OnTextBoxSelected();
var executeQueryHistoryTitle = InternationalizationManager.Instance.GetTranslation("executeQuery");
var lastExecuteTime = InternationalizationManager.Instance.GetTranslation("lastExecuteTime");
Results.RemoveResultsExcept(historyMetadata);
var result = new Result
{
Title = string.Format(executeQueryHistoryTitle, history.Query),
SubTitle = string.Format(lastExecuteTime, history.ExecutedDateTime),
IcoPath = "Images\\history.png",
PluginDirectory = Infrastructure.Constant.ProgramDirectory,
Action = _ =>
{
QueryText = history.Query;
OnTextBoxSelected();
return false;
}
};
Task.Run(() =>
{
Results.AddResults(new List<Result> {result}, historyMetadata.ID);
}, _updateToken);
}
}
**/
private Result ContextMenuTopMost(Result result) private Result ContextMenuTopMost(Result result)
{ {
@@ -473,7 +481,18 @@ namespace Wox.ViewModel
return selected; return selected;
} }
#endregion private bool ContextMenuSelected()
{
var selected = SelectedResults == ContextMenu;
return selected;
}
private bool HistorySelected()
{
var selected = SelectedResults == History;
return selected;
}
#region Hotkey #region Hotkey
private void SetHotkey(string hotkeyStr, EventHandler<HotkeyEventArgs> action) private void SetHotkey(string hotkeyStr, EventHandler<HotkeyEventArgs> action)
@@ -527,8 +546,8 @@ namespace Wox.ViewModel
SetHotkey(hotkey.Hotkey, (s, e) => SetHotkey(hotkey.Hotkey, (s, e) =>
{ {
if (ShouldIgnoreHotkeys()) return; if (ShouldIgnoreHotkeys()) return;
QueryText = hotkey.ActionKeyword;
MainWindowVisibility = Visibility.Visible; MainWindowVisibility = Visibility.Visible;
QueryText = hotkey.ActionKeyword;
}); });
} }
} }
@@ -561,7 +580,7 @@ namespace Wox.ViewModel
{ {
if (!_saved) if (!_saved)
{ {
_queryHistoryStorage.Save(); _historyItemsStorage.Save();
_userSelectedRecordStorage.Save(); _userSelectedRecordStorage.Save();
_topMostRecordStorage.Save(); _topMostRecordStorage.Save();

View File

@@ -165,6 +165,7 @@
<Compile Include="ResultListBox.xaml.cs"> <Compile Include="ResultListBox.xaml.cs">
<DependentUpon>ResultListBox.xaml</DependentUpon> <DependentUpon>ResultListBox.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Storage\HistoryItem.cs" />
<Compile Include="Storage\QueryHistory.cs" /> <Compile Include="Storage\QueryHistory.cs" />
<Compile Include="Storage\TopMostRecord.cs" /> <Compile Include="Storage\TopMostRecord.cs" />
<Compile Include="Storage\UserSelectedRecord.cs" /> <Compile Include="Storage\UserSelectedRecord.cs" />