mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-10 13:35:31 +02:00
Add Context menu
This commit is contained in:
BIN
Plugins/Wox.Plugin.FindFile/Images/edit.png
Normal file
BIN
Plugins/Wox.Plugin.FindFile/Images/edit.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.6 KiB |
@@ -36,7 +36,7 @@ namespace Wox.Plugin.FindFile
|
|||||||
MFTSearcher.IndexAllVolumes();
|
MFTSearcher.IndexAllVolumes();
|
||||||
initial = true;
|
initial = true;
|
||||||
var searchtimeend = DateTime.Now;
|
var searchtimeend = DateTime.Now;
|
||||||
Debug.WriteLine(string.Format("{0} file, {1} folder indexed, {2}ms has spent.", MFTSearcher.IndexedFileCount, MFTSearcher.IndexedFolderCount, searchtimeend.Subtract(searchtimestart).TotalMilliseconds));
|
Debug.WriteLine(string.Format("{0} file, indexed, {1}ms has spent.", MFTSearcher.IndexedRecordsCount, searchtimeend.Subtract(searchtimestart).TotalMilliseconds));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result ConvertMFTSearch(MFTSearchRecord record, string query)
|
private Result ConvertMFTSearch(MFTSearchRecord record, string query)
|
||||||
@@ -67,8 +67,57 @@ namespace Wox.Plugin.FindFile
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
},
|
||||||
|
ContextMenu = GetContextMenu(record)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Result> GetContextMenu(MFTSearchRecord record)
|
||||||
|
{
|
||||||
|
List<Result> contextMenus = new List<Result>();
|
||||||
|
|
||||||
|
contextMenus.Add(new Result()
|
||||||
|
{
|
||||||
|
Title = "Open",
|
||||||
|
Action = _ =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Process.Start(record.FullPath);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
context.API.ShowMsg("Can't open " + record.FullPath, string.Empty, string.Empty);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
IcoPath = "Images/edit.png"
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!record.IsFolder)
|
||||||
|
{
|
||||||
|
contextMenus.Add(new Result()
|
||||||
|
{
|
||||||
|
Title = "Open Containing Folder",
|
||||||
|
Action = _ =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Process.Start("explorer.exe", string.Format("/select, \"{0}\"", record.FullPath));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
context.API.ShowMsg("Can't open " + record.FullPath, string.Empty, string.Empty);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
IcoPath = "Images/folder.png"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return contextMenus;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,12 @@
|
|||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="Images\find.png" />
|
<Content Include="Images\edit.png">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Images\find.png">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="Images\folder.png">
|
<Content Include="Images\folder.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ using System.Diagnostics;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using MyEverything;
|
|
||||||
|
|
||||||
namespace Wox.Infrastructure.MFTSearch
|
namespace Wox.Infrastructure.MFTSearch
|
||||||
{
|
{
|
||||||
@@ -23,8 +22,8 @@ namespace Wox.Infrastructure.MFTSearch
|
|||||||
List<USNRecord> files;
|
List<USNRecord> files;
|
||||||
List<USNRecord> folders;
|
List<USNRecord> folders;
|
||||||
EnumerateVolume(volume, out files, out folders);
|
EnumerateVolume(volume, out files, out folders);
|
||||||
cache.AddRecord(volume, files, USNRecordType.File);
|
//cache.AddRecord(files);
|
||||||
cache.AddRecord(volume, folders, USNRecordType.Folder);
|
//cache.AddRecord(folders);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void IndexAllVolumes()
|
public static void IndexAllVolumes()
|
||||||
@@ -35,13 +34,9 @@ namespace Wox.Infrastructure.MFTSearch
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long IndexedFileCount
|
public static long IndexedRecordsCount
|
||||||
{
|
{
|
||||||
get { return cache.FileCount; }
|
get { return cache.RecordsCount; }
|
||||||
}
|
|
||||||
public static long IndexedFolderCount
|
|
||||||
{
|
|
||||||
get { return cache.FolderCount; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<MFTSearchRecord> Search(string item)
|
public static List<MFTSearchRecord> Search(string item)
|
||||||
@@ -49,7 +44,7 @@ namespace Wox.Infrastructure.MFTSearch
|
|||||||
if (string.IsNullOrEmpty(item)) return new List<MFTSearchRecord>();
|
if (string.IsNullOrEmpty(item)) return new List<MFTSearchRecord>();
|
||||||
|
|
||||||
List<USNRecord> found = cache.FindByName(item);
|
List<USNRecord> found = cache.FindByName(item);
|
||||||
found.ForEach(x => FillPath(x.VolumeName, x, cache));
|
found.ForEach(x => FillPath(x, cache));
|
||||||
return found.ConvertAll(o => new MFTSearchRecord(o));
|
return found.ConvertAll(o => new MFTSearchRecord(o));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,14 +250,16 @@ namespace Wox.Infrastructure.MFTSearch
|
|||||||
}
|
}
|
||||||
Marshal.FreeHGlobal(pData);
|
Marshal.FreeHGlobal(pData);
|
||||||
}
|
}
|
||||||
internal static void FillPath(string volume, USNRecord record, MFTSearcherCache db)
|
|
||||||
|
internal static void FillPath(USNRecord record, MFTSearcherCache db)
|
||||||
{
|
{
|
||||||
if (record == null) return;
|
if (record == null) return;
|
||||||
var fdSource = db.GetFolderSource(volume);
|
var fdSource = db.GetAllRecords();
|
||||||
string fullpath = record.Name;
|
string fullpath = record.Name;
|
||||||
FindRecordPath(record, ref fullpath, fdSource);
|
FindRecordPath(record, ref fullpath, fdSource);
|
||||||
record.FullPath = fullpath;
|
record.FullPath = fullpath;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void FindRecordPath(USNRecord curRecord, ref string fullpath, Dictionary<ulong, USNRecord> fdSource)
|
private static void FindRecordPath(USNRecord curRecord, ref string fullpath, Dictionary<ulong, USNRecord> fdSource)
|
||||||
{
|
{
|
||||||
if (curRecord.IsVolumeRoot) return;
|
if (curRecord.IsVolumeRoot) return;
|
||||||
|
|||||||
@@ -1,133 +1,60 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using MyEverything;
|
|
||||||
|
|
||||||
namespace Wox.Infrastructure.MFTSearch
|
namespace Wox.Infrastructure.MFTSearch
|
||||||
{
|
{
|
||||||
internal class MFTSearcherCache
|
internal class MFTSearcherCache
|
||||||
{
|
{
|
||||||
private Dictionary<string, Dictionary<ulong, USNRecord>> _volumes_files = new Dictionary<string, Dictionary<ulong, USNRecord>>();
|
private Dictionary<ulong, USNRecord> records = new Dictionary<ulong, USNRecord>(100000);
|
||||||
private Dictionary<string, Dictionary<ulong, USNRecord>> _volumes_folders = new Dictionary<string, Dictionary<ulong, USNRecord>>();
|
private Lookup<string, string> recordsLookup;
|
||||||
|
|
||||||
public MFTSearcherCache() { }
|
public MFTSearcherCache() { }
|
||||||
|
|
||||||
public bool ContainsVolume(string volume)
|
public void AddRecord(List<USNRecord> record)
|
||||||
{
|
{
|
||||||
return _volumes_files.ContainsKey(volume) && _volumes_folders.ContainsKey(volume);
|
record.ForEach(AddRecord);
|
||||||
}
|
}
|
||||||
public void AddRecord(string volume, List<USNRecord> r, USNRecordType type)
|
|
||||||
|
public void AddRecord(USNRecord record)
|
||||||
{
|
{
|
||||||
if (type == USNRecordType.File)
|
if(!records.ContainsKey(record.FRN)) records.Add(record.FRN, record);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DeleteRecord(ulong frn)
|
||||||
|
{
|
||||||
|
return records.Remove(frn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateRecord(USNRecord record)
|
||||||
|
{
|
||||||
|
USNRecord firstOrDefault = records[record.FRN];
|
||||||
|
if (firstOrDefault != null)
|
||||||
{
|
{
|
||||||
CheckHashTableKey(_volumes_files, volume);
|
firstOrDefault.Name = record.Name;
|
||||||
r.ForEach(x => _volumes_files[volume].Add(x.FRN, x));
|
firstOrDefault.FullPath = record.FullPath;
|
||||||
}
|
firstOrDefault.VolumeName = record.VolumeName;
|
||||||
else
|
|
||||||
{
|
|
||||||
CheckHashTableKey(_volumes_folders, volume);
|
|
||||||
r.ForEach(x => _volumes_folders[volume].Add(x.FRN, x));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void AddRecord(string volume, USNRecord record, USNRecordType type)
|
|
||||||
{
|
|
||||||
if (type == USNRecordType.File)
|
|
||||||
{
|
|
||||||
CheckHashTableKey(_volumes_files, volume);
|
|
||||||
_volumes_files[volume].Add(record.FRN, record);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CheckHashTableKey(_volumes_folders, volume);
|
|
||||||
_volumes_folders[volume].Add(record.FRN, record);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private void CheckHashTableKey(Dictionary<string, Dictionary<ulong, USNRecord>> hashtable, string key)
|
|
||||||
{
|
|
||||||
if (!hashtable.ContainsKey(key))
|
|
||||||
hashtable.Add(key, new Dictionary<ulong, USNRecord>());
|
|
||||||
}
|
|
||||||
public bool DeleteRecord(string volume, ulong frn)
|
|
||||||
{
|
|
||||||
bool result = false;
|
|
||||||
result = DeleteRecordHashTableItem(_volumes_files, volume, frn);
|
|
||||||
if (!result) result = DeleteRecordHashTableItem(_volumes_folders, volume, frn);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
private bool DeleteRecordHashTableItem(Dictionary<string, Dictionary<ulong, USNRecord>> hashtable, string volume, ulong frn)
|
|
||||||
{
|
|
||||||
if (hashtable.ContainsKey(volume) && hashtable[volume].ContainsKey(frn))
|
|
||||||
{
|
|
||||||
hashtable[volume].Remove(frn);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void UpdateRecord(string volume, USNRecord record, USNRecordType type)
|
|
||||||
{
|
|
||||||
if (type == USNRecordType.File)
|
|
||||||
RealUpdateRecord(volume, _volumes_files, record);
|
|
||||||
else
|
|
||||||
RealUpdateRecord(volume, _volumes_folders, record);
|
|
||||||
}
|
|
||||||
private bool RealUpdateRecord(string volume, Dictionary<string, Dictionary<ulong, USNRecord>> source, USNRecord record)
|
|
||||||
{
|
|
||||||
if (source.ContainsKey(volume) && source[volume].ContainsKey(record.FRN))
|
|
||||||
{
|
|
||||||
source[volume][record.FRN] = record;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public List<USNRecord> FindByName(string filename)
|
public List<USNRecord> FindByName(string filename)
|
||||||
{
|
{
|
||||||
filename = filename.ToLower();
|
filename = filename.ToLower();
|
||||||
var fileQuery = from filesInVolumeDic in _volumes_files.Values
|
var query = from file in records.Values
|
||||||
from eachFilePair in filesInVolumeDic
|
where file.Name.ToLower().Contains(filename)
|
||||||
where eachFilePair.Value.Name.ToLower().Contains(filename)
|
select file;
|
||||||
select eachFilePair.Value;
|
return query.ToList();
|
||||||
|
|
||||||
var folderQuery = from fldsInVolumeDic in _volumes_folders.Values
|
|
||||||
from eachFldPair in fldsInVolumeDic
|
|
||||||
where eachFldPair.Value.Name.ToLower().Contains(filename)
|
|
||||||
select eachFldPair.Value;
|
|
||||||
|
|
||||||
List<USNRecord> result = new List<USNRecord>();
|
|
||||||
|
|
||||||
result.AddRange(fileQuery);
|
|
||||||
result.AddRange(folderQuery);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
public USNRecord FindByFrn(string volume, ulong frn)
|
|
||||||
|
public long RecordsCount
|
||||||
{
|
{
|
||||||
if ((!_volumes_files.ContainsKey(volume)) || (!_volumes_folders.ContainsKey(volume)))
|
get { return records.Count; }
|
||||||
throw new Exception(string.Format("DB not contain the volume: {0}", volume));
|
|
||||||
USNRecord result = null;
|
|
||||||
_volumes_files[volume].TryGetValue(frn, out result);
|
|
||||||
if (result != null) return result;
|
|
||||||
_volumes_folders[volume].TryGetValue(frn, out result);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
public long FileCount
|
|
||||||
|
public Dictionary<ulong, USNRecord> GetAllRecords()
|
||||||
{
|
{
|
||||||
get { return _volumes_files.Sum(x => x.Value.Count); }
|
return records;
|
||||||
}
|
|
||||||
public long FolderCount
|
|
||||||
{
|
|
||||||
get { return _volumes_folders.Sum(x => x.Value.Count); }
|
|
||||||
}
|
|
||||||
public Dictionary<ulong, USNRecord> GetFolderSource(string volume)
|
|
||||||
{
|
|
||||||
Dictionary<ulong, USNRecord> result = null;
|
|
||||||
_volumes_folders.TryGetValue(volume, out result);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using MyEverything;
|
|
||||||
|
|
||||||
namespace Wox.Infrastructure.MFTSearch
|
namespace Wox.Infrastructure.MFTSearch
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,158 +1,158 @@
|
|||||||
using System;
|
//using System;
|
||||||
using System.Collections.Generic;
|
//using System.Collections.Generic;
|
||||||
using System.Linq;
|
//using System.Linq;
|
||||||
using System.Text;
|
//using System.Text;
|
||||||
using System.Runtime.InteropServices;
|
//using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
//using System.Threading;
|
||||||
using System.Diagnostics;
|
//using System.Diagnostics;
|
||||||
using System.IO;
|
//using System.IO;
|
||||||
using Wox.Infrastructure.MFTSearch;
|
//using Wox.Infrastructure.MFTSearch;
|
||||||
|
|
||||||
namespace MyEverything
|
//namespace MyEverything
|
||||||
{
|
//{
|
||||||
internal class VolumeMonitor
|
// internal class VolumeMonitor
|
||||||
{
|
// {
|
||||||
|
|
||||||
public Action<USNRecord> RecordAddedEvent;
|
// public Action<USNRecord> RecordAddedEvent;
|
||||||
public Action<USNRecord> RecordDeletedEvent;
|
// public Action<USNRecord> RecordDeletedEvent;
|
||||||
public Action<USNRecord, USNRecord> RecordRenameEvent;
|
// public Action<USNRecord, USNRecord> RecordRenameEvent;
|
||||||
|
|
||||||
public void Monitor(List<string> volumes, MFTSearcherCache db)
|
// public void Monitor(List<string> volumes, MFTSearcherCache db)
|
||||||
{
|
// {
|
||||||
foreach (var volume in volumes)
|
// foreach (var volume in volumes)
|
||||||
{
|
// {
|
||||||
if (string.IsNullOrEmpty(volume)) throw new InvalidOperationException("Volume cant't be null or empty string.");
|
// if (string.IsNullOrEmpty(volume)) throw new InvalidOperationException("Volume cant't be null or empty string.");
|
||||||
if (!db.ContainsVolume(volume)) throw new InvalidOperationException(string.Format("Volume {0} must be scaned first."));
|
// if (!db.ContainsVolume(volume)) throw new InvalidOperationException(string.Format("Volume {0} must be scaned first."));
|
||||||
Thread th = new Thread(new ParameterizedThreadStart(MonitorThread));
|
// Thread th = new Thread(new ParameterizedThreadStart(MonitorThread));
|
||||||
th.Start(new Dictionary<string, object> { { "Volume", volume }, { "MFTSearcherCache", db } });
|
// th.Start(new Dictionary<string, object> { { "Volume", volume }, { "MFTSearcherCache", db } });
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
private PInvokeWin32.READ_USN_JOURNAL_DATA SetupInputData4JournalRead(string volume, uint reason)
|
// private PInvokeWin32.READ_USN_JOURNAL_DATA SetupInputData4JournalRead(string volume, uint reason)
|
||||||
{
|
// {
|
||||||
IntPtr pMonitorVolume = MFTSearcher.GetVolumeJournalHandle(volume);
|
// IntPtr pMonitorVolume = MFTSearcher.GetVolumeJournalHandle(volume);
|
||||||
uint bytesReturned = 0;
|
// uint bytesReturned = 0;
|
||||||
PInvokeWin32.USN_JOURNAL_DATA ujd = new PInvokeWin32.USN_JOURNAL_DATA();
|
// PInvokeWin32.USN_JOURNAL_DATA ujd = new PInvokeWin32.USN_JOURNAL_DATA();
|
||||||
Wox.Infrastructure.MFTSearch.MFTSearcher.QueryUSNJournal(pMonitorVolume, out ujd, out bytesReturned);
|
// Wox.Infrastructure.MFTSearch.MFTSearcher.QueryUSNJournal(pMonitorVolume, out ujd, out bytesReturned);
|
||||||
|
|
||||||
// 构建输入参数
|
// // 构建输入参数
|
||||||
PInvokeWin32.READ_USN_JOURNAL_DATA rujd = new PInvokeWin32.READ_USN_JOURNAL_DATA();
|
// PInvokeWin32.READ_USN_JOURNAL_DATA rujd = new PInvokeWin32.READ_USN_JOURNAL_DATA();
|
||||||
rujd.StartUsn = ujd.NextUsn;
|
// rujd.StartUsn = ujd.NextUsn;
|
||||||
rujd.ReasonMask = reason;
|
// rujd.ReasonMask = reason;
|
||||||
rujd.ReturnOnlyOnClose = 1;
|
// rujd.ReturnOnlyOnClose = 1;
|
||||||
rujd.Timeout = 0;
|
// rujd.Timeout = 0;
|
||||||
rujd.BytesToWaitFor = 1;
|
// rujd.BytesToWaitFor = 1;
|
||||||
rujd.UsnJournalID = ujd.UsnJournalID;
|
// rujd.UsnJournalID = ujd.UsnJournalID;
|
||||||
|
|
||||||
return rujd;
|
// return rujd;
|
||||||
}
|
// }
|
||||||
private void MonitorThread(object param)
|
// private void MonitorThread(object param)
|
||||||
{
|
// {
|
||||||
|
|
||||||
MFTSearcherCache db = (param as Dictionary<string, object>)["MFTSearcherCache"] as MFTSearcherCache;
|
// MFTSearcherCache db = (param as Dictionary<string, object>)["MFTSearcherCache"] as MFTSearcherCache;
|
||||||
string volume = (param as Dictionary<string, object>)["Volume"] as string;
|
// string volume = (param as Dictionary<string, object>)["Volume"] as string;
|
||||||
IntPtr pbuffer = Marshal.AllocHGlobal(0x1000);
|
// IntPtr pbuffer = Marshal.AllocHGlobal(0x1000);
|
||||||
PInvokeWin32.READ_USN_JOURNAL_DATA rujd = SetupInputData4JournalRead(volume, 0xFFFFFFFF);
|
// PInvokeWin32.READ_USN_JOURNAL_DATA rujd = SetupInputData4JournalRead(volume, 0xFFFFFFFF);
|
||||||
UInt32 cbRead;
|
// UInt32 cbRead;
|
||||||
IntPtr prujd;
|
// IntPtr prujd;
|
||||||
|
|
||||||
while (true)
|
// while (true)
|
||||||
{
|
// {
|
||||||
prujd = Marshal.AllocHGlobal(Marshal.SizeOf(rujd));
|
// prujd = Marshal.AllocHGlobal(Marshal.SizeOf(rujd));
|
||||||
PInvokeWin32.ZeroMemory(prujd, Marshal.SizeOf(rujd));
|
// PInvokeWin32.ZeroMemory(prujd, Marshal.SizeOf(rujd));
|
||||||
Marshal.StructureToPtr(rujd, prujd, true);
|
// Marshal.StructureToPtr(rujd, prujd, true);
|
||||||
|
|
||||||
Debug.WriteLine(string.Format("\nMoniting on {0}......", volume));
|
// Debug.WriteLine(string.Format("\nMoniting on {0}......", volume));
|
||||||
IntPtr pVolume = Wox.Infrastructure.MFTSearch.MFTSearcher.GetVolumeJournalHandle(volume);
|
// IntPtr pVolume = Wox.Infrastructure.MFTSearch.MFTSearcher.GetVolumeJournalHandle(volume);
|
||||||
|
|
||||||
bool fok = PInvokeWin32.DeviceIoControl(pVolume,
|
// bool fok = PInvokeWin32.DeviceIoControl(pVolume,
|
||||||
PInvokeWin32.FSCTL_READ_USN_JOURNAL,
|
// PInvokeWin32.FSCTL_READ_USN_JOURNAL,
|
||||||
prujd, Marshal.SizeOf(typeof(PInvokeWin32.READ_USN_JOURNAL_DATA)),
|
// prujd, Marshal.SizeOf(typeof(PInvokeWin32.READ_USN_JOURNAL_DATA)),
|
||||||
pbuffer, 0x1000, out cbRead, IntPtr.Zero);
|
// pbuffer, 0x1000, out cbRead, IntPtr.Zero);
|
||||||
|
|
||||||
IntPtr pRealData = new IntPtr(pbuffer.ToInt32() + Marshal.SizeOf(typeof(Int64)));
|
// IntPtr pRealData = new IntPtr(pbuffer.ToInt32() + Marshal.SizeOf(typeof(Int64)));
|
||||||
uint offset = 0;
|
// uint offset = 0;
|
||||||
|
|
||||||
if (fok)
|
// if (fok)
|
||||||
{
|
// {
|
||||||
while (offset + Marshal.SizeOf(typeof(Int64)) < cbRead)
|
// while (offset + Marshal.SizeOf(typeof(Int64)) < cbRead)
|
||||||
{
|
// {
|
||||||
PInvokeWin32.USN_RECORD usn = new PInvokeWin32.USN_RECORD(new IntPtr(pRealData.ToInt32() + (int)offset));
|
// PInvokeWin32.USN_RECORD usn = new PInvokeWin32.USN_RECORD(new IntPtr(pRealData.ToInt32() + (int)offset));
|
||||||
ProcessUSN(usn, volume, db);
|
// ProcessUSN(usn, volume, db);
|
||||||
offset += usn.RecordLength;
|
// offset += usn.RecordLength;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
Marshal.FreeHGlobal(prujd);
|
// Marshal.FreeHGlobal(prujd);
|
||||||
rujd.StartUsn = Marshal.ReadInt64(pbuffer);
|
// rujd.StartUsn = Marshal.ReadInt64(pbuffer);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
private void ProcessUSN(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db)
|
// private void ProcessUSN(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db)
|
||||||
{
|
// {
|
||||||
var dbCached = db.FindByFrn(volume, usn.FRN);
|
// var dbCached = db.FindByFrn(volume, usn.FRN);
|
||||||
Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, dbCached, db);
|
// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, dbCached, db);
|
||||||
Debug.WriteLine(string.Format("------USN[frn={0}]------", usn.FRN));
|
// Debug.WriteLine(string.Format("------USN[frn={0}]------", usn.FRN));
|
||||||
Debug.WriteLine(string.Format("FileName={0}, USNChangeReason={1}", usn.FileName, USNChangeReason.ReasonPrettyFormat(usn.Reason)));
|
// Debug.WriteLine(string.Format("FileName={0}, USNChangeReason={1}", usn.FileName, USNChangeReason.ReasonPrettyFormat(usn.Reason)));
|
||||||
Debug.WriteLine(string.Format("FileName[Cached]={0}", dbCached == null ? "NoCache" : dbCached.FullPath));
|
// Debug.WriteLine(string.Format("FileName[Cached]={0}", dbCached == null ? "NoCache" : dbCached.FullPath));
|
||||||
Debug.WriteLine("--------------------------------------");
|
// Debug.WriteLine("--------------------------------------");
|
||||||
|
|
||||||
if (MaskEqual(usn.Reason, USNChangeReason.USN_REASONS["USN_REASON_RENAME_NEW_NAME"]))
|
// if (MaskEqual(usn.Reason, USNChangeReason.USN_REASONS["USN_REASON_RENAME_NEW_NAME"]))
|
||||||
ProcessRenameNewName(usn, volume, db);
|
// ProcessRenameNewName(usn, volume, db);
|
||||||
if ((usn.Reason & USNChangeReason.USN_REASONS["USN_REASON_FILE_CREATE"]) != 0)
|
// if ((usn.Reason & USNChangeReason.USN_REASONS["USN_REASON_FILE_CREATE"]) != 0)
|
||||||
ProcessFileCreate(usn, volume, db);
|
// ProcessFileCreate(usn, volume, db);
|
||||||
if (MaskEqual(usn.Reason, USNChangeReason.USN_REASONS["USN_REASON_FILE_DELETE"]))
|
// if (MaskEqual(usn.Reason, USNChangeReason.USN_REASONS["USN_REASON_FILE_DELETE"]))
|
||||||
ProcessFileDelete(usn, volume, db);
|
// ProcessFileDelete(usn, volume, db);
|
||||||
}
|
// }
|
||||||
private void ProcessFileDelete(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db)
|
// private void ProcessFileDelete(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db)
|
||||||
{
|
// {
|
||||||
var cached = db.FindByFrn(volume, usn.FRN);
|
// var cached = db.FindByFrn(volume, usn.FRN);
|
||||||
if (cached == null)
|
// if (cached == null)
|
||||||
{
|
// {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
else
|
// else
|
||||||
{
|
// {
|
||||||
Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, cached, db);
|
// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, cached, db);
|
||||||
var deleteok = db.DeleteRecord(volume, usn.FRN);
|
// var deleteok = db.DeleteRecord(volume, usn.FRN);
|
||||||
Debug.WriteLine(string.Format(">>>> File {0} deleted {1}.", cached.FullPath, deleteok ? "successful" : "fail"));
|
// Debug.WriteLine(string.Format(">>>> File {0} deleted {1}.", cached.FullPath, deleteok ? "successful" : "fail"));
|
||||||
if (RecordDeletedEvent != null)
|
// if (RecordDeletedEvent != null)
|
||||||
RecordDeletedEvent(cached);
|
// RecordDeletedEvent(cached);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
private void ProcessRenameNewName(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db)
|
// private void ProcessRenameNewName(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db)
|
||||||
{
|
// {
|
||||||
USNRecord newRecord = USNRecord.ParseUSN(volume, usn);
|
// USNRecord newRecord = USNRecord.ParseUSN(volume, usn);
|
||||||
//string fullpath = newRecord.Name;
|
// //string fullpath = newRecord.Name;
|
||||||
//db.FindRecordPath(newRecord, ref fullpath, db.GetFolderSource(volume));
|
// //db.FindRecordPath(newRecord, ref fullpath, db.GetFolderSource(volume));
|
||||||
//newRecord.FullPath = fullpath;
|
// //newRecord.FullPath = fullpath;
|
||||||
var oldRecord = db.FindByFrn(volume, usn.FRN);
|
// var oldRecord = db.FindByFrn(volume, usn.FRN);
|
||||||
Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, oldRecord, db);
|
// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, oldRecord, db);
|
||||||
Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, newRecord, db);
|
// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, newRecord, db);
|
||||||
Debug.WriteLine(string.Format(">>>> RenameFile {0} to {1}", oldRecord.FullPath, newRecord.FullPath));
|
// Debug.WriteLine(string.Format(">>>> RenameFile {0} to {1}", oldRecord.FullPath, newRecord.FullPath));
|
||||||
db.UpdateRecord(volume, newRecord,
|
// db.UpdateRecord(volume, newRecord,
|
||||||
usn.IsFolder ? USNRecordType.Folder : USNRecordType.File);
|
// usn.IsFolder ? USNRecordType.Folder : USNRecordType.File);
|
||||||
if (RecordRenameEvent != null) RecordRenameEvent(oldRecord, newRecord);
|
// if (RecordRenameEvent != null) RecordRenameEvent(oldRecord, newRecord);
|
||||||
if (newRecord.FullPath.Contains("$RECYCLE.BIN"))
|
// if (newRecord.FullPath.Contains("$RECYCLE.BIN"))
|
||||||
{
|
// {
|
||||||
Debug.WriteLine(string.Format(">>>> Means {0} moved to recycle.", oldRecord.FullPath));
|
// Debug.WriteLine(string.Format(">>>> Means {0} moved to recycle.", oldRecord.FullPath));
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
private void ProcessFileCreate(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db)
|
// private void ProcessFileCreate(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db)
|
||||||
{
|
// {
|
||||||
USNRecord record = USNRecord.ParseUSN(volume, usn);
|
// USNRecord record = USNRecord.ParseUSN(volume, usn);
|
||||||
//string fullpath = record.Name;
|
// //string fullpath = record.Name;
|
||||||
//db.FindRecordPath(record, ref fullpath, db.GetFolderSource(volume));
|
// //db.FindRecordPath(record, ref fullpath, db.GetFolderSource(volume));
|
||||||
//record.FullPath = fullpath;
|
// //record.FullPath = fullpath;
|
||||||
db.AddRecord(volume, record, usn.IsFolder ? USNRecordType.Folder : USNRecordType.File);
|
// db.AddRecord(volume, record, usn.IsFolder ? USNRecordType.Folder : USNRecordType.File);
|
||||||
Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, record, db);
|
// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, record, db);
|
||||||
Debug.WriteLine(string.Format(">>>> NewFile: {0}", record.FullPath));
|
// Debug.WriteLine(string.Format(">>>> NewFile: {0}", record.FullPath));
|
||||||
if (RecordAddedEvent != null)
|
// if (RecordAddedEvent != null)
|
||||||
RecordAddedEvent(record);
|
// RecordAddedEvent(record);
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
private bool MaskEqual(uint target, uint compare)
|
// private bool MaskEqual(uint target, uint compare)
|
||||||
{
|
// {
|
||||||
return (target & compare) != 0;
|
// return (target & compare) != 0;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|||||||
@@ -3,71 +3,78 @@ using System.Collections;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Wox.Plugin {
|
namespace Wox.Plugin
|
||||||
|
{
|
||||||
|
|
||||||
public class Result {
|
public class Result
|
||||||
public string Title { get; set; }
|
{
|
||||||
public string SubTitle { get; set; }
|
|
||||||
public string IcoPath { get; set; }
|
|
||||||
|
|
||||||
public string FullIcoPath
|
public string Title { get; set; }
|
||||||
{
|
public string SubTitle { get; set; }
|
||||||
get
|
public string IcoPath { get; set; }
|
||||||
{
|
|
||||||
|
public string FullIcoPath
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
if (string.IsNullOrEmpty(IcoPath)) return string.Empty;
|
if (string.IsNullOrEmpty(IcoPath)) return string.Empty;
|
||||||
if (IcoPath.StartsWith("data:"))
|
if (IcoPath.StartsWith("data:"))
|
||||||
{
|
{
|
||||||
return IcoPath;
|
return IcoPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Path.Combine(PluginDirectory, IcoPath);
|
return Path.Combine(PluginDirectory, IcoPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// return true to hide wox after select result
|
/// return true to hide wox after select result
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Func<ActionContext, bool> Action { get; set; }
|
public Func<ActionContext, bool> Action { get; set; }
|
||||||
public int Score { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
public int Score { get; set; }
|
||||||
/// Auto add scores for MRU items
|
|
||||||
/// </summary>
|
|
||||||
public bool AutoAjustScore { get; set; }
|
|
||||||
|
|
||||||
//todo: this should be controlled by system, not visible to users
|
/// <summary>
|
||||||
/// <summary>
|
/// Auto add scores for MRU items
|
||||||
/// Only resulsts that originQuery match with curren query will be displayed in the panel
|
/// </summary>
|
||||||
/// </summary>
|
public bool AutoAjustScore { get; set; }
|
||||||
public Query OriginQuery { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
//todo: this should be controlled by system, not visible to users
|
||||||
/// Don't set this property if you are developing a plugin
|
/// <summary>
|
||||||
/// </summary>
|
/// Only resulsts that originQuery match with curren query will be displayed in the panel
|
||||||
public string PluginDirectory { get; set; }
|
/// </summary>
|
||||||
|
public Query OriginQuery { get; set; }
|
||||||
|
|
||||||
public new bool Equals(object obj) {
|
/// <summary>
|
||||||
if (obj == null || !(obj is Result)) return false;
|
/// Don't set this property if you are developing a plugin
|
||||||
|
/// </summary>
|
||||||
|
public string PluginDirectory { get; set; }
|
||||||
|
|
||||||
Result r = (Result)obj;
|
public new bool Equals(object obj)
|
||||||
return r.Title == Title && r.SubTitle == SubTitle;
|
{
|
||||||
}
|
if (obj == null || !(obj is Result)) return false;
|
||||||
|
|
||||||
|
Result r = (Result)obj;
|
||||||
|
return r.Title == Title && r.SubTitle == SubTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Title + SubTitle;
|
||||||
|
}
|
||||||
|
|
||||||
public override string ToString() {
|
public Result()
|
||||||
return Title + SubTitle;
|
{
|
||||||
}
|
|
||||||
|
|
||||||
public Result() {
|
}
|
||||||
|
|
||||||
}
|
public Result(string Title = null, string IcoPath = null, string SubTitle = null)
|
||||||
|
{
|
||||||
|
this.Title = Title;
|
||||||
|
this.IcoPath = IcoPath;
|
||||||
|
this.SubTitle = SubTitle;
|
||||||
|
}
|
||||||
|
|
||||||
public Result(string Title = null, string IcoPath = null, string SubTitle = null) {
|
public List<Result> ContextMenu { get; set; }
|
||||||
this.Title = Title;
|
}
|
||||||
this.IcoPath = IcoPath;
|
|
||||||
this.SubTitle = SubTitle;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,7 @@ namespace Wox.Test
|
|||||||
var searchtimestart = DateTime.Now;
|
var searchtimestart = DateTime.Now;
|
||||||
MFTSearcher.IndexAllVolumes();
|
MFTSearcher.IndexAllVolumes();
|
||||||
var searchtimeend = DateTime.Now;
|
var searchtimeend = DateTime.Now;
|
||||||
Console.WriteLine(string.Format("{0} file indexed, {1}ms has spent.", MFTSearcher.IndexedFileCount, searchtimeend.Subtract(searchtimestart).TotalMilliseconds));
|
Console.WriteLine(string.Format("{0} file indexed, {1}ms has spent.", MFTSearcher.IndexedRecordsCount, searchtimeend.Subtract(searchtimestart).TotalMilliseconds));
|
||||||
|
|
||||||
searchtimestart = DateTime.Now;
|
searchtimestart = DateTime.Now;
|
||||||
List<MFTSearchRecord> mftSearchRecords = MFTSearcher.Search("q");
|
List<MFTSearchRecord> mftSearchRecords = MFTSearcher.Search("q");
|
||||||
@@ -28,5 +28,19 @@ namespace Wox.Test
|
|||||||
searchtimeend = DateTime.Now;
|
searchtimeend = DateTime.Now;
|
||||||
Console.WriteLine(string.Format("{0} file searched, {1}ms has spent.", mftSearchRecords.Count, searchtimeend.Subtract(searchtimestart).TotalMilliseconds));
|
Console.WriteLine(string.Format("{0} file searched, {1}ms has spent.", mftSearchRecords.Count, searchtimeend.Subtract(searchtimestart).TotalMilliseconds));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void MemoryTest()
|
||||||
|
{
|
||||||
|
long oldWorkingSet = System.Diagnostics.Process.GetCurrentProcess().WorkingSet64;
|
||||||
|
MFTSearcher.IndexAllVolumes();
|
||||||
|
long newWorkingSet = System.Diagnostics.Process.GetCurrentProcess().WorkingSet64;
|
||||||
|
Console.WriteLine(string.Format("Index: {0}M", (newWorkingSet - oldWorkingSet)/(1024*1024)));
|
||||||
|
|
||||||
|
oldWorkingSet = System.Diagnostics.Process.GetCurrentProcess().WorkingSet64;
|
||||||
|
MFTSearcher.Search("q");
|
||||||
|
newWorkingSet = System.Diagnostics.Process.GetCurrentProcess().WorkingSet64;
|
||||||
|
Console.WriteLine(string.Format("Search: {0}M", (newWorkingSet - oldWorkingSet) / (1024 * 1024)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,16 +17,17 @@ namespace Wox.Commands
|
|||||||
|
|
||||||
public override void Dispatch(Query query)
|
public override void Dispatch(Query query)
|
||||||
{
|
{
|
||||||
|
var queryPlugins = allSytemPlugins;
|
||||||
if (UserSettingStorage.Instance.WebSearches.Exists(o => o.ActionWord == query.ActionName && o.Enabled))
|
if (UserSettingStorage.Instance.WebSearches.Exists(o => o.ActionWord == query.ActionName && o.Enabled))
|
||||||
{
|
{
|
||||||
//websearch mode
|
//websearch mode
|
||||||
allSytemPlugins = new List<PluginPair>()
|
queryPlugins = new List<PluginPair>()
|
||||||
{
|
{
|
||||||
allSytemPlugins.First(o => ((ISystemPlugin)o.Plugin).ID == "565B73353DBF4806919830B9202EE3BF")
|
allSytemPlugins.First(o => ((ISystemPlugin)o.Plugin).ID == "565B73353DBF4806919830B9202EE3BF")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (PluginPair pair in allSytemPlugins)
|
foreach (PluginPair pair in queryPlugins)
|
||||||
{
|
{
|
||||||
PluginPair pair1 = pair;
|
PluginPair pair1 = pair;
|
||||||
ThreadPool.QueueUserWorkItem(state =>
|
ThreadPool.QueueUserWorkItem(state =>
|
||||||
|
|||||||
@@ -22,7 +22,8 @@
|
|||||||
<StackPanel Orientation="Vertical">
|
<StackPanel Orientation="Vertical">
|
||||||
<TextBox Style="{DynamicResource QueryBoxStyle}" PreviewDragOver="TbQuery_OnPreviewDragOver" AllowDrop="True" Grid.Row="0" x:Name="tbQuery" PreviewKeyDown="TbQuery_OnPreviewKeyDown" TextChanged="TextBoxBase_OnTextChanged" />
|
<TextBox Style="{DynamicResource QueryBoxStyle}" PreviewDragOver="TbQuery_OnPreviewDragOver" AllowDrop="True" Grid.Row="0" x:Name="tbQuery" PreviewKeyDown="TbQuery_OnPreviewKeyDown" TextChanged="TextBoxBase_OnTextChanged" />
|
||||||
<Line Style="{DynamicResource PendingLineStyle}" x:Name="progressBar" Y1="0" Y2="0" X2="100" Grid.Row="1" Height="2" StrokeThickness="1"></Line>
|
<Line Style="{DynamicResource PendingLineStyle}" x:Name="progressBar" Y1="0" Y2="0" X2="100" Grid.Row="1" Height="2" StrokeThickness="1"></Line>
|
||||||
<wox:ResultPanel x:Name="resultCtrl" />
|
<wox:ResultPanel x:Name="pnlResult" />
|
||||||
|
<wox:ResultPanel x:Name="pnlContextMenu" Visibility="Collapsed" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
</Window>
|
</Window>
|
||||||
@@ -141,6 +141,13 @@ namespace Wox
|
|||||||
results.ForEach(o =>
|
results.ForEach(o =>
|
||||||
{
|
{
|
||||||
o.PluginDirectory = plugin.PluginDirectory;
|
o.PluginDirectory = plugin.PluginDirectory;
|
||||||
|
if (o.ContextMenu != null)
|
||||||
|
{
|
||||||
|
o.ContextMenu.ForEach(t =>
|
||||||
|
{
|
||||||
|
t.PluginDirectory = plugin.PluginDirectory;
|
||||||
|
});
|
||||||
|
}
|
||||||
o.OriginQuery = query;
|
o.OriginQuery = query;
|
||||||
});
|
});
|
||||||
OnUpdateResultView(results);
|
OnUpdateResultView(results);
|
||||||
@@ -148,7 +155,6 @@ namespace Wox
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@@ -160,7 +166,9 @@ namespace Wox
|
|||||||
|
|
||||||
progressBar.ToolTip = toolTip;
|
progressBar.ToolTip = toolTip;
|
||||||
InitialTray();
|
InitialTray();
|
||||||
resultCtrl.OnMouseClickItem += AcceptSelect;
|
pnlResult.LeftMouseClickEvent += SelectResult;
|
||||||
|
pnlContextMenu.LeftMouseClickEvent += SelectResult;
|
||||||
|
pnlResult.RightMouseClickEvent += pnlResult_RightMouseClickEvent;
|
||||||
|
|
||||||
ThreadPool.SetMaxThreads(30, 10);
|
ThreadPool.SetMaxThreads(30, 10);
|
||||||
try
|
try
|
||||||
@@ -180,6 +188,11 @@ namespace Wox
|
|||||||
this.Closing += MainWindow_Closing;
|
this.Closing += MainWindow_Closing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pnlResult_RightMouseClickEvent(Result result)
|
||||||
|
{
|
||||||
|
ShowContextMenu(result);
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
||||||
{
|
{
|
||||||
UserSettingStorage.Instance.WindowLeft = Left;
|
UserSettingStorage.Instance.WindowLeft = Left;
|
||||||
@@ -300,21 +313,22 @@ namespace Wox
|
|||||||
|
|
||||||
lastQuery = tbQuery.Text;
|
lastQuery = tbQuery.Text;
|
||||||
toolTip.IsOpen = false;
|
toolTip.IsOpen = false;
|
||||||
resultCtrl.Dirty = true;
|
pnlResult.Dirty = true;
|
||||||
Dispatcher.DelayInvoke("UpdateSearch",
|
Dispatcher.DelayInvoke("UpdateSearch",
|
||||||
o =>
|
o =>
|
||||||
{
|
{
|
||||||
Dispatcher.DelayInvoke("ClearResults", i =>
|
Dispatcher.DelayInvoke("ClearResults", i =>
|
||||||
{
|
{
|
||||||
// first try to use clear method inside resultCtrl, which is more closer to the add new results
|
// first try to use clear method inside pnlResult, which is more closer to the add new results
|
||||||
// and this will not bring splash issues.After waiting 30ms, if there still no results added, we
|
// and this will not bring splash issues.After waiting 30ms, if there still no results added, we
|
||||||
// must clear the result. otherwise, it will be confused why the query changed, but the results
|
// must clear the result. otherwise, it will be confused why the query changed, but the results
|
||||||
// didn't.
|
// didn't.
|
||||||
if (resultCtrl.Dirty) resultCtrl.Clear();
|
if (pnlResult.Dirty) pnlResult.Clear();
|
||||||
}, TimeSpan.FromMilliseconds(100), null);
|
}, TimeSpan.FromMilliseconds(100), null);
|
||||||
queryHasReturn = false;
|
queryHasReturn = false;
|
||||||
var q = new Query(lastQuery);
|
var q = new Query(lastQuery);
|
||||||
CommandFactory.DispatchCommand(q);
|
CommandFactory.DispatchCommand(q);
|
||||||
|
BackToResultMode();
|
||||||
if (Plugins.HitThirdpartyKeyword(q))
|
if (Plugins.HitThirdpartyKeyword(q))
|
||||||
{
|
{
|
||||||
Dispatcher.DelayInvoke("ShowProgressbar", originQuery =>
|
Dispatcher.DelayInvoke("ShowProgressbar", originQuery =>
|
||||||
@@ -328,6 +342,12 @@ namespace Wox
|
|||||||
}, TimeSpan.FromMilliseconds(ShouldNotDelayQuery ? 0 : 150));
|
}, TimeSpan.FromMilliseconds(ShouldNotDelayQuery ? 0 : 150));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void BackToResultMode()
|
||||||
|
{
|
||||||
|
pnlResult.Visibility = Visibility.Visible;
|
||||||
|
pnlContextMenu.Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
|
||||||
private bool ShouldNotDelayQuery
|
private bool ShouldNotDelayQuery
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -463,7 +483,7 @@ namespace Wox
|
|||||||
ShowWox(false);
|
ShowWox(false);
|
||||||
if (!tbQuery.Text.StartsWith(">"))
|
if (!tbQuery.Text.StartsWith(">"))
|
||||||
{
|
{
|
||||||
resultCtrl.Clear();
|
pnlResult.Clear();
|
||||||
ChangeQuery(">");
|
ChangeQuery(">");
|
||||||
}
|
}
|
||||||
tbQuery.CaretIndex = tbQuery.Text.Length;
|
tbQuery.CaretIndex = tbQuery.Text.Length;
|
||||||
@@ -473,7 +493,7 @@ namespace Wox
|
|||||||
|
|
||||||
private void updateCmdMode()
|
private void updateCmdMode()
|
||||||
{
|
{
|
||||||
var currentSelectedItem = resultCtrl.GetActiveResult();
|
var currentSelectedItem = pnlResult.GetActiveResult();
|
||||||
if (currentSelectedItem != null)
|
if (currentSelectedItem != null)
|
||||||
{
|
{
|
||||||
ignoreTextChange = true;
|
ignoreTextChange = true;
|
||||||
@@ -489,7 +509,14 @@ namespace Wox
|
|||||||
switch (key)
|
switch (key)
|
||||||
{
|
{
|
||||||
case Key.Escape:
|
case Key.Escape:
|
||||||
HideWox();
|
if (IsInContextMenuMode)
|
||||||
|
{
|
||||||
|
BackToResultMode();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HideWox();
|
||||||
|
}
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -516,14 +543,14 @@ namespace Wox
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Key.PageDown:
|
case Key.PageDown:
|
||||||
resultCtrl.SelectNextPage();
|
pnlResult.SelectNextPage();
|
||||||
if (IsCMDMode) updateCmdMode();
|
if (IsCMDMode) updateCmdMode();
|
||||||
toolTip.IsOpen = false;
|
toolTip.IsOpen = false;
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Key.PageUp:
|
case Key.PageUp:
|
||||||
resultCtrl.SelectPrevPage();
|
pnlResult.SelectPrevPage();
|
||||||
if (IsCMDMode) updateCmdMode();
|
if (IsCMDMode) updateCmdMode();
|
||||||
toolTip.IsOpen = false;
|
toolTip.IsOpen = false;
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
@@ -545,29 +572,68 @@ namespace Wox
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Key.Enter:
|
case Key.Enter:
|
||||||
AcceptSelect(resultCtrl.GetActiveResult());
|
Result activeResult = GetActiveResult();
|
||||||
|
if (globalHotkey.CheckModifiers().ShiftPressed)
|
||||||
|
{
|
||||||
|
ShowContextMenu(activeResult);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SelectResult(activeResult);
|
||||||
|
}
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsInContextMenuMode
|
||||||
|
{
|
||||||
|
get { return pnlContextMenu.Visibility == Visibility.Visible; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result GetActiveResult()
|
||||||
|
{
|
||||||
|
if (IsInContextMenuMode)
|
||||||
|
{
|
||||||
|
return pnlContextMenu.GetActiveResult();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return pnlResult.GetActiveResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void SelectPrevItem()
|
private void SelectPrevItem()
|
||||||
{
|
{
|
||||||
resultCtrl.SelectPrev();
|
if (IsInContextMenuMode)
|
||||||
if (IsCMDMode) updateCmdMode();
|
{
|
||||||
|
pnlContextMenu.SelectPrev();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pnlResult.SelectPrev();
|
||||||
|
if (IsCMDMode) updateCmdMode();
|
||||||
|
}
|
||||||
toolTip.IsOpen = false;
|
toolTip.IsOpen = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SelectNextItem()
|
private void SelectNextItem()
|
||||||
{
|
{
|
||||||
resultCtrl.SelectNext();
|
if (IsInContextMenuMode)
|
||||||
if (IsCMDMode) updateCmdMode();
|
{
|
||||||
|
pnlContextMenu.SelectNext();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pnlResult.SelectNext();
|
||||||
|
if (IsCMDMode) updateCmdMode();
|
||||||
|
}
|
||||||
toolTip.IsOpen = false;
|
toolTip.IsOpen = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AcceptSelect(Result result)
|
private void SelectResult(Result result)
|
||||||
{
|
{
|
||||||
if (!resultCtrl.Dirty && result != null)
|
if (result != null)
|
||||||
{
|
{
|
||||||
if (result.Action != null)
|
if (result.Action != null)
|
||||||
{
|
{
|
||||||
@@ -599,7 +665,20 @@ namespace Wox
|
|||||||
if (o.AutoAjustScore) o.Score += UserSelectedRecordStorage.Instance.GetSelectedCount(o);
|
if (o.AutoAjustScore) o.Score += UserSelectedRecordStorage.Instance.GetSelectedCount(o);
|
||||||
});
|
});
|
||||||
List<Result> l = list.Where(o => o.OriginQuery != null && o.OriginQuery.RawQuery == lastQuery).ToList();
|
List<Result> l = list.Where(o => o.OriginQuery != null && o.OriginQuery.RawQuery == lastQuery).ToList();
|
||||||
Dispatcher.Invoke(new Action(() => resultCtrl.AddResults(l)));
|
Dispatcher.Invoke(new Action(() =>
|
||||||
|
pnlResult.AddResults(l))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowContextMenu(Result result)
|
||||||
|
{
|
||||||
|
if (result.ContextMenu != null && result.ContextMenu.Count > 0)
|
||||||
|
{
|
||||||
|
pnlContextMenu.Clear();
|
||||||
|
pnlContextMenu.AddResults(result.ContextMenu);
|
||||||
|
pnlContextMenu.Visibility = Visibility.Visible;
|
||||||
|
pnlResult.Visibility = Visibility.Collapsed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<!-- a result item height is 50 including margin -->
|
<!-- a result item height is 50 including margin -->
|
||||||
<Grid HorizontalAlignment="Stretch" Height="40" VerticalAlignment="Stretch" Margin="5" Cursor="Hand">
|
<Grid HorizontalAlignment="Stretch" Height="40" VerticalAlignment="Stretch" Margin="5" Cursor="Hand">
|
||||||
<Grid.Resources>
|
<Grid.Resources>
|
||||||
<converters:ImagePathConverter x:Key="ImageConverter" />
|
<converters:ImagePathConverter x:Key="ImageConverter" />
|
||||||
</Grid.Resources>
|
</Grid.Resources>
|
||||||
|
|||||||
@@ -14,11 +14,18 @@ namespace Wox
|
|||||||
{
|
{
|
||||||
public partial class ResultPanel : UserControl
|
public partial class ResultPanel : UserControl
|
||||||
{
|
{
|
||||||
public event Action<Result> OnMouseClickItem;
|
public event Action<Result> LeftMouseClickEvent;
|
||||||
|
public event Action<Result> RightMouseClickEvent;
|
||||||
|
|
||||||
protected virtual void OnOnMouseClickItem(Result result)
|
protected virtual void OnRightMouseClick(Result result)
|
||||||
{
|
{
|
||||||
Action<Result> handler = OnMouseClickItem;
|
Action<Result> handler = RightMouseClickEvent;
|
||||||
|
if (handler != null) handler(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnLeftMouseClick(Result result)
|
||||||
|
{
|
||||||
|
Action<Result> handler = LeftMouseClickEvent;
|
||||||
if (handler != null) handler(result);
|
if (handler != null) handler(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,9 +140,13 @@ namespace Wox
|
|||||||
private void LbResults_OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
|
private void LbResults_OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
var item = ItemsControl.ContainerFromElement(lbResults, e.OriginalSource as DependencyObject) as ListBoxItem;
|
var item = ItemsControl.ContainerFromElement(lbResults, e.OriginalSource as DependencyObject) as ListBoxItem;
|
||||||
if (item != null)
|
if (item != null && e.ChangedButton == MouseButton.Left)
|
||||||
{
|
{
|
||||||
OnOnMouseClickItem(item.DataContext as Result);
|
OnLeftMouseClick(item.DataContext as Result);
|
||||||
|
}
|
||||||
|
if (item != null && e.ChangedButton == MouseButton.Right)
|
||||||
|
{
|
||||||
|
OnRightMouseClick(item.DataContext as Result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user