From 755e7bc2324cc72b7c7cb82c9e86444975bdc968 Mon Sep 17 00:00:00 2001 From: qianlifeng Date: Thu, 23 Oct 2014 18:39:11 +0800 Subject: [PATCH] Add Context menu --- Plugins/Wox.Plugin.FindFile/Images/edit.png | Bin 0 -> 5765 bytes Plugins/Wox.Plugin.FindFile/Main.cs | 53 +++- .../Wox.Plugin.FindFile.csproj | 7 +- Wox.Infrastructure/MFTSearch/MFTSearcher.cs | 21 +- .../MFTSearch/MFTSearcherCache.cs | 139 ++------- Wox.Infrastructure/MFTSearch/USNRecord.cs | 1 - Wox.Infrastructure/MFTSearch/VolumeMonitor.cs | 286 +++++++++--------- Wox.Plugin/Result.cs | 107 ++++--- Wox.Test/MFTSearcherTest.cs | 16 +- Wox/Commands/SystemCommand.cs | 5 +- Wox/MainWindow.xaml | 3 +- Wox/MainWindow.xaml.cs | 115 +++++-- Wox/ResultPanel.xaml | 2 +- Wox/ResultPanel.xaml.cs | 21 +- 14 files changed, 433 insertions(+), 343 deletions(-) create mode 100644 Plugins/Wox.Plugin.FindFile/Images/edit.png diff --git a/Plugins/Wox.Plugin.FindFile/Images/edit.png b/Plugins/Wox.Plugin.FindFile/Images/edit.png new file mode 100644 index 0000000000000000000000000000000000000000..f1710b7c89c33e8a083dbec8c25ec8de38e4971a GIT binary patch literal 5765 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 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); } }