diff --git a/src/LessMsi.Gui/Extensions/ObjectArrayExtensions.cs b/src/LessMsi.Gui/Extensions/ObjectArrayExtensions.cs new file mode 100644 index 0000000..607d7bd --- /dev/null +++ b/src/LessMsi.Gui/Extensions/ObjectArrayExtensions.cs @@ -0,0 +1,19 @@ +using System; + +namespace LessMsi.Gui.Extensions +{ + public static class ObjectArrayExtensions + { + public static bool Contains(this object[] objects, string needle, StringComparison comparisonType) + { + foreach(object obj in objects) + { + if (obj.ToString().Contains(needle, comparisonType)) + { + return true; + } + } + return false; + } + } +} diff --git a/src/LessMsi.Gui/Extensions/StringExtensions.cs b/src/LessMsi.Gui/Extensions/StringExtensions.cs new file mode 100644 index 0000000..95add46 --- /dev/null +++ b/src/LessMsi.Gui/Extensions/StringExtensions.cs @@ -0,0 +1,12 @@ +using System; + +namespace LessMsi.Gui.Extensions +{ + public static class StringExtensions + { + public static bool Contains(this string src, string needle, StringComparison comparisonType) + { + return src.IndexOf(needle, comparisonType) >= 0; + } + } +} diff --git a/src/LessMsi.Gui/LessMsi.Gui.csproj b/src/LessMsi.Gui/LessMsi.Gui.csproj index 25d2784..6b51101 100644 --- a/src/LessMsi.Gui/LessMsi.Gui.csproj +++ b/src/LessMsi.Gui/LessMsi.Gui.csproj @@ -65,6 +65,8 @@ AboutBox.cs + + Form diff --git a/src/LessMsi.Gui/MainForm.cs b/src/LessMsi.Gui/MainForm.cs index 5ae5506..95c317a 100644 --- a/src/LessMsi.Gui/MainForm.cs +++ b/src/LessMsi.Gui/MainForm.cs @@ -426,8 +426,7 @@ private void InitializeComponent() this.fileGrid.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; this.fileGrid.Size = new System.Drawing.Size(446, 366); this.fileGrid.TabIndex = 5; - this.fileGrid.KeyDown += new System.Windows.Forms.KeyEventHandler(this.fileGrid_KeyDown); - this.fileGrid.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.fileGrid_KeyPress); + this.fileGrid.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.SearchableGrid_KeyPress); // // panel2 // @@ -530,6 +529,7 @@ private void InitializeComponent() this.msiTableGrid.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; this.msiTableGrid.Size = new System.Drawing.Size(453, 370); this.msiTableGrid.TabIndex = 10; + this.msiTableGrid.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.SearchableGrid_KeyPress); // // tabSummary // @@ -787,7 +787,7 @@ private void InitializeComponent() this.searchFileToolStripMenuItem.ShortcutKeyDisplayString = "Ctrl+F"; this.searchFileToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.F))); this.searchFileToolStripMenuItem.Size = new System.Drawing.Size(170, 22); - this.searchFileToolStripMenuItem.Text = "Search File"; + this.searchFileToolStripMenuItem.Text = "Search"; this.searchFileToolStripMenuItem.Click += new System.EventHandler(this.searchFileToolStripMenuItem_Click); // // aboutToolStripMenuItem @@ -807,6 +807,7 @@ private void InitializeComponent() this.Controls.Add(this.panel1); this.Controls.Add(this.menuStrip1); this.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.KeyPreview = true; this.MainMenuStrip = this.menuStrip1; this.MinimumSize = new System.Drawing.Size(352, 404); this.Name = "MainForm"; @@ -814,6 +815,7 @@ private void InitializeComponent() this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing); this.DragDrop += new System.Windows.Forms.DragEventHandler(this.MainForm_DragDrop); this.DragEnter += new System.Windows.Forms.DragEventHandler(this.MainForm_DragEnter); + this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.MainForm_KeyDown); this.tabs.ResumeLayout(false); this.tabExtractFiles.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.fileGrid)).EndInit(); @@ -1034,22 +1036,20 @@ private void searchFileToolStripMenuItem_Click(object sender, EventArgs e) if (IsFileTabSelected) { searchPanel.SearchDataGrid(this.fileGrid, - (o, args) => Presenter.BeginSearching(args.SearchString), - (o, args) => { Presenter.BeginSearching(""); } + Presenter.ExecuteFileSearch, + () => { Presenter.ExecuteFileSearch(this.fileGrid, string.Empty); } ); } - } - - private void fileGrid_KeyDown(object sender, KeyEventArgs e) - { - // If they press escape while navigating the grid and the search panel is open in the search panel, cancel the search: - if (e.KeyCode == Keys.Escape) + else if (IsTableTabSelected) { - searchPanel.CancelSearch(); + searchPanel.SearchDataGrid(this.msiTableGrid, + Presenter.ExecuteTableSearch, + () => { Presenter.ExecuteTableSearch(this.msiTableGrid, string.Empty); } + ); } } - private void fileGrid_KeyPress(object sender, KeyPressEventArgs e) + private void SearchableGrid_KeyPress(object sender, KeyPressEventArgs e) { if (Char.IsLetterOrDigit(e.KeyChar)) { @@ -1093,5 +1093,21 @@ protected bool IsFileTabSelected } } + protected bool IsTableTabSelected + { + get + { + return tabs.SelectedTab == tabTableView; + } + } + + private void MainForm_KeyDown(object sender, KeyEventArgs e) + { + // If they press escape while navigating the grid and the search panel is open in the search panel, cancel the search: + if (e.KeyCode == Keys.Escape) + { + searchPanel?.CancelSearch(); + } + } } } diff --git a/src/LessMsi.Gui/MainFormPresenter.cs b/src/LessMsi.Gui/MainFormPresenter.cs index bb5e6e3..b55df1c 100644 --- a/src/LessMsi.Gui/MainFormPresenter.cs +++ b/src/LessMsi.Gui/MainFormPresenter.cs @@ -28,7 +28,9 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Windows.Forms; using LessIO; +using LessMsi.Gui.Extensions; using LessMsi.Gui.Model; using LessMsi.Gui.Windows.Forms; using LessMsi.Msi; @@ -45,6 +47,7 @@ class MainFormPresenter { private readonly MainForm _view; private SortableBindingList fileDataSource; + private IList tableViewDataSource; public MainFormPresenter(MainForm view) { @@ -446,7 +449,8 @@ private void UpdateMSiTableGrid(Database msidb, string tableName) sequenceName = displayName; } } - View.SetTableViewGridDataSource(view.Records); + tableViewDataSource = view.Records; + View.SetTableViewGridDataSource(tableViewDataSource); } if (!string.IsNullOrEmpty(sequenceName)) { @@ -545,7 +549,7 @@ public void LoadCurrentFile() /// Executes searching on gridtable and shows only filtered values /// /// Search term or to cancel the search. - internal void BeginSearching(string searchTerm) + internal void ExecuteFileSearch(DataGridView fileGrid, string searchTerm) { if (this.fileDataSource != null) { @@ -557,12 +561,37 @@ internal void BeginSearching(string searchTerm) } else { - dataSource = this.fileDataSource.Where(x => x.Component.Contains(searchTerm) || x.Directory.Contains(searchTerm) || x.Name.Contains(searchTerm) || x.Version.Contains(searchTerm)).ToList(); + dataSource = this.fileDataSource.Where( + x => x.Component.Contains(searchTerm, StringComparison.OrdinalIgnoreCase) || + x.Directory.Contains(searchTerm, StringComparison.OrdinalIgnoreCase) || + x.Name.Contains(searchTerm, StringComparison.OrdinalIgnoreCase) || + x.Version.Contains(searchTerm, StringComparison.OrdinalIgnoreCase) + ).ToList(); Status(string.Format("{0} files found.", dataSource.Count)); } - ViewLeakedAbstraction.fileGrid.DataSource = dataSource; + fileGrid.DataSource = dataSource; } - } + + internal void ExecuteTableSearch(DataGridView _, string searchTerm) + { + if (this.tableViewDataSource != null) + { + IList dataSource; + if (string.IsNullOrEmpty(searchTerm)) + { + dataSource = this.tableViewDataSource; + Status(); + } + else + { + dataSource = this.tableViewDataSource.Where( + x => x.Contains(searchTerm, StringComparison.OrdinalIgnoreCase) + ).ToList(); + Status(string.Format("{0} rows found.", dataSource.Count)); + } + View.SetTableViewGridDataSource(dataSource); + } + } } } diff --git a/src/LessMsi.Gui/Windows.Forms/SearchPanel.cs b/src/LessMsi.Gui/Windows.Forms/SearchPanel.cs index aa17c28..70ec95b 100644 --- a/src/LessMsi.Gui/Windows.Forms/SearchPanel.cs +++ b/src/LessMsi.Gui/Windows.Forms/SearchPanel.cs @@ -1,55 +1,60 @@ using System; -using System.Diagnostics; using System.Drawing; using System.Windows.Forms; namespace LessMsi.Gui.Windows.Forms { internal partial class SearchPanel : UserControl - { - public event EventHandler SearchTermChanged; - - /// - /// Raised when the search term box is canceled. Any filtering done based on the search can be cleared at this point. - /// - public event EventHandler SearchCanceled; - private Control dataGridToAttachTo; + { + private Action searchTermChanged; + private Action searchCanceled; + private DataGridView dataGridToAttachTo; public SearchPanel() { this.Visible = false; - InitializeComponent(); - } - + InitializeComponent(); + this.cancelButton.Click += (sender, args) => this.CancelSearch(); + } + /// /// Performs the search of the specified data grid. /// /// This DataGrid control the search is performed on. /// This control will position itself within the area of the grid. - /// Handler for search term change. - /// When the user cancels the search the caller can use this handler to clean something up. - public void SearchDataGrid(Control dataGridToAttachTo, - EventHandler searchTermChangedHandler, - EventHandler cancelSearchingEventHandler + /// Handler for search term change. + /// When the user cancels the search the caller can use this handler to clean something up. + public void SearchDataGrid(DataGridView dataGridToAttachTo, + Action searchTermChanged, + Action searchCanceled ) - { - Debug.Assert(this.dataGridToAttachTo == null || object.ReferenceEquals(this.dataGridToAttachTo, dataGridToAttachTo), "expected always to be the same data grid? Something odd here."); + { + if (this.dataGridToAttachTo != null && !object.ReferenceEquals(this.dataGridToAttachTo, dataGridToAttachTo)) + { + this.Parent.Resize -= Parent_Resize; + this.dataGridToAttachTo.Parent.Controls.Remove(this); + } + this.dataGridToAttachTo = dataGridToAttachTo; dataGridToAttachTo.Parent.Controls.Add(this); - SetPreferredLocationAndSize(); - this.SearchTermChanged += searchTermChangedHandler; - this.SearchCanceled += cancelSearchingEventHandler; - this.Parent.Resize += (sender, args) => SetPreferredLocationAndSize(); - this.cancelButton.Click += (sender, args) => this.CancelSearch(); + SetPreferredLocationAndSize(); + this.searchTermChanged = searchTermChanged; + this.searchCanceled = searchCanceled; + this.Parent.Resize += Parent_Resize; this.BringToFront(); this.Visible = true; this.tbSearchText.Focus(); - } - + } + + private void Parent_Resize(object sender, EventArgs e) + { + SetPreferredLocationAndSize(); + } + private void SetPreferredLocationAndSize() { this.SuspendLayout(); - this.Width = 300;//this.Width = dataGridToAttachTo.Width; + this.Width = 300; this.ClientSize = new Size(this.ClientSize.Width, PreferredClientHeight); this.ResumeLayout(true); this.Location = new Point(dataGridToAttachTo.Left, dataGridToAttachTo.Height - this.Height); @@ -61,11 +66,8 @@ private int PreferredClientHeight } private void tbSearchText_TextChanged(object sender, EventArgs e) - { - if (SearchTermChanged != null) - { - SearchTermChanged(this, new SearchTermChangedEventArgs() {SearchString = tbSearchText.Text}); - } + { + searchTermChanged?.Invoke(this.dataGridToAttachTo, tbSearchText.Text); } public void CancelSearch() @@ -73,9 +75,8 @@ public void CancelSearch() if (!this.Visible) return; this.tbSearchText.Text = ""; - this.Hide(); - if (SearchCanceled != null) - SearchCanceled(this, EventArgs.Empty); + this.Hide(); + searchCanceled?.Invoke(); } private void tbSearchText_KeyDown(object sender, KeyEventArgs e) @@ -88,9 +89,4 @@ private void tbSearchText_KeyDown(object sender, KeyEventArgs e) } } } - - internal class SearchTermChangedEventArgs : EventArgs - { - public string SearchString { get; set; } - } -} \ No newline at end of file +}