diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj index 06ec4ab085..f127f7ead4 100644 --- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj +++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj @@ -44,6 +44,10 @@ TRACE;PUBLICINTERPROCESS + + ..\..\..\Libraries\Mono.Cecil\Mono.Cecil.dll + False + 3.0 diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/GacReferencePanel.cs b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/GacReferencePanel.cs index db39bd8f56..45fb955b86 100644 --- a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/GacReferencePanel.cs +++ b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/GacReferencePanel.cs @@ -3,13 +3,15 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.IO; using System.Linq; using System.Threading; using System.Windows.Forms; - +using Mono.Cecil; using ICSharpCode.Build.Tasks; using ICSharpCode.Core; +using ICSharpCode.NRefactory.Ast; using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Project; @@ -47,8 +49,16 @@ namespace ICSharpCode.SharpDevelop.Gui protected ListView listView; CheckBox chooseSpecificVersionCheckBox; + TextBox filterTextBox; + Button searchButton; + ToolTip toolTip = new ToolTip(); + ToolTip filterTextboxToolTip = new ToolTip(); ISelectReferenceDialog selectDialog; ColumnSorter sorter; + BackgroundWorker worker; + List resultList = new List(); + Dictionary assembliesCache = new Dictionary(); + DefaultAssemblyResolver resolver = new DefaultAssemblyResolver(); public GacReferencePanel(ISelectReferenceDialog selectDialog) { @@ -79,10 +89,12 @@ namespace ICSharpCode.SharpDevelop.Gui this.Dock = DockStyle.Fill; this.Controls.Add(listView); + Panel upperPanel = new Panel { Dock = DockStyle.Top, Height = 20 }; + chooseSpecificVersionCheckBox = new CheckBox(); - chooseSpecificVersionCheckBox.Dock = DockStyle.Top; + chooseSpecificVersionCheckBox.Dock = DockStyle.Left; chooseSpecificVersionCheckBox.Text = StringParser.Parse("${res:Dialog.SelectReferenceDialog.GacReferencePanel.ChooseSpecificAssemblyVersion}"); - this.Controls.Add(chooseSpecificVersionCheckBox); + chooseSpecificVersionCheckBox.CheckedChanged += delegate { listView.Items.Clear(); if (chooseSpecificVersionCheckBox.Checked) @@ -91,9 +103,160 @@ namespace ICSharpCode.SharpDevelop.Gui listView.Items.AddRange(shortItemList); }; + filterTextBox = new TextBox { Width = 100, Dock = DockStyle.Right }; + searchButton = new Button { Dock = DockStyle.Right, Width = 50, Text = "Search" }; + toolTip.SetToolTip(searchButton, searchButton.Text); + filterTextboxToolTip.SetToolTip(filterTextBox, "Search by type name"); + searchButton.Click += searchButton_Click; + upperPanel.Controls.Add(chooseSpecificVersionCheckBox); + upperPanel.Controls.Add(filterTextBox); + upperPanel.Controls.Add(searchButton); + + this.Controls.Add(upperPanel); + PrintCache(); + + worker = new BackgroundWorker { WorkerSupportsCancellation = true, WorkerReportsProgress = true }; + worker.DoWork += searchTask_DoWork; + worker.RunWorkerCompleted += searchTask_RunWorkerCompleted; + worker.ProgressChanged += searchTask_ProgressChanged; } + #region Search by types + + void searchTask_ProgressChanged(object sender, ProgressChangedEventArgs e) + { + searchButton.Text = string.Format("{0} %", e.ProgressPercentage); + } + + void searchTask_DoWork(object sender, DoWorkEventArgs e) + { + e.Cancel = !SearchTypesName( + chooseSpecificVersionCheckBox.Checked ? fullItemList : shortItemList, filterTextBox.Text); + } + + void searchButton_Click(object sender, EventArgs e) + { + string text; + if(!worker.IsBusy) { + filterTextBox.ReadOnly = true; + worker.RunWorkerAsync(); + text = "Cancel"; + } + else { + worker.CancelAsync(); + text = "Search"; + filterTextBox.ReadOnly = false; + } + searchButton.Text = text; + this.toolTip.SetToolTip(searchButton, text); + } + + void searchTask_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) + { + searchButton.Text = "Search"; this.toolTip.SetToolTip(searchButton, searchButton.Text); + filterTextBox.ReadOnly = false; + if (resultList != null && resultList.Count > 0) { + listView.Items.Clear(); + listView.Items.AddRange(resultList.ToArray()); + } + } + + /// + /// Search for type name. + /// + /// Array of items where to search. + /// Filter to search. + /// true, if call succeded, false otherwise. + bool SearchTypesName(ListViewItem[] list, string filter) + { + // return null if list is null + if (list == null) return false; + + // return if filter is empty + if (string.IsNullOrEmpty(filter)) { + resultList = list.ToList(); + return true; + } + + // clear result + resultList.Clear(); + + // scan the list + for (int i = 0; i < list.Length; ++i) { + ListViewItem item = list[i]; + DomAssemblyName asm = item.Tag as DomAssemblyName; + + // search path + if (asm.FullName.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0) + resultList.Add(item); + else { + if (worker.CancellationPending) + return false; + + // search using Mono.Cecil the class/interface/structs names + AssemblyDefinition currentAssembly; + if(!assembliesCache.ContainsKey(asm.FullName)) { + try { + currentAssembly = resolver.Resolve(asm.FullName); + } + catch { + continue; + } + assembliesCache.Add(asm.FullName, currentAssembly); + } + else + currentAssembly = assembliesCache[asm.FullName]; + + // search types in modules + if (currentAssembly != null) { + foreach(var module in currentAssembly.Modules) + foreach (var type in module.Types) + if (type.Name.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0 && + !resultList.Contains(item)) + resultList.Add(item); + } + + // report + worker.ReportProgress((int)(((i * 1.0) / list.Length) * 100)); + } + } + + return true; + } + + /// + /// Clear all resources used. + /// + new void Dispose() + { + // cancel the worker + if (worker != null && worker.IsBusy && !worker.CancellationPending) + worker.CancelAsync(); + worker = null; + + // clear all cached data + if (assembliesCache.Count > 0) + assembliesCache.Clear(); + assembliesCache = null; + + if (resultList.Count > 0) + resultList.Clear(); + resultList = null; + + selectDialog = null; + resolver = null; + + if (fullItemList.Length > 0) + Array.Clear(fullItemList, 0, fullItemList.Length); + fullItemList = null; + + // force a collection to reclam memory + GC.Collect(); + } + + #endregion + void columnClick(object sender, ColumnClickEventArgs e) { if(e.Column < 2) { @@ -278,5 +441,12 @@ namespace ICSharpCode.SharpDevelop.Gui list.RemoveAll(name => name.ShortName.EndsWith(".resources", StringComparison.OrdinalIgnoreCase)); return list; } + + protected override void Dispose(bool disposing) + { + Dispose(); + + base.Dispose(disposing); + } } }