diff --git a/Plugins/Wox.Plugin.FindFile/Images/edit.png b/Plugins/Wox.Plugin.FindFile/Images/edit.png new file mode 100644 index 0000000000..f1710b7c89 Binary files /dev/null and b/Plugins/Wox.Plugin.FindFile/Images/edit.png differ diff --git a/Plugins/Wox.Plugin.FindFile/Main.cs b/Plugins/Wox.Plugin.FindFile/Main.cs index a3839ec627..5cad15015b 100644 --- a/Plugins/Wox.Plugin.FindFile/Main.cs +++ b/Plugins/Wox.Plugin.FindFile/Main.cs @@ -36,7 +36,7 @@ namespace Wox.Plugin.FindFile MFTSearcher.IndexAllVolumes(); initial = true; 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) @@ -67,8 +67,57 @@ namespace Wox.Plugin.FindFile return false; } return true; - } + }, + ContextMenu = GetContextMenu(record) }; } + + private List GetContextMenu(MFTSearchRecord record) + { + List contextMenus = new List(); + + 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; + } } } diff --git a/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj b/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj index d16a7a5783..707e2744f4 100644 --- a/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj +++ b/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj @@ -54,7 +54,12 @@ - + + Always + + + Always + Always diff --git a/Wox.Infrastructure/MFTSearch/MFTSearcher.cs b/Wox.Infrastructure/MFTSearch/MFTSearcher.cs index 317468e885..7d4b603e86 100644 --- a/Wox.Infrastructure/MFTSearch/MFTSearcher.cs +++ b/Wox.Infrastructure/MFTSearch/MFTSearcher.cs @@ -9,7 +9,6 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.InteropServices; -using MyEverything; namespace Wox.Infrastructure.MFTSearch { @@ -23,8 +22,8 @@ namespace Wox.Infrastructure.MFTSearch List files; List folders; EnumerateVolume(volume, out files, out folders); - cache.AddRecord(volume, files, USNRecordType.File); - cache.AddRecord(volume, folders, USNRecordType.Folder); + //cache.AddRecord(files); + //cache.AddRecord(folders); } public static void IndexAllVolumes() @@ -35,13 +34,9 @@ namespace Wox.Infrastructure.MFTSearch } } - public static long IndexedFileCount + public static long IndexedRecordsCount { - get { return cache.FileCount; } - } - public static long IndexedFolderCount - { - get { return cache.FolderCount; } + get { return cache.RecordsCount; } } public static List Search(string item) @@ -49,7 +44,7 @@ namespace Wox.Infrastructure.MFTSearch if (string.IsNullOrEmpty(item)) return new List(); List 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)); } @@ -255,14 +250,16 @@ namespace Wox.Infrastructure.MFTSearch } 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; - var fdSource = db.GetFolderSource(volume); + var fdSource = db.GetAllRecords(); string fullpath = record.Name; FindRecordPath(record, ref fullpath, fdSource); record.FullPath = fullpath; } + private static void FindRecordPath(USNRecord curRecord, ref string fullpath, Dictionary fdSource) { if (curRecord.IsVolumeRoot) return; diff --git a/Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs b/Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs index 87c04aedde..1ea9335a6e 100644 --- a/Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs +++ b/Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs @@ -1,133 +1,60 @@ using System; using System.Collections.Generic; using System.Linq; -using MyEverything; namespace Wox.Infrastructure.MFTSearch { internal class MFTSearcherCache { - private Dictionary> _volumes_files = new Dictionary>(); - private Dictionary> _volumes_folders = new Dictionary>(); + private Dictionary records = new Dictionary(100000); + private Lookup recordsLookup; public MFTSearcherCache() { } - public bool ContainsVolume(string volume) + public void AddRecord(List record) { - return _volumes_files.ContainsKey(volume) && _volumes_folders.ContainsKey(volume); + record.ForEach(AddRecord); } - public void AddRecord(string volume, List 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); - r.ForEach(x => _volumes_files[volume].Add(x.FRN, x)); - } - 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> hashtable, string key) - { - if (!hashtable.ContainsKey(key)) - hashtable.Add(key, new Dictionary()); - } - 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> 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> source, USNRecord record) - { - if (source.ContainsKey(volume) && source[volume].ContainsKey(record.FRN)) - { - source[volume][record.FRN] = record; - return true; - } - else - { - return false; + firstOrDefault.Name = record.Name; + firstOrDefault.FullPath = record.FullPath; + firstOrDefault.VolumeName = record.VolumeName; } } + + public List FindByName(string filename) { filename = filename.ToLower(); - var fileQuery = from filesInVolumeDic in _volumes_files.Values - from eachFilePair in filesInVolumeDic - where eachFilePair.Value.Name.ToLower().Contains(filename) - select eachFilePair.Value; - - var folderQuery = from fldsInVolumeDic in _volumes_folders.Values - from eachFldPair in fldsInVolumeDic - where eachFldPair.Value.Name.ToLower().Contains(filename) - select eachFldPair.Value; - - List result = new List(); - - result.AddRange(fileQuery); - result.AddRange(folderQuery); - - return result; + var query = from file in records.Values + where file.Name.ToLower().Contains(filename) + select file; + return query.ToList(); } - public USNRecord FindByFrn(string volume, ulong frn) + + public long RecordsCount { - if ((!_volumes_files.ContainsKey(volume)) || (!_volumes_folders.ContainsKey(volume))) - 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; + get { return records.Count; } } - public long FileCount + + public Dictionary GetAllRecords() { - get { return _volumes_files.Sum(x => x.Value.Count); } - } - public long FolderCount - { - get { return _volumes_folders.Sum(x => x.Value.Count); } - } - public Dictionary GetFolderSource(string volume) - { - Dictionary result = null; - _volumes_folders.TryGetValue(volume, out result); - return result; + return records; } } } diff --git a/Wox.Infrastructure/MFTSearch/USNRecord.cs b/Wox.Infrastructure/MFTSearch/USNRecord.cs index 64c0ee05e7..fe9e85ab30 100644 --- a/Wox.Infrastructure/MFTSearch/USNRecord.cs +++ b/Wox.Infrastructure/MFTSearch/USNRecord.cs @@ -1,5 +1,4 @@ using System; -using MyEverything; namespace Wox.Infrastructure.MFTSearch { diff --git a/Wox.Infrastructure/MFTSearch/VolumeMonitor.cs b/Wox.Infrastructure/MFTSearch/VolumeMonitor.cs index c65cf866d9..772c307b9e 100644 --- a/Wox.Infrastructure/MFTSearch/VolumeMonitor.cs +++ b/Wox.Infrastructure/MFTSearch/VolumeMonitor.cs @@ -1,158 +1,158 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Runtime.InteropServices; -using System.Threading; -using System.Diagnostics; -using System.IO; -using Wox.Infrastructure.MFTSearch; +//using System; +//using System.Collections.Generic; +//using System.Linq; +//using System.Text; +//using System.Runtime.InteropServices; +//using System.Threading; +//using System.Diagnostics; +//using System.IO; +//using Wox.Infrastructure.MFTSearch; -namespace MyEverything -{ - internal class VolumeMonitor - { +//namespace MyEverything +//{ +// internal class VolumeMonitor +// { - public Action RecordAddedEvent; - public Action RecordDeletedEvent; - public Action RecordRenameEvent; +// public Action RecordAddedEvent; +// public Action RecordDeletedEvent; +// public Action RecordRenameEvent; - public void Monitor(List volumes, MFTSearcherCache db) - { - foreach (var volume in volumes) - { - 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.")); - Thread th = new Thread(new ParameterizedThreadStart(MonitorThread)); - th.Start(new Dictionary { { "Volume", volume }, { "MFTSearcherCache", db } }); - } - } - private PInvokeWin32.READ_USN_JOURNAL_DATA SetupInputData4JournalRead(string volume, uint reason) - { - IntPtr pMonitorVolume = MFTSearcher.GetVolumeJournalHandle(volume); - uint bytesReturned = 0; - PInvokeWin32.USN_JOURNAL_DATA ujd = new PInvokeWin32.USN_JOURNAL_DATA(); - Wox.Infrastructure.MFTSearch.MFTSearcher.QueryUSNJournal(pMonitorVolume, out ujd, out bytesReturned); +// public void Monitor(List volumes, MFTSearcherCache db) +// { +// foreach (var volume in volumes) +// { +// 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.")); +// Thread th = new Thread(new ParameterizedThreadStart(MonitorThread)); +// th.Start(new Dictionary { { "Volume", volume }, { "MFTSearcherCache", db } }); +// } +// } +// private PInvokeWin32.READ_USN_JOURNAL_DATA SetupInputData4JournalRead(string volume, uint reason) +// { +// IntPtr pMonitorVolume = MFTSearcher.GetVolumeJournalHandle(volume); +// uint bytesReturned = 0; +// PInvokeWin32.USN_JOURNAL_DATA ujd = new PInvokeWin32.USN_JOURNAL_DATA(); +// Wox.Infrastructure.MFTSearch.MFTSearcher.QueryUSNJournal(pMonitorVolume, out ujd, out bytesReturned); - // 构建输入参数 - PInvokeWin32.READ_USN_JOURNAL_DATA rujd = new PInvokeWin32.READ_USN_JOURNAL_DATA(); - rujd.StartUsn = ujd.NextUsn; - rujd.ReasonMask = reason; - rujd.ReturnOnlyOnClose = 1; - rujd.Timeout = 0; - rujd.BytesToWaitFor = 1; - rujd.UsnJournalID = ujd.UsnJournalID; +// // 构建输入参数 +// PInvokeWin32.READ_USN_JOURNAL_DATA rujd = new PInvokeWin32.READ_USN_JOURNAL_DATA(); +// rujd.StartUsn = ujd.NextUsn; +// rujd.ReasonMask = reason; +// rujd.ReturnOnlyOnClose = 1; +// rujd.Timeout = 0; +// rujd.BytesToWaitFor = 1; +// rujd.UsnJournalID = ujd.UsnJournalID; - return rujd; - } - private void MonitorThread(object param) - { +// return rujd; +// } +// private void MonitorThread(object param) +// { - MFTSearcherCache db = (param as Dictionary)["MFTSearcherCache"] as MFTSearcherCache; - string volume = (param as Dictionary)["Volume"] as string; - IntPtr pbuffer = Marshal.AllocHGlobal(0x1000); - PInvokeWin32.READ_USN_JOURNAL_DATA rujd = SetupInputData4JournalRead(volume, 0xFFFFFFFF); - UInt32 cbRead; - IntPtr prujd; +// MFTSearcherCache db = (param as Dictionary)["MFTSearcherCache"] as MFTSearcherCache; +// string volume = (param as Dictionary)["Volume"] as string; +// IntPtr pbuffer = Marshal.AllocHGlobal(0x1000); +// PInvokeWin32.READ_USN_JOURNAL_DATA rujd = SetupInputData4JournalRead(volume, 0xFFFFFFFF); +// UInt32 cbRead; +// IntPtr prujd; - while (true) - { - prujd = Marshal.AllocHGlobal(Marshal.SizeOf(rujd)); - PInvokeWin32.ZeroMemory(prujd, Marshal.SizeOf(rujd)); - Marshal.StructureToPtr(rujd, prujd, true); +// while (true) +// { +// prujd = Marshal.AllocHGlobal(Marshal.SizeOf(rujd)); +// PInvokeWin32.ZeroMemory(prujd, Marshal.SizeOf(rujd)); +// Marshal.StructureToPtr(rujd, prujd, true); - Debug.WriteLine(string.Format("\nMoniting on {0}......", volume)); - IntPtr pVolume = Wox.Infrastructure.MFTSearch.MFTSearcher.GetVolumeJournalHandle(volume); +// Debug.WriteLine(string.Format("\nMoniting on {0}......", volume)); +// IntPtr pVolume = Wox.Infrastructure.MFTSearch.MFTSearcher.GetVolumeJournalHandle(volume); - bool fok = PInvokeWin32.DeviceIoControl(pVolume, - PInvokeWin32.FSCTL_READ_USN_JOURNAL, - prujd, Marshal.SizeOf(typeof(PInvokeWin32.READ_USN_JOURNAL_DATA)), - pbuffer, 0x1000, out cbRead, IntPtr.Zero); +// bool fok = PInvokeWin32.DeviceIoControl(pVolume, +// PInvokeWin32.FSCTL_READ_USN_JOURNAL, +// prujd, Marshal.SizeOf(typeof(PInvokeWin32.READ_USN_JOURNAL_DATA)), +// pbuffer, 0x1000, out cbRead, IntPtr.Zero); - IntPtr pRealData = new IntPtr(pbuffer.ToInt32() + Marshal.SizeOf(typeof(Int64))); - uint offset = 0; +// IntPtr pRealData = new IntPtr(pbuffer.ToInt32() + Marshal.SizeOf(typeof(Int64))); +// uint offset = 0; - if (fok) - { - while (offset + Marshal.SizeOf(typeof(Int64)) < cbRead) - { - PInvokeWin32.USN_RECORD usn = new PInvokeWin32.USN_RECORD(new IntPtr(pRealData.ToInt32() + (int)offset)); - ProcessUSN(usn, volume, db); - offset += usn.RecordLength; - } - } +// if (fok) +// { +// while (offset + Marshal.SizeOf(typeof(Int64)) < cbRead) +// { +// PInvokeWin32.USN_RECORD usn = new PInvokeWin32.USN_RECORD(new IntPtr(pRealData.ToInt32() + (int)offset)); +// ProcessUSN(usn, volume, db); +// offset += usn.RecordLength; +// } +// } - Marshal.FreeHGlobal(prujd); - rujd.StartUsn = Marshal.ReadInt64(pbuffer); - } - } - private void ProcessUSN(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db) - { - var dbCached = db.FindByFrn(volume, usn.FRN); - Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, dbCached, db); - 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[Cached]={0}", dbCached == null ? "NoCache" : dbCached.FullPath)); - Debug.WriteLine("--------------------------------------"); +// Marshal.FreeHGlobal(prujd); +// rujd.StartUsn = Marshal.ReadInt64(pbuffer); +// } +// } +// private void ProcessUSN(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db) +// { +// var dbCached = db.FindByFrn(volume, usn.FRN); +// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, dbCached, db); +// 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[Cached]={0}", dbCached == null ? "NoCache" : dbCached.FullPath)); +// Debug.WriteLine("--------------------------------------"); - if (MaskEqual(usn.Reason, USNChangeReason.USN_REASONS["USN_REASON_RENAME_NEW_NAME"])) - ProcessRenameNewName(usn, volume, db); - if ((usn.Reason & USNChangeReason.USN_REASONS["USN_REASON_FILE_CREATE"]) != 0) - ProcessFileCreate(usn, volume, db); - if (MaskEqual(usn.Reason, USNChangeReason.USN_REASONS["USN_REASON_FILE_DELETE"])) - ProcessFileDelete(usn, volume, db); - } - private void ProcessFileDelete(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db) - { - var cached = db.FindByFrn(volume, usn.FRN); - if (cached == null) - { - return; - } - else - { - Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, cached, db); - var deleteok = db.DeleteRecord(volume, usn.FRN); - Debug.WriteLine(string.Format(">>>> File {0} deleted {1}.", cached.FullPath, deleteok ? "successful" : "fail")); - if (RecordDeletedEvent != null) - RecordDeletedEvent(cached); - } - } - private void ProcessRenameNewName(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db) - { - USNRecord newRecord = USNRecord.ParseUSN(volume, usn); - //string fullpath = newRecord.Name; - //db.FindRecordPath(newRecord, ref fullpath, db.GetFolderSource(volume)); - //newRecord.FullPath = fullpath; - var oldRecord = db.FindByFrn(volume, usn.FRN); - Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, oldRecord, db); - Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, newRecord, db); - Debug.WriteLine(string.Format(">>>> RenameFile {0} to {1}", oldRecord.FullPath, newRecord.FullPath)); - db.UpdateRecord(volume, newRecord, - usn.IsFolder ? USNRecordType.Folder : USNRecordType.File); - if (RecordRenameEvent != null) RecordRenameEvent(oldRecord, newRecord); - if (newRecord.FullPath.Contains("$RECYCLE.BIN")) - { - Debug.WriteLine(string.Format(">>>> Means {0} moved to recycle.", oldRecord.FullPath)); - } - } - private void ProcessFileCreate(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db) - { - USNRecord record = USNRecord.ParseUSN(volume, usn); - //string fullpath = record.Name; - //db.FindRecordPath(record, ref fullpath, db.GetFolderSource(volume)); - //record.FullPath = fullpath; - db.AddRecord(volume, record, usn.IsFolder ? USNRecordType.Folder : USNRecordType.File); - Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, record, db); - Debug.WriteLine(string.Format(">>>> NewFile: {0}", record.FullPath)); - if (RecordAddedEvent != null) - RecordAddedEvent(record); - } +// if (MaskEqual(usn.Reason, USNChangeReason.USN_REASONS["USN_REASON_RENAME_NEW_NAME"])) +// ProcessRenameNewName(usn, volume, db); +// if ((usn.Reason & USNChangeReason.USN_REASONS["USN_REASON_FILE_CREATE"]) != 0) +// ProcessFileCreate(usn, volume, db); +// if (MaskEqual(usn.Reason, USNChangeReason.USN_REASONS["USN_REASON_FILE_DELETE"])) +// ProcessFileDelete(usn, volume, db); +// } +// private void ProcessFileDelete(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db) +// { +// var cached = db.FindByFrn(volume, usn.FRN); +// if (cached == null) +// { +// return; +// } +// else +// { +// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, cached, db); +// var deleteok = db.DeleteRecord(volume, usn.FRN); +// Debug.WriteLine(string.Format(">>>> File {0} deleted {1}.", cached.FullPath, deleteok ? "successful" : "fail")); +// if (RecordDeletedEvent != null) +// RecordDeletedEvent(cached); +// } +// } +// private void ProcessRenameNewName(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db) +// { +// USNRecord newRecord = USNRecord.ParseUSN(volume, usn); +// //string fullpath = newRecord.Name; +// //db.FindRecordPath(newRecord, ref fullpath, db.GetFolderSource(volume)); +// //newRecord.FullPath = fullpath; +// var oldRecord = db.FindByFrn(volume, usn.FRN); +// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, oldRecord, db); +// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, newRecord, db); +// Debug.WriteLine(string.Format(">>>> RenameFile {0} to {1}", oldRecord.FullPath, newRecord.FullPath)); +// db.UpdateRecord(volume, newRecord, +// usn.IsFolder ? USNRecordType.Folder : USNRecordType.File); +// if (RecordRenameEvent != null) RecordRenameEvent(oldRecord, newRecord); +// if (newRecord.FullPath.Contains("$RECYCLE.BIN")) +// { +// Debug.WriteLine(string.Format(">>>> Means {0} moved to recycle.", oldRecord.FullPath)); +// } +// } +// private void ProcessFileCreate(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db) +// { +// USNRecord record = USNRecord.ParseUSN(volume, usn); +// //string fullpath = record.Name; +// //db.FindRecordPath(record, ref fullpath, db.GetFolderSource(volume)); +// //record.FullPath = fullpath; +// db.AddRecord(volume, record, usn.IsFolder ? USNRecordType.Folder : USNRecordType.File); +// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, record, db); +// Debug.WriteLine(string.Format(">>>> NewFile: {0}", record.FullPath)); +// if (RecordAddedEvent != null) +// RecordAddedEvent(record); +// } - private bool MaskEqual(uint target, uint compare) - { - return (target & compare) != 0; - } - } -} +// private bool MaskEqual(uint target, uint compare) +// { +// return (target & compare) != 0; +// } +// } +//} diff --git a/Wox.Plugin/Result.cs b/Wox.Plugin/Result.cs index 3a7904b2e9..db0bd309c0 100644 --- a/Wox.Plugin/Result.cs +++ b/Wox.Plugin/Result.cs @@ -3,71 +3,78 @@ using System.Collections; using System.Collections.Generic; using System.IO; -namespace Wox.Plugin { +namespace Wox.Plugin +{ - public class Result { - public string Title { get; set; } - public string SubTitle { get; set; } - public string IcoPath { get; set; } + public class Result + { - public string FullIcoPath - { - get - { + public string Title { get; set; } + public string SubTitle { get; set; } + public string IcoPath { get; set; } + + public string FullIcoPath + { + get + { if (string.IsNullOrEmpty(IcoPath)) return string.Empty; - if (IcoPath.StartsWith("data:")) - { - return IcoPath; - } + if (IcoPath.StartsWith("data:")) + { + return IcoPath; + } return Path.Combine(PluginDirectory, IcoPath); - } - } + } + } - /// - /// return true to hide wox after select result - /// - public Func Action { get; set; } - public int Score { get; set; } + /// + /// return true to hide wox after select result + /// + public Func Action { get; set; } - /// - /// Auto add scores for MRU items - /// - public bool AutoAjustScore { get; set; } + public int Score { get; set; } - //todo: this should be controlled by system, not visible to users - /// - /// Only resulsts that originQuery match with curren query will be displayed in the panel - /// - public Query OriginQuery { get; set; } + /// + /// Auto add scores for MRU items + /// + public bool AutoAjustScore { get; set; } - /// - /// Don't set this property if you are developing a plugin - /// - public string PluginDirectory { get; set; } + //todo: this should be controlled by system, not visible to users + /// + /// Only resulsts that originQuery match with curren query will be displayed in the panel + /// + public Query OriginQuery { get; set; } - public new bool Equals(object obj) { - if (obj == null || !(obj is Result)) return false; + /// + /// Don't set this property if you are developing a plugin + /// + public string PluginDirectory { get; set; } - Result r = (Result)obj; - return r.Title == Title && r.SubTitle == SubTitle; - } + public new bool Equals(object obj) + { + 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() { - return Title + SubTitle; - } + public Result() + { - 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) { - this.Title = Title; - this.IcoPath = IcoPath; - this.SubTitle = SubTitle; - } - - } + public List ContextMenu { get; set; } + } } \ No newline at end of file diff --git a/Wox.Test/MFTSearcherTest.cs b/Wox.Test/MFTSearcherTest.cs index b7f318c33d..c7a9ec5841 100644 --- a/Wox.Test/MFTSearcherTest.cs +++ b/Wox.Test/MFTSearcherTest.cs @@ -16,7 +16,7 @@ namespace Wox.Test var searchtimestart = DateTime.Now; MFTSearcher.IndexAllVolumes(); 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; List mftSearchRecords = MFTSearcher.Search("q"); @@ -28,5 +28,19 @@ namespace Wox.Test searchtimeend = DateTime.Now; 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))); + } } } diff --git a/Wox/Commands/SystemCommand.cs b/Wox/Commands/SystemCommand.cs index 162011f8a8..1a5a1949b7 100644 --- a/Wox/Commands/SystemCommand.cs +++ b/Wox/Commands/SystemCommand.cs @@ -17,16 +17,17 @@ namespace Wox.Commands public override void Dispatch(Query query) { + var queryPlugins = allSytemPlugins; if (UserSettingStorage.Instance.WebSearches.Exists(o => o.ActionWord == query.ActionName && o.Enabled)) { //websearch mode - allSytemPlugins = new List() + queryPlugins = new List() { allSytemPlugins.First(o => ((ISystemPlugin)o.Plugin).ID == "565B73353DBF4806919830B9202EE3BF") }; } - foreach (PluginPair pair in allSytemPlugins) + foreach (PluginPair pair in queryPlugins) { PluginPair pair1 = pair; ThreadPool.QueueUserWorkItem(state => diff --git a/Wox/MainWindow.xaml b/Wox/MainWindow.xaml index 71ef2bfd54..448680b218 100644 --- a/Wox/MainWindow.xaml +++ b/Wox/MainWindow.xaml @@ -22,7 +22,8 @@ - + + \ No newline at end of file diff --git a/Wox/MainWindow.xaml.cs b/Wox/MainWindow.xaml.cs index e44a65d539..bce6c69777 100644 --- a/Wox/MainWindow.xaml.cs +++ b/Wox/MainWindow.xaml.cs @@ -141,6 +141,13 @@ namespace Wox results.ForEach(o => { o.PluginDirectory = plugin.PluginDirectory; + if (o.ContextMenu != null) + { + o.ContextMenu.ForEach(t => + { + t.PluginDirectory = plugin.PluginDirectory; + }); + } o.OriginQuery = query; }); OnUpdateResultView(results); @@ -148,7 +155,6 @@ namespace Wox #endregion - public MainWindow() { InitializeComponent(); @@ -160,7 +166,9 @@ namespace Wox progressBar.ToolTip = toolTip; InitialTray(); - resultCtrl.OnMouseClickItem += AcceptSelect; + pnlResult.LeftMouseClickEvent += SelectResult; + pnlContextMenu.LeftMouseClickEvent += SelectResult; + pnlResult.RightMouseClickEvent += pnlResult_RightMouseClickEvent; ThreadPool.SetMaxThreads(30, 10); try @@ -180,6 +188,11 @@ namespace Wox this.Closing += MainWindow_Closing; } + void pnlResult_RightMouseClickEvent(Result result) + { + ShowContextMenu(result); + } + void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) { UserSettingStorage.Instance.WindowLeft = Left; @@ -300,21 +313,22 @@ namespace Wox lastQuery = tbQuery.Text; toolTip.IsOpen = false; - resultCtrl.Dirty = true; + pnlResult.Dirty = true; Dispatcher.DelayInvoke("UpdateSearch", o => { 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 // must clear the result. otherwise, it will be confused why the query changed, but the results // didn't. - if (resultCtrl.Dirty) resultCtrl.Clear(); + if (pnlResult.Dirty) pnlResult.Clear(); }, TimeSpan.FromMilliseconds(100), null); queryHasReturn = false; var q = new Query(lastQuery); CommandFactory.DispatchCommand(q); + BackToResultMode(); if (Plugins.HitThirdpartyKeyword(q)) { Dispatcher.DelayInvoke("ShowProgressbar", originQuery => @@ -328,6 +342,12 @@ namespace Wox }, TimeSpan.FromMilliseconds(ShouldNotDelayQuery ? 0 : 150)); } + private void BackToResultMode() + { + pnlResult.Visibility = Visibility.Visible; + pnlContextMenu.Visibility = Visibility.Collapsed; + } + private bool ShouldNotDelayQuery { get @@ -463,7 +483,7 @@ namespace Wox ShowWox(false); if (!tbQuery.Text.StartsWith(">")) { - resultCtrl.Clear(); + pnlResult.Clear(); ChangeQuery(">"); } tbQuery.CaretIndex = tbQuery.Text.Length; @@ -473,7 +493,7 @@ namespace Wox private void updateCmdMode() { - var currentSelectedItem = resultCtrl.GetActiveResult(); + var currentSelectedItem = pnlResult.GetActiveResult(); if (currentSelectedItem != null) { ignoreTextChange = true; @@ -489,7 +509,14 @@ namespace Wox switch (key) { case Key.Escape: - HideWox(); + if (IsInContextMenuMode) + { + BackToResultMode(); + } + else + { + HideWox(); + } e.Handled = true; break; @@ -516,14 +543,14 @@ namespace Wox break; case Key.PageDown: - resultCtrl.SelectNextPage(); + pnlResult.SelectNextPage(); if (IsCMDMode) updateCmdMode(); toolTip.IsOpen = false; e.Handled = true; break; case Key.PageUp: - resultCtrl.SelectPrevPage(); + pnlResult.SelectPrevPage(); if (IsCMDMode) updateCmdMode(); toolTip.IsOpen = false; e.Handled = true; @@ -545,29 +572,68 @@ namespace Wox break; case Key.Enter: - AcceptSelect(resultCtrl.GetActiveResult()); + Result activeResult = GetActiveResult(); + if (globalHotkey.CheckModifiers().ShiftPressed) + { + ShowContextMenu(activeResult); + } + else + { + SelectResult(activeResult); + } e.Handled = true; 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() { - resultCtrl.SelectPrev(); - if (IsCMDMode) updateCmdMode(); + if (IsInContextMenuMode) + { + pnlContextMenu.SelectPrev(); + } + else + { + pnlResult.SelectPrev(); + if (IsCMDMode) updateCmdMode(); + } toolTip.IsOpen = false; } private void SelectNextItem() { - resultCtrl.SelectNext(); - if (IsCMDMode) updateCmdMode(); + if (IsInContextMenuMode) + { + pnlContextMenu.SelectNext(); + } + else + { + pnlResult.SelectNext(); + if (IsCMDMode) updateCmdMode(); + } 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) { @@ -599,7 +665,20 @@ namespace Wox if (o.AutoAjustScore) o.Score += UserSelectedRecordStorage.Instance.GetSelectedCount(o); }); List 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; } } diff --git a/Wox/ResultPanel.xaml b/Wox/ResultPanel.xaml index 03927ce29d..d1a8e28afd 100644 --- a/Wox/ResultPanel.xaml +++ b/Wox/ResultPanel.xaml @@ -17,7 +17,7 @@ - + diff --git a/Wox/ResultPanel.xaml.cs b/Wox/ResultPanel.xaml.cs index 690a48de69..736d5d262c 100644 --- a/Wox/ResultPanel.xaml.cs +++ b/Wox/ResultPanel.xaml.cs @@ -14,11 +14,18 @@ namespace Wox { public partial class ResultPanel : UserControl { - public event Action OnMouseClickItem; + public event Action LeftMouseClickEvent; + public event Action RightMouseClickEvent; - protected virtual void OnOnMouseClickItem(Result result) + protected virtual void OnRightMouseClick(Result result) { - Action handler = OnMouseClickItem; + Action handler = RightMouseClickEvent; + if (handler != null) handler(result); + } + + protected virtual void OnLeftMouseClick(Result result) + { + Action handler = LeftMouseClickEvent; if (handler != null) handler(result); } @@ -133,9 +140,13 @@ namespace Wox private void LbResults_OnPreviewMouseDown(object sender, MouseButtonEventArgs e) { 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); } }